New in Chrome 89

Pete LePage walks us through the additions in Chrome 89.

🤩 I’m honored to have my WebHID Daft Punk Sound Board be featured in the “WebHID, WebNFC, and Web Serial section there.

Let’s hope other browser vendors follow soon with top level await, as Chromium is the only browser to support it at the time of writing.

New in Chrome 89 →

WebHID Demo: Elgato Stream Deck Daft Punk Soundboard

Sparked by Pete LePage’s work on talking to a Elgato Stream Deck device from within the browser, I wanted to play with WebHID myself. First thing that came to my mind was to create a DrumPad.

What first started out as a simple/classic DrumPad …

… soon led to creating a Soundboard which uses samples from Daft Punk’s “Harder, Better, Faster, Stronger”.


Screenshot of the Soundboard I built.

Before linking to the final version of the Daft Punk Soundboard (which has evolved quite a bit when compared to the screenshot above), let’s take a look at how it works.

~

Building the Drumpad/Soundboard and responding to clicks

All audio samples are defined as a small object on an array, and consist of three properties:

  1. A label
  2. A link to an audio fragment
  3. A Keyboard keyCode to respond to

ℹ️ In the final version I added some extra features such as the ability to use an image instead of a label and to customize the action when the button is being pressed, but these are not the focus here.

Each fragment is rendered as a <button> element and a (non-visible) <audio> element. The <audio> element its id is set to the keyCode.

<button data-keycode="${keyCode}">
    <span>${label}</span>
    <audio id="${keyCode}" src=${url} preload="auto"></audio>
</button>

Upon pressing a button, its linked <audio> element (fetched using the button’s data-keycode attribute value, instead of relying on DOM traversal) is selected and a play action is triggered on the fragment.

const playSound = (keyCode) => {
	const $el = document.getElementById(keyCode);
	
	if (!$el) return;

	$el.currentTime = 0;
	$el.play();
}

~

Responding to Keyboard Key Presses

To capture key presses a listener on the keydown event of the document is added. Using the pressed key’s code the correct button is selected and a click on it is triggered.

document.addEventListener('keydown', (e) => {
	const $button = document.querySelector(`button[data-keycode="${e.code}"]`);
	if ($button) $button.click();
});

~

Attaching the Stream Deck

☝️ Do note that connecting a Stream Deck is entirely optional: using a Stream Deck is considered to be an enhancement.

The Stream Deck code itself was borrowed from Pete’s Google Meet Stream Deck Chrome Plug-in, and launched using similar logic. If a Stream Deck device is found and connected, it is attached to the DrumPad instance.

const go = async () => {
	const drumPad = new DrumPad(config, document.querySelector("#app"));
	await drumPad.init();

	if (navigator.hid) {
		const streamDeck = new StreamDeck();

		// Connect to previously connected device
		await streamDeck.connect();

		// A previously connected device was found
		if (streamDeck.isConnected) {
			drumPad.attachStreamDeck(streamDeck);
		}

		// No Previously connected device was found
		else {
			// Add button to connect new device
			const elem = document.createElement("button");
			elem.innerText = "Connect Stream Deck";
			elem.addEventListener("click", async () => {
				elem.remove();
				await streamDeck.connect(true);
				drumPad.attachStreamDeck(streamDeck);
			});
			document.body.appendChild(elem);
		}
	}
}
go();

💡 As not all browsers support top-level await, we wrap the whole logic in a async function

~

Responding to Stream Deck button presses

To also respond to button presses on the Stream Deck, a map that maps a Stream Deck button ID (0, 1, 2, …) to a certain keyCode is built.

const buttonIdToKeyCodeMap = {
  0: "KeyQ",
  1: "KeyW",
  2: "KeyE",
  …
}

Upon pressing a Stream Deck button it will — using the buttonIdToKeyCodeMap — fetch the corresponding HTML button and trigger a click on it, similar to how the keyboard key presses work.

This is set up in the call to drumPad.attachStreamDeck(streamDeck); (see above) and looks like this:

streamDeck.addEventListener('keydown', (e) => {
	const keyCode = buttonIdToKeyCodeMap[e.detail.buttonId] ?? '';
	const $button = document.querySelector(`button[data-keycode="${keyCode}"]`);
	if ($button) $button.click();
});

In that same attachStreamDeck method the buttons on the Stream Deck are also drawn.

~

Stretching it a bit more …

The switch to the Daft Punk board didn’t sit 100% well me with me though: there are 16 samples to use, but the Stream Deck “only” has 15 buttons available …

But then it hit me: what if I paginated the samples, and allowed you to switch between two sets of 8 samples each? In that idea the 1st row would be filled with buttons to switch between different sample sets, and the 2nd+3rd row would respond to that.

With that refactor being worked on, I also took the time to update the UI to closely reflect the layout of the Stream Deck device.

In the end, it ended up like this:

Here’s a video of it, so see how it works and behaves, including with a connected Stream Deck:

~

During lunch today I polished the code a bit further and pushed everything online. The Source Code can be found in GitHub, and the app is deployed on Netlify.

Elgato Stream Deck Daft Punk Soundboard Demo →
Elgato Stream Deck Daft Punk Soundboard Source Code →

👨‍🔬 The demo website is registered for the WebHID Origin Trial, and therefore WebHID should be enabled by default. If you however don’t see a connect button, go to chrome://flags/ and manually enable ”Experimental Web Platform Features”.

~

Did this help you out? Like what you see?
Thank me with a coffee.

I don't do this for profit but a small one-time donation would surely put a smile on my face. Thanks!

☕️ Buy me a Coffee (€3)

To stay in the loop you can follow @bramus or follow @bramusblog on Twitter.

Use the Elgato Stream Deck in Google Meet with this Chrome Plugin

Recently I purchased an Elgato Stream Deck which comes in handy during video calls: toggling the camera and microphone on/off by means of a dedicated button sure is handy.

As Google Meet is web-based, there are no plugins for the Stream Deck app to use. However, thanks to the WebHID API it is possible to have your browser talk directly to a Stream Deck device.

With this knowledge in hand Pete LePage — whom you might know as Developer Advocate for Chrome — created a Chrome plugin for use with Google Meet. Once your Stream Deck is connected you’ll get some handy buttons to use:

Meet + Stream Deck Helper →

💡 Tip: To connect the Stream Deck to Google Meet you must close the native Stream Deck app.

Using Nintendo Switch Joy-Con Controllers on the Web with the WebHID API

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 per NPM:

npm install joy-con-webhid

Once a Joy-Con has been paired, you can listen 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, a feature the Joy-Con controllers use extensively.

Releasing Joy-Con WebHID →
Joy-Con WebHID Repo (GitHub) →