To practice Recursion:
The core recursive function is drawTree()
Recursion achieves:
Organic branch distribution
Natural color gradient (through lerpColor)
Dynamic swing effect (through noise function)
Interactive generation (through mouse click)
Note
copy(10, 10, W - 20, W - 20, 0, 0, W, W);
This copy() calls the middle area of the canvas (leaving a 10px border) and then stretches it back to the entire canvas.When creatures appear near the edge, part of them is not included in the (10,10,W-20,W-20) area, so a "disconnected" or "jagged" ghosting feeling will be produced.
chatgpt taught me to use get() to grab the entire canvas image, image() to flatten it back out without distortion or cropping, and tint() to color it or fade it,
but I ended up using copy() just to minimize the cropping range to include the entire image: copy(2, 2, W - 4, W - 4, 0, 0, W, W);
Code
let W = 600;
let Counter = 0;
let Angle;
let creatures = [];
function setup() {
createCanvas(W, W);
fill(0, 50);
strokeWeight(1);
Counter = 40;
}
function draw() {
Counter++;
rect(0, 0, W, W);
Angle = (PI + sin(Counter * 0.08)) / 8; // beat
for (let c of creatures) {
for (let j = 0; j < TWO_PI; j += TWO_PI / 8) {
drawTree(6, c.x, c.y, j, c.lengs, c.colorFrom, c.colorTo);
}
}
copy(2, 2, W - 4, W - 4, 0, 0, W, W);//shadow?
}
function mousePressed() {
let x = mouseX;
let y = mouseY;
let lengs = random(20, 40); // size
let fromCol = color(255); // outer
let toCol = color(0, random(50, 255), 0); // inner
creatures.push({ x, y, lengs, colorFrom: fromCol, colorTo: toCol });
}
function drawTree(step, x, y, rad, lengs, fromCol, toCol) {
if (step > 0) {
let inf = 25 - step;
let n = noise((x + Counter) / W, (y - Counter) / W) * inf;
let t = map(step, 6, 1, 0, 1);
let strokeCol = lerpColor(fromCol, toCol, t);
let gra = map(step, 6, 1, 250, 10);
stroke(strokeCol.levels[0], strokeCol.levels[1], strokeCol.levels[2], gra);
let newX = x + cos(rad) * lengs + cos(n) * inf;
let newY = y + sin(rad) * lengs + sin(n) * inf;
line(x, y, newX, newY);
step--;
lengs *= 0.9;
drawTree(step, newX, newY, rad + Angle, lengs, fromCol, toCol);
drawTree(step, newX, newY, rad - Angle, lengs, fromCol, toCol);
}
}