Saltar al contenido

Soporte real y mejora progresiva

Dónde está WebGPU en 2026, por qué cobertura de navegadores no es cobertura de dispositivos, y la estrategia de despliegue que no deja a nadie fuera.

Dónde estamos

La cronología es clara. Chrome llevó WebGPU a Windows, macOS y ChromeOS en 2023, a Android en 2024 y a Linux en 2025. Firefox lo activó por defecto durante 2025, empezando por Windows. Y Safari 26 lo implementó en septiembre de 2025 en macOS, iPadOS, iOS y visionOS, que es lo que completó la baraja: desde entonces, WebGPU está en los tres motores por defecto.

Es un hito real y merece reconocerse como tal. Durante años la respuesta a “¿puedo usar WebGPU?” fue “en Chrome”. Ya no lo es.

Al mismo tiempo, WebGL2 lleva años siendo universal en la práctica. Está en los cuatro navegadores, en versiones que la gente tiene desde hace mucho, y funciona en hardware que ya era viejo cuando WebGPU se especificaba. Su cobertura de dispositivos es, sencillamente, más alta.

Por qué las dos cifras no coinciden

Cuando una tabla de compatibilidad dice que WebGPU tiene un noventa y tantos por ciento de soporte, esa cifra se calcula sobre versiones de navegador ponderadas por uso. Hay al menos cinco motivos por los que la disponibilidad real en el dispositivo de un usuario concreto es menor.

El sistema operativo pone su propio suelo. El WebGPU de Safari llegó con Safari 26, y Safari se actualiza con el sistema. Un iPhone que no puede instalar la versión de iOS correspondiente no va a tener WebGPU nunca, por mucho que su navegador esté “al día” en el sentido que le queda. Lo mismo con macOS antiguo y con las versiones de Android que no alcanzan el mínimo que Chrome exige.

Los controladores gráficos se bloquean. Los navegadores mantienen listas de combinaciones de GPU y controlador donde WebGPU se desactiva por inestabilidad. Esas listas son largas, cambian con cada versión y afectan sobre todo a hardware integrado antiguo, que es exactamente el que más abunda en portátiles de trabajo y ordenadores de oficina.

La virtualización rompe la aceleración. Escritorios remotos, máquinas virtuales, entornos de escritorio como servicio, algunos contenedores de aplicaciones. En muchos de esos entornos no hay aceleración fiable, y WebGPU no arranca aunque el navegador sea la última versión.

Las políticas de empresa desactivan cosas. En entornos gestionados es frecuente que se apaguen funciones recientes por precaución.

Los navegadores integrados van por detrás. Una parte considerable del tráfico móvil llega desde vistas web dentro de aplicaciones, que no siempre exponen las mismas capacidades que el navegador completo del mismo dispositivo.

Ninguno de estos factores es exótico. Sumados, la diferencia entre “el navegador lo soporta” y “este dispositivo lo tiene” es de varios puntos porcentuales, y esos puntos son personas que abren tu página.

La postura correcta

No es “usa WebGPU que ya está en todos”. Es mejora progresiva: la experiencia base tiene que funcionar sobre WebGL2, y WebGPU añade encima lo que puede añadir.

Lo bueno es que Three.js ya está diseñado para eso, y usarlo bien casi no cuesta nada:

JS
import * as THREE from 'three/webgpu';// Intenta WebGPU; cae a WebGL2 solo si hace falta.const renderer = new THREE.WebGPURenderer( { antialias: true } );await renderer.init();

Eso es todo lo que hace falta para el caso general, y es lo que explica en detalle el fallback automático. Tu TSL genera GLSL o WGSL según lo que haya, tus materiales de nodos funcionan en los dos sitios, y el usuario no ve nada raro.

El trabajo empieza cuando quieres usar algo que solo existe en un lado.

Tres niveles, un código

El patrón que funciona en producción es diseñar la escena en niveles, y decidir cuál dar tras inicializar.

JS
import * as THREE from 'three/webgpu';async function arrancar() {  const renderer = new THREE.WebGPURenderer( { antialias: true } );  try {    await renderer.init();  } catch ( e ) {    mostrarAvisoSinAceleracion();    return;  }  const esWebGPU = renderer.backend.constructor.name === 'WebGPUBackend';  const movil = matchMedia( '(pointer: coarse)' ).matches;  let nivel;  if ( esWebGPU && ! movil ) nivel = 'alto';  else if ( esWebGPU ) nivel = 'medio';  else nivel = 'base';  const config = {    base:  { particulas: 6000,   gpu: false, sombras: false, ratio: 1 },    medio: { particulas: 40000,  gpu: true,  sombras: true,  ratio: 1.5 },    alto:  { particulas: 250000, gpu: true,  sombras: true,  ratio: 2 }  }[ nivel ];  renderer.setPixelRatio( Math.min( devicePixelRatio, config.ratio ) );  renderer.shadowMap.enabled = config.sombras;  montarEscena( renderer, config );}arrancar();

La clave de este diseño es que hay una sola escena, con un parámetro de configuración, y no tres aplicaciones distintas. Solo el sistema de partículas necesita dos implementaciones de verdad, y eso es porque el cómputo en GPU no es un ajuste sino otra arquitectura, como viste en lo que solo existe con WebGPU.

Mide lo que reciben de verdad

La parte que casi nadie hace y que convierte todo lo anterior de conjetura en información:

JS
await renderer.init();const backend = renderer.backend.constructor.name;analitica( 'render_backend', {  backend,  nivel,  fabricante: navigator.userAgentData ? navigator.userAgentData.platform : navigator.platform} );

Con dos semanas de esos datos sabrás qué porcentaje de tus usuarios recibe cada backend, y esa cifra —la tuya, no la de una tabla general— es la que debe gobernar tus decisiones. Un producto para desarrolladores y un producto para el público general pueden tener repartos completamente distintos.

Añade un contador de frame time por nivel y tendrás lo que de verdad necesitas para presupuestar: no “cuánto cuesta mi escena” sino “cuánto cuesta mi escena en el peor de los caminos que estoy sirviendo”.

Y sobre TSL

Una nota final que cierra el tramo. Adoptar TSL no obliga a exigir WebGPU. Los materiales de nodos se importan de three/webgpu, pero eso es un punto de entrada de módulo, no un requisito de hardware: WebGPURenderer los renderiza con el backend que haya, y el generador de nodos emite GLSL cuando toca.

Y si por alguna razón necesitas conservar el WebGLRenderer clásico —porque dependes de un addon que solo funciona con él, o porque la migración del renderer es un paso que aún no quieres dar— r184 incluye un puente:

JS
import * as THREE from 'three/webgpu';import { WebGLRenderer } from 'three';import { WebGLNodesHandler } from 'three/addons/tsl/WebGLNodesHandler.js';const renderer = new WebGLRenderer( { antialias: true } );renderer.setNodesHandler( new WebGLNodesHandler() );

Sus limitaciones están escritas en el propio fichero y conviene leerlas antes de apoyarse en él: sin sombras VSM, sin MRT, sin transmisión, sin la pila de post-procesado de nodos, sin texturas de almacenamiento, y con algunas restricciones sobre geometría compartida y compilación anticipada. Es explícitamente un puente de migración.