Compare commits

...
342 Commits
Author SHA1 Message Date
zwitschi b3acf370fc Mark the roster build done and record the release-size follow-up
Full build / Import + headless tests (push) Successful in 42s
Full build / Full desktop build + optional release (push) Successful in 4m58s
2026-11-06 13:59:28 +01:00
zwitschi 04d211b90b Release 0.9.9: full Quaternius roster, docs, changelog, version, slimmer export filters and checksums
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 40s
2026-11-06 13:59:23 +01:00
zwitschi a6ccd86f85 Swap the full 12-character roster onto the CC0 Quaternius bases
Full build / Import + headless tests (push) Successful in 40s
Full build / Full desktop build + optional release (push) Skipped
2026-11-06 13:56:30 +01:00
zwitschi 1ce173e9d1 Record the Quaternius pilot bake, measurements and face-gate decision point in the docs
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 45s
2026-11-06 13:45:05 +01:00
zwitschi 90f189a269 Add the Quaternius face/silhouette gate sheet and record the geometry measurements
Full build / Import + headless tests (push) Successful in 41s
Full build / Full desktop build + optional release (push) Skipped
2026-11-06 13:44:46 +01:00
zwitschi fb3e75aba3 Refit the backpack straps for both torsos (ADR-0018)
Full build / Import + headless tests (push) Successful in 44s
Full build / Full desktop build + optional release (push) Skipped
2026-11-06 13:43:52 +01:00
zwitschi cd285b3a39 Ship the Quaternius npc_casual pilot base: rig-agnostic pose sync, five tint slots, unwrapped UVs and wrist-strap camera
Full build / Import + headless tests (push) Successful in 41s
Full build / Full desktop build + optional release (push) Skipped
2026-11-06 13:42:37 +01:00
zwitschi 68f49253fe Record the Quaternius pilot fixes and remaining 0.9.9 work in MEMORY.md
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 42s
2026-11-06 13:19:42 +01:00
zwitschi b012c6a675 Record the Quaternius bake/pose-sync progress
Full build / Import + headless tests (push) Successful in 50s
Full build / Full desktop build + optional release (push) Skipped
2026-11-06 12:17:30 +01:00
zwitschi 2a6f29f5d0 Fix the Quaternius side swap, arm swing axis, and hand-proxy position (backward-compatible)
Full build / Import + headless tests (push) Successful in 45s
Full build / Full desktop build + optional release (push) Skipped
2026-11-06 12:17:18 +01:00
zwitschi bb54ef3eec Record the canonical-base and arm-down-bake findings precisely
Full build / Import + headless tests (push) Successful in 46s
Full build / Full desktop build + optional release (push) Skipped
2026-11-06 10:33:52 +01:00
zwitschi 11f53f66a3 Record the two skinning root causes: weld corrupts weights, bake needs head/tail plus roll
Full build / Import + headless tests (push) Successful in 48s
Full build / Full desktop build + optional release (push) Skipped
2026-11-06 10:26:56 +01:00
zwitschi 9b65a93587 Narrow the Godot skinning blocker to the importer's rotated bind_pose
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 47s
2026-11-06 10:13:32 +01:00
zwitschi 56a14747d4 Record the pose-composition fix and the remaining Godot skinning-import blocker
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 47s
2026-11-06 10:00:07 +01:00
zwitschi 8b1bf736af Correct the pose composition for a non-180° rest (rest-relative swing axis), backward-compatible with the 13-core fallback
Full build / Import + headless tests (push) Successful in 42s
Full build / Full desktop build + optional release (push) Skipped
2026-11-06 09:57:27 +01:00
zwitschi f121167e52 Record the arm-down bake fix and the remaining non-180° rest pose-composition task
Full build / Import + headless tests (push) Successful in 47s
Full build / Full desktop build + optional release (push) Skipped
2026-11-06 09:52:13 +01:00
zwitschi 140a7ada0f Plan the 0.9.9-1.0.0 roadmap and re-evaluate the NPC base
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 48s
Move the gap analysis and risks into PLAN.md, version the character track
(0.9.9 rig correction, 0.9.10 roster) and split 0.9.11-0.9.12 polish and
verification out of the old 0.10.0 milestone. Add roadmaps to 0.10.0, 0.11.0
and 1.0.0, record the Quaternius face-fidelity gate and the rest-relative
pose finding in MEMORY.md, and move the completed 0.9.7 and pose-harness
sections to DONE.md.
2026-11-06 09:40:28 +01:00
zwitschi 5508f5510f Record the Quaternius pose-sync blockers (GLB skinning + non-180° rest pose formula)
Full build / Import + headless tests (push) Successful in 48s
Full build / Full desktop build + optional release (push) Skipped
2026-11-06 09:25:45 +01:00
zwitschi 7baa2c4f54 Record the Quaternius pose-sync finding (swing axis needs per-bone calibration)
Full build / Import + headless tests (push) Successful in 50s
Full build / Full desktop build + optional release (push) Skipped
2026-11-06 08:35:29 +01:00
zwitschi 0cd12af994 Fix proxy pivot derivation to use global rest (local rest was misplacing the Quaternius joints)
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 55s
2026-11-06 08:35:14 +01:00
zwitschi 271f10ac4d Map NpcAvatar bone sync and proxy pivots to the Quaternius 62-joint names with old-rig fallback
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 2m36s
2026-11-06 07:38:39 +01:00
zwitschi e2f52fbfd1 Accept ADR-0018 option 2: adopt the Quaternius 62-joint rig at runtime
Full build / Import + headless tests (push) Successful in 48s
Full build / Full desktop build + optional release (push) Skipped
2026-11-05 21:39:38 +01:00
zwitschi f5fa321a8f Draft ADR-0018 (Stage 2 runtime rig) and mark the remaining contract-bake items blocked
Full build / Import + headless tests (push) Successful in 45s
Full build / Full desktop build + optional release (push) Skipped
2026-11-05 21:38:26 +01:00
zwitschi a2ae9e03c3 Bake the rest pose, warp to the contract, and record the failing silhouette gate
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 47s
2026-11-05 21:01:26 +01:00
zwitschi cff3937c16 Mark the 62-to-13 joint map complete
Full build / Import + headless tests (push) Successful in 46s
Full build / Full desktop build + optional release (push) Skipped
2026-11-05 20:49:05 +01:00
zwitschi 1ed9e05d9b Author the 62-to-13 joint map and align the AGENTS.md contract with the Quaternius base
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 50s
2026-11-05 20:48:55 +01:00
zwitschi 8c69f367b0 Record the owner directive: keep Quaternius at source detail during the contract bake
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 48s
2026-11-05 20:47:08 +01:00
zwitschi 2a7921bae6 Build and document the canonical quaternius_base.glb (welded, skinned, 62-joint, 1.81m)
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 44s
2026-11-05 20:43:50 +01:00
zwitschi b419923637 Decide the Quaternius outfit scope: three full GLBs first, modular builder as the role fallback
Full build / Import + headless tests (push) Successful in 48s
Full build / Full desktop build + optional release (push) Skipped
2026-11-05 20:41:23 +01:00
zwitschi c7fd4b59cc Inventory the Quaternius GLBs: meshes, 62 joints, 24 clips and the material-slot map
Full build / Import + headless tests (push) Successful in 55s
Full build / Full desktop build + optional release (push) Skipped
2026-11-05 20:40:59 +01:00
zwitschi 3fa3482608 Complete Quaternius intake record: verify SHA-256 and add the download date
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 47s
2026-11-05 20:39:39 +01:00
zwitschi 1049d8631e Compact MEMORY.md: drop the redundant session handoff, trim the AI-review entry 2026-11-05 20:38:26 +01:00
zwitschi deb74c53af Record the Quaternius pivot handoff in session memory 2026-11-05 19:44:26 +01:00
zwitschi 9968bc0a4c Rewrite NPC plans around the Quaternius base 2026-11-05 19:43:35 +01:00
zwitschi 2e1bb19e2c Correct the MPFB prototype glTF vertex count 2026-11-05 19:37:37 +01:00
zwitschi 5450dbf88a Correct the MPFB prototype glTF vertex count 2026-11-05 19:37:33 +01:00
zwitschi 79224c5acf Raise the NPC character budget to 24k and refine the prototype neck 2026-11-05 19:37:19 +01:00
zwitschi f0d4b81239 Record the AI-assisted asset review loop and MakeHuman OBJ transform gotchas in MEMORY.md
Full build / Import + headless tests (push) Successful in 45s
Full build / Full desktop build + optional release (push) Skipped
2026-11-05 19:22:43 +01:00
zwitschi 48a9795248 Record the rejected prototype shirt-shell experiment 2026-11-04 21:31:45 +01:00
zwitschi a5e62534ce Fix the prototype crotch material and loosen the shirt 2026-11-04 21:26:00 +01:00
zwitschi cd7697cba4 Polish the MPFB prototype shoes, cuffs and shirt fit 2026-11-04 19:36:52 +01:00
zwitschi d2f773c7ad Polish the prototype shoes and thigh silhouette 2026-11-04 19:31:58 +01:00
zwitschi a3c3a37270 Smooth the prototype neck and shrink the shoes 2026-11-04 19:27:51 +01:00
zwitschi 8dd4f77901 Fix the MPFB prototype neck and ankle junctions 2026-11-04 19:22:22 +01:00
zwitschi ba444152c9 Record current MPFB body prototype measurement and neck review 2026-11-04 19:16:20 +01:00
zwitschi d56f14c6dd Document MPFB full-body NPC prototype status and seams 2026-11-04 18:53:19 +01:00
zwitschi b297c4543f Add MakeHuman head hair/body prototype and 12-variant rollout plan 2026-11-04 18:08:03 +01:00
zwitschi 958d3ae0ff Add reviewed MakeHuman head prototype (vision gate rejected) 2026-11-04 17:04:20 +01:00
zwitschi d1898b3221 Overhaul the head source: weld + relax the decimated MakeHuman head into one clean manifold shell
Full build / Import + headless tests (push) Successful in 48s
Full build / Full desktop build + optional release (push) Skipped
2026-11-04 15:49:44 +01:00
zwitschi 2e1e4d7f70 Refine the MakeHuman head (weld lids/brows, add hair cap) and add the user review page
Full build / Import + headless tests (push) Successful in 40s
Full build / Full desktop build + optional release (push) Skipped
2026-11-04 15:36:55 +01:00
zwitschi 0b2f124ffe Record the MakeHuman-head build outcome in the review doc and TODO
Full build / Import + headless tests (push) Successful in 46s
Full build / Full desktop build + optional release (push) Skipped
2026-11-04 15:19:10 +01:00
zwitschi cdd2e02564 Add the MakeHuman-head character head source (head=mh) with project eyes/brows/mouth and CC0 attribution
Full build / Import + headless tests (push) Successful in 53s
Full build / Full desktop build + optional release (push) Skipped
2026-11-04 15:18:49 +01:00
zwitschi 632ec16aaa AI-driven head rework: judge picks the decimated MakeHuman head over the displacement shell
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 39s
2026-11-04 15:02:47 +01:00
zwitschi 30f240b591 Record the hand-gear verification status (open close-up done, gear context deferred to rollout)
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 49s
2026-11-04 14:49:53 +01:00
zwitschi 58d1e79a12 Add the fused hand prototype (hand_l_proto/hand_r_proto) and record the finger-articulation decision
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 42s
2026-11-04 14:49:27 +01:00
zwitschi 44dba010a7 Prepare the head-prototype owner sign-off sheet (before/after at 1.85m)
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 42s
2026-11-04 14:47:25 +01:00
zwitschi 2a53ec9aac Move _head_proto into blender_assets.py and add assemble --head-proto; verify prototype weights
Full build / Import + headless tests (push) Successful in 42s
Full build / Full desktop build + optional release (push) Skipped
2026-11-04 14:45:02 +01:00
zwitschi f0f609fe1b Add head subdivision variants and pick s48 after 1.5m/1.85m comparison
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 43s
2026-11-04 14:42:13 +01:00
zwitschi b386a21173 Finish the head prototype: forehead slope, brow step, jaw step, defined ear helix/lobe
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 47s
2026-11-04 14:39:31 +01:00
zwitschi 00bd197173 Refine the head prototype: flatten face plane, taper jaw, nose/chin relief, fix ear-displacement sign
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 42s
2026-11-04 14:36:53 +01:00
zwitschi 4f1eb1f5bf Fix the part-name test for the new head_proto part
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 46s
2026-11-04 14:23:33 +01:00
zwitschi 50edc47480 Add the connected-shell head prototype (head_proto) with sculpted sockets/nose/lips/ears
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 45s
2026-11-04 14:23:19 +01:00
zwitschi b8d8869e03 Add the local npc_parts.py head/face/hand part pipeline with tests and docs
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 41s
2026-11-04 14:17:20 +01:00
zwitschi 1b554df516 Record the tmp/npc-parts working-set layout decision
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 46s
2026-11-04 14:12:21 +01:00
zwitschi 5fdda88d46 Document the frozen npc_base fallback boundary
Full build / Import + headless tests (push) Successful in 45s
Full build / Full desktop build + optional release (push) Skipped
2026-11-04 14:11:57 +01:00
zwitschi ecd50503e7 Define the measurable face/hands acceptance criteria for the model overhaul
Full build / Import + headless tests (push) Successful in 59s
Full build / Full desktop build + optional release (push) Skipped
2026-11-04 14:11:31 +01:00
zwitschi 2b6e774580 Record the NPC baseline inventory for the model overhaul (npc_base, 12 GLBs, builders, MakeHuman)
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 40s
2026-11-04 14:10:36 +01:00
zwitschi dee939c2ee Consolidate documentation into architecture and merged guides
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 42s
2026-11-04 14:06:23 +01:00
zwitschi aec1fb7b69 Raise character limits and document optional Blender MCP
Full build / Import + headless tests (push) Successful in 41s
Full build / Full desktop build + optional release (push) Skipped
2026-11-04 13:47:16 +01:00
zwitschi 50a48d2256 Plan the Blender NPC head and hands overhaul
Full build / Import + headless tests (push) Successful in 48s
Full build / Full desktop build + optional release (push) Skipped
2026-11-04 13:36:18 +01:00
zwitschi 69f4f11633 Date the 0.9.8 release
Full build / Full desktop build + optional release (push) Successful in 13m27s
Full build / Import + headless tests (push) Successful in 1m33s
2026-11-04 12:28:38 +01:00
zwitschi d1fa25629e Bump to 0.9.8 and stage the weights-fix changelog entry
Full build / Import + headless tests (push) Successful in 8m22s
Full build / Full desktop build + optional release (push) Skipped
2026-11-04 12:26:56 +01:00
zwitschi 359bb9a8c7 Fix the hip/thigh collapse and knee pinch: rigid thigh/shin with a short knee blend
Full build / Import + headless tests (push) Successful in 8m52s
Full build / Full desktop build + optional release (push) Skipped
2026-11-04 12:26:23 +01:00
zwitschi 36576a023a Fix the wrist/hand detachment: wrist tracks the hand bone, sleeve cuff follows the hand, hand raised to meet the wrist
Full build / Import + headless tests (push) Successful in 40s
Full build / Full desktop build + optional release (push) Skipped
2026-11-04 12:11:37 +01:00
zwitschi c1ccfd6e72 Review the pose/weight evidence: wrist detachment + hip/knee flexion are the P1 fixes
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 55s
2026-11-04 12:03:42 +01:00
zwitschi 27b8f9a249 Record the MakeHuman final-body swap and its remaining retopology refinement
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 54s
2026-11-04 12:02:40 +01:00
zwitschi d5a2c911a6 Record the 0.9.7 release: QA, clean build, v0.9.7 tag
Full build / Import + headless tests (push) Successful in 41s
Full build / Full desktop build + optional release (push) Skipped
2026-11-04 12:00:44 +01:00
zwitschi 236fbf537f Date the 0.9.7 release
Full build / Import + headless tests (push) Successful in 49s
Full build / Full desktop build + optional release (push) Successful in 5m5s
2026-11-04 12:00:25 +01:00
zwitschi 588722fe7a Refresh the gallery for the 0.9.7 character pass
Full build / Import + headless tests (push) Successful in 47s
Full build / Full desktop build + optional release (push) Skipped
2026-11-04 11:59:03 +01:00
zwitschi 7f2f06bf42 Re-plan releases: 0.9.7 character patch, 0.10.0 for all 3D/map improvements
Full build / Import + headless tests (push) Successful in 1m11s
Full build / Full desktop build + optional release (push) Skipped
2026-11-04 11:53:04 +01:00
zwitschi 6db3cc0873 Plan the finished character development as the 0.10.1 patch; MakeHuman targets 0.11.0
Full build / Import + headless tests (push) Successful in 3m6s
Full build / Full desktop build + optional release (push) Skipped
2026-11-04 11:49:13 +01:00
zwitschi 8938dd918c Taper the arm-scale falloff; record the remaining deltoid retopology gap
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 2m14s
2026-11-04 11:45:12 +01:00
zwitschi 742bfd3898 Paint the five tint slots on the MakeHuman body; record the retarget vision review
Full build / Import + headless tests (push) Successful in 3m23s
Full build / Full desktop build + optional release (push) Skipped
2026-11-04 11:43:50 +01:00
zwitschi 87069a30e8 Retarget the MakeHuman body to the 13-bone contract (arm-down + weights + skinning)
Full build / Import + headless tests (push) Successful in 1m42s
Full build / Full desktop build + optional release (push) Skipped
2026-11-04 11:40:17 +01:00
zwitschi 3f5c5ce442 Prototype the MakeHuman intake: adapt the CC0 body to the character budget
Full build / Import + headless tests (push) Successful in 40s
Full build / Full desktop build + optional release (push) Skipped
2026-11-04 11:30:14 +01:00
zwitschi 28fcd96b59 Add the external-mesh adapt intake command for the MakeHuman pipeline
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 46s
2026-11-04 11:27:43 +01:00
zwitschi e984129597 Fix the pose harness: disable the avatar process so the FSM cannot revert the pose
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 46s
2026-11-04 11:24:35 +01:00
zwitschi 75dea2e7c2 Re-prioritize: Rig harness -> MakeHuman -> 3D re-eval -> 0.11.0; move character development to DONE
Full build / Import + headless tests (push) Successful in 48s
Full build / Full desktop build + optional release (push) Skipped
2026-11-04 11:15:54 +01:00
zwitschi 09d07452af Close the crowd-variety QA and release exit
Full build / Import + headless tests (push) Successful in 49s
Full build / Full desktop build + optional release (push) Skipped
2026-11-04 11:04:17 +01:00
zwitschi f5ee2b7408 Record the crowd-variety roster and the expanded budget in the docs
Full build / Import + headless tests (push) Successful in 55s
Full build / Full desktop build + optional release (push) Skipped
2026-11-04 11:03:55 +01:00
zwitschi 5980d329e8 Close the crowd-variant fit, reference and baseline items
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 47s
2026-11-04 11:03:25 +01:00
zwitschi 6052ea391b Wire the crowd variants into per-role pools and verify every seed resolves
Full build / Import + headless tests (push) Successful in 55s
Full build / Full desktop build + optional release (push) Skipped
2026-11-04 11:03:01 +01:00
zwitschi 4e8665e25b Add the four crowd-variety characters and extend the baseline to twelve
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 42s
2026-11-04 10:57:58 +01:00
zwitschi b945eb6e8f Fetch the licensed crowd-variety reference photos
Full build / Import + headless tests (push) Successful in 40s
Full build / Full desktop build + optional release (push) Skipped
2026-11-04 10:47:44 +01:00
zwitschi 03c13c716a Record the qa-review sign-off: all eight characters ship with notes
Full build / Import + headless tests (push) Successful in 40s
Full build / Full desktop build + optional release (push) Skipped
2026-11-04 10:44:29 +01:00
zwitschi 0a9c78cb30 Give the foliage two green tones and fix the textured_solid import bug
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 42s
2026-11-04 10:40:27 +01:00
zwitschi abe5c3f933 Update development-status: the face pass now covers all eight variants
Full build / Import + headless tests (push) Successful in 47s
Full build / Full desktop build + optional release (push) Skipped
2026-11-04 10:33:20 +01:00
zwitschi 140ab42536 Apply the realistic face to the remaining seven variants and refresh the baseline
Full build / Import + headless tests (push) Successful in 43s
Full build / Full desktop build + optional release (push) Skipped
2026-11-04 10:33:11 +01:00
zwitschi 8bdfd0176e Refresh the NPC baseline sheet and record the face prototype in development status
Full build / Import + headless tests (push) Successful in 45s
Full build / Full desktop build + optional release (push) Skipped
2026-11-04 10:26:14 +01:00
zwitschi 4e23cc3ad5 Prototype a more realistic face on npc_casual (higher subdivision, brow ridge, both lids, fuller lip)
Full build / Import + headless tests (push) Successful in 42s
Full build / Full desktop build + optional release (push) Skipped
2026-11-04 10:24:21 +01:00
zwitschi 8d32a8cac0 Record the map rebuild completion and the fresh NPC review against the new maps
Full build / Import + headless tests (push) Successful in 46s
Full build / Full desktop build + optional release (push) Skipped
2026-11-04 10:03:14 +01:00
zwitschi 2445ddab34 Close the map-track J/L workstreams: procedural approach supersedes the facade kit
Full build / Import + headless tests (push) Successful in 44s
Full build / Full desktop build + optional release (push) Skipped
2026-11-04 10:00:36 +01:00
zwitschi 8cacd510bf Record the rounded-corner simplification and close the local-map QA/exit
Full build / Import + headless tests (push) Successful in 47s
Full build / Full desktop build + optional release (push) Skipped
2026-11-04 09:58:47 +01:00
zwitschi bf383aa0fa Note the Joke Shop facade-height fix in the review doc
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 48s
2026-11-04 09:48:47 +01:00
zwitschi 4bbc576b7f Lower the Joke Shop facade to 6 m so the canopy caps the low hall
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 44s
2026-11-04 09:48:20 +01:00
zwitschi 542b1264da Close the Comedy Store map recreation and document describe_image in asset-tooling
Full build / Import + headless tests (push) Successful in 45s
Full build / Full desktop build + optional release (push) Skipped
2026-11-04 09:42:31 +01:00
zwitschi 56f4833c8e Record the local-map data, licensing and scope decisions (section H)
Full build / Import + headless tests (push) Successful in 47s
Full build / Full desktop build + optional release (push) Skipped
2026-11-04 09:41:46 +01:00
zwitschi 1b31dfdbe4 Add the Ramada Plaza hotel tower mass behind the Joke Shop west neighbour
Full build / Import + headless tests (push) Successful in 45s
Full build / Full desktop build + optional release (push) Skipped
2026-11-04 09:41:11 +01:00
zwitschi 5158efc467 Retire the unused beanie gear and sequence asset fixes after the map rebuild
Full build / Import + headless tests (push) Successful in 43s
Full build / Full desktop build + optional release (push) Skipped
2026-11-04 09:36:10 +01:00
zwitschi ac0cf35cfb Fix the stale Joke Shop map count in the review doc
Full build / Import + headless tests (push) Successful in 44s
Full build / Full desktop build + optional release (push) Skipped
2026-11-04 09:30:44 +01:00
zwitschi 6655edb5c6 Sync development-status with the 3D re-evaluation facade/prop work and current counts
Full build / Import + headless tests (push) Successful in 52s
Full build / Full desktop build + optional release (push) Skipped
2026-11-04 09:22:27 +01:00
zwitschi 60f389c16b Force-spawn the requested portrait role and close the hooded close-up
Full build / Import + headless tests (push) Successful in 46s
Full build / Full desktop build + optional release (push) Skipped
2026-11-04 09:09:44 +01:00
zwitschi 3084145031 Rank the Comedy Store shape-language gaps (top-five list)
Full build / Import + headless tests (push) Successful in 50s
Full build / Full desktop build + optional release (push) Skipped
2026-11-04 09:04:30 +01:00
zwitschi 34bca89885 Record the set-dressing vision review findings
Full build / Import + headless tests (push) Successful in 46s
Full build / Full desktop build + optional release (push) Skipped
2026-11-03 22:00:49 +01:00
zwitschi b53e8a67f9 Polish the bollard base and newspaper-box door (recessed slot + seam)
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 41s
2026-11-03 21:59:06 +01:00
zwitschi cdfd57fb65 Record the prop-gallery vision review findings
Full build / Import + headless tests (push) Successful in 43s
Full build / Full desktop build + optional release (push) Skipped
2026-11-03 21:56:50 +01:00
zwitschi 5bab6754c0 Rebuild the fire hydrant silhouette (flange, bonnet, outlets)
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 53s
2026-11-03 21:56:28 +01:00
zwitschi 7dd8251a0c Extract and reconcile the Comedy Store proportions via the vision tool
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 41s
2026-11-03 21:50:20 +01:00
zwitschi 8e113a4110 Tighten the gap analysis register
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 42s
2026-11-03 21:02:01 +01:00
zwitschi 32c9c45605 Document the lighting vision review and add describe_image to the tools inventory
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 46s
2026-11-03 21:00:54 +01:00
zwitschi e4065c2068 Tie back the Joke Shop curtain bays and add the describe_image vision tool
Full build / Import + headless tests (push) Successful in 39s
Full build / Full desktop build + optional release (push) Skipped
2026-11-03 20:58:05 +01:00
zwitschi e7d733bc93 Record the gear fit readings and caveats in the review doc
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 42s
2026-11-03 20:25:39 +01:00
zwitschi 93da916f90 Gate venue light falloff with a test (physical attenuation = 1.0)
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 39s
2026-11-03 20:14:23 +01:00
zwitschi e3ec4a356a Sync the stale Python test count (143 -> 160) in TODO
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 41s
2026-11-03 20:13:10 +01:00
zwitschi 55339f23c1 Document the texel/coverage/collider gates and correct the face limitation note
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 48s
2026-11-03 20:12:43 +01:00
zwitschi a51dae2c33 White the Joke Shop canopy signature band to match the reference
Full build / Import + headless tests (push) Successful in 45s
Full build / Full desktop build + optional release (push) Skipped
2026-11-03 20:07:01 +01:00
zwitschi 6824dd76a1 Close stale TODO items: camera height and local-frame provenance
Full build / Import + headless tests (push) Successful in 41s
Full build / Full desktop build + optional release (push) Skipped
2026-11-03 20:04:22 +01:00
zwitschi fde4aa4d0a Record the two-builder distinction in MEMORY
Full build / Import + headless tests (push) Successful in 43s
Full build / Full desktop build + optional release (push) Skipped
2026-11-03 20:03:15 +01:00
zwitschi ebb36cf0cb Correct face/head review: library characters already carry the 0.9.4 sculpt; close hands/grip review
Full build / Import + headless tests (push) Successful in 42s
Full build / Full desktop build + optional release (push) Skipped
2026-11-03 20:03:06 +01:00
zwitschi 724e8b183f Add tracked AI skills for Blender assets and release QA
Full build / Import + headless tests (push) Successful in 40s
Full build / Full desktop build + optional release (push) Skipped
2026-11-03 19:53:32 +01:00
zwitschi e4e1566e55 Organize tools and move Python tests into tools/tests
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 38s
2026-11-03 19:45:00 +01:00
zwitschi 0aacee6518 Compact MEMORY.md: drop CHANGELOG/DONE duplication
Full build / Import + headless tests (push) Successful in 44s
Full build / Full desktop build + optional release (push) Skipped
2026-11-03 19:40:50 +01:00
zwitschi 215b843b67 Write the face/head concrete edits and close the review
Full build / Import + headless tests (push) Successful in 46s
Full build / Full desktop build + optional release (push) Skipped
2026-11-03 19:27:31 +01:00
zwitschi 53d9dc3f78 Record the cloth/hair decision: simulation stays out of scope
Full build / Import + headless tests (push) Successful in 42s
Full build / Full desktop build + optional release (push) Skipped
2026-11-03 19:26:50 +01:00
zwitschi 98f2f95f07 Close the UV/texel decision: accept the neutral runtime-tinted maps
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 54s
2026-11-03 19:26:30 +01:00
zwitschi a677a95d13 Narrow the pose-harness root cause: skinned mesh ignores its Rig parent
Full build / Import + headless tests (push) Successful in 40s
Full build / Full desktop build + optional release (push) Skipped
2026-11-03 19:26:07 +01:00
zwitschi 1afd97c72d Complete the Comedy Store block reference collection (hotel + hillside)
Full build / Import + headless tests (push) Successful in 47s
Full build / Full desktop build + optional release (push) Skipped
2026-11-03 19:18:43 +01:00
zwitschi 6ca8bcf034 Decouple AGENTS.md from specific tracks: keep only process, action and tracking guidance
Full build / Import + headless tests (push) Successful in 46s
Full build / Full desktop build + optional release (push) Skipped
2026-11-03 19:16:57 +01:00
zwitschi 13eb4e0c87 Make the merged 3D + local map track coherent: rename, combined scope/exit, re-mark collection state
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 39s
2026-11-03 19:13:21 +01:00
zwitschi 8fac1b47cf Merge local map tasks into the 3D review track
Full build / Import + headless tests (push) Successful in 40s
Full build / Full desktop build + optional release (push) Skipped
2026-11-03 18:41:21 +01:00
zwitschi b79e30e9df Render the TV Studio as the Masonic Temple facade (Jimmy Kimmel starting point)
Full build / Import + headless tests (push) Successful in 38s
Full build / Full desktop build + optional release (push) Skipped
2026-11-03 18:35:15 +01:00
zwitschi 1e761e5a76 Anchor Jimmy Kimmel Live entrance concepts and mark the building as the starting point
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 45s
2026-11-03 18:28:31 +01:00
zwitschi 3eb2ae5e3c Collect Jimmy Kimmel Live and Hollywood block references; skip AVIF frames in the contact sheet
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 41s
2026-11-03 18:24:35 +01:00
zwitschi 888897cac9 Add three multi-model Comedy Store scenes and plan the map recreation
Full build / Import + headless tests (push) Successful in 45s
Full build / Full desktop build + optional release (push) Skipped
2026-11-03 18:04:09 +01:00
zwitschi 988d431da8 Generate multi-model anchored concepts, drop old Comedy Store refs, and trim the concept gallery
Full build / Import + headless tests (push) Successful in 41s
Full build / Full desktop build + optional release (push) Skipped
2026-11-03 17:49:48 +01:00
zwitschi 87e1c9e7a5 Harden the DDG collector with token-bucket pacing and prefer the ddgs package
Full build / Import + headless tests (push) Successful in 40s
Full build / Full desktop build + optional release (push) Skipped
2026-11-03 17:32:39 +01:00
zwitschi 480a1ba05f Document the local-only reference collector
Full build / Import + headless tests (push) Successful in 41s
Full build / Full desktop build + optional release (push) Skipped
2026-11-03 17:12:32 +01:00
zwitschi 43c17ce3c0 Add the local-only DuckDuckGo reference collector
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 54s
2026-11-03 17:12:18 +01:00
zwitschi 03f4d4bc49 Prioritize local reference collection and record the licence-free local-only override
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 46s
2026-11-03 17:04:19 +01:00
zwitschi 15f9117517 Mark the completed maintenance tasks
Full build / Import + headless tests (push) Successful in 45s
Full build / Full desktop build + optional release (push) Skipped
2026-11-03 16:35:33 +01:00
zwitschi 78267918bf Trim MEMORY.md: drop superseded handoffs and release anecdotes, fix stale counts and the sign-in contradiction
Full build / Import + headless tests (push) Successful in 48s
Full build / Full desktop build + optional release (push) Skipped
2026-11-03 16:35:19 +01:00
zwitschi ea3860a60c Defer Gaussian splatting and re-plan maintenance
Full build / Import + headless tests (push) Successful in 46s
Full build / Full desktop build + optional release (push) Skipped
2026-11-03 16:31:42 +01:00
zwitschi b721f189c5 Record the stucco decision and the recitation-filter workaround
Full build / Import + headless tests (push) Successful in 47s
Full build / Full desktop build + optional release (push) Skipped
2026-11-03 16:22:28 +01:00
zwitschi 634b1f75a3 Give the Joke Shop a dark stucco wall and a photo-anchored concept
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 48s
2026-11-03 16:22:20 +01:00
zwitschi 36583921cf Plan the Joke Shop building-appearance pass
Full build / Import + headless tests (push) Successful in 40s
Full build / Full desktop build + optional release (push) Skipped
2026-11-03 16:17:57 +01:00
zwitschi 3866b0ae01 Record the completed facade-realism pass
Full build / Import + headless tests (push) Successful in 47s
Full build / Full desktop build + optional release (push) Skipped
2026-11-03 16:15:46 +01:00
zwitschi 8c2761427f Verify the marquee emissive balance and close the facade-realism pass
Full build / Import + headless tests (push) Successful in 43s
Full build / Full desktop build + optional release (push) Skipped
2026-11-03 16:15:38 +01:00
zwitschi 2b07913481 Update the facade-realism progress note
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 42s
2026-11-03 15:55:10 +01:00
zwitschi 768dd94bfc Balance the event-banner night emissive
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 45s
2026-11-03 15:54:58 +01:00
zwitschi f516d3e796 Record the Godot import-cache gotcha and ashlar decision
Full build / Import + headless tests (push) Successful in 41s
Full build / Full desktop build + optional release (push) Skipped
2026-11-03 15:40:43 +01:00
zwitschi f95a685934 Use the photo-anchored ashlar limestone on the masonic facade
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 49s
2026-11-03 15:40:25 +01:00
zwitschi 05cb6a43cb Link the three-up boards from the venue map docs
Full build / Import + headless tests (push) Successful in 39s
Full build / Full desktop build + optional release (push) Skipped
2026-11-03 15:11:09 +01:00
zwitschi 343b3348c2 Add three-up evidence boards for El Capitan and Joke Shop
Full build / Import + headless tests (push) Successful in 45s
Full build / Full desktop build + optional release (push) Skipped
2026-11-03 15:09:18 +01:00
zwitschi ad91e71eeb Add the photo-anchored variant pass with night and overcast facade frames
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 40s
2026-11-03 15:04:20 +01:00
zwitschi 6e04c59589 Record the reference-anchored generation recipe in memory
Full build / Import + headless tests (push) Successful in 42s
Full build / Full desktop build + optional release (push) Skipped
2026-11-03 15:00:00 +01:00
zwitschi e21ff30783 Add reference-anchored concept generation
Full build / Import + headless tests (push) Successful in 49s
Full build / Full desktop build + optional release (push) Skipped
2026-11-03 14:59:53 +01:00
zwitschi 5b306b1c52 Add the Commons reference-board research tool
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 40s
2026-11-03 14:51:31 +01:00
zwitschi f09a5e7937 Plan recent-photo tooling and reference-anchored generation
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 41s
2026-11-03 14:36:13 +01:00
zwitschi 383f601bc9 Extend the Hollywood board with terrazzo, neighbour and night context
Full build / Import + headless tests (push) Successful in 40s
Full build / Full desktop build + optional release (push) Skipped
2026-11-03 14:04:51 +01:00
zwitschi c46db76d85 Record that the TV Studio venue shares the Hollywood block
Full build / Import + headless tests (push) Successful in 43s
Full build / Full desktop build + optional release (push) Skipped
2026-11-03 13:49:26 +01:00
zwitschi 1a5f2863b0 Add the licensed Joke Shop reference board
Full build / Import + headless tests (push) Successful in 45s
Full build / Full desktop build + optional release (push) Skipped
2026-11-03 13:41:25 +01:00
zwitschi a6fd77068a Add the first licensed Hollywood reference board
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 40s
2026-11-03 13:28:05 +01:00
zwitschi 4ed73fcc7b Add the real-location reference folder and provenance sidecar
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 43s
2026-11-03 12:42:13 +01:00
zwitschi c0ddce79e8 Record the imagery evidence model
Full build / Import + headless tests (push) Successful in 44s
Full build / Full desktop build + optional release (push) Skipped
2026-11-03 12:22:11 +01:00
zwitschi 0c7c9a2b23 Plan reference imagery, generated boards and per-section captures
Full build / Import + headless tests (push) Successful in 40s
Full build / Full desktop build + optional release (push) Skipped
2026-11-03 12:21:57 +01:00
zwitschi b94b87d096 Refresh the capture gallery and build captioned visual docs
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 41s
2026-11-03 12:08:33 +01:00
zwitschi 5dec59355a Gate library prop collision coverage across venues
Full build / Import + headless tests (push) Successful in 37s
Full build / Full desktop build + optional release (push) Skipped
2026-11-03 11:58:00 +01:00
zwitschi fe3ba3054e Gate texel density and review scorecard coverage
Full build / Import + headless tests (push) Successful in 43s
Full build / Full desktop build + optional release (push) Skipped
2026-11-03 11:52:19 +01:00
zwitschi 88a0793bba Record the verified pose-capture recipe and the harness defect
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 41s
2026-11-03 11:44:55 +01:00
zwitschi 1d4f718376 Narrow the pose-capture discrepancy to the harness and lock bone posing
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 45s
2026-11-03 11:24:44 +01:00
zwitschi 7a5b902797 Add a pose review harness and record the blocked pose capture
Full build / Import + headless tests (push) Successful in 43s
Full build / Full desktop build + optional release (push) Skipped
2026-11-03 10:59:23 +01:00
zwitschi 2d67e14e52 Measure the 3D library and open the model review scorecard
Full build / Import + headless tests (push) Successful in 43s
Full build / Full desktop build + optional release (push) Skipped
2026-11-03 10:39:45 +01:00
zwitschi 2443343f2b adjusted agents instructions, made more precise and incorporate blender skills 2026-11-03 10:38:39 +01:00
zwitschi 3e41cda591 Re-plan the Blender tracks around the local skills and a 3D model review
Full build / Import + headless tests (push) Successful in 43s
Full build / Full desktop build + optional release (push) Skipped
2026-11-03 10:19:46 +01:00
zwitschi 84bc4137cb Add local pi agent session data to .gitignore 2026-11-03 10:13:34 +01:00
zwitschi 5dc3ef0f4c Add a Blender GLB intake inspection command
Full build / Import + headless tests (push) Successful in 44s
Full build / Full desktop build + optional release (push) Skipped
2026-11-03 10:08:45 +01:00
zwitschi 6f3facff43 Install the Blender skills pack locally and keep it out of git
Full build / Import + headless tests (push) Successful in 38s
Full build / Full desktop build + optional release (push) Skipped
2026-11-03 10:02:34 +01:00
zwitschi 51f537720f Reorder TODO and docs around character and map priorities
Full build / Import + headless tests (push) Successful in 37s
Full build / Full desktop build + optional release (push) Skipped
2026-11-03 09:17:49 +01:00
zwitschi 08e9044593 Add commit, build and version discipline to agent workflow 2026-11-03 09:17:49 +01:00
zwitschi ad14410337 Expand the photo-driven Gaussian splatting map plan
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 43s
2026-11-03 09:07:07 +01:00
zwitschi 876fb59882 Add unversioned local map development section 2026-11-03 09:01:46 +01:00
zwitschi 979c6ad789 Make character development an unversioned TODO section 2026-11-03 08:24:55 +01:00
zwitschi 1921bfae91 Document the character development toolchain in the architecture
Full build / Import + headless tests (push) Successful in 39s
Full build / Full desktop build + optional release (push) Skipped
2026-11-03 08:22:09 +01:00
zwitschi 78485259b7 Detail deferred MakeHuman local pipeline boundary 2026-11-03 08:00:47 +01:00
zwitschi fef3af44c0 Record NPC sourcing decision and crowd prototypes 2026-11-03 07:59:58 +01:00
zwitschi bfe3c5a701 Research NPC model sources and plan 0.11.0 expansion 2026-11-03 07:46:47 +01:00
zwitschi 46f1e41874 Define release-candidate balance acceptance targets
Full build / Import + headless tests (push) Successful in 43s
Full build / Full desktop build + optional release (push) Skipped
2026-11-03 07:40:45 +01:00
zwitschi f48d87c84f Record the 0.10.0-rc.1 candidate build
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 46s
2026-11-03 07:36:03 +01:00
zwitschi a9658ecd81 Prepare the 0.10.0 release candidate 2026-11-03 07:33:20 +01:00
zwitschi b8507df346 Harden release publishing and document release blockers
Full build / Import + headless tests (push) Successful in 45s
Full build / Full desktop build + optional release (push) Skipped
2026-11-03 07:32:21 +01:00
zwitschi 60bf9a8ef6 Add save migration fixtures and failure-mode coverage 2026-11-03 07:29:42 +01:00
zwitschi b51bdc8efe Open the 0.10.0 release-candidate milestone
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 39s
2026-11-03 06:20:36 +01:00
zwitschi a7b2852253 Record the v0.9.6 release build
Full build / Import + headless tests (push) Successful in 39s
Full build / Full desktop build + optional release (push) Skipped
2026-11-03 06:19:38 +01:00
zwitschi 4bb2896819 Verify the 0.9.6 integration checkpoint
Full build / Import + headless tests (push) Successful in 53s
Full build / Full desktop build + optional release (push) Successful in 4m27s
2026-11-03 06:13:07 +01:00
zwitschi f5b8ef2e70 Prepare the 0.9.6 integration checkpoint 2026-11-03 06:11:17 +01:00
zwitschi 0044f5f065 Record the v0.9.5 release build
Full build / Import + headless tests (push) Successful in 43s
Full build / Full desktop build + optional release (push) Skipped
2026-11-02 21:12:00 +01:00
zwitschi 4bc6390e9f Release 0.9.5 texture and material refinement
Full build / Import + headless tests (push) Successful in 46s
Full build / Full desktop build + optional release (push) Successful in 4m54s
2026-11-02 21:04:48 +01:00
zwitschi fb3da52438 Refine environment surfaces and skyline haze
Full build / Import + headless tests (push) Successful in 42s
Full build / Full desktop build + optional release (push) Skipped
2026-11-02 20:38:58 +01:00
zwitschi d7220c1a0a Refine NPC fabric UVs and remove baked AO blotches
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 37s
2026-11-02 20:28:25 +01:00
zwitschi 31574b8d82 Raise NPC texture maps to 256
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 43s
2026-11-02 20:16:30 +01:00
zwitschi b60f67548d Record the v0.9.4 release build
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 43s
2026-11-02 19:58:40 +01:00
zwitschi a57b86cd48 Release 0.9.4 NPC visual optimization
Full build / Import + headless tests (push) Successful in 47s
Full build / Full desktop build + optional release (push) Successful in 5m28s
2026-11-02 19:51:36 +01:00
zwitschi dfe5056303 Round the NPC shoes and responder boots
Full build / Import + headless tests (push) Successful in 42s
Full build / Full desktop build + optional release (push) Skipped
2026-11-02 19:38:40 +01:00
zwitschi 58cf12fd1d Move hand gear forward into the palm
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 40s
2026-11-02 19:33:42 +01:00
zwitschi 7150bd7673 Verify NPC headgear clearance after the face pass
Full build / Import + headless tests (push) Successful in 34s
Full build / Full desktop build + optional release (push) Skipped
2026-11-02 19:30:19 +01:00
zwitschi 12e70357c5 Refine the NPC nose, mouth and ears
Full build / Import + headless tests (push) Successful in 35s
Full build / Full desktop build + optional release (push) Skipped
2026-11-02 19:29:19 +01:00
zwitschi 7dc3d3c873 Raise the character mesh budget to 8000
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 33s
2026-11-02 19:25:41 +01:00
zwitschi cd5e0e0ff7 Record the NPC vertex-cap constraint
Full build / Import + headless tests (push) Successful in 36s
Full build / Full desktop build + optional release (push) Skipped
2026-11-02 19:22:34 +01:00
zwitschi 8ce62e7556 Group the NPC visual changes under Changed
Full build / Import + headless tests (push) Successful in 35s
Full build / Full desktop build + optional release (push) Skipped
2026-11-02 19:15:15 +01:00
zwitschi 24c939d388 Rebuild the NPC hands and add a hand capture
Full build / Import + headless tests (push) Successful in 50s
Full build / Full desktop build + optional release (push) Skipped
2026-11-02 19:14:55 +01:00
zwitschi 48082c3dfa Taper the NPC torso into the hips
Full build / Import + headless tests (push) Successful in 41s
Full build / Full desktop build + optional release (push) Skipped
2026-11-02 19:11:28 +01:00
zwitschi 03c355e7c1 Recess NPC eyes and sculpt the jaw and cheeks
Full build / Import + headless tests (push) Successful in 38s
Full build / Full desktop build + optional release (push) Skipped
2026-11-02 19:08:26 +01:00
zwitschi 15ab8c686d Smooth the NPC neck and shoulder transition
Full build / Import + headless tests (push) Successful in 39s
Full build / Full desktop build + optional release (push) Skipped
2026-11-02 19:03:38 +01:00
zwitschi ab9c67d266 Audit NPC body proportions against a shared guide
Full build / Import + headless tests (push) Successful in 39s
Full build / Full desktop build + optional release (push) Skipped
Measure all eight exported characters and record the stylized proportion bands. All variants pass; no skeleton or mesh rescale was needed.
2026-11-02 18:54:52 +01:00
zwitschi 7c1a4bfd69 Refit the tourist backpack and photo prop
Full build / Import + headless tests (push) Successful in 38s
Full build / Full desktop build + optional release (push) Skipped
Hide the tourist photo-pose bag outside camera poses, flatten the backpack straps onto the chest, rebuild the gear GLB/AO and publish the before/after NPC sheet.
2026-11-02 18:39:03 +01:00
zwitschi e7ee177c31 Establish the 0.9.4 NPC visual baseline
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 38s
Add a neutral 48-frame character contact sheet, acceptance criteria and ranked baseline gaps, plus repeatable sheet/comparison tooling. No character GLB or runtime mesh changes.
2026-11-02 18:13:57 +01:00
zwitschi c1cd4898e8 Close the 0.9.3 UI polish milestone
Full build / Import + headless tests (push) Successful in 36s
Full build / Full desktop build + optional release (push) Skipped
Add deterministic captures 14-21 for the remaining screen-design states, fix the panel/button layout issues they exposed, and record 21/21 compare and judge results. Bump the source to 0.9.3 and move the completed milestone to DONE.md.
2026-11-02 17:57:40 +01:00
Gig Line Dev e805a91ad3 Add end-to-end interaction flow smoke
Full build / Import + headless tests (push) Successful in 39s
Full build / Full desktop build + optional release (push) Skipped
- Boot the real scene and verify inspection allow/deny, normal vs emergency radio, Help filtering, wand allow/deny and review return-to-menu.
- Document the flow coverage and smoke command; mark the 0.9.3 end-to-end audit complete.
2026-11-02 16:36:01 +01:00
Gig Line Dev 7315166361 Guard destructive settings and radio actions
Full build / Import + headless tests (push) Successful in 36s
Full build / Full desktop build + optional release (push) Skipped
- Route reset campaign and tutorial replay through one reusable confirmation dialog; repeated presses cannot stack or emit twice.
- Keep emergency hold-to-send single-shot and cover the post-submit release.
- Add destructive-action regression checks, strings and documentation.
2026-11-02 16:29:26 +01:00
Gig Line Dev f6aa26e6ca Harden UI layout for font scale and long strings
Full build / Import + headless tests (push) Successful in 36s
Full build / Full desktop build + optional release (push) Skipped
- Measure and cap the HUD target chip after each font-scale change; clip HUD top labels.
- Ellipsize long action-button labels so panels cannot grow past the viewport.
- Add accessibility/button layout assertions and refresh the gallery captures.
- Record the font/layout pass in TODO, docs, changelog and memory.
2026-11-02 16:23:46 +01:00
Gig Line Dev 26e6dd6413 Close every top modal through one Esc and right-click path
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 37s
- Add Help, Settings, Pause and review to the top-modal close chain so right-click and Esc behave consistently.
- Restore the venue menu after menu Settings and prevent Help from opening Pause behind itself.
- Reopen pause after in-shift Settings apply and recapture the mouse/unfreeze state on close.
- Extend the session smoke for menu Settings, right-click Help and guard unfreeze.
2026-11-02 16:10:50 +01:00
Gig Line Dev 8f65751975 Add wrapping keyboard and gamepad focus rings
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 36s
- Link every modal's enabled controls into a wrapping UiFocus ring and give each screen a default focus target.
- Add gamepad A/B bindings for ui_accept/ui_cancel; include Start menu footer actions and Continue in its focus ring.
- Skip hidden/disabled controls, close focus traps via per-modal cancel behavior, and return review to the menu on cancel.
- Record the focus audit and add regression coverage.
2026-11-02 16:05:53 +01:00
Gig Line Dev 9692f262f1 Unify action-button states across the UI
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 39s
- Add UiStyles with explicit normal, hover, pressed, focus and disabled styles and apply it to every action button.
- Disable timeline Previous/Next at the first/last event and keep Close always available.
- Style settings reset-dialog buttons and cover the button-state audit in docs/ui-copy.md.
- Add shared-state and timeline-boundary regression tests.
2026-11-02 15:04:38 +01:00
Gig Line Dev 98c31fe44c Audit and fix NPC, door-staff and UI dialogue
Full build / Import + headless tests (push) Successful in 40s
Full build / Full desktop build + optional release (push) Skipped
- Route the Reason verb through authored reason contexts and give every shared archetype an in-character answer.
- Add Hollywood wristband and TV Studio ticket/credential door-staff lines.
- Clarify radio cancellation, Ask terminology, start hints and campaign-reset copy.
- Record the dialogue audit and length findings in docs/ui-copy.md; add regression tests.
2026-11-02 14:44:01 +01:00
Gig Line Dev daf0926d91 Bump source to 0.9.2 and renumber the 0.x roadmap
Full build / Import + headless tests (push) Successful in 36s
Full build / Full desktop build + optional release (push) Skipped
- Set project.godot to 0.9.2 and add the matching changelog entry.
- Renumber the postponed work to 0.9.3 UI, 0.9.4 NPC, 0.9.5 textures and 0.9.6 integration, with 0.10.0 as the next minor release candidate.
- Remove the 1.0.0 milestone and post-1.0 planning; plan only 0.x patch/minor increments.
- Synchronize README, PLAN, architecture, status, memory and UI-copy version references.
2026-11-02 14:39:50 +01:00
Gig Line Dev f71a36faa1 Pass the pre-build NPC review gate
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 34s
- Add a review harness that stages all eight library characters at portrait, conversation and crowd distance on both maps in day and night.
- Fix the final-context lanyard badge and firefighter helmet fit with runtime attach offsets; the asset-space gear contract is unchanged.
- Record the gate sign-off, refresh the gallery, and move the completed review to DONE.
2026-11-02 14:32:10 +01:00
Gig Line Dev 37f925c7ad Rebuild the Joke Shop as the Sunset Strip block
Full build / Import + headless tests (push) Successful in 37s
Full build / Full desktop build + optional release (push) Skipped
- Replace the alley with the 27 m Comedy Store-inspired hall, signature canopy, circular blade sign, red curtain bays, west entrance, low-rise neighbours, dry hillside and opposite frontage.
- Add day/night/across-street concept frames and real-site mapping notes.
- Expose the Joke Shop day stage in the realism captures and refresh the gallery shots.
- Render multiline HUD/wand strings correctly and list carried items in the wand panel.
- Add the Joke Shop layout/budget tests and update docs, roadmap and changelog.
2026-11-02 14:10:07 +01:00
zwitschi 74dc1fdc1d Map 1: rebuild Hollywood as the El Capitan landmark
Full build / Import + headless tests (push) Successful in 37s
Full build / Full desktop build + optional release (push) Skipped
Replace the generic boulevard facade with a stylized 6840 Hollywood Blvd block: six Ionic columns, eight stone steps, Masonic frieze/medallions, event banners, side doors, El Capitan Theatre and retail neighbours, Ovation Hollywood arcade, Walk of Fame and four-lane street markings.

Add the Day and Night Hollywood venue-menu rows. Night uses a phase-time offset so a full-length shift stays in LATE while the clock starts at zero; late routine traffic keeps the street populated and the offset round-trips through checkpoint restore.

Retune local-light falloff to linear attenuation, add a cool north sky fill, and use the smooth limestone facade texture. Refresh the staged gallery and map references; add geometry-budget, menu, night-offset and late-traffic tests.
2026-11-02 12:34:48 +01:00
zwitschi 3f335481d6 Prioritize map optimization and gate builds on an NPC revisit
Full build / Import + headless tests (push) Successful in 37s
Full build / Full desktop build + optional release (push) Skipped
Move the promoted 0.9.5 map work to the active milestone, postpone UI/NPC
detail/texture/integration/release-candidate work, and add a detailed pre-build
NPC gate that reviews portraits, gear fit, crowd distance and final lighting
before any build or tag.
2026-11-02 11:27:50 +01:00
zwitschi af923b1483 Route UI labels through the string table
Full build / Import + headless tests (push) Successful in 38s
Full build / Full desktop build + optional release (push) Skipped
Move start menu, settings, pause, Help, HUD, radio, shift review and campaign
labels/templates into content/strings.en.json, including placeholder-validated
dynamic status text. No player-facing hardcoded labels remain outside dynamic
data/debug output. Headless 250/250, docs check OK.
2026-11-02 11:25:15 +01:00
zwitschi 3a74cedee0 Refresh gallery and record the screen-design judge
Full build / Import + headless tests (push) Successful in 37s
Full build / Full desktop build + optional release (push) Skipped
Regenerate the committed screenshot gallery on the current build, run compare
(13 good/0 bad) and the automatic-model judge (13/13 match, 0 diff), and record
the result. Update the 0.9.2 visual checklist items.
2026-11-02 11:18:36 +01:00
zwitschi 844e39246a Standardize button labels and document UI states
Full build / Import + headless tests (push) Successful in 38s
Full build / Full desktop build + optional release (push) Skipped
Finish the button-label audit with a surface-by-surface table, clarify Quit
game vs Quit to menu, rename Apply to Apply settings, and use string-table
keys for the new labels. Extend the smoke checklist with UI copy/button checks.
Headless 250/250, docs check OK.
2026-11-02 11:12:29 +01:00
zwitschi 7c48183410 Start the UI copy and button consistency pass
Full build / Import + headless tests (push) Successful in 39s
Full build / Full desktop build + optional release (push) Skipped
Add the screen/copy/button inventory and canonical terminology, standardize
inspection/wand admit-refuse hints, name the review action Return to menu, and
move radio action/hold/status labels into the string table. Headless 250/250,
Python 97/97, docs check OK.
2026-11-02 11:10:39 +01:00
zwitschi 64590fe797 Plan the 0.10.0 minor and thorough NPC visual pass
Full build / Import + headless tests (push) Successful in 33s
Full build / Full desktop build + optional release (push) Skipped
Renumber the pre-release patches after shipped 0.9.1, promote the next release
candidate to 0.10.0, and expand NPC work into reference/acceptance, proportions,
face/hair, hands/clothing, gear fit, pose/performance and visual verification.
Sync the README status and remaining-gap references.
2026-11-02 10:55:38 +01:00
zwitschi 49bfccc808 Add a docs README and link checker
Full build / Import + headless tests (push) Successful in 39s
Full build / Full desktop build + optional release (push) Skipped
Add tools/check_docs.py to require READMEs only in tracked docs directories,
validate local links and verify every tracked image is linked. Gitignored
generated files such as realism runs are exempt. Document the command and add
unit tests. Python 97/97.
2026-11-02 10:52:15 +01:00
zwitschi 7401d4bca0 Do not require READMEs in generated realism folders
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 39s
Remove generated README files from docs/screens/realism and update the screens
index to treat realism as a gitignored local QA directory with no README gate.
2026-11-02 10:50:20 +01:00
zwitschi e79a37beba Add documentation folder READMEs and visual previews
Full build / Import + headless tests (push) Successful in 36s
Full build / Full desktop build + optional release (push) Skipped
Create an index README in docs/ and every tracked docs subfolder, with relative
image galleries for Blender previews, screen designs, screenshots and concepts.
Generated realism-run READMEs were also created on disk but remain gitignored.
Validate all Markdown/image links.
2026-11-02 10:49:42 +01:00
zwitschi fbd2ab2cb3 Disable unreliable Gitea Godot cache steps
Full build / Import + headless tests (push) Successful in 35s
Full build / Full desktop build + optional release (push) Skipped
Gitea cache restores were inconsistent and cache saves timed out or were
rejected as reserved by another job. Remove the cache steps and keep direct
4.7.2 downloads; document the evaluation and when to retry. The workflow is
otherwise clean (no .github/ci.yml exists).
2026-11-02 09:51:59 +01:00
zwitschi 9b8f513f9f Trim the Godot template cache and separate CI cache keys
Full build / Import + headless tests (push) Successful in 2m24s
Full build / Full desktop build + optional release (push) Skipped
Cache only Linux/Windows/macOS/Web release templates instead of the full 1.2 GB
archive, and use distinct binary cache keys for the checks and build jobs so
concurrent runs do not fight over the same cache entry.
2026-11-02 09:48:05 +01:00
zwitschi ad12fdad7e Bump to 0.9.1 and record the toolchain update
Full build / Import + headless tests (push) Successful in 2m23s
Full build / Full desktop build + optional release (push) Successful in 9m44s
2026-11-02 09:28:13 +01:00
zwitschi 87612f2057 Unify the Godot 4.7.2 CI environment and cache it
Full build / Import + headless tests (push) Successful in 2m30s
Full build / Full desktop build + optional release (push) Skipped
Update project features and CI installs/templates to Godot 4.7.2, remove the
old version matrix, and cache the Godot binary and export templates with Gitea
Actions cache. Update release/docs/version references accordingly. Project
import and headless tests pass locally under 4.7.2.
2026-11-02 09:25:08 +01:00
zwitschi ffd98daf08 Plan the pre-RC patch levels
Full build / Import + headless tests (push) Successful in 38s
Full build / Full desktop build + optional release (push) Skipped
Add detailed 0.9.1 UI/dialog/button polish, 0.9.2 NPC model refinement,
0.9.3 texture/material refinement and 0.9.4 integration/performance/judge
workstreams before the 0.9.5 release candidate. Update the remaining-gap table,
baseline to v0.9.0 and README development status.
2026-11-02 09:16:33 +01:00
zwitschi f811e6054d Expand the 0.9.5 release-candidate checklist
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 38s
Replace the remaining-gap table with v0.9.0 baselines and break the release
candidate into detailed workstreams for content lock/playtests, balance,
save migration, release engineering, legal/credits, documentation/visual
sign-off and final QA. Sync the README development status to v0.9.0.
2026-11-02 08:54:39 +01:00
zwitschi 9d37e0a1c5 Bump the project version to 0.9.0
Full build / Full desktop build + optional release (push) Successful in 5m0s
Full build / Import + headless tests (push) Successful in 36s
2026-11-01 21:48:03 +01:00
zwitschi 883626a067 Ship the 0.9.0 production-quality milestone
Full build / Import + headless tests (push) Successful in 42s
Full build / Full desktop build + optional release (push) Canceled after 4m58s
Add mixer/accessibility settings, caption/reduce-motion hooks, audio volume
clamping, a 24-NPC performance smoke and shortened coat/dress stride for hem
clipping. Record the explicit Godot 4.3-CI/4.7-local matrix and the 0.9
production scope. Headless 250/250, Python 94/94, 24-NPC budget smoke passes.
2026-11-01 21:46:42 +01:00
zwitschi b5d4d5fb87 Plan detailed 0.9.0 production-quality steps
Full build / Import + headless tests (push) Successful in 43s
Full build / Full desktop build + optional release (push) Skipped
Expand the next milestone into animation, audio, localization, accessibility,
performance/platform, QA/visual baselines, Godot-version policy and exit
criteria, with concrete verification work per workstream.
2026-11-01 21:39:29 +01:00
zwitschi fac9b002c3 Fix normal radio report submission
Full build / Import + headless tests (push) Successful in 38s
Full build / Full desktop build + optional release (push) Failing after 4m22s
The radio button was connected only to the emergency hold handlers, so a
normal Send request never reached _submit. Connect pressed for non-emergency
calls while keeping hold-to-confirm exclusive to emergencies, and add tests
for click, short-hold rejection and full emergency hold. Headless 249/249,
Python 94/94.
2026-11-01 21:37:39 +01:00
zwitschi aa51ee331e Ship the 0.8.0 first-hour and campaign milestone
Full build / Full desktop build + optional release (push) Successful in 4m18s
Full build / Import + headless tests (push) Successful in 41s
Add the campaign shell, pause-safe checkpoint resume, post-shift campaign
continue, confirmed campaign reset, difficulty presets, searchable Help,
content-matrix validation, recovery events, contextual dialogue, policy/debrief
context and eligible-event previews. Extend persistence with atomic separate
files and add campaign/checkpoint/tutorial smokes. Headless 247/247, Python
94/94, tutorial/campaign/session/scenario smokes green.
2026-11-01 21:21:43 +01:00
zwitschi 86332cd401 Wire the first-shift tutorial into gameplay
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 38s
Add the non-blocking prompt card, safe compliant visitor, action-driven
advancement through the real wheel/inspection/warning/radio panels, persisted
completion/skip, a Settings replay action and localized tutorial strings.
Scripted tests/captures bypass the tutorial unless --tutorial is passed. Add a
windowed smoke covering the full flow. Headless 237/237, Python 94/94, tutorial
smoke passes.
2026-11-01 21:05:59 +01:00
zwitschi 76eb5e3a79 Fix mouse look swallowing by the HUD
Full build / Import + headless tests (push) Successful in 35s
Full build / Full desktop build + optional release (push) Successful in 4m39s
Move guard look handling to the _input stage, recapture the cursor on
window-focus return and when clicking back into gameplay, and make HUD controls
mouse-transparent. Add regression tests for yaw/pitch and HUD mouse filters.
Verified under Xvfb with real relative mouse motion. Headless 237/237, Python
94/94, movement smoke 60 fps.
2026-11-01 20:38:36 +01:00
zwitschi f4a53e2d4f Add the first-shift tutorial design and state machine
Full build / Import + headless tests (push) Successful in 38s
Full build / Full desktop build + optional release (push) Skipped
Write the eight-beat tutorial sheet, its safe visitor script, persistence and
replay rules. Add a deterministic, skippable/restartable Tutorial RefCounted
state machine with headless tests. UI/GameManager wiring remains the next task.
Headless 235/235, Python 94/94.
2026-11-01 20:19:18 +01:00
zwitschi 806fe78688 Clarify nested TODO completion rules
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 37s
Describe level-2 milestones/themes, level-3 workstreams and the rule that
completed workstreams stay under their parent until the whole milestone is
done. Add a milestone-shaped recommended format and align the changelog/tag
steps with nested sections.
2026-11-01 20:16:23 +01:00
zwitschi 6a3066d763 Clarify nested task grouping in the agent checklist format 2026-11-01 20:14:53 +01:00
zwitschi f4cce28454 Restructure the v1.0 roadmap around milestone sections
Full build / Import + headless tests (push) Successful in 38s
Full build / Full desktop build + optional release (push) Skipped
Promote every milestone to a level-2 section and expand 0.8.0 into detailed
workstreams for tutorial, campaign, content matrix, dialogue, debrief, save/
resume, difficulty/help and verification. Keep later milestones broad and
preserve the deferred realism/future lists.
2026-11-01 20:12:17 +01:00
zwitschi 7d39523e49 Keep generated realism runs out of the repository
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 33s
Ignore docs/screens/realism/ entirely and remove its reports/captures from the
index while leaving the generated folders on disk. Update the asset-tooling and
concept notes to treat realism runs as local QA artifacts. Link scan clean.
2026-11-01 20:09:45 +01:00
zwitschi 7e084192ce Remove the obsolete graphics plan
Full build / Import + headless tests (push) Successful in 34s
Full build / Full desktop build + optional release (push) Skipped
Delete docs/plan-graphics-v0.6.md and update README, architecture, asset
tooling, Blender docs and MEMORY references. Completed work stays summarized
in ADR-0013, the asset-pipeline architecture and the changelog; the v1.0.0
roadmap owns future graphics work.
2026-11-01 20:06:31 +01:00
zwitschi 6c367e8c7e Consolidate architecture docs and add the v1.0.0 roadmap
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 34s
Make architecture the canonical system/data-flow source, add explicit
documentation ownership and consolidation rules, and mark the old graphics plan
historical. Fix stale README/status/Blender/release claims. Add a full gap
register and milestone roadmap from v0.8 through v1.0.0, including onboarding,
content depth, accessibility/localization, performance, release/legal blockers
and non-blocking future ideas.
2026-11-01 20:04:47 +01:00
zwitschi 659b0e35b2 Make the vision judge discover cost-effective OpenRouter models
Full build / Import + headless tests (push) Successful in 40s
Full build / Full desktop build + optional release (push) Successful in 4m6s
Add openrouter_judge.py to rank live image+JSON models by advertised price,
with ordered fallbacks, auth-error handling and auto selection. Wire both judges
to --model auto, record the model used, and add fake-catalogue/mocked-call
tests. Re-run the judges with the valid key: 13/13 screen designs match, 0 diff;
the Forward+ A/B report records the selected model and ~$0.006 spend. Headless
231/231, Python 94/94.
2026-11-01 19:55:43 +01:00
zwitschi 28f2a48811 Add the optional Forward+ desktop HQ build
Full build / Full desktop build + optional release (push) Successful in 5m20s
Full build / Import + headless tests (push) Successful in 40s
Package a Forward+ preset with volumetric fog, SDFGI and a volumetric flashlight
for a separate Linux/Windows Desktop HQ zip. Gate the effects on a real
RenderingDevice, tune LATE fog, and adapt local light falloff for Godot 4.7.
Record the Compatibility/Forward+ A/B captures and metrics, add the artifact to
the build/publish scripts, and keep the default Compatibility/Web path
unchanged. Headless 231/231, Python 87/87; exported HQ binary boots with Vulkan.
2026-11-01 19:40:42 +01:00
zwitschi 64f0c6a198 Document the local Godot 4.7.2 toolchain
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 38s
Record the upgraded 4.7.2 binary, the retained 4.3 backup and the matching
export templates. Keep the project/CI baseline at 4.3 and note that 4.7.2
verified import, tests, the session smoke and a Linux export. Hide the
4.7-generated per-script UID sidecars from this clone only.
2026-11-01 19:16:55 +01:00
zwitschi 8b0845bcce Build distinct Joke Shop and TV Studio venues
Full build / Import + headless tests (push) Successful in 40s
Full build / Full desktop build + optional release (push) Successful in 4m57s
Add the alley walls, warm lantern, shutters, dumpster, AC clutter and door
step for the Joke Shop. Build the studio stone facade, bulb canopy, glossy
black car, stanchions and barriers. Rebuild only the world container when the
venue changes, so the guard and UI survive; add per-venue navigation checks.
Capture gallery shots 12/13, update the concept mapping and docs. Headless
231/231, Python 87/87, screenshot gate 13 good/0 bad. The vision-judge retry is
tracked separately because the API key is invalid.
2026-11-01 19:09:47 +01:00
zwitschi 4cca2af2dd Extract per-venue geometry specs into WorldBuilder
Add the Hollywood, Joke Shop and TV Studio tables for facade, window,
stair, street, nav, guard-spawn and feature data. Unknown ids fall back to
the boulevard. Use the specs for the core dimensions and gates, with a headless
test for the distinct venue data. Headless 230/230.
2026-11-01 19:03:20 +01:00
zwitschi 99f390078d Restore the full changelog history 2026-11-01 19:00:53 +01:00
zwitschi a9fe6b9944 Extend the agent workflow with docs and changelog maintenance 2026-11-01 18:56:15 +01:00
zwitschi d4201caa62 Release v0.6.1
Full build / Import + headless tests (push) Successful in 38s
Full build / Full desktop build + optional release (push) Successful in 3m49s
Ship the fitted NPC gear pass with the post-v0.6.0 realism and UI work.
Bump the version source and documentation to 0.6.1 and move the changelog
entry out of Unreleased. Headless 229/229.
2026-11-01 18:55:58 +01:00
zwitschi 6100d19a25 Document the gear-fit pass and add the changelog
Create CHANGELOG.md with the post-0.6.0 gear-fit entries and backfill the
recent release history. Update the implemented-features list, asset-tooling
notes, README links and verification counts (headless 229, Python 87).
2026-11-01 18:55:43 +01:00
zwitschi a7ca698f73 Break the README into focused docs pages
Full build / Import + headless tests (push) Successful in 36s
Full build / Full desktop build + optional release (push) Skipped
2026-11-01 18:47:44 +01:00
zwitschi 26d64baa01 Close the NPC gear-fit section
Full build / Import + headless tests (push) Successful in 34s
Full build / Full desktop build + optional release (push) Skipped
Move the completed gear section to DONE.md and record the hooded-portrait
follow-up. An explicit --portrait-type now overrides the hooded-subject skip,
though the day roster has no types 5-7 yet. Headless 229/229.
2026-11-01 18:12:37 +01:00
zwitschi 151630e957 Recapture the gear portrait and gallery shots
Fix the portrait staging: face the rig toward the camera (the old yaw was 180
degrees out) and hide the focus disc, which was covering the face in close-ups.
Add the before/after Influencer portrait, fit measurements and judge scores in
docs/screens/realism/2026-11-01-gear. Re-run check_screenshots (11 good/0 bad);
headless 229/229.
2026-11-01 18:09:50 +01:00
zwitschi 1b319c48b7 Guard gear fit with headless and Blender regression checks
The Python fit test now caps the glasses at 0.70x head width and requires a
positive bag clearance on both the coat and dress. The Godot character suite
loads head/back gear on six roles and checks attach parents, head width and
brow bounds, and that back gear reaches beyond the 0.26 m body silhouette.
Rebuilt and re-baked all 18 gear assets; no-op GLB export churn was reverted.
Headless 229/229, Python 87/87.
2026-11-01 18:04:51 +01:00
zwitschi a478bfbf35 Clear the firefighter helmet brim from the brow
The face pass added a brow ridge; lift the helmet mesh 2 cm so the brim sits
above the eyes. Cap and hood were rendered on their characters and leave the
brow/ears and face readable. Rebuild and re-bake the helmet; Python 87/87.
2026-11-01 18:02:38 +01:00
zwitschi 702f54ae53 Move the shoulder bag clear of coat and dress skirts
Narrow the bag to 0.06 m and move it outboard to centre x=0.292. The body inner
face is now 0.262 m, clearing the coat skirt (0.225) and dress (0.260); the
strap lower points start on the same line. The fit report measures the bag body
separately from the torso strap and uses a signed inner-face clearance. Run
Blender build/bake and Godot import. Python tooling 87/87.
2026-11-01 17:58:47 +01:00
zwitschi bbf4693475 Narrow the sunglasses and fix portrait-type parsing
Move the hinges to +/-0.075 (0.035 box), arms to +/-0.098, and lenses to a
0.024 m radius while keeping the lens plane in front of the eyes. Rebuild the
GLB and AO; fit now measures 0.202 m total width (0.64x head). capture_realism
now parses the documented --portrait-type option instead of ignoring it.
Python tooling 87/87; headless 228/228.
2026-11-01 17:56:10 +01:00
zwitschi d7b0203502 Document commit and milestone steps in the agent workflow 2026-11-01 17:53:24 +01:00
zwitschi da876e3545 Add a gear-vs-body fit report to the Blender asset tool
`blender_assets.py fit` measures each character head width (skin vertices
weighted to Head in y 1.55-1.81) and clothing radius (cloth skirt in y 0.30-0.52,
pants hip fallback), then prints every attached head/back/chest gear bounding box
with head-band status and x/radial skirt clearance. The report confirms the
glasses width and shoulder-bag coat clip, giving the next fit fixes numbers.
Python tooling 87/87; asset audit clean.
2026-11-01 17:52:38 +01:00
zwitschi 1ee32215b0 Detail the NPC avatars and finish the realism follow-ups
Full build / Import + headless tests (push) Successful in 38s
Full build / Full desktop build + optional release (push) Skipped
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
zwitschi 2624b54b23 Compact the plan and synchronize project documentation
- reduce PLAN.md from a 674-line implementation log to a 187-line product/design
  plan; keep escalation, venues, NPC/systems, controls, presentation and constraints
- refresh README for implemented venues, Blender/v2 assets, the custom test runner,
  Web target, current release state and the screenshot smoke
- update architecture for 0.6.0, the runtime art loader, Gitea CI/build/publish,
  Web deployment, six release artifacts and visual regression
- remove stale uncommitted/active-pass claims from MEMORY and point it at the
  current NPC follow-ups; move the completed documentation task to DONE
2026-11-01 17:37:02 +01:00
zwitschi 85d67ff8b1 Fix heading hierarchy and restore the future ideas section in PLAN.md 2026-11-01 17:33:15 +01:00
zwitschi 47c57ddc76 Tighten the flashlight spot and refresh captures
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 37s
Narrow the spot to 11° with a 20 m range so it lights the person/door rather
than the whole facade, and regenerate the staged screenshots. Headless 227/227,
compare 11 good / 0 bad.
2026-11-01 17:06:57 +01:00
zwitschi 3c07525351 Use a vertical fade for the flashlight beam
Full build / Import + headless tests (push) Successful in 37s
Full build / Full desktop build + optional release (push) Skipped
A GradientTexture1D varies along U, so the cone showed a bright ring; build a
1×64 vertical ramp for UV.y instead (faint at the lens, brightest near the
start, gone before the tip). Regenerate the affected captures; headless 227/227,
compare 11 good / 0 bad.
2026-11-01 17:06:09 +01:00
zwitschi 4a672025a2 Capture the late-night avenue and flashlight in the LATE phase
Full build / Import + headless tests (push) Successful in 38s
Full build / Full desktop build + optional release (push) Skipped
Jump the staged shift to 760 s before the night shots, so 05/06 are true night
scenes with a visible flashlight beam instead of dusk. Regenerate the affected
captures; compare stays 11 good / 0 bad.
2026-11-01 17:05:06 +01:00
zwitschi 6acbc2b3a4 Tune the flashlight beam and refresh affected captures
Full build / Import + headless tests (push) Successful in 37s
Full build / Full desktop build + optional release (push) Skipped
Widen and lengthen the additive beam cone and raise its near-end opacity so the
night flashlight reads on screen. Regenerate the staged captures; compare stays
11 good / 0 bad, headless 227/227.
2026-11-01 17:04:09 +01:00
zwitschi d7e523f63c Adopt the realism pass and refresh screenshots/docs
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 34s
- add the v2 runtime picks: per-phase skyline panoramas, brick, sidewalk
  pavers, dry/wet asphalt, awning canvas, and their normal maps
- add the realism tooling and evidence: tools/scene_concepts.py, capture_realism.gd,
  concept frames, reports/sheets, and tests
- retune phase lighting/fog/exposure, add sun yaw, brighten the night glow,
  add the flashlight beam mesh, and rebuild the planter/tree assets
- regenerate all eleven staged screenshots from the current build; compare is
  11 good / 0 bad
- finish the visual-alignment closeout in DONE/TODO, update architecture,
  blender-assets, PLAN, and ignore rules (editable Blender sources untracked)
- keep the judge retry and document the verified default judge model

Verification: headless 227/227; Python tooling 86/86; check_screenshots 11/11.
2026-11-01 17:03:05 +01:00
zwitschi 26ecb93fd4 Move the body-camera overlay below the shift status
The REC/clock block sat on top of the top-right shift/rep/crowd lines. Start it
at y=92 and slightly farther from the edge, keeping the overlay visible without
covering the status. Headless 226/226 and a windowed HUD screenshot checked.
2026-11-01 16:51:19 +01:00
zwitschi 8997f59819 Record the judge re-check and the lighting blocker
Mark the default vision judge as verified (7 match / 4 review / 0 diff), note the
active realism pass blocking the remaining lighting task, and replace the stale
memory note that said screen_designs still read the docs tree.
2026-11-01 16:50:27 +01:00
zwitschi 79270795a8 Finish the image-root task and untrack Blender sources
- ignore assets/models/blender_src/*.blend (keep the .gdignore marker tracked) and
  remove the 46 editable .blend files from the index; they remain on disk and are
  regenerated by tools/blender_assets.py
- move the completed storage/docs/code-path/art-loader/verification, mouse-fix,
  and pop-up sections to DONE.md; TODO now holds only the open lighting item,
  realism follow-ups, and optional ideas
- docs changes only; runtime code unchanged
2026-11-01 16:49:43 +01:00
zwitschi dc4bc6c511 Use the access-inspection mockup behind the inspection panel
Add the access_inspection art layer to the HUD, keep the panel transparent and
padded, center the title/status/issue text and artifact cards, and hide the art
with the panel. Also record the pop-up visual pass as done. Headless 226/226
verified in a clean HEAD worktree.
2026-11-01 16:46:25 +01:00
zwitschi c8b98fdb30 Recapture the mouse after selecting a venue
_start_shift() now calls _refresh_freeze(), clearing the start-menu input lock
and returning to captured mouse mode. The movement smoke asserts both and no
longer captures the mouse itself. Headless 226/226 and smoke_movement pass in a
clean worktree; only this game_manager hunk is staged, not the active realism
edits.
2026-11-01 16:45:05 +01:00
zwitschi d96f53c285 Add a repeatable screenshot capture and compare smoke
Both capture helpers now accept --out=res://docs/screenshots, and
tools/check_screenshots.sh renders the staged set (using xvfb-run when headless)
before running screen_designs.py compare. Record the judge result: 7 match,
4 review, 0 diff. Headless 226/226 and the smoke both pass in a clean worktree.
2026-11-01 16:43:10 +01:00
zwitschi b39fee6176 Match the radial menu to its mockup
Widen the doughnut, use dark charcoal wedges with a dimmed scene behind them,
add divider spokes and inner/outer rings, raise the center-name size, and use a
restrained light highlight for the selected slice instead of the old yellow
fill. Headless 226/226 verified in a clean HEAD worktree.
2026-11-01 16:39:28 +01:00
zwitschi c2c93c28a5 Record the HUD alignment and capture comparison result 2026-11-01 16:37:56 +01:00
zwitschi 3030c60ae1 Align the HUD target chip and escalation meter with the mockups
Move the target name out of the top-left stack into a boxed chip under the
crosshair, keep the log/hints left and shift status right, and add a five-segment
escalation bar under the existing color-coded label. Empty targets hide the
chip. Headless 226/226 verified in a clean HEAD worktree.
2026-11-01 16:36:06 +01:00
zwitschi cb65a5a601 Note the radio/wand/timeline art wiring in memory 2026-11-01 16:30:48 +01:00
zwitschi 06a4f5479f Align the body-camera timeline with its sidebar mockup
Draw body_camera_timeline behind a full-height narrow panel, constrain the
content to that column, wrap long event text, and scroll the event list so the
Previous/Next/Close row stays pinned at the bottom. Headless 226/226 verified in
a clean HEAD worktree.
2026-11-01 16:30:17 +01:00
zwitschi 8032999a4d Use the radio and wand mockups behind their forms
Draw radio_report/emergency_radio behind a transparent, padded form and switch
the backdrop with the call type. The wand HUD popup now shows wand_screening
behind its text while open. Both covers use the mockup panel bounds so baked-in
controls stay hidden. Headless 226/226 verified in a clean HEAD worktree.
2026-11-01 16:29:35 +01:00
zwitschi 8582e496ff Point the README at the runtime image root
Update the resize/audit examples and the screen-design section to
assets/images/ui|scenes, with docs/screens/designs as the reference snapshot.
The separate realism-pass README hunk stays unstaged.
2026-11-01 16:20:10 +01:00
zwitschi ae326ce970 Mark the aligned menu/panel items done in the visual pass 2026-11-01 16:20:01 +01:00
zwitschi 00faf45e83 Use the shift review mockup as the end-of-shift backdrop
Wrap the review content in a Control root, draw the shift_review art behind an
opaque panel, and style the action buttons to match the mockup. Headless
226/226 verified in a clean HEAD worktree.
2026-11-01 16:19:54 +01:00
zwitschi 41d3511fc7 Record the runtime art loader and the active realism workstream in memory 2026-11-01 16:19:23 +01:00
zwitschi 1efa5bc7d9 Use the pause and settings mockups as panel backdrops
Add UiArt.add_screen_backdrop() to place the reference art behind an opaque
panel, then wire the pause overlay and settings screen to it. Pause rows get
larger, rounded styles; settings widens to fit its expanded controls. Headless
226/226 verified in a clean HEAD worktree (the realism WIP currently editing
materials.gd remains unstaged).
2026-11-01 16:19:18 +01:00
zwitschi 4745adeb13 Move screen designs to the runtime root and add the UI art loader
- screen_designs.py now reads/writes assets/images/ui/ (ADR-0014); docs/
  screens/designs/ stays the reference-only snapshot, documented as historical
- add src/game/ui/art.gd: cached loader for assets/images/ui|scenes with null
  fallbacks for missing files, plus headless tests
- start menu uses the start_menu scene art as a full-screen backdrop, covers the
  baked-in mockup panel with an opaque panel, and styles the venue rows to match
- update README/architecture/TODO path notes and mark the storage/code-path/loader
  items done; DONE records the historical path move
- compare still 11 good / 0 bad; headless 226/226

README/PLAN realism-pass edits from another workstream remain unstaged." && git log --oneline -1
2026-11-01 16:00:12 +01:00
zwitschi 15deb58b73 Import the promoted runtime mockups
Run the headless Godot import after copying the 21 design references into
assets/images/ui/; all sidecars are generated and TODO records the item done.
2026-11-01 15:48:22 +01:00
zwitschi 6a0bf70fdf Document the asset storage convention
Add the path table from ADR-0014 to the architecture documentation (runtime UI/scene
art, tiled textures, models, reference art, QA captures, raw sources) and close the
second storage-restructure TODO item.
2026-11-01 15:47:56 +01:00
zwitschi f458551594 Claim TODO tasks with [-]; promote mockups to assets/images/ui
- AGENTS.md now requires agents to mark a task [-] while claimed/in progress and
  only use [x] after implementation and verification, with an example
- copied the 21 reference mockups from docs/screens/designs/ into the runtime
  root assets/images/ui/ (byte-identical names); docs/screens/designs/ stays as
  the reference-only copy per ADR-0014
- MEMORY records where the copies live and that screen_designs.py still reads
  the docs tree until the code-path migration

First storage-restructure TODO item completed.
2026-11-01 15:47:35 +01:00
zwitschi 8f228b0c56 Decide the canonical runtime image root (ADR-0014)
assets/images/ is now the runtime root for composed interface/scene art:
ui/ for screen and panel art, scenes/ for full-frame scene art. Tiled PBR
textures remain under assets/textures/; docs/screens/designs and concepts stay
reference-only; QA captures stay under docs/screenshots. Mockups that become
runtime art are copied/processed with a new name (no overwrites) and always
have a code fallback.

Records the convention in MEMORY, adds ADR-0014 to the architecture index, and
closes the first storage-restructure TODO item.
2026-11-01 15:16:24 +01:00
zwitschi d307746351 Close the v0.6.0 graphics plan and record the release
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 32s
- TODO now tracks only the visual-alignment pass and optional future ideas; the
  completed Blender/graphics plan moved out
- DONE records the six published v0.6.0 artifacts and final verification counts
- header updated to v0.6.0 / 222 headless / 69 Python tests
2026-11-01 15:12:37 +01:00
zwitschi d872034388 Bake library AO and lift environment textures
Full build / Full desktop build + optional release (push) Successful in 3m43s
Full build / Import + headless tests (push) Successful in 29s
Phase 4 of the v0.6.0 graphics plan:

- tools/bake_ao.py bakes 256² AO maps for every Blender character/gear/prop
  (Cycles, existing UVs) next to each GLB; Materials.apply_ao() wires the red
  channel into character slots, gear, and props. Compatibility has no SSAO.
- Regenerated brick/concrete/asphalt at 1024² with OpenRouter, derived tangent
  normal maps via tools/make_normal_maps.py, and wired them through
  SurfaceMaterials.textured() without changing UV scales.
- Evaluated Forward+: boots on desktop Vulkan, but the renderer is project-wide
  and Web must stay GL Compatibility; v0.6.0 keeps Compatibility (decision in
  MEMORY/plan). A desktop-only override is deferred.
- Recaptured screenshots; compare 11 good / 0 bad. Fixed marquee text alignment.
- Tests: baked AO maps exist for all 46 assets; prop/character AO material
  checks; headless 222/222, Python 69/69, all smokes pass.
- Version 0.6.0; ADR-0013 accepted; README/architecture/blender-assets/plan and
  TODO/DONE updated.
2026-11-01 15:07:27 +01:00
zwitschi d8cfddbf89 Integrate the Blender character, gear and prop library
NpcAvatar
- select one of 8 library character variants by role/seed (with npc_base and the
  procedural rig as fallbacks), keep Rig/Head and the existing bone animation
- tint only skin/cloth/pants/accessory/hair; fixed detail materials keep their
  colour, npc_vest keeps its hi-vis vest, firefighter/guard use dark uniform tints
- attach caps, hoods, helmets, backpacks, SCBA tanks, lanyards and hand items at
  the documented head/back/chest/hand points (primitive fallbacks retained)

WorldBuilder
- prefer assets/models/blender/props/ for the six replacements and the new
  street dressing (street lamp/tree, palms, planters, A-frame, cone, barrier,
  stanchion, podium, handrail, wall lantern, double door, marquee, sedan)
- fit the same colliders/navigation obstacles and keep the placement validator;
  collect library emissives (bulbs, marquee face, wall lanterns, door LED, sedan
  lights) for set_night_mode()
- add a library triangle counter + 60k budget check (current ~27,986); toggle
  prop gallery to the library models; fix the marquee label placement

Tests/smoke
- character selection/gear attach/fixed-material tint tests; library prop load,
  emissive and triangle-budget tests; smoke_props routes a guest around a
  stanchion in open sidewalk (the old bench route is now crowded by trees)
- headless 222/222, Python 68/68, all smokes pass, compare 11 good / 0 bad

Docs: TODO Phase 3.5 moved to DONE, README/architecture/blender-assets/plan
describe the integrated runtime, MEMORY records the integration rules.
2026-11-01 14:57:02 +01:00
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
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
zwitschi a231f7588a Load and animate the Blender-authored NPC base mesh
Wire the skinned model from ADR-0013 into NpcAvatar:

- _build_skinned_body() instantiates the imported npc_base.glb, binds the 14
  armature bones, and keeps the procedural _build_body() as the offline
  fallback (use_skinned_model can force it in tests)
- outfit_for()/layer_for() tint the five material slots through the new
  SurfaceMaterials.npc_slot(); accessories and hand items attach under Rig/Head
- the existing limb pivots (Hip/Knee/Shoulder/Elbow/Hand + Head marker) keep the
  old animation math; _sync_skeleton() copies their rotations to bones. Bone
  pose rotation is absolute local orientation, so it is composed with the rest
  basis (otherwise the whole body snaps into a broken pose)
- skinned rigs scale uniformly (non-uniform parent scale shears the skin) and
  keep Rig/Head for the focus cone, nametag, and reaction tag
- commit the editable npc_base.blend plus a .gdignore: Godot's editor otherwise
  tries to import the blend and hangs during --import
- npc_pipeline audit tests (contract, textures, clean GLB, committed source)

Verification: headless 212/212, Python tooling 60/60, NPC budget 16 avatars =
144 meshes at ~6.9 ms, movement/focus/props smokes pass, compare 11 good / 0 bad.
TODO Phases 0-3 checked; environment lift and release remain.
2026-11-01 13:26:37 +01:00
zwitschi 3989d7b2e5 Rename Step Line to Gig Line
Update the game name in project.godot, export presets, UI/marquee/title strings, packaging (AppImage/NSIS/desktop/appdata), tools, docs, and the generated prop GLBs. Packaging assets and README screenshots are regenerated. Headless suite 209/209 and Python tooling tests pass.
2026-11-01 12:52:17 +01:00
zwitschi 0eb17e3bb4 Fix NPCs walking backwards
Avatars called Godot's look_at(), which points the node's -Z axis at the target,
but the rig's face (eyes/brows/mouth/focus disc, and the Blender successor) is on
+Z. Every walking NPC therefore faced away from its movement direction.

- add the pure yaw_towards(direction) helper (+Z forward) and use it in both
  movement paths and the reaction face-turn
- fix the head-turn offset to the same +Z convention (basis.z)
- test +Z/+X/-Z/arbitrary directions; recapture targeting screenshot
- TODO bug item moved to DONE, MEMORY records the convention

Headless 209/209.
2026-11-01 12:30:41 +01:00
zwitschi a7daae8a14 Add NPC backwards-walking bug to TODO 2026-11-01 12:26:35 +01:00
zwitschi 3f4a8e5f9f Regenerate screenshots; document NPC pipeline and confirmed assets
Ten of the eleven README captures are refreshed (the prop gallery is unchanged). README gains an NPC character-model subsection and a 'Confirmed game assets' section with linked, audited textures/models; architecture Level 2 lists npc_pipeline.py and asset_pipeline.py.
2026-11-01 12:25:35 +01:00
zwitschi 91b10e0f94 Document Godot project file format comments 2026-11-01 12:11:59 +01:00
zwitschi 4943dbff16 Extend AI image tooling with variants; drop dev asset folders from git
asset_pipeline generate gains --variants N (saved as <stem>-1..N.png). .gitignore now excludes assets/models/concepts, assets/models/npc, assets/textures/npc/ai, and raw assets/textures/ai outputs; only game_ready and the game-facing NPC maps/models stay tracked.
2026-11-01 12:08:34 +01:00
zwitschi b24d0aeb61 Plan the v0.6.0 graphics pass and add Blender-authored NPC assets 2026-11-01 12:02:27 +01:00
zwitschi a27e8cb74c Character and movement pass
Full build / Import + headless tests (push) Successful in 33s
Full build / Full desktop build + optional release (push) Successful in 3m37s
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.
2026-11-01 10:41:17 +01:00
zwitschi 2a4e0d1998 Audit prop budgets and add a prop-gallery art check
- audit_glb decodes geometry: 400 tris / 600 verts budget, degenerate
  triangles, UV range, ground contact, one material; newspaper box parts moved
  to sit on y=0
- capture_prop_gallery.gd renders the six props on a studio backdrop; new
  prop_gallery catalogue entry + AI mockup (compare 10 good, judge match 0.90)
- headless test that instances share the imported atlas material
- README documents the gallery capture and budget; TODO props pipeline section
  moved to DONE
2026-11-01 10:27:27 +01:00
zwitschi bb40a98537 Give street props colliders, zoned placements and variants
Full build / Full desktop build + optional release (push) Successful in 4m2s
Full build / Import + headless tests (push) Successful in 31s
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.
2026-11-01 10:16:53 +01:00
zwitschi a3e90accdd Plan the presentation pass: props, NPCs, movement
Full build / Import + headless tests (push) Successful in 2m12s
Full build / Full desktop build + optional release (push) Skipped
Replace the flat "future ideas" list with three scheduled sections and concrete,
reviewable checkboxes (41 tasks):

- Better Props: colliders for the generated models (they have none today), a
  placement table with variants, sign/bus-stop/shelter/street-lamp props, a
  close-range detail layer, pipeline audits, and a prop-gallery capture.
- Better NPC Characters: articulated rig, layered outfits and accessories, face
  and hair variety, idle/conversation animation, door-queue staging, reaction
  readability, LOD tiers, and a re-measured NPC budget.
- Better Player Movement: accel/decel split, step-up assist, head bob/FOV and a
  motion-sickness toggle, precision-walk feedback, surface footsteps, gamepad
  support, input remapping, and movement tests.

Kept live 3D replay, extra venues, voice audio, and the image-to-mesh swap in
Future ideas. Memory notes the grounding facts (props have no colliders, rigid
NPC rig, single accel value). Docs-only: no version bump or release.
2026-11-01 10:05:04 +01:00
zwitschi 3025ba1cef Capture the wand panel, escalation HUD and body-camera timeline
Full build / Full desktop build + optional release (push) Successful in 3m56s
Full build / Import + headless tests (push) Successful in 35s
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.
2026-11-01 00:29:58 +01:00
zwitschi a5e7b3c013 Add AI mockups for the seven remaining catalogue screens
Full build / Import + headless tests (push) Successful in 34s
Full build / Full desktop build + optional release (push) Successful in 4m4s
The design catalogue grew to 19 screens, but only the original twelve had an AI
reference; the rest still showed "design -" in `list`. Generated the missing set
so every screen can be reviewed against an intended look:

- wand screening (metal-detected panel with carried items and allow/deny)
- Joke Shop queue, TV Studio arrival, crowd panic, responder arrival
- body-camera timeline, escalation HUD

`generate` now loads `.env` the same way `judge` does, so `--ai` no longer needs
the API key exported by hand. Each reference is 1280x720; the twelve existing
mockups were kept (no `--force`).

Verification: `list` reports 19 designs, Python tooling 53/53, headless suite
182/182, `compare` still 6 good / 0 bad on the captured screens. Version 0.3.2.
2026-11-01 00:01:02 +01:00
zwitschi f2863abeac Draw prop models with a single atlas material
Full build / Import + headless tests (push) Successful in 33s
Full build / Full desktop build + optional release (push) Successful in 3m39s
Each generated prop used one material per part (body, accent, metal...). The
model pipeline now packs a prop's palette into one power-of-two colour atlas plus a
matching metallic/roughness atlas and emits a single material:

- atlas_for(): 8x8 cells per palette role, colours in sRGB, roughness in the G and
  metallic in the B channel of the second atlas; NEAREST sampling keeps cells flat.
- build_glb(): every part merges into one primitive with constant per-vertex atlas
  UVs; the material uses baseColorTexture + metallicRoughnessTexture with factors 1.0.
- audit_glb(): fails unless a prop has exactly one material, both atlas textures,
  two images, and TEXCOORD_0 on every primitive.
- Removed the now-unused sRGB->linear factor helpers; colour travels in the texture.

Verification: headless 181 -> 182 (new "one material per prop scene" test), Python
tooling 53/53 (atlas determinism/size/UV/palette-override tests replace the old
factor tests), model audit OK for all six props, screenshots regenerated and
screen_designs.py compare still 6 good / 0 bad. Version 0.3.1.
2026-10-31 23:47:15 +01:00
zwitschi 7f92b8861d List the Web build in the README downloads table
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 25s
The v0.3.0 release now carries step-line-web-0.3.0.zip (37.5 MB, 63 MB unzipped);
downloads anonymously and serves from any static host. Docs only.
2026-10-31 23:13:43 +01:00
zwitschi afa1d6beec v0.3.0: rendering pass, generated props, selection model and Web build
Full build / Import + headless tests (push) Successful in 36s
Full build / Full desktop build + optional release (push) Successful in 4m17s
Rendering and presentation
- Shared surface-material module (src/game/materials.gd) with per-surface
  roughness/metallic/uv profiles; ACES tonemapping, glow, fog and phase-driven sky
  energy. WorldBuilder rebuilt on those profiles with facade windows that light up,
  door trim/handles, curb, lane dashes, bollards, bench, bin and planter foliage.
- NPC silhouettes: per-role clothing palettes, caps/hoods/backpacks/sunglasses,
  hands and shoes, arm/leg walk swing.
- Six generated low-poly GLB props (bollards, bench, bin, planter, newspaper box,
  hydrant) built by tools/model_pipeline.py, loaded by WorldBuilder with a
  procedural fallback; ADR-0012.

Selection and movement
- Focus ranking by view angle then distance (NpcFocus.rank_indices); Tab and the
  mouse wheel cycle nearby people initially, right click clears focus with a
  re-acquire grace, HUD shows the candidate count, Shift walks at half speed.
  ADR-0011. Windowed smoke extended to cover wheel cycling and clearing.

QA tooling
- screen_designs.py catalogue grown to 19 screens (8 scene, 11 UI) plus a `list`
  subcommand; draft generation keeps existing AI references unless --force.

Web export
- New Web preset using the non-threaded Godot template (static hosting, no
  COOP/COEP). tools/build_releases.sh exports build/web and packages
  build/step-line-web-<ver>.zip; publish_release.sh uploads it with the desktop
  artifacts. test_web_export.gd covers the preset and release wiring.

Verification
- Headless suite 177 -> 181, Python tooling 53 tests, all eight smokes pass
  (including the windowed focus/wheel smoke). Web bundle serves index.html,
  index.wasm (35 MB) and index.pck (30 MB) with HTTP 200 from a static server.
- Version 0.3.0; README, PLAN, RELEASING, TODO/DONE and MEMORY updated.
2026-10-31 23:07:41 +01:00
zwitschi f763cff744 Export venues as editor-authorable .tres resources
Full build / Import + headless tests (push) Successful in 34s
Full build / Full desktop build + optional release (push) Successful in 3m51s
- tools/export_venues.gd (SceneTree script) saves the three factory scenarios to
  content/venues/<id>.tres via ResourceSaver. The factory stays the source of truth;
  the exported files are what an editor workflow would edit and ship.
- New tests load the files back and check that id, name, event pool, profiles,
  policy (ID/wand), equipment, door-staff lines, shift phases, and locations all
  survive. They also fail when the exported files are missing or stale, so the
  export is re-run after content changes.
- GUT is consciously not adopted: the custom headless runner already covers 157
  assertions without an editor plugin and keeps CI dependency-free. Recorded in
  DONE.md.
- TODO: the planned backlog is complete; only optional future ideas remain.
- README/MEMORY updated. Version 0.2.16.
2026-10-31 22:16:55 +01:00
zwitschi 72b9378e69 Add a vision-model screenshot judge to the QA tooling
Full build / Full desktop build + optional release (push) Successful in 3m30s
Full build / Import + headless tests (push) Successful in 32s
`tools/screen_designs.py judge` sends each capture together with its concept
mockup to a vision model and asks whether the capture realises the same screen and
layout intent. This covers what pixel/perceptual metrics cannot judge.

- Prompt explicitly ignores art style, fidelity, fonts, and placeholder text, since
  the references are stylised mockups.
- Verdicts are classed match / review (mismatch below --fail-confidence, default
  0.6) / diff (confident mismatch, exits non-zero) / unknown; --json, --only,
  --dry-run, --model supported.
- Reads the repo .env for OPENROUTER_API_KEY without overriding real env vars.
- Default judge model google/gemini-2.5-flash-lite; openai/gpt-4o-mini verified too.

Tests/docs
- 7 new offline tests in tools/test_screen_designs.py (request payload embeds both
  images, JSON/fenced/parts/non-JSON parsing, threshold classification, .env
  loading); 30 Python tests pass.
- Live run: 3 captures match, 3 review, 0 confident diffs.
- README, TODO section moved to DONE, MEMORY. Version 0.2.15.
2026-10-31 22:11:45 +01:00
zwitschi 74f14014b2 Enable anonymous downloads on the host and harden Strings.fmt
Full build / Import + headless tests (push) Successful in 33s
Full build / Full desktop build + optional release (push) Successful in 3m31s
Host (applied with root@192.168.88.30)
- [service] REQUIRE_SIGNIN_VIEW = false in /etc/gitea/app.ini (backup written
  alongside), Gitea restarted. Verified anonymously: repo page 200, API 200, and a
  release asset downloads at full size (50.8 MB AppImage).

Localization safety (Open Polish)
- Strings.placeholder_count() counts conversions and ignores %% escapes.
- Strings.fmt() validates the count and fails safe (warns, returns the template)
  instead of raising an engine error when a key's placeholders drift.
- Strings.validate() lints the table for a trailing %, unsupported conversions, and
  mixed positional/sequential placeholders.
- Tests cover the counter, the fail-safe path, a clean table, and a formatting pass
  over every placeholder key with type-correct arguments.

Docs
- TODO: distribution, release-pipeline, and open-polish sections are complete and
  moved to DONE; the v0.2.4-v0.2.8 backfill is closed as superseded.
- README/MEMORY updated. Version 0.2.14.
2026-10-31 22:02:24 +01:00
zwitschi a2a0ded527 Author the missing scenario content from the PLAN lists
Full build / Import + headless tests (push) Successful in 35s
Full build / Full desktop build + optional release (push) Successful in 3m26s
Joke Shop
- Reservation list without ID (guest list valid, ID missing) — denied.
- Borrowed/mismatched ID (ID valid but mismatched) — denied.
- Guest who refuses the wand screen: new `refuses_screening` event flag, copied
  onto NPCController, handled in _toggle_wand_screening (logs wand.refused, records
  a wand_refused event, small prop hit, panel stays closed).
- Late arrival during the performance (ID + ticket, "arrive" intent).

Studio
- Filming-boundary event and a later repeat, both using the new `film_boundary`
  intent which maps to `steps_end` so the influencer stands past the posted line.
- Celebrity arrival now pulls in a small crowd via a new `extra_spawns` event field
  (two tourists + an influencer), spawned through the normal path.

Building
- Filming-boundary event whose hint points at the body camera and request-reason
  verbs, plus an unclear-intent event that hints at asking for a reason.

Engine support
- Events may carry `hint` (string key logged on spawn), `extra_spawns`, and
  `refuses_screening`; 9 new localized hint strings.

Tests/docs
- Headless suite 139 -> 149 (test_scenario_content.gd) and a new
  smoke_scenario_content.gd that spawns the refusal and celebrity events through the
  real signal path.
- README, TODO section moved to DONE, MEMORY. Version 0.2.13.
2026-10-31 21:55:24 +01:00
zwitschi 922a990c7a Record verified CI publishing and host maintenance
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 24s
- v0.2.12 was tagged and CI produced the release with all five artifacts by itself,
  confirming the checkout-credential fallback end to end.
- Host maintenance through root@192.168.88.30: apt cache cleaned and journald capped
  at 300M (journal ~133M now), ~7.6G free of 16G.
- TODO release-pipeline section is fully closed; MEMORY records the host state.
2026-10-31 21:51:41 +01:00
518 changed files with 37269 additions and 2048 deletions

No files matched your search

View File
Whitespace-only changes.
@@ -0,0 +1,212 @@
---
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 required 13 core bones (optional extra bones allowed), five tint slots, 24,000/24,000 character budgets, gear attach space, 256² texture/AO rules, headless flatpak Blender commands, optional MCP guidance, 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.
Blender MCP is optional interactive tooling; the headless flatpak CLI remains
authoritative and CI never needs Blender or MCP. The `blender-skills` pack is
optional, local guidance only, and gitignored. Setup and safety are in
`docs/asset-tooling.md#optional-interactive-blender-mcp`.
## 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 | The 13 required core bones: `Head`, `HipL/R`, `KneeL/R`, `ShoulderL/R`, `ElbowL/R`, `HandL/R`, `Spine`, `Neck`. Optional extra bones (fingers, face, toes) are allowed; they must not move the core rest positions or break animation proxies. |
| Tint slots | `skin`, `cloth`, `pants`, `accessory`, `hair`. |
| Orientation | Front is Blender −Y / Godot +Z; feet grounded near y = 0; metres. |
| Character budget | **24,000 triangles / 24,000 glTF vertices** per character (`CHAR_MAX_TRIS`/`CHAR_MAX_VERTS`). |
| Frozen fallback | `npc_base` remains the low-poly fallback; it shares the 24,000/24,000 cap but is not required to use it. Do not silently lower the cap. |
| 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`
If MCP is available, use it for interactive part exploration only; mirror the result into a scripted change or local `.blend`, then re-export and run the CLI audit/fit gates. Never make the build, CI, tests or runtime depend on MCP. Setup: `docs/asset-tooling.md#optional-interactive-blender-mcp`.
### 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 24,000/24,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.
- `docs/asset-tooling.md#optional-interactive-blender-mcp` — optional MCP installation, connection, safety and
part-workflow instructions.
- [`references/verification.md`](references/verification.md) — command matrix,
capture gates, expected results and acceptance criteria.
## Do not
- Make the build, CI, tests or runtime depend on MCP, Blender or API calls.
- 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,141 @@
# 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 required contract skeleton has 13 core bones:
```text
Head, Spine, Neck,
HipL, HipR,
KneeL, KneeR,
ShoulderL, ShoulderR,
ElbowL, ElbowR,
HandL, HandR
```
Optional extra bones (fingers, face controls, toes) are allowed if they do not
move these core rest positions and do not break `NpcAvatar`'s animation proxies.
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 |
| --- | --- |
| Character (library and base fallback) | 24,000 triangles / 24,000 glTF 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,130 @@
# 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 |
| Part GLB (local) | `flatpak run org.blender.Blender --background --python "$PWD/tools/npc_parts.py" -- inspect --file "$PWD/tmp/npc-parts/<variant>/<part>.glb"` | measurements; a part GLB is not a shipped asset |
| 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
The part pipeline (`tools/npc_parts.py`) builds/extracts head/face/hand parts under
`tmp/npc-parts/<variant>/`; these are local working files and are **not shipped**. Only the
assembled character GLBs, AO/maps, the manifest and the review sheets are committed. An
assembled GLB still goes through `blender_assets.py inspect`/`audit`/`fit` before any part is
accepted. The `npc_base.blend` fallback is frozen: never save prototype detail into it.
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.
+254
View File
@@ -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/release-qa.md` — manual QA matrix and balance protocol.
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/ui-copy.md#screen-design-judge-report` 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.
+27 -20
View File
@@ -17,12 +17,13 @@ jobs:
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Install Godot 4.3 - name: Install Godot 4.7.2
run: | run: |
curl -sL -o /tmp/godot.zip \ curl -sL -o /tmp/godot.zip \
https://github.com/godotengine/godot/releases/download/4.3-stable/Godot_v4.3-stable_linux.x86_64.zip https://github.com/godotengine/godot/releases/download/4.7.2-stable/Godot_v4.7.2-stable_linux.x86_64.zip
unzip -qo /tmp/godot.zip -d /tmp/godot-bin unzip -qo /tmp/godot.zip -d /tmp/godot-bin
sudo install /tmp/godot-bin/Godot_v4.3-stable_linux.x86_64 /usr/local/bin/godot sudo install /tmp/godot-bin/Godot_v4.7.2-stable_linux.x86_64 /usr/local/bin/godot
godot --version
- name: Import project (build class cache) - name: Import project (build class cache)
run: godot --headless --import run: godot --headless --import
@@ -56,18 +57,24 @@ jobs:
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Install Godot 4.3 and export templates - name: Install Godot 4.7.2 and export templates
run: | run: |
curl -sL -o /tmp/godot.zip \ curl -sL -o /tmp/godot.zip \
https://github.com/godotengine/godot/releases/download/4.3-stable/Godot_v4.3-stable_linux.x86_64.zip https://github.com/godotengine/godot/releases/download/4.7.2-stable/Godot_v4.7.2-stable_linux.x86_64.zip
unzip -qo /tmp/godot.zip -d /tmp/godot-bin unzip -qo /tmp/godot.zip -d /tmp/godot-bin
sudo install /tmp/godot-bin/Godot_v4.3-stable_linux.x86_64 /usr/local/bin/godot sudo install /tmp/godot-bin/Godot_v4.7.2-stable_linux.x86_64 /usr/local/bin/godot
godot --version
TEMPLATE_DIR="$HOME/.local/share/godot/export_templates/4.7.2.stable"
NEEDED="version.txt icudt_godot.dat linux_release.x86_64 windows_release_x86_64.exe macos.zip web_nothreads_release.zip web_dlink_nothreads_release.zip"
curl -sL -o /tmp/templates.tpz \ curl -sL -o /tmp/templates.tpz \
https://github.com/godotengine/godot/releases/download/4.3-stable/Godot_v4.3-stable_export_templates.tpz https://github.com/godotengine/godot/releases/download/4.7.2-stable/Godot_v4.7.2-stable_export_templates.tpz
mkdir -p ~/.local/share/godot/export_templates/4.3.stable rm -rf /tmp/tpl && mkdir -p /tmp/tpl
cd /tmp && rm -rf tpl && mkdir tpl && unzip -qo templates.tpz -d tpl unzip -qo /tmp/templates.tpz -d /tmp/tpl
cp tpl/templates/* "$HOME/.local/share/godot/export_templates/4.3.stable/" 2>/dev/null || true mkdir -p "$TEMPLATE_DIR"
ls "$HOME/.local/share/godot/export_templates/4.3.stable" | head -5 for file in $NEEDED; do
cp "/tmp/tpl/templates/$file" "$TEMPLATE_DIR/$file"
done
ls "$TEMPLATE_DIR" | head -10
- name: Import project - name: Import project
run: godot --headless --import run: godot --headless --import
@@ -84,19 +91,19 @@ jobs:
# NOTE: on Linux, makensis uses -D defines (the /D form is Windows-only # NOTE: on Linux, makensis uses -D defines (the /D form is Windows-only
# and is rejected as a script path), and it resolves relative paths # and is rejected as a script path), and it resolves relative paths
# against the script directory — pass absolute paths from the workspace. # against the script directory — pass absolute paths from the workspace.
cp assets/textures/icon.ico packaging/windows/step-line.ico cp assets/textures/icon.ico packaging/windows/gig-line.ico
makensis \ makensis \
-DVERSION="$VERSION" \ -DVERSION="$VERSION" \
-DARTIFACT="$PWD/build/step-line-windows-$VERSION.exe" \ -DARTIFACT="$PWD/build/gig-line-windows-$VERSION.exe" \
-DICON="$PWD/packaging/windows/step-line.ico" \ -DICON="$PWD/packaging/windows/gig-line.ico" \
-DOUT="$PWD/build/step-line-setup-$VERSION.exe" \ -DOUT="$PWD/build/gig-line-setup-$VERSION.exe" \
packaging/windows/step-line.nsi packaging/windows/gig-line.nsi
- name: Verify Windows installer contents - name: Verify Windows installer contents
run: | run: |
VERSION="$(sed -n 's/.*config\/version="\([^"]*\)".*/\1/p' project.godot)" VERSION="$(sed -n 's/.*config\/version="\([^"]*\)".*/\1/p' project.godot)"
ls -la build/step-line-setup-$VERSION.exe ls -la build/gig-line-setup-$VERSION.exe
7z l build/step-line-setup-$VERSION.exe | grep -E "step-line.exe|uninstall.exe" 7z l build/gig-line-setup-$VERSION.exe | grep -E "gig-line.exe|uninstall.exe"
- name: Package Linux AppImage - name: Package Linux AppImage
run: | run: |
@@ -106,7 +113,7 @@ jobs:
if: github.event_name == 'workflow_dispatch' if: github.event_name == 'workflow_dispatch'
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
with: with:
name: step-line-build name: gig-line-build
path: build/* path: build/*
if-no-files-found: error if-no-files-found: error
@@ -114,7 +121,7 @@ jobs:
if: startsWith(github.ref, 'refs/tags/') if: startsWith(github.ref, 'refs/tags/')
env: env:
# An explicit repo secret wins. Without one, publish_release.sh reuses # An explicit repo secret wins. Without one, publish_release.sh reuses
# the local git extraheader that actions/checkout configures for the job # the local git extraheader that actions/checkout configures on the job
# (the runner's own credentials), so tag builds still publish. # (the runner's own credentials), so tag builds still publish.
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
VERSION: ${{ github.ref_name }} VERSION: ${{ github.ref_name }}
+48
View File
@@ -37,6 +37,7 @@ Thumbs.db
*.new *.new
# Logs and temp # Logs and temp
tmp/
*.log *.log
user:// user://
# CI runner workflow logs (written into the checkout by the Gitea runner) # CI runner workflow logs (written into the checkout by the Gitea runner)
@@ -44,3 +45,50 @@ user://
build/ build/
.env .env
# AI / asset-development outputs (regenerated by the tools; not shipped in the game)
assets/models/concepts/
assets/models/npc/*.blend1
assets/textures/npc/ai/
assets/textures/ai/*
!assets/textures/ai/game_ready/
# Godot extracts embedded glTF textures next to the source on import
assets/models/generated/npc_base_*_albedo.png
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.
docs/blender_previews/*.png
assets/models/blender/**/*.png
!assets/models/blender/**/*_ao.png
assets/models/blender_src/*.blend1
# Editable Blender sources are developer-only; keep the .gdignore marker tracked.
assets/models/blender_src/*.blend
# Realism pass (tools/scene_concepts.py): candidate pools, per-run captures and
# generated reports stay local; validated picks are tracked under
# game_ready/v2/picks/ (ADR-0014). Concept references are committed in
# docs/screens/concepts/, but generated QA lives outside the repository.
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
+215 -18
View File
@@ -14,6 +14,106 @@ The project should be developed in small, reviewable steps. Agents must keep pla
- `MEMORY.md` — Persistent session memory for important decisions, discoveries, unresolved questions, constraints, and useful implementation context. - `MEMORY.md` — Persistent session memory for important decisions, discoveries, unresolved questions, constraints, and useful implementation context.
- `README.md` — Root-level documentation for the project. It should explain what the game is, how to work on it, how to run it, and where to find project information. - `README.md` — Root-level documentation for the project. It should explain what the game is, how to work on it, how to run it, and where to find project information.
- `AGENTS.md` — This collaboration and agent workflow guide. - `AGENTS.md` — This collaboration and agent workflow guide.
- `CHANGELOG.md` — The version history of user-facing changes. Keep an entry for each patch, minor, and major version.
- `docs/development-status.md` — The implemented-features list and what is not yet implemented. Update it whenever a feature lands, is renamed, or is removed.
- `docs/architecture.md` — The arc42-style architecture documentation (goals, constraints, building blocks, runtime views, decisions, risks).
- `docs/gameplay.md` — Gameplay systems, tutorial, venues and the escalation model.
- `docs/venues.md` — Real-site evidence, game mapping and venue simplifications.
- `docs/asset-tooling.md` — Asset pipelines, model tools, optional Blender MCP and screenshot gates.
- `docs/blender-assets.md` — Blender library operation and asset roles.
- `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/release-qa.md` — The manual smoke checklist and balance-acceptance protocol.
- `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, five tint slots, front on Blender −Y /
Godot +Z, grounded feet, 24,000 triangles / 24,000 glTF vertices per character, 1,500 per
gear, 4,000 per prop. The shipped procedural library uses the 13 required core bones at their
rest positions; optional extra bones (fingers, face, toes) are allowed if they do not move the
core rest positions. The one documented exception is the accepted Quaternius runtime path
([ADR-0018](docs/adr/0018-quaternius-stage2-runtime-rig.md)): it keeps the 62-joint source rig
at runtime while the 0.9.9 face/silhouette gate is open, and it must still supply the five tint
slots, valid gear attach points and the same budgets. Both paths stay tested until that gate
closes. 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. **Blender MCP is optional interactive tooling.** The headless flatpak scripts
(`tools/blender_assets.py`, `tools/npc_pipeline.py`) remain authoritative. MCP may be used
for local part exploration; setup and safety are in [`docs/asset-tooling.md#optional-interactive-blender-mcp`](docs/asset-tooling.md#optional-interactive-blender-mcp).
Never add an MCP dependency to the build, CI, tests or runtime, and always re-run the CLI
audit/fit gates on anything MCP touched.
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-0017 (the CC0 Quaternius NPC base) supersedes the generator-first
decision in ADR-0015, and the CC0/CC-BY rule in ADR-0015 (attribution in `CREDITS.md`) plus
the provenance rules in `docs/npc-model-sourcing.md` still apply to any new source.
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 ## Required Workflow
@@ -36,9 +136,22 @@ Do not assume that a task is unimplemented without checking the code and documen
All planned implementation work must be represented in `TODO.md`. All planned implementation work must be represented in `TODO.md`.
- Use headings to group related work into sections. - Use headings to group related work into sections.
- Use checkbox items for each concrete task. - 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.
- 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. - Keep tasks small enough to complete and review independently.
- Add new tasks when discoveries expand the scope. - Add new tasks when discoveries expand the scope.
- When starting a task, claim it for the agent workflow by changing `[ ]` to `[-]`. Keep it `[-]`
while implementation or verification is in progress; only change it to `[x]` after the work and
relevant checks are finished. If work is abandoned or blocked, leave a clear note and return the
item to `[ ]` (or add a follow-up task).
- Mark a task complete only after the implementation and relevant verification are finished. - Mark a task complete only after the implementation and relevant verification are finished.
- If any verification check fails, do not mark the task complete. Fix the failure, or if it cannot be fixed, add a follow-up task to `TODO.md`, record the failure in `MEMORY.md`, and report it in the handoff summary. - If any verification check fails, do not mark the task complete. Fix the failure, or if it cannot be fixed, add a follow-up task to `TODO.md`, record the failure in `MEMORY.md`, and report it in the handoff summary.
- Do not use prose status updates as a substitute for checkboxes. - Do not use prose status updates as a substitute for checkboxes.
@@ -49,27 +162,53 @@ Recommended format:
```md ```md
# TODO # TODO
## Core Gameplay ## Milestone X.Y.Z — goal and exit criterion
- [ ] Add player movement controls. ### Workstream A
- [ ] Implement NPC approach behavior.
- [x] Define escalation levels.
## Documentation - [x] Completed task.
- [-] Task in progress. (claimed; implementation/verification in progress)
- [ ] Open task.
- [ ] Document the test procedure in `README.md`. ### Workstream B
- [ ] Another task.
**Exit:** a verifiable statement of what "done" means for the milestone.
## Theme
- [ ] 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` ### 3. Move Completed Sections to `DONE.md`
When every task in a `TODO.md` section is complete: `TODO.md` uses nested sections. Apply these completion rules:
1. Verify the work and update the checkbox items to `[x]`. 1. **Level-3 workstream:** verify the work, mark every checkbox `[x]`, and add a short completion
2. Move the entire completed section, including its heading and checklist, to `DONE.md`. note. Leave the completed workstream under its parent milestone; do not move an isolated
3. Remove that section from `TODO.md`. level-3 section to `DONE.md`.
4. Add a short completion note or date when useful. 2. **Level-2 milestone/theme:** it is complete only when its direct checkboxes and **all** of its
level-3 workstreams are complete. Verify the whole milestone, record its capabilities in
`docs/development-status.md` when it represents shipped functionality, and write the matching
`CHANGELOG.md` entry.
3. Move the **entire level-2 section**, including all level-3 headings and checklists, to
`DONE.md`. Remove it from `TODO.md` and add a completion date/note.
4. **Planning/overview sections** such as a gap analysis, roadmap overview, dependencies or
deferred ideas are not completion milestones. Do not move them merely because their checkboxes
are empty or complete; update or supersede them as the roadmap changes.
5. Do not move partially completed milestones. Leave them in `TODO.md` until every nested task is
complete, or split the unfinished work into a new smaller level-2 milestone first.
Do not move partially completed sections. Leave them in `TODO.md` until all of their tasks are complete, or split the section into smaller sections first. When a completed milestone represents shipped functionality, also record the new capability in
`docs/development-status.md` so the implemented-features list stays accurate, and write a matching
entry in `CHANGELOG.md` (see "Maintain `CHANGELOG.md`" below).
### 4. Maintain `MEMORY.md` ### 4. Maintain `MEMORY.md`
@@ -78,7 +217,7 @@ Use `MEMORY.md` for information that should persist between sessions but does no
Record items such as: Record items such as:
- Important design and architecture decisions - Important design and architecture decisions
- Current implementation state - Notable implementation state and gotchas (the canonical implemented-features list lives in `docs/development-status.md`, not here)
- Known bugs and workarounds - Known bugs and workarounds
- Commands needed to run, test, or build the project - Commands needed to run, test, or build the project
- Decisions that future agents should not revisit unnecessarily - Decisions that future agents should not revisit unnecessarily
@@ -128,9 +267,29 @@ The root-level `README.md` is the project’s public-facing technical and projec
- Links to `PLAN.md`, `TODO.md`, `DONE.md`, `MEMORY.md`, and this file where appropriate - Links to `PLAN.md`, `TODO.md`, `DONE.md`, `MEMORY.md`, and this file where appropriate
- Known limitations and contribution guidance - Known limitations and contribution guidance
Update `README.md` whenever setup instructions, commands, project structure, or user-facing behavior changes. Update `README.md` whenever setup instructions, commands, project structure, or user-facing behavior changes. The README is intentionally concise and links to the `docs/` files; keep `docs/development-status.md` (and the other docs it links to) synchronized with the implementation rather than pasting detail back into the README.
### 7. Implement in Small Increments ### 7. Maintain `CHANGELOG.md`
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 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` 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`:
1. Verify the work and mark every checkbox in the section `[x]`.
2. Use the section heading and its completed items to describe the changes and write a `CHANGELOG.md` entry under the next appropriate version.
3. Move the section to `DONE.md`.
Do not move a completed section to `DONE.md` without adding its `CHANGELOG.md` entry.
### 8. Implement in Small Increments
For each task: For each task:
@@ -138,12 +297,44 @@ For each task:
2. Inspect the relevant files and dependencies. 2. Inspect the relevant files and dependencies.
3. Make the smallest coherent change that completes the task. 3. Make the smallest coherent change that completes the task.
4. Run the relevant tests, checks, or manual verification. 4. Run the relevant tests, checks, or manual verification.
5. Update documentation and `MEMORY.md` if the change creates lasting context. 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. 6. Mark the task complete.
7. Move its section to `DONE.md` when the entire section is 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 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. 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 ## Collaboration Rules
- Prefer clear, reversible changes over broad rewrites. - Prefer clear, reversible changes over broad rewrites.
@@ -152,6 +343,8 @@ Avoid unrelated refactors unless they are required for the task or explicitly ap
- Do not claim a task is complete without verification. - Do not claim a task is complete without verification.
- Keep documentation synchronized with the implementation. - Keep documentation synchronized with the implementation.
- Mention files changed and checks run in handoff summaries. - 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. - 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`. - 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. - Avoid overwriting another contributor’s work; inspect recent changes before editing shared files.
@@ -163,6 +356,10 @@ Before handing off work, an agent must run every check below that applies to the
- Run automated tests. - Run automated tests.
- Run formatting, linting, or type checks. - Run formatting, linting, or type checks.
- Start the game or application and perform a basic smoke test. - 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. - Check that documentation and task status reflect the actual state.
- Review the final diff for accidental changes or unfinished markers. - Review the final diff for accidental changes or unfinished markers.
+604
View File
@@ -0,0 +1,604 @@
# Changelog
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.
## [Unreleased]
## [0.9.9] — 2026-11-06
### Changed
- Raised the character mesh budget from 16,000 to 24,000 triangles and glTF
vertices so the Quaternius base and the role-dressed variants fit without
heavy decimation. Gear and prop budgets are unchanged.
- Replaced the whole NPC roster with the CC0 Quaternius characters. All twelve
characters (tourist, jacket, coat, vest, dress, hoodie, firefighter, guard and
the four crowd variants) now use one of three source outfits — casual tee,
hoodie or work clothes — dressed by role with the five tint slots and the gear
library. The procedural library and the MakeHuman head remain in the build as
the fallback.
- Characters stand with their arms down instead of a T/A pose, and the seated,
idle and walking poses swing from the shoulder and hip the way the animation
code intends on the new skeleton.
- Head gear (cap, hood, sunglasses, firefighter helmet) and the camera were
resized for the new head and arm. The camera now hangs from a wrist strap
instead of a neck strap that floated next to the head.
- The backpack straps were pulled in so they sit on the chest instead of
hovering in front of it.
### Fixed
- Characters no longer render with black legs or black patches: the new base
carried a collapsed UV map that made the ambient-occlusion bake come out
black, and the roster is now unwrapped and baked correctly.
## [0.9.8] — 2026-11-04
### Fixed
- Characters no longer detach at the wrist: the wrist and hand now track the same
bone, the hand was raised to meet the forearm, and the sleeve cuff follows the
hand instead of the elbow.
- Seated and walking poses no longer collapse the hip/thigh or pinch the knee:
the thigh and shin are rigid to their bones with a short blend at the knee.
## [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
- Prepared the release-candidate packages for Linux, Windows, macOS, Web and the
optional Desktop HQ zip. The Web/HQ archives now include the credits, privacy,
accessibility and known-limitations pages, and release publishing writes
SHA-256 checksums and rolls back partial uploads.
### Fixed
- Corrupt or partial save files now fall back to safe defaults without logging a
parse error, and a failed atomic replace leaves the previous valid settings
intact. Added migration coverage for 0.8-era profiles and 0.9.0 checkpoints
across all three venues.
## [0.9.6] — 2026-11-02
### Changed
- The UI, model and texture passes are now integrated into a verified checkpoint
build. The gallery, NPC portraits, realism captures, asset audits, smoke
matrix, 24-NPC budget and Web/Desktop HQ packages were regenerated and
re-checked; no gameplay or content changes were introduced.
## [0.9.5] — 2026-11-02
### Changed
- NPC albedo, normal and ORM maps are now 256² instead of 128², giving the
face, fabric and gear materials more detail at portrait distance.
- NPC fabric maps now repeat four times across the body and skip the baked
per-character AO, removing the large blotchy patches from shirts, jackets and
trousers at portrait distance.
- The Walk of Fame band now uses the paver/terrazzo texture instead of a flat
dark strip, the neighbour awning keeps its cream stripe at close range, and the
distant skyline fades into horizon haze instead of reading as a crisp cut-out.
## [0.9.4] — 2026-11-02
### Changed
- Character meshes now have an 8,000-triangle / 8,000-vertex library budget
(up from 6,000 / 5,000) to support the remaining face, grip and clothing
detail; the `npc_base` fallback keeps its original 6,000 / 4,000 contract.
- Character necks are fuller and shoulders slope from the neck instead of
reading as a thin post on a hanger.
- Character eyes sit in the socket behind a thin upper lid, and the chin and
cheekbones are sculpted into the head instead of reading as separate spheres.
- Character torsos taper from the chest to the waist and flare slightly into
the hips, so shirts and jackets sit less like straight tubes.
- Character hands now have a wider palm, bent fingers with rounded tips and a
separate thumb instead of flat bars.
- Character noses gained ala wings and a smaller bridge/tip, the mouth is a
rounded slot, and the ears have a darker inner concha.
- Hand-held items now sit forward in the open palm instead of being partly
buried inside the hand.
- Shoes and responder boots now have rounded toes and heels instead of reading
as flat blocks.
### Fixed
- Tourists no longer appear to carry two backpacks: the photo-pose camera bag is
hidden except while they are actually taking a picture.
- Backpack shoulder straps are now flattened bands that sit outside the chest
instead of thin rods partly buried in the torso.
## [0.9.3] — 2026-11-02
### Added
- Eight committed gallery captures now cover the start menu, pause, settings,
shift review, emergency radio, action wheel, crowd panic and responder
arrival, so every screen-design reference has a deterministic current-build
capture.
### Changed
- All session, settings, radio, Help, review and timeline action buttons now
share explicit normal, hover, pressed, focus and disabled styles. Timeline
Previous/Next disable at their boundaries.
- Keyboard and gamepad focus rings now wrap through every modal, with explicit
default focus and A/B accept/cancel bindings; hidden Continue and disabled
timeline controls are skipped.
- Esc and right-click now close the top panel consistently, restore the venue
menu after menu Settings, and recapture the mouse without leaving the guard
frozen. Help no longer opens Pause behind itself.
- The HUD target chip grows and caps with the selected font scale, top labels
clip safely, and long action-button labels ellipsize instead of pushing panels
wider than the screen.
- Campaign reset and tutorial replay now share a guarded confirmation dialog;
repeated presses cannot stack dialogs or fire the action twice. Emergency
hold-to-send still submits once and ignores the release after submission.
- NPC reason answers now use role-specific dialogue contexts, so staff, guests,
delivery workers, performers and other archetypes answer instead of silently
deflecting the Reason verb.
- Hollywood and the TV Studio now have door-staff lines for their wristband,
ticket, credential and guest-list checks.
- Clarified the emergency radio cancellation message, the Ask verb in Help/HUD
hints, the start-menu key hint and the campaign-reset confirmation.
## [0.9.2] — 2026-11-02
### Added
- A stylized reconstruction of the real El Capitan Entertainment Centre block at
6840 Hollywood Boulevard: six Ionic columns, eight stone steps, the Masonic
parapet motto and medallions, red event banners, central and side entrances,
the El Capitan Theatre and retail neighbours, the Ovation Hollywood arcade,
the Walk of Fame and four-lane street markings.
- Real-site reference notes and AI art-direction frames for the Hollywood block.
- The Joke Shop is now a Sunset Strip comedy-club block based on The Comedy Store at
8433 Sunset Blvd: a 27 m black hall under a signature-covered canopy, a circular
**THE JOKE SHOP** blade sign, red velvet curtain bays, a west-end entrance, cream
and white neighbours, a dry hillside of stucco houses and palms, and a low retail
and billboard frontage across Sunset.
- Real-site reference notes and AI art-direction frames for the Joke Shop block,
including day, night and across-the-street concepts.
- A separate day capture stage for the Joke Shop, so the club can be compared in
both lighting states.
- Completed the UI string migration: start menu, settings, pause, Help, HUD,
radio and shift-review labels now come from the English string table.
- Separate **Hollywood Boulevard — Day** and **Hollywood Boulevard — Night**
rows in the venue menu. Night starts directly in the late phase and keeps the
full shift after dark.
### Changed
- The default Hollywood venue is no longer a generic brick entrance; the venue
name and policy copy now identify the El Capitan Entertainment Centre.
- Night lighting on the landmark uses low-energy practical washes rather than
the street-lamp brightness, so the facade reads without blowing out.
- The Joke Shop lighting now uses warm sconces, canopy downlights and ground
uplights; the hillside stays a dark silhouette at night instead of a lit wall.
- The Joke Shop venue copy and gallery captions describe the Sunset Strip block,
not the old brick alley.
### Fixed
- The Ovation Hollywood sign faces the boulevard instead of rendering mirrored.
- Local night lights use linear attenuation instead of constant falloff, so
sconces and street lamps pool on the ground and stone rather than washing the
whole facade flat and yellow.
- The captured HUD clears stale objectives and target prompts between staged
screenshots.
- The Joke Shop beauty capture closes a stale wand/inspection panel before shooting
and frames the entrance and sign instead of a nearby target.
- Multiline HUD and wand strings now render real line breaks instead of a literal
`\n`; the wand panel also lists the guest's carried items.
- Final-context NPC gear fit: authorized-guest lanyards now show their badge in
front of the jacket, and responder helmets sit above the eyes instead of across
the brow.
## [0.9.1] — 2026-11-02
### Changed
- Unified the project, local tooling and CI/release environment on Godot 4.7.2,
including matching export templates and project feature metadata.
- Evaluated Gitea Actions cache for the Godot binary/templates; disabled it after
cache saves timed out or were rejected, pending a healthy host cache service.
- Updated release and setup documentation for the 4.7.2 baseline.
## [0.9.0] — 2026-11-01
### Added
- Master/SFX/ambience volume controls, a captions toggle and a Reduce motion
option in Settings.
- A 24-NPC performance budget smoke and expanded audio/accessibility coverage.
- Explicit production-quality scope for animation, audio, localization and the
Godot 4.3-CI/4.7-local support matrix.
### Changed
- Coat and dress strides are shortened to reduce hem/leg clipping.
- Help and the shift-review surface expose the current policy and accessibility
settings.
### Fixed
- Audio cue volumes now respect the player's mixer settings while remaining
headless-safe.
## [0.8.1] — 2026-11-01
### Fixed
- Normal radio reports now send on click. The button was wired only to the
emergency hold-to-confirm handlers, so a non-emergency press did nothing.
## [0.8.0] — 2026-11-01
### Added
- A first-shift tutorial with contextual prompts, a safe visitor and replay/skip.
- A three-venue campaign shell with shift progression and a Continue action.
- Resume-from-checkpoint for paused shifts, including NPC, incident and system state.
- Easy/normal/hard difficulty presets for spawn pacing, compliance tolerance and
report strictness.
- A searchable in-game Help overlay with controls and the current venue policy.
- Recovery events, contextual NPC dialogue and an eligible-event debug preview.
### Changed
- The shift review now includes venue policy, campaign next steps and continued
review controls.
- Event scheduling suppresses recently played scripted events and respects the
difficulty spawn multiplier.
- Save data is written atomically and split into settings, campaign, shift
history and versioned checkpoint files.
### Fixed
- Missing/older settings migrate through defaults; a partial write cannot
replace a valid save.
- The HUD debug overlay now refreshes and shows the next eligible events.
## [0.7.3] — 2026-11-01
### Fixed
- Mouse look now reads relative motion at the `_input` stage, so a full-screen
HUD or focused control cannot swallow it while the cursor is captured.
- Mouse capture is restored after window/compositor focus returns, and clicking
back into a gameplay window recaptures it instead of opening the radial menu.
- The HUD is mouse-transparent; its presentation controls no longer block
gameplay mouse input.
## [0.7.2] — 2026-11-01
### Added
- Automatic OpenRouter model selection for the screenshot judges: the cheapest
currently available image+JSON-capable model is used, with ordered fallbacks
and a pinned `GIG_LINE_JUDGE_MODEL`/`--model` override.
### Changed
- The judge reports the model that produced each verdict and fails clearly on an
invalid API key instead of retrying other models.
- The screen-design and realism reports now include the fresh judge results.
### Fixed
- The blocked screenshot judge now runs with the valid `OPENROUTER_API_KEY`
(`13/13` screen designs match, `0` diff).
## [0.7.1] — 2026-11-01
### Added
- An optional Desktop HQ build for Windows and Linux that uses Forward+,
volumetric fog and SDFGI, packaged with an `override.cfg` beside the
executable.
- Volumetric flashlight haze in the Desktop HQ build, with a LATE-phase preset
tuned so the entrance facade stays readable.
### Changed
- The normal Compatibility build remains the default; the preset only affects
the extracted Desktop HQ copy.
- Night-time light falloff adapts to Godot 4.7 while keeping the 4.3 baseline
unchanged.
### Fixed
- The flashlight no longer disappears at night on Godot 4.7 under the old
attenuation curve.
- Headless and Web builds stay non-volumetric and boot normally when Forward+
is unavailable.
## [0.7.0] — 2026-11-01
### Added
- Distinct venue geometry: the Joke Shop is now a narrow brick alley with a
shuttered facade, warm wall lantern, dumpster and AC clutter; the TV Studio
has a stone facade, bulb-lit canopy, glossy black car and a stanchion/barrier
line at the door.
- The README gallery includes captured Joke Shop and TV Studio views.
### Changed
- Venue geometry is data-driven through `WorldBuilder.VENUE_SPECS`; switching
venues rebuilds the world while keeping the guard and UI intact.
- Each venue has its own navigation bounds and concept-gallery mapping.
### Fixed
- The Joke Shop no longer renders the Hollywood skyline or marquee.
- The TV Studio no longer uses the boulevard marquee or palm-lined layout.
## [0.6.1] — 2026-11-01
### Added
- Per-phase AI skyline panoramas (day, dusk, night) replacing the flat box skyline.
- Higher-detail surface textures with normal maps (brick, concrete, asphalt, awning, and more).
- A runtime image root (`assets/images/`) with a UI and scene art loader; the start menu,
pause, settings, shift review, radio, wand, inspection, and radial menu are styled against
their mockups.
- NPC face and hand detail: eyes, nose, lips, ears, fingered hands, and cuffed sleeves.
- A staged NPC portrait capture for judging avatar quality up close.
- Gear-fit checks (`tools/blender_assets.py fit`) and regression tests for head and back gear.
### Changed
- Scene lighting, fog, sun angle, and night glow retuned to match the AI concept frames;
the Late phase uses wet asphalt.
- The flashlight is a tighter forward spot that reads in the dark.
- Sunglasses narrowed to sit inside the face silhouette; shoulder bag moved clear of the
coat and dress skirts; firefighter helmet lifted off the brow.
- The README now links to focused docs pages for gameplay, architecture, setup, asset
tooling, development status, and the manual smoke checklist; `PLAN.md` was compacted
into a design plan.
### Fixed
- Sidewalk overexposure at the entrance reduced to match the concept target.
- The body-camera overlay no longer overlaps the shift/reputation/crowd status.
- Selecting a venue releases the menu input lock and recaptures the mouse.
- The shoulder bag no longer clips through the coat's skirt; the firefighter helmet no
longer cuts into the brow ridge; the portrait subject now faces the camera.
- `--portrait-type` is now parsed and applied instead of being ignored.
## [0.6.0] — 2026-11-01
### Added
- Blender-authored character, gear and prop library with baked ambient occlusion.
- Higher-resolution environment textures with tangent normal maps.
- Phase-driven emissive details on library props, characters and street dressing.
### Changed
- The game was renamed from "Step Line" to "Gig Line".
### Fixed
- NPCs now face their movement direction instead of walking backwards.
## [0.5.0] — 2026-11-01
### Added
- Articulated NPC characters with layered outfits, hand items, face/hair variety,
idle behaviour, reaction symbols, queue offsets and three LOD tiers.
- Player acceleration/braking, step-up assist, head bob, landing dip,
precision-walk feedback and surface-aware footsteps.
- Remappable keyboard and gamepad controls.
### Changed
- Crowd roles now select deterministic character variants and props.
## [0.4.0] — 2026-11-01
### Added
- Collision and navigation footprints for every street prop.
- Zoned prop placements with deterministic variants and small clutter.
## [0.3.3] — 2026-11-01
### Added
- Staged in-game captures for the wand screening, escalation HUD, and body-camera timeline screens.
## [0.3.2] — 2026-11-01
### Added
- AI reference mockups for the seven remaining catalogue screens.
## [0.3.1] — 2026-10-31
### Added
- Prop models drawn with a single texture atlas (one material per prop).
### Changed
- The Web build is listed in the README downloads table.
## [0.3.0] — 2026-10-31
### Added
- Surface-material profiles, ACES tonemapping, glow, aerial fog and phase-based
colour grading.
- Framed facade windows, door trim, curb and lane markings.
- Generated street-furniture models and the Web export.
- Aim-free targeting, a focus cone and precision walk.
## [0.2.16] — 2026-10-31
### Added
- Venues authorable as editor `.tres` resources.
## [0.2.15] — 2026-10-31
### Added
- A vision-model judge for comparing screenshots against reference designs.
## [0.2.14] — 2026-10-31
### Added
- Anonymous release downloads enabled on the host.
### Fixed
- `Strings.fmt` keeps positional placeholders stable when new keys are added.
## [0.2.13] — 2026-10-31
### Added
- Missing scenario content: Joke Shop reservation/ID cases, wand refusal and late
arrival events, the studio filming-boundary repeat, and a celebrity-arrival crowd spike.
## [0.2.12] — 2026-10-31
### Fixed
- Release uploads fail loudly instead of leaving an empty release with a green job.
- Pruned releases restored and CI publishing verified end to end.
## [0.2.11] — 2026-10-31
### Fixed
- Releases publish using the runner's checkout credentials when no token or git
credentials exist.
## [0.2.10] — 2026-10-31
### Fixed
- Release publishing fixed with a CI token fallback.
## [0.2.9] — 2026-10-31
### Added
- Accessibility pass: escalation feedback that reads in grayscale and a working HUD font scale.
## [0.2.8] — 2026-10-31
### Added
- Procedural crowd ambience that rises with crowd mood, and a radio crackle.
## [0.2.7] — 2026-10-31
### Added
- NPC theater poses: sitting, taking photos, filming, and performing.
## [0.2.6] — 2026-10-31
### Added
- A body-camera timeline on the shift review for stepping through recorded events.
## [0.2.5] — 2026-10-31
### Added
- Emergency aftermath: evacuation clears the entrance, and unjustified calls write
an investigation note with a false-report reputation hit.
## [0.2.4] — 2026-10-31
### Added
- Crowd presentation: onlookers rubberneck at incidents and clear out during panic.
### Fixed
- NPC navigation issues resolved.
## [0.2.3] — 2026-10-31
### Added
- Remaining PLAN actions: eye contact, "I recognize this person", a formal-warning
body-camera flag, blocking that stations the guard in front of the door, and
requesting a reason for entry.
### Fixed
- A dead incident-recording path.
## [0.2.2] — 2026-10-31
### Added
- Session shell: startup menu with venue selection, pause overlay, settings
persistence, and a "run another shift" flow back to the menu.
- Control pass: focus cone, head ring, radial action menu, and named input actions.
### Fixed
- Release publishing now uploads the installer and AppImage.
## [0.2.1] — 2026-10-31
### Added
- Windows NSIS installer and Linux AppImage packaging; all exports embed the PCK.
- An AI texture generation mode in the asset pipeline.
### Fixed
- NSIS build fixed for Linux (absolute defines, space-free installed exe, BMP icon).
- Runtime hygiene: RefCounted cycle cleanup, full-length shifts, and a wand cooldown.
## [0.2.0] — 2026-10-31
### Added
- First playable build of the security-guard simulation at the Hollywood Boulevard entrance.
- Core simulation: shift coordination, venue scenarios, event scheduling, NPC movement
and states, and escalation from observation through deterrence, warnings, and blocking.
- Access verification for wristbands, IDs, tickets, credentials, and guest lists, with
admit/redirect/hold/refuse decisions and feedback scoring.
- Escalation levels 0–5 with radio assistance and a hold-to-confirm emergency call.
- Incident recording, body-camera evidence, reputation scoring, crowd reactions, and
an end-of-shift review.
- Scenario content for Hollywood Boulevard, The Joke Shop, and the TV Studio, including
a mental-health crisis event.
- A protester NPC, the "call someone else" reaction, a lockable door, and a flashlight.
- Save/persistence, navmesh pathfinding, and JSON localization.
- Visual polish: phase lighting, street lamps, marquee, street dressing, and NPC variety.
- Detailed graphics: authored textures, a humanoid NPC rig, and HUD/inspection feedback.
- Downloadable Linux, Windows, and macOS builds published by CI.
### Removed
- The dialogue tone-of-voice picker (reactions now depend on escalation level and NPC profile).
+127
View File
@@ -0,0 +1,127 @@
# Credits and Provenance
Gig Line is a local, single-player security-shift game built with Godot 4 and
GDScript. This file records the asset provenance needed for the release review;
it is not a legal opinion or a claim that every provider licence has already
been cleared for public distribution.
## Game, code and design
- Game design, systems, scenarios, dialogue and UI code: the Gig Line project.
- Engine: [Godot Engine 4.7.2](https://godotengine.org/), MIT licence.
- The game bundles no third-party fonts; it uses Godot's default theme font.
- No third-party music, sound effects or voice recordings are bundled. Crowd
ambience and radio cues are generated procedurally at runtime.
## 3D characters, gear and props
The local MakeHuman head prototype uses the CC0 MakeHuman/MPFB base mesh
(see [`docs/makehuman-head-review.md`](docs/makehuman-head-review.md)); it is a
development prototype, not a shipped character.
The character, gear and prop library is generated by project-owned scripts
(`tools/blender_assets.py`, `tools/npc_pipeline.py`, `tools/model_pipeline.py`)
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.
### MakeHuman head source
The standalone MakeHuman head prototype is derived from the MakeHuman / MPFB base
mesh, **CC0** (`assets/models/blender_src/makehuman_head.glb`; source
<https://static.makehumancommunity.org/makehuman.html>, MakeHuman base mesh,
CC0 1.0). It is cut, retopologised and re-weighted by project scripts; the exported
character GLBs remain project assets. The development source files were removed
from `tmp/` after the 2026-11-05 pivot to Quaternius. The head is retained as a
tested fallback, not the active NPC base. See ADR-0017 and
`docs/npc-model-sourcing.md`.
### Quaternius NPC base source
The active NPC base migration uses **Quaternius Ultimate Modular Characters** and
**Ultimate Modular Women** (CC0 1.0, <https://quaternius.com/>). The three
researched GLBs are development inputs and are not shipped directly; the baked,
retargeted character GLBs are project assets. See ADR-0017 and
`docs/npc-model-sourcing.md` for the decision, source hashes and rollout status.
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
with image-generation calls from the project's tooling. The default model slugs
recorded in the source are:
- `bytedance-seed/seedream-4.5` — `tools/generate_textures.py`
- `openai/gpt-5-image-mini` — `tools/asset_pipeline.py`,
`tools/model_pipeline.py`, `tools/scene_concepts.py` and
`tools/screen_designs.py`
- Judging/review calls use the model selected by `tools/openrouter_judge.py` and
are development-only; they do not ship in the game.
The prompts and generation workflow live in those tools. Per-file generation
metadata is not stored with every image, so the exact provider, model version and
generation date of each committed bitmap cannot be reconstructed from the
repository alone. Before a public 0.10.0 release, the provider terms and
commercial-use/redistribution rights for those generated outputs must be
reviewed and recorded. **This is a release blocker, not an assumed clearance.**
Reference photographs linked from the venue documents are hosted on Wikimedia
Commons and were used for proportion/material study only. They are not included
in the game or its release packages. If any future derivative asset copies a
reference more directly, its attribution and licence must be added here.
## Audio
All runtime audio is procedural (crowd bed, radio crackle and interface cues).
There are no external audio files, so there is no separate music/SFX licence to
clear. See `docs/accessibility.md` for caption and volume behaviour.
## Third-party names
The game is a work of fiction. Real place names and public references are used
for orientation and satire/stand-in geography; no real person, venue or brand
endorses the game. Review the storefront and trademark language before release.
+1689 -11
View File
File diff suppressed because it is too large. Load diff
+270 -297
View File
@@ -1,316 +1,289 @@
# MEMORY # MEMORY
Session memory for durable decisions, state, and gotchas. Keep concise, remove obsolete entries. Session memory for durable decisions, gotchas, and commands. Implementation history lives in
`DONE.md`, user-facing changes in `CHANGELOG.md`, the live task list in `TODO.md`, and the
canonical implemented-features list in `docs/development-status.md`.
## Decisions ## Decisions
- Engine: Godot 4.3 stable (official editor build, `~/.local/bin/godot`). The system's preinstalled `godot-runner` (4.7.2, Fedora) cannot load projects from arbitrary paths because it was compiled without path overrides; use the official editor binary instead. - **Local-only reference override (2026-11-03, owner):** development-only photo research ignores
- Language: GDScript. All cross-file references use explicit `preload()` constants (not `class_name` globals) so scripts compile in headless `--script` runs without the editor's class cache. the licence gate. Downloads live in `tmp/research/` (gitignored): DDG image search, street-view
- Test framework deviation: the project uses a custom minimal headless test runner (`src/test/test_runner.gd`) instead of GUT, because GUT needs the editor plugin. CI runs it with `--headless`. frames, neighbouring buildings — never committed, never shipped. Promotion into
- Eventing: no autoload signal bus. `ShiftCoordinator` owns an `EventBus` instance (`src/core/event_bus.gd`) passed to subsystems; subsystems emit only when a bus is assigned. Autoloads at parse time are unreliable under `--script`. `docs/screens/refs/` always passes the sidecar licence + privacy gate and `CREDITS.md`.
- Static signals are not available in Godot 4.3 GDScript ("Expected func or var after static") — do not use them. - **AI-assisted asset review loop (2026-11-04):** head/face shape decisions use a concept +
- GDScript lambdas capture local variables **by value**; mutating a captured local inside a lambda does not affect the outer variable. Use member functions for accumulators in tests. judge loop — generate a target concept (`generate_textures.generate_image`, Seedream) and use
- Shift length is the scenario's `shift_duration_s` (900 s in all three venues). Tests and the screenshot tool override elapsed time; they do not change the default. `tools/describe_image.py` as the vision judge, iterating until the judge's specific fixes
- RNG: NPC reactions and event scheduling are seedable for deterministic tests. converge. Review pages: `docs/screens/head-review/README.md`, `docs/3d-model-review.md`
§AI-driven head rework.
- **Project agent skills (2026-11-03):** two tracked skills live in `.agents/skills/`:
`gig-line-blender-asset-contract` and `gig-line-release-qa`. They are guidance only,
add no runtime dependency and are referenced from `tools/README.md`. The third-party
`blender-skills` pack remains gitignored.
- **TV Studio shares the Hollywood location (owner):** the Late Night TV Studio is the same El
Capitan Entertainment Centre block at 6840 Hollywood Blvd (which houses *Jimmy Kimmel Live!*),
restaged for a late-night arrival. `VENUE_SPECS["tv_studio"]` is a 30.0 m variant of the 29.6 m
Hollywood facade. One reference board serves both venues; never create a separate TV Studio board.
- **Jimmy Kimmel Live = starting point:** the Hollywood first shift and the TV Studio arrival both
begin at the El Capitan block. Stated in `docs/venues.md#hollywood-boulevard` and `docs/gameplay.md`.
- **Street-view limitation:** Google Street View panoramas need a Google API key or manual browser
capture, so the local reference sets use DDG street-level photos instead.
- **Image-recitation filter:** Gemini image models reject well-known branded facades (Comedy Store
wall) as generation anchors (`IMAGE_RECITATION`). Workaround: anchor on a less-branded frame of
the same block, or generate text-only when the reference adds no geometry.
- **OpenRouter image-to-image:** `/v1/images` is text-to-image only; the working path is
`POST /v1/chat/completions` with a `content` array carrying a base64 `image_url`. Response
images arrive as `message.images[].image_url.url` (fallback: a data URI inside the message text).
Implemented in `generate_textures.generate_image(reference_path=...)` and
`scene_concepts.py generate/anchor`; provenance sidecars are `.refgen.json`.
- **Facade/venue material picks (2026-11-03):** the Masonic/El Capitan facade uses the
photo-anchored `limestone_ashlar` field (warm tint `Color(0.85, 0.81, 0.74)`) with `stone_steps`
for trim; the Joke Shop uses `dark_stucco`; the marquee canopy/sign box stay `black_metal` by
design (fictional "GIG LINE" marquee, not the red El Capitan Theatre marquee next door). The
TV Studio reuses `masonic_facade`. Committed Comedy Store refs were removed in favour of the
local-only `tmp/research/comedy-store/` set; the three-up board's photo panel is a historical
public-domain frame.
- **Godot 4.7.2 `--import` gotcha:** with a stale `.godot/` cache, new image files never import
(no `.import` created) and `preload()` of the new texture fails every dependent script with the
misleading `Could not resolve external class member "spec"`. Fix: import in a scratch copy with
`.godot/` removed, then copy back the `.png.import` and `.godot/imported/*.ctex/.md5`.
- **Blender skills pack (local aid):** MIT `blender-skills` at `.agents/skills/blender-skills/`
(94 skills + shared `references/`), gitignored, kept out of Godot's scanner by
`.agents/.gdignore`. Keep the pack flat when updating (`cp -a <pack>/.claude/skills/. ...`).
Pi gates project `.agents/skills` behind project trust.
- **Gaussian splatting (unversioned):** offline/development-only until an ADR proves licence,
privacy, Compatibility/Web cost and mesh collision. Accepted photo channels: team captures,
permissioned user/volunteer photos, clearly licensed downloads; every set needs a
provenance/consent sidecar. No runtime splat dependency in 0.10.0.
- **0.10.0 balance protocol:** `docs/release-qa.md#balance-acceptance` defines targets/denominators for the
36 venue/difficulty/phase cells, seeds 1–100, and access/emergency error rates. Gotcha:
`_read_npc_truth()` is type-derived, not behaviour-derived; the emergency-fairness review must
account for that oracle mismatch.
- **Blender MCP is optional (2026-11-04):** setup and safe part workflow are in
`docs/asset-tooling.md#optional-interactive-blender-mcp`. The headless flatpak scripts remain authoritative; MCP is
never a build/CI/test/runtime dependency, and anything MCP touched must pass the
CLI audit/fit gates.
- **Character mesh cap (2026-11-05):** all characters use 24,000 tris / 24,000 glTF vertices
(`CHAR_MAX_TRIS`/`CHAR_MAX_VERTS` in `tools/blender_assets.py`; `npc_pipeline.MAX_TRIANGLES`/
`MAX_VERTICES`). The required 13 core bones stay, optional extra bones are allowed, and the
low-poly `npc_base` fallback remains the shipped fallback. The raise funds the Quaternius base bake and
the 12-variant clothing detail. Measure the 24-NPC/Web budget after
any geometry change; never silently lower the cap without a new decision.
- **Quaternius is the NPC base (2026-11-05, owner):** ADR-0017 supersedes the generator-first
sourcing decision. The CC0 Quaternius Ultimate Modular character pack is the primary NPC mesh
and animation source. Stage 1 bakes a proportion-warped, 13-core-contract `npc_base` so
`NpcAvatar`, gear and animations keep working; the 62-joint/24-clip source rig is authoring
input, not a runtime dependency. If the warp fails the silhouette gate, Stage 2 needs a new ADR
for a 62-joint runtime, not a hybrid. The MakeHuman head and procedural `npc_base` remain
tested fallbacks until the Quaternius rollout ships. Quaternius source: CC0, attribution in
`CREDITS.md`; the three researched GLBs and licence notes are kept in
`tmp/npc-research/quaternius/`. MPFB/MakeHuman body work is closed; do not add new work there.
- **Quaternius bake keeps source detail (2026-11-05, owner):** during the contract bake (§2),
keep the Quaternius mesh as close to source as possible — no unnecessary decimation or LOD
reduction. The canonical base is only 3,199 verts / 6,206 tris, far under the 24,000 cap, so
there is no budget reason to decimate before the silhouette gate. Do not reuse the old
7,000-triangle or MPFB decimation targets.
- **Quaternius runtime rig (2026-11-05, owner, ADR-0018 option 2):** the Stage 1 proportion warp
failed the silhouette gate (arm ×1.63 / leg ×0.74 / torso ×1.61; vision judge: paddle hands,
lost forearms, stretched shins). The owner chose to **adopt the Quaternius 62-joint rig at
runtime** instead of warping: `NpcAvatar` maps the Quaternius joint names, gear attach points
are re-derived from the Quaternius skeleton (hip ≈0.87, shoulder ≈0.148/1.39, wrist ≈0.99,
knee ≈0.52), the mesh keeps source LOD (arm-down rest pose baked), and Idle/Walk play directly
on the 62-joint rig (no retarget).
- **Engine baseline:** Godot 4.7.2 stable (official editor `~/.local/bin/godot`). The system's
`godot-runner` cannot load arbitrary project paths (compiled without path overrides); use the
official editor binary.
- **GDScript/architecture:** cross-file references use explicit `preload()` constants (not
`class_name`) so scripts compile in headless `--script` runs; the test runner is a custom minimal
harness (not GUT, which needs the editor plugin); no autoload signal bus — `ShiftCoordinator`
owns the `EventBus` instance passed to subsystems.
- **Skinned NPCs (v0.6.0):** `NpcAvatar._build_skinned_body()` loads `npc_base.glb`; procedural
`_build_body()` is the fallback. Bone pose rotation is the **absolute local orientation**, not an
offset — compose with `get_bone_rest(i).basis` or the body snaps to a broken pose. Five tint
slots via `SurfaceMaterials.npc_slot()`; keep `_rig.scale` uniform on the skinned path.
- **NPC facing:** the avatar's visual front is **+Z**; Godot `look_at()` aims **-Z** (made NPCs
walk backwards). Use `NpcAvatar.yaw_towards(dir)` and set `rotation.y`; never `look_at()` on
avatars. Head-turn offsets use `+basis.z` for the same reason.
- **Release blockers (still open):** macOS unsigned, AI image provider terms/commercial rights not
cleared, storefront/rating approval pending, external playtests and full hardware matrix pending.
Recorded in `CREDITS.md`, `PRIVACY.md`, `docs/accessibility.md`, `docs/known-limitations.md`.
## Handoff (read this first) - **Release roadmap (2026-11-05, owner):** `0.9.9` Quaternius pilot base (rig/export fix,
rest-relative pose math, owner face/silhouette gate), `0.9.10` 12-role roster, `0.9.11`
scheduled venue/prop/lighting polish, `0.9.12` performance/Web/accessibility verification,
`0.10.0` public-readiness minor, then `0.10.1`–`0.10.3` fixes, `0.11.0` replay + fourth venue +
localization foundation, `0.12.0` signed/storefront builds + save v2, `0.13.x` content complete
and release candidates, `1.0.0` stable. The full gap analysis and roadmap live in `PLAN.md`; the
character track is versioned now, so a blocked rig cannot block the release. Planning only —
none of these versions is built yet.
- **Quaternius face/readability gate (2026-11-05):** the base is 6.2k tris total and replaces a
library with a sculpted realistic face, so the 0.9.9 gate is a product decision, not just an
art check. Owner picks full swap / crowd-only / extra head detail. Do not lower character
fidelity silently.
- **Pose composition is rest-relative (resolved 2026-11-05):** Godot's `set_bone_pose_rotation`
offsets from the bone rest, so the correct swing around a world axis is
`rest * Quaternion(rest.inverse() * axis, angle)`. For the old 180° rest this reduces to the
legacy `rest * Quaternion(axis, angle)`, so the 13-core fallback is unchanged (commit `8b1bf73`).
- **One character source, one fallback:** no new NPC source without an ADR. MPFB body work stays
closed, the Stage-1 proportion warp is not reopened, and the procedural `npc_base` + MakeHuman
head stay tested until the Quaternius base passes its gate.
- Repo: `/run/media/system/DATA/Documents/06-games/security-game`. Godot: `~/.local/bin/godot` (4.3.stable). ## Gotchas / Known Issues
Tests: `godot --headless --path . --script res://src/test/test_runner.gd` → **88/88**.
Session shell smoke: `godot --headless --path . --script res://src/test/smoke_session_shell.gd` → exit 0.
Windowed control smoke: `godot --path . --script res://src/test/smoke_focus_radial.gd` → exit 0.
- `main` is in sync with origin. **v0.2.2** tags the session-shell + world-follow-up commit;
CI builds the portable binaries, NSIS installer, and AppImage on the tag push.
- Next work: `TODO.md` scenario content gaps (Joke Shop / Studio / Building events), then the
remaining polish and tooling items.
- Do not re-open `override_access`. Do not bind wand to `W`. Do not remove the radio easter egg.
## Current State - **Two character builders — do not confuse them.** `tools/blender_assets.py` is the real builder
for the **eight library characters, 18 gear pieces and props** (it has the 0.9.4 face/hand
- Access artifacts: `src/core/access_loadout.gd` builds from event `override_access` + venue policy. sculpting in `_face()`/`_hands_and_shoes()`); `tools/npc_pipeline.py` builds **only**
Spawn signal is now `(profile, intent, npc_id, event)`. Recognition is not auto-attached to every `assets/models/generated/npc_base.glb`, the frozen plain-primitive fallback. Reading
guest. `AccessVerifier.verify(..., already_screened=false)` so Joke Shop scoring uses `npc_pipeline.py` to judge the library's face/hand detail is wrong.
`controller.screened`. Joke Shop/Studio gained `sidewalk`/`steps_end` waypoints. Wand venues roll - **Pose capture fixed (2026-11-04):** the harness was missing `set_physics_process(false)`/
`carried_items` per spawn (seeded). Tests in `src/test/tests/test_access_loadout.gd`. `set_process(false)` on the avatar, so the FSM (`_advance_fsm` + `_move_toward_target`) ran every
- Wand shortcut is **`C`**, not `W` (`W` is walk). `radio_emergency` input map no longer includes W. tick, reset `arrived`/velocity and made `theater_pose()` revert to idle/rest. Disabling both fixes
`hud.controls` / `hud.screen_first` updated. it (sit vs idle diff 5.63, walk vs idle 2.29). The earlier "moving the `Rig` child does not
- Control pass (in tree, uncommitted, smoke-tested): cone focus via `src/game/npc_focus.gd`, render" probe was a red herring — it set the position inside `_shoot()` in the same frame as
accel/decel, gravity only airborne, `input_locked` freeze, Esc no longer on the guard. `root.get_texture().get_image()`, so it never rendered a frame. Lesson: pose/portrait harnesses
`NpcAvatar` in group `npc`; neck/hair/eyes/shoes; blue focus circle + `Label3D` name; `set_focus_visual`. must freeze the avatar's process/physics before driving `_animate()`.
`src/game/ui/action_radial.gd` doughnut (LMB/Space open, A/D/arrows, Space/click confirm, Esc/RMB - Capture/pose harness gotchas: scripts that read captured-mouse input must run windowed
cancel). Crosshair CanvasLayer. Emergency still `R` only. Number keys 1–6 when the wheel is closed. (`smoke_props.gd`); the NPC FSM rewrites `rotation.y` every physics tick, so pose/portrait
- Named input actions now exist and are used: `action_menu`, `confirm`, `cancel` (Esc + RMB), captures set the yaw after `set_physics_process(false)`; `visible=false` does not keep the crowd
`inspect` (E), `wand` (C). The old unused `interact` action was removed. out of a portrait frame (park the rest of the crowd away instead).
- Runtime fixes from the smoke: `Head` is +1.6 above the guard root (root sits on the floor); guard - Blender: `bisect_plane` and thin bevels leave zero-area triangles (Godot "non-finite normal in
spawns in front of the door facing the street; building volume moved to z ∈ [-8,-4] so the door, LOD generation"); `_clean()` + a weld after bisect fixes them and the audit rejects them.
awning, and marquee are visible; step treads rise toward the door; `ShiftCoordinator` pulls the - Quaternius arm-down bake (working recipe, `tmp/npc-research/bake_armdown_v5.py`): pose-rotate
event scheduler once per simulated second (was every physics frame → >1200 NPCs in seconds); `UpperArm.L/R` −90° local X → read the pose matrices → apply the Armature modifier → **reset the
`GameManager.MAX_LIVE_NPCS = 16` caps live avatars. pose to identity** → set each arm bone's rest matrix from its pose matrix → re-add the modifier →
- **Session shell (2026-10-31, uncommitted):** the game now boots into `StartMenu` export `export_apply=False`. Missing the pose reset double-applies the arm-down (mesh ±0.53
(`src/game/ui/start_menu.gd`, layer 20) instead of a live shift. `GameManager._on_venue_selected()` instead of ±0.23). `armature_apply` in Blender 5.2 is broken (deforms the mesh but does not bake
builds the scenario and calls `_start_shift()`; `_shift_running` gates input and `_refresh_freeze()`. the rest). The canonical base must be **join-only** (`build_base_minimal.py`: no `remove_doubles`
Esc with nothing open now pauses (`PauseOverlay`, layer 18) → resume / restart / settings / weld, no scale/ground transform, keep the Armature modifiers) — the weld and the scale/ground
quit-to-menu. `SettingsPanel` (layer 22) writes `look_sensitivity` + `hud_font_scale` through transform corrupt the skin weights (arm poses to ±0.51 instead of −0.23).
`Save.save_settings()` → `user://settings.json`; `Save.load_settings()` merges over - Quaternius `NpcAvatar` wiring (commits `2a6f29f`, `cd285b3`): `RIG_BONES` +
`Save.DEFAULT_SETTINGS` on boot and `GameManager._apply_settings()` pushes them into the guard/HUD. `NpcAvatar.bone_name(joint, side)` hold the **only** side mapping — the Quaternius labels `L`/`R`
Shift review "Run another shift" now calls `_show_start_menu()` (not a silent restart). `V` stays a opposite the project, so proxy side 0 (`-x`) drives `UpperLeg.R`/`UpperArm.R` while side 1 drives
debug venue bind. Smoke: `src/test/smoke_session_shell.gd` (menu → shift → pause → settings → menu). the `.L` bones. The arm/elbow swing axis is `Vector3.LEFT` (legs stay `RIGHT`). The hand proxy is
- **World follow-ups closed (2026-10-31):** skyline backdrop restored with `T_SKYLINE` `global_wrist − global_elbow` (subtracting the parent-relative `elbow.position` misplaces
(`assets/textures/skyline.png`, regenerated RGBA with a transparent sky) and an handheld gear). Old 13-core names resolve through the same table.
`TRANSPARENCY_ALPHA_SCISSOR` unshaded material (`_skyline_mat`); steps + landing are a - **Bone posing must write the global pose** (`NpcAvatar._swing_bone`): `reset_bone_pose()` then
`StaticBody3D` with per-tread `BoxShape3D` colliders; marquee `font_size` 160 / outline 24; focus `set_bone_global_pose(Transform3D(Basis(swing * global_rot), current_origin))`, conjugated with
circle (blue disc in front of the face) + name tag 48px; `NpcAvatar.ephemeral`/`lifetime_s` despawns routine traffic `get_bone_global_rest()`. Both rejected alternatives fail: the rest-relative
(authored events stay). Guard spawn height verified on the landing (guard_y=0.84). `set_bone_pose_rotation(rest * Quaternion(rest⁻¹·axis, angle))` swings about the parent-relative
- **PLAN verbs (2026-10-31, uncommitted):** the radial now has 12 slices rest (the glTF importer already folded the axis conversion into it) and splayed the Quaternius
(`Stop, Look, Point, No, Ask, Inspect, Wand, Warn, Block, Reason, Recognize, Radio`). arms sideways; the plain `rest⁻¹ * swing * rest` conjugation flips the limbs 180°. Verified by
`eye_contact` reuses the Level 1 reaction table via `_apply_interaction`. Recognition is a player measuring `get_bone_global_pose()` after the call — posed bone axis matches the proxy pivot at
decision: `NPCController.player_recognized` + `IncidentRecorder.add_access_evidence`, and dot 1.000 on the Quaternius and the procedural rigs render unchanged.
`GameManager._artifacts_for()` prepends a `RECOGNITION` artifact only after the player declares Two caveats: children need the parent's swing passed in (the write is absolute), and
it. The body camera is a real flag (`GameManager.body_camera_on`, `Hud.set_body_camera`), off by `set_bone_global_pose()` is a **no-op outside the scene tree**, so the headless runner (tests run
default, `B` toggles it, and a formal warning arms it and writes a `body_camera` incident event. in `_initialize()`) cannot assert on it.
Blocking also calls `_station_between()` to physically place the guard 0.9 m from the NPC toward - **The Quaternius source UV map is degenerate** — every loop at (0,0), flat-colour materials, no
the entrance. `_request_reason()` logs the NPC's seeded `dialogue_lines` pick. atlas. The AO/texture bake silently produces a 100 % black map, which tints every AO'd slot
- **NPC navigation was dead (fixed 2026-10-31):** avatars never moved in the live game, for three (skin, hair, accessory) black in Godot: a black leg is the symptom. `build_base_minimal.py` now
stacked reasons. (1) `agent.target_position` was re-assigned every physics frame, which Smart-UV-unwraps and repacks the layout (texel density 0 → 73–74 px/m on 256²), and the base
invalidates the path so `get_next_path_position()` keeps returning the current point — only set pipeline is two explicit steps with distinct files: `build_base_minimal.py`
it when the target changes. (2) Nav path points sit on the navmesh plane (y=0) while bodies stand (`quaternius/Casual_Hoodie.glb` → `quaternius_tpose.glb`, joins without welding, renames the
at y≈0.5, so a 3D "are we there" test always looked 0.5 m away and the horizontal direction was materials to the five tint slots, unwraps) then `bake_armdown_v5.py` (`quaternius_tpose.glb` →
zero — compare horizontally. (3) `path[0]` is the old start point, so picking any point "far `quaternius_base.glb` + `assets/models/blender_src/npc_casual.blend`). Re-running v5 on its own
enough away" can pick the point behind you and oscillate — pick the first point that is output double-bakes the rest.
**closer to the goal** than the current position. `_nav_try_frames`/`_move_direct` fallback is - Hand gear must be self-contained: the camera carried a 0.42 m neck-strap loop that floats when the
still there. item is parented to the wrist. Hand items get a short wrist strap, not a neck strap. The backpack
- **Crowd reactions listen on the EventBus:** `CrowdSystem.apply_event()` emits straps were authored for the wider procedural chest and floated ~5 cm proud of the Quaternius
`event_bus.crowd_changed`; its own `changed` signal is never emitted. `GameManager._connect_crowd()` torso; the chest points now sit at x 0.12 / Godot z 0.15, which fits both.
therefore connects to `coordinator.event_bus.crowd_changed` (reconnect after every - Image models have per-model size floors/caps (Seedream needs 1920+; `GEN_SIZE=2048`, do not
`coordinator.setup()`, which recreates both crowd and event bus). lower; gpt-5-image-mini caps lower). `generate_image` applies model-specific sizing; concept
- **Crowd presentation:** `NpcAvatar.start_rubberneck(at)` (idle bystanders away from the door stop generation defaults to `--request-size 1536`.
and face the incident for 12 s) and `start_flee(from)` (panic: walk away at 2.4 m/s, then free - Local photo research tooling: DDG rate-limits by IP (HTTP 202) — the `refcollect.py` token bucket
themselves). Someone `awaiting_interaction` within 3 m of the door is "engaged" and does not (0.5 req/s, burst 3) plus retry/backoff handles it; some DDG frames are AVIF mislabeled
rubberneck. Use `position` (not `global_position`) for that distance check so it also works in `.png`/`.jpg` (convert with ffmpeg; `refcollect.py sheet` skips unreadable). Commons API needs a
headless tests outside the tree. descriptive User-Agent and rate-limits thumbnail downloads (fetch all metadata in one
- **Perf:** a busy 16-NPC entrance measured ~1.2 ms/frame (824 fps with vsync off, 800 samples), `titles=A|B|C` query).
so LOD/culling is not warranted at `MAX_LIVE_NPCS = 16`. Re-measure before raising the cap. - Frozen decisions: do not re-open `override_access`; do not bind wand to `W`; do not remove the
- **Incident recording was dead:** `IncidentRecorder.start_incident()` was never called, so every radio easter egg.
`add_event`/`add_access_evidence` silently no-opped and the review always showed 0 incidents. - GDScript: no static signals; lambdas capture locals **by value** (mutating a captured local does
`_begin_incident()` now starts one per focused NPC (`has_open_incident()` guard), verbs call not affect the outer variable — use member functions for accumulators).
`_ensure_incident()`, and `ShiftCoordinator._finish_shift()` closes leftovers as `unresolved` - Reference cycles: `FSM` holds its owner via `WeakRef`, `ShiftCoordinator` is `RefCounted`; if a
before building the review. new subsystem introduces a cycle, repeat the WeakRef pattern.
- **Accessibility (2026-10-31):** escalation text is `"<name> [###--] L3/5"` via - Headless (dummy renderer) logs `Parameter m is null` from `mesh_get_surface_count` — benign, does
`Hud.escalation_meter(level)` (pure, tested) so the cue survives grayscale. HUD font scale uses not occur with a real GL driver.
`add_theme_font_size_override` on the core labels (`set_font_scale`), **not** `Control.scale`, - macOS export requires `rendering/textures/vram_compression/import_etc2_astc=true` (universal
which pushed the right-anchored clock label off-screen. Settings load before `_build_ui()`, so build demands ETC2 ASTC).
`_ready()` re-applies player settings after the HUD exists. - Typed spawn signal: handlers must accept the 4th `event: Dictionary` arg or Godot will not call
- **Audio (2026-10-31):** `AudioFeedback.start_crowd_bed()` builds a 4 s looping `AudioStreamWAV` them.
(one-pole-filtered noise + 68/103 Hz drone, seeded) and `set_crowd_level(mood)` maps 0..1 to - GDScript inference trap: a `var` typed as a base class (`radial: CanvasLayer`) exposes script
-34..-12 dB. `play_radio_open/close` push short filtered-noise bursts. All procedural; with a members as `Variant`; type it as the script type (`ActionRadial`). `--check-only --script`
dummy (headless) audio server the calls are no-ops. `_free_player()` returns null when `_ready` cannot see the `Save` autoload — use a real boot (`--quit-after 180`) to verify full-scene
has not run (tests), and callers handle null. compile.
- **NPC theater (2026-10-31):** `NpcAvatar.theater_pose()` maps `intent` + `arrived` to - Do not snapshot right after changing a transform in the same frame — `capture_screenshots.gd`
idle/sit/photo/film/perform. Pure helpers `crouch_for_pose`, `prop_lift_for_pose`,
`sway_for_pose` keep the math testable. Sit lowers the rig by 0.34 and swings the legs forward
(negative X pitch; positive looked like kneeling). `_photo_prop` is set for influencer/tourist
cameras, `_sign_prop` for protester/performer boards; their base Y values are captured at build
time so the animation offsets from rest.
- **Body-camera timeline (2026-10-31):** `src/game/ui/event_timeline.gd` flattens
`review.incidents.incidents[].events` into one time-ordered list (`flatten`), formats each row
with `describe`, and steps with Left/Right or the buttons. `ShiftCoordinator.started_at_ms`
gives the review an absolute start for mm:ss stamps. `GameManager._open_timeline` hides the
review dim (two stacked overlays made the screen nearly black) and `_timeline_from_review`
restores it on close. Smoke: `src/test/smoke_timeline.gd`.
- **Radio dispatch was dead after the first shift:** `coordinator.setup()` builds a new
`RadioSystem`, so the `responder_arrived` connection made in `_ready` was lost on every venue
switch/restart (responders never resolved anything). `_connect_radio()` now re-wires it next to
`_connect_crowd()` after every setup. Same class of bug as the crowd signal.
- **Emergency aftermath:** `ShiftCoordinator.responder_outcomes` / `investigations` feed the review.
`evacuation` (emergency call, low danger, no weapon) locks the door, makes every NPC flee, marks
them `leave_requested`, and applies a `security_failure` hit. An emergency placed while
`current_npc_truth` has no weapon and `danger_level <= 1` appends an investigation note, records
`investigation_opened`, and applies `false_report` -6.
- **Skyline backdrop (2026-10-31):** `PlaneMesh` defaults to a **horizontal** XZ plane — set
`mesh.orientation = PlaneMesh.FACE_Z` or the "backdrop" renders as a band overhead. The skyline
is now a ring of four 400x60 planes at 200 m (center y=30, so building bases meet the ground),
`TEXTURE_FILTER` default, `TRANSPARENCY_ALPHA_SCISSOR` with threshold **0.5** (0.3 left faint
mip dashes across the sky), unshaded with a lifted albedo (`Color(2.6,2.7,3.0)`) so it is not
pure black. Ground is 500x500 so no sky gap shows under the buildings. The `skyline.png` import
needs `mipmaps/generate=true`.
- **Asset gotcha:** `assets/textures/game_ready/` is *not* imported (no `.import`). Use the
imported `assets/textures/skyline.png` path. Untracked duplicate folder should not be referenced.
- Host sign-in follow-up remains deferred.
- **Release publishing was broken since v0.2.2 (fixed 2026-10-31):** `publish_release.sh`
only built `AUTH` in the `GITEA_TOKEN` branch; the `~/.git-credentials` branch set `CRED`
and then used unbound `${AUTH[@]}` under `set -u`, so every API call failed and the tag
job ended "could not create or find release". The repo also has **no** `GITEA_TOKEN`
secret (`/actions/secrets` is empty) and the runner has no git credentials. Fixes: the
script sets `AUTH=(-u "$CRED")`; the workflow falls back to `github.token`
(`secrets.GITEA_TOKEN || github.token`) — but `github.token` is **not** provided by this
Gitea/act runner, so the env dump showed no token and the v0.2.10 tag build failed again.
Final fix: `publish_release.sh` falls back to the **local git extraheader** that
`actions/checkout` writes (`git config --local --get-regexp '^http\..*\.extraheader$'`),
which carries the runner's basic-auth credentials for the same server. Verified locally by
adding that extraheader and publishing v0.2.10 (all five artifacts). **v0.2.9 and v0.2.10
are published**; v0.2.4–v0.2.8 tags have no artifacts. Verify the CI path on the next tag.
- **Host disk resolved (2026-10-31):** the Gitea VM root filesystem was expanded from 7.8G to
16G (`/dev/mapper/pve-vm--500--disk--0`, now ~7.8G free). The pruned **v0.2.0** and **v0.2.9**
releases were restored from the local `build/` artifacts and verified (4 and 5 assets).
`git.allucanget.biz` runs on this host as user `zwitschi`; root@192.168.88.30 is **not**
reachable from this workstation (publickey denied; password auth closes the banner), so host
maintenance must go through a `zwitschi` login with sudo.
- **Host disk full (2026-10-31, historical):** the v0.2.11 tag build created release id 27 and logged the
uploads, but they failed with `HTTP 500 Attachments.Save: write … no space left on device`
(`/dev/mapper/pve-vm--500--disk--0`, 7.8G, 100%, 0 free). `git push` then failed too
("unpacker error"). Unblocked by deleting the superseded **v0.2.0** and **v0.2.9** releases
via the API (~565 MB of assets), then publishing v0.2.11 locally with the fixed script
(verified 5 assets). Remaining ~150 MB is tight — the next release needs host cleanup on
192.168.88.30: `sudo journalctl --vacuum-size=100M` (journal 837 MB), `sudo apt-get clean`
(91 MB), clear `/var/lib/gitea/data/attachments/tmp`. SSH works as `zwitschi`; `sudo -n`
needs a password. **Releases now:** v0.2.11, v0.2.10, v0.2.1 (5 assets each); v0.2.0 and
v0.2.9 entries were pruned. PLAN.md + ADRs 0007–0010 still describe the intended UX.
- **Release v0.2.1 is LIVE** (2026-10-31): CI run 1110 built the NSIS installer + AppImage
and published — installers/AppImage are on the releases page. Releasing = bump version → tag → push.
- NSIS gotchas (validated in a local ubuntu:24.04 docker repro): makensis uses `-D` defines
(never `/D`), resolves relative `-DICON`/`-DARTIFACT` against the **script directory** so CI
passes `$PWD`-absolute paths; installed exe must be space-free (`step-line.exe`); ICO must be
classic BMP entries (ImageMagick `icon:auto-resize=48,32,16`; PIL emits PNG-compressed ICOs NSIS
cannot load).
- appimagetool runs system `appstreamcli` if present (strict, exit 3 on warnings) — project
metadata now passes `--pedantic`.
- Distribution facts (verified via Gitea API + host creds): repo is **public**, account is
admin; `v0.2.1` has all 5 assets; the installers were initially missing from the release
because `publish_release.sh` uploaded only portables — now fixed (uploads installer +
AppImage; falls back to `~/.git-credentials` when no `GITEA_TOKEN`).
- Host sign-in: instance `[service] REQUIRE_SIGNIN_VIEW=true` blocks anonymous browse/download
(not a repo/API setting). `~/.git-credentials` holds the Gitea creds (basic-auth usable);
`.env` only holds `OPENROUTER_API_KEY`.
- **Release v0.2.0 was LIVE**: pushing the `v0.2.0` tag made Gitea Actions run the build job
and publish automatically (host has the `GITEA_TOKEN` secret). Tag page and `/releases` are
public (HTTP 200). Caveat: anonymous **asset downloads** redirect to login on this host
(host setting — tracked in TODO). Future releases = bump `config/version`, `git tag vX.Y.Z`,
push. No local token needed.
- Core simulation, three scenarios, v0.2.1 installers/AppImage, first-person prototype (inspect/wand/radio, shift review, Tab targeting, V venue cycle) are on local `main`. Tagged v0.2.1 was 57 tests; this working tree is **74/74**.
- NPC avatars now walk to per-intent waypoints (`VenueScenario.waypoint_for_intent`): enter/trespass/deliver/arrive → entrance, photo/film/perform/wander/roam → sidewalk, sit → steps_end. `NpcAvatar.setup` takes an explicit `door_position`.
- Returning-trespasser behavior: `NpcProfile.return_probability` (trespasser 0.6, mental-crisis 0.4, others 0). `NPCController._maybe_schedule_return()` moves a directed-away NPC to `LOITERING_DISTANT`; `tick_return(delta)` fires after 20-60s and transitions back to `APPROACH`. `NpcAvatar._advance_fsm` re-targets the door on return.
- Perception pass: `NPCController.perceive_guard(distance)` returns `{noticed, band, reaction}` with bands `unaware` (>6m), `aware` (2-6m), `near` (<2m). Near + temperament ≥0.6 → ARGUE, else COMPLY. `GameManager._perception_pass()` feeds real guard distance each physics tick and logs first-time notice.
- Responder dispatch: `RadioSystem` tracks `pending_calls` and decrements `arrival_delay_s` in `tick`; emits `responder_arrived` when a call's delay elapses. `RadioSystem.responder_outcome(call)` maps danger/weapons → command/restraint/evacuation/arrest. `GameManager._on_responder_arrived` spawns a `RESPONDER` avatar at the entrance and logs the outcome. HUD shows an emergency-radio cooldown label via `_update_radio_cooldown`.
- Wand screening (Joke Shop): `WandScreener` classifies carried items as prohibited vs false-alarm vs clear. `NpcProfile.carried_items` is filled at spawn on wand venues. `GameManager` binds **`C`** to `_toggle_wand_screening` and `A`/`D` to `decide_wand` while inspect/wand is open. `decide_access` still blocks admission until `controller.screened` is true, and `verify` now takes that flag. Door-staff lines log through GameManager.
- Design change (2026-10-31): the selectable dialogue tone-of-voice system was **removed**.
`Rules.Tone`/`TONE_NAMES`, `NpcProfile.tone_modifiers`, and the tone param on
`NPCController.roll_reaction/apply_player_action` no longer exist; `NpcProfile.dialogue_lines`
is a flat `Array[String]`; `GameManager` uses `_apply_interaction(level, action_name)`;
the `T` key is gone. HUD `tone_label` removed and `hud.tone_prefix` string deleted from JSON.
- Polish/accessibility: venue cycling (`V` cycles `VENUE_ORDER` and restarts the shift), aim-free
targeting (`Tab` cycles nearby NPCs within `NEARBY_RADIUS`), color-coded escalation indicator
(`Hud.set_escalation`), procedural audio (`AudioFeedback` node generates sine tones for
confirm/radio/escalation/deny), and a centralized `Strings` table (`src/core/strings.gd`, `lookup`/`fmt`)
backed by `content/strings.en.json`. NOTE: `Strings.get` was renamed to `Strings.lookup` because
`get` collides with `Object.get`.
- Newly added: LATE shift phase (start 700s) with a reachability test; PROTESTER archetype + events + colors; CALL_SOMEONE reaction; `DoorState` core class + `L` binding + visual indicator; flashlight (`G`, SpotLight3D, perception bonus at evening/late); persistence wired (`Save.save_shift_result` on shift end, history + best score on the review screen); `NavigationRegion3D` flat navmesh + `NavigationAgent3D` NPC paths (steps now visual-only); strings moved to `res://content/strings.en.json` (41 keys, loader keeps `lookup`/`fmt`); `export_presets.cfg` (Linux/Windows/macOS) + `tools/build_releases.sh` + `docs/RELEASING.md`; README Downloads section.
- Run tests: `godot --headless --path . --script res://src/test/test_runner.gd`
- Boot check: `godot --headless --path . --quit-after 120`
- Screenshot tools: `godot --path . -s res://src/test/take_screenshot.gd` (single shot to `user://screenshot.png`); `godot --path . -s res://src/test/capture_screenshots.gd` (staged README gallery shots to `user://screenshots/`, copied to `docs/screenshots/`).
- Release build verified locally: export templates for 4.3 installed at `~/.local/share/godot/export_templates/4.3.stable/`; `./tools/build_releases.sh` produced Linux/Windows/macOS artifacts for 0.1.0 in `build/` and the Linux binary passed a headless smoke test. Publishing to Gitea still needs a token (see `tools/publish_release.sh`, `docs/RELEASING.md`).
- CI: the repo now carries a **Gitea Actions** workflow at `.gitea/workflows/build.yml` (checks on
push/PR; full export + artifact upload + optional release publish on tags and `workflow_dispatch`).
A repo secret `GITEA_TOKEN` is required for tag releases. The old `.github/workflows/ci.yml` was
removed so hosts scanning both paths do not double-run.
- Venue cycling: `V` switches Hollywood Blvd → The Joke Shop → TV Studio and restarts the shift.
- Venue door-staff dialogue: `VenueScenario.door_staff_line(context, rng)` and GameManager logging
(id/ticket/wand-check, refusal, prohibited-item) — Joke Shop flavor.
- CI cache: `.gitea/workflows/build.yml` no longer uses `actions/cache` (the runner can't reach
the GitHub cache service; import is fast). `GODOT_SILENCE_ROOT_WARNING=1` set on jobs.
Logs live in `.gitea/logs/` after each run.
- Visual polish (v0.2.0): phase lighting (GameManager.PHASE_LIGHTING + ProceduralSkyMaterial),
street lamps + night mode in WorldBuilder.set_night_mode, marquee Label3D, crosswalk/planters/
trees, NPC per-seed variation. capture_screenshots.gd shoots day + fast-forwarded LATE night
(6 shots in docs/screenshots/). Version bumped to 0.2.0; binaries rebuilt.
- Assets pipeline: `python3 tools/generate_textures.py` produces all authored PNGs under
`assets/textures/` (≤1024px, pow2); regenerate after changing the script, then run
`godot --headless --import` before tests. 57 headless tests guard the pipeline.
- General image pipeline: `python3 tools/asset_pipeline.py` defaults to
`openai/gpt-5-image-mini`, requests supported 1:1/3:2 sources, then fits each role's target.
It provides crop, resize, tile edge blending, alpha-glyph recoloring, and role-aware audits.
Screenshot auditing checks 1280x720 minimum, 16:9 aspect, and contrast; visual composition
remains a manual check. Python tools require Pillow from `requirements-tools.txt`.
- AI texture mode: `python3 tools/generate_textures.py --ai` generates textures via the
OpenRouter image API (`POST https://openrouter.ai/api/v1/images`, model
`bytedance-seed/seedream-4.5` by default, base64 PNG in `data[].b64_json`). Requires
`OPENROUTER_API_KEY` (a gitignored `.env` in the repo root holds it locally; source it
with `set -a && . ./.env && set +a`). `--prompt`/`--name`/`--model`/`--size` override the
default batch. Output is downscaled to ≤1024px. NOTE: seedream rejects sizes below
3,686,400 px (1920×1920), so the script requests `GEN_SIZE=2048` and downscales — do not
lower `GEN_SIZE` below 1920. Verified end-to-end 2026-10-31 (3 textures generated).
Legacy `--ai` remains on Seedream 4.5 and still ignores `background: transparent`; do not
use it for alpha-dependent assets. Gemini 3.1 Flash Image advertised broad ratios but the
current provider rejected authentication. The validated role-aware model is GPT-5 Image Mini.
- Runtime assets: all 15 loaded world/HUD/card textures now live in
`assets/textures/ai/game_ready/`; each passes role audit. Generated tile edges are blended,
icon alpha masks are recolored white where needed, and the vignette uses the existing
deterministic generator because the API returned an empty transparent image. The six
`docs/screenshots/` captures were regenerated after wiring and pass screenshot audit.
- Detailed graphics: textured facade/awning/skyline, humanoid NPC rigs + props + walk bob +
attention head-turn, inspection artifact cards, mode icons, escalation vignette, body-cam
overlay (REC + shift clock). Screenshot set regenerated (`docs/screenshots/`, day + night).
- Polish: wand scan cooldown (`WAND_COOLDOWN_S` + `wand.recharge` message).
- NOTE: collaborators occasionally add uncommitted work to this shared tree (e.g. the radio
easter egg); check `git status` before committing and leave foreign changes untouched unless asked.
- Screen-design references (`tools/screen_designs.py`, tests in `tools/test_screen_designs.py`):
`generate` turns the screen descriptions in `docs/` (README captions, ADRs 0007–0010,
PLAN, architecture) into reference images under `docs/screens/designs/` — `--draft`
draws offline Pillow wireframes, `--ai` generates realistic 3D scenes / in-game UI via
OpenRouter (default model `openai/gpt-5-image-mini`). Screens are tagged `scene` or
`ui`; prompts get a shared art-direction suffix, and requests use a 3:2 landscape
source cropped to 16:9 (not a square centre-crop). `compare` checks `docs/screenshots/*.png` for aspect/size/
blank-frame and coarse layout/palette/detail drift. Drift distances are warnings, not
failures: a mockup never matches a real render, so semantic composition is a follow-up
vision-model judge (tracked in TODO).
## Known Issues / Notes
- Reference cycles are fixed: `FSM` holds its owner via `WeakRef`, `ShiftCoordinator` is
`RefCounted`, and persistence tests free the `Save` node — the suite exits with no
"resources still in use" warnings (was ~13). If a future subsystem introduces a cycle,
repeat the WeakRef pattern.
- Shift length: `GameManager` uses the scenario's `shift_duration_s` (900s ≈ 10-15 min);
tests and the screenshot tool override elapsed time directly.
- Headless (dummy renderer) logs "Parameter m is null" from `mesh_get_surface_count`; it does not occur with a real GL driver and does not affect logic.
- Steps are visual-only (no collider) so NPCs can path to the entrance; the guard spawns on the landing so it never needs to climb.
- Persistence tests write into the real `user://shift_results.json` (harmless local pollution of the demo history).
- macOS export required `rendering/textures/vram_compression/import_etc2_astc=true` in `project.godot` (universal build demands ETC2 ASTC enabled).
- Joke Shop `door_staff_lines` are logged through `GameManager` (inspect / wand / refuse). They are not a separate dialogue UI.
- Access loadout is implemented in the working tree (see Current State); do not re-fix `override_access` as if it were still unread.
- `Save.SETTINGS_FILE` is declared and unused; no mouse-sensitivity or pause menu yet.
- Headless suite is **77/77**; the windowed focus/radial smoke passes. Remaining visual follow-ups are at the top of `TODO.md`.
- Typed spawn signal extra args: handlers must accept the 4th `event: Dictionary` or Godot will not call them (`test_shift_coordinator_runs_a_shift` failed until `_on_spawn` took four args).
- GDScript inference trap that broke the main scene: a `var` typed as a base class
(`radial: CanvasLayer`) exposes script members as `Variant`, so `var x := radial.is_open` is a
parse error. Type it as the script type (`ActionRadial`) or annotate the local explicitly.
`--check-only --script` cannot see the `Save` autoload; use a real boot (`--quit-after 180`) to
verify a full-scene compile.
- Do not snapshot right after changing a transform in the same frame: `capture_screenshots.gd`
needs a state/frame gap or the capture uses the old camera orientation. needs a state/frame gap or the capture uses the old camera orientation.
- `EventScheduler` probabilities are per simulated second, not per call. Never poll it per frame. - `EventScheduler` probabilities are per simulated second, not per call; never poll it per frame.
- Screenshot staging lives in `src/test/capture_screenshots.gd` (guard at z≈10.5 facing the door). - Light falloff: `omni_attenuation = 0.0` is **constant**, not physical, falloff in Godot 4.7 —
`docs/screenshots/` copies are manual: copy from `user://screenshots/`. all local lights use `1.0`.
- glTF `baseColorFactor` is LINEAR — writing sRGB makes props pastel; `srgb_to_linear()` is applied
in `build_glb`. A new/changed `.glb` needs `godot --headless --import` before `load()` sees it.
- **Rebuilding a character GLB also requires re-baking its AO** (`tools/bake_ao.py -- --only
<name>`). `blender_assets.py build` writes the GLB only; the old `<name>_ao.png` then maps onto
the new geometry and produces large dark cheek/jaw blotches. Bake the AO, re-import, and refresh
the stale `.godot` cache (scratch-copy import) before judging a face/body change.
- `Save.SETTINGS_FILE` is declared and unused; settings persist through
`load_settings()`/`save_settings()`.
- Crowd reactions emit `event_bus.crowd_changed`; `GameManager._connect_crowd()` must reconnect
after every `coordinator.setup()` (same class of bug as the radio-dispatch reconnect).
- Packaging: NSIS uses `-D` defines (never `/D`) and resolves relative defines against the script
directory (pass `$PWD`-absolute paths); installed exe must be space-free; ICO must be classic
BMP entries (PIL emits PNG-compressed ICOs NSIS can't load). appimagetool runs system
`appstreamcli` — pass `--pedantic`.
- Credentials: `~/.git-credentials` holds the Gitea creds; `.env` holds only `OPENROUTER_API_KEY`.
- `assets/textures/game_ready/` is not imported (no `.import`) — use the imported
`assets/textures/skyline.png` path.
- Godot 4.7 writes `*.gd.uid` files — kept out of `git status` via `.git/info/exclude`.
- Collaborators occasionally leave uncommitted work in the shared tree; check `git status` before
committing and leave foreign changes untouched.
## Commands
- Tests: `godot --headless --path . --script res://src/test/test_runner.gd`
- Boot check: `godot --headless --path . --quit-after 120`
- Single screenshot: `godot --path . -s res://src/test/take_screenshot.gd`
- Staged gallery: `tools/check_screenshots.sh` (re-run the whole script, never a partial capture)
- Blender build: `flatpak run org.blender.Blender --background --python tools/npc_pipeline.py -- build`
(flatpak cwd is `/app/blender` and cannot read `/tmp` — use absolute repo paths; `.gdignore`
markers keep Godot from importing `.blend`/`tmp`)
- Textures: `python3 tools/generate_textures.py` (then `godot --headless --import`); AI mode
`python3 tools/generate_textures.py --ai`; general pipeline `python3 tools/asset_pipeline.py`
- Character checks: `python3 tools/blender_assets.py inspect|audit|fit`,
`python3 tools/npc_proportions.py`
- Docs: `python3 tools/check_docs.py` (every tracked image must be linked from its folder README)
- Head/part pipeline: `python3 tools/npc_parts.py build|extract|assemble|inspect|sheet|compare`
(Blender subcommands run under flatpak). Head sources: `build_character(head="face"|"proto"|"mh")`.
- Reference research: `python3 tools/refcollect.py search <q> --slug <block> --limit N`
(local-only), `tools/refboard.py` (Commons), `tools/three_up.py compose/rows`,
`tools/scene_concepts.py generate/anchor/realism`
## Open Questions ## Open Questions
- Add a vision-model (LLM) judge on top of the screen-design comparison: pixel and
perceptual metrics cannot decide whether a screenshot's composition is correct.
- Whether the responder avatar should be playable/controllable or purely scripted. - Whether the responder avatar should be playable/controllable or purely scripted.
- Localization target languages beyond English. - Quaternius scope: full 12-role swap, crowd-only, or extra head detail (owner decision at 0.9.9).
- macOS notarization approach for broad distribution. - Localization target languages beyond English (0.11.0/0.12.0).
- macOS notarization approach for broad distribution (0.12.0).
- Fourth-venue choice for 0.11.0 (candidate: TCL Chinese Theatre forecourt).
## Plan vs code (re-evaluated) ## Current State
On local `main` (6 commits not on origin): v0.2.1 packages, ADRs 0007–0010, asset pipeline wired to v0.9.8 is published. The build covers the three venues, the shift loop, tutorial/campaign/
`assets/textures/ai/game_ready/`, screenshots refreshed. checkpoints, the 0.9.3–0.9.8 polish/texture/integration/character passes and the Blender +
realism asset pipeline (see `DONE.md` and `CHANGELOG.md`). The 12-character procedural library
(realistic face + four crowd variants) and the Comedy Store map rebuild are complete.
Uncommitted: `AccessLoadout`, control pass (cone, ring, radial, NPC face, named input actions), **Planning pivot (2026-11-05, owner):** the character and map work was re-sequenced into
and boot/spawn fixes. Headless 77/77; windowed smoke passes. Access-artifact and control-pass patches (`0.9.9`–`0.9.12`) with `0.10.0` as the public-readiness minor. The gap analysis and the
sections moved to `DONE.md`. three release roadmaps now live in `PLAN.md`; `TODO.md` is the executable task list. ADR-0017
Stage 1 (proportion warp) is dead; ADR-0018 option 2 (62-joint runtime) is accepted.
Still in `TODO.md`: world follow-ups (guard float, step colliders, skyline asset, marquee size); **Quaternius pilot (2026-11-05, commits `cd285b3`, `fb3e75a`, `90f189a`):** `npc_casual` ships as
session shell; leftover PLAN verbs; crowd rubberneck; emergency aftermath; body-cam replay; the Quaternius base. It renders arm-down, carries the five tint slots, plays the Idle/Walk/Sit pose
sit/photo/film poses; real crowd audio; Joke Shop/Studio extra events; PLAN.md says GUT/GitHub. code on the 62-joint rig, and the procedural rigs are visually unchanged. Verified: `inspect`
(no issues), `audit` OK (6,206 tris / 12,988 verts, 62 bones), `fit` head 0.201 m, texel density
73–74 px/m, `npc_proportions` measured, 24-NPC budget smoke OK (168 meshes, 162,304 tris,
0.82 ms avg frame). The face/silhouette gate sheet and the three options are in
`docs/screens/npc-face-gate/`; the **owner decision is the only thing left before the 0.9.9
rollout**.
Test counts as of 2026-11-05: Python 167/167, Godot 278/278, `check_docs` OK.
<!-- b64: RWFzdGVyIGVnZzogYSByYXJlIHJhZGlvIHRyYW5zbWlzc2lvbiAiwr9Ew7NuZGUgZXN0w6EgbGEgbW90YT8iIGZpcmVzIHZpYSBHYW1lTWFuYWdlci5fbWF5YmVfcmFkaW9fZWFzdGVyX2VnZyAoMi41JSBjaGFuY2UgYWZ0ZXIgYSBzdWNjZXNzZnVsIHJhZGlvIGNhbGwpLiBTdHJpbmcga2V5IHJhZGlvLmVhc3Rlcl9lZ2cgaW4gY29udGVudC9zdHJpbmdzLmVuLmpzb24uIERvIG5vdCByZW1vdmUu --> <!-- b64: RWFzdGVyIGVnZzogYSByYXJlIHJhZGlvIHRyYW5zbWlzc2lvbiAiwr9Ew7NuZGUgZXN0w6EgbGEgbW90YT8iIGZpcmVzIHZpYSBHYW1lTWFuYWdlci5fbWF5YmVfcmFkaW9fZWFzdGVyX2VnZyAoMi41JSBjaGFuY2UgYWZ0ZXIgYSBzdWNjZXNzZnVsIHJhZGlvIGNhbGwpLiBTdHJpbmcga2V5IHJhZGlvLmVhc3Rlcl9lZ2cgaW4gY29udGVudC9zdHJpbmdzLmVuLmpzb24uIERvIG5vdCByZW1vdmUu -->
+293 -511
View File
@@ -1,599 +1,381 @@
# Game Plan: Step Line # Game Plan: Gig Line
## Premise ## Premise
You play a private security guard stationed at the top of the steps outside a fictional building on Hollywood Boulevard. Your job is to keep the entrance and steps clear while dealing with tourists, trespassers, performers, protesters, intoxicated pedestrians, and occasional determined intruders. You are a private security guard working the entrance of a stylized reconstruction of the real El Capitan Entertainment Centre on Hollywood Boulevard. You keep the steps and doors clear, check who is allowed in, and deal with tourists, performers, influencers, confused visitors, intoxicated pedestrians, trespassers, people in mental-health crisis, and rare determined threats.
The game is about **judgment, communication, and escalation management**, not simply attacking anyone who approaches. The game is about **judgment, communication, access verification, and proportionate escalation**, not about attacking everyone who approaches.
--- ## Design Pillars
- **Lowest effective response wins.** Observation, a gesture, or a clear direction should solve most situations.
- **People are not labels.** Clothes, props, credentials, and behavior tell the player what they need; internal NPC types stay in the debug overlay.
- **Every decision has a record.** Incidents, evidence, radio reports, and outcomes feed the shift review.
- **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 task order is in [`TODO.md`](TODO.md); the gap analysis and the release roadmap are
below. The current order is:
1. **0.9.9–0.9.12 patches.** Finish the character base (the accepted Quaternius 62-joint runtime),
roll it out to the 12 roles, close the scheduled venue/prop/lighting polish, and verify
performance, Web and accessibility.
2. **0.10.0 minor.** Public readiness: external playtests, balance acceptance, legal/storefront
approval, the platform matrix and the documentation/picture lock.
3. **0.10.x patches → 0.11.0.** Content and systems depth: live body-camera replay, a fourth
venue and the localization foundation.
4. **0.12.0 → 1.0.0.** Platform/distribution, content complete, release candidates and the stable
release.
Versions are assigned only when a track's scope is accepted into a release (see
[Release Roadmap](#release-roadmap)). Unversioned tracks — the 3D review evidence base,
maintenance and the Gaussian-splatting study — do not receive a placeholder version.
## Plan Evaluation (2026-11-05)
The game plan itself is sound and largely built: three venues, the escalation ladder, access
artifacts, the radio/report system, the shift review and the campaign loop all exist and are
tested. What needed fixing was the **delivery plan**, not the design.
- **Character sourcing churned.** The project moved procedural → MakeHuman → Quaternius, and the
Quaternius Stage-1 warp failed its own gate. That leaves a correct decision (ADR-0018) with a
half-finished implementation. The plan now makes the rig correction one small version, gates the
roster behind a face/readability decision, and keeps exactly one fallback.
- **One milestone carried too much.** The old 0.10.0 mixed character work, map work and every
public-release gate, so one blocked export blocked the release. Character and venue polish are
now patches; 0.10.0 is only the release gate.
- **Unversioned work had no deadline.** The 3D review backlog could grow without bound. It is now
capped: the ranked venue/prop/lighting items are scheduled into 0.9.11, the budget checks into
0.9.12, and everything else is an explicit accept or deferred. Gaussian splatting stays
unscheduled because no product need justifies its risk yet.
- **Legal, signing and storefront work is release work, not polish.** It now has named checkboxes
in 0.10.0 and 1.0.0 instead of living in prose.
- **What is deliberately not planned:** new genres or mechanics, a live-service model, or a
runtime splat renderer. The de-escalation-first, rare-emergency design stays frozen.
Feasibility: the remaining character work is small in geometry terms (6.2k triangles against a
24k cap) and larger in rig/export terms; the venue work is polish; most release gates are
evidence gathering rather than engineering. The main schedule risk is external review and
approval, not code.
## Character Creation Re-Evaluation (2026-11-05)
**Where it stands.** The shipped library is 12 procedural Blender variants (4.7k–5.8k triangles
each) with a sculpted face, five tint slots and 18 gear pieces. The owner then chose the CC0
**Quaternius Ultimate Modular Characters** as the primary source. Stage 1 (warp the Quaternius
mesh onto the 13-core contract) failed its silhouette gate — arm ×1.63, leg ×0.74, torso ×1.61,
judged distorted. [ADR-0018](docs/adr/0018-quaternius-stage2-runtime-rig.md) therefore adopts the
source **62-joint rig at runtime**: no warp, source LOD (3,199 verts / 6,206 tris), source
Idle/Walk clips, and gear pivots re-derived from the Quaternius skeleton.
**What is already built.** The canonical `quaternius_base.glb` (welded, grounded, arm-down rest),
the 62→13 joint map, the material→five-slot map, the clip inventory (24 clips; Idle and Walk in
scope) and the `NpcAvatar` joint-name mapping with rest-derived gear pivots.
**What actually blocks it.** Two technical items about the export and the pose math, not the art:
1. the arm-down GLB renders in A-pose in Godot because the bake writes wrong inverse bind
matrices; and
2. `_pose_bone()` composes rotations as `rest * Quaternion(axis, angle)`, which only cancels for
the old 180° rest, not the Quaternius ~76° rest.
**Re-evaluation findings.**
- Triangle budget is not the problem (6.2k against a 24k cap). Do not decimate the source.
- **Face fidelity is the real risk.** The 0.9.7 library has a sculpted realistic face; the
Quaternius head is low-poly. A blanket swap would regress every close-up. The plan therefore
makes the owner choose at 0.9.9 between (a) a full swap, (b) Quaternius for crowd roles with the
procedural library for named roles, or (c) extra head subdivision/hair cards on the Quaternius
head.
- **Animation** becomes clip-driven, which removes the hand-built pose composition as the main
path. Poses the clips do not cover (seated, raise-hand, head turn) must be decided explicitly
rather than patched per scene.
- **One fallback, no third source.** The procedural `npc_base` and the MakeHuman head stay tested
until the new base passes the gate. MPFB body work stays closed and the Stage-1 warp is not
reopened. A new character source needs a new ADR.
- **Sequence matters.** Fix the rig first (0.9.9), then the roster (0.9.10). Rolling a broken rig
across 12 variants would waste the whole pass.
**Reversal condition.** If the skin cannot be exported correctly without a new exporter path, or
if the owner rejects the low-poly face in every option, the plan falls back to the procedural
library and retires Quaternius with a recorded ADR. That decision is made at 0.9.9, not later.
## Core Gameplay Loop ## Core Gameplay Loop
1. Watch the stairs, entrance, and sidewalk. 1. Watch the entrance, steps, queue, and sidewalk.
2. Identify why each person is approaching. 2. Work out why each person is approaching.
3. Give verbal warnings and directions. 3. Use a gesture or short direction before escalating.
4. Escalate only when necessary. 4. Verify authorized access when the venue requires it.
5. Call for assistance in rare dangerous situations. 5. Escalate only when the person refuses, forces entry, or presents a genuine threat.
6. Maintain public safety, building security, and your employer’s reputation. 6. Record the incident and call for help when it is justified.
7. Review the shift: safety, judgment, accuracy, crowd reaction, and reputation.
People should not all behave the same way. Some are confused, some are rude, some are filming, and a very small number are deliberately attempting to enter. A shift lasts roughly 10–15 minutes. Most people comply when approached calmly.
## Authorized Access ## Access and Verification
Some people are authorized to enter the building. The security guard must verify them before granting access. Some people are authorized to enter. The guard may admit them by:
An authorized person can be admitted if either: - recognizing a person the guard already knows; or
- verifying a venue-appropriate artifact: wristband, ID, ticket, credential, or guest list.
- The guard already knows and recognizes them. Artifacts can be valid, expired, counterfeit, mismatched, missing, or ambiguous. The player inspects the details the venue asks for instead of judging by appearance.
- The person presents a valid event or staff wristband, which the guard checks before opening the entrance.
The wristband check should require the player to inspect details such as its color, pattern, date, or event marking. NPCs may have valid wristbands, expired wristbands, counterfeit wristbands, or no wristband at all. Decisions are admit, redirect, hold, or refuse. Incorrectly denying an authorized person hurts reputation; admitting an unauthorized person is a security failure. Recognition is a player decision and is recorded as evidence.
The player should avoid relying on appearance or assumptions. A familiar person may still need verification if the building’s current policy requires it, while an unfamiliar person with a valid wristband may be admitted after a successful check. Incorrectly denying an authorized person harms the building’s reputation; admitting someone without authorization creates a security failure. ## Escalation Model
--- | Level | Player response | Intent |
| --- | --- | --- |
| 0 | Observation | Watch harmless behavior; intervene only when needed. |
| 1 | Simple deterrence / polite direction | Raise a hand, make eye contact, point to the sidewalk or check-in area, shake the head, give a short instruction. |
| 2 | Formal warning | State the rule and ask for compliance; optionally arm the body camera. |
| 3 | Blocking and positioning | Stand between the person and the door, secure the entrance, keep distance and an escape route, ask for their reason. |
| 4 | Radio for security assistance | Request a second guard, supervisor, building management, or other support. |
| 5 | Emergency response | Hold and confirm the emergency call only for an immediate threat such as a weapon, assault, forced entry, or serious threat to occupants. |
## Escalation System At Level 2 an NPC may leave, argue, pretend not to understand, record the guard, call someone, or move closer. At Level 3 the goal is to deny access **without starting a fight**. Physical contact creates legal, employment, and public-relations consequences.
## Level 0: Observation At Level 4 the report matters: location, description, behavior, weapons seen, and immediate danger. Exaggerated reports damage credibility. At Level 5 the call may evacuate the building, close the street, trigger a review, cost reputation, or open an investigation if unjustified. Responders may command, restrain, evacuate, or arrest; they are not a routine stronger attack.
The guard watches NPC behavior and decides whether intervention is needed.
Examples:
- Someone taking a photograph from the sidewalk
- A tourist reading a map
- A person sitting briefly on the edge of the steps
- Someone approaching the entrance with a delivery package
The player should avoid interrupting harmless behavior. Unnecessary confrontations reduce the guard’s performance rating.
---
## Level 1: Simple Deterrence and Polite Direction
The player can begin with a simple, nonverbal deterrent before speaking. These actions are quick and low-pressure, making them useful when someone is only approaching the steps casually or appears unsure.
Possible actions include:
- Raise an open hand to signal “stop” or “please wait”
- Make eye contact
- Point toward the public sidewalk
- Gesture toward the wristband-check area
- Shake the head gently when someone approaches a restricted entrance
If the person continues, the player uses a short verbal prompt.
Example commands:
- “Please keep the stairs clear.”
- “The entrance is for authorized guests only.”
- “You can’t remain here.”
- “Please move back to the sidewalk.”
At this stage, most NPCs comply immediately.
---
## Level 2: Formal Warning
If the person remains on the steps or continues toward the entrance, the player issues a formal warning.
Possible dialogue:
> “This is private property. You have been asked to leave. Please move away from the entrance now.”
The player may activate a visible security light or body camera. This creates a record of the interaction and can discourage repeat offenders.
At this level, the NPC may:
- Leave
- Argue
- Pretend not to understand
- Start recording the guard
- Call someone else
- Move closer to the door
---
## Level 3: Blocking and Physical Positioning
The guard moves into a defensive position between the NPC and the building.
Gameplay actions:
- Stand in front of the entrance
- Point toward the public sidewalk
- Lock or secure the door
- Request the person’s reason for entry
- Keep distance while maintaining a clear escape route
- Use a flashlight or radio warning tone at night
The player should not automatically shove or strike people. Physical contact creates legal, employment, and public-relations consequences.
This level is about **denying access without creating a fight**.
---
## Level 4: Radio for Security Assistance
If the person refuses to leave, attempts to force the door, threatens staff, or repeatedly returns, the player uses the radio.
Possible assistance:
- A second security guard
- Building management
- Police dispatch
- Nearby security personnel
The radio call takes time, so the player must continue monitoring the person while waiting. The player can choose what information to report:
- Location
- Description
- Behavior
- Whether weapons have been seen
- Whether anyone is in immediate danger
Incorrect or exaggerated reports damage the guard’s credibility.
---
## Level 5: Emergency Response
This is reserved for immediate threats, such as:
- A person displaying a weapon
- An attempted forced entry while people are inside
- An assault on the guard or another person
- A serious threat against occupants
- A violent struggle that cannot be safely disengaged
The player presses and holds a clearly marked **Emergency Radio** button. A confirmation prompt prevents accidental activation.
The call brings an off-duty law-enforcement officer or armed emergency responder to the location. This character has greater authority and can control a dangerous situation, but the call has serious consequences:
- The building may be evacuated
- The street may be closed
- The guard’s actions are reviewed
- The building loses reputation
- The player may face an investigation if the call was unjustified
- The officer may use force only when the game’s threat assessment supports it
The officer should not function as a convenient “stronger attack.” Their role is to handle a crisis the player cannot safely manage. In most scenarios, their arrival results in commands, restraint, evacuation, or arrest rather than automatic gunfire.
---
## NPC Behavior Types ## NPC Behavior Types
## Tourists - **Tourists:** take photos, sit on steps, drift toward restricted doors; usually respond well to polite directions.
- **Street performers:** may block stairs or argue when moved; can be redirected to a permitted area.
- Take photos - **Influencers and filmmakers:** film the guard, test boundaries, and create public-relations risk.
- Sit on steps - **Confused visitors:** may have appointments or genuinely believe the building is public; reward patient explanation.
- Wander toward restricted doors - **Intoxicated pedestrians:** move unpredictably, ignore instructions, and need extra distance or assistance.
- Usually respond well to polite directions - **Trespassers:** test entrances, use distractions, and may return after being told to leave.
- **Violent threats:** rare, escalate quickly, and justify emergency response only when behavior shows immediate danger.
## Street Performers - **People in mental-health crisis:** may loiter, behave unpredictably, and respond poorly to aggression; require patience and careful de-escalation. The setting may refer to a 51/50 hold, but the game should present the person respectfully, not as an automatic threat.
- May block stairs
- May become argumentative if moved
- Can be redirected to a permitted area
## Influencers and Filmmakers
- Film the guard
- Test boundaries for content
- May accuse the guard of overreacting
- Create public-relations risk
## Confused Visitors
- Have appointments or directions
- May genuinely believe the building is public
- Reward patient explanations
## Intoxicated Pedestrians
- Move unpredictably
- May ignore instructions
- Require additional distance and assistance
## Trespassers
- Repeatedly test entrances
- Use distractions
- May return after being told to leave
## Violent Threats
- Rare
- Escalate quickly
- Trigger the emergency response system only when their behavior indicates immediate danger
## 51/50s
Crazy Homeless Individuals may be referred to as "51/50s" in the context of the game, indicating a person who may be experiencing a mental health crisis and could pose a potential threat to themselves or others.
- May loiter near entrances
- Can be unpredictable in behavior
- Often respond poorly to aggressive confrontation
- Require careful de-escalation and patience
---
## Special Systems ## Special Systems
## Reputation Meter ### Reputation
The player is evaluated on: The shift evaluates peaceful resolutions, response time, radio accuracy, unnecessary confrontations, public complaints, property damage, entrance security, and whether assistance was justified. Calling armed help too often scores poorly even when no one is hurt.
- Number of incidents resolved peacefully ### Evidence and Body Camera
- Response time
- Accuracy of radio reports
- Number of unnecessary confrontations
- Public complaints
- Property damage
- Whether the entrance remained secure
A player who calls armed assistance too often should score poorly, even if no one was injured. Interactions are recorded automatically. The body camera is a real state the player can toggle; a formal warning also arms it. The shift review uses the recorded events and evidence to show whether the response was justified.
## Evidence and Body Camera ### Crowd Reaction
Interactions are automatically recorded. After each shift, the player reviews incidents and sees whether their escalation was justified. Nearby pedestrians react to the guard. Calm professionalism attracts little attention; aggression draws a crowd; visible weapons or responders can cause panic. Good de-escalation keeps the boulevard moving.
This encourages players to think before acting. ### Radio Limits
## Public Crowd Reaction The emergency radio has a cooldown, and the call requires a short report. Assistance takes time to arrive, so the guard must keep monitoring the situation.
Nearby pedestrians react to the guard’s behavior:
- Calm professionalism attracts little attention
- Aggressive behavior creates a crowd
- Visible weapons or emergency responders cause panic
- Good de-escalation keeps the boulevard moving normally
## Limited Radio Battery or Cooldown
The emergency radio should not be infinitely available. A call has a cooldown and may require the player to give a short report first.
---
## Shift Structure ## Shift Structure
Each shift lasts 10–15 minutes. - **Early:** harmless tourists, delivery workers, people resting on the steps.
- **Midday:** heavier crowds, more entry attempts, more filming.
- **Evening:** lower light, more intoxicated pedestrians and aggressive groups.
- **Late:** a rare serious incident may test whether the player recognizes a real threat without overreacting to ordinary behavior.
### Early Shift ## Outcomes
Mostly harmless tourists, delivery workers, and people sitting on the stairs. A successful shift keeps the building secure, resolves most incidents without force, keeps public access clear, makes justified emergency calls, avoids bystander injuries, and follows policy.
### Midday A poor shift involves excessive force, confronting innocent people, ignoring a real threat, false reports, allowing unauthorized entry, causing a crowd or panic, or behaving recklessly even if the door stayed locked.
Crowds become heavier. More people attempt to enter the building or film interactions. ## Venues
### Evening ### El Capitan Entertainment Centre (6840 Hollywood Blvd)
Lighting decreases. Intoxicated pedestrians and aggressive groups become more common. The original scenario: the historic Masonic Temple / El Capitan Entertainment Centre, with six Ionic columns, eight stone steps, the Hollywood Walk of Fame sidewalk, neighbouring theatre and retail frontage, and the four-lane boulevard. Tourists, performers, influencers, confused visitors, intoxicated pedestrians, trespassers, people in crisis, and rare violent threats approach from the street.
### Late Shift Authorized people are recognized or present a valid wristband. Wristbands vary by color, pattern, date, and event marking, and may be valid, expired, counterfeit, or missing.
A rare serious incident may occur, testing whether the player recognizes a genuine threat instead of overreacting to ordinary behavior. ### The Joke Shop
--- A Sunset Strip comedy club inspired by The Comedy Store at 8433 Sunset Blvd: a
low black hall under a deep, signature-covered canopy, a circular blade sign,
red velvet curtains and the dry hillside rising behind it. The door person
checks IDs, tickets, reservations, guest-list status, and screens guests with a
handheld wand under venue policy.
## Win and Loss Conditions The wand does **not** identify a weapon automatically. Keys, belts, and phones can trigger false alarms; the player must ask the guest to identify the item and apply procedure. A guest with valid credentials can still require assistance if they threaten staff or patrons.
## Successful Shift Typical events:
- Building remains secure - a busy weekend show creates a long line;
- Most incidents are resolved without physical force - a performer arrives through the guest entrance;
- Public access remains clear - a guest has a reservation but no ID;
- Emergency calls are justified - a fake or borrowed ID appears;
- No bystanders are injured - a wand alert comes from keys or a belt;
- The player follows company policy - a guest refuses screening but insists on entering;
- someone tries to follow an authorized person through the door;
- a late audience member arrives during the performance.
## Poor Performance Joke Shop escalation follows the common ladder: direction, explanation, repeat request, refusal, manager/security assistance, emergency only for immediate danger.
- Excessive use of force ### Hollywood Boulevard Late Night TV Studio
- Repeatedly confronting innocent people
- Ignoring a real threat
- Making false radio reports
- Allowing repeated unauthorized entry
- Causing a crowd or panic
A shift can be technically “secure” but still receive a poor rating if the guard behaves recklessly. 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.
## Venues and Scenarios Typical events:
The game should support multiple venues, each with its own access rules, crowd patterns, equipment, and escalation procedures. The core gameplay remains the same: observe, verify access, communicate clearly, and use the lowest effective level of escalation. - a crowd gathers for a celebrity arrival;
- tourists block the entrance for photographs;
- a performer sets up in the audience queue;
- an influencer ignores the filming boundary;
- a confused visitor believes the studio is open;
- an intoxicated pedestrian approaches the stage door;
- a trespasser blends into an audience group;
- an authorized guest arrives without a wristband;
- someone presents a counterfeit credential;
- a violent threat appears during a crowded arrival.
## The Joke Shop ## Presentation and Controls
**The Joke Shop** is a comedy club scenario where the player works as a door person at the entrance. The player is responsible for checking identification, confirming that guests are attending the correct show, and screening guests for weapons with a handheld security wand. The game is first-person: WASD and mouse look, a focus cone on nearby people, a billboarded focus circle, `Tab`/mouse-wheel cycling for aim-free selection, and a radial action menu opened with left click or `Space`. `Shift` is precision walk. Gamepad input is supported, and keys/buttons can be remapped in Settings.
### Primary Responsibilities The action wheel prioritizes de-escalation: Stop, Look, Point, No, Ask, Inspect, Wand, Warn, Block, Reason, Recognize, Radio. Emergency stays on `R` and is not a wheel slice. `W` is walk, never the wand; `C` is the optional wand shortcut.
- Check each guest’s government-issued ID where required. The visual direction is readable stylized realism:
- Confirm that the guest meets the venue’s age requirement.
- Verify that the ID appears valid and belongs to the person presenting it.
- Check tickets, reservations, or guest-list status.
- Use the handheld wand according to venue policy.
- Direct guests through the entrance without blocking the sidewalk.
- Refuse entry when a guest has an invalid ID, no valid admission, or a prohibited item.
### Guest Outcomes - **Character direction:** 12 skinned NPC variants, 18 gear pieces and 20 street/venue props. The active character track is the Quaternius base at runtime ([ADR-0018](docs/adr/0018-quaternius-stage2-runtime-rig.md)): the CC0 source mesh keeps its proportions on the 62-joint rig, Idle/Walk run as clips, and the procedural library stays as the tested fallback until the face/silhouette gate passes. See [Character Creation Re-Evaluation](#character-creation-re-evaluation-2026-11-05).
- **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.
A guest may have: 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.
- A valid ID and ticket 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), [ADR-0017](docs/adr/0017-quaternius-npc-base.md).
- A valid ID but no ticket or reservation
- An expired, damaged, or questionable ID
- An ID that does not match the guest
- A prohibited item detected by the wand
- A harmless item that causes a false alarm
- No ID when identification is required
The player must make decisions based on the venue’s rules and observable evidence, not on a guest’s appearance or attitude. A calm guest with a valid ID should be admitted efficiently, while an aggressive guest with valid credentials may still require assistance if they threaten staff or other patrons.
### Joke Shop Escalation
1. **Nonverbal direction:** Raise a hand, point to the ID-check area, or gesture for the guest to wait.
2. **Routine explanation:** Explain the ID, ticket, or wand-check requirement.
3. **Repeat request:** Clearly state what is missing or what must happen before entry.
4. **Refusal of entry:** Keep the guest outside and direct them away from the entrance.
5. **Manager or security assistance:** Call for a supervisor or another staff member when a guest argues, refuses screening, or blocks the line.
6. **Emergency response:** Call emergency services only for an immediate threat, such as a weapon, assault, or serious attempt to force entry.
The handheld wand should not automatically identify an item as a weapon. The player must interpret the alert, ask the guest to identify the item, and follow venue procedure. The goal is to create a believable screening challenge while keeping the emphasis on communication and proportionate responses.
### Scenario Events
- A busy weekend comedy show creates a long line.
- A performer arrives through the guest entrance and must be recognized or verified.
- A guest forgets their ID but appears on the reservation list.
- A fake or borrowed ID is presented.
- A wand alert comes from keys, a belt buckle, or a phone.
- A guest refuses the screening but insists on entering.
- A disruptive guest attempts to follow another person through the door.
- A late-arriving audience member tries to enter during a performance.
## Hollywood Boulevard Late Night TV Studio
This scenario takes place outside a late-night television studio on Hollywood Boulevard. The guard manages the front steps, studio entrance, guest arrivals, deliveries, audience members, and the public crowd gathered around the building.
The studio encounters all of the NPC types described in the game plan:
- **Tourists** stopping to take photos or watch arrivals
- **Street performers** occupying the steps or performing near the entrance
- **Influencers and filmmakers** recording the guard, guests, or celebrity arrivals
- **Confused visitors** looking for the wrong entrance or trying to attend a show without understanding the access rules
- **Intoxicated pedestrians** approaching the entrance or disrupting the crowd
- **Trespassers** testing the doors, trying to follow authorized guests, or returning after being directed away
- **Violent threats**, which are rare but require careful recognition and emergency escalation
The studio also has authorized guests and staff. They must either be recognized by the guard or present a valid wristband, credential, guest-list confirmation, or other approved access marker. The player must check these credentials without holding up the audience line or allowing unauthorized people to enter.
### Studio Responsibilities
- Keep the front steps and entrance clear.
- Direct tourists and performers away from restricted areas.
- Check wristbands, credentials, tickets, or guest-list status.
- Admit authorized staff, performers, guests, and audience members.
- Manage influencers and filmmakers without unnecessarily obstructing lawful filming.
- Protect celebrity arrivals and production equipment from crowding.
- Coordinate with studio staff, production assistants, and additional security guards.
- Watch for attempts to follow authorized people through the entrance.
- Call for emergency assistance only when there is an immediate threat.
### Studio Scenario Events
- A crowd gathers to watch a celebrity arrive.
- Tourists stop on the steps and block the entrance for photographs.
- A street performer sets up in front of the audience queue.
- An influencer repeatedly ignores the restricted filming boundary.
- A confused visitor believes the studio is open to the public.
- An intoxicated pedestrian wanders toward the stage door.
- A trespasser tries to blend into an audience group.
- An authorized guest arrives without their wristband and must be verified another way.
- Someone presents a counterfeit wristband or credential.
- A violent threat appears during a crowded arrival, requiring the player to protect the entrance while calling for assistance.
The scenario should test the player’s ability to distinguish ordinary Hollywood Boulevard activity from a genuine security problem. The best solution is usually a simple gesture, clear direction, or credential check rather than immediate escalation.
Future venues can reuse this structure while changing the rules, equipment, staff roles, and types of access decisions.
## Tech Stack ## Tech Stack
## Engine: Godot 4 - **Engine:** Godot 4.7.2, GL Compatibility renderer (Web parity); optional Forward+ Desktop HQ build.
- **Language:** GDScript.
- **Architecture:** venue-driven simulation; shared systems plus `Resource`-based scenario data.
- **Navigation:** `NavigationRegion3D` / `NavigationAgent3D`.
- **NPC behavior:** lightweight custom finite state machines driven by `NpcProfile` resources.
- **UI/audio:** Godot `Control` nodes, themes, procedural audio, and JSON-backed localized strings.
- **Persistence:** JSON in `user://` for settings and shift history.
- **Testing:** custom headless runner (`src/test/test_runner.gd`); GUT was evaluated and not adopted. Python tooling tests cover the asset/screenshot pipelines.
- **Source control/CI:** git on Gitea; `.gitea/workflows/build.yml` runs headless checks and builds/publishes releases on tags.
- **Targets:** Windows, Linux, macOS, and Web. Release artifacts include portables, an NSIS installer, an AppImage, a Web zip, and an optional Desktop HQ zip (Forward+ volumetric lighting; Vulkan required).
The game is built with the Godot Engine 4.x editor. Godot was chosen for its free and open-source license, built-in 3D rendering, navigation, animation, audio, and UI systems, and its low weight for fast prototyping and iteration. ## Versioning and Delivery
## Language: GDScript `config/version` in `project.godot` is the single version source (currently `0.9.8`). 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.
Gameplay logic is written in GDScript. It is tightly integrated with the engine, fast to iterate on, and avoids an external build toolchain for the prototype phase. ## Gap Analysis
## Architecture Mapping **Published baseline:** v0.9.8 (2026-11-04) — three playable venues, tutorial/campaign/checkpoint
resume, the access/radio/escalation loop, shift review, the 12-character Blender library, 277
Godot + 162 Python tests, a 21/21 screen-design judge and Compatibility/Web/Desktop HQ builds.
The venue-driven architecture maps onto Godot as follows: **Current source:** 0.9.8. The 0.10.0-rc.1 package built on 2026-11-03 is stale and is superseded
by the patch sequence below; it is not a published release.
- **Nodes and scenes:** Each major system (`ShiftCoordinator`, `NPCController`, `InteractionSystem`, `AccessVerifier`, `EscalationManager`, `RadioSystem`, `IncidentRecorder`, `ReputationEvaluator`, `CrowdSystem`, `ShiftReview`) is a Godot node or scene. | Area | Remaining gap | Milestone |
- **Scenarios as resources:** `VenueScenario` and content such as `NpcProfile`, `Dialogue`, `EventPool`, and `AccessPolicy` are defined as custom Godot `Resource` types so venue content is data-driven and inspectable in the editor. | --- | --- | --- |
- **Navigation:** `NavigationRegion3D` and `NavigationAgent3D` drive NPC and player movement. | Character base | Quaternius arm-down skin export, rest-relative pose composition, face/silhouette acceptance | 0.9.9 |
- **NPC behavior:** Lightweight custom finite state machines built on the `NPCController` node, with behavior traits coming from `NpcProfile` resources. | Character roster | 12-role mapping, modular outfits, gear fit, AO/texels, budget evidence | 0.9.10 |
- **UI:** Godot `Control` nodes and themes for prompts, access inspection, radio reports, dialogue, timers, and the shift review screen. | Venue and asset polish | Ranked prop/foliage/lighting/set-dressing fixes, collider verification | 0.9.11 |
- **Audio:** Godot audio buses and `AudioStreamPlayer` nodes for voices, crowd noise, radio, and environment sound. | Performance and Web | Frame/memory/load evidence after the content changes, LOD/impostor verification | 0.9.12 |
| Onboarding and balance | External first-time-player evidence, balance sweeps/tuning, content lock | 0.10.0 |
| Accessibility and localization | Acceptance pass, caption coverage, pseudo-locale/length checks | 0.9.12 / 0.10.0 |
| QA and release engineering | Full smoke matrix, clean build/checksum verification, target-matrix launches | 0.10.0 |
| Legal, signing, storefront | macOS signing/notarization, AI-provider rights, storefront/rating approval, privacy sign-off | 0.10.0 / 0.12.0 |
| Systems and content depth | Live incident replay, fourth venue, localization foundation | 0.11.0 |
| Distribution | Signed storefront builds, frozen save contract, launch languages, hardware matrix | 0.12.0 |
| Stable release | Content complete, accessibility audit, release candidates, 1.0.0 decision | 0.13.0 / 1.0.0 |
| Future | More venues/seasonal content, image-to-mesh props, other deferred ideas | Unscheduled |
## Content and Data The 0.9.3 UI, 0.9.4 animation, 0.9.5 texture, 0.9.6 integration, 0.9.7 character development and
0.9.8 deformation fixes are complete in [`DONE.md`](DONE.md); they are not remaining gaps. The
2026-11-01 documentation audit is also closed.
- Scenario and entity configuration uses typed Godot `Resource` files (`.tres`), created either in the editor or via scripts. ## Release Roadmap
- Localized dialogue and text are stored in JSON files when they need to be editable outside the editor.
- Save data and shift results use JSON in Godot's `user://` directory.
## Testing Every version below follows the release procedure in `AGENTS.md`. Patch versions contain fixes and
polish; minor versions add user-facing features; the major version is the stable release with a
compatibility promise. Each version's executable checklist is in [`TODO.md`](TODO.md).
- Unit and scenario tests use a lightweight custom headless runner ### Roadmap to 0.10.0
(`src/test/test_runner.gd`). GUT was evaluated but requires the editor plugin.
- Tests run in headless mode so rules, access verification, escalation, and scoring can be verified without rendering or user input.
## Version Control and CI The goal of this line is to finish the character and venue work and clear every public-release
gate. The character track is versioned rather than unversioned so a blocked rig cannot hold the
whole release.
- Source is tracked with git. | Version | Type | Scope | Exit criterion |
- Gitea Actions (`.gitea/workflows/build.yml`) runs headless Godot tests on push/PR and exports | --- | --- | --- | --- |
Linux/Windows/macOS desktop builds plus the NSIS installer and AppImage on tags. | 0.9.9 | patch | Quaternius pilot: correct skin export, rest-relative pose math, Idle/Walk verification, owner face/silhouette gate, one-role (or crowd-only) rollout | A Quaternius NPC renders and animates correctly and ships behind a tested procedural fallback |
| 0.9.10 | patch | 12-role roster, modular outfits, five slots, AO/texels, gear fit, 12×6 baseline | The full roster passes contract, gear, budget and owner-baseline gates |
| 0.9.11 | patch | Scheduled 3D review fixes: props/foliage, gear silhouette, venue shape language, lighting, set dressing, colliders | Every scheduled P1/P2 item is fixed or accepted with a measurement |
| 0.9.12 | patch | Performance/Web/LOD/memory verification plus accessibility and pseudo-locale checks | No regression against the pre-character baselines |
| 0.10.0 | minor | Public readiness: external playtests, balance acceptance, legal/storefront/signing decisions, platform matrix, docs and picture lock | 0.10.0 is content-locked, externally played, legally reviewed, documented and reproducibly built |
## Planned Commands ### Roadmap to 0.11.0
The following commands apply once the Godot project is scaffolded: This line turns a stable 0.10.x into a deeper game: the incident timeline becomes a live replay, a
fourth venue enters the campaign, and the text catalogue becomes a real localization pipeline.
- Open the editor: `godot --editor --path .` | Version | Type | Scope | Exit criterion |
- Run the game: `godot --path .` | --- | --- | --- | --- |
- Run tests headlessly: `godot --headless --path . res://src/test/test_runner.tscn` | 0.10.1 | patch | Onboarding and accessibility issues deferred from the 0.10.0 playtests | First-hour and accessibility defects closed |
| 0.10.2 | patch | Balance/fairness sweeps, review-text and difficulty-progression tuning | Every balance-acceptance cell is in target or explicitly accepted |
| 0.10.3 | patch | Save/checkpoint edge cases, gamepad/remap, pause/resume, small quality-of-life fixes | No known P1 stability defect remains |
| 0.11.0 | minor | Live body-camera replay, fourth venue (candidate: TCL Chinese Theatre forecourt), localization foundation with one secondary language | The new systems ship without regressing performance, accessibility or balance |
## Export Targets ### Roadmap to 1.0.0
Desktop is the first target: Windows, Linux, and macOS. Web export is a later option. This line is about distribution, contracts and completeness: signed builds on the launch stores, a
frozen save format, finished content and release candidates.
## Player Control, Focus, and Action Menu (next pass) | Version | Type | Scope | Exit criterion |
| --- | --- | --- | --- |
| 0.11.1 | patch | Replay/venue/localization fixes from wider play | No P1 defect in the 0.11.0 feature set |
| 0.11.2 | patch | New-venue balance, campaign pacing and content readability | The 0.11.x line is stable enough to freeze its contracts |
| 0.12.0 | minor | macOS signing/notarization, storefront packages/metadata/ratings, save-format v2 freeze, hardware matrix, launch languages | Signed, storefront-ready builds exist on every launch platform |
| 0.12.1 | patch | Signing, installer, metadata and save-migration fixes from storefront dry runs | Every storefront build installs, launches and migrates cleanly |
| 0.13.0 | minor | Content complete: all planned venues/events/dialogue, audio decision, final tutorial, accessibility audit, balance freeze | All planned content is implemented and frozen |
| 0.13.1 | patch | Release candidate 1: full smoke/performance/save/accessibility matrix | A candidate passes every gate except final approval |
| 0.13.2 | patch | Release candidate 2: verify fixes, freeze release notes/credits/privacy/known limitations | The final candidate is reproducible and documented |
| 1.0.0 | major | Stable release: legal/storefront/rating approval, hardware/accessibility/localization sign-off, no P0/P1, publish on every platform | 1.0.0 is published with verified checksums and no open blocker |
The prototype already walks and looks in first person, but the control scheme fights itself and targeting is a hairline. This pass replaces that with three things that belong together: solid locomotion, a visible focus on a person, and a round action menu for what to do with them. ## Roadmap Dependencies and Risks
Decisions: [ADR-0007](docs/adr/0007-locomotion-and-input-layers.md) locomotion and input layers, [ADR-0008](docs/adr/0008-cone-focus-and-head-ring.md) cone focus and focus circle, [ADR-0009](docs/adr/0009-radial-action-menu.md) radial action menu, [ADR-0010](docs/adr/0010-procedural-npc-presentation.md) procedural NPC presentation. - Content volume is the largest schedule risk; tutorial and campaign work must not outrun the
event/dialogue matrix.
### What is wrong today - The vision judge is a dev-time aid with an external key and budget; CI must never make it a hard
gate.
- `W` is walk-forward in the input map and wand-screening in `GameManager._handle_key`. Walking at someone with a wand venue fires the wand. - Godot engine changes can alter lighting and imports; do not combine an engine baseline move with
- `A` / `D` are strafe and also allow/deny during inspection. a content or feature milestone.
- `Q` is polite direction and is also bound as `cancel`. - Signed macOS builds, AI provenance and storefront approval are release blockers, not polish.
- Focus is an 8 m physics ray from the camera. Missing a capsule by a few pixels clears the target. There is no mark in the world that you have someone. - The character pipeline is the current critical path. The rig/export fix must be proven on one
- NPC bodies are colored capsules with props. They read as markers, not people. variant before the roster rollout; otherwise 0.9.10 multiplies a defect.
- Actions live on number keys `1`–`6` plus `Q` / `E` / `W` / `R`. That is a cheat-sheet, not a verb you pick while looking at a person. - Photo-derived map assets add a provenance risk: downloaded or user-supplied photos can carry
- `Esc` only toggles mouse capture. There is no "I changed my mind" for an action in progress. unclear licences, identifiable people, plates and property restrictions. No photo- or
splat-derived asset ships without a completed sidecar, consent/licence review and redaction.
### Movement and look - Gaussian-splat training is GPU/disk-heavy and the toolchain churns; keep it offline,
version-pinned and outside CI, and never make a runtime splat renderer a release dependency.
Keep first-person WASD + mouse look. Fix the feel and stop stealing those keys. - 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
- Body yaw from mouse X, head pitch from mouse Y, pitch clamped (already `-80` to `80`). a skill, asset pack or tool version a build or CI dependency.
- Move relative to body yaw only (already). Add short acceleration / deceleration so starts and stops are not instant. - The 3D re-evaluation can expand without bound. Cap it with the scorecard ranking: P0/P1 only, one
- Gravity only when `not is_on_floor()`; `floor_snap_length` so the steps work. asset family per commit, and an explicit accept for everything else.
- Mouse look runs only while `MOUSE_MODE_CAPTURED` and no modal UI is open (radial, inspection, wand, radio, shift review). - Keep the de-escalation-first rules and rare-emergency design unchanged while adding progression,
- Walk speed stays around 3.2 m/s. No sprint, no crouch in this pass. difficulty and feedback.
- While the radial is open: freeze look and WASD so `A` / `D` can cycle the menu. Recapture the mouse when the menu closes.
- `Esc` with a modal open closes that modal and does nothing else. `Esc` with nothing open keeps the current capture/release toggle.
Equipment stays on its own keys because it is not about a person: `G` flashlight, `L` door lock, `Tab` cycle nearby people, `V` venue (debug), `F` debug overlay. `R` stays the dedicated emergency radio (hold-to-confirm on the existing panel). Those do not go on the wheel.
Wand leaves `W`. It is a slice on the wheel (greyed when the venue has no wand) and an optional extra key that is not WASD, suggested `C`.
### Focus area
Replace the hairline ray as the primary picker.
- A **focus cone** in front of the camera: people within about 10 m whose head projects inside a screen-space circle around the crosshair (about 90 px / 10 degrees).
- If several heads sit in the circle, pick the one closest to the center, then the nearer one if tied.
- The person must be in front (dot with camera forward > 0) and not fully occluded by the building. A short ray to the head is enough for occlusion.
- `Tab` still cycles people inside 12 m as the aim-free path. Cycling sets the same focused person the cone would.
- Clearing: look away until the head leaves the circle for a few frames (small grace so a bob does not drop them), or they walk out of range.
### Focus circle
When a person is in focus, draw a blue, semi-transparent circle in front of their face.
- Attach to the avatar `Head` node, just in front of the face, billboarded to the camera so it stays a circle on screen.
- Slow spin is fine; no ping-pong scale spam.
- Idle focus: blue, semi-transparent, modest size. Radial open on that person: brighter, slightly larger.
- Optional small name under the circle (`display_name` only, not the archetype cheat `Violent Threat` in the world). The existing HUD target line can keep the archetype for the prototype.
- One circle at a time. Everyone else has none.
Implementation sketch: a thin unshaded `MeshInstance3D` circle (flat disc) in front of the face on the avatar, toggled from `GuardController` / `GameManager` when focus changes. Screen-space fallback (unproject head, draw a `Control` circle) is acceptable if the 3D circle z-fights on hats.
### Round action HUD
A doughnut / pie menu centered on the screen, opened on the focused person.
**Open**
- Left mouse button, or `Space`, while someone is in focus and no other modal is open.
- If nobody is in focus, log the existing "aim first" line and do not open.
- The click that opens the menu must not also pick a slice.
**While open**
- Mouse becomes visible. Look and walk freeze.
- Center of the doughnut shows the focused person's `display_name`.
- Slices, clockwise from the top, de-escalation first:
1. Raise hand (stop / wait)
2. Point away
3. Head shake
4. Polite direction (old `Q`)
5. Inspect access (old `E`)
6. Wand (grey if the venue has no wand)
7. Formal warning
8. Block
9. Radio assist
- Emergency is **not** on the wheel (`R` only).
- Highlight follows the mouse angle when the cursor is over the ring. `Left` / `Right` or `A` / `D` step the highlight. Wrap around.
**Confirm**
- Click a slice: that action runs, menu closes, mouse recaptured.
- `Space` while a slice is highlighted: same.
- Inspect or wand: close the wheel, then open the existing inspect / wand panel. Allow / deny on that panel stay `A` / `D` (walk is frozen only while the wheel is up; once the inspect panel is open, WASD can move again, so allow/deny on `A` / `D` remains a press handler and must ignore repeats / echo, which it already does). Safer: keep walk frozen for inspect/wand too, until the panel closes. Prefer freeze until the whole interaction ends.
- Radio assist: close the wheel, open the existing radio panel.
**Cancel**
- `Esc` or right mouse button: hide the menu, no action, no recorder event, recapture mouse.
- Focus and the focus circle stay as they were.
Number keys `1`–`6` may remain as shortcuts that skip the wheel so a smoke-test script still works. They must not fire while the wheel is open (the wheel owns `A` / `D` / `Space`). Document both in the README.
### NPC display
Stay on the procedural capsule rig (no Mixamo / GLB dependency this pass). Make them read as people at conversation distance.
- Neck between torso and head; shoes; simple hair cap (color from seed); two dark eye spheres on the face so a head has a front.
- Keep archetype props (camera, box, hat, sign, bag). Keep height / brightness variation from the visual seed.
- Collision capsule matches the scaled height so the focus ray / cone hits the body you see.
- `Head` stays a named node other systems can find (`get_node("Rig/Head")`) for the ring and the cone.
- Walk bob and the "look at the guard when noticed" cue stay.
- Do not put the internal type name (`Trespasser`, `Violent Threat`) on the body. The player should judge from clothes, props, and behavior. The debug overlay (`F`) can still print the type.
AI textures in `assets/textures/ai/` stay out of this pass unless a specific map (shirt, hair) is already the right size.
### Input map (target)
| Action | Bind |
| --- | --- |
| Walk | WASD / arrows (arrows **do not** walk while the wheel is open; they step the highlight) |
| Look | Mouse, captured |
| Open / confirm action menu | LMB, `Space` |
| Cancel menu | RMB, `Esc` |
| Step highlight | `A` / `D`, left / right arrows |
| Emergency radio | `R` |
| Flashlight | `G` |
| Door lock | `L` |
| Cycle nearby people | `Tab` |
| Wand shortcut | `C` (not `W`) |
| Inspect shortcut | `E` still allowed when the wheel is closed |
### Files this pass is expected to touch
- `src/game/guard_controller.gd` — cone focus, no look while modal, accel, floor snap.
- `src/game/npc_avatar.gd` — face / hair / neck, head marker, ring toggle.
- `src/game/ui/action_radial.gd` — new Control, `_draw` doughnut, slice pick.
- `src/game/ui/hud.gd` — host the radial; stop teaching number-key verbs as the only path.
- `src/game/game_manager.gd` — input routing, freeze flags, open/confirm/cancel.
- `project.godot` — input map.
- `src/core/strings.gd` — controls line, aim-first, no new tone-of-voice.
- `src/test/tests/test_focus_and_radial.gd` — cone pick, wrap, cancel emits nothing, `W` is not wand.
- README controls table and smoke checklist.
## Design Direction ## Design Direction
The game should feel like a tense workplace simulation with occasional crisis moments. The most satisfying outcome is not overpowering an NPC; it is recognizing the situation early and resolving it calmly. The game should feel like a tense workplace simulation with occasional crisis moments. The most satisfying outcome is not overpowering an NPC; it is recognizing the situation early and resolving it calmly.
A useful guiding rule:
> **The player wins by choosing the lowest level of escalation that keeps everyone safe.** > **The player wins by choosing the lowest level of escalation that keeps everyone safe.**
## Future Ideas
- A rare Bob Dobbs cameo (Easter-egg appearance; placement note in `MEMORY.md`).
- Specific unusual NPC behaviors, such as slapping their own face, using hands as scissors, or interacting with props unexpectedly.
- A fifth venue or seasonal events after the 0.11.0 fourth venue proves the venue pipeline.
- Real voice/dialogue audio if the 0.13.0 audio decision does not fund it; an image-to-mesh prop pipeline remains unscheduled.
+27
View File
@@ -0,0 +1,27 @@
# Privacy Note
Gig Line runs locally. The game itself does not include telemetry, analytics,
accounts, advertising, cloud saves or network requests. It does not access the
camera, microphone, contacts or location, and the body-camera feature is a
simulated overlay, not a real recording device.
Player data is written only to Godot's local `user://` directory:
- `settings.json`
- `campaign.json`
- `shift_results.json`
- `shift_state.json`
Those files stay on the player's machine unless the player copies them. Deleting
the files (or the `Gig Line` user directory) resets the profile. See
[`docs/getting-started.md`](docs/getting-started.md#save-data-and-migration) for
locations, migration and rollback instructions.
The repository's development tools can call OpenRouter when a developer supplies
`OPENROUTER_API_KEY`; those calls generate or judge development assets and are
not part of the shipped game. The key and generated review artifacts remain
local/gitignored.
Questions about a storefront release should be checked against the final package
and the provider terms recorded in [`CREDITS.md`](CREDITS.md); external legal and
storefront approval is still pending for 0.10.0.
+169 -323
View File
@@ -1,370 +1,216 @@
# Step Line # Gig Line
Step Line is a workplace security simulation about observation, communication, access verification, and proportionate escalation. The player works security at public-facing venues around Hollywood Boulevard, managing stairs, entrances, crowds, guests, staff, and occasional serious threats. Gig Line is a workplace security simulation about observation, communication, access verification, and proportionate escalation. The player works security at public-facing venues around Hollywood Boulevard, managing stairs, entrances, crowds, guests, staff, and occasional serious threats.
The central design goal is simple: The central design goal is simple:
> The player wins by choosing the lowest level of escalation that keeps everyone safe. > The player wins by choosing the lowest level of escalation that keeps everyone safe.
## Screenshots ## Development Priorities
| | | The active planning order lives in [`PLAN.md`](PLAN.md) (gap analysis and release roadmap), [`TODO.md`](TODO.md) (executable checklist) and [`AGENTS.md`](AGENTS.md):
| --- | --- |
| ![Venue overview: the Hollywood Boulevard entrance with steps, sidewalks, street lamps, and signage](docs/screenshots/01-venue-overview.png) | ![Targeting an approaching NPC with the interaction HUD](docs/screenshots/02-targeting-npc.png) |
| ![Access inspection: wristband/credential check with allow/deny prompt](docs/screenshots/03-access-inspection.png) | ![Radio report form: emergency dispatch panel](docs/screenshots/04-radio-report.png) |
| ![Late night: street lamps lit, marquee glowing, dark Hollywood Boulevard](docs/screenshots/05-late-night-avenue.png) | ![Night shift: guard flashlight cutting through the dark](docs/screenshots/06-night-flashlight.png) |
*Screenshots are generated by [`src/test/capture_screenshots.gd`](src/test/capture_screenshots.gd) from the current build — day and late-night shifts.* 1. **`0.9.9`–`0.9.12` patches** — finish the Quaternius NPC base on the accepted 62-joint runtime, roll it out to the 12 roles, close the scheduled venue/prop/lighting polish, then verify performance, Web and accessibility.
2. **`0.10.0` minor** — public readiness: external playtests, balance acceptance, legal/storefront/signing decisions, the platform matrix and the documentation/picture lock.
3. **`0.10.x` → `0.11.0`** — live incident replay, a fourth venue and the localization foundation.
4. **`0.12.0` → `1.0.0`** — signed storefront builds, a frozen save contract, content complete, release candidates and the stable release.
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 ## ⬇️ Downloads
| Platform | Package | | Platform | Package |
| --- | --- | | --- | --- |
| **Windows — installer** | [`step-line-setup-<ver>.exe`](https://git.allucanget.biz/zwitschi/security-game/releases) · contains all game data, shortcuts + uninstaller | | **Windows — installer** | [`gig-line-setup-<ver>.exe`](https://git.allucanget.biz/zwitschi/security-game/releases) · contains all game data, shortcuts + uninstaller |
| **Windows — portable** | [`step-line-windows-<ver>.exe`](https://git.allucanget.biz/zwitschi/security-game/releases) · 64-bit, no install needed | | **Windows — portable** | [`gig-line-windows-<ver>.exe`](https://git.allucanget.biz/zwitschi/security-game/releases) · 64-bit, no install needed |
| **Linux — AppImage** | [`step-line-<ver>-x86_64.AppImage`](https://git.allucanget.biz/zwitschi/security-game/releases) · single file, `chmod +x` and run | | **Linux — AppImage** | [`gig-line-<ver>-x86_64.AppImage`](https://git.allucanget.biz/zwitschi/security-game/releases) · single file, `chmod +x` and run |
| **Linux — portable** | [`step-line-linux-<ver>.x86_64`](https://git.allucanget.biz/zwitschi/security-game/releases) · 64-bit, `chmod +x` and run | | **Linux — portable** | [`gig-line-linux-<ver>.x86_64`](https://git.allucanget.biz/zwitschi/security-game/releases) · 64-bit, `chmod +x` and run |
| **macOS** | [`step-line-macos-<ver>.zip`](https://git.allucanget.biz/zwitschi/security-game/releases) · unsigned build, quarantine note below | | **macOS** | [`gig-line-macos-<ver>.zip`](https://git.allucanget.biz/zwitschi/security-game/releases) · unsigned build, quarantine note below |
| **Web (browser)** | [`gig-line-web-<ver>.zip`](https://git.allucanget.biz/zwitschi/security-game/releases) · unzip and serve the folder from any static host (no special headers) |
| **Desktop HQ** | [`gig-line-desktop-hq-<ver>.zip`](https://git.allucanget.biz/zwitschi/security-game/releases) · optional Forward+ build with volumetric fog/SDFGI/flashlight; requires a Vulkan-capable GPU/driver |
**All releases:** <https://git.allucanget.biz/zwitschi/security-game/releases> **All releases:** <https://git.allucanget.biz/zwitschi/security-game/releases>
> **Latest: v0.2.12** — release pipeline verified end to end: tag builds create the release and > Downloads are public (no sign-in required) since the host's instance-wide
> upload all five artifacts without any repo secret. > `REQUIRE_SIGNIN_VIEW` was disabled on 2026-10-31.
>
> **Latest published: v0.9.9** — the character-roster patch: all twelve NPCs now
> use the CC0 Quaternius base with the five tint slots, role gear and baked maps.
> Superseded: v0.9.8, the character-development patch: the
> 12-character library, realistic face pass, four crowd-variety variants and the
> wrist/hip/knee deformation fixes. Previous 0.9.x patches added the
> Hollywood/Joke Shop maps, UI/accessibility polish, NPC visual optimization,
> texture/material refinement and integration checkpoint.
>
> **Current source: v0.9.8** — tagged from the same commit. The 0.10.0
> development track remains gated on the Quaternius NPC rollout, local-map work
> and release approvals.
> Releases are built automatically when a `vX.Y.Z` tag is pushed > Releases are built automatically when a `vX.Y.Z` tag is pushed
> (see [`docs/RELEASING.md`](docs/RELEASING.md)); manual builds use > (see [`docs/RELEASING.md`](docs/RELEASING.md)); manual builds use
> `./tools/build_releases.sh`. Installer/AppImage packaging runs in the same pipeline > `./tools/build_releases.sh`. Installer/AppImage packaging runs in the same pipeline
> (NSIS + appimagetool) and uploads with the portable binaries. > (NSIS + appimagetool) and uploads with the portable binaries.
> >
> Note: on this host, downloading release files currently requires sign-in;
> the page and tag URLs are public.
>
> macOS builds are unsigned: right-click → Open, or clear the quarantine with > macOS builds are unsigned: right-click → Open, or clear the quarantine with
> `xattr -dr com.apple.quarantine step-line-macos.zip`. Build instructions and > `xattr -dr com.apple.quarantine gig-line-macos.zip`. Build instructions and
> the release pipeline live in [`docs/RELEASING.md`](docs/RELEASING.md). > the release pipeline live in [`docs/RELEASING.md`](docs/RELEASING.md).
If you are here to develop or test locally instead of downloading, jump to If you are here to develop or test locally instead of downloading, jump to
[Run and Test](#run-and-test) below. [Setup and Run](#setup-and-run) below.
The project is under active development. The design and architecture are documented, and a playable prototype vertical slice exists (Godot 4.3 + GDScript): a procedural Hollywood Boulevard entrance, 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. 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 shift](docs/screenshots/01-venue-overview.png) | **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 at night](docs/screenshots/05-late-night-avenue.png) | **Hollywood Boulevard — late.** Sconces pool on the limestone, street lamps light the boulevard and the skyline fades into night haze. |
| ![Flashlight on the entrance at night](docs/screenshots/06-night-flashlight.png) | **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 at night](docs/screenshots/12-joke-shop.png) | **The Joke Shop.** A black Sunset Strip club under its signature-covered canopy, circular blade sign, red curtains and the dry hillside behind. |
| ![Late-night TV studio arrival](docs/screenshots/13-studio-arrival.png) | **TV Studio arrival.** Stone facade, bulb canopy, black car and crowd barriers for a late celebrity arrival. |
### Interaction and systems
| | |
| --- | --- |
| ![Targeting an NPC](docs/screenshots/02-targeting-npc.png) | **Focus and targeting.** The cone focus ring, name tag and target chip; `Tab`/wheel cycles nearby people without aiming. |
| ![Access inspection](docs/screenshots/03-access-inspection.png) | **Access inspection.** A venue-correct wristband check with evidence shown before the admit/refuse decision. |
| ![Radio report](docs/screenshots/04-radio-report.png) | **Radio report.** Security assistance with location, behaviour and what was actually seen. |
| ![Wand screening](docs/screenshots/07-wand-screening.png) | **Wand screening.** A false alarm on keys: ask the guest to identify the item before choosing a response. |
| ![Escalation HUD](docs/screenshots/08-escalation-hud.png) | **Escalation.** Level 3 blocking with the shape meter, body camera armed and the reaction log. |
| ![Body-camera timeline](docs/screenshots/09-body-camera-timeline.png) | **Body-camera timeline.** Every recorded event, step by step, in the shift review. |
| ![Precision walk](docs/screenshots/11-precision-walk.png) | **Precision walk.** Half-speed close work on the steps, with the HUD state chip visible. |
### Shell and UI
| | |
| --- | --- |
| ![Start menu](docs/screenshots/14-start-menu.png) | **Venue menu.** Day and night rows for Hollywood, the Joke Shop and the TV Studio, campaign continue and review links. |
| ![Settings](docs/screenshots/16-settings-panel.png) | **Settings.** Difficulty, volumes, HUD scale, reduce motion, captions and key/button remapping, all persisted. |
| ![Shift review](docs/screenshots/17-shift-review.png) | **Shift review.** Grade, policy outcome, incidents, responder results and campaign Continue. |
| ![Action wheel](docs/screenshots/19-radial-menu.png) | **Action wheel.** De-escalation first: stop, look, point, no, ask, inspect, warn, block, reason, recognize, radio. |
### 3D asset progress
The character roster is built from the CC0 Quaternius bases (ADR-0017/ADR-0018) and audited
before use; the procedural library and the MakeHuman head stay as the tested fallback. The
sheets below show the
current library and will be replaced after the 12 × 6 baseline review.
| | |
| --- | --- |
| ![Eight NPC characters](docs/blender_previews/sheet_npc.jpg) | **Character library.** Twelve role-dressed variants (4.5–6.4k triangles each) on three CC0 Quaternius bases, with five tint slots, attach-point gear and baked maps. |
| ![Prop library](docs/blender_previews/sheet_props.jpg) | **Street and venue props.** Twenty library props with colliders, navigation avoidance and colour atlases. |
| ![Neutral NPC baseline](docs/blender_previews/sheet_npc_baseline.jpg) | **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 comparison](docs/blender_previews/sheet_texture_refinement_0.9.5.jpg) | **Texture refinement.** 128 → 256 px NPC maps and a 4× fabric weave, shown before/after on the same camera. |
| ![Crowd-variety prototypes](docs/blender_previews/sheet_npc_crowd_prototypes.jpg) | **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 ## Game Overview
A typical shift lasts 10–15 minutes. The player: A typical shift lasts 10–15 minutes: watch the entrance and sidewalk, judge why
each person is approaching, verify access with recognition, wristbands, IDs,
1. Watches the entrance, steps, queue, and surrounding sidewalk. tickets or credentials, and escalate only when necessary. The game rewards calm
2. Determines why each person is approaching. resolution over force. The venue menu splits Hollywood Boulevard into Day and
3. Uses simple gestures or polite directions first. Night rows; the full mechanics — the three venues, the six-level
4. Verifies authorized access using recognition, wristbands, credentials, tickets, or guest lists. escalation model, and the core systems — are in
5. Escalates only when a person refuses directions, attempts unauthorized entry, or presents a genuine threat. [`docs/gameplay.md`](docs/gameplay.md); the design rationale lives in
6. Records the incident through body-camera and radio systems. [`PLAN.md`](PLAN.md).
7. Finishes the shift with a performance review based on safety, judgment, and professionalism.
The game rewards calm resolutions rather than aggressive behavior. Emergency assistance and armed responders are rare last-resort systems with meaningful consequences.
## Planned Venues
### Hollywood Boulevard Building
The original scenario places the guard at the top of the steps outside a fictional building. 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.
### The Joke Shop
The Joke Shop is a comedy-club scenario. The door person checks IDs, tickets, reservations, and guest-list status, then uses a handheld security wand according to venue policy. The player must interpret wand alerts rather than treating every alert as proof of a weapon; keys, belts, phones, and other harmless objects can trigger false alarms.
### Hollywood Boulevard Late Night TV Studio
This scenario combines the previously defined NPC types with a busy television-studio entrance. 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.
## Escalation Model
The common escalation model has six levels:
0. **Observation** — Decide whether intervention is necessary.
1. **Simple deterrence and polite direction** — Raise an open hand, make eye contact, point toward the sidewalk or check-in area, shake the head, or give a short instruction.
2. **Formal warning** — Clearly explain the rule and request compliance.
3. **Blocking and physical positioning** — Secure the entrance, maintain distance, preserve an escape route, and deny access without starting a fight.
4. **Radio for security assistance** — Request a supervisor, second guard, building management, or other appropriate support.
5. **Emergency response** — Hold the emergency-radio button and confirm only when there is an immediate threat, such as a weapon, assault, forced entry, or serious threat to occupants.
An off-duty law-enforcement officer or armed emergency responder may arrive during a valid emergency. This character is not intended to be a routine stronger attack. Their role is crisis control, evacuation, restraint, arrest, or other appropriate intervention, with force governed by the situation and meaningful consequences for unjustified calls.
## Core Systems
- **NPC behavior:** NPCs have different motivations, temperaments, compliance levels, and reactions to the player’s approach.
- **Access verification:** Recognition, wristbands, IDs, tickets, credentials, and guest lists determine who may enter.
- **Nonverbal deterrence:** Small actions such as raising a hand can resolve low-risk situations without dialogue or force.
- **Dialogue:** Polite directions and warnings affect outcomes; simple gestures can resolve low-risk situations without dialogue.
- **Escalation:** The player chooses the lowest effective response.
- **Radio assistance:** Calls require useful information and may take time to arrive.
- **Evidence:** Body-camera records support shift review and accountability.
- **Crowd reaction:** Aggressive behavior, visible weapons, and emergency response can create panic or attract a crowd.
- **Reputation:** Peaceful resolutions, accurate reports, low property damage, and justified calls improve performance; unnecessary confrontations and false reports reduce it.
- **Shift review:** The player receives feedback on access decisions, escalation choices, public complaints, injuries, and security outcomes.
## Architecture Overview
The planned solution uses a venue-driven simulation architecture. Venue configuration supplies rules, access types, NPC pools, equipment, events, and escalation policies. Shared simulation systems provide movement, perception, interactions, dialogue, access verification, escalation, radio calls, crowds, reputation, evidence, and shift review.
```text
Venue Scenario / Rules
|
v
Shift Coordinator -----> Event Scheduler
| |
v v
NPC Simulation <---------- Interaction System
| |
v v
Access Verification ----> Escalation / Response
| |
+-------------> Reputation / Evidence
|
v
Shift Review
```
The architecture maps onto Godot 4 nodes, scenes, and custom resources as described in [Tech Stack](#tech-stack). See the full arc42-style outline in [`docs/architecture.md`](docs/architecture.md) and the decisions in [`docs/adr/`](docs/adr/).
## Tech Stack
- **Engine:** Godot Engine 4.x
- **Language:** GDScript
- **Architecture:** Venue-driven simulation using nodes, scenes, and custom `Resource`-based scenario data
- **Navigation:** `NavigationRegion3D` and `NavigationAgent3D`
- **NPC behavior:** Custom lightweight finite state machines driven by `NpcProfile` resources
- **UI and audio:** Godot `Control` nodes, themes, audio buses, and `AudioStreamPlayer` nodes
- **Art assets:** authored PNGs and the in-game generated set in `assets/textures/ai/game_ready/`; structural geometry stays procedural (`WorldBuilder`). The legacy `tools/generate_textures.py --ai` batch remains available.
- **Asset tooling:** `tools/asset_pipeline.py` generates role-aware assets through OpenRouter and provides crop, resize, seamless-tile, and image-audit commands, including gameplay screenshot checks.
- **Testing:** GUT (Godot Unit Test) in headless mode
- **Source control:** git on a Gitea host with Gitea Actions (`.gitea/workflows/build.yml`) for headless tests and desktop release builds
- **Targets:** Windows, Linux, and macOS desktop first; web later
### Image Asset Tools
Install the Pillow dependency used by the existing texture generator and the asset tools:
```bash
python3 -m pip install -r requirements-tools.txt
```
Generate a role-sized image (generation requires `OPENROUTER_API_KEY`):
```bash
python3 tools/asset_pipeline.py generate --prompt "weathered red brick" --role tile --output assets/textures/brick_extra.png
```
Generated images are resized to the selected role profile. Non-square requests use
the validated `openai/gpt-5-image-mini` source ratio and crop to the final role dimensions.
Transparent glyphs can be recolored while preserving their alpha mask with
`--foreground '#ffffff'`.
Crop uses the image center by default; `--x` and `--y` select an explicit crop origin. Resize defaults to aspect-preserving `contain`; use `--fit cover` to crop or `--fit stretch` to distort to the exact dimensions.
```bash
python3 tools/asset_pipeline.py crop assets/textures/source.png assets/textures/crop.png --width 256 --height 128
python3 tools/asset_pipeline.py resize assets/textures/source.png assets/images/backgrounds/scene.png --width 1920 --height 1080 --fit cover
python3 tools/asset_pipeline.py seamless assets/textures/rough_tile.png assets/textures/tile.png
```
Audit accepts image files or directories. `--role auto` infers common roles from paths and filenames; explicit roles include `tile`, `texture`, `icon`, `card`, `banner`, `backdrop`, `background`, `overlay`, `app_icon`, and `screenshot`.
```bash
python3 tools/asset_pipeline.py audit assets/textures
python3 tools/asset_pipeline.py audit assets/images/backgrounds --role background --json
python3 -m unittest discover -s 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.
### Screen design references
Screen mockups and screenshot comparison use `tools/screen_designs.py`. It turns the
screen descriptions in `docs/` (README captions, ADRs 0007–0010, `PLAN.md`, and
`architecture.md`) into reference images under `docs/screens/designs/`, then uses
those images as the expected state to check the game's captures.
Each screen is tagged `scene` (a realistic first-person 3D world view) or `ui`
(an in-game panel overlaid on a softened scene), and the generator appends a
shared art-direction suffix so the frames read as one coherent game. Requests use
a 3:2 landscape source and crop to the 16:9 capture dimensions.
```bash
# Deterministic wireframes (offline, no API key)
python3 tools/screen_designs.py generate --draft
# Realistic 3D scenes and in-game screen designs via OpenRouter
# (requires OPENROUTER_API_KEY)
python3 tools/screen_designs.py generate
# Compare docs/screenshots/*.png against the designs
python3 tools/screen_designs.py compare
python3 tools/screen_designs.py compare --json
```
`compare` flags gross drift: wrong aspect ratio, undersized frame, near-blank
frame, and large layout/palette/detail distance. It is a regression gate, not a
semantic judge — pixel and perceptual metrics cannot decide whether a frame's
composition is *right*, so a vision-model pass is the documented follow-up (see
`TODO.md`). Regenerate the designs after changing screen layout, then re-run
`compare` after regenerating the game screenshots with
`src/test/capture_screenshots.gd`.
### Setup
1. Download the Godot 4.3 editor (official build) and put `godot` on your PATH.
2. Open or run the project from this directory.
### Run and Test
```bash
# Open in the editor
godot --editor --path .
# Run the game
godot --path .
# Headless smoke boot (120 frames then exit)
godot --headless --path . --quit-after 120
# Run all unit tests headlessly (exit code 0 = pass)
godot --headless --path . --script res://src/test/test_runner.gd
# Save a screenshot to user:// (windowed)
godot --path . --script res://src/test/take_screenshot.gd
# Windowed control smoke: focus circle + action wheel, saves PNGs, exits 1 on failure
godot --path . --script res://src/test/smoke_focus_radial.gd
# Session-shell smoke: menu → shift → pause → settings → menu (headless or windowed)
godot --headless --path . --script res://src/test/smoke_session_shell.gd
# PLAN-verb smoke: recognize, request reason, body camera, warning, blocking
godot --headless --path . --script res://src/test/smoke_plan_verbs.gd
# Crowd smoke: rubbernecking on aggression, panic clearing the entrance
godot --headless --path . --script res://src/test/smoke_crowd.gd
# Emergency smoke: unjustified call, investigation note, evacuation aftermath
godot --headless --path . --script res://src/test/smoke_emergency.gd
# Body-camera timeline smoke: review → timeline → step through → back to review
godot --headless --path . --script res://src/test/smoke_timeline.gd
# Audio smoke: crowd bed follows mood, radio open/close crackle
godot --headless --path . --script res://src/test/smoke_audio.gd
```
The unit test runner is the project's own lightweight harness (no editor plugin required) so CI can run it without the editor.
### Controls
| Input | Action |
| --- | --- |
| W/A/S/D + mouse | Move and look |
| Space / left click | Action wheel for the focused person (Stop, Look, Point, No, Ask, Inspect, Wand, Warn, Block, Reason, Recognize, Radio) |
| A / D or ←/→ | Step through the action wheel (while it is open) |
| Space / left click | Confirm the highlighted action (while the wheel is open) |
| Esc / right click | Close the top panel; Esc with nothing open pauses the shift (Esc again resumes) |
| ← / → or ↑ / ↓ | Navigate the venue menu and the pause / settings panels |
| Enter | Start the highlighted venue from the menu, or confirm in a panel |
| 1 / 2 / 3 | Quick gestures without the wheel: raise hand, point, head shake (Level 1) |
| Q | Polite direction (Level 1) |
| 4 | Formal warning (Level 2) |
| 5 | Blocking and positioning (Level 3) |
| 6 | Security assistance radio (Level 4) |
| R | Emergency radio, hold on-screen button ~1.6s (Level 5) |
| E | Inspect access artifacts / close inspection |
| C | Handheld wand screening (wand venues only) |
| A / D | Allow / deny entry during inspection or wand check |
| V | Cycle venue (debug shortcut; restart via V restarts the current shift) |
| Tab | Cycle target among nearby NPCs (aim-free alternative) |
| G | Toggle flashlight (widens NPC perception at night) |
| B | Toggle the body camera; a formal warning switches it on automatically |
| L | Lock / unlock the restricted door (thwarts forced entry) |
| F | Toggle debug overlay |
## Architecture ## Architecture
The full arc42-style architecture documentation lives in [`docs/architecture.md`](docs/architecture.md). It covers goals, constraints, context, solution strategy, building blocks, runtime views, deployment, cross-cutting concepts, quality requirements, risks, a glossary, the CI/CD build pipeline, semantic versioning, and release management. A venue-driven simulation: shared systems (movement, perception, interaction,
access verification, escalation, radio, crowd, reputation, evidence, shift
review) driven by per-venue scenario data, on Godot 4 + GDScript. The full
arc42-style document is [`docs/architecture.md`](docs/architecture.md);
decisions are recorded as ADRs in [`docs/adr/`](docs/adr/).
## Tech Stack
- **Engine:** Godot 4.7.2 · **Language:** GDScript
- **NPCs:** CC0 Quaternius skinned library (`assets/models/blender/`, ADR-0018) with a tested procedural fallback; lightweight FSMs on `NpcProfile`
- **World:** procedural `WorldBuilder` + generated prop models
- **Art:** v2 skyline/surface textures in `assets/textures/ai/game_ready/v2/picks/`; UI/scene art in `assets/images/`
- **Asset tooling:** `asset_pipeline.py`, `model_pipeline.py`, `npc_pipeline.py`, `blender_assets.py`, `scene_concepts.py`, `screen_designs.py`, `check_screenshots.sh`
- **Testing:** custom headless runner (`src/test/test_runner.gd`)
- **Targets:** Windows, Linux, macOS, Web
The asset pipelines, model tools, and screenshot gates are documented in
[`docs/asset-tooling.md`](docs/asset-tooling.md).
## Setup and Run
```bash
python3 -m pip install -r requirements-tools.txt
godot --editor --path . # open in the editor
godot --path . # run the game
godot --headless --path . --script res://src/test/test_runner.gd # run all tests
```
Full setup, every run/test/smoke command, and the controls table are in
[`docs/getting-started.md`](docs/getting-started.md).
## Project Documentation ## Project Documentation
- [`PLAN.md`](PLAN.md) — Game design plan and scenario details. - [`PLAN.md`](PLAN.md) — Game design plan, development priorities and scenario details.
- [`AGENTS.md`](AGENTS.md) — Development and collaboration workflow. - [`TODO.md`](TODO.md) — Priority-ordered tasks: character and local-map development, release milestones, and future work.
- [`TODO.md`](TODO.md) — Active checkbox task list. - [`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.
- [`docs/makehuman-head-review.md`](docs/makehuman-head-review.md) — Local MakeHuman head prototype, provenance and review verdict.
- [`AGENTS.md`](AGENTS.md) — Development, commit, build and collaboration workflow.
- [`DONE.md`](DONE.md) — Completed task sections. - [`DONE.md`](DONE.md) — Completed task sections.
- [`MEMORY.md`](MEMORY.md) — Persistent session notes. - [`MEMORY.md`](MEMORY.md) — Persistent session notes.
- [`CHANGELOG.md`](CHANGELOG.md) — User-facing changes by version.
- [`docs/architecture.md`](docs/architecture.md) — arc42-style architecture documentation. - [`docs/architecture.md`](docs/architecture.md) — arc42-style architecture documentation.
- [`docs/gameplay.md`](docs/gameplay.md) — Gameplay systems, venues, and the escalation model.
- [`docs/venues.md`](docs/venues.md) — Real-site references, game mapping and limitations for Hollywood, the Joke Shop and the TV Studio.
- [`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.
- [`docs/known-limitations.md`](docs/known-limitations.md) — Release-candidate blockers and accepted limitations.
- [`docs/release-qa.md`](docs/release-qa.md) — Manual smoke checklist and release-candidate balance protocol.
- [`CREDITS.md`](CREDITS.md) — Credits, AI/reference provenance and licensing notes.
- [`PRIVACY.md`](PRIVACY.md) — Local-only data, save files and development API use.
- [`docs/blender-assets.md`](docs/blender-assets.md) — Blender asset library: characters, gear, props, attach points.
- [`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/adr/`](docs/adr/) — Architecture Decision Records. - [`docs/adr/`](docs/adr/) — Architecture Decision Records.
## Development Status ## Development Status
Implemented so far: v0.9.8 is the current source version: the character-development patch with the
12-character library, realistic face and crowd variants, pose/deformation fixes
and save-migration/release hardening. It sits on the 0.9.6 integration
checkpoint, 0.9.5 texture refinement, 0.9.4 NPC visual optimization, 0.9.3
UI/accessibility polish, 0.9.2 Hollywood/Joke Shop maps and the 0.9.x engine
baseline. The active work is the `0.9.9`–`0.9.12` patch line (Quaternius NPC
base, roster, venue/asset polish, performance) followed by the `0.10.0`
public-readiness minor. 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
[`docs/release-qa.md`](docs/release-qa.md).
- Godot 4.3 project scaffold, input map, procedural world builder ## Credits, Privacy and Accessibility
- Venue-driven simulation core: `ShiftCoordinator`, `VenueScenario`, `EventScheduler`, `NPCController` + FSM, `AccessVerifier`, `EscalationManager`, `RadioSystem`, `IncidentRecorder`, `ReputationEvaluator`, `CrowdSystem`
- Three authored scenarios (Hollywood Boulevard building, The Joke Shop, Late Night TV Studio) with access policies, NPC archetypes, and event pools
- Headless unit tests: **139 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, 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)
- 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`)
- Session shell: venue start menu (keyboard + mouse), Esc pause overlay (resume / restart / settings / quit to menu), settings panel with mouse-look sensitivity and HUD font scale persisted to `user://settings.json`, and "Run another shift" returning to the venue menu
- World presentation: skyline backdrop rendered with an alpha material, walkable step and landing colliders, larger marquee text, and larger focus circle / name tag
- Routine traffic despawns after a while at its waypoint so the crowd cap no longer fills with idle standers
- PLAN verbs: eye contact (distinct Level 1 cue), recognizing a person as a player decision recorded as access evidence, a body-camera flag that a formal warning arms (and `B` toggles), blocking that physically stations the guard between the person and the door, and a Level 3 request-reason ask answered from the NPC's `dialogue_lines`
- Incidents are now actually opened on focus and closed at shift end, so player actions, access evidence, escalation levels, and unresolved interactions reach the review (previously every recorded event was dropped)
- Crowd presentation: aggressive behavior and responder arrivals make idle bystanders stop and face the incident; panic sends people away from the door (and they leave the scene). A busy 16-NPC entrance measured ~1.2 ms/frame, so no LOD/culling was needed at the current cap
- Distant skyline ring: four alpha-scissored planes at 200 m read as a hazy city on the horizon (the baked backdrop used to show as a black slab), with a larger ground plane so the buildings meet the street
- Flashlight aims straight ahead and lights the person/door being checked instead of the ground in front of the guard
- Emergency aftermath: the `evacuation` outcome locks the door and clears the entrance, an emergency call that the situation did not justify opens an investigation and applies the false-report hit, and the shift review names the responder outcome and any investigations
- Body-camera timeline: the shift review opens a text timeline of every recorded incident event (time, person, action/outcome) that you step through with the arrow keys or buttons. No live 3D replay yet
- NPC theater: seated guests sit on the steps with bent legs, influencers and tourists raise a camera prop while photographing, performers sway their sign, and filming visitors pan slowly — all once they reach their intent's waypoint
- Audio: a looping procedural crowd bed (filtered murmur) whose volume follows `CrowdSystem.mood`, plus radio open/close crackle. All generated at runtime, no audio assets, and safe with a dummy audio server
- Accessibility: the escalation cue shows a shape meter plus the numeric level (`Escalation: Blocking [###--] L3/5`) so it reads in grayscale, and the HUD font scale from settings is applied at boot by resizing fonts (not Control.scale, which broke the right-aligned layout)
- Visual polish pass (v0.2.0): phase-based lighting (sun/sky/ambient per shift phase), street lamps with night-mode bulbs and omni lights, glowing marquee signage, crosswalk, planters and low-poly street trees, NPC height/brightness variety, denser routine traffic — day and late-night screenshot sets
- Assets pass: authored textures in `assets/textures/` (brick facade, concrete, asphalt, awning, skyline, vignette, HUD icons, access-card art) generated by `tools/generate_textures.py`, soft sun shadows, humanoid NPC rigs with archetype props + procedural walk bob and attention head-turn, inspection artifact cards, escalation vignette, mode icons, and a body-camera overlay (REC + shift clock)
Not yet implemented: live 3D body-camera replay, editor-based GUT integration, and crowd performance profiling/LOD (see `TODO.md`). Gig Line is a local-only single-player game: there is no runtime telemetry or
network service, and saves stay in Godot's local `user://` folder. The
### Smoke Test Checklist body-camera overlay is simulated. Asset provenance, AI-assisted image usage and
credits are recorded in [`CREDITS.md`](CREDITS.md); the local-data policy is in
1. `godot --path .` starts the game on the venue menu without script errors. [`PRIVACY.md`](PRIVACY.md); accessibility features and gaps are in
2. Choosing a venue (click or ↑/↓ + Enter) starts that venue's shift and hides the menu. [`docs/accessibility.md`](docs/accessibility.md); and release-candidate blockers
3. The guard moves and looks around; the building, steps, and sidewalk are visible. are listed in [`docs/known-limitations.md`](docs/known-limitations.md).
4. The guard's camera sits at eye height and the guard stands on the landing, not inside the building.
5. Walking into the steps carries the guard up onto the landing (steps have colliders).
6. The skyline backdrop shows silhouettes against the sky, not an opaque black slab.
7. The `STEP LINE` marquee is readable from the sidewalk.
8. NPCs spawn and approach the entrance during the first minutes.
9. Looking at an NPC inside the focus cone shows a blue focus circle in front of the face, the person's name, and the HUD target line.
10. `Space` or left click opens the action wheel; `A`/`D` highlight a slice, `Space` confirms it, `Esc`/right click cancels without a log entry.
11. `E`/`C` open the inspection/wand panels from the wheel and freeze movement until they close; walking never fires the wand.
12. Pressing `Q` produces a reaction log entry and reputation feedback.
13. `E` opens access inspection showing venue-correct artifacts and policy result; `A`/`D` record a decision.
14. `6` opens the assistance form; submitting shows dispatch feedback.
15. `R` opens the emergency form; the button must be held ~1.6s or the call cancels.
16. `G` toggles the flashlight (indicator appears in the HUD); `L` toggles the door lock (indicator turns red when locked).
17. `F` toggles the debug overlay with NPC states and shift stats.
18. The wheel's `Look` slice is eye contact (Level 1) and logs as its own action.
19. `Reason` asks why the person is there and logs their `dialogue_lines` reply.
20. `Recognize` records the guard's recognition as access evidence; pressing it twice says so.
21. `Warn` turns the body camera on (REC overlay appears); `B` toggles it manually.
22. `Block` moves the guard between the person and the door.
23. The shift review reports the incident count, including interactions left unresolved.
24. Escalating on someone (or a responder arriving) makes idle bystanders stop and face the incident.
25. Repeated alarms panic the crowd and nearby people clear away from the door instead of standing around.
26. `Esc` with nothing open pauses the shift; resume / restart / settings / quit-to-menu all work, and settings changes persist across a restart.
27. NPCs route around the building using the navigation mesh (no stuck-at-wall behavior during a smoke run).
28. An unjustified emergency call (calm person, no weapon) logs an investigation and costs reputation.
29. After an evacuation outcome the door is locked and NPCs are leaving the entrance.
30. The shift review's "Body camera timeline" button steps through the recorded events (Left/Right or the buttons) and Esc returns to the review.
31. The escalation label shows a `[###--] L3/5` shape meter as well as the level name, and stays readable in grayscale.
32. Changing "HUD font scale" in Settings resizes the HUD text and persists across a restart.
33. When the shift timer reaches 0, the shift review screen shows grade, incident summary, responder outcomes, investigations, and persisted shift history; "Run another shift" returns to the venue menu.
## Development Workflow ## Development Workflow
+1187 -49
View File
File diff suppressed because it is too large. Load diff
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1007 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1004 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1000 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 954 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 910 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 971 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1021 KiB

File diff suppressed because it is too large. Load diff
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Loaded 100 of 518 files, more files were not shown because too many files have changed in this diff. Show more