Voice
Persona
An animated AI visual component powered by Rive that responds to different states like listening, thinking, and speaking.
The Persona component displays an animated AI visual that responds to different conversational states. Built with Rive WebGL2, it provides smooth, high-performance animations for various AI interaction states including idle, listening, thinking, speaking, and asleep. The component supports multiple visual variants to match different design aesthetics.
Installation
npx ai-elements@latest add persona
Features
- Smooth state-based animations powered by Rive
- Multiple visual variants (obsidian, mana, opal, halo, glint, command)
- Responsive to five distinct states: idle, listening, thinking, speaking, and asleep
- WebGL2-accelerated rendering for optimal performance
- Customizable size and styling
- Lifecycle callbacks for load, ready, pause, play, and stop events
- TypeScript support with full type definitions
Variants
The Persona component comes with 6 distinct visual variants, each with its own unique aesthetic:
Obsidian (Default)
Mana
Opal
Halo
Glint
Command
Props
<Persona />
The root component that renders the animated AI visual.
Prop
Type
States
The Persona component responds to five distinct states, each triggering different animations:
- idle: The default resting state when the AI is not active
- listening: Displayed when the AI is actively listening to user input (e.g., during voice recording)
- thinking: Shown when the AI is processing or generating a response
- speaking: Active when the AI is delivering a response (e.g., text-to-speech output)
- asleep: A dormant state for when the AI is inactive or in low-power mode
Usage Examples
Basic Usage
import { Persona } from "@repo/elements/persona";
export default function App() {
return <Persona state="listening" variant="opal" />;
}With State Management
import { Persona } from "@repo/elements/persona";
import { useState } from "react";
export default function App() {
const [state, setState] = useState<
"idle" | "listening" | "thinking" | "speaking" | "asleep"
>("idle");
const startListening = () => setState("listening");
const startThinking = () => setState("thinking");
const startSpeaking = () => setState("speaking");
const reset = () => setState("idle");
return (
<div>
<Persona state={state} variant="opal" className="size-32" />
<div>
<button onClick={startListening}>Listen</button>
<button onClick={startThinking}>Think</button>
<button onClick={startSpeaking}>Speak</button>
<button onClick={reset}>Reset</button>
</div>
</div>
);
}With Custom Styling
import { Persona } from "@repo/elements/persona";
export default function App() {
return (
<Persona
state="thinking"
variant="halo"
className="size-64 rounded-full border border-border"
/>
);
}With Lifecycle Callbacks
import { Persona } from "@repo/elements/persona";
export default function App() {
return (
<Persona
state="listening"
variant="glint"
onReady={() => console.log("Animation ready")}
onLoad={() => console.log("Starting to load")}
onLoadError={(error) => console.error("Failed to load:", error)}
onPlay={() => console.log("Animation playing")}
onPause={() => console.log("Animation paused")}
onStop={() => console.log("Animation stopped")}
/>
);
}