Skip to main content
Offscreen rendering allows you to draw to a surface that isn’t directly visible on screen. This is useful for:
  • Image generation - Create images programmatically
  • Texture creation - Generate textures for use in shaders
  • Intermediate buffers - Apply complex effects
  • Server-side rendering - Generate graphics on Node.js

Basic Offscreen Rendering

Use makeOffscreenSurface to create an offscreen surface and drawOffscreen to render React Native Skia components to it:
import { 
  makeOffscreenSurface, 
  drawOffscreen, 
  Circle, 
  Group 
} from "@shopify/react-native-skia";

const width = 256;
const height = 256;

using surface = makeOffscreenSurface(width, height);
using image = await drawOffscreen(
  surface,
  <Group blendMode="multiply">
    <Circle cx={128} cy={128} r={80} color="cyan" />
    <Circle cx={178} cy={128} r={80} color="magenta" />
  </Group>
);

// Encode to base64 or bytes
const base64 = image.encodeToBase64();
const bytes = image.encodeToBytes();

Using with Canvas Snapshots

You can also capture offscreen renders using the Canvas component’s snapshot methods:
import { useEffect } from "react";
import { Canvas, useCanvasRef, Circle } from "@shopify/react-native-skia";

const SnapshotExample = () => {
  const ref = useCanvasRef();
  
  useEffect(() => {
    const captureImage = async () => {
      const image = await ref.current?.makeImageSnapshotAsync();
      if (image) {
        const bytes = image.encodeToBytes();
        // Save or process bytes
      }
    };
    captureImage();
  }, []);
  
  return (
    <Canvas style={{ width: 256, height: 256 }} ref={ref}>
      <Circle cx={128} cy={128} r={80} color="red" />
    </Canvas>
  );
};

GPU Acceleration

On web and Node.js, offscreen surfaces can use GPU acceleration via the OffscreenCanvas API. See the Headless guide for details.

Use Cases

Image Export

Generate and export images from your Skia drawings:
const exportImage = async () => {
  using surface = makeOffscreenSurface(1024, 1024);
  using image = await drawOffscreen(surface, <MyComplexDrawing />);
  
  const bytes = image.encodeToBytes();
  // Save to file system
};

Texture Generation

Create textures for use in shaders or other graphics:
const texture = await drawAsImage(
  <Rect width={256} height={256} color="blue" />,
  { width: 256, height: 256 }
);

Performance Optimization

For complex graphics that don’t change frequently, render once offscreen and reuse:
const [cachedImage, setCachedImage] = useState(null);

useEffect(() => {
  const generateImage = async () => {
    using surface = makeOffscreenSurface(512, 512);
    using image = await drawOffscreen(surface, <ExpensiveDrawing />);
    setCachedImage(image);
  };
  generateImage();
}, []);

return (
  <Canvas style={{ flex: 1 }}>
    {cachedImage && <Image image={cachedImage} />}
  </Canvas>
);

Build docs developers (and LLMs) love