Adds Tools/facade_detail_concepts.py: generates architectural detail plates from a local reference photograph through OpenRouter's image models. Spec-driven (eight studies: door recess, entrance, column order, entablature/cornice, parapet/motto, window rhythm, street wall, banner), never overwrites (writes -vN), writes a .refgen.json sidecar (model, prompt, source photo, SHA-256) per image, and keeps all output under the gitignored Art/reference/facade-details/ - local only, never shipped. Stdlib only; http 429/5xx back-off; refuses to write a sidecar containing the token. 11 tests cover the study table, prompt assembly, next-free naming, data-URL decoding (both response shapes plus a refusal) and the local-only rule. Measurement pass on the plates: the hero window panes were at Y -1.98, i.e. 1.44 m in FRONT of the wall (Y -0.50) and ahead of the column line, so the glazing floated in the colonnade instead of reading as openings behind it. Moved to Y -0.56; hero rebuilt, re-imported, DemoMap rebuilt, full screenshot set re-rendered. Docs: Tools/README row, Screenshots README known-issues entry now records the fix.
85 lines
5.2 KiB
Markdown
85 lines
5.2 KiB
Markdown
# Tools
|
|
|
|
Repeatable helpers that drive Blender, Unreal, and the reference/asset sources. Nothing here is hand-run twice: every step that produced committed content has a script.
|
|
|
|
Geographic tools live in [`Geo/tools/`](../Geo/README.md) and the Blender-side builders live next to their output in `Art/blender/*/`; this folder holds everything that talks to Unreal, the network, or the repository.
|
|
|
|
## Conventions
|
|
|
|
- One script, one job. Every input is an argument; no interactive prompts.
|
|
- Absolute paths where a tool crosses into a sandbox (Blender Flatpak, the Unreal commandlet). Those processes do not share the repo's working directory.
|
|
- Unreal commandlets swallow `print()`, so each writes a result file under `/tmp/gigline/`. Read the file; do not trust the exit code alone.
|
|
- No credentials, no writes outside the project by default.
|
|
|
|
## Repository and assets
|
|
|
|
| Tool | Purpose |
|
|
| --- | --- |
|
|
| `check-lfs.sh` | Fails if the `lfs` filter is missing or an LFS-tracked file was committed as a plain blob |
|
|
| `sibling_asset_audit.py` | Reads the sibling project's prop library from GLB headers into `Art/props/reuse-manifest.json`; copies nothing |
|
|
| `scale_test_export.py` / `ue_scale_test_import.py` | The 1 m = 100 uu scale test; the named presets `ue_metric_v1` live in these two files |
|
|
|
|
## Reference gathering
|
|
|
|
| Tool | Purpose |
|
|
| --- | --- |
|
|
| `commons_fetch.py` | Wikimedia Commons: search, exact `File:` titles, or a whole category; writes a provenance `sidecar.json` |
|
|
| `page_image_fetch.py` | Resolves a web page's `og:image` and downloads it (Flickr, Commons file pages, photo blogs) |
|
|
| `addon_compat_probe.py` | Verifies MPFB/Blosm can load and generate headless on the pinned Blender |
|
|
|
|
## Blender content
|
|
|
|
| Tool | Purpose |
|
|
| --- | --- |
|
|
| `hero_facade_build.py` | Parametric hero façade; emits a JSON report naming the evidence behind every part |
|
|
| `mpfb_character_export.py` | MPFB human, standard rig, baked skin, FBX export |
|
|
|
|
## Unreal import and level building
|
|
|
|
| Tool | Purpose |
|
|
| --- | --- |
|
|
| `ue_import_site.py` | Imports the six site FBXs into `/Game/Hollywood/Site`, setting collision complexity per mesh |
|
|
| `ue_hero_facade_import.py` | Imports the façade and places it on the measured building line |
|
|
| `ue_build_demo_map.py` | Builds `/Game/Hollywood/DemoMap`: lighting, façade, site meshes, player start |
|
|
| `ue_build_review_map.py` | Rebuilds `Test/ReviewMap`, stages the shot camera list, and stages the demo-map views |
|
|
| `ue_create_input_assets.py` | Creates `/Game/Input` actions and the mapping context headlessly |
|
|
| `ue_character_import.py` | Skeletal import plus the material/texture chain Interchange skips |
|
|
|
|
## Visual review
|
|
|
|
| Tool | Purpose |
|
|
| --- | --- |
|
|
| `render_screenshots.py` / `render_screenshots.sh` | Rebuilds the review map, runs the game, captures the shot list into `Screenshots/` |
|
|
| `judge_screenshot.py` | Vision-model pre-check: judges a screenshot against an expected-scene description (`--image` + `--expect`, or `--shots` for every shot in the README). Reads `OPENROUTER_API_KEY` from `.env` (ignored). Optional helper — a human must still approve. |
|
|
|
|
## Gameplay QA
|
|
|
|
| Command | Purpose |
|
|
| --- | --- |
|
|
| `UnrealEditor <uproject> /Game/Hollywood/DemoMap -game -qaselftest` | Headless behaviour check: drives forward input for 2 s, then resets and pauses. Logs `GigLine QA: ... PASS/FAIL` lines and a final `RESULT`. Runs only with `-qaselftest`, so normal play is unaffected. |
|
|
| `-qaselftest` phases | Walk, reset, pause/unpause, a 16-row seam transect (0 holes) and a ground-referenced wall probe (0/35), plus a frame-time capture writing `Saved/Profiling/perf-walk-frametimes.csv` and logging `GigLine PERF:`. |
|
|
| `gigline.SetupLogs` cvar | Spawn/input setup logging, **off by default** (`DefaultEngine.ini [ConsoleVariables]`); enable at runtime with `gigline.SetupLogs 1`. |
|
|
|
|
## Reference and concept generation
|
|
|
|
| Tool | Purpose |
|
|
| --- | --- |
|
|
| `facade_detail_concepts.py` | Generates architectural detail plates from a local reference photograph with an image model (OpenRouter). `--list` is free and shows which studies have their reference present; `--all`/`--only <name>` generates. Never overwrites (writes `-v2`, `-v3`), writes a `.refgen.json` sidecar per image (model, prompt, source photo, SHA-256), and puts everything under `Art/reference/facade-details/` — gitignored, local-only, never shipped. Costs money per image, so it is never automatic. |
|
|
| `judge_screenshot.py` | (see Visual review) |
|
|
|
|
## Input injection
|
|
|
|
| Tool | Purpose |
|
|
| --- | --- |
|
|
| `input_emulation.py` | Pure-stdlib `ctypes`/`fcntl` driver that creates a virtual keyboard+mouse on `/dev/uinput`. The desktop treats it as real hardware, so it proves whether OS input actually reaches the game. Needs `/dev/uinput` writable (ACL on this host). |
|
|
| `input_test.py` | Injects a scripted sequence into the focused window: `--sequence move:2,look:3,jump:1,reset:1,pause:1,click`. |
|
|
|
|
## Tests
|
|
|
|
```bash
|
|
python3 -m pip install -r requirements-tools.txt
|
|
python3 -m unittest discover -s Tools/tests -t Tools -p 'test_*.py'
|
|
```
|
|
|
|
Stdlib `unittest`, no Blender/Unreal process. See [`tests/README.md`](tests/README.md): test the pure parts (encoding, classification, maths, parsing); if logic is buried in `main()`, extract it into a function so it can be tested.
|