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 @@ -69,6 +69,7 @@
"examples/curve-bevel-arc",
"examples/custom-normals-shade",
"examples/damped-track-aim",
"examples/degenerate-bevel-weld",
"examples/depsgraph-export",
"examples/driver-wave",
"examples/gltf-export-roundtrip",
Expand Down
12 changes: 12 additions & 0 deletions .github/workflows/blender-smoke.yml
Original file line number Diff line number Diff line change
Expand Up @@ -554,3 +554,15 @@ jobs:
# non-zero on failure.
xvfb-run -a "$BLENDER" --background \
--python examples/attribute-domain-shear/attribute_domain_shear.py --

- name: Shipped example - degenerate bevel weld (half-dimension collapse)
run: |
set -euo pipefail
# Check only (no render): a 1.6x0.4x1.0 slab beveled at safe (0.10)
# and threshold (0.20 == min/2) offsets; asserts zero vs exactly 12
# zero-area faces (4 min-axis edges x 3 segments), 16 coincident
# verts (4 x (segments+1)), min_area collapse > 1e5x, and a stdlib
# GLB re-parse counting 32 degenerate triangles shipped versus 0.
# Exits non-zero on failure.
xvfb-run -a "$BLENDER" --background \
--python examples/degenerate-bevel-weld/degenerate_bevel_weld.py --
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 12 skills, 6 rules, 2 templates, 17 snippets, and 39
The content base is 12 skills, 6 rules, 2 templates, 17 snippets, and 40
examples (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/`; the render look is specified
Expand All @@ -35,7 +35,7 @@ Blender-Developer-Tools/
rules/<rule-name>.mdc # 6 rule files
templates/<template-name>/ # 2 starter templates
snippets/<snippet-name>.py # 17 standalone Python snippets
examples/<name>/ # 39 runnable smoke-gated examples (+ gallery.json)
examples/<name>/ # 40 runnable smoke-gated examples (+ gallery.json)
examples/gallery_framing.py # shared Layer 1 framing measurement (render path only)
scripts/build_gallery.py # generates docs/gallery/ (stdlib only)
scripts/site/ # vendored landing-page build (build_site.py + template)
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, 12 total
rules/<rule-name>.mdc - Anti-pattern rules, 6 total
templates/<template-name>/ - Starter projects, 2 total
snippets/<snippet-name>.py - Standalone code patterns, 17 total
examples/<name>/ - Runnable smoke-gated examples, 39 total (+ gallery.json)
examples/<name>/ - Runnable smoke-gated examples, 40 total (+ gallery.json)
scripts/build_gallery.py - Regenerates docs/gallery/ from gallery.json (stdlib only)
scripts/site/ - Vendored landing-page build (Jinja2)
docs/gallery/ - Committed generated gallery pages + hero renders
Expand Down Expand Up @@ -82,11 +82,11 @@ v0.1.0: canonical object creation and deletion, depsgraph evaluated mesh, bmesh

v0.2.0: Principled BSDF material, driver-with-custom-function via `driver_namespace`, application handler registration, shader node group with cross-version `interface` API, `foreach_get` bulk vertex read, version-branch skeleton, and USD export with `evaluation_mode='RENDER'`.

## Examples (39)
## Examples (40)

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 thirty-nine run headless on Blender 4.5 LTS and 5.1 in `blender-smoke.yml`;
`--output`. All forty run headless on Blender 4.5 LTS and 5.1 in `blender-smoke.yml`;
their renders ship in the site gallery at `docs/gallery/`. `examples/gallery.json` is the
gallery's source of truth. When authoring a new one, copy the anatomy of
`examples/bmesh-gear/` (script structure, README shape, dark-studio render recipe) and
Expand Down
22 changes: 21 additions & 1 deletion 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>39 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>40 examples</strong>
</p>

<p align="center">
Expand Down Expand Up @@ -760,6 +760,26 @@ palette[K−1], and the measured shear matches the palette closed form
`active_color`, the shader Attribute node). The broken state is in-frame:
the right pinwheel is the falsification variant.

</td>
</tr>
<tr>
<td width="46%" valign="middle">
<a href="examples/degenerate-bevel-weld/"><img src="examples/degenerate-bevel-weld/preview.webp" alt="Degenerate bevel weld: two teal display trays side by side — left with a soft rounded bevel, right collapsed to a knife edge with orange seam markers at the zero-area face centroids, proving the half-dimension bevel collapse ships degenerate triangles" /></a>
</td>
<td valign="middle">

### [degenerate-bevel-weld](examples/degenerate-bevel-weld/)

The half-dimension bevel collapse, isolated. A slab beveled at
`offset == min_dim/2` pinches its band into exactly **12 zero-area faces**
(4 min-axis edges × 3 segments) with 16 coincident verts and `min_area`
down 3.2e5× — and a stdlib re-parse of the exported GLB counts **32
degenerate triangles shipped** to disk, where an engine merge-by-distance
welds their loops. Companion to
[`gltf-export-roundtrip`](examples/gltf-export-roundtrip/) (where the count
check first caught the weld) and [`mesh-hygiene-audit`](examples/mesh-hygiene-audit/)
(topology gates). Seam markers are placed from live mesh data.

</td>
</tr>
</table>
Expand Down
2 changes: 1 addition & 1 deletion ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ Not committed; target list for the next content version. (v0.3.0 shipped the smo
- ~~Triangulate + tangent-space witness~~ **SHIPPED** as `examples/triangulate-tangents/` — `calc_tangents` aborts on any ngon (back cap must be an explicit fan); mikktspace matches the edge/UV-delta formula within welding tolerance on smooth fields (2.3e-6 measured); planar UVs on a cylindrical wall collapse tangents onto normals (dot 0.998); `MeshUVLoopLayer` handle dangles across `calc_tangents()` on 4.5 (471 phantom flips, silent exit 0) while the mikktspace math is byte-identical on 4.5.11 and 5.1.2
- UV-handle lifetime snippet: re-fetch attribute/UV layers by name after any CustomData-reallocating call (`calc_tangents`, `VertexGroup.add`, modifier edits) — held handles dangle silently on 4.5, survive by luck on 5.1 (found authoring `triangulate-tangents`)
- glTF skinned-mesh export witness: follow-up to `gltf-export-roundtrip` + `vertex-weight-limit` — **SHIPPED** as `examples/gltf-skin-roundtrip/` — `skins[0].joints` names every bone, JOINTS_0/WEIGHTS_0 with unit sums (3e-8), weights bit-exact, rest matrices to 2.4e-07, deformation to 4.8e-07; exporter welds duplicate loops (sorted-multiset comparisons mispair — compare by rest-key); unparented skinned meshes make the exporter bind an armature by name
- Degenerate-bevel weld hazard (snippet or rule): bevel width ≥ half a box dimension creates zero-area faces whose loops weld on glTF export (found authoring `gltf-export-roundtrip`, where the count check caught a 36-vertex weld)
- ~~Degenerate-bevel weld hazard~~ **SHIPPED** as `examples/degenerate-bevel-weld/` — at `offset == min_dim/2` the bevel band collapses to exactly 12 zero-area faces (4 min-axis edges × 3 segments) with 16 coincident verts (4 × (segments+1)) and min_area down 3.2e5×; a stdlib GLB re-parse counts **32 degenerate triangles crossing the export boundary** (MEASURED regression constant) versus 0 for the safe mesh — the loops an engine merge-by-distance welds; byte-identical on 4.5.11 and 5.1.2
- ~~GAMMA_CROSS blend-curve witness~~ **SHIPPED** as `examples/vse-gamma-cross/` — the cross blends in a gamma-0.5 space: `((1-t)·√A + t·√B)²` with `t = (frame − start)/duration`, never 1 inside the effect; mid-cross dips 0.115 below the sRGB lerp from crimson/teal (closed form (0.341, 0.349, 0.463) confirmed per frame); AgX-default sampling poisons the fit (0.146 red-channel error, `view_transform='Standard'` mandatory); deleting a consumed input orphans-and-deletes the effect — follow-up to `vse-cut-list`
- Falsy `bpy_prop_collection` trap snippet: an empty collection is falsy, so `editor.strips or editor.sequences` silently falls through to the legacy accessor on an empty timeline — always branch on `hasattr`; likely generalizes across the API (found authoring `vse-cut-list`)
- ~~Collision compound witness~~ **SHIPPED** as `examples/collision-hull-proxy/` — game-prop collision as a compound of convex pieces, each a `bmesh.ops.convex_hull` of a coarse `sec(π/n)`-inflated cage (containment 4.4e-08, watertight, positive signed volume, Euler 2, per-piece 255-face budget: body 70, caps 60×3, compound 250); a hull of the dense render mesh measures 380 faces — over budget — which is why pipelines hull cages; proud details cost cage rows, concave grooves are free; byte-identical on 4.5.11 and 5.1.2
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
Loading