⚡ Motion Advanced · Skill 4f0402a4

Animaciones Avanzadas
con Motion/React

Catálogo de patrones interactivos y basados en física para Next.js · Implementado para NutriFlow SaaS

drag & drop gestos swipe animación texto SVG draw-on hooks personalizados useAnimate shimmer skeleton progress ring cursor follower
▮ word-by-word reveal · staggerChildren 50ms
Tunutricion,conseguimiento entiemporealanimado

motion/react · variants · staggerChildren: 0.05 · springs.gentle

Principios del sistema
Reglas de oro que gobiernan todos los patrones avanzados
Fisica > Duracion
useSpring siempre suena mas natural que duration fija en manipulacion directa.
🄯
Sin re-renders
useMotionValue + useTransform computan derivados sin disparar setState.
Interrupt-safe
useAnimate cancela el vuelo anterior automaticamente al llamar animate().
👁
Tab hidden
Loops infinitos pausan con visibilitychange. Cero GPU en pestanas ocultas.
ProgressRing + Counter animado
strokeDashoffset
kcal
Calorias
75% objetivo
Proteina
60% objetivo
Hidratacion
90% objetivo
const CIRCUMFERENCE = 2 * Math.PI * 40   // r=40
ProgressRing({ progress: 75 }) 
  animate={{ strokeDashoffset:
    CIRCUMFERENCE - (progress/100) * CIRCUMFERENCE
  }}
  transition={motionTokens.duration.normal}
DraggableCard · drag + dragConstraints
physics release
dragConstraints { ±100px }
🍽

Plan Mediterraneo

Semana 24 · Maria G.

← drag →
<motion.div
  drag
  dragConstraints={{ left: -100, right: 100,
                     top: -100, bottom: 100 }}
  dragElastic={0.1}
  whileDrag={{ scale: motionTokens.scale.pop,
    boxShadow: "0 16px 40px rgba(0,0,0,0.2)" }}
  dragTransition={springs.release}
/>
Drag-to-dismiss BottomSheet
useMotionValue
Arrastrar para cerrar
Desglose · Almuerzo
Carbohidratos 68g
Proteina 32g
Grasa 18g
const y = useMotionValue(0)
const opacity = useTransform(y, [0, 200], [1, 0])
// Rule 3: offset + velocity
onDragEnd={(_, info) => {
  if (info.offset.y > 120 ||
      info.velocity.y > 500) onClose()
}}
Reorder.Group · lista arrastrable
Reorder.Item
⋮⋮
🍳
Desayuno
08:00 · Avena con fruta
380 kcal
⋮⋮
🥗
Snack AM
10:30 · Yogur griego
120 kcal
⋮⋮
🥩
Almuerzo
14:00 · Plan mediterraneo
620 kcal
⋮⋮
🍄
Cena
20:30 · Ensalada + proteina
480 kcal
<Reorder.Group axis="y" values={items}
              onReorder={setItems}>
  {items.map((item) => (
    <Reorder.Item key={item.id} value={item}>
      {item.label}
    </Reorder.Item>
  ))}
</Reorder.Group>
Loaders & Estados de UI
Shimmer skeleton, pulse dot, loading button — con pausa en tab oculta (Rule 2)
ShimmerSkeleton · historial comidas
PulseDot · pacientes activos
Maria Garcia
Plan mediterraneo sem.24
Activa
Carlos Ruiz
Perdida de grasa sem.12
Pendiente
Ana Torres
Plan deportivo sem.3
Sin datos
LoadingButton · AnimatePresence
idle
loading
success
SVG path draw-on · stroke progress
pathLength 0→1
100 75 50 0 Lun Mar Mie Jue Vie Sab Dom
<motion.path
  d="M20,80 L50,80 L90,55..."
  initial={{ pathLength: 0, opacity: 0 }}
  animate={{ pathLength: 1, opacity: 1 }}
  transition={{ duration:
    motionTokens.duration.slow,
    ease: motionTokens.easing.smooth }}
/>
useSpring · cursor follower
CursorFollower
spring: { stiffness:150, damping:15 }
const x = useMotionValue(-100)
const sx = useSpring(x, springs.gentle)
// springs.gentle = { stiffness:150, damping:15 }
useEffect(() => {
  const move = (e) => x.set(e.clientX)
  window.addEventListener('mousemove', move)
  return () => window.removeEventListener(
    'mousemove', move)  // Rule 7
}, [])
Guia de decision de APIs
Como elegir el patron correcto segun el escenario
Escenario API a usar Ejemplo NutriFlow
Drag con fisica al soltar drag + dragTransition: springs.release Tarjeta de plan semanal
Lista drag-to-reorder Reorder.Group + Reorder.Item Orden de comidas del dia
Cerrar al arrastrar drag="y" + onDragEnd offset check Bottom sheet detalle comida
Swipe izq/dcha drag="x" + onDragEnd offset check Navegar semanas del plan
Valor suavizado en tiempo useSpring Cursor follower, scroll-linked
Valor derivado de otro useTransform Opacidad del backdrop segun y
Secuencia multi-paso useAnimate + async/await Onboarding de paciente nuevo
Texto palabra a palabra stagger on inline-block spans Hero de bienvenida
Grafico de linea pathLength 0→1 Historico de calorias semanal
Progreso circular strokeDashoffset tween Anillos kcal/proteina/agua
Anti-patrones a evitar
Las 8 reglas del skill y que falla si no se siguen
Anti-patron Regla Consecuencia · Fix
drag solo testeado en raton R1 Touch fail en movil. Test con emulador tactil.
animate repeat:Infinity sin pausa R2 GPU/CPU en tabs ocultas. Escuchar visibilitychange.
onDragEnd solo con offset R3 No detecta swipe rapido. Combinar offset + velocity.
animate(scope) antes de mount R4 Falla silencioso. Llamar animate() solo en useEffect.
new MotionValue(0) en render R5 Re-crea en cada render. Usar useMotionValue(0).
duration: 1.2 inline R6 Inconsistencia de tokens. Usar motionTokens.duration.*
useEffect sin cleanup R7 Memory leak. Return removeEventListener/controls.stop.
SVG morph rutas distintas R8 Snap en vez de tween. Normalizar comandos de path antes.