Gamepad and joystick tester
Test a game controller in the browser — every button and axis live, stick drift and a suggested dead zone, a circularity score, trigger range, button chatter, polling rate and rumble — and build an SDL GameControllerDB mapping for pads the browser doesn't know.
Added
How to use it
I wrote this to sort out a drawer of controllers: which sticks drift, which buttons double-press, and why a cheap retro USB adapter wouldn’t steer the emulators on this site. Plug in as many pads as you like; each gets a card with its own live view, and the one you pick gets the full workup.
How to use it
-
Plug in or pair the controller and press a button. Browsers keep a pad hidden from a page until a button is pressed while the page is open, so nothing shows until you do. No pad to hand? Add a demo pad — it is driven by the keyboard and an animated stick.
-
The card says what the pad is: the vendor and product ids from its id string, a name from a table of common pads (Xbox, DualShock 4, DualSense, Switch Pro, 8BitDo, Logitech, generic USB pads and adapters), and whether the browser has a standard mapping for it. Standard pads are drawn as a controller, with the triggers filling as you squeeze; anything else (flight sticks, wheels, arcade sticks, retro adapters) is shown raw, one cell per button and a bar per axis.
-
Sticks: a plot of each stick with a trail. The hands-off test records three seconds with the pad untouched and reports where the stick rests (drift), how far it wanders, and a dead zone that covers it. The circularity test has you roll the stick round the edge; it keeps the furthest the stick reached in each of 72 directions and gives the average distance from a perfect circle, as a percentage. A square-gated stick scores high on purpose — the corners reach further.
-
Buttons: a press counter for each button, the shortest hold and quickest re-press seen, and a chatter flag for presses shorter than the threshold you set. Analogue buttons and triggers get a range bar: do they reach 1.00, do they come back to 0, how many steps they have. The polling-rate estimate comes from how often the pad’s timestamp changes, so keep a stick moving while it measures.
-
Vibration: dual rumble with separate strong and weak motors, a duration and a delay, and trigger rumble where the pad and browser have it (Xbox One and Series pads in Chrome or Edge on Windows).
-
Mapping: press each control in turn to build a mapping, then copy it as an SDL GameControllerDB line or as JSON. RetroArch, Dolphin, PCSX2 and anything else built on SDL read these lines. The panel underneath shows what this site’s emulators see — the first pad, d-pad or left stick for directions, any face button for fire — which is how the C64, Atari 8-bit, ZX Spectrum, MSX, Amstrad CPC, Atari ST and Amiga emulators here read a pad.
-
Raw HID (Chrome and Edge on desktop): open the pad over WebHID to see its actual reports, their real rate, and the battery level of a DualShock 4 or DualSense on USB.
The demo pad’s keys: arrows for the d-pad, Z X C V for the face buttons, Q E shoulders, 1 and 3 for the triggers, B and N for back and start, H for home, W A S D and I J K L for the sticks.
What the numbers mean
-
Drift is how far from centre the stick rests; worst is the furthest any sample strayed with hands off. A new stick is usually under 0.05; above about 0.12 it drifts in games without a generous dead zone. A stick that reads exactly 0 has a dead zone applied before the browser sees it.
-
Circularity error is the mean, over the directions you covered, of |outer radius − 1|. Shape alone measures against the stick’s own average radius, so a stick that is round but falls a little short of 1 scores well there.
-
The browser samples a pad at a fixed rate (Chrome about 250 times a second) and this page reads it every 4 ms, so bounces shorter than that, and polling rates above it, can’t be seen through the Gamepad API. The Raw HID tab sees every report.
-
For a standard-mapped pad the indices in a mapping are the browser’s, not the device’s own, so the SDL line is most useful for raw pads — the ones SDL and the browser don’t already know.
Browser support
The Gamepad API works in Chrome, Edge, Firefox and Safari, on desktop and on Android; it needs an
https page, and inside a frame the page must allow gamepad. Chrome on Windows reports Xbox pads
through XInput without their USB ids, so those show as "Xbox / XInput controller". Rumble works in
Chrome, Edge and Safari for the pads they support; Firefox mostly can’t. WebHID is only in Chrome and
Edge on desktop. Without the Gamepad API the page still runs with the demo pad.
I tested this with a scripted pad in a headless browser, not every controller, so the name table will miss some pads; the vendor and product ids it shows are what the pad itself reports.
Feedback is a gift. Something to improve, a feature to add, or a bug? Tell me.
Runs entirely in your browser; nothing you type leaves this page.