Skip to content

Commit b5d5893

Browse files
feat: AI asset pipeline track, Phase 3 (pipeline template) (#135)
* feat: add GLB-in engine-ready AI asset pipeline template Headless entry point composing cleanup, LOD, collider, and engine-preset export. Helpers are duplicated from the named snippets because templates are not a package. Signed-off-by: TMHSDigital <154358121+TMHSDigital@users.noreply.github.com> Co-authored-by: Cursor <cursoragent@cursor.com> * ci: smoke the AI asset pipeline template on 4.5 and 5.2 Same blender-smoke.yml pattern as the headless glTF template: generate a fixture, assert exit 0 and glTF magic, then assert missing-input exit 2. Does not add 5.1 to the PR matrix. Signed-off-by: TMHSDigital <154358121+TMHSDigital@users.noreply.github.com> Co-authored-by: Cursor <cursoragent@cursor.com> * docs: mark the AI asset pipeline template sub-track delivered Inventory counts go to 3 templates. The live-session agent bridge stays unpinned. 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 0a0a0a0 commit b5d5893

9 files changed

Lines changed: 587 additions & 10 deletions

File tree

‎.cursor-plugin/plugin.json‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@
6868
"snippets/version-branch-skeleton.py"
6969
],
7070
"templates": [
71+
"templates/ai-asset-pipeline-template",
7172
"templates/extension-addon-template",
7273
"templates/headless-batch-script-template"
7374
],

‎.github/workflows/blender-smoke.yml‎

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,39 @@ jobs:
122122
[ "$code" -eq 2 ] || { echo "::error::expected exit 2 for no-mesh input, got $code"; exit 1; }
123123
echo "no-mesh exit code = $code (correct)"
124124
125+
- name: Build pipeline template fixture GLB
126+
run: |
127+
set -euo pipefail
128+
xvfb-run -a "$BLENDER" --background --python tests/smoke/make_pipeline_glb.py -- \
129+
"$RUNNER_TEMP/out/pipeline_src.glb"
130+
test -s "$RUNNER_TEMP/out/pipeline_src.glb" || { echo "::error::pipeline fixture missing"; exit 1; }
131+
132+
- name: Headless AI asset pipeline template runs (exit 0, LODs produced)
133+
run: |
134+
set -euo pipefail
135+
mkdir -p "$RUNNER_TEMP/out/pipeline"
136+
xvfb-run -a "$BLENDER" --background --python templates/ai-asset-pipeline-template/pipeline.py -- \
137+
--input "$RUNNER_TEMP/out/pipeline_src.glb" \
138+
--outdir "$RUNNER_TEMP/out/pipeline" \
139+
--preset unity \
140+
--lod-budgets 1024,256,64 \
141+
--collider convex
142+
test -s "$RUNNER_TEMP/out/pipeline/lod0.glb" || { echo "::error::lod0 missing/empty"; exit 1; }
143+
test -s "$RUNNER_TEMP/out/pipeline/collider.glb" || { echo "::error::collider missing/empty"; exit 1; }
144+
head -c4 "$RUNNER_TEMP/out/pipeline/lod0.glb" | grep -q "glTF" || { echo "::error::lod0 not a glTF binary"; exit 1; }
145+
146+
- name: Headless pipeline template missing input returns exit 2
147+
run: |
148+
set +e
149+
xvfb-run -a "$BLENDER" --background --python templates/ai-asset-pipeline-template/pipeline.py -- \
150+
--input "$RUNNER_TEMP/out/does-not-exist.glb" \
151+
--outdir "$RUNNER_TEMP/out/pipeline" \
152+
--preset unity
153+
code=$?
154+
set -e
155+
[ "$code" -eq 2 ] || { echo "::error::expected exit 2 for missing input, got $code"; exit 1; }
156+
echo "missing-input exit code = $code (correct)"
157+
125158
- name: Headless render template runs (exit 0, PNG produced)
126159
run: |
127160
set -euo pipefail

‎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 15 skills, 9 rules, 2 templates, 24 snippets, and 54
23+
The content base is 15 skills, 9 rules, 3 templates, 24 snippets, and 54
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
@@ -33,7 +33,7 @@ in `docs/VISUAL-STYLE.md`; the canonical run prompt is
3333
Blender-Developer-Tools/
3434
skills/<skill-name>/SKILL.md # 15 skill files
3535
rules/<rule-name>.mdc # 9 rule files
36-
templates/<template-name>/ # 2 starter templates
36+
templates/<template-name>/ # 3 starter templates
3737
snippets/<snippet-name>.py # 24 standalone Python snippets
3838
examples/<name>/ # 54 runnable smoke-gated examples (+ gallery.json)
3939
examples/gallery_framing.py # shared Layer 1 framing measurement (render path only)

‎CLAUDE.md‎

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ The **Blender Developer Tools** repository is at **v0.55.0**. It packages skills
1919
```
2020
skills/<skill-name>/SKILL.md - AI workflow definitions, 15 total
2121
rules/<rule-name>.mdc - Anti-pattern rules, 9 total
22-
templates/<template-name>/ - Starter projects, 2 total
22+
templates/<template-name>/ - Starter projects, 3 total
2323
snippets/<snippet-name>.py - Standalone code patterns, 24 total
2424
examples/<name>/ - Runnable smoke-gated examples, 54 total (+ gallery.json)
2525
scripts/build_gallery.py - Regenerates docs/gallery/ from gallery.json (stdlib only)
@@ -62,7 +62,7 @@ VERSION - Source of truth for the repo version
6262
| no-unapplied-modifiers-on-export | `*.py` | Export with live modifiers when the export does not request evaluated geometry |
6363
| use-correct-axis-rna-per-exporter | `*.py` | `export_scene.gltf` with FBX `axis_forward`/`axis_up`, or `export_scene.fbx` with glTF `export_yup` |
6464

65-
## Templates (2)
65+
## Templates (3)
6666

6767
`templates/extension-addon-template/` is a copy-paste-ready Blender extension demonstrating:
6868

@@ -80,6 +80,14 @@ VERSION - Source of truth for the repo version
8080
- glTF export via `bpy.ops.export_scene.gltf`
8181
- Explicit exit codes for CI integration
8282

83+
`templates/ai-asset-pipeline-template/` is a working starter for a headless GLB-in / engine-ready-out job:
84+
85+
- `argparse` parsing of args after the `--` separator
86+
- Import, unit-scale check, transform apply, origin, normals, evaluated tris
87+
- LOD chain and optional convex/box collider
88+
- Unity / Godot / Unreal glTF export via the engine-export-presets contract
89+
- Explicit exit codes matching `headless-batch-script-template` (0, then 2+)
90+
8391
## Snippets (24)
8492

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

‎README.md‎

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

2020
<p align="center">
21-
<strong>15 skills</strong> &nbsp;&bull;&nbsp; <strong>9 rules</strong> &nbsp;&bull;&nbsp; <strong>2 templates</strong> &nbsp;&bull;&nbsp; <strong>24 snippets</strong> &nbsp;&bull;&nbsp; <strong>54 examples</strong>
21+
<strong>15 skills</strong> &nbsp;&bull;&nbsp; <strong>9 rules</strong> &nbsp;&bull;&nbsp; <strong>3 templates</strong> &nbsp;&bull;&nbsp; <strong>24 snippets</strong> &nbsp;&bull;&nbsp; <strong>54 examples</strong>
2222
</p>
2323

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

3737
## Overview
3838

39-
This repository ships **15 skills, 9 rules, 2 templates, 24 snippets, and 54 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 **15 skills, 9 rules, 3 templates, 24 snippets, and 54 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
| --- | --- |
4545
| **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, engine export presets |
4646
| **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 |
47-
| **Templates** | A working Extensions Platform add-on starter and a headless batch script starter |
47+
| **Templates** | A working Extensions Platform add-on starter, a headless batch script starter, and a GLB-in engine-ready asset pipeline |
4848
| **Snippets** | 24 small standalone Python files demonstrating canonical patterns |
4949

5050
## Quick start
@@ -1026,7 +1026,7 @@ the duplicates, then glTF ships 24 tris / 48 positions / 8 unique.
10261026
```
10271027
skills/<name>/SKILL.md - 15 skill files, YAML frontmatter, one canonical pattern each
10281028
rules/<name>.mdc - 9 rule files, anti-pattern + correction
1029-
templates/<name>/ - 2 template directories (extension-addon-template, headless-batch-script-template)
1029+
templates/<name>/ - 3 template directories (extension-addon-template, headless-batch-script-template, ai-asset-pipeline-template)
10301030
snippets/<name>.py - 24 standalone Python snippets, 5 to 50 lines each
10311031
```
10321032

@@ -1052,6 +1052,8 @@ Symlink or clone this repo, then point Cursor at it as a skills/rules source.
10521052

10531053
`templates/headless-batch-script-template/` is a working starter for unattended Blender batch jobs. It opens a `.blend`, optionally adds and applies a modifier to every mesh, and exports to glTF, with explicit exit codes for CI integration. Run with `blender --background <input.blend> --python script.py -- --output ...`.
10541054

1055+
`templates/ai-asset-pipeline-template/` is a working starter for a headless GLB-in / engine-ready-out job. It imports a GLB, runs the `ai-mesh-cleanup` order, emits an LOD chain and optional collider, and exports under a Unity, Godot, or Unreal glTF preset. Run with `blender --background --python pipeline.py -- --input ... --outdir ... --preset unity`.
1056+
10551057
## Snippets
10561058

10571059
Each snippet is a standalone Python file under `snippets/`. They are not loaded as a package. Open one, copy the relevant lines into your script, and adapt the names. Each file's header comment cites the Blender doc URL or research section the pattern came from.

‎ROADMAP.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ derives the actual version from conventional-commit types.
2020
| Modal operators, USD, mathutils | — | — | — | — | Upcoming |
2121
| AI asset pipeline: post-generation cleanup | 14 | 8 | 2 | 21 | Shipped (v0.54.0) |
2222
| AI asset pipeline: engine export presets | 15 | 9 | 2 | 24 | Shipped |
23-
| AI asset pipeline: headless template | - | - | - | - | Upcoming |
23+
| AI asset pipeline: headless template | 15 | 9 | 3 | 24 | Shipped |
2424
| AI asset pipeline: live-session bridge (spike) | - | - | - | - | Upcoming |
2525
| Stable | — | — | — | — | Upcoming |
2626

@@ -97,7 +97,7 @@ Provider-agnostic GLB-in / engine-ready-out. This repo does not generate meshes.
9797

9898
- **Post-generation cleanup skills.** Import and unit-scale normalization, transform apply and origin, poly-budget decimate, LOD chain, collision mesh. Phase 1 shipped in v0.54.0 as `ai-mesh-cleanup`, four snippets, two rules. Bake/UV/atlas follow on.
9999
- **Engine export presets.** **Delivered.** Unity (Y-up glTF), Godot (Z-up glTF, meters), Unreal (centimeter glTF bake and FBX `global_scale`). Skill `engine-export-presets`, three snippets, rule `use-correct-axis-rna-per-exporter`, witness `examples/export-preset-axis/`. Draco remains opt-in via `gltf_draco_export.py`.
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 3. Unpinned.
100+
- **`ai-asset-pipeline-template/`.** **Delivered.** Third template. Headless: GLB path in; LOD set, convex or box collider, engine-preset export; explicit CI exit codes. Pattern: `templates/headless-batch-script-template/`.
101101
- **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. Unpinned.
102102

103103
## Candidate pool (next content)
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
# AI Asset Pipeline Template
2+
3+
A working starter for a headless Blender job that takes a GLB in and
4+
writes an engine-ready LOD set plus optional collider. Provider-agnostic:
5+
the input is a file path, not a generation vendor.
6+
7+
## Usage
8+
9+
```powershell
10+
blender --background --python pipeline.py -- `
11+
--input .\source.glb `
12+
--outdir .\out `
13+
--preset unity `
14+
--lod-budgets 1024,256,64 `
15+
--collider convex
16+
```
17+
18+
Linux / macOS:
19+
20+
```bash
21+
blender --background --python pipeline.py -- \
22+
--input ./source.glb \
23+
--outdir ./out \
24+
--preset unity \
25+
--lod-budgets 1024,256,64 \
26+
--collider convex
27+
```
28+
29+
The `--` separator is required. Everything before it is consumed by
30+
Blender (`--background`, `--python`). Everything after it is forwarded
31+
to `pipeline.py` as `sys.argv`.
32+
33+
Optional `--draco` enables glTF Draco compression on export.
34+
35+
`--preset` is one of `unity` (Y-up glTF), `godot` (Z-up glTF), `unreal`
36+
(centimeter glTF: 100x bake then `export_yup=True`). FBX for Unreal lives
37+
in `snippets/export_preset_unreal.py`; this template emits GLB so a CI
38+
job can check the `glTF` magic bytes the same way for every preset.
39+
40+
## What it does
41+
42+
1. Parses script-side args after `--`.
43+
2. Imports the GLB into an empty scene.
44+
3. Checks scene units (metric meters), applies object rotation/scale,
45+
sits the origin on the lowest Z, recalculates face normals, and
46+
prints the evaluated triangle count.
47+
4. Builds an LOD chain from `--lod-budgets`.
48+
5. Optionally builds a convex hull or AABB box collider.
49+
6. Exports each LOD (and the collider) under the chosen engine preset.
50+
7. Returns explicit exit codes so a CI pipeline can detect failures.
51+
52+
Cleanup order follows `ai-mesh-cleanup`. LOD, collider, and export
53+
helpers are duplicated from the snippets named in `pipeline.py`'s
54+
header; templates are not a package.
55+
56+
## Exit codes
57+
58+
Same convention as `templates/headless-batch-script-template/`
59+
(`script.py` / its README: 0 success, 2+ distinct failure modes;
60+
argparse usage errors also exit 2). Not a repo-wide table; examples such
61+
as `export-preset-axis` number their own checks independently.
62+
63+
| Code | Meaning |
64+
| --- | --- |
65+
| 0 | Success |
66+
| 2 | Input file missing, or argparse rejected the flags (including an unsupported `--preset`) |
67+
| 3 | Input is not a readable GLB (bad magic or import failure) |
68+
| 4 | `--lod-budgets` missing, non-positive, or not strictly decreasing |
69+
| 5 | Import produced no mesh |
70+
| 6 | `outdir` is not a directory, or glTF export failed / wrote no file |
71+
72+
## Expected environment
73+
74+
- Blender on the system `PATH` (or invoked by absolute path).
75+
- `--outdir` already exists. The script does not create it.
76+
- `--input` is a GLB with at least one mesh. With no meshes the script
77+
returns exit code 5.
78+
79+
## Common gotchas
80+
81+
- **Forgetting the `--`**. Blender treats the following args as its
82+
own and complains. The script never sees them.
83+
- **Output path with spaces on Windows**. Quote the whole path:
84+
`--outdir ".\out folder"`.
85+
- **Running without `--background`**. The script still works, but
86+
Blender opens a UI window and stays open after the script finishes.
87+
Use `--background` for unattended runs.
88+
- **Unreal mutates selected meshes** (100x scale bake). Each export
89+
selects one object. Do not re-export the same object as Unity afterward
90+
without restoring scale.
91+
- **Operators that need a 3D Viewport context**. Some operators only
92+
work when a `VIEW_3D` area exists. In headless mode, none does.
93+
Either rewrite using `bpy.data.*`, or fabricate a window+area via
94+
`temp_override` (advanced; see the `headless-batch-scripting` skill).
95+
96+
## Extending the template
97+
98+
This template covers one pipeline (import, clean, LOD, collider, export).
99+
For more complex workflows, factor each step into its own function and
100+
return early with distinct exit codes. The `main()` function is the
101+
orchestration point; everything else should be pure helpers.
102+
103+
## See also
104+
105+
- Skill `ai-mesh-cleanup` for the cleanup order.
106+
- Skill `engine-export-presets` for Unity / Godot / Unreal axis and units.
107+
- Skill `headless-batch-scripting` for the full pattern catalog.
108+
- Rule `prefer-temp-override-over-context-copy` for why we avoid
109+
`bpy.context.copy()`.
110+
- Snippet `lod_chain.py`, `convex_hull_collider.py`, `export_preset_unity.py`.

0 commit comments

Comments
 (0)