Week 3- OOP Assignment

 

Your concept:

I was inspired by my house cats, who always bring joy and happiness when I play with them or when they decide to sit on my lap. I wanted to include them, but wasn’t sure how, so I decided to base it on Nyan Cat, which I used to play when I was younger, when I had to wait for my friends to arrive, didn’t have access to the internet, or just wanted to give my brain a break.

Nyan Cat (Music Video 2011) - IMDb

Code:

I prompted Gemini to add the particles, it used blendMode(ADD) is what makes the magic particles look like they are made of light.

let segments = 8; 
let segLength = 12;
let x = [], y = [];
let fireParticles = [];

const COLORS = {
fur: [255, 235, 245], 
ears: [255, 180, 200],
eyes: [100, 200, 255],
magic: ['#FFD1DC', '#FFECB3', '#B2E2F2', '#D1FFD7', '#E0BBE4']
};

function setup() {
createCanvas(windowWidth, windowHeight);
// Initialize segment positions
for (let i = 0; i < segments; i++) {
x[i] = mouseX; 
y[i] = mouseY;
}
background(0); 
angleMode(RADIANS);
}

function draw() {
// Semi-transparent black rect creates the generative trail
blendMode(BLEND);
fill(0, 0, 0, 30); 
rect(0, 0, width, height);

let mouseSpeed = dist(mouseX, mouseY, pmouseX, pmouseY);

//Follow Logic
dragSegment(0, mouseX, mouseY);
for (let i = 0; i < x.length - 1; i++) {
dragSegment(i + 1, x[i], y[i]);
}

let headAngle = atan2(mouseY - y[1], mouseX - x[1]);
let emissionRate = map(mouseSpeed, 0, 50, 1, 8);

if (mouseIsPressed || mouseSpeed > 2) {
for(let i = 0; i < emissionRate; i++) {
fireParticles.push(new MagicParticle(x[0], y[0], headAngle, mouseSpeed));
}
}



// Tail
drawTail(x[segments-1], y[segments-1]);

// Body
for (let i = x.length - 1; i > 0; i--) {
drawCatBody(x[i], y[i], i);
}

// Glowing Particles
// We use ADD blend mode to make them pop on black
blendMode(ADD);
for (let i = fireParticles.length - 1; i >= 0; i--) {
fireParticles[i].update();
fireParticles[i].display();
if (fireParticles[i].isDead()) fireParticles.splice(i, 1);
}
blendMode(BLEND);

//Head always on top
drawCatHead(x[0], y[0], headAngle);
}

function dragSegment(i, xin, yin) {
let dx = xin - x[i];
let dy = yin - y[i];
let angle = atan2(dy, dx);
x[i] = xin - cos(angle) * segLength;
y[i] = yin - sin(angle) * segLength;
}

function drawCatBody(posx, posy, index) {
push();
translate(posx, posy);
fill(COLORS.fur);
noStroke();
ellipse(0, 0, 50 - index, 45 - index);
pop();
}

function drawTail(tx, ty) {
push();
translate(tx, ty);
stroke(COLORS.fur);
strokeWeight(12);
noFill();
let wag = sin(frameCount * 0.2) * 25;
bezier(0, 0, -15, wag, -30, -wag, -45, 0);
pop();
}

function drawCatHead(hx, hy, angle) {
push();
translate(hx, hy);
rotate(angle);

fill(COLORS.fur);
noStroke();
ellipse(10, 0, 55, 50); // Face

// Ears
fill(COLORS.ears);
triangle(-5, -20, 5, -45, 20, -20); 
triangle(10, -20, 25, -45, 40, -20); 

// Mouth
fill(255, 150, 150);
arc(30, 5, 22, 22, 0, PI);

// Eyes
fill(COLORS.eyes);
ellipse(15, -5, 10, 12);
ellipse(35, -5, 10, 12);
fill(255); 
ellipse(17, -7, 4, 4);
ellipse(37, -7, 4, 4);

// Whiskers
stroke(255, 200);
strokeWeight(1);
line(40, 2, 60, -5);
line(40, 5, 60, 5);
line(40, 8, 60, 15);
pop();
}

class MagicParticle {
constructor(x, y, angle, speed) {
this.pos = createVector(x, y);
// Spread the magic out
this.vel = p5.Vector.fromAngle(angle + random(-0.5, 0.5));
this.vel.mult(speed * 0.2 + random(1, 4));
this.lifespan = 255;
this.c = color(random(COLORS.magic));
this.size = random(2, 7);
}

update() {
this.pos.add(this.vel);
this.vel.mult(0.96); 
this.lifespan -= 4;
}

display() {
noStroke();
let alpha = map(this.lifespan, 0, 255, 0, 200);
fill(red(this.c), green(this.c), blue(this.c), alpha);
ellipse(this.pos.x, this.pos.y, this.size);

// Sparkle effect
if (random(1) > 0.95) {
fill(255, 255, 255, alpha);
ellipse(this.pos.x, this.pos.y, this.size * 0.6);
}
}

isDead() { return this.lifespan < 0; }
}

function windowResized() {
resizeCanvas(windowWidth, windowHeight);
background(0);
}
      • Embedded sketch

     

    Reflection and ideas for future work or improvements:

  • In the future, I might add interactions or obstacles to make it like an interactive fun game, but I want to be unique and something that have been done previously.

Week 3 – Flower Garden

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.

Inside teamLab Phenomena Abu Dhabi | Condé Nast Traveller Middle East

Explore TeamLab Phenomena General Admission for Adults and Youths - Pt Tourism | Groupon

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.

Week 3 – Snake Game

Describe the overall concept of your artwork

The idea for my artwork came from a conversation with my friend, I felt that I wanted to start looking into gamifying my code and so she gave me the idea to do the snake game! I looked for photos online to kind of get an idea of what it would look like. Below is one of the photos that I used as inspiration.

Ngu Update #1: A twist to the classic Snake game - Home

This photo made the concept feel more approachable as I knew I could just use built-in shape functions for the snake, adding more as the snake gets larger. I did want to add some of my own touch so I decided to use fruit images for the food. I imported 4 pictures, orange, strawberry, apple, and banana, and randomly spawned the fruits for the snake to eat. Including an array in my code was easy as I used it to store the 4 images of the fruits. I also knew that I would use a class for the snake as it had many functions unique to it, however, I did struggle a bit to get started on the code for the class. I started by watching the videos on Classes by The Coding Train which helped me wrap my mind around the idea. I also found that he had a video where he coded the snake game as well, so I watched a bit of it and used his code as reference for a few of the snake functions. I also referred to the p5.js reference page to understand the built-in functions he used in his code, and also made some of my own edits and changes to the food aspect of the game.

Embedded Sketch

Use your arrow keys to move the snake!

Week 3 – Written response

In the text I found a new meaning to the term interactive. I understood what will make a work interactive and how I can possibly apply it to my work. The author focused a lot on using feedback from the user to change the work. In other words, the work should be able to react to the user. When it comes to computers, how can we tell if computer is using our feedback to do some work or just following a set of instructions.

Week 3 – Creative Reading Response

What do you consider to be the characteristics of a strongly interactive system?

Building off of the author’s example of interactivity using a conversation (listening, thinking, and speaking), I would say for a system to be strongly interactive, the user has to intentionally cause this ‘interaction.’ I would also argue that the interaction should be something new or different to be a strong interactive system, for instance, pressing a button for the doorbell could be on the same level as the refrigerator light since it’s not a new idea. The user does it without really thinking about it. So by contrast, I would say games shown in the IM Showcase are good examples of a strongly interactive system as they usually use familiar forms of interaction for new situations, so for example, pressing a buzzer for a character to jump on the screen. I would say the characteristics of a strongly interactive system are 1) when there is some form of movement or change as a result of your action and 2) it is unique, unexpected, or different, i.e. done with intentionality. The more I think about this question, the more examples I think of from everyday life that I wonder whether they would be considered an interactive system.

What ideas do you have for improving the degree of user interaction in your p5 sketches?

For p5 sketches, the main way to impose user interaction are using the mouse and keyboard. So far, I’ve mostly used the mouse as a form of interaction to add some uniqueness to my sketches, and to kind of make the work not seem very 2d, but rather more interactive and allow the user to have some control. For this week, I also used the arrow buttons on the keyboard to add more interaction to my sketch (since it’s also a game). I hope to continue exploring more forms of user interaction that are unexpected and go beyond the scope of just the computer, maybe something to do with sound and hand movements. This would add a difference to the interactivity of my sketches as the user may be used to using the mouse and keyboard anyways.

Cosmic Mandala — Radial Symmetry Through Code

Concept

Cosmic Mandala explores radial symmetry and circular motion through generative code, drawing inspiration from 1970s psychedelic computer graphics and ancient mandala symbolism. Unlike traditional static mandalas, this piece breathes and rotates, with each layer moving independently in mesmerizing counter-rotations.

The artwork uses nested loops within loops. The outer loop cycles through 8 concentric layers, while inner loops populate each layer with 36-72 elements (lines, petals, or dots). This creates hundreds of animated elements from just a few lines of code, demonstrating the multiplicative power of loops in generative art.

The piece questions: The slowly shifting hue values and counter-rotating layers create an almost hypnotic effect, inviting viewers into a meditative space.

Code Highlight

I am particularly proud of the central spiral animation, where a single loop creates two intertwining spirals using polar coordinates and Perlin noise:

function drawCentralSpiral() {
  let numPoints = 150;
  let maxInnerRadius = maxRadius * 0.2;
  
  // First spiral
  beginShape();
  for (let i = 0; i < numPoints; i++) {
    let angle = i * 8 + t * 2;  // angle increases with each point + time
    let r = map(i, 0, numPoints, 0, maxInnerRadius);  // radius grows outward
    
    // Add organic wobble with Perlin noise
    let wobble = noise(i * 0.1, t * 0.02) * 10;
    r += wobble;
    
    // Convert polar to cartesian
    let x = cos(angle) * r;
    let y = sin(angle) * r;
    curveVertex(x, y);
  }
  endShape();
  
  // Counter-spiral (rotated 180°)
  rotate(180);
  // ... mirrors the pattern
}

This creates a dynamic yin-yang effect. The key insight: angle = i * 8 + t * 2 means each point is offset by 8 degrees, AND the entire spiral rotates via t * 2. The noise wobble prevents it from looking mechanical. One loop, 150 iterations, endless motion.

Live Sketch

Interaction: Click to pause/resume | Press 'S' to save | Press 'R' to reset animation

Reflection & Future Directions

Week 3 taught me the power of polar coordinates in generative art. While Week 2 used Cartesian grids (x, y), this piece thinks in circles (angle, radius). This shift unlocked organic, flowing patterns that feel more natural despite being equally mathematical.

The most challenging part was balancing chaos and order. Too many rotating layers made viewers dizzy; too few felt static. I settled on 8 layers with alternating rotation directions, creating visual rhythm without overwhelming motion. The counter-rotating spirals provide a focal anchor point.

Technical Insights:

  • Nested loops are multiplicative: 8 layers × 36 elements = 288 animated objects from 2 simple loops
  • Modulo creates patterns: layer % 3 cycles through 3 different pattern types seamlessly
  • HSB color mode enables smooth shifts: incrementing hue creates rainbow cycles naturally

Ideas for Future Work:

  • Interactive Meditation Tool: Mouse distance from center controls rotation speed. Moving closer would slow down the animation, creating a breath-paced meditation aid
  • Generative Variations: Add keyboard triggers (1-9) to switch between preset moods: calm (blues/slow), energetic (warm colors/fast), or chaotic (random colors/opposite rotations)
  • Sacred Geometry: Implement golden ratio (φ) and Fibonacci sequences in radius calculations for mathematically "perfect" proportions
  • Particle Systems: Replace some static elements with particles that orbit along the layers, adding another dimension of motion
  • 3D Depth: Use WebGL to extrude the mandala into 3D space, creating a rotating torus or tunnel effect
  • Sound Generation: Map each layer to a different musical note/frequency, turning the visual mandala into an ambient soundscape using Tone.js
  • Export for Projection: Optimize for full-screen projection mapping in gallery installations or meditation spaces

Created with p5.js | February 2026

Week 3 -Object Oriented Programming Megan

Concept:

The concept of this project comes from cacho, a traditional Bolivian dice game. The game is played by putting five dice inside a small leather cup, and you try to roll combinations like a poker hand, for example House, Full, etc. This game caught my attention because all the dice are identical, so I thought I could use them as objects for this project in object-oriented programming.

click it!

Process:

For the process, I first started with a photo of the cubilete, the cup, and the dice inside to be able to draw it in p5.js. I used my iPad to make a sketch highlighting the geometric shapes I needed and how I had to rotate them at different angles. At first, I used translate to set the origin at zero, zero, but later I switched to WEBGL because the dice are 3D geometric shapes.

For the rotations, I set the canvas to use Degrees so I could control exactly how much each shape rotated. That is how I made the base drawing. Then came the dice, which was the most difficult part. I started with 2D using rect, and I wanted them to rotate, so I created a move function inside the Dice class and used rotate so that every time a dice completes a full rotation, it moves forward.

Then I realized 2D did not really give the impression of a real dice, so I switched to 3D and used box from the p5.js 3D examples. For some reason, the box was deforming, its sides would stretch or cut off, so I had to apply rectMode(CENTER), which I was already using for 2D. After trying several methods, this was the only one that kept the cubes from deforming, probably because a box is made of rectangles, and if they are centered, they do not distort.

Next, I wanted to put numbers on the dice, but that turned out to be very complicated. When I tried, the dice faces blinked and did not display properly. The solution I found was to color the different faces with various shades of white and gray to make them look more realistic. I also made sure each dice had a random starting position so they did not all start at the same place.

Another very important part of the process was setting boundaries for the dice. At first, when I got a square to move, it went off the canvas, so I looked at examples from p5.js on how to use the command constrain on balls and adapted that idea. I set random limits so each dice would stop at different places on the table, giving the scene more realism like when you through dice. A key detail was making sure the dice stop rotating once they reach their limits because when I first tried it the dices would keep going on circles once they stopped moving forward.

Full code:

let dice1;
let dice2;
let dice3;
let dice4;
let dice5;

function setup() {
  createCanvas(600, 600, WEBGL);
  colorMode(HSB);
  //Random starting points
  dice1 = new Dice(random(-50, 30), random(-200, 30));
  dice2 = new Dice(random(-50, 30), random(-200, 30));
  dice3 = new Dice(random(-50, 30), random(-200, 30));
  dice4 = new Dice(random(-50, 30), random(-200, 30));
  dice5 = new Dice(random(-50, 30), random(-200, 30));
}

function draw() {
  background("#deb887");
  angleMode(DEGREES);
  
//Table
  push();
  rotate(48);
  fill("black");
  rect(-320, -250, 800, 800);
  pop();
  
  push();
  rotate(20);
  fill("black");
  rect(-210, -310, 500, 200);
  pop();
  
// Cubilete
   //Outside
  fill(30, 85, 30);
  noStroke();
  quad(-193,-286, -250, -130, -100, 40, 40, -230);
  push();
  rotate(14);
  fill(30, 85, 30);
  ellipse(-253, -145, 102, 172);
  pop();
  //Inside
  push();
  rotate(19);
  fill(120, 100, 15);
  stroke(30, 85, 38);
  strokeWeight(15);
  ellipse(-50, -77, 220, 292);
  pop();
  
  //Dice
  dice1.move()
  dice1.show()
  dice2.move()
  dice2.show()
  dice3.move()
  dice3.show()
  dice4.move()
  dice4.show()
  dice5.move()
  dice5.show()
}

// Function to restart dice when clicking
function mousePressed(){
  dice1 = new Dice(random(-50, 30), random(-200, 30));
  dice2 = new Dice(random(-50, 30), random(-200, 30));
  dice3 = new Dice(random(-50, 30), random(-200, 30));
  dice4 = new Dice(random(-50, 30), random(-200, 30));
  dice5 = new Dice(random(-50, 30), random(-200, 30));
}
class Dice{
  constructor(_x, _y){
    this.x= _x;
    this.y= _y;
    
    //So that dice can rotate
    this.angle=0
    
    //Random limit to make dice stop going forward at a certain place in the table 
    this.maxX = random(-10, 260);
    this.maxY = random(-10, 260);
    
    this.colors=["#FFFFFF", "#808080", "#D3D3D3", "#FFFDD0", "#F5F5F5", "#FAEBD7"]
    
    //To stop dice rotation
    this.stopped = false;
    
  }
  move(){
    //To make dice stop rotating when limit reached
    if (!this.stopped){
    
      //Movement forward
    this.x += 3
    this.y += 3
    
    //Limits for dice to not go past the table
    this.x = constrain(this.x, -10, this.maxX);
    this.y = constrain(this.y, -50, this.maxY);

    //If limit reached, stop rotation
    if (this.x >= this.maxX && this.y >= this.maxY) {
        this.stopped = true;
      }
    
    
    //To make them roll
    this.angle += 15; 
    this.angle %= 360;
     
    }
  }
  
 show(){
  push();
  translate(this.x, this.y);
  rotate(this.angle);
  rectMode(CENTER);

  noFill(); // Base box color
  box(65);   // 3D dice

  // Color each face with planes 
  let s = 65/2; // Half the size of the dice, used to position the planes at each face

  // Front face
  push();
  translate(0, 0, s); 
  fill("#FFFFFF");         
  plane(65, 65);       
  pop();

  // Back face
  push();
  translate(0, 0, -s); 
  rotateY(180);         
  fill("#808080");        
  plane(65, 65);        
  pop();

  // Right face
  push();
  translate(s, 0, 0);  
  rotateY(90);          
  fill("#D3D3D3");         
  plane(65, 65);
  pop();

  // Left face
  push();
  translate(-s, 0, 0); 
  rotateY(-90);         
  fill("#FFFDD0");       
  plane(65, 65);
  pop();

  // Top face
  push();
  translate(0, -s, 0); 
  rotateX(90);          
  fill("#F5F5F5");       
  plane(65, 65);
  pop();

  // Bottom face
  push();
  translate(0, s, 0);  
  rotateX(-90);         
  fill("#FAEBD7");       
  plane(65, 65);
  pop();

  pop(); 
  }
}

Code I am proud of:

I am especially proud of the code I wrote to set the boundaries for the dice. As I mentioned, it was really challenging to figure out how to make the dice stop moving and rotating once they reached their limit. Also, making sure the dice did not deform while rolling was tricky, and using rectMode(CENTER) solved that problem perfectly.

//Random limit to make dice stop going forward at a certain place in the table 
    this.maxX = random(-10, 260);
    this.maxY = random(-10, 260);
    
    
    //To stop dice rotation
    this.stopped = false;
    
  }
  move(){
    //To make dice stop rotating when limit reached
    if (!this.stopped){
    
      //Movement forward
    this.x += 3
    this.y += 3
    
    //Limits for dice to not go past the table
    this.x = constrain(this.x, -10, this.maxX);
    this.y = constrain(this.y, -50, this.maxY);

    //If limit reached, stop rotation
    if (this.x >= this.maxX && this.y >= this.maxY) {
        this.stopped = true;
      }
show(){
  push();
  translate(this.x, this.y);
  rotate(this.angle);
  rectMode(CENTER);

  noFill(); // Base box color
  box(65);   // 3D dice

Overall reflection:

The hardest part was definitely trying to put numbers on the dice, which I did not fully achieve. Maybe with more research on 3D objects, I could eventually make it exactly how I intended. But I really liked the final result, especially because it looks a lot like the cacho I play in real life. I also enjoyed working with objects because it made it easy to create multiple dice without repeating code, giving each one different positions and starting points that I could edit freely.

Overall, this project taught me a lot about working with 3D shapes and object-oriented programming. I learned that even small details, like the starting position, rotation, and boundaries, make a huge difference in making the animation feel realistic. I am happy with how I managed to combine my reference from real-life cacho, geometric thinking, and programming, and I feel more confident creating multiple interactive objects in p5.js for future projects.

Week 3: Arrays and OOP

Concept

I was inspired by candy hearts (as seen below) during Valentine’s Day, which is coming up soon. I wanted to recreate the soft colors and heart shapes of the candy hearts while adding movement and interactivity. So, my final sketch has hearts float and bounce around the screen, and when you click, it changes colors (but still within the color palette I’ve chosen).

My Final Sketch!

Code that I’m Proud of

// hearts' colors selection
getRandomColor() {
  let colorChoice = int(random(4));
  
  if (colorChoice == 0) {
  return color(255, 200, 220);
} else if (colorChoice == 1) {
  return color(220, 200, 255);
} else if (colorChoice == 2) {
  return color(200, 230, 255);
} else {
  return color(200, 255, 220);
  }
}

changeColor() {
  this.col = this.getRandomColor();
}

I particularly liked how I structured the changeColor() method and the color selection system. I created dedicated method that randomly picks from my chosen pastel palette and learned how conditional statements work with color from Patt Vira’s tutorial on YouTube and w3schools’ Statement Reference page. Each time you click, all hearts get new random colors from this palette.

How this was made

I used Object-Oriented Programming with a Heart class in which, each heart object has properties like position, size, color, and movement. I also used an array called hearts[] to store and manage all the heart objects. In the setup() function, I create each heart with random positions and sizes using a for loop, then push them into the array. In the draw() function, I loop through the array to call move() and display() on each heart every frame, which creates the continuous animation. The move() function makes the hearts bounce around. It updates position by adding speed values to the coordinates. When a heart hits a canvas edge, the function reverses its direction by multiplying the speed by -1 and makes it bounce back. This keeps hearts moving continuously without leaving the screen. For the heart shape itself, I used a parametric equation I found from this YouTube tutorial. The equation uses sine and cosine functions to plot the mathematical curve of a heart shape.

Reflection and Future Improvements

I learned a lot about how objects and arrays work and for these elements, I honestly found YouTube tutorials, like The Coding Train and Patt Vira, more helpful than reference pages (though I still used them as a reference for this project), especially with getting used to OOP. Next time, I’d love to learn how to add text to the objects because for my project, the candy hearts I referenced has phrases on them (as seen above) that would’ve added a nice touch and more accuracy.

Week 3: Creative Reading

The words interaction, interactive, and interactivity have been used a lot and I’ve hear those words multiple times so what really does it mean? The word ‘Interactivity’ from the Oxford dictionary means “the process of two people or things working together and influencing each other.” But I dont think I’ve thought of the word in this way. Before reading this text, I mostly used these words without really questioning them or thinking deeply about qualities does something have to be in order to be labeled as interactive. When thinking about the major interactive media, quite frequently I would ask people like professors or students what it is and it seems to be hard to explain. What is interactive media? What does it mean to interact? This made me realize that interactivity is often treated as a vague label rather than a specific defined concept. So looking at this reading and thinking of interactivity I liked how Crawford explained it. He defined interactivity as a conversation when two actors are actively listening, thinking, and speaking which shows that in order to have or make something interactive, it must be able to be present and respond through interactions from both sides. This definition stood out to me because it made ‘interactivity’ feel more intentional instead of it being seen as automatic.

One thing he mentioned was books and movies, while I first believed that movies and books are interactive, I understand now why they aren’t categorized as interactive. They are just one-way monologues, no matter how emotionally involved I feel while reading or watching them. It makes me questions everything, not just books and movies but also the smallest things like the sensory doors for example or every day materials. This made me think about how often reaction is mistaken for interaction in design and media. Overall, the reading made me more critical of how I design, plan, and execute my ideas and projects. Instead of focusing only on visuals, I will start to think more carefully about whether a system can actually listen, think, and respond in a meaningful way.

Week 3 – OOP Assignment (Magic of Light)

Concept:

For this project, I created a generative artwork inspired by the idea of light and movement from a scene found in the movie Encanto. I asked my friends to tell me their favorite Disney movies, some mentioned Tangled, Moana, but one of them said Encanto. I started searching for movie clips to get inspiration from the scenes and movements but none of the Disney movies caught my attention until I looked at Encanto. While looking through images and clips from the film, I was drawn to the candle and flame that symbolized magic and hope. Looking at the circles and light around the candle made me wonder if I could also create the same scene through code which I titled Magic of Light.

Instead of creating the same exact image, I wanted to add my personal twists to create the feeling of movement and energy by making the flames move around a lot and also adding interactivity when clicking on the canvas.
Inspo: Encanto

Embedded sketch:

How the Artwork Was Made:
I first started by creating the base of my code, which to me is the background and candle. I then started creating the arrays and class for the lights and candlelight to start focusing closely on the code and specific movements of the balls which are the flames. I used a class to define each object that is moving included lots of codes and numbers so that the balls would bounce and move left/right or up/down in an array. Each object has its own position, speed, and behavior, which allows them to move independently across the canvas.

I organized my code using functions and clear variable names (light and candlelight) to keep it structured and smooth when I press play. I also added comments in the code (this is probably the best advice I got because when my code kept messing up and not working, I was easily able to look back and understand my thought process).

Resources:

Hardest Part of the Code (and the Part I’m Most Proud Of):
The hardest part of the code was figuring out how I wanted the objects to move and bounce around the canvas. I struggled at first because I didn’t fully understand how to use the array, loop, and class the same way we did in class but especially when trying to figure out how to make the balls bounce on from the edge using the reverse code.

move() {
    this.x += this.xspeed; //moves left/right
    this.y += this.yspeed; //moves up/down

    //using IF and || (OR) to make it bounce, when the ball hits the edge it is reversed by x-1
    if (this.x < 0 || this.x > width) this.xspeed *= -1;
    if (this.y < 0 || this.y > height) this.yspeed *= -1;
  }

I’m proud of this because it took me a while to fully understand what was happening instead of just copying the code. I went back to Professor Aya’s google slides and was able to follow exactly how to create the bounce but also looking at the Ball Class Example 1 helped me create the bounce. Once I understood how multiplying the speed by -1 reversed the direction, I was able to control the movement more intentionally.

Full Code:

let lights = []; //Creating my Array/list that will include all my candleLight

function setup() {
  createCanvas(400, 400);
  
  //Creating my loop for the balls/flames to fill the array with 150x objects (the circles)
  for (let i = 0; i < 250; i++) {
    let light = new candleLight(//candleLight is the new class I'm using for this section
      random(width), //Random x position
      random(height), //Random y position
      random(7, 13) //random size for the object
    );
    lights.push(light); } // To make the balls continue to come and move around the 'push' will push out a new object into the array
}

function draw() {
  background(0);

  // draw candle
  drawCandle();

  //The Loop through the list to update every ball of light
  for (let i = 0; i < lights.length; i++) {
    lights[i].move(); //updating position of ball
    lights[i].show(); //showing the ball
  }
}

function drawCandle() { //Creating the candle+flame
  fill("#E7BE42");
  rect(125, 200, 150, 200);

  fill("#E7BE42");
  ellipse(200, 200, 150, 50);

  fill("#FAF6D0");
  ellipse(200, 180, 20, 40);
}
//What each light will follow and be programmed as
class candleLight {
  constructor(x, y, size) {//everytime a new obkect is created
    this.x = x; //using this to give each ball its specific position
    this.y = y;
    this.size = size;
    
    //playing around with the speed
    this.xspeed = random(-1, 1); //left/right
    this.yspeed = random(-1, 1); //up/down
    
    //creating the array of 3 different color values    
    let colors = ["#FFD700", "#FF8C00", "#FAF6D0"];
    this.color = random(colors); 
  }

 move() {
    this.x += this.xspeed; //moves left/right
    this.y += this.yspeed; //moves up/down

    //using IF and || (OR) to make it bounce, when the ball hits the edge it is reversed by x-1
    if (this.x < 0 || this.x > width) this.xspeed *= -1;
    if (this.y < 0 || this.y > height) this.yspeed *= -1;
  }
  
  show() {
    noStroke();
    fill(this.color); //going back to the random colors above
    ellipse(this.x, this.y, this.size);
  }
}

function mousePressed() { //interactive aspect, when someone clicks on the sketch a new ball appears
  let newLight = new candleLight(
    mouseX,
    mouseY,
    random(5, 10)
  );
  lights.push(newLight); //add to the array
}

  

Problems I Ran Into:
One major issue I faced was constant errors in p5.js where the code would turn red, and I couldn’t figure out what was wrong. At one point, when I pressed play, the sketch would run but only show the black background with no objects. So I tried looking back from top to bottom and commenting again on the functions while also using // to remove the codes I assumed were causing the problem. I was the able to debug it and play it smoothly.

Final reflection:
I am proud of my final artwork because not only is this my first time writing a lot of code (lines 1–78), but I was also able to have fun with my friends throughout the process. Since we all have different majors, I usually show them what I’m learning and creating in Intro to IM. This time I asked them about their favorite movies and used that to create something that could connect us in a meaningful way.

I got my inspiration from the Disney movie Encanto and built my code around that idea. For future improvements, I want to create more realistic versions of my work because even though I’m proud of how far I’ve come and how I used the code, I know I can push myself further and make it look closer to the original inspiration.