The language reference
Every command.
The syntax, the parameters, the possibilities.
Keep this open while you build.
Find a command
01 / Create geometry
Solid primitives
Primitives produce placeable volumes. By default, each ordinary solid stacks on the previous one. Its own frame is centered on X and Y, with its base at Z = 0. To build a solid from a 2D profile, use a solid from a shape.
!@right 6 color steelblue cube 20 color gold cylinder 20 26 color coral cone 20 26 color mediumseagreen sphere 20open in editor

cube#
An equal-sided box, centered on X and Y with its base at Z = 0.
cube size | Argument / option | Meaning & constraints |
|---|---|
size | Side length on all three axes; zero or greater. |
Examplecube 20
block#
A rectangular solid with independently sized axes.
block width depth height | Argument / option | Meaning & constraints |
|---|---|
width / depth / height | Lengths of zero or more along local X, Y, and Z, respectively. |
Exampleblock 40 30 10
cylinder#
A circular cylinder standing on its base.
cylinder diameter height | Argument / option | Meaning & constraints |
|---|---|
diameter | Full width across the circular base; zero or greater. |
height | Length along Z; zero or greater. |
Examplecylinder 20 30
sphere#
A sphere resting on the ground plane. Standard face references touch its outer bounds.
sphere diameter | Argument / option | Meaning & constraints |
|---|---|
diameter | Full width of the sphere; zero or greater. |
Examplesphere 24
cone#
A right circular cone standing on its base.
cone diameter height | Argument / option | Meaning & constraints |
|---|---|
diameter / height | Base diameter and Z height; both zero or greater. |
Examplecone 24 30
pyramid#
A regular pyramid with a base face pointing front. The base is measured through its corners unless a measure word says otherwise.
pyramid sides [diameter | edge | across] size height | Argument / option | Meaning & constraints |
|---|---|
sides | Whole number of base sides, at least 3. |
diameter / edge / across | Optional measure word. Measure the base through its corners (the default), along one side, or between two parallel sides (even sides only). |
size / height | Base size and Z height; both zero or greater. |
Examplepyramid 4 edge 24 30
prism#
A regular prism with one upright face pointing front, measured like a pyramid. Its slot uses the bounds of the actual polygon.
prism sides [diameter | edge | across] size height | Argument / option | Meaning & constraints |
|---|---|
sides | Whole number of upright faces, at least 3. |
diameter / edge / across | Optional measure word. Measure the base through its corners (the default), along one side, or between two parallel sides (even sides only). |
size / height | Base size and Z height; both zero or greater. |
Exampleprism 6 across 24 20
starprism#
A star raised into a solid. Its first spike points along +X.
starprism spikes outer-diameter inner-diameter height | Argument / option | Meaning & constraints |
|---|---|
spikes | Whole number of spikes, at least 3. |
outer-diameter / inner-diameter | Diameters through the spikes and notches; inner must be smaller than outer, unless both are zero. |
height | Extrusion height; zero or greater. |
Examplestarprism 5 40 20 10
!@right 8 color steelblue pyramid 4 30 28 color gold prism 6 30 20 color coral starprism 5 30 15 12open in editor

torus#
A ring lying in the XY plane. Dimensions describe the outside and the hole, not the tube thickness.
torus outer-diameter inner-diameter | Argument / option | Meaning & constraints |
|---|---|
outer-diameter / inner-diameter | Overall and hole diameters; the hole is greater than zero and no larger than the outside. |
Exampletorus 30 18
tube#
An upright hollow cylinder, open at both ends.
tube outer-diameter inner-diameter height | Argument / option | Meaning & constraints |
|---|---|
outer-diameter / inner-diameter | Outside and bore diameters; the bore is greater than zero and no larger than the outside. |
height | Z height; zero or greater. |
Exampletube 30 18 20
tetrahedron#
A regular polyhedron with 4 triangular faces, standing on one face. Numbered references identify its actual planar faces.
tetrahedron [diameter | edge] size | Argument / option | Meaning & constraints |
|---|---|
size | Size of zero or more, measured along an edge by default, unless diameter is specified. |
edge / diameter / across | Optional measure word: along an edge (the default), or the diameter of the sphere through the vertices. A tetrahedron has no opposite faces to measure across. |
Exampletetrahedron 12
octahedron#
A regular polyhedron with 8 triangular faces, standing on one face. Numbered references identify its actual planar faces.
octahedron [diameter | edge | across] size | Argument / option | Meaning & constraints |
|---|---|
size | Size of zero or more, measured along an edge by default, unless diameter or across is specified. |
edge / diameter / across | Optional measure word: along an edge (the default), the diameter of the sphere through the vertices, or between two opposite faces - the height it stands. |
Exampleoctahedron 12
dodecahedron#
A regular polyhedron with 12 pentagonal faces, standing on one face. Numbered references identify its actual planar faces.
dodecahedron [diameter | edge | across] size | Argument / option | Meaning & constraints |
|---|---|
size | Size of zero or more, measured along an edge by default, unless diameter or across is specified. |
edge / diameter / across | Optional measure word: along an edge (the default), the diameter of the sphere through the vertices, or between two opposite faces - the height it stands. |
Exampledodecahedron 12
icosahedron#
A regular polyhedron with 20 triangular faces, standing on one face. Numbered references identify its actual planar faces.
icosahedron [diameter | edge | across] size | Argument / option | Meaning & constraints |
|---|---|
size | Size of zero or more, measured along an edge by default, unless diameter or across is specified. |
edge / diameter / across | Optional measure word: along an edge (the default), the diameter of the sphere through the vertices, or between two opposite faces - the height it stands. |
Exampleicosahedron 12
!@right 6 color steelblue tetrahedron 24 color gold octahedron 18 color coral dodecahedron 10 color mediumseagreen icosahedron 13open in editor

mesh#
A solid written out as its corners and the flat faces between them. Faces are named #f1, #f2, … in the order they are written.
mesh vertices [x y z]… faces [i j k …]… | Argument / option | Meaning & constraints |
|---|---|
vertices | Four or more corners, each [x y z]. They are numbered from 0 in the order written. The solid is placed by its box, so only their relative positions matter. |
faces | Four or more faces, each listing three or more corner indices in order around it. Each face must be flat, and every edge must be shared by exactly two faces. Winding does not matter. |
Examplemesh vertices [0 0 0] [10 0 0] [0 10 0] [0 0 10] faces [0 1 2] [0 1 3] [0 2 3] [1 2 3]
color steelblue mesh vertices [-10 -10 0] [10 -10 0] [10 10 0] [-10 10 0] [10 10 30] faces [0 1 4] [1 2 4] [2 3 4] [3 0 4] [0 1 2 3] on #f1 x right -2 y front 2 color gold block 9 9 1open in editor

02 / Give a profile volume
Solids from shapes
Turn a 2D profile into a placeable solid by raising it, turning
it around an axis, or carrying it along a route. The profile comes first and the sweep
follows it after |: steps before the sweep's word treat the shape, steps
after it the solid. All four accept the same shapes and 2D operations.
extrude#
Raise a 2D profile into a solid. A filled profile is the default; wall gives its outline a thickness instead, twist and size turn and resize it as it rises, apex runs the sides towards a point, and to runs them to another shape.
profile | extrude height [wall thickness [inside | outside]] [twist degrees] [size factor] [apex [x y [z]] | to top] | Argument / option | Meaning & constraints |
|---|---|
height | Zero or greater; extrusion distance along local Z. |
wall thickness | Optional wall thickness, zero or greater. Centered on the outline by default. |
inside / outside | Keep the wall on one side of a closed outline. Open paths only support a centered wall. |
twist | Degrees the outline turns about its own origin by the top, counter-clockwise seen from above. A list, twist [0 30 120], gives the turn at evenly spaced levels from the base to the top, joined by a smooth curve that never overshoots them. Not with apex or to. |
size | The size of the top as a share of the profile, about its own origin; written and listed as twist is. Zero or greater, and zero only at the base or the top, where the solid closes to a point. A wall keeps its thickness at every level. |
apex | The point the sides run towards, in the profile's own coordinates. z defaults to the height, closing to a point; above it the top is cut short, below the base the sides spread. z between 0 and the height is an error. A wall keeps its thickness all the way up. |
to | The shape the top is, in the profile's own coordinates. The side runs straight, corner to corner when both outlines have as many corners, otherwise between points the same share of the way round both, with the top started where the side twists least. Each must be a single outline without holes. Takes no modifiers unless written in a group, to { circle 20 | round 2 }. Cannot be combined with apex. |
profile | circle, rect, ellipse, star, polygon, a face, path, text, a tiling or a group, written before the sweep. |
color steelblue rect 30 20 | extrude 8 @right 10 color gold rect 30 20 | extrude 16 wall 2 insideopen in editor

A filled path closes its subpaths. With wall, open paths stay open. A wall
has no bottom; use shell for a vessel with a floor.
color steelblue path "M24 4C16 12 4 24 12 36 20 48 28 48 36 36 44 24 32 12 24 4Z" | extrude 5 color gold #top | extrude 5 | scale 0.9 color coral #top | extrude 5 | scale 0.9 color mediumseagreen #top | extrude 5 | scale 0.9open in editor

Face references such as #top can be used as profiles.
!@right 8 color steelblue polygon 6 20 | extrude 30 apex [0 0] color gold rect 20 20 | extrude 30 apex [10 0] color coral circle 20 | extrude 30 apex [0 0 60] color mediumseagreen circle 20 | extrude 30 wall 2 inside apex [0 0 60]open in editor

The apex is a point in the profile's own frame, so apex [0 0] stands the point
over a circle's centre or a path's origin. Where the outline shrinks below the wall's thickness,
the wall closes over into solid; a long outline that does so all along its length, such as
text walled to a point, is refused.
!@right 8 color steelblue star 6 40 28 | extrude 40 twist 60 color gold star 6 40 28 | extrude 40 twist 60 size 0.5 color coral star 9 50 40 | round 3 | extrude 80 twist [0 20 80] size [1 1.3 0.8 1] wall 1.5 insideopen in editor

twist and size work about the profile's own origin, as a | rotate or | scale of the shape would. One value is the top's,
reached evenly; a list is the value at each of several evenly spaced levels.
!@right 8 color steelblue rect 30 30 | extrude 30 to circle 20 color gold rect 40 40 | extrude 40 wall 2 inside to circle 12 color coral circle 20 | extrude 30 to polygon points [10 -5] [30 -5] [30 5] [10 5]open in editor

With to, every corner of either outline is a corner of both, so the base
keeps its corners and the top its curve. A wall is its thickness at the base and at the
top and runs straight between, open at both ends.
revolve#
Sweep a profile around an axis. The optional diameter is the circular path of the profile's origin, not the outside diameter of the finished solid.
profile | revolve [diameter] [angle degrees] [start degrees] [about axis] [shrink] | Argument / option | Meaning & constraints |
|---|---|
diameter | Zero or greater. Default 0: use the profile's own coordinates without a radial offset. |
angle | Greater than 0 and at most 360. Default 360 degrees. |
start | Starting angle; default 0, at +X for a Z-axis sweep. |
about | x, y, or z. Default z. |
shrink | Use material bounds for placement. Partial sweeps otherwise keep bounds mirrored about the axis. |
profile | Any 2D profile. Only its outline is swept; profile holes are ignored. |
color gold circle 12 | revolve 40 angle 90 shrinkopen in editor

A path profile's Y grows downwards, so the top of the drawing is the top of the
solid.
A profile crossing the axis is clipped to the half it sweeps. For example, circle 20 | revolve makes a sphere of diameter 20.
helix#
Sweep a profile around an axis while rising. A second diameter tapers the sweep from its starting circle to its ending circle.
profile | helix diameter [end-diameter] [pitch distance] [turns count | height distance]
[start degrees] [about axis] [shrink] | Argument / option | Meaning & constraints |
|---|---|
diameter / end-diameter | Nonnegative path diameters. End diameter defaults to the starting diameter. |
pitch | Nonnegative rise per turn; default 0. |
turns | Greater than 0 and at most 100; fractional turns are allowed. Default 1. With no pitch and no end diameter, more than one turn is a warning and builds one. |
height | Positive path rise, as an alternative to turns. Requires positive pitch; cannot be combined with turns. |
start / about | Starting angle (default 0) and sweep axis (default z). |
shrink | For a sweep of less than one turn, use material bounds instead of mirrored bounds. |
profile | Any 2D profile, which must not cross the sweep axis. |
color coral circle 4 | helix 24 44 pitch 10 turns 4open in editor

Height measures the path's rise, so material can extend beyond it by the profile's size. Choose enough pitch to prevent adjacent coils from intersecting.
The slot includes that overshoot: height 60 with a profile 2 tall is 62
tall, and so is a compound around the rod and its thread. To end a thread flush with its
rod, run it a pitch past both ends and trim it with on a labelled part and &revolve instead of wrapping it in a compound. That hides the helix's capped
ends and lets a chamfer taper the ridge out.
head: prism 6 30 10 cylinder 16 30 @center path "M-0.2,-1.2 L0,-1.2 L1.2,-0.3 L1.2,0.3 L0,1.2 L-0.2,1.2 Z" | helix 16 pitch 3 height 36 on head &path "M0,0 H8 L9.5,1.5 V30 H16 V40 H0 Z" | revolveopen in editor

sweep#
Sweep a profile along the outline of another 2D shape. The trajectory lies in the build plane, where an extruded shape lies.
profile | sweep along trajectory [about axis] [round] | Argument / option | Meaning & constraints |
|---|---|
profile | Any 2D shape with an area. X runs to the right of an open path's travel or outside a closed outline; Y stands off the plane. |
along trajectory | Any 2D shape, read as a wall reads it: an open path stays open and is capped at both ends, a closed outline makes a ring. Every outline is swept and the results are joined. Takes no modifiers unless written in a group. |
about | x, y, or z: the axis the trajectory's plane faces. Default z. |
round | Round the outside of each sharp corner. Corners are mitred by default. |
block 80 40 6 on #top -rect 4 3 | sweep along path "M0,0 H30 C40,0 40,20 50,20 H70"open in editor

The profile's origin rides the route, and the plane never turns, so the profile never
twists. rect 2 10 | sweep along path P is path P | extrude 10 wall 2, and circle 20 | sweep along circle 40 is torus 60 20.
cylinder 60 8 on #top -path "M-6,0 H-3 V2 H-6 Z" | sweep along #topopen in editor

A face follows its real outline. On a closed outline the profile's X points outward, so a profile drawn left of its origin lies inside the rim.
cylinder 40 50 @right -2 color gold circle 6 | sweep along path "M0,0 C0,-30 36,-30 36,0" about yopen in editor

about turns the plane as it turns a revolve's axis: the trajectory's X lies
on the axis after the named one in the x → y → z cycle, and its Y on the one after that.
Corners are mitred like a wall's, and cut off square when sharper; round rounds their outside. A profile wider than the inside of a bend has room for is refused, naming
the bend. A single outline that crosses itself is swept as drawn.
varying profiles#
A profile drawn anew at every point of its sweep: a shape macro called with every argument but its last, which the sweep gives as it goes, from 0 at its start to 1 at its end. Written in place, % and one parameter stand for the macro.
shape-macro [argument …] | sweep | % $parameter profile | sweep | Argument / option | Meaning & constraints |
|---|---|
last argument | Runs over the height of an extrude, the turn of a revolve, the turns of a helix, and each outline of a sweep along. |
% $parameter | A varying profile written in place. Everything up to the sweep is its shape, modifiers included. |
outlines | Each pairs from the point it is drawn from. As many outlines and holes all the way; sizes, corners and turns may change. |
closed sweeps | A whole revolve or a sweep along a closed outline has to end on the shape it starts from. |
extrude | Takes twist, size and wall on top of the profile; not apex or to. |
def %handle $t circle (8 - 4 * $t) !@right 10 color steelblue % $t rect 30 30 | round (1 + 13 * $t) | rotate (45 * $t) | extrude 40 color gold % $t circle (8 + 12 * $t) | revolve 50 angle 270 color coral %handle | sweep along path "M0,0 C0,-30 36,-30 36,0" about yopen in editor

A varying profile is drawn wherever it changes most: eight times, and again between two
wherever the shape strays from the straight way between them. Written alone, it is a
sketch of its start. curve(20, 44, 16, $t) gives a size that passes through each
value on the way.
03 / Define a profile
2D profiles
A profile becomes a solid when a sweep follows it: extrude, revolve, helix or sweep. Written on its own it is a sketch: placed where the swept solid would stand and drawn flat there, building nothing, taking no slot and leaving the reference where it was. The script still builds, with a warning. 2D modifiers written between a profile and its sweep treat its outline before it is swept.
circle#
A circular profile centered on its own origin.
circle diameter | Argument / option | Meaning & constraints |
|---|---|
diameter | Positive full width across the circle. |
Examplecircle 20 | extrude 4
rect#
A rectangular profile centered on its own origin.
rect width height | Argument / option | Meaning & constraints |
|---|---|
width / height | Positive lengths across local X and Y. Extrusion supplies the Z dimension. |
Examplerect 30 20 | extrude 4
ellipse#
An elliptical profile centered on its own origin.
ellipse diameter-x diameter-y | Argument / option | Meaning & constraints |
|---|---|
diameter-x / diameter-y | Positive full widths along local X and Y. |
Exampleellipse 30 20 | extrude 4
star#
The outline of a starprism, centered on its own origin with its first spike along +X. Extruded, `star 5 40 20` is `starprism 5 40 20` of that height.
star spikes outer-diameter inner-diameter | Argument / option | Meaning & constraints |
|---|---|
spikes | Whole number of spikes, at least 3. |
outer-diameter / inner-diameter | Positive diameters through the spikes and notches; inner must be smaller than outer. |
Examplestar 4 20 10 | extrude 5
polygon#
A polygon of corners written out in the shape's own coordinates, Y up and not re-centered, or the regular polygon of a prism's base, centered on its own origin. Extruded, `polygon 6 20` is `prism 6 20` of that height.
polygon sides [diameter | edge | across] size
polygon points [x y]… | Argument / option | Meaning & constraints |
|---|---|
points [x y]... | Three or more corners in order around the outline. The outline closes itself; one that crosses, touches or folds back on itself is an error. |
sides | Whole number of corners of a regular polygon, at least 3. |
diameter / edge / across | Optional measure word, as for prism: through the corners (the default), along one side, or between two parallel sides (even sides only). |
size | Positive size along the measure. |
Examplepolygon points [0 0] [30 0] [20 15] [0 10] | extrude 4
#face#
The outline of a face of a built solid, drawn in the face's own frame. A bare face also builds the solid on that face, covering it exactly, unless an on says otherwise.
#face
label #face | Argument / option | Meaning & constraints |
|---|---|
#face | Any face reference: #top, #f2, #bounds.front. A bare face is read off the volume the next solid is built against, the one on would read it from. |
label | Optional. Reads the face of that labelled volume instead, as its statement built it: booleans written after the label do not reach the outline. |
outline | The surface the solid has on the face, so the #top of a cylinder is a circle. A direction must name a flat side the solid has; every #bounds face is its whole extent. The shape claims the whole face as its slot. |
rect 40 40 | extrude 50 apex [0 0 -130] on #f2 color gold #f2 | extrude 2open in editor

A face shape is most useful as the area of a tiling, which fits a pattern to a face without measuring it.
path#
A profile drawn with an SVG path string. SVG's downward Y axis is flipped so the shape stands as drawn.
path "svg-path"
path $variable | Argument / option | Meaning & constraints |
|---|---|
svg-path | M, L, H, V, Z, C, S, Q, T, A and their lowercase forms. Use ordinary decimal coordinates; literals reject + signs and exponent notation. |
$variable | A string value containing the SVG path. |
color mediumseagreen path "M29.4 1.551C31.446 1.518 33.807 1.959 35.457 3.243 36.234 3.948 37.032 4.689 37.674 5.52 38.925 7.626 39.765 9.96 40.077 12.393 40.173 13.524 40.788 14.37 41.475 15.225 42.099 15.888 43.158 16.119 44.01 16.329 47.217 17.091 50.241 18.27 53.217 19.677 54.423 20.247 55.668 20.7 56.415 21.885 57.684 23.493 57.771 25.653 57.681 27.612 57.576 29.115 56.277 30.177 54.942 30.639 52.665 31.458 50.406 32.319 48.126 33.126 47.559 33.348 46.965 33.552 46.521 33.987 46.407 34.32 46.476 34.608 46.734 34.851 47.664 35.955 48.327 37.239 49.239 38.358 50.082 39.612 51.033 40.785 51.831 42.069 53.685 44.73 55.938 47.475 57.252 50.448 57.981 52.068 58.335 53.775 57.933 55.533 57.753 56.268 57.165 56.832 56.451 57.048 54.627 57.699 52.902 57.606 51.003 57.672 47.301 57.786 43.602 57.879 39.9 58.002 38.499 58.02 36.789 58.134 35.496 57.525 33.867 55.917 33.303 54.042 32.202 52.101 31.494 50.811 30.96 49.419 30.09 48.264 28.833 50.58 27.708 52.962 26.508 55.308 26.145 56.106 25.476 56.415 24.81 56.916 23.967 57.516 22.947 57.816 21.912 57.786 16.821 57.768 11.715 57.798 6.627 57.774 5.037 57.642 2.952 56.694 2.664 54.93 2.124 52.386 2.838 49.77 3.99 47.493 5.094 45.507 6.579 43.872 7.809 42.006 9.747 39.384 11.643 36.753 13.605 34.146 12.669 33.102 11.253 33.075 9.996 32.595 8.4 32.007 6.795 31.422 5.211 30.798 3.642 30.138 2.826 28.662 2.679 27.015 2.571 25.422 2.454 23.526 3.123 22.041 4.11 20.592 5.529 19.773 7.107 19.104 9.561 18.06 12.06 17.169 14.628 16.449 15.75 16.158 16.764 15.717 17.601 14.895 18.714 13.476 18.327 11.937 18.702 10.287 19.266 8.121 19.911 6.021 21.384 4.284 23.676 2.373 26.472 1.686 29.4 1.551Z" | extrude 10open in editor

Because Y is flipped, a larger Y is lower. For revolve and helix, where Y becomes height, draw the profile top first, as it looks on
screen.
The points of an SVG <polygon> paste between M and Z, since the pairs after a move are lines: path "M20,0 40,20 30,20 30,40 10,40 10,20 0,20 Z".
Filled extrusion closes every subpath. extrude … wall preserves open subpaths
as open walls. A path literal takes no escapes.
text#
A line of text in the current font and font-size. Give it depth with a sweep operation.
text "string"
text $variable | Argument / option | Meaning & constraints |
|---|---|
string / $variable | Double-quoted text or a string variable. A string may span lines, each starting below the last, aligned left. Escapes: \n line break, \" quote, \\ backslash, \u{B0} a Unicode character by hex code point. |
color steelblue block 48 24 4 on #top color gold font-size 12 text "Hi" | extrude 2open in editor

font-size#
Set the height of a capital letter in a text profile, independently of the extrusion height.
[!]font-size size
[!]font-size unset | Argument / option | Meaning & constraints |
|---|---|
size | Positive height in model units. Default 10. |
! / unset | Persist the setting or restore the default, following the same rules as color. |
font-size 12 text "Hello" | extrude 2
font#
Set the font of a text profile: a Google Fonts family name, the https URL of a font file, or a font file path for the command-line tool.
[!]font "family" [weight]
[!]font unset | Argument / option | Meaning & constraints |
|---|---|
family | A Google Fonts name such as "Roboto", a font file URL, or a local path such as "fonts/Logo.otf" relative to the script. Local paths are supported only by the CLI. The value must be written as a literal, not a variable, because the font is loaded before the script runs. |
weight | 100 (thin) to 900 (black). Default 400 for a family name. For a file, it picks the weight of a variable font and is otherwise left out. |
! / unset | Persist the setting or return to the built-in font, following the same rules as color. |
font "Roboto" 700 font-size 12 text "Hello" | extrude 2open in editor

font-size stays the height of a capital letter in every font. The built-in font
covers Latin-1 and Greek. A character the font has no glyph for, built-in or not, is left
out, with a warning.
A font file, by URL or on disk, is TTF, OTF, WOFF, or WOFF2, up to 10 MB; a TTC
collection gives its first font. The format is read from the content, so a URL needs no
extension. A path ends in .ttf, .otf, .woff, .woff2, or .ttc, and only the command-line tool reads it.
04 / Treat a profile
2D operations
2D modifiers follow a profile after | and treat its flat outline before it
is swept. They come before the solid's own modifiers, in the
same left-to-right pipeline, and work on every profile, tilings and faces included.
Braces combine profiles into one, placed and signed the way solids are. A shape in
braces, and a profile before its sweep, can also be turned, mirrored and resized.
offset#
Grow the outline of a profile by a signed distance, or shrink it by a negative one. Corners stay sharp, as a wall's do.
| offset distance [round] | Argument / option | Meaning & constraints |
|---|---|
distance | Any number. Holes move the other way, narrowing as the outline grows. A shrink that leaves nothing is an error. |
round | Optional. Keeps the new outline the same distance from the old one, rounding the corners it moves away from. |
def %outline rect 60 40 | round 4 color steelblue { %outline | extrude 2 %outline | extrude 28 wall 2 inside } @right 10 color gold { %outline | extrude 2 %outline | offset -2.2 | extrude 4 }open in editor

2D modifiers come right after the shape and before its sweep, in one pipeline with the
solid's own modifiers: rect 40 30 | offset 2 | extrude 10 | fillet 1. A
modifier treats the innermost shape before it, so after a tiling it treats the area; put
the tiling in braces to treat its cells. The shape stays in the frame it is drawn in.
round#
Round every corner of a profile, those pointing out and those turning in alike.
| round radius | Argument / option | Meaning & constraints |
|---|---|
radius | Zero or greater. Parts narrower than twice the radius are lost; a radius that leaves nothing is an error. |
Examplepolygon points [0 0] [40 0] [40 10] [10 10] [10 40] [0 40] | round 3 | extrude 4
fill#
Fill the holes of a profile, keeping its outlines. A face of a hollowed solid fills into a lid.
| fill Examplebox: block 40 30 20 | shell 2 on box #top box #top | fill | extrude 2
{ group }#
One profile made of several: each shape placed against the one before it, centered unless x, y or an anchor says otherwise, and joined, cut, kept or cancelled by its sign.
{ shape … } [| modifier …] | Argument / option | Meaning & constraints |
|---|---|
shape | Any profile, with optional x, y, @left / @right / @front / @back, a sign - & ^, and slot before it. A flat shape has no z, @top or @bottom. |
first shape | Placed against the origin; with nothing to place it, it keeps its own coordinates, so a group of one shape is that shape. |
[ list ] | Builds each item from the shape the list opened after. |
!setter | Persists to the end of the group or list it is written in. |
The same alignment and offset principles used for 3D solids apply to x and y in a group, including named points, percentages,
and reference:shape pairs.
color steelblue { rect 60 30 | round 4 -rect 40 6 | round 3 [ x left 6 y front 6 -circle 5 x right -6 y front 6 -circle 5 ] } | extrude 3open in editor

The counterpart of a compound. The group claims the box of every
shape in it that adds, slot ones included and cut ones not, and takes 2D modifiers
as a whole, so braces around a tiling let a modifier treat its cells. Braces holding only
shape macro calls are a group too.
− / & / ^#
Change how a shape in a group combines with the shapes before it, as the signs do for solids. Without a sign, the shape is added.
{ … -shape }
{ … &shape }
{ … ^shape } | Argument / option | Meaning & constraints |
|---|---|
- | Difference: cut the shape from the area before it. |
& | Intersection: keep only the overlap. |
^ | Symmetric difference: keep what belongs to exactly one of the two. |
Example{ rect 40 20 @right -rect 10 10 } | extrude 2
The counterpart of the signs on solids. A signed shape cannot be the first in its group. On the axis an anchor names it reaches back into the shape before it, so the example notches the right edge, and it leaves its box as the reference for the next shape.
rotate#
Turn a shape in a group, or a profile before its sweep, about its own origin.
| rotate degrees | Argument / option | Meaning & constraints |
|---|---|
degrees | Counter-clockwise; no axis, since a flat shape turns in its own plane. |
Example{ rect 40 10 rect 40 10 | rotate 90 } | extrude 2
A shape in a group or a profile before its sweep takes it, as a step of the whole shape after that shape's own 2D modifiers. After the sweep the word belongs to the solid's rotate.
scale#
Resize a shape in a group, or a profile before its sweep, about its own origin, uniformly or per axis.
| scale factor
| scale x-factor y-factor | Argument / option | Meaning & constraints |
|---|---|
factor(s) | One for both axes, or one for each; not zero. A negative factor mirrors. |
Example{ circle 10 | scale 2 1 } | extrude 2
A shape in a group or a profile before its sweep takes it, as a step of the whole shape after that shape's own 2D modifiers. After the sweep the word belongs to the solid's scale.
flip#
Mirror a shape in a group, or a profile before its sweep, across its own origin.
| flip axis | Argument / option | Meaning & constraints |
|---|---|
axis | x or y, the axis negated. |
Example{ star 5 20 10 @right star 5 20 10 | flip x } | extrude 2
A shape in a group or a profile before its sweep takes it, as a step of the whole shape after that shape's own 2D modifiers. After the sweep the word belongs to the solid's flip.
05 / Fill an area
Tilings & Voronoi
Tilings are 2D profiles that lay cells over the area of another shape, written last
after in. The cells are the holes, so subtracting a tiling perforates a plate,
and a rim as wide as the strut stays standing along the outline unless rim says otherwise. Any profile can be the area, including a face.
honeycomb#
Hexagonal cells in columns, each column half a cell off the next, laid over the area of a shape and cut back to it, leaving a rim along its outline. Subtract it to perforate a plate.
honeycomb diameter strut [angle degrees] [rim width] in area | Argument / option | Meaning & constraints |
|---|---|
diameter | Positive size of a cell across its corners, as a prism is measured. A flat faces front. |
strut | Positive gap between neighbouring cells. At most 10,000 cells. |
angle | Optional. Turns the cells counter-clockwise inside the area, which stays where it is. |
rim | Optional. Material left standing along the outline of the area; the strut by default, 0 lets the cells run out to the outline. |
in shape | Required, and always last. The area the cells fill: any 2D profile, a shape macro, or a face such as #f2. The pattern claims the box of the area as its slot. |
set $outline "M0,0 H80 L100,20 V40 H0 Z" path $outline | extrude 3 -honeycomb 8 1.5 rim 3 in path $outline | extrude 3open in editor

The tiling and the plate share one outline, so the rim follows it all the way round. angle turns the cells inside the area, which stays where it is.
squares#
Square cells in a plain grid, laid over the area of a shape and cut back to it, leaving a rim along its outline. Subtract it to perforate a plate.
squares diameter strut [angle degrees] [rim width] in area | Argument / option | Meaning & constraints |
|---|---|
diameter | Positive size of a cell across its corners, as a prism is measured. A flat faces front. |
strut | Positive gap between neighbouring cells. At most 10,000 cells. |
angle | Optional. Turns the cells counter-clockwise inside the area, which stays where it is. |
rim | Optional. Material left standing along the outline of the area; the strut by default, 0 lets the cells run out to the outline. |
in shape | Required, and always last. The area the cells fill: any 2D profile, a shape macro, or a face such as #f2. The pattern claims the box of the area as its slot. |
Examplerect 70 50 | extrude 3 -squares 8 1.5 rim 5 in rect 70 50 | extrude 3
triangles#
Triangular cells in rows, pointing back and front in turn, laid over the area of a shape and cut back to it, leaving a rim along its outline. Subtract it to perforate a plate.
triangles diameter strut [angle degrees] [rim width] in area | Argument / option | Meaning & constraints |
|---|---|
diameter | Positive size of a cell across its corners, as a prism is measured. A flat faces front. |
strut | Positive gap between neighbouring cells. At most 10,000 cells. |
angle | Optional. Turns the cells counter-clockwise inside the area, which stays where it is. |
rim | Optional. Material left standing along the outline of the area; the strut by default, 0 lets the cells run out to the outline. |
in shape | Required, and always last. The area the cells fill: any 2D profile, a shape macro, or a face such as #f2. The pattern claims the box of the area as its slot. |
Examplerect 70 50 | extrude 3 -triangles 8 1.5 rim 5 in rect 70 50 | extrude 3
stripes#
Parallel stripes running left to right, laid over the area of a shape and cut back to it, leaving a rim along its outline. Subtract it to cut slots into a plate.
stripes width strut [angle degrees] [rim width] in area | Argument / option | Meaning & constraints |
|---|---|
width | Positive width across a stripe. One stripe runs through the middle of the area. |
strut | Positive gap between neighbouring stripes. At most 10,000 stripes. |
angle | Optional. Turns the stripes counter-clockwise inside the area, which stays where it is; 90 runs them front to back. |
rim | Optional. Material left standing along the outline of the area; the strut by default, 0 lets the cells run out to the outline. |
in shape | Required, and always last. The area the cells fill: any 2D profile, a shape macro, or a face such as #f2. The pattern claims the box of the area as its slot. |
rect 70 50 | extrude 3 -stripes 4 2 angle 45 rim 5 in rect 70 50 | extrude 3open in editor

The stripes are turned inside the area, which stays where it is, and the rim stops every one of them 5 short of the outline.
voronoi#
Cells nearest each of a set of sites, laid over the area of a shape and cut back to it, leaving a rim along its outline. Subtract it to perforate a plate.
voronoi strut [cells count] [seed seed] [points [x y]…] [relax passes] [rim width] in area | Argument / option | Meaning & constraints |
|---|---|
strut | Positive gap between neighbouring cells. |
cells | Whole number of random sites, at most 10,000, all scattered inside the area. |
seed | Whole number choosing the random arrangement; 0 by default. The same seed always gives the same cells. |
points | Sites written out as [x y], in the area's own frame centered on its box, instead of cells. |
relax | Passes that move each site to the middle of its cell, evening the cells out. 2 for random sites, 0 for points. At most 50; more is a warning and makes 50. |
rim | Optional. Material left standing along the outline of the area; the strut by default, 0 lets the cells run out to the outline. |
in shape | Required, and always last. The area the cells fill: any 2D profile, a shape macro, or a face such as #f2. The pattern claims the box of the area as its slot. |
rect 40 40 | extrude 50 apex [0 0 -170] | shell 2 [ on #f2 -voronoi 1.5 cells 20 seed 1 in #f2 | extrude 2 on #f3 -voronoi 1.5 cells 20 seed 2 in #f3 | extrude 2 on #f4 -voronoi 1.5 cells 20 seed 3 in #f4 | extrude 2 on #f5 -voronoi 1.5 cells 20 seed 4 in #f5 | extrude 2 ]open in editor

Each side is its own area, so the pattern follows the trapezoid of the face and the rim keeps the corners standing. The label brings every cut back to the vase.
06 / Shape the result
3D modifiers
Modifiers follow a solid after | and run from left to right before placement.
The whole pipeline remains one solid. Every step returns geometry centered on X and Y with
its base at Z = 0.
rotate#
Turn a solid around one axis in its own frame. Chain rotations to specify their order.
| rotate angle about axis-or-face | Argument / option | Meaning & constraints |
|---|---|
angle | Degrees, counterclockwise as seen from the positive end of the axis. |
axis-or-face | x, y, z, or a face normal such as #front. |
color steelblue cube 24 | rotate 30 about x on #top color gold cylinder 10 16open in editor

Placement uses the transformed bounds. A named face follows the original solid; #bounds.top instead selects the top of the current bounding box.
For a shape inside a 2D group, see 2D rotate.
scale#
Resize uniformly or along all three axes independently. Useful for compounds, macros, and swept solids.
| scale factor
| scale x-factor y-factor z-factor | Argument / option | Meaning & constraints |
|---|---|
factor(s) | One or three nonzero numbers. Negative factors also reflect along those axes. |
color steelblue sphere 20 @right 8 color gold sphere 20 | scale 1 1 2open in editor

Scaling after a fillet scales its radius too. Scaling before the fillet leaves the subsequently specified radius unchanged.
For a shape inside a 2D group, see 2D scale.
flip#
Reflect across the plane normal to an axis, without changing size.
| flip axis | Argument / option | Meaning & constraints |
|---|---|
axis | x, y, or z. flip x has the same geometric effect as scale -1 1 1. |
color steelblue path "M0,0 H24 L0,20 Z" | extrude 8 @right 8 color gold path "M0,0 H24 L0,20 Z" | extrude 8 | flip xopen in editor

For a shape inside a 2D group, see 2D flip.
shell#
Hollow a finished solid inward, keeping its bottom and opening the flat face that points up where the shell stands in the pipeline, the faces named, or none.
| shell thickness [open face | open [face …] | closed] | Argument / option | Meaning & constraints |
|---|---|
thickness | Positive wall thickness that leaves a valid inner cavity. |
face | A face to leave open instead of the top, such as #f2, or a list of them. |
color steelblue cylinder 36 24 | shell 3open in editor

The opening is the solid's flat top face; every other face moves inward and keeps its shape, so sloped walls and narrow necks stay. A solid without a flat top, such as a sphere, needs a cut first. Shell also accepts fused compounds.
open names the faces to leave open instead, one or a list such as open [#top #front], named as on names them where the shell
stands, so a slope such as a pyramid's #f1 can open too. closed opens none, leaving a sealed hollow to subtract from or build into later.
An opening other than the top may need the slow general computation.
color steelblue cube 40 | shell 2 open [#top #front] x 60 pyramid 4 50 40 | shell 2 open #f1open in editor

cut#
Keep only the portion between two levels on the solid's local Z axis. The result gets a new base at Z = 0 and new face names.
| cut lower upper | Argument / option | Meaning & constraints |
|---|---|
lower / upper | Heights above the base, or literal percentages such as 25%. Lower must not exceed upper; the result must retain material. |
color gold sphere 36 | cut 25% 75%open in editor

Percentages measure the solid as the preceding pipeline step left it. Levels outside the solid do not remove additional material.
chamfer#
Bevel selected logical edges of any solid with sharp edges, measured along both faces whatever angle they meet at.
| chamfer distance [distance] [at edge-selector] | Argument / option | Meaning & constraints |
|---|---|
distance | Positive and within the faces beside the selected edges: a whole face when its far edge is left alone, half of it when that edge is selected too. Zero is a warning and leaves the edges as they are. |
second distance | Cuts unevenly: the first distance lands on the face that looks further up, then further front, then further left, and the second on the other face. Swap the numbers to flip the cut. |
edge-selector | A predicate combining faces, axis directions, shared edges, nearest points and coordinate conditions with and / or / not, grown along smooth edges with tangent. See edge selectors below. Every edge when at is left out. |
color steelblue block 40 30 20 | chamfer 3 at parallel z | chamfer 1 at #topopen in editor

color steelblue block 40 30 20 | chamfer 3 1 at #topopen in editor

Edges whose faces meet at any angle are supported. Selectors read the geometry left by the previous step; a selector matching no edges is a warning, and the modifier is left out.
fillet#
Round edges with a surface tangent to their neighboring faces. Uses the same geometry, selectors, and size limits as chamfer.
| fillet radius [at edge-selector] | Argument / option | Meaning & constraints |
|---|---|
radius | Positive and within the faces beside the selected edges: a whole face when its far edge is left alone, half of it when that edge is selected too. Zero is a warning and leaves the edges as they are. |
edge-selector | The edges to round, every edge when at is left out. Edges already smoothed away cannot be selected again. |
color coral cube 30 | fillet 5open in editor

Concave edges gain material; convex edges lose it. Chamfers and fillets can be combined in one pipeline. Apply edge operations before oblique rotations.
Edge selectors#
A predicate that selects whole logical edges for chamfer and fillet, rather than the triangle edges used to draw a surface. Any tests combine with any others.
parallel axis
#face
nearest x y z
axis comparison value
selector or selector
selector and selector
not selector
tangent selector
(selector) | Argument / option | Meaning & constraints |
|---|---|
parallel x / y / z | Edges parallel to one local axis. |
#face | Boundary edges of an axis-aligned face. |
#top and #front | The edge shared by two adjacent faces. |
nearest x y z | Edges closest to a point in the solid's local frame. Ties select all equally close edges. |
z > 10 | Compare x, y, or z using <, <=, >, >=, ==, !=. An edge matches when all of it satisfies the comparison. |
#top or parallel z | Combine any selectors with or, and, not. not and tangent bind tightest, then and, then or; parentheses regroup. |
tangent parallel z | Add every edge that carries a selected edge on without a corner, such as the arcs an earlier fillet left. Stops at sharp corners, where it adds nothing. |
color gold { block 40 30 12 -cylinder 14 12 } | chamfer 2 at nearest 0 0 12open in editor

color teal block 40 30 20 | chamfer 4 at #top or parallel z | chamfer 1 at #bottom and not parallel yopen in editor

color steelblue { block 4 8 27 | fillet 2 at parallel x z top:top -8 block 4 24 8 | fillet 2 at parallel x } | fillet 1 at tangent parallel zopen in editor

Coordinates are evaluated before placement. On block 40 30 20, X spans −20
to 20, Y spans −15 to 15, and Z spans 0 to 20. z > 10 selects top edges; vertical
edges do not satisfy it over their whole length.
Each operand is evaluated over every edge before and, or and not combine the results, so nearest ranks all edges, not only
those its neighbours leave. A cylinder's logical edges are its two complete rims, so
conditions on Z can select them, while x > 0 cannot select half a rim.
07 / Place and paint
Placement & properties
Build a tree of connected volumes: continue from the previous volume, align to its edges, and use lists to branch from a shared parent. Use labels for later returns and patterns for repeated features. See the modeling guide for an example.
Choose where a solid is built, align it with its reference, reserve empty space with slot, and set its color. Placement and color properties precede the solid
they qualify.
@anchors#
Choose the direction from the placement reference and optionally leave a gap. Anchors seed one axis's alignment and offset.
[!]@direction [gap | unset] | Argument / option | Meaning & constraints |
|---|---|
direction | left / right on X; front / back on Y; bottom / top on Z. center centers inside the reference when no other alignment is given. |
gap | Optional signed distance along the chosen direction. |
unset | Clear the gap while keeping the direction. !@right unset closes a spaced row. |
color steelblue cube 20 [ @right 4 color gold cube 10 @front 4 color coral cube 10 @top 4 color mediumseagreen cube 10 ]open in editor

Ordinary solids default to local @top. After a negative volume, ordinary
solids default to @bottom; intersection and symmetric difference also
default to @bottom. A persistent anchor overrides these defaults.
Anchors keep the current orientation. @bottom cone 12 8 places an upright
cone below an unrotated block, with its tip against the block. on #bottom cone 12 8 turns the cone outward, with its base against the block and its tip pointing down.
x / y / z#
Set an axis's alignment, offset, or both. The same forms apply to y and z. Each axis has two independent settings.
[!]x alignment [offset]
[!]x offset
[!]x unset | Argument / option | Meaning & constraints |
|---|---|
alignment | One point aligns the same point on the reference and the new volume: x right is short for x right:right and aligns their right edges. Two points use reference:volume order: x right:left aligns the reference’s right edge with the new volume’s left edge. Named points: left / center / right on X, front / center / back on Y, and bottom / center / top on Z. Each set corresponds to 0% / 50% / 100% of the box along that axis. Percentages work in either form: x 25% aligns the 25% point on both boxes; x 100%:25% aligns the reference’s 100% point with the new volume’s 25% point. Names and percentages can be mixed, as in x right:25%. Percentages must be literal numbers followed immediately by %, such as 25%. |
offset | Signed distance along the axis, applied after alignment. Positive X always moves right. |
unset | Clear both alignment and offset; the anchor or built-in default can apply. |
color steelblue block 50 40 6 on #top [ x left 3 y front 3 color gold cube 10 x right -3 y back -3 color coral cube 10 x left:center y back:center color mediumseagreen cube 10 ]open in editor

Axis commands override whichever settings they name, including settings supplied by an anchor.
on#
Select the reference for the next solid. A face also supplies a local frame whose Z axis points outward.
on #face
on label [#face]
on root
on [label] [#face …] statement | Argument / option | Meaning & constraints |
|---|---|
#face | #front, #back, #left, #right, #top, #bottom, or an actual planar face such as #f1. |
#bounds.face | Select a face of the current bounding box, rather than a face following the original solid through transforms. |
label | A volume named with label: before its solid. Any name but root and pi works, even a command's. Optionally follow it with a face. |
root | The current context's origin; a compound or macro has its own. Reserve on root for deliberate work from that origin. Repeated on root plus XYZ offsets for individual features is an antipattern; use parent volumes, faces and branching lists. |
[#face …] | Build the statement after it on each face in turn, as a list with an on for each face would. Without a label the faces are those of the previous solid. |
body: color steelblue pyramid 4 40 30 on body #f1 color gold cylinder 8 14open in editor

body: color steelblue prism 6 edge 30 20 on body [#f2 #f3 #f4 #f5 #f6 #f7] -cylinder 8 4open in editor

A label and one-shot setters may stand before the on of their solid: plate: color red on #front cube 10. A label cannot stand before a face
list. Before any volume exists, a face selects the build plane; inside a compound or
macro body write it as on root #front. on creates no scope. On
a selected face, use x and y for sideways placement; a sideways
anchor on the first solid is rejected. A persistent anchor is ignored for that first solid,
then resumes.
Face names are local to the solid. After an initial on #front, a new
block's #front faces world-down, #back world-up, and #top world-front. The local frame lets the same macro grow outward from any
face without rewriting its coordinates. See faces and coordinate frames.
slot#
The room a solid takes, without its material. Use its faces, anchors, and labels just as you would the solid's.
slot solid | Argument / option | Meaning & constraints |
|---|---|
solid | Any solid, compound, or macro call, with its modifiers. Its faces, numbered sides included, stay available. |
Slots contribute to compound bounds. They cannot be boolean operands. A modifier shapes the room the way it would shape the solid.
A solid with a size of zero is a zero-sized volume: it keeps its room
like a slot and builds no material. As a boolean operand it is the empty volume, so cube 5 -cube 0 leaves the cube whole and cube 5 &cube 0 leaves nothing.
Transforms turn its room; other modifiers are skipped, and it has no numbered sides. A zero
written as a plain number warns; one computed from a variable does not.
set $lid 0 color steelblue block 40 40 20 @top block 40 40 $lid @top color gold cylinder 10 5open in editor

gap: slot block 60 40 20 color steelblue block 60 40 5 on gap #back color gold block 60 20 5open in editor

slot prism 6 20 20 [ on #f2 color coral cube 10 on #f3 color coral cube 10 on #f4 color coral cube 10 ]open in editor

color#
Set a solid's color. A plain setter applies once; ! makes it persistent in the current scope. 3MF and STEP export include colors only when the model sets one.
[!]color name-or-hex
[!]color unset | Argument / option | Meaning & constraints |
|---|---|
name-or-hex | A CSS color name or six-digit RGB hex color such as #ff0000. Color variables are not supported. |
unset | Use the built-in default once. !color unset clears the persistent color. |
!@right 4 !color steelblue cube 12 color gold cube 12 cube 12 color #e87864 cube 12open in editor

Persistent appearance settings enter lists, compounds, and macro bodies. Changes within a list, compound, or macro stay inside it.
08 / Compute the numbers
Variables & expressions
Every numeric argument is a number, a $variable, a function call such as sqrt(50), a measure such as base.width, or an expression in
parentheses. The parentheses keep the arguments of a command apart, so cube ($a + 2) is one argument where cube $a 2 would be two. A sign alone needs none: x -$inset negates the variable, since no volume begins with a value.
set#
Assign a number or string immediately. Values must exist before use; later reassignment does not change earlier geometry or stored settings.
set $name value | Argument / option | Meaning & constraints |
|---|---|
$name | A case-sensitive name beginning with a letter, followed by letters, digits, or underscores. |
value | A number, variable, parenthesized numeric expression, or double-quoted string. Strings can supply text and path profiles. |
set $size 20 set $label "Hi" block ($size * 2) $size 4 on #top text $label | extrude 2
A variable is written with its $ wherever a number or a profile string is accepted.
Lists share variables; compound assignments stay local. Macro bodies see only parameters and
local assignments. A pattern index is local to its pattern.
( expression )#
Combine numbers and numeric variables. Operators of a higher row bind tighter; within a row they apply from left to right, except ** which applies from right to left.
( operand operator operand … )
( test ? value : otherwise ) | Argument / option | Meaning & constraints |
|---|---|
** | Power: 2 ** 3 is 8, and 2 ** 3 ** 2 is 2 ** 9. Binds tighter than a leading minus, so -2 ** 2 is -4. |
- (unary) | Negation: -$size. |
* / % | Multiply, divide and remainder. % takes the sign of its divisor, so -1 % 4 is 3 and a == floor(a / b) * b + a % b. |
+ - | Add and subtract. |
a < b ? x : y | Choice, the loosest of all: x when the test holds, y otherwise. Compares with < <= > >= == !=, as edge selectors do, and == treats numbers within 0.000001 as equal. Only the picked value is worked out; chains nest to the right. |
and or not | Join and turn comparisons in a test, not binding tightest and or loosest. The right side is only worked out when it can change the answer. |
"text" == $s | A text compares only by == and !=, and never equals a number. |
( ) | Group any part of an expression; nesting is allowed. |
!color steelblue grid 4 3 2 with index $i cylinder 8 (4 + $i % 4 * 3 + floor($i / 4) * 6)open in editor

!color steelblue grid 3 3 with index $i block 8 8 ($i % 2 == 0 ? 10 : 5)open in editor

Numbers may carry a decimal point, as in 1.5, and never touch a word: 2pi is an error, so write (2 * pi). A division or remainder by zero is an
error, and so is a power with no real value, such as (-8) ** 0.5. Percentages such as 25% are literal points on a
box, not expressions; inside parentheses % is always the remainder.
functions#
Work out a number from others. A call stands wherever a number does, inside an expression or bare as an argument, and calls nest. The name touches its opening parenthesis; commas part the arguments.
sin(degrees) cos(degrees) tan(degrees)
asin(value) acos(value) atan(value) atan2(y, x)
sqrt(value) exp(value) log(value) abs(value)
round(value) floor(value) ceil(value)
min(value, …) max(value, …) lerp(from, to, t) curve(value, value, …, t)
pi | Argument / option | Meaning & constraints |
|---|---|
sin cos tan | Sine, cosine and tangent of an angle in degrees. A quarter turn is exact, so sin(180) is 0. tan(90) has no value. |
asin acos atan | The angle, in degrees, of a sine, cosine or tangent: -90 to 90, 0 to 180, -90 to 90. asin and acos need a value from -1 to 1. |
atan2(y, x) | The angle of the point x, y from the +X axis, -180 to 180. |
sqrt abs | Square root of a value that is not negative; the value without its sign. |
exp log | e raised to the value, so exp(1) is e; the natural logarithm of a value above zero. |
round floor ceil | The nearest whole number, with a half rounding away from zero; the nearest at or below; at or above. |
min max | The smallest or largest of one or more values. |
lerp(from, to, t) | The point t of the way from one value to the other: from at 0, to at 1, and on past either end. |
curve(value, value, …, t) | A smooth curve through the values, the first at t 0 and the last at 1, never beyond any of them, holding the ends outside. The curve an extrude size list follows. |
pi | The constant π, written bare like a number. |
!color steelblue linear 8 9 with index $i cylinder 6 (16 + 12 * sin($i * 45))open in editor

An unknown name, a call with the wrong number of arguments, and a call with no value - the square root of a negative number - are errors.
measures#
Read a size back from a labelled volume: the side of its slot along X, Y or Z, measured in the frame the volume was placed in. A measure stands wherever a number does.
label.width label.depth label.height | Argument / option | Meaning & constraints |
|---|---|
label | A volume named with label: before its solid, already built and still in scope. |
width depth height | The slot along the X, Y and Z of its own frame, the order block takes its sizes in. |
title: slot text "PEGMATITE" | extrude 1 @bottom color steelblue block (title.width + 6) (title.depth + 6) 2 on #top color white text "PEGMATITE" | extrude 1open in editor

It is the slot that is measured, not the material, since the slot is what every other
volume is placed from. The two are the same box for most volumes; a partial revolve,
circular pattern or helix measures the whole circle it turns about, and with shrink the arc its material covers. A slot measures a solid without building it, and
a labelled macro call measures the part its body built. A solid cannot measure itself.
width( ) height( )#
Measure a 2D shape in its own frame: how far it reaches along x or y, or only at a given y or x. A shape measure stands wherever a number does.
width(2d-shape [, y]) height(2d-shape [, x]) | Argument / option | Meaning & constraints |
|---|---|
2d-shape | Any 2D shape, modifiers included, written as a profile is. It ends at the comma. A path stands upright, its y running up, as a sweep builds it. |
y / x | Where to measure: from the leftmost point at that y to the rightmost, holes and gaps included. Outside the shape it is an error. |
set $vase "M0 0H16C29.087.1 46.44-13.48 46.51-39.95S13.71-97.47 13.16-123.74 18.98-157.96 20.77-163.99H0" !color steelblue % $t star 8 2 1.6 | scale width(path $vase, $t * height(path $vase)) | rotate (90 * $t) | extrude height(path $vase)open in editor

A circle is centred, so width(circle 20, 0) is 20 and width(circle 20, 10) is 0. A silhouette drawn for a revolve is half of the solid,
so its width is the radius.
09 / Organize the build
Script structure
Branch from a reference, combine solids into a compound, and choose how their material
joins. Define reusable parts with def and choose what to build with if.
[ list ]#
Branch every item from the reference saved at the opening bracket. Closing the list restores that reference.
[ statements ] cube 20 [ @left color gold cube 8 @right color coral cube 8 ] @top sphere 10
Settings and labels are local to the list. Variables and boolean operations remain in the surrounding context. A nested list immediately after an item branches from that item's volume. A build plane selected inside the list reaches only the item it leads into.
{ compound }#
Fuse a body into one placeable solid, with its own origin, labels, and boolean operations.
[properties] { statements } [| modifier …] Touching and overlapping children are joined; disconnected children remain parts of the
same solid. The placement box encloses the slots of the children that add material,
including empty ones; a - or & child leads the next one but
claims no room. Appearance enters the body; placement applies to the finished compound.
color steelblue { block 30 30 6 cylinder 16 20 }
− / & / ^#
Change how a solid combines with existing material in the same construction context. Without a sign, geometry is added.
[properties] -solid
[properties] &solid
[properties] ^solid | Argument / option | Meaning & constraints |
|---|---|
- | Difference: remove the operand from earlier material. |
& | Intersection: retain only overlap. |
^ | Symmetric difference: retain material belonging to exactly one of the two. |
color steelblue { block 40 30 16 on #top -block 28 18 10 }open in editor

A signed volume cannot be the first volume in its construction context. It reaches inward along its anchor axis. Difference defaults to drilling from the top; intersection and symmetric difference default to base alignment. The operand leaves a placement reference even when its material is removed. A difference that removes no material is a warning.
def#
Define a reusable compound or 2D shape with numeric parameters, then call it like a solid, or where a shape is expected. A definition stands among the statements of the script, never inside braces, a list or a branch; a statement calls the macros defined above it, and a body any macro defined by the time it runs.
def %name $parameter … { statements }
def %name $parameter … statement
def %name $parameter … 2d-shape
%name argument … | Argument / option | Meaning & constraints |
|---|---|
%name | A valid identifier after %, written the same in the definition and every call. Any name is free, including one of a built-in command. |
$parameter / argument | Any number of numeric parameters, including zero. Call arguments must match the parameter count. |
body | A construction context of its own. Sees the variables set above the definition, with their values there, and its parameters; inherits appearance settings, but not the caller's variables or internal placement. Without braces it is one statement. |
2d-shape | A shape body makes a shape macro, called inside extrude, revolve, helix, or sweep. Settings such as font-size are read where it is used. |
def %spacer $diameter $height { cylinder $diameter $height -cylinder ($diameter / 2) $height } color steelblue %spacer 24 12 @right 8 color gold %spacer 18 20open in editor

Definitions may call other macros and can be written in any order. A call accepts properties, boolean signs, and modifier pipelines.
def %base path "M0,0 H40 V20 H0 Z" color steelblue %base | extrude 2 on #top color gold %base | extrude 10 wall 2 insideopen in editor

A shape macro is a solid nowhere else: calling it as a statement, or a solid macro in place of a shape, is an error.
part#
Begin a part of the model: the material built after it, up to the next part, is exported to 3MF as one named object, to STEP as bodies carrying its name, and shown or hidden as one in the editor. A part stands among the statements of the script, never inside braces, a list, a branch or a macro body.
part name | Argument / option | Meaning & constraints |
|---|---|
name | A string written out, spaces and all, such as "Left hinge". It names the part and is no reference; two parts may share a name. |
part "Box" box: color steelblue block 60 40 30 | shell 2 part "Lid" on box #top color gold block 60 40 3 on #bottom color gold block 55 35 3open in editor

Placement, labels, settings and variables carry on across a part, so the lid is built on the box. Booleans do not: a part is a construction context of its own, and a signed volume reaches only its own part. What comes before the first part is a part with no name, exported as Unnamed. A part with no material warns and is left out of the export.
if#
Build the statement after the test when it holds, and the one after else when it does not. An if stands for the branch it picks; with none picked it is as though nothing were written.
if test statement [else statement] | Argument / option | Meaning & constraints |
|---|---|
test | Two arguments compared with < <= > >= == !=, such as $ears == 1 or $style == "flange". A test of more than one comparison goes in parentheses, joined by and, or and not. Arithmetic in a bare test goes in parentheses, as in any argument. |
statement | One statement, with any on written before it. A list branches several statements from the same reference; braces are a compound. |
else statement | Optional. Built when the test does not hold; else if chains. An else belongs to the nearest if that can still take one. |
def %case $ears { block 40 30 20 if $ears == 1 [ on #left block 10 30 3 on #right block 10 30 3 ] } !color steelblue !@right 10 %case 1 %case 0open in editor

An if opens no scope and keeps no slot: what follows is placed against whatever the branch left behind, and with no branch picked against whatever the if itself followed. Setters written before it bind to the branch picked, and to nothing when none is. A macro may call itself behind a test, up to 64 calls deep.
10 / Repeat and arrange
Patterns
Repeat or mirror a body. Each pattern takes one statement as its body, with any on written in front of it; braces make that body a compound, and setters written
before the command reach the body.
repeat#
Run a body repeatedly as a continuing sequence. The pattern leaves a combined slot around its iterations.
repeat count [with index $name] body | Argument / option | Meaning & constraints |
|---|---|
count | Whole number from 0 to 10,000. Zero builds nothing. |
with index $name | Optional zero-based iteration variable. Its previous value is restored afterward. |
body | One statement, with any on written before it. Braces are a compound like anywhere else: one volume per iteration, placed by the setters before the brace, with its own variables and settings. |
!color steelblue !@right 3 repeat 5 with index $i block 10 16 (8 + $i * 5)open in editor

One-shot setters before the pattern are consumed by its first solid. A repeat body continues its sequence even when the pattern appears inside a list.
linear#
Space the iterations out along X of the current frame, their centres the distance apart whatever size each iteration is.
linear distance count [with index $name] body
linear inset margin count [with index $name] body | Argument / option | Meaning & constraints |
|---|---|
distance | From the centre of one iteration to the centre of the next. Negative runs toward −X. |
inset margin | Instead of a distance: the row spans what it is placed against, its end centres the margin in from the ends, the rest spaced evenly. One iteration is centred. |
count | Whole number from 0 to 10,000. |
with index $name / body | Same index and body forms as repeat. Each iteration starts centred on its own point of the line. |
color steelblue block 80 20 6 on #top linear 16 5 with index $i -cylinder (4 + $i * 2) 6open in editor

Unlike repeat, which puts each iteration against the previous one, a linear pattern spaces the centres, so iterations of different sizes stay on an even pitch. Placement setters before the pattern position the row as a whole, and what follows is placed against the box over what it built.
circular#
Place each iteration at its own point around a circle, beginning at +X and sweeping toward +Y in the current frame.
circular diameter count [angle degrees] [start degrees] [shrink]
[with index $name] body | Argument / option | Meaning & constraints |
|---|---|
diameter | Nonnegative diameter of the placement circle. |
count | Whole number from 0 to 10,000. |
angle / start | Sweep and starting angle. Defaults 360 and 0. Zero and negative sweeps are allowed. |
shrink | Use material bounds instead of a slot mirrored about the sweep axis. |
with index $name / body | Same index and body forms as repeat. Each iteration starts from its own circle point. |
color steelblue cylinder 60 8 on #top circular 40 8 @top -cylinder 6 8open in editor

Placement setters before the pattern position the ring as a whole. Appearance setters reach only its first solid unless made persistent. Wrap the pattern in a compound to isolate its booleans.
grid#
Lay the iterations out in cells, columns along X and rows along Y of the current frame. Every cell is the size of the largest iteration.
grid columns rows [gap] [inset margin] [y-margin] [with index $name] body | Argument / option | Meaning & constraints |
|---|---|
columns / rows | Whole numbers; their product is at most 10,000. Zero builds nothing. |
gap | Distance between neighbouring cells. Default 0, cells touching; negative overlaps them. |
inset margin y-margin | Instead of a gap: the grid spans what it is placed against, its outermost centres the margin in from the edges, y-margin along Y if given. grid 2 2 inset 9 puts four corner holes 9 from the edges. |
with index $name / body | Same index and body forms as repeat. The index runs along a row first, from the left front cell; each iteration starts centred in its own cell. |
color steelblue block 50 50 6 on #top grid 4 4 4 -cylinder 6 6open in editor

Placement setters before the pattern position the grid as a whole, and what follows is placed against the box over all its cells. A grid of negative volumes reaches into what it was placed against, as a single negative volume does.
mirror#
Build the body, then a reflected copy of it beside it, the two standing against a plane between them that faces the axis.
mirror axis [gap] [inset margin] [with index $name] body | Argument / option | Meaning & constraints |
|---|---|
axis | x, y, or z of the current frame; the plane is normal to it. |
gap | Distance between the halves. Default 0, halves touching; negative overlaps them. |
inset margin | Instead of a gap: the pair spans what it is placed against, each centre the margin in from its edge. Not for mirror z. |
with index $name / body | Same index and body forms as repeat. The index is 0 for the original, on the negative side, and 1 for the copy. |
color steelblue mirror x { block 30 24 4 [ on #top x 6 -cylinder 8 4 ] @top x left block 4 24 20 }open in editor

Each half is placed by its size, as an iteration of a linear pattern is, whatever offset its body is built at. The copy is a true reflection, so text in it reads backwards, and a hole the body drills into an earlier volume is mirrored too. Placement setters before the pattern position the pair as a whole, by the box over both halves; nest one mirror in another for a part symmetric in two directions.