# Glow-Up (Lane E / fx) — Handoff **Brief:** [docs/briefs/GLOWUP_ART.md](briefs/GLOWUP_ART.md) **Scope done here:** **G3 (screen-print decals)** and **G5 (record side texture)** — the two `src/fx/**`-owned tasks. G1/G2 shipped in [GLOWUP_A_handoff.md](GLOWUP_A_handoff.md); G4 in [src/worldgen/HANDOFF.md](../src/worldgen/HANDOFF.md). **Status:** ✅ G3 complete, browser-verified in the real game (port 5212), typecheck clean, zero console errors. **G5 texture generator complete; its platter wiring is left for Lane D** (this lane does not edit `platter.ts`). --- ## What shipped ### G3 — screen-print decal system ([src/fx/decals.ts](../src/fx/decals.ts), new) A `DecalSet` that bakes text/markings onto `CanvasTexture`s and applies them to thin plane meshes floating `0.05` proud of the gear faces, with `polygonOffset` (`factor/units = -4`) so there is **no z-fighting** even at grazing angles. One canvas per gear piece → **13 plane meshes total** (< the brief's 25 draw-call budget; measured live via `window.TURNCRAFT.decals`). All positions derive from `LAYOUT` (`src/core/constants.ts`) and the worldgen anchors (`MIXER`, `DECK_A`, `DECK_B`, `PATCH`, `UNDER` from `src/worldgen/anchors.ts`) — **nothing hardcoded**, so a booth-layout change moves the print with it. Print set (all browser-confirmed legible at play distance): - **Mixer face:** `CH 1–4` ahead of each fader alley, a tick ladder down each alley, the `TURNCRAFT-800` wordmark, and crossfader `A ↔ B` (A on the deck-A side). - **Each deck:** `START·STOP`, `33`/`45`, a pitch `+/−` scale ladder, and a "Quartz Direct Drive" script along the plinth front. Placed on the plinth ring/corners, clear of the platter radius (no clipping with the spinning record — verified at 33). - **Patch bay:** `PATCH BAY` + `01–12` socket numbers aligned to the grid (on the alu panel face, `backWallZ − 2`, not the raw wall behind it). - **Fuse box:** `FUSE 250V` legend. - **Four procedural party flyers** (word-bank names, one accent colour + border each): two flanking the patch bay on the bare back wall, two on the side walls near the front lip. Orientation detail: on flat (`up`) faces the plane's canvas-up points to the booth front, so each glyph is flipped 180° **in place** (letterforms only — positions and tick marks stay put) to read from the player's front-edge view. ### G5 — record side texture (`recordSideTexture()` in the same file) A fine light/dark groove-ring `CanvasTexture` for the vinyl tier **side** cylinders (rings horizontal, `RepeatWrapping`, `NearestFilter`). Standalone generator, no side effects. **Left for Lane D to wire into `platter.ts`** — exact snippet in [src/fx/HANDOFF.md](../src/fx/HANDOFF.md) (Glow-Up section). ## Files touched | file | task | note | |---|---|---| | `src/fx/decals.ts` | G3+G5 | **new** — `DecalSet`, `recordSideTexture()` | | `src/main.ts` | merge | additive: build `DecalSet`, add `.group` to scene, dev handle | | `src/fx/HANDOFF.md` | docs | API + the `recordSideTexture()` wiring snippet for Lane D | **Merge points (per the brief):** - `src/main.ts` — shared with the Workshop + Glow-Up-A briefs. My edits are 3 disjoint additive lines (import, `new DecalSet()` after the machines block, and `decals` on the `window.TURNCRAFT` handle). - `src/worldgen/buildBooth.ts` — listed as a merge point, but **not needed**: G3 reads existing anchors rather than adding worldgen dressing, so buildBooth is untouched. ## Verification (real game, port 5212) - `npm run typecheck` — **clean** (exit 0), whole tree. - Cine screenshots (`window.TURNCRAFT_CINE`): mixer face, deck top, patch bay, side-wall flyer, and a grazing pass across the mixer — every label legible and correctly oriented, **no z-fighting**, and **zero console errors**. - Draw calls: `window.TURNCRAFT.decals` → **13** meshes (< 25). Also **logged at runtime** in the `DecalSet` constructor: `[turncraft] screen-print decals: 13 draw calls (budget < 25)`. - Confirmed the decals are additive: toggling `decals.group.visible` removes only the labels/flyers; the floating `+` shapes near the patch bay are the pre-existing RCA cable plugs (Lane C), not decals. - **No quest regression:** decals live in `decals.group` (a `MeshBasicMaterial` plane group) and add **zero** physics colliders (`machines.getColliders()` stays 58); interaction is voxel-DDA raycast, not scene-mesh raycast, so the decal planes cannot intercept use/mine rays. Booth build unchanged: **746 ms, 467 chunk meshes** (< 600), deterministic (anchors untouched). - **fps:** synchronous per-frame render timing (rAF is throttled in the preview pane) at the mixer, retina buffer: bloom-off ≈ 440 fps, bloom-on ≈ same order — decals (13 static planes) add no measurable regression; comfortably > 100. - Sits cleanly alongside G1 (atlas variants), G2 (LED bloom), G4 (dense knobs). ### Before/after screenshots (`docs/progress-cutoff/`) Captured via `window.TURNCRAFT_CINE` in the real game (port 5205): `mixer_before.jpg` / `mixer_after.jpg` (flagship before/after), `deck_top_after.jpg` (Deck A — `START·STOP` + plinth script, clear of the platter), `pcb_fuse_after.jpg` (`FUSE 250V` legend over the PCB-trace floor), `fullbooth_win.jpg` (emissive-lifted "living booth" — decks, mixer labels + glowing alley pips, patch wall + flyers). ## G5 texture fix (post-merge regression) Lane D found the merged `recordSideTexture()` had a **dark base** (`#101013`), which as a multiply `map` blacked out the vinyl (Deck A side measured `~[38,66,152] → ~[10,8,8]`). Contradicted this doc's "near-white base" intent — the other writer's dark version had won the merge. **Fixed:** inverted to a near-white base (`0.97`) with faint dark groove lands (`0.60`), a soft shoulder (`0.80`) and a bright sheen lip (`1.0`), 16 rings/tile — neutral greys so the multiply never shifts hue. Re-verified live via `readPixels` on the actual Deck A record side (map applied to `sideMat` at runtime, then reverted): blue channel `41 → 36` (~12% dip, stays clearly blue) vs an all-black test map's `41 → 17` blackout. Signature preserved; rings read as subtle sheen. ## Not done / left for others - **G5 platter wiring** — Lane D applies `recordSideTexture()` to the tier-side material in `platter.ts` (snippet in `src/fx/HANDOFF.md`); now safe to wire. ## Note — concurrent edits `src/fx/decals.ts` was refined by another writer mid-session (patch-panel face offset `backWallZ − 2`; flyer wall anchors via `rimThickness`/`WORLD_X`). Those changes are correct and were kept; the browser verification above reflects the merged file.