Final Project-Urban Wildlife-Veronica Wang

In this interactive game/animation:
(click on the canvas first)
Press left arrow to add birds, press right arrow to add chimneys. Bird nests and raccoons will show up according to the added elements. The position of mouseY changes the color of the sky. As more birds are added, bird sound gets louder.

sketch

//Veronica Wang
//Section B
//yiruiw@andrew.cmu.edu
//Final Project

var Y_AXIS = 1; //gradient sky axis
var c1, c2; //gradient sky colors
var PREFIX = "https://courses.ideate.cmu.edu/15-104/f2018/wp-content/uploads/2018/12/";
//var PREFIX = "";
var birdSound;
var trainSound;
var bV = 0.2;
var houseList = []; //array of houses
var allTrees = []; //trees
var birdList = []; //birds
var raccoonList = []; //raccoons
var flap = true;
var nestCount = 0;
var birdperNest = 3; //for every three birds draw a nest
var trainList = []; //trains
var rachouseCount = 0;

frameCount = 200;


function preload(){
    birdSound = loadSound(PREFIX + "birds.wav");
    trainSound = loadSound(PREFIX + "train.wav");
    trainSound.setVolume(0.5);
}

function setup() {
    createCanvas(500, 300);

    //sky colors
    c1 = color(244, 248, 255); //light blue
    c2 = color(94, 164, 186); //dark teal blue

    drawBackground();

    //draw houses
    for(var i = 0; i < 10; i++) {
        var newX = random(80, 420);
        var newY = random(120, 200);
        if (houseList.length < 1){
            houseList.push(makeHouse(newX, newY));
        } 
        else{
            while (checkifLess(newX, newY, houseList, 30)){
                newX = random(80, 420);
                newY = random(120, 200);
            }
            houseList.push(makeHouse(newX, newY));
        }
    }

    //draw trees
    for(var i = 0; i < 40; i++) {
        allTrees.push(makeTree());
    }
    sortTree(allTrees);
    sortTree(houseList);

    //draw creatures
    birdList.push(makeBird(width / 2,height / 2, 15));
    raccoonList.push(makeRac(width / 2, height / 2, 5));


}

function draw() {
    //play sound
    birdSound.setVolume(bV);
    if (frameCount % 100 == 0){
        birdSound.play();
    }
    //set volume to be proportional to number of birds
    bV = (map(birdList.length, 0, 20, 0, 1));
    

    drawBackground();
    drawStairs();

    //initial number of artificial nests
    nestCount = 0;
    rachouseCount = 0;

    //raccoon house counter
    for (var i = 0; i < houseList.length; i++) {
        if (houseList[i].rh){
            rachouseCount += 1;
        }   
    }

    //add raccoons
    if (raccoonList.length < rachouseCount * 2){
        raccoonList.push(makeRac(random(0, 500), random(150, 220)));
    }

    //drawing raccoons and removing them from array if out of canvas
    for (var i = 0; i < raccoonList.length; i++) {
        raccoonList[i].draw();
        raccoonList[i].rx += raccoonList[i].vel;
        if (racoutofBound(raccoonList[i])){
            raccoonList.splice(i, 1);
            i -= 1;
        }       
    }

    //draw houses
    for (var i = 0; i < houseList.length; i++) {
        houseList[i].draw();     
    }

    //draw trees
    for (var i = 0; i < allTrees.length; i++){
        if (i % 3 == 0){
            allTrees[i].draw1();
        } else if (i % 3 == 1){
            allTrees[i].draw2();
        } else {
            allTrees[i].draw3();
        }
        if (allTrees[i].nest){
            nestCount += 1;
        }
    }

    drawTracks();
    
    //bird wing flap
    if (frameCount % 40 == 0){
        flap = !(flap);
    }

    //if bird is out of canvas, take it out of the array
    for (var i = 0; i < birdList.length; i++) {
        if (birdoutofBound(birdList[i])){
            birdList.splice(i, 1);
            i -= 1;
        }
    }

    //draw birds
    for (var i = 0; i < birdList.length; i++) {
        if (flap){
            birdList[i].draw2();
        } else {
            birdList[i].draw();
        }
        birdList[i].bx += birdList[i].xvel * noise(1);
        birdList[i].by += birdList[i].yvel * noise(1);
    };

    //adding random movement and scale birds
    if (frameCount % 100 == 0){
        for (var i = 0; i < birdList.length; i++) {
            birdList[i].xvel += random(-3, 3) * (map(pow(2, birdList[i].by / 50), 0, pow(2, 300 / 50), 1, 100)) / 35;
            birdList[i].yvel += random(-1, 1) * (map(pow(2, birdList[i].by / 50), 0, pow(2, 300 / 50), 1, 100)) / 35;

        }
    }
    

    //night sky filter
    var darkness = map(mouseY, 0, height, 0, 200);
    fill(0, 0, 0, darkness);
    noStroke();
    rect(0, 0, width, height);

    //add nest to empty trees
    if (birdList.length > 0 & int(birdList.length / birdperNest) < 40){
        if (int(birdList.length / birdperNest) > nestCount){
            var seltree = int(random(0, allTrees.length));
            while (allTrees[seltree].nest){
                seltree = int(random(0, allTrees.length));
            }
            allTrees[seltree].nest = true;
        } else if (int(birdList.length / birdperNest) < nestCount){
            var seltree = int(random(0, allTrees.length));
            if (allTrees[seltree].nest == true){
                allTrees[seltree].nest = false;
            }
            
        }
    }

    //draw train
    if (frameCount % 400 == 0) {
        trainList.push(makeTrain());
        trainSound.play();
    }
    for (var i = 0; i < trainList.length; i++) {
        trainList[i].x -= trainList[i].vel;
        trainList[i].draw();
    };
    if (trainList.length > 0){
        if (trainList[0].x < -750){
            trainList.splice(0, 1);
        }
    }
}

//if raccoon is out of canvas
function racoutofBound(bird){
    if (bird.rx < 0){
        return true;
    } else if (bird.rx > width){
        return true;
    } else if (bird.ry < 0){
        return true;
    } else if (bird.ry > height){
        return true;
    }
    return false;
}

//if bird is out of canvas
function birdoutofBound(bird){
    if (bird.bx < 0){
        return true;
    } else if (bird.bx > width){
        return true;
    } else if (bird.by < 0){
        return true;
    } else if (bird.by > height){
        return true;
    }
    return false;
}

//sort tree order by y position
function sortTree(treelist){
    n = treelist.length;
    for (var i = 0; i < n; i++){
        for (var j = 0; j < n - i - 1; j++){
            
            if (treelist[j].y > treelist[j+1].y){
                var temp = treelist[j];
                treelist[j] = treelist[j+1];
                treelist[j+1] = temp;
            }
        }
    }
}

//draw tree outside of houses
function ispointIn(x, y, house){

    var x1 = house.x;
    var x2 = house.x + house.w;
    var y1 = house.y - house.w / 3;
    var y2 = house.y + house.h * house.f;
    if (x < x1){
        return false;
    } else if (x > x2){
        return false;
    } else if (y < y1){
        return false;
    } else if (y > y2 + 13){
        return false;
    }
    return true;
}

//goes through list to check if point is outside the boundary
function hListcheck(x, y, list, n){
    if (list.length < 1){
        return false;
    }
    if (n < list.length - 2){
        return (ispointIn(x, y, list[n]) || hListcheck(x, y, list, n + 1));
    } else {
        return ispointIn(x, y, list[n]);
    }
}

//make sure houses are not overlapping
function checkifLess(x, y, list, mindist){
    var chck = false;
    for (var i = 0; i < list.length; i++) {
        var objdist = dist(x, y, list[i].x, list[i].y);
        if (objdist < mindist){
            chck = true;
        }
    }
    return chck;
}

//house object
function makeHouse(locX, locY){
    var num = 75;
    var house = { x: locX,
                  y: locY,
                  w: map(pow(2, locY / num), 0, pow(2, 300 / num), 1, 100),  //proportionally scale house in the distance
                  f: floor(random() * 2 + 1), //random number of floors from 1-3
                  rh: false, //raccoon houses
                  draw: drawHouse
                };
    return house;
}

function drawHouse(){
    noStroke();
    fill(173, 110, 110);
    var h = this.w / 2;
    rect(this.x, this.y, this.w, h * this.f); //body of house
    rect(this.x + this.w * 0.7, this.y - this.w / 3, 
        this.w / 5, this.w / 3); //chimney
    triangle(this.x, this.y, 
            this.x + this.w / 2, this.y - this.w / 3, 
            this.x + this.w, this.y); //roof
    if(this.f == 1){
        //gradient
        for (var i = 0; i < this.y / 10; i++) { 
            var op2 = map(i, 0, 50, 0, 200);
            stroke(201, 141, 141, op2); 
            line(this.x, i * this.y * 0.005 + this.y, 
                this.x + this.w, i * this.y * 0.005 + this.y);
        }
        drawWindow(this.x + this.w / 5, this.y + this.w / 6, 
                this.w * 0.3, this.w / 5);
        drawShrub(this.x, this.y + h, 
                this.w * 0.5, this.w * 0.3);

    }else{
        //gradient
        for (var i = 0; i < this.y / 5; i++) { 
            var op3 = map(i, 0, 50, 0, 200);
            stroke(201, 141, 141, op3); 
            line(this.x, i * this.y * 0.005 + this.y, 
                this.x + this.w, i * this.y * 0.005 + this.y);
        }
        drawWindow(this.x + this.w / 5, this.y + this.w / 6, 
                this.w * 0.3, this.w / 5);
        drawWindow(this.x + this.w / 5, this.y + this.w * 0.6, 
                this.w * 0.3, this.w / 5);
        drawShrub(this.x, this.y + this.w, 
                this.w * 0.4, this.w * 0.3);
    } 

    if(this.rh){
        fill(135, 81, 132);
        rect(this.x + this.w, 
             this.y + h / 5, this.w / 6, (h * this.f) * 0.75);
        triangle(this.x + this.w, this.y + h * this.f, 
                 this.x + this.w, this.y + (h * this.f) / 2, 
                 this.x + this.w + this.w / 3, this.y + h * this.f);
    }
}

function drawWindow(x, y, w, h){
    noStroke();
    fill(239, 233, 218);
    rect(x, y, w, h);
}

function drawShrub(x, y, w, h){
    noStroke();
    fill(143, 168, 104);
    ellipse(x, y, w, h);
    ellipse(x + 5, y, w * 0.8, h * 0.5);
    ellipse(x + 3, y - 2, w * 0.8, h * 0.8);

}

function makeTree(){
    var num1 = 75;

    var tempY = random(120, 200);
    var tempX = random(0, 450)
    var mult = map(pow(2, tempY / num1), 0, pow(2, 300 / num1), 1, 100) / 40;

    var tX = tempX + 3 * mult;
    var tY = tempY + 30 * mult;

    while (hListcheck(tX, tY, houseList, 0)){
        tempY = random(120, 200);
        tempX = random(0, 450)
        tX = tempX + 3 * mult;
        tY = tempY + 30 * mult;
    }
    
    var tree = { x: tempX,
                 y: tempY,
                 w: map(pow(2, tempY / num1), 0, pow(2, 300 / num1), 1, 100),  //proportionally scale house in the distance
                 m: map(pow(2, tempY / num1), 0, pow(2, 300 / num1), 1, 100) / 40,
                 draw1: tree1draw,
                 draw2: tree2draw,
                 draw3: tree3draw,
                 nest: false
                };
    return tree;

}


function tree1draw(){
    noStroke();
    push();
    
    translate(this.x, this.y);
    scale(this.m, this.m);
    fill(122, 98, 66);
    rect(3, 0, 3, 30);
    fill(95, 140, 99, 180);
    ellipse(0, -5, 30, 35);
    ellipse(15, -5, 20, 25);
    ellipse(5, 8, 50, 20);
    if(this.nest == true){
        fill(89, 68, 49);
        rect(0, 0, 10, 10);
        fill(193, 164, 137);
        ellipse(5, 5, 4, 4);
    }
    pop();
}

function tree2draw(){
    
    noStroke();
    push();
    translate(this.x, this.y);
    scale(this.m, this.m);
    fill(122, 98, 66);
    rect(5, 0, 3, 30);
    fill(95, 120, 96, 200);
    triangle(18, 18, -6, 18, 6, -30);
    if(this.nest == true){
        fill(89, 68, 49);
        rect(0, 0, 10, 10);
        fill(193, 164, 137);
        ellipse(5, 5, 4, 4);
    }
    pop();

}

function tree3draw(){
    noStroke();
    push();
    var mult = this.w / 40;
    translate(this.x, this.y);
    scale(mult, mult);
    fill(122, 98, 66);
    rect(3, 0, 3, 30);
    fill(108, 132, 102, 200);
    ellipse(4, -17, 20, 20);
    ellipse(4, -8, 30, 20);
    ellipse(4, 5, 40, 25);
    if(this.nest == true){
        fill(89, 68, 49);
        rect(0, 0, 10, 10);
        fill(193, 164, 137);
        ellipse(5, 5, 4, 4);
    }
    pop();

}

function drawBackground(){

    //draw background gradient
    setGradient(0, 0, width, height * 0.45, c1, c2, Y_AXIS);

    //mountain layer 1
    noStroke();
    fill(75, 137, 138);
    beginShape();
    curveVertex(0, height);
    curveVertex(0, height);
    curveVertex(0, 200);
    curveVertex(0, 180);
    curveVertex(190, 60);
    curveVertex(280, 80);
    curveVertex(350, 70);
    curveVertex(420, 100);
    curveVertex(520, 80);
    curveVertex(width, height);
    curveVertex(width, height);
    endShape();
    
    //gradient mask
    for (var i = 0; i < 500; i++) { 
        var op = map(i, 100, 500, 0, 255);
        stroke(255, 255, 255, op); 
        line(0, i * 0.6, width, i * 0.6);
    }

    //mountain layer 2
    noStroke();
    strokeWeight(1);
    fill(75, 147, 154);
    beginShape();
    curveVertex(0, height);
    curveVertex(0, height);
    curveVertex(0, 120);
    curveVertex(0, 110);
    curveVertex(100, 70);
    curveVertex(200, 130);
    curveVertex(300, 90);
    curveVertex(400, 130);
    curveVertex(500, 120);
    curveVertex(500, 130);
    curveVertex(width, height);
    curveVertex(width, height);
    endShape();

    //gradient mask
    for (var i = 0; i < 500; i++) { 
        var op = map(i, 100, 500, 0, 255);
        stroke(255, 183, 80, op); 
        line(0, i, width, i);
    }

}

function drawStairs(){
    noStroke();
    fill(99, 88, 77);
    for (var i = 0; i < 15; i++) {
        rect(i * 5 + 30, i * 3 + 190, 8, 1.5);
        rect(i * 5 + 40, -i * 2 + 190, 8, 1);
        rect(i * 5 + 30, i * 3 + 120, 1 + i * 0.5, 1)
    };

    rect(35, 190, 2, 45);
    rect(28, 190, 2, 45);
    rect(28, 210, 8, 2);

    rect(110, 162, 1, 35);
    rect(116, 162, 1, 35);
    rect(110, 170, 6, 1);

    strokeWeight(2);
    line(1, 1, 100, 100);

    for (var j = 0; j < 30; j++) {
        fill(117, 107, 98);
        rect(j * 2 + 440, j * 3 + 130, 1 + j * 0.7, 1);
    };

}

function drawTracks(){
    stroke(122, 102, 82);
    strokeWeight(2);
    line(0, 280, 500, 280);
    strokeWeight(1);
    line(0, 275, 500, 275);

    for (var i = 0; i < 15; i++) {
        rect(i * 40, 273, 1, 6);
    };
}

function makeTrain(){
    var train = { x: 500,
                  y: 277,
                  vel: random(5, 15),
                  draw: drawTrain
                };
    return train;
}

function drawTrain(){
    noStroke();
    fill(80);
    triangle(this.x, this.y - 5, this.x + 25, this.y - 5, this.x + 25, this.y - 20);
    rect(this.x + 12, this.y - 40, 10, 15);
    rect(this.x + 20, this.y - 40, 50, 35);
    rect(this.x + 22, this.y - 50, 15, 25);
    rect(this.x + 55, this.y - 59, 30, 4);
    rect(this.x + 70, this.y - 16, 16, 8);
    rect(this.x + 80, this.y - 16, 8, 8);
    rect(this.x + 88, this.y - 13, 18, 3);
    fill(140, 89, 88);
    rect(this.x + 16, this.y - 45, 40, 25);
    fill(140, 100, 88);
    rect(this.x + 60, this.y - 55, 20, 45);
    fill(201, 216, 215);
    rect(this.x + 64, this.y - 52, 12, 18);
    fill(96, 83, 58);
    ellipse(this.x + 30, this.y - 5, 15, 15);
    ellipse(this.x + 70, this.y - 5, 15, 15);

    for (var i = 1; i < 5; i++) {
        fill(80);
        rect(this.x + 100 * i, this.y - 55, 90, 3);
        rect(this.x + 100 * i, this.y - 13, 100, 3);
        fill(140, 120, 88);
        rect(this.x + 5 + 100 * i, this.y - 52, 80, 45);
        fill(140, 130, 98);
        rect(this.x + 5 + 100 * i, this.y - 22, 80, 15);
        fill(201, 216, 215);
        rect(this.x + 12 + 100 * i, this.y - 48, 30, 18);
        rect(this.x + 48 + 100 * i, this.y - 48, 30, 18);
        fill(96, 83, 58);
        ellipse(this.x + 20 + 100 * i, this.y - 5, 15, 15);
        ellipse(this.x + 70 + 100 * i, this.y - 5, 15, 15);
    };

    fill(0);
    drawSmoke(this.x, this.y);

}

function drawSmoke(x, y){
    fill(255, 255, 255, 100);
    ellipse(x + 30, y - 60, 20, 10);
    ellipse(x + 50, y - 70, 15, 8);
}


function makeBird(x, y) {
    var num = 50;
    var bird = {"bx": x, 
                "by": y, 
                "bsz": size, 
                "bsca": (map(pow(2, y / num), 0, pow(2, 300 / num), 1, 100)) / 35,
                "xvel": random(-10, 10) * (map(pow(2, y / num), 0, pow(2, 300 / num), 1, 100)) / 35,
                "yvel": random(-5, 5) * (map(pow(2, y / num), 0, pow(2, 300 / num), 1, 100)) / 35,
                };
    bird.draw = birdDraw;
    bird.draw2 = birdDraw2;
    return bird;
}

function birdDraw(){
    noFill();
    stroke(0);
    strokeWeight(2);
    push();
    translate(this.bx, this.by);
    scale(this.bsca);
    ellipseMode(CENTER); 
    arc(35, 35, 100, 100, PI * 1.25, PI * 1.5);
    arc(-35, 35, 100, 100, PI * 1.5, PI * 1.75);
    fill(0);
    ellipse(0, 0, 5, 5); 
    pop();
}

function birdDraw2(){
    noFill();
    stroke(0);
    strokeWeight(2);
    push();
    translate(this.bx, this.by);
    scale(this.bsca);
    rotate(PI/10);
    arc(35, 35, 100, 100, PI * 1.25, PI * 1.5);
    fill(0);
    ellipse(0, 0, 5, 5); 
    pop();

    push();
    translate(this.bx, this.by);
    scale(this.bsca);
    rotate(-PI / 10);
    arc(-35, 35, 100, 100, PI * 1.5, PI * 1.75);
    pop();
}

//make raccoon
function makeRac(x, y){
    var rac;
    var num = 50;
    rac = {
        "rx": x ,
        "ry": y, 
        "rsz": size,
        "bsca": (map(pow(2, y / num), 0, pow(2, 300 / num), 1, 100)) / 400,
        "vel": random(-2, 2) * (map(pow(2, y / num), 0, pow(2, 300 / num), 1, 50)) / 35
    };
    rac.draw = racDraw;
    return rac;
}

//draw raccoon
function racDraw(){
    var inv = -1;
    push();
    translate(this.rx, this.ry);
    fill(0);
    noStroke();
    beginShape();
    if (this.vel < 0){
        scale(this.bsca, this.bsca);
    } else{
        scale(this.bsca * -1, this.bsca);
    }
    vertex(0, 0);
    vertex(5, -10);
    vertex(3, -20);
    vertex(7, -30);
    vertex(5, -40);
    vertex(8, -45);
    vertex(20, -40);
    vertex(65, -55);
    vertex(85, -65);
    vertex(150, -60);
    vertex(190, -30);
    vertex(180, 20);
    vertex(190, 50);
    vertex(180, 80);
    vertex(170, 80);
    vertex(170, 75);
    vertex(175, 73);
    vertex(176, 55);
    vertex(140, 25);
    vertex(110, 25);
    vertex(80, 80);
    vertex(70, 80);
    vertex(70, 75);
    vertex(75, 75);
    vertex(80, 50);
    vertex(70, 10);
    vertex(50, 10);
    vertex(30, 5);
    vertex(10, 10);
    vertex(0, 0);
    endShape();

    beginShape();
    vertex(200, -25);
    vertex(192, 10);
    vertex(200, 18);
    vertex(210, -20);
    endShape();

    beginShape();
    vertex(220, -15);
    vertex(230, -8);
    vertex(220, 30);
    vertex(210, 22);
    endShape();

    beginShape();
    vertex(240, -3);
    vertex(250, 5);
    vertex(242, 20);
    vertex(232, 25);
    endShape();

    beginShape();
    fill(255);
    vertex(50, 10);
    vertex(30, -15);
    vertex(20, -13);
    vertex(15, -5);
    vertex(15, -5);
    vertex(20, 0);
    vertex(26, 0);
    vertex(35, 6);
    endShape();

    fill(0);
    ellipse(23, -8, 5, 5);
    rect(112, 50, 15, 7);

    rotate(PI / 4);
    rect(60, -40, 10, 40);
    rect(120, -80, 10, 30);
    pop();
}

//interactions
function keyPressed(){
    if(keyCode === RIGHT_ARROW){
        if (rachouseCount < houseList.length){
            var selhouse = int(random(0, houseList.length));
            while (houseList[selhouse].rh == true){
                selhouse = int(random(0, houseList.length));
            }
            houseList[selhouse].rh = true;
        }
    }
    if(keyCode === LEFT_ARROW){
        birdList.push(makeBird(random(0, 500), random(0, 200)));
    }
}

//Linear gradient code from p5js examples https://p5js.org/examples/color-linear-gradient.html
function setGradient(x, y, w, h, c1, c2, axis) {
    noFill();
    if (axis == Y_AXIS) {  // Top to bottom gradient
        for (var i = y; i <= y + h; i++) {
            var inter = map(i, y, y + h, 0, 1);
            var c = lerpColor(c1, c2, inter);
            stroke(c);
            line(x, i, x + w, i);
        }
    }  
}

In this project I want to create an interactive animation on cohabitation wiht urban wildlife in cities. As we are displacing natural habitats to make way for urban sprawl, effects of a loss of biodiversity and edge effects from habitat fragmentation are becoming more pronounced. In my studio I am currently working on a thesis project dealing with the environment and cohabitation/negotiation of boundaries between human and more-than-human species, and creating installations for endangered species as well as synanthropic species to share urban space. I am inspired by the works of Joyce Hwang and Sarah Gunawan , and I want to create an animation that documents the vision of such installation projects and their impacts on our environment. Especially the bird landing pads and composting chimneys for raccoons.

In this animation, trains pass by at a certain interval of time, pressing left arrow adds a bird, and for every 3 birds added, an artificial bird nest attached to trees will pop up. (Nests will start disappearing when birds leave the screen). Pressing right arrow adds a compost chimney attached to houses, and every chimney attracts 2 raccoons.

Working on this project I spent a large chunk of my time illustrating the creatures and houses which in hindsight could have been done much easier if I just drew them and upload them to imgur. I also had trouble with overlapping objects and had to create functions that sort the order or the object array and also draws objects outside of the boundary of other objects. I feel like I reviewed everything we learned this semester through this project.

Sound Test

 

Project 12-Project Proposal-Veronica

For the final project, I want to create an animation with a bit of interaction and sound effects. In my studio I am currently working on a thesis project dealing with the environment and cohabitation/negotiation of boundaries between human and more-than-human species, and creating installations for endangered species as well as synanthropic species to share urban space. I am inspired by the works of Joyce Hwang and Sarah Gunawan , and I want to create an animation that documents the vision of such installation projects and their impacts on our environment.

I have identified the green spaces along the MLK Jr. East busway in the Hill District, Pittsburgh, and I want to focus my animation on one scene and 3 different species of animals: bats, black throat warblers, and raccoons. The animation will show buses and trains pass by at a certain interval of time, and a key press will add an installation of an artificial “nest” for a certain type of animal. Initially the background sound will be city noises, and as the number of birds are added, the bird sound will get louder and city noises get quieter. Below is a rough sketch of my ideas.

 

Looking Outwards 12-Project Priors and Precursors-Veronica

For this week’s looking outwards, I decided to look at the works from Chloe Varelidi(http://varelidi.com) and Kaho Abe(http://kahoabe.net/portfolio). They are both new media artists and game designers working with a variety of mediums and often produce projects that are a mix of digital and physical artifacts.

Chloe Varelidi is the founder of Humans Who Play, a design firm that uses play as educational and creative tools. What really inspires me about her work is that she could always manage to bridge that creative gap and make coding easily accessible to everyone. In her projects there are also always a physical artifact to help understand the coding work that’s going on behind the scenes, and makes the process of play more meaningful and informative.

project oiko by Chloe Varelidi

Oiko is a project created for younger kids to learn about environmental and energy saving strategies by reminding them to turn off the lights. She managed to make the process fun and playful rather than tedious.

Tinkerly A prototype I developed with the always crafty Jess Klein for an ipad game app that interacts with conductive-paper avatars that kids can tinker with. The gorgeous 3D art is by Christopher Labrooy..
project tinkerly by Chloe Varelidi

Tinkerly is a project to foster creativity, with a digital interface on an ipad that can be combined with physical paper models to create avatars and scenes for children.

Kaho Abe is an American Japanese artist focusing on designing for social interactions and experiences that enhance the relationship between people. Previously a fashion designer, her interest in wearable technology and game design combined to create projects that engage behaviors, gestures, and custom controllers.

Her animation Window Vistas is a generative landscape video that documents her travel on a train. I am hoping to do something similar for my final project and learning from her how she created 3D-looking landscape elements.

screenshot of her animation Window Vistas

Hit Me! is a wearable game device that engages two players and speculators, and tests for their agility, strength, and ability to take quick snapshots. The interactive headpiece has a button and camera that connects wirelessly to a screen. The objective is to hit the opponent’s button, and then take a snapshot of them using your own camera.

Hit Me! (2011) from Kaho A on Vimeo.

Both artists’ work are inspiring, especially how they made digital artifacts tangible and accessible to everyone. Although it would be hard for me to incorporate physical artifacts in my final project, I was inspired by their style, method and intent for their project to be educational and informative.

Project-11 Composition-Veronica

sketch

//Veronica Wang
//Section B
//yiruiw@andrew.cmu.edu
//Project-11

var turtle = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; 
var angle = 0; //current direction turtle is facing
var turnangle = 5; //turn angle
var incre = 0.1; //speed increment
var counter = 0; //how many times turtle had completed a full geometry

function setup() {
    createCanvas(480, 300);
    background(0);
    frameRate(10);

    //create array of turtles
    for (var i = 0; i < turtle.length; i++) {
       turtle[i] = makeTurtle(random(0, width), random(0, height), random(1, 3));
       turtle[i].setColor(color(random(255), random(255), random(255), 60));
    };
}

function draw() {
  //draw turtles
  for (var i = 0; i < turtle.length; i++) {
    turtle[i].penDown();
    turtle[i].setWeight(5);
    //change turtle direction after 100 instances
    if (counter < 100){
      if(angle < 0 || angle > 90){
            turnangle *= -5;
        }
      angle += turnangle;
      turtle[i].forward(1);
      turtle[i].right(turnangle);
      turtle[i].speed += incre;
      counter += 1;
    }
    turtle[i].speed += 0.5;
    turtle[i].forward(2);
    turtle[i].right(turnangle);
  }
    
}

function mousePressed(){
    turtle.push(makeTurtle(mouseX, mouseY, random(1, 3)))
    turtle[turtle.length - 1].setColor(color(random(255), random(100), random(255), 60));
    
}



//------------------------------------------------------------------------------------  


function turtleLeft(d) {
    this.angle -= d;
}

function turtleRight(d) {
    this.angle += d;
}

function turtleForward() {
    var rad = radians(this.angle);
    var newx = this.x + cos(rad) * this.speed;
    var newy = this.y + sin(rad) * this.speed;
    this.goto(newx, newy);
}

function turtleBack(p) {
    this.forward(-p);
}

function turtlePenDown() {
    this.penIsDown = true;
}

function turtlePenUp() {
    this.penIsDown = false;
}

function turtleGoTo(x, y) {
    if (this.penIsDown) {
      stroke(this.color);
      strokeWeight(this.weight);
      line(this.x, this.y, x, y);
    }
    this.x = x;
    this.y = y;
}

function turtleDistTo(x, y) {
    return sqrt(sq(this.x - x) + sq(this.y - y));
}

function turtleAngleTo(x, y) {
    var absAngle = degrees(atan2(y - this.y, x - this.x));
    var angle = ((absAngle - this.angle) + 360) % 360.0;
    return angle;
}

function turtleTurnToward(x, y) {
    var angle = this.angleTo(x, y);
    if (angle < 180) {
        this.angle += speed;
    } else {
        this.angle -= speed;
    }
}

function turtleSetColor(c) {
    this.color = c;
}

function turtleSetWeight(w) {
    this.weight = w;
}

function turtleFace(angle) {
    this.angle = angle;
}

function makeTurtle(tx, ty, vel) {
    var turtle = {x: tx, y: ty,
                  angle: 0.0, 
                  penIsDown: true,
                  color: color(128),
                  weight: 1,
                  speed: vel,
                  left: turtleLeft, right: turtleRight,
                  forward: turtleForward, back: turtleBack,
                  penDown: turtlePenDown, penUp: turtlePenUp,
                  goto: turtleGoTo, angleto: turtleAngleTo,
                  turnToward: turtleTurnToward,
                  distanceTo: turtleDistTo, angleTo: turtleAngleTo,
                  setColor: turtleSetColor, setWeight: turtleSetWeight,
                  face: turtleFace};
    return turtle;
}

In this project I wanted to make a somewhat random drawing machine that generates geometry based on rotation and random population. I liked the aggregation of triangles in this iteration and how the rotation made them look more circular/gear like.

Beginning stage 
More complex stage
Complex/chaotic stage

Looking Outwards-11 Computer Music-Veronica

(Video of performance using MI.MU gloves)

MI.MU gloves are designed by musician and artist, Imogen Heap, as alternatives to instruments during musical performances. Imogen set out to create a better relationship with the music software and hardware that forms her musical toolbox and came across the idea of making music using a pair of musical gloves.

“MI.MU exists to revolutionize the way we make music through movement”

Behind the product is a team of specialist musicians, artists, scientists, and technologists developing cutting-edge wearable technology for the performance and composition of music and specializing in textiles, electronics, sensors, software and, music.

GLOVOLUTIONsmall
Iterations and evolution of glove design
anatomy of a glove tech
Glove design details
Mi. Mu works by capturing movement and hand gestures with sensors and send information wirelessly from the board on the wrists to a computer backstage. The software enables performers to map that data to” musical control signals” and combine different gestures and movements to make more complex controls. Additionally, the gloves can also be programmed to control third-party music production and editing software.
On her product website, it says that “The glove technology evolved in a symbiotic relationship with Imogen’s performances and writing. Real performances drove the development of the gloves, leading to an instrument and controller fit for professional musicians, ready to make complex, beautiful and engaging music.”

(Imogen Heap and a long exposure shot of her using the gloves)

I think the project is really successful at changing music composing into an intuitive and fun process and allowing for a different way of performing music. It also allows performers and artists to experiment with different types of music instruments without having to purchase physical instruments. Dancers and people with disabilities were also able to use these gloves to express themselves through music.

 

Project-10-Landscape-Veronica

sketch

// Veronica Wang
// Section B 
// yiruiw@andrew.cmu.edu
// Project-10

var sushi1 = [];
var sushi2 = [];
var sushi3 = [];

function setup() {
    createCanvas(480, 300); 
    frameRate(100);
}


function draw() {
    background("wheat"); 
    
    displayRoom();

    displayPlates();
    removePlates(sushi1);
    removePlates(sushi2);
    removePlates(sushi3);
    newPlate(); 

}


function displayPlates(){
    for (var i = 0; i < sushi1.length; i++){
        sushi1[i].move();
        sushi1[i].display1();
    }
    for (var i = 0; i < sushi2.length; i++){
        sushi2[i].move();
        sushi2[i].display2();
    }
    for (var i = 0; i < sushi3.length; i++){
        sushi3[i].move();
        sushi3[i].display3();
    }
}


function removePlates(plates){

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


function newPlate() {
    // With a very tiny probability, add a new sushi to the end.   
    var prob = 0.008;
    //sandomly select which type of sushi to serve
    if (random(0, 1) < prob) {
        var sunum = random(0,3);
        if (sunum < 1){
            sushi1.push(makePlate(width));
        } else if (sunum < 2){
            sushi2.push(makePlate(width));
        } else {
            sushi3.push(makePlate(width));
        }
        
    }  
}


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

// draw the building and some windows
function sushi1Display() {

    fill(255); 
    stroke(0); 
    push();
    translate(this.x, height - 135);

    //sushi1
    fill("black");
    noStroke();
    ellipse(12.5, 10, 25, 10);
    rect(0, 0, 25, 10);
    fill("white");
    ellipse(12.5, 0, 25, 10);
    fill("red");
    ellipse(10, 0, 5, 5);
    ellipse(11, 2, 5, 5);
    ellipse(12, -1, 5, 5);
    ellipse(14, -3, 5, 5);
    ellipse(10, 2, 5, 5);
    ellipse(11, -4, 5, 5);
    ellipse(15, -2, 5, 5);
    ellipse(16, -3, 5, 5);

    pop();
}

function sushi2Display() {

    fill(255); 
    stroke(0); 
    push();
    translate(this.x, height - 135);

    //sushi2
    fill("black");
    noStroke();
    ellipse(10, 10, 20, 10);
    rect(0, 0, 20, 10);
    fill("white");
    ellipse(10, 0, 20, 10);
    fill("orange");
    rect(0, -3, 22, 5);
    fill("black");
    rect(7, -5, 5, 10);

    pop();
}

function sushi3Display() {

    fill(255); 
    stroke(0); 
    push();
    translate(this.x, height - 135);

    //sushi3
    fill("black");
    noStroke();
    ellipse(10, 10, 20, 10);
    rect(0, 0, 20, 10);
    fill("white");
    ellipse(10, 0, 20, 10);
    fill("salmon");
    ellipse(10, 0, 10, 5);

    pop();
}


function makePlate(birthLocationX) {
    var plt = {x: birthLocationX,
                breadth: 50,
                speed: -1.0,
                nItems: round(random(1,3)),
                move: platesMove,
                display1: sushi1Display,
                display2: sushi2Display,
                display3: sushi3Display}
    return plt;
}

//drawing elements in the room
function displayRoom(){
    //curtain panels
    fill("cornsilk");
    noStroke();
    rect(0, 0, width, 75);

    stroke("peru");
    strokeWeight(1);

    for (var i = 0; i < 20; i++) {
        line(i * 30, 0, i * 30, 75);
    };
    
    strokeWeight(10);
    line(0, 75, width, 75);

    //lights
    stroke("black");
    strokeWeight(2);

    for (var i = 0; i < 5; i++) {
        line(50 + i * 90, 0, 50 + i * 90, 100);
        triangle(50 + i * 90, 100, 40 + i * 90, 110, 60 + i * 90, 110);
        rect(45 + i * 90, 100, 10, 5);
    };

    //conveyor belt
    fill("gray");
    noStroke();
    rect(0, 150, width, 40);

    //table
    noStroke();
    fill("tan");
    rect(0, 190, width, 200);
    
    fill("peru");
    rect(0, 190, width, 10);

    strokeWeight(1);
    stroke(0);
    line(0,height-70, width, height-70); 

    //plate
    fill("white");
    ellipse(width / 2, height - 40, 90, 30);

    //chopsticks
    noStroke();
    fill("lightgray");
    rect(300, height - 50, 20, 8);
    fill("black");
    rect(305, height - 55, 2, 40);
    rect(310, height - 55, 2, 40);

}



Rotating sushi bars are one of my favorite types of restaurants, so I tried to create a conveyor belt serving scene in this project. It took me some time to figure out how to randomly select different objects, and also the overlapping of objects being generated. I tried playing around with probability/count/ etc. but some instances are still overlapped. 🙁

Initial sketch

Looking Outwards-10 Women Practitioners-Veronica

Mimus is a curious industrial robot coded not to follow instructive movements, but to explore and respond to her surrounding environment from data collected through sensors. Placed in a glass room, Mimus interacts with people walking around her by approaching them and moving along with their movements. The designer, Madeline Gannon, intended to respond to the fear that robots are taking work away from humans. She believes in “a more optimistic future, where robots do not replace our humanity, but instead amplify and expand it”. In her works, robots are treated as living creatures with emotions rather than objects, and she works towards a relationship of empathy and companionship between man and machine.

Interaction_0005_Move-FINAL-06-01.png.png
Mimus responding to movement of people

 

 

 

 

 

Madeline graduated from Carnegie Mellon University with a Ph.D. in Computational Design and have since then been developing projects with natural gesture interfaces and digital fabrication. Some of her other works, for example, Tactum, allows people with little to none coding knowledge to be able to participate in the design process with very intuitive gestures. Her work intends to blur the line between man and machine and to break the stereotypical idea of dominance, and to prove that co-existence and collaboration can better amplify our human capabilities.

 Image by ATONATON, LLC. / Autodesk, Inc.
Long Exposure of Mimus

Looking Outwards-09 on Looking Outwards-Veronica

The exterior of the Israel Pavilion showcasing LifeObject

This week I went through my friend Judy’s posts and was inspired by one of the projects she has shared, LifeObject. The project is a biologically inspired interior installation mimicking the behavior of bird’s nests and was designed through 3D scanning and modeling.

Judy wrote in her blog:

There is a system of hierarchy reflected through the process, from design to fabrication to assembly. The entire form is made by the use of gravity and that is where randomness comes into the design.  With the analysis of the bird’s nest, twig-like structures were produced and arranged/bent randomly with a preset value, which means that the form of LifeObject is adaptable. The core is simple, the inner array is varied slightly, and the edges are diverse in static movement.

The introduction and practice of new materials blurred the line between digital fabrication processes and design. And this sort of architectural exploration – properties of materials and modes of transformation – came from the architect’s palette of expression.

I find the project’s narrative of exploring the relationship between human and nature beyond the binary distinction of nature and culture inspiring. I think the project is successful in conveying and contradicting ideas of ecosystems, eco-literacy and system resiliency. The designers described the project as “an assembly of weak and light found materials with no additional joints or glue, out of which emerges a free-form complex structure that is extremely light, robust and highly resilient”. I think the strength in solidarity and cultural resiliency and tolerance contributes to the conversation of globalization and ongoing cultural issues, and LifeObject presents a stance in the Israeli geopolitical context and responds to the crisis with resiliency.

Project-09-Portrait-Veronica

sketch

//Veronica Wang
//Section B
//yiruiw@andrew.cmu.edu
//Project-09

var underlyingImage;

function preload() {
    //loading image from URL
    var myImageURL = "https://i.imgur.com/25qNlPj.jpg";
    underlyingImage = loadImage(myImageURL);
}

function setup() {
    createCanvas(480, 480);
    background(0);
    //loading pixels from image
    underlyingImage.loadPixels();
    //drawing speed
    frameRate(220);
}

function draw() {
    //random pixel from image
    var px = random(width);
    var py = random(height);
    //constraining pixel to canvas
    var ix = constrain(floor(px), 0, width-1);
    var iy = constrain(floor(py), 0, height-1);
    var theColorAtLocationXY = underlyingImage.get(ix, iy);

    noStroke();
    fill(theColorAtLocationXY);
    push();
    //rotate pixel
    translate(px, py);
    rotate(random(0, PI));
    //scale pixel
    scale(random(0.5, 3));
    //draw pixel as rectangles
    rect(0, 0, 10, 6);
    pop();
}

This is an abstract portrait of my friend Yang. I decided to use randomly sized and rotated rectangles to represent the pixels to create a confetti looking effect. The result ended up looking quite abstract.

Original image
Digital Portrait

Looking Outwards-08 Creative Practice-Veronica

Eyeo 2015 – Meejin Yoon from Eyeo Festival on Vimeo.

Meejin Yoon: mystudio.us

I was interested in the works and creative practice of Meejin Yoon, the co-founder of Howeler Yoon Architecture, former head of the Department of Architecture at MIT, and dean of the College of Architecture, Art, and Planning at Cornell University. Trained as an architect, she had always been interested in the interactive aspect between people and public space, and responsiveness of space and creating relationships between content and context within the public sphere. In the Eyeo talk, she focused on her work in the field of interactive public space projects that “bridge issues of technology and play”. Her work spans across a wide range of topics, including responsive technologies, interactive technologies, smart materials, renewable energy, media-based public art, public engagement, and the public process.

At the beginning of her talk she explained how she is a very private person, but working with the public sphere has made her realize how the environment and responsive space can have a strong impact on her. I find her workflow of defamiliarizing and refamiliarizing interesting, and the psychologic studies she went through in order to create spaces, where people will intuitively interactive with, where people won’t be intimidated to touch elements in a public space. I’ve personally visited one of her projects, the Swing Time, in Boston. The project mimics the rubber tire swings that people would build in their backyards, refamiliarizing them with the concept,  but also has an accelerator and an interactive lighting feature that responds to touch and speed.