Week 1 – Self Portrait

My look-alike animal I chose to portray myself is an owl. It didn’t have to be an animal, but I chose it simply because I like cute animals. It was tough trying to pick between an owl and a raccoon, but I stuck with an owl because when I during my military service, my teammates called me “angry bird” because of my sharp-looking eyebrows. The fact that I was bold probably made it worse. I combined both “angry bird” and owl to create “angry owl”.

Simplistic, but straight to the point. I added 2 animations during my work on this project. Please feel free to find both of them.

I love working at night because it’s quiet and it’s the time of day when I feel most focused. So if you try to get the owl’s attention by clicking, it will lift its eyebrow as a warning. It’s a do-not-disturb signal.

//eyebrow only moves at night
 if (!morning && eyebrow) {
   move += direction * 1.2; //speed of animation

   if (move <= -20) { //moved distance is max 20, if greater, change direction to go down
     direction = 1;     
   }
   if (move >= 0) { //when it reaches its original position
     move = 0;
     eyebrow = false;   //stop animation
     direction = -1;    //reset direction
   }
 }

That is the animation code for the eyebrows. One of the hardest parts of this code was changing the direction of the movement. If the position changes by 20 pixels, then it changes the sign of the direction so that it goes in the opposite direction. It was also difficult to trigger the animation. I have two animations that are played in different conditions: night and day. So coordinating the timing was probably the most difficult part of coding. I will explain the coordinating part after showing the code for morning animation.

(Explanation of Code, Skip this if this is a bit boring)

move+= direction is for the speed of the animation. But the sign of the direction indicates whether it goes up or down. If the animation moves for 20 pixels upwards, it satisfies the first condition, and the sign is changed. It was set to -1 before. So now, the eyebrow moves downward back to its original position. Since the sign has flopped, move slowly turns positive as it goes through the move+=direction line. At some point, it will reach 0, where the variable named eyebrow, which is set to true when the user clicks on the owl, turns false, and the direction changes to positive.

As you could guess, if you click on the moon, it changes the time of day. Also, if you click on the owl during the day, it will show the ZZZ animation.

function mousePressed() {
  //if position of sun/moon is pressed
  if (dist(mouseX, mouseY, X, Y) <= D) {
    //change day/night
    morning = !morning;
    //stop eyebrow
    eyebrow = false; move = 0; direction = -1;
    return;
  }

  // start Z animation in morning
  if (morning) {
    zActive = true;
    zStart = millis();
    return; // don't trigger eyebrows
  }

  //night means eyebrows haha
  if (!eyebrow){
    eyebrow = true;
  } 
}

I used two flags to trigger the animation: zActive and eyebrow. I set these values to true when the screen was clicked based on the time of day. I also had to carefully coordinate so that the flags were triggered where I wanted them to be.

(Explanation of Code)

When the mouse is pressed, it first checks if the user clicks on the area where the sun and moon are placed. If it is, then moring = !morning changes from day to night, vice versa. When the time of day changed, I made sure once again to reset variables just in case the animation plays. Now, if that was not the case, and the user clicks, it checks if it is morning or night. If it is morning, the zActive variable is set to true, and this sets off the ZZZ animation. If it is not morning, then it sets the eyebrow flag to true, which triggers the eyebrow animation. Figuring out this logic was probably the most difficult part of the code.

Finally, this is my ZZZ animation. 

/ZZZ animation
if (morning && zActive) { //only when morning and user clicked
  const elapsed = millis() - zStart; //measure time

  //number of Zs
  let visible = 0;
  if (elapsed >= 0){
    visible = 1;
  }
  if (elapsed >= 300){ //basically every 300ms, add one
    visible = 2;
  }
  if (elapsed >= 600){
    visible = 3;
  }

  ZZZ(width/2 + 70, height/2 - 120, visible);

  // after all Zs have appeared and held, hide all at once
  if (elapsed >= 3 * 300 + 600) { //600 is extra time just in case
    zActive = false; // disappears together
  }
}

I used millis(), which is used to measure the timing of animation. I wanted the Zs to play out one by one, so I had to time them by 300ms. The logic here is quite straightforward. 

function ZZZ(x, y, count) {
  noStroke();
  fill(0);                
  textAlign(LEFT, BASELINE); //aligns text to left and at baseline of font
  
  if (count >= 1) {
    textSize(20); 
    text('z', x, y); 
  }
  if (count >= 2) { 
    textSize(24); 
    text('z', x + 12, y - 12); 
  }
  if (count >= 3) { 
    textSize(28); 
    text('z', x + 28, y - 26); 
  }
}

This is the helper function to create the ZZZ effect. visible and count shows how many Zs are present, and it is incremented with time elapsed, measured with the millis function. Any further explanation of the code can be provided in class. 

For improvements, I was thinking about adding another condition. For now, when the owl is disturbed, it just repeats the animation. However, adding another animation when the owl is disturbed more than 10 times might be interesting. Owl spreading its wings and flying away sounds good. 

P.S. I was scrolling through the posts and found a post that is quite similar to mine (haha), although the contents were totally different. It was nice to see a fellow owl.

Self Portrait – Guli

https://editor.p5js.org/Guli/full/cmL7dFMrF

Our hometask for the first week was to create a self portrait to practice using the simple drawing functions in p5js. For the assignment, I had an idea to use my avatar in Duolingo as a refernce. I really liked my Duolingo avatar — the colors, the shape, and the style, thus recreated it while adding more ideas.

The colors in the avatar are yellow for the background and orange for the dress. The avatar has smiling eyes that are curved at the bottom, along with sparkles. For the body, I simplified the design by making the head float, rather than directly being attached to the body. The idea of a floating head came from one of my chilhood cartoons Phineas and Ferb.

The curls and the curious expression with sparkles in the eyes are the highlights of the portrait. I am proud of myself for thinking off using human face color circles under the eyes to give the impression of smiling eyes. Drawing the curls also proved to be not a straightforward task, with me adjusting and readjusting the position and size of each brown circle untl  achieved the look I wanted.

In my future works, I could make the design interactive, so the art changes color or moves as the viewer comes into contact with the work. In terms of the design itself, I can use codes like arc() and  rotate(), adding more creativity to the work.

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

function draw() {
  background(255, 241, 167); // yellow bg

  // Face --------------------------------------------------->
  fill(255, 226, 214); // face color
  rect(200, 120, 200, 150, 40); // face shape
  
  
  // Eyes --------------------------------------------------->
  fill("white"); 
  ellipse(width/2 - 40, height/2 - 20, 75, 70); // left eye
  ellipse(width/2 + 40, height/2 - 20, 75, 70); // right eye

  // Pupils
  fill(61, 61, 61); // dark pupil
  ellipse(width/2 - 40, height/2 - 20, 45, 45); // left
  ellipse(width/2 + 40, height/2 - 20, 45, 45); // right

  // Blue part of pupil
  fill(57, 94, 130, 200); 
  ellipse(width/2 - 40, height/2 - 10, 35, 30); // left
  ellipse(width/2 + 40, height/2 - 10, 35, 30); // right

  // Sparkles
  drawSparkle(width/2 - 35, height/2 - 27, 15); // left eye sparkle
  drawSparkle(width/2 + 35, height/2 - 27, 15); // right eye sparkle

  // Under-eye curves 
  fill(255, 226, 214); 
  ellipse(width/2 - 40, height/2 + 20, 90, 60); // left
  ellipse(width/2 + 40, height/2 + 20, 90, 60); // right

  // Nose --------------------------------------------------->
  fill(248, 172, 148); // nose color 
  beginShape(); 
  vertex(width/2, height/2 - 10); // top 
  vertex(width/2 - 7, height/2 + 10); // left 
  vertex(width/2, height/2 + 17); // bottom 
  vertex(width/2 + 7, height/2 + 10); // right 
  endShape(CLOSE);

  // Mouth --------------------------------------------------->
  fill(179, 93, 110); // lip color
  ellipse(width/2, height/2 + 45, 20, 20); // lip position
}

// sparkle in the eye function ---->
function drawSparkle(cx, cy, size) {
  fill("white"); // sparkle color
  quad(
    cx, cy - size/2, // top
    cx + size/2, cy, // right
    cx, cy + size/2, // bottom
    cx - size/2, cy  // left
  );
  
  // circular sparkle
  fill("white"); // circle sparkle color 
  ellipse(width/2 - 50, height/2 - 15, 8); // left 
  ellipse(width/2 + 50, height/2 - 15, 8); // right
  
  // HAIR --------------------------------------------------->
  fill(84, 54, 41); // hair color
  // Top
  ellipse(width/2, height/2 - 120, 120, 90); // top middle
  ellipse(width/2 + 60, height/2 - 115, 110, 85); // top right 
  ellipse(width/2 - 60, height/2 - 115, 110, 85); // top left 

  // Left 
  ellipse(width/2 - 120, height/2 - 60, 90, 100); // left top 
  ellipse(width/2 - 140, height/2 + 10, 95, 110); // left bottom 
  

  // Right 
  ellipse(width/2 + 120, height/2 - 60, 90, 100); // right top 
  ellipse(width/2 + 140, height/2 + 10, 95, 110); // right bottom 
 

  // BODY --------------------------------------------------->
  fill(243, 161, 63); 
  ellipse(width/2, height - 10, 170, 200); // body position 
}

 

 

CONCEPT:
For this assignment, I built a self-portrait entirely out of shapes in p5.js. I wasn’t trying to make something realistic, instead, I went for a cartoon version of myself: a round face, messy hair, glasses, and a simple smile. The idea was to see how much “me” I could get across with just ellipses, arcs, and lines. The output is far from realistic; come on, I am not trying to replace my passport photo with this. The portrait is simple, but I like how it balances between looking generic and still recognizably like me.

HIGHLIGHTED CODE:
The glasses ended up being my favorite part. Without them, the face felt empty, but adding two circles and a line suddenly made it feel right:
  noFill();
  stroke(0);
  strokeWeight(3);
  ellipse(167, 170, 60, 60);
  ellipse(233, 170, 60, 60);
  line(200, 170, 200, 170); // bridge

REFLECTION AND FUTURE WORK:
This was my first attempt at drawing myself, and that too using code; and it showed me how powerful even basic shapes can be. It doesn’t need shading or complex details to read as a face, and luckily identify a person if the components are placed right.

However, if I had more time, I’d like to:
– Make the eyes blink or move with the cursor (saw many do that, i can’t just yet)
– Give the background more personality
– Fix the hair so it looks less like a helmet and more like actual messy hair (pretty doable with multiple ellipses but i reckon there are more efficient ways)
Even with its simplicity, I like how it turned out, it’s definitely not a mirror image, but it’s “me” enough.