bêta
Thinking Orb <mv-thinking-orb>
Orbe d’assistant IA en canvas : une goutte brillante qui se déforme, tourbillonne et change de matière selon son état (repos, écoute, réflexion avec satellites en orbite, parole, succès, erreur), avec des transitions fluides entre les états. Réagit à la voix : niveau manuel, MediaStream ou microphone activé par l’utilisateur.
| Catégorie | Feedback |
|---|---|
| Type | Web Component (<mv-thinking-orb>) |
| Statut | bêta |
| 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/marvelousAgent IA avec le serveur MCP Marvelous UI : install_components({ slugs: ["thinking-orb"], target_dir: "<absolute path>/src/marvelous", framework: "react" }).
Fichiers copiés (dépendances comprises) : 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.
Utilisation
Balisage de référence : partez de celui-ci et personnalisez-le avec les attributs, data-* et les variables CSS :
<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 | Type | 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 | Type | 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.