docs: reconvert architecture.adoc to markdown via asciidoctor→docbook→pandoc

Replaced the Python-converted architecture.md with a proper pandoc
conversion chain:

  asciidoctor -b docbook5  →  pandoc -f docbook -t gfm

This fixes table rendering (pipe tables instead of grid tables),
interpolates AsciiDoc attributes ({project-name} → Gig Line), strips
anchor IDs, and normalises escaping. Post-processed: glossary italic
leak from cols="e,2e" table, ® → (R) for the reset key, \>/> escapes.

Also:
- prettier 3.9.10 installed globally as the Markdown formatter/linter
- .prettierrc: proseWrap=never, tabWidth=2
- .prettierignore: skips Binaries/, *.uasset, *.umap, *.blend, images
- architecture.md passes prettier --check
This commit is contained in:
zwitschi committed 2026-11-08 13:26:17 +01:00
1 parent d03829b699
commit e93c27054a
3 files changed
+187 -104

No files matched your search

+12
View File
@@ -0,0 +1,12 @@
# Prettier ignores — don't format generated or binary content
Binaries/
Intermediate/
Saved/
*.uasset
*.umap
*.blend
*.png
*.jpg
*.jpeg
*.gif
*.webp
+5
View File
@@ -0,0 +1,5 @@
{
"proseWrap": "never",
"tabWidth": 2,
"useTabs": false
}
+170 -104
View File
@@ -91,7 +91,7 @@ The system is a self-contained single-player game. It has no server backend, no
| Channel | Protocol / Format | Purpose | | Channel | Protocol / Format | Purpose |
| --- | --- | --- | | --- | --- | --- |
| Keyboard + mouse | Enhanced Input (IA_*, IMC_Default) | First-person movement, look, jump, reset, pause | | Keyboard + mouse | Enhanced Input (IA\_\*, IMC_Default) | First-person movement, look, jump, reset, pause |
| Vulkan RHI | GPU rendering | Scene display at 60 FPS / 1440p | | Vulkan RHI | GPU rendering | Scene display at 60 FPS / 1440p |
| FBX | Autodesk FBX (binary) | Blender→Unreal mesh and skeleton transfer | | FBX | Autodesk FBX (binary) | Blender→Unreal mesh and skeleton transfer |
| GeoTIFF | 3DEP 1 m DEM | Terrain heightfield source | | GeoTIFF | 3DEP 1 m DEM | Terrain heightfield source |
@@ -102,30 +102,41 @@ The system is a self-contained single-player game. It has no server backend, no
## Technology decisions ## 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. - **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. - **Blender 5.2 LTS** for all 3D modelling, UV work, and collision mesh authoring. Driven headlessly via `bpy` Python scripts, not MCP.
** ****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+`). - **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 ## 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/`: 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 - `Site/` — terrain, road, sidewalks, kerbs, crossing markings, site materials
* `ElCapitan/` — hero façade mesh and materials
* `Frontage/` — south-side block building meshes - `ElCapitan/` — hero façade mesh and materials
* `North/` — north-side building meshes
* `Input/` — Enhanced Input actions and mapping context - `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. 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 ## 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). - **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. - **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.
** **Reproducibility*: pinned toolchain in `Docs/toolchain.md`, named export presets, `Tools/check-lfs.sh` gate, fresh-checkout build procedure in `Docs/build.md`.
- **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`.
# Building Block View # Building Block View
@@ -154,7 +165,7 @@ C++ classes in `Game/GigLine/Source/GigLine/`:
| `AGigLineShotActor` | Screenshot camera walker | Drives cameras in `-game` mode, `FScreenshotRequest`, quits | | `AGigLineShotActor` | Screenshot camera walker | Drives cameras in `-game` mode, `FScreenshotRequest`, quits |
| `UGigLineAssetTools` | C++ collision helpers | `SetComplexCollisionAsSimple` on `StaticMesh` assets | | `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`. 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 ### Site
@@ -194,62 +205,89 @@ Source data: `Art/blender/` (`.blend` files), `Geo/` (OSM extracts, DEM, verific
### QA & Review ### QA & Review
* `AGigLineShotActor` walks fixed cameras in `-game` mode, captures PNGs, and quits. - `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. - `-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 ## Level 2
### White Box Gameplay — Input Flow ### White Box Gameplay — Input Flow
* `AGigLineCharacter::SetupPlayerInputComponent` binds `IA_*` actions to `MoveForward`, `MoveBack`, `MoveStrafe`, `MoveLeft`, `Look`, `StartJump`/`StopJump`, `ResetToStart`, `TogglePause`. 1. `AGigLineCharacter::SetupPlayerInputComponent` binds `IA_*` actions to `MoveForward`, `MoveBack`, `MoveStrafe`, `MoveLeft`, `Look`, `StartJump`/`StopJump`, `ResetToStart`, `TogglePause`.
* Movement delegates to `ApplyMove(Forward, Strafe)` → `AddMovementInput`.
* Look applies yaw/pitch scaled by `LookSensitivity` (Y invertable via `bInvertLookY`). 2. Movement delegates to `ApplyMove(Forward, Strafe)` → `AddMovementInput`.
* `ResetToStart` teleports to `StartLocation` (captured on first grounded frame), clears velocity, resets control rotation.
* `TogglePause` toggles `APlayerController::SetPause`, swaps input mode between `FInputModeGameOnly` and `FInputModeUIOnly`, shows/hides mouse cursor. 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 ### White Box Site — Collision Model
* Every site mesh (road, sidewalks, kerbs, crossing) is `STATIC` with `BlockAll` collision. - 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. - `Terrain_DEM` uses `CTF_UseComplexAsSimple` (forced by `UGigLineAssetTools` at build time, saved on the asset).
* Ground Z: north sidewalk 395, road 366, south sidewalk 317 (3.94 m fall along the block, matching the DEM).
- 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).
# Runtime View # Runtime View
## Walk the block ## Walk the block
* Player launches game → `AGigLineGameModeBase` spawns `AGigLineCharacter` at `PlayerStart` `(-13336, -1150, 600)`. 1. Player launches game → `AGigLineGameModeBase` spawns `AGigLineCharacter` at `PlayerStart` `(-13336, -1150, 600)`.
* Character falls 144 cm to road surface (Z 456) and begins walking. `StartLocation` captured on first grounded frame.
* Player holds W → `IA_Move` fires → `ApplyMove(1, 0)` → `AddMovementInput(ForwardVector, 1)` → capsule moves at 450 cm/s. 2. Character falls 144 cm to road surface (Z 456) and begins walking. `StartLocation` captured on first grounded frame.
* Mouse move → `IA_Look` fires → yaw/pitch applied to controller rotation → camera follows (attached to capsule at 160 cm eye height).
* Player presses R → `ResetToStart` → teleport to `StartLocation`/`StartRotation`, `StopMovementImmediately`, reset control rotation. 3. Player holds W → `IA_Move` fires → `ApplyMove(1, 0)` → `AddMovementInput(ForwardVector, 1)` → capsule moves at 450 cm/s.
* Player presses Escape → `TogglePause` → `SetPause(true)`, switch to `FInputModeUIOnly`, show cursor. World timers stop; core tickers continue.
* Player presses Escape again → `TogglePause` → `SetPause(false)`, switch to `FInputModeGameOnly`, hide cursor. 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 ## Screenshot capture
* `Tools/render*screenshots.sh` compiles editor, builds `ReviewMap` from `Tools/ue*build*review*map.py`, launches game in `-game` mode. 1. `Tools/render_screenshots.sh` compiles editor, builds `ReviewMap` from `Tools/ue_build_review_map.py`, launches game in `-game` mode.
* `AGigLineShotActor` iterates the camera list, sets view, calls `HighResShot 1280x720`, waits for capture.
* On last camera, requests engine quit. PNGs are copied to `Screenshots/` and committed. 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`) ## QA self-test (`-qaselftest`)
* Core ticker starts at `BeginPlay` (not a world timer — world timers freeze on pause). 1. Core ticker starts at `BeginPlay` (not a world timer — world timers freeze on pause).
* 1.0 s: begin driving forward input.
* 3.0 s: stop, measure displacement (> 200 cm = PASS). 2. 1.0 s: begin driving forward input.
* 3.5 s: call `ResetToStart`.
* 4.0 s: measure distance from spawn (< 100 cm = PASS). 3. 3.0 s: stop, measure displacement (> 200 cm = PASS).
* 4.5 s: call `TogglePause`, check `IsGamePaused()` (= true = PASS).
* 5.5 s: call `TogglePause`, check `IsGamePaused()` (= false = PASS). 4. 3.5 s: call `ResetToStart`.
* 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.
* 7.0 s: final verdict logged. 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 ## Build and import pipeline
* Blender headless (`Tools/export**.py`) reads `.blend` files, applies metre→centimetre conversion, exports FBX with `ue*metric_v1` preset. 1. Blender headless (`Tools/export_*.py`) reads `.blend` files, applies metre→centimetre conversion, exports FBX with `ue_metric_v1` preset.
* Unreal headless (`Tools/ue*import**.py`) imports FBX via Interchange, places meshes at geographic coordinates, sets collision profiles.
* `Tools/ue*build*demo_map.py` assembles `DemoMap`: creates/repositions actors, sets lighting, saves map and assets. 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.
# Deployment View # Deployment View
@@ -262,17 +300,18 @@ Source data: `Art/blender/` (`.blend` files), `Geo/` (OSM extracts, DEM, verific
| Project repo | `/run/media/system/DATA/Documents/06-games/gig-line` (Git + LFS, remote at `git.allucanget.biz`) | | 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) | | Build output | `/run/media/system/DATA/Builds/GigLine` (packaged Linux build, ~1.1 GiB) |
**Motivation:** Motivation
Single-machine development. No build farm, no CI pipeline yet. The engine, toolchain, and GPU are all on the same host. 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:** Quality and Performance Features
* Vulkan RHI on RTX 5070 Ti, open kernel module driver 615.78.08. - 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:** - 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 | | Building Block | Infrastructure Element |
| --- | --- | | --- | --- |
@@ -295,88 +334,117 @@ No server infrastructure. The game is a standalone executable.
## Coordinate system and scale ## Coordinate system and scale
** ****Source CRS***: EPSG:26911 (UTM zone 11N). Local origin recorded in `Geo/`. - **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). - **Blender**: metres. East → +X, north → +Y (Blender convention).
** ****Conversion***: every exporter calls the metre→centimetre function. Import presets (`ue*metric*v1`, `ue*character*v1`) are named and repeatable.
- **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. Rule: place a building only against a neighbour or street mesh, never in isolation.
## Collision model ## Collision model
* Site meshes (road, sidewalks, kerbs, crossing): `STATIC` mobility, `BlockAll` collision profile. - 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). - Terrain: `STATIC`, `CTF_UseComplexAsSimple` (forced by `UGigLineAssetTools` at build time, saved on the asset — the flag lives on the `UStaticMesh`/`UBodySetup`, not the map).
* Rule: the collision flag must be saved on the asset. Saving only the `.umap` silently reverts it.
- 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 ## Lighting
* Dynamic-only: `r.AllowStaticLighting=False`. All lights are `MOVABLE`. - 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. - 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 ## Materials
* All materials authored in Unreal, not carried from Blender (FBX import loses diffuse colours). - 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). - 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 ## Geographic data provenance
* OSM extract is layout data only — not authoritative for façade, height, or pavement detail. - 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. - DEM from 3DEP 1 m; elevation verified against cross-sections in `Geo/verification/`.
* In-game ODbL attribution drawn by `AGigLineHUD` every frame, bottom-left.
- Reference photography (local, gitignored) drives manual façade work.
- In-game ODbL attribution drawn by `AGigLineHUD` every frame, bottom-left.
## QA harness ## QA harness
* `-qaselftest`: core ticker (not world timer) so pause cannot freeze the test that proves pause works. - `-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. - `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.
# Architecture Decisions # Architecture Decisions
## ADR-1: Dynamic-only lighting for the demo ## 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. - **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. - **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 ## 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. - **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. - **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 ## 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. - **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. - **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 ## 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. - **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). - **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 ## 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. - **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. - **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 ## 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. - **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. - **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 ## ADR-7: Headless Blender via bpy scripts, not MCP
** ****Context***: Blender skill packs assume an MCP server; the project does not run one. - **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. - **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.
# Quality Requirements # Quality Requirements
@@ -425,7 +493,7 @@ Rule: place a building only against a neighbour or street mesh, never in isolati
| 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. | | 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. | | 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. | | 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. | | 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/`. | | 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. | | 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. | | MPFB | MakeHuman Plugin for Blender (2.0.18). Generates parametric human base meshes with rigs and baked materials. |
@@ -435,7 +503,7 @@ Rule: place a building only against a neighbour or street mesh, never in isolati
| Site | The terrain, road, sidewalks, kerbs, and crossing markings — the ground-level infrastructure of the demo area. | | 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. | | 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. | | 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. | | 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. | | 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. |
--- ---
@@ -444,6 +512,4 @@ Rule: place a building only against a neighbour or street mesh, never in isolati
arc42, the template for documentation of software and system architecture. arc42, the template for documentation of software and system architecture.
Template Version 0.1.0. Adapted for the Gig Line project. 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>.
Created, maintained and © by Dr. Peter Hruschka, Dr. Gernot Starke and contributors.
See <https://arc42.org>.