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.
| Entry | Import | Gives you |
|---|---|---|
| Root | libcascade | An already-initialised instance, plus every bound symbol as a named value export. |
| Factory | libcascade/init | createInstance(options) — nothing is instantiated until you call it. |
| Variant | libcascade/single, libcascade/multi | The 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.