Physics-based animations and smooth transitions between state values with spring and tween effects.
Create stores with spring-based physics animations that simulate natural motion with bounce and elasticity.
/**
* Creates a store whose value is animated with spring physics
* @param value - Initial value
* @param opts - Spring configuration options
* @returns Spring store with physics-based animation
*/
function spring<T = any>(value?: T, opts?: SpringOpts): Spring<T>;
interface Spring<T> extends Readable<T> {
/** Set new target value with optional animation options */
set: (new_value: T, opts?: SpringUpdateOpts) => Promise<void>;
/** Update value using callback with optional animation options */
update: (fn: Updater<T>, opts?: SpringUpdateOpts) => Promise<void>;
/** Spring stiffness (0-1, higher = more responsive) */
stiffness: number;
/** Spring damping (0-1, higher = less oscillation) */
damping: number;
/** Animation precision threshold */
precision: number;
}
interface SpringOpts {
/** Stiffness controls responsiveness (default: 0.15) */
stiffness?: number;
/** Damping controls oscillation (default: 0.8) */
damping?: number;
/** Precision threshold for stopping animation (default: 0.01) */
precision?: number;
}
interface SpringUpdateOpts {
/** Hard transition - skip animation */
hard?: boolean;
/** Soft transition - gradual mass recovery */
soft?: string | number | boolean;
}
type Updater<T> = (target_value: T, value: T) => T;Usage Examples:
import { spring } from "svelte/motion";
// Basic spring store
const coords = spring({ x: 50, y: 50 }, {
stiffness: 0.1,
damping: 0.25
});
// Animate to new position
coords.set({ x: 100, y: 200 });
// Update with callback
coords.update((target, current) => ({
x: target.x + 10,
y: target.y + 10
}));
// Responsive spring for UI elements
const scale = spring(1, {
stiffness: 0.3,
damping: 0.6
});
// Mouse hover effects
function handleMouseEnter() {
scale.set(1.1);
}
function handleMouseLeave() {
scale.set(1);
}
// Hard vs soft transitions
const position = spring({ x: 0, y: 0 });
// Hard transition (no animation)
position.set({ x: 100, y: 100 }, { hard: true });
// Soft transition (gradual acceleration)
position.set({ x: 200, y: 200 }, { soft: true });Create stores with smooth, time-based transitions between values using easing functions.
/**
* Creates a store that provides smooth transitions between state values over time
* @param value - Initial value
* @param defaults - Default tween options
* @returns Tweened store with time-based animation
*/
function tweened<T>(value?: T, defaults?: TweenedOptions<T>): Tweened<T>;
interface Tweened<T> extends Readable<T> {
/** Set new value with optional tween options */
set(value: T, opts?: TweenedOptions<T>): Promise<void>;
/** Update value using callback with optional tween options */
update(updater: Updater<T>, opts?: TweenedOptions<T>): Promise<void>;
}
interface TweenedOptions<T> {
/** Delay before animation starts (ms) */
delay?: number;
/** Animation duration (ms) or function */
duration?: number | ((from: T, to: T) => number);
/** Easing function */
easing?: (t: number) => number;
/** Custom interpolation function */
interpolate?: (a: T, b: T) => (t: number) => T;
}
type Updater<T> = (value: T) => T;Usage Examples:
import { tweened } from "svelte/motion";
import { cubicOut } from "svelte/easing";
// Basic tweened store
const progress = tweened(0, {
duration: 400,
easing: cubicOut
});
// Animate progress bar
progress.set(75);
// Dynamic duration based on distance
const position = tweened(0, {
duration: (from, to) => Math.abs(to - from) * 10,
easing: cubicOut
});
// Color transitions
const color = tweened([255, 0, 0], {
duration: 800,
interpolate: (from, to) => (t) => [
Math.round(from[0] + (to[0] - from[0]) * t),
Math.round(from[1] + (to[1] - from[1]) * t),
Math.round(from[2] + (to[2] - from[2]) * t)
]
});
color.set([0, 255, 0]); // Animate from red to green
// Text size animation
const fontSize = tweened(16, {
duration: 300,
easing: cubicOut
});
// Smooth number counting
const counter = tweened(0, { duration: 2000 });
counter.set(1000); // Count up to 1000 over 2 seconds
// Promise-based animation chaining
async function animateSequence() {
await progress.set(25);
await progress.set(50);
await progress.set(100);
console.log('Animation sequence complete');
}Advanced usage with custom interpolation functions for complex data types.
Object Interpolation:
import { tweened } from "svelte/motion";
const objectStore = tweened({ x: 0, y: 0, opacity: 1 }, {
interpolate: (from, to) => (t) => ({
x: from.x + (to.x - from.x) * t,
y: from.y + (to.y - from.y) * t,
opacity: from.opacity + (to.opacity - from.opacity) * t
})
});
objectStore.set({ x: 100, y: 200, opacity: 0.5 });Date Interpolation:
import { tweened } from "svelte/motion";
const dateStore = tweened(new Date(), {
interpolate: (from, to) => (t) => {
const fromTime = from.getTime();
const toTime = to.getTime();
return new Date(fromTime + (toTime - fromTime) * t);
}
});
dateStore.set(new Date(Date.now() + 7 * 24 * 60 * 60 * 1000)); // Week from nowCommon patterns for using motion stores in Svelte applications.
Coordinated Animations:
import { spring } from "svelte/motion";
const mainPosition = spring({ x: 0, y: 0 });
const shadowPosition = spring({ x: 0, y: 0 }, {
stiffness: 0.05,
damping: 0.9
});
// Main element moves immediately, shadow follows with delay
function moveTo(x, y) {
mainPosition.set({ x, y });
setTimeout(() => shadowPosition.set({ x, y }), 100);
}Gesture-based Animation:
import { spring } from "svelte/motion";
const dragPosition = spring({ x: 0, y: 0 }, {
stiffness: 0.2,
damping: 0.4
});
let isDragging = false;
function handleMouseDown() {
isDragging = true;
// Stiffer spring while dragging
dragPosition.stiffness = 1;
dragPosition.damping = 1;
}
function handleMouseUp() {
isDragging = false;
// Bouncy spring when released
dragPosition.stiffness = 0.1;
dragPosition.damping = 0.3;
// Snap back to origin
dragPosition.set({ x: 0, y: 0 });
}Loading Animations:
import { tweened } from "svelte/motion";
import { linear } from "svelte/easing";
const loadingProgress = tweened(0, {
duration: 3000,
easing: linear
});
async function simulateLoading() {
await loadingProgress.set(30); // Quick initial progress
await loadingProgress.set(60); // Slower middle phase
await loadingProgress.set(100); // Final completion
}Using motion stores effectively in Svelte components:
// In a Svelte component
import { spring, tweened } from "svelte/motion";
import { cubicOut } from "svelte/easing";
const scale = spring(1);
const opacity = tweened(1);
function handleHover() {
scale.set(1.1);
opacity.set(0.8);
}
function handleLeave() {
scale.set(1);
opacity.set(1);
}<!-- Template using reactive values -->
<div
style="transform: scale({$scale}); opacity: {$opacity}"
on:mouseenter={handleHover}
on:mouseleave={handleLeave}
>
Animated element
</div>