npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

joyconjs

v2.0.0

Published

JoyconJS. Browser Gamepad API

Downloads

2

Readme

JoyconJS

Library to connect your gamepad to the browser gamepad API.

Install

npm i joyconjs

Initialization

Listen for gamepad connection and disconnection.

  const joycon = new JoyconJS({
    connected(gamepad){},
    disconnected(gamepad){}
  });

Listening and pulling gamepad state

To continiously pull in a standalone requestAnimationFrame loop call the listen method. This creates a new raf loop behind the scenes that keeps pulling the state for each connected gamepad.

joycon.listen();

However if you want to pull the gampad data in your own loop you simply call the pull method. This same method is being called in the listen method and updates the states for all connected gamepads. The difference is that it's up to you to decide when that data is being updated.

joycon.pull();

Cleanup

Since we are listening for the gamepad events we also should clean that up. In a front-end framework that would be done in your components unmount or destroy callback.

The destroy method removes all eventlisteners and cancels the current running raf loop if data is pulled via the listen method.

joycon.destroy();

Mappings

We have two mappings. One for buttons and one for axes. By default there are buttons and axes mapped which you can override to easily fit the your and your users gamepad.

Clear gamepad mappings

gamepad.clearButtons();
gamepad.clearAxes();

Customizing mapping

Mappings are index based. So create a custom key for the particular input at that particular index. We are also able to define multiple mappings to the same index.

Map a single key to a button at index 0. This is my A button so I name it a_button.

gamepad.buttons({
  0: 'a_button'
});

But we can also map it to several custom keys by providing an array of keys. These keys are still mapped to the same index as the previous example and is triggered on the same button press.

gamepad.buttons({
  0: ['player_jump', 'ok_dialog']
});

Also instead of having to clear buttons or axes in a separate function call we can pass a boolean true as the second argument and it will clear any previous bindings.

gamepad.buttons({
  0: ['player_jump', 'ok_dialog']
}, true);

The implementation goes the same for the stick axes.

gamepad.axes({
  0: ['move_character', 'ui_control'],
  1: 'crosshair'
}, true);

Buttons

connected callback provides a gamepad object where we bind our buttons to. There are 3 types of buttons. on, pressed, touched and separate implementations for untouched and released.

  • on - Continiously firing on every frame
  • pressed - Fire once
  • touched - Touch sensitive buttons. Fire once.

These binding methods accepts a key and a callback function and returns an object with the ability to chain a threshold value to the bound button. This threshold is a value between 0 and 1.

gamepad.on('left_trigger', console.log).threshold(.6);
gamepad.pressed('left_trigger', console.log).threshold(.6);
  • released - Fires when a button is released
  • untouched - Fires when a touch is untouched/released

Bind release callbacks.

gamepad.released('left_trigger', console.log);
gamepad.untouched('left_trigger', console.log);

We can also pass an array of keys to map multiple buttons to the same callback.

gamepad.on(['player_jump', 'ok_dialog'], console.log);

Axes

Axes works pretty much as buttons with the difference that you can pass both x and y thresholds. If only one value is provided the y value will inherit the x value.

gamepad.axis('move_character', console.log).thresholds(.3, .8);

Quick help

You can get the current mappings and controller id by calling the help method.

gamepad.help();

Get current axes and button maps as entries array.

gamepad.getAxesMap;
gamepad.getButtonMap;

Callback data

Button data.

data {
  "pressed": true,
  "touched": true,
  "value": 1,
  "key": "player_jump",
  "threshold": 0.8
}

Axis data.

data {
  "key": "move_character",
  "direction": {
    "x": 1,
    "y": 0
  },
  "x": 0.8115510940551758,
  "y": -0.09947359561920166,
  "thresholds": {
    "x": 0.8,
    "y": 0.8
  },
  "angle": -0.12196382640571538,
  "degrees": 353,
  "radians": 6.161012259539983,
  "overThreshold": {
    "x": true,
    "y": false
  }
}

Usage

const joycon = new JoyconJS({
  connected(gamepad){
    gamepad.buttons({
      0: 'player_jump'
    }, true);

    gamepad.on('player_jump', (data) => {
      // do something when button_1 is down
      console.log(data);
    });

    // left_stick_axis is from the default config because it's not cleared like the buttons above.
    gamepad.axis('left_stick_axis', (data) => {
      // move character
      console.log(data);
    }).threshold(.2);

    gamepad.help();
  },
  disconnected(gamepad){
    // do some cleanup
  }
});