Final Project Windy Day Gardening – Simin Li

It is a windy day. Let’s plant some things! Add water and fertilizer to make the plant grow. Fertilizer makes the plant grow faster!

screen-shot-2016-12-09-at-5-48-16-pm

Harvest when you are finished growing. screen-shot-2016-12-09-at-5-41-09-pm

finalproject

// Simin Li
// Section C
// siminl@andrew.cmu.edu
// Final Project 

var tree = [];
var woodlength;
var branchStemX = 340;
//x pos of plant branch stem
var branchStemY = 600;
//y pos of plant branch stem
var fruitAmount = 1;
var fruitSize = 19;
var harvested = 0;
var harvestButton;
var picking = false;
var waterButton;
var watering = false;
var fertilizeButton;
var fertilizing = false;
var wateringCan;
var hand;
var plum;
var leaf;
var compost;
var seedling; 
//image names
var count;
//keep track of times a button is clicked
var branchDirection = 1;
//the direction of the recursion tree
var matureness = 9;
//levels of recursion tree

function preload(){
    wateringCan = loadImage("http://i.imgur.com/JNvlZzy.png");
    hand = loadImage("http://i.imgur.com/7r9pIdV.png");
    plum = loadImage("http://i.imgur.com/JEh9AIh.png");
    leaf = loadImage("http://i.imgur.com/MDoduCh.png");
    compost = loadImage("http://i.imgur.com/Rut3lp4.png");
    seedling = loadImage("http://i.imgur.com/BG0X2wj.png");
    //preload self drawn images
}

function setup() {
    createCanvas(680, 680);
    frameRate(7);

    harvestButton = createButton('harvest');
    harvestButton.position(65, 65);
    harvestButton.mousePressed(pick);
    //create a button that allows you to harvest fruit

    waterButton = createButton('water');
    waterButton.position(65, 85);
    waterButton.mousePressed(water);
    //create a button that allows you to water the plant

    fertilizeButton = createButton('fertilize');
    fertilizeButton.position(65, 105);
    fertilizeButton.mousePressed(fertilize);
    //create a button that allows you to fertilize the plant

    background(240);
}

function draw() {

    noStroke();
    fill("SkyBlue");
    rect(0,0,680,600);
    //render sky
    dirt();
    //render soil
    fill(247,197,51);
    ellipse(width - 90, 90, 160,160);
    //render sun
    push();
        translate(width / 4, height - 80);
        recursionBranch(matureness, 60, 9);
    pop();
    push();
        translate(width * 3 / 4, height - 80);
        recursionBranch(matureness, 60, 9);
    pop();
    //render background recursion trees
    var outcome = "The number of fruit harvested is " + harvested + ".";
    textAlign(CENTER);
    fill(255);
    textSize(16);
    text(outcome,width * 4 / 5 , height - 15);
    //display the number of fruit harvested 
    for(var i = 0; i < tree.length; i ++){
        tree[i].draw();
        stroke(42,27,21);
        strokeWeight(6);
        line(340, 600, 340,tree[i].branchY);

    }
    //render whole plant
    image(seedling, 265, 550, seedling.width * 0.15, seedling.height * 0.15);
    if(picking){
    //if the harvest button is pressed change cursor to hand
        noCursor();
        image(hand, mouseX - 71, mouseY - 15, hand.width * 0.2, hand.height * 0.2);
        //shift the new cursor a bit so the finger tip and arrow can align
        }
    else if(watering){
    //if the harvest button is pressed change cursor to watering can
        noCursor();
        image(wateringCan, mouseX - 50, mouseY - 90, wateringCan.width * 0.3, wateringCan.height * 0.3);
    }
    else if(fertilizing){
    //if the harvest button is pressed change cursor to manure
        noCursor();
        image(compost, mouseX , mouseY , compost.width * 0.3, compost.height * 0.3);
    }
    else{
        cursor();
    }
}
function drawBranch(){
    stroke(42,27,21);
    strokeWeight(4);
    var tipX = this.branchX + this.brachDirection * this.branchLength * cos(this.angle);
    var tipY = this.branchY - this.branchLength * sin(this.angle);
    line(this.branchX,this.branchY,tipX,tipY);
    if(this.fruit){
        //if there is fruit, render fruit
        ellipseMode(RADIUS);
        ellipseMode(CENTER);
        fill(124,23,22);
        noStroke();
        image(plum, this.fruitX - plum.height / 6, this.fruitY - plum.height / 12, plum.width / 3,plum.height / 3);
    }
    for(var n = 0; n < this.leafNumber; n ++){
        push();
            translate(this.leaves[n][0],this.leaves[n][1]);
            rotate(this.leaves[n][2]);
            noStroke();
            fill(92,190,66);
            image(leaf, 0, 0, leaf.width / 2,leaf.height / 2);
        pop();
    }
    //render leaves
}
function makeBranch(length,x,y){
    if ((y / 30) % 2 === 0){
        var direction = - 1;
    } 
    else{
        direction = 1;
    }
    //alternate branch directions
    var branchAngle = random(0, PI / 3);
    //randomize the angle of branch
    var leafNumber = Math.floor(random(2, 6));
    //randomize the number of leaves on each branch
    var leaves = [];
    for(var m = 0; m < leafNumber; m ++){
        var leafPosition = random(0,length);
        leafX = x + direction * leafPosition * cos(branchAngle);
        leafY = y - leafPosition * sin(branchAngle);
        leafRotation = direction * random(-TWO_PI, TWO_PI);
        leaves[m] = [leafX, leafY, leafRotation];
    }
    //store leaf information in an array
    var branches = [];
    var s = {
        brachDirection: direction,
        branchX: x,
        branchY: y,
        angle: branchAngle,
        branchLength: length,
        fruit: true,
        fruitX: x + direction * length * cos(branchAngle),
        fruitY: y - length * sin(branchAngle),
        leafNumber: leafNumber,
        leaves: leaves,
        branches: branches,
        draw: drawBranch
    }
    return s;
}

function mousePressed() {
    // fruitAmount = floor(random(0,3));
    count += 1;
    if(branchStemY > 100){
        if(watering & (count > 1)){
            branchStemY -= 30;
            //grow by 30
            woodlength = random(70,130);
            //randomize length of branch 
            tree.push(makeBranch(woodlength,branchStemX,branchStemY));
            //push branches on to the array tree
        }
        if(fertilizing & (count > 1)){
            branchStemY -= 30;
            woodlength = random(100,150);
            //randomize length of branch (fertilizer causes more length)
            tree.push(makeBranch(woodlength,branchStemX,branchStemY));
            //push branches on to the array tree
        }
    }
    if(picking){
        for(var j = 0; j < tree.length; j++){
            if(tree[j].fruit){
                if(dist(mouseX,mouseY,tree[j].fruitX,tree[j].fruitY) <= fruitSize){
                    tree[j].fruit = false;
                    //do not display picked fruit
                    harvested += 1;
                    //update the amount of fruit harvested
                }
            }
        }
    }
}
function recursionBranch(depth, len, thickness) {
//creates recursive tree with complexity of depth, size of len and boldness of thickness
    strokeWeight(thickness);
    stroke(50,45,39);
    line(0, 0, 0, -len);
    //render trunk
    push();
        translate(0, -len);
        if (depth > 0) {
            if (depth > 5 ) {
            //when complexity is low, thickness decreases faster
                rotate(radians(-25));
                recursionBranch(depth - 1, len * random ((6 / 7), (8 / 9)),thickness * (3/ 4));
                rotate(radians(50));
                recursionBranch(depth - 1, len * random ((6 / 7), (8 / 9)),thickness * (3/ 4));
            }
            else {
            //when complexity is low, thickness decreases slower
                if(random(1) < 0.75){
                //most of the time create one branch
                    if(branchDirection === -1){
                        rotate(radians(random(-10,-20)));
                        recursionBranch(depth - 1, len * random ((6 / 7), (3 / 4)),thickness * (6 / 7));
                        branchDirection *= -1;
                        //alternate branch direction
                    }
                    else{
                        rotate(radians(random(10,20)));
                        recursionBranch(depth - 1, len * random ((6 / 7), (3 / 4)),thickness * (6 / 7));
                        branchDirection *= -1;
                        //alternate branch direction
                    }
                }
        else{
        //occasionally create two branches
            rotate(radians(-14));
            recursionBranch(depth - 1, len * random ((6 / 7), (3 / 4)),thickness * (6/ 7));
            rotate(radians(28));
            recursionBranch(depth - 1, len * random ((6 / 7), (3 / 4)),thickness * (6/ 7));
            }
        }
    }
    pop();
}
function dirt(){
    //render dirt
    noStroke();
    fill(90,80,60);
    rect(0,600,680,80);
    image(seedling, 290, 570, seedling.width * 0.1, seedling.height * 0.1);
}
function pick(){
//set to picking mode
    picking = true;
    watering = false;
    fertilizing = false;
}

function water(){
//set to watering mode
    watering = true;
    picking = false;
    fertilizing = false;
    count = 0;
    
}

function fertilize(){
//set to fertilizing mode
    fertilizing = true;
    watering = false;
    picking = false;
    count = 0;
}

For the final project, I wanted to make an interactive plant. I have always loved gardening games because of the joy of harvesting decided to make one myself. The number and distribution of leaves and fruit are generated randomly . The extent to which the plant grows will depend on how many times it is watered and fertilized . After you have decided to stop watering, it is harvesting season. The player clicks on a button called “Harvest” and  can harvest the fruit by clicking on the fruit and the number of fruit harvested will be displayed on the screen. I also incorporated hand drawn elements in the project to make it more visually pleasing. I scanned the images and uploaded them to imgur to use them in my project.

Looking Outwards 12 – Simin Li

I chose two projects as reference for my final project.

Extinct by Joe Cutting
Extinct by Joe Cutting
Extinct by Joe Cutting
Extinct by Joe Cutting
Extinct by Joe Cutting
Extinct by Joe Cutting

Extinct is an educational game that allows players to plant either a wild plant or a farm crop by Joe Cutting. The goal of the game is to grow as many seeds as possible through deciding how much water, minerals and sunlight to distribute to growing different parts of the plant. The more seeds you get, the higher your survival rate. The game is interesting in that you have control over your plant and it makes use of scientific knowledge that gives the player something more to take away from the game. Something I wish Cutting did better is that the window is too small for the plant. When the plant gets really tall it goes out of view. The slider bars are also a bit too long.

fake flower by W:Mute
fake flower by W:Mute
fake flower by W:Mute
fake flower by W:Mute
121 Fake Flowers by W:Mute
121 Fake Flowers by W:Mute

121 Fake Flowers by W:Mute is a series of 121 computer generated flowers. The artist uses processing to make the flowers and they are all in black and white. What is interesting about the project is that all the flowers have a crystal like structure. Unlike the first project, this is only a simulator of flowers. I thought this project was worth investigating because it could help me generate the leaves and fruit in my game. Is seems that this project has differentiated the petals and the pistils. When I generate my plant I should generate stems and leaves individually. If this project could include more variability, it would be even more interesting.

Links:

About

Joe Cutting

Play Extinct

Final Project Proposal – Simin Li

For the final project, I want to make an interactive animation. I have always loved gardening games because of the joy of harvesting and would like to make one myself. The player would be asked to plant one seed in the soil. Then with each attempt to water the plant the seed would grow leaves and eventually fruit of their own. The number and distribution of leaves and fruit would be generated randomly while following the rules of nature like having more leaves than fruit and not cramming too many leaves on one branch. The extent to which the plant grows will depend on how many times it is watered, but watering the plant too much would cause a sudden and unexpected death. The amount of times of watering that would kill the plant is random and different each time. So it is kind of like a betting game: you want to water the plant as much as possible, but it is up to the player to decide when it might be dangerous to keep watering. Keep your current plant or have a dead one. After you have decided to stop watering, it is harvesting season. The player clicks on a button called “Harvest!” and  can harvest the fruit by clicking on the fruit and the number of fruit harvested will be displayed on the screen.

file_000

Project 11 – Simin Li

siminl-project11

// Simin Li
// Section C
// siminl@andrew.cmu.edu
// Project 11
var seaTurtle;
//create a turtle
function setup() {
    createCanvas(600, 400);
    background(21,40,71);
    seaTurtle = makeTurtle(300,200);
    //make a turtle
}
function draw(){
    strokeJoin(MITER);
    strokeCap(PROJECT);
    for(var i = 0; i < 6; i++){
        seaTurtle.penUp();
        seaTurtle.right(60);
        seaTurtle.forward(random(70,200));
        var snowFlakeSize = random(1,8);
        snowFlake(snowFlakeSize);
    }
}

function mouseReleased() {
//when mouse is clicked, redraw 6 snowflakes according to the mouse position
  seaTurtle.penUp();
  seaTurtle.goto(mouseX,mouseY);
  println(mouseX);
  for(var i = 0; i < 6; i++){
  //draw six snowflakes
        seaTurtle.penUp();
        seaTurtle.right(60);
        seaTurtle.forward(random(70,200));
        //randomize how far apart each snowflake is from each other
        var snowFlakeSize = random(1,10);
        //randomize the size of the snowflakes
        snowFlake(snowFlakeSize);
    }
}
function snowFlake(a){
    seaTurtle.penDown();
//draw snow flake with dimension of a 
    if(a < 5){
    //if a is smaller than 5 fill it with white
    seaTurtle.setColor(255);
    }
    else{
    //else fill it with a randomized shade of blue
        seaTurtle.setColor(color(random(0,100),random(100,255),255));
    }
    for(var i = 0; i < 6; i ++){
        patternA(a);
    }
    noLoop();

}
    
function patternA(a){
    //draw branch of snowflake with dimension a
    seaTurtle.penDown();
    seaTurtle.setWeight(a / 5);
    //determine line weight according to the size
    seaTurtle.left(30);
    seaTurtle.forward(5 * a);
    seaTurtle.left(60);
    seaTurtle.forward(3 * a);
    seaTurtle.left(45);
    seaTurtle.forward(4 * a);
    seaTurtle.right(45);
    seaTurtle.forward(a / sqrt(2));
    seaTurtle.right(90);
    seaTurtle.forward(a / sqrt(2));
    seaTurtle.right(45);
    seaTurtle.forward(3 * a);
    seaTurtle.left(135);
    seaTurtle.forward(2 * a);
    seaTurtle.left(45);
    seaTurtle.forward(4 * a);
    seaTurtle.right(45);
    seaTurtle.forward(a / sqrt(2));
    seaTurtle.right(90);
    seaTurtle.forward(a / sqrt(2));
    seaTurtle.right(45);
    seaTurtle.forward(3 * a);
    seaTurtle.left(135);
    seaTurtle.forward(2 * a);
    seaTurtle.left(30);
    seaTurtle.forward(2 * a);
    seaTurtle.right(60);
    seaTurtle.forward(2 * a);
    seaTurtle.right(60);
    seaTurtle.forward(2 * a);
    seaTurtle.right(60);
    seaTurtle.forward(2 * a);
    seaTurtle.right(60);
    seaTurtle.forward(2 * a);
    seaTurtle.left(30);
    seaTurtle.forward(2 * a);
    seaTurtle.left(135);
    seaTurtle.forward(3 * a);
    seaTurtle.right(45);
    seaTurtle.forward(a / sqrt(2));
    seaTurtle.right(90);
    seaTurtle.forward(a / sqrt(2));
    seaTurtle.right(45);
    seaTurtle.forward(4 * a);
    seaTurtle.left(45);
    seaTurtle.forward(2 * a);
    seaTurtle.left(135);
    seaTurtle.forward(3 * a);
    seaTurtle.right(45);
    seaTurtle.forward(a / sqrt(2));
    seaTurtle.right(90);
    seaTurtle.forward(a / sqrt(2));
    seaTurtle.right(45);
    seaTurtle.forward(4 * a);
    seaTurtle.left(45);
    seaTurtle.forward(3 * a);
    seaTurtle.left(30);
    //draw pattern A
}

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 use turtles to draw a complex shape that would be otherwise difficult to achieve through other methods. The shape of a snowflake seemed beautiful and intriguing to me. 
screen-shot-2016-11-11-at-4-18-42-pm

file_000

screen-shot-2016-11-11-at-4-17-54-pm

Looking Outwards 11- Simin Li

collinstorino
Nicolas Collins In Memoriam Michel Waisvisz in Italy, March 20, 2013 Photo: Stefano Bassanese

In Memoriam Michel Waisvisz was a project done by Nicolas Collins in 2009 to remember the life of Michel Waisvisz who was also a musical composer and inventor of experimental electronic musical instruments. The instrument used in this performance is a simple candle along with a device used to pick up the movement of the flame. The flame controls the oscillators possibly through a temperature sensor.

Candle-controlled oscillators by students of Nicolas Collins in Le quai-Mulhouse Art School
Simple candle-controlled oscillators by students of Nicolas Collins in Le quai-Mulhouse Art School

The way the artist’s artistic abilities are manifested in this project is through his movement of the detector. As the detector moves further or closer to the flame the music changes in pitch and volume. He moves the detector as though it is the baton of a conductor. Another way might be that the artist tuned the device to make it produce the best sounds possible. At the beginning of the performance I did not feel like it was very interesting. However, as the candle started burning out, the flame started flickering which caused the music to be somewhat chaotic. The flickering of the candle and the change in music reminded me of a person struggling for life, refusing to die out and gasping for breath. After a while, the flame dies out as all flames do. All light is gone and the only thing you can hear is silence. The use of a candle in this instrument is very suitable for the artist’s intensions.

Links:

Nicolas Collins Website

Nicolas Collins: Live At Café Oto February 2010

Feedback Examples: Nicolas Collins

In Memoriam Michel Waisvisz by Nicolas Collins on Youtube

 

Project 10 – Simin Li

siminl-project10

// Simin Li
// Section C
// siminl@andrew.cmu.edu
// Project 10

var clowns = [];
//store the clown fish
var terrainSpeed = 0.0005;
var terrainDetail = 0.005;
//used to control sea rocks

function setup() {
    createCanvas(600, 400); 
    // create an initial collection of fish
    for (var i = 0; i < 4; i++){
        var rx = random(width);
        var ry = random(0.8 * height);
        clowns[i] = makeClownFish(rx,ry);
    }
    frameRate(10);
}

function draw() {
    background(160);
    seaViewer(150,200);
    seaViewer(450,200);
    seaRocks(); 
    updateAndDisplayClownFish();
    removeClownFishThatHaveSlippedOutOfView();
    addNewClownFishWithSomeRandomProbability(); 
    fill(41,115,179,0.2);
    rect(0,0,width,height);

}

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

function removeClownFishThatHaveSlippedOutOfView(){
    var clownsToKeep = [];
    for (var i = 0; i < clowns.length; i++){
        if (clowns[i].fishX + clowns[i].fishWidth > 0) {
            clownsToKeep.push(clowns[i]);
        }
    }
    clowns = clownsToKeep; // remember the surviving buildings
}

function addNewClownFishWithSomeRandomProbability() {
    // With a very tiny probability, add a new fish to the end.
    var newClownLikelihood = 0.009; 
    if (random(0,1) < newClownLikelihood) {
        clowns.push(makeClownFish(width,random(0,0.8 * height)));
    }
}

// method to update position of fish every frame
function clownFishMove() {
    this.fishX += this.speed;
    this.fishY += noise(-this.speed,this.speed);
    //randomize speed
}

//draw the clown fish
function clownFishDisplay(){
    var fishHeight = this.fishWidth / 2;
    noStroke();
    fill(255,this.greeness,0);
    beginShape();
        curveVertex(this.fishX, this.fishY);//head of fish
        curveVertex(this.fishX, this.fishY);//head of fish
        curveVertex(this.fishX + 0.15 * this.fishWidth, this.fishY - fishHeight * 2 / 5);
        curveVertex(this.fishX + this.fishWidth / 3, this.fishY - fishHeight * 2 / 3);
        curveVertex(this.fishX + this.fishWidth * 2 / 3, this.fishY - (fishHeight / 4));
        curveVertex(this.fishX + this.fishWidth * 7 / 8, this.fishY - (fishHeight / 3));
        curveVertex(this.fishX + this.fishWidth, this.fishY);//tail of fish
        curveVertex(this.fishX + this.fishWidth * 7 / 8, this.fishY + (fishHeight / 3));
        curveVertex(this.fishX + this.fishWidth * 2 / 3, this.fishY + (fishHeight / 5));
        curveVertex(this.fishX + this.fishWidth / 3, this.fishY + fishHeight / 3);
        curveVertex(this.fishX + 0.1 * this.fishWidth, this.fishY + fishHeight * 1 / 6);
        curveVertex(this.fishX, this.fishY);//head of fish
        curveVertex(this.fishX, this.fishY);//head of fish
    endShape();
    //draw body
    
    noStroke();
    fill(255);
    beginShape();
        curveVertex(this.fishX + 0.15 * this.fishWidth, this.fishY - fishHeight * 2 / 5);
        curveVertex(this.fishX + 0.15 * this.fishWidth, this.fishY - fishHeight * 2 / 5);
        curveVertex(this.fishX + this.fishWidth / 3, this.fishY - fishHeight * 2 / 3);
        curveVertex(this.fishX + this.fishWidth / 3 + this.headStripe, this.fishY - fishHeight * 1 / 3);
        curveVertex(this.fishX + this.fishWidth / 3 - 0.3 * this.headStripe, this.fishY);
        curveVertex(this.fishX + this.fishWidth / 3, this.fishY + fishHeight / 3);
        curveVertex(this.fishX + 0.1 * this.fishWidth, this.fishY + fishHeight * 1 / 6);
        curveVertex(this.fishX + 0.1 * this.fishWidth, this.fishY - fishHeight * 1 / 3);
    endShape();
    //draw head stripe

    noStroke();
    fill(255);
    beginShape();
        curveVertex(this.fishX + this.fishWidth * 2 / 3, this.fishY - (fishHeight / 4));
        curveVertex(this.fishX + this.fishWidth * 2 / 3, this.fishY - (fishHeight / 4));
        curveVertex(this.fishX + this.fishWidth * 7 / 8, this.fishY - (fishHeight / 3));
        curveVertex(this.fishX + this.fishWidth * 7 / 8 + this.tailStripe, this.fishY - (fishHeight / 6));
        curveVertex(this.fishX + this.fishWidth * 7 / 8 + 0.3 * this.tailStripe, this.fishY);
        curveVertex(this.fishX + this.fishWidth * 7 / 8 - this.tailStripe, this.fishY + (fishHeight / 6));
        curveVertex(this.fishX + this.fishWidth * 7 / 8, this.fishY + (fishHeight / 3));
        curveVertex(this.fishX + this.fishWidth * 2 / 3, this.fishY + (fishHeight / 5));
        curveVertex(this.fishX + this.fishWidth * 2 / 3, this.fishY + (fishHeight / 5));
        curveVertex(this.fishX + this.fishWidth * 2 / 3 + this.tailStripe, this.fishY);
        curveVertex(this.fishX + this.fishWidth * 2 / 3, this.fishY - (fishHeight / 4));
    endShape();
    //draw tail stripe 
    
    fill(0);
    ellipse(this.fishX + 0.1 * this.fishWidth, this.fishY - fishHeight * 0.05,fishHeight / 10,fishHeight / 10);
    //draw eye
}

function seaViewer(windowX,windowY){
    //draw submarine outside window 
    strokeWeight(3);
    stroke(90);
    rectMode(CENTER);
    noFill();
    rect(windowX,windowY,240,340,80,80,80,80);
    fill("LightBlue");
    noStroke();
    rect(windowX,windowY,200,300,70,70,70,70);
    nail(windowX,windowY - 160, 12);
    nail(windowX,windowY + 160, 12);
    nail(windowX - 110,windowY, 12);
    nail(windowX + 110,windowY, 12);
    nail(windowX - 100,windowY - 120, 12);
    nail(windowX + 100,windowY + 120, 12);
    nail(windowX - 100,windowY + 120, 12);
    nail(windowX + 100,windowY - 120, 12);

}

//draw nails on window
function nail(nailX, nailY, nailSize){
    noStroke();
    fill(100);
    ellipse(nailX,nailY,nailSize,nailSize);
    var screwlength = nailSize / (4 * sqrt(2));
    strokeWeight(1);
    stroke(0);
    line(nailX - screwlength,nailY - screwlength,nailX + screwlength,nailY + screwlength);
    line(nailX - screwlength,nailY + screwlength,nailX + screwlength,nailY - screwlength);
}

//draw sea rocks
function seaRocks(){
    fill(11,20,61);
    noStroke();
    push();
        translate(0,80);
        //move down 80
        beginShape(); 
        vertex(0, height); 
        for (var x = 0; x < width; x++) {
            var t = (x * terrainDetail) + (millis() * terrainSpeed) * 3 / 4;
            var y = map(noise(t), 0,1, 0, height );
            vertex(x, y); 
        }
        vertex(width, height); 
        endShape();
    pop();
}

//create an object to store clownfish
function makeClownFish(birthLocationX,birthLocationY) {
    var clownFish = {                
                fishX: birthLocationX,
                //x location of fish
                fishY: birthLocationY,  
                //y location of fish              
                fishWidth: random(30,120),
                //width of fish
                greeness: random(30,140), 
                //G value of the fish body color
                move: clownFishMove,
                //move the fish
                speed: -random(0,4),
                //randomize horizontal speed
                display: clownFishDisplay,
                //draw fish
                headStripe: random(-8,8),
                //randomize the stripe on head
                tailStripe: random(-5,5)
                //randomize the stripe on tail
}
    return clownFish;
}


In this project I wanted to depict a view of marine life in front of a submarine window. The camera is following the submarine from outside. At first I only changed the color and size of the fish, then I realized I could make variations in the patterns of the fish as well.

file_000

Looking Outwards 10- Simin Li

 

timthumb-9
An interactive comic by Nova Jiang
A view making a comic using the Ideogenetic Machine by Nova Jiang
A viewer making a comic using the Ideogenetic Machine by Nova Jiang Photo: Patrick Lydon
A view making a comic using the Ideogenetic Machine by Nova Jiang
A viewer making a comic using the Ideogenetic Machine by Nova Jiang Photo: Patrick Lydon
Nova Jiang
Nova Jiang

Nova Jiang is a Chinese artist that builds interactive installations based in Los Angeles. She has a degree in Media Arts from UCLA and has been doing work that makes the audience relate with her artwork in one way or another.

A comic template by Nova Jiang
A comic template by Nova Jiang

The project Ideogenetic Machine that started in 2001 and is still ongoing generates a 4 page graphic novel in real time based on the photos taken of viewers and previously drawn news events. The artist uses a camera to capture visitors who are eager to pose and use their creativity to make a graphic novel that features them as the protagonist. Then, she uses customized software to make those photos into a line drawing and integrate them into the partially finished story randomly. Finally, the visitor can add dialogue into the text boxes left blank based on their own interpretation. Jiang adds to the database of drawings continuously, converting her views of current events into drawings that are then used to make each customized graphic novel.

timthumb-5
A viewer making a comic using the Ideogenetic Machine by Nova Jiang Photo: Otto Saxinger

What is interesting to me about this project is the importance of the viewer in making the comic. The amount of interactivity surpasses many other interactive installations. Another interesting thing is that the project is always up to date. I admire Jiang for her perseverance in adding drawings of current events into the system and making it a story that matters.

Links

Ideogenetic Machine

Ideogenetic Machine on Vimeo

Ideogenetic Machine on Youtube

Simin Li – Project 9

screen-shot-2016-10-27-at-9-35-34-pmsiminl-project9inobjects

// Simin Li
// Section C
// siminl@andrew.cmu.edu
// Project 9 in objects
var d = 9;
//side length of each rhombus
var portrait;
//the image to be preloaded
var cubes = [];
//create array named cubes
var m = 0;
//index of the array cubes
var pointt = [];
//create an array to store coordinates not yet used 
var getIndex = 0;
//the index of the number of array[2]
for(var k = -45; k < 62; k++){
    for(var n = -45; n < 62; n++){  
        pointt.push([k,n]); 
    }
}
//create a 2D array called pointt and store arrays of length of 2 using a for loop in it
function preload(){
    portrait = loadImage("http://i.imgur.com/QPplgCrg.jpg");
    //load image
}
function setup() {
    createCanvas(600, 600);
    background(0);
    portrait.resize(610,610);
    //resize the original image to fit on a 800 by 800 canvas
    //when resized to 600 by 600 rgb values of border points are undefined
    //so it is resized to 610 by 610
    portrait.loadPixels();
    //load pixels
    frameRate(100);
    
}

function draw() {
 
    colorMode(RGB);
var gapY = d * sqrt(3) / 2;
//differnce of x values between two adjacent hexagon left corners
var gapX = d *  3 / 2;
//differnce of y values between two adjacent hexagon left corners     

IndexofCoordinate = floor(random(0,pointt.length));
//randomly select an array inside the array pointt 
var j = pointt[IndexofCoordinate][0];
//j is the first element of the selected array
//assign a random value to j so it draws in a random hexagon slot
var i = pointt[IndexofCoordinate][1];  
//i is the second element of the selected array
//assign a random value to i so it draws in a random hexagon slot  
var X = 18 + gapX * j;
var Y = gapY * j;

    cubeX = X + gapX * i;
    //x coordinates of hexagon
    cubeY = Y - gapY * i;
    //y coordinates of hexagon
    color1 = portrait.get(cubeX + d , cubeY + 3);
    //color of bottom left rhombus is determined by a pixel in that rhombus
    color2 = portrait.get(cubeX + d , cubeY - 3);
    //color of top left rhombus is determined by a pixel in that rhombus
    color3 = portrait.get(cubeX + d + 3, cubeY);
    //color of right rhombus is determined by a pixel in that rhombus
    cubes[m] = new Cube(cubeX,cubeY,color1,color2,color3);
    cubes[m].draw();
    m ++;
    pointt.splice(IndexofCoordinate, 1);
    //remove the coodinate that has already been used so it doesn't redraw in the same slot
    println(IndexofCoordinate);
}

function rhombus(x,y,angle){
//create function that draws rhombus at x,y
//rotate by angle
    var h = d * sqrt(3)/2;
    //height of rhombus
    push();
        translate(x, y);
        rotate(radians(angle));
        shearX(radians(30));
        //shifts a rectangle into a parallelogram by 30 degrees
        rect(0, 0, d, h);
    pop();
}
function Cube(x,y,color1,color2,color3){
//creates object that combines three rhombuses into a cube at x,y
//each filled by color1,color2,color3
    this.x = x;
    this.y = y;
    this.color1 = color1;
    this.color2 = color2;
    this.color3 = color3;

this.draw = function(){
	noStroke();
	fill(color1);
    rhombus(x,y,0);//draws bottom left rhombus
    
    fill(color2);
    rhombus(x,y,300);//draws top left rhombus
    push();
        translate(1.50 * d, d * sqrt(3)/2);
        fill(color3);
        rhombus(x,y,240);//draws right rhombus
    pop();
    }
}

  I wanted controlled randomness in my portrait because I don’t like overlapping geometric shapes so I decided to use my wallpaper project as a template and treated the tiles as “slots” I could fill in randomly. I wanted to practice my objects so in the end I organized my code using an object. After I finished, I realized that a lot of spots were being reused so it is takes a long time to fill in the last few slots. So with help, I decided to create a 2d array that stored all of the coordinates that have not been used yet. After I drew that cube I removed it from the array.

file_000

Simin Li – Looking Outwards 9

Syncro Mail by Lisa Jevbratt 2001
Syncro Mail by Lisa Jevbratt 2001
An image sent in 2002 labeled “Steady” in Syncro Mail

I thought the post MREYES-LOOKINGOUTWARDS-SYNCRO MAIL – UNCONSCIOUS COLLECTIVE by Mreyes posted in 2016 was interesting so I decided to look into this project. This website by Lisa Jevbratt sends a photo paired with a word to a user and documents the content of every sent email. Like the author, I also enjoyed seeing the interaction between people. Not only did this project show the relation between the sender and the receiver, but also the people who were being tied together through the same images.

An image sent in 2002 labeled "Rebels" in Syncro Mail
An image sent in 2001 labeled “Rebels” in Syncro Mail
An image sent in 2002 labeled "Emigrate" in Syncro Mail
An image sent in 2001 labeled “Emigrate” in Syncro Mail

I think the author did a great job of explaining the possible underlying algorithms of the work, but to be more specific, each image is generated using the last 24 numbers of each user’s IP address. Unfortunately, the website is no longer running, but if it was, according to Mreyes’s assumption that the software randomly chooses images from Google and the fact that every two minutes, humans take more photos than ever existed in total 150 years ago, you would see the change of images on the web through the years. In this sense, this project is like a time capsule that adds something every day.

Mreyes was not sure of the artist’s intentions, but in my opinion, the artist is trying to make the point that many events are not causal, they are synchronistic, or coincidences in time which is a romantic thought.

Links:

mreyes-lookingOutwards-Syncro Mail – Unconscious Collective

Lisa Jevbratt Website

Syncro Mail – Unconscious Collective

Syncro Mail Website

Looking Outwards 8 – Simin Li

Specular Portraits by James George
Specular Portraits by James George
Clouds by James George
Clouds by James George

James George was the first artist in residence at Microsoft Research in Seattle and had a background as a computer scientist. He describes himself as an artist and makes software that documents the world in unconventional ways. He and two others founded Specular studios and aims to apply design to emerging technology. Exquisite City was a project done in April 2015 that documented places using photography and built a 3D model of an imaginary city by putting these “building blocks” together. This project was inspired by Exquisite Corpses, surrealist drawings of people made by multiple artists. Some of his other works include Clouds, an interactive installation done by openFrameworks and Specular Portraits that changes the lighting on geometric portraits. What is most interesting about George’s is that he is trying to change from “an artist making things that reflect his vision of the world, to an artist making tools that allow other people to see as they see.” as said by Kevin Slavin. One way that George presented successfully was by playing videos to further explain his description of the project. A lot of art, especially good art is unconventional and the only way to make people understand is showing them.

Here is James George speaking at Eyeo Festival 2015:

Links:

James George Website

James George at the Eyeo Festival

Other works by James George:

Exquisite City

Clouds