Claude Code y Framer Motion: guía práctica de Motion for React
Aprende a usar Claude Code con Framer Motion/Motion for React: prompts, ejemplos TSX, errores comunes, accesibilidad y verificación.
Muchos equipos siguen buscando Framer Motion, pero la documentación oficial actual habla de Motion for React. Para código nuevo, instala motion e importa las APIs de React desde motion/react. Si mantienes una aplicación antigua que ya está unificada en framer-motion, no mezcles ambos estilos sin una decisión explícita. Para una implementación nueva, usa la documentación oficial de Motion for React como referencia.
Claude Code acelera mucho el trabajo de animación, pero no reemplaza el criterio de producto. Si el prompt solo dice “haz que se vea suave”, el resultado puede tener rebotes excesivos, ignorar Reduced Motion o romper animaciones de salida porque se desmonta el padre equivocado. Masa lo probó en un dashboard interno: la primera versión impresionaba en una demo, pero las tarjetas se movían demasiado, las notificaciones desaparecían sin exit y el encabezado con scroll se sentía pesado en un portátil modesto.
La forma útil de trabajar es tratar a Claude Code como colaborador con límites claros. Primero defines intención, alcance, accesibilidad y verificación; después le pides el cambio. Los ejemplos TSX de este artículo funcionan en un proyecto React después de npm install motion. En Next.js o Astro, separa estas piezas como componentes de cliente.
Empieza con restricciones de diseño
Una animación debe explicar un cambio de estado. No debería ser un coste visual que el usuario paga cada vez que abre una pantalla. Antes de pedir cambios, escribe las restricciones.
| Decisión | Qué pedir a Claude Code | Qué revisar |
|---|---|---|
| Propósito | Qué cambio de estado necesita apoyo | La animación mejora la comprensión |
| Alcance | Archivos permitidos y prohibidos | No hay refactor ajeno al objetivo |
| API | motion/react y Reduced Motion | Imports y comportamiento siguen la documentación |
| Verificación | Pruebas manuales, teclado, dispositivo lento | Se probó como una UI real |
El flujo mental es simple:
Intención y restricciones
-> prompt para Claude Code
-> implementación con Motion for React
-> verificación manual y de accesibilidad
-> segundo prompt enfocado
Un primer prompt práctico sería:
Añade animación con Motion for React a este componente React existente.
Requisitos:
- Importar nuevas APIs desde `motion/react`
- No cambiar fetch de datos, envío de formularios ni routing
- Respetar Reduced Motion
- Preferir opacity y transform
- Evitar layout shift
- Devolver una checklist de pruebas manuales
El detalle de los imports evita muchos problemas. En la web hay ejemplos antiguos con framer-motion, y Claude Code puede copiarlos si no marcas el estándar del repositorio.
Caso 1: listas de tarjetas animadas
Dashboards, listados de artículos y tarjetas de producto se benefician de un stagger discreto. El objetivo no es que cada tarjeta haga un espectáculo, sino establecer un orden de lectura. En la prueba de Masa, entre 0,06 y 0,09 segundos funcionó bien para seis tarjetas; más tiempo hacía que la interfaz pareciera lenta.
import { motion, useReducedMotion } from "motion/react";
type Feature = {
id: string;
title: string;
body: string;
metric: string;
};
const demoFeatures: Feature[] = [
{
id: "review",
title: "Revisión pendiente",
body: "Cambios generados por Claude Code que una persona debe revisar.",
metric: "8 items",
},
{
id: "motion",
title: "Mejora de movimiento",
body: "Transiciones cortas explican cambios sin frenar el trabajo.",
metric: "14%",
},
{
id: "a11y",
title: "Reduced Motion",
body: "Los movimientos grandes pasan a un fade más tranquilo.",
metric: "Listo",
},
];
export function AnimatedFeatureCards({
items = demoFeatures,
}: {
items?: Feature[];
}) {
const shouldReduceMotion = useReducedMotion();
const container = {
hidden: { opacity: 0 },
visible: {
opacity: 1,
transition: {
staggerChildren: shouldReduceMotion ? 0 : 0.08,
},
},
};
const card = {
hidden: {
opacity: 0,
y: shouldReduceMotion ? 0 : 16,
},
visible: {
opacity: 1,
y: 0,
transition: {
duration: 0.32,
ease: "easeOut",
},
},
};
return (
<motion.section
aria-label="Tarjetas de funciones"
variants={container}
initial="hidden"
animate="visible"
style={{
display: "grid",
gap: 16,
gridTemplateColumns: "repeat(auto-fit, minmax(220px, 1fr))",
}}
>
{items.map((item) => (
<motion.article
key={item.id}
variants={card}
whileHover={shouldReduceMotion ? undefined : { y: -4 }}
style={{
border: "1px solid #d9e2ec",
borderRadius: 12,
padding: 20,
background: "#ffffff",
boxShadow: "0 8px 24px rgba(15, 23, 42, 0.08)",
}}
>
<p style={{ margin: 0, color: "#2563eb", fontWeight: 700 }}>
{item.metric}
</p>
<h3 style={{ margin: "8px 0", fontSize: 18 }}>{item.title}</h3>
<p style={{ margin: 0, lineHeight: 1.7, color: "#475569" }}>
{item.body}
</p>
</motion.article>
))}
</motion.section>
);
}
Revisa que las claves sean estables, que el movimiento use transform y que Reduced Motion elimine desplazamientos grandes. Un buen segundo prompt es: “Mantén el stagger, pero haz que la lista sea usable de inmediato con 12 tarjetas”.
Caso 2: notificaciones con salida real
AnimatePresence permite animar elementos cuando salen del árbol de React. La documentación de AnimatePresence recalca que los hijos directos necesitan key estable. El fallo típico es condicionar todo el contenedor y desmontarlo antes de que los hijos ejecuten exit.
import { useState } from "react";
import { AnimatePresence, motion } from "motion/react";
type Toast = {
id: number;
message: string;
};
let nextToastId = 1;
export function AnimatedNotifications() {
const [toasts, setToasts] = useState<Toast[]>([
{ id: 0, message: "Guardado correctamente" },
]);
function addToast() {
const id = nextToastId++;
setToasts((current) => [
...current,
{ id, message: `Tarea en segundo plano ${id} completada` },
]);
}
function dismissToast(id: number) {
setToasts((current) => current.filter((toast) => toast.id !== id));
}
return (
<div>
<button type="button" onClick={addToast}>
Añadir notificación
</button>
<div
aria-live="polite"
style={{
position: "fixed",
right: 24,
top: 24,
display: "grid",
gap: 12,
width: "min(360px, calc(100vw - 48px))",
}}
>
<AnimatePresence initial={false} mode="popLayout">
{toasts.map((toast) => (
<motion.div
layout
key={toast.id}
initial={{ opacity: 0, x: 40, scale: 0.96 }}
animate={{ opacity: 1, x: 0, scale: 1 }}
exit={{ opacity: 0, x: 40, scale: 0.96 }}
transition={{ duration: 0.2, ease: "easeOut" }}
style={{
borderRadius: 10,
border: "1px solid #cbd5e1",
background: "#ffffff",
padding: 16,
boxShadow: "0 12px 30px rgba(15, 23, 42, 0.16)",
}}
>
<p style={{ margin: "0 0 12px", color: "#0f172a" }}>
{toast.message}
</p>
<button type="button" onClick={() => dismissToast(toast.id)}>
Cerrar
</button>
</motion.div>
))}
</AnimatePresence>
</div>
</div>
);
}
Pide a Claude Code que confirme tres puntos: el contenedor sigue montado cuando no hay notificaciones, el cierre funciona con teclado y aria-live no anuncia demasiado. Las notificaciones se repiten muchas veces durante una sesión, así que la calma importa más que el brillo.
Caso 3: progreso de lectura con scroll
En guías largas, documentación y landing pages, un indicador de progreso ayuda a orientarse. useScroll devuelve valores de scroll para la página o un elemento; con useSpring el progreso se siente más estable. No conviertas cada sección en una escena de parallax. Si Reduced Motion está activo, elimina desplazamientos grandes.
import { useRef } from "react";
import {
motion,
useReducedMotion,
useScroll,
useSpring,
useTransform,
} from "motion/react";
const sections = [
{
title: "Fijar el requisito",
body: "Antes de editar, Claude Code debe conocer objetivo, archivos y límites.",
},
{
title: "Mover menos",
body: "Empieza con opacity y transform para apoyar la comprensión.",
},
{
title: "Verificar rutas reales",
body: "Prueba dispositivo lento, teclado y Reduced Motion antes de publicar.",
},
];
export function ScrollReadingProgress() {
const articleRef = useRef<HTMLElement | null>(null);
const shouldReduceMotion = useReducedMotion();
const { scrollYProgress } = useScroll({
target: articleRef,
offset: ["start start", "end end"],
});
const scaleX = useSpring(scrollYProgress, {
stiffness: 120,
damping: 28,
mass: 0.2,
});
const y = useTransform(scrollYProgress, [0, 1], [0, -48]);
return (
<article ref={articleRef} style={{ position: "relative", padding: 24 }}>
<motion.div
aria-hidden="true"
style={{
position: "sticky",
top: 0,
zIndex: 10,
height: 4,
scaleX: shouldReduceMotion ? 1 : scaleX,
transformOrigin: "0% 50%",
background: "#2563eb",
}}
/>
<motion.header
style={{
y: shouldReduceMotion ? 0 : y,
padding: "56px 0 32px",
}}
>
<p style={{ color: "#2563eb", fontWeight: 700 }}>
Claude Code x Motion
</p>
<h2 style={{ fontSize: 36, margin: 0 }}>
Una página que revela contexto al leer
</h2>
</motion.header>
<div style={{ display: "grid", gap: 24 }}>
{sections.map((section) => (
<section
key={section.title}
style={{
border: "1px solid #dbe4ee",
borderRadius: 12,
padding: 24,
background: "#ffffff",
}}
>
<h3>{section.title}</h3>
<p style={{ lineHeight: 1.8 }}>{section.body}</p>
</section>
))}
</div>
</article>
);
}
Úsalo como ayuda de orientación, no como relleno visual. Un solo indicador útil suele ser mejor que cinco revelados por scroll que hacen la página más lenta.
Haz que Claude Code revise el diff
Después de implementar, no te quedes en “se ve bien”. Pide una revisión crítica con fallos concretos.
Revisa el diff actual como implementación de Motion for React.
Sé estricto con:
- No mezclar `motion/react` con imports antiguos de `framer-motion`
- Hijos directos de `AnimatePresence` con key estable
- Reduced Motion desactiva grandes desplazamientos, parallax y efectos tipo autoplay
- No se animan frecuentemente width, height, top o left
- La prueba manual representa acciones reales del usuario
Esto convierte a Claude Code en una primera capa de revisión. Como puede leer archivos cercanos, también puede detectar conflictos de CSS, cambios de estado no deseados y pruebas faltantes.
Errores comunes y checklist
El primer error es usar imports obsoletos. En un proyecto heredado puede ser correcto mantener framer-motion, pero el código nuevo debería seguir motion y motion/react salvo decisión contraria del repositorio. El segundo error es depurar exit como si fuera un problema de easing. Casi siempre es un problema del árbol React: el padre se desmonta antes, la key es un índice o el elemento no sale dentro de AnimatePresence.
El tercer error es creer que layout lo arregla todo. Ayuda con reordenamientos y cambios de tamaño, pero imágenes sin dimensiones, fuentes tardías y cambios bruscos de Grid todavía generan saltos. El cuarto error es dejar la accesibilidad para el final. La guía oficial de accesibilidad explica Reduced Motion; si hay grandes desplazamientos, parallax o autoplay, crea la alternativa desde la primera versión.
Antes de publicar, confirma que la documentación oficial y los imports coinciden, cada animación tiene propósito, Reduced Motion elimina grandes movimientos, los hijos de AnimatePresence tienen key, el teclado y el foco siguen funcionando, y los efectos de scroll no reducen la legibilidad.
Para bases de UI, lee Radix UI con Claude Code, shadcn/ui con Claude Code y la guía de animación con Claude Code. Sobre el agente, consulta la documentación de Claude Code de Anthropic.
Conclusión
Combinar Claude Code con Framer Motion no vale solo por escribir animaciones más rápido. Vale porque puedes meter implementación, accesibilidad y revisión en el mismo flujo antes de publicar.
El resultado práctico de Masa fue claro: incluir motion/react, Reduced Motion y verificación manual en el primer prompt redujo más retrabajo que cualquier pulido posterior. Para reutilizar la plantilla, guarda la hoja de trucos gratuita. Si quieres revisar varias pantallas con un equipo, la página de formación y consultoría es el siguiente paso razonable.
PDF gratis: cheatsheet de Claude Code
Introduce tu email y descarga una hoja con comandos, hábitos de revisión y flujos seguros.
Cuidamos tus datos y no enviamos spam.
Sobre el autor
Masa
Ingeniero enfocado en workflows prácticos con Claude Code.
Artículos relacionados
Escalera de permisos de Claude Code para ampliar acceso sin perder control
Pasa de read-only a ediciones limitadas, comandos de prueba y checks de deploy con menos riesgo.
Claude Code Small PR Proof Pack: cambios pequeños que sí se pueden revisar
Un paquete de prueba para PRs de Claude Code: diff, checks, URL pública, CTA y rollback.
Gate de revisión antes del commit con Claude Code
Cómo revisar con Claude Code antes del commit: diff, build, URL pública, Gumroad, consultoría, tests y archivos ajenos.