spryte 0.12: meshes and mipmaps
spryte can bend images now. mesh() stretches an image over triangles you place, for trails, ropes, waving flags and squashy sprites. On WebGL2 it joins the same batch as shapes and the sprites drawn after it, so it adds no draw calls. The same release adds opt-in mipmaps, which keep smooth images steady when they're drawn far below their size.
npm install spryte@latest
The mesh example: a 64x40 image bent over a 16x6 grid that moves every frame, and a ribbon that follows the pointer.
mesh()
import { mesh } from "spryte";
// A 32x32 image bent into a trapezoid: four vertices, two triangles.
mesh(
draw,
image,
[0, 0, 32, 0, -8, 32, 40, 32], // vertices: x, y pairs
[0, 0, 32, 0, 0, 32, 32, 32], // uvs: u, v pairs in source pixels
[0, 1, 2, 1, 3, 2], // three vertex numbers per triangle
);UVs are in source pixels from the frame's top-left, like everything else in spryte, so a frame inside an atlas works the same as a whole image. Vertices, UVs and indices can be typed arrays: keep the UVs and indices, and change only the vertices each frame. It takes the same tint, alpha, flash and smooth options as nineSlice and tiled.
A two-triangle mesh over a frame draws the same pixels as draw.sprite on WebGL2: 0 channels differ in spryte's browser parity test. The Canvas 2D fallback clips and draws each triangle on its own. It's slower, and edges shared between triangles can show faint lines (up to 25 of 255 on a channel in the same test), so meshes are best on WebGL2, which is nearly every browser.
mesh is its own import. It adds 1.6 kB brotli to an app that uses it, or 0.1 kB if the app already draws shapes, since meshes reuse the shape batch. Apps that don't import it grow by 0.08 kB. Measured with esbuild (minified, code splitting, brotli level 11) on the entry chunk.
Custom shaders don't apply to meshes yet.
Mipmaps
A smooth image drawn at a quarter of its size samples one source pixel in sixteen, so it shimmers as it moves. Zoomed-out maps, charts and thumbnails hit this. createRenderer(canvas, { mipmaps: true }) builds smaller copies of every image on upload and samples the size that fits.
It's off by default because it costs a third more GPU memory per image. Leave a few pixels between sprite-sheet frames, or neighbouring frames bleed in at small sizes. Pixel art (smooth: false) and render targets draw as before.
Also in this release
The docs now say that masks and GPU timers shipped (in 0.3.0 and 0.8.0) and list macOS Chrome among the measured platforms. Every change is in the changelog.
Try the mesh guide, or run the example from the spryte repo with npm run example:mesh.