components/image-parallax.tsx
import gsap from "gsap";
import { useGSAP } from "@gsap/react";
import { ScrollTrigger } from "gsap/ScrollTrigger";
import { useRef } from "react";
gsap.registerPlugin(useGSAP, ScrollTrigger);
export interface ImageParallaxProps {
src: string;
alt: string;
intensity?: number;
imageScale?: number;
containerClassName?: string;
imageClassName?: string;
}
const DEFAULT_INTENSITY = 20;
const DEFAULT_IMAGE_SCALE = 1.5;
export function ImageParallax({
src,
alt,
intensity = DEFAULT_INTENSITY,
imageScale = DEFAULT_IMAGE_SCALE,
containerClassName,
imageClassName,
}: ImageParallaxProps) {
const containerRef = useRef<HTMLDivElement>(null);
const imageRef = useRef<HTMLImageElement>(null);
useGSAP(() => {
const image = imageRef.current;
if (!image) return;
gsap.fromTo(
image,
{ yPercent: -intensity },
{
yPercent: intensity,
ease: "none",
scrollTrigger: {
trigger: containerRef.current,
scrub: true,
start: "top bottom",
end: "bottom top",
},
},
);
}, [intensity]);
return (
<div
ref={containerRef}
className={`overflow-hidden ${containerClassName ?? ""}`.trim()}
>
<img
ref={imageRef}
className={imageClassName}
style={{ transform: `scale(${imageScale})` }}
src={src}
alt={alt}
/>
</div>
);
}