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égorieFeedback
TypeWeb Component (<mv-thinking-orb>)
Statutbêta
Keywordsai, 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/marvelous

Agent 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

NameTypeDefaultDescription
stateidle | listening | thinking | speaking | success | erroridleDisplayed state; parameters (size, warp, swirl, glow, satellites, hue) are smoothly interpolated.
labelstringAssistantName announced with the state (“Assistant: thinking”).
colorslist of CSS colors--mv-thinking-orb-1/2/3Three material colors (tokens accepted, follow the theme).
levelnumber 0-1Manual voice level (listening / speaking). With no level or mic, “speaking” simulates a voice.
micbooleanThe orb becomes a toggle button that opens the microphone on click (getUserMedia) and switches to listening.
speednumber1Overall animation speed.

Properties

NameTypeDescription
levelnumber | nullVoice level 0-1 (update every frame if needed, without an attribute).
streamMediaStream | nullExternal audio stream to visualize (not stopped by the orb).
listeningMicbooleanTrue while the orb’s microphone is open.

Methods

NameDescription
listenMic()Opens the microphone (call it from a user gesture); returns a Promise<MediaStream>.
stopMic()Stops the orb’s microphone.

Events

NameDescription
mv-micdetail: { active, stream?, error? }; microphone opened, closed or denied.

CSS variables

NameDefaultDescription
--mv-thinking-orb-size10remSize (the glow and satellites fit inside the box).
--mv-thinking-orb-1 / -2 / -3accent, sky blue, pinkDefault 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.

Cette page a été traduite par IA. Signaler un problème de traduction