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

brepjs-bim

v0.26.0

Published

BIM layer for brepjs — IFC4-aligned parametric building elements

Readme

brepjs-bim

Experimental satellite package, published to npm. Early-stage — the API may change.

npm install brepjs-bim

A BIM (Building Information Modeling) layer for brepjs. It authors IFC4-aligned parametric building elements and a focused IFC4X3 civil bridge profile, assembles them into a spatial structure, and serializes the result to a valid IFC-SPF file — with a matching importer to read IFC back in.

Pipeline: author spec → BimModel (typed element + brepjs geometry) → spatial structure + property sets + classification → export IFC / COBie, validate, round-trip.

The declarative entry point is brepjs-families: author the building as a tree of prop-driven components, then familiesToBim(tree, { project }) projects it onto a BimModel with stable GlobalIds derived from component key paths. Hand-authoring specs against BimModel remains the low-level path (and covers elements the declarative route doesn't yet). See the Declarative Models guide.

Scope

Parametric authoring of the common IFC4 building elements plus the data layers that make a model useful downstream (psets, classification, materials, quantities), with import, export, and validation. Geometry is produced by brepjs (OCCT). Walls and railings carry a ProductBody: PARAMETRIC or AUTHORITATIVE, both with a nonempty, ordered solids collection. Authority and item count are independent. bodySolids() borrows Product-local model handles; do not dispose those handles. Other solid-bearing categories retain their current geometry types.

model.replaceProductBody({ localId, body: { kind: 'AUTHORITATIVE', solids } }) validates and installs the complete collection atomically. Err leaves the model and caller ownership unchanged. Ok returns a COMMITTED receipt and transfers every supplied handle, even when receipt.cleanup.kind === 'FAILED' reports a failed release of the superseded Body. Do not retry an uncertain release or dispose transferred handles. Parametric Bodies may be replaced by either authority; authoritative Bodies may only be replaced by authoritative Bodies. Add wall openings before installing an authoritative Body: later addDoor() and addWindow() return AUTHORITATIVE_WALL_BODY_IMMUTABLE.

Civil-semantic Families Wall/Railing routes require an evaluator and retain the authored Body as AUTHORITATIVE, including when it coincides with the nominal recipe. The adapter copies borrowed evaluator items, localizes every item, and respects the replacement receipt's ownership outcome. Conventional archetype routes retain their existing recipe authoring behavior.

Element geometry is unplaced template geometry in local coordinates. Placement (origin / axisX / axisZ) is applied by the IFC layer via IfcLocalPlacement, not baked into the brepjs solid. Use placedSolids(element) to read fresh, caller-owned solids transformed by the element's own placement. Stairs and ramps return one solid per flight, curtain walls return their panels and mullions, and either Product Body authority returns one placed copy per Body item. When an element is beneath a placed spatial structure, pass its cumulative frame as placedSolids(element, { parentFrame }) to obtain world coordinates. This is especially important for parent-local Proxy and Earthworks Fill bodies.

IFC import reconstructs every supported Body item independently. ImportedGeometry.solids owns the resulting World-placed handles and completeness reports COMPLETE, PARTIAL, or NONE. fidelity reports the least faithful retained item. Raw mesh siblings are combined in meshVertices and meshIndices. The legacy .solid property is a borrowed alias only for a complete one-solid Body. Dispose import geometry through disposeImportedModel() rather than through either property. Complete Bodies also expose aggregate bounds and volumeMm3; both are null when aggregate measurement fails or when the Body is partial or missing.

  • Units default to mm; IFC export emits SI metres.
  • Stable identity: deterministic IFC GUIDs (deriveIfcGuid) and local id counters.
  • Shaped geometry: roofs build real shed/gable/hip/dome solids when pitch is set (flat slab otherwise); railings build posts + top/bottom rails with infill: 'POSTED' (a single swept panel otherwise). Every retained Wall/Railing Body item serializes independently as a tessellated representation, with one conversion from mm to metres. Shaped roofs also use tessellation; flat roofs keep their parametric IfcExtrudedAreaSolid.

Wall net volume measures occupied material across all retained items, so overlaps count once. Nominal recipe quantities require current model recipe eligibility; public Body replacement clears that eligibility even if the new tag is PARAMETRIC. Failed measurements omit the affected quantity and appear in toIfcValidated() as WALL_QUANTITY_OMITTED issues.

Wall openings export as IFC Reference geometry because the retained Wall Body already contains its cuts. Void/fill relationships and opening placements remain intact. IFC4 defines Reference openings as non-subtractive; gross recipe exports such as Slab openings still use subtractive Body geometry. The importer keeps Reference opening records and relationships without treating their reference shape as a display Body or cutting tool.

IfcOpenShell 0.8.5 still subtracts Reference openings in its default geometry engine, even with a separate Reference context. If a replacement Body adds material inside a retained opening's region, that engine can remove the added material. Schema validation and shape generation alone do not detect this difference; check the representation semantics and retained item geometry.

Step 1 retains class-specific geometry storage outside Wall/Railing and the transitional model/modelGeometry.ts ownership enumerator. Converging those records and renaming ProductBody to Body belong to step 2.

Status

| Area | State | | ----------------- | ------------------------------------------------------------------------------------------------------------------------- | | Elements | wall, slab, beam, column, roof, curtain wall, space, footing/pile, stair, ramp, railing, covering, Earthworks Fill, proxy | | Profiles | rectangular / circular / I-shape cores + extended L/T/U/Z/C, hollow, ellipse, arbitrary-with-voids | | Openings | door / window / slab openings cut as boolean voids; FillsOpening / Voids* relationships | | Spatial structure | building: project → site → building → storey; civil: project → site → bridge → recursive bridge part | | Property sets | IFC pset templates + measure types; quantity sets for takeoff | | Data layers | materials (layer/profile/simple sets), classification refs, surface styles, zones/systems | | IFC export | toIfc → IFC-SPF (Uint8Array); IFC4 / IFC4X3 schema selection; owner history | | IFC import | fromIfc / SpfReader → ImportedModel (elements, geometry, psets, materials, spatial tree) | | Validation | referential integrity, schema check, geometry validity, IFC round-trip report, buildingSMART gherkin rules | | Interop | COBie 2.4 export (CSV/JSON), IDS 1.0 checking, BCF 3.0 read/write |

Focused IFC4X3 civil bridge profile

The declarative civilSemantics → resolve → familiesToBim path supports authored Site, Bridge, recursively nested Bridge Part, and exact tessellated Earthworks Fill bodies. Products are contained by their nearest Bridge Part; stable IFC identity derives from Families key paths.

The migrated civil Product vocabulary additionally routes these existing typed product families:

  • beam: beam, cross-girder, girder
  • column: pier-stem
  • footing: pad
  • railing: guardrail
  • slab: deck
  • wall: wall

Their semantic material becomes the normal typed element material when materialName is not otherwise supplied. Existing non-semantic Families archetypes continue to use the ordinary route registry beneath Bridge Parts. Bridge, Bridge Part, and Earthworks Fill require IFC4X3; fromIfc reconstructs their civil spatial hierarchy, direct containment, and typed Earthworks inventory.

Civil-semantic wall and railing routes require bodyEvaluator or the proxyEvaluator fallback to retain the authored Product Body. Missing the evaluator is FAMILIES_PRODUCT_BODY_EVALUATOR_REQUIRED, with the element path and mapped category. Conventional archetype walls and railings retain their existing recipe authoring behavior and do not need an evaluator. The adapter registers wall openings before installing the authored Body, copies every borrowed evaluator item into Product-local coordinates, and retains AUTHORITATIVE authority even when the geometry coincides with the nominal recipe. These products keep their typed Wall or Railing classification and export every Body item as tessellation. The evaluator's source handles remain borrowed. Other typed civil routes continue to use their semantic envelope dimensions.

This is deliberately not a claim of complete IFC infrastructure coverage or unchanged parity with the full scratch prototype. Member and Sign remain outside the profile: without proxyEvaluator they are hard errors; with it they are reported IfcBuildingElementProxy occurrences.

Independent validation

The exported IFC is validated by IfcOpenShell (a separate implementation from the web-ifc parser used internally), not just self-checked. The committed sample (examples/sample-building.ifc) passes IfcOpenShell's EXPRESS schema + where-rule validator and generates geometry for every product. See VALIDATION.md to reproduce, and examples/sampleBuilding.mjs for the model it validates.

The buildingSMART Validation Service's complete normative rule catalog also runs locally (scripts/setupGherkinRunner.sh builds the service's own engine; all three committed fixtures pass 950 scenarios with zero failures), so service findings are reproducible before upload.

Not yet: desktop-tool interop (Revit / Solibri) is unverified. The fixtures and per-tool checklists are ready in VALIDATION.md. This is an experimental pre-1.0 package and the API may change.

Usage

Author a small model and export IFC:

import { BimModel, toIfc } from 'brepjs-bim';
import { unwrap } from 'brepjs';

const model = new BimModel();
model.init({ name: 'Example' });

// Spatial structure: project → site → building → storey.
const project = model.getProject();
const siteId = unwrap(model.addSite({ name: 'Site' }));
const buildingId = unwrap(model.addBuilding({ name: 'Building' }));
const storeyId = unwrap(model.addStorey({ name: 'Level 1', elevation: 0 }));
if (project) model.aggregate(project.localId, siteId);
model.aggregate(siteId, buildingId);
model.aggregate(buildingId, storeyId);

// A parametric wall, placed on the storey. Dimensions in mm; axisX is the wall's
// length direction and axisZ its up direction.
const wall = model.addWall({
  length: 4000,
  height: 3000,
  thickness: 200,
  origin: [0, 0, 0],
  axisX: [1, 0, 0],
  axisZ: [0, 0, 1],
  materialName: 'Concrete',
});
if (wall.ok) model.placeIn(wall.value, storeyId);

// Renderable geometry (a brepjs ValidSolid, unplaced/local coords):
const solid = model.getWalls()[0]?.geometry;

// Serialize to an IFC-SPF byte buffer.
const ifc = await toIfc(model, { applicationName: 'brepjs-bim', applicationVersion: '1.0' });
// ifc.ok && ifc.value instanceof Uint8Array

Reading element geometry requires only the core brepjs kernel; toIfc / fromIfc additionally load the web-ifc peer dependency.

All public operations return Result<T, BimError> (from brepjs); validation issues and non-fatal warnings travel inside the payload rather than throwing.

Design

Each add* call parses and validates its spec and stores a typed BimElement keyed by a LocalId. Parametric physical elements build an analytical brepjs solid; civil spatial elements are body-less, and arbitrary-body products such as Earthworks Fill take ownership of a validated authored solid. Families-projected civil walls and railings always retain copies of the evaluated authored items as an AUTHORITATIVE Product Body, even when the geometry coincides with the nominal recipe. The IFC writer walks the model, applies placement, and emits schema-correct IFC entities; the importer is the inverse. No kernel/WASM changes are required.

Development

npm run typecheck --workspace=brepjs-bim
npm run lint --workspace=brepjs-bim
npm run build --workspace=brepjs-bim
npm run test --workspace=brepjs-bim