Pixel mascot

Pro

A pixel-art robot that shows what an AI assistant is doing. It idles, thinks, types, celebrates and errors in frame-stepped sprite animations, and stays crisp at every integer size from 24px to 192px.

Live · keyboard ready

Ready when you are

1x
2x
3x
4x
  • A friendly generating indicator next to an assistant reply or in a chat composer.
  • An empty state or onboarding panel where a small character makes an AI feature feel approachable.
  • Image or canvas generation, where a mascot in the corner shows thinking, drawing and done.
  • Products with a playful or retro visual voice that still want precise, calm motion.
  • Detailed agent progress with steps and timings; use agent-status or agent-timeline.
  • Dense tables or toolbars where a 24px character is noise; use status-dot or a spinner.
  • Serious or regulated contexts (finance, health, legal) where a character feels flippant; use text-shimmer.
  • Showing model reasoning content; use reasoning-block.

Installation

Pro source and install commands unlock with a Pro plan.

example.tsx
import { PixelMascot } from "@/components/arc/pixel-mascot/pixel-mascot"; // Inline next to a streaming reply<PixelMascot status={isStreaming ? "writing" : "thinking"} size={2} name="Claude Sonnet 5.5" announce={false} /> // Empty state or composer, self playing<PixelMascot size={6} />

API reference

2 parts. The first is the root.

PixelMascot

A pixel art robot on a 24 by 24 grid that shows what an assistant is doing. Every state is a frame based sprite animation on a fixed 40ms clock, and status changes morph from the current pose one pixel at a time.

PropTypeDefaultDescription
status"idle" | "thinking" | "writing" | "done" | "error"–What the assistant is doing. Leave it out to play the built in loop through every state.
sizenumber4Integer pixel scale from 1 to 8. Each sprite pixel is this many CSS pixels: 1 renders 24px, 2 renders 48px, 4 renders 96px, 8 renders 192px. Other values round and clamp.
namestring"Assistant"Who the mascot stands for, used in the accessible label ("Arc is thinking").
labelstring–Replaces the generated accessible label.
announceboolean–Announces status changes in a polite live region. Defaults to true when status is controlled and false for the built in loop. Turn it off when nearby text already announces progress.
pausedbooleanfalseFreezes the animation on the current frame. The mascot also pauses by itself while off screen.
classNamestring–Class for the inline wrapper.
styleCSSProperties–Style for the inline wrapper, for example a custom --accent.

usePixelMascotLoop

Hook that returns the built in status loop (idle, thinking, writing, done, idle, thinking, error). Use it to keep several mascots in step.

PropTypeDefaultDescription
enabledbooleantruePass false to hold the current status.
  • The sprite is one SVG with role="img" and a label such as "Arc is thinking" that follows the status.
  • A visually hidden polite live region announces status changes when the status is controlled; set announce to false when the surrounding UI already reports progress, to avoid double announcements.
  • Status is never color alone: each state has its own shape (thought bubble, keyboard, happy eyes, crossed eyes) and the label carries the words.
  • The error state uses the danger token for the crossed eyes on a tinted screen, so it reads in light and dark and with any accent.
  • Stepped on purpose: the sprite advances on a fixed 40ms clock and moves in whole pixels. Timings are authored as ease curves in steps, for example the done jump rises fast, holds at the top for 120ms and settles without a rebound.
  • Status changes never cut: lids close and open, eyes slide one pixel per step, arms pass through neighbouring poses, the thought bubble and keyboard step in and out from wherever they are. A change mid animation reverses from the current frame.
  • Loops are seamless by construction: idle bobs on a 2s cycle with blinks and a glance on an 8s cycle, thinking cycles three dots every 1.12s, writing types an eight stroke bar every 1.6s while the eyes scan and return.
  • Only SVG attributes change (transform, x, y, visibility, opacity) from a requestAnimationFrame loop outside React, so there is no layout work or re-render per frame.
  • Pauses off screen with an IntersectionObserver and when paused is set. With reduced motion the mascot holds a clear resting pose for each status: open eyes, bubble with three dots, keyboard, happy eyes or crossed eyes.
  • The sprite is a fixed square of 24 times size CSS pixels and never reflows; pick a smaller size on narrow layouts.
  • Inline-flex with vertical-align middle, so it sits on a text line at sizes 1 and 2.
  • Crisp at every integer size thanks to shape-rendering crispEdges and whole pixel transforms.
  • One SVG with about 40 nodes and no images. The loop writes only changed attributes, about 25 times a second at most, and skips writes on unchanged steps.
  • No React re-render per frame; the loop stops off screen, when paused and under reduced motion.
  • Many instances on one page are fine; each runs its own lightweight loop only while visible.

Notes for AI

Give your coding assistant the Markdown reference instead of screenshots.

  • Choose PixelMascot for a characterful "AI is working" indicator with retro charm: inline in a reply at size 2, in a composer at size 2 or 3, on an image canvas or empty state at size 4 to 8.
  • Map your own lifecycle to the five statuses: request sent is thinking, first token is writing, finished is done, failures are error, and settle back to idle a couple of seconds after done.
  • Keep size an integer; the art is drawn for whole pixel multiples and stays crisp at every one of them.
  • The palette follows --accent and the theme neutrals. Set --accent on a parent to brand it; it looks right with Arc's near neutral grey default too.
  • Pair it with text, such as a TextShimmer label, when users need to know exactly what is happening; the mascot carries the mood, the text carries the detail.

The full library index for assistants is at /llms.txt.