API Reference

FragCanvas Reference

Complete prop reference and usage guide for the main FragCanvas component.


This is the complete prop reference for FragCanvas — the main adapter entrypoint for using Motion GPU in Svelte, React, and Vue.

Import

import { FragCanvas } from '@motion-core/motion-gpu/svelte';
import { FragCanvas } from '@motion-core/motion-gpu/svelte';
import { FragCanvas } from '@motion-core/motion-gpu/react';
import { FragCanvas } from '@motion-core/motion-gpu/react';
import { FragCanvas } from '@motion-core/motion-gpu/vue';
import { FragCanvas } from '@motion-core/motion-gpu/vue';

Usage

<FragCanvas
  material={myMaterial}
  clearColor={[0, 0, 0, 1]}
  color={{ outputEncoding: 'srgb', toneMapping: 'khronos-pbr-neutral' }}
  renderMode="always"
  passes={[vignettePass]}
  onError={handleError}
>
  <Runtime />
</FragCanvas>
<FragCanvas
  material={myMaterial}
  clearColor={[0, 0, 0, 1]}
  color={{ outputEncoding: 'srgb', toneMapping: 'khronos-pbr-neutral' }}
  renderMode="always"
  passes={[vignettePass]}
  onError={handleError}
>
  <Runtime />
</FragCanvas>
<FragCanvas
  material={myMaterial}
  clearColor={[0, 0, 0, 1]}
  color={{ outputEncoding: 'srgb', toneMapping: 'khronos-pbr-neutral' }}
  renderMode="always"
  passes={[vignettePass]}
  onError={handleError}
>
  <Runtime />
</FragCanvas>
<FragCanvas
  material={myMaterial}
  clearColor={[0, 0, 0, 1]}
  color={{ outputEncoding: 'srgb', toneMapping: 'khronos-pbr-neutral' }}
  renderMode="always"
  passes={[vignettePass]}
  onError={handleError}
>
  <Runtime />
</FragCanvas>
<FragCanvas
  :material="myMaterial"
  :clear-color="[0, 0, 0, 1]"
  :color="{ outputEncoding: 'srgb', toneMapping: 'khronos-pbr-neutral' }"
  render-mode="always"
  :passes="[vignettePass]"
  :on-error="handleError"
>
  <Runtime />
</FragCanvas>
<FragCanvas
  :material="myMaterial"
  :clear-color="[0, 0, 0, 1]"
  :color="{ outputEncoding: 'srgb', toneMapping: 'khronos-pbr-neutral' }"
  render-mode="always"
  :passes="[vignettePass]"
  :on-error="handleError"
>
  <Runtime />
</FragCanvas>

Adapter-specific naming differences (class vs className, style type, children/slots, and canvas handle access) are listed below.

Props

Required

Prop Type Description
material FragMaterial The material to render. Must be created with defineMaterial().

Rendering

Prop Type Default Description
clearColor [number, number, number, number] [0, 0, 0, 1] RGBA clear color applied before the base pass.
color ColorPipelineOptions undefined Output encoding, HDR working format, canvas dynamic range, canvas color space, and final tone-mapping options. Changing triggers renderer rebuild.
renderMode 'always' | 'on-demand' | 'manual' 'always' Controls frame rendering frequency.
autoRender boolean true Hard gate — when false, no rendering occurs regardless of render mode.
maxDelta number 0.1 Maximum frame delta in seconds (clamps state.delta). Must be > 0.
dpr number devicePixelRatio (or 1 during SSR) Device pixel ratio for resolution scaling.

Color pipeline

color controls the private final presentation stage. It is not a composable render pass; it always runs after the base scene and after all post-scene render passes.

type ColorPipelineOptions = {
	outputEncoding?: 'srgb' | 'linear';
	toneMapping?: 'none' | 'khronos-pbr-neutral';
	dynamicRange?: 'sdr' | 'hdr' | 'auto';
	canvasColorSpace?: 'srgb' | 'display-p3';
	workingFormat?: 'auto' | GPUTextureFormat;
};
type ColorPipelineOptions = {
	outputEncoding?: 'srgb' | 'linear';
	toneMapping?: 'none' | 'khronos-pbr-neutral';
	dynamicRange?: 'sdr' | 'hdr' | 'auto';
	canvasColorSpace?: 'srgb' | 'display-p3';
	workingFormat?: 'auto' | GPUTextureFormat;
};
Option Default Description
outputEncoding 'srgb' Final value encoding. 'srgb' applies linear-to-sRGB encoding before SDR presentation; 'linear' leaves values unchanged.
toneMapping 'none' 'khronos-pbr-neutral' applies Khronos PBR Neutral to linear HDR input before SDR presentation.
dynamicRange 'sdr' 'hdr' requests rgba16float canvas output with WebGPU toneMapping: { mode: 'extended' }; 'auto' tries HDR and falls back to SDR.
canvasColorSpace 'srgb' Canvas presentation color space passed to WebGPU context configuration. This selects the canvas gamut/presentation space; it is separate from outputEncoding.
workingFormat 'auto' Internal scene/pass target format. auto selects rgba16float for HDR or tone-mapped pipelines, otherwise the preferred canvas format.

Khronos PBR Neutral is an SDR tone mapper: it consumes non-negative linear Rec.709 HDR color and returns linear Rec.709 in [0, 1]. Explicit dynamicRange: 'hdr' with toneMapping: 'khronos-pbr-neutral' is rejected because that combination asks for HDR presentation after an SDR tone mapper.

<FragCanvas {material} color={{ toneMapping: 'khronos-pbr-neutral' }} />
<FragCanvas {material} color={{ toneMapping: 'khronos-pbr-neutral' }} />
<FragCanvas material={material} color={{ dynamicRange: 'hdr', canvasColorSpace: 'display-p3' }} />
<FragCanvas material={material} color={{ dynamicRange: 'hdr', canvasColorSpace: 'display-p3' }} />

Post-processing

Prop Type Default Description
passes AnyPass[] [] Array of compute, fragment-feedback, and render passes. Compute and feedback passes execute pre-scene in declaration order; render passes execute post-scene in declaration order. See Render Passes, Passes API, and Compute Shaders.
renderTargets RenderTargetDefinitionMap {} Named off-screen render targets. See Render Targets.

WebGPU configuration

Prop Type Default Description
adapterOptions GPURequestAdapterOptions undefined Forwarded to navigator.gpu.requestAdapter(). Value changes trigger renderer/device recreation.
deviceDescriptor GPUDeviceDescriptor undefined Forwarded to adapter.requestDevice(). Value changes trigger renderer/device recreation.

Error handling

Prop Type Default Description
showErrorOverlay boolean true Enables error UI rendering (errorRenderer or default overlay).
errorRenderer Snippet<[MotionGPUErrorReport]> (Svelte) / (report: MotionGPUErrorReport) => ReactNode (React) / scoped slot #errorRenderer="{ report }" (Vue) undefined Custom error renderer. When set, replaces the default MotionGPUErrorOverlay.
onError (report: MotionGPUErrorReport) => void undefined Error callback. Called regardless of overlay state. See Error Handling for report shape.
errorHistoryLimit number 0 Enables bounded error history when > 0; values are normalized with Math.floor.
onErrorHistory (history: MotionGPUErrorReport[]) => void undefined Callback with deduplicated ring-buffer history snapshots.

Error history behavior

  • History is disabled when errorHistoryLimit <= 0.
  • History stores the latest N reports when errorHistoryLimit > 0.
  • Consecutive identical reports are deduplicated (phase/title/message/rawMessage key).
  • Reducing errorHistoryLimit trims existing history immediately.
  • onErrorHistory receives a fresh snapshot array; mutating it cannot change internal runtime history.

Styling and children

Prop Type Default Description
Native canvas attrs Canvas attributes except width, height, and Motion GPU prop names undefined Attributes such as id, data-*, aria-*, tabindex, events, class/className, and style are applied to the internal <canvas>.
class (Svelte/Vue) / className (React) Framework-native class value undefined CSS class applied directly to the internal <canvas>.
style string (Svelte) / framework-native style object/string undefined Inline styles applied directly to the internal <canvas>.
bind:canvas (Svelte) / ref (React) / Vue component ref expose HTMLCanvasElement access undefined Parent-level access to the internal canvas. Vue refs expose canvas and getCanvas() on the component public instance.
children (Svelte/React) / default slot (Vue) Snippet (Svelte) / ReactNode (React) / slot (Vue) undefined Children rendered inside the FragCanvas context — this is where useFrame, useMotionGPU, usePointer, etc. work.

FragCanvas is canvas-facing: DOM attributes passed to the component target the internal <canvas>, not the implementation wrapper. Wrap FragCanvas in your own element when you need container-level layout classes or styles.

width and height canvas attributes are intentionally not forwarded. Motion GPU controls the backing-store size from CSS size × dpr; use CSS/container sizing plus the dpr prop instead.

Lifecycle

Phase What happens
Mount Frame registry and context created. Material resolved. Pipeline signature computed. Renderer created (async). RAF loop started.
Frame Timing computed. Size updated. Scheduler tasks run. Render gate evaluated. If open: uniforms merged, textures uploaded, pre-scene passes executed, base scene rendered, post-scene passes executed, frame presented.
Signature change Old renderer destroyed. New renderer created with updated signature. Exponential backoff on failure.
Destroy RAF cancelled. Renderer destroyed (GPU resources freed). Scheduler cleared.

Canvas sizing

FragCanvas renders a <canvas> inside an implementation wrapper <div>. Native DOM props passed to FragCanvas are applied to the canvas, while the wrapper remains private to provide stable layout, clipping, context children, and error UI. The canvas fills its container using width: 100%; height: 100% CSS. The container determines the effective canvas dimensions.

The physical size (GPU resolution) is containerSize × dpr.

Example: full configuration

<FragCanvas
  material={material}
  clearColor={[0.05, 0.05, 0.1, 1]}
  color={{ outputEncoding: 'srgb', toneMapping: 'khronos-pbr-neutral' }}
  renderMode="on-demand"
  autoRender={true}
  maxDelta={0.05}
  dpr={2}
  passes={[tonePass, vignettePass]}
  renderTargets={{ halfRes: { scale: 0.5 } }}
  adapterOptions={{ powerPreference: 'high-performance' }}
  showErrorOverlay={true}
  errorRenderer={myErrorRenderer}
  onError={(report) => sendToTelemetry(report)}
  errorHistoryLimit={20}
  onErrorHistory={(history) => sendErrorHistory(history)}
  class="my-canvas"
  style="border-radius: 12px;"
  data-testid="shader-canvas"
>
  <Runtime />
</FragCanvas>
<FragCanvas
  material={material}
  clearColor={[0.05, 0.05, 0.1, 1]}
  color={{ outputEncoding: 'srgb', toneMapping: 'khronos-pbr-neutral' }}
  renderMode="on-demand"
  autoRender={true}
  maxDelta={0.05}
  dpr={2}
  passes={[tonePass, vignettePass]}
  renderTargets={{ halfRes: { scale: 0.5 } }}
  adapterOptions={{ powerPreference: 'high-performance' }}
  showErrorOverlay={true}
  errorRenderer={myErrorRenderer}
  onError={(report) => sendToTelemetry(report)}
  errorHistoryLimit={20}
  onErrorHistory={(history) => sendErrorHistory(history)}
  class="my-canvas"
  style="border-radius: 12px;"
  data-testid="shader-canvas"
>
  <Runtime />
</FragCanvas>
<FragCanvas
  material={material}
  clearColor={[0.05, 0.05, 0.1, 1]}
  color={{ outputEncoding: 'srgb', toneMapping: 'khronos-pbr-neutral' }}
  renderMode="on-demand"
  autoRender={true}
  maxDelta={0.05}
  dpr={2}
  passes={[tonePass, vignettePass]}
  renderTargets={{ halfRes: { scale: 0.5 } }}
  adapterOptions={{ powerPreference: 'high-performance' }}
  showErrorOverlay={true}
  errorRenderer={(report) => (
    <aside className="my-error-banner">
      <strong>{report.title}</strong>
      <p>{report.message}</p>
    </aside>
  )}
  onError={(report) => sendToTelemetry(report)}
  errorHistoryLimit={20}
  onErrorHistory={(history) => sendErrorHistory(history)}
  className="my-canvas"
  style={{ borderRadius: '12px' }}
  data-testid="shader-canvas"
>
  <Runtime />
</FragCanvas>
<FragCanvas
  material={material}
  clearColor={[0.05, 0.05, 0.1, 1]}
  color={{ outputEncoding: 'srgb', toneMapping: 'khronos-pbr-neutral' }}
  renderMode="on-demand"
  autoRender={true}
  maxDelta={0.05}
  dpr={2}
  passes={[tonePass, vignettePass]}
  renderTargets={{ halfRes: { scale: 0.5 } }}
  adapterOptions={{ powerPreference: 'high-performance' }}
  showErrorOverlay={true}
  errorRenderer={(report) => (
    <aside className="my-error-banner">
      <strong>{report.title}</strong>
      <p>{report.message}</p>
    </aside>
  )}
  onError={(report) => sendToTelemetry(report)}
  errorHistoryLimit={20}
  onErrorHistory={(history) => sendErrorHistory(history)}
  className="my-canvas"
  style={{ borderRadius: '12px' }}
  data-testid="shader-canvas"
>
  <Runtime />
</FragCanvas>
<FragCanvas
  :material="material"
  :clear-color="[0.05, 0.05, 0.1, 1]"
  :color="{ outputEncoding: 'srgb', toneMapping: 'khronos-pbr-neutral' }"
  render-mode="on-demand"
  :auto-render="true"
  :max-delta="0.05"
  :dpr="2"
  :passes="[tonePass, vignettePass]"
  :render-targets="{ halfRes: { scale: 0.5 } }"
  :adapter-options="{ powerPreference: 'high-performance' }"
  :show-error-overlay="true"
  :on-error="(report) => sendToTelemetry(report)"
  :error-history-limit="20"
  :on-error-history="(history) => sendErrorHistory(history)"
  class="my-canvas"
  style="border-radius: 12px"
  data-testid="shader-canvas"
>
  <template #errorRenderer="{ report }">
    <aside class="my-error-banner">
      <strong>{{ report.title }}</strong>
      <p>{{ report.message }}</p>
    </aside>
  </template>
  <Runtime />
</FragCanvas>
<FragCanvas
  :material="material"
  :clear-color="[0.05, 0.05, 0.1, 1]"
  :color="{ outputEncoding: 'srgb', toneMapping: 'khronos-pbr-neutral' }"
  render-mode="on-demand"
  :auto-render="true"
  :max-delta="0.05"
  :dpr="2"
  :passes="[tonePass, vignettePass]"
  :render-targets="{ halfRes: { scale: 0.5 } }"
  :adapter-options="{ powerPreference: 'high-performance' }"
  :show-error-overlay="true"
  :on-error="(report) => sendToTelemetry(report)"
  :error-history-limit="20"
  :on-error-history="(history) => sendErrorHistory(history)"
  class="my-canvas"
  style="border-radius: 12px"
  data-testid="shader-canvas"
>
  <template #errorRenderer="{ report }">
    <aside class="my-error-banner">
      <strong>{{ report.title }}</strong>
      <p>{{ report.message }}</p>
    </aside>
  </template>
  <Runtime />
</FragCanvas>
{#snippet myErrorRenderer(report)}
  <aside class="my-error-banner">
    <strong>{report.title}</strong>
    <p>{report.message}</p>
  </aside>
{/snippet}
{#snippet myErrorRenderer(report)}
  <aside class="my-error-banner">
    <strong>{report.title}</strong>
    <p>{report.message}</p>
  </aside>
{/snippet}
// In React, pass an inline render function to errorRenderer:
errorRenderer={(report) => (
  <aside className="my-error-banner">
    <strong>{report.title}</strong>
    <p>{report.message}</p>
  </aside>
)}
// In React, pass an inline render function to errorRenderer:
errorRenderer={(report) => (
  <aside className="my-error-banner">
    <strong>{report.title}</strong>
    <p>{report.message}</p>
  </aside>
)}
<!-- In Vue, use a scoped slot for custom error rendering: -->
<template #errorRenderer="{ report }">
  <aside class="my-error-banner">
    <strong>{{ report.title }}</strong>
    <p>{{ report.message }}</p>
  </aside>
</template>
<!-- In Vue, use a scoped slot for custom error rendering: -->
<template #errorRenderer="{ report }">
  <aside class="my-error-banner">
    <strong>{{ report.title }}</strong>
    <p>{{ report.message }}</p>
  </aside>
</template>