KQ-580 · SCROLL/FRAMES
Scroll Frames
A frame sequence scrubbed by scroll. The stage pins to the top of its container while a tall spacer scrolls past underneath, and the fraction already gone picks the frame — linearly, because a scrub has no physics of its own and any easing laid over it would fight the finger. Frames are drawn rather than loaded: renderFrame is handed a context already scaled to the display and sized by a ResizeObserver, and the sequence redraws itself when the box or the theme changes.
KQ-580 · SCROLL/FRAMES
01 / 32
Frame 1 of 32
Install
One command — the source lands in your repo. Or copy it from the Code tab.
$ pnpm dlx shadcn@latest add @kinetiq/scroll-frames
Props
- frames
- number
- default —
- Frame count. The last frame owns the final sliver, so a fully scrolled stage lands on the end.
- renderFrame
- (index: number, ctx: CanvasRenderingContext2D, size: { w: number; h: number }) => void
- default —
- Draws one frame in logical pixels; the retina scale and the clear are already done.
- container
- React.RefObject<HTMLElement | null>
- default —
- The scrolling element the stage is pinned inside — never the window.
- height
- number
- default 600
- Scroll distance the sequence is spread over. Minus the container's height, this is the scrub.
- label
- string
- default "Frame sequence"
- Names the canvas, which is exposed as an image.
- onFrameChange
- (index: number) => void
- default —
- Fires with the frame index whenever it changes, from scroll and from the reduced-motion scrubber alike.
| Prop | Type | Default | Description |
|---|---|---|---|
| frames | number | — | Frame count. The last frame owns the final sliver, so a fully scrolled stage lands on the end. |
| renderFrame | (index: number, ctx: CanvasRenderingContext2D, size: { w: number; h: number }) => void | — | Draws one frame in logical pixels; the retina scale and the clear are already done. |
| container | React.RefObject<HTMLElement | null> | — | The scrolling element the stage is pinned inside — never the window. |
| height | number | 600 | Scroll distance the sequence is spread over. Minus the container's height, this is the scrub. |
| label | string | "Frame sequence" | Names the canvas, which is exposed as an image. |
| onFrameChange | (index: number) => void | — | Fires with the frame index whenever it changes, from scroll and from the reduced-motion scrubber alike. |