Motion values overview
Motion values are reactive primitives that track the state and velocity of animating values. They’re updated and read outside Svelte’s reactive render cycle, so animations can run at full frame rate without triggering component re-renders.
In @humanspeak/svelte-motion, every motion-value-producing hook returns the same shape: a real motion-dom MotionValue (passes isMotionValue, composes with animate(), follows other motion values) augmented with a Svelte-5 reactive .current getter and a .subscribe shim for legacy $store readers.
<script>
import { useSpring } from '@humanspeak/svelte-motion'
const x = useSpring(0)
</script>
<div
style="transform: translateX({x.current}px)"
onpointerdown={() => x.set(100)}
>
Spring animated
</div><script>
import { useSpring } from '@humanspeak/svelte-motion'
const x = useSpring(0)
</script>
<div
style="transform: translateX({x.current}px)"
onpointerdown={() => x.set(100)}
>
Spring animated
</div>Motion values:
- Have a
.currentgetter backed by$statefor native Svelte 5 reads in templates,$derived, and$effect - Can be updated and read outside Svelte’s reactive render cycle
- Track velocity automatically so springs and transforms stay smooth
- Can be composed — pass one into another to build animation chains
- Are SSR-safe — on the server they return static values with no timers
- Implement Svelte’s
Readablestore contract via a.subscribeshim, so$xtemplate syntax,svelte/store’sget(), andderived()keep working
Hooks at a glance
| Hook | Returns | Read pattern |
|---|---|---|
useSpring | MotionValue<number \| string> | spring.current (preferred) or $spring |
useMotionValue | MotionValue<T> | mv.current (preferred) or $mv |
useTransform | MotionValue<T> | transformed.current (preferred) or $transformed |
useScroll | { scrollX, scrollY, scrollXProgress, scrollYProgress } of MotionValue<number> | scrollY.current (preferred) or $scrollY |
useTime | MotionValue<number> | time.current (preferred) or $time |
useVelocity | MotionValue<number> | velocity.current (preferred) or $velocity |
useMotionTemplate | MotionValue<string> | template.current (preferred) or $template |
For new code, prefer .current everywhere — it tracks under Svelte 5 runes without going through the subscribe path.
Usage
Creating motion values
Use useMotionValue for a value with no spring physics:
<script>
import { useMotionValue } from '@humanspeak/svelte-motion'
const x = useMotionValue(0)
</script>
<div style="transform: translateX({x.current}px)">
Current value: {x.current}
</div><script>
import { useMotionValue } from '@humanspeak/svelte-motion'
const x = useMotionValue(0)
</script>
<div style="transform: translateX({x.current}px)">
Current value: {x.current}
</div>Use useSpring to animate toward each target with spring physics:
<script>
import { useSpring } from '@humanspeak/svelte-motion'
const x = useSpring(0, { stiffness: 300, damping: 30 })
</script>
<button onclick={() => x.set(100)}>Animate</button>
<div style="transform: translateX({x.current}px)">{x.current}</div><script>
import { useSpring } from '@humanspeak/svelte-motion'
const x = useSpring(0, { stiffness: 300, damping: 30 })
</script>
<button onclick={() => x.set(100)}>Animate</button>
<div style="transform: translateX({x.current}px)">{x.current}</div>A plain Svelte writable also works for values that don’t need motion-value composition or velocity tracking:
<script>
import { writable } from 'svelte/store'
const x = writable(0)
</script><script>
import { writable } from 'svelte/store'
const x = writable(0)
</script>Reading values
In templates, $derived, and $effect — use .current:
<div style="transform: translateX({x.current}px)">
{x.current}
</div><div style="transform: translateX({x.current}px)">
{x.current}
</div>In imperative code (event handlers, callbacks) — use .get():
<script>
function logPosition() {
console.log(x.get())
}
</script><script>
function logPosition() {
console.log(x.get())
}
</script>The Svelte 4–style $x syntax still works on every motion value via the .subscribe() shim — useful when migrating existing components incrementally.
Setting values
<script>
x.set(200) // useSpring: animates with spring physics. useMotionValue: immediate write.
x.jump(200) // useSpring only: instantly sets without animation.
</script><script>
x.set(200) // useSpring: animates with spring physics. useMotionValue: immediate write.
x.jump(200) // useSpring only: instantly sets without animation.
</script>Events
Subscribe to value changes with useMotionValueEvent:
<script>
import { useMotionValueEvent, useSpring } from '@humanspeak/svelte-motion'
import { onDestroy } from 'svelte'
const x = useSpring(0)
const unsub = useMotionValueEvent(x, 'change', (latest) => {
console.log('x is now', latest)
})
onDestroy(unsub)
</script><script>
import { useMotionValueEvent, useSpring } from '@humanspeak/svelte-motion'
import { onDestroy } from 'svelte'
const x = useSpring(0)
const unsub = useMotionValueEvent(x, 'change', (latest) => {
console.log('x is now', latest)
})
onDestroy(unsub)
</script>Springs additionally expose motion-dom event types via .on(...):
<script>
import { useSpring } from '@humanspeak/svelte-motion'
const x = useSpring(0)
x.on('animationStart', () => console.log('spring started'))
x.on('animationComplete', () => console.log('spring settled'))
</script><script>
import { useSpring } from '@humanspeak/svelte-motion'
const x = useSpring(0)
x.on('animationStart', () => console.log('spring started'))
x.on('animationComplete', () => console.log('spring settled'))
</script>Composition
Motion values become powerful when you chain them. The output of one feeds into the next:
<script>
import { useSpring, useTransform, useVelocity, useMotionTemplate } from '@humanspeak/svelte-motion'
const x = useSpring(0)
const velocity = useVelocity(x)
const skew = useTransform(velocity, [-1000, 0, 1000], [-20, 0, 20])
const filter = useMotionTemplate`drop-shadow(0 0 ${skew}px rgba(0, 0, 0, 0.4))`
</script>
<div
style="transform: translateX({x.current}px) skewX({skew.current}deg); filter: {filter.current}"
onpointermove={(e) => x.set(e.clientX)}
>
Composed chain
</div><script>
import { useSpring, useTransform, useVelocity, useMotionTemplate } from '@humanspeak/svelte-motion'
const x = useSpring(0)
const velocity = useVelocity(x)
const skew = useTransform(velocity, [-1000, 0, 1000], [-20, 0, 20])
const filter = useMotionTemplate`drop-shadow(0 0 ${skew}px rgba(0, 0, 0, 0.4))`
</script>
<div
style="transform: translateX({x.current}px) skewX({skew.current}deg); filter: {filter.current}"
onpointermove={(e) => x.set(e.clientX)}
>
Composed chain
</div>Every step in the chain is a MotionValue, so .current reads reactively without crossing the subscribe boundary.
Chain helpers
- useTransform — map a motion value’s output range to a new range
- useSpring — add spring physics to any motion value or readable
- useVelocity — derive velocity from any motion value
- useMotionTemplate — build CSS strings from multiple motion values
API
Every motion-value-producing hook in this library returns a value implementing the motion-dom MotionValue interface plus a Svelte 5 reactive surface:
| Member | Description |
|---|---|
current | Svelte 5 reactive getter — use in templates / $derived / $effect. |
get() | Imperative current-value read. |
set(value) | Update the value. useSpring animates with spring physics; every other hook writes immediately. |
jump(value) | Set immediately without animation. useSpring only. |
on(event, cb) | Subscribe to 'change', 'animationStart', 'animationComplete', etc. |
getVelocity() | Current velocity of the value. |
subscribe(run) | Svelte readable store contract — powers $mv template syntax and derived(mv, …). |
destroy() | Tear down the motion value early (normally bound to the surrounding $effect). |
See also
- useMotionTemplate — compose CSS strings from motion values
- useMotionValueEvent — subscribe to change events with cleanup
- useScroll — create scroll-linked motion values
- useSpring — spring-animated motion value
- useTime — time-based motion value
- useTransform — map and transform motion values
- useVelocity — derive velocity from a motion value
Based on Motion’s motion value API.