Skip to content

Instantly share code, notes, and snippets.

@divv919
Created November 23, 2025 10:01
Show Gist options
  • Select an option

  • Save divv919/f27abc7b86ef9eac5ee4afe63b0d92f4 to your computer and use it in GitHub Desktop.

Select an option

Save divv919/f27abc7b86ef9eac5ee4afe63b0d92f4 to your computer and use it in GitHub Desktop.
"use client";
import {
IconActivityHeartbeat,
IconAlertCircleFilled,
} from "@tabler/icons-react";
import Image from "next/image";
import {
motion,
MotionValue,
useMotionValueEvent,
useScroll,
useSpring,
useTransform,
useMotionValue,
motionValue,
useMotionTemplate,
} from "motion/react";
import { useEffect, useRef, useState } from "react";
export default function Parallax() {
const containerRef = useRef(null);
const { scrollYProgress } = useScroll({ target: containerRef });
const x = useTransform(scrollYProgress, [0, 1], [600, -2850]);
return (
<div
ref={containerRef}
className="w-full h-[300vh] bg-neutral-900 relative"
>
<motion.div
style={{
x: x,
}}
className="fixed top-1/2 -translate-y-1/2 flex gap-350 justify-center items-center"
>
{data.map((d, index) => {
return <Card d={d} index={index} globalX={x} />;
})}
</motion.div>
</div>
);
}
function Card({
d,
globalX,
index,
}: {
d: {
title: string;
description: string;
icon: React.ReactElement;
img: string;
};
globalX: MotionValue<number>;
index: number;
}) {
const [innerWidth, setInnerWidth] = useState(0);
useEffect(() => {
if (typeof window === undefined) {
return;
}
setInnerWidth(window.innerWidth);
}, []);
const cardRef = useRef<HTMLDivElement>(null);
const distance = useTransform(globalX, () => {
if (!cardRef.current) return 0;
const rect = cardRef.current.getBoundingClientRect();
const cardCenter = rect.left + rect.width / 2;
const screenCenter = innerWidth / 2;
return cardCenter - screenCenter;
});
const maxDistance = innerWidth / 2;
const opacity = useTransform(
distance,
[-maxDistance, 0, maxDistance],
[0.3, 1, 0.3]
);
const scale = useTransform(
distance,
[-maxDistance, 0, maxDistance],
[0.9, 1.1, 0.9]
);
const blur = useTransform(
distance,
[-maxDistance, 0, maxDistance],
[2, 0, 2]
);
const x = useTransform(distance, [-maxDistance, maxDistance], [-75, 75]);
const blurString = useMotionTemplate`blur(${blur}px)`;
return (
<motion.div
style={{ opacity, scale, filter: blurString }}
ref={cardRef}
key={d.title}
className="flex flex-col max-w-3xl gap-4 mx-auto "
>
<motion.div className="size-70" style={{ x }}>
<Image
className="rounded-md w-full aspect-square"
src={d.img}
alt={d.title}
width={200}
height={200}
/>
</motion.div>
<motion.div className="flex flex-col gap-2">
<div className="flex flex-col gap-2 text-2xl text-nowrap">
{d.icon}
{d.title}
</div>
<div className="text-neutral-400">{d.description}</div>
</motion.div>
</motion.div>
);
}
const data = [
{
title: "Real-time Health Monitoring",
description:
"Track vital health metrics instantly with intelligent, continuous monitoring designed for reliability and speed.",
icon: <IconActivityHeartbeat size={30} />,
img: "https://picsum.photos/id/237/300/300",
},
{
title: "Instant Issue Detection",
description:
"Get alerted the moment something needs your attention with an advanced system built for quick problem identification.",
icon: <IconAlertCircleFilled size={30} />,
img: "https://picsum.photos/id/238/300/300",
},
{
title: "Adaptive Performance Insights",
description:
"Understand patterns and optimize outcomes with dynamic insights that adjust to real-world conditions.",
icon: <IconActivityHeartbeat size={30} />,
img: "https://picsum.photos/id/239/300/300",
},
];
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment