Trim MEMORY.md: drop superseded handoffs and release anecdotes, fix stale counts and the sign-in contradiction
This commit is contained in:
1 parent
ea3860a60c
commit
78267918bf
1 file changed
+37
-326
@@ -131,7 +131,8 @@ Session memory for durable decisions, state, and gotchas. Keep concise, remove o
|
|||||||
P0/P1 only, and must not change the `npc_base` contract, renderer or 0.10.0 candidate. The MIT
|
P0/P1 only, and must not change the `npc_base` contract, renderer or 0.10.0 candidate. The MIT
|
||||||
Blender skill pack is now routed through `AGENTS.md` §Local Blender skills; skill advice loses
|
Blender skill pack is now routed through `AGENTS.md` §Local Blender skills; skill advice loses
|
||||||
to the project contract, and there is no Blender MCP here (headless flatpak scripts instead).
|
to the project contract, and there is no Blender MCP here (headless flatpak scripts instead).
|
||||||
MEMORY is ~960 lines with dated historical entries; trimming it is a tracked maintenance task.
|
MEMORY was trimmed to ~800 lines on 2026-11-03 (historical handoffs and release anecdotes
|
||||||
|
dropped; gotchas kept); further trimming is tracked in `TODO.md`.
|
||||||
- **GLB intake inspection (`blender_assets.py inspect`, 2026-11-03):** runs inside Blender, clears
|
- **GLB intake inspection (`blender_assets.py inspect`, 2026-11-03):** runs inside Blender, clears
|
||||||
parents and applies object transforms, then reports tris/budget, raw and seam-split verts,
|
parents and applies object transforms, then reports tris/budget, raw and seam-split verts,
|
||||||
Godot-space bounds (height/feet for characters), bones, materials, UVs, skinning and
|
Godot-space bounds (height/feet for characters), bones, materials, UVs, skinning and
|
||||||
@@ -279,7 +280,7 @@ Session memory for durable decisions, state, and gotchas. Keep concise, remove o
|
|||||||
`Materials.NPC_FABRIC_UV_SCALE = Vector3(4,4,1)`, and `NpcAvatar` skips the baked per-character
|
`Materials.NPC_FABRIC_UV_SCALE = Vector3(4,4,1)`, and `NpcAvatar` skips the baked per-character
|
||||||
AO on those two slots. The 256² AO was magnifying into large blotches; the fabric now reads as a
|
AO on those two slots. The 256² AO was magnifying into large blotches; the fabric now reads as a
|
||||||
fine weave. Skin/hair/gear keep baked AO. Test `test_fabric_uv_scale_avoids_the_baked_ao_pattern`
|
fine weave. Skin/hair/gear keep baked AO. Test `test_fabric_uv_scale_avoids_the_baked_ao_pattern`
|
||||||
guards this. Current suite is 272/272.
|
guards this. Current suite is 276/276.
|
||||||
- **NPC visual baseline (0.9.4, 2026-11-02):** `src/test/capture_npc_baseline.gd` is the
|
- **NPC visual baseline (0.9.4, 2026-11-02):** `src/test/capture_npc_baseline.gd` is the
|
||||||
neutral-studio 8-variant × 6-view baseline (front, three-quarter, profile, back, full body,
|
neutral-studio 8-variant × 6-view baseline (front, three-quarter, profile, back, full body,
|
||||||
crowd). It uses a fixed orbit camera, mid-grey studio backdrop, key/fill lights, no HUD/crowd/animation;
|
crowd). It uses a fixed orbit camera, mid-grey studio backdrop, key/fill lights, no HUD/crowd/animation;
|
||||||
@@ -295,45 +296,13 @@ Session memory for durable decisions, state, and gotchas. Keep concise, remove o
|
|||||||
stylized guide in `docs/npc-proportion-audit.md`; head ~0.190 (upper 0.22) and broad-build
|
stylized guide in `docs/npc-proportion-audit.md`; head ~0.190 (upper 0.22) and broad-build
|
||||||
shoulders ~0.370/hip ~0.225 are near the upper bounds, not outliers. No skeleton/mesh rescale was
|
shoulders ~0.370/hip ~0.225 are near the upper bounds, not outliers. No skeleton/mesh rescale was
|
||||||
needed; run the report after any body change.
|
needed; run the report after any body change.
|
||||||
- **NPC neck/shoulder transition (0.9.4, 2026-11-02):** the body graph uses a fuller neck base
|
- **NPC 0.9.4 visual passes (2026-11-02, consolidated):** the neck/shoulder, face-depth,
|
||||||
(1.43 m, radius 0.074/0.072), a taller/thicker neck top and a shoulder root lowered from 1.39 to
|
torso/hip, footwear, face-detail and hand passes all landed and are baked into
|
||||||
1.37 m. A final triangulate + tiny-face delete in `build_character` removes zero-area triangles
|
`tools/npc_pipeline.py` / `NpcAvatar`. The durable bits are the `NpcAvatar.HAND_ITEM_FORWARD =
|
||||||
that the new neck branch exposed in jacket/hoodie. All eight GLBs and AO maps were rebuilt;
|
Vector3(0,0,0.04)` offset (hand gear is authored around the wrist proxy) and the zero-area-triangle
|
||||||
`npc_proportions.py` still passes and `sheet_npc_baseline_compare-body.jpg` is the review image.
|
cleanup after the neck branch (see the Blender-tooling note in Known Issues). Exact per-pass
|
||||||
- **NPC face-depth pass (0.9.4, 2026-11-02):** recessed the sclera to `ey=-0.134` and added a
|
values, review sheets and current per-variant counts live in `docs/3d-model-review.md` and the
|
||||||
thin upper lid; removed the separate jaw/cheek spheres and instead sculpt front head vertices
|
code; the library cap is 8,000/8,000. Open: true finger curl/thumb contact and umbrella/sign grips.
|
||||||
(`_shape_head_mesh`) around a chin plate and cheekbones. This avoids dark AO intersection rings.
|
|
||||||
Moved lips forward to stay on the reshaped surface. Latest review sheet:
|
|
||||||
`sheet_npc_baseline_compare-face.jpg`; max character is now 4,754 tris / 4,574 verts.
|
|
||||||
- **NPC torso/hip transition (0.9.4, 2026-11-02):** pelvis radius 0.165→0.168, waist
|
|
||||||
0.150→0.146, chest 0.170→0.168, upper chest 0.172→0.170. This is a subtle shirt taper, not a
|
|
||||||
skeleton change; all proportions pass and `sheet_npc_baseline_compare-torso.jpg` records it.
|
|
||||||
Max character is 4,754 tris / 4,584 verts.
|
|
||||||
- **NPC footwear pass (0.9.4, 2026-11-02):** added `ShoeToe`/`ShoeHeel` spheres to the casual shoe
|
|
||||||
and `BootToe`/`BootHeel` to responder boots; both stay above the sole/boot contact plane. Current
|
|
||||||
counts are 4,482–5,474 tris / 4,260–5,494 verts under 8,000/8,000. Sheet:
|
|
||||||
`sheet_npc_baseline_compare-shoes.jpg`.
|
|
||||||
- **NPC hand-item forward offset (0.9.4, 2026-11-02):** `NpcAvatar.HAND_ITEM_FORWARD =
|
|
||||||
Vector3(0,0,0.04)` is added in `_attach_gear()` for every `GEAR_ATTACH` hand item after the
|
|
||||||
head/chest offsets. Hand gear is authored around the wrist proxy; without this, phone,
|
|
||||||
flashlight, cup and clipboard were partly inside the palm. Fingers are still open, so true
|
|
||||||
curl/thumb contact and umbrella/sign grips stay open. Comparison:
|
|
||||||
`sheet_npc_hands_grip_compare.jpg`; regression assertions cover camera and flashlight positions.
|
|
||||||
- **NPC headgear clearance (0.9.4, 2026-11-02):** after the face-detail pass, the 96
|
|
||||||
final-context frames confirm the cap, firefighter helmet, hood and sunglasses clear the refined
|
|
||||||
brow/eyes; `blender_assets.py fit` stays clean, so no gear was rebuilt. The broad helmet brim is
|
|
||||||
intentional turnout language, not a fit failure.
|
|
||||||
- **NPC face-detail pass (0.9.4, 2026-11-02):** Nose tip radius reduced to 0.022 with ala wings,
|
|
||||||
the two dark lip boxes became one shallow `Mouth` sphere (two blobs read as a moustache), and the
|
|
||||||
ears gained a dark `EarInner` concha. All eight rebuilt; current counts are 4,226–5,218 tris /
|
|
||||||
4,119–5,240 verts under the 8,000/8,000 cap. Sheet:
|
|
||||||
`sheet_npc_baseline_compare-face-detail.jpg`.
|
|
||||||
- **NPC hand pass (0.9.4, 2026-11-02):** palm radius 0.046 at z .742, scale (.80,.62,.88);
|
|
||||||
fingers are `tube` paths from z .758 to .681–.694 with tip spheres, thumb is a bent tube. The
|
|
||||||
optional hand capture is `capture_npc_baseline.gd -- --view=hand` (8 frames, baseline stays 48).
|
|
||||||
`npc_firefighter` is at 5,240 verts after the face-detail pass; the library cap is 8,000 (see
|
|
||||||
the character-mesh-cap decision above), so grip/clothing detail still has headroom. Grip offsets
|
|
||||||
remain open.
|
|
||||||
- **UI flow smoke (2026-11-02):** `smoke_ui_flows.gd` boots the real scene and
|
- **UI flow smoke (2026-11-02):** `smoke_ui_flows.gd` boots the real scene and
|
||||||
exercises inspection allow/deny, normal vs emergency radio, Help filtering,
|
exercises inspection allow/deny, normal vs emergency radio, Help filtering,
|
||||||
wand allow/deny and review return-to-menu. Keep this smoke in the 0.9.6
|
wand allow/deny and review return-to-menu. Keep this smoke in the 0.9.6
|
||||||
@@ -389,7 +358,7 @@ Session memory for durable decisions, state, and gotchas. Keep concise, remove o
|
|||||||
cover 0.8 settings/campaign/history and a 0.9.0 checkpoint. `_load_json` uses
|
cover 0.8 settings/campaign/history and a 0.9.0 checkpoint. `_load_json` uses
|
||||||
`JSON.new().parse()` so corrupt player files fall back silently instead of
|
`JSON.new().parse()` so corrupt player files fall back silently instead of
|
||||||
logging a parse error; atomic writes leave the old file intact when the temp
|
logging a parse error; atomic writes leave the old file intact when the temp
|
||||||
path cannot be written. The migration suite is 9 tests; total 272.
|
path cannot be written. The migration suite is 9 tests; total 276.
|
||||||
- **0.9.6 integration (2026-11-03):** no gameplay/content changes. A clean
|
- **0.9.6 integration (2026-11-03):** no gameplay/content changes. A clean
|
||||||
detached worktree at `f5b8ef2` rebuilt Linux/Windows/macOS/Web/HQ without the
|
detached worktree at `f5b8ef2` rebuilt Linux/Windows/macOS/Web/HQ without the
|
||||||
dirty tree's ignored `tmp/`/`build/` payload; the in-repo build was 1.6–3.1 GB
|
dirty tree's ignored `tmp/`/`build/` payload; the in-repo build was 1.6–3.1 GB
|
||||||
@@ -397,21 +366,11 @@ Session memory for durable decisions, state, and gotchas. Keep concise, remove o
|
|||||||
artifacts from a clean checkout/worktree. Verification: 263/263 tests,
|
artifacts from a clean checkout/worktree. Verification: 263/263 tests,
|
||||||
101/101 Python, 14 smokes, 24-NPC 6.90 ms / 168 meshes / 131,616 triangles,
|
101/101 Python, 14 smokes, 24-NPC 6.90 ms / 168 meshes / 131,616 triangles,
|
||||||
gallery 21/0, screen judge 21/21, realism judge overall 2.1 / gap 0.291.
|
gallery 21/0, screen judge 21/21, realism judge overall 2.1 / gap 0.291.
|
||||||
- **Release v0.9.6 (2026-11-03):** commit `4bb2896` tagged `v0.9.6`; Gitea
|
- **Release v0.9.4/v0.9.5/v0.9.6 (2026-11-02/03):** tags `v0.9.4` (`a57b86c`),
|
||||||
Actions run 1296 passed checks and the full build and published seven assets
|
`v0.9.5` (`4bc6390`) and `v0.9.6` (`4bb2896`, the 0.10.0 integration checkpoint) each
|
||||||
(Linux, Windows, macOS, NSIS setup, AppImage, Web, Desktop HQ). Release page:
|
published seven assets (Linux, Windows, macOS, NSIS setup, AppImage, Web, Desktop HQ) with
|
||||||
`https://git.allucanget.biz/zwitschi/security-game/releases/tag/v0.9.6`. This is
|
full CI runs; release pages live under `releases/tag/`. Never reuse a tag — future fixes
|
||||||
the integration checkpoint before 0.10.0; do not reuse the tag.
|
need a new patch tag. Full per-version records stay in `CHANGELOG.md`.
|
||||||
- **Release v0.9.5 (2026-11-02):** commit `4bc6390` tagged `v0.9.5`; Gitea Actions run
|
|
||||||
922 passed checks and the full build and published seven assets (Linux, Windows,
|
|
||||||
macOS, NSIS setup, AppImage, Web, Desktop HQ). Release page:
|
|
||||||
`https://git.allucanget.biz/zwitschi/security-game/releases/tag/v0.9.5`. Do not
|
|
||||||
reuse the tag; future fixes need a new patch tag.
|
|
||||||
- **Release v0.9.4 (2026-11-02):** commit `a57b86c` tagged `v0.9.4`; Gitea Actions
|
|
||||||
run 916 passed checks and the full build and published seven assets (Linux,
|
|
||||||
Windows, macOS, NSIS setup, AppImage, Web, Desktop HQ). Release page:
|
|
||||||
`https://git.allucanget.biz/zwitschi/security-game/releases/tag/v0.9.4`. Do not
|
|
||||||
reuse the tag; future fixes need a new patch tag.
|
|
||||||
- **Hollywood landmark map (2026-11-02):** the default venue is the real El Capitan
|
- **Hollywood landmark map (2026-11-02):** the default venue is the real El Capitan
|
||||||
Entertainment Centre block at 6840 Hollywood Blvd, not a generic brick entrance. Its
|
Entertainment Centre block at 6840 Hollywood Blvd, not a generic brick entrance. Its
|
||||||
reference/mapping notes live in `docs/hollywood-boulevard-map.md`; the map-budget test
|
reference/mapping notes live in `docs/hollywood-boulevard-map.md`; the map-budget test
|
||||||
@@ -484,224 +443,6 @@ Session memory for durable decisions, state, and gotchas. Keep concise, remove o
|
|||||||
**Mockup copies:** 21 design references live in `assets/images/ui/`; `docs/screens/designs/`
|
**Mockup copies:** 21 design references live in `assets/images/ui/`; `docs/screens/designs/`
|
||||||
remains the reference-only copy. `tools/screen_designs.py` reads/writes the runtime root.
|
remains the reference-only copy. `tools/screen_designs.py` reads/writes the runtime root.
|
||||||
|
|
||||||
## Handoff — historical snapshot (2026-11-01; superseded by Current State / Plan vs code)
|
|
||||||
|
|
||||||
- **Status (2026-11-01, after the venue-geometry pass):** v0.7.0 was released at that point. Post-v0.6.0 the
|
|
||||||
realism pass, the visual-alignment pass and the NPC face/hand pass all landed. Headless
|
|
||||||
**272/272**, Python tooling **108/108**, `tools/check_screenshots.sh` **21 good / 0 bad**,
|
|
||||||
`screen_designs.py compare` 11 good / 0 bad, `scene_concepts.py audit` all GOOD,
|
|
||||||
`blender_assets.py audit` exit 0, `smoke_npc_budget` OK (16 avatars, 6.94 ms of 50 ms).
|
|
||||||
`PLAN.md` is compact; README/architecture track the current controls, asset pipeline, CI and
|
|
||||||
release artifacts. The historical notes below remain useful for implementation gotchas; for
|
|
||||||
current tasks use `TODO.md`.
|
|
||||||
|
|
||||||
- **Phase 2 — AI texturing (this agent, DONE 2026-11-01).** Phase 1 assets were
|
|
||||||
already in the tree (untracked) and are preserved. Generated six seamless AI
|
|
||||||
clothing albedos into `assets/textures/npc/ai/{shirt,trousers,jacket,vest,
|
|
||||||
coat,dress}.png` (512×512, `--role tile`, gpt-5-image-mini; audit 6 good).
|
|
||||||
**Gotcha:** `asset_pipeline.py generate` defaults to `GEN_SIZE=2048`, which
|
|
||||||
gpt-5-image-mini rejects (HTTP 400); pass `--request-size 1024` for 1:1 roles.
|
|
||||||
`generate --role tile` already applies `make_seamless`, so a separate
|
|
||||||
`seamless` pass is redundant. Added to `tools/npc_pipeline.py`: `prepare`
|
|
||||||
(layers AI shirt→cloth, trousers→pants albedos at 256px) and `palette`
|
|
||||||
(writes `assets/textures/npc/palette.json` via `model_pipeline.dominant_colors`).
|
|
||||||
`write_slot_textures()` now skips the albedo for slots with an AI override
|
|
||||||
(normal/ORM stay procedural). Blender `build` re-run: GLB audit ok, 1204 tris /
|
|
||||||
2488 verts, AI albedo embedded for cloth+pants. Phase 2 completed and shipped with
|
|
||||||
the v0.6.0 asset library.
|
|
||||||
**Import concurrency:** a parallel agent is running
|
|
||||||
`timeout 300 godot --headless --editor --quit --path .` and then checks
|
|
||||||
`assets/models/generated/npc_base.glb.import` — treat that as the canonical
|
|
||||||
import. My own `godot --headless --path . --import` hung with no output past
|
|
||||||
the engine banner (two Godot instances contended on `.godot`); I killed the
|
|
||||||
orphan (PID 2482934). Do not run a second import while that `--editor --quit`
|
|
||||||
is active.
|
|
||||||
Next: Phase 3 (`NpcAvatar._load_model` + slot tinting) consumes
|
|
||||||
`palette.json` and the GLB; Phase 2's capture/judge item is blocked on that.
|
|
||||||
|
|
||||||
- **Git hygiene + tooling (2026-11-01):** dev asset folders are now gitignored
|
|
||||||
and untracked: `assets/models/concepts/`, `assets/models/npc/` (Blender
|
|
||||||
sources), `assets/textures/npc/ai/` (raw AI fabrics), and the raw
|
|
||||||
`assets/textures/ai/*` outputs (only `assets/textures/ai/game_ready/` stays).
|
|
||||||
Kept in the repo: `assets/textures/npc/*_{albedo,normal,orm}.png` +
|
|
||||||
`palette.json`, `assets/models/generated/*` (props + npc_base.glb), and the
|
|
||||||
authored `assets/textures/*` set. `tools/asset_pipeline.py generate` gained
|
|
||||||
`--variants N` — generates N alternatives saved as `<stem>-1..N.png` (N=1
|
|
||||||
keeps the unsuffixed path). Python tooling tests still pass (exit 0).
|
|
||||||
|
|
||||||
- **Screenshots + docs (2026-11-01):** regenerated the eleven README captures
|
|
||||||
(`capture_screenshots.gd` + `capture_prop_gallery.gd`) — ten changed, the
|
|
||||||
prop gallery is byte-identical (props unchanged). README gained an NPC
|
|
||||||
character-model subsection, a "Confirmed game assets" section (linked
|
|
||||||
`game_ready` textures, generated models, NPC maps), and refreshed
|
|
||||||
dev-status / not-yet lines; `docs/architecture.md` Level 2 now lists
|
|
||||||
`npc_pipeline.py` + `asset_pipeline.py` and the confirmed-asset locations.
|
|
||||||
|
|
||||||
- Repo: `/run/media/system/DATA/Documents/06-games/security-game` (also reachable at
|
|
||||||
`/var/home/zwitschi/Documents/06-games/security-game`). Godot: `~/.local/bin/godot` (4.7.2).
|
|
||||||
Tests: `godot --headless --path . --script res://src/test/test_runner.gd` → **177/177**.
|
|
||||||
Python tooling tests: `cd tools && python3 -m unittest test_asset_pipeline test_screen_designs test_model_pipeline` → **53**.
|
|
||||||
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
|
|
||||||
(now also covers wheel cycling and right-click clearing).
|
|
||||||
- `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.
|
|
||||||
- **v0.3.0 (2026-10-31, working tree):** rendering pass (`src/game/materials.gd`, phase-driven
|
|
||||||
environment), generated `.glb` props (`tools/model_pipeline.py`, `assets/models/generated/`),
|
|
||||||
aim-free selection with wheel cycling and Shift precision walk (ADR-0011/0012), and a **Web**
|
|
||||||
export target. `export_presets.cfg` gains a `Web` preset with `variant/thread_support=false`
|
|
||||||
(static hosting, no COOP/COEP); `tools/build_releases.sh` exports `build/web/` and zips it to
|
|
||||||
`build/gig-line-web-<ver>.zip`, and `publish_release.sh` uploads it. Covered by
|
|
||||||
`src/test/tests/test_web_export.gd`.
|
|
||||||
- **Prop atlas (v0.3.1):** `model_pipeline.atlas_for()` builds a per-prop power-of-two PNG with
|
|
||||||
one 8×8 cell per palette role, plus a metallic/roughness atlas (G=roughness, B=metallic). The
|
|
||||||
GLB merges all parts into one primitive with constant per-vertex UVs (cell centre) and a single
|
|
||||||
material (`baseColorTexture` + `metallicRoughnessTexture`, NEAREST sampling). Colours are sRGB in
|
|
||||||
the texture, so the old `srgb_to_linear`/`_linear_rgba` helpers were removed. `audit_glb` fails
|
|
||||||
if a prop is not exactly one material or misses TEXCOORD_0/images.
|
|
||||||
- **Mockups complete (v0.3.2, updated 0.9.3):** `docs/screens/designs/` holds AI references for
|
|
||||||
all 21 catalogue screens, and every entry now has a committed current-build capture.
|
|
||||||
`capture_screenshots.gd` covers scenes 01–13, `capture_ui_states.gd` covers UI states 14–21,
|
|
||||||
and `capture_prop_gallery.gd` covers the prop gallery. `generate` now calls `_load_env_file()`.
|
|
||||||
- **Staged captures (v0.3.3, updated 2026-11-02):** `capture_screenshots.gd` emits the scene
|
|
||||||
gallery; states 7–10 switch to The Joke Shop at elapsed 620 s, retry the wand until it alerts,
|
|
||||||
then jump to 760 s after staging for night lighting. LATE now has its own routine pool.
|
|
||||||
Shot 12 closes any stale wand/inspection modal before the venue beauty shot (the wand fallback
|
|
||||||
can leave `hud.show_wand` open without `wand_open`). The timeline needs
|
|
||||||
`recorder.close_all_open()`, because `to_dict()` only lists closed incidents.
|
|
||||||
`capture_ui_states.gd` adds 14–21; crowd panic stages a group 70 frames into the flee and
|
|
||||||
responder arrival parks the responder with the door locked. `check_screenshots.sh` writes all
|
|
||||||
captures to `docs/screenshots/` before `compare`; judge is 21/21 match.
|
|
||||||
- **Prop collision (v0.4.0):** `_add_prop_model()` fits a `StaticBody3D` from the model bounds
|
|
||||||
(cylinder for bollard/bin/hydrant, box otherwise) and adds a `NavigationObstacle3D`; NPC agents
|
|
||||||
enable avoidance and move with the safe velocity from `velocity_computed`. The navmesh stays a
|
|
||||||
flat plane, so avoidance (not a baked mesh) routes guests around props. Placements live in
|
|
||||||
`PROP_PLACEMENTS` with `placement_problems()` validation; variants come from `variant_for(index)`.
|
|
||||||
`smoke_props.gd` must be windowed because the guard reads captured-mouse input.
|
|
||||||
- **Realism pass (2026-11-01, completed + adopted):** `tools/scene_concepts.py`
|
|
||||||
(`list`/`generate`/`process`/`promote`/`audit`/`realism`) never overwrites an image
|
|
||||||
(`next_free_path` adds `-vN`; `process` skips existing unless `--new`; `promote` keeps an
|
|
||||||
existing pick). Raw AI output: `assets/textures/ai/v2/raw/` (gitignored). Candidate pool:
|
|
||||||
`assets/textures/ai/game_ready/v2/` (gitignored) and the **tracked runtime assets** are
|
|
||||||
`.../v2/picks/{skyline_day,skyline_dusk,skyline_night,brick_facade,sidewalk_pavers,asphalt,
|
|
||||||
asphalt_wet,awning_canvas}.png` (+ `_normal`). Concepts `docs/screens/concepts/` (committed,
|
|
||||||
`.gdignore`, targets in its README). Runs `docs/screens/realism/<run>/` (PNG captures
|
|
||||||
gitignored; `report.{json,md}` + `sheet.jpg` committed).
|
|
||||||
`src/test/capture_realism.gd` runs five stages (day 0 s / evening 620 s / late 760 s /
|
|
||||||
joke_shop 700 s / studio 700 s; `--stages=` subset) and swaps textures by the material's
|
|
||||||
*original* albedo path. **Gotcha:** in the SceneTree script, do not overwrite `_phase` after
|
|
||||||
`_begin_stage()` sets `done`, or the run loops forever between stage/shoot (`_queue` empty).
|
|
||||||
**Gotcha:** `elapsed_s = 620` is *Evening* (dusk), 700+ is Late. Godot 4.7
|
|
||||||
`StandardMaterial3D` has no `fog_enabled`; the skyline is a `ShaderMaterial` with
|
|
||||||
`render_mode unshaded, cull_disabled, fog_disabled` + `ALPHA_SCISSOR_THRESHOLD` so the
|
|
||||||
panorama's own haze shows. Backdrop plane is 90 m tall with 2 UV repeats (~200×90 m per
|
|
||||||
repeat, near the 2:1 panorama aspect). Legacy `assets/textures/skyline.png` is no longer
|
|
||||||
loaded but stays on disk for the `test_world` asset check.
|
|
||||||
**Phase look:** day sun 0.62 / exposure 0.6 / ambient 0.22; evening sun 0.12 / exposure
|
|
||||||
0.72 / dark violet sky; late exposure 0.95 / ambient 0.10 with the wet asphalt street and a
|
|
||||||
bright skyline tint (1.5) so the night windows read. Stripes: `stripe_period()` (detrended
|
|
||||||
autocorrelation) + `align_stripes()` (resample to whole periods) replace the edge crossfade
|
|
||||||
for `awning_canvas`; `audit_striped_tile()` compares the wrap step with the harshest interior
|
|
||||||
step.
|
|
||||||
**Judge:** the default `google/gemini-2.5-flash-lite` mostly works but intermittently answers
|
|
||||||
HTTP 400 "API key not valid" (one shot of ten on 2026-11-01); re-run or pass
|
|
||||||
`--model google/gemini-2.5-flash` when it does. Scores are noisy (±1–2), so
|
|
||||||
`realism --repeats 3` averages and `summarize()` reports a like-for-like mean over the shots
|
|
||||||
every set captured. Final: overall 0.8→1.0, backdrop 0.6→1.6, metric gap 0.444→0.348.
|
|
||||||
`screen_designs.py judge` gained one retry for the same transient 400.
|
|
||||||
**Character portrait capture (2026-11-01):** `capture_realism.gd` has a `portrait` stage
|
|
||||||
(`npc_portrait` -> concept `npc_portrait_day`) because crowd shots cannot judge avatars. It
|
|
||||||
freezes one NPC, parks the rest of the crowd 140 m away (a passer-by otherwise blocks the
|
|
||||||
frame), moves the subject to an open sidewalk patch, turns it into the camera and stands the
|
|
||||||
guard on the sunlit side. Needed because the NPC FSM re-writes `rotation.y` every physics tick
|
|
||||||
(so the yaw must be set after `set_physics_process(false)`), the venue's morning sun leaves a
|
|
||||||
face in shadow from most angles, and `visible = false` does not keep the crowd out of frame.
|
|
||||||
`--portrait-type=N` forces a role; hooded roles (trespasser/violent/crisis) are skipped.
|
|
||||||
**Flashlight (2026-11-01, final):** a *tight* `SpotLight3D` on `Head`: `spot_range` 20,
|
|
||||||
`spot_angle` 14, `light_energy` 4.2, `spot_attenuation` 0.9, forward `rotation_degrees = 0`,
|
|
||||||
starts invisible. A fake additive light shaft was tried twice (cylinder with a UV ramp, then a
|
|
||||||
vertical-fade `ShaderMaterial`) and **rejected both times**: on GL Compatibility a first-person
|
|
||||||
camera inside the cone renders it as a filled disc and the far ring shows, so
|
|
||||||
`Materials.light_beam()` and the beam mesh are gone. Regression guard:
|
|
||||||
`test_flashlight_aims_a_tight_forward_spot` in `src/test/tests/test_door_and_flashlight.gd`
|
|
||||||
(lamp on the head, aims straight, cone ≤ 20°, starts off). Night captures are staged in LATE
|
|
||||||
(`elapsed_s` 760), not dusk.
|
|
||||||
**NPC detail pass (2026-11-01):** `_face()` now builds sclera + iris + upper lid per eye, brow
|
|
||||||
ridge, cheekbones, nose bridge/tip, ears with lobes and split upper/lower lips; the new
|
|
||||||
`eye_white` material is a *fixed-colour* slot, so `_apply_outfit_materials()` leaves it white.
|
|
||||||
`_hands_and_shoes()` has four fingers plus a thumb and `_clothing()` adds `Cuff` tori.
|
|
||||||
Budget work at the time: `CHAR_MAX_VERTS` 5000 (the library cap is now 8000; see the
|
|
||||||
character-mesh-cap decision), body decimation 0.26, upper lids are
|
|
||||||
boxes rather than spheres, and knuckle spheres/nostrils were cut to stay inside it.
|
|
||||||
**Orientation debugging:** to check a GLB's front axis, compare the mean Z of the `eye_white`
|
|
||||||
surface (face) and of the `rubber` sole verts (toes) — all 8 avatars are +Z, so any
|
|
||||||
"they walk backwards" symptom is a yaw bug, not an export flip.
|
|
||||||
- **Blender asset library (v0.6.0, integrated 2026-11-01):**
|
|
||||||
`tools/blender_assets.py` (`build`/`render` in Blender; `audit`/`sheet`/`list` stdlib) writes
|
|
||||||
`assets/models/blender/{npc,npc_gear,props}/*.glb`, `manifest.json` (integration source of
|
|
||||||
truth), sources in `assets/models/blender_src/` (`.gdignore`d), and review sheets
|
|
||||||
`docs/blender_previews/sheet_*.jpg` (per-asset PNG renders are gitignored). 8 characters, 18
|
|
||||||
gear, 20 props; notes in `docs/blender-assets.md`. Characters are drop-in for `npc_base`
|
|
||||||
(same mesh node name, bones at the same rest positions, five tint slots); the `npc_base`
|
|
||||||
fallback stayed under its frozen 6000/4000 budget because of body decimation (0.26) +
|
|
||||||
`smart_project` at 80°: glTF vertex
|
|
||||||
count includes UV-seam splits, so extra beveled detail quickly breaks the limit. The 2026-11-01
|
|
||||||
face/hand pass raised `CHAR_MAX_VERTS` to 5000 (tris 3,974–5,026) after measuring 16 avatars at
|
|
||||||
~6.9 ms of a 50 ms frame; on 2026-11-02 the library cap became 8000/8000 while
|
|
||||||
`npc_pipeline.MAX_VERTICES`/`MAX_TRIANGLES` (base mesh) stayed frozen at 4000/6000.
|
|
||||||
**Gotchas:** `bisect_plane` and thin bevels leave zero-area triangles (Godot warns "non-finite
|
|
||||||
normal in LOD generation"); `_clean()` + a weld after bisect fix it, and the audit rejects them.
|
|
||||||
Fixed-colour detail materials carry a 4×4 texture because `_apply_outfit_materials()` sets
|
|
||||||
`albedo_color = WHITE` on unknown slots. Cycles CPU render ≈ 3 s/asset; Godot import of the
|
|
||||||
library is clean.
|
|
||||||
**Integration:** `NpcAvatar.character_model_for()` selects a variant by role/seed; only the
|
|
||||||
five contract slots are tinted (detail materials untouched; `npc_vest` keeps its fixed hivis
|
|
||||||
vest, firefighter/guard get dark uniform tints). Gear is attached at head/back/chest/hand and
|
|
||||||
falls back to primitives; `npc_hoodie` skips the extra hood gear. `WorldBuilder` prefers
|
|
||||||
`assets/models/blender/props/` for the six replacements and the new street dressing, fits the
|
|
||||||
same colliders/obstacles, and collects library emissives for `set_night_mode()`.
|
|
||||||
`LIBRARY_TRIANGLE_BUDGET` = 60k (current ~27,986). Library props are excluded from
|
|
||||||
`PROP_PLACEMENTS` only when they need dedicated slots (door/marquee/sedan/handrail/lantern).
|
|
||||||
**Gear fit (v0.6.1):** `fit` measures head width (0.315 m), skirt/hip radius and gear bounds;
|
|
||||||
sunglasses are 0.202 m, the bag's body inner face is 0.262 m (coat 0.225, dress 0.260), and the
|
|
||||||
helmet is lifted 2 cm above the brow. `test_npc_character` guards head/back gear in Godot.
|
|
||||||
Blender's GLB export is byte-nondeterministic for unchanged assets (padding/index order), so do
|
|
||||||
not commit a full no-op rebuild; rebuild only the assets whose geometry changed.
|
|
||||||
- **Venue geometry (v0.6.1+, Joke Shop updated 2026-11-02):** `WorldBuilder.VENUE_SPECS` is the per-venue table; `WorldBuilder.new(root, id)` / `set_venue()` select it, unknown ids fall back to `hollywood_building`. Dimensions, window/pilaster rows, stairs, street, nav bounds, guard spawn, feature flags and prop placements are read from the spec. `GameManager.world_root` holds only the world; `_rebuild_world_for_venue()` frees/recreates it on venue selection/cycling so guard/UI survive. Joke Shop now uses `architecture: "comedy_store"` with `_build_comedy_store_building()`, `SunsetHillside`, `SunsetNeighbours` and `SunsetAcrossStreet`; the old `_build_alley_dressing()` is gated off. TV Studio keeps the stone facade, bulb canopy, car paint and barrier placements. Gallery shot 12 now maps to `joke_shop_entrance_night`; shot 13 stays `studio_stage_door_night`.
|
|
||||||
- **Screen-design judge (2026-11-01):** `screen_designs.py judge` could not run because `OPENROUTER_API_KEY` returned HTTP 400 "API key not valid". `check_screenshots.sh` still passed 13/13; the judge retry is a TODO follow-up.
|
|
||||||
- **Portrait capture:** `capture_realism.gd` faces the **Rig** toward the camera (using the
|
|
||||||
inverse look direction) and hides the blue `FocusCircle`; the old code used the wrong yaw and
|
|
||||||
left the focus disc over the face. An explicit `--portrait-type=N` now overrides the hooded
|
|
||||||
skip, but the day roster spawns none of types 5-7, so a hooded close-up is deferred.
|
|
||||||
- **v0.6.0 environment pass:** `tools/bake_ao.py` bakes 256² AO maps per library asset
|
|
||||||
(`<name>_ao.png`, red channel) and `Materials.apply_ao()`/`SurfaceMaterials` wire them in;
|
|
||||||
`tools/make_normal_maps.py` derives tangent normals for the 1024² brick/concrete/asphalt
|
|
||||||
textures. Forward+ boots on desktop but is rejected for v0.6.0 (project-wide renderer, Web
|
|
||||||
must stay GL Compatibility). Headless 222/222, Python 69/69.
|
|
||||||
- **Prop pipeline (done):** audit enforces 400 tris / 600 verts, ground contact, UV range, no
|
|
||||||
degenerate tris, one material. `capture_prop_gallery.gd` writes `10-prop-gallery.png` (3x2 studio
|
|
||||||
line-up, back row on a platform) and the `prop_gallery` catalogue entry compares it.
|
|
||||||
- **NPC character pass (v0.5.0):** Rig is articulated (`Rig/Hip* -> Knee`, `Shoulder -> Elbow ->
|
|
||||||
Hand`); `outfit_for` adds layer/hair_style/hand_item; `_idle_layer` drives phone/clipboard/crossed
|
|
||||||
and escalation gestures; `_reaction_tag` shows `!!`, `?!`, `!`, `?`; `apply_lod` swaps to a
|
|
||||||
billboard impostor at 26 m (hysteresis 1.5 m); GameManager `_refresh_queue` assigns queue offsets.
|
|
||||||
Perf: 16 avatars = 534 meshes, ~6.9 ms headless.
|
|
||||||
- **Player movement (v0.5.0):** **W was inverted** (`get_axis(forward, back)` is negative for W and
|
|
||||||
the code multiplied it directly); now `forward * -input_dir.y`. Step-up uses test_move + a raised
|
|
||||||
copy (0.32 m). Guard emits footstep/landed/precision_changed; GameManager forwards them to
|
|
||||||
AudioFeedback and the HUD. Gamepad actions are added at runtime by
|
|
||||||
`GuardController._ensure_gamepad_bindings`; remaps persist via `Save` `input_bindings` and are
|
|
||||||
applied by `InputBindings.apply` (key/button events only). Windowed `smoke_movement.gd` guards it.
|
|
||||||
- **Scheduled TODO pass complete:** only the optional Future ideas remain (live replay, extra
|
|
||||||
venues, voice audio, image-to-mesh). Grounding facts: the
|
|
||||||
NPC rig is rigid capsules with a whole-limb swing, and `guard_controller.gd` uses one `accel`
|
|
||||||
value. Each task should get its own windowed smoke or capture where it changes feel/looks.
|
|
||||||
- **Backlog complete:** every planned TODO section is done and moved to `DONE.md`; `TODO.md`
|
|
||||||
now only lists optional future ideas (live 3D replay, NPC LOD, more venues, real audio, prop
|
|
||||||
atlas, AI mockups for the new catalogue entries, image-to-mesh props). GUT was consciously not
|
|
||||||
adopted (custom runner covers it without an editor plugin).
|
|
||||||
- Do not re-open `override_access`. Do not bind wand to `W`. Do not remove the radio easter egg.
|
|
||||||
|
|
||||||
## UI / Presentation Decisions
|
## UI / Presentation Decisions
|
||||||
|
|
||||||
- Runtime UI/scene art is loaded through `src/game/ui/art.gd` (`assets/images/ui/` then `scenes/`); missing files return null so panels keep procedural fallbacks.
|
- Runtime UI/scene art is loaded through `src/game/ui/art.gd` (`assets/images/ui/` then `scenes/`); missing files return null so panels keep procedural fallbacks.
|
||||||
@@ -895,43 +636,11 @@ Session memory for durable decisions, state, and gotchas. Keep concise, remove o
|
|||||||
- Host sign-in follow-up is **done**: `REQUIRE_SIGNIN_VIEW = false` in `/etc/gitea/app.ini`
|
- Host sign-in follow-up is **done**: `REQUIRE_SIGNIN_VIEW = false` in `/etc/gitea/app.ini`
|
||||||
(backup `app.ini.bak-*` alongside), Gitea restarted; anonymous repo page/API return 200 and
|
(backup `app.ini.bak-*` alongside), Gitea restarted; anonymous repo page/API return 200 and
|
||||||
release assets download in full. Reverse by setting it back to `true` and restarting.
|
release assets download in full. Reverse by setting it back to `true` and restarting.
|
||||||
- **Release publishing was broken since v0.2.2 (fixed 2026-10-31):** `publish_release.sh`
|
- **Release publishing (fixed 2026-10-31):** `publish_release.sh` falls back to the local git
|
||||||
only built `AUTH` in the `GITEA_TOKEN` branch; the `~/.git-credentials` branch set `CRED`
|
extraheader that `actions/checkout` writes (`git config --local --get-regexp
|
||||||
and then used unbound `${AUTH[@]}` under `set -u`, so every API call failed and the tag
|
'^http\..*\.extraheader$'`) because this Gitea/act runner provides no `GITEA_TOKEN`. Always
|
||||||
job ended "could not create or find release". The repo also has **no** `GITEA_TOKEN`
|
build release artifacts from a clean checkout/worktree (the dirty tree's ignored `tmp/`/`build/`
|
||||||
secret (`/actions/secrets` is empty) and the runner has no git credentials. Fixes: the
|
payload blew artifact size to 1.6–3.1 GB once). Per-version records live in `CHANGELOG.md`.
|
||||||
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.
|
|
||||||
- **CI publishing verified (2026-10-31):** tagging v0.2.12 produced a release with all five
|
|
||||||
artifacts automatically (no repo secret), confirming the checkout-extraheader fallback.
|
|
||||||
- **Host access (2026-10-31):** `root@192.168.88.30` now works from this workstation (key auth),
|
|
||||||
host name `gitea`, Gitea 28.2.0. Maintenance applied: `apt-get clean`, journald capped to
|
|
||||||
`SystemMaxUse=300M` (`/etc/systemd/journald.conf.d/99-size.conf`, journal ~133M), disk at
|
|
||||||
~7.6G free of 16G.
|
|
||||||
- **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
|
- 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
|
(never `/D`), resolves relative `-DICON`/`-DARTIFACT` against the **script directory** so CI
|
||||||
passes `$PWD`-absolute paths; installed exe must be space-free (`gig-line.exe`); ICO must be
|
passes `$PWD`-absolute paths; installed exe must be space-free (`gig-line.exe`); ICO must be
|
||||||
@@ -939,19 +648,8 @@ Session memory for durable decisions, state, and gotchas. Keep concise, remove o
|
|||||||
cannot load).
|
cannot load).
|
||||||
- appimagetool runs system `appstreamcli` if present (strict, exit 3 on warnings) — project
|
- appimagetool runs system `appstreamcli` if present (strict, exit 3 on warnings) — project
|
||||||
metadata now passes `--pedantic`.
|
metadata now passes `--pedantic`.
|
||||||
- Distribution facts (verified via Gitea API + host creds): repo is **public**, account is
|
- `~/.git-credentials` holds the Gitea creds (basic-auth usable); `.env` only holds
|
||||||
admin; `v0.2.1` has all 5 assets; the installers were initially missing from the release
|
`OPENROUTER_API_KEY`.
|
||||||
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`.
|
- 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.
|
- 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.
|
- 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.
|
||||||
@@ -1035,6 +733,19 @@ Session memory for durable decisions, state, and gotchas. Keep concise, remove o
|
|||||||
|
|
||||||
## Known Issues / Notes
|
## Known Issues / Notes
|
||||||
|
|
||||||
|
- Capture/pose harness gotchas: scripts that read captured-mouse input must run windowed
|
||||||
|
(`smoke_props.gd`); the NPC FSM re-writes `rotation.y` every physics tick, so pose/portrait
|
||||||
|
captures set the yaw after `set_physics_process(false)`; and `visible = false` does not keep the
|
||||||
|
crowd out of a portrait frame (park the rest of the crowd away instead).
|
||||||
|
- Blender tooling: `bisect_plane` and thin bevels leave zero-area triangles (Godot warns
|
||||||
|
"non-finite normal in LOD generation"); `_clean()` + a weld after bisect fix them and the audit
|
||||||
|
rejects them.
|
||||||
|
- Image models have per-model size floors/caps (Seedream needs 1920+, gpt-5-image-mini caps
|
||||||
|
lower); `generate_image` applies model-specific sizing, and concept generation defaults to
|
||||||
|
`--request-size 1536`. Do not hand-set a single size for every model.
|
||||||
|
- Frozen decisions: do not re-open `override_access`. Do not bind wand to `W`. Do not remove the
|
||||||
|
radio easter egg.
|
||||||
|
|
||||||
- Reference cycles are fixed: `FSM` holds its owner via `WeakRef`, `ShiftCoordinator` is
|
- 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
|
`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,
|
"resources still in use" warnings (was ~13). If a future subsystem introduces a cycle,
|
||||||
@@ -1049,7 +760,7 @@ Session memory for durable decisions, state, and gotchas. Keep concise, remove o
|
|||||||
- Venue `door_staff_lines` are logged through `GameManager` (inspect / wand / refuse). They are not a separate dialogue UI.
|
- Venue `door_staff_lines` are logged through `GameManager` (inspect / wand / refuse). They are not a separate dialogue UI.
|
||||||
- Access loadout is implemented; do not re-fix `override_access` as if it were still unread.
|
- Access loadout is implemented; do not re-fix `override_access` as if it were still unread.
|
||||||
- `Save.SETTINGS_FILE` is declared and unused; settings persistence goes through `Save.load_settings()` / `save_settings()`.
|
- `Save.SETTINGS_FILE` is declared and unused; settings persistence goes through `Save.load_settings()` / `save_settings()`.
|
||||||
- Headless suite is **272/272**; Python tooling is **108/108**; screenshot compare is **21 good / 0 bad** and the automatic judge is **21/21 match, 0 diff**. Remaining visual follow-ups are in `TODO.md`.
|
- Headless suite is **276/276**; Python tooling is **143/143**; screenshot compare is **21 good / 0 bad** and the automatic judge is **21/21 match, 0 diff**. Remaining visual follow-ups are in `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).
|
- 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
|
- 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
|
(`radial: CanvasLayer`) exposes script members as `Variant`, so `var x := radial.is_open` is a
|
||||||
|
|||||||
Reference in new issue
Block a user