Beta
Thinking Orb <mv-thinking-orb>
Canvas-Orb für KI-Assistenten: ein glänzender Blob, der sich verformt, wirbelt und je nach Zustand sein Material wechselt (idle, listening, thinking mit kreisenden Satelliten, speaking, success, error), mit fließenden Übergängen zwischen den Zuständen. Reagiert auf Stimme: manueller Pegel, MediaStream oder ein vom Nutzer aktiviertes Mikrofon.
| Kategorie | Feedback |
|---|---|
| Typ | Web Component (<mv-thinking-orb>) |
| Status | Beta |
| Keywords | ai, assistant, orb, voice, microphone, audio, loader, agent, canvas, status |
When to use
- A voice or AI assistant needs a visual presence that reflects idle, listening, thinking and speaking states
- The assistant should react to microphone input or an audio stream in real time
- A single orb doubles as a mic toggle button for a voice interface
Avoid when
- A lightweight inline thinking indicator is enough, such as in a chat message → use Pixel Loader instead
- Several instances appear on one page or the target is low-end mobile; each orb runs its own canvas
- A generic loading state with no assistant persona is needed → use Spinner instead
Installation
node scripts/add.mjs thinking-orb --out ./src/marvelousKI-Agent mit dem MCP-Server von Marvelous UI: install_components({ slugs: ["thinking-orb"], target_dir: "<absolute path>/src/marvelous", framework: "react" }).
Kopierte Dateien (inklusive Abhängigkeiten): tokens/tokens.css, core/base.css, core/canvas.js, core/dom.js, core/element.js, core/motion.js, components/thinking-orb/thinking-orb.js, components/thinking-orb/thinking-orb.css.
Verwendung
Referenz-Markup zum Starten und Anpassen mit Attributen, data-* und CSS-Variablen:
<div style="display:grid;justify-items:center;gap:1.1rem;width:100%;max-width:560px">
<mv-thinking-orb id="mv-thinking-orb-demo" state="idle" label="Assistant" mic style="--mv-thinking-orb-size:12rem"></mv-thinking-orb>
<p id="mv-thinking-orb-demo-caption" style="margin:0;min-height:1.4em;font-size:.9rem;color:var(--mv-fg-muted)">Tap the orb to talk, or pick a state.</p>
<div role="group" aria-label="Assistant state" style="display:flex;flex-wrap:wrap;justify-content:center;gap:.4rem">
<button class="mv-button" data-size="sm" data-variant="outline" data-state="idle" aria-pressed="true">Idle</button>
<button class="mv-button" data-size="sm" data-variant="outline" data-state="listening" aria-pressed="false">Listening</button>
<button class="mv-button" data-size="sm" data-variant="outline" data-state="thinking" aria-pressed="false">Thinking</button>
<button class="mv-button" data-size="sm" data-variant="outline" data-state="speaking" aria-pressed="false">Speaking</button>
<button class="mv-button" data-size="sm" data-variant="outline" data-state="success" aria-pressed="false">Success</button>
<button class="mv-button" data-size="sm" data-variant="outline" data-state="error" aria-pressed="false">Error</button>
</div>
<div style="display:flex;gap:1.5rem;align-items:center;margin-top:.4rem">
<mv-thinking-orb state="thinking" label="Search" style="--mv-thinking-orb-size:3.5rem"></mv-thinking-orb>
<mv-thinking-orb state="speaking" label="Reading" colors="oklch(0.78 0.16 160), oklch(0.72 0.14 200), oklch(0.85 0.12 110)" style="--mv-thinking-orb-size:3.5rem"></mv-thinking-orb>
<mv-thinking-orb state="listening" label="Dictation" colors="oklch(0.72 0.19 30), oklch(0.8 0.15 70), oklch(0.66 0.2 350)" style="--mv-thinking-orb-size:3.5rem"></mv-thinking-orb>
</div>
</div>
<style>
[aria-label="Assistant state"] .mv-button[aria-pressed="true"] { background: var(--mv-accent-subtle); border-color: var(--mv-accent); color: var(--mv-accent-fg); }
</style>
<script type="module">
const orb = document.getElementById("mv-thinking-orb-demo");
const caption = document.getElementById("mv-thinking-orb-demo-caption");
const texts = {
idle: "Tap the orb to talk, or pick a state.",
listening: "I’m listening…",
thinking: "Looking up flights to Lisbon in October…",
speaking: "Three nonstop flights on Oct 12, from $89.",
success: "Booking confirmed.",
error: "Couldn’t reach the server. Try again.",
};
const buttons = [...document.querySelectorAll("[data-state]")].filter((b) => b.closest("[role=group]"));
const sync = () => {
for (const b of buttons) b.setAttribute("aria-pressed", String(b.dataset.state === orb.state));
caption.textContent = texts[orb.state] ?? "";
};
for (const b of buttons) b.addEventListener("click", () => { orb.state = b.dataset.state; sync(); });
orb.addEventListener("mv-mic", (e) => {
if (e.detail.error) caption.textContent = "Microphone unavailable (" + e.detail.error + ").";
else sync();
});
</script>API
Attributes
| Name | Typ | Default | Description |
|---|---|---|---|
state | idle | listening | thinking | speaking | success | error | idle | Displayed state; parameters (size, warp, swirl, glow, satellites, hue) are smoothly interpolated. |
label | string | Assistant | Name announced with the state (“Assistant: thinking”). |
colors | list of CSS colors | --mv-thinking-orb-1/2/3 | Three material colors (tokens accepted, follow the theme). |
level | number 0-1 | Manual voice level (listening / speaking). With no level or mic, “speaking” simulates a voice. | |
mic | boolean | The orb becomes a toggle button that opens the microphone on click (getUserMedia) and switches to listening. | |
speed | number | 1 | Overall animation speed. |
Properties
| Name | Typ | Description |
|---|---|---|
level | number | null | Voice level 0-1 (update every frame if needed, without an attribute). |
stream | MediaStream | null | External audio stream to visualize (not stopped by the orb). |
listeningMic | boolean | True while the orb’s microphone is open. |
Methods
| Name | Description |
|---|---|
listenMic() | Opens the microphone (call it from a user gesture); returns a Promise<MediaStream>. |
stopMic() | Stops the orb’s microphone. |
Events
| Name | Description |
|---|---|
mv-mic | detail: { active, stream?, error? }; microphone opened, closed or denied. |
CSS variables
| Name | Default | Description |
|---|---|---|
--mv-thinking-orb-size | 10rem | Size (the glow and satellites fit inside the box). |
--mv-thinking-orb-1 / -2 / -3 | accent, sky blue, pink | Default material colors. |
Accessibility
Decorative canvas (aria-hidden); the state is exposed as visually hidden text in a polite live region (“Assistant: listening”). With mic: toggle button with a constant name and aria-pressed, visible focus. The microphone is never opened without a user gesture. Reduced motion: a representative still frame for each state. Pauses when off-screen.