/joy-con-webhid

Use the Nintendo Switch Joy-Cons via the WebHID API

Primary LanguageJavaScriptApache License 2.0Apache-2.0

Joy-Con WebHID

A WebHID driver for Nintendo Joy-Cons with support for all buttons, analog sticks, and the device's gyroscope and accelerometer sensors.

Demo

See the live demo of the driver.

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.

Another demo is Chrome Dino WebHID, where you can play the Chrome dino game 🦖 over WebHID by jumping with a Joy-Con controller in your pocket.

Joy-Con WebHID Chrome dino demo

Yet another demo courtesy of @light2peter is the Web MIDI demo, where the Joy-Cons are being used to make music on Web MIDI receivers.

Joy-Con WebHID Web MIDI

Installation

npm install --save joy-con-webhid

(For Linux, see this comment on Issue #3 for required pre-steps.)

Usage

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();
    await joyCon.enableVibration();
    // Get information about the connected Joy-Con.
    console.log(await joyCon.getDeviceInfo());
    // Rumble.
    await joyCon.rumble(600, 600, 0.5);
    // 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);

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.

Acknowledgements

This project takes heavy inspiration from @wazho's ns-joycon, which in turn is based on @dekuNukem's Nintendo_Switch_Reverse_Engineering. The rumble code was contributed by @baku89. The HVC-Controller code was added by @taisukef. The Ring-Con code from @mascii.

License

Apache 2.0.