Orbital Image Wheel
Scroll-driven half-wheel image layout pinned to the bottom area of the viewport, with GSAP focus effects and animated active captions.
Installation
File Structure
Usage
import { OrbitalImageWheel } from "@/components/unlumen-ui/orbital-image-wheel";
const images = [
{
src: "/photos/01.jpg",
alt: "Capsule pack",
label: "Capsule",
subtitle: "Precision delivery",
},
{
src: "/photos/02.jpg",
alt: "Lab interior",
label: "Lab",
subtitle: "AI diagnostics",
},
{
src: "/photos/03.jpg",
alt: "Clinical scan",
label: "Vision",
subtitle: "Predictive screening",
},
];
export default function Example() {
return <OrbitalImageWheel images={images} />;
}With custom subtitle animation controls
<OrbitalImageWheel
images={images}
subtitleDirection="bottom"
subtitleSpeed={1.25}
subtitleStagger={0.014}
/>With a custom scroll container
If your layout scrolls inside a container (overflow-y-auto) instead of the viewport, pass scrollContainerRef so GSAP ScrollTrigger uses the correct scroller.
"use client";
import { useRef } from "react";
import { OrbitalImageWheel } from "@/components/unlumen-ui/orbital-image-wheel";
export default function ScrollContainerExample() {
const scrollRef = useRef<HTMLDivElement>(null);
return (
<div ref={scrollRef} className="h-[80vh] overflow-y-auto">
<OrbitalImageWheel images={images} scrollContainerRef={scrollRef} />
</div>
);
}Tuning wheel geometry and pacing
<OrbitalImageWheel
images={images}
turns={2.4}
wheelSize={1800}
cropRatio={0.7}
itemWidth={260}
itemHeight={340}
scrollLength={360}
focusSpread={0.28}
scrollSensitivity={0.62}
/>API Reference
imagesOrbitalImageWheelImage[]—Array of image objects. Each item supports `src`, optional `alt`, optional `label`, and optional `subtitle`.
turns?number4Number of full wheel rotations during the scroll range.
blur?number4Maximum blur in pixels for out-of-focus cards.
dim?number40Minimum brightness percentage away from focus.
brightnessBoost?number30Extra brightness around the active focus card.
darknessStrength?number1.05Multiplier for out-of-focus darkening intensity.
minSaturation?number55Minimum saturation percentage away from focus.
saturationStrength?number0.6Multiplier for desaturation intensity away from focus.
focusSpread?number0.34Normalized angular width of the focus window.
scaleEffect?number0.06Scale reduction applied as cards move away from focus.
scrollSensitivity?number0.7Scroll sensitivity multiplier. Lower values require longer scrolling.
itemWidth?number220Card width in pixels.
itemHeight?number300Card height in pixels.
wheelSize?number—Optional fixed wheel diameter in pixels. When omitted, the wheel size is responsive.
cropRatio?number0.75How much of the wheel remains below the viewport. `0.5` keeps only the top half visible.
scrollLength?number330Section height in `vh`. Increase it to slow down the wheel progression.
captionOffset?number15Bottom offset of the centered caption block in viewport units.
showCaption?booleantrueShow or hide the centered active caption.
subtitleDirection?"top" | "bottom""top"Direction used by the subtitle character reveal animation.
subtitleSpeed?number1Speed multiplier for the subtitle animation (`> 1` is faster, `< 1` is slower).
subtitleStagger?number0.018Delay between subtitle character reveals, in seconds.
scrollContainerRef?RefObject<HTMLElement | null>—Optional ref to a custom scroll container. Use this for inner `overflow-y-auto` previews.
className?string—Additional classes applied to the root section.
How it works
The component combines GSAP ScrollTrigger and geometric transforms to simulate a cinematic wheel:
- A large circular layout is positioned below the viewport, so only its top arc is visible.
- Scroll progress rotates virtual card angles around the circle.
- Each card receives position, depth, tilt, blur, brightness, saturation, and scale based on its angular distance from the top focus anchor.
- The active index is stabilized with hysteresis to reduce jitter around boundaries.
- The caption updates from the active item and keeps the title pill centered with dynamic edge spacers.
Caption behavior
- Subtitle source:
image.subtitle->image.alt->"Visual Story" - Title source:
image.label->image.alt-> fallback"Image N" - Subtitle animation is delegated to
MotionSubtitlevia registry dependency (@unlumen-ui/motion-subtitle).
Tuning guide
- Slower wheel motion:
increase
scrollLengthand/or decreasescrollSensitivity. - Stronger foreground/background separation:
increase
blur,darknessStrength,saturationStrength, orbrightnessBoost. - Softer effect:
reduce
blur, raisedim, and reducescaleEffect. - More centered focus window:
lower
focusSpreadfor tighter spotlight, raise for broader spotlight. - More/less visible wheel arc:
lower
cropRatioto show more of the wheel, raise it to hide more below the fold.
Notes
- The wheel center is anchored below the viewport so only its upper arc is visible.
- Clicking a title pill animates scroll to the corresponding image position.
- Captions are derived from the active image with built-in fallbacks.
- Uses GSAP ScrollTrigger for wheel motion and Motion for subtitle text animation.
- Works with viewport scroll and with custom scrollers through
scrollContainerRef.
Credits
Built by leo.
Keep in mind
Most components on this site are inspired by or recreated from existing work across the web. I'm not here to take credit; just to learn, experiment, and sometimes push things a bit further. If something looks familiar and I forgot to mention you, reach out and I'll fix that right away.
This component is part of Unlumen UI [ Pro ]
Includes advanced motion, patterns, and premium support.