The OpenCASCADE 3D CAD kernel, compiled to WebAssembly with TypeScript bindings.
Documentation
·
Issues
Build solids, run booleans, fillet edges, mesh, and read/write STEP — in a
browser tab, a Node CLI, or an LLM tool call. Source lives in
taucad/opencascade.js; this is not
an official Open CASCADE Technology distribution.
| I want to… | Go to |
|---|---|
| Use OCCT from JS or TS | Install |
| Run the threaded build | Multi-threading |
| Build a trimmed or custom WASM | Toolchain |
| Pull a container image | Container images |
| See what changed in v3 | What's new in v3 · BREAKING_CHANGES.md |
| Build OCCT WASM from source | MAINTAINER.md |
| Contribute | CONTRIBUTING.md |
npm install libcascadeimport oc from 'libcascade';
using box = new oc.BRepPrimAPI_MakeBox(10, 10, 10);
const shape = box.Shape();The root export is an initialised instance, selected for the variant the host supports. Every bound symbol is also a named export.
| Import | What it gives you |
|---|---|
libcascade |
Initialised instance, variant selected for the host |
libcascade/init |
Shared lazy selector |
libcascade/single/init |
Fixed single-threaded initializer |
libcascade/multi/init |
Fixed multi-threaded initializer |
libcascade/single/wasm · libcascade/multi/wasm |
Binary URL, for bundlers that relocate assets |
libcascade/api-reference.json |
Class/member hierarchy, source commit, build provenance |
Pass options through a fixed initializer when the variant is known:
// Vite / browser, with a relocated wasm asset
import { createInstance } from 'libcascade/single/init';
import wasmUrl from 'libcascade/single/wasm?url';
const oc = await createInstance({ locateFile: () => wasmUrl });The package is ESM-only. The WASM resolves on its own — reach for locateFile
only when a bundler or deployment moves the binary. Deep imports into dist/
are not a supported surface.
The tarball ships dist/opencascade_single.{wasm,js} and
dist/opencascade_multi.{wasm,js}, each with a provenance.json sidecar naming
the exact toolchain and source commits. Both variants share one assembled
types.d.ts surface. Releases publish through GitHub OIDC Trusted Publishing
with Sigstore provenance — see the
release flow.
For batch meshing, boolean grids, and STEP→glTF pipelines that use OCCT's internal thread pool, ask for the pthread build:
import { createInstance } from 'libcascade/multi/init';
const oc = await createInstance();
// Run once after init — flip OCCT global parallel defaults.
oc.BOPAlgo_Options.SetParallelMode(true); // booleans fan out
oc.BRepMesh_IncrementalMesh.SetParallelDefault(true); // meshing fans outcreateInstance owns the pthread plumbing: worker self-reference, Node path
conversion, and thread-pool sizing. Under Vite, set worker: { format: 'es' }
— Emscripten's workers are ES modules.
Browsers need Cross-Origin-Opener-Policy: same-origin and
Cross-Origin-Embedder-Policy: require-corp on every page that loads the
threaded binary. The multi-threading guide
covers activation, measured speedups, and when not to ship threaded.
Reach for @libcascade/toolchain when you need a binary the prebuilt one is
not: a trimmed symbol set, your own C++ wrappers, or different Emscripten link
settings. It drives digest-pinned Docker images for you, so there is no
docker run string to maintain. A container engine must be installed and
running.
npm install --save-dev @libcascade/toolchain// libcascade.config.ts
import { defineBuild } from '@libcascade/toolchain';
export default defineBuild({
name: 'myapp',
bindings: ['BRepPrimAPI_MakeBox', 'TopoDS_Shape', 'gp_Pnt'],
settings: { MODULARIZE: true, EXPORT_ES6: true, ALLOW_MEMORY_GROWTH: true },
compilerFlags: { optimize: 'O3', simd: true, exceptions: 'wasm', noEntry: true },
variants: [{ name: 'single' }],
});npx libcascade build # link each variant through the pinned image → dist/
npx libcascade assemble # shared types.d.ts + ./init entry + exports map
npx libcascade check src # CI drift guard: referenced symbols ⊆ bound symbolsSymbol names and -s settings are compile-checked against unions generated from
the pinned image, so a typo is a TypeScript error rather than a runtime
BindingError.
Images publish to
ghcr.io/taucad/opencascade.js
as multi-arch manifest lists (linux/amd64 + linux/arm64). Docker resolves the
architecture itself, Apple Silicon runs natively, and no --platform flag is
needed.
| Tag | What it points at |
|---|---|
:single-threaded |
Latest release, single-threaded warm cache (default for browser CAD UIs) |
:multi-threaded |
Latest release, multi-threaded warm cache (requires COOP/COEP) |
:bindgen-base |
Post-PCH/generate, pre-compile — the custom-bindings starting point |
:{{version}}-<stage> |
Pinned release for any of the three stages above |
:{{version}}-canary.<sha8>-<stage> |
Immutable maintainer-dispatched canary, retained for seven days |
:branch-main[-<full-sha>] |
Current or immutable main, single-threaded |
:multi-threaded-branch-main[-<full-sha>] |
Current or immutable main, multi-threaded |
:bindgen-base-branch-main[-<full-sha>] |
Current or immutable main, bindgen-base |
Building the image, or driving it directly, is covered in MAINTAINER.md.
| Change | Detail |
|---|---|
| OCCT 8.0.1 | 1,085+ upstream commits; 22–31% faster boolean operations |
| Emscripten 6.0.5 | LLVM 24, modern WASM features |
| Native WASM exceptions | -fwasm-exceptions replaces JS invoke trampolines; decodable via oc.getExceptionMessage |
| ESM-only distribution | "type": "module", eager root plus fixed and shared lazy entries |
| Full TypeScript bindings | Doxygen-derived JSDoc, rendered in Monaco IntelliSense |
| Suffix-free overloads | One symbol per class with val-based dispatch — no _2/_3 subclasses |
| Reproducible builds | DEPS.json pins every dependency to a commit; per-build provenance.json |
| Incremental builds | Content-addressed cache turns 10–30 minute clean builds into seconds on hit |
Overload dispatch measures ~264 ns/call, under 0.011% of wall time on typical CAD models. BENCHMARKS.md carries the evidence: CAD wall-clock against native C++, threading speedup, embind dispatch cost, and RBV overhead. CHANGELOG.md has the full entry.
| Document | Covers |
|---|---|
| libcascade.xyz | Full docs: package, toolchain, API reference |
| BREAKING_CHANGES.md | v3 consumer migration |
| BENCHMARKS.md | Measured performance, end to end |
| CHANGELOG.md | Release notes |
| MAINTAINER.md | Native build, env vars, release ownership |
| BUILD_SYSTEM.md | OCJS_* env-var matrix and configuration authoring |
| Trim symbols | Cutting the binding set to a consumer-sized build |
| Extend with C++ | customBindings scopes |
| Reproducible CI | Digest pinning, provenance, SBOM, lockfiles |
- ArchiYou — library, code-CAD design tool, community hub
- BitByBit — code- and node-based CAD tool
- CascadeStudio — library and code-CAD design tool
- Replicad — library and code-CAD design tool
- Tau — AI-native CAD platform for the web
Start with CONTRIBUTING.md, check TODO.md for the backlog, and use MAINTAINER.md to build from source.
See LICENSE.