Build123d is a Python-based, parametric (BREP) modeling framework for 2D and 3D CAD. Built on the Open Cascade geometric kernel, it provides a clean, fully Pythonic interface for creating precise models suitable for 3D printing, CNC machining, laser cutting, and other manufacturing processes. Models can be exported to popular CAD tools such as FreeCAD and SolidWorks.
Designed for modern, maintainable CAD-as-code, build123d combines clear architecture with expressive, algebraic modeling. It offers:
With build123d, intricate parametric models can be created in just a few lines of readable Python code—as demonstrated by the tea cup example below.
from build123d import * from ocp_vscode import show wall_thickness = 3 * MM fillet_radius = wall_thickness * 0.49 with BuildPart() as tea_cup: # Create the bowl of the cup as a revolved cross section with BuildSketch(Plane.XZ) as bowl_section: with BuildLine(): # Start & end points with control tangents s = Spline( (30 * MM, 10 * MM), (69 * MM, 105 * MM), tangents=((1, 0.5), (0.7, 1)), tangent_scalars=(1.75, 1), ) # Lines to finish creating ½ the bowl shape Polyline(s @ 0, s @ 0 + (10 * MM, -10 * MM), (0, 0), (0, (s @ 1).Y), s @ 1) make_face() # Create a filled 2D shape revolve(axis=Axis.Z) # Hollow out the bowl with openings on the top and bottom offset(amount=-wall_thickness, openings=tea_cup.faces().filter_by(GeomType.PLANE)) # Add a bottom to the bowl with Locations((0, 0, (s @ 0).Y)): Cylinder(radius=(s @ 0).X, height=wall_thickness) # Smooth out all the edges fillet(tea_cup.edges(), radius=fillet_radius) # Determine where the handle contacts the bowl handle_intersections = [ tea_cup.part.find_intersection_points( Axis(origin=(0, 0, vertical_offset), direction=(1, 0, 0)) )[-1][0] for vertical_offset in [35 * MM, 80 * MM] ] # Create a path for handle creation with BuildLine(Plane.XZ) as handle_path: Spline( handle_intersections[0] - (wall_thickness / 2, 0), handle_intersections[0] + (35 * MM, 30 * MM), handle_intersections[0] + (40 * MM, 60 * MM), handle_intersections[1] - (wall_thickness / 2, 0), tangents=((1, 1.25), (-0.2, -1)), ) # Align the cross section to the beginning of the path with BuildSketch(handle_path.line ^ 0) as handle_cross_section: RectangleRounded(wall_thickness, 8 * MM, fillet_radius) sweep() # Sweep handle cross section along path assert abs(tea_cup.part.volume - 130326) < 1 show(tea_cup, names=["tea cup"])