feat: add car-mirror-symmetry example#105
Merged
Merged
Conversation
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds
examples/car-mirror-symmetry/— a generic hatchback built as onehalf (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(reportsBlender 5.1.2) and.scratch/blender-4.5.11-windows-x64/blender.exe(reportsBlender 4.5.11 LTS). Output byte-identical on both:Falsification evidence (live runs)
use_mirror_merge = FalseDesign note (in README): mutating a non-plane base vertex cannot break the
±X pairing —
half ∪ mirror(half)is symmetric by construction — so thecheck 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) glassrule 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_pathspasses. The twonew 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.
half ∪ mirror(half)) — falsification must target the modifier.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 documentedimg.save(filepath=..., quality=85)path silently writes PNG bytes on these builds) ·
examples/gallery.json·.cursor-plugin/plugin.json·blender-smoke.ymlstep · README counts37→38 + gallery row · ROADMAP pool drained (mirror-symmetry shipped; chess,
dice, bicycle directions remain) · gallery regenerated (
38 detail pages).Test plan
blender --background --python examples/car-mirror-symmetry/car_mirror_symmetry.py --→ exit 0(live-run locally on both, values above).
cms_draft9*.png).blender-smokematrix jobs (4.5, 5.1) must pass on this PR head.Live-run vs inspection-only
both renders, webp conversion + magic-byte verification, gallery build,
Playwright captures, contact-sheet luminance.
Pages deploy (path-filtered, post-merge).