OpenSCAD language reference
OpenSCAD's language is small — a few dozen keywords and a handful of rules.
This page covers them in order: variables and values, vectors and lists,
conditionals and loops, list comprehensions, and the special
$-prefixed variables that control rendering quality and the
viewport.
Comments & whitespace
// single-line comment
/* multi-line
comment */
Whitespace and newlines are insignificant. Statements end with ;; module/function definitions and transformation blocks end with } (no semicolon).
Values & types
OpenSCAD has six value types:
| Type | Examples | Test |
|---|---|---|
| Number | 3, 3.14, -2, 1e6 | is_num() |
| Boolean | true, false | is_bool() |
| String | "hello" | is_string() |
| Vector / list | [1, 2, 3], ["a", 2, true] | is_list() |
| Range | [0:5], [0:0.5:10] | — |
| Undefined | undef | is_undef() |
Variables
Assignment looks normal but has one trap: variables are statically scoped and the last assignment in a block wins, no matter where it appears. There is no runtime mutation.
x = 1;
echo(x); // echoes 2, not 1 — last assignment wins
x = 2;
i = i + 1; inside a for body re-binds i
for the rest of the parsing scope — not for "the next iteration". Use a
list comprehension or recursive function instead.
Vectors & lists
Vectors and lists are the same type — an ordered collection that may hold
mixed types. Index with v[i]. Vectors of length 2–4 also support
dot notation:
p = [10, 20, 30];
a = p[0]; // 10
b = p.y; // 20
c = len(p); // 3
d = concat(p, [40, 50]); // [10,20,30,40,50]
Ranges
A range [start : step : end] is its own value type — primarily
used in for loops and list comprehensions. The step is optional;
ranges are inclusive of both endpoints when possible.
for (i = [0 : 5 : 30]) echo(i); // 0,5,10,15,20,25,30
for (i = [10 : -2 : 0]) echo(i); // 10,8,6,4,2,0
Conditionals
if (thickness > 5) {
cube(10);
} else {
cube(5);
}
// Ternary works in expressions:
h = (thickness > 5) ? 10 : 5;
Loops
for creates a copy of its body per iteration and unions them. To
intersect iterations instead (rarely needed but very powerful), use
intersection_for.
for (x = [0 : 10 : 40])
translate([x, 0, 0]) cube(5);
// Nested iterators (cartesian product):
for (x = [0, 20], y = [0, 20])
translate([x, y, 0]) cylinder(h=5, r=2);
List comprehensions
Comprehensions are the idiomatic way to compute lists of points, sizes, or positions. They are pure expressions (return a list) — use them everywhere you would write a small data pipeline in another language.
// All even numbers 0..20
evens = [for (i = [0:20]) if (i % 2 == 0) i];
// Polygon of points on a circle
pts = [for (a = [0:10:359])
[cos(a) * 20, sin(a) * 20]];
polygon(pts);
// Flatten with `each`
flat = [each [1,2,3], each [4,5]]; // [1,2,3,4,5]
Local bindings with let
let introduces a scoped binding — useful inside comprehensions
and inside transformation chains.
let (r = 10, h = 20) {
cylinder(h=h, r=r);
}
Special $ variables
Dollar-prefixed names are dynamically scoped — they pass into children automatically. Use them to control facet resolution, animation time, and the viewport.
| Variable | Default | Purpose |
|---|---|---|
$fn | 0 | Hard facet count for circles/spheres. Overrides $fa/$fs. |
$fa | 12 | Min facet angle (degrees). Lower ⇒ smoother. |
$fs | 2 | Min facet size (mm). Lower ⇒ smoother on small parts. |
$t | 0 | Animation time (0.0–1.0). |
$preview | — | true in F5 preview, false during F6 render. |
$children | — | Number of children passed into the current module. |
$vpr / $vpt / $vpd / $vpf | — | Viewport rotation / translation / camera distance / FOV. |
$fn=64 globally for clean previews.
Most parts look great at $fn=64; bump to 128 for showcase
renders, drop to 32 while iterating to keep the preview snappy. The AI CAD
agent picks a sensible default and lets you override per-call.
Strings
Use str() to build strings; chr()/ord() for code points; search() for substrings.
label = str("M", screw_size, " x ", screw_len); // "M3 x 10"
Assertions & debug
assert(thickness >= 1, "Wall too thin for FDM");
echo("thickness = ", thickness);
Including external files
include <file.scad>— inlines the file as if you pasted it in (variables and modules become available).use <file.scad>— pulls in modules and functions only, not variables; safer for libraries.
use <BOSL2/std.scad> // modules/functions, no var pollution
include <my_constants.scad>
Read the language by reading generated code
Send a prompt to the AI CAD agent and watch it write idiomatic OpenSCAD — variables at the top, named modules, parametric loops, and assertions for printability.