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

forked from trevato/cs · proposes · 4 behind

The range becomes a game without a renderer: seeded pop-up targets, a traced shot, a clock and a score #51

Merged opened this

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

Merged

`src/range/targets.ts` is the range's game, with no canvas anywhere near it: a seeded `rng` pops plates up as `Box`es down a lane in front of the shooter, each with its own lifetime and worth 100–200 points by how far down the lane it stood; `step(run, dt)` runs those lifetimes and the thirty-second clock and clears the lane when time is up; `shoot(run, eye, direction)` normalises the aim, traces…

shipped production is serving it deploy ae07c2d

opened this

src/range/targets.ts is the range's game, with no canvas anywhere near it: a seeded rng pops plates up as Boxes down a lane in front of the shooter, each with its own lifetime and worth 100–200 points by how far down the lane it stood; step(run, dt) runs those lifetimes and the thirty-second clock and clears the lane when time is up; shoot(run, eye, direction) normalises the aim, traces the engine's boxes, takes the plate down and folds the hit, the score and the accuracy in — and returns nothing at all for a shot the clock refuses. main.ts steps it in whole 50 Hz ticks, starts a run on the edge of Enter (a held trigger is one shot, a held Enter is one run) and fires along angleVectors(yaw, pitch).forward and nothing else; readout.ts leads the panel with score … best … hits … % and the clock, and draws each standing plate as a square on the existing 2D horizon, placed by the angle from the crosshair and sized by the angle it subtends — a projection, not a second renderer.

Worth looking at: targets.test.ts dials the randomness flat so the geometry is arithmetic (a plate at 512 units, 16 from centre to edge — a ray down the barrel stops at 496, a ray 5° wide of it goes by, since 512·tan5° = 44.8), plus the same seed playing the same run twice, a retired plate that cannot be hit, accuracy by hand count and the clock at zero refusing a shot. The new boot.test.ts case plays the game through the entry against the stub page: lock the pointer, press Enter, read the blip the scene drew, turn onto it in mouse counts, click, and the score moves — then the clock runs out, the trigger stops working and the best of the visit survives into the next run.

What I chose not to do: no room, no atlas, no WebGL, no movement, no bots, and no localStorage — the best score is a variable that dies with the tab, so the page's "nothing on this page is stored" stays literally true. Nothing from src/client/; independence.test.ts is untouched and passes. Scope beyond the issue is two lines: a start button on the touch pad (Enter is otherwise unreachable on a phone) and its assertion in src/server.test.ts. Page prose is the one paragraph, plus the overlay's own heading and sentence so a player arriving is told what to press.

range's ceiling is raised from 7,800/3,600 to 12,800/5,800 bytes — the game module, the engine's trace and the blip projection are what was added — and the bundle is rebuilt and committed at 11,575 bytes raw / 5,241 gzipped. /range answers in ~0.9 ms with 7,555 bytes of HTML (5.4 ms cold), bun test is green at 356 tests.

🤖 Generated with Claude Code

Closes #41

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs