LeapJS Plugins

A collection of plugins available built on top of the LeapJS plugin framework. The library is written in CoffeeScript, but CoffeeScript is not required to run applications.

Docs

Blog Posts


Download

Community Plugins

Making Plugins

GitHub Projectleapmotion/leapjs-plugins






Edit the markdown for these docs on github.

This project is maintained by leapmotion.

Hosted on GitHub Pages — Theme by orderedlist

Hand Entry


View Source

Usage

Fires controller events when a hand enters or leaves the frame.

1  controller.use('handEntry')
1Leap.loop(function(frame){
2})
3.use('handEntry')
4.on('handFound', function(hand){
5   // ...
6});

Events

handFound(hand)

Triggered from the controller. This passes in the Hand object.

1  controller.on('handFound',
2    function(hand){console.log( 'hand found', hand ); }
3  )

handLost(hand)

Triggered from the controller. This passes in the Hand as it was seen in the last frame.

This event is also triggered for every hand present when the device is disconnected.

1  controller.on('handLost',
2    function(hand){console.log( 'hand lost', hand ); }
3  )

Hand Hold


View Source

Usage

1  controller.use('handHolding')

The hand-holding plugin provides a simple way to store data about a hand object between frames.

Methods

.data(hashOrKey, value)

Similar to jQuery.data, this method allows a value to be get or set. This is the main method, all else are convenience methods.

1  hand.data('player', 1)  //store data
2  hand.data({player: 1})  //store data
3  hand.data('player') // returns 1

hold(value)

This will either hold the value passed in, or hold on to whatever the hand is currently hovering over (see below).

1  hand.hold(someDiv); // store the div
2  hand.hold();        // store the current hover target

holding()

This will return the object currently being held.

1  hand.holding();  // returns someDiv

hoverFn(callback)

Sets a function which the hand will use to determine what it is hovering over.

1  hand.hoverFn(
2    function(hand){ return hand.closestDiv(); }
3  )

hovering()

Returns what the hand is currently hovering over, based upon the hoverFn. If no callback is set, will return undefined.

1  hand.hovering() // returns the results of hand.closestDiv();
# Calculates how much a hand has changed pitch in the last few seconds.
Leap.Controller.plugin 'sumPitch', (options = {})->
  timeWindow = options.timeWindow || 1 # seconds

  # delta of both hands are combined
  pitchData = []
  {
    hand: (hand)->
      # skip momentary hands
      if hand.timeVisible < 1
        return

      # initial pass
      # we namespace our keys under sumPitch
      lastPitch = hand.data('sumPitch.lastPitch')
      currentPitch = hand.pitch()
      hand.data('sumPitch.lastPitch', currentPitch)

      return unless lastPitch

      # store values with timestamps
      now = Date.now()
      pitchData.push({
        delta: currentPitch - lastPitch,
        time: now
      })

      # manage rolling sum
      while pitchData[0].time < (now - (timeWindow * 1000))
        pitchData.shift()

      hand.sumPitch = 0
      for data in pitchData
        hand.sumPitch += Math.abs(data.delta)
  }

# The controller has already been initialized at the top of the page.  Otherwise:
# controller = new Leap.Controller();
#   controller.connect()
window.handHoldDemo = $('#hand-hold-demo')
controller.on 'frame', (frame)->
  if frame.hands[0]
    handHoldDemo.html("frame id: #{frame.id} <br/>hand sumPitch (in the last second): #{frame.hands[0].sumPitch.toPrecision(3)}")
  else
    handHoldDemo.html('frame id: ' + frame.id + ' <br/>no hand present.');
// Calculates how much a hand has changed pitch in the last few seconds.
Leap.Controller.plugin('sumPitch', function(options) {
  options || (options = {})
  var pitchData = [],
      timeWindow = options.timeWindow || 1; // seconds

  return {
    hand: function(hand) {
      var currentPitch, data, lastPitch, mostDistantTime, now, _i, _len;

      hand.sumPitch = 0;
      if (hand.timeVisible < 1) {
        return;
      }

      lastPitch = hand.data('sumPitch.lastPitch');
      currentPitch = hand.pitch();
      hand.data('sumPitch.lastPitch', currentPitch);

      if (!lastPitch) {
        return;
      }

      // store values with timesstamps
      now = Date.now();
      pitchData.push({
        delta: currentPitch - lastPitch,
        time: now
      });

      // manage rolling sum
      while (pitchData[0].time < (now - (timeWindow * 1000))) {
        pitchData.shift();
      }

      for (_i = 0, _len = pitchData.length; _i < _len; _i++) {
        data = pitchData[_i];
        hand.sumPitch += Math.abs(data.delta);
      }
    }
  };
});

window.handHoldDemo = $('#hand-hold-demo');

// The controller has already been initialized at the top of the page.  Otherwise:
// var controller = new Leap.Controller();
//   controller.connect()

controller
  .use('handHold')
  .use('sumPitch')
  .on('frame', function(frame) {
    if (frame.hands[0]) {
      return handHoldDemo.html('frame id: ' + frame.id + ' <br/>hand sumPitch (in the last second): ' + frame.hands[0].sumPitch.toPrecision(3));
    }else{
      return handHoldDemo.html('frame id: ' + frame.id + ' <br/>no hand present.');
    }
  })
No Leap Device Attached

Screen Position


View Source

Adds the “screenPosition” method by default to hands and pointables. This returns a vec3 (an array of length 3) with [x,y,z] screen coordinates indicating where the hand is. This method can accept an optional vec3, allowing it to convert any arbitrary vec3 of coordinates.

Custom positioning methods can be passed in, allowing different scaling techniques,
e.g., Pointer Ballistics for Windows XP
Here we scale based upon the interaction box and screen size:

Usage

 1  controller.use('screenPosition')
 2  // or
 3  controller.use('screenPosition', {positioning: 'absolute'}) // the default
 4  // or
 5  controller.use 'screenPosition', {
 6    positioning: function(positionVec3){
 7      // Arguments for Leap.vec3 are (out, a, b)
 8      [
 9        Leap.vec3.subtract(positionVec3, positionVec3, this.frame.interactionBox.center)
10        Leap.vec3.divide(positionVec3, positionVec3, this.frame.interactionBox.size)
11        Leap.vec3.multiply(positionVec3, positionVec3, [window.innerWidth, window.innerHeight, 0])
12      ]
13    }
14  }
15
16  // later...
17  hand.screenPosition() // returns [156,204,0]

More info on vec3 can be found, In the gl-matrix docs

Methods

.screenPosition([positionVec3])

Returns the location of the hand in screen-space, or the passed in vector in screen-space.
Applies to hands and pointables.

window.handHoldDemoCursor = $('#screen-position-demo .cursor')
window.handHoldDemoOutput = $('#screen-position-demo .output')
controller
  .use('screenPosition', {scale: 8})
  .on('frame', (frame)->
    if hand = frame.hands[0]
      handHoldDemoOutput.html("[<br/>&nbsp;&nbsp;#{hand.screenPosition()[0]}
        <br/>&nbsp;&nbsp;#{hand.screenPosition()[1]}
        <br/>&nbsp;&nbsp;#{hand.screenPosition()[2]}<br/>]")
      handHoldDemoCursor.css(
        left: hand.screenPosition()[0],
        bottom: hand.screenPosition()[1]
      )
  ).on('deviceConnected', ->
    $('#screen-position-demo .noleap').remove()
  )
window.handHoldDemoCursor = $('#screen-position-demo .cursor');
window.handHoldDemoOutput = $('#screen-position-demo .output')

controller
  .use('screenPosition', {
    scale: 8
  })
  .on('frame', function(frame) {
    var hand;
    if (hand = frame.hands[0]) {

      handHoldDemoOutput.html("[<br/>&nbsp;&nbsp;" + (hand.screenPosition()[0]) +
        "        <br/>&nbsp;&nbsp;" + (hand.screenPosition()[1]) +
        "        <br/>&nbsp;&nbsp;" + (hand.screenPosition()[2]) + "<br/>]");

      return handHoldDemoCursor.css({
        left: hand.screenPosition()[0] + 'px',
        bottom: hand.screenPosition()[1] + 'px'
      });
    }
}).on('deviceConnected', function(){
  $('#screen-position-demo .noleap').remove()
});
No Leap Device Attached

Version Check

View Source

This plugin is used to confirm a minimum LeapJS protocol version. For an application or plugin which requires functionality specific to a minimum protocol, include and configure this plugin.

When a device is ready, it will check the protocol version and if outdated emit versionCheck.outdated from the controller with data e.g., {current: 5, required: 6, disconnect: true}.

Options

Usage

1  // from an app
2  controller.use('versionCheck')
3
4  // from a plugin:
5  this.use('versionCheck')
6
7  // while specifying options
8  this.use('versionCheck', {requiredProtocolVersion: 6})

Playback

View Source

This plugin is used to send pre-recorded Leap frame data in to any Leap App.

Options

Usage

1  controller.use('playback', {
2    recording: 'recordings/pinch.json.lz',
3    requiredProtocolVersion: 6,
4    pauseOnHand: true
5  })

This plugin comes with an extensive API for usage in an application, including functions such as play, pause, record, stop, and export. When leapjs-playback is released as a standalone repository, they will be documented there. These can be access as follows:

1  controller.plugins.playback.player.play()