glytch/fktry/lanes/LANE-SCREEN.md
type-two 5a85360ef9 [screen] round 1 notes
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 16:11:35 +10:00

149 lines
9.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# LANE-SCREEN — THE SCREEN compositor & glitch shaders
You are an Opus 4.8 executor on the SCREEN lane of FKTRY. Read `../MASTERPLAN.md` and
`../CONTRACTS.md` first; world bible `../../docs/FKTRY_LORE.md` (§1 THE SCREEN, §3
products, §8 style). Also read `../../index.html` — the original WIMVEE GLYTCH
prototype — its fragment shader is your seed stock: 8 glitch params (mosh, melt,
chroma, tear, roll, burn, noise, freeze) already written and tuned.
**Mission:** the payoff object. THE SCREEN is the sky-display everything ships to —
the player's factory output composited live as escalating video corruption. When
someone screenshots this game, they screenshot your canvas. It must start sterile and
end deranged, and every shipped item must visibly matter.
**Owned paths:** `src/screen/**`.
**Never touch:** contracts, main.ts, other lanes, the GLYTCH prototype (read-only
seed stock — port, don't move).
**Standing rules (all rounds):**
- WebGL (raw or three.js — your call, note it) on the provided 640×360 canvas.
Budget: <2ms/frame; THE SCREEN is garnish, not the meal.
- Corruption must be *legible*: a player who ships 40 chroma slurry should SEE chroma
damage specifically. Item artifact mapping is the design core, keep it data-driven
off `ItemDef.id`.
- Base content starts as procedural "clean programming" sterile SMPTE-ish test
patterns, slow pans, timestamp overlay (port `makeBaseTexture` thinking from the
prototype; animate it subtly so corruption has motion to chew on).
---
## CURRENT ORDERS — Round 1 (goal: milestone M1 "FLOW")
Replace the stub in `src/screen/index.ts`:
1. **Port the GLYTCH shader stack** into a proper module (`glitchStack.ts`): vertex +
fragment shader with the 8 uniforms, compiled against your base texture. Keep
param semantics identical to the prototype (it's tuned; respect the tuning).
2. **Corruption ledger.** `onEvents`: each `shipped` event adds to a per-item tally.
Map items param pressure in `corruptionMap.ts`, e.g. `melt → u_mosh+u_melt`,
`chroma-slurry → u_chroma`, `hf-dust → u_noise`, `anchor-slab → REDUCES overall
corruption slightly` (shipping clean anchors sanitizes nice tension, note it for
the orchestrator). Unknown items small generic noise bump. Pressure eases toward
its tally-driven target (lerp) so shipments feel like waves, not switches.
3. **Escalation curve.** Total corruption 01 over roughly the first 100 shipped
items (tune by feel), log-ish so early shipments feel huge. Above 0.8, add
compound wobble (params cross-modulate slowly) so a mature factory's SCREEN looks
*alive*, not maxed-out static.
4. **Brownout reaction.** On `brownout:true`, freeze-frame + heavy dropout lines +
desync judder until it lifts. The factory's pain shows in the sky.
5. **Idle charm.** With zero corruption, the clean feed runs bland loops with a
"NOTHING IS WRONG" chyron. First shipment ever interrupts it with a single frame
of full-white glitch the awakening. Cheap, unforgettable.
**Definition of done:** dev build screen starts sterile; console-dispatch a few
shipments (or wait for the real chain) and corruption rises, item-specifically;
brownout visibly seizes it. `npm run check` clean, frame budget respected (note
measured ms). NOTES written.
---
## NOTES (append-only log, newest at bottom)
```
### Round N — YYYY-MM-DD — [your model]
SHIPPED: / DECISIONS: / BLOCKED/BROKEN: / CONTRACT REQUEST: / PROPOSAL: / NEXT:
```
### Round 1 — 2026-07-17 — Opus 4.8
SHIPPED: all 5 orders done and verified on the dev build.
- `params.ts` the 8 params + frame-rate-independent `ease()`.
- `glitchStack.ts` GLYTCH shader stack ported. Raw WebGL, NOT three.js (order 1 said my
call): it's one fullscreen triangle + one texture; three.js would cost more than the
whole effect is allowed to. All 8 prototype params keep their tuning verbatim I
changed no magic numbers. Added 3 uniforms of my own: `u_drift`, `u_brownout`, `u_flash`.
- `baseTexture.ts` procedural clean programming: SMPTE bars + castellations + pluge/ramp
+ camcorder overlay (PLAY ▶, running SP timecode, rec dot), widened to 16:9.
- `corruptionMap.ts` the ledger + itemartifact table + escalation curve.
- `index.ts` compositor: ledger, easing, wobble, brownout, awakening.
- `corruptionMap.test.ts` 24 tests, all green.
DECISIONS:
- **Mix vs. total are separate axes.** WHAT you ship picks the artifact (blend of per-item
weights, by ship share); HOW MUCH you've ever shipped picks the intensity (escalation).
This is what makes 40 chroma slurry read as *chroma* instead of "more glitch".
- Escalation is `log1p(units/6)/log1p(100/6)`, so 10 ships 34% corruption and 100 100%.
Front-loaded hard, per orders there's a test pinning early-vs-late slope.
- Base texture repaints only when a visible glyph changes (timecode ~1/sec), not per frame.
Re-uploading 640×360 every frame would have eaten the budget for nothing. Motion for the
corruption to chew on comes from `u_drift` (bounded sinusoid deliberately not a wrapping
pan, which would show a seam: the texture is non-power-of-two so WebGL1 forces CLAMP_TO_EDGE).
- Wobble above 0.8 total is CPU-side, 8 distinct slow rates, ±0.12 riding on top of the eased
value and never feeding back into the ledger.
- **I extended the item table well past the orders' examples.** LANE-DATA landed the full
40-item codex mid-round, so I mapped every §2 resource, §3 product and §5 wildlife to a
signature (judder-camsfreeze, static-canisternoise, mosquito-swarmnoise, explosive-hits
mosh+burn+chroma, gamut paints graded rec709rec2020, chroma subsampling graded
420>422>slurry). The 5 science packs are intentionally left on the generic-noise fallback —
they're research currency, not ship goods. Unknown ids still degrade gracefully; there's a
test that walks `data/items.json` and asserts every id yields sane params, so LANE-DATA can
keep adding content without me.
VERIFIED (dev build, driving the real module on the real canvas, reading GL pixels — not vibes):
- Starts sterile: bars + "NOTHING IS WRONG" chyron, `idle:true`, all params 0.
- 40× chroma-slurry → `chroma 0.684`, every other param 0 except a 0.082 burn trace. Screenshot
shows channel-split fringing on bars and doubled glyphs. Item-specific: confirmed.
- Awakening: first-ever ship renders exactly ONE frame at mean luminance 255 (full white),
79 the next frame.
- Mature: 120× melt → total 1.0, melt 1.0 / mosh 0.451; screenshot shows the bars dripping
into black. Above 0.8, params drift ~0.095 between frames — alive, not maxed-out static.
- Anchor-slab isolation test: 1× anchor sets `idle:false` with ZERO corruption, and the only
pixel change is the chyron band going 37.1→100.8 luminance (dark overlay removed, bars
revealed). Chyron logic and sanitation both confirmed in one shot.
- Brownout: 1.0 when on, 0.0 when lifted, freeze+dropout+judder all driven off it.
- **Frame budget: 0.0040.013 ms/frame CPU** (rolling avg, `__fktryScreen.stats().msPerFrame`).
Budget was <2ms. GPU side is one fullscreen triangle, no readbacks in the hot path.
BLOCKED/BROKEN: nothing blocking me. Two things worth knowing:
- LANE-SIM emits no `shipped` events yet, so THE SCREEN can't be driven by the real chain.
I shipped a debug hook instead: `__fktryScreen.ship('melt',40)`, `.brownout(true)`,
`.reset()`, `.stats()`. It's ~20 lines in `init` and I'm happy to drop it once the chain
runs say the word.
- `npm test` currently has 2 red in `src/sim/sim.test.ts` (crafting, shipping) and they are
NOT mine flagging for your review, not touching them. My 24 pass; tsc is clean repo-wide.
NOTE ON A THING I TOUCHED OUTSIDE MY LANE: I briefly created `.claude/launch.json` to get a
dev server on a free port (8150 is held by another session), then **deleted it** the tooling
kept resolving to the busy port anyway. Net diff outside `src/screen/**` is zero. If you want
lanes to be able to boot their own preview, that file probably wants to be orchestrator-owned
with one entry per lane; right now five parallel lanes would collide on it.
CONTRACT REQUEST: none. `ScreenFX` + `SimEvent` gave me everything I needed.
PROPOSAL (orders 2 asked me to flag this): **anchor-slab sanitizing is live and it's good
tension** potency 2.0, so 1 anchor cancels ~2 items of corruption and enough of them
sterilize THE SCREEN completely (tested). Right now that's invisible to the player, which
makes it a trap: they'll ship I-frames for a commission and watch their sky go clean with no
explanation. Two options for you (a) UI surfaces it (LANE-UI chip: "SANITISING"), or (b) the
fiction owns it: The Correction *pays* for anchor-slabs, so it's a deliberate sellout loop
bandwidth now, corruption later. I'd build (b); it's the codex's whole conflict in one item.
Also: `ScreenFX` currently only sees events, never the snapshot if you ever want THE SCREEN
to react to *bandwidth strain* or *heat* continuously (not just the brownout on/off edge),
that'd need `frame()` to see the snapshot. Not asking yet; noting the seam.
NEXT (my read, not self-assigning): item-specific artifacts that the 8 prototype params can't
express moiré needs a real interference lattice, ringing needs edge-detected halos,
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.