diff --git a/.cursor-plugin/plugin.json b/.cursor-plugin/plugin.json index b5fcdfc..46742a1 100644 --- a/.cursor-plugin/plugin.json +++ b/.cursor-plugin/plugin.json @@ -68,6 +68,7 @@ "examples/driver-wave", "examples/gn-instance-grid", "examples/gn-sdf-remesh", + "examples/parent-inverse-orrery", "examples/shader-node-group", "examples/shape-key-blend", "examples/swatch-grid", diff --git a/.github/workflows/blender-smoke.yml b/.github/workflows/blender-smoke.yml index cc86777..0a65ca3 100644 --- a/.github/workflows/blender-smoke.yml +++ b/.github/workflows/blender-smoke.yml @@ -264,3 +264,14 @@ jobs: # failure. xvfb-run -a "$BLENDER" --background \ --python examples/color-attribute-wheel/color_attribute_wheel.py -- + + - name: Shipped example - parent inverse orrery (matrix_parent_inverse) + run: | + set -euo pipefail + # Frame-independent check only (no render): a data-API orrery whose arms, + # planets, and moon are parented with the keep-world idiom; asserts bare + # `.parent =` teleports a probe, matrix_parent_inverse restores it exactly, + # matrix_world is stale until view_layer.update(), and every orbit lands + # on its closed form. Exits non-zero on failure. + xvfb-run -a "$BLENDER" --background \ + --python examples/parent-inverse-orrery/parent_inverse_orrery.py -- diff --git a/AGENTS.md b/AGENTS.md index c1d4aa1..c659622 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -27,7 +27,7 @@ The content base (counts are CI-enforced against README.md and the manifest): - 2 templates: `extension-addon-template` for Extensions Platform add-ons, and `headless-batch-script-template` for unattended batch jobs. - 17 snippets covering canonical patterns. -- 15 examples under `examples//`: runnable scripts that assert a real +- 16 examples under `examples//`: runnable scripts that assert a real API contract with deterministic checks, exit non-zero on failure, and optionally render a still via `--output`. Each is executed headless on Blender 4.5 LTS and 5.1 by `blender-smoke.yml`; its render ships in the @@ -41,7 +41,7 @@ Blender-Developer-Tools/ rules/.mdc # 6 rule files templates// # 2 starter templates snippets/.py # 17 standalone Python snippets - examples// # 15 runnable smoke-gated examples (+ gallery.json) + examples// # 16 runnable smoke-gated examples (+ gallery.json) scripts/build_gallery.py # generates docs/gallery/ (stdlib only) scripts/site/ # vendored landing-page build (build_site.py + template) docs/gallery/ # committed generated gallery pages + hero assets diff --git a/CLAUDE.md b/CLAUDE.md index c22bc11..00685b3 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -19,7 +19,7 @@ skills//SKILL.md - AI workflow definitions, 12 total rules/.mdc - Anti-pattern rules, 6 total templates// - Starter projects, 2 total snippets/.py - Standalone code patterns, 17 total -examples// - Runnable smoke-gated examples, 15 total (+ gallery.json) +examples// - Runnable smoke-gated examples, 16 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 @@ -80,11 +80,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 (15) +## Examples (16) Runnable scripts at `examples//`, each asserting a real API contract with deterministic checks (exit non-zero on failure) and optionally rendering a still via -`--output`. All fifteen run headless on Blender 4.5 LTS and 5.1 in `blender-smoke.yml`; +`--output`. All sixteen 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 diff --git a/README.md b/README.md index 2808bec..6512c6a 100644 --- a/README.md +++ b/README.md @@ -17,14 +17,14 @@

- 12 skills  •  6 rules  •  2 templates  •  17 snippets  •  15 examples + 12 skills  •  6 rules  •  2 templates  •  17 snippets  •  16 examples

--- ## Overview -This repository ships **12 skills, 6 rules, 2 templates, 17 snippets, and 15 runnable examples** for Blender Python development targeting Blender 5.1 (current stable) with Blender 4.5 LTS fallback support. +This repository ships **12 skills, 6 rules, 2 templates, 17 snippets, and 16 runnable examples** for Blender Python development targeting Blender 5.1 (current stable) with Blender 4.5 LTS fallback support. 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. @@ -264,6 +264,22 @@ HSV across face corners with `foreach_get`/`foreach_set`. Asserts the attribute is sized to loop count (not vertex count), is `active_color`, and that the shader `Attribute` node is actually linked to Base Color. + + + + +Parent inverse orrery: a brass tabletop orrery with a glowing sun, three planets on pivot arms inside brass orbit rings, and a silver moon, on a dark studio floor + + + +### [parent-inverse-orrery](examples/parent-inverse-orrery/) + +A brass orrery parented entirely through the data API — the keep-world idiom +`child.parent = pivot; child.matrix_parent_inverse = pivot.matrix_world.inverted()` +carries arms, planets, and a two-level moon through spinning pivots. Asserts bare +`.parent =` really teleports, `matrix_world` is stale until `view_layer.update()`, +and every orbit lands on its closed form. + diff --git a/docs/gallery/assets/parent-inverse-orrery-hero.webp b/docs/gallery/assets/parent-inverse-orrery-hero.webp new file mode 100644 index 0000000..e9d3f14 Binary files /dev/null and b/docs/gallery/assets/parent-inverse-orrery-hero.webp differ diff --git a/docs/gallery/index.html b/docs/gallery/index.html index af564d3..7a1ce57 100644 --- a/docs/gallery/index.html +++ b/docs/gallery/index.html @@ -190,10 +190,12 @@

Examples Gallery

+ +
+
+ + parent-inverse-orrery — Data-API parenting for a brass orrery — the keep-world idiom (child + +
+

parent-inverse-orrery

+

Data-API parenting for a brass orrery — the keep-world idiom (child.parent = pivot; child.matrix_parent_inverse = pivot.matrix_world.inverted()) carrying arms, planets, and a two-level moon through spinning pivots.

+

witnesses Bare `.parent =` really does teleport the child; the idiom restores world position exactly; matrix_world stays stale until view_layer.update(); every orbit lands on its closed form.

+ View example +
+