Decode Text
betaText reveal that scrambles glyphs and resolves them left to right, like an AI decoding — width-stable, with the final text read to screen readers at once.
Decode on mount
minimal
Agent online
Triggers, glyph sets and fonts
Replay via `trigger`, text changes, `startOn="view"`, a binary glyph set and a proportional font.
full
Plan ready: 3 steps, 2 files
sha 9f3c2e1 · 412 ms · 1,284 tokens
Proportional fonts keep their width while decoding.
Agent connection status
A status card that decodes its new state inside a polite live region.
composition
Remote agent
Not connected
Installation
npx shadcn@latest add https://kuro.abstergo.fyi/r/decode-text.jsonCopies the source into components/kura/decode-text with its dependencies (kura-theme, kura-merge-refs, use-reduced-motion, utils). Tokens come from the kura-theme item.
When to use it
Use it for
- Revealing a short status or result the agent just produced: “Plan ready”, “Connected to runner-07”.
- Hero taglines or section headings that should arrive with a technical, machine-like flourish.
- IDs, hashes, timings and other mono data appearing after a computation.
Reach for something else when
- Streaming a model's answer token by token — use streaming-text.
- An in-progress label — use shimmer-text or thinking-indicator.
- Paragraphs or anything longer than a line or two: the effect becomes noise and per-glyph DOM gets heavy.
- Text that changes many times a second (live counters) — render it plainly.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| children* | string | — | The final text (a plain string). Changing it replays the reveal. |
| startOn | "mount" | "view" | "mount" | When the first reveal runs: immediately, or the first time ≥ 40% of it scrolls into view (a dim, still scramble shows until then). |
| trigger | string | number | boolean | — | Replay whenever this value changes — a counter, an id or a boolean. |
| duration | number | 1000 | Milliseconds for the reveal to sweep the whole text (ease-out). |
| spread | number | 6 | How many characters ahead of the resolved edge scramble actively, in the accent colour. |
| glyphs | string | — | Characters used for scrambling. Default "A–Z 0–9 #%&*+=/<>". Try "01" for binary or a single "·" for a quiet reveal. |
| as | "span" | "p" | "div" | "h1" | "h2" | "h3" | "code" | "span" | Element to render. |
| onComplete | () => void | — | Called when a reveal finishes (not called under reduced motion). |
All native attributes of the root element, className and ref pass through.
Anatomy
- DecodeTextRoot element. `data-state` = pending | running | done.
data-slot="decode-text" - GlyphsThe visual (aria-hidden) text; plain text once done.
data-slot="decode-text-glyphs" - CharOne glyph slot while decoding. `data-state` = pending | active | done; `data-char` holds the final character.
data-slot="decode-text-char"
Accessibility
- The final text is always present in a visually hidden span, so screen readers read it immediately and once; the scrambling glyphs are aria-hidden.
- Not a live region. Wrap it in role=status if a replay (new text) should be announced.
- Each glyph reserves the width of its final character, so the line never reflows while decoding.
- Reduced motion: No scramble: the final text renders immediately.
Notes for agents
- Pass a plain string child. For mixed formatting, wrap several DecodeTexts.
- Monospace (`font-kura-mono`) gives the cleanest look; proportional fonts work because each glyph keeps its final width.
- Use `trigger` to replay without changing the text (e.g. when a card re-opens); change `children` to decode new text.
- Keep it to one or two lines and ≤ 1.5s — it should feel like arrival, not waiting.