Core Concepts

Hooks & Context

Accessing runtime state, pointer input, and rendering controls with Motion GPU hooks.


This page covers useMotionGPU() for runtime context access, usePointer() for normalized pointer input, the CurrentWritable pattern for synchronous reads, 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/svelte'; const gpu = useMotionGPU(); </script>

Must be called inside a <FragCanvas> component tree. Calling it outside throws.

usePointer()

usePointer() provides adapter-managed pointer tracking (mouse, touch, pen) with shader-friendly coordinates:

  • state.current.uv in 0..1 with Y-up orientation
  • state.current.ndc in -1..1
  • optional synthesized click snapshots via lastClick.current
  • optional automatic frame wakeups (requestFrame: 'auto')

Use it to remove canvas event-listener boilerplate in runtime components.

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

Store-like subscriptions require setup/teardown to read values reactively. In useFrame callbacks (which run 60 times per second), subscribing and unsubscribing per read is wasteful.

CurrentWritable<T> and CurrentReadable<T> extend reactive store contracts with a synchronous .current getter:

// Subscription read — requires subscribe/unsubscribe
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
// Subscription read — requires subscribe/unsubscribe
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 reactive-store style subscription

When to use which

Context Use
Inside useFrame callbacks .current (runs 60+ times/sec)
Framework reactive bindings ($store, useSyncExternalStore, ref + .subscribe, etc.) Standard .subscribe integration
One-off reads outside reactive blocks .current

Integration patterns

Reading canvas size

<script lang="ts"> import { useMotionGPU } from '@motion-core/motion-gpu/svelte'; 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/svelte'; 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, usePointer } from '@motion-core/motion-gpu/svelte'; const gpu = useMotionGPU(); const pointer = usePointer({ requestFrame: 'auto' }); $effect(() => { gpu.renderMode.set('on-demand'); }); useFrame((state) => { state.setUniform('uTime', state.time); state.setUniform('uMouse', pointer.state.current.uv); }, { autoInvalidate: false }); </script>