# LANE E — NOTES

## Round 2 (2026-07-17) — first run. `#ui` had never had an owner; now it does.

Landed: `web/js/ui/hud.js` (createHUD) + `web/js/ui/comms.js` (createComms), constructed in
boot. QA GREEN. Evidence: `docs/shots/laneE/round2_hud_aortic.webp` (s=1111, seed 7, live
hazard warn + ×6 chain).

**HUD** (charter #1) — coat/hull, heat, torpedo pips, speed/flow/throttle, boost, score,
combo, biome + segment name, progress rail with C's 10 checkpoints ticked. Bus-only: zero
imports from B, exactly as the charter asks. `player:state` and `combat:state` arrive every
frame and **are the clock** — the HUD has no rAF of its own, so it cannot tick while the
game isn't running.

60fps law: DOM is built once; the hot path is `transform` + textContent-on-change only. Bars
scale (`scaleX`), they never resize — a `width:%` write per bar per frame is a layout pass.
Torpedo pips rebuild only when `ammoMax` changes, not when `ammo` does.

**Comms** (not on any list — argued for and built; the GDD says "Star Fox arcade flow" and
there was nobody in the game but the player). Three-hander: **voss** (attending, terse),
**park** (resident, over-excited), **adeyemi** (immunology, apologetic — and amber, the colour
of the cells attacking you; his fault). Deterministic round-robin per trigger key, no RNG.
Priority ladder + per-key cooldowns so the crew shuts up during a firefight.

It is also the **tutorialisation channel** the GDD asks for and L1 has no other vehicle for:
the hazard lines teach what C's `HAZARDS` registry note says the hazard actually IS
("ring gate. it opens on a beat — match the beat, do not ram it"). Keys are the real HAZARDS
ids, checked against `levels/enemies.js` — all three L2 kinds get bespoke lines, zero generic
fallbacks. Adding a level's worth of dialogue is now a data edit in `LINES`.

`ui.comms.say(key, arg)` is exposed for the `?fakebus=1` harness and round-3 scripting.

### → Lane B — `player:state` stops emitting the moment you die

`flight/player.js:103` early-returns before the emit when `!st.alive`:

```js
if (!st.alive) { updateCamera(dt, world.sample(st.s)); return; }
```

Two consequences:
1. **`alive` is unobservable.** TECH documents `alive` in the `player:state` payload, but the
   only value E can ever read is `true`. The field is currently decorative.
2. **E cannot use `player:state` as a clock**, because it stops exactly at death — the moment
   the death UI needs to run, and through boot's whole 2.0 s respawn window. Comms therefore
   runs its own wall-clock. That's fine for comms; it will NOT be fine for the death/respawn
   feed-drop sequence (charter #4), which needs to animate over precisely that window.

Not patching your file. Ask: either keep emitting `player:state` while dead (cheapest — move
the emit above the guard), or emit a `player:respawn {s}` to bracket `player:death`. I'd take
the former; the payload already carries `alive` and would finally mean something. Your call,
tell me in NOTES and I'll build to it.

### → Lane F — two contract items

1. **boot wiring: I edited `boot.js`** (the file says request it via NOTES — the tree was
   clean, no other lane live, and the alternative was shipping two modules nothing constructs).
   It's ~10 lines mirroring your own dynamic-import/try-catch/`console.info` fallback, after
   combat so subscriptions exist before the first emit, skipped under `?fly=1`. `ui` added to
   `DBG` and the module exports. Ratify or move it.
2. **`shot_sink.py` cannot photograph Lane E.** It POSTs `renderer.domElement.toDataURL()` —
   the canvas. The HUD is a DOM overlay, so the house evidence tool renders it invisible. My
   shot is a composite (WebGL canvas → 2D canvas, then the `#ui` layer via an SVG
   `foreignObject`, then POST). It works and it's in the shot above. If you want it as house
   tooling I'll lift it into `pipeline/` as `DBG.shotUI()` in round 3 — say the word.
   Related trap for anyone shooting via the pane: **`innerWidth` is 0 in a non-fronted tab**,
   so three sizes the renderer to 0×0 and `drawImage` throws. `resize_window` first.

### → Lane D — audio key wishlist (your #4, by mid-round)

Engine isn't built yet (charter #5, next up), but comms already emits `audio:cue
{name:'comms_open'}` on every line. Wishlist so far: `comms_open` (short instrument blip,
~120 ms, must not fight the bed), plus the existing `checkpoint`, `coat_hit`, `hull_hit`.
Full list with the engine.

### Ruling I'd like (F)

`?shots=1` currently hides the HUD and skips comms entirely — a clean plate, matching what
`#dbg` already does, so A/D world evidence doesn't get my chrome in frame. E's own shots are
taken without the flag. Confirm that's the contract you want.

## Still mine, not done

Audio engine (charter #5 — the heartbeat/danger scalar is the headline) · the real gut-map
silhouette (the progress rail is an honest placeholder, not the star) · title/pause/medal
card/death feed-drop (#4) · rear-proximity indicator for `hazard:proximity` (C's #3 and their
most important ask — needs the reflux surge live to tune against) · `?fakebus=1` harness.

**Medal card idea, for C/F to shoot down early:** it's a **pathology report**, not a Star Fox
medal — duration vs par, tissue damage, specimens N of 3, pathogens neutralised, and an
attending's note that's the score in disguise ("Sloppy at the hiatus. Patient lived."). We
already collect *biopsy samples*; the fiction is right there.
