Agent Orb
betaGlassy liquid sphere for voice agents, drawn in a shader: breathes when idle, reacts to mic and voice levels, swirls while thinking.
Idle orb
minimal
Voice agent idle
States, palettes and audio
Every state and preset, driven by a simulated speech analyser.
full
Speaking
All five states
idle, listening, thinking, speaking and error side by side.
state
Voice agent idle
Listening
Thinking
Speaking
Voice agent error
Voice session card
A scripted call with captions, ShimmerText while thinking and IconButton controls.
composition
Listening
Installation
npx shadcn@latest add https://kuro.abstergo.fyi/r/agent-orb.jsonCopies the source into components/kura/agent-orb with its dependencies (kura-theme, kura-merge-refs, kura-shader-color, shader-canvas, use-audio-analyser, use-reduced-motion, utils). Tokens come from the kura-theme item.
When to use it
Use it for
- The central visual of a voice agent or call screen: idle, listening, thinking, speaking, error.
- Showing that an assistant is hearing the user (mic level) or talking back (TTS level).
- A 'talk to the agent' entry point inside a button or a card.
- An ambient, branded presence for an AI assistant in an empty state.
Reach for something else when
- Precise audio feedback such as a recording meter or waveform — use audio-waveform or voice-dictation.
- Text chat 'thinking' feedback inside a message list — use thinking-indicator or shimmer-text.
- A full-bleed background — use mesh-gradient or aurora.
- More than one per view: the orb is the accent element; repeat it and it stops meaning anything.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| state | "idle" | "listening" | "thinking" | "speaking" | "error" | "idle" | What the agent is doing. idle breathes slowly, listening ripples with the input level, thinking swirls, speaking pulses with the output level, error turns red and calms down. |
| colors | "jade" | "ocean" | "amber" | "graphite" | readonly [string, string, string, string] | "jade" | A palette preset, or four CSS colours `[deep, mid, bright, glint]` (OKLCH, hex, `var(--token)`…). jade is the Kura signal colour. |
| analyser | AudioAnalyser | — | From `useAudioAnalyser`. Its level drives the orb while listening or speaking. Read every frame on the GPU loop — no React re-renders. |
| inputLevel | number | — | Microphone level 0–1 used while `listening`. Overrides `analyser`. |
| outputLevel | number | — | Agent voice level 0–1 used while `speaking`. Overrides `analyser`. |
| label | string | — | Accessible text for the state. Default: Voice agent idle / Listening / Thinking / Speaking / Voice agent error. |
| announce | boolean | true | Render the label in a polite live region. Set false when several orbs are on screen or a parent already announces the state. |
| maxDpr | number | 2 | Device-pixel-ratio cap. |
All native attributes of the root element, className and ref pass through.
Anatomy
- AgentOrbSquare root (`aspect-square`); size it with a width class. `data-state` mirrors `state`.
data-slot="agent-orb" - ShaderCanvasThe WebGL sphere and its halo (aria-hidden). The sphere fills ~70% of the box.
data-slot="agent-orb-canvas" - FallbackCSS gradient sphere used when WebGL2 is unavailable; it still spins while thinking.
data-slot="agent-orb-fallback"
Accessibility
- Role:
status - The canvas is decorative (aria-hidden). The state is exposed as visually hidden text in a role=status live region, announced politely when it changes.
- Audio levels are never announced. Pass `label` to describe custom situations (e.g. “Muted”).
- If the orb is inside a button, give the button its own aria-label and set `announce={false}` to avoid double announcements.
- Reduced motion: No breathing, swirl, flow or audio reaction: a still frame per state. State changes cross-fade colour and brightness over ~0.4s, then rendering stops.
Notes for agents
- Give it a width (`className="size-48"` or `w-full max-w-64`); it is square. The sphere fills ~70% so the halo has room — do not clip it with overflow-hidden.
- For real audio: `const mic = useAudioAnalyser({ source: micStream })` for listening and a second analyser on the TTS <audio> element for speaking; switch `analyser` with the state. For demos use `useAudioAnalyser({ simulate: "speech" })`.
- `inputLevel`/`outputLevel` are fine for levels you already have (e.g. from a WebRTC SDK) at ≤ 30 updates/s; the shader smooths them.
- Changing `state` never restarts the animation: uniforms ease toward the new state, so you can flip states as fast as your agent emits events.
- Only one orb per view should be animated; for lists of agents use a static avatar.