| name | motion-gpu-adapters-wgsl |
|---|---|
| description | Build and edit MotionGPU code across framework-agnostic core and Svelte/React/Vue adapters. Use when implementing or refactoring FragCanvas-based components, defineMaterial shaders, useFrame runtime logic, textures/useTexture workflows, render passes/targets, compute shaders/storage buffers, render-mode scheduling, or MotionGPU error handling and diagnostics. |
Use this skill to produce production-grade MotionGPU code across:
- framework-agnostic core (
@motion-core/motion-gpu,@motion-core/motion-gpu/core), - Svelte adapter (
@motion-core/motion-gpu/svelte), - React adapter (
@motion-core/motion-gpu/react), - Vue adapter (
@motion-core/motion-gpu/vue).
Treat Svelte, React, and Vue as first-class adapters. Do not assume Svelte-only APIs.
Treat public package entrypoints as authoritative:
| Entrypoint | Layer | What it exposes |
|---|---|---|
@motion-core/motion-gpu |
Core | Framework-agnostic runtime primitives (defineMaterial, resolveMaterial, scheduler/runtime builders, passes, texture loader, error normalization) |
@motion-core/motion-gpu/advanced |
Core | Core + scheduler helpers (applySchedulerPreset, captureSchedulerDebugSnapshot) |
@motion-core/motion-gpu/core |
Core | Same core API surface as root, explicit core path |
@motion-core/motion-gpu/core/advanced |
Core | Same advanced core helper surface |
@motion-core/motion-gpu/svelte |
Adapter | Svelte FragCanvas, hooks (useMotionGPU, useFrame, usePointer, useTexture), passes, material helpers |
@motion-core/motion-gpu/svelte/advanced |
Adapter | Svelte adapter + user context APIs + scheduler helpers |
@motion-core/motion-gpu/react |
Adapter | React FragCanvas, hooks (useMotionGPU, useFrame, usePointer, useTexture), passes, material helpers |
@motion-core/motion-gpu/react/advanced |
Adapter | React adapter + user context APIs + scheduler helpers |
@motion-core/motion-gpu/vue |
Adapter | Vue FragCanvas, composables (useMotionGPU, useFrame, usePointer, useTexture), passes, material helpers |
@motion-core/motion-gpu/vue/advanced |
Adapter | Vue adapter + user context APIs + scheduler helpers |
Advanced adapter exports:
- Svelte, React, and Vue advanced entrypoints export:
useMotionGPUUserContextsetMotionGPUUserContextapplySchedulerPresetcaptureSchedulerDebugSnapshot
- React advanced additionally exports:
useSetMotionGPUUserContext
Import only from public entrypoints above. Never import from internal package paths (/src, /lib/core, etc.).
Documentation sources:
- LLM docs index:
http://motion-gpu.dev/llms.txt - Docs generated from source live under
apps/web/src/routes/docs
If examples conflict with exported runtime behavior, prefer exported API contracts from entrypoints.
When writing or refactoring code, keep these differences explicit.
Shared runtime props (all adapters):
material,renderTargets,passes,clearColor,outputColorSpace,renderMode,autoRender,maxDelta,adapterOptions,deviceDescriptor,showErrorOverlay,onError,errorHistoryLimit,onErrorHistory
Adapter-specific differences:
- Svelte:
class?: stringstyle?: stringchildren?: SnippeterrorRenderer?: Snippet<[MotionGPUErrorReport]>
- React:
className?: stringstyle?: React.CSSPropertieschildren?: ReactNodeerrorRenderer?: (report: MotionGPUErrorReport) => ReactNode
- Vue:
canvasClass?: stringcanvasStyle?: string | Record<string, string | number>- default slot for children
#errorRenderer="{ report }"scoped slot for custom error UI
- All adapters support
setMotionGPUUserContext(namespace, valueOrFactory, options?). - React additionally supports
useSetMotionGPUUserContext()and should prefer it for effect/event-handler writes. SetMotionGPUUserContextOptionssupports:existing?: 'skip' | 'replace' | 'merge'functionValue?: 'factory' | 'value'
- Shared return shape:
{ textures, loading, error, errorReport, reload } - Shared URL input:
string[] | () => string[] - Options input:
- Svelte:
TextureLoadOptions | () => TextureLoadOptions - React:
TextureLoadOptions - Vue:
TextureLoadOptions | () => TextureLoadOptions
- Svelte:
- Shared return shape:
{ state, lastClick, resetClick } - Shared option highlights:
requestFrame?: 'auto' | 'invalidate' | 'advance' | 'none'capturePointer?: booleantrackWhilePressedOutsideCanvas?: boolean- click synthesis options (
clickEnabled,clickMaxDurationMs,clickMaxMovePx,clickButtons) - callbacks:
onMove,onDown,onUp,onClick
- Coordinate conventions:
state.current.uvuses shader-friendly Y-up (0..1)state.current.ndcuses Y-up (-1..1)
Enforce these constraints without exceptions:
- Material shader entrypoint must be exactly:
fn frag(uv: vec2f) -> vec4f ShaderPassshader entrypoint must be exactly:fn shade(inputColor: vec4f, uv: vec2f) -> vec4fComputePassshader must contain@compute @workgroup_size(...)and afn compute(...)entrypoint.- Call
useFrame(),useMotionGPU(), andusePointer()only inside the<FragCanvas>subtree. - Declare all runtime-updated uniforms/textures in
defineMaterial(...)first. - Use WGSL-safe identifiers for uniforms/textures/defines/includes/storage buffers:
[A-Za-z_][A-Za-z0-9_]* - Use
needsSwap: trueonly withinput: 'source'andoutput: 'target'. - Never read from
input: 'canvas'in render passes. - Use explicit
{ type: 'mat4x4f', value: [...] }for matrix uniforms. - Keep
maxDelta > 0and scheduler profiling window> 0. - Build materials via
defineMaterial(...); never handcraftFragMaterial. - In
manualmode, calladvance()to render;invalidate()alone does not render. - For
invalidation: { mode: 'on-change' }, always providetoken. - Read/write named pass slots only when declared in
renderTargets. - Declare all storage buffers in
defineMaterial({ storageBuffers })before usingwriteStorageBuffer/readStorageBuffer. - Storage buffer
sizemust be> 0and a multiple of 4. PingPongComputePassiterationsmust be>= 1.- Compute passes do not participate in render pass slot routing (no
input/output/needsSwap).
Default to host + runtime split in all adapters.
- Host component:
- Create stable
materialwithdefineMaterial(...). - Render
FragCanvaswithmaterial. - Attach
passes,renderTargets,renderMode,onErroras needed.
- Runtime child component:
- Call
useFrame(...)for per-frame updates. - Call
useMotionGPU()for canvas/scheduler/render controls. - Call
usePointer(...)for normalized mouse/touch/pen input and click snapshots. - Use
useTexture(...)for URL texture IO.
Prefer this split even for simple effects. It keeps context usage valid and readable.
Pick one main mode:
- Static shader (no runtime updates).
- Animated shader (uniform updates in
useFrame). - Interactive shader (pointer/state-driven updates).
- Texture-driven shader (
useTextureandstate.setTexture). - Post-processing pipeline (
ShaderPass/BlitPass/CopyPass). - Compute shader (
ComputePass/PingPongComputePasswith storage buffers). - Advanced scheduling/user context (advanced entrypoints).
- If building framework runtime usage, pick adapter entrypoint (
/svelte,/react, or/vue). - If building framework-independent tooling, adapter internals, or low-level integrations, use core entrypoints (
@motion-core/motion-gpuor/core). - If adapter is not explicitly stated:
- follow existing imports/files in the target codebase,
- preserve current adapter,
- avoid mixing adapter APIs in one component.
Put in material:
- Fragment WGSL source.
- Uniform declarations and initial values.
- Texture declarations and sampler/upload defaults.
- Storage buffer declarations (
storageBuffers) with size, type, access mode, and optionalinitialData. definesfor compile-time constants.includesfor reusable WGSL chunks.
Put in runtime (useFrame):
state.setUniform(...)for dynamic values.state.setTexture(...)for dynamic texture sources.state.writeStorageBuffer(name, data, { offset? })to write CPU data to GPU storage buffers.state.readStorageBuffer(name)to read GPU storage buffer data back (Promise<ArrayBuffer>).state.invalidate(...)andstate.advance()control.
Choose mode by behavior:
always: continuous animation/video.on-demand: interaction or sporadic updates.manual: explicit frame stepping/testing/capture.
If using on-demand, define invalidation policy explicitly:
- Keep
autoInvalidate: truefor frame-driven effects. - Use
autoInvalidate: false+invalidation: { mode: 'on-change', token: ... }for state-driven redraws.
Render-mode semantics:
on-demandrenders one initial frame, then sleeps until invalidated.- Switching to
on-demandtriggers one frame. manualignores invalidation-only flow; requiresadvance().
Always wire onError.
Keep default overlay in dev unless the task explicitly requires custom UI.
Disable overlay only when the user asks for silent/custom handling.
Run checks available in the target package/app:
npm run check
npm run test
npm run lintIf repository scripts use other package manager commands, run equivalents (pnpm/yarn/bun).
If a script is missing, run closest available static/type/test checks and report what was not run.
If touching .svelte files and svelte-autofixer is available, run:
npx @sveltejs/mcp svelte-autofixer <path-to-file>- Use
motiongpuFrame.time,motiongpuFrame.delta,motiongpuFrame.resolutionfor frame data. - Read user uniforms through
motiongpuUniforms.<name>. - Sample textures with generated pairs:
uTexanduTexSampler. usePointer().state.current.uvalready provides Y-up UV; flip Y manually only for custom DOM event wiring.
- Prefer shorthand for scalar/vector:
0,[x,y],[x,y,z],[x,y,z,w]. - Use explicit typed form for clarity and matrices.
- Keep types stable; type/shape changes require new material.
- Set static sampling defaults in
defineMaterial({ textures }). - Use runtime
state.setTexturefor source changes. - Update-mode guidance:
oncefor static images,onInvalidatefor event-driven updates,perFramefor video/canvas streams.
- Use
nullsafely to unbind user source (fallback texture remains valid).
- Use
includesfor reusable shader functions. - Keep include chunks non-empty and non-circular.
- Use
definesfor compile-time toggles and loop constants. - Use typed integer defines for integer loops:
{ type: 'i32', value: N }or{ type: 'u32', value: N }. - Expect renderer rebuild when define/include output changes.
- Use
applySchedulerPreset(...)when selectingperformance,balanced, ordebugbehavior. - Keep
diagnosticsEnabledandprofilingEnabledequal when overriding preset options. - Keep
profilingWindowfinite and> 0. - Use
setMotionGPUUserContext(namespace, value)for shared canvas-subtree state. - Default conflict behavior is
existing: 'skip'; passexisting: 'replace'orexisting: 'merge'intentionally. - In React, prefer
useSetMotionGPUUserContext()for writes in effects and event handlers. - Use
useMotionGPUUserContext(namespace?)as read API.
- Start with
ShaderPassunless copy/blit is sufficient. - Use
CopyPasswhen fast copy can apply; it falls back automatically. - Use named
renderTargetsfor multi-resolution or branching pipelines. - Validate slot availability order: write before read in same frame plan.
- Declare storage buffers in
defineMaterial({ storageBuffers: { name: { size, type, access? } } }). - Use
ComputePassfor single-dispatch GPU compute;PingPongComputePassfor iterative simulations. - Compute passes run alongside render passes but do not read/write render pass slots.
dispatchcan be static tuple[x, y?, z?],'auto', or dynamic function.- Use
state.writeStorageBuffer(name, data)inuseFrameto upload CPU data before compute. - Use
state.readStorageBuffer(name)to read back GPU results asynchronously. - Storage buffers are bound at group(1) in compute shaders; storage textures at group(2).
- Fragment shaders can read storage buffers as read-only via
var<storage, read>at group(1). PingPongComputePassgenerates two texture bindings fromtarget:{target}Asampled read texture at@group(2) @binding(0){target}Bwrite storage texture at@group(2) @binding(1)
PingPongComputePassrequires target texture declared withstorage: trueand explicitwidth/height.
<script lang="ts">
import { FragCanvas, defineMaterial } from '@motion-core/motion-gpu/svelte';
import Runtime from './Runtime.svelte';
const material = defineMaterial({
fragment: `
fn frag(uv: vec2f) -> vec4f {
let t = 0.5 + 0.5 * sin(motiongpuUniforms.uTime + uv.x * 8.0);
return vec4f(vec3f(t), 1.0);
}
`,
uniforms: { uTime: 0 }
});
</script>
<FragCanvas {material}>
<Runtime />
</FragCanvas><script lang="ts">
import { useFrame } from '@motion-core/motion-gpu/svelte';
useFrame((state) => {
state.setUniform('uTime', state.time);
});
</script>import { FragCanvas, defineMaterial, useFrame } from '@motion-core/motion-gpu/react';
const material = defineMaterial({
fragment: `
fn frag(uv: vec2f) -> vec4f {
let t = 0.5 + 0.5 * sin(motiongpuUniforms.uTime + uv.x * 8.0);
return vec4f(vec3f(t), 1.0);
}
`,
uniforms: { uTime: 0 }
});
function Runtime() {
useFrame((state) => {
state.setUniform('uTime', state.time);
});
return null;
}
export function App() {
return (
<FragCanvas material={material}>
<Runtime />
</FragCanvas>
);
}import { useSetMotionGPUUserContext } from '@motion-core/motion-gpu/react/advanced';
export function QualityButton() {
const setUserContext = useSetMotionGPUUserContext();
return (
<button
onClick={() => {
setUserContext('config', { quality: 'medium' }, { existing: 'merge' });
}}
>
Medium
</button>
);
}Follow this order:
- Contract errors:
- Verify
frag(...)andshade(...)signatures first.
- Missing runtime binding:
- Ensure names exist in
material.uniformsormaterial.textures.
- WGSL compile errors:
- Read normalized report from
onError. - Map error to fragment/include/define line.
- Pass graph errors:
- Verify
needsSwap, input/output slots, and target declarations.
- No redraw in
on-demand:
- Check invalidation path and
autoInvalidatesettings. - If mode is
manual, useadvance().
- Texture issues:
- Confirm source readiness (
readyStatefor video). - Check update mode and source dimensions.
- Compute shader errors:
- Verify
@compute @workgroup_size(...)andfn compute(...). - Ensure storage buffers are declared before use.
- Check
writeStorageBufferoffset + data size does not exceed buffer size. - Verify dispatch dimensions match workgroup layout.
Ship only when all checks pass:
- Keep shader contracts valid (
frag/shade/computesignatures). - Keep all runtime-updated keys predeclared in material.
- Keep render mode and invalidation strategy intentional and documented.
- Keep error handling present (
onErrorat minimum). - Keep passes/targets routing valid.
- Keep imports on public entrypoints only.
- Keep storage buffer names declared before
writeStorageBuffer/readStorageBufferusage. - Keep adapter-specific API differences correct (
classvsclassName,errorRenderer,children,useSetMotionGPUUserContext). - Keep checks/tests executed or report what was not run.