Catálogo de patrones interactivos y basados en física para Next.js · Implementado para NutriFlow SaaS
motion/react · variants · staggerChildren: 0.05 · springs.gentle
const CIRCUMFERENCE = 2 * Math.PI * 40 // r=40 ProgressRing({ progress: 75 }) → animate={{ strokeDashoffset: CIRCUMFERENCE - (progress/100) * CIRCUMFERENCE }} transition={motionTokens.duration.normal}
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} />
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 axis="y" values={items} onReorder={setItems}> {items.map((item) => ( <Reorder.Item key={item.id} value={item}> {item.label} </Reorder.Item> ))} </Reorder.Group>
<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 }} />
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 }, [])
| 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-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. |