cmhoward-finalproject

For my project, I created an animated children’s book. This project was really exciting to create as I was able to practice using simple and more complex animation. With having 10 pages, I focused on experimenting with different kinds of animations and page turning effects. All of the backgrounds were drawn by me! The animated objects were also drawn by me, or created in p5.js. For the sake of cleanliness and consistency, I decided that drawing the background images myself would be the best possible solution.

The code is structured by creating an array of functions that implements the functions by indexing through a page number counter.

Detailed page explanations below:

On page 4, the Giraffe suggests for the Lion to sleep with a spoon under his pillow to make it rain, so the user must move the spoon to the pillow. When the spoon is within the boundaries of the pillow, it flips to the next page. 

On page 5, I chose to do a simple page turning animation where the user must click within the boundary of the page turning image. While not nearly as complex as other pages, it was necessary to add this page for the sake of the story!

On page 9, the animals are having a party so I created an object animation of balloons floating to the top of the page. When the array length (i.e # of balloons) reaches 10 balloons, it moves to the next page.

On the last page, the animals begin to dance and I use a frame animation to flip through images of the animals moving. It also begins to rain and I created an object animation of rain falling from the top of the canvas.

Since I created a lot of my own images, I decided to package this project on my computer and run it on a local server.

To run this program:

  1. Download .zip file and extract it to your computer
  2. Open a command prompt, and type cd “path to file” (ex: C:\Users\Cassie Howard\Downloads\cmhoward-final-project\template-all)
  3. Then connect to python “python -m http.server”
  4. After it connects, open up http://localhost:8000 in your web browser.

If you get confused on how to move to the next page, remember the different page turning implementations i.e clicking on the jittering objects, completing the animation, or simply waiting (i.e for ten balloons to appear).

cmhoward-final-project

Code to drag objects inspired by:

Draggable Example (written by Daniel Shiffman)

code below! (it’s not NOT working, you just can’t see all of the background images until you connect to a local server!)

sketch-87

//Cassandra Howard
//Section B
//cmhoward@andrew.cmu.edu
//Final Project

//IMAGE VARIABLES
var page1;
var page2;
var page3;
var page4;
var spoon;
var page5;
var page6;
var page7;
var page8;
var page9;
var page10;
var turn_page;
var tomato;

//PAGE COUNTER
var page = 0;

//LOOP THROUGH PAGES
var clickFunctions = [click1, click2, click3, click4, click5, click6, click7, click8, click9, click10];
var drawFunctions = [draw1, draw2, draw3, draw4, draw5, draw6, draw7, draw8, draw9, draw10];

//DRAW1 GLOBAL VARIABLES
//VERTICES POINTS OF SUN
var sunX = [40, 50, 60, 50, 80, 50, 60, 50, 40, 50, 20, 50, 40];
var sunY = [26.5, 53, 80, 53, 53, 53, 26.5, 53, 80, 53, 53, 53, 26.5];

//DRAW2 GLOBAL VARIABLES
//SET Y VALUE OF TOMATOES, INTIALIZE TOMATOES POSITIONS 
var tomatoY1 = 315;
var tomatoY2 = 300;
var tomatoFalling = false;

//DRAW4 GLOBAL VARIABLES
//INTIALIZE SPOON VALUES
var draggingSpoon = false;
var rolloverSpoon = false;
var spoonX;
var spoonY;
var spoonW;
var spoonH;
var offsetSpoonX; 
var offsetSpoonY;

//DRAW6 GLOBAL VARIABLES
//LOAD IMAGE FILES FOR FRAME ANIMATION, CREATE EMPTY ARRAY FOR IMAGES
//INTIALIZE COIN POSITION
var frames = [];
var filenames = [
    "assets/coin_1.png",
    "assets/coin_2.png",
    "assets/coin_3.png",
    "assets/coin_4.png"
    ];
var coinX = 50;
var coinY = 50;
var targetX;
var targetY;
var dx;
var dy;
var distanceFromCoinToTarget;

//DRAW7 GLOBAL VARIABLES
//INTIALIZE APPLE VALUES
var draggingApple = false;
var rolloverApple = false;
var appleX;
var appleY;
var appleW;
var appleH;
var offsetAppleX;
var offsetAppleY;

//DRAW8 GLOBAL VARIABLES
//INTIALIZE APPLE2 VALUES
var draggingApple2 = false;
var rolloverApple2 = false;
var apple2X;
var apple2Y;
var apple2W;
var apple2H;
var offsetApple2X;
var offsetApple2Y;

//DRAW9 GLOBAL VARIABLES
//CREATE EMMPTY ARRAY FOR BALLOONS
var balloons = [];
var bx;
var b; 
var by;


//DRAW10 GLOBAL VARIABLES
//LOAD IMAGES FOR FRAME ANIMATION, CREATE EMPTY ARRAY FOR IMAGES
//CREATE EMPTY ARRAY FOR RAINDROPS
var frames2 = [];
var filenames2 = [
    "assets/dance_1.png",
    "assets/dance_2.png",
    ];
var raindrops = []; 
var rx; 
var ry;


//LOAD BACKGROUND IMAGES FOR EACH PAGE
function setup() {
    createCanvas(480, 480);
    page1 = loadImage("assets/page_1.jpg");
    page2 = loadImage("assets/page_2.jpg");
    tomato = loadImage("assets/tomato.png");
    page3 = loadImage("assets/page_3.jpg");
    turn_page = loadImage("assets/turn_page.png");
    page4 = loadImage("assets/page_4.jpg");
    spoon = loadImage("assets/spoon.png");
    spoonX = 100;
    spoonY = 200;
    spoonW = 50;
    spoonH = 50;
    page5 = loadImage("assets/page_5.jpg");
    page6 = loadImage("assets/page_6.jpg");
    //PUSH IMAGES INTO EMPTY ARRAY
    for (var i = 0; i < filenames.length; i++) {
        frames.push(loadImage(filenames[i]));
    }
    //SET ANIMATION VARIABLES
    coinX = width / 2;
    coinY = height / 2;
    targetX = coinX;
    targetY = coinY;
    page7 = loadImage("assets/page_7.jpg");
    apple = loadImage('assets/apple.png');
    //SET APPLE POSITION
    appleX = 240;
    appleY = 355;
    appleW = 50;
    appleH = 50;
    page8 = loadImage("assets/page_8.jpg");
    //SET APPLE2 POSITION
    apple2X = 100;
    apple2Y = 355;
    apple2W = 50;
    apple2H = 50;
    page9 = loadImage("assets/page_9.jpg");
    //CREATE BALLOON OBJECTS
    for (var i = 0; i < 5; i++) {
        var bx = random(0, width);
        var b = random(50, 80);
        var by = height;
        balloons[i] = makeBalloon(bx, by, b);
    }
    page10 = loadImage("assets/page_10.jpg");
    //PUSH IMAGES INTO EMPTY ARRAY
    for (var i = 0; i < filenames2.length; i++) {
        frames2.push(loadImage(filenames2[i]))
    }
    //CREATE RAINDROP OBJECTS
    for (var i = 0; i < 5; i++) {
        var rx = random(0, width);
        var ry = 0;
        raindrops[i] = makeRaindrop(rx, ry);
    }
    frameRate(5);
}

//CLICK THROUGH PAGES WITH CLICK FUNCTIONS
function mouseClicked() {
    clickFunctions[page]();
}

//CALL PAGE FUNCTIONS
function draw() {
    drawFunctions[page]();
}

//OBJECT DRAGGING FUNCTIONS
function mousePressed() {
    //PAGE 4
    if (mouseX > spoonX & mouseX < spoonX + spoonW && mouseY > spoonY && mouseY < spoonY + spoonH) {
        draggingSpoon = true;
        offsetSpoonX = spoonX - mouseX;
        offsetSpoonY = spoonY - mouseY;
    }

    //PAGE 6 
    if (mouseX > appleX & mouseX < appleX + appleW && mouseY > appleY && mouseY < appleY + appleH) {
        draggingApple = true;
        offsetAppleX = appleX - mouseX;
        offsetAppleY = appleY - mouseY;
    }

    //PAGE 7
    if (mouseX > apple2X & mouseX < apple2X + apple2W && mouseY > apple2Y && mouseY < apple2Y + apple2H) {
        draggingApple2 = true;
        offsetApple2X = apple2X - mouseX;
        offsetApple2Y = apple2Y - mouseY;
    }       
}

//PAGE 1
//MAKE SUN JITTER, CLICK SUN TO MOVE TO NEXT PAGE
function draw1() {
    noStroke();
    background('white');
    image(page1, 0, 0, page1.width, page1.height);
    var sunPoints = sunX.length;
    fill(254, 192, 68);
    beginShape();
    for (var i = 0; i < sunPoints; i++) {
        var sunpX = sunX[i] + random(-2, 2);
        var sunpY = sunY[i] + random(-2, 2);
        vertex(sunpX, sunpY); 
    }
    endShape(CLOSE);
    ellipse(50, 53, 10, 10);
}

function click1() {
    if (mouseX < 60 & mouseX > 40 && mouseY < 60 && mouseY > 40) {
        page = 1;
    };
}


//PAGE 2
//MAKE TOMATOES JITTER, CLICK TOMATOES TO MOVE TO NEXT PAGE
function draw2() {
    noStroke();
    background('white');
    image(page2, 0, 0, page2.width, page2.height);
    if (tomatoFalling === true) {
        tomatoY1 += 10;
        tomatoY2 += 10;
    } else {
        tomatoY1 = random(350, 355);
        tomatoY2 = random(300, 305);
    }

    image(tomato, random(260, 265), tomatoY1, 30, 30);
    image(tomato, random(270, 275), tomatoY2, 30, 30);
    image(tomato, random(315, 320), tomatoY1, 30, 30);
    image(tomato, random(310, 315), tomatoY2, 30, 30);
    image(tomato, random(360, 365), tomatoY1, 30, 30);
    image(tomato, random(355, 360), tomatoY2, 30, 30);

    if (tomatoY1 > page2.height & tomatoY2 > page2.height) {
        page = 2;
    }
}

function click2() {
    if (mouseX < 365 & mouseX > 260 && mouseY > 300 && mouseY < 355) {
        tomatoFalling = true;
    }
}

//PAGE 3
//LOAD BACKGROUND IMAGE, CLICK PAGE TURN ANIMATION TO GO TO NEXT PAGE
function draw3() {
    noStroke();
    background('white');
    image(page3, 0, 0, page3.width, page3.height);
    image(turn_page, 430, 430, turn_page.width, turn_page.height);
}

function click3() {
    if (mouseX < 480 & mouseX > 400 && mouseY < 480 && mouseY > 400) {
        page = 3;
    }
}

//PAGE 4
//COMPLETE DRAGGING SPOON TO MOVE TO NEXT PAGE
function draw4() {
    noStroke();
    background('white');
    image(page4, 0, 0, page4.width, page4.height);

    if (mouseX > spoonX & mouseX < spoonX + spoonW && mouseY > spoonY && mouseY < spoonY + spoonH) {
        rolloverSpoon = true;
    }
    else {
        rolloverSpoon = false;
    }

    if (draggingSpoon) {
        spoonX = mouseX + offsetSpoonX;
        spoonY = mouseY + offsetSpoonY;
    }

    image(spoon, spoonX, spoonY, spoonW, spoonH);

    if (spoonX > 100 & spoonX < 200 && spoonY > 50 && spoonY < 100) {
        page = 4;
    }
}

function mouseReleased() {
    dragging = false;
}

function click4() {

}


//PAGE 5
//LOAD BACKGROUND IMAGE, CLICK PAGE TURN ANIMATION TO FLIP TO NEXT PAGE
function draw5() {
    noStroke();
    background('white');
    image(page5, 0, 0, page5.width, page5.height);
    image(turn_page, 430, 430, turn_page.width, turn_page.height);
}

function click5() {
    if (mouseX < 480 & mouseX > 400 && mouseY < 480 && mouseY > 400) {
        page = 5;
    }
}

//PAGE 6
//TOSS COIN INTO POND, USING FRAME ANIMATION, WHEN COIN REACHES POND, FLIP TO NEXT PAGE
function draw6() {
    noStroke();
    background('white');
    image(page6, 0, 0, page6.width, page6.height);

    dx = targetX - coinX;
    dy = targetY - coinY;
    distanceFromCoinToTarget = sqrt(dx*dx + dy*dy);

    coinX = lerp(coinX, targetX, 0.1);
    coinY = lerp(coinX, targetY, 0.1);

    if (targetX < coinX) {
        push();
        scale(-1, 1);
        image(frames[frameCount % frames.length], -coinX, coinY);
        pop();
    }
    else {
        image(frames[frameCount % frames.length], coinX, coinY);
    }

    if (coinY > 350) {
        page = 6;
    }
}

function click6() {
    targetX = mouseX;
    targetY = mouseY;
}

//PAGE 7
//DRAG APPLE TO LION, WHEN APPLE REACHES LION, FLIP TO NEXT PAGE
function draw7() {
    noStroke();
    background('white');
    image(page7, 0, 0, page7.width, page7.height);

    if (mouseX > appleX & mouseX < appleX + appleW && appleY > appleY && mouseY < appleY + appleH) {
        rolloverApple = true;
    }
    else {
        rolloverApple = false;
    }

    if (draggingApple) {
        appleX = mouseX + offsetAppleX;
        appleY = mouseY + offsetAppleY;
    }

    image(apple, appleX, appleY, appleW, appleH);

    if (appleX > 75 & appleX < 125 && appleY > 300 && appleY < 350) {
        page = 7;
    }
}

function click7() {

}

//PAGE 8
//DRAG APPLE FROM LION TO OWL, WHEN APPLE REACHES OWL, FLIP TO NEXT PAGE
function draw8() {
    noStroke();
    background('white');
    image(page8, 0, 0, page8.width, page8.height);

    if (mouseX > apple2X & mouseX < apple2X + apple2W && apple2Y > apple2Y && mouseY < apple2Y + apple2H) {
    rolloverApple2 = true;
    }
    else {
        rolloverApple2 = false;
    }

    if (draggingApple2) {
        apple2X = mouseX + offsetApple2X;
        apple2Y = mouseY + offsetApple2Y;
    }

    image(apple, apple2X, apple2Y, apple2W, apple2H);

    if (apple2X > 230 & apple2X < 300 && apple2Y > 150 && apple2Y < 200) {
        page = 8;
    }
}

function click8() {

}

//PAGE 9
//CREATE BALLOONS THAT RISE FROM THE BOTTOM OF THE SCREEN, WHEN 10 BALLOONS HAVE BEEN CREATED, MOVE TO NEXT PAGE
function draw9() {
    background('white');
    image(page9, 0, 0, page9.width, page9.height);

    updateAndDisplayBalloons();
    addNewBalloons();

    if (balloons.length > 10) {
        page = 9;
    }
}

function updateAndDisplayBalloons() {
    for (var i = 0; i < balloons.length; i++) {
        balloons[i].move();
        balloons[i].display();
    }
}

function addNewBalloons() {
    var newBalloonProb = .05;
    var b = random(50, 80);
    if (random(0, 1) < newBalloonProb) {
        balloons.push(makeBalloon(random(0, width), height, random(50, 80)));
    }
}

function balloonMove() {
    this.y -= this.speed;
}

function balloonDisplay(){
    push();
    if (this.typeColor < 1) {
        fill(255, 0, 0, 100);
    }
    if (this.typeColor > 1 & this.typeColor < 2) {
        fill(0, 0, 255, 100);
    }
    if (this.typeColor > 2 & this.typeColor < 3) {
        fill(128, 0, 128, 100);
    }
    ellipse(this.x, this.y, this.breadth/1.5, this.breadth);
    stroke('black');
    strokeWeight(1);
    line(this.x, this.y + this.breadth/2, this.x, this.y + 100);
    
    pop();
}

function makeBalloon(bx, by, b) {
    var balloons = {x: bx, y: by, move: balloonMove, display: balloonDisplay, speed: 5, breadth: random(50, 80), place: random(50, 250), type: int(random(0, 3)), typeColor: random(0, 3)}
    return balloons;
}

function click9() {

}

//PAGE 10
//CREATE RAINDROPS FALLING FROM TOP OF CANVAS
//USE FRAME ANIMATION TO MAKE ANIMALS DANCE 
function draw10() {
    background('white')
    image(page10, 0, 0, page10.width, page10.height);

    image(frames2[frameCount % frames2.length], 0, 180);

    updateAndDisplayRaindrops();
    addNewRaindrops();
}

function updateAndDisplayRaindrops() {
    for (var i = 0; i < raindrops.length; i++) {
        raindrops[i].move();
        raindrops[i].display();
    }
}

function addNewRaindrops() {
    var newRaindropProb = .25;
    if (random(0, 1) < newRaindropProb) {
        raindrops.push(makeRaindrop(random(0, width), 0));
    }
}

function raindropsMove() {
    this.y += this.speed;
}

function raindropsDisplay(){
    push();
    fill(135, 206, 250, 100);
    beginShape();
    curveVertex(this.x, this.y);
    curveVertex(this.x-5, this.y+15);
    curveVertex(this.x, this.y+20);
    curveVertex(this.x+5, this.y+15);
    curveVertex(this.x, this.y);
    endShape(CLOSE);
    pop();
}

function makeRaindrop(rx, ry) {
    var raindrops = {x: rx, y: ry, move: raindropsMove, display: raindropsDisplay, speed: 5, place: random(50, 250)}
    return raindrops;
}

function click10() {

}

//END

Project Priors + Inspiration

For my project proposal, I am creating an animated children’s book. I have found two interactive stories that, while more advanced, have really interesting levels of interactivity.

The first project is “ENOUGH” by Isaac Cohen. This project is an animated story that loads as the user clicks the logo. I find this project really interesting because of its high level of interactivity from the words moving with the mouse and the jellyfish-like creature following the mouse.

ENOUGH

The second project is “a short journey” directed by Cher Ami. I appreciate this project for its very direct animation and creative use of interactivity. As each screen loads there is a “drag here” button that the user pulls across a line to begin the animation. For example the one on the right, zips the bag. When the animation ends, it moves to the next page.The aesthetic of this animation is truly beautiful.

a short journey

While both projects, are graphically quite different, they both grab the user and pull them into the story, through quite simple (to the user) animations. It’s really exciting to see how this concept can be produced and animated in such different ways.

cmhoward-project12-finalproposal

For my project, I am proposing an animated children’s book. Each time the user clicks the arrow, it will move to a new page of the book. I am proposing that each page has one animation triggered by the user clicking on highlighted text. An animation could be the sun moving, plants growing, or rain falling.

The story is about a lion who is a farmer and his plants are dying in the hot sun so he needs to figure out how to make it rain. After interacting with a few other animals, he finally realizes he has to dance to make it rain (subject to change!)

I am still considering whether the majority of the animation will be hand coded in p5.js or if that will be specifically for the animated objects. It depends on how complicated the final storyline becomes. It may be easier to do a hybrid where the static objects are drawn and the animated objects are coded.

I believe this project will help me learn more about interactivity and animation within p5.js. I am excited to see how this process goes!

Beyond the Fence

Beyond the Fence is the world’s first computer generated musical, created by Benjamin Till and a team of researchers.

Not only is 25% of the music and lyrics computer generated, but aspects of the production such as the setting and size of the cast were based on algorithms as well. Using an algorithm that sorts through over 2,000 musicals, they determined the characteristics of the best musicals and applied those to the premise of the musical. After computing these aspects of the plot, they team filled “in the dots.”

There’s a hint of Romeo and Juliet (or should that be West Side Story?) to the burgeoning relationship between Mary and Jim, a touch of Miracle on 34th Street to the George subplot, and the idea of a band of women taking a stand against oppressors has been rehearsed in the West End as recently as last year’s short-lived musical staging of Made in Dagenham.

This project is extremely interesting because most modern arguments suggest the computer will never be as creative as the human, especially concerning emotional factors, but this project applied creativity in a useful way. After computing the aspects of the plot, the team filled “in the dots.” With most computer generated work, there is a layer of human decision making (even going back to the creation of the algorithm) so things such as the dialogue and blending the lyrics from the poetry generator were created at the hands of the team. Somewhat relying on the machine to inspire their own creativity. With the advantageous use of these algorithms, the reliance on the “What-If Machine” allowed the team to use their talents elsewhere and fall prey to the surprising output of the machine.

The music was created with the algorithmic composing software, Android, the plot-generating script, PropperWryter, and lyric-generating, Clarissa the Cloud Lyricist, with their own software the “What-If Machine.” It was a collective effort of many collaborators and creators to fully realize this computational musical.

This project as a reference for sound art, is quite inspiring to go past the so-called restrictions of machine-learning and computer generated software’s to create something brand new, yet realistic and familiar. It would be really interesting to see what would happen if these algorithms ran throughout the musical, constantly changing its plot and premise- almost like an improv.

Read more about the project here & here!

cmhoward-project11-composition

cmhoward-week-11

var sq1StartWidth = 90;
var sq1StartHeight = 50;
var sq2StartWidth = 375;
var sq2StartHeight = 100;
var sq3StartWidth = 135;
var sq3StartHeight = 150;
var sq4StartWidth = 425;
var sq4StartHeight = 200;
var sq5StartWidth = 240;
var sq5StartHeight = 350;
var sq1length;
var sq2length;
var sq3length;
var sq4length;
var sq5length;

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

function draw() {
    background(0);
    // var mx = constrain(mouseX, 0, width - sq2length);
    // var my = constrain(mouseY, 0, height - sq2length);
    // sq1StartWidth = mx - sq1length;
    // sq1StartHeight = my - sq1length;
    // sq2StartWidth = mouseX + (mx/2);
    // sq2StartHeight = mouseY + (my/2);
    sq1length = map(mouseX, 0, width, 10, 50);
    sq2length = map(mouseX, 0, width, 10, 50);
    sq3length = map(mouseX, 0, width, 20, 40);
    sq4length = map(mouseX, 0, width, 75, 25);
    sq5length = map(mouseX, 0, width, 50, 60);
    square_1();
    square_2();
    square_3();
    square_4();
    square_5();
    lines();
}

function square_1() {
    square1 = makeTurtle(sq1StartWidth, sq1StartHeight);
    square1.color = ('white');
    square1.penDown();
    square1.face(90);
    square1.forward(sq1length);
    square1.right(90);
    square1.forward(sq1length);
    square1.right(90);
    square1.forward(sq1length);
    square1.right(90);
    square1.forward(sq1length);
    square1.penUp();
}

function square_2() {
    square2 = makeTurtle(sq2StartWidth, sq2StartHeight);
    square2.color = ('white');
    square2.penDown();
    square2.face(90);
    square2.forward(sq2length);
    square2.right(90);
    square2.forward(sq2length);
    square2.right(90);
    square2.forward(sq2length);
    square2.right(90);
    square2.forward(sq2length);
    square2.penUp();
}

function square_3() {
    square3 = makeTurtle(sq3StartWidth, sq3StartHeight);
    square3.color = ('white');
    square3.penDown();
    square3.face(90);
    square3.forward(sq3length);
    square3.right(90);
    square3.forward(sq3length);
    square3.right(90);
    square3.forward(sq3length);
    square3.right(90);
    square3.forward(sq3length);
    square3.penUp();
}

function square_4() {
    square4 = makeTurtle(sq4StartWidth, sq4StartHeight);
    square4.color = ('white');
    square4.penDown();
    square4.face(90);
    square4.forward(sq4length);
    square4.right(90);
    square4.forward(sq4length);
    square4.right(90);
    square4.forward(sq4length);
    square4.right(90);
    square4.forward(sq4length);
    square4.penUp();
}

function square_5() {
    square5 = makeTurtle(sq5StartWidth, sq5StartHeight);
    square5.color = ('white');
    square5.penDown();
    square5.face(90);
    square5.forward(sq5length);
    square5.right(90);
    square5.forward(sq5length);
    square5.right(90);
    square5.forward(sq5length);
    square5.right(90);
    square5.forward(sq5length);
    square5.penUp();
}

function lines() {
    line(sq1StartWidth, sq1StartHeight, sq2StartWidth, sq2StartHeight);
    line(sq1StartWidth, sq1StartHeight + sq1length, sq2StartWidth, sq2StartHeight + sq2length);
    line(sq1StartWidth - sq1length, sq1StartHeight, sq2StartWidth - sq2length, sq2StartHeight);
    line(sq1StartWidth - sq1length, sq1StartHeight + sq1length, sq2StartWidth - sq2length, sq2StartHeight + sq2length)   

    line(sq3StartWidth, sq3StartHeight, sq2StartWidth, sq2StartHeight);
    line(sq3StartWidth, sq3StartHeight + sq3length, sq2StartWidth, sq2StartHeight + sq2length);
    line(sq3StartWidth - sq3length, sq3StartHeight, sq2StartWidth - sq2length, sq2StartHeight);
    line(sq3StartWidth - sq3length, sq3StartHeight + sq3length, sq2StartWidth - sq2length, sq2StartHeight + sq2length)   

    line(sq3StartWidth, sq3StartHeight, sq4StartWidth, sq4StartHeight);
    line(sq3StartWidth, sq3StartHeight + sq3length, sq4StartWidth, sq4StartHeight + sq4length);
    line(sq3StartWidth - sq3length, sq3StartHeight, sq4StartWidth - sq4length, sq4StartHeight);
    line(sq3StartWidth - sq3length, sq3StartHeight + sq3length, sq4StartWidth - sq4length, sq4StartHeight + sq4length) 

    line(sq5StartWidth, sq5StartHeight, sq4StartWidth, sq4StartHeight);
    line(sq5StartWidth, sq5StartHeight + sq5length, sq4StartWidth, sq4StartHeight + sq4length);
    line(sq5StartWidth - sq5length, sq5StartHeight, sq4StartWidth - sq4length, sq4StartHeight);
    line(sq5StartWidth - sq5length, sq5StartHeight + sq5length, sq4StartWidth - sq4length, sq4StartHeight + sq4length)     
}

function turtleLeft(d){this.angle-=d;}function turtleRight(d){this.angle+=d;}
function turtleForward(p){var rad=radians(this.angle);var newx=this.x+cos(rad)*p;
var newy=this.y+sin(rad)*p;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,d){var angle = this.angleTo(x,y);if(angle< 180){
this.angle+=d;}else{this.angle-=d;}}function turtleSetColor(c){this.color=c;}
function turtleSetWeight(w){this.weight=w;}function turtleFace(angle){
this.angle = angle;}function makeTurtle(tx,ty){var turtle={x:tx,y:ty,
angle:0.0,penIsDown:true,color:color(128),weight:1,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;}

For this project, I wanted to explore creating animated geometric forms. With turtle graphics, there are a lot of variables that one can easily explore with easier access so this was the perfect excuse to turn a doodle I always do into an actual project. Doodles below…

While these are more complex, they are based on the same principle of connecting squares and rectangles which was the basis for my project.

Hyphen-Labs

Hyphen-Labs is an international team of women of color working at the intersection of technology, art, science, and the future.”

I remember looking at this collective when researching the Eyeo Festival artists. I wanted to go back to them and learn more about their work as a product of collaborative work between women.

The project below, Prismatic_NYC, is a kinetic sculpture above the The High Line in New York City.

Prismatic_NYC_BTS from hyphen_labs on Vimeo.

The project contains 66 individual prisms, inspired by the Trivision billboard which consists of triangular prisms rotating to form 3 different images on each face. To generate a nostalgic feeling, and create a new system, Hyphen-Labs tapered each prism and alternated their orientation. Using light and movement, they can completely control the experience of being under this installation.

The performance of Prismatic_NYC can also be programmed and controlled in response to current weather conditions such as cloud cover, wind speed, humidity, and accumulation. These directly change the amplitude, frequency, speed and position offset of the wave form. It is always changing and never the same.

Using generative and parametric design, they were able to optimize the experience of being under this project. This project will be installed for 5 years.

Another project of interest is Painkillers, in collaboration with the National Safety Council and Energy BBDO. This installation features 22,000 pills carved with human faces representing the 22,000 people who died from opioid addiction last year. This rate is continuing to increase, and as an addition to the installation, it continues to carve a new pill every 24 minutes. Using a small mechanical system, they are able to get very precise details on small objects.

Stop Everyday Killers

Carving_in process

Hyphen-Labs, as a collective of women, has the sensitivity and awareness to tackle important social issues through art, computation, and technology. I can’t wait to see what they, and many other women, do next.

**Using grace day 1/3.**

cmhoward-project10-landscape

cassie-week10

var colorFill;
var pictures = []; //empty picture array 
var next = 0;
var maxX;

function setup() {
    createCanvas(480, 480);
    frameRate(100);
    //background fill
    colorFill = random(150, 255);

    //implement pictures in empty array, also check to make sure they are not within the boundary of another picture
    for (var i = 0; i < 10; i++) {
        var done = false;
        var px = next + random(10, 50);
        var b = random(50, 150);
        next = px + b
        maxX = next 
        pictures[i] = makePicture(px, b)
    }
}

function draw() {
    background(colorFill);
    updateAndDisplayPictures();
    removePictures();
    addNewPictures();
    makeBorder();
}

function updateAndDisplayPictures() {
    //detect border of pictures
    maxX = 0
    for (var i = 0; i < pictures.length; i++) {
        pictures[i].move();
        pictures[i].display();
    }
}

function removePictures() {
    var picturesToKeep = [];
    for (var i = 0; i < pictures.length; i++) {
        if (pictures[i].x + pictures[i].breadth > 0) {
            picturesToKeep.push(pictures[i]);
        }
    }
    pictures = picturesToKeep;
}

function addNewPictures() {
    var newPicturesProb = 0.01;
    //set breadth of image, detect border of picture
    var b = random(50, 150);
    if (random(0, 1) < newPicturesProb) {
        if (maxX < width) {
            pictures.push(makePicture(width, b));
        }   
    }
}

function pictureMove() {
    this.x += this.speed;
}

function pictureDisplay() {
    stroke(153, 76, 0);
    push();
    //random frame size 
    strokeWeight(this.frame);
    //random picture background
    fill(this.fill);
    //move frames across canvas
    translate(this.x, height - 150);
    //create frames 
    rect(0, -this.place, this.breadth, this.height);
    //give object in picture color
    if (this.typeColor < 1) {
        fill('red');
    }
    if (this.typeColor > 1 & this.typeColor < 2) {
        fill('blue');
    }
    if (this.typeColor > 2 & this.typeColor < 3) {
        fill('yellow');
    }
    //select object shape
    if (this.type == 0) {
        noStroke();
        ellipse(this.breadth/2, -this.place + this.height/2, this.breadth/4, this.height/4)
    }
    if (this.type == 1) {
        noStroke();
        rectMode(CENTER);
        rect(this.breadth/2, -this.place + this.height/2, this.breadth/4, this.height/4)
    }
    if (this.type == 2) {
        noStroke();
        triangle(this.breadth/2, -this.place + this.height/2, this.breadth/2 + this.breadth/4, -this.place + this.height/2 + this.height/4, this.breadth/2 - this.breadth/4, -this.place + this.height/2 + this.height/4)
    }
    pop();

    //check to make sure picture is not overlapping with another 
    if (this.x + this.breadth > maxX) {
        maxX = this.x + this.breadth 
    }
}

//create picture object 
function makePicture(px, b) {
    var pictures = {x: px, move: pictureMove, display: pictureDisplay, speed: -1, breadth: b, height: random(50, 150), place: random(50, 250), frame: random(3, 10), fill: random(50, 255), type: int(random(0, 3)), typeColor: random(0, 3)}
    return pictures; 
}

//create borders at top and bottom of screen to imitate baseboards 
function makeBorder() {
    noStroke();
    fill(255 - colorFill);
    rect(0, 0, width, 20);
    rect(0, height - 20, width, 20);
}

For this project, I was inspired by a museum gallery wall where you walk through a room of framed paintings, photographs, etc. and it creates a landscape of art.

I used this sketch to begin my project. I wanted to randomize the size of the art, the size of the frame, and the colors of the wall, border, and painting. Adding in the small abstract shapes to the paintings increases the randomness of the landscape. Because all of these are in flux, it creates a compelling composition of objects in space.

Trying to define the boundaries of these objects so that they wouldn’t overlap was quite challenging, but I learned a lot more about objects and conditions through this process.

Meejin Koon // Howeler + Yoon Architecture

For this week’s blog post, I am taking a deeper dive into the Howeler + Yoon Architecture firm from Min Lee’s Week 8 Looking Outwards on Meejin Yoon.

I actually had the pleasure of seeing 2 of their projects on a studio trip to Boston last summer. One project I really want to highlight from this firm is the Collier Memorial on MIT’s campus.

Sean Collier Memorial, MIT, Boston, Howeler + Yoon

This project is a memorial to an officer, Sean Collier, that was shot and killed in 2013. As most memorials result in statues, plaques, benches, etc. I remember being completely inspired by this project’s ambition, structure, and integration into the public landscape.

Now looking further into this project, and learning more about the firm from Meejin Yoon, I have learned that the entire design and structural analysis utilizes computational design. I believe the project mainly utilizes Rhino 3D Modeling Software and Grasshopper, a Rhino plug-in for computational and parametric design.

Computational model of Memorial

The structure being constructed of 32 granite blocks presents new challenges that are wouldn’t be the same for something like poured in place concrete. So for this project, not only was the design computational, but the actual fabrication of these pieces used a combination of manual labor and robotic sawing.

Fabrication of memorial at Quarra Stone Co., in Madison, Wis.

What I really appreciated in Min Lee’s piece is the emphasis on the idea of public/private space. With the Collier memorial, the project has transformed a public area to create new spaces for the public to interact with, rather than look at or observe. This firm is really combining their design goals with the right tools and software to make them happen.

cmhoward-project-08

click me!

cmhoward-09

var img;

//decalre initial gridsize
var gridSize = 50

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

function setup() {
    createCanvas(600, 600);
    background(0);
    img.loadPixels();
    frameRate(500);
}

function draw() {
    for (var x = 0; x < width; x += gridSize) {
        for (var y = 0; y < height; y += gridSize) {
            //rectangle color
            var theColorAtLocationXY = img.get(x, y);
            fill(theColorAtLocationXY);
            noStroke();
            //array squares in grid
            rect(x, y, gridSize, gridSize);
        }
    }
}

function mouseClicked() {
    //make grid size smaller when user clicks
    gridSize -= 1
    //reset gridSize
    if (gridSize < 5) {
        gridSize = 50;
    }
}

For this project, I wanted to create a pixel grid that becomes smaller and thus, clearer as the user clicks!

The  beginning image:

The final rendering:

I wanted the image to stop at a certain resolution so it maintains the pixelation effect, so it resets after a certain amount of clicks.

FashionTech by Anouk Wipprecht

Anouk Wipprecht is a Dutch, female artist working in the field of Couture Fashion, but at the intersection of analog design and robotics.

Eyeo 2016 – Anouk Wipprecht from Eyeo Festival on Vimeo.

Anouk Wipprecht is such an inspiring artist because she is truly pushing the boundaries of her field. She has defined these two fields of interest to her, fashion and robotics, and exploits them to create a new bias in her designs. She sees her designs as living systems that “move, breathe, and react to the space around them.”

One of the most interesting projects to me is the Spider Dress, which “attacks when you come close to it.” Anouk has been especially interested in defining these spaces of interaction with fasion, i.e the tiers of space around our bodies.

Diagram, Anouk Wipprecht

Attached to the shoulders are robotic arms which expand from this boundary of personal space into the social space as people approach the dress and model.

Spider dress, Anouk Wipprecht

Link to video of dress here!

What I love about this artist is her actual deployment of these intersectional ideas. There exists a conceptual level of her work which influences the development of her work and eventual fabrication. At each of these levels, the others don’t fault.

“FashionTech” is defined as “a rare combination of fashion design combined with engineering, science and interaction/user experience design.” The idea of fashion, as more than a garment, that exists on our bodies, in the space around us, and as a response to the environment we exist in is such a holistic approach to an everyday idea we take for granted.

Read more about the artist here!