Final Project

This program is a Covid-19 version of whack-a-mole called put-on-a-mask. The idea was inspired by an online game that my friends and I played during the pandemic called Covidopoly, a Covid-19 version of the board game Monopoly. Like this game, I wanted to make some light out of this dark situation we are in a make a fun, easy, time-passing game that will (hopefully) keep making you play until the pandemic is over.
To play is simple: the player must put masks on the viruses as fast as they can. There will be a total of 4 viruses on the screen at all times and once a virus is successfully clicked (accompanied by a “pop” sound), it will regenerate in a random color to a random position. If the player misses or takes too long to click a virus, they will get a strike– an accumulation of 3 strikes will end the game. The virus that was on the screen for too long will disappear on its own and regenerate in a new random color and position. Every 20 points, the player will level up which makes the time it takes a virus to disappear on its own shorter.
If I had more time, I would like to add more complex elements to the game like making the viruses move around, add more viruses to the screen after a certain amount of levels, or add more clickable elements for bonus points or strike reductions.

sketch
var covidviruses = [];
var covidImageLinks = ["https://i.imgur.com/iUnzt1x.png", 
                        "https://i.imgur.com/V9cdbDy.png", 
                        "https://i.imgur.com/OjUptCF.png", 
                        "https://i.imgur.com/heDuTxd.png",
                        "https://i.imgur.com/PoNLrQ1.png",
                        "https://i.imgur.com/oIF3cp7.png",
                        "https://i.imgur.com/jc8muyt.png",
                        "https://i.imgur.com/X6MPvtK.png"]
var mask;
var coronavirusSound;
var popSound;
var clickSound;
var covidX = [150, 200, 300, 350];
var covidY = [300, 150, 200, 250];
var strike = 0;
// array of virus objects
var virus = [];
var page = 1;
var score = 0;
var ageIncrease = 1;
var maxScore = 0;
var gameLevel = 1;
var angle = 20;

function preload() {
    // load pictures (different color viruses)
    for(var i = 0; i < covidImageLinks.length; i ++) {
        covidviruses[i] = loadImage(covidImageLinks[i]);
    }
    mask = loadImage("https://i.imgur.com/DdBChjv.png");
    coronavirusSound = loadSound("https://courses.ideate.cmu.edu/15-104/f2020/wp-content/uploads/2020/12/coronavirus.wav");
    popSound = loadSound("https://courses.ideate.cmu.edu/15-104/f2020/wp-content/uploads/2020/12/pop.wav");
    clickSound = loadSound("https://courses.ideate.cmu.edu/15-104/f2020/wp-content/uploads/2020/12/click.wav")
}

function setup() {
    createCanvas(480, 480);
    useSound();
    // create array of objects of 4 starter viruses (location, size, color, age)
    for(var i = 0; i < 4; i ++) {
        virus[i] = new Object();
        virus[i].x = covidX[i];
        virus[i].y = covidY[i];
        virus[i].color = floor(random(0, 8));
        virus[i].size = 90;
        virus[i].age = 0;
     }
     frameRate(40);
     noStroke();
}

function soundSetup() { 
    coronavirusSound.setVolume(.5);
    popSound.setVolume(.5);
    clickSound.setVolume(.5);
}


function draw() {
    // title page 
    if(page == 1) {
        cursor();
        createTitlePage();
    }
    // game
    if(page == 2) {
        noCursor();
        background("#BFEDFF");
        // draw 4 viruses to begin
        for(var i = 0; i < 4; i ++) {
            image(covidviruses[virus[i].color], virus[i].x, virus[i].y, virus[i].size, virus[i].size);
            // add virus age
            virus[i].age += ageIncrease;
            // if virus has been unclicked for 200 frames --> strike + new virus replacement
            if(virus[i].age == 200) {
                makeNewVirus(i);
                strike += 1;
            }
        }   
        // 3 misses --> game over
        if(strike == 3) {
        // go to end page
            page = 3;
        }

        // mask on cursor
        imageMode(CENTER);
        image(mask, mouseX, mouseY, 90, 90);
        
        updateScore();

        // level up every 20 points and increase aging rate (so virus disappears faster)
        if(score%20 == 0 & score > maxScore) {
            ageIncrease += 1;
            maxScore = score;
            gameLevel += 1;
        }
    }

    // end page
    if(page == 3) {
        cursor();
        createEndPage();
    }

    // help page
    if(page == 4) {
        cursor();
        createHelpPage();
    }
}

function mousePressed() {
    // thresholds of a success click for viruses
    var d = [];
    for(var i = 0; i < 4; i ++) {
        d[i] = dist(mouseX, mouseY, virus[i].x, virus[i].y);
    }

    // title page
    if(page == 1) {
        // play  button --> reset everything
        if(mouseX > 190 & mouseX < 290 && mouseY > 305 && mouseY < 355) {           
            // go to game page
            clickSound.play();
            strike = 0;
            score = 0;
            ageIncrease = 1;
            maxScore = 20;
            gameLevel = 1;
            page = 2;
        }
        if(mouseX > 165 & mouseX < 315 && mouseY > 135 && mouseY < 285){
            // sound effect
            coronavirusSound.play();
        }
        if(mouseX > 140 & mouseX < 340 && mouseY > 365 && mouseY < 415) {
            clickSound.play();
            page = 4;
        }
    }

    // game page
    else if(page == 2) {
        // if clicks are successes for any 4 of the viruses --> make pop sound, score increase by 1, new virus replacement
        if (d[0] < 45) {
            popSound.play();
            makeNewVirus(0);
            score += 1;
        }
        else if (d[1] < 45) {
            popSound.play();
            makeNewVirus(1);
            score += 1;
        }
        else if(d[2] < 45) {
            popSound.play();
            makeNewVirus(2);
            score += 1;
        }
        else if(d[3] < 45) {
            popSound.play();
            makeNewVirus(3);
            score += 1;
        }
        else { // a miss
            strike += 1;
        }
    }

    // end page
    else if(page == 3) {
        // play again button --> reset everything
        if(mouseX > 125 & mouseX < 355 && mouseY > 290 && mouseY < 370) {
            clickSound.play();
            strike = 0;
            score = 0;
            ageIncrease = 1;
            maxScore = 20;
            gameLevel = 1;
            page = 2;
        }
        // go back to main page
        if(mouseX > 140 & mouseX < 340 && mouseY > 365 && mouseY < 415) {
            clickSound.play();
            page = 1;
        }
    }

    // help page
    else if(page == 4) {
        // play  button --> reset everything
        if(mouseX > 190 & mouseX < 290 && mouseY > 305 && mouseY < 355) {           
            // game page
            clickSound.play();
            strike = 0;
            score = 0;
            ageIncrease = 1;
            maxScore = 20;
            gameLevel = 1;
            page = 2;
        }
        // return to main page
        if(mouseX > 140 & mouseX < 340 && mouseY > 365 && mouseY < 415) {
            clickSound.play();
            page = 1;
        }
    }
        
}

// replace clicked viruses or missed viruses 
function makeNewVirus(index) {
    covidX[index] = random(90, 390);
    covidY[index] = random(135, 390);

    virus[index].x = covidX[index];
    virus[index].y = covidY[index];
    virus[index].color = floor(random(0, 8));
    virus[index].size = 90;
    virus[index].age = 0;

}

// title page (page 0)
    // button to play
    // button to go to help page
    // interactive graphic (makes sound)
function createTitlePage() {
    background("#D7C9FF");
    // play button
    if(mouseX > 190 & mouseX < 290 && mouseY > 305 && mouseY < 355) {     
        fill("pink");
    }
    else{
        fill("white");
    }

    rectMode(CENTER);
    rect(width/2, 330, 100, 50);
    
    // help button
    if(mouseX > 140 & mouseX < 340 && mouseY > 365 && mouseY < 415) {
        fill("pink");
    }
    else{
        fill("white");
    }
    rect(width/2, 390, 200, 50);

    textSize(30);
    textAlign(CENTER);

    // text, box labels
    fill("black");
    text("put on a mask!", width/2, height/4);
    text("play!", width/2, 340);
    text("how to play", width/2, 400);
    textSize(10);
    text("click on me!", width/2, 280);

    // animation using transformation
    // viruses moving around the borders
    imageMode(CORNER);
    virusBorder();

    // sound effect virus
    // mouse hover --> rotate
    push();
    translate(240, 210);
    if(mouseX > 165 & mouseX < 315 && mouseY > 135 && mouseY < 285){
        rotate(radians(angle));
    }
    imageMode(CENTER);
    image(covidviruses[6], 0, 0, 150, 150);
    pop();
    angle += 5;
    
}

// page 3
function createEndPage() {
    background("#D7C9FF");    
    
    // play button
    if(mouseX > 125 & mouseX < 355 && mouseY > 290 && mouseY < 370) {
        fill("pink");
    }
    else {
        fill("white");
    }
    rectMode(CENTER);
    rect(width/2, 330, 200, 50);
    
    // return to main page
    if(mouseX > 140 & mouseX < 340 && mouseY > 365 && mouseY < 415) {
        fill("pink");
    }
    else {
        fill("white");
    }
    rect(width/2, 390, 200, 50);

    // text, button labels
    fill("black");
    textSize(30);
    textAlign(CENTER);
    text("game over!", width/2, 150);
    textSize(20);
    text("Score: " + str(score), width/2, 200);
    text("Highest Level: " + str(gameLevel), width/2, 230);
    textSize(30);
    text("play again!", width/2, 340);
    text("main page", width/2, 400);

    imageMode(CORNER);
    virusBorder();
}

// keep track of score, strikes, level on game page
function updateScore() {
    // print current score, strikes, and level at top
    textSize(20);
    textAlign(CENTER);
    text("Score: " + str(score), width/2, 50);
    text("Strikes: " + str(strike), width/2, 70);
    text("Level " + str(gameLevel), width/2, 90);
}

// border pattern
function virusBorder() {
    for(var i = 0; i < width; i += 40) {
        image(covidviruses[floor(random(0, 8))], i, 0, 40, 40);
        image(covidviruses[floor(random(0, 8))], i, 440, 40, 40);
        image(covidviruses[floor(random(0, 8))], 0, i, 40, 40);
        image(covidviruses[floor(random(0, 8))], 440, i, 40, 40);
    }
}

// help page, page 4
function createHelpPage() {
    background("#D7C9FF");
    rectMode(CENTER);

    // play button
    if(mouseX > 190 & mouseX < 290 && mouseY > 305 && mouseY < 355) {     
        fill("pink");
    }
    else{
        fill("white");
    }
    rect(width/2, 330, 100, 50);
    
    // return to home button
    if(mouseX > 140 & mouseX < 340 && mouseY > 365 && mouseY < 415) {
        fill("pink");
    }
    else{
        fill("white");
    }
    rect(width/2, 390, 200, 50);

    // text, labels
    fill("black");
    textSize(30);
    textAlign(CENTER);
    // page button
    text("play!", width/2, 340);
    // help button
    text("main page", width/2, 400);

    text("how to play:", width/2, 120);
    textSize(15);
    text("like whack-a-mole but covid edition! click on the viruses as they appear and cover them with masks! make sure to be fast because the higher the score, the faster they disappear! the game ends after you get 3 misses!", 
        width/2, 300, 300, 300);
    
    imageMode(CORNER);
    virusBorder();
}

Project 11: Generative Landscape

For this week’s project, I decided to visualize an NYC subway line I used often (pre-pandemic) and the views of the skyline you can see passing by when the subway tracks are outdoors. I first roughly sketched out the scene on paper and then used Professor Cortina’s sample code as a baseline and customized it further to meet my vision. I displayed the scene to be at night since that’s the time of day I liked most when watching the skyline. Also, although nighttime, the lights would always be on in the buildings, so I decided to have lit up windows on all the buildings as well as the light reflections.

sketch
var frontBuildings = [];
var backBuildings = [];
var moonAndStars;

function preload(){
  moonAndStars = loadImage("https://i.imgur.com/0JJlsGR.png");
}

function setup() {
  createCanvas(480, 270);
  // make initial array of buildings
  for(var i = 0; i < 20; i++) {
    var x = random(width);
    backBuildings[i] = makeBackBuilding(x);
  }
  for(var i = 0; i < 10; i++) {
    var x = random(width);
    frontBuildings[i] = makeFrontBuilding(x);
  }
  frameRate(50);
}

function draw() {
  // gradient night background
  setGradient(color("#655BCE"), color("#1A1449"));
  // moon
  image(moonAndStars, 0, 0, 480, 350);

  updateAndDisplayBuildings();
  removeBuildingsThatHaveSlippedOutOfView();
  addNewBuildingsWithSomeRandomProbability(); 
  // tracks
  drawTrack();
  // train
  drawTrain();

}

function drawTrain() {
  strokeWeight(1);
  stroke("#4A4954");
  // train body
  fill("#65656D");
  rect(0, 180, 220, 80);
  strokeWeight(5);
  line(0, 240, 218, 240);
  strokeWeight(2);
  line(0, 245, 218, 245);
  strokeWeight(5);
  line(0, 190, 218, 190);
  strokeWeight(2);
  line(0, 196, 218, 195);
  noStroke();
  // doors
  fill("#5D5C66");
  rect(10, 200, 36, 60);
  rect(130, 200, 36, 60);
  // windows
  fill("#383664");
  rect(12, 202, 32, 30);
  rect(132, 202, 32, 30);
  rect(58, 200, 60, 30);
  rect(200, 200, 20, 40);
  // train number
  fill("purple");
  circle(182, 220, 25);
  fill(255);
  textSize(20);
  text("7", 177, 227);
}

function drawTrack() {
  fill(20);
  rect(0, 220, width, 100);
  fill("#8F8F91");
  rect(0, 220, width, 30);
  fill("#F0D933");
  rect(0, 240, width, 5);
}

function removeBuildingsThatHaveSlippedOutOfView(){
  // If a building has dropped off the left edge,
  // remove it from the array.  This is quite tricky, but
  // we've seen something like this before with particles.
  // The easy part is scanning the array to find buildings
  // to remove. The tricky part is if we remove them
  // immediately, we'll alter the array, and our plan to
  // step through each item in the array might not work.
  //     Our solution is to just copy all the buildings
  // we want to keep into a new array.
  var frontBuildingsToKeep = [];
  var backBuildingsToKeep = [];
  for (var i = 0; i < frontBuildings.length; i++){
      if (frontBuildings[i].x + frontBuildings[i].width > 0) {
          frontBuildingsToKeep.push(frontBuildings[i]);
      }
  }
  for (var i = 0; i < backBuildings.length; i++){
      if (backBuildings[i].x + backBuildings[i].width > 0) {
          backBuildingsToKeep.push(backBuildings[i]);
      }
  }
  frontBuildings = frontBuildingsToKeep; // remember the surviving buildings
  backBuildings = backBuildingsToKeep;
}


function addNewBuildingsWithSomeRandomProbability() {
  // With a very tiny probability, add a new building to the end.
  var newBuildingLikelihood = 0.08; 
  if (random(0,1) < newBuildingLikelihood) {
      backBuildings.push(makeBackBuilding(width));
      frontBuildings.push(makeFrontBuilding(width));
  }
}

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

// method to update position of building every frame
function frontBuildingMove() {
    this.x += this.speed;
}
    
// draw the building and some windows
function frontBuildingDisplay() {
  noStroke();
  // building
  fill(this.color);
  var y = 220 - this.height;
  rect(this.x, y, this.width, this.height);
  // windows
  fill("#FFE9AD");
  for(var i = 0; i < 5; i ++) {
    rect(this.x + 5, y + 10 + 15*i, this.width/6, 8);
    rect(this.x + 20, y + 10 + 15*i, this.width/6, 8);
    rect(this.x + 35, y + 10 + 15*i, this.width/6, 8);
  }
}

function makeFrontBuilding(xlocation) {
  var building = {x: xlocation, 
                  width: random(40, 50), 
                  height: random(80, 120),
                  color: color(random(20, 70), random(20, 70), 130),
                  speed: -3,
                  move: frontBuildingMove, 
                  display: frontBuildingDisplay}
  return building;
}


// method to update position of building every frame
function backBuildingMove() {
  this.x += this.speed;
}
    
// draw the back building and some windows
function backBuildingDisplay() {
  noStroke();
  var y = 220 - this.height;
  // light reflections
  fill(255, 243, 180, 20);
  ellipse(this.x + this.width/2, y + 20, this.width*2);
  // building
  fill(this.color);
  rect(this.x, y, this.width, this.height);
  // windows
  fill("#FFE9AD");
  for(var i = 0; i < 8; i ++) {
    rect(this.x + 5, y + 10 + 15*i, this.width/6, 8);
    rect(this.x + 20, y + 10 + 15*i, this.width/6, 8);
    rect(this.x + 35, y + 10 + 15*i, this.width/6, 8);
  }
}

function makeBackBuilding(xlocation) {
  var building = {x: xlocation, 
                  width: random(40, 50), 
                  height: random(130, 160),
                  color: color(random(60, 80), random(60, 80), 180),
                  speed: -3,
                  move: backBuildingMove, 
                  display: backBuildingDisplay}
  return building;
}

// code from https://editor.p5js.org/REAS/sketches/S1TNUPzim
function setGradient(c1, c2) {
  noFill();
  for (var y = 0; y < height; y++) {
    var inter = map(y, 0, height, 0, 1);
    var c = lerpColor(c1, c2, inter);
    stroke(c);
    line(0, y, width, y);
  }
}



LO-11: Women in Computational Design

The project I chose for this week is SOMEONE by Lauren Lee McCarthy. This project interested me since its focus was on reimagining home intelligence systems as actual people rather than AI. SOMEONE is primarily a human version of Amazon Alexa. For 2 months, the homes of 4 participants had custom-designed smart devices installed. A command center was installed in NYC where visitors were able to look into the participants’ homes through laptops and control their networked devices. Participants would call out for “someone” in which the visitors respond to their needs as Alexa does.

Lauren Lee McCarthy is an artist whose work focuses on social relationships in the era of surveillance, automatic, and algorithmic living. She received a BS in Computer Science and Art and Design from MIT and an MFA from UCLA. She is also the creator of p5.js!

Command Center at 205 Hudson Gallery in NYC
Example view of visitors at Command Center

LO-10: Computer Music

The project I chose is The Welcome Chorus by Yuri Suzuki. This project is an interactive installation in the county of Kent commissioned by the Turner Contemporary consisting of 12 horns that continuously sing AI generated lyrics. What I admire most about this project, like for most of Suzuki’s other works, is its ability to blend sound and technology to produce music in unconventional ways that are easily accessible to anyone and everyone. The lyrics, reflecting the people’s experiences living in Kent and Kent as a whole, were gathered from workshops and gatherings and put into a data bank in which the AI algorithms learned from to produce the lyrics that will be sung. Another AI system was integrated in order to produce folk song melodies so that the installation can produce songs with both lyrics and melodies. Suzuki’s artistic sensibilities are manifested in the final form since, like his other works, he turns this complex project into an interactive sculpture that any visitor can contribute to (using an ongoing machine learning “conductor”) and learn from without the extra burden of trying to understand complex ideas.

Yuri Suzuki’s The Welcome Chorus (2020)

Project 10: Sonic Story

For my sonic story, I decided to depict a short story of a girl who is waiting for the bus but unfortunately, the bus does not stop, and thundering starts. I used images of drawings for the girl and clouds while I coded the other “characters” (the bus stop, light post, and bus). For the sounds, I used the sound of a bus and the sound of thunder beginning. This story is a very familiar experience in my life (although, fortunately, I never got rained on immediately after missing the bus).

sketch
// story: girl is waiting for the bus but the bus skips over her and it begins to thunder.

var person;
var personFrowning;
var busSound;
var thunder;
var rain;
var clouds;

function preload() {
    person = loadImage("https://i.imgur.com/hEZlRjK.png");
    personFrowning = loadImage("https://i.imgur.com/5vGwTK1.png");
    clouds = loadImage("https://i.imgur.com/xBxIA9K.png")
    busSound = loadSound("https://courses.ideate.cmu.edu/15-104/f2020/wp-content/uploads/2020/11/bus.wav");
    thunder = loadSound("https://courses.ideate.cmu.edu/15-104/f2020/wp-content/uploads/2020/11/thunder-3.wav");
}

function setup() {
    createCanvas(400, 350);
    useSound();
    frameRate(60);
}

function soundSetup() { 
    busSound.setVolume(.5);
    thunder.setVolume(.5);
}

var busPosition = 400;

function draw() {
    // bus sound
    busSound.playMode("untilDone");
    busSound.play();
    noStroke();
    // sky
    background(31, 35, 105);
    image(clouds, 0, 0, width, 100);
    // road
    fill(150);
    rect(0, 250, width, height);
    // sidewalk
    fill(200);
    rect(0, 240, width, 30);
    drawBusStop();
    drawStreetLamp();

    // person
    if(busPosition > 80) { // happy person, waiting for bus, facing the bus (to the right)
        push();
        translate(400, 0);
        scale(-1, 1);
        image(person, 240, 180, 80, 80);
        pop();
        textSize(10);
        fill(255);
        text("yay! the bus is coming!", 100, 300);
    }
    else { // sad person because bus did not stop, facing the bus (to the left)
        image(personFrowning, 80, 180, 80, 80);
        // add captions based on bus position
        if(busPosition < 70 & busPosition > -235) {
            textSize(10);
            fill(255);
            text("what the heck? did he not see me...", 100, 300);
        }
    }
    drawBus(busPosition);
    busPosition -= 1;

    // bus is gone
    if(busPosition == - 235) {
        busSound.stop();
        // thunder starts
        thunder.play();
        noLoop();
    }
}


// draw bus
function drawBus(x) {
    // bus body
    fill(145, 0, 15);
    rect(x, 150, 230, 110);
    // windows
    fill(201, 228, 250);
    rect(x, 160, 40, 40);
    rect(x + 100, 160, 50, 40);
    rect(x + 160, 160, 50, 40);
    // wheels
    fill(0);
    circle(x + 20, 265, 30, 30);
    circle(x + 60, 265, 30, 30);
    circle(x + 170, 265, 30, 30);
    circle(x + 210, 265, 30, 30);
}

// draw bus stop pole
function drawBusStop() {
    // pole
    fill(0);
    rect(70, 105, 5, 140);
    // sign
    fill(213, 33, 33);
    rect(60, 105, 25, 25);
}

// draw street lamp 
function drawStreetLamp() {
    // light reflection
    fill(255, 233, 158, 50);
    circle(355, 105, 50);
    // pole
    fill(0);
    rect(350, 105, 10, 140);
    // light
    fill(255, 233, 158);
    circle(355, 105, 25);

}



LO-09

After browsing through the Looking Outwards posts by my classmates, Maggie’s 3D Computer Graphics post on the Amigos Project by Zigor Samaniego caught my attention. Amigos Project is a series of art by Samaniego started in 2016 using tools such as Photoshop, Pixologic Zbrush, Maxon Cinema 4D, and Wacom Cintiq. As Maggie pointed out, these computer-generated “monsters” are super cute, a reason why I wanted to learn more about it. As they also mentioned, it’s really interesting and impressive how Samaniego was able to achieve such realistic textures using 3D rendering tools to create the adorable “realistic” creatures. Along with that, I am also fascinated by how Samaniego made certain choices while programming and designing to be able to maintain the creatures’ “cuteness” despite making them super realistic (especially since the “more real” something appears, the less “cute” it becomes).

Amigos Project 5
Amigos Project 7

Project-09: Portrait

For this week’s project, I chose to draw a picture of me when I was a baby holding up a peace sign. I tried to draw the portrait by mimicking short paint strokes. To do so, instead of making random dots, I drew random short lines whose directions can be changed by pressing the mouse (there is a total of 4 directions). I also thought it would be interesting to see how the different directions of the same shape can alter the way the portrait was drawn so ran the code several times with the direction being different each time.

sketch
let img;
var lineType = 1;

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

function setup() {
  createCanvas(480, 480);
  background(255);
  img.resize(width, height);
  img.loadPixels();
  frameRate(50);
}

function draw() {
  	var x = floor(random(img.width)); // random x position
  	var y = floor(random(img.height)); // random y position
  	var pixel = img.get(x, y); // single pixel from image (color)
  	stroke(pixel);
  	strokeWeight(3);
	if(lineType == 1) { // slanted lines starting from left
  		line(x, y, x + 7, y + 7);
  	}
 	else if(lineType == 2){ // horizontal lines
  		line(x, y, x + 7, y);	
  	}
  	else if(lineType == 3){ // slanted lines starting from right
  		line(x + 7, y, x, y + 7);
  	}
  	else { // vertical lines
  		line(x, y, x, y + 7);
  	}
}

function mousePressed() {
	if(lineType == 1) {
		lineType = 2;
	}
	else if(lineType == 2) {
		lineType = 3;
	}
	else if(lineType == 3) {
		lineType = 4;
	}
	else {
		lineType = 1;
	}
}
final with all strokes
final with one type of stroke (slanted from left)

LO-8: The Creative Practice of an Individual

The person I chose was Janelle Shane, an artificial intelligence researcher. She is based in Boulder, Colorado, and studied electrical engineering at Michigan State University for her undergraduate degree.
She is essentially a researcher who focuses her work on showing the shortcomings of machine learning and AI through humor.
I admire Shane because her projects are very lighthearted and creative. AI is something that can be very daunting to many because of how “human-like” it’s becoming so I love how she focuses on its struggles in a humorous way to show how it still has a long way to go to actually think like a human.
The work that piqued my interest was Neural Candy Hearts. I thought this project was very creative and funny since she uses AI to recreate the famous Valentine’s Day candy hearts.
Shane’s presentation style is just like the projects she works on. She talks very casually about her works and presents them highlighting the humorous aspects to engage her audience. Based on the way she presents her projects, I think that it is very important to basically let the projects themselves do the “talking.” In other words, I think it’s important to show what your project does rather than try to explain it bit by bit.

Janelle Shane at Eyeo 2018

LO-07: Information Visualization

The project I chose this week was Aaron Koblin’s Amsterdam SMS. This project is an interactive visualization tool developed for the MIT Senseable City Lab which helps visualize SMS messages data. I admired this project because I was drawn to the boldness of the colors and like any artwork done using data, I just thought it was very interesting and cool. To generate this work, Koblin used Processing and OpenGL. The data he used was provided by KPN Mobile. Like his other works, Koblin uses bright colors or “light” (he doesn’t actually use light in this project but the bright colors do give off a similar effect!) to stimulate our sight and draw attention to the artwork.

Video of Amsterdam SMS Messages on New Years Eve (2007)

Project-07: Curves

For this week’s project, I decided to use 2 different curves that reminded me of flowers, a 10 cusp Epicycloid and a 10 cusp Hypotrochoid. I decided to make them rotate and change in size based on the mouse movements but in opposite directions to give off a pulsating effect. I also utilized mousePressed so that the curves can alternate. The mouse positions also control the colors of the curves and the background so that the final output is unique in all positions. The colors of the flowers and background are quite muted to give off a slight vintage wallpaper vibe with a modern twist.

(below are screenshots of the code at different mouse positions)

sketch

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

var nPoints = 100;

// background color codes
var r = 205;
var g = 152;
var b = 152;

// to switch curves based on mouse click
var whichCurve = 0;

// curve color codes
var curver = 202;
var curveg = 255;
var curveb = 255;

function draw() {

	// to add/subtract color codes based on mouse position
	var colordiffX = map(mouseX, 0, 480, 0, 53);
	var colordiffY = map(mouseY, 0, 480, 0, 53);

	background(r - colordiffX, g + colordiffY, b + colordiffX);

	stroke(255); // white outline

	// 5 x 5 curves (outer)
	for(var x = 60; x < width; x += 90){
		for(var y = 60; y < height; y += 90){
			push();
			translate(x, y);
			fill(curver + colordiffX, curveg - colordiffY, curveb - colordiffX);
			if(whichCurve == 0) {
				drawHypotrochoid();
			}
			else {
				drawEpicycloid();
			}
			pop();
		}
	}
	// 4 x 4 curves (inner)
	for(var x = 105; x < width - 90; x += 90) {
		for(var y = 105; y < height - 90; y += 90) {
			push();
			translate(x, y);
			fill(curver + colordiffY, curveg - colordiffX, curveb - colordiffY);
			if(whichCurve == 1) {
				drawHypotrochoid();
			}
			else {
				drawEpicycloid();
			}			
			pop();
		}
	}
}

// draw rotating 10 cusp epicycloid
function drawEpicycloid() {
	var x;
	var y;
	var a = mouseX / 30;
	var b = a / 10;
    var h = constrain(mouseY / 8, a / 10, 8*b);
    var ph = mouseX / 50;

    beginShape();
    for (var i = 0; i < nPoints; i++) {
        var t = map(i, 0, nPoints, 0, TWO_PI);
        x = (a + b) * cos(t) - h * cos(ph + t * (a + b) / b);
        y = (a + b) * sin(t) - h * sin(ph + t * (a + b) / b);
        vertex(x, y);
    }
    endShape(CLOSE);
}

// draw rotating 10 cusp hypotrochoid
function drawHypotrochoid() {
	var x;
	var y;
	var a = (width - mouseX)/20; // opposite movement from epicycloid
	var b = a / 10;
    var h = constrain((height - mouseY)/8, a/10, 10*b);
    var ph = (width - mouseX) / 50;

    beginShape();
    for (var i = 0; i < nPoints; i++) {
        var t = map(i, 0, nPoints, 0, TWO_PI);
        x = (a - b) * cos(t) + h * cos(ph + t * (a - b) / b);
        y = (a - b) * sin(t) - h * sin(ph + t * (a - b) / b);
        vertex(x, y);
    }
    endShape(CLOSE);
}

// mouse pressed alternates order of curves
function mousePressed() {
	if(whichCurve == 0){
		whichCurve = 1;
	}
	else {
		whichCurve = 0;
	}
}