feat(hero): fluting and a recessed motto band; placement gets one source of truth

Hero detail:
- Fluting: 20 grooves per column as thin shadow-tone cylinders set into the shaft
  (120 pieces) rather than boolean cuts - readable in silhouette and grazing light
  at a fraction of the cost.
- Motto band: real recess with a moulded surround 6 cm proud and the panel 12 cm
  behind, replacing the 8 cm dark stripe.
  Hero 148 parts/3044 tris -> 271/5492, still 14.50 m.

Placement bug this exposed (a real one, invisible in a render):
- ue_hero_facade_import.py carried its own hero position (-12024.5, -1450) from
  before the 0.1.0 frontage fix, so running the importer alone moved the hero 13 m
  east and onto the north side of the boulevard. Only symptom: the reference score
  fell 0.69 -> 0.56 and the 3x3 composition correlation flipped +0.54 -> -0.08.
- New Tools/ue_placement.py is the single source of truth (hero position, verified
  frontage spans, span validators). Both the importer and the demo builder use it;
  the import asserts the staged span and logs PLACEMENT ERROR otherwise.
- 11 new tests, including one that fails if the stale literal returns. 78 total.

Spawn-view score recovered to 0.72 (best yet); screenshots verified 4/4, packaged QA
all PASS.
This commit is contained in:
zwitschi committed 2026-11-08 22:12:44 +01:00
1 parent bc5da3a8ab
commit 92b477d340
17 files changed
+255 -25

No files matched your search

+3 -1
View File
@@ -23,6 +23,8 @@ import unreal
MAP = "/Game/Hollywood/DemoMap"
# Repository root, so the texture generator can be invoked by path.
ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
import ue_placement # noqa: E402
RESULT = "/tmp/gigline/demo-map.txt"
lines = []
@@ -401,7 +403,7 @@ def build():
# the NORTH side of the street, which only looked right while it stood alone.
hero = unreal.EditorAssetLibrary.load_asset("/Game/Hollywood/ElCapitan/SM_HeroFacade")
if hero:
actor = spawn(unreal.StaticMeshActor, unreal.Vector(-13336.0, 1307.0, 0.0), "Hero_Facade")
actor = spawn(unreal.StaticMeshActor, unreal.Vector(*ue_placement.HERO_LOCATION_CM), ue_placement.HERO_ACTOR)
if actor:
actor.static_mesh_component.set_static_mesh(hero)
actor.static_mesh_component.set_mobility(unreal.ComponentMobility.STATIC)