This component no longer exists. It was in ruixen-ui’s manifest when we first indexed it and is not there now — the registry served its inventory on 2026-08-12 and this item was not on it. The install command below will fail. It is kept here because a tutorial somewhere still tells people to run it.
Chapter Scrubber
ruixen-ui/chapter-scrubberRemovedComponent
A vertical rail of uniform ticks that magnify toward the cursor like a dock — the lines nearest the pointer rise on a spring-driven wave and a preview card describes the crest chapter, inspired by the OpenAI Codex chapters minimap.
Live preview
live · rendered by the registry
Rendered by ruixen-ui on their own page — this is the component running, not a screenshot of it.Install it
npx shadcn@latest add https://ruixen.com/r/chapter-scrubber.jsonSource
1"use client";23import * as React from "react";4import {5 motion,6 useMotionValue,7 useReducedMotion,8 useSpring,9 useTransform,10 type MotionValue,11} from "motion/react";12import { cn } from "@/lib/utils";1314export interface Chapter {15 /** Stable, unique identifier for the chapter. */16 id: string;17 /** Bold heading shown at the top of the preview card. */18 title: string;19 /** Supporting copy shown under the title (clamped to three lines). */20 description?: React.ReactNode;21 /** Small muted label rendered above the title (e.g. a timestamp or step no.). */22 meta?: React.ReactNode;23}2425export interface ChapterScrubberProps {26 /** Chapters rendered top-to-bottom, one uniform tick each. */27 chapters: Chapter[];28 /** Which side the preview card opens toward. Auto-flips near a viewport edge. Default `"right"`. */29 side?: "left" | "right";30 /** Length a tick reaches at the crest of the magnification, in pixels. Default `56`. */31 peakLength?: number;32 /** Resting length of every tick, in pixels. Keep it small. Default `14`. */33 restLength?: number;34 /** Height of each row in pixels; the gap between ticks. Smaller = denser. Default `10`. */35 rowHeight?: number;36 /** Radius of the magnification wave, in rows — how far the rise reaches from the pointer. Default `4`. */37 radius?: number;38 /** Marks one chapter as the persistent "current" position (e.g. where an agent is now). */39 currentIndex?: number;40 /** Fires when the active (hovered/focused) chapter changes. */41 onActiveChange?: (chapter: Chapter | null, index: number) => void;42 /** Fires when a chapter is chosen via click, Enter or Space. */43 onSelect?: (chapter: Chapter, index: number) => void;44 /** Accessible name for the rail. Default `"Chapters"`. */45 label?: string;46 className?: string;47}4849const CARD_WIDTH = 260;50const GAP = 20;51// Tight, near-critically-damped spring: tracks the cursor with almost no lag52// and never overshoots — the wave feels attached to the pointer.53const POINTER_SPRING = { stiffness: 700, damping: 52, mass: 0.5 };54// Softer spring for the rise/settle so the wave swells and relaxes gracefully.55const STRENGTH_SPRING = { stiffness: 260, damping: 30, mass: 0.6 };5657function clamp(value: number, min: number, max: number) {58 return Math.min(Math.max(value, min), max);59}6061// Raised-cosine bump: 1 at the crest, 0 beyond the radius, with zero slope at62// both ends so the wave has no seams — the source of the buttery falloff.63// … truncated
What it pulls in
npm packages
