Pure, zero-dependency stick-drift detection for the Gamepad API. Feed it raw analog-stick (x, y) samples collected while the stick is at rest, and it returns a clear PASS / DRIFTING / FAIL verdict — not just raw numbers you have to interpret yourself.
This is the exact verdict engine behind Controller Tester — a free, in-browser controller / gamepad tester. Try the full interactive version, no install:
👉 controllertester.co/stick-drift-test
npm install stick-drift-detectimport { classifyStick, rollupController, Verdict } from 'stick-drift-detect';
// Poll navigator.getGamepads()[i].axes for ~2s while the stick is untouched,
// collecting raw (x, y) readings:
const leftStickSamples = [
[0.01, -0.02], [0.0, 0.01], [0.02, 0.0], /* ...30+ samples... */
];
const left = classifyStick(leftStickSamples, /* axesPresent */ true);
console.log(left.verdict); // 'PASS' | 'DRIFTING' | 'FAIL' | 'INVALID' | 'UNAVAILABLE'
console.log(left.mMed); // median resting magnitude — how far the stick sits off-center
// Combine multiple sticks into one controller-level verdict (worst real verdict wins):
const overall = rollupController([left, right]);
if (overall === Verdict.FAIL) console.log('This controller has stick drift.');- Each
(x, y)sample is reduced to a magnitude withMath.hypot(x, y)— the distance of the stick from dead center. No baseline subtraction: subtracting a resting offset would hide the very drift you are trying to measure. - The median magnitude over the window is the drift amount (
mMed), robust to occasional spikes. - A spread check (p90 − p10 of magnitudes) catches the case where the stick was actually moved during sampling and marks the run
INVALID. - The median is compared against thresholds:
mMed < 0.10→PASS0.10 ≤ mMed < 0.25→DRIFTINGmMed ≥ 0.25→FAIL
Thresholds are exported as THRESHOLDS and can be overridden per call.
classifyStick(samples, axesPresent, thresholds?) → StickResult— classify one stick.rollupController(stickResults) → Verdict— worst real verdict across sticks.THRESHOLDS— default tunable thresholds.Verdict— the verdict string constants.
Full TypeScript types are bundled.
MIT — built for and by controllertester.co.