3D Interactive Cards

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.

  • Built with HTML, CSS, and vanilla JavaScript
  • 3D flip animation + pointer-based tilt
  • Responsive grid using auto-fit
HTML

<!-- 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>
CSS

@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 */
JavaScript

// 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)`;
    });
  }
});