[ui] round 5 notes
All nine orders shipped. The tab-click report was a real bug (scrollbar eating half of every tab hitbox) and is fixed; RENDER's demolition tint is verified with a screenshot, closing the item owed since round 3. The honest parts: DATA's commission queue head-of-line blocks the whole game, RENDER doesn't read the inspect selection yet, and the radio drives a stand-in until SCREEN publishes its control. One proposal (audio on the bus), no contract requests. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
4da8096de9
commit
0cc80d3c82
@ -471,3 +471,120 @@ breaks for no good reason.
|
|||||||
**NEXT (suggested):** verify RENDER's tint; research rig in reference.ts so a pack economy
|
**NEXT (suggested):** verify RENDER's tint; research rig in reference.ts so a pack economy
|
||||||
exists to test against; scrolling tab strip if the catalog grows again; era-skinned tech
|
exists to test against; scrolling tab strip if the catalog grows again; era-skinned tech
|
||||||
panel once eras mean something visually (§8).
|
panel once eras mean something visually (§8).
|
||||||
|
|
||||||
|
### Round 5 (MEGA) — 2026-07-18 — Opus 4.8
|
||||||
|
|
||||||
|
**SHIPPED:** All nine orders. New modules: `power.ts` was round 4; this round adds
|
||||||
|
`radio.ts` (SPEAKER bridge + echo stand-in), `tuner.ts` (the dock), `screenview.ts`
|
||||||
|
(enlarge), and tests `tuner.test.ts`, `wildlife.test.ts`, `screenview.test.ts`.
|
||||||
|
**194 UI tests** (was 145); full suite 446/446; `npm run check` clean.
|
||||||
|
|
||||||
|
1. **Scrolling tab strip** — one row, never wraps, active tab scrolled into view on
|
||||||
|
`[`/`]`. Found and fixed a real bug doing it: see the hitbox finding below.
|
||||||
|
2. **Inspect mode published** — `setSelection({mode:'inspect',entity})` on open, cleared
|
||||||
|
on close (X, Esc, or the unit being demolished under it). Holding a tool supersedes it
|
||||||
|
and shuts the panel, so panel and highlight can't disagree.
|
||||||
|
3. **Wildlife surfaced** — infestation toasts in voice; MOSQUITO EXPOSURE + severity in
|
||||||
|
the inspector, read from `snap.wildlife` by `target`; hatch warnings deduped one per
|
||||||
|
pile id.
|
||||||
|
4. **Research tests migrated** to SIM's `testkit.grantResearch`/`grantAllResearch` — my
|
||||||
|
round-4 hand-rolled save-blob edit is gone, and with it the coupling to SIM's schema.
|
||||||
|
Tint + highlight verified, see below.
|
||||||
|
5. **First-brownout mercy toast** — once per session, on the first brownout event.
|
||||||
|
6. **Camera hint** in the idle line; **tab hitbox adjudicated** (below).
|
||||||
|
7. **`no seam` jam voice** — "THERE IS NOTHING DOWN THERE. MOVE." SIM emits this reason
|
||||||
|
at index.ts:498, so it's live copy, not speculative.
|
||||||
|
8. **THE SCREEN click-to-enlarge** — ~2.5×, dimmed backdrop, Esc/click closes.
|
||||||
|
9. **THE TUNER DOCK** — hidden until the fossil is excavated, then slides in with dial
|
||||||
|
(drag + ←/→), AM/FM/SW, volume + mute, and a station readout in voice.
|
||||||
|
|
||||||
|
**VERIFIED — live, in the browser** (screenshots taken of each):
|
||||||
|
- **Cold-start mercy toast**: placed one extractor with no generator → BROWNOUT, and
|
||||||
|
under it "NOTHING IS GENERATING. THE COMMITTEE SUGGESTS: POWER." That's the DoD's
|
||||||
|
opening requirement.
|
||||||
|
- **THE SCREEN enlarge**: the live WebGL sky at 2.5× centred over a dimmed HUD; Esc
|
||||||
|
restored its `style` attribute to `null` and its dock rect to y=10, w=322 — exactly as
|
||||||
|
found.
|
||||||
|
- **THE TUNER DOCK**: excavated SIM's real seeded fossil → dock slid in bottom-right with
|
||||||
|
"AUDIO BUS RESTORED. THE BITSTREAM HAS A VOICE.", dial, FM active, VOL/MUTE, hint line.
|
||||||
|
- **RENDER's demolition tint — the item owed since round 3 is CLOSED.** Armed remove,
|
||||||
|
hovered a machine, and it renders outlined in demolition red. Screenshot taken.
|
||||||
|
- Build bar with padlocks on the POWER page (DECODE ASIC free; SOFTWARE DECODER and ASIC
|
||||||
|
COOLER greyed + 🔒 + REQUIRES:), reference factory healthy at GEN 220 / DRAW 158.
|
||||||
|
|
||||||
|
**VERIFIED — headless** (`live.test.ts`, real sim + real DOM, 19 tests): mercy toast fires
|
||||||
|
once and *stays* once across a second brownout; inspect selection published on open and
|
||||||
|
dropped both on Esc and when the inspected unit is demolished; the tuner stays hidden
|
||||||
|
until `relics[0].found` flips and then reveals with the ceremony toast and the toast
|
||||||
|
standoff; full research loop (lock → pick → deliver → unlock → place) now driven through
|
||||||
|
`grantResearch` and the lab's real per-pack timing.
|
||||||
|
|
||||||
|
**DECISIONS:**
|
||||||
|
- **THE SCREEN is enlarged in place, not mirrored.** I built the mirror first; it rendered
|
||||||
|
black. THE SCREEN is a WebGL canvas, and `drawImage` from a WebGL context without
|
||||||
|
`preserveDrawingBuffer` returns nothing. Asking SCREEN to enable that flag would cost
|
||||||
|
them a buffer copy every frame for an occasional feature, so I enlarge the real element
|
||||||
|
with inline styles and restore its `style` attribute verbatim on close (tested,
|
||||||
|
including the case where SCREEN later adds inline styles of their own).
|
||||||
|
- **The radio bridge is guarded** (`radio.ts`). `src/audio` is still the stub — no `radio`
|
||||||
|
export exists — so the dock resolves a control at runtime and otherwise drives a silent
|
||||||
|
echo stand-in, which is why every dial is testable today. **LANE-SCREEN: publish
|
||||||
|
`window.__fktrySpeaker = { radio }` (or tell me the export name you prefer) and the dock
|
||||||
|
drives real audio with zero change here.** The interface I'm driving is exactly your
|
||||||
|
documented one: `setFrequency / setBand / volume / mute / getState / subscribe`, with
|
||||||
|
`getState()` returning `{freqMHz, band, volume, muted, station}` — `station: string|null`
|
||||||
|
is what flips the readout to "SIGNAL LOCKED". `isLive()` reports which one is attached.
|
||||||
|
- Wildlife exposure shows the swarm's **severity** (`WildlifeState.size`), not a
|
||||||
|
sim-confirmed throughput number — SIM owns the real penalty and doesn't expose one.
|
||||||
|
Labelled as exposure rather than a promise about output.
|
||||||
|
|
||||||
|
**BLOCKED/BROKEN (read this part):**
|
||||||
|
- **The tab-click bug was REAL, and I fixed it.** Reproduced with a genuine mouse click:
|
||||||
|
a click on POWER did nothing. `elementFromPoint` at the button's own centre returned the
|
||||||
|
*strip container*, not the button — the horizontal scrollbar was being painted over the
|
||||||
|
lower half of every tab and swallowing clicks there, which is exactly why keyboard
|
||||||
|
paging still worked. Fixed by giving the scrollbar its own lane (`padding-bottom: 7px`
|
||||||
|
≥ scrollbar height); the full button height now hit-tests to the button, and a real
|
||||||
|
click activates POWER. **Separately**, `computer` clicks via `ref` deliver *no* events to
|
||||||
|
the page at all (document-level capture recorded nothing); coordinate clicks work fine.
|
||||||
|
So: real bug, now fixed, plus a harness quirk on top of it.
|
||||||
|
- **DATA's commission queue head-of-line blocks, and it stalls the whole game.** The v5
|
||||||
|
queue opens with `raw-payload` (20 raw MDAT ORE), but the reference factory refines every
|
||||||
|
scrap of its ore and never ships it — so the head commission can never complete and all
|
||||||
|
19 behind it are unreachable. Probed: 12k ticks ships hf-dust, chroma-slurry,
|
||||||
|
macroblock-bricks, melt and anchor-slab, and `commissionDone` fires **zero** times. My
|
||||||
|
tests now build the obvious player rig (extractor → belt → uplink) to pay it. Worth a
|
||||||
|
design look: either the opening commission should want something the tutorial factory
|
||||||
|
ships, or an unsatisfiable head shouldn't block the tray.
|
||||||
|
- **Machines only push onto belts, never into an adjacent machine.** Cost me a while to
|
||||||
|
find; noting it because it's non-obvious and unstated anywhere in CONTRACTS.
|
||||||
|
- **RENDER doesn't consume the inspect selection yet** — no `inspect` anywhere in
|
||||||
|
`src/render`. I publish it correctly (verified live: `{mode:'inspect',entity:105}`), so
|
||||||
|
the highlight lights up whenever they read it. **Not owed by me any more; owed to me.**
|
||||||
|
- **Stale ghost on keyboard disarm**: main.ts only refreshes the ghost on `pointermove`, so
|
||||||
|
Esc-ing out of remove mode leaves the demolition tint on screen until the mouse moves.
|
||||||
|
Visible in my inspect screenshot. Cosmetic, and it's main.ts's glue, not mine.
|
||||||
|
- **SIM landed wildlife AND relics mid-round, again** — my round-start grep found neither.
|
||||||
|
Fifth round running. It's why my wildlife/relic UI could be verified against the real sim
|
||||||
|
at all, so this is a good problem, but the pattern is now completely reliable: I re-probe
|
||||||
|
a *running* sim before writing NOTES, never a grep from round-start.
|
||||||
|
- Three of my live tests failed mid-round from SIM/DATA changes, not my code (proved by
|
||||||
|
stashing my diff and re-running). Also hit `DUST_SPILL_GRACE is not defined` from SIM
|
||||||
|
mid-edit, which resolved itself between two consecutive commands.
|
||||||
|
- Harness, for the record: the browser pane backgrounds the tab, which pauses rAF **and
|
||||||
|
CSS transitions**. I lost time reading a transitioned `bottom` that never advanced and
|
||||||
|
briefly thought the CSS was broken; `transition:none` proved it computes correctly. Same
|
||||||
|
root cause as the paused sim loop from rounds 3-4.
|
||||||
|
|
||||||
|
**CONTRACT REQUEST:** none. v5/v6 gave me everything these orders needed.
|
||||||
|
|
||||||
|
**PROPOSAL:** `UIBus.audio?: { radio?: RadioControl }` — the tuner currently reaches THE
|
||||||
|
SPEAKER through a global handshake because `ui.init` never sees the audio module, which is
|
||||||
|
the same shape of problem as `pickTile` in round 1 and the `__remove` sentinel in round 3.
|
||||||
|
One optional field on the bus would make it typed and testable instead of a documented
|
||||||
|
convention. Not blocking: the guarded bridge works.
|
||||||
|
|
||||||
|
**NEXT (suggested):** wire the real radio the moment SCREEN publishes it (and describe how
|
||||||
|
it sounds in NOTES, since they're doing the same); inspect highlight once RENDER reads the
|
||||||
|
selection; a station-locked readout screenshot once there are real stations; commission
|
||||||
|
head-of-line blocking is a design question for you, not a UI fix.
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user