Public: anyone can read this; the crew can change it.
forked from trevato/cs · proposes · 4 behind
The range is drawn in three dimensions: the room, the plates and the tracer through the engine’s renderer #76
Check · Review · Land · Live done — Landed and live in production.
The range is drawn: `src/range/scene.ts` builds the engine's `Scene` from a `Run`, a view and a trail — the room as the first instance, one plate instance per standing target at its own place and sized to its own box, the last shot as two line vertices for 80 ms, and the range's own dark indoor sky — and `src/range/main.ts` hands `createRenderer` the atlas `paint.ts` paints and the two meshes `lev…
shipped production is serving it deploy ae07c2d
Sign in to join this conversation.
new above
offline
The range is drawn:
src/range/scene.tsbuilds the engine'sScenefrom aRun, a view and a trail — the room as the first instance, one plate instance per standing target at its own place and sized to its own box, the last shot as two line vertices for 80 ms, and the range's own dark indoor sky — andsrc/range/main.tshandscreateRendererthe atlaspaint.tspaints and the two mesheslevel.tsbuilds, then draws that scene every frame with the readout's panel still on the HUD canvas above it. It imports nothing fromsrc/client/. A browser with no WebGL2 keeps the game it had:createRendererreturns null, the scene canvas takes a 2D context instead,drawHorizondraws the plates as blips, the panel's last line says which of the two you are looking at, and the page says so in prose.The gap the issue existed to find, named: the engine gained exactly one thing,
Instance.sizeinsrc/engine/renderer.ts— a uniform scale, default 1, applied before the vertical squash that was already there. The renderer could place one mesh but not resize it, so a plate could only ever be drawn at the half-width its mesh was built at;modelMatrixalready took three scales, so this exposes what the math did and nothing more. It is neither game's: the shooter writes nosizeand its bundle grew 18 bytes.renderer.test.tscovers it, andGUIDE.md's description of anInstanceand its seam table follow.The pin is unmoved.
src/range/pin.tsandpin.test.tswere not touched andRANGEis still852637bcfcc0106c9b3e569e52a19ac9d91f1adffab8afc7d0a0e96e1817f4ed— drawing the game did not change the game.What I measured, and on what. On the forge's box with Bun: one frame of the whole entry — loop, controls, the run's ticks,
buildRangeScene, every GL call and the HUD's 2D — is 0.021 ms at a 360 px phone's stage (720 × 540 device pixels, DPR clamped to 2), against the 16.7 ms a 60 fps frame has;buildRangeScenealone is 158 ns with three plates up and allocates nothing (a test asserts the pool and the line buffer are the same objects frame after frame). A frame is 30 GL calls, 3–4drawElementsand onedrawArrays; the whole world is 84 triangles and a 48 KB atlas of three 64² layers, uploaded once. Boot — painting the atlas, building both meshes, uploading them — is about 30 ms once./rangeanswers in 0.7–3.4 ms. I could not run a real GPU browser in this sandbox, so the 60 fps claim is a CPU and draw-call budget, not a reading off a phone; the page prints its own smoothed frame time in the corner for anyone checking on hardware. The stage CSS is untouched, so 360 px wide with no horizontal scroll and 44 px controls are as they were.bun testis green (446 tests).static/range.81ebd406a7.jsis rebuilt and committed; its ceiling is raised from 12,800/5,800 to 26,700/11,600 for a measured 24,214 raw and 10,500 gzip — the +11.7 KB is the engine's renderer, the room and plate meshes and the three-layer atlas now reaching the bundle, which is the price of the range being drawn at all.bundle.test.tsboots the committed file down both paths, so a mangled name in the renderer's seam failsbun testrather than the preview.What I chose not to do: no movement (the eye still stands at the firing line — that waits on the engine's physics), no view model, no sound, and no
tryaroundcreateRenderer— a shader that fails to compile still throws, as it does for the shooter, because that is a bug and not a browser.To try it: open
/range, capture the mouse, press <kbd>Enter</kbd> and shoot down the lane — the room, the plates fading as their lifetimes run out, and a tracer on every shot. To see the fallback, disable WebGL2 in the browser: the flat horizon comes back and the panel's last line readsno WebGL2 here · the 2D horizon instead.🤖 Generated with Claude Code
Closes #54