Orb
tier 3 — a surfaceWhat an agent is doing, drawn: an orbit around a focal body, like the mark, that moves the way the work does. The app writes one span with a name and changes one attribute; the library draws the canvas inside it. Nothing around an orb is the library's — the label beside it, the pill it sits in and the button that stops the work are the app's own markup.
Sedna.UI.js finds every [data-orb] and imports its drawing the first
time one comes within a screen of the viewport, so a page without an orb never downloads it.
Every attribute, size and colour role is in docs/orb.md.
States
data-orb names what the agent is doing, and changing it is the whole API: the drawing
changes with it. waiting, error and done are the three a
reader acts on, and pick their own colour family — warn, danger and go — so they are
not mistaken for work still running.
The name is the app's. The orb draws no words; aria-label is its
text alternative, and role="img" is added for you if it is missing. Name what the
reader would want to hear, not the attribute: “Waiting for your approval”, not
“waiting”.
idlethinkingsearchingworkinglisteningspeakingwaitingerrordone<div class="sedna-row-wrap sedna-gap-3" style="row-gap: var(--space-6)">
<div class="sedna-col sedna-center sedna-gap-1" style="width:120px">
<span class="orb orb--lg" data-orb="idle" role="img" aria-label="Idle"></span>
<code>idle</code>
</div>
<div class="sedna-col sedna-center sedna-gap-1" style="width:120px">
<span class="orb orb--lg" data-orb="thinking" role="img" aria-label="Thinking"></span>
<code>thinking</code>
</div>
<div class="sedna-col sedna-center sedna-gap-1" style="width:120px">
<span class="orb orb--lg" data-orb="searching" role="img" aria-label="Searching"></span>
<code>searching</code>
</div>
<div class="sedna-col sedna-center sedna-gap-1" style="width:120px">
<span class="orb orb--lg" data-orb="working" role="img" aria-label="Working"></span>
<code>working</code>
</div>
<div class="sedna-col sedna-center sedna-gap-1" style="width:120px">
<span class="orb orb--lg" data-orb="listening" role="img" aria-label="Listening"></span>
<code>listening</code>
</div>
<div class="sedna-col sedna-center sedna-gap-1" style="width:120px">
<span class="orb orb--lg" data-orb="speaking" role="img" aria-label="Speaking"></span>
<code>speaking</code>
</div>
<div class="sedna-col sedna-center sedna-gap-1" style="width:120px">
<span class="orb orb--lg" data-orb="waiting" role="img" aria-label="Waiting for you"></span>
<code>waiting</code>
</div>
<div class="sedna-col sedna-center sedna-gap-1" style="width:120px">
<span class="orb orb--lg" data-orb="error" role="img" aria-label="Stopped on an error"></span>
<code>error</code>
</div>
<div class="sedna-col sedna-center sedna-gap-1" style="width:120px">
<span class="orb orb--lg" data-orb="done" role="img" aria-label="Done"></span>
<code>done</code>
</div>
</div>
Activities
What the agent is busy with, where the state alone would say only “working”:
solving, writing, connecting, planning,
shaping, reading, remembering, syncing and
analyzing. The same attribute and the same three drawings by size.
solvingwritingconnectingplanningshapingreadingrememberingsyncinganalyzing<div class="sedna-row-wrap sedna-gap-3" style="row-gap: var(--space-6)">
<div class="sedna-col sedna-center sedna-gap-1" style="width:120px">
<span class="orb orb--lg" data-orb="solving" role="img" aria-label="Solving"></span>
<code>solving</code>
</div>
<div class="sedna-col sedna-center sedna-gap-1" style="width:120px">
<span class="orb orb--lg" data-orb="writing" role="img" aria-label="Writing"></span>
<code>writing</code>
</div>
<div class="sedna-col sedna-center sedna-gap-1" style="width:120px">
<span class="orb orb--lg" data-orb="connecting" role="img" aria-label="Connecting sources"></span>
<code>connecting</code>
</div>
<div class="sedna-col sedna-center sedna-gap-1" style="width:120px">
<span class="orb orb--lg" data-orb="planning" role="img" aria-label="Planning"></span>
<code>planning</code>
</div>
<div class="sedna-col sedna-center sedna-gap-1" style="width:120px">
<span class="orb orb--lg" data-orb="shaping" role="img" aria-label="Shaping"></span>
<code>shaping</code>
</div>
<div class="sedna-col sedna-center sedna-gap-1" style="width:120px">
<span class="orb orb--lg" data-orb="reading" role="img" aria-label="Reading"></span>
<code>reading</code>
</div>
<div class="sedna-col sedna-center sedna-gap-1" style="width:120px">
<span class="orb orb--lg" data-orb="remembering" role="img" aria-label="Remembering"></span>
<code>remembering</code>
</div>
<div class="sedna-col sedna-center sedna-gap-1" style="width:120px">
<span class="orb orb--lg" data-orb="syncing" role="img" aria-label="Syncing"></span>
<code>syncing</code>
</div>
<div class="sedna-col sedna-center sedna-gap-1" style="width:120px">
<span class="orb orb--lg" data-orb="analyzing" role="img" aria-label="Analyzing"></span>
<code>analyzing</code>
</div>
</div>
Sizes
.orb--xs (16px), --sm (20px), the bare .orb (32px),
--md (48px), --lg (64px), --xl (96px) and
--hero (220px); --orb-size sets any other. The same scene is
drawn three ways rather than scaled, like the brand mark: below 28px the orbits are
solid lines, because dots that small read as noise; from 28px they are dots; from 72px finer and
denser.
--xs--sm.orb--md--lg--xl<div class="sedna-row-wrap sedna-gap-3" style="align-items: end">
<div class="sedna-col sedna-center sedna-gap-1"><span class="orb orb--xs" data-orb="thinking" role="img" aria-label="Thinking"></span><code>--xs</code></div>
<div class="sedna-col sedna-center sedna-gap-1"><span class="orb orb--sm" data-orb="thinking" role="img" aria-label="Thinking"></span><code>--sm</code></div>
<div class="sedna-col sedna-center sedna-gap-1"><span class="orb" data-orb="thinking" role="img" aria-label="Thinking"></span><code>.orb</code></div>
<div class="sedna-col sedna-center sedna-gap-1"><span class="orb orb--md" data-orb="thinking" role="img" aria-label="Thinking"></span><code>--md</code></div>
<div class="sedna-col sedna-center sedna-gap-1"><span class="orb orb--lg" data-orb="thinking" role="img" aria-label="Thinking"></span><code>--lg</code></div>
<div class="sedna-col sedna-center sedna-gap-1"><span class="orb orb--xl" data-orb="thinking" role="img" aria-label="Thinking"></span><code>--xl</code></div>
</div>
Where a page waits on the agent
.orb--hero for the one thing on screen while the agent works, a voice session or a
first answer. Pair it with a line in the app's words. An orb starts drawing as it comes within a
screen of the viewport; data-orb-eager starts it at once, for one that is the first
thing the page shows.
<div class="sedna-col sedna-center sedna-gap-2">
<span class="orb orb--hero" data-orb="searching" data-orb-eager role="img" aria-label="Searching the runbook"></span>
<span class="text-muted">Searching the runbook</span>
</div>
Tones
data-orb-tone re-points the three colour roles: brand for the app's own
brand colour, mono for a dense table where colour would compete, and
go, warn and danger for a state the app wants to stress.
Without one, an orb is in the agent colours, --agent-from and
--agent-to. Every colour is read through the element in the browser, so a theme,
the colour-blind palette, contrast and forced colours all reach the canvas.
defaultbrandmonogowarndanger<div class="sedna-row-wrap sedna-gap-3">
<div class="sedna-col sedna-center sedna-gap-1"><span class="orb orb--md" data-orb="working" role="img" aria-label="Working"></span><code>default</code></div>
<div class="sedna-col sedna-center sedna-gap-1"><span class="orb orb--md" data-orb="working" data-orb-tone="brand" role="img" aria-label="Working"></span><code>brand</code></div>
<div class="sedna-col sedna-center sedna-gap-1"><span class="orb orb--md" data-orb="working" data-orb-tone="mono" role="img" aria-label="Working"></span><code>mono</code></div>
<div class="sedna-col sedna-center sedna-gap-1"><span class="orb orb--md" data-orb="working" data-orb-tone="go" role="img" aria-label="Working"></span><code>go</code></div>
<div class="sedna-col sedna-center sedna-gap-1"><span class="orb orb--md" data-orb="working" data-orb-tone="warn" role="img" aria-label="Working"></span><code>warn</code></div>
<div class="sedna-col sedna-center sedna-gap-1"><span class="orb orb--md" data-orb="working" data-orb-tone="danger" role="img" aria-label="Working"></span><code>danger</code></div>
</div>
In a line of text
.orb--inline takes the size of the text around it and sits on its x-height.
Research agent is reading three sources, and will wait for you before it writes anything.
<p class="text-lg" style="margin: 0">
Research agent is <span class="orb orb--inline" data-orb="searching" role="img" aria-label="searching"></span>
reading three sources, and will <span class="orb orb--inline" data-orb="waiting" role="img" aria-label="waiting"></span>
<span>wait for you before it writes anything.</span>
</p>
Following a voice
listening and speaking follow --level, from 0 to 1, read from
the orb or any element above it. It is the same number the app writes for the
voice bars, the mic button, an agent avatar and
Mochi, so one write moves everything that shows the voice. Without one they
move gently on their own.
Motion
An orb draws one still frame the moment it starts, at the point in its state where the drawing says
what it is: the tick drawn, the scan part way across. After that one clock draws every orb on screen
while the tab is visible. Under prefers-reduced-motion the still frame is all there is,
and a change of state draws a new one. With scripting off, the span is a still focal body inside
one orbit — something is there, and it is an agent.