Skip to content

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:

  1. Emscripten (emsdk) toolchain setup.
  2. 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).
  3. OrcaSlicer v2.4.0 checked out as a git submodule (orca-wasm/orca/).
  4. orca-wasm/patches/apply.py — idempotent patch script applied before CMake.
  5. CMake + ninja with SLIC3R_WASM=ON.
  6. Artifacts packaged to public/wasm/ and uploaded via deploy.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_sinkunlocked_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_init returns 0.
  • orc_slice on a 20 mm cube returns 0, produces ~175 KB G-code, header generated by OrcaSlicer 2.3.2, 4509 extrusion moves, 50 layers.
  • Exceptions correctly caught after adding -fexceptions to global CMAKE_CXX_FLAGS (Emscripten strips catch blocks 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).