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

occt-wasm

v3.3.1

Published

OpenCascade (OCCT) compiled to WebAssembly with a clean TypeScript API

Readme

occt-wasm

npm Crates.io CI Last release Commit activity License WASM License

OpenCascade V8 compiled to WebAssembly with a clean TypeScript API.

Smaller bundles, branded types, arena-based memory, and modern tooling.

Looking for a higher-level CAD library? brepjs builds on occt-wasm with a friendlier API for parametric modeling, sketching, and production CAD applications. Use occt-wasm directly when you need full control over OCCT operations.

Highlights

  • ~4.5 MB brotli -- roughly 2x smaller than opencascade.js
  • Comprehensive API -- primitives, booleans, sweeps, XCAF assemblies, curves, surfaces, STEP/STL/glTF/BREP I/O, topology, shape evolution tracking
  • Arena-based API -- u32 shape handles, no manual .delete(), Symbol.dispose support
  • TypeScript-first -- branded ShapeHandle, union types for shapes/surfaces/curves, structured returns
  • Structured error handling -- OcctErrorCode enum for programmatic switch/case instead of string parsing
  • Web Worker support -- OcctWorker class for off-main-thread CAD operations via Comlink
  • Modern browser targets -- WASM SIMD, relaxed-SIMD, tail calls, wasm-exceptions

Scope

To set expectations, this library deliberately does not:

  • Provide a higher-level CAD modeling API — parametric sketching, constraints, feature trees, and ergonomic modeling belong in brepjs, which wraps occt-wasm for that purpose
  • Manage memory automatically beyond arena handles — shapes are freed when the kernel is disposed or you call release(); there is no per-shape garbage collection
  • Support non-WASM-SIMD browsers — the build requires WASM SIMD (baseline -msimd128), tail calls, and wasm exceptions; Firefox lacks tail call support as of v130. Relaxed-SIMD is intentionally not used: some Safari/iOS WebKit builds fail to compile relaxed-SIMD modules, and it made geometry non-reproducible across CPUs
  • Include OCCT visualization or display modules — TKV3d, TKHLR (except the HLR facade), and the AIS interactive context are excluded; bring your own renderer (Three.js, Babylon.js, etc.)
  • Support IGES import/export -- TKDEIGES is excluded from the link; use STEP for interchange

Install

npm install occt-wasm

Quick Start

import { OcctKernel } from "occt-wasm";

// Recommended: deterministic cleanup via Symbol.dispose
{
  using kernel = await OcctKernel.init();

  // Primitives
  const box = kernel.makeBox(20, 20, 20);
  const cyl = kernel.makeCylinder(8, 30);

  // Booleans
  const fused = kernel.fuse(box, cyl);

  // Modeling
  const edges = kernel.getSubShapes(fused, "edge");
  const filleted = kernel.fillet(fused, edges.slice(0, 4), 2.0);

  // Tessellation -> Three.js / Babylon.js
  const mesh = kernel.tessellate(filleted);
  // mesh.positions (Float32Array), mesh.normals, mesh.indices

  // STEP I/O
  const step = kernel.exportStep(filleted);
  const reimported = kernel.importStep(step);

  // Query
  const vol = kernel.getVolume(filleted);
  const bbox = kernel.getBoundingBox(filleted);
  const com = kernel.getCenterOfMass(filleted);

  // kernel is disposed at end of block
}

Rust Crate

The same OCCT WASM is available as a Rust crate for native targets (servers, CLIs, build scripts) — no C++ toolchain required:

[dependencies]
occt-wasm = "3"
use occt_wasm::OcctKernel;

let mut kernel = OcctKernel::new()?;
let box_shape = kernel.make_box(10.0, 20.0, 30.0)?;
let sphere = kernel.make_sphere(8.0)?;
let fused = kernel.fuse(box_shape, sphere)?;
let mesh = kernel.tessellate(fused, 0.1, 0.5)?;
let step = kernel.export_step(fused)?;

The crate embeds a brotli-compressed WASM binary (~4.7 MB) and runs it via wasmtime. Same 170+ facade methods as the TS API. See crate/README.md and docs.rs/occt-wasm for full details.

Initialization

By default, OcctKernel.init() auto-locates the .wasm file next to the JS module. You can also provide explicit paths or pre-loaded binaries:

// Auto-detect (browser, Node.js, or Worker):
const kernel = await OcctKernel.init();

// Explicit URL or path:
const kernel = await OcctKernel.init({ wasm: "/assets/occt-wasm.wasm" });

// Pre-fetched binary (skip the fetch):
const binary = await fetch("/occt-wasm.wasm").then((r) => r.arrayBuffer());
const kernel = await OcctKernel.init({ wasm: binary });

// Uint8Array also accepted:
const kernel = await OcctKernel.init({ wasm: new Uint8Array(binary) });

Error Handling

All errors are instances of OcctError with a structured code field for programmatic handling:

import { OcctError, OcctErrorCode } from "occt-wasm";

try {
  kernel.fuse(a, b);
} catch (e) {
  if (e instanceof OcctError) {
    switch (e.code) {
      case OcctErrorCode.BooleanFailed:
        // retry with simpler geometry
        break;
      case OcctErrorCode.InvalidShapeId:
        // shape was already released
        break;
      case OcctErrorCode.KernelError:
        // OCCT internal error (Standard_Failure)
        console.error(e.message);
        break;
    }
  }
}

Available error codes:

| Code | When | | -------------------- | ----------------------------------------------- | | ConstructionFailed | Build()/IsDone() returned false | | BooleanFailed | Boolean operation (fuse/cut/common/etc.) failed | | InvalidShapeId | Shape ID not found in the arena | | InvalidLabelId | XCAF label ID not found | | TessellationFailed | Meshing operation failed | | ImportExportFailed | STEP/STL/BREP I/O error | | HealingFailed | Shape repair failed | | DocumentClosed | Operation on a closed XCAF document | | KernelError | OCCT Standard_Failure (unclassified) | | Unknown | Error from outside the kernel |

Named Enums

Sweep, offset, and boolean operations use self-documenting enums instead of opaque numbers:

import { TransitionMode, JoinType, BooleanOp } from "occt-wasm";

// Sweep with round-corner transitions
kernel.sweep(profile, spine, TransitionMode.RoundCorner);

// Offset wire with arc joins
kernel.offsetWire2D(wire, 2.0, JoinType.Arc);

// Boolean pipeline
kernel.booleanPipeline(base, [BooleanOp.Cut, BooleanOp.Fuse], [tool1, tool2]);

Numeric values (0, 1, 2) are still accepted for backwards compatibility.

Type Predicates

Convenience methods for checking shape topology:

if (kernel.isSolid(shape)) {
  /* ... */
}
if (kernel.isFace(shape)) {
  /* ... */
}
if (kernel.isEdge(shape)) {
  /* ... */
}
if (kernel.isWire(shape)) {
  /* ... */
}
if (kernel.isVertex(shape)) {
  /* ... */
}
if (kernel.isShell(shape)) {
  /* ... */
}
if (kernel.isCompound(shape)) {
  /* ... */
}

Web Workers

For browser apps, heavy CAD operations can block the main thread. OcctWorker runs a full kernel in a Web Worker with the same API:

import { OcctWorker } from "occt-wasm/worker";

// Spawn a worker with its own kernel
const worker = await OcctWorker.spawn({ wasm: "/occt-wasm.wasm" });

// Same API, every call returns a Promise
const box = await worker.makeBox(10, 20, 30);
const cyl = await worker.makeCylinder(5, 40);
const fused = await worker.fuse(box, cyl);
const mesh = await worker.tessellate(fused);
console.log(`${mesh.triangleCount} triangles`);

// Access the full kernel via .kernel for less common methods
const nurbs = await worker.kernel.getNurbsCurveData(edge);

// Clean up
worker.terminate();

The worker helper uses Comlink (~1.2 KB gzipped) for transparent RPC. Each worker has its own WASM instance and arena -- shape handles are local to the worker.

XCAF Assemblies

Create assembly documents with colors, names, and component hierarchies:

// Factory method auto-injects Emscripten FS for glTF export
const doc = kernel.createXCAFDocument();

const housing = doc.addShape(box, { name: "housing", color: [0.8, 0.2, 0.1] });
doc.addChild(housing, gear, {
  name: "gear-1",
  location: { tx: 10, tz: 5 },
  color: [0.5, 0.5, 0.5],
});

// Export
const step = doc.exportSTEP(); // preserves colors/names
const glb = doc.exportGLTF(); // no need to pass FS manually
doc.close();

// Import with preserved metadata
const imported = kernel.importXCAFFromSTEP(stepData);

Bundler Configuration

Vite

// vite.config.ts
export default defineConfig({
  optimizeDeps: {
    exclude: ["occt-wasm"], // Don't pre-bundle WASM
  },
  build: {
    target: "esnext", // Required for WASM features
  },
});

Webpack 5

// webpack.config.js
module.exports = {
  experiments: { asyncWebAssembly: true },
  module: {
    rules: [{ test: /\.wasm$/, type: "asset/resource" }],
  },
};

Node.js

// Works out of the box with Node.js 18+
import { OcctKernel } from "occt-wasm";
const kernel = await OcctKernel.init();

API Reference

Generate full docs locally: cd ts && npm run docs (TypeDoc output).

| Category | What's covered | | ---------------- | -------------------------------------------------------------------------------------------------------------- | | Primitives | Box, cylinder, sphere, cone, torus, ellipsoid, rectangle, half-space | | Booleans | Fuse, cut, common, intersect, section + multi-shape variants, intersection cells | | Modeling | Extrude, revolve, fillet, chamfer, shell, offset, draft | | Sweeps | Pipe, loft, sweep, oriented sweep (fixed/Frenet/up-axis/auxiliary), draft prism, extrusion laws | | Construction | Vertices, edges (line/arc/circle/ellipse/bezier/helix), wires, faces, solids, compounds, sewing | | Transforms | Translate, rotate, scale, mirror, align to bounding box, 3x4 matrix, linear/circular patterns | | Topology | Shape type queries, type predicates, sub-shape extraction, adjacency, hash codes | | Tessellation | Triangle meshes (absolute or relative deflection), wireframe polylines, per-face groups, batched meshing | | I/O | STEP, STL, BREP (text + binary) import/export | | Query | Bounding box, volume, surface area, length, center of mass, inertia tensor, point-in-solid, curvature | | Surfaces | Type, normal, UV bounds, point classification, B-spline construction | | Curves | Type, point/tangent eval, parameters, NURBS data, interpolation (incl. clamped tangents), project point | | Projection | Hidden line removal (HLR), multiview SVG render (Front/Top/Right/Iso) | | Modifiers | Thicken, defeature, reverse, simplify, variable fillet, 2D wire offset | | Evolution | Face-tracking history for translate, fuse, cut, fillet, rotate, mirror, scale, chamfer, shell, offset, thicken | | XCAF | Assembly documents with colors, names, component hierarchies, STEP/glTF export | | Healing | Fix shape, unify domain, heal solid/face/wire, fix orientations, remove degenerate edges | | Batch | Multi-shape translate, chained boolean pipeline |

Architecture

OCCT V8.0.0 C++ (git submodule)
    -> emcmake cmake (48 static libs)
    -> C++ facade (OcctKernel class, arena-based u32 IDs)
    -> Embind bindings
    -> emcc link (-O3, -flto, -fwasm-exceptions, SIMD) -> .wasm
    -> wasm-opt -O4 --converge --gufa -> dist/ (20.8 MB)

Built with Rust xtask (cargo xtask build), tested with Vitest.

Size & Performance

Compared against other OCCT-to-WASM builds (all include STEP, XCAF, glTF):

| Build | brotli | | ------------------ | ------- | | occt-wasm | ~4.5 MB | | opencascade.js | ~9 MB | | brepjs-opencascade | ~5 MB |

Run benchmarks locally: npx tsx test/benchmark.ts

Development

Building from Source

# Prerequisites: Rust 1.85+, emsdk 5.0.3
git clone --recurse-submodules https://github.com/andymai/occt-wasm
cd occt-wasm
npm install && cd ts && npm install && cd ..

cargo xtask build       # Build OCCT + facade -> WASM
cargo xtask test        # Run tests

# View the Three.js example
npx serve .
# Open http://localhost:3000/examples/three-js/

Docker Build

No local emsdk or Rust needed -- everything runs in the container.

npm run docker:build    # Build image (OCCT layer cached after first run)
npm run docker:dist     # Build + copy dist/ artifacts to host

Browser Compatibility

occt-wasm requires modern browsers with WASM SIMD, relaxed-SIMD, tail calls, and exception handling:

| Browser | Minimum Version | Notes | | ------- | --------------- | -------------------------------------- | | Chrome | 114+ | Relaxed-SIMD (114), tail calls (112) | | Edge | 114+ | Same engine as Chrome | | Safari | 17.2+ | Relaxed-SIMD (17.2), tail calls (15) | | Firefox | Not supported | No tail call support as of Firefox 130 |

Node.js 22+ is recommended (tail calls via V8). Node.js 18+ works if your V8 version supports the required WASM features.

Known Limitations

These are upstream OCCT V8.0.0 issues, not occt-wasm bugs:

  • IGES -- TKDEIGES excluded from link; no IGES import/export
  • Zero-length extrusion -- WASM exception escapes JS catch boundary (1 test skip)
  • Single WASM thread -- each kernel instance is single-threaded; use OcctWorker (see above) to move work off the main thread
  • Firefox -- not supported due to missing WASM tail call support

These will be addressed as upstream OCCT and browser support improve.

Contributing

This project is open source. Bug reports and feature requests are welcome via GitHub Issues. For pull requests, please open an issue first to discuss the change.

License

Build tooling (xtask, scripts, TypeScript wrapper): MIT OR Apache-2.0

Compiled WASM output: LGPL-2.1-only (inherits from OCCT)

The LGPL requires that end users can replace the LGPL component. For web applications, this is satisfied by loading the .wasm file from a URL (which users can override via OcctKernel.init({ wasm: '...' })). If you ship a desktop app with the WASM embedded, consult the LGPL-2.1 FAQ.