eeryan + yoonyouk_Final Project

sketch

// Erin Ryan and Yoon Young Kim
// eeryan@andrew.cmu.edu
// yoonyouk@andrew.cmu.edu
// Section C and Section E
//FINAL PROJECT - water animation


//HOME PAGE VARIABLES
//STARTING CODE WITH HOME PAGE
var animation = 0;
//text position variables
var textStart1 = 0;
var textStart2 = 140;
var textStart3 = 280;
var textStart4 = 420;
var textSpace = 140;

//RAINFALL ANIMATION VARIABLES
var numClicks = 0; 
var fall = false; //starting the animation off
var water = [];
var xr; //x position of water droplets

//COHESION ANIMATION VARIABLES
var move = false;
var drop1; //first water object 
var drop2; //second water object 
var opacity = 100; //variable to deal with changing opacity of fills and strokes of different water objects

//RIPPLE ANIMATION VARIABLES
var rx;
var ry;
var diam;

//SPLASH ANIMATION VARIABLES
var SPLASH = [];
var droplets = [];
var dropX = -50; //x coordinate of the water drop
var dropY = 0; // y coordinate of the water drop
var splashpoint = 150;
var numClick = 0;
var explodeTime;
var timeElapsed;
var splashed = false;

function preload(){
    var splashImgs = [];
    //img links of the splash droplets
    splashImgs[0] = "https://i.imgur.com/Aau3BBu.png";
    splashImgs[1] = "https://i.imgur.com/C156jX4.png";
    splashImgs[2] = "https://i.imgur.com/nnR9v06.png";

    //cycling images by pushing into SPLASH array
    for(var i = 0; i<3; i++){
        SPLASH.push(loadImage(splashImgs[i]));
    }
}

function setup() {
  createCanvas(400, 300);
  //object declaration for cohesion animation
  drop1 = makeDrop(120, height / 2, 100);
  drop2 = makeDrop(width - 120, height / 2,100);
  //pushes raindrop objects into the array water
  for(var i = 0; i < 300; i++){
    xr = random(0, width); 
    water.push(makeRain(xr, 20, 5, 0)); 
  }
}

function draw() {
  //default page
  if(animation === 0){ 
    background(173, 212, 255);
    textSize(20);
    fill(255, 255, 255);
    textFont("Courier New")
    text("let's play with water!", width / 2 - 130, 100);
    menuText(200);
  }
  //ripple animation
  if(animation == 1){ 
    background(238, 252, 255);
    noStroke();
    fill(80, 130, 200);
    textFont("courier", 16);
    textAlign(CENTER);
    text("click to touch the water...", width / 2, 30); // creates text guiding user to press a key
    ripple(rx, ry);
    if(diam < 550){
      diam += 1; //circle expands
      opacity -= 0.4; //circle becomes less opaque as it expands
    }
    menuText(275);
  }
  //splash animation
  else if(animation == 2){
    background(238, 252, 255);
    noStroke();
    fill(80, 130, 200);
    textFont("courier", 16);
    textAlign(CENTER);
    text("click to splash water droplets", width / 2, 30); // creates text guiding user to press a key
    fill(26, 133, 192);
    if(dropY > 0 & dropY < splashpoint){
        droplet(dropX, dropY);
        dropY++;
    }
    if(dropY == splashpoint){
        splashed = true;
        if(explodeTime == null){
          explodeTime = frameCount;  
        }
    }
    if(splashed == true){
        timeElapsed = frameCount - explodeTime;
    for(var i = 0; i < 12; i++){
        if(timeElapsed == i){
            imageMode(CENTER);
            image(SPLASH[floor(i / 4)], dropX, dropY);
            }
        }
    }
    menuText(275);
  }
  //rain code animation
  else if(animation == 3){ 
    background(238, 252, 255);
    fill(80, 130, 200);
    textFont("courier", 16);
    textAlign(CENTER);
    text("click once for to make it rain...", width / 2, 30); // creates text guiding user to press a key
    text("click again for clear skies", width / 2, 55);
    if(fall){ 
      for(var i = 0; i < water.length; i++){
        water[i].render();
        water[i].fall();
      }
    }
    menuText(275);
  }
  //cohesion animation
  else if(animation == 4){ 
    background(238, 252, 255);
    textAlign(CENTER);
    noStroke();
    fill(80, 180, 200);
    textFont("courier", 16);
    text("click to see cohesion...", width / 2, 30);
    drop1.render();
    drop2.render();
    if(dist(drop1.x, drop1.y, drop2.x, drop2.y) > 0 & move){// if the two objects are not on top of each other and move == true
      drop1.x++;                                            // move the two drops towards each other and lessen the opacity of their strokes
      drop2.x--;
      opacity -= 1.3;
    }
    menuText(275);
  }
}
    
function keyTyped(){ // assigns a different value to the variable animation based on the key pressed
    if (key == 'r'){ 
      animation = 1;
    }
    if (key == 's'){ 
      animation = 2;
    } 
    if (key == 'u'){ 
      animation = 3;
    }                                             
    if (key == 'c'){ 
      animation = 4;
    } 
    
}

function menuText(posY){ //makes menu scroll with instructions
    noStroke();
    fill(80, 130, 200);
    textSize(10);
    text("press R for ripples", textStart1, posY);
    text("press S for splash", textStart2, posY);
    text("press U for rain", textStart3, posY);
    text("press C for cohesion", textStart4, posY);
    textStart1++;
    textStart2++;
    textStart3++;
    textStart4++;
    if(textStart1 > width){
        textStart1 = -140;
    }    
    if(textStart2 > width){
        textStart2 = -140;
    }
    if(textStart3 > width){
        textStart3 = -140;
    }
    if(textStart4 > width){
        textStart4 = -140;
    }
}

function mousePressed(){
  //variable reset for ripple code
  diam = 0;
  opacity = 100;
  rx = mouseX;
  ry = mouseY;
  if(animation == 2){
    numClick++;
    dropX = mouseX;
    dropY = 1;
    splashpoint = mouseY;
  }

  //rain
  if(animation == 3){
    numClicks++;
    if(numClicks%2 == 1){
      fall = true;
    }
    else{
      fall = false;
    }
  }

  //cohesion
  if(animation == 4){
    move = true;
  }
}

function ripple(px, py){ //draws ripples
  noFill();
  strokeWeight(2.5);
  stroke(0, 0, 255, opacity);
  ellipse(px, py, diam, diam);
  strokeWeight(2);
  ellipse(px, py, diam / 2, diam / 2);
  strokeWeight(1.5);
  ellipse(px, py, diam / 4, diam / 4);
}

function droplet(x, y){
  fill(26, 133, 192);
  //using the map function in order to expand the drop as it moves down
  var xmap = map(dropY, 0, height, 5, 15);
  var ymap = map(dropY, 0, height, 10, 30);
  noStroke();
  beginShape();
  curveVertex(x, y);
  curveVertex(x, y);
  curveVertex(x - xmap, y + ymap);
  curveVertex(x, y + ymap + xmap);
  curveVertex(x + xmap, y + ymap);
  curveVertex(x, y);
  curveVertex(x, y);
  endShape();    
}

//object implementation for cohesion animation
function drawDrop(){ //draws water drop for cohesion animation
  stroke(80, 130, 200, opacity);
  strokeWeight(3);
  fill(230, 242, 255);
  ellipse(this.x, this.y, this.w, this.w);
  noStroke();
}

function makeDrop(posX, posY, diam){//make water drop object for cohestion animation
  var drop = {x:posX, y:posY, w:diam, render:drawDrop};
  return drop;
}

//object implementation for rain animation
function makeRain(px, py, diam, velocity){ //make rain object
  var raindrop = {x:px, y:py, d:diam, v:velocity, render: drawRain, fall:rainFall};
  return raindrop;
}

//draws raindrop
function drawRain(){
  noStroke();
  fill(0, 10, 150, 60);
  ellipse(this.x, this.y, this.d, this.d);
  triangle(this.x - (this.d)/2, this.y, this.x, this.y - 5, this.x + (this.d)/2, this.y);
}

function rainFall(){
  this.v = random(0,8); //randomizess velocity variable
  this.y += this.v; //adds velocity to current y value of each rain drop objects so they'll fal at different speeds
  if(this.y >= height){ //resets rain drops to the top once it hits the bottom of the page
    this.y = 0;
  }
}

For this project, I collaborated with Erin Ryan from Lab section C to make a series of four water-based animations using different animation, interactive, and object oriented techniques. We coded the four interactive animations and the home screen separately, then used a series of conditionals to allow the user to toggle between different animations. We tried to establish cohesive visual language through use of color and simple shapes.

 

Initial sketches of water animations

yoonyouk-LookingOutwards-12

I used one of the advertisements of Apple’s commercials as one of my Looking Outwards examples since there are a lot of relevant elements with this video and what I want to create with this final project. The simple movement of the shapes accompanied the sound so well despite the total simplicity. I like how this example considered not just new shapes appearing on the screen, but also how some shapes blend into new ones. Also, the video primarily utilizes circles to create the shapes and motion and yet is still able to convey so much movement and meaning.

My second example for this week’s LookingOutwards is Jono Brandel’s patapap video. Another example of motion graphics accompanying music. What I liked about this video was the incorporation of color, creating enough contrast between the foreground shapes and the background. When creating my project I think it is important to consider that the shapes must be distinct from each other and should all be noticeable.

yoonyouk-project12-proposal

Initial sketch iterations

For my project, I wanted to create a piano keyboard using the the keyboard of the computer. By pressing different keys, a different note will be played. To accompany these notes, I wanted to add different patterns, shapes, and colors. If chord, or multiple keys are played at the same time, then different patterns will be drawn. I am still deciding whether I want this to be an actual keyboard where a user will hit the keys, or use a piano song and generate the shapes according to those notes. When the keys are played I want to make the background so that the colors adjust the background and maybe even the appearing shapes.

Possible composition of shapes on the screen

With this project, I want to play around with how the shapes will appear on the screen not simply just pop out. Preferably, I would like them to draw out on the screen or transition through opacities. I also need to consider how the shapes will be placed on the screen according to the other shapes and not have everything simply merge together on a single screen.

 

yoonyouk-LookingOutwards-11

 

 

The Classifyer is a gadget that can detect the mood of a social setting and the play the appropriate music. The table can detect different drinks: beer, wine, hot beverages and even catch sounds from the environment whether it be conversations or background sounds. The creators, Benedict Huebermen, Stephanie Lee, Kelvyn Marte, wanted this gadget to enhance the ambience of each environment. The algorithm would be the detection of the different drinks and then the projection of the sounds.

I thought it was cool that the gadget could play the sounds that correlated with different drinks. I also found it particularly interesting that the students of this project determined that drinks were the indicators of the different moods of different settings. Perhaps this product would then be most appropriate in kitchen, bar, or restaurant settings.

Learn more through this link.

yoonyouk-project11-Composition

sketch

//Yoon Young Kim
//Section E
//yoonyouk@andrew.cmu.edu
//Assignment10-A


var turtle;



function setup() {
    var heartmeterangle = random(40, 70);
    var heartmeterlength = random(75, 150);
    createCanvas(480, 360);
    background(random(170, 255));
    frameRate(10);
    turtle = makeTurtle(0, height/2);
    turtle.penDown();
    turtle.setColor(0);
    turtle.setWeight(random(5, 20));


    for(i = 0; i < 8; i++) {

        //rainbow colors
        var r = random(50, 200);
        var g = random(50, 200);
        var b = random(50, 200);
      

        turtle.setColor(color(r, g, b));
        turtle.setWeight(50);


       // turtle.right(sqrt(sq(floor(mouseX - turtle.x))+sq(floor(mouseY-turtle.y))));
        //turtle.forward(floor(mouseX - turtle.x), floor(mouseY-turtle.y));

    turtle.penDown();
    turtle.left(heartmeterangle);
    turtle.forward(heartmeterlength);
    turtle.right(180-heartmeterangle);
    turtle.forward(2*heartmeterlength);
    turtle.left(180-heartmeterangle);
    turtle.forward(heartmeterlength);   
    turtle.right(120-heartmeterangle);

    }

}


function draw() {


}


function turtleLeft(d){this.angle-=d;}function turtleRight(d){this.angle+=d;}
function turtleForward(p){var rad=radians(this.angle);var newx=this.x+cos(rad)*p;
var newy=this.y+sin(rad)*p;this.goto(newx,newy);}function turtleBack(p){
this.forward(-p);}function turtlePenDown(){this.penIsDown=true;}
function turtlePenUp(){this.penIsDown = false;}function turtleGoTo(x,y){
if(this.penIsDown){stroke(this.color);strokeWeight(this.weight);
line(this.x,this.y,x,y);}this.x = x;this.y = y;}function turtleDistTo(x,y){
return sqrt(sq(this.x-x)+sq(this.y-y));}function turtleAngleTo(x,y){
var absAngle=degrees(atan2(y-this.y,x-this.x));
var angle=((absAngle-this.angle)+360)%360.0;return angle;}
function turtleTurnToward(x,y,d){var angle = this.angleTo(x,y);if(angle< 180){
this.angle+=d;}else{this.angle-=d;}}function turtleSetColor(c){this.color=c;}
function turtleSetWeight(w){this.weight=w;}function turtleFace(angle){
this.angle = angle;}function makeTurtle(tx,ty){var turtle={x:tx,y:ty,
angle:0.0,penIsDown:true,color:color(128),weight:1,left:turtleLeft,
right:turtleRight,forward:turtleForward, back:turtleBack,penDown:turtlePenDown,
penUp:turtlePenUp,goto:turtleGoTo, angleto:turtleAngleTo,
turnToward:turtleTurnToward,distanceTo:turtleDistTo, angleTo:turtleAngleTo,
setColor:turtleSetColor, setWeight:turtleSetWeight,face:turtleFace};
return turtle;}

For this turtle graphics project, I made a heart meter like graphic that changes whenever refreshed. A new turtle is drawn after each jump. When refreshed, the colors and positions and lengths change color as well. 

yoonyouk-project10-landscape

sketch

//Yoon Young Kim
//Section E
//yoonyouk@andrew.cmu.edu
//Project10


// Simple demonstration of the noise() function. 
// Change these for different effects:
var terrainSpeed = 0.0005;
var terrainDetail = 0.003;

var cacti = [];


function setup() {
    createCanvas(480, 300);
    background(255);

    for(var i = 0; i <5; i++){
        var rx = random(width);
        cacti[i] = makeCacti(rx);
    }
    frameRate(10);

}
 


function draw() {
    background(255, 192, 141);
    
    stroke(255, 231, 101, 80);
    strokeWeight(20);
    fill(250, 212, 87);
    ellipse(width/2, height/2 - 30, 200, 200);




    fill(196, 100, 76);
    noStroke();
    beginShape(); 
    for (var x1 = 0; x1 < width; x1++) {
        var t1 = (x1 * terrainDetail/2) + (millis() * terrainSpeed/3);
        var y1 = map(noise(t1), 0,1, 75, height/2+100);
        vertex(x1, y1); 
    }

    vertex(x1, height);
    vertex(0, height);
    vertex(0, y1);
    endShape();



    fill(102, 36, 39);
    noStroke();
    beginShape(); 
    for (var x = 0; x < width; x++) {
        var t = (x * terrainDetail*1.5) + (millis() * terrainSpeed*1.5);
        var y = map(noise(t), 0,1, 170, 3*height/4);
        vertex(x, y); 


    }
        vertex(x, height);
        vertex(0, height);
        vertex(0, y);
        endShape();



    fill(25, 7, 5);
    noStroke();
    beginShape(); 
    for (var x2 = 0; x2 < width; x2++) {
        var t2 = (x2 * terrainDetail*2) + (millis() * terrainSpeed*3);
        var y2 = map(noise(t2), 0,1, height/2 + 50, height);
        vertex(x2, y2); 

    }
    vertex(x2, height);
    vertex(0, height);
    vertex(0, y2);


    endShape();


    updateAndDisplayCacti();
    addCacti();

}




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




function addCacti() {
    // With a very tiny probability, add a new building to the end.
    var newCactiLikelihood = 0.007; 
    if (random(0,1) < newCactiLikelihood) {
        cacti.push(makeCacti(width));
    }
}


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

// draw the building and some windows
function cactiDisplay() {
    fill(25, 7, 5);
    push();
    translate(0, 120);
    rect(width/2+this.x, height/2 -60, 20, 70, 200, 200, 0 ,0);
    rect(width/2+15+ this.x, height/2 - 20, 20, 10);
    rect(width/2+25+ this.x, height/2-30, 10, 20, 200, 200, 0, 0);
    rect(width/2 - 15+ this.x, height/2 - 35, 15, 10);
    rect(width/2-15+ this.x, height/2-50, 10, 20, 200, 200, 0, 0);
    pop();
}


function makeCacti(birthLocationX, birthLocationY) {
    var plant = {x: birthLocationX,
                speed: -1.0,
                r: random(0, 50),
                move: cactiMove,
                display: cactiDisplay,
                }
    return plant;
}


For this week’s landscape project, I decided to do a desert scene. I used the noise part in order to create different layers of the landscape essentially creating a foreground, midground, and a background. The front most layer, or the foreground, displays the most detailed landscape and with cacti silhouettes. I found it a bit challenging to create the randomly generated cacti that would move across the screen. I have yet to figure out how to actually place the cacti on top of the terrain.

yoonyouk-LookingOutwards-10

An example of the projection on the walls of Lentos Kuntsmuseum.

For this week’s Looking Outward post I focused on Tina Frank’s work in the Lentos Kuntsmuseum in Germany titled “Hotel Lentos” created in October 2010. By partnering with Elvira Stein, sound director Andrea Kurtz, and curator Magnus Hofmuller, she installed a 40 meter wide screen that would project the scenes of a hotel. The entire wall of the exhibit was filled with the projection work. I like how the entire project, although merely a video projection, is so large and covers up an entire wall. This way, user will feel more immersed into the piece as they watch the scene change from room to room within a hotel.

Tina Frank works as a professor from the University of Art and Design in Austria with a concentration in media art and graphic design. Her works focus on web design, music visualization, and video & multimedia. She also still works as the Creative Director and Founder of URL Agents for Information Design and Tina Frank Designs.

yoonyouk-LookingOutwards-09

I decided to focus on my friend Sharon’s LookingOutward-03, which focused on the work of David Wicks, who works with data visualization. He quotes, “Making Information Beautiful.” The work she decided to focus on was a map of the US with representation of rainfall and water flow.

“A representation of rainfall vs. water consumption in Winter 2001.”

I thought it was interesting that this beautiful visual representation could translate into data information. Although it does not present any numbers, it still provides a general idea of how the water flows. I also thought it was unique that the artist was able to figure out an algorithm that would draw and create such as piece.

yoonyouk-project09-portrait

sketch

//Yoon Young Kim
//Section E
//yoonyouk@andrew.cmu.edu
//Project09


var portraitImage;

function preload(){
    var ImageURL = "https://i.imgur.com/7QWRw4B.jpg";
    portraitImage = loadImage(ImageURL);
}

function setup() {
    createCanvas(480, 480);
    background(0);
    portraitImage.loadPixels();
    frameRate(200);
}

function draw() {
    var px = random(width); //x location where the new pixel will draw
    var py = random(height);//y location where the new pixel will draw

    //constraining the pixels within the canvas
    var ix1 = constrain(floor(mouseX), 0, width-1); 
    var iy1 = constrain(floor(mouseY), 0, height-1);
    //
    var colorofthepixel = portraitImage.get(floor(px), floor(py));

    //determining the thickness and length of the stroke
    var linesize = random(3, 10);

    stroke(colorofthepixel);
    strokeWeight(linesize);
    line(px, py, px, py + linesize);


    //accessing the color of the pixel that the mouse is hovering above
    var colorofthepixelmoused = portraitImage.get(floor(mouseX), floor(mouseY));
    //variety of text sizes when drawing the initials
    textSize(random(5, 20));
    noStroke();
    fill(colorofthepixelmoused);
    //writing initials wherever the mouse hovers
    text("yhk", ix1, iy1);


}

For the portrait, I chose to use my older sister as the subject.

The original image of the portrait

I made the unique pixel a stroke of different weights and lakes to imitate Monet’s water lilies paint strokes, one of my sister’s favorite paintings. In addition, because I wanted add a pixel that would draw according to the mouse, I decided to use her initials (yhk) as this new pixel.

Claude Monet’s water lilies
https://www.claude-monet.com/waterlilies.jsp

I had some help with this project from my 104 tutor who helped my understand that the important components of this project code was the “portraitImage.get” and retrieving the colors of each individual picture. Once I understood this concept, I found it quite easy to create a unique pixel that would develop a portrait image.

The following images display what the portrait looks like throughout the development of frames.

Beginning frames
After a while, with the mouse hovered over to display the initials
A more complete image of the portrait

yoonyouk-lookingoutwards-08

This week’s Looking Outward, I focused on Anouk Wipprecht who spoke at Eyeo Festival in 2016. She is a Dutch artist who identifies herself as Dutch fashion tech designer who welds fashion and technology together. She utilizes fashion and craft skills as well as soldering and technical skills in order to create dresses and garments that move and glow.

She titles her work “Robotic Dresses and Mimicry” combining fashion and technology in order to create eye-catching and moving pieces of clothing. When working with Audi, she took parts from a car and combined them into a garment. Her work is extremely unique and particularly interests me because rather than slapping on technology or LED lights, she integrates fashion and technology in a very cool manner. In addition, the garments don’t look entirely too bulky but rather very high tech and almost high end fashion. I learned that two different subjects can be combined in order to make something quite beautiful. In modern design, a lot of technology is also integrated together but I believe it should be a symbiotic relationship as Wipprecht shows.

 

 

Anouk’s Wipprecht work displayed with an Audi car. She created the clothes to go with the car rather than as an accessory to the car.

Her work can be found in this link.