Week 1 Self Portrait- Sky

Concept:

For the very first assignment in Intro to Interactive media, I was able to make a 2D portrait of my own face which also included parts of my identity such as lifted eyebrows, bigger eyes and writing some parts about my identity such as being a polyglot from Thailand for the very first time using coding as I previously don’t have any previous experience in coding.

Below is my finished portrait:

Screenshot

http://<iframe src=”https://editor.p5js.org/po2127/full/E8eNn1n2a”></iframe>

How it’s made:

This portrait was made using p5.js functions using 2D shapes and different functions such as Fill, Elipse, Stroke, Strokeweight, noStroke, Circle, Arc and line, these basic functions help me have a good foundation of what I need to make a realistic face and to explore and add different more specific features such as eyebrows etc.

When I started it was pretty difficult as it took me quite a while to watch the 3 videos available on YouTube and the link provided to get a good basic grasp of the functions of this platform because I haven’t coded much before and which code I need to do to make the shape of each facial features compatible with the body.

Screenshot

I designed my face to be more of starting with face frame using fill and elipse with no stroke, then eye using ellipse, and the eyehole using fill and circle, then eyebrow using arc, and nose lines and more specifically far apart because my nose is more big, lip, hair and ear using arc and neck using lines and shirt using text and stroke.

Later on adjusting more specific details such as arc of lips and eyebrows to make it fit well with how I look and my body proportions or look like me was also another hard step.

As highlighted code I’m proud of:

The part I am proud of is I was trying to add different parts of my identity to my shirt such as giving purple theme and writing some things that really resonate with me and are part of my identity on the shirt and to be able to write design of NYU shirt on the portrait.

Screenshot

Reflection:

I enjoyed creating my  self portrait, alsthought hroguhout the journey I had some difficulties especially at positioning the shapes and getting used to how the gird works, I was able to get through and I think the main thing I struggled was when to apply the noStroke function and finding the right strokeWeight for specific places such as lips etc.

I think in the future what could have been better is after I get better and more used to program I can add some side effects such as animations, and different gimics into the portrait.  But overall, I think as the first work it was already pretty fun and I feel proud to create my first very own portrait.

Self Portrait

For my self portrait I decided to draw a zombie because I like zombies. I wanted it to look like something I might’ve drawn in MS Paint, so I played around with shapes and colors until it felt and looked right.

The part I’m most proud of is the hair and bangs, since I had to align the points and angles perfectly to the pixel to make it one big coherent shape and honestly it was incredibly painful to do.

 //bangs
strokeWeight(0)
fill('black')
arc(300,225,320,200,PI,0)
triangle(300,220,100,350,150,200)
triangle(280,220,270,400,350,200)
triangle(340,220,500,400,460,220)
triangle(200,220,100,500,150,240)
triangle(80,100,500,300,300,105)
triangle(380,126,550,245,460,240)

I didn’t have any help with this aside from a few tips from the p5 reference page. I just kinda figured things out as I went along. Because of this, there are some aspects of the code that probably could’ve been done more efficiently, so I’ll carry what I learned through trial and error here and apply it to my next project. I’m also thinking of having the colors in her eyes shift so that it looks like it’s spiraling. That’d be pretty cool I think.

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

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.