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 1 — Workbench inventory & classification. For EVERY module in src/Mod, determine: is it C++/Python/mixed; its build dependencies (read each CMakeLists.txt); whether it's currently built (see live list); its user-facing purpose; and a first-cut viability+effort to enable if missing. Read src/Mod/*/CMakeLists.txt and src/Mod/*/Init(Gui).py imports. Produce one gap entry per MISSING module with concrete enable requirements. This is the master inventory the roadmap is built on.
Fable
thinking
I'm starting with Dimension 1 by examining each module in src/Mod, checking their CMakeLists.txt and Init/InitGui.py files to identify which ones are missing from the inventory, then I'll create gap entries for those.
Fable
⚙ Bash {"command": "ls /home/magik6k/lcad-wasm/freecad-port/FreeCAD/src/Mod", "description": "List modules in src/Mod"}
Fable
⚙ Bash {"command": "for d in /home/magik6k/lcad-wasm/freecad-port/FreeCAD/src/Mod/*/; do echo \"=== $d ===\"; ls \"$d\" | head -30; done", "description": "List each module contents"}
Fable
thinking
I need to examine the CMakeLists.txt files for the missing FreeCAD modules to understand their dependencies, focusing on the C++ linking requirements rather than reading through all the large files.
Fable
⚙ Bash {"command": "cd /home/magik6k/lcad-wasm/freecad-port/FreeCAD/src/Mod\nfor m in Draft BIM CAM Fem Mesh MeshPart Points TechDraw Assembly Plot Show OpenSCAD Web Inspection ReverseEngineering Robot JtReader Help AddonManager Test Tux TemplateP…
Fable
thinking
I'm looking at the C++ build dependencies by examining the target_link_libraries directives in the App and Gui CMakeLists files to map out the linking structure.
Fable
⚙ Bash {"command": "cd /home/magik6k/lcad-wasm/freecad-port/FreeCAD/src/Mod\nfor m in CAM Fem Mesh MeshPart Points TechDraw Assembly Web Inspection ReverseEngineering Robot JtReader Test Draft; do\necho \"############## $m App/Gui deps ###########…
Fable
thinking
I need to trace through the CMake configuration to understand the actual library dependencies for each module. Let me search for where the _LIBS variables are defined and check what each component actually imports to map out the link dependencies accurately.
Fable
⚙ Bash {"command": "cd /home/magik6k/lcad-wasm/freecad-port/FreeCAD/src/Mod\nfor m in CAM Fem Mesh MeshPart Points TechDraw Assembly Web Inspection ReverseEngineering Robot JtReader Draft; do\necho \"############## $m LIBS ##############\"\nfor f …
Fable
thinking
I need to examine the specific LIBS blocks and initialization imports for the key modules—particularly ReverseEngineering, TechDraw, Web, and Robot—to understand their dependencies like Eigen, approximation libraries, Pivy, and network components.
Fable
⚙ Bash {"command": "cd /home/magik6k/lcad-wasm/freecad-port/FreeCAD/src/Mod\necho \"=== Reen App LIBS ===\"; sed -n '23,45p' ReverseEngineering/App/CMakeLists.txt\necho \"=== TechDrawGui LIBS ===\"; sed -n '18,60p' TechDraw/Gui/CMakeLists.txt\nech…
Fable
thinking
I'm checking the imports and subprocess/QProcess calls across the key FreeCAD modules—Draft, BIM, CAM, Fem, Show, Plot, Help, AddonManager, and OpenSCAD—to identify external dependencies in their initialization files.
Fable
⚙ Bash {"command": "cd /home/magik6k/lcad-wasm/freecad-port/FreeCAD/src/Mod\necho \"=== subprocess/QProcess/requests/urllib usage counts per missing module ===\"\nfor m in Draft BIM CAM Fem Mesh MeshPart Points TechDraw Assembly Plot Show OpenSCAD…
Fable
thinking
I'm checking the import-time dependencies across several key modules to understand which ones might fail to load based on their imports — looking at Draft, Fem, CAM, TechDraw, Mesh, and Plot workbenches, plus their InitGui counterparts to see what gets loaded at startup.
Fable
⚙ Bash {"command": "cd /home/magik6k/lcad-wasm/freecad-port\necho \"=== numpy/matplotlib present in build/deploy? ===\"\nfind /opt/toolchains/src/freecad-gui-build -maxdepth 4 -iname 'numpy' -o -iname 'matplotlib' 2>/dev/null | head\nfind . -iname…
Fable
thinking
I need to check whether numpy is included in the data files and see how Draft relies on it across its codebase.
Fable
⚙ Bash {"command": "cd /home/magik6k/lcad-wasm/freecad-port/deploy\necho \"=== numpy/matplotlib/scipy in packaged data? ===\"\nfor d in freecad.data freecad-mods.data freecad-pyside.data; do\n js=\"${d%.data}.js\"\n # file_packager stores manife…
Fable
thinking
I'm checking the data file size and looking into how numpy and matplotlib are packaged. Let me examine the JavaScript loader files and search through them to see what packages are actually included.
Fable
⚙ Bash {"command": "cd /home/magik6k/lcad-wasm/freecad-port/deploy\nls *.js 2>/dev/null\necho \"=== grep numpy across all js/html ===\"\ngrep -alE 'numpy' * 2>/dev/null | head\necho \"=== packaged python modules sample (from freecad.js manifest) =…
Fable
⚙ Bash {"command": "cd /home/magik6k/lcad-wasm/freecad-port/deploy\necho \"=== numpy references in each data.js manifest ===\"\nfor j in freecad.data.js freecad-mods.data.js freecad-pyside.data.js; do\n echo \"--- $j ---\"\n grep -aoE '(numpy|ma…
Fable
thinking
I need to reconsider how the manifest paths are organized based on what data.js is actually referencing.
Fable
⚙ Bash {"command": "cd /home/magik6k/lcad-wasm/freecad-port/deploy\necho \"=== sample of freecad.data.js file listing ===\"\ngrep -aoE '\"filename\":\"[^\"]*\"' freecad.data.js 2>/dev/null | head -20\necho \"count:\"; grep -aoc '\"filename\"' free…
Fable
⚙ Bash {"command": "cd /home/magik6k/lcad-wasm/freecad-port/deploy\ngrep -aoE '\"[^\"]{3,80}\"' freecad.data.js 2>/dev/null | grep -iE 'numpy|matplotlib|/Mod/|\\.py\"' | head -20\necho \"--- raw structure ---\"\nhead -c 1500 freecad.data.js\necho;…
Fable
thinking
So the Show mod is already in the data.js file even though it's not listed as active. I should check what mods are actually packaged by looking at the full directory listings and see if numpy is present anywhere in the system.
Fable
⚙ Bash {"command": "cd /home/magik6k/lcad-wasm/freecad-port/deploy\necho \"=== ALL /Mod/ dirs packaged across data files ===\"\ngrep -haoE '/Mod/[A-Za-z0-9_]+' freecad.data.js freecad-mods.data.js 2>/dev/null | sort -u\necho \"=== numpy/matplotlib…
Fable
thinking
Show's Python tree is packaged as a dependency, but numpy and matplotlib aren't available anywhere, which means any module that relies on them—like Draft's utilities, Fem's core functionality, Plot, and BIM—would need numpy compiled for WebAssembly. Let me check whether Draft actually depends on numpy at its core by looking at the imports I found earlier, and it looks like Draft doesn't require it after all, though it does import Part and needs DraftGeomUtils. Now I'm checking what C++ libraries like SMESH, Netgen, and VTK are available in the WebAssembly build tree, since Fem and MeshPart depend on them. Mesh itself is straightforward—it only needs FreeCADBase, FreeCADApp, and QtConcurrent, …
Fable
⚙ Bash {"command": "cd /home/magik6k/lcad-wasm/freecad-port/FreeCAD\necho \"=== 3rdParty in-tree deps ===\"\nls src/3rdParty 2>/dev/null\necho \"=== SMESH source in tree? ===\"\nfind src -maxdepth 3 -iname '*smesh*' -type d 2>/dev/null | head\nls …
Fable
thinking
Looking at what's available in the codebase, SMESH is already there in the source tree, which means Fem and MeshPart could potentially be compiled for WebAssembly, though it would require porting SMESH since it depends on OCCT and optionally Netgen. The good news is that Netgen is optional, so it's not a hard blocker. OndselSolver is also in-tree, making Assembly's solver relatively straightforward to build. And libE57Format is already present and being built.
Points is straightforward since libE57Format is already available in the build tree. CAM's libarea is in-tree and buildable. However, several modules hit hard constraints: VTK, PCL, gmsh, netgen, and calculix aren't available for WebA …
Fable
⚙ Bash {"command": "cd /opt/toolchains/src/freecad-gui-build\necho \"=== which Mod libraries are configured in build.ninja? ===\"\ngrep -oE 'src/Mod/[A-Za-z]+/(App|Gui)' build.ninja 2>/dev/null | sort -u | head -60\necho \"=== SMESH build targets …
Fable
thinking
I'm checking the FreeCAD CMakeLists.txt file to see how the build system gates different modules and what the available BUILD_ options are with their default values.
Fable
⚙ Bash {"command": "cd /home/magik6k/lcad-wasm/freecad-port/FreeCAD\ngrep -nE 'option\\(BUILD_|OPTION\\(BUILD_|cmake_dependent_option\\(BUILD_' CMakeLists.txt | grep -iE 'FEM|MESH|POINT|DRAFT|ARCH|BIM|PATH|CAM|TECHDRAW|ASSEMBLY|ROBOT|INSPECT|REVER…
Fable
⚙ Bash {"command": "cd /home/magik6k/lcad-wasm/freecad-port/FreeCAD\ngrep -rnE 'option\\(BUILD_[A-Z]+' CMakeLists.txt cMake 2>/dev/null | head -60\necho \"=== how src/Mod/CMakeLists gates each module ===\"\ngrep -nE 'BUILD_|add_subdirectory' src/M…
Fable
thinking
I should check the wasm build's CMakeCache to see which modules are actually disabled there, since they're all enabled by default.
Fable
⚙ Bash {"command": "cd /opt/toolchains/src/freecad-gui-build\ngrep -E 'BUILD_(FEM|MESH|MESH_PART|POINTS|DRAFT|BIM|CAM|TECHDRAW|ASSEMBLY|ROBOT|INSPECTION|REVERSEENGINEERING|WEB|OPENSCAD|TEST|PLOT|SHOW|JTREADER|ADDONMGR|HELP|TUX|TEMPLATE|FLAT_MESH|F…
Fable
thinking
All the missing modules are BUILD_*=OFF, and BUILD_SHOW is ON for the Python tree package, while BIM is confirmed OFF. Now I need to verify the Draft InitGui dependencies—Draft relies on Part and is a critical 2D workbench that shouldn't have any missing module issues.
I'm also checking whether Draft's C++ utilities are lightweight, then examining Draft's app library dependencies and how BIM interconnects with Draft, Arch, Part, Points, and TechDraw. Since BIM is substantial and ifcopenshell brings 82 files with its own C++ dependencies for WebAssembly compilation, I need to quickly review TechDraw's Qt dependencies like QtSvg before finalizing my analysis.
Fable
⚙ Bash {"command": "cd /home/magik6k/lcad-wasm/freecad-port/FreeCAD/src/Mod\necho \"=== Draft App LIBS ===\"; sed -n '1,20p' Draft/App/CMakeLists.txt | grep -A6 DraftUtils_LIBS\necho \"=== Draft InitGui workbench deps (imports) ===\"; grep -nE \"^…
Fable
thinking
I'm checking whether the ReverseEngineering module's PCL dependency is truly optional or if it's being linked unconditionally — the CMake guards suggest PCL is optional with fallback approximation via OCCT and GSL, but I need to verify that Reen_LIBS doesn't reference PCL variables unconditionally since empty variables would still attempt linking.
Now I'm ready to map out the full gap analysis across all 22 missing modules, categorizing them by viability and effort. For pure-Python modules like Draft and Show, the path forward depends on runtime dependencies and optional external tools — Draft's DXF import works natively but DWG import requires an external ODA converter, making that particu …
Fable
Based on my evidence-gathering, I have the full picture. Let me verify one more risk item (QtConcurrent under single-thread) before finalizing.
Fable
⚙ Bash {"command": "cd /home/magik6k/lcad-wasm/freecad-port/FreeCAD/src/Mod\necho \"=== Mesh QtConcurrent actual usage ===\"; grep -rlE 'QtConcurrent|QThreadPool|QFuture' Mesh/App 2>/dev/null | head\necho \"=== SMESH source size (Fem/MeshPart dep)…
Fable
thinking
I've identified the key technical blockers: Mesh relies on QtConcurrent for parallel processing which won't work in single-threaded mode, E57Format isn't compiled yet, SMESH is a massive port with nearly 200 source files, and ifcopenshell isn't available in the toolchain. I have enough information to structure my findings now.
Fable
I now have comprehensive evidence. Compiling the workbench inventory.
Fable
⚙ StructuredOutput {"dimension": "Workbench inventory & classification (every module in src/Mod) — master gap inventory for the FreeCAD→wasm parity roadmap", "worksNow": ["LIVE C++ workbenches compiled & in inittab: Part, PartDesign, Sketcher, Surface, Spread…