OpenCascade (OCCT 8.0.0) compiled to WebAssembly with TypeScript bindings.
C++ OCCT Libraries (.a)
|
[embind C++ layer] <- disambiguated names (e.g. Mirror_Pnt, Mirror_Ax1)
(generated/ + manual/) generated from YAML configs + parsed headers
|
WASM Module (.wasm + .js glue)
|
[TypeScript wrapper layer] <- proper overloads with instanceof dispatch
(generated/ + manual/) generated TS wrappers + module loader / types
|
NPM Package (@cesarecaoduro/occtwasm-core)
Why two layers? Emscripten's embind only supports overloading by argument count, while OCCT heavily overloads by type (e.g. gp_Trsf::SetMirror(gp_Pnt) vs SetMirror(gp_Ax1) vs SetMirror(gp_Ax2)). The C++ layer disambiguates with suffixed names; the TypeScript layer restores the original API with runtime instanceof dispatch.
Why manual helpers? Three codegen limitations require hand-written C++ embind wrappers:
- Handle types (e.g.
GC_MakeArcOfCirclereturnsHandle(Geom_TrimmedCurve)) - Virtual methods (
Shape(),Build(),IsDone()are virtual and skipped by the parser) - Abstract base classes (e.g.
GCPnts_AbscissaPointtakesAdaptor3d_Curve&)
- Box, Cylinder, Sphere via
BRepPrimAPI_MakeBox,BRepPrimAPI_MakeCylinder,BRepPrimAPI_MakeSphere - Face from wire via
BRepBuilderAPI_MakeFace
- BSpline curves — create edges from control poles, knots, multiplicities, and degree
- BSpline surfaces — create faces from a 2D control grid
- Curve introspection — extract degree, poles, knots, weights, and rational/periodic flags from intersection result edges via
getEdgeBSplineInfo()
- Lofting —
BRepOffsetAPI_ThruSectionsfor surface/solid lofts through multiple profiles - Pipe sweep —
BRepOffsetAPI_MakePipefor sweeping a profile along a spine wire - Boolean operations —
BRepAlgoAPI_Fuse,BRepAlgoAPI_Cut,BRepAlgoAPI_Common - Surface intersection —
BRepAlgoAPI_Sectionproducing exact NURBS intersection curves
- BREP export —
exportBRep()returns BREP string data - STEP export —
exportSTEP()returns STEP AP214 string data (requires OCCT built with DataExchange module)
import { initOCCT } from '@cesarecaoduro/occtwasm-core';
import { gp_Pnt } from '@cesarecaoduro/occtwasm-core/TKMath';
import { BRepBuilderAPI_MakeEdge, BRepBuilderAPI_MakeWire } from '@cesarecaoduro/occtwasm-core/TKTopAlgo';
import { edgeLength, makeArcEdge3d, wireLength } from '@cesarecaoduro/occtwasm-core/helpers';
await initOCCT();
const p1 = new gp_Pnt(0, 0, 0);
const p2 = new gp_Pnt(10, 0, 0);
const maker = new BRepBuilderAPI_MakeEdge(p1, p2);
const edge = maker.Edge();
console.log(edgeLength(edge)); // 10.0
const a1 = new gp_Pnt(10, 0, 0);
const a2 = new gp_Pnt(0, 10, 0);
const a3 = new gp_Pnt(-10, 0, 0);
const arc = makeArcEdge3d(a1, a2, a3);
console.log(edgeLength(arc)); // ~31.42 (pi * 10)
const wire = new BRepBuilderAPI_MakeWire(edge, arc);
console.log(wireLength(wire.Wire())); // ~41.42A Three.js-powered 3D viewer demonstrates the library interactively using Vite and lil-gui. It renders points and wires directly from OCCT shapes and also triangulates surfaces/solids for shaded previews.
Demos included:
| Group | Demo | Description |
|---|---|---|
| Basics | Edge, Arc, Polyline, Wire | Core wire-frame geometry primitives |
| Wires | Wire Intersection | Compute real intersection points between wires |
| Loft | Loft Surface / Loft Solid | Lofting through open or closed wire profiles |
| Loft | Multi-Section Loft | Loft through 4 different cross-sections (square, octagon, etc.) |
| Sweep | AASHTO BT-72 Girder | Prestressed concrete girder swept along a parabolic pre-camber spine |
| Surfaces | NURBS Surface Intersection | Dome vs. saddle intersection producing true BSpline curves with control polygon display |
| Boolean | Boolean Operations | Union, difference, and intersection of box/cylinder/sphere primitives |
All solid/BREP demos include Export BREP and Export STEP download buttons.
cd examples/viewer
pnpm install
pnpm run devUse the sidebar to switch demos. Orbit: left drag. Pan: right drag. Zoom: scroll.
All generated bindings resolve the active Emscripten module from initOCCT(). Call initOCCT() once before using any bindings:
import { initOCCT } from '@cesarecaoduro/occtwasm-core';
await initOCCT();If you host the WASM on a CDN, pass locateFile:
await initOCCT({
locateFile: (path) => `https://cdn.example.com/wasm/${path}`,
});Embind objects are manual-lifetime. Call .delete() on objects you create:
const p = new gp_Pnt(1, 2, 3);
// ...
p.delete();- Emscripten (e.g.
brew install emscripten) - Node.js >= 18
- CMake
npm install # Install TS dependencies
make init-submodule # Initialize OCCT git submodule
make build-occt # Build OCCT static libs (Emscripten)
make codegen # Generate embind C++ and TS wrappers
make build-bindings # Compile WASM module (occt.js + occt.wasm)
npm run build # Build TypeScript package
npm test # Run testsIf you only change TypeScript wrappers or viewer code, npm run build is enough. If you add or modify C++ bindings, you must run make build-bindings first.
extern/occt/ # OCCT source (git submodule, V8_0_0_rc3)
scripts/ # Build scripts (local Emscripten)
codegen/
config/ # Per-toolkit YAML configs
modules.yaml # Module registry (which toolkits to build)
TKMath.yaml # gp_* geometry classes (3D + 2D)
TKBRep.yaml # TopoDS/BRep topology classes
TKTopAlgo.yaml # BRepBuilderAPI_Make* builder classes
TKGeomBase.yaml # gce_Make* geometry construction classes
src/ # Codegen tool source
codegen.ts # Entry point
parse-headers.ts # OCCT .hxx header parser
parse-config.ts # YAML config loader + resolved types
merge-config.ts # Merge YAML config with parsed headers
emit-embind.ts # Generate C++ embind bindings
emit-typescript.ts # Generate TypeScript wrappers
type-mapper.ts # C++ <-> TS/embind type mapping
overload-resolver.ts # Runtime overload dispatch codegen
generate-yaml.ts # CLI tool to scaffold new YAML configs
bindings/
generated/ # Auto-generated by `make codegen`
cpp/ # embind C++ (one file per OCCT toolkit)
TKMath.cpp
TKBRep.cpp
TKTopAlgo.cpp
TKGeomBase.cpp
ts/ # TypeScript wrappers with runtime overload dispatch
TKMath.ts
TKBRep.ts
TKTopAlgo.ts
TKGeomBase.ts
manual/ # Hand-written code
cpp/
occt_wasm_init.cpp # Module-level init
cast_helpers.cpp # TopoDS downcasting helpers
arc_helpers.cpp # Arc edge from 3 points (wraps Handle types)
curve_measure_helpers.cpp # Edge/wire length, point at length
gprop_helpers.cpp # GProp_GProps + BRepGProp properties
boolean_helpers.cpp # BRepAlgoAPI_Section (wire intersection)
boolean_ops_helpers.cpp # BRepAlgoAPI_Fuse, Cut, Common
loft_helpers.cpp # BRepOffsetAPI_ThruSections (lofting)
pipe_helpers.cpp # BRepOffsetAPI_MakePipe (sweep)
primitive_helpers.cpp # BRepPrimAPI_MakeBox, MakeCylinder, MakeSphere
face_helpers.cpp # BRepBuilderAPI_MakeFace
bspline_helpers.cpp # BSpline curve/surface factory functions
curve_info_helpers.cpp # Extract BSpline curve data from edges
mesh_helpers.cpp # Triangulation for rendering (MeshShape)
export_helpers.cpp # BREP export to string
step_export_helpers.cpp # STEP export to string
ts/
types.ts # OcctModule interface, InitOptions
module-loader.ts # Async initOCCT() singleton WASM loader
helpers.ts # TS wrappers for manual C++ helpers
examples/
viewer/ # Vite + Three.js demo viewer
build/ # Build artefacts (gitignored)
occt-install/ # Pre-built OCCT static libraries + headers
dist/ # occt.js + occt.wasm output
- Arc creation:
MakeArcEdge3d,MakeArcEdge2d - Curve measurement:
EdgeLength,WireLength,PointAtLengthOnEdge,PointAtLengthOnWire - Global properties:
BRepGProp_*+GProp_GProps - Wire intersection:
BRepAlgoAPI_Section - Lofting:
BRepOffsetAPI_ThruSections - Pipe sweep:
BRepOffsetAPI_MakePipe - Primitives:
BRepPrimAPI_MakeBox,MakeCylinder,MakeSphere - Face creation:
BRepBuilderAPI_MakeFace - Boolean ops:
BRepAlgoAPI_Fuse,BRepAlgoAPI_Cut,BRepAlgoAPI_Common - BSpline factories:
MakeBSplineCurveEdge,MakeBSplineSurfaceFace - Curve introspection:
GetEdgeBSplineInfo(extract NURBS curve data from edges) - Cast helpers:
TopoDS_ToVertex,TopoDS_ToEdge,TopoDS_ToWire,TopoDS_ToFace - Meshing:
MeshShape(triangulation for rendering) - Export:
ExportBRep,ExportSTEP
Modeling: TKOffset > TKBO > TKBool > TKShHealing > TKTopAlgo > TKGeomAlgo > TKMesh > TKPrim
TKBRep > TKGeomBase > TKG3d > TKG2d > TKMath > TKernel
DataExchange: TKDESTEP > TKDEIGES > TKXSBase > TKDE
AppFramework: TKXCAF > TKVCAF > TKCAF > TKLCAF > TKCDF
Visualization: TKV3d > TKService
The package is published to the GitHub Packages npm registry via a manual-dispatch GitHub Action.
To install from GitHub Packages:
npm install @cesarecaoduro/occtwasm-core --registry=https://npm.pkg.github.comAdd to .npmrc if needed:
@cesarecaoduro:registry=https://npm.pkg.github.com
LGPL-2.1-only WITH OCCT-exception-1.0 (same as OCCT).
This project does not claim additional rights over Open CASCADE Technology; copyright and related rights for OCCT remain with Open CASCADE and its contributors.
Complete corresponding source and build scripts for the distributed WASM
artifacts are documented in SOURCE_AVAILABILITY.md.


