Building with IfcViewer¶
IfcViewer is a library, not an end-user application. It provides the WebGPU rendering engine and the model loading, sidecar, streaming, selection, visibility, and viewport-state machinery that Bonsai Viewer is built on, and it is meant to be embedded in your own applications. This page is for developers who want to build their own viewer on top of it.
There are two ways to consume it, from two separate CMake roots:
a native desktop library (
IfcViewer/IfcViewerCore) that you link into a C++ application, anda web build that compiles the same portable core to WebAssembly and exposes it to JavaScript, so you can drop the viewer into a web page.
If you instead want to compile the ready-made Bonsai Viewer desktop
application, see the Bonsai Viewer developer documentation (under
src/bonsaiviewer/docs) rather than this page.
Compiling for desktop¶
The desktop side ships as two static libraries, built from
src/ifcviewer/CMakeLists.txt:
IfcViewerCoreThe portable runtime subset — Qt-free and OpenCASCADE-free. It contains the buffer-pool allocator, sidecar cache/layout, streaming loader, instance composition, selection, visibility, and viewport camera state. This is the same library the web build uses.
IfcViewerIfcViewerCoreplus the desktop-only, Qt-coupled layer — the WebGPU surface creation, theViewportWindowwidget, and platform input handling. Link this if you are writing a Qt desktop frontend.
Prerequisites are a C++17 compiler, CMake 3.21 or newer, Ninja, and — for the
full IfcViewer target — Qt6 with OpenGL 4.5 support. IfcViewerCore
additionally uses zstd (and, where enabled, Manifold/RocksDB for the sidecar
formats); these come along when you build IfcOpenShell.
Because the viewer targets live inside the IfcOpenShell source tree, the simplest way to build against them from your own project is to add the directory as a subproject and link the target you need:
# In your own CMakeLists.txt
add_subdirectory(path/to/IfcOpenShell/src/ifcviewer ifcviewer)
add_executable(my_viewer main.cpp)
target_link_libraries(my_viewer PRIVATE IfcViewer) # or IfcViewerCore
The targets carry their public include directory as a usage requirement, so
#include paths resolve automatically once you link them.
Two reference frontends in the tree show the intended integration and are the best starting points to copy from:
IfcViewerMinimal— a small standalone desktop frontend built onIfcViewer.src/ifcviewer-web/main_web.cpp— the web scaffold built onIfcViewerCore(see the next section).
Compiling for the web¶
The web build compiles IfcViewerCore to WebAssembly with the Emscripten
SDK and renders
through WebGPU via Emscripten’s emdawnwebgpu (Dawn) port. It uses neither
Qt nor OpenCASCADE. You will need a recent Emscripten SDK to build, and a
WebGPU-capable browser (current Chrome or Edge, or Firefox Nightly) to run the
result.
Building the module¶
Activate your Emscripten environment, then configure and build the separate web CMake root from the repository root:
source /path/to/emsdk_env.sh
emcmake cmake -S src/ifcviewer-web -B build-web -G Ninja
ninja -C build-web
The build must be configured through emcmake; the CMake root fails fast
with a clear error if invoked with a non-Emscripten toolchain.
It emits a MODULARIZE module — IfcViewerWeb.js (which defines the
global createIfcViewer factory) and IfcViewerWeb.wasm — and copies a
small integration helper (ifcviewer.js) and two example pages next to
them. Everything in build-web/ is static; serve it over http://localhost
or https:// (WebGPU requires a secure context):
python3 -m http.server --directory build-web 8080
# then open http://localhost:8080/
Embedding in your own page¶
ifcviewer.js is a thin wrapper over the raw Emscripten module that exposes
a small IfcViewer JavaScript API. Load IfcViewerWeb.js first, then
ifcviewer.js, and give your canvas id="viewer-canvas" (the wasm side
hard-codes that selector for its WebGPU surface and input handlers):
<canvas id="viewer-canvas" width="960" height="600"></canvas>
<script src="IfcViewerWeb.js"></script>
<script src="ifcviewer.js"></script>
<script>
const canvas = document.getElementById('viewer-canvas');
const viewer = await IfcViewer.create({ canvas });
await viewer.ready; // GPU app is live
// React to picks in the scene.
viewer.onSelect(({ objectId, guid, modelIndex }) => {
console.log('selected', guid, 'in model', modelIndex);
});
// Load a first model (drops any current scene), then federate another.
await viewer.addUrl('/model.ifcview', { replace: true });
await viewer.addUrl('/second.ifcview'); // appends
</script>
The API object returned by IfcViewer.create includes:
ready— a promise that resolves once the GPU app is initialised.onSelect(cb)— register a pick listener({ objectId, guid, modelIndex }); returns an unsubscribe function. Aifcviewer:selectDOM event is also dispatched.addFile(file, { replace })/addUrl(url, { replace })— add a model from a pickedFile(read lazily viaBlob.slice) or a remote.ifcviewURL (read lazily via HTTP range requests). Withoutreplace: truethe model is appended, giving a lightweight federation.clearScene(),viewAll(),frameSelection()— scene and camera controls.modelCount(),modelProgress(i),bytes()— streaming/loading progress for building your own UI.
The bundled embedded.html is a complete, commented reference: it embeds
the viewer as a sized page element and uses plain DOM around it to add models
(by file or URL), list the loaded models with streaming progress, and display
the GlobalId of the clicked object. IfcViewerWeb.html is a fullscreen
variant. Both are good templates to start from.
For the headless-browser smoke tests that exercise this build, see Running tests.