No history yet

Complex Algorithmic Systems

Architecting Emergent Systems

You already know how to draw shapes and use basic loops. Now, we'll move beyond placing elements manually and start designing systems—sets of rules that generate complex, organic results on their own. Instead of drawing a tree, you'll write the rules for how a tree grows.

The first step is to upgrade our source of randomness. The standard random() function is chaotic and unpredictable, like television static. For natural-looking textures and movement, we need something smoother. This is where Perlin noise comes in. It produces a sequence of values that smoothly transition from one to the next. Think of it less like a dice roll and more like the gentle rise and fall of a coastline.

Lesson image

Perlin noise isn't just a one-dimensional line. You can sample it in two dimensions to create textures like clouds or terrain, or in three dimensions to create evolving patterns over time. The key is that points close to each other in the noise space will have similar values, creating the coherent patterns we're looking for.

// In p5.js, creating a wavy line with Perlin noise
function draw() {
  background(255);
  beginShape();
  let xoff = 0; // Start at the beginning of the noise space
  for (let x = 0; x <= width; x += 10) {
    // Map the noise value (from 0-1) to a screen height
    let y = map(noise(xoff), 0, 1, 0, height);
    vertex(x, y);
    // Move through the noise space
    xoff += 0.05;
  }
  endShape();
}

By adding a second dimension to the noise function, you can generate a value for every (x, y) coordinate. This is perfect for creating textures. If you also increment a time variable each frame, you can create evolving 2D patterns, like swirling fog.

Directing Particles with Flow Fields

Now that we have a way to generate organic patterns, we can use them to direct motion. A flow field is a grid where every point has a vector—a direction and a magnitude. We can use Perlin noise to assign a smooth, swirling direction to each point in our grid. Particles placed in this field will then follow these vectors, creating fluid, life-like movement.

First, we create a grid of vectors. For each cell in the grid, we use 2D Perlin noise to get a value, which we then map to an angle. This angle becomes the direction of our vector. The result is a field of invisible currents.

Next, we introduce particles into this system. Each particle has a position, velocity, and acceleration. In each frame, the particle looks up the vector from the flow field at its current location. That vector is applied as a force, which updates the particle's acceleration. By limiting the particle's maximum speed and applying a friction-like force, we can achieve beautifully organic motion.

Growing Complexity with Recursion

Another way to create complexity from simple rules is recursion—a process where a function calls itself. In graphics, we can use this to create fractal patterns where a shape is composed of smaller versions of itself.

Imagine a function that draws a circle. Inside that function, we call it again twice to draw two smaller circles branching off the first. Each of those calls will, in turn, draw two even smaller circles. We just need a 'base case' to stop the recursion, such as when the circles become too small. This simple rule can generate an intricate, tree-like structure.

Lesson image

A more formal way to define these recursive growth patterns is with an L-system, or Lindenmayer system. An L-system is a set of rules and symbols used to model the growth of plants. It starts with an 'axiom' (an initial string, like "F") and applies 'production rules' to rewrite that string over several iterations (e.g., the rule F -> F+F-F). The resulting string is then interpreted as a set of drawing commands, like 'move forward', 'turn left', and 'turn right', to generate complex, self-similar geometry.

Whether using flow fields or recursion, the core idea is the same: you are no longer the direct artist, but the architect of a system. You define the rules, and the system generates the complex, often surprising, visual output.

Now, let's test your understanding of these generative systems.

Quiz Questions 1/5

What is the primary advantage of using Perlin noise over a standard random() function for generating natural-looking textures?

Quiz Questions 2/5

In a flow field system, what does a particle use to determine its direction of movement at any given moment?

By mastering these techniques, you can create work that feels alive, moving from static compositions to dynamic, evolving systems.