The frame scheduler manages all per-frame logic in Motion GPU. Every useFrame callback is registered as a task with ordering constraints and an invalidation policy. This page covers the useFrame API in depth.
For render modes, stages, and profiling, see Render Modes and Scheduling.
Basic usage
<script lang="ts">
import { useFrame } from '@motion-core/motion-gpu/svelte';
useFrame((state) => {
state.setUniform('uTime', state.time);
});
</script>useFrame must be called inside a <FragCanvas> component tree. Calling it outside throws.
Overloads
Return value
useFrame returns a handle for controlling the task:
FrameState callback API
The state parameter passed to your callback provides everything you need for per-frame logic:
Example: complete runtime component
<script lang="ts">
import { useFrame, usePointer } from '@motion-core/motion-gpu/svelte';
const pointer = usePointer();
useFrame((state) => {
state.setUniform('uTime', state.time);
state.setUniform('uMouse', pointer.state.current.uv);
});
</script>UseFrameOptions
Invalidation policies
The invalidation policy controls whether a task’s execution triggers a re-render in on-demand mode:
Simple policies
Object policies
on-change semantics
With on-change, the scheduler compares the current resolved token against the previous frame’s token. Invalidation fires only when they differ. This is ideal for state-driven updates:
Task ordering with dependencies
Use before and after to control execution order within a stage:
Dependencies are resolved via topological sort.
- Circular dependencies throw a deterministic error.
- Missing
before/afterreferences throw a deterministic error.
Lifecycle
useFrameautomatically unregisters the task when the component is destroyed (adapter lifecycle cleanup).- The
stop()/start()methods pause/resume without unregistering — the task remains in the schedule but is skipped. - The
runninggate is checked each frame — a stopped task or a task withrunning: () => falseis simply skipped, not removed. - Re-registering the same explicit key replaces the previous task registration; stale unsubscribe handlers from the replaced task will not remove the newer one.