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

forked from trevato/cs · proposes · 4 behind

The guide’s code runs: src/engine/example.ts is the smallest game on the package, and a test plays it #77

Merged opened this

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

Merged

`src/engine/example.ts` is the smallest game this package can run: 79 lines, one import (`./index.ts`), a host handed in as `{ surface, window, document }`, a bindings table, a 60 Hz tick, one room box to stand in, one plate traced with `rayBox`, a score, and a `step(world, dt, held)` that takes plain data and returns plain data. It opens no canvas, no WebGL and no sound device, and does nothing a…

shipped production is serving it deploy ae07c2d

opened this

src/engine/example.ts is the smallest game this package can run: 79 lines, one import (./index.ts), a host handed in as { surface, window, document }, a bindings table, a 60 Hz tick, one room box to stand in, one plate traced with rayBox, a score, and a step(world, dt, held) that takes plain data and returns plain data. It opens no canvas, no WebGL and no sound device, and does nothing at module scope — purity.test.ts already covers it, since its walk picks the file up for free. Its header says it exists so the guide's code can be executed, names what it leaves out, and points at src/range/ as the real second game.

src/engine/example.test.ts plays it against a stub page and a stub clock: a seeded 600-tick run scores the same twice down to the last plate, a shot down the target's bearing hits while one twenty degrees off either way misses, a second of elapsed time is sixty ticks whether it arrives in ten frames or a hundred (and a five-second frame is clamped to the loop's eight steps), and KeyW becomes the "forward" the step function reads while an unbound key moves nothing.

guide.test.ts gains a fourth rule: every fenced block in GUIDE.md is a run of consecutive lines of example.ts after trimming and dropping blanks. The matching policy is written at the top of the file — any contiguous slice, any order of blocks, but no stitching distant lines together — and the failure message names the first line of the block that is not where the block puts it. All nine blocks in the guide are now slices of the example, and the guide opens by telling you to read it first.

Two things worth a look. The sections whose tools the example cannot use headlessly — grid, mesh, texture, sound, overlay, renderer — lost their code blocks and keep prose that points at src/client/models.ts, materials.ts, audio.ts and src/range/readout.ts instead; that is the cost of the rule as specified, and it is visible in the diff. And boundary.test.ts could not stay untouched: its rules are "every module is behind the door" and "no module goes through the door", and the example is deliberately neither — documentation that ships in no bundle and uses the package the way a game outside it does. It is now one named exception (notAModule) with the reason written down, and it pays for itself with a new test that the example imports the door and nothing else. The door's export list is unchanged.

bun test is green: 452 tests across 51 files in 4.4 s. The server still boots and / answers 200. README points at the example next to the guide.

🤖 Generated with Claude Code

Closes #58

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs