--- name: freecad-step-builder description: Parametric 3D CAD solid modeling skill using headless FreeCAD OpenCASCADE (FreeCADCmd) to generate watertight STEP, FCStd, printable STL files, and standalone 3D WebGL assembly viewers for any CAD project (). --- # FreeCAD OpenCASCADE B-Rep, Printable STL & 3D Viewer Skill (`freecad-step-builder`) This skill governs parametric 3D OpenCASCADE B-Rep solid modeling, boolean interference verification, `.step`/`.stl` export, and standalone interactive 3D WebGL viewer generation (`_3D_Assembly_Viewer.html`) for **any CAD project (``)** using headless FreeCAD (`FreeCADCmd`). --- ## 0. Step 0: Resolve `FreeCADCmd` via `.cad-tools.json` or User Prompt **Do NOT search the filesystem to guess how FreeCAD is installed.** 1. Check `.cad-tools.json` in the workspace root for `"freecad_cmd"` (or check if the user already provided the FreeCAD command/path in the conversation or project `AGENTS.md`). 2. If not yet configured, ask the user (or have the Designer / QA Inspector agent ask via `ask_question`) how FreeCAD is installed: - Flatpak: `flatpak run --command=FreeCADCmd org.freecad.FreeCAD ` - Native package: `freecadcmd ` or `FreeCADCmd ` - AppImage / Custom path: `/path/to/FreeCAD.AppImage -c ` - Or Not installed (use `SolidCraft` only). 3. Save the command in `.cad-tools.json` and guard script entrypoints with: ```python if __name__ in ("__main__", ""): build_and_export() ``` because `FreeCADCmd` sets `__name__` to the script filename stem rather than `"__main__"`. --- ## 1. Standard Project Output Structure (``) > **Blueprint-First Gate**: Do NOT build 3D FreeCAD solids until the 1:1 mm orthographic 2D SVG blueprints (`_Side_View.svg`, `_Front_View.svg`, `_Top_View.svg`) have been generated and reviewed by the user. All 3D deliverables are modeled in millimeters ($1\text{ unit} = 1.0\text{ mm}$) in assembled world coordinates inside `/CAD/`: | Deliverable Type | Path Pattern | Purpose | | :--- | :--- | :--- | | **Parametric FreeCAD Project** | `CAD/_Full_Assembly.FCStd` & `CAD/FCStd/.FCStd` | Native FreeCAD document with a `Params` **`Spreadsheet::Sheet`** and separate **`PartDesign::Body`** containers holding sequential `Sketcher::SketchObject` + `PartDesign::Pad` / `PartDesign::Pocket` features for human editing. | | **Individual Component STEP** | `CAD/STEP/.step` | Exact OpenCASCADE B-Rep solid for CAD interchange. | | **Individual Component STL** | `CAD/STL/.stl` | High-resolution watertight mesh (`LinearDeflection=0.15`, `AngularDeflection=0.35`) for 3D printing. | | **Sub-Assembly STEP** | `CAD/STEP/_Parts_Assembly.step` | Multi-body STEP assembly of all printable components. | | **Full Hardware Assembly** | `CAD/STEP/_Full_Assembly.step` | Complete assembly including host hardware and payload reference solids. | | **Interactive 3D WebGL Viewer** | `_3D_Assembly_Viewer.html` | Zero-dependency standalone HTML/WebGL viewer with Orbit/Pan/Zoom, Explode slider (`0%..100%`), camera presets, and per-part visibility toggles. | --- ## 2. Mandatory Step-by-Step Parametric `PartDesign::Body` Build History Standard **CRITICAL RULE: Never Export a Collapsed Static `Part::Feature` Solid as the Primary `.FCStd` Model**: Instead of fusing/cutting raw `Part.Shape` objects in Python memory and assigning the final shape to a single non-editable `Part::Feature` (`obj.Shape = final_shape`), **always construct each part as a native `PartDesign::Body` with a step-by-step feature history driven by a `Spreadsheet::Sheet` (`Params`)**: 1. **Create a Parametric `Spreadsheet::Sheet` (`Params`)**: - Add a `Spreadsheet::Sheet` named `"Params"` to the FreeCAD document and register every key dimension (board/payload lengths, fan hole spacing, PSU cradle width/height, wall thicknesses, clip overhangs, dovetail clearances) with human-readable labels in Column A, numeric values in Column B, and **aliases** via `sheet.setAlias("B2", "fan_hole_spacing")`. 2. **Build Each Component as a Separate `PartDesign::Body`**: - Create one `PartDesign::Body` per printable part (`doc.addObject("PartDesign::Body", part_name)`). - Add sequential features inside each `PartDesign::Body` so a human opening the `.FCStd` file in FreeCAD GUI sees every step in the Model Tree and can double-click any sketch or pad/pocket to edit it: - **Step A (`Sketcher::SketchObject`)**: `sk = body.newObject("Sketcher::SketchObject", "Sketch_")`, attach to the appropriate plane (`XY_Plane`, `XZ_Plane`, `YZ_Plane` or a datum plane offset), add closed wire geometry (`Part.LineSegment`, `Part.Circle`, `Part.ArcOfCircle`), and apply `Sketcher.Constraint('Coincident', ...)` constraints. - **Step B (`PartDesign::Pad` Additive Extrusion)**: `pad = body.newObject("PartDesign::Pad", "Pad_")`, set `pad.Profile = sk`, `pad.Length = ...` (or bind to spreadsheet via `pad.setExpression("Length", "<>.wall_thickness")`). - **Step C (`PartDesign::Pocket` Subtractive Cutout / Bore / Duct / Mortise)**: `pocket = body.newObject("PartDesign::Pocket", "Pocket_")`, set `pocket.Profile = sk_cut`, `pocket.Type = 0` (Dimension) or `1` (ThroughAll), and `pocket.Reversed = True/False`. 3. **Group Reference Hardware Separately**: - Place non-printed reference hardware solids (e.g., SBC board + heatsink, PSU brick, 120 mm fans, host printer) inside a `App::DocumentObjectGroup` named `"Reference_Hardware"` so they are cleanly separated from the editable `PartDesign::Body` components. --- ## 3. Technical CAD & DFM Design Patterns (User Intent to Engineering Implementation) 1. **Step-by-Step `PartDesign::Body` Sketch-to-Pad/Pocket Modeling**: - Construct cantilever webs, fan shrouds/plenums, PSU cradles, snap-fit clips, clevis hooks, and dovetail tenons/mortises as individual named `Sketcher::SketchObject` + `PartDesign::Pad` / `PartDesign::Pocket` steps inside each part's `PartDesign::Body`. 2. **Cantilever Snap-Fit Retention Clips & Overhang Ledges (`Snap-Fit Retention Tabs`)**: - *User intent*: *"Hold the power supply or board in place with overhangs or clips."* - *CAD implementation*: Model vertical **Cradle Side-Walls** that constrain lateral $(X, Y)$ translation, topped by **Cantilever Snap-Fit Retention Ledges (Overhang Hooks)** with a $1.5\text{ to }2.5\text{ mm}$ inward catch lip, a $30^\circ\text{--}45^\circ$ top **Lead-In Insertion Chamfer** (so the component snaps down past the flex tab during installation), and a $0.30\text{ mm}$ vertical/lateral clearance allowance around the payload envelope. 3. **Coplanar Build-Plate Datum Face (Zero-Stickout Flush Bosses)**: - *User intent*: *"Make the round hole part flush with the arm so it's flat on the bed to print."* - *CAD implementation*: Make the axial length of cylindrical mounting bosses equal to the structural web thickness and align their outer faces to be strictly **coplanar** ($\Delta X = 0$). Eliminating out-of-plane boss stickout ensures the entire outer side face serves as a flat $Z_{\text{print}} = 0$ build-plate datum requiring zero supports. 4. **Orthogonal Anti-Rotation Return Flange (Corner-Wrapping Reaction Pad)**: - *User intent*: *"Wrap the front corner so the sleeve on the round peg can't rotate."* - *CAD implementation*: Extending a $90^\circ$ **Orthogonal Return Flange** around the chassis corner onto a flat orthogonal datum face constrains rotation ($\theta = 0$) and resolves cantilevered bending moment ($M = F \cdot d$) into a tension-at-pin / compression-at-pad force couple. 5. **Interlocking Cleat & Shrouded Clevis Gravity Joint**: - *User intent*: *"Have the top piece hook straight down over the front leg."* - *CAD implementation*: Terminate the lower return flange in an upward **Male Cleat Tang** with a rear **Receiver Channel** and a lower **Horizontal Bearing Shoulder (Step Ledge)**. Form a mating **Female Clevis Saddle** on the upper cantilever rail flanked by **Axial Retention End-Cheeks (Shrouded Side Flanges)** that capture the cleat laterally and prevent the lower brace from sliding off its mounting boss. 6. **Shouldered Half-Lap Dovetail Ledger Joint (Blind Mortises + Integral Drop-In Tenons)**: - *User intent*: *"Have a lip that the center piece rests on with dovetails on top instead of separate bowties."* - *CAD implementation*: Step the inner mating edge into a **Lower Half-Lap Bearing Ledger** (carrying vertical shear in direct compression) and cut **Blind (Stopped) Female Dovetail Mortises** into the upper half. Extrude **Integral Male Dovetail Tenons** ($0.20\text{ mm}$ XY clearance allowance) on the ends of the spanning cross-member so it drops straight in from the top and locks lateral tension ($F_X$) and in-plane racking without separate butterfly/dutchman keys. 7. **Stepped Edge Rabbet Relief (`Rabbet` / `Rebate Cut`) for Overhanging Lids**: - *User intent*: *"Reverse L notch at the top back to clear a cover that overhangs the front by 5 mm."* - *CAD implementation*: Cut a two-sided rectangular **Edge Rabbet Relief** (e.g., $6\text{ mm}$ deep x $5\text{ mm}$ high) along the upper-rear edge to clear the overhanging cover lip while preserving a lower **Undercut Datum Contact Toe** that reaches back to bear against the primary machine datum plane. 8. **FDM Bore Shrinkage Allowance & Coaxial Flange Counterbore**: - *User intent*: *"Open up a tight spool holder hole by 0.5 mm radius."* - *CAD implementation*: Apply an **ISO Free-Running Slip-Fit Clearance Allowance** ($\Delta R = +0.50\text{ to }+0.80\text{ mm}$, or $+1.0\text{ to }+1.6\text{ mm}$ diametral clearance) on large FDM-printed bores ($\varnothing 30\text{--}75\text{ mm}$) to compensate for inner-perimeter shrinkage and seam bulge, paired with a coaxial **Counterbore** clearing the mounting base flange. --- ## 4. Dual Automated Verification Gates - **Gate 1 (Manifold & Zero-Clash Gate)**: - Assert `solid.isValid() == True` and `solid.Volume > 0` for every component. - Assert `part_solid.common(host_reference_solid).Volume < 0.001` ($0.0000\text{ mm}^3$ interference with the host machine, overhanging covers, doors, and keep-out envelopes). - Assert `part_i.common(part_j).Volume < 0.001` ($0.0000\text{ mm}^3$ boolean overlap across all mating components). - **Gate 2 (Conditional Print Bed Bounding-Box Gate ONLY when `"is_3d_printed": true`)**: - When `"is_3d_printed": true` in `.cad-tools.json`, assert `bbox.XLength <= SAFE_LIMIT and bbox.YLength <= SAFE_LIMIT and bbox.ZLength <= SAFE_LIMIT`. - When `"is_3d_printed": false` (e.g., Game Design, Digital Twin, CNC, or Unconstrained CAD), skip print-bed bounding-box limits.