¿Alternativa a PixiJS más rápida? Probamos spryte, el renderizador 2D de 10 kB ✅ yoDEV Tested

Sí: spryte, un nuevo renderizador 2D para la web con licencia MIT, dibujó sprites entre 2 y 3.9 veces más rápido que PixiJS en ocho escenas de 2dbench en nuestro MacBook, y su JavaScript de arranque pesa 10.8 kB frente a 90 kB. Pero no gana en todo: en escenas con mucho texto perdió por mucho, y aquí te mostramos exactamente dónde.

:white_check_mark: yoDEV Tested · 20 de octubre de 2026 Instalamos spryte 0.2.1, medimos su bundle frente a PixiJS 8.22.0, pasamos la verificación de paridad de 2dbench en Chromium headless y corrimos la suite completa de 2dbench en un MacBook con Apple M5 Pro en Chrome 155. Los resultados que reportamos como nuestros salen de esa prueba.

¿Qué es spryte?

spryte es un renderizador 2D en modo inmediato para el navegador. En cada frame le dices qué dibujar y lo agrupa todo sobre WebGL2 con instancing. Puede dibujar:

  • sprites y sprites en bloque
  • rectángulos, círculos y líneas
  • texto, recortes y modos de mezcla
  • render targets y shaders propios

No tiene dependencias, ni scene graph, ni un framework de juegos detrás. Es el renderizador de debuff, el proyecto de juegos de su autor, donde ya corren juegos. Está publicado en npm por la cuenta debuffjp.

Al momento de publicar esta nota (20 de octubre de 2026), spryte es muy nuevo:

  • La primera versión llegó a npm el 19 de octubre de 2026, y la 0.2.1 salió un día después.
  • El README lo marca como alpha, y su API puede cambiar antes de la 1.0.

¿Qué es WebGL y qué pasa si el navegador no lo tiene?

WebGL es la API del navegador que da acceso a la GPU desde JavaScript, y WebGL2 es su versión actual. spryte la usa para dibujar miles de sprites en pocas llamadas a la GPU.

Si el navegador no tiene WebGL2, spryte cambia solo a Canvas 2D, la API de dibujo clásica de canvas en JavaScript. Ese respaldo viene en un fragmento aparte que los navegadores con WebGL2 nunca descargan.

Lo comprobamos en la versión 0.2.1:

  • Con backend: "auto" eligió webgl2.
  • Con backend: "2d" dibujó correctamente sobre Canvas 2D.

¿En qué se diferencia de PixiJS?

PixiJS trabaja en modo retenido (retained mode): creas un Sprite una vez, lo agregas al stage y cambias sus propiedades con el tiempo, y el stage recuerda qué dibujar. spryte no guarda nada entre frames. En cada frame llamas a draw.sprite(...) para todo lo visible, y el estado de tu juego es la única fuente de verdad.

De esa diferencia sale la velocidad. Un Sprite de PixiJS es un objeto que la librería actualiza, mide y agrupa en cada frame. spryte, en cambio, escribe unos pocos números por sprite en un typed array y deja que la GPU haga el resto.

De ahí sale también el costo. Todo lo que hacía el scene graph por ti pasa a ser código tuyo:

  • el hit-testing y los eventos del puntero
  • las transformaciones anidadas
  • el ajuste de línea del texto

Así se ve un loop mínimo con spryte, tomado de la guía oficial:

import { createRenderer } from "spryte";

const draw = createRenderer(canvas, { smooth: false }); // smooth: false for pixel art
canvas.width = 640;
canvas.height = 360;
draw.resize(canvas.width, canvas.height);

function frame() {
  draw.begin("#111", 320, 180, 2); // clear colour, logical size, backing pixels per logical unit
  draw.rect(10, 10, 40, 20, "#cffb2d");
  draw.sprite(image, 160, 90, { rotation: 0.3, tint: "#f0f" });
  draw.text("hello", 8, 8);
  draw.end();
  requestAnimationFrame(frame);
}
requestAnimationFrame(frame);

Para instalarlo:

npm install spryte

Comprobamos que agrega exactamente un paquete a tu proyecto.

¿Es spryte más rápido que PixiJS?

En nuestro hardware, sí: entre 2 y 3.9 veces en el camino general de sprites. Corrimos la suite completa de 2dbench el 20 de octubre de 2026 con esta configuración:

Configuración Valor
Máquina MacBook con Apple M5 Pro
Navegador Chrome 155 en macOS, conectado a la corriente
Rondas 3

2dbench fija spryte 0.1.0 y PixiJS 8.22.0, así que esas son las versiones medidas.

Antes de medir nada, cada renderizador tuvo que pasar una verificación de paridad de píxeles, que confirma que todas las librerías dibujaron el mismo frame. Las cifras son la mediana del tiempo por frame en milisegundos, así que menos es mejor.

Un llamado por sprite: draw.sprite frente a Sprite de PixiJS

Escena spryte, máx. a 60 fps PixiJS, máx. a 60 fps spryte con 50k PixiJS con 50k Ventaja de spryte
bunny 400 000 100 000 2.1 ms 6.2 ms 3.0×
mixed 200 000 50 000 3.6 ms 9.9 ms 2.8×
particles 200 000 50 000 3.4 ms 9.7 ms 2.9×
tilemap 200 000 50 000 2.6 ms 10.2 ms 3.9×
clip 400 000 50 000 2.4 ms 7.5 ms 3.1×
lowres 200 000 100 000 2.7 ms 6.1 ms 2.3×
upload 200 000 100 000 3.4 ms 6.7 ms 2.0×
raycaster (con 10k enemigos) 20 000 10 000 5.5 ms 14.4 ms 2.6×

Esta es la comparación que más importa en la práctica: dibujas cada objeto tú mismo, con un llamado por objeto. La cifra del autor, de 2 a 4 veces, se reproduce en Apple Silicon, una plataforma que sus resultados publicados todavía no cubrían.

Enviamos nuestra corrida al dataset público de 2dbench como el issue #22. Al momento de publicar esta nota, seguía a la espera de la revisión del mantenedor.

En bloque: draw.sprites frente a ParticleContainer de PixiJS

Escena spryte, máx. a 60 fps PixiJS, máx. a 60 fps spryte con 200k PixiJS con 200k Ventaja de spryte
bunny 800 000 800 000 2.0 ms 3.6 ms 1.8×
particles 400 000 200 000 4.6 ms 11.3 ms 2.5×
lowres 800 000 800 000 2.3 ms 4.1 ms 1.8×
upload 800 000 800 000 2.9 ms 4.7 ms 1.6×

En el camino en bloque la diferencia es menor. En tres escenas, las dos librerías sostuvieron 800 000 sprites a 60 fps. Esa es la cifra de “800k sprites” del gráfico de spryte, y en nuestro Mac es un empate a ese conteo, no una ventaja.

Aun así, spryte dibuja cada frame más rápido, y eso te deja más margen para la lógica de tu juego.

¿En qué pierde spryte frente a PixiJS?

En escenas con mucho texto. Con 1000 etiquetas que cambian cada pocos frames, draw.text de spryte tardó 270 ms por frame. Text de PixiJS tardó 39.5 ms en la misma escena, y BitmapText de PixiJS sostuvo 5000 etiquetas a 60 fps.

Un matiz importante: el adaptador de 2dbench usa draw.text y no el BitmapFont que spryte también ofrece, así que no es la configuración más favorable para spryte. Aun así, si tu proyecto es un HUD lleno de números que cambian, pruébalo antes de comprometerte.

En la escena churn no hay resultado de spryte. En churn, los sprites se crean y se destruyen todo el tiempo, como las balas y los objetos recogibles de un juego. spryte no pasó ahí la verificación de paridad de 2dbench: con 2000 sprites cubrió el 99.3 por ciento del área esperada, y el umbral exige 99.5. Un renderizador que no pasa esa verificación nunca se mide. Es una medición que falta, no un resultado lento, y por eso todavía no podemos decirte cómo se comporta spryte con churn.

En escenas que nadie ha medido todavía. Las notas de benchmark del autor, al 20 de octubre de 2026, listan varias escenas como no medidas:

  • el crecimiento de memoria
  • el tiempo de carga
  • el tiempo hasta el primer frame

¿Cuánto pesa frente a PixiJS?

Unas ocho veces menos al arrancar. Armamos la misma app de un sprite con cada librería, con un build de producción de Vite 8 comprimido con brotli a la máxima calidad. La app de PixiJS usó Application, Assets y Sprite.

JS de arranque Todo el JS, con fragmentos diferidos
spryte 0.2.1 10.8 kB 12.3 kB
PixiJS 8.22.0 90.0 kB 155.6 kB

Son 8.3 veces menos al arrancar. El autor reporta 8.7 veces para la versión 0.1.1, así que “una novena parte del tamaño” se sostiene dentro de la diferencia entre versiones.

La parte diferida de spryte es el respaldo de Canvas 2D.

¿Cómo correr 2dbench en tu propio equipo?

La forma más rápida es abrir 2dbench: run on this device, escribir tu dispositivo en el campo de nota y pulsar Run. Tarda unos minutos, y la página pide mantener la pantalla encendida, la pestaña al frente y el equipo conectado a la corriente si puedes.

Desmarca “Quick run” para hacer tres rondas en vez de una, que es más confiable. Al terminar ves tus gráficos en local: no se envía nada hasta que pulsas Submit.

Desde un equipo de escritorio con Chrome o Edge instalado:

git clone https://github.com/debuffjp/2dbench
cd 2dbench
npm install
node run.mjs                        # bunny, every adapter, 5 rounds
node run.mjs particles
node run.mjs mixed spryte pixi-sprite rounds=7
node run.mjs bunny rounds=0         # parity gate only (fast)

Cada corrida escribe un JSON en results/ e imprime una tabla en markdown.

En Linux, Chrome headless cae a renderizado por software, así que corre con una ventana visible: HEADED=1 node run.mjs particles.

En nuestro entorno de pruebas, que no tiene GPU, usamos rounds=0, que corre solo la verificación de paridad. Pasó en bunny, particles, mixed y raycaster:

  • Dentro de los sprites no hubo ni un píxel distinto respecto de PixiJS.
  • En los bordes, las escenas con rotación difirieron entre 8 y 13 por ciento. Eso coincide con el redondeo de esquinas rotadas que documenta el autor.

El benchmark lo creó el propio autor de spryte, y el README lo declara de entrada. La referencia de paridad es Sprite de PixiJS, no spryte, y los mantenedores de cada librería están invitados a revisar su adaptador. Ese conflicto de interés es justamente la razón para correrlo tú mismo en vez de confiar en el gráfico de nadie, incluido el nuestro.

¿Cómo migrar de PixiJS a spryte?

Empieza moviendo solo tu efecto más pesado. La guía oficial de migración sugiere dibujar las partículas o las balas con spryte en un canvas transparente encima del de PixiJS y comparar los tiempos por frame. La opción transparent requiere spryte 0.2 o posterior.

const overlay = document.createElement("canvas");
overlay.width = app.canvas.width;
overlay.height = app.canvas.height;
overlay.style.cssText = "position:absolute;inset:0;pointer-events:none;width:100%;height:100%";
app.canvas.parentElement!.append(overlay);

const draw = createRenderer(overlay, { smooth: false, transparent: true });
draw.resize(overlay.width, overlay.height);

app.ticker.add(() => {
  // transparent clear: PixiJS shows through
  draw.begin("#0000", 320, 180, overlay.width / 320);
  draw.sprites(bullet, bulletPositions, bulletCount);
  draw.end();
});

La guía lo presenta como una forma de evaluar, no como una arquitectura para quedarse. Dos renderizadores implican:

  • dos contextos de GPU
  • texturas duplicadas
  • una capa superpuesta que siempre queda encima

Cuando los números te convenzan, la migración completa sigue la tabla de equivalencias de la guía. Las principales:

PixiJS 8 spryte
new Application(), app.init(...) createRenderer(canvas, { smooth }) + draw.resize(w, h)
app.ticker.add(fn) tu propio loop con requestAnimationFrame
new Sprite(texture) + propiedades draw.sprite(image, x, y, { rotation, scaleX, scaleY, alpha, tint })
ParticleContainer draw.sprites(frame, positions, count, options, { scale, rotation, color })
transformaciones de Container draw.push(), translate, rotate, scale, draw.pop()
zIndex ordena tus datos y dibuja en ese orden
on("pointerdown") tu propio hit-testing sobre el estado del juego

Las partículas son donde más se gana. Si guardas su estado en typed arrays, un ParticleContainer entero se convierte en un solo llamado:

const MAX = 50_000;
const pos = new Float32Array(MAX * 2);    // x, y pairs your simulation updates
const scale = new Float32Array(MAX);
const rotation = new Float32Array(MAX);
const color = new Uint32Array(MAX);       // 0xRRGGBBAA
let live = 0;

// each frame, after updating the arrays:
draw.sprites(spark, pos, live, {}, { scale, rotation, color });

Si tu proyecto depende mucho de árboles de escena profundos, la propia guía recomienda mantener esas partes en PixiJS.

¿Sirve spryte para hacer juegos en JavaScript?

Sí, para eso nació, y también sirve para cualquier cosa que mueva muchos objetos 2D en el navegador:

  • juegos como bullet hells, efectos de partículas y mapas de tiles
  • visualizaciones con miles de puntos en vivo
  • arte generativo
  • efectos de interfaz como confeti o fondos animados

La pregunta real es si conviene llevarlo a producción hoy. Si tu cuello de botella es dibujar muchos sprites en movimiento, vale una tarde de pruebas, pero fija la versión exacta. Al 20 de octubre de 2026 tiene dos días, es pre-1.0 y está marcado como alpha, con seis versiones publicadas en sus primeros dos días.

Su manejo de la pérdida de contexto WebGL funcionó en nuestra prueba, pero al momento de publicar esta nota el autor todavía no lo había medido en Safari para macOS.

Si tu app es sobre todo texto, árboles de interfaz profundos o interacción con el puntero, PixiJS todavía hace más por ti. Y si buscas un motor de juegos completo como Phaser, ten en cuenta que 2dbench aún no lo incluye: está en la lista de librerías que el proyecto quiere sumar.

¿spryte es gratis?

Sí. spryte y 2dbench tienen licencia MIT, y los datos de resultados de 2dbench se publican bajo CC0.


¿Y tú? ¿Qué parte de tu proyecto mueve más objetos por frame: partículas, tiles, texto o algo más?

¿Probarías spryte en tu proyecto?
  • Sí, empezando por mi efecto más pesado
  • Sí, pero cuando llegue a la 1.0
  • No, PixiJS me alcanza
  • Prefiero otra opción (cuéntanos cuál)
0 votantes

Comenta abajo o, si este artículo te llegó por correo, responde directamente al email: tu respuesta se publica aquí.

Relacionado: Cómo hacer un bottom sheet accesible en la web con CSS scroll snap: lo probamos y medimos