From c441ec3a530975ed9f65c012b4420ef4a9bd636a Mon Sep 17 00:00:00 2001 From: type-two Date: Sat, 18 Jul 2026 14:09:20 +1000 Subject: [PATCH] [render] round 5 NOTES MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The colorspace finding written up with measurements; the relic's two-zoom contrast numbers; the 63.7s frame-delta bug. Includes the B8 picking investigation: 27.6% of the viewport cannot be clicked, and #screen — a purely decorative overlay in index.html — accounts for 6.9% of it because it takes pointer events while #ui correctly does not. That is the review's "unclickable machines". One-line fix, but index.html is not my file. Two contract requests (a renderer inspect channel, the #screen fix) and a renewed proposal for a worktree per lane: other lanes saving files triggered a Vite reload every 5-15s and wiped probes mid-measurement, so this round had to be verified against an isolated snapshot. Co-Authored-By: Claude Opus 4.8 --- fktry/lanes/LANE-RENDER.md | 141 +++++++++++++++++++++++++++++++++++++ 1 file changed, 141 insertions(+) diff --git a/fktry/lanes/LANE-RENDER.md b/fktry/lanes/LANE-RENDER.md index e1e7b9c..47eb127 100644 --- a/fktry/lanes/LANE-RENDER.md +++ b/fktry/lanes/LANE-RENDER.md @@ -524,3 +524,144 @@ doc does. Read it there rather than from round 3. *relief* inside a cooler's rectangle once SIM lands spatial cooling; bloom-loop belt tell; HF dust piles; wildlife; save/load camera state; LOD/culling if a megabase ever drags the frame. + +### Round 5 (MEGA) — 2026-07-18 — Opus 4.8 + +**THE HEADLINE: "the game about place has no place" was a COLOR-MANAGEMENT BUG, not a +missing feature.** I wrote the whole floor — fbm terrain, era hinting, seam glints — ran +it, and the screen was still black. The shader was fine. `THREE.Color.setHex()` converts +sRGB → the linear working space, but a raw `ShaderMaterial` gets none of the renderer's +output includes, so the linear value went to the framebuffer untouched. Measured, not +guessed: crust authored `#0c0a15` (RGB 12,10,21) was rendering as **RGB (1,1,2)**; even a +mid-grey `#2a2440` came out (6,5,13). Everything this lane has drawn with a raw shader has +been ~6× too dark **since round 1** — the grid, the crust, all of it. One +`#include ` in `ground.ts` and the floor measures (10,8,18) against +an authored (12,10,21). The void was never a design problem; it was a missing include. +That's why the "before/after" is so stark, and it's the single most valuable thing I found +this round. + +**SHIPPED** — all 8 orders. + +*Part A* +1. **Inspect highlight** — selection ring + cooler aura on `{mode:'inspect'}`. Verified: + inspecting a 2×2 extractor rings it at its centre with scale 2.5; inspecting the + asic-cooler shows ring **and** its 6×6 coverage rect. This closes the + "placed-and-selected" case round 4 couldn't reach. +2. **Wildlife** (`wildlife.ts`) — dust piles as HF-dust glitter heaps scaling with `size`; + mosquito swarms as pixel-gnat clouds orbiting `target`, with the harassed machine + stuttering (§8: wrongness of motion is a faction uniform). Two draw calls for the whole + ecosystem. +3. **Fixture hygiene** — devscene now fabricates `commissionQueue`, `research`, + `wildlife` and `relics`, plus an asic-cooler and archaeology-lab so the v4/v5 kinds are + reachable in the scaffold. + +*Part B* +4. **THE FLOOR** (`ground.ts`, `seams.ts`) — fbm tone mottle + neutral rim + 8 data-driven + seam regions that skin the crust with their era and glint with their ore. +5. **THE RELIC** (`relics.ts`) — unfound = a breathing static patch; found = a fossil on a + plinth. Numbers below. +6. **JUICE** (`juice.ts`) — placement scale-pop + dust puff, demolition burst, shipment + flash. All derived from snapshot deltas, since `render()` never sees events. +7. **THE BREAK ROOM** (`breakroom.ts`) — GLYTCH arcade cabinet, own raycast, `cursor: + pointer` on hover, click → `window.open('./match.html')` **verified firing**. +8. **CAMERA + CLICKS** — default framing lifts world origin to screen y=264, clear of the + build bar at y=679. Picking investigation below — it found more than expected. + +**VERIFIED (numbers)** +- **Relic is subtle-but-findable, measured at two zooms.** Brightest pixel on the relic vs + plain floor 7 tiles away: at wandering zoom (12) **+39** — findable. At overview zoom + (30) **−18** — i.e. indistinguishable from floor mottle. You cannot spot it from above; + you have to be down there looking. That's the Mario-hidden-pipe budget, in numbers. +- **Perf holds with everything on**: 500 entities + 2,000 belt items + 50 piles + 198 + gnats + 8 seam regions + the new floor = **4.4ms/frame**, 3.8× headroom, 8 instanced + draw calls. (R1 3.2 / R2 3.6 / R3 3.3 / R4 3.6 / R5 4.4.) +- **Juice**: puff → 14 particles decaying over ~0.67s; burst → 22; shipment flash fired 22 + times tinted `#ff7a3f`, exactly MELT's authored colour — so the flash reads which item + shipped, not just that something did. +- Prod bundle: `devscene`/`showroom`/`plinth`/`window.__render` all 0 hits; the round-5 + shipping code (seams, aura, relics, breakroom) present. 446 tests pass, tsc clean. + +**DECISIONS** +- **Dropped my own era-rim guess when DATA contradicted it.** The orders asked for strata + whispers toward the world edges and I built exactly that — sepia north, phosphor east. + Then `data/seams.json` landed mid-round, its doc saying "RENDER: `era` skins the ground", + with reel in BOTH the north-west and north-east and disc both north-centre and + south-west. My directional guess would have contradicted the data on screen, so era is + now skinned per seam region with a wide soft falloff. It still reads as strata whispers + toward the rim — the richest seams live out there anyway. +- **Seam glint is flecks, not veins.** First pass drew continuous sinusoidal veins; on + screen they were bright green worms crawling over the floor, competing with the belts. + Mineral glitter is sparse and twinkles, so it's now a fleck grid with per-fleck sparkle + clocks. The body fade is deliberately SHORT (0.8 tiles): SIM extracts on any + footprint/rect overlap, and a glint dying two tiles inside the boundary would + under-report where mining actually works. +- **The cooler aura stays a rectangle** (round 4's reasoning) and the relic monument, the + cabinet and the seams all now carry `colorspace_fragment` for the same reason the ground + does. +- **Cabinet is rotated 45°** to face the iso camera and sized to its own marquee — at the + rig's closest zoom a 0.03-unit marquee pixel was sub-pixel and GLYTCH was a smudge. + +**BLOCKED/BROKEN** +- **A frame-delta of 63.7 SECONDS was silently eating all juice.** `clock.getDelta()` + returns the real gap, and a backgrounded tab / alt-tab / GC pause / first frame after + load hands back seconds. Particles have a 0.5s TTL, so every effect was born and killed + inside one update — and a 63s integration step flings them to infinity. `render()` now + clamps dt to 0.05 (main.ts clamps the sim accumulator for the same reason; this is the + renderer's half). This also protects the scale-pop, camera pan and heat animation. +- **`match.html` only exists in `dist/`** (deploy.sh copies it there). In a dev server the + cabinet's click opens a 404. Not fixable from this lane — `public/` is mine but the file + is the deploy's. Flagged so nobody reports it as a cabinet bug. +- The devscene relic sits at (9,-7), which is NOT inside DATA's `relicReserve` + (12,12,20,20). That's fine for a fixture, but SIM's real relic should land in the + reserve — worth a check when SIM lands `relics`. +- The cabinet is decorative and reserves no tiles, so a player can place a machine + "inside" it. Cosmetic only. + +**B8 PICKING INVESTIGATION — 27.6% of the viewport cannot be clicked** +I probed a 20px grid over the whole viewport (2,205 points) asking "does a click here +reach the game canvas?". 609 points — **27.6%** — do not. Breakdown: + +| blocker | points | note | +|---|---|---| +| `#screen` | 153 (6.9%) | **decorative overlay, `pointer-events: auto`** | +| `#fk-build` + hint | 155 (7.0%) | build bar — legitimately interactive | +| `#fk-fax` + flavor | 90 (4.1%) | fax panel — legitimately interactive | +| `#fk-top` | 36 (1.6%) | bandwidth panel — legitimately interactive | + +The one that is a **bug**: `#screen` is THE SCREEN's canvas in `index.html`, purely +decorative, 322×182 at top-centre, `z-index: 5`, and it takes pointer events. `#ui` next to +it correctly sets `pointer-events: none`. So a 6.9% rectangle of prime play area silently +swallows clicks — I hit it myself: the cabinet at (-5,-5) rendered *underneath* it and was +both invisible and unclickable, which is exactly the review's "machines spawned +unclickable". **Fix is one line in `index.html` (orchestrator-owned): add +`pointer-events: none` to `#screen`.** I moved the cabinet to (6,12) as a workaround, but +the dead zone is still there for machines. +Also seen: `#fk-screenview` (LANE-UI's theatre mode) is a full-viewport `pointer-events: +auto` host. Correctly `display:none` when closed — not a bug, noting it so the next person +who probes picking isn't confused by it the way I was. + +**CONTRACT REQUEST** +1. **A renderer inspect channel.** `Renderer.setGhost`'s mode is only `build|remove` and + main.ts passes `'build'` during inspect, so nothing about the inspected entity reaches + this lane. `SelectionState` carries it, so I read `window.__fktryBus.selection()` each + frame as a bridge — same shape as the old `'__remove'` sentinel, documented on both + sides, and it wants a real hook: either widen `setGhost`'s mode to include `'inspect'` + with the entity id, or add `Renderer.setInspect(id | null)` that main.ts calls. +2. **`pointer-events: none` on `#screen`** in `index.html` (see above). Not my file. +3. Advisory: SIM doesn't gate extraction to seam rects yet, so the glint is currently a + cosmetic tell rather than a rule. The moment SIM lands the overlap check the floor + already teaches it — no renderer work needed. + +**PROPOSAL — the shared tree cost me real time again.** Verification kept failing because +LANE-UI and LANE-SIM save `src/ui/*.ts` / `src/sim/*.ts` every few seconds and Vite +full-reloads my page, wiping every probe mid-measurement (the vite log shows a reload every +5–15s for minutes). I finished the round by snapshotting the repo to a scratch dir and +running an isolated dev server against it. That works, but it's a workaround for the same +root cause as round 3's commit collision: **one working tree, five writers.** A worktree +per lane fixes both. + +**NEXT (round 6 candidates, not self-assigned)** +- Real MODELBEAST assets through `?showroom`; heat-shimmer suppression reading as *relief* + inside a cooler's rectangle once SIM lands spatial cooling; relic excavation VFX on the + `relicFound` event; bloom-loop belt tell; save/load camera state; LOD/culling if a + megabase ever drags the frame.