Persona

Native monochrome waveform, fluid orb, and ring visuals with five conversational states, live intensity, and a custom renderer.

Show the assistant’s current state

The native monochrome visual represents idle, listening, thinking, speaking, and asleep states. It respects reduced motion and visibility. Supply children for an application-owned visual such as the original monochrome orb avatar.

Use it for

  • Drive state from actual application recording, generation and playback events.
  • Choose waveform, orb, or rings. Waveform remains the default. All five states work with each native visual without an external graphics runtime.
  • Supply intensity from zero to one for measured input or output energy; it is clamped, and asleep always settles to zero. Otherwise each state provides a representative intensity.
  • Motion pauses when offscreen, the document is hidden, paused is true, or state is asleep. Reduced motion and forced colors keep a static visual.
  • onMotionChange reports the effective motion policy initially and when it changes. It does not report asset loading or custom engine playback events.
  • Supply children for static custom content, or renderVisual for state, normalized size and intensity, and animated. A custom graphics renderer should honor animated and release its own resources.
  • CSS-only markup shows a static representative visual; the React component manages visibility and user preference changes.
  • Omit label for a decorative visual beside an already named response. Add label to expose the visual and state as an image.

Avoid

  • Mounting a separate graphics runtime for every historical message.
  • Using animation alone to communicate an error or progress that needs readable text.

React package

npm install @noorddev/vlak-react

Load the stylesheet once at your app root, then import the components you use.

import "@noorddev/vlak-react/css";
import { Persona, type PersonaState, type PersonaVariant, type PersonaVisualContext } from "@noorddev/vlak-react";

Per-component imports are available at @noorddev/vlak-react/components/persona.

Copy the source

npx @noorddev/vlak-cli add persona

Adds the component to components/vlak/. Follow the StyleX setup to compile the source in your application.

shadcn registry

npx shadcn add https://vlak.dev/r/persona.json

Installs the same source through the shadcn CLI.

import { Persona, type PersonaState, type PersonaVariant, type PersonaVisualContext } from "@noorddev/vlak-react";
import type { ReactNode } from "react";

export function AssistantPersona({ state = "idle", variant = "orb", intensity, paused, renderVisual }: {
  state?: PersonaState;
  variant?: PersonaVariant;
  intensity?: number;
  paused?: boolean;
  renderVisual?: (context: PersonaVisualContext) => ReactNode;
}) {
  return <Persona state={state} variant={variant} intensity={intensity} paused={paused}
    size={48} label="Assistant" renderVisual={renderVisual} />;
}

See the integration example to compose these components with your application's model and data.

Persona

Three native monochrome visuals share five conversational states and an optional custom renderer.

PropTypeDefaultDescription
statePersonaState"idle"
variantPersonaVariant"waveform"
sizenumber48
labelstring
intensitynumberInput/output energy in the range 0–1. Asleep always settles to zero.
pausedbooleanfalseStop motion without changing the conversational state.
onMotionChange(animated: boolean) => voidCalled initially and whenever the effective motion policy changes.
childrenReactNodeA custom decorative visual. The application owns its rendering lifecycle.
renderVisual(context: PersonaVisualContext) => ReactNodeCustom visuals should honor animated and release their own rendering resources.

Also accepts HTMLAttributes<HTMLDivElement>.

The ref reaches HTMLDivElement.

  • The default is decorative. A supplied label exposes a named image including the current conversational state.
  • Animation respects reduced motion, forced colors, viewport visibility and document visibility.
  • The component forwards native div attributes, class/style and ref; it does not request audio permissions or play speech.

The same styles are available as CSS. Native HTML provides the static presentation; React or application code supplies state updates and actions.

npm install @noorddev/vlak
import "@noorddev/vlak/css";
<div class="rs-persona rs-persona-thinking" role="img" aria-label="Assistant: thinking" data-state="thinking" data-variant="orb" style="width:48px;height:48px"><span class="rs-persona-orb" aria-hidden="true"><span class="rs-persona-orb-surface"></span></span></div>

Classes

.rs-persona.rs-persona-visual.rs-persona-bar.rs-persona-running.rs-persona-listening.rs-persona-thinking.rs-persona-speaking.rs-persona-asleep.rs-persona-orb.rs-persona-orb-surface.rs-persona-rings.rs-persona-ring