Motion
Animate with the theme's timing, in CSS or in script, and hold still when the user asks for less motion.
Timing tokens
Every theme sets three durations and one easing curve: --sv-duration-fast, --sv-duration-normal, --sv-duration-slow and --sv-ease.
The durations are Fibonacci milliseconds, 144, 233 and 377 in Monolith. When the user asks for
reduced motion, the base styles set every duration to 0.01ms whatever the theme, so anything
timed with the tokens becomes instant without checking the setting itself.
.panel {
transition:
opacity var(--sv-duration-normal) var(--sv-ease),
transform var(--sv-duration-normal) var(--sv-ease);
}
.panel[data-closed] {
opacity: 0;
transform: translateY(8px);
}Animate only transform and opacity. The browser moves them without
recalculating layout or repainting, so motion stays smooth on slow devices.
Transitions
For content that mounts and unmounts, fade, rise and pop are Svelte transitions that read the timing of the theme where the element is. They move only opacity
and transform, and the tokens make them instant under reduced motion.
Hide and show the receipt with each transition. Switch theme packs to feel their timing, or turn on reduced motion in your system settings to see it become instant.
<script>
import { rise } from 'sveltier';
let shown = $state(false);
</script>
<button aria-expanded={shown} onclick={() => (shown = !shown)}>Receipt</button>
{#if shown}
<!-- Or in:pop out:fade, or rise with { distance: 13 }. -->
<div transition:rise>Transfer sent: €1,250.00</div>
{/if}| Name | Type | Default | Description |
|---|---|---|---|
duration | number | the theme's normal duration | Length in ms. Under reduced motion the theme duration is 0.01ms. |
delay | number | 0 | Wait before starting, in ms. |
distance | number | 8 | rise only: how far the element travels, in px. |
scale | number | 0.944 | pop only: the scale it grows from, 1 − φ⁻⁶. |
Springs
spring() returns a Svelte Spring with one of three presets. Stiffness steps
down the φ series, 1/φ³, 1/φ⁴ and 1/φ⁵, and damping is what is left of 1. Use snappy for small controls,
standard for most movement and gentle for large surfaces and numbers that count. While the user prefers
reduced motion, every update lands at once.
- snappy 38.2%
- standard 38.2%
- gentle 38.2%
Rebalance to move all three to the other side of the golden split. With reduced motion turned on, they jump there at once.
<script>
import { spring } from 'sveltier';
const balance = spring(248190.35, 'gentle');
</script>
<button onclick={() => (balance.target += 1000)}>Deposit 1,000</button>
<!-- target is where it is going; current is what to show. -->
<p class="amount">{balance.current.toFixed(2)}</p>| Name | Type | Default | Description |
|---|---|---|---|
spring(value, preset) | <T>(value: T, preset?: SpringPreset) => Spring<T> | 'standard' | A Svelte Spring with a preset. Set target to move it and render current. While the user prefers reduced motion, updates land at once unless set() is called with instant: false. |
snappy | { stiffness: 0.236, damping: 0.764 } | – | 1/φ³. Small, quick things: toggles, thumbs, indicators. |
standard | { stiffness: 0.146, damping: 0.854 } | – | 1/φ⁴, close to Svelte's own default. Most movement. |
gentle | { stiffness: 0.09, damping: 0.91 } | – | 1/φ⁵. Large surfaces and numbers that count up or down. |
Timing in script
motion() reads the timing where an element is, for element.animate() and for Svelte's Tween. Like the CSS, it follows the theme in scope and drops to
0.01ms under reduced motion.
import { Tween } from 'svelte/motion';
import { easing, motion } from 'sveltier';
// element.animate() takes the theme's easing as it is.
export function flash(cell: HTMLElement) {
const { fast, ease } = motion(cell);
cell.animate([{ opacity: 0.382 }, { opacity: 1 }], { duration: fast, easing: ease });
}
// Tween needs a function: easing() turns the curve into one.
export function progress(element: HTMLElement) {
const { slow, ease } = motion(element);
return new Tween(0, { duration: slow, easing: easing(ease) });
}| Name | Type | Description |
|---|---|---|
motion(element) | (element: Element) => Motion | The timing where the element is: fast, normal and slow in ms, and ease as a CSS easing. Call it in the browser, from an attachment, an effect or a handler. |
easing(ease) | (ease: string) => (t: number) => number | A CSS easing as a function. Reads cubic-bezier() and the keywords; anything else falls back to ease. |
cubicBezier(x1, y1, x2, y2) | (x1: number, y1: number, x2: number, y2: number) => (t: number) => number | An easing function from control points, as CSS defines them. |