StateSimulator
A development toolbar with one button per orb state. Use it to preview how the orb and the voice
UI react to each AppOrbState without a real voice pipeline.
import { StateSimulator } from 'jarvis-react-ui';
Warning: Development aid
StateSimulator is meant for showcases, prototypes and debugging. Do not ship it in a production UI; render it behind a dev flag such as
import.meta.env.DEV.
Inline
With position="inline" the toolbar sits in the normal document flow. It is controlled: pass the
current state and update it in onChange.
import { useState } from 'react';
import { StateSimulator } from 'jarvis-react-ui';
import type { AppOrbState } from 'jarvis-react-ui';
export default function Inline() {
const [state, setState] = useState<AppOrbState>('idle');
return (
<div className="flex flex-col items-center gap-3">
<StateSimulator state={state} onChange={setState} position="inline" />
<span className="text-[10px] text-text-muted">state = {state}</span>
</div>
);
}
The toolbar has one button per AppOrbState: idle, listening, thinking, speaking,
follow_up (labelled FOLLOW UP) and working.
Drive the orb
Share one state between the simulator, the orb and the StatusLabel to
check every state in context. The active working button turns amber like the orb's working
overlay.
import { useState } from 'react';
import { CssOrb, StateSimulator, StatusLabel } from 'jarvis-react-ui';
import type { AppOrbState } from 'jarvis-react-ui';
export default function DriveTheOrb() {
const [state, setState] = useState<AppOrbState>('thinking');
return (
<div className="flex w-full flex-col items-center gap-3">
<StateSimulator state={state} onChange={setState} position="inline" />
<div className="relative h-[260px] w-full overflow-hidden">
<CssOrb state={state} particles />
</div>
<StatusLabel state={state} />
</div>
);
}
Fixed to the top
By default (position="fixed-top") the toolbar is position: fixed, centred 60px below the top of
the viewport, above the HUD. Inside this demo frame it stays within the frame.
import { useState } from 'react';
import { StateSimulator, StatusLabel } from 'jarvis-react-ui';
import type { AppOrbState } from 'jarvis-react-ui';
export default function FixedTop() {
const [state, setState] = useState<AppOrbState>('listening');
return (
<>
{/* Pinned 60px below the top of the viewport (here: of the demo frame). */}
<StateSimulator state={state} onChange={setState} />
<StatusLabel state={state} />
</>
);
}
Sound
Hovering a state button plays hover_button and clicking it plays click through the nearest
SfxProvider. See Sound effects.
Accessibility
- Every state is a native
<button type="button">whose text is its accessible name, so the toolbar works with Tab, Enter and Space. - The button of the current state has
aria-pressed="true", all othersaria-pressed="false", so screen readers announce which state is selected, not only the color.
API
| Prop | Type | Default | Description |
|---|---|---|---|
onChange (required) |
(state: AppOrbState) => void |
Called with the state of the button that was clicked. | |
state (required) |
'idle' | 'listening' | 'thinking' | 'speaking' | 'follow_up' | 'working' |
Currently selected orb state; its button is highlighted (amber for working) and marked aria-pressed. |
|
className |
string |
Extra classes for the root <div> element (the toolbar). |
|
label |
string |
◈ ORB STATE |
Caption shown before the buttons. |
position |
'fixed-top' | 'inline' |
'fixed-top' |
fixed-top pins the bar centred 60px below the top of the viewport; inline keeps it in the normal document flow. |
Type AppOrbState
Full app-layer orb state — a superset of OrbState that includes
states handled above the base state machine.
Components and hooks should use AppOrbState for their props / return values.
type AppOrbState = OrbState | 'working';
Type OrbState
States that drive the JARVIS orb visual and audio state machine. Single source of truth — copied from src/types.ts.
type OrbState = 'idle' | 'listening' | 'thinking' | 'speaking' | 'follow_up';