Pegmatite Pegmatite

The language guide

Pegmatite Script.

Start with a shape. Build on its faces.
Turn a few readable lines into a 3D model.

.pegm

A small language for
solid ideas.

On this page

01 / Getting started

Your first model

Pegmatite Script builds 3D models by creating solids and placing them against one another. Save scripts with the .pegm extension, or write directly in the editor.

Two posts anchored to a shared base
Two posts anchored to a shared base rendered from the script above
01

Make a base
A blue block, 40 × 30 × 6.

02

Build a branch
A gold post at the left edge carries a sphere.

03

Return to the parent
A coral post aligns with the base's right edge.

Build a tree of connected volumes

Write the model as you would assemble it: start with a base, attach a feature, then continue from it or branch back to its parent. Use anchors and face references for connections, alignment for matching edges, and offsets for local clearances.

Lists [ … ] let features share a parent; nested lists build on a child. Use labels for later returns, patterns for copies, and macros for reusable components. Changing the base's width above carries both posts with its edges.

Repeated on root plus XYZ offsets for individual features is an antipattern. Reserve it for deliberate work from the context's origin. Coordinates still belong in profiles, meshes and local adjustments. Keep names meaningful and indent branches so the construction is easy to read.

The coordinate system

X and Y form the ground plane; Z points up. Right is +X, back is +Y, and front is −Y. Angles are in degrees. Lengths are model units; 3MF and STEP export treat one unit as one millimeter.

Curves use more segments as their size grows. The editor uses a lighter mesh for preview; Export 3MF rebuilds the complete model with finer curves, including all construction steps. Explicit polygon side counts, such as prism 6, stay unchanged.

Export STEP writes the model for CAD programs with its curves exact: a cylinder is a true cylinder, a fillet a true round. What has no exact counterpart yet, such as a helix that widens as it climbs, is written as the flat facets of its mesh.

Try it in the editor

02 / The essentials

Reading a script

Read from top to bottom. Each statement builds geometry, changes a setting, selects a reference, or assigns a variable. Spaces and newlines separate tokens; indentation is for readability.

In command signatures and editor hints, bold keywords and symbols are typed literally; italic names are placeholders for your values, expressions, or statements. Plain brackets mark optional parts and are omitted when typing; bold brackets are literal lists. A plain | separates alternatives, and … means repetition.

grid columns rows [gap] [with index $name] body

For example, sphere diameter takes a diameter value, while prism sides [diameter | edge | across] size height uses diameter as a literal measurement keyword. After with index, choose your own variable name following the literal $.

propertiessolidmodifierscolor red @right 4cube 20| fillet 2

Properties go before their solid. Geometry modifiers go after it, separated by |. Together they form one statement.

Symbols you will meet
SyntaxMeaning
// a commentA note ignored by the script, up to the end of the line.
/* a comment */A note that may span lines. Block comments do not nest.
@topA placement direction, called an anchor.
#topA face reference, used with commands such as on.
!colorA property that stays in effect for following solids.
$size / base:A variable / a label naming a volume.
[ … ] / { … }A branching list / a compound solid.

Keep prefixes attached: !color, @top, #top, $size, and base:. A one-shot property must belong to the solid or pattern immediately following it; one left standing alone changes nothing, and the editor warns about it.

Numbers can be integers or decimals, such as 10, 0.5, or -2.5. A number cannot touch a word, so write (2 * pi) rather than 2pi. Write strings in double quotes; a backslash starts an escape, such as \" for a quote. Strings are covered in Text. Names are case-sensitive.

03 / Your building blocks

Solids & colors

Start with four simple solids. Width follows X, depth follows Y, and height follows Z. Dimensions are zero or greater: a solid of size zero builds no material but still takes its place. Round solids use a diameter.

cube

size

Equal on all three axes

block

width depth height

A rectangular solid

cylinder

diameter height

A circular base with height

sphere

diameter

A sphere measured across

Four primitives, one row
Four primitives, one row rendered from the script above

color accepts CSS color names and hex RGB values such as #ff0000. It affects the next solid only. Use !color steelblue to keep a color in effect, or color unset to use the built-in default for one solid. 3MF and STEP export include colors once a model sets any; a model in the default color exports without them.

More primitives
Command & argumentsShape
cone diameter heightA circular cone.
pyramid sides size heightA regular pyramid; at least 3 sides.
prism sides size heightA regular prism; at least 3 sides.
starprism spikes outer inner heightA star with at least 3 spikes; outer and inner diameters are both required.
torus outer innerA ring, using outer and inner diameters.
tube outer inner heightA hollow cylinder.
tetrahedron edge
octahedron edge
dodecahedron edge
icosahedron edge
Regular polyhedra, measured along an edge as a cube is.
mesh vertices [x y z] … faces [i j k] …Any closed solid with flat faces. Corners are indexed from 0; faces are #f1, #f2, … in the order written.

Prism and pyramid sizes measure the circle through the base corners, and polyhedra their edge. A word before the size measures another way: diameter through the corners, as in icosahedron diameter 20; edge along an edge, as in pyramid 4 edge 20 30; or across between two parallel flats, as in prism 6 across 17 8. For tubes, toruses, and stars, the inner diameter must be smaller than the outer diameter.

04 / Building together

Placement & anchors

The first solid starts at the construction origin. Each ordinary solid after it stacks on the previous one, centered on X and Y. An anchor changes that direction for the next solid.

Choose a direction, leave a gap
Choose a direction, leave a gap rendered from the script above
AxisNegative directionPositive direction
X@left@right
Y@front@back
Z@bottom@top

The optional number after an anchor is the gap. @center centers a volume inside its reference when no other alignment is given. All directions are relative to the current placement frame.

05 / A precise fit

Alignment & offsets

Use x, y, and z to align edges or add an offset. Each axis has two independent settings: alignment and offset.

ExampleEffect
x rightAlign the two right edges; short for x right:right.
x right:leftAlign the reference's right edge with the new solid's left edge.
x 100%:25%Align the reference's 100% point with the new solid's 25% point.
x 5Move 5 units along +X, keeping the current alignment.
x left 4Align left edges, then offset 4 units along +X.
Two corners of the same face
Two corners of the same face rendered from the script above

Use left / center / right on X, front / center / back on Y, and bottom / center / top on Z. These correspond to 0%, 50%, and 100%.

A single percentage uses the same point on both boxes: x 25% is short for x 25%:25%. Names and percentages can be mixed, as in x right:25%. Percentages must be literal numbers followed immediately by %; variables and expressions cannot be suffixed with %.

Anchor first, axis settings second

An anchor supplies alignment and a gap on one axis. Axis commands override whichever settings they name. An offset always follows the axis direction, even when aligning to the opposite edge.

06 / A new point of view

Faces & references

on selects what the next solid is built against. Selecting a face also changes the placement frame: the new solid's local Z points outward from that face.

Build outward from a face
Build outward from a face rendered from the script above
ReferenceBuild against
on #frontThe previous volume's front face.
on baseThe volume named with base:.
on base #topThe top face of that labelled volume.
on #bounds.topThe top of the bounding box, even after a rotation.
on rootThe current construction context's origin.

The standard faces are #front, #back, #left, #right, #top, and #bottom. Curved solids offer faces at their outer bounds. Prisms and polyhedra also offer numbered planar faces such as #f2.

To move across a selected face, use alignment such as on #top x right cube 10. A sideways anchor on the first solid against a face is rejected. @top 5 can still leave a gap outward from it.

A label and setters may stand before the on of their solid, so plate: on #front cube 10 keeps the label at the start of the line; a face list takes no label in front. A face selected before any volume exists chooses the build plane. Inside a compound or macro body, name it through the body's root: on root #front. on itself creates no scope and needs no closing delimiter.

Place below, or build outward?

@bottom places a solid below its reference in the current frame and keeps its orientation. on #bottom selects the bottom face and turns the construction frame so local +Z points outward. A cone makes the difference visible:

@bottom keeps the cone upright: its tip meets the block
@bottom keeps the cone upright: its tip meets the block rendered from the script above
on #bottom turns the cone outward: its base meets the block
on #bottom turns the cone outward: its base meets the block rendered from the script above

A local work surface on every face

The selected face supplies X and Y across its surface, and +Z outward. Write a macro upright once, then use it on a top, side, bottom or slanted face. Its internal dimensions and placement stay the same; the face supplies its orientation.

One boss macro, three face orientations
One boss macro, three face orientations rendered from the script above
Face names follow the solid

Starting with on #front turns the build frame: local +Y points world-up and local +Z points world-front. A block built there has its #front facing world-down, #back world-up, and #top world-front. Names describe the solid in its own frame, not the camera view. Once a solid exists, another on #front selects that solid's front face.

See the public guide's face coordinate table for all six orientations.

07 / Set it once

Persistent properties

Properties normally apply once. Prefix a setter with ! to keep it active for following solids in the current scope. A one-shot setter temporarily overrides it.

!color steelblue
!@right 4
cube 12
color gold cube 12
cube 12
!color unset
cube 12

The first and third cubes are blue; the second is gold. !color unset clears the persistent color. x unset clears both alignment and offset for that axis for one solid.

Appearance settings (color, font-size, and font) reach into compound and macro bodies. Placement settings apply to the finished group, so its internal layout stays independent.

08 / One base, many branches

Branching

Inside a list, [ … ], every item starts from the reference saved at the opening bracket, including the build plane. Closing the list restores that reference, so the surrounding sequence can continue from it.

Three branches from one block
Three branches from one block rendered from the script above

All three small cubes are placed against the large block. The sphere after the list also follows that block. To continue from a list item, open a nested list immediately after it.

When every item is the same statement on a different face, list the faces instead: on [#f2 #f3 #f4] cube 6 builds the cube on each of them, exactly as a list with one on per face would. Put a label first to name another volume's faces.

One stud on each side
One stud on each side rendered from the script above
Lists branch; sequences follow.

A list gives settings and labels a local scope. It does not isolate variables or boolean operations. Use a compound when a part needs its own construction context.

09 / Add, subtract, assemble

Compounds & booleans

Wrap solids in { … } to make a compound. Its children are fused into one placeable solid with its own origin. Properties and modifiers can apply to the whole group.

A simple mounting plate
A simple mounting plate rendered from the script above
SignOperationWhat remains
NoneUnionBoth shapes, joined.
-DifferenceExisting material outside the new solid.
&IntersectionOnly the overlapping material.
^Symmetric differenceMaterial belonging to exactly one shape.

A sign precedes the solid: -cylinder 10 18 removes material. Against a face, a subtraction drills inward. A signed solid needs existing geometry in its construction context. A subtraction that misses it, removing no material, builds with a warning.

Keep cuts local with a compound.

Boolean operations affect earlier material in the same construction context. Braces isolate that work; square brackets do not. The operand also leaves a placement reference. Put a cut in a list to return to its parent afterward, or use a label to select the volume you need.

10 / The finishing touches

Geometry modifiers

Pipe a solid through modifiers with |. They run from left to right, before placement. The finished bounding box determines how the result fits against its reference. A swept solid's pipeline begins with its profile, and the profile's own offset, round and fill come before the sweep, covered in Profiles & 2D operations.

Soften the edges
Soften the edges rendered from the script above
ModifierEffect
| rotate 45 about zTurn around an axis or a face normal.
| scale 2
| scale 1 2 1
Scale uniformly or per axis. Zero is invalid; negative factors reflect.
| flip xReflect along an axis.
| shell 2Hollow inward, leaving a bottom and an opening in local +Z. open #f2 or open [#top #front] opens those faces instead, closed none.
| cut 25% 75%Keep the portion between two Z levels; absolute heights also work.
| chamfer 2 at #topBevel selected edges by a distance.
| fillet 2Round edges by a radius, every edge or those at a selector.

Edge selectors include parallel z, a face such as #top, #top and #front, nearest 0 0 10, and conditions such as z > 10. Any of them combine with and, or and not, as in | chamfer 2 at #top or parallel z, and tangent carries a selection on round curved edges an earlier fillet left, as in | fillet 1 at tangent parallel z. Leaving out at selects every edge, so cube 20 | fillet 5 rounds the whole cube. Chamfers and fillets work on any sharp edge, whatever angle its faces meet at, so a taper or a hexagonal prism takes them too.

Order changes the result.

Select edges in the original frame and rotate afterward. A face name follows the solid through transforms; #bounds.top always selects the top of its current bounding box.

11 / Make it parametric

Variables & expressions

Declare a value with set, then refer to it with $. Wrap arithmetic in parentheses so each command's arguments stay unambiguous; a sign alone needs none, as in x -$size.

set $size 20
set $height ($size / 2)
color steelblue block $size (2 * $size) $height
color gold cylinder ($size / 2) $height

Expressions support +, -, *, /, remainder %, power **, nested parentheses, and unary minus. $i % 4 and floor($i / 4) read the column and row of a grid iteration. A choice such as ($i % 2 == 0 ? 10 : 5) picks a value by a test: comparisons joined by and, or and not, where a text compares by == and !=. Functions such as sin($a), sqrt($area), lerp(10, 20, $t) and curve(10, 30, 12, $t) stand wherever a number does, with angles in degrees; pi is π. Set a variable before using it; reassignment affects only subsequent statements.

Variables can also hold strings for text and path. They cannot supply colors or references. Percentages such as 25% must be literal numbers.

A label reads its volume back as numbers: base.width, base.depth and base.height measure the slot in the frame the volume was placed in, so block base.width base.depth base.height is the slot again. A slot measures without building, which sizes a plate to its text. A flat shape is measured in its own frame instead: width(circle 20) is 20, and width(path $vase, 40) is how wide a silhouette is 40 up, which sizes a varying profile at every height.

A plate sized to its text
A plate sized to its text rendered from the script above

12 / Define a part

Reusable macros

A macro is a named compound with numeric parameters. Write a def among the statements of the script, then call it by name with space-separated arguments anywhere below. A macro name starts with %, in the definition and in every call, so it never clashes with a built-in command.

One definition, two towers
One definition, two towers rendered from the script above

Calls behave like any other solid: anchor, color, subtract, or modify them. A macro body sees its parameters and the variables set above its definition, with the values they had there, so a later set does not change what a call builds; anything that should vary from call to call is a parameter. A body of one statement needs no braces: def %b block 10 20 30.

A macro can also name a 2D shape. Its call then stands wherever a shape goes, so one outline can be filled for a floor and walled for the sides without writing it twice.

One outline, floor and wall
One outline, floor and wall rendered from the script above

if makes a part optional. It builds the statement after its test when the test holds, and the one after else when it does not; with nothing picked it is as though nothing were written, so what follows is placed where it would be anyway. A list builds several statements as one branch.

Mounting ears, switched by a parameter
Mounting ears, switched by a parameter rendered from the script above

A bare test compares two arguments, such as $style == "flange"; a longer one goes in parentheses: if ($w > 50 and $holes == 1). else if chains, and a macro may call itself behind a test.

Names start with a letter and can contain letters, digits, and underscores. No word is reserved: $, % and a label's : keep names clear of commands, so cube: cube 10 is fine. Only root and the constant pi are taken.

13 / Let the script repeat

Repeating patterns

repeat continues a sequence. linear spaces iterations along a line, circular places each iteration around a circle, grid in columns and rows, and mirror adds a reflected copy. Each pattern leaves a combined placement slot for what follows.

!@right 2
repeat 5 with index $i {
  block 10 10 (5 + $i * 3)
  on #top sphere 6
}

The optional index starts at 0. The body is one statement, and an on written before it belongs to the body too. Braces make several statements one compound: each iteration builds one volume, placed by the setters before the brace, and keeps its variables and settings to itself. Counts must be whole numbers from 0 to 10,000.

Evenly spaced pegs of growing size
Evenly spaced pegs of growing size rendered from the script above

A linear pattern takes the distance between the centres of neighbouring iterations, then the count. Where repeat keeps the gaps even, a linear pattern keeps the centres even, so the difference shows once the iterations differ in size.

linear, grid and mirror can take inset and a margin in place of the distance or gap. The pattern then spans what it is placed against: its outermost centres stand the margin in from the edges, and the rest are spaced evenly between. That is how holes dimensioned from the edges are written: on #top grid 2 2 inset 9 -cylinder 5.5 10 drills four corner holes 9 mm in, on #top linear inset 10 3 -cylinder 4 10 a row of three, and on #top mirror x inset 8 -cylinder 4 10 a pair. A second margin sets a grid's Y inset.

Six holes on a bolt circle
Six holes on a bolt circle rendered from the script above

A circular pattern takes the circle's diameter, then the count. Optional angle and start set its sweep and starting angle; defaults are 360° and 0°. Use shrink to size its slot to the generated material instead of symmetric bounds.

Pyramids gaining sides across a grid
Pyramids gaining sides across a grid rendered from the script above

A grid takes the number of columns, then rows, then an optional gap between cells. Every cell is the size of the largest iteration, so the rows stay straight when the index changes the size. The index runs along a row first.

A bracket with gussets, written as one half
A bracket with gussets, written as one half rendered from the script above

A mirror takes the axis its plane faces, then an optional gap. The body is built against one side of the plane and again as a reflected copy against the other, so a symmetric part is written once as a half. Nest a mirror in another to get four quarters.

14 / Keep the model predictable

Slots & scope

Material is the geometry you see. A slot is the box used for placement, which can include empty space. Writing slot before any solid, as in slot block 60 40 20 or slot prism 6 100 20, keeps the room and faces of that solid with no material at all.

gap: slot block 60 40 20
block 60 40 5
on gap #back block 60 20 5

The plate stands 20 units above the ground. The named slot also lets a wall be built against the back of that space. Empty slots contribute to compound bounds, but cannot be used as boolean operands. Cutters are the other way round: a - or & volume claims none of a compound's room, so a hole drilled past both ends of a block leaves the compound the block's size.

Which boundaries affect which state?
ConstructPlacementState & scope
List [ … ]Each item branches from the saved reference.Settings and labels are local. Variables and booleans remain in the surrounding context.
Compound { … }Own origin; placed as one volume.Own labels and booleans. Inherits variables and appearance; internal changes stay local.
MacroLike a compound.Only parameters and local variables are visible. Appearance is inherited.
PatternA sequence, linear, circular, grid or mirrored arrangement; leaves a combined slot.No additional scope for a single statement; a braced body is a compound, with its own. The loop index is restored afterward.
onSelects a reference and frame.Creates no scope.
partCarries on as though it were not written.Own booleans. Settings, labels and variables carry on.

Parts

A model printed in pieces is divided into parts. part "Lid" begins one, and the material built after it, up to the next part, belongs to it. Each part is exported to 3MF as an object of its own carrying its name, and to STEP as bodies carrying it, and the editor shows or hides it as one, so you can look under the lid.

part "Box"
box: block 60 40 30 | shell 2
part "Lid"
on box #top block 60 40 3
on #bottom block 55 35 3

A part divides the material and nothing else: the lid is placed on the box as though no part were written. Only booleans stop at it, so a hole cut in the lid never reaches the box. A part is written at the top level of the script, and its name is a string written out.

15 / Draw an outline

Profiles & 2D operations

A 2D profile is a flat shape with no volume of its own. Draw it first, then give it thickness by piping it into extrude: rect 30 20 | extrude 4 makes a plate 4 units thick. The same profiles can be revolved, carried along a helix, or swept along another outline. A profile on its own, with no sweep after it, is a sketch: the editor draws it flat where the solid would stand and builds nothing, so you can see where a part goes before choosing how to sweep it.

Every profile, extruded
Every profile, extruded rendered from the script above

A path is drawn in SVG coordinates and filled, so each of its subpaths closes. Text follows the current font-size and font, and letters with holes, such as P and g, keep them. Text has a chapter of its own.

Choosing a profile

ProfileArguments
circlediameter
rectwidth height
ellipsediameter-x diameter-y
starspikes outer-diameter inner-diameter
polygonpoints [x y]… or sides [diameter|edge|across] size
#faceA face of the solid before, or label #face: the outline of that face.
pathA quoted SVG path, such as "M0,0 H20 V10 Z".
textA quoted string; font-size sets capital-letter height (default 10), and font "Roboto" 700 picks a Google Fonts family and weight.

polygon points [0 0] [30 0] [20 15] is an outline of its corners, Y up and left where its coordinates put it. polygon 6 20 is the regular hexagon a prism 6 20 stands on, centered on its origin.

Faces as shapes

A face reference written where a shape goes stands for the outline of that face, in the frame on places a solid in. So on #f2 #f2 | extrude 2 covers the face exactly, whatever its shape, and a face is the natural area for a pattern on it.

Through a label, box #top is the face as the statement labelled box built it, so a later cut does not reach it. Label a compound, box: { … }, to read the surface the cut leaves.

2D modifiers

A profile takes modifiers of its own after |, before its sweep: | offset 2 grows the outline and | offset -2 shrinks it, with sharp corners unless round follows the distance; | round 3 rounds every corner; | fill fills the holes.

The sweep is where the shape becomes a solid: steps before its word treat the outline, steps after it the solid. A 2D modifier written after the sweep is an error.

2D groups

Braces where a profile stands combine shapes into one, placed and combined the way solids are in a compound: each against the one before it, centered unless x, y or an anchor says otherwise, and cut with -, kept with & or cancelled with ^. A shape in a group, and a profile before its sweep, can also be turned with | rotate 90, mirrored with | flip x or resized with | scale 2 1.

A plate with a slot and a pair of holes
A plate with a slot and a pair of holes rendered from the script above

The plate combines rounded rectangles and circles into a single profile. The first shape keeps the coordinates it is drawn in, so { x left rect 10 10 } puts the square against a revolve's axis, and a group of one shape is that shape.

16 / Raise any outline

Extrude

extrude raises the flat profile written before it into a solid. The height comes first after the word, then any options. The result is placed like any other solid: centered on X and Y, with its base at Z = 0.

rect 30 20 | extrude 4

Walls

wall draws the outline with a thickness instead of filling it. The wall is open at the top and bottom. By default it is centered on the outline. Use inside or outside to keep the drawn outline as its outer or inner face.

Centered, inside, and outside walls
Centered, inside, and outside walls rendered from the script above

All three walls are drawn from a 30 × 30 square, so they are 32, 30, and 34 across. A hole in a shape is an outline of its own and gets its own wall. A wall thick enough to close the opening entirely is an error.

An open path, filled and walled
An open path, filled and walled rendered from the script above

A path that never returns to its start encloses nothing. Filling it closes it into a triangle, while wall follows the line itself. An open path has no inside or outside, so its wall is always centered.

A lid that fits

Use an offset for clearance: the lip of this lid is the box's outline shrunk by the wall thickness and another 0.2 units. Both parts reuse the same rounded profile.

A lid that fits its box
A lid that fits its box rendered from the script above

Towards an apex

apex [x y] runs the sides towards a point rather than straight up. With no z, the apex sits at the height and the solid closes to a point there: a pyramid on any outline. The apex is written in the profile's own coordinates. Circles, rectangles, and ellipses are centered on their origin, and a path's origin is wherever its coordinates put it.

A pyramid, a leaning point, and an irregular pyramid
A pyramid, a leaning point, and an irregular pyramid rendered from the script above

The gold point leans over the right edge. The coral pyramid has its point above M0,0, the corner where the path starts.

Give a z to place the apex away from the top. Above the height, the sides are cut short on their way to it, giving a frustum. Below the base, a negative z spreads them, so the top is larger than the base.

Cut short of the apex, and spread from below
Cut short of the apex, and spread from below rendered from the script above

With the apex at twice the height, the top is half the base. With it the same distance below, the top is one and a half times the base. An apex between the base and the height is an error, because the sides would cross before they reached the top.

Tapered walls

wall and apex combine. The wall keeps the same thickness all the way up instead of thinning with the outline. Where the outline becomes narrower than the wall, near a point or along a tight curve, the wall closes into solid material, so a walled pyramid ends in a solid tip.

A flared pot and a tapering square tube
A flared pot and a tapering square tube rendered from the script above

Long outlines that close over along their whole length, such as text walled to a point, are refused because they would take too long to build. Move the apex further above the height to keep the top open.

To another shape

to names the shape the top is, so the side runs from one outline to another: a square base rising into a round neck, or a duct changing its section. The line reads from the base to the top, and both are in the profile's own coordinates, so a top drawn off-centre leans the solid over. A top that needs 2D modifiers is written in braces, to { circle 20 | round 2 }, since steps after the sweep treat the solid.

A square base with a round top, a funnel and a twist
A square base with a round top, a funnel and a twist rendered from the script above

Each line of the side is straight. Outlines with as many corners as each other pair corner to corner, so a square runs to a turned square with smooth twisted faces. Otherwise each line joins the points the same share of the way round both outlines. Either way the top starts where the side twists least, so the square's corners meet the circle at 45 degrees. A wall has its thickness at the base and at the top and runs straight between them, open at both ends. Each shape must be a single outline without holes, and to cannot be combined with apex.

Twisting and resizing

twist turns the outline as it rises and size grows or shrinks it, both about the profile's own origin. A number is where the top ends up: twist 60 turns the top 60 degrees counter-clockwise, and size 0.5 makes it half the size of the profile, every level between taking its share.

A twist, a narrowing, and both
A twist, a narrowing, and both rendered from the script above

A list gives the value at levels spaced evenly from the base to the top, joined by a smooth curve that never overshoots them. That is a vase that swells and narrows again, and turns faster near its rim. With wall, every level is drawn with the same thickness, however wide the outline has grown.

A twisted vase
A twisted vase rendered from the script above

A size can be zero only at the base or the top, where the solid closes to a point. apex and to already say how the outline changes, so neither takes a twist or a size.

Extrude options at a glance
OptionDefaultRule
wall thicknessFilled profileZero or greater; must leave an opening.
inside / outsideCenteredOnly with wall on a closed outline.
twist degreesNo turnA number or a list of two or more; not with apex or to.
size factorThe drawn sizeAs twist; zero only at the base or the top.
apex [x y z]Straight sidesz defaults to the height; it may not lie between 0 and the height.
to topThe profile itselfOne outline without holes; not with apex.

17 / Fill an area with cells

Tilings & Voronoi

These profile generators fill a boundary with cells. Extrude the cells and subtract them to perforate a plate, or use the generated profile with another sweep operation.

Tilings

honeycomb, squares, triangles, and stripes lay cells over the area of another shape, written last after in. Each takes the size of a cell and the strut between cells. A polygon cell is measured by its diameter across the corners, as a prism is; a stripe by its width, and it runs left to right through the whole area.

Hexagons, squares, triangles, and stripes
Hexagons, squares, triangles, and stripes rendered from the script above

The cells are the holes, so subtracting a tiling perforates a plate. Along the outline of its area the tiling leaves a rim, as wide as the strut unless rim says otherwise; here rim 2 keeps an edge of 2 on every plate. The area can be any shape, so a tiling cut into a plate of the same outline keeps its edge whatever the outline is:

A honeycomb in a drawn outline
A honeycomb in a drawn outline rendered from the script above

angle turns the cells inside the area, which stays where it is: squares 8 1.5 angle 45 in rect 40 40 is a diamond lattice in the same square. | rotate would turn the area too.

Voronoi

voronoi divides its area among sites, each cell the part nearest its own site. cells 20 scatters sites at random inside the area and seed picks the arrangement, so the same seed always draws the same cells. relax evens them out, twice by default. points [x y] … writes the sites out instead.

A vase with a voronoi pattern on each side
A vase with a voronoi pattern on each side rendered from the script above

Each sloped side is the area of its own pattern, cut from its own seed. The rim, as wide as the strut, keeps the corners of the vase standing, and the label brings every cut back to the vase rather than to the cut before it.

Modifying the boundary or the cells

A 2D modifier treats the innermost shape before it. After a tiling, it changes the boundary shape; braces around the tiling make it change the cells instead.

/* Round the boundary before filling it with cells */
honeycomb 8 1.5 in rect 40 30 | round 3 | extrude 3
/* Round the cells themselves */
@right 8 { honeycomb 8 1.5 in rect 40 30 } | round 1 | extrude 3

18 / Letters as solids

Text

text is a profile like rect or circle, so letters become solids the way every other outline does: raise them with extrude. Put on a face, they stand out of it; with -, they are carved into it.

Raised and carved lettering
Raised and carved lettering rendered from the script above

The extrusion height is the depth of the letters, not their size. A string may also come from a variable, so one set $label "…" can feed several texts.

Size

font-size sets the height of a capital letter in model units, 10 by default. The other letters keep their proportion to it, so accents, tall lowercase letters, and descenders reach above or below it. Like color, it applies to the next solid, or to everything after it with !.

Three sizes; size and depth are independent
Three sizes; size and depth are independent rendered from the script above

Fonts

Without a font, text is drawn in a built-in sans-serif covering Latin-1 and Greek. Name any family from Google Fonts to use it instead, with an optional weight from 100 (thin) to 900 (black). The capital height stays the same in every font, so switching fonts does not resize the model.

Four fonts at the same size
Four fonts at the same size rendered from the script above

A font can also come from a file of your own, by URL or, from the command line, by path:

font "https://example.com/fonts/Logo.woff2"
font "fonts/Logo.otf"   /* beside the script, command-line tool only */
Where a font comes from
FamilyExampleNotes
Google Fonts name"Roboto" 700Weight defaults to 400; a weight the family lacks is an error.
https URL"https://…/Logo.woff2"Any font file; the URL needs no extension.
File path"fonts/Logo.otf"Ends in .ttf, .otf, .woff, .woff2, or .ttc; relative to the script. Read only by the command-line tool.

Font files are TrueType (TTF), OpenType (OTF), WOFF, or WOFF2, up to 10 MB; a TTC collection gives its first font. A file holds one weight, so a weight given with a file only selects one from a variable font. The family is always written out in quotes, never as a variable, because fonts are loaded before the script runs. A character the font has no glyph for is left out, with a warning.

Several lines and special characters

A string may span lines, or break them with \n. Each new line starts below the previous one, aligned on the left.

A two-line plaque
A two-line plaque rendered from the script above

A backslash starts an escape, for the characters a string cannot hold as they are:

String escapes
EscapeStands for
\nA line break
\"A double quote
\\A backslash
\u{…}The Unicode character with that hex code point, such as \u{B0} for °
Quotes and a degree sign
Quotes and a degree sign rendered from the script above

Any other escape is an error, so a backslash meant literally, as in a Windows path, is written \\.

Outlined letters

Every option of extrude works on text. A wall draws the letters hollow, and sweep runs a profile along their outlines for tube lettering.

Hollow and tube letters
Hollow and tube letters rendered from the script above

A sign sized to its text

A label measures the text it names, so the plate below grows with the word. The top face of the plate then serves as a shape, raised into a rim with wall. Change the word or the font, and the sign follows.

A plate that fits its word
A plate that fits its word rendered from the script above

19 / Carry a profile through space

Revolve, helix & sweep

A profile can follow a circular route with revolve, rise as it turns with helix, or follow another outline with sweep. Each follows its profile after | and places the resulting solid like any other model part.

Revolve

circle 20 | revolve 40

circle 20 | revolve 40 sweeps a circle around a path of diameter 40 to form a torus. Options include angle, start, about x (or Y/Z), and shrink.

Helix

A spring from a circular profile
A spring from a circular profile rendered from the script above

helix rises as it turns. pitch is the rise per turn; specify either turns or height. An optional second diameter tapers the coil. Leave enough pitch for the profile so adjacent coils do not overlap.

height is the rise of the path, and the profile reaches half its size past each end, so the helix's box is one profile taller. Center a thread on its rod with @center, and trim it flush with an intersection rather than a compound. In a path profile Y grows downwards, so the top of the drawing is the top of the solid.

Sweep

A bent rod and a mitred frame
A bent rod and a mitred frame rendered from the script above

sweep along carries a profile along the outline of another shape, the trajectory. The trajectory lies in the build plane, where an extruded shape lies, so on #top draws it on a face. The profile stands across the route: its X to the right of an open path's travel or to the outside of a closed outline, its Y up off the plane. An open path is capped at both ends; a closed outline makes a ring.

Sharp corners are mitred, the way a wall's are; add round to round their outside. about x or about y stands the trajectory upright. A profile wider than the inside of a bend has room for is refused.

Varying profiles

A shape macro called before a sweep with its last argument left off is a varying profile: the sweep gives that argument itself, from 0 where it starts to 1 where it ends, and draws the shape anew as it goes. One used once is written in place, with % and its parameter instead of a name.

A square softening as it turns, a horn, and a thinning handle
A square softening as it turns, a horn, and a thinning handle rendered from the script above

The last argument runs over an extrude's height, a revolve's turn, a helix's turns and each outline a sweep follows. Every outline is joined from the point it is drawn from, so a profile that turns turns the solid. It can change its size, corners and turn, but not how many outlines and holes it has, and a whole turn or a closed route has to end on the shape it started from.

Your next model starts here

Put a few lines together.

The editor has syntax highlighting, argument hints, and shaded, translucent, and edges only views to help you build.

Open editor