Project 4: String Art

yosemite
let yPerl = 0.0;

function setup() {
  createCanvas(400, 300);
  
  pinkSky = color(252, 224, 217);
  blueSky = color(190, 228, 235);
  mountainColor = color(46, 130, 129);
  treeColor = color(162, 179, 137);
  sunColor = color(255, 181, 181);
}

function draw() {
    background(0);

    //the sky
    let changeSky = map(mouseY, 0, height, 0, 1);
    var skyColor = lerpColor(pinkSky, blueSky, changeSky);
    fill(skyColor);
    rect(0, 0, width, height/1.5);

    //the sun
    noStroke();
    ellipseMode(CENTER);
    fill(sunColor);
    var stopMouseX = constrain(mouseX, 100, 300);
    var stopMouseY = constrain(mouseY, 0, 300);
    let sunX = map(stopMouseX, 0, width, 0, 400);
    let sunY = map(stopMouseY, 0, height, 0, 300);
    ellipse(sunX, sunY, 90, 90);
  
    //generative mountains
    fill(mountainColor);
    beginShape();
    let xPerl = 0;
    for (let x = 0; x<= width; x += 10) {
        let y = map(noise(xPerl), 0, 1, 200, 50);
        vertex(x, y);
        xPerl += 0.2;
    }
  
    yPerl += 0.2;
    vertex(width, height);
    vertex(0, height);
    endShape(CLOSE);
  
    //trees
    push();
    for (var i = 0; i <= 400; i += 1) {
        stroke(treeColor);
        strokeWeight(0.5);
        line(50, i + 50, i, height); //1st tree from the left
        line(100, i + 20, i + 50, height + 25); //2nd tree
        line(150, i + 70, i + 70, height + 50); //3rd tree
        line(225, i + 80, i + 200, height + 50); //4th tree
        line(width/2, i + 125, i + 150, height); //5th tree
        line(300, i + 60, i + 250, 300); //6th tree
        line(350, i + 100, i + 300, 350); //7th tree
        line(400, i + 100, i + 350, 400); //8th tree on far right
  }
    pop();
}

I was loosely inspired by the sunrises and sunsets at Yosemite National Park. The mountains regenerate randomly every time the page is reloaded.

Looking Outwards 04: Sound Art

Christine Sun Kim’s Elevator Pitch is an interactive art installation that
celebrates the Deaf community of New Orleans and their vitality to a city
that’s world-renowned as the birthplace of jazz music. Kim, who is Deaf,
created the piece to reference her childhood memories of shouting with her
Deaf friends in elevators in order to feel the vibrations and echoes of
their voices in the confined space.

Participants can press buttons in the elevator that feature the voices
of thirteen different people from New Orleans’ Deaf community. The
elevator is a thoughtful structure that challenges the idea of “awkward
silence” in elevators and highlights how ableism can permeate in even the
most innocuous spaces.

Installation Link

Project 3: Dynamic Drawing

Contrary to popular belief, fish bowls are too small for the average betta or goldfish and will likely either stunt their growth or kill them due to the lack of space. I thought it would be cool to bring some awareness about this overlooked fact through this project. The fish will either live and emit bubbles or flip over and die depending on the mouse’s position on canvas.

fishbowl
var bgColor;
var bowlColor;
var bodyPurple;
var bodyGray;
var bodyAngle;
var eyeAngle;
var pupilAngle;
var finOrange;
var finGray;
var floatY;

var angle = 0;
var offWeed = 1;
var wiggleWeed = 1;
var bubbles = [];

function setup() {
    createCanvas(600, 450);

    bgColor = color(255, 247, 219);
    bowlGreen = color(110, 245, 234, 120);
    bowlGray = color(190, 212, 209, 200);
    weedGreen = color(78, 186, 159);
    weedGray = color(114, 130, 126);
    sandOrange = color(245, 147, 132);
    sandGray = color(173, 160, 158);
    bodyPurple = color(155, 159, 242);
    bodyGray = color(113, 113, 117);
    finOrange = color(255, 115, 87);
    finGray = color(156, 144, 142);
    bubblesBlue = color(92, 209, 203, 80);
    invisibleColor = color(92, 209, 203, 0);
    castleColor = color(255, 181, 181);
}

function bubble(x,y) {
    let bubblesColor = map(mouseX, 0, width, 0, 1);
    var lerpBubbles = lerpColor(bubblesBlue, invisibleColor, bubblesColor);
    fill(lerpBubbles);
    ellipse(x, y, 15);
  }

function draw() {
    background(bgColor);
    noStroke();

    //seaweed
    let weed = map(mouseX, 0, width, 0, 1);
    var weedColor = lerpColor(weedGreen, weedGray, weed);
    fill(weedColor);

    beginShape();
    vertex(y + 500, x);
    for(var x = 0; x < width; x++){
        var angle = offWeed + x * 0.03;
        var y = map(sin(angle), -wiggleWeed, wiggleWeed, 170, 200);
    vertex(y + 90, x + 100);
  }
    vertex(275, 100);
    endShape();
    offWeed += 0.01;
  
    beginShape();
    vertex(newY + 600, x - 200);
    for(var x = 0; x < width; x++){
        var angle2 = offWeed + x * 0.02;
        var newY = map(sin(angle2), -wiggleWeed, wiggleWeed, 250, 230);
    vertex(newY - 10, x + 160);
  }
    vertex(newY - 5, x);
    endShape();
    offWeed += 0.03;
  
    beginShape();
    vertex(freshY, x);
    for(var x = 0; x < width; x++){
        var angle3 = offWeed + x * 0.04;
        var freshY = map(sin(angle3), -wiggleWeed, wiggleWeed, 175, 160);
    vertex(freshY + 40, x + 140);
  }
    vertex(freshY + 30, x);
    endShape();
    offWeed += 0.01;

    //cover bottom half of seaweed
    fill(bgColor);
    rect(50, 320, 400, 200);

    //castle
    fill(castleColor);
    rect(355, 250, 55, 70);
    rect(355, 240, 10, 10);
    rect(380, 240, 10, 10);
    rect(400, 240, 10, 10);

    //castle window
    fill(161, 93, 93);
    rect(370, 260, 10, 20, 10);

    //rocks
    fill(97, 100, 201);
    ellipse(350, 310, 40, 40);
    fill(247, 104, 185);
    ellipse(230, 310, 40, 30);
    fill(171, 92, 191);
    ellipse(320, 310, 40, 30);
    fill(119, 224, 172);
    ellipse(255, 310, 35, 25);
    fill(247, 104, 185);
    ellipse(390, 310, 25, 25);

    //fishbowl
    let fishbowl = map(mouseX, 0, width, 0, 1);
    var bowlColor = lerpColor(bowlGreen, bowlGray, fishbowl);
    fill(bowlColor);
    ellipse(width/2, height/2, 300, 300);

    //bubbles
    bubble(240, floatY + 20);
    bubble(245, floatY + 10);
    bubble(250, floatY + 40);
        
    if (mouseX <= width/2.2) {
        floatY = floatY - 0.4
    } else {
        floatY = 150;
    }

    //fin colors
    let finColor = map(mouseX, 0, width, 0, 1);
    var fishFins = lerpColor(finOrange, finGray, finColor);
    fill(fishFins);

    push();
    //rectMode(CENTER);
    translate(width/2, height/2);
    let finAngle = atan2(mouseY - height/2, mouseX - width/2);
    rotate(finAngle);
    //bottom fin
    arc(0, -25, 40, 40, PI + HALF_PI, TWO_PI);

    //tail
    arc(-40, 0, 75, 75, HALF_PI + QUARTER_PI, PI + QUARTER_PI);
    pop();

    //top fin
    push();
    translate(width/2, height/2);
    let topfinAngle = atan2(mouseY - height/2, mouseX - width/2);
    rotate(topfinAngle);
    shearX(-35);
    rect(-10, 25, 50, 25, 70, 5, 70, 10);
    pop();

    //fish body
    let bodyColor = map(mouseX, 0, width, 0, 1);
    var fishBody = lerpColor(bodyPurple, bodyGray, bodyColor);
    fill(fishBody);
    push();
    rectMode(CENTER);
    translate(width/2, height/2);
    let bodyAngle = atan2(mouseY - height/2, mouseX - width/2);
    rotate(bodyAngle);
    rect(0, 0, 100, 55, 30);

    //eye
    fill(255);
    ellipse(25, 5, 20, 20);

    //pupil
    var stopMouseX = constrain(mouseX, 0, 600); //constrain mouseX to canvas
    let dilate = map(stopMouseX, 0, width, 10, 18);
    fill(0);
    ellipse(25, 5, dilate, dilate);

    //mouth
    fill(fishBody);
    rect(50, 0, 10, 5, 20);
    rect(50, -5, 10, 5, 20);
    pop();


    //sandy bottom
    push();
    noStroke();
    let sandColor = map(mouseX, 0, width, 0, 1);
    var coarse = lerpColor(sandOrange, sandGray, sandColor);
    fill(coarse);
    arc(300, 310, 225, 120, TWO_PI, PI);
    pop();

    //bubbles floating
    for (let i = 0; i < bubbles.length; i++) {
        bubbles[i].move();
        bubbles[i].show();
        bubbles[i].update();
    }

    //top of the fishbowl
    fill(bgColor);
    rect(50, 0, 400, 120);
}

Looking Outwards 03: Computational Fabrication

I was really drawn to Kate Hartman, a designer of computational wearables,
and her Porcupine Experiments, a project based on a wearables made from
everyday materials. For her particular project, Hartman opted to use
cardboard, brass fasteners and washers, nylon webbing, and triglide
fasteners. The vest’s design was created in Autodesk Fusion 360 and cut
out with an Epilog laser cutter. Hartman then hosted a Porcupine Workshop
in San Francisco, giving participants free materials and allowing them
to create their own vests with their hands and imaginations.

I think this project is quite enjoyable and unique due to the nature of the
vests. The designs are very spiky and jarring and really emulate a porcupines’
quills, which is very different from typical pleasing design conventions and
brings the vests’ usefulness into question (probably what Hartman was intending.) I also enjoyed how accessible these wearables are. As long as anyone has some cardboard, they’re free to make their own designs from Hartman’s blueprints and create some truly unique and playful vests.

For anyone who also wants to make a porcupine vest, they can find Hartman’s free online instructions here.

Project 2: Variable Face

generative_faces

var bgColor;
var blushColor;
var cheekBlush;
var blushSize;
var blushHeight;
var faceWidth;
var faceHeight;
var faceStyle;
var Bun;
var bunY;
var noseStyle;
var mouthStyle;
var eyeStyle;

function setup() {
    createCanvas(600, 600);
    //background(220);
    //text("p5.js vers 0.9.0 test.", 10, 15);

    bgColor = color(255, 235, 232);
    blushColor = color(255, 138, 130);
    cheekBlush = 0;
    blushSize = 0;
    blushHeight = 0;
    Bun = 0;
    bunY = 0;
    noseStyle = 0;
    faceStyle = 0;
    mouthStyle = 0;
    eyeStyle = 0;
}

function draw() {
    background(bgColor);

    // HAIR BUNS
    fill(0);
    ellipse((width/3), bunY, Bun, Bun); 
    ellipse((width/1.5), bunY, Bun, Bun);

    // FACE
    fill(255);
    strokeWeight(5);
    if (faceStyle >= 2) {
        ellipse((width/2), (height/2), 300, 300); //circular face
    }
    else if (faceStyle >= 1) { //teardrop face
        ellipse((width/2), (height/2.2), 360, 250);
        bezier(475, 300, 400, 500, 220, 550, 125, 300);
    }
    else {
        ellipse((width/2), (height/2), 350, 280); //oval face
    }

    // EYES
    if (eyeStyle >= 2){ //oval eyes
    push();
    fill(255);
    ellipse((width-375), (height-300), 50, 35); // left eye
    ellipse((width-225), (height-300), 50, 35); // right eye

    noStroke();
    fill(0);
    ellipse((width-375), (height-300), 30, 30); //left pupil
    ellipse((width-225), (height-300), 30, 30); // right pupil
    pop();
    }
    else if (eyeStyle >= 1) { //round owl eyes
        stroke(5);
        push();
        fill(255);
        ellipse((width-375), (height-300), 60, 60); //left eye
        ellipse((width-225), (height-300), 60, 60); //right eye
        noStroke();
        fill(0);
        ellipse((width-375), (height-300), 45, 45); //left pupil
        ellipse((width-225), (height-300), 45, 45); //right pupil
        pop();
    }
    else { //closed eyes
        arc((width-375), (height-300), 50, 35, HALF_PI + HALF_PI, TWO_PI); //left eye
        arc((width-225), (height-300), 50, 35, HALF_PI + HALF_PI, TWO_PI); //right eye
    }

    // BLUSHING CHEEKS
    if (cheekBlush >= 0.5){
        push();
        fill(blushColor);
        noStroke();
        ellipse((width-400), blushHeight, blushSize, blushSize); //left blush
        ellipse((width-200), blushHeight, blushSize, blushSize); //right blush
        pop();
    }

    //MOUTH
    noFill();
    strokeWeight(5);
    if (mouthStyle >= 2){ //closed smile
        arc((width-300), (height-280), 200, 140, QUARTER_PI, QUARTER_PI + HALF_PI);
    }
    else if (mouthStyle >= 1){ //open smile
        push();
        fill(0);
        translate((width-300), (height-220));
        rotate(TWO_PI);
        arc(0, 0, 75, 50, 0, PI, CHORD);
        pop();
    }
    else { //shocked mouth
        fill(0);
        ellipse((width/2), (height - 205), 50, 50);
    }

    //NOSE
    if (noseStyle >= 2) {
        noFill();
        arc((width-300), (height-270), 45, 55, QUARTER_PI, QUARTER_PI + HALF_PI); //down-turned nose
    } else if (noseStyle >= 1){ //nostrils
        push();
        noStroke();
        fill(0);
        ellipse((width-310), (height-250), 10, 10); //left nostril
        ellipse((width-290), (height-250), 10, 10); //right nostril
        pop();
    }
    else { //pink button nose
        fill(blushColor); 
        ellipse((width/2), (height-260), 20, 20);
    }

    //BANGS
    fill(0); //right bang
    push();
    translate((width-225), height-350);
    rotate(-QUARTER_PI - HALF_PI);
    arc(0, 0, 250, 200, 0, PI);
    pop();

    translate((width-375), (height-350)); //left bang
    rotate(QUARTER_PI + HALF_PI);
    fill(0);
    arc(0, 0, 250, 200, 0, PI);
}

function mousePressed(){
    cheekBlush = random(0, 1); //randomize blush
    blushSize = random(30, 60); //randomize blush size
    blushHeight = random(350, 360); //randomize blush's Y-axis
    bunY = random(200, 400); //randomize hair buns' Y-axis
    Bun = random(150, 250); //randomize hair buns' size
    noseStyle = random(0,3); //randomize nose shape
    faceStyle = random(0,3); //randomize face shape
    mouthStyle = random(0,3); //randomize mouth shape
    eyeStyle = random(0,3); //randomize eyes
}

For this project, I drew inspiration from the Moomin books, the logo for Utz Snacks, the mascots for PBS Kids, and the logo for a Korean supermarket franchise. The generative process became a lot easier once I started incorporating if-else statements!

Looking Outwards 2: Generative Art

Ian Cheng’s Emissaries is “a trilogy of simulations about cognitive
evolution, past and future, and the ecological conditions that shape
it
,” as per the artist’s website. Cheng created the live, CGI
simulations through a video game engine and observed the works from
2015 – 2017 as the game essentially “played itself.” The characters
and creatures within Emissaries play out their lives in open-
ended narratives generated and modeled through predictive technology
usually reserved for forecasting election results or climate change.

Emissaries is a fascinating case study on narrative consciousness,
evolution, and dealing with natural chaos in life. I had the good
fortune of listening to Ian speak about this work when he visited
Carnegie Mellon back in 2017, and I was struck by the sheer complexity
and time he invested into these generative worlds. In order to build
this game and have it play itself over two years, I think Cheng would
have had to feed the algorithm an inordinate amount of data on past
major events, disasters, and research on human psychology so that the
game could generate narratives and characters that accurately reflect
our world.

LO – My Inspiration

I’ve always been inspired by teamLab Borderless, an immersive, interactive museum of colorful digital art installations in Tokyo. The museum is structured so that there are quite literally no borders between different art installations – each piece seamlessly blends and communicates with each other, creating a breathing, vibrant space that people can interact with. It became the most visited single-artist museum in the world, welcoming over 2.3 million people in its opening year alone.

Borderless is an impressive feat of audiovisual experiences, comprising of over 500 computers and 470 projectors in the museum alone. The museum was created by the art collective teamLab, an interdisciplinary, collaborative group of artists, animators, designers, architects, engineers, and programmers. Although there’s very little public information on how teamLab created Borderless, I think it’s safe to say that the collective used a mix of custom scripts and commercial software to bring the immersive space to life. It’s amazing to witness what they could accomplish only two years ago in this museum, and I’m excited to see how teamLab will build upon their success to enhance immersive, interactive experiences in the future.

Project 1 – Self Portrait

portrait
var bgColor;  
var hairColor;
var hairShadow;
var skinColor;
var blushColor;
var shirtColor;
var glassesColor;
var mouthColor;
var shirtOutline;

function setup() {
    createCanvas(400, 400);
    text("p5.js vers 0.9.0 test.", 10, 15);

    bgColor = color(255, 247, 191);
    hairColor = color(233, 148, 105);
    hairShadow = color(216, 105, 71);
    skinColor = color(244, 190, 130);
    blushColor = color(237, 163, 118);
    shirtColor = color(172, 188, 138);
    glassesColor = color(66, 31, 14);
    mouthColor = color(188, 89, 82);
    shirtOutline = color(104, 149, 129);
}

function draw() {
    background(bgColor);
  
    //back hair
    noStroke();
    fill(hairColor);
    rect(75, 90, 250, 200, 80);
    
    noStroke();
    fill(hairColor);
    rect(75, 140, 250, 170, 40);
  
    //back hair shadow
    fill(hairShadow);
    rect(90, 120, 220, 190, 40);
  
    //shirt
    fill(shirtColor);
    rect(width/4, height/1.25, 200, 250, 75);
  
    //ears
    fill(skinColor);
    ellipse(width/3.75, height/1.9, 50, 50);
    ellipse(width/1.35, height/1.9, 50, 50);
  
    //ear outlines
    noFill();
    stroke(blushColor);
    strokeWeight(3);
    ellipse(width/3.75, height/1.9, 35, 35);
    ellipse(width/1.35, height/1.9, 35, 35);
  
    //neck
    noStroke();
    fill(skinColor);
    rect(width/2.28, height/1.75, 50, 125, 50);
  
    //neck shadow
    fill(blushColor);
    rect(width/2.28, height/1.75, 50, 80, 15);
  
    //face
    fill(skinColor);
    ellipse(width/2, height/2, 200, 200);
  
    //shirt collar
    noFill();
    stroke(shirtOutline);
    strokeWeight(3);
    arc(width/2, height/1.24, 65, 75, 0, HALF_PI + HALF_PI);
  
    //blush
    noStroke();
    fill(blushColor);
    ellipse(width/2.85, height/1.7, 45, 45);
    ellipse(width/1.54, height/1.7, 45, 45);
    
    //mouth
    fill(mouthColor);
    arc(width/2, height/1.65, 50, 50, 0, HALF_PI + HALF_PI);
  
    //bangs
    fill(hairColor);
    arc(width/2, height/2.35, 250, 200, HALF_PI + HALF_PI, TWO_PI);
  
    //glasses
    noFill();
    stroke(glassesColor);
    strokeWeight(4);
    ellipse(width/2.65, height/2.1, 75, 75);
    ellipse(width/1.6, height/2.1, 75, 75);
    line(210, 190, 190, 190);
  
    //eyes
    arc(width/2.65, height/2, 40, 35, HALF_PI + HALF_PI, TWO_PI);
    arc(width/1.6, height/2, 40, 35, HALF_PI + HALF_PI, TWO_PI);
}