Skip to content

The part script

One script per part, at parts/<name>/<name>.py. It is ordinary build123d Python with a few conventions, so every tool (and every agent) knows where to find the dimensions, the variants and the checks.

from dataclasses import dataclass
from build123d import Align, Box, Cylinder, Mode, Part
from b123d_print import View, Wall, hole_comp

BED = (Align.CENTER, Align.CENTER, Align.MIN)

@dataclass(frozen=True)
class Dims:                      # every dimension named, in mm, with its source
    W: float = 30.0              # typed measurement
    H: float = 8.0
    HOLE_D: float = 3.4          # M3 clearance, target printed size
    CBORE_D: float = 6.5
    CBORE_DEPTH: float = 3.0
    HOLE_COMP: float = hole_comp(__file__)   # from YOUR config, default 0

VARIANTS = {"": {}, "wide": dict(W=40.0)}   # overrides only

def build(d: Dims) -> Part:      # print orientation, bed at Z=0
    p = Box(d.W, d.W, d.H, align=BED)
    p -= Cylinder((d.HOLE_D + d.HOLE_COMP) / 2, 50, mode=Mode.PRIVATE)
    p -= Cylinder((d.CBORE_D + d.HOLE_COMP) / 2, d.CBORE_DEPTH, align=BED, mode=Mode.PRIVATE)
    return p

def views(d):                    # sections saved with every export
    return [View("XZ", 0.0, "through the hole")]

def checks(d):                   # how much material is left around the counterbore?
    return [Wall("", "XY", d.CBORE_DEPTH / 2, near=(0, 0), radius=d.W, label="around the counterbore")]

if __name__ == "__main__":
    from b123d_print import run
    run(__file__)

What a script defines

Name Required What
Dims by convention frozen dataclass; every dimension an UPPER_CASE field in mm with a comment saying where it came from; derived values as @property
VARIANTS no (default: only the standard part) {"": {}, "140": dict(PLATE_W=140.0)} — overrides only; "" is the standard part; output files get the key as a suffix
build(d) yes the printable part, or {"name": part} for several, in print orientation, bottom face on Z=0
assembly(d) no [(part, color, label), ...] in assembled position, plus simple stand-ins for what the parts mate with (a board, a sensor, a screw); the overlap check uses it
views(d) no [View(...)] cross-sections saved with every export
templates(d) no [Template.slice(...), Template.face_of(...), Template.crop(...)] fit-test templates written with every export (arguments)
checks(d) no [Wall(...), Overhang(...), Probe(...), ...] — see Checks API
original(d) no for a remix: the original model placed as the remix is; default: what build(d) loaded with import_model. The automatic checks also run on it, so its findings are labeled inherited, and before_after and export compare the remix with it

A script with only a module-level part = ... (no Dims) also works, without variants.

For the design review

Optional names the design review reads, in Dims (so a variant can override them) or at module level:

Name Example What
STYLE STYLE: str = "modern" functional, modern, least_cost, rugged or soft; "" (the template's) uses the workspace's style, else functional
SHOW SHOW = ["+Y", "+Z"] the sides seen in use, in print orientation; surface findings are limited to them
UP UP = "+Y" the side that points up in use (print orientation), for the water-trap check; default +Z
EDGES EDGES = "chamfer" the edge language: chamfer or fillet; functional with chamfer is the industrial look

Values from the user's config

Helper Use
hole_comp(__file__) HOLE_COMP: float = hole_comp(__file__); add it to hole diameters when cutting (Hole compensation)
clearance(__file__) CLEARANCE: float = clearance(__file__); the default mating gap (0.2 mm)
printer(__file__) the active printer profile, or None in generic mode

Starting from an existing model

Helper Use
import_model(path, scale?, max_triangles?, merge?, script?) an STL, 3MF or STEP as a solid to change: base = import_model("ref/bracket.stl"); paths are relative to the script's folder (ref/) or the workspace (refs/). See Remixing a part

Never hard-code a hole compensation from somewhere else; keep hole fields at the size you want printed.

new_part / b123d-print new start from a template with all of this in place. The rules for agents (and humans) writing scripts are in Workflow rules; the modeling API itself is in the build123d docs. For real parts, see the Examples.