11 KiB
Integration Plan
Strategy for integrating ztools and Silo as built-in addons while maintaining clear boundaries with FreeCAD core.
Goals
- Native feel -- ztools and Silo behave as first-class citizens, not bolted-on addons
- Clean boundaries -- Clear separation between FreeCAD core, Kindred extensions, and addon code
- Minimal core modifications -- Preserve FreeCAD's container models (Part, Body, Assembly)
- Maintainability -- Easy to pull upstream FreeCAD changes without merge conflicts
- Extensibility -- Architecture supports future Kindred-specific features
Architecture layers
┌─────────────────────────────────────────────────────────────┐
│ Kindred Create Application │
├─────────────────────────────────────────────────────────────┤
│ Layer 4: Kindred Workbenches (mods/) │
│ ┌──────────────────┐ ┌──────────────────┐ │
│ │ ztools │ │ Silo │ │
│ │ Datum Creator │ │ Open/Save/Commit│ │
│ │ Enhanced Pocket │ │ Part numbering │ │
│ │ Assembly Patterns│ │ Revision control│ │
│ │ Spreadsheet fmt │ │ BOM management │ │
│ └──────────────────┘ └──────────────────┘ │
├─────────────────────────────────────────────────────────────┤
│ Layer 3: Kindred Bootstrap (src/Mod/Create/) │
│ ┌─────────────────────────────────────────────────────────┐│
│ │ Addon loading, theme application, global menu/toolbar ││
│ │ injection via WorkbenchManipulator API ││
│ └─────────────────────────────────────────────────────────┘│
├─────────────────────────────────────────────────────────────┤
│ Layer 2: FreeCAD Python API │
│ ┌─────────────────────────────────────────────────────────┐│
│ │ FreeCAD, FreeCADGui, Part, PartDesign, Sketcher, ││
│ │ Assembly, WorkbenchManipulator ││
│ └─────────────────────────────────────────────────────────┘│
├─────────────────────────────────────────────────────────────┤
│ Layer 1: FreeCAD Core (C++) │
│ ┌─────────────────────────────────────────────────────────┐│
│ │ App::Document, Part::Feature, PartDesign::Body, etc. ││
│ └─────────────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────────────┘
Boundary definitions
Layer 1: FreeCAD Core -- do not modify
FreeCAD's fundamental data structures: PartDesign::Body, PartDesign::Pocket, Part::Feature, App::Document, Sketcher::SketchObject. Modifying these creates merge conflicts with upstream and risks breaking FCStd file compatibility.
Layer 2: FreeCAD Python API -- use as-is
The Python API provides everything needed for feature creation, command registration, and geometry access. ZTools and Silo operate entirely through this layer.
Layer 3: Kindred Bootstrap -- src/Mod/Create/
The Create module is a thin Python loader that:
- Adds
mods/addon paths tosys.pathand executes theirInit.py/InitGui.pyfiles - Installs
SiloMenuManipulatorfor global File menu/toolbar injection - Sets up deferred Silo dock panels (auth, activity) via
QTimer - Handles first-start configuration
This layer does not contain C++ code. It uses FreeCAD's WorkbenchManipulator API for menu/toolbar injection.
Layer 4: Kindred Workbenches -- mods/
Pure Python workbenches following FreeCAD's addon pattern. Self-contained with InitGui.py, Init.py, and package.xml. Developed and versioned independently as git submodules.
Phase status
Phase 1: Addon auto-loading -- DONE
Implementation: src/Mod/Create/Init.py and InitGui.py load workbenches from mods/ at startup using exec(). Addons degrade gracefully if submodule is absent.
Default workbench: ZToolsWorkbench (set in resources/preferences/KindredCreate/KindredCreate.cfg).
Phase 2: Enhanced Pocket as C++ feature -- NOT STARTED
Goal: Replace the Python boolean-operation workaround in ZTools_EnhancedPocket with a proper Create::FlipPocket C++ feature inheriting from PartDesign::ProfileBased.
Rationale: The current Python implementation creates a standard Pocket then applies a boolean Common. A native feature would integrate properly with the feature tree, support undo/redo correctly, and perform better on complex geometry.
Scope:
src/Mod/Create/App/FeatureFlipPocket.cpp-- Feature implementationsrc/Mod/Create/Gui/TaskFlipPocket.cpp-- Task panelsrc/Mod/Create/Gui/ViewProviderFlipPocket.cpp-- View provider- Update
ZTools_EnhancedPocketto createCreate::FlipPocketinstead of the workaround
Decision: Deferred. The Python approach is functional for current needs. Revisit when performance or feature-tree integration becomes a problem.
Phase 3: Datum C++ helpers -- NOT STARTED (SUPERSEDED)
Original goal: Create C++ geometry helper functions for datum calculations.
Current state: The Python implementation now uses FreeCAD's built-in Part::AttachExtension for automatic parametric updates. Each datum type maps to a native MapMode (FlatFace, ThreePointsPlane, NormalToEdge, etc.) with appropriate AttachmentSupport and AttachmentOffset. This eliminates the need for custom geometry calculations.
Decision: Superseded by the AttachExtension approach. Only tangent_to_cylinder still uses manual placement (requires a vertex reference not currently collected by the UI).
Phase 4: Theme system -- PARTIAL
Goal: Theme applies consistently at startup regardless of active workbench.
Current state: The Catppuccin Mocha theme is set as the default via the KindredCreate preference pack. Four copies of the QSS file exist and must be kept in sync manually:
resources/preferences/KindredCreate/KindredCreate.qss(canonical)src/Gui/Stylesheets/KindredCreate.qsssrc/Gui/PreferencePacks/KindredCreate/KindredCreate.qssmods/ztools/CatppuccinMocha/CatppuccinMocha.qss
Remaining work: Eliminate QSS duplication via build-time copy or symlinks. Move theme responsibility out of ztools and into the Create module.
Phase 5: Silo deep integration -- DONE
Goal: Silo commands available globally, not just in the Silo workbench.
Implementation: SiloMenuManipulator in src/Mod/Create/InitGui.py uses FreeCADGui.addWorkbenchManipulator() to inject Silo commands into the File menu and toolbar across all workbenches. Silo_ToggleMode provides a one-click swap of Ctrl+O/S/N between standard FreeCAD and Silo file commands.
Dock panels: Database Auth (1500ms) and Database Activity (4000ms) panels are created via deferred QTimers and docked in the right panel area.
Phase 6: Build system integration -- PARTIAL
Goal: CMake install rules for mods/ submodules so packages include ztools and Silo automatically.
CI/CD status: Release workflows (.gitea/workflows/release.yml) now build for Linux (AppImage + .deb), macOS (DMG for Intel + Apple Silicon), and Windows (.exe NSIS installer + .7z archive). Builds run on public runners in dockerized mode. Releases are triggered by v* tags. See docs/CI_CD.md for details.
Remaining work: CMake install rules should be formalized in src/Mod/Create/CMakeLists.txt so that cmake --install includes mods/ submodules without relying on the packaging scripts to copy them:
install(DIRECTORY ${CMAKE_SOURCE_DIR}/mods/ztools/ztools
DESTINATION ${CMAKE_INSTALL_DATADIR}/Mod/ztools)
install(DIRECTORY ${CMAKE_SOURCE_DIR}/mods/ztools/CatppuccinMocha
DESTINATION ${CMAKE_INSTALL_DATADIR}/Mod/ztools)
install(DIRECTORY ${CMAKE_SOURCE_DIR}/mods/silo/freecad/
DESTINATION ${CMAKE_INSTALL_DATADIR}/Mod/Silo)
install(DIRECTORY ${CMAKE_SOURCE_DIR}/mods/silo/silo-client/
DESTINATION ${CMAKE_INSTALL_DATADIR}/Mod/silo-client)
Design decisions
-
Create::namespace prefix. All Kindred Create features use this prefix to distinguish them from FreeCAD core. -
No upstream contribution. Kindred Create is a standalone product. This allows divergent design decisions without upstream coordination.
-
Silo server distributed separately. Users deploy the Silo server independently. Setup instructions live in
mods/silo/README.md. -
Version synchronization via submodule pins. ztools and Silo versions are pinned git submodule commits. Updates are deliberate:
cd mods/ztools && git pull origin main && cd ../.. git add mods/ztools && git commit -m "Update ztools submodule" -
Python-first approach. C++ extensions are deferred until Python cannot achieve the requirement. The AttachExtension approach for datums validated this strategy.
-
Graceful degradation. The Create module loads successfully even if submodules are absent. Each addon load is wrapped in try/except with console logging.