OpenSCAD-based 3D modeling for programmatic generation of solid CAD models suitable for 3D printing. Use when generating mechanical parts, parametric designs, functional prototypes, geometric shapes, or any 3D printable models. Handles Constructive Solid Geometry (CSG) operations, primitive shapes (cube, sphere, cylinder, polyhedron), transformations (translate, rotate, scale), and export to STL/3MF formats. Ideal for AI-driven model generation where scripts are created and rendered headless.
OpenSCAD is a programmer's solid 3D CAD modeller that uses scripts to generate 3D models. Unlike interactive 3D tools, OpenSCAD models are described declaratively in code, making them ideal for AI-driven generation. Models are built from primitives (cube, sphere, cylinder) combined with boolean operations (union, difference, intersection) and transformed (translate, rotate, scale).
Constructive Solid Geometry (CSG): Combine simple shapes into complex models using boolean operations
union() - Combine multiple shapes into onedifference() - Subtract shapes from each otherintersection() - Keep only overlapping regionsPrimitives: Basic building blocks
cube(size=[x,y,z]) - Rectangular boxsphere(r=radius) - Spherecylinder(h=height, r=radius) - Cylinderpolyhedron(points, faces) - Arbitrary shapeTransformations: Position and orient shapes
translate([x,y,z]) - Move shaperotate([x,y,z]) - Rotate around axesscale([x,y,z]) - Resize shaperesize([x,y,z]) - Resize to specific dimensionsOpenSCAD Script (.scad)
↓
Preview (Fast, GPU, approximate)
↓
Full Render (Slow, CPU, exact)
↓
Export (STL, 3MF, OFF, DXF)
User Request
↓
Is this for 3D printing?
├── YES → Generate OpenSCAD script
│ ↓
│ Validate script syntax
│ ↓
│ Render preview (openscad -o preview.png input.scad)
│ ↓
│ Full render for export (openscad -o output.stl input.scad)
│ ↓
│ Return .stl + .scad + preview image
│
└── NO → May need Three.js (different skill)
or clarify user intent
// Resolution control for 3D printing quality
$fa = 1; // Minimum angle (degrees)
$fs = 0.4; // Minimum size (mm)
// Simple box
cube([20, 20, 10]);
// Sphere
sphere(r=10);
// Cylinder
cylinder(h=20, r=5);
// Union - combine shapes
union() {
cube([20, 10, 10]);
translate([20, 0, 0])
cube([10, 10, 10]);
}
// Difference - subtract shapes
difference() {
cube([20, 20, 10]);
translate([5, 5, -1])
cylinder(h=12, r=3);
}
// Intersection - keep overlap
intersection() {
cube([20, 20, 20]);
sphere(r=15);
}
// Translate
translate([10, 10, 0])
cube([10, 10, 10]);
// Rotate
rotate([90, 0, 0])
cylinder(h=20, r=5);
// Scale
scale([2, 1, 1])
sphere(r=10);
// Chain transformations
translate([10, 0, 0])
rotate([0, 90, 0])
cylinder(h=10, r=5);
module gear(teeth=8, radius=20, thickness=5) {
union() {
cylinder(h=thickness, r=radius);
for (i = [0:teeth-1]) {
rotate([0, 0, i * 360/teeth])
translate([radius, 0, 0])
cube([5, 3, thickness], center=true);
}
}
}
// Use module
gear(teeth=12, radius=15, thickness=3);
Use scripts/validate_openscad.py to check:
python3 scripts/validate_openscad.py model.scad
Returns:
openscad -o preview.png input.scad
openscad -o output.stl input.scad
| Format | Use Case | Command |
|---|---|---|
| STL | 3D printing (most common) | openscad -o model.stl input.scad |
| 3MF | Modern 3D printing (metadata + color) | openscad -o model.3mf input.scad |
| OFF | Simple ASCII format | openscad -o model.off input.scad |
| DXF | 2D drawings (laser cutter) | openscad -o model.dxf input.scad |
| PNG | Preview image | openscad -o model.png input.scad |
Always set resolution variables at the top:
$fa = 1; // Minimum angle: 1 degree
$fs = 0.4; // Minimum size: 0.4mm
$fa: Minimum angle for circle segments (lower = smoother)$fs: Minimum segment size (lower = finer detail)When shapes touch, ensure small overlap (0.001mm):
difference() {
cube([20, 20, 10]);
translate([5, 5, -0.001]) // Small overlap
cylinder(h=10.002, r=3);
}
Encapsulate complex geometry in modules:
module bolt_hole(length, diameter) {
cylinder(h=length, r=diameter/2);
}
// Use multiple times
difference() {
plate();
translate([10, 10, 0]) bolt_hole(10, 5);
translate([20, 10, 0]) bolt_hole(10, 5);
}
Make designs configurable:
module box(width=50, depth=50, height=20, wall_thick=2) {
difference() {
cube([width, depth, height]);
translate([wall_thick, wall_thick, wall_thick])
cube([width-2*wall_thick,
depth-2*wall_thick,
height]);
}
}
// Use with parameters
box(width=60, depth=40, height=15, wall_thick=3);
module hollow_box(width, depth, height, wall_thick) {
difference() {
cube([width, depth, height]);
translate([wall_thick, wall_thick, wall_thick])
cube([width-2*wall_thick,
depth-2*wall_thick,
height-wall_thick]);
}
}
module fillet(radius, length) {
difference() {
cube([radius, radius, length]);
translate([radius, radius, -1])
cylinder(h=length+2, r=radius);
}
}
module bracket(width=40, height=30, thickness=5, hole_diameter=8) {
difference() {
// L-shape
union() {
cube([width, thickness, thickness]);
cube([thickness, height, thickness]);
}
// Holes
translate([width/2, -1, thickness/2])
rotate([-90, 0, 0])
cylinder(h=thickness+2, r=hole_diameter/2);
translate([-1, height/2, thickness/2])
rotate([0, 90, 0])
cylinder(h=thickness+2, r=hole_diameter/2);
}
}
module gear(teeth=8, radius=20, thickness=5, hole_diameter=5) {
difference() {
union() {
// Main body
cylinder(h=thickness, r=radius);
// Teeth
for (i = [0:teeth-1]) {
rotate([0, 0, i * 360/teeth])
translate([radius, 0, 0])
cube([radius/2, radius/teeth*2, thickness], center=true);
}
}
// Center hole
cylinder(h=thickness+1, r=hole_diameter/2, center=true);
}
}
See references/primitives.md for complete primitive reference. See references/modules.md for reusable module patterns. See assets/templates/ for starting templates.
Use scripts/validate_openscad.py to validate scripts before rendering.