What it does
Each frame the worlds sort their objects into tables, one per layer. This backend draws each table as instanced
draws from the kernel's atlas, where every sprite, glyph and render texture lives. A layer is split into runs only
where the blend mode, the deform, the drawer or the texture changes, and draw order is never rearranged, so a frame
takes few draw calls and game.gpu.drawCalls shows how many. World layers draw first and screen layers after, so the
HUD is never lit or post-processed. Big pictures, loaded images wider or taller than 1024 pixels, get textures of their
own, uploaded once with a mip chain and sampled trilinearly, so they stay smooth when shown smaller.
The look columns are on every object. alpha multiplies its tint; blend is normal, add, multiply, screen or
subtract; uvRepeat tiles a frame across a quad and scrollX slides it, which is all a tile sprite is; and deform
turns the quad into a 24×64 mesh bent in the vertex stage, as a wave, a sway, a flip or a jelly wobble, or any kind a
deform-* pack registers. Deforms shade their own folds and animate on the simulation clock, so they pause and replay
with the game.
It is also the base other packs build on. It publishes the frame's device, encoder and target so lighting, post effects, 3D meshes and the debug overlay draw after it in order, and it gives a pack that draws some objects itself a slot inside the sprite pass, in sorted order. When the GPU device is lost, to a driver reset or a crash in another tab, it requests a new one and rebuilds every pipeline, the atlas and the instance buffer from CPU state, and the packs that hold GPU objects rebuild theirs.
Features
- Instanced sprite drawing — runs split only where blend, deform, drawer or texture change, in sorted order.
- Five blend modes — normal, add, multiply, screen and subtract, per object, premultiplied throughout.
- Tiling and scrolling —
uvRepeatandscrollXmake any sprite a tile sprite. - Vertex deforms — wave, sway, flip and jelly built in, more from
deform-*packs, shaded and on the simulation clock. - Big pictures — textures of their own with mipmaps and trilinear filtering, with the atlas sprites around them still batched.
- The HUD last — screen layers draw after lighting and post effects.
- Screenshots and recording — a PNG of the next frame, and WebM recording of the canvas at a bitrate you can set,
by default between 8 and 40 Mbit/s for the canvas size, with the game's sound when the
audiopack is playing it. - Device-loss recovery —
boot.contextLost, a rebuild from CPU state,boot.contextRestored, and aloseDevicecommand to exercise the path on purpose. - Extension points — custom drawers inside the sprite pass, a published frame bag for later passes, and
world-splitandworld-floorfor packs that light part of the world. - Diagnostics —
game.gpu.ready,drawCallsandlosses.
Good for
- Sprite-heavy 2D games — crowds of enemies, bullets and pickups, where a layer goes up in a few draws.
- Scenery and atmosphere — tiled, scrolling grounds, waving flags and swaying plants without extra art, using tiling and deforms.
- Card and board games — the flip deform turns a card over, and
deformFacingsays when to show its back. - Trailers and sharing — screenshots and in-game video recording.
- Games built on WebGPU-only packs —
skymaxskies andwatermaxoceans. - Pack authors — passes of their own on the published encoder, or objects drawn inside the sprite pass.
Make it yours
There are no options: the manifest's screen sets the logical size and whether pixelArt uses texel-snapped
sampling. What you shape is per object, its look columns, and the deform kinds you compose. Most games reach it
through render-auto. Compose it alone to test the WebGPU path by itself, or for a game that records video or tests
device loss, since only this backend fulfils those commands.
Two different uses. A 2D scene with a tiled ground scrolling under the player, an additive glow over a pickup, and a
flag waving with deform: { kind: 'wave', amount: 7, speed: 0.7 }. And a card game whose cards turn over with the
flip deform, swapping to the back frame past 90 degrees, recorded to video for a trailer.
A quick look
The look columns at spawn, and a screenshot:
game.spawn({ id: 'glow', frame, alpha: 0.8, blend: 'add' });
game.spawn({ id: 'wall', width: 256, height: 192, frame, uvRepeat: { x: 8, y: 6 } });
game.spawn({ id: 'flag', frame, deform: { kind: 'wave', amount: 7, speed: 0.7 } });
const png = await game.commands.run('screenshot');
Works with
render-auto— the renderer to compose; it picks this backend when the device has WebGPU.render-webgl2— the fallback for devices without WebGPU, with a few features fewer.world-side,world-topdownandworld-screen— the worlds whose sorted tables it draws.lighting-2d,post,render-3danddebug— draw after it on the frame it publishes.deform-curl— a further deform kind, requested by name like the built-in ones.effects-2d— a drawer of its own inside the sprite pass.
Good to know
- WebGPU only. Composed on its own in a browser without WebGPU, it stops the game starting:
game.start()rejects with the reason.render-autofalls back to WebGL2 instead. - The shared atlas holds sprites, glyphs and render textures on pages that open as it fills, and sprites on different pages draw as separate runs; a picture larger than the device's texture limit (8192 pixels by default) is reported once and not drawn.
- A deformed quad costs 9,216 vertices instead of 6, so a whole layer of deformed particles is not free.
- A deform snippet with a compile error stops every deformed object drawing until it is fixed; the error is logged with its line.
- If a lost device cannot be re-acquired the game keeps running without drawing; there is no software fallback.





