Lamp Effect
Preview
Code
"use client";
import { motion, useMotionValue, useSpring, useTransform } from "framer-motion";
import { type FC, type ReactNode, useRef } from "react";
import { cn } from "@/lib/utils";
interface LampEffectProps {
children: ReactNode;
className?: string;
containerClassName?: string;
lampColor?: string;
glowColor?: string;
}
const LampEffect: FC<LampEffectProps> = ({
children,
className,
containerClassName,
lampColor = "white",
glowColor = "rgba(255, 255, 255, 0.1)",
}) => {
const ref = useRef<HTMLDivElement>(null);
const mouseX = useMotionValue(0);
const handleMouseMove = (e: React.MouseEvent<HTMLDivElement>) => {
if (!ref.current) return;
const { left } = ref.current.getBoundingClientRect();
mouseX.set(e.clientX - left);
};
const springX = useSpring(mouseX, {
stiffness: 300,
damping: 30,
});
const lightX = useTransform(springX, [0, ref.current?.clientWidth || 0], [-100, (ref.current?.clientWidth || 0) + 100]);
return (
<div
ref={ref}
onMouseMove={handleMouseMove}
className={cn("relative w-full bg-slate-950 overflow-hidden", containerClassName)}
>
<div className={cn("relative z-10 p-8", className)}>{children}</div>
<div className="absolute inset-0 z-0" style={{
'--lamp-color': lampColor,
'--glow-color': glowColor,
} as React.CSSProperties}>
<motion.div
className="absolute inset-x-0 h-px w-full -top-px"
style={{
background: `linear-gradient(to right, transparent, var(--lamp-color), transparent)`,
}}
/>
<motion.div
className="absolute h-48 w-px -top-48"
style={{
left: springX,
background: `linear-gradient(to bottom, transparent, var(--lamp-color))`,
}}
/>
<motion.div
className="absolute inset-0 w-full h-full"
style={{
opacity: 0.5,
background: useTransform(
lightX,
(x) => `radial-gradient(350px circle at ${x}px 0px, var(--glow-color), transparent 80%)`
),
}}
/>
</div>
</div>
);
};
export default LampEffect;