sapeck-Clock

With no human present:

When a human is present, the time runs away from the human (either via face detection or mouse click):

The time running away to the other side of the screen:

Embeded demo (responds to both mouse clicks and face detection in the browser):

This clock is scared of people. You can't run away from time if it runs away from you. I imagine this clock on someone's nightstand or in their kitchen like a pet fish. Like a fish swims to the opposite side of the bowl when a hand nears, the time runs to the opposite side of the screen when anyone is in view. The clock is both infuriating, as it doesn't tell you the time when you need it and reflective how necessary time is. I don't think I am as experienced enough to make the time look truly animated and living. I added a flicker and blinks to make it seem more alive, but the motion from an easing function isn't natural enough.

/* Sapeck    9/20/2017
/* Sapeck    9/20/2017
"sapeck-Clock"
60-212                        Carnegie Mellon University
Copyright (C) 2018-present  Sapeck
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License version 3 as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*/
 
var DEBUG = false;
 
var prevSec;
var millisRolloverTime;
var mils;
var moveStartTime = 0;
var sideCounter = 0;
var backColor = 255;
var returning = false;
 
var moveTime = [0, 0, 0];
var sideMoveTime = 0;
var currSideToX = 0;
var moving = false;
var sideMoving = false;
 
var ctracker;
 
function setup() {
  createCanvas(800, 800);
  millisRolloverTime = 0;
 
  var videoInput = createCapture();
  videoInput.size(640, 480);
  //videoInput.position(0, 0);
 
  ctracker = new clm.tracker();
  ctracker.init();
  ctracker.start(videoInput.elt);
}
function draw() {
  time = [hour(), minute(), second(),0];
  updateMils(time[2]);
  time[3] = mils;
  showTime = [nf(time[0],2), nf(time[1],2), nf(time[2],2), nf(time[0],3)];
  stutterDelay = false;
 
 
  if (moving) backColor--;
  else backColor++;
  if (backColor > 255) backColor = 255;
  else if (backColor < 0) backColor = 0;
  background(backColor);
 
  var positions = ctracker.getCurrentPosition();
  noFill();
  stroke(color(0,255,0));
  if (positions.length > 0 && DEBUG) {
    rect(map(positions[0][0], 0, 640, 0, width), map(positions[0][1], 0, 480, 0, height), 100, 100);
  }
 
  if (positions.length > 0 || mouseIsPressed) {
    moving = true;
    sideCounter++;
    if (!sideMoving) moveStartTime = millis();
  } else {
    moving = false;
  }
 
  push();
  translate(width/2, height/2);
  y = [
    int(height/2 * function_PennerEaseOutElastic(moveTime[0])),
    int(height/2 * function_PennerEaseOutElastic(moveTime[1])),
    int(height/2 * function_PennerEaseOutElastic(moveTime[2]))
  ];    
  showTime[1] = nf(int(time[1]+(30*function_PennerEaseOutElastic(moveTime[0])*noise(moveTime[0]))),2);
  showTime[0] = nf(int(time[0]+(30*function_PennerEaseOutElastic(moveTime[0]+0.0025)*noise(moveTime[0]+0.0025))),2);
  showTime[2] = nf(int(time[2]+(30*function_PennerEaseOutElastic(moveTime[0]+0.0025)*noise(moveTime[0]+0.0025))),2);
  if (!sideMoving) {
    if (moving) {
      moveTime[0] += 0.005;
      if (moveTime[0] >= 0.020) moveTime[1] += 0.005;
      if (moveTime[1] >= 0.040) moveTime[2] += 0.005;
      for (var i=0;i<moveTime.length;i++) if (moveTime[i] > 1) moveTime[i] = 1;
    } else if (!moving && (moveTime[0] > 0 || moveTime[1] > 0 || moveTime[2] > 0)) {
      moveTime[0] -= 0.0025;
      if (moveTime[0] <= 0.980) moveTime[1] -= 0.0025;
      if (moveTime[1] <= 0.960) moveTime[2] -= 0.0025;
      for (var j=0;j<moveTime.length;j++) if (moveTime[j] < 0) moveTime[j] = 0;
    } else {
      for (var k=0;k<moveTime.length;k++) moveTime[k] = 0;
 
      if (time[3] % 22 == 0) {
        var jitterRand = int(random(0,3));
        var change = int(random(-1,2));
        showTime[jitterRand] = nf(time[jitterRand] + change, 2);
        stutterDelay = true;
      }
    }
  }
  textFont('VT323');
  textSize(100);
  fill(255 - backColor);
  if (stutterDelay) fill((255 - backColor) + random(80, 100));
  noStroke();
  textAlign(CENTER, CENTER);
 
  var xShift = 0;
  if (moveTime[0] > 0.40) {
    showTime[1] = "00";
    var blink = (""+frameCount).substr(-2, 1);
    var blinkB = (""+frameCount).substr(-3, 1);
    if (4 < blink && blink < 7 && (blinkB == 4 || blinkB == 9)) showTime[1] = "++";
  }
  if (moveTime[0] == 1 && moving) {
    if (millis() - moveStartTime >= 5000 || sideCounter > 200) {
      if (!sideMoving) {
        if (!mouseIsPressed) currSideToX = width - int(map(positions[0][0], 0, 640, 0, width));
        else currSideToX = mouseX;
        console.log(currSideToX, width, mouseX);
      }
      sideMoving = true;
 
      xShift = int((width/2 - currSideToX) * function_PennerEaseOutElastic(sideMoveTime));
 
      sideMoveTime += 0.0025;
      if (sideMoveTime > 1) sideMoveTime = 1;
    }
  } else if (!moving && sideMoving) {
    xShift = int((width/2 - currSideToX) * function_PennerEaseOutElastic(sideMoveTime));
 
    sideMoveTime -= 0.0025;
    if (sideMoveTime < 0) sideMoving = false;
  }
 
  push();
  translate(xShift, y[0]);
  text(showTime[1], 0, 0);
  pop();
 
  if ((moveTime[0] <= 0.470 && moving) || (moveTime[0] <= 0.2 && !moving)) {
    push();
    translate(0, y[1]);
    text(":", -50, 0);
    pop();
 
    push();
    translate(0, y[1]);
    text(":", 50, 0);
    pop();
 
    push();
    translate(0, y[2]);
    text(showTime[0], -100, 0);
    pop();
 
    push();
    translate(0, y[2]);
    text(showTime[2], 100, 0);
    pop();
  }
 
  pop();
 
  //if (stutterDelay) delay(500);
}
 
function updateMils(S) {
  if (prevSec != S) {
    millisRolloverTime = millis();
  }
  prevSec = S;
  mils = floor(millis() - millisRolloverTime);
}
 
// From https://github.com/golanlevin/Pattern_Master converted from Java
function function_PennerEaseOutElastic(t) {
  if (t==0) return 0.0; 
  if (t==1) return 1.0;
  var  p = 0.3;
  var  s = p/4;
 
  return (pow(2, -10*t) * sin( (t-s)*(2*PI)/p ) + 1);
}