Final Project

Virus Run

For my final project, I have created a side-scrolling game in which the player takes on the role of a coronavirus particle. As obstacles such as masks and hand sanitizer fly from right to left, the player must use the space bar to make the virus “jump” and avoid these obstacles. The longer the user holds down the key, the higher the virus floats, until it reaches the max height. If any of the obstacles are touched, the game stops. The score is then calculated based on the frame count. I was inspired by the dinosaur game which people can play when trying to use google with no internet connection, and if I had more time, I would have liked to make it so that the longer the game goes on, the more obstacles there are and the faster they move.

Some Screenshots of what the full canvas looks like:


sketch
var imgV; // image of virus
var imgM; // image of mask obstacle
var imgHS; // image of hand sanitizer

var imgStart; // image for starting screen
var imgGO; // image for game over


var mask = []; // array for masks on ground level
var mx = 800 // x coord of mask

var handSan = []; // array for hand sanitizer flying overhead
var hsx = 800 // x coord of hand sanitizer

var virusX = 100; // permanent x position of virus
var virusY = 270; // starting y position of virus
var virusR = 70; // radius of virus
var virusDy = 0; // change in height of virus when jumping

var score = 0; //counts score based on frames

var start = true; // checks to see if starting page is showing

var hills = []; // making moving hills as a background element
var noiseParam = 0;
var noiseStep = 0.02;

function preload(){
    imgV = loadImage("https://i.imgur.com/k04oKtW.png");
    imgM = loadImage("https://i.imgur.com/v2CRQLt.png");
    imgHS = loadImage("https://i.imgur.com/iFAELeQ.png");
    imgGO = loadImage("https://i.imgur.com/ORHbmPV.png");
    imgStart = loadImage("https://i.imgur.com/OUL56Za.png");

}



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

    //making hills
    for(var i = 0; i <= width/5; i++){
        var n = noise(noiseParam);
        hills[i];
        var value = map(n, 0, 1, 0, height/2);
        hills.push(value);
        noiseParam += 0.5*noiseStep;
    }
}

function draw(){
    
    if (start == true){
    	startingPage();

    } else { 

        background(8, 6, 51); // dark blue background
        drawHills();
        fill(55, 0, 104); // purple floor
        rect(0, 370, 800, 30);
        image(imgV, virusX, virusY, 107, 100); // image of virus
    
        if(keyIsDown(32)){ 
            virusY -= 10;
            // while the space bar is down, the virus moves upward
        } else if (virusY < 270){ 
            virusY +=10;
            // when the space bar is let go while the virus is in the air, 
            //the virus moves down
        } else { virusY = 270; } 
            // otherwise, the virus stays on the ground
        if (virusY < 40)
        { virusY += 10}

        createNewMask();
        displayMask();

        createNewHandSan();
        displayHandSan();

        checkIfGameOver();
    
        score += 1; 

        //display score count in the top right corner during the game
        textSize(15);
        fill(190, 215, 62);
        text(score, 745, 40);
        
    }
    
}

function startingPage(){ // starting page with instructions
	push();
	fill(8, 6, 51);
	rect(-1, -1, 801, 801);
	fill(190, 215, 62);
	textSize(25);
	text('Press any key to begin >', 487, 365);
	textSize(15);
	text('Use the space bar to avoid obstacles!', 490, 230);
	pop();

	image(imgStart, 40, 80, 700, 100);
	image(imgM, 540, 250, 60, 58);
	image(imgHS, 620, 247, 62, 70);
	image(imgV, virusX, virusY, 107, 100);
	

}

function keyPressed(){ 
	if(start == true){ start = false; } // game begins
	
}

//drawing hills (background element)
function drawHills(){
	push();
    translate(0, 130)
    hills.shift();
    var n = noise(noiseParam);
    var value = map(n, 0, 1, 0, height/2);
    hills.push(value);
    // draws shape for sand
    beginShape();
    vertex(0, height);
    for(var i = 0; i <= width/5; i++){
        //filling the hill color
        fill(255, 255, 255, 10);
        noStroke();
        //vertex function to fill the hills
        vertex((i * 5), hills[i]); 
        vertex((i + 1) * 5, hills[i + 1]);   
    }
    vertex(width, height);
    endShape(CLOSE);
    pop();
}


function checkIfGameOver (){

	for (i = 0;i < mask.length;i++)
    {
        if ((dist(mask[i].x, 400,  virusX, 400) <= virusR) 
            // tests if the mask comes within a certain distance of the virus
             & virusY == 270){

            gameOver(); // the screen goes darker
            noLoop(); // the game stops
        }
    }

	for (i = 0;i < handSan.length;i++){
        if ((dist(handSan[i].x, handSan[i].y,  virusX, virusY) <= virusR)){ 
            //tests if the hand sanitizer comes within a certain distance of the virus


            gameOver(); // the screen goes darker
            noLoop(); // the game stops
        }
    }
}


// BEGIN CODE FOR MASK OBSTACLES



function displayMask(){ // update mask positions and display them
    for(var i = 0; i < mask.length; i++){
        mask[i].move();
        mask[i].draw();
    }
}

function createNewMask(){ 
// makes new masks with some random probability
    if(random(0, 1) < 0.008){
        mask.push(makeMask(800));
    }
}

function moveMask(){
    this.x -= 10;
}

function drawMask(){
    mask.push();
    image(imgM, this.x, this.y, 60, 60); 
}

// function to make mask obstacle object
function makeMask(){
    var m = {x: mx, 
             y: 310,
             move: moveMask,
             draw: drawMask
        }
    return m;
}

// BEGIN CODE FOR HAND SANITIZER OBSTACLES

function displayHandSan(){ // update hand sanitizer positions and display them
    for(var i = 0; i < handSan.length; i++){
        handSan[i].move();
        handSan[i].draw();
    }
}

function createNewHandSan(){ 
// makes new masks with some random probability
    if(random(0, 1) < 0.005){
        handSan.push(makeHandSan(800));
    }
}

function moveHandSan(){
    this.x -= 10;
}

function drawHandSan(){
    handSan.push();
    image(imgHS, this.x, this.y, 80, 90); 
}

// function to make mask obstacle object
function makeHandSan(){
    var h = {x: hsx, 
             y: random(30, 100),
             move: moveHandSan,
             draw: drawHandSan
        }
    return h;
}


function gameOver(){
// screen displayed when the virus hits an obstacle
    push();
    fill(0, 0, 0, 80);
    rect(0, 0, 800, 400);
    pop();

    image(imgGO, 50, 100, 700, 100);    
   
    push();
    fill(190, 215, 62);
    noStroke();
    textSize(20);
    text('SCORE:' + ' ' + score, 340, 250);
    textSize(15);
    text('Refresh to play again!', 340, 280)
    pop();
}


Looking Outwards 11

The Pack
Emily Gobeille

Emily Gobeille is an accomplished artist and designer interested in the way that children learn and play. A co-founder of Design I/O, she works to create immersive, interactive installations and experiences for museums, galleries, and more. She also plays a significant role in developing video games like The Pack, a strategy and logic-based game that aims to give players experience with computational thinking concepts. Within the game, players must explore  a fantasy world, befriending creatures that act as algorithms to change the world around them. The game’s visual design makes it accessible to younger and more diverse audiences, helping a wider range of players grasp complex concepts. Gobeille’s intrigue with children’s education is reflected in her own child-like creativity that shines through in the vibrance of her work. 

Project 11

For my generative landscape, I chose to make a desert with different types of cacti whose sizes and colors are randomly generated. For the sand and hills in the back, I referenced the lab from week 7. While the sand keeps moving, the hills in the back are still but change every time the page is refreshed.

zimmy desert
var cacti = [];
var canyons = [];
var sand = [];
var ball = [];
var noiseParam = 0;
var noiseStep = 0.02;

function setup() {
    createCanvas(640, 240); 
    background(0);

    
    /*// create an initial collection of buildings
    for (var i = 0; i < 10; i++){
        var rx = random(width);
        buildings[i] = makeBuilding(rx);
    }*/
    frameRate(20);
    //canyon values
    for(var i = 0; i <= width/5; i++){
        var n = noise(noiseParam);
        canyons[i];
        var value = map(n, 0, 1, 0, height);
        canyons.push(value);
        noiseParam += noiseStep;
    }
    //sand values
    for(var i = 0; i <= width/5; i++){
        var n = noise(noiseParam);
        sand[i];
        var value = map(n, 0, 1, 0, height/2);
        sand.push(value);
        noiseParam += 0.5*noiseStep;
    }

}


function draw() {
    //sunset gradient
    var gradRed = color(190, 60, 38); // darker red color
    var gradYellow = color(250, 185, 21); // yellow
    for (var i = 0; i < height; i++){
        var gradient = map (i, 0, (height/3)*1.5, 0, 1);
        var bgColor = lerpColor(gradRed, gradYellow, gradient);
        stroke(bgColor);
        line(0, i, width, i);
    } 
    // draw a setting sun
    push();
    noStroke();
    fill(255, 226, 161);
    circle(500, 110, 180);
    pop();
    
    drawCanyons();
    drawSand();

    // taller cacti
    updateAndDisplayCacti();
    removeCactiThatHaveSlippedOutOfView();
    addNewCactiWithSomeRandomProbability(); 
    

    updateAndDisplayBalls();
    removeBallsThatHaveSlippedOutOfView();
    addNewBallsWithSomeRandomProbability(); 




}

//draws background canyons (still)
function drawCanyons(){
    // canyon values
    var n = noise(noiseParam);
    var value = map(n, 0, 1, 0, height);
    noiseParam += noiseStep;
    // draws shape for canyons
    beginShape();
    vertex(0, height);
    for(var i = 0; i <= width/5; i++){
        //filling the canyons with translucent brown
        fill(178, 108, 55, 180);
        noStroke();
        //vertex function to fill the canyon
        vertex((i * 5), canyons[i]); 
        vertex((i + 1) * 5, canyons[i + 1]);   
    }
    vertex(width, height);
    endShape(CLOSE);
}

// draws sand (moving)
function drawSand(){
    push();
    translate(0, 130)
    sand.shift();
    var n = noise(noiseParam);
    var value = map(n, 0, 1, 0, height/2);
    sand.push(value);
    // draws shape for sand
    beginShape();
    vertex(0, height);
    for(var i = 0; i <= width/5; i++){
        //filling the sand color
        fill(237, 197, 154);
        noStroke();
        //vertex function to fill the sand
        vertex((i * 5), sand[i]); 
        vertex((i + 1) * 5, sand[i + 1]);   
    }
    vertex(width, height);
    endShape(CLOSE);
    pop();
}



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


function removeCactiThatHaveSlippedOutOfView(){
    var cactiToKeep = [];
    for (var i = 0; i < cacti.length; i++){
        if (cacti[i].x + cacti[i].breadth > 0) {
            cactiToKeep.push(cacti[i]);
        }
    }
    cacti = cactiToKeep; // remember the surviving buildings
}


function addNewCactiWithSomeRandomProbability() {
    // With a very tiny probability, add a new building to the end.
    var newCactusLikelihood = 0.02; 
    if (random(0,1) < newCactusLikelihood) {
        cacti.push(makeCactus(width));
    }
}


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

//draw the cactus
function cactusDisplay() {
    cacti.push();
    strokeWeight(25);
    stroke(this.color);

    //main stalk
    var y = 220;
    line(this.x, this.cBottom, this.x, this.cBottom-this.cHeight)
    strokeWeight(17);
    stroke(204, 209, 135, 60);
    line(this.x, this.cBottom, this.x, this.cBottom-this.cHeight)

    // two stalks on side
    strokeWeight(13);
    stroke(this.color);
    line(this.x-20, this.cBottom-this.s1Bottom, this.x-20, this.cBottom-this.s1Height); 
    // left stalk has a random height
    line(this.x+20, this.cBottom-this.s2Bottom, this.x+20, this.cBottom-this.s2Height); 
    // right stalk has a random height
}



// makes taller cacti
function makeCactus(birthLocationX) {
    var ccts = {x: birthLocationX,
                breadth: 50,
                speed: -4.5,
                cHeight: random(30, 60), // height of cactus
                cBottom: random(200, 225), // bottom of cactus
                s1Height: random(20, 60), // top of the left stalk
                s1Bottom: random(5, 20), // bottom of left stalk
                s2Height: random(20, 60), // top of right stalk
                s2Bottom: random(5, 20), // bottom of right stalk
                
                color: color(random(40, 100), random(80, 200), 72), // varies shades of green
                move: cactusMove,
                display: cactusDisplay}
    return ccts;
}

function addNewBallsWithSomeRandomProbability() {
    // With a very tiny probability, add a new building to the end.
    var newBallLikelihood = 0.02; 
    if (random(0,1) < newBallLikelihood) {
        ball.push(makeBall(width));
    }
}

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

function removeBallsThatHaveSlippedOutOfView(){
    var ballsToKeep = [];
    for (var i = 0; i < ball.length; i++){
        if (ball[i].x + ball[i].breadth > 0) {
            ballsToKeep.push(ball[i]);
        }
    }
    ball = ballsToKeep; // remember the surviving buildings
}

function addNewBallWithSomeRandomProbability() {
    // With a very tiny probability, add a new ball cactus to the end.
    var newBallLikelihood = 0.02; 
    if (random(0,1) < newBallLikelihood) {
        ball.push(makeBall(width));
    }
}

// method to update position of ball shaped cactus every frame
function ballMove() {
    this.x += this.speed;
}


// displays ball-shaped cacti
function ballDisplay(){
    push();
    noStroke();
    fill(this.color);
    ellipse(this.x, this.ey, this.ew, this.eh); // main ball cactus
    fill(204, 209, 135, 60)
    ellipse(this.x, this.ey, this.ew-5, this.eh-5); // highlight
    fill(this.color);
    ellipse(this.x, this.ey, this.ew-10, this.eh-10);
    fill(251, 203, 188);
    stroke(this.color);
    strokeWeight(1);
    ellipse(this.x, this.ey-(this.eh/2), 8, 5) // lil flower guy on top
    pop();
}

// makes ball-shaped cacti
function makeBall(birthLocationX) {
    var b = {x: birthLocationX,
                breadth: 50,
                speed: -4.5,
                eh: random(20, 40), // height of ellipse
                ey: random(200, 225), // y coord of ellipse
                ew: random(20, 40), // width of ellipse
                color: color(random(50, 150), 100, random(100, 200)), // varies shades of blue
                move: ballMove,
                display: ballDisplay}
    return b;
}






LO 10

EMMY
Composer: David Cope

“EMMY” is a program developed by David Cope, a classical composer with a deep interest in the role which computers and AI can play in music. His experiments in music intelligence allowed him to create EMMY, a program which can be fed examples of work from specific musicians and composers and in turn produce new pieces based on the characteristics of the music it studies. I find it fascinating that EMMY is able to break down and learn aspects of what makes a specific composer’s work unique and recreate it in a way that is not necessarily copying, but familiar and new. Moreover, Cope theorized that “what made a composer properly understandable, properly “affecting”, was in part the fact of mortality.” Interestingly, this led him to unplug EMMY in 2004, after it had produced over 11,000 pieces.

A Bach-Style Chorale written by EMMY

Project 10 – Sonic Story + Media Files

For my sonic story, I made an animation of a series of animals chasing each other. I first started with a gif of a dog running, then split it into several frames to animate. I then decided to make it get chased by a bee (also a gif), then have the dog chase a cat who chases a mouse. The full frame is too long to display here, but this is a screenshot of what it looks like when all four characters are in frame:

sonic story
// STORYLINE: A bee chasing a dog chasing a cat chasing a mouse.



var dogWalk = [];   // an array to store the images of a dog walking
var beeFly = []; // array to store images of bee flying
var catRun = []; // images of cat running
var mouse;
var mx = 920; // x position of mouse
var fence;
var barking;
var buzz;
var meow;
var squeak;




function preload(){

    // images of dog walking
    var dogs = [];
    dogs[0] = "https://i.imgur.com/Obg7kQd.gif";
    dogs[1] = "https://i.imgur.com/vUkgpet.gif";
    dogs[2] = "https://i.imgur.com/jvjCknz.gif";
    dogs[3] = "https://i.imgur.com/yFxMHG1.gif";
    dogs[4] = "https://i.imgur.com/oPxOfcq.gif";
    dogs[5] = "https://i.imgur.com/i0WRXiO.gif";
    dogs[6] = "https://i.imgur.com/338YDhl.gif";
    dogs[7] = "https://i.imgur.com/W62WgdJ.gif";
    dogs[8] = "https://i.imgur.com/2GhHX5W.gif";
    dogs[9] = "https://i.imgur.com/VgfCha4.gif";
    dogs[10] = "https://i.imgur.com/MbUowkT.gif";
    dogs[11] = "https://i.imgur.com/CnQCi0T.gif";
    dogs[12] = "https://i.imgur.com/rWgGUWm.gif";
    dogs[13] = "https://i.imgur.com/WPaT5V0.gif";
    dogs[14] = "https://i.imgur.com/y8qx8WE.gif";
    dogs[15] = "https://i.imgur.com/Vp1xVPc.gif";

    for (var i = 0; i < dogs.length; i++) {
        dogWalk[i] = loadImage(dogs[i]);
    }

    //images of bee flying
    var bees = [];
    bees[0] = "https://i.imgur.com/4850hmR.gif";
    bees[1] = "https://i.imgur.com/0FMGyos.gif";
    bees[2] = "https://i.imgur.com/7CozqZ5.gif";
    bees[3] = "https://i.imgur.com/J6e0HBK.gif";
    bees[4] = "https://i.imgur.com/uexlFJE.gif";
    bees[5] = "https://i.imgur.com/intd8Rx.gif";
    bees[6] = "https://i.imgur.com/l3ZVHzT.gif";
    bees[7] = "https://i.imgur.com/NNG3lnb.gif";
    bees[8] = "https://i.imgur.com/wYl8pHt.gif";
    bees[9] = "https://i.imgur.com/CM53Kch.gif";
    bees[10] = "https://i.imgur.com/Tt90vYh.gif";
    bees[11] = "https://i.imgur.com/MTQRrrG.gif";
    bees[12] = "https://i.imgur.com/8S7d588.gif";
    bees[13] = "https://i.imgur.com/tO9HTc5.gif";
    bees[14] = "https://i.imgur.com/KtbttF1.gif";
    

    for (var i = 0; i < bees.length; i++) {
        beeFly[i] = loadImage(bees[i]);
    }

    //images of the cat
    var cats = [];
    cats[0] = "https://i.imgur.com/ZWzbhxI.gif";
    cats[1] = "https://i.imgur.com/GaD7QU7.gif";
    cats[2] = "https://i.imgur.com/i6pEZq8.gif";
    cats[3] = "https://i.imgur.com/ljdWpB9.gif";
    cats[4] = "https://i.imgur.com/3dpfves.gif";
    cats[5] = "https://i.imgur.com/r0rgZRT.gif";
    cats[6] = "https://i.imgur.com/810gnOd.gif";
    cats[7] = "https://i.imgur.com/36qZ7mv.gif";
    cats[8] = "https://i.imgur.com/DPO7GIs.gif";
    cats[9] = "https://i.imgur.com/r9pxkAW.gif";
    cats[10] = "https://i.imgur.com/BNjV3y7.gif";
    cats[11] = "https://i.imgur.com/GOJmcoi.gif";

        for (var i = 0; i < cats.length; i++) {
        catRun[i] = loadImage(cats[i]);
    }
    
    mouse = loadImage("https://i.imgur.com/293UbtW.png");

    fence = loadImage ("https://i.imgur.com/N9jB1Hh.png");

    barking = loadSound ("https://courses.ideate.cmu.edu/15-104/f2020/wp-content/uploads/2020/11/barking.wav");

    buzz = loadSound("https://courses.ideate.cmu.edu/15-104/f2020/wp-content/uploads/2020/11/buzz.wav");

    meow = loadSound("https://courses.ideate.cmu.edu/15-104/f2020/wp-content/uploads/2020/11/meow-2.wav");

    squeak = loadSound("https://courses.ideate.cmu.edu/15-104/f2020/wp-content/uploads/2020/11/squeak.wav");
}
    
function soundSetup(){
    //barking.setVolume(0.75);
    buzz.setVolume(15);
    meow.setVolume(0.4);
    //squeak.setVolume(1);
}

//updates walking dog for next frame
function stepDog(){
    this.imageNumber++;

    //cycles through the 16 images
    if (this.imageNumber>15){
        this.imageNumber=0;
    }
}

//updates flying bee for next frame
function stepBee(){
    this.imageNumber++;

    // cycles through 15 images
    if (this.imageNumber>14){
        this.imageNumber = 0;
    }  
}

//updates cat for next frame
function stepCat(){
    this.imageNumber++;

    // cycles through 12 images
    if (this.imageNumber>11){
        this.imageNumber = 0;
    }  
}


//draws walking dog
function drawDog(){ image(dogWalk[this.imageNumber], this.x, this.y, 200, 110); }

// draws flying bee
function drawBee() { 
    push();
    scale(-1, 1);
    image(beeFly[this.imageNumber], this.x, this.y, 50, 50)
    pop();
}

// draws cat
function drawCat() { 
    push();
    scale(-1, 1);
    image(catRun[this.imageNumber], this.x, this.y, 80, 80)
    pop();
}


//constructor that creates and returns an object representing a dog
function makeDog(cx, cy){
    c = {x: cx, y: cy,
        dx: 8, 
        imageNumber:0,
        stepFunction: stepDog,
        drawFunction: drawDog}
    return c;
}

//constructor that creates and returns an object for a bee
function makeBee(bx, by){
    b = {x: bx, y: by,
        dx: 7,
        imageNumber: 0,
        stepFunction: stepBee,
        drawFunction: drawBee}
    return b;
}

//constructor that creates and returns an object for a cat
function makeCat(ax, ay){
    a = {x: ax, y: ay,
        dx: 9,
        imageNumber: 0,
        stepFunction: stepCat,
        drawFunction: drawCat}
    return a;
}


//empty array for dog
var dog=[];

//empty array for bee
var bee = [];

//empty array for cat
var cat = [];


function setup(){
    createCanvas(800, 100);
    imageMode(CENTER);

    for (var i = 0; i < 1; i++) {
        // make a dog
        var c = makeDog(1100, i+60);
        // push the dog onto dog array
        dog.push(c);

        var b = makeBee(-1200, i+50);
        bee.push(b);

        var a = makeCat(-1000, i+70);
        cat.push(a);
    }
    useSound();
    frameRate(8);
}

function draw(){
    background(201, 74, 88);

    //barking sound
    if (frameCount == 65 || frameCount == 75) {
        barking.play(); 
    } 

    // buzzing sound
    if (frameCount == 80 || frameCount == 90){
        buzz.play();
    }

    // meow
    if (frameCount == 40 || frameCount == 50){
        meow.play();
    }

    //squeak
    if (frameCount == 20 || frameCount == 30){
        squeak.play();
    }
    

    if (0 < frameCount < 100){
        for (var i = 0; i < 1; i++) { // for the dog
            var c = dog[i];
            c.stepFunction();
            c.drawFunction();
            //moves dog to the left
            dog[i].x-=dog[i].dx;
        }
    }
    

    if (0 < frameCount < 100){
        for (var i = 0; i < 1; i++) { // for the bee
            var b = bee[i];
            b.stepFunction();
            b.drawFunction();
            //moves bee to the left
            bee[i].x+=bee[i].dx;
        }
    }

    if (0 < frameCount < 100){
        for (var i = 0; i < 1; i++) { // for the cat
            var a = cat[i];
            a.stepFunction();
            a.drawFunction();
            //moves cat to the left
            cat[i].x += cat[i].dx;
        }
    }

    image(mouse, mx, 75, 45, 30);
    image(fence, 700, 100, 200, 70);

    mx -= 10

}

function mousePressed (){
    frameCount = 0;
}

LO 08

Stephanie Dinkins

Stephanie Dinkins is an interdisciplinary artist whose work focuses on the intersection of artificial intelligence and race, gender, and age, and how technology shapes history. She teaches at Stony Brook University, and was named an “AI Influencer” in the New York Times. Her work consists primarily of interactive installations that use AI algorithms to communicate issues of social justice and her own familial experiences while trying to make AI technology more accessible to underfunded communities. Specifically, her project “Not the Only One” centers around her multigenerational family history, helping to tell the story of her ancestors as a unique, deep-learning entity. I admire the way in which her work humanizes the world of AI, demonstrating how it can intersect with deeply personal topics. She also emphasizes the importance of using programming in a way that brings in audiences who might not otherwise be immersed in or have access to this technological setting, as well as people who might not recognize how it can relate to themselves.

Dinkins’ Eyeo 2019 Lecture

Project 07

curvy curves
var x;
var y;
var spread; // how far each bean is from one another	
var a; // scales the size of individual beans




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

function draw() {
    background(0, 30, 50);	
	translate(width/2, height/2);
	push();
	for(var i = 0; i <= 24; i ++){
		beanWO();
		rotate(radians(15));
	} 
	pop();
    // arrangement of 24 beanWO functions 

	push();
    for(var j = 0; j <= 12; j++){ 
    	beanF();
    	rotate(radians(30));
    }
    pop();
    // arrangement of 12 beanF functions

    push();
    for(var k = 0; k <= 36; k++){
        beanScrib(); 
        rotate(radians(mouseX));	
    }
    pop();
    // arrangement of 36 scribble-like shapes that rotate based on the X position of the mouse

    push();
    for(var m = 0; m <= 3; m ++){
    	beanVar();
    	rotate(radians(120));
    }
    pop();
    // draws function beanVar in the middle of the canvas
} 



function beanWO(){ 
// draws beans with white outlines that move toward and away from the origin based on mouseX
    push();
    a = 100
    spread = mouseX/5;
	stroke(255);
	noFill();
	beginShape();
	for(var theta = 0; theta <= TWO_PI; theta += radians(1)){
        x = a * cos(theta) * (pow(sin(theta), 3) + pow(cos(theta), 3)) + spread; // 
        y = a * sin(theta) * (pow(sin(theta), 3) + pow(cos(theta), 3)) + spread; // y parameter of bean curve
        vertex(x, y)
	}
	endShape();
	pop();
}

function beanF(){ 
// draws translucent beans whose colors change with mouseY
	push();
	a = 200;
	spread = -mouseX/5; 
	var r = map(mouseY, 0, 480, 0, 255);
	noStroke();
	fill(r, 255, 231, 40);
	beginShape();
	for(var theta = 0; theta <= TWO_PI; theta += radians(1)){
        x = a * cos(theta) * (pow(sin(theta), 3) + pow(cos(theta), 3)) + spread; // x paremeter of bean curve
        y = a * sin(theta) * (pow(sin(theta), 3) + pow(cos(theta), 3)) + spread; // y parameter of bean curve
        vertex(x, y)
	}
	endShape();
	pop();	
}

function beanScrib(){ 
// draws a variation of the bean function that looks like a scribble
	push();
	a = mouseY;
	spread = mouseY/12
	noFill();
	stroke(214, 197, 255, 40);
	strokeWeight(3);
	beginShape();
	for(var theta = 0; theta <= radians(180); theta += radians(1)){
        x = a * cos(theta * .5) * (pow(sin(theta * .6), 3) + pow(cos(theta), 3)) + spread; 
        y = a * sin(theta * .5) * (pow(sin(theta * .6), 3) + pow(cos(theta), 3)) + spread; 
        vertex(x, y)
	}
	endShape();
	pop();	
}

function beanVar(){ 
// draws a variation of the bean function that changes with mouseY
	push();
	a = 50
	var b = map(mouseY, 0, height, 0, 5) // modifies an angle in the function with mouseY
	noFill();
	stroke(146, 255, 205);
	strokeWeight(5);
	beginShape();
	for(var theta = 0; theta <= radians(180); theta += radians(1)){
        x = a * cos(theta) * (pow(sin(theta * b), 3) + pow(cos(theta), 3));  
        y = a * sin(theta) * (pow(sin(theta * b), 3) + pow(cos(theta), 3)); 
        vertex(x, y)
	}
	endShape();
	pop();

}

For this project, I chose to explore the properties of the “Bean Curve,” essentially a curve shaped like a bean. After figuring out how to use the parametric equations, I experimented with implementing a series of beans that were arranged in a concentric shape and moved further apart with mouseX. From there, I tried plugging in different variables into this function to see what kinds of compositions I could create with different parameters.

LO 07

Title: Herald/Harbinger
Artists: Jer Thorpe & Ben Rubin

In the heart of Calgary, Alberta, an installation piece titled “Herald/Harbinger” brings to life the motion of Bow Glacier, demonstrating the connection between human activity and that of the melting glacier. A series of LED arrays installed at the entrance of a building use colored light to indicate real-time movements in the glacier; meanwhile, several speakers project the glacier’s subtle noises into the traffic-filled area. The lights and speakers are connected to the glacier via a seismic observatory and relayed via satellite, then put through an algorithm to visualize the data collected for display. Thousands of passersby feel the glacier’s presence every day, a reflection of how the glacier is an integral part of the city’s water source and history. However, the installation has a shelf life; it is a reminder that this glacier is melting, and there will be one day where the city sounds no longer duet those of Bow Glacier.

A video of the installation in action

Looking Outwards 06

“Mantel Rojo” by Manolo Gamboa Naon

Manolo Gamboa Naon, also known as “Manoloide,” is a digital artist based in Argentina whose work centers around generative algorithms that experiment with visual output. In his piece “Mantel Rojo,” or “Red Tablecloth,” he uses creative code to produce a swirling, mesmerizing composition filled with vivid colors and dynamic shapes. I am drawn to this piece because like many of his other works, there is no clear focal point; rather, viewers engage with the piece as a whole. Oftentimes, the longer one spends examining the work, the more little details and interesting coincidences seem to appear. In his piece specifically, the shapes and colors are generated pseudo-randomly, as the same hues reoccur and no other shapes are present besides circles and organic swirls.

Manoloide’s “Mantel Rojo”

Project 06 – Abstract Clock

candles

function setup() {
    createCanvas(480, 480);
    background(46, 27, 61);

   
}

function draw() {
	var sec = second();
    var min = minute();
    var hr = hour();

    background(122, 49, 0);
	noStroke();

	fill(255, 236, 202, 30);
	ellipse(240, 128+sec, 730, 505);
	ellipse(240, 200+(2*min), 540, 330);
	ellipse(240, 30+(13*hr), 368, 230);
	// cast lighting

	fill(0, 0, 0, 60);
	ellipse(240, 425, 420, 75);
	// plate shadow

	fill(146, 138, 183);
	ellipse(240, 415, 400, 75);
	fill(177, 175, 232);
	ellipse(240, 410, 320, 45);
	// plate

    
    fill(255, 242, 233);
    rect(210, 100+(13*hr), 60, 312-(13*hr));
    ellipse(240, 412, 60, 15);
    stroke(255, 205, 171);
    strokeWeight(0.5);
    ellipse(240, 100+(13*hr), 60, 15);
    // middle candle (takes the whole day to melt)

    push();
    fill(255, 210, 110);
    circle(240, 70+(13*hr), 35);
    triangle(225, 61+(13*hr), 255, 61+(13*hr), 240, 30+(13*hr));
    fill(255, 237, 202);
    circle(240, 73+(13*hr), 26); 
    pop();
    // middle candle flame

    var min = minute();
    noStroke();
    rect(160, 292+(2*min), 30, 120-(2*min));
    rect(290, 292+(2*min), 30, 120-(2*min));
    ellipse(175, 412, 30, 8);
    ellipse(305, 412, 30, 8);
    stroke(255, 205, 171);
    strokeWeight(0.5);
    ellipse(175, 292+(2*min), 30, 8);
    ellipse(305, 292+(2*min), 30, 8);
    // candles on either side of the middle candle (take an hour to melt)

    push();
    fill(255, 210, 110);
    circle(175, 270+(2*min), 22);
    circle(305, 270+(2*min), 22);
    triangle(175, 245+(2*min), 166, 264+(2*min), 184, 264+(2*min));
    triangle(305, 245+(2*min), 296, 264+(2*min), 314, 264+(2*min));
    fill(255, 237, 202);
    circle(175, 272+(2*min), 16);
    circle(305, 272+(2*min), 16);  
    pop();
    // flames for hour candles

    
    noStroke();
    rect(120, 352+sec, 20, 60-sec);
    rect(340, 352+sec, 20, 60-sec);
    ellipse(130, 412, 20, 5);
    ellipse(350, 412, 20, 5);
    stroke(255, 205, 171);
    strokeWeight(0.5);
    ellipse(130, 352+sec, 20, 5);
    ellipse(350, 352+sec, 20, 5);    
    // outermost candles (take 1 min to melt)

    push();
    fill(255, 210, 110);
    circle(130, 339+sec, 13);
    circle(350, 339+sec, 13);
    triangle(130, 325+sec, 124, 336+sec, 136, 336+sec);
    triangle(350, 325+sec, 356, 336+sec, 344, 336+sec);
    fill(255, 237, 202);
    circle(130, 340+sec, 9);
    circle(350, 340+sec, 9);
    pop();
    // flames for minute candles
}

For my abstract clock, I used a set of candles melting to represent the time. The biggest candle in the middle takes the entire day to “melt,” the ones on either side of it both take one hour to melt, and the smallest candles on the ends each take one minute to melt. The flames and cast lighting move accordingly, and the candles reset with the time.

I began with a preliminary sketch: