BootLoop
Something is starting up and nobody knows how long it will take.
Part of
@aora-bot/surfaces, not@aora-bot/react:pnpm add @aora-bot/surfaces @aora-bot/react, and import@aora-bot/surfaces/styles.cssafter the React stylesheet.
Activity, not progress
An indeterminate wait is the one case where a progress bar lies, so this scene shows activity instead: the character alternates between working and thinking — under the hood a whirl belt swapping for three travelling beads — while a scanline crosses the screen behind it. durationMs is the time on each state; the pair makes one cycle.
onCycle exists so the host can escalate. Two cycles is a slow start; twelve is a problem worth saying something about, and only the host knows which message that is. The demo above changes its copy after three.
inFront puts the character in front of the screen rather than behind it, for a layout where the bezel is scenery rather than the thing booting.
LoadingMark
A placeholder in the shape of the character that is coming.
A grey circle where a hexagon will land is a layout shift waiting to happen, and a spinner in an avatar slot is a second kind of motion beside whatever the page is already doing. This is the silhouette itself — the same shape generator, as a CSS mask — with a shimmer over it, so the placeholder and the character occupy the identical outline and the swap on ready is a cross-fade rather than a replacement.
Both layers stay mounted through the fade. Unmounting the placeholder on ready would show the character's first frame against nothing for a frame, which is the flicker this exists to avoid.
API
| Prop | Type | Default | Description |
|---|---|---|---|
body | string | — | — |
className | string | — | — |
color | "black" | "brown" | "red" | "orange" | "yellow" | "green" | "cyan" | "blue" | "violet" | "magenta" | "pink" | "gray" | — | — |
durationMs | number | 2600 | Time on each state. The pair makes one full cycle. |
face | "cute" | "eyes" | "line" | — | — |
inFront | boolean | false | The character stands in front of the screen rather than behind it. |
lineWeight | number | — | — |
nose | "slant" | "angular" | "hook" | "long" | "curve" | "bow" | null | — | — |
onCycle | ((cycle: number) => void) | — | Called at the end of every cycle, for a host counting how long this has gone on. |
shape | "mochi" | "circle" | "blob" | "pebble" | "egg" | "bun" | "tofu" | "pill" | "hex" | "onigiri" | "gem" | "cloud" | "drop" | "leaf" | "flower" | "clover" | "sprout" | "mushroom" | "acorn" | "cactus" | "pear" | "apple" | "strawberry" | "cherry" | "star" | "heart" | "flame" | "bell" | "ghost" | "bot" | "crescent" | "boba" | "fish" | "octopus" | "cat" | "bunny" | "bear" | "chick" | "penguin" | "pig" | "fox" | "bob" | "topknot" | "spiky" | "curly" | "twinbuns" | — | — |
sizePx | number | — | — |
style | CSSProperties | — | — |
title | string | — | — |
widthPx | number | 280 | — |
LoadingMark
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | — | — |
color | "black" | "brown" | "red" | "orange" | "yellow" | "green" | "cyan" | "blue" | "violet" | "magenta" | "pink" | "gray" | — | — |
face | "cute" | "eyes" | "line" | — | — |
lineWeight | number | — | — |
nose | "slant" | "angular" | "hook" | "long" | "curve" | "bow" | null | — | — |
onSettle | ((from: "idle" | "sleeping" | "drowsy" | "bored" | "waking" | "powering-down" | "listening" | "thinking" | "searching" | "reading" | "writing" | "working" | "loading" | "progress" | "radar" | "orbit" | "dictating" | "uploading" | "sending" | "receiving" | "messaging" | "waiting" | "spawning" | "composing" | "dragging" | "happy" | "excited" | "laughing" | "playful" | "proud" | "celebrate" | "bouncing" | "shy" | "sad" | "angry" | "confused" | "suspicious" | "surprised" | "scared" | "curious" | "humming" | "alerting" | "notifying" | "refusing", to: "idle" | "sleeping" | "drowsy" | "bored" | "waking" | "powering-down" | "listening" | "thinking" | "searching" | "reading" | "writing" | "working" | "loading" | "progress" | "radar" | "orbit" | "dictating" | "uploading" | "sending" | "receiving" | "messaging" | "waiting" | "spawning" | "composing" | "dragging" | "happy" | "excited" | "laughing" | "playful" | "proud" | "celebrate" | "bouncing" | "shy" | "sad" | "angry" | "confused" | "suspicious" | "surprised" | "scared" | "curious" | "humming" | "alerting" | "notifying" | "refusing") => void) | — | Fires when a finite `state` (`spawning`, `celebrate`, …) has resolved to its settle target. The inner mark is paused until `ready`, so the clock starts at the cross-fade, not at mount. |
ready | boolean | false | Swap the placeholder for the live character. |
shape | "mochi" | "circle" | "blob" | "pebble" | "egg" | "bun" | "tofu" | "pill" | "hex" | "onigiri" | "gem" | "cloud" | "drop" | "leaf" | "flower" | "clover" | "sprout" | "mushroom" | "acorn" | "cactus" | "pear" | "apple" | "strawberry" | "cherry" | "star" | "heart" | "flame" | "bell" | "ghost" | "bot" | "crescent" | "boba" | "fish" | "octopus" | "cat" | "bunny" | "bear" | "chick" | "penguin" | "pig" | "fox" | "bob" | "topknot" | "spiky" | "curly" | "twinbuns" | 'blob' | — |
sizePx | number | 28 | — |
state | "idle" | "sleeping" | "drowsy" | "bored" | "waking" | "powering-down" | "listening" | "thinking" | "searching" | "reading" | "writing" | "working" | "loading" | "progress" | "radar" | "orbit" | "dictating" | "uploading" | "sending" | "receiving" | "messaging" | "waiting" | "spawning" | "composing" | "dragging" | "happy" | "excited" | "laughing" | "playful" | "proud" | "celebrate" | "bouncing" | "shy" | "sad" | "angry" | "confused" | "suspicious" | "surprised" | "scared" | "curious" | "humming" | "alerting" | "notifying" | "refusing" | — | — |
style | CSSProperties | — | — |
Next
- Boot and loading — two different waits
- Belts and particles — how belt states are drawn