awwwards-animations
Awwwards Animations
Create premium web animations at Awwwards/FWA quality level. React-first approach. 60fps non-negotiable.
Decision Matrix
| Task | Library | Why |
|---|---|---|
| Scroll-driven animations | GSAP + ScrollTrigger + useGSAP | Industry standard, best control |
| Smooth scroll | Lenis + ReactLenis | Best performance, works with ScrollTrigger |
| React-native animations | Motion (Framer Motion) | Native React, useScroll/useTransform |
| Simple/lightweight effects | Anime.js 4.0 | Small footprint, clean API |
| Complex timelines | GSAP | Unmatched timeline control |
| SVG morphing | GSAP MorphSVG or Anime.js | Both excellent |
| 3D + animation | Three.js + GSAP | GSAP controls Three.js objects |
| Page transitions | AnimatePresence or GSAP | Motion for React, GSAP for complex |
| Geometric shapes (vector) | SVG + GSAP/Motion | Native, animable |
| Geometric shapes (canvas) | Canvas 2D API | Programmatic, performant |
| Pseudo-3D shapes | Zdog | Flat design 3D, ~2kb |
| Creative coding/generative | p5.js | Rich ecosystem |
| Audio reactive | Tone.js | Web Audio, synths, effects |
| Physics 2D | Matter.js | Gravity, collisions, constraints |
| Algorithmic/generative art | Canvas 2D + p5.js | Math-driven visuals |
| Fractals/L-systems | Canvas 2D recursivo | Recursive rendering |
| Tessellations/geometric puzzles | SVG + GSAP | Precise animated transforms |
| Kinetic typography advanced | GSAP SplitText + Canvas | Per-char control |
| Glitch effects | CSS + GSAP | Layered RGB split, clip-path |
| Brutalist animation | CSS raw + Motion | Hard cuts, no easing |
| Minimalist animation | Motion springs | Subtle, purposeful motion |
Installation (Latest Stable - 2025)
# GSAP + React hook (v3.14.1)
npm install gsap @gsap/react
# Lenis (v1.3.17) - includes React components
npm install lenis
# Motion (Framer Motion)
npm install motion
# Anime.js (v4.0.0)
npm install animejs
React Setup
1. GSAP Configuration (app-wide)
// lib/gsap.ts
'use client' // Next.js App Router
import gsap from 'gsap'
import { ScrollTrigger } from 'gsap/ScrollTrigger'
import { useGSAP } from '@gsap/react'
// Register plugins once
gsap.registerPlugin(ScrollTrigger, useGSAP)
export { gsap, ScrollTrigger, useGSAP }
2. Lenis + GSAP ScrollTrigger Integration (Critical)
// components/SmoothScroll.tsx
'use client'
import { ReactLenis, useLenis } from 'lenis/react'
import { useEffect } from 'react'
import { gsap, ScrollTrigger } from '@/lib/gsap'
export function SmoothScroll({ children }: { children: React.ReactNode }) {
const lenis = useLenis()
useEffect(() => {
if (!lenis) return
lenis.on('scroll', ScrollTrigger.update)
gsap.ticker.add((time) => lenis.raf(time * 1000))
gsap.ticker.lagSmoothing(0)
return () => { gsap.ticker.remove(lenis?.raf) }
}, [lenis])
return (
<ReactLenis root options={{ lerp: 0.1, duration: 1.2, smoothWheel: true }}>
{children}
</ReactLenis>
)
}
// Wrap in layout: <SmoothScroll>{children}</SmoothScroll>
Core Patterns (React)
Detailed implementations in references:
- GSAP + useGSAP: See references/gsap-react.md
- Motion (Framer Motion): See references/motion-patterns.md
- Anime.js 4.0: See references/animejs-react.md
- Lenis React: See references/lenis-react.md
- Geometric Shapes: See references/geometric-shapes.md (SVG, Canvas, Zdog, p5.js, Tetris-style)
- Audio Reactive: See references/audio-reactive.md (Tone.js, Web Audio, scroll audio)
- Physics 2D: See references/physics-2d.md (Matter.js, collisions, constraints)
- Advanced (Three.js, WebGL): See references/advanced-patterns.md
- Algorithmic & Generative Art: See references/algorithmic-art.md (fractals, L-systems, flow fields, attractors, noise, sacred geometry)
- Advanced Text Effects: See references/text-effects.md (glitch, kinetic typography, morphing, explosion, circular text, scramble)
- Geometric Puzzles: See references/geometric-puzzles.md (Dudeney, tangram, tessellations, Penrose, polyominoes)
- Design Philosophy: See references/design-philosophy.md (brutalist, minimalist, abstract, mixing styles, palettes)
- Performance: See references/performance.md
Quick Patterns (React)
1. Magnetic Cursor (GSAP + useGSAP)
'use client'
import { useRef, useEffect } from 'react'
import { gsap, useGSAP } from '@/lib/gsap'
export function MagneticCursor() {
const cursorRef = useRef<HTMLDivElement>(null)
const pos = useRef({ x: 0, y: 0, cx: 0, cy: 0 })
useEffect(() => {
const h = (e: MouseEvent) => { pos.current.x = e.clientX; pos.current.y = e.clientY }
window.addEventListener('mousemove', h)
return () => window.removeEventListener('mousemove', h)
}, [])
useGSAP(() => {
gsap.ticker.add(() => {
const p = pos.current
p.cx += (p.x - p.cx) * 0.15; p.cy += (p.y - p.cy) * 0.15
gsap.set(cursorRef.current, { x: p.cx, y: p.cy })
})
})
return <div ref={cursorRef} className="fixed w-10 h-10 border border-white rounded-full pointer-events-none mix-blend-difference z-[9999] -translate-x-1/2 -translate-y-1/2" />
}
2. Magnetic Button (Motion)
'use client'
import { useRef, useState } from 'react'
import { motion } from 'motion/react'
export function MagneticButton({ children }: { children: React.ReactNode }) {
const ref = useRef<HTMLButtonElement>(null)
const [pos, setPos] = useState({ x: 0, y: 0 })
const onMove = (e: React.MouseEvent) => {
const { left, top, width, height } = ref.current!.getBoundingClientRect()
setPos({ x: (e.clientX - left - width / 2) * 0.3, y: (e.clientY - top - height / 2) * 0.3 })
}
return (
<motion.button ref={ref} onMouseMove={onMove} onMouseLeave={() => setPos({ x: 0, y: 0 })}
animate={pos} transition={{ type: 'spring', stiffness: 150, damping: 15 }}
className="px-8 py-4 bg-white text-black rounded-full">{children}</motion.button>
)
}
3. Parallax Hero (GSAP + useGSAP)
'use client'
import { useRef } from 'react'
import { gsap, ScrollTrigger, useGSAP } from '@/lib/gsap'
export function ParallaxHero() {
const containerRef = useRef<HTMLDivElement>(null)
useGSAP(() => {
gsap.to('.parallax-bg', {
yPercent: 50,
ease: 'none',
scrollTrigger: {
trigger: containerRef.current,
start: 'top top',
end: 'bottom top',
scrub: true,
},
})
gsap.to('.hero-title', {
yPercent: 100,
opacity: 0,
scrollTrigger: {
trigger: containerRef.current,
start: 'top top',
end: '50% top',
scrub: true,
},
})
}, { scope: containerRef })
return (
<div ref={containerRef} className="relative h-screen overflow-hidden">
<div className="parallax-bg absolute inset-0 bg-cover bg-center" />
<h1 className="hero-title absolute inset-0 flex items-center justify-center text-6xl">
Hero Title
</h1>
</div>
)
}
4. Text Character Reveal (Motion)
'use client'
import { motion } from 'motion/react'
const container = {
hidden: { opacity: 0 },
visible: {
opacity: 1,
transition: { staggerChildren: 0.02 },
},
}
const child = {
hidden: { opacity: 0, y: 50, rotateX: -90 },
visible: {
opacity: 1,
y: 0,
rotateX: 0,
transition: { type: 'spring', damping: 12 },
},
}
export function TextReveal({ text }: { text: string }) {
return (
<motion.span
variants={container}
initial="hidden"
whileInView="visible"
viewport={{ once: true }}
className="inline-block"
>
{text.split('').map((char, i) => (
<motion.span key={i} variants={child} className="inline-block">
{char === ' ' ? '\u00A0' : char}
</motion.span>
))}
</motion.span>
)
}
5. Image Reveal (GSAP)
'use client'
import { useRef } from 'react'
import { gsap, useGSAP } from '@/lib/gsap'
export function ImageReveal({ src, alt }: { src: string; alt: string }) {
const containerRef = useRef<HTMLDivElement>(null)
useGSAP(() => {
gsap.from(containerRef.current, {
clipPath: 'inset(100% 0% 0% 0%)',
duration: 1.2,
ease: 'power4.inOut',
scrollTrigger: {
trigger: containerRef.current,
start: 'top 80%',
},
})
gsap.from('.reveal-img', {
scale: 1.3,
duration: 1.5,
ease: 'power2.out',
scrollTrigger: {
trigger: containerRef.current,
start: 'top 80%',
},
})
}, { scope: containerRef })
return (
<div ref={containerRef} className="overflow-hidden">
<img src={src} alt={alt} className="reveal-img w-full h-full object-cover" />
</div>
)
}
6. Glitch Text Effect (CSS + GSAP)
'use client'
import { useRef, useEffect } from 'react'
import { gsap } from '@/lib/gsap'
export function GlitchText({ text }: { text: string }) {
const ref = useRef<HTMLDivElement>(null)
useEffect(() => {
const layers = ref.current!.querySelectorAll('.g-layer')
const tl = gsap.timeline({ repeat: -1, repeatDelay: 3 })
tl.to(layers[0], { x: -5, duration: 0.05, ease: 'none' }, 0)
.to(layers[0], { x: 5, duration: 0.05 }, 0.05)
.to(layers[0], { x: 0, duration: 0.05 }, 0.1)
.to(layers[1], { x: 5, duration: 0.05 }, 0.02)
.to(layers[1], { x: -5, duration: 0.05 }, 0.07)
.to(layers[1], { x: 0, duration: 0.05 }, 0.12)
return () => { tl.kill() }
}, [])
return (
<div ref={ref} className="relative font-mono text-5xl font-black">
<span className="relative z-10">{text}</span>
<span className="g-layer absolute inset-0 text-cyan-400 mix-blend-multiply" aria-hidden>{text}</span>
<span className="g-layer absolute inset-0 text-red-400 mix-blend-multiply" aria-hidden>{text}</span>
</div>
)
}
7. Fractal Tree (Canvas 2D)
'use client'
import { useRef, useEffect } from 'react'
export function FractalTree({ depth = 10, angle = 25 }: { depth?: number; angle?: number }) {
const canvasRef = useRef<HTMLCanvasElement>(null)
useEffect(() => {
const canvas = canvasRef.current!
const ctx = canvas.getContext('2d')!
canvas.width = canvas.offsetWidth * 2; canvas.height = canvas.offsetHeight * 2; ctx.scale(2, 2)
let progress = 0, raf = 0
function branch(x: number, y: number, len: number, a: number, d: number) {
if (d > depth || len < 2) return
const dp = Math.max(0, Math.min(1, progress * depth - d))
if (dp <= 0) return
const ex = x + Math.cos(a * Math.PI / 180) * len * dp
const ey = y - Math.sin(a * Math.PI / 180) * len * dp
ctx.beginPath(); ctx.moveTo(x, y); ctx.lineTo(ex, ey)
ctx.strokeStyle = `hsl(${120 + d * 15}, 60%, ${30 + d * 5}%)`
ctx.lineWidth = Math.max(1, (depth - d) * 1.5); ctx.stroke()
branch(ex, ey, len * 0.72, a + angle, d + 1)
branch(ex, ey, len * 0.72, a - angle, d + 1)
}
const animate = () => {
progress = Math.min(1, progress + 0.008)
ctx.clearRect(0, 0, canvas.offsetWidth, canvas.offsetHeight)
branch(canvas.offsetWidth / 2, canvas.offsetHeight, canvas.offsetHeight * 0.28, 90, 0)
if (progress < 1) raf = requestAnimationFrame(animate)
}
animate()
return () => cancelAnimationFrame(raf)
}, [depth, angle])
return <canvas ref={canvasRef} className="w-full h-full bg-gray-950" />
}
See references/algorithmic-art.md for L-systems, flow fields, attractors, noise, sacred geometry.
8. Geometric Dissection (SVG + GSAP)
'use client'
import { useRef, useState } from 'react'
import { gsap } from '@/lib/gsap'
const P = [
{ id: 'A', tri: 'M 0,173 L 50,87 L 100,173 Z', sq: 'M 0,0 L 100,0 L 100,87 L 0,87 Z', c: '#f43f5e' },
{ id: 'B', tri: 'M 50,87 L 100,0 L 150,87 Z', sq: 'M 100,0 L 200,0 L 200,87 L 100,87 Z', c: '#8b5cf6' },
{ id: 'C', tri: 'M 100,173 L 150,87 L 200,173 Z', sq: 'M 0,87 L 100,87 L 100,173 L 0,173 Z', c: '#06b6d4' },
{ id: 'D', tri: 'M 50,87 L 100,173 L 150,87 L 100,0 Z', sq: 'M 100,87 L 200,87 L 200,173 L 100,173 Z', c: '#f59e0b' },
]
export function GeometricDissection() {
const svg = useRef<SVGSVGElement>(null)
const [isSq, setSq] = useState(false)
const morph = () => {
const t = !isSq
P.forEach((p, i) => {
const el = svg.current!.querySelector(`#d-${p.id}`)
if (el) gsap.to(el, { attr: { d: t ? p.sq : p.tri }, duration: 1.5, ease: 'power2.inOut', delay: i * 0.15 })
}); setSq(t)
}
return (
<div className="flex flex-col items-center gap-4">
<svg ref={svg} viewBox="-10 -10 220 200" className="w-64 h-64">
{P.map(p => <path key={p.id} id={`d-${p.id}`} d={p.tri} fill={p.c} stroke="#000" strokeWidth="1.5" />)}
</svg>
<button onClick={morph} className="px-6 py-2 bg-white text-black font-mono text-sm">{isSq ? '△' : '□'}</button>
</div>
)
}
See references/geometric-puzzles.md for tangram, tessellations, Penrose tiles, polyominoes.
9. Brutalist Grid (Motion)
'use client'
import { motion } from 'motion/react'
export function BrutalistGrid({ items }: { items: string[] }) {
return (
<div className="grid grid-cols-3 border-2 border-black">
{items.map((item, i) => (
<motion.div key={i}
className="border-2 border-black p-6 font-mono font-black uppercase text-2xl"
style={{ mixBlendMode: i % 2 === 0 ? 'normal' : 'difference' }}
initial={{ opacity: 0 }} whileInView={{ opacity: 1 }} viewport={{ once: true }}
transition={{ duration: 0, delay: i * 0.1 }}
whileHover={{ backgroundColor: '#000', color: '#BAFF39', transition: { duration: 0 } }}
>{item}</motion.div>
))}
</div>
)
}
Design Philosophy (Quick Reference)
| Style | Motion Feel | Easing | Typography | Key Trait |
|---|---|---|---|---|
| Brutalist | Hard, instant, jarring | none / steps() |
Mono, 15-30vw | Raw honesty |
| Minimalist | Smooth, subtle, slow | power2.out |
Sans-serif light | Purposeful restraint |
| Abstract | Noise-driven, parametric | Organic/sine | Varies | Mathematical beauty |
| Neo-Brutalist | Bold but controlled | power1.out |
Mono + color | Brutalism + restraint |
See references/design-philosophy.md for full guide with color palettes and mixing strategies.
Easing Reference
| Feel | GSAP | Motion |
|---|---|---|
| Smooth | power2.out |
[0.16, 1, 0.3, 1] |
| Snappy | power4.out |
[0.87, 0, 0.13, 1] |
| Bouncy | back.out(1.7) |
{ type: 'spring', stiffness: 300, damping: 20 } |
| Dramatic | power4.inOut |
[0.76, 0, 0.24, 1] |
Timing
- Micro-interactions: 150-300ms
- UI transitions: 300-500ms
- Page transitions: 500-800ms
- Stagger: 0.02-0.1s per item
Accessibility
// Motion: useReducedMotion() → conditionally disable/reduce animations
import { useReducedMotion } from 'motion/react'
const reduced = useReducedMotion() // true if prefers-reduced-motion: reduce
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
}
Performance Rules
- Only animate
transformandopacity - Use
will-changesparingly - Always cleanup:
useGSAPhandles it automatically - Scope GSAP selectors to container refs
- Use
contextSafe()for event handlers with GSAP - Memoize Motion variants objects
Common Pitfalls
- Not integrating Lenis with ScrollTrigger
- Missing
scopein useGSAP - Not using
contextSafe()for click handlers - React 18 Strict Mode calling effects twice
- Forgetting
'use client'in Next.js App Router - Not calling
ScrollTrigger.refresh()after dynamic content
Testing Checklist
- 60fps on scroll (Chrome DevTools Performance)
- Keyboard navigation works
- Respects prefers-reduced-motion
- No layout shifts (CLS)
- Mobile touch works
- ScrollTrigger markers removed in prod
- No memory leaks on unmount
Inspiration
Active Theory, Studio Freight, Locomotive, Resn, Aristide Benoist, Immersive Garden
More from hainrixz/editor-pro-max
explainer-video-guide
Explainer video production guide: scripting, voiceover, visuals, and assembly. Covers script formulas, pacing rules, scene planning, and multi-tool pipelines. Use for: product demos, how-it-works videos, onboarding videos, social explainers. Triggers: explainer video, how to make explainer, product video, demo video, video production, video script, animated explainer, product demo video, tutorial video, onboarding video, walkthrough video, video pipeline
18ffmpeg
Video and audio processing with FFmpeg. Use for format conversion, resizing, compression, audio extraction, and preparing assets for Remotion. Triggers include converting GIF to MP4, resizing video, extracting audio, compressing files, or any media transformation task.
17motion-designer
Advanced motion designer with decades of After Effects and motion graphics experience, specialized in creating engaging video specifications for Remotion. Use when creating video specs, planning motion graphics, designing animations, or when asked to "create a video", "design motion graphics", "plan video content", or "spec out a video". Produces detailed scene-by-scene specifications with timing, audio, sound effects, and animation descriptions.
17playwright-mcp
Live browser interaction via Playwright MCP — navigate pages, click buttons, fill forms, take screenshots.
17remotion-render
Render videos from React/Remotion component code via inference.sh. Pass TSX code, get MP4. Supports all Remotion APIs: useCurrentFrame, useVideoConfig, spring, interpolate, AbsoluteFill, Sequence. Configurable resolution, FPS, duration, codec. Use for: programmatic video generation, animated graphics, motion design, data-driven videos, React animations to video. Triggers: remotion, render video from code, tsx to video, react video, programmatic video, remotion render, code to video, animated video, motion graphics code, react animation video
17remotion-best-practices
Best practices for Remotion - Video creation in React
17