原生 Web 组件
原生 <orb-z> 元素是 Orbz 的基础。无论应用使用纯 JavaScript 还是框架,只要支持自定义元素就能使用。
自动注册
在应用代码中导入一次浏览器入口:
import "@neongate-ai/orbz/browser";模块会调用 defineOrbz()。注册带有保护:在服务器上不执行操作;若页面其他部分已注册 orb-z,则返回已有构造函数。
标签可在模块加载前后渲染。自定义元素定义完成后,浏览器会升级已有标签。
<orb-z state="idle" size="18rem"></orb-z>连接或升级元素绝不会启动语音。宿主必须显式配置语音引擎,并在访客主动启用时调用 startTalking()。
显式注册
要精确控制注册时机,请使用根入口:
import { defineOrbz } from "@neongate-ai/orbz";
const OrbzElementClass = defineOrbz();defineOrbz() 在浏览器中返回元素构造函数;当 customElements 或 HTMLElement 不可用时返回 undefined。可安全重复调用。
通过 HTML 属性控制
<orb-z
state="thinking"
size="320px"
speed="1.15"
preset="periwinkle"
reduced-motion="system"
elevated
></orb-z>元素监听属性变化,因此更新属性会立即同步外观:
const orb = document.querySelector("orb-z");
orb?.setAttribute("state", "speaking");
orb?.setAttribute("speed", "1.25");
orb?.toggleAttribute("elevated", true);通过 JavaScript 属性控制
在 JavaScript 中更改状态时,使用属性通常更清晰:
import type { OrbzElement } from "@neongate-ai/orbz";
const orb = document.querySelector<OrbzElement>("orb-z");
if (orb) {
orb.state = "listening";
orb.size = 300; // normalized to "300px"
orb.speed = 1.2;
orb.reducedMotion = "system";
orb.elevated = true;
}每个公开 JavaScript 属性都会反映到对应的 HTML 属性。size 可接受转换为像素的数字,或 "20rem" 等 CSS 长度字符串。
语音引擎和对话流程仅通过 JavaScript 属性设置。先准备流程并插入元素,只有用户明确操作后才配置引擎并启动语音:
import "@neongate-ai/orbz/browser";
import { WebSpeechAdapter, type OrbzElement, type OrbzTalkStep } from "@neongate-ai/orbz";
const flow = [
{ id: "welcome", kind: "say", needsAuth: false, text: "Hello." },
{ id: "name", kind: "ask", needsAuth: false, text: "What is your name?", capture: "fullName" },
{ id: "help", kind: "say", needsAuth: false, text: "How can I help, {{fullName}}?" },
{ id: "answer", kind: "respond", needsAuth: false, strategy: "openai", fallback: "I cannot answer that right now." }
] as const satisfies readonly OrbzTalkStep[];
const orb = document.createElement("orb-z") as OrbzElement;
orb.talkFlow = flow;
orb.voiceEngine = new WebSpeechAdapter({ language: "en-US" });
document.body.append(orb);
const startVoiceButton = document.querySelector<HTMLButtonElement>("[data-start-voice]");
startVoiceButton?.addEventListener("click", async () => {
await orb.startTalking();
});布尔属性
paused 和 elevated 遵循原生 HTML 布尔属性语义:只要属性存在就为真,与所赋字符串无关。
<!-- Elevated -->
<orb-z elevated></orb-z>
<!-- Also elevated: "false" is still a present attribute -->
<orb-z elevated="false"></orb-z>移除属性,或将 JavaScript 属性设为 false:
orb?.removeAttribute("elevated");
if (orb) {
orb.paused = false;
orb.elevated = false;
}内置预设或自定义配色
使用 preset 属性选择内置配色:
<orb-z preset="magenta"></orb-z>默认外观是 Neongate;省略 preset 即可跨版本选择默认外观。其他预设为 periwinkle、magenta、peach、mocha 和 ivory。参见预设名称和版本兼容性。
使用自定义配色时,省略 preset 并设置五个颜色属性中的任意属性:
<orb-z
color-primary="#7C3AED"
color-secondary="#22D3EE"
color-accent="#F472B6"
color-highlight="#FDE68A"
color-background="#09090B"
></orb-z>未设置的颜色回退为 Neongate 默认值。不要同时使用显式 preset 和 color-*。若两种模式同时存在,预设优先,Orbz 会在控制台报告冲突。
由应用状态机驱动
让应用保持唯一事实来源,并使 Orbz 映射该状态:
import type { OrbzElement, OrbzState } from "@neongate-ai/orbz";
const orb = document.querySelector<OrbzElement>("orb-z");
function presentAssistantState(state: OrbzState, message: string) {
if (orb) orb.state = state;
const status = document.querySelector<HTMLElement>("[data-assistant-status]");
if (status) status.textContent = message;
}
presentAssistantState("thinking", "Assistant is preparing a response");支持五个状态:idle、listening、thinking、speaking 和 asleep。未知值归一化为 idle。
播放方法
原生元素提供三个专用动画方法:
orb?.pause(); // freeze the current animation
orb?.play(); // resume it
orb?.restart(); // rebuild the current state's animationpaused 属性仍是声明式方案。在命令式浏览器集成更方便时可使用方法。
动效偏好
reduced-motion="system" 遵循用户的 prefers-reduced-motion 并响应变化。always 强制使用减少动态效果的呈现,never 强制使用完整动效。
<div role="status" aria-live="polite">
<orb-z state="thinking" reduced-motion="system"></orb-z>
<span data-assistant-status>Assistant is thinking</span>
</div>在球体外提供有意义的文字。组件是视觉信号,不应成为用户了解助手状态的唯一途径。
框架模板
导入一次 /browser 后,Vue、Svelte 和 Angular 可将响应式值直接绑定到原生标签。应用与 Orbz 之间没有框架适配器或共享运行时。
完整应用见沙盒工作区 。