Files
security-game/TODO.md
T
zwitschi 1ee32215b0
Full build / Import + headless tests (push) Successful in 38s
Full build / Full desktop build + optional release (push) Skipped
Detail the NPC avatars and finish the realism follow-ups
Blender library
- Rebuild the face: sclera, iris and upper lid per eye, brow ridge, cheekbones,
  nose bridge and tip, ears with lobes, split upper/lower lips.
- Give each hand four fingers plus a thumb and end every sleeve in a cuff ring.
- Raise CHAR_MAX_VERTS 4000 -> 5000 (16 avatars still cost ~6.9 ms of a 50 ms
  frame), decimate the body to 26 %; characters are now 3,974-5,026 tris and
  3,744-4,807 verts. Rebuild all 8 variants and re-bake their AO maps.

Capture tooling
- Add a `portrait` stage to capture_realism.gd: freeze one NPC, park the crowd
  out of frame, stand the subject on open sidewalk, turn it into the camera and
  put the guard on the sunlit side. New --portrait-type=N picks the role.
- Add the npc_portrait_day concept and map the shot to it, so avatar detail is
  scored against a portrait instead of a wide street frame.

Flashlight
- Drop the fake additive beam (Materials.light_beam + the cone mesh): on GL
  Compatibility a first-person camera inside the cone renders it as a filled
  disc with a bright far ring. Keep the tight spot (14 deg, 20 m, energy 4.2)
  and its headless test; the visible shaft is now planned behind a Forward+
  preset.

Docs and task tracking
- Move the finished realism follow-ups (ground exposure, flashlight, NPC detail,
  judge re-check) to DONE.md and expand TODO.md with step-by-step plans for NPC
  gear fit, venue geometry plus the committed gallery, and the Forward+ preset.
- Record the decisions, gotchas and portrait recipe in MEMORY.md; update the
  Blender contract, the concept README and the capture section of README.md.
- Refresh the gallery captures affected by the avatar rebuild.

Checks: headless 228/228, Python 86/86, blender_assets audit exit 0,
scene_concepts audit all GOOD, screen_designs compare 11 good / 0 bad,
smoke_npc_budget OK, boot clean (only the known headless mesh warning).
2026-11-01 17:46:25 +01:00

6.8 KiB
Raw Blame History

TODO

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.

NPC gear fit (v0.6.1)

The 2026-11-01 detail pass fixed the bodies but not the props worn on them. In the portrait capture (--stages=day,portrait, see the report in docs/screens/realism/2026-11-01-npc/) the sunglasses span the whole upper face and the shoulder bag cuts through npc_coat's skirt. Blender sources for gear live in tools/blender_assets.py (_build_gear()), the contract in docs/blender-assets.md (gear budget 1500 tris, GEAR_ATTACH points in NpcAvatar).

  • Measure the fit in Blender, not by eye: extend blender_assets.py audit (or add a fit subcommand) to print, per head/back/chest gear piece, its bounding box against the avatar head width (measured 0.314 m on npc_coat), the head height band (y 1.55–1.81) and the clothing radius (coat/dress skirt flare 0.225–0.26 m), for every character variant.
  • Narrow sunglasses from 0.28 m to ~0.20 m. The width is driven by the arms/hinges (Hinge at x = ±0.11 with a 0.06 box, Arm at ±0.138), not by the 0.03 m lenses, so pull those in first and shrink the lenses to ~0.024 m radius; keep the lens plane at y = -0.152 (in front of the sclera) and z = 0.035 (eye line) so it does not ride up over the new brow ridge.
  • Fix shoulder_bag clipping through npc_coat/npc_dress: the bag body spans |x| 0.17–0.25 at the hip while the skirt flares to 0.225–0.26, so its inner half is inside the cloth. Move it outboard (or up onto the belt line) until the inner face clears the flare, and keep the strap tube outside the same radius.
  • Same pass for cap/beanie/hood/firefighter_helmet: they must not clip the new brow/ear geometry, and hood must still leave the face readable for hoodie avatars.
  • Rebuild the gear (build) and re-bake AO (tools/bake_ao.py), then godot --headless --path . --import.
  • Add a regression test: tools/test_blender_assets.py checks the glasses width against the head width, and src/test/tests/test_npc_character.gd checks the head/back attach nodes stay outside the body silhouette radius.
  • Re-capture the portrait (--stages=day,portrait) and the gallery shots; record the before/after in docs/screens/realism/<date>-gear/.
  • Consider a second character close-up for a hoodie/winter NPC so headgear is covered too (--portrait-type=5 already forces a hooded role for comparison).

Today all three venues share the Hollywood WorldBuilder geometry, so the Joke Shop and studio concepts are only compared on lighting (noted in tools/scene_concepts.py SHOTS). They also have no stage in the committed docs/screenshots/ gallery, only in capture_realism.gd.

  • Extract a geometry spec per venue instead of branching inline: a scenario. (or WorldBuilder) table of facade width/height, door style, window rows, awning/marquee flags, street furniture set, palette and props, defaulting to the Hollywood values so nothing regresses.
  • Joke Shop: narrow brick alley (10–12 m wide), one warm wall lantern as the key light, recessed door with a step, shuttered window, dumpster/AC clutter, no skyline ring — the alley concept has depth, not a horizon.
  • TV Studio: granite/stone facade, bulb canopy instead of the marquee, glossy black car on the curb, stanchions and barrier line at the door, no palm trees.
  • Keep navigation working: regenerate/verify the NavigationRegion3D bake per venue, update sidewalk/steps/door waypoints (Joke Shop and Studio already have sidewalk and steps_end), and confirm NPCs still reach the door (smoke + test_venue_*).
  • Split the concept mapping so each venue is judged on its own frame (joke_shop_*, studio_*) and drop the "shared geometry" caveat in tools/scene_concepts.py.
  • Add both venues to the committed gallery: two new stages in src/test/capture_screenshots.gd (12-joke-shop.png, 13-studio-arrival.png) reusing the existing joke_shop_queue / studio_arrival designs, then check_screenshots.sh and a fresh judge run.
  • Update docs/architecture.md (venue geometry), README.md (gallery) and the screenshot table when the stages land.

Forward+ desktop preset and a volumetric flashlight (v0.7.0)

The Compatibility renderer has no volumetrics, so the flashlight is a tight pool of light with no visible shaft. A second desktop build can render it properly without touching the CI/default path.

  • Write the preset as an override.cfg (Godot reads it beside the binary/project) that sets rendering/renderer/rendering_method="forward_plus", enables volumetric_fog_* and SDFGI, and keeps the Compatibility build as the default (project.godot unchanged).
  • Gate the effect in code: only give the flashlight a volumetric component when the renderer is Forward+ (RenderingServer.get_rendering_device() != null), so Web/CI builds are untouched and the existing headless tests keep passing.
  • Tune light_volumetric_fog_energy/fog_density for the LATE phase and re-check the entrance so the shaft does not wash the facade again (the reason the wide cone was cut).
  • A/B the two renderers with capture_realism.gd (same stages, two --out dirs) and record the diff + judge scores in docs/screens/realism/<date>-forward-plus/.
  • Add the preset to tools/build_releases.sh and docs/RELEASING.md as an optional "desktop HQ" artifact, and note the runtime requirement (Vulkan driver) in README.md.
  • Test: a headless run must still boot when Forward+ is unavailable (the preset must degrade to Compatibility instead of failing to start).

Realism follow-ups (deferred)

  • 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 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.