blender-python-scripting
Blender 5.x Python scripting (bpy) — custom operators, UI panels, add-on development, context management, handlers, timers, property system, batch processing, and data model access. Now targets Python 3.13 (Blender 5.1).
Works with
Agent Skills format with YAML frontmatter. Claude Code reads it as-is.
---
name: "blender-python-scripting"
description: "Blender 5.x Python scripting (bpy) — custom operators, UI panels, add-on development, context management, handlers, timers, property system, batch processing, and data model access. Now targets Python 3.13 (Blender 5.1)."
license: "MIT"
---
# Blender Python Scripting Expert
## Overview
This skill provides expert guidance for Blender 5.x Python scripting: writing custom operators, building UI panels, developing add-ons, managing context, using handlers and timers, working with the property system, batch processing, and accessing Blender's data model. The reference files contain complete templates and the data model hierarchy.
## MCP-First Approach
Prefer the **official Blender MCP Server** (Blender Lab, Blender 5.1+) for executing scripts, inspecting datablocks, mutating scene state directly in a running Blender session. Fall back to emitting Python scripts only when the MCP server is not connected.
**Detection:** at session start, look for tools whose names match `execute_blender_code`, `get_objects_summary`, or `search_api_docs` — these belong to the official `blender-mcp` server. If any are present, MCP is available.
**Tools used by this skill:**
- `execute_blender_code` — run `bpy` Python in the live session (primary action)
- `get_objects_summary`, `get_object_detail_summary` — inspect scene state before mutating
- `get_blendfile_summary_datablocks` / `_missing_files` / `_of_linked_libraries` / `_path_info` / `_usage_guess` — inventory the file
- `search_api_docs`, `get_python_api_docs`, `search_manual_docs` — confirm correct API/operator names before calling them
- `get_screenshot_of_window_as_image` / `_as_json`, `get_screenshot_of_area_as_image` — verify visual results
- `jump_to_tab_by_name`, `jump_to_tab_by_space_type`, `jump_to_view3d_object_by_name`, `jump_to_view3d_object_data_by_name` — drive the UI to make changes visible
- `render_thumbnail_to_path`, `render_viewport_to_path` — capture quick visual feedback
**Workflow:** inspect with a `get_*` / `search_*` tool → mutate via `execute_blender_code` → verify with a screenshot or summary tool. Keep code blocks small and idempotent so failures are easy to localize.
Setup: see [docs/blender-mcp-setup.md](../../docs/blender-mcp-setup.md).
## Task Decision Tree
- **"Create a custom operator"** -> Consult `references/python_api.md` for operator templates
- **"Build a UI panel"** -> See Panel templates in `references/python_api.md`
- **"Develop a Blender add-on"** -> Follow the Add-on Structure section below
- **"Batch process files / renders"** -> See Batch Processing patterns
- **"Access scene/object data"** -> Consult `references/data_model_reference.md`
- **"Register a property"** -> See Property System in `references/python_api.md`
- **"Run code on frame change / file load"** -> See Handler patterns in `references/python_api.md`
- **"Context errors / poll failures"** -> See Context Management below
## Blender 5.1 Python Changes
### Python 3.13 Upgrade
1. Blender 5.1 bundles **Python 3.13** (up from 3.12 in 5.0)
2. Update `bl_info["blender"]` to `(5, 1, 0)` for version gating in add-ons
3. Use type hint syntax (`int | None` instead of `Optional[int]`) — now fully supported
4. Performance improvements in CPython 3.13: faster function calls, better GC
### Removed Operators
1. `bpy.ops.anim.convert_legacy_action` — removed; layered actions handle this automatically
### API Additions
1. `bpy.ops.pose.apply_to_basis()` — bake current pose as rest pose
2. Node socket types: `NodeSocketFont` for font data
3. Volume grid node types for geometry nodes (see blender-geometry-nodes skill)
## Add-on Structure
A proper Blender add-on follows this layout:
```
my_addon/
├── __init__.py # bl_info, register(), unregister()
├── operators.py # Custom operators
├── panels.py # UI panels
├── properties.py # PropertyGroups
├── preferences.py # AddonPreferences (optional)
└── utils.py # Shared utilities
```
### Minimal Single-File Add-on
```python
bl_info = {
"name": "My Add-on",
"author": "Author",
"version": (1, 0, 0),
"blender": (5, 0, 0),
"location": "View3D > Sidebar > My Tab",
"description": "Short description",
"category": "Object",
}
import bpy
class MY_OT_my_operator(bpy.types.Operator):
bl_idname = "my.my_operator"
bl_label = "My Operator"
bl_options = {'REGISTER', 'UNDO'}
@classmethod
def poll(cls, context):
return context.active_object is not None
def execute(self, context):
# ... do work ...
return {'FINISHED'}
class MY_PT_my_panel(bpy.types.Panel):
bl_label = "My Panel"
bl_idname = "MY_PT_my_panel"
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI'
bl_category = "My Tab"
def draw(self, context):
layout = self.layout
layout.operator("my.my_operator")
classes = (MY_OT_my_operator, MY_PT_my_panel)
def register():
for cls in classes:
bpy.utils.register_class(cls)
def unregister():
for cls in classes:
bpy.utils.unregister_class(cls)
if __name__ == "__main__":
register()
```
### Naming Conventions
- Operators: `ADDON_OT_name` → `bl_idname = "addon.name"`
- Panels: `ADDON_PT_name`
- Menus: `ADDON_MT_name`
- UILists: `ADDON_UL_name`
- PropertyGroups: `ADDON_PG_name` (convention, not enforced)
- Headers: `ADDON_HT_name`
## Context Management
### Common Context Issues
Blender operations depend on the current context (active object, mode, area type). Many `bpy.ops.*` calls will fail if context is wrong.
**Rule**: Always check context before calling operators. Use `poll()` methods to guard operators.
### Context Override (Blender 4.x+ / 5.x)
```python
# Modern context override using temp_override (4.0+)
with bpy.context.temp_override(active_object=obj, selected_objects=[obj]):
bpy.ops.object.delete()
# Override with area/region for UI-dependent ops
area = next(a for a in bpy.context.screen.areas if a.type == 'VIEW_3D')
region = next(r for r in area.regions if r.type == 'WINDOW')
with bpy.context.temp_override(area=area, region=region):
bpy.ops.view3d.camera_to_view()
```
### Mode Switching
```python
# Safe mode switch
if bpy.context.object and bpy.context.object.mode != 'EDIT':
bpy.ops.object.mode_set(mode='EDIT')
# Always return to object mode when done
bpy.ops.object.mode_set(mode='OBJECT')
```
### Common Context Gotchas
1. **`bpy.ops` in background mode**: Many viewport operators fail in `--background` mode. Use direct data API (`bpy.data.*`) instead.
2. **Operator context in handlers**: Handlers run outside normal context. Use `bpy.context.temp_override()` or avoid `bpy.ops` in handlers.
3. **Active object is None**: Always check `context.active_object is not None` before operations.
4. **Wrong mode**: Object-mode operators fail in edit mode and vice versa. Check `context.object.mode`.
5. **Depsgraph not updated**: After modifying data, call `bpy.context.view_layer.update()` or `depsgraph.update()` if needed.
6. **`display_type` values depend on object type**: `'PLAIN_AXES'` is only valid for Empties. Mesh objects use `'BOUNDS'`, `'WIRE'`, `'SOLID'`, or `'TEXTURED'`.
## Batch Processing
### Batch Render
```python
import bpy, os
scenes_dir = "/path/to/blend/files"
output_dir = "/path/to/output"
for filename in os.listdir(scenes_dir):
if filename.endswith(".blend"):
filepath = os.path.join(scenes_dir, filename)
bpy.ops.wm.open_mainfile(filepath=filepath)
bpy.context.scene.render.filepath = os.path.join(
output_dir, filename.replace(".blend", ".png")
)
bpy.ops.render.render(write_still=True)
```
### Batch Object Processing
```python
import bpy
for obj in bpy.data.objects:
if obj.type == 'MESH':
# Select only this object
bpy.ops.object.select_all(action='DESELECT')
obj.select_set(True)
bpy.context.view_layer.objects.active = obj
# Apply all modifiers
for mod in obj.modifiers:
bpy.ops.object.modifier_apply(modifier=mod.name)
```
### Command-Line Batch
```bash
blender --background scene.blend --python my_script.py
blender --background --python batch_render.py -- --input /files --output /renders
```
Access custom args after `--`:
```python
import sys
argv = sys.argv[sys.argv.index("--") + 1:]
```
## Debugging Tips
1. **System Console**: Window > Toggle System Console (Windows) or run Blender from terminal
2. **Python Console**: Open the Python Console editor area for interactive testing
3. **Info Editor**: Shows Python equivalents of GUI actions — useful for discovering API calls
4. **`dir()` and `help()`**: Use in Python Console to explore API objects
5. **`bpy.context.copy()`**: Returns a dict of the current context for inspection
6. **Error in modal operator**: Add `print()` statements or use `traceback.print_exc()` in exception handlers
## Property System Quick Reference
| Type | Registration | Values |
| --- | --- | --- |
| `BoolProperty` | `bpy.props.BoolProperty()` | True/False |
| `IntProperty` | `bpy.props.IntProperty()` | min, max, default, step |
| `FloatProperty` | `bpy.props.FloatProperty()` | min, max, default, precision |
| `StringProperty` | `bpy.props.StringProperty()` | default, maxlen, subtype |
| `EnumProperty` | `bpy.props.EnumProperty()` | items=[(id, name, desc)] |
| `FloatVectorProperty` | `bpy.props.FloatVectorProperty()` | size, default, subtype |
| `IntVectorProperty` | `bpy.props.IntVectorProperty()` | size, default |
| `BoolVectorProperty` | `bpy.props.BoolVectorProperty()` | size, default |
| `PointerProperty` | `bpy.props.PointerProperty()` | type=PropertyGroup |
| `CollectionProperty` | `bpy.props.CollectionProperty()` | type=PropertyGroup |
### Property Subtypes
- Float/Int: `'PIXEL'`, `'PERCENTAGE'`, `'FACTOR'`, `'ANGLE'`, `'TIME'`, `'DISTANCE'`
- FloatVector: `'COLOR'`, `'TRANSLATION'`, `'DIRECTION'`, `'VELOCITY'`, `'ACCELERATION'`, `'EULER'`, `'QUATERNION'`, `'XYZ'`
- String: `'FILE_PATH'`, `'DIR_PATH'`, `'FILE_NAME'`, `'BYTE_STRING'`, `'PASSWORD'`
## Python API Reference
For complete templates including operators (basic, modal, file dialog, invoke with props), panels (conditional, sub-panels, collapsible), PropertyGroups, handlers, timers, keymaps, and context overrides, consult `references/python_api.md`.
## Data Model Reference
For the complete Blender data hierarchy (`bpy.data.*`), ID types, object types, mesh/curve/armature data access patterns, and depsgraph usage, consult `references/data_model_reference.md`.More General & Other skills
find-skills
vercel-labs/skills
Helps users discover and install agent skills when they ask questions like "how do I do X", "find a skill for X", "is there a skill that can...", or express interest in extending capabilities. This skill should be used when the user is looking for functionality that might exist as an installable skill.
grill-me
mattpocock/skills
A relentless interview to sharpen a plan or design.
grill-with-docs
mattpocock/skills
A relentless interview to sharpen a plan or design, which also creates docs (ADR's and glossary) as we go.

