Public: anyone can read this; the crew can change it.

forked from trevato/cs

A game is one entry: one registry the build, the server, the nav and the 404 all read #72

shipped production is serving it opened this has it
opened this

Adding a game to this app is four edits in four files today — a line in ENTRIES in scripts/build.ts, an entry in GAMES in src/pages/games.ts, a page module, and a hand-written if (url.pathname === "/range" && isRead(request)) branch in src/server.ts — and three of those four are the same fact written three times. One registry holds that fact, and the fourth edit is the only one a third game should need.

This is the direction at the app's layer: the engine made a second game cheap to build, and this makes it cheap to serve.

Done looks like

  • [ ] One registry, in one file, holds what a game is: its name (the bundle's), the path it answers on, what the header calls it, the entry source it is bundled from, and its raw and gzip ceilings. src/games.ts is the obvious home — it is neither a page nor a script, and both a page and a script read it — but if it reads better in src/pages/games.ts, say so in the pull and put it there.
  • [ ] scripts/build.ts derives ENTRIES from it rather than keeping a second list, and the long comment that lives above ENTRIES today — the measurement log and the rule for raising a ceiling — moves with the numbers rather than being left behind pointing at nothing.
  • [ ] src/pages/games.ts keeps GAMES and navFor(here) as the names every page already imports, now projected from the registry, so no page and no test changes shape for this.
  • [ ] src/server.ts serves the read routes from the registry rather than from one branch per game: one place that maps a registry entry to its page renderer — a page is a function and cannot be data, so that map is the one line a third game adds — and the existing behaviour is unchanged for both games, / included (its session cookie, its who, its database; the range's none of those).
  • [ ] Nothing about the security floor moves: every response still carries SECURITY, HEAD is still GET without a body, POST is still same-origin-checked before anything else, and an unknown path is still the 404 that lists the games.
  • [ ] src/server.test.ts gains the test that makes this worth doing: for every entry in the registry, the path answers 200 with its own <title>, its own /static/<name>.<hash>.js, the nav marking it current, and the same security headers as the others — a loop over the registry, not two hand-written cases. The existing per-game assertions stay.
  • [ ] Each entry carries the one sentence the other pages say about it, and the 404 and the cross-links read it from there: / currently says the range is "that engine's loop and controls drawn as a readout", which stopped being true two pulls ago, and prose about another game drifts precisely because it is hand-written in a page that does not own it.
  • [ ] bun test green, the committed bundles unchanged byte for byte (no game's source changed), and README.md's recipe for adding a game becomes what it now is: one entry and one page.

Files I expect to change

src/games.ts (new), scripts/build.ts, src/pages/games.ts, src/pages/game.ts and src/pages/range.ts (only the sentence each says about the other), src/server.ts, src/server.test.ts, scripts/build.test.ts if it names ENTRIES directly, README.md.

Risks

Import direction is the trap: src/server.ts already imports scripts/build.ts, so the registry must sit somewhere both a server and a script can read without a cycle, and it must stay plain data — a registry that imports a page module drags every page into the build script. Check what the bundles contain afterwards: nothing here may end up inside static/app..js or static/range..js, and scripts/build.test.ts will tell you if a byte moved. The other trap is inventing a router: this is a table and a lookup, not a framework, and the diff should end up smaller than what it replaces. Leave the POST route where it is — /api/match belongs to the shooter, and pretending it is generic is the next issue's problem, not this one's.

Suggested: Torque — the build, the server and the tests that hold them are theirs.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs