--- 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 | **Visual realism** | Renders read as the reference photographs: façade identity, proportion, material and light — judged side by side, shot against photo | | 2 | **Geographic fidelity** | Building placement and street scale match the measured data and the photographs | | 3 | **Terrain walkability** | Zero raycast holes across both sidewalks and the carriageway (84-sample transect passes) | | 4 | **Build reproducibility** | Fresh checkout + documented engine path produces a runnable Linux build | | 5 | **Provenance** | Every committed asset has recorded provenance | | 6 | **Performance efficiency** | 60 FPS at 2560×1440 on RTX 5070 Ti, documented preset, no frame generation | **How the order is used.** It decides trade-offs. When realism and performance disagree, realism wins and the cost is paid — but never by silently shipping a frame rate below the floor. The 60 FPS figure is a **budget that must still be met**, so the response to "realism costs too much frame time" is to cut the realism feature deliberately, record the cut, and keep the floor — not to let frames slip. Walkability outranks realism in one direction only: a beautiful block the player falls through is not a demo. ## 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 - **Realism**: reference photography drives every façade decision, measured data fixes placement and scale, and renders are compared against the photographs (`Tools/visual_loop.py`, `Screenshots/README.md`). One module kit at the 4.96 m bay keeps the street wall coherent; materials are world-aligned and lit by a fixed daytime rig so a shot is comparable between runs. - **Performance holds the floor, it does not set the agenda**: dynamic-only lighting (no build step, no static shadow maps), cheap procedural materials, minimal overdraw for street-level geometry, and 60 FPS at 1440p as a budget every release must meet. - **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/GigLineQA/Linux` (packaged Development build, ~1.1 GiB; outside the repository) | 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 Ordered by priority: realism first, performance last. The order decides design trade-offs; it does not license dropping a lower item silently (see the trade-off rule below the table). | Priority | Category | Requirement | | --- | --- | --- | | 1 | Realism / Fidelity | Façade identity, proportion, material and lighting read like the reference photographs when compared side by side | | 2 | Realism / Fidelity | Building placement matches the measured footprints and the photographs (within ~1 m) | | 2 | Realism / Fidelity | Street scale (lane width, sidewalk width) within ~10 cm of the measured profile | | 3 | Reliability / Terrain | Zero raycast holes across sidewalks and carriageway (84-sample transect) | | 3 | Usability | WASD + mouse look, jump, reset (R), pause (Escape) — no tutorial needed | | 4 | Maintainability | Fresh checkout builds with the documented engine installation | | 4 | Portability | Linux build packages and runs; Windows build ships | | 5 | Provenance | Every committed asset has a recorded source and licence | | 6 | Performance efficiency | 60 FPS at 2560×1440, documented preset, no frame generation | **Trade-off rule.** Realism leads: when a realism improvement costs frame time, the improvement wins. Performance is still a **floor, not a preference** — 60 FPS at 1440p without frame generation must be met at every release. If realism cannot fit inside that budget, reduce the realism scope deliberately and record the reduction in `CHANGELOG.md`; never ship below the floor without the owner's explicit approval. Walkability outranks realism in one direction: a block the player falls through is not a demo, whatever it looks like. ## Quality Scenarios | ID | Source/Stimulus | Response | Metric | | --- | --- | --- | --- | | QS-1 | Screenshot is compared against its reference photograph | The render reads as the same building | Similarity score and visual match confirmed by the owner; `Tools/visual_loop.py` reports the deltas | | QS-2 | A façade is placed from measured data | It sits on its verified footprint | World span probed against `Geo/verification/` within ~1 m | | QS-3 | Player walks both sides of the demo | No fall-through, character stays at ground Z | 0 raycast holes in 84-sample transect | | QS-4 | Player holds W for 2 s on flat road | Character moves forward | ≥ 200 cm displacement, Z constant within ±5 cm | | QS-5 | Player presses R | Character teleports to spawn | < 100 cm from `StartLocation` | | QS-6 | Player presses Escape | Game pauses, cursor appears | `IsGamePaused()` = true | | QS-7 | Player presses Escape while paused | Game unpauses, cursor hides | `IsGamePaused()` = false | | QS-8 | Fresh checkout + engine install | Build succeeds | Exit code 0, runnable binary produced | | QS-9 | Game runs on dev workstation at 1440p | Frame rate holds the floor | ≥ 60 FPS, 99th percentile ≥ 55 FPS | > QS-9 is last on purpose. Performance is a floor that every release must meet, not the goal that shapes the content: realism decides what gets built, the frame budget decides how much of it. # 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**