Skip to content
Sign in
VoiceDither orbMenu

Dither orbPro

A voice orb drawn as a lit sphere in 1 bit ordered dither. Threshold, grain and silhouette react to the input and output levels, and every voice state has its own motion. A drop-in swap for the free voice orb.

ProA lit sphere in 1 bit ordered dither. Pick a state; listening and speaking follow simulated voice levels.

Installation

$ pnpm dlx shadcn@latest add @chatcn-pro/dither-orb

Usage

tsx
import { DitherOrb } from "@/components/ui/chatcn/pro/dither-orb"

<DitherOrb state={voice.state} inputLevel={mic.getLevel} outputLevel={agent.getLevel} size="xl" />

Same props as VoiceOrb, so changing the import is the whole migration. Idle breathes, listening stirs the surface with the user's voice, thinking orbits the light around the sphere like a moon's phases, speaking swells it and brings the grain alive, interrupted contracts, muted goes still and sparse, and error breaks along a crack in the red token. It draws through the shared effect runtime, so a page of orbs still uses one WebGL context.

Examples

States, sizes and reduced motion

ProAll eight voice states, the four sizes and the still frames drawn under reduced motion.

One API, four orbs

ProThe free voice orb and the three effect orbs on the same props, so any of them swaps in.

Props

PropTypeNotes
state"idle" | "connecting" | "listening" | "thinking" | "speaking" | "interrupted" | "muted" | "error"Default idle. Same states as VoiceOrb
level, inputLevel, outputLevelnumber | () => number0 to 1. Input drives listening, output drives speaking. A getter animates without re-rendering
simulatebooleanSpeech-like levels where none are passed, for demos
size"sm" | "md" | "lg" | "xl" | number40, 72, 144, 224 px. Default lg
renderer"auto" | "webgl" | "2d"auto uses the shared WebGL2 context, then canvas 2D. canvas and svg are accepted as aliases of 2d
reducedMotionbooleanForce it on or off. Defaults to the user's setting
labelstringAccessible name. Default "Voice: listening" and so on
inkstringToken or CSS color for the marks. Default var(--chatcn-fg)
paused, defaultPaused, onPausedChangebooleanControlled or uncontrolled pause
pauseControlbooleanShow the pause button. Default on from 120 px
pixelSizenumberCSS px per dither cell. Default 1, 2 or 2.5 by size

Keyboard

KeyAction
Tab, EnterFocus and toggle the pause button, when it shows

Accessibility

  • One role="img" named by state, "Voice: speaking", exactly like the free voice orb. Announce state changes in your own live region, as the examples do.
  • The canvas and the text grid are aria-hidden; nothing animated is read out.
  • Error uses the red token and the state label as its backup, never color alone.
  • Under forced-colors: active the effect hides and a plain outline keeps the orb's place. Under prefers-contrast: more the marks snap to the text token.

Motion

  • Each state is a target form. The orb eases toward it every frame with a critically damped approach, so any state can follow any other and nothing bounces. Interrupted snaps in quickly; the rest settle over about half a second.
  • Loops run on the shared frame clock and stop offscreen, in hidden tabs and when paused. Time stops with them, so resuming continues instead of jumping.
  • Under reduced motion each state is one still frame, redrawn only when the state changes.
  • Speaking moves the dither threshold toward blue noise that shifts 12 times a second: the grain of the voice. It fades out with the level.