Week 3 Assignment: Generative Artwork using OOP: Screensavers and Physics

Concept and Inspiration

For this assignment, I drew inspiration from the the era of late 1990s and early 2000s. At that time, Windows 98 and Windows XP had some unique screensaveers which I still remember and which evokes a sense of nostalgia in me. These screensavers (link) often featured geometric shapes and repetitive, hypnotic patterns, such as oscillating lines, spirals, and pendulum-like movements.

Fig: Some of the Windows Screensavers

For this, I used robotic arms and “Inverse Kinematics” as my inspiration. From my point of view, I saw this as the perfect oppertunity to blend computational techniques into this visual style. The robot arms represent the pendulums of the past, but with a unique twist. Instead of being merely simple lines, these arms demonstrate the principles of Object-Oriented Programming (OOP), where each pendulum is treated as an independent object, following specific behaviors such as oscillation and length growth. Moreover, inverse kinematics allows each arm to dynamically respond to changing positions, mimicking the flexibility and precision of robotic motion. The result is a digital artwork that blends the nostalgia of retro visuals with the sophistication of modern computational design.

Code Explanation

“Arm” class

This class features a constructor which initializes each pendulum’s amplitude, angle, angle velocity, and length growth. It also has the “update()” function to update the pendulum’s length (amplitude) and oscillation (angle). Using the “display()” function, it calculates the current position of the pendulum and draws a line from the previous position.

// Defining the Arm class
class Arm {
  constructor(amplitude, angle, angleVel, lengthGrowth) {
    this.amplitude = amplitude;      // Initial length of the arm
    this.angle = angle;              // Starting angle
    this.angleVel = angleVel;        // Angular velocity
    this.lengthGrowth = lengthGrowth; // How fast the arm grows in length
  }

  // Method to update the arm's properties (growth and oscillation)
  update() {
    this.amplitude += this.lengthGrowth; // Increase length over time
    this.angle += this.angleVel;         // Update angle for oscillation
  }

  // Method to display the arm
  display(prevX, prevY) {
    let x = sin(this.angle) * this.amplitude;  // Calculate x position
    let y = cos(this.angle) * this.amplitude;  // Calculate y position
    line(prevX, prevY, x, y); // Draw line from previous position to current
    return { x, y };          // Return current x, y for the next arm
  }
}
“setup()” function

The “setup()” function initializes the canvas size and prepares the environment. It disables fills for the shapes and sets default stroke properties. It randomizes the number of pendulum arms (num_arms) and the other arm’s properties, with each arm receiving random values for amplitude, angular velocity, and growth rate. The arms are stored in an array, each represented as an object with properties for oscillation and growth.

function setup() {
  createCanvas(800, 800);
  noFill();
  stroke(255); // Initial stroke color
  strokeWeight(1); // Initial stroke weight

  // Randomize the number of arms between 2 and 10
  num_arms = int(random(2, 10));

  // Initialize the Arm objects with random values
  for (let i = 0; i < num_arms; i++) {
    let amplitude = random(70, 150);
    let angleVel = random(0.01, 0.05);
    let lengthGrowth = random(0.1, 0.5);

    // Create new Arm and push to the arms array
    arms.push(new Arm(amplitude, 0, angleVel, lengthGrowth));
  }

  // Initially set the center to an off-canvas position
  centerX = -1000;
  centerY = -1000;
}
“draw()” function

This function creates a semi-transparent background overlay to maintain the fading trails without fully erasing the canvas. The “rect()” draws a slightly transparent rectangle over the entire canvas, producing the trailing effect. The “translate()” function shifts the origin of the canvas to the clicked point (centerX, centerY), which acts as the center of the pendulum system. A loop iterates over each arm, calculating its new position based on its current angle and amplitude using “Inverse Kinematics.” The arms are drawn as lines connecting from one pendulum to the next, simulating the robot arm movement whos length increases with time.

// Draw Function
function draw() {
  if (hasStarted) {
    fill(0, 10); // Semi-transparent background to maintain trails
    rect(0, 0, width, height);

    // Set the center of the arms to the clicked position
    translate(centerX, centerY);

    let prevX = 0;
    let prevY = 0;

    // Loop through each arm and update and display them
    for (let i = 0; i < arms.length; i++) {
      let arm = arms[i];

      // Update arm properties
      arm.update();

      // Display the arm and update the previous position for the next one
      let newPos = arm.display(prevX, prevY);
      prevX = newPos.x;
      prevY = newPos.y;
    }
  }
}
“mousePressedI()” function

The “mousePressed()” function updates the center of the pendulum system to wherever the user clicks on the canvas (mouseX, mouseY). This triggers the pendulum animation by setting “hasStarted” to true. Upon clicking, it randomizes the stroke color, weight, and number of arms, creating variety and making each user interaction unique. It also reinitializes the pendulum arms with new random values, ensuring a different pattern is generated with every click.

// This function will run when the mouse is pressed
function mousePressed() {
  // Set the new center of the arm system to the clicked location
  centerX = mouseX;
  centerY = mouseY;
  hasStarted = true;

  // Randomize background and stroke properties
  stroke(random(0, 255), random(0, 255), random(0, 255));
  strokeWeight(random(1, 10));

  // Randomize the number of arms between 2 and 6
  num_Arms = int(random(2, 6));

  // Reinitialize the arms array
  arms = [];
  for (let i = 0; i < num_Arms; i++) {
    let amplitude = random(80, 150);
    let angleVel = random(0.01, 0.05);
    let lengthGrowth = random(0.1, 0.5);

    // Create new Arm objects with random values
    arms.push(new Arm(amplitude, 0, angleVel, lengthGrowth));
  }
}

Sketch

Further Improvements which can be made

Smoother Transitions: Currently, the background might change too quickly when clicking. Adding a smooth transition effect between pendulum sets can make the animation more fluid and visually appealing.

Scaling upto 3D space: I had originally though of introducing a responsive 3D canvas using “WEBGL” mode in p5.js, but that was making the idea of user interaction a little complex, so I had to drop that for now.

Damping: Currently, the simulation runs the pendulums until another person clicks it. Introducing damping can be another way to introduce realism to it.

Collission: Various arms when coming in contact with each other change their path/length can be another aspect which can be looked to.

Reflection

This project modernizes the retro screensaver aesthetic using modern programming techniques such as OOP and inverse kinematics, combined with user interactivity. The code is modular, making it easy to add new features or improvements, and the possibilities for further customization and expansion are vast.

Assignment 03: River Flow

Concept: I wanted to create a view of my home country, Bangladesh, which is filled with. hundreds of rivers, and with time the rivers are shrinking. So, I used this assignment to create something that represents the rivers from Bangladesh in a sunset light.

Code:

I’m particularly proud of the FluidSimulation and FlowingMotif parts of my code because they exemplify a thoughtful blend of creativity and technical skill. The FluidSimulation class captures the essence of fluid dynamics with its elegant use of vectors and noise functions to simulate realistic flow patterns. The display() method, with its precise rendering of flow lines, transforms abstract concepts into a visually engaging experience. This method doesn’t just draw; it visually narrates the movement of fluid in a way that is both aesthetically pleasing and scientifically intriguing.

Similarly, the getForceAt() method provides a crucial interface for interaction with the fluid simulation, enabling dynamic elements like particles to seamlessly integrate with the simulated environment. This capability is pivotal in creating a responsive and immersive visual experience.

The FlowingMotif class adds a touch of artistic flair to the simulation. By using dynamic shapes that evolve over time, it introduces an additional layer of visual interest and complexity. The carefully crafted constructor ensures that each motif is unique, with properties that allow for smooth and captivating motion. The motifs enhance the overall aesthetic of the simulation, bringing a sense of life and movement to the scene.

display() {
    noFill();
    strokeWeight(1);
    for (let y = 0; y < this.rows; y++) {
      for (let x = 0; x < this.cols; x++) {
        let v = this.field[y][x];
        let px = x * this.gridSize;
        let py = y * this.gridSize;
        stroke(255, 100);
        line(px, py, px + v.x * this.gridSize, py + v.y * this.gridSize);
      }
    }
  }

  getForceAt(x, y) {
    let col = floor(x / this.gridSize);
    let row = floor(y / this.gridSize);
    col = constrain(col, 0, this.cols - 1);
    row = constrain(row, 0, this.rows - 1);
    return this.field[row][col].copy();
  }
}

// FlowingMotif class definition
class FlowingMotif {
  constructor(x, y, size) {
    this.x = x;
    this.y = y;
    this.size = size;
    this.angleOffset = random(TWO_PI);
    this.frequency = random(0.01, 0.05);
  }

P5.js Sketch:

Week 03: Reading Reflection

In the first chapter of Chris Crawford’s The Art of Interactive Design, I found myself engaged with the foundational ideas presented. From Crawford’s exploration into the nature of interaction as the core of design, one of the key takeaways for me was Crawford’s emphasis on interaction being the core of design. Before reading this, I often saw interactivity as an added feature rather than the fundamental aspect of the user experience. It was like a light bulb went off when he explained that interaction isn’t just about adding clickable elements but about making the whole design process revolve around the user’s actions and reactions. This perspective has made me question my approach to design—am I truly focusing on how users interact with my work, or am I just ticking off boxes?

I agree with him on the definition of interactivity. If I am creating an interactive device/art/product, I should always remember how four parameters, aka listening, speaking, thinking, and responding, work on my idea. I really enjoyed how he explained interactivity with examples, making it easier to even teach my 7-year-old brother about interactivity in technology.

Lastly, on the notion of traditional entertainment like movies being non-interactive, I think that might get shifted with emerging technologies. Digital media, including interactive films, virtual reality experiences, and even interactive web-based stories, demonstrate that interactivity can be a fundamental aspect of various media forms. The rise of these new media formats challenges the traditional notion that interactivity is limited to games or other explicitly interactive experiences.

Week 3: Reading Response

The whole idea of interactivity and its distinction from mere reactions or participation stood out for me considering the focus of this course (Introduction to Interactive Media). As the text analyses interactivity insisting on dynamic exchanges between participants, requiring active listening, thoughtful consideration, and responsive speaking, I realize the importance of these elements. As an artist, I aim to integrate emotional aspects of my designs, considering how my audience will hear, think, and speak as they interact with my work. Beyond artistic experiences and designs, I also hope that computer systems and programs continue to evolve becoming more interactive as we evidently see it bloom day by day through the advancement of generative AI and other technologies. 

While interactivity involves listening, thinking, and speaking, its application might be challenging or unnecessary in some contexts within computer systems and applications. I hope that the level of interactivity required be only tailored to the specific needs and goals of the system or application.

Week 3: Smooth Lights

Concept and Inspiration

For this week, as I was looking forward to make use of arrays and object oriented programming, I wanted to draw lights that smoothly turn on and off. My idea has inspiration  from disco lights that blink turning on and off. An image of such an arrangement of lights can be seen here below:

The alternation of black and white colour are intended to create an illusion of lights turning on and off.

Implementation

To implement my idea, I created two classes one for the boxes and one for the circles. I had functions to draw the boxes and circles in each class and created the objects in the setup function and saved the locations of each in an array. In the draw function I used the arrays to draw the boxes in the canvas.

My sketch

My final sketch can be seen here below:
<

My code

Continue reading “Week 3: Smooth Lights”

Floating balloons

Concept

The inspiration for using balloons in this project came from a Chelsea football match I watched on Saturday, September 14. During the game, my team struggled to score until a substitute player finally found the net. In his celebration, he blew up a balloon, which sparked the idea to create a project centered around balloons. I wanted to capture that moment of excitement and celebration by translating it into an interactive experience where each balloon expands and changes color when clicked. My goal was to apply the programming concepts I’ve learned so far to build something creative and playful using balloons.

Christopher Nkunku, the chelsea Player who scored the only goal of the game and did his iconic balloon celebration.

 

Implementation

The project is built using p5.js and applies Object-Oriented Programming (OOP) to create interactive floating balloons. A `Balloon` class is defined, with properties like position, size, color, and growth rate. Each balloon floats upwards and resets when it reaches the top of the canvas. On each mouse click, the clicked balloon changes color and expands by a set amount.

The `setup()` function initializes an array of balloons with random attributes, while the `draw()` function continuously updates and displays the balloons. The `mousePressed()` function checks for clicks and triggers balloon growth and color changes. This structure efficiently demonstrates object interaction, animation, and user engagement with OOP principles.

Highlight

One aspect of the code that I enjoyed implementing was the incremental growth of balloons on each mouse click. Instead of making the balloon instantly expand to a large size, I wanted to ensure each click resulted in a smooth, controlled increase. To achieve this, I implemented the grow() and clicked() methods within the Balloon class. This is the code that shows the highlight: 

  // Incrementally expand the balloon when clicked
  grow() {
    this.balloonSize += this.growthAmount;  // Increase size by a fixed amount per click
  }

  // Check if the balloon is clicked
  isClicked(px, py) {
    let d = dist(px, py, this.x, this.y);  // Distance from mouse to balloon center
    return d < this.balloonSize / 2;  // Check if mouse is inside the balloon
  }

  // Change color and grow when clicked
  clicked() {
    this.color = color(random(255), random(255), random(255));  // New random color
    this.grow();  // Incremental growth with each click
  }
}

 

Embedded Sketch 

 

Future Reflections and Ideas for Future Work

Looking ahead, there are several ways I could improve and expand upon this project. One idea is to implement a balloon popping mechanic, where balloons could “pop” after reaching a certain size, adding another layer of interaction and completion. This could involve sound effects to make the interaction even more satisfying and immersive for the user.

Additionally, I could introduce different behaviors for each balloon, such as varying floating speeds or randomized directions, to make the scene feel more dynamic. Another potential improvement would be to add more complex user interactions, like dragging balloons or having them respond to other inputs such as keyboard presses.

Finally, I’d like to explore using advanced animations to create a more gamified experience. These ideas could help make the project more engaging and add more variety for the user.

Week 3: Rainbow Wind Chimes

Concept

When trying to decide what I wanted to do for this assignment, I found Chris Crawford’s definition of interactivity coming to mind. In previous assignments, I think I was too focused on one or two aspects of interactivity that made my piece feel like it was lacking something, despite me being finished. So in getting started with this one, I took to the internet for some general brainstorming on what interactive art could be. After a quick Google search, I came across the following image: 

This ribbon installation by Benoit Pailley caught my attention and became the main inspiration for my piece. In addition, either in class or through clicking through other people’s  work I saw a cool blending trail element  and definitely wanted to incorporate that feature into my own project.

Lastly, as I began to see the project develop further I was reminded of wind chimes (mostly because of their rectangular shape) and their movement in the fading out of colors so decided to go with that as my overall theme. I briefly considered making all the rectangles hues of green to represent the flow of nature but felt that that was a bit too far of a reach and was more comfortable with the brighter, louder colors for this one. I thought the bright colors on contrast with the black and white background was a nice juxtaposition with the soothing nature with which the objects are moving.

Components 

Although it made a big difference in the final outcome making  the object trail as they move was super simply. I simply added on a second parameter to background(0, 10)  so that the alpha transparency value would smooth out the color of the rectangle for every frame. I got this idea from Ethan Hermsey  on Stack Overflow.  For the foundation of the code (generating the rectangles and having them move) I referenced the code we reviewed in class, more specifically Ball Class 2. From there, I simply added an array og objects so that I could store all of the rectangles in one place, and change them by referencing for (let rectangle of rectangles) .

I added a few ‘interactive’ (not sure if they live up to Crawford’s definition) components for the user that are accessed through the mouse and keys. For starters, when the mouse is double clicked, all of the rectangles become shades of grey and depending on what key is pressed, the rectangles will flow from a different side of the canvas. Also, the spacebar changes the colors back from shades of grey to multi-colored and all the rectangles stop moving when you hold down on the mouse.

An Aspect I Am Proud Of

I am most proud of the interactivity in this assignment. Although once you get one side down, it is rather easy to apply it to the other three I ran into little problems (like dealing with keyCode() and keyPressed() that prolonged the process. Furthermore, I ended up undoing a couple of changes with these moving pieces that took me quite a while was rather proud of myself for doing so because although it made me feel like I wasted time, it was all in the name of the artistic process.

function doubleClicked(){
  //why does it change direction for bw but not back to color?
  whiteBack = true;
  for (let rect of rectangles) {
    rect.color = random(255); 
    rect.speedX *= -rect.speedX;
  }
} //color -> BW change direction (after first time?)
//bw -> no change
function keyPressed() {
  whiteBack = true;
  if (key === ' ') {
    for (let rect of rectangles) {
      rect.color = color(random(255), random(255), random(255));
      // rect.speedX *= -rect.speedX;
    }
  }

The code that I’ve embedded is not my entire keyPressed function but actually a piece of keyPressed() and the entirety of doubleClicked(). I chose these two because they were the first two functions I added to alter the rectangles movement and thus the most difficult for me to implement.

Final Product

Reflection

Overall, I am fairly satisfied with the outcome of this piece. It is by far the most aesthetic thing I’ve created for class so far and was an effective application of the concepts we learned. However, I feel like it lacked depth in terms of meaning and kind of just developed as something I’d enjoy visually.

Also, there are two odd bugs that I couldn’t figure out and would like to solve in the future. The first one being that after switching from black and white to color (or vice versa) there are streaks of the previous paths of the rectangles as if they were created in a background of a different color. From what I could tell, I set it so that the background would be the same throughout (either black or white) but when it is supposed to be white, it almost appears grey against the white-streak contrast. Finally, in some instances when the rectangles are returning back to their starting side (after bouncing on the opposite wall) they just fade away and I could not figure out why. I used the code from class  for the walls of the bouncing ball (if (this.y < 0 || this.y > height) ) for both x and y (when deemed necessary) to ensure they stayed within their boundaries but was unable to get it to work how I imagined.

All in all, I really am pleased with this piece and do actually want to fix these issues because once that is done, I do feel like the project will actually be complete.

 

Week 3 – Object-Oriented Programming

Concept: I wanted to create an interactive art piece while challenging myself code-wise. I settled on a little game of popping balloons. I used class to make the circles. I also randomized colors from a set of specific colors in an array. The interactive part of the art is when a circle is clicked, it disappears, giving the popping effect.

Code: I’m specifically proud of this line of code because I used the not condition to check whether to continue growing based on a mouse click.

grow() {
    if (!this.clicked) { // Only grow if not clicked
      this.radius += this.growthRate;
      if (this.radius > this.maxRadius) {
        this.radius = this.maxRadius; // Capping the radius
      }

Problems: A problem I faced was having the circles overlap the text, hiding it from sight. Another one was needing to refresh the sketch to repeat the art. I wish I could have implemented a way that when all balloons are popped, it regenerates them by itself.

 

Reading Reflection – Week 3

Crawford argues that big ideas are elusive and hard to capture in a sentence-long definition, and I agree. However, he then proceeds to do this and limit what can be considered interactive. He argues that books, movies, and performance art are not interactive, but I beg to differ. Consider a choose-your-own-adventure movie or book; is this not regarded as interactive? One could argue that Crawford’s book was published in the early 2000s, so he might not have heard of such media. Yet those interactive forms, specifically books, were famous in the 90s.

Another example that he fails to consider is stand-up comedy. The comic interacts with the audience, listening, thinking, and speaking, all of which Crawford states are part of an interactive piece. Add to that, many of the jokes in a set come from the ability of the comic to improvise based on the audience, further proving the point that performance art is interactive. Putting that aside, I agree with him that interactivity relies on good listening, thinking, and speaking. This could be applied to p5 by implementing real-time feedback mechanisms that respond to user input—for example, having the sketch change based on whether the mouse is pressed.

Week 3 Reading Reflection

Chris Crawford’s “The Art of Interactive Design” emphasizes the importance of interactivity as more than just a simple response to input. Crawford defines true interactivity as a system’s ability to listen, think, and respond, much like a conversation. This approach highlights the need for thoughtful engagement between the user and the system, ensuring that interactions feel dynamic and meaningful. Systems that effectively apply this model create ongoing exchanges, where both user and system influence each other, ultimately making the user feel actively involved and engaged in the process.

In improving the level of interactivity in my p5.js sketches, I aim to apply these concepts by going beyond simple triggers and creating a more thoughtful, adaptive experience. Instead of a one-time action from the user generating a single response, I want the system to react dynamically, changing multiple aspects of the sketch based on continuous input. For example, rather than a simple click to trigger an animation, the user’s actions could influence multiple variables like movement, color, and object behavior, creating a more engaging and evolving experience. Crawford’s “listening, thinking, and responding” approach can help me develop sketches that offer a richer interaction and make the user feel more connected to the experience.