Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .cursor-plugin/plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
"snippets/version-branch-skeleton.py"
],
"templates": [
"templates/ai-asset-pipeline-template",
"templates/extension-addon-template",
"templates/headless-batch-script-template"
],
Expand Down
33 changes: 33 additions & 0 deletions .github/workflows/blender-smoke.yml
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,39 @@ jobs:
[ "$code" -eq 2 ] || { echo "::error::expected exit 2 for no-mesh input, got $code"; exit 1; }
echo "no-mesh exit code = $code (correct)"

- name: Build pipeline template fixture GLB
run: |
set -euo pipefail
xvfb-run -a "$BLENDER" --background --python tests/smoke/make_pipeline_glb.py -- \
"$RUNNER_TEMP/out/pipeline_src.glb"
test -s "$RUNNER_TEMP/out/pipeline_src.glb" || { echo "::error::pipeline fixture missing"; exit 1; }

- name: Headless AI asset pipeline template runs (exit 0, LODs produced)
run: |
set -euo pipefail
mkdir -p "$RUNNER_TEMP/out/pipeline"
xvfb-run -a "$BLENDER" --background --python templates/ai-asset-pipeline-template/pipeline.py -- \
--input "$RUNNER_TEMP/out/pipeline_src.glb" \
--outdir "$RUNNER_TEMP/out/pipeline" \
--preset unity \
--lod-budgets 1024,256,64 \
--collider convex
test -s "$RUNNER_TEMP/out/pipeline/lod0.glb" || { echo "::error::lod0 missing/empty"; exit 1; }
test -s "$RUNNER_TEMP/out/pipeline/collider.glb" || { echo "::error::collider missing/empty"; exit 1; }
head -c4 "$RUNNER_TEMP/out/pipeline/lod0.glb" | grep -q "glTF" || { echo "::error::lod0 not a glTF binary"; exit 1; }

- name: Headless pipeline template missing input returns exit 2
run: |
set +e
xvfb-run -a "$BLENDER" --background --python templates/ai-asset-pipeline-template/pipeline.py -- \
--input "$RUNNER_TEMP/out/does-not-exist.glb" \
--outdir "$RUNNER_TEMP/out/pipeline" \
--preset unity
code=$?
set -e
[ "$code" -eq 2 ] || { echo "::error::expected exit 2 for missing input, got $code"; exit 1; }
echo "missing-input exit code = $code (correct)"

- name: Headless render template runs (exit 0, PNG produced)
run: |
set -euo pipefail
Expand Down
4 changes: 2 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ a `.cursor-plugin/plugin.json` manifest so the ecosystem drift checker
classifies it as a `cursor-plugin`. This is content the AI loads when the user
asks Blender questions or works on Blender add-ons in Cursor or Claude Code.

The content base is 15 skills, 9 rules, 2 templates, 24 snippets, and 54
The content base is 15 skills, 9 rules, 3 templates, 24 snippets, and 54
examples (counts are CI-enforced against README.md and the manifest). The full
inventory tables and per-item purposes live in `CLAUDE.md`. Example anatomy
and authoring rules: copy `examples/bmesh-gear/`; the render look is specified
Expand All @@ -33,7 +33,7 @@ in `docs/VISUAL-STYLE.md`; the canonical run prompt is
Blender-Developer-Tools/
skills/<skill-name>/SKILL.md # 15 skill files
rules/<rule-name>.mdc # 9 rule files
templates/<template-name>/ # 2 starter templates
templates/<template-name>/ # 3 starter templates
snippets/<snippet-name>.py # 24 standalone Python snippets
examples/<name>/ # 54 runnable smoke-gated examples (+ gallery.json)
examples/gallery_framing.py # shared Layer 1 framing measurement (render path only)
Expand Down
12 changes: 10 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ The **Blender Developer Tools** repository is at **v0.55.0**. It packages skills
```
skills/<skill-name>/SKILL.md - AI workflow definitions, 15 total
rules/<rule-name>.mdc - Anti-pattern rules, 9 total
templates/<template-name>/ - Starter projects, 2 total
templates/<template-name>/ - Starter projects, 3 total
snippets/<snippet-name>.py - Standalone code patterns, 24 total
examples/<name>/ - Runnable smoke-gated examples, 54 total (+ gallery.json)
scripts/build_gallery.py - Regenerates docs/gallery/ from gallery.json (stdlib only)
Expand Down Expand Up @@ -62,7 +62,7 @@ VERSION - Source of truth for the repo version
| no-unapplied-modifiers-on-export | `*.py` | Export with live modifiers when the export does not request evaluated geometry |
| use-correct-axis-rna-per-exporter | `*.py` | `export_scene.gltf` with FBX `axis_forward`/`axis_up`, or `export_scene.fbx` with glTF `export_yup` |

## Templates (2)
## Templates (3)

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

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

`templates/ai-asset-pipeline-template/` is a working starter for a headless GLB-in / engine-ready-out job:

- `argparse` parsing of args after the `--` separator
- Import, unit-scale check, transform apply, origin, normals, evaluated tris
- LOD chain and optional convex/box collider
- Unity / Godot / Unreal glTF export via the engine-export-presets contract
- Explicit exit codes matching `headless-batch-script-template` (0, then 2+)

## Snippets (24)

Small standalone `.py` files at `snippets/<name>.py`, each 5 to 50 lines.
Expand Down
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
</p>

<p align="center">
<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>
<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>
</p>

<p align="center">
Expand All @@ -36,15 +36,15 @@

## Overview

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

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.

| Layer | Role |
| --- | --- |
| **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 |
| **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 |
| **Templates** | A working Extensions Platform add-on starter and a headless batch script starter |
| **Templates** | A working Extensions Platform add-on starter, a headless batch script starter, and a GLB-in engine-ready asset pipeline |
| **Snippets** | 24 small standalone Python files demonstrating canonical patterns |

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

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

`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 ...`.

`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`.

## Snippets

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.
Expand Down
4 changes: 2 additions & 2 deletions ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ derives the actual version from conventional-commit types.
| Modal operators, USD, mathutils | — | — | — | — | Upcoming |
| AI asset pipeline: post-generation cleanup | 14 | 8 | 2 | 21 | Shipped (v0.54.0) |
| AI asset pipeline: engine export presets | 15 | 9 | 2 | 24 | Shipped |
| AI asset pipeline: headless template | - | - | - | - | Upcoming |
| AI asset pipeline: headless template | 15 | 9 | 3 | 24 | Shipped |
| AI asset pipeline: live-session bridge (spike) | - | - | - | - | Upcoming |
| Stable | — | — | — | — | Upcoming |

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

- **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.
- **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`.
- **`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.
- **`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/`.
- **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.

## Candidate pool (next content)
Expand Down
110 changes: 110 additions & 0 deletions templates/ai-asset-pipeline-template/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
# AI Asset Pipeline Template

A working starter for a headless Blender job that takes a GLB in and
writes an engine-ready LOD set plus optional collider. Provider-agnostic:
the input is a file path, not a generation vendor.

## Usage

```powershell
blender --background --python pipeline.py -- `
--input .\source.glb `
--outdir .\out `
--preset unity `
--lod-budgets 1024,256,64 `
--collider convex
```

Linux / macOS:

```bash
blender --background --python pipeline.py -- \
--input ./source.glb \
--outdir ./out \
--preset unity \
--lod-budgets 1024,256,64 \
--collider convex
```

The `--` separator is required. Everything before it is consumed by
Blender (`--background`, `--python`). Everything after it is forwarded
to `pipeline.py` as `sys.argv`.

Optional `--draco` enables glTF Draco compression on export.

`--preset` is one of `unity` (Y-up glTF), `godot` (Z-up glTF), `unreal`
(centimeter glTF: 100x bake then `export_yup=True`). FBX for Unreal lives
in `snippets/export_preset_unreal.py`; this template emits GLB so a CI
job can check the `glTF` magic bytes the same way for every preset.

## What it does

1. Parses script-side args after `--`.
2. Imports the GLB into an empty scene.
3. Checks scene units (metric meters), applies object rotation/scale,
sits the origin on the lowest Z, recalculates face normals, and
prints the evaluated triangle count.
4. Builds an LOD chain from `--lod-budgets`.
5. Optionally builds a convex hull or AABB box collider.
6. Exports each LOD (and the collider) under the chosen engine preset.
7. Returns explicit exit codes so a CI pipeline can detect failures.

Cleanup order follows `ai-mesh-cleanup`. LOD, collider, and export
helpers are duplicated from the snippets named in `pipeline.py`'s
header; templates are not a package.

## Exit codes

Same convention as `templates/headless-batch-script-template/`
(`script.py` / its README: 0 success, 2+ distinct failure modes;
argparse usage errors also exit 2). Not a repo-wide table; examples such
as `export-preset-axis` number their own checks independently.

| Code | Meaning |
| --- | --- |
| 0 | Success |
| 2 | Input file missing, or argparse rejected the flags (including an unsupported `--preset`) |
| 3 | Input is not a readable GLB (bad magic or import failure) |
| 4 | `--lod-budgets` missing, non-positive, or not strictly decreasing |
| 5 | Import produced no mesh |
| 6 | `outdir` is not a directory, or glTF export failed / wrote no file |

## Expected environment

- Blender on the system `PATH` (or invoked by absolute path).
- `--outdir` already exists. The script does not create it.
- `--input` is a GLB with at least one mesh. With no meshes the script
returns exit code 5.

## Common gotchas

- **Forgetting the `--`**. Blender treats the following args as its
own and complains. The script never sees them.
- **Output path with spaces on Windows**. Quote the whole path:
`--outdir ".\out folder"`.
- **Running without `--background`**. The script still works, but
Blender opens a UI window and stays open after the script finishes.
Use `--background` for unattended runs.
- **Unreal mutates selected meshes** (100x scale bake). Each export
selects one object. Do not re-export the same object as Unity afterward
without restoring scale.
- **Operators that need a 3D Viewport context**. Some operators only
work when a `VIEW_3D` area exists. In headless mode, none does.
Either rewrite using `bpy.data.*`, or fabricate a window+area via
`temp_override` (advanced; see the `headless-batch-scripting` skill).

## Extending the template

This template covers one pipeline (import, clean, LOD, collider, export).
For more complex workflows, factor each step into its own function and
return early with distinct exit codes. The `main()` function is the
orchestration point; everything else should be pure helpers.

## See also

- Skill `ai-mesh-cleanup` for the cleanup order.
- Skill `engine-export-presets` for Unity / Godot / Unreal axis and units.
- Skill `headless-batch-scripting` for the full pattern catalog.
- Rule `prefer-temp-override-over-context-copy` for why we avoid
`bpy.context.copy()`.
- Snippet `lod_chain.py`, `convex_hull_collider.py`, `export_preset_unity.py`.
Loading
Loading