AgentStack
SKILL verified MIT Self-run

Bonsai Syntax Geometry

skill-impertio-studio-blender-bonsai-ifcopenshell-sverchok-claude-skill-package-bonsai-syntax-geometry · by Impertio-Studio

>

No reviews yet
0 installs
15 views
0.0% view→install

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

✓ Passed

No 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.

Are you the author of Bonsai Syntax Geometry? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

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

  1. 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 returns None.
  2. ALWAYS use ifcopenshell.api.run("geometry.assign_representation", ...) to connect a representation to an element. NEVER set product.Representation directly.
  3. ALWAYS call bpy.ops.bim.edit_object_placement() (or ifcopenshell.api.run("geometry.edit_object_placement", ...)) after moving a Blender object. Changing obj.location or obj.matrix_world does NOT update IfcLocalPlacement.
  4. ALWAYS call geometry.unassign_representation before geometry.remove_representation. Removing an assigned representation leaves dangling references.
  5. NEVER create IfcExtrudedAreaSolid via model.create_entity(). Use geometry.add_wall_representation(), geometry.add_profile_representation(), or ShapeBuilder.extrude() — they handle units, context assignment, and RepresentationType automatically.
  6. NEVER pass a single element to vertices in add_mesh_representation(). The parameter expects [[item1_verts], [item2_verts]] — a list of lists, parallel to faces.
  7. ALWAYS use feature.add_feature() for openings in Bonsai v0.8.0+. The older void.add_opening() still works in standalone IfcOpenShell but is superseded in Bonsai.
  8. NEVER assume RepresentationType is set automatically by model.create_entity("IfcShapeRepresentation", ...). Use API functions or ShapeBuilder.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 by feature.add_feature() for all feature types
  • feature.add_feature() handles subtraction (IfcRelVoidsElement), addition (IfcRelProjectsElement), and surface features (IfcRelAdheresToElement)
  • Relationship API functions now require list parameters: products=[element], not product=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.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet — be the first.

Versions

  • v0.1.0 Imported from the upstream source.