# Thinking Orbs > Animated thinking orbs for AI agent UIs: an open-source React component library (plus plain JS and SwiftUI) with a state for each thing an agent does, like thinking, searching and compacting. No dependencies, built to read at 20px. Website: https://thinkingorbs.com ## Installation Install the package: ```bash npm i @yogesharc/thinking-orbs # or: pnpm add @yogesharc/thinking-orbs, yarn add @yogesharc/thinking-orbs, bun add @yogesharc/thinking-orbs ``` Or copy the React source into the project with shadcn, to own and edit it. It lands in `components/`, so import from `@/components/orb`: ```bash npx shadcn@latest add https://thinkingorbs.com/r/orb.json ``` The React orb needs nothing but React; the plain JS one needs nothing at all. For SwiftUI (iOS 17, macOS 14), add the Swift package. In Xcode: File › Add Package Dependencies, paste https://github.com/yogesharc/thinking-orbs, and add `ThinkingOrbs` to the app target. Or in a Package.swift: ```swift // Package.swift .package( url: "https://github.com/yogesharc/thinking-orbs", from: "0.1.2" ), // and in your target's dependencies: .product(name: "ThinkingOrbs", package: "thinking-orbs"), ``` ## Usage ### React ```tsx import { Orb } from "@yogesharc/thinking-orbs"; export function Thinking() { return ( Thinking ); } ``` ### Without React ```js import { mountOrb } from "@yogesharc/thinking-orbs/vanilla"; // Draws into any on the page, in its CSS color. const orb = mountOrb(document.querySelector("svg"), { state: "reasoning", label: "Thinking" }); orb.pause(); // hold it on its frame orb.play(); // carry on orb.destroy(); // remove it ``` ### SwiftUI ```swift import SwiftUI import ThinkingOrbs struct Thinking: View { var body: some View { HStack(spacing: 8) { Orb(state: .reasoning) Text("Thinking") } } } ``` ## Props All optional. `paused` and `className` are React only; `mountOrb` returns `pause()` and `play()` instead, and takes its color from the svg's CSS `color`. | Prop | Type | Default | Description | | --- | --- | --- | --- | | `state` | `OrbState` | `"idle"` | What the agent is doing. | | `variant` | `OrbVariant` | `"default"` | Which look of that state. | | `size` | `number` | `20` | Width and height in px. | | `speed` | `number` | `1` | Speed multiplier. | | `shape` | `OrbShape` | — | Another form, from @yogesharc/thinking-orbs/shapes. | | `render` | `OrbRender` | — | Another way to draw it, from @yogesharc/thinking-orbs/renders. | | `density` | `number` | `1` | Dot count multiplier. | | `dotSize` | `number` | `1` | Dot size multiplier. | | `tilt` | `number` | `20` | Viewing angle from above, in degrees. | | `direction` | `OrbDirection` | — | Where using clicks, or which way its scroll goes. Anywhere without one. | | `paused` | `boolean` | `false` | Freezes the animation. | | `label` | `string` | — | Name for screen readers. | | `className` | `string` | — | Tint it with text-* classes. | The orb draws in the text color (`currentColor`). With reduced motion it holds still. In SwiftUI, `Orb(...)` takes the same options as typed parameters, minus `shape`, `render` and `className`, all optional: `state: OrbState = .idle`, `variant: OrbVariant = .default`, `size: CGFloat = 20`, `speed: Double = 1`, `density: Double = 1`, `dotSize: Double = 1`, `tilt: Double = 20`, `direction: OrbDirection? = nil`, `paused: Bool = false`, `label: String? = nil`. It draws in the foreground style, so `.foregroundStyle(.blue)` tints it, and with Reduce Motion it holds still. Shapes and renders are web-only for now. ## Shapes and renders The core ships one shape and one render. Other shapes and ways of drawing it are opt-in modules, so only what you import lands in the bundle. With shadcn, add them as `https://thinkingorbs.com/r/orb-shapes.json` and `https://thinkingorbs.com/r/orb-renders.json`. ```tsx import { Orb } from "@yogesharc/thinking-orbs"; import { cube } from "@yogesharc/thinking-orbs/shapes"; import { halftone } from "@yogesharc/thinking-orbs/renders"; ``` - `@yogesharc/thinking-orbs/shapes`: `cube`, `octahedron`, `tetrahedron`, `torus`. - `@yogesharc/thinking-orbs/renders`: `dashes`, `squares`, `crosses`, `mesh`, `halftone`, `lines`, `verticalLines`. Not every state suits every shape or render. A custom shape is an `OrbShape`, `{ points(count, look) }` returning [x, y, z] points inside the unit sphere; a custom render is an `OrbRender`, whose `mount` makes SVG elements and returns `dot(i, x, y, r, a, dx, dy)`. Define either outside the component. ## States - `working`: Busy, running a tool. - `default`: A ring of light runs down it. - `gyro`: Wobbles like a spinning top. - `reasoning`: Thinking. - `default`: One spark wanders over it. - `twins`: Two sparks wander at once. - `searching`: Searching the web or files. - `default`: A lens hops between spots. - `lighthouse`: A beam sweeps round, like a lighthouse. - `background`: Background tasks running, like a dev server. - `default`: Fewer, bigger dots. - `spiral`: The dots wound into spiral arms. - `using`: Using a browser or computer, as a person would. - `default`: An arrow drawn in the dots glides about and clicks. With a `direction`, it clicks out on that side, like a back button for `"left"`. - `tap`: A glowing cursor glides about, clicks, and sends a ripple out. - `scroll`: Rolls in flicks that coast to a stop, the way `direction` scrolls a page. Without one, each flick goes a new way. - `type`: Lines of text type out across it, word by word, after a caret. - `zoom`: The face swells toward you and eases back. - `snap`: Stops dead with a flash, like a screenshot, then turns on. - `record`: Pulses dim and bright, like a recording light. - `retrying`: Retrying after an error. - `default`: Spins, then winds back. - `surge`: Each turn launches fast and eases out. - `compacting`: Compacting the context window. - `default`: Packs tight, then springs back past loose. - `squeeze`: Packs while wringing the top against the bottom. - `fuse`: Packs along a burning fuse line, with no bounce. - `waiting`: Waiting for a usage limit to reset. - `default`: A comet spirals round it. - `idle`: Idle, or anything without its own state. It was called `base`, which still works. - `default`: A plain spin. - `blink`: Blinks now and then, its lids closing from top and bottom. ## About - Built by Yogesh: https://yogesharc.com - X: https://x.com/yogesharc - Sponsor: https://www.patreon.com/c/yogesharc - GitHub: https://github.com/yogesharc/thinking-orbs - License: MIT