Alternativa ao PixiJS mais rápida? Testamos spryte, o renderizador 2D de 10 kB ✅ yoDEV Tested

Sim: spryte, um novo renderizador 2D para a web com licença MIT, desenhou sprites entre 2 e 3,9 vezes mais rápido que PixiJS em oito cenas de 2dbench no nosso MacBook, e seu JavaScript de inicialização pesa 10,8 kB contra 90 kB. Mas não ganha em tudo: em cenas com muito texto perdeu por muito, e aqui mostramos exatamente onde.

:white_check_mark: yoDEV Testado · 20 de outubro de 2026 Instalamos spryte 0.2.1, medimos seu bundle contra PixiJS 8.22.0, passamos a verificação de paridade de 2dbench em Chromium headless e rodamos a suite completa de 2dbench em um MacBook com Apple M5 Pro no Chrome 155. Os resultados que reportamos como nossos saem dessa prova.

O que é spryte?

spryte é um renderizador 2D em modo imediato para o navegador. Em cada frame você diz o que desenhar e agrupa tudo sobre WebGL2 com instancing. Pode desenhar:

  • sprites e sprites em lote
  • retângulos, círculos e linhas
  • texto, recortes e modos de mesclagem
  • render targets e shaders próprios

Não tem dependências, nem scene graph, nem um framework de jogos por trás. É o renderizador de debuff, o projeto de jogos do seu autor, onde já rodamjogos. É publicado no npm pela conta debuffjp.

No momento de publicar esta nota (20 de outubro de 2026), spryte é muito novo:

  • A primeira versão chegou ao npm em 19 de outubro de 2026, e a 0.2.1 saiu um dia depois.
  • O README o marca como alpha, e sua API pode mudar antes da 1.0.

O que é WebGL e o que acontece se o navegador não tiver?

WebGL é a API do navegador que dá acesso à GPU a partir de JavaScript, e WebGL2 é sua versão atual. spryte a usa para desenhar milhares de sprites em poucas chamadas à GPU.

Se o navegador não tiver WebGL2, spryte muda sozinho para Canvas 2D, a API de desenho clássica de canvas em JavaScript. Esse fallback vem em um fragmento separado que os navegadores com WebGL2 nunca baixam.

Comprovamos na versão 0.2.1:

  • Com backend: "auto" escolheu webgl2.
  • Com backend: "2d" desenhou corretamente sobre Canvas 2D.

Em que se diferencia de PixiJS?

PixiJS trabalha em modo retido (retained mode): você cria um Sprite uma vez, o adiciona ao stage e muda suas propriedades com o tempo, e o stage lembra o que desenhar. spryte não guarda nada entre frames. Em cada frame você chama draw.sprite(...) para tudo o que está visível, e o estado do seu jogo é a única fonte da verdade.

Dessa diferença sai a velocidade. Um Sprite de PixiJS é um objeto que a biblioteca atualiza, mede e agrupa em cada frame. spryte, por outro lado, escreve alguns poucos números por sprite em um typed array e deixa a GPU fazer o resto.

Daí sai também o custo. Tudo o que o scene graph fazia por você passa a ser código seu:

  • o hit-testing e os eventos do ponteiro
  • as transformações aninhadas
  • o ajuste de linha do texto

Assim se parece um loop mínimo com spryte, tomado do guia oficial:

import { createRenderer } from "spryte";

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

function frame() {
  draw.begin("#111", 320, 180, 2); // cor de limpeza, tamanho lógico, pixels de suporte por unidade lógica
  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 instalá-lo:

npm install spryte

Comprovamos que adiciona exatamente um pacote ao seu projeto.

spryte é mais rápido que PixiJS?

No nosso hardware, sim: entre 2 e 3,9 vezes no caminho geral de sprites. Rodamos a suite completa de 2dbench em 20 de outubro de 2026 com essa configuração:

Configuração Valor
Máquina MacBook com Apple M5 Pro
Navegador Chrome 155 no macOS, conectado à corrente
Rodadas 3

2dbench fixa spryte 0.1.0 e PixiJS 8.22.0, então essas são as versões medidas.

Antes de medir nada, cada renderizador teve que passar uma verificação de paridade de pixels, que confirma que todas as bibliotecas desenharam o mesmo frame. Os números são a mediana do tempo por frame em milissegundos, então menos é melhor.

Uma chamada por sprite: draw.sprite contra Sprite de PixiJS

Cena spryte, máx. a 60 fps PixiJS, máx. a 60 fps spryte com 50k PixiJS com 50k Vantagem 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 (com 10k inimigos) 20 000 10 000 5,5 ms 14,4 ms 2,6×

Essa é a comparação que mais importa na prática: você desenha cada objeto você mesmo, com uma chamada por objeto. A cifra do autor, de 2 a 4 vezes, se reproduz em Apple Silicon, uma plataforma que seus resultados publicados ainda não cobriam.

Enviamos nossa rodada ao dataset público de 2dbench como a issue #22. No momento de publicar esta nota, ainda aguardava a revisão do mantenedor.

Em lote: draw.sprites contra ParticleContainer de PixiJS

Cena spryte, máx. a 60 fps PixiJS, máx. a 60 fps spryte com 200k PixiJS com 200k Vantagem 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×

No caminho em lote a diferença é menor. Em três cenas, as duas bibliotecas sustentaram 800 000 sprites a 60 fps. Essa é a cifra de “800k sprites” do gráfico de spryte, e no nosso Mac é um empate nessa contagem, não uma vantagem.

Mesmo assim, spryte desenha cada frame mais rápido, e isso te deixa mais margem para a lógica do seu jogo.

Em que spryte perde contra PixiJS?

Em cenas com muito texto. Com 1000 rótulos que mudam a cada poucos frames, draw.text de spryte levou 270 ms por frame. Text de PixiJS levou 39,5 ms na mesma cena, e BitmapText de PixiJS sustentou 5000 rótulos a 60 fps.

Uma nuança importante: o adaptador de 2dbench usa draw.text e não o BitmapFont que spryte também oferece, então não é a configuração mais favorável para spryte. Mesmo assim, se seu projeto é um HUD cheio de números que mudam, teste antes de se comprometer.

Na cena churn não há resultado de spryte. Em churn, os sprites são criados e destruídos o tempo todo, como balas e objetos colecionáveis de um jogo. spryte não passou lá na verificação de paridade de 2dbench: com 2000 sprites cobriu 99,3 por cento da área esperada, e o limiar exige 99,5. Um renderizador que não passa essa verificação nunca é medido. É uma medição que falta, não um resultado lento, e por isso ainda não podemos dizer como spryte se comporta com churn.

Em cenas que ninguém mediu ainda. As notas de benchmark do autor, em 20 de outubro de 2026, listam várias cenas como não medidas:

  • o crescimento de memória
  • o tempo de carga
  • o tempo até o primeiro frame

Quanto pesa contra PixiJS?

Oito vezes menos na inicialização. Montamos a mesma app de um sprite com cada biblioteca, com um build de produção de Vite 8 comprimido com brotli na qualidade máxima. A app de PixiJS usou Application, Assets e Sprite.

JS de inicialização Todo o JS, com fragmentos diferidos
spryte 0.2.1 10,8 kB 12,3 kB
PixiJS 8.22.0 90,0 kB 155,6 kB

São 8,3 vezes menos na inicialização. O autor reporta 8,7 vezes para a versão 0.1.1, então “uma nona parte do tamanho” se sustenta dentro da diferença entre versões.

A parte diferida de spryte é o fallback de Canvas 2D.

Como rodar 2dbench no seu próprio equipamento?

O jeito mais rápido é abrir 2dbench: run on this device, escrever seu dispositivo no campo de nota e clicar em Run. Leva alguns minutos, e a página pede manter a tela acesa, a aba à frente e o equipamento conectado à corrente se conseguir.

Desmarque “Quick run” para fazer três rodadas em vez de uma, o que é mais confiável. Quando terminar você vê seus gráficos localmente: nada é enviado até que clique em Submit.

Desde um equipamento de desktop com Chrome ou Edge instalado:

git clone https://github.com/debuffjp/2dbench
cd 2dbench
npm install
node run.mjs                        # bunny, todo adaptador, 5 rodadas
node run.mjs particles
node run.mjs mixed spryte pixi-sprite rounds=7
node run.mjs bunny rounds=0         # apenas verificação de paridade (rápido)

Cada rodada escreve um JSON em results/ e imprime uma tabela em markdown.

No Linux, Chrome headless cai em renderização por software, então rode com uma janela visível: HEADED=1 node run.mjs particles.

No nosso ambiente de testes, que não tem GPU, usamos rounds=0, que roda apenas a verificação de paridade. Passou em bunny, particles, mixed e raycaster:

  • Dentro dos sprites não houve nem um pixel diferente com respeito a PixiJS.
  • Nas bordas, as cenas com rotação diferiram entre 8 e 13 por cento. Isso coincide com o arredondamento de esquinas rotadas que o autor documenta.

O benchmark foi criado pelo próprio autor de spryte, e o README o declara de entrada. A referência de paridade é Sprite de PixiJS, não spryte, e os mantenedores de cada biblioteca estão convidados a revisar seu adaptador. Esse conflito de interesses é justamente a razão para rodá-lo você mesmo em vez de confiar no gráfico de ninguém, incluindo o nosso.

Como migrar de PixiJS para spryte?

Comece movendo apenas seu efeito mais pesado. O guia oficial de migração sugere desenhar as partículas ou as balas com spryte em um canvas transparente acima do de PixiJS e comparar os tempos por frame. A opção transparent requer spryte 0.2 ou 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(() => {
  // limpeza transparente: PixiJS aparece por trás
  draw.begin("#0000", 320, 180, overlay.width / 320);
  draw.sprites(bullet, bulletPositions, bulletCount);
  draw.end();
});

O guia o apresenta como uma forma de avaliar, não como uma arquitetura para ficar. Dois renderizadores implicam:

  • dois contextos de GPU
  • texturas duplicadas
  • uma camada sobreposta que sempre fica acima

Quando os números o convencerem, a migração completa segue a tabela de equivalências do guia. As principais:

PixiJS 8 spryte
new Application(), app.init(...) createRenderer(canvas, { smooth }) + draw.resize(w, h)
app.ticker.add(fn) seu próprio loop com requestAnimationFrame
new Sprite(texture) + propriedades draw.sprite(image, x, y, { rotation, scaleX, scaleY, alpha, tint })
ParticleContainer draw.sprites(frame, positions, count, options, { scale, rotation, color })
transformações de Container draw.push(), translate, rotate, scale, draw.pop()
zIndex ordene seus dados e desenhe nessa ordem
on("pointerdown") seu próprio hit-testing sobre o estado do jogo

As partículas são onde mais se ganha. Se guardar seu estado em typed arrays, um ParticleContainer inteiro se converte em uma única chamada:

const MAX = 50_000;
const pos = new Float32Array(MAX * 2);    // pares x, y que sua simulação atualiza
const scale = new Float32Array(MAX);
const rotation = new Float32Array(MAX);
const color = new Uint32Array(MAX);       // 0xRRGGBBAA
let live = 0;

// cada frame, após atualizar os arrays:
draw.sprites(spark, pos, live, {}, { scale, rotation, color });

Se seu projeto depende muito de árvores de cena profundas, o próprio guia recomenda manter essas partes em PixiJS.

spryte serve para fazer jogos em JavaScript?

Sim, para isso nasceu, e também serve para qualquer coisa que mova muitos objetos 2D no navegador:

  • jogos como bullet hells, efeitos de partículas e mapas de tiles
  • visualizações com milhares de pontos em tempo real
  • arte generativa
  • efeitos de interface como confete ou fundos animados

A pergunta real é se convém levá-lo para produção hoje. Se seu gargalo é desenhar muitos sprites em movimento, vale uma tarde de testes, mas fixe a versão exata. Em 20 de outubro de 2026 tem dois dias, é pré-1.0 e está marcado como alpha, com seis versões publicadas em seus primeiros dois dias.

Seu manejo da perda de contexto WebGL funcionou na nossa prova, mas no momento de publicar esta nota o autor ainda não o havia medido no Safari para macOS.

Se sua app é principalmente texto, árvores de interface profundas ou interação com o ponteiro, PixiJS ainda faz mais por você. E se procura um motor de jogos completo como Phaser, tenha em conta que 2dbench ainda não o inclui: está na lista de bibliotecas que o projeto quer somar.

spryte é grátis?

Sim. spryte e 2dbench têm licença MIT, e os dados de resultados de 2dbench são publicados sob CC0.


E você? Qual parte do seu projeto move mais objetos por frame: partículas, tiles, texto ou algo mais?

Testaria spryte no seu projeto?
  • Sim, começando pelo meu efeito mais pesado
  • Sim, mas quando chegar à 1.0
  • Não, PixiJS me atende
  • Prefiro outra opção (conte qual)
0 votantes

Comente abaixo ou, se este artigo chegou por email, responda diretamente ao email: sua resposta é publicada aqui.

Relacionado: Como fazer um bottom sheet acessível na web com CSS scroll snap: testamos e medimos