import { CanvasHTMLAttributes } from 'react'; import { CSSProperties } from 'react'; import { ForwardRefExoticComponent } from 'react'; import { RefAttributes } from 'react'; /** Face ink for a body colour: dark ink, or light ink on a dark body. */ export declare function autoInk(color: string): string; /** * The form of one outline from its coverage raster (N × N, 0–255, over * design units [-PAD, 100 + PAD]): a pillow height field, its normals as * matcap cells, and baked occlusion; outside texels near the edge borrow * their nearest inside texel so upscaling never bleeds transparent black. */ export declare function bakeBotAvatarForm(cov: Uint8Array | Uint8ClampedArray, N: number, halfDepth: number): BotAvatarForm; /** the matcap's side, in cells */ export declare const BOT_AVATAR_MATCAP_SIZE = 64; export declare const BOT_AVATAR_OVERSCAN = 1.5; /** The texture covers design units [-PAD, 100 + PAD]. */ export declare const BOT_AVATAR_PAD = 3; /** the body's centre sits this fraction of the box below the canvas centre: hops and flips need the room above, not below */ export declare const BOT_AVATAR_RISE = 0.1; export declare const BOT_AVATAR_SPAN: number; declare const BotAvatar: ForwardRefExoticComponent>; export { BotAvatar } export default BotAvatar; /** Screen-space vectors into the cap's frame: un-roll, then the transpose of the rig's rotation; the back cap is the front mirrored in z. */ export declare function botAvatarCapFrame(r: BotAvatarRig): BotAvatarFrame; export declare interface BotAvatarDrawConfig { path: Path2D; face: BotAvatarFace; faceX: number; faceY: number; faceScale: number; color: string; ink: string; shading: BotAvatarShading; /** intensities and geometry of the lighting; omitted means the stock look */ shadow?: number; highlight?: number; depth?: number; /** degrees clockwise from the top, where the light comes from */ light?: number; rim?: number; spread?: number; /** plastic and fabric: the profile through the depth — 1 (the default) a cushion, thickest in the middle and rounding off to nothing at the outline all round; toward 0 a slab with softened edges */ roundness?: number; /** fabric: the pile's style — length, density, edge fuzz, tufts, curl */ fur?: FurStyle; /** plastic and fabric: 0–1, how much colour the light keeps past the palette's full saturation — highlights, sheen and rim stay coloured rather than paling toward white */ vivid?: number; /** fabric: where the back light comes from, degrees clockwise from the top; by default above the toy, toward the side away from the key */ backLight?: number; /** fabric: how far round to the front the key sits, degrees — 0 grazes the toy from the side, 90 lights it from the camera (default 32) */ lightFront?: number; /** fabric: the strength of the highlights along single fibres (default 0) */ shine?: number; /** fabric: 0–1, how soft the back light is — 0 a small source caught on single fibres, 1 a large one, an even glow (default 1) */ backSoftness?: number; /** fabric: the smooth, satin sheen over the body's edge — the key's sheen and the back light's band as even gradients (default 0) */ sheen?: number; /** identifies the outline for the material caches (the type name) */ typeKey?: string; /** no animation loop follows this draw (reduced motion, paused): build * materials now instead of on idle time */ still?: boolean; /** with `still`, bake fabric's pile on idle time all the same; the caller * draws again when it lands (`takeMissed` and `onLanded` in plastic.ts), * as the component does */ furOnIdle?: boolean; /** thin parts (antennae) drawn behind the body with `partsDepth` of its depth; a list draws each piece as its own solid */ parts?: Path2D | Path2D[]; partsDepth?: number; /** the resolved surface: the whirl is white on dark, black on light */ theme?: 'dark' | 'light'; /** the device pixel ratio the context is scaled by: with it given the context's transform is taken as that scale and never read back */ dpr?: number; /** plastic's side slices: filled as vectors, or blitted from sprites of the outline. `auto` (the default) blits on WebKit, where a conic-gradient fill costs thirty times a flat one. */ sides?: 'auto' | 'vector' | 'sprite'; /** the whirl's knobs; 1 everywhere is the stock look */ whirl?: { strength: number; size: number; width: number; length: number; tilt: number; }; /** what the bot wears: a hat, glasses, headphones, a bow tie */ wear?: Wear; } /** * What the face is made of. The eyes alone by default; `mouth` adds a * small mouth that changes with the state. */ export declare type BotAvatarFace = 'eyes' | 'mouth'; export declare const botAvatarFaces: BotAvatarFace[]; export declare interface BotAvatarForm { N: number; /** bilinear cell in the matcap: index of the top-left cell … */ i00: Uint16Array; /** … and the weights inside it, 0–255 */ wx: Uint8Array; wy: Uint8Array; /** baked occlusion × edge darkening, gamma-compensated, 0–255; 0 = not drawn */ ao: Uint8Array; /** signed distance to the outline in design units (positive inside) and the pillow height: kept for the fabric's fibres, which grow down the slope of the height and out past the edge */ sd: Float32Array; h: Float32Array; } export declare interface BotAvatarFrame { L: V3; V: V3; H: V3; U: V3; W: V3; A: V3; B: V3; /** down on screen, in the cap's frame: toward the floor */ D: V3; /** toward the back light on screen, in the cap's frame */ K: V3; } /** Something to wear over the eyes. */ export declare type BotAvatarGlasses = 'none' | 'round' | 'square' | 'shades'; /** Something to wear on the head. */ export declare type BotAvatarHat = 'none' | 'beret' | 'beanie' | 'party' | 'crown'; /** The jump's numbers: an idle flip's and a click's. */ export declare interface BotAvatarJumpConfig { /** how high, in body units (the body is 100 tall) */ height: number; /** seconds in the air */ time: number; /** how much the body stretches in the air, 0–2 */ stretch: number; /** how much it squashes on the ground, before take-off and on landing, 0–2 */ squash: number; /** seconds the landing squash takes, contact to recovered */ squashTime: number; /** the landing squash's shape */ squashEase: BotAvatarSquashEase; /** seconds the body holds its deepest squash on the ground */ groundTime: number; /** how the weight settles through that hold */ groundEase: BotAvatarSquashEase; /** seconds the body takes to rise from its deepest squash back to shape */ riseTime: number; /** how it rises */ riseEase: BotAvatarSquashEase; /** seconds a click's jump takes for its landing squash */ clickSquashTime: number; /** whole turns in the air */ spin: number; /** degrees of lean into it */ lean: number; /** seconds between idle jumps, roughly (±40 %); 0 for none */ every: number; /** when the landing squash begins: seconds before (negative) or after touch-down; 0 is the moment of contact */ land: number; } export declare const botAvatarJumpDefaults: BotAvatarJumpConfig; export declare interface BotAvatarMaterial { shadow: number; highlight: number; spread: number; rim: number; /** 0–1: how much colour the light keeps past the palette's full saturation (see vivify) */ vivid?: number; /** fabric: how far round to the front the key sits, radians — 0 grazes from the side, π/2 lights from the camera */ front?: number; /** fabric: the strength of the light along single fibres, 1 as it comes */ shine?: number; /** fabric: 0–1, how soft the back light is — 0 a small source caught on single fibres, 1 a large one, an even glow reaching further in */ backSoft?: number; /** fabric: the smooth, satin light over the body's edge — the key's sheen and the back light's band, as even gradients rather than on single fibres; 0 by default (matte) */ sheen?: number; } /** Body colour by type — the palette on its own. */ export declare const botAvatarPalette: Record; /** Thin parts (antennae) drawn with a fraction of the body's depth. */ export declare const botAvatarParts: Partial>; export declare interface BotAvatarPose { /** radians; yaw > 0 turns the face to the viewer's right, pitch > 0 looks up */ yaw: number; pitch: number; roll: number; /** body-box units (the 100×100 design space) */ x: number; y: number; sx: number; sy: number; /** 0 shut … 1 open, before blinks */ eyeOpen: number; /** how far each lid is down right now, 0 … 1 */ blinkL: number; blinkR: number; lookX: number; lookY: number; /** the breathing cycle, −1 … 1 */ breath: number; /** working only: how far the eyes have closed into a laugh, 0 … 1 */ laugh: number; /** the cartoon whirl round a spinning body: strength 0 … 1, and where its head is, in radians round the ring */ whirl: number; whirlAngle: number; /** blend weights: default, working, sleeping — they sum to 1 */ w: [number, number, number]; } export declare interface BotAvatarPreset { /** Display name, for labels and the default `aria-label`. */ label: string; /** The type's own body colour. */ color: string; /** The face the type ships with. */ face: BotAvatarFace; /** Where the face sits, in the 100×100 body box. */ faceX: number; faceY: number; /** Face scale: shapes with a small middle wear a smaller face. */ faceScale: number; /** The type's own `brightness` and `saturation`, where the props leave them out (otherwise 1 and 1.5). */ brightness?: number; saturation?: number; } /** * The eighteen types: each body has its own colour and says where on it the * face sits. Every type wears the eyes alone by default. */ export declare const botAvatarPresets: Record; export declare interface BotAvatarProps extends Omit, '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; } export declare interface BotAvatarRig { /** the rig's (floored) cos/sin of yaw and pitch, as used by the slice affines */ cy: number; sy: number; cp: number; sp: number; /** cos(yaw)·cos(pitch), unfloored: the front cap faces the viewer while positive */ facing: number; roll: number; halfDepth: number; cap: number; /** unit vector toward the light on screen */ lx: number; ly: number; /** unit vector toward the back light on screen (fabric); from the key's when not given */ bx?: number; by?: number; /** the avatar box in device pixels (CSS px × dpr) */ dev: number; /** the context's transform for body space (a, b, c, d, e, f): the slices set theirs from it directly rather than through save/restore */ ctm: readonly number[]; /** no animation loop will follow: build the form now rather than on idle time */ still?: boolean; /** the profile through the depth: 1 a cushion, rounding off to nothing at the outline all round; toward 0 a slab with softened edges */ round?: number; } /** * How the body is lit. `fabric` (default): a plush faux fur — a baked * pillow form under a studio light, fine strands combed down the form and * gathered into lit locks, the silhouette breaking into soft tufts with a * haze of hairs; the eyes turn into glossy beads. `plastic`: the same form * as a real glossy material shaded per pixel — a hot spot and a sheen, a * Fresnel rim, a window reflection, saturated shadows. `crisp`: a lit rim with * a clean edge round the front, vector-style. `smooth`: no edge, a soft * shadow and highlight across the whole form. `flat`: the depth alone, no * lighting. */ export declare type BotAvatarShading = 'crisp' | 'smooth' | 'plastic' | 'flat' | 'fabric'; export declare const botAvatarShapes: Record; export declare class BotAvatarSim { readonly pose: BotAvatarPose; state: BotAvatarState; private rand; private t; private wFrom; private tr; private trDuration; private yawW; private pitchW; private rollW; private lookXW; private lookYW; private blink; private blinkAt; private blinkAgain; private dart; private dartAt; private dartX; private dartY; private flip; private flipPoked; private jump; private flipAt; private flipSide; private nod; private nodAt; private hopPhase; private hopCount; /** the hops' gain: the working weight while in the state, then held so a hop under way finishes whole when the state is left */ private hopGain; private laughEv; private laughAt; private prevYaw; private jelly; private jellyV; /** how far the eyes run ahead of a head turn */ private gazeLead; /** the idle gaze: where the head is looking, and when it moves on */ private gazeDir; private gazeAt; /** how far it turns to the side, 1 as the gaze has it */ private turnK; /** the breathing cycle's phase, in turns */ private breathPhase; private ptrX; private ptrY; private ptrS; private ptrTargetX; private ptrTargetY; private ptrTargetS; private baseYaw; constructor(seed: number, state?: BotAvatarState); setState(next: BotAvatarState, immediate?: boolean): void; /** Where the pointer is, relative to the head (−1 … 1 across a head width), and how strongly to follow it (0 lets go). */ setPointer(x: number, y: number, strength: number): void; /** A hop and a full turn, right now, whatever the state. */ poke(): void; /** How far the head turns to the side while idle: 1 as the gaze has it, 0 keeps it facing forward. */ setTurn(k: number): void; /** The jump's numbers; any subset. */ setJump(j: Partial): void; private nextGaze; /** when the next idle jump is due: `every` seconds, give or take 40 % */ private nextFlip; /** Advance by `dt` seconds (already scaled by the speed). */ update(dt: number): void; } /** How the landing squash of a jump plays out. */ export declare type BotAvatarSquashEase = 'sharp' | 'pulse' | 'soft' | 'bouncy'; /** What the bot is doing. Each state is a pose plus its own motion. */ export declare type BotAvatarState = 'default' | 'working' | 'sleeping'; export declare const botAvatarStates: BotAvatarState[]; /** Texture size for an avatar `devicePx` wide (CSS px × device pixel ratio). */ export declare function botAvatarTier(devicePx: number): number; /** The eighteen body shapes. */ export declare type BotAvatarType = 'clover' | 'flower' | 'triangle' | 'square' | 'blob' | 'ghost' | 'circle' | 'drop' | 'star' | 'droid' | 'mech' | 'alien' | 'hexagon' | 'cat' | 'cloud' | 'pill' | 'pebble' | 'puddle'; export declare const botAvatarTypes: BotAvatarType[]; /** Fill `out` (M × M × rgb, sRGB 0–255) with the lit sphere for body colour `c` (linear). */ export declare function buildBotAvatarMatcap(out: Float32Array, c: V3, f: BotAvatarFrame, p: BotAvatarMaterial): void; export declare function drawBotAvatarFrame(ctx: CanvasRenderingContext2D, box: number, pose: BotAvatarPose, cfg: BotAvatarDrawConfig): void; /** The lights the pile's own fibres are baked for: the back light's direction on screen (unit, y down) and how far round to the front the key sits (radians). */ declare interface FurLights { bx: number; by: number; front: number; } /** The pile's style: `length` and `density` multiply the base fibres', `fuzz` (0–1) is how soft the silhouette is, `clumps` (0–1) how much the fibres gather into tufts, `curl` (0–1) how wavy they are, `gravity` (0–1) how much they hang down. */ declare interface FurStyle { length: number; density: number; fuzz: number; clumps: number; curl: number; /** 0–1: how much the pile hangs down — combed down from a parting at the top rather than standing out evenly all round */ gravity: number; } declare interface Lift { /** the baked occlusion with the edge's darkening taken back out */ ao: Uint8Array; /** the sheen band just inside the outline, a gain */ k: Float32Array; } /** Relative luminance (WCAG), 0–1. Unparseable colours count as mid-grey. */ export declare function luminance(color: string): number; /** Parse #rgb / #rrggbb / rgb() / hsl() into 0–255 channels; null for anything else. */ export declare function parseColor(input: string): [number, number, number] | null; /** The still pose of a state, for reduced motion and the first paint. */ export declare function restPose(state: BotAvatarState): BotAvatarPose; /** * A shade of a colour: `dl` moves the lightness (−1..1), `ds` the * saturation. Darker shades get a touch more saturation so they stay * rich instead of going grey, the way a painted surface falls into shadow. */ export declare function shade(color: string, dl: number, ds?: number): string; export declare function shadeBotAvatarTexels(form: BotAvatarForm, mc: Float32Array, px: Uint8ClampedArray, aoMul: Float32Array, lift?: Lift): void; declare type V3 = [number, number, number]; /** Build a form ahead of time (call from an idle callback at mount). */ export declare function warmBotAvatarPlastic(key: string, path: Path2D, devicePx?: number, depth?: number, fabric?: boolean, style?: FurStyle, light?: number, lights?: FurLights): void; declare interface Wear { hat: BotAvatarHat; glasses: BotAvatarGlasses; headphones: boolean; bowTie: boolean; /** the hat's, the headphones' and the bow tie's colour */ color: string; /** the body is plush: the bow tie is the same felt rather than satin */ fabric?: boolean; } export { }