Redraw is currently in technical preview, available to wcandillon.dev subscribers. API is unstable.
Images
Redraw draws images from plain GPUTextures. Textures live on the
device, not on a Library, so any canvas can sample them; a set of
factories covers the common sources.
Creating textures
import { makeTexture, makeTextureFromCanvas, makeTextureFromImage } from "redraw";
// From raw RGBA pixels (straight alpha, width * height * 4 bytes):
const texture = makeTexture(device, width, height, data);
// From an image source (Blob, ImageData, another canvas, ...):
const photo = await makeTextureFromImage(device, blob);
// Snapshot a 2D canvas's current contents:
const snapshot = makeTextureFromCanvas(device, canvasElement);
All textures are rgba8unorm with straight (un-premultiplied) alpha.
The caller owns the texture: destroy it when no canvas samples it
anymore. In React, get the device with the useDevice() hook (see
React).
drawImage
canvas.drawImage(texture, x?, y?, options?) draws the texture with its
top-left corner at (x, y) in local space, one texel per local unit
(scale via the canvas transform):
canvas.save();
canvas.scale(0.5);
canvas.drawImage(photo, 40, 40, { filter: "linear" });
canvas.restore();
The options:
| Option | Default | What it does |
|---|---|---|
filter | "nearest" | Sampling filter: "nearest", "linear", or a cubic resampler { B, C } (e.g. { B: 1/3, C: 1/3 } for Mitchell). |
tileMode | "decal" | What lies outside the image rect: transparent ("decal") or the image tiled across the whole clip region ("repeat"). |
Shading geometry with an image
drawImage covers the common case; to shade arbitrary geometry with
an image, claim a texture slot yourself and add an ImageShader as the
paint's color shader:
import { Circle, ImageShader, Paint } from "redraw";
const slot = canvas.useTexture(photo);
const paint = new Paint().addShader(
new ImageShader(slot, [photo.width, photo.height], {
filter: "linear",
offset: [40, 40],
}),
);
canvas.draw(new Circle([200, 200], 120), paint);
Texture slots are per-frame state, reset by render() like the rest of
the recording. The same texture always reuses its slot, so only
distinct textures count against the Library's textureSlots (1 by
default); pass a larger textureSlots to createLibrary when a frame
samples more.