OpenSCAD: 3D Printing for Developers
I've previously written about and run a workshop on OpenJSCAD, which is a JavaScript reimagining of OpenSCAD. But I've recently been exploring the OG OpenSCAD.

Basics
The interface looks a little dated (the main release was about 4 years ago!) but the basic functionality works very nicely. It is declarative, which should now seem familiar to UI developers. To draw a cuboid you simply write:
cube([10, 20, 30]);
giving it a width
, depth
and height
in an array. You end the line with a semicolon. You can apply operations such as translate
like:
translate([5,5,5]) cube(5);
on one line, or group with curly brackets, which works nicely with more than one object:
translate([5,5,5]) {
cube(5);
translate([-5,5,5]) sphere(5);
}
For loops exist and can be nested, for example:
for(a = [0:15:360]) {
rotate([0, a, 0])
for(i = [1:1:10]) {
translate([i * 5, i * i / 2, 0])
color([i/12, a/360, 0.3])
cube(i, true);
}
}
This also sets the colour with color
.
Functions (Modules)
You can build reusable functions (modules) with module
. Let's immediately look at something non-trivial, a Lego-style building brick. Modules take parameters which can have defaults.
module lego_box(studs_x = 4, studs_y = 2, base_height_plates = 3) {
local_stud_diameter = 5;
local_stud_height = 1.8;
local_stud_spacing = 8;
local_plate_height = 3.2;
local_wall_thickness = 1.6;
box_width = studs_x * local_stud_spacing;
box_depth = studs_y * local_stud_spacing;
box_height = base_height_plates * local_plate_height;
// --- Main Body and Studs ---
union() {
cube([box_width, box_depth, box_height]);
for (x = [0 : studs_x - 1]) {
for (y = [0 : studs_y - 1]) {
translate([
(x * local_stud_spacing) + (local_stud_spacing / 2),
(y * local_stud_spacing) + (local_stud_spacing / 2),
box_height
]) {
cylinder(h = local_stud_height, r = local_stud_diameter / 2, $fn = 64);
}
}
}
}
}
// Create a standard 4x2 Lego brick
lego_box(4, 2);

Children
A bit like React you can have children
. This is implicitly set up (you don't declare a parameter), but can then be used by calling children()
in the body of the module.
Let's build a grid
module that will replicate the children()
.
module grid(n,m) {
for(i = [1:n]) {
for(j = [1:m]) {
translate([i,j,0]) {
children();
}
}
}
}
grid(4,4) {
cube([0.5,0.5,0.5]);
}

Further Reading
- I read Programming with OpenSCAD which is quite good but for programmers a bit basic/slow.
- LLMs work quite well
How do I ...
Here are some common tasks in OpenSCAD and how to do them. It covers some of the things I didn't above like 2D shapes, ways of combining shapes, text and more:
Task | Description | Code Example |
---|---|---|
Create a Cube | Draws a 3D rectangular prism. The argument can be a single number for a cube or a vector [width, depth, height] . | cube([10, 20, 5]); |
Create a Sphere | Draws a 3D sphere. The r argument specifies the radius. | sphere(r = 10); |
Create a Cylinder | Draws a 3D cylinder. h is height, r is radius (r1 and r2 for a cone). | cylinder(h = 20, r = 5); |
Create a Polyhedron | Defines a 3D shape by specifying its vertices (points) and the faces that connect them. | polyhedron(points=[[0,0,0],[10,0,0],[5,10,5]], faces=[[0,1,2]]); |
Draw a 2D Square | Creates a 2D square or rectangle. | square([15, 10]); |
Draw a 2D Circle | Creates a 2D circle. The r argument is the radius. | circle(r = 10); |
Draw a 2D Polygon | Defines a 2D shape by listing the points of its outline. | polygon(points=[[0,0],[10,5],[5,15]]); |
Extrude to 3D | Turns a 2D shape into a 3D solid by extruding it along the Z-axis. | linear_extrude(height = 10) circle(r = 5); |
Revolve to 3D | Creates a 3D shape by rotating a 2D shape around the Z-axis. | rotate_extrude(angle = 360) translate([10, 0, 0]) square(5); |
Combine Shapes (Union) | Merges multiple shapes into a single object. | union() { cube(10); sphere(r=7); } |
Subtract Shapes (Difference) | Subtracts the second (and subsequent) object(s) from the first. | difference() { cube(10); sphere(r=7); } |
Find Intersection | Keeps only the overlapping parts of multiple shapes. | intersection() { cube(10); sphere(r=7); } |
Move an Object | Translates (moves) an object along the X, Y, and Z axes. | translate([10, -5, 20]) cube(5); |
Rotate an Object | Rotates an object around the X, Y, and Z axes by a given number of degrees. | rotate([45, 0, 90]) cube([10, 20, 5]); |
Scale an Object | Resizes an object by a scaling factor for each axis. | scale([1.5, 1, 0.8]) sphere(r=10); |
Create a Mirror Image | Mirrors an object across a plane defined by a vector. | mirror([1, 0, 0]) translate([5,0,0]) cube(5); |
Create Rounded Hull | Creates a convex hull that connects the child objects, effectively "wrapping" them. | hull() { translate([0,0,0]) sphere(5); translate([20,0,0]) sphere(5); } |
Create Rounded Minkowski | Adds the volumes of two shapes, useful for rounding edges. | minkowski() { cube(10); sphere(r=2); } |
Define a Variable | Stores a value (number, vector, string, boolean) that can be reused. | box_width = 25; cube([box_width, 10, 10]); |
Create a Loop | Iterates over a range or vector, creating an object at each step. | for (i = [0:4]) translate([i*15, 0, 0]) cube(10); |
Use a Conditional | Chooses which geometry to create based on a boolean condition. | if (use_sphere) { sphere(10); } else { cube(10); } |
Create a Reusable Module | Defines a new, reusable object that can take parameters, similar to a function. | module my_box(w, d, h) { cube([w,d,h]); } |
Call a Module | Instantiates an object defined by a module. | my_box(10, 20, 5); |
Module with Children | Creates a module that can modify other objects passed into it. | module place_in_a_row() { for(i=[0:2]) translate([i*15,0,0]) children(); } |
Use children() | A command within a module that refers to the objects passed to it. | place_in_a_row() sphere(5); |
Define a Function | Creates a reusable calculation that returns a value (not geometry). | function hypotenuse(a, b) = sqrt(a*a + b*b); |
Control Resolution ($fn ) | Sets the number of fragments (facets) for curved surfaces. Higher is smoother. | sphere(r=10, $fn=100); |
Control Resolution ($fa ) | Sets the minimum angle for a fragment. Overrides $fn . | cylinder(h=10, r=5, $fa=1); |
Control Resolution ($fs ) | Sets the minimum size of a fragment. Overrides $fn . | sphere(r=10, $fs=0.1); |
Create Text | Generates 3D text from a string. | linear_extrude(5) text("Hello", font="Liberation Sans"); |