@indispec/cad-kernel
v0.1.1
Published
Exact CAD geometry kernel: recorded parametric geometry and STEP become OpenCascade (OCCT) B-rep, with metrics, tessellation and STEP/STL export.
Maintainers
Readme
@indispec/cad-kernel
Exact CAD geometry from recorded parametric data. Takes the scene a FeatureScript program builds (or a STEP file) and turns it into real OpenCascade B-rep: exact volumes, areas and bounds, display-ready tessellation, and STEP/STL export.
The npm package is MIT and ships only our own compiled JavaScript — it contains no OpenCascade
code or wasm. OCCT arrives as the replicad-opencascadejs dependency, and the .wasm is always
kept as a separate file loaded at runtime, never inlined. Read Licensing before you
serve it to users.
Status: experimental (0.x). The operations below are implemented and tested against exact geometry, but the API may change between minor versions.
Install
npm install @indispec/cad-kernel @indispec/fs-compatNode ≥ 20 for the Node host. The browser host needs a bundler that can resolve a ?url import
(Vite, Rollup) — or serve the wasm yourself.
Quickstart (Node)
import { runFeature } from '@indispec/fs-compat'
import { initKernel, translateScene, evaluateBodies, exportSceneStep } from '@indispec/cad-kernel'
await initKernel() // loads the OCCT WASM once per process (~100–200 ms)
const { interp } = runFeature(source, null, null, { includes })
const bodies = translateScene(interp.scene)
const result = evaluateBodies(bodies, { chordMm: 0.5, angleDeg: 15 })
result.bodies[0].volumeMm3 // exact volume, from the B-rep — not from the mesh
result.positions // Float32Array, x/y/z interleaved
result.indices // Uint32Array
const step = await exportSceneStep(bodies) // Uint8Array, millimetresThe same pipeline reads vendor geometry, keeping each solid separate rather than fusing it:
import { importStepScene, exportSceneStl } from '@indispec/cad-kernel'
const imported = await importStepScene(stepBytes, { name: 'vendor-part.step' })
const stl = exportSceneStl(bodies)What you get
| Export | Purpose |
|---|---|
| initKernel() | Load the OCCT wasm once per process; idempotent |
| translateScene(scene) / translateNode(node) | Recorded node → exact OCCT shape (mm) |
| evaluateBodies(bodies, tessellation?) | Per-body volume/area/bounds, open-edge count, timings, display meshes |
| measureBodies(bodies) | Metrics only, no tessellation |
| importStepBodies(bytes) / importStepScene(bytes) | STEP read, one body per solid, units normalised to mm |
| exportSceneStep(bodies) / exportSceneStl(bodies) | STEP / binary STL export |
| composeAssembly(placement) / transformBounds | Assembly placement maths (no OCCT) |
| buildDemMesh / buildPipeRun | Terrain height-grid mesh and pipe-run mesh helpers |
| leafVolumeMm3 / collectLeaves / nodeSignature | Closed-form leaf volumes and stable scene signatures |
| KernelError, DEFAULT_TESSELLATION, kernelVersion() | Typed errors, tessellation defaults, provenance string |
Bodies are never fused, so names and body counts survive. Volumes/areas/bounds come from the exact B-rep; the mesh is a display and export artifact.
Browser host (module Worker)
@indispec/cad-kernel/browser is a separate subpath. The default "." export is Node-only.
// cad-worker.ts — inside a module Worker
import wasmUrl from 'replicad-opencascadejs/wasm?url'
import { initBrowserKernel, evaluateBrowser } from '@indispec/cad-kernel/browser'
await initBrowserKernel({ wasmUrl })
const result = await evaluateBrowser({ source, includes, tessellation })
// typed arrays — transfer them, do not copy
postMessage(result, [result.positions.buffer, result.indices.buffer])It runs only inside a module Worker; the main thread must reach it through messages. No Node
built-ins are imported anywhere under src/browser/, so bundlers can ship it as-is. The wasm URL is
yours to provide — if your package manager does not hoist dependencies (pnpm), add
replicad-opencascadejs to your own dependencies so your bundler can resolve it.
Licensing
The wrapper code in this package is MIT (see LICENSE).
The wasm is not. replicad-opencascadejs is a build of OpenCascade LGPL-2.1-only; OCCT
itself is LGPL-2.1 plus the OCCT exception; replicad (the JavaScript wrapper) is MIT.
This package keeps that wasm as a separate file loaded by URL and never inlined — the deployment shape LGPL-2.1 §6 is designed around. Concretely, that means:
- running the kernel on your servers is not distribution, and carries no obligations;
- the moment you ship the wasm to users — a browser bundle, a desktop installer, an on-prem image — §6 applies to you: prominent notice, the licence and OCCT copyright, and one of the source-offer / relinking options;
- do not embed the wasm into an application bundle, and publish the OCCT source and build config when you distribute it.
This is engineering guidance, not legal advice.
Measured performance
Node 22, single-threaded wasm: kernel load ~125–170 ms; a one-body model evaluates in ~120–600 ms including tessellation; STEP round-trip volume delta 1e-11–2.4e-6 relative. STEP import on a real 45 MB vendor assembly: 13 solids, 546k triangles, ~17 s read + ~22 s tessellate in Node; part-scale STEP files resolve in well under a second.
Not here yet
STEP product names/colours/assembly structure, booleans against imported bodies as recorded operations, drawings/HLR, the analysis/CFD package, and a validity certificate as a first-class export gate.
Provenance
Extracted from the IndiSpec monorepo, where it is the kernel of record for CAD documents. It is
designed to consume the recorded scene produced by
@indispec/fs-compat, but that is the only
IndiSpec dependency: nothing downstream needs the recorded node classes.
FeatureScript and Onshape are trademarks of PTC Inc. This project is not affiliated with or endorsed by PTC.
