'use client'; import { useEffect, useRef } from 'react'; import { motion, useMotionValue, useScroll, useSpring, useTransform } from 'framer-motion'; import { PatronPuntos } from './PatronPuntos'; import { usePrefersReducedMotion } from '@/lib/motion'; // Decorative background: the manual's dot pattern, drifting slightly against // the scroll. Purely presentational — hidden from assistive tech, and it holds // still for anyone who asked for less movement. export function FondoPuntos({ className = '', distance = 40, rows, cols, interactivo = false, }: { className?: string; distance?: number; rows?: number; cols?: number; // Además de derivar con el scroll, sigue el cursor levemente — reservado // para los patrones más prominentes (el hero), no para cada instancia. interactivo?: boolean; }) { const ref = useRef(null); const reduced = usePrefersReducedMotion(); const { scrollYProgress } = useScroll({ target: ref, offset: ['start end', 'end start'] }); const scrollY = useTransform(scrollYProgress, [0, 1], [distance, -distance]); const mouseXRaw = useMotionValue(0); const mouseYRaw = useMotionValue(0); const mouseX = useSpring(mouseXRaw, { stiffness: 40, damping: 15 }); const mouseY = useSpring(mouseYRaw, { stiffness: 40, damping: 15 }); useEffect(() => { if (!interactivo || reduced) return; const handler = (e: MouseEvent) => { mouseXRaw.set((e.clientX / window.innerWidth - 0.5) * 16); mouseYRaw.set((e.clientY / window.innerHeight - 0.5) * 16); }; window.addEventListener('mousemove', handler); return () => window.removeEventListener('mousemove', handler); }, [interactivo, reduced, mouseXRaw, mouseYRaw]); const y = useTransform([scrollY, mouseY], ([a, b]) => (a as number) + (b as number)); return ( ); }