IFC viewer using @ifc-lite/geometry + @ifc-lite/parser with Three.js — no WebGPU required.
Features: progressive streaming, vertex-color batching (1 draw call for opaque geometry), object picking, and a full IFC properties panel (attributes + property sets + quantities).
The @ifc-lite/geometry package outputs engine-agnostic mesh data:
interface MeshData {
expressId: number;
positions: Float32Array; // [x,y,z, ...]
normals: Float32Array; // [nx,ny,nz, ...]
indices: Uint32Array; // triangle indices
color: [r, g, b, a]; // RGBA 0-1
}The ifc-to-threejs.ts bridge converts these into Three.js BufferGeometry + MeshStandardMaterial.
The ifc-data.ts module uses @ifc-lite/parser to scan the same buffer and build a columnar index for entity attributes and property set lookups.
npm install
npm run devOpen http://localhost:5173 and drop an IFC file. Click any element to see its IFC data in the side panel.
| File | Purpose |
|---|---|
src/main.ts |
Three.js scene setup, streaming loader, picking, panel wiring |
src/ifc-to-threejs.ts |
MeshData → Three.js conversion + triangle-map for picking |
src/ifc-data.ts |
@ifc-lite/parser wrapper — data store + entity attribute/pset queries |
import { meshDataToThree } from './ifc-to-threejs';
const threeMesh = meshDataToThree(meshData);
scene.add(threeMesh);import { geometryResultToBatched } from './ifc-to-threejs';
const { group, expressIdMap } = geometryResultToBatched(geometryResult);
scene.add(group);import { batchWithVertexColors, findEntityByFace } from './ifc-to-threejs';
const { group, triangleMaps } = batchWithVertexColors(allMeshes);
scene.add(group);
// On click:
const hits = raycaster.intersectObjects([...triangleMaps.keys()], false);
if (hits[0]) {
const ranges = triangleMaps.get(hits[0].object as THREE.Mesh);
const expressId = findEntityByFace(ranges!, hits[0].faceIndex!);
}import { buildDataStore, getEntityData } from './ifc-data';
const store = await buildDataStore(rawBuffer);
const data = getEntityData(store, expressId, 'IfcWall');
// data.name, data.globalId, data.propertySets, data.quantitySets …getEntityData returns: globalId, name, description, objectType, tag, propertySets (from IfcPropertySet), and quantitySets (from IfcElementQuantity).
import { buildDataStore, buildSpatialTreeFromStore } from './ifc-data';
const store = await buildDataStore(rawBuffer);
const tree = buildSpatialTreeFromStore(store);
// tree: Project → Site → Building → Storey → Elements (grouped by IFC type)
// Each node: { children, elementGroups, elevation, totalElements }Use store.spatialHierarchy.elementToStorey.get(expressId) for reverse lookup (element → storey), enabling two-way sync between the 3D view and spatial tree.
MPL-2.0