[Assignment 1] Self Portrait


For this assignment, I created a self-portrait using p5js. Various shapes (ellipses, triangles, arcs, and splines) were used to make a portrait of myself. This project contains a user interactive feature, in which the color wheel behind the portrait rotates as cursor moves. Not to mention, once the cursor rotates fast enough, color wheels will begin to randomly change for 2 seconds. Thick lines (strokes) and vibrant colors are used to make this portrait appear like a pop art piece.


Writing codes for the hairs was the most challenging part of this project. To draw my hair, I had to read through the p5js reference page (https://p5js.org/learn/curves.html). In the end, I used spline lines to make custom shapes. A considerable amount of time was used to draw even a single spline line because it required coordinates of all points it passes through.

Code for hairs using spline lines:
//Left part of the hair
curveVertex(314, 192);
curveVertex(314, 192);
curveVertex(302, 215);
curveVertex(292, 250);
curveVertex(222, 255);
curveVertex(227, 205);
curveVertex(247, 180);
curveVertex(277, 160);
curveVertex(307, 155);
curveVertex(327, 163);
curveVertex(327, 180);
curveVertex(324, 188);
curveVertex(314, 192);
curveVertex(314, 192);
//Right part of the hair
curveVertex(324, 185);
curveVertex(324, 185);
curveVertex(326, 175);
curveVertex(337, 170);
curveVertex(366, 177);
curveVertex(374, 198);
curveVertex(375, 225);
curveVertex(372, 232);
curveVertex(362, 210);
curveVertex(347, 200);
curveVertex(324, 185);
curveVertex(324, 185);

Another challenge I confronted while working on this project was the translation and rotation of reference points (axis). I translated the origin from the top-left corner to the center of my canvas because color wheels had to rotate around the portrait at the center. Yet, I noticed return values of mouseX and mouseY are not affected by the translation; therefore, I had to manually adjust cursor coordinates as shown below:

let mouseVecCurrent = createVector(mouseX - 300, mouseY - 300);

I expected rotate() to simply rotate objects without altering the axis, but p5js uses a rotation matrix, which means the whole axis will rotate with the object. For this reason, I had to reset the reference point before drawing any shapes:

rotate(radians(350)); //Reset the reference point

To create a responsive color wheel, I had to write several lines of code that calculate the position and rotational speed of the cursor. To do this, I compared current position and previous position of the cursor (pWinMouseX and pWinMouseY are functions that return cursor position in the previous frame). Then, I wrote some conditional statements to determine if the color should change based on the calculated rotational speed.

let mouseVecCurrent = createVector(mouseX - 300, mouseY - 300); //Vector holding current mouse position
let mouseVesPrev = createVector(pwinMouseX - 300, pwinMouseY - 300); //Vector holding previous mouse position

let mouseAngle = mouseVecCurrent.heading(); //Angle of mouse pointer relative to the origin
let mouseAngularV = 9 * abs(mouseAngle - mouseVesPrev.heading()); //Angular velocity of the cursor

//If cursor is rotating rapidly enough around the origin, set colorChange to true. OR, if colorChange is already and it has not been 2 seconds since the last rapid rotation, keep colorChange as true.
if (mouseAngularV > 53 || (colorChange && millis() - t < 2000)) {
if (!colorChange) { //If colorChange is false, set t to current millis time.
t = millis();
colorChange = true;
}else colorChange = false;

With the help of trigonometry and cursor information, I made color wheels that follow the cursor using triangles. The triangles were placed using for loop and their colors were randomly assigned using random()  function.

for (let i = 1; i <= divNum; i++) {
fill(i * 10 + 70, 3 * i + 125, 5 * i); //Default color regardless of the cursor movement.
if (colorChange) fill(random(255), random(255), random(255)); //If colorChange is true, wheel colors will totally be random for 2 seconds.
700 * cos(((i - 1) * 2 * PI) / divNum + mouseAngle),
700 * sin(((i - 1) * 2 * PI) / divNum + mouseAngle),
700 * cos((i * 2 * PI) / divNum + mouseAngle),
700 * sin((i * 2 * PI) / divNum + mouseAngle)

Reflections / Future Improvements

Although I faced some challenges making this self-portrait, the project was very fun and exciting to work on. My portrait may not be perfect, but I am very satisfied with the project and willing to continue working on more intricate codes in this course.

In the future, I would like to write a piece of code that will open and close the mouth when the cursor is clicked. Adding a portion of my upper body that can interact with user input may also be interesting improvements to make in the future.

One thought on “[Assignment 1] Self Portrait”

Leave a Reply