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