Install
$ agentstack add skill-impertio-studio-blender-bonsai-ifcopenshell-sverchok-claude-skill-package-bonsai-syntax-geometry ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
Bonsai Geometry Syntax
> Version: Bonsai v0.8.x | IfcOpenShell v0.8+ | Blender 4.2.0+ | Python 3.11 > Module path: bonsai.bim.module.geometry — NEVER blenderbim.* > Dependencies: bonsai-core-architecture, ifcos-syntax-api
Critical Warnings
- ALWAYS create a Body context before adding geometry. Call
ifcopenshell.util.representation.get_context(model, "Model", "Body", "MODEL_VIEW")and create the context if it returnsNone. - ALWAYS use
ifcopenshell.api.run("geometry.assign_representation", ...)to connect a representation to an element. NEVER setproduct.Representationdirectly. - ALWAYS call
bpy.ops.bim.edit_object_placement()(orifcopenshell.api.run("geometry.edit_object_placement", ...)) after moving a Blender object. Changingobj.locationorobj.matrix_worlddoes NOT updateIfcLocalPlacement. - ALWAYS call
geometry.unassign_representationbeforegeometry.remove_representation. Removing an assigned representation leaves dangling references. - NEVER create
IfcExtrudedAreaSolidviamodel.create_entity(). Usegeometry.add_wall_representation(),geometry.add_profile_representation(), orShapeBuilder.extrude()— they handle units, context assignment, andRepresentationTypeautomatically. - NEVER pass a single element to
verticesinadd_mesh_representation(). The parameter expects[[item1_verts], [item2_verts]]— a list of lists, parallel tofaces. - ALWAYS use
feature.add_feature()for openings in Bonsai v0.8.0+. The oldervoid.add_opening()still works in standalone IfcOpenShell but is superseded in Bonsai. - NEVER assume
RepresentationTypeis set automatically bymodel.create_entity("IfcShapeRepresentation", ...). Use API functions orShapeBuilder.get_representation()which auto-detect the correct type.
Decision Tree: How to Create Geometry
What geometry do you need?
|
+-- Parametric wall (rectangle cross-section)?
| --> geometry.add_wall_representation(context, length, height, thickness)
|
+-- Parametric slab (extruded footprint)?
| --> geometry.add_slab_representation(context, depth, polyline=[(x,y),...])
|
+-- Standard profile extrusion (I-beam, rectangle, circle, L, T, U, Z, C)?
| --> 1. profile.add_parameterized_profile(ifc_class="IfcRectangleProfileDef")
| --> 2. attribute.edit_attributes(product=profile, attributes={"XDim": 0.4, "YDim": 0.4})
| --> 3. geometry.add_profile_representation(context, profile=profile, depth=3.0)
|
+-- Custom profile extrusion (arbitrary shape)?
| --> 1. profile.add_arbitrary_profile(profile=[(x,y), ...])
| --> 2. geometry.add_profile_representation(context, profile=profile, depth=3.0)
|
+-- Arbitrary mesh from Blender (tessellated)?
| --> geometry.add_mesh_representation(context, vertices=[[...]], faces=[[...]])
|
+-- Complex parametric solid (sphere, block, swept disk)?
| --> ShapeBuilder: builder.sphere(), builder.block(), builder.create_swept_disk_solid()
| --> Then: builder.get_representation(context, [solid])
|
+-- Geometry with boolean cuts (clipped walls, angled tops)?
| --> Option A: clippings parameter in add_wall/slab/profile_representation
| --> Option B: geometry.add_boolean(first_item, second_items, operator="DIFFERENCE")
|
+-- 2D axis line (wall centerline, beam axis)?
| --> geometry.add_axis_representation(context, axis=[(x1,y1), (x2,y2)])
|
+-- Blender mesh -> IFC in Bonsai (live editing)?
| --> bpy.ops.bim.update_representation(obj="ObjectName")
Representation Contexts
Two-Step Context Setup
import ifcopenshell.api
import ifcopenshell.util.representation
# Step 1: Check for existing context
body = ifcopenshell.util.representation.get_context(
model, "Model", "Body", "MODEL_VIEW")
# Step 2: Create if missing
if not body:
model3d = ifcopenshell.api.run("context.add_context", model,
context_type="Model")
body = ifcopenshell.api.run("context.add_context", model,
context_type="Model", context_identifier="Body",
target_view="MODEL_VIEW", parent=model3d)
Context Types and Sub-Contexts
| Parent Context | Sub-Context Identifier | Target View | Purpose | |---|---|---|---| | Model | Body | MODELVIEW | Main 3D solid geometry | | Model | Axis | GRAPHVIEW | Centerline/axis (walls, beams) | | Model | Box | MODELVIEW | Bounding box (clash detection) | | Model | FootPrint | MODELVIEW | 2D floor projection | | Model | Profile | ELEVATIONVIEW | Cross-section profile | | Model | Clearance | MODELVIEW | Clearance zones | | Plan | Annotation | PLANVIEW | 2D annotations, dimensions | | Plan | Axis | PLANVIEW | 2D centerline for plan views |
ALWAYS create the root context first (no parent), then create subcontexts with parent=root_context.
Representation Types Reference
| RepresentationType | IFC Items | Typical Use | |---|---|---| | "SweptSolid" | IfcExtrudedAreaSolid, IfcRevolvedAreaSolid | Walls, columns, beams, slabs | | "Clipping" | IfcBooleanClippingResult | Walls/slabs with angled cuts | | "Brep" | IfcFacetedBrep | Arbitrary mesh (IFC2X3 or forced) | | "Tessellation" | IfcPolygonalFaceSet, IfcTriangulatedFaceSet | Arbitrary mesh (IFC4+) | | "AdvancedBrep" | IfcAdvancedBrep | NURBS/curved geometry | | "SurfaceModel" | IfcFaceBasedSurfaceModel | Open shells | | "Curve2D" | IfcPolyline, IfcIndexedPolyCurve | 2D axis lines | | "Curve3D" | IfcPolyline, IfcIndexedPolyCurve | 3D axis lines | | "MappedRepresentation" | IfcMappedItem | Type-shared geometry | | "BoundingBox" | IfcBoundingBox | Box context only |
Common Operations
Create Wall Geometry
import ifcopenshell.api
# Requires: body context, wall element already created
representation = ifcopenshell.api.run("geometry.add_wall_representation", model,
context=body, length=5.0, height=3.0, thickness=0.2)
ifcopenshell.api.run("geometry.assign_representation", model,
product=wall, representation=representation)
ifcopenshell.api.run("geometry.edit_object_placement", model, product=wall)
Create Profile Extrusion (Column)
import ifcopenshell.api
profile = ifcopenshell.api.run("profile.add_parameterized_profile", model,
ifc_class="IfcRectangleProfileDef")
ifcopenshell.api.run("attribute.edit_attributes", model,
product=profile, attributes={"XDim": 0.4, "YDim": 0.4})
representation = ifcopenshell.api.run("geometry.add_profile_representation", model,
context=body, profile=profile, depth=3.0)
ifcopenshell.api.run("geometry.assign_representation", model,
product=column, representation=representation)
Create Mesh Representation
import ifcopenshell.api
# Vertices and faces as list-of-lists (one sub-list per representation item)
vertices = [[(0.,0.,0.), (1.,0.,0.), (1.,1.,0.), (0.,1.,0.),
(0.,0.,1.), (1.,0.,1.), (1.,1.,1.), (0.,1.,1.)]]
faces = [[(0,1,2,3), (4,5,6,7), (0,1,5,4), (1,2,6,5), (2,3,7,6), (3,0,4,7)]]
representation = ifcopenshell.api.run("geometry.add_mesh_representation", model,
context=body, vertices=vertices, faces=faces)
ifcopenshell.api.run("geometry.assign_representation", model,
product=element, representation=representation)
Boolean Clipping (Angled Wall Top)
import ifcopenshell.api
# Option A: Via clippings parameter (preferred for simple cuts)
representation = ifcopenshell.api.run("geometry.add_wall_representation", model,
context=body, length=5.0, height=3.0, thickness=0.2,
clippings=[{"location": (0.0, 0.0, 2.5), "normal": (0.0, -0.3, 1.0)}])
# Option B: Via add_boolean (for complex operations)
# first_item = existing IfcExtrudedAreaSolid from representation.Items[0]
# second_item = IfcHalfSpaceSolid
results = ifcopenshell.api.run("geometry.add_boolean", model,
first_item=first_item, second_items=[second_item], operator="DIFFERENCE")
Create Opening (Void)
import ifcopenshell.api
opening = ifcopenshell.api.run("root.create_entity", model,
ifc_class="IfcOpeningElement", name="Door Opening")
# Create opening geometry (box shape)
opening_repr = ifcopenshell.api.run("geometry.add_wall_representation", model,
context=body, length=0.9, height=2.1, thickness=0.3)
ifcopenshell.api.run("geometry.assign_representation", model,
product=opening, representation=opening_repr)
# Attach opening to wall (Bonsai v0.8+: use feature.add_feature)
ifcopenshell.api.run("feature.add_feature", model,
feature=opening, element=wall)
# Optionally fill with door
ifcopenshell.api.run("feature.add_filling", model,
opening=opening, element=door)
Remove Representation (Correct Order)
import ifcopenshell.api
# Step 1: Unassign from product
ifcopenshell.api.run("geometry.unassign_representation", model,
product=element, representation=representation)
# Step 2: Remove the representation entity
ifcopenshell.api.run("geometry.remove_representation", model,
representation=representation)
ShapeBuilder: Parametric Geometry
from ifcopenshell.util.shape_builder import ShapeBuilder
builder = ShapeBuilder(model)
# Extrude a rectangle
rect = builder.rectangle(size=(0.4, 0.4))
profile = builder.profile(rect, name="Column Profile")
solid = builder.extrude(profile, magnitude=3.0)
representation = builder.get_representation(body, [solid])
# Assign to element
ifcopenshell.api.run("geometry.assign_representation", model,
product=column, representation=representation)
Bonsai Operators (Blender Context)
| Operator | Purpose | |---|---| | bpy.ops.bim.edit_object_placement() | Sync Blender transform to IFC | | bpy.ops.bim.update_representation(obj="Name") | Sync Blender mesh to IFC representation | | bpy.ops.bim.add_representation() | Add new IFC representation to object | | bpy.ops.bim.switch_representation() | Switch active representation | | bpy.ops.bim.remove_representation() | Remove a representation | | bpy.ops.bim.copy_representation() | Copy representation from active to selected | | bpy.ops.bim.override_mode_set_edit() | Enter edit mode (IFC-aware) | | bpy.ops.bim.override_mode_set_object() | Return to object mode (saves IFC) | | bpy.ops.bim.enable_editing_representation_items() | Enable per-item editing | | bpy.ops.bim.remove_representation_item() | Remove single representation item |
Representation Class Hints for update_representation
When calling bpy.ops.bim.update_representation(ifc_representation_class="..."), valid values:
| Value | Effect | |---|---| | "IfcExtrudedAreaSolid/IfcRectangleProfileDef" | Auto-detect rectangular extrusion | | "IfcExtrudedAreaSolid/IfcCircleProfileDef" | Auto-detect cylindrical extrusion | | "IfcExtrudedAreaSolid/IfcArbitraryClosedProfileDef" | Auto-detect arbitrary profile extrusion | | "IfcExtrudedAreaSolid/IfcArbitraryProfileDefWithVoids" | Profile extrusion with holes | | "IfcExtrudedAreaSolid/IfcMaterialProfileSetUsage" | Profile from material set | | "" (empty/omitted) | Tessellation/Brep (mesh as-is) |
MappedItems: Type Geometry Sharing
When type.assign_type is called, geometry on the IfcTypeProduct is shared to all instances via IfcMappedItem. Each instance references the type's IfcRepresentationMap with its own transformation.
ALWAYS assign geometry to the type, not individual occurrences, when using typed elements. This ensures geometry is shared efficiently.
# Add geometry to type (not occurrence)
ifcopenshell.api.run("geometry.assign_representation", model,
product=wall_type, representation=representation)
# Assign type to occurrence: geometry is automatically mapped
ifcopenshell.api.run("type.assign_type", model,
related_objects=[wall], relating_type=wall_type)
Version Notes
IFC2X3 vs IFC4+ Geometry Differences
| Feature | IFC2X3 | IFC4+ | |---|---|---| | Mesh representation | IfcFacetedBrep only | IfcPolygonalFaceSet (preferred), IfcTriangulatedFaceSet | | Curve types | IfcPolyline | IfcIndexedPolyCurve (preferred), IfcPolyline | | Boolean result | IfcBooleanResult | IfcBooleanClippingResult (for DIFFERENCE + SweptSolid) | | Triangulated mesh | Not available | IfcTriangulatedFaceSet |
Bonsai v0.8.0+ Changes
void.add_opening()superseded byfeature.add_feature()for all feature typesfeature.add_feature()handles subtraction (IfcRelVoidsElement), addition (IfcRelProjectsElement), and surface features (IfcRelAdheresToElement)- Relationship API functions now require list parameters:
products=[element], notproduct=element
References
- [methods.md](references/methods.md) — Complete geometry API signatures
- [examples.md](references/examples.md) — Working geometry code examples
- [anti-patterns.md](references/anti-patterns.md) — Geometry mistakes to avoid
Sources
- Bonsai source:
bonsai/bim/module/geometry/(v0.8.x) - IfcOpenShell API:
ifcopenshell/api/geometry/(v0.8+) - IfcOpenShell ShapeBuilder:
ifcopenshell/util/shape_builder.py - Bonsai Documentation: https://docs.bonsaibim.org
- IfcOpenShell Docs: https://docs.ifcopenshell.org
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: Impertio-Studio
- Source: Impertio-Studio/Blender-Bonsai-ifcOpenshell-Sverchok-Claude-Skill-Package
- License: MIT
- Homepage: https://github.com/OpenAEC-Foundation
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.