occt-wasm 3.2.2 → 3.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/README.md +410 -0
  2. package/package.json +2 -1
package/README.md ADDED
@@ -0,0 +1,410 @@
1
+ <div align="center">
2
+
3
+ # occt-wasm
4
+
5
+ [![npm](https://img.shields.io/npm/v/occt-wasm)](https://www.npmjs.com/package/occt-wasm)
6
+ [![Crates.io](https://img.shields.io/crates/v/occt-wasm.svg)](https://crates.io/crates/occt-wasm)
7
+ [![CI](https://github.com/andymai/occt-wasm/actions/workflows/ci.yml/badge.svg)](https://github.com/andymai/occt-wasm/actions/workflows/ci.yml)
8
+ [![Last release](https://img.shields.io/github/release-date/andymai/occt-wasm?label=last%20release)](https://github.com/andymai/occt-wasm/releases)
9
+ [![Commit activity](https://img.shields.io/github/commit-activity/m/andymai/occt-wasm?label=commits%2Fmonth)](https://github.com/andymai/occt-wasm/commits/main)
10
+ [![License](https://img.shields.io/badge/tooling-MIT%20OR%20Apache--2.0-blue.svg)](#license) [![WASM License](https://img.shields.io/badge/wasm%20output-LGPL--2.1--only-blue.svg)](#license)
11
+
12
+ [OpenCascade](https://github.com/Open-Cascade-SAS/OCCT) V8 compiled to WebAssembly with a clean TypeScript API.
13
+
14
+ Smaller bundles, branded types, arena-based memory, and modern tooling.
15
+
16
+ </div>
17
+
18
+ > **Looking for a higher-level CAD library?** [brepjs](https://github.com/andymai/brepjs) builds on occt-wasm with a friendlier API for parametric modeling, sketching, and production CAD applications. Use occt-wasm directly when you need full control over OCCT operations.
19
+
20
+ ## Highlights
21
+
22
+ - **~4.5 MB brotli** -- roughly 2x smaller than opencascade.js
23
+ - **Comprehensive API** -- primitives, booleans, sweeps, XCAF assemblies, curves, surfaces, STEP/STL/glTF/BREP I/O, topology, shape evolution tracking
24
+ - **Arena-based API** -- u32 shape handles, no manual `.delete()`, `Symbol.dispose` support
25
+ - **TypeScript-first** -- branded `ShapeHandle`, union types for shapes/surfaces/curves, structured returns
26
+ - **Structured error handling** -- `OcctErrorCode` enum for programmatic `switch/case` instead of string parsing
27
+ - **Web Worker support** -- `OcctWorker` class for off-main-thread CAD operations via [Comlink](https://github.com/GoogleChromeLabs/comlink)
28
+ - **Modern browser targets** -- WASM SIMD, relaxed-SIMD, tail calls, wasm-exceptions
29
+
30
+ ## Scope
31
+
32
+ To set expectations, this library deliberately does not:
33
+
34
+ - **Provide a higher-level CAD modeling API** — parametric sketching, constraints, feature trees, and ergonomic modeling belong in [brepjs](https://github.com/andymai/brepjs), which wraps occt-wasm for that purpose
35
+ - **Manage memory automatically beyond arena handles** — shapes are freed when the kernel is disposed or you call `release()`; there is no per-shape garbage collection
36
+ - **Support Firefox or other non-WASM-SIMD browsers** — the build requires WASM SIMD, relaxed-SIMD, tail calls, and wasm exceptions; Firefox lacks tail call support as of v130
37
+ - **Include OCCT visualization or display modules** — TKV3d, TKHLR (except the HLR facade), and the AIS interactive context are excluded; bring your own renderer (Three.js, Babylon.js, etc.)
38
+ - **Support IGES import/export** -- TKDEIGES is excluded from the link; use STEP for interchange
39
+
40
+ ## Install
41
+
42
+ ```bash
43
+ npm install occt-wasm
44
+ ```
45
+
46
+ ## Quick Start
47
+
48
+ ```typescript
49
+ import { OcctKernel } from "occt-wasm";
50
+
51
+ // Recommended: deterministic cleanup via Symbol.dispose
52
+ {
53
+ using kernel = await OcctKernel.init();
54
+
55
+ // Primitives
56
+ const box = kernel.makeBox(20, 20, 20);
57
+ const cyl = kernel.makeCylinder(8, 30);
58
+
59
+ // Booleans
60
+ const fused = kernel.fuse(box, cyl);
61
+
62
+ // Modeling
63
+ const edges = kernel.getSubShapes(fused, "edge");
64
+ const filleted = kernel.fillet(fused, edges.slice(0, 4), 2.0);
65
+
66
+ // Tessellation -> Three.js / Babylon.js
67
+ const mesh = kernel.tessellate(filleted);
68
+ // mesh.positions (Float32Array), mesh.normals, mesh.indices
69
+
70
+ // STEP I/O
71
+ const step = kernel.exportStep(filleted);
72
+ const reimported = kernel.importStep(step);
73
+
74
+ // Query
75
+ const vol = kernel.getVolume(filleted);
76
+ const bbox = kernel.getBoundingBox(filleted);
77
+ const com = kernel.getCenterOfMass(filleted);
78
+
79
+ // kernel is disposed at end of block
80
+ }
81
+ ```
82
+
83
+ ## Rust Crate
84
+
85
+ The same OCCT WASM is available as a [Rust crate](https://crates.io/crates/occt-wasm) for native targets (servers, CLIs, build scripts) — no C++ toolchain required:
86
+
87
+ ```toml
88
+ [dependencies]
89
+ occt-wasm = "3"
90
+ ```
91
+
92
+ ```rust
93
+ use occt_wasm::OcctKernel;
94
+
95
+ let mut kernel = OcctKernel::new()?;
96
+ let box_shape = kernel.make_box(10.0, 20.0, 30.0)?;
97
+ let sphere = kernel.make_sphere(8.0)?;
98
+ let fused = kernel.fuse(box_shape, sphere)?;
99
+ let mesh = kernel.tessellate(fused, 0.1, 0.5)?;
100
+ let step = kernel.export_step(fused)?;
101
+ ```
102
+
103
+ The crate embeds a brotli-compressed WASM binary (~4.7 MB) and runs it via [wasmtime](https://wasmtime.dev/). Same 170+ facade methods as the TS API. See [`crate/README.md`](./crate/README.md) and [docs.rs/occt-wasm](https://docs.rs/occt-wasm) for full details.
104
+
105
+ ## Initialization
106
+
107
+ By default, `OcctKernel.init()` auto-locates the `.wasm` file next to the JS module. You can also provide explicit paths or pre-loaded binaries:
108
+
109
+ ```typescript
110
+ // Auto-detect (browser, Node.js, or Worker):
111
+ const kernel = await OcctKernel.init();
112
+
113
+ // Explicit URL or path:
114
+ const kernel = await OcctKernel.init({ wasm: "/assets/occt-wasm.wasm" });
115
+
116
+ // Pre-fetched binary (skip the fetch):
117
+ const binary = await fetch("/occt-wasm.wasm").then((r) => r.arrayBuffer());
118
+ const kernel = await OcctKernel.init({ wasm: binary });
119
+
120
+ // Uint8Array also accepted:
121
+ const kernel = await OcctKernel.init({ wasm: new Uint8Array(binary) });
122
+ ```
123
+
124
+ ## Error Handling
125
+
126
+ All errors are instances of `OcctError` with a structured `code` field for programmatic handling:
127
+
128
+ ```typescript
129
+ import { OcctError, OcctErrorCode } from "occt-wasm";
130
+
131
+ try {
132
+ kernel.fuse(a, b);
133
+ } catch (e) {
134
+ if (e instanceof OcctError) {
135
+ switch (e.code) {
136
+ case OcctErrorCode.BooleanFailed:
137
+ // retry with simpler geometry
138
+ break;
139
+ case OcctErrorCode.InvalidShapeId:
140
+ // shape was already released
141
+ break;
142
+ case OcctErrorCode.KernelError:
143
+ // OCCT internal error (Standard_Failure)
144
+ console.error(e.message);
145
+ break;
146
+ }
147
+ }
148
+ }
149
+ ```
150
+
151
+ Available error codes:
152
+
153
+ | Code | When |
154
+ | -------------------- | ----------------------------------------------- |
155
+ | `ConstructionFailed` | `Build()`/`IsDone()` returned false |
156
+ | `BooleanFailed` | Boolean operation (fuse/cut/common/etc.) failed |
157
+ | `InvalidShapeId` | Shape ID not found in the arena |
158
+ | `InvalidLabelId` | XCAF label ID not found |
159
+ | `TessellationFailed` | Meshing operation failed |
160
+ | `ImportExportFailed` | STEP/STL/BREP I/O error |
161
+ | `HealingFailed` | Shape repair failed |
162
+ | `DocumentClosed` | Operation on a closed XCAF document |
163
+ | `KernelError` | OCCT `Standard_Failure` (unclassified) |
164
+ | `Unknown` | Error from outside the kernel |
165
+
166
+ ## Named Enums
167
+
168
+ Sweep, offset, and boolean operations use self-documenting enums instead of opaque numbers:
169
+
170
+ ```typescript
171
+ import { TransitionMode, JoinType, BooleanOp } from "occt-wasm";
172
+
173
+ // Sweep with round-corner transitions
174
+ kernel.sweep(profile, spine, TransitionMode.RoundCorner);
175
+
176
+ // Offset wire with arc joins
177
+ kernel.offsetWire2D(wire, 2.0, JoinType.Arc);
178
+
179
+ // Boolean pipeline
180
+ kernel.booleanPipeline(base, [BooleanOp.Cut, BooleanOp.Fuse], [tool1, tool2]);
181
+ ```
182
+
183
+ Numeric values (0, 1, 2) are still accepted for backwards compatibility.
184
+
185
+ ## Type Predicates
186
+
187
+ Convenience methods for checking shape topology:
188
+
189
+ ```typescript
190
+ if (kernel.isSolid(shape)) {
191
+ /* ... */
192
+ }
193
+ if (kernel.isFace(shape)) {
194
+ /* ... */
195
+ }
196
+ if (kernel.isEdge(shape)) {
197
+ /* ... */
198
+ }
199
+ if (kernel.isWire(shape)) {
200
+ /* ... */
201
+ }
202
+ if (kernel.isVertex(shape)) {
203
+ /* ... */
204
+ }
205
+ if (kernel.isShell(shape)) {
206
+ /* ... */
207
+ }
208
+ if (kernel.isCompound(shape)) {
209
+ /* ... */
210
+ }
211
+ ```
212
+
213
+ ## Web Workers
214
+
215
+ For browser apps, heavy CAD operations can block the main thread. `OcctWorker` runs a full kernel in a Web Worker with the same API:
216
+
217
+ ```typescript
218
+ import { OcctWorker } from "occt-wasm/worker";
219
+
220
+ // Spawn a worker with its own kernel
221
+ const worker = await OcctWorker.spawn({ wasm: "/occt-wasm.wasm" });
222
+
223
+ // Same API, every call returns a Promise
224
+ const box = await worker.makeBox(10, 20, 30);
225
+ const cyl = await worker.makeCylinder(5, 40);
226
+ const fused = await worker.fuse(box, cyl);
227
+ const mesh = await worker.tessellate(fused);
228
+ console.log(`${mesh.triangleCount} triangles`);
229
+
230
+ // Access the full kernel via .kernel for less common methods
231
+ const nurbs = await worker.kernel.getNurbsCurveData(edge);
232
+
233
+ // Clean up
234
+ worker.terminate();
235
+ ```
236
+
237
+ The worker helper uses [Comlink](https://github.com/GoogleChromeLabs/comlink) (~1.2 KB gzipped) for transparent RPC. Each worker has its own WASM instance and arena -- shape handles are local to the worker.
238
+
239
+ ## XCAF Assemblies
240
+
241
+ Create assembly documents with colors, names, and component hierarchies:
242
+
243
+ ```typescript
244
+ // Factory method auto-injects Emscripten FS for glTF export
245
+ const doc = kernel.createXCAFDocument();
246
+
247
+ const housing = doc.addShape(box, { name: "housing", color: [0.8, 0.2, 0.1] });
248
+ doc.addChild(housing, gear, {
249
+ name: "gear-1",
250
+ location: { tx: 10, tz: 5 },
251
+ color: [0.5, 0.5, 0.5],
252
+ });
253
+
254
+ // Export
255
+ const step = doc.exportSTEP(); // preserves colors/names
256
+ const glb = doc.exportGLTF(); // no need to pass FS manually
257
+ doc.close();
258
+
259
+ // Import with preserved metadata
260
+ const imported = kernel.importXCAFFromSTEP(stepData);
261
+ ```
262
+
263
+ ## Bundler Configuration
264
+
265
+ ### Vite
266
+
267
+ ```typescript
268
+ // vite.config.ts
269
+ export default defineConfig({
270
+ optimizeDeps: {
271
+ exclude: ["occt-wasm"], // Don't pre-bundle WASM
272
+ },
273
+ build: {
274
+ target: "esnext", // Required for WASM features
275
+ },
276
+ });
277
+ ```
278
+
279
+ ### Webpack 5
280
+
281
+ ```javascript
282
+ // webpack.config.js
283
+ module.exports = {
284
+ experiments: { asyncWebAssembly: true },
285
+ module: {
286
+ rules: [{ test: /\.wasm$/, type: "asset/resource" }],
287
+ },
288
+ };
289
+ ```
290
+
291
+ ### Node.js
292
+
293
+ ```typescript
294
+ // Works out of the box with Node.js 18+
295
+ import { OcctKernel } from "occt-wasm";
296
+ const kernel = await OcctKernel.init();
297
+ ```
298
+
299
+ ## API Reference
300
+
301
+ Generate full docs locally: `cd ts && npm run docs` (TypeDoc output).
302
+
303
+ | Category | What's covered |
304
+ | ---------------- | -------------------------------------------------------------------------------------------------------------- |
305
+ | **Primitives** | Box, cylinder, sphere, cone, torus, ellipsoid, rectangle |
306
+ | **Booleans** | Fuse, cut, common, intersect, section + multi-shape variants |
307
+ | **Modeling** | Extrude, revolve, fillet, chamfer, shell, offset, draft |
308
+ | **Sweeps** | Pipe, loft, sweep, draft prism, extrusion laws |
309
+ | **Construction** | Vertices, edges (line/arc/circle/ellipse/bezier/helix), wires, faces, solids, compounds, sewing |
310
+ | **Transforms** | Translate, rotate, scale, mirror, 3x4 matrix, linear/circular patterns |
311
+ | **Topology** | Shape type queries, type predicates, sub-shape extraction, adjacency, hash codes |
312
+ | **Tessellation** | Triangle meshes, wireframe polylines, per-face groups, batched multi-shape meshing |
313
+ | **I/O** | STEP, STL, BREP import/export |
314
+ | **Query** | Bounding box, volume, surface area, length, center of mass, curvature |
315
+ | **Surfaces** | Type, normal, UV bounds, point classification, B-spline construction |
316
+ | **Curves** | Type, point/tangent evaluation, parameters, NURBS data extraction, interpolation |
317
+ | **Projection** | Hidden line removal (HLR) |
318
+ | **Modifiers** | Thicken, defeature, reverse, simplify, variable fillet, 2D wire offset |
319
+ | **Evolution** | Face-tracking history for translate, fuse, cut, fillet, rotate, mirror, scale, chamfer, shell, offset, thicken |
320
+ | **XCAF** | Assembly documents with colors, names, component hierarchies, STEP/glTF export |
321
+ | **Healing** | Fix shape, unify domain, heal solid/face/wire, fix orientations, remove degenerate edges |
322
+ | **Batch** | Multi-shape translate, chained boolean pipeline |
323
+
324
+ ## Architecture
325
+
326
+ ```
327
+ OCCT V8.0.0 C++ (git submodule)
328
+ -> emcmake cmake (48 static libs)
329
+ -> C++ facade (OcctKernel class, arena-based u32 IDs)
330
+ -> Embind bindings
331
+ -> emcc link (-O3, -flto, -fwasm-exceptions, SIMD) -> .wasm
332
+ -> wasm-opt -O4 --converge --gufa -> dist/ (20.8 MB)
333
+ ```
334
+
335
+ Built with Rust xtask (`cargo xtask build`), tested with Vitest.
336
+
337
+ ## Size & Performance
338
+
339
+ Compared against other OCCT-to-WASM builds (all include STEP, XCAF, glTF):
340
+
341
+ | Build | brotli |
342
+ | ------------------ | ------- |
343
+ | **occt-wasm** | ~4.5 MB |
344
+ | opencascade.js | ~9 MB |
345
+ | brepjs-opencascade | ~5 MB |
346
+
347
+ Run benchmarks locally: `npx tsx test/benchmark.ts`
348
+
349
+ ## Development
350
+
351
+ ### Building from Source
352
+
353
+ ```bash
354
+ # Prerequisites: Rust 1.85+, emsdk 5.0.3
355
+ git clone --recurse-submodules https://github.com/andymai/occt-wasm
356
+ cd occt-wasm
357
+ npm install && cd ts && npm install && cd ..
358
+
359
+ cargo xtask build # Build OCCT + facade -> WASM
360
+ cargo xtask test # Run tests
361
+
362
+ # View the Three.js example
363
+ npx serve .
364
+ # Open http://localhost:3000/examples/three-js/
365
+ ```
366
+
367
+ ### Docker Build
368
+
369
+ No local emsdk or Rust needed -- everything runs in the container.
370
+
371
+ ```bash
372
+ npm run docker:build # Build image (OCCT layer cached after first run)
373
+ npm run docker:dist # Build + copy dist/ artifacts to host
374
+ ```
375
+
376
+ ## Browser Compatibility
377
+
378
+ occt-wasm requires modern browsers with WASM SIMD, relaxed-SIMD, tail calls, and exception handling:
379
+
380
+ | Browser | Minimum Version | Notes |
381
+ | ------- | --------------- | -------------------------------------- |
382
+ | Chrome | 114+ | Relaxed-SIMD (114), tail calls (112) |
383
+ | Edge | 114+ | Same engine as Chrome |
384
+ | Safari | 17.2+ | Relaxed-SIMD (17.2), tail calls (15) |
385
+ | Firefox | Not supported | No tail call support as of Firefox 130 |
386
+
387
+ Node.js 22+ is recommended (tail calls via V8). Node.js 18+ works if your V8 version supports the required WASM features.
388
+
389
+ ## Known Limitations
390
+
391
+ These are upstream OCCT V8.0.0 issues, not occt-wasm bugs:
392
+
393
+ - **IGES** -- TKDEIGES excluded from link; no IGES import/export
394
+ - **Zero-length extrusion** -- WASM exception escapes JS catch boundary (1 test skip)
395
+ - **Single WASM thread** -- each kernel instance is single-threaded; use `OcctWorker` (see above) to move work off the main thread
396
+ - **Firefox** -- not supported due to missing WASM tail call support
397
+
398
+ These will be addressed as upstream OCCT and browser support improve.
399
+
400
+ ## Contributing
401
+
402
+ This project is open source. Bug reports and feature requests are welcome via GitHub Issues. For pull requests, please open an issue first to discuss the change.
403
+
404
+ ## License
405
+
406
+ **Build tooling** (xtask, scripts, TypeScript wrapper): MIT OR Apache-2.0
407
+
408
+ **Compiled WASM output**: LGPL-2.1-only (inherits from [OCCT](https://dev.opencascade.org/resources/download))
409
+
410
+ The LGPL requires that end users can replace the LGPL component. For web applications, this is satisfied by loading the `.wasm` file from a URL (which users can override via `OcctKernel.init({ wasm: '...' })`). If you ship a desktop app with the WASM embedded, consult the [LGPL-2.1 FAQ](https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "occt-wasm",
3
- "version": "3.2.2",
3
+ "version": "3.2.3",
4
4
  "description": "OpenCascade (OCCT) compiled to WebAssembly with a clean TypeScript API",
5
5
  "type": "module",
6
6
  "exports": {
@@ -21,6 +21,7 @@
21
21
  "scripts": {
22
22
  "build": "tsc",
23
23
  "prebuild": "bash scripts/copy-wasm.sh",
24
+ "prepack": "cp ../README.md README.md",
24
25
  "lint": "eslint src/",
25
26
  "typecheck": "tsc --noEmit",
26
27
  "test": "vitest run",