Assignment 2: Going Through Life

For my second assignment, my goal became to use simple and basic shapes – rectangles and ellipses, but make the most out of them by playing with sizes and colors, while utilizing the available information resources – p5.js website Reference page, YouTube Channel The Coding Train, and the Internet as a whole. At first, I planned to make a plain art object, but as I was discovering more and more features of p5.js that I could implement to enhance the visual experience, I started seeing the bigger picture with the meaning behind it, and that is why I called it “Going through Life”.

Creating the Art

Art is a very subjective thing, especially nowadays, but I tried to create something that would simply show beauty and uniqueness. I took some inspiration from Computer Graphics and Art Journal, more specifically from “Random Squares” by Bill Kolomyjec, and decided to use shapes, random() functions, and loops as the foundation of my work. I also used the just-gained knowledge of arrays and a couple of other intermediate-level tricks that I took from the resources mentioned in the previous paragraph to make it easier to write the code. My first step was to create rectangles that would be of random size and would emerge in random locations on the canvas while I press the mouse mouseIsPressed(). Later, I decided to make the same effect but with ellipses emerging when I press the space bar using keyIsPressed() . I will explain the part of the code I am most proud of later, but now I would like to talk about the two concepts that I implemented.

1. Paint Blender

Before doing the assignment, I was looking at different works of generative art on the internet and on YouTube. Multiple times I saw how people used p5.js color functions to create something similar to the real painting. Although I was not familiar with any such types of functions, I decided to do some research on the Reference page to find something that I could apply to my work to make it look like a painting too. I came across the filter() function with the built-in parameters to impact the canvas in various types of ways. I started trying to apply them one by one to my work, and I realized that when the BLUR effect is applied, the shapes and colors that are randomly drawn on my canvas look like they are blended together, so I decided to keep it. Whenever ENTER is clicked, the colors and the shapes blend together. For me, it looks kind of like graffiti.

 

Instructions:
Press the Mouse to draw rectangles!
Press Space Bar to draw ellipses!
When you think that’s enough, click ENTER to blend the colors and the shapes!

 

2. “Going Through Life”

After finishing the job with the BLUR filter, I realized that although I reached my initial goal of creating a simple piece of art using the basic functions, it was a little bit boring and did not really have any meaning behind it. As an artist, I thought, I should convey the idea through my work, so I decided to change the filter to something more interesting. I found the DILATE filter, which increases the light areas on the canvas. I really liked the effect that it had – all the dark and grey colors were pushed away and overtaken by the bright ones, and it reminded me of how our thoughts and memories work.

The canvas is by default clear and bright – just like our minds. However, when we start facing problems, difficulties, and overall negative moments during our everyday lives, our minds start to get filled up with bad thoughts that constantly grow if we keep focusing on them. To change that, we must let go of all the negative emotions since we cannot change what happened in the past anyway. Once we do that, our minds will start getting back to light, even if it is just a small area of light left. There are wonderful moments and memories inside every one of us, and we just need to remember to turn them on. This is the mindset that I think is important – you always have to stay positive, even when you are going through tough times, and then you will surely find the light!

Thus, I made the rectangles represent the negative thoughts by changing the RGB to the lower range of values. I did the opposite with the canvas – the mind, and the ellipses – the positive thoughts. For the DILATE effect to start working, you need to “let go” and stop pressing the mouse 🙂

Instructions:

This canvas represents your mind.
Life is not life without challenges and troubles!
And we often concentrate too much on the negative emotions and feelings.
They grow just like when you press the mouse.
But it is important to let go.
And really appreciate the good things that are happening to you – unpress the mouse after some time. 
You can add positive thoughts by pressing SPACE BAR.
Try to mix pressing mouse and SPACE BAR, and then let go to see the effect!

The part of the code that I am most proud of is when I needed to figure out a way to make the process of growing look smooth and unusual. First, I used the floor(random(1, 3)) to make the random choice between numbers 1 and 2 that would represent in which direction – top/bottom (up/down) and width/height – the rectangle would grow. I used a similar technique with the ellipse. Second, I used the trick with frameCount and increased the time variable to regulate the delay before the new rectangle/ellipse started emerging. I am glad that I still remember things I learned in my Python class and am now able to apply them here in JavaScript. Lastly, I used the Alpha value of the fill() to control the transparency and make the so-called “waterfall” effect.

function draw() { 
  if (mouseIsPressed) {

      let width_vs_height = floor(random(1, 3)); // chooses whether width or height of the rectangle will increment
      
      for (let j = 0; j < 100; j += 1) {
        let emerging_rectangle = all_rectangles[j]; // takes rectangles for an array one by one
        
        if (frameCount > emerging_rectangle.time) { // delays the emergence of the next rectangle
          if (emerging_rectangle.up_vs_down === 1) { // grows down
            if (width_vs_height === 1) { // grows in width
              if (emerging_rectangle.w < emerging_rectangle.wLimit) {
                emerging_rectangle.w += incrementingspeed;
              }
            } else if (width_vs_height === 2) { // grows in height
              if (emerging_rectangle.h < emerging_rectangle.hLimit) {
                emerging_rectangle.h += incrementingspeed;
              }
            }
          }
          else if (emerging_rectangle.up_vs_down === 2) { //grows up
            if (width_vs_height === 1) {
              if (emerging_rectangle.w < emerging_rectangle.wLimit) { // grows in width
                emerging_rectangle.w -= incrementingspeed;
              }
            }   
            else if (width_vs_height === 2) { // grows in height
              if (emerging_rectangle.h < emerging_rectangle.hLimit) {
                emerging_rectangle.h -= incrementingspeed;
              }
            }
          }
        }
      

        fill(emerging_rectangle.colorR, emerging_rectangle.colorG, emerging_rectangle.colorB, random(0, 6)); //random transparency to create the 'waterfall' effect
        noStroke();
        rect(emerging_rectangle.x, emerging_rectangle.y, emerging_rectangle.w, emerging_rectangle.h);
      }
    }

Conclusion

I enjoyed working on this Assignment because it challenged me to not only write the code but also find the idea and meaning behind it. I created two variations of my artwork, and I am curious to know which one people would like more – Paint Blender or “Going Through Life”.

In terms of my p5.js skills, I feel that I learned more functions and techniques that I will definitely apply in my future work. There is a lot of room for improvement, and in terms of this particular assignment, I have some things in mind that could make the experience even better. For example, I could implement the restart button that would erase the canvas and make it empty again.

What I realized today is that p5.js is a massive field to explore. It has so many features and advanced-level functions that allow you to create basically anything that you can imagine. While going through the Reference page, I came across the Perlin noise algorithm, which I found to be quite a powerful tool, and I really want to figure out how to use it properly for my future work. I also liked the idea of the WEBGL render mode, which allows you to draw high-level 3D models, and has a number of tools that seem not to be available in the basic mode we are currently working in.

Overall, I am very satisfied with how our class is going. I came to Interactive Media to develop my imagination and creative thinking and explore the idea of thinking about art and producing it. I believe that it really helps me to improve the way I think “outside the box”, and I am looking forward to continuing this journey.

 

Assignment 1. Self-Portrait

For my first assignment, I decided to start with the basic shapes to make sure that I was comfortable with the foundations. I did not want to be too meticulous about the details; rather, I used my imagination and spatial thinking to draw fun yet precise face features that would properly display what game/social media avatars usually do.

Basic shapes – the avatar itself.

In the first stage of my work, I created a head, eyes, eyeballs, ears, and nose using straightforward ellipse() and circle() commands. I searched the Web for the most real-looking skin color RGB code and used it.

The next step was to find out the way to draw mouth, eyebrows, and hair. Again, I wanted my sketch to be similar to the real person’s features, so I decided to spend more time searching for proper code options. Looking at the examples from the past students’ work and watching the videos from The Coding Train helped me to get the idea of using arc() and quad() functions. The lesson that I learned from using these two functions is that you should be very precise with values and pay attention to details, otherwise you might mess up the drawing. It is especially important to learn how PI values work.

Moving on to the torso and the tank top, I used a little trick to visually separate the head and make it look like the neck (thanks to the arc() function that I had just learned).  I used rect() and ellipse() to create the torso and then used triangle() to visually separate the body from the arms.  Inspired by one of the works from previous years I also decided to add sunglasses and create a shape similar to the sunglasses that I usually wear using arc(), and use Alpha value  fill() to make my eyes still visible through the lenses.

Background and animations.

To add more entertainment to my self-portrait, I first decided to add some interactivity. As I had just learned about random() and mouseClicked(), I decided to combine them to make the top tank color change with every click. Next, I created the background using rectangular shapes – the beach, the sea, and the sky. I searched for the most realistic RGB color codes, and I think colors look pretty good.

Lastly, I decided to challenge myself a little bit by trying to implement techniques I used in Python here in p5.js. To catch up with the syntax differences, I watched a couple of YouTube videos and searched the Reference on the p5.js website. The thing I am most proud of is the sun movements that I implemented using a Bezier curve. First, I drew the sun’s movement trajectory using bezier(), and then I followed the instructions written in the Reference to use bezierPoint() and make the sun move back and forth. This is a part of the code I am the most proud of.

//Curve for Sun Movement
x1 = 0
x2 = 100
x3 = 300
x4 = 400
y1 = 150
y2 = 0
y3 = 0
y4 = 150
noFill()
 

let x = bezierPoint(x1, x2, x3, x4, t)
let y = bezierPoint(y1, y2, y3, y4, t)

t += 0.001 * move_sun_dir //regulating the speed of the sun
if (t > 1 || t < 0) {
  move_sun_dir *= -1
} //not letting the sun to go away from the screen
  


//Sun
fill(255,255,112)
noStroke()
circle(x, y, 50)



//Beach
fill(255, 234, 200)
noStroke()
rect(200, 400, 400, 200)

//Sea
fill(0, 105, 148)
noStroke()
rectMode(CORNER)
rect(0, 280, 400, sea_level)

sea_level += 0.05 * move_sea_dir //regulating the speed of the sea level

if (sea_level > 40) {
  move_sea_dir = -1;
} 

else if (sea_level < 30) {
  move_sea_dir = 1;
} // keeping the sea level between the rectangle size values

As you might notice, just for the fun of it, I decided to use a similar coding technique to make the sea level rise and fall (in fact it is just the size of the rectangle that changes :)).

Conclusion.

I enjoyed working on my self-portrait, and I am satisfied with the result. I created a nice-looking sketch and already started to integrate some animations and interactivity into my work. Of course, there is tons to learn, and my self-portrait could be even more advanced. I was thinking of adding moving clouds to the sky, drawing palm trees on the beach, or adding ships going back and forth in the sea. I could add many more details, and I am looking forward to learning new tools and features to implement it. The coolest thing that I wanted to add but couldn’t is the change between day and night. As I made the sun move, I realized that it would look awesome if the brightness dimmed every time the sun went down, and vice-versa. I could also add the moon and the stars at night, and make them disappear in the morning.

Overall, this assignment was a great start to my journey in Interactive Media, and I can’t wait to see where this journey will lead me.

 The Whole Code:

let r, g, b;
let t = 0;
let move_sun_dir = 1;
let move_sea_dir = 1;
let sea_level = 30;

function setup() {
  createCanvas(400, 400);
  r = random(255)
  g = random(255)
  b = random(255);
}

function draw() {
  background(135, 206, 235);
  
  
  //Curve for Sun Movement
  x1 = 0
  x2 = 100
  x3 = 300
  x4 = 400
  y1 = 150
  y2 = 0
  y3 = 0
  y4 = 150
  noFill()
 
  
  let x = bezierPoint(x1, x2, x3, x4, t)
  let y = bezierPoint(y1, y2, y3, y4, t)
  
  t += 0.001 * move_sun_dir //regulating the speed of the sun
  if (t > 1 || t < 0) {
    move_sun_dir *= -1
  } //not letting the sun to go away from the screen
    
  
  
  //Sun
  fill(255,255,112)
  noStroke()
  circle(x, y, 50)

  
  
  //Beach
  fill(255, 234, 200)
  noStroke()
  rect(200, 400, 400, 200)
  
  //Sea
  fill(0, 105, 148)
  noStroke()
  rectMode(CORNER)
  rect(0, 280, 400, sea_level)
  
  sea_level += 0.05 * move_sea_dir //regulating the speed of the sea level
  
  if (sea_level > 40) {
    move_sea_dir = -1;
  } 
  
  else if (sea_level < 30) {
    move_sea_dir = 1;
  } // keeping the sea level between the rectangle size values
  
  
  // Head
  fill(255,205,148)
  noStroke()
  ellipse(200, 200, 120, 150);
  
  // Eyes
  fill('white')
  circle(175, 185, 15);
  circle(225, 185, 15);
  
  //Eyeballs
  fill('black')
  circle(175, 185, 5);
  circle(225, 185, 5);
  
  //Mouth
  fill('white')
  stroke('rgb(255,189,201)')
  strokeWeight(4)
  arc(200, 235, 35, 25, 0, PI, CHORD);
  
  //Nose
  fill(224,172,105)
  noStroke()
  ellipse(200, 210, 10, 20);
  
  //Ears
  fill(255,205,148)
  ellipse(140, 190, 20, 30);
  ellipse(260, 190, 20, 30);
  
  //Side Hair
  fill('black')
  quad(145, 145, 165, 150, 160, 185, 145, 180);
  quad(248, 140, 235, 145, 240, 185, 257, 180);
  
  //Top Hair
  fill('black')
  ellipse(width / 2 - 5, 135, 110, 50);
  
  //Eyebrows
  noFill()
  stroke('black')
  arc(175, 180, 16, 16, PI + 0.6, TWO_PI - 0.5)
  arc(225, 180, 16, 16, PI + 0.6, TWO_PI - 0.5)
  
  //Tank top and Torso
  noStroke()
  fill(255,205,148)
  ellipse(150, 370, 100, 200)
  ellipse(250, 370, 100, 200);
  
  rectMode(CENTER)
  fill(r, g, b)
  rect(200, 370, 115, 200);
  
  stroke(255, 234, 200)
  strokeWeight(5)
  triangle(137, 400, 140, 325, 140, 400)
  triangle(260, 400, 260, 325, 263, 400)
  
  //Neck
  noStroke()
  fill(255,205,148)
  arc(200, 270, 50, 50, 0, PI, CHORD);
  
  //SunGlasses
  fill(0, 0, 0, 100)
  stroke('black')
  strokeWeight(0.2)
  arc(175, 178, 22, 37, 0, PI, CHORD)
  arc(225, 178, 22, 37, 0, PI, CHORD)
  strokeWeight(2)
  line(143, 175, 164, 185)
  line(236, 185, 257, 175)
  line(186, 185, 214, 185)
  
}

// Changing color of the tank top
function mouseClicked() { 
  r = random(255)
  g = random(255)
  b = random(255)

}