# THREADS — append-only lane log One line per landed feature, contract change, or open question. Format: `[lane letter] YYYY-MM-DD — note` [.] 2026-07-16 — repo seeded: DESIGN.md (canon), PLAN3D.md (build plan), prototype/ (2D reference, do not modify) [A] 2026-07-16 — **M0 LANDED on main — rebase your lane onto it now.** stdlib `server.py` on :8801 (`--selfcheck` verifies the tree + prints URLs), `.claude/launch.json` → "shades3d", three r175 vendored in-repo at `web/world/vendor/` (no more reaching into 90sDJsim at runtime), `contracts.js`, graybox 30×20 m yard, third-person camera, selftest harness. `python3 server.py` and it runs. Selftest green: 18 pass / 4 skip (your lanes) in ~90 ms. [A] 2026-07-16 — Yard layout is now FACT, build against it: 7 anchors, same shape as the prototype's — h1/h2/h3 house fascia at x=-5/0/+5, y=2.6, z=-9.9 · t1 tree (-9, 3.2, 2) · t2 tree (8, 3.1, -2) · p1 post (-6.4, 3.9, 7.4) · p2 post (5.3, 3.9, 8) — posts are raked 8° away from yard centre. Garden bed rect {x:1, z:2, w:6, d:4}. North (-Z) is the house edge. Sun sits in the NORTH (Australian yard), elevation 55°, so sail shadows fall south onto the bed — and the house's yard-facing wall is permanently backlit, which is correct and not a bug. [A] 2026-07-16 — **CONTRACT ADDITIONS.** PLAN3D §4 didn't cover these and the code needs them. All are in `contracts.js` with JSDoc. Shout here if any of them fight your lane: · `world.heightAt(x,z) -> number` — ground height, closed-form, pure. Lane D clamps the player to it, Lane C bounces debris off it. · `world.gardenBed -> {x,z,w,d}` — the rect you pass to `sailRig.coverageOver()`. · `world.sunDir -> Vector3` — unit vector from the GROUND **toward** the sun. Shade test is `raycast(origin=groundPoint, direction=sunDir)`; a hit means shaded. · `world.solids -> Object3D[]` — obstacles ONLY. **The ground is deliberately not in it** — use `heightAt()`, it's exact and free. Raycasting 4800 terrain triangles a frame took the camera selftest from 78 ms to 4088 ms before I pulled it out. · `player.update(dt,t)` — main.js has to step the player from somewhere. · `camera.yaw -> number` — Lane D, your WASD is relative to this. · `game.on(type, fn)` with type `'phaseChange'` → `{from, to}`. §4 wrote it as `game.on(phaseChange)`; implemented Emitter-style for consistency with `sailRig.events`. · `checkContract(name, obj) -> string[]` — asserts a module matches its contract. This is the merge tripwire; I run it on every lane's module after every merge. [A] 2026-07-16 — **CONTRACT CLARIFICATION — Lane B read this one.** `anchor.sway(t)` returns the **ABSOLUTE world position**, not an offset. It is exactly what you pin a cloth corner to: `node.copy(anchor.sway(t))`. (The prototype's `anchorPos()` is the precedent.) House and post anchors return a constant; tree anchors wander with the wind they stand in — that wander IS dynamic load, and it's why a tree anchor is the scary choice. Each anchor owns its own scratch vector so two anchors can never alias, but the vector is reused between calls on the same anchor: clone before you store it. Asserted both ways in `js/tests/a.test.js`. [A] 2026-07-16 — selftest.html is **import-only and nobody edits it**. Each lane owns `web/world/js/tests/.test.js` — stubs are pre-created and currently `skip`, with your PLAN3D asserts written into the header comment. Five lanes sharing one selftest.html would be the single guaranteed merge conflict in this repo. Harness + assert helpers in `js/testkit.js`; drive time with `fixedLoop()`, never rAF (rAF is throttled in a hidden tab — verified, the game loop genuinely stalls at t=0.07 s there, so a rAF-driven selftest would be a lie). [A] 2026-07-16 — main.js drives an M0 **placeholder capsule** that satisfies the Player contract, purely so the camera has something to follow. Lane D: when player.js is ready, ping here — I'll swap the factory call in boot() and delete the placeholder. You shouldn't need to touch main.js. [A] 2026-07-16 — ⚠️ **PLAN3D §2's asset inventory was substantially wrong and is now corrected in-place.** Verified against the filesystem on `m3ultra` (Spotlight + find over `~` and `/Volumes`): · `3D-STORE` is at **`~/Documents/Destroyulater/3D-STORE/`**, not `~/Documents/3D-STORE/`. `clean_glbs/` is there and does contain exactly the promised debris (BlueCrate_v2, BlackTub_v2, WhiteTub_v2, WoodenBin_v2, LibraryTrolley_v1). `build_booth_room_v23.py` is there too, and also at `~/Documents/3dstore/`. **Lane E: your inputs are real, just relocated.** · **DOES NOT EXIST anywhere on this box:** `~/Documents/3D=models/` (characters, the 32 anim clips, street-furniture incl. `building_shell_01.glb`, furniture, props-scenes), `~/Documents/character_kit/`, `~/Documents/mixamo-fetch/`, `~/Documents/FBX/`. · Real and verified: the 21-ped fleet at `90sDJsim/web/world/models/peds/`, and `90sDJsim/DEVMANUAL.md`. **Lane D, this lands on you:** §5-D assumed the character_kit retarget pipeline and a Mixamo clip library; neither is here. The only clips I found are `peds/idle.glb` and `peds/walk.glb`. A walking character is still reachable; Running / Falling / Crouch-To-Stand / crank / dig are not sourced. Don't spend a day looking — answer is needed from whoever wrote §2. [A] 2026-07-16 — ⚠️ **WORKTREE COLLISION — happened today, please fix.** Lane D is working inside the shared checkout at `~/Documents/shades/` instead of its own clone. Two agents in one working tree share one HEAD and one index: mid-session Lane D's checkout moved HEAD off `lane/a` onto `main` underneath Lane A, so Lane A's five M0 commits landed on `main` directly rather than on its branch. No damage this time — staged paths were explicit so nothing of Lane D's was swept in, and M0 on main is where it was headed anyway — but the next collision could just as easily eat uncommitted work, and `git checkout` in a shared tree is indistinguishable from sabotage from the other agent's side. Lane A has moved out to `~/Documents/shades-laneA/`. **Lane D: please clone to `~/Documents/shades-laneD/` and work there** — B, C and E already have their own. PLAN3D §0 says to do this; it's the one house rule that has to hold or the whole lane model stops working. [A] 2026-07-16 — ❓ **OPEN QUESTION, needs a human.** PLAN3D §0 says lanes run on "the M1 Ultra (`johnking@100.91.239.7`, Tailscale)", but this box is `m3ultra` and already has `~/Documents/shades-laneB/` and `shades-laneE/` checked out — so lanes are in fact running here, and §0's clone path is what people are actually using. If the four missing libraries above live on that other machine, this isn't a path fix, it's a decision about where lanes run. Flagging rather than guessing.