Filmstrip Scrub
motiq/filmstrip-scrubFreeComponent
A filmstrip with a spring-loaded playhead (k=90, c=16, ζ≈0.84 — one soft overshoot): hover or drag the strip and the large preview crossfades ⌊p⌋ into ⌈p⌉ by the fractional part, with frame ticks and a monospace timecode. Scrubs itself at 0.9 frames/s when idle. The strip is a real slider with arrow/Home/End keys.
Live preview
live · rendered by the registry
Rendered by motiq on their own page — this is the component running, not a screenshot of it.Install it
npx shadcn@latest add https://www.motiq.dev/r/filmstrip-scrub.jsonSource
1"use client";23import * as React from "react";45import { cn } from "@/lib/utils";6import { useControllableState, useReducedMotion, useVisibilityPause } from "@/lib/motiq";78/* -------------------------------------------------------------------------- */9/* Types */10/* -------------------------------------------------------------------------- */1112export interface FilmstripFrame {13 /** Stable key. */14 id: string;15 /** Image URL rendered as a plain `<img>` (use `node` for anything richer). */16 src?: string;17 /** Alternative text for `src`. */18 alt?: string;19 /** Arbitrary frame content — takes precedence over `src`. */20 node?: React.ReactNode;21 /** Short phase name shown in the readout (e.g. "dawn", "step 3"). */22 label?: string;23}2425export interface FilmstripScrubProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "onChange"> {26 /** 8–24 stills read best. */27 frames: FilmstripFrame[];28 /** Timecode base used by the monospace readout. */29 fps?: number;30 /** Idle auto-scrub speed in frames/s (0 disables autoplay). */31 idleSpeed?: number;32 /** Playhead spring stiffness — 90/16 lands with one soft overshoot (ζ≈0.84). */33 stiffness?: number;34 /** Playhead spring damping. */35 damping?: number;36 /** Scrub on hover as well as drag. */37 hoverScrub?: boolean;38 /** Ping-pong the idle scrub at the ends instead of stopping. */39 loop?: boolean;40 /** Seconds of stillness before autoplay resumes. */41 resumeAfter?: number;42 /** Controlled frame index. */43 frameIndex?: number;44 /** Uncontrolled initial frame index. */45 defaultFrameIndex?: number;46 /** Fires when the nearest frame changes. */47 onFrameIndexChange?: (index: number) => void;48 /** Accessible name for the scrubber. */49 scrubberLabel?: string;50 /** Force the still variant regardless of system preference. */51 reducedMotion?: boolean;52 /** Stop the rAF loop while scrolled offscreen or the tab is hidden. */53 pauseWhenHidden?: boolean;54}5556/* -------------------------------------------------------------------------- */57/* Constants (Motion Lab ship spec) */58/* -------------------------------------------------------------------------- */5960const SPRING_K = 90;61const SPRING_C = 16;62const IDLE_SPEED = 0.9;63const RESUME_AFTER = 3;64const FPS = 24;65/** Frame-tick divisions drawn under the strip. */66const TICKS = 48;6768// … truncated
What it pulls in
Other registry items
Files it writes
More from motiq
All 100 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Activity Streamactivity-stream | motiq | Components | Free | 1 dep | |
| Adaptive Safe-Zone Gridadaptive-safe-zone-grid | motiq | Components | Free | no deps | |
| Agent Run Timelineagent-run-timeline | motiq | Components | Free | 1 dep | |
| AI Response Streamai-response-stream | motiq | Components | Free | 1 dep | |
| Animated Accordionanimated-accordion | motiq | Components | Free | 2 deps | |
| Animated Buttonanimated-button | motiq | Components | Free | 1 dep | |
| Animated Dialoganimated-dialog | motiq | Components | Free | 2 deps | |
| Animated Gridanimated-grid | motiq | Components | Free | 2 deps |
