Free 3D Scene

3D Carousel Ring

Eight panels arranged in a circle in 3D space, rotating like a carousel. The radius is calculated with trigonometry so the panels meet edge to edge.

  • dark
  • css 3d
  • carousel
  • gallery
  • animation
  • no javascript

The code

Plain HTML and CSS with no dependencies. Copy a single file, or choose "Full file" for a complete page you can save as index.html and open in a browser.

<div class="stage">
  <div class="ring">
    <div class="panel" style="--i: 0">React</div>
    <div class="panel" style="--i: 1">Next.js</div>
    <div class="panel" style="--i: 2">Node.js</div>
    <div class="panel" style="--i: 3">MongoDB</div>
    <div class="panel" style="--i: 4">Python</div>
    <div class="panel" style="--i: 5">AWS</div>
    <div class="panel" style="--i: 6">Docker</div>
    <div class="panel" style="--i: 7">AI</div>
  </div>
</div>

The AI prompt

Paste this into an AI coding tool to generate the same 3d scene, then ask it to adapt the colours, text or framework to your project.

Works with Claude · ChatGPT · Cursor · v0 · Bolt · Gemini
Create a rotating 3D carousel ring using only HTML and CSS (no JavaScript).

Requirements:
- A stage, 170px wide and 220px tall, with perspective: 1100px.
- A "ring" element with transform-style: preserve-3d that contains eight panels (labels: React, Next.js, Node.js, MongoDB, Python, AWS, Docker, AI). Give each panel an inline CSS variable --i from 0 to 7.
- Each panel is absolutely positioned to fill the stage and transformed with rotateY(calc(var(--i) * 360deg / 8)) translateZ(235px), so the eight panels form a circle. (235px is roughly (170 / 2) / tan(22.5deg) plus a small gap.)
- Panels have an 18px radius, a translucent white border, white bold text and alternate between a solid indigo gradient and a solid orange gradient. Add backface-visibility: hidden (with the -webkit- prefix) so panels facing away from the viewer are hidden and their mirrored text never shows through.
- Animate the ring with keyframes from "translateZ(-235px) rotateY(0deg)" to "translateZ(-235px) rotateY(-360deg)" over 24 seconds, linear, infinite. The negative translateZ moves the ring back so the front panel sits at the screen plane. Pause on hover.
- Respect prefers-reduced-motion by showing a static angle.
- Centre it on a dark background.

Return one HTML file with a <style> block.

How to build it, step by step

  1. 1

    Give every panel an index with an inline CSS variable (--i). One CSS rule can then position all of them.

  2. 2

    Rotate each panel around the Y axis by its share of the circle: index x (360 / number of panels).

  3. 3

    After rotating, translateZ pushes the panel outward along the direction it now faces, placing it on the circumference.

  4. 4

    Work out the radius with trigonometry: radius = (panel width / 2) / tan(180 / count). For 8 panels of 170px that is about 205px; add a little for gaps.

  5. 5

    Move the whole ring back by the same radius with translateZ(-radius) so the nearest panel is at normal size instead of zoomed in.

  6. 6

    Rotate the ring, not the panels, to spin the carousel.

  7. 7

    Add backface-visibility: hidden to the panels. Panels on the far side face away from you, so this hides them and keeps the front of the ring clean.

Customisation tips

  • Change the panel count by updating --count, the --i values and the radius formula.
  • Replace the labels with images for a 3D photo gallery.
  • Add Previous and Next buttons that change a --step variable and use rotateY(calc(var(--step) * -45deg)) with a transition instead of the animation.

More 3d scenes