Compare commits

...
64 Commits
Author SHA1 Message Date
zwitschi a196a35342 Give Hollywood and the TV Studio the same queue story and validate every venue's placements
Full build / Import + headless tests (push) Successful in 42s
Full build / Full desktop build + optional release (push) Skipped
2026-11-06 20:55:52 +01:00
zwitschi efa062833f Give the Joke Shop a real queue line and thicken the rope barrier
Full build / Import + headless tests (push) Successful in 46s
Full build / Full desktop build + optional release (push) Skipped
2026-11-06 20:47:28 +01:00
zwitschi 6381dbc5cb Give the event banners a top-down night gradient so they read as lit cloth
Full build / Import + headless tests (push) Successful in 47s
Full build / Full desktop build + optional release (push) Skipped
2026-11-06 20:33:31 +01:00
zwitschi 7546092c01 Give the street lamps real pools: 10 m range and 8 energy at physical falloff
Full build / Import + headless tests (push) Successful in 37s
Full build / Full desktop build + optional release (push) Skipped
2026-11-06 20:29:26 +01:00
zwitschi 16dc1dfea4 Tune the flashlight against measured luminance and refresh the venue gallery
Full build / Import + headless tests (push) Successful in 41s
Full build / Full desktop build + optional release (push) Skipped
2026-11-06 20:20:22 +01:00
zwitschi 2ba40f3578 Reorganize docs into category folders and drop the retired head-review page
Full build / Import + headless tests (push) Successful in 41s
Full build / Full desktop build + optional release (push) Skipped
Group the top-level docs into docs/project, docs/design, docs/assets and
docs/process, each with its own README index. Delete the superseded
docs/screens/head-review page and sheets. Rewrite every markdown link,
absolute docs path and tool/test reference to the new locations, fix the
pre-existing broken anchors and remove the dead Joke Shop photo-board link.
check_docs OK, Python tooling 167/167.
2026-11-06 20:13:03 +01:00
zwitschi 045ed2a58f Rebuild the foliage with leaf cards: leafier silhouette at two thirds the triangles
Full build / Import + headless tests (push) Successful in 42s
Full build / Full desktop build + optional release (push) Skipped
2026-11-06 20:02:32 +01:00
zwitschi d3a87acf2d Record the three failed Swat yaw attempts and keep the guard on the worker base
Full build / Import + headless tests (push) Successful in 41s
Full build / Full desktop build + optional release (push) Skipped
2026-11-06 19:50:31 +01:00
zwitschi b18236f9b4 Roll out seven modular outfit bases: eleven distinct outfits across twelve roles
Full build / Import + headless tests (push) Successful in 41s
Full build / Full desktop build + optional release (push) Skipped
2026-11-06 19:37:11 +01:00
zwitschi 3b9e3b61d8 Intake the modular outfit pack and ship the Suit base for npc_coat
Full build / Import + headless tests (push) Successful in 42s
Full build / Full desktop build + optional release (push) Skipped
2026-11-06 19:02:38 +01:00
zwitschi f6bb2b1de3 Prepare the modular part intake: inventory, extract, verify, join and the part contract
Full build / Import + headless tests (push) Successful in 41s
Full build / Full desktop build + optional release (push) Skipped
2026-11-06 18:54:08 +01:00
zwitschi 7a46963e3f Add the hair part library and give the roster three silhouettes
Full build / Import + headless tests (push) Successful in 39s
Full build / Full desktop build + optional release (push) Skipped
2026-11-06 18:48:38 +01:00
zwitschi a0dbf75806 Add eye whites and pupils to every base and archive the 0.9.9 milestone
Full build / Import + headless tests (push) Successful in 43s
Full build / Full desktop build + optional release (push) Skipped
2026-11-06 18:44:39 +01:00
zwitschi c70a523f0f Close and archive the 0.9.9 milestone, record that the upstream clips stay unused, and harden the fallback test
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 44s
2026-11-06 18:39:53 +01:00
zwitschi fcbeee0db2 Retire the NPC review pages after owner acceptance and repoint every reference
Full build / Import + headless tests (push) Successful in 50s
Full build / Full desktop build + optional release (push) Skipped
2026-11-06 18:37:17 +01:00
zwitschi d5e180e50c Raise the back gear to shoulder-blade height and compact the review page
Full build / Import + headless tests (push) Successful in 45s
Full build / Full desktop build + optional release (push) Skipped
2026-11-06 18:35:02 +01:00
zwitschi a36068aae7 Drop hand items into the palm, raise the lanyard, and capture every gear piece worn on the character
Full build / Import + headless tests (push) Successful in 43s
Full build / Full desktop build + optional release (push) Skipped
2026-11-06 18:30:52 +01:00
zwitschi 6b58350464 Close the measurable prop-fit items and point the review page row 4 at the owner verdict
Full build / Import + headless tests (push) Successful in 46s
Full build / Full desktop build + optional release (push) Skipped
2026-11-06 18:11:31 +01:00
zwitschi 219588bf8a Start the prop and gear fit pass: hand-gear measurement, top-edge clipboard, carried role props, 15-piece gear set
Full build / Import + headless tests (push) Successful in 39s
Full build / Full desktop build + optional release (push) Skipped
2026-11-06 18:11:20 +01:00
zwitschi cba00facf5 Record the roster fixes, material-list traps and head-gear offset in MEMORY.md
Full build / Import + headless tests (push) Successful in 41s
Full build / Full desktop build + optional release (push) Skipped
2026-11-06 18:05:57 +01:00
zwitschi 9fd48243ad Give every Quaternius head a visible mouth and queue the prop and gear fit pass
Full build / Import + headless tests (push) Successful in 40s
Full build / Full desktop build + optional release (push) Skipped
2026-11-06 18:02:55 +01:00
zwitschi 30d145079a Remove every hat except the firefighter helmet, drop the performer cone, rewrite the review page
Full build / Import + headless tests (push) Successful in 45s
Full build / Full desktop build + optional release (push) Skipped
2026-11-06 17:52:46 +01:00
zwitschi 98f618c501 Copy the hoodie eye pair onto the Worker head and lift every hat except the firefighter helmet
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 46s
2026-11-06 15:11:57 +01:00
zwitschi a290fe83c8 Lift and scale head gear for the Quaternius head so the cap stops reading as a visor
Full build / Import + headless tests (push) Successful in 43s
Full build / Full desktop build + optional release (push) Skipped
2026-11-06 15:00:43 +01:00
zwitschi 529d15ee7a Transplant the hoodie head parts onto the Worker base and put carried props in the hands
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 45s
2026-11-06 14:40:35 +01:00
zwitschi 3ab7577634 Fix the worker torso/crown holes, transplant proper brows, widen the rest-arm clearance
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 42s
2026-11-06 14:28:57 +01:00
zwitschi c8875a3dfa Turn the NPC visual review into the 0.9.9 roster signoff page with committed sheets
Full build / Import + headless tests (push) Successful in 44s
Full build / Full desktop build + optional release (push) Skipped
2026-11-06 14:05:49 +01:00
zwitschi b3acf370fc Mark the roster build done and record the release-size follow-up
Full build / Full desktop build + optional release (push) Successful in 4m58s
Full build / Import + headless tests (push) Successful in 42s
2026-11-06 13:59:28 +01:00
zwitschi 04d211b90b Release 0.9.9: full Quaternius roster, docs, changelog, version, slimmer export filters and checksums
Full build / Import + headless tests (push) Successful in 40s
Full build / Full desktop build + optional release (push) Skipped
2026-11-06 13:59:23 +01:00
zwitschi a6ccd86f85 Swap the full 12-character roster onto the CC0 Quaternius bases
Full build / Import + headless tests (push) Successful in 40s
Full build / Full desktop build + optional release (push) Skipped
2026-11-06 13:56:30 +01:00
zwitschi 1ce173e9d1 Record the Quaternius pilot bake, measurements and face-gate decision point in the docs
Full build / Import + headless tests (push) Successful in 45s
Full build / Full desktop build + optional release (push) Skipped
2026-11-06 13:45:05 +01:00
zwitschi 90f189a269 Add the Quaternius face/silhouette gate sheet and record the geometry measurements
Full build / Import + headless tests (push) Successful in 41s
Full build / Full desktop build + optional release (push) Skipped
2026-11-06 13:44:46 +01:00
zwitschi fb3e75aba3 Refit the backpack straps for both torsos (ADR-0018)
Full build / Import + headless tests (push) Successful in 44s
Full build / Full desktop build + optional release (push) Skipped
2026-11-06 13:43:52 +01:00
zwitschi cd285b3a39 Ship the Quaternius npc_casual pilot base: rig-agnostic pose sync, five tint slots, unwrapped UVs and wrist-strap camera
Full build / Import + headless tests (push) Successful in 41s
Full build / Full desktop build + optional release (push) Skipped
2026-11-06 13:42:37 +01:00
zwitschi 68f49253fe Record the Quaternius pilot fixes and remaining 0.9.9 work in MEMORY.md
Full build / Import + headless tests (push) Successful in 42s
Full build / Full desktop build + optional release (push) Skipped
2026-11-06 13:19:42 +01:00
zwitschi b012c6a675 Record the Quaternius bake/pose-sync progress
Full build / Import + headless tests (push) Successful in 50s
Full build / Full desktop build + optional release (push) Skipped
2026-11-06 12:17:30 +01:00
zwitschi 2a6f29f5d0 Fix the Quaternius side swap, arm swing axis, and hand-proxy position (backward-compatible)
Full build / Import + headless tests (push) Successful in 45s
Full build / Full desktop build + optional release (push) Skipped
2026-11-06 12:17:18 +01:00
zwitschi bb54ef3eec Record the canonical-base and arm-down-bake findings precisely
Full build / Import + headless tests (push) Successful in 46s
Full build / Full desktop build + optional release (push) Skipped
2026-11-06 10:33:52 +01:00
zwitschi 11f53f66a3 Record the two skinning root causes: weld corrupts weights, bake needs head/tail plus roll
Full build / Import + headless tests (push) Successful in 48s
Full build / Full desktop build + optional release (push) Skipped
2026-11-06 10:26:56 +01:00
zwitschi 9b65a93587 Narrow the Godot skinning blocker to the importer's rotated bind_pose
Full build / Import + headless tests (push) Successful in 47s
Full build / Full desktop build + optional release (push) Skipped
2026-11-06 10:13:32 +01:00
zwitschi 56a14747d4 Record the pose-composition fix and the remaining Godot skinning-import blocker
Full build / Import + headless tests (push) Successful in 47s
Full build / Full desktop build + optional release (push) Skipped
2026-11-06 10:00:07 +01:00
zwitschi 8b1bf736af Correct the pose composition for a non-180° rest (rest-relative swing axis), backward-compatible with the 13-core fallback
Full build / Import + headless tests (push) Successful in 42s
Full build / Full desktop build + optional release (push) Skipped
2026-11-06 09:57:27 +01:00
zwitschi f121167e52 Record the arm-down bake fix and the remaining non-180° rest pose-composition task
Full build / Import + headless tests (push) Successful in 47s
Full build / Full desktop build + optional release (push) Skipped
2026-11-06 09:52:13 +01:00
zwitschi 140a7ada0f Plan the 0.9.9-1.0.0 roadmap and re-evaluate the NPC base
Full build / Import + headless tests (push) Successful in 48s
Full build / Full desktop build + optional release (push) Skipped
Move the gap analysis and risks into PLAN.md, version the character track
(0.9.9 rig correction, 0.9.10 roster) and split 0.9.11-0.9.12 polish and
verification out of the old 0.10.0 milestone. Add roadmaps to 0.10.0, 0.11.0
and 1.0.0, record the Quaternius face-fidelity gate and the rest-relative
pose finding in MEMORY.md, and move the completed 0.9.7 and pose-harness
sections to DONE.md.
2026-11-06 09:40:28 +01:00
zwitschi 5508f5510f Record the Quaternius pose-sync blockers (GLB skinning + non-180° rest pose formula)
Full build / Import + headless tests (push) Successful in 48s
Full build / Full desktop build + optional release (push) Skipped
2026-11-06 09:25:45 +01:00
zwitschi 7baa2c4f54 Record the Quaternius pose-sync finding (swing axis needs per-bone calibration)
Full build / Import + headless tests (push) Successful in 50s
Full build / Full desktop build + optional release (push) Skipped
2026-11-06 08:35:29 +01:00
zwitschi 0cd12af994 Fix proxy pivot derivation to use global rest (local rest was misplacing the Quaternius joints)
Full build / Import + headless tests (push) Successful in 55s
Full build / Full desktop build + optional release (push) Skipped
2026-11-06 08:35:14 +01:00
zwitschi 271f10ac4d Map NpcAvatar bone sync and proxy pivots to the Quaternius 62-joint names with old-rig fallback
Full build / Import + headless tests (push) Successful in 2m36s
Full build / Full desktop build + optional release (push) Skipped
2026-11-06 07:38:39 +01:00
zwitschi e2f52fbfd1 Accept ADR-0018 option 2: adopt the Quaternius 62-joint rig at runtime
Full build / Import + headless tests (push) Successful in 48s
Full build / Full desktop build + optional release (push) Skipped
2026-11-05 21:39:38 +01:00
zwitschi f5fa321a8f Draft ADR-0018 (Stage 2 runtime rig) and mark the remaining contract-bake items blocked
Full build / Import + headless tests (push) Successful in 45s
Full build / Full desktop build + optional release (push) Skipped
2026-11-05 21:38:26 +01:00
zwitschi a2ae9e03c3 Bake the rest pose, warp to the contract, and record the failing silhouette gate
Full build / Import + headless tests (push) Successful in 47s
Full build / Full desktop build + optional release (push) Skipped
2026-11-05 21:01:26 +01:00
zwitschi cff3937c16 Mark the 62-to-13 joint map complete
Full build / Import + headless tests (push) Successful in 46s
Full build / Full desktop build + optional release (push) Skipped
2026-11-05 20:49:05 +01:00
zwitschi 1ed9e05d9b Author the 62-to-13 joint map and align the AGENTS.md contract with the Quaternius base
Full build / Import + headless tests (push) Successful in 50s
Full build / Full desktop build + optional release (push) Skipped
2026-11-05 20:48:55 +01:00
zwitschi 8c69f367b0 Record the owner directive: keep Quaternius at source detail during the contract bake
Full build / Import + headless tests (push) Successful in 48s
Full build / Full desktop build + optional release (push) Skipped
2026-11-05 20:47:08 +01:00
zwitschi 2a7921bae6 Build and document the canonical quaternius_base.glb (welded, skinned, 62-joint, 1.81m)
Full build / Import + headless tests (push) Successful in 44s
Full build / Full desktop build + optional release (push) Skipped
2026-11-05 20:43:50 +01:00
zwitschi b419923637 Decide the Quaternius outfit scope: three full GLBs first, modular builder as the role fallback
Full build / Import + headless tests (push) Successful in 48s
Full build / Full desktop build + optional release (push) Skipped
2026-11-05 20:41:23 +01:00
zwitschi c7fd4b59cc Inventory the Quaternius GLBs: meshes, 62 joints, 24 clips and the material-slot map
Full build / Import + headless tests (push) Successful in 55s
Full build / Full desktop build + optional release (push) Skipped
2026-11-05 20:40:59 +01:00
zwitschi 3fa3482608 Complete Quaternius intake record: verify SHA-256 and add the download date
Full build / Import + headless tests (push) Successful in 47s
Full build / Full desktop build + optional release (push) Skipped
2026-11-05 20:39:39 +01:00
zwitschi 1049d8631e Compact MEMORY.md: drop the redundant session handoff, trim the AI-review entry 2026-11-05 20:38:26 +01:00
zwitschi deb74c53af Record the Quaternius pivot handoff in session memory 2026-11-05 19:44:26 +01:00
zwitschi 9968bc0a4c Rewrite NPC plans around the Quaternius base 2026-11-05 19:43:35 +01:00
zwitschi 2e1bb19e2c Correct the MPFB prototype glTF vertex count 2026-11-05 19:37:37 +01:00
zwitschi 5450dbf88a Correct the MPFB prototype glTF vertex count 2026-11-05 19:37:33 +01:00
zwitschi 79224c5acf Raise the NPC character budget to 24k and refine the prototype neck 2026-11-05 19:37:19 +01:00
157 changed files with 5028 additions and 1986 deletions

No files matched your search

@@ -1,6 +1,6 @@
---
name: gig-line-blender-asset-contract
description: Use when adding, rebuilding, auditing or fixing any Gig Line Blender-authored character, NPC base, gear, prop or venue geometry. Covers the required 13 core bones (optional extra bones allowed), five tint slots, 16,000/16,000 character budgets, gear attach space, 256² texture/AO rules, headless flatpak Blender commands, optional MCP guidance, and the inspect/audit/fit/proportion/capture gates. Do not use for pure GDScript/UI work or release publishing.
description: Use when adding, rebuilding, auditing or fixing any Gig Line Blender-authored character, NPC base, gear, prop or venue geometry. Covers the required 13 core bones (optional extra bones allowed), five tint slots, 24,000/24,000 character budgets, gear attach space, 256² texture/AO rules, headless flatpak Blender commands, optional MCP guidance, and the inspect/audit/fit/proportion/capture gates. Do not use for pure GDScript/UI work or release publishing.
compatibility: Gig Line repository checkout. Godot 4.7.2 on PATH; Blender 5.2 LTS via the org.blender.Blender flatpak for build/bake/render. Audit, fit, inspect and proportion checks are stdlib-only.
metadata:
project: Gig Line
@@ -24,7 +24,7 @@ The project contract and measured gates override any generic Blender advice.
Blender MCP is optional interactive tooling; the headless flatpak CLI remains
authoritative and CI never needs Blender or MCP. The `blender-skills` pack is
optional, local guidance only, and gitignored. Setup and safety are in
`docs/asset-tooling.md#optional-interactive-blender-mcp`.
`docs/assets/asset-tooling.md#optional-interactive-blender-mcp`.
## Read first
@@ -33,11 +33,11 @@ skill alone:
1. `AGENTS.md` — required workflow and verification.
2. `TODO.md` and `MEMORY.md` — current track, claimed tasks, known gotchas.
3. `docs/blender-assets.md` — library contract and command reference.
4. `docs/asset-tooling.md` — exact rebuild/bake/capture commands.
5. `docs/npc-visual-review.md` and `docs/3d-model-review.md` — accepted limits,
3. `docs/assets/blender-assets.md` — library contract and command reference.
4. `docs/assets/asset-tooling.md` — exact rebuild/bake/capture commands.
5. `docs/assets/npc-model-sourcing.md` and `docs/assets/3d-model-review.md` — accepted limits,
scorecards and known blockers.
6. `docs/known-limitations.md` — limits that must not be silently “fixed” into
6. `docs/design/known-limitations.md` — limits that must not be silently “fixed” into
contract changes.
The contract lives in code and docs, not in this skill. If they disagree, stop
@@ -51,8 +51,8 @@ and resolve the source of truth before editing assets.
| Bones | The 13 required core bones: `Head`, `HipL/R`, `KneeL/R`, `ShoulderL/R`, `ElbowL/R`, `HandL/R`, `Spine`, `Neck`. Optional extra bones (fingers, face, toes) are allowed; they must not move the core rest positions or break animation proxies. |
| Tint slots | `skin`, `cloth`, `pants`, `accessory`, `hair`. |
| Orientation | Front is Blender −Y / Godot +Z; feet grounded near y = 0; metres. |
| Character budget | **16,000 triangles / 16,000 glTF vertices** per character (`CHAR_MAX_TRIS`/`CHAR_MAX_VERTS`). |
| Frozen fallback | `npc_base` remains the low-poly fallback; it shares the 16,000/16,000 cap but is not required to use it. Do not silently lower the cap. |
| Character budget | **24,000 triangles / 24,000 glTF vertices** per character (`CHAR_MAX_TRIS`/`CHAR_MAX_VERTS`). |
| Frozen fallback | `npc_base` remains the low-poly fallback; it shares the 24,000/24,000 cap but is not required to use it. Do not silently lower the cap. |
| Gear budget | **1,500 triangles** per gear piece; authored in attach-point space. |
| Prop budget | **4,000 triangles** per prop. |
| Gear attach | Use the catalogued attach points; verify with `fit`. Runtime `GEAR_OFFSETS` (lanyard forward, firefighter helmet up) and `HAND_ITEM_FORWARD` are intentional, not asset-contract changes. |
@@ -114,7 +114,7 @@ only the specialists the task needs:
- budget/LOD/collision: `asset-optimization`, `lod-pipeline`, `collision-proxy`
- final review: `qa-review`
If MCP is available, use it for interactive part exploration only; mirror the result into a scripted change or local `.blend`, then re-export and run the CLI audit/fit gates. Never make the build, CI, tests or runtime depend on MCP. Setup: `docs/asset-tooling.md#optional-interactive-blender-mcp`.
If MCP is available, use it for interactive part exploration only; mirror the result into a scripted change or local `.blend`, then re-export and run the CLI audit/fit gates. Never make the build, CI, tests or runtime depend on MCP. Setup: `docs/assets/asset-tooling.md#optional-interactive-blender-mcp`.
### 4. Build or bake
@@ -167,7 +167,7 @@ At minimum:
- `npc_proportions.py` passes the stylized guide.
- `npc_pipeline.py audit` passes if the base/textures changed.
- texel density is inside the authored/fabric bands.
- No character exceeds 16,000/16,000; gear/prop caps hold.
- No character exceeds 24,000/24,000; gear/prop caps hold.
- 24-NPC budget and Web/Compatibility path remain green.
- Contract tests, headless suite, capture gates and docs check pass.
- The diff contains only the intended assets, tools, tests and docs.
@@ -185,7 +185,7 @@ gates run, and any accepted limit.
- **Empty or stale captures** — close modals/pause, check the capture script's
settle frames, and remove stale output directories before re-running.
- **Pose harness mismatch** — the current `capture_npc_pose.gd` is blocked per
`docs/3d-model-review.md`; do not use its frames as pose evidence until the
`docs/assets/3d-model-review.md`; do not use its frames as pose evidence until the
recipe is fixed.
- **Asset test fails after import** — re-run audit/fit first, then import; if the
manifest or AO path changed, rebuild the affected asset rather than editing
@@ -197,7 +197,7 @@ gates run, and any accepted limit.
- [`references/asset-contract.md`](references/asset-contract.md) — full contract,
inventory, file locations and provenance rules.
- `docs/asset-tooling.md#optional-interactive-blender-mcp` — optional MCP installation, connection, safety and
- `docs/assets/asset-tooling.md#optional-interactive-blender-mcp` — optional MCP installation, connection, safety and
part-workflow instructions.
- [`references/verification.md`](references/verification.md) — command matrix,
capture gates, expected results and acceptance criteria.
@@ -1,7 +1,7 @@
# Asset Contract Reference
This is a working summary. The authoritative sources remain
`docs/blender-assets.md`, `docs/asset-tooling.md`, ADR-0013, the tests in
`docs/assets/blender-assets.md`, `docs/assets/asset-tooling.md`, ADR-0013, the tests in
`src/test/tests/` and the constants in `tools/blender_assets.py` /
`tools/npc_pipeline.py`.
@@ -59,7 +59,7 @@ skin, cloth, pants, accessory, hair
| Asset | Limit |
| --- | --- |
| Character (library and base fallback) | 16,000 triangles / 16,000 glTF vertices |
| Character (library and base fallback) | 24,000 triangles / 24,000 glTF vertices |
| Gear piece | 1,500 triangles |
| Prop | 4,000 triangles |
| Library prop/venue total | must stay inside the venue tests and library budget |
@@ -113,8 +113,8 @@ For each changed variant, inspect at least:
- Day and night/LATE final-context frames.
- Front, three-quarter and profile for a shape change.
Accepted stylized limits are in `docs/npc-visual-review.md` and
`docs/known-limitations.md`. Do not turn an accepted limit into an unreviewed
Accepted stylized limits are in `docs/assets/3d-model-review.md` and
`docs/design/known-limitations.md`. Do not turn an accepted limit into an unreviewed
contract change.
## Final diff review
+6 -6
View File
@@ -19,9 +19,9 @@ publishing, and the full visual/QA gate. For a Blender/asset rebuild, use
1. `AGENTS.md` — release procedure and verification rules.
2. `TODO.md` — current milestone, blockers and release exit criteria.
3. `docs/RELEASING.md` — build/publish commands, artifact list, macOS policy.
4. `docs/release-qa.md` — manual QA matrix and balance protocol.
5. `docs/development-status.md`, `CHANGELOG.md`, `README.md` — current claims.
3. `docs/process/RELEASING.md` — build/publish commands, artifact list, macOS policy.
4. `docs/process/release-qa.md` — manual QA matrix and balance protocol.
5. `docs/project/development-status.md`, `CHANGELOG.md`, `README.md` — current claims.
6. `MEMORY.md` — release gotchas, especially the clean-worktree rule.
A release is not just a tag. It includes a version bump, changelog, clean build,
@@ -58,8 +58,8 @@ Update:
1. `project.godot` `config/version`.
2. `CHANGELOG.md` with a dated entry.
3. `README.md`, `PLAN.md`, `docs/architecture.md`,
`docs/development-status.md`, `TODO.md`/`DONE.md` and `MEMORY.md` as needed.
3. `README.md`, `PLAN.md`, `docs/project/architecture.md`,
`docs/project/development-status.md`, `TODO.md`/`DONE.md` and `MEMORY.md` as needed.
For a release candidate, use a prerelease version only if the project policy
allows it and never present it as the final release.
@@ -213,7 +213,7 @@ The default `RETAIN_RELEASES=0` never prunes.
### 7. Post-release record
Update `README.md`, `docs/development-status.md`, `MEMORY.md`, `CHANGELOG.md`,
Update `README.md`, `docs/project/development-status.md`, `MEMORY.md`, `CHANGELOG.md`,
`TODO.md`/`DONE.md` and the release page with the built/CI result. Commit the
release record and push. Record any skipped check and the reason; never leave a
tag with unreported missing verification.
@@ -93,7 +93,7 @@ python3 tools/screen_designs.py judge --model auto
```
Record model, confidence/verdict summary, `diff` count and any manual review.
`docs/ui-copy.md#screen-design-judge-report` is the durable record.
`docs/design/ui-copy.md#screen-design-judge-report` is the durable record.
## 6. Realism judge (when visual assets/lighting changed)
@@ -1,6 +1,6 @@
# Release Runbook
Authoritative source: `AGENTS.md` (Release Procedure), `docs/RELEASING.md`.
Authoritative source: `AGENTS.md` (Release Procedure), `docs/process/RELEASING.md`.
This runbook is the operational checklist; if it conflicts with those, they win.
## 0. Decide the release
@@ -29,8 +29,8 @@ Files to update:
| `project.godot` | `config/version="X.Y.Z"` |
| `CHANGELOG.md` | dated `## [X.Y.Z] — YYYY-MM-DD` entry |
| `README.md` | latest/current version and summary |
| `PLAN.md` / `docs/architecture.md` | current version reference |
| `docs/development-status.md` | shipped capability/release result |
| `PLAN.md` / `docs/project/architecture.md` | current version reference |
| `docs/project/development-status.md` | shipped capability/release result |
| `TODO.md` / `DONE.md` | close/move milestone when complete |
| `MEMORY.md` | release state and gotchas |
+28 -23
View File
@@ -15,15 +15,15 @@ The project should be developed in small, reviewable steps. Agents must keep pla
- `README.md` — Root-level documentation for the project. It should explain what the game is, how to work on it, how to run it, and where to find project information.
- `AGENTS.md` — This collaboration and agent workflow guide.
- `CHANGELOG.md` — The version history of user-facing changes. Keep an entry for each patch, minor, and major version.
- `docs/development-status.md` — The implemented-features list and what is not yet implemented. Update it whenever a feature lands, is renamed, or is removed.
- `docs/architecture.md` — The arc42-style architecture documentation (goals, constraints, building blocks, runtime views, decisions, risks).
- `docs/gameplay.md` — Gameplay systems, tutorial, venues and the escalation model.
- `docs/venues.md` — Real-site evidence, game mapping and venue simplifications.
- `docs/asset-tooling.md` — Asset pipelines, model tools, optional Blender MCP and screenshot gates.
- `docs/blender-assets.md` — Blender library operation and asset roles.
- `docs/npc-model-sourcing.md` — Character-source evaluation, licence rules and the character-development plan.
- `docs/getting-started.md` — Setup, run/test commands, and the controls table.
- `docs/release-qa.md` — The manual smoke checklist and balance-acceptance protocol.
- `docs/project/development-status.md` — The implemented-features list and what is not yet implemented. Update it whenever a feature lands, is renamed, or is removed.
- `docs/project/architecture.md` — The arc42-style architecture documentation (goals, constraints, building blocks, runtime views, decisions, risks).
- `docs/design/gameplay.md` — Gameplay systems, tutorial, venues and the escalation model.
- `docs/design/venues.md` — Real-site evidence, game mapping and venue simplifications.
- `docs/assets/asset-tooling.md` — Asset pipelines, model tools, optional Blender MCP and screenshot gates.
- `docs/assets/blender-assets.md` — Blender library operation and asset roles.
- `docs/assets/npc-model-sourcing.md` — Character-source evaluation, licence rules and the character-development plan.
- `docs/process/getting-started.md` — Setup, run/test commands, and the controls table.
- `docs/process/release-qa.md` — The manual smoke checklist and balance-acceptance protocol.
- `docs/adr/` — Architecture Decision Records.
## Priority and Versioning
@@ -90,22 +90,27 @@ specialists the task needs:
### Project rules that override a skill
1. **The project contract wins.** `npc_base` mesh node, the 13 required core bones at their rest
positions, five tint slots, front on Blender −Y / Godot +Z, grounded feet, 16,000
triangles / 16,000 glTF vertices per character, 1,500 per gear, 4,000 per prop. Optional
extra bones (fingers, face, toes) are allowed if they do not move the core rest positions. A skill
may recommend another topology, naming or budget scheme; do not adopt it unless the
change is explicitly planned and the contract, tests and docs are updated together.
1. **The project contract wins.** `npc_base` mesh node, five tint slots, front on Blender −Y /
Godot +Z, grounded feet, 24,000 triangles / 24,000 glTF vertices per character, 1,500 per
gear, 4,000 per prop. The shipped procedural library uses the 13 required core bones at their
rest positions; optional extra bones (fingers, face, toes) are allowed if they do not move the
core rest positions. The one documented exception is the accepted Quaternius runtime path
([ADR-0018](docs/adr/0018-quaternius-stage2-runtime-rig.md)): it keeps the 62-joint source rig
at runtime while the 0.9.9 face/silhouette gate is open, and it must still supply the five tint
slots, valid gear attach points and the same budgets. Both paths stay tested until that gate
closes. A skill may recommend another topology, naming or budget scheme; do not adopt it unless
the change is explicitly planned and the contract, tests and docs are updated together.
2. **Blender MCP is optional interactive tooling.** The headless flatpak scripts
(`tools/blender_assets.py`, `tools/npc_pipeline.py`) remain authoritative. MCP may be used
for local part exploration; setup and safety are in [`docs/asset-tooling.md#optional-interactive-blender-mcp`](docs/asset-tooling.md#optional-interactive-blender-mcp).
for local part exploration; setup and safety are in [`docs/assets/asset-tooling.md#optional-interactive-blender-mcp`](docs/assets/asset-tooling.md#optional-interactive-blender-mcp).
Never add an MCP dependency to the build, CI, tests or runtime, and always re-run the CLI
audit/fit gates on anything MCP touched.
3. **CI stays offline and skill-free.** Skills are local guidance only; every gate must still
work from a fresh checkout with committed `.glb`/`.png`/`.tres` files and Godot.
4. **No new asset source without the licence gate.** Skills may suggest reference packs or
generated meshes; ADR-0015 (CC0, or CC-BY with attribution in `CREDITS.md`) and the
provenance rules in `docs/npc-model-sourcing.md` still apply.
generated meshes; ADR-0017 (the CC0 Quaternius NPC base) supersedes the generator-first
decision in ADR-0015, and the CC0/CC-BY rule in ADR-0015 (attribution in `CREDITS.md`) plus
the provenance rules in `docs/assets/npc-model-sourcing.md` still apply to any new source.
5. **Evidence, not vibes.** After a skill-informed change, run `blender_assets.py inspect`,
`audit` and `fit` plus the relevant capture/smoke gates, and say in the handoff which
skills informed the change and what the measurements were.
@@ -191,7 +196,7 @@ first, then versioned milestones in version order, then future/deferred work.
level-3 section to `DONE.md`.
2. **Level-2 milestone/theme:** it is complete only when its direct checkboxes and **all** of its
level-3 workstreams are complete. Verify the whole milestone, record its capabilities in
`docs/development-status.md` when it represents shipped functionality, and write the matching
`docs/project/development-status.md` when it represents shipped functionality, and write the matching
`CHANGELOG.md` entry.
3. Move the **entire level-2 section**, including all level-3 headings and checklists, to
`DONE.md`. Remove it from `TODO.md` and add a completion date/note.
@@ -202,7 +207,7 @@ first, then versioned milestones in version order, then future/deferred work.
complete, or split the unfinished work into a new smaller level-2 milestone first.
When a completed milestone represents shipped functionality, also record the new capability in
`docs/development-status.md` so the implemented-features list stays accurate, and write a matching
`docs/project/development-status.md` so the implemented-features list stays accurate, and write a matching
entry in `CHANGELOG.md` (see "Maintain `CHANGELOG.md`" below).
### 4. Maintain `MEMORY.md`
@@ -212,7 +217,7 @@ Use `MEMORY.md` for information that should persist between sessions but does no
Record items such as:
- Important design and architecture decisions
- Notable implementation state and gotchas (the canonical implemented-features list lives in `docs/development-status.md`, not here)
- Notable implementation state and gotchas (the canonical implemented-features list lives in `docs/project/development-status.md`, not here)
- Known bugs and workarounds
- Commands needed to run, test, or build the project
- Decisions that future agents should not revisit unnecessarily
@@ -262,7 +267,7 @@ The root-level `README.md` is the project’s public-facing technical and projec
- Links to `PLAN.md`, `TODO.md`, `DONE.md`, `MEMORY.md`, and this file where appropriate
- Known limitations and contribution guidance
Update `README.md` whenever setup instructions, commands, project structure, or user-facing behavior changes. The README is intentionally concise and links to the `docs/` files; keep `docs/development-status.md` (and the other docs it links to) synchronized with the implementation rather than pasting detail back into the README.
Update `README.md` whenever setup instructions, commands, project structure, or user-facing behavior changes. The README is intentionally concise and links to the `docs/` files; keep `docs/project/development-status.md` (and the other docs it links to) synchronized with the implementation rather than pasting detail back into the README.
### 7. Maintain `CHANGELOG.md`
@@ -292,7 +297,7 @@ For each task:
2. Inspect the relevant files and dependencies.
3. Make the smallest coherent change that completes the task.
4. Run the relevant tests, checks, or manual verification.
5. Update documentation if the change creates lasting context: add features to `docs/development-status.md`, adjust the README links or other `docs/` files as needed, and record decisions/gotchas in `MEMORY.md`.
5. Update documentation if the change creates lasting context: add features to `docs/project/development-status.md`, adjust the README links or other `docs/` files as needed, and record decisions/gotchas in `MEMORY.md`.
6. Mark the task complete.
7. Keep completed level-3 workstreams in place until the parent milestone is complete; then move the entire level-2 milestone to `DONE.md` after recording its `CHANGELOG.md` entry.
8. Commit each coherent, verified change as it is completed. Do not wait until a whole
+68
View File
@@ -4,6 +4,74 @@ All notable user-facing changes to Gig Line. The format follows
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and versions use
Semantic Versioning.
## [Unreleased]
### Fixed
- The red event banners are lit from the top down at night instead of reading as flat red cards.
- Hollywood and the TV Studio got the same queue treatment, and the TV Studio's props no longer sit
in the entrance steps.
- The Joke Shop has a readable queue: a velvet rope line leading to the check-in podium, a thicker
bike-rack barricade on the curb side, and a planter no longer clipping the palm foliage.
- Street lamps now throw a warm pool on the pavement instead of dimly washing the whole walkway.
- The flashlight actually lights what it points at. It was tuned to a beam so weak it changed the
frame by less than one 255th of a level; it now throws a visible pool on the door and the pavement
ahead, in both venues.
### Changed
- Street greenery now reads as leaves instead of green rocks: the planter shrubs and tree crowns
are built from leaf cards, which also cut their triangle count by about a third.
### Changed
- Removed every hat and hood from the NPC roster: the firefighter helmet is the only head gear
left, so no character hides its face behind a cap. The street performer no longer wears the
cone hat and carries the baton and board in the hands instead.
- Hands, head gear and carried items were re-fitted to the new characters: hand items sit in the
palm instead of floating at the wrist, the lanyard moved up to the sternum, back gear moved up to
shoulder-blade height, and the clipboard is carried by its top edge.
- NPCs now wear eleven different outfits instead of three: the modular outfit pack brought a formal
suit for the influencer, a punk jacket and mohawk, beach wear, farmer overalls and straw hat, an
adventurer jacket, a second casual jersey, and royal armour with a gold crown for the street
performer.
- NPCs no longer all share one hairstyle: the roster now uses short, buzz and long hair silhouettes
instead of a single shell in twelve colours.
- Eyes now have whites and pupils instead of flat dark rectangles.
- Every NPC now has a visible mouth; the Quaternius heads shipped without one, so the faces read as
brow-and-eye masks.
- Fixed the modular Worker characters: the guard, delivery, firefighter and crowd roles had holes
in the torso and an open crown, a continuous unibrow and no visible eyes. They now have a closed
torso, hair, two eyebrows and two eyes.
## [0.9.9] — 2026-11-06
### Changed
- Raised the character mesh budget from 16,000 to 24,000 triangles and glTF
vertices so the Quaternius base and the role-dressed variants fit without
heavy decimation. Gear and prop budgets are unchanged.
- Replaced the whole NPC roster with the CC0 Quaternius characters. All twelve
characters (tourist, jacket, coat, vest, dress, hoodie, firefighter, guard and
the four crowd variants) now use one of three source outfits — casual tee,
hoodie or work clothes — dressed by role with the five tint slots and the gear
library. The procedural library and the MakeHuman head remain in the build as
the fallback.
- Characters stand with their arms down instead of a T/A pose, and the seated,
idle and walking poses swing from the shoulder and hip the way the animation
code intends on the new skeleton.
- Head gear (cap, hood, sunglasses, firefighter helmet) and the camera were
resized for the new head and arm. The camera now hangs from a wrist strap
instead of a neck strap that floated next to the head.
- The backpack straps were pulled in so they sit on the chest instead of
hovering in front of it.
### Fixed
- Characters no longer render with black legs or black patches: the new base
carried a collapsed UV map that made the ambient-occlusion bake come out
black, and the roster is now unwrapped and baked correctly.
## [0.9.8] — 2026-11-04
### Fixed
+16 -6
View File
@@ -16,7 +16,7 @@ been cleared for public distribution.
## 3D characters, gear and props
The local MakeHuman head prototype uses the CC0 MakeHuman/MPFB base mesh
(see [`docs/makehuman-head-review.md`](docs/makehuman-head-review.md)); it is a
(see [`docs/assets/makehuman-head-review.md`](docs/assets/makehuman-head-review.md)); it is a
development prototype, not a shipped character.
The character, gear and prop library is generated by project-owned scripts
@@ -48,10 +48,20 @@ shipped derivative of CesiumMan or RiggedFigure must keep the attribution above.
The standalone MakeHuman head prototype is derived from the MakeHuman / MPFB base
mesh, **CC0** (`assets/models/blender_src/makehuman_head.glb`; source
`tmp/npc-research/makehuman/base.obj` with its bundled
`LICENSE.md`/`LICENSE.ASSETS.md`). It is cut, retopologised and re-weighted by
project scripts; the exported character GLBs remain project assets. See ADR-0015
and `docs/npc-model-sourcing.md`.
<https://static.makehumancommunity.org/makehuman.html>, MakeHuman base mesh,
CC0 1.0). It is cut, retopologised and re-weighted by project scripts; the exported
character GLBs remain project assets. The development source files were removed
from `tmp/` after the 2026-11-05 pivot to Quaternius. The head is retained as a
tested fallback, not the active NPC base. See ADR-0017 and
`docs/assets/npc-model-sourcing.md`.
### Quaternius NPC base source
The active NPC base migration uses **Quaternius Ultimate Modular Characters** and
**Ultimate Modular Women** (CC0 1.0, <https://quaternius.com/>). The three
researched GLBs are development inputs and are not shipped directly; the baked,
retargeted character GLBs are project assets. See ADR-0017 and
`docs/assets/npc-model-sourcing.md` for the decision, source hashes and rollout status.
The venue geometry is authored procedurally in `src/game/world_builder.gd` as a
stylized reconstruction. The Joke Shop is a fictional stand-in for the real
@@ -108,7 +118,7 @@ reference more directly, its attribution and licence must be added here.
All runtime audio is procedural (crowd bed, radio crackle and interface cues).
There are no external audio files, so there is no separate music/SFX licence to
clear. See `docs/accessibility.md` for caption and volume behaviour.
clear. See `docs/design/accessibility.md` for caption and volume behaviour.
## Third-party names
+188 -37
View File
@@ -137,7 +137,7 @@ Completed task sections moved from `TODO.md`. Sections are moved only when every
- [x] Commit `export_presets.cfg` with Linux, Windows, and macOS desktop presets.
- [x] Add `tools/build_releases.sh` for headless release exports.
- [x] Add `docs/RELEASING.md` with template installation, build, and Gitea release steps.
- [x] Add `docs/process/RELEASING.md` with template installation, build, and Gitea release steps.
- [x] Add a prominent **Downloads** section at the top of `README.md` linking to the release page.
- [x] Add `tools/publish_release.sh` (Gitea API release + asset upload, requires `GITEA_TOKEN`).
@@ -149,7 +149,7 @@ Completed task sections moved from `TODO.md`. Sections are moved only when every
- [x] Tag builds automatically publish the Gitea release via `tools/publish_release.sh` using
the `GITEA_TOKEN` secret.
- [x] Remove the old `.github/workflows/ci.yml` to avoid double runs on hosts scanning both paths.
- [x] Document the CI flow in `docs/RELEASING.md`.
- [x] Document the CI flow in `docs/process/RELEASING.md`.
## Gameplay — Venue selection
@@ -249,7 +249,7 @@ Completed task sections moved from `TODO.md`. Sections are moved only when every
service; ~2 min of retry timeouts per run; Godot import is fast without it).
- [x] Add `GODOT_SILENCE_ROOT_WARNING=1` to both jobs.
- [x] Confirmed in run 1090: zero `CacheService` lines, 54/54 tests pass, job succeeds.
- [x] Document the cache situation and re-enable path in `docs/RELEASING.md`.
- [x] Document the cache situation and re-enable path in `docs/process/RELEASING.md`.
- [x] Ignore runner logs in `.gitignore` (`.gitea/logs/`).
## Gameplay — Venue door-staff dialogue
@@ -660,7 +660,7 @@ produces a 63 MB static bundle and it serves locally with HTTP 200s for html/was
- [x] Publish the web zip with the desktop artifacts (`tools/publish_release.sh`).
- [x] Cover the preset, the non-threaded choice, and the release wiring in
`src/test/tests/test_web_export.gd`.
- [x] Document the artifact in `docs/RELEASING.md`, the README gallery/status, and `PLAN.md`.
- [x] Document the artifact in `docs/process/RELEASING.md`, the README gallery/status, and `PLAN.md`.
## Prop Texture Atlas
@@ -909,7 +909,7 @@ Goal: replace the outdated flat skyline backdrop (`assets/textures/skyline.png`,
with dot windows) and the flat-looking surface tiles with AI-generated, more realistic
backgrounds and textures. Add a larger set of example 3D scene images as art direction, and
measure the in-game result against that target with the screenshot tools. Plan:
[`PLAN.md` → Visual Quality Direction → Realism pass](PLAN.md#realism-pass).
[`PLAN.md` → Visual Quality Direction → Realism pass](PLAN.md#presentation-and-controls).
**Rule for every step: never overwrite an existing image.** New outputs get new paths. When a
path is taken, the tools pick the next free `-vN` suffix. Raw AI output stays on disk under
@@ -1047,7 +1047,7 @@ reports to `docs/screens/realism/<run>/`.
`docs/screens/realism/2026-11-01-adopt/` (3 judge repeats per shot) gives a like-for-like
improvement on every sub-score: overall 0.8→1.0, lighting 0.8→1.0, materials 0.8→1.0,
texture 0.8→1.0, backdrop 0.6→1.6, and the Pillow metric gap 0.444→0.348.
- [x] Update `README.md` (tool usage + gallery), `MEMORY.md` and `docs/architecture.md`.
- [x] Update `README.md` (tool usage + gallery), `MEMORY.md` and `docs/project/architecture.md`.
## Realism Follow-ups — Lighting, Flashlight, NPC Detail
@@ -1087,7 +1087,7 @@ Completed 2026-11-01. The follow-ups left over after the texture/skyline adoptio
bridge and tip, ears with lobes, and split upper/lower lips. Hands have four fingers plus a
thumb, and every sleeve ends in a cuff ring.
- [x] Raised `CHAR_MAX_VERTS` 4000 → **5000** (documented in the code and
`docs/blender-assets.md`) after measuring 16 avatars at ~6.9 ms of a 50 ms frame on a single
`docs/assets/blender-assets.md`) after measuring 16 avatars at ~6.9 ms of a 50 ms frame on a single
skinned mesh, so `npc_coat` fits at 4807 vertices; the character range is now 3,974–5,026
triangles and 3,744–4,807 vertices. Body decimation 0.36 → 0.26.
- [x] Rebuilt all 8 variants and re-baked their AO maps (`assets/models/blender/npc/*_ao.png`),
@@ -1114,14 +1114,14 @@ Completed 2026-11-01.
- [x] Decide the canonical runtime image root (`assets/images/` for UI/scene art): recorded in
`MEMORY.md` and [ADR-0014](docs/adr/0014-runtime-image-root.md).
- [x] Move the reference mockups from `docs/screens/designs/` into the runtime root (keep `docs/screens/designs/` as a docs-only copy or replace it with the new path).
- [x] Document one convention for game vs reference vs development images across `assets/textures/`, `assets/images/`, `assets/models/generated/`, `docs/screenshots/`, and `docs/screens/designs/` (in `docs/architecture.md`, ADR-0014).
- [x] Document one convention for game vs reference vs development images across `assets/textures/`, `assets/images/`, `assets/models/generated/`, `docs/screenshots/`, and `docs/screens/designs/` (in `docs/project/architecture.md`, ADR-0014).
- [x] Re-run `godot --headless --path . --import` to regenerate `.import` sidecars after any move.
- [x] Confirm `.gitignore` still excludes development-only outputs (concepts, Blender sources, raw AI fabrics) under the new layout; Blender `.blend` sources are now untracked and ignored.
### Documentation path updates
- [x] Update `README.md` paths (screen-designs section, confirmed-assets links, the `assets/images/scenes` resize example).
- [x] Update `docs/architecture.md`, `PLAN.md`, and ADR references: docs/screens/designs/ is now explicitly the reference-only snapshot; runtime art lives in assets/images/ (ADR-0014).
- [x] Update `docs/project/architecture.md`, `PLAN.md`, and ADR references: docs/screens/designs/ is now explicitly the reference-only snapshot; runtime art lives in assets/images/ (ADR-0014).
- [x] Update `tools/screen_designs.py` docstrings and mark the old paths in `DONE.md` as historical.
### Code path updates
@@ -1188,7 +1188,7 @@ architecture's version, runtime-art loader, asset/tooling blocks, Gitea CI/build
Web deployment and release artifact list were brought up to date. `MEMORY.md` was cleaned of
obsolete uncommitted/active-pass claims and now points at the current follow-ups.
- [x] Re-check `PLAN.md`/`MEMORY.md` against the current build, update `README.md` and `docs/architecture.md`, and compact the historical PLAN sections.
- [x] Re-check `PLAN.md`/`MEMORY.md` against the current build, update `README.md` and `docs/project/architecture.md`, and compact the historical PLAN sections.
## NPC gear fit (v0.6.1)
@@ -1197,7 +1197,7 @@ Completed 2026-11-01. Eyes, bag and helmet now fit the measured body silhouette;
The 2026-11-01 detail pass fixed the bodies but not the props worn on them. In the portrait
capture (`--stages=day,portrait`, see the report in `docs/screens/realism/2026-11-01-npc/`) the
sunglasses span the whole upper face and the shoulder bag cuts through `npc_coat`'s skirt. Blender sources for gear
live in `tools/blender_assets.py` (`_build_gear()`), the contract in `docs/blender-assets.md`
live in `tools/blender_assets.py` (`_build_gear()`), the contract in `docs/assets/blender-assets.md`
(gear budget 1500 tris, `GEAR_ATTACH` points in `NpcAvatar`).
- [x] Measure the fit in Blender, not by eye: `python3 tools/blender_assets.py fit` prints each
@@ -1270,7 +1270,7 @@ have no stage in the committed `docs/screenshots/` gallery, only in `capture_rea
`src/test/capture_screenshots.gd` (`12-joke-shop.png`, `13-studio-arrival.png`) reuse the
existing `joke_shop_queue` / `studio_arrival` designs. `check_screenshots.sh` is **13 good /
0 bad**; the new screenshots are 18.2 / 32.6 MAE against their references.
- [-] Update `docs/architecture.md` (venue geometry), `README.md` (gallery) and the screenshot
- [-] Update `docs/project/architecture.md` (venue geometry), `README.md` (gallery) and the screenshot
table when the stages land.
## Forward+ desktop preset and a volumetric flashlight (v0.7.1)
@@ -1296,7 +1296,7 @@ path.
dirs) and record the diff in `docs/screens/realism/2026-11-01-forward-plus/`: entrance
metric gap 1.568 → 1.187, two-shot mean 0.907 → 0.723. Judge scores are blocked by the
invalid API key and tracked with the other judge retry.
- [x] Add the preset to `tools/build_releases.sh` and `docs/RELEASING.md` as an optional
- [x] Add the preset to `tools/build_releases.sh` and `docs/process/RELEASING.md` as an optional
"desktop HQ" artifact, and note the runtime requirement (Vulkan driver) in `README.md`.
`gig-line-desktop-hq-<version>.zip` packages the Linux/Windows binaries, override.cfg and
README; `publish_release.sh` uploads it when present.
@@ -1327,7 +1327,7 @@ back when a provider rejects a request.
- [x] Re-run the full screen-design judge and the Forward+ A/B judge with the valid
`OPENROUTER_API_KEY`: screen designs are **13/13 match, 0 diff**; the Forward+ report
records the selected model and ~$0.006 spend.
- [x] Update `docs/asset-tooling.md`, `MEMORY.md`, `README.md` and `CHANGELOG.md`; the
- [x] Update `docs/assets/asset-tooling.md`, `MEMORY.md`, `README.md` and `CHANGELOG.md`; the
public catalogue picks the cheapest image+JSON model (`z-ai/glm-5.3-flash` at run time).
## Milestone 0.8.0 — First hour and content depth
@@ -1343,7 +1343,7 @@ venues, and see enough authored variety that a second shift does not feel like a
- [x] Write the tutorial beat sheet: menu → movement/look → focus and target cycling → action
wheel → access inspection → polite direction → formal warning/body camera → radio →
shift review. Eight beats and a safe compliant visitor are specified in
[`docs/gameplay.md#first-shift-tutorial`](docs/gameplay.md#first-shift-tutorial).
[`docs/design/gameplay.md#first-shift-tutorial`](docs/design/gameplay.md#first-shift-tutorial).
- [x] Add a tutorial state machine independent of the normal shift FSM. `Tutorial` in
`src/game/tutorial.gd` owns the eight beats, accepts only the current beat's action,
supports skip/restart and has deterministic headless tests. GameManager/UI wiring starts
@@ -1544,7 +1544,7 @@ and supported by a stable CI/release baseline.
- [x] Existing scenario-content, tutorial and campaign smokes cover the venue/action/review paths;
the 0.9.5 release candidate adds the external first-hour pass.
- [x] `docs/getting-started.md` and `docs/release-qa.md#manual-smoke-checklist` list tutorial, campaign/checkpoint,
- [x] `docs/process/getting-started.md` and `docs/process/release-qa.md#manual-smoke-checklist` list tutorial, campaign/checkpoint,
session, scenario, audio, crowd, emergency, movement and performance smokes.
- [x] Current gallery/judge baselines are green; the 0.9.5 release candidate refreshes the final
gallery after content lock.
@@ -1560,7 +1560,7 @@ and supported by a stable CI/release baseline.
smoke requirement. This explicit matrix is documented.
- [x] No project-wide upgrade in 0.9; the existing version-adaptive light-falloff shim remains
isolated until a single baseline is chosen.
- [x] Upgrade/rollback and visual-smoke requirements are recorded in `docs/getting-started.md`
- [x] Upgrade/rollback and visual-smoke requirements are recorded in `docs/process/getting-started.md`
and `MEMORY.md`.
- [ ] Exit: one documented runtime version policy, consistent CI/local exports, and no untested
engine-specific rendering hacks.
@@ -1589,7 +1589,7 @@ Goal: streamline the maps, refactor geometry to match the images in `docs/screen
- [x] Remove unnecessary or hidden geometry to improve performance.
- [x] Ensure texture and material consistency across the map.
Completed: the Hollywood venue is rebuilt from the real 6840 Hollywood Blvd references (six-column Masonic/El Capitan facade, eight steps, neighbours, Ovation arcade, Walk of Fame, four-lane street). The map-budget test measures 58,884 triangles across 409 meshes; Day/Night menu variants start in `EARLY`/`LATE`; the realism judge gaps are 0.148 (day) and 0.278 (late). See `docs/venues.md#hollywood-boulevard`.
Completed: the Hollywood venue is rebuilt from the real 6840 Hollywood Blvd references (six-column Masonic/El Capitan facade, eight steps, neighbours, Ovation arcade, Walk of Fame, four-lane street). The map-budget test measures 58,884 triangles across 409 meshes; Day/Night menu variants start in `EARLY`/`LATE`; the realism judge gaps are 0.148 (day) and 0.278 (late). See `docs/design/venues.md#hollywood-boulevard`.
### Map 2 — Joke Shop
@@ -1601,7 +1601,7 @@ Completed: the Hollywood venue is rebuilt from the real 6840 Hollywood Blvd refe
- [x] Remove unnecessary or hidden geometry to improve performance.
- [x] Ensure texture and material consistency across the map.
Completed 2026-11-02: the Joke Shop is rebuilt from the real Comedy Store block at 8433 Sunset Blvd (27 m black hall, signature canopy, circular blade sign, red curtains, west entrance, low-rise neighbours, dry hillside and opposite frontage). The map-budget test measures 22,680 triangles across 454 meshes. The day/late captures and real-site notes are in `docs/venues.md#the-joke-shop` and `docs/screens/concepts/joke_shop/`; the final gallery passed 13 good / 0 bad and the screen-design judge (13/13 match, 0 diff), with a 0.454 realism gap on the photoreal night reference.
Completed 2026-11-02: the Joke Shop is rebuilt from the real Comedy Store block at 8433 Sunset Blvd (27 m black hall, signature canopy, circular blade sign, red curtains, west entrance, low-rise neighbours, dry hillside and opposite frontage). The map-budget test measures 22,680 triangles across 454 meshes. The day/late captures and real-site notes are in `docs/design/venues.md#the-joke-shop` and `docs/screens/concepts/joke_shop/`; the final gallery passed 13 good / 0 bad and the screen-design judge (13/13 match, 0 diff), with a 0.454 realism gap on the photoreal night reference.
### Scenery Change (Day/Night) for Hollywood Boulevard
@@ -1646,7 +1646,7 @@ redesign.
- [x] Do not run the release build, bump a release version or tag until the map exit criteria and
this NPC revisit are both signed off.
- [x] Record the sign-off in `docs/development-status.md` and `MEMORY.md`, then hand off to the
- [x] Record the sign-off in `docs/project/development-status.md` and `MEMORY.md`, then hand off to the
postponed integration/build milestone.
**Exit:** the final maps and lighting still present the NPCs clearly; no untriaged NPC regression
@@ -1663,20 +1663,20 @@ screen-design judge before any model/texture changes. No gameplay rules change.
- [x] Inventory every screen/panel: start menu, venue menu, tutorial, HUD, pause,
settings, Help, inspection, wand, radio/emergency, wheel, shift review,
timeline and campaign/continue screens. Recorded in `docs/ui-copy.md`.
timeline and campaign/continue screens. Recorded in `docs/design/ui-copy.md`.
- [x] Record the canonical terms for admit/refuse, warning/blocking,
assistance/emergency, body camera, shift review and campaign; the current
inspection/wand/radio/review labels use them (see `docs/ui-copy.md`).
inspection/wand/radio/review labels use them (see `docs/design/ui-copy.md`).
- [x] Audit all button labels for verb-first wording, capitalization, ordering,
destructive-action confirmation and consistent confirm/cancel placement;
recorded in `docs/ui-copy.md` and fixed Quit/Apply wording.
recorded in `docs/design/ui-copy.md` and fixed Quit/Apply wording.
- [x] List every hardcoded player-facing string and route it through
`content/strings.en.json`; remaining UI literals are numeric/debug-only or
dynamic data. Placeholder validation covers the new keys.
- [x] Review NPC/door-staff/radio/tutorial/help/review/campaign dialogue for
repetition, ambiguity, tone and localization length. (Reason contexts,
door-staff lines, radio/tutorial/help copy and length findings recorded in
`docs/ui-copy.md`; longest dialogue line is 56 characters.)
`docs/design/ui-copy.md`; longest dialogue line is 56 characters.)
### Button and panel behavior
@@ -1684,15 +1684,15 @@ screen-design judge before any model/texture changes. No gameplay rules change.
tutorial skip, venue continue, settings apply/cancel/reset, judge/review,
radio send/emergency hold and Help close. (Shared `UiStyles` states applied;
timeline boundary disabling and the keyboard-only F1 skip are documented in
`docs/ui-copy.md`.)
`docs/design/ui-copy.md`.)
- [x] Verify keyboard-only and gamepad-only navigation: focus order, wrapping,
default focus, confirm/cancel behavior and no focus traps. (Focus rings,
gamepad A/B UI bindings, default focus and per-modal cancel behavior are
recorded in `docs/ui-copy.md`.)
recorded in `docs/design/ui-copy.md`.)
- [x] Verify every modal closes with Esc/right-click where documented, recaptures
the mouse, and does not leave the guard frozen or the menu visible. (Single
top-modal close path, menu/settings return handling and pointer recapture are
recorded in `docs/ui-copy.md`; session smoke covers menu Settings, Help
recorded in `docs/design/ui-copy.md`; session smoke covers menu Settings, Help
right-click and pause Settings.)
- [x] Test buttons at minimum/maximum HUD font scale and with 1.5–2× longer
strings; fix clipping, overflow and overlapping layouts. (Target chip now
@@ -1720,9 +1720,9 @@ screen-design judge before any model/texture changes. No gameplay rules change.
- [x] Ran `tools/check_screenshots.sh` and `screen_designs.py compare`: 21 good,
0 bad.
- [x] Ran the judge with automatic model selection: 21/21 match, 0 review, 0 diff.
- [x] Recorded the judge model and result in `docs/ui-copy.md#screen-design-judge-report`; the
- [x] Recorded the judge model and result in `docs/design/ui-copy.md#screen-design-judge-report`; the
generated captures remain local/gitignored.
- [x] Add a short UI copy/button checklist to `docs/release-qa.md#manual-smoke-checklist`.
- [x] Add a short UI copy/button checklist to `docs/process/release-qa.md#manual-smoke-checklist`.
- [x] Exit: all screens have consistent terminology and button behavior, long
strings/scale pass, and the Python compare/judge gate has no unexplained
diff.
@@ -1742,10 +1742,10 @@ fallback behavior.
produces 48 frames; `sheet_npc_baseline.jpg` is committed.)
- [x] Define acceptance criteria for proportions, face readability, hair, hands, shoes, clothing
silhouette, gear fit and animation at the gameplay camera height (1.7 m). (Eight criteria
in `docs/npc-visual-review.md`; the current 8,000-triangle/8,000-vertex library contract is explicit; the `npc_base` fallback remains 6,000/4,000.)
in the review evidence (since retired with the 0.9.9 roster pages); the current 8,000-triangle/8,000-vertex library contract is explicit; the `npc_base` fallback remains 6,000/4,000.)
- [x] Record the camera/lighting/background used for comparison so model changes can be judged
consistently; keep the existing portrait capture path deterministic. (Neutral studio, fixed
orbit cameras, no HUD/crowd/animation; commands recorded in `docs/npc-visual-review.md`.)
orbit cameras, no HUD/crowd/animation; commands recorded in the retired review evidence.)
- [x] Identify the highest-impact gaps from the current portraits (e.g. face depth, hair mass,
neck/shoulder transition, hand/foot shape, coat/dress hem) and rank them by player visibility.
(P1: tourist duplicate bag, face depth, backpack straps; P2: hands/grips, clothing tiling,
@@ -1755,7 +1755,7 @@ fallback behavior.
the side-by-side after sheet without overwriting it.)
Completed 2026-11-02: 48-frame neutral studio baseline, eight criteria, current fit and
triangle/vertex measurements, and ranked P1/P2 gaps are in `docs/npc-visual-review.md`. The
triangle/vertex measurements, and ranked P1/P2 gaps are in `docs/assets/3d-model-review.md`. The
baseline itself changed no character models; the first P1 gear fixes are recorded under Gear
and equipment fit.
@@ -1768,7 +1768,7 @@ and equipment fit.
- [x] Audit all variants against a shared human proportion guide (head height, shoulder width,
torso length, hip width, limb length, foot length) and correct the worst outliers.
(`tools/npc_proportions.py` + `docs/npc-visual-review.md#proportion-audit`: all eight pass; no skeleton or
(`tools/npc_proportions.py` + `docs/assets/3d-model-review.md#character-measurements`: all eight pass; no skeleton or
mesh rescue was needed. Head and broad-build silhouettes are nearest their upper bounds.)
- [x] Improve the neck and shoulder transition so the silhouette reads as one body rather than a
thin post on a hanger. (Fuller neck base/top, lower shoulder root, degenerate-face cleanup;
@@ -1857,7 +1857,7 @@ and equipment fit.
`blender_assets.py audit`, `fit`, character imports and the full Godot test suite.
- [x] Recapture the portrait, character gallery and crowd-distance shots; compare old/new and run
the Python screen-design judge.
- [x] Update `docs/blender-assets.md`, architecture/status, `MEMORY.md` and the changelog with the
- [x] Update `docs/assets/blender-assets.md`, architecture/status, `MEMORY.md` and the changelog with the
new budgets, limitations and rebuild commands.
- [x] Exit: all eight variants pass the portrait/readability criteria, gear and hems no longer
clip in normal play, the 24-NPC budget remains green, and the visual judge has no unexplained
@@ -2007,7 +2007,7 @@ target paths and leave a clean release-candidate handoff.
final patch-level results and any remaining gaps. (README/PLAN/architecture
now point at 0.9.6; the changelog and development status record the
integration build, performance numbers, judge results and the clean-worktree
export rule; `docs/RELEASING.md` documents the ignored-folder trap.)
export rule; `docs/process/RELEASING.md` documents the ignored-folder trap.)
- [x] Tag/version or otherwise freeze `0.9.6` as the integration checkpoint before
the `0.10.0` release candidate. (Tag `v0.9.6` on `4bb2896`; Gitea run 1296
passed checks and the full build and published seven assets.)
@@ -2050,7 +2050,7 @@ must inherit the reviewed face/hand/gear baseline instead of multiplying whateve
the existing Blender contract. (Measured Quaternius CC0, Kenney CC0, Khronos
CesiumMan/RiggedFigure CC-BY and the MakeHuman CC0 base mesh; none is a drop-in.
Results, local preview sheet and SHA-256 provenance are in
`docs/npc-model-sourcing.md`.)
`docs/assets/npc-model-sourcing.md`.)
- [x] Review the sourcing research with the project owner and choose Option A (procedural),
Option B (Quaternius CC0 intake) or Option C (MakeHuman/MPFB body pipeline); record the
decision in an ADR and in `MEMORY.md`. (2026-11-03: extend the procedural generator as the
@@ -2127,7 +2127,7 @@ must inherit the reviewed face/hand/gear baseline instead of multiplying whateve
- [x] Gates with the expanded library: 24-NPC budget smoke 152,464 tris / 168 meshes / 6.94 ms
(under 50 ms), portrait baseline 12 variants × 6 views, `fit` clean, Godot 277/277, Python
160/160. No release build is created for this unversioned track.
- [x] Docs: `docs/development-status.md`, `docs/3d-model-review.md` and the baseline sheet updated;
- [x] Docs: `docs/project/development-status.md`, `docs/assets/3d-model-review.md` and the baseline sheet updated;
`CREDITS.md` needs no change (the crowd variants are procedural, no new source). Accepted
visual limits: the crowd accessories (umbrella canopy, cup, sunglasses, beard) read at
full-body distance but not in the head-only portrait framing.
@@ -2143,3 +2143,154 @@ must inherit the reviewed face/hand/gear baseline instead of multiplying whateve
project-owned clothing; keep out of CI/build.)
- [x] Body-shape diversity decision (2026-11-04, owner): **yes** — use MakeHuman for the next
character pass. Promoted to the **MakeHuman character pipeline** track.
## NPC pose harness (v0.9.8)
Completed 2026-11-04. The pose harness bug that made every staged capture save a rest frame
was found and fixed; it unblocked the weights/pose evidence and the seated/walking deformation
fixes. User-facing changes are recorded under 0.9.7 and 0.9.8 in `CHANGELOG.md`.
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; the evidence now feeds the Quaternius base bake.
*Skill route: `rigging`; evidence in `docs/assets/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.)
## Milestone 0.9.7 — Character development (patch)
Completed 2026-11-04 and published as v0.9.7. The detailed character-development record already
lives under "Character development" above; this milestone checklist is kept verbatim for the
release record.
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 Quaternius NPC base and the map rebuild are
not in this patch (they target 0.10.0).
## Milestone 0.9.9 — Quaternius NPC base swap (patch)
Goal: make one Quaternius-derived NPC render and animate correctly in Godot and ship it as the
pilot base, with the procedural library still selectable as the fallback. This is the first
versioned character milestone; it contains the rig correction that has been blocking the
ADR-0018 rollout.
**Why this is a patch:** it changes character presentation and animation quality but adds no new
player-facing system. The 0.10.0 minor is reserved for the release gates (see below), so a
blocked rig can no longer block the whole release.
**Completed 2026-11-06.** Shipped as `v0.9.9` (tagged, local release build with checksums)
and accepted by the owner after the follow-up fixes. Durable evidence: `docs/assets/3d-model-review.md`,
`docs/assets/blender-assets.md`, `docs/adr/0018-quaternius-stage2-runtime-rig.md`.
### Rig and export correction
- [x] Reproduce and record the failure: the `armature_apply` + `export_apply=True` bake wrote
wrong inverse bind matrices (Godot rendered A-pose while the rest was arm-down). Recorded
in `MEMORY.md`; `bake_armdown_clean.py` was the failing recipe.
- [x] Fix the arm-down bake so the exported skin matches the rest. `tmp/npc-research/bake_armdown_v2.py`
(pose-rotate → apply modifier → reset pose → edit-mode rotate arms → re-add modifier →
export `export_apply=False`) now yields a correct arm-down base: Blender deformed x ±0.221
and the rest bone tail points down. Still local (`tmp/`), not shipped.
- [x] Re-derive the pose composition for a non-180° rest. Superseded by the rig-agnostic
`_swing_bone()` below: the rest-relative `set_bone_pose_rotation` form was never exact,
because `get_bone_rest()` is parent-relative and already carries the importer's axis
conversion. Kept in `MEMORY.md` as a rejected approach.
- [x] Fix the skinning/rest bake end to end (commit `cd285b3`):
(1) the canonical base is **join-only** (`tmp/npc-research/build_base_minimal.py`: no
`remove_doubles` weld, no scale/ground transform, keep the Armature modifiers) — the weld
and the transform corrupted the Quaternius weights;
(2) the arm-down bake (`tmp/npc-research/bake_armdown_v5.py` — pose, read pose matrices,
apply modifier, **reset pose to identity**, set rest matrices, re-add modifier) bakes the
rest correctly (DEFORMED x −0.228/0.228, Godot bind pose arm-down);
(3) `NpcAvatar._swing_bone()` now writes the **global** bone pose from
`get_bone_global_rest()`, so one formula drives both the 62-joint Quaternius rig and the
13-core fallback (measured: posed bone axis matches the proxy pivot at dot 1.000 on the
Quaternius, and the procedural rigs are unchanged);
(4) `RIG_BONES` + `NpcAvatar.bone_name()` hold the only side mapping (the Quaternius labels
`L`/`R` opposite the project), and the hand proxy is `global_wrist − global_elbow`.
Verified in Godot: idle/sit/walk captures on npc_casual plus the unchanged procedural rigs.
- [x] Add regression tests: `test_shipped_rig_resolves_the_animation_joints` covers the joint map,
the baked arm-down rest, the down-pointing arm axis and the proxy side mapping; the Blender
audit/`inspect` and `npc_proportions` now understand both rigs. Godot 278/278, Python
167/167.
- [x] Give the Quaternius base the five tint slots: `build_base_minimal.py` renames the upstream
materials to `skin`/`cloth`/`pants`/`hair`/`accessory` and keeps `Eye`/`Eyebrows` as
fixed-colour detail. The source UV map is degenerate (every loop at 0,0), so the build now
Smart-UV-unwraps and repacks the layout — texel density went from an unmeasurable 0 to
73–74 px/m on the 256² maps and the 256² AO bake works again.
- [x] Idle and Walk verified on the 62-joint rig through the pose code, not the clips: the 24
upstream clips stay authoring reference only, because `_animate()` + `_sync_skeleton()`
already drive sitting, hand-raising and head turns, and playing clips would replace that
state machine rather than supplement it. Recorded in ADR-0018 and `MEMORY.md`.
- [x] Poses the clips do not cover are driven by the same proxy pivots (`_legs`, `_knees`,
`_arms`, `_elbows`, `_head`), which is why no clip retarget was needed.
- [x] Fallback stays tested: `_build_body()` still builds the 13-core rig, and
`test_forced_fallback_still_builds_the_procedural_rig` now asserts the hip swings and a hand
pivot exists on that path. No MPFB or Stage-1 proportion work reopened.
- [x] Backpack straps re-fitted for the Quaternius torso (`fb3e75a`) and the back attach raised to
shoulder-blade height; the camera kept its wrist strap.
### Silhouette and face gate (owner)
- [x] Re-run the silhouette gate at gameplay distance and in portrait against the current
`npc_casual`, front / three-quarter / profile. ADR-0018 removed the proportion warp, so
source proportions are accepted by definition (head 13.4 % of height, measured by
`npc_proportions`).
- [x] Owner visual signoff obtained (2026-11-06) on the roster, the faces, the head gear and the
hand/back gear. The review page and its sheets were retired after acceptance; the measurements
live on in `docs/assets/3d-model-review.md` and `docs/assets/blender-assets.md`.
- [x] Face-fidelity comparison was made and the full swap chosen; the comparison sheets were
retired with the review pages, and the decision is recorded in the follow-up section of
[`docs/adr/0018-quaternius-stage2-runtime-rig.md`](docs/adr/0018-quaternius-stage2-runtime-rig.md).
- [x] **Owner decision:** option (a) full swap (2026-11-05). Applied: all twelve characters are
baked from the three Quaternius sources inside 24,000 tris / 24,000 glTF vertices
(`a6ccd86`), and the gate was re-run.
- [x] Record the decision and its consequence in `MEMORY.md`,
`docs/assets/npc-model-sourcing.md#shipped-roster-099-owner-chose-the-full-swap` and the
follow-up decision section of
[`docs/adr/0018-quaternius-stage2-runtime-rig.md`](docs/adr/0018-quaternius-stage2-runtime-rig.md).
- [x] Owner visual signoff on the shipped roster (2026-11-06): accepted.
### Pilot rollout
- [x] Map the five tint slots onto the Quaternius materials and unwrap the degenerate source
UV map; bake the 256² AO and check texel density (73–74 px/m).
- [x] Re-fit every gear attach point against the Quaternius skeleton and test each piece on the
character (the 0.9.10 *Prop and gear fit pass* below carries the measurements).
- [x] Wired the approved base into all twelve roles, with the procedural library as the instant
fallback; no runtime download or optional dependency.
- [x] Ran `inspect` (clean), `audit` (12/12), `fit` (OK), `npc_proportions` (measured), the 24-NPC
budget smoke (175,264 tris, 0.87 ms) and the capture gates before/after the fixes.
- [x] Released `0.9.9`: `config/version` 0.9.9, `CHANGELOG.md` entry, local build with checksums,
commit, tag `v0.9.9` and push. Owner accepted the roster on 2026-11-06.
**Exit:** one committed Quaternius GLB renders arm-down with correct skinning, plays Idle and
Walk on the 62-joint rig, poses correctly under the new composition, passes the owner face and
silhouette gate, fits the 18 gear pieces, stays inside budget, and ships as `0.9.9` with the
procedural library still available as a fallback.
+239 -93
View File
@@ -2,7 +2,7 @@
Session memory for durable decisions, gotchas, and commands. Implementation history lives in
`DONE.md`, user-facing changes in `CHANGELOG.md`, the live task list in `TODO.md`, and the
canonical implemented-features list in `docs/development-status.md`.
canonical implemented-features list in `docs/project/development-status.md`.
## Decisions
@@ -10,58 +10,11 @@ canonical implemented-features list in `docs/development-status.md`.
the licence gate. Downloads live in `tmp/research/` (gitignored): DDG image search, street-view
frames, neighbouring buildings — never committed, never shipped. Promotion into
`docs/screens/refs/` always passes the sidecar licence + privacy gate and `CREDITS.md`.
- **MakeHuman head accepted (2026-11-04, owner):** the basic human head is a pass.
`assets/models/blender_src/makehuman_head.glb` is the CC0 MakeHuman-derived head
(12,642 tris / 7,690 split verts). The automated vision gate still records REJECT on
the eye/lid region (globe depth, lid overlap, iris at three-quarter) as deferred
polish, not a blocker. The assembled path (`build_character(head="mh")`) adds a
skull-conforming hair cap derived from the closed head shell, hides the scalp under
that cap, and narrows the neck/shoulder body. Default head source stays `face` until
the owner reviews the hair/body and the 12-variant rollout starts.
- **AI-assisted asset review loop (2026-11-04):** head/face shape decisions use a concept +
judge loop — generate a target concept (`generate_textures.generate_image`, Seedream) and use
`tools/describe_image.py` as the vision judge, iterating on the mesh until the judge's specific
fixes converge. This is what picked the MakeHuman head over the procedural displacement head
(`_head_proto` oscillates between "decorated egg" and "spiky wedges" at ~3/5 on the coarse
sphere). Review page: `docs/screens/head-review/README.md`; methodology note:
`docs/3d-model-review.md` §AI-driven head rework.
- **MakeHuman hair/body prototype (2026-11-04):** `npc_casual --head mh` is
14,753 tris / 12,822 raw / 12,823 seam-split verts / 14 bones / 9 materials,
`inspect` clean. All 12 variants were counted at 14,693–15,987 tris. Hair uses flat
shading normals because the old hair normal map caused dark tangent patches on the
new cap. Scalp faces fully covered by the hair cap are deleted (saves ~950 tris);
the accepted face geometry is untouched. The procedural body was narrowed at the
neck/shoulders (shoulder root z 1.345, chest 0.158, neck 0.060/0.054) and its skin
decimate dropped to 0.21. The local renders are in
`tmp/npc-parts/prototype_mh/renders/`.
- **MPFB full-body prototype (2026-11-04):** the current body candidate is the local MPFB 2.0.18
pipeline at `tmp/npc-research/build_mpfb_npc.py` (dev-only; no `.mhclo` clothing installed).
It creates a macro-driven human, bakes targets, adds the `game_engine` rig, captures arm
points/weights, removes the rig, applies the helper MASK, scales to 1.81 m, retargets the A-pose
arms to the contract wrist, cuts the neck at 1.505, decimates, bisects the clothing boundaries,
paints the five slots, adds a short neck flare, project hands, rounded shoes and cuffs, the
accepted head and the 14-bone contract armature. Current output: **15,317 tris / 13,690 glTF
verts / 13,702 seam-split verts / 1.810 m / 14 bones / 10 materials**; `inspect` clean and feet
grounded. The torso is inflated radially by 12% through z 0.72–1.40 to loosen the shirt. The
neck is a radial cut of the decimated column bridged by a four-ring, 20-segment lathe (lower
rings painted cloth, reads as a crew neck); the ankles are hidden by a bevelled 0.11 m shoe
shell, an inset 0.111 × 0.286 m sole, a tongue and a 0.08 m pant cuff. Sleeve cuffs use the
`cloth` slot and the `accessory` slot is carried by the sole. A light smoothing pass on the
closed thigh/hip region softens the decimated silhouette. Earlier torus collar, cloth cylinder
collar, skin neck-blend sphere and destructive neck `smooth_vert` pass failed: the shells read as a
brace, shelf or donut, and vertex smoothing tore the open collar boundary into a dark hole. An
untucked shirt-hem band at the hips also failed: it read as a hanging white flap at the crotch.
Protruding flat sole plates read as skates/bricks and were replaced by an inset sole under a
rounded shell; laces were dropped for triangle budget. The neck skin rule needed a `z > 1.35`
guard: without it the `radius < 0.08` test painted skin at the crotch. Lowering the hem to
z 0.80 (unitard), tilting it up at the front (high-cut swimwear) and a 13% hem flare (peplum)
were all rejected; the remaining crotch V is the dark hollow under a body-painted shirt. A quick
open, flared solidified tube (0.150→0.196 m, z 1.05→0.80, 24 segments, ~288 tris) also failed:
it read as a hanging apron/tabard. The real fix is a shaped shirt shell with armholes and a
curved hem, not a tube. Remaining polish: crotch V, partly loosened shirt,
angular thigh facets. The prototype uses flat slot colours because the one-shot MPFB UV unwrap
does not match the per-slot NPC atlases. Renders:
`tmp/npc-parts/mpfb_proto/renders84/`; body-only: `body_only.glb`.
`tools/describe_image.py` as the vision judge, iterating until the judge's specific fixes
converge. Durable evidence: `docs/assets/3d-model-review.md` §AI-driven head rework; the
retired head-review page was removed in the 2026-11-06 docs restructure.
- **Project agent skills (2026-11-03):** two tracked skills live in `.agents/skills/`:
`gig-line-blender-asset-contract` and `gig-line-release-qa`. They are guidance only,
add no runtime dependency and are referenced from `tools/README.md`. The third-party
@@ -71,7 +24,7 @@ canonical implemented-features list in `docs/development-status.md`.
restaged for a late-night arrival. `VENUE_SPECS["tv_studio"]` is a 30.0 m variant of the 29.6 m
Hollywood facade. One reference board serves both venues; never create a separate TV Studio board.
- **Jimmy Kimmel Live = starting point:** the Hollywood first shift and the TV Studio arrival both
begin at the El Capitan block. Stated in `docs/venues.md#hollywood-boulevard` and `docs/gameplay.md`.
begin at the El Capitan block. Stated in `docs/design/venues.md#hollywood-boulevard` and `docs/design/gameplay.md`.
- **Street-view limitation:** Google Street View panoramas need a Google API key or manual browser
capture, so the local reference sets use DDG street-level photos instead.
- **Image-recitation filter:** Gemini image models reject well-known branded facades (Comedy Store
@@ -97,28 +50,48 @@ canonical implemented-features list in `docs/development-status.md`.
(94 skills + shared `references/`), gitignored, kept out of Godot's scanner by
`.agents/.gdignore`. Keep the pack flat when updating (`cp -a <pack>/.claude/skills/. ...`).
Pi gates project `.agents/skills` behind project trust.
- **NPC model sourcing (ADR-0015):** CC0 acceptable for shipped assets; CC-BY only with
attribution in `CREDITS.md`; no service assets with redistribution restrictions. The procedural
generator is the primary path. Quaternius and MakeHuman were evaluated as references only, not
shipped bases (Quaternius: 62-bone T-pose rig mismatch; MakeHuman: needs retopology + custom
rig + clothing).
- **Gaussian splatting (unversioned):** offline/development-only until an ADR proves licence,
privacy, Compatibility/Web cost and mesh collision. Accepted photo channels: team captures,
permissioned user/volunteer photos, clearly licensed downloads; every set needs a
provenance/consent sidecar. No runtime splat dependency in 0.10.0.
- **0.10.0 balance protocol:** `docs/release-qa.md#balance-acceptance` defines targets/denominators for the
- **0.10.0 balance protocol:** `docs/process/release-qa.md#balance-acceptance` defines targets/denominators for the
36 venue/difficulty/phase cells, seeds 1–100, and access/emergency error rates. Gotcha:
`_read_npc_truth()` is type-derived, not behaviour-derived; the emergency-fairness review must
account for that oracle mismatch.
- **Blender MCP is optional (2026-11-04):** setup and safe part workflow are in
`docs/asset-tooling.md#optional-interactive-blender-mcp`. The headless flatpak scripts remain authoritative; MCP is
`docs/assets/asset-tooling.md#optional-interactive-blender-mcp`. The headless flatpak scripts remain authoritative; MCP is
never a build/CI/test/runtime dependency, and anything MCP touched must pass the
CLI audit/fit gates.
- **Character mesh cap (2026-11-04):** all characters use 16,000 tris / 16,000 glTF vertices
- **Character mesh cap (2026-11-05):** all characters use 24,000 tris / 24,000 glTF vertices
(`CHAR_MAX_TRIS`/`CHAR_MAX_VERTS` in `tools/blender_assets.py`; `npc_pipeline.MAX_TRIANGLES`/
`MAX_VERTICES`). The required 13 core bones stay, optional extra bones are allowed, and the
low-poly `npc_base` fallback remains the shipped fallback. Measure the 24-NPC/Web budget after
low-poly `npc_base` fallback remains the shipped fallback. The raise funds the Quaternius base bake and
the 12-variant clothing detail. Measure the 24-NPC/Web budget after
any geometry change; never silently lower the cap without a new decision.
- **Quaternius is the NPC base (2026-11-05, owner):** ADR-0017 supersedes the generator-first
sourcing decision. The CC0 Quaternius Ultimate Modular character pack is the primary NPC mesh
and animation source. Stage 1 bakes a proportion-warped, 13-core-contract `npc_base` so
`NpcAvatar`, gear and animations keep working; the 62-joint/24-clip source rig is authoring
input, not a runtime dependency. If the warp fails the silhouette gate, Stage 2 needs a new ADR
for a 62-joint runtime, not a hybrid. The MakeHuman head and procedural `npc_base` remain
tested fallbacks until the Quaternius rollout ships. Quaternius source: CC0, attribution in
`CREDITS.md`; the three researched GLBs and licence notes are kept in
`tmp/npc-research/quaternius/`. MPFB/MakeHuman body work is closed; do not add new work there.
- **Quaternius bake keeps source detail (2026-11-05, owner):** during the contract bake (§2),
keep the Quaternius mesh as close to source as possible — no unnecessary decimation or LOD
reduction. The canonical base is only 3,199 verts / 6,206 tris, far under the 24,000 cap, so
there is no budget reason to decimate before the silhouette gate. Do not reuse the old
7,000-triangle or MPFB decimation targets.
- **Quaternius runtime rig (2026-11-05, owner, ADR-0018 option 2):** the Stage 1 proportion warp
failed the silhouette gate (arm ×1.63 / leg ×0.74 / torso ×1.61; vision judge: paddle hands,
lost forearms, stretched shins). The owner chose to **adopt the Quaternius 62-joint rig at
runtime** instead of warping: `NpcAvatar` maps the Quaternius joint names, gear attach points
are re-derived from the Quaternius skeleton (hip ≈0.87, shoulder ≈0.148/1.39, wrist ≈0.99,
knee ≈0.52) and the mesh keeps source LOD (arm-down rest pose baked). **The 24 upstream clips are
not played**: `_animate()` drives the proxies and `_sync_skeleton()` writes the bone poses, which
is what the FSM already needed for sitting, hand-raising and head turns. Playing the clips would
replace that state machine, not supplement it, so all 24 stay unused and the clips are authoring
reference only.
- **Engine baseline:** Godot 4.7.2 stable (official editor `~/.local/bin/godot`). The system's
`godot-runner` cannot load arbitrary project paths (compiled without path overrides); use the
official editor binary.
@@ -135,10 +108,129 @@ canonical implemented-features list in `docs/development-status.md`.
avatars. Head-turn offsets use `+basis.z` for the same reason.
- **Release blockers (still open):** macOS unsigned, AI image provider terms/commercial rights not
cleared, storefront/rating approval pending, external playtests and full hardware matrix pending.
Recorded in `CREDITS.md`, `PRIVACY.md`, `docs/accessibility.md`, `docs/known-limitations.md`.
Recorded in `CREDITS.md`, `PRIVACY.md`, `docs/design/accessibility.md`, `docs/design/known-limitations.md`.
- **Release roadmap (2026-11-05, owner):** `0.9.9` Quaternius pilot base (rig/export fix,
rest-relative pose math, owner face/silhouette gate), `0.9.10` 12-role roster, `0.9.11`
scheduled venue/prop/lighting polish, `0.9.12` performance/Web/accessibility verification,
`0.10.0` public-readiness minor, then `0.10.1`–`0.10.3` fixes, `0.11.0` replay + fourth venue +
localization foundation, `0.12.0` signed/storefront builds + save v2, `0.13.x` content complete
and release candidates, `1.0.0` stable. The full gap analysis and roadmap live in `PLAN.md`; the
character track is versioned now, so a blocked rig cannot block the release. Planning only —
none of these versions is built yet.
- **Quaternius face/readability gate (2026-11-05):** the base is 6.2k tris total and replaces a
library with a sculpted realistic face, so the 0.9.9 gate is a product decision, not just an
art check. Owner picks full swap / crowd-only / extra head detail. Do not lower character
fidelity silently.
- **Pose composition is rest-relative (resolved 2026-11-05):** see `_swing_bone()` in the gotchas —
the rest-relative `set_bone_pose_rotation` form was abandoned; the global-pose write replaced it.
- **Full roster swap (2026-11-05, owner):** at the `0.9.9` face gate the owner chose option (a),
full swap. All twelve public character names are baked from the three CC0 Quaternius sources
(`casual`, `hoodie`, `worker`); variety comes from the five tint slots, the outfit rules and the
gear library. The procedural library + MakeHuman head stay in the tree as the tested fallback
(`build --source procedural`), not in the shipped roster. Silhouette variety is the known
regression — three meshes for twelve roles — and the modular part library is the `0.9.10` fix.
- **Emissive materials can carry a per-material night energy.** `set_night_mode` used to write one
multiplier into every `_marquee_emissive` entry, which flattens any gradient. It now reads
`mat.get_meta("night_energy", 2.0)`, so a multi-strip panel can keep its top-to-bottom ratio
(the event banners: 2.6 → 1.4).
- **`placement_problems()` was only gated for the Joke Shop.** Its test validated one venue's prop
list, so the TV Studio carried six violations (props inside the steps/door exclusion and off the
sidewalk) unnoticed. `test_every_venue_placement_clears_the_sidewalk_and_the_approach` now runs the
validator on all three venues. When adding a venue or a prop, that test is the gate.
- **Venue lights must keep `omni_attenuation == 1.0`** — `test_world.test_venue_lights_use_physical_falloff`
enforces physical falloff on every Omni/Spot in all three venues, so a "pool" cannot come from
sharpening the curve. Use `omni_range` + energy instead: 10 m / energy 8 gives a brighter pool and
a darker gap than the old 16 m / 2.2.
- **Tune lights against a measurement, not a look (2026-11-06):** the shipped flashlight changed the
late-night frame by 0.1/255 and nobody noticed. `capture_realism.gd --stages=late --flashlight`
renders the same frame with the lamp on and off; mean luminance of the aimed region and the near
pavement is now the acceptance number. Current: energy 10, range 45 m, cone 24°, tilted 5° down →
13.5 → 29.7 aimed, 3.7 → 11.7 near ground.
- **Docs live in category folders (2026-11-06):** `docs/project/` (architecture, development status),
`docs/design/` (gameplay, venues, ui-copy, accessibility, known-limitations), `docs/assets/`
(asset tooling, blender assets, npc sourcing, 3d-model-review, makehuman head), `docs/process/`
(getting started, release QA, releasing), plus `docs/adr/`, `docs/screens/`, `docs/screenshots/`.
Write to the new paths; `docs/*.md` at the root no longer exists apart from `README.md`.
- **Foliage is leaf cards, not sphere stacks (2026-11-06):** `_shrub()` is one low-poly inner mass
plus 18–53 two-triangle cards scattered on the canopy shell by a jittered Fibonacci sequence, each
rotated onto the canopy normal and tilted off it. No alpha texture, so the flat-colour library and
the Compatibility renderer are unaffected — and it is ~35 % cheaper than the sphere stack it
replaced. If a shrub ever reads as a rock again, the cards were probably rotated to the normal
without the random tilt (`spread`).
- **Roster is eleven outfits over twelve roles (2026-11-06):** hoodie, Casual, Worker, Suit,
Adventurer, Beach, Casual_2, Farmer, King, Punk (Swat is intaken but unused — it faces Godot −Z and
every yaw attempt broke the skin: node rotation turns the skin with it, object rotation collapses
it, and data-space rotation after `transform_apply` still loses the head). Per-family slot maps
live in `QUATERNIUS_SOURCES`; a family
that cannot paint a slot (Farmer has no hair) gets `patch_slots`, which buries a 4 cm triangle so
the material survives the export and the contract holds.
- **FBX modular parts need five fixes before they are a base (2026-11-06):** (1) every FBX file
carries its own armature — keep one and repoint the meshes; (2) FBX adds `_end` leaf bones and a
`neutral_bone` root, and **Godot refuses the GLB entirely** (`resource_format_binary` / missing
`.scn`) until they are stripped to the 62 joints; (3) bake object transforms before export or the
glTF node transforms change the rest pose and the head renders several times too large;
(4) the pack reuses one fabric material for jacket and trousers — copy it per leg mesh
(`*_legs`) so the slot map can send it to `pants`; (5) imported parts share seams, so dissolve
and drop zero-area triangles or the audit fails.
- **`tmp/` needs a `.gdignore`.** Godot scans the project tree, so a downloaded asset pack under
`tmp/quaternius-intake/` gets imported (it flooded the import log and broke `--import` for the
rest of the project). An empty `tmp/.gdignore` stops it; capture output there is unaffected.
- **Modular part intake is a one-time manual download (2026-11-06, owner):** the upstream pack is a
Google Drive folder, so the owner downloads it once into the gitignored
`tmp/quaternius-intake/` and `tools/quaternius_parts.py` does the rest
(`inventory` → `extract` → `verify`). A part must be one skinned mesh on the 62-joint rig; a GLB
exported *without* an armature has no `JOINTS_0` and validates as bone-less, so `extract` keeps
the armature and `build` drops it again at join time.
- **Hair variety is built in-project (2026-11-06):** the upstream modular pack is a Google Drive
folder, so it cannot be fetched reproducibly; `QUATERNIUS_HAIR_PARTS` reshapes the one hair shell
each base ships (`short` identity, `buzz` squash, `long` stretch, `bald` removal) and the role's
existing `CHARACTERS[...]["hair"]` picks it. `bald` is restricted to bases whose skin closes the
skull. Outfit variety still needs the pack or new garments.
- **No hats except the firefighter helmet (2026-11-06, owner):** the iconography is not worth the
cost — a cap or hood on this head hides the face, and every hat needed a lift+scale hack to clear
the 0.228 m hair shell. `ACCESSORIES` maps no role to `cap`/`hood`, the guard/vest per-character
caps are gone, the performer cone was removed, and the primitive cap/hood fallbacks were deleted
with their `GEAR_OFFSETS`/`GEAR_SCALE` compensation. `firefighter_helmet` is the only head item.
Do not re-add head gear without an owner decision and a fit measurement.
- **Mouths are authored, not upstream (2026-11-06):** none of the three Quaternius heads has a mouth
material, so the faces read as brow-and-eye masks. `_add_quaternius_mouth()` places a small lip
block on the measured skin surface (front-most skin vertex in the 1.600–1.632 m band, ±35 mm of
centre) at 1.616 m. One rule covers all three bases; it runs before the slot map, so match the
material as `_base_name(m.name).lower() == "skin"`.
- **One character source, one fallback:** no new NPC source without an ADR. MPFB body work stays
closed, the Stage-1 proportion warp is not reopened, and the procedural `npc_base` + MakeHuman
head stay tested until the Quaternius base passes its gate.
## Gotchas / Known Issues
- **Blender material-list edits corrupt polygons silently.** Two separate bugs, same root:
`obj.data.materials.clear()` resets **every polygon to slot 0**, so the per-face indices must be
captured *before* the clear and reassigned after; and `IDMaterials.pop(index=)` repoints the
polygons that used the slot, which once painted a whole face with the eye material. The safe
pattern is `_purge_unused_materials()`: read the per-face material **names**, rebuild the slot
list from the names, then write the indices back by name.
- **A zero-user material still owns its name.** Removing a slot leaves the datablock behind, so a
donor material renamed to the freed name lands as `Eye.001` and every `m.name == "Eye"` rule
silently misses it. Purge the datablocks (`bpy.data.materials.remove(m)` when `m.users == 0`) or
match on `_base_name()`.
- **A duplicated detail face has to be offset along its own normal.** Copying the eye quad into a
pupil and nudging it in world `-Y` vanished: the eye plane is tilted, so the "front" nudge went
backwards and the pupil sat inside the sclera. Offsetting along `face.normal * 0.0032` fixed it.
Also scale the depth axis when shrinking a copy, or it flattens onto the parent plane.
- **Blender node colours are linear; Godot tonemaps them.** A mouth lip at `0.16` linear rendered as
salmon/mauve. Divide by roughly 3–4 versus the intended sRGB value: the hair uses 0.027 linear,
the lip 0.055/0.018/0.02.
- **The modular Quaternius Worker has no torso under its vest and no crown under its hard hat.**
Deleting either material leaves real holes (that is what shipped in the first 0.9.9 build: guard
and firefighter showed the inside of the head and torso). Remap instead of deleting; the only
geometry the build removes is the Worker brow bar, which is replaced by a donor part.
- **Head gear authored for the 0.315 m procedural head is wrong on the 0.20 m Quaternius head.** Gear
is authored around the head *centre* (1.62) while the attach node is the Head *bone* (1.587), and
the Quaternius centre is 1.69 — a 7 cm error put every cap brim across the brows, which I spent
several passes misreading as a mesh hole (the band was pure black and no material had faces
there). `HEAD_GEAR_LIFT = 0.103` fixes the common case. With the hats removed this only affects
the firefighter helmet.
- **Two character builders — do not confuse them.** `tools/blender_assets.py` is the real builder
for the **eight library characters, 18 gear pieces and props** (it has the 0.9.4 face/hand
sculpting in `_face()`/`_hands_and_shoes()`); `tools/npc_pipeline.py` builds **only**
@@ -157,27 +249,44 @@ canonical implemented-features list in `docs/development-status.md`.
out of a portrait frame (park the rest of the crowd away instead).
- Blender: `bisect_plane` and thin bevels leave zero-area triangles (Godot "non-finite normal in
LOD generation"); `_clean()` + a weld after bisect fixes them and the audit rejects them.
- MakeHuman head/hair gotchas: the imported head is broad and flat, so a separate hair
ellipsoid floats or leaves a bald patch; derive the cap from the closed head shell and
boolean-cut the hairline. Do not reuse the skull's UVs with the old `hair_normal.png`
(dark tangent patches) — hair skips the normal map. Generate the cap before deleting
the hidden scalp, or the cap inherits the hole. The flatpak sandbox cannot read `/tmp`;
helper scripts must live under `$PWD`.
- MakeHuman OBJ intake transform (`base.obj`): the source is Y-up, 16.946 units tall. To reach
the project Blender Z-up / metres / front -Y space: scale 0.10739, translate y +0.907 (ground
the feet), then rotate +90° around X (maps +Y→+Z up and +Z→−Y front). The full-res head carries
internal geometry (eyes/teeth/mouth shells) and is non-manifold; voxel-remesh and Catmull-Clark
subdivision both fragment it into shards. On the decimated head, weld first
(`remove_doubles` ~0.0002) then Laplacian `smooth_vert`; subdivision without the weld splits
along the GLB seam vertices.
- MPFB gotchas: call `TargetService.bake_targets(body)` before any decimate (shape-key
modifier error); add the built-in rig and capture arm weights before applying the MASK
modifier, or `build_basemesh_position_info` divides by zero on an emptied bone group;
decimate before bisecting the clothing loops, or the decimator collapses the bisect
into a sawtooth. Clear custom split normals after joining (imported MPFB normals leave
flat-shaded thigh facets). Imported GLBs may include helper `Cube`/`Icosphere` meshes at
±1.0, so select `npc_base` explicitly. Delete the MPFB hands by hand/finger vertex-group
weights, not only by `|x|`, or leftover fingers become pants-coloured fins.
- Quaternius arm-down bake (working recipe, `tmp/npc-research/bake_armdown_v5.py`): pose-rotate
`UpperArm.L/R` −90° local X → read the pose matrices → apply the Armature modifier → **reset the
pose to identity** → set each arm bone's rest matrix from its pose matrix → re-add the modifier →
export `export_apply=False`. Missing the pose reset double-applies the arm-down (mesh ±0.53
instead of ±0.23). `armature_apply` in Blender 5.2 is broken (deforms the mesh but does not bake
the rest). The canonical base must be **join-only** (`build_base_minimal.py`: no `remove_doubles`
weld, no scale/ground transform, keep the Armature modifiers) — the weld and the scale/ground
transform corrupt the skin weights (arm poses to ±0.51 instead of −0.23).
- Quaternius `NpcAvatar` wiring (commits `2a6f29f`, `cd285b3`): `RIG_BONES` +
`NpcAvatar.bone_name(joint, side)` hold the **only** side mapping — the Quaternius labels `L`/`R`
opposite the project, so proxy side 0 (`-x`) drives `UpperLeg.R`/`UpperArm.R` while side 1 drives
the `.L` bones. The arm/elbow swing axis is `Vector3.LEFT` (legs stay `RIGHT`). The hand proxy is
`global_wrist − global_elbow` (subtracting the parent-relative `elbow.position` misplaces
handheld gear). Old 13-core names resolve through the same table.
- **Bone posing must write the global pose** (`NpcAvatar._swing_bone`): `reset_bone_pose()` then
`set_bone_global_pose(Transform3D(Basis(swing * global_rot), current_origin))`, conjugated with
`get_bone_global_rest()`. Both rejected alternatives fail: the rest-relative
`set_bone_pose_rotation(rest * Quaternion(rest⁻¹·axis, angle))` swings about the parent-relative
rest (the glTF importer already folded the axis conversion into it) and splayed the Quaternius
arms sideways; the plain `rest⁻¹ * swing * rest` conjugation flips the limbs 180°. Verified by
measuring `get_bone_global_pose()` after the call — posed bone axis matches the proxy pivot at
dot 1.000 on the Quaternius and the procedural rigs render unchanged.
Two caveats: children need the parent's swing passed in (the write is absolute), and
`set_bone_global_pose()` is a **no-op outside the scene tree**, so the headless runner (tests run
in `_initialize()`) cannot assert on it.
- **The Quaternius source UV map is degenerate** — every loop at (0,0), flat-colour materials, no
atlas. The AO/texture bake silently produces a 100 % black map, which tints every AO'd slot
(skin, hair, accessory) black in Godot: a black leg is the symptom. `build_base_minimal.py` now
Smart-UV-unwraps and repacks the layout (texel density 0 → 73–74 px/m on 256²), and the base
pipeline is two explicit steps with distinct files: `build_base_minimal.py`
(`quaternius/Casual_Hoodie.glb` → `quaternius_tpose.glb`, joins without welding, renames the
materials to the five tint slots, unwraps) then `bake_armdown_v5.py` (`quaternius_tpose.glb` →
`quaternius_base.glb` + `assets/models/blender_src/npc_casual.blend`). Re-running v5 on its own
output double-bakes the rest.
- Hand gear must be self-contained: the camera carried a 0.42 m neck-strap loop that floats when the
item is parented to the wrist. Hand items get a short wrist strap, not a neck strap. The backpack
straps were authored for the wider procedural chest and floated ~5 cm proud of the Quaternius
torso; the chest points now sit at x 0.12 / Godot z 0.15, which fits both.
- Image models have per-model size floors/caps (Seedream needs 1920+; `GEN_SIZE=2048`, do not
lower; gpt-5-image-mini caps lower). `generate_image` applies model-specific sizing; concept
generation defaults to `--request-size 1536`.
@@ -251,18 +360,55 @@ canonical implemented-features list in `docs/development-status.md`.
## Open Questions
- Whether the responder avatar should be playable/controllable or purely scripted.
- Localization target languages beyond English.
- macOS notarization approach for broad distribution.
- Quaternius scope: full 12-role swap, crowd-only, or extra head detail (owner decision at 0.9.9).
- Localization target languages beyond English (0.11.0/0.12.0).
- macOS notarization approach for broad distribution (0.12.0).
- Fourth-venue choice for 0.11.0 (candidate: TCL Chinese Theatre forecourt).
## Current State
The playable build covers the three venues, tutorial/campaign/checkpoints, the 0.9.3–0.9.6
polish/texture/integration passes and the Blender + realism asset pipeline (see `DONE.md` and
`CHANGELOG.md`). The 12-character library (realistic face + four crowd variants) and the
Comedy Store map rebuild are complete. **Priority (2026-11-04, owner):** 1) the **Blender NPC
model overhaul** (head/face/hands, local part pipeline), 2) finish the MakeHuman character + the
3D model and map improvements, 3) ship it all together in the **0.10.0 minor**. The 0.9.7/0.9.8
character patches are published; `TODO.md` is the priority source. Test counts as of 2026-11-04:
Godot 277/277, Python 167/167, `check_docs` OK.
v0.9.9 is published. The build covers the three venues, the shift loop, tutorial/campaign/
checkpoints, the 0.9.3–0.9.8 polish/texture/integration/character passes and the Blender +
realism asset pipeline (see `DONE.md` and `CHANGELOG.md`). The 12-character procedural library
(realistic face + four crowd variants) and the Comedy Store map rebuild are complete.
**Planning pivot (2026-11-05, owner):** the character and map work was re-sequenced into
patches (`0.9.9`–`0.9.12`) with `0.10.0` as the public-readiness minor. The gap analysis and the
three release roadmaps now live in `PLAN.md`; `TODO.md` is the executable task list. ADR-0017
Stage 1 (proportion warp) is dead; ADR-0018 option 2 (62-joint runtime) is accepted.
**Full roster (0.9.9, commits `a6ccd86` … `9fd4824`):** all twelve characters run on the
Quaternius bases (62 joints, 73–74 px/m texel density), built by the shipped
`tools/blender_assets.py` two-pass pipeline (`_quaternius_tpose_glb` → `_bake_quaternius_rest`).
The owner signed the roster off **with follow-ups** and rejected three review rows; the Worker
body defects (holes, unibrow, missing eyes) and the head-gear seating are fixed, every hat except
the firefighter helmet is removed, and every head has an authored mouth. Gates: `audit` 12/12,
`inspect` clean, `fit` OK, 24-NPC budget 174,976 tris / 0.85 ms, Godot 278/278, Python 167/167.
The owner **accepted the roster on 2026-11-06** and the review page plus its sheets were then
retired; durable evidence lives in `docs/assets/3d-model-review.md` and `docs/assets/blender-assets.md`. Release
packaging was fixed the same day:
excluding `tmp/`, `build/`, `docs/`, `tools/`, `src/test/` and `.agents/` from the export presets
cut the Linux binary from 426 MB to 273 MB, and `tools/build_releases.sh` writes a SHA256SUMS file.
**Open after the swap:** hand-held gear and role props are still authored for the old body (wrist
y 0.78 → 1.017, arm shorter), so the clipboard and umbrella are oversized; the eyes have no whites;
the arms graze the torso on the `worker` base; roster variety is three meshes for twelve roles. The
prop/gear fit pass is queued in `TODO.md` under 0.9.10.
**Quaternius pilot (2026-11-05, commits `cd285b3`, `fb3e75a`, `90f189a`):** `npc_casual` ships as
the Quaternius base. It renders arm-down, carries the five tint slots, plays the Idle/Walk/Sit pose
code on the 62-joint rig, and the procedural rigs are visually unchanged. Verified: `inspect`
(no issues), `audit` OK (6,206 tris / 12,988 verts, 62 bones), `fit` head 0.201 m, texel density
73–74 px/m, `npc_proportions` measured, 24-NPC budget smoke OK (168 meshes, 162,304 tris,
0.82 ms avg frame). The face/silhouette gate sheet and the three options are in
the face-gate decision (owner chose the full swap).
Test counts as of 2026-11-06: Python 167/167, Godot 278/278, `check_docs` OK.
**Docs layout (2026-11-06):** `docs/` is grouped into `project/`, `design/`, `assets/` and
`process/`; `adr/`, `screens/`, `screenshots/` and `blender_previews/` are unchanged.
`docs/README.md` is the index and every category folder has a README (required by
`tools/check_docs.py`). The retired `docs/screens/head-review/` page and its sheets were deleted;
the MakeHuman fallback head is documented in `docs/assets/makehuman-head-review.md`.
<!-- b64: RWFzdGVyIGVnZzogYSByYXJlIHJhZGlvIHRyYW5zbWlzc2lvbiAiwr9Ew7NuZGUgZXN0w6EgbGEgbW90YT8iIGZpcmVzIHZpYSBHYW1lTWFuYWdlci5fbWF5YmVfcmFkaW9fZWFzdGVyX2VnZyAoMi41JSBjaGFuY2UgYWZ0ZXIgYSBzdWNjZXNzZnVsIHJhZGlvIGNhbGwpLiBTdHJpbmcga2V5IHJhZGlvLmVhc3Rlcl9lZ2cgaW4gY29udGVudC9zdHJpbmdzLmVuLmpzb24uIERvIG5vdCByZW1vdmUu -->
+189 -17
View File
@@ -16,20 +16,91 @@ The game is about **judgment, communication, access verification, and proportion
## Development Priorities
The active planning order is set in [`TODO.md`](TODO.md) and in `AGENTS.md`:
The active task order is in [`TODO.md`](TODO.md); the gap analysis and the release roadmap are
below. The current order is:
1. **Character development (unversioned).** Expand the owned procedural character library with
crowd, age, build, hair and outfit variety. Keep the frozen bone/tint/gear contract; see
[ADR-0015](docs/adr/0015-npc-model-variety-sourcing.md) and
[`docs/npc-model-sourcing.md`](docs/npc-model-sourcing.md). Quaternius is a reference;
MakeHuman is deferred to a separate local pipeline.
2. **Local map development (unversioned).** Move beyond stylized venue reconstruction with
licensed OpenStreetMap and 3D building data, downloaded reference imagery for photoreal
facades, AI-assisted composition, and a Gaussian-splatting evaluation that stays in the
development pipeline unless it proves runtime-safe.
3. **Versioned release hardening.** The 0.10.0 release candidate and later semantic versions come
after the unversioned development tracks in planning order. Versions are assigned only when a
track's scope is accepted into a release.
1. **0.9.9–0.9.12 patches.** Finish the character base (the accepted Quaternius 62-joint runtime),
roll it out to the 12 roles, close the scheduled venue/prop/lighting polish, and verify
performance, Web and accessibility.
2. **0.10.0 minor.** Public readiness: external playtests, balance acceptance, legal/storefront
approval, the platform matrix and the documentation/picture lock.
3. **0.10.x patches → 0.11.0.** Content and systems depth: live body-camera replay, a fourth
venue and the localization foundation.
4. **0.12.0 → 1.0.0.** Platform/distribution, content complete, release candidates and the stable
release.
Versions are assigned only when a track's scope is accepted into a release (see
[Release Roadmap](#release-roadmap)). Unversioned tracks — the 3D review evidence base,
maintenance and the Gaussian-splatting study — do not receive a placeholder version.
## Plan Evaluation (2026-11-05)
The game plan itself is sound and largely built: three venues, the escalation ladder, access
artifacts, the radio/report system, the shift review and the campaign loop all exist and are
tested. What needed fixing was the **delivery plan**, not the design.
- **Character sourcing churned.** The project moved procedural → MakeHuman → Quaternius, and the
Quaternius Stage-1 warp failed its own gate. That leaves a correct decision (ADR-0018) with a
half-finished implementation. The plan now makes the rig correction one small version, gates the
roster behind a face/readability decision, and keeps exactly one fallback.
- **One milestone carried too much.** The old 0.10.0 mixed character work, map work and every
public-release gate, so one blocked export blocked the release. Character and venue polish are
now patches; 0.10.0 is only the release gate.
- **Unversioned work had no deadline.** The 3D review backlog could grow without bound. It is now
capped: the ranked venue/prop/lighting items are scheduled into 0.9.11, the budget checks into
0.9.12, and everything else is an explicit accept or deferred. Gaussian splatting stays
unscheduled because no product need justifies its risk yet.
- **Legal, signing and storefront work is release work, not polish.** It now has named checkboxes
in 0.10.0 and 1.0.0 instead of living in prose.
- **What is deliberately not planned:** new genres or mechanics, a live-service model, or a
runtime splat renderer. The de-escalation-first, rare-emergency design stays frozen.
Feasibility: the remaining character work is small in geometry terms (6.2k triangles against a
24k cap) and larger in rig/export terms; the venue work is polish; most release gates are
evidence gathering rather than engineering. The main schedule risk is external review and
approval, not code.
## Character Creation Re-Evaluation (2026-11-05)
**Where it stands.** The shipped library is 12 procedural Blender variants (4.7k–5.8k triangles
each) with a sculpted face, five tint slots and 18 gear pieces. The owner then chose the CC0
**Quaternius Ultimate Modular Characters** as the primary source. Stage 1 (warp the Quaternius
mesh onto the 13-core contract) failed its silhouette gate — arm ×1.63, leg ×0.74, torso ×1.61,
judged distorted. [ADR-0018](docs/adr/0018-quaternius-stage2-runtime-rig.md) therefore adopts the
source **62-joint rig at runtime**: no warp, source LOD (3,199 verts / 6,206 tris), source
Idle/Walk clips, and gear pivots re-derived from the Quaternius skeleton.
**What is already built.** The canonical `quaternius_base.glb` (welded, grounded, arm-down rest),
the 62→13 joint map, the material→five-slot map, the clip inventory (24 clips; Idle and Walk in
scope) and the `NpcAvatar` joint-name mapping with rest-derived gear pivots.
**What actually blocks it.** Two technical items about the export and the pose math, not the art:
1. the arm-down GLB renders in A-pose in Godot because the bake writes wrong inverse bind
matrices; and
2. `_pose_bone()` composes rotations as `rest * Quaternion(axis, angle)`, which only cancels for
the old 180° rest, not the Quaternius ~76° rest.
**Re-evaluation findings.**
- Triangle budget is not the problem (6.2k against a 24k cap). Do not decimate the source.
- **Face fidelity is the real risk.** The 0.9.7 library has a sculpted realistic face; the
Quaternius head is low-poly. A blanket swap would regress every close-up. The plan therefore
makes the owner choose at 0.9.9 between (a) a full swap, (b) Quaternius for crowd roles with the
procedural library for named roles, or (c) extra head subdivision/hair cards on the Quaternius
head.
- **Animation** becomes clip-driven, which removes the hand-built pose composition as the main
path. Poses the clips do not cover (seated, raise-hand, head turn) must be decided explicitly
rather than patched per scene.
- **One fallback, no third source.** The procedural `npc_base` and the MakeHuman head stay tested
until the new base passes the gate. MPFB body work stays closed and the Stage-1 warp is not
reopened. A new character source needs a new ADR.
- **Sequence matters.** Fix the rig first (0.9.9), then the roster (0.9.10). Rolling a broken rig
across 12 variants would waste the whole pass.
**Reversal condition.** If the skin cannot be exported correctly without a new exporter path, or
if the owner rejects the low-poly face in every option, the plan falls back to the procedural
library and retires Quaternius with a recorded ADR. That decision is made at 0.9.9, not later.
## Core Gameplay Loop
@@ -169,7 +240,7 @@ The action wheel prioritizes de-escalation: Stop, Look, Point, No, Ask, Inspect,
The visual direction is readable stylized realism:
- **Character direction:** 8 skinned NPC variants, 18 gear pieces and 20 street/venue props, with four crowd-variety variants prototyped. The generator-first expansion is the active character track ([ADR-0015](docs/adr/0015-npc-model-variety-sourcing.md)); Quaternius is a reference and MakeHuman is deferred to a local pipeline.
- **Character direction:** 12 skinned NPC variants, 18 gear pieces and 20 street/venue props. The active character track is the Quaternius base at runtime ([ADR-0018](docs/adr/0018-quaternius-stage2-runtime-rig.md)): the CC0 source mesh keeps its proportions on the 62-joint rig, Idle/Walk run as clips, and the procedural library stays as the tested fallback until the face/silhouette gate passes. See [Character Creation Re-Evaluation](#character-creation-re-evaluation-2026-11-05).
- **Realism pass:** AI-assisted per-phase skyline panoramas, v2 surface tiles with normal maps, wet asphalt at night, a warm day haze, phase-specific sun/exposure/fog, a tight flashlight spot (no beam geometry), and denser foliage.
- **Local map direction:** the venues are currently stylized reconstructions. The local-map track evaluates licensed OpenStreetMap/3D building data, licensed reference photography, AI-assisted composition and Gaussian splatting as a development tool; online data and splat rendering are not runtime dependencies.
- **References and QA:** runtime UI art lives in `assets/images/ui/`; reference/art-direction sets live in `docs/screens/designs/` and `docs/screens/concepts/`; captures live in `docs/screenshots/`; realism runs live in `docs/screens/realism/`. `screen_designs.py compare/judge` and `tools/check_screenshots.sh` guard drift.
@@ -177,7 +248,7 @@ The visual direction is readable stylized realism:
The active planning order — unversioned character and local-map development first, then the versioned 0.10.0 release-candidate hardening and later releases — is tracked in [`TODO.md`](TODO.md); this plan stays at the product/design level.
Primary decisions: [ADR-0007](docs/adr/0007-locomotion-and-input-layers.md), [ADR-0008](docs/adr/0008-cone-focus-and-head-ring.md), [ADR-0009](docs/adr/0009-radial-action-menu.md), [ADR-0010](docs/adr/0010-procedural-npc-presentation.md), [ADR-0011](docs/adr/0011-aim-free-selection-and-precision-walk.md), [ADR-0012](docs/adr/0012-surface-materials-and-generated-props.md), [ADR-0013](docs/adr/0013-blender-authored-npc-characters.md), [ADR-0015](docs/adr/0015-npc-model-variety-sourcing.md).
Primary decisions: [ADR-0007](docs/adr/0007-locomotion-and-input-layers.md), [ADR-0008](docs/adr/0008-cone-focus-and-head-ring.md), [ADR-0009](docs/adr/0009-radial-action-menu.md), [ADR-0010](docs/adr/0010-procedural-npc-presentation.md), [ADR-0011](docs/adr/0011-aim-free-selection-and-precision-walk.md), [ADR-0012](docs/adr/0012-surface-materials-and-generated-props.md), [ADR-0013](docs/adr/0013-blender-authored-npc-characters.md), [ADR-0015](docs/adr/0015-npc-model-variety-sourcing.md), [ADR-0017](docs/adr/0017-quaternius-npc-base.md).
## Tech Stack
@@ -194,7 +265,107 @@ Primary decisions: [ADR-0007](docs/adr/0007-locomotion-and-input-layers.md), [AD
## Versioning and Delivery
`config/version` in `project.godot` is the single version source (currently `0.9.8`). Releases are tagged `v<version>`; the CI pipeline builds and publishes the standard artifacts plus the optional Desktop HQ zip. Version bumps follow [Semantic Versioning](https://semver.org/): every major, minor and patch increment needs a changelog entry, a local `tools/build_releases.sh` build, and artifact/checksum verification before tagging. Unversioned development tracks do not receive a version until their scope enters a release. See [`docs/RELEASING.md`](docs/RELEASING.md) and [`README.md`](README.md) for commands.
`config/version` in `project.godot` is the single version source (currently `0.9.9`). Releases are tagged `v<version>`; the CI pipeline builds and publishes the standard artifacts plus the optional Desktop HQ zip. Version bumps follow [Semantic Versioning](https://semver.org/): every major, minor and patch increment needs a changelog entry, a local `tools/build_releases.sh` build, and artifact/checksum verification before tagging. Unversioned development tracks do not receive a version until their scope enters a release. See [`docs/process/RELEASING.md`](docs/process/RELEASING.md) and [`README.md`](README.md) for commands.
## Gap Analysis
**Published baseline:** v0.9.8 (2026-11-04) — three playable venues, tutorial/campaign/checkpoint
resume, the access/radio/escalation loop, shift review, the 12-character Blender library, 277
Godot + 162 Python tests, a 21/21 screen-design judge and Compatibility/Web/Desktop HQ builds.
**Current source:** 0.9.8. The 0.10.0-rc.1 package built on 2026-11-03 is stale and is superseded
by the patch sequence below; it is not a published release.
| Area | Remaining gap | Milestone |
| --- | --- | --- |
| Character base | Quaternius arm-down skin export, rest-relative pose composition, face/silhouette acceptance | 0.9.9 |
| Character roster | 12-role mapping, modular outfits, gear fit, AO/texels, budget evidence | 0.9.10 |
| Venue and asset polish | Ranked prop/foliage/lighting/set-dressing fixes, collider verification | 0.9.11 |
| Performance and Web | Frame/memory/load evidence after the content changes, LOD/impostor verification | 0.9.12 |
| Onboarding and balance | External first-time-player evidence, balance sweeps/tuning, content lock | 0.10.0 |
| Accessibility and localization | Acceptance pass, caption coverage, pseudo-locale/length checks | 0.9.12 / 0.10.0 |
| QA and release engineering | Full smoke matrix, clean build/checksum verification, target-matrix launches | 0.10.0 |
| Legal, signing, storefront | macOS signing/notarization, AI-provider rights, storefront/rating approval, privacy sign-off | 0.10.0 / 0.12.0 |
| Systems and content depth | Live incident replay, fourth venue, localization foundation | 0.11.0 |
| Distribution | Signed storefront builds, frozen save contract, launch languages, hardware matrix | 0.12.0 |
| Stable release | Content complete, accessibility audit, release candidates, 1.0.0 decision | 0.13.0 / 1.0.0 |
| Future | More venues/seasonal content, image-to-mesh props, other deferred ideas | Unscheduled |
The 0.9.3 UI, 0.9.4 animation, 0.9.5 texture, 0.9.6 integration, 0.9.7 character development and
0.9.8 deformation fixes are complete in [`DONE.md`](DONE.md); they are not remaining gaps. The
2026-11-01 documentation audit is also closed.
## Release Roadmap
Every version below follows the release procedure in `AGENTS.md`. Patch versions contain fixes and
polish; minor versions add user-facing features; the major version is the stable release with a
compatibility promise. Each version's executable checklist is in [`TODO.md`](TODO.md).
### Roadmap to 0.10.0
The goal of this line is to finish the character and venue work and clear every public-release
gate. The character track is versioned rather than unversioned so a blocked rig cannot hold the
whole release.
| Version | Type | Scope | Exit criterion |
| --- | --- | --- | --- |
| 0.9.9 | patch | Quaternius pilot: correct skin export, rest-relative pose math, Idle/Walk verification, owner face/silhouette gate, one-role (or crowd-only) rollout | A Quaternius NPC renders and animates correctly and ships behind a tested procedural fallback |
| 0.9.10 | patch | 12-role roster, modular outfits, five slots, AO/texels, gear fit, 12×6 baseline | The full roster passes contract, gear, budget and owner-baseline gates |
| 0.9.11 | patch | Scheduled 3D review fixes: props/foliage, gear silhouette, venue shape language, lighting, set dressing, colliders | Every scheduled P1/P2 item is fixed or accepted with a measurement |
| 0.9.12 | patch | Performance/Web/LOD/memory verification plus accessibility and pseudo-locale checks | No regression against the pre-character baselines |
| 0.10.0 | minor | Public readiness: external playtests, balance acceptance, legal/storefront/signing decisions, platform matrix, docs and picture lock | 0.10.0 is content-locked, externally played, legally reviewed, documented and reproducibly built |
### Roadmap to 0.11.0
This line turns a stable 0.10.x into a deeper game: the incident timeline becomes a live replay, a
fourth venue enters the campaign, and the text catalogue becomes a real localization pipeline.
| Version | Type | Scope | Exit criterion |
| --- | --- | --- | --- |
| 0.10.1 | patch | Onboarding and accessibility issues deferred from the 0.10.0 playtests | First-hour and accessibility defects closed |
| 0.10.2 | patch | Balance/fairness sweeps, review-text and difficulty-progression tuning | Every balance-acceptance cell is in target or explicitly accepted |
| 0.10.3 | patch | Save/checkpoint edge cases, gamepad/remap, pause/resume, small quality-of-life fixes | No known P1 stability defect remains |
| 0.11.0 | minor | Live body-camera replay, fourth venue (candidate: TCL Chinese Theatre forecourt), localization foundation with one secondary language | The new systems ship without regressing performance, accessibility or balance |
### Roadmap to 1.0.0
This line is about distribution, contracts and completeness: signed builds on the launch stores, a
frozen save format, finished content and release candidates.
| Version | Type | Scope | Exit criterion |
| --- | --- | --- | --- |
| 0.11.1 | patch | Replay/venue/localization fixes from wider play | No P1 defect in the 0.11.0 feature set |
| 0.11.2 | patch | New-venue balance, campaign pacing and content readability | The 0.11.x line is stable enough to freeze its contracts |
| 0.12.0 | minor | macOS signing/notarization, storefront packages/metadata/ratings, save-format v2 freeze, hardware matrix, launch languages | Signed, storefront-ready builds exist on every launch platform |
| 0.12.1 | patch | Signing, installer, metadata and save-migration fixes from storefront dry runs | Every storefront build installs, launches and migrates cleanly |
| 0.13.0 | minor | Content complete: all planned venues/events/dialogue, audio decision, final tutorial, accessibility audit, balance freeze | All planned content is implemented and frozen |
| 0.13.1 | patch | Release candidate 1: full smoke/performance/save/accessibility matrix | A candidate passes every gate except final approval |
| 0.13.2 | patch | Release candidate 2: verify fixes, freeze release notes/credits/privacy/known limitations | The final candidate is reproducible and documented |
| 1.0.0 | major | Stable release: legal/storefront/rating approval, hardware/accessibility/localization sign-off, no P0/P1, publish on every platform | 1.0.0 is published with verified checksums and no open blocker |
## 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 and budget; CI must never make it a hard
gate.
- Godot engine changes can alter lighting and imports; do not combine an engine baseline move with
a content or feature milestone.
- Signed macOS builds, AI provenance and storefront approval are release blockers, not polish.
- The character pipeline is the current critical path. The rig/export fix must be proven on one
variant before the roster rollout; otherwise 0.9.10 multiplies a defect.
- Photo-derived map assets add a 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; keep it offline,
version-pinned and outside CI, and never make a runtime splat renderer a release dependency.
- 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. Cap it with the scorecard ranking: P0/P1 only, one
asset family per commit, and an explicit accept for everything else.
- Keep the de-escalation-first rules and rare-emergency design unchanged while adding progression,
difficulty and feedback.
## Design Direction
@@ -206,4 +377,5 @@ The game should feel like a tense workplace simulation with occasional crisis mo
- A rare Bob Dobbs cameo (Easter-egg appearance; placement note in `MEMORY.md`).
- Specific unusual NPC behaviors, such as slapping their own face, using hands as scissors, or interacting with props unexpectedly.
- Live 3D body-camera replay; additional venues or seasonal events; real voice/dialogue audio; an image-to-mesh prop pipeline.
- A fifth venue or seasonal events after the 0.11.0 fourth venue proves the venue pipeline.
- Real voice/dialogue audio if the 0.13.0 audio decision does not fund it; an image-to-mesh prop pipeline remains unscheduled.
+1 -1
View File
@@ -14,7 +14,7 @@ Player data is written only to Godot's local `user://` directory:
Those files stay on the player's machine unless the player copies them. Deleting
the files (or the `Gig Line` user directory) resets the profile. See
[`docs/getting-started.md`](docs/getting-started.md#save-data-and-migration) for
[`docs/process/getting-started.md`](docs/process/getting-started.md#save-data) for
locations, migration and rollback instructions.
The repository's development tools can call OpenRouter when a developer supplies
+44 -39
View File
@@ -8,11 +8,12 @@ The central design goal is simple:
## Development Priorities
The active planning order lives in [`TODO.md`](TODO.md) and [`AGENTS.md`](AGENTS.md):
The active planning order lives in [`PLAN.md`](PLAN.md) (gap analysis and release roadmap), [`TODO.md`](TODO.md) (executable checklist) and [`AGENTS.md`](AGENTS.md):
1. **3D model and local map re-evaluation** — score every shipped asset, then evaluate licensed OpenStreetMap/3D data, reference-derived photoreal facades, AI-assisted composition and a Gaussian-splatting development evaluation.
2. **Character development** — crowd, age, build, hair and outfit variety on the owned procedural library, keeping the frozen NPC contract. Source evaluation and the licence decision are in [`docs/npc-model-sourcing.md`](docs/npc-model-sourcing.md).
3. **Versioned release hardening** — the 0.10.0 release candidate and later semantic versions follow the unversioned development tracks.
1. **`0.9.9`–`0.9.12` patches** — finish the Quaternius NPC base on the accepted 62-joint runtime, roll it out to the 12 roles, close the scheduled venue/prop/lighting polish, then verify performance, Web and accessibility.
2. **`0.10.0` minor** — public readiness: external playtests, balance acceptance, legal/storefront/signing decisions, the platform matrix and the documentation/picture lock.
3. **`0.10.x` → `0.11.0`** — live incident replay, a fourth venue and the localization foundation.
4. **`0.12.0` → `1.0.0`** — signed storefront builds, a frozen save contract, content complete, release candidates and the stable release.
Versions are assigned only when a track's scope is accepted into a release. Every major, minor and patch version requires a changelog entry, a local release build and artifact verification before tagging.
@@ -33,23 +34,25 @@ Versions are assigned only when a track's scope is accepted into a release. Ever
> Downloads are public (no sign-in required) since the host's instance-wide
> `REQUIRE_SIGNIN_VIEW` was disabled on 2026-10-31.
>
> **Latest published: v0.9.8** — the character-development patch: the
> **Latest published: v0.9.9** — the character-roster patch: all twelve NPCs now
> use the CC0 Quaternius base with the five tint slots, role gear and baked maps.
> Superseded: v0.9.8, the character-development patch: the
> 12-character library, realistic face pass, four crowd-variety variants and the
> wrist/hip/knee deformation fixes. Previous 0.9.x patches added the
> Hollywood/Joke Shop maps, UI/accessibility polish, NPC visual optimization,
> texture/material refinement and integration checkpoint.
>
> **Current source: v0.9.8** — tagged from the same commit. The 0.10.0
> development track remains gated on the NPC overhaul, MakeHuman/local-map work
> development track remains gated on the Quaternius NPC rollout, local-map work
> and release approvals.
> Releases are built automatically when a `vX.Y.Z` tag is pushed
> (see [`docs/RELEASING.md`](docs/RELEASING.md)); manual builds use
> (see [`docs/process/RELEASING.md`](docs/process/RELEASING.md)); manual builds use
> `./tools/build_releases.sh`. Installer/AppImage packaging runs in the same pipeline
> (NSIS + appimagetool) and uploads with the portable binaries.
>
> macOS builds are unsigned: right-click → Open, or clear the quarantine with
> `xattr -dr com.apple.quarantine gig-line-macos.zip`. Build instructions and
> the release pipeline live in [`docs/RELEASING.md`](docs/RELEASING.md).
> the release pipeline live in [`docs/process/RELEASING.md`](docs/process/RELEASING.md).
If you are here to develop or test locally instead of downloading, jump to
[Setup and Run](#setup-and-run) below.
@@ -95,19 +98,21 @@ Every capture is rendered from the current build by [`tools/check_screenshots.sh
### 3D asset progress
The character, gear and prop libraries are authored procedurally in Blender and audited before use;
the sheets below track their visual progress.
The character roster is built from the CC0 Quaternius bases (ADR-0017/ADR-0018) and audited
before use; the procedural library and the MakeHuman head stay as the tested fallback. The
sheets below show the
current library and will be replaced after the 12 × 6 baseline review.
| | |
| --- | --- |
| ![Eight NPC characters](docs/blender_previews/sheet_npc.jpg) | **Character library.** Eight skinned variants (4.5–5.5k triangles each) with five tint slots, attach-point gear and baked maps. |
| ![Eight NPC characters](docs/blender_previews/sheet_npc.jpg) | **Character library.** Twelve role-dressed variants (4.5–6.4k triangles each) on three CC0 Quaternius bases, with five tint slots, attach-point gear and baked maps. |
| ![Prop library](docs/blender_previews/sheet_props.jpg) | **Street and venue props.** Twenty library props with colliders, navigation avoidance and colour atlases. |
| ![Neutral NPC baseline](docs/blender_previews/sheet_npc_baseline.jpg) | **Neutral baseline.** 8 characters × 6 views (front, three-quarter, profile, back, full body, crowd) used for the 0.9.4 pass and the current re-evaluation. |
| ![Texture refinement comparison](docs/blender_previews/sheet_texture_refinement_0.9.5.jpg) | **Texture refinement.** 128 → 256 px NPC maps and a 4× fabric weave, shown before/after on the same camera. |
| ![Crowd-variety prototypes](docs/blender_previews/sheet_npc_crowd_prototypes.jpg) | **Crowd variety prototypes.** Four approved looks (bun/slim, bald/broad, coat/umbrella, hood/cup) queued for the roster build. |
More sheets and the review criteria are in [`docs/blender_previews/`](docs/blender_previews/README.md)
and [`docs/3d-model-review.md`](docs/3d-model-review.md).
and [`docs/assets/3d-model-review.md`](docs/assets/3d-model-review.md).
## Game Overview
@@ -117,7 +122,7 @@ tickets or credentials, and escalate only when necessary. The game rewards calm
resolution over force. The venue menu splits Hollywood Boulevard into Day and
Night rows; the full mechanics — the three venues, the six-level
escalation model, and the core systems — are in
[`docs/gameplay.md`](docs/gameplay.md); the design rationale lives in
[`docs/design/gameplay.md`](docs/design/gameplay.md); the design rationale lives in
[`PLAN.md`](PLAN.md).
## Architecture
@@ -125,13 +130,13 @@ escalation model, and the core systems — are in
A venue-driven simulation: shared systems (movement, perception, interaction,
access verification, escalation, radio, crowd, reputation, evidence, shift
review) driven by per-venue scenario data, on Godot 4 + GDScript. The full
arc42-style document is [`docs/architecture.md`](docs/architecture.md);
decisions are recorded as ADRs in [`docs/adr/`](docs/adr/).
arc42-style document is [`docs/project/architecture.md`](docs/project/architecture.md);
decisions are recorded as ADRs in [`docs/adr/`](docs/adr).
## Tech Stack
- **Engine:** Godot 4.7.2 · **Language:** GDScript
- **NPCs:** Blender-authored skinned library (`assets/models/blender/`) with procedural fallbacks; lightweight FSMs on `NpcProfile`
- **NPCs:** CC0 Quaternius skinned library (`assets/models/blender/`, ADR-0018) with a tested procedural fallback; lightweight FSMs on `NpcProfile`
- **World:** procedural `WorldBuilder` + generated prop models
- **Art:** v2 skyline/surface textures in `assets/textures/ai/game_ready/v2/picks/`; UI/scene art in `assets/images/`
- **Asset tooling:** `asset_pipeline.py`, `model_pipeline.py`, `npc_pipeline.py`, `blender_assets.py`, `scene_concepts.py`, `screen_designs.py`, `check_screenshots.sh`
@@ -139,7 +144,7 @@ decisions are recorded as ADRs in [`docs/adr/`](docs/adr/).
- **Targets:** Windows, Linux, macOS, Web
The asset pipelines, model tools, and screenshot gates are documented in
[`docs/asset-tooling.md`](docs/asset-tooling.md).
[`docs/assets/asset-tooling.md`](docs/assets/asset-tooling.md).
## Setup and Run
@@ -152,36 +157,36 @@ godot --headless --path . --script res://src/test/test_runner.gd # run all tes
```
Full setup, every run/test/smoke command, and the controls table are in
[`docs/getting-started.md`](docs/getting-started.md).
[`docs/process/getting-started.md`](docs/process/getting-started.md).
## Project Documentation
- [`PLAN.md`](PLAN.md) — Game design plan, development priorities and scenario details.
- [`TODO.md`](TODO.md) — Priority-ordered tasks: character and local-map development, release milestones, and future work.
- [`docs/README.md`](docs/README.md) — Documentation index, current priorities and visual previews.
- [`docs/npc-model-sourcing.md`](docs/npc-model-sourcing.md) — Character-source evaluation, licence rules and the character-development plan.
- [`docs/makehuman-head-review.md`](docs/makehuman-head-review.md) — Local MakeHuman head prototype, provenance and review verdict.
- [`docs/assets/npc-model-sourcing.md`](docs/assets/npc-model-sourcing.md) — Character-source evaluation, licence rules and the character-development plan.
- [`docs/assets/makehuman-head-review.md`](docs/assets/makehuman-head-review.md) — Local MakeHuman head prototype, provenance and review verdict.
- [`AGENTS.md`](AGENTS.md) — Development, commit, build and collaboration workflow.
- [`DONE.md`](DONE.md) — Completed task sections.
- [`MEMORY.md`](MEMORY.md) — Persistent session notes.
- [`CHANGELOG.md`](CHANGELOG.md) — User-facing changes by version.
- [`docs/architecture.md`](docs/architecture.md) — arc42-style architecture documentation.
- [`docs/gameplay.md`](docs/gameplay.md) — Gameplay systems, venues, and the escalation model.
- [`docs/venues.md`](docs/venues.md) — Real-site references, game mapping and limitations for Hollywood, the Joke Shop and the TV Studio.
- [`docs/asset-tooling.md`](docs/asset-tooling.md) — Asset pipelines, model tools, and screenshot gates.
- [`docs/project/architecture.md`](docs/project/architecture.md) — arc42-style architecture documentation.
- [`docs/design/gameplay.md`](docs/design/gameplay.md) — Gameplay systems, venues, and the escalation model.
- [`docs/design/venues.md`](docs/design/venues.md) — Real-site references, game mapping and limitations for Hollywood, the Joke Shop and the TV Studio.
- [`docs/assets/asset-tooling.md`](docs/assets/asset-tooling.md) — Asset pipelines, model tools, and screenshot gates.
- [`tools/README.md`](tools/README.md) — Tool inventory, categories, test commands and AI-skill evaluation.
- [`.agents/skills/gig-line-blender-asset-contract`](.agents/skills/gig-line-blender-asset-contract/SKILL.md) — tracked AI skill for Blender/NPC/gear asset work.
- [`.agents/skills/gig-line-release-qa`](.agents/skills/gig-line-release-qa/SKILL.md) — tracked AI skill for release and visual-QA work.
- [`docs/getting-started.md`](docs/getting-started.md) — Setup, run/test commands, and controls.
- [`docs/development-status.md`](docs/development-status.md) — Implemented features and what's next.
- [`docs/accessibility.md`](docs/accessibility.md) — Accessibility features, known gaps and statement.
- [`docs/known-limitations.md`](docs/known-limitations.md) — Release-candidate blockers and accepted limitations.
- [`docs/release-qa.md`](docs/release-qa.md) — Manual smoke checklist and release-candidate balance protocol.
- [`docs/process/getting-started.md`](docs/process/getting-started.md) — Setup, run/test commands, and controls.
- [`docs/project/development-status.md`](docs/project/development-status.md) — Implemented features and what's next.
- [`docs/design/accessibility.md`](docs/design/accessibility.md) — Accessibility features, known gaps and statement.
- [`docs/design/known-limitations.md`](docs/design/known-limitations.md) — Release-candidate blockers and accepted limitations.
- [`docs/process/release-qa.md`](docs/process/release-qa.md) — Manual smoke checklist and release-candidate balance protocol.
- [`CREDITS.md`](CREDITS.md) — Credits, AI/reference provenance and licensing notes.
- [`PRIVACY.md`](PRIVACY.md) — Local-only data, save files and development API use.
- [`docs/blender-assets.md`](docs/blender-assets.md) — Blender asset library: characters, gear, props, attach points.
- [`docs/npc-visual-review.md`](docs/npc-visual-review.md) — 0.9.4 NPC baseline, acceptance criteria and ranked visual gaps; 0.9.5 texture comparison is in [`docs/blender_previews/sheet_texture_refinement_0.9.5.jpg`](docs/blender_previews/sheet_texture_refinement_0.9.5.jpg).
- [`docs/adr/`](docs/adr/) — Architecture Decision Records.
- [`docs/assets/blender-assets.md`](docs/assets/blender-assets.md) — Blender asset library: characters, gear, props, attach points.
- [`docs/assets/npc-model-sourcing.md`](docs/assets/npc-model-sourcing.md) — character sources, the shipped roster table and the build steps; 0.9.5 texture comparison is in [`docs/blender_previews/sheet_texture_refinement_0.9.5.jpg`](docs/blender_previews/sheet_texture_refinement_0.9.5.jpg).
- [`docs/adr/`](docs/adr) — Architecture Decision Records.
## Development Status
@@ -190,12 +195,12 @@ v0.9.8 is the current source version: the character-development patch with the
and save-migration/release hardening. It sits on the 0.9.6 integration
checkpoint, 0.9.5 texture refinement, 0.9.4 NPC visual optimization, 0.9.3
UI/accessibility polish, 0.9.2 Hollywood/Joke Shop maps and the 0.9.x engine
baseline. The active priorities are the Blender NPC head/face/hand overhaul,
MakeHuman body intake and the 3D model/map re-evaluation; the 0.10.0 release
candidate follows those tracks. See
[`docs/development-status.md`](docs/development-status.md) for the implemented list
baseline. The active work is the `0.9.9`–`0.9.12` patch line (Quaternius NPC
base, roster, venue/asset polish, performance) followed by the `0.10.0`
public-readiness minor. See
[`docs/project/development-status.md`](docs/project/development-status.md) for the implemented list
and [`TODO.md`](TODO.md) for the priority-ordered roadmap. Manual verification uses
[`docs/release-qa.md`](docs/release-qa.md).
[`docs/process/release-qa.md`](docs/process/release-qa.md).
## Credits, Privacy and Accessibility
@@ -204,8 +209,8 @@ network service, and saves stay in Godot's local `user://` folder. The
body-camera overlay is simulated. Asset provenance, AI-assisted image usage and
credits are recorded in [`CREDITS.md`](CREDITS.md); the local-data policy is in
[`PRIVACY.md`](PRIVACY.md); accessibility features and gaps are in
[`docs/accessibility.md`](docs/accessibility.md); and release-candidate blockers
are listed in [`docs/known-limitations.md`](docs/known-limitations.md).
[`docs/design/accessibility.md`](docs/design/accessibility.md); and release-candidate blockers
are listed in [`docs/design/known-limitations.md`](docs/design/known-limitations.md).
## Development Workflow
+597 -608
View File
File diff suppressed because it is too large. Load diff
+236 -228
View File
@@ -28,12 +28,12 @@
"attach": "back",
"bounds_godot": {
"max": [
0.161,
0.15,
0.296,
0.212
0.172
],
"min": [
-0.161,
-0.15,
-0.12,
-0.319
]
@@ -46,7 +46,7 @@
],
"path": "assets/models/blender/npc_gear/backpack.glb",
"triangles": 380,
"vertices": 408
"vertices": 410
},
"bench": {
"bounds_godot": {
@@ -98,14 +98,14 @@
"attach": "hand",
"bounds_godot": {
"max": [
0.106,
0.376,
0.065,
0.06,
0.143
],
"min": [
-0.106,
-0.065,
-0.053,
-0.055
0.005
]
},
"category": "npc_gear",
@@ -114,42 +114,20 @@
"lens"
],
"path": "assets/models/blender/npc_gear/camera.glb",
"triangles": 318,
"vertices": 406
},
"cap": {
"attach": "head",
"bounds_godot": {
"max": [
0.168,
0.209,
0.258
],
"min": [
-0.168,
0.037,
-0.186
]
},
"category": "npc_gear",
"materials": [
"plastic_black"
],
"path": "assets/models/blender/npc_gear/cap.glb",
"triangles": 328,
"vertices": 285
"triangles": 312,
"vertices": 422
},
"clipboard": {
"attach": "hand",
"bounds_godot": {
"max": [
0.115,
0.05,
0.11,
-0.07,
0.053
],
"min": [
-0.115,
-0.265,
-0.11,
-0.375,
0.036
]
},
@@ -166,12 +144,12 @@
"crowd_barrier": {
"bounds_godot": {
"max": [
1.116,
1.066,
1.12,
1.07,
0.307
],
"min": [
-1.122,
-1.128,
-0.014,
-0.307
]
@@ -264,14 +242,14 @@
"attach": "head",
"bounds_godot": {
"max": [
0.166,
0.26,
0.245,
0.26
0.166
],
"min": [
-0.26,
0.035,
-0.351
-0.166,
0.125,
-0.225
]
},
"category": "npc_gear",
@@ -329,28 +307,6 @@
"triangles": 268,
"vertices": 400
},
"hood": {
"attach": "head",
"bounds_godot": {
"max": [
0.184,
0.236,
0.123
],
"min": [
-0.184,
-0.146,
-0.225
]
},
"category": "npc_gear",
"materials": [
"plastic_grey"
],
"path": "assets/models/blender/npc_gear/hood.glb",
"triangles": 804,
"vertices": 649
},
"lanyard": {
"attach": "chest",
"bounds_godot": {
@@ -428,16 +384,17 @@
"vertices": 648
},
"npc_casual": {
"base": "hoodie",
"bounds_godot": {
"max": [
0.321,
1.824,
0.189
0.262,
1.866,
0.287
],
"min": [
-0.321,
0,
-0.178
-0.262,
-0.004,
-0.091
]
},
"category": "npc",
@@ -445,11 +402,13 @@
"materials": [
"skin",
"cloth",
"pants",
"accessory",
"eye_white",
"Eyebrows",
"sclera",
"hair",
"rubber"
"pants",
"mouth",
"pupil"
],
"mesh_node": "npc_base",
"path": "assets/models/blender/npc/npc_casual.glb",
@@ -466,32 +425,36 @@
"accessory",
"hair"
],
"triangles": 5034,
"vertices": 4607
"triangles": 6242,
"vertices": 13100
},
"npc_coat": {
"base": "suit",
"bounds_godot": {
"max": [
0.332,
1.824,
0.189
0.255,
1.809,
0.279
],
"min": [
-0.332,
0,
-0.18
-0.255,
-0.001,
-0.083
]
},
"category": "npc",
"layer": "coat",
"materials": [
"skin",
"Tie",
"cloth",
"pants",
"White",
"accessory",
"eye_white",
"Eyebrows",
"hair",
"rubber"
"sclera",
"pants",
"pupil"
],
"mesh_node": "npc_base",
"path": "assets/models/blender/npc/npc_coat.glb",
@@ -507,20 +470,21 @@
"accessory",
"hair"
],
"triangles": 6046,
"vertices": 5645
"triangles": 6582,
"vertices": 13607
},
"npc_crowd_a": {
"base": "beach",
"bounds_godot": {
"max": [
0.288,
1.825,
0.189
0.252,
1.805,
0.277
],
"min": [
-0.288,
0,
-0.195
-0.252,
-0.005,
-0.088
]
},
"category": "npc",
@@ -528,11 +492,13 @@
"materials": [
"skin",
"cloth",
"pants",
"accessory",
"eye_white",
"Eyebrows",
"sclera",
"hair",
"rubber"
"Earrings",
"pants",
"pupil"
],
"mesh_node": "npc_base",
"path": "assets/models/blender/npc/npc_crowd_a.glb",
@@ -547,32 +513,38 @@
"accessory",
"hair"
],
"triangles": 5284,
"vertices": 4908
"triangles": 6602,
"vertices": 13557
},
"npc_crowd_b": {
"base": "farmer",
"bounds_godot": {
"max": [
0.358,
1.809,
0.189
0.256,
1.81,
0.28
],
"min": [
-0.358,
0,
-0.155
-0.256,
-0.0,
-0.11
]
},
"category": "npc",
"layer": "none",
"materials": [
"skin",
"LightBlue",
"cloth",
"pants",
"Beige",
"accessory",
"eye_white",
"hair",
"rubber"
"Eyebrows",
"Beige.001",
"Red",
"sclera",
"pants",
"pupil",
"hair"
],
"mesh_node": "npc_base",
"path": "assets/models/blender/npc/npc_crowd_b.glb",
@@ -587,32 +559,40 @@
"accessory",
"hair"
],
"triangles": 4812,
"vertices": 4550
"triangles": 5512,
"vertices": 11291
},
"npc_crowd_c": {
"base": "adventurer",
"bounds_godot": {
"max": [
0.332,
1.824,
0.189
0.255,
1.809,
0.279
],
"min": [
-0.332,
0,
-0.18
-0.255,
-0.001,
-0.256
]
},
"category": "npc",
"layer": "coat",
"materials": [
"Brown",
"LightGreen",
"Gold",
"Green",
"skin",
"Tie",
"cloth",
"pants",
"White",
"accessory",
"eye_white",
"Eyebrows",
"hair",
"rubber"
"sclera",
"pants",
"pupil"
],
"mesh_node": "npc_base",
"path": "assets/models/blender/npc/npc_crowd_c.glb",
@@ -627,20 +607,21 @@
"accessory",
"hair"
],
"triangles": 5690,
"vertices": 5510
"triangles": 9526,
"vertices": 19501
},
"npc_crowd_d": {
"base": "worker",
"bounds_godot": {
"max": [
0.293,
1.856,
0.189
0.262,
1.866,
0.287
],
"min": [
-0.293,
0,
-0.225
-0.262,
-0.004,
-0.087
]
},
"category": "npc",
@@ -648,11 +629,15 @@
"materials": [
"skin",
"cloth",
"pants",
"accessory",
"eye_white",
"Eyebrows",
"Moustache",
"pants",
"Brows",
"sclera",
"hair",
"rubber"
"mouth",
"pupil"
],
"mesh_node": "npc_base",
"path": "assets/models/blender/npc/npc_crowd_d.glb",
@@ -667,32 +652,38 @@
"accessory",
"hair"
],
"triangles": 5810,
"vertices": 5444
"triangles": 6290,
"vertices": 13188
},
"npc_dress": {
"base": "king",
"bounds_godot": {
"max": [
0.288,
1.825,
0.208
0.249,
1.809,
0.269
],
"min": [
-0.288,
0,
-0.208
-0.249,
-0.001,
-0.083
]
},
"category": "npc",
"layer": "dress",
"materials": [
"skin",
"Blue",
"cloth",
"pants",
"Beige",
"Metal_Dark",
"accessory",
"eye_white",
"hair",
"rubber"
"Gold",
"sclera",
"pants",
"Metal_Dark_legs",
"pupil"
],
"mesh_node": "npc_base",
"path": "assets/models/blender/npc/npc_dress.glb",
@@ -706,20 +697,21 @@
"accessory",
"hair"
],
"triangles": 5540,
"vertices": 5073
"triangles": 11126,
"vertices": 22516
},
"npc_firefighter": {
"base": "worker",
"bounds_godot": {
"max": [
0.37,
1.819,
0.213
0.262,
1.866,
0.287
],
"min": [
-0.37,
0,
-0.213
-0.262,
-0.004,
-0.087
]
},
"category": "npc",
@@ -727,13 +719,15 @@
"materials": [
"skin",
"cloth",
"pants",
"accessory",
"eye_white",
"Eyebrows",
"Moustache",
"pants",
"Brows",
"sclera",
"hair",
"hivis",
"reflective",
"rubber"
"mouth",
"pupil"
],
"mesh_node": "npc_base",
"path": "assets/models/blender/npc/npc_firefighter.glb",
@@ -747,20 +741,21 @@
"accessory",
"hair"
],
"triangles": 5888,
"vertices": 5785
"triangles": 6290,
"vertices": 13188
},
"npc_guard": {
"base": "worker",
"bounds_godot": {
"max": [
0.361,
1.819,
0.189
0.262,
1.866,
0.287
],
"min": [
-0.361,
0,
-0.172
-0.262,
-0.004,
-0.087
]
},
"category": "npc",
@@ -768,15 +763,15 @@
"materials": [
"skin",
"cloth",
"pants",
"accessory",
"eye_white",
"Eyebrows",
"Moustache",
"pants",
"Brows",
"sclera",
"hair",
"rubber",
"leather",
"steel",
"patch",
"plastic_black"
"mouth",
"pupil"
],
"mesh_node": "npc_base",
"path": "assets/models/blender/npc/npc_guard.glb",
@@ -791,32 +786,38 @@
"accessory",
"hair"
],
"triangles": 5670,
"vertices": 5671
"triangles": 6290,
"vertices": 13188
},
"npc_hoodie": {
"base": "punk",
"bounds_godot": {
"max": [
0.326,
1.856,
0.189
0.241,
1.806,
0.263
],
"min": [
-0.326,
0,
-0.225
-0.241,
-0.004,
-0.147
]
},
"category": "npc",
"layer": "hood",
"materials": [
"skin",
"White",
"cloth",
"pants",
"accessory",
"eye_white",
"sclera",
"Eyebrows",
"Red_Dark",
"hair",
"rubber"
"Earrings",
"Skin_legs",
"pants",
"pupil"
],
"mesh_node": "npc_base",
"path": "assets/models/blender/npc/npc_hoodie.glb",
@@ -832,20 +833,21 @@
"accessory",
"hair"
],
"triangles": 5864,
"vertices": 5325
"triangles": 5524,
"vertices": 11257
},
"npc_jacket": {
"base": "casual_2",
"bounds_godot": {
"max": [
0.332,
1.824,
0.189
0.255,
1.809,
0.279
],
"min": [
-0.332,
0,
-0.178
-0.255,
-0.001,
-0.164
]
},
"category": "npc",
@@ -853,11 +855,13 @@
"materials": [
"skin",
"cloth",
"pants",
"accessory",
"eye_white",
"Skin_Darker",
"Eyebrows",
"hair",
"rubber"
"sclera",
"pants",
"pupil"
],
"mesh_node": "npc_base",
"path": "assets/models/blender/npc/npc_jacket.glb",
@@ -873,34 +877,38 @@
"accessory",
"hair"
],
"triangles": 5432,
"vertices": 5225
"triangles": 5800,
"vertices": 11866
},
"npc_vest": {
"base": "worker",
"bounds_godot": {
"max": [
0.321,
1.819,
0.189
0.262,
1.789,
0.287
],
"min": [
-0.321,
0,
-0.172
-0.262,
-0.004,
-0.083
]
},
"category": "npc",
"layer": "vest",
"materials": [
"skin",
"Worker_Yellow",
"cloth",
"pants",
"accessory",
"eye_white",
"Eyebrows",
"Moustache",
"pants",
"Brows",
"sclera",
"hair",
"rubber",
"hivis",
"reflective"
"mouth",
"pupil"
],
"mesh_node": "npc_base",
"path": "assets/models/blender/npc/npc_vest.glb",
@@ -914,8 +922,8 @@
"accessory",
"hair"
],
"triangles": 5532,
"vertices": 5195
"triangles": 6290,
"vertices": 13186
},
"palm_tree": {
"bounds_godot": {
@@ -967,7 +975,7 @@
"bounds_godot": {
"max": [
0.5,
1.08,
1.118,
0.5
],
"min": [
@@ -985,8 +993,8 @@
],
"path": "assets/models/blender/props/planter_box.glb",
"replaces": "generated/planter_box.glb",
"triangles": 1324,
"vertices": 2780
"triangles": 818,
"vertices": 1701
},
"protest_sign": {
"attach": "hand",
@@ -1041,14 +1049,14 @@
"round_planter": {
"bounds_godot": {
"max": [
0.432,
1.12,
0.399,
1.175,
0.36
],
"min": [
-0.36,
0,
-0.363
-0.376
]
},
"category": "props",
@@ -1058,8 +1066,8 @@
"foliage_dark"
],
"path": "assets/models/blender/props/round_planter.glb",
"triangles": 1240,
"vertices": 2418
"triangles": 808,
"vertices": 1522
},
"scba_tank": {
"attach": "back",
@@ -1213,14 +1221,14 @@
"street_tree": {
"bounds_godot": {
"max": [
1.179,
3.62,
1.102
1.15,
3.634,
1.053
],
"min": [
-0.941,
-1.041,
0,
-1.082
-1.08
]
},
"category": "props",
@@ -1232,21 +1240,21 @@
],
"path": "assets/models/blender/props/street_tree.glb",
"replaces": "WorldBuilder cone trees",
"triangles": 2592,
"vertices": 5620
"triangles": 1506,
"vertices": 3330
},
"sunglasses": {
"attach": "head",
"bounds_godot": {
"max": [
0.101,
0.059,
0.158
0.065,
0.141,
0.101
],
"min": [
-0.101,
0.011,
0.003
-0.065,
0.11,
0.002
]
},
"category": "npc_gear",
Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 67 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 67 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 65 KiB

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 57 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 65 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.3 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,33 @@
# Quaternius build sources (CC0 1.0)
These are the **build inputs** for the shipped NPC roster, not runtime assets.
`blender_src/.gdignore` keeps Godot from importing this directory.
Source: Quaternius *Ultimate Modular Characters* and *Ultimate Modular Women*
(<https://quaternius.com/packs/ultimatemodularcharacters.html>), licence CC0 1.0,
attribution recorded in the repository `CREDITS.md`.
| File | SHA-256 | Bones | Meshes |
| --- | --- | --- | --- |
| `Casual.glb` | `bc2d84fba249ebaa0629cb9d133ad37234196e4b8004aa205a6397abed04e05c` | 62 | 4 skinned + Icosphere helper |
| `Casual_Hoodie.glb` | `f5b722199f7628b24550989af4230f65d5230727df9c326fd2b3e360effe5249` | 62 | 4 skinned + Icosphere helper |
| `Worker.glb` | `8d0f454336c2effc5c08f63a177af3a82d1a7af025ca9588b40e4c90c4703534` | 62 | 4 skinned + Icosphere helper |
Each file also carries 24 animation clips; the build exports **no** animation data, so
the shipped GLBs contain the mesh, the 62-joint skin and the material slots only.
Reproducing the shipped characters:
flatpak run org.blender.Blender --background \
--python "$PWD/tools/blender_assets.py" -- build --only npc
Upstream quirks the build compensates for (see `docs/assets/npc-model-sourcing.md`):
1. every mesh ships a **degenerate UV map** (all loops at `0,0`) with flat-colour
materials, so the build Smart-UV-unwraps and repacks before export;
2. the meshes must be joined **without welding** — `remove_doubles` corrupts the
skin weights;
3. the rest pose is a T-pose, so the arm-down rest is baked by
`_bake_quaternius_rest()`;
4. the upstream material names differ per file, so each source carries a slot map
down to the project's five tint slots.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,54 @@
# Quaternius modular parts
Build inputs for outfit, hair and accessory variety. Committed like the three whole-body
sources, so `build` works from a fresh checkout without the upstream pack.
## Where they come from
The upstream *Ultimate Modular Characters* pack is distributed as a Google Drive folder
(<https://drive.google.com/drive/folders/1USAAquX2JJWuA2m6zol0KUkFe3UkZ8zX>, CC0 1.0). It cannot be
fetched reproducibly by a script, so the owner downloads it **once** into the gitignored
`tmp/quaternius-intake/`. Everything after that is scripted:
```sh
python3 tools/quaternius_parts.py inventory --dir tmp/quaternius-intake
python3 tools/quaternius_parts.py extract \
--file tmp/quaternius-intake/<file>.glb --mesh <mesh> --part <part>
python3 tools/quaternius_parts.py verify --dir assets/models/blender_src/quaternius/parts
```
`inventory` and `verify` run outside Blender; `extract` needs Blender, because it rewrites the skin.
The pack itself is never committed — only the parts that are actually used, each with its SHA-256
recorded here and in `CREDITS.md`.
## Part contract
A part is **one skinned mesh on the 62-joint rig**:
- one mesh object, parented to the rig's armature, carrying `JOINTS_0`/`WEIGHTS_0`;
- the standard joint names (`Hips`, `Chest`, `Head`, `UpperArm.L`, …). The rig check in
`quaternius_parts.py verify` fails a part that is missing any of them, because
`NpcAvatar` maps those bones;
- materials named after a contract slot (`skin`, `cloth`, `pants`, `hair`, `accessory`) so the
runtime tint reaches them, or a fixed-colour detail name that is deliberately not tinted;
- triangles counted against the character budget: base body plus every joined part must stay
inside 24,000 triangles and 24,000 glTF vertices.
The builder drops the part's own armature when it joins the mesh onto a base body, because the base
already owns the skeleton and two armatures would duplicate every bone. Weights survive the join
because Blender merges vertex groups by name.
## Assigning parts to a role
```python
"npc_vest": {"layer": "vest", "base": "worker", "parts": ["hivis_vest"], ...}
```
`build` joins those parts after the body join and before the material slot map, so the part's
materials go through the same slot mapping as the base. The T-pose cache is keyed on the part list.
## Kept parts
| Part | Source file | SHA-256 | Tris |
| --- | --- | --- | --- |
| _(none yet — the pack has not been intaken)_ | | | |
+31 -31
View File
@@ -1,43 +1,43 @@
# Gig Line Documentation
This folder holds the project documentation, visual references and generated QA evidence.
Documentation is grouped by category. Product intent, the gap analysis and the release roadmap
live in [`../PLAN.md`](../PLAN.md); the executable task list is [`../TODO.md`](../TODO.md); the
workflow rules are in [`../AGENTS.md`](../AGENTS.md).
## Current priorities
## Categories
1. [Blender NPC model overhaul](../TODO.md#blender-npc-model-overhaul-top-priority) — part-based head/face/hands pipeline and 16,000-budget contract.
2. [MakeHuman and 3D model/map improvements](../TODO.md#makehuman-character-pipeline) — body intake, asset re-evaluation and local map reconstruction.
3. [0.10.0 release candidate](../TODO.md#milestone-0100--3d-model-and-map-improvements-minor) — versioned release hardening after the unversioned development tracks.
| Folder | Contents |
| --- | --- |
| [`project/`](project/README.md) | Architecture (arc42) and the implemented-features status |
| [`design/`](design/README.md) | Gameplay, venues, UI copy, accessibility and known limitations |
| [`assets/`](assets/README.md) | Blender library, asset tooling, NPC sourcing and the 3D model review |
| [`process/`](process/README.md) | Setup/controls, release QA and the release runbook |
| [`adr/`](adr/README.md) | Architecture Decision Records |
| [`screens/`](screens/README.md) | Licensed references, concepts and screen designs |
| [`blender_previews/`](blender_previews/README.md) | Committed character/gear/prop preview sheets |
| [`screenshots/`](screenshots/README.md) | The committed in-game gallery |
## Start here
- [`../PLAN.md`](../PLAN.md) — product, design intent and development priorities
- [`../TODO.md`](../TODO.md) — priority-ordered active tasks and roadmap
- [`npc-model-sourcing.md`](npc-model-sourcing.md) — character-source evaluation, licence rules and the character-development plan
- [`makehuman-head-review.md`](makehuman-head-review.md) — local MakeHuman head prototype, provenance and review verdict
- [`architecture.md`](architecture.md) — arc42 system architecture
- [`getting-started.md`](getting-started.md) — setup, run/test commands and controls
- [`asset-tooling.md`](asset-tooling.md) — image/model pipelines and screenshot gates
- [`../tools/README.md`](../tools/README.md) — tool inventory, categories and test runner
- [`gameplay.md`](gameplay.md) — controls, venues and escalation
- [`venues.md`](venues.md) — Hollywood, Joke Shop and TV Studio real-site mapping
- [`npc-visual-review.md`](npc-visual-review.md) — NPC visual baseline, acceptance criteria and ranked gaps
- [`3d-model-review.md`](3d-model-review.md) — 3D model re-evaluation: measurements, scorecard and ranked gaps
- [`development-status.md`](development-status.md) — implemented features, current gaps and active planning
- [`accessibility.md`](accessibility.md) — accessibility statement and known gaps
- [`known-limitations.md`](known-limitations.md) — release-candidate blockers and accepted limits
- [`release-qa.md`](release-qa.md) — manual smoke checklist and balance-acceptance protocol
- [`../CREDITS.md`](../CREDITS.md) — credits and asset provenance
- [`../PRIVACY.md`](../PRIVACY.md) — privacy note
- [`ui-copy.md`](ui-copy.md) — screen, copy and button inventory
- [`RELEASING.md`](RELEASING.md) — export, CI and publishing workflow
- [`adr/README.md`](adr/README.md) — architecture decisions
- [`../PLAN.md`](../PLAN.md) — product, design pillars, gap analysis and the roadmap to 1.0.0
- [`../TODO.md`](../TODO.md) — milestone-ordered active tasks
- [`project/architecture.md`](project/architecture.md) — system architecture and ownership
- [`project/development-status.md`](project/development-status.md) — what the build supports now
- [`design/gameplay.md`](design/gameplay.md) — the playable loop and escalation model
- [`design/venues.md`](design/venues.md) — venue mapping and real-site evidence
- [`assets/npc-model-sourcing.md`](assets/npc-model-sourcing.md) — the active NPC base and licence
rules
- [`assets/3d-model-review.md`](assets/3d-model-review.md) — asset measurements and scorecard
- [`process/getting-started.md`](process/getting-started.md) — setup, run/test and controls
- [`../tools/README.md`](../tools/README.md) — tool inventory and test runner
- [`../CREDITS.md`](../CREDITS.md) — credits, AI/reference provenance and licensing
- [`../PRIVACY.md`](../PRIVACY.md) — local-only data and save files
## Visual references
## Current work
- [`screens/README.md`](screens/README.md) — concepts, designs, screenshots and realism runs
- [`blender_previews/README.md`](blender_previews/README.md) — character/gear/prop previews
- [`screenshots/README.md`](screenshots/README.md) — committed game gallery
- [`ui-copy.md`](ui-copy.md#screen-design-judge-report) — screen/button inventory and latest judge result
v0.9.9 shipped the Quaternius NPC roster. The active patch line is `0.9.10` (roster follow-ups:
outfit families, the Swat base orientation, per-slot atlases) through `0.9.12`, followed by the
`0.10.0` public-readiness minor. See [`../TODO.md`](../TODO.md) for the live checklist.
## Quick preview
+9 -3
View File
@@ -1,8 +1,14 @@
# ADR-0015: NPC model variety sourcing
- **Status:** Accepted (planning)
- **Status:** Superseded by [ADR-0017](0017-quaternius-npc-base.md) (2026-11-05)
- **Date:** 2026-11-03
## Superseded
ADR-0017 replaces the generator-first decision below: Quaternius is now the
primary NPC base. The evaluation, licence rules and consequences remain as the
record of the 2026-11-03 decision.
## Context
The library has eight skinned characters, and role/seed selection reuses them
@@ -15,7 +21,7 @@ A review compared free/open-source sources against that contract. Quaternius
Ultimate Modular (CC0), Kenney Blocky Characters (CC0), Khronos CesiumMan and
RiggedFigure (CC BY 4.0) and the MakeHuman base mesh (CC0) were imported and
measured. None was a drop-in; the full results are in
[`docs/npc-model-sourcing.md`](../npc-model-sourcing.md).
[`docs/assets/npc-model-sourcing.md`](../assets/npc-model-sourcing.md).
## Decision
@@ -80,4 +86,4 @@ measured. None was a drop-in; the full results are in
- MakeHuman is now an active local development pipeline (body retarget plus project-owned
head/hands), while the procedural library remains the shipped path and CI fallback.
- Blender MCP is optional interactive tooling only; it is not a build, CI, test or runtime
dependency. Setup is in [`docs/asset-tooling.md#optional-interactive-blender-mcp`](../asset-tooling.md#optional-interactive-blender-mcp).
dependency. Setup is in [`docs/assets/asset-tooling.md#optional-interactive-blender-mcp`](../assets/asset-tooling.md#optional-interactive-blender-mcp).
+42
View File
@@ -0,0 +1,42 @@
# ADR-0016: 24,000-triangle character budget
- **Status:** Accepted
- **Date:** 2026-11-05
## Context
ADR-0015 raised the character contract to 16,000 triangles / 16,000 glTF
vertices for the MakeHuman head, hands and crowd variety. The local MPFB
full-body prototype now uses that head, project hands and shoes, and a fused
neck: it measures 19,747 triangles before any clothing variation. The 16,000 cap
leaves no room for the firefighter and hoodie gear, and it forces the body and
neck into a low decimation that produces visible facets.
## Decision
Raise the character contract to **24,000 triangles / 24,000 glTF vertices** per
character (`CHAR_MAX_TRIS`/`CHAR_MAX_VERTS`, `npc_pipeline.MAX_TRIANGLES`/
`MAX_VERTICES`, and the `adapt` defaults). The 13 core bones, five tint slots,
front orientation, grounding and single `npc_base` skinned mesh are unchanged.
Gear stays at 1,500 triangles and props at 4,000.
## Consequences
- The MPFB body, accepted head and neck fit with headroom for the 12 clothing
variants and future jacket/hoodie detail.
- The 24-NPC and Web frame-time budgets must be re-measured before shipping any
variant built at the new cap; the extra geometry is not free.
- The procedural generator and the low-poly `npc_base` fallback remain valid;
they are not required to use the new headroom.
- MPFB stays a local development tool. Production must bake a committed source
GLB; CI and the build must not depend on MPFB.
- Historical reviews and measurements that state 16,000 remain accurate for the
date they were recorded; current contract documents state 24,000.
## Alternatives
- **Keep 16,000 and decimate the MPFB body further:** rejected because the neck
and shoulder already show facets and the clothing variants would exceed the
cap.
- **Separate caps for the MPFB prototype and the shipped characters:** rejected
because it creates a second contract and makes the rollout ambiguous.
+69
View File
@@ -0,0 +1,69 @@
# ADR-0017: Quaternius NPC base
- **Status:** Accepted
- **Date:** 2026-11-05
- **Supersedes:** ADR-0015 (generator-first character sourcing)
## Context
The current NPC library is built by the project-owned procedural generator. It
keeps the contract and ships, but the body, neck, hands and shoes need a
bespoke part pipeline to read as human. The MakeHuman head and MPFB body
prototypes improved detail but added a second authoring path, a 19,747-triangle
prototype and unresolved neck/shoulder seams.
The CC0 **Quaternius Ultimate Modular Characters** pack already provides a
coherent low-poly human silhouette, 21 modular outfits and 24 animation clips.
The researched GLBs (`Casual`, `Casual_Hoodie`, `Worker`) measure 4 meshes, 62
joints and 24 clips each. The owner directed that Quaternius become the NPC
base. The full evaluation is in [`docs/assets/npc-model-sourcing.md`](../assets/npc-model-sourcing.md).
## Decision
1. **Quaternius is the primary NPC mesh and animation source.** Keep the
licence and SHA-256 provenance for the three researched GLBs.
2. **Stage 1 keeps the runtime contract.** Bake a canonical Quaternius base onto
the existing 13-core contract, five tint slots, 24,000/24,000 budget,
grounded −Y front and one `npc_base` skinned mesh. Retarget Idle and Walk;
discard the combat/gun/sword clips. `NpcAvatar`, gear attach points and the
pose composition remain the runtime interface.
3. **The 62-joint rig is an authoring source, not a runtime dependency.** It is
not shipped and Quaternius is not loaded by CI, build or runtime.
4. **Stage 2 needs its own ADR.** If the proportion warp fails the silhouette,
deformation or gear gate, stop and decide whether to adopt the 62-joint rig
at runtime. Do not ship a hybrid rig or a second gear offset system.
5. **Close the MakeHuman/MPFB body work.** The accepted MakeHuman head and the
procedural `npc_base` stay as tested fallbacks until the Quaternius rollout
ships. No new MPFB development.
6. **Commit baked assets only.** The release consumes committed GLBs, maps and
the manifest; Quaternius and Blender remain development tools.
## Consequences
### Positive
- A human base, modular outfits and a coherent animation set are already
authored and CC0.
- The bespoke neck, hand and shoe pipelines are no longer on the critical path.
- The runtime contract and gear stay stable during the mesh migration.
### Negative
- A 62-joint T-pose does not share the arm-down 13-core rest pose or
proportions; the proportion warp is the main risk.
- Quaternius' animation quality is only available after retargeting, unless
Stage 2 is accepted.
- The migration touches all 12 variants, their AO maps, manifest entries and
baseline captures at once.
## Alternatives
- **Keep the procedural generator as the primary path.** Rejected by the owner:
the human silhouette remains the weak point and the bespoke part pipeline is
larger than the Quaternius bake.
- **Adopt the 62-joint rig immediately.** Deferred to Stage 2 because it changes
`NpcAvatar`, pose composition and gear offsets at the same time as the mesh.
- **Continue the MPFB body.** Rejected: it needs a separate head/neck/hand
pipeline and still has unresolved surface seams.
- **Use a service character generator (Mixamo, Ready Player Me).** Rejected:
redistribution and runtime terms are not a CC0 basis.
@@ -0,0 +1,98 @@
# ADR-0018: Quaternius Stage 2 — adopt source proportions at runtime
- **Status:** Accepted (2026-11-05, owner chose option 2)
- **Date:** 2026-11-05
- **Supersedes:** ADR-0017 decision 2 (Stage 1 keeps the 13-core contract)
## Context
ADR-0017 made Quaternius the NPC base and staged the migration: Stage 1 bakes a
proportion-warped mesh onto the existing 13-core contract; Stage 2 adopts the
62-joint rig at runtime only if the warp fails.
The Stage 1 proportion warp was executed and measured (`docs/assets/npc-model-sourcing.md`
§Rest-pose and proportion-warp measurement). The arm-down rest pose bakes cleanly, but the
warp to the contract proportions does not:
| Joint | Quaternius | Contract | Delta |
| --- | --- | --- | --- |
| Hips height | 0.869 | 0.62 | −0.249 |
| Shoulder x | 0.148 | 0.27 | +0.122 |
| Arm (shoulder→hand tip) | 0.429 | 0.70 | ×1.63 |
| Leg (hip→ankle) | 0.835 | 0.62 | ×0.74 |
| Torso (hip→head) | 0.745 | 1.20 | ×1.61 |
The vision judge reads the warped mesh as distorted: paddle/claw hands, forearms lost into the
torso, stretched shins, "long legs + short torso". The arm either stays short (a shortened arm
against the contract hand) or stretches 1.63× (a distorted deltoid + hand). Both are the gate's
rejection conditions.
## Decision
Stop the Stage 1 rollout and **adopt the Quaternius 62-joint rig at runtime** (owner chose
option 2). The mesh is not proportion-warped: it keeps its source LOD (3,199 welded verts /
6,206 tris) and only the arm-down rest pose is baked.
- `NpcAvatar` maps the Quaternius joint names instead of the 13-core names.
- Gear attach points are re-derived from the Quaternius skeleton (hip ≈0.87, shoulder ≈0.148/1.39,
wrist ≈0.99, knee ≈0.52).
- The 24 upstream clips ship as authoring reference only and are **not played at runtime**.
`NpcAvatar._animate()` drives the proxy pivots and `_sync_skeleton()` writes the bone poses, which
is what the FSM already needed for sitting, raising a hand and turning the head. Playing the clips
would replace that state machine rather than supplement it; revisiting this needs its own ADR.
Option 1 (keep the 13-core names with Quaternius rest positions) is rejected in favour of the
full source rig.
## Consequences
### Positive
- The Quaternius silhouette, deltoid, hand and leg proportions are preserved — no paddle hands,
no shortened arm, no torso/leg distortion.
- The mesh stays at source LOD (far under the 24,000 cap), so no decimation is needed.
### Negative
- The runtime contract numbers (hip 0.62, shoulder 0.27, hand 0.78) change; every gear attach
point, `npc_proportions` guide, fit measurement and pose-composition constant must be
re-derived and re-tested.
- `NpcAvatar`'s bone mapping and pose composition are rewritten for the 62-joint rig, a larger
change than the mesh swap.
- The 12-variant rollout and the 12×6 baseline are still blocked until the new rest positions
and gear fit are owner-approved.
## Alternatives
- **Ship the warped mesh.** Rejected by the gate: the 1.63× arm / 0.74× leg warp visibly
distorts and the owner directed keeping the Quaternius as close to source as possible.
- **Keep the old contract and accept a short arm.** Rejected for the same reason: the hand ends
at ≈0.99 instead of 0.78, so handheld gear floats unless attach points move — which is option 1.
- **Abandon Quaternius and keep the procedural generator.** Rejected in ADR-0017.
## Open question
Resolved: option 2 (62-joint runtime) is the owner's choice. The first implementation step is
the `NpcAvatar` bone-map + gear-attach re-derivation, then the slot/AO bake and the 12-variant
rollout.
## Follow-up decision: full roster swap
- **Date:** 2026-11-05 (owner, at the `0.9.9` face/silhouette gate)
The owner chose **option (a) full swap** from
the face/silhouette gate (its sheets were retired with the review pages): every roster character
moves onto the Quaternius base, and the procedural generator plus the MakeHuman head retire to
the tested fallback rather than staying in the shipped roster.
Scope consequences:
- The shipped roster keeps its twelve public character names and `CHARACTER_POOLS` mapping; the
geometry behind them comes from the three CC0 full-body sources already researched
(`Casual`, `Casual_Hoodie`, `Worker`), aliased per role.
- Variety now comes from the five tint slots, the gear library and the per-role outfit rules
instead of twelve distinct meshes. Roster silhouettes are therefore *less* varied than the
procedural library until the modular part library (hair, outfits) is added — tracked as a
`0.9.10` task, not hidden.
- The procedural library, `_build_body()` and the MakeHuman head stay in the tree and tested as
the instant fallback; no MPFB or Stage-1 proportion-warp work reopens.
+3
View File
@@ -19,3 +19,6 @@ Each ADR records the context, decision, consequences and alternatives for a dura
- [0013-blender-authored-npc-characters](0013-blender-authored-npc-characters.md)
- [0014-runtime-image-root](0014-runtime-image-root.md)
- [0015-npc-model-variety-sourcing](0015-npc-model-variety-sourcing.md)
- [0016-npc-character-budget-24k](0016-npc-character-budget-24k.md)
- [0017-quaternius-npc-base](0017-quaternius-npc-base.md)
- [0018-quaternius-stage2-runtime-rig](0018-quaternius-stage2-runtime-rig.md)
@@ -1,14 +1,14 @@
# 3D model review (2026-11-03)
Status: **baseline measured; scorecard open.** This is the working document for the unversioned
`3D model re-evaluation` track in [`TODO.md`](../TODO.md). It records what was measured, what the
`3D model re-evaluation` track in [`TODO.md`](../../TODO.md). It records what was measured, what the
Blender skill guidance says the targets are, the ranked candidate gaps, and the decisions that
still need the project owner. Nothing here re-opens the accepted 0.9.4 limits by itself.
Related documents: [`npc-visual-review.md`](npc-visual-review.md) (accepted 0.9.4 limits and
before/after sheets), [`npc-visual-review.md`](npc-visual-review.md#proportion-audit) (proportion guide),
[`blender-assets.md`](blender-assets.md) (asset contract), [`asset-tooling.md`](asset-tooling.md)
(commands).
Related documents: [`npc-model-sourcing.md`](npc-model-sourcing.md) (sources, shipped roster and
build steps), [`blender-assets.md`](blender-assets.md) (asset contract),
[`asset-tooling.md`](asset-tooling.md) (commands). The 0.9.4 procedural baseline this page was
measured against no longer ships; its before/after sheets stay in `blender_previews/`.
## Method and skill routing
@@ -85,10 +85,12 @@ Readings:
## Baseline inventory (2026-11-04)
Recorded for the Blender NPC model overhaul track: the exact starting point before the local
part pipeline is built. `npc_base.blend` is the frozen fallback; the 12 characters are assembled
procedurally by `tools/blender_assets.py`; the MakeHuman prototypes live under `tmp/npc-research/`
and are not the shipped path.
Recorded for the character baseline before the Quaternius migration. `npc_base.blend` is the
frozen fallback; the 12 characters are currently assembled procedurally by
`tools/blender_assets.py`. The active plan is now the CC0 Quaternius base bake
([ADR-0017](../adr/0017-quaternius-npc-base.md)); this section and the MakeHuman notes below are the
pre-migration record. The MPFB/MakeHuman development files were removed from `tmp/` after the
2026-11-05 pivot.
### `assets/models/npc/npc_base.blend` (frozen fallback)
@@ -143,7 +145,7 @@ width scale.
287–440 px/m via the 4× repeat; runtime tint carries the look. This is a recorded note until a
portrait shows texture starvation.
### MakeHuman prototypes (not shipped; `tmp/npc-research/makehuman/`)
### MakeHuman prototypes (historical, not shipped; research files removed from `tmp/`)
| File | Verts / tris | Bones | Slots | Note |
| --- | ---: | ---: | --- | --- |
@@ -193,7 +195,7 @@ capture). Pass conditions:
### Contract (both, every prototype)
- 16,000 triangles / 16,000 glTF vertices per character; gear stays at 1,500.
- 24,000 triangles / 24,000 glTF vertices per character; gear stays at 1,500.
- Optional extra bones are allowed; the required 13 core bones and their rest positions must not
move; the `npc_base` mesh node name and the five tint slots stay unchanged.
@@ -242,7 +244,7 @@ nose/lip/chin relief cleanly.
The judge then compared the displacement head against the **decimated MakeHuman head**
(extracted from `makehuman_retargeted.glb`, 2,009 verts / 1,573 tris, saved as
`tmp/npc-parts/makehuman_head.glb`) and returned a decisive result: **ship the MakeHuman head** —
the local `makehuman_head.glb`) and returned a decisive result: **ship the MakeHuman head** —
it keeps the nose/chin/jaw landmarks at a fraction of the cost, while the procedural head's
"clean ellipse outline instantly screams procedural sphere".
@@ -281,7 +283,98 @@ front/three-quarter/profile and judged side by side:
The chosen s48 is the `head_proto` default; the rejected s24/s64 stay local under
`tmp/npc-parts/`. A before/after sign-off sheet (current `_face` vs s48, 1.85 m
front/three-quarter/profile) is
[`blender_previews/sheet_head_proto_before_after.jpg`](blender_previews/sheet_head_proto_before_after.jpg).
[`blender_previews/sheet_head_proto_before_after.jpg`](../blender_previews/sheet_head_proto_before_after.jpg).
## Foliage language P1 — resolved 2026-11-06
The ranked P1 was that shrubs read as rocks: `_shrub()` stacked spheres, so the silhouette was
smooth and the light response was a single facet per clump.
`_leaf_card()` replaces the stack: one low-poly inner mass for opacity, then 18–53 two-triangle
quads scattered over the canopy shell by a jittered Fibonacci distribution, each rotated onto the
canopy normal and tilted off it. No alpha texture, so the flat-colour library and the Compatibility
renderer are untouched.
| Prop | Before | After |
| --- | --- | --- |
| `planter_box` | 1,324 tris | 818 |
| `round_planter` | 1,240 tris | 808 |
| `street_tree` | 2,592 tris | 1,506 |
| Props total (20) | 13,808 | 11,784 |
## Lighting pass — flashlight measured 2026-11-06
`capture_realism.gd --stages=late --flashlight` renders the same frame with the lamp off and on, so
the beam's contribution is a number instead of an impression. Mean luminance, 0–255:
| Region | Lamp off | Old settings | Shipped now |
| --- | --- | --- | --- |
| Aimed centre (facade) | 13.5 | 13.6 | **29.7** |
| Near pavement | 3.7 | 3.7 | **11.7** |
The old flashlight (energy 4.2, 20 m range, 14° cone, aimed dead ahead) moved the frame by 0.1/255 —
it was effectively off. The shipped values are 10 energy, 45 m, 24°, tilted 5° down: the beam lands
on the door or person being checked *and* puts a pool on the pavement in front, without flooding the
facade. Verified in both venues (Hollywood facade and the Joke Shop door).
### Street-lamp pools, measured
A new `lamp_late` shot frames a street lamp so the pool under it can be sampled. The lamp is
`StreetLamp_*` (named so `set_night_mode` can tune it apart from the sconce and marquee glows).
Attenuation stays at 1.0 — the venue test requires physical falloff — so the pool is made by range
and energy:
| Setting | Pool | Gap | Pool/gap |
| --- | --- | --- | --- |
| old: 16 m, energy 2.2 | 14.1 | 2.7 | 5.2 |
| 16 m, energy 4.0 | 21.1 | 6.5 | 3.3 (washed) |
| 8.5 m, energy 6.5 | 11.5 | 1.3 | 8.9 |
| **10 m, energy 8.0 (shipped)** | **16.0** | **1.3** | **12.3** |
Mean luminance 0–255. The shipped values brighten the pool past the old setting while darkening the
gap between poles, which is what "pools, not a wash" means numerically.
### Event banners read as lit cloth (2026-11-06)
The banners were one flat emissive panel, so they measured the same luminance from the mounting bar
to the hem (114/121/122/125 down the panel) and read as a painted red card rather than lit fabric.
They are now four stacked strips with a night gradient (energies 2.6 / 2.2 / 1.8 / 1.4), carried per
material through `night_energy` metadata so `set_night_mode` keeps the ratio instead of flattening it.
| | Before | After |
| --- | --- | --- |
| Vertical profile down a banner | 114 → 125 (flat) | 135 → 84 |
| Clipping (p99 / pixels ≥ 250) | 192 / 0.2 % | 192 / 0.2 % |
| Daylight read | uniform | uniform (strips flush, no seam) |
No clipping in either state, and the Compatibility renderer draws it with the same flat emissive
material as before — the change is geometry plus per-material energy, not a new shader.
## Set dressing — Joke Shop queue (2026-11-06)
The queue props were placed individually (`stanchion` at ±3, `crowd_barrier` at x 2.2, podium at 6.8),
so no line read and the stanchions' 0.9 m velvet stubs pointed in unrelated directions. They are now
one queue: four stanchions 0.9 m apart west of the guest approach lane, the check-in podium at the
head, and the barricade on the curb side. The line has to sit outside
`PROP_EXCLUSIONS["guest approach lane"]` (x ±1.4), which is what the placement validator enforces —
the first attempt put the podium at x 0.4 and the test caught it.
Readability at 8 m drove the thickness pass: bike-rack frame 22 → 28 mm, bars 10 → 12 mm, velvet rope
18 → 22 mm. The west planter also moved 1.6 m clear of the palm canopy, which was clipping its lip.
Measured at night afterwards: the entrance walkway sits at 20.7/255 against 3.0 on the side pavement,
so the door pool exists; the queue area itself is still unlit and stays queued as a follow-up.
### Hollywood and the TV Studio
Hollywood had one stanchion and one barricade, which read as stray street furniture; it now has the
same three-post rope line into the check-in podium, with a barricade on the curb.
The TV Studio had **never been validated**: `placement_problems()` was only applied to the Joke Shop
in its test, and running it on the studio reported six violations — three props at z 4.2–4.4 sat
inside the steps/door exclusion and outside the sidewalk bounds. They are re-placed as a rope line,
podium and two curb barricades, and `test_every_venue_placement_clears_the_sidewalk_and_the_approach`
now validates all three venues so the gap cannot reopen.
## Scorecard skeleton
@@ -498,6 +591,6 @@ and the full carded-cluster foliage pass is the one remaining owner-gated P1. No
- Review the assembled [`makehuman-head-review.md`](makehuman-head-review.md) prototype (hair cap and full-body silhouette) before rebuilding the 12 shipped character GLBs.
Tracked in [`TODO.md`](../TODO.md) `3D model re-evaluation`: the remaining `A. Baseline…` item is
Tracked in [`TODO.md`](../../TODO.md) `3D model re-evaluation`: the remaining `A. Baseline…` item is
this owner review; `B`/`C`/`D` carry the per-family work, and `E` adds the pose/weight,
collider-coverage and scorecard-coverage gates this document found missing.
+19
View File
@@ -0,0 +1,19 @@
# Asset Documentation
Asset contracts, pipelines, sourcing and reviews. These pages own the measured evidence; the
executable gates are `tools/blender_assets.py inspect|audit|fit`, `tools/npc_proportions.py` and
the capture scripts.
- [`blender-assets.md`](blender-assets.md) — Blender library operation, the character/gear/prop
contract, attach points and rebuild discipline.
- [`asset-tooling.md`](asset-tooling.md) — image/model pipelines, the optional Blender MCP setup
and the screenshot/vision gates.
- [`npc-model-sourcing.md`](npc-model-sourcing.md) — character-source evaluation, licence rules,
the Quaternius intake and the active NPC plan.
- [`3d-model-review.md`](3d-model-review.md) — measurements, per-asset scorecard, ranked gaps and
accepted limits.
- [`makehuman-head-review.md`](makehuman-head-review.md) — the retained MakeHuman fallback head,
its provenance and the review verdict.
Up: [`../README.md`](../README.md) · Product plan: [`../../PLAN.md`](../../PLAN.md) · Tasks:
[`../../TODO.md`](../../TODO.md).
@@ -2,7 +2,7 @@
Everything the game renders is produced or gated by the scripts below. Architecture-level contracts,
data flow and failure fallbacks are summarized in
[`architecture.md`](architecture.md#content-and-asset-pipeline-architecture); this page is the
[`architecture.md`](../project/architecture.md#content-and-asset-pipeline-architecture); this page is the
operational reference. Development-only outputs (AI concept sheets, Blender sources, raw AI fabrics)
are gitignored; the audited game assets are committed.
@@ -72,7 +72,7 @@ colours onto material roles (darkest → metal, warm saturated → wood, light g
stone, green → foliage). glTF stores colours in linear space, so the tool converts
the sRGB palettes before writing them. Re-run `build` and `godot --headless
--path . --import` after changing a prop. See
[ADR-0012](adr/0012-surface-materials-and-generated-props.md).
[ADR-0012](../adr/0012-surface-materials-and-generated-props.md).
Surface materials share one definition in `src/game/materials.gd`: named
roughness/metallic profiles per surface, plus the environment tune-up (ACES
@@ -81,12 +81,14 @@ tonemapping, glow, fog, colour grading) that the phase lighting applies.
## NPC character model
NPCs are moving from the procedural capsule rig to a skinned, UV-mapped base
character authored in Blender ([ADR-0013](adr/0013-blender-authored-npc-characters.md)).
character authored in Blender ([ADR-0013](../adr/0013-blender-authored-npc-characters.md)).
The active base is the CC0 Quaternius modular character, baked to the runtime contract
([ADR-0017](../adr/0017-quaternius-npc-base.md)).
`tools/npc_pipeline.py` builds `assets/models/generated/npc_base.glb` plus the
per-slot material maps. `NpcAvatar` instantiates that skinned model, tints its
five material slots from the seed-driven outfit, and drives the bones from the
existing animation code; the procedural rig remains the offline fallback (see
[ADR-0013](adr/0013-blender-authored-npc-characters.md) and
[ADR-0013](../adr/0013-blender-authored-npc-characters.md) and
[`blender-assets.md`](blender-assets.md)).
```bash
@@ -116,7 +118,7 @@ blotches; skin, hair and fixed gear keep AO. `palette` writes
`tools/blender_assets.py` models a larger library procedurally in Blender for the
v0.6.0 integration: **8 skinned NPC characters** (casual, jacket, coat, hi-vis vest,
dress, hoodie, firefighter, guard), each a drop-in for `npc_base.glb` (same bones,
joint positions and tint slots); **18 gear pieces** authored at head/hand/back/chest
joint positions and tint slots); **15 gear pieces** authored at head/hand/back/chest
attach points (caps, hood, helmet, backpack, SCBA tank, lanyard, phone, cup,
clipboard, umbrella, camera, sign, flashlight, wand, radio, …); and **20 props**
(octagonal bollard and bin, slatted bench, hydrant, news box, planters, street lamp,
@@ -129,14 +131,14 @@ with colliders/avoidance and drives their emissive parts from the day/night
cycle. The single `npc_base.glb` and primitive props remain offline fallbacks.
Contract and integration notes: [`blender-assets.md`](blender-assets.md).
Sourcing and expansion research (no external model is shipped yet):
[`npc-model-sourcing.md`](npc-model-sourcing.md) compares Quaternius, Kenney, Khronos and
MakeHuman sources against the character contract and records the 2026-11-03 direction
(procedural generator first, Quaternius reference, MakeHuman deferred).
Sourcing and migration plan: [`npc-model-sourcing.md`](npc-model-sourcing.md) records the
2026-11-05 direction (ADR-0017). Quaternius Ultimate Modular (CC0) is the primary NPC mesh
and animation source, baked to the existing 13-core contract; the procedural generator is
the fallback. Kenney/Khronos/MakeHuman remain evaluated references, not active bases.
| Characters | Props |
| --- | --- |
| ![characters](../docs/blender_previews/sheet_npc.jpg) | ![props](../docs/blender_previews/sheet_props.jpg) |
| ![characters](../blender_previews/sheet_npc.jpg) | ![props](../blender_previews/sheet_props.jpg) |
```bash
flatpak run org.blender.Blender --background --python "$PWD/tools/blender_assets.py" -- build
@@ -146,7 +148,7 @@ python3 tools/blender_assets.py sheet # docs/blender_previews/sheet_*.jpg
python3 tools/blender_assets.py audit # no Blender needed
python3 tools/blender_assets.py fit # gear-vs-body fit report
python3 tools/blender_assets.py texels # per-slot texel density (px/m) of the characters
# `build --head mh` selects the MakeHuman head; the default stays `face` until rollout.
# `build --head mh` selects the retained MakeHuman fallback head; the default is still `face`.
godot --headless --path . --import
```
@@ -188,9 +190,9 @@ Caveats:
### Intake adaptation (`adapt`)
`adapt` is the mechanical first half of an external-mesh intake (MakeHuman,
MPFB, downloaded GLB): import, apply transforms, ground the feet, weld seam
splits, decimate to the character budget, and export a GLB. It does **not** map
`adapt` is the mechanical first half of an external-mesh intake (Quaternius,
MakeHuman fallback, downloaded GLB): import, apply transforms, ground the feet,
weld seam splits, decimate to the character budget, and export a GLB. It does **not** map
the five tint slots or rebuild the 13-core-bone `npc_base` armature (optional extra bones are allowed) — those stay a
manual `retopology`/`rigging` step with a recorded second-rig contract if the
source rig cannot be retargeted:
@@ -198,14 +200,14 @@ source rig cannot be retargeted:
```bash
flatpak run org.blender.Blender --background \
--python "$PWD/tools/blender_assets.py" -- adapt \
--file "$PWD/tmp/npc-research/makehuman_base.glb" \
--out "$PWD/tmp/npc-research/makehuman_adapted.glb" \
--target-tris 16000
# prints: adapted makehuman_adapted.glb: 36972 -> 16000 tris (bones=N, meshes=1)
--file "$PWD/tmp/npc-research/quaternius/Casual.glb" \
--out "$PWD/tmp/npc-research/quaternius_adapted.glb" \
--target-tris 24000
# prints: adapted quaternius_adapted.glb: <source> -> 24000 tris (bones=N, meshes=1)
```
Run `inspect` on the adapted GLB before and after, and keep the procedural
generator as the fallback until a MakeHuman variant passes `audit`/`fit` and the
generator as the fallback until a Quaternius variant passes `audit`/`fit` and the
24-NPC budget.
- Numbers are Blender-side measurements. Triangles match `audit` on project assets; the seam-split
vertex count can differ by ±1 because the importer rounds normals. `audit` stays the single final
@@ -244,7 +246,7 @@ gate as `--reference` on `generate`.
`tools/refcollect.py` downloads images from DuckDuckGo image search into `tmp/research/<slug>/` for
development reference only. It applies **no licence gate** (rows are marked `local_only` /
`unchecked-local`); everything it fetches must never be committed or promoted into
[`screens/refs/`](screens/refs/README.md) without the normal sidecar licence + privacy gate. This
[`screens/refs/`](../screens/refs/README.md) without the normal sidecar licence + privacy gate. This
is the owner-authorised local-only override (TODO.md §3D model re-evaluation → A).
```bash
@@ -263,7 +265,7 @@ string); the UA alone is no longer enough to look like a browser.
### Reference-board research (`refboard`)
`tools/refboard.py` searches, fetches and documents Wikimedia Commons photos of a real location for
the [`screens/refs/`](screens/refs/README.md) boards. It is stdlib-only and never commits anything
the [`screens/refs/`](../screens/refs/README.md) boards. It is stdlib-only and never commits anything
itself: downloads land in `tmp/`, and moving a file into a board folder is a deliberate manual step
that goes through the sidecar licence gate.
@@ -300,12 +302,30 @@ python3 tools/blender_assets.py texels --json # machine-readable
python3 tools/blender_assets.py texels --only npc_coat
```
### Quaternius modular parts (outfit variety)
`tools/quaternius_parts.py` is the intake for the upstream modular pack, which ships as a Google
Drive folder and is therefore downloaded once by hand into `tmp/quaternius-intake/` (gitignored):
| Step | Command | Runs in |
| --- | --- | --- |
| list what the download contains | `python3 tools/quaternius_parts.py inventory --dir tmp/quaternius-intake` | plain Python (parses the GLB container) |
| cut one mesh out as a part | `... extract --file <glb> --mesh <name> --part <name>` | Blender (rewrites the skin) |
| hash and validate the kept parts | `... verify --dir assets/models/blender_src/quaternius/parts` | plain Python |
A part is one skinned mesh on the 62-joint rig; the contract and the join behaviour are in
`assets/models/blender_src/quaternius/parts/README.md`. `build` joins a role's
`CHARACTERS[...]["parts"]` onto its base body before the slot map, keeping the part's weights and
dropping its redundant armature. The pack is never committed — only the parts that are used, with
their SHA-256 in `CREDITS.md`.
## Local map development (planned)
The local map workstreams (H–M) in [`TODO.md`](../TODO.md#3d-model-re-evaluation) are
The local map workstreams (H–M) in [`TODO.md`](../../TODO.md#3d-model-and-local-map-re-evaluation) are
planned, not implemented; there are no map-generation commands yet. The runtime
contract, provenance rules, budget/navigation gates and fallback are in
[`architecture.md#venue-implementation-contract`](architecture.md#venue-implementation-contract).
[`architecture.md#venue-implementation-contract`](../project/architecture.md#venue-implementation-contract).
The detailed pipeline/task list lives in `TODO.md`.
## Confirmed game assets
@@ -315,9 +335,9 @@ Everything below is audited and shipped in the game; development-only outputs
| | |
| --- | --- |
| ![brick facade](../assets/textures/ai/game_ready/v2/picks/brick_facade.png) | ![sidewalk pavers](../assets/textures/ai/game_ready/v2/picks/sidewalk_pavers.png) |
| ![asphalt](../assets/textures/ai/game_ready/v2/picks/asphalt.png) | ![awning](../assets/textures/ai/game_ready/v2/picks/awning_canvas.png) |
| ![skyline day](../assets/textures/ai/game_ready/v2/picks/skyline_day.png) | ![skyline night](../assets/textures/ai/game_ready/v2/picks/skyline_night.png) |
| ![brick facade](../../assets/textures/ai/game_ready/v2/picks/brick_facade.png) | ![sidewalk pavers](../../assets/textures/ai/game_ready/v2/picks/sidewalk_pavers.png) |
| ![asphalt](../../assets/textures/ai/game_ready/v2/picks/asphalt.png) | ![awning](../../assets/textures/ai/game_ready/v2/picks/awning_canvas.png) |
| ![skyline day](../../assets/textures/ai/game_ready/v2/picks/skyline_day.png) | ![skyline night](../../assets/textures/ai/game_ready/v2/picks/skyline_night.png) |
- **Surface textures:** the v2 picks above (brick, sidewalk pavers, dry and wet asphalt, awning canvas) plus their normal maps, loaded by `src/game/materials.gd` and `WorldBuilder`; the three skyline panoramas are switched per shift phase. The first-generation tiles and `assets/textures/skyline.png` are no longer loaded.
- **UI art:** `assets/textures/ai/game_ready/icons/` (flashlight, door lock, wand, REC) and `assets/textures/ai/game_ready/cards/` (ID, wristband, ticket, credential, guest list), loaded by `src/game/ui/hud.gd`.
@@ -491,7 +511,7 @@ remain optional interactive exploration; the headless commands stay the build an
## Realism pass: scene concepts, skylines and textures
The skyline, surface tiles and phase lighting were rebuilt against AI concept frames. The
concepts live in [`docs/screens/concepts/`](../docs/screens/concepts/README.md); the validated
concepts live in [`docs/screens/concepts/`](../screens/concepts/README.md); the validated
picks the game loads are in `assets/textures/ai/game_ready/v2/picks/` (day/dusk/night
panoramas, brick, sidewalk pavers, dry and wet asphalt, awning canvas, each with a normal
map).
@@ -551,7 +571,7 @@ contract.
`tools/npc_proportions.py` checks the eight character GLBs against the shared
height/head/shoulder/hip/torso/leg/arm/foot guide; the current results are in
[`npc-visual-review.md`](npc-visual-review.md#proportion-audit). It reads the exported GLBs
[`3d-model-review.md`](3d-model-review.md#character-measurements). It reads the exported GLBs
and does not require Blender.
`capture_npc_pose.gd` is the pose/deformation harness for the 3D re-evaluation: idle,
@@ -576,7 +596,7 @@ camera, studio lighting and no venue/HUD/animation. The raw PNGs stay in
`tmp/`; `tools/npc_baseline.py sheet` builds the committed contact sheet, and
`tools/npc_baseline.py compare --before DIR --after DIR` builds the review
comparison after a model change. See
[`npc-visual-review.md`](npc-visual-review.md).
[`3d-model-review.md`](3d-model-review.md).
```bash
godot --path . --script res://src/test/capture_npc_baseline.gd -- \
@@ -613,7 +633,7 @@ texture detail 1.2, backdrop 2.0 and characters 1.2; the Pillow metric gap was
particularly lit night facades and dense backdrop detail. That is expected: the
pass validated close-range surfaces and promoted the texture repairs, not a
photoreal renderer. The 0.9.5 before/after close-up sheet is
[`blender_previews/sheet_texture_refinement_0.9.5.jpg`](blender_previews/sheet_texture_refinement_0.9.5.jpg);
[`blender_previews/sheet_texture_refinement_0.9.5.jpg`](../blender_previews/sheet_texture_refinement_0.9.5.jpg);
the texture-adoption run itself was the earlier 0.8-style candidate comparison,
and its report remains local/gitignored.
@@ -1,18 +1,21 @@
# Blender asset library
Architecture context: the asset contracts and fallback path are summarized in
[`architecture.md`](architecture.md#content-and-asset-pipeline-architecture).
[`architecture.md`](../project/architecture.md#content-and-asset-pipeline-architecture).
Status: built, audited, and integrated (2026-11-01). `NpcAvatar` selects the
Status: built, audited, and integrated (2026-11-01). The active character migration
replaces the procedural body with a baked CC0 Quaternius base
([ADR-0017](../adr/0017-quaternius-npc-base.md)); the current library remains the shipped
fallback until the Quaternius 12-variant baseline passes review. `NpcAvatar` selects the
character variants and attaches the gear; `WorldBuilder` loads the prop library
with colliders and phase-driven emissives. The 0.9.4 neutral baseline and its
acceptance criteria are in [`npc-visual-review.md`](npc-visual-review.md);
acceptance criteria are in [`architecture.md`](../project/architecture.md#character-and-gear-asset-contract);
the committed 8 × 6 contact sheet is
[`blender_previews/sheet_npc_baseline.jpg`](blender_previews/sheet_npc_baseline.jpg).
[`blender_previews/sheet_npc_baseline.jpg`](../blender_previews/sheet_npc_baseline.jpg).
Generator: [`tools/blender_assets.py`](../tools/blender_assets.py). Manifest (the
Generator: [`tools/blender_assets.py`](../../tools/blender_assets.py). Manifest (the
source of truth for integration):
[`assets/models/blender/manifest.json`](../assets/models/blender/manifest.json).
[`assets/models/blender/manifest.json`](../../assets/models/blender/manifest.json).
## Art direction
@@ -63,7 +66,7 @@ flatpak run org.blender.Blender --background \
flatpak run org.blender.Blender --background \
--python "$PWD/tools/npc_parts.py" -- extract --part hand_l --variant npc_casual \
--out "$PWD/tmp/npc-parts/npc_casual/hand_l.glb"
# Assemble a variant (currently rebuilds the procedural character)
# Assemble a variant (current fallback path; Quaternius migration in progress)
flatpak run org.blender.Blender --background \
--python "$PWD/tools/npc_parts.py" -- assemble --variant npc_casual \
--out "$PWD/tmp/npc-parts/npc_casual/assembled.glb"
@@ -139,10 +142,22 @@ render about 2.5 min.
## Characters
All library variants share the [character and gear asset contract](architecture.md#character-and-gear-asset-contract):
`npc_base` mesh node, required 13 core bones (optional extras allowed), five
tint slots, +Z visual front, 16,000/16,000 character budget and the same 256²
slot-map/AO rules. Role selection and look notes:
All library variants share the
[character and gear asset contract](../project/architecture.md#character-and-gear-asset-contract):
`npc_base` mesh node, five tint slots, +Z visual front, 24,000/24,000 character budget and the
same 256² slot-map/AO rules. The shipped roster is on the 62-joint Quaternius skeleton
(ADR-0018); the procedural fallback built by `build --source procedural` keeps the 13 core bones.
Both are accepted by `audit`, `inspect`, the runtime bone map and the tests.
The three Quaternius sources (`casual`, `hoodie`, `worker`) live in
`assets/models/blender_src/quaternius/` as build inputs. `build` (default
`--source quaternius`) does a two-pass bake per character: a cached T-pose round trip that joins
without welding, maps the upstream materials onto the five slots and unwraps the degenerate
source UVs, then an arm-down rest bake exported with `export_apply=False`. The per-character slot
map, triangle counts and measurements are in
[`npc-model-sourcing.md#shipped-roster-099-owner-chose-the-full-swap`](npc-model-sourcing.md#shipped-roster-099-owner-chose-the-full-swap).
Role selection and look notes (tint + gear now carry the role, not the mesh):
| Character | `layer_for()` / look | Suggested roles | Preview gear |
| --- | --- | --- | --- |
@@ -161,6 +176,22 @@ colour texture. The current `_apply_outfit_materials()` sets
`albedo_color = WHITE` on any slot it does not recognise, and these keep their
colour through that. When integrating, tint only the five contract slots.
**Hair part library.** Each base ships one hair shell and the build reshapes it in place
(`QUATERNIUS_HAIR_PARTS`): `short` is identity, `buzz` squashes toward the hairline, `long` stretches
from the crown. The role picks the style through `CHARACTERS[...]["hair"]`, and the T-pose cache is
keyed on it. `bald` is only allowed on the `casual` and `hoodie` bases, where the skin closes the
skull; the modular Worker's head stops at the hairline, so removing its hair would open the crown.
**Face detail.** None of the three Quaternius heads ships a mouth or eye whites, so the build adds
both: `_add_quaternius_mouth()` places a lip block on the measured skin surface, and
`_add_quaternius_eye_whites()` renames the eye quads to `sclera` and adds a shrunken `pupil` copy in
front of each. Both are fixed-colour (not tint slots), so they survive the role palettes.
**Head gear fit.** Head gear is authored for the shipped Quaternius head:
`HEAD_GEAR_SCALE = 0.64` (0.201 m base head against the 0.315 m procedural one) and
`HEAD_GEAR_LIFT = 0.07` (its centre sits higher). The procedural fallback therefore wears slightly
undersized caps — cosmetic and fallback-only.
**Runtime tint notes (implemented).** Only the five contract slots are tinted;
fixed detail materials keep their authored colour. On `npc_vest` the vest is the
fixed `hivis` material and `cloth` is the undershirt, so the yellow override is
@@ -170,7 +201,42 @@ the role's `TYPE_COLORS`.
## Gear attach points
Gear is authored in attach-point space; the exact contract and runtime fit offsets are in
[`architecture.md#character-and-gear-asset-contract`](architecture.md#character-and-gear-asset-contract).
[`architecture.md#character-and-gear-asset-contract`](../project/architecture.md#character-and-gear-asset-contract).
The shipped matrix is **fifteen pieces** since the hat removal (owner, 2026-11-06): `cap` and
`hood` are retired, and `firefighter_helmet` is the only head item.
| Attach | Pieces |
| --- | --- |
| head | `firefighter_helmet`, `sunglasses` |
| back | `backpack`, `shoulder_bag`, `scba_tank` |
| chest | `lanyard` |
| hand | `phone`, `cup`, `clipboard`, `umbrella`, `camera`, `protest_sign`, `flashlight`, `wand`, `radio` |
### Hand-item fit on the Quaternius rig
The hand attach point moved from Godot y 0.78 (procedural wrist) to **y 1.017** (Quaternius
wrist), so `fit` measures hand gear against the new wrist instead of the authored attach offset.
Run `blender_assets.py fit`; per item it reports the grip drop, the lowest point at rest, whether
that clears the hip line (0.95) and `size_vs_head` — the proportion that makes "reads oversized"
measurable on the 0.20 m head.
| Item | Drop (m) | Lowest at rest | Clears hip | Longest | × head |
| --- | --- | --- | --- | --- | --- |
| `camera` | 0.053 | 0.964 | yes | 0.138 | 0.69 |
| `phone` | 0.105 | 0.912 | no | 0.150 | 0.75 |
| `cup` | 0.110 | 0.907 | no | 0.142 | 0.71 |
| `radio` | 0.108 | 0.909 | no | 0.203 | 1.01 |
| `flashlight` | 0.077 | 0.940 | no | 0.243 | 1.14 |
| `wand` | 0.125 | 0.892 | no | 0.400 | 1.87 |
| `umbrella` | 0.201 | 0.816 | no | 0.900 | 4.48 |
| `clipboard` | 0.375 | 0.642 | no | 0.305 | 1.63 |
| `protest_sign` | 0.250 | 0.767 | no | 1.230 | 6.12 |
Falling below the hip line is normal for a carried object; the number that matters is whether the
item was *authored* for the new grip. Only the `clipboard` was: its grip sat in the middle of the
board, so it swung through the thigh. It now grips the top edge (0.22 × 0.30 m) like a carried
clipboard, and `HAND_ITEM_AUTHORED_SIZE` in the tool flags any future drift past 10 %.
## Props
@@ -200,7 +266,7 @@ carry baked AO and the shared neutral material maps described above.
- `python3 tools/blender_assets.py audit`: container, `POSITION`/`NORMAL`/
`TEXCOORD_0`, UVs in [0, 1], no zero-area triangles (Godot warns about them
during LOD generation), budgets (characters 16000/16000, gear 1500, props 4000
during LOD generation), budgets (characters 24000/24000, gear 1500, props 4000
triangles), grounding, and an editable `.blend`. For characters it also
checks skinning, bones, slots, the `npc_base` mesh node and the height.
- `tools/tests/test_blender_assets.py`: catalogue and contract consistency with
@@ -212,7 +278,7 @@ carry baked AO and the shared neutral material maps described above.
`npc_base`, the bones accept `NpcAvatar`'s pose composition, and props are
grounded.
- `tools/test_model_review.py`: every `CHARACTERS`/`GEAR`/`PROPS` entry has a
scorecard row and verdict in `docs/3d-model-review.md` (coverage gate).
scorecard row and verdict in `docs/assets/3d-model-review.md` (coverage gate).
- `src/test/tests/test_world.gd`: every library prop that blocks walking has a
`StaticBody3D` + `NavigationObstacle3D`, checked against the catalogue
(collider/proxy gate).
@@ -235,4 +301,4 @@ carry baked AO and the shared neutral material maps described above.
chin/cheekbone, nose, lips) but its `seg=18/rings=12` head still reads
somewhat faceted at portrait range; a subdivision/deeper-sculpt prototype is
gated on the owner scorecard review. The full ranked list and measurements are
in [`npc-visual-review.md`](npc-visual-review.md).
in [`3d-model-review.md`](3d-model-review.md).
@@ -1,19 +1,19 @@
# MakeHuman head prototype
Status: **owner-accepted head, assembled prototype, not yet shipped.**
The owner accepted the basic human head on 2026-11-04. The automated vision gate
Status: **retained fallback; superseded as the active NPC head by the Quaternius
base (ADR-0017).** The owner accepted the basic human head on 2026-11-04. The automated vision gate
still records REJECT on the eye/lid region as deferred polish. The asset is a
standalone head/neck extracted from the CC0 MakeHuman base in
`tmp/npc-research/makehuman/base.obj`; the assembled path now adds hair, a hidden
scalp trim and the procedural body. The 12 shipped GLBs have not been rebuilt
with it yet.
standalone head/neck extracted from the CC0 MakeHuman base. The assembled path
adds hair, a hidden scalp trim and the procedural body. The 12 shipped GLBs have
not been rebuilt with it, and the Quaternius migration replaces it as the active
base. The development source files were removed from `tmp/` on 2026-11-05.
## Asset
- GLB: [`assets/models/blender_src/makehuman_head.glb`](../assets/models/blender_src/makehuman_head.glb)
- Review sheet: [`blender_previews/sheet_makehuman_head.jpg`](blender_previews/sheet_makehuman_head.jpg)
- Source workflow (development-only): `tmp/npc-research/build_makehuman_head.py`
— extracts the MakeHuman head, cuts it at the neck, keeps the head/eye/mouth
- GLB: [`assets/models/blender_src/makehuman_head.glb`](../../assets/models/blender_src/makehuman_head.glb)
- Review sheet: [`blender_previews/sheet_makehuman_head.jpg`](../blender_previews/sheet_makehuman_head.jpg)
- Source workflow (development-only, files removed after the Quaternius pivot;
retained here as the historical method) — extracts the MakeHuman head, cuts it at the neck, keeps the head/eye/mouth
components, cuts an almond aperture through a skin eyelid mask, adds recessed
eyeballs with flat iris/pupil discs, anchors brows to the face surface, renders
front/three-quarter/profile and exports the standalone GLB.
@@ -26,7 +26,7 @@ with it yet.
- Materials used: `skin`, `eye_white`, `iris`, `pupil`, `hair`. No textures are
baked into this prototype.
![MakeHuman head review sheet](blender_previews/sheet_makehuman_head.jpg)
![MakeHuman head review sheet](../blender_previews/sheet_makehuman_head.jpg)
## What was done
@@ -53,10 +53,11 @@ with it yet.
## Provenance
- Base mesh: MakeHuman / MPFB base, CC0, from the local research set
`tmp/npc-research/makehuman/`; see [`CREDITS.md`](../CREDITS.md).
(development source files removed after the 2026-11-05 Quaternius pivot); see
[`CREDITS.md`](../../CREDITS.md).
- The head is a **derived prototype**, not a shipped NPC. It does not enter
`assets/models/blender/npc/`, `npc_base`, the runtime `NpcAvatar` path, CI, or
a release package until the NPC overhaul plan accepts it.
a release package. It is retained as a fallback, not the active NPC base.
- Source photographs/proportions are not used as textures here; this is a
geometry-only head built from the researched model data.
@@ -123,8 +124,8 @@ than a body-welded seam.
- The procedural body was narrowed at the neck and shoulders (chest 0.158,
neck base 0.060, neck top 0.054, shoulder root z 1.345) and its skin decimate
dropped to 0.21 so all 12 variants fit the 16,000 cap.
- Local review renders: `tmp/npc-parts/prototype_mh/renders/` (portrait
front/three-quarter/profile and full-body front/three-quarter).
- Local review renders were removed with the 2026-11-05 `tmp/` cleanup; the
committed review sheet above is the retained evidence.
## Deferred polish
+380
View File
@@ -0,0 +1,380 @@
# NPC Model Sourcing
This page records the source evaluation and the active character plan. The
decision is [ADR-0017](../adr/0017-quaternius-npc-base.md), which supersedes the
generator-first sourcing decision in [ADR-0015](../adr/0015-npc-model-variety-sourcing.md).
## Active direction
**Quaternius Ultimate Modular Characters (CC0) is the primary NPC mesh and
animation source.** The project-owned procedural library remains the shipped
fallback until the Quaternius migration passes the silhouette and gear gates.
The migration keeps the runtime contract that Godot, gear and tests already
consume:
- one `npc_base` skinned mesh under the 13 required core bones (optional extras
allowed);
- five tint slots: `skin`, `cloth`, `pants`, `accessory`, `hair`;
- front on Blender −Y / Godot +Z, feet grounded, height about 1.81 m;
- 24,000 triangles / 24,000 glTF vertices per character;
- gear stays at 1,500 triangles and props at 4,000;
- committed GLBs and maps only; no Quaternius, Blender or network dependency in
CI, build or runtime.
### Stage 1 (default)
1. Import the researched Quaternius GLBs and choose a canonical base.
2. Map the 62 source joints to the 13-core contract and bake a proportion warp.
3. Skin the mesh, retarget Idle and Walk, and verify seated/arm-down poses.
4. Map the five slots, unwrap and bake 256² maps.
5. Fit the existing gear and render the silhouette gate.
6. Build the 12 variants, audit, and capture the 12 × 6 baseline.
The Quaternius 62-joint rig and its 24 animation clips are an **authoring
source**. They are not loaded at runtime.
### Stage 2 gate
The 62-joint T-pose source does not share the project's arm-down rest pose or
proportions. If the Stage 1 proportion warp cannot preserve the Quaternius
silhouette and deformation, stop the rollout and write a new ADR for adopting
the 62-joint rig at runtime. Do not ship a hybrid rig, a second gear offset
system or a silent `NpcAvatar` change.
## Research findings
The researched files are the three converted Quaternius outfits used by the
Ducz Character Creator: `Casual`, `Casual_Hoodie` and `Worker`. They are kept
locally in `tmp/npc-research/quaternius/` with the licence and mirror notes.
| File | SHA-256 | Structure |
| --- | --- | --- |
| `Casual.glb` | `bc2d84fba249ebaa0629cb9d133ad37234196e4b8004aa205a6397abed04e05c` | 4 meshes, 62 joints, 24 clips, 7 materials |
| `Casual_Hoodie.glb` | `f5b722199f7628b24550989af4230f65d5230727df9c326fd2b3e360effe5249` | 4 meshes, 62 joints, 24 clips, 7 materials |
| `Worker.glb` | `8d0f454336c2effc5c08f63a177af3a82d1a7af025ca9588b40e4c90c4703534` | 4 meshes, 62 joints, 24 clips, 11 materials |
Source: [Quaternius Ultimate Modular Characters](https://quaternius.com/packs/ultimatemodularcharacters.html)
and [Ultimate Modular Women](https://quaternius.com/packs/ultimatemodularwomen.html),
CC0 1.0. Download date: 2026-11-03 (via the Ducz Character Creator browser export).
The Ducz mirror is a browser builder over the same packs; it adds 21
outfits and a shared skeleton. The three full GLBs are the initial scope; the
21-part builder is a fallback for role coverage, not the default.
**Initial outfit scope (2026-11-05):** the three full GLBs (`Casual`,
`Casual_Hoodie`, `Worker`) are the canonical-base and silhouette-gate scope.
They cover only ~3 of the 12 roles (casual, hood, vest); the jacket, coat,
dress, responder (firefighter) and guard looks are not in the three GLBs, so
§4 roster coverage must pull those from the 21-part modular builder or author
new clothing. Do not start the modular builder until the canonical base passes
§3.
The first prototype measured 12,518 imported vertices, 3,199 after welding and
2,423 vertices / 4,654 triangles after a 0.75 decimate. Idle and Walk read well.
The source is a T-pose with a 62-joint realistic rig, roughly 0.96 m hip,
1.68 m arm span and 0.153 m shoulder offset, so a contract bake is required.
The 24,000 cap leaves room to stay much closer to the source LOD than the
prototype's 4,654 triangles. Do not decimate to the old 7,000-triangle target
before the silhouette gate.
## Quaternius GLB inventory (2026-11-05)
All three GLBs share one 62-joint rig and the same 24 animation clips; only the meshes and
materials differ. Each import also adds a 42-vert/80-tri `Icosphere` bone-display helper — ignore it.
### Meshes (verts / tris)
| GLB | Body | Feet | Head | Legs | Total |
| --- | --- | --- | --- | --- | --- |
| `Casual` | 5,338 / 2,654 | 1,082 / 538 | 5,122 / 2,526 | 1,426 / 706 | 12,968 / 6,424 |
| `Casual_Hoodie` | 6,132 / 3,048 | 1,024 / 512 | 3,836 / 1,888 | 1,526 / 758 | 12,518 / 6,206 |
| `Worker` | 6,074 / 3,018 | 928 / 464 | 1,862 / 936 | 1,670 / 822 | 10,534 / 5,240 |
### Joints (62)
- Spine: `Root, Hips, Torso, Body, Abdomen, Chest, Neck, Head` (8).
- Arms: `Shoulder.L/R, UpperArm.L/R, LowerArm.L/R, Wrist.L/R` (8) plus `PT.L/R` (2 pole targets).
- Fingers: `Thumb×3, Index×4, Middle×4, Ring×4, Pinky×4` × L/R (30).
- Legs: `UpperLeg.L/R, LowerLeg.L/R, Foot.L/R` (6).
### Animation clips (24)
`Idle, Idle_Neutral, Walk, Run, Run_Back, Run_Left, Run_Right, Wave, Interact, Death,
Gun_Shoot, Idle_Gun, Idle_Gun_Pointing, Idle_Gun_Shoot, Idle_Sword, Run_Shoot, Sword_Slash,
HitRecieve, HitRecieve_2, Kick_Left, Kick_Right, Punch_Left, Punch_Right, Roll`.
The retarget scope is Idle and Walk; combat/gun/sword clips are discarded (see §2).
### Material → slot map
The five project slots (`skin`, `cloth`, `pants`, `accessory`, `hair`) are assigned by mesh
region first, then material — the same material name can mean `cloth` on the body and
`accessory` on the feet.
| Material | Where | Project slot |
| --- | --- | --- |
| `Skin` | all meshes | `skin` |
| `Hair_Blond`, `Hair_Brown`, `Hair`, `Brown` (head), `Eyebrows`, `Moustache` | Head | `hair` |
| `Eye` | Head | `accessory` |
| `Worker_Yellow` | Worker body (vest stripe) + head (helmet) | `cloth` / `accessory` |
| `White`, `Grey`, `Purple`, `Black` | Body / Feet | `cloth` (body) / `accessory` (feet) |
| `Orange`, `LightBlue`, `LightBrown`, `Brown`, `Brown2` | Legs | `pants` |
| `Worker_Vest` | Worker body | `cloth` |
### Canonical base (built 2026-11-05)
`tmp/npc-research/quaternius_base.glb` is the welded, triangulated, grounded, animation-free
canonical base built from `Casual_Hoodie.glb` (the most detailed body) by
`tmp/npc-research/build_quaternius_base.py`:
- one `npc_base` mesh — 3,199 welded verts / 6,206 tris (Body + Feet + Head + Legs joined);
- 62 joints, skinned (no unskinned faces);
- height 1.81 m, feet at y 0, front on Godot +Z / Blender −Y (T-pose rest);
- no animation clips; `inspect` clean (no issues).
This is the §2 contract-bake input: the 62-joint rig is authoring-only and is mapped to the
13-core contract next, not shipped as-is.
## 62-joint → 13-core joint map (2026-11-05)
The Quaternius hierarchy (measured from `quaternius_base.glb`):
- `Root → Body → Hips → Abdomen → Torso → Chest → Neck → Head` (spine);
- `Chest → Shoulder.L/R → UpperArm.L/R → LowerArm.L/R → Wrist.L/R → fingers` (arms);
- `Body → UpperLeg.L/R → LowerLeg.L/R` and `Root → Foot.L/R` (legs — the foot is a separate
child of Root, not of LowerLeg);
- `Root → PT.L/R` (IK pole targets, no deforming weights).
The contract is 14 bones (13 core + `Hips` root): `Hips, Spine, Neck, Head, Shoulder.L/R,
Elbow.L/R, Hand.L/R, Hip.L/R, Knee.L/R`. The map:
| Contract bone | Quaternius source | Notes |
| --- | --- | --- |
| `Hips` | `Hips` | `Root` + `Body` collapse into `Hips` |
| `Spine` | `Abdomen`, `Torso`, `Chest` | three collapse into one |
| `Neck` | `Neck` | |
| `Head` | `Head` | |
| `Shoulder.L/R` | `UpperArm.L/R` | the collar `Shoulder.L/R` collapses into `Spine` |
| `Elbow.L/R` | `LowerArm.L/R` | |
| `Hand.L/R` | `Wrist.L/R` | |
| `Hip.L/R` | `UpperLeg.L/R` | |
| `Knee.L/R` | `LowerLeg.L/R` | |
Optional extras (allowed by the contract; kept if they survive within 24,000 vertices):
- the 30 finger bones (`Thumb×3, Index×4, Middle×4, Ring×4, Pinky×4` × L/R) → optional finger
bones;
- `Foot.L/R` → optional toe bones.
Dropped (never shipped): `PT.L/R` (pole targets carry no deforming weights), and the
`Root`/`Body`/collar-`Shoulder` collapse bones above.
## Rest-pose and proportion-warp measurement (2026-11-05)
The rest-pose bake (T-pose → arm-down) works: rotate the `UpperArm.L/R` pose bones −90° around
their local X, apply the Armature modifier to bake the deformation, then `armature_apply` to bake
it as the new rest pose (see `tmp/npc-research/warp_full.py`). The mesh deforms cleanly to the
arm-down pose (deformed bounds x ±0.221 vs the T-pose ±0.811).
The proportion warp to the contract positions is measured and it **distorts the silhouette**:
| Joint | Quaternius | Contract | Delta |
| --- | --- | --- | --- |
| Hips height | 0.869 | 0.62 | −0.249 (lower hip) |
| Head top | 1.614 | 1.82 | +0.206 (raise head) |
| Shoulder x | 0.148 | 0.27 | +0.122 (widen) |
| Arm (shoulder→wrist) | 0.402 | 0.60 | ×1.49 |
| Arm (shoulder→hand tip) | 0.429 | 0.70 | ×1.63 |
| Leg (hip→ankle) | 0.835 | 0.62 | ×0.74 |
| Torso (hip→head) | 0.745 | 1.20 | ×1.61 |
The vision judge reads the warped mesh as: paddle/claw hands (the 1.63× arm stretch blows the
hand out), forearms lost into the torso, stretched shins, and "long legs + short torso". The arm
must either stay short (a "shortened arm" vs the contract hand) or stretch 1.63× (a distorted
deltoid + hand) — both are the gate's rejection conditions.
**Finding:** the Stage 1 proportion warp cannot preserve the Quaternius silhouette at the
contract proportions; the gate fails and Stage 2 (a 62-joint runtime ADR) is indicated. Do not
start the 12-variant rebuild on the warped base.
[ADR-0018](../adr/0018-quaternius-stage2-runtime-rig.md) records the Stage 2 decision (accepted
2026-11-05, owner chose option 2): adopt the **Quaternius 62-joint rig at runtime**, keep the
mesh at source LOD, re-derive gear attach points from the Quaternius skeleton, and use the
Quaternius Idle/Walk clips directly (no retarget).
## Pilot bake and shipped state (2026-11-05)
`npc_casual` is the first Quaternius-derived character. The reproducible pipeline lives in
`tmp/npc-research/` (local tooling, not shipped) and has two steps:
1. `build_base_minimal.py` — import `quaternius/Casual_Hoodie.glb`, join the four skinned meshes
**without welding**, rename the upstream materials to the project tint slots, Smart-UV-unwrap
and repack, export `quaternius_tpose.glb`.
2. `bake_armdown_v5.py` — pose `UpperArm.L/R` −90° local X, read the posed matrices, apply the
Armature modifier, **reset the pose to identity**, set the rest matrices, re-add the modifier,
export `quaternius_base.glb` and save `assets/models/blender_src/npc_casual.blend` for the AO
bake.
Then `tools/bake_ao.py --only npc_casual` and a copy of the GLB to
`assets/models/blender/npc/npc_casual.glb`.
| Measurement | npc_casual (Quaternius) | procedural library |
| --- | --- | --- |
| Triangles | 6,206 | 4,812–6,046 |
| glTF vertices | 12,988 | 4,908–5,785 |
| Bones | 62 | 13 |
| Head height / body height | 0.134 | 0.16–0.22 (stylized band) |
| Shoulder width | 0.201 m head width, `fit` OK | `fit` OK |
| Texel density (256² maps) | 73–74 px/m | 75–96 px/m |
| Materials | `skin`, `cloth`, `pants`, `hair`, `accessory` + fixed `Eye`, `Eyebrows` | five slots + fixed detail |
Two source quirks shaped the bake:
- the upstream UV map is degenerate (every loop at 0,0) and its materials are flat colours, so the
AO/texture bake must follow a real unwrap or it silently writes a black map;
- the upstream materials are named `Skin`/`Purple`/`LightBlue`/`White`/`Hair`, so the five-slot
contract is applied as a rename, not a re-author.
The face/silhouette gate that chose the full swap is recorded in the follow-up decision of
[ADR-0018](../adr/0018-quaternius-stage2-runtime-rig.md); its comparison sheets were retired with the
review pages.
## Shipped roster (0.9.9, owner chose the full swap)
Every public character name is baked from one of the three CC0 sources. The build is
`tools/blender_assets.py build` (default `--source quaternius`); the sources live in
`assets/models/blender_src/quaternius/` and the geometry pipeline is two passes:
1. `_quaternius_tpose_glb()` — import, drop the Icosphere helper, join **without welding**,
repoint the upstream materials onto the five tint slots, Smart-UV-unwrap + repack, export an
intermediate T-pose GLB. The round trip also normalises the mirrored upstream bone rolls,
which is what makes the next pass symmetric.
2. `_bake_quaternius_rest()` — pose `UpperArm.L/R` -90° local X, read the posed matrices, apply
the Armature modifier, reset the pose, write the rest matrices, re-add the modifier, export
with `export_apply=False`.
Then `tools/bake_ao.py --only <name>`.
| Character | Source | Tris | Material slots |
| --- | --- | --- | --- |
| `npc_casual` | hoodie | 6,206 | skin, cloth, pants, hair, accessory + Eye, Eyebrows |
| `npc_jacket` | casual | 6,424 | five slots + eyes/brows |
| `npc_coat` | hoodie | 6,206 | five slots + eyes/brows |
| `npc_vest` | worker | 5,240 | five slots + hivis vest/hat, eyes, moustache |
| `npc_dress` | casual | 6,424 | five slots + eyes/brows |
| `npc_hoodie` | hoodie | 6,206 | five slots + eyes/brows |
| `npc_firefighter` | worker (vest + hat dropped) | 4,458 | five slots + eyes, moustache |
| `npc_guard` | worker (vest + hat dropped) | 4,458 | five slots + eyes, moustache |
| `npc_crowd_a` | casual | 6,424 | five slots + eyes/brows |
| `npc_crowd_b` | casual | 6,424 | five slots + eyes/brows |
| `npc_crowd_c` | hoodie | 6,206 | five slots + eyes/brows |
| `npc_crowd_d` | worker (vest + hat dropped) | 4,458 | five slots + eyes, moustache |
Source slot maps (`QUATERNIUS_SOURCES`): the `casual` tee is `Skin`/`White`/`Orange`/`Grey`/
`Hair_Blond`; the hoodie is `Skin`/`Purple`/`LightBlue`/`Hair`/`White`; the worker is `Skin`/
`LightBrown`/`Brown`+`Brown2`/`Grey`+`Black`/`Eyebrows`. Everything not in the map keeps its
authored colour (eyes, brows, moustache, hivis vest and hard hat), so the contract still holds if
upstream adds a material — it shows up as an extra fixed-colour slot instead of vanishing.
Head gear is authored for this head: `HEAD_GEAR_SCALE = 0.64` and `HEAD_GEAR_LIFT = 0.07` map the
0.315 m procedural head onto the 0.201–0.214 m Quaternius head. The procedural fallback therefore
wears slightly small hats.
## Modular outfit intake (2026-11-06)
The owner downloaded the *Ultimate Modular Men* pack once (CC0 1.0, 54.5 MB zip, 15 outfit families
plus weapons and a horse) into the gitignored `tmp/quaternius-intake/`. The pack ships FBX, not GLB,
so the intake composes each family into a single skinned base:
python3 tools/quaternius_parts.py make-base \
--family "tmp/quaternius-intake/Ultimate Modular Men- Feb 2022/Separate Skeletal Meshes and Animations/Suit" \
--out assets/models/blender_src/quaternius/Suit.glb
What `make-base` has to undo, and why it is not a straight import:
1. each of the four FBX files carries its own copy of the armature — one is kept and the meshes are
repointed at it, otherwise `join` leaves three meshes bound to deleted armatures;
2. the FBX rig adds zero-length `_end` leaf bones and a `neutral_bone` root; Godot's importer fails
the exported GLB with them (`resource_format_binary` error), so they are stripped back to the
accepted 62 joints;
3. the object transforms are baked before export, or the glTF node transforms change the rest pose
on import and the character renders with a giant head;
4. the pack reuses one fabric material for jacket and trousers, so the leg meshes get their own
`*_legs` copies that the slot map sends to `pants`;
5. imported parts share seams, which leaves zero-area triangles the audit rejects.
The pack itself is never committed. Only the composed bases are, with their SHA-256 here and in
`CREDITS.md`.
| Base | Source family | SHA-256 | Used by |
| --- | --- | --- | --- |
| `Suit.glb` | Suit | `674f2a63…` | `npc_coat` |
| `Adventurer.glb` | Adventurer | `062caf69…` | `npc_crowd_c` |
| `Beach.glb` | Beach | `81c69837…` | `npc_crowd_a` |
| `Casual_2.glb` | Casual_2 | `fe4edb73…` | `npc_jacket` |
| `Farmer.glb` | Farmer | `b9b67058…` | `npc_crowd_b` (hair slot patched) |
| `King.glb` | King | `85aae2a0…` | `npc_dress` |
| `Punk.glb` | Punk | `56993274…` | `npc_hoodie` (the mohawk is the `Red` material) |
| `Swat.glb` | Swat | `43659684…` | **not used** — authored facing the other way; see below |
The roster therefore runs **eleven distinct outfits across twelve roles** (the worker base serves
`npc_vest`, `npc_firefighter`, `npc_guard` and `npc_crowd_d`).
### Open: the Swat base faces backwards
`Swat.glb` is authored facing Godot −Z. Rotating the exported base about world Z rotates the skin
with the armature node and the character renders headless, and rotating the mesh as well collapses
it into a spike; the reliable fix is to yaw the four FBX parts *before* the join and re-bake. Until
then `npc_guard` stays on the worker base.
### Slots a family cannot paint
`Farmer` has no hair shell and `Swat`/`SpaceSuit` have neither hair nor skin. The audit and the
runtime both need the five slots as *used* materials, so `patch_slots` buries a 4 cm triangle
inside the skull or the pelvis for each missing slot (`_patch_missing_slots`). It is invisible, it
keeps the material in the export, and it means a helmeted head still satisfies the contract.
## Contract mismatch
The expensive part is the rig and proportions, not the mesh. The source has a
T-pose and a realistic skeleton; the runtime expects an arm-down 13-core rig,
fixed gear attach points and the existing pose composition. The Stage 1 bake
must therefore:
- rotate the arms down and match the contract wrist positions;
- warp the hips, knees, shoulders and head without collapsing the deltoid,
shortening the arms or changing the silhouette;
- keep one skinned `npc_base` mesh and the five slots;
- verify gear against the new shoulder, hip and head positions.
If those constraints distort the model, Stage 2 is the correct next decision,
not a local workaround.
## Licence and provenance
- CC0 preferred. CC-BY is allowed only with attribution in
[`CREDITS.md`](../../CREDITS.md).
- No service asset whose terms restrict redistribution may be shipped.
- Keep the source URL, author, licence, download date and SHA-256 in this page
and in `CREDITS.md`.
- Research files and generated previews stay in `tmp/` (gitignored). Only final
audited assets and committed review sheets enter the repository.
- Quaternius models and animations are CC0; the existing credits entry already
names Quaternius. Keep it accurate if the shipped source set changes.
## Closed tracks
The MakeHuman/MPFB body pipeline is closed for the NPC base. The accepted
MakeHuman head and the procedural `npc_base` remain tested fallbacks until the
Quaternius rollout is complete. Their research scripts and renders were removed
from `tmp/` after the pivot; the measurements and decisions remain in
[`DONE.md`](../../DONE.md), [`MEMORY.md`](../../MEMORY.md) and the review docs.
## Related documents
- [ADR-0017: Quaternius NPC base](../adr/0017-quaternius-npc-base.md)
- [ADR-0016: 24,000-triangle character budget](../adr/0016-npc-character-budget-24k.md)
- [Blender asset contract](../project/architecture.md#character-and-gear-asset-contract)
- [`3d-model-review.md`](3d-model-review.md)
- [`asset-tooling.md`](asset-tooling.md)
+4 -6
View File
@@ -9,7 +9,7 @@ capture harnesses.
| --- | --- |
| [![sheet_npc.jpg](sheet_npc.jpg)](sheet_npc.jpg) <br> `sheet_npc.jpg` | Eight skinned character variants (casual, jacket, coat, hi-vis vest, dress, hoodie, firefighter, guard) with their gear attach points. |
| [![sheet_npc_baseline.jpg](sheet_npc_baseline.jpg)](sheet_npc_baseline.jpg) <br> `sheet_npc_baseline.jpg` | Neutral studio baseline: 8 characters x front, three-quarter, profile, back, full body and crowd views. |
| [![sheet_makehuman_head.jpg](sheet_makehuman_head.jpg)](sheet_makehuman_head.jpg) <br> `sheet_makehuman_head.jpg` | MakeHuman head: front, three-quarter and profile review views. The owner accepted the basic head; the automated vision gate still rejects the eye/lid region as deferred polish. See [`../makehuman-head-review.md`](../makehuman-head-review.md). |
| [![sheet_makehuman_head.jpg](sheet_makehuman_head.jpg)](sheet_makehuman_head.jpg) <br> `sheet_makehuman_head.jpg` | MakeHuman head: front, three-quarter and profile review views. The owner accepted the basic head; the automated vision gate still rejects the eye/lid region as deferred polish. See [`../makehuman-head-review.md`](../assets/makehuman-head-review.md). |
| [![sheet_npc_baseline_compare-body.jpg](sheet_npc_baseline_compare-body.jpg)](sheet_npc_baseline_compare-body.jpg) <br> `sheet_npc_baseline_compare-body.jpg` | Neck/shoulder transition: fuller neck base and a lower shoulder root. |
| [![sheet_npc_baseline_compare-face-detail.jpg](sheet_npc_baseline_compare-face-detail.jpg)](sheet_npc_baseline_compare-face-detail.jpg) <br> `sheet_npc_baseline_compare-face-detail.jpg` | Face detail: nose ala wings, a single rounded mouth and a darker ear concha. |
| [![sheet_npc_baseline_compare-face.jpg](sheet_npc_baseline_compare-face.jpg)](sheet_npc_baseline_compare-face.jpg) <br> `sheet_npc_baseline_compare-face.jpg` | Face-depth pass: recessed sclera, upper lid and sculpted chin/cheek planes. |
@@ -19,7 +19,7 @@ capture harnesses.
| [![sheet_npc_baseline_compare-texuv.jpg](sheet_npc_baseline_compare-texuv.jpg)](sheet_npc_baseline_compare-texuv.jpg) <br> `sheet_npc_baseline_compare-texuv.jpg` | 4x fabric weave with the baked per-character AO removed. |
| [![sheet_npc_baseline_compare-torso.jpg](sheet_npc_baseline_compare-torso.jpg)](sheet_npc_baseline_compare-torso.jpg) <br> `sheet_npc_baseline_compare-torso.jpg` | Torso/hip taper without changing the skeleton or build multipliers. |
| [![sheet_npc_crowd_prototypes.jpg](sheet_npc_crowd_prototypes.jpg)](sheet_npc_crowd_prototypes.jpg) <br> `sheet_npc_crowd_prototypes.jpg` | Four approved crowd-variety looks queued for the 12-character roster. |
| [![sheet_npc_gear.jpg](sheet_npc_gear.jpg)](sheet_npc_gear.jpg) <br> `sheet_npc_gear.jpg` | Eighteen gear pieces authored in attach space: caps, hood, helmet, bags, tanks, lanyards and handheld items. |
| [![sheet_npc_gear.jpg](sheet_npc_gear.jpg)](sheet_npc_gear.jpg) <br> `sheet_npc_gear.jpg` | Fifteen gear pieces authored in attach space: helmet, sunglasses, bags, tank, lanyard and the nine hand items. Caps and hoods are retired (owner, 2026-11-06). |
| [![sheet_npc_hands_compare.jpg](sheet_npc_hands_compare.jpg)](sheet_npc_hands_compare.jpg) <br> `sheet_npc_hands_compare.jpg` | Hand pass: wider palms, segmented fingers and a separate thumb. |
| [![sheet_npc_hands_grip_compare.jpg](sheet_npc_hands_grip_compare.jpg)](sheet_npc_hands_grip_compare.jpg) <br> `sheet_npc_hands_grip_compare.jpg` | Grip pass: the forward hand-item offset that puts props in the palm. |
| [![sheet_head_proto_before_after.jpg](sheet_head_proto_before_after.jpg)](sheet_head_proto_before_after.jpg) <br> `sheet_head_proto_before_after.jpg` | Head overhaul sign-off: current `_face` vs the s48 connected-shell prototype at 1.85 m front/three-quarter/profile. |
@@ -27,7 +27,5 @@ capture harnesses.
| [![sheet_props.jpg](sheet_props.jpg)](sheet_props.jpg) <br> `sheet_props.jpg` | Twenty street and venue props with baked maps, ground contact and collider footprints. |
| [![sheet_texture_refinement_0.9.5.jpg](sheet_texture_refinement_0.9.5.jpg)](sheet_texture_refinement_0.9.5.jpg) <br> `sheet_texture_refinement_0.9.5.jpg` | 0.9.5 texture refinement before/after: pavers, awning stripes and NPC fabric. |
The acceptance criteria for these sheets are in [`../npc-visual-review.md`](../npc-visual-review.md),
the measurements in [`../npc-visual-review.md#proportion-audit`](../npc-visual-review.md#proportion-audit) and
[`../3d-model-review.md`](../3d-model-review.md), and the asset contract in
[`../blender-assets.md`](../blender-assets.md).
The measurements are in [`../3d-model-review.md`](../assets/3d-model-review.md) and the asset contract in
[`../blender-assets.md`](../assets/blender-assets.md).
Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 94 KiB

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 126 KiB

After

Width:  |  Height:  |  Size: 132 KiB

+13
View File
@@ -0,0 +1,13 @@
# Design Documentation
Gameplay, venues, presentation and player-facing constraints.
- [`gameplay.md`](gameplay.md) — the playable loop, escalation mechanics, venues and tutorial.
- [`venues.md`](venues.md) — real-site evidence, game mapping and venue simplifications.
- [`ui-copy.md`](ui-copy.md) — screen, copy and button inventory plus the screen-design judge
record.
- [`accessibility.md`](accessibility.md) — accessibility statement and known gaps.
- [`known-limitations.md`](known-limitations.md) — release blockers and accepted limitations.
Up: [`../README.md`](../README.md) · Product plan: [`../../PLAN.md`](../../PLAN.md) · Tasks:
[`../../TODO.md`](../../TODO.md).
@@ -28,5 +28,5 @@ Known gaps:
review is still a 0.10.0 release-review item.
Test evidence and the manual checklist live in
[`release-qa.md`](release-qa.md#manual-smoke-checklist); settings and save behaviour are
documented in [`getting-started.md`](getting-started.md).
[`release-qa.md`](../process/release-qa.md#manual-smoke-checklist); settings and save behaviour are
documented in [`getting-started.md`](../process/getting-started.md).
+1 -1
View File
@@ -1,6 +1,6 @@
# Gameplay
The complete design rationale also lives in [`PLAN.md`](../PLAN.md); this page keeps the playable mechanics close to the README.
The complete design rationale also lives in [`PLAN.md`](../../PLAN.md); this page keeps the playable mechanics close to the README.
## Game Overview
@@ -12,7 +12,7 @@ public release.
observation.
- **AI asset provenance:** the image-generation provider terms and commercial
redistribution rights for the committed AI-assisted textures/UI art still need
legal review. See [`../CREDITS.md`](../CREDITS.md).
legal review. See [`../CREDITS.md`](../../CREDITS.md).
- **Storefront/legal approval:** age/content rating, storefront policy, trademark
language and the mental-health-crisis/body-camera representation have not been
externally approved.
@@ -31,7 +31,7 @@ public release.
- Character faces, hands and fabric use a deliberately low-poly style; the
>26 m tier remains a two-quad impostor and there is no separate finger-curl
rig. The accepted limits are recorded in
[`npc-visual-review.md`](npc-visual-review.md).
[`npc-model-sourcing.md`](../assets/npc-model-sourcing.md).
- There is no live 3D body-camera replay; the timeline is text-based.
- There is no recorded voice/music track. Ambience and cues are procedural.
- The game is English-only and does not yet have a translator workflow or
+4 -4
View File
@@ -1,6 +1,6 @@
# UI copy and button inventory
Status: dialogue, button-state, focus, modal-close, font/layout, destructive-action and end-to-end passes complete; capture/smoke sign-off remains for 0.9.3.
Status: complete (0.9.3). Retained as the screen/button inventory, copy audit and screen-design judge record.
## Screen inventory
@@ -236,9 +236,9 @@ Command: `python3 tools/screen_designs.py judge`
Result: **21/21 match, 0 review, 0 diff**
The screenshot gallery was regenerated on the current build before judging, including the eight UI-state captures 14–21 added in `src/test/capture_ui_states.gd`.
Accepted captures are in [`docs/screens/`](screens/README.md); the committed
gallery is in [`docs/screenshots/`](screenshots/README.md).
Accepted captures are in [`docs/screens/`](../screens/README.md); the committed
gallery is in [`docs/screenshots/`](../screenshots/README.md).
The automatic model selection and retry/spend behavior is documented in
[`docs/asset-tooling.md`](asset-tooling.md). This report intentionally records
[`docs/assets/asset-tooling.md`](../assets/asset-tooling.md). This report intentionally records
the outcome rather than generated captures, which remain local/gitignored.
+5 -5
View File
@@ -11,7 +11,7 @@ The game uses two physical Hollywood blocks across three playable venue rows:
The runtime implementation contract (facade specs, map budgets, navigation,
colliders, phase behavior and fallback) lives in
[`architecture.md`](architecture.md#venue-implementation-contract). This page
[`architecture.md`](../project/architecture.md#venue-implementation-contract). This page
keeps the real-site evidence, mapping decisions and deliberate simplifications.
## Hollywood Boulevard
@@ -49,7 +49,7 @@ keeps the real-site evidence, mapping decisions and deliberate simplifications.
| TV Studio arrival | same six-column facade/eight steps plus bulb canopy, sedan, handrail and barriers |
The generated references in
[`screens/concepts/hollywood_boulevard/`](screens/concepts/hollywood_boulevard/README.md)
[`screens/concepts/hollywood_boulevard/`](../screens/concepts/hollywood_boulevard/README.md)
are art direction for lighting, material scale and composition; they are not
texture or geometry sources.
@@ -128,9 +128,9 @@ The guard starts west of the entrance at (-4.8, 0.1, 1.4), facing the approach.
- [Hollywood Masonic Temple facade — Wikimedia Commons](https://commons.wikimedia.org/wiki/File:El_Capitan_Theater_frontal_fachade-The_Masonic_Temple.jpg)
- [Hollywood Masonic Temple and El Capitan Theatre, 2013 — Wikimedia Commons](https://commons.wikimedia.org/wiki/File:Hollywood_Masonic_Temple_2013-10-13_10-02-25.jpg)
- [Comedy Store — OpenStreetMap way 428854155](https://www.openstreetmap.org/way/428854155)
- Committed photo boards: [`screens/refs/hollywood/`](screens/refs/hollywood/README.md),
[`screens/refs/joke-shop/`](screens/refs/joke-shop/README.md); three-up boards
are in [`screens/boards/`](screens/boards/README.md).
- Committed photo board: [`screens/refs/hollywood/`](../screens/refs/hollywood/README.md);
three-up boards are in [`screens/boards/`](../screens/boards/README.md). The Joke Shop has no
committed photo board: its reference set stays local-only under `tmp/research/comedy-store/`.
- Local-only research (never committed): `tmp/research/elcapitan-2026/`,
`tmp/research/jimmy-kimmel-entrance/`, `tmp/research/comedy-store/` and
`tmp/research/comedy-store-hillside/`. These are evidence for decisions, not
-91
View File
@@ -1,91 +0,0 @@
# NPC Model Sourcing
This page records the source evaluation behind [ADR-0015](adr/0015-npc-model-variety-sourcing.md).
The shipped path is the project-owned Blender/procedural library; external sources
remain references or local prototypes unless a later ADR accepts them.
## Evaluation
The library needs variety beyond the original eight silhouettes while preserving
the `npc_base` contract: mesh node, 13 required core bones (optional extras
allowed), five tint slots, −Y/+Z front, grounded feet and the 16,000/16,000
character budget.
| Source | Licence | Result |
| --- | --- | --- |
| Quaternius Ultimate Modular | CC0 | Good silhouette/decimation material, but a 62-bone T-pose realistic rig and different proportions; not a drop-in. Kept as a reference/prototype. |
| Kenney Blocky Characters | CC0 | No matching rig; style is much blockier than the project look. |
| Khronos CesiumMan / RiggedFigure | CC BY 4.0 | Different bone names/rest pose and no five-slot materials; not a drop-in. |
| MakeHuman / MPFB base | CC0 | Useful body-shape base, but requires retopology, a custom rig, clothing and part integration. Active local pipeline, not the shipped path. |
The contract mismatch is the expensive part, not decimation: retargeting a
different rig or rebuilding slots/weights can distort the body and invalidate
gear placement. Any future second-rig path needs its own ADR and animation/gear
offsets.
## Decision and outcome
- Extend the project-owned procedural generator as the primary shipped path
(12-character library, crowd variants, role pools).
- Keep Quaternius as a studied reference, not a shipped base.
- MakeHuman is a local development pipeline for body-shape diversity; it must
consume the same head/hand parts as the procedural library and never become a
CI/build dependency.
- Record CC0/CC-BY provenance; CC-BY previews require attribution in
[`CREDITS.md`](../CREDITS.md).
## MakeHuman prototype notes
The local prototype (`tmp/npc-research/`, never committed) scaled the base to
1.82 m, grounded it, triangulated/decimated it and retargeted it to the 13-core
armature. The first retarget measured **6,444 / 16,000 tris and**
**7,726 / 16,000 verts**, 14 bones, skinned, arm-down, five slots. It exposed
the expected issues: a 1.63× arm-scale warp at the deltoid/shoulder, blocky
decimated hands, rough slot boundaries and a head/neck shadow gap. The later
project head/hands swap reduced this to **6,407 / 16,000 tris and**
**6,651 / 16,000 verts**, but manual shoulder/neck retopology and part cleanup
remain before it can be considered shippable.
A standalone MakeHuman head is recorded in
[`makehuman-head-review.md`](makehuman-head-review.md). The owner accepted the basic
human head on 2026-11-04; the assembled path (`build_character(head="mh")`) adds a
skull-conforming hair cap and hides the scalp under it. The 12 shipped GLBs still use
the procedural head until the hair/body review and rollout in [`TODO.md`](../TODO.md).
The MakeHuman body should reuse the approved local head/hand parts rather than forking
a second face implementation.
The current local MPFB full-body prototype (`tmp/npc-research/build_mpfb_npc.py`) assembles the
accepted head on an MPFB 2.0.18 body at **15,317 / 16,000 tris**, 1.810 m, 14 bones and 10
materials, with project hands, bevelled shoe shells with inset soles and tongues, pant cuffs,
cloth sleeve cuffs and flat slot colours. The torso is radially inflated by 12% through z 0.72–1.40
to loosen the shirt. It is a review candidate, not a shipped asset. The neck is a radial cut
of the decimated column bridged by a four-ring, 20-segment lathe (lower rings painted cloth,
reading as a crew neck); the ankles are hidden by 0.11 m shoe shells and 0.08 m pant cuffs, and a
light smoothing pass softens the closed thigh/hip region. The neck skin test is guarded to z >
1.35 so it cannot paint the crotch. Remaining polish: the crotch hollow still reads as a V under
the shirt hem, a partly loosened shirt and angular thigh facets; a separate loose shirt shell is
the fix. Lowering the hem to z 0.80, tilting it up at the front and a 13% hem flare were rejected
as a unitard, high-cut swimwear and a peplum respectively. A quick open, flared solidified tube
(0.150→0.196 m, z 1.05→0.80, 24 segments) read as a hanging apron/tabard; the shell needs a shaped
torso, armholes and a curved hem.
A torus collar, cloth cylinder collar, skin neck-blend sphere, destructive vertex-smoothing pass
and untucked shirt-hem band were tried and removed because they read as a brace, shelf, donut or
hanging flap, or tore a hole at the collar. Protruding flat sole plates read as skates or bricks,
so the shoe detail is an inset sole and tongue under a rounded shell; laces were dropped for
triangle budget. The production integration decision (bake a committed source GLB or keep the
procedural body) and the owner review are tracked in `TODO.md`; MPFB itself must not become a
CI/build dependency.
## Provenance rules
- CC0 preferred; CC-BY only with attribution in `CREDITS.md`; no service asset
whose terms restrict redistribution.
- Downloaded research and generated previews stay in `tmp/`/gitignored folders;
only final audited assets and committed review sheets enter the repository.
- Record source URL, licence, author, date and what decision the reference
informed. Never treat a generated concept as licensed map/model data.
Measurements, visual decisions and accepted limits are in
[`3d-model-review.md`](3d-model-review.md) and
[`npc-visual-review.md`](npc-visual-review.md). Commands are in
[`asset-tooling.md`](asset-tooling.md).
Loaded 100 of 157 files, more files were not shown because too many files have changed in this diff. Show more