Voice orb
Free · MITBreathing voice-assistant orb that swells with a level prop through a spring: idle breathing, listening rings, speaking light that churns faster, and a spinning thinking arc, all in CSS on theme colors.
Installation
$ npx shadcn@latest add https://goodui.dev/r/voice-orb.jsonThe file lands in components/goodui/voice-orb.tsx and is yours to edit. With the @goodui registry added, npx shadcn@latest add @goodui/voice-orb works too.
Usage
import { VoiceOrb } from "@/components/goodui/voice-orb"
<VoiceOrb state={call.state} level={micLevel} size="lg" />
// level from the Web Audio API
const analyser = audioContext.createAnalyser()
source.connect(analyser)
const data = new Uint8Array(analyser.frequencyBinCount)
function tick() {
analyser.getByteTimeDomainData(data)
let sum = 0
for (const v of data) sum += ((v - 128) / 128) ** 2
setMicLevel(Math.min(1, Math.sqrt(sum / data.length) * 6))
requestAnimationFrame(tick)
}When to use
- Voice assistants and call agents: one object that shows whether the assistant is idle, listening, thinking or speaking.
- Visualising a microphone or playback level without a waveform.
- Hero or empty-state art for an AI product, kept alive by the slow breathing loop.
- Text chat loading states: use typing-indicator.
- Precise audio visualisation (bars, waveforms) for recording tools: draw a canvas waveform.
| If you need | Use |
|---|---|
| Microphone input | state="listening" with level from an AnalyserNode |
| Assistant audio playing | state="speaking" with the output level |
| Waiting for the model | state="thinking" |
| Brand colors | color and accent (any CSS color); defaults are --chart-1 and --chart-4 |
| Exact pixel size | size={120} |
Examples
Small orbs in brand colors
<VoiceOrb state="idle" size="sm" color="var(--chart-2)" accent="var(--chart-3)" labels={{ idle: "Support bot idle" }} />Translated state names
<VoiceOrb state="listening" labels={{ idle: "Bereit", listening: "Hört zu", speaking: "Spricht", thinking: "Denkt nach" }} />API reference
| Prop | Type | Default |
|---|---|---|
| color Main color (any CSS color); defaults to --chart-1. | string | — |
| state | "idle" | "listening" | "speaking" | "thinking" | "idle" |
| level Audio level 0..1 (microphone while listening, output while speaking). | number | 0 |
| size Diameter in px, or a preset. | number | "sm" | "md" | "lg" | "md" |
| accent Second color for the inner light; defaults to --chart-4. | string | — |
| labels Text for screen readers per state; pass translations here. | Partial<VoiceOrbLabels> | — |
Also accepts every <div> attribute.
Accessibility
- The visual is role="img" labelled with the current state (Assistant idle, Listening, Speaking, Thinking); a visually hidden role="status" region announces state changes.
- Nothing inside is interactive; wrap it in a button if tapping should start listening.
- Reduced motion stops the breathing, spinning blobs, rings and arc; the state is still shown by a static ring (listening), a dashed ring (thinking) and the level by the orb's size.
Motion
- Idle: the orb breathes between 1 and 1.045 scale every 4.2 s; two blob layers with conic gradients rotate slowly (11 s and 15 s) under soft-light blending.
- Listening: three rings expand from 0.86 to 1.55 scale every 1.9 s, staggered 0.65 s; the orb scales up to 1.22 with the level. Speaking: the blobs spin fast (2.6 s and 3.4 s) and the glow grows with the level. Thinking: a thin arc spins once per 1.3 s.
- The level goes through a spring (stiffness 220, damping 20, mass 0.6) so bursts feel physical; under reduced motion it jumps.
- Everything loops in CSS on transform and opacity; the glow is one blurred layer.
- No canvas or WebGL: three gradient layers, one blur filter and CSS keyframes. Expect well under 1% CPU at rest on a laptop; the blur radius scales with the orb size.
Notes for AI
Coding agents read these rules through MCP and llms.txt, or paste this page with Copy page.
- level is 0..1 and only matters in listening and speaking states; feed it 30–60 times a second for a live feel.
- state is one of idle, listening, speaking, thinking. Change it as the call progresses; the orb has no internal state machine.
- Pass color and accent as CSS colors (var(--chart-2), oklch(...)); they drive gradients and glows through CSS variables.
FAQ
Why does the level feel delayed?
It is smoothed through a spring so single noisy frames do not twitch the orb. Lower the stiffness in the source if you want it snappier.
Related
Three dots waving in turn with an "Aiko is typing" sentence for one or several names, as a chat bubble, inline or dots only, mounting and leaving on a spring; reduced motion keeps the dots still.
Prompt input with an auto-growing textarea, attachment chips from picker, paste or drop, a slash-command menu, model and mode selectors, a token ring against the context limit, Enter or Cmd+Enter to send and a Stop button while streaming.
Soft colored light drifts slowly behind a section, with light and dark palettes and only transform animations for low CPU.
Six CSS-only loaders (ring, dots, bars, pulse, orbit, typing) sized in px or presets and painted with currentColor.