Shiffman, Chapter 8

Fractals

Recursion, self-similarity, the Cantor set, Koch curve, fractal trees, and L-systems — the geometry of nature.

Prerequisites: Basic programming. Familiarity with functions and loops is all you need.
10
Chapters
2
Simulations
10
Quizzes

Chapter 0: What Is a Fractal?

Look outside. Trees, coastlines, blood vessels, lightning, cauliflower — none of these are circles, rectangles, or lines. Euclidean geometry can't describe them. We need fractal geometry.

Benoit Mandelbrot coined the term "fractal" in 1975, defining it as "a rough or fragmented geometric shape that can be split into parts, each of which is (at least approximately) a reduced-size copy of the whole."

Self-similarity is the key trait. Pluck a branch from a tree and it looks like a miniature tree. Zoom into a coastline and the jagged pattern repeats. Zoom into a stock market graph and you can't tell if it's a year or an hour. The pattern echoes at every scale.

Two types of fractals: deterministic (perfectly self-similar, like the Koch curve) and stochastic (statistically self-similar, like a real tree or a stock chart).

What is the defining characteristic of a fractal?

Chapter 1: Recursion

Recursion is the engine behind fractals: a function that calls itself. Consider factorial:

pseudocode
function factorial(n):
  if n == 1: return 1
  return n * factorial(n - 1)

# factorial(4) = 4 * 3 * 2 * 1 = 24
Every recursive function needs an exit condition! Without one, the function calls itself forever and your program freezes. For fractals, the exit is typically "stop when the shape is smaller than X pixels."

Recursion is powerful for graphics because a function can call itself more than once. One call becomes two, two become four, four become eight — a branching explosion of self-similar structure.

pseudocode
function drawCircle(x, y, r):
  ellipse(x, y, r, r)
  if r > 2:
    drawCircle(x + r/2, y, r/2)   # right
    drawCircle(x - r/2, y, r/2)   # left
What prevents a recursive function from running forever?

Chapter 2: The Cantor Set

In 1883, George Cantor created one of the first fractals with a simple rule: take a line, erase the middle third, and repeat on the remaining segments.

pseudocode
function cantor(x, y, len):
  if len < 1: return     # Exit condition
  line(x, y, x + len, y)
  y += 20
  cantor(x, y, len / 3)              # Left third
  cantor(x + len * 2/3, y, len / 3)  # Right third
The feedback loop: Draw a line. Replace it with two smaller lines. Replace each of those with two even smaller lines. The rule applies to its own output, recursively. This is the fundamental mechanism of all fractals.
What is the rule for the Cantor set?

Chapter 3: Koch Curve

Helge von Koch (1904) created a curve by replacing the middle third of each line segment with two sides of an equilateral triangle. After many iterations, it forms an infinitely jagged, infinitely long line that fits in a finite space.

The implementation uses an ArrayList technique: instead of recursive function calls, we store line segments as objects and iteratively replace each one with four new segments. This lets us treat each segment independently — useful for animation and physics.

Five key points define the transformation of one segment into four. Points A and E are the start and end of the original. B is one-third of the way. D is two-thirds. C is the peak of the equilateral triangle, found by rotating a one-third vector by 60 degrees.
How does the Koch curve grow with each iteration?

Chapter 4: Fractal Trees

A branch is a line with two branches connected to its end. This recursive definition gives us a tree.

pseudocode
function branch(len):
  line(0, 0, 0, -len)    # Draw upward
  translate(0, -len)      # Move to tip
  len *= 0.66             # Shrink
  if len > 2:
    save()
    rotate(theta)
    branch(len)          # Right branch
    restore()
    save()
    rotate(-theta)
    branch(len)          # Left branch
    restore()
pushMatrix/popMatrix (or save/restore in Canvas) is essential here. Each branch call saves the current position and rotation, draws the sub-branch, then restores. This lets the recursion unwind correctly — after all right branches are drawn, it backtracks and draws the left ones.
Why are save/restore (pushMatrix/popMatrix) calls needed in the tree algorithm?

Chapter 5: Stochastic Trees

Deterministic trees are perfectly symmetrical. Real trees are not. By adding randomness, we get organic, natural-looking results.

Two approaches: (1) vary the branching angle randomly for each branch; (2) vary the number of sub-branches randomly (1 to 4 instead of always 2).

pseudocode
function branch(len):
  line(0, 0, 0, -len)
  translate(0, -len)
  if len > 2:
    n = random(1, 4)           # Random number of branches
    for i in n:
      theta = random(-PI/2, PI/2)  # Random angle
      save()
      rotate(theta)
      branch(len * 0.66)
      restore()
Perlin noise can also drive the angles, producing smooth, wind-like variation instead of jittery randomness. You could even animate the noise over time to make the tree sway.
How do you make a fractal tree look more natural?

Chapter 6: L-Systems

In 1968, botanist Aristid Lindenmayer created a grammar-based system to model plant growth. An L-system has three components:

ComponentDescriptionExample
AlphabetValid charactersF, G, +, -, [, ]
AxiomInitial sentence"F"
RulesReplacement rulesF → FF+[+F-F-F]-[-F+F+F]

Each generation, every character in the sentence is replaced according to the rules. The sentence grows exponentially.

Drawing instructions are embedded in the sentence. F = draw a line and move forward. + = turn right. - = turn left. [ = save position. ] = restore position. This is turtle graphics: imagine a turtle following these commands.
What are the three components of an L-system?

Chapter 7: Turtle Graphics

An L-system sentence is meaningless until we interpret it as drawing commands. The standard mapping:

CharacterAction
FDraw a line forward, then move forward
GMove forward without drawing
+Turn right by angle θ
-Turn left by angle θ
[Save current position and angle (push)
]Restore saved position and angle (pop)
The square brackets are the key to branching. When the turtle hits [, it remembers where it is. It then draws a branch. When it hits ], it teleports back to the saved position and can draw a different branch. This is exactly the pushMatrix/popMatrix pattern from our recursive tree.

With this system, the rule F → FF+[+F-F-F]-[-F+F+F] generates a beautiful, plant-like structure after just 4-5 generations.

In L-system turtle graphics, what do the [ and ] characters do?

Chapter 8: Tree Simulation

Below is an interactive fractal tree. Move the slider to change the branching angle and watch the tree reshape itself in real time.

Fractal Tree

Adjust the angle slider. Click "Randomize" for a stochastic tree with varied angles and branch counts.

Angle: 30°
Symmetry vs. stochasticity: The deterministic tree is beautiful but artificial. Toggle "Randomize" and notice how adding just a bit of variation to each branch angle makes it feel alive. Every real tree in nature is a stochastic fractal.
What makes a fractal tree "stochastic" rather than "deterministic"?

Chapter 9: Summary

TopicKey Takeaway
FractalsSelf-similar patterns that repeat at every scale
RecursionA function that calls itself, with an exit condition
Cantor setErase the middle third, repeat
Koch curveReplace middle third with a triangle bump, repeat
Fractal treeA branch is a line with two branches at its end
StochasticAdd randomness for organic, natural patterns
L-systemsGrammar-based fractals: alphabet, axiom, rules
Turtle graphicsInterpret L-system sentences as drawing commands
The lesson: Fractals reveal nature's recursive heart. A fern leaf is a fern of fern leaves. A tree branch is a tree of tree branches. By writing a function that calls itself with simple rules, we can generate the staggering variety and beauty of the natural world.

What we covered:

• Self-similarity and fractal dimension
• Recursion with exit conditions
• Cantor set, Koch curve
• Deterministic and stochastic trees
• L-systems and turtle graphics

What comes next:

Chapter 9: The Evolution of Code. Genetic algorithms, fitness functions, selection, crossover, and mutation. We let our objects evolve and discover solutions we never could have designed by hand.

What is the relationship between fractals and recursion?