Skip to content

Commit 6ea4ed9

Browse files
TMHSDigitalclaude
andauthored
feat(examples): add solidify-even-thickness and boolean-exact-volume (#305)
solidify-even-thickness: a strip folded at 60, 90 and 120 degrees, solidified in Simple mode (offset -1, t = 0.16). - Without use_even_offset, each fold vertex's copy moves t along the bisector of its face normals, so the shell is t*cos(phi/2) thick: 0.1386, 0.1131 and 0.0800. - With use_even_offset, the copy moves t/cos(phi/2) and the shell is exactly t thick. - Both closed forms are derived from the profile geometry and match to 3.7e-8. Exits: 4 even shell, 5 plain-shell closed form, 6 thinning floor. - --no-even exits 4 (0.0800 against 0.1600). - The ROADMAP candidate's "1/cos(theta/2)" was imprecise; the shipped line states the cos(phi/2) factor on the bend angle. boolean-exact-volume: the Boolean modifier's EXACT solver on a 2 m cube and a 2x1x1 m slab whose top face is coplanar with the cube's top. Both operands are translated and turned 18 degrees about Z. - Union, difference and intersection measure 9, 7 and 1 m^3 by the divergence theorem, to 1e-6 relative (exit 3). - Each result is a closed 2-manifold with no loose geometry (exit 4). - --float-solver exits 3 with a 7.708 m^3 union. - The floating-point solver is named 'FAST' on 4.5 and 'FLOAT' on 5.x, so the script branches on bpy.app.version. Both default runs exit 0 on Blender 4.5.11, 5.1.2 and 5.2.1. Both falsifiers are proven on 4.5.11 and 5.2.1 (boolean's also on 5.1.2). tests/smoke/run_example.py reports [PASS] for both on 5.2.1 and 4.5.11. Contact sheets are committed; every criterion passes for both. Signed-off-by: TMHSDigital <154358121+TMHSDigital@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
1 parent 9ac66bc commit 6ea4ed9

77 files changed

Lines changed: 3570 additions & 144 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.cursor-plugin/plugin.json‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,9 @@
138138
"examples/vse-linear-modifiers",
139139
"examples/wave-displace",
140140
"examples/ray-cast-space",
141-
"examples/lattice-deform"
141+
"examples/lattice-deform",
142+
"examples/solidify-even-thickness",
143+
"examples/boolean-exact-volume"
142144
],
143145
"showcase": [
144146
"showcase/shipping-crate",

‎AGENTS.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ a `.cursor-plugin/plugin.json` manifest so the ecosystem drift checker
2020
classifies it as a `cursor-plugin`. This is content the AI loads when the user
2121
asks Blender questions or works on Blender add-ons in Cursor or Claude Code.
2222

23-
The content base is 16 skills, 9 rules, 3 templates, 27 snippets, 62
23+
The content base is 16 skills, 9 rules, 3 templates, 27 snippets, 64
2424
examples, and 74 showcase pieces (counts are CI-enforced against README.md)
2525
and the manifest). The full inventory tables and per-item purposes live in
2626
`CLAUDE.md`. Example anatomy and authoring rules: copy `examples/bmesh-gear/`;
@@ -36,7 +36,7 @@ Blender-Developer-Tools/
3636
rules/<rule-name>.mdc # 9 rule files
3737
templates/<template-name>/ # 3 starter templates
3838
snippets/<snippet-name>.py # 27 standalone Python snippets
39-
examples/<name>/ # 62 runnable smoke-gated examples (+ gallery.json)
39+
examples/<name>/ # 64 runnable smoke-gated examples (+ gallery.json)
4040
examples/gallery_framing.py # shared Layer 1 framing measurement (render path only)
4141
showcase/<name>/ # budget-conformance props (sibling of examples/)
4242
showcase/gallery.json # this tree's gallery index; merged into docs/gallery/

‎CLAUDE.md‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ skills/<skill-name>/SKILL.md - AI workflow definitions, 16 total
2121
rules/<rule-name>.mdc - Anti-pattern rules, 9 total
2222
templates/<template-name>/ - Starter projects, 3 total
2323
snippets/<snippet-name>.py - Standalone code patterns, 27 total
24-
examples/<name>/ - Runnable smoke-gated examples, 62 total (+ gallery.json)
24+
examples/<name>/ - Runnable smoke-gated examples, 64 total (+ gallery.json)
2525
showcase/<name>/ - Budget-conformance props, 74 pieces, each with a gallery `category` (sibling of examples/; see showcase/README.md § Categories)
2626
scripts/build_gallery.py - Regenerates docs/gallery/ from examples/gallery.json + showcase/gallery.json
2727
scripts/site/ - Vendored landing-page build (Jinja2); tokens.css is the shared palette
@@ -105,12 +105,12 @@ v0.2.0: Principled BSDF material, driver-with-custom-function via `driver_namesp
105105

106106
AI asset pipeline track: `decimate_to_budget.py`, `convex_hull_collider.py`, `lod_chain.py` (helper duplicated, not imported), `gltf_draco_export.py`, `export_preset_unity.py`, `export_preset_godot.py`, `export_preset_unreal.py`, `setup_bake_target_image.py`, `bake_normal_high_to_low.py`, `save_baked_image.py`.
107107

108-
## Examples (62)
108+
## Examples (64)
109109

110110
Runnable scripts at `examples/<name>/`, each asserting a real API contract with
111111
deterministic checks (exit non-zero on failure) and optionally rendering a still via
112112
`--output`. All of them run headless on Blender 5.2 LTS and 4.5 LTS in `blender-smoke.yml` (5.1 on the weekly cron, the `needs-5.1` PR label, or manual dispatch);
113-
**54 of the 62 ship a render in the site gallery** at `docs/gallery/`. The other
113+
**56 of the 64 ship a render in the site gallery** at `docs/gallery/`. The other
114114
eight are **check-only**: they carry no `--output` path, no gallery entry, and no
115115
hero asset. The criterion is whether the contract is expressible in pixels. An
116116
example is check-only when its witness is a data or state fact that no scene

‎README.md‎

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
</p>
1919

2020
<p align="center">
21-
<strong>16 skills</strong> &nbsp;&bull;&nbsp; <strong>9 rules</strong> &nbsp;&bull;&nbsp; <strong>3 templates</strong> &nbsp;&bull;&nbsp; <strong>27 snippets</strong> &nbsp;&bull;&nbsp; <strong>62 examples</strong> &nbsp;&bull;&nbsp; <strong>74 showcase pieces</strong>
21+
<strong>16 skills</strong> &nbsp;&bull;&nbsp; <strong>9 rules</strong> &nbsp;&bull;&nbsp; <strong>3 templates</strong> &nbsp;&bull;&nbsp; <strong>27 snippets</strong> &nbsp;&bull;&nbsp; <strong>64 examples</strong> &nbsp;&bull;&nbsp; <strong>74 showcase pieces</strong>
2222
</p>
2323

2424
<p align="center">
@@ -37,7 +37,7 @@
3737

3838
## Overview
3939

40-
This repository ships **16 skills, 9 rules, 3 templates, 27 snippets, 62 examples, and 74 showcase pieces** for Blender Python development targeting Blender 5.2 LTS (current stable) with Blender 4.5 LTS fallback support. Blender 5.1 is prior stable.
40+
This repository ships **16 skills, 9 rules, 3 templates, 27 snippets, 64 examples, and 74 showcase pieces** for Blender Python development targeting Blender 5.2 LTS (current stable) with Blender 4.5 LTS fallback support. Blender 5.1 is prior stable.
4141

4242
The content is consumed by AI coding agents reading these files directly from a checkout — **there is no MCP server in this repository, and none is required**. Cursor applies `rules/*.mdc` automatically wherever their scope globs match and takes skills by name in chat; Claude Code reads `skills/` and `rules/` from the project workspace, or from this repo kept as a referenced checkout. Any agent that can read files in a workspace can use it the same way. There is no build step for the content — edit the Markdown and Python files directly.
4343

@@ -75,7 +75,7 @@ blender --background --python examples/bmesh-gear/bmesh_gear.py --
7575

7676
## Falsifiers
7777

78-
Every one of the 62 examples carries a **falsifier**: a flag that changes the
78+
Every one of the 64 examples carries a **falsifier**: a flag that changes the
7979
input so a real assertion fails. It never disables the assertion, skips the
8080
check, or short-circuits to an error — it feeds the script something the
8181
contract says must not pass, and the same check that guards the happy path
@@ -458,7 +458,7 @@ Gallery still is a sky-lit obelisk diptych (8° dusk | 55° midday) so the contr
458458
</details>
459459

460460
<details>
461-
<summary><strong>Mesh, curves &amp; text</strong> — 15 examples</summary>
461+
<summary><strong>Mesh, curves &amp; text</strong> — 17 examples</summary>
462462

463463
<table>
464464
<tr>
@@ -686,6 +686,36 @@ A 2×2×2 Lattice modifier set to `'KEY_LINEAR'`, with two corners moved through
686686
blend of the eight deformed corners, and that the default `'KEY_BSPLINE'` misses it
687687
(`--bspline` exits 4).
688688

689+
</td>
690+
</tr>
691+
<tr>
692+
<td width="46%" valign="middle">
693+
<a href="examples/solidify-even-thickness/"><img src="examples/solidify-even-thickness/preview.webp" alt="Solidify even thickness: two folded zigzag shells on a walnut plinth, their cut ends in orange, the left band pinching thin at every fold and the right staying one width, above brass plaques reading use_even_offset = False and use_even_offset = True" /></a>
694+
</td>
695+
<td valign="middle">
696+
697+
### [solidify-even-thickness](examples/solidify-even-thickness/)
698+
699+
Solidify on a strip folded at 60°, 90° and 120°. Without `use_even_offset`, each fold vertex
700+
moves *t* along the bisector and the wall thins to *t*·cos(φ/2), half at 120°. With it, the
701+
vertex moves *t*/cos(φ/2) and the wall stays exactly *t*. Both closed forms are measured off
702+
the evaluated mesh to 1e-5 (`--no-even` exits 4).
703+
704+
</td>
705+
</tr>
706+
<tr>
707+
<td width="46%" valign="middle">
708+
<a href="examples/boolean-exact-volume/"><img src="examples/boolean-exact-volume/preview.webp" alt="Boolean exact volume: three results on a walnut plinth, each inside thin steel and glowing orange outlines of its two operands - a teal union with a slab grown out of a cube, a brass cube with a notch cut down through its top, and the orange one-metre overlap cube, on a dark studio floor" /></a>
709+
</td>
710+
<td valign="middle">
711+
712+
### [boolean-exact-volume](examples/boolean-exact-volume/)
713+
714+
The Boolean modifier on `solver='EXACT'`, cutting a cube with a slab whose top face is
715+
coplanar with the cube's. Union, difference and intersection measure their closed-form
716+
9, 7 and 1 m³ by the divergence theorem and are closed 2-manifolds. The floating-point
717+
solver, renamed `'FAST'` → `'FLOAT'` in 5.0, gets the union wrong (`--float-solver` exits 3).
718+
689719
</td>
690720
</tr>
691721
</table>

‎ROADMAP.md‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,8 +167,9 @@ Not committed; target list for the next content version. (v0.3.0 shipped the smo
167167
- `mathutils.bvhtree` witness — `BVHTree.FromObject` on evaluated geometry: `find_nearest` distances and `overlap` pairs match closed forms on a known arrangement
168168
- Curves datablock witness — the modern `bpy.types.Curves` hair API (`add_curves`, `position` attribute, `curve_offset_data`) vs legacy particle hair: point and curve counts closed-form, every root on the emitter surface
169169
- Non-Color normal-map witness — an image used as a normal map must be `colorspace_settings.name = 'Non-Color'`; a baked/sampled value round-trips only then, and sRGB shifts it by the transfer curve (a silent shading error AI code ships)
170-
- Solidify even-thickness witness — `use_even_offset` keeps shell thickness constant at sharp corners, while without it the corner thins by 1/cos(θ/2): measured thickness at a known angle matches both closed forms
171-
- Boolean solver witness — EXACT solver union/difference volumes match closed forms on overlapping primitives, and the result is manifold; FAST on coplanar faces is the documented failure case
170+
- ~~Solidify even-thickness witness — `use_even_offset` keeps shell thickness constant at sharp corners, while without it the corner thins by 1/cos(θ/2): measured thickness at a known angle matches both closed forms~~ **SHIPPED** as `examples/solidify-even-thickness/` — Simple-mode Solidify (offset −1) on a strip folded at 60°/90°/120°: the even shell is exactly t thick (copies t/cos(φ/2) along the bisector), the plain shell t·cos(φ/2) = t·sin(θ/2) (0.866t, 0.707t, 0.5t), both to 3.7e-8; the candidate's "thins by 1/cos(θ/2)" was imprecise, since the factor is cos(φ/2) on the bend angle; `--no-even` exits 4
171+
- ~~Boolean solver witness — EXACT solver union/difference volumes match closed forms on overlapping primitives, and the result is manifold; FAST on coplanar faces is the documented failure case~~ **SHIPPED** as `examples/boolean-exact-volume/` — union/difference/intersection of a cube and a top-coplanar slab through translated, Z-turned operands: 9 / 7 / 1 m³ by the divergence theorem (1e-6 rel), closed 2-manifolds; the floating-point solver (`'FAST'` on 4.5, renamed `'FLOAT'` in 5.0) gives a 7.708 m³ union and `--float-solver` exits 3
172+
- MANIFOLD Boolean solver witness — the 4.5+ `'MANIFOLD'` solver against EXACT on the same closed-form operands: identical volumes with fewer faces (10 vs 14 on the fully coplanar union), plus its documented refusal of non-manifold input operands (result empty or unchanged) as the falsifier
172173
- ~~Lattice deform witness — a 2×2×2 lattice with one displaced point deforms interior verts by exact trilinear weights (`interpolation_type_u/v/w = 'KEY_LINEAR'`)~~ **SHIPPED** as `examples/lattice-deform/` — 602 evaluated verts on the trilinear closed form (5.6e-7) through a translated, non-uniformly scaled lattice; `--bspline` (the default interpolation) exits 4 at 0.2145
173174
- Lattice `use_outside` / outside-vertex witness — verts outside a KEY_LINEAR lattice's volume: assert the documented clamp or extrapolation closed form, and `use_outside` (deform only the outer points) against an interior-only control move
174175
- FBX unit-scale witness — `export_scene.fbx` with `apply_unit_scale` / `apply_scale_options` changes exported coordinates by the closed-form ×100 cm factor; re-import restores metres only on the matching option

‎docs/gallery/armature-bend/index.html‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ <h1>Armature Bend</h1>
4545
<p>Rigging end to end in the data API — edit_bones chain construction, name-bound vertex groups with smoothstep blend zones, posing, and depsgraph evaluation — bending a ribbed bellows hose through rest, half, and full curl.</p>
4646
</header>
4747
<main id="main">
48-
<nav class="pager" aria-label="Examples"><a rel="prev" href="../grease-pencil-rosette/" aria-label="Previous example: grease-pencil-rosette"><span aria-hidden="true">&larr;</span> grease-pencil-rosette</a><span class="pager-pos hud">19 of 54 examples<span class="pager-keys"> &middot; <kbd>&larr;</kbd><kbd>&rarr;</kbd></span></span><a rel="next" href="../text-version-stamp/" aria-label="Next example: text-version-stamp">text-version-stamp <span aria-hidden="true">&rarr;</span></a></nav>
48+
<nav class="pager" aria-label="Examples"><a rel="prev" href="../grease-pencil-rosette/" aria-label="Previous example: grease-pencil-rosette"><span aria-hidden="true">&larr;</span> grease-pencil-rosette</a><span class="pager-pos hud">19 of 56 examples<span class="pager-keys"> &middot; <kbd>&larr;</kbd><kbd>&rarr;</kbd></span></span><a rel="next" href="../text-version-stamp/" aria-label="Next example: text-version-stamp">text-version-stamp <span aria-hidden="true">&rarr;</span></a></nav>
4949
<button class="detail-hero" id="heroZoom" type="button" aria-label="View full size: Three ribbed bellows hoses with brass collars on steel foot flanges, banded teal to amber to coral, standing straight, half curled and fully curled by an armature.">
5050
<img src="../assets/armature-bend-hero.webp" alt="Three ribbed bellows hoses with brass collars on steel foot flanges, banded teal to amber to coral, standing straight, half curled and fully curled by an armature." width="1280" height="720" fetchpriority="high" />
5151
</button>
@@ -1050,7 +1050,7 @@ <h3><a class="stretch" href="../lod-decimate-chain/">LOD Decimate Chain</a></h3>
10501050
</article>
10511051
</div>
10521052
</section>
1053-
<nav class="pager pager-foot" aria-label="Examples"><a rel="prev" href="../grease-pencil-rosette/" aria-label="Previous example: grease-pencil-rosette"><span aria-hidden="true">&larr;</span> grease-pencil-rosette</a><span class="pager-pos hud">19 of 54 examples</span><a rel="next" href="../text-version-stamp/" aria-label="Next example: text-version-stamp">text-version-stamp <span aria-hidden="true">&rarr;</span></a></nav>
1053+
<nav class="pager pager-foot" aria-label="Examples"><a rel="prev" href="../grease-pencil-rosette/" aria-label="Previous example: grease-pencil-rosette"><span aria-hidden="true">&larr;</span> grease-pencil-rosette</a><span class="pager-pos hud">19 of 56 examples</span><a rel="next" href="../text-version-stamp/" aria-label="Next example: text-version-stamp">text-version-stamp <span aria-hidden="true">&rarr;</span></a></nav>
10541054
</main>
10551055
<dialog class="lightbox" id="lightbox" aria-label="Full-size render">
10561056
<div class="lightbox-bar"><button class="lightbox-close" id="lightboxNative" type="button" aria-pressed="false">Actual size</button><button class="lightbox-close" id="lightboxClose" type="button" autofocus>Close</button></div>
10.5 KB
Loading
33.6 KB
Loading
9.37 KB
Loading
27 KB
Loading

0 commit comments

Comments
 (0)