NPC characters
- Articulated rig (hips/knees, shoulders/elbows/hands) replaces rigid capsules;
the walk cycle bends knees and elbows and flees with a longer stride.
- Layered outfits (jacket/vest/coat/dress), extended accessories and hand items
(bag, umbrella, phone, camera, clipboard, cup), face details and five hair
silhouettes, all deterministic per profile seed.
- Idle behaviour layers (phone, clipboard, crossed arms, look-around), breathing
and weight shift; escalation raises hands or points, and noticed NPCs turn
toward the guard.
- Reaction symbols above the head (!!, ?!, !, ?), door-queue offsets assigned by
GameManager, three LOD tiers with hysteresis and a billboard impostor.
- smoke_npc_budget.gd: 16 avatars = 534 meshes, ~6.9 ms average (50 ms budget).
Player movement
- Separate accel/decel, step-up assist for kerbs and the entrance steps, and a
forward-axis fix: W was inverted (get_axis(forward, back) is negative).
- Head bob, landing dip and precision-walk FOV, gated by persisted head-bob and
invert-Y settings; precision chip and tick; surface-aware footsteps and a
landing cue forwarded to AudioFeedback.
- Gamepad support (sticks, deadzone, face buttons, bumpers), a control legend
that follows the active device, and named actions for the remaining keys.
- Key/button remapping in Settings, persisted as input_bindings and applied by
InputBindings (mouse and gamepad axes are never removed).
- smoke_movement.gd (windowed): climbs the steps, checks precision speed, chip,
footsteps and landing; new 11-precision-walk capture and catalogue entry.
Verification: headless 208/208, Python tooling 56/56, all 11 smokes pass,
compare 11 good / 0 bad, movement judge match. Version 0.5.0. Only optional
Future ideas remain in TODO.
Props were decoration: the guard and guests walked straight through benches,
bins, bollards and planters. They now block movement and steer guests around.
Collision
- _add_prop_model() fits a StaticBody3D from the model's mesh bounds in
holder-local space: a cylinder for bollard/bin/hydrant, a box otherwise, so
placement rotation and variant scale carry over.
- Fallback primitives go through the same fit, so a missing .glb cannot silently
remove collision.
- Each prop also publishes a NavigationObstacle3D; NpcAvatar enables agent
avoidance and moves with the safe velocity from velocity_computed. The navmesh
stays a flat walkable plane and avoidance does the steering.
Placement
- PROP_PLACEMENTS groups furniture by entrance, mid-block and curb zones, with a
static placement_problems() validator for bounds, overlap/min-spacing,
duplicates, and the door/steps/guest-lane exclusions.
- variant_for(index) gives deterministic yaw jitter, subtle scale, and optional
clutter (bag by the bin, crate by the newspaper boxes, cone by the hydrant).
Verification
- New windowed smoke_props.gd: guard walks into a bench and stops; a guest
headed beyond the bench routes around it and never enters the collider.
- Headless 182 -> 187: placement validation and its failure modes, variant
determinism/range, collider + obstacle on every placed prop, fallback collider.
- Other smokes (PLAN verbs, crowd, emergency, timeline) still pass; Python
tooling 53/53; screenshots recaptured; compare 9 good / 0 bad.
- Version 0.4.0. TODO: collision/placement section moved to DONE; prop pipeline
checks remain.
The three newest catalogue screens had AI mockups but no staged capture, so
compare and judge skipped them. capture_screenshots.gd now continues past the
night set:
- switches to The Joke Shop at 620 s (EVENING still has routine spawns), frames a
guest, and retries the wand until it alerts; if nobody carries an alerting item
it stages the documented keys false-alarm case.
- applies a formal warning (arms the body camera) then blocking, jumps to 760 s
for night lighting, and captures the HUD at L3.
- closes the open incident and opens the body-camera timeline, which now shows
the warning / body-camera / blocking rows.
Wired the refs for wand_screening, escalation_hud and body_camera_timeline, and
regenerated the escalation mockup as a third-person over-the-shoulder night shot
so the reference matches the game camera. Added Hud.clear_log() to drop
target-cycling noise from staged shots. README gallery lists the three captures.
Verification: headless 182/182, Python tooling 53/53, compare 9 good / 0 bad,
judge: wand match 0.90, timeline match 1.00, escalation review, 0 diff.
Version 0.3.3.