thinking-orbs について
thinking-orbsは、アニメーションするモノクロのドットで不確定なAIの活動状況を示すReactコンポーネントパッケージです。6種類の状態と2つの固定サイズを備え、テーマや表示状態、視差効果の低減にも対応します。
主な機能
- 01AIの作業に対応する6種類の状態
- 022種類の固定キャンバスサイズ
- 03テーマと表示状態の自動処理
- 04視差効果の低減時に静止画を表示
- 05キャンバス描画用の低レベルAPI
活用シーン
- 01React画面で検索や推論の状態を表示
- 02AI生成の応答にステータスを添える
- 03視差効果を抑えた活動フィードバックの提供
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ mengto/ skills --skill thinking-orbsインストール後、Claude Code で/thinking-orbsを入力して読み込まれたか確認します。
同梱ファイルagents/openai.yamlREFERENCES.md
詳細
Thinking Orbs
基本契約
- 不定の AI アクティビティを示すフィードバックが必要な React 18 以降のインターフェースでは、
thinking-orbsを使用してください。 - 実際のプロダクトのライフサイクルを、用意されている 6 つの状態のいずれかに対応付けてください。
- 調整済みの
20ピクセルまたは64ピクセルのサイズのみを使用してください。一方のプリセットを引き伸ばして、もう一方のサイズにしないでください。 - 周囲の表示領域に既知の固定テーマがない限り、
theme="auto"を使用してください。 - アクティビティがユーザーにとって重要な場合は、オーブに簡潔な表示ステータステキストを添えてください。
- タスク固有のラベルで
aria-labelを上書きするか、隣接するライブテキストが同じ状態をすでに通知している場合は、支援技術からオーブを隠してください。 - 現在のフレームを固定するには
pausedを使用してください。speed={0}で一時停止を再現しないでください。 - オーブは不定のフィードバックとして扱い、進捗率や完了通知として使用しないでください。
パッケージは、透明な 2D キャンバスに単色のドットを描画します。カスタムカラー、任意のサイズ、確定的な進捗には対応していません。
インストール
プロジェクトのパッケージマネージャーを確認してから、インストールします。
npm install thinking-orbs
このパッケージでは、ピア依存関係としてバージョン 18 以降の react と react-dom を宣言しています。コンポーネントとエクスポートされた型は、パッケージのルートからインポートしてください。
import {
ThinkingOrb,
type OrbSize,
type OrbState,
type OrbTheme,
type ThinkingOrbProps,
} from "thinking-orbs";
状態を選ぶ
working— 一般的なツールの実行、複数ステップの作業、またはより適切な状態がないアクティビティ。searching— 情報の取得、ウェブ検索、ファイル検索、またはナレッジの検索。solving— 推論、分析、計算、または計画。listening— マイク入力、音声の取り込み、または発話ターンの待機。composing— テキストの回答の執筆、要約、下書き作成、または生成。shaping— 画像、レイアウト、構造化された成果物、またはその他の形式のある出力の作成や改良。
見た目の面白さを優先した不正確な状態ではなく、実態に即した一般的な working 状態を選んでください。基盤となるアクティビティが変化したときのみ、状態を変更してください。
サイズを選ぶ
- テキスト内、ボタン内、またはコンパクトなステータス行では、
size={20}を使用してください。 - チャットのアバター程度の大きさ、空の状態、またはメインの視覚的ステータスには、
size={64}を使用してください。
プリセットごとにドットの数、サイズ、速度の調整が異なります。これらは単なる拡大縮小ではなく、別々のデザインです。周囲により広いスペースが必要な場合は、キャンバスに CSS 変換を適用するのではなく、ラッパーのサイズを調整してください。
基本的な使い方
import { ThinkingOrb } from "thinking-orbs";
export function AgentStatus() {
return (
<ThinkingOrb
state="searching"
size={20}
theme="auto"
aria-label="Searching project files…"
/>
);
}
className、style、data-*、イベントハンドラー、ARIA 属性など、その他すべてのキャンバスプロパティはそのまま渡されます。
プロダクトのライフサイクルをモデル化する
対応付けを明示できるよう、プロダクトのフェーズと視覚的な状態は分けてください。
import { ThinkingOrb, type OrbState } from "thinking-orbs";
type AgentPhase =
| "idle"
| "retrieving"
| "reasoning"
| "writing"
| "creating"
| "done"
| "error";
const ORB_BY_PHASE: Partial<Record<AgentPhase, OrbState>> = {
retrieving: "searching",
reasoning: "solving",
writing: "composing",
creating: "shaping",
};
export function AgentActivity({ phase }: { phase: AgentPhase }) {
const state = ORB_BY_PHASE[phase];
if (!state) return null;
return <ThinkingOrb state={state} size={20} />;
}
done、error、キャンセル、またはアイドル状態ではオーブを取り除いてください。最後のアクティビティのアニメーションを動かしたままにせず、適切な結果、再試行、またはエラーの UI を表示してください。
ステータスの通知は一度だけにする
コンポーネントのデフォルトは role="img" で、状態ごとの「Searching…」のようなラベルが設定されています。表示されるテキストが同じ状態を説明している場合は、そのテキストを唯一の通知元にしてください。
export function LiveAgentStatus() {
return (
<div role="status" aria-live="polite" className="agent-status">
<ThinkingOrb state="solving" size={20} aria-hidden="true" />
<span>Reviewing the repository…</span>
</div>
);
}
通常のフェーズ変更には aria-live="polite" を使用してください。ラベルが頻繁に変わらないようにしてください。role="status" がすでに通知を担っている場合は、別の非表示ライブリージョンを追加しないでください。
テーマ
次のいずれかを使用してください。
<ThinkingOrb theme="auto" />
<ThinkingOrb theme="dark" />
<ThinkingOrb theme="light" />
autoは、まず祖先要素のdata-theme="dark|light"属性、またはdark/lightクラスを確認します。- 祖先要素にテーマがない場合、
autoはprefers-color-schemeに従います。 - テーマの変更は即座に反映されます。
darkは、暗い背景向けの明るいドットを意味します。lightは、明るい背景向けの暗いドットを意味します。
キャンバスは透明です。ページのルート要素だけでなく、実際の表示領域でコントラストを確認してください。
速度と一時停止
<ThinkingOrb state="working" speed={0.85} />
<ThinkingOrb state="composing" paused={isWaitingForApproval} />
speed は、選択した状態とサイズに設定済みの速度に乗算します。まずは 1 から始め、プロダクトに合わせた微調整にはおおむね 0.75–1.25 を使用してください。極端な値にすると、細かく調整された動きが慌ただしくなったり、停止したように感じられたりすることがあります。
paused は、視覚的なステータスを維持しながら現在のフレームを固定します。アクティビティが実際に終了したら、コンポーネントを取り除いてください。
Next.js とクライアントレンダリング
このコンポーネントは、React エフェクト、canvas、requestAnimationFrame、メディアクエリ、オブザーバーを使用します。Next.js App Router では、インポートをクライアント境界の内側に配置してください。
"use client";
import { ThinkingOrb } from "thinking-orbs";
export function ThinkingStatus() {
return <ThinkingOrb state="working" size={20} />;
}
このライブラリは、テーマの解決後にクライアント側でのみ描画するため、SSR に安全です。ただし、フレームワークがサーバーコンポーネントとクライアントコンポーネントの分離を強制する箇所では、クライアント境界が引き続き必要です。
組み込みのランタイム動作
- WebGL や SVG フィルターを使わず、標準の Canvas 2D の弧を使って描画します。
- デバイスのピクセル比を
2に制限します。 - 表示中の各インスタンスにつき、
requestAnimationFrameループを 1 つ使用します。 - 複数のオーブの動きを同期させるため、共有の
performance.now()クロックを使用します。 - canvas が画面外にスクロールすると、
IntersectionObserverによって一時停止します。 - ブラウザーのタブが非表示になると、一時停止します。
prefers-reduced-motion: reduceの設定時には、決定的な静止フレームを 1 つ描画します。- 動きを抑える設定時も、テーマの変更をリアルタイムで反映し続けます。
ラッパーでこれらの動作を再実装しないでください。コンポーネントの周囲にはプロダクトの状態管理とレイアウトを追加し、別のアニメーションループは追加しないでください。
パワーユーザー向け Canvas API
プロダクト UI では <ThinkingOrb> を使用してください。このパッケージは、React の外でカスタム canvas を使うために、解決済みのプリセットと生のフレーム描画関数もエクスポートしています。
import { MODE_DRAWS, resolvePreset } from "thinking-orbs";
const { mode, speed, opts } = resolvePreset("searching", 64);
const drawFrame = MODE_DRAWS[mode];
drawFrame(
context,
64,
(performance.now() / 1000) * speed,
true, // true draws light ink for a dark surface
opts,
);
STATE_TO_MODE は内部マッピングを公開します。
working→orbitssearching→globesolving→rubiklistening→wavecomposing→ribbonshaping→morph
生の API は、別のレンダラーが canvas のライフサイクルを管理する場合にのみ使用してください。提供するのはフレーム描画関数であり、コンポーネントの動作ではありません。<ThinkingOrb> を使用しない場合は、DPR のサイズ設定、クリア、アニメーションのスケジューリング、一時停止、テーマの解決、動きを抑える設定、可視性の処理、クリーンアップ、アクセシビリティを再実装してください。
検証
プロジェクトの型チェック、テスト、本番ビルド、git diff --check を実行してください。その後、実際のブラウザーで次の項目を検証してください。
- プロダクトの各フェーズを発生させ、マッピングされたオーブの状態が正確であることを確認します。
20ピクセルと64ピクセルのインスタンスが、CSS による拡大縮小なしで鮮明に表示されることを確認します。- ダーク、ライト、テーマのリアルタイム切り替えをテストします。
- 動きを抑える設定をテストし、オーブが代表的な静止フレームになることを確認します。
- オーブを画面外にスクロールしてから戻し、表示に目立った乱れなく再開することを確認します。
- タブを非表示にしてから再表示し、アニメーションが再開することを確認します。
- アクセシビリティを確認します。ステータスが正確に 1 回だけ通知され、タスク固有のラベルが使用されていることを確認します。
- 成功、エラー、キャンセル、アイドルの各状態で、オーブが消えることを確認します。
- コンソールエラー、ハイドレーション警告、レイアウトシフトが発生しないことを確認します。
よくある落とし穴
- サイズの型エラー:
20または64のみを使用してください。任意の寸法は渡さないでください。 - コントラストの誤り:
darkは暗い背景を対象とするため、明るいインクで描画することを覚えておいてください。 - スクリーンリーダーでの読み上げ重複: 隣接する
role="status"のテキストがタスクをすでに通知している場合は、canvas を非表示にしてください。 - 誤解を招く状態: 生成中に
searchingを、マイクでの音声キャプチャ中にcomposingを表示しないでください。 - 読み込み UI の常時表示: 作業が終了したらオーブを削除し、実際の終了状態を表示してください。
- ハイドレーションまたはサーバーコンポーネントのエラー: インポートをクライアントコンポーネントに移動してください。
- ブランドカラーの指定: 公開 API はモノクロです。サポートされていないスタイル設定に頼らず、別のローダーを選ぶか、意図的にライブラリをフォークしてください。
引き継ぎ
マッピングしたプロダクトのフェーズ、選択したサイズ、テーマモード、アクセシブルなラベルの方針、動きを抑える設定時の動作、ビルドとブラウザーでの検証について報告してください。ローカルでの実装とデプロイ済みリリースを区別してください。