Arquitecto de Sistemas de Animación
Construye sistemas de animación accesibles y de alto rendimiento usando Framer Motion, GSAP, la View Transitions API y física de resortes para experiencias de interfaz fluidas.
Disparadores de Activación
Actívalo en: transiciones de página, animaciones de layout, animaciones activadas por scroll, micro-interacciones, física de resortes, motion.div, gsap.to, View Transition API, transiciones de elementos compartidos, animaciones de listas escalonadas.
NO para: efectos hover/focus solo con CSS — usa css-in-js-architect. Renderizado Canvas/WebGL — usa creative-coding-expert. Reproducción de archivos Lottie — usa integración Lottie estándar.
Inicio Rápido
- Elige tu motor — Framer Motion para React declarativo, GSAP para uso intensivo de líneas de tiempo o fuera de React, View Transitions API para navegación entre páginas.
- Anima solo transformaciones y opacidad — se ejecutan en el hilo del compositor (GPU), evitando cambios de diseño.
- Usa
will-changecon moderación — solo en elementos a punto de animarse, elimínalo al finalizar. - Respeta
prefers-reduced-motion— desactiva o simplifica todas las animaciones para usuarios que lo soliciten. - Perfila con DevTools — Panel Rendimiento > verifica si hay cambios de diseño durante las animaciones.
Capacidades Principales
| Dominio | Tecnologías | Patrones Clave |
|---|---|---|
| React Declarativo | Framer Motion 11+, componentes motion | Animaciones de layout, AnimatePresence, variantes |
| Animación con Línea de Tiempo | GSAP 3.12+, ScrollTrigger | Secuencias controladas por scroll, fijación, scrubbing |
| Transiciones de Página | View Transitions API, useViewTransition de Next.js | Transiciones de elementos compartidos entre páginas |
| Física de Resortes | Resortes de Framer Motion, react-spring | Easing natural, animaciones interrumpibles |
| Micro-interacciones | Transiciones CSS + Framer Motion | Feedback de botones, estados hover, indicadores de carga |
| Controladas por Scroll | CSS animation-timeline: scroll(), GSAP ScrollTrigger | Paralaje, indicadores de progreso, revelar al hacer scroll |
Patrones Arquitectónicos
Patrón 1: Animaciones de Layout con Framer Motion
import { motion, AnimatePresence, LayoutGroup } from 'framer-motion';
function FilterableGrid({ items, filter }: Props) {
const filtered = items.filter(item => item.category === filter);
return (
<LayoutGroup>
<motion.div layout className="grid grid-cols-3 gap-4">
<AnimatePresence mode="popLayout">
{filtered.map(item => (
<motion.div
key={item.id}
layout // anima cambios de posición
initial={{ opacity: 0, scale: 0.8 }}
animate={{ opacity: 1, scale: 1 }}
exit={{ opacity: 0, scale: 0.8 }}
transition={{ type: 'spring', stiffness: 300, damping: 25 }}
>
<Card item={item} />
</motion.div>
))}
</AnimatePresence>
</motion.div>
</LayoutGroup>
);
}
Patrón 2: View Transitions API para Navegación entre Páginas
// app/components/TransitionLink.tsx
'use client';
import { useRouter } from 'next/navigation';
import { useCallback } from 'react';
export function TransitionLink({ href, children }: { href: string; children: React.ReactNode }) {
const router = useRouter();
const handleClick = useCallback((e: React.MouseEvent) => {
e.preventDefault();
if (!document.startViewTransition) {
router.push(href);
return;
}
document.startViewTransition(() => {
router.push(href);
});
}, [href, router]);
return <a href={href} onClick={handleClick}>{children}</a>;
}
/* Transiciones de elementos compartidos mediante view-transition-name */
.product-image {
view-transition-name: product-hero;
}
::view-transition-old(product-hero) {
animation: fade-and-scale 0.3s ease-out;
}
::view-transition-new(product-hero) {
animation: fade-and-scale 0.3s ease-in reverse;
}
Patrón 3: Respeto del Movimiento Reducido
import { useReducedMotion } from 'framer-motion';
function AnimatedComponent() {
const shouldReduce = useReducedMotion();
return (
<motion.div
initial={{ opacity: 0, y: shouldReduce ? 0 : 20 }}
animate={{ opacity: 1, y: 0 }}
transition={shouldReduce
? { duration: 0 }
: { type: 'spring', stiffness: 260, damping: 20 }
}
>
Contenido
</motion.div>
);
}
┌─ Árbol de Decisión de Animación ────────────────┐
│ │
│ ¿prefers-reduced-motion? │
│ ├── SÍ → solo fundido instantáneo (sin movimiento)│
│ └── NO → animación completa con resortes/transform│
│ │
│ ¿Qué se anima? │
│ ├── transform/opacity → compositor GPU (bien) │
│ ├── width/height → cambio de diseño (evitar) │
│ └── box-shadow → solo pintura (aceptable) │
└───────────────────────────────────────────────────┘
Antipatrones
- Animar
width,height,top,left— provoca recálculo de diseño en cada fotograma. Usatransform: translate/scalepara lograr 60fps. will-changeen cada elemento — promueve demasiadas capas a la GPU, aumentando el uso de memoria. Aplica solo a elementos a punto de animarse.- Ignorar
prefers-reduced-motion— los usuarios sensibles al movimiento pueden experimentar náuseas o convulsiones. Siempre verifica y respeta esta consulta de medios. - Duración de animación > 500ms para micro-interacciones — hace que la interfaz se sienta lenta. Mantén el feedback de botones/hover por debajo de 200ms, y las transiciones de página por debajo de 400ms.
- Animar durante el scroll sin
requestAnimationFrameo ScrollTrigger — causa tirones. Usa GSAP ScrollTrigger o CSSanimation-timeline: scroll()para animaciones controladas por scroll.
Lista de Verificación de Calidad
- Todas las animaciones usan
transformyopacity(propiedades amigables para el compositor) -
prefers-reduced-motionrespetado medianteuseReducedMotiono consulta de medios CSS - Micro-interacciones por debajo de 200ms, transiciones de página por debajo de 400ms
-
AnimatePresenceusado para animaciones de montaje/desmontaje - Las animaciones de layout usan la propiedad
layoutde Framer Motion (no cálculo manual de posición) -
will-changeaplicado solo durante la animación, eliminado después - Sin tirones en el panel Rendimiento de Chrome DevTools (sin fotogramas largos > 16ms)
- Las animaciones son interrumpibles (física de resortes, no fotogramas clave fijos con
ease) - La View Transitions API tiene un fallback para navegadores no compatibles
- Las animaciones controladas por scroll usan
animation-timelineo ScrollTrigger (no listeners de eventos de scroll)