Ripple Scene Gallery
ericts-ui/ripple-sceneFreeBlock
An immersive scene selector whose photo lifts into a travelling corrugated wave, swapping to the next scene at the crest before settling flat.
Install it
npx shadcn@latest add https://ui.ericts.com/r/ripple-scene.jsonSource
1"use client";23import * as React from "react";45import { RailList, type RailListItem } from "@/components/ui/rail-list";6import { useReducedMotion } from "@/hooks/use-reduced-motion";7import { cn } from "@/lib/utils";89import "./ripple-scene.css";1011export type RippleSceneImage = {12 src: string;13 alt: string;14};1516export type RippleSceneItem = {17 /** Stable value used by controlled state and callbacks. */18 value: string;19 /** Short label rendered in the horizontal selector. */20 label: string;21 /** Main scene heading. */22 title: string;23 /** Optional supporting copy below the heading. */24 description?: string;25 /** Optional context shown above the heading. */26 overline?: string;27 image: RippleSceneImage;28 imagePosition?: React.CSSProperties["objectPosition"];29};3031export interface RippleSceneProps32 extends Omit<React.ComponentPropsWithoutRef<"section">, "onChange"> {33 items: readonly RippleSceneItem[];34 /** Controlled selected scene value. */35 value?: string;36 /** Initial selected scene value for uncontrolled usage. */37 defaultValue?: string;38 /** Called when a scene is selected. */39 onValueChange?: (value: string, item: RippleSceneItem) => void;40 /** Accessible label for the scene selector. */41 selectorLabel?: string;42 /** Small persistent label in the stage header. */43 stageLabel?: string;44 /** Message displayed when no scenes are provided. */45 emptyLabel?: string;46}4748/** Number of vertical strips the wave is built from. */49const STRIP_COUNT = 12;50/** Per-strip delay that makes the wave travel across the scene. */51const STRIP_STAGGER_MS = 26;52/**53 * animationName of a strip's ripple. When the last strip in the wave54 * finishes, the new scene is promoted to the static base layer. Must match55 * the CSS keyframes name.56 */57const RIPPLE_SETTLE_ANIMATION = "ripple-scene-strip";58/**59 * Safety net for when animationend never arrives (hidden tabs pause CSS60 * animations; user styles may disable them). Must exceed the full wave:61 * strip duration + last strip's delay.62 */63const SETTLE_FALLBACK_MS = 1600;6465type MediaStage = {66 /** Scene rendered as the static, untransformed base layer. */67 base: string;68 /** Scene currently rippling in above the base, if any. */69 incoming: string | null;70};7172export function RippleScene({73 items,74 value,75 defaultValue,76 onValueChange,77 selectorLabel = "Choose a scene",78 stageLabel = "Selected stories",79 emptyLabel = "No scenes available",80 className,81 ...props82}: RippleSceneProps) {83// … truncated
What it pulls in
Other registry items
Files it writes
More from ericts-ui
All 38 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Scroll Expand & Focus Heroscroll-expand | ericts-ui | Blocks | Free | no deps · 2 files | |
| Vertical Scene Galleryvertical-scene | ericts-ui | Blocks | Free | 1 dep · 2 files |
