# Animation Libraries Reference ## Framer Motion The most popular React animation library with declarative API. ### Basic Animations ```tsx import { motion, AnimatePresence } from "framer-motion"; // Simple animation function FadeIn({ children }) { return ( {children} ); } // Gesture animations function InteractiveCard() { return ( Hover or tap me ); } // Keyframes animation function PulseButton() { return ( Click me ); } ``` ### Layout Animations ```tsx import { motion, LayoutGroup } from "framer-motion"; // Shared layout animation function TabIndicator({ activeTab, tabs }) { return (
{tabs.map((tab) => ( ))}
); } // Auto-layout reordering function ReorderableList({ items, setItems }) { return ( {items.map((item) => ( {item.title} ))} ); } ``` ### Orchestration ```tsx // Staggered children const containerVariants = { hidden: { opacity: 0 }, visible: { opacity: 1, transition: { staggerChildren: 0.1, delayChildren: 0.2, }, }, }; const itemVariants = { hidden: { opacity: 0, y: 20 }, visible: { opacity: 1, y: 0, transition: { duration: 0.3 }, }, }; function StaggeredList({ items }) { return ( {items.map((item) => ( {item.content} ))} ); } ``` ### Page Transitions ```tsx import { AnimatePresence, motion } from "framer-motion"; import { useRouter } from "next/router"; const pageVariants = { initial: { opacity: 0, x: -20 }, enter: { opacity: 1, x: 0 }, exit: { opacity: 0, x: 20 }, }; function PageTransition({ children }) { const router = useRouter(); return ( {children} ); } ``` ## GSAP (GreenSock) Industry-standard animation library for complex, performant animations. ### Basic Timeline ```tsx import { useRef, useLayoutEffect } from "react"; import gsap from "gsap"; function AnimatedHero() { const containerRef = useRef(null); const titleRef = useRef(null); const subtitleRef = useRef(null); useLayoutEffect(() => { const ctx = gsap.context(() => { const tl = gsap.timeline({ defaults: { ease: "power3.out" } }); tl.from(titleRef.current, { y: 50, opacity: 0, duration: 0.8, }) .from( subtitleRef.current, { y: 30, opacity: 0, duration: 0.6, }, "-=0.4", // Start 0.4s before previous ends ) .from(".cta-button", { scale: 0.8, opacity: 0, duration: 0.4, }); }, containerRef); return () => ctx.revert(); // Cleanup }, []); return (

Welcome

Discover amazing things

); } ``` ### ScrollTrigger ```tsx import { useLayoutEffect, useRef } from "react"; import gsap from "gsap"; import { ScrollTrigger } from "gsap/ScrollTrigger"; gsap.registerPlugin(ScrollTrigger); function ParallaxSection() { const sectionRef = useRef(null); const imageRef = useRef(null); useLayoutEffect(() => { const ctx = gsap.context(() => { // Parallax image gsap.to(imageRef.current, { yPercent: -20, ease: "none", scrollTrigger: { trigger: sectionRef.current, start: "top bottom", end: "bottom top", scrub: true, }, }); // Fade in content gsap.from(".content-block", { opacity: 0, y: 50, stagger: 0.2, scrollTrigger: { trigger: sectionRef.current, start: "top 80%", end: "top 20%", scrub: 1, }, }); }, sectionRef); return () => ctx.revert(); }, []); return (
Block 1
Block 2
); } ``` ### Text Animation ```tsx import { useLayoutEffect, useRef } from "react"; import gsap from "gsap"; import { SplitText } from "gsap/SplitText"; gsap.registerPlugin(SplitText); function AnimatedHeadline({ text }) { const textRef = useRef(null); useLayoutEffect(() => { const split = new SplitText(textRef.current, { type: "chars,words", charsClass: "char", }); gsap.from(split.chars, { opacity: 0, y: 50, rotateX: -90, stagger: 0.02, duration: 0.8, ease: "back.out(1.7)", }); return () => split.revert(); }, [text]); return

{text}

; } ``` ## CSS Spring Physics ```tsx // spring.ts - Custom spring physics interface SpringConfig { stiffness: number; // Higher = snappier damping: number; // Higher = less bouncy mass: number; } const presets: Record = { default: { stiffness: 170, damping: 26, mass: 1 }, gentle: { stiffness: 120, damping: 14, mass: 1 }, wobbly: { stiffness: 180, damping: 12, mass: 1 }, stiff: { stiffness: 210, damping: 20, mass: 1 }, slow: { stiffness: 280, damping: 60, mass: 1 }, molasses: { stiffness: 280, damping: 120, mass: 1 }, }; function springToCss(config: SpringConfig): string { // Convert spring parameters to CSS timing function approximation const { stiffness, damping } = config; const duration = Math.sqrt(stiffness) / damping; const bounce = 1 - damping / (2 * Math.sqrt(stiffness)); // Map to cubic-bezier (approximation) if (bounce <= 0) { return `cubic-bezier(0.25, 0.1, 0.25, 1)`; } return `cubic-bezier(0.34, 1.56, 0.64, 1)`; } ``` ## Web Animations API Native browser animation API for simple animations. ```tsx function useWebAnimation( ref: RefObject, keyframes: Keyframe[], options: KeyframeAnimationOptions, ) { useEffect(() => { if (!ref.current) return; const animation = ref.current.animate(keyframes, options); return () => animation.cancel(); }, [ref, keyframes, options]); } // Usage function SlideIn({ children }) { const elementRef = useRef(null); useWebAnimation( elementRef, [ { transform: "translateX(-100%)", opacity: 0 }, { transform: "translateX(0)", opacity: 1 }, ], { duration: 300, easing: "cubic-bezier(0.16, 1, 0.3, 1)", fill: "forwards", }, ); return
{children}
; } ``` ## View Transitions API Native browser API for page transitions. ```tsx // Check support const supportsViewTransitions = "startViewTransition" in document; // Simple page transition async function navigateTo(url: string) { if (!document.startViewTransition) { window.location.href = url; return; } document.startViewTransition(async () => { await fetch(url); // Update DOM }); } // Named elements for morphing function ProductCard({ product }) { return ( ); } // CSS for view transitions /* ::view-transition-old(root) { animation: fade-out 0.25s ease-out; } ::view-transition-new(root) { animation: fade-in 0.25s ease-in; } ::view-transition-group(product-*) { animation-duration: 0.3s; } */ ``` ## Performance Tips ### GPU Acceleration ```css /* Properties that trigger GPU acceleration */ .animated-element { transform: translateZ(0); /* Force GPU layer */ will-change: transform, opacity; /* Hint to browser */ } /* Only animate transform and opacity for 60fps */ .smooth { transition: transform 0.3s ease, opacity 0.3s ease; } /* Avoid animating these (cause reflow) */ .avoid { /* Don't animate: width, height, top, left, margin, padding */ } ``` ### Reduced Motion ```tsx function useReducedMotion() { const [prefersReduced, setPrefersReduced] = useState(false); useEffect(() => { const mq = window.matchMedia("(prefers-reduced-motion: reduce)"); setPrefersReduced(mq.matches); const handler = (e: MediaQueryListEvent) => setPrefersReduced(e.matches); mq.addEventListener("change", handler); return () => mq.removeEventListener("change", handler); }, []); return prefersReduced; } // Usage function AnimatedComponent() { const prefersReduced = useReducedMotion(); return ( Content ); } ```