Padlock

Tappy

is a JavaScript library for recording and comparing rhythms. It can be used for games and for more serious things.

It's hosted on GitHub, npm, bower, and jsdelivr.

npm install tappy # or whatever
var tappy = require('tappy');

To record rhythms, create a new Rhythm object:

var password = new tappy.Rhythm();

...and call its tap() method at each beat:

function tapThat () { password.tap(); }
window.addEventListener('click', tapThat, false);
var i = 7;
while (i--) password.tap();

Call done() when you're done recording.

if (password.length === 7) password.done();

As you might have noticed, Rhythm objects have a length attribute. They also have a duration attribute and a playback() method.

var pwDuration = password.duration; // in ms

// playback() accepts a callback to run at each
// tap, an optional callback for when the Rhythm
// finishes, and an optional multiplier
password.playback(
  function (i) { console.log('Tap number ' + i); },
  function ( ) { console.log('Finished Rhythm'); },
  2
);
// the multiplier in this example makes the Rhythm
// play 2x slower than the original

To compare two rhythms, pass them into tappy.compare():

// all Rhythm methods are chainable
var newPassword = new tappy.Rhythm().tap().tap();
newPassword.tap().tap().tap().tap().tap().done();
// returns a confidence value from 0 to 1 (1 === exact match)
tappy.compare(password, newPassword, true);
// the third argument is optional; by default, compare() elastically
// matches rhythms played at different tempos. It's useful for cases
// like the lyrics game, where players may slow down when focusing.
//
// a truthy third argument makes compare() match tempo and rhythm;
// this works well for keystroke dynamics analysis etc.

Tappy works on the client and the server:

// if a Rhythm object is stringified,
// eg. you need to pass it to a server
var stringified = JSON.stringify(password);

// it can be easily reconstructed by passing
// the raw object into the Rhythm constructor
var raw = JSON.parse(stringified);
var recovered = new tappy.Rhythm(raw);

Rhythms can be merged with tappy.average() to eliminate timing anomalies:

// accepts any number of Rhythms
var steady = tappy.average(password, newPassword, recovered);

// it even works with rhythms that have already been averaged
var intermediate = tappy.average(password, newPassword);
var steady2 = tappy.average(intermediate, recovered);

alert(tappy.compare(steady, steady2));

There are a few more tricks up Tappy's sleeve:

// the Rhythm constructor can accept an array of ms
// time intervals between notes. For example, four
// quarter-notes followed by four half-notes looks like:
var preset = new tappy.Rhythm([1, 1, 1, 1, 2, 2, 2]);
// since there are 8 notes, we input 7 inter-note intervals
    

That's all there is to it! Have fun.