Build Your Kid a $25 Learning Toy That Isn't a Tablet
My six-year-old wanted a screen for long car rides. Every option on the market wanted something back from him — an account, a subscription, an ad impression, a dopamine loop tuned by a growth team. I didn’t want to negotiate with any of that. I wanted a thing that does math and reading practice, runs on a phone charger, and does nothing else.
So I built it. Total hardware cost: about $25. Total electronics experience required: none — no soldering, no breadboard, no resistor color codes. One board, one USB cable, one afternoon of setup. This post is the full recipe, including the parts that went wrong, so you can build one for your own kid.
(This is part 1 of 2. Part 2 covers the bigger 7-inch version I built later, which is a different class of machine. Start here — this is the one to build first.)
The product rules came before the code
Before any hardware, I wrote down what the toy would refuse to do. These constraints did more for the final result than any line of firmware:
- Five questions per round, then stop. It never feels like homework, and it has a natural “okay, done” moment.
- Stars are the only reward. Correct answers earn a star. Stars accumulate quietly in a corner. No confetti explosions, no jackpot sounds, no streaks to protect.
- Wrong answers cost nothing. No timers, no penalties, no lives. Getting it wrong just means trying again.
- Offline, forever. No accounts, no ads, no internet, no telemetry. It cannot phone home because there is nothing to phone.
- No cartoon aesthetic. Dark background, one accent color, big touch targets. Kids’ software doesn’t have to look like a cereal box. He notices the difference — it feels like his device, not a toy pretending to be one.
The theme underneath all five: treat the kid as capable instead of tricking him into learning.
The hardware: one board, that’s it
The entire bill of materials is a single item: a Hosyond 4.0“ ESP32 development board (the ESP32-32E variant) — a 320×480 ST7796S display with an ESP32 soldered to the back of it, resistive touch, USB-C. Around $25 on Amazon.
What you get for that:
| Component | What it is |
|---|---|
| MCU | ESP32-WROOM-32E, dual-core 240 MHz, 4 MB flash, 520 KB SRAM |
| Display | 4.0“ ST7796S, 320×480, RGB565 color, SPI |
| Touch | XPT2046 resistive (shares the SPI bus with the display on GPIO 12/13/14) |
| USB | Type-C with a CH340C serial chip, auto-reset — flash without touching any buttons |
| Power | Any USB phone charger or power bank |
No wiring, because there’s nothing to wire. The display is the computer. The repo even includes STL files for a 3D-printed case, if you want it to survive a backpack.
Two boring gotchas that account for most “it doesn’t work” moments:
- Your USB-C cable must be a data cable. Many are charge-only and will never enumerate as a serial device. If your laptop doesn’t see the board, swap cables before debugging anything else.
- On macOS, the CH340 serial chip needs the WCH driver installed once. If
/dev/cu.wchusbserial*doesn’t show up when you plug in, that’s the fix.
The firmware: one file, on purpose
The whole game is a single main.cpp — roughly two thousand lines of C++ built with PlatformIO and the TFT_eSPI display library. No LVGL, no UI framework, no abstraction layers.
That was a decision, not laziness, and I’d defend it hard for a project this size. Every embedded UI demo on the internet looks the same — the default widget theme, blue gradients, rounded rainbow buttons. Owning every pixel was the cheapest way to get a look I actually wanted. And on a 4 MB microcontroller, an abstraction layer is a cost you pay in flash, RAM, and debugging depth for flexibility you’ll never use. The project’s standing rule, written into its docs: no new abstraction layers unless splitting becomes unavoidable.
What the one file contains:
- Nine question generators. Math: counting objects, missing number, ten-frame, addition under 10, make-10. Reading: which-letter-does-it-start-with, missing letter in a CVC word, rhyming, uppercase/lowercase matching. All question banks are plain C arrays in the source — you can read them, edit them, and add your own in minutes.
- A star counter persisted to flash (ESP32’s NVS storage), so progress survives power-off.
- A PIN-gated parent panel — long-press to enter a 4-digit PIN — for brightness and star resets. The default PIN is
0000; change it in the source. - Round logic: 5 questions, gentle color-wash feedback per answer, a round-complete screen, done.
The gotcha that will bite you: touch calibration
Resistive touch panels are analog. Every XPT2046 panel reads slightly differently, and the raw corner constants in my source are tuned to my panel. Flash my firmware to your board unmodified and taps will land slightly off — and a six-year-old will conclude the toy is broken within ninety seconds.
There is no software fix; it’s physics. The repo makes calibration a required setup step, not a footnote: run the calibration sketch, tap the corners, copy four constants into main.cpp, reflash. Ten minutes. Do not skip it.
This is the honest lesson of $25 hardware — the real world needs a tuning knob a clean software model can’t see.
How AI tools actually fit into this
I wrote very little of this firmware by hand. Most evenings the workflow was: me describing behavior, an AI coding agent writing and flashing it, me holding the device and reporting what a kid would see.
The concrete setup, for anyone wanting to reproduce the workflow and not just the toy:
- Claude Code in the terminal was the primary builder. It wrote the question generators, the screen flow, the NVS persistence, the settings panel — driven by prompts describing kid-visible behavior, not code. The project keeps a log of every prompt, and reading it back is the real story of the build. An actual entry, verbatim: “for the math its not complex enough for my kid .. can we do multiples or s…” — that one sentence became skip counting within days, then the multiplication tables. The unit of work was a parent’s observation, not a ticket.
- A project constitution file did the steering. The repo has a
CLAUDE.mdthat states the stack, the anti-abstraction rule, and the git discipline:mainmust always be stable and device-tested; new work goes onfeat/branches; flash to the physical device before merging. Written rules beat repeated prompting — the agent reads them every session, so the tenth session behaves like the first. - I stayed the hardware-in-the-loop. An agent can compile for the ESP32; it can’t feel that a touch target is 20 pixels too small for a small thumb, or that the feedback screen lingers a beat too long. Every loop ended with me and the physical device. The calibration constants above are the purest example — values no model could produce, because they live in my specific panel.
- The product rules were mine. Five questions, stars only, no penalties — no tool proposed those. The AI made the build fast; the constraints made it good.
What surprised me is how well embedded work suits this workflow. Firmware has a brutal, honest feedback loop — it compiles and runs on the device, or it doesn’t — and that keeps an AI pair grounded in a way web work sometimes doesn’t.
Build one
Everything is public and written for a non-technical parent:
- Buy the board (search “Hosyond 4.0 ESP32” — the 320×480 ST7796S variant).
- Clone the repo. The macOS setup script installs PlatformIO and the serial driver.
pio run -t uploadflashes it over USB-C.- Run touch calibration. Really.
- Edit the question arrays to match what your kid is working on. This is the best part — when the questions track what’s happening at school, the toy stays relevant for months.
About 30 minutes end to end, no soldering. There’s a 30-second demo if you want to see it running first.
The metric I care about isn’t frame rate. It’s that on the last long drive, he picked this up instead of asking for the tablet.
Part 2: the 7-inch version — a dual-chip ESP32-P4 build with a laptop-class display pipeline, real audio, and over-the-air updates. Same game, very different machine.