Skip to Content
Core conceptsAssistant states

Assistant states

The state attribute selects one of five motion profiles. A state communicates visual intent; it does not start a microphone, call a model, or play audio.

StateVisual intentTypical application signal
idleCalm, available presenceReady for the next interaction
listeningAlert and receptiveInput capture is active
thinkingFocused processingA request or tool chain is in progress
speakingEnergetic, voice-like movementSynthesized or streamed audio is playing
asleepQuiet, dimmed restThe assistant is unavailable or intentionally dormant

Set a state

Use an HTML attribute:

<orb-z state="listening"></orb-z>

Or update the matching property:

import "@neongate-ai/orbz/browser"; import type { OrbzElement } from "@neongate-ai/orbz"; const orb = document.querySelector<OrbzElement>("orb-z"); if (orb) { orb.state = "thinking"; }

React and Next.js use the same value through the strict adapter:

import { Orbz, type OrbzState } from "@neongate-ai/orbz/react"; export function AssistantPresence({ state }: { state: OrbzState }) { return <Orbz state={state} />; }

Changing state replaces the current animation with the new state’s profile. If paused is present, Orbz renders the new state and keeps its animation paused.

Keep domain state outside Orbz

Real assistants usually have more states than a visual orb needs: requesting permission, reconnecting, waiting for a tool, recovering from an error, or being interrupted. Keep those domain states in your application and map them to the nearest visual intent.

type SessionPhase = | "booting" | "ready" | "capturing" | "transcribing" | "requesting" | "playing" | "offline" | "failed"; const visualState = { booting: "idle", ready: "idle", capturing: "listening", transcribing: "thinking", requesting: "thinking", playing: "speaking", offline: "asleep", failed: "idle", } as const;

Error details should appear in real text or controls. Changing the orb’s color or motion alone is not enough to explain a failure.

Invalid and missing values

The default state is idle. Removing state, or assigning an unsupported value through untyped runtime code, normalizes the element back to idle. TypeScript consumers can import OrbzState or the ORBZ_STATES constant to avoid unsupported values.

import { ORBZ_STATES, type OrbzState } from "@neongate-ai/orbz"; function setState(state: OrbzState) { // state is one of the five documented values } for (const state of ORBZ_STATES) { console.log(state); }

State must also be perceivable

Motion is presentation, not an announcement. Pair the orb with visible status text and a live region when state changes matter to the user:

<div role="status" aria-live="polite"> <orb-z state="thinking"></orb-z> <span>Assistant is thinking</span> </div>

This pattern remains meaningful when animation is reduced, paused, unsupported, or not visible. Continue with Motion and accessibility.

Last updated on