This page covers the
useMotionGPU()
hook for accessing the runtime context, the CurrentWritable
pattern for synchronous value access, and recommended integration patterns. For advanced user-defined context, see User Context (Advanced).
useMotionGPU()
useMotionGPU()
returns the MotionGPUContext
— the primary API for reading runtime state and controlling rendering from within FragCanvas
children. <script lang="ts">
import { useMotionGPU } from '@motion-core/motion-gpu';
const gpu = useMotionGPU();
</script>
<script lang="ts">
import { useMotionGPU } from '@motion-core/motion-gpu';
const gpu = useMotionGPU();
</script>
Must be called inside a
<FragCanvas>
component tree. Calling it outside throws. MotionGPUContext shape
Reactive stores
| Store | Type | Description |
gpu.size
| CurrentReadable<{ width: number; height: number }>
| Canvas size in CSS pixels (from getBoundingClientRect ) |
gpu.dpr
| CurrentWritable<number>
| Device pixel ratio |
gpu.maxDelta
| CurrentWritable<number>
| Max frame delta (seconds) |
gpu.renderMode
| CurrentWritable<RenderMode>
| Current render mode |
gpu.autoRender
| CurrentWritable<boolean>
| Auto-render gate |
gpu.user
| CurrentWritable<Record<string symbol, unknown>>
| User-defined namespace store |
Direct values
| Property | Type | Description |
gpu.canvas
| HTMLCanvasElement undefined
| The active canvas element (undefined until mounted) |
Control methods
| Method | Description |
gpu.invalidate()
| Request re-render in on-demand mode |
gpu.advance()
| Request exactly one frame in manual mode |
Scheduler access
| Method | Description |
gpu.scheduler.createStage(key, options)
| Creates a named execution stage |
gpu.scheduler.getSchedule()
| Returns resolved stage/task order |
gpu.scheduler.setDiagnosticsEnabled(flag)
| Enable/disable single-frame timing |
gpu.scheduler.setProfilingEnabled(flag)
| Enable/disable rolling profiling |
gpu.scheduler.setProfilingWindow(n)
| Set rolling window size |
gpu.scheduler.getLastRunTimings()
| Last frame’s timing data |
gpu.scheduler.getProfilingSnapshot()
| Aggregate profiling stats |
gpu.scheduler.resetProfiling()
| Clear profiling history |
For higher-level scheduler configuration and debug snapshots, use the advanced helper exports:
import { applySchedulerPreset, captureSchedulerDebugSnapshot } from '@motion-core/motion-gpu/advanced';
import { applySchedulerPreset, captureSchedulerDebugSnapshot } from '@motion-core/motion-gpu/advanced';
The CurrentWritable / CurrentReadable pattern
Standard Svelte stores require subscription to read values. In
useFrame
callbacks (which run 60 times per second), subscribing and unsubscribing per read is wasteful. CurrentWritable<T>
and CurrentReadable<T>
extend Svelte store contracts with a synchronous .current
getter: // Standard Svelte store — requires subscription
let value: number;
const unsub = gpu.maxDelta.subscribe(v => { value = v; });
// ... use value ...
unsub();
// CurrentWritable — zero-overhead synchronous read
const value = gpu.maxDelta.current; // Instant, no subscription
// Standard Svelte store — requires subscription
let value: number;
const unsub = gpu.maxDelta.subscribe(v => { value = v; });
// ... use value ...
unsub();
// CurrentWritable — zero-overhead synchronous read
const value = gpu.maxDelta.current; // Instant, no subscription
API
| Method | Description |
.current
| Synchronous read of the latest value |
.set(value)
| Update the value (writable only) |
.subscribe(fn)
| Standard Svelte subscription |
When to use which
| Context | Use |
| Inside useFrame callbacks | .current (runs 60+ times/sec) |
| Svelte reactive blocks ( $effect , templates) | Standard $store subscription |
| One-off reads outside reactive blocks | .current
|
Integration patterns
Reading canvas size
<script lang="ts">
import { useMotionGPU } from '@motion-core/motion-gpu';
const gpu = useMotionGPU();
</script>
<p>Canvas: {$gpu.size.width}×{$gpu.size.height} @ {$gpu.dpr}x</p>
<script lang="ts">
import { useMotionGPU } from '@motion-core/motion-gpu';
const gpu = useMotionGPU();
</script>
<p>Canvas: {$gpu.size.width}×{$gpu.size.height} @ {$gpu.dpr}x</p>
Conditional rendering control
<script lang="ts">
import { useMotionGPU } from '@motion-core/motion-gpu';
const gpu = useMotionGPU();
function togglePause() {
gpu.autoRender.set(!gpu.autoRender.current);
}
</script>
<button onclick={togglePause}>
{$gpu.autoRender ? 'Pause' : 'Resume'}
</button>
<script lang="ts">
import { useMotionGPU } from '@motion-core/motion-gpu';
const gpu = useMotionGPU();
function togglePause() {
gpu.autoRender.set(!gpu.autoRender.current);
}
</script>
<button onclick={togglePause}>
{$gpu.autoRender ? 'Pause' : 'Resume'}
</button>
On-demand with external triggers
<script lang="ts">
import { useMotionGPU, useFrame } from '@motion-core/motion-gpu';
const gpu = useMotionGPU();
$effect(() => {
gpu.renderMode.set('on-demand');
});
$effect(() => {
const canvas = gpu.canvas;
if (!canvas) return;
const handler = () => gpu.invalidate();
canvas.addEventListener('pointermove', handler);
return () => canvas.removeEventListener('pointermove', handler);
});
useFrame((state) => {
state.setUniform('uTime', state.time);
}, { autoInvalidate: false });
</script>
<script lang="ts">
import { useMotionGPU, useFrame } from '@motion-core/motion-gpu';
const gpu = useMotionGPU();
$effect(() => {
gpu.renderMode.set('on-demand');
});
$effect(() => {
const canvas = gpu.canvas;
if (!canvas) return;
const handler = () => gpu.invalidate();
canvas.addEventListener('pointermove', handler);
return () => canvas.removeEventListener('pointermove', handler);
});
useFrame((state) => {
state.setUniform('uTime', state.time);
}, { autoInvalidate: false });
</script>