KQ-1554 · OPTICAL/MIX

Optical Mix

A headline painted in dabs of separate pure pigments laid in an ordered dither on a hex lattice, so no two touching dabs share a colour and from reading distance they fuse into one tone; the real text stays the element's own selectable text and the paint is sampled from its exact layout. Hovering opens a soft lens whose fisheye pushes the dabs apart and swells them, each pigment opening on the glide spring 45 ms after the last like light through a prism and closing on the slower drift spring, while idle dabs breathe and the line is painted on left to right on the snap spring. Keyboard focus sweeps the lens along the line; Left and Right move it word to word, Home and End jump, Enter sweeps again and Escape closes it.

KQ-1554 · OPTICAL/MIX

Fieldline Gallery · Summer rooms

Light, one dot at a time

Arrow keys move a lens along the line to see its separate colours; Escape closes it.

Forty paintings made of nothing but points. Until 14 September.

at rest · four pigments read as one tone

Install

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

$ pnpm dlx shadcn@latest add @kinetiq/optical-mix

Props

text
string
default —
The headline; it stays the element's real, selectable text.
as
"h1" | "h2" | "h3" | "p" | "span" | "div"
default "h2"
The element that carries the text.
dotSize
number
default 2.5
Diameter of one dab, px on a 60 px line; dabs scale with the type.
palette
"field" | "dusk" | "press" | "tide"
default "field"
The pigments the line is painted in, each set at one lightness so it fuses.
colors
string[]
default —
Any CSS colours, two to six; replaces palette.
density
number
default 0.8
How tightly the dabs pack, 0 (open weave) to 1 (just overlapping).
spread
number
default 0.6
How far the lens pulls the dabs apart, 0 (they only swell) to 1.
magnify
number
default 2.2
How much the dabs swell under the lens, 1 to 4.
lensRadius
number
default 70
The lens radius, px; held to about 1.3 times the font size.
twinkle
number
default 0.5
How much the dabs breathe while idle, 0 (still) to 1.
interactive
boolean
default true
The pointer and the keyboard can bring the lens.
trigger
"mount" | "inView"
default "inView"
When the dabs are painted on.
once
boolean
default true
Paint on only the first time the line is seen.
delay
number
default 0
Wait before painting on, ms.
paused
boolean
default false
Hold the idle breathing; the lens still works.
seed
number
default 1
Twists the dither so two lines never share a pattern.
dpr
number
default 2
Cap on the canvas pixel ratio, 1 to 2.
onComplete
() => void
default —
The dabs have all been painted on.
onLensChange
(word: string | null) => void
default —
The word under the lens, or null when it closes.
className
string
default —
Size, weight and alignment; the type is inherited.