Project 11: Generative Landscape

For my project, I decided to create a relaxing underwater scene. Although it was a bit challenging to figure out how to execute my ideas, I had fun making my landscape and adjusting properties to make it more interesting. To create my landscape, I combined concepts that we learned in the past, such as arrays, objects, loops, noise, images, and functions. I randomized properties such as the x/y positions, sizes, colors, and speeds of my objects.

landscape-cb
var terrain = [];
var coral;
var bubbles = [];
var fish = [];

var noiseParam = 0;
var noiseStep = 0.05;

function preload() {
    coral = loadImage("https://i.imgur.com/S5HGpZa.png");
}

function setup() {
    createCanvas(480, 300);
    //setup noise for terrain
    for(var i=0; i<=width/5; i++) {
        var n = noise(noiseParam);
        var value = map(n, 0, 1, 0, height);
        terrain.push(value);
        noiseParam += noiseStep;
    }
    //setup for fish
    for (var i = 0; i < 15; i++) {
        fishx = random(width);
        fish[i] = makeFish(fishx);
    }
    //setup for bubbles
    for (var i = 0; i < 10; i++) {
        bubblex = random(width);
        bubbley = random(height);
        bubbles[i] = makeBubble(bubblex, bubbley);
    }
    frameRate(10);
}

function draw() {
    background(0, 180, 200);

    noStroke();
    fill(0, 230, 255, 90);
    ellipse(240, 0, 600, 200);

    blueTerrain();
    
    updateAndDisplayFish();
    removeFish();
    addNewFish();
    
    displayBubbles();
}

//background terrain
function blueTerrain() {
    terrain.shift();
    var n = noise(noiseParam);
    var value = map(n, 0, 1, 0, height);
    terrain.push(value);
    noiseParam += noiseStep;
    
    //blue terrain
    noStroke();
    fill(0, 66, 115);
    beginShape();
    vertex(0, height);
    for(var i=0; i<width/4; i++) {
        vertex(i*5, terrain[i]);
        //placement of coral on terrain
        if(terrain[i] < terrain[i-1] & terrain[i] < terrain[i+1]) {
            drawCoral(i*5, terrain[i]);
        }
    }
    vertex(width, height);
    endShape(CLOSE);
}

//draws coral on terrain
function drawCoral(x, y) {
    imageMode(CENTER);
    image(coral, x, y-10, 65, 80);
}

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

//remove fish that are off the canvas from the array
function removeFish() {
    var fishToKeep = [];
    for (var i = 0; i < fish.length; i++) {
        if (fish[i].x + fish[i].w > 0) {
            fishToKeep.push(fish[i]);
        }
    }
    fish = fishToKeep;
}

//with a small probability, add a new fish to end of the array
function addNewFish() {
    var newFishLikelihood = 0.3;
    if (random(0,1) < newFishLikelihood) {
        fish.push(makeFish(width+20));
    }
}

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

function drawFish() {
    push();
    translate(this.x, this.y);
    fill(this.color);
    ellipse(0, 0, this.w, this.h);
    strokeWeight(1.5);
    stroke(240);
    fill(50);
    ellipse(-15, -4, 8, 8);
    noStroke();
    fill(this.fincolor);
    triangle(0, -4, 0, 4, 15, 0);
    noFill();
    push();
    fill(this.color);
    triangle(this.w/2+20, -8, this.w/2+20, 8, (this.w/2)-2, 0);
    pop();
    pop();
}

//fish constructor
function makeFish(fishx) {
    var f = {x: fishx, y: random(height),
            w: random(40, 80), h: random(10, 45),
            color: color(random(100, 255), random(100, 255), random(100, 255)),
            fincolor: color(random(50, 200), random(50, 200), random(50, 200)),
            speed: random(-10, -20),
            move: moveFish,
            draw: drawFish
    }
    return f;
}

function displayBubbles() {
    for (var i = 0; i < bubbles.length; i++) {
        bubbles[i].move();
        bubbles[i].draw();
    }
}

//bubbles float upwards
function moveBubbles() {
    this.x += this.speed;
    this.y += this.speed;
    if (this.x <= 0) {
        this.x = width;
    }
    if (this.y <= 0) {
        this.y = height;
    }
}

function drawBubbles() {
    push();
    strokeWeight(1);
    stroke(255, 255, 255, 80);
    fill(100, 255, 255, 60);
    ellipse(this.x, this.y, this.size, this.size);
    noFill();
    strokeWeight(2);
    arc(this.x - this.size/12, this.y - this.size/12, 15, 15, PI, PI + HALF_PI);
    pop();
}

//bubbles constructor
function makeBubble(bubblex, bubbley) {
    var b = {x: bubblex, y: bubbley,
            size: random(20, 40),
            speed: random(-1, -6),
            move: moveBubbles,
            draw: drawBubbles
    }
    return b;
}

LookingOutwards-11

For this Looking Outwards, I’ve decided to look into Lauren. I first got interested in her because I saw this description saying, creator/lead-developer of p5.js. One of her works that caught my eye was the LAUREN, in which she attempted to become a human version of Amazon Alexa. It is an installation of a series of custom-designed networked smart devices like camera, door locks, electronic functions, switches, and etc. She claimed that her performance was better than an AI because she can understand the user as a person and anticipate their needs. It was interesting for me because recently there’s a lot of tryout going on to create AI devices to make people’s life easier. LAUREN was an improved version of current AIs except for empathy, that only humans can do.

Project 11: Generative Landscape

sketch
var clouds = [];
var bikeImage = [];
var bike = [];
var terrainCurve = 0.01;
var terrainSpeed = 0.001;


function preload(){
    var filenames =[];
    filenames[0] = "https://i.imgur.com/DSPjyoM.png";
    filenames[1] = "https://i.imgur.com/kGGBLDh.png";
    filenames[2] = "https://i.imgur.com/v9RMtPT.png";
    filenames[3] = "https://i.imgur.com/ZUC5xZ2.png";
    for(var i = 0; i < filenames.length; i++){
      bikeImage.push(loadImage(filenames[i]));
    }
}

function setup() {
    createCanvas(480,480); 
    //clouds 
    for (var i = 0; i < 9; i++){
        var ccloud = random(width);
        clouds[i] = drawCloud(ccloud);
    }
    frameRate(11);
    imageMode(CENTER);
    //bike
    var b = makeCharacter(240, 350);
    bike.push(b);
}

function draw() {
    sky(0, 0, width, height);
    DisplayClouds();
    removeClouds();
    newClouds();
    ground();
    for (var i = 0; i < bike.length; i++) { 
        var bb = bike[i];
        bb.stepFunction();
        bb.drawFunction();
    }
}

function sky(x, y, w, h) { 
    //sky
    var Blue;
    var Pink;    
    Blue = color(114, 193,215);
    Pink = color(253, 209, 164);
    for (var i = y; i <= y + h; i++) {
        var ssky = map(i, y, y + h, 0, 1.1);
        var cco = lerpColor(Blue, Pink, ssky);
        stroke(cco);
        line(x, i, x + w, i);
    }
    //mountains
    beginShape();
    stroke(1, 33,92);
    strokeWeight(200);
    for (var x = 0; x < width; x++){
        var tt = (x * terrainCurve) + (millis() * terrainSpeed);
        var mm = map(noise(tt), 0,1, 110, 255);
        vertex(x, mm + 180); 
    }
    endShape();
}

this.display = function() {
    strokeWeight(this.border);
    stroke(240);
    fill(240);
    ellipse(this.x, this.y,  this.display,  this.display);
}

function ground(){
    beginShape(); 
    noStroke();
    fill(18,12,46);
    rect(0,400,width,80);
    endShape();
}

function cloudDisplay(){
    noStroke(); 
    var floorH = 21;
    var cloudH = this.nFloors * floorH; 
    fill(250,50); 
    push();
    translate(this.x, height - 95);
    ellipse(95, -cloudH, this.breadth, cloudH / 2);
    pop();
    push();
    fill(250,80)
    translate(this.x, height - 220);
    ellipse(95, - cloudH, this.breadth/1.5, cloudH);
    pop();
}

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

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

function removeClouds(){
    var cKeep = [];
    for (var i = 0; i < clouds.length; i++){
        if (clouds[i].x + clouds[i].breadth > 0) {
            cKeep.push(clouds[i]);
        }
    }
    clouds = cKeep;
}

function newClouds(){ 
//random probability
    var newP = 0.01; 
    if (random(0,0.4) < newP) {
        clouds.push(drawCloud(width));
    }
}
    


function drawCloud(xx) {
    var cha = {x: xx,
                breadth: random(95, height),
                speed: -random(1,4),
                nFloors: round(random(4,8)),
                move: cloudMove,
                display: cloudDisplay}
    return cha;
}

function makeCharacter(cx, cy) {
    ccha = {x: cx, y: cy,
         imageNumber: 0,
         stepFunction: characterStep,
         drawFunction: characterDraw
        }
    return ccha;
}
function characterStep() {
    this.imageNumber++;
    if (this.imageNumber == 4) {
        this.imageNumber = 0;
    }
}
function characterDraw() {
    image(bikeImage[this.imageNumber], this.x, this.y,120,120);
}

For this Deliverable 11 project, I tried to collaborate on what I’ve learned from deliverable 9, using preloads for calling image animations and generating landscapes from deliverable 11. I also tried to show the difference in the speed by giving a certain frameRate for the rider and background mountains. Clouds are displayed with low opacity and different speed so that it shows how it has a different relationship with elements on the ground(mountains and humans). It was hard for me to figure out having two functions of makeCharacter because I had two figures to move: character, and the elements in the sky.

Project 11

sketchDownload
var x = 0;
var backgroundValue = [];
var noiseParam = 0;
var noiseStep = 0.1;


function setup() {
    createCanvas(480, 400);
    frameRate(15);
    var ilength = (width/5) + 1
    for (i = 0; i < ilength; i++) {
    	var n = noise(noiseParam);
    	var value = map(n, 0, 1, 0, height);
    	backgroundValue.push(value);
    	noiseParam += noiseStep
    } 
}

function draw() {
	var size = random(50, 150);
	background(166, 238, 255);
	stroke(160, 160, 255);
	strokeWeight(10);
	backgroundValue.shift();
	var x2 = 0;
	var ilength = (width/5) + 1
	var n = noise(noiseParam);
    var value = map(n, 0, 1, 0, height);
    backgroundValue.push(value);
    noiseParam += noiseStep
    for (i = 0; i < ilength; i++) {
		beginShape();
		curveVertex(x2, backgroundValue[i]);
		curveVertex(x2, backgroundValue[i]);
		curveVertex(x2, height);
		curveVertex(x2 + 5, backgroundValue[i + 1]);
		curveVertex(x2 + 5, backgroundValue[i + 1]);
		endShape(CLOSE);
		x2 += 5
	}
	noStroke();
	fill(color(random(255), random(255), random(255)));
    coral(x, size);
    x += 1
    if (x > 480) {
        x = 0;
    }
}

function coral(x, size) {
    beginShape();
    curveVertex(x, 400);
    curveVertex(x, 400);
    curveVertex(x + 5, size*3);
    curveVertex(x - 20, size*2);
    curveVertex(x + 5, size*2 - 5);
    curveVertex(x - 10, size);
    curveVertex(x, size + 5);
    curveVertex(x + 10, size*2 - 20);
    curveVertex(x + 20, size*3);
    curveVertex(x + 20, size*4);
    curveVertex(x + 70, size);
    curveVertex(x + 80, size*2);
    curveVertex(x + 50, 400);
    curveVertex(x + 50, 400);
    endShape(CLOSE);
}

Looking Outwards 11

The artist I am focusing on today is Jessica Rosenkrantz from the Nervous System art studio. Her work takes scientific theory on pattern formation in nature to create algorithms for design. What I admire about her work is that I can recognize what these generative patterns remind me of in nature. For instance, her project Porifera (2018) resembles a sea sponge. And her project Growing Objects (2014) resembles a crystallized snowflake. I don’t if these were patterns she was drawing from, but having that reference for me grounds these highly computerized projects into a context I understand. Jessica graduated from MIT in 2005 with degrees in biology and architecture, then from Harvard’s Graduate School of Design (for architecture) in 2008.

https://n-e-r-v-o-u-s.com/about_us.php

Project 11 – Generative Landscape

For this project, I wanted to create a simple winter landscape, because Christmas is coming and it’s quite exciting. Take a close look at this landscape and close your eyes and imagine that you are Santa Claus on a nice warm sled on your way to California.

I used the noise function to generate the mountains, and objects to create snowflakes and buildings.

sketch
var buildings = [];
var mountains = [];
var noiseParam = 0;
var noiseStep = 0.03;
let snowflakes = [];


function setup() {
    createCanvas(400, 240); 
    
    for(var i = 0; i < width/5; i++){
        var n = noise(noiseParam);
        mountains[i];
        var value = map(n, 0, 1, 0, height);
        mountains.push(value);
        noiseParam += noiseStep;
    }
    // create an initial collection of buildings
    for (var i = 0; i < 10; i++){
        var rx = random(width);
        buildings[i] = makeBuilding(rx);
    }
    frameRate(25);
}


function draw() {
    background(23, 39, 174); 
    noStroke();
    fill(187, 223, 250);
    ellipse(200, 70, 70);
    fill(255, 30);
    cloud(40, 47, 1);
    cloud(275, 15, 0.8);
    cloud(380, 70, 1.5);

    let t = frameCount / 20; // update time

     // create a random number of snowflakes each frame
  for (let i = 0; i < random(5); i++) {
    snowflakes.push(new snowflake()); // append snowflake object
  }

  // loop through snowflakes with a for..of loop
  for (let flake of snowflakes) {
    flake.update(t); // update snowflake position
    flake.display(); // draw snowflake
  }
}

// snowflake class
function snowflake() {
  // initialize coordinates
  this.posX = 0;
  this.posY = random(-50, 0);
  this.initialangle = random(0, 2 * PI);
  this.size = random(2, 5);

  // radius of snowflake spiral
  // chosen so the snowflakes are uniformly spread out in area
  this.radius = sqrt(random(pow(width / 2, 2)));

  this.update = function(time) {
    // x position follows a circle
    let w = 0.6; // angular speed
    let angle = w * time + this.initialangle;
    this.posX = width / 2 + this.radius * sin(angle);

    // different size snowflakes fall at slightly different y speeds
    this.posY += pow(this.size, 0.5);

    // delete snowflake if past end of screen
    if (this.posY > height) {
      let index = snowflakes.indexOf(this);
      snowflakes.splice(index, 1);
    }
  };

  this.display = function() {
    ellipse(this.posX, this.posY, this.size);
  };

    //for animating the mountains
    mountains.shift();
    var n = noise(noiseParam);
    var value = map(n, 0, 1, 0, height);
    mountains.push(value);
    noiseParam += noiseStep;

    //for mountains
    beginShape();

    for(var i = 0; i < width/5; i++){
        //filling the mountain with color
        fill(44, 67, 184);
        noStroke();
        //vertex funciton to fill the mountain
        vertex((i * 5), mountains[i]); 
        vertex((i + 1) * 5, mountains[i + 1]);   
        vertex(width/2, 10000000); 
    }
    endShape(CLOSE);
   
    displayHorizon();

    updateAndDisplayBuildings();
    removeBuildingsThatHaveSlippedOutOfView();
    addNewBuildingsWithSomeRandomProbability(); 
}


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


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


function addNewBuildingsWithSomeRandomProbability() {
    // With a very tiny probability, add a new building to the end.
    var newBuildingLikelihood = 0.007; 
    if (random(0,1) < newBuildingLikelihood) {
        buildings.push(makeBuilding(width));
    }
}


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

// draw the building and some windows
function buildingDisplay() {
    var floorHeight = 20;
    var bHeight = this.nFloors * floorHeight; 
    fill(105, 135, 213); 
    noStroke(); 
    push();
    translate(this.x, height - 40);
    rect(0, -bHeight, this.breadth, bHeight);
    fill(151, 186, 236);
    for (var i = 0; i < this.nFloors; i++) {
        rect(5, -15 - (i * floorHeight), this.breadth - 10, 3);
    }
    pop();
}


function makeBuilding(birthLocationX) {
    var bldg = {x: birthLocationX,
                breadth: 50,
                speed: -3.0,
                nFloors: round(random(2,8)),
                move: buildingMove,
                display: buildingDisplay}
    return bldg;
}


function displayHorizon(){
    fill(68, 91, 193);
    rect(0, height-50, width, height-50); 

}

function cloud(x, y, size) {
    fill(68, 91, 193);
    noStroke();
    arc(x, y, 25 * size, 20 * size, PI + TWO_PI, TWO_PI);
    arc(x + 10, y, 25 * size, 45 * size, PI + TWO_PI, TWO_PI);
    arc(x + 25, y, 25 * size, 35 * size, PI + TWO_PI, TWO_PI);
    arc(x + 40, y, 30 * size, 20 * size, PI + TWO_PI, TWO_PI);
}





LO 11 – A Focus on Women Practitioners

When looking at the list of women in new media arts, I came across Camille Utterback and was intrigued by her project Text Rain (1990), which I remembered seeing last year at the Pittsburgh Children’s Museum. It is an interactive installation where participants use physical movement to play with digital falling letters. Participants stand in front of a large projection screen where they see a mirrored video projection of themselves, combined with an animation of falling letters. Similar to rain and snow, the falling letters land/accumulate on participant’s heads and arms as well as respond to their motions. I find it fascinating how this hybrid installation transforms the museum experience, inviting visitors to engage with the work in an immersive, thoughtful way.

Camille Utterback’s work explores the aesthetic and experiential potential of connecting computational systems to human movement. Utterback combines sensing and display technologies with the custom software she writes to produce her work. Architectural-scale projections, custom LED lighting, and intimate sculptures with embedded screens are just a few examples of the broad range of media which Utterback works with. Camille Utterback holds a BA in Art from Williams College, and a Masters from NYU’s Tisch School of the Arts.

video about Text Rain

LO 11 – A Focus on Women Practitioners

Reality Reduction

Lorna Barnshaw


Reality Reduction
Reality Reduction

For this Looking Outwards post, I will be talking about Lorna Barnshaw’s project called Reality Reduction (2013). Lorna Barnshaw is a 3D designer from London, United Kingdom, with a bachelor’s degree of Fine Arts from Winchester School Of Art. She works as a freelance designer, creating 3D designs during her free time. Her project, Reality Reduction consists of random people 3D scanned in 360 views and using computation to reduce their features to low-poly shapes. She simplifies the person’s features and pixels to visualize what a person may look like after reduction. This project is really interesting to me because it uses advanced technology to effectively communicate her concept. It is both eerie and interesting at the same time, captivating the viewer by its realistic scans. 

View her portfolio here

Project 11

I instantly thought of Tron bikes when I read through the assignment, so that’s what I ended up doing. I modified a version of my generative hillside from Assignment 7 (I think?) and created two types of random objects, some abstract distant vertical structures that are represented by lines, and some dystopian irregular buildings. The height of the buildings and the placement of the window sections are randomized, as well as the heights of the structures in the background. There is also a moving grid to create more sense of motion in the work.

I spent a lot of the time fiddling with the different movement rates of objects and the tonal values to get the right depth and parallax effect.

Tron movie review & film summary (1982) | Roger Ebert
The inspiration
Quick sketch for vertical grid line spacing

sketch

var buildings = [];
var lines = [];
var bottomLines =[];
var topLines =[];
let hillHeight = [];
let noiseParam = 0;
let noiseStep = 0.05;

function setup() {
    createCanvas(480, 240); 
    
    // create an initial collection of buildings
    for (var i = 0; i < 10; i++){
        var rx = random(width);
        buildings[i] = makeBuilding(rx);
    }
    //populates the grid lines
    for (var i=0; i<49;i++){
    	topLines[i]=10*i;
    	bottomLines[i]=-1200+(60*i);
    }
    frameRate(10);
    //hill values
    for (let i=0; i<=width;i+=5){
        var n= noise(noiseParam);
        var value = map(n,0,1,height/8,height/2,true);
        hillHeight.push(value);
        noiseParam += noiseStep;
    }
}


function draw() {
    background(0); 
    drawHill();
    drawGrid();
    drawBike();
    updateAndDisplayLines();
    removeLinesThatHaveSlippedOutOfView();
    addNewLineWithSomeRandomProbability();
    updateAndDisplayBuildings();
    removeBuildingsThatHaveSlippedOutOfView();
    addNewBuildingsWithSomeRandomProbability(); 
    displayHorizon();
}

//updates and draws the grid
function drawGrid(){
	strokeWeight(1);
	stroke(255);
	fill(18,49,62);
	rect(0,height-100,width,height/2);
    //vertical lines
    for (var i=0; i<49;i++){
    	line(topLines[i],height-100,bottomLines[i],height);
    	topLines[i]-=5;
    	bottomLines[i]-=30;
    	if(topLines[i]==0){
    		topLines[i]=480;
    	}
    	if(bottomLines[i]==-1200){
    		bottomLines[i]=1680;
    	}
    }
    //horizontal lines
    for(var i=0; i<10; i++){
    	line(0,height-100+pow(2,i),width,height-100+pow(2,i));
    }
}
//draws background hill
function drawHill(){
	strokeWeight(0.25);
    hillHeight.shift();
        var n= noise(noiseParam);
        var value = map(n,0,1,0,height,true);
        hillHeight.push(value);
        noiseParam+=noiseStep;
        fill(8,26,34);
    //start of the hill shape, with a buffer point off screen
        beginShape();
        curveVertex(0,height);
        curveVertex(0,height);
        curveVertex(-5,hillHeight[0]);
    //loop for drawing all vertices
    for(let j=0; j<(width/5)+1; j++){
    	 if(j!=0&hillHeight[j-1]>hillHeight[j]&&hillHeight[j+1]>hillHeight[j]){
            rect(j*5,hillHeight[j]-20,5,hillHeight[j]-20);
        }
        curveVertex(j*5,hillHeight[j]);
    }

//end of hill shape with buffer
    curveVertex(width+5,hillHeight[width/5]);
    curveVertex(width,height);
    curveVertex(width,height);
    endShape();
   }

//draws the Tron bike
function drawBike(){
	push();
	translate(100,180);
	noStroke();
	//stripe
	fill(255,190,107);
	rect(-213,9,220,15);
	//base back
	fill(182,134,44);
	beginShape();
	vertex(7,5);
	vertex(7,5);
	vertex(31,0);
	vertex(60,10);
	vertex(60,22);
	vertex(19,22);
	vertex(19,10);
	vertex(7,5);
	endShape();
	//wheels
	fill(198,128,4);
    ellipse(6,18,18,18);
    ellipse(52,18,18,18);
    fill(0);
    ellipse(6,18,12,12);
    ellipse(52,18,12,12);
    pop();
}

//buildings 


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


function removeBuildingsThatHaveSlippedOutOfView(){
    // If a building has dropped off the left edge,
    // remove it from the array.  This is quite tricky, but
    // we've seen something like this before with particles.
    // The easy part is scanning the array to find buildings
    // to remove. The tricky part is if we remove them
    // immediately, we'll alter the array, and our plan to
    // step through each item in the array might not work.
    //     Our solution is to just copy all the buildings
    // we want to keep into a new array.
    var buildingsToKeep = [];
    for (var i = 0; i < buildings.length; i++){
        if (buildings[i].x + buildings[i].breadth > 0) {
            buildingsToKeep.push(buildings[i]);
        }
    }
    buildings = buildingsToKeep; // remember the surviving buildings
}


function addNewBuildingsWithSomeRandomProbability() {
    // With a very tiny probability, add a new building to the end.
    var newBuildingLikelihood = 0.12; 
    if (random(0,1) < newBuildingLikelihood) {
        buildings.push(makeBuilding(width));
    }
}


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

// draw the building and some windows
function buildingDisplay() {
	strokeWeight(0.5);
    var floorHeight = 20;
    var bHeight = this.nFloors * floorHeight; 
    fill(14,43,55); 
    stroke(255); 
    push();
    translate(this.x, height - 100);
    rect(0, -bHeight, this.breadth, bHeight);
    fill(0);
    stroke(255); 
    for (var i = 0; i < this.nFloors-1; i++) {
    	if(this.side==2){
        rect(this.breadth/2,-15 - (i * floorHeight),this.breadth-10, 10);
        }
        else{
       rect((this.breadth/2)-this.breadth,-15 - (i * floorHeight),this.breadth-10, 10);
        }
    }
    pop();
}


function makeBuilding(birthLocationX) {
    var bldg = {x: birthLocationX,
    	        side: (int(random(0,3))),
                breadth: 40,
                speed: -15.0,
                nFloors: round(random(2,8)),
                move: buildingMove,
                display: buildingDisplay}
    return bldg;
}

//lines 

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


function removeLinesThatHaveSlippedOutOfView(){
    var linesToKeep = [];
    for (var i = 0; i < lines.length; i++){
        if (lines[i].x + lines[i].breadth > 0) {
            linesToKeep.push(lines[i]);
        }
    }
    lines = linesToKeep; // remember the surviving lines
}


function addNewLineWithSomeRandomProbability() {
    var newLineLikelihood = 1; 
    if (random(0,1) < newLineLikelihood) {
        lines.push(makeLine(width));
    }
}


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

//draw the line spikes 
function lineDisplay() {
	strokeWeight(5);
    var floorHeight = 8;
    var bHeight = this.nFloors * floorHeight;  
    stroke(80); 
    push();
    translate(this.x, height - 100);
    line(0, -bHeight, 0, 0);
    pop();
}


function makeLine(birthLocationX) {
    var ln = {x: birthLocationX,
                breadth: 40,
                speed: -10.0,
                nFloors: round(random(1,6)),
                move: lineMove,
                display: lineDisplay}
    return ln;
}


function displayHorizon(){
    stroke(255);
    line (0,height-100, width, height-100); 
}


LO 11

For this week’s Looking Outwards, I looked at the CAre BOt by Caroline Sinders. The project is an interface bot that is concerned with helping victims of Social Media Break Up. It provides counsel and advice for users undergoing social media harassment, but it doesn’t replace therapy. It highlights inequities and failures in harassment policies and procedures for victims by using an empathetic and artistic interface.

Caroline Sinders is a computational designer and artist, and her work focuses on abuse, interaction, society, A.I., and conversation. She operates a studio that uses machine learning to design for public good and solve problems through user research. She received a Masters in Interactive Telecommunications from New York University.

https://carolinesinders.com/care-b0t/
CAre B0t, Caroline Sinders 2019