subagent transcript
session 17f09f89 · workflow wf_77616857
delegated task
GOAL: Produce a CONCRETE roadmap to FULL FreeCAD desktop feature parity for the FreeCAD->WebAssembly port. Be evidence-based: grep/read the actual sou
▸ Magik
GOAL: Produce a CONCRETE roadmap to FULL FreeCAD desktop feature parity for the FreeCAD->WebAssembly port. Be evidence-based: grep/read the actual sources, don't reason from general FreeCAD knowledge alone. Cite file paths.
CURRENT STATE (verified working in the browser build):
- FreeCAD 26.3.0dev compiled to wasm. Toolchain: emscripten 4.0.12, ASYNCIFY, JS-exceptions, **single-thread (NO pthreads, QT_FEATURE_thread=-1)**, static CPython 3.14, static Qt 6.11.1 (asyncify), static OCCT, static Coin3D. **NO dlopen** — every C-extension is registered via PyImport_AppendInittab in generated src/Main/WasmInittab*.cpp. **NO subprocess/QProcess, NO threads, NO native OS dialogs.** Browser file I/O via upload/download (deploy/index.html). FreeCAD.wasm ~243MB.
- 3D viewport RENDERS (offscreen FBO + QPainter blit; Coin3D/OpenGL via WebGL).
- **PySide6 FULLY WORKS**: QtCore+QtGui+QtWidgets bindings + shiboken runtime + signals/slots; `from PySide import QtGui` compat shim works; `Gui.getMainWindow()` returns a real PySide6 QMainWindow (shiboken wrapInstance); Python macro scripting drives geometry + GUI.
- Workbenches LIVE (7): Part, PartDesign, Sketcher, Surface, Spreadsheet, Material (+None/Start). Measure + Import modules built-in.
- Built-in C-extensions (inittab): Import, ImportGui, Materials, MatGui, Measure, MeasureGui, Part, PartGui, PartDesign, PartDesignGui, Sketcher, SketcherGui, Spreadsheet, SpreadsheetGui, StartGui, Surface, SurfaceGui.
- MISSING modules (present in src/Mod but NOT built/registered): Draft, BIM, CAM, Fem, Mesh, MeshPart, Points, TechDraw, Assembly, Plot, Show, OpenSCAD, Web, Inspection, ReverseEngineering, Robot, JtReader, Help, AddonManager, Test, Tux, TemplatePyMod.
PATHS:
- FreeCAD source: /home/magik6k/lcad-wasm/freecad-port/FreeCAD (src/Mod/<WB>, src/Gui, src/App). Each module has CMakeLists.txt, App/ (C++), Gui/ (C++), and often a Python workbench tree (Init.py/InitGui.py + *.py).
- wasm build tree: /opt/toolchains/src/freecad-gui-build (CMakeCache.txt, build.ninja, src/Main/WasmInittab*.cpp).
- deploy: /home/magik6k/lcad-wasm/freecad-port/deploy (index.html = browser file I/O + boot; *.data = packaged FS).
- The module-enablement pipeline already used for the live modules: add C-ext to inittab (RegName=CInitSuffix form via FREECAD_WASM_EXTRA_PY_MODULES + the SHARED->STATIC rewrite in FreeCAD/CMakeLists.txt:91-107), package the module's Python tree onto the wasm FS via file_packager (freecad-mods.data), drop unbuildable OCCT deps, fix dependency gates.
- External-tool deps that are a problem in wasm: Fem (calculix/gmsh solvers via subprocess), BIM (ifcopenshell, needs building for wasm + network for downloads), CAM (post-processors), AddonManager (git/network), OpenSCAD (external openscad binary), Web (QtWebEngine — almost certainly not portable).
For each thing you assess, classify wasm-viability: WORKS (already), EASY (module-enable pipeline, no hard blocker), MEDIUM (needs a dep built for wasm or a moderate workaround), HARD (needs a wasm-native re-architecture e.g. web worker/fetch/browser API), BLOCKED (fundamentally not portable — say why + what a degraded fallback looks like). Give a rough effort (S/M/L/XL) and cite evidence (CMakeLists deps, Init.py imports, subprocess/QProcess/network usage grep).
DIMENSION 3 — C++ workbenches. Deep-dive Mesh, MeshPart, Points, TechDraw, CAM, Fem, Inspection, ReverseEngineering, Robot, JtReader. For each read src/Mod/<WB>/App/CMakeLists.txt (+Gui): what libraries it links (OCCT toolkits like TKMesh/TKXSDRAW, VTK for Fem, QtSvg/QtXml for TechDraw, external solver libs), whether those deps are already built for wasm (/opt/toolchains has occt-wasm, xerces-wasm, etc.), and the inittab+packaging steps. Flag which need a dep compiled for wasm (MEDIUM) vs which have a hard external-tool/threading blocker (Fem solvers, VTK). Mesh/Points/TechDraw are high value.
Fable
thinking
I'm diving into the C++ workbenches in FreeCAD, specifically examining Mesh, MeshPart, Points, TechDraw, CAM, Fem, Inspection, ReverseEngineering, Robot, and JtReader. I'll need to check the CMakeLists.txt files and search for their dependencies to understand the architecture.
Fable
⚙ Bash {"command": "cd /home/magik6k/lcad-wasm/freecad-port/FreeCAD/src/Mod && ls -d Mesh MeshPart Points TechDraw Cam CAM Fem Inspection ReverseEngineering Robot JtReader 2>/dev/null; echo \"---ALL---\"; ls", "description": "List target module di…
Fable
⚙ Bash {"command": "ls /opt/toolchains/ 2>/dev/null; echo \"---src---\"; ls /opt/toolchains/src 2>/dev/null; echo \"---occt---\"; ls /opt/toolchains/*occt* 2>/dev/null; ls -d /opt/toolchains/*/ 2>/dev/null", "description": "Check toolchain deps"}
Fable
thinking
I need to explore what OCCT toolkits are available in the wasm library and check the Qt modules, then examine the CMakeLists files for each one.
Fable
⚙ Bash {"command": "ls /opt/toolchains/occt-wasm/lib | grep -iE 'TKMesh|TKXSDRAW|TKXDE|TKSTL|TKRWMesh|TKBinL|TKStd|TKMeshVS|TKHLR|TKG3d|TKGeomAlgo' ; echo \"---ALL TK---\"; ls /opt/toolchains/occt-wasm/lib | grep -i '^libTK' | sed 's/lib//;s/\\.a/…
Fable
⚙ Bash {"command": "ls /opt/toolchains/qt-asyncify/lib 2>/dev/null | grep -iE 'Svg|Xml|PrintSupport|Charts|WebEngine|DataVis' ; echo \"---qt libs all---\"; ls /opt/toolchains/qt-asyncify/lib 2>/dev/null | grep -i '^libQt' | sed 's/libQt6//;s/\\.a/…
Fable
thinking
I need to track down where the Qt libraries are actually located by checking the CMakeCache file from the build directory.
Fable
⚙ Bash {"command": "for d in /opt/toolchains/qt-asyncify /opt/toolchains/qt; do echo \"=== $d ===\"; find $d -maxdepth 3 -name 'libQt6Svg*.a' -o -maxdepth 3 -name 'libQt6Xml*' 2>/dev/null | head; done; echo \"---find any qt svg/xml lib---\"; find …
Fable
⚙ Bash {"command": "grep -iE 'Qt6_DIR|QT_DIR|Qt6Svg|Qt6PrintSupport' /opt/toolchains/src/freecad-gui-build/CMakeCache.txt 2>/dev/null | head; echo \"---find qt install prefix---\"; grep -iE 'CMAKE_PREFIX_PATH|Qt6.*DIR:' /opt/toolchains/src/freecad…
Fable
thinking
Qt's SVG, SvgWidgets, Xml, and PrintSupport modules are all compatible with WebAssembly asyncify, which is good news for TechDraw since it relies on QtSvg and QtXml. However, VTK isn't available for WebAssembly, which is a significant blocker for the Fem module and potentially others that depend on it. Now I'm going through the CMakeLists files for each module to understand their dependencies better.
Fable
⚙ Bash {"command": "cd /home/magik6k/lcad-wasm/freecad-port/FreeCAD/src/Mod\nfor m in Mesh MeshPart Points; do\necho \"############ $m/App ############\"; grep -nE 'target_link_libraries|TK[A-Za-z0-9]+|VTK|vtk|\\$\\{[A-Za-z_]+\\}|Boost|Eigen|find_…
Fable
thinking
I need to check the actual LIBS variable definitions across the files.
Fable
⚙ Bash {"command": "cd /home/magik6k/lcad-wasm/freecad-port/FreeCAD/src/Mod\necho \"===== Mesh/App _LIBS =====\"; grep -nA20 'set(Mesh_LIBS' Mesh/App/CMakeLists.txt\necho \"===== Mesh QtConcurrent usage =====\"; grep -rn 'QtConcurrent\\|Concurrent…
Fable
thinking
Looking at the Mesh/App module dependencies, it only links against FreeCADBase, FreeCADApp, and QtConcurrent, while maintaining its own WildMagic4 and Core mesh algorithms. The issue is that QtConcurrent relies on QThreadPool which requires threading support, but the WebAssembly build has threading disabled. I need to verify whether Mesh actually uses QtConcurrent functionally or if it's just a dependency that isn't actively used.
For MeshPart/App, the situation is more complex—it depends on SMESH, a large meshing library that requires VTK, which is a significant blocker. However, MeshPart's core functionality for mesh-to-shape conversion uses OCCT's TKMesh (BRepMesh), which is available. T …
Fable
⚙ Bash {"command": "cd /home/magik6k/lcad-wasm/freecad-port/FreeCAD/src/Mod\necho \"=== VTK includes across modules ===\"; grep -rln 'vtk' Mesh MeshPart Points 2>/dev/null | head\necho \"=== QtConcurrent real usage (Mesh/Points whole tree) ===\"; …
Fable
thinking
I'm checking how QtConcurrent behaves in the single-threaded WebAssembly build—specifically whether QtConcurrent::blockingMap runs synchronously when threading is disabled, and what happens with QThreadPool when it has zero threads available.
Now I need to move through the remaining modules: TechDraw, CAM, Fem, and the smaller ones, checking them in batches.
Fable
⚙ Bash {"command": "cd /home/magik6k/lcad-wasm/freecad-port/FreeCAD/src/Mod\necho \"=== Mesh QtConcurrent calls ===\"; grep -rn 'QtConcurrent::\\|blockingMap\\|QThreadPool\\|QFuture' Mesh/App/Core/Curvature.cpp Points/App/Points.cpp Points/App/Pro…
Fable
thinking
I'm concerned about using QtConcurrent::blockingMap in a single-threaded WebAssembly build since it relies on QThreadPool, but Qt Concurrent actually requires threading support to function properly. Even though the library built, I need to verify whether QThreadPool will work correctly with asyncify in single-threaded mode—blockingMap could potentially hang if the thread pool isn't functioning as expected.
The practical solution here is to replace QtConcurrent calls with standard serial loops where needed, which is a straightforward patch that shouldn't require much effort. I'll note this as a minor workaround and move on to checking the TechDraw LIBS variable.
Fable
⚙ Bash {"command": "cd /home/magik6k/lcad-wasm/freecad-port/FreeCAD/src/Mod\necho \"=== TechDrawLIBS set() ===\"; grep -nB1 -A30 'set(TechDrawLIBS' TechDraw/App/CMakeLists.txt\necho \"=== TechDraw find_package top ===\"; grep -rn 'find_package\\|V…
Fable
thinking
Looking at TechDraw's dependencies, I see it relies on Measure, Part, Spreadsheet, and PartDesign (all already built), plus Import, QtConcurrent, QtCore, and QtWidgets. The key piece is OCCT support—TechDraw uses HLR (Hidden Line Removal) through TKHLR, which is available in the WebAssembly build. I should verify that TechDraw actually uses HLRBRep and check the CMakeLists to see how heavily the GUI depends on QtSvg and QtXml for its QGraphicsView-based rendering.
Now I need to look at the module-level CMakeLists to understand what gates the TechDraw build, check the GUI dependencies more carefully, and confirm whether it's using QGraphicsScene (which works fine in WebAssembly) and QtSvg.
Fable
⚙ Bash {"command": "cd /home/magik6k/lcad-wasm/freecad-port/FreeCAD/src/Mod\necho \"=== TechDraw/Gui LIBS ===\"; grep -nA25 'set(TechDrawGuiLibs\\|set(TechDrawGui_LIBS\\|TechDrawGuiLibs' TechDraw/Gui/CMakeLists.txt | head -40\necho \"=== TechDraw …
Fable
thinking
TechDraw looks really promising for this approach—it's already linking to built FreeCAD modules like Measure, Part, and PartDesign, plus it has access to the necessary Qt libraries for rendering and printing. The GUI layer uses QDomDocument, QPrinter, and QSvgGenerator which are all available, and it leverages QGraphicsView for the scene management, though it seems to need QtS for something that got cut off.
The main blockers are QtConcurrent (which is single-threaded in wasm) and QPrinter (printing degrades in wasm, but there's a workaround through SVG/PDF export). Overall it's a medium-effort module—large with many UI files, but no missing native dependencies—and the value is high. Now I' …
Fable
⚙ Bash {"command": "cd /home/magik6k/lcad-wasm/freecad-port/FreeCAD/src/Mod\nfor m in Inspection ReverseEngineering Robot JtReader; do\necho \"########## $m ##########\"\necho \"--- App/CMakeLists LIBS + deps ---\"\ngrep -nE 'set\\([A-Za-z]*_?LIBS…
Fable
⚙ Bash {"command": "cd /home/magik6k/lcad-wasm/freecad-port/FreeCAD/src/Mod\necho \"=== Inspection_LIBS ===\"; sed -n '3,12p' Inspection/App/CMakeLists.txt\necho \"=== Reen_LIBS ===\"; sed -n '23,45p' ReverseEngineering/App/CMakeLists.txt\necho \"…
Fable
thinking
Looking at the module dependencies, Inspection is straightforward since it only links to FreeCADApp, Mesh, and Points—all of which become available once those core modules are built, with no external dependencies and moderate value. ReverseEngineering is more complex, requiring Part, Mesh, and Points along with the Point Cloud Library, though PCL is optional and the module can still build with reduced functionality if it's not available.
Robot is actually easy to handle since it only depends on Part and QtCore with no external libraries—the kinematics library is bundled in the source tree. JtReader is trickier because while it links to Mesh and OCC libraries, it also needs the optional TKJT …
Fable
⚙ Bash {"command": "cd /home/magik6k/lcad-wasm/freecad-port/FreeCAD/src/Mod\necho \"=== PCL find_package (optional?) ===\"; grep -rniE 'find_package.*PCL|BUILD_REVERSE|HAVE_PCL' ../CMakeLists.txt CMakeLists.txt ReverseEngineering/CMakeLists.txt /h…
Fable
thinking
Looking at the CAM module structure, I see it's a C++ application that links against Part and FreeCADApp, with several bundled third-party libraries including libarea for 2D area operations, pybind11 bindings for a traveling salesman solver, and Voronoi functionality built on Boost's polygon library. I'm trying to trace the dependencies—particularly whether libarea depends on Boost and where exactly these components are organized in the source tree.
The post-processors are pure Python scripts generating G-code output, so they shouldn't require subprocess calls, though I should verify that assumption. The real concern is whether pybind11 is available and if the tsp_solver is actually require …
Fable
⚙ Bash {"command": "cd /home/magik6k/lcad-wasm/freecad-port/FreeCAD/src/Mod\necho \"=== area-native location + deps ===\"; find CAM -type d -iname '*area*' | head; grep -rniE 'find_package|boost|Boost' CAM/App/Area/CMakeLists.txt CAM/libarea/CMake…
Fable
thinking
FEM is heavily dependent on meshing libraries like SMESH and NETGEN that require VTK for visualization, but VTK is too large to build for WebAssembly. The bigger blocker is that FEM relies on external solver binaries like CalculiX, Elmer, and Z88 that are invoked through subprocess calls, which simply don't work in a WebAssembly environment.
Fable
⚙ Bash {"command": "cd /home/magik6k/lcad-wasm/freecad-port/FreeCAD/src/Mod\necho \"=== Fem_LIBS base set ===\"; grep -nA12 'set(Fem_LIBS' Fem/App/CMakeLists.txt | head -18\necho \"=== Fem solver subprocess/QProcess ===\"; grep -rlnE 'subprocess|Q…
Fable
thinking
SMESH is bundled in FreeCAD's source tree under src/3rdParty/salomesmesh, which means it could theoretically be built for WebAssembly, though it's a large dependency. The version included is a trimmed-down variant, and while NETGEN is optional, SMESH itself isn't currently compiled for wasm since there's no libSMESH available yet.
For the Fem workbench, the core blocker is that it requires external solvers running as subprocesses—CalculiX, Elmer, etc.—which fundamentally can't work in a browser environment. SMESH could potentially be ported (medium to hard effort), and VTK for visualization is a substantial port, but the solver dependency makes Fem essentially blocked unless we accept a deg …
Fable
⚙ Bash {"command": "cd /home/magik6k/lcad-wasm/freecad-port/FreeCAD/src\necho \"=== salomesmesh deps (VTK? boost? OCCT?) ===\"; grep -rniE 'find_package|VTK|vtk|Boost|target_link|OpenCASCADE' 3rdParty/salomesmesh/CMakeLists.txt 2>/dev/null | head …
Fable
thinking
So SMESH is the critical blocker here—it mandatorily depends on VTK, which is a massive C++ library with 24 files pulling it in, making a WebAssembly port extremely difficult. While SMESH can optionally use NETGEN and has available dependencies like Boost, OCCT, and HDF5, the VTK requirement alone pushes this into the hard category for single-threaded WebAssembly compilation.
MeshPart is more promising—it can build without SMESH entirely since the meshing code is guarded by a compile flag, though this means losing the netgen/gmsh integration while retaining shape-to-mesh tessellation capabilities. CAM's core path generation is pure Python, but it has subprocess calls for external tools like …
Fable
⚙ Bash {"command": "cd /home/magik6k/lcad-wasm/freecad-port/FreeCAD/src\necho \"=== GuiInit subprocess purpose ===\"; sed -n '88,100p' Mod/CAM/Path/GuiInit.py\necho \"=== pybind11 anywhere in toolchain/python ===\"; find /opt/toolchains/python-was…
Fable
thinking
The CAM GuiInit subprocess is protected by an import guard that'll fail first if camotics isn't available, so it never actually runs—that's safe since it's just an optional GUI component. The tsp_solver is a separate shared library built with pybind11, which in WebAssembly could either be a second inittab module or swapped out for a pure Python implementation, and while pybind11 isn't currently present, it's header-only so it's straightforward to add if needed. The tsp_solver itself is optional and only used for path optimization.
For the Mesh GUI, I have Boost, OpenGL glu, Mesh, and FreeCADGui all available, and Coin3D rendering already works. Now I'm mapping out the gaps for each module: …
Fable
I have enough evidence. Let me compile the structured findings.
Fable
⚙ StructuredOutput {"dimension": "C++ workbenches (Mesh, MeshPart, Points, TechDraw, CAM, Fem, Inspection, ReverseEngineering, Robot, JtReader)", "worksNow": ["None of these 10 modules are currently built or registered (all in the MISSING list), but the OCCT …