thinking-orbs: dotted canvas loading states for AI and agent interfaces
Dotted thought-orb loading indicators for AI & agent UIs, 9 tuned types, two sizes, auto dark/light
At a glance
- What is it?
- A React component that ships nine animated thought-orb states on plain 2D canvas, with two tuned sizes and automatic dark/light resolution. It is a UI ornament, not a status system, and the README is explicit about what it does not do.
- Who is it for?
- Adopt thinking-orbs if you are building a React chat or agent surface and want a distinct animated state per verb without pulling in WebGL or SVG filters; the auto theme resolution and the offscreen pause behaviour are the parts that save you real work. Skip it if you need a framework-agnostic loader, a determinate progress indicator, or anything you can style with CSS, because the component is React-only, strictly monochrome, and paints to a canvas you cannot restyle.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 46 days ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 1, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The gap thinking-orbs fills between a spinner and a status label
Most loading indicators answer one question: is something happening. An agent interface has to answer a harder one: what is happening. A rotating ring next to the words "Searching the web" is the common answer, and it wastes the label. thinking-orbs takes the opposite approach. The animation itself carries the verb. The README lists nine states, and each one is a separate animation rather than a variation on a theme: working shows particles on tilted orbits, searching sweeps a scan meridian across a dotted globe, solving scrambles bands and then clicks them back into a solved arrangement, listening rolls a waveform through the rings, connecting wires a constellation together, weaving plaits three strands around the sphere, composing draws an undulating multi-band sash, breathing slowly morphs a ring, and shaping walks a dotted outline from circle to triangle to square.
The intended audience is narrow and specific. This is for React developers building chat surfaces, agent dashboards and assistant panels where the model's current activity is worth showing. The package declares react >=18.0.0 as a peer dependency, so it assumes a React host. It is not a general-purpose spinner library, and the README never presents it as one. If your interface has exactly one loading state, the nine-state vocabulary is overhead you will not use, and a CSS animation will cost less.
How the nine states render: one shared clock, a 2D canvas, no filters
The rendering choice is the most consequential design decision in the project, and the README states it plainly: plain 2D canvas arcs only, no ctx.filter, no SVG filters, no WebGL, with the same pixels in Chrome, Safari and Firefox. That rules out the effects that usually make this kind of orb expensive, and it is why the README can claim the component is cheap on low-end devices. Device-pixel-ratio is capped at 2, so a retina display does not quadruple the fill cost.
The animation model is shared rather than per-instance. Every instance pauses automatically when it scrolls offscreen via IntersectionObserver or when the tab is hidden, and resumes in phase, because all instances share one clock. That detail matters more than it looks. A chat transcript with a dozen orb instances would otherwise run a dozen independent animation loops; a shared clock means they stay synchronized and a hidden tab stops costing anything. The size prop is not a scale factor. The README describes 64 and 20 as separate designs, each with its own dot count, dot size and speed tuning, which is why a 20px orb does not look like a shrunken 64px orb.
The speed prop is a multiplier on the preset's baked speed, and paused freezes on the current frame. Accessibility defaults are included rather than opt-in: role="img" with a per-state aria-label, and prefers-reduced-motion: reduce renders a static representative frame that still follows the live theme. The package also exposes a ./engine subpath in its exports map alongside the main entry, so the animation engine is importable separately from the React component, though the README does not document that subpath's API.
Installing thinking-orbs and rendering a first state
The package installs from npm. The README gives this exact command, and package.json confirms the published name.
npm install thinking-orbsThe quick start is a single component with a state and a size. Copying the README's example verbatim gives you a 64px orb in the searching animation, which is the chat-avatar scale.
import { ThinkingOrb } from 'thinking-orbs';
function Status() {
return <ThinkingOrb state="searching" size={64} />;
}What you should see is a dotted globe with a scan meridian sweeping across it. Nothing else is required: theme defaults to auto, the aria-label defaults per state, and the component paints only on the client after the theme has resolved, which is what makes it SSR-safe.
The second thing to try is the inline size, because it is a different design rather than a scaled one. Swapping size to 20 gives you the text-scale preset with its own dot count and tuning.
<ThinkingOrb state="working" size={20} />If you need to override the accessible name, pass aria-label, and if you want to slow an animation down, speed is a multiplier on the preset's baked speed. All other canvas props such as className, style and data-* attributes pass through to the underlying element.
Theme resolution has three layers, and the first one is the one that bites
The theme prop accepts auto, dark or light, and auto is the default. Under auto, the README describes three resolution layers that update live when any of them change. The first is an ancestor data-theme="dark|light" attribute or a dark/light class, described as the Tailwind and shadcn convention, watched with a MutationObserver. The second is prefers-color-scheme, subscribed so OS theme switches are picked up. The third is SSR safety: the canvas paints only on the client, after the theme has resolved.
The ordering is sensible, but the first layer is where integrations break. A MutationObserver watches attributes and classes on ancestors. If your application stores its theme in React context or a Zustand store and applies it through a CSS variable, a style attribute on the html element, or a media query written by hand, the observer has nothing to watch. The orb will fall through to prefers-color-scheme and disagree with the rest of your interface. The README does not describe a callback, a context provider or an imperative setter for forcing resolution, so the escape hatch is to pin theme explicitly and manage the switch yourself.
The strict monochrome constraint is the other thing to internalize. Light ink for dark backgrounds, dark ink for light backgrounds, and no color prop. If your design system expects a brand-tinted loader, this component will not produce one, and the README does not suggest it will.
Where thinking-orbs is the wrong choice
The component is React-only. React 18 or newer is a peer dependency, and the README's examples are all TSX. There is no documented vanilla entry point, no web component, no Vue or Svelte binding, and no imperative mount function in the README. A team on another framework would be importing React to draw a canvas, which is the wrong trade.
The second limitation is that the orb is indeterminate by construction. Nine states express what an agent is doing, not how far along it is. There is no progress prop, no completion percentage, and no way to map an animation to a known duration. For file uploads, multi-step wizards or any task with a measurable end, this is decorative where a progress bar is informative.
The third is that everything is painted to canvas. You cannot restyle the dots with CSS, you cannot select them, and you cannot animate them with a stylesheet. The README does not document a color, dot-size or dot-count prop beyond the two size presets, so customization means editing the engine source or importing the ./engine subpath, whose API the README leaves undocumented. If your design review process expects tokens to control the loader, this will fight that process.
How thinking-orbs differs from a CSS spinner or an SVG loader
The realistic alternative is not another orb library; it is the loader you would otherwise write yourself. A CSS keyframe spinner on a border or a conic gradient is a few lines, needs no dependency, is styleable with tokens, and works in any framework. It also renders exactly one idea: rotation. An inline SVG loader can do more shapes and can be colored with currentColor, but SVG filters are the usual way to get organic motion, and the README explicitly rules filters out of this project's approach.
The difference in method is what separates them. A CSS or SVG loader is a markup element your stylesheet controls. thinking-orbs is a canvas program with a fixed vocabulary of nine animations, a shared clock, an IntersectionObserver that pauses offscreen instances, and automatic theme resolution. You are trading control over appearance for animations that would be tedious to author by hand and for lifecycle behavior you would otherwise write yourself. If you need three of the nine states and a specific brand color, the hand-written loader wins. If you need an agent surface where each verb reads differently at both avatar and inline scale, the canvas approach is doing work a spinner cannot.
Maintenance, licence and what a version bump can cost you
The repository is not archived, and the last push was on 2026-08-16, which is recent enough that the project is being touched. The package version in package.json is 0.3.1, and the pre-1.0 numbering is worth reading literally: the README documents the component props, but it does not document a stability guarantee, and no release notes appear in the repository listing to check what changed between versions. The published tarball contains only the dist directory, so you are consuming built output rather than source, and the exports map defines the main entry plus ./engine.
The licence is MIT, copyright Jakub Antalik, and the LICENSE file sits at the repository root. MIT permits commercial use and modification with the copyright notice retained; it also means there is no warranty, which for a decorative UI component is the usual and reasonable arrangement. That is a description of the licence text, not legal advice.
On upgrade cost, the practical risk is the animation vocabulary itself. Nine named states are part of the public API surface, and a state that changes its animation between versions changes what your interface communicates without any code change on your side. The README does not describe a deprecation policy or a changelog, so pinning an exact version and reading the diff before bumping is the cheaper habit. The repository also carries a spec directory and a spec script that extracts spec and golden files, which suggests the animations are treated as testable fixtures, though the README does not explain how to run or interpret them.
Editorial conclusion
Adopt thinking-orbs if you are building a React chat or agent surface and want a distinct animated state per verb without pulling in WebGL or SVG filters; the auto theme resolution and the offscreen pause behaviour are the parts that save you real work. Skip it if you need a framework-agnostic loader, a determinate progress indicator, or anything you can style with CSS, because the component is React-only, strictly monochrome, and paints to a canvas you cannot restyle. Before committing, verify three things in your own app: that your theme signal is an ancestor data-theme attribute or dark/light class rather than a context value the MutationObserver cannot see, that your bundler resolves the exports map for both the main entry and the ./engine subpath, and that your SSR path does not expect the canvas to paint on the server.
Frequently asked questions
What does it mean when an orb visits you?
Nothing in this project. thinking-orbs is a React package of dotted loading animations for AI and agent interfaces, and the README describes nine animated states rather than anything spiritual.
What do spiritual orbs look like?
The README does not cover spiritual orbs. It describes dotted thought-orb indicators rendered on a plain 2D canvas, strictly monochrome, with a per-state aria-label and a static frame under prefers-reduced-motion: reduce.
How much is an orb worth?
The package is published under the MIT licence, so there is no price attached to using it. The README gives npm install thinking-orbs as the install step and does not mention paid tiers.
What is a pondering orb?
The README does not use that phrase. It ships nine states named working, searching, solving, listening, connecting, weaving, composing, breathing and shaping, and a thinking orb in this context is the loading indicator drawn for one of them.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/jakubantalik-thinking-orbs)