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

forked from trevato/cs

One GL recorder, behind the door: the renderer's test double stops being written four times #364

Merged opened this

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

Merged

The engine now ships one fake WebGL2 context, `fakeGl()`, and its `GlRecorder` type from `src/engine/gl.ts`, alongside `fakePage`. It replaces four copies that had drifted apart: `stubGl` in `renderer.test.ts` and `glRecorder` in the shooter's, range's and example's `stage.test-helper.ts`. The range gains the `deleteVertexArray` and `deleteBuffer` its copy was missing. `bun run test` (typecheck pl…

shipped production is serving it deploy ae07c2d

opened this

The engine now ships one fake WebGL2 context, fakeGl(), and its GlRecorder type from src/engine/gl.ts, alongside fakePage. It replaces four copies that had drifted apart: stubGl in renderer.test.ts and glRecorder in the shooter's, range's and example's stage.test-helper.ts. The range gains the deleteVertexArray and deleteBuffer its copy was missing. bun run test (typecheck plus bun test) passes, 1447 tests, and rg "GL_ENUMS|export function glRecorder" src finds nothing.

The names are checked against the renderer. src/engine/gl.test.ts pulls every gl.<name> out of renderer.ts with comments removed. It fails if the renderer uses a name the recorder doesn't answer, or if the recorder still answers a name the renderer no longer uses. A separate test adds a fake gl.deleteTexture call and checks that the comparison reports it.

Written-out lists, not the example's Proxy. A Proxy needs no upkeep, but it answers any name, so a typo or a renamed GL call would pass every test. The lists are explicit and the test above keeps them in step with the renderer. The recorder still only records what was asked for and never grows into a fake GPU; that rule moved into gl.ts's docstring.

Resource kinds are now consistent. Shaders are "Shader" like every other kind; renderer.test.ts used "shader". No test reads that value. renderer.test.ts keeps its resources history.

The games keep only their own parts. Each helper keeps its ids, actions, audio and install(), and sets scene.gl = fakeGl(). The range's two test files import GlRecorder from the engine now. The docstrings in the three helpers and in page.ts that argued the recorder belonged to each game now say what is true.

Door, version and guide:

  • index.ts exports both names.
  • surface.json moves to 0.9.0, since two names were added and none removed.
  • GUIDE.md has a new ### gl section with its measured weight. The page section and the "a host" row of the seam table now name fakeGl. The page and whole-door weight lines are updated to what scripts/cost.ts --guide reports today.

Not in any bundle:

  • All three bundles are exactly the same size as on main (app 125,524 B, range 40,816 B, example 25,004 B).
  • gl.test.ts checks that no built bundle contains the module's marker sentence.
  • It also checks that no non-test file outside gl.ts and index.ts mentions fakeGl, since tree-shaking could drop the sentence without dropping the code.

Not done: nothing reads GL enum values from WebGL2RenderingContext itself; the numbers are only guaranteed distinct, which is all the tests need.

Where to look: src/engine/gl.ts, src/engine/gl.test.ts, and the ### gl section of src/engine/GUIDE.md. Try it with bun test src/engine/gl.test.ts; deleting a line from either list in gl.ts makes it fail and name the missing call.

🤖 Generated with Claude Code

Closes #331

commented

The engine now ships one fake WebGL2 context, fakeGl(), and its GlRecorder type from src/engine/gl.ts, alongside fakePage. It replaces four copies that had drifted apart: stubGl in renderer.test.ts and glRecorder in the shooter's, range's and example's stage.test-helper.ts. The range gains the deleteVertexArray and deleteBuffer its copy was missing. bun run test (typecheck plus bun test) passes, 1448 tests, and rg "GL_ENUMS|export function glRecorder" src finds nothing.

The names are checked against the renderer. src/engine/gl.test.ts pulls every gl.<name> out of renderer.ts with comments removed. It fails if the renderer uses a name the recorder doesn't answer, or if the recorder still answers a name the renderer no longer uses. A separate test adds a fake gl.deleteTexture call and checks that the comparison reports it.

Written-out lists, not the example's Proxy. A Proxy needs no upkeep, but it answers any name, so a typo or a renamed GL call would pass every test. The lists are explicit and the test above keeps them in step with the renderer. The recorder still only records what was asked for and never grows into a fake GPU; that rule moved into gl.ts's docstring.

Resource kinds are now consistent. Shaders are "Shader" like every other kind; renderer.test.ts used "shader". No test reads that value. renderer.test.ts keeps its resources history.

The games keep only their own parts. Each helper keeps its ids, actions, audio and install(), and sets scene.gl = fakeGl(). The range's two test files import GlRecorder from the engine now. The docstrings in the three helpers and in page.ts that argued the recorder belonged to each game now say what is true.

Door, version and guide:

  • index.ts exports both names.
  • surface.json moves to 0.9.0, since two names were added and none removed.
  • GUIDE.md has a new ### gl section with its measured weight. The page section and the "a host" row of the seam table now name fakeGl. The page and whole-door weight lines are updated to what scripts/cost.ts --guide reports today.

Not in any bundle:

  • All three bundles are exactly the same size as on main (app 125,524 B, range 40,816 B, example 25,004 B).
  • gl.test.ts checks that no built bundle contains the module's marker sentence.
  • It also checks that no non-test file outside gl.ts and index.ts mentions fakeGl, since tree-shaking could drop the sentence without dropping the code.

Also fixed: the flaky range boot test that failed the first preview. The range seeds each run from the clock. Its pop-up drill hangs plates with their feet up to 130 units high, but SHADOW_REACH in src/range/scene.ts was 128. On about 1.7% of seeds the first plate cast no shadow, and "every standing plate is one more draw" failed; main has the same flake, from #330.

  • SHADOW_REACH is now 160.
  • A new test in src/range/scene.test.ts puts every drill's highest plate in a frame and expects a shadow under it. It failed before the change.
  • A script over all 65,536 seeds now finds none without a shadow, and the boot test passed 60 runs in a row.
  • Side effect: every plate's shadow is a little darker and less wide than before.

Not done: nothing reads GL enum values from WebGL2RenderingContext itself; the numbers are only guaranteed distinct, which is all the tests need.

Where to look: src/engine/gl.ts, src/engine/gl.test.ts, the ### gl section of src/engine/GUIDE.md, and SHADOW_REACH in src/range/scene.ts. Try it with bun test src/engine/gl.test.ts; deleting a line from either list in gl.ts makes it fail and name the missing call.

🤖 Generated with Claude Code

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs