svitoora – Evolution

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.

Evolution

// 
// 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:

Producers splitting.

Consumers mate after it exceeds a certain caloric threshold and combines their genes with some amount of mutation:

Consumers mating.

At first, the simulation begins with a lot genetic diversity:

The simulation begins with a lot gentic diversity.

But over time due to natural selection for faster (darker) consumers, the genetic diversity is significantly decreased:

Over time natural selection reduces genetic diversity.

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.

Membrane-like structures emerged although it wasn’t explicity programmed.

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.

Wall of producers protecting a rapidly growing colony.

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.

Individual cell-like clusters of rapidly reproducing and consuming begin to emerge.
Here, one cell-like cluster separately moves towards another group of producers.
Last colony of producers consumed.

As the system reaches its carrying capacity, the producer begins to starve and die.

No more food left.
Consumers begin to starve and die.
As food emerge, the cycle of population repeats.

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. 

No more genetic diversity is left.

Conclusion:

  1. Features can be created implicitly through explicitly programming beheaviors. Alhtough certain feaures of this simulation wasn’t explicity programmed, it emerge through the algorithms of the character’s beheavior.
  2. A system of genetic evolution will never reach its ultimate form. Although the black ones were the fastest, they needed to reproduced with inferior consumers thereby creating sub par offpsrings. Over time, this means that humans as a geneticically evolving organsims will never reach our ultimate form, if such form exist.
  3. What happens when there is no genetic diversity? If life on earth continued to evolve due to natural selection and converge towards an ideal form and homogenity what would happen?

 

SaveSave

SaveSave

SaveSave

svitoora – Proposal

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.

My swarm behavior sketch inspired by a petri dish.
My Entropy/Gravity sketch.

svitoora – Looking Outward 12

Google’s DeepMind AI just taught itself to walk

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.

Ant Behavior

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.


http://www.natureincode.com/code/various/ants.html

svitoora-Project-11- Petri Dish

Petri Dish

// 
// 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:

Image result for euglena

 

SaveSave

SaveSave

svitoora – Looking Outward 11

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.

svitoora – Looking Outward 10 – Lorna Barnshaw

Lorna Barnshaw’s Self Portrait

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.

Barnshaw’s various glitched portraits.

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.

Reality Reduction 1

svitoora – 10 Hallow-Eve

Supawat’s Portrait

// 
// 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.

svitoora – 09 Looking Outward

“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.

SaveSave

svitoora – 08 Lines in the Dark

sketch

// 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);
			}
		}
	}
}

Portrait

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:

SaveSave

SaveSave

Sarah Hendren: Inclusive Design

Sarah Hendren’s “Disability” Grafiti Project

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.