Back to Discover
BackgroundsAdvanced
Interactive Constellation
Floating nodes that connect to your cursor.
Live Preview
Interactive Constellation
"use client";
import { useRef, useEffect } from "react";
import { motion, useMotionValue, useSpring, useTransform, useMotionTemplate } from "framer-motion";
export function RealityDistortionCard() {
const cardRef = useRef<HTMLDivElement>(null);
const mouseX = useMotionValue(0);
const mouseY = useMotionValue(0);
const smoothX = useSpring(mouseX, { stiffness: 300, damping: 30 });
const smoothY = useSpring(mouseY, { stiffness: 300, damping: 30 });
const rotateX = useTransform(smoothY, [0, 400], [5, -5]);
const rotateY = useTransform(smoothX, [0, 320], [-5, 5]);
const bgX = useTransform(smoothX, [0, 320], [15, -15]);
const bgY = useTransform(smoothY, [0, 400], [15, -15]);
const spotlight = useMotionTemplate`radial-gradient(300px circle at ${smoothX}px ${smoothY}px, rgba(255,255,255,0.15), transparent 40%)`;
useEffect(() => {
if (cardRef.current) {
const rect = cardRef.current.getBoundingClientRect();
mouseX.set(rect.width / 2);
mouseY.set(rect.height / 2);
}
}, [mouseX, mouseY]);
return (
<div
className="flex items-center justify-center w-full h-[600px] bg-cover bg-fixed bg-center rounded-xl border border-border relative overflow-hidden"
style={{ backgroundImage: "url('https://images.unsplash.com/photo-1550684848-fac1c5b4e853?q=80&w=2070&auto=format&fit=crop')" }}
>
<svg className="hidden">
<filter id="distortionFilter">
<feTurbulence type="fractalNoise" baseFrequency="0.015" numOctaves="3" result="noise">
<animate attributeName="baseFrequency" values="0.015;0.02;0.015" dur="6s" repeatCount="indefinite" />
</feTurbulence>
<feDisplacementMap in="SourceGraphic" in2="noise" scale="25" xChannelSelector="R" yChannelSelector="G" />
</filter>
</svg>
<motion.div
ref={cardRef}
onMouseMove={(e) => {
if (!cardRef.current) return;
const rect = cardRef.current.getBoundingClientRect();
mouseX.set(e.clientX - rect.left);
mouseY.set(e.clientY - rect.top);
}}
onMouseLeave={() => {
if (!cardRef.current) return;
const rect = cardRef.current.getBoundingClientRect();
mouseX.set(rect.width / 2);
mouseY.set(rect.height / 2);
}}
style={{
rotateX,
rotateY,
transformStyle: "preserve-3d",
transformPerspective: 1000,
}}
className="w-80 h-[400px] rounded-2xl relative flex flex-col justify-end p-6 overflow-hidden group cursor-crosshair transition-shadow duration-500 hover:shadow-2xl hover:shadow-white/5"
>
{/* Layer 2: Refraction Background */}
<motion.div
className="absolute inset-[-20%] w-[140%] h-[140%] bg-cover bg-fixed bg-center z-0 opacity-0 group-hover:opacity-100 transition-opacity duration-700 pointer-events-none"
style={{
backgroundImage: "url('https://images.unsplash.com/photo-1550684848-fac1c5b4e853?q=80&w=2070&auto=format&fit=crop')",
x: bgX,
y: bgY,
filter: "url(#distortionFilter)",
}}
/>
{/* Layer 3: Glass Frosting */}
<div
className="absolute inset-0 z-0 bg-white/[0.02] backdrop-blur-[12px]"
/>
{/* Layer 4: Interactive Spotlight Lens */}
<motion.div
className="absolute inset-0 z-0 opacity-0 group-hover:opacity-100 transition-opacity duration-500 pointer-events-none mix-blend-overlay"
style={{ background: spotlight }}
/>
{/* Layer 5: Apple-style Highlights & Borders */}
<div
className="absolute inset-0 z-0 rounded-2xl pointer-events-none"
style={{
border: "1px solid rgba(255, 255, 255, 0.1)",
boxShadow: "inset 0 1px 1px rgba(255, 255, 255, 0.15), 0 4px 24px rgba(0, 0, 0, 0.4)",
}}
/>
{/* Content */}
<div className="relative z-10 pointer-events-none drop-shadow-md transform-gpu" style={{ transform: "translateZ(30px)" }}>
<h3 className="text-2xl font-bold text-white mb-2 tracking-tight">Reality Distortion</h3>
<p className="text-white/70 text-sm">Move your cursor to witness true physical refraction.</p>
</div>
</motion.div>
</div>
);
}