blender-impl-nodes
blender-impl-nodes
Quick Reference
Critical Workflow Rules
ALWAYS follow this order when building node trees from Python:
- Create/get the node tree container
- Clear existing nodes if building from scratch
- Define interface sockets (4.0+) or legacy inputs/outputs (3.x)
- Add Group Input / Group Output nodes
- Add processing nodes with explicit positions
- Link nodes (source output FIRST, destination input SECOND)
- Assign to object/modifier and set input values
ALWAYS use tree.nodes.new() / tree.links.new() for scripting. NEVER use bpy.ops.node.* operators — they require editor context.
ALWAYS set location on every node. Without explicit positions, all nodes stack at (0, 0) making the tree unreadable in the editor.
ALWAYS iterate interface.items_tree to find modifier input identifiers. NEVER use socket names as modifier keys.
Master Decision Tree: Which Workflow?
Q: What are you building?
├── Geometry Nodes modifier on an object
│ └── → Workflow 1: Geometry Nodes Modifier
├── Material / shader for an object
│ └── → Workflow 2: Shader Material
├── World environment (HDRI, sky)
│ └── → Workflow 3: World Shader
├── Compositor post-processing
│ └── → Workflow 4: Compositor Setup
├── Reusable node group (shared across objects)
│ └── → Workflow 5: Custom Node Group
├── Nested / composed node groups
│ └── → Workflow 6: Nested Groups
├── Parametric AEC component (wall, slab, column)
│ └── → Workflow 7: AEC Parametric Component
└── Batch materials for AEC visualization
└── → Workflow 8: AEC Material Library
Version Decision Tree
Q: What Blender version?
├── 3.x
│ ├── Socket creation: node_group.inputs.new() / outputs.new()
│ ├── Compositor: scene.use_nodes = True; scene.node_tree
│ ├── Mix node: ShaderNodeMixRGB
│ └── No interface panels
├── 4.0-4.0.x
│ ├── Socket creation: node_group.interface.new_socket()
│ ├── Compositor: scene.use_nodes = True; scene.node_tree
│ ├── Mix node: ShaderNodeMix
│ └── No interface panels
├── 4.1+
│ ├── Socket creation: node_group.interface.new_socket()
│ ├── Interface panels: node_group.interface.new_panel()
│ ├── Compositor: scene.use_nodes = True; scene.node_tree
│ ├── Mix node: ShaderNodeMix
│ └── Alpha blending (4.2+): mat.surface_render_method = 'BLENDED'
└── 5.0+
├── Socket creation: node_group.interface.new_socket()
├── Interface panels: node_group.interface.new_panel()
├── Compositor: scene.compositing_node_group (scene.node_tree REMOVED)
├── scene.use_nodes: deprecated (always True)
└── Mix node: ShaderNodeMix
Workflow 1: Geometry Nodes Modifier
Use when: creating a Geometry Nodes setup and assigning it to an object.
Step-by-Step
1. Create node group → bpy.data.node_groups.new(name, 'GeometryNodeTree')
2. Clear nodes → group.nodes.clear()
3. Define interface → group.interface.new_socket() for each input/output
4. Set socket defaults → iterate interface.items_tree, set default_value/min/max
5. Add I/O nodes → group.nodes.new('NodeGroupInput') + 'NodeGroupOutput'
6. Add processing nodes → group.nodes.new(node_type) with location
7. Link nodes → group.links.new(output_socket, input_socket)
8. Get target object → bpy.data.objects["Name"] or bpy.context.active_object
9. Add modifier → obj.modifiers.new(name="Name", type='NODES')
10. Assign node group → modifier.node_group = group
11. Set modifier inputs → iterate interface.items_tree, modifier[identifier] = value
Modifier Input Helper Pattern
# Blender 4.0+ — ALWAYS use this pattern to set modifier inputs
def set_geonodes_inputs(modifier, values_dict):
"""Set Geometry Nodes modifier inputs by name.
Args:
modifier: The Geometry Nodes modifier
values_dict: {"socket_name": value, ...}
"""
for item in modifier.node_group.interface.items_tree:
if item.item_type == 'SOCKET' and item.in_out == 'INPUT':
if item.name in values_dict:
modifier[item.identifier] = values_dict[item.name]
Interface Socket Defaults Pattern
# Blender 4.0+ — Set defaults, min, max on interface sockets
def configure_socket_defaults(group, config):
"""Configure socket defaults after creation.
Args:
group: The node group
config: {"socket_name": {"default": val, "min": val, "max": val}, ...}
"""
for item in group.interface.items_tree:
if item.item_type == 'SOCKET' and item.in_out == 'INPUT':
if item.name in config:
cfg = config[item.name]
if "default" in cfg:
item.default_value = cfg["default"]
if "min" in cfg and hasattr(item, 'min_value'):
item.min_value = cfg["min"]
if "max" in cfg and hasattr(item, 'max_value'):
item.max_value = cfg["max"]
Workflow 2: Shader Material
Use when: creating a material with shader nodes for an object.
Step-by-Step
1. Create material → bpy.data.materials.new(name)
2. Enable nodes → mat.use_nodes = True
3. Get node tree → tree = mat.node_tree
4. Clear defaults → tree.nodes.clear()
5. Add shader nodes → tree.nodes.new(shader_type) with location
6. Add Material Output → tree.nodes.new('ShaderNodeOutputMaterial')
7. Set socket values → node.inputs["Name"].default_value = value
8. Link nodes → tree.links.new(output_socket, input_socket)
9. Assign to object → obj.data.materials.append(mat) or obj.data.materials[0] = mat
Material Assignment Decision
Q: Does the object already have materials?
├── NO → obj.data.materials.append(mat)
├── YES, replace first → obj.data.materials[0] = mat
├── YES, replace specific → obj.data.materials[slot_index] = mat
└── YES, add as extra slot → obj.data.materials.append(mat)
Common Shader Chains
PBR Material:
TexCoord → Mapping → ImageTex → Principled BSDF → Material Output
↑ NormalMap ←── ImageTex (normal)
Procedural Material:
TexCoord → Mapping → NoiseTexture → ColorRamp → Principled BSDF → Output
↓ (Fac)
Bump → Principled (Normal input)
Glass Material (AEC):
Principled BSDF (Transmission Weight=1.0, IOR=1.45) → Material Output
+ mat.surface_render_method = 'BLENDED' (4.2+)
+ mat.blend_method = 'BLEND' (3.x/4.0-4.1)
Workflow 3: World Shader
Use when: setting up environment lighting (HDRI, procedural sky).
Step-by-Step
1. Create world → bpy.data.worlds.new(name)
2. Enable nodes → world.use_nodes = True
3. Get node tree → tree = world.node_tree
4. Clear defaults → tree.nodes.clear()
5. Add environment nodes → TexCoord, Mapping, TexEnvironment or TexSky
6. Add Background node → ShaderNodeBackground (set Strength)
7. Add World Output → ShaderNodeOutputWorld
8. Link chain → TexCoord → Mapping → Env → Background → Output
9. Load HDRI (if needed) → env_tex.image = bpy.data.images.load(path)
10. Assign to scene → bpy.context.scene.world = world
Workflow 4: Compositor Setup
Use when: adding post-processing effects to rendered output.
Step-by-Step (Version-Aware)
1. Check Blender version → bpy.app.version
2a. If 5.0+:
- Create node group → bpy.data.node_groups.new(name, 'CompositorNodeTree')
- Assign to scene → scene.compositing_node_group = comp_tree
2b. If 3.x/4.x:
- Enable nodes → scene.use_nodes = True
- Get tree → comp_tree = scene.node_tree
3. Clear nodes → comp_tree.nodes.clear()
4. Add Render Layers → CompositorNodeRLayers
5. Add processing nodes → filters, color correction, etc.
6. Add Composite output → CompositorNodeComposite
7. Add Viewer (optional) → CompositorNodeViewer
8. Link chain → RenderLayers → processing → Composite
Version-Aware Compositor Access
import bpy
def get_compositor_tree(scene, name="Compositor"):
"""Get or create the compositor tree for the given scene."""
if bpy.app.version >= (5, 0, 0):
tree = bpy.data.node_groups.new(name, 'CompositorNodeTree')
scene.compositing_node_group = tree
else:
scene.use_nodes = True
tree = scene.node_tree
return tree
Workflow 5: Custom Node Group
Use when: creating a reusable node group (any type).
Step-by-Step
1. Choose tree type → 'GeometryNodeTree', 'ShaderNodeTree', or 'CompositorNodeTree'
2. Create group → bpy.data.node_groups.new(name, tree_type)
3. Clear nodes → group.nodes.clear()
4. Define interface:
a. Create panels (4.1+) → group.interface.new_panel(name)
b. Add input sockets → group.interface.new_socket(name, 'INPUT', type, parent=panel)
c. Add output sockets → group.interface.new_socket(name, 'OUTPUT', type)
d. Set defaults/limits → iterate items_tree, set default_value/min_value/max_value
5. Add I/O nodes → NodeGroupInput + NodeGroupOutput
6. Add processing nodes → with positions
7. Link everything → I/O nodes to processing nodes
Using a Group Inside Another Tree
# Blender 4.0+ — Embed a node group inside a tree
group_node = tree.nodes.new('GeometryNodeGroup') # or 'ShaderNodeGroup'
group_node.node_tree = bpy.data.node_groups["MyGroup"]
group_node.location = (x, y)
# Access the group's exposed sockets on the group node
group_node.inputs["InputName"].default_value = value
tree.links.new(some_node.outputs["Out"], group_node.inputs["InputName"])
Group Node Type by Tree Type
| Tree Type | Group Node bl_idname |
|---|---|
| Geometry Nodes | 'GeometryNodeGroup' |
| Shader Nodes | 'ShaderNodeGroup' |
| Compositor Nodes | 'CompositorNodeGroup' |
Workflow 6: Nested Groups
Use when: composing complex node setups from smaller reusable groups.
Step-by-Step
1. Create inner group(s) → each a standalone node group (Workflow 5)
2. Create outer group → another node group
3. Add inner as node → outer.nodes.new('GeometryNodeGroup')
4. Assign inner tree → group_node.node_tree = inner_group
5. Link outer I/O → connect outer's GroupInput/Output to inner group's sockets
6. Set inner defaults → group_node.inputs["Name"].default_value = value
Naming Convention for AEC Groups
AEC_{Component}_{Function}
Examples:
AEC_Wall_Profile
AEC_Slab_Generator
AEC_Column_Array
AEC_Facade_Pattern
AEC_Material_Brick
Workflow 7: AEC Parametric Component
Use when: building parametric AEC elements (walls, slabs, columns) with Geometry Nodes.
Decision Tree: Component Approach
Q: What geometry primitive fits?
├── Rectangular profile → GeometryNodeMeshCube (set Size inputs)
├── Circular section → GeometryNodeMeshCylinder
├── Custom profile → GeometryNodeCurvePrimitiveLine + mesh conversion
├── Extruded shape → Profile curve + GeometryNodeExtrudeMesh
└── Array/Pattern → GeometryNodeInstanceOnPoints
Standard AEC Interface Sockets
For parametric AEC components, ALWAYS include these interface sockets:
Inputs:
- Geometry (NodeSocketGeometry) — base geometry passthrough
- Width/Length/Height/Thickness (NodeSocketFloat) — dimensions
- Material (NodeSocketMaterial) — material assignment
- Count/Spacing (NodeSocketFloat/Int) — for arrays
Outputs:
- Geometry (NodeSocketGeometry) — result geometry
See create_aec_component() in references/methods.md for the reusable factory function.
Workflow 8: AEC Material Library
Use when: creating a set of standard AEC materials programmatically.
Step-by-Step
1. Define material specs → list of (name, base_color, roughness, metallic, ...)
2. For each material:
a. Create material → bpy.data.materials.new(name)
b. Enable nodes → mat.use_nodes = True
c. Clear defaults → mat.node_tree.nodes.clear()
d. Build shader chain → Principled BSDF → Output
e. Set properties → base color, roughness, metallic, etc.
3. Assign to objects → by material slot
AEC Material Naming Convention
AEC_{Category}_{Name}
Examples:
AEC_Concrete_Cast
AEC_Steel_Brushed
AEC_Glass_Clear
AEC_Wood_Oak
AEC_Brick_Red
AEC_Plaster_White
Common Utilities
See references/methods.md for complete implementations of:
layout_nodes_horizontal()/layout_nodes_grid()— node positioningget_or_create_node_group()— safe retrievalcreate_socket_compat()— version-aware socket creationbuild_node_chain()— sequential node chain buildercreate_principled_material()— quick material factoryembed_node_group()— embed groups inside other treescreate_aec_component()— AEC parametric component factory
Node Position Guidelines
ALWAYS use consistent positioning to keep node trees readable:
| Element | Recommended X | Purpose |
|---|---|---|
| Group Input | -400 to -600 | Far left |
| Input processing | -200 to -300 | Near left |
| Core processing | -100 to 100 | Center |
| Output processing | 200 to 300 | Near right |
| Group Output | 400 to 600 | Far right |
Vertical spacing: 200 units between parallel branches.
Use NodeFrame nodes to visually group related nodes:
frame = tree.nodes.new('NodeFrame')
frame.label = "Section Name"
node_a.parent = frame
node_b.parent = frame
Reference Links
- references/methods.md — Implementation helper functions and utility patterns
- references/examples.md — Complete AEC node implementation examples
- references/anti-patterns.md — Implementation workflow anti-patterns
- Related syntax skill:
blender-syntax-nodes— API signatures and code patterns
Official Sources
- https://docs.blender.org/api/current/bpy.types.NodeTree.html
- https://docs.blender.org/api/current/bpy.types.NodeTreeInterface.html
- https://docs.blender.org/api/current/bpy.types.GeometryNode.html
- https://developer.blender.org/docs/release_notes/4.0/python_api/
- https://developer.blender.org/docs/release_notes/5.0/python_api/
More from openaec-foundation/computational-design-day-delft-march-2026
blender-core-api
Guides Blender Python API usage including bpy module structure, RNA data access, context system, dependency graph, and operator invocation. Activates when writing bpy scripts, creating Blender addons, or accessing Blender data blocks programmatically.
1blender-syntax-panels
Defines Blender UI panel creation including bpy.types.Panel, draw() method, UILayout API (row/column/box/split), bl_space_type, bl_region_type, bl_category, sub-panels, draw_header, menus, and UIList. Activates when creating custom Blender panels, building addon interfaces, or working with UILayout elements.
1ifcos-syntax-api
Documents the ifcopenshell.api module system with all 30+ API modules, invocation patterns via api.run() and direct module calls, parameter conventions, and module categorization. Activates when creating IFC entities, modifying properties, managing spatial structure, or using any ifcopenshell.api function.
1bonsai-impl-bcf
Guides implementation of BIM Collaboration Format (BCF) workflows in Bonsai including creating BCF topics, adding viewpoints with camera snapshots, managing comments, importing/exporting BCF files (v2.1 and v3.0), and integrating BCF issue tracking with IFC element references. Activates when working with BCF files, BIM issue tracking, clash report management, or collaboration workflows in Bonsai.
1ifcos-impl-mep
Guides MEP (Mechanical, Electrical, Plumbing) modeling in IFC using ifcopenshell.api.system including IfcSystem, IfcDistributionElement, ports, connections, flow segments, fittings, and MEP-specific property sets. Activates when creating HVAC systems, piping networks, electrical circuits, or MEP elements in IFC models.
1ifcos-impl-cost
Guides IFC cost management using ifcopenshell.api.cost including cost schedules, cost items, cost values, cost quantities, and 5D BIM workflows. Activates when implementing cost estimation in IFC models, creating cost schedules, or linking quantities to cost items.
1