"use client"; import { useEffect, useRef, useState, type ReactNode } from "react"; import CopyBar from "@/components/CopyBar"; import type { AnimationEntry } from "@/lib/registry"; /** * Mounts children only once the card scrolls near the viewport. WebGL canvases * are expensive; a gallery that boots every scene at once stutters on load. */ function LazyMount({ children }: { children: ReactNode }) { const ref = useRef(null); const [visible, setVisible] = useState(false); useEffect(() => { const el = ref.current; if (!el) return; if (typeof IntersectionObserver === "undefined") { const id = requestAnimationFrame(() => setVisible(true)); return () => cancelAnimationFrame(id); } const observer = new IntersectionObserver( ([entry]) => { if (entry.isIntersecting) { setVisible(true); observer.disconnect(); } }, { rootMargin: "200px" }, ); observer.observe(el); return () => observer.disconnect(); }, []); return (
{visible ? ( children ) : (
)}
); } export default function AnimationCard({ entry, height = "h-[420px]", children, }: { entry: AnimationEntry; height?: string; children: ReactNode; }) { return (
{children}

{entry.title}

{entry.tags.map((tag) => ( {tag} ))}

{entry.description}

); }