Braineos now has a game: Tower Defense, played on whatever deck you’re studying. Enemies walk a road, you build towers beside it, and gold comes from answering questions from the deck. This is how we built it, and how we tested the balance before anyone playtested it.
Start from code you already own
We didn’t start from zero. There was an earlier vanilla JavaScript prototype: an idle tower defense game on an HTML5 canvas, with three tower types, four enemy types, three levels, upgrades, wave scaling and procedural sound. It also had everything an idle game needs and a quiz game doesn’t: offline earnings, idle income, prestige.
We kept the rules and dropped the idle loop. The tower, enemy and wave data, the path following, targeting and the upgrade maths were ported into typed code. The drawing and the menus were rewritten.
Keep the rules pure
The engine is plain TypeScript with no canvas, DOM or timers. One function, step(state, dt), advances enemies, towers, projectiles, waves, gold and lives, and returns the new state plus events such as “enemy killed” or “life lost”. Given the same state and a seeded random source, it always produces the same result.
That one decision paid for most of what follows:
- Tests. Almost all of the tests run against the engine, with no browser.
- A replaceable renderer. The canvas layer only draws, and takes its colours from the site’s theme, so the game looks right on any site built from the codebase.
- Real DOM where it matters. The question panel, HUD and results screen are ordinary React components, so the text is crisp, keyboard-accessible and read out by screen readers. Only the map, towers, enemies and projectiles are on the canvas.
- A bot that can play the game. Which brings us to balance.
The balance problem
The original numbers assumed idle income: gold trickling in on a timer. In a quiz game, gold arrives at the speed someone can answer questions. That changes everything, and we wanted a clear contract before anyone playtested:
- someone who knows the cards should win;
- someone who ignores the questions should lose;
- the middle should feel like a fight.
Let a bot play it
Because the engine is deterministic and has no timers, a scripted player can play full runs without a browser, as fast as the computer can step the engine. Ours answers one question every 5 seconds, gets each right with probability p, and buys towers from a fixed shopping list. These are its results in simulation, over 12 seeds:
| Bot answers right | Result |
|---|---|
| 0% | Loses on wave 6, every time |
| 40% | Wins 1 run of 12 |
| 55% | Wins 5 of 12 |
| 70% and up | Wins 12 of 12 |
Getting there took real changes from the prototype. Level 1 became 10 waves ending on a boss, with 5 tower slots, 50 starting gold and 20 lives. A right answer pays 42 gold, plus a small bonus for each answer in a streak. Defeating an enemy pays only 30% of what it paid in the idle game, so towers still feel like they earn, but you can’t win by waiting.
We first aimed for “ignoring the questions loses by wave 4”. With 10 lives it did, but the whole curve became much more luck-dependent in the first minute. With 20 lives the no-answers bot lasts to wave 6, which felt right for a learning game.
The table isn’t just in a doc. It’s a test. Change any number in the game data in a way that breaks the contract, and the build fails.
The biggest unknown is human answer speed. The bot answers every 5 seconds. If real players take 10, the game is harder than the table says, and the gold per answer is the first number we’ll raise.
Don’t let the game game the app
Braineos has a streak and a weekly leaderboard, and a game shouldn’t become the fastest way up it. A finished run records one score: the number of different cards answered right at least once. That can never be more than the deck has, the same ceiling as a study session.
Play also doesn’t touch the spaced-repetition schedule. Fast, partly guessed multiple-choice answers would make it noisier, so reviews still come from studying.
Small decisions that made it playable
- Flashcards become multiple choice. The right answer is the card’s own definition, and the wrong ones are definitions from other cards in the same deck, chosen to avoid duplicates and give-away lengths.
- Long answers are skipped. A sentence-long definition makes a bad button, so those cards are left out, and the game says how many.
- Missed cards come back. They return about five questions later, so a run spends more time on what you don’t know.
- Relaxed mode slows the game rather than pausing it. The first design paused the waves while a question was open. But a question is always open, so that would have frozen the game forever. Running at 40% speed gives people time to read.
What’s next
Levels 2 and 3 from the prototype, and then the real test: how people actually play, compared with the bot.
