Docs
AI

Thought Orb

A small glass orb with a voice wave whose colour follows the kind of work, and a glass status pill whose verb morphs as it changes.

$npx swiftpieces add ThoughtOrb
Free · MIT + Commons ClauseiOS 17.0+Liquid GlassMetalaiorbshadermetalthinkingstatus
Type
ThoughtOrb
Files
ThoughtOrb.swift, ThoughtOrb.metal
Depends on
Nothing (Apple frameworks only)
Version
1.2.0

The mark next to the verb an agent is doing. Copy ThoughtOrb.metal alongside this file; its thoughtOrbSiriWave kernel compiles into your app's default Metal library.

Notes

  • Requires ThoughtOrb.metal in the same target. The [[ stitchable ]] thoughtOrbSiriWave function is looked up through ShaderLibrary at runtime. Its helpers live in the thoughtOrbSiri namespace, so it can share a target with other orb kernels.
  • The mark has one look: thinking. Four thin sine membranes travel left to right through the equator of a dark glass ball. There are no motion states and no drag; the sphere never scales or pulses, only the wave inside it moves. The wave's clock starts as the mark appears.
  • Colour says what kind of work is happening. Presets: .siri for thinking (blue, pink, orange, red over violet), .searching (electric blue, aqua and mint), .reading (indigo, lavender and a teal glint) and .writing (red, amber, rose and violet). Build your own with ThoughtOrb.Palette(bands:ground:crest:rimCool:rimWarm:). A change crossfades on a calm spring, so steps that change faster than the fade glide from colour to colour instead of stacking.
  • ThoughtOrb.Pill is liquid glass: the mark rides its own round glass bubble, joined by a liquid neck to a glass capsule holding the label and the dots. They are two parts of one control, so they rest a neck's width apart and the neck holds. The shader ball sits in its bubble rather than on glass, so it is never glass on glass.
  • Drive it from the current step: ThoughtOrb.Pill(step.title, palette: step.palette) morphs the label into the new verb letter by letter, the letters both verbs share holding still while the rest blur through, as the capsule's width and the dots at its end reshape around it in the same quick beat, a 0.3s spring with a little give at the end, quick so it stays light in a toolbar. The mark's bubble stays put; only its colour follows on its slower fade, and the motion keeps thinking. ThoughtOrb(size: 64) works at avatar size.
  • Pill derives type, the glass around the mark and the dots from markSize (0.47x label, a bubble 1.4x the mark) and scales the whole thing with Dynamic Type through @ScaledMetric. Every string is semibold. Each dot rises and falls on an eased curve, then rests, in a ripple from left to right that starts from rest as the dots appear. They run on the clock rather than a repeating animation so they stay in phase however long the pill is up; VoiceOver hears the whole label with "Thinking" as its value and skips the dots. On iOS 26 the glass is Liquid Glass; earlier it is a frosted material with a light rim, and Reduce Transparency makes both shapes solid.
  • With an action, the pill is a button: its glass and what it carries sink together a touch while pressed, centered so it is safe in toolbars and scrolling content, and it plays one soft tap when the action fires.
  • Under Reduce Motion the wave rests on the pose it starts from, a fixed frame that holds through label and colour changes, and the light in it breathes instead: the four bands dim by a quarter and come back over 2.4s, then rest at full for 0.8s, redrawn at 30 frames a second. The glass, rim and crest stay lit and still, so even a bare ThoughtOrb(size: 64) reads as thinking with nothing travelling. In the pill the dots keep cycling too, since they only change opacity. The label crossfades instead of morphing, the capsule resizes on a short spring, a palette change is a short fade, and a press shades the pill instead of sinking it (darker in light mode, lighter in dark). Turning Reduce Motion off resumes the wave from its rest pose without a jump.

Usage

VStack(spacing: 24) {
    ThoughtOrb(size: 96)
    ThoughtOrb.Pill()
    ThoughtOrb.Pill("Searching the web", palette: .searching)
    ThoughtOrb.Pill("Reading the thread", palette: .reading, markSize: 20)
    ThoughtOrb.Pill("Drafting a reply", palette: .writing) {}
}
.padding(32)

Parameters

ParameterDescription
sizeDiameter of the ball in points. 18–30 inside a pill, 64 at avatar size.
paletteThe kind of work the colour portrays: .siri (thinking, default), .searching, .reading or .writing, or your own Palette(bands:ground:crest:rimCool:rimWarm:). A change crossfades calmly, and a quick run of changes glides from colour to colour; the motion never changes.

Install

Pick one. Run it from the folder that contains your .xcodeproj and the files land inside your app.

Terminal

$npx swiftpieces add ThoughtOrb

Or ask your coding agent · Claude Code, Cursor or Xcode, once the MCP server is connected

>Add the SwiftPieces "Thought Orb" piece to my app

Or copy the source above into your app.

New to SwiftUI?If you know React, CSS or Tailwind, SwiftUI is easier to pick up than it looks.Try real app patterns first

Building a whole app? See SwiftPieces Pro →

All ai →

Build it yourself: SwiftUI loading states guide · SwiftUI animations guide

On this page

SwiftPiecesPro

Build the whole app with one library.

Production-ready screens, whole flows, complete app templates, a Build Kit your agent follows and Pro remixing.

54 screens · 46 patterns · 48 flows · 12 templates · 31 Build Kit skills

Explore Pro