23rd logo23rd

Ring Tower

A tower of tilted bands wrapped in your images. Drag to spin it; the pointer turns neighboring bands opposite ways.

Installation

pnpm dlx shadcn@latest add @23rd/ring-tower

Or from the public GitHub registry:

pnpm dlx shadcn@latest add radiumcoders/23rd.dev/ring-tower

Installs three alongside the component.

Usage

Pin it inside a relatively positioned section with a height. The canvas is transparent, so give the section a background. The inside of the bands fades toward black in dark mode and white in light mode, following the page unless you set theme. Each band leans a quarter turn from the last, so the stack zig-zags past the edges of the frame.

"use client"

import { RingTower } from "@/components/ui/ring-tower"

const bands = ["/bands/0.jpg", "/bands/1.jpg", "/bands/2.jpg"]

export function Hero() {
  return (
    <section className="relative isolate h-svh overflow-hidden bg-background">
      <RingTower images={bands} />
      <div className="pointer-events-none absolute inset-x-0 bottom-0 h-1/2 bg-linear-to-t from-background to-transparent" />
    </section>
  )
}

Images are drawn side by side at one height and repeated in whole tiles around each band, then cropped top and bottom to keep their proportions. Images on another origin need CORS headers, or they are skipped. With no images, or if none load, the bands show a plain green grid.

Every band in step, like the original:

<RingTower images={bands} parallax={0} />

Each ring

Pass rings an array instead of a number to set each ring on its own, bottom ring first. The array's length is the ring count, up to 5. Anything a ring leaves out follows the tower, so {} is a plain ring.

<RingTower
  images={bands}
  rings={[
    {},
    { tilt: -20, spin: 30 },
    { rotation: 45, speed: -1.5, images: ["/bands/feature.jpg"] },
  ]}
/>
Ring fieldTypeDefault
rotationnumberi * 90, degrees; which way the ring leans
tiltnumber14, degrees, −45–45
spinnumber0, degrees per second, −180–180; sweeps the lean around
speednumberthe tower's speed, −4–4; negative crawls backwards
parallaxnumberthe tower's parallax, alternating direction; degrees, −90–90
imagesstring[]the tower's images

Props

PropTypeDefault
imagesstring[]none, draws a grid band
ringsnumber | RingTowerRing[]5, 1–5, or one object per ring
speednumber1, 0–4 crawl speed
draggablebooleantrue
parallaxnumber24, degrees, 0–90
backfacenumber0.86, inside fade, 0–1
theme"light" | "dark" | "auto"auto
classNamestringnone