| name | bonsai-impl-bcf |
| description | 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. |
| license | MIT |
| compatibility | Designed for Claude Code. Requires Blender with Bonsai addon. |
| metadata | {"author":"OpenAEC-Foundation","version":"1.0"} |
BCF Workflows in Bonsai
Version: Bonsai v0.8.x | Blender 4.2.0+ | Python 3.11
Module path: bonsai.bim.module.bcf — NEVER blenderbim.bim.module.bcf
BCF versions: v2.1 and v3.0 (via bcf.bcfxml library bundled with IfcOpenShell)
Dependencies: bonsai-core-architecture, bonsai-syntax-elements
Critical Warnings
- ALWAYS set
scene.BCFProperties.author to a valid email BEFORE creating topics or comments. Default "john@doe.com" is a placeholder — replace it.
- ALWAYS use
BcfStore.get_bcfxml() to access BCF data. NEVER access BcfStore.bcfxml directly — get_bcfxml() handles lazy initialization and path resolution.
- ALWAYS call
bpy.ops.bim.save_bcf_project() to persist changes. BCF modifications are in-memory only until saved.
- NEVER mix BCF v2.1 and v3.0 operations on the same project. The version is set at creation/load time and MUST remain consistent.
- ALWAYS ensure an active camera exists before calling
bpy.ops.bim.add_bcf_viewpoint(). The operator polls for an active scene camera.
- NEVER assume viewpoint coordinates match the loaded IFC model coordinates. Viewpoint activation applies georeference offset corrections.
- ALWAYS use
bonsai.* imports. NEVER use blenderbim.* — renamed in 2024 (v0.8.0+).
- BCF v3.0 REQUIRES non-empty
status and type fields on topics. These are optional in v2.1 but mandatory in v3.0.
Architecture Overview
The BCF module diverges from Bonsai's standard core/tool/operator pattern. At v0.8.x, most domain logic lives directly in operators rather than in a separate core/bcf.py. The tool/bcf.py provides version-agnostic helper methods for topic data access.
+----------------------------------------------------------+
| DELIVERY LAYER — bim/module/bcf/ |
| operator.py (30+ operators), prop.py, ui.py |
+----------------------------------------------------------+
| TOOL LAYER — tool/bcf.py |
| Version-agnostic getters/setters for topic data |
+----------------------------------------------------------+
| DATA LAYER — bcfstore.py (BcfStore singleton) |
| Class-level singleton wrapping bcf.bcfxml.BcfXml |
+----------------------------------------------------------+
| LIBRARY — bcf.v2.bcfxml / bcf.v3.bcfxml |
| BCF-XML parser bundled with IfcOpenShell |
+----------------------------------------------------------+
Key singleton: BcfStore manages BCF data as a class-level singleton. Only ONE BCF project is loaded at a time. Access via BcfStore.get_bcfxml().
Properties access: bpy.context.scene.BCFProperties (or tool.Bcf.get_bcf_props()) holds all BCF UI state.
Decision Tree: BCF Workflow Selection
What BCF operation do you need?
│
├── Start a new BCF project?
│ └── bpy.ops.bim.new_bcf_project()
│ ├── Set props.bcf_version = "2" (v2.1) or "3" (v3.0) FIRST
│ └── Sets up empty BcfXml in BcfStore
│
├── Load an existing BCF file?
│ └── bpy.ops.bim.load_bcf_project(filepath="/path/to/file.bcf")
│ └── Auto-detects version, populates BcfStore + topics
│
├── Create/manage issues?
│ ├── Add topic: bpy.ops.bim.add_bcf_topic()
│ ├── Edit topic: bpy.ops.bim.edit_bcf_topic()
│ ├── View topic: bpy.ops.bim.view_bcf_topic(topic_guid="...")
│ └── Remove topic: bpy.ops.bim.remove_bcf_topic(guid="...")
│
├── Add visual context to an issue?
│ ├── Capture viewpoint: bpy.ops.bim.add_bcf_viewpoint()
│ ├── Restore viewpoint: bpy.ops.bim.activate_bcf_viewpoint()
│ └── Remove viewpoint: bpy.ops.bim.remove_bcf_viewpoint()
│
├── Add discussion to an issue?
│ ├── Add comment: bpy.ops.bim.add_bcf_comment()
│ ├── Edit comment: bpy.ops.bim.edit_bcf_comment()
│ └── Remove comment: bpy.ops.bim.remove_bcf_comment(comment_guid="...")
│
├── Attach documents/references?
│ ├── Reference link: bpy.ops.bim.add_bcf_reference_link()
│ ├── Document ref: bpy.ops.bim.add_bcf_document_reference()
│ ├── BIM snippet: bpy.ops.bim.add_bcf_bim_snippet()
│ └── Header file: bpy.ops.bim.add_bcf_header_file()
│
├── Save BCF to disk?
│ └── bpy.ops.bim.save_bcf_project(filepath="/path/to/output.bcf")
│
└── Close BCF project?
└── bpy.ops.bim.unload_bcf_project()
Essential Patterns
Pattern 1: BCF Project Lifecycle
import bpy
props = bpy.context.scene.BCFProperties
props.author = "architect@example.com"
props.bcf_version = "3"
bpy.ops.bim.new_bcf_project()
bpy.ops.bim.save_bcf_project(filepath="/path/to/issues.bcf")
bpy.ops.bim.unload_bcf_project()
Pattern 2: Load Existing BCF File
import bpy
bpy.ops.bim.load_bcf_project(filepath="/path/to/issues.bcf")
props = bpy.context.scene.BCFProperties
print(f"Project: {props.name}")
print(f"Version: BCF v{props.bcf_version}")
print(f"Topics: {len(props.topics)}")
for topic in props.topics:
print(f" [{topic.status}] {topic.title} (GUID: {topic.name})")
Pattern 3: Create Topic with Metadata
import bpy
props = bpy.context.scene.BCFProperties
props.author = "engineer@example.com"
bpy.ops.bim.add_bcf_topic()
topic = props.topics[props.active_topic_index]
topic.title = "MEP clash at Level 2 corridor"
topic.type = "Error"
topic.status = "Open"
topic.priority = "Critical"
topic.assigned_to = "mep-coordinator@example.com"
topic.description = "HVAC duct intersects structural beam at grid B-4."
bpy.ops.bim.edit_bcf_topic()
Pattern 4: Capture Viewpoint with Camera Snapshot
import bpy
if bpy.context.scene.camera is None:
raise RuntimeError("Set an active camera before capturing a viewpoint.")
camera = bpy.context.scene.camera
camera.location = (10.0, -5.0, 3.0)
camera.rotation_euler = (1.22, 0.0, 0.78)
bpy.ops.bim.add_bcf_viewpoint()
Pattern 5: Add Comments to a Topic
import bpy
props = bpy.context.scene.BCFProperties
props.author = "reviewer@example.com"
props.comment = "Duct routing needs to be lowered by 200mm to clear beam."
props.has_related_viewpoint = True
bpy.ops.bim.add_bcf_comment()
Pattern 6: Activate (Restore) a Viewpoint
import bpy
props = bpy.context.scene.BCFProperties
topic = props.active_topic
bpy.ops.bim.activate_bcf_viewpoint()
bpy.ops.bim.activate_bcf_viewpoint(viewpoint_guid="abc-123-def-456")
BCF Version Differences
| Feature | BCF v2.1 | BCF v3.0 |
|---|
props.bcf_version value | "2" | "3" |
Topic status field | Optional | REQUIRED (edit fails without it) |
Topic type field | Optional | REQUIRED (edit fails without it) |
| Document storage | Per-topic (TopicDocumentReference) | Global registry (bcfxml.documents) |
| API support | No | Yes (OpenCDE compliant) |
| Data model module | bcf.v2.model | bcf.v3.model |
| BcfXml class | bcf.v2.bcfxml.BcfXml | bcf.v3.bcfxml.BcfXml |
Version Detection
from bonsai.bim.module.bcf.bcfstore import BcfStore
bcfxml = BcfStore.get_bcfxml()
if bcfxml is None:
raise RuntimeError("No BCF project loaded.")
version_id = bcfxml.version.version_id or ""
is_v2 = version_id.startswith("2")
is_v3 = version_id.startswith("3")
Common Operations
Import BCF from External Tool
import bpy
bpy.ops.bim.load_bcf_project(filepath="/path/to/coordination.bcf")
props = bpy.context.scene.BCFProperties
for i, topic in enumerate(props.topics):
print(f"Topic {i}: [{topic.status}] {topic.title}")
bpy.ops.bim.view_bcf_topic(topic_guid=topic.name)
bpy.ops.bim.load_bcf_comments(topic_guid=topic.name)
for comment in topic.comments:
print(f" Comment by {comment.author}: {comment.comment}")
Export BCF for External Tools
import bpy
bpy.ops.bim.save_bcf_project(filepath="/path/to/export.bcf")
bpy.ops.bim.save_bcf_project(save_current_bcf=True)
Link BCF Topic to IFC Elements
import bpy
import bonsai.tool as tool
model = tool.Ifc.get()
if model is None:
raise RuntimeError("No IFC project loaded.")
bpy.ops.object.select_all(action='DESELECT')
for global_id in ["2O2Fr$t4X7Zf8NOew3FLOH", "1kTvXnbbzEWu00n_qpFOat"]:
entity = model.by_guid(global_id)
obj = tool.Ifc.get_object(entity)
if obj:
obj.select_set(True)
bpy.ops.bim.add_bcf_viewpoint()
Clash Detection to BCF Workflow
import bpy
bpy.ops.bim.execute_ifc_clash()
bpy.ops.bim.load_bcf_project(filepath="/path/to/clashes.bcf")
Attach Documents and References
import bpy
props = bpy.context.scene.BCFProperties
props.reference_link = "https://project.example.com/issues/MEP-042"
bpy.ops.bim.add_bcf_reference_link()
props.document_reference = "/path/to/specification.pdf"
props.document_reference_description = "MEP specification section 4.2"
bpy.ops.bim.add_bcf_document_reference()
props.bim_snippet_reference = "/path/to/fragment.ifc"
props.bim_snippet_type = "IfcSharedBuildingElements"
props.bim_snippet_schema = "IFC4"
bpy.ops.bim.add_bcf_bim_snippet()
Add Labels and Related Topics
import bpy
props = bpy.context.scene.BCFProperties
props.label = "MEP"
bpy.ops.bim.add_bcf_label()
props.label = "Structural"
bpy.ops.bim.add_bcf_label()
bpy.ops.bim.add_bcf_related_topic()
Extract Embedded Files
import bpy
bpy.ops.bim.extract_bcf_file(entity_type="HEADER_FILE", index=0)
bpy.ops.bim.extract_bcf_file(entity_type="BIM_SNIPPET", index=0)
bpy.ops.bim.extract_bcf_file(entity_type="DOCUMENT_REFERENCE", index=0)
BcfStore Singleton
The BcfStore class (at bonsai.bim.module.bcf.bcfstore) manages BCF session state:
from bonsai.bim.module.bcf.bcfstore import BcfStore
bcfxml = BcfStore.get_bcfxml()
BcfStore.set(bcfxml, filepath)
BcfStore.set_by_filepath("/path/to/file.bcf")
BcfStore.unload_bcfxml()
Key behavior:
get_bcfxml() calls bcf.bcfxml.load(filepath) from props.bcf_file on first access
set() auto-detects BCF version from bcfxml.version.version_id and updates props.bcf_version
- Silently handles load exceptions (e.g., permission denied) — check return value for
None
- Resolves relative paths against the
.blend file directory
BCFProperties Quick Reference
Access via bpy.context.scene.BCFProperties:
| Property | Type | Purpose |
|---|
author | str | Author email — REQUIRED before creating topics/comments |
bcf_version | enum | "2" (v2.1) or "3" (v3.0) |
bcf_file | str | Path to loaded BCF file |
name | str | Project name |
topics | Collection[BcfTopic] | All loaded topics |
active_topic_index | int | Currently selected topic index |
comment | str | Input field for new comment text |
has_related_viewpoint | bool | Link new comment to active viewpoint |
reference_link | str | Input field for reference link URL |
label | str | Input field for label text |
Computed property: props.active_topic returns BcfTopic at active_topic_index or None.
Drag-and-Drop Support
Bonsai registers BCFFileHandlerOperator with bl_file_extensions = ".bcf", enabling drag-and-drop import of BCF files directly into Blender. The handler calls bim.load_bcf_project with the dropped file path.
Reference Links
Dependencies
- bonsai-core-architecture — Three-layer architecture, IfcStore, operator execution pattern
- bonsai-syntax-elements — IFC element access for linking BCF issues to IFC entities
Sources