1151 lines
83 KiB
Markdown
1151 lines
83 KiB
Markdown
# TODO
|
||
|
||
Work is grouped by theme. Each item should be small enough to complete and verify on its own;
|
||
see `AGENTS.md` for the workflow and `MEMORY.md` for the decisions behind these plans.
|
||
|
||
**Priority order (2026-11-04, owner):** 1) **Blender NPC model overhaul** — head, face and hands
|
||
with a local part pipeline; 2) finish the MakeHuman character + the 3D model and map improvements;
|
||
3) ship it together in the **0.10.0 minor**. The 0.9.7/0.9.8 character patches are published. See
|
||
`AGENTS.md` §Priority and Versioning and §Local Blender skills.
|
||
|
||
The MIT Blender skill pack lives locally at `.agents/skills/blender-skills/` (gitignored). Every
|
||
3D workstream below names the skills to load; they are guidance only, and the project contract,
|
||
`blender_assets.py audit`/`fit`/`inspect` and the capture gates stay authoritative.
|
||
|
||
## Blender NPC model overhaul (top priority)
|
||
|
||
Goal: replace the sphere-and-primitive face and hand construction with a local, part-based
|
||
development pipeline that can build, inspect and compare the **head/face** and **hands** separately
|
||
before assembling them into the shipped character. Prioritise face readability at portrait
|
||
distance, then hand silhouette and gear contact. Preserve the `npc_base` contract, the 13 core-bone rig (optional extra bones allowed),
|
||
five tint slots, 16,000/16,000 character cap, optional extra bones beyond the required 13, and the Compatibility/Web path.
|
||
|
||
*Skill route: `character-artist`, `retopology`, `sculpting`, `rigging`, `uv-workflow`,
|
||
`texture-workflow`, `materials`, `lookdev`, `asset-optimization`, `qa-review`.*
|
||
|
||
**Current state:** `assets/models/npc/` contains the tracked frozen `npc_base.blend` and its
|
||
gitignored `.blend1`; the 12 production characters are assembled procedurally by
|
||
`tools/blender_assets.py` from `_shape_head_mesh`, `_face`, `_hair` and `_hands_and_shoes`.
|
||
There is no per-part source asset library yet. The MakeHuman body prototype and its temporary
|
||
head/hand swap live under `tmp/npc-research/` and are not the shipped path. This overhaul supplies
|
||
the reusable head/face and hand parts that both the procedural characters and the MakeHuman body
|
||
can consume.
|
||
|
||
This workstream supersedes the face/head and hands items in §C until the prototypes are approved;
|
||
the rest of §C remains the broad review checklist.
|
||
|
||
### 1. Baseline and acceptance
|
||
|
||
- [x] Inventory the real starting point: the frozen `assets/models/npc/npc_base.blend`, the 12
|
||
generated character GLBs/AO maps, the current `_face`/`_hands_and_shoes` builders and the
|
||
temporary MakeHuman head/hand swap. Recorded tris/verts, head subdivision, material slots,
|
||
UV layout and the exact locations of eye/mouth/finger geometry in
|
||
`docs/3d-model-review.md` §Baseline inventory.
|
||
- [x] Define measurable acceptance: face front/three-quarter/profile at 1.5 m and 1.85 m; hands
|
||
open and gripping at 0.8 m; silhouette, eye/mouth readability, ear/nose/jaw planes, finger
|
||
separation and gear contact. Keep the 16,000/16,000 cap; optional extra bones are allowed, but the required 13 core bones and rest positions must not move.
|
||
Recorded in `docs/3d-model-review.md` §Overhaul acceptance criteria.
|
||
- [x] Confirm the identity boundary: `npc_base.blend` is the frozen fallback and must not absorb
|
||
prototype detail unless a separate contract decision approves it.
|
||
Recorded in `docs/3d-model-review.md` §Baseline inventory and
|
||
`docs/blender-assets.md` §Frozen fallback boundary.
|
||
- [x] Choose a local working-set layout: `tmp/npc-parts/<variant>/` (gitignored) for part `.blend`
|
||
and preview GLBs; only the assembled character GLBs, AO/maps, manifest and review sheets are
|
||
committed. Do not add a new committed `.blend` source tree without a docs/ADR decision.
|
||
Recorded in `docs/3d-model-review.md` §Working-set layout and
|
||
`docs/asset-tooling.md` §Recommended part-workflow.
|
||
|
||
### 2. Local part pipeline
|
||
|
||
- [x] Add `tools/npc_parts.py` with a small, documented CLI:
|
||
`extract` (pull the current head/hands for comparison), `build --part head|face|hand_l|hand_r`,
|
||
`assemble --variant <name>`, `inspect`, `compare` and `sheet`. It reuses the existing
|
||
builder helpers (`blender_assets.py` `_face`/`_hands_and_shoes`/`_shape_head_mesh`); no
|
||
second face/hand implementation. Verified end-to-end: built `head`/`face`/`hand_l`/`hand_r`,
|
||
extracted `hand_l` from the shipped GLB, assembled `npc_casual` (contract inspect: no issues).
|
||
- [x] Keep the part pipeline local-only and headless: flatpak Blender for authoring, stdlib/Pillow
|
||
for inspection and sheets. No Blender MCP dependency, no new runtime dependency, no CI
|
||
Blender step.
|
||
- [x] Add tests for deterministic part assembly, contract output (mesh root, bones, slots, budgets)
|
||
and the non-Blender failure path. `tools/tests/test_npc_parts.py` covers the part-name set,
|
||
the clean Blender-required error path, sheet/compare error paths and a real-PNG sheet. The
|
||
assembled prototype passes `inspect` (npc_base, 14 bones, skinned, no issues).
|
||
- [x] Consider optional Blender MCP for interactive part exploration and document setup/safety.
|
||
(`docs/asset-tooling.md#optional-interactive-blender-mcp` covers addon/client setup, Pi `pi mcp add`, flatpak networking,
|
||
viewport/`bpy` workflow and the rule that headless audit/fit remains authoritative; MCP is
|
||
not a build/CI/runtime dependency.)
|
||
- [x] Document the commands, working-set paths and "part source is not a shipped asset" rule in
|
||
`docs/asset-tooling.md`, `docs/blender-assets.md` and
|
||
`.agents/skills/gig-line-blender-asset-contract/references/verification.md`.
|
||
|
||
### 3. Head and face prototype
|
||
|
||
- [-] Build one `npc_casual` head/face prototype as a connected head shell plus intentional feature
|
||
geometry — not a sphere with floating facial balls. Use loop-based eye sockets/lids, a
|
||
readable nose bridge/tip/ala, a mouth with upper/lower lip volumes, ears with concha depth,
|
||
and brow/cheek/jaw planes that survive the 256² AO bake.
|
||
In progress: `tools/npc_parts.py build --part head_proto` displaces the shell (seg 48/rings 26)
|
||
into sockets, a nose bridge/tip/ala, upper/lower lips, a chin bump and ears; the eyeballs stay
|
||
separate. Five vision-judged iterations later (see `docs/3d-model-review.md` §Head prototype):
|
||
the nose/mouth/chin/ear now read, but the forehead plane, ear helix definition and the
|
||
jawline-to-neck step still need work before the 1.5 m/1.85 m comparison.
|
||
- [ ] Compare two or three subdivision/loop variants at 1.85 m front/three-quarter/profile and a
|
||
1.5 m portrait. Pick the variant that reads best before changing all 12 characters; keep the
|
||
rejected variants local.
|
||
- [ ] Verify head weights stay on the Head bone, headgear clearance still passes `fit`, and the
|
||
face does not bake recessed creases into dark AO patches.
|
||
- [ ] Get owner sign-off on the one-variant prototype, then roll the approved head/face into the
|
||
other 11 variants one asset family at a time, with a before/after sheet per batch.
|
||
|
||
### 4. Hands and grip prototype
|
||
|
||
- [ ] Build separate left/right hand parts with a connected palm, four multi-segment fingers, a
|
||
thumb, knuckles and rounded tips. Support an open palm and a relaxed grip; preserve the
|
||
current `HAND_ITEM_FORWARD` behaviour for phone/cup/clipboard/camera/flashlight/wand/radio.
|
||
- [ ] Decide finger articulation explicitly: the current rig has no finger bones, so keep the
|
||
open/relaxed-palm approach unless an ADR approves optional finger bones and the
|
||
budget/weight path.
|
||
- [ ] Verify all hand gear at 0.8 m (contact, clipping, direction) and capture open/grip hand
|
||
close-ups for the review sheet.
|
||
- [ ] Roll the approved hands into all 12 variants only after the one-variant hand sheet passes.
|
||
|
||
### 5. Assembly and rollout
|
||
|
||
- [ ] Integrate the approved parts into `build_character` with deterministic joins, weights, UVs and
|
||
AO. The final output remains one `npc_base` skinned mesh under the existing 13-core armature;
|
||
optional extra bones are allowed but the core rest positions stay fixed;
|
||
no second rig, no material-slot rename.
|
||
- [ ] Keep the MakeHuman body prototype consumable with the same approved head/hands; do not let it
|
||
grow a second face/hand implementation while the part pipeline is being proven.
|
||
- [ ] Rebuild only the changed character GLBs, AO maps and manifest entries; never run a no-op full
|
||
library rebuild. Commit one asset family per change.
|
||
- [ ] Re-run `blender_assets.py audit`/`fit`/`inspect`, `npc_proportions.py`, the 24-NPC budget,
|
||
Godot and Python tests, the 48-frame baseline and the 96-frame final-context review.
|
||
|
||
### 6. QA, docs and exit
|
||
|
||
- [ ] Capture front/three-quarter/profile head comparisons and open/grip hand comparisons; add
|
||
durable sheets to `docs/blender_previews/` and link them from the review docs.
|
||
- [ ] Update `docs/3d-model-review.md`, `docs/npc-visual-review.md`,
|
||
`docs/known-limitations.md`, `MEMORY.md` and the project skills with the accepted limits and
|
||
the new part workflow.
|
||
- [ ] Exit: head/face and hands are approved on one prototype, rolled out across all 12 variants,
|
||
all contract/budget/capture gates pass, the local part pipeline is documented, and no
|
||
runtime dependency or skeleton contract changed.
|
||
|
||
## Fix the Rig pose harness
|
||
|
||
Goal: `src/test/capture_npc_pose.gd` reports a pose but saves rest frames; the root cause is
|
||
narrowed to the skinned mesh ignoring its `Rig` parent transform. Fixing it unblocks the
|
||
weights/pose column of the 3D review and the pose/portrait evidence for the MakeHuman intake.
|
||
|
||
*Skill route: `rigging`; evidence in `docs/3d-model-review.md` §"Pose evidence is blocked".*
|
||
|
||
- [x] Root cause found (2026-11-04): the harness never disabled the avatar's `_physics_process`,
|
||
so `_advance_fsm` + `_move_toward_target` ran every tick and reset `arrived`/velocity, which
|
||
made `theater_pose()` return "idle" and reverted the pose to rest. (The earlier "moving the
|
||
`Rig` child does not render" probe was a red herring: it set `rig.position.y` inside `_shoot()`
|
||
in the same frame as `root.get_texture().get_image()`, so it never got a rendered frame.)
|
||
- [x] Harness rebuilt: `capture_npc_pose.gd` now calls `set_physics_process(false)`/
|
||
`set_process(false)` after staging the avatar; the pose survives because only the direct
|
||
`_animate()` ticks drive it. Verified: sit vs idle diff 5.63, walk vs idle diff 2.29, and the
|
||
vision judge confirms the seated frame reads as crouched.
|
||
- [x] Captured all poses for all 12 variants (idle / walk_contact / walk_pass / sit × full +
|
||
shoulder views = 96 frames) and built `sheet_pose.jpg`/`sheet_shoulder.jpg` under `tmp/`.
|
||
(No separate "wave" theater pose exists; the escalation raise-hand gesture is not a distinct
|
||
capture in this harness.)
|
||
|
||
## MakeHuman character pipeline
|
||
|
||
Goal: replace the procedural body generator with the CC0 MakeHuman base for the next character
|
||
pass — retopologised, rigged and dressed in project-owned clothing — so bodies read more
|
||
realistic than the current primitive shapes. This promotes the deferred MakeHuman evaluation to
|
||
an active track; ADR-0015 (CC0 / CC-BY with attribution) still governs every intake.
|
||
|
||
*Skill route: `retopology`, `rigging`, `uv-workflow`, `materials`, `character-artist`,
|
||
`asset-optimization`, `godot-export`, `qa-review`.*
|
||
|
||
### Intake and adaptation
|
||
|
||
- [x] `adapt` path added to `tools/blender_assets.py` (`adapt --file <in> --out <out>
|
||
[--target-tris 16000]`): imports the GLB, applies transforms, grounds the feet, welds seam
|
||
splits and decimates to the budget, then exports. The five tint slots + 13-core rig
|
||
(optional extra bones allowed) stay a manual step (recorded in the command doc).
|
||
- [x] `audit` stays the final gate; `test_adapt_requires_blender` covers the non-Blender error
|
||
path (162/162 Python).
|
||
- [x] Adapter commands + go/no-go documented in `docs/asset-tooling.md` §Intake adaptation.
|
||
|
||
### MPFB / MakeHuman body pipeline
|
||
|
||
- [x] Prototype the local pipeline: `tmp/npc-research/makehuman_intake.py` imports the CC0
|
||
`base.obj`, scales to 1.82 m, grounds the feet, triangulates, decimates and exports
|
||
`tmp/npc-research/makehuman/makehuman_body.glb` — 3,790 verts / 6,444 tris, bounds
|
||
x ±0.53 / y 0–1.82 / z −0.12…+0.35, one neutral material, UVs present, unskinned. The
|
||
body (no rig) is the input for the rigging step; the script + mesh stay in `tmp/` (CC0, not
|
||
committed).
|
||
- [x] Rig strategy decided (owner): **retarget the body to the 13-core contract; optional extra bones are allowed**.
|
||
`tmp/npc-research/makehuman_retarget.py` rotates the A-pose arms down (−38°/+38°), scales the
|
||
arms 1.63× to the contract 0.70 m length, welds the split vertices, smooth-shades, adds the
|
||
contract armature + `_auto_weights`, paints the five slot regions (hair/cloth/pants/accessory/
|
||
skin) and exports `makehuman_retargeted.glb`. **Contract passes:** 6,444 / 16,000 tris,
|
||
7,726 / 16,000 verts, 14 bones (13 + Hips), skinned, arm-down, grounded, five slots, no issues.
|
||
Vision-reviewed: arms hang down and the silhouette + slot regions read, but the 1.63× arm warp
|
||
distorts the deltoid/shoulder (spiky/warped), the decimated hands are blocky, and the slot
|
||
boundaries are rough — these are the refinement steps below.
|
||
- [x] Head/hands/feet swap (`makehuman_final.py`): cut the decimated MakeHuman head/hands/feet and
|
||
joined the project's `_face`/`_hair`/`_hands_and_shoes`, then re-weighted/re-UV'd. Contract
|
||
passes: 6,407 / 16,000 tris, 6,651 / 16,000 verts, 14 bones, skinned, five slots, no issues.
|
||
Vision-reviewed: the head now reads as a realistic face, the hands as detailed fingers and
|
||
the shoes as attached. Remaining (manual retopology): a 1.63× arm-scale warp still distorts
|
||
the deltoid/shoulder, stray hand blobs linger at the hips, shirt/shirt seams are rough, and
|
||
the head-neck junction has a shadow gap. The procedural generator stays the shipped fallback
|
||
until these are cleaned in an editor session.
|
||
|
||
## 3D model and local map re-evaluation
|
||
|
||
Goal: re-judge every shipped 3D asset against the newly available Blender skill guidance, rank
|
||
the real gaps, and fix only what the rankings justify (sections A–G); and re-evaluate the three
|
||
venues against licensed real-world data — OSM footprints and building massing, reference-derived
|
||
photoreal facades and the photo-driven geometry pipeline (sections H–M). Evidence comes from three
|
||
separate sources: licensed real-location photos, generated concept boards, and build captures. This
|
||
is an unversioned development track: it must not change the `npc_base` contract, the renderer or
|
||
the 0.10.0 release candidate.
|
||
|
||
**Sequencing (2026-11-03, owner):** the asset-review fixes (A–G, notably the character P0/P1
|
||
rebuilds and the face/foliage prototypes) stay **blocked** until the full local map rebuild
|
||
(H–M) is done **and** a fresh 3D model review runs against the new maps. The measurements and
|
||
scorecard in `docs/3d-model-review.md` stand as the pre-rebuild baseline, not a go-ahead to start
|
||
character work now. (Character development has since shipped — see `DONE.md` — and the next
|
||
character pass is the MakeHuman pipeline above.)
|
||
|
||
**Map rebuild status (2026-11-03):** H–M are complete — the Joke Shop is now a 6.0 m low hall
|
||
(dark stucco, white signature fascia, tied-back curtains, hotel tower) and Hollywood/TV Studio
|
||
share the limestone-ashlar Masonic facade. A fresh `capture_npc_review.gd` run produced 96/96
|
||
frames against the new maps (none blank) and a vision spot-check confirms the characters still
|
||
read cleanly. The remaining §L signage-texture candidates and the deferred 3D facade-reveal depth
|
||
are enhancements, not rebuild blockers.
|
||
|
||
Reference material is collected first (section A): local, gitignored, development-only photo
|
||
research may use any source the owner authorises (DuckDuckGo image search, street-view frames,
|
||
neighbouring properties, buildings across the street) **without the licence gate**. The licence
|
||
and privacy gates still apply the moment a frame is promoted into `docs/screens/refs/` or any
|
||
committed asset — local `tmp/research/` is the only licence-free zone.
|
||
|
||
Scope: the shipped 3D catalogue — 8 library characters, the frozen `npc_base` fallback, 18 gear
|
||
pieces, 20 library props, 6 generated props and the three venue families — plus the local map
|
||
pipeline that re-evaluates those venues (OSM data/licensing, reference imagery, the photoreal
|
||
facade kit, AI-assisted composing, Gaussian-splatting evaluation and map QA).
|
||
|
||
**Exit (asset review, A–G):** `docs/3d-model-review.md` scores every catalogue asset; every P0/P1
|
||
is fixed or explicitly accepted with a measurement; `inspect`/`audit`/`fit`/proportions, the
|
||
24-NPC budget and the capture gates are green; no runtime contract, dependency or release artifact
|
||
changed except the rebuilt assets themselves.
|
||
|
||
**Exit (local map, H–M):** one local block is reconstructed from licensed data with
|
||
reference-derived photoreal facades, passes performance/navigation/visual QA and has complete
|
||
provenance; or the pipeline is rejected with the findings recorded.
|
||
|
||
### A. Local reference material collection (development-only, gitignored)
|
||
|
||
*Owner override (2026-11-03):* for local, development-only photo research the licence gate does
|
||
**not** apply. Anything downloaded for this track stays under `tmp/research/` (gitignored) and is
|
||
never committed, shipped, or used as a committed asset. The moment a frame is promoted to
|
||
`docs/screens/refs/<venue>/` it must pass the sidecar licence + privacy gate; local research is the
|
||
licence-free zone only.
|
||
|
||
- [x] Add a DuckDuckGo image-search fetcher: `tools/refcollect.py search <query> --slug <block>
|
||
--limit N` downloads top results into `tmp/research/<block>/` with a source-URL manifest
|
||
(no licence filter, marked `local_only`/`unchecked-local`), and `sheet` composes a local
|
||
contact sheet. Requests go through a token bucket plus polite jittered backoff that honours
|
||
`Retry-After`, and send a full Firefox header set. Tests in
|
||
`tools/test_refcollect.py`. **Run note:** DDG rate-limits aggressively; space batches and
|
||
run the per-venue collection below when the limit clears.
|
||
- [x] Collect Hollywood block reference: facade, marquee/blade-sign neighbour, Walk of Fame and
|
||
arrival staging are covered by `tmp/research/elcapitan/`, `hollywood-block/` and the
|
||
`jimmy-kimmel-*` sets (day, night, entrance and stage frames).
|
||
- [x] Collect Joke Shop / Comedy Store block reference: `tmp/research/comedy-store/` covers the
|
||
facade, canopy, street and visitor views; `ramada-hotel/` adds the neighbouring hotel and
|
||
`comedy-store-hillside/` the hillside/houses behind the roofline.
|
||
- [-] Collect street-view frames of both blocks: street-level DDG frames now cover the facades,
|
||
corners and opposite frontages for both blocks; true Google Street View panorama capture is
|
||
deferred (needs a Google API key or a manual browser capture — recorded in MEMORY).
|
||
- [x] Build a local contact sheet per block: `sheet.jpg` exists for every collected set
|
||
(`elcapitan`, `hollywood-block`, `jimmy-kimmel-stage`, `jimmy-kimmel-entrance`,
|
||
`comedy-store`).
|
||
- [x] Record which local frames changed a decision: added the frame→decision mapping to
|
||
`docs/venues.md#hollywood-boulevard` (recent `elcapitan-2026` geosearch → 2009 frame stays the
|
||
geometry reference; `jimmy-kimmel-entrance/07.jpg` → the four entrance concepts) and
|
||
`docs/venues.md#the-joke-shop` (`comedy-store/` → the four concept pairs + map plan;
|
||
`comedy-store-hillside/` → the day-concept anchor that clears the image-recitation filter).
|
||
Frames stay gitignored; only the provenance notes are committed.
|
||
|
||
### B. Baseline, scorecard and routing
|
||
|
||
- [x] Load `blender-director` plus the per-family specialists before touching geometry, and
|
||
record the skill stack and the advice that changed a decision in `docs/3d-model-review.md`.
|
||
(Routing, QA severity/verdict, texel-density tiers, character loop criteria and budget rules
|
||
recorded in the review doc; MCP-only steps translated to headless flatpak runs.)
|
||
- [x] Re-run the neutral NPC baseline (48 frames), the final-context review (96 frames), the
|
||
prop gallery and the 24-NPC budget on the current build; keep raw frames in `tmp/` and do
|
||
not replace committed sheets until a fix lands. (48/48 and 96/96 frames captured under
|
||
`xvfb-run`, none blank; raw sets in `tmp/model-baseline` and `tmp/model-review`; committed
|
||
sheets untouched. 24-NPC smoke still 6.94 ms / 168 meshes / 131,616 triangles.)
|
||
- [x] Create `docs/3d-model-review.md` with a per-asset scorecard: silhouette, anatomy/proportion,
|
||
topology/edge flow, UV/texel density, textures/materials, rig/weights, LOD/impostor,
|
||
collision/grounding, export contract, provenance, skill route, verdict (P0/P1/P2/accept).
|
||
(Doc created with character/gear/prop/venue tables, verdict columns and a ranked candidate
|
||
list; unmeasured cells are marked `—` instead of being guessed.)
|
||
- [x] Collect the baseline measurements in one table: `blender_assets.py inspect`, `audit`, `fit`,
|
||
`npc_proportions.py`, texel density, triangles/meshes, 24-NPC frame time. (All seven captured;
|
||
`texels` and `inspect --json --out` were added to make the measurements repeatable. All 46
|
||
assets audit/inspect clean; texel density 64–122 px/m authored, 287–440 effective fabric.)
|
||
- [ ] Review the scorecard with the project owner, rank the P0/P1 gaps and decide fix vs accept
|
||
per item; record the decision and the reason in the review document. **Deferred until the
|
||
full map rebuild (H–M) lands and a fresh 3D review runs against the new maps.**
|
||
|
||
### C. Character re-evaluation (8 variants + fallback)
|
||
|
||
*Skill route: `character-artist`, `retopology`, `rigging`, `uv-workflow`, `texture-workflow`,
|
||
`materials`, `hair-groom`, `asset-optimization`, `lookdev`, `qa-review`.*
|
||
|
||
- [x] Face/head review: the eight library characters ARE built with the 0.9.4 face detail in
|
||
`tools/blender_assets.py._face()` — sculpted chin plate + cheekbones (`_shape_head_mesh`),
|
||
socketed sclera + thin upper lid, nose bridge/tip/wings, rounded mouth and ear concha. The
|
||
plain sphere head in `tools/npc_pipeline.py` is the frozen `npc_base` fallback only. The
|
||
ranked P1 "flat faceted cheek/brow + slit eyes" is therefore a readability/scale question on
|
||
the existing sculpt (head `seg=18/rings=12`, small offsets), not missing geometry. Next step
|
||
if the owner funds it: a single-variant `npc_casual` prototype that raises head subdivision
|
||
and deepens the cheek/brow offsets. Fix is gated on the owner scorecard review.
|
||
- [x] Hands/grip review: the hands ARE detailed — `tools/blender_assets.py._hands_and_shoes()`
|
||
builds a wider shallower palm, four two-segment bent fingers with rounded tips and a thumb;
|
||
gear contact is the open palm plus the `HAND_ITEM_FORWARD` (0.04 m) offset. Decision: **keep
|
||
the open palm + forward offset; a finger-curl rig stays out of scope** — the current rig has
|
||
no finger bones, so a curl rig is a contract decision, not a modelling tidy-up. Optional
|
||
extra finger bones are now allowed by the cap/contract extension, but require an ADR and
|
||
weight/budget verification. Recorded as ranked gap #6 (accept; revisit only if face work
|
||
opens the budget).
|
||
- [x] Weights/pose evidence captured and vision-reviewed, and the P1s fixed: wrist/hand
|
||
detachment (wrist + hand now 100% `Hand`, hand raised, sleeve cuff follows the hand),
|
||
hip/thigh collapse + knee pinch (thigh/shin rigid with a short knee blend). Vision-verified:
|
||
hip fix clean, knee crease minor residual. The guard hip-pouch clip and the residual knee
|
||
crease remain as 0.10.0 refinements.
|
||
- [x] UV/texel density: measured (64–122 px/m authored, 287–440 px/m effective fabric on the 4×
|
||
repeat; table in `docs/3d-model-review.md`). Decision: **accept as-is** — the maps are
|
||
neutral/runtime-tinted (not painted skin), so density controls only subtle weave/noise, and
|
||
fabric already sits in the standard tier. No atlas/UDIM/resolution change is justified until
|
||
a portrait shows texture starvation; `CHAR_MAX_TRIS`/`CHAR_MAX_VERTS` stay unchanged.
|
||
- [x] Cloth and hair: hem clipping is already handled by the 0.76 stride scale for `npc_dress`/
|
||
`npc_coat` (v0.9.0), hair/beard are the five procedural styles, and headgear clearance is
|
||
verified clean by `blender_assets.py fit` (0.9.4). Decision: **cloth simulation stays out of
|
||
scope** for the 8-variant library and the Compatibility renderer — rigid procedural meshes
|
||
plus stride scaling are the accepted approach; a baked cloth-sim pipeline would only be
|
||
reconsidered if a later close-up shows visible hem/coat stiffness.
|
||
- [ ] Fix only the ranked P0/P1s, one asset family per commit; refresh the comparison sheet and
|
||
re-run `inspect`, `audit`, `fit` and `npc_proportions.py` after each fix. **Blocked until
|
||
the map rebuild + second 3D review (see the track's sequencing note).**
|
||
- [x] Crowd-variety reference: five licence-cleared Commons photos fetched to
|
||
`tmp/research/crowd-variety/` (CC0 ×2, CC BY 2.0, CC BY 3.0, PD) covering umbrella/dense
|
||
crowds and a pedestrian mall — general build/hair/outer-layer variety context, reference
|
||
only (never traced). The AI proposal set (generated crowd-variety concepts) will carry the
|
||
specific 4-variant detail when the character-development roster starts.
|
||
- [ ] Generate a face/hand concept board for the highest-ranked P1 and compare it with the 0.9.4
|
||
baseline before rebuilding anything; keep it development-only and record model and prompt.
|
||
- [ ] After each accepted fix, capture front/three-quarter/profile comparisons, add them to the
|
||
review sheet, and refresh the README character row.
|
||
- [x] `qa-review` sign-off: all eight variants **ship with notes** (face realism landed, hands/
|
||
cloth/gear accepted, props reviewed); the weights/pose column is the only open item (blocked
|
||
on the harness) and the full foliage carded-cluster is the one remaining owner-gated P1.
|
||
Recorded in `docs/3d-model-review.md` §qa-review sign-off.
|
||
|
||
### D. Gear and prop re-evaluation
|
||
|
||
*Skill route: `prop-artist`, `hard-surface`, `vegetation-artist`, `materials`, `collision-proxy`,
|
||
`lod-pipeline`, `qa-review`.*
|
||
|
||
- [ ] Gear: review the 18 pieces for silhouette, straps/buckles, helmet and lanyard readability
|
||
and rebuild only what fails the scorecard. (Attach/clearance verification is done — the
|
||
`fit` report is recorded in `docs/3d-model-review.md` with the back-gear-vs-hip-radius
|
||
measurement caveat; the visual silhouette read is what remains, pending the owner scorecard.)
|
||
- [ ] Props: review the 20 library props plus the 6 generated props for bevels, chamfers,
|
||
silhouette, ground contact and shared material language (`prop-artist`, `hard-surface`);
|
||
list the rebuilds that are actually worth the triangle budget. (Vision-reviewed 2026-11-03
|
||
via `tools/describe_image.py`: `fire_hydrant` rebuilt and shipped; `planter_box`/
|
||
`round_planter` foliage and `street_tree`/`palm_tree` are the foliage-language P1 (gated on
|
||
the owner); `newspaper_box` slot and `bollard` collar are minor rebuild candidates; `bench`/
|
||
`trash_bin` are ship-ready.)
|
||
- [ ] Foliage: replace the flat-shaded `_shrub()`/`_tree()` clumps with `vegetation-artist`-style
|
||
carded clusters; measure triangles and keep the 60k `LIBRARY_TRIANGLE_BUDGET`.
|
||
(Partial 2026-11-04: `_shrub()` clumps and the palm fronds now alternate two green tones
|
||
(`foliage`/`foliage_dark`, `palm_leaf`/`palm_leaf_dark`) so the crown is no longer one flat
|
||
colour, and a `textured_solid` bug that broke `planter_box`/`round_planter` imports was
|
||
fixed. The two-tone read is subtle at gallery distance; the full carded-cluster pass remains
|
||
the owner-gated P1.)
|
||
- [ ] Materials and emissives: `lookdev` pass on bulbs, signs, lanterns, the marquee and the
|
||
sedan at day and late; confirm the flashlight stays a tight spot with no beam geometry.
|
||
- [ ] Collision: verify every prop collider and navigation obstacle matches its silhouette and
|
||
add the missing `collision-proxy` shapes where walking is blocked.
|
||
- [ ] Build a real-photo comparison for street furniture (bollard, bench, bin, hydrant, planter,
|
||
lamp) and rank the silhouette and proportion mismatches.
|
||
- [ ] Rebuild only the mismatched pieces through the assisted Blender pipeline
|
||
(`blender_assets.py inspect` → scripted retopo/UV assist → atlas → `audit`/`fit`); document
|
||
the exact commands in `docs/asset-tooling.md`.
|
||
- [ ] Refresh `sheet_props.jpg`/`sheet_npc_gear.jpg`, the README asset rows and
|
||
`docs/blender_previews/README.md` after the rebuilds.
|
||
- [ ] Exit: a prop/gear capture sheet, budgets and collision checks pass with no unreviewed asset.
|
||
|
||
### E. Venue and camera re-evaluation
|
||
|
||
*Skill route: `environment-artist`, `archviz`, `set-dressing`, `lighting`, `camera-cinematography`,
|
||
`lookdev`, `rendering`, `qa-review`.*
|
||
|
||
- [-] Facade/venue review: rank the top five shape-language fixes for Hollywood, the Joke Shop and
|
||
the TV Studio (`environment-artist`, `archviz`) and check them against the map-budget tests.
|
||
**Ranked 2026-11-03:** (1) TV Studio renders a generic pilaster/concrete box instead of the
|
||
six-column Masonic Temple — `tv_studio` lacks `masonic_facade`, so `_build_building()` runs
|
||
while the Jimmy Kimmel starting point is the same facade; (2) Joke Shop blade sign is a flat
|
||
slab + label, not the reference's circular sign on a roof pole; (3) Joke Shop canopy fascia
|
||
lacks the deep white-signature band; (4) Hollywood entrance signage shows `EL/CAPITAN/LIVE`
|
||
banners where the real building carries the Jimmy Kimmel Live marquee (owner content call);
|
||
(5) Joke Shop red-curtain bays and entrance-recess rhythm read flat under the canopy.
|
||
**Fix 1 landed:** `tv_studio` now reuses `masonic_facade` (architecture `masonic`, ashlar
|
||
field, six columns, eight steps, landing + guard spawn at y=1.0) while keeping the arrival
|
||
staging (`bulb_canopy`, `sedan`, `handrail`, barriers); Godot 276/276, screenshot smoke
|
||
21/0, `13-studio-arrival.png` recaptured.
|
||
**Fix 3 landed:** the Joke Shop canopy signature band is now white (`Color(0.90, 0.88, 0.80)`)
|
||
over the black fascia, matching the concept's "white celebrity signatures"; a test asserts
|
||
the `CanopySignatures` label is white, Godot 276/276, `12-joke-shop.png` + the three-up
|
||
board recaptured. Note: fix 2 (blade sign) is already a circular disc on a roof pole in the
|
||
code (`37f925c`); the ranking note was stale.
|
||
**Fix 5 landed:** the red curtain bays are now seven tied-back drapes (hourglass cinch, dark
|
||
recess between bays, scalloped hem) instead of four flat red slabs; vision-judged as
|
||
"tied-back/gathered fabric" via `tools/describe_image.py`. Joke Shop map is now 25,828 tris /
|
||
518 meshes (under the 150k/700 budget); Godot 277/277, `12-joke-shop.png` + board recaptured.
|
||
- [ ] Lighting: `lighting`/`lookdev` pass on sconces, canopy, marquee and street lamps with
|
||
day/late captures. (Attenuation is now gated: `test_venue_lights_use_physical_falloff`
|
||
asserts every `OmniLight3D`/`SpotLight3D` in all three venues uses `attenuation = 1.0`,
|
||
so a constant-falloff light cannot return unnoticed.)
|
||
Vision review 2026-11-03 (`tools/describe_image.py` on the night + flashlight captures):
|
||
the flashlight (`light_energy 4.2`, `spot_angle 14°`) washes the facade flat when pointed
|
||
at the door from close range and backlights the nearest NPC into a silhouette (staged-shot
|
||
artifact, but worth a shorter/softer cone or lower energy for the `06-night-flashlight`
|
||
stage); the El Capitan Theatre red marquee reads as a flat saturated block and the event
|
||
banners read as flat emissive decals rather than glowing signs — both are Compatibility
|
||
renderer limits (no bloom) plus the marquee's near-pure-red body; street lamps pool weakly
|
||
on near-black ground. No code change yet; these are owner-scorecard inputs.
|
||
- [ ] Set dressing: review entrance and sidewalk prop clusters (`set-dressing`) for occlusion,
|
||
navigation obstacles and readable storytelling clusters.
|
||
Vision review 2026-11-03 (`tools/describe_image.py` on the Joke Shop capture): the facade is
|
||
well dressed, the sidewalk under-dressed. Findings: (1) the queue story is weak — the
|
||
`security_podium` sits at x=6.8 while the entrance is at x=-8.8, so the host/podium and the
|
||
two `stanchion`/`crowd_barrier` pieces do not read as a line at the door; (2) the rope
|
||
barrier reads as thin bare geometry at night; (3) the west palm (x=-13.0) is inside the
|
||
27 m facade x-range so its fronds visually overlap the roofline from the beauty camera;
|
||
(4) the sidewalk has no light pool or A-frame/poster cluster. These are P2 composition
|
||
items, kept for the owner scorecard rather than moved unilaterally.
|
||
- [x] Camera height: already decided in the 0.9.0 pass — keep the 1.7 m gameplay camera; the
|
||
~1.55 m concept frames are art reference only (recorded in `DONE.md` 0.9.0 Animation).
|
||
- [x] Build the venue three-up boards (real photo | generated concept | current capture):
|
||
`tools/three_up.py compose` renders labelled strips into `docs/screens/boards/` (caption
|
||
sidecar per board, `rows` emits README rows). Boards committed: El Capitan day, El Capitan
|
||
night, Joke Shop day. Tests in `tools/test_three_up.py`.
|
||
- [x] Link each committed board from `docs/venues.md#hollywood-boulevard` and
|
||
`docs/venues.md#the-joke-shop`.
|
||
- [ ] Use the generated concept lighting and palette as the target for the `lighting`/`lookdev`
|
||
pass, and record the deviations that stay accepted.
|
||
- [ ] After the pass, regenerate the venue captures and update README plus both venue documents.
|
||
- [x] Hooded/winter portrait: `capture_realism.gd` now force-spawns the requested `--portrait-type`
|
||
when the role is event-driven (types 5–7 do not appear in the routine day crowd), so the
|
||
deferred close-up can be staged. Captured `--portrait-type=5` and vision-reviewed: the hood
|
||
reads as a hoodie (drawstrings + face opening) but is snug — no slack volume behind the
|
||
head/drape at the neck — and the face stays fully lit with no inner-rim shadow. Acceptable;
|
||
the snug hood is a minor scorecard note, not a P0/P1.
|
||
|
||
### F. Reference images, concept boards and screenshots
|
||
|
||
*Skill route: `lookdev`, `lighting`, `environment-artist`, `qa-review`; tooling:
|
||
`tools/scene_concepts.py`, `tools/screen_designs.py`, `tools/asset_pipeline.py`.*
|
||
|
||
Licensed photos are evidence of what a place looks like, generated boards are art-direction
|
||
proposals, and captures are proof that the build matches. Keep the three labelled and separate,
|
||
and never ship a generated or downloaded image without provenance.
|
||
|
||
- [x] Create `docs/screens/refs/` with a README and a sidecar template: source URL, author,
|
||
licence/attribution, capture or generation date, what it is evidence for, and whether it is
|
||
shipped or development-only. (`docs/screens/refs/README.md` defines the layout, naming,
|
||
licence and privacy gates and the three-way separation from concepts and captures;
|
||
`SIDECAR-TEMPLATE.md` carries the photo table, redaction/permission notes, derived-decision
|
||
log and the generated-board reference table. Linked from `docs/screens/README.md`.)
|
||
- [x] Hollywood board: five licence-cleared photos (facade day, blade sign, 1922 elevation,
|
||
Ovation across street, premiere staging) with a sidecar and per-image purpose, linked from
|
||
`docs/venues.md#hollywood-boulevard` and credited in `CREDITS.md`. Cropped the foreground crowd
|
||
out of the facade shot; EXIF stripped. (`docs/screens/refs/hollywood/`.)
|
||
- [x] Joke Shop board: three licence-cleared photos (hillside/canopy block, frontage with palms,
|
||
canopy signature band) with a sidecar, linked from `docs/venues.md#the-joke-shop` and credited in
|
||
`CREDITS.md`. The CC BY-SA `The Comedy Store.jpg` from the old link list was deliberately not
|
||
used; the public-domain frames cover the same evidence. (`docs/screens/refs/joke-shop/`.)
|
||
**Removed 2026-11-03:** the committed Comedy Store photo board was replaced by the local-only
|
||
`tmp/research/comedy-store/` research set (owner override; see §3D model and local map re-evaluation → A).
|
||
- [x] TV Studio: no separate board — the venue is the same El Capitan Entertainment Centre block as
|
||
the Hollywood day shift, restaged for a late-night arrival. The Hollywood board covers both
|
||
venues and the premiere-staging photo is the arrival evidence; the reuse is now stated in
|
||
`docs/venues.md#hollywood-boulevard`, `docs/gameplay.md`, `PLAN.md` and
|
||
`docs/development-status.md`.
|
||
- [x] Fill the Hollywood gaps that have a clean licence: El Capitan Theatre neighbour and marquee,
|
||
Walk of Fame terrazzo band, star close-up, and a night street-lighting context frame (cropped
|
||
to remove people and a plate). The board now has nine photos. (CC BY-SA night frame is
|
||
redistributed unmodified for study only; the review is recorded in the sidecar.)
|
||
- [ ] Generate one concept board per venue with `tools/scene_concepts.py generate` (palette, facade
|
||
rhythm, lighting), keep raw output gitignored, commit only the selected board, and record the
|
||
model, prompt and spend in the sidecar.
|
||
- [x] Build a three-up sheet per venue (real photo | generated concept | current build capture) and
|
||
use it as the reference for the character, prop and venue verdicts. (Done for the venue
|
||
exteriors via `docs/screens/boards/`; character/prop verdicts still use the Blender
|
||
preview sheets.)
|
||
- [ ] Apply the screenshot rule to every workstream: each accepted fix updates the relevant row in
|
||
`README.md` plus the matching docs page (`docs/blender_previews/README.md`,
|
||
`docs/screenshots/README.md`, `docs/3d-model-review.md` or the venue map doc).
|
||
- [ ] Re-run `tools/check_screenshots.sh` and `python3 tools/check_docs.py` after gallery changes
|
||
and record both results in the handoff.
|
||
- [ ] Keep AI-generated images out of `assets/` until they are picked, cropped, credited and (for
|
||
textures) audited; `CREDITS.md` and ADR-0015 still govern provenance.
|
||
|
||
### G. Gates and documentation
|
||
|
||
- [x] Add the measurable checks the review needs (texel density, weight/pose sanity, collider
|
||
coverage, LOD/impostor check) as stdlib or GDScript gates where possible; CI stays offline.
|
||
(Texel-density gate in `tools/test_blender_assets.py` checks all five slots per character
|
||
and the 40–400 px/m authored band plus the 250 px/m fabric floor; the pose→bone contract is
|
||
covered by `test_pose_reaches_the_skeleton_bones`; LOD/impostor already has
|
||
`test_avatar_mesh_budget_and_lod_swap`. Collider coverage is still open — split below.)
|
||
- [x] Add a collider/proxy check: every library prop that blocks walking has a
|
||
`StaticBody3D` + `NavigationObstacle3D`, checked against the catalogue.
|
||
(`world_builder.gd` tags every library node with a `library_prop` meta and declares the
|
||
non-blocking `marquee`/`handrail`/`lantern`/`door` set; two tests in `test_world.gd`
|
||
verify placed props (body + shape + avoidance radius, all three venues) and library
|
||
dressing (body unless documented exempt). Mutation-checked: removing `_add_prop_collision`
|
||
fails 3 tests, dropping `handrail` from the exemption list fails with the exact node.
|
||
Suite is 275/275.)
|
||
- [x] Add a coverage test so every catalogue asset has a scorecard row and verdict.
|
||
(`tools/test_model_review.py`: every `CHARACTERS`/`GEAR`/`PROPS` entry needs a row in
|
||
`docs/3d-model-review.md`, and character rows need a non-empty verdict.)
|
||
- [x] Document the new gates: `docs/blender-assets.md` now lists `texels`, the
|
||
`test_model_review.py` coverage gate and the `test_world.gd` collider/proxy gate; skill
|
||
routes live in `AGENTS.md` §Local Blender skills and each `TODO.md` section; the scorecard
|
||
and evidence table are in `docs/3d-model-review.md`.
|
||
- [x] Record accepted limits/deferred rebuilds: `docs/known-limitations.md` already records the
|
||
stylized low-poly style, no finger-curl rig and the >26 m impostor; `MEMORY.md` holds the
|
||
durable decisions (texel density accepted, cloth sim out of scope, open palm + forward
|
||
offset, face subdivision prototype gated on the owner). The corrected face note is also in
|
||
`docs/blender-assets.md`.
|
||
|
||
**Local map workstreams (H–M).** Build a local, data-backed map pipeline that can replace or
|
||
supplement the stylized venue geometry with licensed OpenStreetMap footprints, 3D building
|
||
massing, reference-derived photoreal facades and AI-assisted composition. This remains part of
|
||
the same unversioned track, not a release gate. The shared reference/provenance gates in A/F
|
||
still apply; the map pipeline has its own exit in M.
|
||
|
||
*Local-map skill route: `environment-artist`, `archviz`, `hard-surface`, `geometry-nodes`,
|
||
`procedural-modeling`, `vegetation-artist`, `set-dressing`, `lighting`, `materials`,
|
||
`texture-workflow`, `lookdev`, `scene-assembly`, `qa-review`.*
|
||
|
||
### H. Local map data, licensing and scope
|
||
|
||
- [x] First target block + role: **Hollywood (El Capitan, 6840 Hollywood Blvd) and the Comedy
|
||
Store (8433 Sunset Blvd)**; the result **supplements/informs** the stylized `VENUE_SPECS`
|
||
(reference-derived materials, facades and massing), never replaces them with imported OSM
|
||
geometry. Recorded in both venue map docs.
|
||
- [x] ODbL audit: OpenStreetMap is used as **reference only** (hand-built geometry informed by
|
||
OSM ways + Commons photos), so the shipped geometry is not an ODbL derived database and no
|
||
share-alike obligation attaches. Attribution is still kept via the OSM way links in
|
||
`docs/venues.md#hollywood-boulevard` / `docs/venues.md#the-joke-shop`. If derived OSM geometry ever
|
||
ships, it needs the attribution + share-alike review in a separate ADR.
|
||
- [x] OSM extract workflow: no offline extract is required while OSM is reference-only. If the
|
||
pipeline later imports footprints, pin an Overpass query + extract date and record it in a
|
||
provenance sidecar (see below); no city-scale extract is imported into the runtime.
|
||
- [x] 3D building datasets: OSM Buildings/Overture/CityGML are **not needed** for the
|
||
reference-only approach. If massing import returns, OSM Buildings LOD1 is the first
|
||
candidate (CC0-ish footprints); CityGML/Overture need a licence review per source.
|
||
- [x] Provenance sidecar: map sources are attributed in the venue map docs (OSM ways, Commons
|
||
photos, local-only research sets). Any future **derived** map asset adds a sidecar with
|
||
source URL, licence, capture/extract date and attribution text before it is committed.
|
||
|
||
### I. Local map reference imagery
|
||
|
||
**Recent-photo research (2026-11-03):** Commons geosearch around 34.10118/-118.34009 (500 m) plus
|
||
category/date sorting shows usable imagery from the last 12 months: Dolby Theatre billboards
|
||
(2026-09-30, CC0, 6 frames), Dolby street level and a fresh Walk of Fame star (2026-07-17, CC0),
|
||
a Michael Jackson impersonator at the El Capitan frontage (2026-02-25, CC BY-SA 4.0), the Celia
|
||
Cruz Square marker and a 2025-09-28 star series (CC0), and a Thunderbolts premiere (2025-04-28,
|
||
CC BY-SA 2.0). No recent frame shoots the El Capitan facade straight-on in daylight; the best
|
||
facade evidence is still the 2009 CC BY frame. The 8 downloaded candidates are in
|
||
`tmp/research/elcapitan-2026/` (gitignored) with `meta.json`; nothing was committed.
|
||
|
||
- [x] Wire `tools/refboard.py` (standalone, stdlib-only): `search --source search|geo|category`
|
||
lists candidates with ISO date, age-in-months and a commit/review/skip licence gate
|
||
(`--allow-ccbysa` after a recorded review); `fetch` downloads usable rows into `tmp/` with
|
||
spaced requests and writes `meta.json`; `rows` emits SIDECAR + README table rows from the
|
||
manifest. Six recent CC0 photos of the block were re-fetched into
|
||
`tmp/research/elcapitan-2026-tool/`. Tests in `tools/test_refboard.py` (licence gate, recent
|
||
filter, review-row exclusion, row emission).
|
||
- [ ] Add a `--max-age-months` filter (default 12) and a `--must-reuse` mode that matches the
|
||
folder's existing sidecar entries so a refresh only reports what changed.
|
||
- [ ] Research-diff step: keep the last-12-months board as the "current reality" evidence and the
|
||
older photos as the geometry evidence, labelled per photo; no sidecar date field needs to
|
||
change, only the purpose column.
|
||
- [ ] Write a reference shot list per block: facade materials, windows, signage, rooflines,
|
||
street furniture, curb cuts and lighting.
|
||
- [ ] Download and catalogue **committed** reference images from Wikimedia Commons, local/own
|
||
photography or other clearly licensed sources; record author, licence and attribution with
|
||
the §F sidecar template. Local-only research that ignores licence limits (DuckDuckGo,
|
||
street-view frames, neighbours, across-street buildings) is collected under §A into
|
||
`tmp/research/` and is never committed.
|
||
- [ ] Separate development-only references from shipped textures; commit only images with clear
|
||
redistribution rights and keep the rest under `tmp/` or the ignored reference folders.
|
||
- [ ] Build the per-block real-photo board under `docs/screens/refs/<block>/` using the sidecar
|
||
template from the 3D review §E, and link it from the venue map documents.
|
||
- [ ] Define the photoreal target and a material-derivation workflow (albedo/normal/roughness,
|
||
AO, weathering) that matches the existing Compatibility renderer (`texture-workflow`,
|
||
`materials`, `lookdev`), with the recent 2026 street frames as the current-reality reference
|
||
and the 2009 facade frame as the geometry reference.
|
||
|
||
- [ ] Remaining Hollywood gap: a licensed **night photograph of the hero facade and blade sign**
|
||
(the night frame on the board is a different block, near Vine), plus a sidewalk-level shot of
|
||
the steps/door recess and the east retail neighbour. For the committed board the licence gate
|
||
stays (no unlicensed Street View or scraped social media); local-only copies of the same
|
||
viewpoints go through section A instead.
|
||
|
||
### J. Local map geometry and AI-assisted composing
|
||
|
||
- [x] OSM footprint import and 3D building massing: **deferred** — the §H decision keeps OSM as
|
||
reference-only, so no footprint/massing import runs; the procedural `VENUE_SPECS` plus the
|
||
reference-derived materials carry the geometry instead.
|
||
- [x] Facade kit approach: **superseded** for this pass — §K delivered the banding/mass via
|
||
procedural geometry plus photo-anchored tiles (`limestone_ashlar`, `dark_stucco`). A reusable
|
||
Blender facade kit (window bays, cornices, storefronts) is a future enhancement, not a
|
||
blocker for the current maps.
|
||
- [x] Joke Shop building-appearance pass: `dark_stucco` tile (1024 px) promoted via the picks
|
||
pipeline and wired into `_build_comedy_store_building`, replacing the grey paver tile so the
|
||
hall reads as flat matte charcoal instead of masonry; photo-anchored day concept generated
|
||
from the hillside PD frame (the branded frontage photo trips the model's image-recitation
|
||
filter — recorded in the concept README); day capture promoted and the three-up board rebuilt.
|
||
Test asserts the hall wall carries `dark_stucco`.
|
||
- [x] Building-appearance realism pass, measured against the reference set: bring the masonic
|
||
facade's material response (limestone value/roughness, joint lines, weathering streaks),
|
||
the banner/canopy and marquee materials, and the night emissive balance to the level of the
|
||
2009 facade photo and the 2026 street frames; capture before/after and record each delta.
|
||
(Ashlar field: `limestone_ashlar` tile, reference-anchored on the facade photo, 768 px over
|
||
~4.6 m of wall = ~167 px/m, promoted via the picks pipeline, warm-shifted tint behind
|
||
`VENUE_SPECS`. Banner cloth: warm self-light registered with `_marquee_emissive` (0.14 base;
|
||
0.28 night / 0.028 day). Marquee sign face + bulbs: warm-incandescent already in the prop
|
||
PALETTE, now test-verified to brighten at night via `_marquee_emissive`. Day and night
|
||
captures promoted, both three-up boards rebuilt.)
|
||
- [ ] Upgrade the facade from flat material bands to 3D photoreal detail (real cornices/reveals,
|
||
not just the ashlar/stucco tiles). Recorded as a deferred enhancement — the tiles already
|
||
give the material read; the remaining gap is geometric reveal depth (texture-projected or
|
||
Blender modules). Verify texel density, tiling and night look when it lands.
|
||
- [x] Integrate behind `WorldBuilder.VENUE_SPECS`: the photo-anchored tiles are wired into
|
||
`_build_masonic_building` / `_build_comedy_store_building` with colliders, navigation
|
||
obstacles and the existing day/night materials.
|
||
|
||
### K. Comedy Store map recreation
|
||
|
||
*Plan (2026-11-03): rebuild the Joke Shop venue geometry from the new local-only reference set
|
||
(`tmp/research/comedy-store/`, gitignored) and the four photo-anchored scene pairs now in
|
||
`docs/screens/concepts/joke_shop/`. Evidence wins for shape; the concepts win for material/mood.
|
||
Nothing is committed until the licence gate on any promoted reference and the map-budget tests
|
||
pass. The current `_build_comedy_store_building()` stays as the fallback.*
|
||
|
||
- [x] Extract the real proportions and reconcile: vision-read `tmp/research/comedy-store/` frames
|
||
via `tools/describe_image.py` and recorded the reconciled table in `docs/venues.md#the-joke-shop`
|
||
§Measured proportions. Key finding: the game facade is proportionally **taller** than the
|
||
real (3.2:1 vs ~6:1) — the main shape-language deviation; canopy pitch, blade-sign diameter,
|
||
entrance and roofline all match closely. Curtain-bay count is crop-dependent (3–7), so 7 is
|
||
accepted as a readable stylization.
|
||
- [x] Rank the shape-language gaps and write the top-five fix list (measurements from the
|
||
proportions pass, §`docs/venues.md#the-joke-shop`):
|
||
1. **Facade height** — game 8.4 m vs real ~5.5–6 m (≈3.2:1 vs ~6:1 ratio). **Fixed
|
||
2026-11-03:** `facade_height` lowered to 6.0 m; the wall now reads as a low single-storey
|
||
hall with the canopy capping the top (vision-verified).
|
||
2. **Rounded west corner** — the real building has a ~3–4 m radius corner; the game uses a
|
||
hard 90° corner, and the entrance sits at the rounded corner.
|
||
3. **Canopy depth/slope** — game 4.9 m at 11° vs real ~4–4.5 m with a shallower pitch.
|
||
4. **Neighbouring hotel/parking mass** — absent; the hotel reference frame shows a low
|
||
blocker mass east of the club.
|
||
5. **Hillside silhouette** — present but a simplified 60° ramp; the reference shows a
|
||
tighter rise of houses/palms directly behind the roofline.
|
||
- [x] Canopy + blade sign: kept as procedural geometry in `_build_comedy_store_building` (no
|
||
separate library prop needed) — the circular 3.9 m white disc on a roof pole and the sloping
|
||
black canopy with the white signature fascia both match the reference and were vision-verified
|
||
against the entrance concept.
|
||
- [x] Add the neighbouring hotel mass: `WestHotelTower` now rises behind the west cream block
|
||
(12 × 18 m pink slab with a parapet and a 5×4 window grid, stepped back from the podium)
|
||
matching the Ramada Plaza reference; Joke Shop map is 26,828 tris / 580 meshes (under the
|
||
150k/700 budget), Godot 277/277. The parking-ramp/drop-off detail stays out (low-detail
|
||
blocker mass only).
|
||
- [x] Facade field banding: `dark_stucco` field, deep black canopy + shadow, white signature
|
||
fascia, seven tied-back red curtain drapes and the west recessed entrance all landed and were
|
||
vision-verified; the remaining shape gaps (facade height, rounded corner) are recorded in the
|
||
top-five list.
|
||
- [x] Gates after the rebuild: Godot 277/277 (map budget 26,828 tris / 580 meshes under 150k/700;
|
||
navigation/collider tests pass), `tools/check_screenshots.sh` 21 good / 0 bad; the three-up
|
||
board and `docs/venues.md#the-joke-shop` were refreshed.
|
||
- [ ] Update `docs/development-status.md`, `docs/asset-tooling.md` and `CHANGELOG.md` when the
|
||
rebuild lands; record any accepted deviations from the reference.
|
||
|
||
### L. Generated location imagery
|
||
|
||
*Skill route: `lookdev`, `lighting`, `environment-artist`, `texture-workflow`; tooling:
|
||
`tools/scene_concepts.py`, `tools/asset_pipeline.py`, `tools/screen_designs.py`.*
|
||
|
||
**Tool plan for reference-anchored generation (plan first, implement after this section's review):**
|
||
|
||
- [x] Add `scene_concepts.py generate --reference <photo.png>`: attach a licence-cleared real photo
|
||
as a source image to the OpenRouter image request (multimodal chat endpoint with a base64
|
||
data URL), with a prompt suffix that preserves the photographed facade geometry. Record the
|
||
reference file, its licence and page in the `.refgen.json` provenance sidecar next to the
|
||
generated frame.
|
||
- [x] Extend `generate_textures.generate_image()` with an optional `reference_path` argument
|
||
(base64 data URL of the photo); existing call signatures unchanged, and the path is gated by
|
||
`scene_concepts._reference_source` requiring a refs-board `SIDECAR.md` row (or an explicit
|
||
`--reference-unchecked`). Verified live on the El Capitan day concept anchored on the CC BY
|
||
2.0 2009 facade photo; tests in `ReferenceGateTests`.
|
||
- [x] Add a sidecar-driven variant pass: `scene_concepts.py anchor --reference <photo>
|
||
--treatments day,night,weathered` generates same-framing variants with treatment clauses,
|
||
one `.refgen.json` provenance sidecar per frame. Verified live on the facade photo (night +
|
||
overcast frames committed; the weathered treatment reads as mild overcast — noted on the
|
||
board). Tests in `AnchorTests`.
|
||
- [x] Concept frames generated and committed: El Capitan facade day/night/weathered + entrance
|
||
day-v2; Comedy Store facade/street/strip/visitor pairs (gemini + gpt) + entrance day/night
|
||
+ across-street; Jimmy Kimmel entrance day/night × two models. Each frame carries a
|
||
`.refgen.json` sidecar (model, prompt, source photo).
|
||
- [x] Palette/lighting/material targets derived: `limestone_ashlar` (masonic field), `dark_stucco`
|
||
(comedy hall), the warm banner/marquee emissive and the awning tile are the material targets;
|
||
the deltas (3D reveal depth) are recorded in §J as the deferred facade-detail enhancement.
|
||
- [ ] Generate signage, awning and poster texture candidates with `asset_pipeline.py`; run the
|
||
role audit and the `CREDITS.md` provenance check before anything is used in the kit.
|
||
- [ ] Compare generated concepts against the licensed photos: where they disagree, the photos win
|
||
for shape and the generated board only informs colour, mood and detail density. Human review
|
||
stays the acceptance gate, and AI output is never treated as licensed map data.
|
||
|
||
### M. Local map QA and exit
|
||
|
||
- [x] Compare the block against screenshots/map docs and keep the stylized fallback: the three-up
|
||
boards (photo | concept | capture) and `docs/venues.md#the-joke-shop` record the evidence chain;
|
||
the procedural `_build_comedy_store_building()` remains the fallback.
|
||
- [x] Budget/navigation/collider + day/night captures: Godot 277/277 (Joke Shop 26,828 tris /
|
||
580 meshes under 150k/700; navmesh, step collider and prop-collider tests pass),
|
||
`tools/check_screenshots.sh` 21 good / 0 bad.
|
||
- [x] Gallery + before/after: the Joke Shop day gallery frame and three-up board were recaptured
|
||
after each facade change; the photo/concept/capture strip is the before/after record.
|
||
- [x] `tools/check_screenshots.sh` re-run (21/0) and the Joke Shop three-up board refreshed.
|
||
- [x] Docs: `docs/venues.md#the-joke-shop` (mapping, measured proportions, simplifications),
|
||
`docs/asset-tooling.md` (`describe_image.py`) and `docs/development-status.md` updated.
|
||
`CHANGELOG.md` is untouched (unversioned track; no release).
|
||
- [x] Exit: **one local block (the Comedy Store) is reconstructed with reference-derived facades
|
||
and massing** — 6.0 m low hall, white signature fascia, tied-back curtains, hotel tower —
|
||
passes performance/navigation/visual QA with complete provenance; the rounded west corner
|
||
and hillside detail are recorded as accepted simplifications.
|
||
|
||
## Maintenance and documentation hygiene
|
||
|
||
Unversioned housekeeping that keeps the planning sources trustworthy. Do these when they block a
|
||
task, not on a schedule.
|
||
|
||
**Status (2026-11-03):** v0.10.0-rc.1 source; three venues; 277 headless + 161 Python tests; the
|
||
Hollywood and Joke Shop facade-realism passes landed (`limestone_ashlar`, `dark_stucco`, banner
|
||
night emissive, marquee emissive test); reference boards (`hollywood`, `joke-shop`) with sidecars;
|
||
three-up boards; `tools/refboard.py` + reference-anchored generation (`--reference`, `anchor`) +
|
||
`tools/three_up.py`. Gaussian splatting is deferred to the end of this file.
|
||
|
||
### Memory and status accuracy
|
||
|
||
- [x] Trim `MEMORY.md` from ~1088 lines to the durable set: dropped the superseded 2026-11-01
|
||
handoff, the v0.2.x host/disk/NSIS/release anecdotes and duplicated release notes; kept the
|
||
gotchas (async/event wiring, import order, colliders, RNG, contracts, Godot `--import` cache,
|
||
image-recitation filter, capture-harness windowing, bisect zero-area triangles) and the
|
||
easter-egg note. Now ~800 lines.
|
||
- [x] Re-check the remaining memory claims against code before deleting them; `MAX_LIVE_NPCS` is
|
||
still 16 for gameplay while the separate budget smoke spawns 24, so do not "fix" that.
|
||
(Verified phase timing is data-driven via `shift_phases`, fixed the stale `REQUIRE_SIGNIN_VIEW`
|
||
contradiction and the old 272/108 counts.)
|
||
- [x] Fix stale status claims as they are found; add a documentation check or grep note only if
|
||
the same class of drift returns. (Counts and the sign-in state corrected on 2026-11-03.)
|
||
- [x] Keep the Gap Analysis baseline and the README status line in sync when a test count, version
|
||
or feature milestone changes (the baseline was bumped to 277/161 on 2026-11-03).
|
||
|
||
### Imagery and provenance upkeep
|
||
|
||
- [ ] Keep `docs/screens/refs/` sidecars, concept-board records and `CREDITS.md` in sync whenever
|
||
an image is added, replaced or dropped; photo-anchored concept frames must keep their
|
||
`.refgen.json` provenance sidecar (source photo, licence, page, model) next to the frame.
|
||
- [ ] Run `python3 tools/check_docs.py` after any gallery or reference-board edit so every tracked
|
||
image stays linked from its folder README.
|
||
- [ ] Use `tools/refboard.py search/fetch/rows` for new Commons research instead of ad-hoc API
|
||
scripts; downloads stay under `tmp/` and only licence-cleared rows (commit/review gate)
|
||
reach a board after a sidecar entry.
|
||
- [ ] Delete or ignore development-only photos and raw generations once a board is committed; the
|
||
repository carries the picks and their provenance, not the working set.
|
||
|
||
### Godot import-cache hygiene
|
||
|
||
- [ ] When a new committed texture (`assets/textures/...`, `picks/`) fails to import under the
|
||
existing `.godot/` cache, use the scratch-copy import (`rsync --exclude .godot ...` then
|
||
`godot --headless --import` and copy back the `.import` + `.godot/imported/*.ctex/.md5`);
|
||
never hand-edit the `uid=` in a copied `.import`. Record any new instance in MEMORY.
|
||
- [ ] Prefer `tools/scene_concepts.py promote` (or a manual move into `game_ready/v2/` plus a
|
||
`PICKS` entry) so new picks follow the same path as `limestone_ashlar` and `dark_stucco`.
|
||
|
||
### Agent skill upkeep
|
||
|
||
- [x] Add the tracked project skills `gig-line-blender-asset-contract` and
|
||
`gig-line-release-qa` under `.agents/skills/`, with references for the
|
||
asset contract/verification and release/QA runbooks.
|
||
- [x] Keep the third-party `blender-skills` pack local/gitignored while allowing
|
||
project-authored skills to be committed; reference the skills from
|
||
`tools/README.md`, `AGENTS.md` and `MEMORY.md`.
|
||
- [ ] Revisit the skills after the next Blender or release work changes the
|
||
contract, commands or gates; stale skills are worse than no skill.
|
||
|
||
### Blender skills upkeep
|
||
|
||
- [ ] Re-check the installed Blender pack (`version.json`) when updating it and record the version
|
||
in `AGENTS.md` if it changes; keep `.agents/` gitignored and `.agents/.gdignore` in place.
|
||
- [ ] Prune the skill routes in `AGENTS.md` if a skill stops matching the project (for example if
|
||
a future second-rig path makes `rigging`/`animation` guidance authoritative).
|
||
|
||
## Gap Analysis and 0.x Roadmap
|
||
|
||
**Published baseline:** v0.9.6 (2026-11-03) — three playable venues, tutorial/campaign/checkpoint
|
||
resume, access/radio/escalation loop, shift review, the Blender asset library, 277 Godot + 161
|
||
Python tests, a 21/21 screen-design judge and Compatibility/Web/Desktop HQ builds.
|
||
**Current source:** 0.10.0-rc.1. Its clean release-candidate build is verified, but it is not
|
||
published while the gates below remain open.
|
||
|
||
### Open gaps
|
||
|
||
| Area | Remaining gap | Milestone |
|
||
| --- | --- | --- |
|
||
| 3D model and local map re-evaluation | Skill-guided asset scorecard/repairs; OSM/3D data, reference-derived facades, AI-assisted composition and map QA | Unversioned |
|
||
| Character development | Complete (moved to `DONE.md`); the MakeHuman body pipeline is the next character pass | 0.11.0 |
|
||
| Content and balance | External first-time-player evidence, balance sweeps/tuning and content lock | 0.10.0 |
|
||
| Audio, accessibility and localization | Accessibility/localization acceptance, caption coverage and pseudo-locale/layout sign-off | 0.10.0 |
|
||
| Performance and platform | Target-hardware matrix, Web/Desktop HQ profiling and frame/memory evidence | 0.10.0 |
|
||
| QA and release engineering | Final smoke matrix, clean build/checksum verification and target-matrix launch tests | 0.10.0 |
|
||
| Legal, signing and storefront | macOS signing/notarization, AI-provider rights, storefront/rating approval and privacy sign-off | 0.10.0 |
|
||
| Documentation and sign-off | Final README/status/TODO/manual evidence and known-limitations sign-off | 0.10.0 |
|
||
| Future 0.x | Live replay, more venues, VO/music, image-to-mesh props and seasonal content | Unscheduled |
|
||
|
||
The 0.9.3 UI, 0.9.4 animation, 0.9.5 texture, 0.9.6 integration and save-migration work are
|
||
complete in `DONE.md`; they are not remaining gaps. The 2026-11-01 documentation audit
|
||
(architecture ownership, stale-claim cleanup and obsolete-plan removal) is also closed.
|
||
|
||
**Priority (2026-11-04):** fix the `Rig` pose harness, then the MakeHuman character pipeline,
|
||
then re-evaluate the 3D models, then ship the **0.11.0** minor release. The 0.10.0 candidate
|
||
still accepts only release-blocking fixes until its external-playtest, legal/storefront, signing
|
||
and platform gates clear.
|
||
|
||
## Milestone 0.10.0 — 3D model and map improvements (minor)
|
||
|
||
Goal: ship all 3D model and map improvements together as the **0.10.0 minor** — the MakeHuman
|
||
body retarget (contract armature + project head/hands), the rebuilt Comedy Store/Hollywood maps,
|
||
and the re-evaluated 3D scorecard — plus the external playtest, legal/storefront, signing and
|
||
platform gates from the old release candidate. The character-development patch (0.9.7) ships
|
||
first; this minor contains the model/map work.
|
||
|
||
### Content lock and external playtest
|
||
|
||
### Content lock and external playtest
|
||
|
||
- [x] Declare a content/feature freeze for 0.10.0; only release-blocking fixes and balance changes
|
||
may land after the freeze. (Frozen 2026-11-03 after the 0.9.6 integration
|
||
checkpoint; this pass is limited to release reliability, accessibility,
|
||
balance evidence and packaging.)
|
||
- [x] Produce a release-candidate build with the tutorial, campaign, all three venues, Help,
|
||
accessibility settings and checkpoint/resume enabled. (Clean worktree
|
||
`a9658ec` built `0.10.0-rc.1`: Linux 161.5 MB, Windows 197.2 MB, macOS
|
||
148.0 MB, Web 97.8 MB and HQ 241.6 MB. The Web/HQ archives include the
|
||
credits, privacy, accessibility and known-limitations pages; SHA-256
|
||
manifests were written; the Linux and HQ binaries launched headless and the
|
||
Web index/wasm/pck/docs returned HTTP 200. Not published because external
|
||
playtest and legal approval remain open.)
|
||
- [ ] Run at least five first-time-player sessions covering the tutorial and one full venue shift;
|
||
record where players get stuck, misunderstand evidence or choose disproportionate escalation.
|
||
- [ ] Triage findings by severity (P0/P1/P2) and fix every P0/P1 onboarding/accessibility issue;
|
||
keep the rest as explicit known limitations or post-0.10 items.
|
||
- [ ] Re-run the affected tutorial/campaign smokes after each fix and capture a fresh first-hour
|
||
walkthrough for the release notes.
|
||
|
||
### Balance and fairness pass
|
||
|
||
- [x] Define measurable targets for routine compliance, access-decision accuracy, peaceful
|
||
resolution, justified emergency calls and false-positive/false-negative rates.
|
||
(`docs/release-qa.md#balance-acceptance` defines cohorts, denominators, 36 matrix cells,
|
||
seeds, thresholds and matched emergency-first comparisons. Documentation verified;
|
||
targets are not measured results.)
|
||
- [ ] Run scripted venue sweeps across easy/normal/hard and all four phases; compare outcomes and
|
||
tune event weights, reaction tables, compliance and report strictness where targets fail.
|
||
- [ ] Review emergency calls against actual danger: no routine behavior should make emergency the
|
||
dominant winning move, and genuine threats must remain answerable. Include the
|
||
type-derived `_read_npc_truth()` mismatch with observed threats/forced entry;
|
||
use independently labelled behavior evidence, not the helper as its own oracle.
|
||
- [ ] Verify the reputation grades, debrief explanations and campaign progression still communicate
|
||
the de-escalation-first design after tuning.
|
||
- [ ] Record the balance evidence and any deliberate exceptions in `docs/development-status.md`
|
||
or `MEMORY.md`.
|
||
|
||
### Save migration and session reliability
|
||
|
||
- [x] Add fixtures for a 0.8-era settings/campaign/history save and a 0.9.0 checkpoint; verify
|
||
migration/default-filling and a clean first launch with no files. (Committed
|
||
fixtures under `src/test/fixtures/saves/`; 9 migration/failure tests cover
|
||
old settings/campaign/history, the 0.9.0 checkpoint, all three venue
|
||
checkpoint round-trips, clean install, corrupt JSON and a blocked atomic
|
||
replace. Suite is now 272 tests.)
|
||
- [x] Test fresh install → tutorial → campaign → pause → quit → resume → review → next venue on
|
||
an isolated user-data directory. (Tutorial and campaign smokes shared one
|
||
isolated `XDG_DATA_HOME`; tutorial completion/replay/skip then campaign
|
||
resume/review-continue/help both passed. Pause/menu behavior is covered by
|
||
`smoke_session_shell.gd`.)
|
||
- [x] Test corrupt JSON, partial temp files, missing optional fields and a failed atomic rename;
|
||
confirm fallback behavior never destroys a valid save. (Corrupt/partial files
|
||
fall back to defaults; a blocked temp path reports an error and leaves the
|
||
prior valid settings intact. `_load_json` now uses the non-logging JSON
|
||
instance parser.)
|
||
- [x] Verify checkpoint resume after all three venues, after an incident, with NPCs at the door and
|
||
with flashlight/body-camera/door state set. (The migration suite round-trips a
|
||
checkpoint for Hollywood, the Joke Shop and the TV Studio with an open
|
||
incident, one NPC row, flashlight/body-camera/door flags; the campaign smoke
|
||
resumes a live checkpoint through the real `GameManager`.)
|
||
- [x] Document save locations, schema versions, reset behavior and rollback/export instructions in
|
||
`docs/getting-started.md` and the release notes. (`getting-started.md` now
|
||
documents the four files, version-1 checkpoint, atomic write/fallback,
|
||
clean install, reset and backup/rollback.)
|
||
|
||
### Release engineering and distribution
|
||
|
||
- [x] Run `tools/build_releases.sh` from a clean checkout and verify Linux/Windows/macOS/Web/HQ
|
||
artifact names, sizes and checksums. (Clean worktree `a9658ec` built the
|
||
five artifacts listed above; `PUBLISH_DRY_RUN=1` produced and printed
|
||
`build/SHA256SUMS-0.10.0-rc.1.txt` without touching the API.)
|
||
- [ ] Smoke-test fresh Linux portable/AppImage, Windows portable/installer, macOS unzip/launch,
|
||
Web static hosting and Desktop HQ Vulkan fallback on the target matrix.
|
||
(Linux portable and Desktop HQ launched headless; Web files served over a
|
||
local static server with HTTP 200. AppImage/installer were not built locally
|
||
and Windows/macOS launch testing still needs the target matrix.)
|
||
- [x] Add a disk-space preflight and retention policy to the release/publish scripts so a full
|
||
Gitea host cannot leave a partially uploaded release. (`publish_release.sh`
|
||
checks artifact size/free space, writes SHA-256 checksums, supports
|
||
`PUBLISH_DRY_RUN`, rolls back uploaded assets/new releases on failure, and
|
||
offers opt-in `RETAIN_RELEASES` pruning; dry-run verified.)
|
||
- [x] Verify release metadata, tag/version consistency, asset counts and download links; retain
|
||
at least the latest 0.8/0.9 releases and document older-asset pruning.
|
||
(Source/version and tag are both 0.9.6; all seven published releases carry
|
||
5–7 assets, including the retained v0.8.0/v0.8.1/v0.9.0/v0.9.1 line.
|
||
`publish_release.sh` documents opt-in `RETAIN_RELEASES` pruning and
|
||
`RELEASING.md` describes the seven-release policy.)
|
||
- [x] Decide and document whether macOS signing/notarization is required for 0.10.0 or explicitly
|
||
remains a future release blocker; record the quarantine instructions either way.
|
||
(0.10.0 ships unsigned with quarantine instructions; signing/notarization
|
||
remains an explicit public-release blocker in `RELEASING.md` and
|
||
`known-limitations.md`.)
|
||
|
||
### Legal, credits and platform policy
|
||
|
||
- [x] Audit AI-assisted asset provenance and licenses; record source/model usage and any
|
||
redistribution constraints for textures, characters, props and UI art.
|
||
(`CREDITS.md` records the Blender/OpenRouter toolchain, default model slugs,
|
||
missing per-file generation metadata and the commercial-rights review as an
|
||
explicit release blocker.)
|
||
- [x] Audit audio/SFX/music licensing (or confirm everything is procedural) and add a credits file.
|
||
(All runtime audio is procedural; no external music/SFX files are bundled.
|
||
`CREDITS.md` records this.)
|
||
- [x] Review body-camera/privacy language, mental-health-crisis representation, age/content rating
|
||
and storefront requirements; fix any release-blocking copy or content.
|
||
(`PRIVACY.md` clarifies the simulated body camera/local-only data; the
|
||
accessibility and known-limitations pages record the remaining
|
||
mental-health/rating/storefront review as a release blocker rather than
|
||
claiming approval.)
|
||
- [x] Add the player-facing credits, known limitations, accessibility statement and privacy note to
|
||
the release package/README. (`README.md` links `CREDITS.md`, `PRIVACY.md`,
|
||
`docs/accessibility.md` and `docs/known-limitations.md`; the Web and Desktop
|
||
HQ package builders copy those documents into the shipped archives.)
|
||
- [ ] Mark external legal/storefront approval as complete or explicitly block the 0.10.0 release on it.
|
||
|
||
### Documentation and visual sign-off
|
||
|
||
- [ ] Update `README.md`, `PLAN.md`, `docs/architecture.md`, ADRs, `docs/development-status.md`,
|
||
`docs/getting-started.md`, `docs/release-qa.md#manual-smoke-checklist`, `CHANGELOG.md` and this roadmap.
|
||
- [ ] Regenerate the full screenshot gallery and realism baselines from the release-candidate
|
||
build (not the dev tree) after content lock; run `check_screenshots.sh` and the pinned vision
|
||
judge, recording model/spend/verdicts, and refresh the README and venue-doc images.
|
||
- [ ] Include the reference/concept boards and the updated asset sheets in the release docs, and
|
||
verify every README and docs-page image resolves from the tagged build.
|
||
- [ ] Run the manual smoke checklist on every target and attach/link the release-candidate evidence.
|
||
- [ ] Verify the tutorial/campaign/help text at maximum font scale and with the longest strings.
|
||
- [x] Remove or archive stale plans/notes and confirm no contradictory version/status claims remain.
|
||
- [x] Document the character development toolchain in `docs/architecture.md`: base vs library
|
||
sources, tool/artifact/gate table, runtime attach/animation contracts and rebuild discipline.
|
||
(Added §5 "Character development tooling" plus risk and ownership-map updates;
|
||
documentation check passed.)
|
||
|
||
### Release-candidate QA and exit
|
||
|
||
- [ ] Run the complete headless suite, Python tooling, tutorial/campaign/session/scenario smokes,
|
||
24-NPC budget smoke and release build from a clean checkout.
|
||
- [ ] Run the manual QA matrix: fresh install, upgrade, offline launch, gamepad, accessibility
|
||
settings, pause/resume, all venues and Desktop HQ fallback.
|
||
- [ ] Confirm no P0/P1 defects remain; P2 items must be documented as known limitations or
|
||
post-0.10 work.
|
||
- [ ] Create the `v0.10.0` version bump, changelog entry and tag; build/publish the release and
|
||
verify all assets and download links.
|
||
- [ ] Exit: the release candidate is content-locked, externally played, legally reviewed,
|
||
documented, reproducibly built, and approved as the 0.10.0 release candidate.
|
||
|
||
## Milestone 0.9.7 — Character development (patch)
|
||
|
||
Goal: release the finished procedural character development — the realistic face on all eight
|
||
variants, the four crowd-variety characters and the per-role pools — as a **patch** on top of
|
||
0.9.6. This keeps the 3D model and map improvements out of the patch; they land together in the
|
||
0.10.0 minor.
|
||
|
||
- [x] Rig pose harness fixed and the weights/pose evidence captured (see the top track).
|
||
- [x] Character work done: 12-character library, realistic face, crowd variants, per-role pools,
|
||
24-NPC budget 6.94 ms (152,464 tris / 168 meshes).
|
||
- [x] QA + local build for 0.9.7: Godot 277/277, Python 161/161, audit 49 OK, fit/proportions
|
||
12/12, release smoke matrix green, gallery 21/0, clean worktree build (Linux 172 MB,
|
||
Windows 206 MB, macOS 159 MB, Web 111 MB, HQ 266 MB), checksums verified, Linux binary
|
||
launches headless. Tagged `v0.9.7` (CI build/publish follows).
|
||
|
||
**Exit:** met — 0.9.7 ships the 12-character library (face realism + crowd variety) with the pose
|
||
harness fixed; the runtime contract is unchanged. The MakeHuman body and the map rebuild are not
|
||
in this patch (they target 0.10.0).
|
||
|
||
## Roadmap dependencies and risks
|
||
|
||
- Content volume is the largest schedule risk; tutorial and campaign work must not outrun the
|
||
event/dialogue matrix.
|
||
- The vision judge is a dev-time aid with an external key/budget; CI must never make it a hard gate.
|
||
- Godot version changes can alter lighting/imports; do not combine an engine baseline move with a
|
||
content/feature milestone.
|
||
- Signed macOS builds and legal/AI provenance are release blockers, not polish.
|
||
- Photo-derived map assets add a second provenance risk: downloaded or user-supplied photos can
|
||
carry unclear licences, identifiable people, plates and property restrictions. No photo or
|
||
splat-derived asset ships without a completed sidecar, consent/licence review and redaction.
|
||
- Gaussian-splat training is GPU/disk-heavy and the toolchain churns quickly; keep it offline,
|
||
version-pinned and outside CI, and never make a runtime splat renderer a release dependency.
|
||
- Keep the de-escalation-first rules and rare-emergency design unchanged while adding progression,
|
||
difficulty and feedback.
|
||
|
||
- The Blender skill pack is local, unversioned guidance; it can drift from the project contract or
|
||
assume Blender MCP. Re-verify every adopted technique with `inspect`/`audit`/`fit` and never
|
||
make a skill, asset pack or tool version a build or CI dependency.
|
||
- The 3D re-evaluation can expand without bound (retopo every head, rig every finger). Cap it with
|
||
the scorecard ranking: P0/P1 only, one asset family per commit, and an explicit accept for
|
||
everything else.
|
||
|
||
## Future / deferred (not scheduled)
|
||
|
||
- [ ] Live 3D body-camera replay; the timeline is text-only today.
|
||
- [ ] Additional venues or seasonal events authored from the `content/venues/` resources.
|
||
- [ ] Real voice/dialogue audio; ambience, cues and radio crackle are procedural.
|
||
- [ ] Swap the primitive prop builder for an image-to-mesh model API behind the same
|
||
`assets/models/generated/<prop>.glb` contract.
|
||
- [ ] Rare easter eggs/cameos (e.g. Bob Dobbs) only after core content and QA are stable.
|
||
|
||
## Gaussian splatting evaluation (deferred)
|
||
|
||
Postponed for further development on 2026-11-03. The local-map track ships the facade kit and
|
||
reference-anchored material passes first; this photo-driven pipeline stays an unversioned,
|
||
offline study with no runtime or release dependency until an ADR closes it. All licence and
|
||
privacy gates below remain in force whenever the track resumes.
|
||
|
||
### Photo intake and provenance
|
||
|
||
Gaussian splatting is evaluated as a photo-driven pipeline: licensed or permissioned photos
|
||
become a reference, texture source, mesh proxy or distant backdrop. It is an unversioned local
|
||
track with no runtime dependency or release gate until the ADR closes it, and it extends the
|
||
reference-image licence and privacy gates above rather than replacing them.
|
||
|
||
- [ ] Define the accepted photo channels: project/team captures, volunteer or user-supplied
|
||
photos with written permission, and downloaded images from clearly licensed archives
|
||
(Wikimedia Commons, Openverse, Mapillary and similar). Record which channel produced
|
||
each reconstruction.
|
||
- [ ] Write a one-page capture brief for user-supplied photos: overlapping arc or orbit around
|
||
the facade, 60–80% view overlap, 12 MP+ originals, fixed exposure/white balance, HDR and
|
||
filters off, no motion blur, no people or plates in frame where avoidable, overcast or
|
||
even light, and the facade height/doors/steps included in several frames.
|
||
- [ ] Build an intake checklist and provenance sidecar per photo set: contributor, consent or
|
||
property permission, licence and attribution text, source URL, capture date, camera/lens,
|
||
location, faces/plates/interiors present, redactions applied, file hashes and whether the
|
||
set is shipped or development-only.
|
||
- [ ] Set the licence gate: own photos need an explicit contributor licence; CC0/CC BY are
|
||
preferred; CC BY-SA triggers a share-alike review for derived textures and meshes; reject
|
||
Street View, social-media scrapes, unlicensed commercial imagery and AI-upscaled copies of
|
||
unknown originals. Attribution must be feasible in `CREDITS.md` before use.
|
||
- [ ] Set the privacy gate: blur or remove faces, minors, licence plates, screens, private
|
||
interiors and anything behind a closed door; obtain property permission where required;
|
||
keep a redacted copy as the reconstruction input and never commit the originals.
|
||
- [ ] Treat downloaded photo sets as sparse and of unknown intrinsics. Use them for reference,
|
||
palette and texture study, or as extra training views; do not expect a usable splat from
|
||
10–30 casual web photos of a facade.
|
||
- [ ] Keep photos, masks, COLMAP databases, checkpoints and splats outside git; commit only
|
||
derived, licensed, provenance-stamped assets that pass the review gate.
|
||
|
||
### Reconstruction and alignment
|
||
|
||
- [ ] Pin a reproducible offline toolchain (for example COLMAP or GLOMAP for camera poses plus
|
||
gsplat, OpenSplat, Nerfstudio or Brush for training), with exact versions, GPU/VRAM/disk
|
||
needs and known failure modes recorded in the sidecar.
|
||
- [ ] Reconstruct two quality tiers: a dense 100–400-photo arc/orbit capture and a sparse
|
||
10–30-photo downloaded set. Record camera-registration rate, training time, splat count,
|
||
file size and held-out PSNR/SSIM/LPIPS for both.
|
||
- [ ] Mask sky, people, vehicles and moving foliage before training; verify the masks do not
|
||
erase facade edges, signage or window detail, and keep the redacted input variant.
|
||
- [ ] Align the splat to game coordinates from the OSM footprint plus surveyed points (door
|
||
width, column spacing, step rise, storefront height) and record alignment residuals in a
|
||
Blender scene containing both the splat and the current venue geometry (`scene-assembly`).
|
||
- [ ] Judge quality from held-out views and a render from the game's day/night camera poses
|
||
(`camera-cinematography`, `lookdev`, `qa-review`), not from training views alone; reject
|
||
splats that only look correct from the capture path.
|
||
- [ ] Maintain a coverage map per block: which facades, corners and rooflines have usable views,
|
||
and which areas must fall back to the facade kit or stylized geometry.
|
||
|
||
### Map enhancement paths
|
||
|
||
- [ ] **Path A — Reference and QA (lowest risk):** render the splat from game camera poses and
|
||
compare it with the realism captures; derive dimensions, signage placement, facade rhythm
|
||
and material colours. No splat data reaches the runtime.
|
||
- [ ] **Path B — Texture derivation:** project splat renders **or reference photos** onto the
|
||
facade kit to produce albedo, normal, roughness and AO candidates; de-light and bake them
|
||
(`texture-workflow`), then verify UV scale, tiling and readability under the Compatibility
|
||
renderer. Deriving directly from a committed reference photo requires its licence to allow
|
||
derived works and a `CREDITS.md` entry; CC BY-SA sources stay out unless reviewed.
|
||
- [ ] **Path C — Mesh proxy:** extract a mesh from the splat or dense reconstruction, retopo and
|
||
dress it in Blender (`retopology`, `prop-artist`), assign LODs (`lod-pipeline`), and keep it
|
||
inside the venue triangle/material budgets with mesh-based colliders (`collision-proxy`).
|
||
- [ ] **Path D — Distant backdrop:** test a baked panorama, impostor or billboard generated from
|
||
the splat for skyline and opposite-street depth where the player cannot walk; measure file
|
||
size, loading and visible pop at the venue boundary.
|
||
- [ ] **Path E — User-photo supplement:** let a small supplied photo set improve one facade or
|
||
landmark (a signage patch, colour reference or hero detail) without rebuilding the venue;
|
||
define the minimum evidence and the same licence/privacy/review gate as a full capture.
|
||
- [ ] For every path record quality gain versus effort, licence compatibility of the derived
|
||
output, and whether the result may ship or stays development-only. Prefer the cheapest
|
||
path that closes the visible gap.
|
||
|
||
### Runtime evaluation and decision
|
||
|
||
- [ ] Probe Godot 4.7.2 Compatibility and Web support for splat rendering in a throwaway scene:
|
||
addon or importer availability, shader/sort cost, memory, load time and fallback behaviour.
|
||
Do not add a splat dependency to the release project during evaluation.
|
||
- [ ] Set hard limits before any runtime experiment: maximum per-splat file size and total
|
||
memory, allowed frame-time delta on the 24-NPC budget scene, acceptable Web load time, and
|
||
no compute-shader requirement for the Compatibility/Web path.
|
||
- [ ] Keep collision and navigation mesh-based even if a splat is displayed; a splat must never
|
||
become the playable floor or the access/occlusion authority.
|
||
- [ ] Write the ADR with a per-path go/no-go, the accepted licence/provenance rules, whether each
|
||
result ships or stays development-only, rejected alternatives and the evidence bundle.
|
||
- [ ] Exit: one licensed photo capture measurably improves a venue through a documented path and
|
||
passes visual, performance and provenance review; or the approach is rejected with
|
||
reproducible findings and removed from the release path.
|