Back to skills
SKILL.md
Blender Compositing
ASecurityCompositor nodes, post-processing, and color grading in Blender. Use for compositing workflows, render pass integration, post-processing, color correction, or when user mentions "compositor," "post-process," "color grade," or "render passes."
- 6 stars
- 0 votes
- 0 copies
- 1 view
- Added September 3, 2026
Works with
Security analysis
100/100Pro scans all 5 files and shows the line behind each finding
npx -y skills add sideshowroberto/vfx-agent-toolkit --skill blender-compositing --agent claude-codeAre you the author of Blender Compositing?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/sideshowroberto-blender-compositing)---
name: blender-compositing
description: Compositor nodes, post-processing, and color grading in Blender. Use for compositing workflows, render pass integration, post-processing, color correction, or when user mentions "compositor," "post-process," "color grade," or "render passes."
allowed-tools: Read,Write
---
# Blender Compositing Skill
**Version:** 3.0.0
**Last Updated:** 2026-06-15
**Dependencies:** Blender 5.1+
---
## Breaking Changes (5.1+)
### Compositor Node Tree Access Changed
`scene.node_tree` no longer exists. Use `scene.compositing_node_group` instead. Must create the node group manually if None.
```python
import bpy
scene = bpy.context.scene
scene.use_nodes = True
# [FAIL] BROKEN in 5.1+
# compositor = scene.node_tree
# [OK] Access or create compositor node group
comp_tree = scene.compositing_node_group
if comp_tree is None:
comp_tree = bpy.data.node_groups.new(name="Compositor", type='CompositorNodeTree')
scene.compositing_node_group = comp_tree
scene.render.use_compositing = True
```
### CompositorNodeComposite Removed
There is no Composite output node in 5.1+. The main render output comes directly from the render pipeline (set via `scene.render.filepath` and `scene.render.image_settings`). Use `CompositorNodeViewer` for preview and `CompositorNodeOutputFile` for additional outputs.
```python
import bpy
# [FAIL] BROKEN in 5.1+ (RuntimeError: Node type undefined)
# composite = nodes.new('CompositorNodeComposite')
# [OK] Main render output is controlled by scene.render settings
scene = bpy.context.scene
scene.render.filepath = "//output/render_"
scene.render.image_settings.file_format = 'PNG'
# [OK] Use Viewer for compositor preview
viewer = comp_tree.nodes.new('CompositorNodeViewer')
```
### CompositorNodeMapRange Removed
No Map Range node in the compositor. Use `ShaderNodeMath` (works in compositor context) to build equivalent logic.
```python
import bpy
# [FAIL] BROKEN in 5.1+
# map_range = comp_tree.nodes.new('CompositorNodeMapRange')
# [OK] Use Math nodes for range mapping
# Example: clamp depth to max 80m, then normalize
clamp = comp_tree.nodes.new('ShaderNodeMath')
clamp.operation = 'MINIMUM'
clamp.inputs[1].default_value = 80.0
normalize = comp_tree.nodes.new('CompositorNodeNormalize')
comp_tree.links.new(rl.outputs['Depth'], clamp.inputs[0])
comp_tree.links.new(clamp.outputs[0], normalize.inputs[0])
```
### CompositorNodeColorRamp Removed
```python
import bpy
# [FAIL] BROKEN in 4.5.0+
# color_ramp = nodes.new('CompositorNodeColorRamp')
# [OK] Use ShaderNodeValToRGB (identical API, works in compositor)
color_ramp = comp_tree.nodes.new('ShaderNodeValToRGB')
```
### OPEN_EXR_MULTILAYER Not Available as Main Render Format
Multilayer EXR can only be created via the compositor's File Output node (which defaults to `OPEN_EXR_MULTILAYER`). The main render output supports `OPEN_EXR` (single layer) but not multilayer.
```python
import bpy
# [FAIL] BROKEN in 5.1+ - not in scene render format enum
# scene.render.image_settings.file_format = 'OPEN_EXR_MULTILAYER'
# [OK] Use File Output compositor node (defaults to OPEN_EXR_MULTILAYER)
fo = comp_tree.nodes.new('CompositorNodeOutputFile')
print(fo.format.file_format) # 'OPEN_EXR_MULTILAYER'
```
### EEVEE Bloom -> Compositor Glare (4.5.3+)
```python
import bpy
# [FAIL] BROKEN
# scene.eevee.use_bloom = True
# [OK] Use Compositor Glare node
glare = comp_tree.nodes.new('CompositorNodeGlare')
glare.glare_type = 'FOG_GLOW'
glare.threshold = 0.8
glare.size = 8
```
---
## QUICK START
### Basic Compositor Setup (5.1+)
```python
import bpy
scene = bpy.context.scene
scene.use_nodes = True
# Create or get compositor node group
comp_tree = scene.compositing_node_group
if comp_tree is None:
comp_tree = bpy.data.node_groups.new(name="Compositor", type='CompositorNodeTree')
scene.compositing_node_group = comp_tree
scene.render.use_compositing = True
comp_tree.nodes.clear()
# Core nodes
rl = comp_tree.nodes.new('CompositorNodeRLayers')
rl.location = (0, 0)
viewer = comp_tree.nodes.new('CompositorNodeViewer')
viewer.location = (400, 0)
comp_tree.links.new(rl.outputs['Image'], viewer.inputs['Image'])
```
---
## STANDARD WORKFLOWS
### Workflow 1: File Output Node (Multilayer EXR)
The File Output node in 5.1+ uses `directory` and `file_name` (not `base_path`/`file_slots`). Add pass inputs via `file_output_items.new()`.
**CRITICAL: Trailing dot in `file_name`** - the File Output node appends the scene frame number to `file_name`. Without a trailing `.`, sequential numbering like `0001` gets the scene frame appended (e.g., `00010276`). Add `.` to terminate: `"output_0001."` -> `output_0001.exr`.
```python
import bpy
comp_tree = bpy.context.scene.compositing_node_group
rl = comp_tree.nodes.get('Render Layers')
fo = comp_tree.nodes.new('CompositorNodeOutputFile')
fo.location = (600, -300)
# Set output directory and base filename
fo.directory = "D:\\output\\exr\\"
fo.file_name = "shot_0001." # Trailing dot prevents frame number append
# Add pass inputs (the node starts with 1 default input + 0 file_output_items)
# Must add items for the node to actually write output
combined = fo.file_output_items.new(socket_type='RGBA', name='Combined')
depth = fo.file_output_items.new(socket_type='FLOAT', name='Depth')
crypto0 = fo.file_output_items.new(socket_type='RGBA', name='CryptoObject00')
# Connect render layer outputs to file output inputs
comp_tree.links.new(rl.outputs['Image'], fo.inputs['Combined'])
comp_tree.links.new(rl.outputs['Depth'], fo.inputs['Depth'])
comp_tree.links.new(rl.outputs['CryptoObject00'], fo.inputs['CryptoObject00'])
```
**File Output API Reference (5.1+):**
| Old API (pre-5.1) | New API (5.1+) |
|---|---|
| `fo.base_path` | `fo.directory` |
| `fo.file_slots[0].path` | `fo.file_name` |
| `fo.file_slots.new("name")` | `fo.file_output_items.new(socket_type='RGBA', name='name')` |
| Format changeable per-node | Format locked to `OPEN_EXR_MULTILAYER` |
**Socket types for `file_output_items.new()`:** `'FLOAT'`, `'RGBA'`, `'VECTOR'`, `'INT'`, `'BOOLEAN'`
---
### Workflow 2: Depth Pass Normalization
**IMPORTANT: Never change camera `clip_end` to control depth range.** Reducing `clip_end` clips geometry from the render entirely - far objects disappear. Instead, clamp depth values in the compositor.
```python
import bpy
comp_tree = bpy.context.scene.compositing_node_group
rl = comp_tree.nodes.get('Render Layers')
# Clamp depth at desired max distance (e.g., 80m)
# Objects beyond this distance map to black, but still RENDER
clamp = comp_tree.nodes.new('ShaderNodeMath')
clamp.operation = 'MINIMUM'
clamp.inputs[1].default_value = 80.0 # max depth in meters
clamp.location = (200, -200)
# Normalize to 0-1 range
normalize = comp_tree.nodes.new('CompositorNodeNormalize')
normalize.location = (400, -200)
# Invert so near=white, far=black (ControlNet convention)
invert = comp_tree.nodes.new('CompositorNodeInvert')
invert.location = (600, -200)
# Chain: Depth -> Clamp -> Normalize -> Invert -> Viewer
comp_tree.links.new(rl.outputs['Depth'], clamp.inputs[0])
comp_tree.links.new(clamp.outputs[0], normalize.inputs[0])
comp_tree.links.new(normalize.outputs[0], invert.inputs['Color'])
# View in Viewer, save via viewer_img.save_render()
viewer = comp_tree.nodes.new('CompositorNodeViewer')
viewer.location = (800, -200)
comp_tree.links.new(invert.outputs['Color'], viewer.inputs['Image'])
```
**Saving Viewer output as PNG:**
```python
import bpy
viewer_img = bpy.data.images.get('Viewer Node')
if viewer_img and viewer_img.size[0] > 0:
viewer_img.save_render(filepath="//depth_0001.png", scene=bpy.context.scene)
```
---
### Workflow 3: Color Correction Pipeline
```python
import bpy
scene = bpy.context.scene
scene.use_nodes = True
comp_tree = scene.compositing_node_group
if comp_tree is None:
comp_tree = bpy.data.node_groups.new(name="Compositor", type='CompositorNodeTree')
scene.compositing_node_group = comp_tree
scene.render.use_compositing = True
comp_tree.nodes.clear()
rl = comp_tree.nodes.new('CompositorNodeRLayers')
rl.location = (0, 0)
bright_contrast = comp_tree.nodes.new('CompositorNodeBrightContrast')
bright_contrast.location = (250, 0)
bright_contrast.inputs['Bright'].default_value = 0.1
bright_contrast.inputs['Contrast'].default_value = 0.2
rgb_curves = comp_tree.nodes.new('CompositorNodeCurveRGB')
rgb_curves.location = (500, 0)
hue_sat = comp_tree.nodes.new('CompositorNodeHueSat')
hue_sat.location = (750, 0)
hue_sat.inputs['Saturation'].default_value = 1.2
viewer = comp_tree.nodes.new('CompositorNodeViewer')
viewer.location = (1000, 0)
comp_tree.links.new(rl.outputs['Image'], bright_contrast.inputs['Image'])
comp_tree.links.new(bright_contrast.outputs['Image'], rgb_curves.inputs['Image'])
comp_tree.links.new(rgb_curves.outputs['Image'], hue_sat.inputs['Image'])
comp_tree.links.new(hue_sat.outputs['Image'], viewer.inputs['Image'])
```
---
### Workflow 4: Cryptomatte + Render Passes
```python
import bpy
scene = bpy.context.scene
vl = scene.view_layers["ViewLayer"]
# Enable passes
vl.use_pass_combined = True
vl.use_pass_z = True
vl.use_pass_cryptomatte_object = True
vl.use_pass_cryptomatte_accurate = True
# Cryptomatte outputs appear as CryptoObject00, CryptoObject01, CryptoObject02
# on the Render Layers node. Must be saved in multilayer EXR to be useful
# (use File Output node - see Workflow 1)
```
---
## TROUBLESHOOTING
### "Scene object has no attribute node_tree"
**Cause:** Blender 5.1+ removed `scene.node_tree`
**Fix:** Use `scene.compositing_node_group` (see Breaking Changes above)
### "Node type CompositorNodeComposite undefined"
**Cause:** Composite node removed in 5.1+
**Fix:** Main output uses `scene.render.filepath`. Use Viewer for preview.
### File Output Node Produces No Files
**Cause:** `file_output_items` is empty (0 items). The default input exists but without items defined, nothing is written.
**Fix:** Add at least one item via `fo.file_output_items.new(socket_type='RGBA', name='Combined')`
### File Output Frame Numbers Wrong (e.g., 00010276)
**Cause:** File Output appends the scene frame number to `file_name`
**Fix:** Add trailing `.` to `file_name`: `fo.file_name = "output_0001."`
### Far Objects Missing from Render
**Cause:** Camera `clip_end` was reduced for depth normalization
**Fix:** Never change `clip_end`. Use compositor Math(MINIMUM) node to clamp depth values instead.
### Render Passes Not Showing in Render Layers Node
```python
import bpy
view_layer = bpy.context.scene.view_layers[0]
view_layer.use_pass_z = True
view_layer.use_pass_normal = True
```
---
## VALIDATION CHECKLIST
- [ ] Compositor accessed via `scene.compositing_node_group` (not `scene.node_tree`)
- [ ] No `CompositorNodeComposite` nodes (removed in 5.1)
- [ ] No `CompositorNodeMapRange` nodes (removed - use ShaderNodeMath)
- [ ] ColorRamp nodes use `ShaderNodeValToRGB`
- [ ] File Output uses `directory`/`file_name` (not `base_path`/`file_slots`)
- [ ] File Output `file_name` ends with `.` when using custom frame numbering
- [ ] File Output has `file_output_items` defined (otherwise produces no output)
- [ ] Depth normalization uses compositor clamp, NOT camera `clip_end`
- [ ] Render passes enabled in view layer before use
- [ ] `scene.render.use_compositing = True` set
---
## VERSION HISTORY
**v3.0.0** (2026-06-15) - Blender 5.1.2 compositor overhaul
- `scene.node_tree` -> `scene.compositing_node_group` (CompositorNodeTree)
- `CompositorNodeComposite` removed - documented replacement pattern
- `CompositorNodeMapRange` removed - Math node workaround
- File Output node: `base_path`->`directory`, `file_slots`->`file_output_items`
- File Output trailing dot naming fix
- OPEN_EXR_MULTILAYER only via File Output node
- Depth normalization: never change clip_end, use compositor clamp
- Added Cryptomatte + render pass workflow
**v2.0.0** (2026-06-10) - MCP migration
**v1.1.0** (2025-10-24) - Progressive disclosure update
**v1.0.0** (2025-10-24) - Initial release
---
**Status:** Production Ready
**Maintainer:** VFX Pipeline Team
**Dependencies:** Blender 5.1+
Files in this skill
- SKILL.md
- reference/ADVANCED_COMPOSITING.md
- reference/COLOR_GRADING.md
- reference/RENDER_PASSES.md
- reference/detailed-workflows.md
Attribution
Comments
Loading comments…
Newsletter
Get the weekly list of safe new skills, and the ones we pulled.