Redraw is currently in technical preview, available to wcandillon.dev subscribers. API is unstable.
React Native
react-native-redraw mirrors the react-redraw API on top of
react-native-webgpu:
the same <RedrawCanvas>, <RedrawProvider>, useRedraw(), and
useSurface(). It requires react-native-webgpu as a peer dependency.
As on the web, every canvas and hook needs a <RedrawProvider> above it
(or an explicit instance via the redraw prop) and throws a clear error
otherwise. Wrap your app, or the part of it that draws, once:
// App.tsx
import { StyleSheet } from "react-native";
import { RedrawCanvas, RedrawProvider } from "react-native-redraw";
import { render, animate } from "./hello-world";
export function App() {
return (
<RedrawProvider>
<Hello />
</RedrawProvider>
);
}
function Hello() {
return (
<RedrawCanvas style={styles.canvas} render={render} animate={animate} />
);
}
const styles = StyleSheet.create({
canvas: {
flex: 1,
},
});
No matter how many canvases live under the provider, the app holds a
single GPU device and shares one set of pipeline caches. The provider
accepts every RedrawInit() option through its options prop, for
example options={{ timestampQuery: true }} or an existing device with
options={{ device }} (which stays yours).
Nesting
As on the web, nesting <RedrawProvider> is idempotent.
To create an isolated instance with its own device,
use <LocalRedrawProvider>, which always owns its instance even when
nested.
RedrawCanvas
render runs once to build the scene (and again when the canvas
resizes); animate runs every frame and mutates the nodes returned by
render. For static scenes or immediate-mode rendering, use onDraw
(with loop for an animation loop), exactly like on the web.
Loading and error states
The provider initializes asynchronously. By default children render
immediately and canvases start drawing once the instance is ready. To
show loading and unsupported states instead, pass fallback and
errorFallback:
<RedrawProvider
fallback={<ActivityIndicator />}
errorFallback={(error) => <Text>WebGPU is not available</Text>}
>
<RedrawCanvas render={render} animate={animate} />
</RedrawProvider>
If the device is ever lost, the provider notifies onError, shows
fallback again, and re-initializes with a fresh device; canvases resume
automatically.
useRedraw
useRedraw() hands you the Redraw instance directly for
imperative work on the same device and backend, e.g. offscreen rendering
or loading textures. It suspends while the provider initializes, so it
composes with your own <Suspense> and error boundaries.
useSurface
When you want to drive rendering yourself but stay in React,
useSurface works exactly like on the web: it manages the canvas
and a surface whose flush(canvas) presents the frame (internally
through an offscreen surface and a blit pass):
import { Canvas as WGPUCanvas } from "react-native-webgpu";
import { useSurface } from "react-native-redraw";
function MyComponent() {
const { ref, surface } = useSurface();
useEffect(() => {
if (!surface) return;
const canvas = new Canvas();
// ... draw to canvas
surface.flush(canvas);
}, [surface]);
return <WGPUCanvas ref={ref} style={{ flex: 1 }} />;
}
Bring your own instance
Create an instance yourself with RedrawInit() and pass it via the
redraw prop (or the hook's redraw option), which overrides any
surrounding provider. Ownership is simple: whoever creates the instance
owns its device. A canvas only ever destroys its own resources; the
provider destroys the device it created on unmount; an instance you pass
in stays yours.
Lifecycle callbacks
- On the provider,
onErrorfires when initialization fails or when the device is lost (a loss triggers automatic re-initialization). - On a canvas,
onErrorfires when the device is lost or when rendering a frame throws; the animation loop stops first. - On a canvas,
onReadyreceives theRedrawinstance once it is ready, before the first frame. It is safe under React StrictMode. - On a canvas,
onGPUTimereceives the GPU time of the most recently completed shading pass in nanoseconds after each frame. It requiresoptions={{ timestampQuery: true }}on the provider and a device that supports thetimestamp-queryfeature (note: the iOS Simulator does not); when timestamps are unavailable, a one-time warning is logged instead.
Without an onError handler, errors are logged to the console.