Skip to content

Commit 0df86fb

Browse files
TMHSDigitalclaude
andauthored
fix: review polish for the four newest examples + documentation currency (#51)
Example fixes from review of the auto-generated batch: - gn-instance-grid and temp-override-join reframed — the right cube column and the top step were clipped at the frame edge; both now sit fully in frame with margin (heroes and previews re-rendered) - temp-override-join drops the redundant select_set/active-object setup: the temp_override alone fabricates the operator context, which is the contract the example teaches - curve-bevel-arc stops calling its vert/face constants closed-form: they are labeled as a measured regression gate with re-measure instructions (curve tessellation has no simple formula) Documentation currency (examples existed nowhere in the core docs): - CLAUDE.md: examples/scripts/docs-gallery in the architecture block, a new Examples (12) section with the authoring/wiring contract, examples in release-hygiene step 1, site-generation note in the workflow section - AGENTS.md: content-base list de-pinned from 'as of v0.2.0' and gains the examples bullet, structure block gains examples/scripts/docs entries, blender-smoke.yml documented in CI/CD - README: header, badge row, and overview now count 12 examples (validate-counts language preserved) - ROADMAP: the fleet-template lift-and-shift candidate marked resolved differently — vendored locally, gallery.json is permanent Both touched examples re-verified headless on Blender 5.1.1 and 4.4.3. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
1 parent b2407eb commit 0df86fb

14 files changed

Lines changed: 75 additions & 40 deletions

File tree

AGENTS.md

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,15 @@ Guidance for AI coding agents working on the Blender Developer Tools repository.
66

77
## Repository overview
88

9-
Skills, rules, snippets, and a starter template for Blender Python development.
9+
Skills, rules, snippets, starter templates, and runnable smoke-gated examples
10+
for Blender Python development.
1011
The repo targets **Blender 5.1** (current stable) with a **Blender 4.5 LTS**
1112
fallback. There is no MCP server. It ships a `.cursor-plugin/plugin.json`
1213
manifest so the ecosystem drift checker classifies it as a `cursor-plugin`.
1314
This is content the AI loads when the user asks Blender questions or works on
1415
Blender add-ons in Cursor or Claude Code.
1516

16-
The content base as of v0.2.0:
17+
The content base (counts are CI-enforced against README.md and the manifest):
1718

1819
- 12 skills covering scaffolding, operators, panels, properties, mesh and
1920
bmesh, headless batch scripts, slotted-actions animation (5.x), programmatic
@@ -26,6 +27,11 @@ The content base as of v0.2.0:
2627
- 2 templates: `extension-addon-template` for Extensions Platform add-ons,
2728
and `headless-batch-script-template` for unattended batch jobs.
2829
- 17 snippets covering canonical patterns.
30+
- 12 examples under `examples/<name>/`: runnable scripts that assert a real
31+
API contract with deterministic checks, exit non-zero on failure, and
32+
optionally render a still via `--output`. Each is executed headless on
33+
Blender 4.5 LTS and 5.1 by `blender-smoke.yml`; its render ships in the
34+
site gallery. Anatomy and authoring rules: copy `examples/bmesh-gear/`.
2935

3036
## Repository structure
3137

@@ -35,7 +41,11 @@ Blender-Developer-Tools/
3541
rules/<rule-name>.mdc # 6 rule files
3642
templates/<template-name>/ # 2 starter templates
3743
snippets/<snippet-name>.py # 17 standalone Python snippets
38-
.github/workflows/ # validate, drift-check, release, label-sync
44+
examples/<name>/ # 12 runnable smoke-gated examples (+ gallery.json)
45+
scripts/build_gallery.py # generates docs/gallery/ (stdlib only)
46+
scripts/site/ # vendored landing-page build (build_site.py + template)
47+
docs/gallery/ # committed generated gallery pages + hero assets
48+
.github/workflows/ # validate, blender-smoke, drift-check, release, pages, label-sync
3949
.github/dependabot.yml
4050
AGENTS.md, CLAUDE.md, README.md, ROADMAP.md, CHANGELOG.md
4151
CONTRIBUTING.md, SECURITY.md, CODE_OF_CONDUCT.md
@@ -116,6 +126,10 @@ way, and a one-paragraph rationale. 30 to 80 lines is the right size.
116126
every skill, rule, snippet, template, and example on disk must be listed,
117127
and the manifest `version` must equal `VERSION`. The release pipeline owns
118128
the manifest `version` line (see `release.yml` below) — never hand-edit it.
129+
- `blender-smoke.yml` executes every shipped example (check-only, no render)
130+
plus snippet/template smoke tests inside REAL headless Blender, on both
131+
4.5 LTS and 5.1, on every PR and a weekly schedule. A new example is not
132+
shipped until it has a step here.
119133
- `drift-check.yml` consumes `Developer-Tools-Directory/.github/actions/
120134
drift-check@v1.15` to enforce ecosystem standards-version markers.
121135
- `release.yml` auto-bumps the version, tags, force-updates floating tags

CLAUDE.md

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
66

77
## Project Overview
88

9-
The **Blender Developer Tools** repository is at **v0.9.1**. It packages skills, rules, snippets, and starter templates for Blender Python development with Cursor and Claude Code. Coverage targets **Blender 5.1** (current stable) with **Blender 4.5 LTS** fallback. There is no MCP server; content is consumed directly by the AI when working in Blender add-on or scripting projects.
9+
The **Blender Developer Tools** repository is at **v0.9.1**. It packages skills, rules, snippets, starter templates, and runnable smoke-gated examples for Blender Python development with Cursor and Claude Code. Coverage targets **Blender 5.1** (current stable) with **Blender 4.5 LTS** fallback. There is no MCP server; content is consumed directly by the AI when working in Blender add-on or scripting projects.
1010

1111
**Version:** 0.9.1
1212
**License:** CC-BY-NC-ND-4.0
@@ -19,6 +19,10 @@ skills/<skill-name>/SKILL.md - AI workflow definitions, 12 total
1919
rules/<rule-name>.mdc - Anti-pattern rules, 6 total
2020
templates/<template-name>/ - Starter projects, 2 total
2121
snippets/<snippet-name>.py - Standalone code patterns, 17 total
22+
examples/<name>/ - Runnable smoke-gated examples, 12 total (+ gallery.json)
23+
scripts/build_gallery.py - Regenerates docs/gallery/ from gallery.json (stdlib only)
24+
scripts/site/ - Vendored landing-page build (Jinja2)
25+
docs/gallery/ - Committed generated gallery pages + hero renders
2226
VERSION - Source of truth for the repo version
2327
```
2428

@@ -76,9 +80,24 @@ v0.1.0: canonical object creation and deletion, depsgraph evaluated mesh, bmesh
7680

7781
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'`.
7882

83+
## Examples (12)
84+
85+
Runnable scripts at `examples/<name>/`, each asserting a real API contract with
86+
deterministic checks (exit non-zero on failure) and optionally rendering a still via
87+
`--output`. All twelve run headless on Blender 4.5 LTS and 5.1 in `blender-smoke.yml`;
88+
their renders ship in the site gallery at `docs/gallery/`. `examples/gallery.json` is the
89+
gallery's source of truth. When authoring a new one, copy the anatomy of
90+
`examples/bmesh-gear/` (script structure, README shape, dark-studio render recipe) and
91+
wire all of: gallery.json entry, `.cursor-plugin/plugin.json` examples array (CI-gated),
92+
a `blender-smoke.yml` step, a README gallery row, hero webp (1280×720) in
93+
`docs/gallery/assets/` + preview webp (1200×675), then run `python scripts/build_gallery.py`.
94+
7995
## Development Workflow
8096

81-
This is a content repository, no build step. Edit `SKILL.md`, `.mdc`, `.py`, and `.toml` files directly.
97+
This is a content repository, no build step for skills/rules/snippets/templates — edit
98+
`SKILL.md`, `.mdc`, `.py`, and `.toml` files directly. The website is generated:
99+
`scripts/build_gallery.py` (stdlib) regenerates `docs/gallery/` and must be re-run after
100+
touching `examples/`; the landing page builds from `scripts/site/` at deploy time.
82101

83102
The AI consumes content via:
84103

@@ -109,7 +128,7 @@ The release pipeline is automated via `release.yml` on push to `main` for conten
109128

110129
When adding content to a future version:
111130

112-
1. Add files under `skills/`, `rules/`, `snippets/`, or `templates/`.
131+
1. Add files under `skills/`, `rules/`, `snippets/`, `templates/`, or `examples/`.
113132
2. Update README.md aggregate counts (the `validate-counts` job enforces correctness).
114133
3. Update ROADMAP.md candidate pool entries.
115134
4. Use `feat:` for new content, `fix:` for corrections.

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
---
44

55
<p align="center">
6-
<strong>Skills, rules, snippets, and a starter template for Blender Python development</strong>
6+
<strong>Skills, rules, snippets, templates, and runnable examples for Blender Python development</strong>
77
</p>
88

99
<p align="center">
@@ -17,14 +17,14 @@
1717
</p>
1818

1919
<p align="center">
20-
<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>
20+
<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>12 examples</strong>
2121
</p>
2222

2323
---
2424

2525
## Overview
2626

27-
This repository ships **12 skills, 6 rules, 2 templates, and 17 snippets** for Blender Python development targeting Blender 5.1 (current stable) with Blender 4.5 LTS fallback support.
27+
This repository ships **12 skills, 6 rules, 2 templates, 17 snippets, and 12 runnable examples** for Blender Python development targeting Blender 5.1 (current stable) with Blender 4.5 LTS fallback support.
2828

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

ROADMAP.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ Audit pass on v0.1.0 content: standards-version markers bumped from `1.9.1` to `
8989

9090
Not committed; target list for the next content version. (v0.3.0 shipped the smoke-gated `examples/` track.)
9191

92-
- **Fleet Pages facelift + examples support** (infra) -- ship as ONE coordinated change to the meta-repo `site-template/template.html.j2` + `build_site.py`, since both need a template edit and two fleet-wide pushes is worse than one. (a) examples discovery: load `examples/gallery.json` and render an Examples grid + a nav link to it (the nav link closes the landing->gallery cross-link gap, impossible today without a template edit); (b) landing facelift adopting the direction proven by this repo's gallery (shared light/dark tokens, fluid hero type scale, the card system, `:focus-visible`, reduced-motion). This repo's local gallery (`examples/gallery.json` + `docs/gallery/`, see `docs/gallery/DESIGN_NOTES.md`) is the **prototype and convergence target**: once the shared template reads the same `gallery.json` schema, the local generator (`scripts/build_gallery.py`) and page are retired -- a lift-and-shift, not a rewrite. The Option-2 cycle must read the full template-consumer set, account for floating-main consumption (every repo updates on next deploy), and prove backward compatibility (a repo with no `gallery.json` renders unchanged) before any meta-repo merge. No confirmed rendering bug today (the suspected Skills/Rules overlap was verified to be a normal collapsed accordion), so the cross-link discoverability gap is the main driver.
92+
- ~~Fleet Pages facelift + examples support~~ **RESOLVED differently (2026-07-03)**: the meta-repo migration was dropped — the fleet template only scaffolds new tools, and each tool's site evolves independently after that. This repo vendored the site build into `scripts/site/`, redesigned landing + gallery as the Blender-viewport system (see `docs/gallery/DESIGN_NOTES.md`), added the examples grid, nav link, and full hero stats locally. `scripts/build_gallery.py` and `examples/gallery.json` are now permanent, not a prototype awaiting lift-and-shift.
9393
- `modal-operators` skill -- `invoke` returning `RUNNING_MODAL`, the `modal()` event handler, modal cancellation patterns
9494
- `usd-pipelines` skill -- USD export options, `evaluation_mode`, instancing, the USD vs glTF tradeoffs
9595
- `mathutils-patterns` skill -- `mathutils.Vector`, `Matrix`, `Quaternion`, common transforms, the `@` operator
-3.09 KB
Loading
-568 Bytes
Loading

docs/gallery/curve-bevel-arc/index.html

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -205,9 +205,11 @@ <h2>Source</h2>
205205
Witnesses that renderable tubes are authored on `bpy.types.Curve` directly
206206
(`splines.new(&#x27;BEZIER&#x27;)`, `bezier_points`, `bevel_depth`, `use_fill_caps`) —
207207
not by meshing first or calling curve operators. The check asserts the
208-
closed-form point count, bevel depth, filled-cap topology, and that the
209-
depsgraph-evaluated mesh has a Z span of a tube whose centerline sits at
210-
`z = bevel_depth` (resting on the floor).
208+
closed-form point count and bevel depth, the closed-form Z span (tube
209+
centerline at `z = bevel_depth`, resting on the floor) and X span, plus the
210+
evaluated vert/face counts as a MEASURED regression gate — curve tessellation
211+
has no simple closed form, so those two constants pin today&#x27;s behavior (see
212+
EXPECT_VERTS below for how to re-measure if a future Blender retessellates).
211213

212214
By default it runs only the correctness check (no render) — the CI smoke
213215
check. Pass --output to also render a still:
@@ -222,7 +224,10 @@ <h2>Source</h2>
222224
BEVEL = <span class="n">0.15</span>
223225
BEVEL_RES = <span class="n">4</span>
224226
RES_U = <span class="n">12</span>
225-
<span class="c"># measured for the parameters above with use_fill_caps=True — identical on 4.4 and 5.1</span>
227+
<span class="c"># MEASURED regression constants, not closed-form: curve-to-mesh tessellation</span>
228+
<span class="c"># (rings x bevel segments + cap fans) has no simple formula. Verified identical</span>
229+
<span class="c"># on 4.4, 4.5 LTS, and 5.1. If a future Blender changes tessellation, re-measure</span>
230+
<span class="c"># by printing len(em.vertices)/len(em.polygons) in check() and update these.</span>
226231
EXPECT_VERTS = <span class="n">1044</span>
227232
EXPECT_FACES = <span class="n">1028</span>
228233

docs/gallery/gn-instance-grid/index.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -405,9 +405,9 @@ <h2>Source</h2>
405405
light(<span class="s">&quot;Rim&quot;</span>, (<span class="n">1.5</span>, <span class="n">4.5</span>, <span class="n">2.0</span>), <span class="n">480.0</span>, <span class="n">4.0</span>, (<span class="n">1.0</span>, <span class="n">0.75</span>, <span class="n">0.45</span>))
406406

407407
cam_data = bpy.data.cameras.new(<span class="s">&quot;Cam&quot;</span>)
408-
cam_data.lens = <span class="n">55.0</span>
408+
cam_data.lens = <span class="n">50.0</span>
409409
cam = bpy.data.objects.new(<span class="s">&quot;Cam&quot;</span>, cam_data)
410-
cam.location = (<span class="n">3.6</span>, -<span class="n">4.2</span>, <span class="n">2.8</span>)
410+
cam.location = (<span class="n">4.6</span>, -<span class="n">5.4</span>, <span class="n">3.4</span>)
411411
scene.collection.objects.link(cam)
412412
scene.camera = cam
413413
track = cam.constraints.new(<span class="s">&#x27;TRACK_TO&#x27;</span>)

docs/gallery/temp-override-join/index.html

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -250,15 +250,11 @@ <h2>Source</h2>
250250

251251

252252
<span class="k">def</span> join_with_temp_override(target, sources):
253-
<span class="s">&quot;&quot;&quot;The contract this example witnesses: temp_override, not context.copy().&quot;&quot;&quot;</span>
254-
view_layer = bpy.context.view_layer
255-
<span class="k">for</span> obj <span class="k">in</span> bpy.data.objects:
256-
obj.select_set(<span class="k">False</span>)
257-
target.select_set(<span class="k">True</span>)
258-
<span class="k">for</span> src <span class="k">in</span> sources:
259-
src.select_set(<span class="k">True</span>)
260-
view_layer.objects.active = target
253+
<span class="s">&quot;&quot;&quot;The contract this example witnesses: temp_override, not context.copy().
261254

255+
The override alone fabricates the whole operator context — no select_set,
256+
no view_layer.objects.active. That is the point: the scene&#x27;s real
257+
selection state stays untouched.&quot;&quot;&quot;</span>
262258
<span class="k">with</span> bpy.context.temp_override(
263259
active_object=target,
264260
selected_objects=[target, *sources],
@@ -374,7 +370,7 @@ <h2>Source</h2>
374370
cam_data = bpy.data.cameras.new(<span class="s">&quot;Cam&quot;</span>)
375371
cam_data.lens = <span class="n">50.0</span>
376372
cam = bpy.data.objects.new(<span class="s">&quot;Cam&quot;</span>, cam_data)
377-
cam.location = (<span class="n">4.2</span>, -<span class="n">5.2</span>, <span class="n">4.0</span>)
373+
cam.location = (<span class="n">5.0</span>, -<span class="n">6.4</span>, <span class="n">4.6</span>)
378374
scene.collection.objects.link(cam)
379375
scene.camera = cam
380376
track = cam.constraints.new(<span class="s">&#x27;TRACK_TO&#x27;</span>)

examples/curve-bevel-arc/curve_bevel_arc.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@
33
Witnesses that renderable tubes are authored on `bpy.types.Curve` directly
44
(`splines.new('BEZIER')`, `bezier_points`, `bevel_depth`, `use_fill_caps`) —
55
not by meshing first or calling curve operators. The check asserts the
6-
closed-form point count, bevel depth, filled-cap topology, and that the
7-
depsgraph-evaluated mesh has a Z span of a tube whose centerline sits at
8-
`z = bevel_depth` (resting on the floor).
6+
closed-form point count and bevel depth, the closed-form Z span (tube
7+
centerline at `z = bevel_depth`, resting on the floor) and X span, plus the
8+
evaluated vert/face counts as a MEASURED regression gate — curve tessellation
9+
has no simple closed form, so those two constants pin today's behavior (see
10+
EXPECT_VERTS below for how to re-measure if a future Blender retessellates).
911
1012
By default it runs only the correctness check (no render) — the CI smoke
1113
check. Pass --output to also render a still:
@@ -20,7 +22,10 @@
2022
BEVEL = 0.15
2123
BEVEL_RES = 4
2224
RES_U = 12
23-
# measured for the parameters above with use_fill_caps=True — identical on 4.4 and 5.1
25+
# MEASURED regression constants, not closed-form: curve-to-mesh tessellation
26+
# (rings x bevel segments + cap fans) has no simple formula. Verified identical
27+
# on 4.4, 4.5 LTS, and 5.1. If a future Blender changes tessellation, re-measure
28+
# by printing len(em.vertices)/len(em.polygons) in check() and update these.
2429
EXPECT_VERTS = 1044
2530
EXPECT_FACES = 1028
2631

0 commit comments

Comments
 (0)