▸ Magik
FreeCAD is ported to WebAssembly (JSPI + native-EH, static CPython 3.14, no dlopen, no subprocess, single-thread, Qt 6.11). 17 workbenches already work incl. Part/PartDesign/Sketcher/Measure/Draft/Assembly/TechDraw/Mesh + numpy + PySide6 + pivy._coin. Source tree: /home/magik6k/lcad-wasm/freecad-port/FreeCAD (branch wasm-parity-push). Build tree (already configured, DO NOT build — read only): /opt/toolchains/src/freecad-gui-build. The module-enablement pipeline is documented in the memory files at /home/magik6k/.claude/projects/-home-magik6k-lcad-wasm/memory/ (read freecad-wasm-parity-roadmap.md and freecad-wasm-viewport.md FIRST — they describe the src/Main/CMakeLists.txt inittab generator, FREECAD_WASM_EXTRA_PY_MODULES / FREECAD_WASM_EXTRA_LINK_LIBS, SHARED->STATIC conversion, data-packaging with file_packager, and known gotchas).
Constraints that shape feasibility: NO subprocess/fork/exec, NO dlopen (all C-ext modules static via inittab), NO threads (QThreadPool/QtConcurrent absent), NO listen sockets, wasm32 4GB ceiling. C++ deps must be new-EH (-fwasm-exceptions -sWASM_LEGACY_EXCEPTIONS=0). Pure-Python addons are fine; native ones need static linking.
Your job: READ ONLY. Do not edit source, do not run cmake/ninja/emcc. Produce an actionable plan a build engineer can execute.
Here are 5 parallel parity investigations (JSON):
[{"area":"CAM (Path) workbench","verdict":"tractable-with-work","effortHours":"8-16","valueToUsers":"high","rootBlockers":["pybind11 is not installed anywhere in the toolchain (no headers under /opt/toolchains, not in the venv, FREECAD_USE_PYBIND11=OFF). BUILD_CAM auto-forces FREECAD_USE_PYBIND11=ON which calls find_package(pybind11 REQUIRED) -> hard configure failure until pybind11 is provided. This is also the FIRST pybind11 module in the wasm build, so pybind11's exception-translation + shared-internals under JSPI + native wasm-EH is unproven (no fundamental reason it should fail; header-only, RTTI+exceptions available).","src/Main/CMakeLists.txt has NO BUILD_CAM block adding the modules to the inittab/link lists (only a stubbed Path->PathApp name mapping exists at lines 116-118). Without it the static PathApp/area/tsp_solver/PathGui/PathSimulator archives are never linked or registered.","The 'packaging' Python module is imported UNGUARDED at CAM workbench init (InitGui.py:109 'from packaging.version import Version, parse' and GuiInit.py:101) and is not confirmed present in any deploy .data package; workbench Initialize() will raise ImportError and fail to load unless packaging (pure-Python, present in /opt/toolchains/venv/lib/python3.14/site-packages/packaging) is added to the wasm FS.","The full CAM Python tree (~400 .py under src/Mod/CAM: Path/**, PathScripts, Machine, Tools) is not in the base freecad.data and must be FS-packaged via a supplementary file_packager .data (pack-mods.sh), deduped against existing packages."],"concreteSteps":["Provide pybind11 to CMake: `pip install pybind11` into /opt/toolchains/venv (header-only, arch-independent, safe for the emscripten cross-build). At reconfigure pass `-Dpybind11_DIR=$(/opt/toolchains/venv/bin/python -m pybind11 --cmakedir)`. pybind11 headers only need Python.h (already the wasm CPython include already used by the CAM targets, which link Python3::Python directly and pass ${pybind11_INCLUDE_DIR} manually) so find_package resolving host-Python is harmless here.","Reconfigure the existing build tree (do NOT re-run emcmake): `cmake -S /home/magik6k/lcad-wasm/freecad-port/FreeCAD -B /opt/toolchains/src/freecad-gui-build -DBUILD_CAM=ON -Dpybind11_DIR=...`. REQUIRES_MODS(BUILD_CAM BUILD_PART BUILD_MESH) is already satisfied (both ON). This auto-turns FREECAD_USE_PYBIND11 ON (InitializeFreeCADBuildOptions.cmake:230).","Edit src/Main/CMakeLists.txt: add a BUILD_CAM block after the BUILD_ASSEMBLY block (~line 79) registering the five static modules. The generator already maps Path->PathApp; area/tsp_solver/PathSimulator/PathGui are plain names matching their PyInit_* symbols (verified: PYBIND11_MODULE(area)/(tsp_solver), PyMOD_INIT_FUNC(PathSimulator)/(PathGui)). No SHARED->STATIC edits needed anywhere (global add_library override at CMakeLists.txt:96 handles it).","FS-package the CAM Python tree + the `packaging` dependency: run /home/magik6k/lcad-wasm/pack-mods.sh CAM to build deploy/freecad-mods-cam.data(.js/.gz), add packaging/ (copy /opt/toolchains/venv/lib/python3.14/site-packages/packaging into the package or the python stdlib zip), and load it in index.html before FreeCAD.js. Dedup against base freecad.data to avoid the opaque createFreeCAD '[object Object]' duplicate-path rejection.","Build: `cd /opt/toolchains/src/freecad-gui-build && ninja FreeCAD.js`. Expect the heaviest new TUs to be libarea/clipper.cpp, libarea/Adaptive.cpp, App/Area.cpp (140KB) and the two pybind11 TUs (memory-heavy). area-native transitively pulls the already-built Clipper2::Clipper2Z and Import.","Deploy + runtime-verify: copy bin/FreeCAD.{js,wasm} to deploy, regen .gz, load the CAM .data. Probe in-browser: `import PathApp, area, tsp_solver, PathSimulator`; `Gui.activateWorkbench('CAM_Workbench')`; run a Pocket/Profile op (exercises area.makeSections + Adaptive2d) and tsp_solver.solve to confirm the pybind11 path works under JSPI.","Leave the OCL-dependent ops (Surface/Waterline/RotarySurface, import ocl) degraded — they are already internally try/except-guarded (Surface.py:36-41) and not imported at workbench init, so they don't block boot; opencamlib is a separate unported native module out of scope."],"risks":"\"Primary risk is pybind11 being the first pybind11 module in this JSPI+new-EH build: its C++ exception translation (py::cast_error/error_already_set caught in tsp_solver_pybind.cpp) and per-process 'internals' capsule shared between the two pybind11 modules (area, tsp_solver) must work with -fwasm-exceptions/-sWASM_LEGACY_EXCEPTIONS=0; both compiled by the same toolchain so ABI-id matches, and no dlopen is involved, but …