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>, and useDevice(). 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 device via the device 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 { library, render } from "./hello-world";
export function App() {
return (
<RedrawProvider>
<Hello />
</RedrawProvider>
);
}
function Hello() {
return (
<RedrawCanvas style={styles.canvas} library={library} render={render} />
);
}
const styles = StyleSheet.create({
canvas: {
flex: 1,
},
});
No matter how many canvases live under the provider, the app holds a
single GPU device. The provider accepts its device-request options
through the 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 device, use <LocalRedrawProvider>, which always owns its
device even when nested.
RedrawCanvas
The component works exactly like on the web:
the library prop declares the drawing vocabulary (read once on mount),
and render runs every frame with a fresh recorder. Coordinates are
logical (dp) pixels; the canvas transform is pre-scaled by
PixelRatio.get(), and FrameInfo carries width, height, time,
frame, and dpr.
Same props as the web (library, render, loop, paused, device,
onError, onReady, onStats), plus two native-specific ones:
transparent(defaulttrue): whether the canvas is transparent where nothing is drawn, letting any view behind it show through. Set it tofalseto composite the canvas as opaque, a minor perf win when the scene always fills the frame.format(default"rgba8unorm"): pixel format of the render target, read once on mount."rgba16float"renders at 16-bit float precision and presents on the platform's preferred high-bit-depth swapchain (rgba16floaton iOS,rgb10a2unormon Android), which removes the banding that 8-bit quantization produces on slow gradients. Colors match the 8-bit path exactly; only the precision changes. On Android the 10-bit format leaves only 2 bits of alpha, so pair it withtransparent={false}.
Internally the pipeline renders into an offscreen storage texture and presents it through a blit pass, since the native swapchain formats are not storage-bindable.
Loading and error states
The provider initializes asynchronously. By default children render
immediately and canvases start drawing once the device 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 library={library} render={render} />
</RedrawProvider>
If the device is ever lost, the provider notifies onError, shows
fallback again, and re-initializes with a fresh device; canvases
resume automatically.
useDevice
useDevice() hands you the GPUDevice directly for imperative work on
the same device, e.g. loading textures with makeTexture. It suspends
while the provider initializes, so it composes with your own
<Suspense> and error boundaries.
Bring your own device
Pass a device via the device prop, which overrides any surrounding
provider. Ownership is simple: whoever creates the device owns it. A
canvas only ever destroys its own resources; the provider destroys the
device it created on unmount; a device 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 theGPUDeviceonce it is ready, before the first frame. It is safe under React StrictMode. - On a canvas,
onStatsreceives, after each frame, the frame's CPU time plus the per-pass GPU times. The GPU fields requireoptions={{ timestampQuery: true }}on the provider and a device that supports thetimestamp-queryfeature (note: the iOS Simulator does not); without it they are null and a one-time warning is logged.
Without an onError handler, errors are logged to the console.