SELF PORTRAIT

For this assignment, I decided to do a simple portrait as it was my first time coding. However, I did want to play around with the background and try new codes, so I decided to do a background that changes color at random when you toggle around the mouse. At first, I thought it was too hard, and it took me time to figure out the codes, but I watched some tutorials on YouTube and went over the presentations in class, and I finally figured it out and was definitely proud of the outcome. I honestly found it difficult to figure out the shapes and where everything goes, but the Mouse X and Y function was a lifesaver, and it was a matter of getting the hang of it. The hair, however, was my least favorite part as it was getting really confusing with the placements of each circle. Maybe there was an easier way instead of just repeating each circle in a different location, so hopefully, I will figure it out in the future. Overall, after a long process of figuring out each shape, size, and code I’m happy with the outcome.

here is the background code which I am most proud of:

let x, y, r, g, b;

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

function draw() {
  // background that changes color
  background(mouseX, mouseY, 100, 7);
  r = random(0, 255);
  g = 0;
  b = random(0, 255);
  x = random(0, 600);
  y = random(0, 400);
  noStroke();
  fill(r, g, b, 100);
  circle(x, y, 24);

here is my portrait!

here is the code:

let eyeRX = 170;
let eyeLX = 225;
let speed = 15;
let x, y, r, g, b;

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

function draw() {
  // background that changes colour
  background(mouseX, mouseY, 100, 7);
  r = random(0, 255);
  g = 0;
  b = random(0, 255);
  x = random(0, 600);
  y = random(0, 400);
  noStroke();
  fill(r, g, b, 100);
  circle(x, y, 24);
  print(mouseX + "," + mouseY);

  //neck
  fill(240, 190, 120);
  stroke(0, 0, 0);
  strokeWeight(1);
  rect(200, 280, 70, 150, 100);

  //   left ear
  fill(240, 190, 120);
  stroke(0, 0, 0);
  strokeWeight(1);
  circle(135, 177, 25);

  //   right ear
  fill(240, 190, 120);
  stroke(0, 0, 0);
  strokeWeight(1);
  circle(264, 177, 25);

  // face
  fill(240, 190, 120);
  stroke(0, 0, 0);
  strokeWeight(1);
  ellipse(200, 160, 125, 185);

  //nose
  noFill();
  arc(199, 183, 20, 15, 270, 90);

  // hair
  noStroke();
  fill(46, 28, 17);

  //  top hair
  circle(140, 60, 40);
  circle(183, 95, 40);
  circle(205, 88, 40);
  circle(160, 100, 40);
  circle(170, 50, 40);
  circle(200, 40, 40);
  circle(230, 50, 40);
  circle(233, 94, 40);
  circle(260, 60, 40);

  // More top curls
  fill(46, 28, 10);
  circle(160, 80, 40);
  circle(190, 70, 40);
  circle(220, 70, 40);
  circle(250, 80, 40);

  // Left side curls
  fill(46, 28, 17);
  circle(130, 90, 40);
  circle(120, 120, 40);
  circle(134, 135, 40);
  circle(142, 113, 40);

  // Right side curls
  fill(46, 28, 17);
  circle(270, 90, 40);
  circle(280, 120, 40);
  circle(262, 134, 40);
  circle(256, 115, 40);

  // eyebrows
  stroke(21, 19, 19);
  strokeWeight(2);
  noFill();
  arc(170, 135, 30, 10, PI, TWO_PI);
  arc(225, 135, 30, 10, PI, TWO_PI);

  //right eye
  fill(255);
  ellipse(eyeRX, 150, 20, 20);

  //left eye
  fill(255);
  ellipse(eyeLX, 150, 20, 20);

  //right pupil
  fill(51, 0, 0);
  ellipse(eyeRX, 150, 10, 10);

  //left pupil
  fill(51, 0, 0);
  ellipse(eyeLX, 150, 10, 10);

  //  mouth up
  strokeWeight(1);
  fill("pink");
  rectMode(CENTER);
  arc(200, 209, 30, 15, PI, 0);

  //   mouth down
  strokeWeight(1);
  fill("pink");
  rectMode(CENTER);
  arc(200, 209, 30, 15, 0, PI);

  //   lip line
  arc(200, 210, 27, 1, 0, PI);

  //shirt
  fill(126, 167, 189);
  noStroke();
  rect(200, 380, 199, 200, 50);

  //   shirt neck line
  fill(240, 190, 120);
  noStroke();
  arc(200, 280, 90, 80, 0, PI, CHORD);

  //   short neck shadow
  noFill();
  strokeWeight(8);
  stroke("#212E2D");
  arc(200, 280, 90, 80, 0, PI);

  noStroke();
  fill(64, 102, 122);
  triangle(128, 315, 135, 400, 150, 400);
  triangle(265, 315, 267, 400, 250, 400);
}

 

Week 1: Self – Portrait

My Concept:

As the first assignment, I thought to keep things simple but also to add some personality into it. The background is a beach. One thing about me is that I absolutely cannot tolerate the beach – it is one of those outings I just cannot stand and enjoy. So as I started to create this piece, I thought to implement that (which is why I look so unhappy haha)

In terms of code, I decided to include some user interactivity. If you do click on me, then I end up blushing for as long as you press on the mouse.  I was quite happy with this part of the code because it took me some time to decide on what particular user interactivity I wanted.

// BLUSH
if (mouseIsPressed) {
  fill('pink');
  ellipse(460, 400, 40, 40); // blush on the right cheek
  ellipse(300, 400, 40, 40); // blush on the left cheek
}

Reflection:

This first assignment was quite an enjoyable one, because I liked getting the opportunity make something both creative and having a technical element into it. I suppose the most time consuming thing was editing the circles for the eyes and pupils, deciding where exactly they go and their sizes. I think this assignment helped me to have a solid understanding in how p5.js operates. I had hit a wall when I was drawing the hair on the character. It just looked awkward, especially as there was none present at the forehead, hence I decided to give her a fringe. If I had another opportunity, perhaps I would elevate the work by adding facial expressions and adding some text.

Week 1 – Self-Portrait: The Sword of Damocles

Intro

Sometimes I wonder if there is indeed some force behind coincidence – especially when those coincidences are of my favorability.

Right before I set off for my adventurous journey to Abu Dhabi, I visited an exhibition in Shanghai, in which a collection of portraits and self-portraits were borrowed from Centre Pompidou. From those who devoted their efforts to whether capture the subject faithfully or replicate their physical appearance to those who indulged their artistic preference, streaks of character, habits, and egos into the paints, the portraits collectively reminded me of that recurrent theme in every art form, I presume – the tension between the art and the artist. Aside from the cliche saying from Oscar Wild (although his definitive statement is, even for an ambivalent person like I am, attractive enough), I would stick to leaving the answer for now.

On the other hand, even if I cannot answer the big question for now (and, in fact, it could be forever), I can indeed establish a bit of myself under this daunting siding game. One of my takeaways from my first acting class today is that as a narrator, despite our habits of storytelling and the eventual manner we picked, it is our responsibility to Stay True in terms of this present moment, the soul of our story. I’ll not delve into the other takeaway of being courageous to leave others the right to tell our stories for now but make use of the first one promptly.

That being said, when it comes to composing my own self-portrait, which I’ve never tried, I’d be glad to take full responsibility for representing myself at this moment. To me, this is something that demands great courage as well. Looking back at how I could probably gain this courage, I’d say it’s the fact that I, at the end of the day, tried to admit the lack of it for so many years – from representing myself, playing music, to speaking up when I’d love to, dealing with interpersonal relationships, and to live and love, had brought me that serenity and tranquility to seeking for courage. It seems for many of us, at least many people I know, as soon as the concept of being courageous and brave was instilled into our heads, we started to self-exert as well as receive external expectations to “be courageous and brave” right away. And simply, it is impossible. It is impossible to develop that true courage and bravery by merely being told how a courageous person would possibly behave instead of honing oneself step by step and again and again in this world of reality.

Product Concept

Despite my rationale (or more of like my self-prep talk), it’s time to tackle the problem (if not the question), and I’ll try to put it as plainly as possible. At this moment, I’d be willing to conceptualize myself into a set of symbols, figures, or whatever you may call some figurative representations that could be found in real life. Although I could make a list of the symbols I’m about to include in this portrait right here, I’d like to leave it till the end and see if my conceptualization and abstraction make sense to you.

Nevertheless, the overall concept is MEs versus an ideological black hole that I’ve found as the Sword of Damocles in my life. That being said, whenever the mouse is pressed, my hovering incarnations in this blended world of 2D and 3D shapes will initiate their attack toward the black hole despite their shaky, timid, and hyped state, setting off on a journey with no way back.

Technically speaking, my using 2D shapes as my personal representatives while letting the black hole be 3D results from the simple attempt to utilize both 2D and 3D drawing/shaping functions somewhere around this project (plus, it would be quite time-consuming if I used basic 3D shapes to abstract the symbols I’d like to include). However, I can indeed also justify this choice in terms of its symbolic connotation. To reflect the nature of this colossal hazard, bain of insecurity, and ineffable abyss that lies completely out of my mortal control, I placed the threat one dimension higher than myself.

Metaphorically, MEs’ attacking the black hole embodies the courage I’d like to attain despite what comes next. As for the ending of this one-act play, maybe it’s MEs’ begone from this world? Or maybe it’s MEs entering a brand-new universe. At least if the black hole could be gone from this particular universe, it would be a happy ending for both me and the rest.

coding highlight

Despite the fact that I was not familiar with js, I would self-reckon as someone who is used to product-oriented coding; in other words, I tried to utilize as much as possible at this moment from the source to get to my ideal product as closely as possible. Although, from time to time, this mindset could lead me to a hasty organization and poor-looking codes, I do believe it’s beneficial for me to realize (at least part of) my vision quickly.

In this product, I took the black hole as a starting point. While calling the function shpere() is rather an easy deal, it did take me some time to figure out how to maintain both 2D and 3D shapes on the same canvas. The answer turned out to be using push()/pop() to create an individual drawing group. Another takeaway is the general approach to creating animation with p5js – thinking from a perspective of frame generation, specifying the animation frame by frame. And this led me to use variables to store the current status and then update the variables to achieve animation (see the usage of rotateX()/rotateY()). On top of that, to add texture() to the sphere, I tried with loadImage() in the preload() function (and thus used an image as the background as well).

*: all image files used in this project are generated with DALL-E3

// draw the sphere with texture
function blackhole() {
  // Increment the rotation angles
  angleXrotate += 0.005; // Adjust the speed by changing this value
  angleYrotate += 0.005; // Adjust the speed by changing this value

  push(); // save the current state
  
  translate(0, -200, 0); // translate the coordinate system temporarily to place the sphere
  
  rotateX(angleXrotate); // Rotate around X-axis
  rotateY(angleYrotate); // Rotate around Y-axis
  
  texture(imgBlackhole); // adding texture to the sphere
  
  stroke('white'); // contour the sphere
  strokeWeight(0.25);
  
  sphere(100); // placing the sphere on the canvas with r = 100
  
  pop(); // return to the previous state

}
let imgBlackhole; // variable to hold image texture for the sphere
let imgUniverse; // variable to hold image for the background

function preload() {
  // load image files
  imgBlackhole = loadImage('blackhole.jpg');
  imgUniverse = loadImage('the universe.jpg');
}

As for the ME representatives, I break it down into two parts: the static drawing and the animation. Initially, I adopted the animation approach mentioned in the black hole section, only used functions to hold the drawing operations and called them in the draw() function. However, as my drawings are rather complex (although they have abstract appearances), I found that the code performance had started to decline. Therefore, I reorganized the code by placing the drawings into p5.Graphics object (that provides a dedicated drawing surface), in order to improve efficiency. This also enabled me to process the objects individually as a whole later on. Following is one example of my utilizing p5.Graphics object to draw an abstract guitar.

function drawGuitar() {
  let c = color('#bd6d36');
  let c1 = color('#592c0e');
  let c2 = color('#814116');
  
  // Create a graphics object guitar
  guitar = createGraphics(100, 150);

  // Draw to the graphics object guitar
  // Body of the guitar
  guitar.fill(c); // Brown color
  guitar.noStroke()
  guitar.beginShape();
  guitar.vertex(25, 100); // Start at bottom left
  guitar.bezierVertex(10, 75, 10, 50, 25, 25); // Left curve
  guitar.bezierVertex(75, 0, 75, 50, 25, 25); // Right curve
  guitar.bezierVertex(90, 50, 90, 75, 25, 100); // Bottom curve
  guitar.endShape(CLOSE);

  // Neck of the guitar
  guitar.fill(c2); // Mid-dark brown color
  guitar.rect(25, 5, 8, 80); // Neck
  
  // Sound hole
  guitar.fill(c1); // Dark sound hole
  guitar.ellipse(25, 50, 10, 25); // Draw sound hole

  // Strings
  guitar.stroke('white'); // White color for strings
  guitar.strokeWeight(1);
  for (let i = 0; i < 6; i++) {
    guitar.line(25 + 2 * i, 0, 25 + 2 * i, 60); // Draw strings
  }
  
}

That being said, as I started working on the animation for MEs, p5.Graphics objects made it easier for me to instantiate them in class in order to define different behaviors (aka. hovering around the mouse and attacking the black hole). While I will not delve into every function I wrote for the MEs, I would like to briefly outline its operation logic. As the centerpiece, a class called Hoveringme includes six variables as parameters and two methods. The X/Y variables are used to track the relative coordinate of the object to the mouse and its absolute coordinate on the canvas. The show() method is my version of the draw() function for this particular class and will be called in the draw() function in every frame. The attack() method only updates the instance status (whether it’s ‘hovering’ or ‘attacking’), which, as a condition, determines the exact operation in the show() method.

// the hovering MEs' class
class Hoveringme {
  constructor(relativeX, relativeY, shape, status) {
    this.relativeX = relativeX;
    this.relativeY = relativeY;
    this.shape = shape;
    this.status = 'hovering';
    this.displayedX = 0
    this.displayedY = 0;
  }
  
  // show the MEs
  show() {
    push();
    /*
    ...
    */
    pop();
    
  }
  
  // ME to attack the blackhole
  attack() {
    this.status = 'attacking';
    
  }
  
}

Just to add a bit about my animations, which are broken down into two statuses as mentioned. First, the hovering status includes random() in the coordinates added on mouseX/Y

if (this.status === 'hovering') {
      // Update the ME's position around the mouse
      this.displayedX = mouseX + this.relativeX + random(-10, 10) * 0.05; 
      this.displayedY = mouseY + this.relativeY + random(-10, 10) * 0.05; 
      
    }

On the other hand, to achieve the attacking effect, the mouseX/Y has to be excluded (otherwise, the translation/movement of the object will always be relative to the mouse’s position).

else if (this.status === 'attacking') {
      let spherePosition = createVector(0, -200, 0); // Sphere's position
      let targetX = spherePosition.x + width / 2; // Sphere's X position in 2D
      let targetY = spherePosition.y + height / 2; // Sphere's Y position in 2D
      
      // Update the ME's position towards the target
      this.displayedX += (targetX - (this.displayedX)) * 0.05; // Move towards target X
      this.displayedY += (targetY - (this.displayedY)) * 0.05; // Move towards target Y
}

The other part of the attacking process is to decide if the object has collided with the black hole and, if so, remove it from the canvas. I achieved this by holding all ME instances in an array and then, when needed, removing them along with removing elements from the array (splice ()). (For clearer demonstration, I’ve also placed the instantiating function callingme() here.) In fact, whenever the code deals with the instances, it accesses them by calling the first item in the array objectsme.

let objectsme = []; // array to hold ME graphics objects

// create ME instances, add to array objectsme, and create graphics objects
function callingme() {
  guitarObject = new Hoveringme(20, 20, 'guitar');
  racketObject = new Hoveringme(-40, -60, 'racket');
  rectObject1 = new Hoveringme(-70, -10);
  rectObject2 = new Hoveringme(-80, 90);
  rectObject3 = new Hoveringme(60, -60);
  objectsme.push(guitarObject, racketObject, rectObject1, rectObject2, rectObject3); 
  drawGuitar();
  drawRacket();
 }

// in Hoveringme.show() method
if (((this.displayedX - targetX)**2 < 200) & ((this.displayedY - targetY)**2 < 200)) {
   objectsme.splice(objectsme[0], 1);
}

reflections, and so on

I would say I’m quite satisfied with this production for now, whether in terms of technical tryouts or basically achieving my message-conveying intention. Still, there is much room for improvement – both technically and beyond. I could have tried with more 3D features, alpha channel, typography, etc. I could have also designed a better disappearing for the black hole when MEs had made the attacks. But overall, I believe this is quite an interesting exploration.

Continue reading “Week 1 – Self-Portrait: The Sword of Damocles”

Self-Portrait: Me Meme

My idea was creating a portrait of myself with some simple and fun interaction. After looking online, I saw that eye movement is quite common and flexible. I was thinking about which type of movement I should implement when I remember a meme that is quite popular on the internet:

I'm the creator of the meme: "Awkward Look Monkey Puppet". Is it possible to sell it as NFT? : r/ethtrader

The awkward monkey meme

I decided to use interaction in p5js to depict the eye movement. When the cursor is far away from the face, the eyes will be looking towards the left, when the cursor is near, the eyes will look away (like when you just did something wrong and someone look at you).

To implement this in programming, I calculate the distance between the cursor and the center of the face. If the distance is smaller than the radius, the eyes movement is triggered.

if (distance < 90){
  eyePositionLeft = 230;
  eyePositionRight = 280;
} else{
  eyePositionLeft = 210;
  eyePositionRight = 262;
}

For the rest of the portrait, I use circle, ellipse, line and rect to draw a simplified version of myself. Here is the final version:

Reflection

Because I am used to using graphic software with a wide range of shapes and tools, drawing with p5.js initially felt limiting. However, I rather enjoy the challenge of using only a limited number of shapes and seeing what I can create with them. I also enjoy planning the interactivity I could incorporate, which is a different experience compared to drawing with graphic software.

 

Assignment 1 – Self Portrait

For this self portrait I was inspired by the art style of Toca Boca, a mobile video game I used to play a lot as a kid. So I attempted to create myself in that art style.

 Highlighted Code:
I am proud of this code because I originally was worried with how I would create the hijab, but I ended up simply creating a circle and making the “head” above it. Even though it’s just 2 circles on top of each other, I’m glad I found a simply solution.

//hijab
fill('#523F2D');
circle(width/2,height/2,270);

Reflection:

I’m happy with the final result, when starting I thought I wouldn’t be able to create what I envisioned. I did want to add some hair, and I tried with arc using HALF_PI but with the hijab it didn’t work so I scratched that idea. I think for future assignments I want to try to make my work interactive.