yalbert-clock

For this project, I wanted to capture how time is not necessarily experienced linearly. Often time is is measured by the speed at which moments pass by. When moments are plentiful, they pass by quickly. However, when we only have a few left, we savor them lest they slip away from us. I did my best to express this in a visual way. Making this clock was fairly straightforward as I was able to reuse a particle system from a previous project. However, I'm not thrilled with how the particles clump together oddly when the minute is midway through. I think the clock is most visually pleasing at the beginning and end of the minute. Because my clock is heavily motion based, I chose to use a minute long loop. However, I think this draws away from using the clock for day long timekeeping (the hours are on the left and minutes on the right).

var offset = 25;
var plugOffset = 10;
var cirlceDist = 15;
var miniFill = 170;
var correctnessIndex = 1;
var plugThickness = 15;
var plugTipThickness = 45;
var plugTipHeight = 25;
var miniSize = 450;
 
var particleSystem;
var voiceSystem;
 
var modes = ["off", "listening", "answering"];
var currMode = "off";
 
var speech;
var mic;
 
var scenarios = []
var nullScenario;
var currScenario;
var anotherDayOfSun;
var activate;
var selectAnswers;
var demi;
var instrumental;
var startTime;
 
var instructionsX = 50;
var instructionsY = 50;
 
var barrier = 450
var baselineSec = 0
var resetted = false;
var subjectiveMin = 0
var numActiveParticles = 220;
var r
var g
var b
 
function setup(){
    angleMode(DEGREES);
    createCanvas(700, 700);
    particleSystem = new ParticleSystem();
    particleSystem.reset();
    baselineSec = second();
    subjectiveMin = minute();
 
}
 
function draw(){
    r = map(second()%60 - baselineSec, 0, 60, 0, 255);
    g = map(subjectiveMin, 0, 60, 0, 255);
    b = map(minute(), 0, 24, 0, 255);
 
    print(second(), baselineSec)
    print(second()%60 - baselineSec)
    print("")
 
    background(r, g, b);
    currMode = "listening";
    particleSystem.updateOpacity();
    particleSystem.updateVelocities();
    particleSystem.updatePosition();
    particleSystem.draw();
    // print(resetted)
    if(second()%60 == baselineSec && resetted == false){
      particleSystem.reset();
      resetted = true;
      subjectiveMin =(subjectiveMin + 1)%60
    }
    if(second() != baselineSec){
      resetted = false;
    }
    drawHours();
    drawMins();
}
 
function drawMins(){
  for(i = 1; i <= 2; i++){
    for(j = 1; j <= 30; j++){ if(i == 1){ minValue = j; }else{ minValue = j + 30; } if(subjectiveMin > minValue){
        opacity = 255;
      }else{
        opacity = 100;
      }
      fill(255-r, 255-g, 255-b, opacity);
      ellipse(width - 20 - 12*2+ 12*i, j*12 + 20, 10, 10);
      //text(minValue, width - 20 - 12*2+ 12*i, (j-1)*12 + 20)
 
    }
  }
}
 
function drawHours(){
  for(i = 0; i < 24; i++){ if(hour() > i){
      opacity = 255;
    }else{
      opacity = 100;
    }
    fill(255-r, 255-g, 255-b, opacity);
    ellipse(20, i*12 + 20, 10, 10);
  }
}
 
//courtesy of Golan Levin (http://cmuems.com/2015c/november-4/)
function ParticleSystem(){
    this.bigParticles = [];
    this.myParticles = [];
    this.nParticles = 300;
    this.particleSize = 10;
    this.isVisible = false;
    this.opacity = 0;
    this.reset = function(){
      this.myParticles = [];
      numActiveParticles = 220
        for (var i = 0; i < this.nParticles; i++) {
            var distFromCenter = random(0, miniSize/2);
            var degree = random(0, 360);
            var rx = cos(degree)*distFromCenter + width/2;
            var ry = sin(degree)*distFromCenter;
            this.myParticles[i] = new Particle(rx, ry, 10, random(.7, 1), true);
        }
 
        for(i = 0; i < 80; i+=2){
          var x1 = width/2 + i*3 + 10;
          var x2 = width/2 - i*3 - 10;
          var y = -i*3 + barrier;
          this.myParticles[i] = new Particle(x1, y, 10, random(.7, 1), false);
          this.myParticles[i+1] = new Particle(x2, y, 10, random(.7, 1), false);
        }
    }
 
    this.setForScenario = function(scenario){
        if(this.bigParticles.length != scenario.possibleAnswers.length){
            for(ansInd = 0; ansInd < scenario.possibleAnswers.length; ansInd++){
                this.addToBigParticles(scenario.answerProbabilities[ansInd]*250);
            }
        }
        for(ind = 0; ind < this.bigParticles.length; ind++){
            if(ind == scenario.selectedInd){
                this.bigParticles[ind].answering = true;
            }else{
                this.bigParticles[ind].answering = false;
            }
        }
    }
 
    this.addToBigParticles = function(goalSize){
        index = floor(random(0, particleSystem.nParticles));
        changingParticle = particleSystem.myParticles[index];
        changingParticle.goalSize = goalSize;
        particleSystem.bigParticles.push(changingParticle);
    }
 
    this.updateVelocities = function(){
        var gravityForcex = 0;
        var gravityForcey = -.17;
 
 
        for (var i = 0; i < this.myParticles.length; i++) {
            var ithParticle = this.myParticles[i];
            var px = ithParticle.px;
            var py = ithParticle.py;
 
 
            ithParticle.addForce(gravityForcex, gravityForcey);
 
            for (var j = 0; j < i; j++) { var jthParticle = this.myParticles[j]; var qx = jthParticle.px; var qy = jthParticle.py; var mutualAttractionAmount = (ithParticle.mass * jthParticle.mass)/2; var dx = px - qx; var dy = py - qy; var dh = sqrt(dx*dx + dy*dy); var componentInX = dx/dh; var componentInY = dy/dh; var proportionToDistanceSquared = 1.0/(dh*dh); var attractionForcex = mutualAttractionAmount * componentInX * proportionToDistanceSquared; var attractionForcey = mutualAttractionAmount * componentInY * proportionToDistanceSquared; if (dh > (ithParticle.mass + jthParticle.mass)/2 * 8) {
                    ithParticle.addForce( attractionForcex,  attractionForcey); // add in forces
                    jthParticle.addForce(-attractionForcex, -attractionForcey); // add in forces
                }else{
                    ithParticle.addForce( -attractionForcex,  -attractionForcey); // add in forces
                    jthParticle.addForce(attractionForcex, attractionForcey);  // add in forces
                }
            }
        }
    }
 
    this.updatePosition = function(){
        for (var i = 0; i < this.myParticles.length; i++) {
                particle = this.myParticles[i];
                particle.update();
        }
    }
 
    this.draw = function(){
        for (var i = 0; i < this.myParticles.length; i++) { particle = this.myParticles[i]; particle.render(this.opacity); } } this.updateOpacity = function(){ if(this.isVisible == false){ //if(this.opacity > 0){
                this.opacity = this.opacity*.9 +0*.1;
            //}
        }else{
            //if(this.opacity < 255){
                this.opacity = this.opacity*.9 + 255*.1 ;               
            //}
        }
 
    }
}
 
 
 
 
//courtesy of Golan Levin (http://cmuems.com/2015c/november-4/)
function Particle(x, y, mass, personalOpacity, canMove){
    this.personalOpacity = personalOpacity;
    this.size = mass;
    this.px= x;
    this.py=y;
    this.vx= 0;
    this.vy=0;
    this.damping = 0.96;
    this.mass = (pow(mass, 3))/100;
    this.bLimitVelocities=true;
    this.bPeriodicBoundaries=false;
    this.bElasticBoundaries=true;
    this.goalSize = mass;
    this.answering = false;
    this.opacity = 0;
    this.movable = canMove;
    this.passedThrough = false;
 
    this.addForce=function(fx,fy){
        var ax=fx/this.mass*1.5;
        var ay=fy/this.mass*1.5;
        if(this.goalSize < 30){ this.vx+=ax; this.vy+=ay; }else{ this.vx+=ax*.1; this.vy+=ay*.1; } } this.update=function(){ this.vx*=this.damping; this.vy*=this.damping; this.limitVelocities(); this.handleBoundaries(); if(this.movable){ this.py-=this.vy; this.px-=this.vx; } // if(abs(this.goalSize-this.size) > 1){
        //     this.size = this.size*.9 + this.goalSize*.1;
        // }
 
        if(this.py > barrier){
          if(this.passedThrough == false){
            numActiveParticles -=1
          }
          this.passedThrough = true
        }
    }
    this.limitVelocities=function(){
        if(this.bLimitVelocities){
            var speed=sqrt(this.vx*this.vx+this.vy*this.vy);
            var maxSpeed=10;
            if(speed>maxSpeed){
                this.vx*=maxSpeed/speed;this.vy*=maxSpeed/speed;
            }
        }
    }
    this.inBounds=function(){
        return(this.px<width&&this.px>0&&this.py<height&&this.py>0);
    }
    this.handleBoundaries=function(){
        if(this.bPeriodicBoundaries){
            if(this.px>width)
                this.px-=width;
            if(this.px<0) this.px+=width; if(this.py>height)
                this.py-=height;
            if(this.py<0) this.py+=height; }else if(this.bElasticBoundaries){ if(particle.py > height){
                this.vy = this.vy*-1; // draw all particles
                this.vx = this.vx*-1;
            }
        }
    }
    this.render=function(parentOpacity){
 
        if(abs(this.goalSize-this.size) < 15 && this.goalSize < 20){
 
                // this.opacity = 255 -getDist(this.px, this.py, width/2, height/2)*1.2 //+ this.size*this.size;
                // this.opacity = this.opacity*this.personalOpacity 
            noStroke();
 
            if(this.movable){
              if(this.passedThrough == false){
                opacity = 255;
              }else{
                opacity = map(numActiveParticles, 220, 0, 100, 25) //50;
              }
 
              fill(255, 255, 255, opacity);
              ellipse(this.px,this.py,this.size,this.size);
            }
        }else{
            if(this.answering){
                numLayers = 5;
            }else{
                numLayers = 1;
            }
           for(j = 0; j < numLayers; j++){
                diameter = this.size - j*5
                r = lerp(255, 40, 1 - j*.1);
                g = lerp(255, 140, 1 - j*.1);
                b = lerp(255, 250, 1 - j*.1);
 
                fill(r, g, b, 255*(parentOpacity/255));
                ellipse(this.px,this.py,diameter,diameter);
           }
 
        }
    }
}
 
function getDist(x1, y1, x2, y2){
    return sqrt(pow(x1 - x2, 2) + pow(y1 - y2, 2))
}
 
//for testing
 
function mousePressed(){
 
}
 
function keyPressed(){
    if(particleSystem.isVisible){
        particleSystem.isVisible = false;
    }else{
        particleSystem.isVisible = true;
    }
}