Karolina Sobecka is an artist, and researcher that operates in the intersection of art, science, technology, and activism. Her most recent work is a series called ‘Matter of Air’ in which she explores environmental activism through art and technology, including a project in which she creates, with a group of folks, a pseudo weather controlling machine. However, for this LO I’ll be discussing one of her older interactive installations. This project is called stability. The project entails having a user interact with a cube and a screen that supposedly shows a small room with a person inside the cube. Every time you shake up the room, the person rearranges the room and records the “disaster” in its disaster journal. The interesting thing is that every single arrangement created by this person is unique. This perhaps can be interpreted as pseudo Automated Intelligence, as the person is actively “creating” a new layout every time. But, this could perhaps just an illusion coded by the creator.
Month: November 2020
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.
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;
}
Project 11: Generative Landscape
For this week’s project, I decided to visualize an NYC subway line I used often (pre-pandemic) and the views of the skyline you can see passing by when the subway tracks are outdoors. I first roughly sketched out the scene on paper and then used Professor Cortina’s sample code as a baseline and customized it further to meet my vision. I displayed the scene to be at night since that’s the time of day I liked most when watching the skyline. Also, although nighttime, the lights would always be on in the buildings, so I decided to have lit up windows on all the buildings as well as the light reflections.
var frontBuildings = [];
var backBuildings = [];
var moonAndStars;
function preload(){
moonAndStars = loadImage("https://i.imgur.com/0JJlsGR.png");
}
function setup() {
createCanvas(480, 270);
// make initial array of buildings
for(var i = 0; i < 20; i++) {
var x = random(width);
backBuildings[i] = makeBackBuilding(x);
}
for(var i = 0; i < 10; i++) {
var x = random(width);
frontBuildings[i] = makeFrontBuilding(x);
}
frameRate(50);
}
function draw() {
// gradient night background
setGradient(color("#655BCE"), color("#1A1449"));
// moon
image(moonAndStars, 0, 0, 480, 350);
updateAndDisplayBuildings();
removeBuildingsThatHaveSlippedOutOfView();
addNewBuildingsWithSomeRandomProbability();
// tracks
drawTrack();
// train
drawTrain();
}
function drawTrain() {
strokeWeight(1);
stroke("#4A4954");
// train body
fill("#65656D");
rect(0, 180, 220, 80);
strokeWeight(5);
line(0, 240, 218, 240);
strokeWeight(2);
line(0, 245, 218, 245);
strokeWeight(5);
line(0, 190, 218, 190);
strokeWeight(2);
line(0, 196, 218, 195);
noStroke();
// doors
fill("#5D5C66");
rect(10, 200, 36, 60);
rect(130, 200, 36, 60);
// windows
fill("#383664");
rect(12, 202, 32, 30);
rect(132, 202, 32, 30);
rect(58, 200, 60, 30);
rect(200, 200, 20, 40);
// train number
fill("purple");
circle(182, 220, 25);
fill(255);
textSize(20);
text("7", 177, 227);
}
function drawTrack() {
fill(20);
rect(0, 220, width, 100);
fill("#8F8F91");
rect(0, 220, width, 30);
fill("#F0D933");
rect(0, 240, width, 5);
}
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 frontBuildingsToKeep = [];
var backBuildingsToKeep = [];
for (var i = 0; i < frontBuildings.length; i++){
if (frontBuildings[i].x + frontBuildings[i].width > 0) {
frontBuildingsToKeep.push(frontBuildings[i]);
}
}
for (var i = 0; i < backBuildings.length; i++){
if (backBuildings[i].x + backBuildings[i].width > 0) {
backBuildingsToKeep.push(backBuildings[i]);
}
}
frontBuildings = frontBuildingsToKeep; // remember the surviving buildings
backBuildings = backBuildingsToKeep;
}
function addNewBuildingsWithSomeRandomProbability() {
// With a very tiny probability, add a new building to the end.
var newBuildingLikelihood = 0.08;
if (random(0,1) < newBuildingLikelihood) {
backBuildings.push(makeBackBuilding(width));
frontBuildings.push(makeFrontBuilding(width));
}
}
function updateAndDisplayBuildings(){
// Update the building's positions, and display them.
for (var i = 0; i < backBuildings.length; i++){
backBuildings[i].move();
backBuildings[i].display();
}
for (var i = 0; i < frontBuildings.length; i++){
frontBuildings[i].move();
frontBuildings[i].display();
}
}
// method to update position of building every frame
function frontBuildingMove() {
this.x += this.speed;
}
// draw the building and some windows
function frontBuildingDisplay() {
noStroke();
// building
fill(this.color);
var y = 220 - this.height;
rect(this.x, y, this.width, this.height);
// windows
fill("#FFE9AD");
for(var i = 0; i < 5; i ++) {
rect(this.x + 5, y + 10 + 15*i, this.width/6, 8);
rect(this.x + 20, y + 10 + 15*i, this.width/6, 8);
rect(this.x + 35, y + 10 + 15*i, this.width/6, 8);
}
}
function makeFrontBuilding(xlocation) {
var building = {x: xlocation,
width: random(40, 50),
height: random(80, 120),
color: color(random(20, 70), random(20, 70), 130),
speed: -3,
move: frontBuildingMove,
display: frontBuildingDisplay}
return building;
}
// method to update position of building every frame
function backBuildingMove() {
this.x += this.speed;
}
// draw the back building and some windows
function backBuildingDisplay() {
noStroke();
var y = 220 - this.height;
// light reflections
fill(255, 243, 180, 20);
ellipse(this.x + this.width/2, y + 20, this.width*2);
// building
fill(this.color);
rect(this.x, y, this.width, this.height);
// windows
fill("#FFE9AD");
for(var i = 0; i < 8; i ++) {
rect(this.x + 5, y + 10 + 15*i, this.width/6, 8);
rect(this.x + 20, y + 10 + 15*i, this.width/6, 8);
rect(this.x + 35, y + 10 + 15*i, this.width/6, 8);
}
}
function makeBackBuilding(xlocation) {
var building = {x: xlocation,
width: random(40, 50),
height: random(130, 160),
color: color(random(60, 80), random(60, 80), 180),
speed: -3,
move: backBuildingMove,
display: backBuildingDisplay}
return building;
}
// code from https://editor.p5js.org/REAS/sketches/S1TNUPzim
function setGradient(c1, c2) {
noFill();
for (var y = 0; y < height; y++) {
var inter = map(y, 0, height, 0, 1);
var c = lerpColor(c1, c2, inter);
stroke(c);
line(0, y, width, y);
}
}
LO-11: Women in Computational Design
The project I chose for this week is SOMEONE by Lauren Lee McCarthy. This project interested me since its focus was on reimagining home intelligence systems as actual people rather than AI. SOMEONE is primarily a human version of Amazon Alexa. For 2 months, the homes of 4 participants had custom-designed smart devices installed. A command center was installed in NYC where visitors were able to look into the participants’ homes through laptops and control their networked devices. Participants would call out for “someone” in which the visitors respond to their needs as Alexa does.
Lauren Lee McCarthy is an artist whose work focuses on social relationships in the era of surveillance, automatic, and algorithmic living. She received a BS in Computer Science and Art and Design from MIT and an MFA from UCLA. She is also the creator of p5.js!
PROJECT-10 (generative landscape)
// 15-104
// SEAN CHEN
var bgbuildings = [];
var forebuildings = [];
var sidewalk = [];
var dash = [];
var light, bgCloud, foreCloud;
var frames = [];
var run = [];
function preload() {
light = loadImage('https://i.imgur.com/147kNrs.png');
bgCloud = loadImage('https://i.imgur.com/Fn6e7H6.png');
foreCloud = loadImage('https://i.imgur.com/PNyKohG.png');
frames[0] = loadImage('https://i.imgur.com/xxj2N5D.png');
frames[1] = loadImage('https://i.imgur.com/ju233XV.png');
frames[2] = loadImage('https://i.imgur.com/En4Sjg2.png');
frames[3] = loadImage('https://i.imgur.com/KXPlTB9.png');
frames[4] = loadImage('https://i.imgur.com/Ya0obgN.png');
frames[5] = loadImage('https://i.imgur.com/wFN72zO.png');
frames[6] = loadImage('https://i.imgur.com/DtMtZEq.png');
frames[7] = loadImage('https://i.imgur.com/oEUisa6.png');
}
// update scene objects
function sceneUpdate(){
for (var i = 0; i < bgbuildings.length; i++){
bgbuildings[i].move();
bgbuildings[i].display();
}
for (var i = 0; i < forebuildings.length; i++) {
forebuildings[i].move();
forebuildings[i].display();
}
for (var i = 0; i < dash.length; i++) {
dash[i].move();
dash[i].display();
}
for (var i = 0; i < run.length; i++) {
run[i].move();
run[i].display();
}
for (var i = 0; i < sidewalk.length; i++) {
sidewalk[i].move();
sidewalk[i].display();
}
}
// adding and deleting excess objects
function shiftScene() {
var buildingsToKeep = [];
for (var i = 0; i < bgbuildings.length; i++) {
if (bgbuildings[i].x + bgbuildings[i].breadth > 0) {
buildingsToKeep.push(bgbuildings[i]);
}
}
bgbuildings = buildingsToKeep;
for (var i = 0; i < forebuildings.length; i++) {
if (forebuildings[0].x + forebuildings[0].width < 0) {
forebuildings.push(makeBuildingFore((forebuildings.length-1)*95));
forebuildings.shift();
}
}
for (var i = 0; i < sidewalk.length; i++) {
if (sidewalk[0].x + 50 < 0) {
sidewalk.push(makeSidewalk(width + width/7));
sidewalk.shift();
}
}
for (var i = 0; i < dash.length; i++) {
if (dash[0].x + width/7 < 0) {
dash.push(makeDash(width));
dash.shift();
}
}
}
// randomly adding background buildings
function bldgProb() {
var newBuildingLikelihood = 2.5;
if (random(0,100) < newBuildingLikelihood) {
bgbuildings.push(makeBuilding(width));
}
}
// method to update position of objects every frame
function buildingMove() {
this.x += this.speed;
}
// draw background building and windows
function buildingDisplay() {
var floorHeight = 20;
var bHeight = this.nFloors * floorHeight;
fill(53);
stroke(0);
push();
translate(this.x, height - 60);
rect(0, -bHeight, this.breadth, bHeight);
for (var i = 0; i < this.nFloors; i++) {
for (var j = 0; j < this.breadth/20; j++) {
fill(155, 133, 38);
circle(j*15+10, -10-(i * floorHeight), 10);
}
}
pop();
}
function makeBuilding(birthLocationX) {
var bldg = {x: birthLocationX,
breadth: 50,
speed: -1,
nFloors: round(random(6,10)),
move: buildingMove,
display: buildingDisplay}
return bldg;
}
// drawing foreground buildings with long windows
function buildingDisplayFore() {
var floorHeight = 20;
var bHeight = this.nFloors * floorHeight;
fill(120);
stroke(0);
push();
translate(this.x, height - 60);
rect(0, -bHeight, this.width, bHeight+10);
for (var i = 0; i < this.nFloors; i++) {
fill(155, 133, 38);
rect(5, -10-(i*floorHeight), this.width-10, floorHeight-10, 5);
}
pop();
}
function makeBuildingFore(birthLocationX) {
var bldg = {x: birthLocationX,
width: 90,
speed: -2,
nFloors: round(random(3, 6)),
move: buildingMove,
display: buildingDisplayFore
}
return bldg;
}
// adding street lights
function sidewalkDisplay() {
image(light, this.x, height-85, 57, 50);
}
function makeSidewalk(birthLocationX) {
var swalk = {x: birthLocationX,
speed: -2.5,
width: width/4,
move: buildingMove,
display: sidewalkDisplay
}
return swalk;
}
// adding street dashes
function dashDisplay() {
stroke(144, 133, 0);
line(this.x, height-20, this.x + width/14, height-20);
}
function makeDash(birthLocationX) {
var d = {x: birthLocationX,
speed: -2.5,
width: width/7,
move: buildingMove,
display: dashDisplay
}
return d;
}
// adding running dude
function charDisplay() {
image(frames[this.frame], this.x, 243, 30, 27);
}
function frameMove() {
if (this.frame == 7 & this.step%3 == 0) {
this.frame = 0;
} else if (this.step%3 == 0) {
this.frame++;
}
this.step++;
}
function makeChar(birthLocationX) {
var c = {x: birthLocationX,
frame: 0,
step: 0,
move: frameMove,
display: charDisplay
}
return c;
}
function setup() {
createCanvas(450, 300);
background(5, 5, 45);
// create an initial collection of buildings
for (var i = 0; i < 7; i++){
var rx = random(width);
bgbuildings[i] = makeBuilding(rx);
forebuildings[i] = makeBuildingFore(i * 95);
dash[i] = makeDash(i * width/6);
}
for (var i = 0; i < 5; i++) {
sidewalk[i] = makeSidewalk(i * width/4);
}
for (var i = 0; i < frames.length; i++) {
run[i] = makeChar(10);
}
frameRate(30);
}
function draw() {
background(5, 5, 45);
//backgournd cloud
image(bgCloud, 0, 0, 600, 100);
// road and sidewalk
fill(0);
rect(0, height-50, width, 60);
fill(66);
rect(0, height-60, width, 20);
// updatinga and displaying scene objects
sceneUpdate();
shiftScene();
bldgProb();
push();
// layering transparent clounds
tint(255, 127);
image(foreCloud, 0, 0, 600, 100);
pop();
}
Beach Landscape
When I saw the prompt for the project this week, I immediately thought of doing something with a noise function. I felt as though mountains wouldn’t allow for enough variability, so I decided to do a beach. I laid out the very basic sand, water, and sky, and then added embellishing elements to try to create a drive by beach scene.
var boats = []; //arrays to hold respective objects
var clouds = [];
var umbrellas = [];
var planes = [];
var buildings = [];
var railings = [];
var people = [];
var towels = [];
var landscape = []; //array that creates slope of shoreline
var noiseParam = 0;
var noiseStep = 0.005; //defines extremity of shoreline slope
function setup() {
createCanvas(480,300);
for (var i = 0; i < 3; i++){ //make a certain amount of (object) to start out, at random locations within a constraint
var rx = random(width);
var ry = random(80,150)
boats[i] = makeBoat(rx,ry);
}
for (var i = 0; i < 3; i++){
var Cx = random(width);
var Cy = random(0,60)
clouds[i] = makeCloud(Cx,Cy);
}
for (var i = 0; i < people.length; i++){
var Tx = random(width);
var Ty = random(250,300)
towels[i] = makeTowel(Tx,Ty);
}
for (var i = 0; i < people.length; i++){
var Px = random(width);
var Py = random(250,300)
people[i] = makePerson(Px,Py);
}
for (var i = 0; i < 5; i++){
var Ux = random(width);
var Uy = random(250,300)
umbrellas[i] = makeUmbrella(Ux,Uy);
}
for (var i = 0; i < 15; i++){
var Bx = random(width);
buildings[i] = makeBuilding(Bx);
}
for (var i = 0; i < 0.9; i++){
var Px = random(width);
var Py = random(0,20)
planes[i] = makePlane(Px,Py);
}
for(var i=0;i<=width/5;i++){
var n= noise(noiseParam); //picks value 0-1
var value = map(n,0,1,50,height); //scales it to the canvas size
landscape.push(value); //adds to array
noiseParam+=noiseStep; //moves to the right for the next point in the array
}
frameRate(5);
}
function draw() {
background(3,220,245);
fill(13,66,212,230); //dark blue
rect(0,height/4,width,height); //body of water
fill(227,232,164,175); //pale beige
rect(0,height/4-7,width,7); //distant shoreline
//call the functions to spawn and despawn respective obejcts
removeBoat();
newBoat();
removeCloud();
newCloud();
removeUmbrella();
removePlane();
newPlane();
removeBuilding();
newBuilding();
removeRailing();
newRailing();
removePerson();
removeTowel();
//call the move and show functions to continually draw and redraw objects after updated coordinates
for (var i = 0; i < clouds.length; i++){
clouds[i].move();
clouds[i].show();
}
for (var i = 0; i < buildings.length; i++){
buildings[i].move();
buildings[i].show();
}
for (var i = 0; i < boats.length; i++){
boats[i].move();
boats[i].show();
}
displayHorizon();
for (var i = 0; i < towels.length; i++){
towels[i].move();
towels[i].show();
}
for (var i = 0; i < people.length; i++){
people[i].move();
people[i].show();
}
for (var i = 0; i < umbrellas.length; i++){
umbrellas[i].move();
umbrellas[i].show();
}
for (var i = 0; i < planes.length; i++){
planes[i].move();
planes[i].show();
}
fill(159,159,159);
rect(0,height-50,width,40);
fill(110,110,110);
rect(0,height-45,width,30);
for (var i = 0; i < railings.length; i++){
railings[i].move();
railings[i].show();
}
}
//functions to remove an object from a displayed array once "out of sight"
function removeBoat(){
var boatsToKeep = []; //the boats that should still be displayed
for (var i = 0; i < boats.length; i++){
if (boats[i].x + boats[i].breadth > 0) { //if the boat is closer than it's width to the edge
boatsToKeep.push(boats[i]); //add this boat to the boats that will be displayed
}
}
boats = boatsToKeep; // only display the baots currently being kept
}
function removeCloud(){
var cloudsToKeep = [];
for (var i = 0; i < clouds.length; i++){
if (clouds[i].x + clouds[i].breadth > 0) {
cloudsToKeep.push(clouds[i]);
}
}
clouds = cloudsToKeep;
}
function removeUmbrella(){
var umbrellasToKeep = [];
for (var i = 0; i < umbrellas.length; i++){
if (umbrellas[i].x + umbrellas[i].breadth > 0) {
umbrellasToKeep.push(umbrellas[i]);
}
}
umbrellas = umbrellasToKeep;
}
function removePlane(){
var planesToKeep = [];
for (var i = 0; i < planes.length; i++){
if (planes[i].x + 150 > 0) {
planesToKeep.push(planes[i]);
}
}
planes = planesToKeep;
}
function removeBuilding(){
var buildingsToKeep = [];
for (var i = 0; i < buildings.length; i++){
if (buildings[i].x > 0) {
buildingsToKeep.push(buildings[i]);
}
}
buildings = buildingsToKeep;
}
function removeRailing(){
var railingsToKeep = [];
for (var i = 0; i < railings.length; i++){
if (railings[i].x > 0) {
railingsToKeep.push(railings[i]);
}
}
railings = railingsToKeep;
}
function removePerson(){
var peopleToKeep = [];
for (var i = 0; i < people.length; i++){
if (people[i].x > 0) {
peopleToKeep.push(people[i]);
}
}
people = peopleToKeep;
}
function removeTowel(){
var towelsToKeep = [];
for (var i = 0; i < towels.length; i++){
if (towels[i].x > 0) {
towelsToKeep.push(towels[i]);
}
}
towels = towelsToKeep;
}
//functions to create new objects that come into sight
function newBoat() {
var newBoatChance = 0.009; //the chance that a new boat will appear
if (random(0,1) < newBoatChance) { //activate probability
boats.push(makeBoat(width,random(100,150))); //add a new boat if the porbability condition is met
}
}
function newCloud() {
var newCloudChance = 0.001;
if (random(0,1) < newCloudChance) {
clouds.push(makeCloud(width,random(0,60)));
}
}
function newPlane() {
var newPlaneChance = 0.003;
if (random(0,1) < newPlaneChance) {
planes.push(makePlane(width, random(0,50)));
}
}
function newBuilding() {
var newBuildingChance = 0.1;
if (random(0,1) < newBuildingChance) {
buildings.push(makeBuilding(width));
}
}
function newRailing() {
var newRailingChance = 0.8;
if (frameCount % 2 == 0 & random(0,1)
Yael Braha
Eamonn Burke
This is Yael Braha’s “Tree of Changes”, an interactive sculpture which utilizes metalwork, voice recognition and algorithms, LED lights, and a custom Max/MSP software. It allows a user to speak a “wish” into a microphone, watch it travel up the tree, and become a glowing leaf on the branches.
What I really admire about this project is interactivity, and especially how intimate that interactivity is. It shows the power of computational design as a way to connect to people and make them feel special. Not only is a user able to alter the sculpture, but they are able to do it in a way that feels personal to them, which is the epitome of user experience design. In addition to this, the tree itself looks very elegant despite being made from metal, which is quite a feat.
Yael Braha studied Graphic Design at the European Institute of Design in Rome. She then immigrated to the US to study film at San Francisco State University. She now works in Canada, and works mainly with large computational and architectural installations, but also creates fine hand art such as jewelry and ceramics.
Project 11 – Generative Landscape
For this project, I wanted to create a bustling city environment. I created an iPhone in the middle with someone pressing the record button, imagining that they are in a driving car and want to take in the city.
/*
* Amy Lee
* amyl2
* Section B
*/
// Variables for people
var px = [];
var py = [];
var pdx = [];
var pc = [];
var skin = [];
var pWidth = [];
var pHeight = [];
// Variables for clouds
var cx = [];
var cy = [];
var cdx = [];
var cWandH = [];
var buildings = [];
var houses = [];
function preload() {
// loading image files
finger = loadImage("https://i.imgur.com/DPWPwwe.png");
police = loadImage("https://i.imgur.com/9xYWNnM.png");
taxi = loadImage("https://i.imgur.com/ywwvyoP.png")
}
function setup() {
createCanvas(480,480);
frameRate(20);
// Finger
fin = new Object();
fin.image = finger;
fin.x = 200;
fin.y = 460;
fin.dx = 1;
fin.dy = 1;
fin.width = 290;
fin.height = 200;
fin.move = fingerMove;
fin.draw = fingerDraw;
pol = new Object();
pol.image = police;
pol.x = 700;
pol.y = 255;
pol.dx = 15;
pol.width = 240;
pol.height = 240;
pol.move = polMove;
pol.draw = polDraw;
tax = new Object();
tax.image = taxi;
tax.x = 900;
tax.y = 275;
tax.dx = 10;
tax.width = 230
tax.height = 230
tax.move = taxiMove;
tax.draw = taxiDraw;
// People
for (var i = 0; i < 10; i ++){
px[i] = random(25, width - 25);
py[i] = 350;
pdx[i] = random(1,3);
pc[i] = color(random(255), random(255), random(255));
skin[i] = color(random(55,200), 80, 90);
pWidth[i] = random(20,50);
pHeight[i] = random(30,80);
}
// Clouds
for (var i = 0; i < 5; i ++){
cx[i] = random(20,460);
cy[i] = random(30,90);
cdx[i] = 2;
// cloud width and height
cWandH[i] = random(20,30);
}
// Building
for (var j = 0; j < 5; j ++){
var bx = random(width);
buildings[j] = makeBuildings(bx);
}
// House
for (var k = 0; k < 3; k ++){
var hx = random(width);
houses[k] = makeHouses(hx);
}
frameRate(10);
}
function draw() {
// background(130,208,218);
background(200,241,208);
sidewalk();
road();
// Draw clouds, make them move right, and reappear if they move off canvas
for (var i = 0; i < 5; i++){
cloud(cx[i], cy[i], cdx[i], cWandH[i], cWandH[i]);
cx[i] += cdx[i];
if (cx[i] > width + 10){
cx[i] = -40;
}
}
updateAndDisplayBuildings();
removeBuildingsThatHaveSlippedOutOfView();
addNewBuildingsWithSomeRandomProbability();
updateAndDisplayHouses();
removeHousesThatHaveSlippedOutOfView();
addNewHousesWithSomeRandomProbability();
// Make buildings reappear if they go off the right side of the canvas
// Reappear on the left side
for (var j = 0; j < buildings.length; j++){
if (buildings[j].x > width + 20) {
buildings[j].x = -60;
}
}
// Make houses reappear if they go off the right side of the canvas
// Reappear on the left side
for (var k = 0; k < houses.length; k ++){
if (houses[k].x > width + 20) {
houses[k].x = -100;
}
}
// Make people reappear if they go off the right side of the canvas
// Reappear on the left side
for (var i = 0; i < 10; i ++){
people(px[i], py[i], pdx[i], pc[i],skin[i],pWidth[i], pHeight[i]);
px[i] += pdx[i];
if(px[i] > width+50){
px[i] = -50;
}
}
pol.draw();
pol.move();
tax.draw();
tax.move();
drawiPhone();
fin.draw();
fin.move();
if (frameCount >= 60){
record();
}
}
function people(px, py, pdx, pc,skin, pWidth, pHeight){
fill(pc);
noStroke();
// Shirt
ellipse(px, py, pWidth, pHeight);
// Head
fill(skin);
ellipse(px,py-25,20,20);
}
function fingerDraw(){
image(finger, this.x, this.y, this.width, this.height);
}
// Move finger to record button
function fingerMove(){
if (fin.x > 142 & this.y > 378){
this.x -= this.dx;
this.y -= this.dy;
}
}
function polDraw(){
image(police, this.x, this.y, this.width, this.height);
}
function polMove(){
this.x -= this.dx;
if (this.x <= -800){
this.x = 500;
}
}
function taxiDraw(){
image(taxi, this.x, this.y, this.width, this.height);
}
function taxiMove(){
this.x -= this.dx;
if (this.x <= -1000){
this.x = 500;
}
}
// BUILDINGS //
function updateAndDisplayBuildings(){
// Update the building's positions, and display them.
for (var j = 0; j < buildings.length; j++){
buildings[j].move();
buildings[j].display();
}
}
function removeBuildingsThatHaveSlippedOutOfView(){
var buildingsToKeep = [];
for (var j = 0; j < buildings.length; j++){
if (buildings[j].x + buildings[j].breadth > 0) {
buildingsToKeep.push(buildings[j]);
}
}
buildings = buildingsToKeep; // remember the surviving buildings
}
function addNewBuildingsWithSomeRandomProbability() {
// With a very tiny probability, add a new building to the end.
var newBuildingsLikelihood = .0006;
if (random(0,1) < newBuildingsLikelihood) {
buildings.push(makeBuildings(width));
}
}
// Make buildings move to right
function buildingsMove() {
this.x += this.speed;
}
function buildingsDisplay() {
var floorHeight = 30;
var bHeight = this.nFloors * floorHeight;
push();
noStroke();
fill(this.col);
translate(this.x, height - 40);
// Drawing the actual buildings
rect(0, -bHeight-110, this.breadth, bHeight);
// fill(18, 126, 190);
// Windows
for (var i = 0; i < this.nFloors; i++) {
fill(18, 126, 190);
rect(5, -130 - (i * floorHeight), this.breadth - 10, 10);
}
// Building antennae
stroke(18,126,190);
strokeWeight(2);
line(5,-bHeight-110,5,-bHeight-120);
line(10,-bHeight-110,10, -bHeight-130);
noStroke();
pop();
}
function makeBuildings(birthLocationX) {
var bldg = {x: birthLocationX,
breadth: 60,
speed: 4.0,
col: color(121,204,221),
nFloors: round(random(5,10)),
move: buildingsMove,
display: buildingsDisplay}
return bldg;
}
// HOUSES //
function updateAndDisplayHouses(){
for (var k = 0; k < houses.length; k++){
houses[k].move();
houses[k].display();
}
}
function makeHouses(birthLocationX){
var houses = {x: birthLocationX,
breadth: 100,
speed: 4.0,
col1: color(232,175,104),
col2: color(182,110,125),
nFloors: round(random(2,4)),
move: housesMove,
display: housesDisplay}
return houses;
}
function removeHousesThatHaveSlippedOutOfView() {
var housesToKeep = [];
for (var k = 0; k < houses.length; k++){
if (houses[k].x + houses[k].breadth > 0) {
housesToKeep.push(houses[k]);
}
}
houses = housesToKeep;
}
function addNewHousesWithSomeRandomProbability() {
var newHousesLikelihood = .0001;
if (random(0,1) < newHousesLikelihood) {
houses.push(makeHouses(width));
}
}
function housesMove() {
this.x += this.speed;
}
function housesDisplay() {
var floorHeight = 20;
var hHeight = this.nFloors * floorHeight;
push();
noStroke();
fill(this.col1);
translate(this.x, height-30);
rect(0, -hHeight - 110, this.breadth, hHeight);
fill(this.col2);
triangle(0, -hHeight - 110, this.breadth, -hHeight - 110, this.breadth/2, -hHeight - 140);
rect(30, -hHeight - 90, this.breadth - 60, hHeight - 20);
fill(252, 197, 132);
ellipse(50, -hHeight - 110 , 8, 8);
pop();
}
function cloud(cx, cy, cdx, cWandH, cWandH){
push();
stroke(255);
strokeWeight(20);
line(cx, cy, cx+30, cy);
pop();
fill(255);
ellipse(cx,cy,cWandH, cWandH);
ellipse(cx+10,cy-10,cWandH, cWandH);
ellipse(cx+20,cy,cWandH, cWandH);
}
function drawiPhone(){
fill(0);
// top rectangle
rect(130,40,200,60);
// left side
rect(130,40,20,400);
// right side
rect(330,40,20,400);
// bottom rectangle
rect(130,380,200,60)
// home button
fill(255);
ellipse(236,416,31,31);
fill(33);
ellipse(240,416,33,33);
// small rectangle at top
fill(58);
rect(215,65,50,10);
// glass shine
push();
stroke(255);
strokeWeight(10);
line(160,140,200,110);
line(160,170,240,110);
line(240,360,310,305);
line(272,370,315,336);
pop();
}
function sidewalk(){
noStroke();
fill(236,205,158);
rect(0,330,480,70);
fill(132,64,64);
rect(0,390,480,10);
}
function road(){
fill(180,145,126);
rect(0,400,480,80);
}
// REC button on iPhone
function record(){
fill(255,0,0);
ellipse(270,124,13,13);
textSize(20);
text("REC", 280, 130);
}
Project 11: Landscape
var Stars = [];
var Planets = [];
var asteroids = [];
var terrain = [];
var noiseParam = 0;
var noiseStep = 0.007;
function setup() {
createCanvas(480, 300);
// create an initial collection of stars, planets, and asteroids
for (var i = 0; i < 100; i++){
var rx = random(width);
var ry = random(height);
Stars[i] = makeStar(rx, ry);
}
for (var i = 0; i < 5; i++){
var rx = random(width);
var ry = random(height);
Planets[i] = makePlanet(rx, ry);
}
for (var i = 0; i < 2; i++){
var rx = random(width);
var ry = random(height);
asteroids[i] = makePlanet(rx, ry);
}
//set up noise function to create scrolling planet terrain
for (i = 0; i<=width/5; i++){
var n = noise(noiseParam);
var value = map(n, 0,1,height/2, height)
terrain.push(value)
noiseParam+= noiseStep
}
frameRate(20);
}
function draw() {
background(0);
updateStars();
removeStars();
addNewStars();
updatePlanets();
removePlanets();
addNewPlanets();
updateasteroids();
removeasteroids();
addNewasteroids();
mars();
insideSpaceship();
astronaut();
}
function updateStars(){
// Update the Star's positions, and display them.
for (var i = 0; i < Stars.length; i++){
Stars[i].move();
Stars[i].display();
}
}
function removeStars(){
var StarsToKeep = [];
for (var i = 0; i < Stars.length; i++){
if (Stars[i].x + Stars[i].breadth > 0) {
StarsToKeep.push(Stars[i]);
}
}
Stars = StarsToKeep;
}
function addNewStars() {
var newStarLikelihood = 0.2;
if (random(0,1) < newStarLikelihood) {
Stars.push(makeStar(width, random(height)));
}
}
// method to update position of Star every frame
function StarMove() {
this.x += this.speed;
}
// draw Stars
function StarDisplay() {
fill(255);
push();
translate(this.x, this.y);
ellipse(0, this.breadth, this.nsize)
pop();
}
function makeStar(birthLocationX, birthLocationY) {
var star = {x: birthLocationX,
breadth: 50,
y:birthLocationY,
speed: -2.0,
nsize: round(random(1,8)),
move: StarMove,
display: StarDisplay}
return star;
}
//view scrolling landscape from inside spaceship
function insideSpaceship(){
noStroke()
fill(151, 163, 194)
rect(0, height/9*7, width, height);
rect(0,0, width, height/9);
rect(0,0, width/9, height)
rect(width/9*8, 0, width, height);
noFill();
strokeWeight(10);
stroke(61, 81, 133)
beginShape();
vertex(width/9, height/9);
vertex(width/9*8, height/9);
vertex(width/9*8, height/9*7);
vertex(width/9, height/9*7);
vertex(width/9, height/9);
endShape();
strokeWeight(2);
var lx = 80;
var ly = 10;
var pt = 15
for (i=0; i<4; i++){
line(lx, 0, lx, height/9)
line(lx, height/9*7, lx, height)
lx+=110
line(0, ly, width, ly)
ly += 250
}
line(0, 120, width/9, 120)
line(width/9*8, 120, width, 120)
strokeWeight(7)
point(width/9 + 10, height/9 +10)
point(width/9 + 10, height/9*7 - 10)
point(width/9*8-10, height/9 +10)
point(width/9*8-10, height/9*7 - 10)
noStroke();
}
//draw astronaut looking out spaceship window
function astronaut(){
fill(255)
ellipse(70, 230, 100);
rect(30, 240, 80,100)
fill(143, 150, 168)
ellipse(85,225, 60)
stroke(143, 150, 168)
strokeWeight(4);
line(85, 270, 85, height)
noFill()
stroke(181, 199, 247)
ellipse(85,225, 60)
noStroke();
}
function updatePlanets(){
for (var i = 0; i < Planets.length; i++){
Planets[i].move();
Planets[i].display();
}
}
function removePlanets(){
var PlanetsToKeep = [];
for (var i = 0; i < Planets.length; i++){
if (Planets[i].x + Planets[i].breadth > 0) {
PlanetsToKeep.push(Planets[i]);
}
}
Planets = PlanetsToKeep;
}
function addNewPlanets() {
var newPlanetLikelihood = 0.01;
if (random(0,1) < newPlanetLikelihood) {
Planets.push(makePlanet(width, random(height)));
}
}
function PlanetMove() {
this.x += this.speed;
}
function PlanetDisplay() {
fill(this.clr);
push();
translate(this.x, this.y);
ellipse(0, this.breadth, this.nsize)
pop();
}
function makePlanet(birthLocationX, birthLocationY) {
var Planet = {x: birthLocationX,
breadth: 50,
y:birthLocationY,
clr: color(random(1, 255), random(1, 255), random(1, 255)),
speed: -1.0,
nsize: round(random(10,50)),
move: PlanetMove,
display: PlanetDisplay}
return Planet;
}
function updateasteroids(){
for (var i = 0; i < asteroids.length; i++){
asteroids[i].move();
asteroids[i].display();
}
}
function removeasteroids(){
var asteroidsToKeep = [];
for (var i = 0; i < asteroids.length; i++){
if (asteroids[i].x + asteroids[i].breadth > 0) {
asteroidsToKeep.push(asteroids[i]);
}
}
asteroids = asteroidsToKeep;
}
//asteroids appear the least frequently - "surprise element"
function addNewasteroids() {
var newasteroidLikelihood = 0.005;
if (random(0,1) < newasteroidLikelihood) {
asteroids.push(makeasteroid(width, random(height)));
}
}
//make the asteroid move in both x direction and y direction
function asteroidMove() {
this.x += this.speed;
this.y += this.speedy;
}
// draw asteroids
function asteroidDisplay() {
fill(random(255), random(255), random(255));
push();
translate(this.x, this.y);
ellipse(0, 5, this.nsize)
beginShape();
vertex(5,5);
vertex(15,5);
vertex(9,7);
vertex(15,10);
vertex(9,13);
vertex(10,15);
vertex(5,15);
endShape();
pop();
}
function makeasteroid(birthLocationX, birthLocationY) {
var asteroid = {x: birthLocationX,
breadth: 50,
y:birthLocationY,
speed: -5.0,
speedy: -1.0,
nsize: 10,
move: asteroidMove,
display: asteroidDisplay}
return asteroid;
}
//generate landscape of planet in foreground, placed low on screen so low frequency of apearance
function mars (){
var n = noise(noiseParam);
var value = map(n, 0,1,height/5*3, height)
terrain.push(value)
terrain.shift();
noiseParam+= noiseStep
for (i = 0; i<=width/5; i++){
noStroke();
fill(222, 106, 11)
beginShape();
vertex(0, height)
vertex(width, height)
vertex(i*5, terrain[i])
endShape();
if (terrain[i] < terrain[i+1] & terrain[i] < terrain[i-1]){
drawAlien(i)
}
}
}
function drawAlien(i){
fill(0,255,0)
ellipse(i*5, terrain[i]-10, 10);
stroke(0,255,0)
strokeWeight(2);
line(i*5,terrain[i]-20, i*5, terrain[i]-10)
strokeWeight(10)
ellipse(i*5, terrain[i]-5, 5)
noStroke()
fill(255)
ellipse(i*5, terrain[i]-5, 8)
fill(0)
ellipse(i*5, terrain[i]-5, 5)
}
For this assignment, I had a lot of fun deciding what I wanted my landscape to be. However, I found that there were a lot of components that I wanted to introduce, but wasn’t able to efficiently generate them in a concise amount of code. I ended up utilizing methods from different classes to generate different aspects of my landscape – for example, objects in the background similar to what was provided in the sample code, as well as usage of the noise function for objects in the foreground. I was partially inspired by the game Among Us as well as a music video called “Where the Sea Sleeps.”
Looking Outwards – 11
One project that I admire is “Bot Party,” helmed by Phoenix Perry and aided by Freida Abtan, both women artists. The project is a game that requires the players to help the robots communicate with each other through audio interaction. They utilize a ‘bot to skin and skin to bot’ communication protocol – the user physically connects the bots so that they may send encoded messages to each other. I admire that the project is both thoughtful in its simplistic message, while simultaneously is efficient as well as aesthetically pleasing. It also utilizes robots for a considerably unique purpose. Phoenix Perry amusingly calls herself a cultural engineer, game designer, instigator, as well as “feminist killjoy.” She was educated at NYU Tandon. I admire her in that while she has evidently found personal success, she has used that success to help others – she founded the Code Liberation Institute, which teaches women how to program games, as well as Dozen Eyes Games, a studio aimed at games and installations that generate social change. She also gives lectures, and in general, her active pursuit of positive change in the world of a male dominated profession is really inspiring.