Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a196a35342 | ||
|
|
efa062833f | ||
|
|
6381dbc5cb | ||
|
|
7546092c01 | ||
|
|
16dc1dfea4 | ||
|
|
2ba40f3578 | ||
|
|
045ed2a58f | ||
|
|
d3a87acf2d | ||
|
|
b18236f9b4 | ||
|
|
3b9e3b61d8 | ||
|
|
f6bb2b1de3 | ||
|
|
7a46963e3f | ||
|
|
a0dbf75806 | ||
|
|
c70a523f0f | ||
|
|
fcbeee0db2 | ||
|
|
d5e180e50c | ||
|
|
a36068aae7 | ||
|
|
6b58350464 | ||
|
|
219588bf8a | ||
|
|
cba00facf5 | ||
|
|
9fd48243ad | ||
|
|
30d145079a | ||
|
|
98f618c501 | ||
|
|
a290fe83c8 | ||
|
|
529d15ee7a | ||
|
|
3ab7577634 | ||
|
|
c8875a3dfa |
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
|
||||
|
||||
@@ -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 |
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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.
|
||||
@@ -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 -->
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.** 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
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
]
|
||||
},
|
||||
|
||||
|
Before Width: | Height: | Size: 70 KiB After Width: | Height: | Size: 73 KiB |
|
Before Width: | Height: | Size: 70 KiB After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 70 KiB After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 67 KiB After Width: | Height: | Size: 72 KiB |
|
Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 67 KiB After Width: | Height: | Size: 72 KiB |
|
Before Width: | Height: | Size: 67 KiB After Width: | Height: | Size: 72 KiB |
|
Before Width: | Height: | Size: 70 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 72 KiB |
|
Before Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 9.3 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 37 KiB |
|
Before Width: | Height: | Size: 35 KiB |
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 35 KiB |
|
Before Width: | Height: | Size: 51 KiB After Width: | Height: | Size: 52 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 47 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 52 KiB |
@@ -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;
|
||||
|
||||
@@ -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)_ | | | |
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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).
|
||||
@@ -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.
|
||||
@@ -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 |
|
||||
| --- | --- |
|
||||
|  |  |
|
||||
|  |  |
|
||||
|
||||
```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
|
||||
|
||||
| | |
|
||||
| --- | --- |
|
||||
|  |  |
|
||||
|  |  |
|
||||
|  |  |
|
||||
|  |  |
|
||||
|  |  |
|
||||
|  |  |
|
||||
|
||||
- **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.
|
||||
|
||||

|
||||

|
||||
|
||||
## 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)
|
||||
@@ -9,7 +9,7 @@ capture harnesses.
|
||||
| --- | --- |
|
||||
| [](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) <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) <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) <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) <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) <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) <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) <br> `sheet_npc_baseline_compare-texuv.jpg` | 4x fabric weave with the baked per-character AO removed. |
|
||||
| [](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) <br> `sheet_npc_crowd_prototypes.jpg` | Four approved crowd-variety looks queued for the 12-character roster. |
|
||||
| [](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) <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) <br> `sheet_npc_hands_compare.jpg` | Hand pass: wider palms, segmented fingers and a separate thumb. |
|
||||
| [](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) <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) <br> `sheet_props.jpg` | Twenty street and venue props with baked maps, ground contact and collider footprints. |
|
||||
| [](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).
|
||||
|
Before Width: | Height: | Size: 63 KiB After Width: | Height: | Size: 63 KiB |
|
Before Width: | Height: | Size: 94 KiB After Width: | Height: | Size: 80 KiB |
|
Before Width: | Height: | Size: 126 KiB After Width: | Height: | Size: 132 KiB |
@@ -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,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
|
||||
@@ -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.
|
||||
@@ -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
|
||||
@@ -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.
|
||||
@@ -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
|
||||
|
||||
@@ -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).
|
||||
@@ -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).
|
||||
|
||||

|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||