(null); const inView = useInView(ref, { margin: "-10% 0px -10% 0px", amount: 0.25 }); return ( (null); const inView = useInView(ref, { margin: "-10% 0px -10% 0px", amount: 0.25 }); return ( (null); const inView = useInView(ref, { margin: "-10% 0px -10% 0px", amount: 0.25 }); return (

Screen Recording 2025-09-11 at 6.56.29 PM.mov

  • https://motion.dev/
  • fades & lifts into view when ~25% of it is visible in the viewport,
  • fades & drops back out when it leaves the viewport,
  • slightly scales up on hover,
  • staggers its entrance based on its index to create a “cascade” effect across a grid.
import { motion, useInView } from "framer-motion";
import { useRef } from "react";

export default function CascadeCard({ index }: { index: number }){
    const ref = useRef<HTMLDivElement | null>(null);
    const inView = useInView(ref, { margin: "-10% 0px -10% 0px", amount: 0.25 });
    
    return (
        <motion.div
        ref={ref}
        // Use variants-like behavior via animate prop to allow in/out transitions
        initial={{ opacity: 0, y: 28, scale: 0.98 }}
        animate={inView ? { opacity: 1, y: 0, scale: 1 } : { opacity: 0, y: 28, scale: 0.98 }}
        whileHover={{ scale: 1.03 }}
        transition={{
            duration: 0.6,
            ease: [0.22, 1, 0.36, 1],
            // Stagger by index to create a cascade effect
            delay: (index % 12) * 0.20, // small wave across each screenful
        }}
        className="group relative h-48 w-full rounded-md bg-gradient-to-br from-slate-700 to-slate-800 shadow-lg ring-1 ring-white/5 overflow-hidden will-change-transform"
        >
            <img
                src={"./data/photos/pic1.jpg"}                // pass this in from your items
                className="absolute inset-0 h-full w-full object-cover"
                loading="lazy"
            />

            {/* optional: bottom gradient to improve text contrast */}
            <div className="pointer-events-none absolute inset-0 bg-gradient-to-t from-black/50 via-black/0 to-black/10" />

            {/* your existing text overlay, just give it higher z-index */}
            <div className="absolute inset-0 z-10 flex items-end">
                <div className="w-full p-4 text-slate-200/90 text-sm tracking-wide flex items-center justify-between">
                    <span className="font-semibold">Frame {index + 1}</span>
                    <span className="opacity-70">{inView ? "in view" : "out"}</span>
                </div>
            </div>
        
            {/* subtle hover lift */}
            <div className="absolute inset-0 transition-transform duration-300 group-hover:scale-[1.02]" />
        </motion.div>
    );

}