blogccasion

Releasing Joy-Con WebHID

The WebHID API received its third LGTM on December 17, which means it is approved for shipping in Chrome 🎉. WebHID allows websites to access devices that use the human interface devices (HID) protocol via JavaScript. Here is a little Christmas present 🎄 to the community to celebrate the API approval: releasing Joy-Con WebHID, a WebHID "driver" for Nintendo Joy-Con controllers so you can use them in the browser. If you have Joy-Cons, be sure to check out the demo to get a feel for what is possible.

Joy-Con WebHID demo showing two Joy-Cons slightly tilted with one of the analog sticks moved to the right on one Joy-Con and the 'A' button pressed on the other.
Joy-Con WebHID in action.

Using the library

Getting started is straight-forward. Make sure you have a pairing button on your page.

<button class="connect" type="button">Connect Joy-Con</button>

Import the script and hook up the pairing button. Then create an interval that waits for Joy-Cons to appear, which can happen after pairing, on page load when previously paired Joy-Cons are reconnected, and when Joy-Cons wake up again after being idle.

import * as JoyCon from './node_modules/dist/index.js';

// For the initial pairing of the Joy-Cons. They need to be paired one by one.
// Once paired, Joy-Cons will be reconnected to on future page loads.
document.querySelector('.connect').addEventListener('click', async () => {
  // `JoyCon.connectJoyCon()` handles the initial HID pairing.
  // It keeps track of connected Joy-Cons in the `JoyCon.connectedJoyCons` Map.
  await JoyCon.connectJoyCon();
});

// Joy-Cons may sleep until touched and fall asleep again if idle, so attach
// the listener dynamically, but only once.
setInterval(async () => {
  for (const joyCon of JoyCon.connectedJoyCons.values()) {
    if (joyCon.eventListenerAttached) {
      continue;
    }
    // Open the device and enable standard full mode and inertial measurement
    // unit mode, so the Joy-Con activates the gyroscope and accelerometers.
    await joyCon.open();
    await joyCon.enableStandardFullMode();
    await joyCon.enableIMUMode();
    // Get information about the connected Joy-Con.
    console.log(await joyCon.getDeviceInfo());
    // Listen for HID input reports.
    joyCon.addEventListener('hidinput', ({ detail }) => {
      // Careful, this fires at ~60fps.
      console.log(`Input report from ${joyCon.device.productName}:`, detail);
    });
    joyCon.eventListenerAttached = true;
  }
}, 2000);

Check the file demo/index.js to see how to deal with the various signals you receive from the driver.

Chrome Dino WebHID

A first example that I have built based on the Joy-Con WebHID project is Chrome Dino WebHID. It allows you to play the chrome://dino game 🦖 via WebHID using your Joy-Cons. Here is a video preview of what to expect:

Why not use the Gamepad API?

The Gamepad API supports Joy-Con controllers out-of-the-box, but since the API (currently) does not have a concept of orientation, the Joy-Cons' accelerometer and gyroscope data cannot be accessed. The buttons and analog sticks are fully exposed, though. If all you need is this, then by all means go for the Gamepad API.

Credits

Joy-Con WebHID takes heavy inspiration from @wazho's ns-joycon, which in turn is based on @dekuNukem's Nintendo_Switch_Reverse_Engineering. Standing on the shoulders of giants…