KQ-1357 · PEN/OUTLINE
Pen Outline
A small nib travels the contour of every letter — outlines traced from the glyphs the browser actually rendered — while the stroke's dash offset grows under its tip, letter after letter, lifting between loops; when the last stroke closes, ink floods each letter from the bottom up behind a gentle wave on springs.drift, one after another. The pen runs on a linear clock (a hand at constant speed) that pauses off screen, and the flood is the real, selectable text clipped by a per-letter wave. Focused, Enter or Space drains the ink, rewinds the outline on the exit ease and writes it again.
Fernworks · bottled ink no. 4
Written by hand
Press Enter to draw it again.waiting · the nib is ready
Install
One command — the source lands in your repo. Or copy it from the Code tab.
$ pnpm dlx shadcn@latest add @kinetiq/pen-outline
Props
- text
- string
- default —
- The words the pen writes.
- as
- "h1" | "h2" | "h3" | "p" | "span" | "div"
- default "p"
- The element rendered.
- speed
- number
- default 1
- How fast the pen writes and the ink floods, 0.5 to 2.
- stroke
- number
- default 1.25
- Outline width, px.
- flood
- number
- default 1
- How much ink floods in once the outline closes: 0 leaves a pure outline, 1 is solid ink.
- ink
- string
- default "var(--foreground)"
- Outline colour, any CSS colour.
- floodColor
- string
- default the ink colour
- The colour the letters flood with.
- guide
- number
- default 0.12
- Opacity of the pencil guide shown before the pen arrives, 0 to 1.
- wave
- number
- default 0.5
- Height of the flood's wave front, 0 (flat) to 1.
- nib
- boolean
- default true
- Show the travelling nib; the box reserves a quarter em above and right for it.
- keepOutline
- boolean
- default true
- Keep the inked edge once the flood settles; false dissolves it into the fill.
- trigger
- "mount" | "inView" | "hover" | "manual"
- default "inView"
- What starts the drawing.
- once
- boolean
- default true
- Draw once; false rewinds when it leaves view or the hover ends.
- play
- boolean
- default —
- Manual trigger: true draws, false rewinds.
- delay
- number
- default 0
- Wait before the pen starts, ms.
- duration
- number
- default 180
- Time the pen spends on an average letter at speed 1, ms (a whole headline is capped at about three seconds).
- stagger
- number
- default 55
- Gap between the letters' floods, ms.
- interactive
- boolean
- default true
- A press, or Enter or Space while focused, erases and redraws.
- onPhaseChange
- (phase: "waiting" | "drawing" | "flooding" | "inked") => void
- default —
- The drawing moved on; reported from the first commit.
- onComplete
- () => void
- default —
- The ink has settled.
- className
- string
- default —
- Size, weight and tracking live here; the outline follows whatever font renders.
| Prop | Type | Default | Description |
|---|---|---|---|
| text | string | — | The words the pen writes. |
| as | "h1" | "h2" | "h3" | "p" | "span" | "div" | "p" | The element rendered. |
| speed | number | 1 | How fast the pen writes and the ink floods, 0.5 to 2. |
| stroke | number | 1.25 | Outline width, px. |
| flood | number | 1 | How much ink floods in once the outline closes: 0 leaves a pure outline, 1 is solid ink. |
| ink | string | "var(--foreground)" | Outline colour, any CSS colour. |
| floodColor | string | the ink colour | The colour the letters flood with. |
| guide | number | 0.12 | Opacity of the pencil guide shown before the pen arrives, 0 to 1. |
| wave | number | 0.5 | Height of the flood's wave front, 0 (flat) to 1. |
| nib | boolean | true | Show the travelling nib; the box reserves a quarter em above and right for it. |
| keepOutline | boolean | true | Keep the inked edge once the flood settles; false dissolves it into the fill. |
| trigger | "mount" | "inView" | "hover" | "manual" | "inView" | What starts the drawing. |
| once | boolean | true | Draw once; false rewinds when it leaves view or the hover ends. |
| play | boolean | — | Manual trigger: true draws, false rewinds. |
| delay | number | 0 | Wait before the pen starts, ms. |
| duration | number | 180 | Time the pen spends on an average letter at speed 1, ms (a whole headline is capped at about three seconds). |
| stagger | number | 55 | Gap between the letters' floods, ms. |
| interactive | boolean | true | A press, or Enter or Space while focused, erases and redraws. |
| onPhaseChange | (phase: "waiting" | "drawing" | "flooding" | "inked") => void | — | The drawing moved on; reported from the first commit. |
| onComplete | () => void | — | The ink has settled. |
| className | string | — | Size, weight and tracking live here; the outline follows whatever font renders. |