Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | 1x 1x 1x 1x | 'use client';
import { motion, AnimatePresence } from 'framer-motion';
import { usePathname } from 'next/navigation';
import { ReactNode, useEffect } from 'react';
/**
* High-performance page transition wrapper
* Uses only GPU-accelerated properties for stable 60fps
* Features:
* - Subtle fade + micro-scale animation
* - Professional ease-out curve
* - Smooth scroll reset on page change
* - GPU-accelerated for consistent 60fps
*/
export function PageTransition({ children }: { children: ReactNode }) {
const pathname = usePathname();
// Smooth scroll to top on page change
useEffect(() => {
window.scrollTo({ top: 0, behavior: 'instant' });
}, [pathname]);
return (
<AnimatePresence mode="wait" initial={false}>
<motion.div
key={pathname}
initial={{
opacity: 0.9,
}}
animate={{
opacity: 1,
}}
exit={{
opacity: 0.9,
}}
transition={{
duration: 0.18,
ease: 'easeOut',
}}
style={{
willChange: 'opacity',
}}
className="relative"
>
{children}
{/* Subtle overlay for extra polish - barely visible but adds depth */}
<motion.div
initial={{ opacity: 0.04 }}
animate={{ opacity: 0 }}
transition={{ duration: 0.2, ease: 'easeOut' }}
className="fixed inset-0 bg-white pointer-events-none z-50"
style={{ willChange: 'opacity' }}
/>
</motion.div>
</AnimatePresence>
);
}
|