Week 4 – OOP and Array

References and Inspiration

This project was inspired by sunsets, specifically their color transitions from yellow to orange and purple. These colors were used to design the gradient effect in the particle trails. The movement of the particles was influenced by the idea of natural flows and atmospheric motion. On the technical side, the code was built in p5.js using established techniques such as Perlin noise flow fields and particle systems, which were adapted to fit the chosen sunset theme.

Pink Sunset Color Scheme - Image Color Palettes - SchemeColor.com

Embedded Code

//this is our particle class responsible for each line of perlin noise
class Particle {
  constructor() {
    this.pos = createVector(random(width), random(height)); //randomly positioned
    this.vel = createVector(0, 0);
    this.acc = createVector(0, 0);
    this.maxSpeed = 2; //limit to how fast the particle moves
    this.prevPos = this.pos.copy(); //saves the previous/latest position of the trail 
  }

  update() {
    this.vel.add(this.acc); //alowing the vleocity to change based on the acceleration 
    this.vel.limit(this.maxSpeed); //limting the speed
    this.pos.add(this.vel); //change position based on the velocity 
    this.acc.mult(0); //reset accelration so it foes not increase infintely 
  }

  applyForce(force) {
    this.acc.add(force);
  }

  follow(vectors) {
    let x = floor(this.pos.x / scl); //getting the position of the particle x and y 
    let y = floor(this.pos.y / scl);
    let index = x + y * cols; //makingt he 2d grid into 1 d for indexing
    let force = vectors[index]; //access the vector at index
    this.applyForce(force); //apply the perlin noise
  }


  show() {
    // Sunset gradient colors
    let t = map(this.pos.y, 0, height, 0, 1);

    // Top → yellow, middle → orange/red, bottom → purple
    let topColor = color(255, 200, 50, 30);    // golden yellow
    let midColor = color(255, 100, 50, 30);    // deep orange/red
    let bottomColor = color(180, 60, 160, 30); // magenta/purple

    
    
    let c; // c is the chosen "sunset color"
    if (t < 0.5) { c = lerpColor(topColor, midColor, t * 2); } else { c = lerpColor(midColor, bottomColor, (t - 0.5) * 2); } stroke(c); strokeWeight(1.5); line(this.pos.x, this.pos.y, this.prevPos.x, this.prevPos.y); this.updatePrev(); } updatePrev() { //updating to make sure that the trail starts from the current positoin for the next/continued oaeticle this.prevPos.set(this.pos); } edges() { //limit particles ot stay within the frame if (this.pos.x > width) {
      this.pos.x = 0;
      this.updatePrev();
    }
    if (this.pos.x < 0) { this.pos.x = width; this.updatePrev(); } if (this.pos.y > height) {
      this.pos.y = 0;
      this.updatePrev();
    }
    if (this.pos.y < 0) {
      this.pos.y = height;
      this.updatePrev();
    }
  }
}

Concept:

In my p5.js sketch for this week, I mainly use a particle system where many small points move across the screen, each leaving a trail. Their movement is controlled by a flow field, which is simialr to an invisible grid of arrows that points the particles in the direction they should move in. The directions of these arrows are created with Perlin noise, which makes the movement look smooth and natural instead of random. Each particle updates its position based on the flow field and avoids the mouse when it gets too close, adding interactivity. To match the sunset theme, the particles are colored with a gradient that changes from yellow to orange to purple depending on their vertical position on the screen.

✨Sunset on the Beach ✨

Problems I Ran Into:

I had to review the previous Decoding Nature slides in order to refresh my memory on the concepts like flow field and perlin noise, and particles leaving a trail. So although it was not exactly a “problem” I had to readjust some parameters and play around with the values of certain parameters to remember what they were responsible for.

Embedded Skecth:

Reflection & Future Sketches:

I plan to incorporate more of the concepts taught in decoding nature to the weekly sketches.  I also want to focus on the creative elements and aspects of the sketches.Looking ahead, I want to experiment with making the particles react to more external inputs, such as sound or keyboard interaction, to create more dynamic sketches.

 

Reading Reflection:

When readings Crawfords piece I noticed that he mainly focused on three elements that make strong creativity: Listening, Thinking, and Speaking. By listening he means the system should be able to “capture” or “record”. Not only that but to accurately respond to certain triggers, whether it would be accurately through time, as in instant reaction, or accurately respond in an area specifically clicked on through the mouse.

After reading the piece, I have a few ideas for future sketches that will enhance the interactivity. For example, I want to start integrating all the Listening, Thinking, and Speaking elements cohesively so that the user does not have to be told that the piece is interactive- the piece speaks for itself. For instance, if my sketch has audio interaction or mouse interaction, I want the interactive element to shine through and to be the main focus rather than just an addition..

Creating Interactive Visuals with p5.js | Cratecode

 

Reading Reflection – Week 3

Chris Crawford compares interactivity to two people holding a conversation, where each listens and responds, and that back and forth creates something dynamic. Before reading this, I hadn’t really thought deeply about what makes a system truly interactive, and Crawford’s explanation really clarified it for me. I agree with him because a strongly interactive system is one where the user’s input can meaningfully change the outcome, rather than just triggering a predictable or surface-level reaction. That’s when interaction feels real.

For my own p5 sketches, I’ve thought about ways I could improve the interactivity in them. Instead of just clicking to trigger something to happen, the sketch could react differently depending on the type of input, like how long you hold a key or how fast your mouse is moving. This would make the artwork/program feel less like a machine following certain orders and more like an actual conversation between the user and the program.

Week 3 – Reading Reflection

Reading Chris Crawford’s chapter “What Exactly Is Interactivity?” made me rethink what I usually call “interactive.” Especially, now as I am taking 3 IM classes, and we often see the artworks and come to the term interactive, I have started to understand how truly important it is. After the reading, I realized that I often label something as interactive just because I can click or move something and it changes, but Crawford’s explanation made me see that real interactivity is much deeper than that. I really liked his comparison to conversation, it made sense that true interactivity should feel like a back-and-forth exchange where both sides “listen, think, and speak.” This idea made me reflect on my own p5 sketches and notice that, while they respond to user input, they do not necessarily feel like a conversation. They just react without much “thinking” or meaningful change based on the user’s action.

Speaking of 5p, the reading challenged me to think about how I can make my work more engaging and meaningful. I felt motivated to experiment more with giving my sketches some kind of “memory” or adaptive behavior so that the experience feels less mechanical and more like a dialogue. For me, a strongly interactive system is one where the user’s input actually matters and shapes the outcome in noticeable, sometimes unexpected ways. It should feel like the system is “paying attention” and changing its behavior based on what I do, rather than just executing a simple trigger. I think strong interaction also invites me to explore, experiment, and maybe even get surprised by the result.

After the reading, I had some ideas of how I can improve my interactivity of  p5 sketches. I could add elements that respond over time or evolve depending on how much and how often I interact. For example, instead of bubbles just appearing when I click (assignment 3 – OPP), I could make them “learn” from my clicks, maybe clustering in areas where I click often or changing colors based on patterns of interaction. I could also make my sketches remember past actions so that the experience feels continuous rather than resetting each time. I think, after this steps, it would move my work closer to what Crawford calls a real conversation between user and system.

Week 3: Generative Artwork

Concept

When I thought about what to do for this assignment, I started brainstorming and eventually decided to create a simple simulation of rainfall. I always found rain both calming and visually appealing, so I wanted to capture that feeling in my artwork.

Code I’m Proud Of

I’m proud of this code because I figured out how to make the raindrops disappear at the bottom of the canvas (when they reach the sea). At first, I used pop(), but it didn’t work the way I wanted it to: it would randomly delete all the droplets in the middle of the page. So I researched a bit and instead, used splice(), it deletes the droplets when they reach the bottom of the page and works perfectly!

//deletes raindrops after they reach the sea
if (raindrops[i].disappear()) {
  raindrops.splice(i,1);
  //splice removes/deletes the disappeared raindrops 
}

Here’s the artwork I created:

Reflection and Future Improvements

Overall, I’m happy with the way my rainfall artwork turned out. I especially liked learning how to use arrays with objects because it made me think more carefully about organization and how each part of the code connects.

If I were to improve this piece in the future, I’d probably add sound effects of rain falling, or even experiment with lightning and thunder for a more dramatic atmosphere. Another idea I had is to adapt the same logic to create snow instead, using different PNGs for different snowflake shapes. That way, the piece could feel more unique while still using the same object-oriented structure I implemented here.

Assignment 3 – Functions, Arrays, and Object-Oriented Programming

Concept:

For this project, I wanted to make something a bit more playful and fun. I took inspiration from the classic “Why did the chicken cross the road?” joke, but instead of just one answer, I made each chicken have its own punchline inside a speech bubble. This time I wanted to use a more creative inspiration and make it a little comedic by playing with humor and randomness.

I also challenged myself more with the coding. I didn’t just stick to what we already learned in class, but tried to experiment by looking things up, exploring, and figuring out how to make it work. For example, I had to learn how to make the speech bubble size change depending on the sentence length, and how to make sure each chicken gets a unique punchline. It was tricky, but I liked that I was able to understand and fix something new on my own.

So overall, this piece is both about the humor of random answers to the same old joke, and also about me pushing myself creatively and technically.

Highlight of a code i’m proud of:

One part of my code I’m really proud of is how I made sure each chicken gets a unique punchline. I used shuffle(punchlines, true) to mix up all the punchlines randomly so the order isn’t always the same. The true part is important because it tells the program to change the original punchlines array directly, instead of just making a shuffled copy. This way, when I assign punchlines to chickens, the original array is already randomized. Then, I looped through the array with for (let i = 0; i < punchlines.length; i++) to create a new chicken for each punchline using chickens.push(new Chicken(0, 50 + i * 40, punchlines[i]). The 0 makes each chicken start on the left side of the canvas, and 50 + i * 40 spaces them vertically so they don’t overlap. I like this part because it shows how I can combine arrays, loops, and objects to create multiple unique characters on the screen, and it really brings the sketch to life.

// shuffle punchlines so each chicken gets a unique one
  shuffle(punchlines, true); // randomize the order of punchlines in place

  // create one chicken for each punchline
  for (let i = 0; i < punchlines.length; i++) {
    // x = 0 so chicken starts on left
    // y = 50 + i*40 to space them vertically
    // punchlines[i] gives each chicken its own joke
    chickens.push(new Chicken(0, 50 + i * 40, punchlines[i]));
  }
}

Problems I Ran Into: 

   – Speech bubbles being too small
At first, the text didn’t fit inside the bubbles. I fixed this by using textWidth() to measure the punchline and then adding padding, so the bubble grows depending on how long the sentence is.

   – Same punchlines repeating
In the beginning, some chickens had the same joke. To fix this, I used shuffle(punchlines, true) so the punchlines get mixed up randomly, and each chicken gets its own unique one.

– Balancing simplicity and creativity
I didn’t want the code to be too complicated, but I still wanted it to be fun and creative. That’s why I kept the chicken shape simple (just ellipses for the body and a triangle for the beak) and focused more on the concept with the speech bubbles and punchlines.

Reflection and ideas for future work or improvements: 

I really enjoyed making this project because it let me experiment with coding in a creative way, using arrays, loops, and objects together. I learned a lot about how to structure a sketch, how to make multiple objects move independently. 

For future improvements, I’d love to make the sketch even more dynamic and interactive. For example, I could let the user click on a chicken to make it say a new punchline, or have the chickens move at different speeds across a more detailed road scene. I could also experiment with animations in the bubbles, like making them pop up.  Another idea is to add more randomness to the chicken shapes or colors to give each one even more personality. Overall, I’d like to keep exploring ways to make the sketch playful and visually fun while practicing more advanced coding techniques.

Assignment 3 – Object-Oriented Programming

Concept

When I started thinking about how I wanted to use Object-Oriented Programming (OOP) in my project, I imagined an underwater world. I wanted to make something calm and relaxing, so I created a digital aquarium. In this scene, bubbles float gently to the surface, colorful fish swim across the canvas, and seaweed sways back and forth at the bottom of the ocean.

Each time the sketch runs, the scene looks slightly different. The bubbles start at random positions and have different sizes and speeds. The fish are given random colors and swim in different directions, and even the seaweed moves with slightly different timing. This randomness makes the project feel alive,  it never looks exactly the same twice.

I also wanted the viewer to feel like they could interact with the piece. When you click anywhere on the canvas, new bubbles appear, as if you are adding more air into the water. I think this small interaction gives the viewer the feeling that they are part of the underwater world, and they can keep changing it over time

Code I am proud of

Since this was one of my first tries using OOP, I am proud of how I used classes and arrays to keep my code neat and reusable. Instead of writing separate code for every single bubble, fish, or piece of seaweed, I made classes for each one with their own properties and methods. Then I stored all the objects in arrays and used a simple loop to update and display them. It made my code much easier to read and change, if I want to add more bubbles or fish, I just push a new object into the array and everything works automatically.

function displayBubbles() {
  for (let b of bubbleArray) {
    b.update();
    b.show();
  }
}

Also, there was some difficulties, for example, all the bubbles were moving in perfectly straight lines, which looked too mechanical. To make them look more natural, I added a sin() wave offset and a slight random angular speed so they gently drift side to side as they rise

update() {
    // Move upward and slight sideways wiggle
    this.y -= this.speed;
    this.x += sin(this.angle) * 0.5;
    this.angle += this.angleSpeed;

    // reset bubble when it leaves canvas
    if (this.y < -this.size) {
      this.y = height + this.size;
      this.x = random(width);
    }
  }

Sketch:

Click the mouse to add more bubbles

Reflection

I am proud of how this project demonstrates the use of Object-Oriented Programming (OOP), arrays, and dynamic interactivity to create a visually engaging underwater scene. I was able to organize the code cleanly, avoid repetition, and make it scalable, while arrays allowed for easy iteration and animation

Yet, I think for the future development, I could increase interactivity by having fish respond to the mouse or implement bubble popping effects, introduce more dynamic visuals such as a gradient background, diverse sea creatures, and multi-layered seaweed for depth, and incorporate physics-based movement or sound interaction to create a more immersive experience. Overall,  for me this project combines programming, aesthetics, and interactivity that explores potential of generative digital art.

Week 3 – The Art of Interactive Design Ch.1

My definition of interactive was always just… I do something, and the thing does something back. A game, a movie, whatever. As long as we were both making actions, I figured that was it.

But in the chapter putting the interaction or being interactive into the frame of a conversation (listen, think, speak) made me stop and question that. It makes me wonder if the actions have to actually depend on each other. Like, the system’s reaction should be different based on what I did, not just a pre-programmed response to any action.

This makes me look at a lot of stuff we’ve made in p5.js completely differently. Most of those examples aren’t really interactive by this standard. I mean, you click the mouse and a shape appears, but it’s the same shape every single time. The code isn’t really thinking about my input, it’s just reacting. It’s a glorified light switch. True interaction needs that middle ‘think’ step, where the response is actually considered, not just triggered. That’s a way more interesting goal to aim for.

Week 3 – OOP Assignment

Hi everyone,

For this week’s work on OOP, I wanted to build on what we did last time implementing a bouncing ball with OOP. I wanted to make it kinds more interactive this time. I wanted to take a familiar p5.js example and make it more dynamic by implementing proper OOP principles, allowing the balls to not only bounce off the walls but also collide realistically with each other.

I created a `Ball` class that bundles together all the data (properties like `x`, `y`, `xspeed`, `radius`) and the functions (methods like `move()`, `display()`, `bounceWalls()`) that define what a ball is and what it can do. This makes the main `sketch.js` file much cleaner and more manageable. Instead of tracking dozens of separate variables for each ball, I can simply create an array of `Ball` objects and let each object manage its own state. And this what gave me the freedom of creating a lot of new balls whenever the mouse is clicked.

One of the most interesting parts of this project was implementing the collision detection between the balls. A simple approach where every ball checks against every other ball can lead to a glitch where they get stuck. When Ball A collides with Ball B, they reverse direction. But in the same frame, when Ball B checks against Ball A, it reverses direction *again*, undoing the bounce.

The highlight of my code is the solution to this problem in the main `draw()` loop. By using a nested loop where the inner loop starts at `j = i + 1`, I can ensure that every pair of balls is checked for collision exactly once per frame. This prevents the double-bounce glitch and is much more efficient.

Here is the snippet for the collision logic:

for (let i = 0; i < balls.length; i++) {
for (let j = i + 1; j < balls.length; j++) {
let ball1 = balls[i];
let ball2 = balls[j];
// Check the distance between the two balls
let distance = dist(ball1.x, ball1.y, ball2.x, ball2.y);
// If they overlap, trigger the collision resolution function
if (distance < ball1.radius + ball2.radius) {
resolveCollision(ball1, ball2);
}
}
}

Week 3 – Exquisite Candidate

Inspiration

I found myself thinking about the current state of political discourse—how it often feels chaotic, random, and almost nonsensical. Arguments and personas could go totally random, as if different parts have been stitched together to form a strange new whole.

This immediately brought to mind ancient myths, like the 人头马身 (the centaur), a creature with the head and torso of a human and the body of a horse. This became my core visual metaphor: what if I could create political “centaurs”? I could randomly pair the heads of recognizable political figures with symbolic, abstract bodies to represent the absurdity and randomness of political rhetoric.

The project needed a name that captured this idea. I was inspired by the Surrealist parlor game, “Exquisite Corpse,” where artists collaboratively draw a figure without seeing the other sections. My program does something similar, but with political figures, or “candidates.” The name clicked almost instantly: Exquisite Candidate.

Description

Exquisite Candidate is an interactive artwork that explores the chaotic nature of political identity. By clicking the mouse, the viewer generates a new “candidate”—a hybrid figure composed of a randomly selected head and a randomly selected body.

The heads are abstract but recognizable vector drawings of political figures. The bodies are symbolic and thematic, representing concepts like power (“suit”), vulnerability (“stripped_down”), foolishness (“sheep”), or emotional immaturity (“baby with tears”). The resulting combinations are surprisingly (at least for me the creator) humorous or poignant, creating a visual commentary on the fragmented and performative nature of public personas. To bring these abstract figures to life, Gemini helped me generate part of the many vector-based drawing functions for the assets.

Code

The program is built on an Object-Oriented structure with three main classes: HeadBody, and Creature. This keeps the code clean, organized, and easy to expand.

A challenge I encountered was with the “baby with tears” body. My initial design was simple: the Body object would draw itself, and the Head object would draw itself. But the tears needed to be drawn on the face, which is part of the Head object. How could the Body object know where the head was going to be drawn? Unfortunately, until submission, I haven’t figured out how to implement this successfully.

Week 3 – art work

Title: Does the Power of Lover overcome the Love of Power

This is an interactive generative artwork that explores the dynamic struggle between two opposing forces: Power of Love and Love of Power. Using color, motion, and shape, the piece visualizes how these forces interact, dominate, and fade.

Users can interact with the artwork using the keyboard: pressing X strengthens the Power of Love, Z increases Love of Power, and R resets the canvas. As one force grows, it overwhelms the other, creating a constantly shifting visual narrative of dominance, balance, and fragility.

Highlight of Code I’m Proud Of:

One part I’m particularly proud of is the heart shape formula used in the Heart class. Creating a convincing pulsing heart shape took a bit of trial and error—adjusting the sine and cosine coefficients to get the proportions and curves right. When I looked it up to check my work, I was pleasantly surprised to realize that I had remembered the formula almost perfectly! The code also incorporates time-based pulsing and subtle distortions influenced by the interaction of the two forces:

class Heart {
  constructor(battle) {
    this.battle = battle;
  }

  display() {
    let { t, loveStrength, powerStrength } = this.battle;

    let heartOpacity = map(loveStrength, 0, 1, 10, 90);
    let heartPulse = map(loveStrength, 0, 1, 0.4, 2.5);

    stroke(340, 80, 100, heartOpacity);
    strokeWeight(2 * heartPulse);

    for (let i = 0; i < 3; i++) {
      let s = 100 + sin(t * 2 + i) * 50 * heartPulse; // pulsing size
      beginShape();
      for (let a = 0; a < TWO_PI; a += 0.1) {
        // classic heart shape formula
        let x = s * 16 * pow(sin(a), 3) / 10 + sin(t + i) * 30 * powerStrength;
        let y = -s * (13 * cos(a) - 5 * cos(2 * a) - 2 * cos(3 * a) - cos(4 * a)) / 10
                + cos(t + i) * 30 * powerStrength;
        vertex(x, y);
      }
      endShape(CLOSE);
    }
  }
}

This section highlights the combination of mathematical formula, animation, and interaction to make the heart both accurate and dynamic.