Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
236fbf537f | ||
|
|
588722fe7a | ||
|
|
7f2f06bf42 | ||
|
|
6db3cc0873 | ||
|
|
8938dd918c | ||
|
|
742bfd3898 | ||
|
|
87069a30e8 | ||
|
|
3f5c5ce442 | ||
|
|
28fcd96b59 | ||
|
|
e984129597 | ||
|
|
75dea2e7c2 | ||
|
|
09d07452af | ||
|
|
f5ee2b7408 | ||
|
|
5980d329e8 | ||
|
|
6052ea391b | ||
|
|
4e8665e25b | ||
|
|
b945eb6e8f | ||
|
|
03c13c716a | ||
|
|
0a9c78cb30 | ||
|
|
abe5c3f933 | ||
|
|
140ab42536 | ||
|
|
8bdfd0176e | ||
|
|
4e23cc3ad5 | ||
|
|
8d32a8cac0 | ||
|
|
2445ddab34 | ||
|
|
8cacd510bf | ||
|
|
bf383aa0fa | ||
|
|
4bbc576b7f | ||
|
|
542b1264da | ||
|
|
56f4833c8e | ||
|
|
1b31dfdbe4 | ||
|
|
5158efc467 | ||
|
|
ac0cf35cfb | ||
|
|
6655edb5c6 | ||
|
|
60f389c16b | ||
|
|
3084145031 | ||
|
|
34bca89885 | ||
|
|
b53e8a67f9 | ||
|
|
cdfd57fb65 | ||
|
|
5bab6754c0 | ||
|
|
7dd8251a0c | ||
|
|
8e113a4110 | ||
|
|
32c9c45605 | ||
|
|
e4065c2068 | ||
|
|
e7d733bc93 | ||
|
|
93da916f90 | ||
|
|
e3ec4a356a | ||
|
|
55339f23c1 | ||
|
|
a51dae2c33 | ||
|
|
6824dd76a1 | ||
|
|
fde4aa4d0a | ||
|
|
ebb36cf0cb | ||
|
|
724e8b183f | ||
|
|
e4e1566e55 | ||
|
|
0aacee6518 | ||
|
|
215b843b67 | ||
|
|
53d9dc3f78 | ||
|
|
98f2f95f07 | ||
|
|
a677a95d13 | ||
|
|
1afd97c72d | ||
|
|
6ca8bcf034 | ||
|
|
13eb4e0c87 | ||
|
|
8fac1b47cf | ||
|
|
b79e30e9df | ||
|
|
1e761e5a76 | ||
|
|
3eb2ae5e3c | ||
|
|
888897cac9 | ||
|
|
988d431da8 | ||
|
|
87e1c9e7a5 | ||
|
|
480a1ba05f | ||
|
|
43c17ce3c0 | ||
|
|
03f4d4bc49 | ||
|
|
15f9117517 | ||
|
|
78267918bf | ||
|
|
ea3860a60c | ||
|
|
b721f189c5 | ||
|
|
634b1f75a3 | ||
|
|
36583921cf | ||
|
|
3866b0ae01 | ||
|
|
8c2761427f | ||
|
|
2b07913481 | ||
|
|
768dd94bfc | ||
|
|
f516d3e796 | ||
|
|
f95a685934 | ||
|
|
05cb6a43cb | ||
|
|
343b3348c2 | ||
|
|
ad91e71eeb | ||
|
|
6e04c59589 | ||
|
|
e21ff30783 | ||
|
|
5b306b1c52 | ||
|
|
f09a5e7937 | ||
|
|
383f601bc9 | ||
|
|
c46db76d85 | ||
|
|
1a5f2863b0 | ||
|
|
a6fd77068a | ||
|
|
4ed73fcc7b | ||
|
|
c0ddce79e8 | ||
|
|
0c7c9a2b23 | ||
|
|
b94b87d096 | ||
|
|
5dec59355a | ||
|
|
fe3ba3054e | ||
|
|
88a0793bba | ||
|
|
1d4f718376 | ||
|
|
7a5b902797 | ||
|
|
2d67e14e52 | ||
|
|
2443343f2b | ||
|
|
3e41cda591 | ||
|
|
84bc4137cb | ||
|
|
5dc3ef0f4c | ||
|
|
6f3facff43 | ||
|
|
51f537720f | ||
|
|
08e9044593 | ||
|
|
ad14410337 | ||
|
|
876fb59882 | ||
|
|
979c6ad789 | ||
|
|
1921bfae91 | ||
|
|
78485259b7 | ||
|
|
fef3af44c0 | ||
|
|
bfe3c5a701 | ||
|
|
46f1e41874 |
No files matched your search
@@ -0,0 +1,210 @@
|
||||
---
|
||||
name: gig-line-blender-asset-contract
|
||||
description: Use when adding, rebuilding, auditing or fixing any Gig Line Blender-authored character, NPC base, gear, prop or venue geometry. Covers the 13-bone npc_base contract, five tint slots, triangle/vertex budgets, gear attach space, 256² texture/AO rules, headless flatpak Blender commands, and the inspect/audit/fit/proportion/capture gates. Do not use for pure GDScript/UI work or release publishing.
|
||||
compatibility: Gig Line repository checkout. Godot 4.7.2 on PATH; Blender 5.2 LTS via the org.blender.Blender flatpak for build/bake/render. Audit, fit, inspect and proportion checks are stdlib-only.
|
||||
metadata:
|
||||
project: Gig Line
|
||||
domain: 3d-assets
|
||||
version: "1.0.0"
|
||||
triggers: Blender, NPC, character, gear, prop, npc_base, GLB, AO, texel, asset rebuild, fit, audit
|
||||
---
|
||||
|
||||
# Gig Line Blender Asset Contract
|
||||
|
||||
Use this skill for any change that touches:
|
||||
|
||||
- `assets/models/blender/**`
|
||||
- `assets/models/generated/npc_base.glb`
|
||||
- `assets/textures/npc/**`
|
||||
- `tools/blender_assets.py`, `tools/npc_pipeline.py`, `tools/bake_ao.py`,
|
||||
`tools/npc_proportions.py` or `tools/npc_baseline.py`
|
||||
- Blender-authored venue/prop geometry
|
||||
|
||||
The project contract and measured gates override any generic Blender advice.
|
||||
There is **no Blender MCP** in this project. Blender runs headless through the
|
||||
flatpak CLI; the `blender-skills` pack is optional, local guidance only, and
|
||||
gitignored.
|
||||
|
||||
## Read first
|
||||
|
||||
From the repository root, read the relevant sources rather than relying on this
|
||||
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,
|
||||
scorecards and known blockers.
|
||||
6. `docs/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
|
||||
and resolve the source of truth before editing assets.
|
||||
|
||||
## Non-negotiable contract
|
||||
|
||||
| Area | Rule |
|
||||
| --- | --- |
|
||||
| Mesh root | `npc_base` mesh node, skinned under `Rig`; preserve the limb node names. |
|
||||
| Bones | 13 contract bones: `Head`, `HipL/R`, `KneeL/R`, `ShoulderL/R`, `ElbowL/R`, `HandL/R`, `Spine`, `Neck` (parent/helper bones must not change the contract). |
|
||||
| Tint slots | `skin`, `cloth`, `pants`, `accessory`, `hair`. |
|
||||
| Orientation | Front is Blender −Y / Godot +Z; feet grounded near y = 0; metres. |
|
||||
| Library budget | **8,000 triangles / 8,000 glTF vertices** per character (`CHAR_MAX_TRIS`/`CHAR_MAX_VERTS`). |
|
||||
| Frozen fallback | `npc_base` keeps **6,000 tris / 4,000 verts**. Do not silently raise or lower it. |
|
||||
| Gear budget | **1,500 triangles** per gear piece; authored in attach-point space. |
|
||||
| Prop budget | **4,000 triangles** per prop. |
|
||||
| Gear attach | Use the catalogued attach points; verify with `fit`. Runtime `GEAR_OFFSETS` (lanyard forward, firefighter helmet up) and `HAND_ITEM_FORWARD` are intentional, not asset-contract changes. |
|
||||
| Textures | 256² albedo/normal/ORM maps. Cloth and pants use `NPC_FABRIC_UV_SCALE = (4,4,1)` and **skip** baked per-character AO; skin/hair/gear keep baked AO. |
|
||||
| CI | Offline and skill-free. Committed GLBs/AO/maps must make CI pass without Blender or MCP. |
|
||||
| Licensing | No new asset source without ADR-0015: CC0, or CC-BY with attribution in `CREDITS.md`; record provenance. |
|
||||
|
||||
Do not change the renderer, engine baseline, runtime dependency graph or the
|
||||
`npc_base` contract as part of an asset pass.
|
||||
|
||||
## Workflow
|
||||
|
||||
### 1. Preflight and claim
|
||||
|
||||
```bash
|
||||
git status --short
|
||||
git log --oneline -5
|
||||
godot --version
|
||||
flatpak run org.blender.Blender --version | head -3
|
||||
```
|
||||
|
||||
Inspect the current asset and the relevant docs. Claim the TODO item with `[-]`
|
||||
before starting. Work on one asset family per commit.
|
||||
|
||||
### 2. Establish a baseline
|
||||
|
||||
Run the checks that do not need Blender first:
|
||||
|
||||
```bash
|
||||
python3 tools/blender_assets.py audit
|
||||
python3 tools/blender_assets.py fit
|
||||
python3 tools/blender_assets.py texels
|
||||
python3 tools/npc_proportions.py report
|
||||
python3 tools/npc_pipeline.py audit
|
||||
```
|
||||
|
||||
For a specific incoming or existing GLB:
|
||||
|
||||
```bash
|
||||
flatpak run org.blender.Blender --background \
|
||||
--python "$PWD/tools/blender_assets.py" -- \
|
||||
inspect --file "$PWD/path/to/asset.glb" --category npc_gear --json
|
||||
```
|
||||
|
||||
Record the before measurements (tris/verts, head/shoulder/hip/leg/arm/foot,
|
||||
fabric texel density, gear clearance). Do not “improve” an asset without a
|
||||
measurable target.
|
||||
|
||||
### 3. Optional Blender-skill routing
|
||||
|
||||
If the local `blender-skills` pack is installed, load `blender-director`, then
|
||||
only the specialists the task needs:
|
||||
|
||||
- character mesh/face/hands: `character-artist`, `retopology`
|
||||
- rig/weights/pose: `rigging`
|
||||
- UVs/texel density: `uv-workflow`
|
||||
- maps/materials: `texture-workflow`, `materials`, `lookdev`
|
||||
- gear/props: `prop-artist`, `hard-surface`
|
||||
- budget/LOD/collision: `asset-optimization`, `lod-pipeline`, `collision-proxy`
|
||||
- final review: `qa-review`
|
||||
|
||||
Translate any MCP instruction into a change to `tools/*.py` or a headless CLI
|
||||
run. Never add an MCP dependency to the build, CI or runtime.
|
||||
|
||||
### 4. Build or bake
|
||||
|
||||
Characters, gear and library props:
|
||||
|
||||
```bash
|
||||
flatpak run org.blender.Blender --background \
|
||||
--python "$PWD/tools/blender_assets.py" -- build --only <name>
|
||||
|
||||
flatpak run org.blender.Blender --background \
|
||||
--python "$PWD/tools/bake_ao.py" -- --only <name>
|
||||
```
|
||||
|
||||
NPC base and its material maps:
|
||||
|
||||
```bash
|
||||
python3 tools/npc_pipeline.py prepare # only when fabric tiles change
|
||||
flatpak run org.blender.Blender --background \
|
||||
--python "$PWD/tools/npc_pipeline.py" -- build
|
||||
python3 tools/npc_pipeline.py audit
|
||||
```
|
||||
|
||||
Do not overwrite a review image or a promoted texture pick. Use a new `-vN`
|
||||
path and document the promotion.
|
||||
|
||||
### 5. Import and capture
|
||||
|
||||
```bash
|
||||
godot --headless --path . --import
|
||||
godot --headless --path . --script res://src/test/test_runner.gd
|
||||
|
||||
# neutral baseline: 8 variants x 6 views, raw frames stay in tmp/
|
||||
godot --path . --script res://src/test/capture_npc_baseline.gd \
|
||||
-- --out=res://tmp/npc-baseline
|
||||
|
||||
# final-context: 96 frames across both venues and day/night
|
||||
godot --path . --script res://src/test/capture_npc_review.gd \
|
||||
-- --out=res://tmp/npc-review
|
||||
```
|
||||
|
||||
Compare before/after with `tools/npc_baseline.py compare`; do not replace the
|
||||
committed baseline sheet until a fix actually lands. See
|
||||
`references/verification.md` for the full gate matrix.
|
||||
|
||||
### 6. Verify and hand off
|
||||
|
||||
At minimum:
|
||||
|
||||
- `blender_assets.py audit` and `fit` exit 0.
|
||||
- `npc_proportions.py` passes the stylized guide.
|
||||
- `npc_pipeline.py audit` passes if the base/textures changed.
|
||||
- texel density is inside the authored/fabric bands.
|
||||
- No character exceeds 8,000/8,000; gear/prop caps hold.
|
||||
- 24-NPC budget and Web/Compatibility path remain green.
|
||||
- Contract tests, headless suite, capture gates and docs check pass.
|
||||
- The diff contains only the intended assets, tools, tests and docs.
|
||||
|
||||
State in the handoff: files changed, measurements before/after, skills used,
|
||||
gates run, and any accepted limit.
|
||||
|
||||
## Failure playbook
|
||||
|
||||
- **`Class "..." hides a global script class`** — a stray `.gd` backup is in the
|
||||
project. Delete `tmp/*.gd` backups, `rm -rf .godot`, re-import; never keep
|
||||
`class_name` copies in `tmp/`.
|
||||
- **Blender cannot see the path** — the flatpak cwd is `/app/blender`; use
|
||||
absolute paths (`"$PWD/..."`).
|
||||
- **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
|
||||
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
|
||||
the manifest by hand.
|
||||
- **Uncertain about a visual change** — produce a labelled before/after sheet and
|
||||
ask for review; do not hide a regression behind a budget claim.
|
||||
|
||||
## Bundled references
|
||||
|
||||
- [`references/asset-contract.md`](references/asset-contract.md) — full contract,
|
||||
inventory, file locations and provenance rules.
|
||||
- [`references/verification.md`](references/verification.md) — command matrix,
|
||||
capture gates, expected results and acceptance criteria.
|
||||
|
||||
## Do not
|
||||
|
||||
- Add an MCP server, Blender dependency or API call to the build/runtime.
|
||||
- Change the bone/tint/contract to make a generic asset fit.
|
||||
- Rewrite committed baselines or overwrite existing images.
|
||||
- Commit `.blend` sources, raw captures or generated AI inputs.
|
||||
- Treat an asset audit as a substitute for visual review at portrait and crowd
|
||||
distance.
|
||||
@@ -0,0 +1,139 @@
|
||||
# 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
|
||||
`src/test/tests/` and the constants in `tools/blender_assets.py` /
|
||||
`tools/npc_pipeline.py`.
|
||||
|
||||
## Library inventory
|
||||
|
||||
- **Character variants (8):** `npc_casual`, `npc_jacket`, `npc_coat`,
|
||||
`npc_vest`, `npc_dress`, `npc_hoodie`, `npc_firefighter`, `npc_guard`.
|
||||
- **Frozen fallback:** `npc_base` / `assets/models/generated/npc_base.glb`.
|
||||
- **Gear:** 18 attach-space pieces covering head, back, chest and hand items.
|
||||
- **Library props:** 20 Blender-authored props plus 6 generated props.
|
||||
- **Venues:** procedural venues in `src/game/world_builder.gd`; Blender venue
|
||||
geometry follows the same budgets and collision/provenance rules.
|
||||
|
||||
## Skeleton and geometry
|
||||
|
||||
The contract skeleton has 13 bones:
|
||||
|
||||
```text
|
||||
Head, Spine, Neck,
|
||||
HipL, HipR,
|
||||
KneeL, KneeR,
|
||||
ShoulderL, ShoulderR,
|
||||
ElbowL, ElbowR,
|
||||
HandL, HandR
|
||||
```
|
||||
|
||||
Requirements:
|
||||
|
||||
- `npc_base` mesh node exists and is skinned under `Rig`.
|
||||
- Limb node names stay stable for `NpcAvatar` and tests.
|
||||
- Front is Blender −Y / Godot +Z.
|
||||
- Feet are grounded at approximately y = 0; no floating origin.
|
||||
- Units are metres; character height is approximately 1.8 m.
|
||||
- No zero-area/duplicate degenerate faces in the exported mesh.
|
||||
- Every character has UVs in [0,1] unless a planned UDIM/atlas change is
|
||||
explicitly accepted.
|
||||
|
||||
## Material slots
|
||||
|
||||
Exactly these five tint slots:
|
||||
|
||||
```text
|
||||
skin, cloth, pants, accessory, hair
|
||||
```
|
||||
|
||||
- Neutral albedo is authored in Blender; runtime tinting is authoritative.
|
||||
- Slot names are contract values; do not rename or add a sixth slot casually.
|
||||
- The procedural fallback (`NpcAvatar._build_body`) must keep working when the
|
||||
GLB is missing.
|
||||
|
||||
## Budgets
|
||||
|
||||
| Asset | Limit |
|
||||
| --- | --- |
|
||||
| Library character | 8,000 triangles / 8,000 glTF vertices |
|
||||
| `npc_base` fallback | 6,000 triangles / 4,000 vertices |
|
||||
| Gear piece | 1,500 triangles |
|
||||
| Prop | 4,000 triangles |
|
||||
| Library prop/venue total | must stay inside the venue tests and library budget |
|
||||
|
||||
`CHAR_MAX_TRIS`, `CHAR_MAX_VERTS`, `GEAR_MAX_TRIS`, `PROP_MAX_TRIS` and related
|
||||
constants live in `tools/blender_assets.py`. The budget is per character, not an
|
||||
average. Measure after every mesh change. Do not lower the cap to make a diff
|
||||
pass.
|
||||
|
||||
## Gear and hand items
|
||||
|
||||
- Gear is authored in the attach-point space documented by `GEAR` /
|
||||
`GEAR_ATTACH` / `ATTACH_BLENDER`.
|
||||
- `blender_assets.py fit` measures gear boxes against the character's head band,
|
||||
clothing radius and back clearance.
|
||||
- Runtime offsets are intentional:
|
||||
- `NpcAvatar.GEAR_OFFSETS = {"lanyard": Vector3(0,0,0.04),
|
||||
"firefighter_helmet": Vector3(0,0.03,0)}`
|
||||
- `NpcAvatar.HAND_ITEM_FORWARD = Vector3(0,0,0.04)`
|
||||
- An offset is **not** an authored-asset change; do not bake it into the GLB
|
||||
without a separate contract decision.
|
||||
- Open-palm grip (no finger-curl rig) is the accepted stylized limit.
|
||||
|
||||
## Textures and AO
|
||||
|
||||
- NPC maps are 256² albedo + normal + packed ORM.
|
||||
- `TEX_SIZE = 256` in `tools/npc_pipeline.py`.
|
||||
- Fabric UV scale is `Materials.NPC_FABRIC_UV_SCALE = Vector3(4,4,1)`.
|
||||
- Cloth/pants skip the per-character baked AO; skin/hair/gear keep it. This
|
||||
avoids the large blotchy magnification that appeared at 256².
|
||||
- Gear/props may have their own AO maps; `tools/bake_ao.py` writes
|
||||
`<name>_ao.png` next to the GLB and Godot wires it into the AO channel.
|
||||
- Never overwrite an existing committed image; use a new `-vN` candidate and
|
||||
promote only after review.
|
||||
- Run `python3 tools/asset_pipeline.py audit <path>` and the relevant
|
||||
`npc_pipeline.py audit` before committing map changes.
|
||||
|
||||
## File map
|
||||
|
||||
| Path | Role |
|
||||
| --- | --- |
|
||||
| `tools/blender_assets.py` | Catalogue, builders, audit/fit/inspect/texels/sheet. |
|
||||
| `tools/npc_pipeline.py` | `npc_base` builder, texture preparation and audit. |
|
||||
| `tools/bake_ao.py` | Blender AO bake into `<name>_ao.png`. |
|
||||
| `tools/npc_proportions.py` | Exported-GLB proportion audit (no Blender). |
|
||||
| `tools/npc_baseline.py` | Contact sheets/comparisons (no Blender). |
|
||||
| `assets/models/blender/manifest.json` | Generated asset manifest. |
|
||||
| `assets/models/blender/**/*.glb` | Committed library assets. |
|
||||
| `assets/models/generated/npc_base.glb` | Frozen NPC fallback. |
|
||||
| `assets/textures/npc/*_{albedo,normal,orm}.png` | Committed NPC maps. |
|
||||
| `src/test/capture_npc_baseline.gd` | 48-frame neutral baseline. |
|
||||
| `src/test/capture_npc_review.gd` | 96-frame final-context review. |
|
||||
|
||||
## Provenance and source rules
|
||||
|
||||
- Procedural Blender assets are project-owned.
|
||||
- External/CC assets need ADR-0015 clearance: CC0 preferred, CC-BY only with
|
||||
attribution in `CREDITS.md`; no service assets with redistribution limits.
|
||||
- Editable `.blend` files under `assets/models/blender_src/` are gitignored;
|
||||
only exported `.glb`, AO maps, manifests and committed preview sheets ship.
|
||||
- AI-generated source images are development inputs, not shipped assets. Keep
|
||||
raw generations under gitignored paths until picked, checked and credited.
|
||||
- Do not copy a downloaded/Street View/AI reference into a committed asset
|
||||
without the licence and provenance review.
|
||||
|
||||
## Verification invariants
|
||||
|
||||
The asset pass is not complete unless:
|
||||
|
||||
1. `python3 tools/blender_assets.py audit` exits 0.
|
||||
2. `python3 tools/blender_assets.py fit` exits 0 and the report is reviewed.
|
||||
3. `python3 tools/npc_proportions.py report` passes the stylized guide.
|
||||
4. `python3 tools/npc_pipeline.py audit` passes when the base/textures changed.
|
||||
5. The 48-frame baseline and 96-frame final-context review are captured, with no
|
||||
blank frames.
|
||||
6. The 24-NPC budget smoke is inside its frame budget.
|
||||
7. The full Godot suite and Python tooling tests pass.
|
||||
8. No runtime contract, renderer or dependency changed except the rebuilt
|
||||
assets and their generated metadata.
|
||||
@@ -0,0 +1,123 @@
|
||||
# Verification Matrix
|
||||
|
||||
Run from the repository root. Stop and fix the first failure before continuing.
|
||||
|
||||
## Environment
|
||||
|
||||
```bash
|
||||
godot --version
|
||||
flatpak run org.blender.Blender --version | head -3
|
||||
git status --short
|
||||
```
|
||||
|
||||
Expected: Godot 4.7.2; Blender 5.2 LTS flatpak; clean or intentionally scoped
|
||||
working tree. Blender's flatpak cwd is `/app/blender`; all paths passed to
|
||||
Blender must be absolute.
|
||||
|
||||
## Asset checks
|
||||
|
||||
| Check | Command | Expected |
|
||||
| --- | --- | --- |
|
||||
| Contract audit | `python3 tools/blender_assets.py audit` | exit 0, no `BAD` assets |
|
||||
| Gear fit | `python3 tools/blender_assets.py fit` | exit 0; review head band/clothing/back clearances |
|
||||
| Texture/texel density | `python3 tools/blender_assets.py texels` | authored 40–400 px/m; fabric ≥250 px/m |
|
||||
| NPC base | `python3 tools/npc_pipeline.py audit` | exit 0, contract bones/slots/maps |
|
||||
| Proportions | `python3 tools/npc_proportions.py report` | all eight inside the stylized guide |
|
||||
| Single incoming GLB | `flatpak run org.blender.Blender --background --python "$PWD/tools/blender_assets.py" -- inspect --file "$PWD/path.glb" --category <cat> --json` | contract result and measurements |
|
||||
| Prop audit | `python3 tools/model_pipeline.py audit` | exit 0 when generated props changed |
|
||||
| Texture audit | `python3 tools/asset_pipeline.py audit assets/textures/ai/game_ready` | exit 0 when textures changed |
|
||||
|
||||
## Build/bake
|
||||
|
||||
```bash
|
||||
# one library asset
|
||||
flatpak run org.blender.Blender --background \
|
||||
--python "$PWD/tools/blender_assets.py" -- build --only npc_guard
|
||||
|
||||
# bake AO for the same asset
|
||||
flatpak run org.blender.Blender --background \
|
||||
--python "$PWD/tools/bake_ao.py" -- --only npc_guard
|
||||
|
||||
# NPC base material maps/base
|
||||
python3 tools/npc_pipeline.py prepare
|
||||
flatpak run org.blender.Blender --background \
|
||||
--python "$PWD/tools/npc_pipeline.py" -- build
|
||||
python3 tools/npc_pipeline.py audit
|
||||
```
|
||||
|
||||
Only run `prepare` when AI fabric inputs changed. Do not run a full library
|
||||
rebuild just to hide a small diff; build the affected asset and its AO map.
|
||||
|
||||
## Import and tests
|
||||
|
||||
```bash
|
||||
godot --headless --path . --import
|
||||
godot --headless --path . --script res://src/test/test_runner.gd
|
||||
python3 -m unittest discover -s tools/tests -t tools -p 'test_*.py'
|
||||
python3 tools/check_docs.py
|
||||
```
|
||||
|
||||
Expected: Godot suite passes; Python tooling suite passes; docs check OK. The
|
||||
project uses its own headless runner, not GUT.
|
||||
|
||||
## Capture gates
|
||||
|
||||
```bash
|
||||
# neutral studio baseline: 48 frames (8 characters x 6 views)
|
||||
godot --path . --script res://src/test/capture_npc_baseline.gd \
|
||||
-- --out=res://tmp/npc-baseline-after
|
||||
|
||||
# final-context: 96 frames (8 models x 3 distances x 2 venues x day/night)
|
||||
godot --path . --script res://src/test/capture_npc_review.gd \
|
||||
-- --out=res://tmp/npc-review-after
|
||||
|
||||
# optional hand close-up: 8 frames
|
||||
godot --path . --script res://src/test/capture_npc_baseline.gd \
|
||||
-- --out=res://tmp/npc-hands --view=hand
|
||||
```
|
||||
|
||||
Raw frames stay under `tmp/` and are never committed. Compare with:
|
||||
|
||||
```bash
|
||||
python3 tools/npc_baseline.py compare \
|
||||
--before tmp/npc-baseline --after tmp/npc-baseline-after \
|
||||
--out docs/blender_previews/sheet_npc_baseline_compare-<topic>.jpg
|
||||
```
|
||||
|
||||
Do not replace the committed baseline sheet until the change is accepted.
|
||||
|
||||
## Budget/performance
|
||||
|
||||
```bash
|
||||
godot --headless --path . --script res://src/test/smoke_npc_budget.gd
|
||||
```
|
||||
|
||||
Expected report: 24 avatars / 168 meshes / 131,616 triangles (current baseline)
|
||||
inside the 50 ms budget. Record the actual frame time; do not copy an old number
|
||||
without measuring.
|
||||
|
||||
## Visual review criteria
|
||||
|
||||
For each changed variant, inspect at least:
|
||||
|
||||
- 2 m portrait: eyes, mouth, ears, neck/shoulder, hair/headgear clearance.
|
||||
- 4.2 m conversation: hands, gear contact, clothing silhouette.
|
||||
- 8 m crowd: readable silhouette and LOD/impostor swap.
|
||||
- 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
|
||||
contract change.
|
||||
|
||||
## Final diff review
|
||||
|
||||
```bash
|
||||
git diff --check
|
||||
git status --short
|
||||
git diff --stat
|
||||
```
|
||||
|
||||
Check that only intended `.glb`, AO/maps, manifest, tests and docs changed. If a
|
||||
`.blend`, raw capture, generated AI input or temporary sheet is staged, stop and
|
||||
remove it. Commit one coherent asset family per commit.
|
||||
@@ -0,0 +1,254 @@
|
||||
---
|
||||
name: gig-line-release-qa
|
||||
description: Use when preparing, validating, tagging or publishing a Gig Line release or release candidate, or when running the full screenshot, screen-design and realism QA gates. Covers version/changelog discipline, smoke and tooling matrices, clean-worktree builds, checksums, Web/HQ verification, publish rollback and post-release records. Do not use for ordinary asset edits or feature work.
|
||||
compatibility: Gig Line repository checkout with Godot 4.7.2 on PATH and Python 3 + Pillow. Release export needs installed Godot export templates; publishing needs Gitea credentials and is intentionally CI/tag-driven.
|
||||
metadata:
|
||||
project: Gig Line
|
||||
domain: release-qa
|
||||
version: "1.0.0"
|
||||
triggers: release, tag, version bump, changelog, build releases, publish, screenshots, screen design, realism judge, release candidate, deployment
|
||||
---
|
||||
|
||||
# Gig Line Release and Visual QA
|
||||
|
||||
Use this skill for version bumps, release candidates, tags, artifact builds,
|
||||
publishing, and the full visual/QA gate. For a Blender/asset rebuild, use
|
||||
`gig-line-blender-asset-contract` first.
|
||||
|
||||
## Read first
|
||||
|
||||
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/smoke-checklist.md` — manual QA matrix.
|
||||
5. `docs/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,
|
||||
artifact/checksum verification, CI publication, and post-release records.
|
||||
|
||||
## Hard rules
|
||||
|
||||
- **Do not tag while the TODO still lists unresolved release blockers.** Check
|
||||
external playtest, legal/AI provenance, signing and target-hardware items.
|
||||
- **Never reuse a tag.** If a published version needs a fix, bump the patch and
|
||||
create a new tag.
|
||||
- **Build from a clean checkout or detached worktree.** A normal working tree can
|
||||
pack ignored `tmp/` and `build/` content into exports, inflating a ~160 MB
|
||||
package to 1.6–3.1 GB.
|
||||
- A tag push triggers CI checks/build/publish. Do not upload manually unless CI is
|
||||
unavailable and you have followed the same preflight.
|
||||
- Do not commit generated realism runs, raw captures, API keys, or build artifacts.
|
||||
- The vision judge is an optional development aid with external API cost, never a
|
||||
hard CI gate.
|
||||
- Keep `project.godot`, changelog, tag and release asset version equal.
|
||||
|
||||
## Release workflow
|
||||
|
||||
### 1. Scope and version
|
||||
|
||||
Choose the semantic increment from `AGENTS.md`:
|
||||
|
||||
- MAJOR: incompatible/removed behavior, save/config contract or core-pillar
|
||||
replacement.
|
||||
- MINOR: new user-facing feature/venue.
|
||||
- PATCH: fixes and polish.
|
||||
|
||||
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.
|
||||
|
||||
For a release candidate, use a prerelease version only if the project policy
|
||||
allows it and never present it as the final release.
|
||||
|
||||
### 2. Preflight
|
||||
|
||||
```bash
|
||||
git status --short
|
||||
git log --oneline -5
|
||||
git tag -l "v<version>"
|
||||
rg -n 'config/version' project.godot
|
||||
```
|
||||
|
||||
Expected: only intended release changes; tag does not exist; version matches the
|
||||
changelog and planned artifacts.
|
||||
|
||||
### 3. Automated checks
|
||||
|
||||
```bash
|
||||
godot --headless --path . --script res://src/test/test_runner.gd
|
||||
python3 -m unittest discover -s tools/tests -t tools -p 'test_*.py'
|
||||
python3 tools/check_docs.py
|
||||
python3 tools/blender_assets.py audit
|
||||
python3 tools/blender_assets.py fit
|
||||
python3 tools/npc_proportions.py report
|
||||
python3 tools/npc_pipeline.py audit
|
||||
```
|
||||
|
||||
Then run the smoke matrix, using isolated user-data directories for
|
||||
tutorial/campaign:
|
||||
|
||||
```bash
|
||||
for s in smoke_audio smoke_crowd smoke_emergency smoke_npc_budget \
|
||||
smoke_plan_verbs smoke_scenario_content smoke_session_shell \
|
||||
smoke_timeline smoke_ui_flows; do
|
||||
godot --headless --path . --script res://src/test/$s.gd || exit 1
|
||||
done
|
||||
|
||||
XDG_DATA_HOME=/tmp/gig-line-campaign godot --path . --fixed-fps 60 \
|
||||
--script res://src/test/smoke_campaign.gd
|
||||
XDG_DATA_HOME=/tmp/gig-line-tutorial godot --path . --fixed-fps 60 \
|
||||
--script res://src/test/smoke_tutorial.gd -- --tutorial
|
||||
|
||||
godot --path . --script res://src/test/smoke_movement.gd
|
||||
godot --path . --script res://src/test/smoke_props.gd
|
||||
godot --path . --script res://src/test/smoke_focus_radial.gd
|
||||
```
|
||||
|
||||
Use a fresh `$XDG_DATA_HOME` for campaign/tutorial and check the exit code, not
|
||||
just the log.
|
||||
|
||||
### 4. Visual and judge gates
|
||||
|
||||
```bash
|
||||
./tools/check_screenshots.sh
|
||||
python3 tools/screen_designs.py compare
|
||||
python3 tools/screen_designs.py judge --model auto # optional, record model/verdicts
|
||||
```
|
||||
|
||||
For realism/venue work:
|
||||
|
||||
```bash
|
||||
godot --path . --script res://src/test/capture_realism.gd \
|
||||
-- --out=res://docs/screens/realism/<run>/after
|
||||
python3 tools/scene_concepts.py realism --run docs/screens/realism/<run> \
|
||||
--judge --model <pinned-model>
|
||||
```
|
||||
|
||||
Requirements:
|
||||
|
||||
- Gallery: 21 good / 0 bad; screen judge has no unexplained `diff`.
|
||||
- Realism runs stay under `docs/screens/realism/` (gitignored); only decisions and
|
||||
committed sheets/docs are tracked.
|
||||
- Record judge model, run count/attempts, spend if exposed, and verdicts.
|
||||
- Review every `review` verdict; turn layout regressions into fixes or documented
|
||||
known limitations.
|
||||
|
||||
### 5. Clean build
|
||||
|
||||
Commit the release preparation first, then build the committed tree in a clean
|
||||
worktree:
|
||||
|
||||
```bash
|
||||
git worktree add --detach /tmp/gig-line-release HEAD
|
||||
cd /tmp/gig-line-release
|
||||
./tools/build_releases.sh
|
||||
```
|
||||
|
||||
Verify artifact names/sizes and checksums:
|
||||
|
||||
```bash
|
||||
ls -lh build/gig-line-*<version>*
|
||||
PUBLISH_DRY_RUN=1 ./tools/publish_release.sh <version>
|
||||
sha256sum -c build/SHA256SUMS-<version>.txt
|
||||
```
|
||||
|
||||
Check package contents:
|
||||
|
||||
```bash
|
||||
unzip -l build/gig-line-web-<version>.zip | head
|
||||
unzip -l build/gig-line-desktop-hq-<version>.zip | head
|
||||
unzip -p build/gig-line-desktop-hq-<version>.zip override.cfg
|
||||
```
|
||||
|
||||
Check the runnable Linux and HQ packages:
|
||||
|
||||
```bash
|
||||
./build/gig-line-linux-<version>.x86_64 --headless --quit-after 60
|
||||
unzip -q build/gig-line-desktop-hq-<version>.zip -d /tmp/gig-line-hq
|
||||
/tmp/gig-line-hq/gig-line-linux-<version>.x86_64 --headless --quit-after 60
|
||||
```
|
||||
|
||||
Check Web static serving with a local HTTP server and `curl` for `index.html`,
|
||||
`index.wasm`, `index.pck` and the player docs. Windows/macOS/AppImage/installer
|
||||
checks require the target matrix; if unavailable, record that explicitly.
|
||||
|
||||
Remove the worktree after verification:
|
||||
|
||||
```bash
|
||||
git worktree remove --force /tmp/gig-line-release
|
||||
```
|
||||
|
||||
### 6. Tag and publish
|
||||
|
||||
Only after every gate is green:
|
||||
|
||||
```bash
|
||||
git add -A
|
||||
git commit -m "Release <version> <topic>"
|
||||
git tag -a "v<version>" -m "Gig Line <version>"
|
||||
git push origin main "v<version>"
|
||||
```
|
||||
|
||||
CI builds and publishes on the tag. Verify:
|
||||
|
||||
- Tag commit equals the release commit.
|
||||
- CI checks/build job succeeded.
|
||||
- Release page has the expected 7 assets (Linux, Windows, macOS, NSIS setup,
|
||||
AppImage, Web, Desktop HQ).
|
||||
- Asset names and download links point at the released version.
|
||||
|
||||
`tools/publish_release.sh` preflights artifact size/free space, writes SHA-256
|
||||
checksums, rolls back newly uploaded assets/release on failure, and supports
|
||||
opt-in retention:
|
||||
|
||||
```bash
|
||||
RETAIN_RELEASES=7 ./tools/publish_release.sh <version>
|
||||
```
|
||||
|
||||
The default `RETAIN_RELEASES=0` never prunes.
|
||||
|
||||
### 7. Post-release record
|
||||
|
||||
Update `README.md`, `docs/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.
|
||||
|
||||
## Known gotchas
|
||||
|
||||
- **Dirty build inflation:** always use the clean worktree above.
|
||||
- **`Class ... hides a global script class`:** remove stray `.gd` backups in
|
||||
`tmp/`, delete `.godot`, re-import.
|
||||
- **Screenshot staging:** `capture_ui_states.gd` needs its settle frames and
|
||||
staged state; do not capture a paused frame or a stale modal.
|
||||
- **Judge keys:** OpenRouter calls need `.env`/`OPENROUTER_API_KEY`; never commit
|
||||
the key or generated review folders.
|
||||
- **Tag builds publish automatically:** do not run a second manual publish that
|
||||
duplicates assets; use the existing release if re-running.
|
||||
- **macOS is unsigned unless policy changes:** record quarantine instructions and
|
||||
do not claim notarization.
|
||||
- **Release blockers are real:** external playtest, legal/storefront approval,
|
||||
AI-provider rights and target-hardware checks cannot be replaced by green unit
|
||||
tests.
|
||||
|
||||
## Bundled references
|
||||
|
||||
- [`references/release-runbook.md`](references/release-runbook.md) — version,
|
||||
build, tag, CI, publish and rollback sequence.
|
||||
- [`references/qa-gates.md`](references/qa-gates.md) — full command matrix,
|
||||
expected results and evidence to record.
|
||||
|
||||
## Completion checklist
|
||||
|
||||
- [ ] Version/changelog/docs/tag match.
|
||||
- [ ] No unresolved release blockers for a final tag.
|
||||
- [ ] Godot, Python, smokes, asset and docs gates pass.
|
||||
- [ ] Gallery and optional judges reviewed with evidence.
|
||||
- [ ] Clean worktree build and checksums verified.
|
||||
- [ ] Linux/HQ/Web checks recorded; unavailable platforms noted.
|
||||
- [ ] Tag pushed; CI/publish succeeded; seven assets verified.
|
||||
- [ ] Release record and durable docs committed.
|
||||
@@ -0,0 +1,171 @@
|
||||
# QA Gate Matrix
|
||||
|
||||
Run from the repository root. Capture the exit code and the useful report line,
|
||||
not only the final “OK”.
|
||||
|
||||
## 1. Source and docs
|
||||
|
||||
```bash
|
||||
git status --short
|
||||
git log --oneline -5
|
||||
python3 tools/check_docs.py
|
||||
git diff --check
|
||||
```
|
||||
|
||||
Expected: intended files only; `check_docs: OK`; no whitespace errors.
|
||||
|
||||
## 2. Automated suites
|
||||
|
||||
```bash
|
||||
godot --headless --path . --script res://src/test/test_runner.gd
|
||||
python3 -m unittest discover -s tools/tests -t tools -p 'test_*.py'
|
||||
```
|
||||
|
||||
Expected: the current Godot suite passes (historically 272+ tests) and the
|
||||
Python tooling suite passes (currently 160 tests). Do not edit expected counts
|
||||
without inspecting the suite.
|
||||
|
||||
## 3. Asset gates
|
||||
|
||||
```bash
|
||||
python3 tools/blender_assets.py audit
|
||||
python3 tools/blender_assets.py fit
|
||||
python3 tools/blender_assets.py texels
|
||||
python3 tools/npc_pipeline.py audit
|
||||
python3 tools/npc_proportions.py report
|
||||
```
|
||||
|
||||
Expected: exit 0, no `BAD` assets, all eight characters inside the stylized
|
||||
proportion guide, no budget/contract regression.
|
||||
|
||||
Optional texture/model audits when those assets changed:
|
||||
|
||||
```bash
|
||||
python3 tools/asset_pipeline.py audit assets/textures/ai/game_ready
|
||||
python3 tools/model_pipeline.py audit
|
||||
```
|
||||
|
||||
## 4. Smoke matrix
|
||||
|
||||
Headless:
|
||||
|
||||
```bash
|
||||
for s in smoke_audio smoke_crowd smoke_emergency smoke_npc_budget \
|
||||
smoke_plan_verbs smoke_scenario_content smoke_session_shell \
|
||||
smoke_timeline smoke_ui_flows; do
|
||||
echo "== $s"
|
||||
godot --headless --path . --script res://src/test/$s.gd || exit 1
|
||||
done
|
||||
```
|
||||
|
||||
Isolated data:
|
||||
|
||||
```bash
|
||||
rm -rf /tmp/gig-line-release-campaign /tmp/gig-line-release-tutorial
|
||||
XDG_DATA_HOME=/tmp/gig-line-release-campaign godot --path . --fixed-fps 60 \
|
||||
--script res://src/test/smoke_campaign.gd
|
||||
XDG_DATA_HOME=/tmp/gig-line-release-tutorial godot --path . --fixed-fps 60 \
|
||||
--script res://src/test/smoke_tutorial.gd -- --tutorial
|
||||
```
|
||||
|
||||
Windowed input/UI:
|
||||
|
||||
```bash
|
||||
godot --path . --script res://src/test/smoke_movement.gd
|
||||
godot --path . --script res://src/test/smoke_props.gd
|
||||
godot --path . --script res://src/test/smoke_focus_radial.gd
|
||||
```
|
||||
|
||||
Expected: 14 smokes green. `smoke_npc_budget` should print the current mesh,
|
||||
triangle and frame-time evidence; the 50 ms budget is a safety ceiling.
|
||||
|
||||
## 5. Screenshot and design gates
|
||||
|
||||
```bash
|
||||
./tools/check_screenshots.sh
|
||||
python3 tools/screen_designs.py compare
|
||||
```
|
||||
|
||||
Expected: 21 good / 0 bad; no unexplained compare output. The judge is optional:
|
||||
|
||||
```bash
|
||||
python3 tools/screen_designs.py judge --model auto
|
||||
```
|
||||
|
||||
Record model, confidence/verdict summary, `diff` count and any manual review.
|
||||
`docs/screen-design-report.md` is the durable record.
|
||||
|
||||
## 6. Realism judge (when visual assets/lighting changed)
|
||||
|
||||
```bash
|
||||
godot --path . --script res://src/test/capture_realism.gd \
|
||||
-- --out=res://docs/screens/realism/<run>/after
|
||||
python3 tools/scene_concepts.py realism --run docs/screens/realism/<run> \
|
||||
--judge --model <pinned-model>
|
||||
```
|
||||
|
||||
Expected: a complete set of required stage captures, no stale pauses/modals, and
|
||||
a report under the gitignored run directory. Record:
|
||||
|
||||
- pinned model/fallbacks
|
||||
- shots attempted/completed
|
||||
- spend if the tool exposes it
|
||||
- mean score and Pillow gap
|
||||
- every `review` verdict and disposition
|
||||
|
||||
Do not commit the run. Commit only the decision/report summary and any durable
|
||||
comparison sheet explicitly intended for review.
|
||||
|
||||
## 7. Package checks
|
||||
|
||||
Use the clean worktree from `release-runbook.md`.
|
||||
|
||||
```bash
|
||||
PUBLISH_DRY_RUN=1 ./tools/publish_release.sh <version>
|
||||
sha256sum -c build/SHA256SUMS-<version>.txt
|
||||
unzip -l build/gig-line-web-<version>.zip
|
||||
unzip -l build/gig-line-desktop-hq-<version>.zip
|
||||
unzip -p build/gig-line-desktop-hq-<version>.zip override.cfg
|
||||
./build/gig-line-linux-<version>.x86_64 --headless --quit-after 60
|
||||
```
|
||||
|
||||
Expected:
|
||||
|
||||
- names match the version;
|
||||
- Linux/Windows/macOS/Web/HQ present locally;
|
||||
- Web contains HTML/wasm/pck and docs;
|
||||
- HQ contains `override.cfg`, executables and docs;
|
||||
- Linux/HQ start without a script error.
|
||||
|
||||
Windows installer/AppImage and macOS launch require CI or the target matrix. If
|
||||
not available, mark them as unverified rather than passing them by analogy.
|
||||
|
||||
## 8. Release verification
|
||||
|
||||
After the tag push:
|
||||
|
||||
- CI checks job succeeded;
|
||||
- CI build job succeeded;
|
||||
- release page has seven assets;
|
||||
- each artifact name includes the released version;
|
||||
- the tag points at the release commit;
|
||||
- README/changelog/status and release notes agree.
|
||||
|
||||
## Evidence summary template
|
||||
|
||||
```text
|
||||
Release: vX.Y.Z (commit)
|
||||
Godot: pass (N/N)
|
||||
Python tooling: pass (N/N)
|
||||
Smokes: 14/14
|
||||
Assets: audit/fit/proportions/npc audit pass
|
||||
Budget: 24 NPCs, N meshes, N triangles, N ms
|
||||
Gallery: 21 good / 0 bad
|
||||
Screen judge: N/N match, N review, N diff
|
||||
Realism: model, attempts, mean, gap, review dispositions
|
||||
Build: clean worktree, artifact sizes/checksums
|
||||
Launch: Linux/HQ/Web checks; unverified platforms
|
||||
CI/release: run id, seven assets
|
||||
Skipped checks + reason:
|
||||
Known limitations:
|
||||
```
|
||||
@@ -0,0 +1,171 @@
|
||||
# Release Runbook
|
||||
|
||||
Authoritative source: `AGENTS.md` (Release Procedure), `docs/RELEASING.md`.
|
||||
This runbook is the operational checklist; if it conflicts with those, they win.
|
||||
|
||||
## 0. Decide the release
|
||||
|
||||
Determine whether this is a major, minor, patch, or release-candidate checkpoint.
|
||||
Do not assign a version to an unversioned development track until its scope is
|
||||
accepted into a release.
|
||||
|
||||
Check the current release constraints in `TODO.md`:
|
||||
|
||||
- external playtest evidence
|
||||
- legal/AI-provider/storefront review
|
||||
- macOS signing/notarization policy
|
||||
- target hardware matrix
|
||||
- any manual QA gaps
|
||||
|
||||
If a final release would ship with unresolved blockers, prepare an RC or stop;
|
||||
do not create a final tag.
|
||||
|
||||
## 1. Prepare the version
|
||||
|
||||
Files to update:
|
||||
|
||||
| File | Change |
|
||||
| --- | --- |
|
||||
| `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 |
|
||||
| `TODO.md` / `DONE.md` | close/move milestone when complete |
|
||||
| `MEMORY.md` | release state and gotchas |
|
||||
|
||||
Then commit the preparation before building.
|
||||
|
||||
## 2. Run gates
|
||||
|
||||
Use `qa-gates.md` as the command matrix. The minimum release gate is:
|
||||
|
||||
- Godot suite
|
||||
- Python tooling tests
|
||||
- documentation gate
|
||||
- asset audits/fit/proportions
|
||||
- 24-NPC budget
|
||||
- 14 smoke scripts
|
||||
- screenshot compare
|
||||
- optional screen/realism judge with recorded model/attempts
|
||||
- clean build and artifact checks
|
||||
|
||||
Any skipped check must be written into `MEMORY.md` or `TODO.md` with a reason.
|
||||
|
||||
## 3. Build in a clean worktree
|
||||
|
||||
Why: Godot can pack ignored `tmp/` captures and `build/` outputs into the export.
|
||||
A dirty build can produce 1.6–3.1 GB artifacts instead of ~160–240 MB.
|
||||
|
||||
```bash
|
||||
git worktree add --detach /tmp/gig-line-release HEAD
|
||||
cd /tmp/gig-line-release
|
||||
./tools/build_releases.sh
|
||||
```
|
||||
|
||||
Expected local artifacts:
|
||||
|
||||
```text
|
||||
build/gig-line-linux-<version>.x86_64
|
||||
build/gig-line-windows-<version>.exe
|
||||
build/gig-line-macos-<version>.zip
|
||||
build/gig-line-web-<version>.zip
|
||||
build/gig-line-desktop-hq-<version>.zip
|
||||
```
|
||||
|
||||
CI additionally produces the NSIS setup and AppImage, for seven release assets.
|
||||
|
||||
## 4. Preflight and checksum
|
||||
|
||||
```bash
|
||||
PUBLISH_DRY_RUN=1 ./tools/publish_release.sh <version>
|
||||
sha256sum -c build/SHA256SUMS-<version>.txt
|
||||
```
|
||||
|
||||
`publish_release.sh` checks non-empty artifacts and local free space before any
|
||||
API call. It writes checksums under `build/` and does not upload them by default.
|
||||
|
||||
Inspect packages:
|
||||
|
||||
```bash
|
||||
unzip -l build/gig-line-web-<version>.zip | head -20
|
||||
unzip -l build/gig-line-desktop-hq-<version>.zip | head -20
|
||||
unzip -p build/gig-line-desktop-hq-<version>.zip override.cfg
|
||||
```
|
||||
|
||||
Web must contain `index.html`, `index.wasm`, `index.pck`, and player docs.
|
||||
Desktop HQ must contain the Linux/Windows executables, `override.cfg`,
|
||||
`README.txt`, `CREDITS.md`, `PRIVACY.md`, `accessibility.md` and
|
||||
`known-limitations.md`.
|
||||
|
||||
## 5. Runtime launch smoke
|
||||
|
||||
```bash
|
||||
./build/gig-line-linux-<version>.x86_64 --headless --quit-after 60
|
||||
unzip -q build/gig-line-desktop-hq-<version>.zip -d /tmp/gig-line-hq
|
||||
/tmp/gig-line-hq/gig-line-linux-<version>.x86_64 --headless --quit-after 60
|
||||
```
|
||||
|
||||
For Web, serve `build/web` and check HTTP 200 for `index.html`, `index.wasm`,
|
||||
`index.pck` and docs. Do not claim browser interaction from a curl check.
|
||||
|
||||
Remove the temporary worktree after checks:
|
||||
|
||||
```bash
|
||||
git worktree remove --force /tmp/gig-line-release
|
||||
```
|
||||
|
||||
## 6. Tag and CI
|
||||
|
||||
From the real repository, on the release commit:
|
||||
|
||||
```bash
|
||||
git tag -a "v<version>" -m "Gig Line <version>"
|
||||
git push origin main "v<version>"
|
||||
```
|
||||
|
||||
The tag triggers `.gitea/workflows/build.yml`: checks, export, installer,
|
||||
AppImage, release publish. Verify the run and assets:
|
||||
|
||||
- check job success
|
||||
- build job success
|
||||
- seven assets present
|
||||
- tag/version/artifact names equal
|
||||
- download links respond
|
||||
|
||||
Do not reuse a published tag. If a fix is needed, bump patch and repeat.
|
||||
|
||||
## 7. Manual publish fallback
|
||||
|
||||
Only if CI cannot publish:
|
||||
|
||||
```bash
|
||||
RETAIN_RELEASES=7 ./tools/publish_release.sh <version>
|
||||
```
|
||||
|
||||
The script reuses or creates the release, uploads present artifacts, verifies the
|
||||
asset count, and rolls back newly uploaded assets/new release on failure. The
|
||||
default retention is `0` (no deletion). Never delete older releases implicitly.
|
||||
|
||||
## 8. Post-release record
|
||||
|
||||
Commit a release record that includes:
|
||||
|
||||
- tag and commit
|
||||
- CI run/result
|
||||
- seven assets
|
||||
- checksums or size evidence
|
||||
- skipped checks
|
||||
- known limitations
|
||||
- release URL
|
||||
|
||||
Update `DONE.md`/`TODO.md` and `MEMORY.md`; keep the changelog and README
|
||||
consistent. Push the record commit.
|
||||
|
||||
## Versioning pitfalls
|
||||
|
||||
- A `vX.Y.Z` tag is immutable in practice; do not move/replace it.
|
||||
- A release candidate is not a final release. Do not label it as such in the
|
||||
README or release page if blockers remain.
|
||||
- `config/version` must match the tag and artifact filenames.
|
||||
- The clean-worktree build is a release requirement, not an optimization.
|
||||
@@ -58,6 +58,20 @@ assets/models/generated/npc_base_*_normal.png
|
||||
|
||||
# Local AppImage extraction
|
||||
squashfs-root/
|
||||
|
||||
# Local agent skills. The third-party Blender pack is installed per machine and
|
||||
# stays ignored; the two project-authored skills are tracked so the workflow can
|
||||
# be shared and reviewed.
|
||||
.agents/
|
||||
!.agents/
|
||||
.agents/*
|
||||
!.agents/.gdignore
|
||||
!.agents/skills/
|
||||
.agents/skills/*
|
||||
!.agents/skills/gig-line-blender-asset-contract/
|
||||
!.agents/skills/gig-line-blender-asset-contract/**
|
||||
!.agents/skills/gig-line-release-qa/
|
||||
!.agents/skills/gig-line-release-qa/**
|
||||
# Blender asset library: per-asset Cycles renders are local review output (the
|
||||
# committed review artefacts are docs/blender_previews/sheet_*.jpg), and Godot
|
||||
# extracts the GLB-embedded textures next to the models on import.
|
||||
@@ -74,3 +88,7 @@ assets/models/blender_src/*.blend
|
||||
assets/textures/ai/game_ready/v2/*
|
||||
!assets/textures/ai/game_ready/v2/picks/
|
||||
docs/screens/realism/
|
||||
|
||||
## Local pi agent session data
|
||||
pi-session-*.html
|
||||
pi-session-*.jsonl
|
||||
@@ -19,10 +19,93 @@ The project should be developed in small, reviewable steps. Agents must keep pla
|
||||
- `docs/architecture.md` — The arc42-style architecture documentation (goals, constraints, building blocks, runtime views, decisions, risks).
|
||||
- `docs/gameplay.md` — Gameplay systems, venues, and the escalation model.
|
||||
- `docs/asset-tooling.md` — Asset pipelines, model tools, and screenshot gates.
|
||||
- `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/smoke-checklist.md` — The manual smoke-test checklist.
|
||||
- `docs/adr/` — Architecture Decision Records.
|
||||
|
||||
## Priority and Versioning
|
||||
|
||||
`TODO.md` is the priority source. The active order is:
|
||||
|
||||
1. unversioned development tracks;
|
||||
2. versioned release milestones, in version order;
|
||||
3. future/unversioned candidates and deferred work.
|
||||
|
||||
Do not assign a version number to an unversioned track until its scope is accepted into a
|
||||
release. When a version is assigned, it must be the next semantic version that matches the
|
||||
scope (major/minor/patch), not a placeholder.
|
||||
|
||||
## Local Blender skills (development aid)
|
||||
|
||||
The MIT `blender-skills` pack is installed locally at `.agents/skills/blender-skills/`
|
||||
(94 skills plus a shared `references/` folder). It is **gitignored on purpose**: it is not
|
||||
game content, not part of the build, tests, CI or release packages, and every contributor
|
||||
may or may not have it. The agent runtime (Pi) gates project `.agents/skills` behind project
|
||||
trust, so the trust prompt must be accepted before the skills load; `/skill:blender-director`
|
||||
forces one.
|
||||
|
||||
Use them when a task touches `tools/blender_assets.py`, `tools/npc_pipeline.py`,
|
||||
`tools/bake_ao.py`, `assets/models/blender/**`, or Blender-authored venue/prop geometry.
|
||||
|
||||
### Project-authored skills (tracked)
|
||||
|
||||
Two project skills are committed under `.agents/skills/` and are guidance for
|
||||
any agent, not only Pi:
|
||||
|
||||
- `gig-line-blender-asset-contract` — the NPC/gear/prop contract, build order,
|
||||
headless Blender commands, failure playbook and verification gates.
|
||||
- `gig-line-release-qa` — the test/smoke matrix, visual judges, clean-worktree
|
||||
build, checksum/tag/publish sequence and release records.
|
||||
|
||||
They are not runtime dependencies and do not move tool implementations into
|
||||
`.agents/`. The third-party `blender-skills` pack stays local/gitignored.
|
||||
|
||||
### Routing
|
||||
|
||||
Start with `blender-director` for anything multi-discipline, then load only the
|
||||
specialists the task needs:
|
||||
|
||||
| Work | Skills |
|
||||
| --- | --- |
|
||||
| Plan/route a Blender task, reference photo match | `blender-director` |
|
||||
| Character mesh, face, hands, proportions | `character-artist`, `character-archetypes`, `retopology` |
|
||||
| Skeleton, weights, pose/contract rigging | `rigging` |
|
||||
| UV layout, texel density, UDIM | `uv-workflow` |
|
||||
| Bakery, atlas, normal/AO/ORM maps | `texture-workflow` |
|
||||
| PBR materials and shading | `materials` |
|
||||
| Screenshot-driven material/light iteration | `lookdev` |
|
||||
| Triangle/vertex budgets, naming, scene hygiene | `asset-optimization` |
|
||||
| LOD tiers and impostors | `lod-pipeline` |
|
||||
| Collision shapes and proxies | `collision-proxy` |
|
||||
| GLB export for Godot | `godot-export`, `export-pipeline` |
|
||||
| Gear, props, street furniture | `prop-artist`, `hard-surface` |
|
||||
| Trees, hedges, foliage cards | `vegetation-artist` |
|
||||
| Facades, venues, modular kits, dressing | `environment-artist`, `archviz`, `set-dressing`, `geometry-nodes` |
|
||||
| Lighting, framing, final render/composite | `lighting`, `camera-cinematography`, `rendering`, `compositing` |
|
||||
| Style direction (stylized / low-poly / realistic) | `stylized-style`, `lowpoly-style`, `realistic-style` |
|
||||
| Ship/no-ship review | `qa-review` |
|
||||
|
||||
### Project rules that override a skill
|
||||
|
||||
1. **The project contract wins.** `npc_base` mesh node, the 13 contract bones at their rest
|
||||
positions, five tint slots, front on Blender −Y / Godot +Z, grounded feet, 8,000
|
||||
triangles / 8,000 glTF vertices per character, 1,500 per gear, 4,000 per prop. A skill
|
||||
may recommend another topology, naming or budget scheme; do not adopt it unless the
|
||||
change is explicitly planned and the contract, tests and docs are updated together.
|
||||
2. **There is no Blender MCP here.** The skills assume MCP tools; this project runs Blender
|
||||
as headless flatpak scripts (`tools/blender_assets.py`, `tools/npc_pipeline.py`). Translate
|
||||
MCP steps into script changes or CLI runs. Never add an MCP dependency to the build, CI or
|
||||
runtime.
|
||||
3. **CI stays offline and skill-free.** Skills are local guidance only; every gate must still
|
||||
work from a fresh checkout with committed `.glb`/`.png`/`.tres` files and Godot.
|
||||
4. **No new asset source without the licence gate.** Skills may suggest reference packs or
|
||||
generated meshes; ADR-0015 (CC0, or CC-BY with attribution in `CREDITS.md`) and the
|
||||
provenance rules in `docs/npc-model-sourcing.md` still apply.
|
||||
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.
|
||||
|
||||
## Required Workflow
|
||||
|
||||
### 1. Start by Inspecting the Repository
|
||||
@@ -47,8 +130,11 @@ All planned implementation work must be represented in `TODO.md`.
|
||||
- Use level-2 headings (`##`) for milestones or stable themes. A milestone should state its goal
|
||||
and an explicit exit criterion; a theme groups small related work that does not need a
|
||||
milestone.
|
||||
- Use level-3 headings (`###`) for workstreams inside a milestone (for example, `0.8.1
|
||||
First-shift tutorial`). Keep the hierarchy to three levels: milestone → workstream → checkbox.
|
||||
- Order level-2 sections by current priority: unversioned development tracks first, then
|
||||
versioned release milestones in version order, then future/deferred work. Do not assign a
|
||||
version number to an unversioned track until it is scheduled for a release.
|
||||
- Use level-3 headings (`###`) for workstreams inside a milestone. Keep the hierarchy to three
|
||||
levels: milestone → workstream → checkbox.
|
||||
- Use checkbox items for each concrete task, normally under a level-3 workstream. Direct
|
||||
checkboxes under a level-2 section are acceptable for small, single-workstream sections.
|
||||
- Keep tasks small enough to complete and review independently.
|
||||
@@ -67,26 +153,31 @@ Recommended format:
|
||||
```md
|
||||
# TODO
|
||||
|
||||
## Milestone 0.8.0 — First hour and content depth
|
||||
## Milestone X.Y.Z — goal and exit criterion
|
||||
|
||||
### 0.8.1 First-shift tutorial
|
||||
### Workstream A
|
||||
|
||||
- [x] Write the tutorial beat sheet.
|
||||
- [-] Implement the tutorial state machine. (claimed; implementation/verification in progress)
|
||||
- [ ] Add the tutorial smoke test.
|
||||
- [x] Completed task.
|
||||
- [-] Task in progress. (claimed; implementation/verification in progress)
|
||||
- [ ] Open task.
|
||||
|
||||
### 0.8.2 Campaign shell
|
||||
### Workstream B
|
||||
|
||||
- [ ] Define campaign data.
|
||||
- [ ] Persist campaign progress.
|
||||
- [ ] Another task.
|
||||
|
||||
**Exit:** a first-time player completes a shift without external documentation.
|
||||
**Exit:** a verifiable statement of what "done" means for the milestone.
|
||||
|
||||
## Documentation
|
||||
## Theme
|
||||
|
||||
- [ ] Document the test procedure in `README.md`.
|
||||
- [ ] A small housekeeping task with no milestone.
|
||||
```
|
||||
|
||||
Recommended `DONE.md` format: a `# DONE` heading, followed by each moved level-2 section
|
||||
unchanged, with a completion date line under each section heading.
|
||||
|
||||
Order the actual file as described in "Priority and Versioning": unversioned development tracks
|
||||
first, then versioned milestones in version order, then future/deferred work.
|
||||
|
||||
### 3. Move Completed Sections to `DONE.md`
|
||||
|
||||
`TODO.md` uses nested sections. Apply these completion rules:
|
||||
@@ -174,10 +265,12 @@ Update `README.md` whenever setup instructions, commands, project structure, or
|
||||
The root-level `CHANGELOG.md` records the user-facing changes for every release. It exists so players and contributors can see what changed between versions without reading the commit log.
|
||||
|
||||
- Add an entry for every patch, minor, and major version change.
|
||||
- Follow Semantic Versioning (`major.minor.patch`): bump major for breaking or vision-level changes, minor for new features, and patch for fixes and small polish.
|
||||
- Follow Semantic Versioning (`major.minor.patch`): bump major only for changes that remove or break an existing player-facing feature, save format, or config contract, or that replace a system listed as a core pillar in PLAN.md; bump minor for new user-facing features; bump patch for fixes and small polish.
|
||||
- A version increment is not complete until its `CHANGELOG.md` entry, `config/version` update and
|
||||
matching local release build have all been produced and verified.
|
||||
- Group each entry under `Added`, `Changed`, `Fixed`, and `Removed` headings, and date every entry.
|
||||
- Describe changes in user-facing terms, not as raw commit messages.
|
||||
- Add the entry when its work ships. If the version number is not yet known, record it under `Unreleased` and move it into a numbered version when the version is tagged.
|
||||
- Add the entry when its work ships. If the version number is not yet known, record it under `Unreleased` as a staging entry; moving it into a numbered version is a version increment and is complete only when the `config/version` update and matching local release build have also been produced and verified (see "Commit, Build and Version Discipline").
|
||||
|
||||
When a full executable level-2 milestone/theme in `TODO.md` is implemented, completed, and moved to `DONE.md`:
|
||||
|
||||
@@ -198,13 +291,41 @@ For each task:
|
||||
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`.
|
||||
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 the changes to the version control system with a descriptive message.
|
||||
9. If a level-2 milestone from `TODO.md` has been fully completed, ensure its `CHANGELOG.md` entry is in place, then create a new version or tag in the version control system to mark the milestone.
|
||||
10. Push the committed changes to the shared repository if applicable.
|
||||
11. Note the new version or tag created in the version control system in any relevant documentation or handoff summary.
|
||||
8. Commit each coherent, verified change as it is completed. Do not wait until a whole
|
||||
milestone is finished; keep commits small and descriptive and push them when the branch is
|
||||
shareable.
|
||||
9. If the change is a release (a major, minor, or patch version increment), follow the Release
|
||||
Procedure in "Commit, Build and Version Discipline".
|
||||
10. Push committed changes to the shared repository if applicable.
|
||||
11. Note the new version, build artifacts or tag in the relevant documentation and handoff
|
||||
summary.
|
||||
|
||||
Avoid unrelated refactors unless they are required for the task or explicitly approved.
|
||||
|
||||
### 9. Commit, Build and Version Discipline
|
||||
|
||||
- **Commit often.** Make a commit after each coherent change or verified task, not only when a
|
||||
milestone or release is finished. Keep the working tree clean between tasks where possible.
|
||||
- **Push regularly.** Push shareable commits to the shared repository; do not accumulate a long
|
||||
local-only history.
|
||||
- **Build every version.** Every major, minor and patch increment follows the Release Procedure
|
||||
below; a changelog entry alone is not a release.
|
||||
- **CI is a second gate, not a substitute.** Tag builds remain automated, but the local build is
|
||||
the required pre-tag check for every version.
|
||||
- **Unversioned tracks stay unversioned.** A development track does not get a placeholder
|
||||
version; the version is assigned when the work is scoped into a release.
|
||||
|
||||
**Release Procedure** — follow these steps in order for every major, minor, or patch version
|
||||
increment:
|
||||
|
||||
1. Update `config/version`.
|
||||
2. Write the `CHANGELOG.md` entry for the version.
|
||||
3. Run the local release build (`tools/build_releases.sh`).
|
||||
4. Verify the build artifacts and checksums.
|
||||
5. Commit the changes.
|
||||
6. Tag the version.
|
||||
7. Push the commit and tag.
|
||||
|
||||
## Collaboration Rules
|
||||
|
||||
- Prefer clear, reversible changes over broad rewrites.
|
||||
@@ -213,6 +334,8 @@ Avoid unrelated refactors unless they are required for the task or explicitly ap
|
||||
- Do not claim a task is complete without verification.
|
||||
- Keep documentation synchronized with the implementation.
|
||||
- Mention files changed and checks run in handoff summaries.
|
||||
- Commit coherent increments as you go; do not wait until the end of a milestone.
|
||||
- Follow the Release Procedure in "Commit, Build and Version Discipline" whenever a major, minor or patch version is incremented.
|
||||
- Leave follow-up work as checkbox items in `TODO.md` rather than hiding it in prose.
|
||||
- If blocked, document the blocker in `MEMORY.md` and add a corresponding task to `TODO.md`.
|
||||
- Avoid overwriting another contributor’s work; inspect recent changes before editing shared files.
|
||||
@@ -224,6 +347,10 @@ Before handing off work, an agent must run every check below that applies to the
|
||||
- Run automated tests.
|
||||
- Run formatting, linting, or type checks.
|
||||
- Start the game or application and perform a basic smoke test.
|
||||
- For 3D/Blender changes: `blender_assets.py inspect`, `audit` and `fit`, the relevant capture
|
||||
gate, and a note of which local skills informed the change.
|
||||
- If the local Blender skills are not installed, state "no local skills used" in the handoff
|
||||
and list the skill-free checks that were run instead.
|
||||
- Check that documentation and task status reflect the actual state.
|
||||
- Review the final diff for accidental changes or unfinished markers.
|
||||
|
||||
|
||||
@@ -4,6 +4,20 @@ All notable user-facing changes to Gig Line. The format follows
|
||||
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and versions use
|
||||
Semantic Versioning.
|
||||
|
||||
## [0.9.7] — 2026-11-04
|
||||
|
||||
### Added
|
||||
|
||||
- Character development: a more realistic face on all eight library characters
|
||||
(higher head subdivision, brow ridge, both eyelids, fuller lower lip) and four
|
||||
crowd-variety characters (`npc_crowd_a`–`d`) with deterministic per-role pools
|
||||
so the routine crowd no longer clones a single look.
|
||||
|
||||
### Fixed
|
||||
|
||||
- The NPC pose harness now captures seated, walking and idle deformation (the
|
||||
harness froze the avatar's process so the FSM could no longer revert the pose).
|
||||
|
||||
## [0.10.0-rc.1] — 2026-11-03
|
||||
|
||||
### Changed
|
||||
|
||||
@@ -21,11 +21,51 @@ using Blender. The `.blend` working sources are developer artifacts and are not
|
||||
shipped. The exported `.glb` files and baked AO maps are project assets; they do
|
||||
not embed third-party models or purchased asset packs.
|
||||
|
||||
### Development-only research previews
|
||||
|
||||
Two review sheets under `docs/blender_previews/` compare source candidates for
|
||||
the future NPC variety work. They are development documentation and are not
|
||||
bundled with the game or its release packages. The underlying source models are
|
||||
kept outside version control.
|
||||
|
||||
- [`sheet_npc_sources_research.jpg`](docs/blender_previews/sheet_npc_sources_research.jpg)
|
||||
includes renders of **Quaternius Ultimate Modular Characters** (CC0 1.0,
|
||||
<https://quaternius.com/>), **Kenney Blocky Characters 2.0** (CC0 1.0,
|
||||
<https://kenney.nl/assets/blocky-characters>), and **CesiumMan** and
|
||||
**RiggedFigure** (CC BY 4.0, © 2017 Cesium,
|
||||
<https://github.com/KhronosGroup/glTF-Sample-Assets>).
|
||||
- [`sheet_npc_crowd_prototypes.jpg`](docs/blender_previews/sheet_npc_crowd_prototypes.jpg)
|
||||
contains renders of project-owned generator prototypes.
|
||||
|
||||
The CC-BY preview images are included only as development evidence. Any future
|
||||
shipped derivative of CesiumMan or RiggedFigure must keep the attribution above.
|
||||
|
||||
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
|
||||
Sunset Strip block; the game does not claim endorsement by, or an exact replica
|
||||
of, any real venue or tenant.
|
||||
|
||||
### Development-only reference images
|
||||
|
||||
The venue reference boards under `docs/screens/refs/` are development documentation and are not
|
||||
bundled with the game or its release packages. Files under CC BY are attributed here as well as in
|
||||
their folder sidecar:
|
||||
|
||||
- `docs/screens/refs/hollywood/el-capitan-facade-day-wikimedia-2009-10-27.jpg` — "woo (Irvine, CA,
|
||||
USA)", CC BY 2.0, via Wikimedia Commons.
|
||||
- `docs/screens/refs/hollywood/el-capitan-theatre-blade-sign-day-wikimedia-2008-10.jpg` — Andreas
|
||||
Praefcke, CC BY 3.0, via Wikimedia Commons.
|
||||
- `docs/screens/refs/hollywood/premiere-staging-street-day-wikimedia-2006-02-12.jpg` — John
|
||||
Barreiros, CC BY 2.0, via Wikimedia Commons.
|
||||
- Public-domain files in the same folder: Charles W. Beam (1922) and Gary Minnaert (2006).
|
||||
- `docs/screens/refs/hollywood/el-capitan-theatre-marquee-neighbour-day-wikimedia-2009-07-11.jpg` —
|
||||
Alan Light, CC BY 2.0, via Wikimedia Commons.
|
||||
- `docs/screens/refs/hollywood/hollywood-boulevard-night-context-ccbysa.jpg` — Downtowngal,
|
||||
CC BY-SA 3.0, via Wikimedia Commons; used unmodified for colour/lighting study only, no derivative
|
||||
asset is made from it.
|
||||
- CC0 files in the Hollywood folder need no attribution: Luijtenphotos (2019) and Benoît Prieur
|
||||
(2022).
|
||||
|
||||
## AI-assisted images
|
||||
|
||||
Surface textures, skyline panoramas, UI art and concept references were produced
|
||||
|
||||
@@ -1109,7 +1109,6 @@ Completed 2026-11-01. The follow-ups left over after the texture/skyline adoptio
|
||||
|
||||
Completed 2026-11-01.
|
||||
|
||||
|
||||
### Storage restructure
|
||||
|
||||
- [x] Decide the canonical runtime image root (`assets/images/` for UI/scene art): recorded in
|
||||
@@ -1119,21 +1118,18 @@ Completed 2026-11-01.
|
||||
- [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 `tools/screen_designs.py` docstrings and mark the old paths in `DONE.md` as historical.
|
||||
|
||||
|
||||
### Code path updates
|
||||
|
||||
- [x] Point `tools/screen_designs.py generate` at the new design output path and keep `compare`/`judge` reading the right locations.
|
||||
- [x] Update GDScript `preload()` paths if game textures move (no runtime material/model textures moved; UI art added under assets/images/).
|
||||
- [x] Update capture output directories if captures relocate (none did; QA captures stay in docs/screenshots/).
|
||||
|
||||
|
||||
### Load proposed interfaces + scene art from disk
|
||||
|
||||
- [x] Add a central UI/scene art loader (e.g. `src/game/ui/art.gd`) that loads the mockup-derived images from the new runtime root, with a procedural fallback when a file is missing.
|
||||
@@ -1144,19 +1140,16 @@ Completed 2026-11-01.
|
||||
- [x] Wire the wand popup to `wand_screening` art.
|
||||
- [x] Style the radial menu and finish the remaining HUD chrome against their reference images.
|
||||
|
||||
|
||||
### Verify against the mockups
|
||||
|
||||
- [x] Regenerate the staged captures and run `screen_designs.py compare` (11 good, 0 bad; verified in a clean HEAD worktree).
|
||||
- [x] Run `screen_designs.py judge` and clear every `diff` verdict (7 match, 4 review, 0 diff).
|
||||
- [x] Add the capture + compare step as a repeatable smoke so drift is caught early (`tools/check_screenshots.sh`).
|
||||
|
||||
|
||||
## Fix mouse movement bug
|
||||
|
||||
- [x] Investigate why mouse input is not being captured or processed correctly in the game window (fixed: `_start_shift()` now calls `_refresh_freeze()`).
|
||||
|
||||
|
||||
## Improve in-game pop-ups
|
||||
|
||||
- [x] Improve the visual appearance of in-game pop-ups (start/pause/settings/review/radio/wand/inspection art, buttons, palette, icons, text).
|
||||
@@ -1943,7 +1936,6 @@ Compatibility/Web parity, deterministic assets and offline CI.
|
||||
carry the texture results; the 0.9.5 section moved to `DONE.md` after the
|
||||
release build.)
|
||||
|
||||
|
||||
Completed 2026-11-02: all 0.9.5 texture and material checks are closed. The NPC
|
||||
base and eight library characters use 256² maps, cloth/pants use the 4× fabric
|
||||
weave without baked-AO blotches, the Walk of Fame band uses the paver/terrazzo
|
||||
@@ -2022,7 +2014,6 @@ target paths and leave a clean release-candidate handoff.
|
||||
- [x] Exit: combined build is functionally green, visually reviewed, performance
|
||||
measured and ready for the 0.10.0 content-lock/playtest phase.
|
||||
|
||||
|
||||
Completed 2026-11-03: the 0.9.6 integration checkpoint is closed. The current
|
||||
asset set re-imported and passed `blender_assets.py audit`/`fit` and
|
||||
`npc_pipeline.py audit`; the full suite is 263/263 with 101/101 Python tests and
|
||||
@@ -2033,3 +2024,122 @@ with a 0.291 Pillow gap. A clean worktree built Linux/Windows/macOS/Web/HQ at
|
||||
161.5/197.1/148.0/97.8/241.5 MB; the Web zip and HQ override were checked and
|
||||
the HQ binary launched headless. Tagged `v0.9.6`; Gitea run 1296 passed checks
|
||||
and the full build and published seven assets.
|
||||
|
||||
## Character development
|
||||
|
||||
Completed 2026-11-04. The procedural crowd-variety roster (four new variants, per-role pools)
|
||||
shipped with the realistic face; the external-asset intake and the MakeHuman body pipeline were
|
||||
promoted to the active **MakeHuman character pipeline** track in `TODO.md`.
|
||||
|
||||
## Character development
|
||||
|
||||
Goal: break the eight-character clone effect with four licence-cleared crowd-variety looks while
|
||||
keeping the frozen `npc_base` bone, tint-slot and gear-attach contract. The procedural generator is
|
||||
the primary path; Quaternius is a reviewed reference and MakeHuman is deferred to a separate local
|
||||
development pipeline.
|
||||
|
||||
The roster build is deliberately sequenced **after** the 3D model and local map re-evaluation: the new variants
|
||||
must inherit the reviewed face/hand/gear baseline instead of multiplying whatever it finds.
|
||||
|
||||
*Skill route: `character-artist`, `retopology`, `rigging`, `uv-workflow`, `materials`,
|
||||
`asset-optimization`, `lowpoly-style`, `godot-export`, `qa-review`.*
|
||||
|
||||
### Source review and decision
|
||||
|
||||
- [x] Research free/open-source character sources and evaluate at least three downloads against
|
||||
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`.)
|
||||
- [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
|
||||
primary path, keep Quaternius as a reviewed prototype/reference, defer MakeHuman to a
|
||||
separate local pipeline. Recorded in ADR-0015 and `MEMORY.md`.)
|
||||
- [x] Add a source licence allow-list and provenance rule: CC0 preferred, CC-BY only with
|
||||
attribution in `CREDITS.md`, and no service assets whose terms restrict redistribution.
|
||||
(ADR-0015; the CC-BY research previews are attributed in `CREDITS.md`.)
|
||||
- [x] Decide whether the external preview sheet stays local under `tmp/` or is committed with
|
||||
the required CC-BY attribution. (Committed as
|
||||
`docs/blender_previews/sheet_npc_sources_research.jpg` with Cesium CC-BY attribution;
|
||||
the project-owned crowd prototype sheet is also committed.)
|
||||
|
||||
### Intake and validation
|
||||
|
||||
- [x] Add a Blender `inspect` path that imports a GLB, applies node transforms, reports
|
||||
tris/verts, bounds, bones, materials, UVs and skinning, and lists contract failures.
|
||||
(`blender_assets.py inspect --file ...` applies parent/object transforms, converts to
|
||||
Godot Y-up, ignores the importer's bone-shape helper and prints budgets, bones, slots,
|
||||
UVs, skinning and animations with issues/warnings; `--json` and `--category` supported.
|
||||
Seven synthetic contract tests added; all 46 library GLBs inspect clean. `audit` remains
|
||||
the final gate.)
|
||||
- [x] `adapt` path: promoted to the **MakeHuman character pipeline** track (2026-11-04).: scale/ground, weld seams, decimate, map the
|
||||
five tint slots, and either rebuild the contract armature or record an explicit second-rig
|
||||
contract. Use `retopology`/`rigging`/`uv-workflow` guidance for the manual steps, but keep
|
||||
the Quaternius no-go: a contract rebuild needs a proportion warp, so this is not on the
|
||||
character critical path.
|
||||
- [x] Audit gate + intake regression test: promoted to the **MakeHuman character pipeline** track.
|
||||
- [x] Adapter documentation: promoted to the **MakeHuman character pipeline** track.
|
||||
|
||||
### Quaternius prototype
|
||||
|
||||
- [x] Prototype one Quaternius CC0 variant: weld/decimate to budget and capture Idle/Walk
|
||||
renders. (12,518 imported verts -> 3,199 after weld -> 2,423 / 4,654 tris after a 0.75
|
||||
decimate; Idle/Walk quality is good. Preview in
|
||||
`docs/blender_previews/sheet_npc_sources_research.jpg`.)
|
||||
- [x] Measure the prototype against the `npc_casual` controls: silhouette, rest pose, body
|
||||
proportions and gear fit. (No-go for a contract rebuild: T-pose 62-bone realistic rig,
|
||||
~0.96 m hip, ~1.68 m arm span and ~0.153 m shoulder joint do not match the arm-down
|
||||
13-bone contract. Keep as reference; a second rig/animation path needs its own ADR.)
|
||||
- [x] Make a go/no-go decision on Option B. (No-go for the current pass; proceed with the procedural
|
||||
generator and keep Quaternius as a visual/style reference.)
|
||||
|
||||
### Roster and runtime
|
||||
|
||||
- [x] Approve four crowd-variety looks (build, head silhouette, hair/beard, outer layer and
|
||||
accessory; no clothing that labels the NPC's behaviour). (`npc_crowd_a` bun/slim/sunglasses,
|
||||
`npc_crowd_b` bald/broad/beard/shoulder bag, `npc_crowd_c` coat/umbrella, `npc_crowd_d`
|
||||
hood/cup; prototype sheet committed.)
|
||||
- [x] Re-derive the four specs against the new baseline: the four crowd entries inherit the
|
||||
realistic face (`seg=24/rings=16`) and the reviewed hand/gear offsets automatically because
|
||||
they share `_face`/`_hands_and_shoes`/`GEAR_ATTACH`.
|
||||
- [x] Generate the four variants: built via `blender_assets.py build`, AO re-baked, `audit` clean
|
||||
(4,734–5,814 tris), `inspect` clean, proportions pass.
|
||||
- [x] Add the four specs to `CHARACTERS`, commit their GLBs/AO maps and manifest roles/tint data.
|
||||
(Note: this adds ~2 MB to the next release build via `export_filter=all_resources` — accepted
|
||||
for the crowd-variety roster.)
|
||||
- [x] Per-role pools: `character_model_for()` now picks from `CHARACTER_POOLS` by seed — the
|
||||
routine crowd roles gain the crowd variants (tourist → casual/crowd_a/crowd_d,
|
||||
confused_visitor → casual/crowd_b, intoxicated → casual/crowd_c) while the special roles
|
||||
keep their existing alternation (guest ⅓ jacket, trespasser/threat ½ hoodie). The test
|
||||
now checks seed-stability plus that every pool entry resolves to a committed GLB
|
||||
(277/277).
|
||||
- [x] Gear fit + inspect for the four new variants: `fit` is clean (sunglasses band=inside,
|
||||
shoulder bag clear; cup/umbrella are hand gear with the forward offset), `inspect` clean,
|
||||
proportions pass.
|
||||
- [x] Crowd-variety reference: five licence-cleared Commons photos fetched to
|
||||
`tmp/research/crowd-variety/`; the AI proposal set stays the next step for detail.
|
||||
- [x] Baseline + portrait rows: the four variants are in `capture_npc_baseline.gd` and
|
||||
`sheet_npc_baseline.jpg` (12 variants × 6 views); review-doc rows added.
|
||||
|
||||
### QA and release
|
||||
|
||||
- [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;
|
||||
`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.
|
||||
- [x] Exit: the 12-character library passes contract audit, portrait/gear acceptance, the 24-NPC
|
||||
budget and licence/provenance review; the runtime contract (13 bones, five tint slots,
|
||||
`npc_base` fallback) is unchanged.
|
||||
|
||||
### Deferred MakeHuman local pipeline
|
||||
|
||||
- [x] Evaluate the MakeHuman CC0 base mesh for a later separate local development pipeline.
|
||||
(19,158 verts / 36,972 tris; scaled to 1.82 m; decimate 0.35 -> 3,780 verts / 6,468 tris;
|
||||
UVs present, no normals/material groups/rig. Feasible only with retopology, a custom rig and
|
||||
project-owned clothing; keep out of CI/build.)
|
||||
- [x] Body-shape diversity decision (2026-11-04, owner): **yes** — use MakeHuman for the next
|
||||
character pass. Promoted to the **MakeHuman character pipeline** track.
|
||||
@@ -14,6 +14,23 @@ The game is about **judgment, communication, access verification, and proportion
|
||||
- **Emergency help is a last resort.** Responders handle crises the guard cannot safely manage; calling them has costs.
|
||||
- **Readability beats raw fidelity.** The GL Compatibility renderer, clear silhouettes, the focus ring, and the HUD stay legible.
|
||||
|
||||
## Development Priorities
|
||||
|
||||
The active planning order is set in [`TODO.md`](TODO.md) and in `AGENTS.md`:
|
||||
|
||||
1. **Character development (unversioned).** Expand the owned procedural character library with
|
||||
crowd, age, build, hair and outfit variety. Keep the frozen bone/tint/gear contract; see
|
||||
[ADR-0015](docs/adr/0015-npc-model-variety-sourcing.md) and
|
||||
[`docs/npc-model-sourcing.md`](docs/npc-model-sourcing.md). Quaternius is a reference;
|
||||
MakeHuman is deferred to a separate local pipeline.
|
||||
2. **Local map development (unversioned).** Move beyond stylized venue reconstruction with
|
||||
licensed OpenStreetMap and 3D building data, downloaded reference imagery for photoreal
|
||||
facades, AI-assisted composition, and a Gaussian-splatting evaluation that stays in the
|
||||
development pipeline unless it proves runtime-safe.
|
||||
3. **Versioned release hardening.** The 0.10.0 release candidate and later semantic versions come
|
||||
after the unversioned development tracks in planning order. Versions are assigned only when a
|
||||
track's scope is accepted into a release.
|
||||
|
||||
## Core Gameplay Loop
|
||||
|
||||
1. Watch the entrance, steps, queue, and sidewalk.
|
||||
@@ -127,7 +144,7 @@ Joke Shop escalation follows the common ladder: direction, explanation, repeat r
|
||||
|
||||
### Hollywood Boulevard Late Night TV Studio
|
||||
|
||||
A busy studio entrance with audience members, production staff, performers, guests, deliveries, celebrity arrivals, tourists, influencers, and the same range of street behavior as the building scenario.
|
||||
A busy studio entrance at the same real El Capitan Entertainment Centre block as the Hollywood day shift, restaged for a late-night arrival: the same stone facade and steps with a bulb-lit canopy, a black car at the kerb and a barrier line. It has audience members, production staff, performers, guests, deliveries, celebrity arrivals, tourists, influencers, and the same range of street behavior as the building scenario.
|
||||
|
||||
Staff and guests are recognized or present a wristband, credential, ticket, guest-list confirmation, or other approved marker. The player keeps the steps clear, protects arrivals and equipment, manages filming boundaries, watches for tailgating, and calls for help only when there is immediate danger.
|
||||
|
||||
@@ -152,14 +169,15 @@ The action wheel prioritizes de-escalation: Stop, Look, Point, No, Ask, Inspect,
|
||||
|
||||
The visual direction is readable stylized realism:
|
||||
|
||||
- **Blender library:** 8 skinned NPC variants, 18 gear pieces, and 20 street/venue props, with baked albedo/normal/AO/ORM maps, a manifest, and procedural fallbacks. `Rig/Head` stays the focus anchor.
|
||||
- **Realism pass:** AI-assisted per-phase skyline panoramas, v2 surface tiles with normal maps, wet asphalt at night, a warm day haze, phase-specific sun/exposure/fog, a visible flashlight beam, and denser foliage.
|
||||
- **Character direction:** 8 skinned NPC variants, 18 gear pieces and 20 street/venue props, with four crowd-variety variants prototyped. The generator-first expansion is the active character track ([ADR-0015](docs/adr/0015-npc-model-variety-sourcing.md)); Quaternius is a reference and MakeHuman is deferred to a local pipeline.
|
||||
- **Realism pass:** AI-assisted per-phase skyline panoramas, v2 surface tiles with normal maps, wet asphalt at night, a warm day haze, phase-specific sun/exposure/fog, a tight flashlight spot (no beam geometry), and denser foliage.
|
||||
- **Local map direction:** the venues are currently stylized reconstructions. The local-map track evaluates licensed OpenStreetMap/3D building data, licensed reference photography, AI-assisted composition and Gaussian splatting as a development tool; online data and splat rendering are not runtime dependencies.
|
||||
- **References and QA:** runtime UI art lives in `assets/images/ui/`; reference/art-direction sets live in `docs/screens/designs/` and `docs/screens/concepts/`; captures live in `docs/screenshots/`; realism runs live in `docs/screens/realism/`. `screen_designs.py compare/judge` and `tools/check_screenshots.sh` guard drift.
|
||||
- **Storage convention:** see [ADR-0014](docs/adr/0014-runtime-image-root.md). Never overwrite an existing image; new outputs get a new path or `-vN` suffix.
|
||||
|
||||
The path from the current vertical slice to the 0.10.0 release candidate — content depth, onboarding, accessibility, platform QA and release readiness — is tracked in [`TODO.md`](TODO.md); this plan stays at the product/design level.
|
||||
The active planning order — unversioned character and local-map development first, then the versioned 0.10.0 release-candidate hardening and later releases — is tracked in [`TODO.md`](TODO.md); this plan stays at the product/design level.
|
||||
|
||||
Primary decisions: [ADR-0007](docs/adr/0007-locomotion-and-input-layers.md), [ADR-0008](docs/adr/0008-cone-focus-and-head-ring.md), [ADR-0009](docs/adr/0009-radial-action-menu.md), [ADR-0010](docs/adr/0010-procedural-npc-presentation.md), [ADR-0011](docs/adr/0011-aim-free-selection-and-precision-walk.md), [ADR-0012](docs/adr/0012-surface-materials-and-generated-props.md), [ADR-0013](docs/adr/0013-blender-authored-npc-characters.md).
|
||||
Primary decisions: [ADR-0007](docs/adr/0007-locomotion-and-input-layers.md), [ADR-0008](docs/adr/0008-cone-focus-and-head-ring.md), [ADR-0009](docs/adr/0009-radial-action-menu.md), [ADR-0010](docs/adr/0010-procedural-npc-presentation.md), [ADR-0011](docs/adr/0011-aim-free-selection-and-precision-walk.md), [ADR-0012](docs/adr/0012-surface-materials-and-generated-props.md), [ADR-0013](docs/adr/0013-blender-authored-npc-characters.md), [ADR-0015](docs/adr/0015-npc-model-variety-sourcing.md).
|
||||
|
||||
## Tech Stack
|
||||
|
||||
@@ -176,7 +194,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.10.0-rc.1`). 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/). 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.10.0-rc.1`). 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.
|
||||
|
||||
## Design Direction
|
||||
|
||||
|
||||
@@ -6,20 +6,15 @@ The central design goal is simple:
|
||||
|
||||
> The player wins by choosing the lowest level of escalation that keeps everyone safe.
|
||||
|
||||
## Screenshots
|
||||
## Development Priorities
|
||||
|
||||
| | |
|
||||
| --- | --- |
|
||||
|  |  |
|
||||
|  |  |
|
||||
|  |  |
|
||||
|  |  |
|
||||
|  |  |
|
||||
|  |  |
|
||||
|  | |
|
||||
The active planning order lives in [`TODO.md`](TODO.md) and [`AGENTS.md`](AGENTS.md):
|
||||
|
||||
*Screenshots are generated by [`src/test/capture_screenshots.gd`](src/test/capture_screenshots.gd) and [`src/test/capture_prop_gallery.gd`](src/test/capture_prop_gallery.gd) from the current build — day, late-night, wand screening, escalation, shift-review timeline,
|
||||
precision walk, the Joke Shop's Sunset Strip frontage, the TV Studio arrival, and the prop lineup.*
|
||||
1. **3D model and local map re-evaluation** — score every shipped asset, then evaluate licensed OpenStreetMap/3D data, reference-derived photoreal facades, AI-assisted composition and a Gaussian-splatting development evaluation.
|
||||
2. **Character development** — crowd, age, build, hair and outfit variety on the owned procedural library, keeping the frozen NPC contract. Source evaluation and the licence decision are in [`docs/npc-model-sourcing.md`](docs/npc-model-sourcing.md).
|
||||
3. **Versioned release hardening** — the 0.10.0 release candidate and later semantic versions follow the unversioned development tracks.
|
||||
|
||||
Versions are assigned only when a track's scope is accepted into a release. Every major, minor and patch version requires a changelog entry, a local release build and artifact verification before tagging.
|
||||
|
||||
## ⬇️ Downloads
|
||||
|
||||
@@ -60,6 +55,59 @@ If you are here to develop or test locally instead of downloading, jump to
|
||||
|
||||
The project is under active development. The design and architecture are documented, and a playable prototype vertical slice exists (Godot 4 + GDScript): a stylized El Capitan Entertainment Centre block, a first-person guard, simulated NPCs with intents and reactions, the six-level escalation model, access inspection and admission decisions, radio calls with credibility checks, reputation, crowd mood, and an end-of-shift review.
|
||||
|
||||
## Screenshots
|
||||
|
||||
Every capture is rendered from the current build by [`tools/check_screenshots.sh`](tools/check_screenshots.sh)
|
||||
(21 captures, compared against the runtime art). The full gallery, including every UI state, is in
|
||||
[`docs/screenshots/`](docs/screenshots/README.md).
|
||||
|
||||
### Venues
|
||||
|
||||
| | |
|
||||
| --- | --- |
|
||||
|  | **Hollywood Boulevard — day.** The El Capitan Entertainment Centre block: six Ionic columns, Masonic parapet, event banners, eight stone steps and the Walk of Fame terrazzo. |
|
||||
|  | **Hollywood Boulevard — late.** Sconces pool on the limestone, street lamps light the boulevard and the skyline fades into night haze. |
|
||||
|  | **Night patrol.** A tight flashlight spot picks out the door and the person in front of it; movement and awareness change at night. |
|
||||
|  | **The Joke Shop.** A black Sunset Strip club under its signature-covered canopy, circular blade sign, red curtains and the dry hillside behind. |
|
||||
|  | **TV Studio arrival.** Stone facade, bulb canopy, black car and crowd barriers for a late celebrity arrival. |
|
||||
|
||||
### Interaction and systems
|
||||
|
||||
| | |
|
||||
| --- | --- |
|
||||
|  | **Focus and targeting.** The cone focus ring, name tag and target chip; `Tab`/wheel cycles nearby people without aiming. |
|
||||
|  | **Access inspection.** A venue-correct wristband check with evidence shown before the admit/refuse decision. |
|
||||
|  | **Radio report.** Security assistance with location, behaviour and what was actually seen. |
|
||||
|  | **Wand screening.** A false alarm on keys: ask the guest to identify the item before choosing a response. |
|
||||
|  | **Escalation.** Level 3 blocking with the shape meter, body camera armed and the reaction log. |
|
||||
|  | **Body-camera timeline.** Every recorded event, step by step, in the shift review. |
|
||||
|  | **Precision walk.** Half-speed close work on the steps, with the HUD state chip visible. |
|
||||
|
||||
### Shell and UI
|
||||
|
||||
| | |
|
||||
| --- | --- |
|
||||
|  | **Venue menu.** Day and night rows for Hollywood, the Joke Shop and the TV Studio, campaign continue and review links. |
|
||||
|  | **Settings.** Difficulty, volumes, HUD scale, reduce motion, captions and key/button remapping, all persisted. |
|
||||
|  | **Shift review.** Grade, policy outcome, incidents, responder results and campaign Continue. |
|
||||
|  | **Action wheel.** De-escalation first: stop, look, point, no, ask, inspect, warn, block, reason, recognize, radio. |
|
||||
|
||||
### 3D asset progress
|
||||
|
||||
The character, gear and prop libraries are authored procedurally in Blender and audited before use;
|
||||
the sheets below track their visual progress.
|
||||
|
||||
| | |
|
||||
| --- | --- |
|
||||
|  | **Character library.** Eight skinned variants (4.5–5.5k triangles each) with five tint slots, attach-point gear and baked maps. |
|
||||
|  | **Street and venue props.** Twenty library props with colliders, navigation avoidance and colour atlases. |
|
||||
|  | **Neutral baseline.** 8 characters × 6 views (front, three-quarter, profile, back, full body, crowd) used for the 0.9.4 pass and the current re-evaluation. |
|
||||
|  | **Texture refinement.** 128 → 256 px NPC maps and a 4× fabric weave, shown before/after on the same camera. |
|
||||
|  | **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).
|
||||
|
||||
## Game Overview
|
||||
|
||||
A typical shift lasts 10–15 minutes: watch the entrance and sidewalk, judge why
|
||||
@@ -107,18 +155,23 @@ Full setup, every run/test/smoke command, and the controls table are in
|
||||
|
||||
## Project Documentation
|
||||
|
||||
- [`PLAN.md`](PLAN.md) — Game design plan and scenario details.
|
||||
- [`AGENTS.md`](AGENTS.md) — Development and collaboration workflow.
|
||||
- [`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.
|
||||
- [`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/README.md`](docs/README.md) — Documentation index and visual previews.
|
||||
- [`docs/architecture.md`](docs/architecture.md) — arc42-style architecture documentation.
|
||||
- [`docs/gameplay.md`](docs/gameplay.md) — Gameplay systems, venues, and the escalation model.
|
||||
- [`docs/hollywood-boulevard-map.md`](docs/hollywood-boulevard-map.md) — Real-site references, game mapping and limitations for the Hollywood venue.
|
||||
- [`docs/joke-shop-map.md`](docs/joke-shop-map.md) — Real-site references, game mapping and limitations for the Joke Shop / Sunset Strip venue.
|
||||
- [`docs/tutorial.md`](docs/tutorial.md) — First-shift tutorial beats and rules.
|
||||
- [`docs/asset-tooling.md`](docs/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.
|
||||
@@ -130,7 +183,6 @@ Full setup, every run/test/smoke command, and the controls table are in
|
||||
- [`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/npc-proportion-audit.md`](docs/npc-proportion-audit.md) — NPC proportion measurements against the shared stylized guide.
|
||||
- [`docs/adr/`](docs/adr/) — Architecture Decision Records.
|
||||
- [`TODO.md`](TODO.md) — Active tasks plus the 0.x gap analysis and milestone roadmap.
|
||||
|
||||
## Development Status
|
||||
|
||||
@@ -141,9 +193,12 @@ Walk of Fame/awning surfaces and per-phase skyline haze), on top of the v0.9.4
|
||||
NPC visual optimization and the v0.9.3 UI/accessibility polish pass. It builds on
|
||||
v0.9.2's Hollywood/Joke Shop map rebuilds, v0.9.1's Godot 4.7.2 baseline,
|
||||
v0.9.0's production-quality pass, v0.8's
|
||||
tutorial/campaign/resume work and the v0.7.x venue/gear/judge work. See [`docs/development-status.md`](docs/development-status.md)
|
||||
for the implemented list and [`TODO.md`](TODO.md) for the 0.x roadmap. Manual
|
||||
verification uses the [`docs/smoke-checklist.md`](docs/smoke-checklist.md).
|
||||
tutorial/campaign/resume work and the v0.7.x venue/gear/judge work. The active
|
||||
planning priorities are the unversioned character and local-map development tracks;
|
||||
the 0.10.0 release candidate is the next versioned release. See
|
||||
[`docs/development-status.md`](docs/development-status.md) for the implemented list
|
||||
and [`TODO.md`](TODO.md) for the priority-ordered roadmap. Manual verification uses
|
||||
the [`docs/smoke-checklist.md`](docs/smoke-checklist.md).
|
||||
|
||||
## Credits, Privacy and Accessibility
|
||||
|
||||
|
||||
@@ -3,58 +3,724 @@
|
||||
Work is grouped by theme. Each item should be small enough to complete and verify on its own;
|
||||
see `AGENTS.md` for the workflow and `MEMORY.md` for the decisions behind these plans.
|
||||
|
||||
**Priority order (2026-11-04, owner):** 1) release the finished procedural character development
|
||||
as the **0.9.7 patch**, 2) finish the MakeHuman character + the 3D model and map improvements,
|
||||
3) re-evaluate the 3D models, 4) ship all of it together in the **0.10.0 minor**. See `AGENTS.md`
|
||||
§Priority and Versioning and §Local Blender skills.
|
||||
|
||||
The MIT Blender skill pack lives locally at `.agents/skills/blender-skills/` (gitignored). Every
|
||||
3D workstream below names the skills to load; they are guidance only, and the project contract,
|
||||
`blender_assets.py audit`/`fit`/`inspect` and the capture gates stay authoritative.
|
||||
|
||||
## Fix the Rig pose harness
|
||||
|
||||
Goal: `src/test/capture_npc_pose.gd` reports a pose but saves rest frames; the root cause is
|
||||
narrowed to the skinned mesh ignoring its `Rig` parent transform. Fixing it unblocks the
|
||||
weights/pose column of the 3D review and the pose/portrait evidence for the MakeHuman intake.
|
||||
|
||||
*Skill route: `rigging`; evidence in `docs/3d-model-review.md` §"Pose evidence is blocked".*
|
||||
|
||||
- [x] Root cause found (2026-11-04): the harness never disabled the avatar's `_physics_process`,
|
||||
so `_advance_fsm` + `_move_toward_target` ran every tick and reset `arrived`/velocity, which
|
||||
made `theater_pose()` return "idle" and reverted the pose to rest. (The earlier "moving the
|
||||
`Rig` child does not render" probe was a red herring: it set `rig.position.y` inside `_shoot()`
|
||||
in the same frame as `root.get_texture().get_image()`, so it never got a rendered frame.)
|
||||
- [x] Harness rebuilt: `capture_npc_pose.gd` now calls `set_physics_process(false)`/
|
||||
`set_process(false)` after staging the avatar; the pose survives because only the direct
|
||||
`_animate()` ticks drive it. Verified: sit vs idle diff 5.63, walk vs idle diff 2.29, and the
|
||||
vision judge confirms the seated frame reads as crouched.
|
||||
- [x] Captured all poses for all 12 variants (idle / walk_contact / walk_pass / sit × full +
|
||||
shoulder views = 96 frames) and built `sheet_pose.jpg`/`sheet_shoulder.jpg` under `tmp/`.
|
||||
(No separate "wave" theater pose exists; the escalation raise-hand gesture is not a distinct
|
||||
capture in this harness.)
|
||||
|
||||
## MakeHuman character pipeline
|
||||
|
||||
Goal: replace the procedural body generator with the CC0 MakeHuman base for the next character
|
||||
pass — retopologised, rigged and dressed in project-owned clothing — so bodies read more
|
||||
realistic than the current primitive shapes. This promotes the deferred MakeHuman evaluation to
|
||||
an active track; ADR-0015 (CC0 / CC-BY with attribution) still governs every intake.
|
||||
|
||||
*Skill route: `retopology`, `rigging`, `uv-workflow`, `materials`, `character-artist`,
|
||||
`asset-optimization`, `godot-export`, `qa-review`.*
|
||||
|
||||
### Intake and adaptation
|
||||
|
||||
- [x] `adapt` path added to `tools/blender_assets.py` (`adapt --file <in> --out <out>
|
||||
[--target-tris 8000]`): imports the GLB, applies transforms, grounds the feet, welds seam
|
||||
splits and decimates to the budget, then exports. The five tint slots + 13-bone rig stay a
|
||||
manual step (recorded in the command doc).
|
||||
- [x] `audit` stays the final gate; `test_adapt_requires_blender` covers the non-Blender error
|
||||
path (161/161 Python).
|
||||
- [x] Adapter commands + go/no-go documented in `docs/asset-tooling.md` §Intake adaptation.
|
||||
|
||||
### MPFB / MakeHuman body pipeline
|
||||
|
||||
- [x] Prototype the local pipeline: `tmp/npc-research/makehuman_intake.py` imports the CC0
|
||||
`base.obj`, scales to 1.82 m, grounds the feet, triangulates, decimates and exports
|
||||
`tmp/npc-research/makehuman/makehuman_body.glb` — 3,790 verts / 6,444 tris, bounds
|
||||
x ±0.53 / y 0–1.82 / z −0.12…+0.35, one neutral material, UVs present, unskinned. The
|
||||
body (no rig) is the input for the rigging step; the script + mesh stay in `tmp/` (CC0, not
|
||||
committed).
|
||||
- [x] Rig strategy decided (owner): **retarget the body to the 13-bone contract**.
|
||||
`tmp/npc-research/makehuman_retarget.py` rotates the A-pose arms down (−38°/+38°), scales the
|
||||
arms 1.63× to the contract 0.70 m length, welds the split vertices, smooth-shades, adds the
|
||||
contract armature + `_auto_weights`, paints the five slot regions (hair/cloth/pants/accessory/
|
||||
skin) and exports `makehuman_retargeted.glb`. **Contract passes:** 6,444 / 8,000 tris,
|
||||
7,726 / 8,000 verts, 14 bones (13 + Hips), skinned, arm-down, grounded, five slots, no issues.
|
||||
Vision-reviewed: arms hang down and the silhouette + slot regions read, but the 1.63× arm warp
|
||||
distorts the deltoid/shoulder (spiky/warped), the decimated hands are blocky, and the slot
|
||||
boundaries are rough — these are the refinement steps below.
|
||||
- [ ] Re-run `inspect`/`audit`/`fit`/proportions and the 24-NPC budget after each intake; keep the
|
||||
procedural generator as the fallback until a MakeHuman variant ships.
|
||||
|
||||
## 3D model and local map re-evaluation
|
||||
|
||||
Goal: re-judge every shipped 3D asset against the newly available Blender skill guidance, rank
|
||||
the real gaps, and fix only what the rankings justify (sections A–G); and re-evaluate the three
|
||||
venues against licensed real-world data — OSM footprints and building massing, reference-derived
|
||||
photoreal facades and the photo-driven geometry pipeline (sections H–M). Evidence comes from three
|
||||
separate sources: licensed real-location photos, generated concept boards, and build captures. This
|
||||
is an unversioned development track: it must not change the `npc_base` contract, the renderer or
|
||||
the 0.10.0 release candidate.
|
||||
|
||||
**Sequencing (2026-11-03, owner):** the asset-review fixes (A–G, notably the character P0/P1
|
||||
rebuilds and the face/foliage prototypes) stay **blocked** until the full local map rebuild
|
||||
(H–M) is done **and** a fresh 3D model review runs against the new maps. The measurements and
|
||||
scorecard in `docs/3d-model-review.md` stand as the pre-rebuild baseline, not a go-ahead to start
|
||||
character work now. (Character development has since shipped — see `DONE.md` — and the next
|
||||
character pass is the MakeHuman pipeline above.)
|
||||
|
||||
**Map rebuild status (2026-11-03):** H–M are complete — the Joke Shop is now a 6.0 m low hall
|
||||
(dark stucco, white signature fascia, tied-back curtains, hotel tower) and Hollywood/TV Studio
|
||||
share the limestone-ashlar Masonic facade. A fresh `capture_npc_review.gd` run produced 96/96
|
||||
frames against the new maps (none blank) and a vision spot-check confirms the characters still
|
||||
read cleanly. The remaining §L signage-texture candidates and the deferred 3D facade-reveal depth
|
||||
are enhancements, not rebuild blockers.
|
||||
|
||||
Reference material is collected first (section A): local, gitignored, development-only photo
|
||||
research may use any source the owner authorises (DuckDuckGo image search, street-view frames,
|
||||
neighbouring properties, buildings across the street) **without the licence gate**. The licence
|
||||
and privacy gates still apply the moment a frame is promoted into `docs/screens/refs/` or any
|
||||
committed asset — local `tmp/research/` is the only licence-free zone.
|
||||
|
||||
Scope: the shipped 3D catalogue — 8 library characters, the frozen `npc_base` fallback, 18 gear
|
||||
pieces, 20 library props, 6 generated props and the three venue families — plus the local map
|
||||
pipeline that re-evaluates those venues (OSM data/licensing, reference imagery, the photoreal
|
||||
facade kit, AI-assisted composing, Gaussian-splatting evaluation and map QA).
|
||||
|
||||
**Exit (asset review, A–G):** `docs/3d-model-review.md` scores every catalogue asset; every P0/P1
|
||||
is fixed or explicitly accepted with a measurement; `inspect`/`audit`/`fit`/proportions, the
|
||||
24-NPC budget and the capture gates are green; no runtime contract, dependency or release artifact
|
||||
changed except the rebuilt assets themselves.
|
||||
|
||||
**Exit (local map, H–M):** one local block is reconstructed from licensed data with
|
||||
reference-derived photoreal facades, passes performance/navigation/visual QA and has complete
|
||||
provenance; or the pipeline is rejected with the findings recorded.
|
||||
|
||||
### A. Local reference material collection (development-only, gitignored)
|
||||
|
||||
*Owner override (2026-11-03):* for local, development-only photo research the licence gate does
|
||||
**not** apply. Anything downloaded for this track stays under `tmp/research/` (gitignored) and is
|
||||
never committed, shipped, or used as a committed asset. The moment a frame is promoted to
|
||||
`docs/screens/refs/<venue>/` it must pass the sidecar licence + privacy gate; local research is the
|
||||
licence-free zone only.
|
||||
|
||||
- [x] Add a DuckDuckGo image-search fetcher: `tools/refcollect.py search <query> --slug <block>
|
||||
--limit N` downloads top results into `tmp/research/<block>/` with a source-URL manifest
|
||||
(no licence filter, marked `local_only`/`unchecked-local`), and `sheet` composes a local
|
||||
contact sheet. Requests go through a token bucket plus polite jittered backoff that honours
|
||||
`Retry-After`, and send a full Firefox header set. Tests in
|
||||
`tools/test_refcollect.py`. **Run note:** DDG rate-limits aggressively; space batches and
|
||||
run the per-venue collection below when the limit clears.
|
||||
- [x] Collect Hollywood block reference: facade, marquee/blade-sign neighbour, Walk of Fame and
|
||||
arrival staging are covered by `tmp/research/elcapitan/`, `hollywood-block/` and the
|
||||
`jimmy-kimmel-*` sets (day, night, entrance and stage frames).
|
||||
- [x] Collect Joke Shop / Comedy Store block reference: `tmp/research/comedy-store/` covers the
|
||||
facade, canopy, street and visitor views; `ramada-hotel/` adds the neighbouring hotel and
|
||||
`comedy-store-hillside/` the hillside/houses behind the roofline.
|
||||
- [-] Collect street-view frames of both blocks: street-level DDG frames now cover the facades,
|
||||
corners and opposite frontages for both blocks; true Google Street View panorama capture is
|
||||
deferred (needs a Google API key or a manual browser capture — recorded in MEMORY).
|
||||
- [x] Build a local contact sheet per block: `sheet.jpg` exists for every collected set
|
||||
(`elcapitan`, `hollywood-block`, `jimmy-kimmel-stage`, `jimmy-kimmel-entrance`,
|
||||
`comedy-store`).
|
||||
- [x] Record which local frames changed a decision: added the frame→decision mapping to
|
||||
`docs/hollywood-boulevard-map.md` (recent `elcapitan-2026` geosearch → 2009 frame stays the
|
||||
geometry reference; `jimmy-kimmel-entrance/07.jpg` → the four entrance concepts) and
|
||||
`docs/joke-shop-map.md` (`comedy-store/` → the four concept pairs + map plan;
|
||||
`comedy-store-hillside/` → the day-concept anchor that clears the image-recitation filter).
|
||||
Frames stay gitignored; only the provenance notes are committed.
|
||||
|
||||
### B. Baseline, scorecard and routing
|
||||
|
||||
- [x] Load `blender-director` plus the per-family specialists before touching geometry, and
|
||||
record the skill stack and the advice that changed a decision in `docs/3d-model-review.md`.
|
||||
(Routing, QA severity/verdict, texel-density tiers, character loop criteria and budget rules
|
||||
recorded in the review doc; MCP-only steps translated to headless flatpak runs.)
|
||||
- [x] Re-run the neutral NPC baseline (48 frames), the final-context review (96 frames), the
|
||||
prop gallery and the 24-NPC budget on the current build; keep raw frames in `tmp/` and do
|
||||
not replace committed sheets until a fix lands. (48/48 and 96/96 frames captured under
|
||||
`xvfb-run`, none blank; raw sets in `tmp/model-baseline` and `tmp/model-review`; committed
|
||||
sheets untouched. 24-NPC smoke still 6.94 ms / 168 meshes / 131,616 triangles.)
|
||||
- [x] Create `docs/3d-model-review.md` with a per-asset scorecard: silhouette, anatomy/proportion,
|
||||
topology/edge flow, UV/texel density, textures/materials, rig/weights, LOD/impostor,
|
||||
collision/grounding, export contract, provenance, skill route, verdict (P0/P1/P2/accept).
|
||||
(Doc created with character/gear/prop/venue tables, verdict columns and a ranked candidate
|
||||
list; unmeasured cells are marked `—` instead of being guessed.)
|
||||
- [x] Collect the baseline measurements in one table: `blender_assets.py inspect`, `audit`, `fit`,
|
||||
`npc_proportions.py`, texel density, triangles/meshes, 24-NPC frame time. (All seven captured;
|
||||
`texels` and `inspect --json --out` were added to make the measurements repeatable. All 46
|
||||
assets audit/inspect clean; texel density 64–122 px/m authored, 287–440 effective fabric.)
|
||||
- [ ] Review the scorecard with the project owner, rank the P0/P1 gaps and decide fix vs accept
|
||||
per item; record the decision and the reason in the review document. **Deferred until the
|
||||
full map rebuild (H–M) lands and a fresh 3D review runs against the new maps.**
|
||||
|
||||
### C. Character re-evaluation (8 variants + fallback)
|
||||
|
||||
*Skill route: `character-artist`, `retopology`, `rigging`, `uv-workflow`, `texture-workflow`,
|
||||
`materials`, `hair-groom`, `asset-optimization`, `lookdev`, `qa-review`.*
|
||||
|
||||
- [x] Face/head review: the eight library characters ARE built with the 0.9.4 face detail in
|
||||
`tools/blender_assets.py._face()` — sculpted chin plate + cheekbones (`_shape_head_mesh`),
|
||||
socketed sclera + thin upper lid, nose bridge/tip/wings, rounded mouth and ear concha. The
|
||||
plain sphere head in `tools/npc_pipeline.py` is the frozen `npc_base` fallback only. The
|
||||
ranked P1 "flat faceted cheek/brow + slit eyes" is therefore a readability/scale question on
|
||||
the existing sculpt (head `seg=18/rings=12`, small offsets), not missing geometry. Next step
|
||||
if the owner funds it: a single-variant `npc_casual` prototype that raises head subdivision
|
||||
and deepens the cheek/brow offsets. Fix is gated on the owner scorecard review.
|
||||
- [x] Hands/grip review: the hands ARE detailed — `tools/blender_assets.py._hands_and_shoes()`
|
||||
builds a wider shallower palm, four two-segment bent fingers with rounded tips and a thumb;
|
||||
gear contact is the open palm plus the `HAND_ITEM_FORWARD` (0.04 m) offset. Decision: **keep
|
||||
the open palm + forward offset; a finger-curl rig stays out of scope** — there are no finger
|
||||
bones in the 13-bone contract, so a curl rig is a contract decision, not a modelling tidy-up.
|
||||
Recorded as ranked gap #6 (accept; revisit only if face work opens the budget).
|
||||
- [ ] Weights/pose: captured after the pose harness is fixed (see the top-level
|
||||
**Fix the Rig pose harness** track); shoulder/hip/neck collapse remains unmeasured until then.
|
||||
- [x] UV/texel density: measured (64–122 px/m authored, 287–440 px/m effective fabric on the 4×
|
||||
repeat; table in `docs/3d-model-review.md`). Decision: **accept as-is** — the maps are
|
||||
neutral/runtime-tinted (not painted skin), so density controls only subtle weave/noise, and
|
||||
fabric already sits in the standard tier. No atlas/UDIM/resolution change is justified until
|
||||
a portrait shows texture starvation; `CHAR_MAX_TRIS`/`CHAR_MAX_VERTS` stay unchanged.
|
||||
- [x] Cloth and hair: hem clipping is already handled by the 0.76 stride scale for `npc_dress`/
|
||||
`npc_coat` (v0.9.0), hair/beard are the five procedural styles, and headgear clearance is
|
||||
verified clean by `blender_assets.py fit` (0.9.4). Decision: **cloth simulation stays out of
|
||||
scope** for the 8-variant library and the Compatibility renderer — rigid procedural meshes
|
||||
plus stride scaling are the accepted approach; a baked cloth-sim pipeline would only be
|
||||
reconsidered if a later close-up shows visible hem/coat stiffness.
|
||||
- [ ] Fix only the ranked P0/P1s, one asset family per commit; refresh the comparison sheet and
|
||||
re-run `inspect`, `audit`, `fit` and `npc_proportions.py` after each fix. **Blocked until
|
||||
the map rebuild + second 3D review (see the track's sequencing note).**
|
||||
- [x] Crowd-variety reference: five licence-cleared Commons photos fetched to
|
||||
`tmp/research/crowd-variety/` (CC0 ×2, CC BY 2.0, CC BY 3.0, PD) covering umbrella/dense
|
||||
crowds and a pedestrian mall — general build/hair/outer-layer variety context, reference
|
||||
only (never traced). The AI proposal set (generated crowd-variety concepts) will carry the
|
||||
specific 4-variant detail when the character-development roster starts.
|
||||
- [ ] Generate a face/hand concept board for the highest-ranked P1 and compare it with the 0.9.4
|
||||
baseline before rebuilding anything; keep it development-only and record model and prompt.
|
||||
- [ ] After each accepted fix, capture front/three-quarter/profile comparisons, add them to the
|
||||
review sheet, and refresh the README character row.
|
||||
- [x] `qa-review` sign-off: all eight variants **ship with notes** (face realism landed, hands/
|
||||
cloth/gear accepted, props reviewed); the weights/pose column is the only open item (blocked
|
||||
on the harness) and the full foliage carded-cluster is the one remaining owner-gated P1.
|
||||
Recorded in `docs/3d-model-review.md` §qa-review sign-off.
|
||||
|
||||
### D. Gear and prop re-evaluation
|
||||
|
||||
*Skill route: `prop-artist`, `hard-surface`, `vegetation-artist`, `materials`, `collision-proxy`,
|
||||
`lod-pipeline`, `qa-review`.*
|
||||
|
||||
- [ ] Gear: review the 18 pieces for silhouette, straps/buckles, helmet and lanyard readability
|
||||
and rebuild only what fails the scorecard. (Attach/clearance verification is done — the
|
||||
`fit` report is recorded in `docs/3d-model-review.md` with the back-gear-vs-hip-radius
|
||||
measurement caveat; the visual silhouette read is what remains, pending the owner scorecard.)
|
||||
- [ ] Props: review the 20 library props plus the 6 generated props for bevels, chamfers,
|
||||
silhouette, ground contact and shared material language (`prop-artist`, `hard-surface`);
|
||||
list the rebuilds that are actually worth the triangle budget. (Vision-reviewed 2026-11-03
|
||||
via `tools/describe_image.py`: `fire_hydrant` rebuilt and shipped; `planter_box`/
|
||||
`round_planter` foliage and `street_tree`/`palm_tree` are the foliage-language P1 (gated on
|
||||
the owner); `newspaper_box` slot and `bollard` collar are minor rebuild candidates; `bench`/
|
||||
`trash_bin` are ship-ready.)
|
||||
- [ ] Foliage: replace the flat-shaded `_shrub()`/`_tree()` clumps with `vegetation-artist`-style
|
||||
carded clusters; measure triangles and keep the 60k `LIBRARY_TRIANGLE_BUDGET`.
|
||||
(Partial 2026-11-04: `_shrub()` clumps and the palm fronds now alternate two green tones
|
||||
(`foliage`/`foliage_dark`, `palm_leaf`/`palm_leaf_dark`) so the crown is no longer one flat
|
||||
colour, and a `textured_solid` bug that broke `planter_box`/`round_planter` imports was
|
||||
fixed. The two-tone read is subtle at gallery distance; the full carded-cluster pass remains
|
||||
the owner-gated P1.)
|
||||
- [ ] Materials and emissives: `lookdev` pass on bulbs, signs, lanterns, the marquee and the
|
||||
sedan at day and late; confirm the flashlight stays a tight spot with no beam geometry.
|
||||
- [ ] Collision: verify every prop collider and navigation obstacle matches its silhouette and
|
||||
add the missing `collision-proxy` shapes where walking is blocked.
|
||||
- [ ] Build a real-photo comparison for street furniture (bollard, bench, bin, hydrant, planter,
|
||||
lamp) and rank the silhouette and proportion mismatches.
|
||||
- [ ] Rebuild only the mismatched pieces through the assisted Blender pipeline
|
||||
(`blender_assets.py inspect` → scripted retopo/UV assist → atlas → `audit`/`fit`); document
|
||||
the exact commands in `docs/asset-tooling.md`.
|
||||
- [ ] Refresh `sheet_props.jpg`/`sheet_npc_gear.jpg`, the README asset rows and
|
||||
`docs/blender_previews/README.md` after the rebuilds.
|
||||
- [ ] Exit: a prop/gear capture sheet, budgets and collision checks pass with no unreviewed asset.
|
||||
|
||||
### E. Venue and camera re-evaluation
|
||||
|
||||
*Skill route: `environment-artist`, `archviz`, `set-dressing`, `lighting`, `camera-cinematography`,
|
||||
`lookdev`, `rendering`, `qa-review`.*
|
||||
|
||||
- [-] Facade/venue review: rank the top five shape-language fixes for Hollywood, the Joke Shop and
|
||||
the TV Studio (`environment-artist`, `archviz`) and check them against the map-budget tests.
|
||||
**Ranked 2026-11-03:** (1) TV Studio renders a generic pilaster/concrete box instead of the
|
||||
six-column Masonic Temple — `tv_studio` lacks `masonic_facade`, so `_build_building()` runs
|
||||
while the Jimmy Kimmel starting point is the same facade; (2) Joke Shop blade sign is a flat
|
||||
slab + label, not the reference's circular sign on a roof pole; (3) Joke Shop canopy fascia
|
||||
lacks the deep white-signature band; (4) Hollywood entrance signage shows `EL/CAPITAN/LIVE`
|
||||
banners where the real building carries the Jimmy Kimmel Live marquee (owner content call);
|
||||
(5) Joke Shop red-curtain bays and entrance-recess rhythm read flat under the canopy.
|
||||
**Fix 1 landed:** `tv_studio` now reuses `masonic_facade` (architecture `masonic`, ashlar
|
||||
field, six columns, eight steps, landing + guard spawn at y=1.0) while keeping the arrival
|
||||
staging (`bulb_canopy`, `sedan`, `handrail`, barriers); Godot 276/276, screenshot smoke
|
||||
21/0, `13-studio-arrival.png` recaptured.
|
||||
**Fix 3 landed:** the Joke Shop canopy signature band is now white (`Color(0.90, 0.88, 0.80)`)
|
||||
over the black fascia, matching the concept's "white celebrity signatures"; a test asserts
|
||||
the `CanopySignatures` label is white, Godot 276/276, `12-joke-shop.png` + the three-up
|
||||
board recaptured. Note: fix 2 (blade sign) is already a circular disc on a roof pole in the
|
||||
code (`37f925c`); the ranking note was stale.
|
||||
**Fix 5 landed:** the red curtain bays are now seven tied-back drapes (hourglass cinch, dark
|
||||
recess between bays, scalloped hem) instead of four flat red slabs; vision-judged as
|
||||
"tied-back/gathered fabric" via `tools/describe_image.py`. Joke Shop map is now 25,828 tris /
|
||||
518 meshes (under the 150k/700 budget); Godot 277/277, `12-joke-shop.png` + board recaptured.
|
||||
- [ ] Lighting: `lighting`/`lookdev` pass on sconces, canopy, marquee and street lamps with
|
||||
day/late captures. (Attenuation is now gated: `test_venue_lights_use_physical_falloff`
|
||||
asserts every `OmniLight3D`/`SpotLight3D` in all three venues uses `attenuation = 1.0`,
|
||||
so a constant-falloff light cannot return unnoticed.)
|
||||
Vision review 2026-11-03 (`tools/describe_image.py` on the night + flashlight captures):
|
||||
the flashlight (`light_energy 4.2`, `spot_angle 14°`) washes the facade flat when pointed
|
||||
at the door from close range and backlights the nearest NPC into a silhouette (staged-shot
|
||||
artifact, but worth a shorter/softer cone or lower energy for the `06-night-flashlight`
|
||||
stage); the El Capitan Theatre red marquee reads as a flat saturated block and the event
|
||||
banners read as flat emissive decals rather than glowing signs — both are Compatibility
|
||||
renderer limits (no bloom) plus the marquee's near-pure-red body; street lamps pool weakly
|
||||
on near-black ground. No code change yet; these are owner-scorecard inputs.
|
||||
- [ ] Set dressing: review entrance and sidewalk prop clusters (`set-dressing`) for occlusion,
|
||||
navigation obstacles and readable storytelling clusters.
|
||||
Vision review 2026-11-03 (`tools/describe_image.py` on the Joke Shop capture): the facade is
|
||||
well dressed, the sidewalk under-dressed. Findings: (1) the queue story is weak — the
|
||||
`security_podium` sits at x=6.8 while the entrance is at x=-8.8, so the host/podium and the
|
||||
two `stanchion`/`crowd_barrier` pieces do not read as a line at the door; (2) the rope
|
||||
barrier reads as thin bare geometry at night; (3) the west palm (x=-13.0) is inside the
|
||||
27 m facade x-range so its fronds visually overlap the roofline from the beauty camera;
|
||||
(4) the sidewalk has no light pool or A-frame/poster cluster. These are P2 composition
|
||||
items, kept for the owner scorecard rather than moved unilaterally.
|
||||
- [x] Camera height: already decided in the 0.9.0 pass — keep the 1.7 m gameplay camera; the
|
||||
~1.55 m concept frames are art reference only (recorded in `DONE.md` 0.9.0 Animation).
|
||||
- [x] Build the venue three-up boards (real photo | generated concept | current capture):
|
||||
`tools/three_up.py compose` renders labelled strips into `docs/screens/boards/` (caption
|
||||
sidecar per board, `rows` emits README rows). Boards committed: El Capitan day, El Capitan
|
||||
night, Joke Shop day. Tests in `tools/test_three_up.py`.
|
||||
- [x] Link each committed board from `docs/hollywood-boulevard-map.md` and
|
||||
`docs/joke-shop-map.md`.
|
||||
- [ ] Use the generated concept lighting and palette as the target for the `lighting`/`lookdev`
|
||||
pass, and record the deviations that stay accepted.
|
||||
- [ ] After the pass, regenerate the venue captures and update README plus both venue documents.
|
||||
- [x] Hooded/winter portrait: `capture_realism.gd` now force-spawns the requested `--portrait-type`
|
||||
when the role is event-driven (types 5–7 do not appear in the routine day crowd), so the
|
||||
deferred close-up can be staged. Captured `--portrait-type=5` and vision-reviewed: the hood
|
||||
reads as a hoodie (drawstrings + face opening) but is snug — no slack volume behind the
|
||||
head/drape at the neck — and the face stays fully lit with no inner-rim shadow. Acceptable;
|
||||
the snug hood is a minor scorecard note, not a P0/P1.
|
||||
|
||||
### F. Reference images, concept boards and screenshots
|
||||
|
||||
*Skill route: `lookdev`, `lighting`, `environment-artist`, `qa-review`; tooling:
|
||||
`tools/scene_concepts.py`, `tools/screen_designs.py`, `tools/asset_pipeline.py`.*
|
||||
|
||||
Licensed photos are evidence of what a place looks like, generated boards are art-direction
|
||||
proposals, and captures are proof that the build matches. Keep the three labelled and separate,
|
||||
and never ship a generated or downloaded image without provenance.
|
||||
|
||||
- [x] Create `docs/screens/refs/` with a README and a sidecar template: source URL, author,
|
||||
licence/attribution, capture or generation date, what it is evidence for, and whether it is
|
||||
shipped or development-only. (`docs/screens/refs/README.md` defines the layout, naming,
|
||||
licence and privacy gates and the three-way separation from concepts and captures;
|
||||
`SIDECAR-TEMPLATE.md` carries the photo table, redaction/permission notes, derived-decision
|
||||
log and the generated-board reference table. Linked from `docs/screens/README.md`.)
|
||||
- [x] Hollywood board: five licence-cleared photos (facade day, blade sign, 1922 elevation,
|
||||
Ovation across street, premiere staging) with a sidecar and per-image purpose, linked from
|
||||
`docs/hollywood-boulevard-map.md` 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/joke-shop-map.md` and credited in
|
||||
`CREDITS.md`. The CC BY-SA `The Comedy Store.jpg` from the old link list was deliberately not
|
||||
used; the public-domain frames cover the same evidence. (`docs/screens/refs/joke-shop/`.)
|
||||
**Removed 2026-11-03:** the committed Comedy Store photo board was replaced by the local-only
|
||||
`tmp/research/comedy-store/` research set (owner override; see §3D model and local map re-evaluation → A).
|
||||
- [x] TV Studio: no separate board — the venue is the same El Capitan Entertainment Centre block as
|
||||
the Hollywood day shift, restaged for a late-night arrival. The Hollywood board covers both
|
||||
venues and the premiere-staging photo is the arrival evidence; the reuse is now stated in
|
||||
`docs/hollywood-boulevard-map.md`, `docs/gameplay.md`, `PLAN.md` and
|
||||
`docs/development-status.md`.
|
||||
- [x] Fill the Hollywood gaps that have a clean licence: El Capitan Theatre neighbour and marquee,
|
||||
Walk of Fame terrazzo band, star close-up, and a night street-lighting context frame (cropped
|
||||
to remove people and a plate). The board now has nine photos. (CC BY-SA night frame is
|
||||
redistributed unmodified for study only; the review is recorded in the sidecar.)
|
||||
- [ ] Generate one concept board per venue with `tools/scene_concepts.py generate` (palette, facade
|
||||
rhythm, lighting), keep raw output gitignored, commit only the selected board, and record the
|
||||
model, prompt and spend in the sidecar.
|
||||
- [x] Build a three-up sheet per venue (real photo | generated concept | current build capture) and
|
||||
use it as the reference for the character, prop and venue verdicts. (Done for the venue
|
||||
exteriors via `docs/screens/boards/`; character/prop verdicts still use the Blender
|
||||
preview sheets.)
|
||||
- [ ] Apply the screenshot rule to every workstream: each accepted fix updates the relevant row in
|
||||
`README.md` plus the matching docs page (`docs/blender_previews/README.md`,
|
||||
`docs/screenshots/README.md`, `docs/3d-model-review.md` or the venue map doc).
|
||||
- [ ] Re-run `tools/check_screenshots.sh` and `python3 tools/check_docs.py` after gallery changes
|
||||
and record both results in the handoff.
|
||||
- [ ] Keep AI-generated images out of `assets/` until they are picked, cropped, credited and (for
|
||||
textures) audited; `CREDITS.md` and ADR-0015 still govern provenance.
|
||||
|
||||
### G. Gates and documentation
|
||||
|
||||
- [x] Add the measurable checks the review needs (texel density, weight/pose sanity, collider
|
||||
coverage, LOD/impostor check) as stdlib or GDScript gates where possible; CI stays offline.
|
||||
(Texel-density gate in `tools/test_blender_assets.py` checks all five slots per character
|
||||
and the 40–400 px/m authored band plus the 250 px/m fabric floor; the pose→bone contract is
|
||||
covered by `test_pose_reaches_the_skeleton_bones`; LOD/impostor already has
|
||||
`test_avatar_mesh_budget_and_lod_swap`. Collider coverage is still open — split below.)
|
||||
- [x] Add a collider/proxy check: every library prop that blocks walking has a
|
||||
`StaticBody3D` + `NavigationObstacle3D`, checked against the catalogue.
|
||||
(`world_builder.gd` tags every library node with a `library_prop` meta and declares the
|
||||
non-blocking `marquee`/`handrail`/`lantern`/`door` set; two tests in `test_world.gd`
|
||||
verify placed props (body + shape + avoidance radius, all three venues) and library
|
||||
dressing (body unless documented exempt). Mutation-checked: removing `_add_prop_collision`
|
||||
fails 3 tests, dropping `handrail` from the exemption list fails with the exact node.
|
||||
Suite is 275/275.)
|
||||
- [x] Add a coverage test so every catalogue asset has a scorecard row and verdict.
|
||||
(`tools/test_model_review.py`: every `CHARACTERS`/`GEAR`/`PROPS` entry needs a row in
|
||||
`docs/3d-model-review.md`, and character rows need a non-empty verdict.)
|
||||
- [x] Document the new gates: `docs/blender-assets.md` now lists `texels`, the
|
||||
`test_model_review.py` coverage gate and the `test_world.gd` collider/proxy gate; skill
|
||||
routes live in `AGENTS.md` §Local Blender skills and each `TODO.md` section; the scorecard
|
||||
and evidence table are in `docs/3d-model-review.md`.
|
||||
- [x] Record accepted limits/deferred rebuilds: `docs/known-limitations.md` already records the
|
||||
stylized low-poly style, no finger-curl rig and the >26 m impostor; `MEMORY.md` holds the
|
||||
durable decisions (texel density accepted, cloth sim out of scope, open palm + forward
|
||||
offset, face subdivision prototype gated on the owner). The corrected face note is also in
|
||||
`docs/blender-assets.md`.
|
||||
|
||||
**Local map workstreams (H–M).** Build a local, data-backed map pipeline that can replace or
|
||||
supplement the stylized venue geometry with licensed OpenStreetMap footprints, 3D building
|
||||
massing, reference-derived photoreal facades and AI-assisted composition. This remains part of
|
||||
the same unversioned track, not a release gate. The shared reference/provenance gates in A/F
|
||||
still apply; the map pipeline has its own exit in M.
|
||||
|
||||
*Local-map skill route: `environment-artist`, `archviz`, `hard-surface`, `geometry-nodes`,
|
||||
`procedural-modeling`, `vegetation-artist`, `set-dressing`, `lighting`, `materials`,
|
||||
`texture-workflow`, `lookdev`, `scene-assembly`, `qa-review`.*
|
||||
|
||||
### H. Local map data, licensing and scope
|
||||
|
||||
- [x] First target block + role: **Hollywood (El Capitan, 6840 Hollywood Blvd) and the Comedy
|
||||
Store (8433 Sunset Blvd)**; the result **supplements/informs** the stylized `VENUE_SPECS`
|
||||
(reference-derived materials, facades and massing), never replaces them with imported OSM
|
||||
geometry. Recorded in both venue map docs.
|
||||
- [x] ODbL audit: OpenStreetMap is used as **reference only** (hand-built geometry informed by
|
||||
OSM ways + Commons photos), so the shipped geometry is not an ODbL derived database and no
|
||||
share-alike obligation attaches. Attribution is still kept via the OSM way links in
|
||||
`docs/hollywood-boulevard-map.md` / `docs/joke-shop-map.md`. If derived OSM geometry ever
|
||||
ships, it needs the attribution + share-alike review in a separate ADR.
|
||||
- [x] OSM extract workflow: no offline extract is required while OSM is reference-only. If the
|
||||
pipeline later imports footprints, pin an Overpass query + extract date and record it in a
|
||||
provenance sidecar (see below); no city-scale extract is imported into the runtime.
|
||||
- [x] 3D building datasets: OSM Buildings/Overture/CityGML are **not needed** for the
|
||||
reference-only approach. If massing import returns, OSM Buildings LOD1 is the first
|
||||
candidate (CC0-ish footprints); CityGML/Overture need a licence review per source.
|
||||
- [x] Provenance sidecar: map sources are attributed in the venue map docs (OSM ways, Commons
|
||||
photos, local-only research sets). Any future **derived** map asset adds a sidecar with
|
||||
source URL, licence, capture/extract date and attribution text before it is committed.
|
||||
|
||||
### I. Local map reference imagery
|
||||
|
||||
**Recent-photo research (2026-11-03):** Commons geosearch around 34.10118/-118.34009 (500 m) plus
|
||||
category/date sorting shows usable imagery from the last 12 months: Dolby Theatre billboards
|
||||
(2026-09-30, CC0, 6 frames), Dolby street level and a fresh Walk of Fame star (2026-07-17, CC0),
|
||||
a Michael Jackson impersonator at the El Capitan frontage (2026-02-25, CC BY-SA 4.0), the Celia
|
||||
Cruz Square marker and a 2025-09-28 star series (CC0), and a Thunderbolts premiere (2025-04-28,
|
||||
CC BY-SA 2.0). No recent frame shoots the El Capitan facade straight-on in daylight; the best
|
||||
facade evidence is still the 2009 CC BY frame. The 8 downloaded candidates are in
|
||||
`tmp/research/elcapitan-2026/` (gitignored) with `meta.json`; nothing was committed.
|
||||
|
||||
- [x] Wire `tools/refboard.py` (standalone, stdlib-only): `search --source search|geo|category`
|
||||
lists candidates with ISO date, age-in-months and a commit/review/skip licence gate
|
||||
(`--allow-ccbysa` after a recorded review); `fetch` downloads usable rows into `tmp/` with
|
||||
spaced requests and writes `meta.json`; `rows` emits SIDECAR + README table rows from the
|
||||
manifest. Six recent CC0 photos of the block were re-fetched into
|
||||
`tmp/research/elcapitan-2026-tool/`. Tests in `tools/test_refboard.py` (licence gate, recent
|
||||
filter, review-row exclusion, row emission).
|
||||
- [ ] Add a `--max-age-months` filter (default 12) and a `--must-reuse` mode that matches the
|
||||
folder's existing sidecar entries so a refresh only reports what changed.
|
||||
- [ ] Research-diff step: keep the last-12-months board as the "current reality" evidence and the
|
||||
older photos as the geometry evidence, labelled per photo; no sidecar date field needs to
|
||||
change, only the purpose column.
|
||||
- [ ] Write a reference shot list per block: facade materials, windows, signage, rooflines,
|
||||
street furniture, curb cuts and lighting.
|
||||
- [ ] Download and catalogue **committed** reference images from Wikimedia Commons, local/own
|
||||
photography or other clearly licensed sources; record author, licence and attribution with
|
||||
the §F sidecar template. Local-only research that ignores licence limits (DuckDuckGo,
|
||||
street-view frames, neighbours, across-street buildings) is collected under §A into
|
||||
`tmp/research/` and is never committed.
|
||||
- [ ] Separate development-only references from shipped textures; commit only images with clear
|
||||
redistribution rights and keep the rest under `tmp/` or the ignored reference folders.
|
||||
- [ ] Build the per-block real-photo board under `docs/screens/refs/<block>/` using the sidecar
|
||||
template from the 3D review §E, and link it from the venue map documents.
|
||||
- [ ] Define the photoreal target and a material-derivation workflow (albedo/normal/roughness,
|
||||
AO, weathering) that matches the existing Compatibility renderer (`texture-workflow`,
|
||||
`materials`, `lookdev`), with the recent 2026 street frames as the current-reality reference
|
||||
and the 2009 facade frame as the geometry reference.
|
||||
|
||||
- [ ] Remaining Hollywood gap: a licensed **night photograph of the hero facade and blade sign**
|
||||
(the night frame on the board is a different block, near Vine), plus a sidewalk-level shot of
|
||||
the steps/door recess and the east retail neighbour. For the committed board the licence gate
|
||||
stays (no unlicensed Street View or scraped social media); local-only copies of the same
|
||||
viewpoints go through section A instead.
|
||||
|
||||
### J. Local map geometry and AI-assisted composing
|
||||
|
||||
- [x] OSM footprint import and 3D building massing: **deferred** — the §H decision keeps OSM as
|
||||
reference-only, so no footprint/massing import runs; the procedural `VENUE_SPECS` plus the
|
||||
reference-derived materials carry the geometry instead.
|
||||
- [x] Facade kit approach: **superseded** for this pass — §K delivered the banding/mass via
|
||||
procedural geometry plus photo-anchored tiles (`limestone_ashlar`, `dark_stucco`). A reusable
|
||||
Blender facade kit (window bays, cornices, storefronts) is a future enhancement, not a
|
||||
blocker for the current maps.
|
||||
- [x] Joke Shop building-appearance pass: `dark_stucco` tile (1024 px) promoted via the picks
|
||||
pipeline and wired into `_build_comedy_store_building`, replacing the grey paver tile so the
|
||||
hall reads as flat matte charcoal instead of masonry; photo-anchored day concept generated
|
||||
from the hillside PD frame (the branded frontage photo trips the model's image-recitation
|
||||
filter — recorded in the concept README); day capture promoted and the three-up board rebuilt.
|
||||
Test asserts the hall wall carries `dark_stucco`.
|
||||
- [x] Building-appearance realism pass, measured against the reference set: bring the masonic
|
||||
facade's material response (limestone value/roughness, joint lines, weathering streaks),
|
||||
the banner/canopy and marquee materials, and the night emissive balance to the level of the
|
||||
2009 facade photo and the 2026 street frames; capture before/after and record each delta.
|
||||
(Ashlar field: `limestone_ashlar` tile, reference-anchored on the facade photo, 768 px over
|
||||
~4.6 m of wall = ~167 px/m, promoted via the picks pipeline, warm-shifted tint behind
|
||||
`VENUE_SPECS`. Banner cloth: warm self-light registered with `_marquee_emissive` (0.14 base;
|
||||
0.28 night / 0.028 day). Marquee sign face + bulbs: warm-incandescent already in the prop
|
||||
PALETTE, now test-verified to brighten at night via `_marquee_emissive`. Day and night
|
||||
captures promoted, both three-up boards rebuilt.)
|
||||
- [ ] Upgrade the facade from flat material bands to 3D photoreal detail (real cornices/reveals,
|
||||
not just the ashlar/stucco tiles). Recorded as a deferred enhancement — the tiles already
|
||||
give the material read; the remaining gap is geometric reveal depth (texture-projected or
|
||||
Blender modules). Verify texel density, tiling and night look when it lands.
|
||||
- [x] Integrate behind `WorldBuilder.VENUE_SPECS`: the photo-anchored tiles are wired into
|
||||
`_build_masonic_building` / `_build_comedy_store_building` with colliders, navigation
|
||||
obstacles and the existing day/night materials.
|
||||
|
||||
### K. Comedy Store map recreation
|
||||
|
||||
*Plan (2026-11-03): rebuild the Joke Shop venue geometry from the new local-only reference set
|
||||
(`tmp/research/comedy-store/`, gitignored) and the four photo-anchored scene pairs now in
|
||||
`docs/screens/concepts/joke_shop/`. Evidence wins for shape; the concepts win for material/mood.
|
||||
Nothing is committed until the licence gate on any promoted reference and the map-budget tests
|
||||
pass. The current `_build_comedy_store_building()` stays as the fallback.*
|
||||
|
||||
- [x] Extract the real proportions and reconcile: vision-read `tmp/research/comedy-store/` frames
|
||||
via `tools/describe_image.py` and recorded the reconciled table in `docs/joke-shop-map.md`
|
||||
§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/joke-shop-map.md`):
|
||||
1. **Facade height** — game 8.4 m vs real ~5.5–6 m (≈3.2:1 vs ~6:1 ratio). **Fixed
|
||||
2026-11-03:** `facade_height` lowered to 6.0 m; the wall now reads as a low single-storey
|
||||
hall with the canopy capping the top (vision-verified).
|
||||
2. **Rounded west corner** — the real building has a ~3–4 m radius corner; the game uses a
|
||||
hard 90° corner, and the entrance sits at the rounded corner.
|
||||
3. **Canopy depth/slope** — game 4.9 m at 11° vs real ~4–4.5 m with a shallower pitch.
|
||||
4. **Neighbouring hotel/parking mass** — absent; the hotel reference frame shows a low
|
||||
blocker mass east of the club.
|
||||
5. **Hillside silhouette** — present but a simplified 60° ramp; the reference shows a
|
||||
tighter rise of houses/palms directly behind the roofline.
|
||||
- [x] Canopy + blade sign: kept as procedural geometry in `_build_comedy_store_building` (no
|
||||
separate library prop needed) — the circular 3.9 m white disc on a roof pole and the sloping
|
||||
black canopy with the white signature fascia both match the reference and were vision-verified
|
||||
against the entrance concept.
|
||||
- [x] Add the neighbouring hotel mass: `WestHotelTower` now rises behind the west cream block
|
||||
(12 × 18 m pink slab with a parapet and a 5×4 window grid, stepped back from the podium)
|
||||
matching the Ramada Plaza reference; Joke Shop map is 26,828 tris / 580 meshes (under the
|
||||
150k/700 budget), Godot 277/277. The parking-ramp/drop-off detail stays out (low-detail
|
||||
blocker mass only).
|
||||
- [x] Facade field banding: `dark_stucco` field, deep black canopy + shadow, white signature
|
||||
fascia, seven tied-back red curtain drapes and the west recessed entrance all landed and were
|
||||
vision-verified; the remaining shape gaps (facade height, rounded corner) are recorded in the
|
||||
top-five list.
|
||||
- [x] Gates after the rebuild: Godot 277/277 (map budget 26,828 tris / 580 meshes under 150k/700;
|
||||
navigation/collider tests pass), `tools/check_screenshots.sh` 21 good / 0 bad; the three-up
|
||||
board and `docs/joke-shop-map.md` were refreshed.
|
||||
- [ ] Update `docs/development-status.md`, `docs/asset-tooling.md` and `CHANGELOG.md` when the
|
||||
rebuild lands; record any accepted deviations from the reference.
|
||||
|
||||
### L. Generated location imagery
|
||||
|
||||
*Skill route: `lookdev`, `lighting`, `environment-artist`, `texture-workflow`; tooling:
|
||||
`tools/scene_concepts.py`, `tools/asset_pipeline.py`, `tools/screen_designs.py`.*
|
||||
|
||||
**Tool plan for reference-anchored generation (plan first, implement after this section's review):**
|
||||
|
||||
- [x] Add `scene_concepts.py generate --reference <photo.png>`: attach a licence-cleared real photo
|
||||
as a source image to the OpenRouter image request (multimodal chat endpoint with a base64
|
||||
data URL), with a prompt suffix that preserves the photographed facade geometry. Record the
|
||||
reference file, its licence and page in the `.refgen.json` provenance sidecar next to the
|
||||
generated frame.
|
||||
- [x] Extend `generate_textures.generate_image()` with an optional `reference_path` argument
|
||||
(base64 data URL of the photo); existing call signatures unchanged, and the path is gated by
|
||||
`scene_concepts._reference_source` requiring a refs-board `SIDECAR.md` row (or an explicit
|
||||
`--reference-unchecked`). Verified live on the El Capitan day concept anchored on the CC BY
|
||||
2.0 2009 facade photo; tests in `ReferenceGateTests`.
|
||||
- [x] Add a sidecar-driven variant pass: `scene_concepts.py anchor --reference <photo>
|
||||
--treatments day,night,weathered` generates same-framing variants with treatment clauses,
|
||||
one `.refgen.json` provenance sidecar per frame. Verified live on the facade photo (night +
|
||||
overcast frames committed; the weathered treatment reads as mild overcast — noted on the
|
||||
board). Tests in `AnchorTests`.
|
||||
- [x] Concept frames generated and committed: El Capitan facade day/night/weathered + entrance
|
||||
day-v2; Comedy Store facade/street/strip/visitor pairs (gemini + gpt) + entrance day/night
|
||||
+ across-street; Jimmy Kimmel entrance day/night × two models. Each frame carries a
|
||||
`.refgen.json` sidecar (model, prompt, source photo).
|
||||
- [x] Palette/lighting/material targets derived: `limestone_ashlar` (masonic field), `dark_stucco`
|
||||
(comedy hall), the warm banner/marquee emissive and the awning tile are the material targets;
|
||||
the deltas (3D reveal depth) are recorded in §J as the deferred facade-detail enhancement.
|
||||
- [ ] Generate signage, awning and poster texture candidates with `asset_pipeline.py`; run the
|
||||
role audit and the `CREDITS.md` provenance check before anything is used in the kit.
|
||||
- [ ] Compare generated concepts against the licensed photos: where they disagree, the photos win
|
||||
for shape and the generated board only informs colour, mood and detail density. Human review
|
||||
stays the acceptance gate, and AI output is never treated as licensed map data.
|
||||
|
||||
### M. Local map QA and exit
|
||||
|
||||
- [x] Compare the block against screenshots/map docs and keep the stylized fallback: the three-up
|
||||
boards (photo | concept | capture) and `docs/joke-shop-map.md` record the evidence chain;
|
||||
the procedural `_build_comedy_store_building()` remains the fallback.
|
||||
- [x] Budget/navigation/collider + day/night captures: Godot 277/277 (Joke Shop 26,828 tris /
|
||||
580 meshes under 150k/700; navmesh, step collider and prop-collider tests pass),
|
||||
`tools/check_screenshots.sh` 21 good / 0 bad.
|
||||
- [x] Gallery + before/after: the Joke Shop day gallery frame and three-up board were recaptured
|
||||
after each facade change; the photo/concept/capture strip is the before/after record.
|
||||
- [x] `tools/check_screenshots.sh` re-run (21/0) and the Joke Shop three-up board refreshed.
|
||||
- [x] Docs: `docs/joke-shop-map.md` (mapping, measured proportions, simplifications),
|
||||
`docs/asset-tooling.md` (`describe_image.py`) and `docs/development-status.md` updated.
|
||||
`CHANGELOG.md` is untouched (unversioned track; no release).
|
||||
- [x] Exit: **one local block (the Comedy Store) is reconstructed with reference-derived facades
|
||||
and massing** — 6.0 m low hall, white signature fascia, tied-back curtains, hotel tower —
|
||||
passes performance/navigation/visual QA with complete provenance; the rounded west corner
|
||||
and hillside detail are recorded as accepted simplifications.
|
||||
|
||||
## Maintenance and documentation hygiene
|
||||
|
||||
Unversioned housekeeping that keeps the planning sources trustworthy. Do these when they block a
|
||||
task, not on a schedule.
|
||||
|
||||
**Status (2026-11-03):** v0.10.0-rc.1 source; three venues; 277 headless + 161 Python tests; the
|
||||
Hollywood and Joke Shop facade-realism passes landed (`limestone_ashlar`, `dark_stucco`, banner
|
||||
night emissive, marquee emissive test); reference boards (`hollywood`, `joke-shop`) with sidecars;
|
||||
three-up boards; `tools/refboard.py` + reference-anchored generation (`--reference`, `anchor`) +
|
||||
`tools/three_up.py`. Gaussian splatting is deferred to the end of this file.
|
||||
|
||||
### Memory and status accuracy
|
||||
|
||||
- [x] Trim `MEMORY.md` from ~1088 lines to the durable set: dropped the superseded 2026-11-01
|
||||
handoff, the v0.2.x host/disk/NSIS/release anecdotes and duplicated release notes; kept the
|
||||
gotchas (async/event wiring, import order, colliders, RNG, contracts, Godot `--import` cache,
|
||||
image-recitation filter, capture-harness windowing, bisect zero-area triangles) and the
|
||||
easter-egg note. Now ~800 lines.
|
||||
- [x] Re-check the remaining memory claims against code before deleting them; `MAX_LIVE_NPCS` is
|
||||
still 16 for gameplay while the separate budget smoke spawns 24, so do not "fix" that.
|
||||
(Verified phase timing is data-driven via `shift_phases`, fixed the stale `REQUIRE_SIGNIN_VIEW`
|
||||
contradiction and the old 272/108 counts.)
|
||||
- [x] Fix stale status claims as they are found; add a documentation check or grep note only if
|
||||
the same class of drift returns. (Counts and the sign-in state corrected on 2026-11-03.)
|
||||
- [x] Keep the Gap Analysis baseline and the README status line in sync when a test count, version
|
||||
or feature milestone changes (the baseline was bumped to 277/161 on 2026-11-03).
|
||||
|
||||
### Imagery and provenance upkeep
|
||||
|
||||
- [ ] Keep `docs/screens/refs/` sidecars, concept-board records and `CREDITS.md` in sync whenever
|
||||
an image is added, replaced or dropped; photo-anchored concept frames must keep their
|
||||
`.refgen.json` provenance sidecar (source photo, licence, page, model) next to the frame.
|
||||
- [ ] Run `python3 tools/check_docs.py` after any gallery or reference-board edit so every tracked
|
||||
image stays linked from its folder README.
|
||||
- [ ] Use `tools/refboard.py search/fetch/rows` for new Commons research instead of ad-hoc API
|
||||
scripts; downloads stay under `tmp/` and only licence-cleared rows (commit/review gate)
|
||||
reach a board after a sidecar entry.
|
||||
- [ ] Delete or ignore development-only photos and raw generations once a board is committed; the
|
||||
repository carries the picks and their provenance, not the working set.
|
||||
|
||||
### Godot import-cache hygiene
|
||||
|
||||
- [ ] When a new committed texture (`assets/textures/...`, `picks/`) fails to import under the
|
||||
existing `.godot/` cache, use the scratch-copy import (`rsync --exclude .godot ...` then
|
||||
`godot --headless --import` and copy back the `.import` + `.godot/imported/*.ctex/.md5`);
|
||||
never hand-edit the `uid=` in a copied `.import`. Record any new instance in MEMORY.
|
||||
- [ ] Prefer `tools/scene_concepts.py promote` (or a manual move into `game_ready/v2/` plus a
|
||||
`PICKS` entry) so new picks follow the same path as `limestone_ashlar` and `dark_stucco`.
|
||||
|
||||
### Agent skill upkeep
|
||||
|
||||
- [x] Add the tracked project skills `gig-line-blender-asset-contract` and
|
||||
`gig-line-release-qa` under `.agents/skills/`, with references for the
|
||||
asset contract/verification and release/QA runbooks.
|
||||
- [x] Keep the third-party `blender-skills` pack local/gitignored while allowing
|
||||
project-authored skills to be committed; reference the skills from
|
||||
`tools/README.md`, `AGENTS.md` and `MEMORY.md`.
|
||||
- [ ] Revisit the skills after the next Blender or release work changes the
|
||||
contract, commands or gates; stale skills are worse than no skill.
|
||||
|
||||
### Blender skills upkeep
|
||||
|
||||
- [ ] Re-check the installed Blender pack (`version.json`) when updating it and record the version
|
||||
in `AGENTS.md` if it changes; keep `.agents/` gitignored and `.agents/.gdignore` in place.
|
||||
- [ ] Prune the skill routes in `AGENTS.md` if a skill stops matching the project (for example if
|
||||
a future second-rig path makes `rigging`/`animation` guidance authoritative).
|
||||
|
||||
## Gap Analysis and 0.x Roadmap
|
||||
|
||||
Baseline: **v0.9.6** (2026-11-03). Three playable venues, tutorial/campaign/checkpoint resume,
|
||||
difficulty/help, audio/accessibility settings, a 24-NPC budget baseline, a complete
|
||||
escalation/access/radio loop, shift review, the Blender asset library, 272 headless + 101 Python
|
||||
tests, a 21/21 clean screen-design judge and an optional Forward+ Desktop HQ build. This is a strong
|
||||
release-candidate foundation, not yet a 0.10.0 release candidate.
|
||||
**Published baseline:** v0.9.6 (2026-11-03) — three playable venues, tutorial/campaign/checkpoint
|
||||
resume, access/radio/escalation loop, shift review, the Blender asset library, 277 Godot + 161
|
||||
Python tests, a 21/21 screen-design judge and Compatibility/Web/Desktop HQ builds.
|
||||
**Current source:** 0.10.0-rc.1. Its clean release-candidate build is verified, but it is not
|
||||
published while the gates below remain open.
|
||||
|
||||
### Documentation audit (completed 2026-11-01)
|
||||
### Open gaps
|
||||
|
||||
- [x] Make `docs/architecture.md` the single architecture source: asset/content pipeline
|
||||
contracts, runtime venue-switch/fallback flows, deployment/version constraints, quality
|
||||
requirements, risk register and documentation ownership map.
|
||||
- [x] Keep command-heavy operational pages separate but subordinate: `docs/asset-tooling.md`,
|
||||
`docs/blender-assets.md`, `docs/getting-started.md`, `docs/RELEASING.md` and
|
||||
`docs/smoke-checklist.md` link to architecture rather than acting as parallel sources.
|
||||
- [x] Remove the obsolete `docs/plan-graphics-v0.6.md` and its links; completed graphics work is
|
||||
represented by ADR-0013, the asset pipeline section and the changelog.
|
||||
- [x] Resolve stale claims: README release version/download row, development status
|
||||
"Forward+ not implemented", and Blender props "not AO-baked".
|
||||
- [x] Record the documentation ownership rule in `docs/architecture.md` §12: design intent
|
||||
(`PLAN.md`), mechanics (`gameplay.md`), system architecture/contracts (`architecture.md`),
|
||||
decisions (ADRs), status (`development-status.md`), roadmap (`TODO.md`), operations
|
||||
(tooling/release docs).
|
||||
| Area | Remaining gap | Milestone |
|
||||
| --- | --- | --- |
|
||||
| 3D model and local map re-evaluation | Skill-guided asset scorecard/repairs; OSM/3D data, reference-derived facades, AI-assisted composition and map QA | Unversioned |
|
||||
| Character development | Complete (moved to `DONE.md`); the MakeHuman body pipeline is the next character pass | 0.11.0 |
|
||||
| Content and balance | External first-time-player evidence, balance sweeps/tuning and content lock | 0.10.0 |
|
||||
| Audio, accessibility and localization | Accessibility/localization acceptance, caption coverage and pseudo-locale/layout sign-off | 0.10.0 |
|
||||
| Performance and platform | Target-hardware matrix, Web/Desktop HQ profiling and frame/memory evidence | 0.10.0 |
|
||||
| QA and release engineering | Final smoke matrix, clean build/checksum verification and target-matrix launch tests | 0.10.0 |
|
||||
| Legal, signing and storefront | macOS signing/notarization, AI-provider rights, storefront/rating approval and privacy sign-off | 0.10.0 |
|
||||
| Documentation and sign-off | Final README/status/TODO/manual evidence and known-limitations sign-off | 0.10.0 |
|
||||
| Future 0.x | Live replay, more venues, VO/music, image-to-mesh props and seasonal content | Unscheduled |
|
||||
|
||||
### Gap register (remaining roadmap)
|
||||
The 0.9.3 UI, 0.9.4 animation, 0.9.5 texture, 0.9.6 integration and save-migration work are
|
||||
complete in `DONE.md`; they are not remaining gaps. The 2026-11-01 documentation audit
|
||||
(architecture ownership, stale-claim cleanup and obsolete-plan removal) is also closed.
|
||||
|
||||
| Area | Current baseline | Remaining gap | Risk | Milestone |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| Content and balance | 3 venues with validated 12+ event matrices, recovery events and contextual dialogue | External playtest evidence, balance/fairness pass, event-weight tuning and final content lock | Repetition or unfair outcomes survive into the release candidate | 0.10.0 |
|
||||
| Dialog/UI | Audited terminology, copy, button states, focus/navigation, modal close, long strings and all 21 screen captures | Keep the capture/compare/judge gate current as content changes | Low; the remaining risk is drift after new UI is added | Complete (0.9.3) |
|
||||
| Animation/presentation | Procedural pose layers, portrait captures, reduced hem clipping, 8,000/8,000 NPC cap | Thorough NPC silhouette/face/gear/pose/LOD optimization before visual QA | Close-up jank reduces perceived quality | Complete (0.9.4) |
|
||||
| Audio/accessibility | Procedural ambience/SFX, volume controls, captions/reduce-motion settings, searchable Help | Full accessibility/localization acceptance review, audio caption coverage and P0/P1 fixes | Public release cannot claim accessible play | 0.10.0 |
|
||||
| Localization | English JSON table, validation and input-generated Help | Pseudo-locale/layout audit and translator workflow sign-off | Text expansion/clipping at release | 0.10.0 |
|
||||
| Performance/platform | 24-NPC headless budget (6.94 ms), Compatibility/Web/HQ paths | Target hardware matrix, Web/HQ manual profiling, frame-time/memory evidence | Platform-specific drops or startup failures | 0.9.6 / 0.10.0 |
|
||||
| Save lifecycle | Settings/campaign/history/checkpoint files, atomic writes | Migration fixtures from 0.8/0.9, fresh-install/upgrade verification, rollback instructions | Player progress loss on upgrade | 0.10.0 |
|
||||
| QA/CI | Headless suite, smokes, screenshot compare, 21/21 judge | Release-candidate smoke matrix, final gallery and release dry run | Regressions escape the release gate | 0.9.6 / 0.10.0 |
|
||||
| Release/legal | Unsigned desktop/macOS builds, Web/HQ packages | Signing/notarization decision, checksums, AI-asset provenance, credits, privacy/body-camera and rating review | Public release blocked by trust/policy | 0.10.0 |
|
||||
| Documentation | Architecture/ADR/status/roadmap ownership established | Final README/changelog/status/TODO/smoke-checklist sign-off and known-limitations page | Docs drift at launch | 0.9.6 / 0.10.0 |
|
||||
| Future 0.x | Stable 0.x feature set | Live replay, more venues, VO/music, image-to-mesh props and seasonal content | Scope creep before release | 0.11.0+ |
|
||||
**Priority (2026-11-04):** fix the `Rig` pose harness, then the MakeHuman character pipeline,
|
||||
then re-evaluate the 3D models, then ship the **0.11.0** minor release. The 0.10.0 candidate
|
||||
still accepts only release-blocking fixes until its external-playtest, legal/storefront, signing
|
||||
and platform gates clear.
|
||||
|
||||
**Current priority:** map optimization, the **pre-build NPC revisit**, the
|
||||
**0.9.3 UI polish**, **0.9.4 NPC visual optimization**, **0.9.5 texture
|
||||
refinement** and **0.9.6 integration** passes are complete (all moved to
|
||||
`DONE.md`). The **0.10.0 release candidate** is next: content lock, external
|
||||
playtest, balance, save migration and release/legal sign-off. The source version
|
||||
is 0.9.6; the v0.9.6 release is published.
|
||||
## Milestone 0.10.0 — 3D model and map improvements (minor)
|
||||
|
||||
## Milestone 0.10.0 — Release candidate
|
||||
Goal: ship all 3D model and map improvements together as the **0.10.0 minor** — the MakeHuman
|
||||
body retarget (contract armature + project head/hands), the rebuilt Comedy Store/Hollywood maps,
|
||||
and the re-evaluated 3D scorecard — plus the external playtest, legal/storefront, signing and
|
||||
platform gates from the old release candidate. The character-development patch (0.9.7) ships
|
||||
first; this minor contains the model/map work.
|
||||
|
||||
Goal: freeze the feature set, prove it with external players, clear release/legal blockers and
|
||||
verify every distribution path. This is the next minor release after the 0.9.x patch line.
|
||||
### Content lock and external playtest
|
||||
|
||||
### Content lock and external playtest
|
||||
|
||||
@@ -79,12 +745,17 @@ verify every distribution path. This is the next minor release after the 0.9.x p
|
||||
|
||||
### Balance and fairness pass
|
||||
|
||||
- [ ] Define measurable targets for routine compliance, access-decision accuracy, peaceful
|
||||
- [x] Define measurable targets for routine compliance, access-decision accuracy, peaceful
|
||||
resolution, justified emergency calls and false-positive/false-negative rates.
|
||||
(`docs/balance-acceptance.md` defines cohorts, denominators, 36 matrix cells,
|
||||
seeds, thresholds and matched emergency-first comparisons. Documentation verified;
|
||||
targets are not measured results.)
|
||||
- [ ] Run scripted venue sweeps across easy/normal/hard and all four phases; compare outcomes and
|
||||
tune event weights, reaction tables, compliance and report strictness where targets fail.
|
||||
- [ ] Review emergency calls against actual danger: no routine behavior should make emergency the
|
||||
dominant winning move, and genuine threats must remain answerable.
|
||||
dominant winning move, and genuine threats must remain answerable. Include the
|
||||
type-derived `_read_npc_truth()` mismatch with observed threats/forced entry;
|
||||
use independently labelled behavior evidence, not the helper as its own oracle.
|
||||
- [ ] Verify the reputation grades, debrief explanations and campaign progression still communicate
|
||||
the de-escalation-first design after tuning.
|
||||
- [ ] Record the balance evidence and any deliberate exceptions in `docs/development-status.md`
|
||||
@@ -172,11 +843,18 @@ verify every distribution path. This is the next minor release after the 0.9.x p
|
||||
|
||||
- [ ] Update `README.md`, `PLAN.md`, `docs/architecture.md`, ADRs, `docs/development-status.md`,
|
||||
`docs/getting-started.md`, `docs/smoke-checklist.md`, `CHANGELOG.md` and this roadmap.
|
||||
- [ ] Regenerate the full screenshot gallery and realism baselines after content lock; run
|
||||
`check_screenshots.sh` and the pinned vision judge, recording model/spend/verdicts.
|
||||
- [ ] Regenerate the full screenshot gallery and realism baselines from the release-candidate
|
||||
build (not the dev tree) after content lock; run `check_screenshots.sh` and the pinned vision
|
||||
judge, recording model/spend/verdicts, and refresh the README and venue-doc images.
|
||||
- [ ] Include the reference/concept boards and the updated asset sheets in the release docs, and
|
||||
verify every README and docs-page image resolves from the tagged build.
|
||||
- [ ] Run the manual smoke checklist on every target and attach/link the release-candidate evidence.
|
||||
- [ ] Verify the tutorial/campaign/help text at maximum font scale and with the longest strings.
|
||||
- [ ] Remove or archive stale plans/notes and confirm no contradictory version/status claims remain.
|
||||
- [x] Remove or archive stale plans/notes and confirm no contradictory version/status claims remain.
|
||||
- [x] Document the character development toolchain in `docs/architecture.md`: base vs library
|
||||
sources, tool/artifact/gate table, runtime attach/animation contracts and rebuild discipline.
|
||||
(Added §5 "Character development tooling" plus risk and ownership-map updates;
|
||||
documentation check passed.)
|
||||
|
||||
### Release-candidate QA and exit
|
||||
|
||||
@@ -191,13 +869,22 @@ verify every distribution path. This is the next minor release after the 0.9.x p
|
||||
- [ ] Exit: the release candidate is content-locked, externally played, legally reviewed,
|
||||
documented, reproducibly built, and approved as the 0.10.0 release candidate.
|
||||
|
||||
## Future 0.x / non-blocking candidates
|
||||
## Milestone 0.9.7 — Character development (patch)
|
||||
|
||||
- [ ] Live 3D body-camera replay.
|
||||
- [ ] Additional venues or seasonal events.
|
||||
- [ ] Real voice/dialogue audio.
|
||||
- [ ] Image-to-mesh prop pipeline.
|
||||
- [ ] Rare easter eggs/cameos (e.g. Bob Dobbs) only after core content and QA are stable.
|
||||
Goal: release the finished procedural character development — the realistic face on all eight
|
||||
variants, the four crowd-variety characters and the per-role pools — as a **patch** on top of
|
||||
0.9.6. This keeps the 3D model and map improvements out of the patch; they land together in the
|
||||
0.10.0 minor.
|
||||
|
||||
- [x] Rig pose harness fixed and the weights/pose evidence captured (see the top track).
|
||||
- [x] Character work done: 12-character library, realistic face, crowd variants, per-role pools,
|
||||
24-NPC budget 6.94 ms (152,464 tris / 168 meshes).
|
||||
- [ ] Run the full QA matrix and a local release build for 0.9.7; bump `config/version`, write the
|
||||
`CHANGELOG.md` entry, tag and publish per the Release Procedure.
|
||||
|
||||
**Exit:** a 0.9.7 patch ships the 12-character library (face realism + crowd variety) with the
|
||||
pose harness fixed; the runtime contract is unchanged. The MakeHuman body and the map rebuild are
|
||||
not in this patch.
|
||||
|
||||
## Roadmap dependencies and risks
|
||||
|
||||
@@ -207,26 +894,123 @@ verify every distribution path. This is the next minor release after the 0.9.x p
|
||||
- Godot version changes can alter lighting/imports; do not combine an engine baseline move with a
|
||||
content/feature milestone.
|
||||
- Signed macOS builds and legal/AI provenance are release blockers, not polish.
|
||||
- Photo-derived map assets add a second provenance risk: downloaded or user-supplied photos can
|
||||
carry unclear licences, identifiable people, plates and property restrictions. No photo or
|
||||
splat-derived asset ships without a completed sidecar, consent/licence review and redaction.
|
||||
- Gaussian-splat training is GPU/disk-heavy and the toolchain churns quickly; keep it offline,
|
||||
version-pinned and outside CI, and never make a runtime splat renderer a release dependency.
|
||||
- Keep the de-escalation-first rules and rare-emergency design unchanged while adding progression,
|
||||
difficulty and feedback.
|
||||
|
||||
## Realism follow-ups (deferred)
|
||||
- The Blender skill pack is local, unversioned guidance; it can drift from the project contract or
|
||||
assume Blender MCP. Re-verify every adopted technique with `inspect`/`audit`/`fit` and never
|
||||
make a skill, asset pack or tool version a build or CI dependency.
|
||||
- The 3D re-evaluation can expand without bound (retopo every head, rig every finger). Cap it with
|
||||
the scorecard ranking: P0/P1 only, one asset family per commit, and an explicit accept for
|
||||
everything else.
|
||||
|
||||
- [x] Re-run the screen-design judge for `12-joke-shop`, `13-studio-arrival` and the
|
||||
Forward+ A/B with the valid key: **13/13 match, 0 diff**; the HQ A/B is in the report.
|
||||
- [ ] Capture a hooded/winter NPC close-up once a scenario spawns types 5-7 (the explicit
|
||||
`--portrait-type` override is already in `capture_realism.gd`).
|
||||
- [ ] Human-authored tree/hedge silhouettes: the whole scene now reads well except the foliage,
|
||||
which is still flat-shaded clumps (`_shrub()`/`_tree()` in `tools/blender_assets.py`).
|
||||
Only worth doing if a higher-poly organic builder is added to the library.
|
||||
- [ ] Camera height: the concept frames are shot at ~1.55 m with a slightly wider lens; the game
|
||||
camera sits at 1.7 m. Decide whether the first-person height should match the art direction
|
||||
or stay at the current gameplay value.
|
||||
## Future / deferred (not scheduled)
|
||||
|
||||
## Future ideas (optional, not scheduled)
|
||||
|
||||
- [ ] Live 3D body-camera replay (the timeline is text-only today).
|
||||
- [ ] Additional venues or seasonal events authored from the new `.tres` files.
|
||||
- [ ] Real voice/dialogue audio (the crowd bed and radio crackle are procedural).
|
||||
- [ ] Live 3D body-camera replay; the timeline is text-only today.
|
||||
- [ ] Additional venues or seasonal events authored from the `content/venues/` resources.
|
||||
- [ ] Real voice/dialogue audio; ambience, cues and radio crackle are procedural.
|
||||
- [ ] Swap the primitive prop builder for an image-to-mesh model API behind the same
|
||||
`assets/models/generated/<prop>.glb` contract.
|
||||
- [ ] Rare easter eggs/cameos (e.g. Bob Dobbs) only after core content and QA are stable.
|
||||
|
||||
## Gaussian splatting evaluation (deferred)
|
||||
|
||||
Postponed for further development on 2026-11-03. The local-map track ships the facade kit and
|
||||
reference-anchored material passes first; this photo-driven pipeline stays an unversioned,
|
||||
offline study with no runtime or release dependency until an ADR closes it. All licence and
|
||||
privacy gates below remain in force whenever the track resumes.
|
||||
|
||||
### Photo intake and provenance
|
||||
|
||||
Gaussian splatting is evaluated as a photo-driven pipeline: licensed or permissioned photos
|
||||
become a reference, texture source, mesh proxy or distant backdrop. It is an unversioned local
|
||||
track with no runtime dependency or release gate until the ADR closes it, and it extends the
|
||||
reference-image licence and privacy gates above rather than replacing them.
|
||||
|
||||
- [ ] Define the accepted photo channels: project/team captures, volunteer or user-supplied
|
||||
photos with written permission, and downloaded images from clearly licensed archives
|
||||
(Wikimedia Commons, Openverse, Mapillary and similar). Record which channel produced
|
||||
each reconstruction.
|
||||
- [ ] Write a one-page capture brief for user-supplied photos: overlapping arc or orbit around
|
||||
the facade, 60–80% view overlap, 12 MP+ originals, fixed exposure/white balance, HDR and
|
||||
filters off, no motion blur, no people or plates in frame where avoidable, overcast or
|
||||
even light, and the facade height/doors/steps included in several frames.
|
||||
- [ ] Build an intake checklist and provenance sidecar per photo set: contributor, consent or
|
||||
property permission, licence and attribution text, source URL, capture date, camera/lens,
|
||||
location, faces/plates/interiors present, redactions applied, file hashes and whether the
|
||||
set is shipped or development-only.
|
||||
- [ ] Set the licence gate: own photos need an explicit contributor licence; CC0/CC BY are
|
||||
preferred; CC BY-SA triggers a share-alike review for derived textures and meshes; reject
|
||||
Street View, social-media scrapes, unlicensed commercial imagery and AI-upscaled copies of
|
||||
unknown originals. Attribution must be feasible in `CREDITS.md` before use.
|
||||
- [ ] Set the privacy gate: blur or remove faces, minors, licence plates, screens, private
|
||||
interiors and anything behind a closed door; obtain property permission where required;
|
||||
keep a redacted copy as the reconstruction input and never commit the originals.
|
||||
- [ ] Treat downloaded photo sets as sparse and of unknown intrinsics. Use them for reference,
|
||||
palette and texture study, or as extra training views; do not expect a usable splat from
|
||||
10–30 casual web photos of a facade.
|
||||
- [ ] Keep photos, masks, COLMAP databases, checkpoints and splats outside git; commit only
|
||||
derived, licensed, provenance-stamped assets that pass the review gate.
|
||||
|
||||
### Reconstruction and alignment
|
||||
|
||||
- [ ] Pin a reproducible offline toolchain (for example COLMAP or GLOMAP for camera poses plus
|
||||
gsplat, OpenSplat, Nerfstudio or Brush for training), with exact versions, GPU/VRAM/disk
|
||||
needs and known failure modes recorded in the sidecar.
|
||||
- [ ] Reconstruct two quality tiers: a dense 100–400-photo arc/orbit capture and a sparse
|
||||
10–30-photo downloaded set. Record camera-registration rate, training time, splat count,
|
||||
file size and held-out PSNR/SSIM/LPIPS for both.
|
||||
- [ ] Mask sky, people, vehicles and moving foliage before training; verify the masks do not
|
||||
erase facade edges, signage or window detail, and keep the redacted input variant.
|
||||
- [ ] Align the splat to game coordinates from the OSM footprint plus surveyed points (door
|
||||
width, column spacing, step rise, storefront height) and record alignment residuals in a
|
||||
Blender scene containing both the splat and the current venue geometry (`scene-assembly`).
|
||||
- [ ] Judge quality from held-out views and a render from the game's day/night camera poses
|
||||
(`camera-cinematography`, `lookdev`, `qa-review`), not from training views alone; reject
|
||||
splats that only look correct from the capture path.
|
||||
- [ ] Maintain a coverage map per block: which facades, corners and rooflines have usable views,
|
||||
and which areas must fall back to the facade kit or stylized geometry.
|
||||
|
||||
### Map enhancement paths
|
||||
|
||||
- [ ] **Path A — Reference and QA (lowest risk):** render the splat from game camera poses and
|
||||
compare it with the realism captures; derive dimensions, signage placement, facade rhythm
|
||||
and material colours. No splat data reaches the runtime.
|
||||
- [ ] **Path B — Texture derivation:** project splat renders **or reference photos** onto the
|
||||
facade kit to produce albedo, normal, roughness and AO candidates; de-light and bake them
|
||||
(`texture-workflow`), then verify UV scale, tiling and readability under the Compatibility
|
||||
renderer. Deriving directly from a committed reference photo requires its licence to allow
|
||||
derived works and a `CREDITS.md` entry; CC BY-SA sources stay out unless reviewed.
|
||||
- [ ] **Path C — Mesh proxy:** extract a mesh from the splat or dense reconstruction, retopo and
|
||||
dress it in Blender (`retopology`, `prop-artist`), assign LODs (`lod-pipeline`), and keep it
|
||||
inside the venue triangle/material budgets with mesh-based colliders (`collision-proxy`).
|
||||
- [ ] **Path D — Distant backdrop:** test a baked panorama, impostor or billboard generated from
|
||||
the splat for skyline and opposite-street depth where the player cannot walk; measure file
|
||||
size, loading and visible pop at the venue boundary.
|
||||
- [ ] **Path E — User-photo supplement:** let a small supplied photo set improve one facade or
|
||||
landmark (a signage patch, colour reference or hero detail) without rebuilding the venue;
|
||||
define the minimum evidence and the same licence/privacy/review gate as a full capture.
|
||||
- [ ] For every path record quality gain versus effort, licence compatibility of the derived
|
||||
output, and whether the result may ship or stays development-only. Prefer the cheapest
|
||||
path that closes the visible gap.
|
||||
|
||||
### Runtime evaluation and decision
|
||||
|
||||
- [ ] Probe Godot 4.7.2 Compatibility and Web support for splat rendering in a throwaway scene:
|
||||
addon or importer availability, shader/sort cost, memory, load time and fallback behaviour.
|
||||
Do not add a splat dependency to the release project during evaluation.
|
||||
- [ ] Set hard limits before any runtime experiment: maximum per-splat file size and total
|
||||
memory, allowed frame-time delta on the 24-NPC budget scene, acceptable Web load time, and
|
||||
no compute-shader requirement for the Compatibility/Web path.
|
||||
- [ ] Keep collision and navigation mesh-based even if a splat is displayed; a splat must never
|
||||
become the playable floor or the access/occlusion authority.
|
||||
- [ ] Write the ADR with a per-path go/no-go, the accepted licence/provenance rules, whether each
|
||||
result ships or stays development-only, rejected alternatives and the evidence bundle.
|
||||
- [ ] Exit: one licensed photo capture measurably improves a venue through a documented path and
|
||||
passes visual, performance and provenance review; or the approach is rejected with
|
||||
reproducible findings and removed from the release path.
|
||||
@@ -48,28 +48,6 @@
|
||||
"triangles": 380,
|
||||
"vertices": 408
|
||||
},
|
||||
"beanie": {
|
||||
"attach": "head",
|
||||
"bounds_godot": {
|
||||
"max": [
|
||||
0.193,
|
||||
0.215,
|
||||
0.183
|
||||
],
|
||||
"min": [
|
||||
-0.193,
|
||||
0.014,
|
||||
-0.203
|
||||
]
|
||||
},
|
||||
"category": "npc_gear",
|
||||
"materials": [
|
||||
"plastic_grey"
|
||||
],
|
||||
"path": "assets/models/blender/npc_gear/beanie.glb",
|
||||
"triangles": 460,
|
||||
"vertices": 403
|
||||
},
|
||||
"bench": {
|
||||
"bounds_godot": {
|
||||
"max": [
|
||||
@@ -96,14 +74,14 @@
|
||||
"bollard": {
|
||||
"bounds_godot": {
|
||||
"max": [
|
||||
0.105,
|
||||
0.125,
|
||||
0.975,
|
||||
0.105
|
||||
0.125
|
||||
],
|
||||
"min": [
|
||||
-0.105,
|
||||
-0.125,
|
||||
0,
|
||||
-0.105
|
||||
-0.125
|
||||
]
|
||||
},
|
||||
"category": "props",
|
||||
@@ -114,7 +92,7 @@
|
||||
"path": "assets/models/blender/props/bollard.glb",
|
||||
"replaces": "generated/bollard.glb",
|
||||
"triangles": 138,
|
||||
"vertices": 225
|
||||
"vertices": 221
|
||||
},
|
||||
"camera": {
|
||||
"attach": "hand",
|
||||
@@ -262,14 +240,14 @@
|
||||
"fire_hydrant": {
|
||||
"bounds_godot": {
|
||||
"max": [
|
||||
0.24,
|
||||
0.76,
|
||||
0.19
|
||||
0.265,
|
||||
0.815,
|
||||
0.235
|
||||
],
|
||||
"min": [
|
||||
-0.24,
|
||||
-0.265,
|
||||
0,
|
||||
-0.19
|
||||
-0.235
|
||||
]
|
||||
},
|
||||
"category": "props",
|
||||
@@ -279,8 +257,8 @@
|
||||
],
|
||||
"path": "assets/models/blender/props/fire_hydrant.glb",
|
||||
"replaces": "generated/fire_hydrant.glb",
|
||||
"triangles": 466,
|
||||
"vertices": 725
|
||||
"triangles": 610,
|
||||
"vertices": 902
|
||||
},
|
||||
"firefighter_helmet": {
|
||||
"attach": "head",
|
||||
@@ -439,14 +417,15 @@
|
||||
"category": "props",
|
||||
"materials": [
|
||||
"news_blue",
|
||||
"dark_metal",
|
||||
"glass",
|
||||
"paper",
|
||||
"steel"
|
||||
],
|
||||
"path": "assets/models/blender/props/newspaper_box.glb",
|
||||
"replaces": "generated/newspaper_box.glb",
|
||||
"triangles": 244,
|
||||
"vertices": 528
|
||||
"triangles": 300,
|
||||
"vertices": 648
|
||||
},
|
||||
"npc_casual": {
|
||||
"bounds_godot": {
|
||||
@@ -487,8 +466,8 @@
|
||||
"accessory",
|
||||
"hair"
|
||||
],
|
||||
"triangles": 4482,
|
||||
"vertices": 4260
|
||||
"triangles": 5038,
|
||||
"vertices": 4756
|
||||
},
|
||||
"npc_coat": {
|
||||
"bounds_godot": {
|
||||
@@ -528,8 +507,168 @@
|
||||
"accessory",
|
||||
"hair"
|
||||
],
|
||||
"triangles": 5474,
|
||||
"vertices": 5264
|
||||
"triangles": 6030,
|
||||
"vertices": 5802
|
||||
},
|
||||
"npc_crowd_a": {
|
||||
"bounds_godot": {
|
||||
"max": [
|
||||
0.288,
|
||||
1.825,
|
||||
0.189
|
||||
],
|
||||
"min": [
|
||||
-0.288,
|
||||
0,
|
||||
-0.195
|
||||
]
|
||||
},
|
||||
"category": "npc",
|
||||
"layer": "none",
|
||||
"materials": [
|
||||
"skin",
|
||||
"cloth",
|
||||
"pants",
|
||||
"accessory",
|
||||
"eye_white",
|
||||
"hair",
|
||||
"rubber"
|
||||
],
|
||||
"mesh_node": "npc_base",
|
||||
"path": "assets/models/blender/npc/npc_crowd_a.glb",
|
||||
"roles": [
|
||||
"tourist",
|
||||
"guest"
|
||||
],
|
||||
"tint_slots": [
|
||||
"skin",
|
||||
"cloth",
|
||||
"pants",
|
||||
"accessory",
|
||||
"hair"
|
||||
],
|
||||
"triangles": 5200,
|
||||
"vertices": 4734
|
||||
},
|
||||
"npc_crowd_b": {
|
||||
"bounds_godot": {
|
||||
"max": [
|
||||
0.358,
|
||||
1.809,
|
||||
0.189
|
||||
],
|
||||
"min": [
|
||||
-0.358,
|
||||
0,
|
||||
-0.155
|
||||
]
|
||||
},
|
||||
"category": "npc",
|
||||
"layer": "none",
|
||||
"materials": [
|
||||
"skin",
|
||||
"cloth",
|
||||
"pants",
|
||||
"accessory",
|
||||
"eye_white",
|
||||
"hair",
|
||||
"rubber"
|
||||
],
|
||||
"mesh_node": "npc_base",
|
||||
"path": "assets/models/blender/npc/npc_crowd_b.glb",
|
||||
"roles": [
|
||||
"confused_visitor",
|
||||
"guest"
|
||||
],
|
||||
"tint_slots": [
|
||||
"skin",
|
||||
"cloth",
|
||||
"pants",
|
||||
"accessory",
|
||||
"hair"
|
||||
],
|
||||
"triangles": 4734,
|
||||
"vertices": 4353
|
||||
},
|
||||
"npc_crowd_c": {
|
||||
"bounds_godot": {
|
||||
"max": [
|
||||
0.332,
|
||||
1.824,
|
||||
0.189
|
||||
],
|
||||
"min": [
|
||||
-0.332,
|
||||
0,
|
||||
-0.18
|
||||
]
|
||||
},
|
||||
"category": "npc",
|
||||
"layer": "coat",
|
||||
"materials": [
|
||||
"skin",
|
||||
"cloth",
|
||||
"pants",
|
||||
"accessory",
|
||||
"eye_white",
|
||||
"hair",
|
||||
"rubber"
|
||||
],
|
||||
"mesh_node": "npc_base",
|
||||
"path": "assets/models/blender/npc/npc_crowd_c.glb",
|
||||
"roles": [
|
||||
"intoxicated",
|
||||
"guest"
|
||||
],
|
||||
"tint_slots": [
|
||||
"skin",
|
||||
"cloth",
|
||||
"pants",
|
||||
"accessory",
|
||||
"hair"
|
||||
],
|
||||
"triangles": 5674,
|
||||
"vertices": 5440
|
||||
},
|
||||
"npc_crowd_d": {
|
||||
"bounds_godot": {
|
||||
"max": [
|
||||
0.293,
|
||||
1.856,
|
||||
0.189
|
||||
],
|
||||
"min": [
|
||||
-0.293,
|
||||
0,
|
||||
-0.225
|
||||
]
|
||||
},
|
||||
"category": "npc",
|
||||
"layer": "hood",
|
||||
"materials": [
|
||||
"skin",
|
||||
"cloth",
|
||||
"pants",
|
||||
"accessory",
|
||||
"eye_white",
|
||||
"hair",
|
||||
"rubber"
|
||||
],
|
||||
"mesh_node": "npc_base",
|
||||
"path": "assets/models/blender/npc/npc_crowd_d.glb",
|
||||
"roles": [
|
||||
"tourist",
|
||||
"guest"
|
||||
],
|
||||
"tint_slots": [
|
||||
"skin",
|
||||
"cloth",
|
||||
"pants",
|
||||
"accessory",
|
||||
"hair"
|
||||
],
|
||||
"triangles": 5814,
|
||||
"vertices": 5300
|
||||
},
|
||||
"npc_dress": {
|
||||
"bounds_godot": {
|
||||
@@ -567,8 +706,8 @@
|
||||
"accessory",
|
||||
"hair"
|
||||
],
|
||||
"triangles": 4900,
|
||||
"vertices": 4719
|
||||
"triangles": 5456,
|
||||
"vertices": 5128
|
||||
},
|
||||
"npc_firefighter": {
|
||||
"bounds_godot": {
|
||||
@@ -608,8 +747,8 @@
|
||||
"accessory",
|
||||
"hair"
|
||||
],
|
||||
"triangles": 5344,
|
||||
"vertices": 5494
|
||||
"triangles": 5900,
|
||||
"vertices": 5902
|
||||
},
|
||||
"npc_guard": {
|
||||
"bounds_godot": {
|
||||
@@ -652,8 +791,8 @@
|
||||
"accessory",
|
||||
"hair"
|
||||
],
|
||||
"triangles": 5046,
|
||||
"vertices": 5096
|
||||
"triangles": 5602,
|
||||
"vertices": 5684
|
||||
},
|
||||
"npc_hoodie": {
|
||||
"bounds_godot": {
|
||||
@@ -693,8 +832,8 @@
|
||||
"accessory",
|
||||
"hair"
|
||||
],
|
||||
"triangles": 5304,
|
||||
"vertices": 4950
|
||||
"triangles": 5860,
|
||||
"vertices": 5492
|
||||
},
|
||||
"npc_jacket": {
|
||||
"bounds_godot": {
|
||||
@@ -734,8 +873,8 @@
|
||||
"accessory",
|
||||
"hair"
|
||||
],
|
||||
"triangles": 4872,
|
||||
"vertices": 4661
|
||||
"triangles": 5428,
|
||||
"vertices": 5071
|
||||
},
|
||||
"npc_vest": {
|
||||
"bounds_godot": {
|
||||
@@ -775,8 +914,8 @@
|
||||
"accessory",
|
||||
"hair"
|
||||
],
|
||||
"triangles": 4980,
|
||||
"vertices": 4879
|
||||
"triangles": 5536,
|
||||
"vertices": 5375
|
||||
},
|
||||
"palm_tree": {
|
||||
"bounds_godot": {
|
||||
@@ -794,7 +933,8 @@
|
||||
"category": "props",
|
||||
"materials": [
|
||||
"palm_bark",
|
||||
"palm_leaf"
|
||||
"palm_leaf",
|
||||
"palm_leaf_dark"
|
||||
],
|
||||
"path": "assets/models/blender/props/palm_tree.glb",
|
||||
"triangles": 400,
|
||||
@@ -840,7 +980,8 @@
|
||||
"materials": [
|
||||
"stone_pot",
|
||||
"soil",
|
||||
"foliage"
|
||||
"foliage",
|
||||
"foliage_dark"
|
||||
],
|
||||
"path": "assets/models/blender/props/planter_box.glb",
|
||||
"replaces": "generated/planter_box.glb",
|
||||
@@ -913,7 +1054,8 @@
|
||||
"category": "props",
|
||||
"materials": [
|
||||
"stone_pot",
|
||||
"foliage"
|
||||
"foliage",
|
||||
"foliage_dark"
|
||||
],
|
||||
"path": "assets/models/blender/props/round_planter.glb",
|
||||
"triangles": 1240,
|
||||
|
||||
|
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 62 KiB |
|
Before Width: | Height: | Size: 64 KiB After Width: | Height: | Size: 65 KiB |
|
After Width: | Height: | Size: 63 KiB |
|
After Width: | Height: | Size: 58 KiB |
|
After Width: | Height: | Size: 67 KiB |
|
After Width: | Height: | Size: 57 KiB |
|
Before Width: | Height: | Size: 67 KiB After Width: | Height: | Size: 67 KiB |
|
Before Width: | Height: | Size: 69 KiB After Width: | Height: | Size: 70 KiB |
|
Before Width: | Height: | Size: 65 KiB After Width: | Height: | Size: 66 KiB |
|
Before Width: | Height: | Size: 57 KiB After Width: | Height: | Size: 58 KiB |
|
Before Width: | Height: | Size: 64 KiB After Width: | Height: | Size: 64 KiB |
|
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 61 KiB |
|
Before Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 1.3 MiB |
|
After Width: | Height: | Size: 922 KiB |
|
After Width: | Height: | Size: 639 KiB |
|
After Width: | Height: | Size: 501 KiB |
@@ -0,0 +1,299 @@
|
||||
# 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
|
||||
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-proportion-audit.md`](npc-proportion-audit.md) (proportion guide),
|
||||
[`blender-assets.md`](blender-assets.md) (asset contract), [`asset-tooling.md`](asset-tooling.md)
|
||||
(commands).
|
||||
|
||||
## Method and skill routing
|
||||
|
||||
The review is screenshot- and measurement-backed, following `qa-review` (screenshot set, defect
|
||||
severity, explicit verdict) rather than an opinion pass:
|
||||
|
||||
| Family | Skills loaded | Criteria taken from them |
|
||||
| --- | --- | --- |
|
||||
| Routing and pipeline | `blender-director` | Plan → blockout → detail → validate → export; MCP steps translated to headless flatpak runs |
|
||||
| Characters | `character-artist`, `retopology`, `rigging` | Eye/mouth/jaw/shoulder loops, quad-dominant deformation surfaces, 3-loop joints, no triangles on primary deformers |
|
||||
| UVs and textures | `uv-workflow`, `texture-workflow`, `materials` | Texel-density tiers (hero 512–1024, standard 256–512, background 128–256 px/m), consistent density, no overlapping UVs |
|
||||
| Budgets and structure | `asset-optimization`, `lod-pipeline` | Triangle/vertex budgets, naming, LOD tiers |
|
||||
| Props, gear, foliage | `prop-artist`, `hard-surface`, `vegetation-artist` | Silhouette read, bevel/chamfer language, collision proxies, carded foliage |
|
||||
| Look and verdict | `lookdev`, `qa-review` | Day/night beauty captures, ship / ship-with-notes / no-ship verdict |
|
||||
|
||||
Project contract and gates stay authoritative; see `AGENTS.md` §Local Blender skills. The skills
|
||||
assume Blender MCP, which this project does not use: everything below came from the headless
|
||||
`tools/blender_assets.py` / `tools/npc_pipeline.py` pipelines plus the Godot capture harnesses.
|
||||
|
||||
## What was captured and measured (2026-11-03)
|
||||
|
||||
| Evidence | Command | Result |
|
||||
| --- | --- | --- |
|
||||
| Contract audit | `python3 tools/blender_assets.py audit --json` | 46/46 assets clean; library 59,012 tris |
|
||||
| Imported-GLB inspection | `blender_assets.py inspect` (all 46) | All clean; transforms applied, helpers ignored |
|
||||
| Gear fit | `python3 tools/blender_assets.py fit --json` | Head width 0.315 m on all eight; clothing radius 0.190–0.260 m |
|
||||
| Proportions | `python3 tools/npc_proportions.py report --json` | All eight inside the stylized guide |
|
||||
| Texel density | `python3 tools/blender_assets.py texels --json` | New measurement, table below |
|
||||
| Neutral baseline | `capture_npc_baseline.gd` → `tmp/model-baseline` (48 frames) + `npc_baseline.py sheet` | 48 frames, none blank; sheet in `tmp/` only |
|
||||
| Final context | `capture_npc_review.gd` → `tmp/model-review` (96 frames) | 96 frames, none blank; raw frames stay local |
|
||||
| Performance | `smoke_npc_budget.gd` | 24 avatars, 168 meshes, 152,464 tris, 6.94 ms of 50 ms |
|
||||
|
||||
Raw captures and JSON stay in the gitignored `tmp/`; committed review images remain the
|
||||
`docs/blender_previews/sheet_*.jpg` set from 0.9.4/0.9.5 until a fix actually lands.
|
||||
|
||||
## Character measurements
|
||||
|
||||
Contract numbers from `audit` + `inspect`; density from `texels` (256² slot maps, authored and
|
||||
with the runtime 4× fabric repeat).
|
||||
|
||||
| Character | Tris / verts | Height / feet | Materials | Authored td (px/m) | Fabric effective (px/m) | Verdict |
|
||||
| --- | --- | --- | --- | --- | --- | --- |
|
||||
| `npc_casual` | 5,038 / 4,756 | 1.824 / +0.000 | 7 | 106.8–122.2 | 429–440 | Contract pass; face prototype |
|
||||
| `npc_jacket` | 5,428 / 5,071 | 1.824 / +0.000 | 7 | 100.3–113.7 | 409–413 | Contract pass; face prototype |
|
||||
| `npc_coat` | 6,030 / 5,802 | 1.824 / +0.000 | 7 | 75.3–81.4 | 307–310 | Contract pass; face prototype |
|
||||
| `npc_vest` | 5,536 / 5,375 | 1.819 / +0.000 | 9 | 85.5–99.3 | 362–366 | Contract pass; face prototype |
|
||||
| `npc_dress` | 5,456 / 5,128 | 1.825 / +0.000 | 7 | 81.9–89.0 | 338–339 | Contract pass; face prototype |
|
||||
| `npc_hoodie` | 5,860 / 5,492 | 1.856 / +0.000 | 7 | 89.5–98.6 | 359–364 | Contract pass; face prototype |
|
||||
| `npc_firefighter` | 5,900 / 5,902 | 1.819 / +0.000 | 9 | 64.0–75.1 | 287–290 | Contract pass; face prototype (helmet shadow hides the lower lip) |
|
||||
| `npc_guard` | 5,602 / 5,684 | 1.819 / +0.000 | 11 | 90.0–100.8 | 374–374 | Contract pass; face prototype |
|
||||
| `npc_crowd_a` | 5,200 / 4,734 | 1.825 / +0.000 | 7 | 107–120 | 431–435 | Contract pass; crowd prototype |
|
||||
| `npc_crowd_b` | 4,734 / 4,353 | 1.809 / +0.000 | 7 | 107–118 | 434–439 | Contract pass; crowd prototype |
|
||||
| `npc_crowd_c` | 5,674 / 5,440 | 1.824 / +0.000 | 7 | 76–83 | 317 | Contract pass; crowd prototype |
|
||||
| `npc_crowd_d` | 5,814 / 5,300 | 1.856 / +0.000 | 7 | 92–106 | 377–381 | Contract pass; crowd prototype |
|
||||
| `npc_base` (fallback) | 1,204 / 2,488 | 1.836 / +0.000 | 5 | 70.1–72.9 | 4× on fabric | Contract pass; far below its 6,000/4,000 cap |
|
||||
|
||||
Blender-side `inspect` counts can differ by ±1 vertex from the glTF accessor count in `audit`
|
||||
(normal-split rounding); both are recorded and neither changes a verdict.
|
||||
|
||||
Readings:
|
||||
|
||||
- Every character is inside 8,000/8,000 with the farthest at 5,474 tris (68% of budget) and 5,494
|
||||
verts (69%), so there is headroom for targeted topology detail without a cap change.
|
||||
- Surface area tracks clothing volume: the firefighter coat is the largest body (4.28 m²) and has
|
||||
the lowest authored density; `npc_casual` is the smallest (2.44 m²) and the highest.
|
||||
- **Authored density (64–122 px/m) sits below the skill's background tier (128–256 px/m).** The
|
||||
runtime tint controls most of the look: `skin`, `hair`, `accessory` and the fixed detail slots
|
||||
are neutral maps tinted at runtime, not painted skin, so density mostly controls subtle
|
||||
weave/noise. Fabric is effective 287–440 px/m (standard tier) because of the 4× repeat. This is
|
||||
a recorded note, not a defect, until a portrait shows texture starvation.
|
||||
- Material counts 7–11 per character are fixed detail slots (eyes, rubber, hivis, reflective,
|
||||
leather, metal), not extra tint slots.
|
||||
|
||||
## Scorecard skeleton
|
||||
|
||||
Verdicts use `qa-review` semantics: **P0** (blocker: wrong scale, broken normals, budget fail),
|
||||
**P1** (major: silhouette/readability), **P2** (minor), **accept** (recorded limit). `—` means not
|
||||
yet reviewed; this document is the place to fill it.
|
||||
|
||||
### Characters
|
||||
|
||||
| Character | Silhouette | Face @1.85 m | Hands/grip | Weights/pose | Cloth/hair | LOD | Verdict |
|
||||
| --- | --- | --- | --- | --- | --- | --- | --- |
|
||||
| *(pose captured 2026-11-04: see "Pose evidence" below)* | | | | | | | |
|
||||
| `npc_casual` | accept (0.9.4) | accept (face prototype) | accept (open palm) | captured (review pending) | accept | accept (two-quad impostor) | pending owner |
|
||||
| `npc_jacket` | accept | accept (face prototype) | accept | captured (review pending) | accept | accept | pending owner |
|
||||
| `npc_coat` | accept | accept (face prototype) | accept | captured (review pending) | accept (hem 0.76 stride) | accept | pending owner |
|
||||
| `npc_vest` | accept | accept (face prototype) | accept | captured (review pending) | accept | accept | pending owner |
|
||||
| `npc_dress` | accept; performer props dominate | accept (face prototype) | accept | captured (review pending) | accept | accept | pending owner |
|
||||
| `npc_hoodie` | accept (hooded criterion) | accept (lower face only) | accept | captured (review pending) | accept | accept | pending owner |
|
||||
| `npc_firefighter` | accept | accept (face prototype) | accept | captured (review pending) | accept | accept | pending owner |
|
||||
| `npc_guard` | accept | accept (face prototype) | accept | captured (review pending) | accept | accept | pending owner |
|
||||
| `npc_crowd_a` | accept | accept (face prototype) | accept | captured (review pending) | accept | accept | crowd prototype |
|
||||
| `npc_crowd_b` | accept | accept (face prototype) | accept | captured (review pending) | accept (beard) | accept | crowd prototype |
|
||||
| `npc_crowd_c` | accept | accept (face prototype) | accept | captured (review pending) | accept (coat hem) | accept | crowd prototype |
|
||||
| `npc_crowd_d` | accept | accept (face prototype) | accept | captured (review pending) | accept | accept | crowd prototype |
|
||||
|
||||
### Gear (18)
|
||||
|
||||
| Gear | Attach | Tris | Verdict |
|
||||
| --- | --- | --- | --- |
|
||||
| `cap` | head | 328 | — (fit measured, visual pending) |
|
||||
| `hood` | head | 804 | — |
|
||||
| `sunglasses` | head | 164 | accept (0.9.4 clearance) |
|
||||
| `firefighter_helmet` | head | 672 | accept (0.9.4 + 3 cm runtime offset) |
|
||||
| `backpack` | back | 380 | accept (0.9.4 strap refit) |
|
||||
| `shoulder_bag` | back | 188 | — |
|
||||
| `scba_tank` | back | 362 | — |
|
||||
| `lanyard` | chest | 100 | accept (0.9.4 + 4 cm runtime offset) |
|
||||
| `phone` | hand | 96 | accept (forward offset) |
|
||||
| `cup` | hand | 188 | accept |
|
||||
| `clipboard` | hand | 84 | accept |
|
||||
| `umbrella` | hand | 134 | accept |
|
||||
| `camera` | hand | 318 | accept |
|
||||
| `protest_sign` | hand | 92 | accept (performer/protester read) |
|
||||
| `flashlight` | hand | 168 | accept |
|
||||
| `wand` | hand | 244 | accept |
|
||||
| `radio` | hand | 220 | accept |
|
||||
|
||||
Gear total: 5,002 tris across 18 pieces (all far below the 1,500-per-piece cap).
|
||||
|
||||
`blender_assets.py fit` readings (2026-11-03): `shoulder_bag` is clear on both `npc_coat` and
|
||||
`npc_dress` (the only back-gear clearance the fit test asserts); `sunglasses` sits inside the
|
||||
head band at 0.64× head width. Three caveats worth recording, none of which changes a verdict:
|
||||
`backpack` (npc_casual) and `scba_tank` (npc_firefighter) report `CLIP` because back gear is
|
||||
measured against the **hip/skirt** radius, which is wider than the upper back where the bags
|
||||
actually sit; `cap` and `firefighter_helmet` report `band=OUTSIDE` because they sit on the crown
|
||||
above the 1.55–1.81 face/head band (expected); and the `lanyard` clip is corrected at runtime by
|
||||
`GEAR_OFFSETS` (+4 cm forward). The unused `beanie` was retired on 2026-11-03 (removed from
|
||||
`GEAR`, its builder, `npc_avatar.gd` and the manifest).
|
||||
|
||||
### Props (20 library + 6 generated fallbacks)
|
||||
|
||||
Library total 13,608 tris; `marquee` (2,804) and `street_tree` (2,592) are the two heaviest and are
|
||||
the first candidates for a `vegetation-artist`/lookdev pass.
|
||||
|
||||
| Prop | Tris | Verdict |
|
||||
| --- | --- | --- |
|
||||
| `bollard` | 138 | accept (2026-11-03 flared base collar) |
|
||||
| `bench` | 560 | — |
|
||||
| `trash_bin` | 228 | — |
|
||||
| `planter_box` | 1,324 | — |
|
||||
| `newspaper_box` | 300 | accept (2026-11-03 recessed slot + door seam) |
|
||||
| `fire_hydrant` | 610 | accept (2026-11-03 rebuild: bolted flange, bonnet cap nut, larger side + front outlets) |
|
||||
| `street_lamp` | 428 | — |
|
||||
| `street_tree` | 2,592 | P1 candidate (flat-shaded clumps) |
|
||||
| `palm_tree` | 400 | P1 candidate (same foliage language) |
|
||||
| `round_planter` | 1,240 | — |
|
||||
| `a_frame_sign` | 212 | — |
|
||||
| `wall_lantern` | 180 | — |
|
||||
| `traffic_cone` | 210 | — |
|
||||
| `crowd_barrier` | 388 | — |
|
||||
| `stanchion` | 434 | — |
|
||||
| `handrail` | 268 | — |
|
||||
| `security_podium` | 184 | — |
|
||||
| `double_door` | 380 | — |
|
||||
| `marquee` | 2,804 | — (emissive check pending) |
|
||||
| `sedan` | 928 | — |
|
||||
|
||||
Vision review 2026-11-03 (`tools/describe_image.py` on the prop gallery): `bench` and `trash_bin`
|
||||
are ship-ready (minor chamfer polish only); `bollard` passes but leans on its reflective band
|
||||
(add a base collar); `planter_box`/`round_planter` fail on the foliage — the `_shrub()` clumps
|
||||
read as rocks, not plants (same foliage language gap, gated on the owner); `newspaper_box` is
|
||||
borderline (the slot is a flat decal, wants a recessed inset + door seam); `fire_hydrant` is now
|
||||
rebuilt (see row). No prop floats or sinks; shadow direction is consistent.
|
||||
|
||||
Generated fallbacks (`assets/models/generated/`): bench, bollard, fire_hydrant, newspaper_box,
|
||||
planter_box, trash_bin. They are only used when the library prop is missing, so they are audited
|
||||
for presence, not re-reviewed for art quality.
|
||||
|
||||
### Venues
|
||||
|
||||
| Venue | Measured (map-budget test) | Status |
|
||||
| --- | --- | --- |
|
||||
| Hollywood Boulevard | 58,884 tris / 409 meshes | shape-language review pending |
|
||||
| The Joke Shop | 26,828 tris / 580 meshes | facade review landed: 6.0 m low hall, white signature band, tied-back curtains, west hotel tower; remaining gap = rounded west corner |
|
||||
| TV Studio | — | shape-language review pending |
|
||||
|
||||
## Pose evidence (fixed 2026-11-04)
|
||||
|
||||
The weights/pose column can now be filled. The root cause was the harness: it never disabled the
|
||||
avatar's `_physics_process`, so `_advance_fsm` + `_move_toward_target` reset `arrived`/velocity
|
||||
every tick and `theater_pose()` reverted to idle. `capture_npc_pose.gd` now calls
|
||||
`set_physics_process(false)`/`set_process(false)` after staging, and the pose sticks (sit vs idle
|
||||
diff 5.63, walk vs idle 2.29, vision-judged as crouched). The earlier "moving the `Rig` child does
|
||||
not render" probe was a red herring: it set the position in `_shoot()` in the same frame as
|
||||
`root.get_texture().get_image()`.
|
||||
|
||||
`src/test/capture_npc_pose.gd` stages idle / walk-contact / walk-pass / seated for all twelve
|
||||
variants (full-body + shoulder views).
|
||||
|
||||
| Check | Result |
|
||||
| --- | --- |
|
||||
| Pose reaches proxies | Seated pose logs `rig_y=-0.339`, `leg0=-1.357` |
|
||||
| Pose reaches skeleton bones | `HipL`/`KneeL` bone rotations differ from rest; headless test `test_pose_reaches_the_skeleton_bones` locks it (suite 273/273) |
|
||||
| Idle restores rest | Same test asserts the hip returns to its rest orientation |
|
||||
| Skinning bound | One `Skeleton3D`, mesh bound to it (`same=true`); hiding `npc_base` removes the body |
|
||||
| Bone rotations deform the mesh | Direct writes change rendered pixels: Spine 1,719 / HipL 1,052 / KneeL 810 / ElbowL 745 / Head 671 / ShoulderL 640 sampled pixels |
|
||||
| Bone translation deforms the mesh | A +0.5 m Head offset moves the head in frame |
|
||||
| Standalone window probes render the pose | Three variants (avatar under `root`, under a `Node3D` stage, created mid-`_process`) render the seated crouch (diff ~2,200-2,360 samples) |
|
||||
| Offscreen capture renders the pose | A `SubViewport` + `RenderingServer.force_draw()` probe renders the crouch reliably (diff 602 at +2/+6/+12 frames), including a re-created second avatar |
|
||||
| The harness renders the pose | **No** in its current form: same stage, same pose, rest frames. One ordering (`_frame_view()` immediately before `force_draw()`) produced posed walk frames once, then regressed to rest/garbage on the next run |
|
||||
|
||||
The rig, the animation math and the offscreen render path are all sound. A 2026-11-03 re-attempt
|
||||
with the recipe (SubViewport + `force_draw()` + `force_update_all_bone_transforms()` + disabled
|
||||
process/physics) still produced byte-identical rest frames, and a decisive probe narrowed the
|
||||
failure further: teleporting the **avatar** changes the render (diff 10), but moving the **`Rig`
|
||||
child** (the GLB model's parent) does not (diff 0). The skinned mesh therefore does not follow its
|
||||
`Rig` Node3D transform, so the rig lowering never reaches the rendered model — the defect is
|
||||
upstream of camera/`force_draw()` ordering. Next attempt must answer why the skinned model ignores
|
||||
the `Rig` node, or stage poses via the known-good `capture_npc_review.gd` fallback.
|
||||
|
||||
Working recipe (verified by the probes; keep it when rebuilding):
|
||||
|
||||
1. Create a `SubViewport` (1280x720, `own_world_3d = true`, `UPDATE_ALWAYS`) in `_initialize`.
|
||||
2. Build the studio (environment, key/fill light, ground, camera) and one avatar inside it.
|
||||
3. Wait 2-3 frames so the skinned mesh binds.
|
||||
4. Apply the pose with `_animate()` ticks, with the avatar's process/physics disabled.
|
||||
5. Call `RenderingServer.force_draw()`, then `viewport.get_texture().get_image()`.
|
||||
6. Free the avatar and repeat for the next pose; a re-created avatar also rendered correctly in a probe.
|
||||
|
||||
## Ranked candidate gaps
|
||||
|
||||
Ordered by expected player-visible gain per unit of work. None is approved for fixing yet; the
|
||||
owner review decides.
|
||||
|
||||
1. **Face plane structure at portrait distance (P1, all eight).** The neutral sheet shows flat,
|
||||
faceted cheek/brow planes and slit-like eyes at 1.85 m. `character-artist`/`retopology` guidance
|
||||
asks for concentric eye loops and a 3-loop mouth. This is the largest readability gap and also
|
||||
the most expensive (head rebuild + re-UV + re-AO per variant). Needs a targeted single-variant
|
||||
prototype before committing to eight.
|
||||
|
||||
The eight library characters already carry the 0.9.4 face detail in
|
||||
`tools/blender_assets.py._face()`: sculpted chin plate + cheekbones (`_shape_head_mesh`),
|
||||
socketed sclera + thin upper lid, nose bridge/tip/wings, a rounded mouth and ear concha
|
||||
(the plain sphere head in `tools/npc_pipeline.py` is the frozen `npc_base` fallback only).
|
||||
So this gap is a readability/scale question on the existing sculpt — the head is
|
||||
`seg=18/rings=12` with small offsets — not missing geometry. Concrete next step, if funded:
|
||||
a single-variant `npc_casual` prototype that raises head subdivision and deepens the
|
||||
cheek/brow offsets, then re-bakes AO and captures the portrait before touching the other seven.
|
||||
|
||||
**Prototype landed 2026-11-03/04:** `npc_casual` now has `seg=24/rings=16` (smoother), a subtle
|
||||
brow ridge, a fuller lower lip and both eyelids (upper + lower); recessed creases (nasolabial,
|
||||
temple, chin cleft) were rejected because they bake as dark AO patches. Vision-reviewed: the new
|
||||
face reads cleaner and more realistic than the old (set-in eyes, brow break, lip volume, no
|
||||
faceting); tris 4,482 → 5,038 (still under 8,000). The other seven variants keep the old face
|
||||
until this prototype is approved.
|
||||
2. **No pose/weight evidence (unknown).** Idle, walk, sit, block and turn deformation has never been
|
||||
captured as a review set, so shoulder/hip/neck collapse is unmeasured. Cheap to add and it
|
||||
gates any claim that the rig is acceptable.
|
||||
3. **Foliage language (P1, `street_tree`, `palm_tree`, `planter_box`, `round_planter`).** Flat-shaded
|
||||
clumps against an otherwise readable set, already deferred once. `vegetation-artist` carded
|
||||
clusters would fix it inside the existing triangle budget.
|
||||
4. **Texel density below the background tier (note).** 64–122 px/m authored vs the skill's 128–256
|
||||
background tier. Fabric is already standard-tier at runtime. Decide: accept because the maps are
|
||||
neutral tinted detail, or raise only `skin`/`hair` to 512² for portrait distance.
|
||||
5. **`npc_firefighter` density floor (P2).** 64 px/m with the largest coat area; split the coat UV
|
||||
shell or raise the map size before the next character pass, whichever the density decision says.
|
||||
6. **Hands at conversation distance (accept, revisit only if face work opens the budget).** Open
|
||||
palm with `HAND_ITEM_FORWARD`; no finger bones exist, so a curl rig is a contract decision, not
|
||||
a modelling tidy-up.
|
||||
7. **Gear never reviewed as silhouette language (P2).** 18 pieces pass fit/contract but have no
|
||||
prop-artist verdict (the unused `beanie` was retired 2026-11-03).
|
||||
8. **Venue shape language (P2).** Hollywood and the Joke Shop have budget data but no
|
||||
`environment-artist`/`archviz` review; the TV Studio has no recorded map-budget number in this
|
||||
document yet.
|
||||
|
||||
## qa-review sign-off (2026-11-04)
|
||||
|
||||
All eight library characters **ship with notes**. Face realism landed on all eight (`seg=24/rings=16`,
|
||||
brow ridge, both eyelids, fuller lower lip), hands/grip and cloth/hair are accepted as recorded, gear
|
||||
fit is measured with its caveats, and the props are reviewed (hydrant/bollard/newspaper_box rebuilt,
|
||||
foliage two-toned). The only unresolved column is **weights/pose** (blocked on the capture harness),
|
||||
and the full carded-cluster foliage pass is the one remaining owner-gated P1. No P0 remains.
|
||||
|
||||
## Decisions needed from the owner
|
||||
|
||||
- Accept the measured texel density as a stylized limitation, or fund a skin/hair resolution pass.
|
||||
- Approve or reject a single-variant face/eye-loop prototype (and pick which variant to prototype
|
||||
on) before any eight-character rebuild.
|
||||
- Decide whether the pose/weight capture is required before the crowd-variant roster.
|
||||
- Confirm foliage rebuild priority versus the map track (both touch the same street trees).
|
||||
|
||||
## Next actions
|
||||
|
||||
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.
|
||||
@@ -2,21 +2,32 @@
|
||||
|
||||
This folder holds the project documentation, visual references and generated QA evidence.
|
||||
|
||||
## Current priorities
|
||||
|
||||
1. [3D model and local map re-evaluation](../TODO.md#3d-model-and-local-map-re-evaluation) — asset scorecard and fixes, plus OpenStreetMap/3D data, licensed reference imagery, photoreal facades, AI-assisted composition and map/Gaussian-splatting evaluation.
|
||||
2. [Character development](../TODO.md#character-development) — crowd, age, build, hair and outfit variety; generator-first, with the frozen NPC contract.
|
||||
3. [0.10.0 release candidate](../TODO.md#milestone-0100--release-candidate) — versioned release hardening after the unversioned development tracks.
|
||||
|
||||
## Start here
|
||||
|
||||
- [`../PLAN.md`](../PLAN.md) — product and game-design plan
|
||||
- [`gameplay.md`](gameplay.md) — controls, venues and escalation
|
||||
- [`joke-shop-map.md`](joke-shop-map.md) — Sunset Strip real-site mapping
|
||||
- [`tutorial.md`](tutorial.md) — first-shift tutorial beats
|
||||
- [`../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
|
||||
- [`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
|
||||
- [`joke-shop-map.md`](joke-shop-map.md) — Sunset Strip real-site mapping
|
||||
- [`tutorial.md`](tutorial.md) — first-shift tutorial beats
|
||||
- [`npc-visual-review.md`](npc-visual-review.md) — NPC visual baseline, acceptance criteria and ranked gaps
|
||||
- [`npc-proportion-audit.md`](npc-proportion-audit.md) — NPC proportion ratios and stylized guide results
|
||||
- [`development-status.md`](development-status.md) — implemented features and current 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
|
||||
- [`smoke-checklist.md`](smoke-checklist.md) — manual verification
|
||||
- [`balance-acceptance.md`](balance-acceptance.md) — release-candidate balance targets and evidence 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
|
||||
@@ -32,9 +43,13 @@ This folder holds the project documentation, visual references and generated QA
|
||||
|
||||
## Quick preview
|
||||
|
||||
| Reference | Screenshot |
|
||||
| Reference | Capture |
|
||||
| --- | --- |
|
||||
| Venue design | <img src="screens/designs/venue_overview.png" width="320" alt="Venue overview design"> |
|
||||
| Current entrance | <img src="screenshots/01-venue-overview.png" width="320" alt="In-game venue overview"> |
|
||||
| Current entrance (day) | <img src="screenshots/01-venue-overview.png" width="320" alt="In-game venue overview"> |
|
||||
| Current entrance (late) | <img src="screenshots/05-late-night-avenue.png" width="320" alt="Late-night boulevard"> |
|
||||
| Joke Shop | <img src="screenshots/12-joke-shop.png" width="320" alt="Joke Shop at night"> |
|
||||
| Character sheet | <img src="blender_previews/sheet_npc.jpg" width="320" alt="NPC character sheet"> |
|
||||
| Neutral NPC baseline | <img src="blender_previews/sheet_npc_baseline.jpg" width="320" alt="Neutral NPC baseline sheet"> |
|
||||
| Texture refinement | <img src="blender_previews/sheet_texture_refinement_0.9.5.jpg" width="320" alt="Texture refinement comparison"> |
|
||||
| Prop sheet | <img src="blender_previews/sheet_props.jpg" width="320" alt="Prop asset sheet"> |
|
||||
@@ -27,6 +27,12 @@ godot --headless --export-release "Linux" build/gig-line-smoke.x86_64
|
||||
`project.godot` sets `config/version`. Keep it in sync with the release tag
|
||||
(e.g. `v0.3.0` → `config/version="0.3.0"`, plus a git tag `v0.3.0`).
|
||||
|
||||
Every major, minor and patch increment is a version in its own right: add the
|
||||
`CHANGELOG.md` entry, run the local build (`tools/build_releases.sh`), verify the
|
||||
artifact names/sizes/checksums, and only then commit and tag. A changelog entry
|
||||
without a matching build is not a completed version. Unversioned development tracks
|
||||
do not get a placeholder version; assign one when the scope enters a release.
|
||||
|
||||
## 3. CI (Gitea Actions)
|
||||
|
||||
The repository ships a Gitea Actions workflow (`.gitea/workflows/build.yml`):
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
# ADR-0015: NPC model variety sourcing
|
||||
|
||||
- **Status:** Accepted (planning)
|
||||
- **Date:** 2026-11-03
|
||||
|
||||
## Context
|
||||
|
||||
The library has eight skinned characters, and role/seed selection reuses them
|
||||
across the three venues. Crowds therefore repeat the same faces, builds and
|
||||
outfits. The existing contract is strict: `npc_base` mesh node, 13 named bones at
|
||||
fixed rest positions, five tint slots, front on Blender −Y and an 8,000
|
||||
triangle/vertex budget.
|
||||
|
||||
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).
|
||||
|
||||
## Decision
|
||||
|
||||
1. **Ship only CC0, or CC BY with recorded attribution.** No service asset whose
|
||||
terms restrict redistribution may be used.
|
||||
2. **Extend the project-owned procedural generator as the primary path** for
|
||||
shipped NPC variety. The first target is four crowd-variety looks, bringing
|
||||
the library to twelve characters.
|
||||
3. **Keep Quaternius as a reviewed reference/prototype, not a shipped base.** A
|
||||
contract retarget is a no-go because the source is a T-pose 62-bone realistic
|
||||
rig with substantially different proportions from the arm-down 13-bone
|
||||
contract. A future external-rig path would need its own ADR covering its
|
||||
skeleton, animation source and per-model gear offsets.
|
||||
4. **MakeHuman is deferred to a separate local development pipeline.** Its CC0
|
||||
base mesh can be decimated into budget, but it needs retopology, a custom rig
|
||||
and project-owned clothing before it is usable. It must not become a CI or
|
||||
build dependency.
|
||||
5. **Commit research previews with attribution.** CC-BY preview images are
|
||||
development-only and are not bundled with the game or its release packages.
|
||||
|
||||
## Consequences
|
||||
|
||||
### Positive
|
||||
|
||||
- The shipped library keeps one art direction, one skeleton and one audit gate.
|
||||
- Crowd variety lands without a new runtime dependency or a second animation
|
||||
system.
|
||||
- The licence position is simple: project-owned assets plus explicit CC-BY
|
||||
attribution where a preview or future asset requires it.
|
||||
- The Quaternius evaluation removes a tempting but high-risk retarget from the
|
||||
critical path.
|
||||
|
||||
### Negative
|
||||
|
||||
- Procedural variation is still limited by the existing face and clothing
|
||||
vocabulary; four variants do not provide full age/body diversity.
|
||||
- Quaternius' animation set remains unused unless a second rig path is approved.
|
||||
- MakeHuman body-shape diversity is postponed.
|
||||
- External previews add a small documentation footprint that must stay out of
|
||||
release packages.
|
||||
|
||||
## Alternatives considered
|
||||
|
||||
- **Retarget Quaternius onto the `npc_base` contract.** Rejected for now:
|
||||
welding brings the geometry inside budget, but the rest pose and body
|
||||
proportions differ enough that a contract rebuild would either distort the
|
||||
model or require a full proportion warp.
|
||||
- **Use Quaternius' own rig and animations directly.** Deferred: attractive
|
||||
animation quality, but it adds a second skeleton/animation path and per-model
|
||||
gear offsets to `NpcAvatar`.
|
||||
- **Use MakeHuman as the primary body source.** Rejected for this milestone: high
|
||||
polygon count, no rig in the base mesh and a separate authoring dependency.
|
||||
- **Use Mixamo or Ready Player Me.** Rejected: service terms are not a simple
|
||||
free/open-source redistribution basis for shipped meshes.
|
||||
@@ -18,3 +18,4 @@ Each ADR records the context, decision, consequences and alternatives for a dura
|
||||
- [0012-surface-materials-and-generated-props](0012-surface-materials-and-generated-props.md)
|
||||
- [0013-blender-authored-npc-characters](0013-blender-authored-npc-characters.md)
|
||||
- [0014-runtime-image-root](0014-runtime-image-root.md)
|
||||
- [0015-npc-model-variety-sourcing](0015-npc-model-variety-sourcing.md)
|
||||
@@ -117,6 +117,7 @@ The asset/content pipeline is part of the architecture, not an external build de
|
||||
| Gear/props | Blender flatpak + tool + bake | `npc_gear/*.glb`, `props/*.glb`, `*_ao.png` | `NpcAvatar`, `WorldBuilder` | primitive assets / generated props |
|
||||
| Surface/UI art | Python pipelines / AI-assisted references | `assets/textures/ai/game_ready/`, `assets/images/` | `SurfaceMaterials`, `UiArt` | neutral material / procedural UI |
|
||||
| Screenshots/QA | capture scripts + `scene_concepts`/`screen_designs` | `docs/screenshots/`, `docs/screens/realism/` | reviewers and CI gates | regenerate; never runtime input |
|
||||
| Local map data (planned) | OSM/3D building extract + licensed reference photos + AI/splat evaluation | derived map assets with provenance sidecars | `WorldBuilder` venue specs | current stylized venue geometry |
|
||||
| Release | Gitea workflow + build/publish scripts | platform binaries, Web zip, Desktop HQ zip | players | source build |
|
||||
|
||||
Contracts that keep the pipeline replaceable:
|
||||
@@ -127,6 +128,80 @@ Contracts that keep the pipeline replaceable:
|
||||
- UI/scene art is loaded through `UiArt` with a null/neutral fallback; composed images live in `assets/images/`, not in the docs reference tree (ADR-0014).
|
||||
- CI stays offline: only committed `.glb`/`.png`/`.tres` and Godot are needed; optional AI/Blender steps are reproducible development tools.
|
||||
|
||||
### Character development tooling
|
||||
|
||||
Characters have two authored sources and one procedural fallback. The eight-variant
|
||||
Blender library (`assets/models/blender/npc/`) is the normal presentation path; the
|
||||
older skinned `npc_base` (`assets/models/generated/npc_base.glb`) remains a frozen
|
||||
contract and fallback; `NpcAvatar`'s procedural rig is the offline last resort.
|
||||
Four crowd-variety prototypes have been built and audited locally but are not yet in
|
||||
the shipped catalogue; generator-first expansion is the active character track
|
||||
(ADR-0015). Blender is a developer tool 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 frozen 6,000-triangle / 4,000-vertex base contract |
|
||||
| `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` | Library cap 8,000 tris / 8,000 verts per character, 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-proportion-audit.md` | 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` |
|
||||
| `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 |
|
||||
|
||||
Runtime contracts that must survive any character change:
|
||||
|
||||
- `NpcAvatar.character_model_for(role, seed)` selects the library variant; `character_override`
|
||||
exists only to stage roles without a spawned model (for example the guard).
|
||||
- The armature node names, `Rig/Head`, the Hip/Knee/Shoulder/Elbow/Hand proxies and the
|
||||
**+Z visual front** are frozen; animation and `yaw_towards()` depend on them.
|
||||
- Only the five contract slots are tinted. Fixed detail materials (eyes, reflective bands,
|
||||
rubber) stay untouched, gear is placed by `GEAR_ATTACH`, and `GEAR_OFFSETS` plus
|
||||
`HAND_ITEM_FORWARD` are runtime attach-space corrections, not authoring changes.
|
||||
- Cloth/pants use `Materials.NPC_FABRIC_UV_SCALE` (4×) and skip the baked per-character AO;
|
||||
skin/hair/gear keep AO. Do not reintroduce the blotchy cloth AO.
|
||||
- `apply_lod()` swaps to an impostor at 26 m; the 24-NPC budget smoke (6.94 ms, 168 meshes,
|
||||
131,616 triangles) is the performance gate. Changing either triangle cap requires
|
||||
re-measuring that smoke and the Web/Compatibility path.
|
||||
- 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-proportion-audit.md`](npc-proportion-audit.md); command-level usage is in
|
||||
[`asset-tooling.md`](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
|
||||
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.
|
||||
|
||||
Planned stages and gates:
|
||||
|
||||
| Stage | Source | Output | Gate |
|
||||
| --- | --- | --- | --- |
|
||||
| Footprints and massing | Offline OpenStreetMap extract + licence-compatible 3D building data (OSM Buildings, Overture, CityGML/LOD1–2) | Local footprint/massing scenes, extract date and query pinned | ODbL attribution/share-alike review; scale/orientation and venue-footprint comparison |
|
||||
| Reference imagery | Wikimedia Commons, own/team photos or other clearly licensed images | Reference boards and material candidates | Written author/licence/attribution, privacy redaction, no unlicensed Street View or scraped commercial imagery |
|
||||
| AI-assisted composition | Project image tooling | Palette/facade-rhythm boards and material candidates | Model/prompt/output recorded; human review; never treated as licensed map data |
|
||||
| Photoreal facade kit | Project-authored geometry and derived materials | Committed facade modules and PBR maps | WorldBuilder budget, collider/nav coverage, Compatibility-readability and screenshot review |
|
||||
| Gaussian splatting | Licensed/permissioned photo sets + pinned offline toolchain | Development-only splat, texture or proxy experiments | Per-path ADR; runtime only if performance, collision/navigation and provenance are proven |
|
||||
|
||||
Contracts for any future map source:
|
||||
|
||||
- Runtime consumes committed, derived assets only; no online OSM, photo or splat
|
||||
service is a build or play dependency.
|
||||
- OSM ODbL, photo licences, capture permissions and privacy redaction are recorded
|
||||
in a provenance sidecar before an asset enters the repository.
|
||||
- Collision and navigation stay mesh-based; a splat may never become the playable
|
||||
floor or the access/occlusion authority.
|
||||
- The stylized venue geometry remains the fallback until a data-backed block passes
|
||||
the venue budget, navigation, visual and provenance gates.
|
||||
|
||||
### Content authoring and runtime data flow
|
||||
|
||||
`ScenarioFactory` is the source of truth for the three authored venues. `tools/export_venues.gd`
|
||||
@@ -272,6 +347,8 @@ Architecture decisions are recorded as ADRs:
|
||||
- Accessibility and localization coverage is partial; a public release needs subtitles/captions, colour-independent cues, remapping, text expansion tests and at least a documented localization workflow.
|
||||
- Unsigned macOS builds, AI asset provenance and any storefront/legal requirements are release blockers for a public release.
|
||||
- Documentation drift has already occurred (release version, implemented status and obsolete plan docs); the ownership map and roadmap must be kept current in the same change as the implementation.
|
||||
- Character quality is only partly automatable: proportions, budgets and gear fit are measured, but face realism and venue-lighting readability still need the baseline/review sheets and human sign-off after any mesh, map or material change.
|
||||
- Local-map data and photo-derived assets add a second provenance and privacy risk: OSM share-alike, photo rights, faces/plates, property permission and rapidly churning splat tooling must be resolved before any derived asset ships.
|
||||
|
||||
## 12. Documentation Consolidation and Ownership
|
||||
|
||||
@@ -287,11 +364,14 @@ architecture document.
|
||||
| [`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 and pipeline usage | Operational appendix to the pipeline section |
|
||||
| [`docs/blender-assets.md`](blender-assets.md) | Blender character/gear/prop contracts and attach points | Detailed asset contract appendix |
|
||||
| [`docs/npc-visual-review.md`](npc-visual-review.md) | NPC baseline views, acceptance criteria and ranked visual gaps | Visual-QA appendix to the character tooling section |
|
||||
| [`docs/npc-proportion-audit.md`](npc-proportion-audit.md) | Measured proportions against the stylized guide | Measurement appendix to the character tooling section |
|
||||
| [`docs/npc-model-sourcing.md`](npc-model-sourcing.md) | Character-source evaluation, licence rules and the character-development plan | 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/smoke-checklist.md`](smoke-checklist.md) | Manual verification script | QA appendix to §10 |
|
||||
| [`docs/development-status.md`](development-status.md) | Implemented features and current gaps | Status companion to the roadmap |
|
||||
| [`TODO.md`](../TODO.md) | Active tasks and 0.x roadmap | Planning source; no architecture duplication |
|
||||
| [`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:
|
||||
@@ -299,7 +379,7 @@ 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, including the 0.x gap analysis and milestone exit criteria.
|
||||
- **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.
|
||||
- **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
|
||||
|
||||
@@ -38,7 +38,7 @@ Audit accepts image files or directories. `--role auto` infers common roles from
|
||||
```bash
|
||||
python3 tools/asset_pipeline.py audit assets/textures
|
||||
python3 tools/asset_pipeline.py audit assets/images/scenes --role background --json
|
||||
python3 -m unittest discover -s tools -p 'test_*.py'
|
||||
python3 -m unittest discover -s tools/tests -t tools -p 'test_*.py'
|
||||
```
|
||||
|
||||
The audit classifies measurable fit issues as `good` or `bad` based on role-specific dimensions, aspect ratio, alpha requirements, and tile-edge continuity. It lists perspective/projection as a visual review item because image semantics cannot be judged reliably by these deterministic checks.
|
||||
@@ -129,6 +129,11 @@ with colliders/avoidance and drives their emissive parts from the day/night
|
||||
cycle. The single `npc_base.glb` and primitive props remain offline fallbacks.
|
||||
Contract and integration notes: [`blender-assets.md`](blender-assets.md).
|
||||
|
||||
Sourcing and expansion research (no external model is shipped yet):
|
||||
[`npc-model-sourcing.md`](npc-model-sourcing.md) compares Quaternius, Kenney, Khronos and
|
||||
MakeHuman sources against the character contract and records the 2026-11-03 direction
|
||||
(procedural generator first, Quaternius reference, MakeHuman deferred).
|
||||
|
||||
| Characters | Props |
|
||||
| --- | --- |
|
||||
|  |  |
|
||||
@@ -138,9 +143,182 @@ flatpak run org.blender.Blender --background --python "$PWD/tools/blender_assets
|
||||
flatpak run org.blender.Blender --background --python "$PWD/tools/blender_assets.py" -- render
|
||||
python3 tools/blender_assets.py sheet # docs/blender_previews/sheet_*.jpg
|
||||
python3 tools/blender_assets.py audit # no Blender needed
|
||||
python3 tools/blender_assets.py fit # gear-vs-body fit report
|
||||
python3 tools/blender_assets.py texels # per-slot texel density (px/m) of the characters
|
||||
godot --headless --path . --import
|
||||
```
|
||||
|
||||
### Intake inspection (`inspect`)
|
||||
|
||||
`audit` reads accessor-local bounds and ignores node transforms, so it is the right
|
||||
release gate but a poor first look at a downloaded or newly authored GLB. `inspect`
|
||||
imports the file into Blender, clears parents and applies object transforms, then
|
||||
reports what the scene actually contains:
|
||||
|
||||
```bash
|
||||
# one asset, a batch, or an external download; repeat --file as needed
|
||||
flatpak run org.blender.Blender --background \
|
||||
--python "$PWD/tools/blender_assets.py" -- inspect \
|
||||
--file "$PWD/assets/models/blender/npc/npc_casual.glb" \
|
||||
--file "$PWD/tmp/downloads/SomeCharacter.glb"
|
||||
# machine-readable, for intake scripts (write to a file: Blender prints a banner first)
|
||||
... -- inspect --file "$PWD/tmp/x.glb" --json --out "$PWD/tmp/x.json"
|
||||
# force a contract family instead of inferring it from the path
|
||||
... -- inspect --file "$PWD/tmp/x.glb" --category npc
|
||||
```
|
||||
|
||||
It prints triangles (with the category budget), raw and seam-split vertex counts,
|
||||
Godot-space bounds with height/feet for characters, whether transforms had to be
|
||||
applied, mesh nodes and armatures, bone names, materials, UV layers, skinning and
|
||||
animation count. Hard contract failures (`issues`) fail the command; advisory
|
||||
findings (`warnings`) do not. The category is inferred from the path:
|
||||
`blender/npc` → `npc`, `blender/npc_gear` → `npc_gear`, `blender/props` and
|
||||
`generated` → `props`, anything else → `external` (measured but with no project
|
||||
budget or rig contract).
|
||||
|
||||
Caveats:
|
||||
|
||||
- The glTF importer adds a bone-display mesh (`Icosphere`, used as
|
||||
`pose_bone.custom_shape`). `inspect` excludes custom-shape helpers so they never
|
||||
pollute bounds or the unskinned list.
|
||||
- Bounds and bone rests are converted from Blender Z-up to Godot Y-up (`x, z, -y`),
|
||||
matching the contract bands and the audit's coordinate space.
|
||||
|
||||
### Intake adaptation (`adapt`)
|
||||
|
||||
`adapt` is the mechanical first half of an external-mesh intake (MakeHuman,
|
||||
MPFB, downloaded GLB): import, apply transforms, ground the feet, weld seam
|
||||
splits, decimate to the character budget, and export a GLB. It does **not** map
|
||||
the five tint slots or rebuild the 13-bone `npc_base` armature — those stay a
|
||||
manual `retopology`/`rigging` step with a recorded second-rig contract if the
|
||||
source rig cannot be retargeted:
|
||||
|
||||
```bash
|
||||
flatpak run org.blender.Blender --background \
|
||||
--python "$PWD/tools/blender_assets.py" -- adapt \
|
||||
--file "$PWD/tmp/npc-research/makehuman_base.glb" \
|
||||
--out "$PWD/tmp/npc-research/makehuman_adapted.glb" \
|
||||
--target-tris 8000
|
||||
# prints: adapted makehuman_adapted.glb: 36972 -> 8000 tris (bones=N, meshes=1)
|
||||
```
|
||||
|
||||
Run `inspect` on the adapted GLB before and after, and keep the procedural
|
||||
generator as the fallback until a MakeHuman variant passes `audit`/`fit` and the
|
||||
24-NPC budget.
|
||||
- Numbers are Blender-side measurements. Triangles match `audit` on project assets; the seam-split
|
||||
vertex count can differ by ±1 because the importer rounds normals. `audit` stays the single final
|
||||
gate: it is stdlib-only, runs in CI, and matches what the engine imports.
|
||||
- `inspect` never writes or adapts the file; scale/grounding/weld/retarget work is the
|
||||
separate (not yet built) `adapt` step.
|
||||
- `--json` also captures the importer's INFO log in `stats.import_log` instead of printing it.
|
||||
Blender still prints its own version banner before the script runs, so intake scripts should use
|
||||
`--json --out <file>` rather than parsing stdout.
|
||||
|
||||
### Reference-anchored concept generation
|
||||
|
||||
`tools/scene_concepts.py generate --reference <photo>` anchors a concept frame on a real
|
||||
photograph: the photo is sent to the OpenRouter multimodal chat endpoint as a base64 data URL
|
||||
(`generate_textures.generate_image(reference_path=...)`) with a prompt suffix that pins the
|
||||
photographed geometry (column rhythm, band heights, signage placement, camera angle) while the
|
||||
prompt restages lighting, weather and people.
|
||||
|
||||
Licence gate: the reference must be listed in its `docs/screens/refs/<venue>/SIDECAR.md` row
|
||||
(which also supplies the licence and Commons page for provenance). A photo from anywhere else
|
||||
requires `--reference-unchecked`, which records `unchecked` in the provenance. Each anchored
|
||||
generation writes a `.refgen.json` sidecar next to the frame (`model`, reference file/licence/page,
|
||||
geometry suffix) so a concept frame can always be traced back to its evidence photo. Where a
|
||||
generated frame and its reference photo disagree, the photo wins for shape.
|
||||
|
||||
### Photo-anchored variant pass
|
||||
|
||||
`tools/scene_concepts.py anchor --reference <photo> --context "..." --treatments day,night,weathered
|
||||
--out-dir docs/screens/concepts/<block>` generates several restaged conditions (day, night,
|
||||
weathered) of one reference photo's framing, each with its `.refgen.json` provenance sidecar, so a
|
||||
concept board stays comparable with its photo board. The reference passes the same SIDECAR licence
|
||||
gate as `--reference` on `generate`.
|
||||
|
||||
### Local-only reference collection (`refcollect`)
|
||||
|
||||
`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
|
||||
is the owner-authorised local-only override (TODO.md §3D model re-evaluation → A).
|
||||
|
||||
```bash
|
||||
python3 tools/refcollect.py search "Comedy Store Sunset Boulevard" --slug comedy-store --limit 20
|
||||
python3 tools/refcollect.py sheet --slug comedy-store # local contact sheet (never committed)
|
||||
```
|
||||
|
||||
Requires `pip install duckduckgo-search` (renamed `ddgs` upstream). DuckDuckGo rate-limits by IP
|
||||
(HTTP 202), so every request — the search itself and each image download — passes through a shared
|
||||
token bucket (`--rate`, default 0.5 req/s, and `--burst`, default 3) and a polite retry routine:
|
||||
transient statuses (408/425/429/5xx/52x) and network errors back off exponentially with full
|
||||
jitter, `Retry-After` is honoured, permanent failures fail fast, and the loop gives up after six
|
||||
attempts. Requests carry a full, coherent Firefox header set (`--user-agent` overrides the UA
|
||||
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
|
||||
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.
|
||||
|
||||
```bash
|
||||
# search: keyword, geosearch (the reliable "photos of this exact place"), or category
|
||||
python3 tools/refboard.py search --source geo "34.10118|-118.34009" --limit 60 --months 12
|
||||
python3 tools/refboard.py search "El Capitan Entertainment Centre" --source search
|
||||
python3 tools/refboard.py search "Hollywood Masonic Temple" --source category --json
|
||||
# fetch the usable rows into tmp/ (review-only rows need --include-review)
|
||||
python3 tools/refboard.py search ... --json > /tmp/manifest.json
|
||||
python3 tools/refboard.py fetch --from /tmp/manifest.json --dir tmp/research/<block> --max 12
|
||||
# emit SIDECAR + README table rows from the fetched manifest
|
||||
python3 tools/refboard.py rows --from tmp/research/<block>/meta.json
|
||||
```
|
||||
|
||||
Licence gate: `Public domain`, `CC0` and `CC BY` are committable with attribution; `CC BY-SA` rows
|
||||
are flagged `review` and stay research-only until the share-alike decision is written into the
|
||||
sidecar (`--allow-ccbysa` marks them committable after that review); anything else is skipped.
|
||||
`--months 12` flags recent captures so a "current reality" photo can be distinguished from the
|
||||
older geometry evidence. Network gotchas baked in: a descriptive User-Agent, batched `titles=`
|
||||
metadata queries and ~3 s download spacing to avoid Commons HTTP 429s.
|
||||
|
||||
### Texel density (`texels`)
|
||||
|
||||
`texel_density()` and the `texels` command compute `resolution * sqrt(UV area / world area)` per
|
||||
material slot straight from the GLB, so the number does not depend on island packing. The NPC slot
|
||||
maps are 256², and cloth/pants are reported twice: authored density and effective density with the
|
||||
runtime 4× repeat from `Materials.NPC_FABRIC_UV_SCALE`. Current values and interpretation are in
|
||||
[`3d-model-review.md`](3d-model-review.md).
|
||||
|
||||
```bash
|
||||
python3 tools/blender_assets.py texels # all eight characters
|
||||
python3 tools/blender_assets.py texels --json # machine-readable
|
||||
python3 tools/blender_assets.py texels --only npc_coat
|
||||
```
|
||||
|
||||
## Local map development (planned)
|
||||
|
||||
The local map workstreams (**H–M**) in [`TODO.md`](../TODO.md#3d-model-re-evaluation)
|
||||
are not implemented yet; there are no map-generation commands to run. The planned
|
||||
pipeline will evaluate:
|
||||
|
||||
- offline OpenStreetMap extracts for footprints and licence-compatible 3D building
|
||||
massing (OSM Buildings, Overture, CityGML/LOD1–2);
|
||||
- downloaded reference imagery from Wikimedia Commons, own/team photography or
|
||||
other clearly licensed sources, with author/licence/attribution and privacy
|
||||
redaction recorded per set;
|
||||
- AI-assisted composition boards for palette, facade rhythm and material study,
|
||||
with model/prompt/output provenance and human acceptance;
|
||||
- Gaussian splatting as a development-only capture/reference/texture/proxy tool,
|
||||
version-pinned offline and outside CI, until an ADR proves runtime safety.
|
||||
|
||||
No online map/photo/splat service is a build or play dependency. Committed map
|
||||
assets will need provenance sidecars, ODbL/photo-licence review and the same
|
||||
`WorldBuilder` venue-budget/navigation/collider gates as the current stylized
|
||||
geometry. The detailed task plan and exit criteria live in `TODO.md`.
|
||||
|
||||
## Confirmed game assets
|
||||
|
||||
Everything below is audited and shipped in the game; development-only outputs
|
||||
@@ -199,6 +377,16 @@ and ranks them by advertised token/image price. The run falls through the list
|
||||
on provider/model errors and aborts on an invalid key. Use
|
||||
`GIG_LINE_JUDGE_MODEL` or `--model <id>` for a pinned comparison.
|
||||
|
||||
For an open-ended review of a single capture/reference (no structured verdict),
|
||||
`tools/describe_image.py` sends the image plus a question to a vision model and
|
||||
prints the answer. It is how the 2026-11-03 re-evaluation read the local-only
|
||||
reference frames and the prop/venue captures:
|
||||
|
||||
```bash
|
||||
python3 tools/describe_image.py docs/screenshots/12-joke-shop.png \
|
||||
--question "Do the red curtain bays read as tied-back fabric or flat slabs?"
|
||||
```
|
||||
|
||||
`capture_npc_review.gd` is the pre-build NPC gate: it stages all eight
|
||||
library character models at portrait, conversation and crowd distance on both
|
||||
promoted maps in day and night lighting, with the normal crowd hidden. It uses
|
||||
@@ -221,6 +409,22 @@ height/head/shoulder/hip/torso/leg/arm/foot guide; the current results are in
|
||||
[`npc-proportion-audit.md`](npc-proportion-audit.md). 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,
|
||||
walk-contact, walk-pass and seated poses of all eight variants, full-body plus shoulder
|
||||
close-ups. **It is currently blocked**: the applied pose is visible in the rig and bone values
|
||||
but not in the captured frames, so do not use its sheets as pose evidence. The reproduction and
|
||||
what was ruled out are in [`3d-model-review.md`](3d-model-review.md) §"Pose evidence is blocked".
|
||||
|
||||
The baseline sheet tool accepts a custom view list, which is also how pose sheets are tiled:
|
||||
|
||||
```bash
|
||||
# baseline set (six views, eight variants)
|
||||
python3 tools/npc_baseline.py sheet --dir tmp/npc-baseline
|
||||
# pose set produced by capture_npc_pose.gd
|
||||
python3 tools/npc_baseline.py sheet --dir tmp/npc-pose \
|
||||
--views idle,walk_contact,walk_pass,sit --out tmp/npc-pose/sheet_pose.jpg
|
||||
```
|
||||
|
||||
`capture_npc_baseline.gd` is the 0.9.4 neutral baseline: eight characters ×
|
||||
front/three-quarter/profile/back/full-body/crowd = 48 frames with a fixed
|
||||
camera, studio lighting and no venue/HUD/animation. The raw PNGs stay in
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
# Release-candidate balance acceptance
|
||||
|
||||
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.
|
||||
|
||||
## Test matrix and evidence
|
||||
|
||||
Run Hollywood, Joke Shop and TV Studio on easy, normal and hard, in Early,
|
||||
Midday, Evening and Late: **36 cells**. Use seeds 1–100 for each cell and retain
|
||||
those seeds for before/after comparisons. Exercise each eligible authored event
|
||||
at least once as a separate coverage pass; a random schedule can miss rare events.
|
||||
Record scheduled event counts separately from forced coverage cases so the latter
|
||||
do not distort event-frequency estimates.
|
||||
|
||||
For reaction measurements, use a fresh controller at the entrance for each sample.
|
||||
Routine cases are tourists, confused visitors and delivery workers obstructing the
|
||||
entrance without threatening behavior. Do not include authorized entry requests in
|
||||
this redirect cohort. For peaceful-resolution measurements, send one polite
|
||||
direction (L1), then one warning (L2) only if still unresolved. Do not reroll until
|
||||
success. Observe return behavior for 60 simulated seconds before closing the case.
|
||||
Do not issue emergency calls as part of this policy.
|
||||
|
||||
For access cases, follow the venue's required inspection and screening steps before
|
||||
allow/deny. Include valid, expired, counterfeit, mismatched, missing and ambiguous
|
||||
artifacts, known recognition, age boundaries, screening refusal, benign wand alerts
|
||||
and prohibited items. Recognition must be independently justified by the fixture;
|
||||
calling a stranger recognized is not evidence of correct admission. An unresolved
|
||||
hold counts as unresolved, not as a correct refusal.
|
||||
|
||||
Evidence must identify the commit, engine, venue, difficulty, phase, seed, event ID,
|
||||
cohort, visible evidence, policy action, reaction/state, return, access truth and
|
||||
decision, emergency truth and call, report fields, reputation modifiers, final grade
|
||||
and unresolved cases. Save raw rows plus numerator/denominator summaries for every
|
||||
cell. Use at least **100 eligible cases per metric per cell**; if the schedule
|
||||
provides fewer, add a separately labelled forced-case sample. Report zero eligible
|
||||
cases as **N/A**, never as 100% success. Keep scheduled and forced results separate.
|
||||
|
||||
## Targets
|
||||
|
||||
Percentages below apply to each matrix cell, not only a pooled average. Scripted
|
||||
access/report cases use complete evidence and are held to exact correctness;
|
||||
first-time-player results measure whether that evidence is understandable.
|
||||
|
||||
| Metric | Numerator / denominator | Acceptance target |
|
||||
| --- | --- | --- |
|
||||
| First-direction routine compliance | First L1 reaction is `COMPLY` or `LEAVE` / eligible routine redirect cases | Easy ≥80%; normal ≥75%; hard ≥65% |
|
||||
| Routine peaceful resolution | Routine cases leaving after at most L1 then L2, with no return during 60 s and no L3–L5 / eligible routine redirect cases | Easy ≥90%; normal ≥85%; hard ≥80% |
|
||||
| Access accuracy | Correct final allow/deny decisions / all eligible access cases (including unresolved cases) | Scripted 100%; first-time players ≥90% pooled, with each error reviewed |
|
||||
| Access false positive | Unauthorized people allowed / unauthorized access cases | Scripted 0%; first-time players ≤5% pooled |
|
||||
| Access false negative | Authorized people denied / authorized access cases | Scripted 0%; first-time players ≤10% pooled |
|
||||
| Emergency precision | Calls supported by immediate-danger evidence / all emergency calls | Scripted 100%; first-time players ≥95% pooled; zero calls is N/A |
|
||||
| Emergency false positive | Routine/no-immediate-danger cases receiving an emergency call / all routine/no-immediate-danger cases | Scripted 0%; first-time players ≤5% pooled |
|
||||
| Emergency false negative | Immediate-danger cases without an accepted emergency call within 15 simulated seconds of visible danger / all immediate-danger cases with radio initially available | Scripted 0%; first-time players ≤10% pooled |
|
||||
| Report accuracy | Reports with correct weapon and danger fields / all submitted reports | Scripted 100%; first-time players ≥90% pooled |
|
||||
|
||||
For access, authorized means entitled under the venue policy **after required
|
||||
screening**, without a prohibited item or an independent immediate-danger reason
|
||||
to refuse. Compare to a hand-labelled fixture expectation, not only to
|
||||
`AccessVerifier.verify()`: using the verifier as both decision and oracle would
|
||||
hide policy bugs. Report unresolved access cases separately; they cannot improve
|
||||
either error rate by being omitted from accuracy.
|
||||
|
||||
Immediate danger means an observed weapon, assault, active forced entry or a
|
||||
credible immediate threat to occupants. Argument, filming, intoxication, a crisis,
|
||||
a refused screen or a benign wand alert alone is not immediate danger. A mental
|
||||
health label or clothing must never be used as the emergency oracle. The 15 s
|
||||
window is a test-response target, not the responder-arrival time (currently 15 s
|
||||
after an accepted emergency call). Separately test depleted battery and active
|
||||
cooldown cases for safe containment/assistance; do not silently drop them from the
|
||||
evidence or claim the initially-available-radio target covers them.
|
||||
|
||||
## Scoring and emergency dominance
|
||||
|
||||
Compare the calm policy with an emergency-first policy on the same routine events
|
||||
and seeds. Each comparison starts with fresh radio, crowd and reputation state.
|
||||
An accurate report about harmless behavior must not make its emergency call
|
||||
justified. Require an unjustified-call investigation and a strictly lower rating
|
||||
for emergency-first in every routine comparison. Inspect modifiers as well as the
|
||||
final rating: the 0–100 clamp can hide rewards/penalties. Emergency-first must not
|
||||
improve the campaign outcome or final grade. Grade boundaries remain A ≥90,
|
||||
B ≥75, C ≥60, D ≥40, otherwise F; these are existing rules, not new tuning.
|
||||
|
||||
In genuine-danger cases, verify that the call is accepted, responders arrive,
|
||||
the incident remains answerable and the debrief explains the outcome without an
|
||||
unjustified-call investigation. Also compare assistance/containment routes where
|
||||
appropriate; emergency need not be mandatory for every difficult interaction.
|
||||
|
||||
## Implementation cautions and sign-off
|
||||
|
||||
- `NPCController.roll_reaction()` samples per-level weights. Difficulty adds
|
||||
+12/0/−8 to the `COMPLY` weight before normalization; `base_compliance` alone
|
||||
is not the observed compliance percentage. Measure `COMPLY` plus `LEAVE`.
|
||||
- `GameManager._read_npc_truth()` currently derives weapon/danger truth from the
|
||||
NPC type (violent threat: weapon/3; everyone else: no weapon/1), rather than
|
||||
observed behavior. This is a balance-review risk: test nonviolent profiles that
|
||||
threaten or force entry, and violent profiles before visible danger. Do not
|
||||
treat agreement with this helper as proof of fair emergency judgment.
|
||||
- `RadioSystem.credibility_hits()` checks weapon and danger fields only;
|
||||
location, description and behavior still need human review. Difficulty scales
|
||||
report penalties, not the oracle.
|
||||
- A terminal peaceful reaction is not sufficient evidence of an incident staying
|
||||
resolved: returning NPCs and unresolved shift-review entries must be retained.
|
||||
|
||||
Do not tune to a pooled average that hides a failing venue, phase or difficulty.
|
||||
Record each miss, its severity, the raw evidence and any approved exception before
|
||||
changing weights. Re-run the affected cells and tutorial/campaign smokes after a
|
||||
fix. Five first-time-player sessions must cover the tutorial and a complete venue
|
||||
shift; report pooled counts and per-session errors, not statistical confidence
|
||||
from five players. Scripted sweeps do not substitute for those sessions.
|
||||
|
||||
**Status:** targets defined; sweeps, emergency fairness review, grade/campaign
|
||||
verification and external-player acceptance remain pending. No balance sign-off
|
||||
or release approval is implied by this document.
|
||||
@@ -21,7 +21,7 @@ captures in `docs/screenshots/`.
|
||||
|
||||
- **People** (`targeting_npc`, `joke_shop_queue`, `studio_arrival`,
|
||||
`crowd_panic`, `responder_arrival`): ordinary adults in sweaters, jackets,
|
||||
long coats, hoodies and beanies; a security guard in a dark uniform with a cap
|
||||
long coats and hoodies; a security guard in a dark uniform with a cap
|
||||
and belt; a firefighter in a dark turnout coat with yellow reflective bands,
|
||||
a helmet and an SCBA tank. The current skinned `npc_base` is a set of boxes
|
||||
and cylinders with a flat face, so silhouette was the main gap.
|
||||
@@ -47,7 +47,11 @@ flatpak run org.blender.Blender --background \
|
||||
python3 tools/blender_assets.py sheet # -> docs/blender_previews/sheet_<category>.jpg
|
||||
python3 tools/blender_assets.py audit # stdlib only; exit 1 on any issue
|
||||
python3 tools/blender_assets.py fit # head/clothing fit + bag-body clearance, per character
|
||||
python3 tools/blender_assets.py texels # 256² slot-map density (authored + 4× fabric), per character
|
||||
python3 tools/blender_assets.py list
|
||||
# import a GLB, apply node transforms, report geometry/bones/UVs/skinning + contract failures
|
||||
flatpak run org.blender.Blender --background \
|
||||
--python "$PWD/tools/blender_assets.py" -- inspect --file "$PWD/tmp/downloads/x.glb"
|
||||
godot --headless --path . --import # after any rebuild
|
||||
```
|
||||
|
||||
@@ -141,7 +145,7 @@ attach point:
|
||||
|
||||
| Attach | Godot parent / position | Gear |
|
||||
| --- | --- | --- |
|
||||
| `head` | `Rig/Head` marker (0, 1.62, 0) | cap, beanie, hood, sunglasses, firefighter_helmet |
|
||||
| `head` | `Rig/Head` marker (0, 1.62, 0) | cap, hood, sunglasses, firefighter_helmet |
|
||||
| `back` | `Rig` at (0, 1.10, 0), spine centre; items sit behind the body (Blender +Y = Godot −Z) | backpack, shoulder_bag, scba_tank |
|
||||
| `chest` | `Rig` at (0, 1.30, 0), sternum | lanyard |
|
||||
| `hand` | Hand proxy (±0.27, 0.78, 0.02); grip 5 cm below the origin | phone, cup, clipboard, umbrella, camera, protest_sign, flashlight, wand, radio |
|
||||
@@ -184,13 +188,19 @@ carry baked AO and the shared neutral material maps described above.
|
||||
during LOD generation), budgets (library characters 8000/8000, base fallback 6000/4000, gear 1500, props 4000
|
||||
triangles), grounding, and an editable `.blend`. For characters it also
|
||||
checks skinning, bones, slots, the `npc_base` mesh node and the height.
|
||||
- `tools/test_blender_assets.py`: catalogue and contract consistency with
|
||||
`npc_pipeline.py`, plus a clean audit and full manifest coverage when the
|
||||
library is built.
|
||||
- `tools/tests/test_blender_assets.py`: catalogue and contract consistency with
|
||||
`npc_pipeline.py`, plus a clean audit, a texel-density gate (all five slots,
|
||||
40–400 px/m authored, 250 px/m fabric floor) and full manifest coverage when
|
||||
the library is built.
|
||||
- `src/test/tests/test_blender_assets.gd`: every asset imports as a scene
|
||||
with geometry, characters keep their bones and slots, joints match
|
||||
`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).
|
||||
- `src/test/tests/test_world.gd`: every library prop that blocks walking has a
|
||||
`StaticBody3D` + `NavigationObstacle3D`, checked against the catalogue
|
||||
(collider/proxy gate).
|
||||
|
||||
## Known limitations
|
||||
|
||||
@@ -206,6 +216,8 @@ carry baked AO and the shared neutral material maps described above.
|
||||
stay neutral.
|
||||
- The 0.9.4 baseline found three P1 portrait issues. The tourist's photo prop
|
||||
now only appears in photo/film poses and the backpack straps were refit as
|
||||
flattened chest bands; the face is still shallow/faceted at portrait range.
|
||||
The full ranked list, measurements and before/after sheet are in
|
||||
[`npc-visual-review.md`](npc-visual-review.md).
|
||||
flattened chest bands. The face carries the 0.9.4 sculpt (socketed sclera,
|
||||
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).
|
||||
@@ -1,69 +1,31 @@
|
||||
# Blender Previews
|
||||
# Blender previews
|
||||
|
||||
Committed contact sheets and local Blender renders for the character, gear and prop library. Individual PNGs are development previews and are gitignored; the sheets are tracked.
|
||||
Committed contact sheets for the character, gear and prop library. Per-asset Cycles renders
|
||||
(`*.png`) are local development output and gitignored; the sheets below are the review artefacts
|
||||
and are built with `blender_assets.py render` + `sheet`, `npc_baseline.py sheet/compare`, or the
|
||||
capture harnesses.
|
||||
|
||||
## Image previews
|
||||
|
||||
| Preview | File |
|
||||
| Sheet | What it records |
|
||||
| --- | --- |
|
||||
| <img src="a_frame_sign.png" width="280" alt="a_frame_sign.png"> | [`a_frame_sign.png`](a_frame_sign.png) |
|
||||
| <img src="backpack.png" width="280" alt="backpack.png"> | [`backpack.png`](backpack.png) |
|
||||
| <img src="beanie.png" width="280" alt="beanie.png"> | [`beanie.png`](beanie.png) |
|
||||
| <img src="bench.png" width="280" alt="bench.png"> | [`bench.png`](bench.png) |
|
||||
| <img src="bollard.png" width="280" alt="bollard.png"> | [`bollard.png`](bollard.png) |
|
||||
| <img src="camera.png" width="280" alt="camera.png"> | [`camera.png`](camera.png) |
|
||||
| <img src="cap.png" width="280" alt="cap.png"> | [`cap.png`](cap.png) |
|
||||
| <img src="clipboard.png" width="280" alt="clipboard.png"> | [`clipboard.png`](clipboard.png) |
|
||||
| <img src="crowd_barrier.png" width="280" alt="crowd_barrier.png"> | [`crowd_barrier.png`](crowd_barrier.png) |
|
||||
| <img src="cup.png" width="280" alt="cup.png"> | [`cup.png`](cup.png) |
|
||||
| <img src="double_door.png" width="280" alt="double_door.png"> | [`double_door.png`](double_door.png) |
|
||||
| <img src="fire_hydrant.png" width="280" alt="fire_hydrant.png"> | [`fire_hydrant.png`](fire_hydrant.png) |
|
||||
| <img src="firefighter_helmet.png" width="280" alt="firefighter_helmet.png"> | [`firefighter_helmet.png`](firefighter_helmet.png) |
|
||||
| <img src="flashlight.png" width="280" alt="flashlight.png"> | [`flashlight.png`](flashlight.png) |
|
||||
| <img src="handrail.png" width="280" alt="handrail.png"> | [`handrail.png`](handrail.png) |
|
||||
| <img src="hood.png" width="280" alt="hood.png"> | [`hood.png`](hood.png) |
|
||||
| <img src="lanyard.png" width="280" alt="lanyard.png"> | [`lanyard.png`](lanyard.png) |
|
||||
| <img src="marquee.png" width="280" alt="marquee.png"> | [`marquee.png`](marquee.png) |
|
||||
| <img src="newspaper_box.png" width="280" alt="newspaper_box.png"> | [`newspaper_box.png`](newspaper_box.png) |
|
||||
| <img src="npc_casual.png" width="280" alt="npc_casual.png"> | [`npc_casual.png`](npc_casual.png) |
|
||||
| <img src="npc_coat.png" width="280" alt="npc_coat.png"> | [`npc_coat.png`](npc_coat.png) |
|
||||
| <img src="npc_dress.png" width="280" alt="npc_dress.png"> | [`npc_dress.png`](npc_dress.png) |
|
||||
| <img src="npc_firefighter.png" width="280" alt="npc_firefighter.png"> | [`npc_firefighter.png`](npc_firefighter.png) |
|
||||
| <img src="npc_guard.png" width="280" alt="npc_guard.png"> | [`npc_guard.png`](npc_guard.png) |
|
||||
| <img src="npc_hoodie.png" width="280" alt="npc_hoodie.png"> | [`npc_hoodie.png`](npc_hoodie.png) |
|
||||
| <img src="npc_jacket.png" width="280" alt="npc_jacket.png"> | [`npc_jacket.png`](npc_jacket.png) |
|
||||
| <img src="npc_vest.png" width="280" alt="npc_vest.png"> | [`npc_vest.png`](npc_vest.png) |
|
||||
| <img src="palm_tree.png" width="280" alt="palm_tree.png"> | [`palm_tree.png`](palm_tree.png) |
|
||||
| <img src="phone.png" width="280" alt="phone.png"> | [`phone.png`](phone.png) |
|
||||
| <img src="planter_box.png" width="280" alt="planter_box.png"> | [`planter_box.png`](planter_box.png) |
|
||||
| <img src="protest_sign.png" width="280" alt="protest_sign.png"> | [`protest_sign.png`](protest_sign.png) |
|
||||
| <img src="radio.png" width="280" alt="radio.png"> | [`radio.png`](radio.png) |
|
||||
| <img src="round_planter.png" width="280" alt="round_planter.png"> | [`round_planter.png`](round_planter.png) |
|
||||
| <img src="scba_tank.png" width="280" alt="scba_tank.png"> | [`scba_tank.png`](scba_tank.png) |
|
||||
| <img src="security_podium.png" width="280" alt="security_podium.png"> | [`security_podium.png`](security_podium.png) |
|
||||
| <img src="sedan.png" width="280" alt="sedan.png"> | [`sedan.png`](sedan.png) |
|
||||
| <img src="sheet_npc.jpg" width="280" alt="sheet_npc.jpg"> | [`sheet_npc.jpg`](sheet_npc.jpg) |
|
||||
| <img src="sheet_npc_baseline.jpg" width="280" alt="sheet_npc_baseline.jpg"> | [`sheet_npc_baseline.jpg`](sheet_npc_baseline.jpg) |
|
||||
| <img src="sheet_npc_baseline_compare-p1.jpg" width="280" alt="sheet_npc_baseline_compare-p1.jpg"> | [`sheet_npc_baseline_compare-p1.jpg`](sheet_npc_baseline_compare-p1.jpg) |
|
||||
| <img src="sheet_npc_baseline_compare-body.jpg" width="280" alt="sheet_npc_baseline_compare-body.jpg"> | [`sheet_npc_baseline_compare-body.jpg`](sheet_npc_baseline_compare-body.jpg) |
|
||||
| <img src="sheet_npc_baseline_compare-face.jpg" width="280" alt="sheet_npc_baseline_compare-face.jpg"> | [`sheet_npc_baseline_compare-face.jpg`](sheet_npc_baseline_compare-face.jpg) |
|
||||
| <img src="sheet_npc_baseline_compare-torso.jpg" width="280" alt="sheet_npc_baseline_compare-torso.jpg"> | [`sheet_npc_baseline_compare-torso.jpg`](sheet_npc_baseline_compare-torso.jpg) |
|
||||
| <img src="sheet_npc_baseline_compare-face-detail.jpg" width="280" alt="sheet_npc_baseline_compare-face-detail.jpg"> | [`sheet_npc_baseline_compare-face-detail.jpg`](sheet_npc_baseline_compare-face-detail.jpg) |
|
||||
| <img src="sheet_npc_hands_compare.jpg" width="280" alt="sheet_npc_hands_compare.jpg"> | [`sheet_npc_hands_compare.jpg`](sheet_npc_hands_compare.jpg) |
|
||||
| <img src="sheet_npc_hands_grip_compare.jpg" width="280" alt="sheet_npc_hands_grip_compare.jpg"> | [`sheet_npc_hands_grip_compare.jpg`](sheet_npc_hands_grip_compare.jpg) |
|
||||
| <img src="sheet_npc_baseline_compare-shoes.jpg" width="280" alt="sheet_npc_baseline_compare-shoes.jpg"> | [`sheet_npc_baseline_compare-shoes.jpg`](sheet_npc_baseline_compare-shoes.jpg) |
|
||||
| <img src="sheet_npc_baseline_compare-tex256.jpg" width="280" alt="sheet_npc_baseline_compare-tex256.jpg"> | [`sheet_npc_baseline_compare-tex256.jpg`](sheet_npc_baseline_compare-tex256.jpg) |
|
||||
| <img src="sheet_npc_baseline_compare-texuv.jpg" width="280" alt="sheet_npc_baseline_compare-texuv.jpg"> | [`sheet_npc_baseline_compare-texuv.jpg`](sheet_npc_baseline_compare-texuv.jpg) |
|
||||
| <img src="sheet_texture_refinement_0.9.5.jpg" width="280" alt="sheet_texture_refinement_0.9.5.jpg"> | [`sheet_texture_refinement_0.9.5.jpg`](sheet_texture_refinement_0.9.5.jpg) |
|
||||
| <img src="sheet_npc_gear.jpg" width="280" alt="sheet_npc_gear.jpg"> | [`sheet_npc_gear.jpg`](sheet_npc_gear.jpg) |
|
||||
| <img src="sheet_props.jpg" width="280" alt="sheet_props.jpg"> | [`sheet_props.jpg`](sheet_props.jpg) |
|
||||
| <img src="shoulder_bag.png" width="280" alt="shoulder_bag.png"> | [`shoulder_bag.png`](shoulder_bag.png) |
|
||||
| <img src="stanchion.png" width="280" alt="stanchion.png"> | [`stanchion.png`](stanchion.png) |
|
||||
| <img src="street_lamp.png" width="280" alt="street_lamp.png"> | [`street_lamp.png`](street_lamp.png) |
|
||||
| <img src="street_tree.png" width="280" alt="street_tree.png"> | [`street_tree.png`](street_tree.png) |
|
||||
| <img src="sunglasses.png" width="280" alt="sunglasses.png"> | [`sunglasses.png`](sunglasses.png) |
|
||||
| <img src="traffic_cone.png" width="280" alt="traffic_cone.png"> | [`traffic_cone.png`](traffic_cone.png) |
|
||||
| <img src="trash_bin.png" width="280" alt="trash_bin.png"> | [`trash_bin.png`](trash_bin.png) |
|
||||
| <img src="umbrella.png" width="280" alt="umbrella.png"> | [`umbrella.png`](umbrella.png) |
|
||||
| <img src="wall_lantern.png" width="280" alt="wall_lantern.png"> | [`wall_lantern.png`](wall_lantern.png) |
|
||||
| <img src="wand.png" width="280" alt="wand.png"> | [`wand.png`](wand.png) |
|
||||
| [](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_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. |
|
||||
| [](sheet_npc_baseline_compare-p1.jpg) <br> `sheet_npc_baseline_compare-p1.jpg` | 0.9.4 P1 pass: tourist photo-prop visibility and the refit backpack straps. |
|
||||
| [](sheet_npc_baseline_compare-shoes.jpg) <br> `sheet_npc_baseline_compare-shoes.jpg` | Footwear: rounded toe/heel caps on shoes and responder boots. |
|
||||
| [](sheet_npc_baseline_compare-tex256.jpg) <br> `sheet_npc_baseline_compare-tex256.jpg` | 128 -> 256 px NPC slot maps on the same camera. |
|
||||
| [](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_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_npc_sources_research.jpg) <br> `sheet_npc_sources_research.jpg` | External character-source evaluation (CC0/CC-BY) for the roster research. |
|
||||
| [](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-proportion-audit.md`](../npc-proportion-audit.md) and
|
||||
[`../3d-model-review.md`](../3d-model-review.md), and the asset contract in
|
||||
[`../blender-assets.md`](../blender-assets.md).
|
||||
|
Before Width: | Height: | Size: 268 KiB After Width: | Height: | Size: 405 KiB |
|
After Width: | Height: | Size: 36 KiB |
|
After Width: | Height: | Size: 55 KiB |
@@ -1,11 +1,18 @@
|
||||
# Development Status
|
||||
|
||||
Current planning priorities are the unversioned **3D model and local map re-evaluation** and
|
||||
**Character development** tracks in [`TODO.md`](../TODO.md); none is part of the implemented list
|
||||
below yet. The re-evaluation scores the existing characters, gear, props and
|
||||
venues against the locally installed Blender skill guidance before the roster expands. The 0.10.0
|
||||
release candidate remains the next versioned release.
|
||||
|
||||
Implemented so far:
|
||||
|
||||
- 3D re-evaluation — facade and prop pass (unversioned, 2026-11-03): the Masonic/El Capitan facade uses the photo-anchored `limestone_ashlar` field and warm-tinted stone; the TV Studio reuses `masonic_facade` (same Jimmy Kimmel starting point); the Joke Shop canopy signature band is white over black, the red curtain bays are seven tied-back hourglass drapes, and the hall wall uses `dark_stucco`. The `fire_hydrant` was rebuilt with a bolted flange, bonnet cap nut and larger outlets; `bollard` gained a flared base collar and `newspaper_box` a recessed window slot and door seam. A venue light-falloff gate asserts physical attenuation, and `tools/describe_image.py` adds free-form vision review alongside the structured judges. The scorecard, measurements and accepted limits are in [`3d-model-review.md`](3d-model-review.md).
|
||||
- Godot 4.7.2 project scaffold, input map, procedural world builder (CI/local/release unified)
|
||||
- Venue-driven simulation core: `ShiftCoordinator`, `VenueScenario`, `EventScheduler`, `NPCController` + FSM, `AccessVerifier`, `EscalationManager`, `RadioSystem`, `IncidentRecorder`, `ReputationEvaluator`, `CrowdSystem`
|
||||
- Three authored scenarios (El Capitan Entertainment Centre / Hollywood Boulevard, The Joke Shop, Late Night TV Studio) with access policies, NPC archetypes, and event pools
|
||||
- Headless unit tests: **272 passing** (access rules and venue-correct access loadout, escalation, radio cooldown/battery, NPC reaction determinism, door lock, flashlight perception, persistence round-trip, settings round-trip, input remaps, navmesh, step colliders, skyline alpha, scenario data, full-shift simulation, wand screening, responder dispatch, localization strings, focus cone, action wheel, session shell, PLAN verbs and incident recording, crowd presentation, emergency aftermath, body-camera timeline, NPC theater poses, audio, accessibility, authored scenario content, string formatting, `.tres` venue round-trip, surface materials and environment, focus ranking and outfit/gait helpers, generated prop models, web export preset, prop atlas material, player movement, NPC character layers/LOD/queue, input bindings)
|
||||
- Headless unit tests: **277 passing** (access rules and venue-correct access loadout, escalation, radio cooldown/battery, NPC reaction determinism, door lock, flashlight perception, persistence round-trip, settings round-trip, input remaps, navmesh, step colliders, skyline alpha, scenario data, full-shift simulation, wand screening, responder dispatch, localization strings, focus cone, action wheel, session shell, PLAN verbs and incident recording, crowd presentation, emergency aftermath, body-camera timeline, NPC theater poses, audio, accessibility, authored scenario content, string formatting, `.tres` venue round-trip, surface materials and environment, focus ranking and outfit/gait helpers, generated prop models, web export preset, prop atlas material, player movement, NPC character layers/LOD/queue, input bindings, venue light-falloff gate, prop collider coverage)
|
||||
- Simulation extras: protester archetype, CALL_SOMEONE reaction, door lock/secure mechanic (visual indicator), flashlight with night perception bonus, LATE shift phase reaching the violent-threat event
|
||||
- First-person prototype with interaction HUD, access inspection, wand screening, radio report form (incl. emergency hold-to-confirm), dispatched responder avatars, aim-free targeting, venue cycling between all three scenarios, color-coded escalation feedback, procedural audio cues, navigation-mesh NPC paths, JSON-backed localized strings, persisted shift history, debug overlay, and shift review
|
||||
- Control pass: focus cone on NPC heads with a billboarded blue circle in front of the face and name, action wheel (LMB/Space) with de-escalation-first slices, mouse-look freeze while a panel is open, acceleration-based walking, and named input actions (`action_menu`, `confirm`, `cancel`, `inspect`, `wand`)
|
||||
@@ -44,7 +51,8 @@ Implemented so far:
|
||||
- NPC torso/hip transition (0.9.4 work): the pelvis and chest are slightly wider than the waist, giving shirts and jackets a readable taper into the hips without changing the build multipliers or the skeleton. The comparison is `sheet_npc_baseline_compare-torso.jpg`.
|
||||
- Release v0.9.6 (2026-11-03): the tagged commit `4bb2896` passed Gitea Actions run 1296 (checks + full build) and published seven artifacts (Linux, Windows, macOS, NSIS setup, AppImage, Web and Desktop HQ). Release page: <https://git.allucanget.biz/zwitschi/security-game/releases/tag/v0.9.6>.
|
||||
- Release candidate (0.10.0-rc.1, 2026-11-03): clean worktree `a9658ec` built Linux 161.5 MB, Windows 197.2 MB, macOS 148.0 MB, Web 97.8 MB and Desktop HQ 241.6 MB. The Web/HQ archives contain `CREDITS.md`, `PRIVACY.md`, `docs/accessibility.md` and `docs/known-limitations.md`; SHA-256 checksums were generated, the Linux and HQ binaries launched headless, and the Web index/wasm/pck/docs served with HTTP 200. The candidate is not published: external playtest, AI-provider/legal approval, macOS signing and the Windows/macOS target matrix remain open blockers.
|
||||
- Save migration and reliability (0.10.0 work): committed 0.8-era settings/campaign/history fixtures and a 0.9.0 checkpoint. The loader default-fills old settings, keeps campaign progress and validates checkpoints for all three venues with an open incident, NPC rows, door, flashlight and body-camera state. Corrupt and partial files fall back to defaults; a blocked atomic replace leaves the prior valid file intact. `_load_json` uses the non-logging JSON parser; save locations and rollback are documented in `getting-started.md`. Suite is 272/272.
|
||||
- Save migration and reliability (0.10.0 work): committed 0.8-era settings/campaign/history fixtures and a 0.9.0 checkpoint. The loader default-fills old settings, keeps campaign progress and validates checkpoints for all three venues with an open incident, NPC rows, door, flashlight and body-camera state. Corrupt and partial files fall back to defaults; a blocked atomic replace leaves the prior valid file intact. `_load_json` uses the non-logging JSON parser; save locations and rollback are documented in `getting-started.md`. Suite is 277/277;
|
||||
Python tooling is 161/161 after the GLB `inspect` intake coverage.
|
||||
- Integration checkpoint (0.9.6 work): the clean worktree at `f5b8ef2` rebuilt all five release packages and the Desktop HQ zip without ignored `tmp/`/`build/` content (Linux 161.5 MB, Windows 197.1 MB, macOS 148.0 MB, Web 97.8 MB, HQ 241.5 MB). The Web zip contains `index.html`, `index.wasm` and `index.pck`; the HQ zip contains `override.cfg` and launches headless with the Forward+ override. Current verification: Godot 263/263, Python 101/101, 14 smokes green, 24-NPC budget 6.90 ms / 168 meshes / 131,616 triangles, gallery 21 good / 0 bad, screen judge 21/21 match with 0 review/diff, and a pinned realism judge (`z-ai/glm-5.3-flash`, one pass per shot) at mean overall 2.1 and Pillow gap 0.291. No new gameplay or content changes.
|
||||
- Release v0.9.5 (2026-11-02): the tagged commit `4bc6390` passed Gitea Actions run 922 (checks + full build) and published seven artifacts (Linux, Windows, macOS, NSIS setup, AppImage, Web and Desktop HQ). Release page: <https://git.allucanget.biz/zwitschi/security-game/releases/tag/v0.9.5>.
|
||||
- Release v0.9.4 (2026-11-02): the tagged commit `a57b86c` passed the Gitea checks and full build and published seven artifacts (Linux, Windows, macOS, NSIS setup, AppImage, Web and Desktop HQ). Release page: <https://git.allucanget.biz/zwitschi/security-game/releases/tag/v0.9.4>.
|
||||
@@ -54,6 +62,8 @@ Implemented so far:
|
||||
- Texture visual verification (0.9.5 work): the nine-stage realism run used `z-ai/glm-5.3-flash` once per shot; mean `after` scores were overall 1.8, lighting 2.3, materials 1.8, texture detail 1.2, backdrop 2.0 and characters 1.2, with a Pillow metric gap of 0.306. The judge remains an optional review aid, not a CI gate. The committed before/after close-up sheet is [`blender_previews/sheet_texture_refinement_0.9.5.jpg`](blender_previews/sheet_texture_refinement_0.9.5.jpg); it records that the paver/Walk of Fame and NPC fabric repairs are visible, while asphalt, limestone and skyline picks held without a replacement. `tools/check_screenshots.sh` passed 21 good / 0 bad and the screen-design judge passed 21/21 match with 0 review.
|
||||
- NPC visual optimization (0.9.4, complete 2026-11-02): all eight variants passed the portrait/readability, proportion, gear, foot/shoe, headgear and final-context gates. The library uses an 8,000-triangle / 8,000-glTF-vertex cap (up from 6,000/5,000; `npc_base` fallback remains 6,000/4,000); current characters measure 4,482–5,474 triangles and 4,260–5,494 vertices. The 48-frame baseline and 96-frame final-context review pass, the hand/gear offset and shoes are in, and the accepted stylized limits are documented in `npc-visual-review.md`.
|
||||
- NPC face-detail pass (0.9.4 work): ala wings and a smaller nose bridge/tip, one rounded mouth slot, and a darker ear concha; all eight rebuilt. The comparison is `sheet_npc_baseline_compare-face-detail.jpg`.
|
||||
- NPC face realism pass (2026-11-03/04): all eight variants now use the `seg=24/rings=16` head with a subtle brow ridge, a fuller lower lip and both eyelids (recessed creases were rejected because they bake as dark AO patches). Vision-reviewed as cleaner/more realistic than the 0.9.4 face; characters measure 5,038–5,900 tris / 4,756–5,902 verts (still under 8,000). `sheet_npc_baseline.jpg` was refreshed.
|
||||
- Crowd-variety roster (character development, 2026-11-04): four new variants — `npc_crowd_a` (slim/bun/sunglasses), `npc_crowd_b` (broad/bald/beard/shoulder bag), `npc_crowd_c` (coat/umbrella), `npc_crowd_d` (slim/hood/cup) — built with the realistic face and wired into `CHARACTER_POOLS` so the routine crowd roles (tourist, confused visitor, intoxicated) pick them by seed instead of cloning `npc_casual`. The 24-NPC smoke is now 152,464 tris / 168 meshes / 6.94 ms (under the 50 ms budget).
|
||||
- NPC headgear clearance (0.9.4 work): the 96-frame final-context review after the face-detail pass confirms the cap, firefighter helmet, hood and sunglasses clear the refined brow and eyes; no gear rebuild was needed.
|
||||
- NPC footwear pass (0.9.4 work): casual shoes gained rounded toe and heel caps; responder/firefighter boots gained matching toe/heel volumes while retaining the black rubber boot language. All eight rebuilt; comparison `sheet_npc_baseline_compare-shoes.jpg`.
|
||||
- NPC hand-item grip (0.9.4 work): runtime `HAND_ITEM_FORWARD` moves every hand gear 4 cm forward from the wrist proxy, so phone, cup, clipboard, camera, flashlight, wand and radio sit in the open palm instead of partly inside it. The open-hand/no-finger-rig limit is accepted for this stylized release; the comparison is `sheet_npc_hands_grip_compare.jpg`.
|
||||
@@ -62,7 +72,8 @@ Implemented so far:
|
||||
- NPC P1 portrait fixes (0.9.4 work): tourists now hide their photo-pose camera bag outside `photo`/`film` poses, removing the duplicate-backpack silhouette; the backpack gear was rebuilt with flattened, forward chest straps and a fresh AO map. The before/after sheet is [`blender_previews/sheet_npc_baseline_compare-p1.jpg`](blender_previews/sheet_npc_baseline_compare-p1.jpg); the remaining face/hand work was closed under the 0.9.4 acceptance limits.
|
||||
- NPC visual baseline (0.9.4 work): `src/test/capture_npc_baseline.gd` captures all eight library characters from front, three-quarter, profile, back, full-body and crowd views in a neutral studio (48 frames). The criteria, measurements and ranked gaps are in [`npc-visual-review.md`](npc-visual-review.md); the committed sheet is [`blender_previews/sheet_npc_baseline.jpg`](blender_previews/sheet_npc_baseline.jpg). No model changes were made in this baseline step.
|
||||
- UI-state capture pass (0.9.3 work): `src/test/capture_ui_states.gd` adds committed captures 14–21 for the start menu, pause, settings, shift review, emergency radio, action wheel, crowd panic and responder arrival. Every one of the 21 catalogue entries now has a current-build capture; `tools/check_screenshots.sh` reports 21 good / 0 bad and the automatic judge reports 21/21 match, 0 diff. Crowd panic and responder arrival are staged presentation frames, not gameplay changes.
|
||||
- Realism adoption (post-v0.6.0): v2 per-phase skylines and surface tiles with normal maps, retuned sun/exposure/fog, wet asphalt, denser foliage, a visible additive flashlight beam, and refreshed staging captures. `tools/check_screenshots.sh` is the repeatable capture/compare gate; judge is clean of `diff` verdicts.
|
||||
- Realism adoption (post-v0.6.0): v2 per-phase skylines and surface tiles with normal maps, retuned sun/exposure/fog, wet asphalt, denser foliage, a tight additive flashlight spot with no beam geometry, and refreshed
|
||||
staging captures. `tools/check_screenshots.sh` is the repeatable capture/compare gate; judge is clean of `diff` verdicts.
|
||||
- Input/reliability fixes: selecting a venue releases the start-menu input lock and recaptures the mouse; the body-camera overlay no longer covers the shift status. Mouse look now reads at `_input`, restores capture on window focus/click-back, and the HUD is mouse-transparent. Normal radio reports submit on click; emergency calls still require the hold-to-confirm path.
|
||||
- Production-quality pass (v0.9.0): mixer/accessibility settings, audio volume clamping, 24-NPC budget smoke, shortened coat/dress stride, and a unified Godot 4.7.2 CI/local support baseline with documented upgrade/rollback requirements.
|
||||
- Campaign and first-hour pass (v0.8.0): campaign progression, checkpoint resume, difficulty presets, a searchable Help overlay, recovery events, contextual dialogue, policy/debrief lines and tutorial/replay/skip. Scripted QA bypasses the tutorial unless `--tutorial` is passed.
|
||||
@@ -71,8 +82,8 @@ Implemented so far:
|
||||
- Desktop HQ (v0.7.1): optional Forward+ Windows/Linux zip with volumetric fog, SDFGI and a volumetric flashlight; the default Compatibility/Web builds and headless tests gate the effect off. A/B captures are generated locally under `docs/screens/realism/` (gitignored).
|
||||
- Hollywood landmark map (map optimization): the default venue is now a stylized reconstruction of 6840 Hollywood Blvd (the 1921 Masonic Temple / El Capitan Entertainment Centre) with a six-column Ionic portico, eight stone steps, Masonic parapet motto and medallions, three red event banners, central and side entrances, the El Capitan Theatre and east retail neighbours, the Ovation Hollywood arcade opposite, the Walk of Fame terrazzo and a four-lane boulevard with red kerb paint. The facade uses the shared limestone/stone material; the whole venue measures **58,884 triangles across 409 meshes** in the map-budget test. The venue menu exposes separate **Day** and **Night** Hollywood rows; the night row resolves to the same scenario with a late-phase offset, so its whole shift stays after dark. Real-site references and the geometry mapping are in [`hollywood-boulevard-map.md`](hollywood-boulevard-map.md).
|
||||
- Day/night scenery variants (map optimization): the Hollywood row in the venue menu is split into Day and Night entries, with localized names/blurbs. The night entry uses `ShiftCoordinator.phase_offset_s` to start a full-length shift in `LATE` while the clock still starts at 00:00; the scheduler reads the offset time so late-night routine traffic and the late violent-threat event still fire, and the offset round-trips through checkpoints. Three `LATE` routine events keep the night street populated. Local lights were retuned from constant falloff to linear attenuation so sconces pool instead of flooding the stone.
|
||||
- Joke Shop / Sunset Strip map (map optimization): the second venue is now a stylized reconstruction of The Comedy Store block at 8433 Sunset Blvd, with a 27 m black hall, signature-covered sloping canopy, circular **THE JOKE SHOP** blade sign, red velvet curtain bays, a west-end entrance, cream and white low-rise neighbours, a dry hillside with stucco houses and palms behind the roofline, and a low retail/billboard frontage across Sunset. The same geometry serves day and late lighting through the phase system. Real-site references and limits are in [`joke-shop-map.md`](joke-shop-map.md); the map measures **22,680 triangles across 454 meshes** in the budget test.
|
||||
- Venue geometry (v0.7.0, Joke Shop frontage superseded by the map-optimization pass): the TV Studio builds a stone facade, bulb canopy, glossy black car and barrier line. `WorldBuilder.VENUE_SPECS` drives facade/street/nav dimensions, and `GameManager` rebuilds only the world container when the venue changes.
|
||||
- Joke Shop / Sunset Strip map (map optimization): the second venue is now a stylized reconstruction of The Comedy Store block at 8433 Sunset Blvd, with a 27 m black hall, signature-covered sloping canopy, circular **THE JOKE SHOP** blade sign, seven tied-back red velvet curtain drapes, a west-end entrance, cream and white low-rise neighbours, a dry hillside with stucco houses and palms behind the roofline, and a low retail/billboard frontage across Sunset. The same geometry serves day and late lighting through the phase system. Real-site references and limits are in [`joke-shop-map.md`](joke-shop-map.md); the map measures **25,828 triangles across 518 meshes** in the budget test.
|
||||
- Venue geometry (v0.7.0, Joke Shop frontage superseded by the map-optimization pass): the TV Studio is the same El Capitan block restaged for a late-night arrival — a stone facade, bulb canopy, glossy black car and barrier line. `WorldBuilder.VENUE_SPECS` drives facade/street/nav dimensions, and `GameManager` rebuilds only the world container when the venue changes.
|
||||
- Gear fit (post-v0.6.0): Blender gear is measured against the avatar head/skirt silhouette and the checks run in both the Python tooling and the headless suite. Sunglasses, the shoulder bag and the firefighter helmet were fitted to the new faces; the Influencer portrait and gallery were recaptured with a before/after report.
|
||||
- End-to-end interaction pass (0.9.3 work): `smoke_ui_flows.gd` drives inspection allow/deny, normal vs emergency radio, Help filtering, wand allow/deny and review return-to-menu in the real scene; campaign and timeline smokes cover review continue and timeline round-trips.
|
||||
- Destructive-action pass (0.9.3 work): reset campaign and tutorial replay share a guarded confirmation dialog (one open instance, one emission, Cancel is inert); emergency send remains hold-to-confirm with no post-submit double-fire. Covered by session/radio tests and recorded in `docs/ui-copy.md`.
|
||||
|
||||
@@ -29,7 +29,7 @@ offers the same map as **Hollywood Boulevard — Day** and **Hollywood Boulevard
|
||||
— Night**; the night variant starts directly in the late phase instead of
|
||||
waiting for the shift clock.
|
||||
|
||||
The original scenario places the guard at the top of the eight stone steps outside the historic Masonic Temple / El Capitan Entertainment Centre on Hollywood Boulevard. Tourists, street performers, influencers, confused visitors, intoxicated pedestrians, trespassers, people experiencing a mental-health crisis, and rare violent threats may approach the entrance.
|
||||
The original scenario — the starting point of the campaign — places the guard at the top of the eight stone steps outside the historic Masonic Temple / El Capitan Entertainment Centre on Hollywood Boulevard, the building that houses the *Jimmy Kimmel Live!* stage and studio. Tourists, street performers, influencers, confused visitors, intoxicated pedestrians, trespassers, people experiencing a mental-health crisis, and rare violent threats may approach the entrance.
|
||||
|
||||
Authorized people must either be recognized by the guard or present a valid wristband. Wristbands can have different colors, patterns, dates, or event markings. They may be valid, expired, counterfeit, or missing.
|
||||
|
||||
@@ -39,7 +39,7 @@ The Joke Shop is a Sunset Strip comedy club inspired by the real Comedy Store at
|
||||
|
||||
### Hollywood Boulevard Late Night TV Studio
|
||||
|
||||
This scenario combines the previously defined NPC types with a busy television-studio entrance: a stone facade, a bulb-lit canopy, a glossy black car at the curb, and stanchions/barriers holding the arrival line. The player manages audience members, production staff, performers, guests, deliveries, celebrity arrivals, tourists, street performers, influencers, confused visitors, intoxicated pedestrians, trespassers, people experiencing a mental-health crisis, and rare violent threats.
|
||||
This scenario combines the previously defined NPC types with a busy television-studio entrance: the same El Capitan Entertainment Centre block as the Hollywood day shift, restaged as a late-night studio arrival — the stone facade and steps, a bulb-lit canopy, a glossy black car at the curb, and stanchions/barriers holding the arrival line. The player manages audience members, production staff, performers, guests, deliveries, celebrity arrivals, tourists, street performers, influencers, confused visitors, intoxicated pedestrians, trespassers, people experiencing a mental-health crisis, and rare violent threats.
|
||||
|
||||
The studio uses wristbands, credentials, tickets, guest-list confirmation, and personal recognition to authorize entry. Crowd control, filming boundaries, following authorized guests through the door, and counterfeit credentials are key events.
|
||||
|
||||
|
||||
@@ -11,7 +11,10 @@ eye height, while side streets and interiors are simplified.
|
||||
- **Coordinates:** 34.10118 N, 118.34009 W (OSM way `424024147`).
|
||||
- **Building:** the 1921 Hollywood Masonic Temple, designed by John C. Austin in
|
||||
the Classical Revival style; now the El Capitan Entertainment Centre and the
|
||||
home of *Jimmy Kimmel Live!*.
|
||||
home of *Jimmy Kimmel Live!*. This is the game's **starting point**: the first
|
||||
shift (Hollywood) and the late-night TV Studio arrival both begin at this
|
||||
building, where the Kimmel stage and studio occupy the interior behind the
|
||||
six-column facade.
|
||||
- **Facade:** a light stone/render Neoclassical front with six oversized Ionic
|
||||
columns, a recessed main entrance reached by eight stone steps, ornamental
|
||||
iron door grilles, a continuous crosscut-grille transom, two street-level side
|
||||
@@ -22,6 +25,19 @@ eye height, while side streets and interiors are simplified.
|
||||
- **Sidewalk:** the Hollywood Walk of Fame terrazzo strip with brass stars runs
|
||||
along the kerb; the kerb is painted red in the reference photographs.
|
||||
|
||||
### Late Night TV Studio venue
|
||||
|
||||
The game's third venue is **the same block**, not a separate real site. The building houses
|
||||
*Jimmy Kimmel Live!*, so the "Late Night TV Studio" scenario restages 6840 Hollywood Blvd as a
|
||||
studio arrival: the same stone facade and steps, plus a bulb-lit canopy, a glossy black car at the
|
||||
kerb, a barrier/stanchion line and an audience queue. The Kimmel stage/audience and the entrance
|
||||
marquee are researched as local-only reference sets under
|
||||
`tmp/research/jimmy-kimmel-stage/` and `tmp/research/jimmy-kimmel-entrance/` (gitignored); the
|
||||
photo-anchored entrance concepts live in
|
||||
[`screens/concepts/hollywood_boulevard/README.md`](screens/concepts/hollywood_boulevard/README.md). `VENUE_SPECS["tv_studio"]` is a variant of the
|
||||
Hollywood spec (30.0 m facade instead of 29.6 m, arrival staging instead of the day-time banners),
|
||||
and it shares this block's reference board rather than owning one.
|
||||
|
||||
## Game mapping
|
||||
|
||||
| Real feature | In-game representation |
|
||||
@@ -37,6 +53,7 @@ eye height, while side streets and interiors are simplified.
|
||||
| Ovation Hollywood | `OvationHollywood` arcade with seven arched openings, sign and south sidewalk |
|
||||
| Walk of Fame | `WalkOfFame` dark terrazzo band with ten stars |
|
||||
| Four-lane boulevard | double-yellow centre, broken white lane lines, red kerb paint and crosswalk |
|
||||
| TV Studio arrival staging | `VENUE_SPECS["tv_studio"]`: same six-column Masonic facade and eight steps (reuses `masonic_facade`), plus `bulb_canopy`, `sedan`, `handrail` and barrier placements instead of the day-time marquee |
|
||||
|
||||
The generated AI references live in
|
||||
[`docs/screens/concepts/hollywood_boulevard/`](screens/concepts/hollywood_boulevard/README.md).
|
||||
@@ -63,14 +80,37 @@ not texture or geometry sources.
|
||||
- Local lights use linear attenuation (`omni_attenuation = 1.0`). Godot treats
|
||||
`0.0` as constant falloff, which previously turned the night facade into a
|
||||
flat yellow wall; the sconces now pool light instead.
|
||||
- The masonic facade field uses the `limestone_ashlar` pick: a seamless ashlar
|
||||
tile generated reference-anchored on the 2009 facade photo (CC BY 2.0),
|
||||
768 px over ~4.6 m of wall (~167 px/m), so the wall carries course joints and
|
||||
per-block value variation instead of flat plaster.
|
||||
- Night balance: the event banners carry a warm self-light and the marquee sign
|
||||
face + bulbs brighten after dark (registered with `_marquee_emissive`), so the
|
||||
facade reads as practical-lights-only rather than a flat lit wall. The marquee
|
||||
canopy stays black metal by design — the fictional "GIG LINE" marquee, not the
|
||||
red El Capitan Theatre marquee next door.
|
||||
|
||||
## References
|
||||
|
||||
The committed, license-cleared photo board for this block — with the provenance sidecar and the
|
||||
decisions each photo informed — is in
|
||||
[`screens/refs/hollywood/README.md`](screens/refs/hollywood/README.md). The three-up boards
|
||||
(real photo | generated concept | current capture) live in
|
||||
[`screens/boards/README.md`](screens/boards/README.md) and make the remaining facade-realism gap
|
||||
visible: the capture panel still shows flat material bands where the photo has limestone value
|
||||
variation, joint lines and reveal depth.
|
||||
|
||||
- [Hollywood Masonic Temple — Wikipedia](https://en.wikipedia.org/wiki/Hollywood_Masonic_Temple)
|
||||
- [El Capitan Entertainment Centre — OpenStreetMap way 424024147](https://www.openstreetmap.org/way/424024147)
|
||||
- [El Capitan Theatre — OpenStreetMap way 424024148](https://www.openstreetmap.org/way/424024148)
|
||||
- [Ovation Hollywood — OpenStreetMap way 151485232](https://www.openstreetmap.org/way/151485232)
|
||||
- [Hollywood Masonic Temple facade — Wikimedia Commons](https://commons.wikimedia.org/wiki/File:El_Capitan_Theater_frontal_fachade-The_Masonic_Temple.jpg)
|
||||
- Local frames that changed a decision (gitignored, never committed):
|
||||
- `tmp/research/elcapitan-2026/` (recent Commons geosearch) → established that no recent photo
|
||||
frames the El Capitan facade straight-on in daylight, so the 2009 CC BY frame stays the
|
||||
geometry reference.
|
||||
- `tmp/research/jimmy-kimmel-entrance/07.jpg` → the photo anchor for the four Jimmy Kimmel
|
||||
entrance concepts (day/night × gemini/gpt), confirming the starting-point building.
|
||||
- [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)
|
||||
|
||||
## Verification
|
||||
|
||||
@@ -27,18 +27,34 @@ signature-covered canopy, with the circular blade sign above the roof, red
|
||||
curtains along the frontage and the main entrance set toward the west end. The
|
||||
hillside houses behind it are part of the silhouette from the sidewalk.
|
||||
|
||||
## Measured proportions (vision-extracted from the local frames, 2026-11-03)
|
||||
|
||||
`tools/describe_image.py` was used to read the gitignored `tmp/research/comedy-store/` frames
|
||||
(the harness cannot display images directly). Two frames disagreed on crop-dependent details, so
|
||||
the ranges below are the reconciled reading; the game spec is a deliberate compression.
|
||||
|
||||
| Feature | Reference reading | Game spec | Reconciliation |
|
||||
| --- | --- | --- | --- |
|
||||
| Street frontage | ~35–40 m wide, parapet ~5.5–6 m (≈6:1 width:height), rounded corner | 27 m × 6.0 m | Facade height lowered 8.4 → 6.0 m (2026-11-03); width still compressed for the playable block |
|
||||
| Canopy | ~4–4.5 m projection, tilts forward noticeably | 4.9 m at 11° | Close; the forward pitch is confirmed |
|
||||
| Fascia band | black, 30–40 cm deep, marquee-bulb string | black `SignatureCanopy` fascia + `CanopySignatures` + bulbs | Matches; signatures now white |
|
||||
| Circular blade sign | ~3–4 m diameter white disc, red serif wordmark, pole-mounted | 3.9 m white disc, black wordmark, pole | Diameter matches; the game wordmark is black (fictional `THE JOKE SHOP`) |
|
||||
| Red curtain bays | 3–5 visible depending on frame, floor-length, tied-back mid-bay | 7 tied-back drapes | Count is crop-dependent; 7 is a readable stylization, not a defect |
|
||||
| Entrance | west end, recessed at the rounded corner | west end at x = -8.8, recessed | Matches |
|
||||
| Roofline | taller dark mass rises behind the right half | `RoofPlant` box at x = 5.5 | Matches |
|
||||
|
||||
## How the map maps to the real site
|
||||
|
||||
| Real element | Game implementation |
|
||||
| --- | --- |
|
||||
| Low black comedy hall | 27 m × 12 m footprint, 8.4 m street wall; matte black concrete surface with a low plinth and parapet |
|
||||
| Low black comedy hall | 27 m × 12 m footprint, 6.0 m street wall; matte black concrete surface with a low plinth and parapet |
|
||||
| Deep overhanging canopy | 4.9 m sloped slab dropping about 1 m to the outer fascia; the fascia carries white signature lettering and the club name |
|
||||
| Signature-covered front | Two `Label3D` signature bands on the fascia plus a smaller wall panel, so the handwriting reads at gameplay distance without dozens of decals |
|
||||
| Circular blade sign | 3.9 m white disc with a black rim on a roof pole; `THE JOKE SHOP` lettering faces the street |
|
||||
| Red curtains | Four three-fold velvet bays with tiebacks between the entrance and the east end; a red velvet entrance curtain |
|
||||
| Red curtains | Seven tied-back velvet drapes between the entrance and the east end — each cinched into an hourglass with a scalloped hem and dark recess between bays; a red velvet entrance curtain |
|
||||
| West-end entrance | Recessed opening at x = -8.8 m with a low step, brass pulls and the door-lock indicator |
|
||||
| Warm practicals | Sconces along the wall, canopy downlights, entrance wash and three ground uplights; all off in daylight and switched by `set_night_mode()` |
|
||||
| Neighbouring low-rise frontage | Cream Mediterranean block west (balconies, red awning) and white commercial block east (ribbon windows, lobby) |
|
||||
| Neighbouring low-rise frontage | Cream Mediterranean block west (balconies, red awning) with a stepped-back 5–6 storey pink hotel tower behind it (`WestHotelTower`, the Ramada Plaza mass); white commercial block east (ribbon windows, lobby) |
|
||||
| Hillside and houses | Fog-free unshaded 60° ramp behind the rear wall with stucco houses, shrubs and palms; its tint drops to a dark silhouette at night |
|
||||
| Opposite side of Sunset | Low retail row, rooftop billboard, neon and palms as background context beyond the far kerb |
|
||||
| Sidewalk furniture | Palms, queue barriers, stanchions, bins, planters, a-frame sign, hydrant and a parked sedan; prop placements pass the shared validator |
|
||||
@@ -51,7 +67,7 @@ hillside houses behind it are part of the silhouette from the sidewalk.
|
||||
Hollywood block and a crosswalk in front of the entrance.
|
||||
- **Playable area:** x = -15…15, z = -0.6…14.0. The guard starts on the west
|
||||
side of the entrance at (-4.8, 0.1, 1.4), facing the approach.
|
||||
- **Map budget:** the headless audit measures **22,680 triangles across 454
|
||||
- **Map budget:** the headless audit measures **25,828 triangles across 518
|
||||
meshes**, well inside the 150k/700 test budget.
|
||||
|
||||
The same geometry serves the day and late-night looks. There is no second baked
|
||||
@@ -65,9 +81,12 @@ just as with the Hollywood day/night rows.
|
||||
- The 47 m OSM footprint includes rear parcels and does not match the 27 m
|
||||
street frontage; the game keeps the frontage proportions rather than the full
|
||||
lot.
|
||||
- Neighbouring businesses are represented by generic low-rise blocks. Their
|
||||
exact names and current tenants were not verified, so the docs do not claim
|
||||
them.
|
||||
- Neighbouring businesses are represented by generic low-rise blocks (plus the
|
||||
stepped-back `WestHotelTower` mass behind the west block, standing in for the
|
||||
Ramada Plaza). Their exact names and current tenants were not verified, so the
|
||||
docs do not claim them.
|
||||
- The real club's west street corner is rounded (radius ~3–4 m); the game keeps
|
||||
a hard 90° corner as a stylized-reconstruction simplification.
|
||||
- The hillside is a background ramp with simplified houses, not a terrain
|
||||
heightfield; it exists to restore the real silhouette above the roofline.
|
||||
- Signage uses the fictional **The Joke Shop** name, not the real Comedy Store
|
||||
@@ -79,13 +98,21 @@ just as with the Hollywood day/night rows.
|
||||
|
||||
## References
|
||||
|
||||
The old committed Comedy Store photo board was removed on 2026-11-03 in favour of a local-only
|
||||
research set under `tmp/research/comedy-store/` (owner override: development reference, never
|
||||
committed, no licence gate). The three-up board (real photo | generated concept | current capture)
|
||||
is in [`screens/boards/README.md`](screens/boards/README.md); its photo panel is a historical
|
||||
public-domain frame, and the current block reference now lives in the gitignored research folder.
|
||||
|
||||
- OpenStreetMap way 428854155: <https://www.openstreetmap.org/way/428854155>
|
||||
- Wikimedia Commons photographs used for proportion and material study:
|
||||
- <https://commons.wikimedia.org/wiki/File:ComedyStore_01.jpg>
|
||||
- <https://commons.wikimedia.org/wiki/File:ComedyStore_02.jpg>
|
||||
- <https://commons.wikimedia.org/wiki/File:The_Comedy_Store.jpg>
|
||||
- <https://commons.wikimedia.org/wiki/File:The_Comedy_Store_West_Hollywood_(51017780551).jpg>
|
||||
- AI art-direction frames: [`screens/concepts/joke_shop/`](screens/concepts/joke_shop/README.md)
|
||||
- Local frames that changed a decision (gitignored, never committed):
|
||||
- `tmp/research/comedy-store/` facade/street/strip/visitor frames → the four
|
||||
`comedy_store_*` photo-anchored concept pairs and the map-recreation plan.
|
||||
- `tmp/research/comedy-store-hillside/` (public-domain hillside frame) → the photo anchor for
|
||||
`joke_shop_entrance_day-v2.png` (a less-branded frame that clears the image-recitation filter).
|
||||
- The hall wall uses the `dark_stucco` pick (1024 px, matte charcoal grain) instead of the grey
|
||||
paver tile, so the black stucco reads as the real club's flat plaster rather than masonry.
|
||||
- Verification: `godot --headless --path . --script res://src/test/test_runner.gd`
|
||||
(`test_joke_shop_uses_the_real_sunset_strip_layout`,
|
||||
`test_joke_shop_geometry_stays_inside_the_map_budget`), and
|
||||
|
||||
@@ -0,0 +1,336 @@
|
||||
# NPC model sourcing and expansion plan
|
||||
|
||||
Status: **direction chosen 2026-11-03.** The procedural generator is the primary
|
||||
path, the Quaternius CC0 pack is a reviewed reference/prototype, and MakeHuman is
|
||||
deferred to a separate local development pipeline. No downloaded source model is
|
||||
committed to the game or included in a release; the committed research preview
|
||||
sheets carry the required attribution. Local evaluation files live under
|
||||
`tmp/npc-research/` (gitignored). The decision is recorded in
|
||||
[ADR-0015](adr/0015-npc-model-variety-sourcing.md).
|
||||
|
||||
This page records the free/open-source character sources that were reviewed, how
|
||||
they behave when imported into the existing Blender tooling, and the options for
|
||||
creating a larger NPC model library. The runtime contract and current library are
|
||||
documented in [`blender-assets.md`](blender-assets.md) and
|
||||
[`npc-visual-review.md`](npc-visual-review.md).
|
||||
|
||||
## Why this review exists
|
||||
|
||||
The library has eight skinned characters, and `NpcAvatar.character_model_for()`
|
||||
reuses them across role families. That is enough for a release candidate, but
|
||||
crowds repeat the same faces, builds and outfits. Three venues, a 24-NPC budget
|
||||
and close-up portraits make that repetition visible.
|
||||
|
||||
Any expansion must preserve the existing integration contract:
|
||||
|
||||
- mesh node `npc_base` under a `Skeleton3D`;
|
||||
- bones `Head`, `HipL/R`, `KneeL/R`, `ShoulderL/R`, `ElbowL/R`, `HandL/R` plus
|
||||
`Hips`, `Spine`, `Neck` at the contract rest positions;
|
||||
- five tint slots (`skin`, `cloth`, `pants`, `accessory`, `hair`);
|
||||
- front on Blender −Y / Godot +Z, feet near the floor, 1.6–2.1 m height;
|
||||
- at most 8,000 triangles and 8,000 glTF vertices per character;
|
||||
- gear attach points at head, back, chest and hand.
|
||||
|
||||
The existing `audit` command is the gate. A source that looks good in a preview
|
||||
but fails `audit` is not usable without an adaptation step.
|
||||
|
||||
## What was evaluated
|
||||
|
||||
Blender 5.2.0 LTS (Flatpak) imported each file in background mode. Measurements
|
||||
below come from the imported scene, because external GLBs often carry node
|
||||
transforms that the project's audit (which reads accessor-local bounds) does not
|
||||
apply. "Vertices" are the imported, seam-split counts that matter for the glTF
|
||||
budget, not the source file's vertex count.
|
||||
|
||||
| Source | Licence | Files checked | Geometry / rig | Height | Verdict |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| **Quaternius Ultimate Modular Men / Women** (mirrored GLB pack) | CC0 1.0 | `Casual_Hoodie.glb`, `Worker.glb`, `Casual.glb` | 5,240–6,424 tris; 10,534–12,968 verts; 62 bones; 24 animations; 4 skinned meshes on one armature | 1.80–1.87 m | **Best silhouette/outfit match.** Fails the contract: wrong bone names/rest positions, no tint slots, no `npc_base` node, vertex budget exceeded. |
|
||||
| **Kenney Blocky Characters 2.0** | CC0 1.0 | full pack (18 characters), `character-a.glb`, `character-f.glb` | 72 tris; 143 verts; static, no armature; one texture atlas per character | 2.7 m imported (needs 0.67× scale) | **Not a close-up character.** Useful as a crowd/impostor LOD or placeholder, but cannot be driven by the skeleton and has no separate face/clothing slots. |
|
||||
| **Khronos CesiumMan** | CC BY 4.0 (© Cesium) | `CesiumMan.glb` | 4,672 tris; 3,273 verts; 19-bone walk rig; 1 material/texture; 1 animation | 1.45 m | **Technical retarget test only.** One outfit and one look, wrong rig, short; works as a skinning/pose reference. Attribution is required. |
|
||||
| **Khronos RiggedFigure** | CC BY 4.0 (© Cesium) | `RiggedFigure.glb` | 256 tris; 370 verts; 19-bone walk rig; no UVs; 1 animation | 1.48 m | **Rig smoke test only.** A mannequin with no usable surface detail. |
|
||||
| **MakeHuman core base mesh / MPFB** | Core assets CC0 1.0; application AGPL/GPL | `makehuman/data/3dobjs/base.obj` | 19,158 verts; 18,486 polygons; 36,972 tris; no rig in the base mesh | ~16.9 model units before scaling | **Best body-shape diversity, highest pipeline cost.** Needs scaling, decimation/retopology and a generated rig. The MakeHuman/MPFB tool itself is not bundled. |
|
||||
|
||||
Local review sheet (front views, not committed):
|
||||
`tmp/npc-research/previews/contact_sheet.jpg`.
|
||||
|
||||
Rejected without downloading: Mixamo and Ready Player Me. Both are useful
|
||||
services, but their terms are not a simple free/open-source redistribution basis
|
||||
for shipped character meshes. Sketchfab, Poly Pizza and OpenGameArt can contain
|
||||
excellent CC0 work, but each asset needs a case-by-case licence and provenance
|
||||
check; they are not a consistent library source.
|
||||
|
||||
### Measured contract failures
|
||||
|
||||
Every example fails the unmodified `audit` contract:
|
||||
|
||||
| Check | Quaternius | Kenney | CesiumMan | RiggedFigure | MakeHuman base |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `npc_base` mesh node | no | no | no | no | no |
|
||||
| Required 13 bones | no (62 different names) | no rig | no (19 different names) | no (19 different names) | no rig |
|
||||
| Five tint slots | no | no | no | no | no |
|
||||
| ≤ 8,000 tris | yes | yes | yes | yes | no |
|
||||
| ≤ 8,000 verts | no (10.5–13k) | yes | yes | yes | no (19k) |
|
||||
| Feet on floor | yes | yes (2.7 m scale) | yes (−11 mm) | yes | no (needs scaling) |
|
||||
| Height 1.6–2.1 m | yes | no (2.7 m) | no (1.45 m) | no (1.48 m) | needs scale |
|
||||
| Skinned / UV mapped | yes / yes | no / yes | yes / yes | yes / no | no / no |
|
||||
|
||||
The practical conclusion is that **there is no drop-in download**. External
|
||||
sources need a deliberate intake step, and the expensive part is not decimation:
|
||||
it is rebuilding or retargeting the skeleton and material slots without breaking
|
||||
the animation proxies and gear placement.
|
||||
|
||||
The table uses Blender-imported world bounds. The stdlib `audit` reads accessor-local
|
||||
bounds and ignores node transforms, so an unapplied external GLB can fail floor/height
|
||||
checks even when the imported scene looks correct. The intake step must apply
|
||||
transforms before it measures and exports.
|
||||
|
||||
## Options
|
||||
|
||||
### Option A — extend the procedural generator
|
||||
|
||||
Add more variation to `tools/blender_assets.py` rather than importing models:
|
||||
body builds, height ranges, head/face shapes, hair and facial hair, outfit
|
||||
layers, and more `CHARACTERS` specs. This keeps a single owned style, needs no
|
||||
third-party licence review, and stays inside the existing builder/audit flow.
|
||||
|
||||
- **Strengths:** lowest integration risk, deterministic, no new dependencies.
|
||||
- **Limits:** the current face and clothing vocabulary is intentionally simple;
|
||||
more variants may still read as the same model with a different coat.
|
||||
- **Best for:** a quick 4–8 variant expansion and filling obvious role gaps.
|
||||
|
||||
### Option B — Quaternius CC0 intake with a contract adapter
|
||||
|
||||
Use Quaternius meshes as silhouette/outfit donors and adapt them to the project
|
||||
contract. The visible result is a different body/clothing language from the
|
||||
current library, so the adapter must also normalise head/hand style or rebuild
|
||||
those parts.
|
||||
|
||||
- **Strengths:** best free outfit/hair variety, animations included, CC0,
|
||||
already close to game proportions, front axis and floor contact.
|
||||
- **Work:** weld/decimate to the vertex budget, remap materials to the five
|
||||
slots, rebuild the armature at the contract rest positions, transfer weights,
|
||||
repose/normalise proportions, rename the mesh node, export, audit and compare
|
||||
in the acceptance harness.
|
||||
- **Main risk:** retargeting a 62-bone T-pose rig to the 13-bone arm-down
|
||||
contract. Hip/knee rest heights differ substantially (Quaternius upper leg
|
||||
starts near 0.96 m; the contract hip starts near 0.62 m), so a naive
|
||||
nearest-bone weight transfer can produce a good still image and bad walk
|
||||
poses. Prototype one character before committing to a roster.
|
||||
- **Best for:** a larger, visibly different library if the prototype passes the
|
||||
portrait and walk gates.
|
||||
|
||||
### Option C — MakeHuman/MPFB body-shape pipeline
|
||||
|
||||
Generate a range of ages, builds and body shapes from the CC0 MakeHuman base
|
||||
mesh, then replace the head/hands and dress them with project-owned clothing.
|
||||
This is the strongest answer to "everyone has the same body", but requires an
|
||||
offline authoring step, decimation/retopology and a custom rig/weight step. It
|
||||
should be treated as a later pipeline project, not a quick content drop.
|
||||
|
||||
## Decision and prototype outcome
|
||||
|
||||
The project owner reviewed this page on 2026-11-03. The decision is:
|
||||
|
||||
1. **CC0 is acceptable** for shipped character assets. CC-BY is acceptable only
|
||||
with attribution in `CREDITS.md`; service assets whose terms restrict
|
||||
redistribution remain excluded.
|
||||
2. **Extend the procedural generator** as the primary path, starting with
|
||||
crowd-variety looks.
|
||||
3. **Prototype Quaternius** as a secondary source. It is not approved for
|
||||
shipping yet; the contract-retarget result below is a no-go for the current
|
||||
skeleton.
|
||||
4. **Use crowd variety** as the first visual goal, not role-specific costumes.
|
||||
5. **Evaluate MakeHuman for a later, separate local development pipeline.** It
|
||||
is not part of the normal build, CI or release flow.
|
||||
6. **Commit the research previews with attribution.** The CC-BY entries are
|
||||
listed in `CREDITS.md` and remain development-only.
|
||||
|
||||
### Quaternius prototype
|
||||
|
||||
The prototype used `Casual_Hoodie.glb`:
|
||||
|
||||
- **Geometry budget is not the blocker.** Imported: 12,518 vertices / 6,206
|
||||
triangles. After welding seam splits: 3,199 vertices / 6,206 triangles. After
|
||||
a 0.75 decimate: 2,423 vertices / 4,654 triangles, comfortably inside the
|
||||
library budget.
|
||||
- **Animation quality is attractive.** The imported Idle and Walk clips read
|
||||
well at game distance, and the model brings 24 animations.
|
||||
- **The contract rest pose is the blocker.** The source is a T-pose 62-bone rig
|
||||
with realistic proportions: upper leg starts near 0.96 m, arm span is about
|
||||
1.68 m, and the shoulder joint sits near x = 0.153 m. The project contract is
|
||||
an arm-down 13-bone rig with a hip near 0.62 m, a shoulder near x = 0.27 m and
|
||||
a hand near z = 0.78 m. Rebuilding the contract armature around this mesh would
|
||||
either distort the body substantially or require a full proportion warp.
|
||||
- **Decision:** do not retarget Quaternius to the contract now. Keep it as a
|
||||
silhouette/style reference and, if a second rig path is ever wanted, prototype
|
||||
it as its own animation path (its own skeleton, AnimationPlayer clips and
|
||||
per-model gear offsets) rather than forcing it into `npc_base`. That is a
|
||||
separate architecture decision, not an asset conversion.
|
||||
|
||||
Preview: [`blender_previews/sheet_npc_sources_research.jpg`](blender_previews/sheet_npc_sources_research.jpg).
|
||||
|
||||
### Generator crowd prototype
|
||||
|
||||
Four proposed crowd specs were built with the existing generator in a temporary
|
||||
output directory. All four audit clean and stay inside the character budget:
|
||||
|
||||
| Prototype | Look | Tris / verts | Gear |
|
||||
| --- | --- | --- | --- |
|
||||
| `npc_crowd_a` | slim, bun, sunglasses | 4,644 / 4,356 | sunglasses |
|
||||
| `npc_crowd_b` | broad, bald, beard | 4,550 / 4,453 | shoulder bag |
|
||||
| `npc_crowd_c` | average, short hair, long coat | 5,118 / 5,086 | umbrella |
|
||||
| `npc_crowd_d` | slim, short hair, hood up | 5,258 / 4,907 | cup |
|
||||
|
||||
They vary build, head silhouette, hair/beard and outer layer while keeping the
|
||||
existing face language. They are **not in the shipped catalogue**; production
|
||||
integration belongs to the roster/runtime work under the unversioned `Character
|
||||
development` section, after the current release candidate.
|
||||
|
||||
Preview: [`blender_previews/sheet_npc_crowd_prototypes.jpg`](blender_previews/sheet_npc_crowd_prototypes.jpg).
|
||||
|
||||
### MakeHuman local-pipeline evaluation
|
||||
|
||||
The CC0 base mesh is 19,158 vertices / 18,486 polygons (36,972 triangles after
|
||||
triangulation), with 21,334 UV coordinates but no normals, material groups or
|
||||
rig. Scaling it to 1.82 m and decimating to 0.35 produced 3,780 vertices / 6,468
|
||||
triangles, which fits the geometry budget but is a collapse-decimation result,
|
||||
not production topology.
|
||||
|
||||
MakeHuman is therefore **feasible only as a separate local body-shape pipeline**.
|
||||
The boundary for that future work is:
|
||||
|
||||
Intake prototype (2026-11-04): `tmp/npc-research/makehuman_intake.py` scales the
|
||||
CC0 base to 1.82 m, grounds it, triangulates and decimates to **3,790 verts /
|
||||
6,444 tris**, then exports `tmp/npc-research/makehuman/makehuman_body.glb` (body
|
||||
only, one neutral material, UVs present, no rig). The body is the input for the
|
||||
contract-rig/retopology step; the script and mesh stay under `tmp/` and are never
|
||||
committed.
|
||||
|
||||
Retarget prototype (2026-11-04): `tmp/npc-research/makehuman_retarget.py` rotates
|
||||
the A-pose arms down (−38°/+38°) and scales them **1.63×** to the contract 0.70 m
|
||||
arm, welds the split vertices, smooth-shades, adds the 13-bone contract armature
|
||||
with the project's distance-to-bone `_auto_weights`, paints the five slot regions,
|
||||
renames the mesh to `npc_base`, and exports `makehuman_retargeted.glb` — **6,444 /
|
||||
8,000 tris, 7,726 / 8,000 verts**, 14 bones, skinned, arm-down, grounded, five
|
||||
slots, no contract issues. The proportion warp (1.63× arms) is the same class of
|
||||
issue that blocked Quaternius; here it is accepted, but the vision review shows
|
||||
it distorts the deltoid/shoulder, the decimated hands are blocky, and the slot
|
||||
boundaries are rough — refinement work (arm-scale falloff, project head/hands,
|
||||
weight tuning) is the next step.
|
||||
|
||||
The arm-scale falloff (1.0 at the shoulder tapering to 1.63 at the fingertip) was
|
||||
added, then the arm threshold was raised to x > 0.22 and a rotation falloff was
|
||||
added — the deltoid/shoulder junction is now smooth (no spiky triangles or
|
||||
arm/torso gaps). Remaining visual defects: the decimated MakeHuman head reads
|
||||
dark/featureless, the hands are flat claw-like, and the feet are detached/spiked
|
||||
— these are fixed by swapping in the project's `_face`/`_hands_and_shoes`/shoe
|
||||
parts, the next step.
|
||||
|
||||
- MPFB/MakeHuman is installed and run by a contributor, never by CI or the game
|
||||
build.
|
||||
- Generated bodies and intermediate exports stay in `tmp/` (gitignored); the
|
||||
CC0 base mesh is not committed.
|
||||
- The contributor scales to 1.8–1.9 m, decimates or retopologises to roughly
|
||||
6–7k triangles, and checks the silhouette against `npc-visual-review.md`.
|
||||
- The body gets the contract armature, weights, project-owned head/hands,
|
||||
clothing and gear; it must pass `blender_assets.py audit` and `fit`.
|
||||
- Only the final CC0-derived GLB and its provenance note are committed. The
|
||||
application code and any non-CC0 assets stay outside the repository.
|
||||
|
||||
This is deferred; it is not part of the current crowd-variety work.
|
||||
|
||||
## Provisional NPC roster
|
||||
|
||||
The design rule stays: clothes, props and behaviour carry the read; a model must
|
||||
not label a person as "the threat". The roster therefore adds ordinary adults
|
||||
across age, build and style, not costumes that telegraph the outcome.
|
||||
|
||||
| Look family | Current | Proposed additions | Variation axes |
|
||||
| --- | --- | --- | --- |
|
||||
| Everyday | `npc_casual`, `npc_jacket`, `npc_coat`, `npc_hoodie`, `npc_dress` | `npc_crowd_a` (bun/slim), `npc_crowd_b` (bald/broad), `npc_crowd_c` (coat/umbrella), `npc_crowd_d` (hood/cup) | build, height, hair, facial hair, outer layer, accessory |
|
||||
| Workwear | `npc_vest`, `npc_guard` | later: second hi-vis build, venue-security build | build, height, headwear, badge/radio gear |
|
||||
| Responder | `npc_firefighter` | later: paramedic/medical responder only if the design supports it | turnout vs medical kit, build, helmet |
|
||||
| Crowd/LOD | none | optional Kenney blocky or a decimated library variant for distant crowds | silhouette and palette only |
|
||||
|
||||
A first target is **12 library characters** (the current eight plus the four
|
||||
crowd prototypes), not twenty. That is enough to break the clone effect without
|
||||
doubling the portrait QA matrix. `character_model_for()` becomes a pool per role
|
||||
family with a deterministic seed choice; the current two-way alternation for
|
||||
guests, trespassers and threats is the template.
|
||||
|
||||
## Implementation plan
|
||||
|
||||
The actionable tasks live in `TODO.md` under the `Character development` section. The workstreams
|
||||
are:
|
||||
|
||||
1. **Decision and licence gate.** Complete: ADR-0015, the CC0/CC-BY rule and the
|
||||
committed preview sheets.
|
||||
2. **Generator crowd variants.** Complete as a prototype (four specs, clean
|
||||
audit, review sheet). Production integration is pending the current release candidate.
|
||||
3. **Quaternius intake.** The contract-retarget prototype is a no-go. Keep the
|
||||
source as a reference; a second-rig/animation path would need its own ADR.
|
||||
4. **Roster build and runtime.** Add the four approved specs to `CHARACTERS`,
|
||||
build and commit their GLBs, update the manifest, and extend the role pools.
|
||||
5. **QA and integration.** Run the 24-NPC budget, portrait baseline, gear fit,
|
||||
headless suite and release build. Record provenance and any accepted limits.
|
||||
Only then update `CHANGELOG.md` and `docs/development-status.md`.
|
||||
|
||||
### Adapter notes
|
||||
|
||||
- Apply node transforms before measuring or exporting. CesiumMan imports with a
|
||||
Z-up root and an `Icosphere` helper object; exclude helpers, not just the mesh
|
||||
names, when measuring.
|
||||
- Weld duplicate seam vertices before decimating. Quaternius' 12k imported
|
||||
vertices are mostly UV/normal splits; the underlying surface is much smaller,
|
||||
but the glTF budget counts the splits after export.
|
||||
- Decimate to a target below 8,000 tris/verts, then re-unwrap only if the
|
||||
existing UVs cannot survive the material remap. The current library uses
|
||||
smart projection at 80° to keep islands large.
|
||||
- Map materials by semantic role, not by source name. A source "Purple" or
|
||||
"Worker_Vest" needs an explicit mapping to `cloth`, `pants`, `skin`, `hair` or
|
||||
`accessory`; do not rely on colour heuristics.
|
||||
- Keep the face direction unambiguous. The front is Blender −Y; verify it with
|
||||
a capture, not by guessing from the source file.
|
||||
- For any future external-rig path, do not silently add a second skeleton format
|
||||
to `NpcAvatar`. Record the per-model skeleton, animation source and gear
|
||||
offsets as an explicit contract.
|
||||
|
||||
## Review outcome
|
||||
|
||||
The project owner answered the review questions on 2026-11-03:
|
||||
|
||||
| Question | Answer |
|
||||
| --- | --- |
|
||||
| Are third-party CC0 characters acceptable? | Yes. |
|
||||
| Which direction? | Prototype Quaternius and extend the procedural generator. |
|
||||
| Which looks first? | Crowd variety. |
|
||||
| Should MakeHuman be pursued? | Evaluate it for a later, separate local development pipeline. |
|
||||
| Commit the previews? | Yes, with CC-BY attribution. |
|
||||
|
||||
## Downloaded example provenance
|
||||
|
||||
Source models were downloaded on 2026-11-03 and kept out of version control. The two
|
||||
research preview sheets are committed under `docs/blender_previews/`; the CC-BY
|
||||
attribution is recorded in `CREDITS.md`.
|
||||
|
||||
| File | Source | SHA-256 |
|
||||
| --- | --- | --- |
|
||||
| `quaternius/Casual_Hoodie.glb` | `raw.githubusercontent.com/LuanDucate/Ducz.CharacterCreator/HEAD/public/models/Male/Casual_Hoodie.glb` (Quaternius CC0) | `f5b722199f7628b24550989af4230f65d5230727df9c326fd2b3e360effe5249` |
|
||||
| `quaternius/Worker.glb` | same mirror, `Male/Worker.glb` | `8d0f454336c2effc5c08f63a177af3a82d1a7af025ca9588b40e4c90c4703534` |
|
||||
| `quaternius/Casual.glb` | same mirror, `Female/Casual.glb` | `bc2d84fba249ebaa0629cb9d133ad37234196e4b8004aa205a6397abed04e05c` |
|
||||
| `kenney_blocky_characters.zip` | `kenney.nl/assets/blocky-characters` | `5e123859aa0c1598342b600c6db197024a1d63eb9ec531398b310725f589887e` |
|
||||
| `khronos/CesiumMan.glb` | `github.com/KhronosGroup/glTF-Sample-Assets` | `b7001eaeea8254bd44773bcd247e78696d94169388fbb2a1800fc69434e777d9` |
|
||||
| `khronos/RiggedFigure.glb` | same repository | `d6be85417d3e256861ee733eea6916093a7af7c79c16366181fd8abcaeb38cf5` |
|
||||
| `makehuman/base.obj` | `github.com/makehumancommunity/makehuman/blob/master/makehuman/data/3dobjs/base.obj` | `8e761e6624b8f54536409135d1636da63b32486a90d4897f84e121d144f6fb4c` |
|
||||
|
||||
Source terms:
|
||||
|
||||
- Quaternius packs are CC0 1.0 according to the pack page and the mirror's
|
||||
credits. The mirror is a convenience download; the original pack page is
|
||||
<https://quaternius.com/packs/ultimatemodularcharacters.html>.
|
||||
- Kenney Blocky Characters 2.0 is CC0 1.0; the pack's `License.txt` is included
|
||||
in the download.
|
||||
- CesiumMan and RiggedFigure are CC BY 4.0, © 2017 Cesium. If any derivative is
|
||||
committed or shipped, the attribution must be added to `CREDITS.md`.
|
||||
- MakeHuman core assets are CC0 per `LICENSE.ASSETS.md`; the application source
|
||||
is AGPL and is not bundled.
|
||||
@@ -13,6 +13,14 @@ 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
|
||||
@@ -74,7 +82,7 @@ pass every applicable item before a library rebuild is accepted.
|
||||
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, beanies, hoods,
|
||||
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.
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
Visual references and generated QA evidence for Gig Line.
|
||||
|
||||
- [`refs/README.md`](refs/README.md) — licensed real-location photos, provenance sidecars and the licence/privacy rules
|
||||
- [`concepts/README.md`](concepts/README.md) — AI-assisted realism concept frames
|
||||
- [`designs/README.md`](designs/README.md) — screen-design mockups
|
||||
- [`../screenshots/README.md`](../screenshots/README.md) — committed game gallery
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
# Three-up boards: photo | concept | capture
|
||||
|
||||
Each strip lines up the three image sources for one venue state so the evidence
|
||||
chain stays visible: the licensed real photo is the **evidence**, the generated
|
||||
frame is the **proposal** (geometry anchored on the photo; see the
|
||||
[concepts board](../concepts/README.md) and each frame's `.refgen.json`), and
|
||||
the game capture is the **proof** of the current build. Where the concept and
|
||||
the photo disagree, the photo wins for shape; the capture shows the gap the
|
||||
facade-realism work has to close.
|
||||
|
||||
Composed with `tools/three_up.py compose` (labels baked in; the photo panel's
|
||||
attribution lives in the caption and the [refs sidecars](../refs/README.md)).
|
||||
|
||||
| Board | Caption |
|
||||
| --- | --- |
|
||||
|  | El Capitan facade, day. Photo: [CC BY 2.0, woo, 2009](https://commons.wikimedia.org/wiki/File:El_Capitan_Theater_frontal_fachade-The_Masonic_Temple.jpg) via `refs/hollywood`. Concept: photo-anchored generation. Capture: current build with the ashlar limestone field (`limestone_ashlar`, anchored on the same photo). |
|
||||
|  | El Capitan block, night. Photo: CC BY-SA 3.0 (reviewed; redistribution only, no derived assets) via `refs/hollywood`. Concept: photo-anchored night restage. Capture: current build. |
|
||||
|  | Joke Shop frontage, day. Photo: local-only research frame (`tmp/research/comedy-store`, gitignored). Concept: photo-anchored (gemini + gpt). Capture: current build with the `dark_stucco` wall tile. |
|
||||
|
After Width: | Height: | Size: 174 KiB |
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"board": "elcapitan-day-board.jpg",
|
||||
"caption": "El Capitan facade, day. Photo: CC BY 2.0 2009 via refs/hollywood. Concept: photo-anchored. Capture: ashlar limestone pass (limestone_ashlar, 768 px tile, ~167 px/m).",
|
||||
"photo": "docs/screens/refs/hollywood/el-capitan-facade-day-wikimedia-2009-10-27.jpg",
|
||||
"concept": "docs/screens/concepts/hollywood_boulevard/hollywood_boulevard_entrance_day-v2.png",
|
||||
"capture": "docs/screenshots/01-venue-overview.png"
|
||||
}
|
||||
|
After Width: | Height: | Size: 107 KiB |
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"board": "elcapitan-night-board.jpg",
|
||||
"caption": "El Capitan block, night: CC BY-SA photo (redistribution only) | photo-anchored concept | current capture (banner self-light + facade washes).",
|
||||
"photo": "docs/screens/refs/hollywood/hollywood-boulevard-night-context-ccbysa.jpg",
|
||||
"concept": "docs/screens/concepts/hollywood_boulevard/el_capitan_facade_night.png",
|
||||
"capture": "docs/screenshots/05-late-night-avenue.png"
|
||||
}
|
||||
|
After Width: | Height: | Size: 117 KiB |
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"board": "jokeshop-day-board.jpg",
|
||||
"caption": "Joke Shop frontage, day. Photo: local-only research frame (tmp/research/comedy-store). Concept: photo-anchored (gemini + gpt). Capture: 6.0 m low hall, dark stucco, white signature band, tied-back curtains, west hotel tower.",
|
||||
"photo": "tmp/research/comedy-store/01.jpg",
|
||||
"concept": "docs/screens/concepts/joke_shop/joke_shop_entrance_day-v2.png",
|
||||
"capture": "docs/screenshots/12-joke-shop.png"
|
||||
}
|
||||
@@ -1,6 +1,13 @@
|
||||
# Scene concepts: the realistic target look
|
||||
|
||||
These are AI-generated example frames (`python3 tools/scene_concepts.py generate --group scene`, `openai/gpt-5-image-mini`, 1280×720) for the realism pass. They are art direction, not assets. `tools/scene_concepts.py realism` pairs them with the in-game shots from `src/test/capture_realism.gd` (see `SHOTS` in the tool). New generations never overwrite a file here; they are saved as `<name>-vN.png`.
|
||||
These are AI-generated example frames for the realism pass. They are art direction, not assets.
|
||||
`tools/scene_concepts.py realism` pairs them with the in-game shots from `src/test/capture_realism.gd`
|
||||
(see `SHOTS` in the tool). New generations never overwrite a file here; they are saved as
|
||||
`<name>-vN.png`.
|
||||
|
||||
Concepts are organised per venue in the two subfolders below. The older top-level single-frame
|
||||
concepts were removed on 2026-11-03 in favour of the per-venue boards, which carry photo-anchored
|
||||
generations with a `.refgen.json` provenance sidecar each (source photo, licence, model).
|
||||
|
||||
## Real-world Hollywood block
|
||||
|
||||
@@ -10,37 +17,10 @@ The map-optimization references for the El Capitan Entertainment Centre block
|
||||
facts and game mapping are documented in
|
||||
[`../../hollywood-boulevard-map.md`](../../hollywood-boulevard-map.md).
|
||||
|
||||
## Concept list
|
||||
|
||||
### Hollywood Entrance
|
||||
|
||||

|
||||
warm low sun, long soft shadows, brick with visible mortar and wear, stone plinth, potted topiary, haze that fades the far street to beige
|
||||
|
||||
### Hollywood Entrance Golden Hour
|
||||
|
||||

|
||||
strong back light and rim light on people, marquee bulbs reading even in daylight
|
||||
|
||||
### Hollywood Entrance Rain Night
|
||||
|
||||

|
||||
dark scene lit by practical lights only (marquee, sodium lamps), wet glossy ground with reflections, fog
|
||||
|
||||
### Boulevard Skyline
|
||||
|
||||

|
||||
deep layered skyline with real towers and haze, palms lining the road, red curb paint, believable asphalt
|
||||
|
||||
### Boulevard Skyline Dusk
|
||||
|
||||

|
||||
purple/orange gradient sky, neon signs, lit windows, car light trails
|
||||
|
||||
### The Joke Shop — Sunset Strip
|
||||
## The Joke Shop — Sunset Strip
|
||||
|
||||
The current Joke Shop map is based on The Comedy Store at 8433 Sunset Blvd.
|
||||
The real-site mapping, simplifications and reference photographs are in
|
||||
The real-site mapping and simplifications are in
|
||||
[`../../joke-shop-map.md`](../../joke-shop-map.md); the frames are in
|
||||
[`joke_shop/README.md`](joke_shop/README.md).
|
||||
|
||||
@@ -48,56 +28,15 @@ The real-site mapping, simplifications and reference photographs are in
|
||||
|
||||

|
||||
|
||||
### Legacy Joke Shop Alley (pre-map optimization)
|
||||
## Cross-cutting targets
|
||||
|
||||

|
||||
narrow brick alley, one warm wall lantern as key light, deep shadows, people in dark jackets
|
||||
For comparison with locally generated realism runs (`docs/screens/realism/`, gitignored):
|
||||
|
||||

|
||||
close material detail: brick, mortar, aged wood door, brass
|
||||
|
||||
These two frames describe the old alley layout and are retained for comparison;
|
||||
they are no longer the target for the Joke Shop map.
|
||||
|
||||
### Studio Stage Door Night
|
||||
|
||||

|
||||
granite facade, a bright bulb canopy as the main light, a glossy black car, stanchions and a barrier
|
||||
|
||||
### Sidewalk Material Closeup
|
||||
|
||||

|
||||
paver joints, stains, granite curb, aggregate asphalt and a tree grate at grazing light
|
||||
|
||||
### Entrance Steps Podium
|
||||
|
||||

|
||||
granite steps, handrails, glass doors, the check-in podium
|
||||
|
||||
### Crowd Barrier Line
|
||||
|
||||

|
||||
steel barriers, a red carpet, a crowd with depth-of-field haze
|
||||
|
||||
### Responder Arrival Wide
|
||||
|
||||

|
||||
fire engine, turnout gear, red/blue light spill on wet pavement
|
||||
|
||||
### NPC Portrait Day
|
||||
|
||||

|
||||
close portrait of a pedestrian: skin with visible pores and stubble, fabric weave, shallow depth of field. The bar for an avatar close-up, not for the crowd shots
|
||||
|
||||
The `npc_portrait` capture in `capture_realism.gd` is staged, not posed by the crowd: it freezes one NPC on an open patch of sidewalk, parks the rest of the crowd out of frame, turns the subject into the camera and stands the guard on the sunlit side. It is the only shot where a face fills the frame, so it is the one to eyeball after an avatar change (generate a local run under `docs/screens/realism/`).
|
||||
|
||||
Cross-cutting targets, for comparison with locally generated realism runs:
|
||||
|
||||
- **Exposure.** The concepts keep the ground mid-grey. The game's sidewalk is close to white, so it is overexposed.
|
||||
- **Night means dark.** The night/dusk concepts are lit by practical lights. The game's "Evening" phase is a bright pink-orange frame.
|
||||
- **Depth.** The concepts show a layered skyline fading into haze. The new v2 skyline strips supply this; the old box skyline did not.
|
||||
- **Geometry and foliage.** The facades have plinths, cornices and deep window reveals, and the trees and shrubs are organic. The game uses flat walls and blob trees.
|
||||
|
||||
## Additional previews
|
||||
|
||||

|
||||
- **Exposure.** The concepts keep the ground mid-grey; the game's sidewalk reads lighter, so it
|
||||
overexposes against the reference.
|
||||
- **Night means dark.** The night/dusk concepts are lit by practical lights only (marquee,
|
||||
signage, street lamps), with wet pavement reflections.
|
||||
- **Depth.** The concepts show a layered skyline fading into haze; the v2 skyline strips supply
|
||||
this at the boulevard boundary.
|
||||
- **Geometry and foliage.** The facades have plinths, cornices and deep window reveals, and the
|
||||
trees and shrubs are organic; the venue-realism passes close these gaps incrementally.
|
||||
|
Before Width: | Height: | Size: 1.3 MiB |
|
Before Width: | Height: | Size: 1.1 MiB |
|
Before Width: | Height: | Size: 1.1 MiB |
|
Before Width: | Height: | Size: 1.5 MiB |
@@ -10,6 +10,33 @@ game textures. The geometry mapping and source links are in
|
||||
|
||||

|
||||
|
||||
## Entrance — day, photo-anchored
|
||||
|
||||

|
||||
|
||||
Generated with `generate --reference`, anchored on the licence-cleared
|
||||
[`el-capitan-facade-day-wikimedia-2009-10-27.jpg`](../../refs/hollywood/el-capitan-facade-day-wikimedia-2009-10-27.jpg)
|
||||
board photo (CC BY 2.0); provenance in
|
||||
[`hollywood_boulevard_entrance_day-v2.refgen.json`](hollywood_boulevard_entrance_day-v2.refgen.json).
|
||||
The facade geometry (motto band, column rhythm, lattice windows, banner slots,
|
||||
blade sign) follows the photograph; the street is restaged clean for art
|
||||
direction.
|
||||
|
||||
## Facade — night (photo-anchored)
|
||||
|
||||

|
||||
|
||||
Same facade photo as the day frame, restaged to night with practical lighting
|
||||
only (marquee, signage, street lamps) and wet pavement. The blade sign, banner
|
||||
slots and lattice windows follow the photograph.
|
||||
|
||||
## Facade — overcast (photo-anchored)
|
||||
|
||||

|
||||
|
||||
Same framing under flat overcast light. The weathering requested came out
|
||||
mild — treat this as the overcast target, not a decay reference.
|
||||
|
||||
## Entrance — night
|
||||
|
||||

|
||||
@@ -17,3 +44,32 @@ game textures. The geometry mapping and source links are in
|
||||
## Across the boulevard
|
||||
|
||||

|
||||
|
||||
## Jimmy Kimmel Live entrance — local-reference anchored, two models
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
Four frames anchored on the same local-only research photo
|
||||
(`tmp/research/jimmy-kimmel-entrance/07.jpg`, gitignored) with `--reference-unchecked`, two
|
||||
treatments (day, night) × two models (`google/gemini-2.5-flash-image`, `openai/gpt-5-image-mini`).
|
||||
Provenance and model are in each frame's `.refgen.json` sidecar. The building is the starting-point
|
||||
venue: the El Capitan Entertainment Centre carrying the "Jimmy Kimmel Live!" marquee over the
|
||||
six-column Masonic Temple facade.
|
||||
|
||||
## Facade — local-reference anchored, two models
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
Both frames are anchored on the same local-only research photo
|
||||
(`tmp/research/elcapitan/01.jpg`, gitignored) with `--reference-unchecked`, one with
|
||||
`google/gemini-2.5-flash-image` and one with `openai/gpt-5-image-mini`. Provenance and model are
|
||||
in each frame's `.refgen.json` sidecar. Local reference only; the photo never enters the repo and
|
||||
these frames are art direction, not assets.
|
||||
|
After Width: | Height: | Size: 1.5 MiB |
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"concept": "el_capitan_facade_gemini_day",
|
||||
"generated": "el_capitan_facade_gemini_day.png",
|
||||
"model": "google/gemini-2.5-flash-image",
|
||||
"reference": {
|
||||
"file": "tmp/research/elcapitan/01.jpg",
|
||||
"licence": "unchecked",
|
||||
"page": "",
|
||||
"licence_checked": false
|
||||
},
|
||||
"suffix": "Use the attached reference photograph as the fixed source of geometry and composition: keep the building's proportions, column rhythm, band heights, signage placement and camera angle exactly as photographed. Only restage lighting, weather, people and surface condition where the prompt asks for it. Do not invent extra storeys, wings or ornaments that the photo does not show."
|
||||
}
|
||||
|
After Width: | Height: | Size: 1.4 MiB |
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"concept": "el_capitan_facade_gpt_day",
|
||||
"generated": "el_capitan_facade_gpt_day.png",
|
||||
"model": "openai/gpt-5-image-mini",
|
||||
"reference": {
|
||||
"file": "tmp/research/elcapitan/01.jpg",
|
||||
"licence": "unchecked",
|
||||
"page": "",
|
||||
"licence_checked": false
|
||||
},
|
||||
"suffix": "Use the attached reference photograph as the fixed source of geometry and composition: keep the building's proportions, column rhythm, band heights, signage placement and camera angle exactly as photographed. Only restage lighting, weather, people and surface condition where the prompt asks for it. Do not invent extra storeys, wings or ornaments that the photo does not show."
|
||||
}
|
||||
|
After Width: | Height: | Size: 1.2 MiB |
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"concept": "el_capitan_facade_night",
|
||||
"generated": "el_capitan_facade_night.png",
|
||||
"model": "google/gemini-2.5-flash-image",
|
||||
"reference": {
|
||||
"file": "docs/screens/refs/hollywood/el-capitan-facade-day-wikimedia-2009-10-27.jpg",
|
||||
"licence": "CC BY 2.0",
|
||||
"page": "https://commons.wikimedia.org/wiki/File:El_Capitan_Theater_frontal_fachade-The_Masonic_Temple.jpg",
|
||||
"licence_checked": true
|
||||
},
|
||||
"suffix": "Use the attached reference photograph as the fixed source of geometry and composition: keep the building's proportions, column rhythm, band heights, signage placement and camera angle exactly as photographed. Only restage lighting, weather, people and surface condition where the prompt asks for it. Do not invent extra storeys, wings or ornaments that the photo does not show."
|
||||
}
|
||||
|
After Width: | Height: | Size: 1.4 MiB |
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"concept": "el_capitan_facade_weathered",
|
||||
"generated": "el_capitan_facade_weathered.png",
|
||||
"model": "google/gemini-2.5-flash-image",
|
||||
"reference": {
|
||||
"file": "docs/screens/refs/hollywood/el-capitan-facade-day-wikimedia-2009-10-27.jpg",
|
||||
"licence": "CC BY 2.0",
|
||||
"page": "https://commons.wikimedia.org/wiki/File:El_Capitan_Theater_frontal_fachade-The_Masonic_Temple.jpg",
|
||||
"licence_checked": true
|
||||
},
|
||||
"suffix": "Use the attached reference photograph as the fixed source of geometry and composition: keep the building's proportions, column rhythm, band heights, signage placement and camera angle exactly as photographed. Only restage lighting, weather, people and surface condition where the prompt asks for it. Do not invent extra storeys, wings or ornaments that the photo does not show."
|
||||
}
|
||||
|
After Width: | Height: | Size: 1.4 MiB |
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"concept": "hollywood_boulevard_entrance_day",
|
||||
"generated": "hollywood_boulevard_entrance_day-v2.png",
|
||||
"model": "google/gemini-2.5-flash-image",
|
||||
"reference": {
|
||||
"file": "docs/screens/refs/hollywood/el-capitan-facade-day-wikimedia-2009-10-27.jpg",
|
||||
"licence": "CC BY 2.0",
|
||||
"page": "https://commons.wikimedia.org/wiki/File:El_Capitan_Theater_frontal_fachade-The_Masonic_Temple.jpg",
|
||||
"licence_checked": true
|
||||
},
|
||||
"suffix": "Use the attached reference photograph as the fixed source of geometry and composition: keep the building's proportions, column rhythm, band heights, signage placement and camera angle exactly as photographed. Only restage lighting, weather, people and surface condition where the prompt asks for it. Do not invent extra storeys, wings or ornaments that the photo does not show."
|
||||
}
|
||||
|
After Width: | Height: | Size: 1.3 MiB |
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"concept": "jimmy_kimmel_entrance_day_gemini_day",
|
||||
"generated": "jimmy_kimmel_entrance_day_gemini.png",
|
||||
"model": "google/gemini-2.5-flash-image",
|
||||
"reference": {
|
||||
"file": "tmp/research/jimmy-kimmel-entrance/07.jpg",
|
||||
"licence": "unchecked",
|
||||
"page": "",
|
||||
"licence_checked": false
|
||||
},
|
||||
"suffix": "Use the attached reference photograph as the fixed source of geometry and composition: keep the building's proportions, column rhythm, band heights, signage placement and camera angle exactly as photographed. Only restage lighting, weather, people and surface condition where the prompt asks for it. Do not invent extra storeys, wings or ornaments that the photo does not show."
|
||||
}
|
||||