Files
gig-line/MEMORY.md
T
zwitschi 5e5e5ae9b4 refs: survey the sibling project and recalibrate the hero facade
Tools/sibling_asset_audit.py reads the sibling security-game project's prop
library straight from the GLB headers: 20 street props, 11.8k triangles, every
one with a Blender source. The 50 .blend sources are copied to
Art/props/blender_src/ with a manifest; nothing is imported into Unreal yet. Its
building meshes are deliberately not taken - they are Godot GLBs built around a
29.6 m facade that this project measured at 25.75 m.

The facade proportions were wrong against the photograph: 5.7 m of blank wall
above the capitals. Entablature is now 3.4 m, parapet 2.2 m, with architrave and
cornice bands and square pedestals, so the elevation reads as layered stone.
2026-11-07 12:20:41 +01:00

116 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# MEMORY.md
Shared working memory between sessions and collaborators. Short, dated entries with evidence: the command, the log line, or the file path.
Scope: facts and traps that cost time to establish. Planned work lives in [ROADMAP.md](ROADMAP.md); formal setup, pins, and licensing live in [Docs/](Docs/).
---
## 2026-11-07 — Publication audit
- MPFB 2.0.18's installed `blender_manifest.toml` identifies its code as GPL-3.0-or-later; its versioned `LICENSE.md` explicitly puts bundled mesh, texture, and rig assets under CC0 1.0. The earlier CC0 claim for the add-on code was wrong.
- Blender inspection found no packed images or linked libraries in the tracked scenes. The character scene references local MPFB textures and a temporary baked texture, so those paths are not portable to a fresh checkout.
- The 2026-11-07 publication rewrite removed the approved private documents and bundled skills from all reachable refs; local copies remain ignored. The original history backup at `/tmp/gig-line-private-history-backup-42a29fe2` contains those private files and must not be pushed; `/tmp` may be cleared by the system.
- `git ls-remote --refs origin` succeeded on 2026-11-07 with no advertised refs; `git ls-remote --exit-code origin HEAD` returned 2 because no HEAD was advertised. This does not verify LFS upload support.
- Gitleaks 8.28.0 found an Android File Server token in historical `Game/GigLine/Config/DefaultEngine.ini`. The token was removed from reachable history and the unused server disabled; the old private backup and earlier temporary sanitized clone still contain it and must not be published.
- The first Gitea push uploaded 26 LFS objects. An independent clone fetched all 26 and `git lfs fsck` passed for the full history; the server also advertised LFS locking support.
## 2026-11-07 — Unreal Engine 5.8.4
- **Extracted** to `/run/media/system/DATA/Engines/UE_5.8.4` (73 GiB, `unzip` exit 0). CL `58902052`, `++UE5+Release-5.8`.
- **Gotcha: the editor needs a writable `~/.config/Epic`.** In the agent shell it crashed with signal 11 twice and looked like a broken install. The log named it:
`create dir('/home/zwitschi/.config/Epic/') failed: errno=30 (Read-only file system)` →
`Fatal error: Failed to create Intermediate directory '…/.config/Epic/UnrealEngine/5.8/Intermediate/'`.
Rerunning with `HOME=/tmp/uehome XDG_CONFIG_HOME=/tmp/uehome/.config` reached `LogInit: Display: Engine is initialized.`
- **Vulkan RHI is still unproven.** The successful run used `-NullRHI`. Untested: `UnrealEditor -vulkan` from a desktop terminal.
- A packaged game does not need `~/.config/Epic`, so this failure does not follow the build.
## 2026-11-07 — Agent shell limits
- The agent shell has a **read-only home** and read-only `/run`: `sudo` is blocked (`no new privileges`), `flatpak run` and `podman` cannot create instances, `/dev/nvidia*` is absent so `nvidia-smi` always fails there. None of this is a broken machine; verify GPU things from a normal terminal.
- Anything outside the session workspace (`/run/media/system/DATA/Engines`, `/tmp`) needs the wider sandbox with an approval prompt.
## 2026-11-07 — Reference photography
- **Licensing is not a gate for local development.** Reference images live in the gitignored `Art/reference/` and are never committed. What each set establishes is written into `Docs/reference-notes-hollywood.md`.
- **Commons text search runs dry; categories do not.** `Tools/commons_fetch.py --category "Category:Hollywood Masonic Temple"` surfaced 15 files a search never showed, including 4–5k px façades.
- **`upload.wikimedia.org` throttles hard.** Batches of six or fewer with `--delay 3`; a throttled file is skipped and recorded rather than killing the run (HTTP 429).
- **Unqualified queries return junk.** `Hollywood Boulevard shops` returned a Münster street, `Hollywood Masonic Temple entrance` a Seattle card index. Check the hit list before accepting a set.
- **OpenRouter web search is expensive.** One `gpt-5.2` + `openrouter:web_search` call ran 17 searches and cost **$0.38**; two of its eight URLs were Commons files already held. Use it for a known gap, not a sweep. `Tools/page_image_fetch.py` turns results into files by reading `og:image`.
- **The inherited "eight stone steps, 12 m wide" is wrong.** Photographs show three portals, each with its own short flight. Do not copy that number into geometry.
## 2026-11-06 — Blender and Blosm, headless
- **`flatpak run` does not work here.** Call the binary inside the app tree:
`B=/var/lib/flatpak/app/org.blender.Blender/x86_64/stable/active/files`, then `LD_LIBRARY_PATH="$B/blender/lib" "$B/blender/blender" -b …` with `BLENDER_USER_SCRIPTS="$HOME/.var/app/org.blender.Blender/config/blender/5.2/scripts"`.
- **Blosm needs two headless workarounds**, both already in `Tools/blosm_blockout.py`:
1. it refuses to import until an asset directory is set, and the check fires before the mode is honoured;
2. in background mode the default level table is empty, and the add-on then takes a path with a broken relative import (`from gui import addDefaultLevels`). Seeding one entry avoids it.
- **Blosm projects on a sphere, not an ellipsoid.** Its frame is about 0.4 % oversized and rotated by meridian convergence — roughly 2 m at the theatre. Fixed with a six-parameter affine into EPSG:26911 (0.0 cm residual).
- **Transform roots only.** 256 of 275 objects are children; transforming both parent and child applies the correction twice and reads as a 2 m placement error.
- **Blosm quietly fetches from Overpass** for relation members missing from the extract. `loadMissingMembers` is off by default in the tool so imports stay offline and reproducible.
## 2026-11-06 — Geo data traps
- **The 3DEP export is a tiled TIFF, not strips.** A strip reader silently scrambles rows and produces fake 0 m / 127 m bands. `Geo/scripts/dem_stats.py` handles tiles.
- **Sample walk routes through PROJ.** Placing samples with the OSM spherical approximation put them metres off the UTM meshes and reported 91 phantom holes. `/tmp` is not shared between tool calls here either — regenerate instead of saving intermediate files there.
- **3DEP cannot resolve kerbs.** Sharpest break near the kerb line is 0.09–0.12 m/m, a gutter transition, not a 0.15 m upstand. Kerb height stays a stated assumption.
- **Building interiors are not ground.** Points inside the hero footprint returned 114.5–117.1 m — structure, not terrain. Excluded from the relief figure.
- Two measurements independently agree on the carriageway: crossing length 20.9 m and gutter spacing −10 / +10…12 m.
## 2026-11-06 — Repository traps
- **Without `git lfs install` the lfs filter is inactive and `git add` does not warn** — it stores the file as a plain blob. `Tools/check-lfs.sh` is the guard.
- **Never commit reference images or `.env`.** `.gitignore` covers `/Art/reference/`, `.env`, `*.env`. When images slipped in early, history was rewritten to remove them.
- The project origin is Hollywood × Highland: `E 376 515.389 / N 3 774 224.083` in EPSG:26911. Blender X east, Y north, Z up, metres, Z measured from the origin ground (NAVD88 115.911 m). The whole block sits at negative X.
## 2026-11-07 — Unreal pipeline findings
- **UE 5.8 game targets must use `BuildSettingsVersion.V7`** to share the installed editor's build environment; V5 is rejected with "modifies the values of properties … not allowed".
- **`UnrealEditor-Cmd -run=pythonscript` swallows Python `print()`** with `-stdout` in 5.8 — write results to a file instead (see `Tools/ue_scale_test_import.py`).
- **`unreal.Box` has `min`/`max`, not `origin`/`get_extent()`** in 5.8 Python; compute centre/size from the corners.
- **FBX Blender→UE axis mapping is east→+X, north→−Y, up→+Z** with preset `ue_metric_v1`; the Y mirror is inherent (RH→LH). Compass math in game code: north = −Y. Verified with the three-cube scale test.
- Headless asset import works fine with `-nullrhi`; `unreal.AssetImportTask` + `FbxImportUI` is the pattern (Interchange pipeline under the hood).
- **Flatpak Blender headless needs `XDG_CONFIG_HOME=$HOME/.var/app/org.blender.Blender/config`** for extensions: `bpy.utils.user_resource('EXTENSIONS')` otherwise resolves to `~/.config/blender/5.2/extensions` (empty) and `bl_ext.blender_org.mpfb` is undiscoverable. Blosm unaffected (scripts/addons via `BLENDER_USER_SCRIPTS`). Found via `Tools/addon_compat_probe.py`; documented in `Art/blender/README.md`.
- **UE 5.8 Interchange skips material/texture assets for skeletal FBX imports** (static imports do get materials). Finish the chain in Python: import texture, build Material via `MaterialEditingLibrary`, assign with `sm.set_editor_property('materials', [SkeletalMaterial])` — the struct field is `material_interface`, not `material`, and `SkeletalMesh.set_material()` does not exist. See `Tools/ue_character_import.py`.
- **Blender 5.2 FBX exporter removed `armature_nla`** (passes for 4.x recipes fail). Also: a baked image is only referenced by the FBX exporter when `image.filepath` (not just `filepath_raw`) is set and the exporter can map the node — MPFB's v2 skin node-group tree can't be mapped, so a flat export material is required.
## 2026-11-07 — Collaboration and scope
- **Two sessions edit this repo at once.** The other session created the Unreal project and the blank package while this one was documenting. Check `git log` and `git status` before committing, and never `git add -A` blindly: it once swept generated `Game/GigLine/Build/**` logs into a commit. Stages the source files deliberately.
- **`Build/` under a project is generated**, not source — `FileOpenOrder/*.log` and packaging output. `.gitignore` now covers it alongside `Binaries/`, `Intermediate/`, `Saved/`, `DerivedDataCache/`.
- **Scope boundary for `0.1.0`:** do not tag `v0.1.0` without an explicit go-ahead from the owner. It is a minor release and carries the walking/driving demo promise; the board's release checks decide when it is ready, not the pace of work.
## 2026-11-07 — Screenshot pipeline
- **`-executePythonScript` + editor is unreliable for captures**: the editor quits right after a *successful* deferred script (async screenshot requests never render), and after `load_map` in a commandlet every `spawn_actor` call returns None — build scenes in the default world instead.
- **Robust in-game capture recipe**: commandlet builds a map (`ue_build_review_map.py`), then the game runs in `-game` mode and a tiny C++ actor (`AGigLineShotActor`) walks camera setups via `SetViewTarget` + `FScreenshotRequest::RequestScreenshot`. In 5.8 `FScreenshotRequest` has no resolution argument (window size via `-ResX/-ResY`) and no `IsFinished()` — poll `!IsScreenshotRequested()`. Lives in `UnrealClient.h`, not `Misc/ScreenshotManager.h`.
- **Commandlet-only quirks**: bulk render-target readback (`read_render_target_raw`, `export_render_target`) silently returns empty in commandlets; single-pixel `read_render_target_uv` works. Game targets must use `BuildSettingsVersion.V7`.
## 2026-11-07 — Enhanced Input from Python (UE 5.8)
- **`unreal.InputCoreTypes` does not exist** in the 5.8 Python bindings, and `unreal.Key` takes no constructor argument. Build a key with `k = unreal.Key(); k.import_text("SpaceBar")` — the export text is the key name (`MouseX`, `Gamepad_Left2D`).
- **Factories are `unreal.InputAction_Factory` and `unreal.InputMappingContext_Factory`**, not `InputActionFactory`. `create_asset(..., factory=None)` also works.
- **Do not delete an asset and recreate it in the same commandlet run.** `create_asset` returns `None` for a path deleted earlier in that process. Load the existing asset and overwrite it instead (`Tools/ue_create_input_assets.py: fresh()`).
- **Modifiers on `EnhancedActionKeyMapping` do not survive saving.** Assigning `InputModifierNegate` to the mapping's `modifiers` reads back correctly in memory, even after a `gc.collect()`, but the saved asset reads `mods=[NoneType]`. Keep-alive references, explicit flag setting, and in-place saves all failed to change it. Workaround: bind one action per direction (W and S as separate actions) so no modifier is needed.
- **A read-only packed `.umap` silently blocks `save_map`.** `EditorLoadingAndSavingUtils.save_map` returned `False` with no error until the file's mode was fixed (`chmod u+w`). Symptom: a rebuilt review map keeps three cameras after a fourth is added.
- `-run=pythonscript` still swallows `print()`, so write results to a file; `/tmp` is visible to the commandlets even though it is not shared between agent tool calls.
## 2026-11-07 — Hero facade build and review cameras
- **The review floor was 5 cm thick and centred at Z -50 cm**, so anything placed at Z 0 floated ~1.8 m. It is now a 90 m x 90 m x 10 cm slab with its top face at Z 0; a character's bounds should read Z 0..83 cm when it stands on it. **The review floor is the only ground in the scene.** Cameras 25 m from the building line look past its edge and see the black horizon band under the facade. Place facade cameras so both the facade and enough floor are in frame, or extend the floor.
- **The facade's frontage faces Unreal -Y.** The FBX preset maps Blender +Y (north) to Unreal -Y, so the elevation looks at negative Y and a straight-on camera must stand at **Y < -1450 cm**. A camera at positive Y looks at the back wall; cameras inside Y -1443..+250 are inside the building and render flat blue.
- **The imported mesh is centre-origin in X but not in Y or Z.** Bounds are `x -1302..1302, y -7..1250, z 0..1450` cm, so to put the front plane on the building line the actor goes at `Y = line + 7 cm`, and `X = east edge + half width`.
- **`save_map` returns False, without an error, when the packed `.umap` is read-only.** The review map silently keeps its old camera list. `chmod u+w` the file before rebuilding; a `umap` that keeps rendering four shots after a sixth was added is this, not a caching problem.
- **`StaticMaterial` is a struct**: `material.get_editor_property("material_interface")`, no `get_name()` on the wrapper.
- **Review screenshots are committed on the owner's instruction (2026-11-07).** They are large PNGs, so a review run adds weight to the repo; keep the shot list short and delete retired shots rather than accumulating.
## 2026-11-07 — Sibling project reuse survey
- **`security-game` holds 20 reusable street props** with Blender sources (`assets/models/blender_src/*.blend`) and Godot GLBs: bollard, bench, trash bin, stanchion, crowd barrier, street lamp, traffic cone, fire hydrant, newspaper box, palm/street trees, sedan, marquee, doors, lanterns. About 727 KB and 11.8k triangles for the set. Audit: `Tools/sibling_asset_audit.py`, manifest at `Art/props/reuse-manifest.json`; the 50 `.blend` sources are copied to `Art/props/blender_src/`.
- **Their building meshes are not reusable** — they are Godot GLBs built to a different key set (hero facade scaled to 29.6 m, a figure this project measured at 25.75 m). Do not import their venue geometry.
- **`tools/generate_textures.py` in that project is the OpenRouter image endpoint pattern** (`POST /api/v1/images`, `b64_json`, optional `reference_path` for image-to-image on the chat endpoint) and it already has procedural `brick_facade` / `seamless_concrete` / `asphalt` generators. Worth porting for our facade materials.
- **Its AI concept frames are restaged photograph references** (`.refgen.json` sidecars point at photos with a "keep geometry fixed" suffix). Useful as art direction, not as texture sources.
- **Blosm exposes `setupScript`** (`scene.blosm.setupScript` → `loadSetupScript`) for custom building materials, and ships `setup/neoclassical.py` as an example — the hook for giving OSM buildings a per-building facade style instead of flat colours.