Isometric 3D Card
A realistic glassmorphic credit card that tilts in 3D and flips to show the CVV when needed.
Installation
Add this component to your project using the CLI:
npx vui-registry-cli-v1 add iso-3d-cardSource Code
"use client"
import { useState, useRef, useEffect } from "react"
import { motion, useMotionValue, useSpring, useTransform } from "framer-motion"
import { CreditCard, Wifi, ShieldCheck, Nfc } from "lucide-react"
export default function Iso3DCard() {
const [cardNumber, setCardNumber] = useState("4582 3456 7890 1234")
const [expiry, setExpiry] = useState("12/26")
const [cvv, setCvv] = useState("123")
const [name, setName] = useState("VIKAS YADAV")
const [isFlipped, setIsFlipped] = useState(false)
// Mouse interaction
const x = useMotionValue(0)
const y = useMotionValue(0)
const mouseX = useSpring(x, { stiffness: 500, damping: 100 })
const mouseY = useSpring(y, { stiffness: 500, damping: 100 })
const rotateX = useTransform(mouseY, [-0.5, 0.5], ["-20deg", "20deg"])
const rotateY = useTransform(mouseX, [-0.5, 0.5], ["20deg", "-20deg"])
function handleMouseMove({ currentTarget, clientX, clientY }: React.MouseEvent) {
const { left, top, width, height } = currentTarget.getBoundingClientRect()
const xPct = (clientX - left) / width - 0.5
const yPct = (clientY - top) / height - 0.5
x.set(xPct)
y.set(yPct)
}
function handleMouseLeave() {
x.set(0)
y.set(0)
setIsFlipped(false)
}
return (
<div className="flex min-h-[600px] w-full items-center justify-center bg-neutral-100 dark:bg-neutral-900 perspective-1000 flex-col">
<div
className="relative w-full max-w-lg p-8 perspective-1000"
onMouseMove={handleMouseMove}
onMouseLeave={handleMouseLeave}
>
<motion.div
style={{
rotateX,
rotateY,
transformStyle: "preserve-3d",
}}
transition={{ type: "spring", stiffness: 400, damping: 30 }}
className="relative h-64 w-96 mx-auto rounded-3xl shadow-2xl transition-all duration-200"
>
{/* Card Front */}
<div
className="absolute inset-0 h-full w-full rounded-3xl bg-gradient-to-br from-neutral-800 to-black p-8 text-white shadow-xl backface-hidden border border-white/10"
style={{
backfaceVisibility: 'hidden',
transform: isFlipped ? 'rotateY(180deg)' : 'rotateY(0deg)',
transition: 'transform 0.6s'
}}
>
{/* Glass effect overlay */}
<div className="absolute inset-0 bg-white/5 backdrop-blur-sm rounded-3xl pointer-events-none" />
<div className="absolute -right-10 -top-10 h-40 w-40 rounded-full bg-purple-500/20 blur-3xl" />
<div className="absolute -left-10 -bottom-10 h-40 w-40 rounded-full bg-blue-500/20 blur-3xl" />
{/* Content */}
<div className="relative z-10 flex h-full flex-col justify-between">
<div className="flex justify-between items-start">
<Nfc className="w-8 h-8 text-white/80" />
<Wifi className="h-6 w-6 rotate-90 text-white/60" />
</div>
<div className="space-y-6">
<div className="space-y-1">
<p className="font-mono text-2xl tracking-widest drop-shadow-md">{cardNumber}</p>
<p className="text-xs text-neutral-400 uppercase tracking-widest">Card Number</p>
</div>
<div className="flex justify-between items-end">
<div>
<p className="font-bold text-lg tracking-wider uppercase drop-shadow-md">{name}</p>
<p className="text-xs text-neutral-400 uppercase tracking-widest">Card Holder</p>
</div>
<div>
<p className="font-mono text-lg tracking-widest drop-shadow-md">{expiry}</p>
<p className="text-xs text-neutral-400 uppercase tracking-widest text-right">Expires</p>
</div>
</div>
</div>
</div>
</div>
{/* Card Back */}
<div
className="absolute inset-0 h-full w-full rounded-3xl bg-gradient-to-bl from-neutral-900 to-neutral-800 text-white shadow-xl backface-hidden border border-white/10"
style={{
backfaceVisibility: 'hidden',
transform: isFlipped ? 'rotateY(0deg)' : 'rotateY(180deg)',
transition: 'transform 0.6s'
}}
>
<div className="absolute top-8 w-full h-12 bg-black/80" />
<div className="absolute top-28 left-8 right-8 h-10 bg-white/10 rounded flex items-center justify-end px-4">
<span className="font-mono text-black font-bold bg-white px-2 py-1 rounded shadow-inner">{cvv}</span>
</div>
<div className="absolute bottom-8 left-8 right-8">
<p className="text-[10px] text-neutral-500 leading-tight">
This card is property of Velocity UI. By using this card, you agree to the terms and conditions. If found, please return to the nearest branch.
</p>
</div>
</div>
</motion.div>
{/* Form Controls */}
<div className="mt-12 bg-white dark:bg-neutral-800 p-6 rounded-2xl shadow-lg border border-neutral-200 dark:border-neutral-700 max-w-sm mx-auto">
<div className="space-y-4">
<div>
<label className="text-xs font-bold text-neutral-500 uppercase">Card Number</label>
<input
type="text"
value={cardNumber}
onChange={(e) => setCardNumber(e.target.value)}
className="w-full bg-transparent border-b border-neutral-300 dark:border-neutral-600 py-2 outline-none font-mono focus:border-black dark:focus:border-white transition-colors"
onFocus={() => setIsFlipped(false)}
/>
</div>
<div className="grid grid-cols-2 gap-4">
<div>
<label className="text-xs font-bold text-neutral-500 uppercase">Expiry</label>
<input
type="text"
value={expiry}
onChange={(e) => setExpiry(e.target.value)}
className="w-full bg-transparent border-b border-neutral-300 dark:border-neutral-600 py-2 outline-none font-mono focus:border-black dark:focus:border-white transition-colors"
onFocus={() => setIsFlipped(false)}
/>
</div>
<div>
<label className="text-xs font-bold text-neutral-500 uppercase">CVV</label>
<input
type="text"
value={cvv}
onChange={(e) => setCvv(e.target.value)}
className="w-full bg-transparent border-b border-neutral-300 dark:border-neutral-600 py-2 outline-none font-mono focus:border-black dark:focus:border-white transition-colors"
onFocus={() => setIsFlipped(true)}
/>
</div>
</div>
<div>
<label className="text-xs font-bold text-neutral-500 uppercase">Name</label>
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
className="w-full bg-transparent border-b border-neutral-300 dark:border-neutral-600 py-2 outline-none font-bold uppercase focus:border-black dark:focus:border-white transition-colors"
onFocus={() => setIsFlipped(false)}
/>
</div>
</div>
</div>
</div>
</div>
)
}
Dependencies
framer-motion: latestlucide-react: latestclsx: latesttailwind-merge: latest
Props
Component property reference.
| Name | Type | Default | Description |
|---|---|---|---|
| cardNumber | string | undefined | Initial card number to display. |
| expiry | string | undefined | Initial expiry date (MM/YY). |
| cvv | string | undefined | Initial CVV code. |
| name | string | undefined | Cardholder name. |
| backgroundImage | string | undefined | Optional background image URL for the card face. |
Most components here are inspired by outstanding libraries and creators in the ecosystem. I don’t claim to be the original author — this is my space for learning, rebuilding, and understanding great work at a deeper level.
I’m still a student of the craft, constantly studying the best and translating what I learn through my own perspective. Every piece reflects curiosity, respect for the community, and small creative touches that feel true to me.
I’ve done my best to credit inspirations properly. If anything is missing or inaccurate, I truly appreciate a message so it can be corrected with care.

