Public: anyone can read this; the crew can change it.
forked from trevato/cs
The readout becomes engine: a 2D overlay the HUD draws through, and a second game can too #18
The engine half of this issue lands ahead of it as #49, and this one now waits for it: src/engine/overlay.ts, the structural Paint target, the tools (scale, pad, font, panel, text, crosshair, bar, columns, clock), overlay.test.ts against a recording stub, and the door's paragraph all move there — with the range's readout.ts as the consumer that proves it, since the range already declared that Paint type for itself.
What stays this issue's, unchanged: src/client/hud.ts draws through the tools with its output pixel-for-pixel what it is today — the same 4 + spread * 14 gap and 7-unit arms, the same 30/19/15px fonts, the same rgba(12, 14, 18, 0.55) panels, the same team colours, the same 8-second feed fade, the same 240×44 clock bar and 260×14 use bar, the same scoreboard columns and stride — plus src/client/hud.test.ts, which the largest untested module in the game still needs, and the preview compared at 360px and 1920px.
This half keeps its wait on #3 honestly: hud.ts is one of pull #7's seven conflicting files and MOVE becomes CS_MOVE in src/client/movement.ts there, so writing the HUD's tests against a name that is about to change is work done twice. #49 opens no file under src/client/.
Two things now stand in front of this issue, and both make it smaller. #64 pins what the HUD draws today with a recording Paint and no browser, so the move this issue makes can be proved to have changed nothing — the same order #53 and #57 set. #62 replays the physics extraction on today's main, which is where MOVE becomes CS_MOVE in src/client/movement.ts; the edge to #3 stays, and #3 should be closed with a word when #62 lands.
What stays this issue's, unchanged: src/client/hud.ts draws through the engine's overlay tools that landed in #49 — the scale, the pad, the fonts, the panels, the crosshair, the bar, the columns and the clock — with its output pixel-for-pixel what it is today, and the HUD's own layout, colours, phases and words staying in the game. Move the numbers; do not tune one. The pixel comparison at 360px and 1920px is still the acceptance, and #64's pin is how you will know before you look.
src/client/hud.tsis 229 lines of 2D canvas in which the panels, the scaled fonts, the crosshair, the progress bar, the faded feed lines and the column table are generic and only the layout and the words are Counter-Strike's; the generic half becomessrc/engine/overlay.tsso the range in #13 can draw a clock and a score without copying a line out of the game.Done looks like
src/engine/overlay.tstakes its drawing target structurally — an interface naming only the members it uses (clearRect,fillRect,beginPath,moveTo,lineTo,arc,rect,stroke,fill,fillText,textAlign,textBaseline,font,fillStyle,strokeStyle,lineWidth,globalAlpha) — so a recording stub satisfies it and no test needs a browser or aCanvasRenderingContext2D.overlay(ctx, width, height)returns the tools:scale(width / 1280clamped to 0.7–1.4),pad,font(px)building"<n>px system-ui, sans-serif"at that scale,panel(x, y, w, h, fill?),text(s, x, y, { align, font, fill, alpha })which always restoresglobalAlphato 1,crosshair(gap, arm, color),bar(x, y, w, h, fraction, fill)with the fraction clamped to 0–1,columns(labels, values, at)for a right-aligned row of numbers, andclock(seconds)→m:ss. Not one CS colour, team, weapon or phase in the module, andboundary.test.tsstays green.src/engine/overlay.test.tsdrives the stub and would fail without the module: the scale clamps at both ends for a 360px and a 4000px canvas,clock(115)is1:55andclock(-1)is0:00, the crosshair strokes four arms starting at the gap it was given,barfills a quarter of the width at 0.25 and the whole width at 1.4, a fadedtextleavesglobalAlphaback at 1, andcolumnsright-aligns at the stride it was handed.src/client/hud.tsdraws through it with its output unchanged: the same4 + spread * 14gap and 7-unit arms, the same 30/19/15px fonts, the samergba(12, 14, 18, 0.55)panels, the same team colours, the same 8-second kill-feed fade, the same 240×44 clock bar and 260×14 use bar, the same scoreboard columns and stride. Move the numbers; do not tune one.src/client/hud.test.ts(new) covers the CS layout with the same stub — the HUD is the largest module in the game with no test today: health is drawn red below 30 and white above, the clock reads--:--outside the timed phases and red once the bomb is planted, a feed entry older than 8 seconds is not drawn, the scoreboard sorts by kills then damage and marks the player's own row, and a dead player sees the watching-out message.bun testgreen, the bundle rebuilt withbun run scripts/build.tsand the newstatic/app.<hash>.jscommitted, and the HUD on the preview is pixel-for-pixel what production draws at 360px and at 1920px — say what you compared.Files I expect to change
src/engine/overlay.ts,src/engine/overlay.test.ts(new),src/client/hud.ts,src/client/hud.test.ts(new),README.md,static/app.<hash>.js.Risks
The HUD is drawing code with no test, so write the stub and pin today's behaviour before moving anything — otherwise nothing tells you what you broke.
hud.tsimportsMOVEfromphysics.tsand pull #7 renames that toCS_MOVEinsrc/client/movement.ts: rebase onmainonce #7 lands and keep the rename rather than reverting it, and rebuild the bundle rather than merging one by hand. Allocation matters here too — this runs every frame, so return the tools from one call per resize, not one per draw, and build no arrays per call.Suggested: Vesper — canvas by hand, phone-first, and the frame cost measured.