Banner lettering (JIMMY KIMMEL LIVE): new Tools/gen/generate_banner_texture.py draws the exact title with Pillow + Liberation Sans Bold - an image model would mangle a trademark string, and Qwen-Image 2.1 is research-only. Gold JIMMY / KIMMEL / LIVE stacked on a crimson ground. ue_hero_facade_import.py generalises import_albedo to import_texture and wires the banner into M_Facade_Banner_Ref as Base Color (tiling 1.0), replacing the flat dark tint with a brighter red per the owner's 'less dark, more bright'. Re-rendered all three ReviewMap staging shots (front, oblique, portals) and updated their Screenshots/README.md status rows. The hero facade rework is now closed at 'surface detail that reads at 45 m'. The remaining elevation work - volute capital depth, lattice grille depth, and the full realism pass - is deferred to 0.9.0 per the owner, and the 0.9.0 hero item records the hand-off.
44 KiB
TODO.md
Actionable task list for this project. This file is the single, central place for planned work, claims, and progress marks. Milestone goals, scope, and release gates are in ROADMAP.md.
Conventions
- Mark items open (
- [ ]), active/in progress (- [A], deferred- [D]), or done (- [x]). Keep the marks accurate. - A level-three (
###) section being worked on carries- active - <sessionId>(and optionally the branch name) in its heading. Remove the suffix when you stop. - When all steps in a version section are done: write a
CHANGELOG.mdentry, then remove the version section from this file. - Release gate: a version is tagged only on the owner's explicit go-ahead once its release checks pass, not automatically when the checkboxes close.
Toolchain — end-to-end asset check (done 2026-11-10)
The chain that answers "does the asset look right in both the staging map and the game map" is now one command: python3 Tools/review/e2e_asset_check.py. It renders the Blender source, empties both maps, runs both builders, captures, judges with two models, and regenerates Screenshots/README.md. Last full run: PASS on all six steps (empty maps 9 s, demo build 10 s, review build 9 s, captures 80 s, judge 388 s).
- Group the sixty tools by sandbox:
Tools/unreal/,Tools/blender/,Tools/review/,Tools/gen/,Tools/input/, with the layout documented inTools/README.md. Tools/unreal/ue_recreate_maps.py: empties both maps and verifies 0 actors left. Deliberately does not delete the.umap- measured thatnew_level()refuses a path whose package is still in memory.- Whole-level clear in both builders; a prefix-only clear let experiment actors survive into saved maps.
- Two-model judge with reconciliation, and a two-checkpoint texture generator that compares before choosing.
- Texture generation through the documented Stability Matrix workflows (
texturesubcommand). - Local ComfyUI documented, including "start Stability Matrix first" and the per-model licence rules.
- Driver hardening: unlink result files before each step, stream child output to a per-step log, refuse to start while another editor is alive.
- Make the judge useful again. It reports 0/11 on shots the owner has approved and has been wrong in both directions.
- Until its expectations are re-derived, treat a model disagreement as the signal and the verdict as noise.
- Examine comfyui tool to extend judge coverage or improve its scoring mechanism.
- Wire the e2e driver into the release checks once the judge can be trusted.
Vehicle physics — Chaos rig (own task, from 0.3.0)
Split out of 0.3.0 because it is a physics problem, not an asset one. The Chaos pawn is parked: with it staged the actor is launched to Z 1993 cm (18 m up) and reports 0 wheels, so it litters the demo without being drivable. The visible car is the plain panel set, which looks right and is what the review shots show.
Evidence
GigLine vehicle geometry: box 452x205x40 centre 0,0,-18 | bounds origin ...,1393 extent 1,1,1
GigLine vehicle motion: velocity -24,-182,-28 cm/s angular ~0 mass 1500 sim=1
GigLine vehicle mesh asset: SK_Vehicle_Sedan
GigLine vehicle diag: mesh=1 simulating=1 physasset=yes setups=4 wheels=0
The physics body is nearly still while the actor is nine metres above its spawn. That is not a force problem, it is a transform problem: something writes the actor transform that is neither the body's velocity nor our code. The mesh component's bounds read extent 1,1,1 - a degenerate 1 cm box - which is the same symptom seen from the other side.
Ruled out (each tested in its own run)
- Spawn penetration - spawned level with the road, 1.2 m above it, 3 m above it and 5 m above it; the actor climbs in every case.
- Visual panel collision - disabling it changed nothing.
- Wrong chassis box -
452x205x40 centre 0,0,-18is the car. - Gravity -
global_gravity_z = 0.0and the character falls normally, so the world pulls down. - Mass - the 1500 kg override applies (logged), and the body still does not rise.
Measured after the transform finding
bones: 6 [VehicleRig root Wheel_FL Wheel_FR Wheel_RL Wheel_RR]
setups: [Wheel_FL Wheel_FR Wheel_RL Wheel_RR] -> names match, suspect 3 is gone
mover: updated=VehicleMesh ticking=1
stop: mover tick disabled at 2.5 s (Z 2001); at 3.0 s the actor is still at Z 2258
terrain: CTF_USE_COMPLEX_AS_SIMPLE, 0 box elements -> no invisible lid to be ejected from
So the wheel bones match, the terrain has no proxy lid, and stopping the mover did not stop the climb - meaning either the stop does not take effect (something else re-enables or writes the transform every frame) or a second writer exists.
Suspects, in order
- Component hierarchy: a pawn whose root is the mesh while the physics state belongs to another component behaves exactly like this - correct box, correct mass, near-zero velocity, moving actor, 1 cm bounds.
UChaosWheeledVehicleMovementComponent::UpdateState/OnUpdateTransformwriting the transform from a vehicle state that was never created (which is also whyCreateVehicle()yields no wheels).- The skeletal mesh asset itself -
SK_Vehicle_Sedancame from our own FBX pipeline; if its bone layout does not match what the wheel setups name,CreateVehicle()bails before creating wheels.
Bisect result: the map, not the pawn
The same pawn, unchanged, in two maps:
ReviewMap (flat 160 m floor): Z 200 -> 188 -> 174 -> 157 -> 87 vZ -208 -> -663 falls correctly
DemoMap, on the street: Z 486 -> 920 -> 1126 -> 1385 vZ oscillates ~0 teleports up
DemoMap, 60 m off the street: Z 291 -> 467 -> 920 -> 1343 vZ +1595 launches
DemoMap, 25 m above ground: Z 2496 -> 2664 -> 3068 -> 3434 vZ +1509 launches at once
So the Chaos rig is fine and DemoMap is what breaks it - at any height, anywhere in that map, and not by contact (25 m in the air launches immediately). The next comparison is between the two maps' world settings and level actors: ReviewMap was built by Tools/unreal/ue_build_review_map.py, DemoMap by Tools/unreal/ue_build_demo_map.py, and the difference that matters is in what one stages and the other does not.
The transform is written directly, not moved
Zeroing the body's linear and angular velocity every frame for two seconds changes nothing:
t=0.25 Z=3220 vZ=0 t=0.75 Z=3683 vZ=0 t=1.25 Z=4197 vZ=0
The actor keeps rising at ~1200 cm/s while its velocity is pinned to zero. Something calls a transform setter on the vehicle every frame - this is not a force, an impulse or a bad initial state, all of which the clamp would have removed.
Game/GigLine/Source/GigLine/*.cpp contains exactly one direct transform write outside the character (GigLineShotActor moves its camera), so the writer is engine-side: the Chaos vehicle component driving UpdatedComponent from a vehicle state that was never created, or a skeletal-mesh transform update.
Map-content bisect: the terrain is involved
Built Tools/unreal/ue_vehicle_probe_map.py (duplicates ReviewMap, optionally adds ONE demo mesh plus the pawn, saves as VehicleProbe) and ran it:
control (no extra mesh) Z 300 -> 297 over 1.25 s (resting on the review floor)
+ Terrain_DEM Z 300 -> 498 over 1.25 s (thrown upward)
So Terrain_DEM is enough to reproduce it in a map that otherwise works. Two fixes were then tried and neither helped:
Tools/unreal/ue_clear_simple_collision.pycleared the auto-generated convex hulls from all 76 site/street meshes (terrain had 1 convex element over the whole 279 m) and set complex-as-simple - still rises.- Setting the terrain component to
CollisionEnabled::QueryOnlyso traces still hit it but the physics solver ignores it - still rises.
That means the ejection is not the convex hull and not the collision channel; the next probe is whether it is the complex triangles (inverted winding pushing bodies out) - test by setting Terrain_DEM to no collision at all in the probe map and confirming the pawn falls.
Where it stands: deferred to its own session
Three fixes were tried after the terrain bisect and none changed the behaviour:
- clearing the auto-generated convex hulls from all 76 site/street meshes;
- setting the terrain component to
QueryOnly; - staging the terrain in the probe map with collision disabled entirely.
The pawn still rises in every case, so the fault is not the terrain's convex hull, not its collision channel, and not even its collision. The player is unaffected throughout - re-checked after each fix, and the character still stands on Sidewalk_North_07 at 157 cm.
Deferred rather than guessed. What a fresh session needs:
- the probe workflow is in place:
Tools/unreal/ue_vehicle_probe_map.pywithGIGLINE_PROBE_ASSETandGIGLINE_PROBE_NOCOLLISION,Tools/unreal/ue_clear_simple_collision.pyfor the hull hygiene; - the vehicle diagnostics are switches:
-probes,-profile,-novehmover, plus the always-on velocity clamp, overlap list and velocity profile; - the next question is why a map carrying a 279 m static mesh changes a physics body's behaviour when that mesh has no collision at all, which points at streaming, memory layout or the physics scene's broadphase rather than at collision authoring.
Bisect plan (kept for the next session)
- Spawn the same pawn in
ReviewMap(flat 160 m floor, no slices, no UCX ground) and repeat the profile. Flies there too -> the asset/component is at fault. Settles there -> something inDemoMap(the UCS slabs, the terrain, or the world settings) drives it. - In parallel, spawn a stock
AWheeledVehiclePawnwithSK_Vehicle_Sedanand default settings in the same spot: if the stock pawn settles, the difference is inAGigLineVehicle's setup (mass override, stability control, our movement subclass). - Only after the bisect: fix, then confirm
Wheels.Num() == 4.
Where it was left (2026-11-10)
Two facts that matter more than the hypothesis list above: on ReviewMap's flat floor the same pawn falls correctly (Z 200 -> 87, vZ -663), and in DemoMap it teleports upward at any height - including 25 m in the air - with the transform written directly (clamping velocity to zero every frame does not stop it) while the body reports a near-zero velocity. Disabling the movement component's tick changes nothing; there are zero overlaps; the body is genuinely dynamic (profile=PhysicsActor); shadow-style collision explanations were ruled out by staging the terrain with collision disabled entirely and seeing the pawn still rise.
Tasks
- [D] Give
SK_Vehicle_Sedana physics asset whose single chassis body matches the car's box and is positioned below the shell, then confirm the pawn settles on the road instead of launching. Deferred: the chassis box, mass and gravity all measure correct, so this is not the shape of the body. - Find what writes the actor transform in
DemoMapbut not inReviewMap. The map diff is empty where it matters - samekill_z, same gravity, no World Partition, neither has a physics volume - so the next probe is a fresh map with staged content added group by group (Tools/unreal/ue_vehicle_probe_map.pyalready does the one-mesh version). - Confirm
Wheels.Num()becomes 4 once the vehicle is created; log it at the settle check. - Only then re-stage the pawn, re-add enter/exit and the driving route.
Hero facade rework — from the ReviewMap review (own task)
Split out of 0.3.0 on 2026-11-09 on the owner's instruction: the three hero-facade staging shots (review-hero-facade-front, review-hero-facade-oblique, review-hero-portals) were rejected as "rework needed to match reference", and that is asset work rather than vehicle work.
Reference vs current
Reference: security-game/docs/screens/refs/hollywood/el-capitan-facade-day-wikimedia-2009-10-27.jpg (the north elevation, daylight). What it shows, and where the model stands:
| Feature | Reference | Model (SM_HeroFacade) |
|---|---|---|
| Rusticated stone, warm limestone | heavy banded rustication over the whole wall | flat M_Facade_Stone, no banding |
| Six giant Ionic columns | fluted shafts, volute capitals, moulded bases | present, fluted (20 flutes each), capital block only |
| Three vertical JIMMY KIMMEL LIVE banners | red, gold lettering, hung between the middle columns | present as flat panels with M_Facade_Banner |
| Inscription band | "FREEMASONRY BUILDS ITS TEMPLES..." carved lettering | Hero_MottoBand + surround + two medallions, no lettering |
| Lattice windows between columns | dark metal grilles, two bands | Hero_Window_1_* / _2_* as plain panels |
| Cornice, dentils, parapet | deep cornice, 52 dentils, balustrade with finials | cornice + 52 dentils + parapet, no balustrade or finials |
| Three entry portals with steps | recessed, framed, three sets of steps | present: portals, jambs, lintels, mullions, five steps each |
So the model has the massing and most of the parts; what it lacks is surface (rustication, lettering, grille detail, balustrade) and material variation.
Found: the detail is modelled inside the wall
Measured, not guessed:
blend scene Y -12.50 .. +0.13 (front of the wall at -0.50)
Hero_Mass y = -BODY_D/2 - 0.5 -> spans -12.50 .. -0.50
Hero_Banner_1 y = -1.08 .. -1.02 -> 55 cm BEHIND the front face
imported mesh bounds y = -13 .. +1250 cm
The facade's detail - banners, and by the same construction the window bays and portal surrounds - is placed behind the wall's front face, so it is inside Hero_Mass and never renders. That is why the captures show a plain block with six columns: the columns, cornice and dentils happen to protrude, everything else does not. The model does not need remodelling first; its detail needs moving in front of the wall.
Fix: give Tools/blender/hero_facade_build.py a FRONT_Y = -BODY_D / 2.0 - 0.5 constant (the mass's front face) and place every elevation detail relative to it (FRONT_Y - 0.10 for applied detail, FRONT_Y for flush), instead of the hand-typed negative coordinates each call site uses now. Then re-export, re-import and re-render.
And check the review shot. The three hero captures show a plain block with six columns and nothing else - no banners, no windows, no portals - while the mesh demonstrably carries all four materials (M_Facade_Banner, M_Facade_Stone, M_Facade_StoneShadow, M_Facade_GlassDark) and is staged at (-13336, 1307, 0) with yaw 0. That suggests the cameras are framing the wrong actor (Frontage_SM_ElCapitanTheatre sits at the origin) or the wrong side, and the "rework" note may be describing a camera error rather than the model. Verify that first: one render with a camera aimed at Hero_Facade from Y -4000 at 8 m height.
First pass against the folder references
Art/reference/hero-masonic/ (15 images, ignored by git as reference photography) is now the source of truth rather than one Wikimedia photo. 02-masonictemple01.jpg and 06-el-capitan-theater-frontal-fachade.jpg are the front elevations used for the first pass; 05-hollywoodmasonictemple-1922.jpg records the original masonry.
Done in this pass:
- the detail is seated on the wall (previous step), so banners, windows and portals render;
- the blank
Hero_Stylobate_LintelBandacross the portals is gone - the reference has open doorways with steps, which now read correctly; rustication()cuts five ashlar courses from the pavement to the portal heads;balustrade()adds a bottom rail, a top rail and 38 balusters along the roof edge.
Still missing, from the same references: warm sandstone instead of the flat pale stone, lattice grilles in the window bays, the carved inscription on the motto band, and the two medallions are not reading at distance.
The iteration loop
bash Tools/review/hero_iterate.sh runs the whole chain in one command: chmod the Blender files, build the facade, import it, render the capture set, judge the shot with the vision model, and write a comparison plate at Screenshots/review/hero-compare-front.png. Each step fails loudly and logs to /tmp/gigline/.
Iteration 1 verdict (judge, confidence 0.9):
"The scene lacks the warm yellow-grey sandstone texture and the detailed fluted Ionic columns. Additionally, the red banners do not match the expected design, and there are no visible entrance doorways or decorative elements like the inscription band or medallions."
Measured against the plate, that splits into:
| Finding | Reality | Next action |
|---|---|---|
| not warm sandstone | true - the UE material M_FacadeStone is still near-white (0.62-0.76 grey) |
warm the UE material spec in Tools/unreal/ue_hero_facade_import.py, not the Blender one |
| fluting missing | false - 120 flute strips exist and cast shadows; they are lost at 45 m | not a modelling problem; check the review camera distance |
| banners wrong | partly - proportions are now 1.35 x 6.2 m and hang correctly, the lettering is absent | needs a texture, not geometry |
| no doorways | false - three 1.2 m deep recesses with steps; they read dark because the reveal is glass-black | lighten the reveal material |
| no inscription/medallions | true - the band and two medallions exist but are flat and untextured | texture the motto band |
Tasks
Done on 2026-11-09/10, each verified by a capture:
- Confirm the hero captures frame
Hero_Facade- cameras at (-13336, 1307), hero actor there, frontage at the origin. - Seat the elevation detail in front of the mass (
FRONT_Y+seat_on_front(), 99 parts moved) - banners, windows and portals render now. - Remove the blank lintel band across the portals; the three doorways are 1.2 m deep with five steps each.
- Window grilles (7 vertical + 5 horizontal bars per bay), five ashlar courses, roof balustrade with 38 balusters.
- Warm sandstone in the engine -
tint_imported_materials()authors one material per slot from the reference. - Banner proportions 1.35 x 6.2 m hung from 7.2 m, matching the photographs.
Open:
- Make the generated ashlar albedo render. Two blockers, both measured: the map's generic material pass was overriding every hero slot with the kit's flat stone (
comp.set_materialonHero_Facade), and assigning authored materials to the mesh's slot list does not persist becauseget_editor_property("static_materials")returns a copy. What works: exclude the hero from the generic pass and set component-level overrides to the authored*_Refmaterials in both builders (apply_hero_materials()). The elevation now shows coursed, grainy limestone. - Carved inscription:
inscription()inTools/blender/hero_facade_build.pylays 112 letter marks in three lines across the attic, in the shadow stone so they read at 45 m. They had to be seated on the parapet face (FRONT_Y + 0.40): the parapet is 1.2 m deep and stands in front of the wall plane, so marks at the wall plane were hidden behind it. - Medallion relief that reads at 45 m. Measured first, then fixed: the discs were not just flat - they were buried.
seat_on_frontputHero_Medallionat offset 0.08 → front face Y −0.42, while the parapet (1.2 m deep) stands at Y −0.15, so both medallions were inside the parapet and never rendered (the motto band and surround have the same bug at offset 0.06). Fixed: three stepped layers per medallion —Hero_MedallionRim(0.55 m, dark, offset 0.36 → Y −0.14),Hero_MedallionField(0.38 m, light, offset 0.43 → Y −0.07),Hero_MedallionBoss(0.15 m, dark, offset 0.50 → Y 0.00) — a 7 cm step each way so the rim/field/boss read as relief. Moved from ±6.2 (inside the inscription text, ±6.87) to ±9.8. Rendered and judged; the two-model judge is advisory-pessimistic (no0.93) and does not flag medallions any more. Owner review pending. - Motto band and surround — same burial bug (offset 0.06 → front Y −0.44). The band is now light stone (was
stone_dark, which would have swallowed the dark lettering once visible), recessed at offset 0.34 (Y −0.16), with the moulded surround proud at offset 0.43 (Y −0.07) and the inscription at 0.40 (Y −0.10); the dead duplicateHero_MottoBand 0.40entry is removed. Rendered and judged; the judge (no0.93) no longer flags the band, only the stone warmth/column fluting the owner has already directed lighter. Owner review pending. - Banner lettering (JIMMY KIMMEL LIVE). New
Tools/gen/generate_banner_texture.pydraws the exact title with Pillow + Liberation Sans Bold (an image model would mangle a trademark string, and Qwen-Image 2.1 is research-only). GoldJIMMY/KIMMEL/LIVEstacked on a crimson ground, 512 × 2304.ue_hero_facade_import.pygeneralisedimport_albedo→import_textureand wires the banner intoM_Facade_Banner_Refas Base Color (tiling 1.0). Owner review pending. - Crimson banner tone + lettering. The texture carries the red ground (186,24,24 — brighter than the old dark tint, per the owner's "less dark, more bright") and the gold lettering, so the flat tint is replaced outright.
- Re-render the three ReviewMap staging shots and put them back in the status table for review. All three (
review-hero-facade-front,review-hero-facade-oblique,review-hero-portals) regenerated 2026-11-10 with the full attic detail, and theScreenshots/README.mdstatus table updated. Owner review pending.
Deferred to 0.9.0 (owner, 2026-11-10). This pass is closed at "surface detail that reads at 45 m". The remaining elevation work is a 0.9.0 pass, not another patch here: volute capital depth (the capitals are block-only, the reference has strong shadow lines), lattice grille depth (the window bays are plain panels with bars, not the dark metal lattice), and the full realism pass (heavy banded rustication, measured material library, texel-density and LOD/collision per building). The 0.9.0 hero item records the hand-off.
0.3.0 — Chaos vehicle, enter/exit, closed driving route (weeks 10–13)
Vehicle production - active - session-5598ce7e-27e3-4c64-bb49-c04a4a31ee58 (branch vehicle-0.3.0)
- [A] Model one vehicle in Blender with collision meshes; export to Unreal. Model done (
Tools/blender/vehicle_build.py→Art/blender/vehicle/gigline-sedan.blend, preview inArt/blender/vehicle/preview.png): 4.72 x 1.80 x 1.44 m, 2.78 m wheelbase, 1.62 m track, 0.33 m wheels, 252 triangles, fourUCX_convex hulls. Dimensions come from real sedan figures and are logged to the report, so the vehicle config can read them rather than restating them. - Imported into Unreal (Tools/unreal/ue_vehicle_import.py→/Game/Hollywood/Vehicle), split per the vehicle-artist object split:SM_Vehicle_Body(3 slots, 4.76 x 1.76 x 1.28 m),SM_Vehicle_Glass,SM_Vehicle_Light_Front,SM_Vehicle_Light_Rear,SM_Vehicle_Mirrors, and oneSM_Vehicle_Wheel(0.22 x 0.66 x 0.66 m) reused four times. The body FBX carries theUCX_hulls as simple collision.- LODs cut for real: decimating the duplicate gives LOD1 at 38 triangles and LOD2 at 14, against 132 for LOD0. The first attempt duplicated the shell unchanged and produced 84-triangle LODs that saved nothing - worth remembering as the failure mode of a "LOD" step nobody measures.
- LOD group wiring is open:
StaticMeshEditorSubsystem.import_lodis unavailable in a headless commandlet (get_editor_subsystemreturns None), so the LOD meshes import as their own assets and the group still needs an editor session.
- [D] Set up Chaos Vehicle with wheel and physics configuration. Deferred to its own task (
Vehicle physics — Chaos rig): the pawn is parked, the visible car is the panel set, and the remaining question is what writes the actor transform inDemoMapbut not inReviewMap.- Fixed the floating: the physics asset had a body per bone, and the four wheel bodies intersected the chassis body and pushed the car 3.7 m up. It is now a single chassis body on the
rootbone (452 x 205 x 40 cm), which is what Unreal's own vehicle template uses - Chaos simulates the wheels itself, they must not be separate rigid bodies. Settle check: Z 119 cm at a spawn of 120 (was 494). - Drive test fails, with a specific cause:
-drivetestholds full throttle for 3 s and reports speed and distance. Result:speed=0 cm/s, travelled 2.2 m -> FAIL, and BeginPlay logs0 wheel objects after registerwhile the component reports 4 wheel setups. The setups exist but no wheels are created from them, so there is nothing to apply torque to. - Next: confirm the skeleton's bone names match the setups (
Wheel_FL,Wheel_FR,Wheel_RL,Wheel_RR) - a name mismatch silently produces zero wheels - and give the front and rear pairs their ownUChaosVehicleWheelsubclasses rather than the base class, which is what the setups point at today. - Also open: LOD group wiring, enter/exit, driving route, handling.
- Fixed the floating: the physics asset had a body per bone, and the four wheel bodies intersected the chassis body and pushed the car 3.7 m up. It is now a single chassis body on the
- Fix the vehicle not rendering in the scene. Chased to a strong clue, not yet solved. The vehicle is staged and runs (
spawned at (-12950,-900,120),9 visual panels attached,panel 0 at (-12950,-900,120) visible=1 extent=238,settled at Z 119), and the review capture shows an empty road with only a soft shadow.Tools/review/visual_loop.py --verifypasses the frame;Tools/review/judge_screenshot.pyreturnsverdict=no confidence=1.0. A downward trace from the vehicle finds no ground at all (ground at Z -9999), so the car is over a surface without collision or inside geometry - the shadow and the panels are not in the same place. Fixed 2026-11-09 — the car renders, built from the owner'shot hatch.blend. Fixed: the vehicle was spawned 2.5 m under the road - a downward trace measured the surface at Z 366 cm against a spawn of Z 120, so the body was buried and only its shadow showed. The spawn is now Z 470 and it settles there.- Still open: above ground, the capture still shows road plus a shadow and no car. Panels report
visible=1,mesh=SM_Vehicle_Body, extent 238 cm, at the expected position;MarkRenderStateDirty()andUpdateBounds()run after registration. Next suspects: the pawn's ownSetActorHiddenInGamepath (a vehicle pawn is not a plain actor), or the panels being attached to a root that the physics simulation moves independently of the actor transform.
- Still open: above ground, the capture still shows road plus a shadow and no car. Panels report
- Fix the character and car floating. The measurement was taken at the wrong moment. The foot probe ran in
BeginPlay, while the pawn is still at its spawn height and falling, so every trace reported a surface far below it (ground 366against an actor at 561) and read as a float that was not there. The probe now runs three seconds after spawn, from the capsule's feet, on three channels, and names the actor it hits. Character: the player start at Z 600 left the soles 39 cm in the air (the capsule settles at 561 on this pavement); the start is now the measured 561. Car: the template's lowest geometry is exhaust, so grounding on the whole model put the tyres 4 cm above the origin - it is now grounded on its wheels, staged at Z 342 after the traced road height (366) disagreed with the visible road by ~25 cm. - Fix the vehicle's material colour. The template's
car paintis a legacy mix-shader graph that the FBX exporter cannot map, soSM_Vehicle_Bodyimported holdingWorldGridMaterialand rendered black while Blender showed red. Legacy graphs are now converted to Principled before export (saturated colour wins over the grey diffuse next to it), and the staged body panel is assignedM_Vehicle_HatchPaint. Judge:verdict=yes confidence=0.9. - Fix the missing vehicle glazing. The
windowsmaterial was metallic 1.0 with roughness 0.0 - a black void that read as an empty cabin. Now tinted translucent (opacity 0.85, roughness 0.08); opacity 0.45 was tried first and made the glass invisible. The vision judge still returnsverdict=nofor the frame, disagreeing with what is visibly tinted glass; it is advisory, and the human verdict decides. - Reconcile the road and sidewalk surfaces. Solved: the road strip was a single 279 m mesh whose auto-generated convex hull sat 2 m above the visible surface.
- The site export now slices sidewalks and kerbs into ~20 m pieces with explicit
UCX_boxes, and the slice cuts are fixed (the far cut kept the wrong half, so every slice spanned the whole street). Slice tops descend honestly along the street: 380, 340, 309, 284, 254, 231, 205, 169 at the player's X, 138, 104 cm. - In the map at the same X:
Sidewalk_North_07tops at 169 cm,Road_Hollywoodat 366 cm. The road is ~2 m above its sidewalk, so the player lands on the road and no collision setting on the sidewalk can change that. - Neither slicing,
UCX_hulls,set_complex_collision_as_simple, nor winding (all 2790 sidewalk faces point up) changed the outcome - each of those was the wrong layer. - Cause found: the road is built across -10.5..+10.5 m and the north sidewalk +10.5..+15.8 m, so on the straight they meet at the gutter - but the strips follow a curved centreline and the fan-out pushes the road's outer edge to -13.8 m, overlapping the sidewalk band (-17.3..-11.8 m). In that overlap the road sits at 366 cm and the sidewalk at 158 cm.
- Resolved 2026-11-10: the real cause was the collision hull, not the geometry. A 279 m strip imports with one auto-generated convex hull whose top is the mesh's maximum height, so every downward trace landed on a flat lid at 366 cm. Slicing the road like the sidewalks, and removing the single
Road_Hollywoodasset from the map so the slices win, gives a continuous cross-section:Terrain 154 / Sidewalk_North_07 158 / Road_Hollywood_07 158. The player now stands onSidewalk_North_07at 158 cm with feet at 161. - Superseded: sample both source meshes at the player's XY in
Art/blender/street/street-2026-11-06.blend. The road is built asdem_z + 0.02and the sidewalk asdem_z + kerb * tfrom the same DEM sampler, so a 2 m gap cannot come from that code - the suspect is the DEM lookup or the mesh's coordinate frame, not the assembly logic.
- The site export now slices sidewalks and kerbs into ~20 m pieces with explicit
- Implement enter/exit interaction.
- Build a closed driving route with boundaries.
- Tune basic handling to a drivable state.
Release checks
- Player can enter, drive the closed route, and exit without defects.
- No blocking vehicle collision or packaging defects.
- Performance target still met at 1440p.
- Tag
v0.3.0and writeCHANGELOG.mdentry; then remove this section.
0.3.1 — Handling tuning (patch)
Patch tasks
- Refine vehicle handling feel based on
0.3.0feedback. - Tag
v0.3.1and writeCHANGELOG.mdentry; then remove this section.
0.3.2 — Vehicle collision fixes (patch)
Patch tasks
- Fix vehicle collision defects (mesh/physics mismatches).
- Tag
v0.3.2and writeCHANGELOG.mdentry; then remove this section.
0.3.3 — Input fixes (patch)
Patch tasks
- Fix vehicle/character input issues in
0.3.x. - Tag
v0.3.3and writeCHANGELOG.mdentry; then remove this section.
0.4.0 — Small connected neighborhood and map streaming (weeks 14–17)
World expansion
- Extend geo pipeline to a small connected neighborhood beyond the demo block.
- Produce modular buildings, sidewalks, and roads for the expanded area.
- Set up World Partition with streaming cells.
- Configure HLOD for distant buildings.
- Verify no seams or popping between streamed cells during traversal.
Release checks
- Continuous walking (and driving) across the expanded area works.
- Streaming does not introduce blocking defects.
- Performance target re-validated at 1440p with streaming active.
- Tag
v0.4.0and writeCHANGELOG.mdentry; then remove this section.
0.4.1 — Seam fixes (patch)
Patch tasks
- Fix visible seams between streamed cells.
- Tag
v0.4.1and writeCHANGELOG.mdentry; then remove this section.
0.4.2 — Streaming corrections (patch)
Patch tasks
- Correct streaming/loading issues found in
0.4.x. - Tag
v0.4.2and writeCHANGELOG.mdentry; then remove this section.
0.4.3 — HLOD tuning (patch)
Patch tasks
- Tune HLOD quality and distance settings.
- Tag
v0.4.3and writeCHANGELOG.mdentry; then remove this section.
0.5.0 — Pedestrians, crosswalk behavior, ambient traffic (weeks 18–21)
Simulation
- Add pedestrian characters with navigation, using
AGigLineNPCPerson(the reusable NPC prefab) as the base, driving it via AI/AutoPossessAI. - Implement crosswalk behavior (pedestrians use the designated crossing).
- Add limited ambient traffic on the street network.
- Optimize simulation cost to stay within frame budget.
Release checks
- Pedestrians and traffic behave without blocking defects.
- Performance target re-validated at 1440p.
- Tag
v0.5.0and writeCHANGELOG.mdentry; then remove this section.
0.5.1 — Navigation fixes (patch)
Patch tasks
- Fix pedestrian navigation issues.
- Tag
v0.5.1and writeCHANGELOG.mdentry; then remove this section.
0.5.2 — Crossing fixes (patch)
Patch tasks
- Fix crosswalk behavior defects.
- Tag
v0.5.2and writeCHANGELOG.mdentry; then remove this section.
0.5.3 — Simulation optimization (patch)
Patch tasks
- Optimize pedestrian/traffic simulation cost.
- Tag
v0.5.3and writeCHANGELOG.mdentry; then remove this section.
0.6.0 — Visual/audio pass and evening lighting preset (weeks 22–24)
Look and sound
- Create an evening lighting preset.
- Complete a visual polish pass across the neighborhood.
- Model the pavement between kerb and building line; today that strip is the terrain mesh, which reads as bare ground under the shopfronts (
Screenshots/README.md). Carried over 2026-11-09. - Add ambient audio (city ambience, traffic, basic SFX).
- Verify licenses for all added audio files.
Release checks
- Both day and evening presets render without defects.
- Audio plays without gaps or licensing issues.
- Performance target re-validated at 1440p.
- Tag
v0.6.0and writeCHANGELOG.mdentry; then remove this section.
0.6.1 — Lighting fixes (patch)
Patch tasks
- Fix lighting defects in day/evening presets.
- Tag
v0.6.1and writeCHANGELOG.mdentry; then remove this section.
0.6.2 — Material corrections (patch)
Patch tasks
- Fix material errors found in
0.6.x. - Tag
v0.6.2and writeCHANGELOG.mdentry; then remove this section.
0.6.3 — Audio balancing (patch)
Patch tasks
- Balance audio levels across the scene.
- Tag
v0.6.3and writeCHANGELOG.mdentry; then remove this section.
0.7.0 — Settings, control rebinding, save/load, accessibility (weeks 25–27)
Systems
- Build settings menu (graphics and audio options).
- Implement control rebinding with persistence.
- Implement save/load for player state.
- Add accessibility basics (e.g. FOV, subtitle, colorblind options as applicable).
Release checks
- Settings, rebinding, and save/load all persist across restarts.
- No blocking UI defects.
- Tag
v0.7.0and writeCHANGELOG.mdentry; then remove this section.
0.7.1 — Save fixes (patch)
Patch tasks
- Fix save/load defects.
- Tag
v0.7.1and writeCHANGELOG.mdentry; then remove this section.
0.7.2 — UI fixes (patch)
Patch tasks
- Fix UI issues in
0.7.x. - Tag
v0.7.2and writeCHANGELOG.mdentry; then remove this section.
0.7.3 — Input persistence fixes (patch)
Patch tasks
- Fix rebinding persistence issues.
- Tag
v0.7.3and writeCHANGELOG.mdentry; then remove this section.
0.8.0 — Performance budgets and broader Linux hardware testing (weeks 28–30)
Performance
- Define performance budgets (frame time, VRAM) and document them.
- Profile the full neighborhood; fix budget violations.
- Test on broader Linux hardware and VRAM configurations; document results.
- Re-validate the 1440p quality preset with upscaling state recorded.
Release checks
- Performance budgets met on documented hardware matrix.
- No blocking compatibility defects.
- Tag
v0.8.0and writeCHANGELOG.mdentry; then remove this section.
0.8.1 — VRAM reductions (patch)
Patch tasks
- Reduce VRAM usage where profiling shows excess.
- Tag
v0.8.1and writeCHANGELOG.mdentry; then remove this section.
0.8.2 — Frame-time fixes (patch)
Patch tasks
- Fix frame-time spikes found in
0.8.x. - Tag
v0.8.2and writeCHANGELOG.mdentry; then remove this section.
0.8.3 — Compatibility fixes (patch)
Patch tasks
- Fix compatibility issues from the hardware testing matrix.
- Tag
v0.8.3and writeCHANGELOG.mdentry; then remove this section.
0.9.0 — Realistic buildings (weeks 31–34)
Suggested blender skills: archviz (real-world scale, façade composition, elevation read), references (reference-image-match and visual-match checklists — every building is judged against its own photograph), procedural-modeling + geometry-nodes (the façades system: bay module, cornice and coping profiles, storefront types as reusable node groups), materials (measured albedo and roughness per surface type), texture-workflow (baked AO/curvature/normal, decals for painted lettering and signs), uv-workflow (texel density and modular UVs), lod-pipeline (LOD chain per building), collision-proxy (UCX proxies so detail geometry is not the collider), lookdev (screenshot comparison loop), camera-cinematography (reproducing each building's reference angle), asset-optimization + unreal-export (pre-export validation, ue_metric_v1), qa-review (the gate before every review shot).
Façade system
- Extend the module kit beyond one order. Art Deco, neoclassical and streamline-moderne variants on the shared 4.96 m bay: alternate window proportions, spandrel and transom bands, and the way each order terminates at the roof.
- Build a profile library for cornices, copings, string courses, sills and storefront surrounds, so a building is assembled from named profiles rather than ad-hoc boxes.
- Storefront types: recessed entry, bulkhead and kickplate, mullion spacing, transom, awning/canopy brackets, and grille/shutter variants.
- Signage and lettering as decals. Painted wall lettering, blade signs and fascia panels become texture and decal work with a documented projection;
0.1.6proved that lettering built as geometry plates cannot resolve at review distance. - Document the system in
Art/blender/README.mdand the arc42 building block view.
Per-building models
Each building needs its own reference set; where none exists the blockout stays and the item says so.
- Hero façade (6840): raise to this pass's detail level — volute capital depth and lattice grille depth (both deferred from the 2026-11-10 hero rework, which closed the inscription/medallions/motto-band/banner surface), window rhythm behind the colonnade, and the heavy banded rustication the elevation still lacks. The motto band, medallions and banner lettering are already done and carry over.
- Hero façade (6840), entrance: doors at street level left and right of the central bay, as the photographs show, and correct positioning of the central-bay elements (column bases, entrance stairs, set-back entrance, door frames, banners and signage). Nothing may stand in front of the façade that blocks it — no awning, no temporary structure. Carried over from
Screenshots/README.md, 2026-11-09. - El Capitan Theatre (6838): marquee, blade sign, entrance and the theatre's own elevation from its 18-frame set.
- 6800 Lee Drug and 6806–6820: second pass on the
0.1.6trim. Moved here from that patch because geometry cannot close them: wall lettering as a decal (a plate at 0.10 m still vanishes at 40 m), a moulded parapet profile instead of a two-tier box, richer corner-tower stepping, and the portrait panels reworked as textures rather than framed plates. - Photography gap — 6822 Budget (deferred out of
0.1.6, blocked): no photograph exists; the single-storey 6.0 × 5.5 m volume cannot be read from the neighbour shot, so it stays a bare blockout until references are acquired. Record the sources checked inGeo/. Also re-shoot 6806–6820 and 6800 from the south sidewalk: the only reference is one oblique with a bus across Lee Drug's shopfront and a car across 6806's. - 6902, 6922 and the remaining south frontage.
- North side: TCL Chinese Theatre and Madame Tussaud's façades from their reference sets.
- Reconcile every modelled height against
Geo/tools/block_height_report.pyand record the source per building.
Materials, UVs and performance
- Measured material library, including the hero's stone, which currently renders pale because it is a procedural graph and a generated texture set rather than a measured surface: stucco, painted render, ashlar, brick, terrazzo, glazing, bronze and steel trim, with albedo and roughness taken from the photographs rather than guessed; one Unreal material instance per surface type.
- Texel-density rule per building class, applied through modular UVs; lightmap UVs where required.
- LOD chain and collision proxies per building: UCX proxies for blocking volume, detail geometry non-colliding.
- Re-validate the 60 FPS floor at 1440p once the detail lands, and record the cost of the pass.
Release checks
- Every building with a photograph has a review shot measured against it, with silhouette and proportion deltas recorded in
Screenshots/README.md. - No building carries an unverified façade; blockouts without references are listed as such in
TODO.md. - Every building has a collision proxy and at least one LOD.
- No surface left on a placeholder material.
THIRD_PARTY_NOTICES.mdcovers every photographic reference used in this pass.- Performance target still met at 1440p.
- Tag
v0.9.0and writeCHANGELOG.mdentry; then remove this section.
0.10.0 — Feature freeze, public beta, license and build audit (weeks 35–38)
Freeze and audit
- Freeze features; document the freeze in
CHANGELOG.md. - Produce a public beta build for testers.
- Complete license audit:
THIRD_PARTY_NOTICES.md, all MPFB assets, textures, animations, vehicles, audio. - Review Epic distribution requirements before publishing.
- Verify a fresh checkout builds and packages reproducibly.
Release checks
- Beta feedback triaged; blockers logged for
0.10.x. - Tag
v0.10.0and writeCHANGELOG.mdentry; then remove this section.
0.10.1 — Blocker fixes (patch)
Patch tasks
- Fix blockers reported during the public beta.
- Tag
v0.10.1and writeCHANGELOG.mdentry; then remove this section.
0.10.2 — Regression fixes (patch)
Patch tasks
- Fix regressions introduced by
0.9.xfixes. - Tag
v0.10.2and writeCHANGELOG.mdentry; then remove this section.
0.10.3 — Documentation fixes (patch)
Patch tasks
- Update all
Docs/for accuracy before1.0.0. - Tag
v0.10.3and writeCHANGELOG.mdentry; then remove this section.
1.0.0 — Stable neighborhood-scale walking/driving release (weeks 35–40)
Final release
- Complete final acceptance sweep across all
0.xfeatures. - Confirm the stable, agreed game scope is met (neighborhood-scale walking and driving).
- Final build, documentation, and licensing verification.
- Tag
v1.0.0and writeCHANGELOG.mdentry; then remove this section.