Every shape has a position, orientation and size. These can be set in absolute units by using the position, orientation and size options, or in relative units using the translate, rotate and scale commands (see relative transforms below).


When you define a shape in ShapeScript, it is created at the point of origin. By default, this is the zero position of the X, Y and Z axes within the current scope, but this can be overridden using the position option.

The position option accepts a vector of up to 3 values representing a coordinate along the X Y and Z axes. If values are omitted they are assumed to be zero. The default position of every shape is 0 0 0, which is located at the origin, aka the center of the world.

Positive position values move the shape right, up, and towards the camera respectively. Negative values move it left, down and away from the camera:

cube {
    position 0 0 5 // moves the cube 5 units towards the camera

Positions are applied hierarchically. For shapes located at the root of the ShapeScript file, their position is relative to the world origin, however you can nests shapes inside groups, in which case the position of the child shapes will be measured relative to the position of their containing group.


The orientation option defines the rotation for the shape using three parameters called roll, yaw and pitch. The roll value represents a rotation around the Z axis, the yaw is rotation around the Y axis, and the pitch is a rotation around the X axis:

cube {
    orientation 0 0.25 0 // rotates the cube 45 degrees around the Y axis

The ordering of these three parameters may seem counterintuitive (Z, Y, X), but it makes sense in the context that when working with 2D paths, you often wish to apply a rotation only around the Z axis (in the XY plane), and by having that as the first parameter, you can simply omit the other values, which will default to zero.

Angles of rotation are specified as numbers in the range 0 to 2 (or 0 to -2 if you prefer), representing the number of half-turns. This again may seem odd if you were expecting degrees or radians, but using this range works better mathematically, as you avoid the need to multiply or divide computed rotation values by pi or 180, and it’s easier to mentally convert 90 degrees to 0.5 than to 1.5707963268 (see the trigonometry section for more about converting between angular representations).

While it is relatively simple to use the orientation property to specify a rotation around a single axis, it can be awkward to apply a rotation around multiple axes at once due to the fixed order. If you need to do that, you may find it simpler to use the rotate command instead (described below), which can be applied multiple times in any order.


The size option applies a scaling factor to all subsequent geometry. A scale factor of 0.5 0.5 0.5 for example, would halve the size of all subsequent shapes, as well as halving the offset applied by subsequent translate commands.

Like the position and orientation commands, size allows you to omit one or two parameters, however unlike the other commands, omitted parameters are assumed to be equal to the first value given. So size 0.5 is equivalent to size 0.5 0.5 0.5.

It it possible to apply a negative scale factor, which has the effect of flipping the geometry. For example, size 1 -1 1 would flip all subsequent shapes upside-down along the Y axis. This does not always work as intended however, and may produce odd side-effects such as turning shapes inside-out. In general it is better to stick to positive size values, and use orientation if you need to flip a shape around.

Relative Transforms

When defining paths or shapes procedurally using loops or other logic, you will often wish to position shapes or points using relative coordinates, rather than absolutely. You can do this using the translate, rotate and scale commands, which are counterparts to the position, orientation and size options.

Translation is the mathematical term for directional movement. Like position, translate takes up to 3 values representing offsets along the X Y and Z axes. Unlike position, the values do not specify the position of the containing shape, but rather they move the origin of the current scope, affecting all subsequently defined shapes.

The two following examples are therefore equivalent:

cube { position 1 0 0 }
translate 1 0 0

In both cases, the cube is moved one unit to the right. But whereas in the first example the cube itself has been moved, in the second example, the world has been moved.

This distinction doesn’t matter much until you create another shape. In the first example, the effect of setting the position is limited to the cube itself, and subsequent shapes will be unaffected. However in the second example, all subsequent shapes will also be shifted by one unit to the right.

You can prevent this by using another translate to move the origin back to its original position:

translate 1 0 0
cube // located at 1 0 0
translate -1 0 0
sphere // located at 0 0 0

Just as the translate command moves the origin, the rotate command rotates it, and the scale command increases or decreases the scale factor. These are equivalent:

cube {
    size 2
    orientation 0.25
scale 2
rotate 0.25

And as with translate, in the second case the rotation and scale will be permanently altered for all future shapes, so to reset them you would need to apply the inverse transforms:

scale 2
rotate 0.25
rotate -0.25
scale 0.5

As mentioned in the orientation section above, an advantage of the rotate command is that it allows you to apply rotations in any order. For example the following code applies a pitch of 45 degrees followed by a roll of 80 degrees, which would be very difficult to express as a single rotate or orientation instruction due to the fixed roll-yaw-pitch order:

rotate 0 0 0.25 // pitch 45 degrees
rotate 0.4 0 0 // roll 80 degrees

Index | Next: Bounds