This skill should be used when the user asks to "create a 3D model with build123d", "design parametric parts", "use builder mode", "use algebra mode", "select faces or edges", "export STEP or STL", or works with build123d CAD programming.
Use this skill when the user says:
Use this skill when:
build123d is a Python-based parametric CAD library built on OpenCascade. It provides two distinct programming modes:
Core principle: Choose the mode that matches the modeling pattern. Use Algebra Mode for simple, direct construction. Use Builder Mode for complex, context-aware workflows.
from build123d import *
Note: While wildcard imports are generally discouraged, build123d scripts are typically self-contained and this is the standard pattern.
| Dimension | Objects | Operations |
|---|---|---|
| 1D | Line, Arc, Spline, Helix, Bezier | add(), offset(), mirror(), split() |
| 2D | Circle, Rectangle, Polygon, Ellipse | fillet(), chamfer(), offset(), extrude() |
| 3D | Box, Cylinder, Sphere, Cone, Torus | fillet(), chamfer(), loft(), revolve() |
| Aspect | Algebra Mode | Builder Mode |
|---|---|---|
| State | Stateless | Stateful contexts |
| Syntax | obj += part | with BuildPart(): |
| Objects | Explicit tracking | Implicit tracking |
| Locations | Manual transforms | Context-aware |
| Best for | Simple models | Complex workflows |
For detailed comparison, see references/mode-comparison.md.
from build123d import *
# Create objects explicitly
sketch = Circle(5)
sketch -= Pos(2, 0) * Circle(1)
# Extrude to 3D
part = extrude(sketch, amount=10)
# Modify with operators
part += Pos(0, 0, 10) * Cylinder(3, 5)
+= - Add/union-= - Subtract/difference* - Transform (Location * Shape)@ - Position along Edge/Wire (0.0 to 1.0)% - Tangent along Edge/Wire (0.0 to 1.0)^ - Location along Edge/Wire (0.0 to 1.0)Access shape topology with selectors that return ShapeLists:
# Get all faces
faces = part.faces()
# Filter by property
top_face = part.faces().sort_by(Axis.Z)[-1]
# Group and select
cylinders = part.faces().filter_by(GeomType.CYLINDER)
# Chain operations
edges = part.edges().filter_by(lambda e: e.length > 5).sort_by(Axis.X)
from build123d import *
with BuildPart() as part_context:
# 2D sketch on current plane
with BuildSketch() as sketch:
Rectangle(10, 10)
with Locations((3, 3)):
Circle(2, mode=Mode.SUBTRACT)
# Extrude pending sketch
extrude(amount=5)
# Operations on pending objects
fillet(edges().filter_by(Axis.Z), radius=0.5)
# Access result
final_part = part_context.part
BuildLine - 1D curves and wiresBuildSketch - 2D faces and sketchesBuildPart - 3D solids and partsLocations - Position multiple objectsGridLocations, PolarLocations, HexLocations - Pattern locationsControl how objects combine with context:
Circle(5, mode=Mode.ADD) # Union (default)
Circle(2, mode=Mode.SUBTRACT) # Difference
Circle(3, mode=Mode.INTERSECT) # Intersection
Circle(4, mode=Mode.REPLACE) # Replace all
Circle(1, mode=Mode.PRIVATE) # Create but don't add
Selectors return ShapeLists with powerful filtering methods:
# Basic selectors
vertices = part.vertices()
edges = part.edges()
faces = part.faces()
solids = part.solids()
# Filter by geometry type
circles = faces.filter_by(GeomType.CIRCLE)
planes = faces.filter_by(GeomType.PLANE)
# Filter by property
long_edges = edges.filter_by(lambda e: e.length > 10)
large_faces = faces.filter_by(lambda f: f.area > 50)
# Sort by axis/property
sorted_faces = faces.sort_by(Axis.Z)
by_area = faces.sort_by(Face.area)
# Group by property
grouped = faces.group_by(Axis.Z)
top_group = grouped[-1] # Highest Z group
bottom_group = grouped[0] # Lowest Z group
# Operators for filtering
top_faces = faces >> Axis.Z # Group by Z, get max
bottom_faces = faces << Axis.Z # Group by Z, get min
max_faces = faces > Axis.Z # Sort by Z, ascending
min_faces = faces < Axis.Z # Sort by Z, descending
planar = faces | GeomType.PLANE # Filter by type
# Extrude
solid = extrude(sketch, amount=10)
solid = extrude(sketch, amount=10, both=True) # Both directions
solid = extrude(sketch, amount=10, taper=5) # Tapered
# Revolve
solid = revolve(sketch, axis=Axis.X, angle=360)
# Loft between profiles
solid = loft([sketch1, sketch2, sketch3])
# Sweep along path
solid = sweep(profile, path)
# Fillet edges
part = fillet(part.edges().filter_by(Axis.Z), radius=1)
# Chamfer edges
part = chamfer(part.edges(), length=0.5)
# Full round (creates tangent blend)
sketch = full_round(sketch.edges(), radius=2)
# Union
result = part1 + part2
# Difference
result = part1 - part2
# Intersection
result = part1 & part2
# Create locations
loc = Pos(10, 0, 5) # Position
loc = Rot(45, 0, 0) # Rotation
loc = Pos(10, 5) * Rot(45) # Combined
# Apply to shapes
moved = loc * Circle(5)
# Planes for positioning
plane = Plane.XY # Standard planes
plane = Plane.XZ * Pos(10, 0, 0) # Offset plane
with BuildPart():
with Locations((0, 0, 0), (10, 0, 0), (0, 10, 0)):
Cylinder(2, 10) # Creates 3 cylinders
with GridLocations(5, 5, 4, 4):
Hole(1) # Creates 4x4 grid of holes
with PolarLocations(radius=10, count=6):
Box(2, 2, 5) # Creates 6 boxes in circle
# STEP (CAD interchange)
export_step(part, "model.step")
# STL (3D printing)
export_stl(part, "model.stl")
export_stl(part, "model.stl", tolerance=0.01) # Higher quality
# DXF (2D drawings)
export_dxf(sketch, "profile.dxf")
# SVG (2D graphics)
export_svg(sketch, "outline.svg")
# Import STEP
imported = import_step("existing.step")
# Import SVG (creates 2D sketch)
svg_sketch = import_svg("logo.svg")
# Import DXF
dxf_sketch = import_dxf("profile.dxf")
Create reusable parametric objects:
class CustomBracket(BasePartObject):
def __init__(
self,
width: float,
height: float,
thickness: float,
hole_dia: float,
mode: Mode = Mode.ADD,
):
with BuildPart() as bracket:
with BuildSketch():
Rectangle(width, height)
extrude(amount=thickness)
with Locations(Plane.XY.offset(thickness)):
with GridLocations(width-10, height-10, 2, 2):
CounterSinkHole(hole_dia, hole_dia*1.5)
super().__init__(part=bracket.part, mode=mode)
# Use custom object
part = CustomBracket(50, 30, 5, 4)
def create_gear(teeth: int, module: float, thickness: float):
"""Create parametric gear"""
pitch_radius = teeth * module / 2
with BuildPart() as gear:
with BuildSketch():
Circle(pitch_radius)
extrude(amount=thickness)
return gear.part
Most objects support align parameter:
# Align to center
Rectangle(10, 5, align=(Align.CENTER, Align.CENTER))
# Align to min corner
Box(10, 10, 10, align=(Align.MIN, Align.MIN, Align.MIN))
# Mixed alignment
Cylinder(5, 10, align=(Align.CENTER, Align.CENTER, Align.MIN))
from build123d import *
# Create assembly
assy = Assembly()
# Add parts with positions
assy.add(base_part, name="base")
assy.add(arm_part, name="arm", loc=Pos(10, 0, 20) * Rot(0, 45, 0))
# Access parts
base = assy["base"]
arm = assy["arm"]
Use ocp_vscode for live visualization:
pip install ocp-vscodeshow() or show_object() to display shapesfrom build123d import *
from ocp_vscode import show
part = Box(10, 10, 10)
show(part) # Displays in viewer
# Get properties
print(f"Volume: {part.volume}")
print(f"Area: {face.area}")
print(f"Length: {edge.length}")
# Get bounding box
bbox = part.bounding_box()
print(f"Size: {bbox.size}")
# Count topology
print(f"Faces: {len(part.faces())}")
print(f"Edges: {len(part.edges())}")
❌ Wrong:
fillet(part.edges(), 1) # Returns new object, part unchanged
✅ Correct:
part = fillet(part.edges(), 1) # Assign result
❌ Wrong:
with BuildPart():
box = Box(10, 10, 10)
result = box + Cylinder(5, 15) # Mixing Builder and Algebra
✅ Correct:
# Stay in Builder mode
with BuildPart():
Box(10, 10, 10)
Cylinder(5, 15, mode=Mode.ADD)
❌ Wrong:
face = part.faces() # Returns ShapeList, not single face
fillet(face, 1) # Error: needs edges
✅ Correct:
faces = part.faces() # ShapeList
top_face = faces.sort_by(Axis.Z)[-1] # Single face
edges = top_face.edges() # Edges of that face
build123d scripts commonly use wildcard imports:
✅ Correct:
from build123d import *
This is standard practice for build123d despite general Python conventions.
make_hull() instead of multiple boolean unions when applicablemake_face() for complex 2D profiles vs many boolean operationsreferences/api-quick-reference.md - Comprehensive object and operation referencereferences/mode-comparison.md - Detailed comparison of Builder vs Algebra modesexamples/algebra-mode-example.py - Complete parametric part in Algebra modeexamples/builder-mode-example.py - Complex assembly in Builder modeTo develop with build123d:
from build123d import *export_step(), export_stl(), etc.Focus on understanding the two modes, mastering selectors, and leveraging the operator-based syntax for clean, readable parametric CAD code.