blender
SKILL.md
Blender 3D Automation
Automate Blender 3D modeling, animation, rendering, and scene management using Python's bpy API and command-line rendering. Supports headless operation, batch processing, and procedural generation.
Direct Control (CLI / API / Scripting)
Command-Line Rendering
# Render single frame
blender scene.blend --background --render-frame 1
# Render animation range
blender scene.blend --background --render-anim --frame-start 1 --frame-end 120
# Render with custom output path
blender scene.blend --background --render-output /tmp/render_#### --render-anim
# Render specific scene
blender file.blend --background --scene "Scene.001" --render-frame 1
# Set render engine
blender scene.blend --background --engine CYCLES --render-frame 1
blender scene.blend --background --engine BLENDER_EEVEE --render-frame 1
# Use GPU for rendering
blender scene.blend --background --python-expr "import bpy; bpy.context.preferences.addons['cycles'].preferences.compute_device_type = 'CUDA'; bpy.context.scene.cycles.device = 'GPU'" --render-frame 1
Python bpy Scripting
import bpy
import math
# Create new cube
bpy.ops.mesh.primitive_cube_add(size=2, location=(0, 0, 0))
cube = bpy.context.active_object
cube.name = "MyCube"
# Set material
mat = bpy.data.materials.new(name="RedMaterial")
mat.use_nodes = True
mat.node_tree.nodes["Principled BSDF"].inputs[0].default_value = (1, 0, 0, 1)
cube.data.materials.append(mat)
# Add keyframe animation
cube.location = (0, 0, 0)
cube.keyframe_insert(data_path="location", frame=1)
cube.location = (5, 0, 0)
cube.keyframe_insert(data_path="location", frame=120)
# Set render settings
scene = bpy.context.scene
scene.render.engine = 'CYCLES'
scene.cycles.device = 'GPU'
scene.render.resolution_x = 1920
scene.render.resolution_y = 1080
scene.render.fps = 24
scene.frame_start = 1
scene.frame_end = 120
# Render current frame
bpy.ops.render.render(write_still=True)
# Save blend file
bpy.ops.wm.save_as_mainfile(filepath="/path/to/output.blend")
Execute Python Script in Blender
# Run Python script
blender --background --python script.py
# Run script with arguments
blender --background --python script.py -- arg1 arg2
# Run inline Python
blender --background --python-expr "import bpy; bpy.ops.mesh.primitive_cube_add()"
# Run script and save
blender scene.blend --background --python modify_scene.py --save
Scene Manipulation
import bpy
# List all objects
for obj in bpy.data.objects:
print(f"{obj.name}: {obj.type}")
# Delete object by name
obj = bpy.data.objects.get("Cube")
if obj:
bpy.data.objects.remove(obj, do_unlink=True)
# Import FBX/OBJ
bpy.ops.import_scene.fbx(filepath="/path/to/model.fbx")
bpy.ops.import_scene.obj(filepath="/path/to/model.obj")
# Export FBX/OBJ
bpy.ops.export_scene.fbx(filepath="/path/to/output.fbx", use_selection=False)
bpy.ops.export_scene.obj(filepath="/path/to/output.obj")
# Camera setup
camera_data = bpy.data.cameras.new(name="Camera")
camera_object = bpy.data.objects.new("Camera", camera_data)
bpy.context.scene.collection.objects.link(camera_object)
camera_object.location = (7.5, -6.5, 5.4)
camera_object.rotation_euler = (math.radians(63), 0, math.radians(46))
bpy.context.scene.camera = camera_object
# Lighting
light_data = bpy.data.lights.new(name="Light", type='SUN')
light_object = bpy.data.objects.new(name="Sun", object_data=light_data)
bpy.context.collection.objects.link(light_object)
light_object.location = (5, 5, 10)
light_data.energy = 2.0
Geometry Nodes (Procedural)
import bpy
# Add geometry nodes modifier
obj = bpy.context.active_object
modifier = obj.modifiers.new(name="GeometryNodes", type='NODES')
# Create node group
node_group = bpy.data.node_groups.new('MyNodeTree', 'GeometryNodeTree')
modifier.node_group = node_group
# Add input/output nodes
input_node = node_group.nodes.new('NodeGroupInput')
output_node = node_group.nodes.new('NodeGroupOutput')
# Add geometry nodes (e.g., subdivide)
subdivide_node = node_group.nodes.new('GeometryNodeSubdivisionSurface')
node_group.links.new(input_node.outputs[0], subdivide_node.inputs[0])
node_group.links.new(subdivide_node.outputs[0], output_node.inputs[0])
MCP Server Integration
Add to .codebuddy/mcp.json:
{
"mcpServers": {
"blender": {
"command": "npx",
"args": ["-y", "@ahujasid/blender-mcp"],
"env": {
"BLENDER_PATH": "/usr/bin/blender"
}
}
}
}
Available MCP Tools
blender_execute_script- Execute Python bpy script in Blenderblender_render_frame- Render single frame or animationblender_create_object- Create primitive objects (cube, sphere, plane, etc.)blender_modify_object- Transform, scale, rotate objectsblender_set_material- Apply materials and shadersblender_add_keyframe- Create animation keyframesblender_import_model- Import FBX, OBJ, STL, GLTFblender_export_model- Export to various formatsblender_list_objects- Get scene object hierarchyblender_get_scene_info- Get render settings and scene data
Common Workflows
1. Batch Render Multiple Scenes
# Render all scenes in a blend file
for scene in $(blender file.blend --background --python-expr "import bpy; print(','.join([s.name for s in bpy.data.scenes]))" | tail -1 | tr ',' '\n'); do
blender file.blend --background --scene "$scene" --render-output "/renders/${scene}_####" --render-anim
done
# Python version with progress
import bpy
import os
output_dir = "/renders"
os.makedirs(output_dir, exist_ok=True)
for scene in bpy.data.scenes:
print(f"Rendering scene: {scene.name}")
bpy.context.window.scene = scene
scene.render.filepath = os.path.join(output_dir, f"{scene.name}_")
bpy.ops.render.render(animation=True)
2. Procedural Asset Generation
import bpy
import random
# Clear scene
bpy.ops.object.select_all(action='SELECT')
bpy.ops.object.delete()
# Generate random cubes
for i in range(10):
x = random.uniform(-5, 5)
y = random.uniform(-5, 5)
z = random.uniform(0, 3)
scale = random.uniform(0.5, 2.0)
bpy.ops.mesh.primitive_cube_add(location=(x, y, z), scale=(scale, scale, scale))
obj = bpy.context.active_object
obj.name = f"Cube_{i:03d}"
# Random color material
mat = bpy.data.materials.new(name=f"Mat_{i}")
mat.use_nodes = True
mat.node_tree.nodes["Principled BSDF"].inputs[0].default_value = (
random.random(), random.random(), random.random(), 1
)
obj.data.materials.append(mat)
# Save
bpy.ops.wm.save_as_mainfile(filepath="/tmp/procedural_scene.blend")
3. Camera Animation Sequence
import bpy
import math
scene = bpy.context.scene
camera = scene.camera
# Circular camera path
center = (0, 0, 0)
radius = 10
height = 5
num_frames = 240
for frame in range(1, num_frames + 1):
angle = (frame / num_frames) * 2 * math.pi
x = center[0] + radius * math.cos(angle)
y = center[1] + radius * math.sin(angle)
z = center[2] + height
camera.location = (x, y, z)
camera.keyframe_insert(data_path="location", frame=frame)
# Look at center
direction = (center[0] - x, center[1] - y, center[2] - z)
rot_quat = direction.to_track_quat('-Z', 'Y')
camera.rotation_euler = rot_quat.to_euler()
camera.keyframe_insert(data_path="rotation_euler", frame=frame)
scene.frame_end = num_frames
4. Batch Model Import and Render
import bpy
import os
import glob
model_dir = "/path/to/models"
output_dir = "/path/to/renders"
os.makedirs(output_dir, exist_ok=True)
# Setup scene once
scene = bpy.context.scene
scene.render.resolution_x = 1920
scene.render.resolution_y = 1080
scene.render.engine = 'CYCLES'
# Import and render each model
for model_path in glob.glob(os.path.join(model_dir, "*.fbx")):
# Clear scene
bpy.ops.object.select_all(action='SELECT')
bpy.ops.object.delete()
# Import model
bpy.ops.import_scene.fbx(filepath=model_path)
# Center camera on object
obj = bpy.context.selected_objects[0]
bpy.ops.view3d.camera_to_view_selected()
# Render
model_name = os.path.splitext(os.path.basename(model_path))[0]
scene.render.filepath = os.path.join(output_dir, f"{model_name}.png")
bpy.ops.render.render(write_still=True)
print(f"Rendered: {model_name}")
5. Material Library Application
import bpy
# Load material library
with bpy.data.libraries.load("/path/to/materials.blend") as (data_from, data_to):
data_to.materials = data_from.materials
# Apply material to selected objects
material_name = "GoldMetal"
mat = bpy.data.materials.get(material_name)
if mat:
for obj in bpy.context.selected_objects:
if obj.type == 'MESH':
if len(obj.data.materials) > 0:
obj.data.materials[0] = mat
else:
obj.data.materials.append(mat)
print(f"Applied {material_name} to {obj.name}")
Weekly Installs
6
Repository
phuetz/code-buddyGitHub Stars
6
First Seen
11 days ago
Security Audits
Installed on
claude-code6
github-copilot6
codex6
kimi-cli6
gemini-cli6
amp6