npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

occt-kernel-wasm

v1.0.0

Published

Reusable OCCT-based CAD kernel for WebAssembly with a small TypeScript API for exact solid modelling

Readme

occt-kernel-wasm

Reusable OCCT-based CAD kernel for WebAssembly with a small TypeScript API for exact solid modeling.

CI


Purpose

occt-kernel-wasm is a narrow, high-level WebAssembly adapter for Open CASCADE Technology (OCCT). It exposes a stable, domain-oriented TypeScript API for exact solid modelling in browser and Node.js environments — without leaking any OCCT types into JavaScript.

It is designed to be consumed by modelling applications focused on SolidWorks-like sketching and feature workflows.


Scope (v1)

| Feature | Status | |-------------------------------|--------| | Box / Cylinder / Sphere | ✅ | | Sketch extrusion | ✅ | | Sketch revolution | ✅ | | Sketch sweep / loft | ✅ | | Boolean union / subtract / intersect | ✅ | | Fillet / chamfer | ✅ | | Structured native blend specs | ✅ | | Structured sketch feature specs | ✅ | | Exact edge/face interrogation | ✅ | | Exact analysis + point containment | ✅ | | Topology query (solids/shells/wires/faces/edges/vertices/bbox) | ✅ | | Validity check | ✅ | | Tessellation for WebGL | ✅ | | STEP import | ✅ | | STEP export | ✅ | | Version + session metadata | ✅ | | Structured error objects | ✅ | | Browser + Node.js support | ✅ |


Install

npm install occt-kernel-wasm

Note: The npm package ships with a pre-compiled WASM binary. If you need to rebuild against a different OCCT version, see Building from source.


API

import { createKernel } from 'occt-kernel-wasm';

const kernel = await createKernel();

All shapes are represented by opaque ShapeHandle objects ({ id: number, sessionId: string }). Resident handles are valid only inside the kernel session that created them; passing a handle to a different kernel instance throws SESSION_MISMATCH. No OCCT types are ever exposed.

Primitives

const box = kernel.createBox({ dx: 100, dy: 50, dz: 25 });
const cyl = kernel.createCylinder({ radius: 15, height: 40 });
const sph = kernel.createSphere({ radius: 20 });

Sketch-based features

const profile = {
    outer: {
        segments: [
            { type: 'line', start: [0, 0], end: [20, 0] },
            { type: 'line', start: [20, 0], end: [20, 10] },
            { type: 'line', start: [20, 10], end: [0, 10] },
            { type: 'line', start: [0, 10], end: [0, 0] },
        ],
    },
    holes: [{
        segments: [
            { type: 'line', start: [6, 3], end: [14, 3] },
            { type: 'line', start: [14, 3], end: [14, 7] },
            { type: 'line', start: [14, 7], end: [6, 7] },
            { type: 'line', start: [6, 7], end: [6, 3] },
        ],
    }],
};

const extruded = kernel.extrudeProfile({
    profile,
    plane: {
        origin: [0, 0, 10],
        normal: [0, 1, 0],
        xDirection: [1, 0, 0],
    },
    height: 15,
});

const revolved = kernel.revolveProfile({
    profile,
    axisOrigin: [0, 0, 0],
    axisDirection: [0, 0, 1],
    angleDegrees: 360,
});

const moved = kernel.transformShape({
    shape: extruded,
    transform: {
        rotation: {
            axisOrigin: [0, 0, 0],
            axisDirection: [0, 0, 1],
            angleDegrees: 30,
        },
        translation: [25, 0, 0],
    },
});

Legacy single-wire profiles using { segments: [...] } are still supported. extrudeProfile accepts either height or an explicit world-space vector.

Arc segments:

{ type: 'arc', start: [10, 0], mid: [15, 5], end: [10, 10] }

Circle segments:

{ type: 'circle', centre: [0, 0], radius: 5 }

Bezier segments:

{ type: 'bezier', controlPoints: [[0, 0], [4, 6], [8, 6], [12, 0]] }

B-spline segments (non-rational, non-periodic):

{
    type: 'bspline',
    controlPoints: [[0, 0], [3, 4], [7, 4], [10, 0]],
    degree: 3,
    knots: [0, 1],
    multiplicities: [4, 4],
}

Structured sketch feature specs

The last three feature commits added versioned CAD-style feature APIs on top of the legacy sketch helpers. Use these methods when you need exact OCCT feature behavior, richer end conditions, native feature lineage, and machine-readable capability discovery through getCapabilities() / getOperationSchema().

Structured profile extrude and extrude cut:

const base = kernel.createBox({ dx: 80, dy: 60, dz: 20 });

const bossProfile = {
    segments: [
        { type: 'line', start: [0, 0], end: [24, 0] },
        { type: 'line', start: [24, 0], end: [24, 18] },
        { type: 'line', start: [24, 18], end: [0, 18] },
        { type: 'line', start: [0, 18], end: [0, 0] },
    ],
};

const boss = kernel.extrudeProfileWithSpec({
    shape: base,
    profile: bossProfile,
    spec: {
        schemaVersion: 1,
        plane: {
            origin: [20, 20, 20],
            normal: [0, 0, 1],
            xDirection: [1, 0, 0],
        },
        draftAngleDegrees: 2,
        extent: {
            type: 'blind',
            distance: 16,
        },
    },
});

const topFace = kernel.getTopology(boss).faces?.[0];

const pocket = kernel.extrudeCutProfileWithSpec({
    shape: boss,
    profile: {
        segments: [
            { type: 'line', start: [4, 4], end: [20, 4] },
            { type: 'line', start: [20, 4], end: [20, 14] },
            { type: 'line', start: [20, 14], end: [4, 14] },
            { type: 'line', start: [4, 14], end: [4, 4] },
        ],
    },
    spec: {
        schemaVersion: 1,
        plane: {
            origin: [20, 20, 20],
            normal: [0, 0, 1],
            xDirection: [1, 0, 0],
        },
        extent: {
            type: 'offsetFromSurface',
            surface: { face: { topoId: topFace?.id ?? 1 } },
            offset: 3,
        },
    },
});

extrudeProfileWithSpec supports draft plus blind, upToNext, throughAll, upToSurface, and offsetFromSurface end conditions. The subtractive path is exposed as extrudeCutProfileWithSpec.

Structured profile revolve and revolve cut:

const revolveResult = kernel.revolveProfileWithSpec({
    shape: base,
    profile: {
        segments: [
            { type: 'line', start: [0, 0], end: [8, 0] },
            { type: 'line', start: [8, 0], end: [8, 14] },
            { type: 'line', start: [8, 14], end: [0, 14] },
            { type: 'line', start: [0, 14], end: [0, 0] },
        ],
    },
    spec: {
        schemaVersion: 1,
        plane: {
            origin: [0, 30, 0],
            normal: [0, -1, 0],
            xDirection: [1, 0, 0],
        },
        axisOrigin: [0, 30, 0],
        axisDirection: [0, 0, 1],
        extent: {
            type: 'angle',
            angleDegrees: 225,
        },
    },
});

const revolveCut = kernel.revolveProfileWithSpec({
    shape: revolveResult,
    cut: true,
    profile: {
        segments: [
            { type: 'line', start: [0, 2], end: [5, 2] },
            { type: 'line', start: [5, 2], end: [5, 10] },
            { type: 'line', start: [5, 10], end: [0, 10] },
            { type: 'line', start: [0, 10], end: [0, 2] },
        ],
    },
    spec: {
        schemaVersion: 1,
        plane: {
            origin: [0, 30, 0],
            normal: [0, -1, 0],
            xDirection: [1, 0, 0],
        },
        axisOrigin: [0, 30, 0],
        axisDirection: [0, 0, 1],
        extent: {
            type: 'throughAll',
        },
    },
});

revolveProfileWithSpec supports additive and subtractive revolve through cut?: boolean, plus angle, upToSurface, fromSurfaceToSurface, throughAll, and upToSurfaceAtAngle extents. If you prefer separate calls, revolveCutProfileWithSpec remains available too.

Structured sweep and loft:

const path = {
    segments: [
        { type: 'line', start: [40, 30, 20], end: [40, 30, 50] },
    ],
};

const sweep = kernel.sweepProfileWithSpec({
    shape: pocket,
    profile: {
        segments: [
            { type: 'line', start: [-4, -4], end: [4, -4] },
            { type: 'line', start: [4, -4], end: [4, 4] },
            { type: 'line', start: [4, 4], end: [-4, 4] },
            { type: 'line', start: [-4, 4], end: [-4, -4] },
        ],
    },
    spec: {
        schemaVersion: 1,
        plane: {
            origin: [40, 30, 20],
            normal: [0, 0, 1],
            xDirection: [1, 0, 0],
        },
        spine: path,
        trihedronMode: { type: 'discrete' },
        sectionWithCorrection: true,
        solid: true,
        transitionMode: 'roundCorner',
    },
});

const loft = kernel.loftWithSpec({
    shape: sweep,
    sections: [
        {
            type: 'profile',
            profile: {
                segments: [
                    { type: 'line', start: [-6, -6], end: [6, -6] },
                    { type: 'line', start: [6, -6], end: [6, 6] },
                    { type: 'line', start: [6, 6], end: [-6, 6] },
                    { type: 'line', start: [-6, 6], end: [-6, -6] },
                ],
            },
            plane: {
                origin: [60, 20, 20],
                normal: [0, 0, 1],
                xDirection: [1, 0, 0],
            },
        },
        {
            type: 'wire',
            wire: {
                segments: [
                    { type: 'line', start: [56, 16, 34], end: [64, 16, 34] },
                    { type: 'line', start: [64, 16, 34], end: [64, 24, 34] },
                    { type: 'line', start: [64, 24, 34], end: [56, 24, 34] },
                    { type: 'line', start: [56, 24, 34], end: [56, 16, 34] },
                ],
            },
        },
        {
            type: 'point',
            point: [60, 20, 46],
        },
    ],
    spec: {
        schemaVersion: 1,
        solid: true,
        smoothing: true,
        parametrization: 'centripetal',
        continuity: 'C1',
    },
});

const loftCut = kernel.loftWithSpec({
    shape: loft,
    cut: true,
    sections: [
        {
            type: 'profile',
            profile: {
                segments: [
                    { type: 'line', start: [-5, -5], end: [5, -5] },
                    { type: 'line', start: [5, -5], end: [5, 5] },
                    { type: 'line', start: [5, 5], end: [-5, 5] },
                    { type: 'line', start: [-5, 5], end: [-5, -5] },
                ],
            },
            plane: {
                origin: [15, 15, -1],
                normal: [0, 0, 1],
                xDirection: [1, 0, 0],
            },
        },
        {
            type: 'profile',
            profile: {
                segments: [
                    { type: 'line', start: [-3, -3], end: [3, -3] },
                    { type: 'line', start: [3, -3], end: [3, 3] },
                    { type: 'line', start: [3, 3], end: [-3, 3] },
                    { type: 'line', start: [-3, 3], end: [-3, -3] },
                ],
            },
            plane: {
                origin: [15, 15, 21],
                normal: [0, 0, 1],
                xDirection: [1, 0, 0],
            },
        },
    ],
    spec: {
        schemaVersion: 1,
        solid: true,
        ruled: true,
    },
});

sweepProfileWithSpec uses cut?: boolean for additive vs subtractive sweep and supports spine wires, trihedron modes, solid output, transition modes, tolerances, and continuity controls. loftWithSpec accepts profile, wire, and point sections plus cut?: boolean; profile sections must be single-wire closed loops, matching the native OCCT builder restriction enforced by the wrapper.

Boolean operations

const united    = kernel.booleanUnion({ base: box, tool: cyl });
const cut       = kernel.booleanSubtract({ base: box, tool: cyl });
const intersect = kernel.booleanIntersect({ base: box, tool: cyl });

Modifiers

const filleted = kernel.filletEdges({ shape: box, radius: 2 });
const chamfered = kernel.chamferEdges({ shape: box, distance: 1.5 });

Simple modifiers keep their original all-edge behavior. For feature-level CAD workflows, use the structured native blend APIs so OCCT owns exact blend construction and the JS layer receives lineage metadata instead of rebuilding blends from mesh edges.

const topo = kernel.getTopology(box);
const edge = topo.edges?.[0];
const referenceFace = edge?.topoFaceIds?.[0];

const filletResult = kernel.filletEdgesWithSpec({
    shape: box,
    spec: {
        schemaVersion: 1,
        edges: [{ topoId: edge?.id ?? 1, radius: 2 }],
        blendShape: 'rational',
        continuity: 'C1',
        overflowMode: 'fail',
    },
});

const chamferResult = kernel.chamferEdgesWithSpec({
    shape: box,
    spec: {
        schemaVersion: 1,
        mode: 'twoDistance',
        edges: [{
            topoId: edge?.id ?? 1,
            distance1: 1,
            distance2: 2,
            referenceFace: { topoId: referenceFace ?? 1 },
        }],
    },
});

const nextShape = filletResult.shape;
const generatedBlendFaces = filletResult.blendFaces;

Fillets support constant radius, start/end radius, station radii, constant and linear radius laws, OCCT fillet shape modes (rational, quasiAngular, polynomial), and C0/C1/C2 continuity. Chamfers support symmetric, two-distance, and distance-angle modes with reference-face side selection. Tangent propagation is native and enabled. Partial-edge blends, disabled tangent propagation, and setback-style corner handling are reported as structured unsupported INVALID_PARAMS errors in this OCCT-backed build.

Exact subshape evaluation

const edgeEval = kernel.evaluateEdge({
    shape: box,
    edge: { topoId: 1 },
    t: 0.5,
});

const edgeSamples = kernel.sampleEdge({
    shape: box,
    edge: { topoId: 1 },
    count: 16,
});

const edgeCurve = kernel.getEdgeCurve({ shape: box, edge: { topoId: 1 } });

const faceEval = kernel.evaluateFace({
    shape: box,
    face: { topoId: 1 },
    u: 0.5,
    v: 0.5,
});

Edge and face references accept a runtime topoId or a stableHash. Edge and face evaluation use normalized parameters by default; pass parameterMode: 'native' on the reference to use the OCCT curve or surface parameter domain directly. getEdgeCurve returns analytic line/circle metadata where available and Bezier/B-spline poles, weights, knots, and multiplicities for exact curve types.

Topology query

const topo = kernel.getTopology(box);
// {
//   revisionId: 'rev_...', topologyHash: 'T:...', historySchemaVersion: 1,
//   operationId: 'op_...', operationType: 'createBox', operandRevisionIds: [],
//   identityStatus: 'generated', historyWarnings: [],
//   shapeType: 'solid', solidCount: 1, shellCount: 1, wireCount: 6,
//   faceCount: 6, edgeCount: 12, vertexCount: 8,
//   boundingBox: { xMin: 0, yMin: 0, zMin: 0, xMax: 100, yMax: 50, zMax: 25 },
//   isValid: true,
//   solids: [{ id: 1, shellIds: [1], status: 'generated' }],
//   shells: [{ id: 1, solidIds: [1], faceIds: [1, 2, 3, 4, 5, 6], status: 'generated' }],
//   wires: [{ id: 1, edgeIds: [1, 2, 3, 4], topoFaceIds: [1], status: 'generated' }],
//   faces: [{ id: 1, stableHash: 'F:...', status: 'generated' }],
//   edges: [{ id: 1, stableHash: 'E:...', topoFaceIds: [1, 2], status: 'generated' }],
//   vertices: [{ id: 1, stableHash: 'V:...', status: 'generated' }],
//   deletedEntities: []
// }

const capabilities = kernel.getCapabilities();
// featureEdgesV1, topologyHierarchyV1, versionInfoV1, analysisV1,
// sessionHandlesV1, triangleNormalsV1, topologySubshapesV1, historyV1,
// entityRemapV1, revisionRetentionV1, checkpointV1, and native exact blend
// operations are available. capabilities.analysis and capabilities.runtime
// describe exact mass/containment support and browser/worker/node coverage.
// capabilities.fillet / capabilities.chamfer describe supported modes and
// explicitly false unsupported modes.
// stableNamingV1 is true: semantic face/edge/vertex ids are materialized per
// revision and propagated through exact transform, boolean, and blend history
// instead of falling back to geometry-derived hashes.

const schema = kernel.getOperationSchema();
// Versioned machine-readable operation contracts for structured extrude,
// revolve, sweep, loft, fillet, chamfer, getVersionInfo, analyzeShape,
// classifyPointContainment, intersectShapes, findClosestPointOnShape,
// measureShapeDistance, evaluateEdge, sampleEdge, getEdgeCurve, and
// evaluateFace.

Version metadata and exact analysis

const version = kernel.getVersionInfo();
// {
//   libraryVersion: '1.0.0',
//   apiVersion: 1,
//   kernelVersion: '8.0.0',
//   checkpointSchemaVersion: 1,
//   operationSchemaVersion: 1,
//   sessionId: 'session_...',
//   supportedRuntimes: ['browser', 'worker', 'node']
// }

const analysis = kernel.analyzeShape({ shape: box });
// {
//   shapeType: 'solid',
//   solidCount: 1,
//   shellCount: 1,
//   wireCount: 6,
//   faceCount: 6,
//   edgeCount: 12,
//   vertexCount: 8,
//   boundingBox: { xMin: 0, yMin: 0, zMin: 0, xMax: 100, yMax: 50, zMax: 25 },
//   isValid: true,
//   volume: 125000,
//   surfaceArea: 25000,
//   linearLength: 700,
//   centerOfMass: [50, 25, 12.5],
//   centerOfMassBasis: 'volume'
// }

const inside = kernel.classifyPointContainment({
    shape: box,
    point: [50, 25, 12.5],
});
// { point: [50, 25, 12.5], tolerance: 1e-7, state: 'in', isInside: true }

const closest = kernel.findClosestPointOnShape({
    shape: box,
    point: [140, 25, 12.5],
});
// {
//   queryPoint: [140, 25, 12.5],
//   closestPoint: [100, 25, 12.5],
//   distance: 40,
//   support: { kind: 'face', topoId: 2, stableHash: 'F:...' }
// }

const moved = kernel.transformShape({
    shape: box,
    transform: { translation: [140, 0, 0] },
});

const clearance = kernel.measureShapeDistance({
    shapeA: box,
    shapeB: moved,
});
// {
//   distance: 40,
//   clearance: 40,
//   isInContact: false,
//   solutions: [{ pointOnA: [100, 25, 12.5], pointOnB: [140, 25, 12.5], ... }]
// }

const overlap = kernel.transformShape({
    shape: box,
    transform: { translation: [50, 10, 0] },
});

const section = kernel.intersectShapes({ shapeA: box, shapeB: overlap });
// { hasIntersection: true, edgeCount: 4, vertexCount: 4, sectionShape: { id: ..., sessionId: ... } }

Revision history, remap, and checkpoints

const revision = kernel.getRevisionInfo(box);

const moved = kernel.transformShape({
    shape: box,
    transform: { translation: [25, 0, 0] },
});

const firstFaceHash = topo.faces?.[0]?.stableHash ?? '';
const resolved = kernel.resolveStableEntity({ shape: moved, stableHash: firstFaceHash });
const remap = kernel.mapEntitiesAcrossRevisions({
    fromRevisionId: revision.revisionId,
    toRevisionId: kernel.getRevisionInfo(moved).revisionId,
    stableHashes: [firstFaceHash],
});

const checkpoint = kernel.createCheckpoint({ shape: moved });
const restored = kernel.hydrateCheckpoint({ checkpoint });

kernel.retainRevision({ shape: restored });
kernel.releaseRevision({ shape: restored });

Tessellation

const mesh = kernel.tessellate({ shape: box, linearDeflection: 0.1 });
// {
//   positions: Float32Array,  // [x0,y0,z0, x1,y1,z1, ...]
//   normals:   Float32Array,  // [nx0,ny0,nz0, ...]
//   indices:   Uint32Array,   // [i0,i1,i2, ...] triangles
//   triangleNormals?: Float32Array,
//   triangleTopoFaceIds?: Uint32Array,
//   triangleFaceGroups?: Uint32Array,
//   triangleStableHashes?: string[],
//   featureEdges?: [{
//     points: [[x, y, z], [x, y, z]],
//     isClosed: false,
//     chainId: 1,
//     faceIndices: [1, 2],
//     topoFaceIds: [1, 2],
//     isBoundary: false,
//     isSharp: true,
//     isSeam: false,
//     stableHash: 'E:...'
//   }],
//   rawEdgeSegments?: Float32Array // debug only; do not use for selection
// }

Pass directly to Three.js BufferGeometry:

const geometry = new THREE.BufferGeometry();
geometry.setAttribute('position', new THREE.BufferAttribute(mesh.positions, 3));
geometry.setAttribute('normal',   new THREE.BufferAttribute(mesh.normals, 3));
geometry.setIndex(new THREE.BufferAttribute(mesh.indices, 1));

Import / export (STEP)

// Export
const stepContent = kernel.exportStep({ shape: box });

// Import
const imported = kernel.importStep({ content: stepContent });

// Structured import diagnostics
const detailedImport = kernel.importStepDetailed({
    content: stepContent,
    options: {
        heal: true,
        sew: true,
        fixSameParameter: true,
    },
});

if (!detailedImport.shape) {
    console.error(detailedImport.readStatus, detailedImport.transferStatus);
    console.table(detailedImport.messageList);
}

Memory management

Always dispose shapes when they are no longer needed:

kernel.disposeShape({ shape: box });

Error handling

All operations throw a KernelError on failure:

import { KernelError } from 'occt-kernel-wasm';

try {
    const box = kernel.createBox({ dx: -1, dy: 1, dz: 1 });
} catch (err) {
    if (err instanceof KernelError) {
        console.error(err.code);   // 'INVALID_PARAMS'
        console.error(err.detail); // 'dx must be > 0'
    }
}

Error codes: INVALID_HANDLE | INVALID_PARAMS | OPERATION_FAILED | IMPORT_FAILED | EXPORT_FAILED | NOT_INITIALIZED | UNKNOWN


Browser Usage

<script type="module">
    import { createKernel } from './dist/index.mjs';

    const kernel = await createKernel();

    const box = kernel.createBox({ dx: 10, dy: 10, dz: 10 });
    const mesh = kernel.tessellate({ shape: box });
    // Use mesh.positions, mesh.normals, mesh.indices with WebGL/Three.js
    kernel.disposeShape({ shape: box });
</script>

CDN example:

<script type="module">
    import { createKernel } from 'https://cdn.jsdelivr.net/npm/occt-kernel-wasm@VERSION/dist/index.mjs';

    const kernel = await createKernel();
    const box = kernel.createBox({ dx: 10, dy: 10, dz: 10 });
    console.log(kernel.getTopology(box));
    kernel.disposeShape({ shape: box });
</script>

See examples/browser/index.html for a complete demo.


Node.js Usage

const { createKernel } = require('occt-kernel-wasm');

async function main() {
    const kernel = await createKernel();

    const box = kernel.createBox({ dx: 10, dy: 10, dz: 10 });
    const step = kernel.exportStep({ shape: box });
    kernel.disposeShape({ shape: box });
    console.log(step);
}
main();

See examples/nodejs/demo.js for a complete demo.


Building from source

Prerequisites

| Tool | Version | Purpose | |------------|---------|------------------------| | Node.js | ≥ 18 | TypeScript / tests | | CMake | ≥ 3.20 | Build system | | Emscripten | ≥ 3.1 | C++ → WASM | | OCCT | 8.0.x | CAD kernel |

Steps

# 1. Install Node.js dependencies
npm install

# 2. Build OCCT for Emscripten (dispatches to PowerShell on Windows)
npm run build:occt

# 3. Build the WASM module
npm run build:wasm

# 4. Build the publishable dist/
npm run build

On Windows, npm run build:occt and npm run build:wasm use the PowerShell wrappers in scripts/ so the local Emscripten .bat entrypoints are used directly.

The OCCT build scripts pin V8_0_0 and keep the V8 source, build, and install trees in a versioned local cache outside the workspace by default. On Windows that defaults to %LOCALAPPDATA%\occt-kernel-wasm\V8_0_0; on Unix-like systems it defaults to $XDG_CACHE_HOME/occt-kernel-wasm/V8_0_0 or ~/.cache/occt-kernel-wasm/V8_0_0. Set OCCT_WASM_CACHE_ROOT to override that location.

If the existing third-party/occt-src checkout has local changes, the build preserves it and uses the cached V8 checkout instead of overwriting that tree.

For faster local iteration, use npm run build:wasm:fast. That uses a separate Fast CMake build with low optimization and no debug source maps, and the wrapper scripts reuse the existing CMake configure unless you explicitly request a reconfigure.

Output: dist/occt-kernel.js, dist/occt-kernel.wasm, dist/index.js, dist/index.mjs, dist/index.d.ts


Testing

npm test            # all tests
npm run test:watch  # watch mode
npm run test:coverage

Tests run entirely in Node.js using the mock adapter — no WASM binary required.


Limitations

  • Full raw OCCT API bindings are intentionally not exposed.
  • Sketch constraint solving is not included.
  • Parametric feature trees are not included.
  • Assembly modelling is not in scope for v1.
  • STEP import requires the WASM binary (not available in the mock adapter for production use).

Architecture

See ARCHITECTURE.md for the full layer diagram, design decisions, and extension guide.


License

MIT — see LICENSE.

OCCT is distributed under LGPL-2.1 with an exception. See NOTICE and THIRD_PARTY_LICENSES.md for details.