3D Tilt Parallax Card
Cards that literally tilt on their X and Y axes in response to mouse movement. Internal elements (like a logo or image) often move at a faster rate to simulate true 3D depth.
Use
Physical product representations (e.g. Credit Cards)
Avoid
Cards that contain heavy interaction like form inputs or carousels
Safer Alternative
No safer default listed.
Risk Level
Low risk
Live Demo
What It Is
Cards that literally tilt on their X and Y axes in response to mouse movement. Internal elements (like a logo or image) often move at a faster rate to simulate true 3D depth.
✓When to Use
- Physical product representations (e.g. Credit Cards)
- Premium feature show-offs
✕When NOT to Use
- Cards that contain heavy interaction like form inputs or carousels
Configuration Tips
- 01Use Framer Motion's useMouse, map coordinates to rotationX and rotationY (-15deg to 15deg), and apply translateZ to child elements.
You've Seen It In
AI Implementation Prompts
Move from a fast scaffold to production details, then tune timing and edge states.
Create a card that tilts in 3D space based on mouse position. Add a transform: translateZ(50px) to the text inside so it seems to float above the card background.
Reference Implementation
The same implementation approach used by the live preview, kept compact enough to inspect and adapt.
"use client";
import { motion, useMotionTemplate, useMotionValue, useSpring, useTransform } from "framer-motion";
import { MouseEvent, useEffect, useRef, useState } from "react";
export function TiltParallaxCardDemo({ isPlaying = false }: { isPlaying?: boolean }) {
const ref = useRef<HTMLDivElement>(null);
const [isInteracting, setIsInteracting] = useState(false);
const x = useMotionValue(0);
const y = useMotionValue(0);
const mouseXSpring = useSpring(x, { stiffness: 100, damping: 20 });
const mouseYSpring = useSpring(y, { stiffness: 100, damping: 20 });
"text-stone-400 italic">// Map mouse position to degree rotations (-15 to 15 degrees)
const rotateX = useTransform(mouseYSpring, [-0.5, 0.5], ["15deg", "-15deg"]);
const rotateY = useTransform(mouseXSpring, [-0.5, 0.5], ["-15deg", "15deg"]);
useEffect(() => {
if (!isPlaying || isInteracting) return;
"text-stone-400 italic">// Auto-play the tilt effect
let time = 0;
const loop = setInterval(() => {
time += 0.03;
x.set(Math.cos(time) * 0.4);
y.set(Math.sin(time) * 0.4);
}, 16);
return () => {
clearInterval(loop);
if (!isInteracting) {
x.set(0);
y.set(0);
}
};
}, [isPlaying, isInteracting, x, y]);
const handleMouseMove = (e: MouseEvent<HTMLDivElement>) => {
setIsInteracting(true);
if (!ref.current) return;
const rect = ref.current.getBoundingClientRect();
const width = rect.width;
const height = rect.height;
"text-stone-400 italic">// Normalized values (-0.5 to 0.5)
const mouseX = e.clientX - rect.left;
const mouseY = e.clientY - rect.top;
const xPct = mouseX / width - 0.5;
const yPct = mouseY / height - 0.5;
x.set(xPct);
y.set(yPct);
};
const handleMouseLeave = () => {
setIsInteracting(false);
x.set(0);
y.set(0);
};
return (
<div className="flex h-64 w-full items-center justify-center overflow-hidden rounded-2xl bg-stone-100 p-4 shadow-sm ring-1 ring-stone-200 perspective-1000">
{"text-stone-400 italic">/* The container that preserves 3D and applies the tilt */}
<motion.div
ref={ref}
onMouseMove={handleMouseMove}
onMouseLeave={handleMouseLeave}
style={{
rotateX,
rotateY,
transformStyle: "preserve-3d",
}}
className="relative w-64 h-40 max-w-sm rounded-2xl bg-gradient-to-br from-indigo-500 to-purple-600 shadow-2xl overflow-visible flex items-center justify-center"
>
{"text-stone-400 italic">/* Internal floating elements (Z translated physically in 3D space) */}
<div
style={{ transform: "translateZ(50px)" }}
className="absolute inset-4 rounded-xl border border-white/20 bg-white/10 backdrop-blur-sm pointer-events-none"
/>
<div style={{ transform: "translateZ(75px)" }} className="pointer-events-none flex flex-col items-center">
<svg className="w-10 h-10 text-white mb-2 drop-shadow-md" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M3 10h18M7 15h1m4 0h1m-7 4h12a3 3 0 003-3V8a3 3 0 00-3-3H6a3 3 0 00-3 3v8a3 3 0 003 3z" />
</svg>
<span className="text-white font-bold tracking-widest uppercase drop-shadow-lg text-xs font-mono">Premium Pass</span>
</div>
{"text-stone-400 italic">/* Simulated shiny gloss that tracks the mouse subtly */}
<motion.div
className="absolute inset-0 rounded-2xl opacity-20 pointer-events-none"
style={{
background: useMotionTemplate`radial-gradient(150px circle at calc(50% + ${useTransform(x, v => v * 100)}%) calc(50% + ${useTransform(y, v => v * 100)}%), white, transparent 60%)`
}}
/>
</motion.div>
</div>
);
}Related Effects
Hover Lift Effect
A card or button smoothly translates upwards by a few pixels and increases its shadow cast, creating the illusion of moving closer to the user on hover.
Spotlight Glare Card
A glossy card element where a soft, radial gradient spotlight perfectly tracks the user's mouse position over the surface, creating a physical "glare" effect.