### Article summary

In my previous post on generative art, we used Python’s Turtle library to learn the basics of generative art. In this post, we’ll dive deeper and create a generative art program that uses recursion to produce infinitely complex pieces. This time, we’ll be using p5.js.

## Why use recursion?

You might remember recursion from your computer science courses in college and think, “How does this apply to art?” It may seem like a rigid, mathematical concept, but as you can see in the examples below, recursion manifests itself in the natural world. These patterns repeat upon themselves in a beautiful, unique way, and we can use these patterns to inspire our art.

## Let’s dive in.

To explore recursion in generative art, we’re going to build a program that draws a tree. Trees, as you know, are inherently recursive data structures used in many computer algorithms, but they’re also naturally-occurring lifeforms with bark and leaves that grow out of the ground. We’ll combine both of our tree definitions in our tree-drawing program.

First off, open up the p5.js web editor. You’ll notice that the project is initialized with some boilerplate code, which sets up a blank canvas with a gray background.

```
function setup() {
createCanvas(400, 400);
}
function draw() {
background(220);
}
```

The one modification we’ll make to this boilerplate is adding a call to `noLoop`

inside of `setup`

. By default, p5.js re-runs `draw`

on every frame. This is useful for animated pieces, but since we’re drawing a static image, we can use `noLoop`

to disable this behavior.

```
function setup() {
createCanvas(400, 400);
noLoop();
}
```

Next, let’s write the signature for our recursive tree function:

```
function drawTree(x, y, angle, length) {}
```

In our function, `x`

and `y`

will represent the coordinates of the base of the tree, `angle`

will denote the angle in radians at which the tree is leaning, and `length`

will denote the length, in pixels, of the tree’s trunk.

Let’s continue with a non-recursive implementation of our function:

```
function drawTree(x, y, angle, length) {
const [x1, y1] = [x, y];
const x2 = x1 + cos(angle) * length;
const y2 = y1 - sin(angle) * length;
line(x1, y1, x2, y2);
}
```

Using a bit of trigonometry, this function draws a line starting at (`x`

, `y`

) with an `angle`

and `length`

as specified in the parameters. Note that in p5.js, the origin of the coordinate plane is the top-left corner, so y-coordinates increase in value as you go *down* the canvas, hence the `-`

in the `y2`

calculation.

Try calling the `drawTree`

function inside of `draw`

to verify that it works as expected. This invocation, for example, should draw a line starting at the bottom-center of the screen at a 90-degree angle and at a length of 1/2 of the canvas:

```
drawTree(
width / 2,
height,
PI / 2,
height / 2
);
```

## Add the recursive step.

Now let’s add the recursive step to our function. We’ll branch into two sub-trees, one leaning left and one leaning right, each half the length of the previous tree. Of course, since this is a recursive function, we also need to define a base case. We’ll set a `minLength`

of 5 at the top of our program, and stop recursing if `length`

falls below it.

```
const minLength = 5;
function drawTree(x, y, angle, length) {
const [x1, y1] = [x, y];
const x2 = x1 + cos(angle) * length;
const y2 = y1 - sin(angle) * length;
line(x1, y1, x2, y2);
if (length >= minLength) {
drawTree(x2, y2, angle + PI / 4, length / 2);
drawTree(x2, y2, angle - PI / 4, length / 2);
}
}
```

With this modification, we get our first tree-like output:

Right now, our program produces the exact same output on every run, which is a little boring. Let’s fix that by moving our inputs to variables and giving them random values in the `setup`

function.

```
let baseLength;
let minLength;
let lengthRatio;
let angleChange;
function setup() {
createCanvas(400, 400);
noLoop();
baseLength = random(height / 8, height / 2);
minLength = random(1, 10);
lengthRatio = random(0.25, 0.75);
angleChange = random(PI / 32, PI / 3);
}
function draw() {
background(220);
drawTree(width / 2, height, PI / 2, baseLength);
}
function drawTree(x, y, angle, length) {
const [x1, y1] = [x, y];
const x2 = x1 + cos(angle) * length;
const y2 = y1 - sin(angle) * length;
line(x1, y1, x2, y2);
if (length >= minLength) {
drawTree(x2, y2, angle + angleChange, length * lengthRatio);
drawTree(x2, y2, angle - angleChange, length * lengthRatio);
}
}
```

Re-running our program now, we get results that look much more diverse:

Of course, I promised we were going to take inspiration from real-life trees here, so let’s add some leaves. We’ll add a `drawLeaves`

function with the following signature:

```
function drawLeaves(x, y) {}
```

Next, we’ll add a couple more variables to the top of our file, `leafDensity`

and `leafColor`

, and randomize them in `setup`

.

```
let leafDensity;
let leafColor;
// in setup
leafDensity = random(0, 10);
leafColor = color(
random(0, 255),
random(0, 255),
random(0, 255)
);
```

Finally, we’ll implement our `drawLeaves`

function and call it in the `else`

clause of our `drawTree`

function, so leaves are only drawn at the end of branches.

```
function drawTree(x, y, angle, length) {
const [x1, y1] = [x, y];
const x2 = x1 + cos(angle) * length;
const y2 = y1 - sin(angle) * length;
line(x1, y1, x2, y2);
if (length >= minLength) {
drawTree(x2, y2, angle + angleChange, length * lengthRatio);
drawTree(x2, y2, angle - angleChange, length * lengthRatio);
} else {
drawLeaves(x2, y2);
}
}
function drawLeaves(x, y) {
push();
fill(leafColor);
noStroke();
for (let i = 0; i < leafDensity; i++) {
circle(
randomGaussian(x, 10),
randomGaussian(y, 10),
random(2, 5)
);
}
pop();
}
```

Some special notes about this code:

- The
`push`

and`pop`

functions allow us scope styles like fill and stroke to this particular function call. This allows us to apply`noStroke`

to the leaves while still using the default stroke on the branches. `randomGaussian`

produces random numbers using a normal (bell-shaped) distribution, unlike`random`

which uses a uniform distribution. This allows us to make the leaves cluster close to (`x`

,`y`

). Normal distributions are found more commonly in nature than uniform distributions, so`randomGaussian`

is usually the way to go when you want to mimic nature.

When we run the program now, we get the following results, and with that, our program is done!

## It doesn't stop there

Recursion allows us to generate beautiful, complex pieces with just a few lines of code. This tree example only scratches the surface. Below are some of my recent pieces using recursion, to give a few examples of the possibilities:

What will you create?