Timothy Liu — Project 02 — Variable Face

tcliu-OpenEnded-02

// Timothy Liu
// 15104 Section C
// Open Ended-02

// facial features (variables)
var eyeWidth = 25;
var eyeHeight = 15;
var pupilWidth = eyeWidth / 2;
var pupilHeight = 11 * eyeHeight / 16;
var noseWidth = 15;
var noseHeight = 40;
var earSize = 30;
var headWidth = 125;
var headHeight = 150;
var mouthWidth = 60;
var mouthHeight = 40;
var mouthStart;
var mouthEnd;
var skin1 = "#FFD3A1";
var eyeL;
var eyeR;

// body shape and size (variables)
var bodyWidth = 200;
var bodyHeight = 370;
var colorR = 105;
var colorG = 64;
var colorB = 122;

// hat dimensions and color (variables)
var hatR = 14;
var hatG = 28;
var hatB = 117;
var hatBottom;

// function time!
function setup() {
    
    createCanvas(600, 480);
    mouthStart = TWO_PI;
    mouthEnd = PI;
    eyeL = width / 2 - headWidth / 5;
    eyeR = width / 2 + headWidth / 5;
    hatBottom = height / 4 - headHeight / 6;
    // initializing P5.js functions in setup()

}
 
function draw() {

    // background color
    background(240, 196, 101);
    noStroke();

    // ears
    fill(skin1);
    ellipse(width / 2 - headWidth / 2, height / 4, headWidth / 8, headHeight / 6);
    ellipse(width / 2 + headWidth / 2, height / 4, headWidth / 8, headHeight / 6);

    // neck
    fill(skin1);
    rect(width / 2 - headWidth / 4, height / 4 + headHeight / 4, headWidth / 2, headHeight);

    // head and face
    fill(skin1);
    ellipse(width / 2, height / 4, headWidth, headHeight);

    // bucket hat
    fill(hatR, hatG, hatB);
    quad(width / 2 - headWidth / 2, hatBottom, width / 2 - headWidth / 3, height / 4 - headHeight / 2, 
    	width / 2 + headWidth / 3, height / 4 - headHeight / 2, width / 2 + headWidth / 2, hatBottom);
    rect(width / 2 - 2 * headWidth / 3, hatBottom, headWidth * 1.35, headWidth / 32);

    // eyeballs
    fill("white");
    ellipse(eyeL, height / 4 - height / 48, eyeWidth, eyeHeight);
    fill("white");
    ellipse(eyeR, height / 4 - height / 48, eyeWidth, eyeHeight);

    // pupils
    fill(59, 35, 18);
    ellipse(eyeL, height / 4 - height / 48, pupilWidth, pupilHeight);
    fill(59, 35, 18);
    ellipse(eyeR, height / 4 - height / 48, pupilWidth, pupilHeight);

    // nose
    fill("#D39972");
    arc(width / 2, height / 4 + headHeight / 8, noseWidth, noseHeight, PI, TWO_PI);

    // mouth
    fill(255, 150, 150);
    arc(width / 2, height / 3, mouthWidth, mouthHeight, mouthStart, mouthEnd, CHORD);

    // body and shirt
    fill(colorR, colorG, colorB);
    arc(width / 2, 5 * height / 6, bodyWidth, bodyHeight, PI, TWO_PI);

    // pants
    fill("#003366");
    rect(width / 2 - bodyWidth / 2, 5 * height / 6, bodyWidth, height / 6);

    // thigh gap
    fill(240, 196, 101);
    rect(width / 2 - bodyWidth / 8, 15 * height / 16, bodyWidth / 4, bodyWidth / 4)
}

function mousePressed() {

    // brackets to denote an array. The coinFlip variable helps determine whether it's a smile or frown.
    var coinFlip = random([0, 1]);

    // randomly generating head proportions including eyes, face size, pupil, nose, and mouth.
    headWidth = random(100, 200);
    headHeight = random(121, 180);
    eyeWidth = random(15, 40);
    eyeHeight = random(10, 20);
    eyeL = width / 2 - headWidth / 5;
    eyeR = width / 2 + headWidth / 5;
    pupilSize = 9 * eyeWidth / 16;
    noseWidth = random(10, 30);
    noseHeight = random(20, 50);
    mouthWidth = random(20, 60);
    mouthHeight = random(20, 60);

    // randomly generating body size and color.
    bodyWidth = random(170, 350);
    colorR = random(0, 255);
    colorG = random(0, 255);
    colorB = random(0, 255);

    // randomly generating hat color.
    hatR = random(0, 255);
    hatB = random(0, 255);
    hatG = random(0, 255);

    // this is an array of different hex values for skin tones.
    // the program randomly selects a skin tone every time the mouse is pressed.
    skin1 = random(["#FFD3A1", "#F5CB9A", "#C39582", "#FFCEB4", "#A57E6E", "#EABD9D", "#FFCEB4", "#DEAB7F", "#FFDCB1"]);
    
    // this if statement helps determine whether the character is smiling or frowning using the coinFlip variable defined above. 
    if (coinFlip == 0) {
        mouthStart = 6.28;
        mouthEnd = 3.14;
        // Smiley mouth
    } else {
    	mouthStart = 3.14;
    	mouthEnd = 6.28;
    	// Frowny mouth
    }

    // condition to ensure that the Smiley mouth never sticks out past the chin
    // note: this was originally an if-and statement, but the ampersand was causing issues with WordPress embedding.
    if (mouthStart == 6.28) {
        if ((height / 3 + mouthHeight) > (height / 4 + headHeight / 2)) {
            mouthHeight = mouthHeight / 2;
        }
    }

    // condition to ensure Frowny mouth never touches the nose
    if (mouthStart == 3.14) {
        if ((height / 3 - mouthHeight) < (height / 4 + headHeight / 8 + noseHeight)) {
            mouthHeight = mouthHeight / 2;
        }
    }

}

This project was a fun challenge for me because it required a heavy amount of step-by-step variable referencing, but it also encouraged me to think very logically. Every time I set up coordinates, I actively made sure to question if I could use a variable to simplify my code, and this made it significantly easier to randomize the face (as well as other features) later because all of my variables were already consolidated.

I enjoyed getting to play with an abstract art style, and I made my characters reflect that; they each have simplified features, but my program incorporates a wide array of body types and shapes. I’ve come away from this project with a much stronger understanding of how to utilize local and global variables, as well as how to use if-else statements to set up different conditions to ensure my faces didn’t distort in odd ways.

Timothy Liu — LookingOutwards — 02

Kate Compton is a self-described “crafter of twitching generative bots.” Her work perfectly encapsulates concepts of generative art; it is bright, geometric, whimsical, and most importantly, random. A great example I found of her work is “Flowers,” a generative art piece that randomly spawns a sequence of graphically-generated flowers that sway in the wind. If you click “replant,” you’re able to regenerate the sequence of flowers, and the “evolve” button causes the regeneration to occur rapidly. 

An example snapshot of one of Kate Compton’s sequence of generative flowers (http://www.galaxykate.com/apps/Prototypes/LTrees/).

I thought that this was a fascinating example of generative art because you can almost see the principles in action. According to Free Code Camp, some of the core foundations of generative art is that:

  1. It’s random
  2. It’s based on algorithms
  3. It’s geometric in nature

The “replant” and “evolve” buttons make it clear that there’s an element of randomness to Compton’s work. Further, she’s very upfront in her bio that she works mainly with JavaScript (and very possibly, p5.js!). Thus, it’s likely that Compton wrote an algorithm in JavaScript and allowed it to reign freely over her art. Finally, the graphical style of the flowers is clearly geometric and shape-driven, and this works wonderfully with her work because of how flowy and limber the flowers feel in the wind. 

It’s clear that Compton’s artistic capabilities are embedded in her algorithm because of how she utilizes color palettes and combinations as part of the “random” element. Every time the sequence of flowers evolves, so does the color palette, but Compton’s clear knowledge of color theory keeps the colors vivid, bright, and fun. My guess on how the algorithm functions is that with every mouseClick on “replant,” a random color is selected for each of the different flowers. Not only that, but a new random sequence of shapes is generated as well. Then, for the “evolve” buttons, the algorithm emulates a continuous sequence of mouseClicks to keep the colors and shapes evolving and changing. Kate doesn’t explain the secrets to her work, but it’s that element of randomness and surprise that keeps fans coming back for more.

Kate explaining how she creates generative art with Javascript at the JSConf in Iceland, 2018.

Sources:

https://www.freecodecamp.org/news/an-introduction-to-generative-art-what-it-is-and-how-you-make-it-b0b363b50a70/

http://www.galaxykate.com/apps/Prototypes/LTrees/

http://www.galaxykate.com

Timothy Liu — Project01 — Face


I really enjoyed this project as it allowed me to take creative liberties in portraying a few aspects of who I am—an upbeat, fun-loving, Yankees/sports fan—through graphic fundamentals of P5. The coding process was tricky in how long it took to align each of the components I included on the grid system (especially the hat logo), but it was a really rewarding first project.

tcliu-self-portrait

//Timothy Liu
//15-104 Section C
//tcliu@andrew.cmu.edu
//SELF-PORTRAIT

function setup() {
    createCanvas(600,600);
    background("#CAE9F5");
}

function draw() {

    fill("#F5CB9A");
    noStroke();
    rect(260,270,80,50);
    //neck

    fill("#FFD3A1");
    noStroke();
    ellipse(300,200,160,180);
    fill("#FFD3A1");
    noStroke();
    ellipse(220,210,20,45);
    fill("#FFD3A1");
    noStroke();
    ellipse(380,210,20,45);
    //head

    fill("#23120B");
    noStroke();
    quad(218,170,235,170,230,195,218,195);
    fill("#23120B");
    noStroke();
    quad(380,170,365,170,370,195,382,195);
    fill("#23120B");
    noStroke();
    arc(310, 165, 80, 25, TWO_PI, PI, CHORD);
    //hair

    fill(255);
    noStroke();
    arc(270,200,30,25,PI,TWO_PI);
    fill(255);
    noStroke();
    arc(330,200,30,25,PI,TWO_PI);
    fill(0);
    noStroke();
    ellipse(270,193.5,12,12);
    fill(0);
    noStroke();
    ellipse(330,193.5,12,12);
    //eyes

    fill(255);
    noStroke();
    ellipse(270,190,3,3);
    fill(255);
    noStroke();
    ellipse(330,190,3,3);
    //pupils

    fill("#003366");
    noStroke();
    quad(200,320,400,320,410,height,190,height);
    fill("#1261A0");
    noStroke();
    quad(203,443,195,height,202,height,208,447);
    //shirt/body

    fill("#1261A0");
    noStroke();
    arc(300, 320, 95, 50, TWO_PI, PI, CHORD);
    fill("#F5CB9A");
    noStroke();
    arc(300, 320, 85, 40, TWO_PI, PI, CHORD);
    //collar area

    fill("#CAE9F5");
    noStroke();
    triangle(200,320,250,320,190,350);
    //Left shoulder

    fill("#CAE9F5");
    noStroke();
    triangle(400,320,350,320,410,350);
    //Right shoulder

    fill("#003366");
    noStroke();
    quad(105,450,110,500,200,440,200,345);
    fill("#003366");
    noStroke();
    quad(90,350,110,500,150,450,120,340);
    fill("#1261A0");
    noStroke();
    quad(140,415,138,420,200,360,200,349);
    fill("#1261A0");
    noStroke();
    quad(200,349,200,360,257,327,253,324);
    //Right arm

    fill("#003366");
    noStroke();
    quad(495,450,490,500,400,440,400,345);
    fill("#003366");
    noStroke();
    quad(490,500,470,height,430,height,450,400);
    //Left arm

    fill("#FFD3A1");
    noStroke();
    ellipse(105,340,60,55);
    fill("#FFD3A1");
    noStroke();
    quad(83,275,93,315,108,320,95,272);
    fill("#FFD3A1");
    noStroke();
    quad(120,273,108,315,118,330,132,276);
    fill("#FFD3A1");
    noStroke();
    triangle(73,322,77,350,120,308);
    fill("#F5CB9A");
    noStroke();
    quad(73,322,82,348,105,340,94,313);
    fill("#E4B98E");
    noStroke();
    quad(97,335,120,364,133,350,105,327);
    //Right hand (with peace sign)

    fill("#D39972");
    noStroke();
    arc(300,225,10,40,PI,TWO_PI);
    //nose

    fill(255,150,150);
    noStroke();
    arc(300, 235, 60, 60, TWO_PI, PI, CHORD);
    //mouth

    fill("#003366");
    noStroke();
    arc(300,170,165,180,PI,TWO_PI);
    fill("#003366");
    noStroke();
    rect(218,155,190,15);
    fill("#CAE9F5");
    noStroke();
    triangle(381,155,420,170,420,155);
    //hat

    fill(255);
    noStroke();
    rect(285,120,5,25);
    fill(255);
    noStroke();
    rect(310,120,5,25);
    fill(255);
    noStroke();
    quad(290,120,315,142,310,145,287,126);
    fill(255);
    noStroke();
    quad(290,105,300,118,300,123,287,111);
    fill(255);
    noStroke();
    quad(310,105,300,118,300,123,313,111);
    fill(255);
    noStroke();
    rect(297.5,120,5,28);
    //logo on hat
   
}

Timothy Liu — Looking Outwards — 01

This is a before-and-after map of Kamrangirchar, Bangladesh — a striking example of the type of impact Missing Maps can have on a rural area (via Missing Maps, Twitter)

I recently had the opportunity to participate in a “mapathon” through Missing Maps, a collaborative initiative that aims to map “off-the-grid” parts of the world in order to improve humanitarian access and disaster relief efforts during times of crisis. The platform was designed and launched in September of 2014 by the American Red Cross alongside Doctors Without Borders. The project is an open collaboration that involves volunteers mapping streets, buildings, and infrastructure in high-risk areas into OpenStreetMap. Community volunteers then take these satellite maps and add in specific details, including what each building specifically is, before handing them off to humanitarian organizations that then use these maps to plan more efficient disaster responses. This project heavily utilizes OpenStreetMap (OSM), a software that actually originally involved a java-based applet on the OSM homepage. Over time, the basis of OSM has evolved into an online JavaScript editor known as iD.

The creators were likely motivated to create an initiative that enabled anyone with a working computer to help those in need. OSM was already in existence before the start of Missing Maps, and the creators of the initative likely felt that OSM could be better utilized through humanitarian efforts. Through its simple and easy-to-use online OSM editor, Missing Maps has impacted hundreds and thousands of people around the world who have suffered through crises. I was incredibly inspired by how simple yet powerful Missing Maps’ mission is, and it was amazing to think that I was able to potentially impact a small town in Kenya simply by mapping out a portion of their rural roads. And yet, the opportunities for further exploration and mapping are endless. There’s still a massive amount of rural area that needs to be mapped, and the 86,543 contributors thus far are ready to continue with their efforts to help the Red Cross save lives.

Some of the incredible contributions that have been made by the thousands of Missing Maps volunteers around the world (via Missingmaps.org).
A video explaining how Missing Maps works (https://www.youtube.com/watch?v=wEEnOqmVfqM)

Sources used:

https://www.missingmaps.org/

https://www.redcross.org/about-us/our-work/international-services/mapping-vulnerable-communities.html

https://wiki.openstreetmap.org/wiki/History_of_OpenStreetMap