EverLight
Don’t ask me about the name, but this iteration happened completely by accident. I was messing around with creating a grid of ellipses for my other idea when I decided to use lines instead. However, all i did was change “ellipse” to “line” and it created this amazingly cool, modern image.
void setup(){
size(1280,720);
background(0);
}
void draw(){
int orig = 0;
int x = int(random(6,20));
strokeWeight(1);
for (int i=1; i
A Diet of Bones
This is an experiment in generated grammar and poetics. the display is a blank black screen, and clicking generates a phrase that will slowly rise on the page. The type of phrase is based off of this, and are delineated into 3 types:
Left: A grammatically correct english phrase
Middle: a semi-random phrase in disyllabic trimeter (each line has 6 syllables).
Right: a randomised set of words that are in iambic pentameter (each line consists of 4 sets of iambs, which consist of one weak-stress syllable, and one strong-stress syllable).
//class containgng pertinent information abot a word
class Word {
String sing;
String plur;
int syllables;
int[] metre;
Word(String tempSing, String tempPlur,
int tempSyl, int[] tempMet) {
sing = tempSing;
plur = tempPlur;
syllables = tempSyl;
metre = tempMet;
}
}
// word tupole class - needed for a function return
class WordTuple {
Word x;
Word y;
WordTuple(Word tempX, Word tempY) {
x = tempX;
y = tempY;
}
}
// class that contains the phrases (built from Words) that appear
// on the display
class Phrase {
String contents;
int x;
int y;
Phrase(String tempConts, int tempX, int tempY){
contents = tempConts;
x = tempX;
y = tempY;
}
//phrases rise after generation
void update(){
y = y-1;
}
void display(){
fill(250,250,250);
textAlign(CENTER);
text(contents,x,y);
}
Boolean finished(){
return y < -50;
}
}
//word declaration - I have to hard-code the words right now,
//but processing automitically seems possible, if difficult
Word confessional;
Word studio;
Word Lebanon;
Word diet;
Word timber;
Word along;
Word bee;
Word bone;
Word of;
Word forWord;
Word a;
Word redouble;
Word[] nouns;
Word[] allWords;
//rythm patterns for iambic tetrameter and trimeter - 0 is a soft
//stress, 1 a hard stress. tetram is the only one currently in use
//since makeTrimet only follows the syllable restriuction
//Note: this is oversimplified - actually 4 levels of stress in
//english.
int[] tetramPattern = {0,1,0,1,0,1,0,1};
int[] trimetPattern = {0,1,0,1,0,1};
ArrayList<Phrase> phrases;
//makes a gramatically correct english phrase of one of a set of
//structures and randomly selected nouns
String makePhrase(){
float chooser = random(0,360);
int word1 = floor(random(nouns.length));
int word2 = floor(random(nouns.length));
String result;
if (chooser < 120) {
// a noun for noun
result = "a " + nouns[word1].sing + " for "
+ nouns[word2].plur;
} else if (chooser < 240) {
// the noun noun
result = "the " + nouns[word1].sing + " " + nouns[word2].sing;
} else {
// noun for noun
if (chooser < 300) {
result = nouns[word1].sing + " for " + nouns[word2].plur;
} else {
result = nouns[word1].plur + " for " + nouns[word2].plur;
}
}
return result;
}
//adds a word's metre to the main pattern
int[] addWord( int[] pattern, Word newWord, int patternLen){
/*println("adding" + newWord.sing +
"from " + patternLen + "to:");
printArray(pattern);*/
for(int i = 0; i < newWord.syllables; i++) {
pattern[patternLen + i] = newWord.metre[i];
}
/*println("result:");
printArray(pattern);*/
return pattern;
}
//test wether a metre pattern follows the main pattern up to
//the given size
Boolean followsMetre(int[] pattern, int[] testPattern, int size){
for(int i = 0; i < size; i++){
if (pattern[i] != testPattern[i]) {
return false;
}
}
return true;
}
//maked a nonsense iambic tetrameter
String makeTetram(){
int[] testPattern = new int[tetramPattern.length];
int[] resultPattern = new int[tetramPattern.length];
int currentLen = 0;
int tryI = 0;
int counter = 0;
String result = "";
Word tryWord;
while (currentLen < tetramPattern.length) {
tryI = floor(random(allWords.length));
tryWord = allWords[(tryI + counter) % allWords.length];
if ((currentLen + tryWord.syllables) <= tetramPattern.length){
testPattern = addWord(resultPattern, tryWord, currentLen);
if (followsMetre(tetramPattern, testPattern,
currentLen + tryWord.syllables)) {
resultPattern = testPattern;
currentLen += tryWord.syllables;
result = result + tryWord.sing + " ";
counter = 0;
} else {
testPattern = resultPattern;
}
}
counter += 1;
if (counter >= allWords.length) {
/*println(currentLen);
printArray(resultPattern);*/
return result + "pain "; //code failure
}
}
return result;
}
//chooses 2 words with total syllable cound of sylSum
WordTuple getWords(int sylSum){
Word word1 = allWords[floor(random(allWords.length))];
int[] nul = {};
Word word2 = new Word("","",0,nul);
int goalSyl = sylSum - word1.syllables;
if(goalSyl == 0){
return new WordTuple(word1, word2);
}
int tryI = floor(random(allWords.length));
for(int i=0; i < allWords.length; i++){
word2 = allWords[(tryI + i) % allWords.length];
if(word2.syllables == goalSyl){
return new WordTuple(word1, word2);
}
}
return new WordTuple(word1, word2);
}
// makes a disyllabic trimeter loosely based off of the
// phrase patterns
String makeTrimet(){
float chooser = random(0,360);
WordTuple choices;
String result;
if (chooser < 120) {
choices = getWords(4);
result = "a " + choices.x.sing + " for "
+ choices.y.plur;
} else if (chooser < 240) {
choices = getWords(5);
result = "the " + choices.x.sing + " " + choices.y.sing;
} else {
choices = getWords(5);
if (chooser < 300) {
result = choices.x.sing + " for " + choices.y.plur;
} else {
result = choices.x.plur + " for " + choices.y.plur;
}
}
return result;
}
void setup() {
//sets up words - hard coding
int[] feed4 = {0,1,0,1};
confessional = new Word("confessional",
"confessionals", 4, feed4);
int[] feed3 = {1,0,1};
studio = new Word("studio", "studios", 3, feed3);
Lebanon = new Word("Lebanon", "Lebanon", 3, feed3);
int[] feed3a = {0,1,0};
redouble = new Word("redouble", "redoubles", 3, feed3a);
int[] feed2 = {1,0};
diet = new Word("diet", "diets", 2, feed2);
timber = new Word("timber", "timber", 2, feed2);
int[] feed2a = {0,1};
along = new Word("along", "along", 2, feed2a);
int[] feed1 = {1};
bee = new Word("bee", "bees", 1, feed1);
bone = new Word("bone", "bones", 1, feed1);
int[] feed1a = {0};
of = new Word("of", "ofs", 1, feed1a);
forWord = new Word("for", "fors", 1, feed1a);
a = new Word("a", "a", 1, feed1a);
nouns = new Word[7];
nouns[0] = studio;
nouns[1] = bee;
nouns[2] = Lebanon;
nouns[3] = diet;
nouns[4] = bone;
nouns[5] = timber;
nouns[6] = confessional;
//nouns = {studio, bee, Lebanon, diet, bone, timber};
allWords = new Word[12];
allWords[0] = bee;
allWords[1] = redouble;
allWords[2] = Lebanon;
allWords[3] = of;
allWords[4] = diet;
allWords[5] = confessional;
allWords[6] = bone;
allWords[7] = forWord;
allWords[8] = studio;
allWords[9] = timber;
allWords[10] = along;
allWords[11] = a;
phrases = new ArrayList<Phrase>();
size(800,500);
frameRate(24);
/*println(makePhrase());
println("");
println(makeTetram());
println("");
println(makeTrimet());*/
}
void draw() {
background(0);
Phrase phrase;
for (int i = phrases.size()-1; i >= 0; i--) {
phrase = phrases.get(i);
phrase.update();
phrase.display();
if (phrase.finished()) {
phrases.remove(i);
}
}
}
//what kind of phrase is selected based off of the mouse position
//when clicked3
void mousePressed() {
println("mouse press:" + mouseX + "in" + width);
if(mouseX < (width/3)){
phrases.add(new Phrase(makePhrase(),mouseX, mouseY));
println("phrase added");
} else if(mouseX < 2*(width/3)){
phrases.add(new Phrase(makeTrimet(),mouseX, mouseY));
println("trimet added");
} else {
phrases.add(new Phrase(makeTetram(),mouseX, mouseY));
println("tetram added");
}
}
Neon Easter
Rapidly vibrating easter island faces. This starts as a static image of the above face, but clicking causes the colour of the bars to change and for each bar to be assigned a variable amount of wobble.
class Bar{ //class for each of the neon bars that for the fave
color c;
int sX;
int sY;
int eX;
int eY;
float var;
Bar(color tempC,int tempSx, int tempSy, int tempEx, int tempEy){
c = tempC;
sX = tempSx;
sY = tempSy;
eX = tempEx;
eY = tempEy;
var = 0.0;
}
void update(){
}
// randomly moves the bar based on the amount of chosen variance,
// then draws the line
void display(){
int tsx = sX + int(random(-var, var));
int tsy = sY + int(random(-var, var));
int tex = eX + int(random(-var, var));
int tey = eY + int(random(-var, var));
strokeWeight(1);
stroke(c);
line(tsx, tsy, tex, tey);
strokeWeight(4); //second low-alpha line imitates a glow
stroke(c,100);
line(tsx, tsy, tex, tey);
}
//feeds a new colour and movement cariance from a mouse click
void updateCol(color newC, float newVar){
c = newC;
var = newVar;
}
}
//these are the 2 sets of bars that equate to 2 light sources
ArrayList<Bar> hiBars;
ArrayList<Bar> loBars;
void setup(){
size(600,800);
hiBars = new ArrayList<Bar>();
loBars = new ArrayList<Bar>();
color cLo = color(255,0,0);
color cHi = color(250,250,250);
// adding the bars themselves
loBars.add(new Bar(cLo, 150,200, 275,200));
loBars.add(new Bar(cLo, 325,200, 450,200));
loBars.add(new Bar(cLo, 240,450, 360,450));
hiBars.add(new Bar(cHi, 310,245, 335,370));
hiBars.add(new Bar(cHi, 260,490, 340,490));
hiBars.add(new Bar(cHi, 220,220, 220,235));
hiBars.add(new Bar(cHi, 390,220, 390,235));
}
void draw(){
background(30);
Bar bar;
for (int i = hiBars.size()-1; i >= 0; i--) {
bar = hiBars.get(i);
bar.update();
bar.display();
}
for (int i = loBars.size()-1; i >= 0; i--) {
bar = loBars.get(i);
bar.update();
bar.display();
}
}
//returns a clolour with net brightness (r+g+b) higher than cs
color brighter(color c){
float r = red(c);
float g = green(c);
float b = blue(c);
//rgb values are cycled to give color variance
return color(random(g,255),random(r,255),random(b,255));
}
// creates new color choices and shake variance on click
void mousePressed(){
color newLo = color(random(255),random(255),random(255));
color newHi = brighter(newLo);
int var = 10;
Bar bar;
for (int i = hiBars.size()-1; i >= 0; i--) {
bar = hiBars.get(i);
bar.updateCol(newLo, random(var));
}
for (int i = loBars.size()-1; i >= 0; i--) {
bar = loBars.get(i);
bar.updateCol(newHi, random(var));
}
}
Duress
a .gif of the wallpaper running
This is an experiment in a dynamic desktop wallpaper. It is a simple white plain containing randomly-generated, vibrating red dots. these are generated recursively, and their random movement is recursive down the trees The program could be scaled to cover an entire wall. I find the quiet stress of the piece kind of amusing given the conventional purpose of a wallpaper
//recursive class that are represented by cicles in-render
class Node {
color c;
float xpos;
float ypos;
int radius;
boolean hasChildren;
Node child1;
Node child2;
Node child3;
Node(color tempC, float tempXpos, float tempYpos, int tempRadius) {
c = tempC;
xpos = tempXpos;
ypos = tempYpos;
radius = tempRadius;
float inc = 40.0;
float r = red(c);
float g = green(c)-inc;
float b = blue(c)-inc;
// base case: when the colour is close to true red, no recusion
// is called
if( b >= 10){
// creates connected nodes based off of current node
hasChildren = true;
child1 = new Node(color(r,g,b),(xpos+random(0,width/5)),
(ypos+random(-(width/5),width/5)),radius);
child2 = new Node(color(r,g,b),(xpos+random(0,width/5)),
(ypos+random(-(width/5),width/5)),radius);
child3 = new Node(color(r,g,b),(xpos+random(0,width/5)),
(ypos+random(-(width/5),width/5)),radius);
} else {
hasChildren = false;
}
}
//pre-updates a node with the movement of a parent node, and
//feeds that information to its children
void predate(float x, float y){
xpos += x;
ypos += y;
if(hasChildren) {
child1.predate(x,y);
child2.predate(x,y);
child3.predate(x,y);
}
}
//couses random movement in the node, and feeds that movement to
//its children, as well as causing them to update
void update() {
float x = random(-2,2);
float y = random(-5,5);
xpos += x;
ypos += y;
if(hasChildren) {
child1.predate(x,y);
child2.predate(x,y);
child3.predate(x,y);
child1.update();
child2.update();
child3.update();
}
}
//draws the red circles and connecting lines
void display() {
if(hasChildren) {
stroke(1);
line(xpos,ypos,child1.xpos,child1.ypos);
line(xpos,ypos,child2.xpos,child2.ypos);
line(xpos,ypos,child3.xpos,child3.ypos);
child1.display();
child2.display();
child3.display();
}
noStroke();
fill(c);
ellipse(xpos,ypos,radius,radius);
}
}
// class for the root node - similar to Nodes, but static -
// not nescesarry, could be streamlined into the Node class
class Root {
color c;
float xpos;
float ypos;
int radius;
Node child1;
Node child2;
Node child3;
Root(color tempC, float tempXpos, float tempYpos, int tempRadius) {
c = tempC;
xpos = tempXpos;
ypos = tempYpos;
radius = tempRadius;
float inc = 40.0;
float r = red(c);
float g = green(c)-inc;
float b = blue(c)-inc;
child1 = new Node(color(r,g,b),(xpos+random(0,width/5)),
(ypos+random(-(width/5),width/5)),radius);
child2 = new Node(color(r,g,b),(xpos+random(0,width/5)),
(ypos+random(-(width/5),width/5)),radius);
child3 = new Node(color(r,g,b),(xpos+random(0,width/5)),
(ypos+random(-(width/5),width/5)),radius);
}
void update() {
child1.update();
child2.update();
child3.update();
}
void display() {
line(xpos,ypos,child1.xpos,child1.ypos);
line(xpos,ypos,child2.xpos,child2.ypos);
line(xpos,ypos,child3.xpos,child3.ypos);
child1.display();
child2.display();
child3.display();
noStroke();
fill(c);
ellipse(xpos,ypos,radius,radius);
stroke(1);
}
}
Root progen;
//
void setup() {
size(1080,720);
progen = new Root(color(240,240,240), float(width/20), float(height/2),35);
}
void draw() {
background(255);
progen.update();
progen.display();
}
Control/Chaos x SelfPortrait
For the selfPortrait assignment, I had a lot of trouble figuring out how to insert images. That being said, I decided to continue working on it for the order chaos assignment. The mouseX position is used to control randomly changing bars that cover my image. As you move the mouse to the right side of the window, the bars move away from the face. Moving back to the left covers the face in chaos via quickly changing colored ellipses/rectangles. The mouseY position makes it more likely for the bars and ellipses to be thinner as you approach the bottom of the window.
Unfortunately, the code for this assignment was reverted to my first 30 minutes of work when my computer died.
Assignment 4: Wallpaper
Assignment 4: Chaos/Order/Faces Experiments
My Chaos vs. Order and Face projects kind of merged together in terms of what ideas they explore, so I’ve combined them into one blog post here…
I decided to research chaos and faces through visual distortion and face detection algorithms. I was inspired greatly by this blog post about “machine pareidolia”.
For the Chaos/Order project, I took an image of a human face and slowly distorted it until it was not recognizable by a face detection algorithm. Each step of the program increments a chaos constant which controls the amount of distortion that is passed into a shader that uses a perlin noise texture to transform the texture coordinates of a quad textured with the face image. Here are the results:
The face was obviously detected at step 0, where chaos=0…
At step 30, the face begins to look slightly “off”, but is still recognized.
Step 57 is still considered a face…
The face stays a face until step 162.
It’s interesting to see that step 161, the previous step, is only so slightly different enough from step 162 that it is still a machine-readable face!
On a similar note, my Generative Face project was about finding more faces from distorted faces (meta pareidolia?). I started with a basic geometric machine-recognisable face and incremented a similar chaos variable. Here are the results (detected faces are highlighted by squares):
Chaos = 5
Chaos = 10
Chaos = 50
Iterative wallpaper
This is the wallpaper I made for the iterative assignment. Some aspects of this pattern I had fun playing with involved opacities of the shapes, as well as the layering that occurs as the program runs. Unfortunately, I was unable to recover the exact code after my computer died, but I will post the code I used to start, below.
// Will Taylor
// Iteration wallpaper
int width = 800; int height = 800;
int fr = 24;
void setup(){
size(width, height);
background(255);
}
void draw(){
background(#FF4D6E);
strokeWeight(5);
stroke(#4DFF6F);
int diam = width/10;
float rad = diam*.75;
//green lines
for (int i = 0; i <=20; i++){
line(0, i*diam/2, width, i*diam);
}
stroke(0);
for (int r = 0; r <= 13; r++){
for (int c = 0; c <= 13; c++){
smooth();
strokeWeight(5);
fill(#FFF300,25); // yellow
ellipse(r*rad, c*rad, diam, diam);
strokeWeight(2);
fill(#008AFF, random(100)); // blue
ellipse(r*rad, c*rad, diam/4, diam/4);
}
}
}
Active KKK groups in the United States
For this assignment, I wanted my face to be used for data visualization. Initially, I was thinking I could change the characteristics of the figure to illustrate certain statistics like the example shown to us in class. However, when I tried to implement this technique in the design, the results weren’t very effective.
Instead I decided to use my face as a graphic to create a visualization of today’s active KKK groups in the United States.
//WT
//Chernoff faces
void setup(){
size(500,500);
PImage img = loadImage("confederate.jpg");
}
void draw(){
PImage img = loadImage("confederate.jpg");
float cx = width/2; float cy = height/2 + 20;
float eyeWidth = 5;
float eyeHeight = 3;
float bot = cy + 100;
float top = cy - 50;
float skullX0 = cx - 50;
float skullX1 = cx + 50;
float skullY = cy - 20;
float jawX0 = cx - 70;
float jawX1 = cx + 70;
float jawY = cy + 30;
if (mousePressed){
background(100);
image(img, 140,200);
strokeWeight(2);
//Body
ellipse(cx, height+20, random(300,400),random(150,200));
eyeWidth = random(25,30);
eyeHeight = random(35,50);
bot = cy + random(200,240);
top = cy - random(100, 150);
skullX0 = cx - random(width/6, width/10);
skullX1 = cx + random(width/5, width/8);
skullY = cy + random(width/2, width/5);
jawX0 = cx - random(width/6, width/10);
jawX1 = cx + random(width/6, width/10);
jawY = cy + random(width/3,width/5);
//hat
bezier(cx, top, skullX0,skullY,jawX0, jawY,cx,bot);
bezier(cx, bot, jawX1, jawY, skullX1, skullY, cx, top);
strokeWeight(random(18,25));
//EYES
point(cx + eyeWidth, cy + 2*eyeHeight);
point(cx - eyeWidth, cy + 2*eyeHeight);
}
}