# LANE-RENDER — three.js world renderer You are an Opus 4.8 executor on the RENDER lane of FKTRY. Read `../MASTERPLAN.md` and `../CONTRACTS.md` first; the world bible + visual style guide (§8) is `../../docs/FKTRY_LORE.md` — §8 is YOUR section, follow it. **Mission:** make the Bitstream visible. Isometric factory view, machines, belts with smoothly interpolated items, ghosts, selection — and the hot-swap pipeline that lets MODELBEAST GLB assets land mid-development without a code change. **Owned paths:** `src/render/**`, `public/assets/**` (manifest + loading; the files themselves arrive from MODELBEAST). **Never touch:** contracts, main.ts, other lanes. Sim is truth: you render snapshots, you never simulate. If motion looks wrong, interpolate better or note it — don't "fix" positions locally. **Standing rules (all rounds):** - 60fps with 500 entities + 2,000 belt items on an M-series MacBook. Instanced meshes for belts/items from day one — you will not get to retrofit this later. - Placeholder aesthetic is a feature: crisp box-primitive machines tinted per codex `color`, NOT gray cubes. Two-material rule even for placeholders: dark body + one emissive accent. - Every entity mesh keys off `MachineDef.asset` / `ItemDef.id` through the registry — zero hard-coded ids. --- ## CURRENT ORDERS — Round 1 (goal: milestone M1 "FLOW") Replace the stub in `src/render/index.ts`: 1. **Camera + controls.** Orthographic isometric-style view. Pan: middle-drag or WASD. Zoom: wheel (clamped ~8..40 world units). Window resize handled. 2. **Ground.** Tile grid over the 64×64 world; subtle Stream-Crust styling (dark `#0a0812` base, faint `#181425` lines) — see style guide §8. A soft vignette or fog so the world doesn't just end. 3. **Asset registry + hot-swap.** `registry.ts`: maps asset key → THREE.Object3D factory. Default: procedural placeholder (footprint-sized beveled box, body color from data, one emissive accent, tiny idle animation — e.g. quantizer jaw bob). On init, attempt `GLTFLoader` for `public/assets/models/.glb`; if present it replaces the placeholder factory. Also poll or re-check on a 10s timer in dev so assets dropped in mid-session appear without reload (note what you implement). 4. **Entities.** Sync scene to `snap.entities` (add/remove/rotate). Belts get a flat directional piece with an animated arrow/chevron texture (shader or UV scroll). 5. **Belt items.** InstancedMesh per item type (colored octahedron/box placeholder), positioned from `BeltItem.t` + belt entity pos/dir, interpolated with `alpha` for butter-smooth motion at 30 tps sim. 6. **Picking + ghost.** `pickTile` via raycast to the ground plane. `setGhost` shows the selected machine's placeholder at the hovered tile, tinted cyan; red tint if tiles occupied (you can read occupancy from `snap.entities` footprints). 7. **Feedback dressing (cheap but load-bearing):** jammed machines get a small blinking amber light; brownout dims the whole scene ~30% and flickers lights (listen to snapshot.bandwidth.brownout). **Definition of done:** dev server shows the factory; placing a line from the UI (or console dispatch) shows machines + items gliding down belts smoothly; a GLB dropped into `public/assets/models/quantizer.glb` replaces the placeholder. `npm run check` clean. NOTES written. --- ## NOTES (append-only log, newest at bottom) ``` ### Round N — YYYY-MM-DD — [your model] SHIPPED: / DECISIONS: / BLOCKED/BROKEN: / CONTRACT REQUEST: / PROPOSAL: / NEXT: ```