Assignment 4: Loading Data, Displaying text

Sketch

Concept

Since I am a huge Beatles fan, for this assignment I decided to use a dataset of Beatles songs popularity on Spotify and visualize it in p5. Each song is represented as a hoop, and the more popular the song is on Spotify, the bigger its hoop is. The hoops are all stacked on top of each other, and the colors show how many songs share that popularity range. A brighter, more solid white hoop means more songs fall into that range, while a more transparent, greyish hoop means fewer songs are in there. For the visual style, I designed it to resemble a vinyl record, using the Abbey Road album cover as the center label.

The Beatles, Abbey Road (1969)

Code Highlight

let popularity = float(songs.getColumn("Popularity"));
let minPop = min(popularity);
let maxPop = max(popularity);
let minRadius = 82;
let maxRadius = 240;

for (let i = 0; i < rowsNum; i++) {
    let radius = map(popularity[i], minPop, maxPop, minRadius, maxRadius);
    noFill();
    stroke(255, 30);
    strokeWeight(2);
    circle(0, 0, radius * 2);
  }

This part of the code is one of the main things that allows me to visualize the numbers from my .csv file on my actual sketch canvas. It basically converts the raw popularity numbers into a range that fits the canvas, scaling each song’s popularity into a radius between 82 and 240.

push();
translate(300, 300);
rotate(angle);

angle += 0.01;
pop();

I used translate to move the origin from the default top left corner (0,0) to (300, 300) which is the center of my canvas. I did this so the vinyl record spins properly around its own center, instead of spinning from the upper left corner and taking the whole thing off the canvas.

How this was made

This sketch loads a Beatles songs dataset and turns it into a spinning vinyl record visualization. In setup, the .csv file with songs and Spotify popularity values is loaded using loadTable, and the Abbey Road logo is loaded using loadImage.

Then I used min and max to find the largest and smallest numbers in the popularity column, and used the map function to stretch those values so they fit properly within my canvas. Using these mapped values as the radius, I created white hoops with slight transparency, where each song gets its own hoop sized according to its popularity. Every hoop uses no fill and a low opacity white stroke, so they visibly stack on top of each other and kind of display the quantity of songs within a specific popularity range.

In the middle of my vinyl record, I added the Abbey Road logo image that I loaded in setup. Then, to make the vinyl record rotate, I used the rotate function paired with translate, changing the origin point to the center of my canvas so the disc spins around its own center instead of the corner.

Reflection

The main issue my current sketch has is that the hoops are all perfectly symmetric circles, and because of that, it is actually impossible to see that the record is rotating at all. To fix this I think I could add some kind of texture to the hoops, or maybe add a light glare effect or small visual markers that would make the spinning motion noticeable.

Another problem I ran into was a performance difference between operating systems. The sketch runs completely smooth on macOS, but when I tried running it on a Windows laptop, it became very laggy, even though the Windows laptop has much stronger specs than the MacBook I initially built and tested this sketch on. This came as quite a surprise to me, and I was not able to find a fix for it. Most likely, the issue lies in how the two operating systems handle rendering differently.

Week 3: Reading Reflection

Before this reading, I had never had a clear definition of what interactivity means. Now I realize that one cannot call something interactive just because it reacts to input. If we consider the superficial meaning of interactivity that many people use, then even turning on a light is considered interactive. You press a button, and in response the light bulb turns on. Using this definition of interactivity is meaningless, since it makes almost everything interactive. For something to be truly interactive, it has to involve two sides that alternately listen, think, and speak.

It has to be like a dialogue between two sides, where each action shapes and changes future inputs. This made me rethink my last assignment, where I created a sketch with fireflies that fly away when the mouse cursor gets close. I used to think of this as interactivity, but it is really just a simple reaction to input. It is not an interactive dialogue, since only one side is speaking while the other is just listening without giving any response back.

I think I could make the fireflies respond differently depending on how the user moves the mouse. For example, if the user moves the mouse slowly, the fireflies could drift away calmly, but if the cursor moves faster, the fireflies could fly away more dramatically. This would at least make the interaction feel like the fireflies are thinking before reacting, rather than just responding the same way every time.

Assignment 3: Functions, Arrays, and OOP

Sketch

Concept

The idea for this sketch came to me after recently watching the animated film “Grave of the Fireflies” and I decided to make a sketch with fireflies that move in random directions. To imitate actual firefly behavior, I made them fly away when you bring the cursor closer to them, just like how they avoid human touch. I always thought of fireflies as truly magical creatures, so this idea felt the closest to me.

Grave of the fireflies (1998)

Code Highlight

 this.transp = random(50, 255);
 this.fadeSpeed = random(1, 3);

this.transp += this.fadeSpeed;
    if (this.transp > 255 || this.transp < 50) {
      this.fadeSpeed *= -1;

The most interesting part of this code is the fading fireflies effect. This part creates the pulsing fade effect for each firefly using two values, transp and fadeSpeed. When a firefly is created, transp starts as a random value between 50 and 255, which sets how visible the firefly looks at first. fadeSpeed starts as a random value between 1 and 3, which sets how fast the firefly light fades. Every frame, fadeSpeed is added to transp, making it slowly rise or fall. Once transp goes above 255 or below 50, the fadeSpeed flips direction so it fades back the other way.

Also, a problem I ran into was when the center of a firefly’s circle reached the edge of the canvas, it would just disappear and teleport straight to the opposite side, which looked abrupt and ruined the whole sketch. To fix this, I adjusted the restart function to give the firefly a small buffer of 14 pixels past the edge before it teleported to the other side.

restart() {
    if (this.x > width+14) {
      this.x = 0-14;
    }
    if (this.x < 0-14) {
      this.x = width+14;
    }
    if (this.y > height+14) {
      this.y = 0-14;
    }
    if (this.y < 0-14) {
      this.y = height+14;
    }
  }

 

How this was made

This sketch was built using two separate classes. The first class, called fli, handles the fireflies, and the second class, called star, handles the background stars. The stars are very simple, as they are just small ellipses with random positions in the background without any movement. Their sizes and transparency or brightness are also random between certain values to create variety. The fli class, on the other hand, is a little more complicated. Each firefly gets random values for position, speed, size, transparency, and fade speed when it is created. In the move function, the firefly drifts slowly across the screen, and its transparency rises and falls between 50 and 255 to create a glow effect. When the mouse comes within 70 pixels, the firefly flies away from the cursor. The restart function makes fireflies wrap around to the opposite edge instead of disappearing when they leave the canvas.

Reflection

While making this sketch I used a lot of randomness across all sorts of parameters. This approach definitely made the whole picture look more natural. Since the main focus of my sketch was fireflies, I had to make sure their behavior felt believable and alive. Adding randomness into parameters like size, speed, and fade timing made the fireflies move and glow at their own pace instead of all acting the same, which created a harmonic, natural looking scene overall.
If I worked on this again I would try to make the glowing effect more realistic, maybe by making a color transition between circles smoother. I would also change how the fireflies avoid the mouse to make that interaction feel more realistic, since the movement feels kind of stiff right now.

Week 2: Reading Reflection

As a perfectionist, the word “chaos” would always evoke negative emotions in me. It is a word that feels like the direct antonym of my favorite word, “perfection,” and so it never quite sat right with me. However, listening to Casey Reas’ speech made this word more tolerable, as the examples of work he showed made me see a certain beauty in randomness.

For me, the most meaningful takeaway was that adding elements of randomness can sometimes help keep a work alive and dynamic. Previously, when I tried to incorporate randomness into my work, it would usually result in a messy, overwhelming chaos. But now I realize that to avoid that kind of mess, you need to set certain limits and keep a balance, something like 75% control and 25% chaos. My mistake was that I overemphasized and exaggerated the chaos, turning my work into an uncontrollable mess.

In a recent assignment for this class, I ran into something similar. I created a perfect grid of squares, but that perfection made the sketch look dead and homogenous. Then I experimented with spacing and movement, and eventually found my ideal ratio of randomness to order, something I’d call “controlled mess.” This change made the sketch look more alive and visually interesting.

In my future projects, I plan to expand my use of chaotic elements, but with the same rules in mind. I am eager to experiment and discover ways in which I can add random elements to parameters like size, rotation, or even frameRate to create unorthodox projects that still feel ordered and meaningful.

Assignment 2: Animation, Conditionals, Loops

Sketch

Concept

Fun fact: my work was unintentionally inspired by Georg Nees’ “Schotter“.
My first Idea was to recreate colorful bathroom tiles, like the ones in old style houses, and I built a grid of squares in perfect order. But as I worked through the project, that perfect order started to feel boring to me. So I decided to add some chaos by making the squares move and rotate. Later, I realized that I had subconsciously taken inspiration from one of the artworks I had reviewed earlier before starting my sketch. Once I noticed that, I began taking inspiration from that work on purpose. Obviously, it is not a 1 to 1 copy of Georg Nees’ work, but my own version with animation that resembles the flow of a waterfall.

George Nees “Schotter”

Code Highlight

for (let x = 0; x <= width; x += 25) {
  for (let y = 0; y <= height; y += 25) {
    
    push();
    //The lower it gets, the more it moves
    translate(x + random(-y / 30, y / 30), y + random(-y / 30, y / 30));

    // The lower it gets, the more it rotates
    rotate(radians(random(-y / 10, y / 10)));
    
    stroke(random(150, 255), 100, 220);
    strokeWeight(random(1, 2.5));
    rect(0, 0, 22, 22);
    pop();
  }
}

The hardest part was creating a falling effect where the movement increases as the squares go down. To do that I used:

translate(x + random(-y / 30, y / 30), y + random(-y / 30, y / 30)) rotate(radians(random(-y / 10, y / 10)));

So as the Y axis value increases, the range of movement gets larger too. As you can see the first row squares are not moving at all. But the squares further down drift and rotate randomly.

How was this made

First, I set up a basic grid with two nested for loops, one for x and one for y, and spaced the squares 25 pixels apart across the whole canvas. Next, to create the progressive breakdown effect, I used translate() and rotate(), and divided my y value inside the random() functions. Because y value is small at the top of the canvas, those squares barely move at all. But as y increases going down the canvas, the range passed into random() gets wider, so the lower squares shift and rotate more. To accomplish this I had to look up translate() and rotate() functions on p5js reference page.

Reflection

Looking back, this project turned out quite different from what I initially planned. At the start, my idea was simply to make an artwork similar to colorful bathroom tiles. But as I kept working on my code, my plan swerved in a direction I wasn’t expecting. If I had more time, I would definitely experiment more with the color palette and add some sort of fading effect as the squares “fall down.” It would also be interesting to add elements of interactivity, like letting the mouse position affect how the squares fall apart.

Assignment 1: Pikachu portrait

For my first assignment in Intro to Interactive Media, I decided to recreate Pikachu using p5.js. To build the sketch, I combined basic geometric shapes like circles, triangles, and quads with a few custom shapes for details like Pikachu’s unique tail.

How this was made

I started by making Pikachu’s body using a simple rectangle shape. Next, I added a circle for the head. I used smaller circles and arc function to draw the eyes, nose, mouth, and bright red cheeks. For the ears, I combined long arcs with sharp triangles at the tips to imitate Pikachu’s pointed look. I also used AI to get an explanation on how to use the rotate function properly so I could angle the ears correctly. The main problem was Pikachu’s tail, which has a unique zigzag shape that is hard to recreate with basic shapes. I explain more on how I managed to draw the tail in the next section.


Code highlight

//Tail  
  beginShape();
vertex(235, 216);
vertex(252, 210);
vertex(248, 195);
vertex(262, 190);
vertex(256, 172);
vertex(290, 160);
vertex(275, 126);
vertex(230, 150);
vertex(241, 183);
vertex(234, 186);
vertex(237, 197);
vertex(230, 200);
  endShape(CLOSE);
//Brown part of the tail
  beginShape();
fill('brown');
vertex(248, 199);
vertex(231, 204);
vertex(234,216);
vertex(252, 210);
  endShape(CLOSE);

After finishing this part of the code, I felt very satisfied with my work. At first, I drew the entire tail outline using line() functions. However, after finishing it, I realized that lines cannot be filled with color. I then searched through the p5.js reference page and discovered that I could use the beginShape() function to create any shape I want by plotting coordinate points. I utilized this function, plotting each vertex to finally make a shape that matched that specific zigzag pattern and filled it smoothly with yellow color.

This assignment turned out to be a bit more challenging than I initially expected. Still, I really enjoyed the process of figuring out different ways to draw the specific shapes I had in mind.
For future assignments, I would love to move toward more realistic sketches, and eventually start adding animation into my work.