weirdie-telematic

Rain Ghosts

Interactive: Hover and move your mouse around the screen in the rain.

This is as a simple interactive environment based on the idea of being together with someone even though you cannot see them. 

 

Below is a GIF of 2 people interacting with it.

 

The project is a rainy forest in which the only indication that anyone else is there with you is where the rain is falling. If there is a gap, there must be another person present. After testing it out with a few friends, it has become apparent that not only is this something you must be looking and waiting for, but that you may find yourself seeing gaps or "ghosts" that aren't really there. It attempts to combine anonymity and intimacy through the concept of simply being there with another person. You may or may not know who they are, but you share a space and environment that reacts to you together regardless of how far apart you actually are.

Originally, I had many grand ideas for this project. Perhaps a collaborative garden where individuals planted trees and helped care for other peoples' saplings, or a drawing program where individuals had different "parts" - branches, leaves, and flowers.

In the end, this is what I had time for, and while it is simple, I think it has potential. I would like to expand this first to have the drops impact and make small splashes on the ground and on the tops of the entities in the environment, and to create leaves on the bushes that would react to being "brushed past".

 

Rain code derived from: http://thecodingtrain.com/CodingChallenges/004-purplerain.html

Interactivity based on Shar Stiles' drawing program: https://glitch.com/~cmuems-drawing-game

weirdie-Clock

The original idea for this piece was something that represented growth and decay in terms of nature. This evolved into a clock that drew generative artwork - one that changed throughout the day and grew more complex the longer you looked at it. For this, I started off with the code from The Coding Train's Perlin Noise Flow Field as a base template of sorts. The seed for the Perlin noise field is generated based on the day and year. Every second there is a white particle added, every minute a blue, and every red an hour, each traveling at different speeds to show how time "flies by". One can tell how many minutes or hours they have been staring at the clock, either watching or wasting time, by how many particles there are.

To continue this project, there are two things I would like to expand upon. First, there is currently a maximum number of each type of particle, as having an unlimited number results in a continuously lower framerate, and I would like to find a way to remove this limitation. Additionally, I would want to see this displayed so that it is continuously generating - that is, it would show how many seconds, minutes, and hours had passed in the day thus far.

12:04-12:05, with very little time elapsed:

3:13-3:14, with a around 60 minutes passed:

8:32-8:33, with way too many hours passed:

 

Sketches:

Code (it's really ugly I know):

var prevSec;
var millisRolloverTime;
 
var inc = 0.1;
var scl = 20;
var cols, rows;
var numpart = 0;
 
var zoff = 0;
var radius = 250;
var particles = [];
var flowfield;
 
function setup() {
  createCanvas(700, 700);
  background(40);
  cols = floor(width/scl);
  rows = floor(height/scl);
  noiseSeed(day*year);
  millisRolloverTime = 0;
 
  //seconds particles
  for(var i = 0; i < 60; i++)
  {
    var angle = 3*PI/2 + (TWO_PI/60*i);
    particles[i] = new Particle(radius*cos(angle)+width/2, radius*sin(angle)+height/2);
  }
 
  //minute particles
  for(var i = 60; i < 120; i++)
  {
    var angle = 3*PI/2 + (TWO_PI/60*(i-60));
    particles[i] = new Particle(radius*cos(angle)+width/2, radius*sin(angle)+height/2);
    particles[i].type = 1;
  }
 
  //hour particles
  for(var i = 120; i < 132; i++)
  {
    var angle = 3*PI/2 + (TWO_PI/12*(i-120));
    particles[i] = new Particle(radius*cos(angle)+width/2, radius*sin(angle)+height/2);
    particles[i].type = 2;
  }
 
 
  flowfield = new Array(cols*rows);
}
 
function draw() {
  //draw the circle of circles
  for(var i = 0; i < 12; i++)
  {
    var angle = 3*PI/2 + (TWO_PI/12*i);
    noFill();
    strokeWeight(1);
    stroke(255, 50);
    ellipse(radius*cos(angle)+width/2, radius*sin(angle)+height/2, 30, 30);
    strokeWeight(0.05);
  }
 
  background(0,3);
 
  strokeWeight(5);
  stroke(255);
  var angle = 3*PI/2 + (TWO_PI/60*second());
 
  var nextsec = abs((second()+1)%60);
  var angle = 3*PI/2 + (TWO_PI/60*nextsec);
  particles[second()].active = true;
  particles[nextsec] = new Particle(radius*cos(angle)+width/2, radius*sin(angle)+height/2);
  particles[second()].maxspeed = 5;
 
  var nextmin = abs((minute()+1)%60);
  var angle = 3*PI/2 + (TWO_PI/60*nextmin);
  particles[60+minute()].active = true;
  particles[nextmin+60] = new Particle(radius*cos(angle)+width/2, radius*sin(angle)+height/2);
  particles[60+minute()].type = 1;
  particles[60+minute()].maxspeed = 3;
 
  var nexthour = abs((hour()+1)%60);
  var angle = 3*PI/2 + (TWO_PI/12*nexthour);
  var h = hour()%12;
  particles[120+h].active = true;
  particles[120+h].type = 2;
  particles[120+h].maxspeed = 1.5;
 
 
 
  var yoff = 0;
  for (var y = 0; y < rows; y++)
  {
    var xoff = 0;
    for (var x = 0; x < cols; x++)
    {
      var index = (x+y*cols);
      var angle = noise(xoff, yoff, zoff)*TWO_PI*4;
      var v = p5.Vector.fromAngle(angle);
      v.setMag(1);
      flowfield[index] = v;
      xoff += inc;
    }
    yoff += inc;
    zoff += 0.0005;
  }
for (var i = 0; i < particles.length; i++) {
    if (particles[i].active) {
      particles[i].follow(flowfield);
      particles[i].update();
      particles[i].show();
      particles[i].edges();
    }
  }
strokeWeight(10);
  stroke(86, 255, 238);
  var angle = 3 * PI / 2 + (TWO_PI / 60 * (minute()));
  point(radius * cos(angle) + width / 2, radius * sin(angle) + height / 2);
  strokeWeight(5);
}
 
function Particle(startx, starty) {
  this.active = false;
  this.pos = createVector(startx, starty);
  this.vel = createVector(0, 0);
  this.acc = createVector(0, 0);
  this.maxspeed = 2;
  this.type = 0;
 
  this.h = 0;
 
  this.prevPos = this.pos.copy();
 
  this.update = function() {
    this.vel.add(this.acc);
    this.vel.limit(this.maxspeed);
    this.pos.add(this.vel);
    this.acc.mult(0);
  }
 
this.follow = function(vectors) {
    var x = floor(this.pos.x / scl);
    var y = floor(this.pos.y / scl);
    var index = x + y * cols;
    var force = vectors[index];
    this.applyForce(force);
  }
 
  this.applyForce = function(force) {
    this.acc.add(force);
  }
 
  this.show = function() {
 
    if (this.active) {
      if (this.type == 0) {
        strokeWeight(5);
        stroke(255);
        var angle = 3 * PI / 2 + (TWO_PI / 60 * (second()));
        point(radius * cos(angle) + width / 2, radius * sin(angle) + height / 2);
        strokeWeight(1);
      } else if (this.type == 2) {
        strokeWeight(20);
        stroke(255, 111, 86);
        var angle = 3 * PI / 2 + (TWO_PI / 12 * (hour()));
        point(radius * cos(angle) + width / 2, radius * sin(angle) + height / 2);
        strokeWeight(15);
      } else if (this.type == 1) {
        strokeWeight(10);
        stroke(86, 255, 238);
        var angle = 3 * PI / 2 + (TWO_PI / 60 * (minute()));
        point(radius * cos(angle) + width / 2, radius * sin(angle) + height / 2);
        strokeWeight(5);
      }
 
      line(this.pos.x, this.pos.y, this.prevPos.x, this.prevPos.y);
      this.updatePrev();
    }
  }
 
  this.updatePrev = function() {
    this.prevPos.x = this.pos.x;
    this.prevPos.y = this.pos.y;
  }
 
  this.edges = function() {
 
    if (this.pos.x > width) {
      this.pos.x = 0;
      this.updatePrev();
    }
    if (this.pos.x < 0) { this.pos.x = width; this.updatePrev(); } if (this.pos.y > height) {
      this.pos.y = 0;
      this.updatePrev();
    }
    if (this.pos.y < 0) {
      this.pos.y = height;
      this.updatePrev();
    }
  }
}

weirdie-LookingOutwards02

Politics of Power by automato

Politics of Power is an interactive installation piece that uses different "models" of plugs - Model D, M, and T - to simulate different ideological structures in the politics of networks by using different algorithms to distribute power between the lights which are plugged in. For example, in Model M, power is distributed hierarchically, where the topmost light gets the most power, and the bottom row gets very little. The "monarch" may randomly die, but this does not give any more power to those that were beneath it.

I was intrigued by this project because it played with a dual meaning of the word "power" and was able to convey such a complex issue in a simple and entertaining way. I think this project alludes to a greater link between generative art and sculpture, one that can react to viewers and change its behavior accordingly. To take this piece even further, I think it would be exciting to be able to combine different hierarchical structures and see how they interact with one another - how a monarchy influences a democracy and the vying for power between them.

The artists behind automato are Simone Rebaudengo, Matthieu Cherubini, Saurabh Datta and Lorenzo Romagnoli. Their work often deals with the ethics of technology, and the idea of how technology can be used to reflect human ethics.

weirdie-Reading03

I think that categorizing things as either "First Word Art" or "Last Word Art" is difficult, if not impossible to do except in hindsight. I think every artist strives to make one or the other, but there is no real way to know other than to see what follows, and as such I believe most projects will fall somewhere in the middle.

Particularly the idea of "Last Word Art" is troublesome to me. It seems to require a universal understanding that the best of the best has already been created, and to attempt to refine the idea any further would be ridiculous, but I think that overlooks the fact that the most innovative ideas draw inspiration from the past as part of the process.

Since technology is constantly evolving, one might anticipate that a lot of "First Word Art" can stem from the development of technology. However, just because something is new and different doesn't necessarily mean it's valuable simply because it utilizes a new material or concept (though it certainly can be).

weirdie-AnimatedLoop

My initial inspiration for the piece was simply thinking about how objects could visually track movement, and because I'm me I wanted to do that in kind of a weird way. The first step was creating the eyes that would be able to track movement, initially using the mouse for testing. After that, I tried a bunch of functions to find a path for the fly that I liked, eventually picking a 3-petaled polar graph "flower" because of the way it looped around 3 of the eyes. Getting the fly to face the direction it was traveling was a little tricky, as that involved calculating the direction of the next frame of the fly and rotating it towards that. I chose the Double Exponential Ogee function because I wanted the fly to slow down slightly going around corners, and speed up when it was traveling in more of a straight line, and the Ogee function had that pattern - fast, slow, fast - and so I used that while phase-shifting it a bit. Overall, I'm pretty pleased with the result, as I came pretty close to that concept that I had in mind and I learned a lot about mapping and direction changes in the process. I initially thought about having some of the eyes blink randomly or blink in response to the fly coming too close. However, with the short length of the GIF I chose not too, but it could be something to try in the future. I also think the addition of motion blur to the fly would have made the appearance more smooth.

Sketches:

Code:

function renderMyDesign(percent) {
 
  // here, I set the background
	background(255, 147, 140);
  smooth();
 
  // coordinates of the fly
  var flyx = 0;
  var flyy = 0;
 
  var p = map(percent, 0, 1, 0, 3.14);
 
  if(percent >=0 && percent <= 0.3333) { var frac = map(percent, 0, 0.3333, 0, 1); var speed = function_DoubleExponentialOgee(frac, 0.15); p = map(speed, 0, 1, 0, PI/3); } else if(percent > 0.333 && percent <= 0.666)
  {
    var frac = map(percent, 0.3333, 0.666, 0, 1);
  	var speed = function_DoubleExponentialOgee(frac, 0.15);
  	p = map(speed, 0, 1, PI/3, 2*PI/3);
  }
  else
  {
    var frac = map(percent, 0.666, 1, 0, 1);
  	var speed = function_DoubleExponentialOgee(frac, 0.15);
  	p = map(speed, 0, 1, 2*PI/3, PI);
  }
 
  var r = cos(3*(p+PI/2));
  var nr = cos(3*(p+0.0157+PI/2));
 
  var jousx = map(r*cos((p+PI/3+PI/2)), -1, 1, 30, 630);
  var jousy = map(r*sin((p+PI/3+PI/2)), -1, 1, 30, 630);
  var nextx = map(nr*cos((p+0.0157 + PI/3+PI/2)), -1, 1, 30, 630);
  var nexty = map(nr*sin((p+0.0157 + PI/3+PI/2)), -1, 1, 30, 630);
 
  var jx = map(jousx, 30, 630, -1, 1);
  var jy = map(jousy, 30, 630, -1, 1);
  var nx = map(nextx, 30, 630, -1, 1);
  var ny = map(nexty, 30, 630, -1, 1);
 
  var direction = atan2((ny - jy), (nx - jx)) + PI/2.2;
 
  flyx = jousx;
  flyy = jousy;
 
  //eyeballs!!!
  noStroke();
 
  for (var r = 0; r < 5; r++) {
    for (var c = 0; c < 4; c++) {
      var midx = 0;
      var midy = 0;
      if (r % 2 == 0) {
        midx = 106.66 + c * 213.33;
        midy = 160 * r;
      } else {
        midx = 213.333 * c;
        midy = 160 * r
      }
 
      //direction of the fly
      var fx = map(flyx, 0, width, -1, 1);
      var fy = map(flyy, 0, height, -1, 1);
      var mx = map(midx, 0, width, -1, 1);
      var my = map(midy, 0, height, -1, 1);
      var dir = atan2((fy - my), (fx - mx));
 
      var amp = 30;
      if (dist(midx, midy, flyx, flyy) <= 30)
        amp = dist(midx, midy, flyx, flyy);
 
      //white of eye
      fill(244, 244, 233);
      ellipse(midx, midy, 130, 130);
 
      push();
      translate(midx + amp * cos(dir), midy + amp * sin(dir));
      rotate(dir);
 
      //distortion value
      var d = constrain(dist(midx, midy, flyx, flyy), 0, 30);
      var squish = map(d, 0, 30, 1, 0.9);
 
      //cornea
      stroke(20, 114, 80);
      strokeWeight(3);
      fill(61, 249, 187);
      ellipse(0, 0, 70 * squish, 70);
      noStroke();
      //pupil
      fill(19, 20, 45);
      ellipse(0, 0, 30 * squish, 30);
      pop();
    }
  }
 
  push();
  fill(19, 20, 45);
 
  translate(flyx, flyy);
  rotate(direction);
  stroke(19, 20, 45);
  strokeWeight(1.5);
 
  ellipse(0, 0, 20, 30);
  ellipse(0, -15, 16, 10);
 
  line(0, 0, -17, -17);
  line(0, 0, 17, -17);
  line(-17, -17, -20, -15);
  line(17, -17, 20, -15);
 
  line(0, -10, 17, 3);
  line(0, -10, -17, 3);
  line(17, 3, 20, 6);
  line(-17, 3, -20, 6);
 
  line(0, 0, 17, 17);
  line(0, 0, -17, 17);
 
  fill(255, 89, 0);
  noStroke();
  ellipse(6, -17, 6, 8);
  ellipse(-6, -17, 6, 8);
 
  fill(160, 255, 223, 150);
  beginShape();
  vertex(0, -10);
  vertex(-15, 0);
  vertex(-15, 25);
  vertex(-4, 15);
  vertex(0, -10);
  endShape();
 
  beginShape();
  vertex(0, -10);
  vertex(15, 0);
  vertex(15, 25);
  vertex(4, 15);
  vertex(0, -10);
  endShape();
  pop();
 
} 
// Double Exponential Ogee function ('_a' is the slope)
//(it goes fast, slowwww, fast)
// See https://github.com/IDMNYU/p5.js-func/blob/master/lib/p5.func.js
// From: https://idmnyu.github.io/p5.js-func/
//===================================================
  function function_DoubleExponentialOgee (x, a){
  functionName = "Double-Exponential Ogee";
 
  var min_param_a = 0.0 + Number.EPSILON;
  var max_param_a = 1.0 - Number.EPSILON;
  a = constrain(a, min_param_a, max_param_a); 
 
  var y = 0;
  if (x<=0.5){
    y = (pow(2.0*x, 1.0-a))/2.0;
  } 
  else {
    y = 1.0 - (pow(2.0*(1.0-x), 1.0-a))/2.0;
  }
  return y;
}

weirdie-Scope

http://cmuems.com/2018/60212f/wp-content/uploads/2018/09/Buggos.png

For the praxinoscope I just wanted to make some little bugs crawling around. There are two bugs coded that start from opposite ends and walk along a sine curve. It was a good learning process in making the legs draw properly and for all of the pieces to move together. Pretty simple, but this partially inspired my final GIF design.

function drawArtFrame ( whichFrame ) {
// Draw the artwork for a generic frame of the Praxinoscope,
// given the framenumber (whichFrame) out of nFrames.
// NOTE #1: The "origin" for the frame is in the center of the wedge.
// NOTE #2: Remember that everything will appear upside-down!
 
stroke(0);
strokeWeight(1.5);
fill(0);
 
//bug one!
var moveY = whichFrame * 17;
var a = 20*cos(whichFrame*0.5 + 50);
 
ellipse(0+a, 80-moveY, 12, 20);
ellipse(0+a, 70-moveY, 5, 5);
 
line(0+a, 80-moveY, 10+a, 70-moveY);
line(0+a, 80-moveY, -10+a, 70-moveY);
 
line(0+a, 75-moveY, 10+a, 90-moveY);
line(0+a, 75-moveY, -10+a, 90-moveY);
 
line(0+a, 75-moveY, 12+a, 80-moveY);
line(0+a, 75-moveY, -12+a, 80-moveY);
 
line(0+a, 70-moveY, 5+a, 65-moveY);
line(0+a, 70-moveY, -5+a, 65-moveY);
 
//bug two!
 
rotate(PI);
var a = -20*cos(whichFrame*0.2 + 50);
 
ellipse(0+a, 60-moveY, 12, 20);
ellipse(0+a, 50-moveY, 5, 5);
 
line(0+a, 60-moveY, 10+a, 50-moveY);
line(0+a, 60-moveY, -10+a, 50-moveY);
 
line(0+a, 55-moveY, 10+a, 70-moveY);
line(0+a, 55-moveY, -10+a, 70-moveY);
 
line(0+a, 55-moveY, 12+a, 60-moveY);
line(0+a, 55-moveY, -12+a, 60-moveY);
 
line(0+a, 50-moveY, 5+a, 45-moveY);
line(0+a, 50-moveY, -5+a, 45-moveY);
 
}

 

weirdie-Reading02

1A. Something I've always been fascinated with that exhibits effective complexity is the appearance of the Fibonacci sequence in nature. Not only do (most) flowers have a number of petals which is a Fibonacci number, but the arrangement of the seeds in the centers of flowers is determined by Fibonacci numbers. For example, the flower below has seeds arranged in spirals. There are 55 spirals going to the right, and 34 spirals going to the left, both numbers in the Fibonacci sequence. This is an example of almost total order - while different flowers have different numbers, flowers of the same type are virtually indistinguishable from one another.

 

 

 

 

 

 

 

1B. I relate to Galanter's idea of the problem of meaning. While I value creating works that are visually or technically interesting and enjoyable to see, there is a big difference for me between that and a piece that holds a lot of meaning. I struggle with whether or not the process or the product is more important to me as well as the viewer, but I think they are equally as valuable in different ways. Intent and concept are important in making art to me, but I'm certainly open to "happy accidents" that are part of the process of making generative art.

weirdie-Interruptions

Observations

  1. The artwork is square
  2. The artwork consists of many short black lines on a white backgrounds
  3. All of the lines have the same length
  4. The lines do not go off of the page
  5. There is a white border around the artwork
  6. There are random, small sections which do not have any lines
  7. The lines have an average direction, whether that be vertical or horizontal
  8. Very few lines do not touch another line
  9. There are sections of repeating patterns of lines
  10. The lines have roughly the same amount of space between them
  11. The lines which touch do so barely - they either just hit the edge of another line or cross over only slightly
  12. The lines appear to be in columns
  13. Lines intersect at most 3 other lines, most likely 2, and sometimes no other lines.

I started by placing the lines into a grid, but faced the problem of many overlapping "X's", so I wrote a function that found and removed them. This created the problem of too much space between lines, and it took bringing the image into Photoshop and plotting points to realize it was the midpoints that were on the grid, and not either endpoint.

This realization made the lines "fit together" properly, which is what I was finding most difficult to replicate. The noise function was used to generate values based on each line's coordinates, deleting those which were over a certain threshold to make gaps.

I now appreciate that generative art is not nearly as random as it initially appears, and that there are several layers of rules and calculations behind it. After many versions, I believe my replication is close, though hers may have nicer, more balanced empty sections.

weirdie-Intersections

var boolDoRefresh;
var numlines = 12;
var length = 400;
var lines = new Array(numlines);
 
function setup() {
  createCanvas(720, 480);
  background(21, 62, 71);
  boolDoRefresh = true;
}
 
function draw() {
  if (boolDoRefresh) {
    //reset background
    background(21, 62, 71);
    stroke(24, 191, 179);
 
    //create lines
    for(var x = 0; x < numlines; x++) 
    {
      var xstart = int(random(0, width)); 
      var ystart = int(random(0, height)); 
      var slope = random(0, 6.28); 
      var xend = length*cos(slope) + xstart; 
      var yend = length*sin(slope) + ystart; 
      lines[x] = [xstart, ystart, xend, yend]; 
    } 
    //check intersections 
    for(var l1 = numlines-1; l1 >=0; l1--)
    {
      var l2 = l1-1;
      while(l2 >= 0)
      {
        line1 = lines[l1];
        line2 = lines[l2];
        var cross = intersect(line1[0], line1[1], line1[2], line1[3], 
                              line2[0], line2[1], line2[2], line2[3]);
        if(cross != false)
        {
          fill(28, 229, 242);
          noStroke();
          ellipse(cross.x, cross.y, 20, 20);
        }
        l2--;
      }
    }
 
    //draw lines
    {
      for(x = 0; x < numlines; x++)
      {
        stroke(24, 191, 179);
        line(lines[x][0], lines[x][1], lines[x][2], lines[x][3]);
      }
    }
 
    boolDoRefresh = false;
  }
}
 
// original calculation by Paul Bourke
// Implementation by Leo Bottaro
// http://paulbourke.net/geometry/pointlineplane/javascript.txt
// Determine the intersection point of two line segments
// Return FALSE if the lines don't intersect
function intersect(x1, y1, x2, y2, x3, y3, x4, y4) {
 
  // Check if none of the lines are of length 0
	if ((x1 === x2 && y1 === y2) || (x3 === x4 && y3 === y4)) {
		return false
	}
 
	denominator = ((y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1))
 
  // Lines are parallel
	if (denominator === 0) {
		return false
	}
 
	let ua = ((x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3)) / denominator
	let ub = ((x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3)) / denominator
 
  // is the intersection along the segments
	if (ua < 0 || ua > 1 || ub < 0 || ub > 1) {
		return false
	}
 
  // Return a object with the x and y coordinates of the intersection
	let x = x1 + ua * (x2 - x1)
	let y = y1 + ua * (y2 - y1)
 
	return {x, y};
}
 
function mousePressed() {
  boolDoRefresh = true;
}

weirdie-IterationExercise

var boolDoRefresh;
 
function setup() {
  createCanvas(400, 400);
  background(21, 62, 71);
  boolDoRefresh = true;
}
 
function draw() {
  if (boolDoRefresh) {
 
    background(21, 62, 71);
    noStroke();
 
    for (var r = 0; r < 8; r++)
    {
      for (var c = 0; c < 8; c++)
      {
    		var wow = int(random(0,12));
        if(wow == 0)
        {
          fill(28, 229, 242);
          ellipse(r*46+40, c*46+40, 40, 40);
        }
        else
        {
          fill(24, 191, 179);
          rect(r*46+20, c*46+20, 40, 40);
        }
      }
    }
    boolDoRefresh = false;
  }
}
 
function mousePressed() {
  boolDoRefresh = true;
}