Files
security-game/TODO.md
T
zwitschi 7efb5024ec Extend the v0.6.0 plan with the Blender asset library
Document the larger asset set produced by the running Blender generator
(tools/blender_assets.py): 8 NPC character variants, 18 gear pieces, and 22
street/venue props with a manifest, editable sources, and preview sheets.

- TODO gains Phase 3.5 with the audit/budget reconciliation (npc_casual is
  currently 7,756 tris / 5,616 verts, above the 6,000/4,000 contract), character
  selection by role, gear attach points, prop replacement/placement, emissive
  wiring, budgets, and screenshot gates
- PLAN's Visual Quality Direction describes the library, runtime selection, and
  offline fallbacks
- docs/plan-graphics-v0.6.md adds the library contract/output table and
  integration steps, and points Phase 4 at the Blender props
- MEMORY records the manifest-as-source-of-truth rule and the generator caveat

Generated library files stay untracked until the running build finishes and
passes the audit; the generator itself is committed so the plan is reproducible.
2026-11-01 13:39:03 +01:00

186 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# TODO
Godot 4.3 prototype. Latest release **v0.5.0** (NPC characters and player movement). Headless
suite **212/212** plus **60** Python tooling tests; the session, PLAN-verb, crowd, emergency,
timeline, audio, scenario-content, props, NPC-budget, movement, and windowed focus/radial smokes
pass. Anonymous downloads are enabled on the host.
The scheduled presentation pass is complete (see `DONE.md`). The next scheduled pass is the
graphics-quality work in [`docs/plan-graphics-v0.6.md`](docs/plan-graphics-v0.6.md).
> **Asset build in progress:** `tools/blender_assets.py` is being run separately (flatpak
> Blender) to generate a larger library: 8 NPC character variants, 18 gear pieces, and 22
> street/venue props under `assets/models/blender/`, with a manifest and preview renders.
> Do not edit the generator while that process is running. Treat
> `assets/models/blender/manifest.json` as the integration source of truth, and audit the
> finished outputs before wiring anything into the game.
## Graphics quality — Blender-authored NPC characters (v0.6.0)
Detailed plan: [`docs/plan-graphics-v0.6.md`](docs/plan-graphics-v0.6.md) · [ADR-0013](docs/adr/0013-blender-authored-npc-characters.md)
### Phase 0 — Toolchain spike and contract freeze
- [x] Verify `flatpak run org.blender.Blender --version` reports Blender 5.2.x and runs headless in this shell.
- [x] Run a minimal headless Blender export using an absolute `--python` path (sandbox cwd is `/app/blender`); confirm the output file lands where expected.
- [x] Record the exact working invocation (flatpak + absolute paths) in `MEMORY.md`.
- [x] Freeze the NPC asset contract in `docs/plan-graphics-v0.6.md` and ADR-0013: file paths, bone names, material slots, triangle budget.
- [x] Fix the material-slot set (`skin` / `cloth` / `pants` / `accessory` / `hair`) and the ORM packing (R=occlusion, G=roughness, B=metallic).
- [x] Choose and record the initial tier-0 triangle/vertex budget (≤ ~6000 tris / ~4000 verts) in the plan.
- [x] Spike: Godot 4.3 imports the `.glb` as a `PackedScene` with a `Skeleton3D`; no clips are needed because `_animate()` drives the bones at runtime.
### Phase 1 — Blender authoring + export pipeline
- [x] Author the low-poly base humanoid in Blender: torso, articulated arms/legs, head with a face front, hands, shoes.
- [x] Rig with an armature whose bones mirror the node contract (`Head`, `HipL/R`, `KneeL/R`, `ShoulderL/R`, `ElbowL/R`, `HandL/R`); origin at the feet, +Y up.
- [x] UV-unwrap the mesh into a power-of-two layout, one region per material slot.
- [x] Save the editable source as `assets/models/npc/npc_base.blend` (committed).
- [x] Add `tools/npc_pipeline.py` with `list` / `build` / `audit` subcommands, run through the Blender flatpak.
- [x] `build` exports `assets/models/generated/npc_base.glb` plus the material textures.
- [x] Bake neutral albedo per slot, normal maps (fabric weave, denim, knit), and the packed ORM map.
- [x] Bake ambient occlusion into the albedo or the ORM R channel (the Compatibility renderer has no SSAO).
- [x] `audit` enforces UVs in [0,1], expected bone names, triangle/vertex budget, feet at y≈0, and material-slot presence.
- [x] Reuse the `model_pipeline.py` colour-space discipline (linear factors vs sRGB textures) in the exporter.
- [x] Run `godot --headless --path . --import` and confirm `npc_base.glb` imports without errors.
### Phase 2 — AI-assisted texturing
- [x] Generate seamless clothing albedos (shirt, trousers, jacket, hi-vis vest, coat, dress) with `tools/asset_pipeline.py generate` (OpenRouter, `openai/gpt-5-image-mini`) — written to `assets/textures/npc/ai/` (512×512).
- [x] Tile-edge blending on each fabric — applied automatically by `generate --role tile` (`make_seamless`); the `tile` audit's edge check confirms continuity.
- [x] Run `asset_pipeline.py audit` on the outputs — 6 good, 0 bad (role `tile`).
- [x] Commit the validated textures under `assets/textures/npc/ai/` (tracked in the v0.6.0 asset commit).
- [x] Derive per-role outfit palettes via `model_pipeline.dominant_colors` — written to `assets/textures/npc/palette.json` (`npc_pipeline.py palette`).
- [x] Bake normal/roughness procedurally and layer the AI albedos on top — `npc_pipeline.py prepare` + Blender `build` keeps the AI albedo for `cloth`/`pants` and regenerates normal/ORM; GLB audit ok (1204 tris / 2488 verts).
- [x] Regenerate the staged captures and run `screen_designs.py judge` after the Phase 3 integration (11 good / 0 bad in `compare`; judge: no diff).
### Phase 3 — Godot integration
- [x] Add `NpcAvatar._load_model()` that instantiates the imported `npc_base.glb` `PackedScene`.
- [x] Keep `_build_body()` as the offline fallback; choose per-avatar and record `loaded_model` / `fallback_avatar` for tests.
- [x] Map `outfit_for()` onto the model's material slots so seed variety, `layer_for`, `hand_item_for`, and archetype colors survive.
- [x] Keep accessory attachments (cap / hood / backpack / sunglasses / lanyard) under `Rig` / `Head`.
- [x] Add `SurfaceMaterials` baked-map recipes (`npc()` / `skin()` / `cloth()`); stop calling `Materials.flat()` for the body.
- [x] Add `_set_limb_rotation()` so `_animate()` / `_idle_layer()` write to bones or pivots; keep `Rig/Head` findable by the focus cone.
- [x] Update `test_npc_character`, `test_npc_theater`, and `test_target_cycle` for the skinned path (or document why they stay on the fallback).
- [x] Re-measure `smoke_npc_budget.gd`; tune `LOD_TIERS` if the skinned rig is heavier up close.
- [x] Re-verify the focus-cone smoke (`smoke_focus_radial.gd`) and the movement smoke.
### Phase 3.5 — Blender asset library integration (generator running)
Contract and outputs: [`assets/models/blender/manifest.json`](assets/models/blender/manifest.json),
generator `tools/blender_assets.py`, previews `docs/blender_previews/` (the generator's
integration notes are being written to `docs/blender-assets.md`). The library currently targets
8 `npc` variants, 18 `npc_gear` pieces, and 22 `props`; each entry records path, triangle/vertex
count, bounds, material slots, and (for gear) its attach point.
- [ ] Wait for the running build to finish, then run `python3 tools/blender_assets.py audit` and
reconcile every failure. The first `npc_casual` build is over the 6,000-triangle contract
(7,756 tris / 5,616 verts): reduce the mesh or raise/annotate the character budget in the
plan before integrating.
- [ ] Run `python3 tools/blender_assets.py sheet` and review the contact sheets; reject assets
whose silhouette, grounded origin, or face direction (+Z in Godot) is wrong.
- [ ] Commit the finished library with the generator, `.blend` sources, manifest, previews, and
`docs/blender-assets.md`; add generated/preview folders to `.gitignore` only where CI can
rebuild them offline. Keep the audit runnable without Blender.
- [ ] Add `tools/test_blender_assets.py` for the manifest contract (all catalogue entries present,
audit clean, attach points known, paths inside `assets/models/blender/`).
- [ ] Let `NpcAvatar` choose a character model from the manifest by the profile's role/layer
(`npc_casual` / `npc_jacket` / `npc_coat` / `npc_vest` / `npc_dress` / `npc_hoodie` /
`npc_firefighter` / `npc_guard`), with the existing `npc_base.glb` and procedural rig as
fallbacks; record the chosen path for tests.
- [ ] Keep `outfit_for()` tinting the `skin`/`cloth`/`pants`/`accessory`/`hair` slots on every
variant and keep `Rig/Head` as the focus/nametag anchor.
- [ ] Replace the procedural cap/hood/backpack/sunglasses/lanyard and hand items with the
matching `npc_gear` assets at the documented `head` / `back` / `chest` / `hand` attach
points; fall back to the current primitives when gear is missing.
- [ ] Load the replacement props (`bollard`, `bench`, `trash_bin`, `planter_box`,
`newspaper_box`, `fire_hydrant`, `street_lamp`, `street_tree`, `traffic_cone`) from the
Blender library behind the existing `WorldBuilder` model/fallback path.
- [ ] Place the new street/venue props (`palm_tree`, `round_planter`, `a_frame_sign`,
`wall_lantern`, `crowd_barrier`, `stanchion`, `handrail`, `security_podium`,
`double_door`, `marquee`, `sedan`) through `PROP_PLACEMENTS`/dedicated venue slots, with
collider + `NavigationObstacle3D` footprints and no overlap with the door/approach lane.
- [ ] Wire the emissive parts (`street_lamp` bulb, `wall_lantern`, `double_door` lock LED,
`marquee` bulbs/sign face, `sedan` headlights) to the day/night phase lighting instead of
leaving them always on.
- [ ] Use the library `street_tree`/`palm_tree` instead of the current cone trees, and the
Blender `marquee`/`double_door` where the procedural versions currently sit; compare
silhouettes with `screen_designs.py`.
- [ ] Re-measure `smoke_npc_budget.gd` and add a prop draw/triangle budget check; keep
`MAX_LIVE_NPCS` unchanged until the new characters are measured.
- [ ] Regenerate all staged captures and run `screen_designs.py compare` + `judge`; add a
character close-up capture (the 02 target shot) to the catalogue if needed.
### Phase 4 — Environment and lighting lift
- [ ] Bake AO for the prop set through the Blender library (replacements above) or into the ORM/albedo maps behind the existing `WorldBuilder` contract; keep the procedural fallback.
- [ ] Regenerate higher-resolution brick / concrete / asphalt textures via `asset_pipeline.py` with normal maps, keeping the current UV scales; apply the same map discipline to the library's street materials.
- [ ] Evaluate a desktop-only Forward+ export preset (SSAO/SSIL/volumetrics); keep the Web preset on GL Compatibility with `thread_support=false`.
- [ ] Record the renderer decision in an ADR addendum or `MEMORY.md`.
- [ ] Regenerate `docs/screenshots/` with `capture_screenshots.gd` and run `screen_designs.py compare`.
### Phase 5 — Verification and release
- [ ] Headless suite green: fallback build, outfit determinism, `Rig/Head` presence, material recipe assertions, `npc_pipeline.py audit`, and `blender_assets.py audit` + manifest tests (skip Blender builds with a reason when Blender is absent).
- [ ] Windowed smokes pass: `smoke_npc_budget.gd`, `smoke_movement.gd`, `smoke_focus_radial.gd`, `smoke_props.gd`.
- [ ] `screen_designs.py compare` and `judge` show no regressions; `blender_assets.py sheet` contact sheets reviewed for the character/gear/prop library.
- [ ] Bump `config/version` to `0.6.0`.
- [ ] Update `README.md`, `docs/architecture.md` (Level 2 gains `tools/npc_pipeline.py`), and mark ADR-0013 Accepted.
- [ ] Publish the release per `docs/RELEASING.md`.
## Visual alignment with rendered mockups
The AI-rendered references in `docs/screens/designs/` (start menu, pause, settings,
shift review, radial menu, HUD, scene views) describe the intended look of every
screen. This pass reorganizes how generated images are stored, makes the game load
the proposed interface/scene art from disk, and aligns the selection screens, HUD,
and scene visuals with those mockups — verified with
`tools/screen_designs.py compare` + `judge`.
### Storage restructure
- [ ] Decide the canonical runtime image root (e.g. `assets/images/` for UI/scene art) and record it in `MEMORY.md` and an ADR.
- [ ] Move the reference mockups from `docs/screens/designs/` into the runtime root (keep `docs/screens/designs/` as a docs-only copy or replace it with the new path).
- [ ] Document one convention for game vs reference vs development images across `assets/textures/`, `assets/images/`, `assets/models/generated/`, `docs/screenshots/`, and `docs/screens/designs/`.
- [ ] Re-run `godot --headless --path . --import` to regenerate `.import` sidecars after any move.
- [ ] Confirm `.gitignore` still excludes development-only outputs (concepts, Blender sources, raw AI fabrics) under the new layout.
### Documentation path updates
- [ ] Update `README.md` paths (screen-designs section, confirmed-assets links, the `assets/images/backgrounds` resize example).
- [ ] Update `docs/architecture.md`, `PLAN.md`, and ADR-0010/0011/0012/0013 references to `docs/screens/designs/`.
- [ ] Update `tools/screen_designs.py` docstrings and mark the old paths in `DONE.md` as historical.
### Code path updates
- [ ] Point `tools/screen_designs.py generate` at the new design output path and keep `compare`/`judge` reading the right locations.
- [ ] Update GDScript `preload()` paths (`materials.gd`, `hud.gd`, `world_builder.gd`) if the game textures move.
- [ ] Update `capture_screenshots.gd` / `capture_prop_gallery.gd` output directories if captures relocate.
### Load proposed interfaces + scene art from disk
- [ ] 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.
- [ ] Wire the start menu and venue selection screen to use the `start_menu` scene art.
- [ ] Wire the pause overlay, settings, shift review, radial menu, and HUD chrome to their reference images.
### Align in-game visuals
- [ ] Make the venue selection screen match the `start_menu` mockup (layout, palette, background).
- [ ] Make the HUD match the `targeting_npc` / `escalation_hud` mockups (focus ring, escalation meter, log, hints).
- [ ] Align the remaining panels (pause, settings, shift review, radio, wand, timeline) to their mockups.
- [ ] Align scene lighting, fog, and post-processing for `venue_overview` and `late_night_avenue`.
### Verify against the mockups
- [ ] Regenerate the staged captures and run `screen_designs.py compare` (no gross drift).
- [ ] Run `screen_designs.py judge` and clear every `diff` verdict (target `match`/`review`).
- [ ] Add the capture + compare step to CI or a repeatable smoke so drift is caught early.
## 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).
- [ ] Swap the primitive prop builder for an image-to-mesh model API behind the same
`assets/models/generated/<prop>.glb` contract.