Week 15 – Final Project

My project is a simple interactive and informative game based on the theme of Covid-19. The setting takes place in a store with racks that display different supplies people use to prevent the spread of the disease. The main problem I realize these days is that people don’t seem to know which supplies and masks are necessary/appropriate during the pandemic. When you run my program, you should drag the objects in order from numbers 1-12 to either the shopping bag or the trash can. You should place the supply on the shopping bag if you think the object is necessary/effective during the pandemic, and place the supply on the trash can if you think the object is not necessary/effective during the pandemic. You will be able to see texts that explain whether the supplies are helpful or not in preventing Covid-19 when you place them onto the shopping bag or trash can. Also, Christmas season is coming. In celebration of the holiday, I’ve added some Christmas lights to the shop, like how real stores do during the holiday season. If I had more time, I would like to find out other ways to drag objects without having them collect multiple objects when they are overlapped in similar locations on canvas. Although it isn’t a problem in running my program and playing the game, adding codes that help objects be selected one by one despite overlapped locations would be great if I had more time to work on the project.

sketch
//Stefanie Suk
//ssuk@andrew.cmu.edu
//15-104 Section D

//Covid-19 Object Variables
var dentalMask = makedentalMask();
var n95Mask = maken95Mask();
var spongeMask = makespongeMask();
var clothMask = makeclothMask();
var homemadeMask = makehomemadeMask();
var bandanaMask = makebandanaMask();
var thermometer = makeThermometer();
var waterBottle = makewaterBottle();
var toiletPaper = maketoiletPaper();
var soap = makeSoap();
var lowSanitizer = makelowSanitizer();
var highSanitizer = makehighSanitizer();

//Shopping bag and Trash Can Variables
var shoppingBag = makeshoppingBag();
var trashCan = maketrashCan();

//Array of Covid-19 supplies
//Array of Shopping bag and Trashcan 
var covidObjects = [dentalMask, n95Mask, spongeMask, clothMask, homemadeMask, bandanaMask, 
                    thermometer, waterBottle, toiletPaper, soap, lowSanitizer, highSanitizer];
var bagandTrash = [shoppingBag, trashCan];

//offset variable for mouse press and drag supplies
var offsetX;
var offsetY;

//Objects for Covid-19 supplies, Shopping bag, and Trashcan with specific datas
function makeshoppingBag() {
    var shoppingBag = {
        imageUrl: "https://i.imgur.com/WdeIUp0.png",       //imageURL: url of object images
        positionX: 75,                                     //positionX: X position of objects on canvas
        positionY: 375,                                    //positionY: Y position of objects on canvas
    }
    return shoppingBag;
}

function maketrashCan() {
    var trashCan = {
        imageUrl: "https://i.imgur.com/5jjADwl.png",
        positionX: 330,
        positionY: 375,
    }
    return trashCan;
}

function makedentalMask() {
    var dentalMask = {
        imageUrl: "https://i.imgur.com/Lsg9xeK.png",
        imagex: 45,
        imagey: 25,
        positionX: 41,
        positionY: 167,
        informationTwo: "Dental Masks, "
                        + "Dental masks are effective in preventing Covid-19.",                                //informationTwo: texts when placed on trashcan
        information: "Dental Masks, Effective. "
                    + "Dental masks are designed to prevent the spread of droplets and splatters. "
                    + "Wearing surgical masks can reduce the spread of respiratory infection."
                    + "*Important* Surgical masks are designed to be used only once."                      //information: texts when placed on shopping bag
    }
        return dentalMask;
}

function maken95Mask() {
    var n95Mask = {
        imageUrl: "https://i.imgur.com/b5hh3hx.png",
        imagex: 45,
        imagey: 25,
        positionX: 106,
        positionY: 167,
        informationTwo: "N95 Masks, N95 masks are effective in preventing Covid-19.",
        information: "N95 Masks, Effective. N95 is the most protective mask against coronavirus and other respiratory "
                    + "diseases. It filters out 95% of particles from the air."
    }
    return n95Mask;
}

function makespongeMask() {
    var spongeMask = {
        imageUrl: "https://i.imgur.com/KhnI7An.png",
        imagex: 45,
        imagey: 25,
        positionX: 171,
        positionY: 169,
        informationTwo: "Sponge Mask, Not Effective. Sponge mask, or neoprene mask, may be designed to be comfortable, but "
                        + "is not effective in preventing the spread of Covid-19 disease. "
                        + "*Tips* Adding replaceable filer can help with the mask's effectiveness.",
        information: "Sponge Mask, Sponge masks are not effective in preventing Covid-19."
    }
    return spongeMask;
}

function makeclothMask() {
    var clothMask = {
        imageUrl: "https://i.imgur.com/SierEPM.png",
        imagex: 45,
        imagey: 25,
        positionX: 41,
        positionY: 242,
        informationTwo: "Effective, Cloth Masks bought in stores are effective in preventing Covid-19.",
        information: "Cloth Mask, Effective. A typical store-bought cloth mask is approximately 50% protective, but "
                    + "depending on its construction and quality, it can protect the virus to about 80-95%."
    }
    return clothMask;
}

function makehomemadeMask() {
    var homemadeMask = {
        imageUrl: "https://i.imgur.com/scSV8qR.png",
        imagex: 45,
        imagey: 25,
        positionX: 106,
        positionY: 242,
        informationTwo: "Handmade Mask, Not Effective. A single-layered handmade mask only filters 1% of particles "
                        + "from air. A two-layered cotton mask can filter only about 35% of particles. *Tips* More "
                        + "layers with more dense woven fabrics can increase the protection.",
        information: "Not Effective, Handmade Masks are not effective in preventing Covid-19."
    }
    return homemadeMask;
}

function makebandanaMask() {
    var bandanaMask = {
        imageUrl: "https://i.imgur.com/QX6uDBJ.png",
        imagex: 45,
        imagey: 25,
        positionX: 171,
        positionY: 242,
        informationTwo: "Bandanas, Not Effective. Covering your mouth and nose with a bandana provides little "
                        + "protection against droplets and does not filter particles from air.",
        information: "Not Effective, Bandanas are not effective in preventing Covid-19."
    }
    return bandanaMask;
}

function makeThermometer() {
    var thermometer = {
        imageUrl: "https://i.imgur.com/qbeSsFP.png",
        imagex: 30,
        imagey: 40,
        positionX: 285,
        positionY: 160,
        informationTwo: "Effective, Thermometers are effective in preventing Covid-19.",
        information: "Thermometer, Effective. Using a thermometer to check your body temperature daily is always "
                    + "important in preventing the spread of Covid-19. *Important* Make sure to check your body temperature does not go over 37.8C."
    }
    return thermometer;
}

function makewaterBottle() {
    var waterBottle = {
        imageUrl: "https://i.imgur.com/0h5YpiF.png",
        imagex: 20,
        imagey: 45,
        positionX: 359,
        positionY: 156,
        informationTwo: "Not Effective, Water. Suggestions are that drinking every 15 minutes would wash any virus down the throat, but there are at "
                        + "least thousands of viruses that we come into contact with and it’s highly unlikely you would wash all that virus down. "
                        + "Thus, the primary way the virus is transmitted is through respiratory droplets in the air.",
        information: "Not Effective, Drinking water is not effective in preventing Covid-19."
    }
    return waterBottle;
}

function maketoiletPaper() {
    var toiletPaper = {
        imageUrl: "https://i.imgur.com/pxMwAgb.png",
        imagex: 35,
        imagey: 35,
        positionX: 415,
        positionY: 161,
        informationTwo: "Toilet Papers, Not effective. There is absolutely no reason to buy toilet papers for preventing Covid-19. Stop stockpiling "
                        + "toilet papers, because they don’t help you prevent the spread of Covid-19.",
        information: "Not Effective, Toilet Papers are not effective in preventing Covid-19."
    }
    return toiletPaper;
}

function makeSoap() {
    var soap = {
        imageUrl: "https://i.imgur.com/JQBa2uV.png",
        imagex: 40,
        imagey: 30,
        positionX: 285,
        positionY: 239,
        informationTwo: "Effective, Soaps are effective in preventing Covid-19.",
        information: "Soaps, Effective. Washing your hands regularly with soap and water break germs up and remove them, which is one of the most "
                    + "effective ways to prevent Covid-19 from spreading."
    }
    return soap;
}

function makelowSanitizer() {
    var lowSanitizer = {
        imageUrl: "https://i.imgur.com/YdnSXSO.png",
        imagex: 20,
        imagey: 45,
        positionX: 359,
        positionY: 231,
        informationTwo: "40% Alcohol Sanitizers, Not Effective. Sanitizers with 40% alcohol doesn’t really help with disinfection. *Important* "
                        + "Not only sanitizers, but any alcohol solutions that contain less than 70% alcohol is ineffective.",
        information: "Not Effective, Sanitizers with 40% alcohol are not effective in preventing Covid-19."
    }
    return lowSanitizer;
}

function makehighSanitizer() {
    var highSanitizer = {
        imageUrl: "https://i.imgur.com/YZihMaD.png",
        imagex: 20,
        imagey: 45,
        positionX: 424,
        positionY: 231,
        informationTwo: "Effective, Sanitizers with 70% alcohol are effective in preventing Covid-19.",
        information: "70% Alcohol Sanitizers, Effective. Sanitizers (or any alcohol solutions) with 70% alcohol or more are "
                    + "perfect for disinfecting your hands and objects."
    }
    return highSanitizer;
}

function preload() {
    //Preload background image
    backgroundImage = loadImage("https://i.imgur.com/uRLr2HC.png");
    //Preload object images, push objects to new array
    bagandtrashImages = [];
    for (var i = 0; i < bagandTrash.length; i++) {
        bagandtrashImages.push(loadImage(bagandTrash[i].imageUrl));
    }
    covidobjectImages = [];
    for (var i = 0; i < covidObjects.length; i++) {
        covidobjectImages.push(loadImage(covidObjects[i].imageUrl));
    }
}

function setup() {
    createCanvas(500, 600);
    frameRate(10); //Frame rate for christmas lights
}

function draw() {
    //load images of background, covid objects, bag and trash 
    background(220);
    image(backgroundImage, 0, 0, 500, 600);

    for (var i = 0; i < bagandTrash.length; i++) {
        image(bagandtrashImages[i], bagandTrash[i].positionX, bagandTrash[i].positionY, 90, 100);
    }
    for (var i = 0; i < covidObjects.length; i++) {
        image(covidobjectImages[i], covidObjects[i].positionX, covidObjects[i].positionY, covidObjects[i].imagex, covidObjects[i].imagey);
        //drag object with mouse
        if (covidObjects[i].drag) {
            covidObjects[i].positionX = offsetX + mouseX;
            covidObjects[i].positionY = offsetY + mouseY;
        }
        //When objects placed in specific locations (bag and trashcan), text appears
        if ((covidObjects[i].positionX > 65) & (covidObjects[i].positionX < 145)) {
            if ((covidObjects[i].positionY > 400) && (covidObjects[i].positionY < 460)) {
                noStroke();
                fill(163, 160, 72);
                rect(3, 502, 486, 100);
                fill(0);
                text(covidObjects[i].information, 20, 520, 460, 70);                          //texts appear when placed on shopping bag
            }
        }

        if ((covidObjects[i].positionX > 310) & (covidObjects[i].positionX < 395)) {
            if ((covidObjects[i].positionY > 365) && (covidObjects[i].positionY < 465)) {
                noStroke();
                fill(163, 160, 72);
                rect(3, 502, 486, 100);
                fill(0);
                text(covidObjects[i].informationTwo, 20, 520, 460, 70);                       //texts appear when placed on trashcan
            }
        }
    }

    //lightbulbs on ceiling for Christmas holiday season
    for (var i = 5; i < 600; i = i+13) {
        push();
        translate(i, 5);
        makelightBulb();
        pop();
    }
}

function mousePressed() {
    //drag covid objects with mouse when mousepressed
    //drag when mouse pressed in specific range of object
    for (var i = 0; i < covidObjects.length; i++) {
        if (mouseX > covidObjects[i].positionX - 25 & mouseX < covidObjects[i].positionX + 25 && mouseY > covidObjects[i].positionY - 25 && mouseY < covidObjects[i].positionY + 25) {
            offsetX = covidObjects[i].positionX - mouseX;
            offsetY = covidObjects[i].positionY - mouseY;
            covidObjects[i].drag = true;
        }
    }
}

function mouseReleased() {
    for (var i = 0; i < covidObjects.length; i++) {
        covidObjects[i].drag = false;
    }
}

function makelightBulb() {
    //variables for lightbulb colors
    var lightColor;
    var lightVariations;

    //red, green, blue, yellow randomly used
    lightColor = floor(random(1, 5));
    if (lightColor === 1) {
        lightVariations = [255, 0, 0];
    }
    if (lightColor === 2) {
        lightVariations = [0, 255, 0];
    }
    if (lightColor === 3) {
     lightVariations = [0, 0, 255];
    }
    if (lightColor === 4) {
     lightVariations = [255,255,0];
    }

    //left side of canvas, square lightbulbs
    //right side of canvas, circle lightbulbs
    fill(lightVariations);
    if (mouseX > width/2) {
        ellipse(5, 5, 7, 7);
    } else {
        rect(2, 2, 7, 7);
    }
}

Project 11 – Generative Landscape

One of my hobbies is collecting adorable dolls, especially teddy bears. I like to decorate my boring room with dolls like teddy bears to lighten up the mood. I have always imagined a shop specifically for teddy bears, so I decided to create a visual of my dream shop in this project. The unique part of this shop is that it has a teddy bear conveyor belt. This conveyor belt has different types of teddy bears with different colors and characteristics. I have made the shop colored in shades of beige to really focus on the bright colors of the teddy bears.

sketch
//Stefanie Suk
//15104 Section D

var brownTeddy;
var blueTeddy;
var pinkTeddy;
var purpleTeddy;
var redTeddy;

var base = []; //array for base under teddy bears
var x; //position of base
var speed;

var cloudX = 60;
var cloudY = 100;

var teddyBears = 
["https://i.imgur.com/VdXQHac.png",
"https://i.imgur.com/l87wQNo.png",
 "https://i.imgur.com/1xcChWa.png",
 "https://i.imgur.com/olZHcs2.png",
 "https://i.imgur.com/pW0wt4W.png"]

function preload(){ //preloading teddy bear images 
    brownTeddy = loadImage(teddyBears[0]);
    blueTeddy = loadImage(teddyBears[1]);
    pinkTeddy = loadImage(teddyBears[2]);
    purpleTeddy = loadImage(teddyBears[3]);
    redTeddy = loadImage(teddyBears[4]);

    clock = loadImage('https://i.imgur.com/QBWxgao.png');
    tablePattern = loadImage('https://i.imgur.com/jZoPb4m.png');
}

function setup() {
    createCanvas(450, 450);
    frameRate(17);

    var dist = 0;
    for (var i = 0; i < 500; i++){ //creating 500 variations of teddy bears
        base[i] = varBase(dist);
        dist += 200; //dist of base and teddy bears
    }
}

function draw(){
    //drawing shop
    drawShop(); 
    //drawing clock
    image(clock, 355, 50);
    //drawing pattern on conveyor table
    image(tablePattern, -150, 325, 310, 13);
    image(tablePattern, 157, 325, 310, 13);
    //drawing cloud
    drawCloud();
    translate(200, -20);
    drawCloud();
    translate(-100, 30);
    drawCloud();
    //drawing base and belt
    showBase();
    conveyorBelt(); 
}

//drawing teddy bear shop
function drawShop(){
    noStroke();

    //back wall
    fill(234, 224, 212);
    rect(0, 0, width, 235)

    //window
    fill(113, 207, 230);
    rect(20, 20, 300, 250);

    //four borders of window
    fill(80, 46, 46);
    rect(20, 20, 300, 10);
    rect(20, 260, 300, 10);
    rect(20, 20, 10, 250);
    rect(320, 20, 10, 250);
    //division of window
    rect(220, 20, 5, 250);
    rect(20, 140, 300, 5);

    //conveyer belt
    fill(88, 87, 86);
    rect(0, 235, width, 90);

    //bottom conveyor belt table
    fill(214, 196, 173);
    rect(0, 325, width, 180);

    //text on conveyor belt table
    textSize(25);
    textStyle(ITALIC);
    fill(89, 80, 68);
    text('S.S Teddy Bear Shop', 110, 395)
  
}

//drawing cloud in window
function drawCloud(cloudx, cloudy) {
    noStroke();
    fill(255);
    ellipse(cloudX,cloudY,30);
    ellipse(cloudX+10,cloudY+10,30);
    ellipse(cloudX+20,cloudY-10,50,40);
    ellipse(cloudX+30,cloudY+5,30);
}

//variables for base
function varBase(basex){
    var base = {x: basex,
                basey: 275,
                basew: 120,
                baseh: 70,
                display: createBase,
                move: moveBase,
                speed: -8.0,
                teddyBears: random([brownTeddy, blueTeddy, pinkTeddy, purpleTeddy, redTeddy]) //random teddy bears appear on conveyor belt
    }
    return base; 
}

function createBase(){

    fill(209, 165, 109);
    ellipse(this.x, this.basey, this.basew, this.baseh); //drawing circular base under teddy bears


    //creating different varieties of teddy bears
    if(this.teddyBears == brownTeddy){
        image(brownTeddy,this.x-42, 180, brownTeddy.width*1.5, brownTeddy.height*1.5);  
    }
    if(this.teddyBears == blueTeddy){
        image(blueTeddy,this.x-42, 170, blueTeddy.width*1.5, blueTeddy.height*1.5);  
    }
    if(this.teddyBears == pinkTeddy){
        image(pinkTeddy,this.x-42, 175, pinkTeddy.width*1.5, pinkTeddy.height*1.5);  
    }
    if(this.teddyBears == purpleTeddy){
        image(purpleTeddy,this.x-42, 165, purpleTeddy.width*1.5, purpleTeddy.height*1.5);  
    }
    if(this.teddyBears == redTeddy){
        image(redTeddy,this.x-42, 180, redTeddy.width*1.5, redTeddy.height*1.5);  
    }

}

//calling move and show function of base
function showBase(){
    for(var i = 0; i < base.length; i++){
        base[i].display();
        base[i].move();
    }
}

//speed of base on conveyor best
function moveBase(){
    this.x += this.speed; 
}

function conveyorBelt(){
    for(var i = 0; i < 400; i++) { 
        var moveBelt = i * 25;
        line(x + moveBelt, height, x * moveBelt, height);
    }
    x += speed;
}
Rough sketch of project visual

Looking Outwards 11 – A Focus on Women Practitioners

Image of Camille Utterback’s Entangled

Camille Utterback is an artist who creates digital and interactive art. She is currently an Assistant Professor of Art Practice in the Department of Art & Art History, as well as Computer Science in the Department of Engineering at Stanford University. She holds a bachelor’s degree in Art from Williams College, and a Masters degree from The Interactive Telecommunications Program at New York University’s Tisch School of the Arts. Utterback’s works explore the different possibilities of relation between computational systems and human movement. She focuses and studies the beauty of body and physicality into her works. In this Looking Outwards, I want to talk about Utterback’s interactive installation called Entangled. This artwork encourages audiences to interact with slightly translucent screens that project images on both sides. Body movements of the audiences cause images of computer cables, earbuds, ropes, and other different types of cords to form and disappear on the corresponding side’s projection. What I really admire about this installation is that it not only allows an interaction between the installation and audience, but also allows interaction between the audience and audience. The fact people can see other people’s body movements through the translucent screens amazes me that a single installation can show many different explorations like embodied relationships, depth, and volumetric complexity.

Website: http://camilleutterback.com/projects/entangled/

Video of Camille Utterback’s Entangled

Project 10 – Sonic Story

In this project, I’ve created a story of a journey of birds flying across the sky in different weathers. I’ve used sounds of snow, rain, birds, and cars to show different weathers and scenes of the story. Each scene shifts to different weathers when keys ‘0’ ‘1’ and ‘2’ are pressed. The sun rises and falls with mouse Y.

sketch
//Stefanie Suk
//15-104 Section D

//This stroy is about a journey of birds flying through different scenes of weather.
//Journey of birds flying in a sunny day, snowy day, and rainy day. 

var story = "start"; //scene of story initially set to "start"

var winterSnow = []; // array to hold snowflake objects

var rainFalls = [];

var cloudX = 0;

var birdImage = [];
var birdFrame = 0;
var birdx = 0;
var birdTime = 0;

var snowbirdImage = [];
var snowbirdFrame = 0;
var snowbirdx = 0;
var snowbirdTime = 0;

var car = [];
var carNum = 10; //number of cars

var sun;

function preload() {
  rainSound = loadSound("https://courses.ideate.cmu.edu/15-104/f2020/wp-content/uploads/2020/11/rain-3.wav");
  snowstormSound = loadSound("https://courses.ideate.cmu.edu/15-104/f2020/wp-content/uploads/2020/11/snowstorm.wav");
  birdSound = loadSound("https://courses.ideate.cmu.edu/15-104/f2020/wp-content/uploads/2020/11/bird-3.wav");
  carSound = loadSound("https://courses.ideate.cmu.edu/15-104/f2020/wp-content/uploads/2020/11/car-2.wav");
  birdchirpSound = loadSound("https://courses.ideate.cmu.edu/15-104/f2020/wp-content/uploads/2020/11/birdchirp.wav");

  //Bird images, for rain scene
  birdImage[0] = loadImage("https://i.imgur.com/tg67EJp.png");
  birdImage[1] = loadImage("https://i.imgur.com/NzqZdC6.png");
  birdImage[2] = loadImage("https://i.imgur.com/PoLXRp1.png");
  birdImage[3] = loadImage("https://i.imgur.com/RR23waU.png");
  birdImage[4] = loadImage("https://i.imgur.com/bomc4zU.png");
  birdImage[5] = loadImage("https://i.imgur.com/yvMEopS.png");
  birdImage[6] = loadImage("https://i.imgur.com/NNqLSfZ.png");
  birdImage[7] = loadImage("https://i.imgur.com/JgASL5k.png");
  birdImage[8] = loadImage("https://i.imgur.com/yDRvXLi.png");
  birdImage[9] = loadImage("https://i.imgur.com/sH0IWH2.png");

  //Bird images with snow on top, for snow scene
  snowbirdImage[0] = loadImage("https://i.imgur.com/9UBa9S7.png");
  snowbirdImage[1] = loadImage("https://i.imgur.com/P13A1Gj.png");
  snowbirdImage[2] = loadImage("https://i.imgur.com/WLn63gv.png");
  snowbirdImage[3] = loadImage("https://i.imgur.com/rYCLLmV.png");
  snowbirdImage[4] = loadImage("https://i.imgur.com/65hbFvj.png");
  snowbirdImage[5] = loadImage("https://i.imgur.com/ifH75Di.png");
  snowbirdImage[6] = loadImage("https://i.imgur.com/8ER6XPt.png");
  snowbirdImage[7] = loadImage("https://i.imgur.com/AXF0fpu.png");
  snowbirdImage[8] = loadImage("https://i.imgur.com/ONvchFq.png");
  snowbirdImage[9] = loadImage("https://i.imgur.com/W0Wu9Ou.png");


}

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

  //snow
  fill(240);
  noStroke();

  //rain
  for (var i = 0; i < 400; i++) {
    rainFalls[i] = new drawRain();
  }

  //car
  for (let i = 0; i < carNum; i++) {
    car[i] = new Car(random(height),
      random(width),
      color(random(255), random(255), random(255)), //random car color
      random(1, 8), //random car speed
      random(20, 90) //random car size
    );
    print(car[i]);
  }

  birdSound.loop(); //looping bird sound 

  rectMode(CENTER);
  useSound();

}

function soundSetup(){
  rainSound.setVolume(0.5);
  snowstormSound.setVolume(0.7);
  birdSound.setVolume(0.5)
  birdchirpSound.setVolume(0.8);
}

function draw() {

  if (frameCount == 1) {
    birdchirpSound.play();
  }

  //snow
  let snowT = frameCount/10; //time for snow falling

  //each scene
  if (story == "start") { //starting scene

    //sun
    //background color change, mouse Y
    //sun move up and down
    sun = map(mouseY, 0, 600, 200, 0); //map background color
    background(0, sun/2, sun);
    noStroke();
    fill(255, 255, 0);
    ellipse(300,mouseY,60,60);

    fill(255);
    textSize(10);
    text("Press keys '1' and '2' to change scene", 40, height/2-40);
    text("Press key '0' to reset", 40, height/2-20);

    drawCloud();

    drawBird();

	} else if (story == "frame1") { //snowing scene
    
    //sun
    //background color change, mouse Y
    //sun move up and down
    sun = map(mouseY, 0, 500, 100, 0);
    background(0, sun/2, sun);
    fill(255, 255, 0);
    ellipse(300,mouseY,60,60);

    //snow
    fill(250);
    for (let i = 0; i < random(6); i++) { // drawing random snows
	   winterSnow.push(new drawSnow());
    }
  	for (let snowParticles of winterSnow) {
      snowParticles.display(); //looping, display snow
  	  snowParticles.update(snowT); // updating snow
  	}

    //cars
    for (let i = 0; i < 10; i++) {
      car[i].move();
      car[i].display(); //making cars show
    }

    //cloud
    drawCloud();

    //bird with snow
    drawSnowbird();

  } else if (story == "frame2") { //raining scene
    
    //sun
    //background color change, mouse Y
    //sun move up and down
  	sun = map(mouseY, 0, 600, 50, 0); //map background color
    background(0, sun/2, sun);
    noStroke();
    fill(255, 255, 0);
    ellipse(300,mouseY,60,60);

    //rain
  	for (var i = 0; i < rainFalls.length; i++) {
    rainFalls[i].rainMove();
    rainFalls[i].rainShow();
  	}

    //cars
    for (let i = 0; i < 10; i++) {
      car[i].move();
      car[i].display(); //making cars show
    }

    //bird
    drawBird();
  }

}

function drawSnow() {
  this.snowX = 0; //position X of snow
  this.snowY = random(-70, 10); //position Y of snow
  this.snowstartAngle = random(0, PI*3); //starting angle of snow
  this.snowSize = random(1, 5.5);

  //radius of snow
  //make snow spread evenly throught canvas
  this.snowRadius = sqrt(random(pow(width, 2)));

  this.update = function(snowTime) {
    // snow fall spiral, like wind blowing
    var snowSpeed = 0.5; // angled speed
    var snowAngle = snowSpeed * snowTime + this.snowstartAngle;
    this.snowX = this.snowRadius * cos(snowAngle) + width/2;

    // various sizes of snow falling at different speeds
    this.snowY += pow(this.snowSize, 0.5);

  }

  this.display = function() {
    ellipse(this.snowX, this.snowY, this.snowSize);
  }



}

function drawRain() {
  this.rainX = random(width); //pos X, rain falling randomly throughout canvas
  this.rainY = random(-400, -100); //pos Y
  this.rainS = random(0, 15); //rain size
  this.rainLength = map(this.rainS, 0, 5, 10, 15); //rain length
  this.rainSpeed = map(this.rainS, 0, 15, 5, 25); //map rain speed

  this.rainMove = function() {
    this.rainY = this.rainSpeed + this.rainY;
    var rainFalling = map(this.rainS, 0, 15, 0, 0.3); //falling speed of rain
    this.rainSpeed = this.rainSpeed + rainFalling;

    //keeping rain fall
    if (this.rainY > height) {
      this.rainY = random(-300, -50);
      this.rainSpeed = map(this.rainS, 0, 15, 5, 10);
    }
  }

  this.rainShow = function() {
    var rainSize = map(this.rainS, 0, 15, 0.5, 2); //map rain size
    strokeWeight(rainSize);
    stroke(205, 235, 244);
    line(this.rainX, this.rainY, this.rainX, this.rainY+this.rainLength);
  }
}

function drawCloud(){

  //translate cloud
  translate(cloudX, 0);
  
  // draw cloud
  fill(255);
  noStroke();
  ellipse(100,100,50);
  ellipse(110,110,50);
  ellipse(120,95,50,60);
  ellipse(130,105,50);

  ellipse(200,200,50);
  ellipse(210,210,50);
  ellipse(220,195,50,60);
  ellipse(230,205,50);

  ellipse(-100,250,50);
  ellipse(-110,260,50);
  ellipse(-120,245,50,60);
  ellipse(-130,255,50);

  //make cloud appear canvas again
  if (cloudX -200> width){
    cloudX = -300;
  }
  cloudX++;

}

function drawBird() {
  image(birdImage[birdFrame], birdx, height/2);
  image(birdImage[birdFrame], birdx-300, height/2+50);

  if (birdTime > 20) { //change position, every 20 frames
    birdx += 5; //moving bird image
    birdFrame += 1; //next index of array
    if (birdFrame >= birdImage.length) {
      birdFrame = 0; //keep frame index within image length array
    }
    birdTime = 0; //frame time reset
  }
  birdTime++;
}

function drawSnowbird() {
  image(snowbirdImage[snowbirdFrame], snowbirdx, height/2);
  image(snowbirdImage[snowbirdFrame], snowbirdx-300, height/2+50);

  if (snowbirdTime > 20) { //change position, every 20 frames
    snowbirdx += 1; //moving bird image
    snowbirdFrame += 1; //next index of array
    if (snowbirdFrame >= snowbirdImage.length) {
      snowbirdFrame = 0; //keep frame index within image length array
    }
    snowbirdTime = 0; //frame time reset
  }
  snowbirdTime++;
}


class Car {
  constructor(x, y, c, s, l) {
    this.carX = x;
    this.carY = y;
    this.carC = c; //color of car
    this.carL = l; //length of car
    this.carSpeed = s; //speed of car
  }
  
  move() {
    this.carX = this.carX + this.carSpeed; //cars move
    if (this.carX > width) {
      this.carX = 0; //initial pos X of cars
    }
  }

  display() {
    noStroke();
    fill(this.carC);
    rect(this.carX, 600, this.carL, 35, 20); //position of cars, different shapes of cars 
  }
}



function keyPressed() {
	if (key == "0") {
		story = "start";
    birdSound.play();
    rainSound.stop();
    snowstormSound.stop();
    carSound.stop();
	} else if (key == "1") {
		story = "frame1";
    snowstormSound.play();
    birdSound.play();
    carSound.play();
    rainSound.stop();
	} else if (key == "2") {
		story = "frame2";
    snowstormSound.stop();
    birdSound.play();
    rainSound.play();
    carSound.play();
	} 
}

Looking Outwards 10 – Computer Music

Image of Haptic Organ

Haptic Organ is a kinetic soundscape installation created by COLLECTIVE and honh1m. ‘Haptic’ comes from the greek word ‘haptikos,’ which means “pertaining to the sense of touch.” This installation is based on kinesthetic communication, in other words the installation is generated using motion of hands to create variations of visual displays and sounds. The intention of this project was to make music visible, tangible, and shareable at the same time. This encourages people to interact with each other, which was the main goal of the creators and purpose of the installation Haptic Organ is designed with 20 transparent tubes with metallic spheres in them that move up and down through initiated air movement by hand motion. Audiences can freely perform their own music with the aid of sensors that give different notes across an octave. The volume of musical sounds from the installation can be controllable with growing and falling movements of hands over the haptic interfaces. What I really love about this artwork is that there is a unity between artificial (tube and sphere balls) and natural (sound energy) presented in a single piece of art that encourages interaction between people and the installation itself. I can really sense the artist’s sensibilities for interactivity and minimalism by looking at the complexity of interaction created through visuals and sound as well as simplicity of the installation design. 

Website: http://h0nh1m.com/

Video of Haptic Organ

Project 09 – Computational Portrait

sketch
//Stefanie Suk
//15-104 Section D

var selfPic;
var starSize = 10; //initial star size 10
let stefanie = ['s', 't', 'e', 'f', 'a', 'n', 'i', 'e']; //letters of my name
let stars = ['✦', '★', '✷', '✸']; //shapes of stars

function preload() {
  selfPic = loadImage("https://i.imgur.com/iSI6MtQ.jpg"); //preloading image
} 

function setup() {
  createCanvas(400, 400);
  noStroke();
  background(0); //initial background color set to black
  imageMode(CENTER);
  selfPic.loadPixels(); 
  frameRate(30);
  
}

function draw() {
  //get random x, y coordinates 
  var x = random(selfPic.width);
  var y = random(selfPic.height);
  var p = selfPic.get(x, y); //color to image at location

  //draw letters s,t,e,f,a,n,i,e
  fill(p);
  textSize(15);
  textFont("Helvetica");
  textStyle(BOLD);
  text(random(stefanie), x, y); //draw random letters from my name 

  //draw stars
  var mouseColor = selfPic.get(mouseX, mouseY); //color star to image at mouse location
  fill(mouseColor);
  textSize(starSize);
  text(random(stars), mouseX, mouseY); //draw random stars
}

function mousePressed() {
  background(255); //resets with the color of white
}

function keyPressed() {
  starSize += 1; //star size increases when any key is pressed
}

I chose a photo of me during quarantine taking pictures of myself because I was really bored. This portrait draws random letters of my name, as well as random shapes of stars based on the mouse position. The star increases in size when any key is pressed, and the portrait resets to a color of white when the mouse is clicked. 

Image of portrait
Portrait with only letters
Portrait with letters and stars with different sizes

Looking Outwards 09 – on Looking Outwards

Image of Flight Patterns

Looking Outwards 07 (Information Visualization) by Shruti Prasanth talks about Aaron Koblin’s Flight Patterns. I was first drawn to the project because of its aesthetic visuals. The contrast between the dark background and bright neon lines were eye-catching, and the shapes created by overlapping strings give an interesting pattern. I definitely agree with Shruti that the overlapping intersections of the strings really enhance the visuals of this project, especially because the lines glow brighter at the intersection point which shows the density of the air traffic. It was interesting to know that Shruti finds this map similar to the map she saw in global history class about traffic patterns of slave ships. I definitely see the similarity between the visuals of the traffic patterns of slave ships in American history and the Flight Patterns by Aaron Koblin, because they both use lines to represent the traffic patterns. The interesting part I personally think about the connection between the two maps is that one represents the traffic pattern on the ocean and the other represents the traffic pattern in the sky. We can compare and see how much technology has developed over time, and also see how different transportation is. The contrast between the colors of the background and the strings definitely makes the shape of the United States more clear in the project, but I personally think the dark spaces in the background represents the “air/sky” rather than the “sea”. The visuals of the project to me feels like the strings are placed in mid-air. I personally interpreted the strings to be visual representations of trails left behind planes, something like contrails.

Link to Aaron Koblin’s Flight Patterns here

Shruti Prasanth’s Looking Outwards-07, October 18, 2020: https://courses.ideate.cmu.edu/15-104/f2020/2020/10/18/lookingoutwards-07-6/

Video of Flight Patterns

Looking Outwards 08 – The Creative Practice of an Individual

Lecture Video of

Mariana Santos is a co-founder and CEO of Unicorn Interactive, an independent startup that focuses on storytelling through digital media. She worked as a director of animation and interactive at Fusion Media until 2016. She graduated from JSK Journalism Knight Fellowship at Stanford, working in major newsrooms across Latin America as a 2014 Knight International Journalism Fellow. Mariana Santos is a visual storyteller and a trained animator. She worked with a lot of newsrooms to create projects that convey datas as compelling stories through motion graphics. What I admire about Mariana Santos the most is that she leads design thinking in a multidisciplinary approach to storytelling. As a design major, I always realize how difficult it is to incorporate stories I want to convey visually. The way she combines design and storytelling into her work really shows not only what kind of designer and storyteller she is, but also shows who she is as an individual. Olympics 2012 in Numbers is an animation Mariana Santos worked on for theGuardian. For six months right until the Olympic Games arrived in London 2012, this video explores statistics and results about the Olympics and UK through data visualization. It’s interesting to see how numbers of statistics can be visually represented in such a way that it amazes me this animation was produced in 2012. She uses effective illustrations in parts that are necessary to enhance the quality of her storytelling, and her transitions are smooth so that it makes it easy for the audiences to read and understand the video. Also, she designed for a mobile first experience with responsive user design. This interactive design has all available information that can be seen and enjoyed in London during the Olympics Summer 2012. The fascinating part of this project is that it is an extension of storytelling and interactive design. Through her works, I learned the power of storytelling through visuals, and I hope to convey strong stories into my designs as well.

Mariana Santos’s Website: http://marysaints.com/

Olympics 2012 in Numbers video here

Image of London 2012 Olympics City Guide

Project 07 – Composition with Curves

sketch
// Stefanie Suk
// 15-104 Section D

var nPoints = 100; //number of points for curves
var angle = 10; //angle of rotation

function setup() {
    createCanvas(480,480);
    frameRate(15); //set frame rate to 15
}

function draw() {
    background(33, 63, 99); //background of canvas to dark blue

    //placing Hypocycloid in center
    push();
    translate(width/2, height/2);
    Hypocycloid();
    pop();

    //placing Deltoid in center and rotate by angle
    push();
    translate(width/2, height/2);
    rotate(radians(angle));
    angle += mouseX;
    Deltoid();
    pop();

    //placing Epitrochoid in center
    push();
    translate(width/2, height/2);
    Epitrochoid();
    pop();
}

function Hypocycloid(){
    // variables for Hypocycloid
    var a1 = map(mouseY, 0, 300, 150, 180); //size changes with respect to mouseY
    var b1 = 15;
    var c1 = mouseX / 25;

    //color, stroke of Hypocycloid
    stroke(167, 219, 239);
    strokeWeight(6);
    noFill();

    //create curve, map to full circle radians
    //use math function to find x and y values
    beginShape();
    for (var i = 0; i < nPoints; i++) {
        var angle1 = map(i, 0, nPoints, 0, TWO_PI);     
        x1 = (a1 - b1) * cos(angle1) + c1 * cos((a1 - b1) * angle1);
        y1 = (a1 - b1) * sin (angle1) - c1 * sin((a1 - b1) * angle1);
        vertex(x1, y1);
    }
    endShape(CLOSE); 
}

function Deltoid(){
    colorR = map(mouseX, 0, 50, 100, 255);
    colorG = map(mouseX, 0, 50, 100, 255); //set color in specific range
    colorB = map(mouseY, 0, 50, 100, 255); //changes color with respect to mouseX,Y
    
    // variable for Deltoid, change size
    a2 = map(mouseY, 0, height, 10, 40); //size changes with respect to mouseY
    
    //color, stroke, fill of Deltoid
    stroke(255);
    strokeWeight(6);
    fill(colorR, colorG, colorB);

    //create curve, map to full circle radians
    //use math function to find x and y values
    beginShape();
    for (var i = 0; i < nPoints; i++) {
        var angle2 = map(i, 0, nPoints, 0, TWO_PI);
        x2 = ((2 *(cos(angle2))) + (cos(2*angle2)))* a2 ;
        y2 = ((2 *(sin(angle2))) - (sin(2*angle2)))* a2 ;
        vertex(x2, y2);
    }
    endShape(CLOSE);
}

function Epitrochoid() {

    colorR = map(mouseX, 0, 50, 100, 255);
    colorG = map(mouseX, 0, 50, 100, 255); //set color in specific range
    colorB = map(mouseY, 0, 50, 100, 255); //changes color with respect to mouseX,Y

    // variables for epitrochoid
    var a3 = map(mouseY, 0, 400, 40, 110); //size changes with respect to mouseY
    var b3 = 50;
    var c3 = (mouseX / 15);

    //color, stroke of epitrochoid
    stroke(colorR, colorG, colorB);
    strokeWeight(1.5);
    noFill();

    //create curve, map to full circle radians
    //use math function to find x and y values
    beginShape();
    for (var i = 0; i < nPoints; i++) {
        var angle3 = map(i, 0, nPoints, 0, TWO_PI);
        x3 = (a3 + b3) * cos(angle3) + c3 * cos((a3 + b3) * angle3);
        y3 = (a3 + b3) * sin(angle3) + c3 * sin((a3 + b3) * angle3);
        vertex(x3, y3);
    }
    endShape(CLOSE);
}

I utilized hypocycloid, deltoid, and epitrochoid using the reference from Mathworld to create this project. I chose these curves because I loved how they were structured. I thought that when these three curves are put together would create one unique interactive shape for my project. The exploration of this project was interesting, and I also played around with random colors and sizes with mouseX and mouseY. The unique part about these curves in my project is that the curves in my work create different smoothness depending on the position of the mouse (round, shape, spiky, squiggly). The different shapes created in the project look like forms of snowflakes, which is why I made the main color blue.

Looking Outwards 07 – Information Visualization

Image of Unnumbered Sparks

Unnumbered Sparks is a project by Aaron Koblin and Janet Echelman. This interactive monumental sculpture is a crowd-controlled visual artwork that is installed in air on a large canvas. The designs and colors of the sculpture are based on the visitors present in the area through their mobile devices. People are able to use their phones to paint different colors of light across the artwork. Every single movement of the mobile devices project vivid beams of light in the artwork. What I admire about this sculpture is that it is interactive with the audiences in the area. Thus, I find the large scale and complexity of the installation is really inspiring as a design major. The computational software that is used in this artwork explores different scale, shape, density, and interaction with visitors. The material used in this installation is also very interesting, because the structure of the sculpture is made with soft fibers that are attached to existing buildings in the area. The exploration of unique materials and interaction really shows how much the artists focused on the connection between installation and people. Computation technology is successfully used in this interactive sculpture and it also shows the creator’s sensibilities to incorporate art and people into the project.

Website:  http://www.aaronkoblin.com/project/unnumbered-sparks/

Video of Unnumbered Sparks