A Python library for 3D modeling on the SMLib NURBS kernel. The API follows the style of build123d's algebra mode and shares a few ideas with CadQuery, but not its method chains: shapes are plain values, and every operation returns a new one.
It comes with an MCP server, so your agent can build parts too. And it runs in the browser: smlibwasm is the same library for JavaScript and TypeScript, on the kernel compiled to WebAssembly.
Website · Documentation · Getting started · API reference · For agents · JavaScript
from smlibpy import *
plate = Box(80, 60, 10)
plate = plate.fillet(plate.edges().parallel_to(Z), 8)
plate -= GridLocations(60, 40, 2, 2) * Cylinder(4, 10)
plate -= Rectangle(30, 20).on(plate.faces().top()).extrude(-4)
plate.export("plate.step")
show(plate)Parts are B-reps with exact surfaces: planes, cylinders, cones, spheres, tori and NURBS.
Volumes, areas and inertia are integrated over those surfaces, and STEP files keep them as they
are. You combine shapes with +, - and &, and every feature returns a new part. Faces and
edges are picked by their geometry, for example part.faces().top() or
part.edges().parallel_to(Z).concave(). The plate above builds in about 40 ms. The
concepts explain shapes, planes, locations and selections.
- Primitives:
Box,Cylinder,Cone,Sphere,Torus,Wedge - Holes:
Hole,CounterBoreHole,CounterSinkHole, placed withLocations,GridLocations,PolarLocations,HexLocations - Booleans:
fuse,cut,intersect, which can also be written+,-,&;mergemakes one part of several cells (as for several materials),cells()gives them back - Operations:
extrude(also tapered),revolve,loft,sweep(also along helices),shell,offset,thicken,draft,mirror,split,section - Fillets: circular, variable radius, and curvature-continuous (G2/G3); chamfers
foldandflangewith exact bends (radius and K-factor)unfold, andflat_patternwith bend linesbends(),bend_allowance,bend_deduction,developed_length
twist,taperandbendwork on finished parts. A tapered cylinder becomes an exact cone.- Free-form deformation with a
Lattice
Simplifying: remove_fillets and remove_faces take out fillets, holes and bosses, also on
imported parts. faces().fillets() finds the fillet faces.
Molding: draft tilts walls, pockets and holes by a draft angle about a neutral plane.
draft_analysis sorts each face for a pull direction into positive, insufficient, vertical or
undercut. parting_line finds the parting line.
2D (sketches)
Profileis a pen: it draws lines and tangent arcs, turns, and adds fillets and chamfers at corners as it goes.- Shapes:
Rectangle,RoundedRectangle,Circle,Ellipse,Polygon,RegularPolygon,Triangle,Trapezoid,Slot,ArcSlot,Hull, andStroke(a band along a path). The polygon shapes takefillet=andchamfer=. - Exact 2D Booleans, offsets, and corner fillets and chamfers. Sketches can be extruded, revolved and swept.
Textwith exact font outlines (the Lato font is included)
- Curves:
Line,Polyline,PolarLine,CenterArc,ThreePointArc,RadiusArc,SagittaArc,TangentArc,EllipticalArc,Spline,Bezier,Helix,FilletPolyline; their NURBS data (nurbs()),make_compatible,remove_knots - Surfaces:
surfacethrough a grid of points or fitted to a cloud of points (a scan),ruled,surface_fillet(a round blend between two sheets),stitch(faces into a solid),to_nurbs
- By position (
top(),bottom(),nearest(), …), by size (largest(),smallest()), and by geometry (lines(),circles(),planar(),cylinders(),parallel_to(),facing(),convex(),concave(),fillets(), …) filter_by,sort_by,group_by, set operators between lists, andneighbors()of a facehit_by(): the faces a ray meets, nearest first
volume,area,centerandmass_properties(inertia, principal axes), computed from the exact surfaces to seven significant digits, with an error estimatedistance_to,closest_point,raycast,intersection_curves,silhouette,project,outline, edge radius and convexityis_validandheal(). Every kernel result is checked, and a fillet or shell that can't work raises an error that says what would fit.
- STEP in and out: exact geometry, assemblies, units, names and colors (
named(),colored());read_stepalso reads coordinate systems, curves and points - USD in and out: exact bodies as the
BrepArrayprims of NVIDIA's usd-brep (Omniverse), with names and colors, meshes for plain viewers - DXF in and out with exact arcs and splines; STL in and out; glTF/GLB and OBJ out; Booleans of
meshes (
+,-,&), also of STL files - SMLib's own format (
save,load)
render()needs no GPU or browser:- shaded views, and sheets of 2 or 4 views
- technical drawings in first-angle (ISO E) or third-angle (ISO A) projection, with dashed hidden lines and center lines
- sections, x-ray, highlights, markers, a measurement overlay, zebra stripes and curvature maps
diff_imagescompares two renders.show()opens a 3D viewer in the browser or a notebook.
- The MCP server
smlibpy-mcpshows the session live in Buerligons, where what you select reaches the agent; it has snapshots, function search and a tested guide for every function. People who want parametric apps that rebuild from sketches and features are sent to the ClassCAD MCP. - A Claude Code plugin, installed from this repository (see below)
pip install smlibpyThere are wheels for Linux (x86_64, aarch64), macOS (arm64, x86_64) and Windows, for Python
3.10 to 3.14, with the kernel compiled in. They are 5 to 7 MB, and numpy is the only
dependency. For agents, pip install "smlibpy[mcp]" adds the MCP server; see
AI agents.
To build from source you need CMake and a C++17 compiler (about a minute on a laptop):
git clone --recursive https://github.com/awv-informatik/smlibpy
cd smlibpy
pip install .The MCP server lets Claude and other agents model with smlibpy. In Claude Code:
claude plugin marketplace add awv-informatik/smlibpy
claude plugin install smlibpy@smlibpyOther hosts start uvx --from "smlibpy[mcp]" smlibpy-mcp; see AI agents. The
agent works in four steps:
- A skill tested on the real kernel: every function has a guide, written by agents that ran each call and wrote down what they found. The server hands the guides out, and its search knows CAD synonyms.
- One script per step: the agent writes a whole step as a Python script and runs it. The session keeps the model between scripts; a kernel crash costs a restart, and the session is rebuilt from the scripts that made it.
- A renderer to look with:
snapshotdraws the model in software, as technical drawings with hidden lines, sections, x-ray, highlighted selections, markers, zebra stripes or curvature maps. - Loops until it is right: after every step the agent checks numbers and pictures, fixes what is off, compares before and after on a pinned frame, and goes back to a checkpoint when a step fails.
smlibwasm (@classcad/smlibwasm on npm) is smlibpy for JavaScript and TypeScript: the same API on
the same kernel, compiled to WebAssembly. It runs in the browser and in Node, without a server and without dependencies.
npm install @classcad/smlibwasmimport { Box, Cylinder, GridLocations, Z, toStep } from '@classcad/smlibwasm'
let plate = Box(80, 60, 10)
plate = plate.fillet(plate.edges().parallelTo(Z), 8)
plate = plate.cut(GridLocations(60, 40, 2, 2).mul(Cylinder(4, 10)))
const step = toStep(plate) // the STEP file as textNames are camelCase, keyword arguments become an options object, and operators become methods
(a.cut(b) for a - b). A browser loads about 1.9 MB with brotli: 1.6 MB for the kernel
(smlibwasm.wasm, 6.5 MB uncompressed) and 0.3 MB for the library and its font. The
JavaScript docs have the sizes, examples for the browser and the whole API in
TypeScript; the source is in js/.
Sketches are 2D regions. Place them on a plane or a face, then extrude, revolve, loft or sweep them.
profile = Polygon((25, 0), (60, 0), (60, 12), (35, 12), (35, 40), (25, 40))
flange = profile.on(Plane.front).revolve(Z)
flange -= PolarLocations(47.5, 8) * Cylinder(5, 30)Lettering is a sketch with the exact outlines of a font; size is the height of the capitals.
tag = Box(60, 20, 3)
tag -= Text("SMLIB 01", 8).on(tag.faces().top()).extrude(-0.5)Selectors chain and always return lists. A list with one element works wherever a single shape is expected.
flange = flange.fillet(flange.edges().concave(), 4)
flange = flange.chamfer(flange.faces().top().edges().circles(), 1)Fillets can be circular, vary in radius, or be curvature continuous.
box = Box(30, 20, 10)
soft = box.fillet(box.edges(), 3, continuity="G2")
ramp = box.fillet(box.edges().parallel_to(Z).first, (1, 4))Open curves make surfaces. You can stitch them, thicken them, or start from a grid of points.
import math
grid = [[(x, y, 4 * math.sin(x / 15) * math.cos(y / 15)) for x in range(0, 60, 10)] for y in range(0, 50, 10)]
panel = surface(grid).thicken(2)mp = flange.mass_properties(density=7.85e-3) # steel, g/mm³
mp.mass, mp.center, mp.inertiaSTEP, USD, DXF, STL, glTF/GLB, OBJ and SMLib's own exact format.
export_step([flange, panel.named("panel")], "parts.step")
export_glb(flange, "flange.glb")
export_dxf(flange.section(Plane.XZ), "flange-profile.dxf")The documentation is on smlibpy.classcad.ch:
- Getting started
- Concepts: shapes, planes, locations, selections
- Sketches, parts, features, deformations, selecting, surfaces, sheet metal
- Measuring and analysis, files and pictures
- AI agents: the MCP server, so Claude and other agents can model with smlibpy
- JavaScript: smlibwasm, on the kernel compiled to WebAssembly
- Examples
- The kernel: how smlibpy uses SMLib, accuracy, limitations
- API reference
smlibpy is new (version 0.3). It covers solid and surface modeling, text, and reads and writes STEP, USD and DXF with the exact geometry; smlibwasm has all of it in JavaScript. Assemblies with product structure and dimensioned 2D drawings are not there yet.
smlibpy and smlibwasm are MIT licensed. They build and bundle the SMLib kernel from NVIDIA-Omniverse/usd-brep, © NVIDIA, under the Apache License 2.0; see NOTICE.
