# 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 (
);
}
```
### 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
);
}
```