libcascade

Entry points

The eager root export, the ./init factory, createInstance options, and the raw per-variant subpaths.

libcascade exposes three entry points. Which one you want depends on whether you need to control when the WASM module is instantiated.

EntryImportGives you
RootlibcascadeAn already-initialised instance, plus every bound symbol as a named value export.
Factorylibcascade/initcreateInstance(options) — nothing is instantiated until you call it.
Variantlibcascade/single, libcascade/multiThe raw Emscripten glue for one binary. Advanced.

Root — the initialised instance

The root entry probes the host, picks the most capable variant it supports, and initialises it with a top-level await:

import oc from 'libcascade';

using box = new oc.BRepPrimAPI_MakeBox(10, 10, 10);
const shape = box.Shape();

Every bound symbol is also a named value export, so you can import the classes you use directly:

import { BRepPrimAPI_MakeBox } from 'libcascade';

using box = new BRepPrimAPI_MakeBox(10, 10, 10);

Types are exported from the same specifier:

import oc, { type OpenCascadeInstance, type TopoDS_Shape } from 'libcascade';

Because the module instantiates at import time, there is nothing to memoise — ES module evaluation happens once per realm.

libcascade/init — the factory

Use this entry when you need options, a specific variant, or control over when the WASM comes up. Importing it never evaluates the eager root.

import { createInstance } from 'libcascade/init';

const oc = await createInstance();
const mt = await createInstance({ variant: 'multi' });
const capped = await createInstance({ variant: 'multi', threadCount: 4 });

Options

Prop

Type

createInstance owns the plumbing that is otherwise the consumer's problem: the glue self-reference Emscripten's pthread workers spawn from, Node file: URL → path conversion, and OCCT thread-pool sizing for a threads variant. It throws with an actionable message when you request a variant this host cannot run.

Memoised singleton pattern

WASM instantiation is expensive. Memoise the Promise when several call sites share one runtime and you are not using the eager root:

import { createInstance } from 'libcascade/init';

let ocPromise: ReturnType<typeof createInstance> | undefined;
export const getOc = () => (ocPromise ??= createInstance());

Variant selection

Selection picks the most capable variant whose requirements the host meets; multi requires SharedArrayBuffer and cross-origin isolation (Node always qualifies). To force a choice before anything is imported:

globalThis[Symbol.for('libcascade.select')] = 'single';

Return type

The resolved object exposes every bound class and namespace as instance properties (oc.BRepPrimAPI_MakeBox, oc.TopoDS) together with oc.FS, oc.wasmMemory, and exception helpers such as oc.getExceptionMessage.

One OpenCascadeInstance type describes every variant, so a shape produced by the single-threaded instance is assignable wherever the multi-threaded one is expected.

Variant subpaths — advanced

libcascade/single and libcascade/multi resolve to the raw Emscripten glue. Their default export is the module factory:

import init from 'libcascade/multi';

const oc = await init();

This bypasses createInstance, so you own the pthread plumbing — including the mainScriptUrlOrBlob self-reference workers need. Prefer createInstance({ variant: 'multi' }) unless you have a reason not to. The matching binaries are exported as libcascade/single/wasm and libcascade/multi/wasm.

Browser deployments of the threaded variant also need cross-origin isolation. See Multi-threaded build.

On this page