KQ-1370 · PIGMENT/FLOW
Pigment Flow
Gradient text that behaves like pigment let into water: soft clouds of each colour wander seeded paths through the letters over a thinner wash of them all, every gradient mixed in oklab, all of it pure CSS on clipped text with motion values driving the stops. On arrival a drop blooms from the middle of the plain ink on a critically damped spring sized by duration (springs.drift at the default), and the pointer stirs a swirl of the pigments around a centre that trails it on springs.glide — circling winds it up, and it unwinds and fades as the water stills while the clouds it pushed drift home. Keyboard focus on, inside or around the element stirs the middle once, and with focusable the Left and Right keys stir the ink round either way.
Fernworks Inks · studio set 04
Pigment you can stirLeft and Right stir the ink.
Twelve water inks, ground by hand.
drifting · 4 pigments · move across to stir
Install
One command — the source lands in your repo. Or copy it from the Code tab.
$ pnpm dlx shadcn@latest add @kinetiq/pigment-flow
Props
- text
- string
- default —
- The words the pigments drift through. Real text: it wraps, selects and copies.
- as
- "p" | "h1" | "h2" | "h3" | "span" | "div"
- default "p"
- The element the text lives in.
- colors
- "ink" | "tide" | "ember" | "moss" | string[]
- default "ink"
- The pigments: a named palette of tokens, or 2 to 6 CSS colours of your own.
- speed
- number
- default 1
- How fast the pigments drift, 0 (still) to 3.
- stir
- number
- default 0.6
- How strongly the pointer stirs the flow, 0 (not at all) to 1.
- radius
- number
- default 2.2
- Reach of the stir's swirl, em.
- diffusion
- number
- default 0.5
- How soft and wide each pigment cloud spreads, 0 (tight) to 1 (diffuse).
- angle
- number
- default 100
- Direction of the underlying wash, degrees.
- seed
- number
- default 3
- Seed for the clouds' paths, so two lines never drift in step.
- trigger
- "mount" | "inView" | "hover" | "manual"
- default "inView"
- When the drop of pigment blooms into the ink.
- active
- boolean
- default true
- With trigger="manual", the pigment blooms when this turns true.
- once
- boolean
- default true
- Bloom once, or again whenever the trigger fires anew.
- delay
- number
- default 0
- Wait before the bloom, ms.
- duration
- number
- default 900
- How long the bloom takes to spread, ms.
- onComplete
- () => void
- default —
- The bloom has spread and settled.
- onStirChange
- (stirring: boolean) => void
- default —
- Fires when the pointer starts stirring (true) and when the water stills (false).
- paused
- boolean
- default false
- Hold the drift. Stirring still works.
- interactive
- boolean
- default true
- The pointer, touch and focus stir the flow.
- focusable
- boolean
- default false
- Put the words in the tab order: focused, Left and Right stir the ink.
- className
- string
- default —
- Classes for the element; set the type here (size, weight, leading).
| Prop | Type | Default | Description |
|---|---|---|---|
| text | string | — | The words the pigments drift through. Real text: it wraps, selects and copies. |
| as | "p" | "h1" | "h2" | "h3" | "span" | "div" | "p" | The element the text lives in. |
| colors | "ink" | "tide" | "ember" | "moss" | string[] | "ink" | The pigments: a named palette of tokens, or 2 to 6 CSS colours of your own. |
| speed | number | 1 | How fast the pigments drift, 0 (still) to 3. |
| stir | number | 0.6 | How strongly the pointer stirs the flow, 0 (not at all) to 1. |
| radius | number | 2.2 | Reach of the stir's swirl, em. |
| diffusion | number | 0.5 | How soft and wide each pigment cloud spreads, 0 (tight) to 1 (diffuse). |
| angle | number | 100 | Direction of the underlying wash, degrees. |
| seed | number | 3 | Seed for the clouds' paths, so two lines never drift in step. |
| trigger | "mount" | "inView" | "hover" | "manual" | "inView" | When the drop of pigment blooms into the ink. |
| active | boolean | true | With trigger="manual", the pigment blooms when this turns true. |
| once | boolean | true | Bloom once, or again whenever the trigger fires anew. |
| delay | number | 0 | Wait before the bloom, ms. |
| duration | number | 900 | How long the bloom takes to spread, ms. |
| onComplete | () => void | — | The bloom has spread and settled. |
| onStirChange | (stirring: boolean) => void | — | Fires when the pointer starts stirring (true) and when the water stills (false). |
| paused | boolean | false | Hold the drift. Stirring still works. |
| interactive | boolean | true | The pointer, touch and focus stir the flow. |
| focusable | boolean | false | Put the words in the tab order: focused, Left and Right stir the ink. |
| className | string | — | Classes for the element; set the type here (size, weight, leading). |