20 KiB
MEMORY
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
-
Local-only reference override (2026-11-03, owner): development-only photo research ignores the licence gate. Downloads live in
tmp/research/(gitignored): DDG image search, street-view frames, neighbouring buildings — never committed, never shipped. Promotion intodocs/screens/refs/always passes the sidecar licence + privacy gate andCREDITS.md. -
AI-assisted asset review loop (2026-11-04): head/face shape decisions use a concept + judge loop — generate a target concept (
generate_textures.generate_image, Seedream) and usetools/describe_image.pyas the vision judge, iterating until the judge's specific fixes 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-contractandgig-line-release-qa. They are guidance only, add no runtime dependency and are referenced fromtools/README.md. The third-partyblender-skillspack 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-boulevardanddocs/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/imagesis text-to-image only; the working path isPOST /v1/chat/completionswith acontentarray carrying a base64image_url. Response images arrive asmessage.images[].image_url.url(fallback: a data URI inside the message text). Implemented ingenerate_textures.generate_image(reference_path=...)andscene_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_ashlarfield (warm tintColor(0.85, 0.81, 0.74)) withstone_stepsfor trim; the Joke Shop usesdark_stucco; the marquee canopy/sign box stayblack_metalby design (fictional "GIG LINE" marquee, not the red El Capitan Theatre marquee next door). The TV Studio reusesmasonic_facade. Committed Comedy Store refs were removed in favour of the local-onlytmp/research/comedy-store/set; the three-up board's photo panel is a historical public-domain frame. -
Godot 4.7.2
--importgotcha: with a stale.godot/cache, new image files never import (no.importcreated) andpreload()of the new texture fails every dependent script with the misleadingCould not resolve external class member "spec". Fix: import in a scratch copy with.godot/removed, then copy back the.png.importand.godot/imported/*.ctex/.md5. -
Blender skills pack (local aid): MIT
blender-skillsat.agents/skills/blender-skills/(94 skills + sharedreferences/), 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/skillsbehind 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-acceptancedefines 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_VERTSintools/blender_assets.py;npc_pipeline.MAX_TRIANGLES/MAX_VERTICES). The required 13 core bones stay, optional extra bones are allowed, and the low-polynpc_basefallback 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_basesoNpcAvatar, 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 proceduralnpc_baseremain tested fallbacks until the Quaternius rollout ships. Quaternius source: CC0, attribution inCREDITS.md; the three researched GLBs and licence notes are kept intmp/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:
NpcAvatarmaps 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'sgodot-runnercannot load arbitrary project paths (compiled without path overrides); use the official editor binary. -
GDScript/architecture: cross-file references use explicit
preload()constants (notclass_name) so scripts compile in headless--scriptruns; the test runner is a custom minimal harness (not GUT, which needs the editor plugin); no autoload signal bus —ShiftCoordinatorowns theEventBusinstance passed to subsystems. -
Skinned NPCs (v0.6.0):
NpcAvatar._build_skinned_body()loadsnpc_base.glb; procedural_build_body()is the fallback. Bone pose rotation is the absolute local orientation, not an offset — compose withget_bone_rest(i).basisor the body snaps to a broken pose. Five tint slots viaSurfaceMaterials.npc_slot(); keep_rig.scaleuniform on the skinned path. -
NPC facing: the avatar's visual front is +Z; Godot
look_at()aims -Z (made NPCs walk backwards). UseNpcAvatar.yaw_towards(dir)and setrotation.y; neverlook_at()on avatars. Head-turn offsets use+basis.zfor 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. -
Release roadmap (2026-11-05, owner):
0.9.9Quaternius pilot base (rig/export fix, rest-relative pose math, owner face/silhouette gate),0.9.1012-role roster,0.9.11scheduled venue/prop/lighting polish,0.9.12performance/Web/accessibility verification,0.10.0public-readiness minor, then0.10.1–0.10.3fixes,0.11.0replay + fourth venue + localization foundation,0.12.0signed/storefront builds + save v2,0.13.xcontent complete and release candidates,1.0.0stable. The full gap analysis and roadmap live inPLAN.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_rotationoffsets from the bone rest, so the correct swing around a world axis isrest * Quaternion(rest.inverse() * axis, angle). For the old 180° rest this reduces to the legacyrest * Quaternion(axis, angle), so the 13-core fallback is unchanged (commit8b1bf73). -
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.
Gotchas / Known Issues
- Two character builders — do not confuse them.
tools/blender_assets.pyis the real builder for the eight library characters, 18 gear pieces and props (it has the 0.9.4 face/hand sculpting in_face()/_hands_and_shoes());tools/npc_pipeline.pybuilds onlyassets/models/generated/npc_base.glb, the frozen plain-primitive fallback. Readingnpc_pipeline.pyto judge the library's face/hand detail is wrong. - Pose capture fixed (2026-11-04): the harness was missing
set_physics_process(false)/set_process(false)on the avatar, so the FSM (_advance_fsm+_move_toward_target) ran every tick, resetarrived/velocity and madetheater_pose()revert to idle/rest. Disabling both fixes it (sit vs idle diff 5.63, walk vs idle 2.29). The earlier "moving theRigchild does not render" probe was a red herring — it set the position inside_shoot()in the same frame asroot.get_texture().get_image(), so it never rendered a frame. Lesson: pose/portrait harnesses must freeze the avatar's process/physics before driving_animate(). - Capture/pose harness gotchas: scripts that read captured-mouse input must run windowed
(
smoke_props.gd); the NPC FSM rewritesrotation.yevery physics tick, so pose/portrait captures set the yaw afterset_physics_process(false);visible=falsedoes not keep the crowd out of a portrait frame (park the rest of the crowd away instead). - Blender:
bisect_planeand thin bevels leave zero-area triangles (Godot "non-finite normal in LOD generation");_clean()+ a weld after bisect fixes them and the audit rejects them. - Quaternius arm-down bake (working recipe,
tmp/npc-research/bake_armdown_v5.py): pose-rotateUpperArm.L/R−90° local X → read the pose matrices → apply the Armature modifier → reset the pose to identity → set each arm bone's rest matrix from its pose matrix → re-add the modifier → exportexport_apply=False. Missing the pose reset double-applies the arm-down (mesh ±0.53 instead of ±0.23).armature_applyin Blender 5.2 is broken (deforms the mesh but does not bake the rest). The canonical base must be join-only (build_base_minimal.py: noremove_doublesweld, no scale/ground transform, keep the Armature modifiers) — the weld and the scale/ground transform corrupt the skin weights (arm poses to ±0.51 instead of −0.23). - Quaternius
NpcAvatarwiring (commit2a6f29f): the Quaternius labelsL/Ropposite the project, so the dot-suffixed bone names are looked up with a swapped suffix (proxyL→UpperLeg.R/UpperArm.R, proxyR→.L). The arm/elbow swing axis isVector3.LEFT(legs stayRIGHT). The hand proxy position isglobal_wrist − global_elbow(subtracting the relativeelbow.positionmisplaces handheld gear). Old 13-core names fall back unchanged. - Image models have per-model size floors/caps (Seedream needs 1920+;
GEN_SIZE=2048, do not lower; gpt-5-image-mini caps lower).generate_imageapplies model-specific sizing; concept generation defaults to--request-size 1536. - Local photo research tooling: DDG rate-limits by IP (HTTP 202) — the
refcollect.pytoken bucket (0.5 req/s, burst 3) plus retry/backoff handles it; some DDG frames are AVIF mislabeled.png/.jpg(convert with ffmpeg;refcollect.py sheetskips unreadable). Commons API needs a descriptive User-Agent and rate-limits thumbnail downloads (fetch all metadata in onetitles=A|B|Cquery). - Frozen decisions: do not re-open
override_access; do not bind wand toW; do not remove the radio easter egg. - GDScript: no static signals; lambdas capture locals by value (mutating a captured local does not affect the outer variable — use member functions for accumulators).
- Reference cycles:
FSMholds its owner viaWeakRef,ShiftCoordinatorisRefCounted; if a new subsystem introduces a cycle, repeat the WeakRef pattern. - Headless (dummy renderer) logs
Parameter m is nullfrommesh_get_surface_count— benign, does not occur with a real GL driver. - macOS export requires
rendering/textures/vram_compression/import_etc2_astc=true(universal build demands ETC2 ASTC). - Typed spawn signal: handlers must accept the 4th
event: Dictionaryarg or Godot will not call them. - GDScript inference trap: a
vartyped as a base class (radial: CanvasLayer) exposes script members asVariant; type it as the script type (ActionRadial).--check-only --scriptcannot see theSaveautoload — use a real boot (--quit-after 180) to verify full-scene compile. - Do not snapshot right after changing a transform in the same frame —
capture_screenshots.gdneeds a state/frame gap or the capture uses the old camera orientation. EventSchedulerprobabilities are per simulated second, not per call; never poll it per frame.- Light falloff:
omni_attenuation = 0.0is constant, not physical, falloff in Godot 4.7 — all local lights use1.0. - glTF
baseColorFactoris LINEAR — writing sRGB makes props pastel;srgb_to_linear()is applied inbuild_glb. A new/changed.glbneedsgodot --headless --importbeforeload()sees it. - Rebuilding a character GLB also requires re-baking its AO (
tools/bake_ao.py -- --only <name>).blender_assets.py buildwrites the GLB only; the old<name>_ao.pngthen maps onto the new geometry and produces large dark cheek/jaw blotches. Bake the AO, re-import, and refresh the stale.godotcache (scratch-copy import) before judging a face/body change. Save.SETTINGS_FILEis declared and unused; settings persist throughload_settings()/save_settings().- Crowd reactions emit
event_bus.crowd_changed;GameManager._connect_crowd()must reconnect after everycoordinator.setup()(same class of bug as the radio-dispatch reconnect). - Packaging: NSIS uses
-Ddefines (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 systemappstreamcli— pass--pedantic. - Credentials:
~/.git-credentialsholds the Gitea creds;.envholds onlyOPENROUTER_API_KEY. assets/textures/game_ready/is not imported (no.import) — use the importedassets/textures/skyline.pngpath.- Godot 4.7 writes
*.gd.uidfiles — kept out ofgit statusvia.git/info/exclude. - Collaborators occasionally leave uncommitted work in the shared tree; check
git statusbefore 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/blenderand cannot read/tmp— use absolute repo paths;.gdignoremarkers keep Godot from importing.blend/tmp) - Textures:
python3 tools/generate_textures.py(thengodot --headless --import); AI modepython3 tools/generate_textures.py --ai; general pipelinepython3 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
- Whether the responder avatar should be playable/controllable or purely scripted.
- Quaternius scope: full 12-role swap, crowd-only, or extra head detail (owner decision at 0.9.9).
- 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).
Current State
v0.9.8 is published. The build covers the three venues, the shift loop, tutorial/campaign/
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.
Planning pivot (2026-11-05, owner): the character and map work was re-sequenced into
patches (0.9.9–0.9.12) with 0.10.0 as the public-readiness minor. The gap analysis and the
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.
Quaternius pilot (2026-11-05): the arm-down skin export and pose composition are now fixed
(bake_armdown_v5.py, 2a6f29f). The join-only quaternius_base.glb renders arm-down in Godot;
idle/sit/walk were vision-verified (coherent humanoid, seated arms on thighs, contralateral walk).
Remaining before 0.9.9: handheld-gear fitting (the 0.43 m camera reads shoulder-mounted on the
0.42 m arm), five-slot mapping + AO bake, the owner face/silhouette gate, then the rollout.
No character GLB has been rebuilt since the pivot.
Test counts as of 2026-11-05: Python 167/167, Godot 277/277, check_docs OK.