The simplicity of OpenSCAD. The full power of Python.
Write parametric 3D models in real Python, see them live, and export them for 3D printing and manufacturing.
Download latest release All downloads
Releases on GitHub
Loading latest release…
Try in browser ↗ No install needed · Get started · Tutorial

A fork, and a superset of OpenSCAD
PythonSCAD is a fork of OpenSCAD that stays closely
synced with upstream. Everything OpenSCAD can do, PythonSCAD can do too: your
.scad files, libraries, and habits carry over unchanged.
On top of that, it adds features that don't fit OpenSCAD's deliberately minimal design: a full programming language, fillets, SDFs, point-cloud surfaces, and more. Those live here, so you don't have to choose between the two.
What PythonSCAD adds

Fillets and rounded seams
Round edges with fillet(), or round only the seams of a boolean with
union(a, b, r=2).

Sweep along any path
path_extrude() sweeps a profile along a 3D path, with twist, scaling, and
rounded corners.

SDF and implicit modeling
Built-in libfive for smooth blends and organic shapes that plain CSG cannot produce.

Lattices from a formula
Write a gyroid or any other implicit surface as a single math expression and get a printable lattice.

The whole pip ecosystem
pip is Python's free package library with hundreds of thousands of ready-made
add-ons. One pip install and they work in your model: this QR code comes
straight from the pyqrcode package.

Shapes from a point cloud
organic() wraps a cloud of points into a smooth, watertight solid —
sketch a knob, a grip, or a figure from a few coordinates.
One app, three languages
PythonSCAD runs your model in whichever language you prefer: plain Python,
classic OpenSCAD .scad code, or build123d once you import its module. Here
is the same desk organizer, sized automatically from a list of slots, in each
of them.
from pythonscad import *
# A desk organizer, sized from your own data
slots = {"pens": 14, "markers": 18, "ruler": 30}
wall = 6
length = sum(slots.values()) + wall * (len(slots) + 1)
tray = cube([length, 40, 20]).fillet(2, fn=8)
x = wall
for name, width in slots.items():
tray -= cube([width, 40 - 2 * wall, 20]) + [x, wall, 4]
x += width + wall
tray.show()
Ordinary Python: a dictionary, a for loop, sum(), and a one-line
fillet().
slots = [14, 18, 30]; // no dictionaries: the names are gone
wall = 6;
// no built-in sum(): write a recursive helper
function sum(v, i = 0) = i < len(v) ? v[i] + sum(v, i + 1) : 0;
function pos(i) = wall + sum([for (j = [0:1:i-1]) slots[j]]) + i * wall;
length = sum(slots) + wall * (len(slots) + 1);
difference() {
// no fillet(): approximate with a (slow) minkowski sum
translate([2, 2, 2])
minkowski() { cube([length - 4, 36, 16]); sphere(2, $fn = 16); }
for (i = [0 : len(slots) - 1])
translate([pos(i), wall, 4]) cube([slots[i], 40 - 2 * wall, 20]);
}
Existing .scad files open and render as they always did, but plain
OpenSCAD needs workarounds for the sum and the rounded edges.
from pythonscad import *
from build123d import *
from pybuild123d import build123d # ships with PythonSCAD
@build123d # turns the B-rep result into a PythonSCAD solid
def organizer(slots, wall=6):
length = sum(slots.values()) + wall * (len(slots) + 1)
with BuildPart() as tray:
Box(length, 40, 20, align=Align.MIN)
fillet(tray.edges(), radius=2)
x = wall
for width in slots.values():
with Locations((x, wall, 4)):
Box(width, 40 - 2 * wall, 20,
align=Align.MIN, mode=Mode.SUBTRACT)
x += width + wall
return tray
organizer({"pens": 14, "markers": 18, "ruler": 30}).show()
Install build123d with pip, and its models appear in the PythonSCAD
viewer, ready to combine with everything else.
Made for real workflows
| Runs in your browser | The full kernel compiled to WebAssembly. Try it without installing anything. Open the Playground ↗ |
| Jupyter notebooks | Model, document, and iterate inside a notebook next to your analysis. Jupyter setup |
| Your OpenSCAD libraries | Load existing .scad libraries such as MCAD with osuse() and call their modules from Python. osuse |
| Read any data format | Import STL, 3MF, OBJ, DXF, parse CSV, JSON, or even chip layouts (GDS) with plain Python and turn the data into geometry. GDS example |
| Handles and align | Attach named reference frames to parts and assemble them with align() instead of computing transformations by hand. Handles |
How does it compare?
| OpenSCAD | CadQuery / build123d | PythonSCAD | |
|---|---|---|---|
| Languages | OpenSCAD language | Python | Python, OpenSCAD, build123d |
| Variables, classes, dicts, file I/O | limited | ✓ | ✓ |
| pip packages (free Python add-ons: NumPy, qrcode, …) | – | ✓ | ✓ |
| Edge fillets | workarounds | ✓ | ✓ |
Reuse existing .scad libraries |
✓ | – | ✓ |
| Built-in editor, live preview, customizer | ✓ | separate tools | ✓ |
| SDF / implicit modeling | – | – | ✓ |
| Runs in the browser | ✓ | – | ✓ |
| Geometry kernel | mesh | B-rep (STEP export) | mesh |
Need exact B-rep geometry and STEP files for mechanical CAD exchange? CadQuery and build123d are great choices. Want OpenSCAD's quick, script-to-print workflow with a real programming language behind it? That's PythonSCAD.
Is PythonSCAD for you?
A great fit if you…
- think in code and want precise, repeatable parametric models
- already know Python — or want to learn Python or programming through something tangible
- have OpenSCAD designs and libraries but keep hitting the limits of its language
- need models for 3D printing, CNC, or engineering workflows
Probably not the right tool if you…
Learn more
- Download for your platform — or use the button above
- Installation — APT/YUM repos, AppImage, PyPI, and build options
- Getting Started tutorial — hands-on walkthrough
- Coming from OpenSCAD? — what changes and what stays
- Cheat sheet, Examples gallery, and API reference
Community
- PyForge — share and remix PythonSCAD designs
- r/OpenPythonSCAD
- Google Group
- Community wiki
- IDE and type-checker setup
- Contact & support
PythonSCAD is open source on GitHub. It builds on the solid foundation of OpenSCAD and stays closely synced with upstream; Python-specific features are developed here. See Upstream sync.