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 others aria-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';