Skip to content

fix(examples): redesign export-preset-axis as a banded radio mast with measured axis gizmos - #262

Merged
TMHSDigital merged 2 commits into
mainfrom
fix/hero-export-preset-axis
Sep 26, 2026
Merged

TMHSDigital merged 2 commits into
mainfrom
fix/hero-export-preset-axis

Conversation

@TMHSDigital

Copy link
Copy Markdown
Owner

What and why

The review picked out this hero as weak: dim olive on grey with very low contrast, a thin undesigned pole with a box, and a Godot copy lying on its side that looked like it had "fell over" instead of showing an axis convention. This PR redesigns both the subject and the composition. The check contract is unchanged.

  • Subject: a modelled radio mast where "up" is obvious. It has a stepped, chamfered concrete footing, a bolted flange, a tapered mast in red/white aviation bands with steel collars, three sector panel antennas, a shrouded microwave dish on a raked arm, an equipment cabinet, and a red obstruction lamp under a lightning rod. The rod's point is the witnessed TIP vertex. It uses 8 named materials.
  • Axis story: each re-import has a modelled X/Y/Z gizmo (red/green/blue arrows). The gizmo is measured, not placed. The render path tries all 24 axis-aligned rotations and keeps the one that maps the source vertices onto the re-imported vertices, then prints fit_err. It exits 12 if the error is above 1 mm. Unity comes out as identity, so blue Z points up. Godot comes out as Y->+Z, Z->-Y, so green Y points up and blue Z runs along the lying mast. The render now reads as "this file's Y is up" and not as a fallen prop.
  • Camera now looks along +X, so the lying mast shows its full length instead of pointing at the lens. The light rig is rotated to match, with the wedge raking the back wall.
  • The render path now also runs gallery_asset_quality (exit 11).
  • scripts/asset_sheet.py gets a RadioMast.Unity selector row.

Before: the old hero (olive pole and box). After: docs/gallery/assets/export-preset-axis-hero.webp.

Gates (5.2.1)

  • Framing: fill x=0.713, y=0.794 (band 0.70–0.90). Margins: left 0.034, right 0.053, bottom 0.044, top 0.044 (floor 0.02). framing_ok.

  • Asset quality: no default names, 8 materials, edge90 0.000. aq_ok.

  • Contact sheet: docs/gallery/contact-sheets/export-preset-axis-contact-sheet.webp

    tile luma stage warmth sat
    export-preset-axis (candidate) 0.2603 0.2310 -0.0147 0.1378
    armature-bend 0.2787 0.2132 -0.4279 0.1436
    damped-track-aim 0.1511 0.1448 +0.2772 0.2305
    bmesh-gear 0.2358 0.1772 +0.3027 0.2495

    Verdicts:

    • Stage darkness: pass. Luma 0.260 is inside the calibration range 0.151–0.279. The stage is a little lighter than bmesh-gear.
    • Wedge warmth: pass. A warm pool sits on the back wall. Warmth is between armature-bend and the warm references.
    • Subject fill: pass, as measured above.
    • Saturation: pass, at the low end (0.138 vs 0.144–0.250). The red bands and RGB gizmos carry the color.
    • Thumbnail legibility: pass. At 427x240 you can read one standing mast with blue up and one lying mast with green up.
  • Asset sheet: docs/gallery/asset-sheets/export-preset-axis.webp was rendered against the reference set on main after chore(gates): raise the asset-sheet reference bar and commit its renderer #257: hydrant, survey drone, stone well, wheelbarrow, apothecary shelf. Verdict: narrow pass. The mast has more modelled fixtures than the hydrant (flange bolts, collars, panels on brackets, dish, cabinet with hood and handle, lamp, rod). It is not the least-designed object in the lineup. Its tall aspect does render it small in a 16:9 panel, and it has no surface wear, so it sits in the lower half of this lineup, not the top.

  • Hero drift: measure_hero_drift.py --only export-preset-axis reports mean_abs 0.00322, gt2pct 0.95%, verdict matches.

Check runs (check-only path via tests/smoke/run_example.py, plus --same-axis)

binary reports check --same-axis --output render
.scratch/blender-5.2.1-windows-x64/blender.exe Blender 5.2.1 LTS PASS (tip err 2.4e-07) exit 9 exit 0
.scratch/blender-5.1.2-windows-x64/blender.exe Blender 5.1.2 PASS exit 9 exit 0
.scratch/blender-4.5.11-windows-x64/blender.exe Blender 4.5.11 LTS PASS exit 9 exit 0

Falsifiers

  • Existing contract: --same-axis exits 9 on all three binaries (ERROR: orientations did not differ).
  • New render-path guard (exit 12): a scratch probe pre-multiplied the Godot re-import's matrix_world by a 10° Z rotation before rendering. The best axis-aligned fit rose to 4.288e-01, and the script exited 12 with ERROR: no axis-aligned rotation maps the source onto the Godot re-import. Restored; the unmodified run gives fit_err 0.000e+00 for both.

Proven by live run vs by inspection only

  • Proven by live run: check PASS and --same-axis exit 9 on 5.2.1, 5.1.2 and 4.5.11. Render path exit 0 with framing_ok and aq_ok on all three. The exit-12 falsifier on 5.2.1. render_hero.py, contact_sheet.py, asset_sheet.py and measure_hero_drift.py on 5.2.1. build_gallery.py, with the generated <img alt> checked in docs/gallery/index.html and docs/gallery/export-preset-axis/index.html.
  • By inspection only: the visual verdicts (contact sheet and asset sheet), and CI results on the floating 4.5.x point release.

Exit code 11 now means two things: --same-axis did not collapse the difference (check path, --same-axis only), and the asset-quality floor (render path only). The two paths never overlap, and the README documents both.

🤖 Generated with Claude Code

TMHSDigital and others added 2 commits September 25, 2026 20:14
…h measured axis gizmos

The review judged the hero weak: dim olive-on-grey, a thin undesigned pole
with a box, and the Godot copy lying sideways read as "fell over" rather
than as an axis convention.

- The source is now a modelled radio mast: stepped chamfered concrete
  footing, bolted flange, tapered mast in red/white aviation bands with
  steel collars, three sector panels, a shrouded microwave dish on a raked
  arm, an equipment cabinet, and a red obstruction lamp under a lightning
  rod whose point is the witnessed tip vertex. Eight materials.
- Each re-import gets a modelled X/Y/Z gizmo. The frame is measured, not
  placed: the render path picks the axis-aligned rotation mapping source
  vertices onto the re-import (fit_err printed; exit 12 above 1 mm). Unity
  shows blue Z up; Godot shows green Y up and blue Z along the lying mast.
- The camera looks along +X so the lying mast shows its full length.
- The render path now runs gallery_asset_quality (exit 11).

The check contract is unchanged; the same checks pass on 4.5.11, 5.1.2
and 5.2.1, and --same-axis still exits 9.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Signed-off-by: TMHSDigital <[email protected]>
…ence set

Adds the RadioMast.Unity selector to scripts/asset_sheet.py and regenerates
the asset sheet and contact sheet after rebasing onto the new reference set
(#257) and the new bmesh-gear calibration hero (#258).

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Signed-off-by: TMHSDigital <[email protected]>
@github-actions github-actions Bot added examples Runnable smoke-gated examples under examples/ documentation Improvements or additions to documentation labels Sep 26, 2026
@TMHSDigital
TMHSDigital merged commit 25108f6 into main Sep 26, 2026
11 checks passed
@TMHSDigital
TMHSDigital deleted the fix/hero-export-preset-axis branch September 26, 2026 23:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation examples Runnable smoke-gated examples under examples/

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant