Skip to content

Commit 6be6529

Browse files
TMHSDigitalclaude
andcommitted
feat: four rules for the headline Blender 5 breaks
The porting table lists about 20 breaks, but only bgl, the normals API, .sequences, context.copy and bl_info had a rule, so the most common 5.x breaks were caught only when an agent happened to load the right skill. action.fcurves is one of the three bugs the README tagline names. New rules, each stating only behavior this repo already measured on 4.5 and 5.x: - no-legacy-action-fcurves: action.fcurves/groups/id_root (removed in 5.0) - principled-v2-socket-names: 3.x Principled BSDF input names or indices - no-nodes-modifier-idprop-inputs: mod[ident] = value without a 5.2 branch - branch-eevee-engine-id: a literal EEVEE engine id without a 5.0 branch Each is linked from its porting-table row; the Cursor manifest, CLAUDE.md and README tables, counts (12 -> 16) and the generated Claude/AGENTS/Copilot rule files are updated. Closes #526 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LpkeXRvikhJZSVGBFM91Dv Signed-off-by: TM Hospitality Strategies <TMHospitalityStrategies@gmail.com>
1 parent 33f26af commit 6be6529

17 files changed

Lines changed: 435 additions & 18 deletions

‎.cursor-plugin/plugin.json‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,10 @@
5858
"rules/use-correct-axis-rna-per-exporter.mdc",
5959
"rules/no-bgl.mdc",
6060
"rules/no-removed-normals-api.mdc",
61-
"rules/no-legacy-vse-sequences.mdc"
61+
"rules/no-legacy-vse-sequences.mdc",
62+
"rules/no-legacy-action-fcurves.mdc",
63+
"rules/principled-v2-socket-names.mdc",
64+
"rules/no-nodes-modifier-idprop-inputs.mdc",
65+
"rules/branch-eevee-engine-id.mdc"
6266
]
6367
}

‎AGENTS.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ a `.cursor-plugin/plugin.json` manifest so the ecosystem drift checker
2020
classifies it as a `cursor-plugin`. This is content the AI loads when the user
2121
asks Blender questions or works on Blender add-ons in Cursor or Claude Code.
2222

23-
The content base is 25 skills, 12 rules, 3 templates, 31 snippets, 66
23+
The content base is 25 skills, 16 rules, 3 templates, 31 snippets, 66
2424
examples, and 80 showcase pieces (counts are CI-enforced across README.md, the agent docs, ROADMAP.md,
2525
`site.json` and the site templates). The full inventory tables and per-item purposes live in
2626
`CLAUDE.md`. Example anatomy and authoring rules: copy `examples/bmesh-gear/`;
@@ -33,7 +33,7 @@ in `docs/VISUAL-STYLE.md`; the canonical run prompt is
3333
```
3434
Blender-Developer-Tools/
3535
skills/<skill-name>/SKILL.md # 25 skill files
36-
rules/<rule-name>.mdc # 12 rule files
36+
rules/<rule-name>.mdc # 16 rule files
3737
templates/<template-name>/ # 3 starter templates
3838
snippets/<snippet-name>.py # 31 standalone Python snippets
3939
examples/<name>/ # 69 runnable smoke-gated examples (+ gallery.json)

‎CLAUDE.md‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ The **Blender Developer Tools** repository is at **v0.158.0**. It packages skill
1818

1919
```
2020
skills/<skill-name>/SKILL.md - AI workflow definitions, 25 total
21-
rules/<rule-name>.mdc - Anti-pattern rules, 12 total
21+
rules/<rule-name>.mdc - Anti-pattern rules, 16 total
2222
templates/<template-name>/ - Starter projects, 3 total
2323
snippets/<snippet-name>.py - Standalone code patterns, 31 total
2424
examples/<name>/ - Runnable smoke-gated examples, 69 total (+ gallery.json)
@@ -60,7 +60,7 @@ VERSION - Source of truth for the repo version
6060
| curves-and-text | Curve and TextCurve datablocks: splines, bevel/extrude closed forms, `body`, Bfont, evaluated mesh read-back |
6161
| compositor-nodes | 4.5 `scene.node_tree` vs 5.x `scene.compositing_node_group`, Glare node enum-to-menu-socket change, `use_compositing` |
6262

63-
## Rules (12)
63+
## Rules (16)
6464

6565
Every rule sets `alwaysApply: false`, so the Scope column below is the rule's
6666
actual load condition, not a description: a rule enters context only when a file
@@ -80,6 +80,10 @@ matching its `globs` does. Changing a glob changes when the rule fires.
8080
| no-bgl | `*.py` | `import bgl` or any `bgl.` call (removed in 5.x; the add-on fails to register) |
8181
| no-removed-normals-api | `*.py` | `use_auto_smooth`, `auto_smooth_angle`, `calc_normals_split()` and the other normals calls removed in 4.1 |
8282
| no-legacy-vse-sequences | `*.py` | `sequence_editor.sequences` / `.sequences_all` (removed in 5.x; `.strips` / `.strips_all` exist on 4.5 too) |
83+
| no-legacy-action-fcurves | `*.py` | `action.fcurves`, `action.groups`, `action.id_root` (removed in 5.0; F-curves live in the slot's channelbag) |
84+
| principled-v2-socket-names | `*.py` | Principled BSDF inputs by 3.x name (`Emission`, `Specular`, `Clearcoat`, ...) or by index (renamed in 4.0) |
85+
| no-nodes-modifier-idprop-inputs | `*.py` | `mod["Socket_N"] = value` on a NODES modifier without a 5.2 branch (TypeError on 5.2; `mod.properties.inputs` does not exist before it) |
86+
| branch-eevee-engine-id | `*.py` | literal `'BLENDER_EEVEE_NEXT'` / `'BLENDER_EEVEE'` engine id without a 5.0 version branch |
8387

8488
## Templates (3)
8589

‎CONTRIBUTING.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,7 @@ The drift-check workflow enforces these on every push and PR.
329329

330330
## Aggregate Counts
331331

332-
`README.md` declares aggregate counts (e.g. "25 skills, 12 rules, 3 templates, 31 snippets, 69 examples, and 80 showcase pieces"). The `validate-counts` job in `.github/workflows/validate.yml` enforces these substrings against the filesystem on every push and PR. Showcase pieces are counted separately from examples. When you add or remove content, update the README counts in the same commit.
332+
`README.md` declares aggregate counts (e.g. "25 skills, 16 rules, 3 templates, 31 snippets, 69 examples, and 80 showcase pieces"). The `validate-counts` job in `.github/workflows/validate.yml` enforces these substrings against the filesystem on every push and PR. Showcase pieces are counted separately from examples. When you add or remove content, update the README counts in the same commit.
333333

334334
## Pull Request Process
335335

‎README.md‎

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
</p>
2626

2727
<p align="center">
28-
<strong>25 skills</strong> &nbsp;&bull;&nbsp; <strong>12 rules</strong> &nbsp;&bull;&nbsp; <strong>3 templates</strong> &nbsp;&bull;&nbsp; <strong>31 snippets</strong> &nbsp;&bull;&nbsp; <strong>69 examples</strong> &nbsp;&bull;&nbsp; <strong>80 showcase pieces</strong>
28+
<strong>25 skills</strong> &nbsp;&bull;&nbsp; <strong>16 rules</strong> &nbsp;&bull;&nbsp; <strong>3 templates</strong> &nbsp;&bull;&nbsp; <strong>31 snippets</strong> &nbsp;&bull;&nbsp; <strong>69 examples</strong> &nbsp;&bull;&nbsp; <strong>80 showcase pieces</strong>
2929
</p>
3030

3131
<p align="center">
@@ -44,14 +44,14 @@
4444

4545
## Overview
4646

47-
This repository ships **25 skills, 12 rules, 3 templates, 31 snippets, 69 examples, and 80 showcase pieces** for Blender Python development targeting Blender 5.2 LTS (current stable) with Blender 4.5 LTS fallback support. Blender 5.1 is prior stable.
47+
This repository ships **25 skills, 16 rules, 3 templates, 31 snippets, 69 examples, and 80 showcase pieces** for Blender Python development targeting Blender 5.2 LTS (current stable) with Blender 4.5 LTS fallback support. Blender 5.1 is prior stable.
4848

4949
The content is consumed by AI coding agents, installed as a plugin or read from a checkout. An optional second plugin registers the official [Blender Lab MCP server](https://www.blender.org/lab/mcp-server/) for live sessions (see [Live Blender session](#live-blender-session-mcp)); the server is referenced from upstream, not part of this repository, and nothing else depends on it. Cursor and Claude Code both install it as a plugin (see [Quick start](#quick-start)): Cursor loads the skills and applies `rules/*.mdc` wherever their scope globs match; Claude Code loads the skills and gets the rules through a generated `blender-rules` skill, since it does not read Cursor `.mdc` files. An agent picks a skill up when its description matches the task. Any agent that can read files in a workspace can use it the same way. There is no build step for the content — edit the Markdown and Python files directly.
5050

5151
| Layer | Role |
5252
| --- | --- |
5353
| **Skills** | Guided workflows: scaffolding, operators, panels, properties, mesh and bmesh, headless batch, slotted actions, geometry nodes, procedural materials, depsgraph queries, drivers and handlers, `bl_info` migration, video sequencer, imported-mesh cleanup, high-to-low baking, engine export presets, extension runtime and packaging, timers, modal operators and threading, GPU drawing and viewport overlays, porting add-ons to Blender 5, Grease Pencil v3, constraints and parenting, images and pixels, curves and text, compositor nodes |
54-
| **Rules** | Guardrails for the most common AI mistakes: ops-in-loops, bmesh leaks, legacy `bl_info` only, prop assignments, deprecated context-copy override, per-element loops over bulk mesh data, import without scale check, export without evaluated geometry, mixed glTF/FBX axis RNA, and the 5.x removals: `bgl`, the pre-4.1 normals API, `sequence_editor.sequences` |
54+
| **Rules** | Guardrails for the most common AI mistakes: ops-in-loops, bmesh leaks, legacy `bl_info` only, prop assignments, deprecated context-copy override, per-element loops over bulk mesh data, import without scale check, export without evaluated geometry, mixed glTF/FBX axis RNA, and the 5.x breaks: `bgl`, the pre-4.1 normals API, `sequence_editor.sequences`, `action.fcurves`, 3.x Principled socket names, NodesModifier ID-property inputs, the EEVEE engine id |
5555
| **Templates** | A working Extensions Platform add-on starter, a headless batch script starter, and a GLB-in engine-ready asset pipeline |
5656
| **Snippets** | 31 small standalone Python files demonstrating canonical patterns, 5 to 75 lines each |
5757
| **Examples** | Runnable headless scripts under [`examples/`](examples/). Each asserts an API contract and exits non-zero on failure. |
@@ -61,7 +61,7 @@ The content is consumed by AI coding agents, installed as a plugin or read from
6161

6262
Neither agent needs a clone of `main`: both install the slim `plugin-dist` build. Clone the full repository only to [run the examples or contribute](#run-the-examples-or-contribute).
6363

64-
- **Cursor** — install it as a local plugin from the slim `plugin-dist` branch, then run **Developer: Reload Window**. **Customize** lists the 25 skills and 12 rules; the rules apply by glob scope and the agent loads a skill when its description matches the task.
64+
- **Cursor** — install it as a local plugin from the slim `plugin-dist` branch, then run **Developer: Reload Window**. **Customize** lists the 25 skills and 16 rules; the rules apply by glob scope and the agent loads a skill when its description matches the task.
6565

6666
```bash
6767
git clone --branch plugin-dist --single-branch https://github.com/TMHSDigital/Blender-Developer-Tools.git ~/.cursor/plugins/local/blender-developer-tools
@@ -198,7 +198,7 @@ Browse both, with filters, full-size renders and each script's README, in the **
198198

199199
```
200200
skills/<name>/SKILL.md - 25 skill files, YAML frontmatter, one canonical pattern each
201-
rules/<name>.mdc - 12 rule files, anti-pattern + correction
201+
rules/<name>.mdc - 16 rule files, anti-pattern + correction
202202
templates/<name>/ - 3 template directories (extension-addon-template, headless-batch-script-template, ai-asset-pipeline-template)
203203
snippets/<name>.py - 31 standalone Python snippets, 5 to 75 lines each
204204
examples/<name>/ - 69 example directories: script, README with exit codes and falsifier
@@ -208,7 +208,7 @@ claude/ - generated Claude Code copies of the rules (blender-ru
208208

209209
## Using rules in Cursor
210210

211-
With the Cursor plugin installed, the `.mdc` files in `rules/` apply automatically when Cursor opens a Blender Python project, scoped by the `globs` in each rule's frontmatter. The 12 rules are:
211+
With the Cursor plugin installed, the `.mdc` files in `rules/` apply automatically when Cursor opens a Blender Python project, scoped by the `globs` in each rule's frontmatter. The 16 rules are:
212212

213213
- `prefer-data-over-ops-in-loops`: flags `bpy.ops.*` calls inside object iteration
214214
- `always-free-bmesh`: flags `bmesh.new()` without paired `bm.free()` in `try`/`finally`
@@ -222,6 +222,10 @@ With the Cursor plugin installed, the `.mdc` files in `rules/` apply automatical
222222
- `no-bgl`: flags `import bgl` or any `bgl.` call (removed in 5.x; the add-on fails to register)
223223
- `no-removed-normals-api`: flags `use_auto_smooth`, `auto_smooth_angle`, `calc_normals_split()` and the other normals calls removed in 4.1
224224
- `no-legacy-vse-sequences`: flags `sequence_editor.sequences` / `.sequences_all` (removed in 5.x; `.strips` / `.strips_all` exist on 4.5 too)
225+
- `no-legacy-action-fcurves`: flags `action.fcurves`, `action.groups` and `action.id_root` (removed in 5.0; reach F-curves through the slot's channelbag)
226+
- `principled-v2-socket-names`: flags Principled BSDF inputs by 3.x name (`Emission`, `Specular`, `Clearcoat`, ...) or by index (renamed in 4.0)
227+
- `no-nodes-modifier-idprop-inputs`: flags `mod["Socket_N"] = value` on a Geometry Nodes modifier without a 5.2 version branch (the dict write raises on 5.2)
228+
- `branch-eevee-engine-id`: flags a literal `'BLENDER_EEVEE_NEXT'` / `'BLENDER_EEVEE'` engine id without a 5.0 version branch
225229

226230
Cursor: the plugin covers the rules (see [Quick start](#quick-start)); copying `rules/*.mdc` into a project's `.cursor/rules/` is only the per-project alternative without the plugin. Claude Code: the plugin ships the rules as the `blender-rules` skill.
227231

‎ROADMAP.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ derives the actual version from conventional-commit types.
3939
| Porting snippets and the legacy VSE `.sequences` rule | 20 | 12 | 3 | 31 | Shipped |
4040
| Skills for stranded examples: Grease Pencil v3, constraints and parenting, images and pixels, curves and text, compositor nodes | 25 | 12 | 3 | 31 | Shipped |
4141
| Live-session bridge (opt-in `blender-live-session` plugin, upstream Blender Lab MCP) | - | - | - | - | Shipped |
42+
| Rules for the headline 5.x breaks: `action.fcurves`, Principled v2 socket names, NodesModifier ID-property inputs, the EEVEE engine id | 25 | 16 | 3 | 31 | Shipped |
4243
| Stable (1.0) | — | — | — | — | Upcoming; criteria below |
4344

4445
## What "Stable (1.0)" means

‎claude/blender-rules.md‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,36 @@ Flag bmesh.new() calls without a paired bm.free() in a try/finally block. Blende
1111

1212
Applies to: `**/*.py`. Full rule: [`rules/always-free-bmesh.mdc`](https://github.com/TMHSDigital/Blender-Developer-Tools/blob/main/rules/always-free-bmesh.mdc).
1313

14+
## branch-eevee-engine-id
15+
16+
Flag `render.engine = 'BLENDER_EEVEE_NEXT'` or `= 'BLENDER_EEVEE'` written without a version branch. EEVEE Next used the id 'BLENDER_EEVEE_NEXT' on 4.2 through 4.5 LTS and took back 'BLENDER_EEVEE' in 5.0; each id raises TypeError (enum not found) on the other side. Branch on bpy.app.version >= (5, 0, 0). See the procedural-materials-and-shaders skill.
17+
18+
Applies to: `**/*.py`. Full rule: [`rules/branch-eevee-engine-id.mdc`](https://github.com/TMHSDigital/Blender-Developer-Tools/blob/main/rules/branch-eevee-engine-id.mdc).
19+
1420
## no-bgl
1521

1622
Flag `import bgl` and any `bgl.` call. The `bgl` OpenGL wrapper was deprecated in 3.x and is gone in Blender 5.x (`importlib.util.find_spec('bgl')` is `None` on 5.0, 5.1 and 5.2), so an add-on that imports it fails to register. Draw with the `gpu` module, `gpu.state` and `gpu_extras.batch` instead; see the gpu-drawing-and-overlays skill.
1723

1824
Applies to: `**/*.py`. Full rule: [`rules/no-bgl.mdc`](https://github.com/TMHSDigital/Blender-Developer-Tools/blob/main/rules/no-bgl.mdc).
1925

26+
## no-legacy-action-fcurves
27+
28+
Flag `action.fcurves`, `action.groups` and `action.id_root` on an Action. Blender 5.0 removed the flat legacy Action API (AttributeError on 5.x); F-curves live in a channelbag per slot. On 4.4/4.5 LTS the legacy path still runs but is a trap on a fresh Action (it creates a slot without binding it). Reach F-curves through the slot's channelbag, or use obj.keyframe_insert. See the slotted-actions-animation skill.
29+
30+
Applies to: `**/*.py`. Full rule: [`rules/no-legacy-action-fcurves.mdc`](https://github.com/TMHSDigital/Blender-Developer-Tools/blob/main/rules/no-legacy-action-fcurves.mdc).
31+
2032
## no-legacy-vse-sequences
2133

2234
Flag `sequence_editor.sequences` and `.sequences_all`. Both are gone in Blender 5.x (AttributeError on 5.0, 5.1 and 5.2), while `.strips` and `.strips_all` already exist on 4.5 LTS, so use those everywhere with no version branch. See the vse-python skill.
2335

2436
Applies to: `**/*.py`. Full rule: [`rules/no-legacy-vse-sequences.mdc`](https://github.com/TMHSDigital/Blender-Developer-Tools/blob/main/rules/no-legacy-vse-sequences.mdc).
2537

38+
## no-nodes-modifier-idprop-inputs
39+
40+
Flag writing a Geometry Nodes modifier input as an ID property (`mod["Socket_2"] = value`, `mod[identifier] = value`) without a version branch. Blender 5.2 removed that form (it raises TypeError, id properties not supported for this type); 5.2+ writes `getattr(mod.properties.inputs, identifier).value`, which does not exist on 4.5 LTS or 5.1. Branch on bpy.app.version >= (5, 2, 0). See the geometry-nodes-python skill.
41+
42+
Applies to: `**/*.py`. Full rule: [`rules/no-nodes-modifier-idprop-inputs.mdc`](https://github.com/TMHSDigital/Blender-Developer-Tools/blob/main/rules/no-nodes-modifier-idprop-inputs.mdc).
43+
2644
## no-removed-normals-api
2745

2846
Flag the mesh normals API removed in Blender 4.1 — `use_auto_smooth`, `auto_smooth_angle`, `calc_normals_split()`, `free_normals_split()`, `create_normals_split()`. Each raises AttributeError on 4.5 LTS and 5.x. Use `Mesh.set_sharp_from_angle`, `object.shade_auto_smooth`, and `Mesh.corner_normals` (always current) instead.
@@ -47,6 +65,12 @@ Flag uses of `bpy.context.copy()` to override context for an operator call. Pass
4765

4866
Applies to: `**/*.py`. Full rule: [`rules/prefer-temp-override-over-context-copy.mdc`](https://github.com/TMHSDigital/Blender-Developer-Tools/blob/main/rules/prefer-temp-override-over-context-copy.mdc).
4967

68+
## principled-v2-socket-names
69+
70+
Flag Principled BSDF inputs looked up by their 3.x names (`inputs["Emission"]`, `["Specular"]`, `["Clearcoat"]`, `["Subsurface"]`, `["Transmission"]`, `["Sheen"]`) or by index. Principled v2 (Blender 4.0) renamed them, so they raise KeyError on 4.5 LTS and 5.x. Use the 4.0+ names (`Emission Color`, `Specular IOR Level`, `Coat Weight`, ...), which need no version branch. See the procedural-materials-and-shaders skill.
71+
72+
Applies to: `**/*.py`. Full rule: [`rules/principled-v2-socket-names.mdc`](https://github.com/TMHSDigital/Blender-Developer-Tools/blob/main/rules/principled-v2-socket-names.mdc).
73+
5074
## target-extensions-platform-format
5175

5276
Flag new Blender add-ons that ship only a legacy bl_info dict without a blender_manifest.toml. New add-ons must use the Extensions Platform format. bl_info may appear alongside as a fallback for backward compatibility, but the manifest is the source of truth.

0 commit comments

Comments
 (0)