Typing Tales: Teaching Kids to Type with Stories
My kids were using a typing tool at school, and they wanted something similar at home. The problem was, every tool I looked at was the same thing. Type “asdf asdf” over and over. Repetitive drills. Cluttered interfaces. They were technically teaching the right skills but my kids were bored within minutes.
I wasn’t interested in making them type fast. I wanted them to feel comfortable on a keyboard and maybe pick up some reading practice along the way. That combination didn’t seem to exist, so I built it.
The idea
Instead of drills, what if kids typed out a story? A story where they are the main character, set in a world they actually care about. Minecraft adventures, fairy tales, space missions, unicorn quests. They pick a theme, enter their name and age, and the app generates a short story starring them. Then they type it out, one character at a time, with live feedback on accuracy and speed.
The goal was never WPM scores. It was getting them to willingly sit at a keyboard and engage with text.
The stack
I went with plain PHP, SQLite, and Alpine.js. No framework.
I know Laravel well, but this project didn’t need routing, middleware, or an ORM. It needed a few API endpoints and a single-page frontend. Plain PHP let me ship the first working version in about a week of evening sessions. SQLite meant no database server to worry about. One file, runs anywhere.
Alpine.js handled the interactive bits on the frontend: the character-by-character validation, live WPM and accuracy counters, progress tracking, and a printable certificate at the end.
How the stories work
The first version had about six pre-written stories. They were generated using AI ahead of time and hardcoded. It worked, but the options ran out fast. My kids went through all of them within a few days.
To make it more engaging I wired up OpenAI directly. The app calls gpt-4o-mini with a prompt that includes the theme, the child’s age range, and a placeholder for their name. The prompt is specific about word count, reading level, and keeping content age-appropriate. A story for a 7-year-old picking “Dinosaur Discovery” reads very differently from a 12-year-old picking “Detective Mystery.”
Generated stories get cached in the database by theme and age range. If another kid picks the same combination, they get the same story with their name swapped in. This keeps API costs low and response times fast. One generation, many uses.
There are 26 themes now. Most of them came from asking my kids what they wanted. Minecraft was the first request. Then dragons. Then my daughter asked for a fairy tale castle. I threw in a few popular ones I knew would work and kept adding from there.
What my kids thought
My 9-year-old daughter loves it. She goes through different themes and types out the stories. The personalization keeps her coming back because she is the hero in every story.
My 12-year-old son is a different story. He is not really into the typing part, but he loves the story generation. He picks themes just to read what the app comes up with, especially when he is the main character in some over-the-top adventure. Not exactly the intended use case, but honestly, if he is reading, I’ll take it.
What I learned
Ship it, then fix it. The first version was rough. Six hardcoded stories, basic styling, no certificates. But it worked and my kids used it that same evening. Every improvement after that was driven by watching them use it. Auto-scroll to keep the cursor visible? That came from my daughter losing her place on longer stories. Safari compatibility fixes? From my son using the iPad.
Plain PHP still works. Not every project needs a framework. For something this small, the overhead of setting up Laravel would have taken longer than building the actual feature. The codebase is a handful of service files and API endpoints. Easy to understand, easy to change.
What I’d change
If I started over, I’d probably pick a different stack. Not because PHP was wrong for this, but because I’ve been reaching for TypeScript and Next.js more often lately, and having the frontend and backend in the same language simplifies things. The project has grown enough that a framework would earn its keep now.
I’d also think about mobile earlier. Most kids reach for a tablet before a laptop, and the typing experience on a physical keyboard is fundamentally different from a touchscreen.
You can try it at typingtales.org.