OpenCascade.js

First Shape Tutorial

Build a filleted box from scratch, render it in three.js, and inspect the OCCT call sites.

This tutorial extends the npm quickstart with explanations of every OCCT type involved — useful if you've never touched OCCT before.

Step 1 — Choose a primitive

BRepPrimAPI_MakeBox constructs an axis-aligned box from three lengths.

using box = new oc.BRepPrimAPI_MakeBox(60, 40, 20);
const shape = box.Shape();

shape is a TopoDS_Shape — the universal OCCT geometry handle. All booleans, fillets, and exports take and return TopoDS_Shape instances.

Step 2 — Walk topology

OCCT shapes are hierarchical: SOLID → SHELL → FACE → WIRE → EDGE → VERTEX. TopExp_Explorer iterates entries of a given kind in declaration order.

using explorer = new oc.TopExp_Explorer(shape, oc.TopAbs_ShapeEnum.TopAbs_EDGE);
const edges: typeof oc.TopoDS_Edge[] = [];
while (explorer.More()) {
  edges.push(oc.TopoDS.Edge(explorer.Current()));
  explorer.Next();
}

A box has 12 edges — three groups of 4 parallel edges along each axis.

Step 3 — Apply a fillet

BRepFilletAPI_MakeFillet takes the shape and a per-edge radius. Calling Add(radius, edge) once per edge marks them for filleting; Shape() runs the algorithm and returns the result.

using fillet = new oc.BRepFilletAPI_MakeFillet(shape);
for (const edge of edges) fillet.Add(3, edge);
const filletedShape = fillet.Shape();

Step 4 — Tessellate and export

Until you call BRepMesh_IncrementalMesh, the shape has no triangulation — it's still analytic. The mesher caches per-shape triangulation; pass decreate=true on the third argument to force regeneration when you change tolerance.

using _mesh = new oc.BRepMesh_IncrementalMesh(filletedShape, 0.1, false, 0.5, false);

The two tolerances are linear (mm) and angular (radians). 0.1 mm linear is fine for a 60 mm box; tighten it on small features.

Export via the XCAF path documented in Export glTF / GLB to get a GLB your three.js viewer can load.

Step 5 — Render

The npm quickstart shows the full three.js wiring. The minimal version:

const loader = new GLTFLoader();
loader.parse(glb.buffer, '', (gltf) => scene.add(gltf.scene));

What went wrong if…

SymptomLikely cause
BindingError: ptr<-1>You called a method on a disposed object — using exited scope earlier than expected
Black canvas, no errorsCamera is inside the shape — set camera.position.set(100, 100, 100)
Fillet Shape() throwsOne of your edges is degenerate; check edge.Orientation()
RWGltf_CafWriter.Perform returns falseThe XCAF doc has no shape attached — verify ShapeTool.AddShape succeeded

Where to next

On this page