KQ-1585 · FLIPBOOK/PATH
Flipbook Path
A surface that turns the pointer's path into a flipbook: moving over open space lays the next page of a drawn sequence every few pixels — a paper card with a binding edge and its frame number — set down on springs.snap and leaning into the direction it was laid in, so the path becomes a fanned deck. Sweep back over the trail and the page under the pointer lifts on springs.flick with its neighbours rising a little, so the drawing plays in order under the pointer at the speed of the sweep, forward or backward; left alone, the trail clears from its oldest page. The surface is one tab stop: the arrow keys move a pen that lays and plays exactly as the pointer does, and Backspace clears the trail.
Fernworks Animation School
Every line is a frame. Draw one, then play it back.
Fernworks · open studio
move to lay frames · sweep back to play them
Install
One command — the source lands in your repo. Or copy it from the Code tab.
$ pnpm dlx shadcn@latest add @kinetiq/flipbook-path
Props
- frames
- number
- default 12
- Pages in one cycle of the drawing (4 to 24); laid pages loop through it.
- sequence
- "bounce" | "flap" | "bloom" | "orbit"
- default "bounce"
- The built-in drawing: a ball with squash and stretch, a gull's wingbeat, a flower opening and closing, a moon passing in front of and behind its planet.
- renderFrame
- (ctx: CanvasRenderingContext2D, progress: number, size: number) => void
- default —
- Your own drawing for each page, into a square `size` CSS px wide at the origin; progress runs 0 to 1 across the cycle. Replaces sequence; pages are redrawn when the function's identity changes.
- spacing
- number
- default 30
- Travel between two laid pages, px (12 to 96).
- frameSize
- number
- default 56
- Width of a page, px (24 to 96); pages are 4:5 landscape.
- fade
- number
- default 2.5
- Seconds a trail left alone takes to clear, oldest page first.
- hold
- number
- default 700
- Milliseconds a trail waits, left alone, before it starts to clear.
- lift
- number
- default 1.5
- How far the page under the pointer rises, as a scale (1 to 2).
- tilt
- number
- default 0.5
- How far pages lean into the direction they were laid in, 0 to 1.
- maxFrames
- number
- default 36
- Most pages on the surface; past it the oldest fades.
- resting
- boolean
- default true
- Lay an S-curve of pages at rest (played once by an unseen hand on first view), and lay it again whenever the trail has cleared and the pointer has left.
- paper
- string
- default "var(--card)"
- Page colour, any CSS colour.
- ink
- string
- default "var(--foreground)"
- Drawing colour.
- accent
- string
- default "var(--accent-bright)"
- The drawings' one fill colour, and the lifted page's edge.
- paused
- boolean
- default false
- Freeze the pages where they are; nothing lays, lifts or fades.
- seed
- number
- default 3
- Seeds the pages' hand-laid jitter and the resting curve.
- dpr
- number
- default 2
- Cap on the canvas's device pixel ratio, at most 2.
- disabled
- boolean
- default false
- The surface ignores the pointer and the keys, leaves the tab order and lets touch scroll.
- label
- string
- default "Flipbook path"
- The surface's accessible name.
- onFrame
- (frame: number, of: number) => void
- default —
- Fires when the page under the pointer (or the keyboard's pen) changes, with its frame (1-based) and the cycle length.
- onTrail
- (count: number, resting: boolean) => void
- default —
- Fires when the number of pages on the surface changes; resting is true when the component laid them itself.
- className
- string
- default "h-56 w-full"
- Sizes and shapes the surface; pages stay inside it.
| Prop | Type | Default | Description |
|---|---|---|---|
| frames | number | 12 | Pages in one cycle of the drawing (4 to 24); laid pages loop through it. |
| sequence | "bounce" | "flap" | "bloom" | "orbit" | "bounce" | The built-in drawing: a ball with squash and stretch, a gull's wingbeat, a flower opening and closing, a moon passing in front of and behind its planet. |
| renderFrame | (ctx: CanvasRenderingContext2D, progress: number, size: number) => void | — | Your own drawing for each page, into a square `size` CSS px wide at the origin; progress runs 0 to 1 across the cycle. Replaces sequence; pages are redrawn when the function's identity changes. |
| spacing | number | 30 | Travel between two laid pages, px (12 to 96). |
| frameSize | number | 56 | Width of a page, px (24 to 96); pages are 4:5 landscape. |
| fade | number | 2.5 | Seconds a trail left alone takes to clear, oldest page first. |
| hold | number | 700 | Milliseconds a trail waits, left alone, before it starts to clear. |
| lift | number | 1.5 | How far the page under the pointer rises, as a scale (1 to 2). |
| tilt | number | 0.5 | How far pages lean into the direction they were laid in, 0 to 1. |
| maxFrames | number | 36 | Most pages on the surface; past it the oldest fades. |
| resting | boolean | true | Lay an S-curve of pages at rest (played once by an unseen hand on first view), and lay it again whenever the trail has cleared and the pointer has left. |
| paper | string | "var(--card)" | Page colour, any CSS colour. |
| ink | string | "var(--foreground)" | Drawing colour. |
| accent | string | "var(--accent-bright)" | The drawings' one fill colour, and the lifted page's edge. |
| paused | boolean | false | Freeze the pages where they are; nothing lays, lifts or fades. |
| seed | number | 3 | Seeds the pages' hand-laid jitter and the resting curve. |
| dpr | number | 2 | Cap on the canvas's device pixel ratio, at most 2. |
| disabled | boolean | false | The surface ignores the pointer and the keys, leaves the tab order and lets touch scroll. |
| label | string | "Flipbook path" | The surface's accessible name. |
| onFrame | (frame: number, of: number) => void | — | Fires when the page under the pointer (or the keyboard's pen) changes, with its frame (1-based) and the cycle length. |
| onTrail | (count: number, resting: boolean) => void | — | Fires when the number of pages on the surface changes; resting is true when the component laid them itself. |
| className | string | "h-56 w-full" | Sizes and shapes the surface; pages stay inside it. |