| 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). |
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.
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
- Blender 5.1 bundles Python 3.13 (up from 3.12 in 5.0)
- Update
bl_info["blender"] to (5, 1, 0) for version gating in add-ons
- Use type hint syntax (
int | None instead of Optional[int]) โ now fully supported
- Performance improvements in CPython 3.13: faster function calls, better GC
Removed Operators
bpy.ops.anim.convert_legacy_action โ removed; layered actions handle this automatically
API Additions
bpy.ops.pose.apply_to_basis() โ bake current pose as rest pose
- Node socket types:
NodeSocketFont for font data
- 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
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):
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)
with bpy.context.temp_override(active_object=obj, selected_objects=[obj]):
bpy.ops.object.delete()
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
if bpy.context.object and bpy.context.object.mode != 'EDIT':
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.object.mode_set(mode='OBJECT')
Common Context Gotchas
bpy.ops in background mode: Many viewport operators fail in --background mode. Use direct data API (bpy.data.*) instead.
- Operator context in handlers: Handlers run outside normal context. Use
bpy.context.temp_override() or avoid bpy.ops in handlers.
- Active object is None: Always check
context.active_object is not None before operations.
- Wrong mode: Object-mode operators fail in edit mode and vice versa. Check
context.object.mode.
- Depsgraph not updated: After modifying data, call
bpy.context.view_layer.update() or depsgraph.update() if needed.
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
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
import bpy
for obj in bpy.data.objects:
if obj.type == 'MESH':
bpy.ops.object.select_all(action='DESELECT')
obj.select_set(True)
bpy.context.view_layer.objects.active = obj
for mod in obj.modifiers:
bpy.ops.object.modifier_apply(modifier=mod.name)
Command-Line Batch
blender --background scene.blend --python my_script.py
blender --background --python batch_render.py -- --input /files --output /renders
Access custom args after --:
import sys
argv = sys.argv[sys.argv.index("--") + 1:]
Debugging Tips
- System Console: Window > Toggle System Console (Windows) or run Blender from terminal
- Python Console: Open the Python Console editor area for interactive testing
- Info Editor: Shows Python equivalents of GUI actions โ useful for discovering API calls
dir() and help(): Use in Python Console to explore API objects
bpy.context.copy(): Returns a dict of the current context for inspection
- 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.