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…

You can edit this page on GitHub.

Webmentions

12 Replies

Prefer Gamepad API when possible. It has a better user experience. HID requires a device to be selected and connected. Use it when the higher level APIs can't get the job done.
Is there a way in the Gamepad API to detect that a device is eg a Nintendo Joypad so one could then limit the asking to only when such a gamepad is used then? To get the best of both worlds?
Should a use like this be seen as something that supersedes the Gamepad API? The new “correct” way of doing it? Or see it as a complement to the Gamepad API for those cases where one can support a controller better through WebHID? If a complement: How do one know which to use?
HID can access more devices beyond gamepads, and also obscure features that may take a long time or never be part of a generic high level gamepad API. github.com/robatwilliams/…
Can’t see any mention of why one would want this rather than the Gamepad API? Could you elaborate? Or is it just to demo things? Anyhow, cool WebHID stuff!
Nice demo (and great work). Was wondering if there’s an input latency difference between this and the Gamepad API (because it looks quite laggy in the demo video)? Guessing certain types of games might warrant different API (twitch/reaction-based game vs digital board game)?

8 Mentions

Now coming to Chrome (and perhaps other Chromium-based browsers). But don’t expect to see this in Safari or Firefox, whose developers see these hardware interfaces (like Web USB and Web Bluetooth) to be too risky.
Now coming to Chrome (and perhaps other Chromium-based browsers). But don’t expect to see this in Safari or Firefox, whose developers see these hardware interfaces (like Web USB and Web Bluetooth) to be too risky.
Thomas Steiner: 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. Installation of the driver per NPM: npm install joy-con-webhid Once a Joy-Con has been paired, you can listend to hidinput events: joyCon.addEventListener('hidinput', ({ detail }) => { // Careful, this fires at ~60fps. console.log(`Input report from ${joyCon.device.productName}:`, detail); }); 💡 The code does not use on the Gamepad API but the WebHID API as the former does not have support for orientation, which the Joy-Con controllers do support. Releasing Joy-Con WebHID → Joy-Con WebHID Repo (GitHub) → Related: Jumping the Hurdles with the Gamepad API →