Austin Treu – Final Project

atreu-final_project

How to run: download and unzip the folder, then open the index.html file in your browser of choice, mine being Firefox.

For my final project, I worked utilizing turtle graphics to create a game and drawing software. I used the turtles like a snake from the game of the same name. Thus, I decided on the name Snakle for my game. The main game is a two player competitive game in which each player is trying to make their snakle the longest by outlasting the other player. Player one is blue and player two is red. The game keeps track of score and displays the winner after each round, so the players can continue playing to a certain score. The drawing feature is based off of a similar concept to that of the game, where you control a single snakle in four directions with a color palette. It works very similarly to an Etch-A-Sketch, but you can click to move the snakle elsewhere.

Start screen:

Help Screen:

Game:

Etch-A-Sketch:

 

Dani Delgado and Elena Deng – Final Project

Click to make music!

sketch

/*
Elena Deng and Dani Delgado
Section E
edeng1 and ddelgad1
Final Project
*/

//variables to load sounds into

var ellipseSound;
var arcSound;
var squareSound;
var triSound;
var bgs;
//create the slider to control bg noise pan
var sliderPan;
//variables to inciment the bg
var volInc;
var pitchInc;
//stores the amount of mouse clicks
var mouseClick = 0;
//variables for the bg graphic based on amplitude
var amp;
var volhistory = [];

var objects = []; //sets the array for objects

var bright = 1; //sets the brightness of the screen+background

var xe = []; //sets the x pos array for the centroid
var ye = []; //sets the y pos array for the centroid


function preload() {
    //load all of the sounds into the file
    ellipseSound = loadSound("https://courses.ideate.cmu.edu/15-104/f2018/wp-content/uploads/2018/12/ellipseDrip.mp3");

    squareSound = loadSound("https://courses.ideate.cmu.edu/15-104/f2018/wp-content/uploads/2018/12/bloopSquare.mp3");

    arcSound = loadSound("https://courses.ideate.cmu.edu/15-104/f2018/wp-content/uploads/2018/12/bong.mp3");

    triSound = loadSound("https://courses.ideate.cmu.edu/15-104/f2018/wp-content/uploads/2018/12/ding.mp3");

    bgs = loadSound("https://courses.ideate.cmu.edu/15-104/f2018/wp-content/uploads/2018/12/whiteNoise.mp3");
}

function setup() {
    createCanvas(640, 480);
    frameRate(14);
    angleMode(DEGREES);
    //play bg sound
    bgs.loop();
    bgs.setVolume(1.5);
    //get amplitude
    amp = new p5.Amplitude();
    //create pan slider
    sliderPan = createSlider(-1, 1, 0, 0.01);
    sliderPan.size(640, AUTO);

    for (var i = 0; i < 7; i++) {  //sets the centroid points
        var t = map(i, 0, 7, 0, TWO_PI);
        xe.push(width / 2 + 75 * cos(t));
        ye.push(height / 2 + 75 * sin(t));
    }
}

function draw() {
    background(10, 10, bright); //everytime the mouse is pressed, background brightness increases/decreases
    bright = bright - 5;
    if (mouseIsPressed) {
        bright = 110;
    }
    //pan slider
    bgs.pan(sliderPan.value());
    //get bgs amplitude and apply it the the graphic
    //the graphic is made from a "begin and end shape" method
    //and mapping of amps is made in a forloop
    var vol = amp.getLevel();
    volhistory.push(vol);
    push();
    frameRate(40);
    translate(width / 2, height / 2);
    //create the outer circle
    beginShape();
    strokeWeight(5);
    stroke(20, 20, -bright, 80);
    noFill();
    for (var i = 0; i < 360; i++) {
        var r = (map (volhistory[i], 0, 1, 10, 100)) * 18;
        var x = r * cos(i);
        var y = r * sin(i);
        vertex(x, y);
    }
    endShape();
    //create the inner circle
    beginShape();
    strokeWeight(0.5);
    stroke(80, 80, -bright);
    noFill();
    for (var i = 0; i < 360; i++) {
        var r = (map(volhistory[i], 0, 1, 10, 100)) * 17;
        var x = r * cos(i);
        var y = r * sin(i);
        vertex(x, y);
    }
    endShape();

    if (volhistory.length > 360) {
        volhistory.splice(0, 1);
    }
    pop();

    for (var i = 0; i < objects.length; i++) { //sets the order of the objects
        if (objects[i].type == "circle") {
            drawCir(objects[i]);
        }
        if (objects[i].type == "rect") {
            drawRect(objects[i]);
        }
        if (objects[i].type == "tri") {
            var change = random(0, 2)
            drawTri(objects[i].x, objects[i].y, objects[i].s + change);
        }
        if (objects[i].type == "centroid") {
            drawCentroid();

        }
    }
}

function mousePressed() {
    //variables for sounds made to easily reset the mouse clicks
    var firstSound = mouseClick < 10;
    var secondSound = mouseClick >= 10 & mouseClick <= 20;
    var thirdSound = mouseClick > 20 & mouseClick <= 30;
    var fourthSound = mouseClick > 30 & mouseClick <= 40;
    //images and sounds are based on mouse clicks
    if (firstSound) {
        //this code is to play the sounds
        //only allows a sound effect to be triggered if it's not playing
        //that way theres no overlap of sounds
        if(!ellipseSound.isPlaying()) {
            volInc = map(mouseY, 0, 480, 5, 0.09);
            pitchInc = map(mouseX, 0, 640, 0.25, 1.25);
            ellipseSound.play();
            ellipseSound.setVolume(volInc);
            ellipseSound.rate(pitchInc);
        }
        //pan the sounds based on mouse click
        //you'll hear it in every other ear every other click
        if (mouseClick % 2) {
            ellipseSound.pan(-1.0);
        } else {
            ellipseSound.pan(1.0);
        }
        if (objects.length >= 7) {
            objects.shift();
        }
        objects.push(createCir(mouseX, mouseY)); //creates the circle for the first ten mouse clicks
    }

    if (secondSound) {
        if(!squareSound.isPlaying()) {
            volInc = map(mouseY, 0, 480, 8, 1.5);
            pitchInc = map(mouseX, 0, 640, 0.25, 1.75);
            squareSound.play();
            squareSound.setVolume(volInc);
            squareSound.rate(pitchInc);
            // if (mouseClick % 2){
            //     squareSound.pan(-1.0);
            // } else {
            //     sqaureSound.pan(1.0);
            // }
        }
        if (objects.length >= 7) {
            objects.shift();
        }
        objects.push(createRect(mouseX, mouseY)); //creates the square/rect for the next ten mouse clicks
    }

    if (thirdSound) {
        if(!triSound.isPlaying()) {
            volInc = map(mouseY, 0, 480, 7, 0.5);
            pitchInc = map(mouseX, 0, 640, 0.5, 1.75);
            triSound.play();
            triSound.setVolume(volInc);
            triSound.rate(pitchInc);
        }
        if (mouseClick % 2) {
            triSound.pan(-1.0);
        } else {
            triSound.pan(1.0);
        }
        if (objects.length >= 7) {
            objects.shift();
        }
        objects.push(createTri(mouseX, mouseY, random(1, 2))); //creates the diamond for the next ten mouse clicks
    }

    if (fourthSound) {
        if(!arcSound.isPlaying()) {
            volInc = map(mouseY, 0, 480, 8, 0.5);
            pitchInc = map(mouseX, 0, 640, 0.25, 1.25);
            arcSound.play();
            arcSound.setVolume(volInc);
            arcSound.rate(pitchInc);
        }
        if (mouseClick % 2) {
            arcSound.pan(-1.0);
        } else {
            arcSound.pan(1.0);
        }
        if (objects.length >= 7) {
            objects.shift();
        }
        xe.push(mouseX);
        ye.push(mouseY);
        objects.push(createCentroid()); //creates the centroid for the next ten mouse clicks
    }
    if (mouseClick > 40) {
        mouseClick = firstSound; //mouseClicks resets the cycle
    }
    //increment the mouse clicks
    mouseClick ++;
}

function createCir(bx,by) { //creates the circle
    return {x:bx, y:by, type: "circle", oDiam: 0};
}

function drawCir(cir) { //draws the circle
    for (var i = 0; i < 10; i++) {
        var diam = cir.oDiam - 70 * i; //adjusts the drip spacing effect
        if (diam > 0) {
            var fade = map(diam, 0, width / 2, 100, 255); //sets the color
            strokeWeight(map(diam, 0, width, 12, 1)); //stroke weight decreases as circle gets larger
            stroke(fade, fade / 1.3, fade / 2, 85);
            noFill();
            ellipse(cir.x, cir.y, diam / 2); //draws ellipse
        }
    }
    cir.oDiam = cir.oDiam + 2; //increases size of the circle
    if (cir.oDiam > height / 2) { //once circle is larger than height/2 then the circle enlargement speed decreases
        cir.oDiam -= 1.25;
    }
}

function createRect(bx,by,bs) {
    return {x:bx, y:by, s:bs, type: "rect", oRect: 210}
}

function drawRect(square) {
    noStroke();
    rectMode(CENTER);

    for (var i = 0; i < 6; i++) {
        var recta = square.oRect - 100 * i; //sets the frequency/size of squares
        if (recta < 0) {
            var fade = map(recta, 0, width / 2, 255, 180); //maps the color
            strokeWeight(10)
            stroke(fade, fade / 1.3, fade / 2); //sets the color fade
            noFill();
            rect(square.x, square.y, recta / 2, recta / 2); //draws the square
        }
    }
    square.oRect = square.oRect - random(-2, -4); //shrinks square at random rates
}

function createTri(bx, by, bs) { //creates the diamond
    return {x:bx, y:by, s:bs, type: "tri"}
}

function drawTri(bx, by, bs) { //draws the diamond
    var smashorpass = random(-1, 10); //sets the random rate at which the shapes twinkle
    var smashthenpass = random(-1, 5);
    noStroke();
    //draws the first diamond
    fill(map(by, 0, height, 200, 255), map(by, 0, height, 120, 225), map(by, 0, height, 40, 85));
    quad(bx - 10 + bs - smashorpass, by + bs + random(-4, 4), bx + bs + random(-4, 4), by - 30 + bs - smashthenpass, bx + 10 + smashorpass, by + bs + random(-4, 4), bx + bs + random(-4, 4), by + 30 + bs + smashthenpass);

    strokeWeight(2); //draws the second diamond outline
    stroke(255, 230, 215, 70);
    noFill();
    quad(bx - 15 + bs - smashorpass, by + bs + random(-4, 4), bx + bs + random(-4, 4), by - 35 + bs - smashthenpass, bx + 15 + smashorpass, by + bs + random(-4, 4), bx + bs + random(-4, 4), by + 35 + bs + smashthenpass);

}

function createCentroid() { //creates the centroid
    return {type: "centroid"};
}

function drawCentroid() { //draws the centroid
    noStroke();
    fill(map(ye, 0, height, 200, 255), map(ye, 0, height, 120, 225), map(ye, 0, height, 40, 85));

    // moving the components of the centroid
    var nPoints = xe.length;
    for (var i = 0; i < nPoints; i++) {
        xe[i] += (noise(i * 1 + millis() / 500.0) - .5) * 10;
        ye[i] += (noise(i * 2 + millis() / 500.0) - .5) * 10;
        ellipse(xe[i], ye[i], 30, 30);
    }
    // draw the dots on the outside
    for (var i = 0; i < nPoints; i++) {
        ellipse(xe[i], ye[i], 1, 1);
    }
    // finding the average of the dots (x,y)
    var xAverage = 0;
    var yAverage = 0;
    for (var i = 0; i < nPoints; i++) {
        xAverage += xe[i];
        yAverage += ye[i];
    }
    xAverage /= nPoints;
    yAverage /= nPoints;
    // draws line from center to the points
    strokeWeight(4);
    stroke(255, 255, 255, 10);
    for (var i = 0; i < nPoints; i++) {
        line(xe[i], ye[i], xAverage, yAverage);
    }
    // Draw the centroid
    stroke(0);
    strokeWeight(2);
    ellipse(xAverage, yAverage, 10, 10);
}

For our final project, we wanted to create a “digital instrument” which synthesizes user interaction, sound, and generative visuals. We decided to start with a simple background which not only contains a graphic that reacts to the amplitude of the played music, but also flashes brighter when the user clicks in. From there, we added different graphics and corresponding sound effects to increase visual and audio interest. These graphics all have unique movements and correlate to the sound, while the sound effects change based on the mouseX and mouse Y position. As the user clicks, they’ll explore a range of different sounds and shapes that are placed on a loop which resets after every 40 clicks. Also, as they click, the sounds’s panning will change with every other click (e.x. click once, sound effect will play in one ear and click again, it’ll play in the other).

Here are some screenshots of possible screens you would get by interacting with this project!

shape 1: ripples
shape 2: squares
shape 3: diamonds
shape 4: centroid

We really enjoyed working on this project and exploring how different sounds and visuals interact and affect one another! We had difficulty at the beginning decided on exactly what we wished to do, but once we got the ball rolling things started to fall into place!

Since this was a partner project, we divided up the work to make it manageable and easier to code (as two people working on one computer would be slow and painful on our friendship). So we split the work up into such parts:
Elena Deng created the objects and visuals.
Dani Delgado edited the sound effects and created the background graphic.
Together we worked on debugging the code and adding the intended effects.

We hope you click around and have fun!

Katherine Hua and Min Lee – Final Project

sketch

/*
Katherine Hua, Min Lee
Section A
khua@andrew.cmu.edu, mslee@andrew.cmu.edu
Final Project
*/

var characters = []; // images of the characters are loaded into this array
var mushroom; // image of mushroom that represents # of lives left is loaded into this variable
var cloud; // image of cloud is loaded into this variable
var cloudsX = []; //cloud's randomized x positions will be loaded into this array
var cloudsY = []; //cloud's randomized y positions will be loaded into this array 
var cloudsSpeed = []; // cloud's randomized speed will be loaded into this array

var gameMode = 0; // determines which screen you see; title screen = 0, game = 1, game over = 2, instructions = 3
var lives = 3; // you start out with 3 lives 
var score = 0; // you begin with a score of 0

var characterIndex; //assigns a number value to a character 
var pipeNumber; // //assigns each pipe a number value
var characterX; //keeps track of the character's X values
var characterY = 180; //keeps track of the character's Y values
var characterSpeed = -3; // //keeps track of the character's speed
var pipesOccupied; //the pipe number that's occupied by a character
var newIndex; //new number value assigned to character

function preload() {
    //links of character images 
    var characterImages = [];
    mushroom = loadImage("https://i.imgur.com/V1vjvug.png"); //mushroom that is meant to represent # of lives
    cloud = loadImage("https://i.imgur.com/7PCTEzk.png"); //clouds that will be floating by in the background
    characterImages[0] = "https://i.imgur.com/Bf9U7OE.png"; //mario
    characterImages[1] = "https://i.imgur.com/s7o5h2m.png"; //peach
    characterImages[2] = "https://i.imgur.com/xQqZiZb.png"; //toad
    characterImages[3] = "https://i.imgur.com/0bcsmDZ.png"; //bowser
    characterImages[4] = "https://i.imgur.com/Wv9Dkzj.png"; //wario
    characterImages[5] = "https://i.imgur.com/AkWIiIw.png"; //boo

    //initial cloud positions
    for (var i = 0; i < 4; i++) {
        //setting the clouds to random initial positions
        cloudsX[i] = width + i * 50;
        cloudsY[i] = random(0, 130);
        cloudsSpeed[i] = random(0.25, 1); // moving the clouds at a randomized speed between 0.25 and 1
    };

    //load images of characters into characters array
    //allows for object to change characters
    characters[0] = loadImage(characterImages[0]);
    characters[1] = loadImage(characterImages[1]);
    characters[2] = loadImage(characterImages[2]);
    characters[3] = loadImage(characterImages[3]);
    characters[4] = loadImage(characterImages[4]);
    characters[5] = loadImage(characterImages[5]);

}

function setup() {
    createCanvas(600, 400);
    //random positions of character
    pipeNumber = round(random(0, 5)); //randomly chooses which pipe the character will appear at
    pipesOccupied = pipeNumber; //corresponding pipe number
    characterX = width / 7 * (pipeNumber + 1) + 60; //character's x position that will determine their corresponding pipe
    characterIndex = round(random(0, 5)); //randomly chooses which character will appear
}

function draw() {
    background(21, 30, 99); // setting background to the blue
    //creating the clouds; just loading the image onto the canvas; they do not move here yet
    for (var i = 0; i < 4; i++) {
        image(cloud, cloudsX[i], cloudsY[i]);
    };

    displayHill(); // creating the hill landscape moving in the background

    //part of the Title Screen
    //images of characters spread out across title screen
    if (gameMode === 0) {
        for (var x = 0; x < 6; x++) {
            image(characters[x], (width/7 * (x+1)) - (width / 7 / 2) + 10, 110);
        }
    }

    gameScreen(); // this is the actual game 
    displayChutes(); // creates the green chutes/pipes 
    displayGround(); // creates the criss-crossed red brick ground 
    titleScreen(); // this is the starting, default screen
    drawScoreTally(); // keeps track of the score in gameScreen and gameOverScreen
    instructionsScreen(); // instructions screen
    displayButtons(); // creates the buttons in the actual game part
    gameOverScreen(); // the game over screen after you lose all your lices

    //clouds are made to move here at randomized speeds
    for (var i = 0; i < cloudsX.length; i++) {
        cloudsX[i] -= cloudsSpeed[i];
        if (cloudsX[i] < -60) {
            cloudsX[i] = width;
        };
    };
}


function drawScoreTally() {
    if (gameMode === 1) { // we only want this visual element to appear in the gameScreen 
        push();
        //making the yellow rectangle where the score will be kept
        fill(181, 141, 38);
        strokeWeight(2);
        stroke(255, 229, 163);
        rectMode(CENTER);
        rect(width / 2, 35, 70, 20, 3);
        noStroke();
        //adding the actual text on top of the rectangle 
        fill(255,229, 163);
        textAlign(CENTER);
        text("Score:" + " " + score, width / 2, 40)
        //text saying that if user wishes to restart the game at any point, the user can just press the key 'x' to restart the game
        text("Press 'x' to restart game", width/2, 60);
        pop();
    };
}

//creating the generative hill landscape in the background of the game
function displayHill() {
    var hill = 0.006 
    var hillSec = 0.0007;
    push();
    stroke(25, 83, 19);
    beginShape();
    for (i = 0; i < width; i ++) {
        var h = (millis() * hillSec) + (i * hill);
        var y = map(noise(h), 0, 1, 200, 100);
        line(i, y, i, height);
    }
    endShape();
    pop();
}
// creating the brick ground 
function displayGround() {
    push();
    strokeWeight(2);
    stroke(211, 71, 71);
    fill(181, 38, 38);
    rectMode(CORNER);
    rect(0, 260, 600, 400-260);
    for (var k = 0; k < 60; k ++) {
        line(k * 10, 260, k * 10, 400);
        line(0, 260 + k * 10, 600, 260 + k * 10);
    }
    pop();
}
//creating the green chutes/pipes
function displayChutes() {
    if (gameMode === 0 || gameMode === 1 || gameMode === 3) { //we want the chutes/pipes to appear in all screens except the game over screen
        push();
        //creating 6 chutes/pipes
        for (var j = 1; j < 7; j++) {
            rectMode(CENTER); //drawing rectangles from the center rather than the corner
            fill(43, 130, 58);
            strokeWeight(3);
            stroke(81, 163, 95);
            rect((width/7) * j, 220, 65, 80, 2); //body of the chute
            rect((width/7) * j, 200, 75, 40, 2); //head of the chute
            strokeWeight(7);
            //giving the pipes the highlight on their left side
            line(55 + (width/7 * (j-1)), 186, 55 + (width/7 * (j-1)), 215);
            line(60 + (width/7 * (j-1)), 225, 60 + (width/7 * (j-1)), 255);

        }    
        pop();
    }
}

function titleScreen() {
    push();
    if (gameMode === 0 || gameMode === 3) { // we want the title screen to appear in title screen and instructions screen
        //creating title of the game: "Pipe it Up"
        stroke(155, 115, 0); 
        strokeWeight(8);
        fill(255, 203, 57);
        textAlign(CENTER);
        textSize(70);
        textFont('arial')
        text("PIPE IT UP", width / 2, (height / 3 * 2) + 60);
        push();
        //creating the two yellow buttons on bottom of screen
        fill(155, 115, 0);
        strokeWeight(2);
        stroke(255, 230, 57);
        rect(150, 350, 125, 35, 4); //left button
        rect(325, 350, 125, 35, 4); // right button
        textSize(15);
        //creating the text on top of buttons
        textFont('Arial');
        strokeWeight(1);
        stroke(255, 203, 57);
        fill(255, 203, 57);
        text("START GAME", 213, 373);
        text("INSTRUCTIONS", 388, 373);
        pop();
    }
    pop();

    //changes cursor to hand when hovering over start button and instructions button 
    if (mouseX > 150 & mouseX < 275 && mouseY < 385 && mouseY > 350) {
        cursor(HAND);
        if (mouseIsPressed) {
            gameMode = 1;
        };
    } else if (mouseX > 325 & mouseX < 450 && mouseY > 350 && mouseY < 385) {
        cursor(HAND);
        if (mouseIsPressed) {
            gameMode = 3;
        };
    } else {
        cursor(ARROW);
    }
}

function instructionsScreen() {
    if (gameMode === 3) {  //we only want the instructions screen to occur during instructions Screen time
        push();
        //creating an lowered opacity blanket of black across the title screen
        fill(0, 0, 0, 200); 
        rect(0,0,600,400); 
        //title of the instructions screen: "Instructions"
        textSize(30);
        strokeWeight(1);
        stroke(255, 188, 0);
        fill(255, 188, 0);
        textAlign(CENTER);
        text("INSTRUCTIONS", width/2, 80);
        //purpose of the game
        fill(255);
        strokeWeight(1);
        stroke(255);
        textSize(18);
        text("Keep the Mushroom Kingdom safe!", width/2, 125);
        //instructions of the game
        textSize(15);
        noStroke();
        textAlign(LEFT);
        text("There are 6 pipes leading into the kingdom, each one assigned to a button \n on your keyboard : S, D, F, J, K, L. \n \n It is your job as royal guard to delegate who enters and who does not. \n Unfortunately, some baddies will try to infiltrate the kingdom \n and make you lose your job. But luckily, with the tap of a button, \n you can immediately prevent them from entering. \n But be careful! Reject a civilian and you'll get a demerit. \n Three demerits is a disadulation.", 50, 160);
        textAlign(CENTER);
        strokeWeight(1);
        stroke(255);
        text("Press 'x' to return to Start page", width/2, 350);
        pop();
    }
}

function gameScreen() {
    if (gameMode === 1) {
    //----------------------------- get random character to pop up at different location -------

        //places character down
        image(characters[characterIndex], characterX, characterY);
        //if character reaches peak, move in opposite direction
        if (characterY < 100) {
            characterSpeed = characterSpeed * -1
        //if character reaches bottom of the pipe, changes character randomly and goes to new pipe
        } else if (characterY > 200) {
            characterSpeed = characterSpeed * -1
            characterIndex = round(random(0, 5))
            pipesOccupied = round(random(0, 5))
            characterX = width / 7 * (pipesOccupied) + 60
        };
        characterY += characterSpeed;

    //----------------------------- correct answer / wrong answer ------------------------------
        //draws lives as mushrooms
        for (var i = 0; i < lives; i++) {
            image(mushroom, 60 + (40 * i), 20)
        };
        //once lives reaches 0, game ends
        if (lives === 0) {
            gameMode = 2
        };
    }
}

function displayButtons() {
    //draws each of the buttons 
    var txt = ["S", "D", "F", "J", "K", "L"];
    if (gameMode === 1) {
        push();
        stroke(137, 144, 200);
        strokeWeight(5);
        //changing color of button if respective key is pressed
        //if 's' key is pressed
        if (keyIsPressed) {
            if (key === 's') {
                fill(39, 49, 124);
            } else {
                fill(91, 100, 168);
            }
        } else {
            fill(91, 100, 168);
        }
        ellipse((width/7), height - height/7, 40, 40);
        // if 'd' key is pressed
        if (keyIsPressed) {
            if (key === 'd') {
                fill(39, 49, 124);
            } else {
                fill(91, 100, 168);
            }
        } else {
            fill(91, 100, 168);
        }
        ellipse((width / 7) * 2, height - (height / 7), 40, 40);
        // if 'f' key is pressed
        if (keyIsPressed) {
            if (key === 'f') {
                fill(39, 49, 124);
            } else {
                fill(91, 100, 168);
            }
        } else {
            fill(91, 100, 168);
        }
        ellipse((width / 7) * 3, height - (height / 7), 40, 40);
        // if 'j' key is pressed
        if (keyIsPressed) {
            if (key === 'j') {
                fill(39, 49, 124);
            } else {
                fill(91, 100, 168);
            }
        } else {
            fill(91, 100, 168);
        }
        ellipse((width / 7) * 4, height - (height / 7), 40, 40);
        // if 'k' key is pressed
        if (keyIsPressed) {
            if (key === 'k') {
                fill(39, 49, 124);
            } else {
                fill(91, 100, 168);
            }
        } else {
            fill(91, 100, 168);
        }
        ellipse((width / 7) * 5, height - (height / 7), 40, 40);
        // if 'l' key is pressed
        if (keyIsPressed) {
            if (key === 'l') {
                fill(39, 49, 124);
            } else {
                fill(91, 100, 168);
            }
        } else {
            fill(91, 100, 168);
        }
        ellipse((width / 7) * 6, height - (height / 7), 40, 40);
        // adding the text on top of the button
        pop();
        for (var j = 1; j < 7; j++) {
            push();
            fill(200, 184, 220);
            noStroke();
            textAlign(CENTER);
            textSize(19);
            text(txt[j - 1], (width / 7) * j , height - (height / 7) + 5);
            pop();
        }
    }
}

function gameOverScreen() {
    //press 'r' to restart
    if (gameMode === 2) {
        //title of the gameOverScreen: "game over"
        push();
        fill(11, 16, 90, 200);
        rect(0, 0, 600, 400);
        textSize(50);
        fill(239, 0, 42);
        strokeWeight(5);
        stroke(145, 0, 26);
        textAlign(CENTER);
        text("GAME OVER", width/2, height/2 - 20);
        //displays your score
        textSize(30);
        strokeWeight(2);
        text("Score:" + " " + score, width/2, height/2 + 20);
        //tells you how you can play again and restart the game
        textSize(20);
        strokeWeight(1);
        fill(239, 0, 42);
        text("Press 'r' to restart game", width/2, height/2 + 70);
        pop();
    };
} 

function keyPressed() {
    //if game hasn't started yet, press S to start
    //if game started, press X to go to home screen
    //if game over, press r to restart 
    if (gameMode === 1) {
        if (key === 'x' || key === 'X') {
            gameMode = 0;
            level = 1;
            score = 0;
    // if character is bad guy, add point for pressing; else subtract life 
    //if character is good guy, subtract life for pressing and add point for not pressing
        } else {
            for (var i = 0; i < characters.length; i++) {
                var keys = ["s", "d", "f", "j", "k", "l"]
                if (pipesOccupied === i) {
                    //if good guy, 
                    if (characterIndex === 0 || characterIndex === 1 || characterIndex === 2) {
                        if (key === keys[i]) {
                            lives -= 1
                        }
                    } else if (characterIndex === 3 || characterIndex === 4 || characterIndex === 5 & key === keys[i]) {
                        score += 1
                    } else if (characterIndex === 3 || characterIndex === 4 || characterIndex === 5 && key != keys[i]) {
                        lives -= 1
                    }
                };
            };
        }
    //GAMEOVER - press R to restart the game 
    } else if (gameMode === 2) {
        if (key === 'r' || key === 'R') {
            gameMode = 0;
            level = 1;
            score = 0;
            lives = 3;
        };
    //INSTRUCTIONS - press X to go to title screen
    } else if (gameMode === 3) {
        if (key === 'x' || key === 'X') {
            gameMode = 0;
        };
    };

} 

Instructions:

Keep the Mushroom Kingdom safe! There are 6 pipes leading into the Mushroom Kingdom and each one is assigned to a respective button on your keyboard : S, D, F, J, K, L. It is your job as a royal guard of the kingdom to delegate who is able to enter and who is not. Unfortunately, some villains will try to infiltrate the kingdom and make you lose your job. Luckily, with the tap of a button, you can immediately prevent them from entering. But be careful! Reject a civilian and you’ll lose a demerit (life). “Three demerits is a disadulation” – Jim  Halpert from The Office. haha

Statements:

What we have produced for our final project is a completely different direction than what we had proposed to do in our Proposal. After lots of thought, we decided to change the topic of our final project because we believed this was something that could best reflect our creativity and have a more set goal (and also in celebration of Nintendo’s release of Super Smash Bros Ultimate today).

In regards to the distribution of work, Min and I worked in person together throughout the whole process. In the beginning, we would just sit next to each other, create a visual element, and then come together to merge whatever the two of us came up with. After the visual aspects were basically all done and we had to get to the interactive component of the game, that is when things started to get a little more difficult. We had to communicate a lot and constantly merge our codes to make sure that we are using the same variables, going towards the same direction, and following the same general train of thought. In the end, I focused more on the game design and structure while Min focused more on gameplay and functionality.

In the beginning, we had wanted characters to be coming out of all six chutes randomly, but at all times. But, we couldn’t figure out how to prevent characters from appearing in pipes that another character already occupies. So, we shifted our goals to stick to one pipe. We also could not figure out how to debug our code so that if no key is pressed to capture a “bad” character, a life is lost, or vice versa, if no key is pressed to let a “good character remain free, points are added to the score. However other than those two problems, the rest of the game came out quite successfully.

Sarah Yae – Final Project

sketch

// Sarah Yae
// smyae@andrew.cmu.edu
// Section B
// Final Project - "EDM and Jam!"

// Declare sound variables globally

// "Rumors" by R3HAB
var r1;
var r2;
var r3;
var r4;
var r5;
var r6;
// "Lullaby" by R3HAB
var l1;
var l2;
var l3;
var l4;
var l5;
var l6;
var l7;
var l8;
var l9;
var l10;
// Drum Sounds
var d1;
var d2;
var d3;
var d4;
// Random Sounds
var rn1;
var rn2;
var rn3;
var rn4;
var rn5;
var rn6;
//Other Variables 
var x1 = 170;
var x2 = 230;
var y1 = 170;
var y2 = 230;
var rad = 60; 
var startpx = 10; 
var startox = 10;
var startix = 10; 
var ldia = 100;
var kdia = 100;
var jdia = 100;
var xb1 = 200;
var yb1 = 200;
var xb2 = 200;
var yb2 = 200; 
var uparc_x;
var uparc_y;
var arc_w = 100;
var arc_h = 50; 

// Load all sounds
function preload() {
    r1 = loadSound("rumor1.wav");
    r1.setVolume(0.5);

    r2 = loadSound("rumor2.wav");
    r2.setVolume(0.5); 

    r3 = loadSound("etc1.wav");
    r3.setVolume(0.5); 

    r4 = loadSound("rumor4.wav");
    r4.setVolume(0.5); 

    r5 = loadSound("rumor5.wav");
    r5.setVolume(0.5); 

    r6 = loadSound("rumor6.wav");
    r6.setVolume(0.5); 

    l1 = loadSound("lullaby1.wav");
    l1.setVolume(0.5); 

    l2 = loadSound("lullaby2.wav");
    l2.setVolume(0.5);

    l3 = loadSound("lullaby3.wav");
    l3.setVolume(0.5);

    l4 = loadSound("lullaby4.wav");
    l4.setVolume(0.5);

    l5 = loadSound("lullaby5.wav");
    l5.setVolume(0.5);

    l6 = loadSound("lullaby6.wav");
    l6.setVolume(0.5);

    l7 = loadSound("lullaby7.wav");
    l7.setVolume(0.5);

    l8 = loadSound("lullaby8.wav");
    l8.setVolume(0.5);

    l9 = loadSound("lullaby9.wav");
    l9.setVolume(0.5);

    l10 = loadSound("lullaby10.wav");
    l10.setVolume(0.5);

    d1 = loadSound("drum1.wav");
    d1.setVolume(0.5);

    d2 = loadSound("drum2.mp3");
    d2.setVolume(0.5);

    d3 = loadSound("drum3.wav");
    d3.setVolume(0.5);

    d4 = loadSound("drum4.wav");
    d4.setVolume(0.5);

    rn1 = loadSound("rand1.wav");
    rn1.setVolume(0.5);

    rn2 = loadSound("rand2.wav");
    rn2.setVolume(0.5);

    rn3 = loadSound("rand3.wav");
    rn3.setVolume(0.5);

    rn4 = loadSound("etc2.wav");
    rn4.setVolume(0.5);

    rn5 = loadSound("rand5.wav");
    rn5.setVolume(5.0);

    rn6 = loadSound("rand6.wav");
    rn6.setVolume(0.5);
}

//Setup Canvas
function setup() {
    createCanvas (400,400);
}

//Draw graphics and play corresponding sounds
function draw() {

    background (51);

    textSize(25);
    textAlign(CENTER);
    fill("Salmon");
    text("EDM AND JAM! press any key", width / 2, 50);

    if (keyIsPressed) {

        var slant = 30;

// Play "Rumors" = Key B, N , M, L, K, J

        if (key == 'm') { //pink slash lines
            r1.play();
            for (var i = 0; i < 40; i++) {
                strokeWeight(10);
                stroke(246, 203, 190);
                line(0, height - slant, slant, height);
                slant += 40; 
            }
        }         

        if (key == 'n') { //purple slash lines
            r2. play();
            for (var i = 0; i < 40; i++) {
                strokeWeight(10);
                stroke(203, 202, 231);
                line(0, height - slant, slant, height);
                slant += 40; 
            } 
        }

        if (key == 'b') { //half circles move
            r3.play();
            background (200);
            fill ('Salmon');

            arc(xb1, yb1, 100, 100, PI/2, PI*3/2);
            yb1 -= 10;
            if (yb1 < 0) {
                yb1 = 200; 
            }

            arc(xb2, yb2, 100, 100, PI*3/2, PI/2);
            yb2 += 10; 
            if (yb2 > height) {
                yb2 = 200; 
            }
        }
    
        if (key == 'l') { //yellow circle gets bigger
            r4.play();
            fill(204,255,0);
            noStroke();
            ellipse(width/2, height/2, ldia, ldia);
            ldia = ldia + 10;

            if (ldia > 150) {
                ldia = 30;
            }
        }

        if (key == 'k') { //blue circle gets bigger
            r5.play();
            fill(0, 204, 255);
            noStroke();
            ellipse(width/2, height/2, ldia, ldia);
            ldia = ldia + 10;

            if (ldia > 150) {
                ldia = 30;
            }
        } 

        if (key == 'j') { //pink circle gets bigger
            r6.play();
            fill(255, 0, 204);
            noStroke();
            ellipse(width/2, height/2, ldia, ldia);
            ldia = ldia + 10;

            if (ldia > 150) {
                ldia = 30;
            }
        }   

// Play Random Sounds = Key A, S, D, F, G, H

        if (key == 'a') { //yellow one dash
            rn1.play();
            strokeWeight(10);
            stroke(254, 226, 62);
            line(width/2 - 70, height/2, width/2 + 70, height/2)
        }

        if (key == 's') { //yellow two dashes
            rn2.play();
            strokeWeight(10);
            stroke(254, 254, 73);
            line(width/2 - 70, height/2 - 20, width/2 + 70, height/2 - 20);
            line(width/2 - 70, height/2 + 20, width/2 + 70, height/2 + 20);
        }

        if (key == 'd') { //yellow three dashes
            rn3.play();
            strokeWeight(10);
            stroke(255, 255, 146);
            line(width/2 - 70, height/2 - 30, width/2 + 70, height/2 - 30);
            line(width/2 - 70, height/2, width/2 + 70, height/2);
            line(width/2 - 70, height/2 + 30, width/2 + 70, height/2 + 30);
        }

        if (key == 'f') { //gradient orange
            rn4.play();
            loadPixels();
            for (var y = 0; y < height; y++) {
                for (var x = 0; x < width; x++) {
                    var ind = (x + y * width) * 4;
                    pixels[ind+0] = 200;
                    pixels[ind+1] = 100; 
                    pixels[ind+2] = y;
                    pixels[ind+3] = 255;
                }
            }
            updatePixels();
        }

        if (key == 'g') { //gradient pink
            rn5.play();
            loadPixels();
            for (var y = 0; y < height; y++) {
                for (var x = 0; x < width; x++) {
                    var ind = (x + y * height) * 4;
                    pixels[ind+0] = 100;
                    pixels[ind+1] = 50; 
                    pixels[ind+2] = y;
                    pixels[ind+3] = 255;
                }
            }
            updatePixels();
        }

        if (key == 'h') { //gradient blue 
            rn6.play();
            loadPixels();
            for (var y = 0; y < height; y++) {
                for (var x = 0; x < width; x++) {
                    var ind = (x + y * width) * 4;
                    pixels[ind+0] = 100;
                    pixels[ind+1] = 150; 
                    pixels[ind+2] = y;
                    pixels[ind+3] = 255;
                }
            }
            updatePixels();
        }

// Play "Lullaby" = Key P, O, I , U, Y, T, R, E, W, Q

        if (key == 'p') { //one top star moving
            l1.play();
            background(17, 30, 108); 
            textSize(50); 
            fill('Yellow');
            text('*', startpx, 100);
            startpx += 10; 

            if (startpx > width) {
                startpx = 10; 
            }
        }

        if (key == 'o') { //one middle star moving
            l2.play();
            background(17, 30, 108); 
            textSize(50); 
            fill('Yellow');
            text('*', startox, 200);
            startox += 10;  

            if (startox > width) {
                startox = 10; 
            }       
        }

        if (key == 'i') { //one bottom star moving
            l3.play();
            background(17, 30, 108); 
            textSize(50); 
            fill('Yellow');
            text('*', startix, 300);
            startix += 10;  

            if (startix > width) {
                startix = 10; 
            }  
        }

        if (key == 'u') { //green springs wallpaper
            l4.play();
            background(255, 235, 205);
            for (var uparc_y = 50; uparc_y < 500; uparc_y += 100) {
                for (var uparc_x = 50; uparc_x < 500; uparc_x += 100) {
                noFill ();
                stroke (177,194,122);
                strokeWeight (3);
                arc(uparc_x, uparc_y, arc_w, arc_h, PI, TWO_PI);
                }
            }
        }

        if (key == 'y') { //blue springs wallpaper
            l5.play();
            background(255, 235, 205);
            for (var uparc_y = 50; uparc_y < 500; uparc_y += 100) {
                for (var uparc_x = 50; uparc_x < 500; uparc_x += 100) {
                noFill ();
                stroke (180,216,231);
                strokeWeight (3);
                arc(uparc_x, uparc_y, arc_w, arc_h, PI, TWO_PI);
                }
            }
        }

        if (key == 't') { //pink springs wallpaper 
            l6.play();
            background(255, 235, 205);
            for (var uparc_y = 50; uparc_y < 500; uparc_y += 100) {
                for (var uparc_x = 50; uparc_x < 500; uparc_x += 100) {
                noFill ();
                stroke (255,195,194);
                strokeWeight (3);
                arc(uparc_x, uparc_y, arc_w, arc_h, PI, TWO_PI);
                }
            }
        }

        if (key == 'r') { //four triangles
            l7.play();
            noFill();
            for (var i = 0; i < 4; i++) {
                strokeWeight(12 - 3 * i)
                var rr = 244
                var rg = 147
                var rb = 242
                stroke(rr - (50 * i), rg + (20 * i), rb);
                triangle(width/2, (height/4) + 40 * i, (width/4) + 35 * i, (height*3/4) - 20 * i, (width * 3/4) - 35 * i, (height*3/4) - 20 * i);
            }
        }

        if (key == 'e') { //three triangles
            l8.play();
            noFill();
            for (var i = 0; i < 3; i++) {
                strokeWeight(12 - 3 * i)
                var er = 244
                var eg = 147
                var eb = 242
                stroke(er - (50 * i), eg + (20 * i), eb);
                triangle(width/2, (height/4) + 40 * i, (width/4) + 35 * i, (height*3/4) - 20 * i, (width * 3/4) - 35 * i, (height*3/4) - 20 * i);
            }
        } 

        if (key == 'w') { //two triangles
            l9.play();
            noFill();
            for (var i = 0; i < 2; i++) {
                strokeWeight(12 - 3 * i)
                var wr = 244
                var wg = 147
                var wb = 242
                stroke(wr - (50 * i), wg + (20 * i), wb);
                triangle(width/2, (height/4) + 40 * i, (width/4) + 35 * i, (height*3/4) - 20 * i, (width * 3/4) - 35 * i, (height*3/4) - 20 * i);
            }
        }
        
        if (key == 'q') { //one triangle
            l10.play();
            strokeWeight(12);
            noFill();
            for (var i = 0; i < 1; i++) {
                var qr = 244
                var qg = 147
                var qb = 242
                stroke(qr - (50 * i), qg + (20 * i), qb);
                scale(1/(1+i));
                triangle(width/2, height/4, width/4, height * 3/4, width * 3/4, height * 3/4);
            }
        }

// Play Drum Sounds = Key V, C, X, Z

        if (key == 'c') { //two balls move horizontally
            d1.play();

            noStroke();
            fill(255, 228, 196);
            ellipse(x1, height/2, rad, rad);
            x1 -= 5;

            fill(230, 230, 250);
            ellipse(x2, height/2, rad, rad);
            x2 += 5;

            if (x1 < 0) {
                x1 = 170;
            }

            if (x2 > width) {
                x2 = 230;
            }
        }

        if (key == 'v') { //two balls move vertically
            d2.play();

            noStroke();
            fill(255, 228, 196);
            ellipse(width/2, y1, rad, rad);
            y1 -= 5;

            fill(230, 230, 250);
            ellipse(width/2, y2, rad, rad);
            y2 += 5;

            if (y1 < 0) {
                y1 = 170;
            }

            if (y2 > height) {
                y2 = 230;
            }  
        }   

        if (key == 'x') { //white thunder
            d3.play();
            noFill();
            stroke('White');
            strokeWeight(10);
            beginShape();
            vertex(width/2, height/4 - 20);
            vertex(width/3 + 10, height/2);
            vertex(width*2/3 - 10, height/2);
            vertex(width/2, height*3/4 + 20);
            endShape();
        }

        if (key == 'z') { //yellow thunder
            d4.play();
            noFill();
            stroke('Yellow');
            strokeWeight(20);
            beginShape();
            vertex(width/2, height/4 - 20);
            vertex(width/3 + 10, height/2);
            vertex(width*2/3 - 10, height/2);
            vertex(width/2, height*3/4 + 20);
            endShape();
        }
    }
}

“EDM AND JAM!”

INSTRUCTIONS: Press any alphabetical key on the keyboard to play a particular sound and see a corresponding graphic. You can even listen to your favorite music and add beats to it, simply by pressing a key!

HOW TO OPERATE FROM ZIP FILE: Because this program incorporated a lot of sounds (approximately 26 different sound files), it was best to upload as a zip file. First, download the zip file. Secondly, run a terminal locating the file and localhost:8000. Third, open up the program and play around with it! Download it right here: smyae-finalproject

SCREENSHOTS:

Background of “EDM AND JAM!”
Key “u” pressed, a sound from “Lullaby” plays
Key “m” pressed, a sound from “Rumor” plays

REFLECTION STATEMENT: After getting inspired by “Patatap,” I wanted to create something similar to it. My project, “EDM AND JAM!” focuses on EDM sounds with animations or graphics that reminds me of a particular corresponding sound. Although the code was pretty straightforward, cutting out individual sound from music files was tedious and challenging. It was cool to see the final project though! I had a fun time playing around with it, and even putting a background music while I run the program.

SONGS USED: “Lullaby” by R3HAB, “Rumors” by R3HAB (and other random sounds)

Xiaoying Meng -Final Project

sketch

//Xiaoying Meng
//Section B
//xiaoyinm@andrew.cmu.edu
//final project

var soulmate;//song
var fft;
var w;//width for fft visual
var play = false;
var amp;
var vol = [];

//load song
function preload(){
    soulmate = loadSound('https://courses.ideate.cmu.edu/15-104/f2018/wp-content/uploads/2018/12/01-SoulMate-feat.-IU-online-audio-converter.com_.mp3');
}
function setup() {
    createCanvas(256,256);
    fft = new p5.FFT(0,64);
    w = width/64;//divide amp visual width
    amp = new p5.Amplitude();
}

function draw(){
    background(255,196,8);
    noStroke();
    //fft visual 
    var spectrum = fft.analyze();
    for (var i=0; i < spectrum.length; i++){
        var amp2 = spectrum[i];
        var y = map(amp2,0,256,height,0);//map fft to canvas height
        //draw rectangles for visual
        fill(255,255,255,200);
        rect(i*w,y-6,w-1,height - y);//rectangles showing different frequencies
        ellipse(random(0,260),y,2,2);//randomly placed dots for filter effect
    }

//amp visual
    push();
    var singlevol = amp. getLevel(); //add single volume to array
    vol.push(singlevol);
    stroke(255);
    noFill();
    for (var i=0; i < vol.length; i++){
        var m = map(vol[i],0,1,height,0);// map volume to canvas 
    }
    pop();
    if(vol.length > width-50){
        vol.splice(0,1);
    }
//d circle degree
    for(var d=0;d<=360; d+=2){

        x1=200+m*cos(d);
        y1=150+m*sin(d);
        x2=200+(m+40)*cos(d+50);
        y2=150+(m+40)*sin(d+50);
        x3=200+(m+80)*cos(d+10);
        y3=150+(m+80)*sin(d+10);            
        x4=200+(m+120)*cos(d+50);
        y4=150+(m+120)*sin(d+50);

        
        strokeWeight(0.3);
        stroke(255);
        //line between 1st and 2nd cimcle
        line(x2,y2,x1,y1);
        //line between 3rd and 1st, 2nd circle
        line(x2,y2,x3,y3);
        line(x1,y1,x3,y3); 

        //line between 4th circle and 1st, 2nd, 3rd circle
        line(x3,y3,x4,y4);
        line(x2,y2,x4,y4);
        line(x1,y1,x4,y4);        
    }
    //distinguish larger amplitude sounds with ellipse
    if (singlevol>0.1){
        ellipse(200,150,120,120);
        noFill();
        stroke(255);
        strokeWeight(2);
        ellipse(200,150,130,130);
    }
        drawButton(); //drawing button
}

function drawButton(){
    //changing between rectangle and triangle
    noStroke();
    fill(255);
    if (play === true){
        rect(10,height-26,20,20);
    }else{
        triangle(10,height-26,30,height-16,10,height-6);
    }
}

function mousePressed(){
    //playing and pausing 
    if(mouseX>10 & mouseX <30 && mouseY > height-26 && mouseY < height-6 ){
        if(play){
            soulmate.pause();
        }else{
            soulmate.play();
        }
        play =! play;
    }
}

I wanted to create sound visualization since we did not do much of this. My final project tries to connect music to visual and express a mood and atmosphere. I always feel cheerful when I listen to this song, Soulmate by Zico. Therefore I used yellow for the visuals. The visuals are created by analyzing the song’s frequency and amplitude. Simply click the play button to enjoy the music.

Christine Seo – Final Project

sketch

//Chrisitne Seo
//mseo1@andrew.cmu.edu
//Section C
//Final Project

//items, where they are placed
var smileX = 200, smile, smileY = 0;
var clover, cloverX = 100, cloverY = 0;
var drop, dropX = 250, dropY = 0;
var cat, catX = 495, catY = 0;
var fire, fireX = 380, fireY = 0;
var flower, flowerX = 430, flowerY = 0;
var heart, heartX = 330, heartY = 0;
var mad, madX = 20, madY = 0;
var star, starX = 140, starY = 0;
var thunder, thunderX = 150, thunderY = 0;
var startY = 0;

var beat1, beat2, beat3, beat4, beat5, beat7, beat8, beat9, beatS;

//speed that the items want to go
var directionY = 1, directionX = 0, direction1Y = 0.7, direction2Y = 2,direction3Y = 2.5, direction3Y = 2.5, direction4Y = 2.1, direction5Y = 0.4, direction6Y = 0.2, direction7Y = 1.5, direction8Y = 1.2, direction9Y = 0.2;

//no repetition of sounds when touched once
var lastFrameTouch, lastFrameTouch2, lastFrameTouch3, lastFrameTouch4, lastFrameTouch5, lastFrameTouch6, lastFrameTouch7, lastFrameTouch8, lastFrameTouch9;

//sound trackers
var ctracker, mic;
var volume = 0;
var currScene = 0;

//recording
var recorder;
var soundFile;
var state = 0;

//color of eyebrows
var r = 176;
var g = 196;
var b = 222;

function preload(){ //beats that each item plays
  beat1 = loadSound("beats/1.mp3");
  beat2 = loadSound("beats/2.mp3");
  beat3 = loadSound("beats/3.mp3");
  beat4 = loadSound("beats/4.mp3");
  beat5 = loadSound("beats/5.mp3");
  beat7 = loadSound("beats/7.mp3");
  beat8 = loadSound("beats/8.mp3");
  beat9 = loadSound("beats/9.mp3");
  beatS  = loadSound("beats/swoosh.mp3");
}

function setup() {
  
  // setup camera capture
  var videoInput = createCapture(VIDEO);
  videoInput.size(550, 500);
  videoInput.position(0, 0);

  // setup canvas
  var cnv = createCanvas(550, 500);
  cnv.position(0, 0);

  // setup tracker
  ctracker = new clm.tracker();
  ctracker.init(pModel);
  ctracker.start(videoInput.elt);

  // Create an Audio input
  mic = new p5.AudioIn();
  mic.start();
  
  //recording
  recorder = new p5.SoundRecorder();
  recorder.setInput(mic);
  soundFile = new p5.SoundFile();
  
  //loading the items
  smile = loadImage("images/smile.png");
  clover = loadImage("images/clover.png");
  drop = loadImage("images/drop.png");
  cat = loadImage("images/cat.png");
  fire = loadImage("images/fire.png");
  heart = loadImage("images/heart.png");
  flower = loadImage("images/flower.png");
  mad = loadImage("images/mad.png");
  star = loadImage("images/star.png");
  
  //making sure each item is false when it didn't touch the face
  lastFrameTouch = false;
  lastFrameTouch2 = false;
  lastFrameTouch3 = false;
  lastFrameTouch4 = false;
  lastFrameTouch5 = false;
  lastFrameTouch6 = false;
  lastFrameTouch7 = false;
  lastFrameTouch8 = false;
  lastFrameTouch9 = false;
  
}

function draw() {
  
  //playing through by "scenes"
  if(currScene == 0){
  	startScene();
  } else if (currScene == 1){
    camScene();  
		}
}

function startScene(){ 
  
  //frame
  push();
  noFill();
  stroke("PaleVioletRed");
  strokeWeight(50);
  rect(0,0,width,height);
  pop();
  
  //start button
  stroke("LightSteelBlue");
  strokeWeight(5);
  fill(0);
  rect(200,365,170,100,60);
  push();
  fill("PaleVioletRed");
  strokeWeight(3);
  textSize(50);
  textStyle(BOLD);
  stroke("PapayaWhip");
  text("start",232,430);

  //intstructions
  fill(0);
  textSize(20);
  text("Catch each item",310,70);
  text("with your eyebrows",310,100);
  text("in order to make",310,130);
  text("your own soundtrack!",310,160);
  textSize(13);
  stroke("LightSteelBlue");
  text("*fyi: need to refresh if",350,190);
  text("face detection jitters",350,210);
  stroke("PaleVioletRed");
  text("*play with speakers",350,230);
  pop();
  
}

function camScene(){
  
  //face tracker codes
  clear();
 
  //getting mic
  var v = mic.getLevel();
  
  //getting volume
  volume += (v-volume)/3;

  var detectionScore = ctracker.getScore();
  	
 	if (detectionScore > 0) { 
    //location points of the faces  
  	var positions = ctracker.getCurrentPosition();
  	var leftBrowX = positions [20][0];
  	var leftBrowY = positions [20][1];  
    var rightBrowX = positions [16][0];
    var rightBrowY = positions [16][1];
    var faceLeftX = positions [1][0];
    var faceLeftY = positions [1][1];
    var faceRightX = positions [13][0];
    var faceRightY = positions [13][1];
    var noseX = positions [62][0]
    var noseY = positions [62][1];
    var eyeLeftX = positions [27][0];
    var eyeLeftY = positions [27][1];
    var eyeRightX = positions [32][0];
    var eyeRightY = positions [32][1];
    //corresponding the face feature sizes by volume
    var mouthSize = map(volume, 0,0.3, 70, 100);
    var eyeSize = map(volume,0,0.3,45,75);
    var eyeballSize = map(volume,0,0.3,40,70);
    var noseSize = map(volume,0,0.3,25,55);
    var eyebrowSize = map(volume,0,0.3,20,30);
    
    rect(5,5,230,40);
    fill(0);  
    textSize(15);  
    text('Double click to pause & record', 18, 25);
    
  //smile sounds
  if (smileX > leftBrowX - 50 &  smileX < leftBrowX + 50 && smileY > leftBrowY - 20 && smileY < leftBrowY + 20){
    directionY = 0; //stop when it touches the eyebrow until brow moves again
    r = 255; //change colors of eyebrows in relation to item
    g = 255;
    b = 0;
    if(! lastFrameTouch2){ 
      beat2.loop();  
      lastFrameTouch2 = true; //play sound once
      r = 255; //change colors of eyebrows in relation to item
      g = 255;
      b = 0;  
    } //same as about but for right brow placements
  } else if (smileX > rightBrowX - 50 &  smileX < rightBrowX + 50 && smileY > rightBrowY - 20 && smileY < rightBrowY + 20){
    	directionY = 0;  
      if(! lastFrameTouch2){ 
      	beat2.loop();  
        lastFrameTouch2 = true;
      } //if item stops touching the face, continue falling down
    } else { 
        directionY = 1.5;
      }
    
	//fire sounds
  if (fireX > leftBrowX - 50 &  fireX < leftBrowX + 50 && fireY > leftBrowY - 20 && fireY < leftBrowY + 20){
    direction4Y = 0; //stop when it touches the eyebrow until brow moves again
    r = 255; //change colors of eyebrows in relation to item
    g = 125;
    b = 65;  
    if(! lastFrameTouch){
    	beat1.loop();  
      lastFrameTouch = true; //play sound once
    } //same as about but for right brow placements
  } else if (fireX > rightBrowX - 50 &  fireX < rightBrowX + 50 && fireY > rightBrowY - 20 && fireY < rightBrowY + 20){
    direction4Y = 0;  
    r = 255;
    g = 125;
    b = 65; 
    if(! lastFrameTouch){
    	beat1.loop();  
      lastFrameTouch = true;
    } //if item stops touching the face, continue falling down
  } else {
      direction4Y = 1.6;
    }
    
    //clover sounds
	if (cloverX > leftBrowX - 50 &  cloverX < leftBrowX + 50 && cloverY > leftBrowY - 20 && cloverY < leftBrowY + 20){
  	direction1Y = 0; //stop when it touches the eyebrow until brow moves again
    r = 75; //change colors of eyebrows in relation to item
    g = 185;
    b = 105; 
    if(! lastFrameTouch3){
    	beat3.loop();  
      lastFrameTouch3 = true; //play sound once
    } //same as about but for right brow placements
	} else if (cloverX > rightBrowX - 50 &  cloverX < rightBrowX + 50 && cloverY > rightBrowY - 20 && cloverY < rightBrowY + 20){
    direction1Y = 0; 
    r = 75;
    g = 185;
    b = 105; 
    if(! lastFrameTouch3){
    	beat3.loop();  
      lastFrameTouch3 = true;
    } //if item stops touching the face, continue falling down
  } else {
  	direction1Y = 0.9;
    }
    
    //drop sounds
	if (dropX > leftBrowX - 50 &  dropX < leftBrowX + 50 && dropY > leftBrowY - 20 && dropY < leftBrowY + 20){
  	direction2Y = 0; //stop when it touches the eyebrow until brow moves again
    r = 130; //change colors of eyebrows in relation to item
    g = 200;
    b = 255; 
    if(! lastFrameTouch4){
    	beat4.loop();  
      lastFrameTouch4 = true; //play sound once
    } //same as about but for right brow placements
  } else if (dropX > rightBrowX - 50 &  dropX < rightBrowX + 50 && dropY > rightBrowY - 20 && dropY < rightBrowY + 20){
    direction2Y = 0;  
    r = 130;
    g = 200;
    b = 255; 
		if(! lastFrameTouch4){
  		beat4.loop();  
      lastFrameTouch4 = true;
    } //if item stops touching the face, continue falling down
	} else {
    direction2Y = 0.73;
    }
    
   //cat sounds
	if (catX > leftBrowX - 50 &  catX < leftBrowX + 50 && catY > leftBrowY - 20 && catY < leftBrowY + 20){
		direction3Y = 0; //stop when it touches the eyebrow until brow moves again
    r = 160; //change colors of eyebrows in relation to item
    g = 160;
    b = 160;      
    if(! lastFrameTouch5){
    	beat5.loop();  
      lastFrameTouch5 = true; //play sound once
    } //same as about but for right brow placements
	} else if (catX > rightBrowX - 50 &  catX < rightBrowX + 50 && catY > rightBrowY - 20 && catY < rightBrowY + 20){
    direction3Y = 0;  
    r = 160;
    g = 160;
    b = 160;   
		if(! lastFrameTouch5){
    	beat5.loop();  
      lastFrameTouch5 = true;
    } //if item stops touching the face, continue falling down
	} else {
    direction3Y = 0.65;
    }

//flower sounds
	if (flowerX > leftBrowX - 50 & flowerX < leftBrowX + 50 && flowerY > leftBrowY - 20 && flowerY < leftBrowY + 20){
  	direction5Y = 0; //stop when it touches the eyebrow until brow moves again
    r = 250; //change colors of eyebrows in relation to item
    g = 250;
    b = 250;
    if(! lastFrameTouch6){
    	beat8.loop();  
      lastFrameTouch6 = true; //play sound once
    } //same as about but for right brow placements
	} else if (flowerX > rightBrowX - 50 & flowerX < rightBrowX + 50 && flowerY > rightBrowY - 20 && flowerY < rightBrowY + 20){
    direction5Y = 0;  
    r = 250;
    g = 250;
    b = 250;
		if(! lastFrameTouch6){
      beat8.loop();  
      lastFrameTouch6 = true;
		} //if item stops touching the face, continue falling down
	} else {
    direction5Y = 0.8;
    }
    
   //heart sounds
	if (heartX > leftBrowX - 50 &  heartX < leftBrowX + 50 && heartY > leftBrowY - 20 && heartY < leftBrowY + 20){
		direction6Y = 0; //stop when it touches the eyebrow until brow moves again
    r = 200; //change colors of eyebrows in relation to item
    g = 0;
    b = 50;
    if(! lastFrameTouch7){
    	beat7.loop();  
    	lastFrameTouch7 = true; //play sound once
    } //same as about but for right brow placements
	} else if (heartX > rightBrowX - 50 & heartX < rightBrowX + 50 && heartY > rightBrowY - 20 && heartY < rightBrowY + 20){
    direction6Y = 0; 
    r = 200;
    g = 0;
    b = 50;
		if(! lastFrameTouch7){
      beat7.loop();  
      lastFrameTouch7 = true;
    } //if item stops touching the face, continue falling down
	} else {
    direction6Y = 1.65;
    }
    
    //mad sounds
	if (madX > leftBrowX - 50 & madX < leftBrowX + 50 && madY > leftBrowY - 20 && madY < leftBrowY + 20){
  	direction7Y = 0; //stop when it touches the eyebrow until brow moves again
    r = 250; //change colors of eyebrows in relation to item
    g = 0;
    b = 0;
    if(! lastFrameTouch8){
      beat9.loop();  
      lastFrameTouch8 = true; //play sound once
    } //same as about but for right brow placements
	} else if (madX > rightBrowX - 50 & madX < rightBrowX + 50 && madY > rightBrowY - 20 && madY < rightBrowY + 20){
    direction7Y = 0;  
    r = 250;
    g = 0;
    b = 0;
		if(! lastFrameTouch8){
      beat9.loop();  
      lastFrameTouch8 = true;
    } //if item stops touching the face, continue falling down
  } else {
    direction7Y = 1.3;
    }
    
    //star sounds
	if (starX > leftBrowX - 50 & starX < leftBrowX + 50 && starY > leftBrowY - 20 && starY < leftBrowY + 20){
    direction8Y = 0; //stop when it touches the eyebrow until brow moves again
    r = 240; //change colors of eyebrows in relation to item
    g = 220;
    b = 50;
    if(! lastFrameTouch9){
      beatS.loop();  
      lastFrameTouch9 = true; //play sound once
    } //same as about but for right brow placements
	} else if (starX > rightBrowX - 50 & starX < rightBrowX + 50 && starY > rightBrowY - 20 && starY < rightBrowY + 20){
    direction8Y = 0;  
    r = 240;
    g = 220;
    b = 50;  
		if(! lastFrameTouch9){
      beatS.loop();  
      lastFrameTouch9 = true;
    } //if item stops touching the face, continue falling down
  } else {
      direction8Y = 0.45;
    }
    
  //eyebrow
	stroke(r,g,b);
  fill("PapayaWhip");
  strokeWeight(7);
  rectMode(RADIUS);
  rect(leftBrowX,leftBrowY,eyebrowSize + 20,eyebrowSize-20);
  rect(rightBrowX,rightBrowY,eyebrowSize + 20,eyebrowSize-20);
    
  //eyes
  stroke("PapayaWhip");
  strokeWeight(2);
  fill(0);
  ellipse(eyeLeftX,eyeLeftY,eyeSize,eyeSize);
  ellipse(eyeRightX,eyeRightY,eyeSize,eyeSize);
  ellipse(positions[27][0],positions[27][1],eyeballSize,eyeballSize); 
  ellipse(positions[32][0],positions[32][1],eyeballSize,eyeballSize);

  //nose
  stroke("PaleVioletRed");
  fill("LightSteelBlue");
  ellipse(positions[62][0],positions[62][1],noseSize,noseSize+20);
        	
  //mouth
  stroke("PapayaWhip");
  fill("PaleVioletRed");
  arc(positions[47][0],positions[47][1],mouthSize,mouthSize,0,PI);
  }
  
  //placing item and moving it downwards and back up when it reaches bottom
  image(smile,smileX,smileY,50,50);
  smileX += directionX;
  smileY += directionY;
  	if (smileY > 460){
   		smileY = 0;
  	}
  
  //placing item and moving it downwards and back up when it reaches bottom
  image(clover,cloverX,cloverY,50,50);
  cloverX += directionX;
  cloverY += direction1Y;
    if (cloverY > 460){
    cloverY = 0;
  }
  
  //placing item and moving it downwards and back up when it reaches bottom
  image(drop,dropX,dropY,50,50);
  dropX += directionX;
  dropY += direction2Y;
    if (dropY > 460){
    dropY = 0;
  }
  
  //placing item and moving it downwards and back up when it reaches bottom
  image(cat,catX,catY,40,40);
  catX += directionX;
  catY += direction3Y;
    if (catY > 460){
    catY = 0;
  }
  
  //placing item and moving it downwards and back up when it reaches bottom
  image(fire,fireX,fireY,50,55);
  fireX += directionX;
  fireY += direction4Y;
    if (fireY > 460){
    fireY = 0;
  }
  
  //placing item and moving it downwards and back up when it reaches bottom
  image(flower,flowerX,flowerY,35,35);
  flowerX += directionX;
  flowerY += direction5Y;
    if (flowerY > 460){
    flowerY = 0;
  }
  
  //placing item and moving it downwards and back up when it reaches bottom
  image(heart,heartX,heartY,40,40);
  heartX += directionX;
  heartY += direction6Y;
    if (heartY > 460){
    heartY = 0;
  }

  //placing item and moving it downwards and back up when it reaches bottom
  image(star,starX,starY,40,40);
  starX += directionX;
  starY += direction8Y;
    if (starY > 460){
    starY = 0;
  }

  //placing item and moving it downwards and back up when it reaches bottom
  image(mad,madX,madY,40,40);
  madX += directionX;
  madY += direction7Y;
    if (madY > 460){
    madY = 0;
  }
}

function mousePressed(){
  //when mouse pressed, it switches scenes 
  
  if (currScene == 0){
    if (mouseX > 100 & mouseX < 500 && mouseY > 100 && mouseY < 300);
    	currScene =1;
    
  	} else if (currScene == 1){
    if (mouseX > 0 & mouseX < width && mouseY > 0 && mouseY < height);
    	currScene = 2;
      
	} else if (currScene == 2){
    if (state === 0) {
      // Tell recorder to record to a p5.SoundFile which we will use for playback
      recorder.record(soundFile);
      
      //buttons
      fill("LightSteelBlue");    	
      rect(5,5,230,40);
      fill(0);
      textSize(15);    
      text('Recording now! Click to stop.', 18, 25);
      state++;
  } else if (state === 1) {
      recorder.stop(); // stop recorder, and send the result to soundFile
      rect(5,5,288,40);
      fill("PapayaWhip");
      noStroke();
      text('Recording stopped. Click to play & save', 18, 25);
      state++;
  } else if (state === 2) {
      soundFile.play(); // play the result!
      saveSound(soundFile, 'mySound.wav'); // save file
      state++;
    }
	}
}

Start screen has instructions
When you touch an object it changes the the color of the eyebrows to the corresponding color (i.e clover = green)
The elements on the face vibrate corresponding to the audio
You can record your files with clicking the button
You can save your music as it saves as an audio file!

Caption: Video documentation of the final project

I realized that the WordPress does not run my project, so I provided a live online link to run my project: https://editor.p5js.org/mseo1/full/rkD_gLl0Q

For my final project, I was successfully able to perform what I wanted to display by adding audio (beats) and creating an instrument. This project is a fun game like instrument that lets you play beats (which I made my own beats using Garageband) with the items that are falling down. The beats are played when the items are touched with your eyebrows, which change colors corresponding with the color of the items. Additionally, the face detector adds an interesting visual addition to the project. The elements on the face (eyes, brows, nose, and mouth) increase/decrease in correlation to the sound of the audio, so you must run it with speakers, not headphones. The face recognition element was found on GitHub’s Javascript Library.  Finally, you can record the audio by clicking the button on the top of the screen, and download the file. Overall, this was a fun project to perform, as well as an interesting element to my portfolio.

Zip File: Seo Final

Julie Choi – Final Project

My final project requires the use of a camera (webcam), so it does not properly run on WordPress. Here is the link to the zip file:

Julie_Choi_Final_Project.zip

Instructions: Start with a white background for this project. Preferably wear a dark shade shirt and place your portrait on the center on the screen. An easier way to interact with this short game is to wait for all the balls to drop from the top of the screen, but this does not matter hugely. Start clicking the red balls to make them disappear. Once the screen has no red balls, an orange screen will pop up and tell you “good job!”

Since the program does not run on this page, here are some screenshots of the step by step process of the game.

This is how it looks when all the bubbles have stacked on top of each other.
This is how it looks when you click on the red bubbles to get rid of them on the screen.
This screen will appear once all the red bubbles disappear from the screen.

final project

/*Julie Choi
15-104 Section E
jjchoi@andrew.cmu.edu
Final Project
*/

var px = 20;
var py =  100;
var myCaptureDevice;
var brightnessThreshold = 50;
var darknessThreshold = 45
var circleCenter = [];
var x = 5;
var radius = 20;
var randomBalls = 2;
var initGeneration = true;
var initRandom = true;
let timer = 30;


function setup() {
    createCanvas(640, 480);
    myCaptureDevice = createCapture(VIDEO);
    myCaptureDevice.size(640, 480); // attempt to size the camera. 
    myCaptureDevice.hide(); // this hides an unnecessary extra view.
    frameRate(60);
    // generateCircleCenter function is called in setup
    generateCircleCenter();   	
}

function generateCircleCenter(){
	// sets the circles on the top of the circle by pushing makeCircleFall into the circle center
    while(x <= width - radius){
        circleCenter.push(makeCircleFall(x, 20, radius, true, false));
        x += radius;
    }
    x = 5;
    generateRandom(randomBalls);
}

function generateRandom(n){
	// generates more lines of circles to fall after the previous line
    if (n == 0){
        return;
    }
    var j = int(random(0, circleCenter.length));
    if (circleCenter[j].random != true){
        circleCenter[j].random = true;
        generateRandom(n-1);
    } else {
        generateRandom(n);
    }
}

function draw() {
    background(220);
    myCaptureDevice.loadPixels(); 
    // draw the camera at 1:1 resolution
    image(myCaptureDevice, 0, 0);  
    fill(255);
    // call all the objects in draw function
    for(var c = 0; c < circleCenter.length; c++){
        if (circleCenter[c].exist){
            circleCenter[c].render();
            circleCenter[c].update();
            if(circleCenter[c].py >= height){
                circleCenter[c].reset();
            }
        }
    }
    // if the frameCount is divisible by 60, then a second has passed. it will stop at 0
    if (frameCount % 60 == 0 & timer > 0) { 
        timer --;
    }
    if (timer % 2 == 1 & initGeneration){
        initGeneration = false;
        generateCircleCenter();
    }
    if (timer % 2 == 0 & initGeneration != true){
        initGeneration = true;
    }

    // instruction text on the bottom
    fill(0);
    noStroke();
    fill(255);
    textFont('futura');
    textSize(10);
    text("use a white background", width / 2, height - 25);
    text("tip: wait for all the balls to fall and have fun playing with the balls :)", width / 2, height - 10);
    textAlign(CENTER, CENTER);
    textSize(30);
    text( "Pop the red bubbles!", width / 2, height - 50);

    // detect only the py of the yellow point exsisting on the screen
    var result = circleCenter.filter(obj => {
    return obj.py > 0 & obj.random;
    });
    // if the result of the value above is 0 then the timer stops
    if (result.length == 0){
        timer == 0;
        fill(249, 173, 129);
        rect(0, 0, width, height);
        noFill();
        stroke(255);
        strokeWeight(1);
        text("GOOD JOB!", width/2, height /2);
    }
}

function makeCircleFall(inputX, inputY, radius, exist, random) {
    return {px: inputX, py: inputY, radius: radius, exist: exist, random: random,
            update: Update,
            reset: Reset,
            render: Render
           };
}

function isColor(c) {
    return (c instanceof Array);
}

function Update() {
    // fetch the color of the pixel at the (px,py) location of the circleCenter
    var theColorAtPxPy = myCaptureDevice.get(this.px, this.py);
    // compute its brightness
    if(isColor(theColorAtPxPy)){
        var theBrightnessOfTheColorAtPxPy = brightness(theColorAtPxPy);
    }
    // if the circleCenter is in a bright area, move downwards.
    // else, if it's in a dark area, move up until we're in a light area
    if(theBrightnessOfTheColorAtPxPy > brightnessThreshold){
        this.py += 1;
    } else if(theBrightnessOfTheColorAtPxPy < darknessThreshold & this.py > 0){
        this.py -=1;
        theColorAtPxPy = myCaptureDevice.get(px, py);
    }
    // take the objects in the circleCenter array and filter them into the name obj
    // obj.px to keep track of each px in the circleCenter array
    // this makes each circle stack on top of each other regarding the distance of the diameter of each circle
    var result = circleCenter.filter(obj => {
        return obj.px == this.px & obj.py > this.py
    });
    for (var i = 0; i < result.length; i++) {
        if ((result[i].py - radius) < this.py){
            this.py --;
        }
    }
}

function Reset() {
	// reset py to stop at the bottom of the screen
    this.py = height;
}

function Render() {
	// choose 3 circles randomly from each line to fill with red
    if(this.random){
        fill("red");
        stroke(255);
        strokeWeight(2);
        if (initRandom){
            initRandom = false;
        }
    }
    // draw circle at points of px and py in a line across the top of the screen
    if (this.exist) {
        ellipse(this.px, this.py, this.radius, this.radius);
        fill(random(0, 255), random(0, 255), random(0, 150), 80);
        stroke(255);
        strokeWeight(2);
        initRandom = true;
    }
}

function mousePressed() {
	// circles stay on the screen if exist is true
	// when mouse is pressed, exist and random becomes false to pop and make the circle that was clicked disappear
    for (var i = 0; i < circleCenter.length; i++) {
        var c = circleCenter[i];
        if (c.exist & dist(c.px, c.py, mouseX, mouseY) < c.radius / 2) {
            c.exist = false;
            c.random = false;
            return;
        }
    }
}

Reflection: This project utilizes the concept of raining letter assignment that we did a few weeks back. Using what we have learned plus some outside research more about p5.js, I was able to execute a satisfying result. I would say though that that using the different existing functions of p5.js and applying my mathematical calculation for the timer and the balls stacked on top of each other was the most challenging part. Overall, I learned a lot of new operators in the program and enjoyed the process of controlling both the display and the function.

Alice Fang and Jaclyn Saik – Final Project

This program uses the typeface ‘Avara’ from fontlibrary. Some of the words might not be perfectly aligned if the typeface isn’t installed. If so, here’s the zip file that includes the typeface: acfang_jsaik

And here’s a screen capture of all of the interactions: video

sketch

/*
An interactive display of Maya Angelou's poem "Still I Rise"
Click and move the mouse to interact, and press the right key to continue reading

We were inspired in part by digital children's books and "choose-your-own-adventure", except in this piece of 
work, we wanted to create simple interactions in a consistent aesthetic that would complement the words in poem.  
We also really love typography, poetry and literature, so we wanted to take the opportunity to augment a person's experience in 
the reading of a poem. 
 
We chose "Still I Rise" by Maya Angelou because we felt that her words were especially pertinent in today's social and political climate. 

Alice: Stanzas 1, 4, 8, 9, title slide, combining into one file
Jaclyn: Stanzas 3, 5, 6, 7, uploading font ('Avara') into css/html files
Stanza 2 ended up being a combination of the two of us
*/

var state = 0
var instruct = "click and explore to interact, press right key to continue";

// stanza 1
var stanza1a = ["You", "may", "write", "me", "down", "in", "history"];
var stanza1b = ["With", "your", "bitter,", "twisted", "lies,"];
var stanza1c = ["You", "may", "trod", "me", "in", "the", "very", "dirt"];
var stanza1d = ["But", "still,", "like", "dust,", "I’ll", "rise."];
var clickcountStanzaOne = 0;

//stanza 2
var stanzaSassyA = "Does my sassiness upset you?";
var stanzaSassyB = "Why are you beset with gloom?";
var stanzaSassyC = "’Cause I walk like I've got oil wells";
var stanzaSassyD = "Pumping in my living room.";
var AccentStanzaSassyA = "sassiness";
var SassyX = 50;
var SassyY = 200;
var timeKeeping = 0;
var AnotherPositionX = 180;
var AnotherPositionY = 180;
var ROLL = 0.1;
var CircleFill = 40;

// stanza 3
var stanzaThreeA = "Just like moons and like suns,";
var stanzaThreeB = "With the certainty of tides,";
var stanzaThreeC = "Just like hopes springing high,";
var stanzaThreeD = "Still I'll rise.";
var AccentStanzaA = "shoot me";
var AccentStanzaB = "cut me";
var AccentStanzaC = "kill me";
var tX = 50;
var tY = 200;
var y = 200;
var y2 = 200
var speed = 0;
var speed2 = 0;
var acceleration = 0.1;
var acceleration2 = 0.1;
var clicksStanzaThree = 0;
var Ang = 0;

// stanza 4
var stanza4 = "Did you want to see me broken?\nBowed head and lowered eyes?\nShoulders falling down like teardrops,\nWeakened by my soulful cries?";
var teardrops = "teardrops";
var tears = [];

// stanza 5
var stanzaFiveA = "Does my haughtiness offend you?";
var stanzaFiveB = "Don't you take it awful hard";
var stanzaFiveC = "’Cause I laugh like I've got gold mines";
var stanzaFiveD = "Diggin’ in my own backyard.";
var AccentStanzaFiveA = "gold";
var AccentStanzaFiveB = "haughtiness";
var AccentStanzaFiveC = "awful";
var AccentStanzaFiveD = "own";
var AccentStanzaFiveE = "laugh";
var FiveX = 50;
var Fivey = 200;
var ExRan = 10;
var terrainDetailB = 0.01;
var terrainSpeedB = 0.0002;
var imG;
var imgG2;

// stanza 6
var stanzaSixA = "You may shoot me with your words,";
var stanzaSixB = "You may cut me with your eyes,";
var stanzaSixC = "You may kill me with your hatefulness,";
var stanzaSixD ="But still, like air, I’ll rise.";
var AccentStanzaSixA = "shoot me";
var AccentStanzaSixB = "cut me";
var AccentStanzaSixC = "kill me";
var AccentStanzaSixD = "I'll rise.";
var SixtX = 50;
var SixtY = 200;

// stanza 7
var stanzaSevenA = "Does my sexiness upset you?";
var stanzaSevenB = "Does it come as a surprise";
var stanzaSevenC = "That I dance like I've got diamonds";
var stanzaSevenD = "At the meeting of my thighs?";
var AccentStanzaSexy = "sexiness";
var Sevent = 0; 
var SevenX = 50;
var SevenY = 200;
var words = [stanzaSevenA.split(" ")];
var speed = 0;
var speed2 = 0;
var acceleration = 0.1;
var acceleration2 = 0.1;

// stanza 8
var array = ["Out", "of", "the", "huts", "of", "history's", "shame"];
var array2 = ["I", "rise"];
var array3 = ["Up", "from", "a", "past", "that's", "rooted", "in", "pain"];
var array4 = ["I", "rise"];
var array5 = ["I'm", "a", "black", "ocean,", "leaping", "and", "wide,"];
var array6 = ["Welling", "and", "swelling", "I", "bear", "in", "the", "tide."];
var waveSpeed = 0.00005;
var waveDetail = 0.005;
var TimeWaveOne = 0.001;
var TimeWaveTwo = 0.0006;

// stanza 9
var stanza9a = "Leaving behind nights of terror and fear\nI rise";
var stanza9b = "Into a daybreak that’s wondrously clear\nI rise";
var stanza9c = "Bringing the gifts that my ancestors gave,\nI am the dream and the hope of the slave.";
var stanza9d = "I rise\nI rise\nI rise.";
var rows;
var cols;
var radius;
var d; 
var stateStanzaNine = 0;

function preload() { // load images for stanza 5
    var imgURL = "https://i.imgur.com/ppkgvPp.png";
    var imgURL2 = "https://i.imgur.com/QDwN1E1.png"
    imG = loadImage(imgURL);
    imgG2 = loadImage(imgURL2)
}

function setup() {
    createCanvas(480, 480);
    textFont("avara");

    // for stanza 4, pushing teardrops into array
    for (var i = 0; i < 8; i++) {
        var rainX = random(width);
        var rainY = -10;
        tears[i] = makerain(rainX, rainY);
    }
    // for stanza 9, determining grid variables
    rows = 100;
    cols = rows;
    radius = (width / rows) / 2;
    d = radius * 2;
}

function draw() {
    // change stanza when state changes; state changes when right key is pressed
    if (state === 0) {
        StanzaZero();
    } else if (state === 1) {
        StanzaOne();
    } else if (state === 2) {
        StanzaTwo();
    } else if (state === 3) {
        StanzaThree();
    } else if (state === 4) {
        StanzaFour();
        broken();
        for (var j = 0; j < tears.length; j++) { // draw and move teardrop objects
            tears[j].draw();
            tears[j].move();
        }
    } else if (state === 5) {
        StanzaFive();
    } else if (state === 6) {
        StanzaSix();
    } else if (state === 7) {
        StanzaSeven();
    } else if (state === 8) {
        wavey();
        foam();
        StanzaEight();
    } else if (state === 9 || state > 9) {
        StanzaNine();
    }
}

// introduction slide
function StanzaZero() { 
    background(66, 77, 88);
    fill('AliceBlue');
    textSize(30);
    textAlign(LEFT);
    text("Still I Rise", 50, 120);
    textSize(18);
    text("Maya Angelou", 50, 150);
    fill(240, 248, 255, 150);
    text("an interactive poem", 50, 240, 60);
    textSize(12);
    textAlign(RIGHT);
    text(instruct, 430, 430);
}

// stanza 1
function StanzaOne() { // as mouse is clicked, words appear on screen
    background(66, 77, 88);
    textSize(18);
    textAlign(LEFT);
    fill('AliceBlue');
    var offset1 = 0;
    var offset2 = 0;
    var offset3 = 0;
    var offset4 = 0;
    var yPOS = 200; // original y position of first line
        for (var i = 0; i < clickcountStanzaOne; i++) { // with each line, stanza length increases by previous line
        var sLength;
        if (i < stanza1a.length) {
           var WORD1 = textWidth(stanza1a[i]);
           text(stanza1a[i], 5 * i + offset1 + 50, yPOS);
           offset1 += WORD1; //offset determines spacing between words based of width of previous word
        } else if (i - stanza1a.length < stanza1b.length) {
          sLength = i - stanza1a.length;
          var WORD2 = textWidth(stanza1b[sLength]);
          text(stanza1b[sLength], 5 * (sLength) + offset2 + 50, yPOS + 25);
          offset2 += WORD2;
        } else if (i - stanza1a.length - stanza1b.length < stanza1c.length) {
          sLength = i - stanza1a.length - stanza1b.length;
          var WORD3 = textWidth(stanza1c[sLength]);
          text(stanza1c[sLength], 5 * (sLength) + offset3 + 50, yPOS + 50);
          offset3 += WORD3;
        } else if (i - stanza1a.length - stanza1b.length - stanza1c.length < stanza1d.length) {
          sLength = i - stanza1a.length - stanza1b.length - stanza1c.length;
          var WORD4 = textWidth(stanza1d[sLength]);
          text(stanza1d[sLength], 5 * (sLength) + offset4 + 50, yPOS + 75);
          offset4 += WORD4;
        }  
    }   
}

// stanza 2
function StanzaTwo() {
    trial(); //function  for rotating oil blobs
    StanzaSassyWords(); //function for printing stanza 2 words
    Stretch();
}

function StanzaSassyWords() {
    push();
    noStroke();
    textSize(18);
    fill('AliceBlue');
    text(stanzaSassyB, SassyX, SassyY + 30); //manually setting leading for the type 
    text(stanzaSassyC, SassyX, SassyY + 60);
    text(stanzaSassyD, SassyX, SassyY + 90);
    pop();
}

function trial() {
    fill(66, 77, 88);
    rect(-3, -3, width + 3, height + 3); //background rectangle
    for (var i = 0; i < 360; i += 3) { //for loop for the angle that the blobs rotate and generate
        var x = 0; //variables for blob's position and width
        var y = 0; 
        var w = 0;
        floor(x = cos(radians(i)) * 100 + width / 3); //floor function for whole numbers 
        floor(y = sin(radians(i)) * 100 + height / 2); 
        floor(w = sin(radians(timeKeeping/4 + i)) * 400); //the timekeeping variable keeps the blobs constantly moving
        w = abs(w); //whole and positive numbers for w, since it defines width

        float(colOR = map(i, 0, 360, 0, 30)); //color mapped from a range of gray 
        circleFill = map(mouseX, 0, width, 0, 40); //opacity mapped so it changes with mouseX
        noStroke();
        fill(colOR, circleFill);
        ellipse(x, y, w, w);
        fill(255);
    }
    timeKeeping++;
}

function Stretch() {
    push(); //stretch text vertically and horizontally based on mouse
    textSize(18);
    fill('AliceBlue');
    var MouseScaleX = map(mouseX, 100, width, 1, 2); 
    var MouseScaleY = map(mouseY, 100, height, 1, 2);
    scale(MouseScaleX, MouseScaleY);
    text(stanzaSassyA, SassyX, SassyY);
    pop();
}

// stanza 3
function StanzaThree() {
    StanzaThreeWords();
    if (clicksStanzaThree > 0) {
        BounceOne(); //call bounce function when screen is clicked
    }
    if (clicksStanzaThree > 1) {
        clicksStanzaThree = 0; //resets click count specifically for this stanza
    }
    BounceClick() //keeps click count increasing when mouse is pressed
    Moon(); //function for rotating sun and moon 
}

function StanzaThreeWords() {
    push();
    fill(66, 77, 88);
    rect(-3, -3, width + 10, height + 10); //background rectangle
    noStroke();
    textSize(18);
    textFont("Avara");
    fill(255, 255, 255);
    text(stanzaThreeA, tX, tY);
    text(stanzaThreeB, tX, tY + 30);
    text(stanzaThreeC, tX, tY + 60);
    text(stanzaThreeD, tX, tY + 90);

    stroke(66, 77, 88);
    strokeWeight(2);
    fill(66, 77, 88);
    text("springing", 183, 260); //type to cover existing type in stanza,
    text("hopes", 127, 260); //makes room for bouncing type
    noStroke();
    pop();
}

function BounceOne() { 
    textSize(18);
    fill(255);
    textFont("Avara");
    text("springing", 183, y + 60);
    y += speed;
    speed += acceleration;
    
    if (y + 60 > height || y + 60 < 1) { //invert direction if the type hits the bottom of the page 
        speed = -speed;
    }
    text("hopes", 127, y2 + 60);
    y2 += speed2;
    speed2 += acceleration2; //acceleration makes type get progressively faster 
    
    if (y2 + 60 > height || y2 + 60 < 1) { //invert direction if the type hits the bottom of the page
        speed2 = -speed2;
    }
}

function BounceClick() {
    if (mouseIsPressed) {
        clicksStanzaThree++; //adds clicks to stanza click variable
    }
}

function Moon() {
    noStroke();
    push();
    translate(240, 240); //translates center to the center of the page 
    rotate(radians(Ang)); //rotates by Angle defined globally 
    Ang += 0.7; 
    var moonX = 200; //moon and sun inversely positioned to each other 
    var moonY = 90;
    var sunX = -200;
    var sunY = -90;
    fill(255);
    ellipse(moonX, moonY, 30, 30);
    fill(66, 77, 88, 220);
    ellipse(moonX - 10, moonY, 30, 30); //moon is made of 2 ellipses
    noStroke();
    fill(255);
    sunshine(sunX, sunY); //calls function for sun rays 
    pop();
}

function sunshine(sx, sy) { //seperate function for sun rays 
    strokeWeight(2);
    stroke(255);
    line(sx - 20, sy, sx + 20, sy);
    line(sx, sy - 20, sx, sy + 20);
    line(sx - 15, sy - 15, sx + 15, sy + 15);
    line(sx + 15, sy - 15, sx - 15, sy + 15);
    stroke(66, 77, 88);
    strokeWeight(3);
    ellipse(sx, sy, 30, 30);
}

// stanza 4
function StanzaFour() {
    background(66, 77, 88);
    fill('AliceBlue');
    textSize(18);
    noStroke();
    text(stanza4, 50, 180);
    text(teardrops, 299, 225);
}

function makerain() {
    var drop = { x: random(0, width),
                y: -10,
                speed: random(1, 2),
                draw: drawrain,
                move: moverain}
    return drop;
}

function drawrain() { // create falling teardrops
    textSize(12);
    var tearOpacity = map(this.y, 0, height, 200, 0);
    stroke(240, 248, 255, tearOpacity);
    noFill();
    var tearSize = random(4, 8);
    ellipse(this.x, this.y, tearSize, tearSize);
    noStroke();
}

function moverain() {
    this.y += this.speed;
    if (this.y > height) {
        this.y = -10;
    }
}

function broken() { // as mouseY changes, background darkens, highlighting last line of stanza
    var OP = map(mouseY, 0, height, 0, 255); // map opacity to mouseY
    background(30, 30, 40, OP);
    fill('AliceBlue');
    text("Weakened by my soulful cries?", 50, 248);
}

// stanza 5
function StanzaFive() {
    DarkHill(); //background and digging person function 
    StanzaFiveWords(); //stanza word placement 
    DrawTwoo(); //function for the cursor effect
    GoldenWords(); //word interaction function 
}

function StanzaFiveWords() { //simlpe placement of stanza
    push();
    noStroke();
    textSize(18);
    textFont("Avara");
    fill(255, 255, 255);
    text(stanzaFiveA, FiveX, Fivey);
    text(stanzaFiveB, FiveX, Fivey + 30);
    text(stanzaFiveC, FiveX, Fivey + 60);
    text(stanzaFiveD, FiveX, Fivey + 90);
    pop();
}

function DrawTwoo() { //cursor effect to illuminate the mouse
    stroke(255, 215, 80);
    strokeWeight(4);
    line(mouseX, mouseY, pmouseX, pmouseY);
}

function GoldenWords() { //function for the gold words when mouse hovers 
    push();
    stroke(255, 215, 80); //includes background type and also 
    strokeWeight(1);
    textSize(18);
    textFont("Avara");
    fill(255, 215, 80);
    ExRan = random(0, 2);

    if (dist(mouseX, mouseY, 285 + 5, 260) < 40) {
        text(AccentStanzaFiveA, 285, 260); // "gold"
        strokeWeight(3);
        textSize(27);
        textFont("Avara");
        fill(255, 215, 80, 20);
        stroke(255, 215, 80, 20);
        text(AccentStanzaFiveA, 285 + ExRan, 260 + ExRan); // "gold"
    } 
    if (dist(mouseX, mouseY, 135 + 10, 200) < 40) {
        text(AccentStanzaFiveB, 135, 200); // "haughty"
        strokeWeight(3);
        textSize(27);
        textFont("Avara");
        fill(255, 215, 80, 20);
        stroke(255, 215, 80, 20);
        text(AccentStanzaFiveB, 135 + ExRan, 200 + ExRan); // "haughty"
    }
    if (dist(mouseX, mouseY, 201 + 5, 230) < 40) {
        text(AccentStanzaFiveC, 201, 230); // "awful"
        strokeWeight(3);
        textSize(27);
        textFont("Avara");
        fill(255, 215, 80, 20);
        stroke(255, 215, 80, 20);
        text(AccentStanzaFiveC, 201 + ExRan, 230 + ExRan); // "awful"
    }
    if (dist(mouseX, mouseY, 182 + 5, 290) < 40) {
        text(AccentStanzaFiveD, 182, 290); // "own"
        strokeWeight(3);
        textSize(27);
        textFont("Avara");
        fill(255, 215, 80, 20);
        stroke(255, 215, 80, 20);
        text(AccentStanzaFiveD, 182 + ExRan, 290 + ExRan); // "own"
    }
    if (dist(mouseX, mouseY, 124 + 5, 260) < 40) {
        text(AccentStanzaFiveE, 124, 260); // "laugh"
        strokeWeight(3);
        textSize(27);
        textFont("Avara");
        fill(255, 215, 80, 20);
        stroke(255, 215, 80, 20);
        text(AccentStanzaFiveE, 124 + ExRan, 260 + ExRan); // "laugh"
    }
    noStroke();
    pop();
}

function DarkHill() { //function for background hill and digging
    push();
    background(66, 77, 88); //generative landscape based on milliseconds
    beginShape(); 
    stroke(0, 30);
    for (var x = 0; x < width; x++) { //
        var t = (x * terrainDetailB) + (millis() * terrainSpeedB);
        var y = map(noise(t), 0,1, 100, 200);
        line(x, y, x, height); 
    }
    endShape();
    pop();

    if (dist(mouseX, mouseY, 285 + 5, 260) < 80) { //mouse trigger for the digging person to animate 
        image(imgG2, 100, 100);
    } else {
        image(imG, 100, 100);
    }
}
// stanza 6
function StanzaSix() {
    background(66, 77, 88);
    Shootin(); //function for stanza six type 
    Blinds(); //function for closing blinds
    Accent(); //function for accent type above blinds  
}

function Shootin() { 
    push();
    fill(66, 77, 88);
    rect(0, 0, width, height);
    noStroke();
    textSize(18);
    textFont("Avara");
    fill(255, 255, 255);
    text(stanzaSixA,SixtX,SixtY);
    text(stanzaSixB,SixtX,SixtY + 30);
    text(stanzaSixC,SixtX,SixtY + 60);
    text(stanzaSixD,SixtX,SixtY + 90);
    pop();
}

function Blinds() {
    noStroke();
    var whyOne = max(0, min(mouseY, 479));
    var gentleOne = 0.5; //determines easing function for each "blind"
    var gentleTwo = 0.7;
    var y = 1; //y length for blind 1
    var y2 = 1; //y length for blind 2

    var disy = whyOne - y; //finds distance between mapped y vaiable and y position 
    var disy2 = whyOne - y2;
    y += disy * gentleOne; //applies distance to easing 
    y2 += disy2 * gentleTwo;

    //blinds 1
    fill(30, 30, 40, 220);//opacity 
    rect(480, 0, -y, 480); //negative y value so that the blinds open and close on both sides 
    rect(0, 0, y, 480)
    //blinds2
    fill(30, 30, 40, 220);
    rect(480, 0, -y2, 480);
    rect(0, 0, y2, 480)
}

function Accent() { //simple function for placing selected accent words on top of blinds
    fill(255);
    textSize(18);
    textFont("Avara");
    text(AccentStanzaSixA, SixtX + 83.5, SixtY);
    text(AccentStanzaSixB, SixtX + 83.5, SixtY + 30);
    text(AccentStanzaSixC, SixtX + 83.5, SixtY + 60);
    text(AccentStanzaSixD, SixtX + 152.5, SixtY + 90);
}

// stanza 7
function StanzaSeven(){
    mouseGlow(); //mouse background function to make type more readible when mouse hovers 
    wavee() //wave function for diamond pattern 
    Sexy1(); //basic stanza type 
    if (mouseIsPressed) {
        Sexy2(); //second type interaction 
    }
}
function Sexy1() { //basic stanza type 
    push();
    noStroke();
    buffer = dist(mouseX, mouseY, SevenX + 150, SevenY + 40);
    textSize(18);
    textFont("Avara");
    fill('AliceBlue');
    text(stanzaSevenA, SevenX, SevenY);
    text(stanzaSevenB, SevenX, SevenY + 30);
    text(stanzaSevenC, SevenX, SevenY + 60);
    text(stanzaSevenD, SevenX, SevenY + 90);
    pop();
  }

function mouseGlow() {
    noStroke();
    fill(66, 77, 88);
    ellipse(mouseX, mouseY, 120, 120); //ellipse follows mouse, function placed BEHIND 
    //all other functions so this becomes another background
}

function wavee() {
    background(66, 77, 88, 20); 
    noFill();
    stroke(255, 180);
    strokeWeight(1);
    for (var x = 0; x <= width; x = x + 90) { 
        for (var y = 0; y <= height; y = y + 60) { //nested for loop defines grid system for diamonds
            var xAngle = map(mouseX, 0, width, -4 * PI, 4 * PI, true); //maps angle around a circle so it's based on 
            var yAngle = map(mouseY, 0, height, -4 * PI, 4 * PI, true); //the mouse x and y positions 
            var angle = xAngle * (x / width) + yAngle * (y / height); //angle tells diamond to osccillate
            var myX = x + 20 * cos(2 * PI * Sevent + angle); //synthesize x and y angles to one data point for each diamond
            var myY = y + 20 * sin(2 * PI * Sevent + angle);//also makes the diamond change over time regardless of mouse
            Diamond(myX, myY);
        }
    }
    Sevent = Sevent + 0.01; //time function 
}
function Diamond(vx, vy) { //function to manually draw diamond shapes 
    noFill();
    beginShape();
    vertex(vx, vy);
    vertex(vx + 4, vy);
    vertex(vx + 8, vy + 4);
    vertex(vx, vy + 12);
    vertex(vx - 8, vy + 4);
    vertex(vx - 4, vy);
    endShape(CLOSE);

    beginShape();
    vertex(vx - 8, vy + 4);
    vertex(vx + 8, vy + 4);
    vertex(vx, vy + 12);
    vertex(vx - 4, vy + 4);
    vertex(vx, vy);
    vertex(vx + 4, vy + 4);
    vertex(vx, vy + 12);
    endShape(CLOSE);
}

function Sexy2() { //function for interaction with the words "sexinesss"
    textSize(18);
    textFont("Avara");
    fill(0);
    fill(255, 215, 80);
    noStroke();
    text(AccentStanzaSexy, 134.5, 200);
}

// stanza 8
function StanzaEight() { // "wavy" text, affected by mouseX and mouseY
    fill('AliceBlue');
    noStroke();
    var offset1 = 0;
    var yPOS = 85;
    for (var a = 0; a < array.length; a++) { //first line
        var WORD1 = textWidth(array[a]);
        text(array[a], 5 * a + offset1 + 50, yPOS);
        offset1 += WORD1; // offset determines spacing between words based on width of previous word

        var d = dist(mouseX, mouseY, 5 * a + offset1 + 10, yPOS);
        if (d > 0 & d < 20) { // based on distance, word will rise/ fall
            yPOS += 1;
        }
        if (d > 0 & d < 35) {
            yPOS += 5;
        }
        if (d > 0 & d < 50) {
            yPOS += 8;
        }
    }
    var offset2 = 0;
    var yPOS2 = 135;
    for (var b = 0; b < array2.length; b++) { //second line
        var WORD2 = textWidth(array2[b]);
        text(array2[b], 5 * b + offset2 + 50, yPOS2);
        offset2 += WORD2;

        var dd = dist(mouseX, mouseY, 5 * b + offset2 + 10, yPOS2);
        if (dd > 0 & dd < 20) { // based on distance, word will rise/ fall
            yPOS2 += 1;
        }
        if (dd > 0 & dd < 35) {
            yPOS2 += 5;
        }
        if (dd > 0 & dd < 50) {
            yPOS2 += 8;
        }
    }
    var offset3 = 0;
    var yPOS3 = 185;
    for (var c = 0; c < array3.length; c++) { //third line
        var WORD3 = textWidth(array3[c]);
        text(array3[c], 5 * c + offset3 + 50, yPOS3);
        offset3 += WORD3;

        var ddd = dist(mouseX, mouseY, 5 * c + offset3 + 10, yPOS3);
        if (ddd > 0 & ddd < 20) { // based on distance, word will rise/ fall
            yPOS3 += 1;
        }
        if (ddd > 0 & ddd < 35) {
            yPOS3 += 5;
        }
        if (ddd > 0 & ddd < 50) {
            yPOS3 += 8;
        }
    }
    var offset4 = 0;
    var yPOS4 = 235;
    for (var d = 0; d < array4.length; d++) { //fourth line
        var WORD4 = textWidth(array4[d]);
        text(array4[d], 5 * d + offset4 + 50, yPOS4);
        offset4 += WORD4;

        var dddd = dist(mouseX, mouseY, 5 * d + offset4 + 10, yPOS4);
        if (dddd > 0 & dddd < 20) { // based on distance, word will rise/ fall
            yPOS4 += 1;
        }
        if (dddd > 0 & dddd < 35) {
            yPOS4 += 5;
        }
        if (dddd > 0 & dddd < 50) {
            yPOS4 += 8;
        }
    }
    var offset5 = 0;
    var yPOS5 = 285;
    for (var e = 0; e < array5.length; e++) { //fifth line
        var WORD5 = textWidth(array5[e]);
        text(array5[e], 5 * e + offset5 + 50, yPOS5);
        offset5 += WORD5;

        var ddddd = dist(mouseX, mouseY, 5 * e + offset5 + 10, yPOS5);
        if (ddddd > 0 & ddddd < 20) { // based on distance, word will rise/ fall
            yPOS5 += 1;
        }
        if (ddddd > 0 & ddddd < 35) {
            yPOS5 += 5;
        }
        if (ddddd > 0 & ddddd < 50) {
            yPOS5 += 8;
        }
    }
    var offset6 = 0;
    var yPOS6 = 335;
    for (var f = 0; f < array6.length; f++) { //sixth line
        var WORD6 = textWidth(array6[f]);
        text(array6[f], 5 * f + offset6 + 50, yPOS6);
        offset6 += WORD6;

        var dddddd = dist(mouseX, mouseY, 5 * f + offset6 + 10, yPOS6);
        if (dddddd > 0 & dddddd < 20) { // based on distance, word will rise/ fall
            yPOS6 += 1;
        }
        if (dddddd > 0 & dddddd < 35) {
            yPOS6 += 5;
        }
        if (dddddd > 0 & dddddd < 50) {
            yPOS6 += 8;
        }
    }
}

// create wave and foam for stanza 8
function wavey() {
    background(66, 77, 88);
    beginShape();
    stroke(30, 30, 40);
    for (var w = 0; w < width; w++) {
        var t = (w * TimeWaveOne) + (millis() * TimeWaveTwo);
        var waveY = map(noise(t), 0, 0.5, 0, mouseY);
        line(w, waveY, w, width);
    } endShape();
}

function foam() {
    beginShape();
    stroke(255, 255, 255, 90);
    for (var waveF = 0; waveF < width; waveF++) {
        var t = (waveF * TimeWaveOne) + (millis() * TimeWaveTwo);
        var foamY = map(noise(t), 0, 0.5, 0, mouseY);
        vertex(waveF, foamY - 5);
        vertex(waveF, foamY - 5);
    } endShape();
}   

// stanza 9
function StanzaNine() {
    if (stateStanzaNine == 0) { //highlight only first two lines
        fill('AliceBlue');
        stroke(0);
        textSize(18);
        text(stanza9a, 50, 125);
        if (mouseX > 40 & mouseX < 140 && mouseY > 105 && mouseY < 165) {
            fill(66, 77, 88);
            text("rise", 62.25, 147.25) //change color when mouse hovers to indicate "click"
        }
    }
    if (stateStanzaNine == 1) { //highlight only third and fourth lines
        fill('AliceBlue');
        stroke(0);
        text(stanza9b, 50, 170);
        if (mouseX > 40 & mouseX < 140 && mouseY > 150 && mouseY < 215) {
            fill(66, 77, 88);
            text("rise", 62.25, 192.25) //change color when mouse hovers to indicate "click"
        }
    }
    if (stateStanzaNine == 2) { //highlight only fifth and sixth lines
        fill('AliceBlue');
        text(stanza9c, 50, 215);
        stroke(0);
        fill(255, 215, 80);
        text("hope", 268.25, 237.5); //change color when mouse hovers to indicate "click"
    }
    drawGrid(); // create spotlight
    
    if (stateStanzaNine == 3) { //reveal last stanza
        background(255, 250, 205);
        fill(110);
        text(stanza9a, 50, 125);
        text(stanza9b, 50, 170);
        text(stanza9c, 50, 215);
        fill(0);
        text(stanza9d, 50, 300);
    }
}

function drawGrid() { //create spotlight grid
    for (var gridY = 0; gridY < height; gridY += d) {
        for (var gridX = 0; gridX < width; gridX += d) {
            var modifiedX = gridX;
            if ((gridY % (d * 2)) === 0) {
                modifiedX = gridX + radius;
            }
            fill(0);
            var distance = dist(mouseX, mouseY, modifiedX, gridY);
            opacity = map(distance, 0, 160, 0, 255); //zero opacity at center of spotlight, fade as dist increases
            noStroke();
            fill(0, 0, 0, opacity);
            rectMode(CENTER);
            rect(gridX, gridY, d, d);
        }
    }
}

// for stanza nine
function mouseClicked() { //range for click-ability to switch lines
    if (state === 9 & mouseX > 40 && mouseX < 140 && mouseY > 105 && mouseY < 165) { //if clicked in this range, next two lines will be revealed
        stateStanzaNine = 1;
    } else if (state === 9 & mouseX > 40 && mouseX < 140 && mouseY > 150 && mouseY < 215) { //if clicked in this range, next two lines will be revealed
        stateStanzaNine = 2;
    } else if (state === 9 & mouseX > 268 && mouseX < 310 && mouseY > 223 && mouseY < 243) { //if clicked in this range, reveal all of stanza
        stateStanzaNine = 3;
    }
}

// for global state change
function keyPressed() {
    if (keyCode === RIGHT_ARROW) { //when right key is pressed, change stanzas
        state++;
    }
}

// for stanza one
function mousePressed() { //allow text to appear word by word in stanza one
    clickcountStanzaOne++;
}

Both of us are very interested in poetry and literature, so for this final project we wanted to take the opportunity to use animation and mouse interaction to augment the experience of reading a poem. We were inspired in part by digital children’s books and “choose-your-own-adventure”, except in this piece of work, we wanted to create simple interactions in a consistent aesthetic that would complement the words in poem.  We chose “Still I Rise” by Maya Angelou because we felt that her words were especially pertinent in today’s social and political climate.

This project was challenging to accomplish, and luckily we were able to work together well in order to tackle bigger problems. One of the most time-consuming struggles we encountered was the process of uploading, arranging, aligning, ordering and placing all of the type: we had to learn a couple new functions in order to manipulate the text in certain ways and treat some words as objects. We got sucked into the technicalities of typography, and spend more time than we should have finding and uploading the correct typeface. In the treatment of individual words, when placing words from a string in a for loop to appear one at a time, spacing became a tricky thing to deal with because our typeface wasn’t monospace. Another thing we struggled with was synthesizing all of our work. Because we would create sketches for each slide in a separate file, we had to establish a guide for how we labeled our variables so that they didn’t conflict. We also had to be careful about universal functions like mousePressed and keyPressed.

Inspiration credit:
p5.js official Wavemaker exampled
bounce function from p5.js official examples
Yasai openprocessing CircleShift Sketch

Even if we were working on different stanzas, we were able to talk problems out with each other and give advice. Although Alice focused on the opening slide, stanzas 1, 4, 8, and 9, and Jaclyn focused on stanzas 2, 3, 5, 6, and 7, the collaborative nature of our workflow allowed both of us to have a holistic influence to the project.
Overall, we are happy how this project turned out, and excited that we got to explore typography within p5.js.

Rachel Park – Final Project

Project Description & Instructions Below!!

finalproject

// Name: Rachel Park
// Andrew ID: rjpark
// 15-104 Section C

var i;
var currentkey = 'c';
var choreography = [];

var contemporary = [];
var groovy = [];
var footwork = [];
var isolation = [];
var pretty = [];
var swaggySassy = [];
var tutting = [];
var wavesWacking = [];

function preload() {
    // database of dance moves
    // loading the videos
    contemporary = ['C1.MOV', 'C2.MOV', 'C3.MOV', 'C4.MOV', 'C5.MOV',
        'C6.MOV', 'C7.MOV', 'C8.MOV', 'C9.MOV', 'C10.MOV', 'C11.MOV', 'C12.MOV',
        'C13.MOV', 'C14.MOV', 'C15.MOV', 'C16.MOV', 'C17.MOV', 'C18.MOV',
        'C19.MOV', 'C20.MOV', 'C21.MOV', 'C22.MOV', 'C23.MOV', 'C24.MOV',
        'C25.MOV', 'C26.MOV', 'C27.MOV', 'C28.MOV', 'C29.MOV', 'C30.MOV',
        'C31.MOV', 'C32.MOV', 'C33.MOV', 'C34.MOV', 'C35.MOV', 'C36.MOV',
        'C37.MOV', 'C38.MOV',];

    for (var j = 0; j < contemporary.length; j ++) {
        contemporary[j] = './Moves/C/' + contemporary[j];
    }

    groovy = ['G1.MOV', 'G2.MOV', 'G3.MOV', 'G4.MOV', 'G5.MOV', 'G6.MOV',
        'G7.MOV', 'G8.MOV', 'G9.MOV', 'G10.MOV', 'G11.MOV', 'G12.MOV',
        'G13.MOV', 'G14.MOV'];

    for (var j = 0; j < groovy.length; j ++) {
        groovy[j] = './Moves/G/' + groovy[j];
    }

    footwork = ['F1.MOV', 'F2.MOV', 'F3.MOV', 'F4.MOV', 'F5.MOV', 'F6.MOV',
        'F7.MOV', 'F8.MOV', 'F9.MOV', 'F10.MOV', 'F11.MOV', 'F12.MOV',
        'F13.MOV', 'F14.MOV', 'F15.MOV', 'F16.MOV', 'F17.MOV', 'F18.MOV',
        'F19.MOV', 'F20.MOV', 'F21.MOV'];

    for (var j = 0; j < footwork.length; j ++) {
        footwork[j] = './Moves/F/' + footwork[j];
    }

    isolation = ['I1.MOV', 'I2.MOV', 'I3.MOV','I4.MOV', 'I5.MOV', 'I6.MOV',
        'I7.MOV', 'I8.MOV', 'I9.MOV', 'I10.MOV', 'I11.MOV', 'I12.MOV',
        'I13.MOV', 'I14.MOV', 'I15.MOV', 'I16.MOV', 'I17.MOV', 'I18.MOV',
        'I19.MOV', 'I20.MOV', 'I21.MOV', 'I22.MOV', 'I23.MOV', 'I24.MOV',
        'I25.MOV', 'I26.MOV', 'I27.MOV', 'I28.MOV', 'I29.MOV', 'I30.MOV',
        'I31.MOV', 'I32.MOV', 'I33.MOV', 'I34.MOV', 'I35.MOV'];

    for (var j = 0; j < isolation.length; j ++) {
        isolation[j] = './Moves/I/' + isolation[j];
    }

    pretty = ['P1.MOV', 'P2.MOV', 'P3.MOV', 'P4.MOV', 'P5.MOV', 'P6.MOV',
        'P7.MOV', 'P8.MOV', 'P9.MOV', 'P10.MOV', 'P11.MOV', 'P12.MOV',
        'P13.MOV', 'P14.MOV', 'P15.MOV', 'P16.MOV', 'P17.MOV', 'P18.MOV',
        'P19.MOV', 'P20.MOV', 'P21.MOV', 'P22.MOV', 'P23.MOV', 'P24.MOV',
        'P25.MOV', 'P26.MOV', 'P27.MOV', 'P28.MOV', 'P29.MOV'];

    for (var j = 0; j < pretty.length; j ++) {
        pretty[j] = './Moves/P/' + pretty[j];
    }

    swaggySassy = ['S1.MOV', 'S2.MOV', 'S3.MOV', 'S4.MOV', 'S5.MOV', 'S6.MOV',
        'S7.MOV', 'S8.MOV', 'S9.MOV', 'S10.MOV', 'S11.MOV','S12.MOV', 'S13.MOV',
        'S14.MOV', 'S15.MOV', 'S16.MOV', 'S17.MOV', 'S18.MOV', 'S19.MOV',
        'S20.MOV', 'S21.MOV', 'S22.MOV', 'S23.MOV', 'S24.MOV', 'S25.MOV',
        'S26.MOV', 'S27.MOV', 'S28.MOV', 'S29.MOV', 'S30.MOV', 'S31.MOV',
        'S32.MOV'];

    for (var j = 0; j < swaggySassy.length; j ++) {
        swaggySassy[j] = './Moves/S/' + swaggySassy[j];
    }

    tutting = ['T1.MOV', 'T2.MOV', 'T3.MOV', 'T4.MOV', 'T5.MOV', 'T6.MOV',
        'T7.MOV', 'T8.MOV', 'T9.MOV', 'T10.MOV', 'T11.MOV', 'T12.MOV',
        'T13.MOV', 'T14.MOV', 'T15.MOV', 'T16.MOV', 'T17.MOV', 'T18.MOV',
        'T19.MOV', 'T20.MOV', 'T21.MOV', 'T22.MOV', 'T23.MOV', 'T24.MOV',
        'T25.MOV', 'T26.MOV', 'T27.MOV', 'T28.MOV', 'T29.MOV', 'T30.MOV',
        'T31.MOV', 'T32.MOV', 'T33.MOV', 'T34.MOV', 'T35.MOV', 'T36.MOV',
        'T37.MOV', 'T38.MOV'];

    for (var j = 0; j < tutting.length; j ++) {
        tutting[j] = './Moves/T/' + tutting[j];
    }

    wavesWacking = ['W1.MOV', 'W2.MOV', 'W3.MOV', 'W4.MOV', 'W5.MOV', 'W6.MOV',
        'W7.MOV', 'W8.MOV', 'W9.MOV', 'W10.MOV', 'W11.MOV', 'W12.MOV',
        'W13.MOV'];

    for (var j = 0; j < wavesWacking.length; j ++) {
        wavesWacking[j] = './Moves/W/' + wavesWacking[j];
    }
}

function setup() {
    createCanvas(700, 355);
    background(0);
    fill(255);
    noStroke();
    rect(600, 0, 100, 355);
}

function draw() {
    // title
    fill("pink");
    stroke(0);
    strokeWeight(3);
    textAlign(CENTER);
    textSize(30);
    text("Make Your Own Choreography!!", 300, 45);

    // box for reference
    fill(255);
    stroke("pink");
    strokeWeight(3);
    rectMode(CENTER);
    rect(85, 170, 120, 140);

    // text in reference box
    fill(0);
    noStroke();
    textAlign(CENTER);
    textSize(12);
    text("c = contemporary", 85, 117);
    text("f = footwork", 85, 133);
    text("g = groovy", 85, 149);
    text("i = isolation", 85, 165);
    text("p = pretty/feminine", 85, 181);
    text("s = swaggy/sassy", 85, 197);
    text("t = tutting", 85, 213);
    text("w = wavy/wacking", 85, 229);
    fill(255);
    stroke(0);
    strokeWeight(1);
    text("Letter Key Chart", 85, 90);

    // box for which letter key is pressed
    fill(255);
    stroke("pink");
    strokeWeight(3);
    rectMode(CENTER);
    rect(205, 127, 55, 55);

    // display the letter key that's pressed
    fill(0);
    noStroke();
    textAlign(CENTER);
    textSize(40);
    text(currentkey, 205, 140);
    fill(255);
    stroke(0);
    strokeWeight(1);
    textSize(12);
    text("Last Key Pressed", 205, 90);

    // box for play button
    fill(255);
    stroke("pink");
    strokeWeight(3);
    rectMode(CENTER);
    rect(205, 213, 55, 55);

    // display the play sign
    fill(0);
    noStroke();
    triangle(195, 200, 195, 230, 220, 215);
    fill(255);
    stroke(0);
    strokeWeight(1);
    textSize(12);
    text("Play Button", 205, 175);

    // box for instructions
    fill(255);
    stroke("pink");
    strokeWeight(3);
    rectMode(CENTER);
    rect(400, 170, 260, 140);

    // text in instructions box
    fill(0);
    noStroke();
    textAlign(LEFT);
    textSize(10);
    text("1. Look at the letter key chart & choose a letter to press", 
        280, 115);
    text("2. Press the letter key (displayed in the box to the right)", 
        280, 134);
    text("3. Keep pressing desired letter keys", 280, 153);
    text("4. When finished pressing letter keys, click the play", 280, 172);
    text("button to watch your choreography", 280, 191);
    text("5. Repeat steps 1-4 to keep adding to choreography", 280, 210);
    text("6. Refresh page to start over", 280, 229)
    fill(255);
    stroke(0);
    strokeWeight(1);
    textAlign(CENTER);
    textSize(12);
    text("Instructions", 400, 90);

    // side note & credit/shoutout to dancers
    fill(255);
    stroke(0);
    strokeWeight(1);
    textAlign(LEFT);
    textSize(10);
    text("** The objective of this project is to help you create a sequence" + 
        "of dance moves (choreography) that can be adjusted", 30, 280);
    text("and modified to match a song you choose when actually" +
        "choreographing.", 30, 295);
    text("** Also, shoutout to the featured dancers (by letter key chart);" +
        "Léann Bahi, Elizabeth Kuo, Jackie Jiang, Chris Shon,", 30, 320);
    text("Maggie Lyu, Emily Wu, Newton Xie, and Yuyan Sun.", 30, 335);
}

function getRandomInt(min, max) {
    min = Math.ceil(min);
    max = Math.floor(max);
    return Math.floor(Math.random() * (max - min)) + min;
}

function keyTyped() {
    document.getElementById("danceVideo").muted = true;

    // assigning pressed keys to a dance move video
    // playing that dance move video
    // adding each dance move video into a new array called choreography
    if (key === 'c') {
        currentkey = key;
        i = getRandomInt(0, contemporary.length);
        choreography.push(contemporary[i]);
        document.getElementById("video").src = str(contemporary[i]);
        document.getElementById("danceVideo").load();
        document.getElementById("danceVideo").play();
    }

    if (key === 'g') {
        currentkey = key;
        i = getRandomInt(0, groovy.length);
        choreography.push(groovy[i]);
        document.getElementById("video").src = str(groovy[i]);
        document.getElementById("danceVideo").load();
        document.getElementById("danceVideo").play();
    }

    if (key === 'f') {
        currentkey = key;
        i = getRandomInt(0, footwork.length);
        choreography.push(footwork[i]);
        document.getElementById("video").src = str(footwork[i]);
        document.getElementById("danceVideo").load();
        document.getElementById("danceVideo").play();
    }

    if (key === 'i') {
        currentkey = key;
        i = getRandomInt(0, isolation.length);
        choreography.push(isolation[i]);
        document.getElementById("video").src = str(isolation[i]);
        document.getElementById("danceVideo").load();
        document.getElementById("danceVideo").play();
    }
    if (key === 'p') {
        currentkey = key;
        i = getRandomInt(0, pretty.length);
        choreography.push(pretty[i]);
        document.getElementById("video").src = str(pretty[i]);
        document.getElementById("danceVideo").load();
        document.getElementById("danceVideo").play();
    }

    if (key === 's') {
        currentkey = key;
        i = getRandomInt(0, swaggySassy.length);
        choreography.push(swaggySassy[i]);
        document.getElementById("video").src = str(swaggySassy[i]);
        document.getElementById("danceVideo").load();
        document.getElementById("danceVideo").play();
    }

    if (key === 't') {
        currentkey = key;
        i = getRandomInt(0, tutting.length);
        choreography.push(tutting[i]);
        document.getElementById("video").src = str(tutting[i]);
        document.getElementById("danceVideo").load();
        document.getElementById("danceVideo").play();
    }

    if (key === 'w') {
        currentkey = key;
        i = getRandomInt(0, wavesWacking.length);
        choreography.push(wavesWacking[i]);
        document.getElementById("video").src = str(wavesWacking[i]);
        document.getElementById("danceVideo").load();
        document.getElementById("danceVideo").play();
    }
}

function mouseClicked() {
    // plays through all videos in choreography array
    var nextVideos = function(i) {
       document.getElementById('video').src = choreography[i];

       var videoElement = document.getElementById('danceVideo');
       videoElement.load();
       videoElement.play();

       // checks to see if there are videos left to play (i < array length)
       // checks to see if current video has ended to play next video in array
       if (i < choreography.length) {
            videoElement.onended = function() {
                nextVideos(i + 1);
            }
        }
    }

    // clicking the play button will play back entire choreography
    if (mouseX > 205 - (55 / 2) & mouseX < 205 + (55 / 2)) {
        if (mouseY > 213 - (55 / 2) && mouseY < 213 + (55 / 2)) {
            nextVideos(0);
        }
    }
}

Statement

As stated in my final project proposal, I wanted to create something that was going to be personally interesting to me. So, I decided to create a visual and interactive computer keyboard dance generator. The objective of my project was to allow the user to compile a bunch of dance moves that are generated based off of the letter key that they pressed. This would help the user create their own choreography that can be adjusted and modified to fit a song they choose when they actually choreograph.

In order to create this, I had to collect a database of dance moves. So, I recorded various dancers on campus dancing in a specific dance style, and, from this, I gathered videos of 220 unique dance moves. Once I collected my videos, I loaded them into code and assigned specific dancers/dance style to different arrays. Next, I essentially paired certain letter keys to arrays so that, when the user presses a letter key, a random dance video (dance move) from the paired array would play. In addition, as the user presses a letter key, the corresponding dance videos are added to a “choreography” array which contains the entire choreography that the user makes and can be played by pressing the play button at the end.

My greatest struggle with this project was getting all the videos in the “choreography” array to play in succession. I had to do a lot of outside research to figure out how to see if one video has ended in the array for another one to start. I used document.getElementById().src, load, play, and onended to make this happen.

Below is a screenshot of what the project looks like as well as instructions on how to install and run it.

Screenshots

** can’t show the interactiveness of the project through screenshots; click the link below and follow instructions to use it!

Instructions

  1. Press the link below (you will only get access with CMU Andrew email).
  2. Download the file (it is safe to download & it will take a while).
  3. Open the folder Final Project.
  4. Open the index.html file.
  5. Read the instructions on the web page to play!

Choreography Generator Download Link

Jenny Hu — Final Project

For my final project, I created a simple step sequencer with 4 sounds and background music! You can add sounds at different points by toggling the squares and circles (the squares indicate a note switched off, and a circle indicates a note switched on), and change the speed the music player loops through the sequencer on the bpm toggle.

I really enjoyed making this because it became about the curation of the sounds and music,  letting anyone generate a soothing atmosphere.

Jenny’s sketch

//Jenny Hu
//Section E
//jjh1@andrew.cmu.edu
//Final Project

//This final project is a simple step sequencer.
//Sounds are loaded into each row,
//as the music player passes each note (switched on), it plays the sound
//squares indicate switched off notes, and circles indicate the ones switched on.

var playing = false;
var notesArray = []; //all notes are pushed into this array

//sizing variables
var totalC = 15; 
var canvasWidth = window.innerWidth; //sizing of everything should overall be parametric to this width.
var margin = 0.02 * canvasWidth; //space between notes and everything else
var noteW = (canvasWidth - (totalC + 1) * margin)/ totalC; //calculated width of each square/circle
var canvasHeight = 5 * margin + 4 * noteW + (noteW*4); 

//variables key to moving and playing components
var playButtonW = margin ; //big play/pause button
var baseLineX = margin; 
var baseLineY = (canvasHeight / 5) * 3.5;
var movingPlayBar = 20; 
var movingPlayBarW = 10; 
var playX; //moving x tracked against the array's x's. 

//variables to make bpm changeable
var bpmEdit = 2;
var bpm;
var bpmX;
var bpmToggleX;
var bpmToggleLength;

var backgroundMusicToggle = false;
var interval;
var volume = 1;

function preload() {
    // load sound files 
    bird = loadSound("https://courses.ideate.cmu.edu/15-104/f2018/wp-content/uploads/2018/12/182507__swiftoid__bird-chirp.wav");
    bird.setVolume(volume);
    bell = loadSound("https://courses.ideate.cmu.edu/15-104/f2018/wp-content/uploads/2018/12/173000__keykrusher__bicycle-bell-2.wav");
    bell.setVolume(volume / 3 * 2);
    cello = loadSound("https://courses.ideate.cmu.edu/15-104/f2018/wp-content/uploads/2018/12/398494__anthousai__wind-chimes-single-01.wav");
    cello.setVolume(volume);
    shaker = loadSound("https://courses.ideate.cmu.edu/15-104/f2018/wp-content/uploads/2018/12/368607__samsterbirdies__shake.wav");
    shaker.setVolume(volume);
    backgroundMusic = loadSound("https://courses.ideate.cmu.edu/15-104/f2018/wp-content/uploads/2018/12/203099__lemoncreme__groove-music.wav");
    backgroundMusic.setVolume(volume);
}

function setup(){
	createCanvas(canvasWidth, canvasHeight);
	frameRate(1000);
	angleMode(DEGREES);

    bpmToggleLength = width / 8 * 5; 
	bpmX = bpmToggleLength + margin;
	//setting up rows with different sounds
    for (var c = 0; c < totalC; c++){
    	for (var r = 0; r < 4; r++){
    		var x = c * (noteW + margin) + margin;
    		var y = r * (noteW + margin) + margin; 
    		if ( r == 0){
    			snd = bird;
    		} else if (r == 1){
    			snd = bell;
    		} else if (r == 2){
    			snd = cello; 
    		} else {
    			snd = shaker;
    		}
    		var n = Note(x , y, snd, noteW);
            notesArray.push(n);
    	}
    }
}



function draw(){
	background(250, 230, 10);
	var wiggleRoom = 2;

	//intro text
	stroke(0, 0, 250);
	strokeWeight(1);
	fill(0, 0, 250);
	textSize(margin);
	textFont('Courier');
	text('press play to begin!', width / 2 - bpmToggleLength / 1.75, canvasHeight / 8 * 7); 

	//static line
	strokeWeight(5);
	line( baseLineX, baseLineY, canvasWidth - baseLineX, baseLineY);//playbar baseline

	//for loop rendering the array into notes
    for (var i = 0; i < notesArray.length; i++){
    	notesArray[i].render();

    	//play music when the play x and array of on notes collide
    	if (playX >= notesArray[i].x - wiggleRoom 
    		& playX <= notesArray[i].x + wiggleRoom 
    		&& notesArray[i].on == true){
    		notesArray[i].snd.play();
    	}
    }

	bpmToggle();
	playBackground();
	playButton();
    movePlayStream();
}

//function to move the bpm visual ui
function bpmToggle(){
	//shadow
	noStroke();
	fill(250, 250, 250, 150);
	rect( bpmToggleLength + margin, baseLineY + (margin * 2.5), width/5, noteW/5, 80); 
	//bpm text
	stroke(0, 0, 250, 250);
	fill(0, 0, 250);
	strokeWeight(1);
	text('bpm', bpmToggleLength + margin, canvasHeight / 8 * 7 + margin);
	//toggle
	fill(0, 0, 250);
	ellipse(bpmX, baseLineY + (margin * 2) + noteW / 3, noteW / 3, noteW / 3); 
}


//function to play background music
function playBackground(){
	if (backgroundMusicToggle == true){ //counter will be 1, or 2 (on rare occasion), immediate at play
		interval = 1250;
		if (counter  > 0 & counter < 3){
			backgroundMusic.play();
			playing = true;
		} else if ( counter % interval > 0 & counter % interval <= 2){ //interval is based on the timing of the background song
			playing = false;
			counter = 0; //reset counter if you've paused the music
		}
	 } 
}

//play/pause functionality + visuals
//playing is toggled in mousePressed
function playButton(){
	fill(0, 0, 250);

	if (playing == true) { 
		//pause button
		rect(width/2 - playButtonW, baseLineY + (margin * 2) , 
			playButtonW, playButtonW * 3);
		rect(width/2 + playButtonW, baseLineY + (margin * 2), 
			playButtonW, playButtonW * 3);
		//mapping of the bpm toggle to the speed of  playX
		bpmEdit = map(bpmX, 
				bpmToggleLength + noteW / 2, bpmToggleLength - noteW / 2 + width/5, 
				2, 4);
		bpm = bpmEdit; // the set BPM by the user
		backgroundMusicToggle = ! backgroundMusicToggle; //turning on the background music
		counter += 1;

	} else {
		//play button
		triangle ( width/2 - playButtonW, baseLineY + (margin * 2),
				  width/2 - playButtonW, baseLineY + (margin * 2) + noteW * .75 * 2,
				  width/2 - playButtonW + noteW * .75 * 2, baseLineY + (margin * 2) + noteW * .75 )
		bpm = 0; //stop the player if we've paused the switch
		counter = 0;
		backgroundMusic.stop();

	}
}

//draws the animated line
function movePlayStream(){
	playX = baseLineX + movingPlayBar - 20;
	stroke(0, 0, 250);
	fill(250);
	strokeWeight(4);
	//loops the line if the play button moves off the line
	if (playX > canvasWidth - baseLineX) {	
		movingPlayBar = baseLineX;
	} else {
		//the visual parts
		rect(playX, margin / 2, movingPlayBarW, canvasHeight / 5 * 3.5);
		ellipse( playX + movingPlayBarW / 2 , baseLineY, movingPlayBarW*2, movingPlayBarW*2);
	}
	//add whatever the bpm has been toggled to be
    movingPlayBar += bpm;
}



function mousePressed(){
	//turning on and off the individual notes by checking your mouse position
    for (var i = 0; i < notesArray.length; i++){
		if (mouseX > notesArray[i].x 
			& mouseX < notesArray[i].x + noteW 
			&& mouseY > notesArray[i].y
			&& mouseY < notesArray[i].y + noteW){
			var currentToggle = !notesArray[i].on;
			notesArray[i].on = currentToggle;
		}    	
    }
    //switch play/pause mode by clicking on the play/pause button
    if (mouseX > width / 2 - playButtonW 
    	& mouseX < width / 2 + margin + playButtonW 
    	&& mouseY > baseLineY + (margin * 2)
    	&& mouseY < baseLineY + (margin * 2) + playButtonW * 3){
    	playing = ! playing;
    }
}


function mouseDragged(){
	//dragging the bpm toggle
	if (mouseX > bpmToggleLength + margin
    	& mouseX < bpmToggleLength + width/5 + margin
    	&& mouseY > baseLineY + (margin * 2.5)
    	&& mouseY < baseLineY + (margin * 2.5) + noteW){
		bpmX = mouseX;
    }
}


//make the note real
function render(){
	fill(250);
	stroke(0, 0, 250);
	strokeWeight(5);
	//rendering cirlces if the note is on
	if (this.on){
		fill(250, 130, 180);
		noStroke();
		ellipse(this.x + noteW/2, this.y + noteW/2, this.w, this.w);
	} else { 
		//rendering squares if the notes is off
		rect(this.x, this.y, noteW, noteW); 
	}

	if(this.snd.isPlaying() & playX < this.x + noteW*1.5 && playX > this.x){
		var t = frameCount;
		this.w = noteW * sin(t*5);
	}else{
		this.w = noteW;
	}
}

//my note object maker function
function Note(x, y, snd, wide){
	var objNote = { //object literal format
		x : x,
		y : y,
		w: wide,
		snd : snd,
		on : false,
		playing: false
	}
	objNote.render = render;
	return objNote;
}