9 CSS 3D Designs 07 / 09

Obsidian Vault

Three floating jewel product cards (Amethyst, Sapphire, Ruby) hover-flip in a dark atmospheric void with drifting gold-dust particles.

Best forluxury e-commerce, high-end jewelry brands, watchmaker product pages, premium collectible drops.

CSS + JS MIT licensed
Live Demo Open in tab
Open in playground

The code

<section class="cd-obs" aria-label="Obsidian Vault luxury cards demo">
  <div class="card">
    <div class="cd-obs-bg" aria-hidden="true"></div>
    <div class="cd-obs-floor" aria-hidden="true"></div>

    <div class="scene" data-cd-obs-scene>

      <article class="obs-card">
        <div class="face front">
          <span class="series-label">Collection I</span>
          <div class="gem-stage" style="--glow:rgba(148,80,230,0.85); --g-light:#c8a0f8; --g-mid:#8844e0; --g-dark:#4820a8;">
            <div class="gem-body">
              <div class="gem-table"></div>
              <div class="gem-crown-left"></div>
              <div class="gem-crown-right"></div>
            </div>
          </div>
          <div class="gem-name">Amethyst<br />Nocturne</div>
          <div class="gem-divider"></div>
          <div class="gem-price">$ 4,200</div>
          <div class="gem-dots">
            <div class="gem-dot active"></div>
            <div class="gem-dot active"></div>
            <div class="gem-dot active"></div>
            <div class="gem-dot"></div>
            <div class="gem-dot"></div>
          </div>
        </div>
        <div class="face back">
          <span class="back-ornament">◈</span>
          <span class="back-brand">Obsidian</span>
          <div class="back-rule"></div>
          <p class="back-description">A rare Zambian amethyst, set in cold-forged 18k white gold. Each stone selected for its violet depth and natural clarity.</p>
          <button class="back-cta" type="button">Acquire</button>
          <span class="back-sub">Limited Edition · No. 12 of 30</span>
        </div>
      </article>

      <article class="obs-card">
        <div class="face front">
          <span class="series-label">Collection II</span>
          <div class="gem-stage" style="--glow:rgba(30,140,240,0.85); --g-light:#80d0ff; --g-mid:#2888d8; --g-dark:#0c4a98;">
            <div class="gem-body">
              <div class="gem-table"></div>
              <div class="gem-crown-left"></div>
              <div class="gem-crown-right"></div>
            </div>
          </div>
          <div class="gem-name">Sapphire<br />Meridian</div>
          <div class="gem-divider"></div>
          <div class="gem-price">$ 7,800</div>
          <div class="gem-dots">
            <div class="gem-dot active"></div>
            <div class="gem-dot active"></div>
            <div class="gem-dot active"></div>
            <div class="gem-dot active"></div>
            <div class="gem-dot"></div>
          </div>
        </div>
        <div class="face back">
          <span class="back-ornament">◈</span>
          <span class="back-brand">Obsidian</span>
          <div class="back-rule"></div>
          <p class="back-description">Ceylon blue sapphire, untreated and certified. Suspended in a hand-finished platinum bezel, worn by the extraordinarily few.</p>
          <button class="back-cta" type="button">Acquire</button>
          <span class="back-sub">Limited Edition · No. 7 of 20</span>
        </div>
      </article>

      <article class="obs-card">
        <div class="face front">
          <span class="series-label">Collection III</span>
          <div class="gem-stage" style="--glow:rgba(228,55,50,0.85); --g-light:#ff9888; --g-mid:#d83030; --g-dark:#7a1018;">
            <div class="gem-body">
              <div class="gem-table"></div>
              <div class="gem-crown-left"></div>
              <div class="gem-crown-right"></div>
            </div>
          </div>
          <div class="gem-name">Ruby<br />Solstice</div>
          <div class="gem-divider"></div>
          <div class="gem-price">$ 12,400</div>
          <div class="gem-dots">
            <div class="gem-dot active"></div>
            <div class="gem-dot active"></div>
            <div class="gem-dot active"></div>
            <div class="gem-dot active"></div>
            <div class="gem-dot active"></div>
          </div>
        </div>
        <div class="face back">
          <span class="back-ornament">◈</span>
          <span class="back-brand">Obsidian</span>
          <div class="back-rule"></div>
          <p class="back-description">Burmese pigeon-blood ruby of extraordinary rarity. Each stone handpicked, individually documented, and signed by the master craftsman.</p>
          <button class="back-cta" type="button">Acquire</button>
          <span class="back-sub">Singular Edition · No. 1 of 8</span>
        </div>
      </article>

    </div>
  </div>
</section>
/* ─── 01 Obsidian Vault — luxury product cards ─────────────── */
@import url('https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,300;0,400;0,600;1,300;1,400&family=Cinzel:wght@400;600;700&display=swap');

.cd-obs {
  --cd-obs-bg: #060309;
  --cd-obs-gold: rgba(212, 168, 52, 0.85);

  position: relative;
  width: 100%;
  height: 560px;
  background: var(--cd-obs-bg);
  font-family: 'Cormorant Garamond', serif;
  overflow: hidden;
  perspective: 1600px;
  box-sizing: border-box;
}

.cd-obs *,
.cd-obs *::before,
.cd-obs *::after { box-sizing: border-box; margin: 0; padding: 0; }

.cd-obs .card {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* Atmospheric background — scoped to wrapper, not body */
.cd-obs .cd-obs-bg {
  position: absolute;
  inset: 0;
  pointer-events: none;
}
.cd-obs .cd-obs-bg::before {
  content: '';
  position: absolute;
  inset: 0;
  background:
    radial-gradient(ellipse 55% 55% at 18% 38%, rgba(90, 25, 150, 0.18) 0%, transparent 65%),
    radial-gradient(ellipse 45% 45% at 82% 62%, rgba(170, 80, 15, 0.13) 0%, transparent 65%),
    radial-gradient(ellipse 35% 50% at 50% 85%, rgba(15, 50, 90, 0.10) 0%, transparent 70%);
}
.cd-obs .cd-obs-bg::after {
  content: '';
  position: absolute;
  inset: 0;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='300' height='300'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.75' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='1'/%3E%3C/svg%3E");
  opacity: 0.028;
  background-size: 300px 300px;
}

/* Floor reflection */
.cd-obs .cd-obs-floor {
  position: absolute;
  bottom: 0; left: 0; right: 0;
  height: 180px;
  background: linear-gradient(to top, rgba(212,168,52,0.04) 0%, transparent 100%);
  pointer-events: none;
}

/* Scene */
.cd-obs .scene {
  display: flex;
  gap: 30px;
  align-items: center;
  transform-style: preserve-3d;
  position: relative;
  z-index: 1;
  will-change: transform;
}

.cd-obs .obs-card {
  width: 196px;
  height: 288px;
  position: relative;
  transform-style: preserve-3d;
  cursor: pointer;
  transition: transform 1s cubic-bezier(0.175, 0.885, 0.32, 1.275);
}
.cd-obs .obs-card:nth-child(1) { animation: cd-obs-float-a 6.4s ease-in-out infinite; }
.cd-obs .obs-card:nth-child(2) { animation: cd-obs-float-b 7.6s ease-in-out infinite -2.1s; }
.cd-obs .obs-card:nth-child(3) { animation: cd-obs-float-c 5.8s ease-in-out infinite -1.4s; }

@keyframes cd-obs-float-a { 0%,100%{transform:translateY(0) translateZ(0)} 50%{transform:translateY(-18px) translateZ(10px)} }
@keyframes cd-obs-float-b { 0%,100%{transform:translateY(-8px) translateZ(0)} 50%{transform:translateY(-24px) translateZ(12px)} }
@keyframes cd-obs-float-c { 0%,100%{transform:translateY(-4px) translateZ(0)} 50%{transform:translateY(-20px) translateZ(8px)} }

.cd-obs .obs-card:hover { transform: rotateY(180deg) translateZ(30px) !important; animation-play-state: paused; }

.cd-obs .face {
  position: absolute;
  inset: 0;
  border-radius: 20px;
  backface-visibility: hidden;
  overflow: hidden;
}

/* Front */
.cd-obs .front {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 26px 20px 22px;
  background: linear-gradient(148deg, #140c20 0%, #0c091a 42%, #160c22 100%);
  border: 1px solid rgba(212, 168, 52, 0.22);
  box-shadow:
    0 0 0 1px rgba(212,168,52,0.05),
    0 50px 100px rgba(0,0,0,0.85),
    0 25px 50px rgba(0,0,0,0.6),
    inset 0 1.5px 0 rgba(212,168,52,0.20),
    inset 0 -1px 0 rgba(0,0,0,0.5);
}
.cd-obs .front::before {
  content: '';
  position: absolute;
  top: 0; left: 14%; right: 14%;
  height: 1px;
  background: linear-gradient(90deg, transparent, rgba(212,168,52,0.9), transparent);
}
.cd-obs .front::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 20px;
  background: radial-gradient(ellipse 90% 55% at 50% 18%, rgba(212,168,52,0.08) 0%, transparent 60%);
  pointer-events: none;
}

.cd-obs .series-label {
  font-family: 'Cinzel', serif;
  font-size: 9px;
  letter-spacing: 4.5px;
  color: rgba(212,168,52,0.72);
  text-transform: uppercase;
  z-index: 1;
}

/* Gem */
.cd-obs .gem-stage {
  width: 88px;
  height: 100px;
  margin: 16px auto 12px;
  position: relative;
  z-index: 1;
  animation: cd-obs-gem-breathe 3.5s ease-in-out infinite;
}
@keyframes cd-obs-gem-breathe {
  0%,100% { filter: drop-shadow(0 0 10px var(--glow)) drop-shadow(0 0 25px var(--glow)); transform: scale(1); }
  50%     { filter: drop-shadow(0 0 18px var(--glow)) drop-shadow(0 0 42px var(--glow)); transform: scale(1.04); }
}
.cd-obs .gem-body {
  width: 88px;
  height: 100px;
  background: linear-gradient(162deg, var(--g-light) 0%, var(--g-mid) 38%, var(--g-dark) 100%);
  clip-path: polygon(50% 0%, 88% 32%, 100% 56%, 50% 100%, 0% 56%, 12% 32%);
  position: relative;
}
.cd-obs .gem-body::before {
  content: '';
  position: absolute;
  inset: 0;
  clip-path: polygon(50% 0%, 88% 32%, 100% 56%, 50% 100%, 0% 56%, 12% 32%);
  background: linear-gradient(42deg, transparent 28%, rgba(255,255,255,0.14) 46%, rgba(255,255,255,0.03) 56%, transparent 68%);
  animation: cd-obs-shimmer-a 4.2s ease-in-out infinite;
}
.cd-obs .gem-body::after {
  content: '';
  position: absolute;
  inset: 0;
  clip-path: polygon(50% 0%, 88% 32%, 100% 56%, 50% 100%, 0% 56%, 12% 32%);
  background: linear-gradient(210deg, transparent 30%, rgba(255,255,255,0.08) 48%, transparent 62%);
  animation: cd-obs-shimmer-b 5.8s ease-in-out infinite;
}
@keyframes cd-obs-shimmer-a { 0%,100%{opacity:1} 50%{opacity:0.4} }
@keyframes cd-obs-shimmer-b { 0%,100%{opacity:0.3} 50%{opacity:1} }

.cd-obs .gem-table {
  position: absolute;
  top: 14%;
  left: 50%;
  transform: translateX(-50%);
  width: 44px;
  height: 14px;
  clip-path: polygon(50% 0%, 100% 100%, 0% 100%);
  background: linear-gradient(to bottom, rgba(255,255,255,0.35), rgba(255,255,255,0.08));
}
.cd-obs .gem-crown-left,
.cd-obs .gem-crown-right {
  position: absolute;
  top: 0;
  width: 0; height: 0;
}
.cd-obs .gem-crown-left {
  left: 12%;
  border-left: 10px solid transparent;
  border-right: 10px solid transparent;
  border-bottom: 22px solid rgba(255,255,255,0.09);
}
.cd-obs .gem-crown-right {
  right: 12%;
  border-left: 10px solid transparent;
  border-right: 10px solid transparent;
  border-bottom: 22px solid rgba(255,255,255,0.09);
}

.cd-obs .gem-name {
  font-family: 'Cormorant Garamond', serif;
  font-size: 22px;
  font-weight: 300;
  color: #ede4f8;
  text-align: center;
  line-height: 1.3;
  letter-spacing: 0.4px;
  z-index: 1;
}
.cd-obs .gem-divider {
  width: 38px;
  height: 1px;
  background: linear-gradient(90deg, transparent, rgba(212,168,52,0.75), transparent);
  margin: 12px 0 10px;
  z-index: 1;
}
.cd-obs .gem-price {
  font-family: 'Cinzel', serif;
  font-size: 12px;
  letter-spacing: 2.5px;
  color: rgba(232,208,135,0.88);
  z-index: 1;
}
.cd-obs .gem-dots {
  display: flex;
  gap: 5px;
  margin-top: 8px;
  z-index: 1;
}
.cd-obs .gem-dot {
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: rgba(212,168,52,0.5);
}
.cd-obs .gem-dot.active { background: rgba(212,168,52,0.95); box-shadow: 0 0 6px rgba(212,168,52,0.8); }

/* Back */
.cd-obs .back {
  transform: rotateY(180deg);
  background: linear-gradient(152deg, #100c1e 0%, #0c0818 52%, #140a20 100%);
  border: 1px solid rgba(212,168,52,0.18);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 28px 24px;
  gap: 0;
}
.cd-obs .back::before {
  content: '';
  position: absolute;
  inset: 10px;
  border: 1px solid rgba(212,168,52,0.09);
  border-radius: 12px;
}
.cd-obs .back-ornament {
  font-size: 8px;
  color: rgba(212,168,52,0.4);
  position: absolute;
  top: 20px;
  left: 24px;
}
.cd-obs .back-brand {
  font-family: 'Cinzel', serif;
  font-size: 9px;
  letter-spacing: 7px;
  color: rgba(212,168,52,0.62);
  margin-bottom: 20px;
}
.cd-obs .back-rule {
  width: 28px;
  height: 1px;
  background: rgba(212,168,52,0.35);
  margin-bottom: 20px;
}
.cd-obs .back-description {
  font-family: 'Cormorant Garamond', serif;
  font-size: 13.5px;
  font-weight: 300;
  font-style: italic;
  color: rgba(210,198,228,0.7);
  text-align: center;
  line-height: 1.82;
  margin-bottom: 22px;
}
.cd-obs .back-cta {
  padding: 9px 26px;
  border: 1px solid rgba(212,168,52,0.38);
  background: rgba(212,168,52,0.04);
  color: rgba(212,168,52,0.88);
  font-family: 'Cinzel', serif;
  font-size: 9px;
  letter-spacing: 4px;
  cursor: pointer;
  border-radius: 2px;
  transition: background 0.35s, border-color 0.35s;
  margin-bottom: 16px;
}
.cd-obs .back-cta:hover { background: rgba(212,168,52,0.10); border-color: rgba(212,168,52,0.6); }
.cd-obs .back-sub {
  font-family: 'Cormorant Garamond', serif;
  font-size: 11px;
  color: rgba(180,170,200,0.4);
  letter-spacing: 1.5px;
  font-style: italic;
}

/* Particles — injected by JS, position:absolute inside wrapper */
.cd-obs .cd-obs-particle {
  position: absolute;
  border-radius: 50%;
  pointer-events: none;
  z-index: 0;
  animation: cd-obs-p-rise var(--pd) linear infinite var(--dl);
}
@keyframes cd-obs-p-rise {
  0%   { transform: translateY(20px) scale(0); opacity: 0; }
  8%   { opacity: var(--op); transform: translateY(0) scale(1); }
  85%  { opacity: calc(var(--op) * 0.4); }
  100% { transform: translateY(-90px) scale(0.4); opacity: 0; }
}

@media (max-width: 720px) {
  .cd-obs { height: 640px; }
  .cd-obs .scene { flex-direction: column; gap: 18px; }
  .cd-obs .obs-card { width: 168px; height: 248px; }
}

@media (prefers-reduced-motion: reduce) {
  .cd-obs .obs-card,
  .cd-obs .gem-stage,
  .cd-obs .gem-body::before,
  .cd-obs .gem-body::after,
  .cd-obs .cd-obs-particle { animation: none !important; }
  .cd-obs .scene { transform: none !important; }
}
(() => {
  const root = document.querySelector('.cd-obs');
  if (!root) return;
  const scene = root.querySelector('[data-cd-obs-scene]');
  if (!scene) return;

  // Particles — appended to wrapper, not document.body
  const prefersReduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
  if (!prefersReduced) {
    for (let i = 0; i < 36; i++) {
      const p = document.createElement('div');
      p.className = 'cd-obs-particle';
      const sz = Math.random() * 2.2 + 0.4;
      p.style.cssText = `
        width: ${sz}px; height: ${sz}px;
        left: ${Math.random() * 100}%;
        top: ${Math.random() * 100}%;
        background: rgba(212,168,52,${Math.random() * 0.5 + 0.1});
        --pd: ${Math.random() * 12 + 8}s;
        --dl: ${-Math.random() * 20}s;
        --op: ${Math.random() * 0.55 + 0.1};
      `;
      root.appendChild(p);
    }
  }

  // Mouse parallax scoped to the wrapper
  let tRx = 0, tRy = 0, cRx = 0, cRy = 0, rafId = null;

  root.addEventListener('mousemove', e => {
    const rect = root.getBoundingClientRect();
    tRx = ((e.clientY - rect.top) / rect.height - 0.5) * 18;
    tRy = ((e.clientX - rect.left) / rect.width - 0.5) * 24;
    if (!rafId && !prefersReduced) rafId = requestAnimationFrame(animate);
  });
  root.addEventListener('mouseleave', () => {
    tRx = 0; tRy = 0;
  });

  function animate() {
    cRx += (tRx - cRx) * 0.06;
    cRy += (tRy - cRy) * 0.06;
    scene.style.transform = `rotateX(${cRx}deg) rotateY(${cRy}deg)`;
    if (Math.abs(tRx - cRx) > 0.05 || Math.abs(tRy - cRy) > 0.05) {
      rafId = requestAnimationFrame(animate);
    } else {
      rafId = null;
    }
  }
})();

Search CodeFronts

Loading…