// Main portfolio components — Cédrick Picard / Nyxoril const { useState, useEffect, useRef, useMemo } = React; // ---------- Smooth scroll ---------- function smoothScrollTo(targetY, duration = 900) { const startY = window.scrollY; const distance = targetY - startY; if (Math.abs(distance) < 4) return; const startT = performance.now(); const ease = (p) => p < 0.5 ? 4 * p * p * p : 1 - Math.pow(-2 * p + 2, 3) / 2; const step = (t) => { const p = Math.min(1, (t - startT) / duration); window.scrollTo(0, startY + distance * ease(p)); if (p < 1) requestAnimationFrame(step); }; requestAnimationFrame(step); } function scrollToId(id) { if (id === "top") return smoothScrollTo(0); const el = document.getElementById(id); if (!el) return; const top = el.getBoundingClientRect().top + window.scrollY - 70; smoothScrollTo(top); } // ---------- Background grid + parallax glow ---------- function GridBackground({ accentHue }) { const ref = useRef(null); useEffect(() => { const onMove = (e) => { const x = (e.clientX / window.innerWidth - 0.5) * 30; const y = (e.clientY / window.innerHeight - 0.5) * 30; if (ref.current) ref.current.style.transform = `translate3d(${x}px, ${y}px, 0)`; }; window.addEventListener("mousemove", onMove); return () => window.removeEventListener("mousemove", onMove); }, []); return (