KQ-1544 · INCENSE/SCRIPT

Incense Script

A stick of incense stands at the left edge and one thread of smoke leaves its ember, rises and drifts right, its curls catching on the letters one by one so each forms out of the smoke the thread leaves there; written, the phrase lingers, then diffuses upward into haze and the next one begins. Canvas 2D draws the thread along a seeded spline with turbulence, its ageing trail, the ember's plume and every smoke particle sampled from the real glyphs, each pulled into place by a spring at springs.glide's damping ratio while a decaying swirl curls it in. A hand through the smoke pushes it aside and it drifts back, and a transparent button gives the keyboard Enter to waft a breath across the words.

KQ-1544 · INCENSE/SCRIPT

Fieldline · tea rooms

Slow mornings. Quiet rooms. Tea at four.

Enter wafts a breath across the words.

writing · Slow mornings · 1 of 3

Install

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

$ pnpm dlx shadcn@latest add @kinetiq/incense-script

Props

phrases
string[]
default —
The phrases, written in smoke one after another.
as
"h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "p" | "span" | "div"
default "p"
The element that carries the phrases.
drift
number
default 0.5
How fast the thread travels and how far its wisps lean on the draught, 0 to 1.
curl
number
default 0.5
Turbulence, 0 (a laminar thread) to 1 (curling, swirling smoke).
linger
number
default 2600
How long a written phrase stays before it clears to haze, ms.
color
string
default "var(--ink-2)"
The smoke, any CSS colour; resolved on the element, so it follows the theme.
ember
string
default —
The ember, any CSS colour; a fixed glowing pigment by default.
density
number
default 0.6
How much smoke makes each letter, 0 (wisps) to 1 (dense).
stick
boolean
default true
Draw the stick of incense and its dish at the left edge.
loop
boolean
default true
Cycle the phrases; false stops on the last one, written.
trigger
"mount" | "inView" | "manual"
default "inView"
What lights the stick.
play
boolean
default false
With trigger "manual": true lights the stick, false lets it rest.
delay
number
default 0
Wait before the first thread leaves the ember, ms.
interactive
boolean
default true
A hand through the smoke pushes it aside; Enter wafts a breath across.
dpr
number
default 2
Cap on the canvas's pixel ratio (never above 2).
onPhraseChange
(index: number) => void
default —
A phrase began: its index in phrases.
onComplete
(index: number) => void
default —
A phrase finished writing: its index in phrases.
className
string
default —
Size and type; the stick and gutter are in em.