Compare commits

...
27 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
143 changed files with 3000 additions and 1299 deletions

No files matched your search

@@ -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
@@ -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
@@ -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`.
@@ -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 |
+16 -16
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
@@ -102,7 +102,7 @@ specialists the task needs:
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
@@ -110,7 +110,7 @@ specialists the task needs:
4. **No new asset source without the licence gate.** Skills may suggest reference packs or
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/npc-model-sourcing.md` still apply to any new source.
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.
@@ -196,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.
@@ -207,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`
@@ -217,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
@@ -267,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`
@@ -297,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
+38
View File
@@ -6,6 +6,44 @@ 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
+4 -4
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
@@ -53,7 +53,7 @@ CC0 1.0). It is cut, retopologised and re-weighted by project scripts; the expor
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/npc-model-sourcing.md`.
`docs/assets/npc-model-sourcing.md`.
### Quaternius NPC base source
@@ -61,7 +61,7 @@ The active NPC base migration uses **Quaternius Ultimate Modular Characters** an
**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/npc-model-sourcing.md` for the decision, source hashes and rollout status.
`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
@@ -118,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
+140 -38
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.
@@ -2154,7 +2154,7 @@ Goal: `src/test/capture_npc_pose.gd` reports a pose but saves rest frames; the r
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/3d-model-review.md` §"Pose evidence is blocked".*
*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
@@ -2192,3 +2192,105 @@ variants, the four crowd-variety characters and the per-role pools — as a **pa
**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.
+142 -17
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
@@ -13,8 +13,8 @@ canonical implemented-features list in `docs/development-status.md`.
- **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 until the judge's specific fixes
converge. Review pages: `docs/screens/head-review/README.md`, `docs/3d-model-review.md`
§AI-driven head rework.
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
@@ -24,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
@@ -54,12 +54,12 @@ canonical implemented-features list in `docs/development-status.md`.
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-05):** all characters use 24,000 tris / 24,000 glTF vertices
@@ -87,8 +87,11 @@ canonical implemented-features list in `docs/development-status.md`.
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), the mesh keeps source LOD (arm-down rest pose baked), and Idle/Walk play directly
on the 62-joint rig (no retarget).
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.
@@ -105,7 +108,7 @@ 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`
@@ -119,16 +122,115 @@ canonical implemented-features list in `docs/development-status.md`.
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):** Godot's `set_bone_pose_rotation`
offsets from the bone rest, so the correct swing around a world axis is
`rest * Quaternion(rest.inverse() * axis, angle)`. For the old 180° rest this reduces to the
legacy `rest * Quaternion(axis, angle)`, so the 13-core fallback is unchanged (commit `8b1bf73`).
- **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**
@@ -265,7 +367,7 @@ canonical implemented-features list in `docs/development-status.md`.
## Current State
v0.9.8 is published. The build covers the three venues, the shift loop, tutorial/campaign/
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.
@@ -275,15 +377,38 @@ patches (`0.9.9`–`0.9.12`) with `0.10.0` as the public-readiness minor. The ga
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
`docs/screens/npc-face-gate/`; the **owner decision is the only thing left before the 0.9.9
rollout**.
the face-gate decision (owner chose the full swap).
Test counts as of 2026-11-05: Python 167/167, Godot 278/278, `check_docs` OK.
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 -->
+1 -1
View File
@@ -265,7 +265,7 @@ 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
+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
+26 -26
View File
@@ -46,13 +46,13 @@ Versions are assigned only when a track's scope is accepted into a release. Ever
> 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.
@@ -112,7 +112,7 @@ current library and will be replaced after the 12 × 6 baseline review.
| ![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
@@ -122,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
@@ -130,8 +130,8 @@ 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
@@ -144,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
@@ -157,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
@@ -198,9 +198,9 @@ UI/accessibility polish, 0.9.2 Hollywood/Joke Shop maps and the 0.9.x engine
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/development-status.md`](docs/development-status.md) for the implemented list
[`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
@@ -209,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
+215 -148
View File
@@ -74,7 +74,7 @@ pieces, 20 library props, 6 generated props and the three venue families — plu
pipeline that re-evaluates those venues (OSM data/licensing, reference imagery, the photoreal
facade kit, AI-assisted composing, Gaussian-splatting evaluation and map QA).
**Exit (asset review, A–G):** `docs/3d-model-review.md` scores every catalogue asset; every P0/P1
**Exit (asset review, A–G):** `docs/assets/3d-model-review.md` scores every catalogue asset; every P0/P1
is fixed or explicitly accepted with a measurement; `inspect`/`audit`/`fit`/proportions, the
24-NPC budget and the capture gates are green; no runtime contract, dependency or release artifact
changed except the rebuilt assets themselves.
@@ -111,16 +111,16 @@ licence-free zone only.
(`elcapitan`, `hollywood-block`, `jimmy-kimmel-stage`, `jimmy-kimmel-entrance`,
`comedy-store`).
- [x] Record which local frames changed a decision: added the frame→decision mapping to
`docs/venues.md#hollywood-boulevard` (recent `elcapitan-2026` geosearch → 2009 frame stays the
`docs/design/venues.md#hollywood-boulevard` (recent `elcapitan-2026` geosearch → 2009 frame stays the
geometry reference; `jimmy-kimmel-entrance/07.jpg` → the four entrance concepts) and
`docs/venues.md#the-joke-shop` (`comedy-store/` → the four concept pairs + map plan;
`docs/design/venues.md#the-joke-shop` (`comedy-store/` → the four concept pairs + map plan;
`comedy-store-hillside/` → the day-concept anchor that clears the image-recitation filter).
Frames stay gitignored; only the provenance notes are committed.
### B. Baseline, scorecard and routing
- [x] Load `blender-director` plus the per-family specialists before touching geometry, and
record the skill stack and the advice that changed a decision in `docs/3d-model-review.md`.
record the skill stack and the advice that changed a decision in `docs/assets/3d-model-review.md`.
(Routing, QA severity/verdict, texel-density tiers, character loop criteria and budget rules
recorded in the review doc; MCP-only steps translated to headless flatpak runs.)
- [x] Re-run the neutral NPC baseline (48 frames), the final-context review (96 frames), the
@@ -128,7 +128,7 @@ licence-free zone only.
not replace committed sheets until a fix lands. (48/48 and 96/96 frames captured under
`xvfb-run`, none blank; raw sets in `tmp/model-baseline` and `tmp/model-review`; committed
sheets untouched. 24-NPC smoke still 6.94 ms / 168 meshes / 131,616 triangles.)
- [x] Create `docs/3d-model-review.md` with a per-asset scorecard: silhouette, anatomy/proportion,
- [x] Create `docs/assets/3d-model-review.md` with a per-asset scorecard: silhouette, anatomy/proportion,
topology/edge flow, UV/texel density, textures/materials, rig/weights, LOD/impostor,
collision/grounding, export contract, provenance, skill route, verdict (P0/P1/P2/accept).
(Doc created with character/gear/prop/venue tables, verdict columns and a ranked candidate
@@ -144,11 +144,10 @@ licence-free zone only.
### C. Character re-evaluation (superseded 2026-11-05)
The procedural character review is complete and its evidence stays in
`docs/3d-model-review.md`. The next character pass is the Quaternius base in
[`Milestone 0.9.9`](#milestone-099--quaternius-npc-base-swap-patch) and
[`Milestone 0.9.10`](#milestone-0910--npc-roster-rollout-patch); the open items below are kept
as evidence for what the new base must not regress (face read, hands, weights, cloth, texel
density, crowd variety).
`docs/assets/3d-model-review.md`. The Quaternius base shipped in 0.9.9; the remaining roster
follow-ups are [`Milestone 0.9.10`](#milestone-0910--npc-roster-rollout-patch). The open items
below are kept as evidence for what the new base must not regress (face read, hands, weights,
cloth, texel density, crowd variety).
*Skill route: `character-artist`, `retopology`, `rigging`, `uv-workflow`, `texture-workflow`,
`materials`, `hair-groom`, `asset-optimization`, `lookdev`, `qa-review`.*
@@ -175,7 +174,7 @@ density, crowd variety).
hip fix clean, knee crease minor residual. The guard hip-pouch clip and the residual knee
crease remain as 0.10.0 refinements.
- [x] UV/texel density: measured (64–122 px/m authored, 287–440 px/m effective fabric on the 4×
repeat; table in `docs/3d-model-review.md`). Decision: **accept as-is** — the maps are
repeat; table in `docs/assets/3d-model-review.md`). Decision: **accept as-is** — the maps are
neutral/runtime-tinted (not painted skin), so density controls only subtle weave/noise, and
fabric already sits in the standard tier. No atlas/UDIM/resolution change is justified until
a portrait shows texture starvation; `CHAR_MAX_TRIS`/`CHAR_MAX_VERTS` stay unchanged.
@@ -187,7 +186,7 @@ density, crowd variety).
reconsidered if a later close-up shows visible hem/coat stiffness.
- [ ] Fix only the ranked P0/P1s, one asset family per commit; refresh the comparison sheet and
re-run `inspect`, `audit`, `fit` and `npc_proportions.py` after each fix. **Scheduled: the
remaining character items are covered by Milestone 0.9.9/0.9.10; this row is evidence only.**
remaining character items are covered by Milestone 0.9.10; this row is evidence only.**
- [x] Crowd-variety reference: five licence-cleared Commons photos fetched to
`tmp/research/crowd-variety/` (CC0 ×2, CC BY 2.0, CC BY 3.0, PD) covering umbrella/dense
crowds and a pedestrian mall — general build/hair/outer-layer variety context, reference
@@ -200,7 +199,7 @@ density, crowd variety).
- [x] `qa-review` sign-off: all eight variants **ship with notes** (face realism landed, hands/
cloth/gear accepted, props reviewed); the weights/pose column is the only open item (blocked
on the harness) and the full foliage carded-cluster is the one remaining owner-gated P1.
Recorded in `docs/3d-model-review.md` §qa-review sign-off.
Recorded in `docs/assets/3d-model-review.md` §qa-review sign-off.
### D. Gear and prop re-evaluation
@@ -209,7 +208,7 @@ density, crowd variety).
- [ ] Gear: review the 18 pieces for silhouette, straps/buckles, helmet and lanyard readability
and rebuild only what fails the scorecard. (Attach/clearance verification is done — the
`fit` report is recorded in `docs/3d-model-review.md` with the back-gear-vs-hip-radius
`fit` report is recorded in `docs/assets/3d-model-review.md` with the back-gear-vs-hip-radius
measurement caveat; the visual silhouette read is what remains, pending the owner scorecard.)
- [ ] Props: review the 20 library props plus the 6 generated props for bevels, chamfers,
silhouette, ground contact and shared material language (`prop-artist`, `hard-surface`);
@@ -233,7 +232,7 @@ density, crowd variety).
lamp) and rank the silhouette and proportion mismatches.
- [ ] Rebuild only the mismatched pieces through the assisted Blender pipeline
(`blender_assets.py inspect` → scripted retopo/UV assist → atlas → `audit`/`fit`); document
the exact commands in `docs/asset-tooling.md`.
the exact commands in `docs/assets/asset-tooling.md`.
- [ ] Refresh `sheet_props.jpg`/`sheet_npc_gear.jpg`, the README asset rows and
`docs/blender_previews/README.md` after the rebuilds.
- [ ] Exit: a prop/gear capture sheet, budgets and collision checks pass with no unreviewed asset.
@@ -293,8 +292,8 @@ density, crowd variety).
`tools/three_up.py compose` renders labelled strips into `docs/screens/boards/` (caption
sidecar per board, `rows` emits README rows). Boards committed: El Capitan day, El Capitan
night, Joke Shop day. Tests in `tools/test_three_up.py`.
- [x] Link each committed board from `docs/venues.md#hollywood-boulevard` and
`docs/venues.md#the-joke-shop`.
- [x] Link each committed board from `docs/design/venues.md#hollywood-boulevard` and
`docs/design/venues.md#the-joke-shop`.
- [ ] Use the generated concept lighting and palette as the target for the `lighting`/`lookdev`
pass, and record the deviations that stay accepted.
- [ ] After the pass, regenerate the venue captures and update README plus both venue documents.
@@ -322,10 +321,10 @@ and never ship a generated or downloaded image without provenance.
log and the generated-board reference table. Linked from `docs/screens/README.md`.)
- [x] Hollywood board: five licence-cleared photos (facade day, blade sign, 1922 elevation,
Ovation across street, premiere staging) with a sidecar and per-image purpose, linked from
`docs/venues.md#hollywood-boulevard` and credited in `CREDITS.md`. Cropped the foreground crowd
`docs/design/venues.md#hollywood-boulevard` and credited in `CREDITS.md`. Cropped the foreground crowd
out of the facade shot; EXIF stripped. (`docs/screens/refs/hollywood/`.)
- [x] Joke Shop board: three licence-cleared photos (hillside/canopy block, frontage with palms,
canopy signature band) with a sidecar, linked from `docs/venues.md#the-joke-shop` and credited in
canopy signature band) with a sidecar, linked from `docs/design/venues.md#the-joke-shop` and credited in
`CREDITS.md`. The CC BY-SA `The Comedy Store.jpg` from the old link list was deliberately not
used; the public-domain frames cover the same evidence. (`docs/screens/refs/joke-shop/`.)
**Removed 2026-11-03:** the committed Comedy Store photo board was replaced by the local-only
@@ -333,8 +332,8 @@ and never ship a generated or downloaded image without provenance.
- [x] TV Studio: no separate board — the venue is the same El Capitan Entertainment Centre block as
the Hollywood day shift, restaged for a late-night arrival. The Hollywood board covers both
venues and the premiere-staging photo is the arrival evidence; the reuse is now stated in
`docs/venues.md#hollywood-boulevard`, `docs/gameplay.md`, `PLAN.md` and
`docs/development-status.md`.
`docs/design/venues.md#hollywood-boulevard`, `docs/design/gameplay.md`, `PLAN.md` and
`docs/project/development-status.md`.
- [x] Fill the Hollywood gaps that have a clean licence: El Capitan Theatre neighbour and marquee,
Walk of Fame terrazzo band, star close-up, and a night street-lighting context frame (cropped
to remove people and a plate). The board now has nine photos. (CC BY-SA night frame is
@@ -348,7 +347,7 @@ and never ship a generated or downloaded image without provenance.
preview sheets.)
- [ ] Apply the screenshot rule to every workstream: each accepted fix updates the relevant row in
`README.md` plus the matching docs page (`docs/blender_previews/README.md`,
`docs/screenshots/README.md`, `docs/3d-model-review.md` or the venue map doc).
`docs/screenshots/README.md`, `docs/assets/3d-model-review.md` or the venue map doc).
- [ ] Re-run `tools/check_screenshots.sh` and `python3 tools/check_docs.py` after gallery changes
and record both results in the handoff.
- [ ] Keep AI-generated images out of `assets/` until they are picked, cropped, credited and (for
@@ -372,16 +371,16 @@ and never ship a generated or downloaded image without provenance.
Suite is 275/275.)
- [x] Add a coverage test so every catalogue asset has a scorecard row and verdict.
(`tools/test_model_review.py`: every `CHARACTERS`/`GEAR`/`PROPS` entry needs a row in
`docs/3d-model-review.md`, and character rows need a non-empty verdict.)
- [x] Document the new gates: `docs/blender-assets.md` now lists `texels`, the
`docs/assets/3d-model-review.md`, and character rows need a non-empty verdict.)
- [x] Document the new gates: `docs/assets/blender-assets.md` now lists `texels`, the
`test_model_review.py` coverage gate and the `test_world.gd` collider/proxy gate; skill
routes live in `AGENTS.md` §Local Blender skills and each `TODO.md` section; the scorecard
and evidence table are in `docs/3d-model-review.md`.
- [x] Record accepted limits/deferred rebuilds: `docs/known-limitations.md` already records the
and evidence table are in `docs/assets/3d-model-review.md`.
- [x] Record accepted limits/deferred rebuilds: `docs/design/known-limitations.md` already records the
stylized low-poly style, no finger-curl rig and the >26 m impostor; `MEMORY.md` holds the
durable decisions (texel density accepted, cloth sim out of scope, open palm + forward
offset, face subdivision prototype gated on the owner). The corrected face note is also in
`docs/blender-assets.md`.
`docs/assets/blender-assets.md`.
**Local map workstreams (H–M).** Build a local, data-backed map pipeline that can replace or
supplement the stylized venue geometry with licensed OpenStreetMap footprints, 3D building
@@ -402,7 +401,7 @@ still apply; the map pipeline has its own exit in M.
- [x] ODbL audit: OpenStreetMap is used as **reference only** (hand-built geometry informed by
OSM ways + Commons photos), so the shipped geometry is not an ODbL derived database and no
share-alike obligation attaches. Attribution is still kept via the OSM way links in
`docs/venues.md#hollywood-boulevard` / `docs/venues.md#the-joke-shop`. If derived OSM geometry ever
`docs/design/venues.md#hollywood-boulevard` / `docs/design/venues.md#the-joke-shop`. If derived OSM geometry ever
ships, it needs the attribution + share-alike review in a separate ADR.
- [x] OSM extract workflow: no offline extract is required while OSM is reference-only. If the
pipeline later imports footprints, pin an Overpass query + extract date and record it in a
@@ -501,13 +500,13 @@ Nothing is committed until the licence gate on any promoted reference and the ma
pass. The current `_build_comedy_store_building()` stays as the fallback.*
- [x] Extract the real proportions and reconcile: vision-read `tmp/research/comedy-store/` frames
via `tools/describe_image.py` and recorded the reconciled table in `docs/venues.md#the-joke-shop`
via `tools/describe_image.py` and recorded the reconciled table in `docs/design/venues.md#the-joke-shop`
§Measured proportions. Key finding: the game facade is proportionally **taller** than the
real (3.2:1 vs ~6:1) — the main shape-language deviation; canopy pitch, blade-sign diameter,
entrance and roofline all match closely. Curtain-bay count is crop-dependent (3–7), so 7 is
accepted as a readable stylization.
- [x] Rank the shape-language gaps and write the top-five fix list (measurements from the
proportions pass, §`docs/venues.md#the-joke-shop`):
proportions pass, §`docs/design/venues.md#the-joke-shop`):
1. **Facade height** — game 8.4 m vs real ~5.5–6 m (≈3.2:1 vs ~6:1 ratio). **Fixed
2026-11-03:** `facade_height` lowered to 6.0 m; the wall now reads as a low single-storey
hall with the canopy capping the top (vision-verified).
@@ -533,8 +532,8 @@ pass. The current `_build_comedy_store_building()` stays as the fallback.*
top-five list.
- [x] Gates after the rebuild: Godot 277/277 (map budget 26,828 tris / 580 meshes under 150k/700;
navigation/collider tests pass), `tools/check_screenshots.sh` 21 good / 0 bad; the three-up
board and `docs/venues.md#the-joke-shop` were refreshed.
- [ ] Update `docs/development-status.md`, `docs/asset-tooling.md` and `CHANGELOG.md` when the
board and `docs/design/venues.md#the-joke-shop` were refreshed.
- [ ] Update `docs/project/development-status.md`, `docs/assets/asset-tooling.md` and `CHANGELOG.md` when the
rebuild lands; record any accepted deviations from the reference.
### L. Generated location imagery
@@ -575,7 +574,7 @@ pass. The current `_build_comedy_store_building()` stays as the fallback.*
### M. Local map QA and exit
- [x] Compare the block against screenshots/map docs and keep the stylized fallback: the three-up
boards (photo | concept | capture) and `docs/venues.md#the-joke-shop` record the evidence chain;
boards (photo | concept | capture) and `docs/design/venues.md#the-joke-shop` record the evidence chain;
the procedural `_build_comedy_store_building()` remains the fallback.
- [x] Budget/navigation/collider + day/night captures: Godot 277/277 (Joke Shop 26,828 tris /
580 meshes under 150k/700; navmesh, step collider and prop-collider tests pass),
@@ -583,8 +582,8 @@ pass. The current `_build_comedy_store_building()` stays as the fallback.*
- [x] Gallery + before/after: the Joke Shop day gallery frame and three-up board were recaptured
after each facade change; the photo/concept/capture strip is the before/after record.
- [x] `tools/check_screenshots.sh` re-run (21/0) and the Joke Shop three-up board refreshed.
- [x] Docs: `docs/venues.md#the-joke-shop` (mapping, measured proportions, simplifications),
`docs/asset-tooling.md` (`describe_image.py`) and `docs/development-status.md` updated.
- [x] Docs: `docs/design/venues.md#the-joke-shop` (mapping, measured proportions, simplifications),
`docs/assets/asset-tooling.md` (`describe_image.py`) and `docs/project/development-status.md` updated.
`CHANGELOG.md` is untouched (unversioned track; no release).
- [x] Exit: **one local block (the Comedy Store) is reconstructed with reference-derived facades
and massing** — 6.0 m low hall, white signature fascia, tied-back curtains, hotel tower —
@@ -755,102 +754,6 @@ reference-image licence and privacy gates above rather than replacing them.
passes visual, performance and provenance review; or the approach is rejected with
reproducible findings and removed from the release path.
## 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.
### 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.
- [ ] Verify Idle and Walk on the 62-joint rig: loop seam, foot contact, root motion and frame
rate. Record which of the 24 clips are in scope and which stay unused.
- [ ] Decide and record how poses the clips do not cover (seated, raise-hand, head turn) are
driven at runtime.
- [ ] Keep the fallback tested: `npc_base`, the MakeHuman head and `_build_body()` remain
selectable; no MPFB work is reopened and no Stage-1 proportion warp returns. (The procedural
library is still the majority of `CHARACTER_POOLS` and captures clean, but the fallback path
itself has no dedicated test yet.)
- [ ] Re-fit the remaining gear against the Quaternius torso: the `backpack` strap geometry was
authored for the old body width and now hangs in front of the chest. The camera was fixed
with a wrist strap (a neck strap floats when the item is hand-attached).
### 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] Face-fidelity comparison sheet: [`docs/screens/npc-face-gate/`](../../docs/screens/npc-face-gate/README.md)
captures the Quaternius base, the procedural + MakeHuman head and a procedural crowd variant
at front / three-quarter / profile / 8 m. The page records the three options (full swap,
crowd only, add head detail) and recommends the full swap.
- [ ] **Owner decision:** pick (a) full swap, (b) crowd only or (c) add head detail from
`docs/screens/npc-face-gate/README.md`, then apply it within 24,000 tris / 24,000 glTF
vertices and re-run the gate.
- [ ] Record the decision and its consequence in `MEMORY.md`, `docs/npc-model-sourcing.md` and
(if it changes the contract) a new ADR. Do not silently lower character fidelity.
### 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).
- [ ] Bake the per-slot albedo/normal/ORM maps and a per-slot atlas (the five slots currently
share one whole-body UV set).
- [-] Re-fit gear attach points against the Quaternius skeleton and test cap, helmet, backpack,
shoulder bag, lanyard, clipboard and firefighter tank. (Camera done: wrist strap instead of
the floating neck strap. Backpack straps still cut across the Quaternius chest.)
- [ ] Wire the approved base into one role (or the crowd roles if option b is chosen) with the
procedural model as an instant fallback; no runtime download or optional dependency.
- [ ] Run `blender_assets.py inspect`/`audit`/`fit`, `npc_proportions.py`, the 24-NPC budget smoke
and the capture gate; record the measurements before/after.
- [ ] Release `0.9.9`: update the version source in `project.godot` (`config/version`), write the
`CHANGELOG.md` entry, run `tools/build_releases.sh`, verify checksums, commit, tag and push.
**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.
## Milestone 0.9.10 — NPC roster rollout (patch)
Goal: extend the approved base to the full 12-role roster in asset-family batches, without
@@ -862,8 +765,90 @@ regressing gear fit, budget or readability.
casual/coat/hoodie/crowd_c, casual tee for jacket/dress/crowd_a/crowd_b, worker for
vest/firefighter/guard/crowd_d. `npc_firefighter`, `npc_guard` and `npc_crowd_d` drop the
upstream hivis vest and hard hat. All twelve built, AO-baked and committed (`a6ccd86`).
- [ ] Add the modular part library (hair styles, outfits) so the roster regains the silhouette
variety the twelve procedural meshes had; three shared meshes is the current ceiling.
- [x] **Hair part library.** Every base ships one hair shell; `QUATERNIUS_HAIR_PARTS` reshapes it in
place (`short` identity, `buzz` squashed toward the hairline, `long` stretched from the crown),
and each role picks a style through the existing `CHARACTERS[...]["hair"]` field. The T-pose
cache is keyed on the style. The roster now reads as three silhouettes instead of one.
- [x] **Outfit part library — intake landed (`Suit` pilot).** The owner downloaded the
*Ultimate Modular Men* pack (CC0, 15 families, FBX only) into `tmp/quaternius-intake/`.
`tools/quaternius_parts.py make-base` composes a family into a skinned base GLB, undoing five
FBX artefacts (per-file armatures, `_end`/`neutral_bone`, node transforms, the shared
jacket/trouser fabric, seam degenerates). `Suit.glb` is the first base: `npc_coat` is now a
dark formal suit instead of a tinted hoodie. The pitfalls are recorded in
`docs/assets/npc-model-sourcing.md` and `MEMORY.md`.
- [x] **Outfit families rolled out.** Seven more bases intaken (Adventurer, Beach, Casual_2,
Farmer, King, Punk, Suit) with a slot map each: the roster now runs **eleven distinct outfits
across twelve roles**. `patch_slots` buries a hidden triangle for slots a family cannot paint
(Farmer has no hair shell), so the five-slot contract holds on helmeted and hatted heads.
- [ ] **Swat base faces backwards, and three yaw attempts failed.** It is authored facing Godot
−Z. Tried and rejected: (a) rotating the exported armature node — the skin turns with it and
the character renders headless; (b) rotating armature + mesh objects — collapses into a
spike; (c) rotating mesh *data* plus the rest bones after `transform_apply` — still headless.
Next idea: yaw each of the four FBX parts in its own import (before any join), or re-author
the base from the pack's `All together/Humans_Master` scene where facing is known.
`npc_guard` stays on the worker base; `Swat.glb` is intaken but unused.
- [ ] `SpaceSuit` is not intaken: it has no skin, eye or hair geometry at all and no role fits an
astronaut on Hollywood Boulevard. `Weapons` (pistol, sword) is unused by design — the game
has no weapon system.
- [ ] Heavy outfits cap the texel density: `npc_dress` (King, 11k tris) runs at 212 px/m on the
4× fabric weave where the lighter bases reach 320. The test floor moved to 200 px/m; a
per-slot atlas would recover the difference.
- [x] Intake tooling: `inventory` / `extract` / `verify` / `make-base` in
`tools/quaternius_parts.py`, all exercised against the real pack.
- [ ] Bake per-slot albedo/normal/ORM maps and a per-slot atlas; the five slots currently share one
whole-body UV set, which caps how much the cloth/pants tints can differ.
### Owner review findings (2026-11-06)
The owner signed the roster off **with follow-ups** and rejected three review rows (faces at
portrait, hands and hand-held gear, head gear on the skull). All follow-ups landed and the roster was
accepted on 2026-11-06; the review page and its sheets were then retired.
- [x] Worker torso holes on `npc_guard`: the build deleted `Worker_Vest`, which on the modular
Worker *is* the torso. Fixed by mapping it to `cloth` instead of deleting it.
- [x] Worker crown hole on `npc_firefighter`/`npc_crowd_d`: the deleted `Worker_Yellow` hat was
the crown of the skull. Fixed by keeping it and splitting the material at z 1.65 (crown →
`hair`, vest stripes → `cloth`).
- [x] Unibrow on `npc_guard`/`npc_vest`/`npc_crowd_d`: the Worker `Eyebrows` bar *and* its
oversized eye quads are cut out, and the hoodie's two brows are transplanted onto the Worker
head, lifted 18 mm clear of the eye line (`WORKER_HEAD_DONOR`).
- [x] Worker crown reads as a hard hat: the hoodie's hair is transplanted onto the Worker head and
the hard-hat faces above the collar are cut away, so guard/responder/crowd_d have hair.
- [x] Worker roles (vest, firefighter, guard, crowd_d) had **no visible eyes**: the Worker's own
quads sit inside the head. The hoodie's eye pair is now transplanted with a 4 mm forward
offset, so all four roles show two eyes and two brows (owner request).
- [x] Owner: remove **all** hats except the firefighter helmet, and remove the performer cone.
Caps and hoods are gone from `ACCESSORIES`, the per-character gear list and the primitive
fallbacks; the performer keeps only the baton and board in hand. The head-gear lift/scale
compensation those hats needed is deleted with them, so `firefighter_helmet` is the only
head item and no role can hide its face.
- [x] Worker faces: the dark "unibrow" band turned out to be the **cap brim** sitting on the brow,
not head geometry. `HEAD_GEAR_LIFT` went 0.07 → 0.103 (the gear is authored around the head
*centre* at 1.62, the Quaternius head centre is 1.69) and `GEAR_SCALE` grows the cap/hood so
they clear the 0.228 m hair shell. The cap now reads as a cap and both eyes *and* brows show.
- [x] Hair poking through head gear: fixed by the same lift + cap/hood scale; the firefighter
helmet dome covers the hair, and the cap reads as a cap rather than a visor.
- [x] Eyes now have a sclera and a pupil, done as geometry rather than a texture: the existing eye
quads became the light sclera and a shrunken copy pushed along the sclera's own normal became
the dark pupil (`_add_quaternius_eye_whites()`). Two extra draw calls per head, no new UV work.
- [x] Review page re-created for the second pass, then retired after the owner accepted the roster
(2026-11-06). The durable evidence is `docs/assets/3d-model-review.md`, the measurements in
`docs/assets/blender-assets.md`, and the `capture_npc_gear.gd` / `capture_npc_baseline.gd` scripts.
- [-] Arm/torso intersection on `npc_dress`/`npc_jacket`/`npc_crowd_a`/`npc_crowd_d`: the baked
rest now aims the upper arm 7° out from vertical. Verified clear on the `casual` base; a
light clip remains on `worker`, so this needs either a wider angle or a per-base shoulder
offset.
- [ ] Worker crown still reads as a hard hat: the shape is upstream geometry, so it needs the
modular hair/cap library (or a carved brim) instead of a tint.
- [ ] Eyes and brows still read as one heavy dark mass at portrait distance (checklist row 3).
- [ ] Head gear still does not sit on the skull convincingly (row 5): the firefighter helmet brim
is 1.55× the head width and the cap sits high.
- [x] Carried role props floated beside the body: `_add_props()` placed the performer hat/board
and the protester pole/sign at fixed rig offsets. They now ride the hand proxies
(`_hand_for()`), and the performer cone was resized from a 0.44 m base to 0.25 m so it sits
on the 0.20 m head instead of swallowing it.
- [ ] Hand-held gear is still authored for the old hand (row 4): the `npc_vest` clipboard is
oversized on the shorter Quaternius arm.
- [-] Build one asset family per commit, AO-baked and re-imported; never run a no-op full-library
rebuild. Use the concept + vision-judge loop for head/outfit decisions and record model,
prompt and spend. (Roster family landed in one commit because the three sources share one
@@ -873,17 +858,71 @@ regressing gear fit, budget or readability.
- [ ] Refresh `CHARACTERS`, the manifest roles/tint data, `CREDITS.md` and the review doc rows as
each family lands.
### Prop and gear fit pass (new NPC attach points)
Goal: every gear piece and role prop is measured against, and re-authored for, the Quaternius
skeleton. The 0.9.9 roster swap moved the hand from y 0.78 to the wrist at y 1.017, the head centre
from 1.62 to 1.69 and the shoulder width from 0.27 to 0.15, so anything authored for the procedural
body is now the wrong size or in the wrong place. Nothing in this workstream changes the runtime
contract.
- [x] Extend `tools/blender_assets.py fit` to measure **hand** gear (it skipped `hand` outright).
It now reports grip drop, the lowest point at rest against the Quaternius wrist (y 1.017), the
hip-line flag (0.95), the authored size and `size_vs_head` — the proportion number that makes
"reads oversized" measurable.
- [x] Record the nine hand-item measurements (table in `docs/assets/blender-assets.md`). Only the
`clipboard` was actually mis-authored: its grip sat in the *middle* of the board, so it hung
through the thigh line. It now grips the top edge like a carried clipboard (0.22 x 0.30 m).
- [x] Re-author the `clipboard` (top-edge grip, 0.22 x 0.30 m) and rebuild + re-bake AO. The
`umbrella` (0.90 m) measures on its real-world size and keeps its grip, so it stays.
- [x] Re-fit the role props in `NpcAvatar._add_props()`: the delivery parcel (0.34 m slab across
the torso) is now a 0.26 m carried box in the hand, and the confused visitor carries a folded
map instead of a tray hovering at the hip.
- [x] The primitive cap/hood fallbacks in `_add_accessory()` are deleted with the hat removal;
the remaining hand-item primitives are unreachable while the gear GLBs exist and stay as the
documented fallback.
- [x] Retire the gear GLBs the roster no longer uses: `cap` and `hood` are gone from `GEAR`, the
manifest and the asset tree (`beanie` was already retired). The builder branches stay for a
future design, guarded by a comment.
- [x] `docs/assets/blender-assets.md` documents the 15-piece matrix and the hand-item fit table;
`architecture.md`, `asset-tooling.md` and the preview index were updated with the new counts.
`CREDITS.md` still cites the upstream pack, which is unchanged.
- [x] Owner feedback: the back gear hung at the waist. The `back` attach moved from y 1.10 to
1.26 (shoulder-blade height on the Quaternius torso); backpack, shoulder bag and SCBA tank
re-captured on the character sheet.
- [x] Re-measure `fit` for the back and chest gear on the slimmer torso: `backpack` inner x 0.150
against a 0.190 clothing radius (straps cross the body, as intended), `shoulder_bag` x
clearance +0.072, `scba_tank` inner x 0.150, `lanyard` radial clearance +0.012 on the chest.
The backpack straps were re-fitted for this torso in `fb3e75a`; nothing further needed.
- [x] Rebuilt `docs/blender_previews/sheet_npc_gear.jpg` for the 15-piece set (all renders
regenerated) and re-ran the 24-NPC budget smoke (175,264 tris, 0.87 ms).
- [x] New [`src/test/capture_npc_gear.gd`](src/test/capture_npc_gear.gd) captures every gear piece
**worn by a real avatar** through the runtime attach path, one frame per item, and
the gear-on-character sheet (retired with the review pages) collected them. It caught two things
the asset renders could not: `sunglasses` were hidden inside the hair shell, and the outfit's
own gear double-attached over the tested piece (the capture now clears it first).
- [x] Owner feedback on grip height applied: every hand item drops into the palm
(`HAND_ITEM_DROP`, camera 0.085 m, flashlight 0.065, cup 0.050, umbrella 0.045, clipboard and
board 0.035, phone/radio/wand 0.030), the carried role props drop 0.06 m, and the lanyard
attach moved from y 1.30 to 1.38 for the taller Quaternius sternum.
- [x] Owner verdict on the hand-held gear: accepted (2026-11-06).
**Exit:** every gear piece and role prop has a measured fit against the Quaternius attach points,
the hand-held items are within +/-10 % of their authored real-world size, and the review page row 4
is signed off.
### Gates and rollout
- [ ] Re-bake AO per rebuilt GLB and refresh the stale `.godot` import cache (scratch-copy
import) before judging any face or body change.
- [ ] Run `inspect`/`audit`/`fit`/`texels` and `npc_proportions.py report`; record the
12-variant measurement table.
- [ ] Capture the 12 × 6 baseline and get owner approval before replacing the committed GLBs.
- [-] Capture the 12 × 6 baseline and get owner approval before replacing the committed GLBs.
Owner signed off on 2026-11-06; the review page was retired afterwards.
- [ ] Re-run the 24-NPC budget smoke and the Web/Compatibility capture; record frame time,
mesh/triangle counts and Web load before/after.
- [ ] Retire the procedural variants that are no longer used, keeping one tested fallback; update
`docs/development-status.md`, `docs/3d-model-review.md`, `docs/blender-previews` sheets and
`docs/project/development-status.md`, `docs/assets/3d-model-review.md`, `docs/blender-previews` sheets and
the README character row.
- [ ] Release `0.9.10` with the full procedure (version, changelog, local build, checksums, tag).
- [ ] Shrink the release artifacts: `assets/` alone is ~273 MB in the Linux binary. Excluding
@@ -905,8 +944,11 @@ scorecard source, this milestone is the actionable list.
- [ ] Rebuild the ranked prop candidates from §D: the foliage-language P1
(`planter_box`/`round_planter` foliage, `street_tree`/`palm_tree`), plus the
`newspaper_box` slot and `bollard` collar if the budget allows.
- [ ] Replace the flat `_shrub()`/`_tree()` clumps with carded clusters and keep the 60k
library triangle budget; measure before/after.
- [x] Replace the flat `_shrub()` clumps with **leaf cards** (`_leaf_card()`), the foliage-language
P1. Each shrub is now one low-poly inner mass wrapped in 18–53 two-triangle cards scattered on
the canopy shell and tilted off its normal, so the silhouette is ragged instead of
rock-like — and it is *cheaper*: `planter_box` 1,324 → 818 tris, `round_planter`
1,240 → 808, `street_tree` 2,592 → 1,506. Props total 13,808 → 11,784 tris (budget 60k).
- [ ] Review the 18 gear pieces for silhouette and strap/buckle readability and rebuild only what
fails; re-run `fit` after every change.
- [ ] Verify prop colliders and navigation obstacles against the final silhouettes.
@@ -915,17 +957,42 @@ scorecard source, this milestone is the actionable list.
- [ ] Joke Shop / Hollywood shape language: fix the ranked remaining items (west rounded corner,
canopy pitch, facade reveal depth) only where a capture shows a readable gain.
- [ ] `lighting`/`lookdev` pass: flashlight cone/energy for the `06-night-flashlight` stage,
marquee/event-banner emissive read under the Compatibility renderer, street-lamp pools.
- [ ] Set dressing: fix the Joke Shop queue story (podium/stanchion line at the door), rope
barrier thickness, the west palm overlap and the empty sidewalk light pool; apply the same
review to Hollywood and the TV Studio.
- [x] **Flashlight tuned by measurement.** The late-night capture proved it did nothing: energy 4.2,
20 m range and a 14° cone changed the frame by **0.1/255**. Now 10 energy, 45 m, 24°, tilted 5°
down — the aimed region goes 13.5 → 29.7 and the near pavement 3.7 → 11.7 (0–255), and the
committed `06-night-flashlight` shot shows the beam on the steps and the NPC in front.
- [x] **Event banners read as lit cloth.** Measured flat top-to-bottom (114 → 125/255) with no
clipping, so the problem was not brightness but the missing gradient: four stacked strips
with night energies 2.6/2.2/1.8/1.4 now run 135 → 84, carried per material via `night_energy`
metadata so `set_night_mode` keeps the ratio. Daylight is unchanged and nothing clips.
- [x] **Street-lamp pools.** Added a `lamp_late` shot that frames a lamp, and made the lamps
`StreetLamp_*` so they tune apart from the sconces. Attenuation must stay 1.0 (the venue test
requires physical falloff), so the pool comes from range and energy: 16 m/2.2 → **10 m/8.0**
takes the pool 14.1 → 16.0 and the gap between poles 2.7 → 1.3, pool/gap 5.2 → 12.3.
- [x] Refresh `docs/screenshots/` for the whole roster and the new flashlight; `check_screenshots.sh`
reports 21 good / 0 bad.
- [x] **Joke Shop queue story.** The four queue props were scattered (stanchions at ±3, a barricade
at x 2.2, the podium at 6.8) so nothing read as a queue. They are now one line: four
stanchions 0.9 m apart west of the guest approach lane, the check-in podium at its head, and
the bike-rack barricade on the curb side. The placements stay outside the `guest approach
lane` exclusion that `placement_problems()` enforces.
- [x] **Rope and barrier thickness.** Bike-rack frame 22 → 28 mm, bars 10 → 12 mm, velvet rope
18 → 22 mm; the old sizes read as wire at 8 m.
- [x] **West palm / planter overlap.** The planter box sat under the west palm canopy (palm spans
x −15.0…−11.0 there) and the foliage cards clipped its lip; it moved 1.6 m clear.
- [x] **Hollywood and TV Studio review.** Hollywood: the lone stanchion and single barricade became
a three-post rope line into the check-in podium plus a curb barricade. TV Studio: **six
placement violations** surfaced once the validator was applied to it — three props sat inside
the steps/door exclusion and off the sidewalk at z 4.2–4.4; re-placed into a rope line +
podium + two barricades. `test_every_venue_placement_clears_the_sidewalk_and_the_approach`
now runs the validator on all three venues, so this cannot regress.
- [ ] Sidewalk light pool at the Joke Shop: the entrance walkway measures 20.7/255 against 3.0 on
the side pavement, so a pool exists but only at the door; the queue area itself is unlit.
- [ ] Build one real-photo comparison for street furniture and record the accepted mismatches.
### Evidence and release
- [ ] Refresh `sheet_props.jpg`, `sheet_npc_gear.jpg`, the three-up boards, the affected venue
captures and the README asset rows.
- [x] `sheet_props.jpg` and `sheet_npc_gear.jpg` rebuilt; the 21-image venue gallery regenerated.
- [ ] Re-run `tools/check_screenshots.sh` and `python3 tools/check_docs.py`; record both results.
- [ ] Release `0.9.11` with the full procedure.
@@ -983,7 +1050,7 @@ only release-blocking fixes and balance changes may land here.
### Balance and fairness
- [ ] Run the scripted venue sweeps across easy/normal/hard and all four phases using the
`docs/release-qa.md#balance-acceptance` targets; tune event weights, reaction tables,
`docs/process/release-qa.md#balance-acceptance` targets; tune event weights, reaction tables,
compliance and report strictness where targets fail.
- [ ] Review emergency calls against independent behaviour labels, not `_read_npc_truth()` as its
own oracle; no routine behaviour may make emergency the dominant winning move.
@@ -1009,8 +1076,8 @@ only release-blocking fixes and balance changes may land here.
### Documentation and visual sign-off
- [ ] Update `README.md`, `PLAN.md`, `docs/architecture.md`, the ADRs, `docs/development-status.md`,
`docs/getting-started.md`, `docs/release-qa.md`, `CHANGELOG.md` and this roadmap.
- [ ] Update `README.md`, `PLAN.md`, `docs/project/architecture.md`, the ADRs, `docs/project/development-status.md`,
`docs/process/getting-started.md`, `docs/process/release-qa.md`, `CHANGELOG.md` and this roadmap.
- [ ] Regenerate the gallery and realism baselines from the release-candidate build, not the dev
tree; verify every README/docs image resolves from the tagged build.
- [ ] Run the manual smoke checklist on every target and link the evidence.
@@ -1182,7 +1249,7 @@ Goal: publish the first stable release with a documented compatibility promise.
- [ ] Confirm legal, privacy, rating and storefront approval is complete in writing.
- [ ] Confirm the hardware matrix, accessibility audit and localization sign-off are complete.
- [ ] Confirm no P0/P1 defects remain and every P2 is a documented known limitation.
- [ ] Update `README.md`, `PLAN.md`, `docs/development-status.md`, `CHANGELOG.md`, `CREDITS.md`,
- [ ] Update `README.md`, `PLAN.md`, `docs/project/development-status.md`, `CHANGELOG.md`, `CREDITS.md`,
`PRIVACY.md` and the release notes for 1.0.0.
- [ ] Run the full release procedure: version 1.0.0, changelog, clean build, checksum
verification, tag, push and publish.
+196 -194
View File
@@ -117,39 +117,17 @@
"triangles": 312,
"vertices": 422
},
"cap": {
"attach": "head",
"bounds_godot": {
"max": [
0.108,
0.204,
0.165
],
"min": [
-0.108,
0.094,
-0.119
]
},
"category": "npc_gear",
"materials": [
"plastic_black"
],
"path": "assets/models/blender/npc_gear/cap.glb",
"triangles": 328,
"vertices": 285
},
"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
]
@@ -265,12 +243,12 @@
"bounds_godot": {
"max": [
0.166,
0.227,
0.26,
0.166
],
"min": [
-0.166,
0.092,
0.125,
-0.225
]
},
@@ -329,28 +307,6 @@
"triangles": 268,
"vertices": 400
},
"hood": {
"attach": "head",
"bounds_godot": {
"max": [
0.118,
0.221,
0.079
],
"min": [
-0.118,
-0.024,
-0.144
]
},
"category": "npc_gear",
"materials": [
"plastic_grey"
],
"path": "assets/models/blender/npc_gear/hood.glb",
"triangles": 804,
"vertices": 649
},
"lanyard": {
"attach": "chest",
"bounds_godot": {
@@ -431,12 +387,12 @@
"base": "hoodie",
"bounds_godot": {
"max": [
0.228,
0.262,
1.866,
0.287
],
"min": [
-0.228,
-0.262,
-0.004,
-0.091
]
@@ -448,9 +404,11 @@
"cloth",
"accessory",
"Eyebrows",
"Eye",
"sclera",
"hair",
"pants"
"pants",
"mouth",
"pupil"
],
"mesh_node": "npc_base",
"path": "assets/models/blender/npc/npc_casual.glb",
@@ -467,33 +425,36 @@
"accessory",
"hair"
],
"triangles": 6206,
"vertices": 12988
"triangles": 6242,
"vertices": 13100
},
"npc_coat": {
"base": "hoodie",
"base": "suit",
"bounds_godot": {
"max": [
0.228,
1.866,
0.287
0.255,
1.809,
0.279
],
"min": [
-0.228,
-0.004,
-0.091
-0.255,
-0.001,
-0.083
]
},
"category": "npc",
"layer": "coat",
"materials": [
"skin",
"Tie",
"cloth",
"White",
"accessory",
"Eyebrows",
"Eye",
"hair",
"pants"
"sclera",
"pants",
"pupil"
],
"mesh_node": "npc_base",
"path": "assets/models/blender/npc/npc_coat.glb",
@@ -509,21 +470,21 @@
"accessory",
"hair"
],
"triangles": 6206,
"vertices": 12988
"triangles": 6582,
"vertices": 13607
},
"npc_crowd_a": {
"base": "casual",
"base": "beach",
"bounds_godot": {
"max": [
0.18,
1.843,
0.271
0.252,
1.805,
0.277
],
"min": [
-0.18,
-0.009,
-0.099
-0.252,
-0.005,
-0.088
]
},
"category": "npc",
@@ -532,10 +493,12 @@
"skin",
"cloth",
"accessory",
"Hair_Brown",
"Brown",
"Eyebrows",
"sclera",
"hair",
"pants"
"Earrings",
"pants",
"pupil"
],
"mesh_node": "npc_base",
"path": "assets/models/blender/npc/npc_crowd_a.glb",
@@ -550,33 +513,38 @@
"accessory",
"hair"
],
"triangles": 6424,
"vertices": 13440
"triangles": 6602,
"vertices": 13557
},
"npc_crowd_b": {
"base": "casual",
"base": "farmer",
"bounds_godot": {
"max": [
0.18,
1.843,
0.271
0.256,
1.81,
0.28
],
"min": [
-0.18,
-0.009,
-0.099
-0.256,
-0.0,
-0.11
]
},
"category": "npc",
"layer": "none",
"materials": [
"skin",
"LightBlue",
"cloth",
"Beige",
"accessory",
"Hair_Brown",
"Brown",
"hair",
"pants"
"Eyebrows",
"Beige.001",
"Red",
"sclera",
"pants",
"pupil",
"hair"
],
"mesh_node": "npc_base",
"path": "assets/models/blender/npc/npc_crowd_b.glb",
@@ -591,33 +559,40 @@
"accessory",
"hair"
],
"triangles": 6424,
"vertices": 13440
"triangles": 5512,
"vertices": 11291
},
"npc_crowd_c": {
"base": "hoodie",
"base": "adventurer",
"bounds_godot": {
"max": [
0.228,
1.866,
0.287
0.255,
1.809,
0.279
],
"min": [
-0.228,
-0.004,
-0.091
-0.255,
-0.001,
-0.256
]
},
"category": "npc",
"layer": "coat",
"materials": [
"Brown",
"LightGreen",
"Gold",
"Green",
"skin",
"Tie",
"cloth",
"White",
"accessory",
"Eyebrows",
"Eye",
"hair",
"pants"
"sclera",
"pants",
"pupil"
],
"mesh_node": "npc_base",
"path": "assets/models/blender/npc/npc_crowd_c.glb",
@@ -632,21 +607,21 @@
"accessory",
"hair"
],
"triangles": 6206,
"vertices": 12988
"triangles": 9526,
"vertices": 19501
},
"npc_crowd_d": {
"base": "worker",
"bounds_godot": {
"max": [
0.217,
1.826,
0.262,
1.866,
0.287
],
"min": [
-0.217,
-0.262,
-0.004,
-0.065
-0.087
]
},
"category": "npc",
@@ -655,10 +630,14 @@
"skin",
"cloth",
"accessory",
"hair",
"Eyebrows",
"Moustache",
"Eye",
"pants"
"pants",
"Brows",
"sclera",
"hair",
"mouth",
"pupil"
],
"mesh_node": "npc_base",
"path": "assets/models/blender/npc/npc_crowd_d.glb",
@@ -673,33 +652,38 @@
"accessory",
"hair"
],
"triangles": 4458,
"vertices": 9370
"triangles": 6290,
"vertices": 13188
},
"npc_dress": {
"base": "casual",
"base": "king",
"bounds_godot": {
"max": [
0.18,
1.843,
0.271
0.249,
1.809,
0.269
],
"min": [
-0.18,
-0.009,
-0.099
-0.249,
-0.001,
-0.083
]
},
"category": "npc",
"layer": "dress",
"materials": [
"skin",
"Blue",
"cloth",
"Beige",
"Metal_Dark",
"accessory",
"Hair_Brown",
"Brown",
"hair",
"pants"
"Gold",
"sclera",
"pants",
"Metal_Dark_legs",
"pupil"
],
"mesh_node": "npc_base",
"path": "assets/models/blender/npc/npc_dress.glb",
@@ -713,21 +697,21 @@
"accessory",
"hair"
],
"triangles": 6424,
"vertices": 13440
"triangles": 11126,
"vertices": 22516
},
"npc_firefighter": {
"base": "worker",
"bounds_godot": {
"max": [
0.217,
1.826,
0.262,
1.866,
0.287
],
"min": [
-0.217,
-0.262,
-0.004,
-0.065
-0.087
]
},
"category": "npc",
@@ -736,10 +720,14 @@
"skin",
"cloth",
"accessory",
"hair",
"Eyebrows",
"Moustache",
"Eye",
"pants"
"pants",
"Brows",
"sclera",
"hair",
"mouth",
"pupil"
],
"mesh_node": "npc_base",
"path": "assets/models/blender/npc/npc_firefighter.glb",
@@ -753,21 +741,21 @@
"accessory",
"hair"
],
"triangles": 4458,
"vertices": 9370
"triangles": 6290,
"vertices": 13188
},
"npc_guard": {
"base": "worker",
"bounds_godot": {
"max": [
0.217,
1.826,
0.262,
1.866,
0.287
],
"min": [
-0.217,
-0.262,
-0.004,
-0.065
-0.087
]
},
"category": "npc",
@@ -776,10 +764,14 @@
"skin",
"cloth",
"accessory",
"hair",
"Eyebrows",
"Moustache",
"Eye",
"pants"
"pants",
"Brows",
"sclera",
"hair",
"mouth",
"pupil"
],
"mesh_node": "npc_base",
"path": "assets/models/blender/npc/npc_guard.glb",
@@ -794,33 +786,38 @@
"accessory",
"hair"
],
"triangles": 4458,
"vertices": 9370
"triangles": 6290,
"vertices": 13188
},
"npc_hoodie": {
"base": "hoodie",
"base": "punk",
"bounds_godot": {
"max": [
0.228,
1.866,
0.287
0.241,
1.806,
0.263
],
"min": [
-0.228,
-0.241,
-0.004,
-0.091
-0.147
]
},
"category": "npc",
"layer": "hood",
"materials": [
"skin",
"White",
"cloth",
"accessory",
"sclera",
"Eyebrows",
"Eye",
"Red_Dark",
"hair",
"pants"
"Earrings",
"Skin_legs",
"pants",
"pupil"
],
"mesh_node": "npc_base",
"path": "assets/models/blender/npc/npc_hoodie.glb",
@@ -836,21 +833,21 @@
"accessory",
"hair"
],
"triangles": 6206,
"vertices": 12988
"triangles": 5524,
"vertices": 11257
},
"npc_jacket": {
"base": "casual",
"base": "casual_2",
"bounds_godot": {
"max": [
0.18,
1.843,
0.271
0.255,
1.809,
0.279
],
"min": [
-0.18,
-0.009,
-0.099
-0.255,
-0.001,
-0.164
]
},
"category": "npc",
@@ -859,10 +856,12 @@
"skin",
"cloth",
"accessory",
"Hair_Brown",
"Brown",
"Skin_Darker",
"Eyebrows",
"hair",
"pants"
"sclera",
"pants",
"pupil"
],
"mesh_node": "npc_base",
"path": "assets/models/blender/npc/npc_jacket.glb",
@@ -878,21 +877,21 @@
"accessory",
"hair"
],
"triangles": 6424,
"vertices": 13440
"triangles": 5800,
"vertices": 11866
},
"npc_vest": {
"base": "worker",
"bounds_godot": {
"max": [
0.217,
1.863,
0.262,
1.789,
0.287
],
"min": [
-0.217,
-0.262,
-0.004,
-0.103
-0.083
]
},
"category": "npc",
@@ -900,13 +899,16 @@
"materials": [
"skin",
"Worker_Yellow",
"Worker_Vest",
"cloth",
"accessory",
"hair",
"Eyebrows",
"Moustache",
"Eye",
"pants"
"pants",
"Brows",
"sclera",
"hair",
"mouth",
"pupil"
],
"mesh_node": "npc_base",
"path": "assets/models/blender/npc/npc_vest.glb",
@@ -920,8 +922,8 @@
"accessory",
"hair"
],
"triangles": 5240,
"vertices": 10936
"triangles": 6290,
"vertices": 13186
},
"palm_tree": {
"bounds_godot": {
@@ -973,7 +975,7 @@
"bounds_godot": {
"max": [
0.5,
1.08,
1.118,
0.5
],
"min": [
@@ -991,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",
@@ -1047,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",
@@ -1064,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",
@@ -1219,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",
@@ -1238,20 +1240,20 @@
],
"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.065,
0.108,
0.141,
0.101
],
"min": [
-0.065,
0.077,
0.11,
0.002
]
},
Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 67 KiB

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 67 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: 72 KiB

Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

After

Width:  |  Height:  |  Size: 72 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: 29 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.
@@ -21,7 +21,7 @@ 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/npc-model-sourcing.md`):
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;
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. [Quaternius NPC base migration](../TODO.md#quaternius-npc-base-migration-top-priority) — CC0 Quaternius mesh/animation source baked to the 24,000-budget runtime contract.
2. [3D model and local map improvements](../TODO.md#3d-model-and-local-map-re-evaluation) — 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) — retained MakeHuman fallback head, 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
+2 -2
View File
@@ -21,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
@@ -86,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).
+1 -1
View File
@@ -16,7 +16,7 @@ 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/npc-model-sourcing.md`](../npc-model-sourcing.md).
base. The full evaluation is in [`docs/assets/npc-model-sourcing.md`](../assets/npc-model-sourcing.md).
## Decision
@@ -10,7 +10,7 @@ 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/npc-model-sourcing.md`
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:
@@ -36,8 +36,10 @@ option 2). The mesh is not proportion-warped: it keeps its source LOD (3,199 wel
- `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 Quaternius Idle and Walk clips are used directly — they are authored for the 62-joint rig,
so no retargeting pass is needed. Combat/gun/sword clips stay unused.
- 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.
@@ -79,7 +81,7 @@ rollout.
- **Date:** 2026-11-05 (owner, at the `0.9.9` face/silhouette gate)
The owner chose **option (a) full swap** from
[`docs/screens/npc-face-gate/`](../../screens/npc-face-gate/README.md): every roster character
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.
@@ -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
@@ -88,7 +88,7 @@ Readings:
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
([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.
@@ -283,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
@@ -500,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,14 +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)).
([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
@@ -118,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,
@@ -138,7 +138,7 @@ the fallback. Kenney/Khronos/MakeHuman remain evaluated references, not active b
| 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
@@ -246,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
@@ -265,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.
@@ -302,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
@@ -317,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`.
@@ -493,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).
@@ -553,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,
@@ -578,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 -- \
@@ -615,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,21 +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). 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
([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
@@ -143,7 +143,7 @@ render about 2.5 min.
## Characters
All library variants share the
[character and gear asset contract](architecture.md#character-and-gear-asset-contract):
[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.
@@ -176,6 +176,17 @@ 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
@@ -190,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
@@ -232,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).
@@ -255,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).
@@ -10,8 +10,8 @@ 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)
- 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
@@ -26,7 +26,7 @@ base. The development source files were removed from `tmp/` on 2026-11-05.
- 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
@@ -54,7 +54,7 @@ base. The development source files were removed from `tmp/` on 2026-11-05.
- Base mesh: MakeHuman / MPFB base, CC0, from the local research set
(development source files removed after the 2026-11-05 Quaternius pivot); see
[`CREDITS.md`](../CREDITS.md).
[`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. It is retained as a fallback, not the active NPC base.
@@ -1,8 +1,8 @@
# 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).
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
@@ -198,7 +198,7 @@ deltoid + hand) — both are the gate's rejection conditions.
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
[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).
@@ -236,7 +236,9 @@ Two source quirks shaped the bake:
- 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 and silhouette gate sheet is in [`screens/npc-face-gate/`](screens/npc-face-gate/README.md).
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)
@@ -279,6 +281,60 @@ Head gear is authored for this head: `HEAD_GEAR_SCALE = 0.64` and `HEAD_GEAR_LIF
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
@@ -298,7 +354,7 @@ not a local workaround.
## Licence and provenance
- CC0 preferred. CC-BY is allowed only with attribution in
[`CREDITS.md`](../CREDITS.md).
[`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`.
@@ -313,12 +369,12 @@ 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.
[`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](architecture.md#character-and-gear-asset-contract)
- [`3d-model-review.md`](3d-model-review.md), [`npc-visual-review.md`](npc-visual-review.md)
- [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
-317
View File
@@ -1,317 +0,0 @@
# NPC visual baseline and acceptance criteria
Status: **accepted 2026-11-02 for the 0.9.4 stylized target.** The P1 fixes
(tourist photo-prop visibility, backpack straps), neck/shoulder and torso/hip
transitions, face depth/detail, hand and gear placement, headgear clearance and
shoe/boot silhouettes are applied. The baseline remains the comparison reference;
the accepted limitations are listed below. Comparison sheets:
[`sheet_npc_baseline_compare-p1.jpg`](blender_previews/sheet_npc_baseline_compare-p1.jpg),
[`sheet_npc_baseline_compare-body.jpg`](blender_previews/sheet_npc_baseline_compare-body.jpg),
the latest [`sheet_npc_baseline_compare-torso.jpg`](blender_previews/sheet_npc_baseline_compare-torso.jpg),
the face-detail pass [`sheet_npc_baseline_compare-face-detail.jpg`](blender_previews/sheet_npc_baseline_compare-face-detail.jpg),
the conversation-distance hand pass
[`sheet_npc_hands_compare.jpg`](blender_previews/sheet_npc_hands_compare.jpg), and the
forward-grip pass [`sheet_npc_hands_grip_compare.jpg`](blender_previews/sheet_npc_hands_grip_compare.jpg).
The 2026-11-03 skill-guided re-evaluation, its measurements (texel density, budgets, imported
bounds) and the open scorecard live in [`3d-model-review.md`](3d-model-review.md). It does not
change the accepted limits below.
A single-variant face prototype (`npc_casual`) landed 2026-11-03/04: `seg=24/rings=16` head,
subtle brow ridge, fuller lower lip and both eyelids. It reads cleaner than the 0.9.4 face and is
a candidate for the remaining seven once the owner approves (see the review doc).
## What was captured
`src/test/capture_npc_baseline.gd` stages all eight library characters in a
neutral studio and captures six views per character:
| View | Camera | Purpose |
| --- | --- | --- |
| `front` | 1.85 m, 32° FOV, head/upper body | face, hair, collar, shoulders |
| `three_quarter` | 1.85 m, yaw 35° | cheek/jaw, ear, profile transition |
| `profile` | 1.85 m, yaw 90° | head depth, nose, ear, chest silhouette |
| `back` | 1.85 m, yaw 180° | hair cap, neck, coat/backpack fit |
| `full_body` | 4.2 m, 38° FOV | proportions, hands, shoes, hem |
| `crowd` | 8.0 m, 45° FOV | silhouette read at normal crowd distance |
The stage is deliberately separate from the venue review harness: a mid-grey
solid background, ground plane, one key light and one cool fill light, no HUD,
no crowd, no flashlight, no phase lighting and no animation. Front is Godot +Z,
matching `NpcAvatar.yaw_towards()`. The camera orbits at the recorded yaw rather
than rotating the avatar, so the pose and foot contact stay fixed between views.
The full command is:
```bash
godot --path . --script res://src/test/capture_npc_baseline.gd -- \
--out=res://tmp/npc-baseline
python3 tools/npc_baseline.py sheet --dir tmp/npc-baseline
```
The 48 raw PNGs are local QA under `tmp/` (gitignored). The committed contact
sheet is [`blender_previews/sheet_npc_baseline.jpg`](blender_previews/sheet_npc_baseline.jpg).
For the P2 hand/grip check there is an optional eighth view, captured separately
so the 48-frame baseline stays stable:
```bash
godot --path . --script res://src/test/capture_npc_baseline.gd -- \
--out=res://tmp/npc-hands --view=hand
```
That writes eight `*__hand.png` frames at 0.80 m from the right hand; the
before/after review image is
[`sheet_npc_hands_compare.jpg`](blender_previews/sheet_npc_hands_compare.jpg).
The capture is deterministic apart from engine rasterisation; re-running into
the same directory keeps the earlier files and writes `-vN` copies rather than
overwriting them.
## Acceptance criteria
The criteria below are for the stylized target, not photorealism. A change must
pass every applicable item before a library rebuild is accepted.
1. **Asset contract:** `npc_base` mesh node, the required bones, five tint slots,
front +Z, feet within 3 cm of y=0, 1.6–2.1 m height, at most 24,000 triangles
and 24,000 glTF vertices per character. The required 13 core bones stay fixed;
optional extra bones are allowed. Gear remains at most 1,500 triangles.
2. **Proportion and silhouette:** head, neck, shoulders, torso, hips, limbs and
feet read as one body; front/three-quarter/profile silhouettes agree with the
rest of the eight-character library; broad/slim/average build variation is
preserved.
3. **Face:** at 1.85 m the eyes, iris, brows, nose, mouth and ears are distinct;
the head volume has a readable jaw/cheek/chin transition; no face-plane seams,
inverted normals or z-fighting. The face direction must remain unambiguous.
4. **Hair and headgear:** hair covers the scalp without gaps or scalp-through
seams; fringes, buns and beards keep their silhouette. Caps, hoods,
sunglasses and the firefighter helmet clear the brow, eyes and ears. Headgear
may sit outside the 1.55–1.81 m face band, but its brim must not cover the
eyes.
5. **Hands and footwear:** at conversation distance the fingers and thumb read
as a hand, not a mitten; hand items contact the palm rather than floating;
shoes and boots are grounded with a readable toe/heel silhouette and preserve
the responder/firefighter footwear language.
6. **Clothing:** collars, cuffs, plackets, waistbands, pockets, badges and
reflective bands transition cleanly; no z-fighting or floating detail; coat,
dress and skirt hems do not show legs through the fabric during idle, walk,
block, sit or turn; the five tint slots and fixed detail colours remain
unchanged.
7. **Gear:** head gear clears the refined face/hair; the lanyard badge remains
readable in front of the jacket; backpack, shoulder bag and SCBA tank straps
lie outside the torso and do not read as a second bag; hand items use the
authored grip points.
8. **Crowd and performance:** the silhouette remains readable at the 8 m crowd
frame and the LOD/impostor tiers match the full mesh; the 24-NPC budget stays
within the existing 6.94 ms baseline (no regression beyond the measured
variance), and no new per-frame material or mesh churn is introduced.
Asset-space `fit` values are measurements of the untouched GLBs, not a pass/fail
result. A negative `x_clearance` means the gear's narrowest face is inside the
body reference; a negative `radial_clearance` means it extends beyond the body
silhouette (normal for a backpack, suspicious when it is a strap). Runtime
`NpcAvatar.GEAR_OFFSETS` is applied after attachment and is not part of the GLB
measurement.
## Proportion audit
Status: audited 2026-11-02. All eight library variants are inside the stylized
proportion guide; no geometry correction was required in this pass. The report
is repeatable from the exported GLBs:
```bash
python3 tools/npc_proportions.py report
python3 tools/npc_proportions.py report --json
```
### Method
`tools/npc_proportions.py` reads the GLB meshes and rest-pose joint hierarchy:
- height from the full mesh bounds;
- head height, width and aspect from `Head`/`skin` vertices (hair excluded so
long hairstyles do not change the head measurement);
- shoulder silhouette from vertices in the upper-chest band around the
shoulder joint;
- hip width from `HipL`/`HipR` pants vertices;
- torso length from the Spine joint to the shoulder joint;
- leg length from the Spine joint to the lowest vertex;
- arm length from the shoulder joint to the Hand joint;
- foot length from the forward extent of the KneeL/KneeR shoe vertices.
All ratios are divided by total standing height except `head_aspect`
(width / head height).
### Guide
These are stylized-but-credible bands for the game's low-poly adults, not
photoreal anatomy. The broad build is allowed a larger shoulder/hip silhouette
than the slim build.
| Ratio | Target | Notes |
| --- | ---: | --- |
| `head_height` | 0.16–0.22 | deliberately larger than a realistic 0.13–0.15 |
| `head_aspect` | 0.70–1.00 | width / height; rounded heads are acceptable |
| `shoulder_width` | 0.28–0.38 | silhouette includes sleeves and build scaling |
| `hip_width` | 0.17–0.23 | pants-only width, not skirt/coat flare |
| `torso_length` | 0.28–0.38 | Spine joint to shoulder |
| `leg_length` | 0.40–0.48 | Spine joint to ground |
| `arm_length` | 0.28–0.38 | shoulder to hand |
| `foot_length` | 0.12–0.18 | shoe forward extent |
### Result
| Character | Height | Head | Aspect | Shoulder | Hip | Torso | Leg | Arm | Foot | Result |
| --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | --- |
| `npc_casual` | 1.824 m | 0.190 | 0.907 | 0.321 | 0.209 | 0.307 | 0.449 | 0.329 | 0.144 | PASS |
| `npc_jacket` | 1.824 m | 0.190 | 0.907 | 0.333 | 0.209 | 0.307 | 0.449 | 0.329 | 0.144 | PASS |
| `npc_coat` | 1.824 m | 0.190 | 0.907 | 0.328 | 0.209 | 0.307 | 0.449 | 0.329 | 0.144 | PASS |
| `npc_vest` | 1.819 m | 0.191 | 0.907 | 0.322 | 0.209 | 0.308 | 0.451 | 0.330 | 0.144 | PASS |
| `npc_dress` | 1.825 m | 0.190 | 0.907 | 0.289 | 0.191 | 0.307 | 0.449 | 0.329 | 0.144 | PASS |
| `npc_hoodie` | 1.856 m | 0.187 | 0.907 | 0.328 | 0.206 | 0.302 | 0.442 | 0.323 | 0.141 | PASS |
| `npc_firefighter` | 1.819 m | 0.191 | 0.907 | 0.358 | 0.223 | 0.308 | 0.451 | 0.330 | 0.148 | PASS |
| `npc_guard` | 1.819 m | 0.191 | 0.907 | 0.369 | 0.219 | 0.308 | 0.451 | 0.330 | 0.144 | PASS |
No variant is outside a band, so the body pass does not need a global skeleton
or mesh rescale. The values closest to a boundary are:
- **head height 0.190** against the 0.22 upper bound, and **head aspect 0.907**
against 1.00 — the head is deliberately large. Any head-size change must be
coordinated with the face/headgear pass and its gear-fit measurements.
- **guard shoulder 0.369** and **firefighter hip 0.223** against the broad-build
upper bounds — these are the intended uniform/turnout silhouettes, not
outliers.
- **leg length 0.449** and **torso 0.307** sit inside the guide for all variants;
the earlier short-leg impression came from the hip joint position, not the
visible pelvis line.
### Follow-up
The proportion audit does not replace the visual criteria in
[`npc-visual-review.md`](npc-visual-review.md): neck/shoulder/hip transitions,
face depth, hand grips, clothing hems and shoes still need the appearance pass.
Re-run the audit after any body mesh or skeleton change and record the new
ratios here.
## Baseline measurements
From `python3 tools/blender_assets.py fit` and the manifest:
| Character | Tris | Verts | Head width | Clothing radius | Notable gear clearances |
| --- | ---: | ---: | ---: | ---: | --- |
| `npc_casual` | 4,482 | 4,260 | 0.315 m | 0.191 m (hip) | backpack x −0.041, radial −0.162 |
| `npc_jacket` | 4,872 | 4,661 | 0.315 m | 0.191 m (hip) | lanyard x −0.116, radial +0.023 (runtime +4 cm forward) |
| `npc_coat` | 5,474 | 5,264 | 0.315 m | 0.225 m (skirt) | sunglasses width ratio 0.641; bag x +0.037, radial −0.130 |
| `npc_vest` | 4,980 | 4,879 | 0.315 m | 0.191 m (hip) | cap width ratio 1.067 |
| `npc_dress` | 4,900 | 4,719 | 0.315 m | 0.260 m (skirt) | bag x +0.002, radial −0.095 |
| `npc_hoodie` | 5,304 | 4,950 | 0.315 m | 0.190 m (hip) | — |
| `npc_firefighter` | 5,344 | 5,494 | 0.315 m | 0.255 m (skirt) | helmet width ratio 1.651; SCBA x −0.105, radial −0.076 |
| `npc_guard` | 5,046 | 5,096 | 0.315 m | 0.194 m (hip) | cap width ratio 1.067 |
`npc_coat` is widest at 5,474 triangles (well below the 16,000 cap);
`npc_firefighter` is closest on vertices at 5,494 (well below the 16,000 cap).
The refit backpack measures 380 triangles / 406 vertices.
## Baseline findings, ranked
### P1 — fix in the first model pass
1. **The tourist carried two bag silhouettes. Fixed 2026-11-02.** `_add_props()`
created a 0.30 × 0.36 × 0.14 box at `(-0.34, 1.15, -0.18)` for the tourist
photo pose while `_add_accessory("backpack")` also attached the library
backpack. From the three-quarter/back view the two read as separate bags. The
photo prop is now hidden outside `photo`/`film` poses
(`photo_prop_visible_for_pose()`), so it only appears when the character is
actually taking a picture; the after frame confirms one bag at rest.
2. **Face depth and detail. Fixed 2026-11-02.** The sclera was recessed into the
socket and wrapped with a thin upper lid; the separate jaw/cheek spheres were
replaced by a chin plate and cheekbones sculpted into the head mesh. The nose
now has ala wings and a smaller bridge/tip, the mouth is one rounded slot
instead of a flat bar, and the ears have a darker concha. That removes the
dark intersection rings and the moustache-like read at portrait distance; the
low-poly brows remain stylized.
3. **Backpack straps read as rigid black bars. Refit 2026-11-02.** The straps
were thin round tubes whose chest/waist points sat inside the torso, so only
fragments showed from the front. They are now flattened bands whose front path
sits outside the chest; the after sheet shows a continuous strap instead of
two detached rods. The backpack asset is now 380 triangles / 406 vertices
(still far below the 1,500-triangle gear budget).
### P2 — fix after the first P1 pass
4. **Hands: geometry and forward offset fixed 2026-11-02; finger curl still
open.** The palm is wider and shallower, and each finger is now a
two-segment bent tube with a rounded tip and a separate bent thumb. Hand gear
is authored around the wrist proxy, so the runtime now moves every hand item
`HAND_ITEM_FORWARD` (4 cm) into the open palm; the phone, flashlight, camera,
cup and clipboard are no longer buried inside the hand. The fingers are still
open, so a true wrap/thumb contact and the umbrella/sign grips remain to be
judged.
5. **Clothing detail is tile-driven and transitional seams are visible.** The
fabric pattern repeats strongly on the casual, coat and dress variants, and
collar/cuff/waist edges are abrupt. This is more visible than the shoe/hem
details in the current portraits.
6. **Shoes: fixed 2026-11-02.** Casual shoes gained rounded toe and heel caps;
responder/firefighter boots gained matching toe/heel volumes while keeping the
taller black rubber boot language. Both stay above the sole contact plane, and
the full-body comparison is `sheet_npc_baseline_compare-shoes.jpg`.
7. **Headgear scale and clearance. Checked 2026-11-02.** The cap and helmet
width ratios are 1.067 and 1.651; those are expected for headgear. Final-context
portraits confirm the cap, firefighter helmet, hood and sunglasses clear the
refined brow/eyes, and the helmet brim still reads as deliberate turnout gear.
No gear rebuild was needed.
8. **Performer props dominate the silhouette.** The red cone hat and the
primitive sign are intentionally large stage props, but they should be
checked during the pose pass so they do not read as head/body geometry.
### Accepted limits for the 0.9.4 release
- The hooded variants intentionally cover part of the face; face readability is
judged on the visible lower face and silhouette, not on hidden eyes.
- The low-poly style is the target. The acceptance bar is readability and clean
construction, not photoreal skin or hair.
- Held items use the forward-offset open palm (`HAND_ITEM_FORWARD`) rather than a
finger-curl rig. There are no finger bones in the contract; phone, cup,
clipboard, camera, flashlight, wand and radio were judged in the hand capture.
- Fabric folds are not separate geometry; the current torso, elbow and knee
shaping is the accepted stylized construction.
- The >26 m impostor remains a two-quad billboard; the LOD tier/hysteresis and
near/far swap are covered by `test_avatar_mesh_budget_and_lod_swap`.
- NPC fabric textures are 256² with a 4× UV repeat; cloth/pants skip the baked
per-character AO to avoid large portrait blotches. Skin, hair and gear keep AO.
- Evening readability is represented by the day/night/LATE final-context set;
LATE is the venue night variant.
## Before/after workflow
Keep the baseline directory, rebuild the same capture into a new directory after
the model changes, then produce a comparison sheet. Do not overwrite the
committed baseline image:
```bash
godot --path . --script res://src/test/capture_npc_baseline.gd -- \
--out=res://tmp/npc-baseline-after
python3 tools/npc_baseline.py compare \
--before tmp/npc-baseline --after tmp/npc-baseline-after \
--out tmp/npc-baseline-compare.jpg
```
The comparison sheet places the before/after pair for each view side by side.
The committed runs are
[`sheet_npc_baseline_compare-p1.jpg`](blender_previews/sheet_npc_baseline_compare-p1.jpg),
[`sheet_npc_baseline_compare-body.jpg`](blender_previews/sheet_npc_baseline_compare-body.jpg)
and [`sheet_npc_baseline_compare-face.jpg`](blender_previews/sheet_npc_baseline_compare-face.jpg).
The transition pass is [`sheet_npc_baseline_compare-torso.jpg`](blender_previews/sheet_npc_baseline_compare-torso.jpg).
The face-detail pass is [`sheet_npc_baseline_compare-face-detail.jpg`](blender_previews/sheet_npc_baseline_compare-face-detail.jpg).
The hand pass is [`sheet_npc_hands_compare.jpg`](blender_previews/sheet_npc_hands_compare.jpg);
the forward-grip pass is
[`sheet_npc_hands_grip_compare.jpg`](blender_previews/sheet_npc_hands_grip_compare.jpg).
The 0.9.5 texture pass adds
[`sheet_texture_refinement_0.9.5.jpg`](blender_previews/sheet_texture_refinement_0.9.5.jpg),
which pairs the close-range surface and cloth comparisons. Keep the baseline
sheet as the before artifact and add a new comparison sheet rather than
replacing it.
## Next implementation order
0.9.4 and the 0.9.5 texture pass are closed. The next visual work belongs to the
0.10.0 acceptance review; keep the NPC baseline/final-context commands as the
regression gate for any future character edit.
+11
View File
@@ -0,0 +1,11 @@
# Process Documentation
Setup, quality assurance and releasing.
- [`getting-started.md`](getting-started.md) — setup, run/test commands, controls and save data.
- [`release-qa.md`](release-qa.md) — the manual smoke checklist and the balance-acceptance
protocol.
- [`RELEASING.md`](RELEASING.md) — export templates, release build, CI/publishing and rollback.
Up: [`../README.md`](../README.md) · Product plan: [`../../PLAN.md`](../../PLAN.md) · Tasks:
[`../../TODO.md`](../../TODO.md).
@@ -127,7 +127,7 @@ the documented right-click/`xattr` quarantine instructions. Signing and
notarization remain a public-release blocker until an Apple Developer account and
a reproducible signing/notarization job are available; they are not silently
claimed as complete. The same limitation is recorded in
[`known-limitations.md`](known-limitations.md).
[`known-limitations.md`](../design/known-limitations.md).
Always run the release build from a clean checkout or detached worktree. Godot
can pack files from ignored `tmp/` and old `build/` folders into the PCK; the
@@ -205,7 +205,7 @@ change, update `tools/build_releases.sh` first.
- [ ] All headless tests pass (exit code 0).
- [ ] Game boots cleanly in a smoke test.
- [ ] Controls documented in `docs/getting-started.md` match the build.
- [ ] Controls documented in `docs/process/getting-started.md` match the build.
- [ ] Version in `project.godot` matches the tag.
- [ ] Export templates used are the official ones for the pinned engine.
- [ ] Artifacts uploaded; README downloads page shows them.
@@ -87,7 +87,7 @@ The game writes four JSON files in Godot's `user://` directory:
Files: `settings.json`, `campaign.json`, `shift_results.json` and the versioned
`shift_state.json` checkpoint. The schema, migration/default-filling rules,
atomic-write behavior and checkpoint contents are in
[`architecture.md#persistence-and-save-contract`](architecture.md#persistence-and-save-contract).
[`architecture.md#persistence-and-save-contract`](../project/architecture.md#persistence-and-save-contract).
For a clean first launch, delete the four files (or the whole `Gig Line` user
directory). Settings' **Reset campaign** clears campaign progress separately.
@@ -60,8 +60,8 @@ owns the mechanics.
These are the acceptance targets for the 0.10.0 balance pass, not measured results.
No reaction tables, event weights or scoring rules were changed to set them. The
[roadmap](../TODO.md) tracks the sweeps and external playtests still needed.
[Gameplay](gameplay.md) owns the mechanics; this page owns their balance-test protocol.
[roadmap](../../TODO.md) tracks the sweeps and external playtests still needed.
[Gameplay](../design/gameplay.md) owns the mechanics; this page owns their balance-test protocol.
### Test matrix and evidence
+11
View File
@@ -0,0 +1,11 @@
# Project Documentation
Architecture and project status.
- [`architecture.md`](architecture.md) — the arc42-style architecture: goals, constraints,
building blocks, runtime views, decisions and risks.
- [`development-status.md`](development-status.md) — the canonical implemented-features list,
verification baseline and known gaps.
Up: [`../README.md`](../README.md) · Product plan: [`../../PLAN.md`](../../PLAN.md) · Tasks:
[`../../TODO.md`](../../TODO.md).
@@ -27,8 +27,8 @@ This document follows the structure of the arc42 architecture documentation temp
- The first implementation should be small enough for a playable vertical slice.
- The engine is Godot 4.7.2 with GDScript; a playable prototype vertical slice is implemented. CI, local development and exported builds use 4.7.2; the default renderer stays GL Compatibility for Web parity, with an optional Forward+ Desktop HQ build.
- Venue-specific policies must be configurable rather than hard-coded into individual NPCs.
- The game must preserve the de-escalation-first design described in [`PLAN.md`](../PLAN.md).
- The project uses the repository workflow described in [`AGENTS.md`](../AGENTS.md).
- The game must preserve the de-escalation-first design described in [`PLAN.md`](../../PLAN.md).
- The project uses the repository workflow described in [`AGENTS.md`](../../AGENTS.md).
- The project follows [Semantic Versioning](https://semver.org/) (`MAJOR.MINOR.PATCH`).
### Version management
@@ -37,7 +37,7 @@ This document follows the structure of the arc42 architecture documentation temp
- **MINOR** — new venues, NPC archetypes, systems, or features that are backward compatible.
- **PATCH** — bug fixes and small polish that do not change behavior.
The single source of truth for the version is `config/version` in `project.godot` (currently `0.9.8`). Each release is tagged in git as `v<version>` (e.g. `v0.6.0`). The `0.x` series is pre-stable, so MINOR bumps may introduce breaking changes while the prototype is still stabilizing. `tools/build_releases.sh` and `tools/publish_release.sh` read the version from `project.godot`, so bumping it there is the only required step before a release. The full bump checklist lives in [`RELEASING.md`](RELEASING.md).
The single source of truth for the version is `config/version` in `project.godot` (currently `0.9.9`). Each release is tagged in git as `v<version>` (e.g. `v0.6.0`). The `0.x` series is pre-stable, so MINOR bumps may introduce breaking changes while the prototype is still stabilizing. `tools/build_releases.sh` and `tools/publish_release.sh` read the version from `project.godot`, so bumping it there is the only required step before a release. The full bump checklist lives in [`RELEASING.md`](../process/RELEASING.md).
## 3. Context and Scope
@@ -82,7 +82,7 @@ The player interacts with NPCs, venue entrances, access artifacts, equipment, st
- `src/game/ui/art.gd` loads runtime UI/scene art from `assets/images/ui/` and `assets/images/scenes/`, with null fallbacks so panels keep their procedural layouts.
- `tools/model_pipeline.py` builds and audits the street-prop `.glb` models and packs their colour atlases.
- `tools/npc_pipeline.py` builds and audits the skinned NPC base model (`assets/models/generated/npc_base.glb`) and its per-slot material maps, with an optional AI fabric override (ADR-0013). The active character migration bakes the CC0 Quaternius base onto the same contract (ADR-0017); the procedural base remains the fallback.
- `tools/blender_assets.py` builds, renders and audits the Blender asset library (`assets/models/blender/{npc,npc_gear,props}/` + `manifest.json`): NPC character variants that are drop-in for `npc_base`, attach-point gear, and street/venue props. `NpcAvatar` selects variants/gear by role/seed and `WorldBuilder` loads the prop replacements and new street dressing, with procedural fallbacks (see `docs/blender-assets.md`).
- `tools/blender_assets.py` builds, renders and audits the Blender asset library (`assets/models/blender/{npc,npc_gear,props}/` + `manifest.json`): NPC character variants that are drop-in for `npc_base`, attach-point gear, and street/venue props. `NpcAvatar` selects variants/gear by role/seed and `WorldBuilder` loads the prop replacements and new street dressing, with procedural fallbacks (see `docs/assets/blender-assets.md`).
- `tools/scene_concepts.py` generates realism-pass references (`docs/screens/concepts/`), skyline backdrops and surface tiles (raw `assets/textures/ai/v2/raw/` → candidates `assets/textures/ai/game_ready/v2/`), promotes the validated ones to the tracked `v2/picks/` that `SurfaceMaterials`/`WorldBuilder` preload, audits them, and scores `src/test/capture_realism.gd` A/B captures (six stages, runtime texture swaps) against the concepts (`docs/screens/realism/<run>/`).
- `tools/asset_pipeline.py` generates and audits role-aware textures; `tools/screen_designs.py` generates screen references and judges captures; `tools/check_screenshots.sh` renders the staged gallery and runs the compare gate.
@@ -90,7 +90,7 @@ Confirmed game assets live in `assets/textures/ai/game_ready/` (audited surface,
### Asset storage conventions
The canonical rules live in [ADR-0014](adr/0014-runtime-image-root.md). In short:
The canonical rules live in [ADR-0014](../adr/0014-runtime-image-root.md). In short:
| Location | Contents | Loaded at runtime? |
| --- | --- | --- |
@@ -190,7 +190,7 @@ Venue rules:
Persistence is local-only under Godot's `user://` directory. The architecture
owns the schema; operational locations and reset/rollback steps live in
[`getting-started.md`](getting-started.md#save-data-and-migration).
[`getting-started.md`](../process/getting-started.md#save-data).
| File | Contents | Compatibility |
| --- | --- | --- |
@@ -218,10 +218,10 @@ developer tools only — runtime, tests and CI consume committed GLBs and maps.
| Tool | Role | Committed artifact | Verification gate |
| --- | --- | --- | --- |
| `tools/npc_pipeline.py` | Builds the skinned base avatar, five-slot material maps, palette and AI-fabric preparation (`prepare`/`palette`) | `npc_base.glb`, `assets/textures/npc/*_{albedo,normal,orm}.png`, `palette.json` | `audit_glb` against the 24,000-triangle / 24,000-vertex base contract (13 core bones required; extras allowed) |
| `tools/blender_assets.py` | Builds/renders the library: 8 characters, 18 gear pieces, 20 props, plus `manifest.json`; stdlib `audit`/`fit`/`sheet`/`list` | `assets/models/blender/{npc,npc_gear,props}/*.glb` | Character cap 24,000 tris / 24,000 verts, 1,500 per gear, 4,000 per prop; grounding, UV, degenerate-triangle, attach-fit and manifest coverage checks |
| `tools/blender_assets.py` | Builds/renders the library: 12 characters, 15 gear pieces, 20 props, plus `manifest.json`; stdlib `audit`/`fit`/`sheet`/`list` | `assets/models/blender/{npc,npc_gear,props}/*.glb` | Character cap 24,000 tris / 24,000 verts, 1,500 per gear, 4,000 per prop; grounding, UV, degenerate-triangle, attach-fit and manifest coverage checks |
| `tools/bake_ao.py` | Bakes per-asset AO maps | `<asset>_ao.png` (256²) | Wired through `Materials.apply_ao()`/`SurfaceMaterials`; cloth/pants opt out (see below) |
| `tools/npc_proportions.py` | Measures exported GLB rest pose (height, head, shoulders, hips, torso, limbs, feet) against the stylized guide | report / JSON in `docs/npc-visual-review.md#proportion-audit` | All eight variants must stay inside the guide after a body change |
| `tools/npc_baseline.py` | Assembles neutral-baseline sheets and before/after comparisons | `docs/blender_previews/sheet_npc_baseline*.jpg` | Human review against `docs/npc-visual-review.md` |
| `tools/npc_proportions.py` | Measures exported GLB rest pose (height, head, shoulders, hips, torso, limbs, feet) against the stylized guide | report / JSON in `docs/assets/3d-model-review.md#character-measurements` | All eight variants must stay inside the guide after a body change |
| `tools/npc_baseline.py` | Assembles neutral-baseline sheets and before/after comparisons | `docs/blender_previews/sheet_npc_baseline*.jpg` | Human review against `docs/assets/3d-model-review.md` |
| `src/test/capture_npc_baseline.gd` | Fixed-camera studio baseline, 8 variants × 6 views | local `tmp/` frames | Neutral silhouette/face/gear review |
| `src/test/capture_npc_review.gd` | Final-context gate: 8 variants × 2 venues × day/night × 3 distances = 96 frames, crowd hidden, review-only `character_override` for the guard | local `tmp/` frames | Pre-build acceptance gate for gear fit and venue lighting |
| `src/test/capture_realism.gd` | Venue realism stages plus a frozen portrait and surface close-ups | `docs/screens/realism/<run>/` | Optional vision judge; portrait is the only avatar-detail capture |
@@ -243,16 +243,16 @@ Runtime contracts that must survive any character change:
- Rebuild only the assets whose geometry changed (Blender GLB export is byte-nondeterministic),
then run `godot --headless --path . --import`; never commit a no-op full rebuild.
Evidence and detailed contracts live in [`blender-assets.md`](blender-assets.md),
[`npc-visual-review.md`](npc-visual-review.md) and
[`npc-visual-review.md#proportion-audit`](npc-visual-review.md#proportion-audit); command-level usage is in
[`asset-tooling.md`](asset-tooling.md).
Evidence and detailed contracts live in [`blender-assets.md`](../assets/blender-assets.md),
[`3d-model-review.md`](../assets/3d-model-review.md) and
[`3d-model-review.md#character-measurements`](../assets/3d-model-review.md#character-measurements); command-level usage is in
[`asset-tooling.md`](../assets/asset-tooling.md).
### Local map development tooling (planned)
The current venues are hand-authored procedural reconstructions in
`src/game/world_builder.gd`. The local map workstreams (**H–M**) in
[`TODO.md`](../TODO.md#3d-model-re-evaluation) are unversioned and planned: they will
[`TODO.md`](../../TODO.md#3d-model-and-local-map-re-evaluation) are unversioned and planned: they will
test whether licensed data and reference photography can replace or supplement the
stylized geometry without moving map data, AI composition or splat rendering into
the runtime.
@@ -353,7 +353,7 @@ Releases are produced from a tagged commit and published to the repository host'
- `tools/build_releases.sh` — exports the desktop binaries and Web zip into `build/`, named `gig-line-<platform>-<version>.<ext>`.
- `tools/publish_release.sh` — creates a release and uploads the artifacts via the Gitea API, using `GITEA_TOKEN` or the checkout extraheader fallback.
- Packaging — NSIS builds the Windows installer; `packaging/linux/build_appimage.sh` builds the AppImage.
- [`RELEASING.md`](RELEASING.md) — step-by-step guide and release checklist.
- [`RELEASING.md`](../process/RELEASING.md) — step-by-step guide and release checklist.
The release process is: bump the version, run the full test suite and `tools/check_screenshots.sh`, run `tools/build_releases.sh`, tag and push (CI publishes), then verify the README "Downloads" links and the release artifacts.
@@ -372,27 +372,27 @@ The release process is: bump the version, run the full test suite and `tools/che
- **Campaign and checkpoint state:** `Campaign` owns venue order/progression; settings, campaign, completed shift history and a versioned pause checkpoint are separate JSON documents. The checkpoint snapshots coordinator systems, scheduler RNG and NPC presentation/access state; it deliberately does not serialize the tutorial overlay or transient input state.
- **Difficulty:** easy/normal/hard only scale spawn pacing, NPC compliance tolerance and report-credibility strictness; access/escalation rules and emergency rarity are invariant.
- **Settings and accessibility:** volume/motion/caption settings persist through `settings.json`; Help is generated from the input-binding catalogue and the HUD log is the text caption surface. CI/release, local development and exported builds are unified on Godot 4.7.2.
- **Documentation ownership:** `PLAN.md` owns design intent; `docs/gameplay.md` owns playable mechanics; `docs/architecture.md` owns system boundaries, data flow, constraints and cross-cutting decisions; ADRs own decision history; `docs/development-status.md` owns the implemented/gap list; `TODO.md` owns the roadmap; `MEMORY.md` owns gotchas and open questions. Specialized docs link to these rather than becoming competing sources of truth.
- **Documentation ownership:** `PLAN.md` owns design intent; `docs/design/gameplay.md` owns playable mechanics; `docs/project/architecture.md` owns system boundaries, data flow, constraints and cross-cutting decisions; ADRs own decision history; `docs/project/development-status.md` owns the implemented/gap list; `TODO.md` owns the roadmap; `MEMORY.md` owns gotchas and open questions. Specialized docs link to these rather than becoming competing sources of truth.
## 9. Architecture Decisions
Architecture decisions are recorded as ADRs:
- [ADR-0001: Venue-driven simulation architecture](adr/0001-venue-driven-simulation-architecture.md)
- [ADR-0002: De-escalation-first escalation model](adr/0002-de-escalation-first-escalation-model.md)
- [ADR-0003: Explicit access-verification system](adr/0003-explicit-access-verification-system.md)
- [ADR-0004: Local single-player first](adr/0004-local-single-player-first.md)
- [ADR-0005: Event-based incident recording](adr/0005-event-based-incident-recording.md)
- [ADR-0006: Godot 4 with GDScript](adr/0006-godot-4-gdscript.md)
- [ADR-0007: Locomotion and input layers](adr/0007-locomotion-and-input-layers.md)
- [ADR-0008: Cone focus and focus circle](adr/0008-cone-focus-and-head-ring.md)
- [ADR-0009: Radial action menu](adr/0009-radial-action-menu.md)
- [ADR-0010: Procedural NPC presentation](adr/0010-procedural-npc-presentation.md)
- [ADR-0017: Quaternius NPC base](adr/0017-quaternius-npc-base.md)
- [ADR-0011: Aim-free selection and precision walk](adr/0011-aim-free-selection-and-precision-walk.md)
- [ADR-0012: Surface materials and generated props](adr/0012-surface-materials-and-generated-props.md)
- [ADR-0013: Blender-authored NPC characters and baked materials](adr/0013-blender-authored-npc-characters.md)
- [ADR-0014: Canonical runtime image root and image conventions](adr/0014-runtime-image-root.md)
- [ADR-0001: Venue-driven simulation architecture](../adr/0001-venue-driven-simulation-architecture.md)
- [ADR-0002: De-escalation-first escalation model](../adr/0002-de-escalation-first-escalation-model.md)
- [ADR-0003: Explicit access-verification system](../adr/0003-explicit-access-verification-system.md)
- [ADR-0004: Local single-player first](../adr/0004-local-single-player-first.md)
- [ADR-0005: Event-based incident recording](../adr/0005-event-based-incident-recording.md)
- [ADR-0006: Godot 4 with GDScript](../adr/0006-godot-4-gdscript.md)
- [ADR-0007: Locomotion and input layers](../adr/0007-locomotion-and-input-layers.md)
- [ADR-0008: Cone focus and focus circle](../adr/0008-cone-focus-and-head-ring.md)
- [ADR-0009: Radial action menu](../adr/0009-radial-action-menu.md)
- [ADR-0010: Procedural NPC presentation](../adr/0010-procedural-npc-presentation.md)
- [ADR-0017: Quaternius NPC base](../adr/0017-quaternius-npc-base.md)
- [ADR-0011: Aim-free selection and precision walk](../adr/0011-aim-free-selection-and-precision-walk.md)
- [ADR-0012: Surface materials and generated props](../adr/0012-surface-materials-and-generated-props.md)
- [ADR-0013: Blender-authored NPC characters and baked materials](../adr/0013-blender-authored-npc-characters.md)
- [ADR-0014: Canonical runtime image root and image conventions](../adr/0014-runtime-image-root.md)
## 10. Quality Requirements
@@ -435,32 +435,32 @@ architecture document.
| Document | Canonical role | Relationship to this architecture |
| --- | --- | --- |
| [`PLAN.md`](../PLAN.md) | Product/design intent, pillars, venues and success criteria | Design source; architecture realizes it |
| [`docs/gameplay.md`](gameplay.md) | Playable loop, escalation, tutorial, venue mechanics | Runtime/behavioral view |
| [`docs/venues.md`](venues.md) | Real-site evidence, mapping decisions and deliberate simplifications | Runtime venues' evidence companion to §5 |
| [`docs/architecture.md`](architecture.md) | System boundaries, data flow, constraints, deployment, cross-cutting decisions, quality risks | Single architecture source |
| [`docs/adr/`](adr/) | Immutable decision records with context and consequences | Decision history linked from §9 |
| [`docs/asset-tooling.md`](asset-tooling.md) | Build/audit/capture commands, optional Blender MCP and pipeline usage | Operational appendix to the pipeline section |
| [`docs/blender-assets.md`](blender-assets.md) | Blender library art direction, roles, layout and checks | Operational asset appendix; contract lives here in §5 |
| [`docs/npc-visual-review.md`](npc-visual-review.md) | NPC baseline views, acceptance criteria, visual gaps and proportion audit | Visual-QA appendix to the character tooling section |
| [`docs/3d-model-review.md`](3d-model-review.md) | Scorecard, measurements and ranked asset gaps | Working review companion to §5 |
| [`docs/npc-model-sourcing.md`](npc-model-sourcing.md) | Character-source evaluation and licence/prototype outcome | Supports the character tooling section and ADR-0015 |
| [`docs/getting-started.md`](getting-started.md) | Setup, commands, controls | Developer onboarding |
| [`docs/RELEASING.md`](RELEASING.md) | Release checklist and CI/publishing steps | Deployment appendix to §7 |
| [`docs/release-qa.md`](release-qa.md) | Manual smoke checklist and balance protocol | QA appendix to §10 |
| [`docs/accessibility.md`](accessibility.md) | Accessibility features, statement and known gaps | Player-facing quality statement |
| [`docs/known-limitations.md`](known-limitations.md) | Release blockers and accepted limitations | Player/release-facing risk statement |
| [`docs/ui-copy.md`](ui-copy.md) | Screen/button inventory, copy audit and screen-judge report | Presentation appendix |
| [`docs/development-status.md`](development-status.md) | Implemented features and current gaps | Status companion to the roadmap |
| [`TODO.md`](../TODO.md) | Priority-ordered active tasks, unversioned development tracks and versioned roadmap | Planning source; no architecture duplication |
| [`CHANGELOG.md`](../CHANGELOG.md) | User-facing release history | Release/version companion |
| [`PLAN.md`](../../PLAN.md) | Product/design intent, pillars, venues and success criteria | Design source; architecture realizes it |
| [`docs/design/gameplay.md`](../design/gameplay.md) | Playable loop, escalation, tutorial, venue mechanics | Runtime/behavioral view |
| [`docs/design/venues.md`](../design/venues.md) | Real-site evidence, mapping decisions and deliberate simplifications | Runtime venues' evidence companion to §5 |
| [`docs/project/architecture.md`](architecture.md) | System boundaries, data flow, constraints, deployment, cross-cutting decisions, quality risks | Single architecture source |
| [`docs/adr/`](../adr) | Immutable decision records with context and consequences | Decision history linked from §9 |
| [`docs/assets/asset-tooling.md`](../assets/asset-tooling.md) | Build/audit/capture commands, optional Blender MCP and pipeline usage | Operational appendix to the pipeline section |
| [`docs/assets/blender-assets.md`](../assets/blender-assets.md) | Blender library art direction, roles, layout and checks | Operational asset appendix; contract lives here in §5 |
| [`docs/assets/3d-model-review.md`](../assets/3d-model-review.md) | Character and asset measurements, scorecard and ranked gaps | Visual-QA appendix to the character tooling section |
| [`docs/assets/3d-model-review.md`](../assets/3d-model-review.md) | Scorecard, measurements and ranked asset gaps | Working review companion to §5 |
| [`docs/assets/npc-model-sourcing.md`](../assets/npc-model-sourcing.md) | Character-source evaluation and licence/prototype outcome | Supports the character tooling section and ADR-0015 |
| [`docs/process/getting-started.md`](../process/getting-started.md) | Setup, commands, controls | Developer onboarding |
| [`docs/process/RELEASING.md`](../process/RELEASING.md) | Release checklist and CI/publishing steps | Deployment appendix to §7 |
| [`docs/process/release-qa.md`](../process/release-qa.md) | Manual smoke checklist and balance protocol | QA appendix to §10 |
| [`docs/design/accessibility.md`](../design/accessibility.md) | Accessibility features, statement and known gaps | Player-facing quality statement |
| [`docs/design/known-limitations.md`](../design/known-limitations.md) | Release blockers and accepted limitations | Player/release-facing risk statement |
| [`docs/design/ui-copy.md`](../design/ui-copy.md) | Screen/button inventory, copy audit and screen-judge report | Presentation appendix |
| [`docs/project/development-status.md`](development-status.md) | Implemented features and current gaps | Status companion to the roadmap |
| [`TODO.md`](../../TODO.md) | Priority-ordered active tasks, unversioned development tracks and versioned roadmap | Planning source; no architecture duplication |
| [`CHANGELOG.md`](../../CHANGELOG.md) | User-facing release history | Release/version companion |
Consolidation decisions:
- **Architecture owns the "how"** (components, contracts, data flow, constraints, quality gates); **PLAN/gameplay own the "what"**; **ADRs own the "why"**. Links replace duplicated prose.
- **Asset and release documents remain separate** because they are command-heavy operational procedures; their architecture-relevant contracts and failure modes are summarized in §5 and §7.
- **Completed plans are removed, not kept as competing roadmaps.** Historical graphics work is summarized by ADR-0013, the asset pipeline section and the v0.6.0 changelog; new work belongs in TODO.
- **Status and roadmap are separate from architecture.** `docs/development-status.md` records what exists; `TODO.md` records what remains, ordered as unversioned development tracks, versioned milestones and deferred work.
- **Status and roadmap are separate from architecture.** `docs/project/development-status.md` records what exists; `TODO.md` records what remains, ordered as unversioned development tracks, versioned milestones and deferred work.
- **Documentation drift is a tracked risk:** release/version, test counts, renderer status, and stale plans must be corrected in the same commit as the change that invalidates them.
## 13. Glossary
@@ -1,9 +1,9 @@
# Development Status
Baseline: **v0.9.8** (2026-11-04). This page lists what the build currently
Baseline: **v0.9.9** (2026-11-06). This page lists what the build currently
supports and what remains; it is not a release history. Completed work lives in
[`DONE.md`](../DONE.md), user-facing changes in [`CHANGELOG.md`](../CHANGELOG.md),
and the active order/gaps in [`TODO.md`](../TODO.md).
[`DONE.md`](../../DONE.md), user-facing changes in [`CHANGELOG.md`](../../CHANGELOG.md),
and the active order/gaps in [`TODO.md`](../../TODO.md).
## Implemented
@@ -16,7 +16,7 @@ and the active order/gaps in [`TODO.md`](../TODO.md).
| Access and escalation | Six escalation levels, venue access policies, artifact validity/recognition, door lock, crowd reactions, investigation/false-report handling and shift review. |
| UI/input | Keyboard/mouse and gamepad bindings, focus rings, default modal focus, single top-modal close path, shared button states, font scaling, long-string handling, searchable Help and 21 committed UI/game captures. |
| Audio/accessibility | Procedural crowd bed and radio cues, master/SFX/ambience volumes, reduced motion, captions, colour-independent escalation cue, hold-to-confirm emergency and guarded destructive actions. |
| Persistence | Separate settings, campaign, shift-history and versioned checkpoint files; default-filling migration, atomic writes and corrupt/partial-file fallback. Save locations and rollback are documented in [`getting-started.md`](getting-started.md#save-data-and-migration). |
| Persistence | Separate settings, campaign, shift-history and versioned checkpoint files; default-filling migration, atomic writes and corrupt/partial-file fallback. Save locations and rollback are documented in [`getting-started.md`](../process/getting-started.md#save-data). |
| Assets | Blender character/gear/prop library with AO and manifests; 256² NPC maps with 4× fabric weave; image/texture pipelines, reference boards and three-up boards; environment/realism capture tools. |
| Build/release | Godot 4.7.2 Compatibility/Web default plus optional Forward+ Desktop HQ. Gitea checks/build/publish, seven release assets, checksums, preflight/rollback and clean-worktree release discipline. |
@@ -28,8 +28,9 @@ and the active order/gaps in [`TODO.md`](../TODO.md).
`npc_proportions.py` pass for the committed library.
- 24-NPC smoke: 168 meshes, 152,464 triangles, 6.94 ms (50 ms budget).
- Screenshot gate: 21 good / 0 bad; screen-design judge 21/21 match.
- Release baseline: v0.9.8 is published; the 0.10.0 release candidate remains
gated on external playtest, legal/storefront, signing and platform-matrix work.
- Release baseline: **v0.9.9** is published (Quaternius roster, accepted by the owner on
2026-11-06); the 0.10.0 release candidate remains gated on external playtest, legal/storefront,
signing and platform-matrix work.
## Known gaps
@@ -38,6 +39,9 @@ and the active order/gaps in [`TODO.md`](../TODO.md).
sources (casual tee, hoodie, work clothes), 4,458–6,424 triangles each, 62-joint rig at source
proportions, arm-down rest, five tint slots, unwrapped UVs and baked 256² AO. The procedural
library and the MakeHuman head remain the tested fallback.
- The roster passed its owner visual review on 2026-11-06: faces, head gear, hand-held and back
gear were all accepted after the follow-up fixes. The review page and its sheets were retired;
the measurements live in `docs/assets/3d-model-review.md` and `docs/assets/blender-assets.md`.
- Roster silhouette variety is narrower than the procedural library (three meshes for twelve
roles, differentiated by tint and gear) until the modular part library is added.
- Head gear is authored for the shipped Quaternius head; the procedural fallback therefore wears
@@ -47,6 +51,6 @@ and the active order/gaps in [`TODO.md`](../TODO.md).
- Live 3D replay, recorded VO/music, more venues and seasonal content are future
work.
See [`TODO.md`](../TODO.md) for the ordered task list and
[`known-limitations.md`](known-limitations.md) for the current release blockers.
See [`TODO.md`](../../TODO.md) for the ordered task list and
[`known-limitations.md`](../design/known-limitations.md) for the current release blockers.
Architecture and ownership are in [`architecture.md`](architecture.md).
+2 -2
View File
@@ -15,13 +15,13 @@ The map-optimization references for the El Capitan Entertainment Centre block
(6840 Hollywood Blvd) are in
[`hollywood_boulevard/README.md`](hollywood_boulevard/README.md). The real-site
facts and game mapping are documented in
[`../../venues.md`](../../venues.md#hollywood-boulevard).
[`../../venues.md`](../../design/venues.md#hollywood-boulevard).
## The Joke Shop — Sunset Strip
The current Joke Shop map is based on The Comedy Store at 8433 Sunset Blvd.
The real-site mapping and simplifications are in
[`../../venues.md`](../../venues.md#the-joke-shop); the frames are in
[`../../venues.md`](../../design/venues.md#the-joke-shop); the frames are in
[`joke_shop/README.md`](joke_shop/README.md).
![Joke Shop entrance in daylight](joke_shop/joke_shop_entrance_day.png)
@@ -4,7 +4,7 @@ AI-generated art-direction frames for the real El Capitan Entertainment Centre
block at 6840 Hollywood Boulevard. They are generated with
`tools/scene_concepts.py generate --group scene --only ...` and are not shipped
game textures. The geometry mapping and source links are in
[`../../../venues.md`](../../../venues.md#hollywood-boulevard).
[`../../../venues.md`](../../../design/venues.md#hollywood-boulevard).
## Entrance — day
Loaded 100 of 143 files, more files were not shown because too many files have changed in this diff. Show more