Madeup is a language for making things up. Using commands for moving around, its speakers walk interesting paths through 3-D space and generate geometric models tracing the paths. The models may be viewed in any standard 3-D model viewer or sent to a 3-D printer.

The language was designed for several reasons:

  1. To enable the creation of 3-D models through code. Some models are best sculpted with a mouse in a full-blown 3-D modeler. Others can be expressed more simply using a program.
  2. To teach math and computational thinking from a tangible, “first person” perspective. Madeup programmers build something out of nothing, giving them a high degree of creative involvement and responsibility in the construction process.
  3. To feed the diverse cravings of its designer, who loves programming languages and anything visual.

This document briefly describes the language.


Madeup is a programming language—a language for instructing a machine to perform some action on its user’s behalf. Like most programming languages, Madeup lets its speakers

  • repeat actions using loops,
  • choose between alternative actions using conditional statements,
  • abstract data into variables and process into functions,
  • and manipulate data through builtin functions.

The language supports recursion, higher order functions, and partial function application.

Geometric Commands

Programmers traverse 3-D space using Cartesian or turtle geometry.

moveto <x> <y> <z>
move <distance>
yaw <degrees>
pitch <degrees>
roll <degrees>

Once a satisfactory path has been traversed, that path can be turned into a geometric model in several ways:

revolve <degrees>
surface <nrows> <ncolumns>
extrude <direction> <height>

Let’s explain these through examples. Consider the following Madeup program, which walks from (3, 0, 0) in the Cartesian coordinate system in a roundabout way to (3, 2, 0):

moveto 3 0 0
moveto 7 0 0
moveto 7 2 0
moveto 3 2 0

Using tube to generate the geometry, we produce a model that surrounds the path with a hose-like structure:

A model generated using the tube command.

If instead of tube we use the revolve command, we spin the path around an axis to produce a surface of revolution:

A model generated using the revolve command.

If we use the dots command, we mark each stopping point along the path with a sphere:

A model generated using the dot command.

If we use all three of tube, dot, and revolve, we get a medley:

A model generated using tube, dots, and revolve—really, three models.

If we use the forget command, we throw away the path without generating any geometry. This is like lifting the pen in Logo:

A (non-)model generated using the forget command.

The surface command doesn’t produce anything meaningful for the above program. Let’s switch to a new program, which visits a 3×3 grid of positions, the center of which is peaked upward:

-- Closest row
moveto 0 0 0
moveto 1 0.5 0
moveto 2 0 0

-- Middle row
moveto 0 0.5 1
moveto 1 1 1
moveto 2 0.5 1

-- Farthest row
moveto 0 0 2
moveto 1 0.5 2
moveto 2 0 2

surface 3 3

Unlike the other commands, the resulting model is not a solid object:

A model generated using the surface command.

The last command, extrude, treats the path as the perimeter of a solid object’s base. It pulls the perimeter up some specified height and fills in walls, floor, and ceiling. In the following example, we trace the path of a star and then extrude it 5 units along the negative Z axis:

moveto 0 0 0
repeat 5
  move 10
  yaw -144
  move 10
  yaw 72
extrude 0 0 -1 5
A star built through extrusion.

A star built through extrusion.

Flow Commands

Besides commands to move and orient in 3-D space, Madeup has commands for controlling which commands are executed and how often:

if <condition> <then-block> else <else-block> end
repeat <n> <block> end
while <condition> <block> end
for <identifier> to <upper-bound> <block> end
for <identifier> through <upper-bound> <block> end
for <identifier> in <lower-bound>..<upper-bound> <block> end

Let’s start with a simple repeat loop. We surround a block of commands with a repeat loop and quantify how many times we’d like that block to execute. In the following program, we move 5 units forward and turn right 30 degrees—and then we do this four more times:

moveto 0 0 0
repeat 5
  move 5
  yaw 30

We get a curved tube:

A model generated using a simple loop.

Loops can nest inside of each other. In the following program: we walk along a 5×5 grid using two for loops and generate a sphere at each location:

for r to 5
  for c to 5
    moveto c 0 r


A model generated using nested loops.

Conditional statements let us choose between commands based on some criteria. We can perturb a walk along a straight line, for example, by having one step zig and the next step zag. If we’re on an even step, let’s perturb right. Otherwise, let’s perturb left:

for i to 10
  if i % 2 == 0
    moveto 0.5 i 0
    moveto -0.5 i 0


A zigzag created through conditional logic.

New Commands

If we have a sequence of code that represents a meaningful action, we can give it a meaningful name. This name becomes a new command, which we can use to execute the sequence. In the following program, for example, the code to draw a square is given the name square. We invoke the square command whenever we want a square to be drawn:

to square =
  repeat 4
    move 10
    yaw 90

moveto 0 0 0
moveto 5 -5 0

Adding a new command to Madeup to draw a square.


Numbers in Madeup programs can also be given names. The benefits are twofold. Mathematical expressions that use variables are easier to make sense of, and it’s easier to try out different values if the number isn’t sprinkled throughout the code. To draw a regular, n-sided polygon, we might use the following program:

n = 5
angle = 360.0 / n

moveto 0 0 0
repeat n
  move 5
  yaw angle


An n-sided polygon, where n is 5—a pentagon.

The value of n can be changed freely to generate hexagons, heptagons, octagons, nonagons, and so on.

Special Variables

Madeup relies on a few special variables when generating geometry:

nsides -- Defines the smoothness of the geometry (tube, dot, revolve)
radius -- Defines the girth of the geometry (tube, dot)
axis -- Defines the direction of motion (revolve, extrude)

By assigning different values to these variables, we can generate a snowman with varying levels of facetedness and body segment size using the dot command:

nsides = 6
radius = 1
moveto 0 6.5 0

nsides = 15
radius = 2
moveto 0 4 0

nsides = 50
radius = 3
moveto 0 0 0

A snowman with changing radius and nsides.



Madeup supports recursion, where functions call themselves. The following program, for example, recursively generates a Hilbert curve:

size = 10

to hilbert level degrees =
  if level > 0
    yaw degrees * -1
    hilbert level - 1 degrees * -1
    move size
    yaw degrees
    hilbert level - 1 degrees
    move size
    hilbert level - 1 degrees
    yaw degrees
    move size
    hilbert level - 1 degrees * -1
    yaw degrees * -1

moveto 0 0 0
hilbert level:4 degrees:90
Hilbert's space-filling curve, generated with recursion.

Hilbert’s space-filling curve, generated with recursion.

Where Can I Find It?

The language and its execution environment are under active development. You can try it out at


  1. Mark Osborne says:

    I liked your description of memorizing a path once it is travelled.
    I would like to write a program for a vacuum cleaner (an actual vacuum cleaner that is operated by a robot like the first Honda robot is ideal because it requires little maintenance). I just saw a good robot called Darwln. If the robot operating the vacuum cleaner could walk through the house using a remote control for the first walk through,and store this information so that it could be repeated, even set on a timer,this would be a great advantage and save over 365 hours a year just for one house. I don’t know any programming language, although I think I could learn it. Programming and memorizing movement is a very interesting topic for me, and I would like to know more about it. Thank you. Hope to hear from you soon.

Leave a Reply

Your email address will not be published. Required fields are marked *