FreeCAD OpenCASCADE B-Rep, Printable STL & 3D Viewer Skill (`freecad-step-builder`)
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 (<ProjectName>).
This skill governs parametric 3D OpenCASCADE B-Rep solid modeling, boolean interference verification, .step/.stl export, and standalone interactive 3D WebGL viewer generation (<ProjectName>_3D_Assembly_Viewer.html) for any CAD project (<ProjectName>) 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.
- Check
.cad-tools.jsonin the workspace root for"freecad_cmd"(or check if the user already provided the FreeCAD command/path in the conversation or projectAGENTS.md). - 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 <script.py> - Native package:
freecadcmd <script.py>orFreeCADCmd <script.py> - AppImage / Custom path:
/path/to/FreeCAD.AppImage -c <script.py> - Or Not installed (use
SolidCraftonly).
- Flatpak:
- Save the command in
.cad-tools.jsonand guard script entrypoints with:
becauseif __name__ in ("__main__", "<script_stem>"): build_and_export()FreeCADCmdsets__name__to the script filename stem rather than"__main__".
1. Standard Project Output Structure (<ProjectName>)
Blueprint-First Gate: Do NOT build 3D FreeCAD solids until the 1:1 mm orthographic 2D SVG blueprints (
<ProjectName>_Side_View.svg,<ProjectName>_Front_View.svg,<ProjectName>_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 <ProjectName>/CAD/:
| Deliverable Type | Path Pattern | Purpose |
|---|---|---|
| Parametric FreeCAD Project | CAD/<ProjectName>_Full_Assembly.FCStd & CAD/FCStd/<PartName>.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/<PartName>.step |
Exact OpenCASCADE B-Rep solid for CAD interchange. |
| Individual Component STL | CAD/STL/<PartName>.stl |
High-resolution watertight mesh (LinearDeflection=0.15, AngularDeflection=0.35) for 3D printing. |
| Sub-Assembly STEP | CAD/STEP/<ProjectName>_Parts_Assembly.step |
Multi-body STEP assembly of all printable components. |
| Full Hardware Assembly | CAD/STEP/<ProjectName>_Full_Assembly.step |
Complete assembly including host hardware and payload reference solids. |
| Interactive 3D WebGL Viewer | <ProjectName>_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):
- Create a Parametric
Spreadsheet::Sheet(Params):- Add a
Spreadsheet::Sheetnamed"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 viasheet.setAlias("B2", "fan_hole_spacing").
- Add a
- Build Each Component as a Separate
PartDesign::Body:- Create one
PartDesign::Bodyper printable part (doc.addObject("PartDesign::Body", part_name)). - Add sequential features inside each
PartDesign::Bodyso a human opening the.FCStdfile 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_<FeatureName>"), attach to the appropriate plane (XY_Plane,XZ_Plane,YZ_Planeor a datum plane offset), add closed wire geometry (Part.LineSegment,Part.Circle,Part.ArcOfCircle), and applySketcher.Constraint('Coincident', ...)constraints. - Step B (
PartDesign::PadAdditive Extrusion):pad = body.newObject("PartDesign::Pad", "Pad_<FeatureName>"), setpad.Profile = sk,pad.Length = ...(or bind to spreadsheet viapad.setExpression("Length", "<<Params>>.wall_thickness")). - Step C (
PartDesign::PocketSubtractive Cutout / Bore / Duct / Mortise):pocket = body.newObject("PartDesign::Pocket", "Pocket_<FeatureName>"), setpocket.Profile = sk_cut,pocket.Type = 0(Dimension) or1(ThroughAll), andpocket.Reversed = True/False.
- Step A (
- Create one
- 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::DocumentObjectGroupnamed"Reference_Hardware"so they are cleanly separated from the editablePartDesign::Bodycomponents.
- Place non-printed reference hardware solids (e.g., SBC board + heatsink, PSU brick, 120 mm fans, host printer) inside a
3. Technical CAD & DFM Design Patterns (User Intent to Engineering Implementation)
- Step-by-Step
PartDesign::BodySketch-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::Pocketsteps inside each part'sPartDesign::Body.
- Construct cantilever webs, fan shrouds/plenums, PSU cradles, snap-fit clips, clevis hooks, and dovetail tenons/mortises as individual named
- 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.
- 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.
- 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.
- 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.
- 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.
- 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.
- 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() == Trueandsolid.Volume > 0for 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).
- Assert
- Gate 2 (Conditional Print Bed Bounding-Box Gate ONLY when
"is_3d_printed": true):- When
"is_3d_printed": truein.cad-tools.json, assertbbox.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.
- When
