-
Notifications
You must be signed in to change notification settings - Fork 1
CADSmith
The cadsmith module handles parametric CAD generation, geometry extraction, asset generation, and assembly layout. All CAD scripts use build123d and execute in an isolated uv environment.
| Tool | Description |
|---|---|
cadsmith_run_script |
Execute a build123d Python script in an isolated uv env with pre- and post-execution validation |
cadsmith_extract_part |
Extract volume, surface area, bounding box, centre of mass from a STEP or BREP file; writes gui/parts/<name>.json to the project directory. Optional out_path overrides the output location. |
cadsmith_generate_assets |
Generate visualization assets for a STEP file: isometric PNG thumbnail, 360° rotating isometric GIF, and/or 360-frame ASCII loading animation; writes to gui/assets/ in the project directory. Optional out_dir overrides the output directory. |
cadsmith_assembly |
Generate or read assembly.json -- the spatial layout of parts for the 3D viewer; writes to the project directory. Optional out_path overrides the output location. |
cadsmith_bd_warehouse_info |
Instantiate a bd_warehouse parametric part and return dimensional attributes; exports STEP and Part JSON to the project directory. Optional out_path overrides the STEP output location. |
The Part model (cadsmith/models.py) uses pintdantic for unit-aware geometry fields:
class Part(QuantityModel):
name: str
stl_path: str | None
step_path: str | None
brep_path: str | None
bounding_box: UnitVector | None # (x, y, z) extents in mm
color: str = "#cccccc"
cost: float | None
description: str | None
id: str | None
volume: QuantityField | None # mm^3
surface_area: QuantityField | None # mm^2
center_of_mass: UnitVector | None # (x, y, z) in mm
mass: QuantityField | None # g or kgPart also has an optional display_name field for human-readable names (e.g. "Nose Cone").
AssemblyPart references a part JSON file instead of duplicating part data:
class AssemblyPart(QuantityModel):
part_file: str # e.g. "gui/parts/nose_cone.json"
position: UnitVector
rotation: UnitVector
color: str = "#cccccc"
invert_z: bool = False # flip 180° around X (e.g. nose cones)
joint_offset: QuantityField | None # shoulder overlap in mmAn Assembly holds a list of AssemblyPart references plus total_length. The assembly generator computes positions accounting for shoulder overlaps (joint_offset) so parts interlock correctly.
UnitVector is a shared 3D vector model with unit-aware components (default: mm):
class UnitVector(QuantityModel):
x: QuantityField = (0.0, "mm")
y: QuantityField = (0.0, "mm")
z: QuantityField = (0.0, "mm")Two class methods:
-
UnitVector.from_vector(v, precision=3)-- create from a build123dVectororBoundBox.size, rounding to the given precision. -
UnitVector.deg(x=0, y=0, z=0)-- create a vector in degrees (used for rotation fields in assembly parts).
validate_script.py performs AST-level checks before executing any build123d script:
-
Export checks -- the script must call
export_step(). STL files are generated separately bycadsmith_generate_assets. -
Import allowlist -- only
build123d,bd_warehouse,pathlib,math, andtypingare permitted. Any other import is rejected.
After execution, cadsmith_run_script also performs post-run validation: it verifies that non-empty .step files were actually written to the output directory.
Pre-run: AST parse -> check export calls -> check imports
Execute: uv run --isolated --with build123d <script.py>
Post-run: verify .step files exist and are non-empty
cadsmith_generate_assets produces up to three output types for a given STEP file. All three read directly from the STEP and run in parallel with STL generation via a ThreadPoolExecutor. The outputs parameter controls which types are generated; it defaults to all three.
| Output | Format | Path | Description |
|---|---|---|---|
thumbnail |
PNG | gui/assets/png/<part_name>.png |
Single isometric view |
gif |
GIF | gui/assets/gif/<part_name>.gif |
360° rotating isometric animation (36 frames, 10°/frame) |
ascii |
TXT | gui/assets/txt/<part_name>.txt |
360-frame text animation (1°/frame), used as a loading icon |
A gui/progress/<part_name>.json file tracks the status of each output type in real time so the GUI can display a progress bar:
{
"part_name": "nose_cone",
"outputs": {
"thumbnail": {"status": "done", "path": "gui/assets/png/nose_cone.png"},
"gif": {"status": "in_progress", "path": null},
"ascii": {"status": "pending", "path": null}
}
}Status values: pending, in_progress, done, failed.
The PreviewProgress class manages this file, flushing to disk on every update() call.
cadsmith_extract_part extracts geometric properties from a STEP file and writes a part JSON:
-
Input: STEP file path, optional material density, optional display name, optional
out_path -
Output:
Partobject with volume, surface area, bounding box, center of mass, and mass - Always writes
gui/parts/<name>.jsonto the project directory;out_pathoverrides the destination
The part JSON serves as the single source of truth for part metadata, referenced by assembly.json and displayed in the GUI's part detail pages.
cadsmith_assembly supports two actions:
Reads the component tree and STEP files to compute a spatial layout:
- Extracts bounding boxes from each STEP file via
extract_part()and writes part JSONs togui/parts/. - Stacks parts along the Z axis, accounting for shoulder overlaps (
joint_offset) so parts interlock correctly. - Sets
invert_z=trueon nose cones (built shoulder-down for printing, displayed tip-forward). - Each
AssemblyPartreferences apart_file(e.g.gui/parts/nose_cone.json) instead of duplicating geometry data. - Writes
gui/assembly.json.
Loads and returns an existing gui/assembly.json.
The resulting Assembly model contains schema_version, project_root, generated_at, parts (list of AssemblyPart), and total_length.