
Thatopen Core Fragments
- 5 installs
- 17 repo stars
- Updated July 8, 2026
- openaec-foundation/thatopen-claude-skill-package
Helps with ai & agent building tasks.
About
thatopen-core-fragments is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted development.
- thatopen-core-fragments
- AI & Agent Building
- AI-coding skill
Thatopen Core Fragments by the numbers
- 5 all-time installs (skills.sh)
- Ranked #13,065 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Jul 26, 2026 (Skillselion catalog sync)
npx skills add https://github.com/openaec-foundation/thatopen-claude-skill-package --skill thatopen-core-fragmentsAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 5 |
|---|---|
| repo stars | ★ 17 |
| Last updated | July 8, 2026 |
| Repository | openaec-foundation/thatopen-claude-skill-package ↗ |
What it does
Helps with ai & agent building tasks.
Files
ThatOpen Fragment System
Overview
The fragment system is ThatOpen's optimized geometry pipeline for BIM models. It converts IFC files into a GPU-friendly binary format built on FlatBuffers and THREE.InstancedMesh, enabling fast rendering of large models with millions of elements. The @thatopen/fragments package provides the binary format, worker architecture, and core operations. FragmentsManager in @thatopen/components orchestrates model lifecycle, raycasting, data queries, and coordinate alignment.
Pipeline:
IFC File → web-ifc (WASM) → IfcLoader → FragmentsModel (binary .frag)
│
┌─────────┴─────────┐
│ Fragment[] │
│ (InstancedMesh) │
└────────────────────┘Convert once, reload fast: ALWAYS convert IFC to fragments once via IfcLoader, then store the binary .frag file. Subsequent loads skip WASM parsing entirely and load the pre-converted fragment binary directly.
Critical Warnings
1. ALWAYS call `FragmentsManager.init(workerURL)` before ANY fragment operation. The worker handles raycasting, data queries, and model loading off the main thread. Omitting this causes silent failures or crashes.
2. ALWAYS dispose models via FragmentsManager.disposeModel(modelId) or components.dispose() when done. Fragment models hold GPU buffers (InstancedMesh geometry, textures) and worker state. Undisposed models cause memory leaks that crash browser tabs.
3. NEVER skip coordinate alignment in multi-model scenarios. Models from different origins will appear scattered in 3D space. Use applyBaseCoordinateSystem() to align them to a common origin.
4. ALWAYS match the worker.mjs URL to your installed `@thatopen/fragments` version. A version mismatch between the main-thread library and the worker script causes deserialization failures.
Core Concepts
Fragment Binary Format
Fragments use Google FlatBuffers for zero-copy binary serialization:
| Layer | Content |
|---|---|
FragmentGroup (root) | Coordination matrix, IFC metadata, array of Fragments |
Fragment | ID, type (Mesh/InstancedMesh/Point/Line), geometry, transforms, colors |
Geometry | Position/normal/index arrays, groups, bounding box |
Transform | 4x4 matrix, local ID, express ID per instance |
File identifier: FRAG. Dependencies: flatbuffers, pako (compression), earcut (triangulation).
Key advantage: Geometry arrays (position, index) map directly to GPU buffers as zero-copy typed array views. No deserialization step.
GPU Instancing
Each Fragment wraps a THREE.InstancedMesh. Identical geometries (e.g., all doors of the same type) share one GPU geometry buffer with per-instance transform matrices. This reduces draw calls from thousands to dozens.
FragmentsModel
A FragmentsModel represents one loaded BIM model. It contains:
- An array of
Fragmentobjects (instanced meshes) - The coordination matrix (world positioning)
- IFC metadata and property data
- GUID-to-localID mappings
Access loaded models via FragmentsManager.list: Map<string, FragmentsModel>.
FragmentsManager API
class FragmentsManager extends Component implements Disposable {
// State
list: Map<string, FragmentsModel>;
initialized: boolean;
baseCoordinationModel: string;
baseCoordinationMatrix: THREE.Matrix4;
// Initialization — MUST call before any operation
init(workerURL: string, options?): void;
// Raycasting
raycast(config: {
camera: THREE.Camera,
mouse: THREE.Vector2,
dom: HTMLElement,
snappingClasses?: number[]
}): Promise<Result | undefined>;
// Visual operations
highlight(style: MaterialDefinition, items?: ModelIdMap): Promise<void>;
resetHighlight(items?: ModelIdMap): Promise<void>;
// Data queries
getData(items: ModelIdMap, config?): Promise<Record<string, ItemData[]>>;
getPositions(items: ModelIdMap): Promise<THREE.Vector3[]>;
getBBoxes(items: ModelIdMap): Promise<THREE.Box3[]>;
// GUID mapping
guidsToModelIdMap(guids: Iterable<string>): Promise<ModelIdMap>;
modelIdMapToGuids(modelIdMap: ModelIdMap): Promise<string[]>;
// Coordinate alignment
applyBaseCoordinateSystem(object: THREE.Object3D, originalMatrix?: THREE.Matrix4): THREE.Matrix4;
// Disposal
disposeModel(modelId: string): void;
}Events:
onFragmentsLoaded: Event<FragmentsModel>— fires after a model is loadedonBeforeDispose: Event<FragmentsModel>— fires before model disposalonDisposed: Event<void>— fires after FragmentsManager itself is disposed
ModelIdMap
The universal data structure for targeting items across models:
type ModelIdMap = Record<string, Set<number>>;
// Keys: model UUID strings
// Values: sets of local element IDs (numbers)Used by: FragmentsManager, Hider, Classifier, BoundingBoxer, Highlighter, and every component that operates on specific BIM elements.
ALWAYS use ModelIdMap to reference items. NEVER reference items by expressID alone — expressIDs are only unique within a single model.
Worker Architecture
FragmentsManager offloads heavy operations (raycasting, data extraction, model loading) to a dedicated web worker.
// Worker initialization — ALWAYS do this first
const fragments = components.get(OBC.FragmentsManager);
fragments.init("https://unpkg.com/@thatopen/fragments@3.3.6/dist/Worker/worker.mjs");What runs in the worker:
- FlatBuffers deserialization
- Raycast intersection tests
- Property data extraction (getData)
- Position and bounding box calculations
- GUID-to-ID mapping
What stays on the main thread:
- THREE.InstancedMesh creation and scene graph management
- Highlight/resetHighlight (GPU material swaps)
- Coordinate alignment (matrix multiplication)
Coordinate Alignment
When loading multiple models, each may have a different world origin stored in its coordination matrix.
// Set the first loaded model as the base
fragments.baseCoordinationModel = firstModel.modelId;
fragments.baseCoordinationMatrix = firstModel.coordinationMatrix;
// Align subsequent models
fragments.applyBaseCoordinateSystem(secondModel, secondModel.coordinationMatrix);NEVER skip this step for multi-model federation. Models will appear at wrong positions without alignment.
Data Operations
getData: Extract IFC Properties
const items: ModelIdMap = { [model.modelId]: new Set([42, 43, 44]) };
const data = await fragments.getData(items);
// Returns: Record<string, ItemData[]>
// Keys are model IDs, values are arrays of property data per elementgetPositions: Get 3D Coordinates
const positions = await fragments.getPositions(items);
// Returns: THREE.Vector3[] — center positions of targeted elementsgetBBoxes: Get Bounding Boxes
const boxes = await fragments.getBBoxes(items);
// Returns: THREE.Box3[] — axis-aligned bounding boxesGUID Mapping
Convert between IFC GlobalId (GUID) strings and ModelIdMap:
// GUIDs → ModelIdMap (for targeting elements by GUID)
const items = await fragments.guidsToModelIdMap(["2O2Fr$t4X7Zf8NOew3FLOH"]);
// ModelIdMap → GUIDs (for exporting selections)
const guids = await fragments.modelIdMapToGuids(items);Highlight and Raycast
Raycasting
const result = await fragments.raycast({
camera: world.camera.three,
mouse: new THREE.Vector2(normalizedX, normalizedY),
dom: renderer.three.domElement,
snappingClasses: [IFCWALL, IFCSLAB] // optional: restrict hit targets
});
if (result) {
console.log(result.modelId, result.localId, result.point);
}Highlighting
// Define a highlight style (material definition)
const style: MaterialDefinition = {
color: new THREE.Color("#BCF124"),
opacity: 0.6
};
// Highlight specific items
await fragments.highlight(style, items);
// Reset to original appearance
await fragments.resetHighlight(items);IFC-to-Fragment Pipeline
The recommended workflow for production:
1. First time: Convert IFC via IfcLoader, export binary 2. Subsequent loads: Load the binary directly (10-100x faster)
// Step 1: Convert IFC to FragmentsModel
const ifcLoader = components.get(OBC.IfcLoader);
await ifcLoader.setup();
const model = await ifcLoader.load(ifcBytes, true, "MyBuilding");
// Step 2: Export as binary for storage
// The FragmentsModel binary can be persisted (IndexedDB, server, etc.)
// Step 3: On next load, skip IFC parsing entirely
// Load the pre-converted fragment binary through FragmentsManagerDependencies
| Package | Purpose |
|---|---|
@thatopen/fragments | Core fragment engine, FlatBuffers format, worker |
flatbuffers | Binary serialization (zero-copy reads) |
pako | Compression/decompression of fragment binaries |
earcut | Polygon triangulation for 2D profiles |
three (>=0.175) | 3D rendering, InstancedMesh, scene graph |
web-ifc (>=0.0.74) | IFC parsing (used by IfcLoader, not fragments directly) |
Quick Reference
| Task | Method |
|---|---|
| Initialize worker | fragments.init(workerURL) |
| Get loaded models | fragments.list |
| Raycast scene | fragments.raycast({camera, mouse, dom}) |
| Get element properties | fragments.getData(items) |
| Get element positions | fragments.getPositions(items) |
| Get bounding boxes | fragments.getBBoxes(items) |
| GUID to items | fragments.guidsToModelIdMap(guids) |
| Items to GUIDs | fragments.modelIdMapToGuids(items) |
| Highlight elements | fragments.highlight(style, items) |
| Reset highlights | fragments.resetHighlight(items) |
| Align coordinates | fragments.applyBaseCoordinateSystem(obj, matrix) |
| Dispose a model | fragments.disposeModel(modelId) |
| Dispose everything | components.dispose() |
Related Skills
thatopen-core-architecture— Component system, world setup, lifecyclethatopen-syntax-ifc-loading— IfcLoader configuration and WASM setupthatopen-syntax-properties— Deep property extraction from IFC datathatopen-impl-viewer— Full viewer setup including fragments initialization
References
- references/methods.md — Complete FragmentsManager API, FragmentsModel, ModelIdMap details
- references/examples.md — Init worker, load model, getData, raycast, coordinate alignment examples
- references/anti-patterns.md — Missing worker init, disposal failures, common mistakes
Fragment System Anti-Patterns
1. Missing Worker Initialization
WRONG — calling fragment operations before init:
const fragments = components.get(OBC.FragmentsManager);
// MISSING: fragments.init(workerURL)
const ifcLoader = components.get(OBC.IfcLoader);
await ifcLoader.setup();
const model = await ifcLoader.load(data, true, "test");
// Result: silent failure, undefined behavior, or crashCORRECT:
const fragments = components.get(OBC.FragmentsManager);
fragments.init("https://unpkg.com/@thatopen/fragments@3.3.6/dist/Worker/worker.mjs");
// NOW safe to use IfcLoader and all fragment operationsRule: ALWAYS call fragments.init(workerURL) immediately after getting the FragmentsManager and BEFORE any model loading or querying.
---
2. Worker Version Mismatch
WRONG — hardcoded worker URL that does not match installed version:
// package.json has @thatopen/fragments@3.3.6
// but worker URL points to a different version:
fragments.init("https://unpkg.com/@thatopen/fragments@3.2.0/dist/Worker/worker.mjs");
// Result: deserialization errors, worker message format mismatchesCORRECT:
// ALWAYS match the worker URL to your installed package version
fragments.init("https://unpkg.com/@thatopen/fragments@3.3.6/dist/Worker/worker.mjs");Rule: ALWAYS verify that the worker URL version matches the @thatopen/fragments version in your package.json or lock file.
---
3. Forgetting to Dispose Models
WRONG — loading models without disposing them:
async function loadModel(file: File) {
const data = new Uint8Array(await file.arrayBuffer());
const model = await ifcLoader.load(data, true, file.name);
// User loads 5 more files... no disposal
// GPU memory grows unbounded, browser tab crashes
}CORRECT:
async function loadModel(file: File) {
const data = new Uint8Array(await file.arrayBuffer());
const model = await ifcLoader.load(data, true, file.name);
return model;
}
function unloadModel(modelId: string) {
fragments.disposeModel(modelId);
}
// On page unload or component teardown:
window.addEventListener("beforeunload", () => {
components.dispose();
});Rule: ALWAYS dispose models when they are no longer needed. ALWAYS call components.dispose() on page/app teardown.
---
4. Skipping Coordinate Alignment in Multi-Model
WRONG — loading multiple models without alignment:
const modelA = await ifcLoader.load(dataA, true, "Arch");
const modelB = await ifcLoader.load(dataB, true, "Struct");
const modelC = await ifcLoader.load(dataC, true, "MEP");
// Models appear at completely different positions in 3D space
// because each IFC file has its own world originCORRECT:
const modelA = await ifcLoader.load(dataA, true, "Arch");
fragments.baseCoordinationModel = modelA.modelId;
fragments.baseCoordinationMatrix = modelA.coordinationMatrix;
const modelB = await ifcLoader.load(dataB, true, "Struct");
fragments.applyBaseCoordinateSystem(modelB, modelB.coordinationMatrix);
const modelC = await ifcLoader.load(dataC, true, "MEP");
fragments.applyBaseCoordinateSystem(modelC, modelC.coordinationMatrix);Rule: NEVER skip coordinate alignment when loading multiple models. ALWAYS set a base coordination model and align all subsequent models to it.
---
5. Using expressID Alone as Identifier
WRONG — assuming expressIDs are globally unique:
// expressID 42 exists in BOTH modelA and modelB
const expressId = 42;
// Which model does this belong to? Ambiguous!CORRECT — use ModelIdMap:
// ALWAYS pair element IDs with their model ID
const items: ModelIdMap = {
[modelA.modelId]: new Set([42]), // expressID 42 in model A
[modelB.modelId]: new Set([42]) // expressID 42 in model B (different element!)
};Rule: NEVER reference elements by expressID alone. ALWAYS use ModelIdMap to pair element IDs with their parent model UUID.
---
6. Reloading IFC Instead of Cached Fragments
WRONG — parsing IFC from scratch every session:
// User opens the app → fetch IFC → parse with web-ifc → convert to fragments
// Every. Single. Time. Slow and wasteful.
const model = await ifcLoader.load(ifcBytes, true, "building");CORRECT — convert once, cache the binary:
// First load: convert IFC to fragments and cache
const model = await ifcLoader.load(ifcBytes, true, "building");
// Store the fragment binary (IndexedDB, server, etc.)
// Subsequent loads: load the cached fragment binary directly
// Skips WASM parsing entirely — 10-100x fasterRule: ALWAYS convert IFC to fragments once and store the result. NEVER re-parse the same IFC file on every page load.
---
7. Not Listening to Disposal Events
WRONG — holding references to disposed models:
const model = await ifcLoader.load(data, true, "test");
const modelRef = model; // Stored reference
// Later: model is disposed elsewhere
fragments.disposeModel(model.modelId);
// Bug: modelRef is now a zombie — GPU resources freed, but reference exists
modelRef.fragments.forEach(f => f.mesh); // undefined behaviorCORRECT — listen to disposal events and clean up references:
const model = await ifcLoader.load(data, true, "test");
let activeModel = model;
fragments.onBeforeDispose.add((disposedModel) => {
if (disposedModel.modelId === activeModel?.modelId) {
activeModel = null; // Clear reference
}
});Rule: ALWAYS listen to onBeforeDispose if you hold references to models outside of FragmentsManager. NEVER use a model reference after disposal.
---
8. Blocking Main Thread with Fragment Operations
WRONG — expecting synchronous results:
// getData, raycast, getPositions are ALL async (worker-based)
const data = fragments.getData(items); // Returns Promise, not data!
console.log(data); // Logs: Promise {<pending>}CORRECT:
const data = await fragments.getData(items);
console.log(data); // Actual dataRule: ALWAYS await fragment operation results. All data queries and raycasting run in the worker thread and return Promises.
---
Summary Table
| Anti-Pattern | Consequence | Rule |
|---|---|---|
Missing init(workerURL) | Silent failures, crashes | ALWAYS init before any operation |
| Worker version mismatch | Deserialization errors | ALWAYS match worker URL to package version |
| No disposal | Memory leaks, tab crashes | ALWAYS dispose unneeded models |
| No coordinate alignment | Models at wrong positions | ALWAYS align multi-model scenarios |
| expressID without model ID | Ambiguous element references | ALWAYS use ModelIdMap |
| Re-parsing IFC every load | Slow startup (WASM overhead) | ALWAYS cache fragment binaries |
| Zombie model references | Undefined behavior | ALWAYS clean refs on dispose |
| Missing await on operations | Promise instead of data | ALWAYS await async fragment methods |
Fragment System Examples
1. Initialize Worker
ALWAYS initialize the worker before any fragment operations.
import * as OBC from "@thatopen/components";
const components = new OBC.Components();
// Get FragmentsManager (lazy singleton)
const fragments = components.get(OBC.FragmentsManager);
// Initialize worker — MUST match installed @thatopen/fragments version
fragments.init(
"https://unpkg.com/@thatopen/fragments@3.3.6/dist/Worker/worker.mjs"
);
// Verify initialization
console.log(fragments.initialized); // trueLocal worker alternative:
// If bundling the worker locally (e.g., copied to public/):
fragments.init("/workers/fragments-worker.mjs");---
2. Load IFC and Convert to Fragments
import * as OBC from "@thatopen/components";
const components = new OBC.Components();
const worlds = components.get(OBC.Worlds);
const world = worlds.create<
OBC.SimpleScene,
OBC.OrthoPerspectiveCamera,
OBC.SimpleRenderer
>();
world.scene = new OBC.SimpleScene(components);
world.scene.setup();
world.renderer = new OBC.SimpleRenderer(components, container);
world.camera = new OBC.OrthoPerspectiveCamera(components);
components.init();
// Initialize fragments worker
const fragments = components.get(OBC.FragmentsManager);
fragments.init(workerURL);
// Setup IFC loader (configures WASM)
const ifcLoader = components.get(OBC.IfcLoader);
await ifcLoader.setup();
// Load IFC file
const response = await fetch("/models/building.ifc");
const data = new Uint8Array(await response.arrayBuffer());
const model = await ifcLoader.load(data, true, "MyBuilding");
// model is now a FragmentsModel added to the scene
console.log("Model ID:", model.modelId);
console.log("Loaded models:", fragments.list.size);---
3. getData — Extract Element Properties
const fragments = components.get(OBC.FragmentsManager);
// Target specific elements
const items = {
[model.modelId]: new Set([42, 43, 44])
};
// Extract IFC property data (runs in worker)
const data = await fragments.getData(items);
// Process results
for (const [modelId, itemDataArray] of Object.entries(data)) {
for (const itemData of itemDataArray) {
console.log("Element:", itemData);
}
}---
4. Raycast — Pick Elements in 3D
const fragments = components.get(OBC.FragmentsManager);
// Normalized mouse coordinates from a click event
function onPointerClick(event: PointerEvent) {
const rect = renderer.three.domElement.getBoundingClientRect();
const mouse = new THREE.Vector2(
((event.clientX - rect.left) / rect.width) * 2 - 1,
-((event.clientY - rect.top) / rect.height) * 2 + 1
);
fragments.raycast({
camera: world.camera.three,
mouse,
dom: renderer.three.domElement
}).then((result) => {
if (result) {
console.log("Hit model:", result.modelId);
console.log("Hit element:", result.localId);
console.log("Hit point:", result.point);
// Highlight the hit element
const hitItems = {
[result.modelId]: new Set([result.localId])
};
fragments.highlight(
{ color: new THREE.Color("#ff0000"), opacity: 0.8 },
hitItems
);
}
});
}With snapping classes (restrict to specific IFC types):
import { IFCWALL, IFCSLAB, IFCCOLUMN } from "web-ifc";
const result = await fragments.raycast({
camera: world.camera.three,
mouse,
dom: renderer.three.domElement,
snappingClasses: [IFCWALL, IFCSLAB, IFCCOLUMN]
});---
5. Coordinate Alignment for Multi-Model Federation
const fragments = components.get(OBC.FragmentsManager);
// Load first model — becomes the base
const modelA = await ifcLoader.load(ifcBytesA, true, "Building-A");
fragments.baseCoordinationModel = modelA.modelId;
fragments.baseCoordinationMatrix = modelA.coordinationMatrix;
// Load second model — align to base
const modelB = await ifcLoader.load(ifcBytesB, true, "Building-B");
fragments.applyBaseCoordinateSystem(modelB, modelB.coordinationMatrix);
// Load third model — also align to base
const modelC = await ifcLoader.load(ifcBytesC, true, "MEP-Model");
fragments.applyBaseCoordinateSystem(modelC, modelC.coordinationMatrix);
// All three models now share the same coordinate origin---
6. GUID Mapping
const fragments = components.get(OBC.FragmentsManager);
// Convert IFC GlobalIds to ModelIdMap for targeting
const guids = ["2O2Fr$t4X7Zf8NOew3FLOH", "3MVF2h$Kv7gPC5cv0IKXCA"];
const items = await fragments.guidsToModelIdMap(guids);
// Use the items map for any operation
await fragments.highlight(
{ color: new THREE.Color("#00ff00"), opacity: 0.5 },
items
);
// Convert back to GUIDs (e.g., for BCF export)
const exportedGuids = await fragments.modelIdMapToGuids(items);
console.log(exportedGuids); // ["2O2Fr$t4X7Zf8NOew3FLOH", "3MVF2h$Kv7gPC5cv0IKXCA"]---
7. Get Positions and Bounding Boxes
const fragments = components.get(OBC.FragmentsManager);
const items = { [model.modelId]: new Set([42, 43]) };
// Get center positions
const positions = await fragments.getPositions(items);
positions.forEach((pos, i) => {
console.log(`Element ${i}: x=${pos.x}, y=${pos.y}, z=${pos.z}`);
});
// Get bounding boxes
const boxes = await fragments.getBBoxes(items);
boxes.forEach((box, i) => {
console.log(`Element ${i}: min=${box.min.toArray()}, max=${box.max.toArray()}`);
});---
8. Highlight and Reset
const fragments = components.get(OBC.FragmentsManager);
// Define styles
const selectionStyle = { color: new THREE.Color("#BCF124"), opacity: 0.6 };
const errorStyle = { color: new THREE.Color("#ff0000"), opacity: 0.8 };
// Highlight a selection
const selectedItems = { [model.modelId]: new Set([10, 20, 30]) };
await fragments.highlight(selectionStyle, selectedItems);
// Highlight errors differently
const errorItems = { [model.modelId]: new Set([99]) };
await fragments.highlight(errorStyle, errorItems);
// Reset only the selection (errors stay highlighted)
await fragments.resetHighlight(selectedItems);
// Reset all highlights
await fragments.resetHighlight();---
9. Listen to Fragment Events
const fragments = components.get(OBC.FragmentsManager);
// React to model loading
fragments.onFragmentsLoaded.add((model) => {
console.log("Model loaded:", model.modelId);
console.log("Fragments count:", model.fragments.length);
});
// React before disposal (e.g., save state)
fragments.onBeforeDispose.add((model) => {
console.log("About to dispose:", model.modelId);
});
// React after full disposal
fragments.onDisposed.add(() => {
console.log("FragmentsManager fully disposed");
});---
10. Dispose a Single Model
const fragments = components.get(OBC.FragmentsManager);
// Dispose one model (frees GPU memory, removes from scene)
fragments.disposeModel(model.modelId);
// Verify removal
console.log(fragments.list.has(model.modelId)); // false
// Dispose everything when leaving the page
components.dispose();FragmentsManager API Reference
FragmentsManager
The central component for managing fragment models. Extends Component, implements Disposable.
Properties
| Property | Type | Description |
|---|---|---|
list | Map<string, FragmentsModel> | All loaded fragment models, keyed by model UUID |
initialized | boolean | Whether init() has been called |
baseCoordinationModel | string | UUID of the model used as coordination origin |
baseCoordinationMatrix | THREE.Matrix4 | The 4x4 matrix of the base coordination model |
Methods
init(workerURL: string, options?): void
Initializes the web worker for offloaded operations. MUST be called before any other FragmentsManager method.
workerURL— URL to theworker.mjsfile from@thatopen/fragments- ALWAYS use a URL matching your installed
@thatopen/fragmentsversion
raycast(config): Promise<Result | undefined>
Performs a raycast against all loaded fragment models.
config: {
camera: THREE.Camera, // The active camera
mouse: THREE.Vector2, // Normalized device coordinates (-1 to +1)
dom: HTMLElement, // The renderer's DOM element
snappingClasses?: number[] // Optional: restrict to IFC classes
}Returns a Result object with modelId, localId, point, normal, distance, or undefined if nothing was hit.
highlight(style: MaterialDefinition, items?: ModelIdMap): Promise<void>
Applies a highlight material to targeted items. If items is omitted, highlights all loaded elements.
type MaterialDefinition = {
color: THREE.Color;
opacity: number;
};resetHighlight(items?: ModelIdMap): Promise<void>
Resets highlighted items to their original materials. If items is omitted, resets all highlights.
getData(items: ModelIdMap, config?): Promise<Record<string, ItemData[]>>
Extracts IFC property data for the specified items. Runs in the worker thread.
Returns a record keyed by model ID, with arrays of ItemData objects containing IFC property sets, type information, and relationships.
getPositions(items: ModelIdMap): Promise<THREE.Vector3[]>
Returns the center positions of the specified items as an array of THREE.Vector3 objects.
getBBoxes(items: ModelIdMap): Promise<THREE.Box3[]>
Returns axis-aligned bounding boxes for the specified items.
guidsToModelIdMap(guids: Iterable<string>): Promise<ModelIdMap>
Converts IFC GlobalId (GUID) strings to a ModelIdMap. Searches across all loaded models. GUIDs not found in any model are silently skipped.
modelIdMapToGuids(modelIdMap: ModelIdMap): Promise<string[]>
Converts a ModelIdMap back to an array of IFC GlobalId strings. Useful for exporting selections to BCF or external systems.
applyBaseCoordinateSystem(object: THREE.Object3D, originalMatrix?: THREE.Matrix4): THREE.Matrix4
Transforms a Three.js object so it aligns with the base coordination model.
object— The Three.js object to transform (typically a FragmentsModel's root)originalMatrix— The object's original coordination matrix- Returns the applied transformation matrix
disposeModel(modelId: string): void
Disposes a single model by UUID. Removes it from list, disposes GPU resources (geometry, materials, textures), and cleans up worker state. Triggers onBeforeDispose before cleanup.
Events
| Event | Type | When |
|---|---|---|
onFragmentsLoaded | Event<FragmentsModel> | After a model finishes loading |
onBeforeDispose | Event<FragmentsModel> | Before a model is disposed |
onDisposed | Event<void> | After FragmentsManager itself is disposed |
---
FragmentsModel
Represents a single loaded BIM model in the fragment system.
Key Properties
| Property | Type | Description |
|---|---|---|
modelId | string | Unique identifier (UUID) |
coordinationMatrix | THREE.Matrix4 | Original world positioning matrix |
fragments | Fragment[] | Array of instanced mesh fragments |
boundingBox | THREE.Box3 | Overall bounding box of the model |
A FragmentsModel is a Three.js Object3D that can be added to scenes directly. Its children are the individual Fragment instanced meshes.
---
ModelIdMap
type ModelIdMap = Record<string, Set<number>>;The universal item-targeting data structure in ThatOpen.
- Keys: Model UUID strings (matching
FragmentsModel.modelId) - Values:
Set<number>of local element IDs within that model
Usage Patterns
// Target specific elements in one model
const items: ModelIdMap = {
[model.modelId]: new Set([42, 43, 44])
};
// Target elements across multiple models
const multiItems: ModelIdMap = {
[modelA.modelId]: new Set([1, 2, 3]),
[modelB.modelId]: new Set([10, 20])
};
// Empty map (no items)
const empty: ModelIdMap = {};Where ModelIdMap is Used
| Component | Methods |
|---|---|
| FragmentsManager | getData(), getPositions(), getBBoxes(), highlight(), resetHighlight(), guidsToModelIdMap(), modelIdMapToGuids() |
| Hider | set(), isolate(), toggle() |
| Classifier | find() returns ModelIdMap |
| BoundingBoxer | addFromModelIdMap(), getCenter() |
| Highlighter | highlightByID(), clear(), selection property |
---
MaterialDefinition
type MaterialDefinition = {
color: THREE.Color;
opacity: number;
};Used by highlight() and Highlighter for defining visual styles applied to selected/highlighted elements. The opacity controls transparency (0 = fully transparent, 1 = fully opaque).
---
Worker Communication
The FragmentsManager worker handles:
| Operation | Main Thread Call | Worker Processing |
|---|---|---|
| Raycast | raycast(config) | Intersection tests against fragment BVH |
| Data extraction | getData(items) | FlatBuffers property deserialization |
| Position query | getPositions(items) | Geometry center calculation |
| Bounding boxes | getBBoxes(items) | AABB computation from geometry |
| GUID mapping | guidsToModelIdMap() | Lookup in model's GUID index |
| GUID export | modelIdMapToGuids() | Reverse lookup from local IDs |
All worker operations return Promises. The worker uses postMessage with transferable buffers for zero-copy data transfer where possible.