Portrait of a classmate with p5.js.

This week’s project was an exercise in patience because, to paraphrase the poet Mary Ruefle, I’m just a handmaiden with a broken urn when it comes to writing code. I felt like I learned a lot, though, and I’m slowly developing a process for these assignments.

In our first class, we were introduced to the basic functions in p5.js, function setup() and function draw(). Our assignment this week was to draw a portrait of one of our classmates using only primitive shapes in p5.js (translation: no complex shapes, no animation, no interactive elements).

Here’s a link to the final portrait.

My process was simple: (1) Sketch out the drawing in Illustrator; (2) Create a quick outline in p5.js; and (3) Code like hell.

I found it helpful before even writing a line of code to use Illustrator to make a sketch so I had a better sense of what kinds of shapes I’d be drawing. In terms of color, I used the site Coolors to generate the RGB values that matched the color scheme I envisioned.

Here’s my initial sketch and the outline of shapes I planned to use:

Sketch

Sketch---shapes

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

From there, I started coding.

Overall, I wanted the portrait to be symmetrical so I was doing a lot of math in my head to calculate some of the x and y coordinates for each shape that I drew. Just about all the shapes I drew were various combinations of quad(), rect(), ellipse(), triangle(), and line(). There was a lot of trial and error, since I was pretty much guessing at where different points would be on the canvas.

That proved to be a massive headache since I was constantly trying to remember which line of code corresponded to which shape in the drawing and which coordinate corresponded to which point on the shape. It’s no big deal when you have three shapes, but when you are drawing 30+ shapes it can get messy.

I found it helpful to organize my lines of code with some subheadings: //face, //hair, //shirt, etc. I think that in the future I will create a much more detailed system for labeling shapes in my code.

I quickly realized that the portrait I’d sketched out at the beginning of the project was going to be an ambitious undertaking with the limited tools that were available to me in p5.js (since we could only use functions that drew primitive shapes). It took me longer than I’d anticipated, but I found that I was able to add a lot of detail to the portrait despite these limitations.

Here’s a screenshot of the final portrait:

Portrait screenshot

Overall, the project was an excellent exercise in learning the basics of p5. Here’s my full code:

function setup() {
createCanvas(1000,1000);
background(132,220,207);
}

function draw() {

//shirt
stroke(33,131,128);
fill(33,131,128);
quad(50,450,80,350,420,350,450,450);
quad(80,350,190,300,310,300,420,350);
stroke(130,150,133);
fill(130,150,133);
triangle(190,300,290,400,220,395);
triangle(310,300,290,400,330,350);
stroke(60,132,131);
fill(60,132,131);
ellipse(232,382,10,10)
stroke(97,61,193);
fill(97,61,193);
quad(120,330,160,312,190,450,155,450);
quad(400,337,350,317,375,450,400,450);

//face
stroke(230,202,171);
fill(230,202,171);
triangle(190,300,310,300,290,400);
quad(190,300,200,270,300,270,310,300);
quad(180,230,320,230,280,300,220,300);
rect(180,160,140,70);
quad(180,160,320,160,300,90,200,90);

//hair
stroke(161,131,87);
fill(161,131,87);
quad(180,230,320,230,280,300,220,300);
triangle(180,230,180,190,199,230);
triangle(320,230,320,190,301,230);
quad(170,185,180,185,200,130,177,115);
quad(200,130,177,115,210,65,267,55);
quad(200,130,267,55,290,90,270,90);
quad(267,55,270,90,300,110,320,100);
triangle(270,90,250,110,260,90);
quad(300,110,320,100,330,140,310,150);
quad(310,150,330,140,320,185,315,185);
triangle(300,105,299,140,315,170);
triangle(200,130,196,155,180,175);
rect(207,149,23,4);
triangle(207,149,207,153,199,160);
rect(271,149,23,4);
triangle(294,149,294,153,303,160);

//face #2
stroke(230,202,171);
fill(230,202,171);
ellipse(175,185,26,50);
ellipse(325,185,26,50);
triangle(200,229,240,229,220,250);
triangle(300,229,260,229,280,250);
ellipse(250,260,33,11);

//facial features.
stroke(133,138,227,100);
strokeWeight(1.2)
fill(222,255,240);
quad(226,168,210,168,203,177,233,177);
quad(274,168,290,168,297,177,267,177);
stroke(86,88,87,190);
fill(86,88,87,190);
ellipse(223,172,8,7);
ellipse(287,172,8,7);
stroke(222,242,200);
fill(222,242,200);
ellipse(225,170,3,2);
ellipse(289,170,3,2);
stroke(133,138,227,0);
fill(133,138,227,110);
quad(203,177,233,177,226,181,210,181);
quad(297,177,267,177,274,181,290,181);
quad(243,230,259,230,267,223,235,223);
quad(267,223,235,223,242,218,260,218);
stroke(133,138,227,100);
strokeWeight(2.2);
line(258,217,258,163);
line(228,181,210,200);
line(272,181,290,200);
line(290,310,280,370);
line(230,313,260,350);

//hands
stroke(230,202,171);
fill(230,202,171);
rect(136,410,68,13);
rect(138,425,70,13);
rect(136,437,70,13);

//hair #2
stroke(161,131,87);
fill(161,131,87);
triangle(186,185,189,163,175,160);
triangle(314,185,311,163,325,160);
triangle(175,140,175,123,165,145);
triangle(210,67,190,79,210,75);
triangle(330,138,338,143,325,120)

//glasses
stroke(71,44,27,230);
strokeWeight(2.7);
noFill();
ellipse(217,175,44,24);
ellipse(284,175,44,24);
line(239,175,262,175);
line(195,175,182,170);
line(306,175,318,170);

}