3D Interactive Cards
A grid of tilt-on-hover, click-to-flip product cards with neon backdrops, call-to-action buttons, and smooth 3D transforms.
<!-- 3D card grid wrapper -->
<div class="card-grid">
<!-- Card 1 -->
<div class="card">
<div class="card-inner">
<div
class=
"card-face card-front one"
>
<div>
<h2>Quantum UI</h2>
<p>
Next-gen UI framework designed for speed, interactivity,
and effortless scalability.
</p>
</div>
<p>Tap or click to flip</p>
</div>
<!-- back face -->
<div
class=
"card-face card-back"
>
<h3>Features</h3>
<ul class="features">
<li>Lightning-fast rendering</li>
<li>Modular component system</li>
</ul>
<div class="cta-buttons">
<a href="#"
class="primary">
Get Started
</a>
<a href="#"
class="secondary">
Learn More
</a>
</div>
</div>
</div>
</div>
<!-- Cards 2–4 follow the same pattern -->
</div>
@import url("https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700&family=Inter:wght@400;600&display=swap");
:root {
--bg: #0a0c10;
--card-bg: rgba(20,25,35,0.9);
--accent: #00f5ff;
--text: #fafbfd;
}
body {
background: var(--bg);
color: var(--text);
font-family: "Inter", sans-serif;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
padding: 40px;
}
.card-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
gap: 30px;
width: 100%;
max-width: 1200px;
}
.card {
perspective: 1000px;
cursor: pointer;
}
.card-inner {
position: relative;
min-height: 360px;
transform-style: preserve-3d;
border-radius: 20px;
transition: transform .7s cubic-bezier(.4,.2,.2,1);
}
.card-face {
position: absolute;
inset: 0;
padding: 24px;
border-radius: 20px;
background: var(--card-bg);
backface-visibility: hidden;
display: flex;
flex-direction: column;
justify-content: space-between;
}
.card-back {
transform: rotateY(180deg);
}
.one {
background-image: url("https://iili.io/KSTN6ps.png");
background-size: cover;
}
/* .two, .three, .four use your other neon assets */
// Basic 3D flip + hover tilt (no duplicates)
const isTouch = "ontouchstart" in window;
document.querySelectorAll(".card").forEach((card) => {
const inner = card.querySelector(".card-inner");
// Tap / click: flip with small bounce
card.addEventListener("click", () => {
const isFlipped = card.classList.contains("flipped");
const targetFlip = isFlipped ? 0 : 180;
inner.style.transition = "transform 0.15s ease-out";
inner.style.transform = `rotateY(${targetFlip}deg) scale(1.05)`;
setTimeout(() => {
inner.style.transition =
"transform 0.7s cubic-bezier(.4,.2,.2,1)"
;
inner.style.transform = `rotateY(${targetFlip}deg) scale(1)`;
card.classList.toggle("flipped");
}, 150);
});
// Mouse-move tilt only on non-touch devices
if (!isTouch) {
card.addEventListener("mousemove", (e) => {
const rect = card.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
const centerX = rect.width / 2;
const centerY = rect.height / 2;
const tiltX = ((y - centerY) / centerY) * -10;
const tiltY = ((x - centerX) / centerX) * 10;
const flipY = card.classList.contains("flipped") ? 180 : 0;
inner.style.transform =
`rotateX(${tiltX}deg) rotateY(${flipY + tiltY}deg)`;
});
card.addEventListener("mouseleave", () => {
const flipY = card.classList.contains("flipped") ? 180 : 0;
inner.style.transform = `rotateY(${flipY}deg)`;
});
}
});