// ───────────── Hero with video bg + liquid glass nav ───────────── // (Nav + LogoMark + Reveal live in shell.jsx) // Custom seamless video loop fade system (JS-driven, not CSS transitions) function useVideoFadeLoop(ref) { const fadingOutRef = useRef(false); const rafRef = useRef(null); useEffect(() => { const v = ref.current; if (!v) return; // Skip if not a real video element (HeroScene fallback) if (!(v instanceof HTMLVideoElement)) return; const cancel = () => { if (rafRef.current) cancelAnimationFrame(rafRef.current); rafRef.current = null; }; const fadeTo = (target, duration, onDone) => { cancel(); const start = performance.now(); const from = parseFloat(v.style.opacity || "0"); const step = (t) => { const k = Math.min(1, (t - start) / duration); const eased = k; // linear is fine v.style.opacity = (from + (target - from) * eased).toString(); if (k < 1) rafRef.current = requestAnimationFrame(step); else { rafRef.current = null; onDone && onDone(); } }; rafRef.current = requestAnimationFrame(step); }; const onLoaded = () => { v.style.opacity = "0"; v.play().catch(()=>{}); fadeTo(1, 500); }; const onTime = () => { if (!v.duration) return; const left = v.duration - v.currentTime; if (!fadingOutRef.current && left < 0.55) { fadingOutRef.current = true; fadeTo(0, 500); } }; const onEnded = () => { v.style.opacity = "0"; setTimeout(() => { v.currentTime = 0; v.play().catch(()=>{}); fadingOutRef.current = false; fadeTo(1, 500); }, 100); }; v.addEventListener("loadeddata", onLoaded); v.addEventListener("timeupdate", onTime); v.addEventListener("ended", onEnded); return () => { cancel(); v.removeEventListener("loadeddata", onLoaded); v.removeEventListener("timeupdate", onTime); v.removeEventListener("ended", onEnded); }; }, []); } function Hero({ accent, videoBg = true }) { const videoRef = useRef(null); useVideoFadeLoop(videoRef); return (
{/* Video or fallback gradient scene */} {videoBg ? (
); } Object.assign(window, { Hero, HeroScene }); // ───────────── Procedural 3D Hero Scene (fallback when videoBg=false) ───────────── function HeroScene({ accent }) { const ref = useRef(null); useEffect(() => { const el = ref.current; if (!el) return; const onMove = (e) => { const x = (e.clientX / window.innerWidth - 0.5) * 2; const y = (e.clientY / window.innerHeight - 0.5) * 2; el.style.setProperty("--px", x); el.style.setProperty("--py", y); }; window.addEventListener("mousemove", onMove); return () => window.removeEventListener("mousemove", onMove); }, []); return (
{/* Big orb */}
{/* Inner core */}
{/* Concentric rings */} {[1.0, 1.5, 2.2, 3.0, 4.2].map((s, i) => (
))} {/* Stars */} {Array.from({ length: 140 }).map((_, i) => { const x = (i * 37) % 100, y = (i * 53) % 100; return 0.85 ? 1.4 : 0.6} fill="rgba(255,255,255,0.5)"/>; })}
); }