Inspiration

New York has been playing tower defense for fifty years. Trash goes to the curb in plastic bags, the rats organize around it, and the city's new containerization program is the biggest balance patch in municipal history. We're Made in Brooklyn Games — we live here — and we wanted to build the smallest possible game about that arms race.

The design thesis came before any code: the rats are running the same loop as the player — chasing a pile that resets and never fills. Your trash is your money, and your money is what the rats come for. Everything else in the game is that sentence, mechanized.

Two other inspirations: Basquiat, borrowed as a clarity system rather than a costume (thick outlines, flat color fields, five colors total, defined as code tokens from day one), and the collectathons we grew up on — our worthless subway tokens are Banjo-Kazooie by way of the MTA: "exact fare for a train that no longer runs."

What it does

Rat City is a ~7-minute, portrait, fully offline tower defense with one currency. Trash bags are your income, your build cost, your bait, and your final score. The twist is one rule: every liquid bag on the curb makes tonight's wave bigger. So you place bags as bait to route the rats, spend them on towers (a bodega cat, a snap trap, a bin), or containerize them — theft-proof and invisible to rats, but frozen until you dig them back out. Checking versus savings.

A DSNY truck banks your curbside hoard into score every third dawn, so pickup eve is a self-inflicted boss fight: maximum bags, maximum wave. If a rat grabs a bag, you can tap it mid-drag and fight for it back; every bag that escapes pushes an infestation meter toward RAT STORM, the lose state. Survive to night 10 and you earn a 90-second, three-phase Pizza Rat.

How we built it

Doc-first, then agent. We followed the competition case study's process: design interview → a 15-section GDD locked before any code → a two-hat expert review → handoff to Claude Code with four hard constraints set on day one (single-player, fixed portrait, fully self-contained, one readable index.html). The GDD is the declared source of truth: when code and doc disagree, the doc wins — until playtesting revises it, at which point we revise the doc first.

Tech: Three.js with an orthographic camera and flat billboarded sprites (no 3D models), six source modules assembled by a build script into a single unminified index.html, libraries vendored locally, zero network requests at runtime. All audio is procedural Web Audio — zero audio files; every squeak, snap, and truck horn is synthesized. Sprites load through a manifest, so final art drops in by filename with no code changes. Fixed-timestep sim decoupled from render, object pools for rats and tokens, and three test layers: sim unit tests, a DOM smoke test, and a headless Playwright playthrough of night 1. Debugging on a phone with no console meant building our own tools — an on-screen error banner and a ?debug live sim readout.

Challenges we ran into

  • The most natural player move triggered our worst bug. Spending everything on day 1 is the obvious opening — and with zero bags on the curb, rats spawned targetless and instantly despawned. An invisible wave. Lesson: test the default path hardest.
  • "Functional" is not "fun." With the build working, we ran a structured fun-pass and named six failure modes — passive nights, a solved strategy, weightless hits, pacing drag among them. The fixes were surgical: bags became player-placed bait (the day phase became a real decision), the truck now banks curbside bags only (killing the bin-everything strategy), and theft became a fight instead of a spectacle. We shipped that revision the morning of the deadline.
  • Budgeting the juice. If everything screen-shakes, nothing does. We wrote a rarity-tiered effects budget — one signature sound per tier, shake reserved for three moments — and then had to actually obey it.
  • The constraint set. Fully offline + single file + portrait sounds limiting; it forced procedural audio and manifest-driven art, and both made the game better.

Accomplishments that we're proud of

  • A complete 10-night arc — a hand-tuned curve, a deliberately quiet night 9, and a three-phase boss — in about a week of build time.
  • One currency doing five jobs. No gems, no gold, no energy, no anything else.
  • Night 9 is 35 seconds of near-silence, on purpose. We shipped quiet as content and trusted contrast to make night 10 land.
  • Acceptance tests written as felt experiences, not pass/fail technical states.
  • The entire game is one readable HTML file a judge can open in a text editor.

What we learned

  • One mechanic done well beats four that work partially. Our cut list is longer than our feature list, and the game is better for it.
  • Loud is a ratio. Quiet has to be engineered — silence before the wave, a held beat after — or the loud moments have nothing to land against.
  • Roughly two-thirds of the effort belongs after feature freeze. Tuning is the game.
  • Working with a coding agent, the document is the API. Every ambiguity left in the GDD resurfaces later as a bug in the build.

What's next for Rat City

  • Rat adaptation: rats that learn your layout and force tower rotation.
  • The pigeon strike: finally giving the subway tokens teeth, as a summonable one-time air strike.
  • New blocks, new boroughs, new sanitation problems.
  • The flip: a playable rat-perspective survival mode. The rats want what you want — eventually you get to want it as them.

Built With

Share this project:

Updates

Submission history