<script type="text/javascript">
window.console = window.console || {}
window.console.log = window.console.log || function() {};
return ar.reduce(function(s, val) {
return sum(ar) / ar.length;
function avg_square_diffs(ar) {
var sqdiffs = ar.map(function(e) {
// Yup, it's standard deviation
return Math.sqrt(avg_square_diffs(ar));
var blink_controller = function(cycle_ms, blink_ms, blink_element, record_blinks) {
my.blink_element = blink_element;
my.record_blinks = record_blinks;
my.keep_blinking = false;
my.blink_element.classList.add("on");
console.log(my.blinks_recorded);
my.blink_element.classList.remove("on");
if (my.blinks_recorded >= my.record_blinks) {
var evt = new Event('finish');
my.blink_element.dispatchEvent(evt);
function record_blink(timestamp) {
var handle_frame = function(timestamp) {
// console.log("in handle_frame...")
my.last_frame_time = my.last_frame_time || timestamp;
var elapsed = timestamp - my.last_frame_time;
// console.log([elapsed, my.blink_remaining, my.cycle_remaining].join("\t"));
if (isFinite(my.blink_remaining)) {
my.blink_remaining -= elapsed;
if (my.blink_remaining <= 0) {
my.blink_remaining = NaN;
//my.event_list.push(["blink_off", timestamp])
console.log("blink_off\t"+timestamp);
my.cycle_remaining -= elapsed;
if (my.cycle_remaining <= 0 ) {
my.blink_remaining = my.blink_ms;
my.cycle_remaining = my.cycle_ms;
console.log("blink_on\t"+timestamp);
my.last_frame_time = timestamp;
window.requestAnimationFrame(handle_frame);
my.start_blinking = function() {
my.cycle_remaining = my.cycle_ms;
my.blink_remaining = my.blink_ms;
window.requestAnimationFrame(handle_frame);
my.stop_blinking = function() {
my.keep_blinking = false;
function make_sort_function(evt) {
return function(ke1, ke2) {
var dist1 = Math.abs(evt.timestamp - ke1.timestamp);
var dist2 = Math.abs(evt.timestamp - ke2.timestamp);
function get_blink_events() {
return my.event_list.filter(function(e) { return e.type == 'blink_on'; });
function get_press_events() {
return my.event_list.filter(function(e) { return e.type == 'keypress'; });
my.match_blinks_and_presses = function() {
var blinks = get_blink_events();
var presses = get_press_events();
presses.forEach(function(p) {
console.log("Finding closest blink...");
var sort_fx = make_sort_function(p);
console.log("Closest match:");
console.log([p.timestamp, b.timestamp]);
b.press_candidate = b.press_candidate || p;
var old_diff = Math.abs(b.timestamp, b.press_candidate.timestamp);
var new_diff = Math.abs(b.timestamp, p.timestamp);
if (new_diff < old_diff) {
return blinks.filter(function(b) { return b.press_candidate; }).map(function(b) {
"press": b.press_candidate,
"diff": b.press_candidate.timestamp - b.timestamp
function record_press(timestamp) {
my.handle_press = function(event) {
console.log("starting to record");
record_press(window.performance.now());
window.addEventListener('load', function() {
var blink_elt = document.getElementById('blinker');
var blinks_per_minute = 60;
var cycle_ms = (60 * 1000) / blinks_per_minute;
var blink_ms = (6/60) * 1000;
window.bc = blink_controller(cycle_ms, blink_ms, blink_elt, record_blinks);
document.addEventListener('keydown', bc.handle_press);
blink_elt.addEventListener('finish', function(e) {
var res = bc.match_blinks_and_presses();
var diffs = res.map(function(thing) { return thing.diff; });
document.getElementById("results").innerHTML = diffs.join("\n");
document.getElementById("mean").innerHTML = "Mean: " + m;
document.getElementById("std").innerHTML = "Stdev: " + s;
<div id="blinker" class="on"> </div>
<p>Press space when it blinks!</p>
<pre><div id="results"></div></pre>