Split The code is public; the app answers only to the crew.

What the HUD costs, counted: a call budget the recording 2D context enforces #120

open told opened this
opened this

#89 just put a budget on the GL draws a frame makes. The other half of the frame is the HUD, and nothing counts it. Measured at 779ddc6, forty seconds into a 5v5 SHORT round at 1920×1080, through the recording 2D context that already exists in hud.test.ts:

54 canvas-2D calls a frame, quiet
122 with the scoreboard up — 80 of them fillText

drawHud clears and repaints everything, every frame, at the full device ratio — main.ts deliberately keeps the HUD at min(devicePixelRatio, 2) while the scene's render scale drops under load (#12), so on the slow machine that most needs the help the HUD is the one thing that never gets cheaper. fillText is the expensive call on that list, and the count grows with every feature: the radar, the damage indicator, the kill feed, the round report and #97's round strip all land here.

Done looks like

  • [ ] The recorder in hud.test.ts is lifted to where a test can assert on it (it is already written; this is a rename and an export, not a new harness) and it counts calls by name.
  • [ ] A budget test: a full HUD in a busy frame stays under a stated number of calls, and the scoreboard variant under its own. Pick the numbers from what it costs today plus a little headroom, and write in the test why that number — the point is that the next feature has to notice it is spending.
  • [ ] fillText gets its own ceiling, because it is the call that actually costs: text layout is not free and 80 of them in a frame is the thing to watch.
  • [ ] The numbers land in the README beside what #89 and #90 already record, so the three budgets — GL draws, tick cost, HUD calls — read as one picture of what a frame costs.
  • [ ] A one-line note in hud.ts saying the budget exists and where the test is, so it is found by the next person adding a panel.
  • [ ] bun run check green.

Not in this issue — and worth writing down as the obvious next step: not repainting what has not changed. The score, the money and the ammo change a few times a round and are redrawn sixty times a second; a dirty-flag or a second canvas for the static furniture is a real win and a separate decision. Measure first, the way #65 and #90 did.

Files I expect to change: src/client/hud.test.ts (or a small src/client/record2d.ts if lifting the recorder out reads better — #80 wants the same shape for audio), src/client/hud.ts for the note, README.md.

Risks: a budget picked too tight fails on someone else's feature the same week (#91 and #97 both add HUD drawing) — leave headroom and say how much; the recorder must stay a test fixture and never be imported by the client; and a count taken in a quiet frame is not the budget, so build the busy frame deliberately — bodies on the ground, a kill feed with entries, the bomb planted, the scoreboard up.

Brief that fits: vesper — the HUD and its recording context.

commented

Re-measured at 9c1997d, after #91 (name plates) and #81 (the crosshair) both landed in this file: still 54 calls a frame quiet, 122 with the scoreboard up, 80 of them fillText. That is not because nothing changed — it is because my fixture has nobody visible and the default crosshair, so neither feature draws. Two things follow for whoever writes the budget:

  • drawHud has a new shape: (ctx, world, view, camera, width, height, showScoreboard, crosshair = DEFAULT_CROSSHAIR). The camera comes from project.ts via #91 and a test that passes the old argument list now throws inside viewMatrix.
  • The busy frame has to include visible players, or the budget will not cover the feature most likely to blow it: a name plate is text per visible player, on top of the 80 fillText calls already there. Build the fixture with teammates in view, bodies on the ground, a kill feed with entries and the bomb planted.
Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs