Week 2 – art work

Turning Math into Motion: Playing with Sine and Cosine in p5.js

I’ve always liked the concept of sine and cosine waves. They’re simple functions on paper, just waves that go up and down forever. But I was wondering what would it make if it’s involved in creating virtual art. So I decided to use them to make something that looks alive on the screen.

The Concept

The artwork is based on the idea of ripples. Every click on the canvas sends out a circle that grows, but instead of being a perfect circle, it wobbles slightly — almost like the ripple is remembering where it’s been. Over time, these ripples overlap and fade, and the whole thing feels less like a diagram and more like a memory unfolding.

I think that’s what I love about it: it’s math doing what math does, but the output feels alive.

Highlights in the Code

I don’t want to break it down line by line, but a few details stood out to me while I was building this:

1. The Wavy Distortion
let offset = 15 * sin(this.t / 10);
ellipse(this.x, this.y, radius + offset);

Here, the sin() function is doing all the work. Instead of the circle growing in a boring, linear way, sin(this.t / 10) gives me a smooth back-and-forth motion between -1 and 1. Multiplying by 15 stretches that into a range of -15 to +15.

So when I add offset to the radius, the circle doesn’t stay steady. It breathes, gently expanding and shrinking as it grows. That tiny detail is what makes the ripple feel alive rather than mechanical.

2. The Colors That Shift on Their Own
stroke(
map(sin(this.t / 70), -1, 1, 100, 255),
map(cos(this.t / 25), -1, 1, 100, 255),
map(sin(this.t / 30), -1, 1, 150, 255),
180
);

At first, I hard-coded colors, but it looked flat. Then I realized I could let sine and cosine drive the colors, too.

Here’s how it works:

sin() and cos() output values between -1 and 1.

map() stretches those into ranges that make sense for color (e.g., 100–255).

Because the math is always oscillating, the stroke color is always changing — slowly shifting through different shades.

It’s not random; it’s predictably unpredictable. That’s why the transitions feel smooth instead of jarring.

3. Here is where I used loops:
function draw() {
background(10, 10, 20, 30);
for (let r of ripples) {
r.update();
r.show();
}
}

Each click I add one ripple to an array of ripples where I do the get bigger – wave distortion effect. And here I loop over them to update and show the effect.

Every ripple has its own this.t, which increases every frame. That’s what drives everything: the size, the offset wobble, the color shifts. Without t, nothing would move. With it, the math unfolds frame by frame, and the artwork comes alive.

Week 2 – Looped

This week we’re asked to create an artwork that incorporates the “loop” concept in code. I saw dynamic squares before, and would personally like to create a grid that gently “breathes” and drifts. Each square’s size, brightness are driven by layered sine waves using a shared time phase so the whole field feels organic and connected, like a low‑key pixel ocean.

Below is the code for core motion + styling logic (the vibe engine).

const w = sin(phase + (x * 0.35) + (y * 0.45));  // wave seed
const s = map(w, -1, 1, cell * 0.25, cell * 0.85);  // size pulse
const dx = sin(phase * 0.7 + x * 0.3) * 6;
const dy = cos(phase * 0.7 + y * 0.3) * 6;
const hueVal = (x * 8 + y * 6 + frameCount * 0.4) % 360;
const bri = map(w, -1, 1, 35, 90);
fill(hueVal, 60, bri, 0.9);
rect(px, py, s, s, 6);
  • What works: Simple math, no arrays or heavy state—scales nicely with window size. The motion feels smooth and unified.
  • Limitations: All squares animate uniformly; interaction is missing. No colors. (In a version, colors follow a fixed formula, so longer viewing gets predictable.)

To be frank, this implementation still lacks the smooth “sea wave” vibe that I was looking for. In particular, I would have liked the edges to transform into non-linear lines like waves. But I would call this a first prototype as a p5.js beginner.

However, I trialed for smaller square size, and I’m surprised that such a minor change created something perceptually different. Finally, I implemented a super cool mouse click effect, which in a way achieved another level of dynamic aesthetics.

Week 2 – Kaleidoscope

Concept

When I was trying to come up with an idea on what art to create, I tried to sketch different styles, 3D, pressable, not pressable, colorful, black and white. But I wasn’t fully satisfied with the end result and couldn’t get myself to code. I was scrolling shorts and I saw one that said “Why do we still have these in a store?” and the first thing he showed was a kaleidoscope (link to short: https://youtube.com/shorts/vnFYE48zqIA?si=TGT7zf0O8515eiQ_).

When I was a child kaleidoscope was my favorite thing ever, but I would also break it eventually to get the pretty stones out of it (lmao). So then I thought, why not recreate that pattern? I also thought that the most interesting art is usually interactive. That was when I came up with the idea to make a kaleidoscope, an individual one, the one that people can customize and interact with.

Production

I didn’t really understand how to make it work and this YouTube tutorial helped me a lot: https://youtu.be/KcHqRAM0sEU?si=AfDeL56RTEBYEjbl . I watched it and customized the code as I wanted.

I first made a usual one:
Press C to clear the canvas. 

But then I wanted to make it more interesting, so I added a function where the sketch disappears every second:

Try drawing simple circles and rectangles in one place along the rhythm of one second

Difficulties and favorite part of code:

The code itself is very short and was’t so difficult to make. What actually challenged me was understanding how to do it initially. And once I got the concept I was able to create without further struggles.

One part of the code that I liked was the function that draws a line in a random color, and then draws a vertically mirrored “reflection” of that line.

function drawReflection(x, y, px, py) {
  strokeWeight(7);
  stroke(random(255), random(255), random(255));
  line(x, y, px, py);

  push();
  scale(1, -1);
  line(x, y, px, py);
  pop();
}

Conclusion:

I really enjoyed seeing how a small code can create very interesting customizable designs, and overall it was really interesting to do.

Week 2 – Reading Response

After I watched Casey Reas’s Chance Operations talk I was filled with different emotions, curious and even inspired. The way he treated randomness was probably the most interesting part of it, although it may sound cliche. The progress of his works that were shown was fascinating. He treated randomness not as something chaotic but rather international, and the precision and effort it took to create that art is truly fascinating. Even a single dash or slash, once given a set of rules and a little unpredictability, could turn into visuals that felt alive. It made me think about my own tendency to over-control creative work, sometimes the most interesting results come when I just let the imagination be (just like in homework for this class). 

I also liked the way he uses geometry as a way to move from points to lines, and even dimensions that are very difficult to picture in mind. At the same time, his examples reminded me that digital randomness isn’t truly random at all, it’s always controlled by algorithms and history. 

What stayed with me most was his idea that just a “slight bit of noise” keeps systems alive, which I think is such a relatable thing in our daily life as well, because would it be so interesting to live and to be if it wasn’t for imperfections?



Week2 – Reading Response

The video inspired me with my week 2 project. Similar to Casey’s examples, I wanted to create a piece that is randomly generated, a work where I don’t fully decide the outcome but instead design the conditions for it to emerge. What stood out to me is that randomness on its own often creates noise, but randomness framed by rules creates variation that still feels intentional. That’s why, in my own project, I didn’t let the lines fall anywhere on the canvas. If the verticals were completely random, sometimes they would overlap or sit too close together, which broke the balance I was trying to capture from Mondrian’s style. By enforcing rules, like keeping vertical lines at least 60 pixels apart and limiting where they could end, I was shaping the randomness so it produced results that still looked coherent.

This process made me think more about the balance between total control and total randomness. If I had forced every line into fixed positions, the piece would look the same every time and lose the surprise that makes generative art exciting. But if I gave up all control, the results would drift too far from what inspired me in the first place. The balance is somewhere in the middle: I act like the system builder, defining boundaries and constraints, while letting randomness fill in the details. For me, that tension is where the art lives. Creating a space where the computer surprises me, but always within a framework that reflects my intention.

Week 2 – Simple Art

I always liked Piet Mondrian’s art. Something about the lines and the geometrical shapes was satisfying. Although it is simple, I find his art, particularly his most famous work “Composition with Red, blue and yellow” to be one of my favourite art. I thought his art could be somewhat re-created with code so I decided to give it a shot.

 

Unlike its simplistic looks, creating this was much harder than I thought. At first, I just selected completely random vertical and horizontal lines. However, I quickly realized that in his work, the lines do not reach from one end to another. It sometimes fell short before reaching the total width or height of the canvas. Choosing random positions of the lines along with random lengths was not an easy process, so I decided to simple things out by controlling the lengths to a certain extent.

I made three rules. The first rule was to choose 2 verticals lines with spaces of at least 60 in between. If it wasnt for this, sometimes the vertical lines overlapped, or the distance between the lines fell so small that the outcome looked a bit ugly. The second rule was to controll the height of the vertical lines. The lines should start from 0, but the end point of the lines had to fall randomly between 60% of the height to the end. The last rule of the lines was to keep the distance between the horizontal lines to be atleast 80 pixels apart.

After setting these rules, I tried generating the lines. However, I was soon met with another problem. The horizontal lines did not intersect perfectly with the vertical lines. So to prevent this, I just placed horizontal lines where the vertical lines ended. I also decided not to play around with the lengths of the horizontal lines to keep things simple.

//the key function that chooses the lines drawn on the canvas
  function pickRandomWithSpacing(minVal, maxVal, existing, spacing) {
    for (let t = 0; t < 300; t++) {
      //first it chooses a random candidate in selecting lines.
      //usually selects lines from 0 to either height or width, this is saved as candidate
      const candidate = random(minVal, maxVal);
      let ok = true;
      //now we assume that this is a valid space, and try to check if the distance between the previously selected line and e has enough space.
      for (const e of existing) {
        //gets the previously selected value,
        if (abs(candidate - e) < spacing) { //checks if the distance is valid
          //if not, break the loop
          ok = false; 
          break; 
        }
      }
      if (ok){ //if the distance is valid, we found the valid line.
        return candidate;
      } 
    }
    return null; //if we couldnt find it, give up finding to avoid beig stuck in loop
  }

 

The key part for this artwork was randomly choosing the lines in a sort of a controlled manner. If it was chosen completely randomly, it would not look like the orignal art so I had to make some working boundaries. This is the function called pickRandomWithSpacing. It takes 4 variables: minVal, maxVal, existing, spacing. Line needs two points. The starting point of vertical line is chosen from a ranges 0 to width and is saved in array called verticalX with space of 60. The end point of vertical line is chosen from ranges 60%of height to height and is saved in array called verticalEndYs with spacing of 80. The idea of trial and error is applied when finding the correct spacing. When we first choose the space, we assume that it follows the rules that I made. However, it checks if the spaces are correctly picked. If it does not follow the rules, it breaks the loop and chooses another random space which hopes to follow the rule. It ensures that it finds the correct working spacing by repeating the loop 300 times.

This is an example of how its called

//pick two valid vertical lines
  for (let i = 0; i < 2; i++) {
    //we use the function that we created. from 0 to width, saved in arraynamed verticalX with spacing 60.
    let x = pickRandomWithSpacing(0, width, verticalXs, 60);
    verticalXs.push(x);

    //yEnd is the end value for the vertical line, I wanted to give it a end to the length of it. The vertical lines start at 0 but is randomly chosen when to end. The minimum is 60% of the height, all the way untill height. These values are saved in array calkled verticalEndYs
    let yEnd = pickRandomWithSpacing(MIN_VERTICAL_LENGTH, height, verticalEndYs, MIN_Y_SPACING);
    verticalEndYs.push(yEnd);
    
    //this pushing is key in finding the cells to color. It saves the coordinates of the lines created in order to select the different sized cells
    verticalLines.push({ x1: x, y1: 0, x2: x, y2: yEnd });
  }

 

After the lines were correctly chosen, the next part was correctly identifying the cells created. Since I saved all the nessasary points of the array. I went through several trial and error sessions to identify the cells. I found that there were 9 cells when I applied the rules and focused on finding the cells generated with the random lines. This was much more complicated then I thought because the cell sizes of x and y are completely different and unique. I had a notebook with me that kept track of the coordinates. The key point about identidying cells was finding out with points to skip. When the vertical lines fall short, when identifying the cell that does not include that particular vertical line, it needs to skip it. I was stuck on this for a long time and received advice from openAI on the logistics of it.

The rest of it was easy. I had to pick random colors from the color pallete that I chose. (The color pallete from the original work).

As you see here, I repeated null three times to increases the chances of white rectangles. This is because the original artwork contains more background than the colored ones.

Lastly, I drew the lines on top of the colored rectangles to create the final look.

For future improvements, I can apply random horizontal lengths so that not all horizontal lines reach from one end to another. Also I can also apply controlled randomization in choosing the colors instead of my complete randomization that I have now with colors. In the original artwork, when the color is chosen, the same color should not be next to each other. However, for simplicity I allowed this.

 

Week 2: Work of Art

Portrait Concept

While browsing the old computer art magazines I came across the two images below and felt like they perfectly captured the different possible contrast that can be achieved with computer art. The first one is more mechanical, sharp and exact, while the second one felt more natural and human due to it’s varying corners and circular flow. I derived my concept from this contrast, creating a work that is able to capture both ends of the scale using interactivity created with the use of loops. Initially the screen displays a constant line that stimulates the contents of a heart rate monitor, it is mechanical and rigid, what one could describe as lifeless. Then when the user comes in the picture and interacts with the work by pressing their mouse, the work begins to transition into a more organic flowing curve, along with a pulsing heart that appears in the middle that in a way adds life to the piece. This highlights the collaboration between human and machine that computer art embodies, combining both mechanical precision and human emotions.

Bild 1 Polygonzug

Bild 2 Kreis-Variationen

 

Code that I am Proud of  

for (let x = 0; x < width; x++) {
    let y_machine = baseline;

    let lineX = (x + frameCount*1.5) % 130;

    //Machine heart beat based on x position
    if (lineX < 15) {
      y_machine = baseline;
    } else if (lineX < 30) {
      y_machine = baseline - 60;
    } else if (lineX < 45) {
      y_machine = baseline + 30;
    } 

    //Human heartbeat wave
    let y_human = baseline + sin((x + frameCount) * 0.05) * 40;

    //Transitioning between machine and human
    let y = y_machine + (y_human - y_machine) * trans;

    noFill();
    strokeWeight(2);
    
    //Color changing with transition
    let r = 255 * trans;
    let g = 255 * (1 - trans);
    let b = 50 * trans;
    stroke(r, g, b);

    vertex(x, y);
  }

Most my time spent on this assignment was in creating and refining the transition between the mechanical and human line, trying to recreate the vision. After multiple tries I ended up with the for loop above, that both creates the lines and blends them together using the transition factor defined earlier in the code. I do believe that this is the most important element of the code that creates the part that captures the concept, which is why it occupied most of my attention when creating the work.  Creating it taught me a lot about the technical and conceptual thinking that goes into coding computer art. It brought my attention to things like the use of color and the possibilities technically when it came to transitioning the color, which I integrated into the code.

Embedded Sketch

Reflection

I really enjoyed exploring the possibilities that come with using loops in the creation of a work of art. After completing my previous assignment and getting more comfortable with the program, I had a goal of shifting my focus a little to the concept behind the work. Which I think I was able to achieve this assignment with the use of the computer art magazines. With their assistance I was able to get inspired and integrate meaning into the code. For future work I’d like to use the techniques I learnt today to create a work where the user interaction does not only affect the visuals, but also the narrative and direction of the piece. With this time of interactivity the work can become a collaboration between the creator, the users and the computer all at once.

Week 2: Corner Contact (Production)

 

(You can wait until it hits the corner naturally or hold Mouse1 to Speed it Up)

Before what I have here, this project started with me really curious to experiment with 3D objects, but the WEBGL system got terribly confusing with all sorts of new functions and ways I had to approach drawing shapes. I gave up on that and decided to first focus on 2D for this assignment.

I had a real tough time coming up with an idea after that. I thought about it over the weekend and I landed on the idea that I wanted whatever I made to feel satisfying, so I started thinking of things that are visually satisfying. This reminded me of a YouTube short I recently saw about how the DVD screensaver can ever only touch two opposite corners and NEVER the corner adjacent to them. This fact really lived in my head rent-free for a bit but it also made me wonder if I could create simple physics in p5js to recreate a DVD screensaver with the little JavaScript that I understood.

I started with just a ball and a simple if statement that detected whether the x position of the ball was greater than the width minus the radius, essentially allowing me to cause things to happen when the borders of the ball touched the edge. Once I had both the X and Y movements done, I needed to check for corner contacts.

function edgeBounce(i) {
  if (xPos[i] > width - radius[i] || xPos[i] < radius[i]) {
    xSpeed[i] *= -1;
  }
  if (yPos[i] > height - radius[i] || yPos[i] < radius[i]) {
    ySpeed[i] *= -1;
  }
}

Also, I know these are two dimensional circles but I will continue to refer to them as balls.

The time it would take for the ball to hit one of the corners took a really long time so I wanted to add the ability to speed up the ball animation! At first I tried to use the while() to detect when mouseIsPressed but after a lot of confusion I realized it had to be and if() function instead. However, I learned two important things today: the first was that while-else() was not a thing like if-else() is, and how to return variables from a function. It was such a natural way of learning through trial and error and it felt quite satisfying.

I eventually figured out how to do it by assigning a function, speedUp(), to return a value straight into the multiplier variable.

//somewhere in draw()
 for (let i = 0; i < xPos.length; i++) {
    // move ball
    multiplier = speedUp(i);

//..lots of code inbetween

function speedUp(i){
  if (mouseIsPressed){
    return timeMultiplier;
  } else{
    return 1;
  }
}

While I was here, I felt like the background looked a little bland at first so I decided to have a faint text in the background that would say the current speed multiplier. I made sure to have it drawn first so it’s always layered underneath the circles.

//MULTIPLIER TEXT 
textSize(400);
textAlign(CENTER,CENTER);
noStroke();
fill(multiplierColor);
text(speedUp() + "x", width/2, height/2);

And of course the main highlight of this assignment was to use loops. I was actually quite proud of how quickly I got the hang of the for loops and using arrays to take advantage of each loop.

for (let i = 0; i < xPos.length; i++) {
  // move ball
  multiplier = speedUp(i);

  
  xPos[i] += xSpeed[i] * multiplier;
  yPos[i] += ySpeed[i] * multiplier;

  edgeBounce(i); //checks for edge touch
  cornerBounce(i) //checks for corner touch, creates a new ball if successful

  // draw ball
  let c = ballColors[i];

  fill(c[0], c[1], c[2]); //RGB values of c
  stroke(c[0]-20, c[1]-20, c[2]-20); //-20 shifts it a little darker
  strokeWeight(8);
  ellipse(xPos[i], yPos[i], radius[i] * 2);
}//end of for loop
Difficulties Endured

A lot of tutorials I followed would introduce things I was not familiar with at all so I did workarounds that were probably a lot less efficient.

But most importantly, I crashed so many times and had to redo so much of my work so many times.

I originally wanted to have the new balls come out from the corner that the “motherball” contacted but when I tested my code it ended up spawning an infinite number of balls and caused my tab to completely crash and required me to redo almost 20 minutes of work.

I remember I had to write and rewrite the cornerBounce() function twice and it was really frustrating especially because of how long the if() statement was.

function cornerBounce(i){
    if ((xPos[i] <= radius[i] || xPos[i] >= width - radius[i]) &&
    (yPos[i] <= radius[i] || yPos[i] >= height - radius[i])) {
      console.log("Corner Contact Confirmed")
      if(ballCount < maxBallCount){ 
        console.log("Ball #" + xPos.length + " was Created")
        xPos.push(width/2); //PUSH adds to an array
        yPos.push(height/2); //if spawn in the corner it creates infinite balls
        xSpeed.push(random(-8, 8));
        ySpeed.push(random(-8, 8));
        
        //assigns a random color
        let newColor = random(colorOptions); 
        ballColors.push(newColor);
        
        radius.push(50);
        ballCount += 1;
      } else if (ballCount == maxBallCount){
        console.log("Max Ball Count Reached") 
      }//ends the ballcount if()
        
    }//ends the if()
}
Conclusion

Even thought my web editor crashed half a dozen times and disheartened me throughout the process, the trial and error felt like a satisfying loop of learning that will certainly help me navigate JavaScript a little more easily with each passing week.

Reading Response – Week 2

Casey Reas’ Eyeo 2012 talk, Chance Operations, made me think differently about randomness in art. He shows how even data from something as steadfast as a natural component can generate patterns that are surprising and meaningful when processed through a system with rules. It made me realize that randomness isn’t just chaos, rather it can actually be a tool if some limits are set on this. That idea challenged how I usually approach making things; I used to tend to want complete control, but maybe leaving room for the unexpected could make my work more interesting and dynamic.

For my own work for this weeks production, I’ve tried experimenting with randomness in things like layout, placement, or small visual details so the final piece isn’t predictable. For me, the balance between control and chance is having a framework that guides the work but still allows it to surprise me. I don’t want total randomness, because then it wouldn’t feel like my work at all, but I also don’t want it completely fixed, because then it might feel rigid or boring. I believe we can not overstate the attempt of finding the sweet spot between dictation and improvisation that allows the bounds of structure, and at the same time, manages to surprise with the output.

Week 2 – A Simple Work of Art

Concept:

I wanted to make something playful and unpredictable using what we have learned so far: loops, conditionals, and simple shapes. The idea was to fill the canvas with a grid, but instead of every cell looking the same, each square of the grid gets randomly assigned a circle, a square, or a diagonal line. This way, the overall structure feels ordered (in code, not compilation), but the details are different every time you run (or click) the sketch.

Code snippet to highlight:

The piece of code I’m most proud of is the tiny decision that controls the orientation of the lines. Despite it being only an If condition, it has quite an effect on how the final image looks. Without it, all the lines would lean the same way, and the grid would look stiff. With it, each line can either go \ or /, which suddenly makes the whole composition feel more dynamic and unpredictable.

stroke(random(50, 200), random(50, 200), random(50, 200), 220);
strokeWeight(random(1, 4));
let orientation = int(random(2)) // decides orientation of the line
if (orientation == 0) {
  line(i, j, i + space, j + space);
} else {
  line(i + space, j, i, j + space);

 

Reflection and Prospects:

What I like most about this sketch is how structured chaos plays out. The grid keeps everything orderly, but within each cell, there’s randomness that gives the piece character, resulting in the chaotic image we get./
If I were to push it further, I’d try:
– Rotating the rectangles randomly, not just keeping them straight.
– Introducing a shifting color palette that changes slowly over time.
– Adding a gentle animation so the grid breathes instead of sitting still.
For now, though, I think it’s a fun little experiment in how tiny tweaks (like flipping a line) can completely change the energy of a generative artwork.