Skip to main content
Technical preview

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:

MethodWhat 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.