Where ideas percolate and thoughts brew

Fractal Tree

About This Sketch

The classic fractal tree demonstrates how complex natural forms emerge from simple recursive rules. Each branch splits into two smaller branches, which themselves split again, creating organic tree-like structures.

The gentle swaying motion comes from varying the branch angle with a sine wave. This is one of the most elegant examples of recursion in computer graphicsβ€”the entire tree structure is defined by a single rule applied at different scales.

Algorithm

A recursive fractal tree that grows through self-similar branching. Each branch splits into two smaller branches at an angle, creating organic tree-like structures. **Key Concepts:** - **Recursion**: Function calls itself with smaller parameters - **Self-Similarity**: Pattern repeats at different scales - **Recursive Base Case**: Stop when branches become too small - **Transformation Matrix**: Using translate/rotate for positioning - **Dynamic Animation**: Angle varies with sine wave **How it works:** 1. Draw a vertical line (the trunk/branch) 2. Move to the end of the line 3. Rotate and recursively draw left branch (67% length) 4. Rotate and recursively draw right branch (67% length) 5. Base case: stop when length < 10 pixels 6. Animate branch angle with sine wave for gentle swaying 7. Color varies by depth in the tree

Pseudocode

FUNCTION branch(length, depth):
  color = gradient based on depth
  thickness = map(length to strokeWeight)

  DRAW line from (0,0) to (0, -length)
  MOVE to (0, -length)

  IF length > 10:
    SAVE transformation state

    ROTATE by angle
    branch(length Γ— 0.67, depth + 1)

    RESTORE transformation state
    SAVE transformation state

    ROTATE by -angle
    branch(length Γ— 0.67, depth + 1)

    RESTORE transformation state

DRAW (every frame):
  CLEAR background
  MOVE to (canvas_center, canvas_bottom)

  dynamic_angle = Ο€/6 + sin(time) Γ— 0.2
  branch(100, 0)

  time = time + 0.02

Source Code

let sketch = function(p) {
    let angle = 0;

    p.setup = function() {
        p.createCanvas(400, 300);
        p.colorMode(p.RGB);
    };

    p.draw = function() {
        const colors = getThemeColors();
        p.background(...colors.bg);

        p.translate(p.width/2, p.height);
        let dynamicAngle = p.PI / 6 + p.sin(angle) * 0.2;

        branch(100, 0, colors, dynamicAngle);

        angle += 0.005;
    };

    function branch(len, depth, colors, branchAngle) {
        let t = depth / 8;
        let col = t < 0.5 ?
            colors.accent2.map((c, idx) => p.lerp(c, colors.accent1[idx], t * 2)) :
            colors.accent1.map((c, idx) => p.lerp(c, colors.accent3[idx], (t - 0.5) * 2));

        p.stroke(...col);
        p.strokeWeight(p.map(len, 10, 100, 1, 8));

        p.line(0, 0, 0, -len);
        p.translate(0, -len);

        if (len > 10) {
            p.push();
            p.rotate(branchAngle);
            branch(len * 0.67, depth + 1, colors, branchAngle);
            p.pop();

            p.push();
            p.rotate(-branchAngle);
            branch(len * 0.67, depth + 1, colors, branchAngle);
            p.pop();
        }
    }
};