crucıble

Reel

A draggable, throwable rail of media cards with momentum and detent snapping (transform-only) where off-center cards rest in a quiet duotone and the centered one blooms to full contrast. Clicking a card performs a genuine shared-element expand — media and title travel into a centered detail overlay with unbroken radii, then body copy fades up. Focus-trapped dialog with Escape, outside-click, and arrow-key rail nav; reduced motion snaps instantly.

motionpro

Installation

CLI

npx shadcn@latest add @crucible/reel

Manual — install dependencies, then copy the source

npm install motion

Props

PropTypeDefaultDescription
itemsReelItem[]Cards to arrange along the rail. Each expands into a centered overlay on click.
cardWidthnumber240Card face width in px.
cardHeightnumber320Card face height in px.
gapnumber16Gap between cards in px.
defaultIndexnumber0Index centered on first paint.
onIndexChange(index: number) => voidFires whenever the centered card changes.
onExpand(item: ReelItem, index: number) => voidFires when a card is expanded into the overlay.
onAction(item: ReelItem) => voidCalled when a non-link action button is pressed in the expanded card.
duotonebooleantrueRest off-center cards in a quiet duotone; the centered card blooms to full color.
expandedMaxWidthnumber520Expanded overlay max width in px.
closeOnOutsideClickbooleantrueClose when the backdrop is clicked.
closeOnEscapebooleantrueClose on the Escape key.
accentstring"#93c5fd"Single cool accent hex for focus rings.
labelstring"Card carousel"Accessible name for the carousel.
classNamestringExtra classes for the outer wrapper.

Honors prefers-reduced-motion with a designed static fallback, and passes className through.