Files
gig-line/Docs/Architecture/09_architecture_decisions.md
T
zwitschi 5aa883eaff docs: convert all architecture .adoc sections to markdown, prettier-format all .md
- Converted 13 individual .adoc section files to .md via
  asciidoctor→docbook5→pandoc(gfm) + post-processing, placed alongside
  the .adoc sources in Docs/Architecture/
- Rebuilt architecture.md from the individual section .md files
- Ran prettier --write on all .md in the repo (23 files changed):
  normalised table column alignment, trailing whitespace, line breaks
- Added .agents/ to .prettierignore (vendored third-party content)
- All .md now passes prettier --check
2026-11-08 13:33:44 +01:00

3.2 KiB
Raw Blame History

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.