New Geo/tools/mapbox_buildings.py (stdlib urllib) Tilequeries mapbox-streets-v8 / layer building at each building centroid and merges height/min_height/type with our OSM height + source (tag > levels > guess, reusing block_height_report.classify_height). Reports matches, close calls, disagreements (sorted worst first), our-only and mapbox-only cases, and writes optional JSON. First run over 72 buildings: 58 match, 5 close, 3 disagree, 6 non-building. - Mapbox independently classifies our roof/canopy/shelter volumes as roof, canopy or shelter -> corroborates the 0.1.2 finding. - The 3 disagreements are rear building=yes/apartments structures rendering at our 2-level guess (6.4 m) vs Mapbox's 3.0 m. - Every levels x 3.2 m building is ~0.6 m per 6 levels taller than Mapbox implies, i.e. Mapbox suggests 3.1 m per level. Recorded, not applied. classify_height() now also treats building=canopy as a non-building volume (found by this cross-check), with tests. Data handling: Mapbox terms restrict persisting/redistributing their data, so .gitignore covers Geo/raw/mapbox-cache/ and Geo/verification/*mapbox*; the tool refuses to cache a response containing the token, and the token is never written to the cache, report or JSON. Token comes from the ignored .env. Also: 17 new tests (29 total) for the compare/nearest/centroid/render helpers and the canopy rule; Geo/README inventory row; architecture 05 + architecture.md tools table updated per the new upkeep rule.
523 lines
28 KiB
Markdown
523 lines
28 KiB
Markdown
---
|
||
title: Gig Line Architecture Documentation
|
||
description: Architecture documentation for the Gig Line Linux-first Unreal Engine 5 demo around 6840 Hollywood Blvd.
|
||
status: v0.1.0
|
||
date: 2026-11-08
|
||
---
|
||
|
||
# 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-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 | **Provenance** | Every committed asset has recorded provenance |
|
||
|
||
## 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 |
|
||
|
||
# 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. |
|
||
|
||
# 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 | — |
|
||
| 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 |
|
||
|
||
# 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`.
|
||
|
||
# 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` | HUD text 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) |
|
||
| `input_emulation.py`, `input_test.py` | OS-level virtual keyboard/mouse injection for input verification |
|
||
| `Tools/tests/` | Stdlib `unittest` tests for the pure parts of the tools (`requirements-tools.txt`) |
|
||
| `Geo/tools/mapbox_buildings.py` | Second height source: Mapbox `mapbox-streets-v8` building data vs our OSM heights |
|
||
|
||
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).
|
||
|
||
# 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.
|
||
|
||
# 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.
|
||
|
||
# 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.
|
||
|
||
## 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.
|
||
|
||
# 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.
|
||
|
||
# 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 |
|
||
| 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 |
|
||
|
||
# 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-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. |
|
||
|
||
# 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. |
|
||
| PIE | Play In Editor — an Unreal Editor feature that runs the current map as a live game session inside the editor window, with full game code, input, and physics, without packaging a build. Used for interactive verification (walk, reset, pause) before the scripted QA self-test. |
|
||
| 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. |
|
||
| 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. |
|
||
| UE | Unreal Engine — Epic Games' real-time 3D creation platform (version 5.8.4 in this project). Comprises the Unreal Editor (including PIE, content browser, viewport, blueprint editor), a C++ game framework, and runtime systems for rendering (Vulkan RHI on Linux), physics (Chaos), and input (Enhanced Input). The game project is `GigLine.uproject`; game code is a single C++ module in `Game/GigLine/Source/GigLine/`. |
|
||
| 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. |
|
||
|
||
---
|
||
|
||
**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).
|