Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
55cc60b
feat: OCCT V8 dual WASM build (single 18.96 MB + exceptions 22.22 MB)
rifont Feb 27, 2026
7fd46ee
wip: replicad-ocjs-v8
rifont Mar 6, 2026
12bd9cf
wip-suffix-overload-removal
rifont Mar 21, 2026
36b3cca
feat: return by value and wasm-opt-O4
rifont Mar 22, 2026
c7daa97
chore: format
rifont Mar 22, 2026
8fe0c9a
chore: add latest opencascadejs bindings
rifont Mar 23, 2026
36bbf25
fix: specify O3 instead of invalid O4 wasm-opt flag
rifont Mar 23, 2026
eb0ad95
build(replicad-opencascadejs): add --traps-never-happen flag to wasm-…
rifont Mar 23, 2026
9ddaf4c
chore: add latest simd max-perf builds
rifont Mar 24, 2026
e38aa56
refactor(shapeHelpers): replace deprecated TColgp array types with NC…
rifont Apr 6, 2026
598cc0b
fix(shapes): remove redundant normal consistency enforcement in mesh …
rifont Apr 6, 2026
4c9541c
fix(export): fix STEP export by calling correct Transfer method
rifont Apr 6, 2026
959b405
refactor(build-config): consolidate OpenCascade build configs into si…
rifont Apr 6, 2026
a1e6a94
chore: regenerate wasm bindings
rifont Apr 6, 2026
8bcd48e
chore: bump replicad-opencascadejs version
rifont Apr 6, 2026
6d22951
chore: bump replicad version
rifont Apr 6, 2026
db21c69
fix(shapes): clear mesh cache before remeshing with coarser tolerance
rifont Apr 18, 2026
7157137
chore(replicad): clean up obsolete tarball build artifacts
rifont Apr 18, 2026
08a3937
refactor(lib2d): update OpenCascade 2D curve API to v8 naming
rifont Apr 18, 2026
37ca844
feat(export): add material density and PBR support to assembly exporter
rifont Apr 18, 2026
775b02c
fix(shapeHelpers): replace deprecated GCE2d_MakeSegment with GC_MakeS…
rifont Apr 18, 2026
f5dc773
refactor(shapes): replace face iteration mesh logic with native C++ e…
rifont Apr 18, 2026
37e457e
chore: bump package versions
rifont Apr 18, 2026
fb01a8b
chore: rebuild replicad-opencascadejs
rifont Apr 19, 2026
b8359b2
fix: drop relaxed-simd for safari support
rifont Apr 24, 2026
651594c
refactor(export): rename metallic to metalness in ShapeConfig type
rifont Apr 24, 2026
f7b86c7
chore(packages): add npm publish configuration and update descriptions
rifont Apr 24, 2026
79c52f0
docs: clarify origin-relative positioning in solid creation APIs
rifont May 18, 2026
d868d4c
feat(ui): migrate to ESM sub-path exp
rifont May 27, 2026
1e065b7
chore: rebuild latest ocjs builds
rifont May 31, 2026
a9a6abe
Merge upstream replicad v0.23.3 into taucad fork
rifont May 31, 2026
8839e02
chore: regenerate wasm builds with gp_Pln included
rifont May 31, 2026
6ba609c
refactor(api): simplify OpenCASCADE constructor calls with default pa…
rifont Jun 1, 2026
38fa556
build(replicad): change moduleResolution from node to bundler
rifont Jun 1, 2026
37f8368
chore: bump package verisons to beta
rifont Jun 1, 2026
55535cd
fix: reconcile tau fork with replicad v0.23.3
rifont Jun 1, 2026
fe7a5b6
fix(example): build worker as ES module
rifont Jun 14, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 104 additions & 0 deletions docs/occt-v8-migration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# OCCT V8 Migration — replicad Perspective

This document covers the replicad-specific changes for the OCCT V8 migration.

## Summary

The OCCT V8 migration consolidates replicad's three WASM builds (`single`, `with_exceptions`, `multi`) into a **single unified build** using native WASM exceptions (`-fwasm-exceptions`).

| Build variant | V7.6 / V8 (before) | V8 (after) |
|---|---|---|
| `replicad_single` | No exception support | Full exception support via `-fwasm-exceptions` |
| `replicad_with_exceptions` | Separate build with `-fexceptions` | **Removed** — merged into single build |
| `replicad_multi` | pthread-based multi-threading | **Removed** — deferred (see below) |

## Why a Single Build?

### Native WASM Exceptions (`-fwasm-exceptions`)

The WebAssembly Exception Handling proposal (Phase 4) is now supported by 94.5%+ of browsers (Chrome 95+, Firefox 100+, Safari 15.2+). It provides:

- **Zero-cost happy path**: No `invoke_SIG` wrapper overhead on every function call
- **Proper stack traces**: `WebAssembly.Exception` objects preserve the call stack
- **Smaller binary**: ~10-15% smaller than JavaScript-based exception handling (`-fexceptions`)
- **No performance penalty**: Unlike `-fexceptions`, which added ~75% binary size and measurable runtime overhead, `-fwasm-exceptions` has negligible impact on non-throwing code paths

This eliminates the need for a separate "with_exceptions" build. The single build has full exception decoding support with `OCJS.getStandard_FailureData()`.

### Multi-threading Deferred

Analysis revealed that OCCT's parallel algorithms were never actually activated in the replicad codebase:

- `BRepMesh_IncrementalMesh`: called with `isInParallel=false` (hardcoded in `shapes.ts`)
- `BOPAlgo_Options::SetRunParallel()`: defaults to `false`
- All benchmark operations showed **slower** performance with the multi-threaded build due to pthread infrastructure overhead (SharedArrayBuffer, mutex costs, pre-spawned workers)

Multi-threading will be revisited when explicit parallel algorithm activation is implemented upstream.

## replicad Source Changes

The following replicad source files were modified for OCCT V8 compatibility:

- **`packages/replicad/src/Sketcher.ts`**: Updated for V8 API changes
- **`packages/replicad/src/shapes.ts`**: Updated mesh and shape operations
- **`packages/replicad/src/geom.ts`**: Geometry utility updates

## Build Configuration

### Single V8 YAML (`custom_build_single_v8.yml`)

Key changes from the V7.6 configuration:

```yaml
emccFlags:
- -flto # Dead-code elimination at link
- -fwasm-exceptions # Native WASM exceptions
- -sEXPORT_EXCEPTION_HANDLING_HELPERS # JS helpers for exception decoding
- -sEXPORT_ES6=1
- -sALLOW_MEMORY_GROWTH=1
- -sINITIAL_MEMORY=100MB
- -sMAXIMUM_MEMORY=4GB
- --no-entry
- --emit-symbol-map
- -O3
```

Bindings include `OCJS` and `Standard_Failure` for exception decoding (previously only in the `with_exceptions` build).

## Performance

Benchmarks show V8 is significantly faster than V7.6, especially for boolean operations:

| Operation | V7.6.2 (ms) | V8 Single (ms) | Delta |
|---|---|---|---|
| fuse-two-boxes | 26.6 | 20.7 | -22% |
| n-body-fuse | 65.1 | 48.3 | -26% |
| deep-boolean-chain | 132.1 | 91.7 | -31% |
| bottle | 342.3 | 254.4 | -26% |
| birdhouse | 271.1 | 198.3 | -27% |
| vase | 226.4 | 162.8 | -28% |

## Package Structure

```
dist/
replicad-opencascadejs-0.21.0-v8.XX.tgz # WASM + JS glue
replicad-0.21.0-v8.XX.tgz # replicad library
```

Consumers reference these tarballs via GitHub raw URLs:

```yaml
catalog:
replicad: "https://github.com/taucad/replicad/raw/main/dist/replicad-0.21.0-v8.XX.tgz"
replicad-opencascadejs: "https://github.com/taucad/replicad/raw/main/dist/replicad-opencascadejs-0.21.0-v8.XX.tgz"
```

## Removed Files

- `build-config/custom_build_with_exceptions_v8.yml` — merged into `custom_build_single_v8.yml`
- `build-config/custom_build_multi_v8.yml` — multi-threading deferred
- `src/replicad_with_exceptions.*` — no longer needed
- `src/replicad_multi.*` — no longer needed

See `repos/opencascade.js/docs/occt-v8-migration.md` for build-level details.
8 changes: 4 additions & 4 deletions packages/replicad-app-example/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "replicad-app-example",
"version": "0.23.1",
"version": "0.21.0",
"description": "A simple React app based on replicad.",
"private": true,
"license": "MIT",
Expand All @@ -16,9 +16,9 @@
"file-saver": "^2.0.5",
"react": "18.2.0",
"react-dom": "18.2.0",
"replicad": "^0.23.1",
"replicad-opencascadejs": "^0.23.0",
"replicad-threejs-helper": "^0.23.0",
"replicad": "^0.21.0",
"replicad-opencascadejs": "workspace:@taucad/replicad-opencascadejs@^",

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this needs to change

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes it does - I will add a task for this to the PR description so I don't forget to update, for now it's there whilst I publish the taucad scoped package to NPM for testing.

"replicad-threejs-helper": "^0.21.0",
"three": "^0.155.0"
},
"devDependencies": {
Expand Down
2 changes: 1 addition & 1 deletion packages/replicad-app-example/src/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import ReactDOM from "react-dom";
import App from "./App.jsx";

// This is here to compensate for a bug in vite
import "replicad-opencascadejs/src/replicad_single.wasm?url";
import "replicad-opencascadejs/wasm?url";

ReactDOM.render(
<React.StrictMode>
Expand Down
10 changes: 5 additions & 5 deletions packages/replicad-app-example/src/worker.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import opencascade from "replicad-opencascadejs/src/replicad_single.js";
import opencascadeWasm from "replicad-opencascadejs/src/replicad_single.wasm?url";
import { setOC } from "replicad";
import { expose } from "comlink";
import opencascade from 'replicad-opencascadejs';
import opencascadeWasm from 'replicad-opencascadejs/wasm?url';
import { setOC } from 'replicad';
import { expose } from 'comlink';

// We import our model as a simple function
import { drawBox } from "./cad";
import { drawBox } from './cad';

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make sure you run prettier (with default config) to keep the same quotes than before.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will do 👍


// This is the logic to load the web assembly code into replicad
let loaded = false;
Expand Down
3 changes: 3 additions & 0 deletions packages/replicad-app-example/vite.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ export default defineConfig({
build: {
outDir: "build",
},
worker: {
format: "es",
},
server: {
port: 4444,
},
Expand Down
4 changes: 2 additions & 2 deletions packages/replicad-cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,9 @@
"commander": "^14.0.1",
"jszip": "^3.10.1",
"manifold-3d": "^3.0.1",
"replicad": "workspace:^",
"replicad": "workspace:@taucad/replicad@^",
"replicad-evaluator": "workspace:^",
"replicad-opencascadejs": "workspace:^",
"replicad-opencascadejs": "workspace:@taucad/replicad-opencascadejs@^",
"tsx": "^4.20.6"
},
"devDependencies": {
Expand Down
4 changes: 2 additions & 2 deletions packages/replicad-cli/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { createRequire } from "node:module";
import { fileURLToPath } from "node:url";
import { Command, Option } from "commander";
import { getManifoldModule, setWasmUrl } from "manifold-3d/lib/wasm.js";
import opencascadeModule from "replicad-opencascadejs/src/replicad_single.js";
import opencascadeModule from "replicad-opencascadejs";
import * as replicad from "replicad";
import { createEvaluator } from "replicad-evaluator";
import packageJson from "../package.json" with { type: "json" };
Expand Down Expand Up @@ -97,7 +97,7 @@ async function createCliEvaluator() {
(opencascadeModule as any)?.default?.default ||
(opencascadeModule as any)?.default ||
opencascadeModule;
const wasmPath = require.resolve("replicad-opencascadejs/src/replicad_single.wasm");
const wasmPath = require.resolve("replicad-opencascadejs/wasm");
const manifoldWasmPath = require.resolve("manifold-3d/manifold.wasm");
setWasmUrl(manifoldWasmPath);
const oc = await openCascadeFactory({
Expand Down
12 changes: 4 additions & 8 deletions packages/replicad-evaluator/__tests__/setup.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { dirname, join } from "node:path";
import { fileURLToPath } from "node:url";
import { createRequire } from "node:module";
import { beforeAll } from "vitest";
import opencascade from "../../replicad-opencascadejs/src/replicad_single.js";
import opencascade from "replicad-opencascadejs";
import * as replicad from "../../replicad/src/index";

declare global {
Expand All @@ -12,11 +11,8 @@ declare global {
beforeAll(async () => {
if (globalThis.replicadEvaluatorReady) return;

const here = dirname(fileURLToPath(import.meta.url));
const opencascadeWasm = join(
here,
"../../replicad-opencascadejs/src/replicad_single.wasm"
);
const require = createRequire(import.meta.url);
const opencascadeWasm = require.resolve("replicad-opencascadejs/wasm");

globalThis.replicadEvaluatorOC = await opencascade({
locateFile: () => opencascadeWasm,
Expand Down
2 changes: 2 additions & 0 deletions packages/replicad-evaluator/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
},
"devDependencies": {
"@types/node": "^22.13.1",
"replicad": "workspace:@taucad/replicad@^",
"replicad-opencascadejs": "workspace:@taucad/replicad-opencascadejs@^",
"typescript": "5.1.6",
"vite": "^4.5.5",
"vite-plugin-dts": "^3.5.2",
Expand Down
1 change: 1 addition & 0 deletions packages/replicad-opencascadejs/.npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.npm-pack-all-tmp
Loading