npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

babylon-ifc-loader

v2.2.1

Published

Babylon.js Loader for IFC files using web-ifc

Readme

Babylon.js IFC Loader

IFC Loader built with Babylon.js and web-ifc. Features automatic loading of sample IFC files, drag-and-drop support, intelligent mesh merging, element picking with metadata display, and automatic camera framing.

While providing the minimal viewer experience, this repo is dedicated to developing and testing the IFC Babylon.js Loader. The viewer is provided for testing and demonstration purposes only. Full-featured Babylon.js IFC Babylon.js Viewer will be available in a separate repo later.

Installation

npm install babylon-ifc-loader

Upgrade Guide (NPM users)

Use these steps to upgrade safely to the latest published package version.

  1. Check your currently installed version.
npm ls babylon-ifc-loader
  1. Upgrade to latest.
npm install babylon-ifc-loader@latest
  1. Verify the installed version.
npm ls babylon-ifc-loader
  1. If you use a lockfile in CI (package-lock.json), commit the lockfile changes after upgrade.

  2. If you previously used npm link for local testing, unlink and reinstall from registry:

npm unlink babylon-ifc-loader
npm install babylon-ifc-loader@latest

Minimal migration checklist

  1. Prefer unified loader API:
import { createIfcLoader } from "babylon-ifc-loader";

const loader = createIfcLoader({ useWorker: true });
await loader.init("/");
  1. Prefer prepared loading for performance:
const prepared = await loader.loadPreparedIfcModel("/model.ifc");
  1. Build scene from prepared model:
const result = buildIfcModel(prepared, scene, { usePBRMaterials: true });
  1. Use merged-picking-safe resolve helper when needed:
const expressID = resolveExpressIDFromMeshPick(pickedMesh, pickResult.faceId);
  1. Review version notes in CHANGELOG.md for behavior changes before deploy.

Quick Start

# Install dependencies
npm install

# Start development server
npm run dev

# Build for production
npm run build

# Preview production build
npm run preview

# Run tests
npm test

# Run tests with coverage
npm run test:coverage

Dev Server URL

After running npm run dev, open:

| URL | Entry Point | Description | | ----------------------------------------- | ---------------------- | ------------------------------------------------ | | http://localhost:5173/ | src/main.ts | App viewer using worker-prepared geometry flow | | http://localhost:5173/test-npm/index.html | test-npm/main.ts | NPM package integration test page | | http://localhost:5173/test-speed/index.html | test-speed/main.ts | Benchmark (main-thread vs worker, all merge modes) |

Features

  • Automatic Loading: Sample IFC file loads on startup
  • Drag & Drop: Drop .ifc files onto the canvas to load them
  • Element Picking: Click on elements to view metadata and highlight them
  • Intelligent Merging: Automatically merges meshes with same material while preserving metadata
  • Structured Logging: Typed logging helpers with optional IFC context (modelID, expressID, geometryExpressID)
  • Camera Framing: Automatically positions camera to view the entire model
  • Inspector (Dev only): Babylon.js Inspector is loaded dynamically only in dev mode
  • Keyboard Shortcuts: Ctrl+I (or Cmd+I on Mac) toggles the inspector, works across all keyboard layouts
  • Memory Management: Proper cleanup when loading new files

Architecture

The codebase follows a strict layered architecture with clear separation of concerns:

IFC Data Layer (src/ifcInit.ts)

All web-ifc interaction. Zero Babylon.js dependencies.

  • initializeWebIFC(wasmPath?, logLevel?) - initialize web-ifc API
  • loadIfcModel(ifcAPI, source, options?) - load and extract raw geometry data
  • closeIfcModel(ifcAPI, modelID) - free IFC model memory
  • getProjectInfo(ifcAPI, modelID) - extract project metadata

Rendering Layer (src/ifcModel.ts)

All Babylon.js scene construction. Zero web-ifc dependencies.

  • buildIfcModel(model, scene, options?) - create meshes, materials, merge, center
  • disposeIfcModel(scene) - dispose all IFC meshes and materials
  • getModelBounds(meshes) - calculate bounding box
  • centerModelAtOrigin(meshes, rootNode?) - center model at origin

Application Layer

  • src/main.ts - uses worker + prepared geometry (loadPreparedIfcModel) and Babylon build step

Shared Utilities (src/logging.ts)

Structured logging helpers used across IFC loading and rendering:

  • logInfo(message, context?)
  • logWarn(message, context?, detail?)
  • logError(message, context?, detail?)

Usage

Two-Step Loading API

For more control, use the two-step API directly:

// Step 1: Initialize web-ifc
const ifcAPI = await initializeWebIFC("./");

// Step 2: Load raw IFC data (web-ifc only)
const model = await loadIfcModel(ifcAPI, "/test.ifc", {
  coordinateToOrigin: true,
  verbose: true,
});

// Step 3: Extract metadata (optional)
const projectInfo = getProjectInfo(ifcAPI, model.modelID);

// Step 4: Build Babylon.js scene (Babylon only)
const { meshes, rootNode, stats } = buildIfcModel(model, scene, {
  autoCenter: true,
  mergeMeshes: true,
  doubleSided: true,
  verbose: true,
});

Single Loader API (choose worker or main-thread)

import { createIfcLoader } from "babylon-ifc-loader";

const ifc = createIfcLoader({ useWorker: true }); // false = main-thread
await ifc.init("/"); // Optional second arg: WebIFC.LogLevel

const model = await ifc.loadIfcModel("/test.ifc", {
  coordinateToOrigin: true,
  verbose: true,
});

Prepared Geometry API (recommended)

Use this path to do IFC parse + geometry preparation off-thread (when useWorker: true), then build Babylon meshes on main thread:

const ifc = createIfcLoader({ useWorker: true });
await ifc.init("/");

const prepared = await ifc.loadPreparedIfcModel(
  "/test.ifc",
  {
    coordinateToOrigin: true,
    keepModelOpen: false,
  },
  {
    autoMergeStrategy: {
      lowMaxParts: 1500,
      mediumMaxParts: 5000,
      lowMode: "by-express-color",
      mediumMode: "by-color",
      highMode: "two-material",
    },
  },
);

const result = buildIfcModel(prepared, scene, { usePBRMaterials: true });

renderOnly: true is available for visualization-only flows and forces:

  • mergeMode: "two-material"
  • keepModelOpen: false
  • includeElementMap: false

Load from URL or File

// From URL
const model = await loadIfcModel(ifcAPI, "/path/to/file.ifc");

// From File object (drag-and-drop)
const model = await loadIfcModel(ifcAPI, fileObject);

Cleanup before loading a new model

// Dispose Babylon.js scene (meshes, materials, root node)
disposeIfcModel(scene);

// Close IFC model and free WASM memory
closeIfcModel(ifcAPI, modelID);

API Reference

See API.md for complete API documentation with all types, parameters, and examples.

NPM Package

The package is published as babylon-ifc-loader and exports:

// Low-level IFC Data Layer (web-ifc only)
import { initializeWebIFC, loadIfcModel, closeIfcModel, getProjectInfo } from "babylon-ifc-loader";

// Rendering Layer (Babylon.js only)
import { buildIfcModel, disposeIfcModel, getModelBounds, centerModelAtOrigin } from "babylon-ifc-loader";

Testing NPM Package Locally

To test the npm package locally before publishing:

# 1. Build the npm package
npm run build:npm

# 2. Run Vite dev server with the test-npm entry point
npx vite . --open test-npm/index.html

The test-npm/ folder contains a test page that imports from babylon-ifc-loader. Since the package's main entry points to dist-npm/index.js, Vite resolves the import from the built output.

Benchmarking Merge Modes and Worker/Main-Thread

Open test-speed/index.html to benchmark:

  • Backends: main-thread and worker
  • Merge modes: by-express-color, by-color, two-material
  • Metrics: load ms, build ms, total ms, mesh/material count, memory estimate, transfer/map bytes, opaque/transparent counts

Testing from another project:

To test the package in a different project:

# In ifc-babylon root
npm link

# In the other project
npm link babylon-ifc-loader

Testing

The project uses Vitest for unit testing with the following setup:

  • Test Runner: Vitest v4 with jsdom environment
  • Coverage: @vitest/coverage-v8 for code coverage reports
  • Location: Test files are in src/__tests__/

Test Files

| File | Description | | -------------------------- | ------------------------------------- | | initializeWebIFC.test.ts | Tests for web-ifc initialization | | loadIfcModel.test.ts | Tests for IFC model loading | | ifcLoader.test.ts | Tests for unified loader and renderOnly flow | | ifcModelPreparation.test.ts | Tests for merge tiers/profiles and telemetry | | closeIfcModel.test.ts | Tests for model cleanup | | getProjectInfo.test.ts | Tests for project metadata extraction | | buildIfcModel.test.ts | Tests for Babylon.js scene building | | zOffset.test.ts | Tests for z-offset material handling | | buildIfcModel.perf.test.ts | Perf regression tests for synthetic large models | | logging.test.ts | Unit tests for structured logging helpers |

Running Tests

# Run tests in watch mode
npm test

# Run tests once
npm test -- --run

# Run tests with coverage report
npm run test:coverage

Writing Tests

Tests follow the standard Vitest pattern with mocked dependencies:

import { describe, it, expect, beforeEach, vi } from "vitest";

describe("myFunction", () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  it("should do something", async () => {
    const result = await myFunction();
    expect(result).toBe(expected);
  });
});

Project Structure

src/
|-- main.ts          - app entry (worker-prepared load + Babylon build)
|-- ifcInit.ts       - IFC data layer (web-ifc only)
|-- ifcLoader.ts     - unified loader facade (worker or main-thread)
|-- ifcWorkerClient.ts - worker client transport
|-- ifc.worker.ts    - worker runtime for web-ifc + preparation
|-- ifcModelPreparation.ts - merge strategies and telemetry
|-- ifcModel.ts      - rendering layer (Babylon.js only)
|-- style.css        - basic styling
`-- __tests__/       - unit tests

public/
|-- test.ifc         - sample IFC file loaded at startup
|-- example.ifc      - additional sample
`-- bplogo.svg       - asset

Root
|-- index.html       - HTML entry
|-- vite.config.ts   - copies web-ifc.wasm to dist/, sets WASM handling
|-- tsconfig.json    - TypeScript config
`-- package.json     - scripts and deps

Picking and Highlighting

  • Left-click a mesh to log full element data via ifcAPI.GetLine(modelID, expressID, true) and type name via GetNameFromTypeCode
  • Highlight uses renderOverlay with teal color and alpha=0.3
  • Upper text banner shows type, name, and ExpressID; clicking empty space clears it

Materials, Merging, and Performance

  • Materials are StandardMaterial per unique RGBA color, configurable backFaceCulling, incremental zOffset to mitigate z-fighting
  • Prepared geometry supports merge modes: by-express-color, by-color, two-material, and none
  • Optional auto-merge tiers via autoMergeStrategy (low, medium, high)
  • Metadata (expressID, modelID) preserved on merged meshes
  • For merged prepared meshes, elementRanges can preserve per-face expressID mapping for picking
  • Material metadata includes source color as material.metadata.color with { r, g, b, a } (or null)
  • Telemetry includes tier, opaque/transparent counts, map bytes, geometry bytes, and transfer bytes

Custom Merging Strategy

When mergeMeshes = false, each geometry part remains as a separate mesh with full metadata. This lets you implement your own merging strategy based on:

  • Mesh metadata (expressID, modelID) for element identification
  • IFC queries via ifcAPI.GetLine() for property-based grouping
  • Spatial relationships for storey/zone-based organization
  • Material or color-based batching

Example:

const { meshes } = buildIfcModel(model, scene, { mergeMeshes: false });

// Custom grouping by IFC type
for (const mesh of meshes) {
  const element = ifcAPI.GetLine(modelID, mesh.metadata.expressID, true);
  const typeName = ifcAPI.GetNameFromTypeCode(element.type);
  // Group or merge meshes by typeName, storey, etc.
}

Coordinate System and Geometry

  • web-ifc streams interleaved vertex data [x,y,z,nx,ny,nz]
  • Optional normal generation when required
  • Per-part transforms baked from placed geometry matrices
  • Z-axis flip applied via root node scaling for IFC-to-Babylon coordinate conversion

Build and Deploy Notes

  • The Vite config copies node_modules/web-ifc/web-ifc.wasm to dist/
  • In production, initializeWebIFC("./") ensures the WASM is loaded from the dist root
  • optimizeDeps.exclude = ["web-ifc"] prevents esbuild issues during dev

Dependencies

| Package | Version | Description | | ----------------------- | ------- | ----------------------------------- | | @babylonjs/core | ^8.52.0 | Core Babylon.js engine | | @babylonjs/inspector | ^8.52.0 | Built-in debugging inspector | | web-ifc | ^0.0.75 | IFC parsing and geometry extraction | | vite | ^7.3.1 | Build tool and dev server | | vite-plugin-static-copy | ^3.2.0 | Copy WASM files to dist |

Limitations and Future Improvements

  • No spatial tree or filters yet
  • No property panel UI
  • No outline/edge rendering highlight option
  • No UI controls for scene manipulation

License

Apache-2.0 - See LICENSE for details.

Changelog

See CHANGELOG.md for release notes and recent changes.