Static Methods
Motion.set(), Motion.kill(), Motion.killAll(), Motion.reset(), Motion.refreshScrollTriggers().
Static methods on the Motion object let you manage the global timeline registry, set properties instantly, and handle cleanup for SPAs and dynamic content.
Overview
| Method | Signature | Description |
|---|---|---|
Motion.set() | set(target: TargetInput, vars: AnimationVars): void | Immediately apply CSS properties with no animation |
Motion.get() | get(name: string): Timeline | undefined | Safe timeline retrieval — undefined if not found |
Motion.has() | has(name: string): boolean | Check if a named timeline is registered |
Motion.getNames() | getNames(): string[] | Array of all registered timeline names |
Motion.kill() | kill(name: string): void | Kill one timeline by name, restore initial CSS |
Motion.killAll() | killAll(): void | Kill every registered timeline |
Motion.reset() | reset(targets: TargetInput): void | Kill animations, revert text splits, clear transform cache |
Motion.refreshScrollTriggers() | refreshScrollTriggers(): void | Recalculate all scroll trigger positions |
Motion.cleanup() | cleanup(): void | Remove ScrollTrigger spacer and marker DOM nodes |
Motion.context() | context(fn: () => void): MotionContext | Create a scoped context for grouped teardown |
Motion.utils | — | Utility functions |
Motion.set()
Motion.set() immediately applies CSS properties to one or more elements — a zero-duration snapshot with no animation played.
import { Motion } from "@motion.page/sdk";
// Set a single element's initial state
Motion.set("#hero", { opacity: 0, y: 40 });
// Set multiple elements at once
Motion.set(".card", { scale: 0.95, opacity: 0 });
// Set CSS custom properties
Motion.set(":root", { "--accent": "#6633EE" }); | Parameter | Type | Description |
|---|---|---|
target | TargetInput | CSS selector, Element, NodeList, or array of elements |
vars | AnimationVars | The same property object accepted by from / to |
Use cases
Set initial state before animating — hide elements before a page-load animation so they don’t flash:
import { Motion } from "@motion.page/sdk";
// Hide immediately, then animate in
Motion.set(".hero-title, .hero-sub, .hero-cta", { opacity: 0, y: 30 });
Motion("hero", [
{ target: ".hero-title", to: { opacity: 1, y: 0 }, duration: 0.7 },
{ target: ".hero-sub", to: { opacity: 1, y: 0 }, duration: 0.6, position: "+=0.1" },
{ target: ".hero-cta", to: { opacity: 1, y: 0 }, duration: 0.5, position: "+=0.1" },
]).onPageLoad(); Reset after animation completes:
Motion("slide", ".panel", { from: { x: -300 }, duration: 0.6 })
.onComplete(() => {
// Snap back without a visible animation
Motion.set(".panel", { x: 0 });
})
.onPageLoad(); Registry Methods
The timeline registry tracks every named Motion timeline. These helpers let you inspect it safely without risking a thrown error.
| Method | Returns | Description |
|---|---|---|
Motion.get(name) | Timeline | undefined | Returns the timeline, or undefined if not registered |
Motion.has(name) | boolean | true if the timeline exists in the registry |
Motion.getNames() | string[] | All currently registered timeline names |
import { Motion } from "@motion.page/sdk";
// Safe conditional control
if (Motion.has("hero")) {
Motion.get("hero")?.pause();
}
// Debug — log all active timelines
console.log(Motion.getNames()); // ["hero", "nav-reveal", "card-hover"] These are most useful when you need to control a timeline from a different scope than where it was created. See Timeline Control for the full set of playback and state methods available on a retrieved timeline.
Motion.kill()
Motion.kill(name) removes a single timeline from the registry by name and, by default, restores all CSS properties the animation touched to their pre-animation values.
import { Motion } from "@motion.page/sdk";
Motion("modal-in", "#modal", {
from: { opacity: 0, scale: 0.92 },
duration: 0.4,
}).onPageLoad({ paused: true });
// Show modal
document.querySelector("#open-modal")?.addEventListener("click", () => {
Motion("modal-in").play();
});
// Dismiss and clean up
document.querySelector("#close-modal")?.addEventListener("click", () => {
Motion.kill("modal-in");
}); After Motion.kill("modal-in"), calling Motion("modal-in") will throw. Guard with Motion.has() or use Motion.get() which returns undefined safely.
Motion.killAll()
Motion.killAll() kills every timeline currently in the registry. Use it for full-page teardown — SPA route changes, modal unmounts that own several animations, or any situation where you want a clean slate.
import { Motion } from "@motion.page/sdk";
// SPA router — clean up before navigating away
router.beforeEach(() => {
Motion.killAll();
}); // Vue Router equivalent
router.afterEach(() => {
Motion.killAll();
}); Motion.reset()
Motion.reset(targets) is a more thorough cleanup than kill. In addition to stopping animations, it:
- Reverts any Text Splitter splits on the targets (re-merges characters/words/lines)
- Clears the internal transform cache for those elements
- Restores initial CSS
import { Motion } from "@motion.page/sdk";
// After a page section is removed from the DOM
Motion.reset(".hero-section");
// Reset all animated elements before reinitialising
Motion.reset(".animate-in");
Motion("page-reveal", ".animate-in", {
from: { opacity: 0, y: 20 },
duration: 0.5,
stagger: 0.08,
}).onPageLoad(); | Parameter | Type | Description |
|---|---|---|
targets | TargetInput | CSS selector, Element, NodeList, or array of elements |
Use Motion.reset() when reinitialising animations on elements that previously had split text or complex transform sequences — it prevents stale state from carrying over.
Motion.refreshScrollTriggers()
Motion.refreshScrollTriggers() recalculates the start and end scroll positions for all active scroll-based animations. Call it any time the page layout changes after scroll triggers were created.
Common situations that require a refresh:
- Dynamic content finishes loading (images, async data, lazy components)
- An accordion or disclosure opens/closes
- A tab panel becomes visible
- Fonts finish loading and reflow the page
- CSS transitions that change element height complete
import { Motion } from "@motion.page/sdk";
// After async content loads
async function loadItems() {
const items = await fetchItems();
renderList(items);
// Layout has changed — recalculate scroll positions
Motion.refreshScrollTriggers();
} Debounced resize handler
Scroll trigger positions are also invalidated by window resizes. Wrap in a debounce to avoid excessive recalculations:
import { Motion } from "@motion.page/sdk";
let resizeTimer: ReturnType<typeof setTimeout>;
window.addEventListener("resize", () => {
clearTimeout(resizeTimer);
resizeTimer = setTimeout(() => {
Motion.refreshScrollTriggers();
}, 150);
}); See Scroll Trigger for full documentation on scroll-based animation options.
Motion.cleanup()
Motion.cleanup() removes the spacer <div> elements and debug marker nodes that ScrollTrigger injects into the DOM. It does not kill animations — combine it with Motion.killAll() for a complete teardown.
import { Motion } from "@motion.page/sdk";
// Full scroll-animation teardown
function teardown() {
Motion.killAll();
Motion.cleanup();
}
// E.g., on SPA route change
document.addEventListener("astro:before-swap", teardown); Spacer nodes are only present when pin: true is used on a scroll trigger. Markers are visible only in development. cleanup() is safe to call even when neither is present.
Motion.context()
Motion.context(fn) creates a scoped context that tracks every timeline registered inside the callback function. It returns a MotionContext object you can use to revert, refresh, or extend the group later.
This is the recommended pattern for SPAs and any component that creates more than one animation — instead of calling Motion.kill() individually for each timeline, a single ctx.revert() tears them all down.
MotionContext methods
| Method | Signature | Description |
|---|---|---|
revert() | revert(): void | Kill all timelines created in this context and restore CSS |
refresh() | refresh(): void | Recalculate scroll trigger positions for timelines in this context |
add() | add(fn: () => void): void | Register additional timelines into the context after creation |
Basic usage
import { Motion } from "@motion.page/sdk";
const ctx = Motion.context(() => {
Motion("nav-fade", ".nav-item", {
from: { opacity: 0, x: -12 },
stagger: 0.06,
duration: 0.4,
}).onPageLoad();
Motion("nav-underline", ".nav-link", {
to: { scaleX: 1 },
duration: 0.25,
}).onHover({ onLeave: "reverse" });
});
// Tears down both timelines in one call
ctx.revert(); React — useEffect cleanup
import { useEffect } from "react";
import { Motion } from "@motion.page/sdk";
export function HeroSection() {
useEffect(() => {
const ctx = Motion.context(() => {
Motion("hero-title", "#hero h1", {
from: { opacity: 0, y: 40 },
duration: 0.7,
ease: "power3.out",
}).onPageLoad();
Motion("hero-body", "#hero p", {
from: { opacity: 0, y: 20 },
duration: 0.6,
position: "+=0.1",
}).onPageLoad();
});
// ctx.revert() kills both timelines when the component unmounts
return () => ctx.revert();
}, []);
return (
<section id="hero">
<h1>Welcome</h1>
<p>Subtitle copy here.</p>
</section>
);
} Astro View Transitions
<script>
import { Motion } from "@motion.page/sdk";
let ctx: ReturnType<typeof Motion.context>;
function initAnimations() {
ctx = Motion.context(() => {
Motion("page-reveal", ".animate-in", {
from: { opacity: 0, y: 20 },
duration: 0.5,
stagger: 0.1,
}).onPageLoad();
});
}
// Initial page load
initAnimations();
// Reinitialise after each View Transition
document.addEventListener("astro:page-load", () => {
initAnimations();
});
// Tear down before the DOM is swapped out
document.addEventListener("astro:before-swap", () => {
ctx?.revert();
});
</script> Adding timelines after creation
Use ctx.add() to register timelines that are created outside the original callback — for example, inside a dynamic content render:
import { Motion } from "@motion.page/sdk";
const ctx = Motion.context(() => {
Motion("list-header", ".list-header", {
from: { opacity: 0 },
duration: 0.4,
}).onPageLoad();
});
// Later — dynamic items loaded; add their animations into the same context
ctx.add(() => {
Motion("list-items", ".list-item", {
from: { opacity: 0, y: 12 },
duration: 0.35,
stagger: 0.06,
}).onPageLoad();
});
// ctx.revert() now cleans up all three timelines Motion.utils
Motion.utils provides utility functions (toArray, clamp, random, snap, interpolate, mapRange, normalize, wrap). See Motion.utils for the full reference.
Common Patterns
Full teardown on SPA navigation
import { Motion } from "@motion.page/sdk";
// Works with any router that exposes a before-navigate hook
router.beforeEach(() => {
Motion.killAll();
Motion.cleanup(); // removes ScrollTrigger spacers and markers
}); Debounced resize with scroll refresh
import { Motion } from "@motion.page/sdk";
let timer: ReturnType<typeof setTimeout>;
window.addEventListener("resize", () => {
clearTimeout(timer);
timer = setTimeout(() => Motion.refreshScrollTriggers(), 150);
}); Reinitialise after dynamic content
import { Motion } from "@motion.page/sdk";
async function loadAndAnimate() {
const data = await fetchProducts();
renderProductGrid(data);
// Recalculate scroll positions now that new elements exist
Motion.refreshScrollTriggers();
} Generic SPA cleanup with context
import { Motion } from "@motion.page/sdk";
let pageCtx: ReturnType<typeof Motion.context> | null = null;
function onPageEnter() {
pageCtx = Motion.context(() => {
Motion("page-in", "main", { from: { opacity: 0 }, duration: 0.35 }).onPageLoad();
Motion("page-items", ".item", {
from: { opacity: 0, y: 16 },
stagger: 0.07,
duration: 0.4,
}).onPageLoad();
});
}
function onPageLeave() {
pageCtx?.revert();
Motion.cleanup();
pageCtx = null;
} Related: Timeline Control · Scroll Trigger · Motion.utils