From Idea to Deployment: How I built a multilingual, adaptive learning app using Lovable for design and Cursor Composer for development with 9 prompts.
Paul
My daughter was struggling with learning multiplication tables, and I wanted to create something better than the standard forms with sums to make that we could easily get in Dutch. I envisioned an app that:
Adapts to the learner's progress
Focuses on difficult problems
Provides immediate feedback
Tracks progress visually
And I wanted to test Lovable which I hear so much rave about.
I started with Lovable to quickly prototype the UI and get the basic structure in place.
Young children need to learn their multiplication tables (the standard sequences of 1 x 1 = 1, 2 x 1 = 2, and up to 10 x 10 = 100). To automate this, they need a lot of practice.
We're going to create a mini-app that presents a multiplication table in a standard quiz format, each time asking the child to answer it. The results are saved in the browser.
The app starts with the multiplication table of 1, then 2, then 5, then 10, then 3, 4, 6, 7, 8, and 9 (increasing difficulty). The multiplication tables are practiced from low to high on the first run, with more tables being added gradually. The required sums are taken from the answers that were answered incorrectly most (or not yet asked because a new table has been added) until all the answers are consistently correct.
Lovable's AI-powered design tool helped me:
Create a clean, child-friendly interface
Set up the basic React + TypeScript + Vite structure
Implement the initial quiz card component
Add progress tracking visualization
Style it with Tailwind CSS and shadcn/ui components
The initial version had:
A quiz card with number pad input
Progress bar showing unlocked tables
Statistics display (total questions, accuracy)
Basic state management with localStorage
This gave me a solid foundation to build upon. But I also reached the end of my free credits on Lovable.
No worries there. I prefer to work in Cursor locally anyway. But the startup with Lovable was great.
Once I had the basic structure, I switched to the new free Composer 1 model from Cursor to improve on the basic app that was designed. For one, the lovable app went sequentially through a table and surfaced questions based on detected error rates. So I decided to add smart learning logic and polish the experience. Here's what we built:
The core challenge was creating an algorithm that prioritizes questions based on actual learning needs, not just error rates.
The Problem: Initially, questions were selected based on error rate. This meant a question like 7×2 with 11 correct answers and 1 mistake (error rate: 8.3%) would keep appearing more often than 6×2 with 2 correct and 0 mistakes (error rate: 0%), even though 6×2 obviously needs repeat practice as well.
The Solution: We switched to a net score system: netScore = correct - mistakes. This prioritizes questions with fewer net correct answers, ensuring learners practice what they actually need.
So because the user answered a question wrong once (like 7x2, 11/12 correct) it keeps re-surfacing that one a lot more often than the others (only asked twice). Make sure that selection between questions to ask is based on how often they have been correctly answered minus mistakes. So in case of 7x2 it's now 10 (11 correct, 1 mistake), which is way more than 6x2 (2/2)
const netScore = correct - mistakes; // Higher net score = more practice, lower priority
Progressive Difficulty: After completing the first pass through a new table sequentially, the app uses a 25/75 split:
25% of questions come from the latest unlocked table
75% come from previous tables
This keeps focus on the newest material while maintaining practice on older tables.
After going through a new table sequentially, change the logic so that 25% of the questions come from the latest table (randomly taken from top sorted by netScore) and the rest comes from the previous tables (randomly taken from top sorted by Netscore). So that the focus stays on the furthest table.
Shuffling for Variety: To prevent the same questions from appearing in order, we shuffle questions with the same priority before selecting from the top candidates.
Because sort keeps the initial order, now all from table 1 are at the 'topCandidates' so still feels sequential. The sums with the same netScore should be shuffled first before a slice is taken from the top.
Retry Logic: When a user answers incorrectly, the same question reappears immediately. When correct, a different question is always shown. This ensures mistakes are addressed while maintaining variety.
After a mistake, always re-surface the same question.
After a correct answer, make sure the next question is always a different one.
Progress Unlocking: Tables unlock progressively as learners master previous ones. A table unlocks when 70% of questions in all unlocked tables meet mastery criteria (either 2+ attempts with 70%+ accuracy, or 5+ attempts total).
After this was all working properly, it was a matter of a simple prompt to add Multilingual support.
The app supports six languages: English, Dutch, German, Spanish, Italian and French.
Propose a plan to make it multilingual (English, Dutch, German, Spanish, Italian and French). Detect the language based on the browser. And add a 'language selector' at the top.
Implementation:
Used react-i18next with i18next-browser-languagedetector
Auto-detects browser language on first visit
Saves language preference to localStorage
Language selector dropdown at the top
All UI text translated, including toast messages and debug view
Translation Structure:
{
"app": { "title": "...", "subtitle": "..." },
"quiz": { "correct": "...", "incorrect": "..." },
"statistics": { "practicedSums": "...", ... },
"progress": { "unlockedTables": "..." }
}
For debug purposes, add a view at the bottom showing the current saved state of questions / answers. Hide the debug by default, and add a small button at the bottom to open it again.
Added a comprehensive debug view (hidden by default) showing:
Current question state
Unlocked tables and progress
Table-by-table breakdown with net scores
Recent answer history
Raw state JSON
This was invaluable for testing and understanding the algorithm's behavior.
After testing multiple times, I noticed that it would help me, but probably also kids with a keyboard available, to support keyboard entry.
Also allow keyboard entry (with enter to confirm).
Frontend: React 18 + TypeScript
Build Tool: Vite
Styling: Tailwind CSS + shadcn/ui components
Animations: Framer Motion
State Management: React hooks + localStorage
i18n: react-i18next
Deployment: Docker + nginx
Created a multi-stage Dockerfile:
Make a Dockerfile so this can be published.
# Build stage
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# Production stage
FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html
EXPOSE 1080
CMD ["nginx", "-g", "daemon off;"]
The app is configured to run on port 1080 and includes SPA routing support for React Router.
I already have great experience with pair programming with Cursor Composer for fixing bugs, planning features and performing scoped updates and changes. But adding Lovable was new.
Start with design tools: Lovable was perfect for rapid prototyping and getting the UI right before diving into complex logic.
Algorithm matters: The net score approach proved much better than simple error rates for adaptive learning.
User experience details: Small things like delay timing, retry logic, and visual feedback make a huge difference in learning apps.
Debug tools are essential: Having a debug view helped identify and fix issues quickly during development.
All in all it took less than 3 hours from start, to deployment and blog. 9 primary prompts, and a few little bumps to fix small bugs and inconsistencies. The final app Table Trainer Junior is a polished, multilingual multiplication table trainer that:
Adapts to each learner's needs
Provides immediate, helpful feedback
Tracks progress visually
Works seamlessly across devices
Supports multiple languages
Keyboard support
It's ready to help kids (and adults!) master their multiplication tables in a fun, engaging way.
Built with ❤️ using Lovable and Cursor Composer
Copyright © 2025 brain-dump.space. All rights reserved.