Bot Avatars
Install: npm install bot-avatars@0.2.2
When to use
Give an agent a configurable animated avatar; the example defaults to lighter crisp shading.
Key native props
| Prop | Meaning |
|---|---|
type | Choose one of 18 public shapes; path may replace the outline, not the type's face placement. |
state | default, working or sleeping. These are visual states, not task completion events. |
shading | crisp/smooth/plastic/flat/fabric. Fabric's fur controls can be expensive; do not multiply many avatars without profiling. |
paused | Freeze movement. interactive enables pointer play; disabling animation does not turn the canvas into a semantic button. |
theme | Synchronize app light/dark explicitly; size and aria-label remain native canvas props. |
Interaction and state checks
Test all states, shape/material changes, pause/resume and pointer play. Keep a textual accessible name and ensure offscreen avatars do not accumulate.
Integration boundaries
No agent identity, image upload, chat transport or authentication is supplied. Accessories and public presets are npm APIs, not permission to copy paid Studio content.
Example files and host setup
Copy the component file and shared.tsx from examples in the source panel, keeping their relative locations; do not copy only the upstream implementation. Install the pinned npm package and use its own export in a browser component. Examples need no Tailwind or competing theme provider, read host html language/theme and provide reduced-motion/graphics fallbacks. Native implementation references are for reading; import via npm rather than copying an incomplete engine. Showcase labels are not new native props. Upstream detailed prose remains English; no full-translation claim is made.
Runnable usage
"use client";
import { useState } from "react";
import { BotAvatar, type BotAvatarType, type BotAvatarState, type BotAvatarShading } from "bot-avatars";
import { DemoFrame, GraphicsGuard, control, demoTheme, t } from "./shared";
export default function Example({ variant = "Default" }: { variant?: string }) {
const shapes: BotAvatarType[] = ["clover", "flower", "triangle", "square", "blob", "ghost", "circle", "drop", "star", "droid", "mech", "alien", "hexagon", "cat", "cloud", "pill", "pebble", "puddle"];
const [type, setType] = useState<BotAvatarType>("clover"), [state, setState] = useState<BotAvatarState>(variant === "Working" ? "working" : variant === "Sleeping" ? "sleeping" : "default"), [shading, setShading] = useState<BotAvatarShading>("crisp"), [paused, setPaused] = useState(variant === "Paused");
return <DemoFrame status={`type=${type}, state=${state}, shading=${shading}, paused=${paused}`} controls={<>
<label>{t("Shape", "形状")} <select style={control} aria-label={t("Avatar shape", "头像形状")} value={type} onChange={e => setType(e.target.value as BotAvatarType)}>{shapes.map(s => <option key={s}>{s}</option>)}</select></label>
<label>{t("State", "状态")} <select style={control} aria-label={t("Avatar state", "头像状态")} value={state} onChange={e => setState(e.target.value as BotAvatarState)}>{["default", "working", "sleeping"].map(s => <option key={s}>{s}</option>)}</select></label>
<label>{t("Material", "材质")} <select style={control} aria-label={t("Avatar material", "头像材质")} value={shading} onChange={e => setShading(e.target.value as BotAvatarShading)}>{["crisp", "smooth", "plastic", "flat", "fabric"].map(s => <option key={s}>{s}</option>)}</select></label>
<button type="button" style={control} aria-pressed={paused} onClick={() => setPaused(!paused)}>{paused ? t("Resume", "继续动画") : t("Pause", "暂停动画")}</button>
</>}><GraphicsGuard><BotAvatar type={type} state={state} shading={shading} size={100} color="#2F67FF" theme={demoTheme()} paused={paused} aria-label={t(`Demo ${type} avatar, ${state}`, `演示 ${type} 头像,${state}`)} /></GraphicsGuard></DemoFrame>;
}
Preview states
Default, Working, Sleeping, Paused
Demo state and mock data do not provide a backend service. Inspect the component props before wiring real data.
bot-avatars
Animated bot avatars for React. Eighteen simple 3D shapes with living faces — round eyes that blink and glance, an optional mouth — and three states an agent can be in: idle, working and sleeping. Each one turns its head, looks around, hops and flips, and every state change is a cross-animation. Vector shapes drawn on a 2D canvas as a lit, inflated body in plush faux fur (or glossy plastic): no WebGL, no runtime dependencies.
Live demo · Repository · Report an issue
Install
npm install bot-avatars
Quick start
import { BotAvatar } from 'bot-avatars';
function Agent({ busy }: { busy: boolean }) {
return <BotAvatar type="clover" state={busy ? 'working' : 'default'} />;
}
Types
Eighteen bodies, each with its own colour:
<BotAvatar type="clover" /> {/* sky */}
<BotAvatar type="flower" /> {/* green */}
<BotAvatar type="triangle" /> {/* magenta */}
<BotAvatar type="square" /> {/* sky */}
<BotAvatar type="blob" /> {/* green */}
<BotAvatar type="ghost" /> {/* white */}
<BotAvatar type="circle" /> {/* lavender */}
<BotAvatar type="drop" /> {/* teal */}
<BotAvatar type="star" /> {/* yellow */}
<BotAvatar type="droid" /> {/* pale, antenna ball, round ears */}
<BotAvatar type="mech" /> {/* slate, wide head, two antennae */}
<BotAvatar type="alien" /> {/* lime, wide brow, narrow chin */}
<BotAvatar type="hexagon" /> {/* coral nut */}
<BotAvatar type="cat" /> {/* apricot, round head, two ears */}
<BotAvatar type="cloud" /> {/* pale sky, five puffs */}
<BotAvatar type="pill" /> {/* indigo, a wide capsule */}
<BotAvatar type="pebble" /> {/* sage, a wide flat stone */}
<BotAvatar type="puddle" /> {/* pink, a taller lumpy blob */}
Your own shape
path takes SVG path data for the body outline, in a 100×100 box centred on (50, 50), in place of the type's own. It is inflated, lit and animated like any stock shape. The type still sets where the face sits, the default colour and the label, so keep the outline solid round the face.
const heart = 'M50 88C50 88 12 64 12 38C12 24 23 14 35 14C42 14 47 18 50 23C53 18 58 14 65 14C77 14 88 24 88 38C88 64 50 88 50 88Z';
<BotAvatar type="circle" path={heart} color="#ff5c8a" />
The stock outlines are exported as botAvatarShapes, a good place to start from.
Faces
The eyes alone by default. face="mouth" adds a small mouth that changes with the state:
<BotAvatar type="clover" face="mouth" />
States
<BotAvatar state="default" /> {/* idle: turns to look around, blinks, a jump with a full turn now and then */}
<BotAvatar state="working" /> {/* busy: hopping — every third hop a spin — with a wide smile and the odd laugh */}
<BotAvatar state="sleeping" /> {/* head down, lids shut, slow breaths and the odd nod */}
Every state is a resting pose plus its own motion. The pose is a small rig — yaw, pitch, roll, position, squash, eyes — and a state switch eases from the old targets to the new ones on a timed curve (soft start, soft finish), so it never snaps or creeps. With prefers-reduced-motion: reduce (or paused) the still pose of the state is drawn instead.
Colour
<BotAvatar type="blob" color="#ff5c8a" /> {/* any body colour */}
<BotAvatar type="clover" color="#111" /> {/* the ink turns light on a dark body */}
<BotAvatar type="star" ink="#4D7CFF" /> {/* or pick the ink yourself */}
<BotAvatar type="drop" brightness={1.25} /> {/* lighter body; below 1 darker */}
<BotAvatar type="drop" saturation={0.7} /> {/* duller body; the default is 1.5 (or the type's own), more vivid than the palette */}
<BotAvatar type="clover" saturation={2.2} /> {/* past 1.5 (up to 2.5) more vivid: richer colour, richer shade, coloured light */}
<BotAvatar type="clover" paused pose={{ yaw: 0.8, pitch: -0.2 }} /> {/* held turned round, as a 3D viewer would */}
<BotAvatar type="clover" shading="plastic" /> {/* glossy plastic instead of the default plush fur */}
<BotAvatar type="square" shading="crisp" /> {/* a lit rim with a clean edge */}
<BotAvatar type="square" shading="smooth" /> {/* soft shadow and highlight, no edge */}
<BotAvatar type="square" shading="flat" /> {/* keep the depth, drop the lighting */}
The palette is exported as botAvatarPalette (type → colour), with botAvatarPresets carrying each type's face and label (and, for a few, their own brightness and saturation).
Shading
fabric is the default, a plush fur (below); plastic is a real material, shaded per pixel: the outline is baked once into a pillow height field (lobes become domes, rays become tubes, the cusps between them fall into shadow), and every frame a lit sphere is evaluated for the head's pose — wrap-around diffuse, a tight hot spot and a broad sheen, a Fresnel rim under a sky, a window reflection, saturated shadows — and mapped onto it. fabric dresses the same form in a plush faux fur, like a toy's, under a strong studio light: a key from the upper left, low and from round the side, with a clear terminator and a real shade side (the colour deepened, never grey, with a saturated band where the key turns into shade), a dim fill, the floor's shade under the body, and a back light from behind the toy that the fibres carry through to a bright rim over the top and the side away from the key, the edge's hairs glowing. Single fibres catch the key as highlights along the locks where it grazes them. backLight sets where the light behind comes from, lightFront how far round to the front the key sits, shine the fibres' highlights, backSoftness how soft the back light is (crisp hairs to an even glow), sheen the smooth satin light over the edge (0 for a matte pile), and rim the back light's strength. The fur is a volume, not a texture: tapered locks lie on the curved body, each a lit mound with a shaded side and a contact shadow under the tip of the one above, made of fine strands with dark roots and lighter tips that cast thin shadows into the pile, gathered into tufts with darker partings between them; it covers the whole body as one continuous pile, round the sides and the back as it turns, its gaps a deep shade of the body's own colour. The silhouette is a soft halo: a haze of fine hairs lit toward their tips, broken into tufts, laid round the whole turned body, so a side view or a flip is as fuzzy as the front. Fabric has its own default light (shadow 1.15, highlight 1.45, light 295, rim 0.6, spread 1.6, lightFront 32, shine 0, sheen 0, backSoftness 1).
Both are drawn on an inflated body: thickest in the middle and rounding off to nothing at the outline all round, like a cushion or a plush toy, so a turn shows a round side rather than the wall of an extruded shape, smooth all the way round to a side view. roundness (0–1, default 1) bends that profile toward a slab with soft edges. crisp lights a rim round the front with a clean edge, smooth lays a soft shadow and highlight over the whole form, flat keeps only the depth. The light itself is adjustable:
<BotAvatar
shadow={1.4} // 0–2, strength of the shadow side (default 1.15 in fabric, 0.35 in the others)
highlight={0.6} // 0–2, strength of the lit side (default 1.45 in fabric, 1.3 in the others)
light={265} // degrees clockwise from the top (default 295 in fabric, 300 in the others: the upper left)
depth={1.5} // 0.2–2, thickness shown when the head turns (default 0.65)
roundness={0.5} // 0–1, plastic and fabric: a cushion at 1, toward a slab at 0 (default 1)
rim={1.5} // 0–2, strength of the back light in fabric, of the Fresnel rim in plastic, rim width in crisp (default 0.6 in fabric, 0.5 in the others)
spread={0.7} // 0.4–2.5, how far the light wraps round in fabric, width of the highlight in plastic, reach of the soft shading in smooth (default 1.6 in fabric, 1.55 in the others)
/>
The plush pile has a style of its own:
<BotAvatar
furLength={2} // 0.3–2.5, length of the pile (default 1)
furDensity={1} // 0.3–2, how many fibres (default 1.6)
furFuzz={0.5} // 0–1, the haze of hairs at the silhouette (default 0.9)
furClumps={0.7} // 0–1, how much the fibres gather into tufts (default 0.4)
furCurl={0.5} // 0–1, straight to wavy (default 0.7)
furGravity={0.4} // 0–1, how much it hangs: combed down from the top, hanging off the sides (default 0.9)
/>
Each style is baked once per shape on idle time and shared by every avatar that wears it.
Wear
A hat, glasses, headphones and a bow tie, each a small 3D object built from lit surfaces and placed on the body's own shape — the hat seated where the head is wide enough to hold it, the headphones on its widest row with the band resting on the head, the glasses over the eyes, the bow tie under the face — and turned with the head, so it tips, turns and flips with the body. They are lit from the body's light and cast a soft shadow where they sit. Each surface is built once per shape and size and painted a strip at a time with the light carried along it, so a hat is a few dozen canvas fills — about 0.2–0.8 ms a frame at 120 px.
<BotAvatar type="clover" hat="beret" />
<BotAvatar type="triangle" glasses="round" bowTie />
<BotAvatar type="flower" headphones accessoryColor="#f4efe6" />
hat:none(default),beret(pleated felt with a leather binding and a stalk),beanie(knit stitch by stitch, with a ribbed cuff and a yarn pompom),party(a striped paper cone with a foil trim and tinsel) orcrown(gold, with ridged points, pearls, cut stones, a velvet cap and an orb and cross)- the headphones are over-ear: leather cushions, brushed metal rings and yokes, a stitched padded band; the glasses are acetate with rounded rims and reflecting lenses; the bow tie is satin, or felt on a plush body
glasses:none(default),round,squareorshadesheadphones,bowTie: booleansaccessoryColor: the hat's, the headphones' and the bow tie's colour, a soft black by default (the crown stays gold)
Other props
<BotAvatar
type="star"
size={40} // px, or any CSS length; default 64
speed={1.5} // multiplier on every animation
paused={false} // freeze on the current frame
seed={0.3} // 0–1: offsets the blink and glance loops; auto by default
interactive={false} // no pointer following, no hop on click
theme="light" // the surface the avatar sits on; auto by default
aria-label="Talent scout, working" // overrides the per-state default
/>
All other <canvas> props (className, style, onClick, data-*, …) pass through. The canvas draws a little larger than its box and pulls itself back with negative margins, so a hop or a flip is never clipped while the layout stays exactly size square.
Drawing it yourself
The rig and the renderer are exported for custom uses — a filmstrip, a sprite sheet, another canvas:
import { BotAvatarSim, drawBotAvatarFrame, botAvatarShapes, botAvatarPresets, autoInk, BOT_AVATAR_OVERSCAN } from 'bot-avatars';
const sim = new BotAvatarSim(0.5, 'working');
sim.update(1 / 60); // advance a frame
drawBotAvatarFrame(ctx, 64, sim.pose, {
path: new Path2D(botAvatarShapes.clover),
...botAvatarPresets.clover, // face, faceX, faceY, faceScale, color
ink: autoInk(botAvatarPresets.clover.color),
shading: 'plastic',
typeKey: 'clover', // names the outline for the material caches, the key warmBotAvatarPlastic takes
dpr: devicePixelRatio, // the scale the context is set to (optional; else read from the context)
sides: 'auto', // plastic's side slices: 'vector' fills, or 'sprite' blits (what WebKit gets by default)
}); // on a canvas 64 * BOT_AVATAR_OVERSCAN * devicePixelRatio px square; the body's centre sits BOT_AVATAR_RISE * 64 below its middle
In plastic and fabric the first frame of a new type bakes its form (a few ms, done on idle time when an animation loop is running; the smooth look stands in until then). warmBotAvatarPlastic(type, path, devicePx) bakes ahead of time; warmBotAvatarPlastic(type, path, devicePx, depth, true) also queues fabric's pile, in small steps on idle time.
The idle look
Idle, the head looks to a corner, stays a few seconds and swings across to the opposite one. turn scales how far it goes to the side:
<BotAvatar turn={1.4} /> {/* 0–2; 1 as the library has it, 0 faces forward */}
The jump
Now and then in the idle state, and on every click, the avatar jumps and turns right round. Its numbers are props:
<BotAvatar
jumpHeight={32} // body units; the body is 100 tall (default 26)
jumpTime={0.8} // seconds in the air (0.68)
jumpStretch={1.3} // stretch in the air, 0–2 (1)
jumpSquash={1.4} // squash on the ground, before take-off and on landing, 0–2 (1.15)
jumpSquashTime={0.3} // seconds the landing squash takes (0.37)
jumpSquashEase="bouncy" // sharp | pulse | soft | bouncy (pulse)
jumpGroundTime={0.2} // seconds held at the deepest squash on the ground (0.11; 0 for none)
jumpGroundEase="bouncy" // how the weight settles through it: sharp | pulse | soft | bouncy (pulse)
jumpRiseTime={0.5} // seconds from the deepest squash back to shape (0.33)
jumpRiseEase="bouncy" // how it rises: sharp | pulse | soft | bouncy (pulse)
jumpClickSquashTime={0.8} // seconds a click's jump takes for its crouch and landing squash (0.24)
jumpSpin={2} // whole turns in the air, 0–2 (1)
jumpLean={10} // degrees of lean into it (6)
jumpEvery={5} // seconds between idle jumps, give or take 40 %; 0 for none (8)
jumpLand={-0.08} // when the landing squash begins: seconds before (negative) or after touch-down (0, at contact)
/>
Pointer play
By default an avatar's eyes and head follow a pointer that comes within a few head widths, and a click makes it hop and turn right round, in any state. Turn it off with interactive={false}; your own onClick still runs either way.
The whirl
Off by default. With whirl set, a spin — the idle jump, a click, the working spin hop — draws a puff of motion round the body: one tapered trail on a tilted ring, made of the body's own material as a translucent plastic tube, lit from the same light, passing behind the body on the far side and over the face on the near side, where it casts a soft shadow. It is only there while the turn is under way, and it is already moving when it appears.
<BotAvatar
whirl={1} // 0–2 strength; off by default
whirlSize={1.1} // 0.6–1.6 ring size
whirlWidth={0.8} // 0.4–2 trail thickness
whirlLength={1.3} // 0.4–1.6 trail length round the ring
whirlTilt={1.4} // 0.5–1.8, how open the ring is seen
/>
A row of them
Each instance seeds its own blink timing from its React id, so a roster never blinks in unison. Pass the same seed to two avatars to make them move in step.
{agents.map((a) => (
<BotAvatar key={a.id} type={a.avatar} state={a.busy ? 'working' : 'default'} size={32} />
))}
Accessibility & performance
role="img"with a per-statearia-label("Clover bot, working") out of the box.prefers-reduced-motion: reducekeeps the pose and drops the motion.- One shared animation frame loop for every avatar on the page; each one pauses when scrolled offscreen or when the tab is hidden. Device-pixel-ratio capped at 2.
- In
crisp,smoothandflatthe body is seventeen copies of its outline stacked through the depth with a pillow profile; inplasticandfabricit is slices through an inflated height field, each in the side's own light, with the lit front laid over them — a rounded solid that turns and flips, in plain 2D canvas fills, about 1 ms of main thread a frame (fabric a little more: its fur is baked once per shape on idle time and laid over the whole body in one pass). Cheap enough for a whole roster at once. - Server rendering works: the canvas paints on the client, after mount.
License
MIT © Jakub Antalik
Source-backed parameter reference
Implementation signatures and types are generated from the pinned local source. Optional props, native inherited types, union branches and never exclusions are preserved. A forwardRef implementation's ref is a React reference, not an additional business prop.
BotAvatar({
type = 'clover',
path,
face,
state = 'default',
size = 64,
color,
ink,
brightness: brightnessProp,
saturation: saturationProp,
speed = 1,
paused = false,
seed,
shading = 'fabric',
hat = 'none',
glasses = 'none',
headphones = false,
bowTie = false,
accessoryColor = '#27272b',
shadow,
highlight,
depth = 0.65,
roundness = 1,
furLength = 1,
furDensity = 1.6,
furFuzz = 0.9,
furClumps = 0.4,
furCurl = 0.7,
furGravity = 0.9,
light,
rim,
spread,
backLight,
lightFront,
shine,
sheen,
backSoftness,
pose: heldPose,
interactive = true,
turn = 1,
theme = 'auto',
whirl = 0,
whirlSize = 1,
whirlWidth = 1,
whirlLength = 1,
whirlTilt = 1,
jumpHeight = 26,
jumpTime = 0.68,
jumpStretch = 1,
jumpSpin = 1,
jumpLean = 6,
jumpEvery = 8,
jumpLand = 0,
jumpSquash = 1.15,
jumpSquashTime = 0.37,
jumpSquashEase = 'pulse',
jumpGroundTime = 0.11,
jumpGroundEase = 'pulse',
jumpRiseTime = 0.33,
jumpRiseEase = 'pulse',
jumpClickSquashTime = 0.24,
className,
style,
'aria-label': ariaLabel,
...rest
}, ref)
export type BotAvatarType =
| 'clover'
| 'flower'
| 'triangle'
| 'square'
| 'blob'
| 'ghost'
| 'circle'
| 'drop'
| 'star'
| 'droid'
| 'mech'
| 'alien'
| 'hexagon'
| 'cat'
| 'cloud'
| 'pill'
| 'pebble'
| 'puddle';
export type BotAvatarFace = 'eyes' | 'mouth';
export type BotAvatarState = 'default' | 'working' | 'sleeping';
export type BotAvatarSquashEase = 'sharp' | 'pulse' | 'soft' | 'bouncy';
export type BotAvatarShading = 'crisp' | 'smooth' | 'plastic' | 'flat' | 'fabric';
export type BotAvatarHat = 'none' | 'beret' | 'beanie' | 'party' | 'crown';
export type BotAvatarGlasses = 'none' | 'round' | 'square' | 'shades';
export interface BotAvatarProps
extends Omit<CanvasHTMLAttributes<HTMLCanvasElement>, 'color' | 'ref'> {
/** Body shape. Default `clover`. */
type?: BotAvatarType;
/**
* A custom body outline: SVG path data in the 100×100 body box, centred
* on (50, 50), replacing the type's own (and its antennae). The type
* still sets the face's place, the default colour and the label, so keep
* the outline solid round the face. Default: the type's outline.
*/
path?: string;
/** Face kind. Defaults to the type's own. */
face?: BotAvatarFace;
/** What the bot is doing: `default` (idle), `working` (hopping, spinning) or `sleeping`. */
state?: BotAvatarState;
/** Rendered size in px, or any CSS length. Default `64`. */
size?: number | string;
/** Body colour. Defaults to the type's palette colour. */
color?: string;
/** Face ink. Defaults to dark, or light on a dark body. */
ink?: string;
/**
* Lightness of the body colour: 1 as the palette has it, below 1 darker,
* above 1 lighter (0.5–1.5 is the useful range). Default `1`, or the
* type's own (the star's is `1.1`).
*/
brightness?: number;
/**
* Saturation of the body colour: 1 as the palette has it, below 1
* duller, above 1 more vivid, 0.5–2.5. Past 1.5, where most of the
* palette is already as saturated as a screen shows it, the colour is
* pushed along its own hue toward its most vivid shade (deepening by at
* most 15% where the screen cannot show it brighter), the shade side
* grows richer, and `plastic` and `fabric` keep
* more of it in the light — highlights, sheen, rim and fur tips stay
* coloured rather than paling toward white. Default `1.5`, or the
* type's own (the star's is `1.84`).
*/
saturation?: number;
/** Multiplier on every animation's speed. Default `1`. */
speed?: number;
/** Freeze every animation on its current frame. */
paused?: boolean;
/**
* 0–1. Offsets the blink and glance timing so a row of avatars does not
* blink in unison. Defaults to a value derived from the instance id.
*/
seed?: number;
/** How the body is lit: `fabric` (default), `plastic`, `crisp`, `smooth`
* or `flat`. `true` and `false` mean crisp and flat. */
shading?: BotAvatarShading | boolean;
/** A hat, sitting on the top of the head and turning with it: `beret`,
* `beanie`, `party` or `crown`. Default `none`. */
hat?: BotAvatarHat;
/** Glasses over the eyes: `round`, `square` or `shades`. Default `none`. */
glasses?: BotAvatarGlasses;
/** Headphones over the head, a cup on either side. Default `false`. */
headphones?: boolean;
/** A bow tie under the face. Default `false`. */
bowTie?: boolean;
/** Colour of the hat, the headphones and the bow tie. Default a soft black. */
accessoryColor?: string;
/** Strength of the shadow side, 0–2. Default `0.35` (`1.15` for `fabric`). */
shadow?: number;
/** Strength of the lit side, 0–2. Default `1.3` (`1.45` for `fabric`). */
highlight?: number;
/** Thickness of the body, 0.2–2: what shows when it turns or flips. Default `0.65`. */
depth?: number;
/**
* `plastic` and `fabric`: the body's profile through its depth, 0–1. At
* `1` (default) it is inflated like a cushion or a plush toy — thickest in
* the middle and rounding off to nothing at the outline all round, so a
* turn shows a round side; toward `0` it becomes a slab with soft edges.
*/
roundness?: number;
/** `fabric`: length of the pile, 0.3–2.5. Default `1`. */
furLength?: number;
/** `fabric`: how many fibres, 0.3–2. Default `1.6`. */
furDensity?: number;
/** `fabric`: softness of the silhouette — the haze of fine hairs standing past it, 0–1. Default `0.9`. */
furFuzz?: number;
/** `fabric`: how much the fibres gather into tufts, 0–1. Default `0.4`. */
furClumps?: number;
/** `fabric`: how wavy the fibres are, 0 (straight) – 1. Default `0.7`. */
furCurl?: number;
/**
* `fabric`: how much the pile hangs, 0–1 — combed down from a parting at
* the top, lying over the top edge and hanging off the sides and bottom,
* rather than standing out evenly all round. Default `0.9`.
*/
furGravity?: number;
/** Where the light comes from, in degrees clockwise from the top. Default `300` (`295` for `fabric`): from the upper left, like a studio key light. */
light?: number;
/** Width of the lit rim in `crisp` shading, strength of the Fresnel rim in `plastic`, of the back light in `fabric` — the bright rim it wraps round the top and sides, and the glow of the edge's hairs — 0–2. Default `0.5` (`0.6` for `fabric`). */
rim?: number;
/** `fabric`: where the back light comes from, in degrees clockwise from the top. Default: above the toy, toward the side away from `light`. */
backLight?: number;
/** `fabric`: how far round to the front the key light sits, in degrees — `0` grazes the toy from the side (dramatic), `85` lights it nearly from the camera (flat). Default `32`. */
lightFront?: number;
/** `fabric`: strength of the highlights along single fibres where the key grazes the pile, 0–2. Default `0` (off: a soft, matte pile). */
shine?: number;
/** `fabric`: the smooth, satin sheen over the body's edge — the key's sheen and the back light's band as even gradients, a material shine rather than the fur's own — 0 (matte, only the fibres shine) – 2. Default `0`. */
sheen?: number;
/** `fabric`: how soft the back light is, 0–1 — `0` a small source caught on single fibres as crisp bright hairs, `1` a large one, an even glow reaching further in from the edge and fading out gently. Default `1`. */
backSoftness?: number;
/** Reach of the soft shading in `smooth`, width of the highlight in `plastic`, how far the light wraps round in `fabric`, 0.4–2.5. Default `1.55` (`1.6` for `fabric`). */
spread?: number;
/**
* Holds the body at this orientation, in radians — `yaw` turns it to the
* viewer's right, `pitch` tips it to look up, `roll` tilts it — in the
* state's rest pose, overriding the animation's turns, hops and glances
* (and pointer play) while it is set. For turning an avatar round by
* hand, as a 3D viewer does; usually with `paused`.
*/
pose?: { yaw?: number; pitch?: number; roll?: number };
/**
* Pointer play: the eyes and head follow a pointer that comes near, and
* a click makes the avatar hop and turn right round. Default `true`.
*/
interactive?: boolean;
/**
* The surface the avatar sits on, for touches that have to read against
* it. `auto` (default) reads an ancestor `data-theme` attribute or
* `dark` / `light` class, then `prefers-color-scheme`.
*/
theme?: 'auto' | 'dark' | 'light';
/**
* How far the head turns from side to side while idle, 0–2: `1` as the
* library has it, `0` keeps it facing forward. Default `1`.
*/
turn?: number;
/** The whirl round a spin: its strength, 0–2. Off by default (`0`); `1` turns it on. */
whirl?: number;
/** Size of the whirl's ring, 0.6–1.6. Default `1`. */
whirlSize?: number;
/** Thickness of the whirl's trail, 0.4–2. Default `1`. */
whirlWidth?: number;
/** Length of the trail round the ring, 0.4–1.6. Default `1`. */
whirlLength?: number;
/** How flat the ring is seen, 0.5–1.8 (higher is more open). Default `1`. */
whirlTilt?: number;
/** The jump (an idle flip, a click): how high, in body units — the body is 100 tall. Default `26`. */
jumpHeight?: number;
/** Seconds the jump spends in the air. Default `0.68`. */
jumpTime?: number;
/** How much the body stretches in the air, 0–2. Default `1`. */
jumpStretch?: number;
/** How much the body squashes on the ground, before take-off and on landing, 0–2. Default `1.15`. */
jumpSquash?: number;
/** Seconds the landing squash takes, from contact to recovered. Default `0.37`. */
jumpSquashTime?: number;
/**
* How the landing squash plays out: `sharp` (all at once, then eases
* off), `pulse` (a quick press that recovers without a wobble, the
* default), `soft` (eases in and out), `bouncy` (overshoots into a
* stretch and settles).
*/
jumpSquashEase?: BotAvatarSquashEase;
/** Seconds a jump holds its deepest squash on the ground before recovering. Default `0.11`. */
jumpGroundTime?: number;
/**
* How the weight settles through that hold, in the same shapes as
* `jumpSquashEase`: the body presses a little deeper and comes back to
* the held depth, `sharp` at once, `pulse` quickly, `soft` in the
* middle, `bouncy` with a wobble. Default `pulse`.
*/
jumpGroundEase?: BotAvatarSquashEase;
/** Seconds the body takes to rise from its deepest squash back to its own shape. Default `0.33`. */
jumpRiseTime?: number;
/**
* How it rises: `sharp` lets go at once and eases in to rest, `pulse`
* leaves quickly with a long settle, `soft` eases out of the squash and
* into rest, `bouncy` passes rest into a slight stretch and settles
* back. Default `pulse`.
*/
jumpRiseEase?: BotAvatarSquashEase;
/** Seconds a click's jump takes for its landing squash (an idle jump's uses `jumpSquashTime`). Default `0.24`. */
jumpClickSquashTime?: number;
/** Whole turns made in the air, 0–2. Default `1`. */
jumpSpin?: number;
/** Degrees of lean into a jump. Default `6`. */
jumpLean?: number;
/** Seconds between idle jumps, give or take 40 %; 0 for none. Default `8`. */
jumpEvery?: number;
/** When the landing squash begins: seconds before touch-down (negative, bracing for the ground) or after it. Default `0`, the moment of contact. */
jumpLand?: number;
className?: string;
style?: CSSProperties;
}
Destructuring defaults in source
Only defaults written directly in parameter/props destructuring are listed. Conditional expressions, runtime theme and computed values require source inspection; this is not an exhaustive behavior-default list.
// BotAvatar
type = 'clover'
// BotAvatar
state = 'default'
// BotAvatar
size = 64
// BotAvatar
speed = 1
// BotAvatar
paused = false
// BotAvatar
shading = 'fabric'
// BotAvatar
hat = 'none'
// BotAvatar
glasses = 'none'
// BotAvatar
headphones = false
// BotAvatar
bowTie = false
// BotAvatar
accessoryColor = '#27272b'
// BotAvatar
depth = 0.65
// BotAvatar
roundness = 1
// BotAvatar
furLength = 1
// BotAvatar
furDensity = 1.6
// BotAvatar
furFuzz = 0.9
// BotAvatar
furClumps = 0.4
// BotAvatar
furCurl = 0.7
// BotAvatar
furGravity = 0.9
// BotAvatar
interactive = true
// BotAvatar
turn = 1
// BotAvatar
theme = 'auto'
// BotAvatar
whirl = 0
// BotAvatar
whirlSize = 1
// BotAvatar
whirlWidth = 1
// BotAvatar
whirlLength = 1
// BotAvatar
whirlTilt = 1
// BotAvatar
jumpHeight = 26
// BotAvatar
jumpTime = 0.68
// BotAvatar
jumpStretch = 1
// BotAvatar
jumpSpin = 1
// BotAvatar
jumpLean = 6
// BotAvatar
jumpEvery = 8
// BotAvatar
jumpLand = 0
// BotAvatar
jumpSquash = 1.15
// BotAvatar
jumpSquashTime = 0.37
// BotAvatar
jumpSquashEase = 'pulse'
// BotAvatar
jumpGroundTime = 0.11
// BotAvatar
jumpGroundEase = 'pulse'
// BotAvatar
jumpRiseTime = 0.33
// BotAvatar
jumpRiseEase = 'pulse'
// BotAvatar
jumpClickSquashTime = 0.24
Native and external types
External types remain defined by React or native dependencies, not manually expanded into guessed props. The installed version's TypeScript definitions are authoritative.
HTMLCanvasElement
Omit<CanvasHTMLAttributes<HTMLCanvasElement>, 'color' | 'ref'>
CanvasHTMLAttributes<HTMLCanvasElement>
CSSProperties