Reference

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:

TypeExamplesTest
Number3, 3.14, -2, 1e6is_num()
Booleantrue, falseis_bool()
String"hello"is_string()
Vector / list[1, 2, 3], ["a", 2, true]is_list()
Range[0:5], [0:0.5:10]
Undefinedundefis_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;
You cannot increment a variable inside a loop.

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.

VariableDefaultPurpose
$fn0Hard facet count for circles/spheres. Overrides $fa/$fs.
$fa12Min facet angle (degrees). Lower ⇒ smoother.
$fs2Min facet size (mm). Lower ⇒ smoother on small parts.
$t0Animation time (0.0–1.0).
$previewtrue in F5 preview, false during F6 render.
$childrenNumber of children passed into the current module.
$vpr / $vpt / $vpd / $vpfViewport rotation / translation / camera distance / FOV.
Set $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.

Open the agent