BlurReveal
Words revealed out of a blur — the landing hero's headline and subhead. By line, each line sweeps in letter by letter as the words wrap, line after line; by letter, Spell UI's Blur Reveal (MIT, vendored). A span of the words: put it in the element that styles them, which a screen reader reads whole.
By line
The lines are measured once the words wrap; until then the letters hold hidden. Each letter comes out of a 12px blur over duration-very-slow, starting as far along its line as it sits, so every line sweeps in the same time: duration-very-slow, or a pace.
Every message answered, every chair filled
import { BlurReveal, RiseIn } from "@/components/shared/blur-reveal";
<p className="text-xl font-medium">
<BlurReveal by="line">Every message answered, every chair filled</BlurReveal>
</p>By letter
Spell UI's own reveal, one continuous run of letters, each over duration-very-slow, half a duration-stagger apart.
Every message answered, every chair filled
<p className="text-xl font-medium">
<BlurReveal>Every message answered, every chair filled</BlurReveal>
</p>A sequence
The landing hero: the headline's lines at duration-medium each, then the subhead's at duration-quick once they're in (wait), then the way in rising (RiseIn) once the subhead's three are. All on one clock: held until the page runs, so nothing shows before the words.
Your craft, uninterrupted
Okami answers every message and call, books your clients, and brings them back — while you stay with the one in your chair.
On scroll
The landing's section titles (Jozef, 2026-11-09: “subtle and not too much”): the same sweep, the first time a title is seen, at duration-quick a line (when="seen"); its lead and cards rise under it (Reveal), a duration-micro a step, three at most. Only once the page runs, and only if it was below the screen then: as served it simply stands, so the page reads whole without scripts and nothing on screen at load ever moves. Once seen, it stays.
Scroll the landing to see it: a demo here is already on screen, so it would simply stand.
import { Reveal } from "@/components/shared/reveal";
<h2 className="text-3xl font-medium">
<BlurReveal by="line" when="seen" pace="duration-quick">
One price a seat. Zero commissions.
</BlurReveal>
</h2>
<Reveal step={1}>
<p>Every seat gets everything.</p>
</Reveal>API reference
BlurReveal
| Prop | Type | Default | Description |
|---|---|---|---|
| children | string | — | The words: read whole by a screen reader. |
| by | "letter" | "line" | "letter" | Spell's continuous run of letters, or each line swept letter by letter as the words wrap, line after line. |
| when | "load" | "seen" | "load" | By line: as the page loads (the hero's), or the first time it's seen on scroll (a section title's), held only if it was below the screen. |
| pace | `duration-${string}` | duration-very-slow | By line: how long each line takes to sweep in. |
| wait | string | — | By line: a CSS time from tokens to wait first — another reveal's sweeps, as calc(var(--duration-medium) * 2). |
| after | `duration-${string}` | — | A token's time to wait before the first letter. |
RiseIn
| Prop | Type | Default | Description |
|---|---|---|---|
| after | string | — | A CSS time from tokens: how long after the page runs it rises (opacity and transform only, blur-in). |
| children | ReactNode | — | The block: the hero's way in. |
Reveal
| Prop | Type | Default | Description |
|---|---|---|---|
| step | number | 0 | How many duration-micro after the first piece beside it it rises; three at most in a row. |
| as | "div" | "li" | "div" | The element it is: a list item rises as itself, so a subgrid or a grid's columns hold. |
| children | ReactNode | — | The block that rises in the first time it's seen (opacity and transform only, reveal-rise). |
Guidelines
- Words only: a headline, its subhead. Chrome — the nav, a button — rises on opacity and transform (
blur-in,RiseIn): a blur is painted on the main thread and stuttered in the nav while the page loaded. - The page's top reveals once as it loads; each section's title once as it's first seen, quicker. Never twice, never on text a reader is waiting for (a reply, a chat).
- On scroll, subtle: titles sweep, leads and cards only rise, a duration-micro apart, three steps at most. What moves on its own (a demo, a story, a flow that measures itself) is left alone.
- Under
prefers-reduced-motionthe words are there at once.