HOVER OVER
components/snippet/3d-card.tsx
// @NOTE: in case you are using Next.js
"use client";
import React, { useRef } from "react";
import {
motion,
useMotionTemplate,
useMotionValue,
useSpring,
} from "framer-motion";
import { HomeIcon } from "lucide-react";
const ROTATION_RANGE = 32.5;
const HALF_ROTATION_RANGE = 32.5 / 2;
const ThreeDCard = () => {
const ref = useRef<HTMLDivElement | null>(null);
const x = useMotionValue(0);
const y = useMotionValue(0);
const xSpring = useSpring(x);
const ySpring = useSpring(y);
const transform = useMotionTemplate`rotateX(${xSpring}deg) rotateY(${ySpring}deg)`;
const handleMouseMove = (e: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
if (!ref.current) return [0, 0];
const rect = ref.current.getBoundingClientRect();
const width = rect.width;
const height = rect.height;
const mouseX = (e.clientX - rect.left) * ROTATION_RANGE;
const mouseY = (e.clientY - rect.top) * ROTATION_RANGE;
const rX = (mouseY / height - HALF_ROTATION_RANGE) * -1;
const rY = mouseX / width - HALF_ROTATION_RANGE;
x.set(rX);
y.set(rY);
};
const handleMouseLeave = () => {
x.set(0);
y.set(0);
};
return (
<motion.div
ref={ref}
onMouseMove={handleMouseMove}
onMouseLeave={handleMouseLeave}
style={{
transformStyle: "preserve-3d",
transform,
}}
className="relative h-96 w-72 rounded-xl bg-gradient-to-br from-indigo-400 to-emerald-400"
>
<div
style={{
transform: "translateZ(75px)",
transformStyle: "preserve-3d",
}}
className="absolute inset-4 grid place-content-center rounded-xl bg-gradient-to-br from-emerald-200 to-indigo-200 shadow-lg"
>
<HomeIcon
size={64}
style={{
transform: "translateZ(75px)",
}}
className="mx-auto text-4xl text-black "
/>
<p
style={{
transform: "translateZ(50px)",
}}
className="text-center text-2xl font-bold text-black "
>
HOVER OVER
</p>
</div>
</motion.div>
);
};
export default ThreeDCard;