Week 1 – Self Portrait

My Concept:

Going into this assignment as a beginner in p5, I knew I wanted to choose a muse that would give me the flexibility to play around with the basic foundations of the coding language, especially with coordinates and the order of execution of lines of code. I ended up choosing to create a simple sketch of a mouse. The simplicity of the shapes were beginner friendly and helped me become more comfortable with coding in p5. The final result left me quite satisfied, as I ended up with a cute animated animal created using 2D shapes.

Highlight of Sketch:

One part of the code I was particularly proud of was the use of arcs. It may seem quite simple; however, I was quite satisfied with how I was able to utilise what I learned in class to create a desired outcome for the mouse’s mouth.

I was also quite satisfied with the placements of lines to represnt whiskers, as it took some trial and error.

//MOUTH
//arcs are tilised to create a cute representation of a mouse's mouth
noFill();
stroke(0)
strokeWeight(2)
arc(190,239,18,14,0,PI)
arc(208,239,18,14,0,PI)

//WHISKERS
//lines are drawn in pairs of two and parralel of eachother to create a set of whiskers for the mouse
line(160,235,185,230)
line(160,245,185,230)
line(240,235,215,230)
line(240,245,215,230)

 

Embedded Sketch:

How this was Made:

I started the process by setting my mind on an idea, and I ended up choosing a mouse. I decided to emphasize what we learned in class in my code, and I reviewed the links to the different shapes we created to refresh my memory of coordinates and different lines of code.

I started by creating the body and ears with circles first to put them in the back. I then drew the mouse’s head right after to account for the overlapping of the shapes. I then drew the mouse’s features using a variety of shapes such as circles, ellipses, and lines. Finally, I went over my code and added more detail to the code visual to try to add dimension to the mouse as much as possible, given that it is two-dimensional.

Reflection and Future Ideas:

Overall, considering this is my very first time playing around with p5, I am satisfied with the outcome and quite fond of my cute mouse illustration. In most coding experiences, there was obviously some trial and error, which, in my opinion, is the art of coding. I was able to create an outcome I am proud of, and hopefully in future assignments I can see how far I’ve come from my very first assignment.

In future assignments, I hope to incorporate interactivity and some dynamic features into the code. I also hope that as the lessons progress, I am able to obtain more knowledge in p5 and create even more impressive coding experiences.

Assignment 1: Self Portrait

“I am my own muse. I am the subject I know best. The subject I want to know better.” — Frida Kahlo

Concept:

For our very first assignment in Intro to Interactive Media, I was able to make a portrait of myself, using only simple 2D shapes, through the use of p5.js’ functions. My main goal was to try an recreate as many facial features about myself, such as my lush, green eyes. Also I added some clothing with a color which sort of, compliments my eyes.

Below is my finished portrait:

How it’s made:

The portrait was made using p5.js’ functions for 2D shapes. I made good use of ellipse, quad, arc, circle mostly as they helped me get a good grasp of how I would shape my face.

Starting out though was actually difficult, as I was confliced of whether it would be best to use a circle or an ellipse for my facial structure. Of course both would work out, but I chose the ellipse as it made more sense for me, as I could add get a better shape to add external features, such as my ears or hair.

Then it was a simple case of designing my face out. I used ellipses for my sclera, and a circle for my pupil and iris. I used ellipse for my nose (though I was considering using a triangle too). And for my shirt I used a few quadilaterals to make the shape of my body. As for the shoulders, I used ellipses that are slightly raised and feel more natural.

Now I did have a few struggles whilst creating the portrait, such as positioning the shapes. I started out using the width and height arguments and then having them positioned by either adding or subtracting a given value. Whilst this worked for a while, it was cumbersome as to figure out the starting and end points of where I wanted my shapes.

But then is when I used my smart head for once and thought

“Wait, I can use the print function to see the exact coordinates of the canvas, so I can see where I can pop my x and y coordinates”

So afterwards for some of the shapes in the code I decided to simply use exact values in order to make my life easier haha. This was done just by using the print function to print out the current position of the mouse using mouseX and mouseY.

Another issue I faced and a partial learning curve was the arc function. I had difficulty with understanding how to utilize it in terms of generating the shape of the arc. As the function utilized the arguements pi, half pi and quarter pi, it was difficult to see at what part did the arc start and end. The arc function was mostly used for my mouth and eyebrows and my hair for a more curved feel.

A highlighted bit of code I’m proud of:

So as my birthday was approaching (14th of February and yes, I’m born on Valentine’s Day 😊), I thought to try my hand at adding a funky effect to sort of mark the occasion. I was aware of the mousePressed and random functions and decided to have it generate circles of random color and size, with them being randomly appear around the background. The reason why I’m proud of it was I wanted to see what a simple effect would do for my canvas.

if (mouseIsPressed){
  
  background(0)
  
  noStroke()
  fill(random(0, 255), random(0, 255), random(0, 255), 100)
  circle(random(width), random(height), random(10, 100))
  
}

Reflection:

I throroughly enjoyed creating my self portrait. Although at many points I had struggles with positioning the shapes around, I was able to sort of overcome it in my own manner. The main thing I struggled with was the arc function, as I was a bit confused at how to implement it with getting the arc correct.

I also did like the addition of the effect but I feel like I’d love to add more perhaps to my own self, such as giving myself a different expression. And maybe I could touch up the effect a little more, such as adding more texture. Perhaps even having a smooth effect would be a nice addition. But overall, as a start, this assignment was quite fun to do and I relished in creating my own portrait.

Week 1 – Self-portrait

Concept

When I think about portraits, I believe personal characteristics should always be included to reveal who the person really is. When it comes to me, my favorite hobby— sports —immediately came to mind. Now I play for the NYUAD Volleyball team and I really love being there and doing my best at practice.

When I study, I usually feel sleepy and I don’t enjoy doing boring homework, but I always have energy for volleyball. So, I decided to make an interactive self-portrait that reflects this contrast. In the sketch, an item (either a book or a ball) is tied to the mouse’s position. When the user double-clicks, my facial expression, clothes, the item itself, and the background all change.

Highlight Code

One part of the code that I particulary liked is integration of double-click:

function doubleClicked() {
  if (thing.chosen_type == 'book' && bg.type == 'library' && character.type == 'sad') {

    thing.chosen_type  = 'ball';
    bg.type = 'volleyball';
    character.type = 'happy';
  } else {
    thing.chosen_type = 'book';
    bg.type = 'library';
    character.type = 'sad';
  }
}

Since I have some prior coding experience, I used OOP principles to make the object move with the mouse and change states with a double-click. Even though the code itself is quite simple and straightforward, these interactive elements make a big difference to the overall picture. In this code snippet, double-click changes the attributes of the background, character, and item. It changes their type to another one, so in the next frame they will change and the code will display the picture with changed characteristics.

While creating the self-portrait, I relied on the p5.js reference page and Googled RGB codes for specific colors. I also had to look up the syntax for class and function creation, since I know how to do this in Python, but not JavaScript.

I used simple shapes in my portrait, but the most difficult ones were the arcs. It was hard to find the exact angles to make the arcs look the way I wanted while maintaining the right shape. I had to experiment with different angle values and ellipse diameters to create bangs that looked correct. I also spent time figuring out the angles for the main hair so it would look like a short haircut and not just a squished circle.

Reflection

Reflecting on my work, I definitely want to improve the overall design. I want to add more specific details so the portrait becomes less simplistic. In terms of interaction, I think adding more complex animations, such as the eyes tracking the movement of the ball or book as they moce with a mouse, would be great. Finally, making it a 3D version where the character is a detailed 3D model with depth, shades and textures, and the object actually rotates in 3D space would be awesome.

Assignment 1: Self Portrait

Here is my final self-portrait:

Concept:

For this project, I created a self-portrait using only 2D primitives. My goal was to make the portrait have many traits of me while still keeping the forms simple, using what we learned in class about 2D primitives and the p5 reference website. I used the same hijab color I wear most often, gold jewelry that is similar to what I wear every day, and burgundy for the shirt since it is my favorite color. 

How this was made:

The portrait was created using basic 2D primitives such as the ellipse, rect, arc, line, and quad. It was really hard positioning the shapes, especially when creating the lashes and the bent right arm. It was a constant trial-and-error process, which helped me better understand how each value in the shape controls the position and form.

For the face, I was not sure what exactly to do, especially because my knowledge of the platform and scope was limited. But I kept the features minimal by just using simple shapes, like an ellipse for the eyes, a small half-triangle nose made with lines, and an arc for the mouth. I was initially unsure how to create the hijab, but by experimenting with a large black ellipse and putting it behind and around my face, I was able to create a framing effect that resembles a hijab without making it too difficult. 

After making the portrait of myself, I decided to experiment with some motion and interactivity, even though we have not covered it yet in class. I started looking at some examples, and I saw many people make the pupils of the eye follow the mouse. So I did this by slightly adding mouseX and mouseY values to their original positions and then limiting the movement by multiplying by 0.008 so the pupils stayed inside the eye. I learned this by reviewing the slides to get an understanding of the variables and watching some tutorials from “The Coding Train” to get a better idea of it. 

Code highlight:

One part of the code that I am particularly proud of is the thought bubble interaction. When you click on the portrait, two thought bubbles appear with random words generated inside them to represent my thoughts. 

let showThoughts = false;//to make the thoughts hidden at first

let thoughts = [
  "THINKING",
  "IDK",
  "SCHOOL",
  "FUTURE",
  "TIME",
  "WHY",
  "WHAT IF",
  "PRESSURE",
  "OK",
  "TIRED"
]; //words I want to have in the background

function setup() {
  createCanvas(400,400);
  }

function mousePressed() {
  showThoughts = !showThoughts;
}//so if you click the thoughts the thoughts appear and if you click again the thoughts disappear.

function draw() {
background('#D2D1C7');//to set the background
print(mouseX, mouseY)
 
//Thought words (the background layer)
//fill(0,80); //making the words black and low opacity
//stroke(0,80);//so the stroke is the same color as the fill
//strokeWeight (3); //to make the text bold
//textSize(20);//to make the text bigger
//text(random(thoughts), random(width), random(height));//to draw a random word at a random position.

  
  
//Only draw thoughts if clicked
if (showThoughts) {
//Thought bubbles
noStroke();
fill(255, 230);//soft white and slightly transparent
ellipse(110, 90, 200, 140);//left bubble shape
ellipse(297, 85, 200, 140);//right bubble shape

//Thought words
fill(0);//black
stroke(0);
strokeWeight(2);
textSize(20);

//Left bubble text
text(random(thoughts),random(110 - 60, 110 + 50),random(90 - 40, 90 + 40))//picks one word randomly, then I put padding so it does not go outside the circle 
//Right bubble text
text(random(thoughts),random(277 - 60, 277 + 50),random(85 - 40, 85 + 40));//same thing here just with different placements (I put a smaller number, 277 instead of 297 because some of the text still went outside the bubble for some reason)
  }

This section was quite challenging because I had to control where the text appeared so it stayed inside the bubbles. 

Reflection/future work:

I did not want the background to be left empty. At first, I wanted random words to fill the entire background, but I figured it was too visually messy, and I did not like the result of the background just being black. So I decided to scratch that and just make a thought bubble using white ellipses and have my thoughts scatter in them, where they only appear when you click on the portrait. 

I liked this idea because it allows the viewer to first see my appearance, then reveal what is happening internally, making my self-portrait a bit more personal. At first, you only see me holding up a peace sign, but when you click on the portrait, you get a deeper look into my mind. So I’m particularly proud of this part of the code because it took some time learning how to do it by searching questions and the keyword functions like the function mousepressed and random, and what I needed to equal them with for the function to work, on Google, and watching multiple tutorials, especially from “The Coding Train” like these:

https://youtu.be/POn4cZ0jL-o?si=yuoXE6cM294Seczd

 https://www.youtube.com/watch?v=Bn_B3T_Vbxs 

At one point, I was confused about why words were still appearing in the background. I later realized this was because I left the background in the setup function instead of the draw function, which caused text from previous frames to accumulate on the canvas rather than being cleared each frame.

For future work, I would like to be more accurate with the positioning of things, add smoother animations, and create more interactive elements to further express more emotion and movement.

Week 1 – Self Portrait

Concept:

I dove into the assignment blind, no initial sketches or anything as such, instead of conveying an idea through the portrait beyond simply portraying myself, I thought it would be fun to try to implement other features of p5js into it, which lead to us having a color changing shirt, moving clouds and automatic blinking animation!

Implementation:

Honestly I did not sure on how to make my curly hair, at first I thought I could use the curve() function of p5.js to maybe simulate “curl” layers over a circle layer on the head. However it did not turn out realistic whatsoever, so my next step was to first add a rectangular layer behind the head, (besides the forehead part where I added a small rectangle on top of the forehead so that it looks like the hair is covering). I then added a bunch of circles centered inside the hair layer so that it looks like curls on top of my head, there was an emoji I used as reference actually and it was this: 👨‍🦱, not exactly the same however I took the top part of the hair as reference.

// hair
fill(0);
noStroke();
rect(210, 50, 180, 80);
circle(220, 60, 30);
circle(220, 80, 30);
circle(220, 100, 30);
circle(220, 120, 30);
circle(240, 50, 30);
circle(260, 50, 30);
circle(280, 50, 30);
circle(300, 50, 30);
circle(320, 50, 30);
circle(340, 50, 30);
circle(360, 50, 30);
circle(380, 60, 30);
circle(380, 80, 30);
circle(380, 100, 30);
circle(380, 120, 30);

// face
noStroke();
fill(223, 170, 139);
ellipse(300, 150, 175, 200);

// hair over face
fill(0);
rect(236, 50, 125, 20);

Next is the automatic blinking, there is 3 variables that are used for this process, lastblink, blinkInterval and the boolean blinking. The way the logic works is that I use the in built function millis(), and what this does is keep track of how much time has passed since the sketch started running, using that we can subtract our last blink and check if it is greater than our blink interval, so here I use that so the blink interval is 3 seconds, so when the sketch start running lastblink is going to be 0, so when millis reach 3001 milliseconds we get 3001-0 which is greater than 3000, meaning it is time for the character to blink, this sets blinking to true which “disables” the eye and pupil code giving the illusion of blinking. However we want the character eyes to open up after a bit so we use setTimeout() which waits a certain time we set before executing a command, so here we wait  300 ms / 0.3 seconds before setting blinking to false and opening up the character’s eyes.

let lastBlink = 0;
let blinkInterval = 3000; 
let blinking = false;

  // Check if time to blink
  if (millis() - lastBlink > blinkInterval) {
    blinking = true;
    setTimeout(() => blinking = false, 300); 
    lastBlink = millis();
  }

  // eyes and pupils
  stroke(223, 170, 139);
  strokeWeight(2);
  if (!blinking) {
    fill(255);
    ellipse(260, 125, 50, 40);
    ellipse(335, 125, 50, 40);
    noStroke();
    fill(0);
    circle(260, 125, 15);
    circle(335, 125, 15);
  }

The color changing shirt logic is pretty simple, for smooth transition I use sin on our shirtcolor variable, sin goes between -1 and 1, however rgb takes from 0 to 255, so we multiply by 127 to get -127 and 127 and then add 128 to this to get a range from 0 to 255, for r we just use sin of colorshirt, for g and b we delay the sin by two_pi  / 3 and 2*two_pi / 3, and finally we add 0.03 every time draw runs to shirtcolor.

let shirtcolor = 0;
  // shirt color changing
  let r = 128 + 127 * sin(shirtcolor);
  let g = 128 + 127 * sin(shirtcolor + TWO_PI / 3);
  let b = 128 + 127 * sin(shirtcolor + 2 * TWO_PI / 3);
  shirtcolor += 0.03;

  // shirt
  noStroke();
  fill(r, g, b);
  rect(200, 290, 200, 250);

The final thing that is worth mentioning is the cloud movement in the background, I use a function that takes in the x, y and s (where s is set to 1 unless specified otherwise), and draw our cloud using an ellipse with the parameters we put. I initialize 14 different “clouds” with different x,y and s values in an array, now to draw and move the clouds, I use a loop to move through the cloud array and call the drawCloud function that draws each cloud, then to move it along the background, I add 1 to every cloud’s x value in the loop and to make the clouds move up and down add the value of sin(shirtcolor) to the y value of each cloud, since shirtcolor constantly changes it’s a good variable to use in this case. Finally to make sure the clouds wrap back, we check if the x value of each cloud has went past the width of canvas by 25 pixels or not, if it has we set the x value to -50! This gives the illusion of clouds wrapping around without them “disappearing” from one side and “appearing” at the other.

let clouds = [];
clouds = [
    {x: 80, y: 80, s: 1},
    {x: 200, y: 60, s: 1.3},
    {x: 350, y: 90, s: 0.9},
    {x: 500, y: 70, s: 1.2},
    {x: 120, y: 140, s: 0.8},
    {x: 300, y: 160, s: 1.1},
    {x: 450, y: 140, s: 0.7},
    {x: 80, y: 200, s: 1},
    {x: 200, y: 260, s: 1.3},
    {x: 350, y: 290, s: 0.9},
    {x: 500, y: 270, s: 1.2},
    {x: 120, y: 340, s: 0.8},
    {x: 300, y: 460, s: 1.1},
    {x: 450, y: 340, s: 0.7},
  ];

  // draw and move clouds
  for (let c of clouds) {
    drawCloud(c.x, c.y, c.s);
    c.x += 1;
    c.y += sin(shirtcolor)
    if (c.x > width+25) c.x = -50;
  }


function drawCloud(x, y, s = 1) {
  stroke(255);
  strokeWeight(1);
  fill(255);
  ellipse(x, y, 50 * s, 24 * s);
}

Overall code:

let shirtcolor = 0;
let clouds = [];
let lastBlink = 0;
let blinkInterval = 3000; 
let blinking = false;

function setup() {
  createCanvas(600, 550);

  // initialize clouds
  clouds = [
    {x: 80, y: 80, s: 1},
    {x: 200, y: 60, s: 1.3},
    {x: 350, y: 90, s: 0.9},
    {x: 500, y: 70, s: 1.2},
    {x: 120, y: 140, s: 0.8},
    {x: 300, y: 160, s: 1.1},
    {x: 450, y: 140, s: 0.7},
    {x: 80, y: 200, s: 1},
    {x: 200, y: 260, s: 1.3},
    {x: 350, y: 290, s: 0.9},
    {x: 500, y: 270, s: 1.2},
    {x: 120, y: 340, s: 0.8},
    {x: 300, y: 460, s: 1.1},
    {x: 450, y: 340, s: 0.7},
  ];
}

function draw() {

  // Check if time to blink
  if (millis() - lastBlink > blinkInterval) {
    blinking = true;
    setTimeout(() => blinking = false, 300); 
    lastBlink = millis();
  }
  // shirt color changing
  let r = 128 + 127 * sin(shirtcolor);
  let g = 128 + 127 * sin(shirtcolor + TWO_PI / 3);
  let b = 128 + 127 * sin(shirtcolor + 2 * TWO_PI / 3);
  shirtcolor += 0.03;

  // background
  background(178, 237, 232);

  fill(0);
  strokeWeight(1);
  text(`${mouseX}, ${mouseY}`, 20, 20);

  // draw and move clouds
  for (let c of clouds) {
    drawCloud(c.x, c.y, c.s);
    c.x += 1;
    c.y += sin(shirtcolor)
    if (c.x > width+25) c.x = -50;
  }

  // hair
  fill(0);
  noStroke();
  rect(210, 50, 180, 80);
  circle(220, 60, 30);
  circle(220, 80, 30);
  circle(220, 100, 30);
  circle(220, 120, 30);
  circle(240, 50, 30);
  circle(260, 50, 30);
  circle(280, 50, 30);
  circle(300, 50, 30);
  circle(320, 50, 30);
  circle(340, 50, 30);
  circle(360, 50, 30);
  circle(380, 60, 30);
  circle(380, 80, 30);
  circle(380, 100, 30);
  circle(380, 120, 30);

  // face
  noStroke();
  fill(223, 170, 139);
  ellipse(300, 150, 175, 200);

  // hair over face
  fill(0);
  rect(236, 50, 125, 20);

  // jaw and neck
  noStroke();
  fill(223, 170, 139);
  quad(224, 200, 377, 200, 340, 250, 260, 250);
  rect(260, 250, 80, 40);

  // shirt
  noStroke();
  fill(r, g, b);
  rect(200, 290, 200, 250);

  // eyebrows
  fill(0);
  stroke(0);
  noFill();
  strokeWeight(10);
  arc(265, 100, 25, 7, PI, -0.2);
  arc(332, 100, 25, 7, PI, -0.2);

  // eyes and pupils
  stroke(223, 170, 139);
  strokeWeight(2);
  if (!blinking) {
    fill(255);
    ellipse(260, 125, 50, 40);
    ellipse(335, 125, 50, 40);
    noStroke();
    fill(0);
    circle(260, 125, 15);
    circle(335, 125, 15);
  }

  // nose
  stroke(194, 132, 103);
  noFill();
  line(297.5, 150, 295, 170);
  line(302.5, 150, 305, 170);
  arc(305, 170, 10, 10, -0.5, PI / 2);
  arc(295, 170, 10, 10, PI / 2, PI + 0.5);

  // mouth
  fill(180, 13, 61);
  noStroke();
  arc(300, 200, 50, 50, 0, PI);

  // glasses
  stroke(0);
  noFill();
  ellipse(260, 125, 40, 30);
  ellipse(335, 125, 40, 30);
  line(275, 115, 320, 115);
  line(355, 125, 385, 130);
  line(240, 125, 210, 130);

  // ears
  stroke(194, 132, 103);
  fill(194, 132, 103);
  arc(385, 145, 30, 30, -PI / 2, PI / 2);
  arc(214, 145, 30, 30, PI / 2, -PI / 2);
}

function drawCloud(x, y, s = 1) {
  stroke(255);
  strokeWeight(1);
  fill(255);
  ellipse(x, y, 50 * s, 24 * s);
}

 

 

Reflection:

I am not a very artistic person so honestly I did not know how this would go, I did not know how I’d draw myself using just 2D shapes, and to be honest I did struggle, especially with the hair, however I am pretty happy with how it turned out, in the future I am hoping to be able to make more realistic animations, for example for the blinking animation maybe the animation of the eye slowly closing up and opening up would be a cool thing to experiment with and add. Maybe also a scene where my character is doing some sort of activity! I love wall climbing so something where my character is climbing would be cool to do in the future.