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
4 changes: 3 additions & 1 deletion .cursor-plugin/plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,9 @@
"examples/vse-linear-modifiers",
"examples/wave-displace",
"examples/ray-cast-space",
"examples/lattice-deform"
"examples/lattice-deform",
"examples/solidify-even-thickness",
"examples/boolean-exact-volume"
],
"showcase": [
"showcase/shipping-crate",
Expand Down
4 changes: 2 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ a `.cursor-plugin/plugin.json` manifest so the ecosystem drift checker
classifies it as a `cursor-plugin`. This is content the AI loads when the user
asks Blender questions or works on Blender add-ons in Cursor or Claude Code.

The content base is 16 skills, 9 rules, 3 templates, 27 snippets, 62
The content base is 16 skills, 9 rules, 3 templates, 27 snippets, 64
examples, and 74 showcase pieces (counts are CI-enforced against README.md)
and the manifest). The full inventory tables and per-item purposes live in
`CLAUDE.md`. Example anatomy and authoring rules: copy `examples/bmesh-gear/`;
Expand All @@ -36,7 +36,7 @@ Blender-Developer-Tools/
rules/<rule-name>.mdc # 9 rule files
templates/<template-name>/ # 3 starter templates
snippets/<snippet-name>.py # 27 standalone Python snippets
examples/<name>/ # 62 runnable smoke-gated examples (+ gallery.json)
examples/<name>/ # 64 runnable smoke-gated examples (+ gallery.json)
examples/gallery_framing.py # shared Layer 1 framing measurement (render path only)
showcase/<name>/ # budget-conformance props (sibling of examples/)
showcase/gallery.json # this tree's gallery index; merged into docs/gallery/
Expand Down
6 changes: 3 additions & 3 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ skills/<skill-name>/SKILL.md - AI workflow definitions, 16 total
rules/<rule-name>.mdc - Anti-pattern rules, 9 total
templates/<template-name>/ - Starter projects, 3 total
snippets/<snippet-name>.py - Standalone code patterns, 27 total
examples/<name>/ - Runnable smoke-gated examples, 62 total (+ gallery.json)
examples/<name>/ - Runnable smoke-gated examples, 64 total (+ gallery.json)
showcase/<name>/ - Budget-conformance props, 74 pieces, each with a gallery `category` (sibling of examples/; see showcase/README.md § Categories)
scripts/build_gallery.py - Regenerates docs/gallery/ from examples/gallery.json + showcase/gallery.json
scripts/site/ - Vendored landing-page build (Jinja2); tokens.css is the shared palette
Expand Down Expand Up @@ -105,12 +105,12 @@ v0.2.0: Principled BSDF material, driver-with-custom-function via `driver_namesp

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`.

## Examples (62)
## Examples (64)

Runnable scripts at `examples/<name>/`, each asserting a real API contract with
deterministic checks (exit non-zero on failure) and optionally rendering a still via
`--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);
**54 of the 62 ship a render in the site gallery** at `docs/gallery/`. The other
**56 of the 64 ship a render in the site gallery** at `docs/gallery/`. The other
eight are **check-only**: they carry no `--output` path, no gallery entry, and no
hero asset. The criterion is whether the contract is expressible in pixels. An
example is check-only when its witness is a data or state fact that no scene
Expand Down
38 changes: 34 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
</p>

<p align="center">
<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>
<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>
</p>

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

## Overview

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.
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.

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.

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

## Falsifiers

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

<details>
<summary><strong>Mesh, curves &amp; text</strong> — 15 examples</summary>
<summary><strong>Mesh, curves &amp; text</strong> — 17 examples</summary>

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

</td>
</tr>
<tr>
<td width="46%" valign="middle">
<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>
</td>
<td valign="middle">

### [solidify-even-thickness](examples/solidify-even-thickness/)

Solidify on a strip folded at 60°, 90° and 120°. Without `use_even_offset`, each fold vertex
moves *t* along the bisector and the wall thins to *t*·cos(φ/2), half at 120°. With it, the
vertex moves *t*/cos(φ/2) and the wall stays exactly *t*. Both closed forms are measured off
the evaluated mesh to 1e-5 (`--no-even` exits 4).

</td>
</tr>
<tr>
<td width="46%" valign="middle">
<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>
</td>
<td valign="middle">

### [boolean-exact-volume](examples/boolean-exact-volume/)

The Boolean modifier on `solver='EXACT'`, cutting a cube with a slab whose top face is
coplanar with the cube's. Union, difference and intersection measure their closed-form
9, 7 and 1 m³ by the divergence theorem and are closed 2-manifolds. The floating-point
solver, renamed `'FAST'` → `'FLOAT'` in 5.0, gets the union wrong (`--float-solver` exits 3).

</td>
</tr>
</table>
Expand Down
5 changes: 3 additions & 2 deletions ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,8 +167,9 @@ Not committed; target list for the next content version. (v0.3.0 shipped the smo
- `mathutils.bvhtree` witness — `BVHTree.FromObject` on evaluated geometry: `find_nearest` distances and `overlap` pairs match closed forms on a known arrangement
- 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
- 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)
- 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
- 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
- ~~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
- ~~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
- 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
- ~~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
- 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
- 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
Expand Down
4 changes: 2 additions & 2 deletions docs/gallery/armature-bend/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ <h1>Armature Bend</h1>
<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>
</header>
<main id="main">
<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>
<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>
<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.">
<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" />
</button>
Expand Down Expand Up @@ -1050,7 +1050,7 @@ <h3><a class="stretch" href="../lod-decimate-chain/">LOD Decimate Chain</a></h3>
</article>
</div>
</section>
<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>
<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>
</main>
<dialog class="lightbox" id="lightbox" aria-label="Full-size render">
<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>
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.
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.
4 changes: 2 additions & 2 deletions docs/gallery/attribute-domain-shear/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ <h1>Attribute Domain Shear</h1>
<p>POINT vs CORNER color-attribute domains on a shared-vertex fan: CORNER stays exact per face while a naive per-wedge POINT loop shears to the last write at the hub. A striped parasol keeps crisp stripes under CORNER and smears, with one panel turned the wrong color, under POINT; the measured shear equals the palette closed form.</p>
</header>
<main id="main">
<nav class="pager" aria-label="Examples"><a rel="prev" href="../car-mirror-symmetry/" aria-label="Previous example: car-mirror-symmetry"><span aria-hidden="true">&larr;</span> car-mirror-symmetry</a><span class="pager-pos hud">41 of 54 examples<span class="pager-keys"> &middot; <kbd>&larr;</kbd><kbd>&rarr;</kbd></span></span><a rel="next" href="../degenerate-bevel-weld/" aria-label="Next example: degenerate-bevel-weld">degenerate-bevel-weld <span aria-hidden="true">&rarr;</span></a></nav>
<nav class="pager" aria-label="Examples"><a rel="prev" href="../car-mirror-symmetry/" aria-label="Previous example: car-mirror-symmetry"><span aria-hidden="true">&larr;</span> car-mirror-symmetry</a><span class="pager-pos hud">41 of 56 examples<span class="pager-keys"> &middot; <kbd>&larr;</kbd><kbd>&rarr;</kbd></span></span><a rel="next" href="../degenerate-bevel-weld/" aria-label="Next example: degenerate-bevel-weld">degenerate-bevel-weld <span aria-hidden="true">&rarr;</span></a></nav>
<button class="detail-hero" id="heroZoom" type="button" aria-label="View full size: Two patio parasols on a terracotta paver deck behind CORNER and POINT slate placards: the left has crisp crimson and cream stripes, the right has its stripes smeared pink.">
<img src="../assets/attribute-domain-shear-hero.webp" alt="Two patio parasols on a terracotta paver deck behind CORNER and POINT slate placards: the left has crisp crimson and cream stripes, the right has its stripes smeared pink." width="1280" height="720" fetchpriority="high" />
</button>
Expand Down Expand Up @@ -1507,7 +1507,7 @@ <h3><a class="stretch" href="../custom-normals-shade/">Custom Normals Shade</a><
</article>
</div>
</section>
<nav class="pager pager-foot" aria-label="Examples"><a rel="prev" href="../car-mirror-symmetry/" aria-label="Previous example: car-mirror-symmetry"><span aria-hidden="true">&larr;</span> car-mirror-symmetry</a><span class="pager-pos hud">41 of 54 examples</span><a rel="next" href="../degenerate-bevel-weld/" aria-label="Next example: degenerate-bevel-weld">degenerate-bevel-weld <span aria-hidden="true">&rarr;</span></a></nav>
<nav class="pager pager-foot" aria-label="Examples"><a rel="prev" href="../car-mirror-symmetry/" aria-label="Previous example: car-mirror-symmetry"><span aria-hidden="true">&larr;</span> car-mirror-symmetry</a><span class="pager-pos hud">41 of 56 examples</span><a rel="next" href="../degenerate-bevel-weld/" aria-label="Next example: degenerate-bevel-weld">degenerate-bevel-weld <span aria-hidden="true">&rarr;</span></a></nav>
</main>
<dialog class="lightbox" id="lightbox" aria-label="Full-size render">
<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>
Expand Down
Loading
Loading