ADR-004: Self-Built WASM from OrcaSlicer v2.4.0
Status: Accepted
Date: 2026-06-13
OrcaSlicer version since upgraded
This ADR records the decision made on 2026-06-13, when the pinned
ORCA_VERSION was v2.4.0. The pipeline it describes is unchanged in
structure, but the pinned version has since moved to v2.4.2 (a routine
upgrade — see "Upgrading OrcaSlicer version" in
Building WASM, not a
new ADR). For the currently shipped version see
status.md or architecture.md.
Context
The initial prototype used pre-built WASM artifacts from an external GitHub
project (allanwrench28/orcaslicer-wasm, v1.1, October 2025, OrcaSlicer v2.3.1).
While this was sufficient to prove the concept, it had significant drawbacks:
- No control over the build — we couldn't fix bugs, apply our own patches, or choose exactly which features to include/exclude.
- External dependency — if the external project became unmaintained or changed its release format, we would be stuck.
- Old version — we wanted OrcaSlicer v2.4.0, not v2.3.1.
- Opaque artifact — we couldn't verify what patches or flags were applied.
Decision
Build our own WASM pipeline in orca-wasm/, targeting OrcaSlicer v2.4.0, and
ship the resulting artifacts as OrcaWeb GitHub Releases (wasm-v2.4.0).
The build pipeline (orca-wasm/) consists of:
- Emscripten (emsdk) toolchain setup.
- Dependencies built once and cached in
orca-wasm/deps-install/: Boost 1.83 (b2, emscripten toolset, single-threaded), GMP/MPFR/CGAL, Eigen/nlohmann/EXPAT/NLopt/cereal, emscripten ports (zlib/png/jpeg). - OrcaSlicer v2.4.0 checked out as a git submodule (
orca-wasm/orca/). orca-wasm/patches/apply.py— idempotent patch script applied before CMake.- CMake + ninja with
SLIC3R_WASM=ON. - Artifacts packaged to
public/wasm/and uploaded viadeploy.yml.
CI trigger: the Build WASM workflow (build-wasm.yml) runs on manual dispatch,
tag push (wasm-v*), and on pull_request for changes to orca-wasm/**.
Non-Obvious Build Pitfalls
Boost.Log ABI mismatch (v2s_st vs v2s_mt_posix)
Boost built with BOOST_LOG_NO_THREADS=1 emits symbols in namespace v2s_st.
Without the same flag on the consumer side (libslic3r), wasm-ld reports
hundreds of undefined symbol: boost::log::v2s_mt_posix::*.
Fix: BOOST_LOG_NO_THREADS=1 added via add_compile_definitions() in
wasm_find_paths.cmake for the entire libslic3r build. utils.cpp patched:
synchronous_sink → unlocked_sink, thread-ID log expression removed.
-sEMULATE_FUNCTION_POINTER_CASTS=1 crashes wasm-opt
The Binaryen --fpcast-emu pass at -O3 triggers a SIGABRT in
mixed_arena.h:188. The link step (wasm-ld) succeeds; only the optimiser
crashes.
Fix: flag removed from orca-wasm/wasm/CMakeLists.txt. The module
instantiates and slices correctly without it — no runtime traps were observed.
Verification
Artifacts from CI tested in-browser:
- Module instantiates cleanly (~0.8 s).
orc_initreturns 0.orc_sliceon a 20 mm cube returns 0, produces ~175 KB G-code, headergenerated by OrcaSlicer 2.3.2, 4509 extrusion moves, 50 layers.- Exceptions correctly caught after adding
-fexceptionsto globalCMAKE_CXX_FLAGS(Emscripten stripscatchblocks by default).
Consequences
- Positive: Full control over build flags, patches, and feature set.
- Positive: Reproducible — anyone can re-run the pipeline from the submodule.
- Positive: CI check on every PR touching
orca-wasm/**. - Negative: Build takes ~40 minutes on GitHub Actions (dependency compilation is cached across runs once warm).
- Negative: Requires maintaining our own patch set as OrcaSlicer evolves (see ADR-006).