A port of the OpenCascade CAD library to JavaScript and WebAssembly via Emscripten.
Explore the docs »
Issues
·
Discuss
| I want to… | Go to |
|---|---|
Use OCCT from JS or TS (npm install, ESM init) |
Quickstart (npm) |
| Run a reproducible build (CI, Docker, custom YAML) | Quickstart (Docker) |
| See what changed in v3 (OCCT V8, ESM-only, exceptions) | What's New in v3 · BREAKING_CHANGES.md |
| Customize the binding set (trim YAML, add wrappers) | docs/reference/yaml-schema.md |
| Build OCCT WASM from source (fork maintainers) | MAINTAINER.md |
| Contribute or report an issue | Contributing · Issues |
- Choose Your Path
- Table of Contents
- Quickstart (npm)
- Quickstart (Docker)
- Tags
- What's New in v3
- Documentation
- Projects Using opencascade.js
- Contributing
- License
Upgrading from v2? See BREAKING_CHANGES.md for the v3 migration guide (package rename, ESM-only loading, exception decode pattern, OCCT V8 API).
pnpm add @taucad/opencascade.js@beta
# or: npm install @taucad/opencascade.js@betaThe package is ESM-only with a default-export init function. Pass locateFile so the Emscripten loader can resolve the wasm binary from your bundler's output (browser) or node_modules layout (Node). Both runtimes reach the binary through the @taucad/opencascade.js/wasm subpath export — no dist/... deep imports required.
// Node
import { fileURLToPath } from 'node:url';
import { dirname, join } from 'node:path';
import init from '@taucad/opencascade.js';
const WASM_DIR = dirname(fileURLToPath(import.meta.resolve('@taucad/opencascade.js/wasm')));
const oc = await init({
locateFile: (filename: string) => join(WASM_DIR, filename),
});
using box = new oc.BRepPrimAPI_MakeBox(10, 10, 10);
const shape = box.Shape();// Vite / browser
import init from '@taucad/opencascade.js';
import wasmUrl from '@taucad/opencascade.js/wasm?url';
const oc = await init({ locateFile: () => wasmUrl });The published tarball ships pre-built WASM at dist/opencascade_full.{wasm,js,d.ts} (single-threaded default) and dist/opencascade_full_multi.{wasm,js,d.ts} (multi-threaded opt-in), each with a provenance.json sidecar describing the exact toolchain and source commits used.
For batch meshing, boolean grids, and STEP→glTF pipelines that benefit from OCCT's internal thread pool, import the pthread-enabled variant instead of the default:
// Node
import { fileURLToPath } from 'node:url';
import { dirname, join } from 'node:path';
import init from '@taucad/opencascade.js/multi';
const WASM_DIR = dirname(fileURLToPath(import.meta.resolve('@taucad/opencascade.js/multi/wasm')));
const oc = await init({
locateFile: (filename: string) => join(WASM_DIR, filename),
});
// Run once after init — flip OCCT global parallel defaults and size the thread pool.
oc.BOPAlgo_Options.SetParallelMode(true); // booleans fan out by default
oc.BRepMesh_IncrementalMesh.SetParallelDefault(true); // meshing fan out by default
const pool = oc.OSD_ThreadPool.DefaultPool(-1); // lazy-init pool to NbLogicalProcessors
pool.SetNbDefaultThreadsToLaunch(pool.NbThreads()); // let each call use all workers// Vite / browser (requires COOP/COEP headers — see docs)
import init from '@taucad/opencascade.js/multi';
import wasmUrl from '@taucad/opencascade.js/multi/wasm?url';
const oc = await init({ locateFile: () => wasmUrl });
oc.BOPAlgo_Options.SetParallelMode(true);
oc.BRepMesh_IncrementalMesh.SetParallelDefault(true);
using pool = oc.OSD_ThreadPool.DefaultPool(-1);
pool.SetNbDefaultThreadsToLaunch(pool.NbThreads());Browsers require Cross-Origin-Opener-Policy: same-origin and Cross-Origin-Embedder-Policy: require-corp on every page that loads the threaded wasm. See the multi-threaded build guide for activation, benchmarks, and when not to ship threaded; toolchain custom-build covers the YAML recipe for trimmed MT variants.
Pre-built images are published to ghcr.io/taucad/opencascade.js:
- Release tags (
v*) publish multi-arch manifest lists (linux/amd64+linux/arm64). - Branch pushes publish
linux/amd64-only images for fast smoke iteration.
No local build required.
docker pull ghcr.io/taucad/opencascade.js:single-threaded
# Single-mount Quickstart — outputs land next to your YAML
docker run --rm \
-v "$(pwd):/src" \
-u "$(id -u):$(id -g)" \
ghcr.io/taucad/opencascade.js:single-threaded link /src/my-config.ymlFor cached iterative builds (link-only reruns in ≤ 5 min), see the named-volume recipe in MAINTAINER.md. Apple Silicon runs natively from the manifest list — no --platform flag required.
The entrypoint dispatches subcommands (link, compile-bindings, compile-sources, pch, generate, apply-patches) through npx nx run ocjs:<target>. link is the end-to-end command — Nx's dependsOn graph pulls every upstream step with cache reuse, so a fresh container performs a full build and cached re-runs replay only the link. Use docker run … --help for the complete reference, or docker run … nx <args> as an escape hatch into raw Nx.
| 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 |
Latest release, post-PCH/generate but pre-compile (custom-bindings starting point) |
:<version>-single-threaded |
Pinned release, single-threaded (e.g. :3.0.0-single-threaded) |
:<version>-multi-threaded |
Pinned release, multi-threaded |
:<version>-bindgen-base |
Pinned release, bindgen-base |
:branch-<slug> |
Branch tip, single-threaded (amd64-only, ephemeral — 7-day GHCR retention) |
:multi-threaded-branch-<slug> |
Branch tip, multi-threaded (amd64-only, ephemeral) |
:bindgen-base-branch-<slug> |
Branch tip, bindgen-base (amd64-only, ephemeral) |
On release tags, Docker resolves the right architecture from the manifest list automatically — no --platform flag is needed on either linux/amd64 or linux/arm64 hosts.
- OCCT 8.0.0 RC5 — 1,085 commits of improvements; 22-31% faster boolean operations
- Emscripten 5.0.1 — LLVM 17, modern WASM features
- Native WASM Exceptions —
-fwasm-exceptionsreplaces JS invoke trampolines; decodable end-to-end viagetExceptionMessage - ESM-only distribution —
"type": "module"; default export is single-threadedopencascade_full.{js,wasm,d.ts}; multi-threadedopencascade_full_multi.{js,wasm,d.ts}ships under@taucad/opencascade.js/multiand/multi/wasm - Full TypeScript bindings — Doxygen-derived JSDoc rendered correctly in Monaco IntelliSense
- Suffix-free overloads — single symbol per class with val-based dispatcher, no more
_2/_3subclasses - Reproducible builds —
DEPS.jsonpins every dependency to an exact commit; per-buildprovenance.jsonsidecar - Cached, incremental builds — content-addressed compilation cache turns 10-30 minute clean builds into seconds on hit
See CHANGELOG.md for the full v3.0.0 entry.
- BREAKING_CHANGES.md — v3 consumer migration guide
- CHANGELOG.md — release notes
- MAINTAINER.md — native build, env vars, customization for fork maintainers
- docs/reference/yaml-schema.md — YAML schema (bindings, emccFlags, additionalCppCode, additionalCppFiles, additionalBindCode, allowedUndefinedSymbols)
- BUILD_SYSTEM.md —
OCJS_*env-var matrix and configuration authoring - docs/guides/custom-emcc-flags.md — tuning size, speed, and build time
- docs/guides/trim-symbols.md — trim from
full.ymlto a consumer-sized build - docs/guides/extend-with-cpp.md — add wrappers via
additionalCppCode/additionalCppFiles/additionalBindCode - docs/guides/reproducible-ci.md — pin-by-SHA,
provenance.json, SBOM, lockfile discipline
- ArchiYou — Library, Code-CAD Design Tool, Community Hub
- BitByBit — Code- & node-based CAD Design Tool
- CascadeStudio — Library and Code-CAD Design Tool
- RepliCAD — Library and Code-CAD Design Tool
- Tau — AI-native CAD platform for the web
Contributions are welcome! See TODO.md for the current backlog and MAINTAINER.md for build-from-source instructions.
See LICENSE.