Blender Developer Tools
smoke-gated on 4.5 LTS + 5.1 · exit 0

Blender Python
that actually runs.

Skills, rules, snippets, and starter templates that teach Cursor and Claude Code the bpy that works — every pattern executed headless on Blender 4.5 LTS and 5.1 before it ships.

$ git clone https://github.com/TMHSDigital/Blender-Developer-Tools
Render Result 8 of 44 frames

Every render here is a CI artifact.

These aren't mockups. Each example runs headless on Blender 4.5 LTS and 5.1 in the smoke workflow, asserts its own correctness, and exits non-zero if the API drifted. The render is what the code produced.

Browse all 44 examples in the gallery →

car-mirror-symmetry render
car-mirror-symmetry A generic hatchback lofted as one half (14 stations, 9-point rings) and completed by the Mirror modifier, evaluated through the depsgraph. Wheels and lamps mirror about object origins parked on the symmetry plane.
soccer-ball-goldberg render
soccer-ball-goldberg A soccer ball as a Goldberg polyhedron: a bmesh icosphere truncated at 1/3 per edge, faces ordered by link-topology walks, panels bound by face vertex count.
damped-track-aim render
damped-track-aim Aim constraints via the data API — Object.constraints.new('DAMPED_TRACK') with target and TRACK_Z, not bpy.ops.object.constraint_add in a headless loop. Gallery still: brass spike cage around an ember core.
light-link-studio render
light-link-studio One key, one hero: a light linked to a receiver collection lights only the hero, proven by two pixel renders in one pass. Linked: 3.6x luminance ratio; unlinked in the same check: the decoy rises 233% while the hero holds at 0.3% drift.
collision-hull-proxy render
collision-hull-proxy A fire hydrant street prop inside its compound collision shell: four convex pieces hulled by bmesh.ops.convex_hull from a coarse inflated cage. The dense render mesh is never hulled - its hull would measure 380 faces, over the 255-face per-piece engine budget. Closed-form plane tests prove containment, convexity, watertightness, outward winding, and Euler characteristic 2 per piece.
armature-bend render
armature-bend Rigging end to end in the data API — edit_bones chain construction, name-bound vertex groups with smoothstep blend zones, posing, and depsgraph evaluation — bending a tapered tube through rest, half, and full curl.
bmesh-gear render
bmesh-gear A 14-tooth gear built entirely with bmesh — profile ring, face, extrude — with bm.free() in a try/finally, exactly as the ownership contract demands.
modular-kit-snap render
modular-kit-snap A tiling corridor kit whose open-end boundary verts snap to the tile grid, so instances at 4 m multiples join with zero gap or overlap.
Open the gallery — code, README, and full-size renders →
Skills 12 loaded

Workflows the AI loads by name.

Each skill is the canonical pattern for one job — operators, panels, bmesh, geometry nodes, slotted actions — plus the mistakes AI assistants actually make there. Where 4.5 LTS and 5.1 diverge, both code paths are shown.

addon-scaffolding Scaffold a Blender add-on against the Extensions Platform format with blender_manifest.toml, modular file layout, and the register_classes_factory pattern. Targets Blender 5.1 with 4.5 LTS fallback.
bl-info-migration Migrate a legacy bl_info-format add-on to the Extensions Platform. Three concrete steps, before-and-after diff, dual-format pattern for backward compatibility, and answers to "is bl_info still…
custom-properties Define and bind Blender custom properties via bpy.props using the type annotation form, with PropertyGroup for grouping, PointerProperty for binding, and the four storage location options for…
depsgraph-and-evaluated-data Read the actual evaluated geometry the user sees by going through the dependency graph rather than reading raw `obj.data`. Covers `evaluated_get`, `to_mesh`, `to_mesh_clear`, and the lifetime rules…
drivers-and-app-handlers Drive properties from expressions or other properties via the Driver API, and react to scene events via the bpy.app.handlers callbacks. Covers driver_namespace for Python functions, the new exit_pre…
geometry-nodes-python Programmatically construct Geometry Nodes trees in Blender 5.x via bpy.data.node_groups, interface socket creation, node instantiation by RNA name, link wiring, and applying as a NODES modifier.…
headless-batch-scripting Run Blender headless via blender --background --python script.py for batch jobs. What changes without a UI, how to avoid UI-dependent operators, the temp_override pattern when ops must be used, and…
mesh-editing-and-bmesh Performant mesh manipulation in Blender. When to use bpy.data vs bpy.ops vs bmesh, the canonical bm.new/free pattern, foreach_set bulk vertex injection, and depsgraph evaluation for modifier-applied…
operators Author Blender operators with bpy.types.Operator, bl_idname conventions, the poll/invoke/execute/modal lifecycle, REGISTER and UNDO options, and defensive context handling. Targets 5.1 with 4.5 LTS…
procedural-materials-and-shaders Build materials and shader graphs from Python by enabling nodes, instantiating shader nodes, setting socket default values, and wiring links. Targets Blender 5.1 EEVEE Next and Cycles. Avoids the…
slotted-actions-animation Animate from Python under the Slotted Actions architecture (data model shipped in Blender 4.4). Action contains Layers contain Strips contain Channelbags. Cross-version channelbag access -…
ui-panels Author Blender UI panels with bpy.types.Panel, declarative draw(), bl_space_type and bl_region_type, layout primitives like row/column/split, and conditional UI via .enabled. Targets 5.1.
Rules 6 active

Anti-patterns, caught before they ship.

Always-on guardrails for the failure modes that make Blender Python look right and run wrong: ops in loops, leaked bmesh, deprecated context dicts, per-vertex Python loops.

RuleScopeFlags
always-free-bmesh Flag bmesh.new() calls without a paired bm.free() in a try/finally block. BMesh allocates C-side memory that Python's garbage collector cannot reclaim; missing free() leaks and eventually crashes…
prefer-data-over-ops-in-loops Flag bpy.ops.* calls inside iteration over many objects, meshes, or frames. Each bpy.ops call triggers a full depsgraph evaluation and UI redraw; loops slow down by orders of magnitude. Use…
prefer-temp-override-over-context-copy Flag uses of `bpy.context.copy()` to override context for an operator call. The copy-and-pass pattern was deprecated in Blender 4.x and the override semantics were removed in 5.x. Use…
target-extensions-platform-format 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…
type-annotate-props-and-defend-context Flag two related anti-patterns. (1) bpy.props defined as class-level assignments instead of type annotations (deprecated since 2.8). (2) Code that touches bpy.context.active_object without guarding…
use-foreach-set-for-bulk-data Flag Python loops that set vertex coordinates, normals, UVs, or other bulk per-element data one element at a time. For meshes of more than a few thousand elements, this is 100x to 1000x slower than…
Snippets 17 patterns

Canonical patterns, five to fifty lines.

Standalone, paste-ready answers to the questions that come up every session: the right way to create and delete objects, read bulk vertex data, bind properties, bridge the 4.x/5.x API boundary.

Plus 2 starter templates: extension-addon-template and headless-batch-script-template — a complete Extensions-Platform add-on and a headless batch job with CI exit codes.

Install

Clone it. Point your AI at it.

  1. Clone the repo: git clone https://github.com/TMHSDigital/Blender-Developer-Tools
  2. Cursor: copy rules/ into your project's .cursor/rules/ — they auto-apply via scope globs; reference skills by name in chat
  3. Claude Code: copy skills/ and rules/ into your project workspace, or point Claude Code at the checkout
  4. Grab snippets/ and templates/ as starting points for add-ons and headless batch jobs