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.
WebGPU está en los tres motores desde septiembre de 2025 y eso se cita constantemente como si zanjara la discusión. No la zanja. Que una API esté implementada en todos los navegadores y que esté disponible en todos los dispositivos que ejecutan esos navegadores son dos afirmaciones distintas, y la distancia entre ambas es justamente donde vive la decisión de despliegue que te toca tomar.
- Situar el estado real de WebGPU y de WebGL2 a mediados de 2026.
- Explicar por qué la cobertura de navegadores sobreestima la cobertura de dispositivos.
- Diseñar una escena con mejora progresiva de tres niveles.
- Instrumentar la aplicación para saber qué reciben tus usuarios de verdad.
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:
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.
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:
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”.
Hay proyectos donde tiene sentido: una herramienta interna, un producto para un público que controlas, una demostración técnica, algo cuyo valor central depende del cómputo en GPU y que sin él no es nada. En esos casos, pide WebGPU y muestra un mensaje claro a quien no lo tenga. Lo que no vale es llegar ahí por omisión, sin haber medido, y descubrir seis meses después que un porcentaje de dos cifras de las visitas veía una pantalla en blanco.
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:
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.
Hay un patrón que se repite en cada transición de tecnología web y que conviene reconocer antes de estar dentro de él. La discusión pública se organiza siempre alrededor de una fecha —“ya está en todos los navegadores”— y esa fecha marca el momento en que la tecnología deja de ser experimental, no el momento en que se puede asumir. Entre las dos hay siempre un intervalo de años, y su duración no la fija el ritmo de los navegadores sino el ritmo de reemplazo del hardware y de los sistemas operativos, que es mucho más lento y que ninguna decisión de un fabricante de navegadores puede acelerar. Pasó con WebGL, que estuvo en todos los motores mucho antes de poder usarse sin plan B. Pasó con los módulos ES, con las fuentes variables, con el grid. Y está pasando con WebGPU. Lo interesante es que el error caro no es el que uno teme. Quien va con retraso y sigue en WebGL2 en 2026 no pierde gran cosa: su escena funciona en todas partes, y adoptar WebGPU cuando le convenga le costará dos líneas gracias al diseño de Three.js. Quien va adelantado y exige WebGPU sin haberlo medido pierde usuarios sin enterarse, porque el fallo no es visible desde su lado: no hay error en su consola, no hay alerta, solo hay gente que abrió la página, no vio nada y se fue. Esa asimetría es la que debe gobernar la decisión. El coste de esperar es conocido y pequeño; el coste de adelantarse es invisible y potencialmente grande. Y la buena noticia es que en este caso concreto no hace falta elegir: WebGPURenderer con su respaldo automático te da la ruta rápida donde existe y la segura donde no, gratis, con una sola base de código. Que exista esa opción es, con diferencia, la mejor decisión de diseño de todo este tramo.
- Añade un interruptor de
forceWebGLpor parámetro de URL y ejecuta tu escena entera con él. - Instrumenta qué backend recibe cada visita y déjalo dos semanas.
- Diseña tres niveles de configuración y comprueba que solo cambia un objeto de parámetros.
- Mide el frame time en el nivel base sobre el dispositivo más modesto que quieras soportar.
- Simula un fallo total de inicialización y comprueba que tu mensaje de aviso aparece.