Underneath the broom
A chore tracker that plays like an RPG, built for one household and shipped as a single file. It runs one board across every phone in the house. Then it grew a Colosseum, a sweeping company, two looks and a sound for every Tool. This page is what’s underneath, for anyone curious how it works rather than doing the dishes.
Eight rooms, eight mechanisms
Each part of the game is a different kind of problem underneath. What a player sees is on the left. How it works is on the right.
01Two looks, one hero
Every hero, Tool, foe and room is a drawing, and every drawing comes in two looks: Warband, knife-cut and bold, and Paper Guild, cut paper and brass pins. Each hero picks a look, light or dark, and the whole game changes with them.
No image files for heroes, gear or foes. Two art kits draw SVG from code, and both answer the same calls: hero(look, gear), item(id), held(look, tool), FOE[id](mood), SCENE, DUST, ICON. The game only ever draws through one name, so changing looks is a single assignment. Warband ships inside the file. Paper Guild (1.16 MB) loads only for a hero who picks it, written in before the first paint so the page never flashes the other look.
02Hold to seal
A tap on the seal only reminds you to hold. The quest seals when a gold ring has filled around it, and scrolling past never seals anything by accident.
Pointer events with capture. The ring is a conic gradient driven by a CSS variable on requestAnimationFrame, but the seal itself is a plain timer, so a dropped frame can never swallow a real press. A drift past the finger’s slop, or the browser taking the gesture for a scroll, resets it. A sealed quest pays only when the guild master accepts it.
03Fifty foes, tuned by simulation
One bout opens per level, up to level 51. Five rooms, ten foes to a room, a champion at the end of each. Gear and fight skills matter: a hero who skips them stalls.
Every rule lives in one file, rules.js: what each slot and charm does, the four fight skills, a hero’s Power, how each foe is scaled to its bout, and the fight’s own steps. They are pure functions with no page and no save, so the game and a fight simulator run exactly the same code. The simulator plays heroes through the whole season, and the tuning constants came out of it, not out of guesses.
04Twenty-six ways to swing
A broom sweeps. A plunger slams. A sponge squelches, a dish-rag boomerang comes back around, and the rarest Tools light up the whole arena. Every Tool has its own swing, its own effect, its own sound.
attacks.js gives each Tool a hand motion (a CSS animation), a reaction from the foe, and an effect drawn on a canvas laid over the arena: light, water, dust and weather, never the skin, so both looks share it. The 26 sounds were made with ElevenLabs, one take each to spend few credits. A script cut each one to its first second or two, faded it, levelled it and encoded it: 444 KB for all 26. Reduced motion keeps the sounds and a third of the particles.
05Music that knows where it is
The Colosseum plays “Iron Vow” from Path Not Taken. Sweep Co. plays “Old Tree” from Tether Ball. The quests stay quiet. One button turns it off, everywhere.
Both songs are Josh’s, made with ElevenLabs Music for his other games. Each loops between two points picked by ear: Iron Vow from 13.7 s back from 75.4 s, so the intro plays once; Old Tree starts at 27.5 s, past its slow opening. Only the song for the room you’re in stays decoded, so a phone holds one song in memory, never two.
06Sweep Co., priced by a clock
A side game: tap a dust pile for silver, hire a crew, and see how far the company goes. Chores keep it running. What it grows into is for players to find.
Every price came out of a simulator that plays the company on a real clock: three chores a day, the hours they fuel, the helpers bought in order. The first version paid back a helper in minutes while a chore fuelled four hours, so a hero away for a day came back rich. The fix was in the prices, checked by the same simulator, not a cap on idle time.
07The hall online
Open a hall on one phone and it hands you a code. Join with that code on the others and everyone plays the same board. No accounts. Leave the hall and the phone keeps its own save.
A free Postgres with every table locked (row-level security, no policies), reachable only through a few security definer functions that each take the code. Sync runs after every save, on return to the app and when the phone comes back online. The board merges per quest in the database, newer seal wins, so a phone that joins with a fresh board can never wipe another’s seals. A weekly cron pings the database so the free project never pauses.
08This page
The site you just came from switches looks like a hero does. Its quest board seals, its hero grows, its Colosseum opens the Cellar, and its Sweep Co. hires a first crew. Past the first dozen levels, everything is sealed.
The site draws nothing of its own. A headless browser opens the game, asks both kits for each hero, Tool, foe, scene and icon the page shows, and saves them as two JSON files (about 90 KB and 110 KB compressed); the second loads only if you switch. What the site keeps sealed is never written into those files, so its source spoils nothing, and a test fails if a sealed name ever turns up. The Colosseum runs the game’s own attacks.js and sounds, trimmed to the Tools on show. The phone screenshots are the real app, captured the same way with a level-4 hero.
How it grew
From a chore list to a season, in public, one household at a time.
- The first board goes live the same evening: chores as quests, gold, a shop.
- One board across every phone, through a hall code. Two days later the guild master starts accepting each sealed quest.
- Faces become a character builder: four kinds of hero, drawn in code.
- Warband: a new art direction, the Colosseum, and Paper Guild beside it.
- Sweep Co. opens.
- Season 1: 180 pieces of gear, 50 foes in five rooms, fight skills.
- Twenty-six Tool attacks with their own sounds, and music in both games.