'use client' import { useEffect, useRef, useState } from 'react' import { motion, useInView, useAnimation } from 'framer-motion' // Scroll-triggered animation hook export function useScrollAnimation(threshold = 0.1, once = true) { const ref = useRef(null) const isInView = useInView(ref, { threshold, once }) const controls = useAnimation() useEffect(() => { if (isInView) { controls.start('visible') } }, [isInView, controls]) return { ref, controls } } // Fade up animation component export function FadeUp({ children, delay = 0, className = '' }: { children: React.ReactNode delay?: number className?: string }) { const { ref, controls } = useScrollAnimation() return ( {children} ) } // Stagger children animation export function StaggerContainer({ children, className = '', staggerDelay = 0.1 }: { children: React.ReactNode className?: string staggerDelay?: number }) { const { ref, controls } = useScrollAnimation() return ( {children} ) } // Individual stagger item export function StaggerItem({ children, className = '' }: { children: React.ReactNode className?: string }) { return ( {children} ) } // Scale in animation export function ScaleIn({ children, delay = 0, className = '' }: { children: React.ReactNode delay?: number className?: string }) { const { ref, controls } = useScrollAnimation() return ( {children} ) } // Slide in from left export function SlideInLeft({ children, delay = 0, className = '' }: { children: React.ReactNode delay?: number className?: string }) { const { ref, controls } = useScrollAnimation() return ( {children} ) } // Slide in from right export function SlideInRight({ children, delay = 0, className = '' }: { children: React.ReactNode delay?: number className?: string }) { const { ref, controls } = useScrollAnimation() return ( {children} ) } // Hover card with micro-interactions export function HoverCard({ children, className = '' }: { children: React.ReactNode className?: string }) { return ( {children} ) } // Magnetic button effect export function MagneticButton({ children, className = '', strength = 0.3 }: { children: React.ReactNode className?: string strength?: number }) { const ref = useRef(null) const handleMouseMove = (e: React.MouseEvent) => { if (!ref.current) return const rect = ref.current.getBoundingClientRect() const x = e.clientX - rect.left - rect.width / 2 const y = e.clientY - rect.top - rect.height / 2 ref.current.style.transform = `translate(${x * strength}px, ${y * strength}px)` } const handleMouseLeave = () => { if (!ref.current) return ref.current.style.transform = 'translate(0px, 0px)' } return ( {children} ) } // Counter animation export function CountUp({ end, duration = 2, suffix = '' }: { end: number duration?: number suffix?: string }) { const ref = useRef(null) const isInView = useInView(ref, { threshold: 0.1, once: true }) const [count, setCount] = useState(0) useEffect(() => { if (!isInView) return let startTime: number let animationFrame: number const animate = (timestamp: number) => { if (!startTime) startTime = timestamp const progress = Math.min((timestamp - startTime) / (duration * 1000), 1) setCount(Math.floor(progress * end)) if (progress < 1) { animationFrame = requestAnimationFrame(animate) } } animationFrame = requestAnimationFrame(animate) return () => { if (animationFrame) { cancelAnimationFrame(animationFrame) } } }, [isInView, end, duration]) return ( {count}{suffix} ) } // Parallax effect export function ParallaxElement({ children, speed = 0.5, className = '' }: { children: React.ReactNode speed?: number className?: string }) { const ref = useRef(null) useEffect(() => { const element = ref.current if (!element) return const handleScroll = () => { const scrolled = window.pageYOffset const rect = element.getBoundingClientRect() const elementTop = rect.top + scrolled const elementHeight = rect.height const windowHeight = window.innerHeight if (scrolled + windowHeight > elementTop && scrolled < elementTop + elementHeight) { const yPos = -(scrolled - elementTop) * speed element.style.transform = `translateY(${yPos}px)` } } let ticking = false const throttledScroll = () => { if (!ticking) { requestAnimationFrame(() => { handleScroll() ticking = false }) ticking = true } } window.addEventListener('scroll', throttledScroll, { passive: true }) return () => window.removeEventListener('scroll', throttledScroll) }, [speed]) return (
{children}
) }