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

forked from trevato/cs · proposes · 4 behind

The second game's plumbing lands first: /range is served, bundled and proven engine-only #29

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

`GET /range` now answers with its own server-rendered page from `src/pages/shell.ts` — its own title, heading, prose and overlay, the same security floor as `/`, `HEAD` answering like `GET`, no session cookie because the page stores nothing — and its only script is `static/range.2543880d32.js` (7.1 kB), built from the new `{ name: "range", entry: "src/range/main.ts" }` row in `ENTRIES`. `/` links…

shipped production is serving it deploy ae07c2d

opened this

GET /range now answers with its own server-rendered page from src/pages/shell.ts — its own title, heading, prose and overlay, the same security floor as /, HEAD answering like GET, no session cookie because the page stores nothing — and its only script is static/range.2543880d32.js (7.1 kB), built from the new { name: "range", entry: "src/range/main.ts" } row in ENTRIES. / links to it and it links back.

What runs there is the plumbing and only the plumbing: src/range/binding.ts is the range's own key table (50 Hz, its own actions — no buy, no scoreboard, no weapon slots, a keyboard key for the trigger) plus the held-actions-to-intent mapping; src/range/readout.ts draws a horizon on #scene and a panel on #hud with plain 2D calls; src/range/main.ts wires createControls and createLoop to the shell's ids and prints ticks run, milliseconds a frame, the held actions, the movement they and the thumb stick add up to, and yaw and pitch. A canvas that gives no 2D context becomes a sentence in the overlay, not an exception. No room, no targets, no physics and no WebGL — those are #13's, and the page says so.

Worth looking at: src/range/independence.test.ts, which reads every source under src/range/ and fails on any import that is not src/engine/, src/pages/shell.ts or a sibling, reusing sources/specifiersOf from src/engine/boundary.test.ts rather than copying the regex (the price is the engine's four boundary tests being registered a second time, noted in the file); and src/range/dom.ts + boot.test.ts, which boot the real entry against a document of plain objects and a clock the test moves, so a key, an on-screen button, a thumb stick, a dragged finger, a locked mouse and a missing context are all checked with no browser. src/server.test.ts pins the route's status, headers, script and every id the entry looks up, and that cs's ids and bundle are not on it.

I did not refactor the dispatch into src/routes.ts: /range is one more if beside /, with withoutBodyIfHead/isRead lifted out so both read in one line — the server still fits in one read, and adding the game and moving the table in one pull is the thing the issue warns about. Measured locally: /range answers in 0.5–0.8 ms warm (first request 8 ms, cold start), bun test is 249 green across 32 files, both bundles rebuilt and committed. The frame rate itself is what the page prints for you — there is no browser in this sandbox, so I have not measured 60 fps, only the frame time the readout reports.

🤖 Generated with Claude Code

Closes #24

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs