Every button on my game's main menu opened the same mode.
I found that out after a buyer paid for it. Not before. Four modes existed, four buttons existed, four buttons led to one screen. The game worked. The door didn't.
I'd run 26 tests before shipping and every one passed. That's the part worth writing about.
The harness was testing a road I never drove
My test script called the mode functions directly. startMode('A'), startMode('B'), and so on, then checked that taps scored, bubbles popped, audio fired. Twenty-six green checks.
What it never did was click a menu button.
So when a typo in the click handler pointed all four buttons at mode A, my suite had nothing to say. The logic underneath was perfect. The interface on top was broken. And I had a report that said "26/26 clean," which felt like proof and was actually just a description of my own test.
The fix was boring, and now it's law: the test has to walk in the same door a player walks in. Click the menu. Read the screen. Take the first tap. If the test reaches past the interface to call internals, it proves nothing about the interface, because the interface is the part you didn't touch.
If you only take one thing from this post: a harness that bypasses the entry point isn't a weaker test, it's a different subject. It can pass while the thing you shipped is broken, and it will.
The uploader wasn't broken, my file was
I tried to publish the game as an embeddable interactive bundle and the platform rejected it. I tested four tiny files, concluded the scanner was broken, and told someone it rejected "every JavaScript game ever written."
Wrong. I compared my file against one that had uploaded fine. That one contained zero instances of the string function( and no localStorage access. Mine had 25 and 2. The scanner was a ban list, it worked exactly as designed, and my file was the one that tripped it.
The fix took ten minutes: rewrite anonymous functions as arrow functions, drop the two storage calls, re-run the real menu walk, upload. First try.
The lesson isn't about that platform. It's that "the tool is broken" is a conclusion, and conclusions cost less than checks. One diff against a known-passing file would have saved me an hour and a public statement I had to walk back.
One drawing routine, everywhere
Every mode in the game draws the same fox. Not four foxes that look similar. One function, one set of coordinates, called from four places. Same with the bubbles and the letter tiles.
When the fox needed to sit in one mode and run in another, that's a parameter, not a redraw. When the proportions were off in one place, they were off everywhere, which sounds bad until you remember you only have to fix it once.
The temptation with a small game is to copy-paste the drawing code per screen because each screen wants a slightly different pose. Six months later you have six characters that are almost the same character, and the player notices the drift even if they can't name it. Consistency is cheap when it's structural and expensive when it's a decision you make per screen.
Cutting 26 audio clips out of one song
I needed the 26 letter lines from a 90-second vocal take. Standard approach: detect silence, cut at the gaps.
It doesn't work. There weren't 26 usable gaps, there were 27, and one of them put "L" where "N" belongs. No threshold value between -25 and -45 dB produced a sane 26-part split.
What did work: get word-level timings from speech recognition, then walk backwards from each reported start to the last frame below the noise floor and cut there. ASR onsets run late by up to half a second, so the reported time is a map, not a cut point.
Then verify by listening programmatically, not by trusting the numbers. Small model passes over the clips caught a "J" that carried the attack of "K" and a "Z" whose tail had been sliced off. Both were invisible in the waveform stats I'd been checking.
What I'd tell myself two weeks ago
Test through the door a user uses. Diff against something that works before you blame the tool. Keep one drawing function per character. And when you cut audio from timings, trust the timings to get you close and your ears (or a model's ears) to tell you when you're wrong.
That last one is the general version: the metric is a proxy. The thing itself is the thing itself.
The game this is about is called Foxfire English: four modes for learning the alphabet, letters, sounds, words, spelling, built around one animated fox and a song. It runs in a browser, no install, free to play.
Play it here: https://foxutils.com/foxfire-english/
If you're building something like it and hit a wall on the same problems, I've already fallen into most of the nearby pits. Happy to compare notes in the comments.
Top comments (0)