For best viewing experience, please open in full screen here, and let it run for a while in the background. Check on your simulation occasionally to see how they’re evolving.
You can click to add producers, but this is highly unrecommended as it will alter the carrying capacity of the system. I recommend simply letting the software simulation run in the background.
//
// Supawat Vitoorapakorn
// Svitoora@andrew.cmu.edu
// Section E
// EVOLUTION: An overview of genetic algorithms
//
// Evoltuion is a software that simulates evolution over time
// of a specie of consumers. The three main conceps are:
// VARIABILITY
// At setup, a diverse pool of genetic material is randomly created.
// HERERDITY
// Every time two producers mate, it's geneteics are combined and passed down.
// SELECTION
// The consumer's speed is determine by its darkness.
// Over time natural selection will probabilistically occur.
// CHARACTERS
//
// PRODUCERS:
// A certain amount of producers is randomly created every time interval.
// The producers gathers sunlight, grows, and if it exceeds a certain amount
// of calories it splits into two. Producers' calories can be consumed
// by consumers, and if producers' calories is negative it dies.
// CONSUMERS:
// A certain amount of consumers is randomly generated at setup.
// Consumers move around randomly searching for food (prdoucers).
// Each movement of a consumer consumes a certain amount of calories, and
// If a consumer's calorie is below zero, it dies. If a consumer's calorie
// reaches a certain threshold, it will stop searching for food and begin
// searching for a potential mate nearby to reproduce with.
//
// Reproduction consumes energy, and the the consumer may die shortly after.
var time = 1; // Time variable
var w = 480; // width
var h = 480; // height
var turtles_AI = []; // array of consumers
var INDEX = 0; // ID for each turtle
var debug_mode = false; // true to see calorie transfer.
//------------------------------------------
// Creates Turtle
// Each turtle has fitness level based on its color's darkness
// The darker it is the faster it moves to food.
// Each turtle also has a certain amount of energy (calorie).
// Input: x,y,energy, color
// Output: Object turtle
function makeTurtle(tx, ty, energy = random(25, 300),
c = color(random(0, 255), random(0, 255), random(0, 255))) {
var turtle = {
x: tx,
y: ty,
life_index: random(-1, 1), //random seed for perlin bheavior
life_index2: random(-1, 1), //random seed for perlin bheavior
x_dir: 1,
y_dir: 1,
c: c,
energy: energy,
index: INDEX,
mating: false
};
turtle.fitness = fitness(turtle); //0 to 100
turtle.diameter = map(turtle.energy, 0, 100, 1, 20);
INDEX += 1;
return turtle;
}
// Determines fitness of Turtle from 0 to 100%
// The darker the color the faster it is.
// Input: Color
// Out: fitness
function fitness(turtle) {
R = red(turtle.c);
G = green(turtle.c);
B = blue(turtle.c);
avg = (R + G + B) / 3 // 0-255
return map(avg, 0, 255, 100, 0); //Darker the fitter
}
// Moves Turtle with noise
function turtle_move_AI() {
speed = .045;
for (i in turtles_AI) {
life = turtles_AI[i].life_index;
life2 = turtles_AI[i].life_index2;
x_dir = turtles_AI[i].x_dir;
y_dir = turtles_AI[i].y_dir;
// Moves turtle with Perlin Noise
SIZE = 10; //Radius of displacement
turtles_AI[i].x += x_dir * (noise(time * life) - .5) * SIZE;
turtles_AI[i].y += y_dir * (noise(time * life2) - .5) * SIZE;
turtles_AI[i].energy -= .01; //Caloric Cost of movement
}
}
// Contains any group of objects within the screen
// If object touch boundary of screen reverse direction
// Input: group
function contain(group) {
for (i in group) {
// Min
if (group[i].x < 0) {
group[i].x = 0
group[i].x_dir *= -1;
group[i].dx *= -1;
}
if (group[i].y < 0) {
group[i].y = 0
group[i].y_dir *= -1;
group[i].dy *= -1;
}
// Max
if (group[i].x > w) {
group[i].x = w
group[i].x_dir *= -1;
group[i].dx *= -1;
}
if (group[i].y > h) {
group[i].y = h
group[i].y_dir *= -1;
group[i].dy *= -1;
}
}
}
// Draws Turtle
function drawTurtle() {
for (var i = 0; i < turtles_AI.length; i++) {
d = map(turtles_AI[i].energy, 0, 100, 1, 20);
fill(turtles_AI[i].c);
ellipse(turtles_AI[i].x, turtles_AI[i].y, d, d)
fill(255);
textSize(10);
if (debug_mode == true) {
text(floor(turtles_AI[i].energy), turtles_AI[i].x, turtles_AI[i].y)
}
}
}
// Removes dead turtles
// If turtle has less than zero energy left it dies.
function turtle_update() {
for (var i = 0; i < turtles_AI.length; i++) {
if (turtles_AI[i].energy > 250) {
turtles_AI[i].mating = true;
}
if (turtles_AI[i].energy < 0) {
turtles_AI.splice(i, 1);
return
}
}
}
//------------------------------------------
// Hunt Food
// Input: individuall turtle
// Output: individiual turtle's target
function hunt(turtle) {
x = turtle.x;
y = turtle.y;
// If no food return false
if (Object.keys(PRODUCERS) == 0) {
return false
} else {
// Else target is the closest food
target = {
x: null,
y: null,
d: null
};
// Search all food
for (j in PRODUCERS) {
// Distance to food
d_food = dist(x, y, PRODUCERS[j].x, PRODUCERS[j].y);
// If target is null or closer than previous
// Reassign target to closest producers
if (target.d == null || d_food < target.d) {
target.x = PRODUCERS[j].x;
target.y = PRODUCERS[j].y;
target.d = d_food;
target.i = j
}
}
return PRODUCERS[target.i];
}
}
// Make all turtle hunt for Food
function HUNT() {
for (var i = 0; i < turtles_AI.length; i++) {
target = hunt(turtles_AI[i]);
if (target != false & turtles_AI[i].mating == false) {
moveToward(turtles_AI[i], target, turtles_AI[i].fitness);
eat(turtles_AI[i], target)
}
}
}
// Makes Object X moves towards Object Y with V velocity
function moveToward(X, Y, V) {
v = map(V, 0, 100, 0, .1);
X.x = lerp(X.x, Y.x, v / 2);
X.y = lerp(X.y, Y.y, v / 2);
}
// Eat food if food is inisde circle
// Input: individual food, FOOD array
function eat(turtle, target) {
d = dist(turtle.x, turtle.y, target.x, target.y)
// If food is inside turtle
if (d < (turtle.diameter / 2)) {
target.energy -= .2;
turtle.energy += 1;
}
}
//------------------------------------------
// Mating function of turtles
// Turtle becomes mature at 200 calories and seeks to reproduce
// Input: individual turtle
// Ouput: closest mateable target
function mate(turtle) {
x = turtle.x;
y = turtle.y;
target = {
x: null,
y: null,
d: null
};
// Search all potential mate
mate_count = 0;
for (var j = 0; j < turtles_AI.length; j++) {
// If Mate-able and not self
if (turtles_AI[j].mating == true & turtles_AI[j] != turtle) {
mate_count += 1;
d = dist(turtles_AI[j].x, turtles_AI[j].y, turtle.x, turtle.y)
if (target.d == null || d < target.d) {
target.x = turtles_AI[j].x;
target.y = turtles_AI[j].y;
target.d = d;
target.i = j
}
}
}
// If there is no mate return false.
if (mate_count == 0) {
return false
}
// If there is mate return target.
else {;
return turtles_AI[target.i];
}
}
// Makes turtles have sex.
// If mateable turtles touch one another they both lose 100 calorie
// and creates 1 baby. Turtle bcomes mateable at 200 calories.
function sex(turtle, target) {
d = dist(turtle.x, turtle.y, target.x, target.y)
if (d < turtle.diameter / 2) {
turtle.energy -= 100;
target.energy -= 100;
// Genetic Averaging and Mutation
c = lerpColor(turtle.c, target.c, random(.3, .7));
x = (turtle.x + target.x) / 2;
y = (turtle.y + target.y) / 2;
turtles_AI.push(makeTurtle(x, y, 66, c))
}
}
// Loop through turtles to and make them mate
function MATE() {
for (var i = 0; i < turtles_AI.length; i++) {
target = mate(turtles_AI[i]);
if (target != false & turtles_AI[i].mating == true) {
moveToward(turtles_AI[i], target, turtles_AI[i].fitness);
sex(turtles_AI[i], target);
}
}
}
//------------------------------------------
// Control
// Adds producers where mouse is clicked
function mouseClicked() {
// FOOD.push(new makeFood(mouseX, mouseY));
producer = (new makeProducer(mouseX, mouseY, 30));
PRODUCERS[time] = producer;
print(PRODUCERS);
}
// Adds producers where mouse is dragged
function mouseDragged() {
if (millisecond % 2 == 0) {
producer = (new makeProducer(mouseX, mouseY, 30));
PRODUCERS[time] = producer;
}
}
//------------------------------------------
// Producers
// Make food from sunlight
// Grows overtime and increase cell amount
var PRODUCERS = {};
// Creates prodcuers that grows from light
// Producers are eaten by turtles
// Input: x,y, energy, dx, dy
function makeProducer(x, y, energy = 10, dx = 0, dy = 0) {
this.x = x;
this.y = y;
this.life_index = random(-1, 1); //random seem for perlin beheavior
this.life_index2 = random(-1, 1); //random seem for perlin beheavior
this.energy = energy;
this.c = color(0, 255 / 2, 0, 255 * random(.5, 1));
this.mitosis = false;
this.dx = dx;
this.dy = dy;
}
// Draws producers
function drawProducer() {
for (key in PRODUCERS) {
x = PRODUCERS[key].x;
y = PRODUCERS[key].y;
c = PRODUCERS[key].c;
energy = PRODUCERS[key].energy;
fill(c);
strokeWeight(1)
// Perlin noise to size to give it life
base_vivacity = 5;
speed = 1
life = base_vivacity * (sin(time / 5 * speed))
// Make rectangles rotate randomly
push();
rectMode(CENTER);
translate(x, y);
rotate((noise(PRODUCERS[key].life_index) * 360));
rect(0, 0, energy + life, energy + life);
pop();
// Debug mode
if (debug_mode == true) {
fill(255);
textAlign(CENTER);
text(round(PRODUCERS[key].energy), x, y);
}
}
}
// Makes producer grow and reproduce if it has enough energy
function growProducer() {
for (key in PRODUCERS) {
// Grow Producer
life_index = PRODUCERS[key].life_index;
PRODUCERS[key].energy += noise(time * life_index) / 4;
// Reproduce
if (PRODUCERS[key].energy > 50) {
PRODUCERS[key].mitosis = true
}
}
}
// Producers preform mitosis by using it's energy to reproduce
function mitosisProducer() {
for (key in PRODUCERS) {
if (PRODUCERS[key].mitosis == true) {
energy = PRODUCERS[key].energy
// Create 2 new cells
for (i = 0; i < 2; i++) {
producer = (new makeProducer(
PRODUCERS[key].x,
PRODUCERS[key].y,
5,
random(-energy / 4, energy / 4),
random(-energy / 4, energy / 4)));
PRODUCERS[time] = producer;
PRODUCERS[key].energy -= 25;
}
}
}
}
// Basic Physics for producer while splittig
function mitosisPhysic() {
for (key in PRODUCERS) {
PRODUCERS[key].x += PRODUCERS[key].dx;
PRODUCERS[key].y += PRODUCERS[key].dy;
PRODUCERS[key].dx = lerp(PRODUCERS[key].dx, 0, .1);
PRODUCERS[key].dy = lerp(PRODUCERS[key].dy, 0, .1);
}
}
// Kills Producer if its energy is below 0.
function dieProducer() {
for (key in PRODUCERS) {
if (PRODUCERS[key].energy < 0) {
delete PRODUCERS[key]
}
}
}
// Give Producer Perlin noise to make it look alive
function lifeProducer() {
for (key in PRODUCERS) {
SIZE = .5;
lifeX = (noise(time * PRODUCERS[key].life_index) - .5) * SIZE;
lifeY = (noise(time * PRODUCERS[key].life_index2) - .5) * SIZE;
PRODUCERS[key].x += lifeX;
PRODUCERS[key].y += lifeY;
}
}
var producer_timer = 1;
// Adds new producer into the system every producer timer interval
function add_food(interval) {
producer_timer += 1;
print(producer_timer)
if (producer_timer % 500 == 0) {
for (var i = 0; i < random(0, 6); i++) {
PRODUCERS[time] = (new makeProducer(random(0, w), random(0, h), 1));
time += .1;
}
}
}
//------------------------------------------
// SETUP
function preload() {
w = windowWidth;
h = windowHeight;
}
// Creates petri dish
function setup() {
createCanvas(w, h);
background(255);
num_node = 100;
// Create a diverse genetic pool of consumers
for (i = 0; i < num_node; i++) {
t = makeTurtle(random(0, w), random(0, h));
turtles_AI.push(t);
}
// Initial set of producers
for (i = 0; i < num_node / 10; i++) {
PRODUCERS[i] = (new makeProducer(random(0, w), random(0, h)));
}
}
//------------------------------------------
function draw() {
background(255, 255, 255, 255 * .33);
millisecond = floor(millis()) % 2000;
// Model
time += .1;
turtle_move_AI();
contain(turtles_AI);
contain(PRODUCERS);
HUNT();
MATE()
turtle_update();
// Producers
growProducer();
dieProducer();
mitosisProducer();
mitosisPhysic();
lifeProducer();
add_food(1000);
// Draw
noStroke();
drawTurtle();
drawProducer();
}
Producer splits into two after growing big enough:
Consumers mate after it exceeds a certain caloric threshold and combines their genes with some amount of mutation:
At first, the simulation begins with a lot genetic diversity:
But over time due to natural selection for faster (darker) consumers, the genetic diversity is significantly decreased:
Interestingly, membrane-like structures also start to emerge from how food is being consumed. Here, the producers form a membrane around a dense cluster of producers that is rapidly splitting.
These membrane-like and clusters macrostructures were not explicitly programmed, they emerge probabilistically out of the specification and rules of this simulation. Here, a wall of producer is protecting a rapidly splitting colony of producers.
Group behavior also emerged out of the algorithm. Here, the producers began to form almost cell like clusters where food is rapidly consumed and reproduction distance is significantly decreased thereby creating a cell-like unit.
As the system reaches its carrying capacity, the producer begins to starve and die.
And as this cycle of extreme population swing for both the producers and consumers restarts, the genetic diversity of population doesn’t. Over time, despite natural mutation rate, the consumer population becomes abosolutely homogenous without any genetic diversity. In real life, this means that the population is extremely susceptible to a disease that can complete wipe its whole population out.
Conclusion:
]]>
I am interested in learning how to implement the genetic algorithm from Dan Shiftman’s The Nature of Code. Artistically, I am inspired by nature and I try to mimic it with technology. I’ve modeled a recursive L-system, gravity/entropy, and a basic swarm behavior. Now I want to model a living and evolving system. I plan on working on this over Thanksgiving break, so it’s a highly feasible project. Aesthetically, it’ll look similar to my turtle project which I went back and modified. The difference is that somehow there should be an evolutionary component incorporated. All of the renderings of the project will be done in simple geometric forms whereby it’ll look similar to a particle system because I am inspired by cells. I’m not 100% sure where this will take me, but one concrete thing is that I will be learning how to model evolution and there’ll be a lot of class and object-based behaviors.
I admire how I can watch the model slowly evolve into fitness. The project was created by Google’s DeepMind AI, and it involves teaching various models how to traverse across an obstacle. The model learned how to walk, run, balance, and climb. I am not actually sure if this is a machine learning AI, it could most likely be a genetic algorithm that is making this work. Regardless of the underlying algorithm, it is still an impressive feat of compressing the natural process of evolution.
I admire how a swarm behavior is represented here. The nodes simply randomly search the space, and one it found food it starts moving back to its hive leaving behind a trail of chemicals. If other nodes found the trail of chemical they simply followed it. It’s amazing how such a simple rule can produce such complex behavior. One downfall for this piece of “art” is that it is very unaesthetic. The system is implemented via a grid system, which is fine, but it is represented using simply rectangles as if this was the early 90s. Really the aesthetic of just sucks.
]]>//
// Supawat Vitoorapakorn
// Svitoora@andrew.cmu.edu
// Section E
// Petri Dish
// Create Node
function makeTurtle(tx, ty) {
var turtle = {
x: tx,
y: ty,
life_index: random(-.5, .5) //random seem for bug bheavior
};
return turtle;
}
var time = 1; // Time variable
var w = 480;
var h = 480;
var turtles = []
function setup() {
createCanvas(w, h);
background(255);
num_node = 15;
for (i = 0; i < num_node; i++) {
t = makeTurtle(random(0, w), random(0, h));
turtles.push(t);
}
}
// Ease turtles towards mouse
function turtle_move() {
speed = .045;
for (i in turtles) {
if (turtles[i].x < mouseX) {
dx = abs(turtles[i].x - mouseX)
turtles[i].x += dx * speed
} else {
dx = abs(turtles[i].x - mouseX)
turtles[i].x -= dx * speed
}
if (turtles[i].y < mouseY) {
dy = abs(turtles[i].y - mouseY)
turtles[i].y += dy * speed
} else {
dy = abs(turtles[i].y - mouseY)
turtles[i].y -= dy * speed
}
}
}
// Add Perlin noise to movement of turtle
function add_life() {
if (mouseIsPressed == false) {
SIZE = 10; //magnitude of noise movement add
} else {
SIZE = 30;
}
for (i in turtles) {
life = turtles[i].life_index
turtles[i].x += (noise(time * life) - .5) * SIZE;
turtles[i].y += (noise(time * life / 2) - .5) * SIZE;
}
}
// Draws membrane of turtles
function membrane() {
strokeWeight(1);
fill(0, 0, 0, 255 * .1);
beginShape(TRIANGLE_STRIP);
for (i in turtles) {
x = turtles[i].x
y = turtles[i].y
curveVertex(x, y);
}
endShape(CLOSE);
}
// Connect lines
function connect_lines() {
stroke(0, 0, 0, 255 * .25)
for (i in turtles) {
x_0 = turtles[i].x
y_0 = turtles[i].y
for (i in turtles) {
x_1 = turtles[i].x
y_1 = turtles[i].y
line(x_0, y_0, x_1, y_1);
}
}
}
function draw() {
time += .1;
background(255, 255, 255, 255 * .75);
turtle_move();
add_life()
for (i in turtles) {
fill(0, 0, 0, 255 * .75);
ellipse(turtles[i].x, turtles[i].y, 10, 10)
}
membrane();
connect_lines();
}
This is my first time playing with the noise() function and I absolutely love it! Try clicking and moving your mouse around the canvas. I wanted to create a digital petri dish inspired by seeing Euglena protist under the microscope:
]]>
Break Free by Taryn Southern is a music track and video art that is created using artificial intelligence. I admire the merging of human and machine in this project. Although the music track is generated via artificial intelligence the vocal lyrics are still handwritten by the artist herself. The raw footage is most likely shot by hand, by edited via artificial intelligence. The video art is also further manipulated in an algorithm similar to Google’s deep mind. Since the song is set to pop music tune, it begs the question of what does making music mean in an age of automation. Can one automate the art of music making? If so, what does it mean to humans who once thought that art and music were the highest echelons of human creativity? Could good music and art be deconstructed simply into just a pattern of stimuli that simply engages the human mind at an aesthetic level? These are the question of the age of automation.
]]>Lorna Barnashaw works as a digital creative director in the UK Barnshaw’s private life is relatively unknown, but she is famous as the artist that tries to 3-D Copy and Print herself.
While Barnshaw was attempting to 3-D capture herself so that she could 3D print herself, Barnshaw encountered many glitches in the various software and hardware she uses. Instead of discarding those glitches as defects, Barnshaw embraces the technological imperfection because it “illustrates that technology is flawed”. This notion that technology is “close mimicking reality but isn’t quite there yet” is a central theme to Barnshaw’s work, but for me, her work raises the question of what does human identity mean in a digital age? By 3D printing, these glitched forms from the digital realm into the physical realm, Barnshaw’s work transcend the digital and physical binary. I really Barnshaw’s work because it speaks about identity and technology in a physical form.
//
// Supawat Vitoorapakorn
// Svitoora@andrew.cmu.edu
// Section E
//
// Hallow-Eve: Recusively generate a forest of Sakura.
// Using a Lindenmayer system, each plant grows towards the sun.
var terrainSpeed = 0.0005;
var terrainDetail = 0.005;
var w = 480;
var h = 480;
var x_create = w + 50;
// Global Variable
var PLANT;
var PLANTS = [];
var segment_l = h * .1;
var r = h * .05 * .5;
var common_ratio = .618033 //Golden Ratio
var food;
// Recursively generates a plant model
var max_i = 5; // Max iteration depth
var cur_i = 0;
var DRAW_i = 0; // DRAW's iteration depth
///// MODEL /////
// Creates the sun for plants to grow towards
function food_create(x = w / 2, y = -h * 2) {
this.x = x;
this.y = y;
}
// Creates plants node. Nodes that have .child are branches,
// and nodes without .child are leaves.
function create_plant_node(x, y) {
this.x = x;
this.y = y;
this.x0 = this.x;
this.y0 = this.y;
this.child = [];
this.x1 = null;
this.y1 = null;
}
// Grows plant by making plant seek sunlight
function grow(plant, cur_i) {
// Using the golden ratio, plant's branch size is a geometric sequence
l = segment_l * (common_ratio ** (cur_i))
// Randomly generate the next node via reducing
// distance from plant ro sun
do {
angleMode(DEGREES);
if (cur_i == 0) {
angle = 5;
theta = random(-90 - angle, -90 + angle);
} else {
theta = random(0, 360);
}
plant.x1 = plant.x0 + (l * cos(theta));
plant.y1 = plant.y0 + (l * sin(theta));
d_new = dist(plant.x1, plant.y1, food.x, food.y)
d_old = dist(plant.x0, plant.y0, food.x, food.y)
}
// Keep generating until the new distance is less than the current one
while (d_new > d_old)
plant.child = [];
// Randomly decide how many children(branches) a node should have
for (var x = 0; x < random(1, 4); x++) {
plant.child.push(new create_plant_node(plant.x1, plant.y1));
}
}
// Recursively generates plant
function generate_plant(PLANT, cur_i, max_i) {
// Break Base
if (cur_i == max_i) {
return
// Continue case
} else {
grow(PLANT, cur_i);
cur_i++;
for (i in PLANT.child) {
generate_plant(PLANT.child[i], cur_i, max_i)
}
}
}
///// DRAW /////
// Recursively draws plant
function draw_PLANT(plant, DRAW_i) {
DRAW_i++; // Increases DRAW's Depth counter
stroke(255 * .3)
strokeCap(SQUARE);
strokeWeight((h * .0125) * (common_ratio ** DRAW_i))
// Break case: Flowers
// If node has no children; draw leaf.
// print(plant);
if (plant.child == []) {
fill(255, 255, 255);
ellipse(plant.x, plant.y, (2 / 600) * w, (2 / 600) * w);
return
} // If node has chldren; draw branches
else {
r = r ** common_ratio;
if (plant.child.length != 0) {
for (i in plant.child) {
line(plant.x, plant.y,
plant.child[i].x, plant.child[i].y)
draw_PLANT(plant.child[i], DRAW_i);
}
}
}
}
///// SETUP /////
function setup() {
createCanvas(w, h);
background("#ff9900");
food = new food_create();
// Row Cols Controller
num_tree = 3;
num_row = 4;
y_pos = 0;
// Translates Row and Col of Trees
// Rows
y_pos = w * .75;
PLANT = new create_plant_node(x_create, y_pos);
generate_plant(PLANT, cur_i, max_i);
PLANTS.push(PLANT);
}
// Recursively move each node of tree
function tree_move(tree) {
D = -1;
tree.x += D;
tree.x0 += D;
tree.x1 += D;
// Break
if (tree.child == []) {
return
} else {
// Recurse
for (i in tree.child) {
tree_move(tree.child[i]);
}
}
}
// To reduce system overload
function kill_plant() {
if (PLANTS.length > 5) {
PLANTS.shift();
}
}
var time = 1;
function draw() {
time += 1
background("#ff9900");
kill_plant();
// Represent and move trees
for (index in PLANTS) {
tree_move(PLANTS[index])
draw_PLANT(PLANTS[index], DRAW_i);
}
// Create new tree every modulo time
if (time % 160 == 0) {
PLANT = new create_plant_node(x_create, y_pos);
generate_plant(PLANT, cur_i, max_i);
PLANT.time = time;
PLANTS.push(PLANT);
}
// Draw Floor
fill(255 * .3);
rect(0, h * .75, w, h);
}
The most difficult part of this project was to get each node of the tree to move. Recursively creating the tree was easy because I had already done it before, but doing a DOF search for each node and moving it along was a challenge because it was hard to keep track of variables. I also didn’t expect recursive trees to be so computationally expensive to make, therefore I can only limit it to a few moving ones.
“Our Time” is a piece commissioned by the MONA (Museum of Old and New Art) which was intended to take you on an ethereal sensory journey, warping the way you view and think of time.”
I agree that “the amount of effort put into immersion in this is remarkable, and the piece utilizes our most basic senses to warp our perceptions of human constructs”. Although the code is simply an analog input of a person heartbeat being actuated by the motors of pendulums and the lights, the immersion effect created by the multitude of lights ad movement overwhelms our sense of time and space, thereby transporting us to a whole different state of existence. As somebody who is personally interested in physical computing, I deeply admire this project because it takes computing away from the digital screen and into the physical realm, thereby blurring the line between physical and digital environments. Although the algorithms itself is not sophisticated or complex, the whole of the artwork is greater than the sum of its mechanical and digital parts. If possible, I would love to experiment more with writing code on a physical level.
]]>
// Supawat Vitoorapakorn
// Svitoora@andrew.cmu.edu
// Section E
var face = "https://i.imgur.com/EyvV5mU.jpg"
var img;
var pixel_info = [];
// Createm Node
function new_pixel(x, y, k) {
this.x = x;
this.y = y;
this.k = contrast_add(k, .25);
this.m = map(k, 0, 255, 50, 1);
}
// Load links to image into an array
function preload() {
img = loadImage(face)
}
w = 480;
h = w;
function setup() {
createCanvas(w, h);
background(255 * .75);
image(img, 0, 0, w, h);
// Extract Image info
step = 1;
for (Y = 0; Y < w; Y += step) {
for (X = 0; X < h; X += step) {
k = brightness(get(X, Y));
// print(X, Y, k);
pixel_info.push(new new_pixel(X, Y, k));
step = random(7, 10)
}
}
// Sort pixels by brightness
pixel_info.sort(function(a, b) {
return a.k - b.k
});
// Print info and clear screen
print(pixel_info);
background(255 * .2);
// Draw
noStroke();
print(pixel_info.length)
draw_face(.9);
add_lines();
draw_face(.2);
}
// Draw Face
function draw_face(opacity) {
for (i in pixel_info) {
x = pixel_info[i].x;
y = pixel_info[i].y;
k = pixel_info[i].k;
r = map(k, 0, 255, 15, 1);
noStroke();
fill(k, k, k, 255 * opacity);
ellipse(x, y, r, r);
}
}
// Increase contrast
// x is input
// k is percent e.g. 0.1
function contrast_add(x, p) {
if (x < 255 / 2) {
x = x * (1 + p);
} else {
x = x * (1 - p);
}
return x
}
// Add lines for sophistication
function add_lines() {
for (i in pixel_info) {
x = pixel_info[i].x;
y = pixel_info[i].y;
k = pixel_info[i].k;
for (i in pixel_info) {
x1 = pixel_info[i].x;
y1 = pixel_info[i].y;
k1 = pixel_info[i].k;
if (round(k) == round(k1)) {
strokeWeight(1);
stroke(k, k, k, 255 * .05);
line(x, y, x1, y1);
}
}
}
}
I was experiencing some dark times in my life, therefore I decided to make a dark portrait. I was inspired by the algorithmic portrait.
I tried to replicate the portrait above, but sadly I couldn’t do in time. Since my portrait is a bit computationally heavy, here is a still image of it:
]]>
I remember Sarah Hendren coming to CMU give a lecture for the School of Design’s Design the Future lecture series. Her presentation revolves around presenting an intriguing project, explaining the process of it, and then using the story of the process to make her point. Sarah is an artist and design researcher at the Ollin College of Engineering whose work “engages adaptive and assistive technologies, prosthetics, inclusive design, accessible architecture, and related ideas”. As designers, unless prompted otherwise, we will always assume that the user is of able body, sense, and intellect. Because of this unstated assumption in design, the most designer would fail to consider how handicapped people would interact with their designs. Additionally, even when designers do consider these “not-normal” people, often time designers would assume that these “not-normal” people would want to reestablish “normalcy” through technology. Sarah distinguishes between the idea of cure versus accommodation, should we cure disability or should we accommodate a disability? She contrasts a high-tech electric muscle prosthetic arm that Gizmodo celebrates, with the high-impact almost free prosthetic leg that is made of recycled plastic in India. From communication to products, and environments, Sarah’s work spans no bounds. As a whole, Sarah’s practice is about re-contextualizing disability and transitioning towards a society where differences are celebrated.
]]>