← Back to Portfolio
Personal

Head Rush Kids

Work in progress. The game is built, live and playable, but payments are still in Stripe test mode and nothing is instrumented, so there are no player, retention or revenue numbers here yet. It is in the portfolio for what it took to build, not for what it has done.

Hold a phone to your forehead, tilt down when your group gets the word, tilt up to skip, 60 seconds a round. 28 decks, 50 cards each, 1,400 cards total, every one a word plus a large emoji so a child who cannot read can still give the clue. It opens from a link with no install.

The reason it exists is that my own kids could not play the games in the app store. The good ones assume you can read, and every one of them charges again for content that should have shipped with it.

The reason it took a year is one bug.

headrushkids.com →
1,400
Cards across 28 decks
0
npm dependencies and no build step
1,217
Lines of application code
3
Unlock tiers: 4 free decks, 4 for an email, 20 paid
6
Serverless endpoints
3 months
That one motion bug stalled the project

The bug that stalled it for three months

A phone held flat against a forehead sits exactly where the browser orientation API breaks down. My first attempt read the gamma angle, which flips sign near vertical, so tilts registered twice or not at all. Three months of the project died on that.

The fix was to stop reading orientation angles and read the gravity vector instead. The devicemotion event reports acceleration including gravity, and the z component of that vector gives a clean pitch angle with no discontinuity in the forehead position. Tilt down is positive, tilt up is negative, and it behaves the same in both landscape directions.

That is the whole reason this project is worth showing. Not the game. The three months it took to learn that the obvious API was the wrong one.

Tuning it for a room full of kids

On top of the gravity vector sits the tuning that makes it feel right. Three sensitivity presets expressed in real degrees from vertical: 45, 35 and 25. A card only re-arms once the phone returns within 15 degrees of vertical and at least 400 milliseconds have passed, so one enthusiastic swing cannot burn two cards. A single sign constant flips the whole thing if a device reports gravity inverted.

There is a debug mode that prints live pitch and lets arrow keys drive the same code path, so most of the work could be tested on a laptop instead of by picking up a phone after every change.

Portrait is for setup, landscape is for play. The round starts on its own when the phone turns and pauses if it turns back. Orientation events are unreliable across mobile browsers, so that runs off listeners plus a polling watchdog rather than trusting any single event to fire.

1,400 cards, tagged at the source

Sixteen cards per deck was not enough. A deck ran out before the timer did. Getting every deck to 50 meant writing 952 new cards.

I ran four Claude subagents in parallel, each owning seven decks, each working against the same fixed schema: a word, one emoji, and three tags covering what kind of thing it is, whether it is best acted, sounded or described, and whether it is real or fictional. They wrote to separate files and a merge script checked every card before it landed, rejecting duplicates within a deck and any invalid tag. All 28 decks came out at exactly 50 with no failures.

The tags are not decoration. They are the schema the capture layer records against.

Where it stands

Shipped: the game, 1,400 cards, the motion engine, the three-tier unlock, Stripe Checkout with session verification, two domains, a manifest and icons so it installs as a real web app, and a plain-language privacy policy written for parents.

Not done: payments are in test mode, the capture layer and email list are unconfigured in production, and it has never been put in front of anyone at scale. The next step is the app stores, which is what the privacy policy and the installable wrapper were for.

One architectural note I would keep. The whole game is one HTML file, one data file and six serverless functions. No framework, no bundler, no npm dependencies. It deploys by pushing a folder and it loads instantly on a bad phone at a birthday party, which is the only performance test that matters here. No model runs in the shipped product. AI was the build method, not the feature.

Head Rush Kids — image 1
The deck store. Each tier states its price once in the section header
Head Rush Kids — image 2
Results screen with a per-card recap
Head Rush Kids — image 3
The unlock sheet, behind a press-and-hold gate so a child cannot trigger it
Head Rush Kids — image 4