Skip to content

SaltiePulse

  • Layer: Primitive
  • Base: Custom SVG — no Ark UI dependency
  • Motion: rAF-driven SVG attribute updates; skipped entirely under prefers-reduced-motion: reduce

Three phases carry a directional grammar: quiet water when waiting, outward ripples when thinking, inward convergence when an answer is surfacing. The primitive itself does not auto-advance — callers choose the phase.

Idle → Thinking → Emerging

Half-submerged.
Phase · idle

One primitive, four sizes. Pick by where Saltie is rendered — inline chip, row marker, panel header, empty state.

xs · sm · md · lg

XS · 16px · inline chip
Chewing.
SM · 24px · row marker
Rolling it around.
MD · 48px · panel header
Working the jaw.
LG · 80px · empty state

Microcopy lives in the component. Callers pick phase + context and Saltie supplies the voice. general is poker-faced; reviewing, planning, researching tilt the language toward the task.

general / reviewing / planning / researching — thinking then emerging

general
Rolling it around.Breaking the surface.
reviewing
Turning it over.Got the shape of it.
planning
Tracing the line.Found the seam.
researching
Listening to the reeds.Coming up with it.

Chat thinking · titlebar dot · empty state

Chat thinking · sm · reviewing
Checking the bones.
Titlebar dot · xs · idle · no label
Saltie · Lurking
Empty state · lg · idle · long
Half-submerged.
PropTypeDefaultDescription
phase"idle" | "thinking" | "emerging"requiredWhich phase to render.
size"xs" | "sm" | "md" | "lg""md"16 / 24 / 48 / 80 px.
context"general" | "reviewing" | "planning" | "researching""general"Microcopy pool. Non-general pools cover thinking + emerging only; idle falls back to general.
showLabelbooleanfalse at xs, true elseShow copy next to the pulse.
labelstringOverride the resolved label entirely. Wins over pools.
labelVariant"short" | "long""short" at sm, "long" at md/lgOnly meaningful for context="general" — contextual pools are long-only.
classstringExtra class on the outer span.
  • Direction is meaning. Outward = input dropped in. Inward = output surfacing. Never invert — the metaphor only works one way.
  • Cycle times are fixed across themes. Saltie is 200 million years old. Idle breathes on 6s; thinking ripples on 2.2s; emerging converges in 2.4s then holds for 1.4s. A fast pulse reads anxious. A slow pulse reads considered.
  • Stroke resolves through var(--colors-accent), so themes work without extra plumbing. Switch delight / relight / gilt mid-render and the colour updates in one frame.
  • Reduced motion is detected via matchMedia at mount; under prefers-reduced-motion: reduce the component renders a static settled pose and never starts requestAnimationFrame.
  • aria-label is phase-only ("Saltie idle" / "Saltie thinking" / "Saltie answering"). Visible copy is flavour; screen readers get intent.

Each context supplies a long pool of one-liners. Pool selection is deterministic — a minute-granularity hash of context + phase + size, so the quip is stable for the duration of one phase but varies across mounts.

  • General carries both a single-word short default ("Lurking." / "Chewing." / "Surfacing.") and a long pool.
  • Reviewing is close-up, in the jaws: "Chewing on it.", "Reading the grain.", "Checking the bones."
  • Planning is wide-angle: "Lining up the shot.", "Picking the angle.", "Mapping the shallows."
  • Researching is going deep: "Sounding the depths.", "Consulting the mangroves.", "Waking the council."

SALTIE_PULSE_RARE_THINKING_GENERAL exports the "Letting it marinate." quip as a named constant. It is not in any default pool — pass it via label when you want the flavour without polluting the poker-faced default. Keep it rare.

  • No background, no border on the component itself — composition sits with the caller.
  • No color shifts on errors or success; pulse carries only presence and phase.
  • No CSS keyframes — the rAF engine writes SVG attributes directly so the timings match the reference exactly and cleanup is deterministic.
TokenSource
--colors-accentStroke + fill across all phases
text.secondaryLabel colour
font.monoLabel typeface