Skip to content

feat: add car-mirror-symmetry example#105

Merged
TMHSDigital merged 1 commit into
mainfrom
feat/example-car-mirror-symmetry
Jul 22, 2026
Merged

feat: add car-mirror-symmetry example#105
TMHSDigital merged 1 commit into
mainfrom
feat/example-car-mirror-symmetry

Conversation

@TMHSDigital

Copy link
Copy Markdown
Owner

Summary

Adds examples/car-mirror-symmetry/ — a generic hatchback built as one
half
(a loft of 14 stations × 9-point half-rings from bottom centerline to
roof centerline) and completed by a Mirror modifier, evaluated through
the depsgraph. Wheels and lamps are separate objects mirrored the idiomatic
way: object origin parked on the symmetry plane, mesh data offset —
mirror mirrors about the object origin, so you offset the data, never the
object. The recognizable object is the contract: a car is the thing
everyone knows is bilaterally symmetric, and its failure is unmissable.

Contract witnessed

Original datablock keeps only the authored half; the depsgraph carries the
mirrored, welded whole. Closed forms, exit non-zero on failure: half
126/231/106 with 28 centerline verts · evaluated exactly 2n − c = 224
(434 edges / 212 faces), watertight, Euler 2 · every evaluated vertex
has an exact negated-X partner · bbox min.x == −max.x · wheels (96/81 →
192/162) and lamps (8/6 → 16/12) double across the plane with origins at
x == 0.

Measured check values (live runs, both binaries)

Binaries: .scratch/blender-5.1.2-windows-x64/blender.exe (reports Blender 5.1.2) and .scratch/blender-4.5.11-windows-x64/blender.exe (reports
Blender 4.5.11 LTS). Output byte-identical on both:

  • body half=126/231/106, centerline=28 · eval=224/434/212, euler=2, manifold
  • sym_dev 0.000e+00 (tol 2.0e-05), bbox_asym 0.000e+00
  • all four mirrored parts sym_dev 0.000e+00, evaluated spans both sides

Falsification evidence (live runs)

Probe Exit Measured
use_mirror_merge = False 5 evaluated 252 ≠ 224 (doubled seam) — 5.1.2 and 4.5.11 identical
one centerline vert pulled off plane 4 27 ≠ 28 welded
mirror axis disabled 5 126 ≠ 224 — the half-car
modifier applied into data 3 datablock (224, 434, 212) ≠ (126, 231, 106)

Design note (in README): mutating a non-plane base vertex cannot break the
±X pairing — half ∪ mirror(half) is symmetric by construction — so the
check set targets the modifier, which is where realistic failures live.

Render / visual-pass log

Hero: candy-red dielectric-glass hatchback, default stage per
docs/VISUAL-STYLE.md (no deviation). 9 draft iterations: (1) glass
rule swallowed pillars → window band only; (2) headlamp strip painted the
nose white → lamps as separate mirrored boxes; (3) lamps floated → embedded
in the bumper band, bumper trim narrowed to the lower half; (4–6) windshield
rendered as a hot salmon slab — diagnosed as the paint-only center strips
(k=6/7) of the windshield slope catching the key, not the glass: the glass
rule now assigns the full windshield/rear-window slopes (steepest roof
rise/drop pairs) and the glass is dielectric, not metallic; (7) camera
stance. Pass 1 crops: no clipped highlights (windshield sheen ~0.75,
headlamps small and bright by design), lamps flush, contact shadow grounded.
Pass 2 falsification pair: mirror disabled renders half a car — halved
windshield/hood, one headlamp — wrong on sight. Pass 3: card webp reads as a
car in under a second; distinct from the soccer-ball card (subject, palette,
camera).

Contact sheet:
docs/gallery/contact-sheets/car-mirror-symmetry-contact-sheet.webp
(candidate TL; armature-bend TR; damped-track-aim BL; bmesh-gear BR).
Verdicts: stage darkness match ✓ · wedge warmth within family range ✓ ·
subject fill comparable ✓ · saturation: deep candy red, holds the lineup ✓ ·
thumbnail legibility ✓. Mean luminance 0.1372 vs set 0.2787 / 0.1722 /
0.3048 — darkest of the four, attributable to subject albedo (dark red
paint, black glass/tires), not underexposure: paint highlights and
windshield sit at full exposure without clipping. Same stage, same wedge —
not sortable as the odd one out.

Pass 4 (Playwright, live local server)

Card captured in situ at desktop (1280px) and ~390px mobile widths, plus the
detail page: image fills card media at both widths, teaches/WITNESSES copy
complete, car recognizable at both sizes. Generated HTML read
character-by-character: alt complete under the generator's 160-char cap
(first sentence sized to fit), no truncation, no markdown artifacts,
Unicode (∪, ±, −) intact, assert_alts_survive_dotted_paths passes. The two
new cards (this + soccer-ball-goldberg) sit side by side at the grid's end
and read as distinct works.

Hazards found while authoring (in code comments + README)

  • Object.to_mesh_clear() takes no argument on current Blender
    (5.1.2 and 4.5.11) — passing the mesh raises TypeError.
  • A base-mesh mutation cannot falsify mirror symmetry (always
    half ∪ mirror(half)) — falsification must target the modifier.
  • Metallic glass mirrors the key light: the windshield renders as a hot
    salmon slab even though the material is "dark". Dielectric glass is the
    studio look.

Integration

Example dir + README + preview webp (1200×675) · hero webp (1280×720, true
RIFF via save_render — the documented img.save(filepath=..., quality=85)
path silently writes PNG bytes on these builds) · examples/gallery.json ·
.cursor-plugin/plugin.json · blender-smoke.yml step · README counts
37→38 + gallery row · ROADMAP pool drained (mirror-symmetry shipped; chess,
dice, bicycle directions remain) · gallery regenerated (38 detail pages).

Test plan

  • Check-only, both binaries above: blender --background --python examples/car-mirror-symmetry/car_mirror_symmetry.py -- → exit 0
    (live-run locally on both, values above).
  • Render path: exercised locally on 5.1.2 and 4.5.11 (EEVEE stills,
    cms_draft9*.png).
  • CI: both blender-smoke matrix jobs (4.5, 5.1) must pass on this PR head.

Live-run vs inspection-only

  • Live run: all checks (both binaries), all four falsification probes,
    both renders, webp conversion + magic-byte verification, gallery build,
    Playwright captures, contact-sheet luminance.
  • Inspection only: CI runner behavior of the new smoke step; GitHub
    Pages deploy (path-filtered, post-merge).

Witness the Mirror + depsgraph contract on a subject whose failure is
unmissable: a generic hatchback lofted as one half (14 stations, 9-point
rings) and completed by the Mirror modifier. Closed forms assert the
datablock keeps only the authored half (126/231/106, 28 centerline verts)
while the evaluated mesh is exactly 2n-c (224/434/212), watertight with
Euler 2, every evaluated vertex paired at negated X with zero deviation.
Wheels and lamps mirror about object origins parked on the symmetry plane —
offset the data, never the object. Hide the mirror and the render is
literally half a car.

Signed-off-by: fOuttaMyPaint <TMhospitalitystrategies@gmail.com>
@github-actions github-actions Bot added documentation Improvements or additions to documentation ci labels Jul 22, 2026
@TMHSDigital
TMHSDigital merged commit 9bbdd11 into main Jul 22, 2026
9 checks passed
@TMHSDigital
TMHSDigital deleted the feat/example-car-mirror-symmetry branch July 22, 2026 19:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci documentation Improvements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant