Redraw is currently in technical preview, available to start-react-native.dev subscribers. API is unstable.
Drawings
Two objects do most of the work in Redraw: a Surface owns the GPU target, and a Canvas records what to draw. The split matters: it's why animation in Redraw is fast and stateless from the user's perspective.
Surface
A Surface wraps the destination texture. You get one from a
Redraw instance:
import { RedrawInit } from "redraw";
const redraw = await RedrawInit();
// Onscreen: bind to an HTML canvas element
const surface = redraw.makeSurfaceFromCanvas(htmlCanvasElement);
// Offscreen: render into an internally-managed texture
const surface = redraw.makeSurfaceOffscreen(width, height);
If you're using the React binding, useRedraw() from react-redraw boots
both RedrawInit and a Surface bound to a <canvas> ref for you.
Canvas
A Canvas is a recorder. You call methods like drawPath, drawCircle,
pushTransform, pushLayer on it; each call appends to an internal
display list: an immutable sequence of GPU commands. The Canvas
isn't drawing anything yet.
import { Canvas, Brush } from "redraw";
const canvas = new Canvas({ dpr: window.devicePixelRatio });
canvas.fillColor("#1a1a2e");
const brush = new Brush();
brush.addFill("#3FCEBC");
canvas.drawCircle([200, 200], 80, brush);
Here are the most important canvas methods:
| Method | What it appends |
|---|---|
fillColor(color) | Solid background fill. |
drawPath(path, brush, options?) | A path stroked or filled with brush. |
draw(geometry, brush) | Any RenderNode (Circle, RoundedRect, …). |
addGeometry(path) / drawGeometry(geo, brush) | Add a path to be drawn/instanciated many times. |
pushTransform() / popTransform() | Save/restore the transform stack. |
transform(matrix) | Apply a MatrixTransform to subsequent draws. |
pushLayer(descriptor) / popLayer() | Open/close a feathered, optionally tinted layer. |
pushClip(node) / pushFeather(node) | Lower-level clip / feather variants. |
Each method that produces a node returns a handle you can mutate later; that's how animation works without rebuilding the scene.
Render
Once your recording is ready, you can send it to the surface.
surface.flush(canvas);
Animate
The methods that draw something into the Canvas (drawCircle, drawPath,
addGeometry, etc.) return a handle to the node they appended.
Mutating that handle changes what gets drawn on the next flush:
import { Brush } from "redraw";
const brush = new Brush();
brush.addFill("#3FCEBC");
const dot = canvas.drawCircle([100, 100], 40, brush);
// later, between flushes:
dot.center = [200, 150];
dot.radius = 60;
surface.flush(canvas);
There's no animation callback in Redraw; the library just records draws and flushes them. The pattern the example gallery and the React bindings use is to split your code into two phases: build the display list once, then run a frame loop that mutates handles and reflushes. That's a convention, not an API; see Hello World for how the convention plugs into vanilla JS, React, and React Native hosts.
For closed-form motion, redraw exports a small animation() helper that
turns elapsed time into a normalized [0, 1] value with optional duration,
delay, looping, and easing:
import { animation, Easing } from "redraw";
const t = animation({ time: elapsedSeconds }, {
duration: 12,
boomerang: true,
easing: Easing.out(Easing.cubic),
});
animation() accepts any object with a time field (seconds since some
origin) and returns a value in [0, 1]. Apply it to whatever you're
mutating (node positions, function props, feather sigma) to drive timed
animations.