You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat: add VSE linear-modifiers and GN socket-rename cross-version examples (#145)
* feat: witness VSE use_linear_modifiers removal across 4.5, 5.1, and 5.2
Naive getattr still works on 4.5.11 and 5.1.2 and raises AttributeError on 5.2.1. Version-guarded hasattr then read exits 0 on all three; --assume-present is red only where the RNA is gone.
Signed-off-by: TMHSDigital <154358121+TMHSDigital@users.noreply.github.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
* feat: witness GN Compare and Random Value socket identifier collapse on 5.2
Enabled-name lookup wires on 4.5.11, 5.1.2, and 5.2.1. Pre-5.2 identifiers Min_001 and A_INT are absent on 5.2; --legacy-ids is red only there. Regenerates gallery pages so the new still is in the index.
Signed-off-by: TMHSDigital <154358121+TMHSDigital@users.noreply.github.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
---------
Signed-off-by: TMHSDigital <154358121+TMHSDigital@users.noreply.github.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
This repository ships **16 skills, 9 rules, 3 templates, 27 snippets, and 55 examples** for Blender Python development targeting Blender 5.2 LTS (current stable) with Blender 4.5 LTS fallback support. Blender 5.1 is prior stable.
39
+
This repository ships **16 skills, 9 rules, 3 templates, 27 snippets, and 57 examples** 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
40
41
41
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.
42
42
@@ -203,7 +203,7 @@ Gallery still is a dual-elevation diptych so the contract reads at thumbnail sca
203
203
</details>
204
204
205
205
<details>
206
-
<summary><strong>Mesh, curves & text</strong> — 11 examples</summary>
206
+
<summary><strong>Mesh, curves & text</strong> — 12 examples</summary>
207
207
208
208
<table>
209
209
<tr>
@@ -370,14 +370,28 @@ inside the effect. Per-frame sample renders assert the closed form (mid dips
370
370
0.115 below the sRGB lerp), and the AgX-default sampling trap is documented
371
371
(`view_transform = 'Standard'` is mandatory for any pixel witness).
@@ -436,6 +450,21 @@ evaluated cubes against closed forms — Repeat `8×(1+N)` with X-centers at
436
450
nodes exist. Unpaired evaluates empty; For Each's main Geometry socket is a
437
451
passthrough.
438
452
453
+
</td>
454
+
</tr>
455
+
<tr>
456
+
<tdwidth="46%"valign="middle">
457
+
<ahref="examples/gn-socket-rename/"><imgsrc="examples/gn-socket-rename/preview.webp"alt="GN socket rename: a copper jo-block column on a steel plinth in a dark studio, the column switched in by Compare and tagged by Random Value, warm wedge on the back wall" /></a>
Copy file name to clipboardExpand all lines: ROADMAP.md
+4Lines changed: 4 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -140,6 +140,10 @@ Not committed; target list for the next content version. (v0.3.0 shipped the smo
140
140
- ~~Vertex-colour AO witness~~ **SHIPPED** as `examples/vertex-color-ao/` — baked occlusion in a colour attribute on a stone village well, checked against a closed form rather than a captured value: the cosine-weighted hemisphere integral for an infinitely wide wall of height H at distance d is `AO = 1 − ½(1 − 1/√(1+k²))`, `k = H/d`, matched to **6.760e-04** across k = 60.0…0.60 (gate 2.5e-03, QMC noise ~1/√n at 4096 samples); unoccluded plate bakes to **exactly 1.0**; strictly monotone 0.508301 → 0.928467; asset values in [0,1] with spread 1.0; **`BYTE_COLOR` is sRGB-encoded 8-bit, not linear** (0.735 → 0.7379107, peak round-trip error 3.782e-03, matching an independent encode/quantise/decode model to 3.189e-07) while `FLOAT_COLOR` is exact; both survive depsgraph evaluation at deviation 0.0; `bmesh.ops.bevel` offsets along **cached** face normals and flips outward past 90° of staleness (12 mm below ground on a ring of boxes, fixed by `normal_update()`); point-domain AO needs subdivision or the crevice gradient never reaches the attribute; `color_attributes` enumeration order differs between 4.5.11 and 5.1.2 — look up by name; byte-identical on 4.5.11 and 5.1.2 (6966 verts)
141
141
-~~High-to-low tangent normal bake~~**SHIPPED** as `examples/bake-normal-high-to-low/` — Cycles CPU `type='NORMAL'` cage bake onto a `DECIMATE COLLAPSE` hatch; statistical gates (detail frac 0.7211 / MAD 0.09356 vs flat 0.0000 / 0.00277); `--flat-source` exits 5; RNA identical on 4.5.11, 5.1.2, 5.2.1; byte-identity is not the contract
142
142
- UV atlas **utilization** witness — coverage/wasted-texel closed forms for a packed lightmap atlas (the non-overlap, unit-square, margin, and active/active_render contracts shipped in `lightmap-uv-channel`; utilization is the remaining unbuilt slice of the old "UV atlas pack" candidate)
143
+
-~~VSE `use_linear_modifiers` removal~~**SHIPPED** as `examples/vse-linear-modifiers/` — bool on 4.5.11 and 5.1.2, `AttributeError` on 5.2.1; `--assume-present` red only on 5.2; pathology, no gallery still
144
+
-~~GN Compare / Random Value socket identifier rename~~**SHIPPED** as `examples/gn-socket-rename/` — `A_INT` / `Min_001` present on 4.5.11 and 5.1.2, absent on 5.2.1; enabled-name lookup wires all three; `--legacy-ids` red only on 5.2
145
+
- GN evaluated `to_mesh().name` no longer equals the original mesh name (5.2 contract change)
146
+
-`MeshAutomaskingSettings` move: old `Brush` automasking attributes gone on 5.2
143
147
-~~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`
144
148
- 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`)
145
149
-~~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
<p>It exits non-zero on failure (edit-bone lifetime violation, LBS deviation, moved root ring, or an undeformed tip). The <code>blender-smoke</code> workflow runs the check on Blender 5.2 LTS and 4.5 LTS.</p>
277
+
<h2>Exit codes</h2>
278
+
<p>Per-script sequential checks. <code>9</code> is a valid check code; there is no rule against it.</p>
279
+
<p>| Code | Meaning | | --- | --- | | 0 | Success | | 1 | Uncaught exception (FATAL wrapper) | | 2 | argparse / usage | | 3 | <code>edit_bones</code> populated in object mode | | 4 | Edit-mode bone chain off closed form | | 5 | Evaluated vertex count changed | | 6 | Evaluated mesh off closed-form LBS | | 7 | Root ring moved | | 8 | Tip did not deflect (<code>--zero-curl</code> lands here) | | 9 | <code>--output</code> produced no file |</p>
280
+
<p>The <code>blender-smoke</code> workflow runs the check on Blender 5.2 LTS and 4.5 LTS (5.1 on the weekly cron, the <code>needs-5.1</code> PR label, or manual dispatch). Smoke does not pass <code>--output</code> or <code>--zero-curl</code>.</p>
275
281
</section>
276
282
<sectionclass="detail-section src">
277
283
<h2>Source</h2>
@@ -300,10 +306,14 @@ <h2>Source</h2>
300
306
The same API works unchanged on Blender 4.5 LTS and 5.1 — no version gate is
301
307
needed, which this example demonstrates by running identically on both.
302
308
309
+
``--zero-curl`` leaves every pose bone at rest and still asserts the tip
310
+
deflects. That is the falsifier (``--same-axis`` in export-preset-axis).
311
+
303
312
By default it runs only the correctness check (no render) — the CI smoke
304
313
check. Pass --output to also render a still:
305
314
306
315
blender --background --python armature_bend.py -- # check only
316
+
blender --background --python armature_bend.py -- --zero-curl # must fail
p.add_argument(<spanclass="s">"--output"</span>, default=<spanclass="k">None</span>, help=<spanclass="s">"optional: render a still PNG here"</span>)
<p><strong>Render as proof:</strong> dual pinwheel from the same closed-form palette the check asserts. CORNER (left) holds eight crisp petals to the hub; naive POINT (right) smears — petal colors bleed across the shared hub and ring verts into a swirl. The broken state is in-frame by design: the right fan *is* the falsification variant. Fully matte petal materials (<code>Specular IOR Level = 0</code>) so the flat color data carries no specular line, per <code>docs/VISUAL-STYLE.md</code>.</p>
<p>Exits non-zero on failure. The <code>blender-smoke</code> workflow runs the check on Blender 5.2 LTS and 4.5 LTS. The <code>--output</code> render path additionally measures framing against the Layer 1 band via <code>examples/gallery_framing.py</code> (exit 10 on violation) before writing the still.</p>
274
+
<h2>Exit codes</h2>
275
+
<p>Per-script sequential checks. <code>9</code> is a valid check code; there is no rule against it. <code>10</code> is the shared framing helper.</p>
276
+
<p>| Code | Meaning | | --- | --- | | 0 | Success | | 1 | Uncaught exception (FATAL wrapper) | | 2 | argparse / usage | | 3 | CORNER or POINT attribute size wrong | | 4 | CORNER hub corners off wedge color | | 5 | POINT hub is not last-write (<code>--no-overwrite</code> lands here) | | 6 | Outer ring verts off last-write order | | 7 | Measured shear off palette closed form, or ~0 | | 9 | <code>--output</code> produced no file | | 10 | Gallery framing violation |</p>
277
+
<p>The <code>blender-smoke</code> workflow runs the check on Blender 5.2 LTS and 4.5 LTS (5.1 on the weekly cron, the <code>needs-5.1</code> PR label, or manual dispatch). Smoke does not pass <code>--output</code> or <code>--no-overwrite</code>.</p>
274
278
</section>
275
279
<sectionclass="detail-section src">
276
280
<h2>Source</h2>
@@ -306,6 +310,7 @@ <h2>Source</h2>
306
310
check. Pass --output to also render a still:
307
311
308
312
blender --background --python attribute_domain_shear.py -- # check only
313
+
blender --background --python attribute_domain_shear.py -- --no-overwrite # must fail
<spanclass="k">if</span> len(attr_p.data) != len(me_p.vertices) <spanclass="k">or</span> len(me_p.vertices) != K + <spanclass="n">1</span>:
423
429
print(<spanclass="s">f"</span><spanclass="s">ERROR: POINT attr size </span>{len(attr_p.data)}<spanclass="s"> != verts </span>{len(me_p.vertices)}<spanclass="s">"</span>,
424
430
file=sys.stderr)
@@ -663,11 +669,13 @@ <h2>Source</h2>
663
669
p.add_argument(<spanclass="s">"--output"</span>, default=<spanclass="k">None</span>, help=<spanclass="s">"optional: render a still PNG here"</span>)
0 commit comments