# The orbs kit — thinking orbs that say what a wait is for

> `Osysharp.LoadingOrbs` draws a small dotted 3D sphere for a wait — nine states (searching, composing, weaving, connecting…) at two sizes — so a loading state says WHAT is happening instead of only that something is. A port of thinking-orbs (MIT, Jakub Antalik) to pure Osy#: themed by your tokens, still under reduced motion, idle when out of view, and announced by name.

<!-- id: ui-orbs-kit · area: ui · stability: preview · html: https://osysharp.com/reference/ui/orbs-kit/ -->

## Summary        {#summary}
A spinner says one thing: *wait*. An orb says what for. `Orb(OrbState.Searching)` is a dotted globe with a scan
line sweeping it; `Orb(OrbState.Composing)` is a sash of dots rolling like a line being written; `Orb(OrbState.Weaving)`
is three strands plaiting — each a hand-tuned animation from Jakub Antalik's
[thinking-orbs](https://github.com/Jakubantalik/thinking-orbs) (MIT), ported to Osy# so it is an ordinary kit:
one `use` line, no JavaScript bundle.

```osy syntax
app Desk {
  use Osysharp.LoadingOrbs@0;
  model "model/**/*.osy";
}
```

## Signature      {#signature}
```osy syntax
using Osysharp.LoadingOrbs;

Orb(OrbState.Searching)                                   // 64px — beside a name, in a panel
Orb(OrbState.Composing, size: OrbSize.Inline)             // 20px — in a line of text, a button, a field
Orb(OrbState.Weaving, label: "Translating from Swedish…") // what a screen reader (and a test) hears
Orb(OrbState.Working, speed: 1.5)                         // a multiplier on the tuned speed
Orb(OrbState.Connecting, paused: true)                    // hold still on the current frame
Orb(OrbState.Shaping, accent: true)                       // drawn in the theme's accent instead of its ink
```

## Description    {#description}

### The nine states — pick the one that names the wait   {#states}
| state | what it draws | label | a wait it names |
|---|---|---|---|
| `Working` | particles on tilted orbits | Working… | an automation or a process running |
| `Searching` | a scan meridian sweeps a dotted globe | Searching… | a search, similar items, a knowledge base |
| `Solving` | bands scramble in quarter turns, then click back | Solving… | a rule or a check being evaluated |
| `Listening` | a waveform rolls through latitude rings | Listening… | voice |
| `Connecting` | a constellation wires itself | Connecting… | a mailbox, a channel, another service |
| `Weaving` | three strands plait around the sphere | Weaving… | translating |
| `Composing` | an undulating multi-band sash | Composing… | writing a draft |
| `Breathing` | a face-on ring slowly morphing | Thinking… | idle, ready |
| `Shaping` | a dotted outline, circle → triangle → square | Shaping… | building or formatting something |

### Two sizes, two designs   {#sizes}
`OrbSize.Avatar` is 64px and `OrbSize.Inline` is 20px. They are separate tunings, not one drawing scaled: the
small one has fewer, larger dots and runs faster, so it still reads at text size.

### Which colour is it?   {#colour}
The theme's ink — `Colors.OnSurface` — so a re-themed app's orb is drawn in that app's text colour, light or dark.
`accent: true` draws it in the theme's accent (`Colors.Primary`) instead, for an app whose one accent means
"something is working". It takes no colour of its own: an orb in a third colour is a second accent.

### When to show one   {#when}
For a wait the reader can see the reason of, and that lasts longer than about 400ms. Under that, show nothing — a
spinner that flashes for a fifth of a second is noise. For content arriving in a known shape, a skeleton says more
([skeleton](https://osysharp.com/reference/ui/skeleton/)); an orb is for a PROCESS whose result has no shape yet.

### What it does for you   {#behaviour}
- **It is drawn in your theme's ink** — `Colors.OnSurface`, at the depth-mapped strength of the original, so it is
  dark on a light page, light on a dark one, and follows a mode switch on the next frame.
- **Reduced motion** shows the original's representative still frame, redrawn only when the theme changes.
- **Out of view it does no work** — scrolled away or in a hidden tab, it runs no frames ([[ui-canvas#offscreen]]).
- **It is sharp** on a high-density screen ([[ui-canvas#density]]).
- **It has a name** — `role: UiRole.Graphic` with its state's label, so a screen reader announces "Searching…" and a
  test reads it: `Assert.Visible("Searching…")`.

### The same technique, for a drawing of your own   {#technique}
An orb is an ordinary component: a `Canvas`, an `on frame` body, and `Draw.*` in theme colours. The pieces it needs
are in [[ui-canvas#themed]]; the smallest version of the idea — a lamp that breathes, still when the reader asks for
less motion — compiles on its own:

```osy title="a lit lamp that breathes, in the theme's colours" test app=orbs-technique
theme Desk { Colors { Lamp = Modes.Of(light: "#0E9AA9", dark: "#33CAD8"); } }

[Route("/lamp")]
[AllowAnonymous]
component Lamp() {
  double t = 0;
  on frame (double dt) {
    t = Theme.ReducedMotion() ? 0 : t + dt;
    var ring = 0.5 + 0.5 * Math.Sin(t * 2.6);
    Draw.Clear();
    Draw.Alpha(0.3 * (1 - ring));
    Draw.Circle(10, 10, 4 + 5 * ring, Colors.Lamp);
    Draw.Alpha(1);
    Draw.Circle(10, 10, 4, Colors.Lamp);
  }
  render { Canvas(w: 20, h: 20, density: 2, role: UiRole.Graphic, label: "Live"); }
}
```

### Credit   {#credit}
The geometry, the nine tunings and the golden vectors the kit's tests are generated from are Jakub Antalik's, under
the MIT licence; `kits/loading-orbs/LICENSE` carries the notice. The port is checked number for number against the
original's own golden vectors (`kits/loading-orbs/tests/golden.test.osy`).

## See also   {#see-also}
- [Canvas](https://osysharp.com/reference/ui/canvas/) — the drawing surface an orb is made of, and how to draw on a themed page
- [animation — keyframe motion, on entry, on exit, in a loop, or as it scrolls into view](https://osysharp.com/reference/ui/animation/) — declarative motion for ordinary elements, and reduced motion
- [skeleton](https://osysharp.com/reference/ui/skeleton/) — for content arriving in a known shape
- [Designing an app that looks designed — direction, type, colour, composition and motion](https://osysharp.com/reference/ui/design/) — where motion belongs, and where it does not
