diff --git a/docs/LANES/ROUND3_INSTRUCTIONS.md b/docs/LANES/ROUND3_INSTRUCTIONS.md new file mode 100644 index 0000000..14c3bb5 --- /dev/null +++ b/docs/LANES/ROUND3_INSTRUCTIONS.md @@ -0,0 +1,123 @@ +# PROCITY — Round 3 lane instructions (from Fable, integrator) + +Date: 2026-07-14 · Written after all six lanes finished round 2 and Lane F's first two +integration passes landed. Repo state as of these instructions: **everything committed on +`main`**, `tools/qa.sh --strict` **GREEN** (4/4 gates, selfcheck 1283/1283, manifest 0 errors). + +## Where we are + +v1 is **integrated and playable**: the game boots on Lane A's generated town (seed 20261990 → +"Boolarra Heads", 493 shops), Lane B streams/renders it under budget, doors enter Lane C +interiors, Lane D keepers greet at counters and peds walk the streets, Lane E's 48 facades + +manifest are live, Lane F's bridge + QA harness tie it together. What remains is **polish, +validation, and the last two integration steps** (LANE_F_NOTES §3.4/§3.5). + +## Integrator decisions (so nobody blocks on them) + +1. **Retail density stays at ~493 shops/core.** Lane B's facade atlas got the worst view to + ~261 draws with citizens; no need to thin the town for v1. +2. **True closed residential ring → v2** (stays in V2_IDEAS). +3. **F finding #4 (doubled possessives) is CLOSED** — verified 0 across 2,418 shop names / + 5 seeds on current main. It predated Lane A's round-1 fix. +4. **Depot publish and the ~$2.70 MeshGod hero batch remain gated on John** — do not publish, + do not spend. Local validation paths below unblock everything else. + +## Process rules (unchanged, they matter) + +- Lanes share ONE working tree. Never bare `git add .` / `git commit -a`. Stage **only your + files by exact path** and commit immediately. Check `git status` first; touch nothing + another lane has modified. +- Real repo path is `/Users/m3ultra/Documents/procity` (old prompts say /Users/jing — wrong). +- Update your `*-progress.md` at the end of your session; leave notes for other lanes in + `docs/LANES/`. +- Dev server: `cd web && python3 -m http.server 8130`. +- Run `bash tools/qa.sh --strict` before you finish; leave it green. + +--- + +## Lane A (CityGen) — on-call + one verification + +Small round. Priority order: +1. **Verify F finding #5**: "some shops have storeys outside the registry type range (e.g. + video at 2, range [1,1])". Your round-1 `cornerBoost` gate (registry max ≥ 2) may already + have fixed it — prove it on current main across ≥5 seeds. If real, fix + add a selfcheck + assertion; if stale, mark it closed in A-progress. +2. Confirm the committed `GOLDEN.hash` matches the current selfcheck fingerprint (`0x098eec2b`). +3. Otherwise standby: answer contract questions from F's §3.5 hours work (your `openLate` / + `hours=[open,close]` contract is about to get its first real consumer). + +## Lane B (Streetscape) — draw-budget shave + hooks + +1. **F finding #3 (the one open budget item): ~334 draws at spawn with radius 3.** Your + radius-2 auto measure is ~261. Make the compliant configuration the default at spawn + (radius 2 auto, or more merging if you'd rather keep 3) and re-measure the worst + continuous-walk view **with citizens at pop 140** via `window.DBG`. Target: ≤300 + everywhere, documented in LANE_B_NOTES. +2. **Confirm `scene.environment` is set** in all modes — Lane D's PBR peds go dark without it + (F verified street mode works; check night + interior-return edge cases). +3. Support F's §3.4: when the manifest GLB upgrade lands, verify street furniture GLBs + (benches, streetlight, food cart) place on their manifest footprints without collision + regressions. +4. Optional polish: fresh `docs/shots/laneB/` stills of the *generated* city; wire `map` mode + to Lane A's map.html. + +## Lane C (Interiors) — GLB path visual validation + +Your `glb.js` path is wired but never seen pixels. Lane E's 16 normalized GLBs exist locally +in `pipeline/_normalized/` — you don't need the depot publish. +1. Coordinate with Lane E's local-depot mode (below); flip `useGLB` on and **visually validate + every fitting GLB in real rooms**: correct scale on footprint, base on floor, facing −Z, + no z-fighting with primitive decor. +2. Re-run your sweep + soak with `useGLB` on: 0 throws / 0 path-fails / 0 leaks, perf still + <50ms warm. GLB textures must dispose correctly on room exit. +3. Report any footprint/origin mismatches to Lane E by file name (they have 3 known near-miss + assets already excluded). +4. Screenshot evidence into `docs/shots/` (a laneC dir is fine). + +## Lane D (Citizens) — small support round + +1. When F's §3.4 fleet upgrade lands, verify keepers upgrade from placeholder to shared GLB + rigs and remain leak-free over enter/exit cycles (your dispose contract, F's loop). +2. Wire/document `ImpostorLayer.setExposure()` to the shell's day/night segment so mid-tier + billboards match rigs at dusk (one paragraph + one verified call site with F). +3. Write the **chunk-streamed roster design note** (keyed `chunkKey+i`, stream with Lane B's + chunk build/dispose) — design only, no implementation; it's the v1.5 fix for big-town + street emptiness. + +## Lane E (Assets) — local depot mode + near-misses + +Publish stays gated (needs `GOD3_PW` + provenance recording — John's call). +1. **Unblock local validation**: make `core/loaders.js` (or a manifest/URL flag, e.g. + `?localdepot=1`) resolve `depot:` to the locally staged GLBs so Lanes B/C/F can + validate before publish. Keep the placeholder-on-miss behaviour. +2. Support Lane C's visual validation — fix any origin/footprint mismatch they report + (your normalize.py now handles hierarchies; re-run per asset). +3. Optional: manual Blender re-origin pass on the 3 near-misses (garage_shelves, radiogram, + market_stall) if C wants more variety; otherwise leave to primitives. +4. Have the publish command + per-asset provenance list **staged and documented** so the + moment John says go it's a 5-minute job. + +## Lane F (Integration) — lead lane this round + +Priority order, per your own §3 plan: +1. **§3.4 Manifest + `?noassets`**: GLB upgrades from manifest.json through B (street + furniture) and C (`useGLB`), using E's local-depot mode; includes the **rig-fleet upgrade** + so keepers/peds share GLB meshes (then try raising `?pop=`). Verify `?noassets=1` still + runs 100% primitive/fallback with zero network. +2. **§3.5 Hours / closed shops**: consume Lane A's contract — `hours=[open,close]` 24h ints, + **exactly one `openLate:true` landmark per town** (closes ≥22:00). Closed shops: door + locked + toast, lights/sign off after close; the openLate shop is the night destination. +3. **Browser QA gates 1–4,6**: `tools/shots.py` + `tools/soak.py` against `window.DBG` + (B's dbg.js is committed). Capture the `docs/shots/v1_tour/` set. Re-measure budgets after + B's shave; update the gate table in LANE_F_NOTES. +4. Keep the findings table current; anything cross-lane goes through a note in `docs/LANES/` + + a line in the target lane's instructions, not silent edits (inline seam edits marked + `[Lane F integration]` are fine where they're your seam). + +## Needs a human (John) + +- **Push to origin** — main is now 10 commits ahead of origin/main (only the scaffold is pushed). +- **Depot publish go/no-go** (needs `GOD3_PW`; E will have it staged). +- **~$2.70 MeshGod hero-prop batch** go/no-go (pure polish; primitives cover everything). +- **A real pointer-lock playtest** — automation can't engage pointer lock; + `cd web && python3 -m http.server 8130` → http://localhost:8130?seed=20261990. diff --git a/priorwork/procity-a.txt b/priorwork/procity-a.txt new file mode 100644 index 0000000..b9e9320 --- /dev/null +++ b/priorwork/procity-a.txt @@ -0,0 +1,188 @@ +Thanks — good to know. The docs referenced `/Users/jing/...` but the repos live at `/Users/m3ultra/Documents/{thriftgod,90sDJsim}` here, and ultra (`johnking@100.91.239.7`) is reachable. For Lane A (pure-data generator + 2D map) my algorithm is bespoke, so I don't need to port engine code — but I'll keep the thriftgod REFIDEX map vibe and seeded-hours patterns in mind. Continuing with `plan.js`, the core generator. + +I left messy placeholder lines in the main-street strip loop. Let me clean that up. + +The warehouse block also has dead placeholder lines. Let me clean it. + +Now the self-check — the node-runnable acceptance harness. This is what will catch my geometry/determinism bugs empirically. + +Now let me run the self-check to catch bugs empirically before building the map viewer. + +Only the overlap check fails; determinism, performance, structure, assets, and brief-presence all pass (909 lots, 722 shops — a dense retail town). The overlapping pairs are always the first sequential lots in a block, which by construction have disjoint along-street intervals — so this is almost certainly a rounding artifact at touching edges. Let me measure the actual overlap magnitude before deciding. + +Confirmed: it's a rounding artifact. Lots 1 and 2 are sequential along the street and merely *touch* at a shared boundary — but 2-decimal rounding pushes the touching edge past my 1mm SAT tolerance. Real overlaps in this generator would be metres, not centimetres. Let me widen the tolerance to 5cm and check the shop-type breakdown. + +Still failing on seed 8675309 (lots 2,3) even at 5cm — so that one is a *real* overlap, not rounding. And stalls (238) are wildly over-dominating the shop count. Let me measure the real overlap and see what's special. + +The overlap is tiny (~5mm by center spacing) yet SAT still flags it at 5cm — my geometric reasoning about the minimal axis must be off. Let me measure the actual SAT penetration directly rather than guess. + +Found it: the SAT axis in `overlaps()` isn't normalized, so my 5cm `EPS` is scaled by edge length (~19×) and becomes inconsistent per-axis — the real penetration is 5.6mm, well under tolerance. Normalizing the axis fixes it correctly. And I'll trim the market from 238 stalls to a tidy ~40. + +All green — 1082/1082 checks pass. Now the crucial visual deliverable: `map.html`, the Canvas-2D debug viewer. This is how humans and Lane F eyeball a seed, and it grows into the in-game map. Let me build it. + +The map needs to be served over HTTP (ES module imports fail on `file://`). Let me start the dev server and load it in the browser to verify it renders as a town. + +Server is up. Let me load the map in the browser and screenshot seed 20261990. + +Panel data is perfect (Boolarra Heads, 22 streets, 711 lots, 523 shops, type breakdown), but the canvas collapsed to a dot — `fitView()` ran before the browser finished layout, so it read zero canvas dimensions and computed a near-zero scale. Let me fix the boot order (resize → fit under `requestAnimationFrame`) and guard `draw()` against a null plan. + +It reads clearly as a town now: the N–S retail spine, 4 jittered cross-streets (2 long central high streets + 2 shorter backstreets), the market stall grid + dept anchor (pink) west of centre, the residential collar ring with red milkbars at its corners, and the warehouse fringe block at the north edge. Let me zoom into the centre to confirm the arcade and market/dept detail. + +Zoom-crop isn't supported; let me use the app's own zoom (scroll) to inspect the centre — the market grid, dept anchor, and arcade. + +The map renders as a town with every brief element present. Browser mouse-interaction is sluggish because my `mousemove` handler redraws all 711 lots on every event — a real UX smell for a tool Lane F will use. Let me coalesce redraws with `requestAnimationFrame` before capturing screenshots. + +Now let me capture screenshots for 5 seeds into `docs/shots/laneA/` via the canvas's `toDataURL`, saving each to disk. Starting with the directory and seed 20261990. + +Now I need real PNG files on disk. The cleanest path is headless Chromium screenshotting the live page. Let me check what browser binaries are available. + +Chrome is available. Let me screenshot all 5 seeds headlessly to `docs/shots/laneA/`. + +Exit 143 = timeout, likely a profile-lock hang from the shared `--user-data-dir` plus the screenshot firing before my rAF render runs. Let me kill stragglers, check what landed, and retry with `--virtual-time-budget` (lets JS/rAF run) and per-run isolation. + +Seed 20261990 rendered (200k). The rest hung on profile-lock. Let me force-kill all Chrome and verify that first PNG actually shows the town before retrying the rest. + +That's a proper town at full res — spine, 4 cross-streets, market stall grid + pink dept anchor, the record-heavy arcade cluster beside it, the warehouse block up north outside the ring, the green residential collar with red milkbars at its corners. The hang was just the shared profile lock. Let me capture the remaining 4 seeds, each with a unique profile dir and a per-run watchdog so nothing hangs. + +All 5 captured (187–212k each). Let me verify two of them show distinct, valid towns (seed variety). + +Seed 42 is a distinctly different town — "Mount Yinnar Gully", 684 lots, 500 shops, different spine bends and rung angles, 4 corner milkbars. The name generator and full determinism-with-variety both work. Now let me verify the grep-clean requirement (zero `Math.random`/THREE in citygen) and remove the unused THREE importmap from map.html. + +citygen and registry are grep-clean (no `Math.random`, no THREE). The only `Math.random` is map.html's 🎲 random-*seed* button (UI-only; generation stays fully seeded). But the THREE importmap in map.html is dead code — the page is pure Canvas 2D and never imports three. Let me remove it. + +Let me confirm removing the importmap didn't break the page, then launch the adversarial review. + +No console errors, importmap removal is clean, and seed 777 ("Lower Corryong Hollow") even placed its warehouse fringe to the *south* — the seeded N/S pick works. All 5 deliverables are built and empirically verified. + +Now the ultracode adversarial pass: I'll fan out a multi-dimension review of the whole lane (determinism, schema/spec-compliance, geometry, chunk/JSON/perf, cross-lane contract, code quality), then adversarially verify each finding before I act on it. + +The review is running in the background. While it works, let me draft the `A-progress.md` report Fable asked for. I'll finalize it after applying any confirmed review findings. + +While the review runs, let me independently sanity-check a couple of things the review will also probe — that plans contain no `NaN`/`Infinity` (which JSON silently turns to `null`) and that `chunkIndex` doesn't mutate the returned plan. + +Independent checks pass: no `NaN`/`Infinity`/`null` leaks, `chunkIndex` doesn't mutate the plan, JSON round-trips, and edge-case seeds (0 and max-uint32) both generate valid towns. + +**Lane A is built and empirically verified.** Here's where things stand while the adversarial review finishes: + +**Done & green:** +- `plan.js` (`generatePlan` + `chunkIndex`), `registry.js`, `names.js`+`wordlists.js`, `map.html`, `selfcheck.js` — all landed +- `node web/js/citygen/selfcheck.js` → **ALL GREEN, 1082/1082** across 6 seeds +- 5 seeds screenshotted to `docs/shots/laneA/` — each reads as a town (spine, cross-streets, market+dept, arcade, warehouse fringe, residential collar with corner milkbars) +- grep-clean: zero `Math.random` / zero THREE in citygen +- `docs/A-progress.md` drafted for your review + +**In flight:** a 6-dimension adversarial review (determinism · schema/spec · geometry · chunk/JSON/perf · cross-lane contract · code quality) with per-finding refutation. I'll apply any *confirmed* findings, re-run the self-check, append the outcomes to `A-progress.md`, then commit the lane on `main` (per the LANE_A brief's "commit in small steps" instruction; no push). + +I'll continue automatically when the review reports back. + +The review completed (27 agents, ~1.6M tokens). It confirmed at least two real defects — a genuine facing bug in the market builder that my self-check couldn't catch (no orientation assertion), and a registry↔spec drift. The result was truncated at 57KB; let me read the full output to see every confirmed finding before acting. + +The Bash classifier is temporarily down; read-only tools still work. Let me read the output file directly. + +A high-value review: 21 findings, 15 confirmed. Several are the same defect found from multiple angles. Let me read the rest to capture all distinct confirmed issues. + +This review paid for itself — 15 confirmed defects, several my self-check structurally couldn't catch (no facing/orientation check, only within-block overlap, no edge-coverage check). Deduplicating the multi-angle repeats, here are the **distinct** confirmed issues: + +| # | Defect | Sev | Fix | +|---|--------|-----|-----| +| D1 | Market stalls + dept anchor face **backwards** (`ryEast=atan2(1,0)` → west, away from spine) | HIGH | `atan2(-1,0)` | +| D2 | **Cross-block lot overlaps** at spine×cross-street corners (~45 shop pairs/seed, ≤8.7m); self-check only tests within-block | HIGH | corner reservation + resolution pass + global self-check | +| D3 | `chunkIndex` **skips chunks** (32m sampling on 64m grid); origin chunk misses the spine; road width ignored | HIGH | DDA supercover + width rails | +| D4 | Market stalls' `frontEdge` points at wrong spine segment (z-band mismatch) | MED | stalls→`spineEdges[2]`, dept→`[3]` | +| D5 | Name generator emits doubled possessive `Macca's's` | HIGH | drop redundant `*` | +| D6 | map.html main-road color `var(--roadmain)` unparseable by canvas → spine mis-drawn | MED | bare `--roadmain` | +| D7 | Registry facades/fittings drift from CITY_SPEC table | LOW | update CITY_SPEC table (treaty change) | + +Plus valid points from *refuted* findings worth acting on: no golden-fingerprint drift check, `cornerBoost` can exceed a type's storey max, undocumented `block.kind`/`block.district`-is-id, dead stall guard, and the map's `_sbl` cache polluting exported JSON. + +Let me re-read the current plan.js to make precise edits. + +Now let me apply the plan.js fixes. First, the `cornerBoost` storey gate: + +Now the market builder — D1 (ryEast) + D4 (frontEdge per z-band) + R6 (dead guard). Let me read the current market section. + +Now D2 — corner overlaps. First, bump the rung near-spine inset to reserve the corner against the spine strip's depth. Let me read the rung-strip section. + +Now the resolution pass. Let me read the laneways + return section to place it correctly. + +Now I'll insert the corner-overlap resolution pass before the return, and add shared OBB helpers at the top of the module so both `chunkIndex` and the pass can use them. + +Now add the shared `lotCorners` and `obbOverlap` helpers at module top (used by the resolution pass and `chunkIndex`): + +Now D3 — replace `chunkIndex`'s edge point-sampling with a DDA supercover (+ width rails so a wide road registers in every chunk it covers). Let me read the current edge section. + +Now D5 — the doubled-possessive name bug. Remove the redundant `*` from the six `{First}*` patterns and simplify `fill()` (the `*` mechanism is now dead). + +Now map.html — D6 (main road color) and the `_sbl` cache polluting exported JSON. + +Now the self-check enhancements — this is critical: the review proved my harness had blind spots (no orientation check, only within-block overlap, no edge-coverage, no drift detection). Let me rewrite `selfcheck.js` to import the shared OBB helpers (single source of truth) and add: a **global cross-block building-overlap** check, an **edge-coverage** check, a **facing/orientation** check, a **finiteness** check, and a **golden-fingerprint** drift guard. + +The golden placeholder is invalid JS. Let me set it to 0, run to get all checks + the real fingerprint, then lock it in. + +All checks pass except the placeholder fingerprint (`0xb5d5cc13`). The new guards confirm the fixes: **facing** ✓ (D1), **cross-block building overlap** ✓ (D2), **edge coverage** ✓ (D3), plus finiteness, storey-range, and no-unresolved-token (D5) all green. Lot count dropped 711→681 (the corner resolution demoted ~30 colliding lots to infill). Let me lock in the golden hash. + +ALL GREEN — 1271/1271. Let me verify the two headline fixes produce correct output empirically (the doubled-possessive and the market facing). + +D1 facing is fixed (dept + stall now face `[1,0]` = east toward the spine). My name-check seed was off; let me scan a full set of plans for any lingering doubled-possessive `’s’s`. + +D5 confirmed: zero doubled possessives, names like "Macca's Pawn & Loan" render cleanly. Now the treaty change (D7) + schema documentation. Let me read the relevant CITY_SPEC sections. + +Now the shop-types table (D7 treaty change). Let me read and update it to match the registry. + +Now the ownership-table note for `web/package.json` (R4). Let me read that section. + +All 15 confirmed findings plus the worthwhile refuted-but-valid points are now addressed, and the self-check is green at 1271/1271. Let me refresh the 5 screenshots to reflect the fixes (corrected main-road color, corner de-confliction). + +The main-street spine now renders in its proper lighter-brown (`--roadmain`) — a clearly distinct wide road (D6 fixed), and the corners are de-conflicted (D2). 681 lots / 493 shops / 174 chunks. All fixes are reflected in the map. + +Let me append the review outcomes to `A-progress.md`. + +All fixes documented. Let me run a final verification pass — self-check, grep-clean, and review the git status before committing. + +I see the situation clearly now: **this is a shared working tree and lanes B/C/D/E/F have been running in parallel** — there are untracked `C/D/E/F-progress.md`, `pipeline/`, `web/index.html`, `web/js/world/`, `web/js/interiors/`, `web/js/citizens/`, etc., plus a modified `.gitignore` I didn't touch. Let me check whether `CITY_SPEC.md` contains only my edits before deciding anything about committing. + +`CITY_SPEC.md` contains **only my edits** (verified), `.gitignore` was changed by Lane E (not me), and my owned files are cleanly separable. The LANE_A doc I was told to execute explicitly says "commit in small, described steps on `main`," so a clean, isolated lane commit is the right review unit for Fable. I'll stage **only my owned paths** — never other lanes' files, `.gitignore`, or shared dirs. Let me confirm the shots directory contents first. + +Two things stand out: `docs/shots/` is a shared scaffold (lanes B–E all have shots there), so I'll stage only `docs/shots/laneA/`. More importantly, **there's a `web/js/citygen/index.js` I did not create** — something (another lane or a coordinator) wrote a file into my owned directory. I need to look at it before doing anything. + +`index.js` is a **Lane F integration shim** in my owned directory: Lane B's shell imports `./js/citygen/index.js` expecting `generatePlan`, and it explicitly says *"If Lane A later adds its own citygen entry point, fold this into it."* Since `web/js/citygen/*` is my ownership and Lane F invited me to adopt it, I'll make it a canonical Lane A barrel — but first let me verify exactly what Lane B's shell imports so I don't break the wiring. + +Lane B does `citygen.generatePlan || citygen.default` from `./js/citygen/index.js`, falling back to a fixture if absent. I'll adopt `index.js` as the canonical Lane A barrel — preserving the exact exports Lane B needs and rounding out the public API. + +Let me verify the barrel resolves correctly under node (Lane B's import pattern). + +Barrel works — Lane B's shell will now get the real generator. Now I'll commit my lane, staging **only** my owned paths (never `.gitignore` or other lanes' files). Let me stage precisely and review before committing. + +Staging is cleanly isolated — only Lane A files, with `.gitignore` and all other lanes' work left untouched. Committing now (on `main`, no push): + +Committed cleanly as `8b7ca9a` — the 27 remaining uncommitted entries are all other lanes' work and `.gitignore`, left untouched. Let me do a final runtime check on the map (I changed `index.js`, `EDGE_STYLE`, and the `_sbl` cache) to confirm no console errors and a clean JSON export. + +No console errors. Let me confirm the `_sbl` cache fix — that the plan object stays schema-clean after drawing (no stray key in exports). + +No console errors, no schema pollution, clean export. `window.plan` being empty just confirms proper module encapsulation (the fix moved the cache off the plan object). Everything is verified and committed. + +--- + +## Lane A (CityGen) — done, verified, committed + +**PROCITY-A reporting.** I read Fable's docs (CITY_SPEC + LANE_A brief + RESEARCH), built the full lane, hardened it with an adversarial multi-agent review, and committed cleanly on `main` (`8b7ca9a`, no push). + +**Delivered** (all owned paths only): +- `web/js/citygen/plan.js` — `generatePlan(citySeed)` → CityPlan (spine, cross-streets, market square + dept anchor, arcade, warehouse fringe, residential collar w/ corner milkbars, laneways) + `chunkIndex` + `index.js` barrel entry +- `web/js/core/registry.js` — `SHOP_TYPES` (all 9) + district weights + enums +- `web/js/citygen/names.js` + `wordlists.js` — seeded 90s-AU names, 50+ patterns +- `web/map.html` — Canvas-2D plan debugger (pan/zoom/hover, layers, export JSON) +- `web/js/citygen/selfcheck.js` — `node …/selfcheck.js` → **ALL GREEN 1271/1271** +- `docs/shots/laneA/` — 5 seeds screenshotted, each reads as a town +- `docs/A-progress.md` — full writeup for your review + +**Verification I actually ran** (not just claimed): node self-check green over 6 seeds; browser + headless screenshots across 5 seeds; a 6-dimension **adversarial review (27 agents)** that found **15 real defects** — all fixed and re-verified, with the self-check grown so none can regress (facing check, cross-block overlap, edge coverage, finiteness, golden fingerprint `0xb5d5cc13`). Sample: seed 20261990 → "Boolarra Heads", 681 lots / 493 shops / 174 chunks. + +**Things you'll want to know as coordinator:** +1. **Integration already in motion:** I found a Lane F shim (`web/js/citygen/index.js`) — Lane B's shell imports `./js/citygen/index.js` for `generatePlan`. I adopted it as the canonical Lane A barrel (its own note invited this); Lane B now gets the real generator instead of the 14-shop fixture. +2. **Treaty amendment (in my commit, flagged loudly):** I aligned CITY_SPEC's shop-types table to the registry lanes actually import, and documented `lot.ry`/`frontEdge`, `block.kind`/`district`-is-id, and `web/package.json` (`{"type":"module"}`, needed for the node self-check). +3. **I left everything else alone:** `.gitignore` (Lane E's change) and all B/C/D/E/F files remain uncommitted/untouched — my commit is isolated to Lane A paths. + +**Open questions for you** (in A-progress): retail density (~500 shops/core — dial down for Lane B's draw budget?) and whether the residential collar should become a true closed ring. Awaiting your review + next instructions. + +The dev server is still up on `:8130` if you want to eyeball seeds (`/map.html?seed=…`). \ No newline at end of file diff --git a/priorwork/procity-b.txt b/priorwork/procity-b.txt new file mode 100644 index 0000000..2bb8e46 --- /dev/null +++ b/priorwork/procity-b.txt @@ -0,0 +1,206 @@ +b cutoff + +Thanks — that's a big help. 90sDJsim is the primary reference for Lane B (its `buildStrip` and `applyLighting` are exactly what I'm generalizing). Let me pull those key patterns before continuing: + +I have the key `applyLighting`/`buildStrip` patterns. Now the facade kit — the biggest module. Task 3: + +Now ground.js — I'll build the road/footpath/plaza network **once** as merged strips (persistent, not per-chunk streamed): with only a handful of edges this is far cheaper and seam-free versus per-chunk clipping. Task 4: + +Now furniture.js — instanced street furniture with mandatory primitive fallbacks (GLB depot upgrade documented but off by default for v1 robustness). Task 5: + +Now lighting.js — sky dome + 6-segment day/night cycle (global, with fog to mask chunk pop-in). Task 6: + +Now player.js. Let me first check the vendored PointerLockControls API (r175 changed some method names): + +`_euler` re-syncs from the camera each move, so I can set orientation directly. Writing player.js. Task 7: + +I made a sign error on the strafe vector — camera-right = cross(forward, up) = (−fz, 0, fx). Let me fix: + +Now hud.js. First let me attach `doorRects` to the door mesh userData so the HUD can map raycast hits to shops: + +Before writing the streamer, I need the fixture town to actually span enough chunks that streaming triggers with the default radius 3. Let me widen the main street to ~6 chunks (24 shops across 4 north + 2 south blocks): + +Now widen the street nodes to match: + +Now the streamer. First, one efficiency fix in buildings.js — make the 2048² sign atlas lazy so shopless chunks (mid-street) don't each allocate a 16MB canvas: + +Now the streamer — chunks.js. Task 8: + +Now the shell — index.html. Task 10. Let me also write a small minimap module for `map` mode. First index.html: + +Now the shell — index.html: + +Before booting, I caught a few bugs by re-reading. Let me fix them. First, the ground quad winding — my triangles wind so the geometric normal points **down**, so `FrontSide` ground would be invisible from above: + +Now fix the spawn heading (should look east into town) and add click-to-relock: + +All modules written. Now let me boot the server and verify in the browser. Task 11: + +Server started from the wrong directory — it needs to serve from `web/`. Let me fix that: + +All paths resolve. Let me open it in the browser and check the console for errors: + +No errors. Let me take a screenshot to see the start screen, then enter the town: + +Start screen renders cleanly. Let me verify the full script initialized (it exposes `window.PROCITY` only at the very end) and check the plan built correctly: + +I need an expression, not a return statement. Let me wrap it: + +The script errored before completion. Let me reload and capture the error: + +Console capture is missing module-load errors. Let me probe each module directly with a dynamic import to find the failure: + +All modules parse and import fine — so the error is a runtime throw during inline setup. Let me replay the setup to find the throwing call: + +Setup replays fine (26 items incl. stalls, 8 chunks warmed). The failing piece must be the post-processing / HUD / minimap chain that my replay skipped. Let me test those: + +Everything works in isolation — the earlier `initialized:false` was likely a timing read during the top-level `await` on the citygen 404. Let me re-check now that it's settled: + +Still failing at runtime though it replays fine — let me confirm the served `index.html` is actually my latest version and hunt the real error. Let me capture it via a fresh load with an error listener: + +There's a genuine runtime error the console tool isn't surfacing. Let me add temporary global error capture at the top of the module, reload, and read it: + +`__PCERR` is null and no PROCITY — meaning the module is **suspended**, not thrown. The only top-level `await` is the citygen import. Let me check whether that import hangs (rather than 404-rejecting) in this preview environment: + +The import rejects cleanly, so the `catch` runs — but a later **synchronous** throw in a top-level-await module surfaces as a "module evaluation error" that `window.onerror` doesn't catch (which is why `__PCERR` is null). Wrapping the body in an async IIFE with try/catch will both fix the structure and surface the real error. Let me refactor: + +Let me verify the browser is actually getting the wrapped version (cache/service-worker suspicion) and check if the module even starts: + +Served version is correct, so `main()` is pending. Let me reproduce the exact `await import` in try/catch pattern to see if it hangs versus my earlier `.then/.catch` test: + +That exact pattern completes — so main() is pending on something else, and the console tool isn't surfacing this tab's errors. Let me instrument `main()` with stage markers to pinpoint where it stops: + +`__S` is undefined — the module body isn't executing at all. Let me wait a beat and re-check (large three.module.js fetch), and also check network for any failed import: + +Module script is in the DOM but never executed — that's a **parse error in the inline script itself**. Let me extract it and validate with node: + +The regex found no `` — I never wrote the closing tags! Let me check the file tail: + +That's the bug — the inline `