FoundryKit

Performance Guidelines

Performance optimization guidelines for FoundryKit animations

Performance Guidelines

Learn how to optimize FoundryKit animations for maximum performance and smooth user experiences.

Animation Performance Best Practices

Use Transform-Based Animations

Prefer transform animations over layout-triggering properties for better performance.

import { FadeIn, SlideUp, Scale } from '@foundrykit/animation'

function OptimizedAnimations() {
  return (
    <div className="space-y-4">
      {/* ✅ Good - Transform-based animations */}
      <FadeIn>
        <div className="p-4 bg-blue-100 rounded">Fade In (opacity transform)</div>
      </FadeIn>
      
      <SlideUp>
        <div className="p-4 bg-green-100 rounded">Slide Up (transform: translateY)</div>
      </SlideUp>
      
      <Scale>
        <div className="p-4 bg-purple-100 rounded">Scale (transform: scale)</div>
      </Scale>
    </div>
  )
}

// ❌ Avoid - Layout-triggering animations
function AvoidLayoutAnimations() {
  return (
    <div className="space-y-4">
      {/* These trigger layout recalculations */}
      <div className="animate-width">Width animation</div>
      <div className="animate-height">Height animation</div>
      <div className="animate-margin">Margin animation</div>
    </div>
  )
}

Optimize Animation Timing

Use appropriate durations and delays to maintain smooth performance.

import { FadeIn, SlideUp } from '@foundrykit/animation'

function OptimizedTiming() {
  return (
    <div className="space-y-4">
      {/* Fast animations for immediate feedback */}
      <FadeIn duration={0.2}>
        <button className="px-4 py-2 bg-blue-600 text-white rounded">
          Quick Response
        </button>
      </FadeIn>
      
      {/* Medium animations for content transitions */}
      <SlideUp duration={0.4} delay={0.1}>
        <div className="p-4 bg-gray-100 rounded">
          Content transition
        </div>
      </SlideUp>
      
      {/* Longer animations for dramatic effects */}
      <FadeIn duration={0.8} delay={0.3}>
        <div className="p-6 bg-white rounded-lg shadow">
          Hero content
        </div>
      </FadeIn>
    </div>
  )
}

Memory Management

Cleanup Animations on Unmount

Ensure animations are properly cleaned up to prevent memory leaks.

import { FadeIn } from '@foundrykit/animation'
import { useState, useEffect } from 'react'

function CleanupExample() {
  const [isVisible, setIsVisible] = useState(true)

  useEffect(() => {
    const timer = setTimeout(() => {
      setIsVisible(false)
    }, 5000)

    return () => {
      clearTimeout(timer)
      // Framer Motion automatically cleans up animations
    }
  }, [])

  if (!isVisible) {
    return null
  }

  return (
    <FadeIn>
      <div className="p-4 bg-yellow-100 rounded">
        This will be cleaned up after 5 seconds
      </div>
    </FadeIn>
  )
}

Limit Concurrent Animations

Avoid running too many animations simultaneously to prevent performance issues.

import { Stagger } from '@foundrykit/animation'

function LimitedConcurrentAnimations() {
  const items = Array.from({ length: 20 }, (_, i) => `Item ${i + 1}`)

  return (
    <div className="space-y-2">
      {/* Limit visible animations */}
      <Stagger 
        animation="slideUp" 
        staggerDelay={0.05} // Faster stagger for better performance
        maxVisible={10 // Only animate visible items
      >
        {items.map((item, index) => (
          <div key={index} className="p-2 bg-gray-100 rounded">
            {item}
          </div>
        ))}
      </Stagger>
    </div>
  )
}

Accessibility and Performance

Respect Reduced Motion Preferences

Always respect user preferences for reduced motion.

import { FadeIn, SlideUp } from '@foundrykit/animation'
import { useMediaQuery } from '@foundrykit/hooks'

function AccessibleAnimations() {
  const prefersReducedMotion = useMediaQuery('(prefers-reduced-motion: reduce)')

  if (prefersReducedMotion) {
    return (
      <div className="space-y-4">
        {/* No animations for users who prefer reduced motion */}
        <div className="p-4 bg-blue-100 rounded">
          <h2 className="text-xl font-bold">Welcome</h2>
          <p>Content without animations</p>
        </div>
      </div>
    )
  }

  return (
    <div className="space-y-4">
      <FadeIn>
        <div className="p-4 bg-blue-100 rounded">
          <h2 className="text-xl font-bold">Welcome</h2>
          <p>Content with animations</p>
        </div>
      </FadeIn>
    </div>
  )
}

Optimize for Low-Power Devices

Detect and adapt to low-power devices.

import { FadeIn, SlideUp } from '@foundrykit/animation'
import { useMediaQuery } from '@foundrykit/hooks'

function LowPowerOptimized() {
  const isLowPower = useMediaQuery('(prefers-reduced-motion: reduce)')
  const isMobile = useMediaQuery('(max-width: 768px)')

  // Use simpler animations on low-power devices
  const animationProps = {
    duration: isLowPower || isMobile ? 0.3 : 0.6,
    easing: isLowPower ? 'linear' : 'ease-out'
  }

  return (
    <div className="space-y-4">
      <FadeIn {...animationProps}>
        <div className="p-4 bg-green-100 rounded">
          Optimized for your device
        </div>
      </FadeIn>
      
      <SlideUp {...animationProps}>
        <div className="p-4 bg-blue-100 rounded">
          Smooth performance
        </div>
      </SlideUp>
    </div>
  )
}

Performance Monitoring

Track Animation Performance

Monitor animation performance in development.

import { FadeIn } from '@foundrykit/animation'
import { useEffect, useRef } from 'react'

function PerformanceTrackedAnimation() {
  const startTimeRef = useRef(performance.now())
  const animationRef = useRef(null)

  useEffect(() => {
    const endTime = performance.now()
    const duration = endTime - startTimeRef.current

    if (process.env.NODE_ENV === 'development') {
      console.log(`Animation completed in ${duration.toFixed(2)}ms`)
      
      // Warn if animation takes too long
      if (duration > 100) {
        console.warn('Animation may be causing performance issues')
      }
    }
  }, [])

  return (
    <FadeIn ref={animationRef}>
      <div className="p-4 bg-purple-100 rounded">
        Performance tracked animation
      </div>
    </FadeIn>
  )
}

Monitor Frame Rate

Check for animation frame drops.

import { useEffect, useRef } from 'react'

function useFrameRateMonitor() {
  const frameCountRef = useRef(0)
  const lastTimeRef = useRef(performance.now())

  useEffect(() => {
    const checkFrameRate = () => {
      frameCountRef.current++
      const currentTime = performance.now()
      
      if (currentTime - lastTimeRef.current >= 1000) {
        const fps = Math.round((frameCountRef.current * 1000) / (currentTime - lastTimeRef.current))
        
        if (process.env.NODE_ENV === 'development') {
          console.log(`Current FPS: ${fps}`)
          
          if (fps < 30) {
            console.warn('Low frame rate detected. Consider reducing animations.')
          }
        }
        
        frameCountRef.current = 0
        lastTimeRef.current = currentTime
      }
      
      requestAnimationFrame(checkFrameRate)
    }

    const animationId = requestAnimationFrame(checkFrameRate)
    
    return () => cancelAnimationFrame(animationId)
  }, [])
}

function MonitoredAnimations() {
  useFrameRateMonitor()

  return (
    <div className="space-y-4">
      <FadeIn>
        <div className="p-4 bg-red-100 rounded">Monitored animation</div>
      </FadeIn>
    </div>
  )
}

Optimization Techniques

Use CSS Containment

Improve performance with CSS containment.

import { FadeIn, Stagger } from '@foundrykit/animation'

function ContainedAnimations() {
  return (
    <div className="contain-layout contain-paint">
      <FadeIn>
        <div className="p-4 bg-blue-100 rounded">
          Contained animation
        </div>
      </FadeIn>
      
      <Stagger>
        <div className="space-y-2">
          {[1, 2, 3].map(i => (
            <div key={i} className="p-2 bg-gray-100 rounded">
              Item {i}
            </div>
          ))}
        </div>
      </Stagger>
    </div>
  )
}

Optimize for GPU

Use GPU-accelerated properties for better performance.

import { FadeIn, SlideUp } from '@foundrykit/animation'

function GPUOptimized() {
  return (
    <div className="space-y-4">
      {/* These animations use GPU-accelerated properties */}
      <FadeIn>
        <div className="p-4 bg-green-100 rounded will-change-opacity">
          GPU-accelerated fade
        </div>
      </FadeIn>
      
      <SlideUp>
        <div className="p-4 bg-blue-100 rounded will-change-transform">
          GPU-accelerated slide
        </div>
      </SlideUp>
    </div>
  )
}

Lazy Load Animations

Load animations only when needed.

import { lazy, Suspense } from 'react'
import { FadeIn } from '@foundrykit/animation'

const LazyAnimatedComponent = lazy(() => 
  import('./LazyAnimatedComponent').then(m => ({ default: m.LazyAnimatedComponent }))
)

function LazyLoadedAnimations() {
  const [showLazy, setShowLazy] = useState(false)

  return (
    <div className="space-y-4">
      <FadeIn>
        <div className="p-4 bg-yellow-100 rounded">
          Immediate animation
        </div>
      </FadeIn>
      
      <button onClick={() => setShowLazy(true)}>
        Load Lazy Animation
      </button>
      
      {showLazy && (
        <Suspense fallback={<div className="p-4 bg-gray-100 rounded">Loading...</div>}>
          <LazyAnimatedComponent />
        </Suspense>
      )}
    </div>
  )
}

Performance Checklist

Before Production

  • Test animations on low-end devices
  • Verify reduced motion preferences are respected
  • Check for memory leaks in long-running animations
  • Monitor frame rate during complex animations
  • Optimize animation timing for smooth performance
  • Use transform-based animations instead of layout-triggering ones
  • Limit concurrent animations to prevent performance issues
  • Implement proper cleanup for unmounted components

Performance Metrics

  • Target FPS: 60 FPS for smooth animations
  • Animation Duration: 200-600ms for most interactions
  • Stagger Delay: 50-150ms between staggered items
  • Memory Usage: Monitor for leaks in long-running animations
  • Layout Thrashing: Avoid multiple layout recalculations

Next Steps