APIs de la web, hoyLaboratorio · Alex Harto

Gamepad

Mandos de consola en la web, con vibración y gatillos hápticos.

En tu navegador: comprobando…Revisado 1 oct 2026

getGamepads() da el estado de botones y ejes de cada mando; con el mapeo «standard» la disposición es la misma en mandos de Xbox, PlayStation o Switch. vibrationActuator.playEffect() hace vibrar el mando y, con mandos tipo Xbox en Chrome, también los gatillos.

La lectura es Baseline desde 2017 (ampliamente disponible desde 2019). La vibración está en Chrome, Edge y Safari para macOS; Firefox no la implementa. Por privacidad, ningún mando aparece hasta que el usuario pulsa un botón.

Para qué sirve

  • Juegos web con mando
  • Control de presentaciones, robots o instalaciones
  • Accesibilidad con mandos adaptados

Demo

Conecta un mando (USB o Bluetooth) y pulsa cualquier botón: por privacidad, el navegador no lo muestra hasta entonces.

Compatibilidad

Baseline · ampliamente disponible · 27 sep 2019
FunciónEscritorioMóvil
ChromeEdgeFirefoxSafariChrome AndroidFirefox AndroidSafari iOS
getGamepads()35Chrome: 35 12Edge: 12 29Firefox: 29 10.1Safari: 10.1 35Chrome: 35 32Firefox: 32 10.3Safari: 10.3
Vibración (dual-rumble)68Chrome: 68 79Edge: 79 —Firefox: No16.41Safari: 16.4 68Chrome: 68 —Firefox: No—Safari: No
Gatillos (trigger-rumble)1262Chrome: 126 126Edge: 126 —Firefox: No—Safari: No126Parcial3Chrome: 126 Parcial—Firefox: No—Safari: No
  1. 1Solo en macOS.
  2. 2Windows y macOS; en Linux y ChromeOS, solo por Bluetooth. Mandos tipo Xbox.
  3. 3La API existe, pero los gatillos no vibran en Android.

Compatibilidad generada en cada publicación desde MDN browser-compat-data 8.1.3 (24 sep 2026) · web-features 3.40.0 · revisión manual: 1 oct 2026

Código mínimo

<!doctype html>
<meta charset="utf-8">
<title>Gamepad · ejemplo mínimo</title>
<!-- Conecta un mando y pulsa un botón: el navegador solo lo muestra tras la primera pulsación. -->
<p id="status">Pulsa un botón del mando…</p>
<pre id="state"></pre>
<button id="rumble" disabled>Vibrar</button>
<script>
  const $ = (s) => document.querySelector(s);
  let index = null;

  addEventListener('gamepadconnected', (e) => {
    index = e.gamepad.index;
    $('#status').textContent = `Conectado: ${e.gamepad.id} (${e.gamepad.mapping || 'sin mapeo estándar'})`;
    $('#rumble').disabled = !e.gamepad.vibrationActuator;
    requestAnimationFrame(loop);
  });
  addEventListener('gamepaddisconnected', () => { index = null; $('#status').textContent = 'Desconectado'; });

  // El estado no llega por eventos: se consulta en cada fotograma
  function loop() {
    const pad = index === null ? null : navigator.getGamepads()[index];
    if (!pad) return;
    const pressed = pad.buttons.flatMap((b, i) => (b.pressed ? [i] : []));
    $('#state').textContent =
      `Botones pulsados: ${pressed.join(', ') || '—'}\n` +
      `Ejes: ${pad.axes.map((a) => a.toFixed(2)).join('  ')}`;
    requestAnimationFrame(loop);
  }

  // Vibración: 'trigger-rumble' en los gatillos de mandos Xbox (Chrome), si no 'dual-rumble'
  $('#rumble').onclick = () => {
    const actuator = navigator.getGamepads()[index]?.vibrationActuator;
    const effect = actuator?.effects?.includes('trigger-rumble') ? 'trigger-rumble' : 'dual-rumble';
    actuator?.playEffect(effect, {
      duration: 400, strongMagnitude: 1, weakMagnitude: 0.5, leftTrigger: 0.8, rightTrigger: 0.8,
    });
  };
</script>

Novedades

  1. Chrome 149: prueba de origen de un evento de entrada de mando con menos latencia.
  2. Chrome 126: efecto trigger-rumble y lista de efectos (effects).

Ten en cuenta

  1. El estado no llega por eventos: consulta getGamepads() en cada fotograma (requestAnimationFrame).
  2. Firefox exige HTTPS. En iframes de otro origen, Chrome y Edge (103+) piden allow="gamepad".
  3. En Chrome, un efecto de más de 5 segundos (duración más retardo) se rechaza como invalid-parameter.

Más información

Fuentes