awwwards-animations

Professional React animation skill for creating Awwwards/FWA-level animations using GSAP (useGSAP), Motion (Framer Motion), Anime.js, and Lenis. Use when building premium scroll experiences, custom cursors, page transitions, text animations, parallax effects, micro-interactions, or any animation that needs to be 60fps and award-worthy. Triggers on requests for smooth scroll, ScrollTrigger, magnetic effects, reveal animations, horizontal scroll, pin sections, stagger effects, useScroll, useTransform, integration with Three.js/WebGL, algorithmic art, mathematical art, generative art, fractals, L-systems, flow fields, strange attractors, sacred geometry, geometric puzzles, Dudeney dissections, tangram, tessellations, Penrose tiles, kinetic typography, glitch effects, text explosion, morphing text, circular text, brutalist design, minimalist animation, neo-brutalism, or design philosophy mixing. React-first approach with proper cleanup and hooks.

Skill file

Preview skill file
---
name: awwwards-animations
description: Professional React animation skill for creating Awwwards/FWA-level animations using GSAP (useGSAP), Motion (Framer Motion), Anime.js, and Lenis. Use when building premium scroll experiences, custom cursors, page transitions, text animations, parallax effects, micro-interactions, or any animation that needs to be 60fps and award-worthy. Triggers on requests for smooth scroll, ScrollTrigger, magnetic effects, reveal animations, horizontal scroll, pin sections, stagger effects, useScroll, useTransform, integration with Three.js/WebGL, algorithmic art, mathematical art, generative art, fractals, L-systems, flow fields, strange attractors, sacred geometry, geometric puzzles, Dudeney dissections, tangram, tessellations, Penrose tiles, kinetic typography, glitch effects, text explosion, morphing text, circular text, brutalist design, minimalist animation, neo-brutalism, or design philosophy mixing. React-first approach with proper cleanup and hooks.
---

# 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)

```bash
# 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)

```tsx
// 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)

```tsx
// 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](references/gsap-react.md)
- **Motion (Framer Motion)**: See [references/motion-patterns.md](references/motion-patterns.md)
- **Anime.js 4.0**: See [references/animejs-react.md](references/animejs-react.md)
- **Lenis React**: See [references/lenis-react.md](references/lenis-react.md)
- **Geometric Shapes**: See [references/geometric-shapes.md](references/geometric-shapes.md) (SVG, Canvas, Zdog, p5.js, Tetris-style)
- **Audio Reactive**: See [references/audio-reactive.md](references/audio-reactive.md) (Tone.js, Web Audio, scroll audio)
- **Physics 2D**: See [references/physics-2d.md](references/physics-2d.md) (Matter.js, collisions, constraints)
- **Advanced (Three.js, WebGL)**: See [references/advanced-patterns.md](references/advanced-patterns.md)
- **Algorithmic & Generative Art**: See [references/algorithmic-art.md](references/algorithmic-art.md) (fractals, L-systems, flow fields, attractors, noise, sacred geometry)
- **Advanced Text Effects**: See [references/text-effects.md](references/text-effects.md) (glitch, kinetic typography, morphing, explosion, circular text, scramble)
- **Geometric Puzzles**: See [references/geometric-puzzles.md](references/geometric-puzzles.md) (Dudeney, tangram, tessellations, Penrose, polyominoes)
- **Design Philosophy**: See [references/design-philosophy.md](references/design-philosophy.md) (brutalist, minimalist, abstract, mixing styles, palettes)
- **Performance**: See [references/performance.md](references/performance.md)

## Quick Patterns (React)

### 1. Magnetic Cursor (GSAP + useGSAP)

```tsx
'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)

```tsx
'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)

```tsx
'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)

```tsx
'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)

```tsx
'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)

```tsx
'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)

```tsx
'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](references/algorithmic-art.md) for L-systems, flow fields, attractors, noise, sacred geometry.

### 8. Geometric Dissection (SVG + GSAP)

```tsx
'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](references/geometric-puzzles.md) for tangram, tessellations, Penrose tiles, polyominoes.

### 9. Brutalist Grid (Motion)

```tsx
'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](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

```tsx
// Motion: useReducedMotion() → conditionally disable/reduce animations
import { useReducedMotion } from 'motion/react'
const reduced = useReducedMotion() // true if prefers-reduced-motion: reduce
```

```css
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
}
```

## Performance Rules

1. Only animate `transform` and `opacity`
2. Use `will-change` sparingly
3. Always cleanup: `useGSAP` handles it automatically
4. Scope GSAP selectors to container refs
5. Use `contextSafe()` for event handlers with GSAP
6. Memoize Motion variants objects

## Common Pitfalls

1. Not integrating Lenis with ScrollTrigger
2. Missing `scope` in useGSAP
3. Not using `contextSafe()` for click handlers
4. React 18 Strict Mode calling effects twice
5. Forgetting `'use client'` in Next.js App Router
6. 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

Source

Creator's repository · devmartinese/awwwards-animations-skill

View on GitHub

Security

Security checks in progress
Results will appear here once audits complete
What this skill can do
Reads your filesConnects to the internetRuns code on your machine
Checked by 3 independent security firms
Does it try to trick the AI?Not yet checkedPending · Gen Agent Trust Hub
Does it sneak in hidden code?Not yet checkedPending · Socket
Does it have known bugs?Not yet checkedPending · Snyk