KQ-1125 · FILTER/SWIPE

Filter Swipe

A photo whose look changes as you swipe across it: the boundary between the current look and the incoming one sits under the finger 1:1 with the incoming look's name riding it, and a release that carries or throws it past the threshold runs on to the far edge on the glide spring with the release velocity, while a short one slides back. The incoming look is the same picture under another CSS filter, revealed by a mask that is crisp or feathered, and past the first or last look the picture rubber-bands. The looks are also a radio group of dots whose arrow keys slide each look in from the side a swipe would, with the same swish and click.

KQ-1125 · FILTER/SWIPE

Swipe across the picture for the next or previous look. Arrow keys choose a look, Home and End the first and last.

look · original · 1 of 5 · swipe across

Install

One command — the source lands in your repo. Or copy it from the Code tab.

$ pnpm dlx shadcn@latest add @kinetiq/filter-swipe

Props

children
ReactNode
default —
The picture. It is drawn twice, the look underneath and the look coming in, so keep ids out of it.
alt
string
default —
What the picture shows: its accessible name, followed by the current look ("Coldbrook harbour at dawn, Harvest look").
filters
"film" | "mono" | "tone" | { name: string; filter: string }[]
default "film"
A built-in set of five looks, or your own list of named CSS filter values. Names must be unique.
value / defaultValue
number
default 0
The look on the photo, by index. Controlled or uncontrolled; a slide runs on while the value agrees with it and slides back when it does not.
onValueChange
(index: number, look: FilterSwipeLook) => void
default —
Fires from the release, key or dot that chose a look, with its index and the look.
threshold
number
default 0.5
How far across the boundary must be carried, or thrown, to commit: 0.2 to 0.8 of the width, judged on the projected throw. Notches on the frame's edges mark it while dragging.
label
boolean
default true
The incoming look's name rides the boundary in a pill that turns light once a release would commit, and the current look's name sits in the corner at rest.
edge
"hard" | "soft"
default "hard"
A crisp boundary with a light rule on it, or a feathered blend with no rule.
sound
boolean
default false
A swish as a released slide sets off (higher and louder when it commits, low and soft when it goes back) and a click on the frame the new look lands. Nothing plays, and no audio context exists, unless this is on.
disabled
boolean
default false
Dims the photo and ignores swipes, dots and keys.
className
string
default —
Merged onto the frame's classes; the frame is w-full at 4:3 unless an aspect class here says otherwise.