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();
}
}
};