Final Project

2020 was full of surprises that shook our world and changed the lives of many. My final project comments on the concept of misfortune and plays with the sense of control that many felt like they didn’t have in the face of a global pandemic, monumental election, civil rights movements, wildfires, and more. The 2020 slot machine presents the user with an attractive and exciting prospect of winning, but ultimately delivers the raw reality of this year.

To play, click and drag down on the lever, then release. The reels will spin and generate your 2020. Observe the effects of a jackpot!

I was inspired to create a slot machine for my final project because when presented with the project theme “2020,” I couldn’t narrow down to one single event that I wanted to focus on. I instead wanted to take a more macro approach and reflect on the year as a whole and satirize it with a classic casino game. With more time, I would add a greater jackpot effect, more buttons, and user interaction opportunities to the slot machine.

Icon Key
sketchDownload
//2020 SLOT MACHINE
//Elysha Tsai

//All illustrated assets made by me
var bg;
var symbolLinks = [
    "https://i.imgur.com/gj4Ztah.png", //COVID
    "https://i.imgur.com/a8qsuTb.png", //AUSTRALIAN BUSHFIRES
    "https://i.imgur.com/TLZnWQ9.png", //BLM
    "https://i.imgur.com/1tdvXwb.png", //ELECTION
    "https://i.imgur.com/SsV7YIF.png", //2020
    "https://i.imgur.com/EHQEMEP.png", //MURDER HORNETS
]
var textLinks = [
    "https://i.imgur.com/qBgKflt.png", //COVID
    "https://i.imgur.com/jTMJxU5.png", //AUSTRALIAN BUSHFIRES
    "https://i.imgur.com/L47KJMN.png", //BLM
    "https://i.imgur.com/IAmvG2D.png", //ELECTION
    "https://i.imgur.com/051k4xi.png", //2020
    "https://i.imgur.com/sRj9Ipi.png", //MURDER HORNETS
]

var maxlinks = 6;

//assign links to 3 separate reels
var reelA;
var reelB;
var reelC;

var reelimages=[];
var reeltext=[];
var reelAindex=0
var defaultText;
var textimage;
var jackpotWin;

var count =0;
var doneReel=0;
var jackpotindex=0;

//light object variables
var light =[];
var x; //position of light
var speed;

var leverpull;
//var jackpotwin;
var ball;
var slotmachine;
var chair;

function preload() {

  //IMAGES
  bg= loadImage("https://i.imgur.com/Mt81CeD.jpg"); //green gradient background
  ball= loadImage("https://i.imgur.com/5UZk7nN.png"); //lever ball
  slotmachine= loadImage("https://i.imgur.com/3OioKHj.png");
  chair= loadImage("https://i.imgur.com/KXMlSo1.png");

  defaultText= loadImage("https://i.imgur.com/dcfoYh5.png");
  jackpotWin= loadImage("https://i.imgur.com/ih2wbgn.png");

  for (var i=0; i<maxlinks; i++) { 
    reelimages[i] = loadImage(symbolLinks[i]);
  } 
  for (var i=0; i<maxlinks; i++) { 
    reeltext[i] = loadImage(textLinks[i]);
  }

//initial array assignment
  reelA=reelimages[2];
  reelB=reelimages[0];
  reelC=reelimages[4];


}

function setup() {
    createCanvas(600, 450);
    frameRate(10); //mechanical feeling of lever

    //textimage = defaultText;


    //setup light object
    var dist =0;
    for (var i =0; i<1000; i++){
      light[i]= varLight(dist);
      dist +=12; //distance b/w lights
    }
}
/*
function soundSetup() { 
    leverpull.setVolume(1);
    jackpotwin.setVolume(1.2);
    */

function draw() {
  image(bg, -50, -50, 700, 550);

  //draw lightstrip
  push();
  noStroke();
  fill(110, 186, 173); //green
  rect(0, 14, width, 12);
  pop();

  //draw lights
  for(var i = 0; i < light.length; i++){
        light[i].display();
        light[i].move();
  }

  image(slotmachine, 0, 0, 600, 450);
  image(chair, 0, 0, 600, 450);

  //draw text
  push();
  //imageMode(CENTER)
  //image(jackpotWin, 0, 0);
  pop();

  
//JACKPOT
//background flashes when hit jackpot after reels stop changing
  if ((reelA == reelB) & (reelB == reelC) && doneReel){

    //background flashes when hit jackpot after reels stop changing
    rect(0, 0, 600, 450);
    image(slotmachine, 0, 0, 600, 450);
    image(chair, 0, 0, 600, 450);
    image(chair, 0, 0, 600, 450);
     
    count ++;

    if(count==1){
      fill(255, 0, 0);
      }else if(count==2){
        fill(0, 255, 0);
      }else if(count==3){
        fill(0, 0, 255);
        count = 0; 
      }
      
      image(jackpotWin, 0, 0);
      //textimage= reeltext[jackpotindex];
      //assign jackpot symbol to text

      //displayText();
  }

    
  

  //draw images in a row
  image(reelA, 119.5, 181.5, 53, 138);
  image(reelB, 178.5, 181.5, 53, 138);
  image(reelC, 237.5, 181.5, 53, 138);

  lever(); 
}

function lever(){

//hold down mouse to pull down lever
    if (mouseIsPressed  
       & mouseX> 330 && mouseX < 370){

    var x1 = 350; //base x
    var y1 = 293; //base y
    var x2 = constrain(mouseX, 350, 350);//lever only moves vertically
    var y2 = constrain(mouseY, 191, 333);

    
  //stick
    strokeWeight(8);
    stroke(248, 230, 194); //cream
    strokeCap(ROUND);
    line(x1, y1 + (y2/40), x2, y2);
  //ball handle
    push();
    imageMode(CENTER)
    image(ball, x2, y2, 25, 25);
    pop();

    var d = dist(x1, y1, x2, y2); //line length determined by distance from base and handle
    
    }else{ //default lever state
  
  //stick
    strokeWeight(8);
    stroke(248, 230, 194);
    strokeCap(ROUND);
    line(350, 293, 350, 191);
  
  //ball handle
    push();
    imageMode(CENTER)
    image(ball, 350, 191, 25, 25); 
    pop();
      

    }
  }
  
// sleep time expects milliseconds
function sleep (time) {
  return new Promise((resolve) => setTimeout(resolve, time));
}
// based on https://stackoverflow.com/questions/951021/what-is-the-javascript-version-of-sleep

// actual wait time based on clock
function waittime(milliseconds) {
  
  const date = Date.now();

  let currentDate = null;

  do {
    
    currentDate = Date.now();

  } while (currentDate - date < milliseconds);

}


function mouseReleased(){

  if (mouseX> 330 & mouseX < 370){   //end position of lever

    reelA=reelimages[int(random(0,maxlinks))];
    reelB=reelimages[int(random(0,maxlinks))];
    reelC=reelimages[int(random(0,maxlinks))]; 
    
    doneReel=0 // start reel turning, not done yet

    //randomize symbol display with lever push
    // for each reel sleep for a random time between 0 and 200ms then show image
    // left to right
    for (var i =0; i<20; i++){
      
      sleep(50).then (()=> {
        reelAindex=int(random(0,maxlinks));
        reelA=reelimages[reelAindex];
          sleep(50).then(()=> {
          reelB=reelimages[int(random(0,maxlinks))];
            sleep(50).then(()=> {
            reelC=reelimages[int(random(0,maxlinks))]; 
          });
        });
      })
      
      waittime(int(random(0,50))) // wait random time up to 100ms before changing 
    }  
    // wait some time for all reels to settle before calling it done
    sleep(500).then(()=> {
      doneReel=1
    })
  }
}

//lightstrip functions

  function varLight(basex){
    var light ={lighty:20,
                x: basex,
                lightw:4,
                display: createLight,
                move: movestrip,
                speed: 4.0,
                }
    return light;
  }

  function createLight(){
    strokeWeight(1.5);
    stroke(227, 88, 158);//pink outline
    fill(248, 230, 194); //cream
    ellipse(this.x, this.lighty, this.lightw, this.lightw);
  }

  function movestrip(){
    this.x -= this.speed
  }
/*
function displayText(){
  push();
  imageMode(CENTER);
  image(reeltext[jackpotindex], 200, 148);
  pop();

}
/*
/*
function mousePressed(){
  if (mouseX>330 & mouseX<370 &&){
    jackpotwin.stop();
    leverpull.play();
  }
}
*/

LO – 11

I’m choosing to focus on FIELD’s “10,000 Digital Paintings,” which is a brochure design for GF Smith (fine quality paper company.) What caught my attention about this project is its beautiful colors and aesthetics and its slight resemblance of paint in water. Looking into it more, I was able to appreciate the practical quality of generative design. FIELD used custom software to generate 10,000 iterations (different views) of a hypercomplex structure. The results are thousands of brochures that are unique yet fit into a cohesive design theme. I find the intersection between modern generative design and the more traditional print medium interesting and relevant to what I want to study. 

The female artist behind FIELD is Vera-Maria Glahn. She started out as a producer and curator of media arts, performance and film for European film and media festivals in 2003. She later studied Visual Communication several years after and co-founded FIELD. FIELD is a creative studio based in London, U.K. specializing in art and technology; they make both independent and commissioned works for brands and cultural institutions.

Generative art in print!

Project 10

For my sonic story I wanted to create a looped animation involving a water droplet falling into a pond, fish getting caught by a hook and flung out of the water, and the “fish” returning back into the water in the form of a droplet. Logistically, I couldn’t get the animation to flow the way I intended to, but I used sound to create a sense of mood in an otherwise modern positive color story.

I created storyboards in Illustrator prior to “animating” in p5.js to plan out the scenes. They illustrate what my animation is supposed to communicate.

sketch wordpress

//FISH STORY
/*PREMISE: Water drops into a pond, where ripples form.
            Pans down to swimming fish. 
            A fishing hook descends and a fish takes the bait. 
            The fish is yanked out of the water.
            The animation loops.
            */
//global variables
var x; // translate multipliers
var y; 
var sx = 1; //scale multipliers
var sy =1;

function preload() {
    //sounds downloaded from freesound.org
    drop = loadSound("https://courses.ideate.cmu.edu/15-104/f2020/wp-content/uploads/2020/11/waterdrop.wav");
    ambience = loadSound("https://courses.ideate.cmu.edu/15-104/f2020/wp-content/uploads/2020/11/ambience.wav");
    looming = loadSound("https://courses.ideate.cmu.edu/15-104/f2020/wp-content/uploads/2020/11/looming.wav");
}

function setup() {
    createCanvas(480, 480);
    useSound();
    frameRate(40);
}

function soundSetup() { 
    drop.setVolume();
    ambience.setVolume(1.5);
    looming.setVolume(1.2);
}

function draw() {
    background(247, 242, 223); //cream

    //play sound
    print(frameCount.toString());

    if (frameCount == 50) {
      drop.play();
    } else if (frameCount == 100) {
      ambience.play();
    } else if (frameCount == 180) {
      looming.play();
    } else if (frameCount == 400) {
      looming.stop();
    }

    //animate visual assets
     if (frameCount >=0 & frameCount<50) {// water drops
        waterbody(0,0);
        waterdrop(0,frameCount*2);
    } else if (frameCount >= 50 & frameCount <80) {//ripples form
        waterbody(0,0);
        ripple(0,0);
    } else if (frameCount >= 80 & frameCount <100){
        translate(0, -3* frameCount)
        push();
        waterbody(0,0);
        pop();
        ripple(0,0);
    } else if (frameCount >= 100 & frameCount <250) {//teal fish keeps swimming
        waterbody(0, -260);
        //pink fish
        fill(255, 75, 130);
        fish(-frameCount,0);
        //teal fish
        push();
        fill(28, 158, 175);
        translate(300, 250);
        scale(.6);
        fish(-frameCount, 0);
        pop();
        if (frameCount >= 180 & frameCount <250) {//hook descends
        //waterbody(0, -260);
        //main fish
        fill(255, 75, 130);
        fish(-frameCount,0);
        hook(0, frameCount-200);
        }
    /*} else if (frameCount >= 100 & frameCount <180) {//fishes swim by
    /*} else if (frameCount >= 180 & frameCount <250) {//hook descends
        //waterbody(0, -260);
        //main fish
        fill(255, 75, 130);
        fish(-frameCount,0);

        hook(0, frameCount-200);
        */
    } else if (frameCount >= 250 & frameCount <350) {//hook ascends with fish
        waterbody(0,-260);

        hook(0, 100+(-2* frameCount));

        fill(255, 75, 130);
        fish(0,0);

        //teal fish
        push();
        fill(28, 158, 175);
        translate(300, 250);
        scale(.6);
        fish(-frameCount -100, 0);
        pop();

    }
    //loop animation
    if (frameCount> 400){
        frameCount =0;
    }

}
//draw visual assets

//ABOVE WATER
function waterbody(x,y){
    noStroke();
    //waterbody
        push();
        translate(x,y);
        stroke(255); //white outline
        fill(148, 213, 213); //light teal
        rect(0, 260, width, height);
        pop();
    }
function fullwaterbody(x,y){
    noStroke();
    //waterbody
        push();
        translate(x,y);
        stroke(255); //white outline
        fill(148, 213, 213); //light teal
        rect(0, 0, width, height);
        pop();
    }
function ripple(x, y){
    translate(x,y);
    scale(sx,sy);
    noStroke();
    //ripple1
        push();
        fill(28, 158, 175); //dark teal
        ellipse(width/2, 383, 620, 242);
        pop();
    //ripple2
        push();
        stroke(255);
        fill(255, 75, 130); //pink
        ellipse(width/2, 350, 382, 121);
        pop();
    //ripple3
        push();
        fill(96, 201, 224); //light blue
        ellipse(width/2, 350, 189, 60);
        pop();
    //ripple4 (center)
        push();
        stroke(255);
        fill(247, 242, 223); //cream
        ellipse(width/2, 350, 99, 31);
        pop();
    }
function waterdrop(x,y){
    noStroke();
    //waterdrop
        push();
        translate(x,y);
        fill(255, 75, 130); //pink
        ellipse(width/2, 176, 38);
        triangle(width/2, 135, width/2+16, 166, width/2-16, 166);
}

//UNDER WATER
function hook(x,y){
    //hook
    push();
    translate(x,y);
    noFill();
    stroke(28, 158, 175); //dark teal
    strokeWeight(5);
    strokeCap(SQUARE);
    line(width/2 +20, 92-20, width/2 +20, -300);
    arc(width/2, 92-20, 40, 50, 0, PI, OPEN);
    pop();
}

function fish(x,y){
noStroke();
push();
translate(x,y);
ellipse(width/2, height/2, 38);
triangle(width/2+40, height/2, width/2 +10, height/2 -16, width/2 +10, height/2 +16);
triangle(width/2+40, height/2, width/2 +60, height/2 -10, width/2 +60, height/2 +10); //tail
pop();
}

LO – 10

I came across the work of Robert Henke and found his installation, music, and software development work interesting especially with more knowledge of computer generated sounds from this weeks’ lectures. One track I wanted to highlight is “Gobi: The Long Edit” released this spring, a remastered edit of a previous track. What I find very impressive with this track is how organic it feels and the complexity of the layering of frequencies. It’s clear that Henke used a variety of modulators to adjust the frequency and amplitude of the waveforms. The result is an experience that is comparable to the sounds of creatures, vibrations, and ambience of a rainforest. To create something that feels organic and “real” with synthetic, digital means must be a difficult process. It makes me wonder how authentic soundtracks are in movies and TV. To what extent are they manipulated to resemble real-life? Even though I find this track comparable to nature, there is no doubt Henke incorporates his personal artistic vision into this sound art. This is especially apparent in his other tracks like the ones in his album “Archaeopteryx.” These pieces feel more distinctly “electronic” with clear examples of techniques like reverb, delay, and different-shaped waves.

Project 9

This week, I coded a self-portrait based on an old picture of myself. I wanted to express my love for drawing and painting, so I included a draw and erase mode. As the portrait renders, it adopts a painterly style with brushstrokes in the shape of a pencil. When mouse is pressed, it goes into erase mode. Together, they demonstrate the imperfect creative process which I’ve become familiar with.

sketch
Beginning of rendering
Halfway rendered
Near-complete rendering
Erase mode
var img;
var txttype = 1;

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

function setup() {
  createCanvas(480, 480);
  background(255);
  
  img.loadPixels();
  frameRate(10000000);
}

function draw() {
  //image(img, -20, -10, 640, 500);  //fix warped image
  //image (img, 0, 0);
  
  var x = floor(random(img.width)); // random x position
  var y = floor(random(img.height)); // random y position
  var pixel = img.get(x, y); // associate locations of pixels to image

  
  fill(pixel); //text color is pixel color
  noStroke();
  
  //var time = millis(); //text movement = rotation to milliseconds
  //rotateX(time / 1000);
  //rotateY(time / 1000);
  textSize(20);
  if (txttype ==1){ //drawmode
   // rect(x, y, 10, 10);
    textSize(20);
    text ("✎", x, y);
  }
  if (txttype ==2){ //erase mode
    push();
    fill(255);
    textSize(100); //erase faster than draw
    text ("✸", x, y);
    pop();
  }
  
}

function mousePressed(){
//switch between draw and 
  if (txttype ==1){
    txttype =2;
  }
  else
  if (txttype ==2){
    txttype =1;
  }
  }
  

LO – 9

I chose Hayoon’s 7th Looking Outwards post to examine in greater detail. She highlighted the data visualization“We feel fine” project created by Jonathan Harris. Like Hayoon, I found the subject matter of emotion a really intriguing topic to visualize. I had just watched a lecture about the complexity and necessity of emotion as a consideration in design solutions earlier this semester; this made data visualization of this concept all more important in my eyes. I also took note of the extensive use of color to categorize information. Furthermore, I believe that the use of text and simple shapes was pretty ingenious at representing complex information, especially with a concept as abstract and conventionally-unquantifiable as emotion. It goes to show that smart design does not need to use the most groundbreaking techniques, but can instead solve the problem efficiently using what is available. I also thought it was a good design choice to incorporate photographs as a way to humanize and contextualize the data. In examining Hayoon’s interpretations of her chosen project, I was able to take a different approach to examining Harris’ insightful initiative.

I especially enjoyed Harris’ interpretation of mood swings and how the colors relate 2 data visualizations together.

LO – 8

I found the information designer Stefanie Posavec very inspiring — she spoke at Eyeo in 2018. With roots in communication and graphic design studying in various American colleges, Stefanie is now based in London and is most known for exploring non-traditional representations of data across a variety of mediums. Her ability to translate data (collected from her personal life and for the service of various enterprises who commission her) into consumable visual pieces of art and design is very interesting to me as it is both visually appealing and accessible to more people than traditional fine arts. In this way, she is both an artist and designer, solving problems through translating data while instilling her personal vision and at times, using data from her personal life.

Eyeo Talk 2018

I find all of Stefanie’s work interesting, but I really enjoyed one of her most notable projects Dear Data, where she and English designer Giorgia Lupi sent each other hand-drawn postcards visualizing data collected over their everyday lives, over the course of a year. The analog format of these data visualizations really strip away the complexity that many associate with code. Even without code, information can be communicated in an elegant, concise way. I wish to continue exploring Stefanie’s work to continue incorporating my artistic voice into pragmatic and interesting solutions.

Clever and creative ways to represent data, concisely delivered in a hand-drawn postcard

Project 7

After exploring the variety of equations on the MathWorld site, I decided to use a heart curve to create peaches. My peaches are inspired by Japanese peaches, and they change color and size based on mouseX.

peaches
Japanese peach
function setup() {
    createCanvas(480, 480);
}

function draw() {
    background(150, 240, 210); //mint background
    //4 peaches
    for (var x = 140; x <= width; x += 200) {
        for (var y = 140;y <= height; y+= 200) {
        push();
        leaf(x, y);
        pop();
        push();
        translate(x, y);
        peach();
        pop();
        }
    }
}
function leaf(x, y){
    push();
    stroke(35, 153, 139);
    strokeWeight(2);
    strokeCap(SQUARE);
    fill(50, 200, 180);
    arc(x+15, y+15, 70, 40, PI/4, PI + PI/3, OPEN);
      //arc(width/220 - 25, height/2, 40, 40, PI-PI/3, , OPEN);
    pop();
  
}
function peach(){
    var colorshift = constrain(mouseX, 5, 50);
    fill(255, 180- colorshift/4, 120+colorshift/2);// peach become redder based on mouseX
    stroke(250, 250, 250); //offwhite outline
    scale(2.5);//no need to rotate peach shape
    beginShape();
    for (var i = 0; i < 2*PI; i+=0.1) {
        var mx = constrain(mouseX/300, 0.7, 1.2); //mouseX multiplier
        var x = mx*20*pow(sin(i),3);
        var y = mx*20*cos(i)-4*cos(2*i)-2*cos(3*i);
        vertex(x,y); 
    }
    endShape();
}

LO 7

COVID-19 cases across the 50 states over the course of the pandemic

I found Pitch Interactive Inc.’s Ebb and Flow: COVID-19 Daily Cases Across the US a very effective data visualization tool, not to mention very relevant during the pandemic. The tool plots the daily cases and fatalities of each state in the U.S. in relation to each other over the course of the entire pandemic. I think the use of color and the visual nature of the graph effectively instills alertness and demonstrates the severity of the pandemic. As we enter the 7th month of dealing with this public health crisis, the inclusion of all states on the map is essential for the public to access to inspire better community action. People living in states that are doing worse in the current moment will feel a greater sense of responsibility to do better, as they can see their state “called out,” their performance directly plotted against “better” states, and how it affects the holistic curve of the United States. With our country becoming increasingly divided, a tool like this is not only scientifically representative, but has the potential to inspire social and political unity. I find it more effective than the largely achromatic COVID-19 graph provided by Google that forces users to choose their state from a drop-down menu.

Magnifying function displays state’s curve in comparison to the national curve when the user mouses over the state’s curve on the main map

I believe the algorithm is largely determined by some of the functions that made the “stock market tracker” from the last lab, like arrays and array methods like push. Instead of using the noise function to generate the data values, real COVID data from The New York Times would determine the “marketvalue” array. A loop will also hold the array so that it updates daily without manual input. I wouldn’t consider this project to have a lot of artistic considerations, but I do believe the color and other visual decision made make this a good form of communication design made functional with code.

Deaths in America due to COVID-19

Project 06 – Abstract Clock

I took inspiration from cuckoo clocks to make an abstract clock based on a face. The clock gets increasingly fatigued as its tongue inches out with every minute– its cheeks flush and the background also becomes redder with every hour. Saliva drip documents seconds.

sketch
Concept sketch
Illustrator sketch


function setup() {
  createCanvas(480, 480);
  // time
    var minShift= 2 * minute();
}

function draw(){
  
  //background
  var top = color(200, 219, 162); // pale green
  var bottom = color(124 +3*hour(), 124-hour(), 232- 3*hour()); // purple, turns redder with hours
  setGradient(top, bottom); // background gradient
    //offwhite wall
    noStroke();
    fill(240, 244, 237); //offwhite
    rect(368, 0, 124, height);
  clock();
  
}

function setGradient(color1, color2) { //background gradient
    for(var a = 0; a <= height; a++) {
      var amount = map(a, 0, height, 0, 1);
      var back = lerpColor(color1, color2, amount);
      stroke(back);
      line(0, a, width, a);
    }
}

function clock(){
  //base face
  fill(67, 40, 144);
  rect(0, 58, 265, 330, 0, 110, 0, 0);
  //face side panel
  fill(234, 249, 48); //neon yellow
  rect(-161, 58, 265, 330, 0, 110, 0, 0);
  //pendulum
  fill(208, 216, 91); //darker yellow
  rect(120, 388, 5, 92);
  rect(145, 388, 5, 92);
  //mouth opening
  rect (181, 300, 75, 50, 24, 0, 0, 0);
  //teeth
  fill(240, 244, 237);
  rect (228, 300, 13, 10);
  rect (243, 300, 13, 10);
  //eyes
  eyes();
  //blush
  blush();
  //nose
  fill(170, 192, 255); //lavender
  rect(177, 163, 24, 120);
  triangle(201, 164, 201, 284, 256, 284);
  fill (234, 249, 48); //neon yellow
  triangle(177, 164, 177, 284, 232, 284);
  //lines
  stroke(234, 249, 48);
  strokeWeight(0.75);
  line (83, 163, 248, 163);
  line (177, 141, 177, 379);
  //tongue
  tongue();
  
}

function eyes(){
  //whites
  push();
  fill(240, 244, 237);
  stroke(255, 73, 165);
  strokeWeight(3);
  strokeCap (SQUARE);
  arc(134, 228, 80, 80, PI, TWO_PI, OPEN);
  arc(230, 215, 61, 61, PI, TWO_PI, OPEN);
  //pupils
  fill(255, 73, 165); //pink
  ellipse(153, 213, 22);
  ellipse( 240, 203, 19);
  pop();
}

function blush(){
  fill(255, 73, 165 - 2*hour()); //pink becomes more red with hours
  ellipse(247, 247, 48+ hour());// blush increases with hours
  ellipse(111, 277, 74 + hour());
}

function tongue(){
  fill(255, 73, 165); //pink
  noStroke();
  var minShift= 2*minute();
  rect (181, 334, 154 + minShift, 16, 0, 15, 0, 0); //tongue length increases with minutes
  bird();
  
  // saliva drips by seconds and follows tongue
  fill(170, 192, 255); //lavender
  ellipse(307+ minShift, 376+ second(), 18); 
  triangle(300 + minShift, 370+ second(), 314+ minShift, 370+ second(), 307 + minShift, 360+ second());
  fill(170, 206, 255); //lighter lavender
  ellipse(287+ minShift, 364+ 2*second(), 26); 
  triangle(277 + minShift, 356+ 2*second(), 297+ minShift, 356+ 2*second(), 287 + minShift, 340+ 2*second());
}

function bird(){
  var minShift = 2* minute();
  //feet
  fill(208, 216, 91); //darker yellow
  rect(296 + minShift, 331, 15, 4, 0, 3, 0, 0);
  //legs
  stroke(208, 216, 91); //darker yellow
  strokeWeight(2);
  line(297 + minShift, 306, 297 + minShift, 334);
  line(301 + minShift, 306, 301 + minShift, 334);
  
  //body
  fill(255, 73, 165); //pink
  noStroke();
  ellipse(297 + minShift, 293, 42);
  triangle(280 + minShift, 280, 267+ minShift, 314, 297+ minShift, 314);
  push();
  fill(170, 192, 255); //lavender
  arc(298 + minShift, 293, 42, 42, -QUARTER_PI, HALF_PI, OPEN); //belly
  pop()
  //wing
  fill(240, 244, 237);
  arc(275 +minShift, 295, 43, 43, -QUARTER_PI, HALF_PI, OPEN);
  //head
    //beak
    fill(208, 216, 91); //darker yellow
    triangle (320 + minShift, 260, 320 + minShift, 271, 339 + minShift, 266);
    //head
    fill(255, 73, 165);
    ellipse(313 + minShift, 266, 23);
    //eye
    fill(234, 249, 48); //neon yellow
    ellipse(316 + minShift, 265, 6);

}