Week 3 – Generative Artwork

Concept

For this project, I wanted to make something playful and a little alive. I imagined ordinary water bottles sitting on a table and thought about what it would look like if they could bounce around on their own. Well, needless to say, I have some funny stories with water bottle, and so I wanted to create this specifically. I wanted each bottle to feel different, with its own color, size, and movement.

To make this work efficiently, I used object-oriented programming. Each bottle is an instance of a WaterBottle class with its own properties like position, size, color, velocity, and gravity.

Part of the Code I’m Proud Of

One of the parts I like the most is ensuring each bottle had a unique color while keeping everything randomized. While it’s easy to do, I found it fun to experiment with colors.

let shuffledColors = shuffle(BOTTLE_COLORS).slice(0, NUM_BOTTLES);
for (let i = 0; i < NUM_BOTTLES; i++) {
  bottles.push(new WaterBottle(
    random(50, width - 50),
    height - TABLE_HEIGHT,
    random(30, 50),
    shuffledColors[i]
  ));
}

Here I shuffle the array of predefined colors and then slice the first few to assign one to each bottle. This guarantees uniqueness without hardcoding or risking duplicates. Then I loop through and create a new WaterBottle instance for each color, giving it a random size and horizontal position.

The class itself encapsulates the motion logic:

class WaterBottle {
  constructor(x, y, size, bottleColor) {
    this.x = x;
    this.y = y;
    this.size = size;
    this.baseY = y;
    this.velocity = random(-8, -5);
    this.gravity = 0.1;
    this.color = color(bottleColor);
  }

  update() {
    this.velocity += this.gravity;
    this.y += this.velocity;

    if (this.y > this.baseY) {
      this.y = this.baseY;
      this.velocity = random(-8, -5);
    }
  }

  display() {
    push();
    fill(this.color);
    noStroke();
    rectMode(CENTER);
    rect(this.x, this.y - this.size / 2, this.size / 2, this.size);
    fill(200);
    rect(this.x, this.y - this.size, this.size / 3, this.size / 7);
    pop();
  }
}

Challenges

At first, the motion felt mechanical. The bounce was either too uniform or too abrupt. I solved this by giving the bottle a randomized upward velocity every time it hits the table. That small change added unpredictability and made the motion feel more natural.

I also had to think about code structure. Without using classes, I would have had to manually update and draw each bottle, which would be messy and unscalable. Using arrays and a class keeps the logic modular and easy to extend.

Code

 

Reflection and Future Work

This project allowed me to combine visual creativity with programmatic thinking. I practiced designing independent objects, managing them in arrays, and applying simple physics in a clean, maintainable way.

For future improvements, I could: implement collisions so bottles interact with each other, add rotation or wobble for more lifelike motion, or let the user click a bottle to apply an impulse or change its colorOverall, the project demonstrates how small variations in physics and color, combined with object-oriented design, can turn a simple idea into a dynamic, generative animation.

Overall, it was incredibly fun!

Leave a Reply