blender-syntax-properties
blender-syntax-properties
Quick Reference
Property Type Selection
| Need | Property Type | Python Type |
|---|---|---|
| Toggle/flag | BoolProperty |
bool |
| Count/index | IntProperty |
int |
| Size/factor | FloatProperty |
float |
| Name/path | StringProperty |
str |
| Dropdown/mode | EnumProperty |
str (identifier) |
| Axis toggles (X, Y, Z) | BoolVectorProperty |
tuple[bool, ...] |
| Dimensions | IntVectorProperty |
tuple[int, ...] |
| Color/position/rotation | FloatVectorProperty |
tuple[float, ...] |
| Link to another type | PointerProperty |
Reference to PropertyGroup or ID |
| Dynamic list | CollectionProperty |
List of PropertyGroup items |
Critical Warnings
ALWAYS use Python annotation syntax (: not =) for property declarations in classes.
ALWAYS register sub-PropertyGroups BEFORE parent PropertyGroups — registration order matters.
ALWAYS store dynamic enum callback results in a module-level variable to prevent garbage collection crashes.
ALWAYS set explicit unique integer values in enum items used with ENUM_FLAG or getter/setter patterns.
NEVER modify the property that triggered an update callback — causes infinite recursion.
NEVER define set without a matching get callback — Blender raises an error.
NEVER call operators inside update callbacks — they trigger undo and corrupt state.
NEVER set default on EnumProperty when items is a callback — use default=None or omit it.
Version-Critical Changes
| Version | Change | Impact |
|---|---|---|
| 4.1 | Enum ID properties via id_properties_ui |
Integer custom properties can display as dropdowns |
| 5.0 | property_unset() replaces del obj["prop"] |
RNA properties use separate storage from custom properties |
| 5.0 | get_transform / set_transform callbacks |
Faster alternative to get/set using internal storage |
| 5.0 | IDProperty storage split | bpy.props-defined properties no longer accessible via dict syntax |
Blender 5.0 Property Storage Split
# Blender <5.0: dict access to RNA properties worked
value = obj["my_rna_prop"] # WORKED in 4.x
# Blender 5.0+: dict access BROKEN for bpy.props-defined properties
value = obj["my_rna_prop"] # Returns None or KeyError
# CORRECT in 5.0+: use RNA path
value = obj.my_rna_prop
# Reset property to default (replaces del obj["prop"]):
obj.property_unset("my_rna_prop")
Essential Patterns
Pattern 1: Basic Property Declaration
# Blender 3.x/4.x/5.x — annotation syntax REQUIRED
class MyOperator(bpy.types.Operator):
bl_idname = "object.my_operator"
bl_label = "My Operator"
count: bpy.props.IntProperty(name="Count", default=5, min=1, max=100)
factor: bpy.props.FloatProperty(name="Factor", default=1.0, subtype='FACTOR')
name_input: bpy.props.StringProperty(name="Name", default="Object")
Pattern 2: PropertyGroup Registration
# Blender 3.x/4.x/5.x
class MySettings(bpy.types.PropertyGroup):
enabled: bpy.props.BoolProperty(name="Enabled", default=True)
count: bpy.props.IntProperty(name="Count", default=5, min=1)
scale: bpy.props.FloatProperty(name="Scale", default=1.0, min=0.01)
def register():
bpy.utils.register_class(MySettings)
bpy.types.Scene.my_settings = bpy.props.PointerProperty(type=MySettings)
def unregister():
del bpy.types.Scene.my_settings
bpy.utils.unregister_class(MySettings)
Pattern 3: Nested PropertyGroups
# Blender 3.x/4.x/5.x — registration order is CRITICAL
class SubSettings(bpy.types.PropertyGroup):
value: bpy.props.FloatProperty(name="Value", default=0.0)
class MainSettings(bpy.types.PropertyGroup):
sub: bpy.props.PointerProperty(type=SubSettings)
items: bpy.props.CollectionProperty(type=SubSettings)
active_index: bpy.props.IntProperty()
def register():
bpy.utils.register_class(SubSettings) # FIRST: sub-types
bpy.utils.register_class(MainSettings) # SECOND: parent type
bpy.types.Scene.settings = bpy.props.PointerProperty(type=MainSettings)
def unregister():
del bpy.types.Scene.settings
bpy.utils.unregister_class(MainSettings) # Reverse order
bpy.utils.unregister_class(SubSettings)
Pattern 4: Static EnumProperty
# Blender 3.x/4.x/5.x
# Items: (identifier, name, description[, icon[, number]])
my_mode: bpy.props.EnumProperty(
name="Mode",
items=[
('FAST', "Fast", "Low quality, fast render", 'PLAY', 0),
('MEDIUM', "Medium", "Balanced quality", 'PAUSE', 1),
('HIGH', "High", "High quality, slow render", 'RENDER_STILL', 2),
],
default='MEDIUM',
)
Pattern 5: Dynamic EnumProperty
# Blender 3.x/4.x/5.x
# WARNING: MUST store results to prevent garbage collection crash
_enum_items_cache = [] # Module-level storage REQUIRED
def get_object_items(self, context):
global _enum_items_cache
_enum_items_cache = [
(obj.name, obj.name, f"Select {obj.name}", 'OBJECT_DATA', i)
for i, obj in enumerate(bpy.data.objects)
]
if not _enum_items_cache:
_enum_items_cache = [('NONE', "None", "No objects available", 'ERROR', 0)]
return _enum_items_cache
my_object: bpy.props.EnumProperty(
name="Object",
items=get_object_items,
# default MUST be None or omitted when items is a callback
)
Pattern 6: Update Callback
# Blender 3.x/4.x/5.x
def on_count_changed(self, context):
# SAFE: modify OTHER properties on self
if self.count > 10:
self.warning = "High count may impact performance"
# UNSAFE: do NOT modify self.count here (infinite recursion)
# UNSAFE: do NOT call bpy.ops.* here (undo corruption)
class MySettings(bpy.types.PropertyGroup):
count: bpy.props.IntProperty(
name="Count", default=5, update=on_count_changed,
)
warning: bpy.props.StringProperty()
Pattern 7: Getter/Setter
# Blender 3.x/4.x/5.x
def get_computed(self):
# Compute value on read — no internal storage
return len(bpy.data.objects)
def set_computed(self, value):
# Handle write — must store somewhere if persistence needed
self["_cached_count"] = value
class MySettings(bpy.types.PropertyGroup):
object_count: bpy.props.IntProperty(
name="Object Count",
get=get_computed,
set=set_computed,
)
Pattern 8: Get/Set Transform (Blender 5.0+)
# Blender 5.0+ ONLY — faster than get/set, uses internal storage
def clamp_transform(self, new_value, curr_value, is_set):
"""Transform value before storing."""
return max(0.0, min(new_value, 100.0))
def display_transform(self, curr_value, is_set):
"""Transform value on read."""
return curr_value * 2.0 if is_set else 0.0
class MySettings(bpy.types.PropertyGroup):
clamped: bpy.props.FloatProperty(
name="Clamped",
set_transform=clamp_transform,
get_transform=display_transform,
)
Pattern 9: ENUM_FLAG (Multi-Select)
# Blender 3.x/4.x/5.x — numbers MUST be powers of 2
my_flags: bpy.props.EnumProperty(
name="Axes",
items=[
('X', "X Axis", "Include X axis", 1),
('Y', "Y Axis", "Include Y axis", 2),
('Z', "Z Axis", "Include Z axis", 4),
],
options={'ENUM_FLAG'},
default={'X', 'Z'}, # Default is a SET, not a string
)
Pattern 10: PointerProperty with Poll
# Blender 3.x/4.x/5.x — filter selectable objects
def filter_mesh_objects(self, obj):
return obj.type == 'MESH'
class MySettings(bpy.types.PropertyGroup):
target: bpy.props.PointerProperty(
type=bpy.types.Object,
name="Target",
poll=filter_mesh_objects,
)
Pattern 11: CollectionProperty Operations
# Blender 3.x/4.x/5.x
scene = bpy.context.scene
# Add item
item = scene.my_settings.items.add()
item.name = "New Item"
item.value = 42.0
# Remove by index
scene.my_settings.items.remove(0)
# Move item (from_index, to_index)
scene.my_settings.items.move(0, 2)
# Clear all
scene.my_settings.items.clear()
# Iterate
for item in scene.my_settings.items:
print(item.name, item.value)
# Access by index
first = scene.my_settings.items[0]
# Find by name (returns index or -1)
idx = scene.my_settings.items.find("New Item")
Subtype and Unit Quick Reference
Numeric Subtypes
| Subtype | Applies To | Effect |
|---|---|---|
'NONE' |
All | Default display |
'PIXEL' |
Int/Float | Pixel unit display |
'UNSIGNED' |
Int | Unsigned display |
'PERCENTAGE' |
Float | 0-100% display |
'FACTOR' |
Float | 0.0-1.0 slider |
'ANGLE' |
Float | Radians with degree display |
'TIME' |
Float | Scene-relative time (frames) |
'TIME_ABSOLUTE' |
Float | Absolute time (seconds) |
'DISTANCE' |
Float | Distance in scene units |
'POWER' |
Float | Power unit display |
'TEMPERATURE' |
Float | Temperature display |
Vector Subtypes
| Subtype | Applies To | Effect |
|---|---|---|
'COLOR' |
FloatVector | Linear RGB color picker |
'COLOR_GAMMA' |
FloatVector | Gamma-space color picker |
'TRANSLATION' |
FloatVector | Position in scene units |
'DIRECTION' |
FloatVector | Normalized direction |
'VELOCITY' |
FloatVector | Velocity vector |
'ACCELERATION' |
FloatVector | Acceleration vector |
'EULER' |
FloatVector | Euler rotation (radians) |
'QUATERNION' |
FloatVector | Quaternion rotation (size=4) |
'AXISANGLE' |
FloatVector | Axis-angle rotation (size=4) |
'XYZ' |
FloatVector | Generic XYZ coordinates |
'MATRIX' |
FloatVector | Matrix representation |
String Subtypes
| Subtype | Effect |
|---|---|
'NONE' |
Plain text input |
'FILE_PATH' |
File browser button |
'DIR_PATH' |
Directory browser button |
'FILE_NAME' |
File name field |
'BYTE_STRING' |
Byte string |
'PASSWORD' |
Masked input (***) |
Unit Values (FloatProperty / FloatVectorProperty only)
| Unit | Display |
|---|---|
'NONE' |
No unit |
'LENGTH' |
Scene length unit |
'AREA' |
Area (length²) |
'VOLUME' |
Volume (length³) |
'ROTATION' |
Degrees/radians |
'TIME' |
Scene-relative time |
'TIME_ABSOLUTE' |
Absolute seconds |
'VELOCITY' |
Speed |
'ACCELERATION' |
Acceleration |
'MASS' |
Mass |
'CAMERA' |
Camera distance |
'POWER' |
Power |
'TEMPERATURE' |
Temperature |
Options Flags
| Flag | Applies To | Effect |
|---|---|---|
'HIDDEN' |
All | Hidden from UI, accessible via Python |
'SKIP_SAVE' |
All | Value not saved between operator invocations |
'ANIMATABLE' |
All (default) | Can be keyframed |
'LIBRARY_EDITABLE' |
All | Editable on linked data-blocks |
'PROPORTIONAL' |
Numeric | Proportional editing support |
'TEXTEDIT_UPDATE' |
String | Updates on each keystroke |
'ENUM_FLAG' |
Enum only | Multi-select with power-of-2 values |
Decision Trees
When to Use PointerProperty vs CollectionProperty
Need to reference ONE item?
├── YES → PointerProperty
│ ├── Reference to another PropertyGroup? → type=MyPropertyGroup
│ └── Reference to an ID type? → type=bpy.types.Object (or Material, etc.)
└── NO → Need a LIST of items?
└── YES → CollectionProperty(type=MyPropertyGroup)
└── Track active selection? → Add IntProperty for active_index
When to Use get/set vs get_transform/set_transform
Blender version?
├── <5.0 → Use get/set (only option)
└── >=5.0
├── Need custom storage logic? → Use get/set
└── Only need value transformation?
└── Use get_transform/set_transform (faster, uses internal storage)
When to Use update vs msgbus
Property changes on THIS class?
├── YES → Use update callback on the property
└── NO → Watching EXTERNAL property changes?
└── YES → Use bpy.msgbus.subscribe_rna()
Attachment Points
Properties can be attached to any Blender ID type:
# Per-scene settings
bpy.types.Scene.my_prop = bpy.props.PointerProperty(type=MySettings)
# Per-object settings
bpy.types.Object.my_prop = bpy.props.PointerProperty(type=MySettings)
# Per-material settings
bpy.types.Material.my_prop = bpy.props.FloatProperty(name="Custom")
# Per-mesh settings
bpy.types.Mesh.my_prop = bpy.props.IntProperty(name="Custom")
# Per-bone settings
bpy.types.Bone.my_prop = bpy.props.StringProperty(name="Custom")
# Per-window-manager (session-only, not saved)
bpy.types.WindowManager.my_prop = bpy.props.BoolProperty(name="Temp")
WindowManager properties are session-only — they reset when Blender restarts. Use for temporary UI state.
Reference Links
- references/methods.md — Complete API signatures for all bpy.props types
- references/examples.md — Working code examples for every property pattern
- references/anti-patterns.md — What NOT to do, with explanations
Official Sources
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