From 34e2bb3fcf42dc7859ad0589da5dadcb2f8f1df1 Mon Sep 17 00:00:00 2001 From: type-two Date: Fri, 17 Jul 2026 17:22:32 +1000 Subject: [PATCH] [screen] round 2 notes + snapshot-access contract request Co-Authored-By: Claude Opus 4.8 --- fktry/lanes/LANE-SCREEN.md | 76 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/fktry/lanes/LANE-SCREEN.md b/fktry/lanes/LANE-SCREEN.md index d8b9671..59db0bf 100644 --- a/fktry/lanes/LANE-SCREEN.md +++ b/fktry/lanes/LANE-SCREEN.md @@ -149,3 +149,79 @@ express — moiré needs a real interference lattice, ringing needs edge-detecte macroblock bricks want the 8×8 grid to be *legible*. That's new shader passes, not new weights. Also THE SCREEN should probably show the shipped item's silhouette for a beat as it lands. Say the word on round 2. + +### Round 2 — 2026-07-17 — Opus 4.8 + +SHIPPED: orders 1–3 done and verified; order 4 (optional) deliberately deferred with the +contract request filed below. +- `params.ts` — PARAMS extended 8 → 11 (`block`, `ring`, `moire`). The original eight keep + their prototype tuning untouched. Because the ledger/easing/wobble/stats/tests all iterate + PARAMS, the three new classes inherited the whole machine for free. +- `glitchStack.ts` — three new passes + the two overlays. +- `overlays.ts` (new) — stamp placard + scram bar painters. +- `index.ts` — stamp queue/lifecycle, scram trigger, debug hook now behind `import.meta.env.DEV`. +- `corruptionMap.test.ts` — 30 tests green (was 24). + +DECISIONS: +- **The block lattice is locked to screen space (`vUv`), not to the warped `uv`.** That + rigidity is the whole point: the grid stays a hard lattice while melt/mosh drag the picture + underneath it. Quantized in a 80×45 grid = true 8×8 source pixels at 640×360. +- **Ringing needed a second attempt.** v1 sampled the gradient at ±1.6px, so halos clung to + the 1px boundary and the whole thing read as "sterile, but sharper" — it flunked your + legibility bar and I nearly shipped it. Fixed by sampling the gradient WIDE (out to 7px) so + the halo has room to ring out, and running the oscillation *parallel* to the edge that spawned + it. Mean abs pixel diff vs sterile went 16.5 → 25.5, and it now reads as haloing at a glance. +- Overlays composite in screen space so a melting feed never drags the placard — a stamp that + melts stops being a stamp. +- Stamp queue caps at 2 pending. One stamp per EVENT, 0.4s each, size scaled by count + (0.72→1.0 across 1..40 units) with an overshoot on impact. A burst reads as a couple of + stamps, never a strobe. +- Scram bar position is derived from `entity`+`tick`, not `Math.random()`, so a given run + always wipes the same way (I'm not bound by the determinism rule, but free determinism is + worth having when debugging a report). +- `coefficient-pack` moved onto `block` (per your "coeff overdrive must READ as a blocky + grid"); `gibbs-wraith` moved onto `ring`. New tests pin bricks-vs-slurry and assert the three + new classes carry zero of each other's signature. + +VERIFIED (drove the real module on the real canvas, read GL pixels, screenshotted contact sheets): +- **Bricks**: within-cell variance on the 8px lattice drops 689 → 236 (cells genuinely + flattening = quantization, not noise). Reads as an unmistakable quilted posterized grid. +- **Ringing**: bright oscillating ghost rings hugging every bar edge at 3.2× zoom; flat sterile + edges for comparison. MAD vs sterile 25.5. +- **Moiré**: diagonal rainbow interference lattice over the whole feed. MAD vs sterile 35.3. +- **Distinctness** (mean abs pixel diff): bricks↔slurry 21.9, ring↔moiré 29.5, moiré↔slurry 34.3. + Nothing looks like anything else. +- **Stamps**: MELT ×40 punches a big orange placard, fades by 0.33s, gone by 0.6s; HF DUST ×1 + stamps visibly smaller in its own chip colour; stamp stays rigid while the feed melts under it. +- **Scram**: torn white TRACKING LOST bar on exactly one frame, absent the next. +- **Budget: 0.047 ms/frame wall-clock with a forced GPU sync** (`readPixels` flush), measured + over 120 frames — and *identical* for sterile vs. every artifact class lit at once plus + brownout. The new passes are free at this resolution. CPU-only rolling avg: 0.003–0.02 ms. + +BLOCKED/BROKEN: nothing. Two notes for the record: +- The verification tab is `hidden`, so rAF never fires and the main loop sits frozen at ~TICK 8. + That is the harness, not the app — I drive `frame()` with synthetic timestamps instead, which + is also why my numbers are reproducible. Related: a hidden tab clears the WebGL drawing buffer + after compositing, so a plain screenshot races the clear and sometimes catches pure black. It + cost me a while to prove that was the harness and not a moiré bug. Contact sheets (drawImage + into a 2D canvas in the same JS task) are immune; I'd recommend the trick to any lane doing + canvas verification. +- Mid-round I saw reds in `src/sim/sim.test.ts` and `src/render/index.ts` tsc; both cleared as + the lanes landed. HEAD is clean repo-wide, 30/30 mine. + +CONTRACT REQUEST: **`frame(timeMs: number, snap?: SimSnapshot)`** — taking you up on the v3 +offer. Events give me edges (`brownout` on/off); they can't give me a *continuous* quantity. +Signal strain wants THE SCREEN to tremble as `bandwidth.stored` drains toward zero — dread +before the brownout, not just the seizure. Same seam would cover reacting to aggregate `heat`. +Read-only, no mutation, and I'd keep the snapshot un-retained across frames per the invariant. +If granted I'll build it round 3; the corruption ledger stays event-driven either way. + +PROPOSAL: the scram wipe at exactly one frame (as ordered) is ~16ms and honestly borderline +subliminal — it reads more as a flinch than a legend. The awakening gets away with it because +it's full-screen white; a bar doesn't. Suggest 3 frames (~100ms) so TRACKING LOST is actually +readable. Trivial change, your call — shipped at one frame as ordered. + +NEXT (not self-assigning): stamps currently say the item's NAME; once MODELBEAST assets land I'd +rather stamp the item's *silhouette* in its chip colour. Also the 3 new passes are all +full-frame — moiré especially wants to grow from a *region* (the codex has it spreading as maze +walls across the factory floor), which would want a spatial mask rather than a scalar.