docs: convert all architecture .adoc sections to markdown, prettier-format all .md
- Converted 13 individual .adoc section files to .md via asciidoctor→docbook5→pandoc(gfm) + post-processing, placed alongside the .adoc sources in Docs/Architecture/ - Rebuilt architecture.md from the individual section .md files - Ran prettier --write on all .md in the repo (23 files changed): normalised table column alignment, trailing whitespace, line breaks - Added .agents/ to .prettierignore (vendored third-party content) - All .md now passes prettier --check
This commit is contained in:
1 parent
e93c27054a
commit
5aa883eaff
29 files changed
+570
-127
No files matched your search
@@ -10,3 +10,6 @@ Saved/
|
||||
*.jpeg
|
||||
*.gif
|
||||
*.webp
|
||||
|
||||
# Vendored third-party content — never reformat
|
||||
.agents/
|
||||
@@ -4,8 +4,7 @@ Working rules for autonomous agents, AI coding assistants, and contributors. Pla
|
||||
|
||||
## Project Goal
|
||||
|
||||
Develop and test on Linux; ship Windows and Linux builds, with Linux as the primary development and CI platform. The game supports walking and driving through a real city.
|
||||
The initial release is **`0.1.0`**: a walkable exterior demo around **6840 Hollywood Blvd / El Capitan Entertainment Centre**, including buildings on the south side of Hollywood Blvd between Highland Avenue and Orange Drive, plus buildings whose footprint lies within 50 m of the north-side frontage.
|
||||
Develop and test on Linux; ship Windows and Linux builds, with Linux as the primary development and CI platform. The game supports walking and driving through a real city. The initial release is **`0.1.0`**: a walkable exterior demo around **6840 Hollywood Blvd / El Capitan Entertainment Centre**, including buildings on the south side of Hollywood Blvd between Highland Avenue and Orange Drive, plus buildings whose footprint lies within 50 m of the north-side frontage.
|
||||
|
||||
- Verify the address, building footprints, and demo boundaries **before** modeling.
|
||||
- If the address, footprint, or boundary cannot be verified from permitted sources, do not model that structure. Record the unresolved item in `Geo/` with the sources checked and continue with verified structures only.
|
||||
@@ -15,7 +14,7 @@ The initial release is **`0.1.0`**: a walkable exterior demo around **6840 Holly
|
||||
## Toolchain
|
||||
|
||||
| Tool | Role |
|
||||
| --- | --- |
|
||||
| ------------- | --------------------------------------------------------- |
|
||||
| Unreal Engine | Rendering, gameplay, World Partition, Chaos Vehicles |
|
||||
| Blender | Modeling, UVs, baking, collision meshes, character prep |
|
||||
| MPFB | Human base meshes; baked materials, deform skeletons |
|
||||
@@ -80,13 +79,13 @@ Before starting any task:
|
||||
3. **Record the active branch in the heading** of the section you are working on in `TODO.md`: append `- active - <sessionId>` (and, if useful, the branch name) to the level-three heading. This is the only way other agents can see that work is in progress on this section.
|
||||
4. **Commit changes often** on that branch — small, focused commits with clear messages. Do not accumulate large uncommitted changes.
|
||||
5. **Push to remote when a checklist item is done** — each completed `- [x]` item in that section should be committed and pushed. This keeps the remote state visible and makes progress recoverable.
|
||||
6. When the section is complete, report the branch, changes, checks, and unresolved issues to the coordinator for integration (see *Parallel agent workflow* below). Do not merge into `main` yourself unless authorized.
|
||||
6. When the section is complete, report the branch, changes, checks, and unresolved issues to the coordinator for integration (see _Parallel agent workflow_ below). Do not merge into `main` yourself unless authorized.
|
||||
|
||||
**Branch hygiene:**
|
||||
|
||||
- Branch from the current `main` revision, not from a stale local checkout.
|
||||
- Keep `TODO.md` checkbox updates on your branch — they are part of the work.
|
||||
- If a task needs a different camera angle, or affects visual review, follow the *Visual review* section before pushing.
|
||||
- If a task needs a different camera angle, or affects visual review, follow the _Visual review_ section before pushing.
|
||||
- If a task is abandoned, remove the `- active - <sessionId>` suffix from the heading in `TODO.md` and leave the branch for the coordinator to clean up.
|
||||
|
||||
## Parallel agent workflow
|
||||
|
||||
@@ -57,7 +57,7 @@ LD_LIBRARY_PATH="$B/blender/lib" "$B/blender/blender" -b --factory-startup --p
|
||||
Spot checks against the measured cross-sections:
|
||||
|
||||
| Point | Terrain Z |
|
||||
| --- | ---: |
|
||||
| ----------------------------- | --------: |
|
||||
| Origin, Hollywood × Highland | 0.00 |
|
||||
| Orange Drive end of the block | +3.39 |
|
||||
| North sidewalk mid-block | +1.43 |
|
||||
@@ -104,7 +104,7 @@ Objects are appended from the source files, not regenerated, and grouped into `S
|
||||
A downward raycast on a 1 m grid along both sidewalks and the designated crossing, ignoring blockout meshes so marquees and canopies overhead do not count as ground:
|
||||
|
||||
| Route | Samples | Holes | Z range | Worst step |
|
||||
| --- | ---: | ---: | --- | ---: |
|
||||
| ----------------- | ------: | ----: | ------------- | ---------: |
|
||||
| South sidewalk | 279 | 0 | −0.45 … +3.13 | 20.5 cm |
|
||||
| North sidewalk | 279 | 0 | +0.07 … +3.83 | 15.1 cm |
|
||||
| Crossing at 130 m | 26 | 0 | +1.16 … +1.80 | 8.6 cm |
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
# Introduction and Goals
|
||||
|
||||
Gig Line is a Linux-first Unreal Engine 5 game that reconstructs a walkable (and eventually drivable) stretch of Hollywood Boulevard around 6840 Hollywood Blvd / El Capitan Entertainment Centre. The initial release (`0.1.0`) delivers a first-person walking demo of the south-side block between Highland Avenue and Orange Drive, plus north-side buildings within 50 m of the frontage.
|
||||
|
||||
## Requirements Overview
|
||||
|
||||
| ID | Description |
|
||||
| --- | --- |
|
||||
| F-1 | Walk both sides of Hollywood Blvd in the demo area without falling through geometry |
|
||||
| F-2 | First-person movement (WASD + mouse look), jump, reset (R), pause (Escape) |
|
||||
| F-3 | Fixed daytime lighting and atmosphere (sun, sky, fog, exposure) |
|
||||
| F-4 | Geographic attribution display (ODbL: "© OpenStreetMap contributors" + licence link) |
|
||||
| F-5 | Designated street crossing with zebra markings at signalised crossings |
|
||||
| F-6 | Building façades recognisable against reference photography |
|
||||
| F-7 | Terrain, road, and sidewalk follow real-world DEM elevation |
|
||||
| F-8 | 60 FPS at 1440p on the documented workstation and quality preset |
|
||||
|
||||
Full requirements and progress are in [TODO.md](../../TODO.md); version direction is in [ROADMAP.md](../../ROADMAP.md).
|
||||
|
||||
## Quality Goals
|
||||
|
||||
| Priority | Quality Goal | Scenario |
|
||||
| --- | --- | --- |
|
||||
| 1 | **Performance efficiency** | 60 FPS at 2560×1440 on RTX 5070 Ti, documented preset, no frame generation |
|
||||
| 2 | **Terrain walkability** | Zero raycast holes across both sidewalks and the carriageway (84-sample transect passes) |
|
||||
| 3 | **Geographic fidelity** | Building placement, street scale, and façade identity match reference photography |
|
||||
| 4 | **Build reproducibility** | Fresh checkout + documented engine path produces a runnable Linux build |
|
||||
| 5 | **Licensing compliance** | Every redistributable asset has verified provenance; ODbL attribution is visible at runtime |
|
||||
|
||||
## Stakeholders
|
||||
|
||||
| Role | Contact | Expectations |
|
||||
| --- | --- | --- |
|
||||
| Owner / Director | zwitschi | Sets scope, approves screenshots, cuts release tags |
|
||||
| AI coding agents | multiple sessions | Read `AGENTS.md`, `TODO.md`, `ROADMAP.md`, and this document for architecture constraints; never commit directly to `main` |
|
||||
| Players | end users | Walk the demo at 60 FPS without falling through the world; see a recognisable Hollywood block |
|
||||
| OSM contributors | OpenStreetMap | ODbL attribution is displayed and derivative-database obligations are met |
|
||||
@@ -0,0 +1,32 @@
|
||||
# Architecture Constraints
|
||||
|
||||
## Technical Constraints
|
||||
|
||||
| Constraint | Explanation |
|
||||
| --- | --- |
|
||||
| Engine: Unreal 5.8.4 | Pinned; no bundled Linux clang — uses system clang 23.1.4. Game targets use `BuildSettingsVersion.V7`. |
|
||||
| Platform: Linux first | Developed and tested on Bazzite Linux (Fedora 45 base). Windows builds ship but are secondary. |
|
||||
| GPU: RTX 5070 Ti 16 GB | Dev workstation target. Vulkan RHI; open kernel module driver 615.78.08. |
|
||||
| No static lighting | `r.AllowStaticLighting=False`. The demo is a fixed daytime scene lit entirely dynamically to avoid "LIGHTING NEEDS TO BE REBUILT" warnings. |
|
||||
| Blender→UE via FBX | Flat diffuse colours do not survive FBX→Unreal import. All materials are authored in UE. |
|
||||
| Terrain collision | UE 5.8 exposes `CollisionTraceFlag` (not `bUseComplexAsSimpleCollision`); Python cannot set it. Must use C++ helper `UGigLineAssetTools::SetComplexCollisionAsSimple`. |
|
||||
| Coordinate convention | South = +Y, north = −Y (ground truth = street mesh orientation). 1 m in Blender = 100 cm in Unreal. |
|
||||
|
||||
## Organisational Constraints
|
||||
|
||||
| Constraint | Explanation |
|
||||
| --- | --- |
|
||||
| Squash-merge to `main` | Every PR is squash-merged for a linear history. No direct commits to `main` except integration merges. |
|
||||
| Visual review required | Any change affecting appearance must produce screenshots for human approval before being marked done. |
|
||||
| Asset provenance | Every committed asset must have verified licence and redistribution permission recorded in `THIRD_PARTY_NOTICES.md`. |
|
||||
| Reference photography | Local only, gitignored, never committed. Used for façade work under fair-use / internal-development rationale. |
|
||||
| LFS for binaries | `.uasset`, `.umap`, `.blend` tracked with Git LFS; `Binaries/`, `Intermediate/`, `Saved/` are gitignored. |
|
||||
|
||||
## Conventions
|
||||
|
||||
| Convention | Explanation |
|
||||
| --- | --- |
|
||||
| Semantic versioning | `MAJOR.MINOR.PATCH`. `0.x` documents breaking changes. `1.0.0` = agreed game scope. |
|
||||
| Task tracking in `TODO.md` | Single central task list. `- [ ]` open, `- [-]` or `- [~]` in progress, `- [x]` done, `- [A]` active, `- [D]` deferred. |
|
||||
| Headless Blender | All Blender work driven by `bpy` scripts in `Tools/`, not MCP. Blender skills are method guides only. |
|
||||
| Named export presets | `ue_metric_v1` for static meshes, `ue_character_v1` for skeletal. Every exporter calls the metre→centimetre conversion. |
|
||||
@@ -0,0 +1,22 @@
|
||||
# Context and Scope
|
||||
|
||||
## Business Context
|
||||
|
||||
The system is a self-contained single-player game. It has no server backend, no multiplayer, and no live service dependencies. Its communication partners are:
|
||||
|
||||
| Partner | Inbound | Outbound |
|
||||
| --- | --- | --- |
|
||||
| Player (keyboard/mouse) | WASD, mouse, R (reset), Escape (pause), Space (jump) | Rendered 3D scene + HUD |
|
||||
| OSM data | Extracted building footprints, street geometry, elevation | Attribution string at runtime |
|
||||
| Filesystem | Engine content (`.uasset`, `.umap`), Blender sources (`.blend`), DEM GeoTIFF | Saved maps, screenshots, packaged build |
|
||||
|
||||
## Technical Context
|
||||
|
||||
| Channel | Protocol / Format | Purpose |
|
||||
| --- | --- | --- |
|
||||
| Keyboard + mouse | Enhanced Input (IA\_\*, IMC_Default) | First-person movement, look, jump, reset, pause |
|
||||
| Vulkan RHI | GPU rendering | Scene display at 60 FPS / 1440p |
|
||||
| FBX | Autodesk FBX (binary) | Blender→Unreal mesh and skeleton transfer |
|
||||
| GeoTIFF | 3DEP 1 m DEM | Terrain heightfield source |
|
||||
| OSM XML | Overpass API extract | Building footprint and street layout source |
|
||||
| Git / LFS | HTTPS to Gitea remote | Source control, binary asset storage |
|
||||
@@ -0,0 +1,39 @@
|
||||
# Solution Strategy
|
||||
|
||||
## Technology decisions
|
||||
|
||||
- **Unreal Engine 5.8.4** for rendering, World Partition, physics (Chaos), and the Enhanced Input system. Chosen for its Linux support, open C++ source, and real-time rendering quality.
|
||||
|
||||
- **Blender 5.2 LTS** for all 3D modelling, UV work, and collision mesh authoring. Driven headlessly via `bpy` Python scripts, not MCP.
|
||||
|
||||
- **QGIS 4.2.3** for geographic data cleanup, coordinate conversion (EPSG:26911), and DEM preparation.
|
||||
|
||||
- **Blosm 2.7.28** for OSM building and street blockouts inside Blender (layout data only — not authoritative façade, height, or pavement detail).
|
||||
|
||||
- **MPFB 2.0.18** for human base meshes and baked materials (NPCs in `0.2.0+`).
|
||||
|
||||
## Top-level decomposition
|
||||
|
||||
The system is a single Unreal game module (`GigLine`) with no plugins beyond `EnhancedInput`. Content is organised by domain under `/Game/Hollywood/`:
|
||||
|
||||
- `Site/` — terrain, road, sidewalks, kerbs, crossing markings, site materials
|
||||
|
||||
- `ElCapitan/` — hero façade mesh and materials
|
||||
|
||||
- `Frontage/` — south-side block building meshes
|
||||
|
||||
- `North/` — north-side building meshes
|
||||
|
||||
- `Input/` — Enhanced Input actions and mapping context
|
||||
|
||||
All modelling and geographic processing live outside the game project in `Art/`, `Geo/`, and `Tools/`. The `Game/` directory contains only engine-ready content and C++ source.
|
||||
|
||||
## Quality achievement
|
||||
|
||||
- **Performance**: dynamic-only lighting (no build step, no static shadow maps), world-space-noise materials (cheap procedural variation), minimal overdraw (simple street-level geometry).
|
||||
|
||||
- **Walkability**: complex-as-simple collision on terrain (C++ helper forces the flag on the asset), block-all collision on every site mesh, swept transect QA verifies zero raycast holes.
|
||||
|
||||
- **Fidelity**: geographic data verified before modelling (footprints, bounds, DEM); building placement checked against street mesh, never in isolation; reference photography drives façade work.
|
||||
|
||||
- **Reproducibility**: pinned toolchain in `Docs/toolchain.md`, named export presets, `Tools/check-lfs.sh` gate, fresh-checkout build procedure in `Docs/build.md`.
|
||||
@@ -0,0 +1,96 @@
|
||||
# Building Block View
|
||||
|
||||
## Whitebox Overall System
|
||||
|
||||
The system decomposes into five top-level building blocks:
|
||||
|
||||
| **Name** | **Responsibility** |
|
||||
| --- | --- |
|
||||
| Gameplay | Player pawn, movement, camera, input bindings, HUD, game mode |
|
||||
| Site | Terrain, road, sidewalks, kerbs, crossing markings, site-level collision |
|
||||
| Façades | Hero façade (El Capitan), south block frontage, north-side buildings |
|
||||
| Art Pipeline | Blender models, geographic data, export scripts, import scripts |
|
||||
| QA & Review | Screenshot pipeline, self-test harness, visual review workflow |
|
||||
|
||||
### Gameplay
|
||||
|
||||
C++ classes in `Game/GigLine/Source/GigLine/`:
|
||||
|
||||
| Class | Responsibility | Key detail |
|
||||
| --- | --- | --- |
|
||||
| `AGigLineCharacter` | First-person player pawn | 1.75 m capsule, 4.5 m/s walk, Enhanced Input bindings, reset, pause, `-qaselftest` harness |
|
||||
| `AGigLineGameModeBase` | Sets game mode and HUD class | `HUDClass = AGigLineHUD` |
|
||||
| `AGigLineHUD` | ODbL attribution overlay | `DrawText` every frame, bottom-left |
|
||||
| `AGigLineNPCPerson` | NPC prefab (future) | Capsule + visible MPFB body, feet on Z 0 |
|
||||
| `AGigLineShotActor` | Screenshot camera walker | Drives cameras in `-game` mode, `FScreenshotRequest`, quits |
|
||||
| `UGigLineAssetTools` | C++ collision helpers | `SetComplexCollisionAsSimple` on `StaticMesh` assets |
|
||||
|
||||
Input assets in `/Game/Input/`: `IA_Move`, `IA_MoveBack`, `IA_Strafe`, `IA_StrafeLeft`, `IA_Look`, `IA_Jump`, `IA_Reset`, `IA_Pause`, bound in `IMC_Default`.
|
||||
|
||||
### Site
|
||||
|
||||
Static meshes and materials in `/Game/Hollywood/Site/`:
|
||||
|
||||
| Asset | Role |
|
||||
| --- | --- |
|
||||
| `Terrain_DEM` | Ground heightfield (complex-as-simple collision) |
|
||||
| `Road_Hollywood` | Carriageway surface (block-all collision) |
|
||||
| `Sidewalk_North`, `Sidewalk_South` | Pedestrian surfaces (block-all collision) |
|
||||
| `Kerb_North`, `Kerb_South` | Kerb edges |
|
||||
| `Crossing_Markings` | Zebra markings at signalised crossing |
|
||||
| `M_Asphalt`, `M_Concrete`, `M_KerbConcrete`, `M_Ground`, `M_RoadPaint`, `M_Stucco`, `M_FacadeStone` | Procedural materials (world-space-noise blend + roughness) |
|
||||
|
||||
### Façades
|
||||
|
||||
| Asset | Role |
|
||||
| --- | --- |
|
||||
| `SM_HeroFacade` | El Capitan Entertainment Centre detailed façade |
|
||||
| `SM_ElCapitanTheatre`, `SM_Budget_6822`, `SM_Hollywood_6806`, `SM_Hollywood_6902`, `SM_Hollywood_6922`, `SM_LeeDrug_6800` | South block frontage (6 buildings) |
|
||||
| `SM_Madame_Tussauds`, `SM_TCL_Chinese_Theatre` | North-side buildings (within 50 m) |
|
||||
|
||||
### Art Pipeline
|
||||
|
||||
Python scripts in `Tools/` drive the content pipeline:
|
||||
|
||||
| Script group | Purpose |
|
||||
| --- | --- |
|
||||
| `export_*`, `hero_facade_build` | Blender headless export (FBX) |
|
||||
| `ue_import_*`, `ue_hero_facade_import` | Unreal headless import + placement |
|
||||
| `ue_build_demo_map`, `ue_build_review_map` | Map assembly (lighting, meshes, player start) |
|
||||
| `ue_create_input_assets` | Enhanced Input actions + mapping context |
|
||||
| `render_screenshots.sh` | Screenshot capture pipeline |
|
||||
| `judge_screenshot.py` | Vision-model pre-check (optional) |
|
||||
|
||||
Source data: `Art/blender/` (`.blend` files), `Geo/` (OSM extracts, DEM, verification docs).
|
||||
|
||||
### QA & Review
|
||||
|
||||
- `AGigLineShotActor` walks fixed cameras in `-game` mode, captures PNGs, and quits.
|
||||
|
||||
- `-qaselftest` switch on `AGigLineCharacter` runs a core-ticker harness: walk 2 s, reset, pause/unpause, ground transect — all PASS/FAIL logged.
|
||||
|
||||
- `Screenshots/` holds committed PNGs and `README.md` approval table.
|
||||
|
||||
## Level 2
|
||||
|
||||
### White Box Gameplay — Input Flow
|
||||
|
||||
1. `AGigLineCharacter::SetupPlayerInputComponent` binds `IA_*` actions to `MoveForward`, `MoveBack`, `MoveStrafe`, `MoveLeft`, `Look`, `StartJump`/`StopJump`, `ResetToStart`, `TogglePause`.
|
||||
|
||||
2. Movement delegates to `ApplyMove(Forward, Strafe)` → `AddMovementInput`.
|
||||
|
||||
3. Look applies yaw/pitch scaled by `LookSensitivity` (Y invertable via `bInvertLookY`).
|
||||
|
||||
4. `ResetToStart` teleports to `StartLocation` (captured on first grounded frame), clears velocity, resets control rotation.
|
||||
|
||||
5. `TogglePause` toggles `APlayerController::SetPause`, swaps input mode between `FInputModeGameOnly` and `FInputModeUIOnly`, shows/hides mouse cursor.
|
||||
|
||||
### White Box Site — Collision Model
|
||||
|
||||
- Every site mesh (road, sidewalks, kerbs, crossing) is `STATIC` with `BlockAll` collision.
|
||||
|
||||
- `Terrain_DEM` uses `CTF_UseComplexAsSimple` (forced by `UGigLineAssetTools` at build time, saved on the asset).
|
||||
|
||||
- The terrain corridor is carved to half-width 10.7 m around the road centreline so the player can walk the carriageway and both sidewalks.
|
||||
|
||||
- Ground Z: north sidewalk 395, road 366, south sidewalk 317 (3.94 m fall along the block, matching the DEM).
|
||||
@@ -0,0 +1,53 @@
|
||||
# Runtime View
|
||||
|
||||
## Walk the block
|
||||
|
||||
1. Player launches game → `AGigLineGameModeBase` spawns `AGigLineCharacter` at `PlayerStart` `(-13336, -1150, 600)`.
|
||||
|
||||
2. Character falls 144 cm to road surface (Z 456) and begins walking. `StartLocation` captured on first grounded frame.
|
||||
|
||||
3. Player holds W → `IA_Move` fires → `ApplyMove(1, 0)` → `AddMovementInput(ForwardVector, 1)` → capsule moves at 450 cm/s.
|
||||
|
||||
4. Mouse move → `IA_Look` fires → yaw/pitch applied to controller rotation → camera follows (attached to capsule at 160 cm eye height).
|
||||
|
||||
5. Player presses R → `ResetToStart` → teleport to `StartLocation`/`StartRotation`, `StopMovementImmediately`, reset control rotation.
|
||||
|
||||
6. Player presses Escape → `TogglePause` → `SetPause(true)`, switch to `FInputModeUIOnly`, show cursor. World timers stop; core tickers continue.
|
||||
|
||||
7. Player presses Escape again → `TogglePause` → `SetPause(false)`, switch to `FInputModeGameOnly`, hide cursor.
|
||||
|
||||
## Screenshot capture
|
||||
|
||||
1. `Tools/render_screenshots.sh` compiles editor, builds `ReviewMap` from `Tools/ue_build_review_map.py`, launches game in `-game` mode.
|
||||
|
||||
2. `AGigLineShotActor` iterates the camera list, sets view, calls `HighResShot 1280x720`, waits for capture.
|
||||
|
||||
3. On last camera, requests engine quit. PNGs are copied to `Screenshots/` and committed.
|
||||
|
||||
## QA self-test (`-qaselftest`)
|
||||
|
||||
1. Core ticker starts at `BeginPlay` (not a world timer — world timers freeze on pause).
|
||||
|
||||
2. 1.0 s: begin driving forward input.
|
||||
|
||||
3. 3.0 s: stop, measure displacement (> 200 cm = PASS).
|
||||
|
||||
4. 3.5 s: call `ResetToStart`.
|
||||
|
||||
5. 4.0 s: measure distance from spawn (< 100 cm = PASS).
|
||||
|
||||
6. 4.5 s: call `TogglePause`, check `IsGamePaused()` (= true = PASS).
|
||||
|
||||
7. 5.5 s: call `TogglePause`, check `IsGamePaused()` (= false = PASS).
|
||||
|
||||
8. 6.0 s: swept ground transect across three lanes (Y −1400, −167, +1000), X −14900 to −9420 at 200 cm spacing. 84 samples, 0 holes = PASS.
|
||||
|
||||
9. 7.0 s: final verdict logged.
|
||||
|
||||
## Build and import pipeline
|
||||
|
||||
1. Blender headless (`Tools/export_*.py`) reads `.blend` files, applies metre→centimetre conversion, exports FBX with `ue_metric_v1` preset.
|
||||
|
||||
2. Unreal headless (`Tools/ue_import_*.py`) imports FBX via Interchange, places meshes at geographic coordinates, sets collision profiles.
|
||||
|
||||
3. `Tools/ue_build_demo_map.py` assembles `DemoMap`: creates/repositions actors, sets lighting, saves map and assets.
|
||||
@@ -0,0 +1,40 @@
|
||||
# Deployment View
|
||||
|
||||
## Infrastructure Level 1 — Development Workstation
|
||||
|
||||
| Node | Specification |
|
||||
| --- | --- |
|
||||
| Dev workstation | Bazzite Linux 45 (Fedora 45 base, immutable ostree), Ryzen 7 7700X, 64 GB RAM, RTX 5070 Ti 16 GB, Vulkan RHI |
|
||||
| Engine install | `/run/media/system/DATA/Engines/UE_5.8.4` (73 GiB, external to repo) |
|
||||
| Project repo | `/run/media/system/DATA/Documents/06-games/gig-line` (Git + LFS, remote at `git.allucanget.biz`) |
|
||||
| Build output | `/run/media/system/DATA/Builds/GigLine` (packaged Linux build, ~1.1 GiB) |
|
||||
|
||||
Motivation
|
||||
Single-machine development. No build farm, no CI pipeline yet. The engine, toolchain, and GPU are all on the same host.
|
||||
|
||||
Quality and Performance Features
|
||||
|
||||
- Vulkan RHI on RTX 5070 Ti, open kernel module driver 615.78.08.
|
||||
|
||||
- System clang 23.1.4 (no bundled engine clang) compiles game code.
|
||||
|
||||
- Build time: ~90 s incremental, ~5 min clean for the editor target.
|
||||
|
||||
Mapping of Building Blocks to Infrastructure
|
||||
|
||||
| Building Block | Infrastructure Element |
|
||||
| --- | --- |
|
||||
| Gameplay (C++) | Dev workstation — compiled to `libUnrealEditor-GigLine.so`, loaded by engine |
|
||||
| Site + Façades (UE content) | Dev workstation — `.uasset`/`.umap` in `Game/GigLine/Content/` |
|
||||
| Art Pipeline (Python/Blender) | Dev workstation — headless Blender 5.2 Flatpak, Python 3.14.8 |
|
||||
| QA & Review | Dev workstation — game run in `-game` mode, PNGs to `Screenshots/` |
|
||||
| Git remote | `git.allucanget.biz` — Gitea instance, LFS-enabled |
|
||||
|
||||
## Infrastructure Level 2 — Packaged Build
|
||||
|
||||
| Element | Detail |
|
||||
| --- | --- |
|
||||
| Linux packaged build | Development config, ~1.1 GiB. Contains engine binaries, game module, cooked content, no editor. |
|
||||
| Run command | `./GigLine.sh -windowed -ResX=2560 -ResY=1440` |
|
||||
|
||||
No server infrastructure. The game is a standalone executable.
|
||||
@@ -0,0 +1,57 @@
|
||||
# Cross-cutting Concepts
|
||||
|
||||
## Coordinate system and scale
|
||||
|
||||
- **Source CRS**: EPSG:26911 (UTM zone 11N). Local origin recorded in `Geo/`.
|
||||
|
||||
- **Blender**: metres. East → +X, north → +Y (Blender convention).
|
||||
|
||||
- **Unreal**: centimetres. East → +X, north → **−Y** (confirmed from street mesh: `Sidewalk_North` Y −1912..−1053, `Sidewalk_South` Y +718..+1447).
|
||||
|
||||
- **Conversion**: every exporter calls the metre→centimetre function. Import presets (`ue_metric_v1`, `ue_character_v1`) are named and repeatable.
|
||||
|
||||
Rule: place a building only against a neighbour or street mesh, never in isolation.
|
||||
|
||||
## Collision model
|
||||
|
||||
- Site meshes (road, sidewalks, kerbs, crossing): `STATIC` mobility, `BlockAll` collision profile.
|
||||
|
||||
- Terrain: `STATIC`, `CTF_UseComplexAsSimple` (forced by `UGigLineAssetTools` at build time, saved on the asset — the flag lives on the `UStaticMesh`/`UBodySetup`, not the map).
|
||||
|
||||
- Buildings: `STATIC`, simple collision (convex hull from mesh).
|
||||
|
||||
- Rule: the collision flag must be saved on the asset. Saving only the `.umap` silently reverts it.
|
||||
|
||||
## Lighting
|
||||
|
||||
- Dynamic-only: `r.AllowStaticLighting=False`. All lights are `MOVABLE`.
|
||||
|
||||
- Fixed daytime rig: directional light (sun, −62° pitch), sky light, exponential height fog, post-process volume with fixed exposure.
|
||||
|
||||
- Rationale: avoids "LIGHTING NEEDS TO BE REBUILT" warnings; no bake step; the scene never changes time of day.
|
||||
|
||||
## Materials
|
||||
|
||||
- All materials authored in Unreal, not carried from Blender (FBX import loses diffuse colours).
|
||||
|
||||
- World-space-noise blend nodes for cheap procedural variation (asphalt grain, concrete speckle, stucco roughness).
|
||||
|
||||
- Instance parameters where tunable (e.g. wetness, ageing).
|
||||
|
||||
## Geographic data provenance
|
||||
|
||||
- OSM extract is layout data only — not authoritative for façade, height, or pavement detail.
|
||||
|
||||
- DEM from 3DEP 1 m; elevation verified against cross-sections in `Geo/verification/`.
|
||||
|
||||
- Reference photography (local, gitignored) drives manual façade work.
|
||||
|
||||
- In-game ODbL attribution drawn by `AGigLineHUD` every frame, bottom-left.
|
||||
|
||||
## QA harness
|
||||
|
||||
- `-qaselftest`: core ticker (not world timer) so pause cannot freeze the test that proves pause works.
|
||||
|
||||
- `GigLine SIM` / `GigLine GROUND`: TEMP diagnostic logging, to be removed before release tag.
|
||||
|
||||
- Screenshot approval: human must tick `Screenshots/README.md` before visual work is marked done.
|
||||
@@ -0,0 +1,57 @@
|
||||
# Architecture Decisions
|
||||
|
||||
## ADR-1: Dynamic-only lighting for the demo
|
||||
|
||||
- **Context**: The demo is a fixed daytime scene. Stationary lights demand a lighting build and produce "LIGHTING NEEDS TO BE REBUILT" warnings.
|
||||
|
||||
- **Decision**: `r.AllowStaticLighting=False`, all lights `MOVABLE`.
|
||||
|
||||
- **Consequences**: No bake step, no warning, simpler iteration. Slightly higher GPU cost per frame (no baked shadows) — acceptable for the demo scope.
|
||||
|
||||
## ADR-2: Materials authored in Unreal, not imported from Blender
|
||||
|
||||
- **Context**: FBX→Unreal import maps all Blender diffuse colours to white. Flat colour materials do not survive the pipeline.
|
||||
|
||||
- **Decision**: Build all materials (asphalt, concrete, stucco, façade stone, road paint) directly in Unreal with procedural nodes.
|
||||
|
||||
- **Consequences**: Materials cannot be previewed in Blender look-dev. Must round-trip to Unreal for visual check. But: full PBR control, world-space noise, no import surprise.
|
||||
|
||||
## ADR-3: Complex-as-simple collision on terrain via C++ helper
|
||||
|
||||
- **Context**: UE 5.8 removed `bUseComplexAsSimpleCollision`. Python cannot set `CollisionTraceFlag` on `StaticMesh`/`BodySetup` at all. The Interchange default is bbox-only simple collision, which placed an invisible lid 8 m above the street.
|
||||
|
||||
- **Decision**: `UGigLineAssetTools::SetComplexCollisionAsSimple` (C++) forces `CTF_UseComplexAsSimple` and saves the asset.
|
||||
|
||||
- **Consequences**: One C++ helper class. The flag must be saved on the asset (not just the map). No Python workaround exists.
|
||||
|
||||
## ADR-4: Reset captures StartLocation on first grounded frame
|
||||
|
||||
- **Context**: `BeginPlay` captures `StartLocation` at the PlayerStart, which is above grade (Z 600) so the capsule does not spawn embedded. Every reset dropped the player 1.4 m back into the air.
|
||||
|
||||
- **Decision**: Repeating 0.25 s timer captures `StartLocation` once the character reports `IsMovingOnGround()`, then clears itself.
|
||||
|
||||
- **Consequences**: Reset is correct. A one-shot timer at 2 s is wrong (fires after walking begins, records mid-stride position).
|
||||
|
||||
## ADR-5: Core ticker for QA self-test, not world timer
|
||||
|
||||
- **Context**: Pausing the game stops world timers. A timer-driven test freezes exactly when it proves pause works.
|
||||
|
||||
- **Decision**: `FTSTicker::GetCoreTicker()` drives the `-qaselftest` harness.
|
||||
|
||||
- **Consequences**: Test runs even while paused. Must be enabled explicitly (`-qaselftest`), never in normal play.
|
||||
|
||||
## ADR-6: South = +Y, north = −Y in Unreal
|
||||
|
||||
- **Context**: The street mesh established this convention: `Sidewalk_North` has Y range −1912..−1053, `Sidewalk_South` has +718..+1447.
|
||||
|
||||
- **Decision**: Adopt it project-wide. Never place a building by assumption; always verify against a street mesh or neighbour.
|
||||
|
||||
- **Consequences**: Matches Blender’s north→+Y after the Y-flip in the `ue_metric_v1` export preset.
|
||||
|
||||
## ADR-7: Headless Blender via bpy scripts, not MCP
|
||||
|
||||
- **Context**: Blender skill packs assume an MCP server; the project does not run one.
|
||||
|
||||
- **Decision**: All Blender work driven by Python scripts in `Tools/`. Skill packs used as method guides (checklists, naming, proportions) only.
|
||||
|
||||
- **Consequences**: Scripts are version-controlled and repeatable. No live Blender session needed for CI.
|
||||
@@ -0,0 +1,26 @@
|
||||
# Quality Requirements
|
||||
|
||||
## Quality Requirements Overview
|
||||
|
||||
| Category | Requirement | Priority |
|
||||
| --- | --- | --- |
|
||||
| Performance efficiency | 60 FPS at 2560×1440, documented preset, no frame generation | 1 |
|
||||
| Reliability / Terrain | Zero raycast holes across sidewalks and carriageway (84-sample transect) | 1 |
|
||||
| Accuracy / Fidelity | Building placement matches reference photography within ~1 m | 2 |
|
||||
| Accuracy / Fidelity | Street scale (lane width, sidewalk width) within ~10 cm of measured profile | 2 |
|
||||
| Usability | WASD + mouse look, jump, reset (R), pause (Escape) — no tutorial needed | 2 |
|
||||
| Compliance | ODbL attribution visible at runtime | 2 |
|
||||
| Maintainability | Fresh checkout builds with documented engine installation | 2 |
|
||||
| Portability | Linux build packages and runs; Windows build ships | 3 |
|
||||
|
||||
## Quality Scenarios
|
||||
|
||||
| ID | Source/Stimulus | Response | Metric |
|
||||
| --- | --- | --- | --- |
|
||||
| QS-1 | Player walks both sides of the demo | No fall-through, character stays at ground Z | 0 raycast holes in 84-sample transect |
|
||||
| QS-2 | Player holds W for 2 s on flat road | Character moves forward | ≥ 200 cm displacement, Z constant within ±5 cm |
|
||||
| QS-3 | Player presses R | Character teleports to spawn | < 100 cm from `StartLocation` |
|
||||
| QS-4 | Player presses Escape | Game pauses, cursor appears | `IsGamePaused()` = true |
|
||||
| QS-5 | Player presses Escape while paused | Game unpauses, cursor hides | `IsGamePaused()` = false |
|
||||
| QS-6 | Game runs on dev workstation at 1440p | Frame rate stable | ≥ 60 FPS, 99th percentile ≥ 55 FPS |
|
||||
| QS-7 | Fresh checkout + engine install | Build succeeds | Exit code 0, runnable binary produced |
|
||||
@@ -0,0 +1,11 @@
|
||||
# Risks and Technical Debts
|
||||
|
||||
| ID | Risk / Debt | Priority | Mitigation |
|
||||
| --- | --- | --- | --- |
|
||||
| R-1 | Terrain bbox proxy misdiagnosed as fall-through — already fixed, but the root-cause path (Interchange defaults to simple collision) could recur on reimport | High | `UGigLineAssetTools` runs in the build script; always reassert complex-as-simple after any reimport. Documented in `MEMORY.md` and ADR-3. |
|
||||
| R-2 | Blosm 3Dsimple on Blender 5.2 — worked around, not resolved; `3Drealistic` mode untested | Medium | Pin Blosm 2.7.28 and Blender 5.2 LTS; test realistic mode before depending on it. |
|
||||
| R-3 | Kerb height is an assumption (DEM does not resolve it) | Medium | Record the assumption in `Geo/verification/`; measure from reference photography if possible; mark as unresolved until verified. |
|
||||
| R-4 | ODbL derivative-database posture for shipped builds is open | Medium | In-game attribution is done; legal review of shipped-DB obligations needed before public release. |
|
||||
| R-5 | `GigLine SIM` / `GigLine GROUND` TEMP diagnostic logging still in `GigLineCharacter.cpp` | Medium | Strip behind a cvar or remove entirely before the `v0.1.0` release tag. |
|
||||
| TD-1 | Materials are Unreal-only — no Blender preview round-trip | Low | Accepted (ADR-2). Look-dev happens in UE; screenshot review catches issues. |
|
||||
| TD-2 | No CI pipeline — all builds and QA are manual on the dev workstation | Low | Acceptable for `0.x`. CI is a `0.3.0+` concern. |
|
||||
@@ -0,0 +1,20 @@
|
||||
# Glossary
|
||||
|
||||
| Term | Definition |
|
||||
| --- | --- |
|
||||
| Blosm | Blender add-on (2.7.28) that imports OSM data as 3D building and street blockouts. Used for layout only — not authoritative for façade or height. |
|
||||
| Complex-as-simple collision | `CTF_UseComplexAsSimple`: Unreal collision mode where the render mesh triangles are used as the collision surface, instead of a simplified proxy. Required for terrain so the player walks on the actual ground shape. |
|
||||
| DEM | Digital Elevation Model. 3DEP 1 m resolution GeoTIFF covering the demo bounds. Source of terrain heightfield. |
|
||||
| El Capitan | El Capitan Entertainment Centre, 6838 Hollywood Blvd. The hero building of the demo. |
|
||||
| Enhanced Input | Unreal’s modern input system (UE 5+). Uses Input Actions (`IA_*`) and Input Mapping Contexts (`IMC_*`) instead of legacy axis/action bindings. |
|
||||
| EPSG:26911 | UTM zone 11N, the projected CRS used for the demo area. Local origin recorded in `Geo/`. |
|
||||
| Hero façade | The detailed, reference-calibrated model of the El Capitan building frontage. |
|
||||
| MPFB | MakeHuman Plugin for Blender (2.0.18). Generates parametric human base meshes with rigs and baked materials. |
|
||||
| ODbL | Open Database Licence 1.0. The licence covering OSM-derived data. Requires attribution and may impose share-alike on derivative databases. |
|
||||
| PlayerStart | Unreal actor that defines where the player pawn spawns. Positioned above grade so the capsule does not embed in the floor on spawn. |
|
||||
| QA self-test | The `-qaselftest` command-line switch that runs an automated behaviour check (walk, reset, pause, ground transect) via a core ticker. |
|
||||
| Site | The terrain, road, sidewalks, kerbs, and crossing markings — the ground-level infrastructure of the demo area. |
|
||||
| Squash merge | Git merge strategy that compresses all branch commits into one commit on `main`, keeping a linear history. |
|
||||
| Swept transect | A QA technique that raycasts vertically at regular intervals along a path (e.g. every 200 cm along both sidewalks and the carriageway) and counts holes (misses). Zero holes = the block is fully walkable. |
|
||||
| World Partition | Unreal’s world composition system for large open-world levels. Not yet used in `0.1.0` but planned for `0.3.0+` driving routes. |
|
||||
| Y convention | In Unreal, south = +Y, north = −Y (confirmed from street mesh orientation). In Blender, north = +Y; the `ue_metric_v1` export preset flips Y. |
|
||||
@@ -0,0 +1,13 @@
|
||||
**About arc42**
|
||||
|
||||
<div data-wrapper="1" role="lead">
|
||||
|
||||
arc42, the template for documentation of software and system architecture.
|
||||
|
||||
</div>
|
||||
|
||||
Template Version 0.1.0. initial architecture documentation, 2026-11-08
|
||||
|
||||
Created, maintained and © by Dr. Peter Hruschka, Dr. Gernot Starke and contributors. See <https://arc42.org>.
|
||||
|
||||
Adapted for the Gig Line project (Linux-first walking/driving demo around 6840 Hollywood Blvd).
|
||||
@@ -510,6 +510,14 @@ Rule: place a building only against a neighbour or street mesh, never in isolati
|
||||
|
||||
**About arc42**
|
||||
|
||||
<div data-wrapper="1" role="lead">
|
||||
|
||||
arc42, the template for documentation of software and system architecture.
|
||||
|
||||
Template Version 0.1.0. Adapted for the Gig Line project. Created, maintained and © by Dr. Peter Hruschka, Dr. Gernot Starke and contributors. See <https://arc42.org>.
|
||||
</div>
|
||||
|
||||
Template Version 0.1.0. initial architecture documentation, 2026-11-08
|
||||
|
||||
Created, maintained and © by Dr. Peter Hruschka, Dr. Gernot Starke and contributors. See <https://arc42.org>.
|
||||
|
||||
Adapted for the Gig Line project (Linux-first walking/driving demo around 6840 Hollywood Blvd).
|
||||
+5
-18
@@ -10,8 +10,7 @@ Fresh-checkout build procedure. Completed 2026-11-07 after the pinned engine was
|
||||
|
||||
## Engine
|
||||
|
||||
Pinned install: **Unreal Engine 5.8.4** (CL 58902052, promoted build) at
|
||||
`/run/media/system/DATA/Engines/UE_5.8.4`. The engine bundles **no** Linux clang; the system clang (23.1.4, Fedora 45) is the game-code toolchain. Game targets must use `BuildSettingsVersion.V7` to share the installed editor's build environment.
|
||||
Pinned install: **Unreal Engine 5.8.4** (CL 58902052, promoted build) at `/run/media/system/DATA/Engines/UE_5.8.4`. The engine bundles **no** Linux clang; the system clang (23.1.4, Fedora 45) is the game-code toolchain. Game targets must use `BuildSettingsVersion.V7` to share the installed editor's build environment.
|
||||
|
||||
## Fresh-checkout build
|
||||
|
||||
@@ -49,13 +48,7 @@ Engine/Build/BatchFiles/RunUAT.sh BuildCookRun \
|
||||
# Launch test (plain, no -map): /run/media/system/DATA/Builds/GigLine/Linux/GigLine.sh
|
||||
```
|
||||
|
||||
**Launch test must open the DemoMap.** A plain `./GigLine.sh` should load
|
||||
`/Game/Hollywood/DemoMap` (set via `DefaultEngine.ini` `GameMapsSettings`). If it
|
||||
instead opens `/Engine/Maps/Templates/OpenWorld`, the game shows an empty
|
||||
non-interactive "stuck" scene — check that `GameDefaultMap` is in
|
||||
`DefaultEngine.ini`, not `DefaultGame.ini`. Confirm the loaded map in the engine
|
||||
log: `.../Linux/GigLine/Saved/Logs/GigLine.log` (`LoadMap: /Game/Hollywood/DemoMap`).
|
||||
The archive directory is deliberately **outside** the repository; never archive into the checkout.
|
||||
**Launch test must open the DemoMap.** A plain `./GigLine.sh` should load `/Game/Hollywood/DemoMap` (set via `DefaultEngine.ini` `GameMapsSettings`). If it instead opens `/Engine/Maps/Templates/OpenWorld`, the game shows an empty non-interactive "stuck" scene — check that `GameDefaultMap` is in `DefaultEngine.ini`, not `DefaultGame.ini`. Confirm the loaded map in the engine log: `.../Linux/GigLine/Saved/Logs/GigLine.log` (`LoadMap: /Game/Hollywood/DemoMap`). The archive directory is deliberately **outside** the repository; never archive into the checkout.
|
||||
|
||||
## Headless content checks
|
||||
|
||||
@@ -76,9 +69,7 @@ Both content-acceptance tests run headless and are the template for all asset im
|
||||
|
||||
## Content pipeline (current)
|
||||
|
||||
The hero block and the demo level are built by a fixed sequence. Each step writes
|
||||
a result file under `/tmp/gigline/`; read it, because the commandlet's own stdout
|
||||
can be swallowed.
|
||||
The hero block and the demo level are built by a fixed sequence. Each step writes a result file under `/tmp/gigline/`; read it, because the commandlet's own stdout can be swallowed.
|
||||
|
||||
| Step | Tool | Output |
|
||||
| --- | --- | --- |
|
||||
@@ -95,12 +86,8 @@ can be swallowed.
|
||||
|
||||
Two rules that the pipeline enforces rather than documents:
|
||||
|
||||
- **One conversion.** Metres to Unreal centimetres happens only in
|
||||
`Geo/tools/osm_common.py::to_unreal_local`. Sidecars (`<asset>.geo.json`) record
|
||||
the result and `Geo/tools/asset_metadata.py audit` re-derives it.
|
||||
- **Collision is decided at import,** not later: terrain, road and sidewalks are
|
||||
complex-as-simple; kerbs and props stay simple. A simple hull over a kerbed
|
||||
street ramps straight across the kerb.
|
||||
- **One conversion.** Metres to Unreal centimetres happens only in `Geo/tools/osm_common.py::to_unreal_local`. Sidecars (`<asset>.geo.json`) record the result and `Geo/tools/asset_metadata.py audit` re-derives it.
|
||||
- **Collision is decided at import,** not later: terrain, road and sidewalks are complex-as-simple; kerbs and props stay simple. A simple hull over a kerbed street ramps straight across the kerb.
|
||||
|
||||
## Known engine quirks (2026-11-07)
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ Measured at 1440p on the development workstation: Bazzite, Ryzen 7 7700X, 64 GB
|
||||
## Check-record template
|
||||
|
||||
| Version | Check | Result | Evidence | Date |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| ------- | ----------------------- | ------ | -------- | ---- |
|
||||
| `0.1.0` | Traversal, both sides | — | — | — |
|
||||
| `0.1.0` | Placement vs references | — | — | — |
|
||||
| `0.1.0` | Collision and packaging | — | — | — |
|
||||
|
||||
+5
-10
@@ -25,21 +25,16 @@ Next: `0.1.0` gameplay (attribution display, lighting, crossing) and the El Capi
|
||||
|
||||
## 1. System
|
||||
|
||||
- `[x]` Update Bazzite with its supported mechanism.
|
||||
`ujust update` (or `rpm-ostree upgrade`) followed by a reboot. Deployment `45.20261105` is booted and default; `44.20261026` retained as rollback.
|
||||
- `[x]` Verify the NVIDIA driver and Vulkan from the desktop session.
|
||||
`nvidia-smi` names the RTX 5070 Ti on driver `615.78.08` and the Wayland desktop renders through it. Vulkan enumerates it as GPU0: discrete, proprietary driver `615.78.08`, API `1.4.351`, conformance `1.4.3.3`. The integrated RADV GPU is GPU1 — watch that the engine does not select it.
|
||||
- `[x]` Install `git-lfs`, `cmake`, `ninja-build`, `clang` as an ostree layer, reboot, then `git lfs install`.
|
||||
Done: `git-lfs 3.7.1`, `clang 23.1.4`, `cmake 4.3.0`, `ninja 1.13.2`; lfs filter active, `Tools/check-lfs.sh` passes.
|
||||
- `[x]` Update Bazzite with its supported mechanism. `ujust update` (or `rpm-ostree upgrade`) followed by a reboot. Deployment `45.20261105` is booted and default; `44.20261026` retained as rollback.
|
||||
- `[x]` Verify the NVIDIA driver and Vulkan from the desktop session. `nvidia-smi` names the RTX 5070 Ti on driver `615.78.08` and the Wayland desktop renders through it. Vulkan enumerates it as GPU0: discrete, proprietary driver `615.78.08`, API `1.4.351`, conformance `1.4.3.3`. The integrated RADV GPU is GPU1 — watch that the engine does not select it.
|
||||
- `[x]` Install `git-lfs`, `cmake`, `ninja-build`, `clang` as an ostree layer, reboot, then `git lfs install`. Done: `git-lfs 3.7.1`, `clang 23.1.4`, `cmake 4.3.0`, `ninja 1.13.2`; lfs filter active, `Tools/check-lfs.sh` passes.
|
||||
|
||||
## 2. Engine acquisition
|
||||
|
||||
- `[x]` **Human step.** Create an Epic account, accept the Unreal license.
|
||||
Done on 2026-11-06 with the account email recorded locally; no credentials stored in the repository.
|
||||
- `[x]` **Human step.** Create an Epic account, accept the Unreal license. Done on 2026-11-06 with the account email recorded locally; no credentials stored in the repository.
|
||||
- `[x]` **Human step.** Acquire one pinned engine build. Two routes:
|
||||
- **Launcher build**: install the Linux Epic Games Launcher, download the pinned engine version, install to the DATA volume, and disable auto-update so the pin holds.
|
||||
- **Source build**: clone the pinned `release` branch from the Epic Games GitHub organisation, then `./Setup.sh`, `./GenerateProjectFiles.sh`, `make -j16`. Budget 120–200 GB and a multi-hour first build on 16 threads.
|
||||
**5.8.4** downloaded to `/run/media/system/DATA/Downloads/Linux_Unreal_Engine_5.8.4.zip`: 39 819 212 076 bytes (37.08 GiB), ZIP central directory present with 299 959 entries, `Engine/Build/Build.version` reports **5.8.4**, changelist 58902052, `++UE5+Release-5.8`.
|
||||
- **Source build**: clone the pinned `release` branch from the Epic Games GitHub organisation, then `./Setup.sh`, `./GenerateProjectFiles.sh`, `make -j16`. Budget 120–200 GB and a multi-hour first build on 16 threads. **5.8.4** downloaded to `/run/media/system/DATA/Downloads/Linux_Unreal_Engine_5.8.4.zip`: 39 819 212 076 bytes (37.08 GiB), ZIP central directory present with 299 959 entries, `Engine/Build/Build.version` reports **5.8.4**, changelist 58902052, `++UE5+Release-5.8`.
|
||||
- `[x]` Verify the archive end to end before extracting. `unzip -tq` on 2026-11-06: "No errors detected", exit 0.
|
||||
- `[x]` Extract to the DATA volume and record the install path. Done 2026-11-07: `/run/media/system/DATA/Engines/UE_5.8.4`, 73 GiB on disk, extraction verified by full headless editor start.
|
||||
- `[x]` Resolve the engine version: **5.8.4 pinned** (see the decision below). The 5.2.0 archive (19.59 GiB, CL 25360045) remains on disk as a fallback only and should be deleted once the pin is trusted.
|
||||
|
||||
@@ -22,7 +22,7 @@ The window is the block plus a ~100 m margin on the east and ~70 m on the other
|
||||
The raster is reprojected by the service, not by us, so it was checked against the service's own point query (`getSamples`) and against the independent point service used in `../verification/2026-11-06-elevation.md`:
|
||||
|
||||
| Point | Raster pixel | Service `getSamples` | Earlier point probe |
|
||||
| --- | ---: | ---: | ---: |
|
||||
| --- | --: | --: | --: |
|
||||
| Hollywood × Highland (origin) | 115.911 | 115.910 | 115.911 |
|
||||
| Hollywood × Orange Dr | 119.422 | 119.418 | 119.418 |
|
||||
| Mid-block crossing | 117.593 | — | 117.53 |
|
||||
|
||||
@@ -38,7 +38,7 @@ Reproduce it the same way, or with `pyproj` once a geo environment exists. If a
|
||||
Optional check values, all NAD83 / UTM 11N, and the same points as local X/Y relative to the origin. Use them to confirm a transformation before trusting a blockout.
|
||||
|
||||
| Point | WGS84 lat, lon | Easting | Northing | Local X | Local Y |
|
||||
| --- | --- | ---: | ---: | ---: | ---: |
|
||||
| --- | --- | --: | --: | --: | --: |
|
||||
| Hollywood × Orange Dr | 34.101543, −118.341749 | 376 235.784 | 3 774 227.529 | −279.605 | +3.446 |
|
||||
| **Origin: Hollywood × Highland** | 34.101545, −118.338718 | **376 515.389** | **3 774 224.083** | 0.000 | 0.000 |
|
||||
| Hero NW corner | 34.101412, −118.340299 | 376 369.380 | 3 774 211.202 | −146.009 | −12.881 |
|
||||
@@ -54,7 +54,7 @@ Note the sign pattern: the whole block lies at **negative X** and the hero at **
|
||||
## Axis convention
|
||||
|
||||
| Axis | Meaning |
|
||||
| --- | --- |
|
||||
| ------- | ------------------------------------------------------------ |
|
||||
| Local X | easting − origin easting, metres, east positive |
|
||||
| Local Y | northing − origin northing, metres, north positive |
|
||||
| Local Z | up, metres, elevation relative to the origin's ground height |
|
||||
|
||||
@@ -16,7 +16,7 @@ Those gutter positions bracket a carriageway of roughly **20–22 m**, which ind
|
||||
## Section table
|
||||
|
||||
| Along block | Lowest point | Road crown | Cross-fall across the road | Gutter candidates |
|
||||
| ---: | ---: | ---: | ---: | --- |
|
||||
| --: | --: | --: | --: | --- |
|
||||
| 0.0 m | 118.78 @ −10 | ~119.41 @ 0 | ~0.6 m / 2 % | −10, +10 |
|
||||
| 40.0 m | 118.43 @ −11 | ~118.94 @ 0 | ~0.5 m / 2 % | −11, +10.5 |
|
||||
| 80.0 m | 117.84 @ −10 | ~118.33 @ 0 | ~0.5 m / 2 % | −10, +10.5–11.5 |
|
||||
|
||||
@@ -15,7 +15,7 @@ Note: the point service answers in 6–8 s per request, so the probe runs reques
|
||||
Five positions along the 279.4 m block, at the south sidewalk (12.6 m from the centreline), the road centreline, and the north sidewalk (13.6 m).
|
||||
|
||||
| Along block | South sidewalk | Centreline | North sidewalk |
|
||||
| ---: | ---: | ---: | ---: |
|
||||
| ---------------------: | -------------: | ---------: | -------------: |
|
||||
| 0.0 m (Orange Dr) | 118.90 | 119.36 | 119.59 |
|
||||
| 69.8 m | 118.11 | 118.46 | 118.49 |
|
||||
| 139.7 m | 116.95 | 117.41 | 117.50 |
|
||||
|
||||
@@ -30,7 +30,7 @@ Crossing endpoints sit within about 1 m of the kerb line, so these lengths appro
|
||||
Mapped sidewalk centrelines sit **12.6 m** (south) and **13.6 m** (north) from the road centreline. Building setbacks, measured to each building's nearest vertex:
|
||||
|
||||
| Side | Building | Setback | Frontage extent |
|
||||
| --- | --- | ---: | ---: |
|
||||
| --- | --- | --: | --: |
|
||||
| S | 6922 | 14.6 m | 66.1 m |
|
||||
| S | 6902 | 14.5 m | 31.0 m |
|
||||
| S | **6840 El Capitan Entertainment Centre** | **14.5 m** | **25.7 m** |
|
||||
|
||||
@@ -8,14 +8,14 @@ Scope: facts and traps that cost time to establish. Planned work lives in [TODO.
|
||||
|
||||
## 2026-11-08 — Reset was returning to mid-air; QA self-test switch
|
||||
|
||||
- **`ResetToStart()` restored a `StartLocation` captured in `BeginPlay`**, which is the PlayerStart position *above* grade (Z 600) so the capsule never spawns embedded. Every reset therefore dropped the player 1.4 m back into the air. Fix: capture `StartLocation` on the first grounded frame (repeating 0.25 s timer, cleared once captured) — not a one-shot timer, which can fire after the player has already started walking and record a mid-stride position.
|
||||
- **`ResetToStart()` restored a `StartLocation` captured in `BeginPlay`**, which is the PlayerStart position _above_ grade (Z 600) so the capsule never spawns embedded. Every reset therefore dropped the player 1.4 m back into the air. Fix: capture `StartLocation` on the first grounded frame (repeating 0.25 s timer, cleared once captured) — not a one-shot timer, which can fire after the player has already started walking and record a mid-stride position.
|
||||
- **`-qaselftest`** drives the checks headlessly and logs `GigLine QA: ... PASS/FAIL`. It runs on a **core ticker, not a world timer**: pausing the game stops world timers, so a timer-driven test freezes exactly when it proves pause works.
|
||||
- Current results: walk 746 cm / 2 s with Z steady, reset 0 cm from spawn, pause `IsGamePaused()` 1, unpause 0, transect 84 samples / 0 holes (ground Z 317..395).
|
||||
|
||||
## 2026-11-08 — The fall-through was an 8 m invisible box (QA branch)
|
||||
|
||||
- **Symptom:** player "spawned above ground but never fell", sat at Z 909, `fall=0`, `mode=1` (Walking), no fall-through, view looked plausible so it was mistaken for working.
|
||||
- **Cause:** `Terrain_DEM` had only a **bounding-box simple collision proxy** (Interchange default). A line trace down at *every* Y through the block hit `Demo_Terrain_DEM` at exactly **819** — the mesh bbox max Z. The whole street was under an invisible lid; the pawn stood on the box, 8 m above the road.
|
||||
- **Cause:** `Terrain_DEM` had only a **bounding-box simple collision proxy** (Interchange default). A line trace down at _every_ Y through the block hit `Demo_Terrain_DEM` at exactly **819** — the mesh bbox max Z. The whole street was under an invisible lid; the pawn stood on the box, 8 m above the road.
|
||||
- **Proof:** a debug `LineTraceSingleByChannel` profile at Y −1912…+1447 reported `top=819 actor=Demo_Terrain_DEM` for the entire street. After the fix it reports `Sidewalk_North 395`, `Road_Hollywood 366`, `Sidewalk_South 317`.
|
||||
- **Fix:** force complex-as-simple collision on the terrain. Python **cannot** set it (`StaticMesh`/`BodySetup` expose no such property; `dir()` shows only `lod_for_collision`). Added `UGigLineAssetTools::SetComplexCollisionAsSimple` in the C++ module (`BodySetup->CollisionTraceFlag = CTF_UseComplexAsSimple`, UE 5.8 no longer has `bUseComplexAsSimpleCollision`).
|
||||
- **Second gotcha:** the flag lives on the **asset**, not the map. Setting it in a builder session and saving only the `.umap` loses it — `EditorAssetLibrary.save_loaded_asset()` is required, otherwise the next run reloads the bbox proxy.
|
||||
@@ -34,10 +34,7 @@ Scope: facts and traps that cost time to establish. Planned work lives in [TODO.
|
||||
## 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.`
|
||||
- **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.
|
||||
|
||||
@@ -57,8 +54,7 @@ Scope: facts and traps that cost time to establish. Planned work lives in [TODO.
|
||||
|
||||
## 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"`.
|
||||
- **`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 `Art/blender/blockout/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.
|
||||
@@ -99,7 +95,7 @@ Scope: facts and traps that cost time to establish. Planned work lives in [TODO.
|
||||
|
||||
## 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.
|
||||
- **`-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`.
|
||||
|
||||
@@ -156,7 +152,6 @@ Scope: facts and traps that cost time to establish. Planned work lives in [TODO.
|
||||
- **Docs drift silently after a refactor.** Moving the geo scripts to `Geo/tools/` and the Blender builders into `Art/blender/*/` left stale paths in six documents and two tool READMEs. Grep for old paths (`.md` and `.py`) after any move, not just the ones that error at runtime.
|
||||
- **Every new tool needs a row in `Tools/README.md` and `Docs/build.md`**, or the next session will not know it exists. Both now list the full content pipeline in order.
|
||||
|
||||
|
||||
## 2026-11-07 — Character diffuse bake
|
||||
|
||||
- **`img.save()` writes black for an image created in memory** even though Cycles `bpy.ops.object.bake` does update `img.pixels` correctly (verified in-memory px were warm). Writing the PNG ourselves from `img.pixels` is required.
|
||||
@@ -168,16 +163,16 @@ Scope: facts and traps that cost time to establish. Planned work lives in [TODO.
|
||||
|
||||
- `Tools/judge_screenshot.py` — runs an OpenRouter vision model over a screenshot vs an expected-scene description. Reads `OPENROUTER_API_KEY` from the repo `.env` (ignored). Base64 data-URI image under `image_url.url`; OpenAI-compatible body → `POST /api/v1/chat/completions`. `openai/gpt-4o-mini` returns a `{verdict, confidence, reason, missing}` JSON. It flags genuinely missing content (e.g. `main`'s pre-warm-skin character shot judged "no"); it is a pre-check, not the human verdict.
|
||||
- Test one: `Tools/judge_screenshot.py --image Screenshots/review-01-character.png --expect "<scene>" --verbose`. Bulk: `--shots` (parses the README rows).
|
||||
|
||||
## 2026-11-07 — Blender skill packs: discovery depth
|
||||
|
||||
- **The 94 packs were never registered with the `skill` tool**, only readable as files. The loader resolves `<skills-root>/<pack>/SKILL.md` one level down; `.agents/skills/blender-skills/` is a *container* of 94 packs, so it was skipped silently (no warning, no error). Symptom: `skill("archviz")` unresolvable even though `archviz/SKILL.md` exists.
|
||||
- **The 94 packs were never registered with the `skill` tool**, only readable as files. The loader resolves `<skills-root>/<pack>/SKILL.md` one level down; `.agents/skills/blender-skills/` is a _container_ of 94 packs, so it was skipped silently (no warning, no error). Symptom: `skill("archviz")` unresolvable even though `archviz/SKILL.md` exists.
|
||||
- **Fix applied:** 94 symlinks in `~/.agents/skills/<pack>` → `<repo>/.agents/skills/blender-skills/<pack>/`. The catalog then lists all of them (verified by calling `skill` on `collision-proxy`: base dir resolves through the link). `references/` stays unlinked — it is a shared folder with no `SKILL.md`, not a pack.
|
||||
- **The AGENTS.md "MCP-driven" caveat is overstated.** 41 of 94 SKILL.md mention MCP, mostly only in the `description` line; the bodies are method guides (naming, proportions, validation checklists) that work headless. Do not skip a pack because it advertises MCP.
|
||||
- **Skill names in AGENTS.md/TODO.md all resolve** except `references`, which is the folder above, not a pack.
|
||||
- Symlinks are user-level: a fresh machine needs the same 94 links before the packs are loadable by name.
|
||||
- **A shared checkout can commit your uncommitted edit for you, or lose it.** This entry was written but not yet committed when another session ran a `git commit` that included `MEMORY.md`; it landed inside their commit (`54b6239`) with a message that does not mention it. Had they overwritten the file instead, the work would have been gone with no reflog to recover from. On a shared worktree, either commit a shared file immediately or check `git log -S` for it before assuming the edit is missing.
|
||||
|
||||
|
||||
## 2026-11-07 — Street visibility and the LFS lockable trap
|
||||
|
||||
- **Every street surface (road, sidewalks, kerbs, markings) had 100 % downward face normals** — `strip()`'s natural winding (rows along +s, cols along +normal) faces the ground. Invisible in engine for as long as the terrain covered them; the corridor cut exposed the black trench. Fixed by reversing the winding in `strip()`, `kerb_faces()` and `crossing_band()`.
|
||||
@@ -188,17 +183,17 @@ Scope: facts and traps that cost time to establish. Planned work lives in [TODO.
|
||||
## 2026-11-07 — ReviewMap corruption: deprecated level calls + save-order bug
|
||||
|
||||
- **`EditorLevelLibrary.load_level`/`new_level` are deprecated no-ops in `-nullrhi` commandlets** (they return without switching worlds, so staged actors land in whatever world is current and get saved over the wrong map). Use the `LevelEditorSubsystem`: `unreal.get_editor_subsystem(unreal.LevelEditorSubsystem).load_level(path)` actually switches. Symptom was ReviewMap containing Demo actors + `ShotSequencer`.
|
||||
- **Map-save ordering bug in `Tools/ue_build_review_map.py`**: the script saved ReviewMap *after* the DemoMap section, but the switch back to ReviewMap fails silently because the map only exists in memory at that point — so the final `save_map` wrote the demo world over ReviewMap. Fix: save ReviewMap first, then stage the demo cameras, and never switch back. Both maps verified by probe (ReviewMap lists Review actors; DemoMap lists Demo actors).
|
||||
- **Map-save ordering bug in `Tools/ue_build_review_map.py`**: the script saved ReviewMap _after_ the DemoMap section, but the switch back to ReviewMap fails silently because the map only exists in memory at that point — so the final `save_map` wrote the demo world over ReviewMap. Fix: save ReviewMap first, then stage the demo cameras, and never switch back. Both maps verified by probe (ReviewMap lists Review actors; DemoMap lists Demo actors).
|
||||
- Rebuilt ReviewMap after the fixes: character, both cubes (A grounded, B floating at 2 m), pawn, NPC prefab, hero facade all present; user re-approved the shots. README cube naming corrected (README had A/B swapped vs the script).
|
||||
|
||||
## 2026-11-07 — Materials and lighting in the demo map
|
||||
|
||||
- **Blender flat diffuse colours do not survive FBX -> Unreal.** Every site mesh (road, sidewalks, kerbs, crossing paint) imported with a material asset that had a default *white* base colour, and the terrain imported with `WorldGridMaterial` (UE's bright grey grid). That — not the sun — is what made the demo look blown out and washed white. Fix: create the colours in UE (`M_Asphalt`, `M_Concrete`, `M_Ground`, `M_RoadPaint` via `Constant3Vector`) and assign them per actor in `Tools/ue_build_demo_map.py`.
|
||||
- **Blender flat diffuse colours do not survive FBX -> Unreal.** Every site mesh (road, sidewalks, kerbs, crossing paint) imported with a material asset that had a default _white_ base colour, and the terrain imported with `WorldGridMaterial` (UE's bright grey grid). That — not the sun — is what made the demo look blown out and washed white. Fix: create the colours in UE (`M_Asphalt`, `M_Concrete`, `M_Ground`, `M_RoadPaint` via `Constant3Vector`) and assign them per actor in `Tools/ue_build_demo_map.py`.
|
||||
- **Auto-exposure makes review shots non-comparable**: the same road rendered washed-out in one framing and near-black in another because each camera saw a different amount of sky. Fix: an unbound `PostProcessVolume` with `AEM_HISTOGRAM` and `auto_exposure_min_brightness == auto_exposure_max_brightness` (fixed exposure). Do not use `AEM_MANUAL` + `auto_exposure_bias` — a bias of 11 blew the whole frame out.
|
||||
- **`DirectionalLightComponent.light_color` takes a `Color` struct, not `LinearColor`** (`unreal.Color(r=255,g=245,b=230,a=255)`); passing `LinearColor` raises a nativize error.
|
||||
- **One band per object loses geometry downstream.** `crossing_band()` created `Crossing_Markings` each call, so Blender renamed the second and third to `.001`/`.002`; `site_assembly.py` appends by exact name, so only one crossing ever reached the game. Build all bands into a single mesh instead of one object per band.
|
||||
- **Street arc length -> UE X:** s=0 is the west end of the block (UE X −27966 cm) and s increases eastward, so the designated mid-block crossing at s=130.1 m is UE X ≈ −14956, not the −24291 used by an earlier camera (that is the s=36.6 crossing).
|
||||
- **Camera placement in the demo map needs the mesh bounds, not intuition.** The hero façade body spans UE Y −1457..−200, so a "street level" camera at Y −400 is *inside* the building and renders its unlit back face. Read `get_bounding_box()` on the staged meshes before choosing a camera.
|
||||
- **Camera placement in the demo map needs the mesh bounds, not intuition.** The hero façade body spans UE Y −1457..−200, so a "street level" camera at Y −400 is _inside_ the building and renders its unlit back face. Read `get_bounding_box()` on the staged meshes before choosing a camera.
|
||||
- **"LIGHTING NEEDS TO BE REBUILT" (Build Lighting Only / `BuildLighting`) appears whenever a map has Stationary/Static lights and no baked lightmap.** For a fully dynamic scene the clean fix is `r.AllowStaticLighting=False` in `Config/DefaultEngine.ini` plus `set_mobility(ComponentMobility.MOVABLE)` on the directional light, sky light and height fog (and MOVABLE on the staged mesh components). Nothing to build, warning gone. Note the cvar is read at startup, so each new commandlet/game run picks it up.
|
||||
- The Android File Server `SecurityToken` kept reappearing in `Config/DefaultEngine.ini`; the plugin is disabled and excluded from shipping, so the value is cleared and must stay empty — it is a credential and must not be committed.
|
||||
|
||||
@@ -215,24 +210,10 @@ Scope: facts and traps that cost time to establish. Planned work lives in [TODO.
|
||||
- The two north-side buildings (TCL, Tussaud's) were similarly on the **south** side: `export_north_buildings.py` mirrored Y, which put them where the frontage belongs.
|
||||
- Fix: hero at X −13336 / Y +1307 (the frontage gap between 6902 and 6838); frontage and north buildings exported **without** a Y mirror (the FBX preset already maps Blender −Y south to UE +Y south).
|
||||
- Lesson: **place a building only against a neighbour or the street mesh, never in isolation.** A single object in an empty map hides any number of placement errors; adding the adjacent frontage immediately exposed this one.
|
||||
|
||||
## 2026-11-07 — walkable demo QA bugs (fix branch qa-input-collision-fix-0.1.0)
|
||||
|
||||
- **"Stuck" window = wrong default map.** A plain `./GigLine.sh` opened
|
||||
`/Engine/Maps/Templates/OpenWorld` (empty engine template) instead of the demo,
|
||||
so nothing was interactive. `GameDefaultMap` was in `DefaultGame.ini` and not
|
||||
applied; it must live in `DefaultEngine.ini[/Script/EngineSettings.GameMapsSettings]`
|
||||
with `GlobalDefaultGameMode`. Verified: plain launch now loads
|
||||
`/Game/Hollywood/DemoMap`. Evidence: `LogLoad: LoadMap: /Engine/Maps/Templates/OpenWorld`.
|
||||
- **Input assets were pruned from the pak.** The Enhanced Input assets under
|
||||
`/Game/Input` were only soft-referenced at runtime, so the cooker excluded them
|
||||
(cook `ReferencedSet.txt` had zero `/Game/Input` lines -> all inputs nil at
|
||||
runtime). Fix: hard-reference via `ConstructorHelpers::FObjectFinder` in the
|
||||
character ctor (cooker follows hard refs) + `+DirectoriesToAlwaysCook`. Packaged
|
||||
log then showed `ctx=ok move=ok ... jump=ok`.
|
||||
- **Character fell through** the site: site meshes staged MOVABLE + PlayerStart far
|
||||
past the north sidewalk. Fix: STATIC mobility + explicit collision
|
||||
(QUERY_AND_PHYSICS/WorldStatic/BlockAll) and PlayerStart at Y -1200 on the
|
||||
sidewalk. Packaged run: `grounded=1 movement=Walking`.
|
||||
- Diagnose packaged runtime via the engine log
|
||||
(`.../Linux/GigLine/Saved/Logs/GigLine.log`); a headless `-nullrhi` commandlet
|
||||
cannot validate physics traces (even a spawned cube returns NO HIT there).
|
||||
- **"Stuck" window = wrong default map.** A plain `./GigLine.sh` opened `/Engine/Maps/Templates/OpenWorld` (empty engine template) instead of the demo, so nothing was interactive. `GameDefaultMap` was in `DefaultGame.ini` and not applied; it must live in `DefaultEngine.ini[/Script/EngineSettings.GameMapsSettings]` with `GlobalDefaultGameMode`. Verified: plain launch now loads `/Game/Hollywood/DemoMap`. Evidence: `LogLoad: LoadMap: /Engine/Maps/Templates/OpenWorld`.
|
||||
- **Input assets were pruned from the pak.** The Enhanced Input assets under `/Game/Input` were only soft-referenced at runtime, so the cooker excluded them (cook `ReferencedSet.txt` had zero `/Game/Input` lines -> all inputs nil at runtime). Fix: hard-reference via `ConstructorHelpers::FObjectFinder` in the character ctor (cooker follows hard refs) + `+DirectoriesToAlwaysCook`. Packaged log then showed `ctx=ok move=ok ... jump=ok`.
|
||||
- **Character fell through** the site: site meshes staged MOVABLE + PlayerStart far past the north sidewalk. Fix: STATIC mobility + explicit collision (QUERY_AND_PHYSICS/WorldStatic/BlockAll) and PlayerStart at Y -1200 on the sidewalk. Packaged run: `grounded=1 movement=Walking`.
|
||||
- Diagnose packaged runtime via the engine log (`.../Linux/GigLine/Saved/Logs/GigLine.log`); a headless `-nullrhi` commandlet cannot validate physics traces (even a spawned cube returns NO HIT there).
|
||||
@@ -55,9 +55,7 @@ Progress lives in `ROADMAP.md`; session findings live in `MEMORY.md`; rendered r
|
||||
- `Tools/` — repeatable import/export helpers.
|
||||
- `Docs/` — setup, licenses, architecture, release checks.
|
||||
|
||||
Track `.uasset`, `.umap`, `.blend`, and large source binaries with LFS.
|
||||
Ignore generated `Binaries/`, `Intermediate/`, `Saved/`, and Derived Data Cache.
|
||||
Do not commit Unreal Engine source, credentials, or non-redistributable assets.
|
||||
Track `.uasset`, `.umap`, `.blend`, and large source binaries with LFS. Ignore generated `Binaries/`, `Intermediate/`, `Saved/`, and Derived Data Cache. Do not commit Unreal Engine source, credentials, or non-redistributable assets.
|
||||
|
||||
## Geographic and Art Pipeline
|
||||
|
||||
@@ -101,7 +99,7 @@ Driving, interiors, crowds, traffic simulation, multiplayer, and a full-city map
|
||||
Solo-development estimate: **approximately 30–40 weeks**, subject to asset quality and available hours.
|
||||
|
||||
| Release | Weeks | Larger task | Small patch tasks after release |
|
||||
| --- | ---: | --- | --- |
|
||||
| --- | --: | --- | --- |
|
||||
| `0.1.0` | 1–6 | Local setup and initial walkable Hollywood block | `0.1.1` collision fixes; `0.1.2` scale/façade corrections; `0.1.3` packaging and setup fixes |
|
||||
| `0.2.0` | 7–9 | MPFB player body, third-person camera, basic animation | `0.2.1` rig fixes; `0.2.2` skin/hair tuning; `0.2.3` camera clipping fixes |
|
||||
| `0.3.0` | 10–13 | One Chaos vehicle, enter/exit interaction, closed driving route | `0.3.1` handling tuning; `0.3.2` vehicle collision fixes; `0.3.3` input fixes |
|
||||
|
||||
+14
-43
@@ -1,9 +1,6 @@
|
||||
# Screenshots — visual review
|
||||
|
||||
Rendered in-game captures of the current project content, generated by
|
||||
[`Tools/render_screenshots.sh`](../Tools/render_screenshots.sh). The PNGs are
|
||||
committed alongside this README so a reviewer sees exactly what the build
|
||||
rendered.
|
||||
Rendered in-game captures of the current project content, generated by [`Tools/render_screenshots.sh`](../Tools/render_screenshots.sh). The PNGs are committed alongside this README so a reviewer sees exactly what the build rendered.
|
||||
|
||||
## How to regenerate
|
||||
|
||||
@@ -11,20 +8,13 @@ rendered.
|
||||
Tools/render_screenshots.sh
|
||||
```
|
||||
|
||||
Rebuilds `Game/GigLine/Content/Test/ReviewMap.umap` from current content, runs
|
||||
the game on it (and on the DemoMap for the walkable views), walks the fixed
|
||||
camera list via `AGigLineShotActor`, captures each shot, copies the PNGs here
|
||||
and exits — about a minute. The camera list lives in
|
||||
`Tools/ue_build_review_map.py`; add new shots there, remove retired ones here.
|
||||
Rebuilds `Game/GigLine/Content/Test/ReviewMap.umap` from current content, runs the game on it (and on the DemoMap for the walkable views), walks the fixed camera list via `AGigLineShotActor`, captures each shot, copies the PNGs here and exits — about a minute. The camera list lives in `Tools/ue_build_review_map.py`; add new shots there, remove retired ones here.
|
||||
|
||||
> Naming: shots use their stable camera name (no index prefix), so adding or
|
||||
> reordering cameras never renumbers files or orphans the old ones. Click an
|
||||
> image for the full-size PNG.
|
||||
> Naming: shots use their stable camera name (no index prefix), so adding or reordering cameras never renumbers files or orphans the old ones. Click an image for the full-size PNG.
|
||||
|
||||
## Shot list
|
||||
|
||||
All shots ☑ approved 2026-11-07, including the block frontage pass that added
|
||||
the neighbouring buildings and corrected the hero and north-building placement.
|
||||
All shots ☑ approved 2026-11-07, including the block frontage pass that added the neighbouring buildings and corrected the hero and north-building placement.
|
||||
|
||||
| # | File | Preview | Map | View | What it shows |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
@@ -45,41 +35,22 @@ the neighbouring buildings and corrected the hero and north-building placement.
|
||||
|
||||
## Scene conventions
|
||||
|
||||
- **Review map** (`/Game/Test/ReviewMap`): 160 m floor, top face at Z 0; the
|
||||
character measures Z 0..83 cm. One warm key light plus sky fill.
|
||||
- **Cubes**: `Cube_ScaleTest_A` rests on the floor, `Cube_ScaleTest_B` floats at
|
||||
Z 2 m; both are exactly 1 m — the scale reference.
|
||||
- **Demo map** (`/Game/Hollywood/DemoMap`): fixed daytime — sun at pitch −50 /
|
||||
yaw 120 (intensity 4, warm), sky light 2.6, sky atmosphere, height fog, fixed
|
||||
exposure.
|
||||
- **Materials**: every exported surface carries a look-developed material built
|
||||
in `Tools/ue_build_demo_map.py` (`ensure_material`) because Blender's flat
|
||||
diffuse colours do not survive the FBX → Unreal import. Each has an explicit
|
||||
roughness and a subtle world-space noise blend between two shades:
|
||||
`M_Asphalt` (0.92), `M_Concrete` (0.88), `M_KerbConcrete` (0.85),
|
||||
`M_Ground` (0.98), `M_RoadPaint` (0.62), `M_FacadeStone` (0.72) and
|
||||
`M_Stucco` (0.86) for the north-side buildings.
|
||||
- **Lighting is dynamic-only** (`r.AllowStaticLighting=False`, all lights
|
||||
Movable), so no lighting build is ever required.
|
||||
- **Attribution overlay**: every shot carries the required ODbL credit in the
|
||||
bottom-left (`© OpenStreetMap contributors` / `Data © OpenStreetMap
|
||||
contributors, ODbL 1.0 — openstreetmap.org/copyright`), drawn by
|
||||
`AGigLineHUD`. Screenshots are requested with the UI shown so the obligation
|
||||
is visible in review.
|
||||
- **Review map** (`/Game/Test/ReviewMap`): 160 m floor, top face at Z 0; the character measures Z 0..83 cm. One warm key light plus sky fill.
|
||||
- **Cubes**: `Cube_ScaleTest_A` rests on the floor, `Cube_ScaleTest_B` floats at Z 2 m; both are exactly 1 m — the scale reference.
|
||||
- **Demo map** (`/Game/Hollywood/DemoMap`): fixed daytime — sun at pitch −50 / yaw 120 (intensity 4, warm), sky light 2.6, sky atmosphere, height fog, fixed exposure.
|
||||
- **Materials**: every exported surface carries a look-developed material built in `Tools/ue_build_demo_map.py` (`ensure_material`) because Blender's flat diffuse colours do not survive the FBX → Unreal import. Each has an explicit roughness and a subtle world-space noise blend between two shades: `M_Asphalt` (0.92), `M_Concrete` (0.88), `M_KerbConcrete` (0.85), `M_Ground` (0.98), `M_RoadPaint` (0.62), `M_FacadeStone` (0.72) and `M_Stucco` (0.86) for the north-side buildings.
|
||||
- **Lighting is dynamic-only** (`r.AllowStaticLighting=False`, all lights Movable), so no lighting build is ever required.
|
||||
- **Attribution overlay**: every shot carries the required ODbL credit in the bottom-left (`© OpenStreetMap contributors` / `Data © OpenStreetMap contributors, ODbL 1.0 — openstreetmap.org/copyright`), drawn by `AGigLineHUD`. Screenshots are requested with the UI shown so the obligation is visible in review.
|
||||
|
||||
## What to look for
|
||||
|
||||
- **Ground contact**: feet meet the plane with no gap and no shadow seam.
|
||||
- **Scale**: everything checks against the 1 m cubes.
|
||||
- **Façade rhythm**: six columns at 4.96 m across 25.75 m should read as the
|
||||
photographs in silhouette.
|
||||
- **Façade rhythm**: six columns at 4.96 m across 25.75 m should read as the photographs in silhouette.
|
||||
|
||||
## Known cosmetic issues
|
||||
|
||||
- Floor speckle from the `Constant3Vector` wiring in `Tools/ue_build_review_map.py`.
|
||||
- Hero façade renders pale — Blender flat colours with no normal/roughness, so
|
||||
it reads as untextured stone (the `0.1.4` façade patch, not a lighting bug).
|
||||
- Banners and window panels float detached from the colonnade wall (next
|
||||
modelling pass).
|
||||
- Between kerb and building line, the walkable surface is the terrain mesh, not
|
||||
a modelled pavement.
|
||||
- Hero façade renders pale — Blender flat colours with no normal/roughness, so it reads as untextured stone (the `0.1.4` façade patch, not a lighting bug).
|
||||
- Banners and window panels float detached from the colonnade wall (next modelling pass).
|
||||
- Between kerb and building line, the walkable surface is the terrain mesh, not a modelled pavement.
|
||||
@@ -53,6 +53,4 @@ Rules that still apply, because they are about shipped output rather than local
|
||||
| OSM blockout | OSM extract and Blosm-generated geometry | ODbL 1.0 for source data | Source attribution above; review ODbL obligations for distributed derived databases. |
|
||||
| Terrain and street prototype | USGS 3DEP DEM, OSM data, project scripts | Public domain USGS data; ODbL 1.0 for OSM data | Source manifests in `Geo/manifests/`; review ODbL obligations for distributed derived databases. |
|
||||
|
||||
| Hero façade blockout | Project-owned geometry from `Tools/hero_facade_build.py`, dimensions from OSM and the reference photography | Project-owned; ODbL 1.0 applies to the OSM measurements it derives from | Committed with a per-part evidence report (`Art/blender/hero/hero-facade-*.json`) and a position sidecar (`hero-facade.geo.json`). |
|
||||
| Street props (candidate reuse) | Sibling project `…/06-games/security-game`, `assets/models/blender_src/*.blend` | Project-owned by the same author | **Not yet imported.** Sources copied to `Art/props/blender_src/` with `Art/props/reuse-manifest.json`; a licence statement is required before any of them ship. |
|
||||
|
||||
| Hero façade blockout | Project-owned geometry from `Tools/hero_facade_build.py`, dimensions from OSM and the reference photography | Project-owned; ODbL 1.0 applies to the OSM measurements it derives from | Committed with a per-part evidence report (`Art/blender/hero/hero-facade-*.json`) and a position sidecar (`hero-facade.geo.json`). | | Street props (candidate reuse) | Sibling project `…/06-games/security-game`, `assets/models/blender_src/*.blend` | Project-owned by the same author | **Not yet imported.** Sources copied to `Art/props/blender_src/` with `Art/props/reuse-manifest.json`; a licence statement is required before any of them ship. |
|
||||
Reference in new issue
Block a user