The Gamepad API

I’ve been fascinated by video games since I was a kid. From the Atari and Colecovision to the NES and Super NES, I’ve spent countless hours playing a variety of games. While my own video game playing has tapered off, I’m still interested in the issues and advancements surrounding gaming. I’ve watched the recent popularity explosion of web gaming and am positive that it’s going to herald a new era of gaming, with a tremendous number of games available to a wide audience. However, one thing struck me while exploring the burgeoning web gaming scene–many of these games would be a lot more fun to play with a gamepad! I set out to remedy that by implementing something for Firefox and thus the Gamepad API was born.

A collection of game controllers

Enabling the API

As of Firefox 24, the Gamepad API is available behind a preference. You can enable it by loading about:config and setting the dom.gamepad.enabled preference to true. Nightly and Aurora builds of Firefox have the API enabled by default. We expect to ship release builds with it similarly enabled in Firefox 28.

Using the API

The Gamepad API was designed to be very simple. The spec intentionally only attempts to describe an interface for working with traditional Gamepad controllers—a collection of buttons and axes. We felt that this covers the majority of the gaming controllers that are out there, while avoiding the complexity of trying to specify an API that covers everything in existence. The API consists of one function call, a few DOM events, and one type of object to work with.

Getting a Gamepad

As implemented, gamepads will not be exposed to a webpage unless the user interacts with them while the page is visible. This is for privacy reasons, mostly to prevent them from being used in fingerprinting a user’s system. If the user interacts with (presses a button, moves a stick) a controller while the page is visible a gamepadconnected event will be sent to the page.

The GamepadEvent object has a gamepad property that describes the device in question. In Firefox, once one gamepad has been exposed to a page, connecting any other gamepad to the system (by plugging in a USB gamepad or associating a Bluetooth gamepad) will immediately expose that device to the page and send a gamepadconnected event.

The Gamepad API also provides a function–navigator.getGamepads()–that returns a list of all devices currently visible to the webpage. Each gamepad visible to the page is returned at the position in the list specified by its index property.

Note: this code snippet will work in Firefox 28 nightly builds but not in older builds due to a bug that was just recently fixed.

If a gamepad is disconnected–by being unplugged, for example–a gamepaddisconnected event is fired at the page. Any lingering references to the Gamepad object will have their connected property set to false.

The Gamepad object

The Gamepad object represents the state of a game controller. It has several properties that describe the controller:

A string containing some information about the controller. This is not strictly specified, but in Firefox it will contain three pieces of information separated by dashes (-): two 4-digit hexadecimal strings containing the USB vendor and product id of the controller, and the name of the controller as provided by the driver. This information is intended to allow you to find a mapping for the controls on the device as well as display useful feedback to the user.
An integer that is unique for each device currently connected to the system. This can be used to distinguish multiple controllers.
A boolean: true if the controller is still connected, false if it has been disconnected.
A string indicating whether the browser has remapped the controls on the device to a known layout. Currently there is only one supported known layout–the “standard gamepad“. If the browser is able to map controls on the device to that layout the mapping property will be set to the string standard.
An array of floating point values containing the state of each axis on the device. Usually these represent analog sticks, with a pair of axes giving the position of the stick in its X and Y axes. Each axis is normalized to the range of -1.0..1.0, with -1.0 representing the up or left-most position of the axis, and 1.0 representing the down or right-most position of the axis.
An array of GamepadButton objects containing the state of each button on the device. Each GamepadButton has a pressed and a value property. The pressed property is a boolean indicating whether the button is currently pressed (true) or unpressed (false). The value property is a floating point value used to enable representing analog buttons, such as the triggers on many modern gamepads. The values are normalized to the range 0.0..1.0, with 0.0 representing a button that is not pressed, and 1.0 representing a button that is fully pressed.

Cross-browser compatibility

The Gamepad API specification is implemented in both Firefox and Chrome, to varying degrees of compatibility. Currently Firefox implements the entirety of the editor’s draft with the exception of the timestamp property on Gamepad objects.

As of this writing, Chrome does not implement the ongamepadconnected or ongamepaddisconnected events. You must use the navigator.webkitGetGamepads() function (note the prefix) to access gamepads.

Another difference to note is that Gamepad objects are snapshots in Chrome, whereas they always reflect the latest state of the controller in Firefox. This means that for Chrome you will need to poll the set of gamepads with navigator.webkitGetGamepads() each frame, whereas in Firefox you can hold a reference to a Gamepad object in a variable and refer to it later to check the current state.

Finally, a recent spec change means Chrome and release versions of Firefox have a difference from Firefox 28—the buttons property of the Gamepad object was originally specified as an array of doubles, not an array of GamepadButton objects. This can be handled safely with a simple type check, as the following code sample shows.

A simple demo

I’ll leave you with a simple demo that puts all the pieces here together and shows how you can use the API today in a cross-browser fashion. It simply looks for gamepads being connected or disconnected and displays the current state of the buttons and axes of all known controllers. This demo should work in any version of Firefox from 24 onwards and in Chrome from version 21 onwards. You can find the source of the demo on Github.

I hope this post inspires you to rethink what is possible in gaming on the web. Let’s go make some games!

A screenshot showing the Gamepad test page

View full post on Mozilla Hacks – the Web developer blog

Tagged on:

Leave a Reply