Xzero UI
Pro library

AI mascotPro

A small assistant character, a soft pebble with pill eyes and a companion dot, that shows what the AI is doing. It breathes and glances when idle, leans in to listen, looks up while the dot orbits its head, reads along the line it writes, squints with a sparkle when done and shakes once with worried brows on an error.

$ pnpm dlx shadcn@4.23.0 add @xzero-ui-pro/ai-mascot
Live · keyboard ready

When to use

When not to use

Installation

Register both Xzero UI namespaces in your project's components.json:

{
  "registries": {
    "@xzero-ui": "https://mcp.xzero.co.uk/r/{name}.json",
    "@xzero-ui-pro": "https://mcp.xzero.co.uk/r/pro/{name}.json"
  }
}
npx shadcn@4.23.0 add @xzero-ui-pro/ai-mascot

Install xzero-foundation once, and import @/components/xzero/foundation.css in your app root. No Xzero token is used by this snapshot. For sample portraits, photos, fonts, or logos, download https://mcp.xzero.co.uk/install-assets.mjs and run node xzero-install-assets.mjs <receiving-project>.

Usage

import { AiMascot, type MascotStatus } from "@/components/xzero/ai-mascot/ai-mascot";

// Inline next to a streaming reply
export function ReplyHeader({ phase }: { phase: "thinking" | "streaming" | "complete" | "failed" }) {
  const status: MascotStatus = phase === "streaming" ? "writing" : phase === "complete" ? "done" : phase === "failed" ? "error" : "thinking";
  return (
    <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
      <AiMascot status={status} size={24} name="Atlas" followPointer={false} />
      <span>Atlas</span>
    </div>
  );
}

// Empty state: large, watching the pointer anywhere on the page
<AiMascot status="idle" size={160} followPointer="page" name="Atlas" />

// In a voice composer while the microphone is open
<AiMascot status={recording ? "listening" : "idle"} size={40} tone="ink" announce />

// Brand color body with light eyes
<AiMascot status="thinking" size={96} color="#7747ff" eyeColor="white" />

API reference

AiMascot

A small assistant character drawn in SVG: a soft pebble with pill eyes, a quiet form shade and a companion dot. Six states, each a continuous motion with no loop seam. Idle breathes, floats, blinks and glances around. Listening leans in with wider eyes while the dot pulses like a voice level. Thinking tilts the head and looks up as the dot orbits it, passing behind and in front. Writing looks down and reads along a line the dot writes, then the pen lifts and returns. Done squints happily as the dot turns into a sparkle. Error shakes once and shows worried brows. Status changes blend the two poses over 420ms, never a hard cut, and the eyes follow the pointer on hover.

PropTypeDefaultDescription
status"idle" | "listening" | "thinking" | "writing" | "done" | "error"–What the assistant is doing. Leave unset to play through every state on a loop (the docs demo).
sizenumber96Width and height in px, from 24 (inline next to a message) to 160 (empty state). Below 56 a compact drawing takes over: tighter framing, bolder eyes and dot, no ground line.
tone"accent" | "ink" | "soft""accent"Body color from the theme: the accent with accent-foreground eyes, the foreground ink with background eyes, or a muted surface with a 1px border and foreground eyes.
colorstring–Any CSS color for the body. Overrides tone; the eyes become a dark mix of it unless eyeColor is set.
eyeColorstring–Any CSS color for the eyes and brows.
followPointerboolean | "page"trueEyes follow the pointer while it is over the mascot (true), anywhere on the page ("page", good for empty states) or never. Touch is ignored. Thinking and writing keep their own gaze.
companionbooleantrueShow the companion dot that floats, pulses, orbits, writes and becomes the done sparkle.
groundbooleantrueThe soft contact shadow and the writing line under the mascot. Drawn only at 56px and up.
pausedbooleanfalseFreeze on the current frame. The mascot also pauses by itself off screen and in background tabs, and resumes without a jump.
namestring"Assistant"Used in the accessible label, for example "Atlas, thinking".
labelstring–Overrides the whole accessible label.
announcebooleanfalseAnnounce status changes in a polite live region. Turn it on for the one mascot that carries status, not for decorative copies.
onStatusChange(status: MascotStatus) => void–Called when the self-playing loop (status unset) moves to the next state. Use it to sync a caption or a control.
classNamestring–Class on the root span. Set --mascot-body, --mascot-eye, --mascot-dot, --mascot-shade or --mascot-ground here to restyle.
styleCSSProperties–Inline style on the root span.

Keyboard interactions

KeysAction
NoneThe mascot is a status image and takes no focus. Pair it with a real control when people act on what it shows.

Accessibility

Motion

Responsive behavior

Performance

Notes for AI

Also in ai

Guidance for AI tools

AI mascot: A small assistant character, a soft pebble with pill eyes and a companion dot, that shows what the AI is doing. It breathes and glances when idle, leans in to listen, looks up while the dot orbits its head, reads along the line it writes, squints with a sparkle when done and shakes once with worried brows on an error. Follow the declared prop types and do not invent props. Keep keyboard access, reduced motion support, and both light and dark themes intact when adapting it.

Full library index: https://ui.xzero.co.uk/llms.txt

Browse all components