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 <a href="https://dvcs.w3.org/hg/gamepad/raw-file/default/gamepad.html#the-gamepadconnected-event">gamepadconnected</a> event will be sent to the page.

The <a href="https://dvcs.w3.org/hg/gamepad/raw-file/default/gamepad.html#gamepadevent-interface">GamepadEvent</a> object has a <a href="https://dvcs.w3.org/hg/gamepad/raw-file/default/gamepad.html#widl-GamepadEvent-gamepad">gamepad</a> 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–<a href="https://dvcs.w3.org/hg/gamepad/raw-file/default/gamepad.html#methods">navigator.getGamepads()</a>–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 <a href="https://dvcs.w3.org/hg/gamepad/raw-file/default/gamepad.html#the-gamepaddisconnected-event">gamepaddisconnected</a> 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:

id
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.
index
An integer that is unique for each device currently connected to the system. This can be used to distinguish multiple controllers.
connected
A boolean: true if the controller is still connected, false if it has been disconnected.
mapping
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.
axes
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.
buttons
An array of GamepadButton objects containing the state of each button on the device. Each GamepadButton has a <a href="https://dvcs.w3.org/hg/gamepad/raw-file/default/gamepad.html#widl-GamepadButton-pressed">pressed</a> and a <a href="https://dvcs.w3.org/hg/gamepad/raw-file/default/gamepad.html#widl-GamepadButton-value">value</a> 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 <a href="https://dvcs.w3.org/hg/gamepad/raw-file/default/gamepad.html#widl-Gamepad-timestamp">timestamp</a> 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

About Robert Nyman [Editor emeritus]

Technical Evangelist & Editor of Mozilla Hacks. Gives talks & blogs about HTML5, JavaScript & the Open Web. Robert is a strong believer in HTML5 and the Open Web and has been working since 1999 with Front End development for the web - in Sweden and in New York City. He regularly also blogs at http://robertnyman.com and loves to travel and meet people.

More articles by Robert Nyman [Editor emeritus]…


17 comments

  1. Dietrich Ayala

    Very cool to see this come about.

    Can you link a few gamepad models that you recommend work well with this API?

    Do the gamepads work across various OSes?

    Is this available on Firefox OS yet?

    December 19th, 2013 at 10:20

    1. Ted Mielczarek

      Most generic USB gamepads will work fine on any platform. The Xbox 360 controller works fine everywhere. The PS3 controller is finicky–it works great on Linux, might require a driver on OS X, and doesn’t work well on Windows (there’s an unofficial driver but it’s terrible). The ancient USB controllers in the photo in the post work great everywhere.

      We currently have support for Windows, OS X, and Linux. There are bugs on adding support for Android[1] (currently unowned) and Firefox OS[2]. The Firefox OS part is a bit complicated because HID support in Firefox OS is currently bleeding-edge AIUI, but it’s being looked at, certainly.

      1. https://bugzilla.mozilla.org/show_bug.cgi?id=852935
      2. https://bugzilla.mozilla.org/show_bug.cgi?id=852945

      December 19th, 2013 at 13:46

      1. Jason Hutchinson

        The BetterDS3 tool makes the PS3 controller more bearable to use on Windows.

        December 23rd, 2013 at 09:15

  2. sole

    That demo works nicely with a Logitech Dual Action controller ^_^

    December 19th, 2013 at 11:54

    1. Robert Nyman [Editor]

      Nice!

      December 20th, 2013 at 09:08

  3. Hugo Habel

    This is just amazing!. I tried the demo with a PS3 controller and worked great. Right now I am thinking what can I create with this API.

    December 19th, 2013 at 16:58

    1. Robert Nyman [Editor]

      Thanks, and sounds good!

      December 20th, 2013 at 09:07

  4. Šime Vidas

    Here’s a video of my playing with the demo on my Logitech USB gamepad: https://twitter.com/simevidas/status/413899560734306304. I agree with Hugo. This is amazing :-D

    December 19th, 2013 at 23:34

    1. Robert Nyman [Editor]

      Very cool!

      December 20th, 2013 at 09:08

  5. ilyas

    It’s very very good! Gamepad welcome to browser gameworld!

    December 20th, 2013 at 00:21

    1. Robert Nyman [Editor]

      Thanks!

      December 20th, 2013 at 09:08

  6. Andy

    Thanks for this post guys! I’ve been tinkering with this in a custom game engine since it was navigator.gamepads.

    I’m updating my generic input library that abstracts keyboard and gamepad input to a common interface but with Firefox 27 I’m hitting problems with using a Gamepad object as a prototype, eg:

    a = navigator.getGamepads();
    b = Object.create(a[1]);
    console.log(b);
    console.log(b.buttons);

    This results in Firebug’s console and object inspector giving me:
    http://xhva.net/gamepad_error_1.png
    http://xhva.net/gamepad_error_2.png

    Is it intentional that I can’t access props on the Gamepad when used as a prototype?

    December 22nd, 2013 at 07:30

    1. Ted Mielczarek

      It’s not clear to me that this is something that should work, but I’m not really a DOM expert. You’re welcome to file a bug and I can get some expert opinion on it.

      December 23rd, 2013 at 10:10

  7. thinsoldier

    The demo works perfectly with my Logitech Driving Force GT wheel. :)

    December 23rd, 2013 at 09:36

    1. Jaja

      wheel can work? It’s amazing for me : )

      i think it can be use in very interesting apps

      December 30th, 2013 at 23:58

      1. Ted Mielczarek

        I believe gaming wheels should work fine since they generally look just like gamepad devices to the system.

        December 31st, 2013 at 09:57

  8. Dread Knight

    Tested the demo with PS3 controller via USB connection. Works flawlessly, woot!

    January 17th, 2014 at 13:12

Comments are closed for this article.