Contents
SVG loading spinner
import "./styles.css" import { animate, stagger } from "motion" const numSegments = document.querySelectorAll(".segment").length /** * Stagger offset (in seconds) * Decrease this to speed the animation up or increase * to slow it down. */ const offset = 0.09 setTimeout(() => { animate( ".segment", { opacity: [0, 1, 0] }, { offset: [0, 0.1, 1], duration: numSegments * offset, delay: stagger(offset), repeat: Infinity, } ) }, 1000)
SVG path drawing timeline
import "./styles.css" import { timeline } from "motion" /** * Remember to set the pathLength="1" SVG attribute on * the elements you want to draw. This makes it easy * to use the same animation logic for elements of a * different path length. */ const draw = (progress) => ({ // This property makes the line "draw" in when animated strokeDashoffset: 1 - progress, // Each line will be hidden until it starts drawing // to fix a bug in Safari where the line can be // partially visible even when progress is at 0 visibility: "visible", }) timeline([ ["circle", draw(1), { duration: 0.8, delay: 1 }], ["path", draw(1), { duration: 0.6, at: "-0.2" }], ])
Scroll-triggered animation
Animating HTML text
Morph SVG path
import { animate } from "motion"; import { interpolate } from "flubber"; import { paths } from "./paths"; const path = document.querySelector("path"); let currentPath = paths.star; path.setAttribute("fill", currentPath.color); path.setAttribute("d", currentPath.d); const transition = { duration: 0.5 }; function togglePath() { currentPath = currentPath === paths.star ? paths.heart : paths.star; const mixPaths = interpolate(path.getAttribute("d"), currentPath.d, { maxSegmentLength: 0.1 }); animate(path, { fill: currentPath.color }, transition); animate((progress) => path.setAttribute("d", mixPaths(progress)), transition); } setTimeout(togglePath, 1000); path.addEventListener("click", togglePath);
P5
Mixing Motion One custom animations with the P5 library.
import P5 from "p5"; import { animate, spring } from "motion"; import { mix, progress, wrap } from "@motionone/utils"; new P5(function (p5) { let x = 0; let y = 0; let radius = 50; let weight = 3; let currentAnimation; const startAnimation = (targetX, targetY) => { const originX = x; const originY = y; currentAnimation && currentAnimation.stop(); currentAnimation = animate( (progress) => { x = mix(originX, targetX, progress); y = mix(originY, targetY, progress); }, { easing: spring({ stiffness: 300, damping: 10, restDistance: 0.001 }) } ); }; p5.setup = () => { const { width, height, elt: element } = p5.createCanvas( Math.max(document.documentElement.clientWidth, window.innerWidth || 0), Math.max(document.documentElement.clientHeight, window.innerHeight || 0) ); x = width / 2; y = height / 2; element.addEventListener("click", (event) => { startAnimation(event.pageX, event.pageY); }); }; p5.draw = () => { p5.noFill(); p5.strokeWeight(weight); p5.stroke(`hsl(${getHue(performance.now())}, 100%, 50%)`); p5.circle(x, y, radius); }; }); const duration = 4000; function getHue(t) { const looped = wrap(0, duration, t); const p = progress(0, duration, looped); return Math.round(mix(0, 360, p)); }