My project is an interactive generative artwork featuring a digital garden where flowers bloom and fade over time while butterflies move toward them. The user can interact by clicking anywhere on the canvas to plant new flowers.
My inspiration came from teamLab Phenomena in Abu Dhabi I visited, where there was an immersive environment allowing people to draw butterflies, snakes, and other animals that then came to life in a shared space. That experience brought me back to childhood memories of imagination, and I wanted to capture a similar feeling through code. In future versions, I plan to expand this project by adding sound elements for the atmosphere to be richer and more immersive. I also hope to introduce more types of creatures and possibly explore touch or motion-based interaction.


The program begins in the setup() function, which creates the canvas and spawns an initial set of flowers and butterflies in random positions across the screen. The draw() loop serves as the heartbeat of the sketch. It first draws a smooth vertical gradient sky using the lerpColor() function, transitioning from soft blue at the top to gentle green near the bottom. Then, it updates all active flowers, allowing each one to grow and eventually fade as time passes. Meanwhile, the butterflies search for nearby flowers, moving toward them. The sketch also displays basic information such as the number of flowers and user instructions on planting new ones.
// Arrays to store objects
let flowers = [];
let butterflies = [];
function setup() {
createCanvas(700, 600);
// start flowers
for (let i = 0; i < 8; i++) {
flowers.push(new Flower(random(width), random(height)));
}
// start butterflies
for (let i = 0; i < 6; i++) {
butterflies.push(new Butterfly(random(width), random(height)));
}
}
function draw() {
// Draw gradient sky background
for (let y = 0; y < height; y++) {
let c = lerpColor(color(135, 206, 235), color(180, 220, 160), y / height);
stroke(c);
line(0, y, width, y);
}
// Update and draw flowers
for (let i = flowers.length - 1; i >= 0; i--) {
flowers[i].grow();
flowers[i].display();
// Remove old flowers
if (flowers[i].age > flowers[i].lifespan) {
flowers.splice(i, 1);
}
}
// Update and draw butterflies
for (let butterfly of butterflies) {
butterfly.moveTowardFlowers();
butterfly.display();
}
// Instructions
fill(255, 200);
noStroke();
fill(60);
textSize(14);
text("Click to plant flowers", 20, 30);
text(`Flowers: ${flowers.length}`, 20, 45);
}
// mouse interaction
function mousePressed() {
flowers.push(new Flower(mouseX, mouseY));
}
// flower class
class Flower {
constructor(x, y) {
// Position
this.x = x;
this.y = y;
// Size (starts small, grows)
this.size = 0;
this.maxSize = random(30, 60);
// colors (random pastels)
this.petalColor = color(random(200, 255), random(100, 200), random(200, 255));
this.centerColor = color(random(200, 255), random(180, 220), random(50, 100));
// Life
this.age = 0;
this.lifespan = random(600, 1000);
// Look
this.petalCount = floor(random(5, 9));
this.angle = random(TWO_PI);
}
// make flower grow each frame
grow() {
this.age++;
if (this.size < this.maxSize) {
this.size += 0.5;
}
this.angle += 0.005; // Slow rotation
}
// draw the flower
display() {
push();
translate(this.x, this.y);
rotate(this.angle);
// Fade out when old
let alpha = 255;
if (this.age > this.lifespan * 0.7) {
alpha = map(this.age, this.lifespan * 0.7, this.lifespan, 255, 0);
}
// draw petals
fill(red(this.petalColor), green(this.petalColor), blue(this.petalColor), alpha);
noStroke();
for (let i = 0; i < this.petalCount; i++) {
let angle = (TWO_PI / this.petalCount) * i;
let px = cos(angle) * this.size * 0.4;
let py = sin(angle) * this.size * 0.4;
push();
translate(px, py);
rotate(angle);
ellipse(0, 0, this.size * 0.6, this.size * 0.3);
pop();
}
// draw center
fill(red(this.centerColor), green(this.centerColor), blue(this.centerColor), alpha);
ellipse(0, 0, this.size * 0.4);
pop();
}
}
// butterfly class
class Butterfly {
constructor(x, y) {
// Position
this.x = x;
this.y = y;
// movement
this.vx = random(-1, 1);
this.vy = random(-1, 1);
this.speed = 1.5;
// wings
this.wingAngle = 0;
this.wingSize = random(15, 25);
// colors (random)
this.wingColor = color(random(150, 255), random(100, 200), random(150, 255));
}
// move toward nearest flower
moveTowardFlowers() {
// Find closest flower
let closestFlower = null;
let closestDist = 999999;
for (let flower of flowers) {
let d = dist(this.x, this.y, flower.x, flower.y);
if (d < closestDist && flower.size > 20) {
closestDist = d;
closestFlower = flower;
}
}
// move toward it if close enough
if (closestFlower && closestDist < 200) {
let dx = closestFlower.x - this.x;
let dy = closestFlower.y - this.y;
this.vx += dx * 0.0002;
this.vy += dy * 0.0002;
}
// randomness
this.vx += random(-0.1, 0.1);
this.vy += random(-0.1, 0.1);
// limit speed
let currentSpeed = sqrt(this.vx * this.vx + this.vy * this.vy);
if (currentSpeed > this.speed) {
this.vx = (this.vx / currentSpeed) * this.speed;
this.vy = (this.vy / currentSpeed) * this.speed;
}
// update position
this.x += this.vx;
this.y += this.vy;
// wrap around edges
if (this.x < 0) this.x = width;
if (this.x > width) this.x = 0;
if (this.y < 0) this.y = height;
if (this.y > height) this.y = 0;
// flap wings
this.wingAngle += 0.2;
}
// draw the butterfly
display() {
push();
translate(this.x, this.y);
// point in direction of movement
let angle = atan2(this.vy, this.vx);
rotate(angle);
// wing flapping (0 to 1)
let flap = sin(this.wingAngle) * 0.5 + 0.5;
let wingHeight = this.wingSize * (0.5 + flap * 0.5);
// wings
fill(this.wingColor);
noStroke();
ellipse(-5, -wingHeight, 12, wingHeight * 1.5);
ellipse(-5, wingHeight, 12, wingHeight * 1.5);
// body
fill(40);
ellipse(0, 0, 8, 15);
pop();
}
}
Every flower is represented by an instance of the Flower class. Each flower starts small and increases in size frame by frame until it reaches its maximum. Colors are chosen randomly from pastel ranges to keep the palette gentle. Each flower contains several petals arranged uniformly in a circle and slowly rotates over time. The petals fade as the flower ages. The Butterfly class handles behavior for each butterfly’s movement, which combines randomness with directed motion toward flowers.
One of the challenges I encountered was controlling butterfly motion. At first, they moved too chaotically. By adjusting acceleration toward flowers and capping their speed, I achieved a more graceful flying style. I also experimented with the fading for flowers to make the transition from bright color to transparency appear gradual and organic.
Visually, the project is calm and immersive as I wanted it to be. The background gradient, flower and butterflies all work together to create an environment that feels alive yet peaceful.