Final Project: An Animated Rant

For my final project I was inspired by the Facebook page Zoom memes for self quarantines. Over the course of the past semester I’ve found posts that I really resonated with. Although it is a meme page – there are a lot of references to mental health and how the current pandemic and other social issues are affecting our lives beyond the Zoom classroom stress. My project uses mainly black and white colors to reflect the seriousness of the issue and to address topics of funny conversations as something bigger than that and in dire need of attention.

Beyond being a student, I also work full-time so life was getting difficult to balance. So I also found aspects of this rant to encompass elements of work from home life as well and that I do understand both sides of the story.

Now to get into how the program works. It is an interactive “flip book” where you can interact with certain pages with your cursor. Simply moving the cursor along the x and y axis of certain pages reveals new elements or changes existing one. Each of the interactions are in place to put emphasis on certain aspects of the text components but some are only animations. If I had more time to flush out some more details – I would have liked to add flame element to the last page. I think that additional interaction would have also made it more engaging.

Please feel free to interact with it below 🙂

sketch

//Helen Cheng
//helenc1@andrew.cmu.edu
//Final Project
//Section C

// text verses
var page1 = ["i'm tired.", "school is hard.", " navigating life", "during a pandemic", "is hard."]
var page2 = ["staring at a screen from ", "morning to night is hard on my eyes.",
"my vision is becoming fuzzy"];
var page3 = ["paying attention during a Zoom lecture is hard.",
"i already couldn't pay attention in person."]
var page4 = ["doing homework is hard.", "i'm not procrastinating",
"i have 3 homeworks,", "an exam,", "and a project,", "all due on the same day",
"i have to choose which one i don't want to", "'procrastinate on this time.'"];
var page5 = ["it feels like", "i'm overwhelmed"];
var page6 = ["you might feel the same way too.", "so let's all just be kind"]
var page7 = ["has anyone stopped to ask us how we feel?"]
var page8 = ["i'm burnt out."];

// global variables
var pageTracker = 0;
var sentenceTracker = 0;

//for text avoidance function
var minMouseDist = 1000;

//var for helper functions
var floater = [];

function setup() {
    createCanvas(500, 500);
    background(0);
    frameRate(1);
    textAlign(LEFT);
    textFont("serif", 20);
    imageMode(CENTER);

    //setup for page 4 - mouse repelling letters
    //characters into array
    points = new Array(page4[1].length);
    for (var i = 0; i < points.length; i++) {
        points[i] = new Array(2);
    }
    var textW = textWidth(page4[1]);
    var s2 = "";
    // logs location of characters
    for (var i = 0; i < page4[1].length; i++){
        var charPosn = textWidth(s2);
        points[i][0] = createVector((width - textW) / 2 + textWidth(s2), height / 2);
        s2 = s2 + page4[1].charAt(i);
        console.log("s2: " + s2);
    }
    console.log(points);

    //setup for floaters
    for (var i = 0; i < 100; i++) {
        floater.push(makeFloaters(random(width), random(height), 
            random(30), color(random(255), 0, 0), random(-5, 5), random(-5, 5)));
    }
}


function draw() {
    background(0);
    fill(255);

    // starting screen with instructions
    if (pageTracker == 0) {
        textSize(42);
        text("new frustrations", 200, 250);
        textSize(20);
        text("an interactive rant: flip through with arrow keys", 50, 400);
        text("interact by moving your mouse", 50, 450);
        text(concat(str(pageTracker), "/8"), 450, 450);
    }

    //auto displays all strings in a simple animation
    else if (pageTracker == 1) {
        background(0);
        textSize(42);
        text(page1[sentenceTracker], 50, 250);
        textSize(20);
        text(concat(str(pageTracker), "/8"), 450, 450);
    
        if (sentenceTracker < 4) {
            sentenceTracker += 1;
        } 
   }
   //red floaters mimic tired eyes
   else if (pageTracker == 2) {
        frameRate(10);
        animation2();
        for (var i = 0; i < 100; i++) {
            floater[i].drawFunction();
            floater[i].moveFunction();
        }
   }
   //flashing letters makes text harder to read and references attention issues
   else if (pageTracker == 3) {
        animation3();
        fill(255);
        text(concat(str(pageTracker), "/8"), 450, 450);
   }
   //red text avoids cursor to represent procrastination
   else if (pageTracker == 4) {
        animation4();
        fill(255);
        text(concat(str(pageTracker), "/8"), 450, 450);
   }
   //mouseY affects text size
   else if (pageTracker ==5) {
        animation5();
        textSize(20);
        text(concat(str(pageTracker), "/8"), 450, 450);
   }
   //mouseX reveals two sides
   else if (pageTracker == 6)  {
        animation6();
        fill(255);
        text(concat(str(pageTracker), "/8"), 450, 450);
   }
   //mouseY turns a smile upside down
   else if (pageTracker == 7) {
        animation7();
        text(concat(str(pageTracker), "/8"), 450, 450);
   }
   //flashing red text simulates emergency or error text above toaster
   else if(pageTracker == 8) {
        animation8();
        textSize(20);
        fill(255);
        text(concat(str(pageTracker), "/8"), 450, 450);
   }

}

// the page turner 
function keyPressed() {
    background(0);
    if (keyCode === LEFT_ARROW) {
        pageTracker -= 1;
    }
    else if (keyCode === RIGHT_ARROW) {
        pageTracker += 1;
    }

}

//page 5 helper functions
function makeFloaters(x, y, s, c, dx, dy) {
    var floater = new Object();
    floater.x = x;
    floater.y = y;
    floater.size = s;
    floater.c = c;
    floater.dx = dx;
    floater.dy = dy;
    floater.drawFunction = drawFloaters;
    floater.moveFunction = moveFloaters;
    return floater;
}

function moveFloaters() {
    this.x += this.dx;
    this.y += this.dy; 
}

function drawFloaters() {
    fill(this.c);
    ellipse(this.x, this.y, this.size);
}

//page 2: random circles float across the screen to mimic tired eyes
function animation2() {
    fill(255);

    textFont("serif", 20);

    text(page2[0], 100, height/4);
    text(page2[1], 200, height/2);
    text(page2[2], 100, 3*height/4);

    text(concat(str(pageTracker), "/9"), 450, 450);
}


//page 3: moving in and out of focus mimics attention disorders
function animation3() {
    strokeWeight(0);

    fill(128 + sin(frameCount*0.2) * 128);

    text(page3[0], 50, height/3);
    text(page3[1], 50, height/2);
}

//page 4: all text displayed at once but is repelled by cursor
//to symbolize avoidance/procrastination
function animation4() {
    background(0);
    text(page4[0], 50, 50);
    for (var i = 2; i < 8; i++){
        if (i < 5) {
            text(page4[i], 50, 50*i);
        }
        else {
            text(page4[i], 50, 400+50*(i - 6));
        }
    }
    //repels text from cursor
    for(var i = 0; i < points.length; i++){
        var p = points[i][0];
        var p2 = createVector(0, 0);
        var mouseDist = dist(p.x, p.y, mouseX, mouseY);
    
        if(mouseDist < minMouseDist){
            p2 = createVector(p.x - mouseX, p.y - mouseY);   
            var distDifference = minMouseDist - mouseDist;
            p2.setMag(sqrt(distDifference));
    }
    points[i][1] = p2;
    //draws text
    fill(255, 0, 0);
    text(page4[1].charAt(i), p.x + p2.x, p.y + p2.y);
    }   
}

//page 5: text grows in size with mouse position
function animation5() {
    text(page5[0], 100, height/3);
    textSize(mouseY/4);
    text(page5[1], 100, height/2);
}

//page 6: text reveals to show the two sides/perspectives
function animation6() {
    fill(255);
    rect(0, 0, mouseX/2, 500);
    rect(500, height, mouseX/2, 500);
    fill(255);
    text(page6[0], 100, height/3);
    fill(0);
    text(page6[1], 100, height/2);
}

//page 7: smiley face turns from smile to frown
function animation7() {
    ellipse(200, 200, 50, 70);
    ellipse(300, 200, 50, 70);
    //smiles at top half, frowns at bottom half of canvas
    noFill();
    strokeWeight(5);
    stroke(255);
    if (mouseY < 250) {
        arc(250, 300, 100, 50+mouseY/5, 0, PI);
    }
    else {
        arc(250, 300, 100, mouseY/5, PI, 2*PI);
    }
    strokeWeight(0);
    fill(255);
    text(page7[0], 80, 100);
}

//page 8: toaster
function animation8() {
    rectMode(CENTER);
    var toaster = 300;
    //toaster side view
    fill(220);
    rect(width/2, height/2, 200, 100);
    ellipse(170, 210, 50, 30);
    ellipse(330, 210, 50, 30);
    rect(width/2, 300, 220, 20);
    rect(350, 230, 20, 10);
    fill(128 + sin(frameCount*0.2) * 128, 0, 0);
    
    textSize(40);
    text(page8[0], 140, 100);
}

Project 11: Generative Landscape

For this project, I went with a simple scrolling sunset city & mountain view. The sun has a second ring around it just because I felt that it gave it more of a setting sun feeling. Then the buildings have flashing lights because I thought about how dorm/student living buildings when you look at them from the outside. Everyone seems to have different color LED lights lighting up their rooms in all different colors.

//Helen Cheng
//helenc1@andrew.cmu.edu
//Project 11
//Section C

var buildings = [];
var hill = [];
var noiseParam = 0;
var noiseStep = 0.01;
var n;
var hillPoint;


function setup() {
    createCanvas(640, 240); 
    
    // create an initial collection of buildings
    for (var i = 0; i < 10; i++){
        var rx = random(width);
        buildings[i] = makeBuilding(rx);
    }

    //creates initial set of mountains
    for (i=0; i<=width/5; i++) {
        n = noise(noiseParam);
        hillPoint = map(n, 0, 1, 0, height);
        hill.push(hillPoint);
        noiseParam += noiseStep;
    }

    frameRate(10);
}


function draw() {
    background(93, 150, 168); 

    //setting sun
    fill(245, 188, 159);
    circle(width/2, height/2, 100);
    fill(250, 211, 125);
    circle(width/2, height/2, 50);

    drawHills();

    displayHorizon();

    updateAndDisplayBuildings();
    removeBuildings();
    addNewBuildings(); 
}

function drawHills() {
    var x = 0;
    beginShape();
    vertex(0, height);
    stroke(0);
    fill(126, 168, 151);


    //draws hill shape
    for (i=0; i<width/5; i++) {
        vertex(5*i, hill[i]);
    }

    //appends new hill point and removes first
    hill.shift();
    vertex(width, height);
    n = noise(noiseParam);
    hillPoint = map(n, 0, 1, 0, height);
    hill.push(hillPoint);
    noiseParam += noiseStep;
    
    endShape(CLOSE);
}

function updateAndDisplayBuildings(){
    // Update the building's positions, and display them.
    for (var i = 0; i < buildings.length; i++){
        buildings[i].move();
        buildings[i].display();
    }
}


function removeBuildings(){
    var buildingsToKeep = [];
    for (var i = 0; i < buildings.length; i++){
        if (buildings[i].x + buildings[i].breadth > 0) {
            buildingsToKeep.push(buildings[i]);
        }
    }
    buildings = buildingsToKeep;
}


function addNewBuildings() {
    var newBuildingLikelihood = 0.005; 
    if (random(0,1) < newBuildingLikelihood) {
        buildings.push(makeBuilding(width));
    }
}


// method to update position of building every frame
function buildingMove() {
    this.x += this.speed;
}
    

// draw the building and some windows
function buildingDisplay() {
    var floorHeight = 20;
    var bHeight = this.nFloors * floorHeight; 
    stroke(0);
    fill(245, 229, 201);
    push();
    translate(this.x, height - 40);
    rect(0, -bHeight, this.breadth, bHeight);
    stroke(200); 
    for (var i = 0; i < this.nFloors; i++) {
        fill(color(random(255), random(255), random(255))); 
        rect(5, -15 - (i * floorHeight), this.breadth - 10, 10);
    }
    pop();
}


function makeBuilding(birthLocationX) {
    var bldg = {x: birthLocationX,
                breadth: 50,
                speed: -2.0,
                nFloors: round(random(2,9)),
                move: buildingMove,
                display: buildingDisplay}
    return bldg;
}


function displayHorizon(){
    stroke(0);
    fill(202, 245, 201);
    rect(0,height-50, width, height);
}

Looking Outwards 11

The female new media artist that I chose to highlight is Mimi Son. She studied interactive design at the Copenhagen Institute of Interaction Design before starting a design firm alongside Elliot Woods named Kimchi and Chips. Mimi’s fascination with geometry and Buddhist philosophy play a large role in inspiring her work and the elements of time and space.

Line Segments Space is a work by Mimi Son displayed in nylon string and digital emulsion. This display is shown in the Vimeo above where you can see the interaction between the light display and sound. I found this to be such a captivating form of line art. Each of lines represents a transformed 2 dimensional canvas which is also represented in different dimension, sound.

Looking Outwards 10

Since my LO-4 assignment focused on a form of sound art, I chose the option to investigate a piece of music that you could hear in a concert hall. Which in this case, actually took place in one. I was drawn to this project because it wasn’t just auditory, but also a beautiful visual experience as well. The Stanford Laptop Orchestra used SLork musical lanterns that communicate with ChucK via wifi to translate the movements of the lanterns into sound and light.

The musical performance was called “Aura” since they used multiple people with different light color and sounds that harmonized with one another in a similar way that people do in society. I thought it was a very clever and interesting way to create music through movement.

Project 9: Portrait

For this assignment, I used circles that size in size in correspondence to clicking the up or down arrow. It was inspired by the concept of paint splash art where it can create a very interesting portrait when you mix different brush sizes.

sketch

//Helen Cheng
//helenc1@andrew.cmu.edu
//Section C
//Project-09

var selfie;
var pixelSize = 5;

function preload() {
  selfie = loadImage("https://i.imgur.com/TWhDyur.jpg");
}

function setup() {
  createCanvas(480, 320);
  selfie.resize(480, 320);
  selfie.loadPixels();
}

function draw() {
  //random pixel drawer
  var picX = floor(random(selfie.width));
  var picY = floor(random(selfie.height));
  fill(selfie.get(picX, picY)); 
  drawPixel(picX, picY);

  //mouse brush
  fill(selfie.get(mouseX, mouseY));
  drawPixel(mouseX, mouseY);

}

 function drawPixel(x, y) {
    //circlular brush strokes
    strokeWeight(0);
    circle(x, y, pixelSize);
  }

//increase or decreases brush stroke using up and down arrows
function keyPressed() {
  if (keyCode === UP_ARROW) {
    pixelSize += 1;
  }
  else if (keyCode === DOWN_ARROW);
    pixelSize = pixelSize - 1;
  }

Looking Outwards 9

For this looking outwards assignment, I chose to look at Sarah’s LO-7 on data visualization. What really caught my eye about the visualization of color themes in Pixar films is that it was essentially showing non-numerical data about movies that we watched growing up. Although it seems like non-numerical data, Sarah’s description got in detail as to how they extracted the color themes using python. I agree with what Sarah said about each of the color wheels closely resembling a disc that the movies would normally be played on.

Something relevant that came to mind when I saw this project is how nowadays there are branding consultants that look at everything about a brand and design logos, office color schemes, and website color in order to convey a certain story or emotion. Here, we know what the general theme of each movie is and seeing the color wheel is still able to transfer some of those emotions as well.

Looking Outwards 8

Mike Tucker is the Interactive Director at Magic Leap, a company that focuses on Mixed Reality and Spatial computing. Before he started at Magic Leap, Mike was the Interactive Director at Universal Everything, where he created his most famous project. One that I will touch on later as one of the works I admire most from him. Before he launched his career as a designer/developer, he attended Virginia Commonwealth University where he received a BFA in Graphic Design.

The reason why I chose to highlight Mike Tucker and Magic Leap’s work is that interactive art is amazing already, but it just becomes even more captivating when it is immersive and interactive. The projects he describes in the presentation show the prototypes where the art work changes at the literal touch of your fingertips. This leads me to what I admired about how he presented his work. Such complex technologies are difficult to explain, but I found it easy to follow along since he showed so many graphics and “behind the scenes” work. He gave us a glimpse into every step in the process which I hope to try implementing in the future when describing my own work.

Now to discuss Mike Tucker’s art installation in San Francisco, the infinity room. It’s something that I’ve seen a lot on social media but finally being able to see the purpose behind it was amazing. The Microsoft Infinity Room was created as a visualization of big data as explained by a quarter. We have worked on projects that touch on data visualization so I found the room to be such a fascinating way of presenting complex data.

Project 7: Curves

For project 7, I chose to use a logarithmic spiral to create a series of spirals that interact with the mouse position. I was inspired to do logarithmic spirals by some shells I have in a jar on my desk. Then, I wanted to do something that is colored differently than my previous projects.

screen capture of my program

The spiral’s distance from the center increases or decreases relative to the mouse x position while the degree from the center changes relative to Y depending on the Y position.

sketch

//Helen Cheng
//helenc1@andrew.cmu.edu
//Section C
//Project-07

var theta;
var r;
var nPoints = 500;

function setup() {
  createCanvas(480, 480);
  angleMode(DEGREES);
}

function draw() {
  background(0);
  startAngle = constrain(mouseY, 10,360);
  //parallel spirals
  stroke(255,255,0);
  logSpiral(0,startAngle);
  stroke(255,255,255)
  logSpiral(mouseX, startAngle);
  stroke(255,0,0)
  logSpiral(mouseX+25, startAngle+25);
  stroke(0,255,0)
  logSpiral(mouseX+50, startAngle+50);
  stroke(0,0,255)
  logSpiral(mouseX+75, startAngle+75);

}

function logSpiral(r, theta, color) {
  var x;
  var y;
  noFill();
  beginShape();
  //populates points on each of the spirals
  for (i=0; i<nPoints; i++) {
    x = 240+(r+i)*-cos(theta+2*i);
    y = 240+(r+i)*sin(theta+2*i);
    vertex(x, y);
  }
  endShape();
}

Looking Outwards 7

For this looking outwards assignment, I decided to look at this chart that helped visualize food additives and where they are most commonly found. The reason why I chose this graph is because I’ve always been very health conscious and aware of what goes into my foods. Although I’ve always on and on about how unhealthy snacks can be.

Something that I really like about this work is asides from it’s informational purposes is how it is able to turn data that would normally be a bar chart into something easier to read that can communicate data on quantity on bar thickness like a pie chart but demonstrate the dramatic disproportionate distribution like a pie chart.

I think that they used algorithms that determined thickness as a proportion of the quantity and then just connected the points to the corresponding category.

Project 06: Abstract Clock

For my abstract clock I built it off the idea that we (or at least I), run on coffee. The day starts with a cup of coffee and is essentially continuously fueled by yet another cup. The clock begins with 12 empty cups on the screen that represent each hour in the AM or PM. Then with each minute – the coffee level increases in the cup until its filled, capped, and sleeved. Ticking along is a coffee bean counter that is representative of each second that goes by (the brewing/drip process) that helps fill the cup.

During the AM hours, the background represents a daytime sky with a sun. Then during PM hours, there is a night sky with a moon and randomly generated stars.

sketch

//Helen Cheng
//helenc1@andrew.cmu.edu
//Section C
//Project-06

var mugX = [];
var currH;
var starX = [];
var starY = [];

function setup() {
    createCanvas(480, 300);
    rectMode(CENTER);
    //initializes array with num of cups
    for (h=0; h<12; h++) {
        mugX[h] =  h*40 + 20
    }

    for (i=0; i< 20; i++) {
        starX[i] = random(width);
        starY[i] = random(height);
    }
}

function draw() {
    //colors sky based on AM or PM
    if(hour()<12){
        dayTime();
    }
    else{
        nightTime();
    }

    //draws table
    fill(235, 227, 218);
    rect(240, 250, 480, 200);

    //draws a coffee bean per second
    for(s =0; s<second(); s++){
        coffRow = Math.floor(s/20);
        coffeeBean(45 + 20*(s-20*coffRow), 200 + 30*coffRow);
    }
  
    //draws coffee cups depicting hours
    currH = hour()%12;
    for (h=0; h<12; h++) {
        if (h<currH){
          fill(92, 48, 7);
          strokeWeight(1);
          rect(mugX[h], height/2, 30, 50); 
          strokeWeight(0);
          ellipse(mugX[h], height/2 + 25, 30, 10);
          //cap
          fill(191, 155, 187);
          rect(mugX[h], height/2-25, 35, 10);
          ellipse(mugX[h], height/2-30, 25, 10);
          //cup sleeve
          rect(mugX[h], height/2, 35, 20);
        }
        else{
          fill(240, 234, 223);
          strokeWeight(1);
          rect(mugX[h], height/2, 30, 50); 
          arc(mugX[h], height/2 + 25, 30, 10, 0, PI);
        }
    }
  
    //fills coffee cup per minute
    for (m=0; m<minute(); m++) {
        strokeWeight(0);
        fill(92, 48, 7);
        ellipse(hour()%12*40 + 20, (height/2+25)-(m*50/60), 30, 10);
    }
}

function coffeeBean(x,y){
    strokeWeight(2);
    fill(92, 48, 7);
    ellipse(x, y, 10, 20);
    line(x, y-10, x, y+10);
} 

function nightTime() {
    background(35, 41, 94);
    fill(242, 242, 233);
    circle(width/3, height/5, 30);

    for (i=0; i< 20; i++) {
        circle(starX[i], starY[i], 5);
    }
}

function dayTime() {
    background(152, 210, 237);
    fill(245, 205, 103);
    circle(width/3, height/5, 40);
}

sketch of concept