*“Honor thy error as a hidden intention”*

– Brian Eno and Peter Schmidt, *The Oblique Strategies *

This is the first real code I have written since I was a high school freshman. I was pretty overwhelmed playing around with P5 in class, but I got home and decided to keep exploring. And suddenly little tiny bits and pieces of half-remembered stuff came floating back – first Booleans (because who can forget a word like “Boolean”?), then “if/then,” then “else if”… and I was off to the races. I wrote a very very silly program and was deeply impressed with what I had discovered I could do.

And then it came time to Do the Actual Work, and I realized I had no idea. It’s one thing to gather up party tricks and various ways of making the screen do what you want it to, but quite another to use those techniques to tell a story, even a very simple one.

I looked through all of the available functions to see which one would give the most flexibility and ease of use, and I hit on the idea that I could use curve() like the pen tool in Photoshop, if only I could plot coordinates. So I opened my sample photo:

sized it to the canvas I wanted to use, and began to move the mouse to where I would normally put anchor points in Photoshop, and noted the values for x and y on a piece of paper.

I then entered them into P5 (using curveVertex()), and a picture began to emerge:

but not a very compelling one. It’s amazing how difficult it is to draw by conjecture and guesswork, using only numbers and no visual interface. Even with a set of likely points, I was getting weird, lumpy, incoherent shapes, and had absolutely no meaningful way of resolving them.

I then had a think and reread the assignment and decided that it might be more edifying to try to use the actual shapes in the program. It was still painfully slow going, but I developed a process where I decided everything (save a couple choice elements) would be simplified and symmetrical, that I would make the left feature first, “perfect” it by modifying axes, curves, etc., then copy it to the right. In looking for a way to rotate shapes I came across the translate() function, which helped immensely as I could put the center of the face at the center of my coordinate system and easily just change negatives to positives to copy elements from left to right.

But it was still mighty slow going, all trial and error and moving things five pixels at a time. It’s also amazing how resonant the idea of a face is, and the effect of any element being “off.”

My code is below – there are still a couple of abandoned shapes in there, examples of things I tried that didn’t work. And there’s a very inelegant (since it repeats almost the *entire code*) odd-interval blinking function that I couldn’t resist throwing in.

function setup() {

createCanvas (460, 600);

}

function draw() {

background(150);

if ((second() % 5 <= 0) && (abs(sin(millis()/1000)) <= 1/4)) {

//left hair 1

fill(50);

noStroke();

translate(230, 260);

quad(-40, 200, -80, -60, -127, -60, -120, 200);

//right hair 1

fill(50);

noStroke();

quad(40, 200, 80, -60, 122, -64, 115, 200);

// face

fill(220);

stroke(0);

strokeWeight(3);

ellipse(0, 0, 214, 260);

//left temple

fill(0);

noStroke();

translate(0, 5);

quad(-115, -45, -70, -45, -70, -5, -115, -35);

//right temple

fill(0);

noStroke();

quad(115, -45, 70, -45, 70, -5, 115, -35);

//nose bridge

noFill();

stroke(0);

strokeWeight(5);

arc(0, -13, 65, 57, PI+QUARTER_PI, -QUARTER_PI);

//bottom of left lens

fill(240);

stroke(0);

strokeWeight(3);

arc(-55, -59, 90, 135, QUARTER_PI / 2, PI-(QUARTER_PI/2), OPEN);

//top of left lens

fill(240);

stroke(0);

strokeWeight(3);

arc(-55, -23, 100, 60, PI+QUARTER_PI / 2, 2 * PI-(QUARTER_PI/2), OPEN);

//bottom of right lens

fill(240);

stroke(0);

strokeWeight(3);

arc(55, -59, 90, 135, QUARTER_PI / 2, PI-(QUARTER_PI/2), OPEN);

//top of right lens

fill(240);

stroke(0);

strokeWeight(3);

arc(55, -23, 100, 60, PI+QUARTER_PI / 2, 2 * PI-(QUARTER_PI/2), OPEN);

//bottom of left eye

noFill();

stroke(0);

strokeWeight(1);

arc(-55, -38, 60, 47, QUARTER_PI / 2, PI-(QUARTER_PI/2), OPEN);

//bottom of right eye

noFill();

stroke(0);

strokeWeight(1);

arc(55, -38, 60, 47, QUARTER_PI / 2, PI-(QUARTER_PI/2), OPEN);

//bridge of nose

noFill();

stroke(160);

translate(0, 2);

strokeWeight(2);

arc(57, -27, 100, 130, HALF_PI+QUARTER_PI+QUARTER_PI/6, PI);

//left nostril

//fill(220);

//stroke(120);

//strokeWeight(2);

//arc(-20, 22, 30, 30, HALF_PI, PI, OPEN);

//right nostril

//fill(220);

//stroke(120);

//strokeWeight(2);

//arc(20, 22, 30, 30, 0, PI-HALF_PI, OPEN);

//center of nose

fill(220);

stroke(120);

strokeWeight(2);

arc(0, 18, 50, 50, QUARTER_PI/2, PI-QUARTER_PI/2, OPEN);

//mouth

noFill();

stroke(100);

strokeWeight(2);

arc(0, 15, 170, 110, QUARTER_PI, PI-QUARTER_PI, OPEN);

//lower lip

noFill;

stroke(160);

strokeWeight(1);

arc(0, 30, 170, 100, HALF_PI-QUARTER_PI/3, HALF_PI+QUARTER_PI/3, OPEN);

//left smile

noFill;

stroke(180);

strokeWeight(1);

arc(0, 55, 110, 50, PI-QUARTER_PI/3, PI, OPEN);

//right smile

noFill;

stroke(180);

strokeWeight(1);

arc(0, 55, 110, 50, 0, QUARTER_PI/3, OPEN);

//left hair

fill(50);

noStroke();

translate(-52, -108);

rotate(PI/3.35);

ellipse(0, 0, 70, 180);

translate(72, -97);

//right hair

fill(50);

noStroke();

rotate(-2*PI/3.5);

ellipse(0, 0, 50, 130);

}

else {

//left hair 1

fill(50);

noStroke();

translate(230, 260);

quad(-40, 200, -80, -60, -127, -60, -120, 200)

//right hair 1

fill(50);

noStroke();

quad(40, 200, 80, -60, 122, -64, 115, 200)

// face

fill(220);

stroke(0);

strokeWeight(3);

ellipse(0, 0, 214, 260);

//left temple

fill(0);

noStroke();

translate(0, 5);

quad(-115, -45, -70, -45, -70, -5, -115, -35);

//right temple

fill(0);

noStroke();

quad(115, -45, 70, -45, 70, -5, 115, -35);

//nose bridge

noFill();

stroke(0);

strokeWeight(5);

arc(0, -13, 65, 57, PI+QUARTER_PI, -QUARTER_PI);

//bottom of left lens

fill(240);

stroke(0);

strokeWeight(3);

arc(-55, -59, 90, 135, QUARTER_PI / 2, PI-(QUARTER_PI/2), OPEN);

//top of left lens

fill(240);

stroke(0);

strokeWeight(3);

arc(-55, -23, 100, 60, PI+QUARTER_PI / 2, 2 * PI-(QUARTER_PI/2), OPEN);

//bottom of right lens

fill(240);

stroke(0);

strokeWeight(3);

arc(55, -59, 90, 135, QUARTER_PI / 2, PI-(QUARTER_PI/2), OPEN);

//top of right lens

fill(240);

stroke(0);

strokeWeight(3);

arc(55, -23, 100, 60, PI+QUARTER_PI / 2, 2 * PI-(QUARTER_PI/2), OPEN);

//top of left eye

fill(255);

stroke(0);

strokeWeight(1);

arc(-55, -15, 60, 47, PI+QUARTER_PI / 2, 2 * PI-(QUARTER_PI/2), OPEN);

//bottom of left eye

fill(255);

stroke(0);

strokeWeight(1);

arc(-55, -38, 60, 47, QUARTER_PI / 2, PI-(QUARTER_PI/2), OPEN);

//center of left eye

fill(0);

noStroke();

ellipse(-55, -26, 20, 20);

//top of right eye

fill(255);

stroke(0);

strokeWeight(1);

arc(55, -15, 60, 47, PI+QUARTER_PI / 2, 2 * PI-(QUARTER_PI/2), OPEN);

//bottom of right eye

fill(255);

stroke(0);

strokeWeight(1);

arc(55, -38, 60, 47, QUARTER_PI / 2, PI-(QUARTER_PI/2), OPEN);

//center of right eye

fill(0);

noStroke();

ellipse(55, -26, 20, 20);

//bridge of nose

noFill();

stroke(160);

translate(0, 2);

strokeWeight(2);

arc(57, -27, 100, 130, HALF_PI+QUARTER_PI+QUARTER_PI/6, PI);

//left nostril

//fill(220);

//stroke(120);

//strokeWeight(2);

//arc(-20, 22, 30, 30, HALF_PI, PI, OPEN);

//right nostril

//fill(220);

//stroke(120);

//strokeWeight(2);

//arc(20, 22, 30, 30, 0, PI-HALF_PI, OPEN);

//center of nose

fill(220);

stroke(120);

strokeWeight(2);

arc(0, 18, 50, 50, QUARTER_PI/2, PI-QUARTER_PI/2, OPEN);

//mouth

noFill();

stroke(100);

strokeWeight(2);

arc(0, 15, 170, 110, QUARTER_PI, PI-QUARTER_PI, OPEN);

//lower lip

noFill;

stroke(160);

strokeWeight(1);

arc(0, 30, 170, 100, HALF_PI-QUARTER_PI/3, HALF_PI+QUARTER_PI/3, OPEN);

//left smile

noFill;

stroke(180);

strokeWeight(1);

arc(0, 55, 110, 50, PI-QUARTER_PI/3, PI, OPEN);

//right smile

noFill;

stroke(180);

strokeWeight(1);

arc(0, 55, 110, 50, 0, QUARTER_PI/3, OPEN);

//left hair

fill(50);

noStroke();

translate(-52, -108);

rotate(PI/3.35);

ellipse(0, 0, 70, 180);

translate(72, -97);

//right hair

fill(50);

noStroke();

rotate(-2*PI/3.5);

ellipse(0, 0, 50, 130);

}