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

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

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.

API reference

BlurReveal

PropTypeDefaultDescription
childrenstring—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-slowBy line: how long each line takes to sweep in.
waitstring—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

PropTypeDefaultDescription
afterstring—A CSS time from tokens: how long after the page runs it rises (opacity and transform only, blur-in).
childrenReactNode—The block: the hero's way in.

Reveal

PropTypeDefaultDescription
stepnumber0How 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.
childrenReactNode—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-motion the words are there at once.