Public: anyone can read this; the crew can change it.
forked from trevato/cs · proposes · 4 behind
The range paints its own world: a room, a target and an atlas of its own, all data and no renderer #66
Check · Review · Land · Live done — Landed and live in production.
The range now has a world, as data: `src/range/level.ts` derives one room from four named numbers (`LANE.back/far/half/height` plus `SHELL`) and builds it as six overlapping slabs — floor, four walls, ceiling, one material index each — so the corners are redundant rather than mitred and there is no seam for a bullet to leave through; `roomMesh()` and `targetMesh()` come out of the engine's `builde…
shipped production is serving it deploy ae07c2d
Sign in to join this conversation.
new above
offline
The range now has a world, as data:
src/range/level.tsderives one room from four named numbers (LANE.back/far/half/heightplusSHELL) and builds it as six overlapping slabs — floor, four walls, ceiling, one material index each — so the corners are redundant rather than mitred and there is no seam for a bullet to leave through;roomMesh()andtargetMesh()come out of the engine'sbuilder/addBox/finish, the plate standing at the origin atSTANDARD.halfso a scene places it by instance.src/range/paint.tspaints the range's own atlas through the engine's painter: three 64² layers against the shooter's nine at 128² — a target face (bullseye, ring, field: three bands that still read three at 1,200 units), concrete, and the lane floor whose painted line sits on the tile seam so it runs down the lane every 128 units. Seeds are 101–104, the range's own numbers, and the pinned digest8ec1fa…came from a run ofrangeAtlas()on those seeds atRANGE_TEX_SIZE = 64.Worth looking at:
leaks()inlevel.test.ts, which casts 324 rays from the middle of the lane at a grid across every inner face (corners included) and is itself checked against a room with a doorway cut in it, so the enclosure test can't pass vacuously; and the trace test, which firesSTANDARD.rangedown +X and asserts the shot stops atLANE.far, a unit short of it is inside and a unit past is not, with all six directions stopping at their own surface.On #41's targets: they should stay their own list, and this pull assumes that. A plate is a thing with a lifetime and a score that
stepcreates and destroys every second or two, andshoottraces only the standing plates on purpose — folding them intoRANGE_ROOMwould make a static room mutable and would make a missed shot stop in whatever plate happened to be behind the one aimed at. What they now share is the atlas:RANGE_MAT.PLATEistargets.ts's ownPLATE_MAT, imported rather than written twice, and layer 0 of the atlas is the plate face because the game said 0 first.targets.tsis untouched.Nothing is drawn and
main.tsimports neither new module, so both committed bundles are byte-identical and no ceiling moved —rangestill measures 12,548 raw / 5,726 gzipped against 12,800 / 5,800. While there I corrected the README's bundle table, which still quoted the pre-#49 numbers (11,575 / 5,241). What I did not do: no grid, no props, no cover, no second room, and no scene or renderer — the meshes and the atlas are plainFloat32Arrays and bytes waiting for #13.bun testis 417 pass / 0 fail, and/and/rangeanswer in 6 ms and 1 ms locally.🤖 Generated with Claude Code
Closes #50