13 KiB
13 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. - 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/hollywood-boulevard-map.mdanddocs/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. - NPC model sourcing (ADR-0015): CC0 acceptable for shipped assets; CC-BY only with
attribution in
CREDITS.md; no service assets with redistribution restrictions. The procedural generator is the primary path. Quaternius and MakeHuman were evaluated as references only, not shipped bases (Quaternius: 62-bone T-pose rig mismatch; MakeHuman: needs retopology + custom rig + clothing). - 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/balance-acceptance.mddefines 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. - Character mesh cap: eight library variants use 8,000 tris / 8,000 glTF vertices
(
CHAR_MAX_TRIS/CHAR_MAX_VERTSintools/blender_assets.py); the frozennpc_basefallback keeps 6,000/4,000. Measure after any geometry change; never silently lower the cap back to 5,000. - 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.
Gotchas / Known Issues
- Pose capture is blocked (narrowed 2026-11-03): the recipe (SubViewport +
force_draw()+force_update_all_bone_transforms()+ disabled process/physics) still yields byte-identical rest frames. Decisive probe: teleporting the avatar renders (diff 10) but moving itsRigchild does not (diff 0) — the skinned mesh ignores itsRigparent transform. Next attempt must answer that, or stage poses via the known-goodcapture_npc_review.gd. - 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. - 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. 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) - 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.
- Localization target languages beyond English.
- macOS notarization approach for broad distribution.
Current State
The playable build covers the three venues, tutorial/campaign/checkpoints, the 0.9.3–0.9.6
polish/texture/integration passes and the Blender + realism asset pipeline (see DONE.md and
CHANGELOG.md). Active work is the unversioned 3D model and local map re-evaluation track,
then character development, then the 0.10.0 release candidate — TODO.md is the priority source.
Test counts as of 2026-11-03: Godot 276/276, Python 160/160, check_docs OK.