Skip to content

Commit b293ccb

Browse files
feat: AI asset pipeline track, Phase 1 (#132)
* docs: add the AI asset pipeline as a multi-version track Four sub-tracks (cleanup skills, engine export presets, headless template, live-session spike) listed as upcoming and unpinned, matching existing cadence. Signed-off-by: TMHSDigital <154358121+TMHSDigital@users.noreply.github.com> Co-authored-by: Cursor <cursoragent@cursor.com> * feat: add decimate, collider, LOD, and Draco glTF snippets Standalone helpers for evaluated triangle budgets, convex hull colliders, LOD chains, and Draco-compressed glTF export. LOD duplicates the decimate helper because snippets are not a package. calc_loop_triangles is always called; tessellation is still explicit on 4.5 LTS and 5.x. Signed-off-by: TMHSDigital <154358121+TMHSDigital@users.noreply.github.com> Co-authored-by: Cursor <cursoragent@cursor.com> * feat: add ai-mesh-cleanup skill Canonical ordered cleanup for an imported generated mesh: units, transform apply, origin, normals, evaluated triangle count, decimate, collider. Composes depsgraph and bmesh skills; does not generate meshes. Signed-off-by: TMHSDigital <154358121+TMHSDigital@users.noreply.github.com> Co-authored-by: Cursor <cursoragent@cursor.com> * feat: add imported-scale and unevaluated-export rules Catch glTF/FBX import plus mesh work with no transform_apply and no unit check, and export of live modifiers without export_apply or evaluation_mode. Signed-off-by: TMHSDigital <154358121+TMHSDigital@users.noreply.github.com> Co-authored-by: Cursor <cursoragent@cursor.com> * ci: gate import-scale and unevaluated-export anti-patterns Static scan of snippets and templates so the two new rules fail on a deliberate canary, not only on good input. examples/ is excluded because pathology witnesses are intentional. Signed-off-by: TMHSDigital <154358121+TMHSDigital@users.noreply.github.com> Co-authored-by: Cursor <cursoragent@cursor.com> * docs: update inventory counts for the cleanup track README, CLAUDE.md, AGENTS.md, and plugin.json now list 14 skills, 8 rules, and 21 snippets so validate-counts and validate-manifest stay aligned. 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>
1 parent 40cc04e commit b293ccb

14 files changed

Lines changed: 701 additions & 20 deletions

.cursor-plugin/plugin.json

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
],
1616
"skills": [
1717
"skills/addon-scaffolding/SKILL.md",
18+
"skills/ai-mesh-cleanup/SKILL.md",
1819
"skills/operators/SKILL.md",
1920
"skills/ui-panels/SKILL.md",
2021
"skills/custom-properties/SKILL.md",
@@ -34,19 +35,25 @@
3435
"rules/target-extensions-platform-format.mdc",
3536
"rules/type-annotate-props-and-defend-context.mdc",
3637
"rules/prefer-temp-override-over-context-copy.mdc",
37-
"rules/use-foreach-set-for-bulk-data.mdc"
38+
"rules/use-foreach-set-for-bulk-data.mdc",
39+
"rules/validate-imported-mesh-scale.mdc",
40+
"rules/no-unapplied-modifiers-on-export.mdc"
3841
],
3942
"snippets": [
4043
"snippets/action-ensure-channelbag-for-slot.py",
4144
"snippets/app-handler-registration.py",
4245
"snippets/bmesh-load-edit-free.py",
4346
"snippets/canonical-object-creation.py",
4447
"snippets/canonical-object-deletion.py",
48+
"snippets/convex_hull_collider.py",
4549
"snippets/cross-version-property-delete.py",
50+
"snippets/decimate_to_budget.py",
4651
"snippets/depsgraph-evaluated-mesh.py",
4752
"snippets/driver-with-custom-function.py",
4853
"snippets/foreach-get-vertices.py",
4954
"snippets/foreach-set-vertices.py",
55+
"snippets/gltf_draco_export.py",
56+
"snippets/lod_chain.py",
5057
"snippets/pointerproperty-binding.py",
5158
"snippets/principled-bsdf-material.py",
5259
"snippets/register-classes-factory.py",

.github/workflows/validate.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,9 @@ jobs:
130130
fi
131131
echo "All snippets have valid Python syntax."
132132
133+
- name: Check import-scale and unevaluated-export anti-patterns
134+
run: python3 tests/check_import_export_rules.py
135+
133136
- name: Validate template Python syntax
134137
run: |
135138
echo "Checking template Python syntax..."

AGENTS.md

Lines changed: 4 additions & 4 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 13 skills, 6 rules, 2 templates, 17 snippets, and 53
23+
The content base is 14 skills, 8 rules, 2 templates, 21 snippets, and 53
2424
examples (counts are CI-enforced against README.md and the manifest). The full
2525
inventory tables and per-item purposes live in `CLAUDE.md`. Example anatomy
2626
and authoring rules: copy `examples/bmesh-gear/`; the render look is specified
@@ -31,10 +31,10 @@ in `docs/VISUAL-STYLE.md`; the canonical run prompt is
3131

3232
```
3333
Blender-Developer-Tools/
34-
skills/<skill-name>/SKILL.md # 13 skill files
35-
rules/<rule-name>.mdc # 6 rule files
34+
skills/<skill-name>/SKILL.md # 14 skill files
35+
rules/<rule-name>.mdc # 8 rule files
3636
templates/<template-name>/ # 2 starter templates
37-
snippets/<snippet-name>.py # 17 standalone Python snippets
37+
snippets/<snippet-name>.py # 21 standalone Python snippets
3838
examples/<name>/ # 53 runnable smoke-gated examples (+ gallery.json)
3939
examples/gallery_framing.py # shared Layer 1 framing measurement (render path only)
4040
scripts/build_gallery.py # generates docs/gallery/ (stdlib only)

CLAUDE.md

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,22 +17,23 @@ The **Blender Developer Tools** repository is at **v0.53.0**. It packages skills
1717
## Repository Architecture
1818

1919
```
20-
skills/<skill-name>/SKILL.md - AI workflow definitions, 13 total
21-
rules/<rule-name>.mdc - Anti-pattern rules, 6 total
20+
skills/<skill-name>/SKILL.md - AI workflow definitions, 14 total
21+
rules/<rule-name>.mdc - Anti-pattern rules, 8 total
2222
templates/<template-name>/ - Starter projects, 2 total
23-
snippets/<snippet-name>.py - Standalone code patterns, 17 total
23+
snippets/<snippet-name>.py - Standalone code patterns, 21 total
2424
examples/<name>/ - Runnable smoke-gated examples, 53 total (+ gallery.json)
2525
scripts/build_gallery.py - Regenerates docs/gallery/ from gallery.json (stdlib only)
2626
scripts/site/ - Vendored landing-page build (Jinja2)
2727
docs/gallery/ - Committed generated gallery pages + hero renders
2828
VERSION - Source of truth for the repo version
2929
```
3030

31-
## Skills (13)
31+
## Skills (14)
3232

3333
| Skill | Purpose |
3434
| --- | --- |
3535
| addon-scaffolding | Extensions Platform manifest, file layout, register/unregister symmetry |
36+
| ai-mesh-cleanup | Ordered cleanup for imported generated meshes: units, transform apply, origin, normals, budget, collider |
3637
| operators | `bpy.types.Operator` lifecycle, `bl_idname`, redo, defensive context handling |
3738
| ui-panels | `bpy.types.Panel` declarative `draw()`, layout primitives, conditional UI |
3839
| custom-properties | `bpy.props` annotations, PropertyGroup, PointerProperty, storage tradeoffs |
@@ -46,7 +47,7 @@ VERSION - Source of truth for the repo version
4647
| bl-info-migration | Three-step migration from legacy `bl_info` to Extensions Platform, dual-format pattern |
4748
| vse-python | VSE timeline from Python: `.strips` vs `.sequences`, `new_effect` kwargs, 5.2 COLOR `width`/`height` bake |
4849

49-
## Rules (6)
50+
## Rules (8)
5051

5152
| Rule | Scope | What it flags |
5253
| --- | --- | --- |
@@ -56,6 +57,8 @@ VERSION - Source of truth for the repo version
5657
| type-annotate-props-and-defend-context | `*.py` | `bpy.props` defined as assignments, unguarded `context.active_object` |
5758
| prefer-temp-override-over-context-copy | `*.py` | `bpy.context.copy()` passed to operators (deprecated 4.x, removed 5.x) |
5859
| use-foreach-set-for-bulk-data | `*.py` | Python loops over `mesh.vertices` setting bulk attributes one at a time |
60+
| validate-imported-mesh-scale | `*.py` | glTF/FBX import then mesh work with no `transform_apply` and no unit-scale check |
61+
| no-unapplied-modifiers-on-export | `*.py` | Export with live modifiers when the export does not request evaluated geometry |
5962

6063
## Templates (2)
6164

@@ -75,14 +78,16 @@ VERSION - Source of truth for the repo version
7578
- glTF export via `bpy.ops.export_scene.gltf`
7679
- Explicit exit codes for CI integration
7780

78-
## Snippets (17)
81+
## Snippets (21)
7982

8083
Small standalone `.py` files at `snippets/<name>.py`, each 5 to 50 lines.
8184

8285
v0.1.0: canonical object creation and deletion, depsgraph evaluated mesh, bmesh load-edit-free, temp_override context, foreach_set vertex bulk write, register_classes_factory, PointerProperty binding, cross-version property delete, and the `action_ensure_channelbag_for_slot` slotted-actions bridge.
8386

8487
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'`.
8588

89+
AI asset pipeline track: `decimate_to_budget.py`, `convex_hull_collider.py`, `lod_chain.py` (helper duplicated, not imported), `gltf_draco_export.py`.
90+
8691
## Examples (53)
8792

8893
Runnable scripts at `examples/<name>/`, each asserting a real API contract with

README.md

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
</p>
1919

2020
<p align="center">
21-
<strong>13 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>53 examples</strong>
21+
<strong>14 skills</strong> &nbsp;&bull;&nbsp; <strong>8 rules</strong> &nbsp;&bull;&nbsp; <strong>2 templates</strong> &nbsp;&bull;&nbsp; <strong>21 snippets</strong> &nbsp;&bull;&nbsp; <strong>53 examples</strong>
2222
</p>
2323

2424
<p align="center">
@@ -36,16 +36,16 @@
3636

3737
## Overview
3838

39-
This repository ships **13 skills, 6 rules, 2 templates, 17 snippets, and 48 runnable 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 **14 skills, 8 rules, 2 templates, 21 snippets, and 53 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.
4040

4141
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.
4242

4343
| Layer | Role |
4444
| --- | --- |
45-
| **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 |
46-
| **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 |
45+
| **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 |
46+
| **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 |
4747
| **Templates** | A working Extensions Platform add-on starter and a headless batch script starter |
48-
| **Snippets** | 17 small standalone Python files demonstrating canonical patterns |
48+
| **Snippets** | 21 small standalone Python files demonstrating canonical patterns |
4949

5050
## Quick start
5151

@@ -1008,22 +1008,24 @@ the duplicates, then glTF ships 24 tris / 48 positions / 8 unique.
10081008
## How content is organized
10091009

10101010
```
1011-
skills/<name>/SKILL.md - 13 skill files, YAML frontmatter, one canonical pattern each
1012-
rules/<name>.mdc - 6 rule files, anti-pattern + correction
1011+
skills/<name>/SKILL.md - 14 skill files, YAML frontmatter, one canonical pattern each
1012+
rules/<name>.mdc - 8 rule files, anti-pattern + correction
10131013
templates/<name>/ - 2 template directories (extension-addon-template, headless-batch-script-template)
1014-
snippets/<name>.py - 17 standalone Python snippets, 5 to 50 lines each
1014+
snippets/<name>.py - 21 standalone Python snippets, 5 to 50 lines each
10151015
```
10161016

10171017
## Using rules in Cursor
10181018

1019-
The `.mdc` files in `rules/` apply automatically when Cursor opens a Blender Python project, scoped by the `globs` in each rule's frontmatter. The six rules are:
1019+
The `.mdc` files in `rules/` apply automatically when Cursor opens a Blender Python project, scoped by the `globs` in each rule's frontmatter. The eight rules are:
10201020

10211021
- `prefer-data-over-ops-in-loops`: flags `bpy.ops.*` calls inside object iteration
10221022
- `always-free-bmesh`: flags `bmesh.new()` without paired `bm.free()` in `try`/`finally`
10231023
- `target-extensions-platform-format`: flags add-ons missing `blender_manifest.toml`
10241024
- `type-annotate-props-and-defend-context`: flags `bpy.props` assignment form and unguarded `context.active_object`
10251025
- `prefer-temp-override-over-context-copy`: flags `bpy.context.copy()` passed to operators (deprecated 4.x, removed 5.x)
10261026
- `use-foreach-set-for-bulk-data`: flags Python loops over `mesh.vertices` setting `co`, normals, or other per-element bulk data
1027+
- `validate-imported-mesh-scale`: flags glTF/FBX import then mesh work with no `transform_apply` and no unit-scale check
1028+
- `no-unapplied-modifiers-on-export`: flags export of objects with live modifiers when the export does not request evaluated geometry
10271029

10281030
Symlink or clone this repo, then point Cursor at it as a skills/rules source.
10291031

ROADMAP.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ derives the actual version from conventional-commit types.
1818
| 5.2 LTS targeting, GN modifier inputs | 12 | 6 | 2 | 17 | Shipped |
1919
| VSE COLOR strip intrinsic size (undocumented 5.2) | 13 | 6 | 2 | 17 | Shipped |
2020
| Modal operators, USD, mathutils ||||| Upcoming |
21+
| AI asset pipeline: post-generation cleanup | - | - | - | - | Upcoming |
22+
| AI asset pipeline: engine export presets | - | - | - | - | Upcoming |
23+
| AI asset pipeline: headless template | - | - | - | - | Upcoming |
24+
| AI asset pipeline: live-session bridge (spike) | - | - | - | - | Upcoming |
2125
| Stable ||||| Upcoming |
2226

2327
## v0.1.0 - Foundation
@@ -87,6 +91,15 @@ The 7 new snippets:
8791

8892
Audit pass on v0.1.0 content: standards-version markers bumped from `1.9.1` to `1.9.4` across all skills, rules, AGENTS.md, CLAUDE.md, and ROADMAP.md. Verified the `bpy_extras.anim_utils.action_ensure_channelbag_for_slot` import path against the current Blender 5.1 API reference and removed the stale "verify before production" caveat in `slotted-actions-animation/SKILL.md`.
8993

94+
## AI asset pipeline track
95+
96+
Provider-agnostic GLB-in / engine-ready-out. This repo does not generate meshes.
97+
98+
- **Post-generation cleanup skills** (this phase starts the family; bake/UV/atlas follow on): import and unit-scale normalization, transform apply and origin, poly-budget decimate, LOD chain, collision mesh, high-to-low bake, UV transfer and atlas packing. Phase 1: `ai-mesh-cleanup`, four snippets, two rules.
99+
- **Engine export presets.** Unity (Y-up), Godot, and Unreal (centimeter scale) glTF and FBX paths with Draco. One skill, one snippet set.
100+
- **`ai-asset-pipeline-template/`.** Third template. Headless: GLB path in; LOD set, convex collider, engine-preset export; explicit CI exit codes. Pattern: `templates/headless-batch-script-template/`. Phase 2.
101+
- **Live-session agent bridge.** Research spike, not a committed deliverable. MCP server or socket listener so an agent can execute against a running Blender instance instead of blind `--background` scripts. Built on `templates/extension-addon-template/`. Needs its own design pass.
102+
90103
## Candidate pool (next content)
91104

92105
Not committed; target list for the next content version. (v0.3.0 shipped the smoke-gated `examples/` track.)
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
---
2+
description: Flag an export call on objects that still carry unapplied modifiers when the export arguments do not request evaluated geometry. The engine then receives the authored cage, not the modifier result.
3+
alwaysApply: true
4+
globs:
5+
- "**/*.py"
6+
standards-version: 1.10.0
7+
---
8+
9+
# No unapplied modifiers on export
10+
11+
`obj.data` is the authored mesh. DECIMATE, subdivision, and geometry nodes
12+
live in the depsgraph. An export that does not ask for evaluated geometry
13+
writes the cage: the LOD modifier is dropped, the engine gets the dense
14+
mesh, and the script still exits 0.
15+
16+
glTF: `export_apply=True` applies modifiers excluding armatures.
17+
USD: `evaluation_mode='RENDER'` or `'VIEWPORT'`.
18+
FBX: `use_mesh_modifiers=True`.
19+
20+
`export_apply` is not "apply object transforms". Apply object scale first.
21+
See rule `validate-imported-mesh-scale`.
22+
23+
## What this rule flags
24+
25+
A `bpy.ops.export_scene.gltf`, `bpy.ops.export_scene.fbx`, or
26+
`bpy.ops.wm.usd_export` call in a file that adds modifiers (`modifiers.new`)
27+
and never requests evaluated geometry (`export_apply=True` or
28+
`evaluation_mode=`), and never applies those modifiers before export.
29+
30+
```python
31+
# WRONG: DECIMATE on the object, glTF without export_apply
32+
mod = obj.modifiers.new("Lod", "DECIMATE")
33+
mod.decimate_type = "COLLAPSE"
34+
mod.ratio = 0.25
35+
bpy.ops.export_scene.gltf(filepath=path, use_selection=True)
36+
```
37+
38+
```python
39+
# WRONG: USD viewport/render mode omitted; default BEST_MATCH writes the cage
40+
obj.modifiers.new("ss", "SUBSURF").levels = 2
41+
bpy.ops.wm.usd_export(filepath=path)
42+
```
43+
44+
## The required pattern
45+
46+
```python
47+
import bpy
48+
49+
mod = obj.modifiers.new("DecimateBudget", "DECIMATE")
50+
mod.decimate_type = "COLLAPSE"
51+
mod.ratio = 0.25
52+
53+
bpy.ops.export_scene.gltf(
54+
filepath=path,
55+
use_selection=True,
56+
export_apply=True,
57+
export_yup=True,
58+
)
59+
```
60+
61+
USD:
62+
63+
```python
64+
bpy.ops.wm.usd_export(
65+
filepath=path,
66+
evaluation_mode="RENDER",
67+
export_subdivision="TESSELLATE",
68+
)
69+
```
70+
71+
Alternatively apply the modifier before export with `temp_override` and
72+
`bpy.ops.object.modifier_apply`. Either path is valid; omitting both is not.
73+
74+
## Why it matters
75+
76+
A live DECIMATE that never ships is the usual LOD bug: Blender's viewport
77+
shows the reduced mesh, the glTF still has the source triangle count, and
78+
the engine budget check fails in production. `examples/lod-decimate-chain/`
79+
shows the modifier is non-destructive on `obj.data`; export must opt in to
80+
the evaluated result.
81+
82+
## Related
83+
84+
- Skill `ai-mesh-cleanup`
85+
- Skill `depsgraph-and-evaluated-data`
86+
- Snippet `gltf_draco_export.py`
87+
- Snippet `usd-export-evaluation-mode.py`
88+
- Example `lod-decimate-chain`
89+
- `bpy.ops.export_scene.gltf`: https://docs.blender.org/api/current/bpy.ops.export_scene.html#bpy.ops.export_scene.gltf

0 commit comments

Comments
 (0)