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
3 changes: 2 additions & 1 deletion .cursor-plugin/plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,11 @@
],
"examples": [
"examples/armature-bend",
"examples/attribute-domain-shear",
"examples/bmesh-gear",
"examples/car-mirror-symmetry",
"examples/color-attribute-wheel",
"examples/collision-hull-proxy",
"examples/color-attribute-wheel",
"examples/compositor-glare",
"examples/curve-bevel-arc",
"examples/custom-normals-shade",
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 @@ -542,3 +542,15 @@ jobs:
# non-zero on failure.
xvfb-run -a "$BLENDER" --background \
--python examples/car-mirror-symmetry/car_mirror_symmetry.py --

- name: Shipped example - attribute domain shear (POINT vs CORNER semantics)
run: |
set -euo pipefail
# Check only (no render): an 8-wedge pinwheel around one shared hub
# vertex; asserts CORNER attr sizing (3K loops) and exact per-wedge
# hub colors, POINT sizing (K+1 verts), and that a naive per-wedge
# POINT loop shears to the last write at every shared vertex with
# the measured deviation equal to the palette closed form. Exits
# non-zero on failure.
xvfb-run -a "$BLENDER" --background \
--python examples/attribute-domain-shear/attribute_domain_shear.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 23
The content base is 12 skills, 6 rules, 2 templates, 17 snippets, and 39
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>/ # 23 runnable smoke-gated examples (+ gallery.json)
examples/<name>/ # 39 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, 23 total (+ gallery.json)
examples/<name>/ - Runnable smoke-gated examples, 39 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 (23)
## Examples (39)

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 twenty-three run headless on Blender 4.5 LTS and 5.1 in `blender-smoke.yml`;
`--output`. All thirty-nine 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
23 changes: 22 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>38 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>39 examples</strong>
</p>

<p align="center">
Expand Down Expand Up @@ -739,6 +739,27 @@ Companion to [`depsgraph-export`](examples/depsgraph-export/) (evaluated-vs-
original) and [`shape-key-blend`](examples/shape-key-blend/) (non-destructive
evaluation). Break the mirror and the render is literally half a car.

</td>
</tr>
<tr>
<td width="46%" valign="middle">
<a href="examples/attribute-domain-shear/"><img src="examples/attribute-domain-shear/preview.webp" alt="Attribute domain shear: two eight-petal pinwheels side by side — left CORNER-domain with crisp colored petals to the hub, right naive POINT-domain smeared into a swirl, proving last-write-wins shear at shared vertices" /></a>
</td>
<td valign="middle">

### [attribute-domain-shear](examples/attribute-domain-shear/)

What `POINT` versus `CORNER` **means** on `Mesh.color_attributes` once a mesh
has shared vertices. An eight-wedge pinwheel around one raised hub: CORNER
authoring holds each wedge's exact color (hub corners disagree by face,
err ≤ 1e-6), while the naive per-wedge POINT loop rewrites every shared
vertex once per neighbor and the **last write wins** — the hub reads
palette[K−1], and the measured shear matches the palette closed form
(0.751031) exactly. Companion to
[`color-attribute-wheel`](examples/color-attribute-wheel/) (domain sizing,
`active_color`, the shader Attribute node). The broken state is in-frame:
the right pinwheel is the falsification variant.

</td>
</tr>
</table>
Expand Down
3 changes: 1 addition & 2 deletions ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ Not committed; target list for the next content version. (v0.3.0 shipped the smo
- Gallery coverage follow-ups from the GPv3 review: light-linking (`grease-pencil-rosette`, `armature-bend`, `text-version-stamp`, `image-pixels-testcard`, and `vse-cut-list` shipped first)
- ~~UV-layer authoring witness~~ **SHIPPED** as `examples/uv-layer-grid/` — `create_grid(..., calc_uvs=True)` silent no-op without a pre-existing UV layer; closed-form UV fill + explicit assignment fallback; dual-panel render (flat texel (0,0) vs neon checker)
- ~~Image save-format witness~~ **SHIPPED** as `examples/png-exr-alpha/` — float→PNG is RGBA16 and false-unpremultiplies as if associated-alpha (closed-form err 0.98 at RGB 0.02 / a=1/255); OpenEXR preserves float RGBA; byte→PNG is straight RGBA8; `EXR color_mode='RGB'` drops alpha
- 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`
- ~~Attribute domain witness~~ **SHIPPED** as `examples/attribute-domain-shear/` — POINT vs CORNER semantics on an 8-wedge pinwheel with one shared hub: CORNER authoring exact (hub corners disagree by face, err ≤ 1e-6), naive per-wedge POINT loop shears to the last write at hub + ring verts, measured deviation == palette closed form (0.751031); byte-identical on 4.5.11 and 5.1.2; crisp-vs-smeared dual pinwheel still — companion to `color-attribute-wheel`
- ~~Light-linking collection witness~~ **SHIPPED** as `examples/light-link-studio/` — the API is `obj.light_linking` on the light OBJECT (`ld.light_linking` is an AttributeError on both versions); linked ratio 4.0x at projected-center luminance samples, unlink raises the decoy 244–251% with 0.0% hero drift in the same two-render check; EEVEE Next honors linking too (5.5x on 4.5.11, 5.9x on 5.1.2), Cycles pinned for deterministic samples
- ~~VSE sequences-to-strips witness~~ **SHIPPED** as `examples/vse-cut-list/` — `.sequences` removed on 5.x (4.5 bridges to `.strips`), `new_effect` end kwarg `frame_end=` (4.5) vs `length=` (5.x), `frame_final_*` deprecated in favor of `left_handle`/`right_handle`/`duration`, TRANSFORM effect type removed, GAMMA_CROSS clamps to the source overlap, effect strips consume inputs only when stacked above them, same-scene scene strips render transparent; save/reload round-trip + tiny-render pixel witness
- ~~glTF export round-trip witness~~ **SHIPPED** as `examples/gltf-export-roundtrip/` — `export_yup` bakes `(x,y,z)→(x,z,−y)` into vertex data with no node rotation (probed identical on 4.5.11 and 5.1.2), `export_apply` ships the evaluated mesh (one disk vertex per evaluated loop), TEXCOORD_0 is V-flipped on disk, per-triangle material bindings survive; exporter/importer RNA signatures byte-identical between 4.5.11 and 5.1.2 (guarded against future renames); `Mesh.calc_normals()` removal on 5.x surfaced during authoring
Expand All @@ -127,7 +127,6 @@ Not committed; target list for the next content version. (v0.3.0 shipped the smo
- 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`

- ~~Gallery framing recomposition worklist~~ **DRAINED**: all four recomposition cases restaged and gated with `check_framing` — depsgraph-export (0.984x/touch→0.812x; cube+dome recentered, aim-based camera), vertex-weight-limit (touch B→0.867y; more frontal camera, lower aim, base in frame), triangulate-tangents (0.334x→0.833y; 2x-class move-in plus Key/Glint trim that also cleared a pre-existing dome blowout), text-version-stamp (0.663x→0.719x; moved in with aim on the stamp center, dead third gone). The seven marginal cases were camera-nudged in the preceding sweep; deviations documented in #108 (damped-track-aim, wave-displace); sky-texture-sun-elevation is a measurement artifact (world subject — report-only if wired). Remaining: nothing on the framing worklist — future examples inherit the gate at authoring time.

Expand Down
12 changes: 12 additions & 0 deletions docs/VISUAL-STYLE.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,18 @@ the default stage.
- The image must witness the API: if the contract failed, the render should
visibly break. If the render would look the same whether the code worked or
not, the scene design is wrong, not merely unpolished.
- **Numeric-only contracts are a narrow, declared exception.** Some contracts
have no visual signature: the broken state renders pixel-identical because
the evidence is a count, a cap, or a buffer invariant, not a shape. Then
the example says so in its README, the render's job is to depict the
subject and its setup legibly — so the reader can see what the numbers
describe — and the falsification pass is satisfied by naming why no visual
difference exists. Precedents: `vertex-weight-limit` (the prune preserves
the pose by design, so the 4-influence cap is numeric) and
`triangulate-tangents` (the ring sweep is UV/bump-driven, so a
tangent-field break does not move pixels). This is for contracts that
genuinely cannot be seen, not for scenes that were not designed hard
enough: where a visual witness is possible, it is required.
- Presentation may be staged; evidence may not. When the witnessed artifact
is itself an image (a sequencer frame, a pixel buffer, a baked texture),
the authentic pixels must appear unaltered — mount them in the scene
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
Loading