block by dribnet d80f76ef698c268da0b46e550198a47f

MNIST clock

Full Screen

MNIST clock

Digits rendered with a variational auto-encoder and 10 concept vectors in 8 dimensinoal latent space. The digit style changes as the concept vectos are applied to a drifting anchor point.

(note: neural net decoder weights are currently 6.5M so loading might take a few seconds before clock starts)

index.html

<head>
    <meta charset="utf-8">
    <script src="//cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.8/p5.js"></script>
    <script src="//cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.8/addons/p5.dom.js"></script>
    <script language="javascript" type="text/javascript" src=".purview_helper.js"></script>
    <script src="keras.js"></script>
    <script src="https://cdn.jsdelivr.net/bluebird/latest/bluebird.min.js"></script>
    <script language="javascript" type="text/javascript" src="clock.js"></script>
    <script language="javascript" type="text/javascript" src="sketch.js"></script>
</head>
<body style="background-color:white">
    <div class="outer">
        <div class="inner">
            <div id="canvasContainer"></div>
        </div>
    </div>
</table>
</body>

clock.js

/*
 * us p5.js to draw a clock on a 960x500 canvas
 */ 

// in browser, URLs can be relative or absolute
const model = new KerasJS.Model({
  filepaths: {
    model: 'mnist_06_110_decoder.json',
    weights: 'mnist_06_decoder_weights_weights.buf',
    metadata: 'mnist_06_decoder_weights_metadata.json'
  },
  gpu: true
})

var concept_vecs = [
  [-0.097372,  0.598627, -0.427888, -0.388575, -0.447317,  0.543890, -0.420167, -0.526876],
  [ 0.482085, -0.421570,  0.156896,  0.101969,  0.710080, -0.315153,  0.189396, -0.628475],
  [ 0.199009,  0.302628, -0.304984,  0.743103, -0.321666, -0.196440,  0.837206, -0.164660],
  [ 0.702927,  0.061100,  0.391677,  0.078674, -0.263728,  0.399588, -0.117211,  0.555933],
  [-0.887413,  0.153023,  0.637169, -0.192469,  0.257092, -0.610011,  0.369441,  0.231632],
  [ 0.216774, -0.898855,  0.178582, -0.546435, -0.145294,  0.506996,  0.026063,  0.054160],
  [ 0.154096,  0.222272,  0.355234, -0.828151, -0.295889, -0.548858,  0.320933, -0.284068],
  [-0.004918, -0.491446,  0.105555,  0.905816, -0.065926,  0.348899, -0.759633, -0.242949],
  [-0.026785,  0.249264, -0.292006, -0.133150,  0.454588,  0.370761,  0.128081,  0.253320],
  [-0.478251,  0.057617, -0.203836, -0.186867,  0.461135,  0.025850, -0.784070, -0.052860]
];

var curAnchor = [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1];
var curDAnchor = [0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6];

var curModelImages = [null, null, null, null, null, null];
var curConceptVecs = [null, null, null, null, null, null];
var digitPositions = [null, null, null, null, null, null];

var MODEL_LOADING = 0;
var MODEL_READY = 1;
var MODEL_LOAD_ERROR = 2;
var MODEL_WORKING = 3;
var modelStatus = MODEL_LOADING;

function local_setup() {
  model.ready()
    .then(() => {
      print("Model says it is ready")
      modelStatus = MODEL_READY;
      // redraw();
    })
    .catch(err => {
      // handle error
      print("Model says LOAD_ERROR")
      modelStatus = MODEL_LOAD_ERROR;
      // redraw();
    })

  for(var i=0; i<6; i++) {
    curModelImages[i] = createImage(56, 56);
  }
  for(var i=0; i<8; i++) {
    curDAnchor[i] = random(0.01, 0.05);
  }

  var s = 24;
  var hour_pos = [80, height/2 - 2 * s];
  digitPositions[0] = [hour_pos[0] + 0.0 * 5 * s, hour_pos[1]];
  digitPositions[1] = [hour_pos[0] + 1.0 * 5 * s, hour_pos[1]];
  digitPositions[2] = [hour_pos[0] + 2.5 * 5 * s, hour_pos[1]];
  digitPositions[3] = [hour_pos[0] + 3.5 * 5 * s, hour_pos[1]];
  digitPositions[4] = [hour_pos[0] + 5.0 * 5 * s, hour_pos[1]];
  digitPositions[5] = [hour_pos[0] + 6.0 * 5 * s, hour_pos[1]];
}

function move_anchor() {
  for(var i=0; i<8; i++) {
    var next = curAnchor[i] + curDAnchor[i];
    if(next > 0.5) {
      curDAnchor[i] = random(-0.01, -0.03);
      next = curAnchor[i] + curDAnchor[i];
    }
    else if(next < -0.5) {
      curDAnchor[i] = random(0.01, 0.03);
      next = curAnchor[i] + curDAnchor[i];
    }
    curAnchor[i] = next;
  }
  // print(curAnchor);
}

function digits_from_num(num) {
  digits = []
  if (num < 10) {
    digits.push(0);
  }
  else {
    n1 = Math.floor(num / 10);
    digits.push(n1);
  }
  n2 = Math.floor(num % 10);
  digits.push(n2);
  return digits;
}

function interp_vec(frac, v1, v2) {
  var v = new Array(8);
  for(var i=0; i<8; i++) {
    v[i] = lerp(v1[i], v2[i], frac)
  }
  return v;
}

function add_vec(v1, v2) {
  var v = new Array(8);
  for(var i=0; i<8; i++) {
    v[i] = v1[i] + v2[i];
  }
  return v;  
}

// numbers waiting to be drawn
var pendingOutput = [null, null, null, null, null, null];
var digit_in_flight = false;

function firePrediction() {
  var predict_map = [];
  for(var i=0; i<6; i++) {
    predict_map.push({ input_1: curConceptVecs[i] })
  }
  modelStatus = MODEL_WORKING;
  Promise.mapSeries(curConceptVecs, arr => model.predict({ input_1: arr }))
  .then(outputs => {
    for(var i=0; i<6; i++) {
      pendingOutput[i] = outputs[i]['convolution2d_5']
    }
    modelStatus = MODEL_READY;
  })

  // const inputData = { input_1: new Float32Array(v_sum) };
  // model.predict(inputData).then(outputData => {
  //   pendingOutput[ix] = outputData['convolution2d_5'];
  //   digit_in_flight[ix] = false;
  // });
}

function get_cur_concept_vec(frac, num1, num2) {
  var v1 = concept_vecs[num1];
  var v2 = concept_vecs[num2];
  var v_interp = interp_vec(frac, v1, v2);
  var v_sum = add_vec(curAnchor, v_interp);
  return new Float32Array(v_sum);
}

var first_time = true;

function draw_clock(hour, minute, second, millis, alarm) {
  if(first_time) {
    local_setup();
    first_time = false;
    background(0);
  }

  move_anchor();

  // is alarm going off?
  /*
  if (alarm == 0) {
    if (second % 2 == 0) {
      background(0,0,100);      
    }
    else {
      background(100,100,0);      
    }
  }
  else {
    background(0);
  }
  */
  // background(0);
  blendMode(BLEND);
  fill(0, 0, 0, 96);
  rect(0, height/3, width, 2*height/3);
  blendMode(ADD);

  // draw what digits we have
  var one_was_pending = false;
  for(var d=0;d<6;d++) {
    if(pendingOutput[d] != null) {
      one_was_pending = true;
      var curOutput = pendingOutput[d];
      pendingOutput[d] = null;

      curModelImages[d].loadPixels();
      for (var i = 0; i < 27; i++) {
        for (var j = 0; j < 27; j++) {
          var val = (255 * curOutput[j*27 + i]);
          if(val == null || curModelImages[d] == null) {
            print("Found error at " + d + ":" + val +"," + curModelImages[d]);
          }
          else {
            // print(val);
            var c = color(val);
            curModelImages[d].set(i*2, j*2, c);
            curModelImages[d].set(i*2+1, j*2, c);
            curModelImages[d].set(i*2, j*2+1, c);
            curModelImages[d].set(i*2+1, j*2+1, c);
          }
        }
      }
      curModelImages[d].updatePixels();
    }
    if(curModelImages[d] != null) {
      image(curModelImages[d], digitPositions[d][0], digitPositions[d][1]);
    }
  }
  if(digit_in_flight && modelStatus == MODEL_READY && !one_was_pending) {
    digit_in_flight = false;
  }

  // see if we should compute a new set of digits
  if(modelStatus == MODEL_READY && digit_in_flight == false) {
    digit_in_flight = true;
    var precise_s = second + millis / 1000.0;
    print(hour, minute, precise_s);

    // HOURS
    next_hour = (hour + 1) % 24;
    digits1 = digits_from_num(hour);
    digits2 = digits_from_num(next_hour);
    if(second >= 50 && minute == 59 && 
        (hour == 9 || hour == 19 || hour == 23)) {
      // minute_fraction_tens = millis  / 1000.0;
      seconds_left = (second - 50) + millis / 1000.0;
      hour_fraction_tens = seconds_left  / 10.0;
    }
    else {
      hour_fraction_tens = 0;
    }
    curConceptVecs[0] = get_cur_concept_vec(hour_fraction_tens, digits1[0], digits2[0]);

    if(second >= 55 && minute == 59) {
      // minute_fraction_tens = millis  / 1000.0;
      seconds_left = (second - 55) + millis / 1000.0;
      hour_fraction_ones = seconds_left  / 5.0;
    }
    else {
      hour_fraction_ones = 0;
    }
    curConceptVecs[1] = get_cur_concept_vec(hour_fraction_ones, digits1[1], digits2[1]);

    // MINUTES
    next_minute = (minute + 1) % 60;
    digits1 = digits_from_num(minute);
    digits2 = digits_from_num(next_minute);
    if(second >= 58 && digits1[1] === 9) {
      // minute_fraction_tens = millis  / 1000.0;
      seconds_left = (second - 58) + millis / 1000.0;
      minute_fraction_tens = seconds_left  / 2.0;
    }
    else {
      minute_fraction_tens = 0;
    }
    curConceptVecs[2] = get_cur_concept_vec(minute_fraction_tens, digits1[0], digits2[0]);


    if(second === 59) {
      minute_fraction_ones = millis  / 1000.0;
    }
    else {
      minute_fraction_ones = 0;
    }
    curConceptVecs[3] = get_cur_concept_vec(minute_fraction_ones, digits1[1], digits2[1]);

    // SECONDS
    next_second = (second + 1) % 60;
    second_fraction = millis / 1000.0;
    digits1 = digits_from_num(second);
    digits2 = digits_from_num(next_second);


    if(digits1[1] === 9 && millis > 500) {
      second_fraction_tens = (millis - 500) / 500.0;
    }
    else {
      second_fraction_tens = 0;
    }
    // draw the 10 second position
    curConceptVecs[4] = get_cur_concept_vec(second_fraction_tens, digits1[0], digits2[0]);

    if(millis > 750) {
      second_fraction_ones = (millis-750) / 250.0;
    }
    else {
      second_fraction_ones = 0;
    }
    // draw the 1 second position
    curConceptVecs[5] = get_cur_concept_vec(second_fraction_ones, digits1[1], digits2[1]);
    firePrediction();
  }
}

debug.html

<head>
    <meta charset="utf-8">
    <script src="//cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.8/p5.js"></script>
    <script src="//cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.8/addons/p5.dom.js"></script>
    <script language="javascript" type="text/javascript" src=".purview_helper.js"></script>
    <script src="keras.js"></script>
    <script src="https://cdn.jsdelivr.net/bluebird/latest/bluebird.min.js"></script>
    <script language="javascript" type="text/javascript" src="debug.js"></script>
    <script language="javascript" type="text/javascript" src="clock.js"></script>
    <script language="javascript" type="text/javascript" src="sketch.js"></script>
</head>
<body style="background-color:white">
    <div class="outer">
        <div class="inner">
            <div id="canvasContainer"></div>
        </div>
        <div class="inner" id="controls">
            <table>
                <tr>
                    <td>debug</td>
                    <td id="checkboxDebug"></td>
                </tr>
                <tr>
                    <td>hours</td>
                    <td id="sliderHours"></td>
                    <td>minutes</td>
                    <td id="sliderMinutes"></td>
                    <td>seconds</td>
                    <td id="sliderSeconds"></td>
                    <td>millis</td>
                    <td id="sliderMillis"></td>
                </tr>
                <tr>
                    <td>alarm</td>
                    <td id="checkboxAlarm"></td>
                    <td>alarm_secs</td>
                    <td id="sliderAlarm"></td>
                </tr>
            </table>
        </div>
    </div>
</table>
</body>

debug.js

var DEBUG=true;

var debugCheckbox;
var hourSlider;
var minSlider;
var secSlider;
var millisSlider;
var alarmSlider;

function debug_setup() {
  debugCheckbox = createCheckbox('', false);
  debugCheckbox.parent("checkboxDebug")
  hourSlider = createSlider(0, 23, 12);
  hourSlider.parent("sliderHours")
  minSlider = createSlider(0, 59, 0);
  minSlider.parent("sliderMinutes")
  secSlider = createSlider(0, 59, 0);
  secSlider.parent("sliderSeconds")
  millisSlider = createSlider(0, 999, 0);
  millisSlider.parent("sliderMillis")
  alarmCheckbox = createCheckbox('', false);
  alarmCheckbox.parent("checkboxAlarm")
  alarmSlider = createSlider(0, 60, 0);
  alarmSlider.parent("sliderAlarm")
}

mnist_06_110_decoder.json

{"class_name": "Model", "keras_version": "1.1.0", "config": {"layers": [{"class_name": "InputLayer", "config": {"batch_input_shape": [null, 8], "input_dtype": "float32", "sparse": false, "name": "input_1"}, "inbound_nodes": [], "name": "input_1"}, {"class_name": "Dense", "config": {"W_constraint": null, "b_constraint": null, "name": "dense_2", "activity_regularizer": null, "trainable": true, "init": "glorot_uniform", "bias": true, "input_dim": null, "b_regularizer": null, "W_regularizer": null, "activation": "relu", "output_dim": 128}, "inbound_nodes": [[["input_1", 0, 0]]], "name": "dense_2"}, {"class_name": "Dense", "config": {"W_constraint": null, "b_constraint": null, "name": "dense_3", "activity_regularizer": null, "trainable": true, "init": "glorot_uniform", "bias": true, "input_dim": null, "b_regularizer": null, "W_regularizer": null, "activation": "relu", "output_dim": 12544}, "inbound_nodes": [[["dense_2", 0, 0]]], "name": "dense_3"}, {"class_name": "Reshape", "config": {"target_shape": [14, 14, 64], "trainable": true, "name": "reshape_1"}, "inbound_nodes": [[["dense_3", 0, 0]]], "name": "reshape_1"}, {"class_name": "Deconvolution2D", "config": {"W_constraint": null, "b_constraint": null, "name": "deconvolution2d_1", "activity_regularizer": null, "trainable": true, "dim_ordering": "tf", "nb_col": 3, "subsample": [1, 1], "init": "glorot_uniform", "bias": true, "nb_filter": 64, "activation": "relu", "b_regularizer": null, "W_regularizer": null, "nb_row": 3, "output_shape": [null, 14, 14, 64], "border_mode": "same"}, "inbound_nodes": [[["reshape_1", 0, 0]]], "name": "deconvolution2d_1"}, {"class_name": "Deconvolution2D", "config": {"W_constraint": null, "b_constraint": null, "name": "deconvolution2d_2", "activity_regularizer": null, "trainable": true, "dim_ordering": "tf", "nb_col": 3, "subsample": [1, 1], "init": "glorot_uniform", "bias": true, "nb_filter": 64, "activation": "relu", "b_regularizer": null, "W_regularizer": null, "nb_row": 3, "output_shape": [null, 14, 14, 64], "border_mode": "same"}, "inbound_nodes": [[["deconvolution2d_1", 0, 0]]], "name": "deconvolution2d_2"}, {"class_name": "Deconvolution2D", "config": {"W_constraint": null, "b_constraint": null, "name": "deconvolution2d_3", "activity_regularizer": null, "trainable": true, "dim_ordering": "tf", "nb_col": 2, "subsample": [2, 2], "init": "glorot_uniform", "bias": true, "nb_filter": 64, "activation": "relu", "b_regularizer": null, "W_regularizer": null, "nb_row": 2, "output_shape": [null, 28, 28, 64], "border_mode": "valid"}, "inbound_nodes": [[["deconvolution2d_2", 0, 0]]], "name": "deconvolution2d_3"}, {"class_name": "Convolution2D", "config": {"W_constraint": null, "b_constraint": null, "name": "convolution2d_5", "activity_regularizer": null, "trainable": true, "dim_ordering": "tf", "nb_col": 2, "subsample": [1, 1], "init": "glorot_uniform", "bias": true, "nb_filter": 1, "border_mode": "valid", "b_regularizer": null, "W_regularizer": null, "activation": "sigmoid", "nb_row": 2}, "inbound_nodes": [[["deconvolution2d_3", 0, 0]]], "name": "convolution2d_5"}], "input_layers": [["input_1", 0, 0]], "output_layers": [["convolution2d_5", 0, 0]], "name": "decoder"}}

mnist_06_decoder_weights_metadata.json

[{"weight_name": "dense_2_W:0", "length": 1024, "shape": [8, 128], "layer_name": "dense_2", "offset": 0, "type": "float32"}, {"weight_name": "dense_2_b:0", "length": 128, "shape": [128], "layer_name": "dense_2", "offset": 4096, "type": "float32"}, {"weight_name": "dense_3_W:0", "length": 1605632, "shape": [128, 12544], "layer_name": "dense_3", "offset": 4608, "type": "float32"}, {"weight_name": "dense_3_b:0", "length": 12544, "shape": [12544], "layer_name": "dense_3", "offset": 6427136, "type": "float32"}, {"weight_name": "deconvolution2d_1_W:0", "length": 36864, "shape": [3, 3, 64, 64], "layer_name": "deconvolution2d_1", "offset": 6477312, "type": "float32"}, {"weight_name": "deconvolution2d_1_b:0", "length": 64, "shape": [64], "layer_name": "deconvolution2d_1", "offset": 6624768, "type": "float32"}, {"weight_name": "deconvolution2d_2_W:0", "length": 36864, "shape": [3, 3, 64, 64], "layer_name": "deconvolution2d_2", "offset": 6625024, "type": "float32"}, {"weight_name": "deconvolution2d_2_b:0", "length": 64, "shape": [64], "layer_name": "deconvolution2d_2", "offset": 6772480, "type": "float32"}, {"weight_name": "deconvolution2d_3_W:0", "length": 16384, "shape": [2, 2, 64, 64], "layer_name": "deconvolution2d_3", "offset": 6772736, "type": "float32"}, {"weight_name": "deconvolution2d_3_b:0", "length": 64, "shape": [64], "layer_name": "deconvolution2d_3", "offset": 6838272, "type": "float32"}, {"weight_name": "convolution2d_5_W:0", "length": 256, "shape": [2, 2, 64, 1], "layer_name": "convolution2d_5", "offset": 6838528, "type": "float32"}, {"weight_name": "convolution2d_5_b:0", "length": 1, "shape": [1], "layer_name": "convolution2d_5", "offset": 6839552, "type": "float32"}]

preview.jpg

����JFIF��C	

			

		


��C	����"��	
���}!1AQa"q2���#B��R��$3br�	
%&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz���������������������������������������������������������������������������	
���w!1AQaq"2�B����	#3R�br�
$4�%�&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz��������������������������������������������������������������������������?����(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��(��|pK/�L�"�EJ�EQEQEQEQEQEQEQEQEQEQEQEQEQE��S���/�ͥ韴$_h���h��z�f-.Y~{FJ��=:f�|�`����?�:�oᾛ7�&����mV��Y�7B��D}��� ���P?�'o����{�~-|��#��?�o���߷������.XE嬒�ݎ0
~LW�W�������ٚ��������������B�iz!_���2�n<W�QEQEQEQEQE�������o��}���~���L�Fs˲���z��8��o�#�t+�k�^4ԓ:������r�y��G/F��@���`�@��8��!>�e���A���y6�?E�=����W�"���/��n����q�	���˛X���?k������>)�e�_��������?
��e=GӞ��_���u��_����g�_m���O�>�k��|�>� ;v���
����i����O+‡�?��1��3洂?��\��y��#|���<`��J��o�t�d�ɪ�Ǩ���>���q�y��v���QEQEQEQEQEQEQEQE������~ӟ��c��d�M�y��BO�b	�_ݙc-�^�l�����Y��P����K������^�+�ݻ��g��ػ�R���-k�
{FߩXo�N���Hy��tO�u�E\,�>��>ے��G?c(.M��6�?���T��_�c�~���'��$kr���:����۾_"(��T,j��QGN�Z�$�?�o�߳���c|=}kB_��g�ٿ����e�Fib
�[�a������	�|6�u�����yc�y��8�H>�0�㹯���&��]c����x�O/V�<�Y�O������:H���E<cM~1��������ğ+�c�xM۱�Y�]��<��?��袊(��(��(��(��HS�3@ �o.!{���q�q�8���U�����o�&���|r��-���?����^��g݋��oݤ���J�����l|W�����:���d�uc�oS��I�fw?Ҁ9��h�����q��_���O�����j|m�]�g�7�?�r��y����Y6�/�}�k�3�~�-�o��4����̽�<��4c]����>�-�C�ڏ۟ƞ��d�G��?�S��?�v_��~�J�K��:���9���o�}

~�*�vm]����[���f��F�M�������(��(��(��(��(��(��(��(GBӡ�o��<��9l�	�z��[���	Eg�+M����'��]��$��#��#�b�B����Rk�U$d9S�+��w1�?p<a�����"xb���>���Ϳn���R�~$Pu=��$_�{
�7�'����W��G���rO���%�����qz�!���+��
���>�[�
�d�s��c����tf�����	������٬j��>����/��/�t�o#�K�|�ƒ��bA�{r��_k�զ��Ce�[�6��y��ܡ�(H��^��_�?�Z/xB����/����5O�:]��<�ӣ^7lM�q�����QEQEQEQE�����8�ҭ<��������zϯ�?�&_���o�|�5�
|Y����?�m�<����my!��9�4k�}��8����"�.����Lz/������Ew��HlR�t��[�^yc�_�����`��y?�,���Zv��Q������7����G����
#�4���uC�'�o���,�݌��l�����$���;|_�	�G�|V��%�ۼ��}���,ly�W�c��^��?��?�4i���O�lZ����ž���L�NLO�v�����_h?4�	j�n��O;�&6E�~�ya$�*�F܄��vɠ�B1IN(v���(��(��(��(��(��(��(��(��(��(��(��(��+���	1�,��WǭoQ�n��-�f��Z?쟲\�Z��fI��pܢ��O5�����7��ƽ'������<�����%�>-.%��bX��<~V�9<pM௟.�|�>��>l���2���O�]XN>C	7�#�.:��(�����/?i��W~%�+�V~_�5�}�}��O��r>� -�::��@8PEPEPEPEPE�2ph��O���]�i��zō��E�Cc�0��]ӵ��oVm2��g��K������������;���~i���O���w��ן#}�˻��>C#�mIH�1��������K��R�ũj��٧�'�>c���+}����m�P��L���?�п�^���+�&�<d ?��?��U�?�{�_�u|p�����
n�4_#�������$����P���\��3��;�Ǐ#�N���|����vb��
��?��w��?{��?�<1�csb{�'Ο��F̒��w`8�_�����?
t�%�WŞw��>P�~�qas�ќ�q?#��zW�i�^��P��?hO�Z��5Vڷ�G���oG��3�$��'�(��(��(��(��(��(��(��(��(��������|d���R�m?��2wy�Ǚk?��ʿ�7�ْ�t�z@>f�'��q�X�����	��^�0�Q���#O�wش�+}�r�A'��.�G��/�/=s_k�̟���Oٞ�L�tM+�K�V^w��>���3*���đ&�g1�9��4�k
|}���a������������R��$E�\#��|��Oj��
��gZhV7�_����Ro/�1��L�_���z��W'���#��ɯ��o�������G���"�v�}���<Ixq�X�}����
�A?�|Se�MB�o���w"8������z樢�(��(��(��(���s��>|l��|9�| ��˼����c��K���G���W緥c�߿�����&���^��ϑ�O�����66��&�6��~�8��~)���"x����}Z���گ��;!�"M��w*~i�»��� ���4��c�s�~4�����g��[W�G��o��?���$�|���v�̖���I��]�~�s����G�f~Ҿ)���!�x�]7�3@�����y���]�[����w�$�a�p8�������$����x���Oi����W�ݹVW���1�%O-�<u ����/�q������d�q�2-������rd �1?��~3N���:�U������Yx#Z��+�~�sQ��������=xQEQEQEQEQEQEQEQE����5�h?���k������f��f=י拓�O1�q�ݱ��5�x'�^%��C��c��v�<���Q�������������R�}��T�����~�����g�_?"]���������L��M>�͗���V��	��o���oڮ�߱n��d��$ޓ�|��ك�P��y~����/<�7x����o������+~�x�dp��N�r���U��+�
���W���S���d}�X����c��c��ϭ|#�������Cx�_|C���r�v���Eg�Lq��
v��ϚR�%QEQEQEQE�IZ���P�൛�6����J�</�hm���w����0Xv89�������;/��o*K�3ι�m�m�YW�wMۼ�7}���7s�z>��e��p26Ή���_��/쳢���
��$����V��$:����U��Z��Β(�E>�ݑ��d��9��C�,|!3L���x�N.�~�����i3�|n죏�_ڻ����5�J�Ǻŏ�m��W���69�͋x"���e�r�g��s�=����e���S�ݤ�w>m��_�!��|�h�:��z�8��
KP��.����>����zRR���QEQEQEQEQEQEQEQEQEQEQEQE�����/�|?��-�%���O���
�}����.�r��*���5���ٓ����q�$Ǔ�mŝ�nG\�ׂ�6���ko�>
Ӿ�<������'�����?����I�ɭ��2H��g^W�[���?��3����?�?�Z�������[y�\I|�" �qF8Q�ry$�?=���(��(��(��(��)S�
J(�]�n��I��g�5��i�"�Qy�g}�g��~���?4��y4���#/��˧�?>��.ݚ��<2���'�+}�a�O�=+�������=����� �`�j�W���&����̅9�����N���zz��=C��ٷ�����G���J�����f����g�<.<�����������&�����*DZn>B7u>ߚ�Q_�(���O?������M�n�<�?�s�K��ssl���3G*|���<`W˿�mo�c㾈����#�kM�;`����������z(�_��9��rrh''&�(��(��(��(��(��(��(��(��(���%g���㖫�O�I��в�����e�O������y�W$nA�1�$�͢[�[�A�$�98�����i�
~ѿ�g�B}W����n�v��gZ]nڲ(��'���?��b���>3�[������_�[��
/HcA�$;{��~�|p���~��-|y�	����E��}��?����KFV����M��E|ͫ��m����i_����'I{�a����
��������4��f_.w��i�M�,��
�sھ
�����O���Y�[�>��g��s�4�p���Q{W3EQEQEQEQE��E��P����6�����i�n�7��g�~φ�-�>T�k�RΜ�R���~��9�w����&��>|��I<�e�Fc���� %6�o���¾�5�p����5wᏆ�4�˶����ĺ�}�d���NL�߿�ǎ��ƞ%���q�j_n���y��1Żj*/���*(�v���y:����|LW|��+�2��y2a߷���=ڼ�;/C@�R���I�o��S�{qs�5�aPPEPEPEPEPEPEPEP[��׍|Og�/��~fޟ�9�@觽`՝;Q��o#����;_hldx ����~4��K~Ӻu��>�ٶ$�v�o�{Iy�����]����#oş5��Q�����ح�O�n�7�oz6m�篙�ɯ�����Y_�\�?f��wH���%d��R��_�zd�6���w|ȿ��Sv�9[PG*�?[tk��	��x��5�C��F|ˏ+T�>��i	 ��{
�mݿ<�ɯۗ��׿j�ۥ�?a𦍿�.�rK���[y߼0E!̶��l�8~a�����{��|�_�h���q�T4QEQEQEQEQEk��%��ω-��-�6��p#c޹��~��#`�)�x�Ğ=���<S�}��O.��̎�+�"�o�"���q�<��׿�/�#��[/�_������/���3�>`na�x&�m�N�����|�ݶ�~�'�<u�x������?k���[y!�̆f~_��?ڇ�
a�gᯂ��~���_���5��.��~��<֭�N�LH��?�@�/į�x�ŗ�lԯ6y�yQǻdi�����QG�c�:����]\��l��=��6�q@�EPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP��

sketch.js

var canvasWidth = 960;
var canvasHeight = 500;

var prevSec;
var millisRolloverTime;
var nextAlarm;
var debug_is_on = (typeof DEBUG !== 'undefined');

function setup () {
  // create the drawing canvas, save the canvas element
  var main_canvas = createCanvas(canvasWidth, canvasHeight);
  main_canvas.parent('canvasContainer');


  // this is true if debug.js is included
  if(debug_is_on) {
    debug_setup();
  }
  turn_off_alarm();
}

function turn_on_alarm() {
  nextAlarm = millis() + 20000;    
  print("Alarm on: T minus 20 seconds");  
}

function turn_off_alarm() {
  nextAlarm = -1;
  print("Alarm turned off");  
}

function mouseClicked() {
  if (debug_is_on && debugCheckbox.checked()) {
    return;
  }
  if (nextAlarm > 0) {
    turn_off_alarm();
  }
  else {
    turn_on_alarm();
  }
}

// taking ideas from http://cmuems.com/2016/60212/deliverables/deliverables-02/
function draw () {
  var H, M, S, mils, alarm;

  if (debug_is_on && debugCheckbox.checked()) {
    hourSlider.removeAttribute('disabled');
    minSlider.removeAttribute('disabled');
    secSlider.removeAttribute('disabled');
    millisSlider.removeAttribute('disabled');
    alarmCheckbox.removeAttribute('disabled');
    alarmSlider.removeAttribute('disabled');

    H = hourSlider.value();
    M = minSlider.value();
    S = secSlider.value();
    mils = millisSlider.value();
    if (alarmCheckbox.checked()) {
      alarm = alarmSlider.value();
    }
    else {
      alarm = -1;
    }
  }
  else {
    // Fetch the current time
    H = hour();
    M = minute();
    S = second();
    if (nextAlarm > 0) {
      now = millis();
      var millis_offset = nextAlarm - now;
      if (millis_offset < -10000 ){
        // turn off alarm
        nextAlarm = -1;
        alarm = -1;
      }
      else if (millis_offset < 0) {
        alarm = 0;
      }
      else {
        alarm = millis_offset / 1000.0;
      }
    }
    else {
      alarm = -1;
    }

    // Reckon the current millisecond, 
    // particularly if the second has rolled over.
    // Note that this is more correct than using millis()%1000;
    if (prevSec != S) {
      millisRolloverTime = millis();
    }
    prevSec = S;
    mils = floor(millis() - millisRolloverTime);

    if (debug_is_on) {
      hourSlider.attribute('disabled','');
      minSlider.attribute('disabled','');
      secSlider.attribute('disabled','');
      millisSlider.attribute('disabled','');
      alarmCheckbox.attribute('disabled','');
      alarmSlider.attribute('disabled','');

      hourSlider.value(H);
      minSlider.value(M);
      secSlider.value(S);
      millisSlider.value(mils);
      alarmCheckbox.checked(alarm >= 0);
      alarmSlider.value(alarm);
    }
  }


  draw_clock(H, M, S, mils, alarm);
}

function keyTyped() {
  if (key == '!') {
    saveBlocksImages();
  }
  else if (key == '@') {
    saveBlocksImages(true);
  }
}