# Design Document: Premium Animations ## Overview Este documento detalha o design técnico para implementar animações premium no portfolio evandro.dev.br, inspiradas no estilo suave e elegante do site on.energy. O sistema de animações será construído sobre Framer Motion e Lenis, mantendo a identidade visual existente (cores, tipografia Monument Extended, paleta --slash #ccff00) enquanto adiciona transições fluidas, scroll-triggered animations, parallax sutil e animações de hover sofisticadas. ### Objetivos Principais 1. Elevar a experiência visual com animações premium e fluidas 2. Manter performance consistente (60fps) em todos os dispositivos 3. Garantir acessibilidade completa com suporte a prefers-reduced-motion 4. Criar um sistema de animações reutilizável e escalável 5. Integrar smooth scroll global com Lenis 6. Implementar interações sofisticadas (magnetic buttons, custom cursor) ### Princípios de Design - **Performance First**: Usar apenas propriedades GPU-accelerated (transform, opacity) - **Accessibility First**: Respeitar prefers-reduced-motion em todas as animações - **Progressive Enhancement**: Funcionalidade básica sem JavaScript, animações como enhancement - **Consistency**: Usar curvas de easing e durações consistentes em todo o sistema - **Subtlety**: Animações devem ser elegantes e discretas, não distrativas ## Architecture ### System Overview O sistema de animações será organizado em camadas modulares: ``` Animation System ├── Core Layer (Hooks & Utilities) │ ├── useScrollTrigger - Detecta elementos no viewport │ ├── useParallax - Aplica efeitos parallax │ ├── useReducedMotion - Detecta preferências de acessibilidade │ ├── useMagneticEffect - Implementa efeito magnético │ └── animationConfig - Configurações centralizadas │ ├── Component Layer (Wrappers Reutilizáveis) │ ├── ScrollReveal - Wrapper para scroll-triggered animations │ ├── StaggerContainer - Container para stagger animations │ ├── ParallaxElement - Wrapper para parallax effects │ ├── PageTransition - Transições entre páginas │ ├── ImageReveal - Reveal animado para imagens │ ├── TextReveal - Reveal animado para textos │ └── CustomCursor - Cursor customizado │ ├── Integration Layer (Providers & Context) │ ├── LenisProvider - Smooth scroll global │ ├── AnimationProvider - Context para configurações │ └── CursorProvider - Context para cursor customizado │ └── Enhancement Layer (Micro-interactions) ├── Card hover effects ├── Button hover effects ├── Form field interactions └── Loading states ``` ### Technology Stack - **Framer Motion 12.23.12**: Biblioteca principal de animações - **Lenis 1.3.18**: Smooth scroll library - **React 19.1.0**: Framework base - **Next.js 15.5.9**: App Router para routing - **TypeScript**: Type safety - **Tailwind CSS 4**: Styling utilities ### Integration Points 1. **App Layout**: LenisProvider e AnimationProvider no root layout 2. **Page Components**: PageTransition wrapper em cada página 3. **Section Components**: ScrollReveal wrapper em seções principais 4. **Card Components**: Hover effects e stagger animations 5. **Form Components**: Micro-interactions em campos 6. **Hero Component**: Remoção da fase logo, manutenção de typing animation ## Components and Interfaces ### Core Hooks #### useScrollTrigger Hook para detectar quando elementos entram no viewport e disparar animações. ```typescript interface UseScrollTriggerOptions { threshold?: number; // Porcentagem do elemento visível (default: 0.2) once?: boolean; // Executar apenas uma vez (default: true) margin?: string; // Margin do viewport (default: "0px") } interface UseScrollTriggerReturn { ref: RefObject; isInView: boolean; entry: IntersectionObserverEntry | null; } function useScrollTrigger(options?: UseScrollTriggerOptions): UseScrollTriggerReturn ``` **Implementação**: Wrapper sobre `useInView` do Framer Motion com configurações otimizadas. #### useParallax Hook para aplicar efeitos parallax em elementos durante o scroll. ```typescript interface UseParallaxOptions { speed?: number; // Velocidade do parallax (default: 0.5 = 50% mais lento) direction?: "vertical" | "horizontal"; // Direção do movimento (default: "vertical") disabled?: boolean; // Desabilitar parallax (usado com reduced motion) } interface UseParallaxReturn { ref: RefObject; style: MotionStyle; } function useParallax(options?: UseParallaxOptions): UseParallaxReturn ``` **Implementação**: Usa `useScroll` e `useTransform` do Framer Motion para calcular posição baseada no scroll. #### useReducedMotion Hook para detectar preferência de movimento reduzido do usuário. ```typescript function useReducedMotion(): boolean ``` **Implementação**: Wrapper sobre `useReducedMotion` do Framer Motion, retorna `true` se `prefers-reduced-motion: reduce` está ativo. #### useMagneticEffect Hook para implementar efeito magnético em botões. ```typescript interface UseMagneticEffectOptions { radius?: number; // Raio de influência em pixels (default: 80) strength?: number; // Força do efeito, max movement em pixels (default: 12) disabled?: boolean; // Desabilitar efeito (usado com reduced motion) } interface UseMagneticEffectReturn { ref: RefObject; style: MotionStyle; } function useMagneticEffect(options?: UseMagneticEffectOptions): UseMagneticEffectReturn ``` **Implementação**: Rastreia posição do mouse, calcula distância ao elemento, aplica transform proporcional com spring physics. ### Component Wrappers #### ScrollReveal Componente wrapper para aplicar scroll-triggered animations. ```typescript interface ScrollRevealProps { children: React.ReactNode; direction?: "up" | "down" | "left" | "right"; // Direção do slide (default: "up") distance?: number; // Distância do movimento em pixels (default: 24) duration?: number; // Duração da animação em segundos (default: 0.6) delay?: number; // Delay antes da animação (default: 0) threshold?: number; // Threshold do viewport (default: 0.2) once?: boolean; // Executar apenas uma vez (default: true) className?: string; } function ScrollReveal(props: ScrollRevealProps): JSX.Element ``` **Comportamento**: - Normal: fade in + slide na direção especificada com blur inicial - Reduced Motion: apenas fade in simples, sem movimento ou blur #### StaggerContainer Container para aplicar stagger animations em elementos filhos. ```typescript interface StaggerContainerProps { children: React.ReactNode; staggerDelay?: number; // Delay entre elementos em segundos (default: 0.08) initialDelay?: number; // Delay inicial antes do primeiro elemento (default: 0) className?: string; } function StaggerContainer(props: StaggerContainerProps): JSX.Element ``` **Implementação**: Usa `motion.div` com `variants` para aplicar stagger automático aos filhos. #### ParallaxElement Wrapper para aplicar parallax effect em elementos. ```typescript interface ParallaxElementProps { children: React.ReactNode; speed?: number; // Velocidade do parallax (default: 0.5) direction?: "vertical" | "horizontal"; className?: string; } function ParallaxElement(props: ParallaxElementProps): JSX.Element ``` **Comportamento**: - Normal: movimento parallax suave - Reduced Motion: sem movimento, elemento estático #### PageTransition Wrapper para transições entre páginas. ```typescript interface PageTransitionProps { children: React.ReactNode; } function PageTransition(props: PageTransitionProps): JSX.Element ``` **Comportamento**: - Normal: fade in de 0.4s com ease-out - Reduced Motion: fade in de 0.15s #### ImageReveal Componente para reveal animado de imagens. ```typescript interface ImageRevealProps { src: string; alt: string; width?: number; height?: number; className?: string; priority?: boolean; } function ImageReveal(props: ImageRevealProps): JSX.Element ``` **Comportamento**: - Normal: clip-path reveal + fade in + scale (0.98 → 1) + blur (8px → 0px), duração 0.9s - Reduced Motion: apenas fade in simples #### TextReveal Componente para reveal animado de textos por palavra. ```typescript interface TextRevealProps { text: string; as?: "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "p" | "span"; // Tag HTML (default: "p") staggerDelay?: number; // Delay entre palavras (default: 0.04) className?: string; } function TextReveal(props: TextRevealProps): JSX.Element ``` **Comportamento**: - Normal: cada palavra com blur (6px → 0px) + scale (0.95 → 1) + clip-path slide horizontal - Reduced Motion: texto completo com fade in simples #### CustomCursor Componente para cursor customizado. ```typescript interface CustomCursorProps { size?: number; // Tamanho base do cursor (default: 40) expandedSize?: number; // Tamanho expandido (default: 60) color?: string; // Cor do cursor (default: "var(--slash)") } function CustomCursor(props: CustomCursorProps): JSX.Element ``` **Comportamento**: - Desktop: cursor customizado com smooth delay, expande sobre interativos - Touch devices: cursor padrão do sistema - Reduced Motion: cursor padrão do sistema ### Providers #### LenisProvider Provider para smooth scroll global. ```typescript interface LenisProviderProps { children: React.ReactNode; options?: { duration?: number; // Duração do smooth scroll (default: 1.2) easing?: number[]; // Curva de easing (default: [0.25, 0.0, 0.35, 1.0]) smoothWheel?: boolean; // Smooth wheel scroll (default: true) smoothTouch?: boolean; // Smooth touch scroll (default: false) }; } function LenisProvider(props: LenisProviderProps): JSX.Element ``` **Implementação**: Inicializa Lenis, sincroniza com RAF, fornece instância via context. #### AnimationProvider Provider para configurações globais de animação. ```typescript interface AnimationConfig { reducedMotion: boolean; easings: { easeOut: string; easeIn: string; spring: { stiffness: number; damping: number }; }; durations: { fast: number; normal: number; slow: number; }; } interface AnimationProviderProps { children: React.ReactNode; } function AnimationProvider(props: AnimationProviderProps): JSX.Element function useAnimationConfig(): AnimationConfig ``` **Implementação**: Detecta reduced motion, fornece configurações centralizadas via context. #### CursorProvider Provider para cursor customizado. ```typescript interface CursorProviderProps { children: React.ReactNode; } function CursorProvider(props: CursorProviderProps): JSX.Element function useCursor(): { setExpanded: (expanded: boolean) => void; setColor: (color: string) => void; } ``` **Implementação**: Gerencia estado do cursor, fornece métodos para controle via context. ## Data Models ### Animation Configuration Configurações centralizadas para todas as animações. ```typescript export const animationConfig = { // Easing curves easings: { easeOut: "cubic-bezier(0.16, 1, 0.3, 1)", easeIn: "cubic-bezier(0.4, 0, 1, 1)", spring: { default: { stiffness: 200, damping: 20 }, hover: { stiffness: 260, damping: 20 }, magnetic: { stiffness: 150, damping: 15 }, gentle: { stiffness: 60, damping: 20 }, }, }, // Durations (in seconds) durations: { instant: 0.15, fast: 0.3, normal: 0.6, slow: 0.9, verySlow: 1.2, }, // Scroll trigger scrollTrigger: { threshold: 0.2, once: true, margin: "0px", }, // Stagger stagger: { default: 0.08, fast: 0.04, slow: 0.12, reducedMotion: 0.03, }, // Parallax parallax: { speed: 0.5, // 50% mais lento que scroll normal maxDistance: 100, // pixels }, // Magnetic effect magnetic: { radius: 80, // pixels strength: 12, // max movement in pixels }, // Cursor cursor: { size: 40, expandedSize: 60, followDelay: 0.1, }, // Reduced motion overrides reducedMotion: { duration: 0.15, stagger: 0.03, disableParallax: true, disableMagnetic: true, disableCursor: true, }, } as const; ``` ### Variant Presets Presets de variants do Framer Motion para animações comuns. ```typescript export const variants = { // Fade in fadeIn: { initial: { opacity: 0 }, animate: { opacity: 1 }, exit: { opacity: 0 }, }, // Fade in + slide up fadeInUp: { initial: { opacity: 0, y: 24, filter: "blur(8px)" }, animate: { opacity: 1, y: 0, filter: "blur(0px)" }, exit: { opacity: 0, y: -24, filter: "blur(8px)" }, }, // Fade in + slide down fadeInDown: { initial: { opacity: 0, y: -24, filter: "blur(8px)" }, animate: { opacity: 1, y: 0, filter: "blur(0px)" }, exit: { opacity: 0, y: 24, filter: "blur(8px)" }, }, // Fade in + slide left fadeInLeft: { initial: { opacity: 0, x: 24, filter: "blur(8px)" }, animate: { opacity: 1, x: 0, filter: "blur(0px)" }, exit: { opacity: 0, x: -24, filter: "blur(8px)" }, }, // Fade in + slide right fadeInRight: { initial: { opacity: 0, x: -24, filter: "blur(8px)" }, animate: { opacity: 1, x: 0, filter: "blur(0px)" }, exit: { opacity: 0, x: 24, filter: "blur(8px)" }, }, // Scale in scaleIn: { initial: { opacity: 0, scale: 0.95 }, animate: { opacity: 1, scale: 1 }, exit: { opacity: 0, scale: 0.95 }, }, // Image reveal imageReveal: { initial: { opacity: 0, scale: 0.98, filter: "blur(8px)", clipPath: "inset(0 100% 0 0)", }, animate: { opacity: 1, scale: 1, filter: "blur(0px)", clipPath: "inset(0 0% 0 0)", }, }, // Text reveal (per word) textReveal: { initial: { opacity: 0, scale: 0.95, filter: "blur(6px)", clipPath: "inset(0 100% 0 0)", }, animate: { opacity: 1, scale: 1, filter: "blur(0px)", clipPath: "inset(0 0% 0 0)", }, }, // Stagger container staggerContainer: { animate: { transition: { staggerChildren: 0.08, }, }, }, // Reduced motion variants reducedMotion: { fadeIn: { initial: { opacity: 0 }, animate: { opacity: 1 }, exit: { opacity: 0 }, }, }, } as const; ```