mcpField
T
thinking-orbs

thinking-orbs

github.com/mengto设计与 UI7.1k1.4k 次安装3 天前更新
代码仓库

关于 thinking-orbs

thinking-orbs 是 React 组件包,用单色动态圆点呈现不确定的 AI 活动状态。它提供六种状态和两种固定尺寸,并内置主题、可见性及减少动态效果的处理。

主要功能

  1. 01六种常见 AI 任务状态
  2. 02两种固定画布尺寸
  3. 03自动处理主题和可见性
  4. 04减少动态效果时显示静态帧
  5. 05原始画布帧绘制 API

适用场景

  1. 01在 React 界面显示搜索或推理状态
  2. 02在 AI 生成回复旁展示状态
  3. 03提供适配减少动态效果设置的反馈

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/mengto/skills --skill thinking-orbs

安装后在 Claude Code 中输入/thinking-orbs确认已加载。

附带文件agents/openai.yamlREFERENCES.md

详细介绍

思考光球

核心约定

  1. 在需要提供不确定性 AI 活动反馈的 React 18+ 界面中使用 thinking-orbs。
  2. 将产品的实际生命周期映射到已提供的六种状态之一。
  3. 仅使用经过调校的 20 或 64 像素尺寸。不要将一个预设拉伸成另一个尺寸。
  4. 除非周围界面的主题固定,否则保持 theme="auto"。
  5. 如果活动对用户很重要,请将光球与简洁、可见的状态文本搭配使用。
  6. 将 aria-label 覆盖为针对具体任务的标签;如果相邻的实时文本已播报相同状态,也可以让辅助技术忽略光球。
  7. 使用 paused 冻结当前帧。不要用 speed={0} 模拟暂停。
  8. 将光球视为不确定性反馈,绝不能将其用作进度百分比或完成信号。

此包会在透明的 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、取消或空闲时移除光球。应显示相应的结果、重试或错误界面,而不是让最后一个活动动画继续运行。

只播报一次状态

组件默认使用 role="img",并为每种状态提供相应标签,例如“正在搜索……”。当可见文本描述相同状态时,应让该文本成为唯一的播报来源:

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 effect、画布、requestAnimationFrame、媒体查询和观察器。在 Next.js App Router 中,请将包导入放在客户端边界之后:

"use client";

import { ThinkingOrb } from "thinking-orbs";

export function ThinkingStatus() {
  return <ThinkingOrb state="working" size={20} />;
}

该库兼容 SSR,因为它只会在客户端解析主题后绘制。框架强制区分服务端组件和客户端组件时,仍然需要客户端边界。

内置运行时行为

  • 使用纯 Canvas 2D 弧线绘制;不使用 WebGL 或 SVG 滤镜。
  • 将设备像素比上限设为 2。
  • 每个可见实例使用一个 requestAnimationFrame 循环。
  • 使用共享的 performance.now() 时钟,让多个光球保持同步。
  • 画布滚动到视口外时,通过 IntersectionObserver 暂停。
  • 浏览器标签页隐藏时暂停。
  • 在 prefers-reduced-motion: reduce 下渲染一个确定性的静态帧。
  • 在减少动态效果模式下继续跟随实时主题变化。

不要在包装组件中重新实现这些行为。围绕该组件添加产品状态管理和布局,而不是再创建一个动画循环。

高级用户 Canvas API

产品 UI 优先使用 <ThinkingOrb>。该包还会导出解析后的预设和原始帧绘制器,供 React 之外的自定义画布使用:

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 → orbits
  • searching → globe
  • solving → rubik
  • listening → wave
  • composing → ribbon
  • shaping → morph

仅当其他渲染器负责管理画布生命周期时,才使用原始 API。它提供的是帧绘制器,而非组件行为。绕过 <ThinkingOrb> 时,请自行实现 DPR 尺寸调整、清除画布、动画调度、暂停、主题解析、减少动态效果、可见性处理、清理和无障碍支持。

验证

运行项目的类型检查、测试、生产构建和 git diff --check。然后在真实浏览器中验证:

  1. 触发每个产品阶段,确认映射后的光球状态准确。
  2. 确认 20 和 64 像素的实例无需 CSS 缩放也清晰锐利。
  3. 测试深色、浅色主题以及实时主题切换。
  4. 测试减少动态效果模式,确认光球变为具有代表性的静态帧。
  5. 将光球滚动到视口外再返回;确认它恢复运行且没有明显异常。
  6. 隐藏并恢复标签页;确认动画恢复运行。
  7. 检查无障碍支持:状态只播报一次,并使用针对具体任务的标签。
  8. 确认光球在成功、错误、取消和空闲状态下都会消失。
  9. 确认没有控制台错误、水合警告或布局偏移。

常见问题

  • 尺寸类型错误: 尺寸只能使用 20 或 64;不要传入任意尺寸。
  • 对比度不正确: 请记住,dark 针对深色背景,因此绘制的是浅色图案。
  • 屏幕阅读器重复播报: 如果相邻的 role="status" 文本已播报任务状态,请隐藏画布。
  • 状态具有误导性: 生成期间不要显示 searching,麦克风采集期间不要显示 composing。
  • 加载 UI 一直存在: 工作结束后移除光球,并渲染实际的终态。
  • 水合或服务端组件错误: 将导入移入客户端组件。
  • 需要品牌色: 公共 API 为单色;请改用其他加载指示器,或有意创建库的分支,而不要依赖不受支持的样式。

交接

报告映射后的产品阶段、选定的尺寸、主题模式、无障碍标签策略、减少动态效果行为,以及构建和浏览器验证情况。区分本地实现与已部署版本。

评论

支持 Markdown