Files
security-game/TODO.md
T
zwitschi d513e0b82c Stage the Blender character/gear/prop library
Commit the finished generator output from the parallel Blender pass:
8 skinned NPC variants, 18 gear pieces, and 20 props under
assets/models/blender/, editable sources (gdignored), manifest, review sheets,
and the integration notes in docs/blender-assets.md.

- audit: all 46 assets clean (characters 3,788-4,640 tris, under 6000/4000)
- tests: Python manifest/audit contract and Godot import/bone/slot/ground checks
- docs: README library section, architecture/plan references, TODO Phase 3.5
  status, MEMORY integration rules
- .gitignore: per-asset preview PNGs, extracted GLB textures, blend1 backups

Nothing in the game loads the library yet; integration follows." && git log --oneline -1
2026-11-01 14:33:30 +01:00

15 KiB
Raw Blame History

TODO

Godot 4.3 prototype. Latest release v0.5.0 (NPC characters and player movement). Headless suite 218/218 plus 68 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.

Blender asset library built (2026-11-01): tools/blender_assets.py generated 8 NPC character variants, 18 gear pieces, and 20 street/venue props under assets/models/blender/ (audit clean, Godot import clean, see docs/blender-assets.md). Treat assets/models/blender/manifest.json as the integration source of truth; nothing is wired into the game yet.

Graphics quality — Blender-authored NPC characters (v0.6.0)

Detailed plan: docs/plan-graphics-v0.6.md · ADR-0013

Phase 0 — Toolchain spike and contract freeze

  • Verify flatpak run org.blender.Blender --version reports Blender 5.2.x and runs headless in this shell.
  • Run a minimal headless Blender export using an absolute --python path (sandbox cwd is /app/blender); confirm the output file lands where expected.
  • Record the exact working invocation (flatpak + absolute paths) in MEMORY.md.
  • Freeze the NPC asset contract in docs/plan-graphics-v0.6.md and ADR-0013: file paths, bone names, material slots, triangle budget.
  • Fix the material-slot set (skin / cloth / pants / accessory / hair) and the ORM packing (R=occlusion, G=roughness, B=metallic).
  • Choose and record the initial tier-0 triangle/vertex budget (≤ ~6000 tris / ~4000 verts) in the plan.
  • 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

  • Author the low-poly base humanoid in Blender: torso, articulated arms/legs, head with a face front, hands, shoes.
  • 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.
  • UV-unwrap the mesh into a power-of-two layout, one region per material slot.
  • Save the editable source as assets/models/npc/npc_base.blend (committed).
  • Add tools/npc_pipeline.py with list / build / audit subcommands, run through the Blender flatpak.
  • build exports assets/models/generated/npc_base.glb plus the material textures.
  • Bake neutral albedo per slot, normal maps (fabric weave, denim, knit), and the packed ORM map.
  • Bake ambient occlusion into the albedo or the ORM R channel (the Compatibility renderer has no SSAO).
  • audit enforces UVs in [0,1], expected bone names, triangle/vertex budget, feet at y≈0, and material-slot presence.
  • Reuse the model_pipeline.py colour-space discipline (linear factors vs sRGB textures) in the exporter.
  • Run godot --headless --path . --import and confirm npc_base.glb imports without errors.

Phase 2 — AI-assisted texturing

  • 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).
  • Tile-edge blending on each fabric — applied automatically by generate --role tile (make_seamless); the tile audit's edge check confirms continuity.
  • Run asset_pipeline.py audit on the outputs — 6 good, 0 bad (role tile).
  • Commit the validated textures under assets/textures/npc/ai/ (tracked in the v0.6.0 asset commit).
  • Derive per-role outfit palettes via model_pipeline.dominant_colors — written to assets/textures/npc/palette.json (npc_pipeline.py palette).
  • 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).
  • 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

  • Add NpcAvatar._load_model() that instantiates the imported npc_base.glb PackedScene.
  • Keep _build_body() as the offline fallback; choose per-avatar and record loaded_model / fallback_avatar for tests.
  • Map outfit_for() onto the model's material slots so seed variety, layer_for, hand_item_for, and archetype colors survive.
  • Keep accessory attachments (cap / hood / backpack / sunglasses / lanyard) under Rig / Head.
  • Add SurfaceMaterials baked-map recipes (npc() / skin() / cloth()); stop calling Materials.flat() for the body.
  • Add _set_limb_rotation() so _animate() / _idle_layer() write to bones or pivots; keep Rig/Head findable by the focus cone.
  • Update test_npc_character, test_npc_theater, and test_target_cycle for the skinned path (or document why they stay on the fallback).
  • Re-measure smoke_npc_budget.gd; tune LOD_TIERS if the skinned rig is heavier up close.
  • Re-verify the focus-cone smoke (smoke_focus_radial.gd) and the movement smoke.

Phase 3.5 — Blender asset library integration

Contract and outputs: assets/models/blender/manifest.json, generator tools/blender_assets.py, review sheets docs/blender_previews/sheet_*.jpg, integration notes docs/blender-assets.md. The library has 8 npc variants, 18 npc_gear pieces, and 20 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. Characters were reduced to fit the unchanged 6,000/4,000 contract (now 3,788–4,640 tris / 3,195–3,962 verts); the audit also rejects zero-area triangles.
  • 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. (.gitignore already excludes the per-asset preview PNGs, Godot-extracted GLB textures, and *.blend1.)
  • Add src/test/tests/test_blender_assets.gd: library imports as scenes, characters keep bones/slots, joints match npc_base, bones accept the avatar pose math, props grounded.
  • Tint only the five contract slots in _apply_outfit_materials() (fixed-colour detail materials such as hivis/reflective/leather must keep their colour), and skip the vest cloth→yellow override for npc_vest (its vest is the fixed hivis material).
  • Bake AO/ORM for the Blender characters and props (they currently reuse tiling slot maps or plain PBR factors).
  • 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.