FoundryKit

Animation Utilities

Advanced animation utilities and helpers for FoundryKit animations

Animation Utilities

Learn how to use advanced animation utilities and helpers to create complex, performant animations.

Custom Animation Hooks

useAnimationSequence

Create complex animation sequences with precise timing control.

import { useAnimationSequence } from '@foundrykit/animation'
import { useState } from 'react'

function AnimationSequence() {
  const [isVisible, setIsVisible] = useState(false)
  
  const sequence = useAnimationSequence([
    {
      key: 'title',
      animation: 'fadeIn',
      delay: 0,
      duration: 0.6
    },
    {
      key: 'subtitle',
      animation: 'slideUp',
      delay: 0.3,
      duration: 0.5
    },
    {
      key: 'button',
      animation: 'scale',
      delay: 0.6,
      duration: 0.4
    }
  ])

  return (
    <div className="space-y-4">
      <button onClick={() => setIsVisible(!isVisible)}>
        {isVisible ? 'Hide' : 'Show'} Sequence
      </button>
      
      {isVisible && (
        <div className="space-y-4">
          <div className={sequence.title}>
            <h1 className="text-3xl font-bold">Welcome</h1>
          </div>
          
          <div className={sequence.subtitle}>
            <p className="text-lg text-gray-600">This is a subtitle</p>
          </div>
          
          <div className={sequence.button}>
            <button className="px-4 py-2 bg-blue-600 text-white rounded">
              Action Button
            </button>
          </div>
        </div>
      )}
    </div>
  )
}

useStaggeredAnimation

Create staggered animations with custom timing and easing.

import { useStaggeredAnimation } from '@foundrykit/animation'

function StaggeredList() {
  const items = ['Item 1', 'Item 2', 'Item 3', 'Item 4', 'Item 5']
  
  const staggeredProps = useStaggeredAnimation({
    items,
    animation: 'slideUp',
    staggerDelay: 0.1,
    duration: 0.5,
    easing: 'ease-out'
  })

  return (
    <div className="space-y-2">
      {items.map((item, index) => (
        <div key={index} className={staggeredProps[index]}>
          <div className="p-4 bg-gray-100 rounded">
            {item}
          </div>
        </div>
      ))}
    </div>
  )
}

useIntersectionAnimation

Trigger animations when elements come into view.

import { useIntersectionAnimation } from '@foundrykit/animation'

function IntersectionTriggered() {
  const fadeInProps = useIntersectionAnimation({
    animation: 'fadeIn',
    threshold: 0.1,
    duration: 0.6
  })

  const slideUpProps = useIntersectionAnimation({
    animation: 'slideUp',
    threshold: 0.2,
    duration: 0.8
  })

  return (
    <div className="space-y-8">
      <div className={fadeInProps}>
        <h2 className="text-2xl font-bold">Fade In on Scroll</h2>
        <p>This content will fade in when it comes into view.</p>
      </div>
      
      <div className={slideUpProps}>
        <h2 className="text-2xl font-bold">Slide Up on Scroll</h2>
        <p>This content will slide up when it comes into view.</p>
      </div>
    </div>
  )
}

Animation Presets

Predefined Animation Sequences

Use predefined animation sequences for common patterns.

import { animationPresets } from '@foundrykit/animation'

function PresetAnimations() {
  const heroSequence = animationPresets.hero()
  const cardSequence = animationPresets.card()
  const listSequence = animationPresets.list()

  return (
    <div className="space-y-8">
      {/* Hero section with preset */}
      <div className="text-center py-12">
        <div className={heroSequence.title}>
          <h1 className="text-4xl font-bold mb-4">Welcome</h1>
        </div>
        <div className={heroSequence.subtitle}>
          <p className="text-xl text-gray-600 mb-6">Subtitle text</p>
        </div>
        <div className={heroSequence.cta}>
          <button className="px-6 py-3 bg-blue-600 text-white rounded">
            Get Started
          </button>
        </div>
      </div>
      
      {/* Card grid with preset */}
      <div className="grid grid-cols-1 md:grid-cols-3 gap-6">
        {[1, 2, 3].map((index) => (
          <div key={index} className={cardSequence[index - 1]}>
            <div className="p-6 bg-white rounded-lg shadow">
              <h3 className="text-lg font-semibold mb-2">Card {index}</h3>
              <p className="text-gray-600">Card content</p>
            </div>
          </div>
        ))}
      </div>
      
      {/* List with preset */}
      <div className="space-y-2">
        {['Item 1', 'Item 2', 'Item 3'].map((item, index) => (
          <div key={index} className={listSequence[index]}>
            <div className="p-4 bg-gray-100 rounded">
              {item}
            </div>
          </div>
        ))}
      </div>
    </div>
  )
}

Custom Animation Presets

Create your own animation presets for consistent patterns.

import { createAnimationPreset } from '@foundrykit/animation'

// Create a custom preset for dashboard widgets
const dashboardPreset = createAnimationPreset({
  name: 'dashboard',
  animations: [
    {
      key: 'header',
      animation: 'fadeIn',
      delay: 0,
      duration: 0.6
    },
    {
      key: 'widgets',
      animation: 'slideUp',
      staggerDelay: 0.1,
      duration: 0.5
    },
    {
      key: 'sidebar',
      animation: 'slideIn',
      delay: 0.3,
      duration: 0.7
    }
  ]
})

function DashboardWithPreset() {
  const dashboard = dashboardPreset()

  return (
    <div className="flex">
      {/* Sidebar */}
      <div className={dashboard.sidebar}>
        <div className="w-64 bg-gray-100 p-4">
          <h3 className="font-semibold mb-4">Navigation</h3>
          <nav className="space-y-2">
            <a href="#" className="block py-2 px-3 rounded hover:bg-gray-200">Dashboard</a>
            <a href="#" className="block py-2 px-3 rounded hover:bg-gray-200">Analytics</a>
            <a href="#" className="block py-2 px-3 rounded hover:bg-gray-200">Settings</a>
          </nav>
        </div>
      </div>
      
      {/* Main content */}
      <div className="flex-1 p-6">
        <div className={dashboard.header}>
          <h1 className="text-3xl font-bold mb-6">Dashboard</h1>
        </div>
        
        <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
          {[1, 2, 3, 4, 5, 6].map((index) => (
            <div key={index} className={dashboard.widgets[index - 1]}>
              <div className="p-6 bg-white rounded-lg shadow">
                <h3 className="text-lg font-semibold mb-2">Widget {index}</h3>
                <p className="text-gray-600">Widget content</p>
              </div>
            </div>
          ))}
        </div>
      </div>
    </div>
  )
}

Performance Utilities

useAnimationOptimization

Optimize animations for performance and accessibility.

import { useAnimationOptimization } from '@foundrykit/animation'

function OptimizedAnimation() {
  const { shouldAnimate, animationProps } = useAnimationOptimization({
    prefersReducedMotion: true,
    isLowPowerMode: true,
    isMobile: true
  })

  if (!shouldAnimate) {
    return (
      <div className="space-y-4">
        <h1 className="text-3xl font-bold">Welcome</h1>
        <p className="text-lg text-gray-600">Content without animations</p>
        <button className="px-4 py-2 bg-blue-600 text-white rounded">
          Action Button
        </button>
      </div>
    )
  }

  return (
    <div className="space-y-4">
      <div className={animationProps.fadeIn}>
        <h1 className="text-3xl font-bold">Welcome</h1>
      </div>
      
      <div className={animationProps.slideUp}>
        <p className="text-lg text-gray-600">Content with optimized animations</p>
      </div>
      
      <div className={animationProps.scale}>
        <button className="px-4 py-2 bg-blue-600 text-white rounded">
          Action Button
        </button>
      </div>
    </div>
  )
}

useAnimationThrottling

Throttle animations to prevent performance issues.

import { useAnimationThrottling } from '@foundrykit/animation'

function ThrottledAnimation() {
  const { isThrottled, animationProps } = useAnimationThrottling({
    maxAnimations: 3,
    throttleDelay: 100
  })

  const items = ['Item 1', 'Item 2', 'Item 3', 'Item 4', 'Item 5']

  return (
    <div className="space-y-2">
      {items.map((item, index) => (
        <div key={index} className={animationProps[index]}>
          <div className="p-4 bg-gray-100 rounded">
            {item} {isThrottled && '(Throttled)'}
          </div>
        </div>
      ))}
    </div>
  )
}

Advanced Animation Patterns

Conditional Animation Rendering

import { useConditionalAnimation } from '@foundrykit/animation'

function ConditionalAnimation() {
  const [showContent, setShowContent] = useState(false)
  const [animationType, setAnimationType] = useState('fadeIn')

  const animationProps = useConditionalAnimation({
    condition: showContent,
    animation: animationType,
    fallback: 'none'
  })

  return (
    <div className="space-y-4">
      <div className="space-x-4">
        <button onClick={() => setShowContent(!showContent)}>
          {showContent ? 'Hide' : 'Show'} Content
        </button>
        
        <select 
          value={animationType} 
          onChange={(e) => setAnimationType(e.target.value)}
        >
          <option value="fadeIn">Fade In</option>
          <option value="slideUp">Slide Up</option>
          <option value="scale">Scale</option>
        </select>
      </div>
      
      <div className={animationProps}>
        <div className="p-6 bg-green-100 rounded">
          <h3 className="text-lg font-semibold mb-2">Conditional Content</h3>
          <p>This content animates based on the selected animation type.</p>
        </div>
      </div>
    </div>
  )
}

Animation State Management

import { useAnimationState } from '@foundrykit/animation'

function AnimationStateManagement() {
  const { state, setState, animationProps } = useAnimationState({
    initialState: 'idle',
    states: {
      idle: { animation: 'none' },
      loading: { animation: 'fadeIn', duration: 0.3 },
      success: { animation: 'scale', duration: 0.5 },
      error: { animation: 'shake', duration: 0.6 }
    }
  })

  return (
    <div className="space-y-4">
      <div className="space-x-2">
        <button onClick={() => setState('loading')}>Loading</button>
        <button onClick={() => setState('success')}>Success</button>
        <button onClick={() => setState('error')}>Error</button>
        <button onClick={() => setState('idle')}>Reset</button>
      </div>
      
      <div className={animationProps}>
        <div className="p-6 bg-gray-100 rounded">
          <h3 className="text-lg font-semibold mb-2">State: {state}</h3>
          <p>This content animates based on the current state.</p>
        </div>
      </div>
    </div>
  )
}

Animation Debugging

useAnimationDebug

Debug animation performance and timing.

import { useAnimationDebug } from '@foundrykit/animation'

function AnimationDebug() {
  const debugInfo = useAnimationDebug({
    enabled: process.env.NODE_ENV === 'development',
    logPerformance: true,
    logTiming: true
  })

  return (
    <div className="space-y-4">
      <div className="p-4 bg-blue-100 rounded">
        <h3 className="font-semibold mb-2">Animation Debug Info</h3>
        <pre className="text-sm">
          {JSON.stringify(debugInfo, null, 2)}
        </pre>
      </div>
      
      <div className="p-6 bg-white rounded-lg shadow">
        <h2 className="text-2xl font-bold mb-4">Animated Content</h2>
        <p>This content will show debug information in development mode.</p>
      </div>
    </div>
  )
}

Next Steps