SCADwright is a Python library for designing 3D models. You write Python code that describes shapes, transforms, and combinations; SCADwright writes an OpenSCAD source file (.scad); OpenSCAD renders that file into STL or other formats.
If you've used OpenSCAD before, the shapes and operations will look familiar. The language around them is Python, which gives you classes, functions, automated tests, and proper error messages.
If you haven't used OpenSCAD, the basic idea is:
- Start with primitive shapes (cubes, spheres, cylinders).
- Move them around with transforms (translate, rotate, scale).
- Combine them with boolean operations (union, difference, intersection).
- The result is a 3D shape you can save and 3D-print.
This quick guide shows you how a project can organically grow from very simple OpenSCAD-like code to levaraging more complex constructs like reusable Components and variants without having to re-write anything.
Example projects arranged from simplest to most complex, each building on the last: from flat OpenSCAD-like scripts up to multi-file projects around shared specs.
Reading them in order is a guided tour of the constructs in context.
- Coming from OpenSCAD — SCAD features (for, if, let, modules,
$t,$preview, etc.) mapped to their SCADwright/Python equivalents - How is SCADwright different? — comparison with SolidPython, PythonSCAD, CadQuery, Build123d, JSCAD, and plain OpenSCAD
- 3D primitives —
cube,sphere,cylinder,polyhedron - 2D primitives —
square,circle,polygon - Transformations — moving, rotating, scaling, coloring shapes
- Boolean operations — combining shapes (
union,difference,intersection,hull,minkowski) - Extrusions — turning 2D shapes into 3D (
linear_extrude,rotate_extrude) - Math —
scadwright.mathSCAD trig (in degrees). Python trig works fine too. - Animation and viewpoints —
t()for$t-driven shapes,cond()for ternary,viewpoint()for the default camera. See also Morph for one-line animation between variants. - Using existing SCAD files — emitting
use <...>/include <...>at the boundary to an existing SCAD codebase
Core concepts
- Components — your own parametric parts as classes (replaces OpenSCAD modules)
- Composition helpers —
mirror_copy,rotate_copy,linear_copy,multi_hull,sequential_hull - Variants — print vs. display, multi-part assemblies, section views, resolution tiers
- Shape library — 50+ ready-made Components: tubes, gears, fasteners, bearings, infill panels, and more
- Anchors — the data type (named attachment points), authoring custom anchors on Components
- Attaching shapes —
attach()to position parts relative to each other - Text on a surface —
add_text()for raised or inset labels on a face, wall, or rim - A 2D profile on a surface —
wrap_2d()for an SVG logo, polygon, or outline as relief - Eliminating epsilon overlap —
through()for cutters,attach(fuse=True)for joints - Custom transforms — adding your own verbs (e.g.
.chamfer_top(depth=1)) - Specs — shared dimensions across parts in a single source of truth
- Morph — one-line animations between two variants, exported as APNG for READMEs. See also Animation and viewpoints for the lower-level
$ttoolkit.
Workflow
- Resolution — controlling smoothness (
fn/fa/fs), precedence rules - Errors and logging — what SCADwright does when something's wrong, plus
echofor render-time output - Command line —
scadwright build/preview/render, script parameters - Project dependency graph —
scadwright graphprints a map of how Components, Specs, and Designs relate, as text or JSON - Preview performance —
force_renderfor slow or flickering OpenSCAD previews - Testing —
tree_hashfor regression pinning, geometry assertions, golden-file patterns
Advanced
- Adjustments — printer-error fudges recorded inline alongside the equations they correct
- Bounding boxes and tests — measuring parts and writing tests
- Matrix — 4×4 transform math for advanced placement calculations
A compact one-page reference of the whole public API — imports, primitives, transforms, CSG, extrusions, components, resolution, variants, math, matrix, bbox, CLI. Start here when you know what you want and just need the syntax.
- Vector arguments (positions, sizes) accept either a list
[x, y, z]or keyword argumentsx=, y=, z=. Both forms work everywhere. - Scalar shorthand.
cube,square, andscaleaccept a single number as shorthand for "same on every axis" —cube(5)meanscube([5, 5, 5]). Other vector-taking operations (translate,mirror,resize) require an explicit vector because a scalar would be ambiguous there ("translate 5 along which axis?"). - Lowercase names like
cubeorcylinderare basic shapes (functions). Capitalized names likeTubeorComponentare classes. - Chained methods like
.translate(...)or.red()create a new shape; the original is unchanged. - Errors include the file and line of the call that produced them.
The public API is split into small, focused submodules. Import what you need:
scadwright.primitives—cube,sphere,cylinder,polyhedron,square,circle,polygonscadwright.boolops—union,difference,intersection,hull,minkowskiscadwright.transforms— standalonetranslate/rotate/scale/mirror/color/resize+ the custom-transform decoratorscadwright.extrusions—linear_extrude,rotate_extrudescadwright.composition_helpers—linear_copy,rotate_copy,mirror_copy,multi_hull,sequential_hullscadwright.shapes— higher-level parametric parts (Tube,Funnel,RoundedBox,Arc,Sector, etc.)scadwright.math— trig and numeric helpers matching OpenSCAD semanticsscadwright.errors—ValidationError,BuildError,EmitError,SCADwrightErrorscadwright.asserts— geometry assertions for tests
The root namespace (from scadwright import ...) keeps the Component authoring surface (Component, Param, Spec, Adjustment, validators) and top-level tools (bbox, tree_hash, emit, render, resolution, variant, etc.).
Transforms also exist as chained methods on every shape (cube(10).translate([5, 0, 0])), which usually reads better for simple expressions; the standalone translate(cube(10), [5, 0, 0]) form is available for cases where the subject is a complex expression already.
Style guide — conventions for writing idiomatic SCADwright code: preferred patterns (equations, directional helpers, attach/through), when lower-level alternatives are justified, and common anti-patterns. Worth reading before authoring Components or contributing to the shape library.
It's also particularly useful to drop into an LLM's context when using AI assistance — it steers generated code away from generic-Python habits toward SCADwright's idioms.