An African mask, drawn with a turtle
Code study · 2018
The oldest code I still have. I was eleven, and I had worked out how to draw a curve using only straight lines — which turns out to be the whole idea behind how computers draw curves at all.
What it is
In April 2018 I pushed a file called turtle-afrincan-mask.sb — African misspelled, and I have left the typo alone — to my first GitHub repository. I was eleven.
It draws a mask in Microsoft Small Basic, using the Turtle: a cursor you steer with Move and Turn, the same idea as Logo. It knows how to go forwards and how to rotate. It does not know what a circle is.
I am putting it here because I went back to read it recently and found something I did not expect: past-me had already found the right idea.
The one idea
Every curve in this drawing is made of straight lines. The face, the eyes, the chin — all of them come out of this:
sides = 50
length = 400 / sides
angle = 90 / sides
For j = 1 To sides
Turtle.Move(length)
Turtle.Turn(angle)
EndFor
Move a little, turn a little, fifty times. Each step is straight; the accumulated turning bends the path into an arc.
What I would defend now is the division. Both the length and the angle are divided by sides, so the total distance travelled is always 400 and the total turn is always 90°, no matter what sides is set to. The arc stays the same shape. sides only controls how finely it is drawn.
That makes it a resolution knob, and one number changes every curve in the picture at once:
At sides = 3 you can see the trick exposed — the “curve” is three straight lines. By 50 the eye cannot find the corners any more.
The radius follows from the two parameters. For a step length and a turn per step, the polygon that results is inscribed in a circle of radius
With and , that is a radius of about 255 units — which is why the face fills the window the way it does. I did not know that formula at eleven. I got there by choosing numbers until it looked right, which is a completely legitimate way to arrive at a curve.
This is also, more or less, what a graphics card does. Curves get flattened into line segments and the only real question is how many.
What else is in there
Two things I am glad past-me did.
Resetting the heading. Turtle geometry is relative: every turn is measured from wherever the turtle happens to be facing. To place a feature at an absolute position you have to normalise first, and the file does exactly that:
Turtle.PenUp()
Turtle.MoveTo(300,200)
Turtle.PenDown()
Turtle.Turn(-Turtle.Angle)
Turn(-Turtle.Angle) turns by the negative of the current heading, which sets it to zero. It is the turtle equivalent of resetting a coordinate frame, and getting it wrong is the usual reason turtle drawings come out rotated.
Separating pen state from position. PenUp, move, PenDown — travel without drawing. Obvious once you know it, not obvious when you are working it out.
What is wrong with it
Being honest about the code is more interesting than defending it.
The comments describe a different program. One block is labelled ' Left eye and the next ' Right eye. They are not. The first block draws the inner ring of both eyes, at x = 250 and x = 350; the second draws the outer ring of both, at x = 240 and x = 360. Past-me organised the code by ring and the comments by eye.
Three of the four circles do not reset their heading. The first eye does Turn(-Turtle.Angle); the other three just TurnRight() from wherever MoveTo left them pointing. A full 360° arc closes on itself either way, so the mistake is invisible in the output — but it is luck rather than design, and it is why the rings sit slightly off-centre from the point they were drawn from.
Everything is a magic number. 300, 400, 250, 150, 60, 100. Nothing is derived from anything else, so moving the face means editing eleven coordinates by hand. The sides parameter shows the instinct for abstraction was there; it just had not reached the geometry yet.
Why I kept it
I am now writing analysis pipelines where the whole point is that a parameter should be declared once and everything downstream should follow from it. That is the same instinct as dividing by sides — I just have better words for it.
It also has the shape of every piece of engineering I have enjoyed since: something continuous approximated by something discrete, with an explicit knob controlling how much error you are willing to accept.
The repository is unchanged from 2018 apart from its README. The Python reimplementation used to produce the figures on this page is in the repo, so the drawing can be run without installing Small Basic.