Skip to content

Aixle reference

Generated by npm run docs from the builtin signatures. Do not edit by hand; see docs/language.md for the language itself.

Arguments are positional or by name (cylinder(r=1, h=2)); name=value in a signature is a default. shape is a 3D shape, shape2 a 2D profile, curve a bezier() or curve(). Angles are degrees. a | f(x) means f(a, x).

3D primitives

box

A box centred on the origin. One size makes a cube. round rounds every edge.

box(w, h=?, d=?, round=0) -> shape
  • w: width along x
  • h: height along y (defaults to w)
  • d: depth along z (defaults to w)
  • round: edge radius

sphere

A sphere of radius r.

sphere(r) -> shape

cylinder

A cylinder standing along y, centred on the origin.

cylinder(r, h, round=0) -> shape
  • h: height
  • round: edge radius

cone

A cone or frustum along y: radius r1 at the bottom, r2 at the top (0 for a point).

cone(r1, r2, h) -> shape

capsule

A capsule (a cylinder with hemispherical ends) along y; h is the total height.

capsule(r, h) -> shape

torus

A ring lying flat around y: R to the tube's centre, r the tube's radius.

torus(R, r) -> shape

ellipsoid

An ellipsoid with radii rx, ry, rz.

ellipsoid(rx, ry, rz) -> shape

octahedron

An octahedron with its points s from the centre.

octahedron(s) -> shape

prism

A regular polygon (sides, circumradius r) extruded to height h along y, one flat facing +z.

prism(sides, r, h) -> shape

empty

Nothing. The starting value for building up a shape in a loop.

empty() -> shape

2D profiles

circle

A circle of radius r in the x/y plane.

circle(r) -> shape2

rect

A rectangle w by h, centred; round rounds its corners.

rect(w, h=?, round=0) -> shape2
  • h: defaults to w

ellipse

An ellipse with radii rx, ry.

ellipse(rx, ry) -> shape2

ngon

A regular polygon with sides sides and circumradius r.

ngon(sides, r) -> shape2

star

A star with points points, outer radius r1 and inner radius r2.

star(points, r1, r2) -> shape2

polygon

A polygon from x, y pairs, either as numbers or one list: polygon(0,0, 2,0, 1,1.5).

polygon(points) -> shape2
polygon(coords...) -> shape2

text

Lettering as a 2D profile from a single-stroke font (A-Z, a-z, 0-9, punctuation), laid out from x = 0 on the baseline y = 0; face="serif" adds slab serifs. size is the cap height, weight the stroke width (the profile's box reaches half the weight past the strokes, so the lettering stands size plus weight tall, and a line of n characters is about 0.8 × n × size wide, 0.93 with serifs); align is "left", "center" or "right". Extrude it for a sign, subtract it for engraving. check warns when the weight is under a grid cell.

text(text, size=1, weight=0.15, align="left", spacing=0, arc=0, face="sans") -> shape2
  • size: cap height
  • weight: stroke width
  • spacing: extra gap between letters
  • arc: bend onto a circle of this radius, centred on the origin: positive reads over the top, negative under the bottom
  • face: "sans" or "serif" (slab serifs on the same letters, set a little wider)

2D to 3D

extrude

Thicken a profile to height h, centred on its plane. axis="y" (default): the profile lies flat, its x along world x and its y along world -z, thickened up. axis="z": the profile stands facing +z, its x along x and its y along y. axis="x": it stands facing +x, its x along world -z and its y along y.

extrude(profile, h, axis="y") -> shape

revolve

Spin a profile around y; its x is the radius (draw it on x >= 0), pushed out by offset. angle below 360 sweeps only that far, from +z towards +x, with flat ends: an arch, a cutaway.

revolve(profile, offset=0, angle=360) -> shape
  • angle: degrees swept

Paths

tube

A round tube of radius r along a path of x, y, z points, joins rounded and the ends hemispheres unless cap="flat". smooth > 0 curves the path through the points (8 is plenty); taper is the radius at the end relative to the start.

tube(r, points, smooth=0, taper=1, cap="round") -> shape
tube(r, curve, taper=1, cap="round") -> shape
  • points: a flat list [x,y,z, x,y,z, ...]
  • taper: end radius / start radius
  • cap: "round" (hemispheres, reaching r past each end) or "flat" (cut at the ends)
  • curve: a bezier() or curve()
  • cap: "round" or "flat"

sweep

A 2D profile carried along a path of x, y, z points: its x runs across the path, its y up. smooth curves the path; twist turns the profile by that many degrees over the whole path; taper scales it to that factor by the end.

sweep(profile, points, smooth=0, twist=0, taper=1) -> shape
sweep(profile, curve, twist=0, taper=1) -> shape
  • points: a flat list [x,y,z, x,y,z, ...]
  • twist: degrees over the path
  • taper: end scale
  • curve: a bezier() or curve()
  • twist: degrees over the curve

bezier

An exact curve from cubic Bezier control points: an anchor, then two handles and an anchor for each piece (4, 7, 10, ... points). A tube or sweep along it is the true offset of the curve, with no facets at any grid, and costs about as much per piece as a spline's.

bezier(points) -> curve
  • points: a flat list [x,y,z, x,y,z, ...]

curve

An exact smooth curve through the points, the same shape spline() draws, for tube() and sweep(): the surface follows the true curve rather than a polyline through it.

curve(points) -> curve
  • points: a flat list [x,y,z, x,y,z, ...]

helix

A path list for a helix of radius r around y, for tube() or sweep(): it starts at (r, 0, 0) and rises from y = 0 to y = h over turns turns.

helix(r, h, turns, per_turn=16) -> list
  • per_turn: points per turn

spline

A smooth path through the points, subdivided until no piece turns more than degrees: a curve that shows no faceting in a tube or sweep, however tight.

spline(points, degrees=3) -> list
  • points: a flat list [x,y,z, x,y,z, ...]
  • degrees: largest turn between pieces

arc

A path list for an arc of radius r on the ground plane from from to to degrees (0 is +z, 90 is +x).

arc(r, from=0, to=90, segments=16) -> list

loft

A solid h tall that is profile a at the bottom and profile b at the top, blending between them; centred on y = 0 like extrude (from -h/2 to h/2), each profile laid flat with its y along -z.

loft(a, b, h) -> shape

Booleans

union

Everything in any of the shapes. k > 0 blends the joins smoothly over about k units. Same as a + b.

union(a, shapes..., k=0) -> shape
union(a, profiles..., k=0) -> shape2
  • k: blend radius

difference

a with b cut away. Same as a - b. The cut surface keeps a's material.

difference(a, b, k=0) -> shape
difference(a, b, k=0) -> shape2
  • k: blend radius

intersect

Only where a and b overlap. Same as a & b.

intersect(a, b, k=0) -> shape
intersect(a, b, k=0) -> shape2
  • k: blend radius

Transforms

move

Translate by x, y, z (a profile takes x, y).

move(shape, x=0, y=0, z=0) -> shape
move(profile, x=0, y=0) -> shape2

rotate

Rotate by degrees about x, then y, then z, around the origin, right-handed: a positive x angle turns +y towards +z, a positive y angle turns +z towards +x, a positive z angle turns +x towards +y. rotate(shape, y=45) is the usual call. A profile takes one angle, counter-clockwise.

rotate(shape, x=0, y=0, z=0) -> shape
rotate(profile, angle) -> shape2

scale

Scale about the origin: one factor for all axes, or one per axis.

scale(shape, x, y=?, z=?) -> shape
scale(profile, x, y=?) -> shape2
  • y: defaults to x
  • z: defaults to x

mirror

The shape plus its reflection across the plane perpendicular to axis through the origin: model half, mirror the rest.

mirror(shape, axis) -> shape
mirror(profile, axis) -> shape2

flip

Reflect across the plane perpendicular to axis (no copy kept).

flip(shape, axis) -> shape
flip(profile, axis) -> shape2

ground

Move the shape so the lowest point of its surface rests on y = 0 (the surface, found by rays from below, not the bounding box, which a blend or a cut can leave loose).

ground(shape) -> shape

center

Move the shape so its bounding box is centred on the origin; axes picks which of x, y, z.

center(shape, axes="xyz") -> shape

Modifiers

round

Round every edge by growing the surface outward by r (on a number: round to the nearest integer).

round(shape, r) -> shape
round(profile, r) -> shape2
round(x) -> number

offset

Grow (r > 0) or shrink (r < 0) the surface by r.

offset(shape, r) -> shape
offset(profile, r) -> shape2

hollow

Hollow for printing: a shell wall thick with a drain hole of radius r (default the wall) cut through it at the drain point, usually on the bottom, so the void is open and resin or support can escape. hollow(cup, 0.1, 0, 0, 0) drains a model standing on y = 0 through its floor.

hollow(shape, wall, x, y, z, r=?) -> shape
  • x: the drain point
  • r: drain radius

shell

Hollow the shape leaving a wall t thick inside its surface. Subtract something to open it up. check warns when t is under a grid cell.

shell(shape, t) -> shape
shell(profile, t) -> shape2
  • t: wall thickness

twist

Twist around y by degrees for every unit of height.

twist(shape, degrees) -> shape

bend

Bend about z: the shape's x axis becomes an arc of a circle of radius 57.3 / degrees centred above the origin at (0, R), curving up by degrees for every unit along x (negative bends down). A point at height y rides at radius R - y. Exact, so the box check prints is the bent shape's.

bend(shape, degrees) -> shape

wrap

Wrap around y: the shape's x axis goes round a cylinder of radius r, x = 0 landing on +z and reading left to right from the front; depth z rides at radius r + z. Standing lettering (extrude(text(...), h, "z")) wrapped this way is a label round a jar or a name round a rim: wrap(letters, 1.3) | move(0, y, 0).

wrap(shape, r) -> shape
  • r: the cylinder's radius

displace

Roughen the surface with noise: in and out by up to amp, features about size across.

displace(shape, amp, size=1, seed=0) -> shape

Repetition

array

count copies stepping by dx, dy, dz from the original.

array(shape, count, dx=0, dy=0, dz=0) -> shape

grid

nx by nz copies on the ground plane, dx and dz apart.

grid(shape, nx, nz, dx, dz=?) -> shape
  • dz: defaults to dx

ring

count copies evenly around axis (default y), each first pushed out to radius along +x.

ring(shape, count, radius=0, axis="y") -> shape

Assembly

place

Copies of a shape at each x, y, z, yaw (degrees about y) in a flat list, optionally x, y, z, yaw, scale with fields=5. Rendered as a union; exported once with a node per copy.

place(shape, placements, fields=4) -> shape
  • placements: [x,y,z,yaw, x,y,z,yaw, ...]
  • fields: 4 for x,y,z,yaw or 5 to add a scale

Queries

height

The y of the highest surface of the shape above the point (x, z): where to set something down on a blended or roughened surface. An error when nothing is there.

height(shape, x, z) -> number

top

The highest y of a shape's bounds (a bound, not necessarily a surface point); bottom(), left()... are the other faces of the box.

top(shape) -> number

bottom

The lowest y of a shape's bounds.

bottom(shape) -> number

width

The size of a shape's bounds along x.

width(shape) -> number

depth

The size of a shape's bounds along z.

depth(shape) -> number

tall

The size of a shape's bounds along y.

tall(shape) -> number

surface

The point on a shape's surface nearest to (x, y, z), as [x, y, z]: where a rod, a foot or a decal should meet a curved body. Found by sliding along the field, so it is exact on primitives and close on blends and warps.

surface(shape, x, y, z) -> list

angle

The current pose's angles for a joint, as [x, y, z] degrees (all zero at rest, or for a joint the pose does not set): what a member between two moving bodies (a hydraulic cylinder, a strut) needs to work out its end points with sin and cos. Nested joints' angles are relative to their parent.

angle(joint) -> list
  • joint: the joint's name

Materials

paint

Give the whole shape a material: a preset name, a colour ("#rrggbb" or a name), or material(...). Paint parts before combining them to keep several materials.

paint(shape, material) -> shape

decal

Paint only the part of the surface inside region, adding no geometry: a pupil on an eye (decal(eye, sphere(0.1) | move(...), "black")), a mouth line along a thin tube, a label on a jar. The region is any shape; its inside picks the material.

decal(shape, region, material) -> shape
  • region: the part of the surface inside this shape gets the material

material

A custom material, from a colour or from a preset with some of its fields changed: material("granite", scale=0.3). Patterns: solid, checker, stripes, wood, marble, noise, speckle, brick, tiles, dots. scale is the feature size in units; metal 0..1; rough 0..1; transmit 0..1 for glass; glow 0..2 for a flame or a lamp. Patterns are laid out in the frame the part is painted in, along axis (default y): stripes are bands stacked along it, wood rings and brick courses go round it, tiles and checks lie in the plane across it (floor tiles with the default y). Paint before moving the part, or set axis="x" for stripes running the other way.

material(color, pattern="", color2="", scale=?, metal=?, rough=?, seed=?, transmit=?, axis="", glow=?) -> material
  • color: a colour, or a preset name to start from
  • color2: second colour for two-tone patterns
  • scale: feature size in units
  • transmit: 0 opaque .. 1 clear glass (beauty render only)
  • axis: the pattern's axis: stripes stack along it, grain runs along it
  • glow: light the surface gives off, 0..2 (unshadowed, for flames and lamps)

rgb

A colour string from red, green, blue in 0..255.

rgb(r, g, b) -> string

hsl

A colour string from hue in degrees, saturation and lightness in 0..1.

hsl(h, s, l) -> string

Numbers

range

A list of integers: range(n) is 0..n-1; range(a, b) is a..b-1; range(a, b, step).

range(a, b=?, step=1) -> list

len

Length of a list.

len(list) -> number

sin

Sine of an angle in degrees.

sin(degrees) -> number

cos

Cosine of an angle in degrees.

cos(degrees) -> number

tan

Tangent of an angle in degrees.

tan(degrees) -> number

asin

Arcsine, in degrees.

asin(x) -> number

acos

Arccosine, in degrees.

acos(x) -> number

atan

Arctangent of y/x, in degrees; atan(y, x) takes the quadrant into account.

atan(y, x=?) -> number

sqrt

Square root.

sqrt(x) -> number

abs

Absolute value.

abs(x) -> number

floor

Round down.

floor(x) -> number

ceil

Round up.

ceil(x) -> number

min

Smallest of the numbers.

min(a, more...) -> number

max

Largest of the numbers.

max(a, more...) -> number

pow

x to the power y (also x ^ y).

pow(x, y) -> number

clamp

x limited to lo..hi.

clamp(x, lo, hi) -> number

lerp

a + (b - a) * t.

lerp(a, b, t) -> number

mod

a modulo b, always in 0..b (also a % b).

mod(a, b) -> number

rand

A repeatable pseudo-random number in 0..1 for an integer seed (use the loop index).

rand(seed) -> number

Anchors

anchor

Name a point on a shape, in the shape's own frame: anchor(post, "top", 0, 1, 0). Every move, rotate, scale, warp and posed joint above it carries the point along, so at() reads it wherever the part ends up, and a union keeps every part's anchors (the first part wins a repeated name).

anchor(shape, name, x, y, z) -> shape

at

The world point of a shape's anchor as [x, y, z]: one named with anchor(), or a free one every shape has from its box: centre, top, bottom, front, back, left, right (the box's face centres). In a pose, a point inside a joint is where the pose put it.

at(shape, name) -> list

attach

Move part so its anchor lands on the target's anchor: attach(arm, "root", post, "top") is a move with no numbers. Either anchor may be a named one or a free one (top, bottom, ...). Rotate the part first, then attach it; the anchors turn with it.

attach(part, anchor, target, targetAnchor) -> shape
  • anchor: the part's anchor
  • targetAnchor: the target's anchor

Files

import

An existing mesh as a shape: import("part.obj") or a .glb, relative to the program's folder. The mesh is sampled into a distance field over a grid of resolution cells on its longest side (default 96), so it can be cut, blended, hollowed and painted like any shape; size= scales its longest side to that many units. Closed meshes work; an open mesh has no inside and the report says so.

import(path, size=?, resolution=96) -> shape

Poses and animation

joint

Make a part turn about a pivot under poses: joint(part, "elbow", x, y, z) with the pivot in world units, declared once the part is in place; combine it with + and paint afterwards, not move. Nested joints turn with their parent. With axis=[x, y, z] the joint turns about that one direction through the pivot (a raked steering column) and a pose gives it a single angle. Exports get a node per joint and glTF animations from animation().

joint(part, name, x, y, z) -> shape
joint(part, name, x, y, z, axis=[ax, ay, az]) -> shape

pose

Name a set of joint angles: pose("wave", shoulder=[0, 0, 70], elbow=[0, 0, 40]), degrees about x, y, z per joint, or one number for a joint declared with axis=. Joints not named stay at rest. Every pose is drawn on poses.png; set pose wave makes the sheet and exports show it.

pose(name, joint=[x, y, z], ...) -> string

animation

A glTF animation from poses: animation("wave", ["rest", "wave", "rest"], seconds=1.2); keyframes are spaced evenly and interpolate linearly. A rest pose is any pose with no angles, or the name "rest". Each animation gets a frame strip anim_<name>.png.

animation(name, poses, seconds=1, loop=1) -> string

Material presets

Use any of these by name in paint(). A colour name ("red") or hex ("#c8342a") also works.

NamePatternFeature sizeColoursNotes
claysolid#c9b8a6rough 0.7
whitesolid#f2f2f0rough 0.6
blacksolid#1a1a1crough 0.6
graysolid#8a8a8arough 0.6
redsolid#c8342arough 0.6
greensolid#3f9a45rough 0.6
bluesolid#2f66c4rough 0.6
yellowsolid#e8c53arough 0.6
orangesolid#e07a2arough 0.6
purplesolid#7a4bb0rough 0.6
pinksolid#e58cb8rough 0.6
brownsolid#7a4d2brough 0.6
tealsolid#2a9b8frough 0.6
creamsolid#f0e6c8rough 0.6
navysolid#213a6brough 0.6
tansolid#c9a97arough 0.6
olivesolid#7a7a2erough 0.6
maroonsolid#6e1f2arough 0.6
skysolid#8cc4earough 0.6
limesolid#9ad13arough 0.6
charcoalsolid#3a3a3erough 0.6
ivorysolid#f4f0e2rough 0.6
coralsolid#e8735arough 0.6
goldsolid#e2b13cmetal, rough 0.3
silversolid#d4d6dametal, rough 0.25
coppersolid#c67a4ametal, rough 0.35
bronzesolid#a5772fmetal, rough 0.4
steelsolid#8e949cmetal, rough 0.45
ironsolid#5c5e62metal, rough 0.6
brasssolid#c9a54ametal, rough 0.35
chromesolid#e8eaeemetal, rough 0.1
woodwood0.25 units#b07d4a / #7a4f2arough 0.7
oakwood0.3 units#c69a63 / #8f6539rough 0.7
walnutwood0.22 units#6b4327 / #3e2414rough 0.6
pinewood0.35 units#e0c08a / #b48c55rough 0.75
ebonywood0.2 units#2c2420 / #171210rough 0.4
marblemarble1.2 units#ececea / #9a9aa0rough 0.3
granitespeckle0.05 units#8e8a86 / #3c3a38rough 0.5
stonenoise0.5 units#9a9590 / #6e6a66rough 0.9
sandstonenoise0.6 units#d9b98a / #b8945frough 0.9
concretespeckle0.03 units#a9a8a4 / #8c8b87rough 0.95
brickbrick0.5 units#b0503a / #d8cbb8rough 0.9
tilestiles0.5 units#e8e4dc / #7a7670rough 0.3
checkerchecker0.5 units#f0f0ec / #2a2a2erough 0.5
stripesstripes0.25 units#e8e4dc / #c8342arough 0.6
dotsdots0.5 units#f4f0e2 / #2f66c4rough 0.6
grassnoise0.3 units#5a9a3a / #3e7228rough 0.95
dirtnoise0.2 units#6e4e32 / #4d341frough 0.95
sandspeckle0.04 units#e2cf9a / #c8b27arough 0.95
waternoise0.8 units#3a8ad8 / #6fb4eerough 0.1
glasssolid#dff0f6glass (transmit 0.9), rough 0.05
ambersolid#e0a030glass (transmit 0.7), rough 0.1
emeraldsolid#40b070glass (transmit 0.7), rough 0.08
leatherspeckle0.06 units#6b3f24 / #4a2a16rough 0.7
rubbersolid#2a2a2crough 0.95
plasticsolid#e8e8e8rough 0.35
porcelainsolid#f6f4eerough 0.2
snownoise0.3 units#f8f9fb / #dfe6efrough 0.9
lavamarble0.8 units#f06a1a / #3a1a10rough 0.6

A pattern's feature size is in model units: a wood ring every 0.25 units suits a table leg, not a 20-unit floor. Use material(color, pattern, color2, scale=) with the two colours from this table for the same look at another size.

Patterns

For material(color, pattern, ...): solid, checker, stripes, wood, marble, noise, speckle, brick, tiles, dots.