Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .cursor-plugin/plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@
"examples/shader-node-group",
"examples/shape-key-blend",
"examples/sky-texture-sun-elevation",
"examples/soccer-ball-goldberg",
"examples/swatch-grid",
"examples/temp-override-join",
"examples/text-version-stamp",
Expand Down
13 changes: 13 additions & 0 deletions .github/workflows/blender-smoke.yml
Original file line number Diff line number Diff line change
Expand Up @@ -516,3 +516,16 @@ jobs:
# on failure.
xvfb-run -a "$BLENDER" --background \
--python examples/prop-origin-transform/prop_origin_transform.py --

- name: Shipped example - soccer ball Goldberg (polyhedron invariants + panel binding)
run: |
set -euo pipefail
# Check only (no render): a bmesh icosphere truncated at 1/3 per edge
# into the Goldberg polyhedron; asserts closed-form counts (60/90/32,
# Euler 2), 12-pentagon/20-hexagon census, uniform degree 3,
# watertightness, edge-length uniformity, face planarity vs an
# independent Newell normal, centroid-at-origin circumsphere, and
# panel materials bound by face vertex count. Exits non-zero on
# failure.
xvfb-run -a "$BLENDER" --background \
--python examples/soccer-ball-goldberg/soccer_ball_goldberg.py --
24 changes: 22 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
</p>

<p align="center">
<strong>12 skills</strong> &nbsp;&bull;&nbsp; <strong>6 rules</strong> &nbsp;&bull;&nbsp; <strong>2 templates</strong> &nbsp;&bull;&nbsp; <strong>17 snippets</strong> &nbsp;&bull;&nbsp; <strong>36 examples</strong>
<strong>12 skills</strong> &nbsp;&bull;&nbsp; <strong>6 rules</strong> &nbsp;&bull;&nbsp; <strong>2 templates</strong> &nbsp;&bull;&nbsp; <strong>17 snippets</strong> &nbsp;&bull;&nbsp; <strong>37 examples</strong>
</p>

<p align="center">
Expand All @@ -36,7 +36,7 @@

## Overview

This repository ships **12 skills, 6 rules, 2 templates, 17 snippets, and 36 runnable examples** for Blender Python development targeting Blender 5.1 (current stable) with Blender 4.5 LTS fallback support.
This repository ships **12 skills, 6 rules, 2 templates, 17 snippets, and 37 runnable examples** for Blender Python development targeting Blender 5.1 (current stable) with Blender 4.5 LTS fallback support.

The content is consumed by AI coding agents (Cursor, Claude Code, any MCP-capable client) when working on Blender add-ons, geometry nodes scripts, batch pipelines, or animation tooling. There is no build step. Edit the markdown and Python files directly.

Expand Down Expand Up @@ -700,6 +700,26 @@ Extends [`parent-inverse-orrery`](examples/parent-inverse-orrery/) without
retreading orbits. Dual-panel still: TRAP (bare parent — empty socket +
teleported flange) vs MPI KEEP.

</td>
</tr>
<tr>
<td width="46%" valign="middle">
<a href="examples/soccer-ball-goldberg/"><img src="examples/soccer-ball-goldberg/preview.webp" alt="Soccer ball Goldberg: a white soccer ball with black pentagon panels on a dark studio floor — a bmesh icosphere truncated at one-third per edge into the Goldberg polyhedron, proving closed-form counts, uniform degree, equal edges, planar faces, one circumsphere, and panels bound by face vertex count" /></a>
</td>
<td valign="middle">

### [soccer-ball-goldberg](examples/soccer-ball-goldberg/)

The truncated icosahedron as a bmesh contract: every icosphere edge cut at
exactly `1/3`, faces ordered by link-topology walks (nothing hand-listed),
and every invariant asserted as a closed form — `60/90/32`, Euler 2, uniform
degree 3, edge lengths within 3e-5, planar faces against an independent
Newell normal, one circumsphere, and the black pentagons / white hexagons
bound by face vertex count, never enumeration order. Sibling to
[`bmesh-gear`](examples/bmesh-gear/) (parametric extrusion): this one
witnesses polyhedral invariants plus per-face-class material binding. The
smoothed render inverts on sight if the panel binding does.

</td>
</tr>
</table>
Expand Down
5 changes: 5 additions & 0 deletions ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,11 @@ Not committed; target list for the next content version. (v0.3.0 shipped the smo
- Volumetric scatter optical-depth witness: Volume Scatter density → Beer–Lambert transmittance along a known path (Cycles; Stage deviation)
- Freestyle SVG / line-set witness: Freestyle line set on a silhouette (full render pass; prefer Line Art first)
- ~~prop-origin-transform witness~~ **SHIPPED** as `examples/prop-origin-transform/` — origin to base center + data-API scale apply + `matrix_parent_inverse` for a bolted accessory; scale `(1,1,1)`, local `min.z==0`, world AABB delta 0, bare jump ~0.43 m, MPI err ~3e-8; stale `matrix_world` until `view_layer.update()`; byte-identical on 4.5.11 and 5.1.2
- ~~Goldberg polyhedron topology witness~~ **SHIPPED** as `examples/soccer-ball-goldberg/` — soccer ball as a truncated icosahedron: bmesh icosphere cut at 1/3 per edge, faces ordered by link-topology walks; closed forms 60/90/32 + Euler 2, census 12×5+20×6, uniform degree 3, edge dev 6.5e-06, planarity 1.9e-06 (independent Newell normal), circumsphere dev 9.0e-06, panels bound by face vertex count (enumeration-order probes exit 13); float32 noise floor ~9e-6 → 3e-5 gates; byte-identical on 4.5.11 and 5.1.2
- Mirror-modifier symmetry witness: half-model completed by Mirror evaluated through the depsgraph — evaluated-vs-original counts (2n − welded centerline), exact ±X partner for every evaluated vertex, merge-threshold weld proof, failure dramatically visible (half a subject / split seam). Strongest subject: a generic vehicle body
- Chess-piece lathe witness: a turned piece (rook/pawn) via Screw modifier or bmesh spin from an authored profile — evaluated verts == profile × steps (minus pole merges), ring radii match the profile closed form, axis of revolution exact
- Dice-pair per-face witness: material/attribute assignment driven by face normal direction, opposite-faces-sum-to-7 as an independently computed invariant, pip placement from a closed-form lattice
- Bicycle-wheel radial witness: spokes via radial Array with object offset — exact angular spacing, spoke count, hub/rim concentricity, every evaluated spoke endpoint on its computed rim coordinate
- ~~mesh-hygiene-audit witness~~ **SHIPPED** as `examples/mesh-hygiene-audit/` — engine-ingest topology checklist on a stepped street electrical pedestal: no ngons, no loose verts, manifold edges (exactly 2 faces), no zero-area faces (`min_area` printed), positive signed volume, Euler `V−E+F==2` (24/44/22, volume 0.989248); byte-identical on 4.5.11 and 5.1.2; dual-panel dirty vs clean still
- UV atlas pack witness — lightmap/unique UV island packing with non-overlap + utilization closed forms (deferred behind hygiene/origin; overlaps `uv-layer-grid` / `triangulate-tangents` / `gltf-export-roundtrip` UV arc)
- Attribute domain witness: writing a POINT-domain color attribute and reading it as if it were CORNER (or vice versa) silently shears colors across shared verts — companion to `color-attribute-wheel`
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 11 additions & 0 deletions docs/gallery/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -609,6 +609,17 @@ <h2><a href="prop-origin-transform/">prop-origin-transform</a></h2>
<a class="card-link" href="prop-origin-transform/">View example <span aria-hidden="true">&rarr;</span></a>
</div>
</article>
<article class="card" data-tags="bmesh mesh">
<a class="card-media" href="soccer-ball-goldberg/" aria-label="soccer-ball-goldberg example detail page">
<img src="assets/soccer-ball-goldberg-hero.webp" alt="soccer-ball-goldberg — A soccer ball as a Goldberg polyhedron: a bmesh icosphere truncated at 1/3 per edge, faces ordered by link-topology walks, panels bound by face vertex count." loading="lazy" decoding="async" />
</a>
<div class="card-body">
<h2><a href="soccer-ball-goldberg/">soccer-ball-goldberg</a></h2>
<p class="teaches">A soccer ball as a Goldberg polyhedron: a bmesh icosphere truncated at 1/3 per edge, faces ordered by link-topology walks, panels bound by face vertex count.</p>
<p class="witnesses"><span class="tag">witnesses</span> Goldberg invariants are closed forms — counts, degree 3, uniform edges, planar faces, one circumsphere — and panels bind by vertex count, never enumeration order.</p>
<a class="card-link" href="soccer-ball-goldberg/">View example <span aria-hidden="true">&rarr;</span></a>
</div>
</article>
</div>
</main>
<footer>
Expand Down
2 changes: 1 addition & 1 deletion docs/gallery/prop-origin-transform/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ <h1>prop-origin-transform</h1>
<ul><li><strong>Stale <code>matrix_world</code>.</strong> After a location edit, <code>matrix_world</code> is unchanged until <code>view_layer.update()</code> (same half of the orrery contract).</li><li><strong>Scale apply via data API.</strong> Non-uniform scale baked into verts; <code>obj.scale == (1,1,1)</code> exactly afterward.</li><li><strong>Origin at base center.</strong> Local bbox <code>min.z == 0</code>, XY centered; world AABB delta across the bake is <strong>0</strong> (gate <code>1e-5</code>).</li><li><strong>Bare-parent trap.</strong> Parenting the accessory without MPI jumps it (~0.43 m measured); setting <code>matrix_parent_inverse</code> restores world location (err ~3e-8).</li></ul>
<p><strong>What each check catches on failure:</strong> skipping scale apply leaves non-identity scale; skipping origin bake leaves <code>min.z ≈ -0.756</code>; skipping MPI leaves the accessory teleported.</p>
<p><strong>Version witness:</strong> byte-identical numbers on Blender 4.5.11 LTS and 5.1.2.</p>
<p>The render is a dual panel: left <strong>TRAP</strong> (bare parent — accessory teleports, hazard material) vs right <strong>MPI KEEP</strong> (accessory stays put), with emissive origin markers at each pedestal&#x27;s base.</p>
<p>The render is a dual panel: left <strong>TRAP</strong> (bare parent — flanged conduit teleports off an empty mount socket, hazard material) vs right <strong>MPI KEEP</strong> (flange seated in the socket), with emissive origin markers at each pedestal&#x27;s base. Check closed forms are unchanged; the flange/socket are render form only.</p>
<h2>Run</h2>
<pre><code>blender --background --python prop_origin_transform.py --
blender --background --python prop_origin_transform.py -- --output origin.png
Expand Down
Loading
Loading