# Thinking Orbs

- Page: https://jiguang132.com/resources/libraries-dev/docs/thinking-orbs
- Resource: Libraries.dev (https://jiguang132.com/resources/libraries-dev.md)
- All guides: https://jiguang132.com/resources/libraries-dev/docs.md

Install: `npm install thinking-orbs@0.3.2`


## When to use

Render a compact visual state for a coding or chat agent.

## Key native props

| Prop | Meaning |
|---|---|
| `state` | Nine native literal states: working, searching, solving, listening, connecting, weaving, composing, breathing, shaping. |
| `size` | 20, 32 or 64; 20 and 64 are tuned designs, 32 is interpolated. Arbitrary numeric sizes are not this API. |
| `paused` | Freeze the current frame. speed, dots and dotSize tune the animation and density. |
| `theme` | auto observes ancestor theme attributes/classes, while light/dark pin the palette. |
| `color` | Optional ink tint; preserve a useful contrast against the transparent canvas background. |

## Interaction and state checks

Switch every state, all three sizes, pause/resume and light/dark. Provide nearby semantic status text instead of relying on a canvas animation alone.

## Integration boundaries

listening does not capture audio and searching does not call a search service. Advanced frame/opts/gravity are native escape hatches; they are not a guaranteed universal state-machine contract.

## 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

```tsx
"use client";
import { useState } from "react";
import { ThinkingOrb, type OrbState, type OrbSize } from "thinking-orbs";
import { DemoFrame, GraphicsGuard, control, demoTheme, t } from "./shared";
export default function Example({ variant = "Default" }: { variant?: string }) {
  const states: OrbState[] = ["working", "searching", "solving", "listening", "connecting", "weaving", "composing", "breathing", "shaping"];
  const [state, setState] = useState<OrbState>(states.find(s => s === variant.toLowerCase()) ?? "working"), [size, setSize] = useState<OrbSize>(64), [paused, setPaused] = useState(variant === "Paused");
  return <DemoFrame status={`state=${state}, size=${size}, paused=${paused}`} controls={<>
    <label>{t("State", "状态")} <select style={control} aria-label={t("Orb state", "光球状态")} value={state} onChange={e => setState(e.target.value as OrbState)}>{states.map(s => <option key={s}>{s}</option>)}</select></label>
    <label>{t("Size", "尺寸")} <select style={control} aria-label={t("Orb size", "光球尺寸")} value={size} onChange={e => setSize(Number(e.target.value) as OrbSize)}>{[20, 32, 64].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><ThinkingOrb state={state} size={size} theme={demoTheme()} paused={paused} aria-label={t(`Agent visual state: ${state}`, `智能体视觉状态：${state}`)} /></GraphicsGuard></DemoFrame>;
}

```


## Preview states

Default, Searching, Solving, Listening, Connecting, Weaving, Composing, Breathing, Shaping, Paused

Demo state and mock data do not provide a backend service. Inspect the component props before wiring real data.

# thinking-orbs

Dotted thought-orb loading indicators for AI & agent UIs. Nine hand-tuned animated states, each shipped at two purpose-tuned sizes, rendered on a plain 2D canvas — no WebGL, no filters, works identically in Chrome, Safari and Firefox.

[Live demo](https://libraries.dev/orbs) · [Repository](https://github.com/Jakubantalik/Libraries.dev) · [Report an issue](https://github.com/Jakubantalik/Libraries.dev/issues)

## Install

```bash
npm install thinking-orbs
```

## Quick start

```tsx
import { ThinkingOrb } from 'thinking-orbs';

function Status() {
  return <ThinkingOrb state="searching" size={64} />;
}
```

## States

Nine verbs an agent can be doing, each a distinct animation:

```tsx
<ThinkingOrb state="working" />     {/* particles on tilted orbits */}
<ThinkingOrb state="searching" />   {/* a scan meridian sweeps a dotted globe */}
<ThinkingOrb state="solving" />     {/* bands scramble, then click back solved */}
<ThinkingOrb state="listening" />   {/* a waveform rolls through the rings */}
<ThinkingOrb state="connecting" />  {/* a constellation wires itself */}
<ThinkingOrb state="weaving" />     {/* three strands plait around the sphere */}
<ThinkingOrb state="composing" />   {/* an undulating multi-band sash */}
<ThinkingOrb state="breathing" />   {/* a ring slowly morphing */}
<ThinkingOrb state="shaping" />     {/* dotted outline: circle → triangle → square */}
```

## Sizes

Two tuned presets — separate designs, not a scale factor. `64` for chat-avatar scale, `20` for inline-text scale. Each carries its own dot count, dot size and speed tuning:

```tsx
<ThinkingOrb state="working" size={64} />
<ThinkingOrb state="working" size={20} />
```

## Theme

Strictly monochrome — light ink for dark backgrounds, dark ink for light backgrounds — with the mode picked automatically from the host project:

```tsx
<ThinkingOrb theme="auto" />   {/* default — detects from the project */}
<ThinkingOrb theme="dark" />   {/* pin: light dots for dark backgrounds */}
<ThinkingOrb theme="light" />  {/* pin: dark dots for light backgrounds */}
```

`auto` resolves in three layers and updates live when any of them change:

1. an ancestor `data-theme="dark|light"` attribute or `dark`/`light` class (the Tailwind / shadcn convention), watched via `MutationObserver`;
2. otherwise `prefers-color-scheme`, subscribed for live OS theme switches;
3. SSR-safe — the canvas paints only on the client, after the theme has resolved.

## Other props

```tsx
<ThinkingOrb
  state="solving"
  size={20}
  speed={1.5}          // multiplier on the preset's baked speed
  paused={false}       // freeze on the current frame
  aria-label="Analysing repository…"  // overrides the per-state default
/>
```

All other `<canvas>` props (`className`, `style`, `data-*`, …) pass through.

## Accessibility & performance

- `role="img"` with a sensible per-state `aria-label` out of the box.
- `prefers-reduced-motion: reduce` renders a static representative frame — no animation — and still follows the live theme.
- Every instance pauses automatically when scrolled offscreen (`IntersectionObserver`) or when the tab is hidden, and resumes in phase — all instances share one clock.
- Plain 2D canvas arcs only: no `ctx.filter`, no SVG filters, no WebGL — the same pixels everywhere, cheap on low-end devices. Device-pixel-ratio capped at 2.

## 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.


```ts
ThinkingOrb({
  state = 'working',
  size = 64,
  theme = 'auto',
  speed = 1,
  paused = false,
  color,
  dots = 1,
  dotSize = 1,
  opts: optsOverride,
  frame: customFrame,
  gravity,
  style,
  'aria-label': ariaLabel,
  ...rest
}: ThinkingOrbProps)
```



```ts
export type OrbState =
  | 'working'
  | 'searching'
  | 'solving'
  | 'listening'
  | 'connecting'
  | 'weaving'
  | 'composing'
  | 'breathing'
  | 'shaping';

export type OrbSize = 64 | 32 | 20;

export type OrbTheme = 'auto' | 'dark' | 'light';

export interface ThinkingOrbProps extends Omit<CanvasHTMLAttributes<HTMLCanvasElement>, 'style'> {
  /** Which animation to show. @default 'working' */
  state?: OrbState;

  /** Tuned size preset — 64 or 20 CSS px. @default 64 */
  size?: OrbSize;

  /** Theme mode; `auto` detects from the host project. @default 'auto' */
  theme?: OrbTheme;

  /**
   * Animation speed multiplier on top of the preset's baked speed.
   * @default 1
   */
  speed?: number;

  /** Freeze the animation on the current frame. @default false */
  paused?: boolean;

  /**
   * Optional ink tint — any `#rgb`, `#rrggbb` or `rgb()` color. The orb's
   * depth-shading ramp is preserved on the tint (fading toward black on
   * dark substrates, toward white on light ones), so colored orbs read
   * with the same 3D language as the grayscale default. Omit for the
   * stock grayscale ink.
   */
  color?: string;

  /**
   * Density multiplier for the mode's dot/strand/node counts, applied with
   * the same paired-count scaler the size presets use so the mode keeps
   * its balance. `1` (default) is the tuned look; `0.5` halves density,
   * `2` doubles it. Clamped to a 0.1 floor.
   */
  dots?: number;

  /**
   * Radius multiplier for every dot, applied with the same scaler the size
   * presets use so near/far falloff keeps its proportion. `1` (default) is
   * the tuned mark; `0.7` reads finer, `1.5` bolder.
   */
  dotSize?: number;

  /**
   * Advanced: raw draw options merged over the resolved preset, last. These
   * are the engine's own knobs, so they reach past the tuned surface — the
   * orbit paths' `ghostA` and `particles` (working), the globe's `scanMul`
   * and `dimBase` (searching), the constellation's `thr`, `signals`, `lineW`
   * and `spread` (connecting), the plait's `turns` (weaving), the sash's
   * `wobMul`, `bandMul` and `spin` (composing, breathing), and the outline's
   * `spread` and `shape` (shaping — `shape` 0 / 1 / 2 holds the circle,
   * triangle or square instead of cycling). Unknown keys are ignored; a key
   * the current state does not read does nothing.
   */
  opts?: ModeOpts;

  /**
   * Escape hatch below `opts`: replace the state's geometry outright. The
   * function gets `(size, t, opts)` and returns the frame to paint — the
   * same contract every built-in mode implements (see `MODE_FRAMES` and the
   * helpers exported alongside it). The painter, theme, tint, pause and
   * offscreen handling all stay the library's.
   */
  frame?: ModeFrame;

  /**
   * Gravity: the orb pulls at the pointer. As the pointer nears, a raster
   * of the platform's cursor is drawn in its place with its body warped
   * toward the orb — the tip stays put, nothing rotates or scales. Needs the
   * platform's real pointer raster (`gravity.sprite`, or
   * `setGravitySprite`) or it stays off; off automatically under reduced
   * motion, forced colours, coarse pointers, zoom, and over anything but
   * the plain arrow. `true` takes the defaults. See gravity.ts.
   */
  gravity?: boolean | GravityOptions;

  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.


```ts
// ThinkingOrb
state = 'working'

// ThinkingOrb
size = 64

// ThinkingOrb
theme = 'auto'

// ThinkingOrb
speed = 1

// ThinkingOrb
paused = false

// ThinkingOrb
dots = 1

// ThinkingOrb
dotSize = 1
```


### 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.


```ts
Omit<CanvasHTMLAttributes<HTMLCanvasElement>, 'style'>
CanvasHTMLAttributes<HTMLCanvasElement>
HTMLCanvasElement
ModeOpts
ModeFrame
GravityOptions
CSSProperties
```

---

Index of all JGuang resources: https://jiguang132.com/llms.txt
