aeworks.tech/lab/carrusel-cilindro
← AE Lab

Carrusel en 3D que gira como un cilindro

14 oct 2026· nivel avanzadocarruselCSS 3Dfísica

El catálogo de una bodega colocado en un anillo 3D que giras con el dedo o el ratón: lleva inercia, frena suave y encaja en la botella más cercana, que se ilumina y enseña sus detalles. Las de detrás se ven por el revés, difuminadas.

// CÓMO ESTÁ HECHO

  1. Cada tarjeta se coloca con rotateY(i·360/N) translateZ(radio), y el radio sale de (ancho/2)/tan(π/N) para que cierren un polígono perfecto.
  2. El anillo (transform-style: preserve-3d) es lo único que gira; se inclina con rotateX para que la fila de atrás asome por encima.
  3. Cada tarjeta tiene dos caras con backface-visibility: hidden; la trasera está girada 180° y lleva un desenfoque falso con degradados y text-shadow.
  4. Al soltar se calcula la velocidad del gesto, se proyecta dónde se pararía y un muelle amortiguado lo encaja en la tarjeta más cercana.
  5. En cada fotograma se mide cuánto mira cada tarjeta hacia el frente y con eso se cambia solo la opacidad de su luz, su sombra y sus detalles.

// EL CÓDIGO

<div class="app">
  <header class="cabecera">
    <span class="marca mono">Bodega Nueve Lunas</span>
    <h1>Nuestros <span>vinos</span></h1>
    <p>Gira la bodega y descubre cada botella</p>
  </header>

  <!-- La escena es un carrusel accesible: se maneja con el teclado y anuncia la botella activa -->
  <section class="escena" id="escena" tabindex="0"
           role="region" aria-roledescription="carrusel" aria-label="Catálogo de vinos">
    <div class="suelo" aria-hidden="true"></div>
    <div class="anillo" id="anillo"></div>
  </section>

  <footer class="pie">
    <div class="controles">
      <button class="btn" id="anterior" type="button" aria-label="Vino anterior">
        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M15 5l-7 7 7 7"/></svg>
      </button>
      <span class="contador" id="contador"><b>01</b> / 08</span>
      <button class="btn" id="siguiente" type="button" aria-label="Vino siguiente">
        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 5l7 7-7 7"/></svg>
      </button>
    </div>
    <span class="pista">Arrastra para girar · <kbd>←</kbd> <kbd>→</kbd></span>
    <p class="solo-lectores" id="anuncio" aria-live="polite"></p>
  </footer>
</div>