Persona 运行一个本地 WebSocket 服务器,供外部应用程序连接与驱动:切换场景、添加并排列图层、开关表情、播放动作、播放带口型的语音、读取捕捉状态,以及直接写入模型参数。
API 服务默认处于关闭状态。可在 设置 → 插件 API 中开启服务、创建 API 密钥,并将生成的 Token 填入插件或外部集成中。
服务配置
| 配置项 | 说明 |
|---|---|
| 启用 API | 启动 WebSocket 服务。客户端须携带有效的 API 密钥方可建立连接 |
| 端口 | 默认端口为 25034 |
| 允许局域网访问 | 绑定到回环地址之外的网络接口,允许局域网内的移动设备或其他主机连接 |
启用局域网访问后,Persona 会显示当前主机的局域网 IP 与端口,便于远程设备或 Web 控制台配置连接。
若指定端口已被其他进程占用,设置面板将直接显示错误状态提示。
API 密钥
所有外部连接均须经过身份验证,未经认证的连接将被直接拒绝。点击 创建密钥 可指定密钥名称,系统将生成 Token 并完整展示一次;后续亦可随时点击对应行右侧的复制按钮获取完整 Token。
| 操作 | 说明 |
|---|---|
| 复制令牌 | 将完整 Token 复制至剪贴板 |
| 重命名密钥 | 修改密钥名称 |
| 吊销密钥 | 吊销并删除密钥。正在使用该密钥的活跃会话将被强制断开,并通知客户端禁止自动重连 |
各密钥行会实时显示 已连接、从未使用 或最近使用的相对时间。客户端在连接握手中声明身份后,该行将记录其名称与版本信息,即便断开后仍可识别调用来源。
Token 安全保存在操作系统的凭据存储区(如 macOS Keychain、Windows Credential Manager 等)。在不支持安全凭据存储的环境中,密钥创建操作将明确返回失败原因,杜绝明文存储风险。
插件目录与资源注册
插件可通过 API 请求 Persona 注册并加载模型或素材资源。model.register 与 asset.register 仅接受位于用户在设置中(通过系统对话框)配置的 插件目录 下的绝对路径,路径验证会自动解析两端的符号链接;访问其余任何路径均会被系统以 forbidden-path 错误拒绝。
具备 asset-import 能力时,连接自同一台计算机(回环地址)的客户端还可调用 registry.pluginFolders(返回 { folders })读取已配置的插件目录,或调用 asset.import { path, want? } 将本地文件导入素材库:
- 位于插件目录内或已在素材库中的文件会直接完成注册,不弹出提示;其余路径会在桌面控制面板中弹出确认提示(添加文件,显示客户端名称与 API 密钥名称,开启推流模式时隐藏所在文件夹名)。用户拒绝或在 45 秒(
ASSET_IMPORT_PROMPT_MS)内未响应时返回forbidden-path;已有导入提示等待确认期间再次发起导入将返回invalid-state。非回环地址的远程客户端调用这两个方法均直接返回forbidden-path。 asset.register与asset.import均会等待舞台刷新资源列表后再返回,随后即可直接调用object.add加载该素材。
注册的资源 ID 采用内容寻址(sha256(path) 前缀),重启后保持不变,真实路径也无需经网络传输。ModelRef 与 AssetRef 的 origin: 'bundled' 同时涵盖应用随附的内置内容与桌面端从 Persona 目录按需下载的内容;尚未下载的目录条目不会出现在列表中,API 也不提供目录下载方法。
asset.register 的 want 字段声明素材种类,不匹配时返回 invalid-params:
image、video、prop、ibl、lutanimation与cameraMotion:共用.vmd扩展名,由文件头特征自动区分audio(WAV、MP3、OGG、FLAC、M4A 或 AAC 文件)与lyrics(.lrc文件):属于素材/清单资源类型,而非ObjectContent,注册后不会在舞台上创建独立的场景图层
模型引用以 entryFile 携带入口文件的基准名称;.vtube.json 文件的基准名称 vtubeFile 仅在 model.list 中返回(未配置时为 null,且不是完整目录路径)。SDK 的 modelMatchesFile 即基于这些名称匹配模型加载快捷键,因此匹配快捷键时应比对 model.list 的返回结果,而非场景条目引用。
已连接的客户端
服务运行期间,控制面板将列出所有已建立连接的客户端会话,展示其声明的客户端名称、版本、开发者标识、使用的 API 密钥以及连接来源 IP。Web 浏览器客户端将一并展示其页面 Origin。
未声明身份信息的客户端将归类为 未识别的客户端,其 API 调用权限不受影响。点击会话行右侧的断开按钮可主动终止该连接,并通知客户端停止重连。
每当建立新连接时,系统将发出一条静默系统通知,提示客户端名称、密钥与连接来源 IP。若操作系统权限阻止发送通知(如未签名的开发版本或系统通知权限关闭),控制面板打开时会在其中改为显示弹出提示。通知不会在舞台渲染窗口中叠加显示,避免污染直播采集画面。
请妥善保管 API 密钥 Token。持有 Token
的客户端具备完整的舞台控制权限,包括加载插件目录内的任意模型与素材资源。除非手动开启局域网访问,服务仅监听本地回环地址(127.0.0.1)。
Web 控制台
这些控制项的说明见 网页控制台。
Stream Deck
Persona 官方提供的 Stream Deck 插件 是基于该 API 开发的另一款第一方集成,将模型与场景切换、快捷键触发、表情与动作控制以及虚拟形象位移缩放直接映射至实体按键。
MCP 服务器
@laplace.live/persona-mcp 为基于 Model Context Protocol 构建的官方服务,将该套 API 封装为面向 AI 助手(如 Claude、Cursor、Codex 等)的任务专用工具集与通用的 call_api 接口,并提供 stage.capture 供智能体实时观测画面状态。
SDK
@laplace.live/persona-sdk 是官方提供的类型安全客户端库,兼容 Node.js、Bun、Web 浏览器以及 OBS 浏览器源等运行环境。
import { PersonaClient } from "@laplace.live/persona-sdk";
const persona = new PersonaClient({ token: "sk-lp-v1-…" });
await persona.connect();
await persona.call("expression.toggle", { name: "Smile" });
persona.on("motion.started", (m) => console.log("playing", m.group));SDK 内所有方法调用均由同一份强类型 Schema 定义,调用的参数签名与响应结构均由方法名称自动推导。SDK 参考文档 详细介绍了安装、客户端配置、身份认证、参数租约以及所有导出的类型定义。
事件
客户端仅会接收已订阅的事件消息。若发生断线重连,SDK 将自动恢复此前的所有订阅。
| 事件 | 触发时机 |
|---|---|
scene.changed | 场景发生变更:创建、删除、重命名、激活或属性修改 |
scene.loading | 场景激活生效或渲染管线预热的开始与结束阶段 |
settings.changed | 应用程序全局设置发生变化 |
instance.loaded | 模型实例在舞台上完成加载与初始化 |
selection.changed | 编辑器选中目标发生变化(包含所有来源) |
expression.changed | 当前激活的表情组合发生变化 |
expression.persistence | 模型的「记住表情」开关状态发生改变 |
expression.groups | 模型的表情组发生变化,由任意编辑器或表情文件的重命名、删除触发(依赖 expression-groups 能力) |
motion.started | 动作片段开始播放;支持 motion-stop 能力的主机将附带 oneShot 标识 |
motion.ended | 动作片段播放结束 |
speech.started | 由 speech.play 触发的语音开始播放 |
speech.ended | 语音播放结束(播放完成、被手动停止或被新语音替换) |
hotkey.state | 舞台上模型的快捷键配置或其后台触发状态变化;模型移出舞台时返回空列表 |
automation.state | 自动化列表、名称、触发器类型、启用状态或后台触发状态发生变化 |
tracking.status | 面部或姿态捕捉状态变化,或任一捕捉源自身状态变化(涵盖面部、手部与身体捕捉) |
registry.changed | 本地模型或素材注册表更新、文件丢失与恢复,或模型缩略图发生变更;需按 kind 重新拉取资源列表并清除对应的 registry.thumbnail 缓存 |
model.movement | Live2D 模型的整体移动配置发生变化,由任意编辑器触发(依赖 model-movement 能力) |
model.versions | 模型的版本历史发生变化(保存、命名或切换版本,开启或关闭版本历史),或 Persona 写入了该模型的某个文件,需重新调用 model.listVersions(依赖 model-history 能力) |
方法一览
所有以模型为作用域的 API 方法均接受可选的 instanceId 参数,省略时默认作用于当前场景的 主模型。
| 分组 | 方法 |
|---|---|
scene.* | list get activate create duplicate rename delete patch inspect setLightFollowCamera |
preset.* | create update rename setTransition delete apply(依赖 scene-presets 能力) |
instance.* | list get add setModel remove setVisible setEffects setTrackingSources reorder setPrimary setPlacement attach setMToon setIdle setControllerMovement setLipSync info |
binding.* | get preview set release inputs override |
controller.* | state rename setDeadZone remove assign |
selection.* | get set |
object.* | add addMany rename setContent setText setSpace setPlacement attach setLightOverrides anchors |
expression.* | list active toggle getPersistence setPersistence,以及 getGroups setGroups(依赖 expression-groups 能力) |
motion.* | list play playing stop |
speech.* | play stop |
hotkey.* | list set trigger |
automation.* | list run,以及 get create update delete(依赖 automation-editing 能力)与 control status(依赖 automation-transport 能力) |
model.* / asset.* | 各自的 list 与 register、asset.import 与 registry.pluginFolders(依赖 asset-import 能力)、registry.thumbnail,针对 Live2D 模型的 model.getMovement 与 model.setMovement,管理 版本历史 的 model.listVersions setVersionHistory saveVersion nameVersion switchVersion restoreFiles compareVersions |
fonts.* | list(依赖 object-text 能力) |
settings.* | get patch |
tracking.* / pose.* | tracking.addSource tracking.updateSource tracking.removeSource、setEnabled、setSource,以及 pose.setPort 和 tracking.status |
lipSync.* | state configure restart calibrate |
stage.* | resetTransform resetCamera spawn clearSpawned capture |
app.* / session.* | app.info app.localAddresses app.stats,以及 session.identify |
storage.* | get set delete list |
param.* | inject release |
scene.create 会追加一个空白场景并立即激活,行为与桌面端新建场景一致。响应中的 activeSceneId 即为新场景 ID;请直接使用该值,不要比对前后两次的场景列表,以免与其他会话并发创建场景时产生时序冲突。
scene.patch 用于修改当前场景的背景、相机、灯光、环境以及 场景转场;场景内的条目则通过 instance.* 与 object.* 修改。
灯光的 enabled 设为 false 时,灯光与其投射的阴影一同关闭,其他配置保持不变。该字段默认为 true;不支持单独关闭灯光的旧版本不包含该字段。
相机
vrmCamera 支持整组覆盖配置:orbit、fov(1 – 179°)、roll(绕视线轴旋转的弧度)、projection(perspective 或 orthographic)以及 clipAssetId。
- 环绕角度接受任意弧度值,
distance支持负值(鼠标交互导航保留相对受限的范围)。 - 正交投影下,视图宽度为
abs(distance),fov保留但不参与计算;distance为负时两个轴向均会翻转。 - 调用
stage.resetCamera会一并重置相机滚转与投影模式。 - 旧版本构建不包含
roll与projection,按 0 与perspective处理;渲染对应控件前,应先检查返回结果中是否存在这两个字段。
vrmCamera.follow 让相机跟随某个图层取景:{ instanceId, anchor, binding, damping }。默认为 null,需要 camera-follow 能力。
| 字段 | 说明 |
|---|---|
instanceId | 要跟随的 VRM 模型或 3D 物体。传入 { target: 'primary' } 则始终跟随当前主模型(主模型不是 VRM 时暂停) |
anchor | 模型可用 { kind: 'bone', bone }(默认 head)或 { kind: 'root' };3D 物体始终跟随其根节点 |
binding | 目标旋转如何带动相机:world 忽略旋转;yaw、yaw-pitch、full 分别跟随偏航、偏航与俯仰、三轴旋转;lazy 仅在锚点从画面侧边移出时转动 |
damping | 各轴平滑时间(秒),0 – 10,0 为立即锁定:位置 x、y、z,旋转 yaw、pitch、roll |
orbit决定目标位于原点时的构图。跟随期间,相机随目标的位移、走动、动作与姿态捕捉一起移动,不会改写orbit。- 切换到其他图层或锚点时平滑过渡;移除被跟随的图层或将其移入 2D 时,
follow重置为null。 - 正在播放的相机运动会覆盖跟随;
stage.resetCamera重新对准目标并保留follow。
vrmCamera.aim 让相机原地转动镜头,使目标保持在画面的指定区域:{ instanceId, anchor, screenX, screenY, deadZone, softZone, bias, damping, lookahead }。默认为 null,需要 camera-aim 能力。
| 字段 | 说明 |
|---|---|
screenX、screenY | 目标在画面中的归一化位置(0 – 1,从左上角起算) |
deadZone | 死区宽高,各 0 – 1。目标位于死区内时相机静止 |
softZone | 软区,不小于死区。目标超出软区时相机全速回转 |
bias | 软区的偏移量 |
damping | 目标超出死区后,相机在 damping.horizontal/vertical 秒内平滑旋回 |
lookahead | lookahead.time(0 – 1 秒,0 为关闭)根据移动速度预判朝向,带平滑度 smoothing(0 – 30)与 ignoreY 开关 |
- 相机机位坐标与视距保持不变,仅视线朝向转动:以世界 Y 轴偏航、以自身横轴俯仰,并保持镜头滚转。
- 拖拽舞台手柄或模型加载时,镜头保持静止。
- 清除规则与
follow一致;相机运动轨迹动画会覆盖注视效果。
vrmCamera.focus 在 景深 开启时,把焦平面锁定在指定图层或锚点上,而非注视点距离。默认为 null,需要 camera-focus 能力;damping 默认为 0.2 秒。
- 锚点位于相机视锥背面时,自动回退至常规注视距离。
- 相机运动轨迹回放期间依然生效;景深关闭时不产生可见效果。
vrmCamera.handheld 用连续平滑噪声为相机添加手持拍摄般的微幅晃动。默认为 { enabled: false, intensity: 0.5, speed: 1 },需要 camera-handheld 能力;intensity 范围 0 – 1,speed 范围 0 – 2。
- 开关或修改强度时,在约 1 秒内平滑过渡。
- 不写入保存的场景配置;播放相机运动轨迹时被覆盖,拖拽舞台手柄时自动暂停。
物体与文字
object.add 支持传入 place2d 或 place3d 空间摆放参数,在创建物体的同一事务中直接放到指定位置,避免先在默认原点处渲染一帧;取值规则同 object.setPlacement。
object.addMany { objects } 在单次场景编辑中批量添加最多 100 个条目,仅触发一次保存,撤销也只计一步,并按请求顺序返回 instanceIds。任意一个素材无法解析时,整批操作回滚。
具备 object-text 能力时,ObjectContent 可以是文字图层:{ kind: 'text', text, font, size, color, shear, letterSpacing, wordSpacing, lineHeight, align, verticalAlign, boxWidth, boxHeight, overflow, stroke, shadow, plate, sung, extrude, bevel, bevelResolution, roughness, metalness, emission, faceCamera }。单个图层共享同一样式。
| 字段 | 说明 |
|---|---|
font | 优先通过 postscriptName 指定系统字形,字体缺失时回退至 family、weight、italic 与 stretch 匹配;传入 null 使用默认无衬线字体 |
size | 单位为像素。3D 文字尺寸按 1000 像素每米计算,与图片平面一致 |
boxWidth、boxHeight | 文本框尺寸,单位为像素 |
letterSpacing、wordSpacing | 间距,单位为 em |
lineHeight | 倍数 |
align、verticalAlign | 摆放位置锚定在对齐基点上,如同 Blender 文字原点(如左对齐文本向右扩展) |
stroke、shadow、plate | 仅 2D:描边、阴影与背景板,绘制范围单位为像素 |
sung: { color, strokeColor } | 渲染歌词片段已唱过的部分:在两个空间均填充颜色,在 2D 中同时渲染描边 |
extrude、bevel | 仅 3D,单位为 em |
bevelResolution | 仅 3D,细分段数 |
roughness、metalness、emission | 仅 3D,参与光照 |
faceCamera | 仅 3D,开启后始终朝向视线 |
- 在 3D 空间中,文字呈现为类似 Blender 的几何挤出立体字;两个空间各自保留对方的特有属性,不予丢弃。
- 所有字段均实时生效。对文字图层调用
object.setContent会像拖拽一样直接编辑,每次输入停顿计为一步撤销。 fonts.list返回桌面主机已安装的字体族与字形,供远程控制面板选择。- 未声明该能力的旧版主机无法正确解析文字图层,会将其丢弃。
object.setText { instanceId, text, transient? } 仅更新文字图层的文本内容,实时生效,输入停顿合并为单步撤销。
- 传入
transient: true时仅展示临时文本,不写入scenes.json,也不记录撤销历史;临时文本保留至传入text: null、保存真实文本,或该图层移出舞台(被移除或激活另一场景)为止。scene.inspect会将其作为该物体的liveText返回。 - 对非文字物体调用将返回
unsupported-for-format错误。 - 超出
TEXT_LENGTH_MAX的文本将被截断。
具备 object-video-sound 能力时,可通过 object.setContent 像拖拽一样直接修改视频图层的 loop(循环)、muted(静音)与 volume(音量),每次停顿计为一步撤销,避免重新加载场景;视频声音通过桌面主机配置的音频输出设备播放。未声明该能力的旧版主机每次修改都会重新加载场景并记录独立的撤销历史,声音则在系统默认设备上播放。
具备 object-chroma-key 能力时,图片、视频与网页图层可配置 chromaKey 色度键参数({ enabled, color, similarity, smoothness, spill }),用于去除纯色背景。调用 object.setContent 会直接更新图层,拖拽调整停止时合并记录为单步撤销。未声明该能力的旧版主机会在规范化时丢弃该字段。
instance.attach { instanceId, attach } 可将 Live2D 实例作为 物品 挂接至另一个 Live2D 模型,参数结构与 object.attach 一致;传入 null 可在当前位置解除挂接。
| 字段 | 说明 |
|---|---|
attach.depth | { kind: 'front' }、{ kind: 'behind' } 或 { kind: 'artMesh', id }。最后一种会将物品插入父模型指定 ArtMesh 的正上方,父模型不存在该 ID 时回退至最前方 |
attach.split | { itemArtMesh, depth }:在物品自身的指定 ArtMesh 处切分层级,将其下层部分渲染至第二深度 |
object.anchors返回的各条目包含order字段,即查询时该 ArtMesh 的绘制顺序,深度控制面板依此排列选项。- 挂接关系形成循环依赖时返回
invalid-params错误;对 VRM 实例调用返回unsupported-for-format。 - 在具备
object-pin-depth能力的主机上,钉选到 Live2D 模型的 2D 图片、视频或网页同样按attach.depth深度交错渲染在父模型图层内部(整体绘制,不支持split切分);3D 物体目前仅front模式生效。 object-pin-depth还让 2D 网页作为标准场景图层参与图层排序与后处理特效,并移除旧版专用的layer属性。未声明该能力的旧版主机会忽略物体的深度设定,按场景顺序叠放钉选的媒体,并通过layer将 2D 网页整体置于舞台前后。
舞台
stage.resetTransform { instanceId? } 重置指定图层的空间变换摆放;未传入 instanceId 时作用于应用内当前选中的图层,未选中时作用于主模型。已加载的模型会在约 ⅓ 秒内平滑回到原位。
stage.capture 返回舞台视口当前画面的带透明通道 PNG 截图:{ dataUrl, width, height }。需要 stage-capture 应用能力;最长边缩放至不超过 maxEdge(64 – 2048,默认 1024),且不会放大。
- 该方法主要供无界面客户端(如通过 MCP 服务器 集成的 AI 助手)校验操作效果。
- 截图会让渲染管线暂停一帧,建议按需调用,避免高频轮询。
renderer-unavailable错误表示舞台窗口未就绪或没有可供复制的帧缓冲区;舞台崩溃重载后,首帧完成渲染前均会返回该错误,客户端应重试。
能力声明
应用级与实例级的能力表(Capabilities)声明当前运行版本支持哪些特性。请始终依据能力表适配功能,不要通过解析版本号字符串来推断。
应用级能力由握手响应 hello 与 app.info 返回:
| 能力 | 新增功能 |
|---|---|
storage | 插件存储 |
speech | 语音驱动 |
automations | 自动化 |
layer-effects | 图层特效 |
scene-transitions | 场景转场 |
light-area | 面光源 |
light-spot | 聚光灯 |
light-camera-follow | 灯光跟随相机 |
light-shadow-filter | 逐灯阴影过滤(PCF 或 PCSS) |
environment-map-model | 同时使用环境贴图与环境模型 |
stage-spawn | stage.spawn |
idle-tracking-lost | 面部丢失时的待机设置 |
motion-stop | motion.stop |
stage-capture | stage.capture |
controllers | controller.* 与 controller.enabled 开关 |
model-editing | binding.* 与 instance.setBreath |
model-movement | model.getMovement 与 model.setMovement |
asset-inspection | scene.inspect 与 registry.thumbnail |
object-pin-depth | 钉选到 Live2D 模型的 2D 媒体按深度渲染 |
object-text | 文字图层与 fonts.list |
camera-follow | vrmCamera.follow |
camera-aim | vrmCamera.aim |
camera-focus | vrmCamera.focus |
camera-handheld | vrmCamera.handheld |
object-video-sound | 视频图层直接编辑与声音输出 |
object-chroma-key | 图片、视频与网页图层的色度键去除背景 |
model-movement-pivot | 整体移动的缩放中心 pivot |
layer-effects-2d | 2D 图片、视频、网页与文字的图层特效 |
scene-presets | 场景预设 |
background-alpha | 背景颜色的 Alpha 通道 |
binding-calibration | 逐输入绑定校准 |
binding-random-pulses | 随机脉冲输入与 randomPulses 触发设置 |
expression-groups | 表情组 |
expression-groups-hide-first | 表情组的「先隐藏再显示」切换模式 |
model-history | 模型版本历史 |
automation-editing | automation.get、create、update 与 delete |
automation-transport | automation.control 与 automation.status |
asset-import | asset.import 与 registry.pluginFolders |
各能力标识以其扩展的特性命名(如 light-spot、object-text)。服务端会同时列出重命名前的历史标识,以兼容旧版本客户端;SDK 客户端会自动将旧名称映射为当前名称。
各模型实例的能力表通过 instance.list 返回的 capabilities 声明;调用当前实例格式不支持的方法将返回 unsupported-for-format 错误。instance.list 与 instance.get 还会返回 loadError?: string | null,说明最近一次加载失败的原因(已加载或正在加载时为 null,旧版主机省略该字段)。
手柄
controllers 对应 controller.*(查询已连接设备与预设配置、重命名、配置死区、移除配置及发起通道映射),并允许通过 settings.patch 配置 controller.enabled 全局开关。这里的设备指连接至桌面主机物理接口的硬件。
instance.setControllerMovement 用于更新实例的 手柄移动 配置:enabled、slot(预设槽位编号)、moveSpeed、turnSpeed、smoothing;对 VRM 模型还包含 walkEnabled、walkClip、walkSpeed 与 faceMovement。walkClip 的引用格式与 instance.setIdle 完全一致。超出范围的数值将被修正至边界值;对非模型物体调用将返回 unsupported-for-format。
参数绑定
model-editing 对应 instance.setBreath 与 binding.*,后者用于查询、预览、写入与释放模型参数映射。
binding.override用于短时覆盖输入。binding.inputs返回{ inputs, outputs }:inputs为实时捕捉输入数据,outputs包含各被映射参数在完成动作、表情与物理演算后的当前读取值,模型未声明的输出项不予返回。Time24h与Time12h为内置的时间绑定输入通道,取值范围为0..1。它们每渲染帧采样一次桌面主机的本地时钟,独立于面部捕捉,同时驱动 Live2D 与 VRM 绑定(详见 时间参数绑定)。SDK 通过TIME_INPUT_NAMES、TIME_INPUT_RANGES与isTimeInputName导出相关定义。
binding-calibration 新增逐输入校准表 calibration:
binding.get会一并返回calibration:未校准时为{},未声明该能力的旧版主机不包含该字段。binding.preview与binding.set支持单独或同时传入connections与calibration,未传入的一侧在实时预览与磁盘写入时均保持原状。- 仅保存校准不会向
<model>.persona.json写入bindings,因此.vtube.json的原有绑定仍继续生效。
binding-random-pulses 新增内置随机脉冲输入 RandomPulse1 – RandomPulse8(取值范围 0..1,独立于面部捕捉)以及按模型保存的触发设置表 randomPulses:
- 仅由随机脉冲驱动的绑定会叠加在驱动同一参数的其他绑定之上(触发时向
outRange[1]过渡,静止时不覆盖,除非其静止输出与参数默认值不同),因此可与普通绑定共用同一输出参数(详见 参数绑定)。 binding.get一并返回randomPulses:未自定义任何脉冲时为{},未声明该能力的旧版主机不包含该字段。每项配置为{ intervalSeconds: [min, max], durationSeconds: [min, max], fadeInSeconds, fadeOutSeconds }(单位为秒,间隔与持续时长范围0.1–3600,淡入与淡出范围0–3600);未单独配置的脉冲采用DEFAULT_RANDOM_PULSE_SCHEDULE(间隔0.5–4.5秒、持续0.58秒、淡入淡出各0.29秒,与 VTube Studio 自动眨眼一致)。binding.preview与binding.set支持任意组合传入connections、calibration与randomPulses,省略的部分在实时预览与磁盘写入时均保持原状;仅保存randomPulses同样不会将.vtube.json的bindings复制到<model>.persona.json。
模型整体移动
具备 model-movement 能力时,可通过 model.getMovement 与 model.setMovement 读取与更新 Live2D 模型的 模型整体移动 配置,兼容 VTube Studio。
| 方法 | 说明 |
|---|---|
model.getMovement { modelId? } | 返回 { movement } |
model.setMovement { modelId?, movement } | 合并部分更新 { enabled, x, y, z },各轴移动量自动修正至 ±50(MODEL_MOVEMENT_MAX)内的整数。返回 { movement, saved }:saved 指示配置是否已成功写入磁盘;对只读或不可写文件返回 false,此时修改在 Persona 退出前持续生效,并在该文件下次成功写入时一并保存 |
modelId省略时默认作用于当前主模型;模型不存在返回not-found,对 VRM 模型调用返回unsupported-for-format。- 该配置作用于模型定义而非单个实例:优先保存在模型的
.vtube.json,不存在时写入.persona.json,与 VTube Studio 共享。 - 整体移动直接作用于模型摆放位置而不写入参数,与模型自有的
FacePosition*绑定叠加生效。 - 默认值沿用 VTube Studio 标准(开启,6/8/11);每次配置变更均会触发
model.movement { modelId, movement }事件。
model-movement-pivot 允许在 movement 中携带前后缩放中心 pivot:{ kind: 'root' } 为默认值,指向模型中心;也可传入 ArtMesh 锚点 { kind: 'artMesh', id, verts, weights }。
- 即使模型存在
.vtube.json文件,缩放中心仍保存在.persona.json中。 - 缩放中心基于模型的静止姿态计算,避免头部转动带动模型偏移。
表情组
具备 expression-groups 能力时,可通过 expression.getGroups 与 expression.setGroups 读写模型的 表情组,规则与 VTube Studio 的 Expression Groups 一致:在启用的组内,一个成员显示时,其余已显示的成员自动隐藏,使同组表情一次只显示一个。
| 方法 | 说明 |
|---|---|
expression.getGroups { modelId? } | 返回 { supported, groups, edited },每个组为 { id, name, enabled, hideFirst?, entries: [{ expression, fadeSeconds, inverted }] };supported 为 false 表示模型没有可供写入的配置文件,edited 表示同时存在 .vtube.json 的模型是否已在 .persona.json 中单独保存表情组(旧版主机省略该字段) |
expression.setGroups { modelId?, groups } | 整体替换所有组并宽容修正:缺失或重复的 id 重新生成,缺少 expression 的成员被丢弃,fadeSeconds 修正至 0 – 2 秒。返回配置文件中实际保存的 { supported, groups, edited } |
expression为成员的表情键:Live2D 为.exp3.json文件名,VRM 为表情名称,匹配时不区分大小写。- 表情开启或
inverted(反转)成员关闭时,均视为「显示」(反转成员关闭时算作显示,适合默认戴帽模型上的「摘帽」表情)。成员显示时,其所在各启用组内其他已显示的成员随之隐藏:普通成员关闭,反转成员开启,各自按自身的fadeSeconds过渡。隐藏一个成员不会显示另一个,因此组内可以一个都不显示;同一表情属于多个组且结果冲突时,以后面的组为准。 - 具备
expression-groups-hide-first能力时,组可设置hideFirst: true(先隐藏再显示):当某成员变为显示时,会等待该组隐藏的所有其他成员完全淡出后(包含淡入隐藏的反转成员)再开始淡入;省略或设为false时采用默认的交叉淡化(与 VTube Studio 一致)。由组触发的隐藏、清除全部表情、恢复表情、组整理以及将表情权重设为 0 均不会等待;未声明该能力的旧版主机会丢弃hideFirst。 - 成员的
fadeSeconds取代触发切换一方的淡入淡出时长,包括快捷键的fadeSeconds;停用的组连同其淡入淡出时长一并被忽略。 - 表情组对所有切换途径生效:
expression.toggle、快捷键、自动化、清除全部表情(之后每组重新整理,保留第一个显示的成员)以及恢复记住的表情;实际切换结果通过expression.changed推送。 expression.setGroups切换组的启用状态,或增删、反转成员时,会立即整理舞台上该模型当前显示的表情;仅重命名、调整淡入淡出时长或修改hideFirst不触发整理,与 VTS 编辑器一致。- 若
.persona.json尚未保存表情组,Persona 会以只读方式导入.vtube.json的ExpressionGroups(edited: false);一旦通过expression.setGroups或面板编辑了表情组,完整列表即写入.persona.json并从此优先于.vtube.json(同时存在.vtube.json时edited: true),不会改写.vtube.json。在表情编辑器中重命名或删除.exp3.json时,则会原地更新.vtube.json(不触发.persona.json接管)及已存在的.persona.json中的对应条目。 - 每次变更(包括表情文件重命名或删除引起的变更)均触发
expression.groups { modelId, groups, edited }事件(旧版主机省略edited)。
版本历史
具备 model-history 能力时,可读取与管理模型已保存的版本,对应桌面端模型详情中的 版本 分区(详见 版本历史)。所有方法均接受 modelId,省略时作用于主模型;对内置模型调用返回 invalid-state。除非手动保存或触发备份,系统不会自动保存版本。
| 方法 | 说明 |
|---|---|
model.setVersionHistory { enabled } | 开启或关闭版本历史,返回 { enabled }。是否开启应由用户决定;开启时会保存第一个版本 |
model.listVersions { limit? } | 返回 { enabled, versions, more, unsavedFiles }:从新到旧最多 limit 个 ModelVersion(1 – MODEL_VERSIONS_LIST_MAX,默认 MODEL_VERSIONS_LIST_DEFAULT)、是否还有更早的版本,以及磁盘上与当前版本不同的文件路径(不计表情开关状态) |
model.saveVersion { name?, notes? } | 将当前文件保存为一个版本并返回 { version };文件未改动且未指定名称时,返回当前版本 |
model.nameVersion { versionId, name, notes? } | 命名或重命名版本,name: null 移除名称。名称在所有版本中唯一(不区分大小写),重名返回 invalid-params |
model.switchVersion { versionId, unsavedChanges? } | 将模型文件切换为该版本并重新载入模型,保留当前开启的表情,返回 { version, backup };切换不会新增版本 |
model.restoreFiles { versionId, paths, unsavedChanges? } | 仅恢复列出的文件路径,返回 { backup };这些文件在下次保存前仍属于未保存的改动 |
model.compareVersions { from, to } | 返回 { files }:任一侧包含的每个路径及其 status(MODEL_VERSION_CHANGE_STATUSES)。任一侧均可传入 MODEL_VERSION_CURRENT 表示磁盘上的当前文件;仅表情开关状态不同的配置文件视为 unchanged |
ModelVersion为{ id, parentId, time, kind, message, name, notes, current }:kind取自MODEL_VERSION_KINDS(first、saved、backup),其他 Git 工具创建的提交为null,此时message为其提交信息首行;current标记当前磁盘文件基于的版本。- 切换或恢复将覆盖存在未保存改动的文件时,若未传入
unsavedChanges(MODEL_VERSION_UNSAVED_ACTIONS),返回invalid-state:'save'先将全部未保存改动保存为backup版本并在backup中返回;'discard'放弃将被覆盖的改动。 - 版本历史关闭时,保存、切换与恢复返回
invalid-state;列出、比较与命名仍可读取此前保留的历史。 - 模型文件缺失时,开启版本历史、保存、切换与恢复返回
not-found;为版本历史无法读取的文件夹(UNC 共享路径,或 macOS 与 Linux 上名称含反斜杠的文件夹)开启时返回invalid-state。 - 遇到 Persona 无法写入的文件,或其他 Git 工具留下的未完成状态(已暂存的文件、合并进行中、无分支)时,返回
invalid-state且不做任何改动。 - 版本名称最长 80 字符(
MODEL_VERSION_NAME_MAX_LENGTH),备注最长 2000 字符(MODEL_VERSION_NOTES_MAX_LENGTH)。 - 每次变更均触发
model.versions { modelId }事件;其他应用对文件的修改不会触发。旧版主机不提供上述方法。
动作与待机
motion.list 用于查询模型的动作分组列表。针对 Live2D 模型,系统会自动扫描模型目录下未在 .model3.json 中声明的 .motion3.json 文件,并以文件名自动生成对应动作分组,因此在桌面端通过 动作 分区 录制保存的动作 无需重新载入模型即可直接出现在列表中。
motion.stop 结束当前播放中的单次动作,并让模型平滑回到待机状态而非瞬间跳变(motion.ended 立即触发,不等待过渡结束),需要应用能力 motion-stop。若当前仅有待机动画在播放,该调用不执行任何操作并返回 { stopped: false }。
motion.playing 返回的 oneShot 字段(motion.started 事件中同样包含)表示当前动作是否为叠加在待机层之上的单次动作,即由 stop 负责停止的类型;旧版本构建不返回该字段。
instance.setIdle 用于更新指定实例的待机配置:
| 字段 | 说明 |
|---|---|
idleAnimation | 待机总开关。设为 false 将停止 VRM 的动画片段;针对 Live2D 则停止所有待机动作(包含模型内置的 Idle 分组) |
idleClip | 仅适用于 VRM 模型。指定的待机动画片段引用 |
idleMotion | 仅适用于 Live2D 模型,依赖实例能力 idle-motions。指定在其他动作底层循环播放的动作文件;设为 null 表示从模型内置 Idle 组中随机选出一个动作循环播放。若指定文件已不存在,系统将自动回退为 null 处理 |
trackingLostBehavior | 依赖 idle-tracking-lost 能力。hold 保持丢失前的最后一帧姿态;idle 在约 0.3 秒内平滑过渡回归待机状态,面部重新捕获后平滑恢复 |
trackingLostMotion | 依赖 idle-tracking-lost 能力,仅适用于 Live2D。在面部丢失超出指定时延后替代待机动作播放,设为 null 表示不作替换 |
trackingLostDelay | 依赖 idle-tracking-lost 能力。判定面部丢失的超时阈值(秒),范围 0 – 60 |
调用 instance.get 会同步返回上述待机配置。
灯光
具备 light-area 能力时,SceneLight 支持 area 类型:一块位于 x/y/z 处的矩形面光源。
| 字段 | 说明 |
|---|---|
azimuth、elevation | 朝向(度) |
roll | 在自身平面内旋转,−180 – 180°,默认 0 |
width、height | 尺寸,各 0.01 – 20 场景单位,默认 1 |
- 面光源可照亮 PBR 材质与 MToon 虚拟形象(MToon 在卡通着色管线中采用 4 个光照采样点近似模拟矩形光照),但不影响 Live2D 图层,也不投射阴影。
- 其
range与阴影配置会在数据层保留,便于之后切换灯光类型。
具备 light-spot 能力时,SceneLight 支持 spot 类型:一盏位于 x/y/z 空间坐标处的聚光灯。
| 字段 | 说明 |
|---|---|
azimuth、elevation | 朝向角。两者均为 0 时光束朝向 −Z 方向,仰角为正时向下倾斜 |
range | 0.1 – 20 场景单位 |
angle | 光锥半角,1 – 89°,默认 30 |
penumbra | 光锥边缘虚化过渡,0 – 1,默认 0.3 |
- 光照强度范围 0 – 20,与点光源一致。
- 聚光灯可照亮 PBR 与 MToon 材质,支持配置阴影品质等级与柔化半径,并可参与体积光照渲染。面光源与聚光灯的新建与类型切换仅在具备对应能力的版本中可用。
shadowFilter 可为每盏平行光、点光源或聚光灯单独选择 pcf(默认)或 pcss,两种算法可在同一场景中混用。是否可用须依据 light-shadow-filter 能力判断;即便在不支持的构建上,本地新建的灯光对象也可能携带 shadowFilter 字段。加载旧版场景时默认使用 PCF。
| 字段 | 说明 |
|---|---|
shadowQuality | 阴影贴图分辨率;off 表示关闭阴影投射 |
shadowRadius | PCF 模式的边缘柔化范围(阴影贴图纹素)。PCSS 不会覆写已保存的值 |
shadowSourceSize | PCSS 模式使用的光源物理尺寸:PCSS 会搜索场景遮挡物,距离遮挡物越远,半影越宽。平行光以角度计量,点光源与聚光灯以米计量;0 – 10,默认 0.1,设为 0 时表现为硬阴影 |
followCamera 让灯光跟随相机移动,需要 light-camera-follow 能力,环境光会忽略此设置。该属性默认关闭(false);开启时,灯光的空间坐标与朝向相对于相机实时计算,随相机的交互移动及镜头轨迹动画同步平移旋转。
followCameraOptions 用于选择跟随哪些变换分量,各项默认均为 true:
| 字段 | 说明 |
|---|---|
position | 跟随相机的注视目标与平移 |
rotation | 跟随相机的世界空间旋转(包含滚转) |
distance | 跟随带符号的环绕距离 |
- 单纯修改
fov视场角不会让灯光发生位移。 - 未启用的分量会冻结在
followCameraReference中的定格值(包含targetX、targetY、targetZ、distance以及世界空间旋转四元数);缺少参考值时,按原点、单位旋转与零距离处理。
scene.setLightFollowCamera { lightId, followCamera, options? } 可切换当前场景中指定灯光的跟随状态或合并更新 options,同时保持灯光的世界空间位置与朝向不变。它与 followCamera 一样,须依据 light-camera-follow 能力判断是否可用。
- 桌面端会根据当前视口中的相机变换(包含正在播放的相机轨迹)反算灯光坐标,并返回换算后的
{ light }(灯光已被删除时返回light: null)。 scene.patch与场景加载则直接按写入的原始数值生效,不做换算。
SceneLight.volumetric 用于为单个点光源、聚光灯或面光源开启体积光(受光照亮的雾气效果),默认处于关闭状态(false),其他类型灯光将忽略该配置。旧版本构建不包含此字段,而是采用全局统一的场景级开关;加载使用全局开关保存的历史场景时,所有支持雾气的灯光均会自动启用 volumetric。
SceneEnvironment 新增了 volumetricLighting 与 clusteredLighting 两个可选配置项。旧版本构建不包含这些属性,提供相应控件前应预先检查字段是否存在。
volumetricLighting 决定全场景雾气的外观表现,其自身不设全局开关;仅当场景中至少存在一盏开启了雾气效果的活跃光源时,体积雾才会渲染生效。当前版本会返回完整的雾气参数配置,可通过 scene.patch 更新:
volumetricLighting 属性 | 取值范围 | 默认值 |
|---|---|---|
density | 0 – 10 | 1 |
intensity | 0 – 10 | 1 |
range | 距相机 1 – 100 场景单位 | 20 |
quality | low、medium、high | medium |
speed | 0 – 5;设为 0 时雾气动画静止 | 0.2 |
体积雾围绕开启了雾气的光源产生散射,受深度遮挡,未受照亮区域保持完全透明;只要场景中存在任意一盏开启了雾气的活跃光源,3D 物体与环境模型内置的点光源、聚光灯和面光源亦会共同激发散射。
体积雾要求使用透视相机:在正交投影下配置参数予以保留,但不进行体积雾渲染。平行光与环境光不参与体积雾计算,Live2D 图层亦不产生遮挡。
clusteredLighting: true 用于在 WebGPU 透视相机管线下,为 1 – 64 盏具备有效照射范围且不投射阴影的点光源提供分簇光照着色加速,默认关闭(false)。若点光源未设有效照射范围、光源数量超出上限,或运行在不支持的渲染器/相机投影下,系统将自动回退至常规光照管线。分簇着色不会降低阴影渲染开销,亦不影响体积光照的采样光源。
在支持 environment-map-model 能力的构建中,SceneEnvironment 可同时包含 iblAssetId 与 modelAssetId:
bakeFromModel决定是否从 3D 环境模型生成环境光照探针,并将环境贴图作为输入;设为false时直接采用环境贴图照明,若无贴图则回退至模型内置天空。showSkybox仅控制背景渲染:无论由何种方式提供环境照明,背景始终渲染贴图或模型天空。- 清除其中一项资源将完整保留另一项,可通过 SDK 的
environmentClearPatch()生成对应的补丁对象。旧版构建同一时刻仅允许设置一项环境资源,设置新资源时须显式清空另一项。
此外,可通过 scene.patch 配置全景环境贴图的以下三个可选属性。这些属性仅在支持的构建中存在,应先确认字段可用后再展示对应控件:
| 字段 | 说明 |
|---|---|
skyboxBlur | 0 – 1,默认 0。仅作用于可见的天空盒背景 |
skyboxIntensity | 0 – 2,默认 1。仅作用于可见的天空盒背景 |
iblRotation | 弧度,默认 0,支持超出整周范围。使全景贴图及其环境照明一体旋转,基于模型生成光照的天空亦同步旋转 |
物理模拟
SceneEnvironment.physics 为场景的 物理模拟 全局开关:开启后 3D 物体将受到重力作用坠落至舞台地面,并与 VRM 虚拟形象产生碰撞接触。该字段默认为 false,旧版本构建不包含该属性。物理引擎演算生成的动态姿态不会写入场景文件,通过 API 读取的物体坐标始终为初始摆放数值;关闭 physics 后,所有物体将立即重置回初始坐标。
stage.spawn 将已注册的 prop 道具素材批量生成为受物理驱动的动态物体,投放至舞台中。需要 stage-spawn 能力;成功时返回 { spawned, alive },其中 alive 为舞台上所有物理物体的当前存活总数。
这些物理物体仅存在于渲染器内存中:不创建独立场景条目,不占用图层列表,不可撤销,也不随场景保存。同一素材的所有物理副本共享几何体网格、纹理与合批绘制调用,即便有数百个实例依然具备高性能。当前场景未开启 physics 时,调用返回 invalid-state 错误;素材未注册时返回 not-found,素材不是 prop 类型时返回 invalid-params。
| 字段 | 说明 |
|---|---|
assetId | 已在注册表中登记的 prop 道具素材 ID |
count | 生成数量,范围 1 – 200,默认 1。舞台物理物体总数上限为 500,超出时将优先销毁最早生成的实例 |
origin | 生成中心点坐标 { x, y, z }(米),默认为 { x: 0, y: 3, z: 0 }(位于虚拟形象头顶上方) |
spread | 散布立方体边长(米),范围 0 – 20,默认 1 |
velocity | 所有物体共享的初始线速度 { x, y, z }(米/秒),各轴范围 ±50,默认静止 |
scale | 缩放比例,范围 0.01 – 100,默认 1 |
ttlMs | 物体存活寿命(毫秒),范围 0 – 600000,默认 30000。设为 0 表示持续存在直至被手动清除 |
transition | { style, inMs, outMs }:为此批物体单独指定的 显示与隐藏 过渡样式,出现与消失时长各 0 – 5000 毫秒;省略字段沿用当前场景环境配置 |
超出有效范围的参数值将被自动截断修正至边界值。物理物体将在 ttlMs 超时、切换场景或关闭全局 physics 开关时自动销毁;亦可调用 stage.clearSpawned {} 主动清空,该调用返回 { cleared },并会取消尚未完成素材加载的生成任务。
场景转场
调用 scene.activate 将等待目标场景资源完全载入并接管舞台渲染(加载期间原场景保持正常运行并支持实时编辑),但不会阻塞等待转场动画完全结束。若在转场过程中发起新的场景切换请求,后发请求将覆盖抢占前序任务,因此响应返回的 activeSceneId 代表实际最终生效的场景。SDK 默认为场景切换操作预留 120 秒超时时间,配置了 requestTimeoutMs 时以配置值为准。
支持 scene-transitions 能力的构建会在 Scene.transition 中包含各场景配置的 场景转场 参数(即进入该场景时播放的视觉过渡)。调用 scene.patch { transition } 可整组替换转场配置,但不会立即触发播放:
| 字段 | 说明 |
|---|---|
type | 转场类型:cut、fade、wipe、circle、image 或 video |
durationMs | 过渡持续时间,范围 100 – 10000 毫秒 |
color | 淡入、擦除或圆形遮罩的过渡颜色(十六进制颜色值) |
assetId | 已注册的图片或视频素材 ID,设为 null 表示不使用媒体资源 |
switchPoint | 视频转场中的画面切换切入点,范围 0.05 – 0.95。应选取视频中画面完全覆盖舞台的关键帧 |
autoFade | 是否在视频两端自动叠加淡入淡出过渡,默认关闭 |
fadeInMs / fadeOutMs | 淡入与淡出时长,各为 0 – 10000 毫秒,默认 300,分别以切换点之前和之后的时长为上限;0 表示禁用对应淡变 |
无论何种场景切换途径,均统一执行目标场景中定义的转场效果。除无过渡的直接硬切(cut)外,所有转场均会立即启动并在后台资源加载完成前持续遮蔽舞台,若目标场景加载耗时较长,遮罩将自动延长超越 durationMs。视频素材转场全程静音播放,播放速率根据时长自动缩放适配,等待场景就绪期间画面将自动定格在 switchPoint 对应的帧上。
场景预设
支持 scene-presets 能力的构建会在 Scene.presets 中按显示顺序列出该场景已保存的 场景预设,每项为 { id, name, transition, items }。旧版本主机不包含 presets 字段。
items以实例 ID 为键,值为{ visible, place }。- Live2D 模型与 2D 物体的
place为{ space: '2d', x, y, scale, rotation },其余为{ space: '3d', x, y, z, rotX, rotY, rotZ, scale }。不透明度不属于预设。 - 保存预设后新添加的图层没有对应条目,应用预设时保持原状。
preset.* 方法均作用于当前活动场景:
| 方法 | 请求 | 说明 |
|---|---|---|
preset.create | { name?, transition? } | 将当前布局保存为新预设并追加至列表末尾;名称默认按应用界面语言依序生成(如「预设 1」),转场默认为 glide |
preset.update | { presetId } | 以当前布局重新保存指定预设 |
preset.rename | { presetId, name } | 重命名预设 |
preset.setTransition | { presetId, transition } | 修改预设的转场方式 |
preset.delete | { presetId } | 删除预设,图层保持原位 |
preset.apply | { presetId } | 将舞台移至该预设布局;过渡一开始即返回,不等待图层到位 |
create、update、rename 与 setTransition 返回 { preset },delete 与 apply 返回 {}。
transition 决定舞台如何移至预设布局,图层的显隐变化同样遵循该方式:
| 取值 | 说明 |
|---|---|
glide | 移动的图层平滑滑入目标位置 |
item | 所有发生变化的图层先按场景的 itemTransition 退场,再在新位置重新登场 |
cut | 全部瞬间就位 |
- 在过渡进行中保存,记录的是图层即将停驻的位置;对舞台正在前往的预设再次调用
apply不会产生变化。 - 当前场景中不存在的预设 ID 返回
not-found;预设 ID 仅在单个场景内唯一,复制场景会保留原有 ID。 - 桌面端的编辑与应用均计为场景撤销步骤,每次变更都会通过
scene.changed推送。 - 键盘、手柄与 Stream Deck 通过包含应用预设操作的自动化(或 Stream Deck 的应用预设按键)触发预设。
背景透明度
支持 background-alpha 能力的构建允许 SceneBackground.color 携带 Alpha 字节(#rrggbbaa)。透明舞台即 Alpha 为 00 的 color 背景,不再是独立的背景模式(详见 舞台背景)。主机仍接受旧版 transparent 模式(LEGACY_TRANSPARENT_BACKGROUND),并将其存储为同一颜色的零 Alpha 版本。
未声明该能力的旧版主机仍使用 transparent 模式,并会将带 Alpha 的颜色修正为默认颜色。SDK 客户端会自动适配此类主机:
- 将其返回的
transparent读取为零 Alpha 颜色。 - 发送
scene.patch时,把 Alpha 为00的color背景转换为transparent。 - 去除其余背景颜色的 Alpha 字节。
显示与隐藏
SceneEnvironment.itemTransition { style, durationMs } 用于配置场景内图层的 显示与隐藏 过渡规则:定义模型、物体及生成道具在登场与退场时的动画表现。旧版本构建不包含该属性。style 可选:
| 取值 | 说明 |
|---|---|
glitch | 带撕裂与灼烧的故障抖动溶解(默认) |
fade | 整层单通道平滑淡入淡出,兼容旧版 dither |
pop | 缩放弹性弹出与缩回 |
cut | 瞬时切换 |
durationMs 范围为 0 – 5000 毫秒,默认 300。当样式为 cut 或 durationMs 设为 0 时,图层将瞬时出现或消失。可通过 scene.patch 更新环境配置。
图层特效
支持 layer-effects 能力的构建允许为单个模型或物体挂载专属的 画面特效,在图层并入全场景合成前先行渲染。每个场景条目均具备独立的 effects 与 effectLayers 结构,与全场景特效规范完全一致,可通过 instance.setEffects { instanceId, effects, effectLayers? } 进行编辑:
effects接受color、levels、colorWheels、colorShift、selectColors、gradient、blur、bloom、diffusion、sketch、rim、outline与dropShadow的局部参数配置,未声明项保留原值- 传入
effectLayers时将完整覆盖已添加的特效层级列表;处于启用状态的特效始终包含在列表中
接口响应将返回校正后的完整配置:超出范围的数值将被限制在边界内,未知字段将被自动过滤丢弃。若传入参数存在格式错误,整个调用将在任何修改应用前失败退出。
泛光(bloom)的光照强度遵循 Warudo 的 Camera Bloom(Beautify 规格):
| 字段 | 取值范围 | 默认值 | 说明 |
|---|---|---|---|
intensity | 0 – 10 | 0.1 | 纯增益,0 为不添加辉光 |
threshold | 0 – 5 | 0.75 | Gamma 空间每通道截断,计算中平方映射至线性光,最高截断至 1000 |
radius | 0 – 6 | 3 | 基于 1080p 标准画面高度缩放 |
边缘光(rim)采用类似 VTube Studio 的背光算法:白色轮廓截断为纯白,并自然衰减融入主体固有色。它不包含 blendMode 属性(旧版传入将被丢弃),默认颜色为 #ffeb74,默认大小为 0.5。
轮廓(outline)接受归一化的 size、color、opacity、quality(low、medium、high)以及 roundness:归一化的圆角平滑半径,用于填充狭窄缝隙并平滑转角,设为 0 时严格贴合剪影原貌。
素描特效(sketch)基于 Jaume Sanchez 的 NPR 素描着色器,可作为全场景特效(environment.effects.sketch)或图层特效使用:
| 字段 | 取值范围 | 说明 |
|---|---|---|
paperColor | — | 纸张底色 |
lines | 0 – 2 | 线稿强度 |
lineWidth | 0.5 – 4 | 线宽(像素) |
shading | 0 – 2 | 明暗排线 |
softness | 0 – 1 | 柔和度 |
saturation | 0 – 1 | 色彩饱和度 |
opacity | 0 – 1 | 不透明度 |
- 全场景下
paperBackground: true会用纸张底色填充透明背景;图层级则始终保留源图层透明通道。 - 较旧版本的主机返回的特效集合中不包含
sketch。
鱼眼特效(fisheye)仅可作为全场景特效使用(environment.effects.fisheye):画面按鱼眼镜头的成像从中心向外鼓起。strength(0 – 1,默认 0.5)控制弯曲程度,1 相当于画面对角线 150° 的鱼眼。四角保持不动,因此画面始终铺满,边缘中段会被裁切。较旧版本的主机返回的特效集合中不包含 fisheye。
图层特效支持作用于虚拟形象模型及位于 2D 或 3D 空间的物体。2D 空间中的图像、视频、网页与文本需主机声明 layer-effects-2d 能力,其特效在该物体于图层栈中的位置合成(无论是否钉住),并随物体不透明度一同淡变;旧版本主机针对 2D 空间物体调用将返回 unsupported-for-format 错误,但会保留已保存的特效配置。切换物体空间时,已保存的特效配置同样予以保留。
捕捉源
Persona 支持并发运行多个已配置的动作与面部捕捉源。settings.tracking.sources 列出当前所有捕捉源,可通过 tracking.addSource、tracking.updateSource 与 tracking.removeSource 进行管理。
instance.setTrackingSources 支持按捕捉源 ID 将实例的面部、姿态与手部通道(faceSourceId、poseSourceId、handSourceId)分别路由至指定源。若将某个通道配置为 null 或传入不存在的 ID,将停止该通道的动作驱动。新创建的实例默认绑定各通道的系统全局默认源;单个捕捉源可并发驱动多个舞台实例。
instance.setTrackingSources 还支持配置 handTrackingMode:arms 模式下捕捉的手部将同时联动驱动 VRM 的手臂、手腕与手指关节;fingers 模式下仅驱动手指关节点,手臂姿态交由 VMC 或 mocopi 等身体姿态源控制。
面部与姿态捕捉源支持以下类型:
| 类型 | 通道 | 默认端口 |
|---|---|---|
persona-ios | 面部 | 19700 |
ifacialmocap | 面部 | 49983 |
vts-ios | 面部 | 由协议底层规范固定 |
vmc | 姿态 | 39539 |
mocopi | 姿态 | 12351 |
- 面部捕捉源可通过可选的
phoneIp绑定指定的发送设备。 - 添加源时省略
port,将从该类型的默认端口起自动选用首个空闲端口。 - 若端口已被其他进程或捕捉源占用,配置请求将被拒绝;同类
ifacialmocap或同类persona-ios实例间支持共享同一底层套接字。 - 已废弃的
vts-ios-native会在协议层直接被拒绝。
mediapipe 为内置的 摄像头捕捉源,全局单例运行,无需配置 port 或 phoneIp。其配置对象包含:
| 字段 | 说明 |
|---|---|
face、hands、body | 独立开启面部、手部与身体三项任务,分别对应三个输出通道 |
deviceId | 摄像头;空字符串 '' 表示系统默认摄像头 |
mirror | 画面镜像 |
delegate | 计算后端,CPU 或 GPU |
默认配置为镜像开启、基于 CPU 运行,开启面部与手部跟踪并关闭身体跟踪。tracking.addSource 与 tracking.updateSource 接受局部选项配置,未声明的参数保持原有状态。捕捉到的手部姿态数据亦会同步驱动 参数注入 规范中声明的手部输入项。
tracking.status 返回网络面部源与姿态源的汇总运行状态,并在 sources 映射表中提供每个已配置捕捉源(包含摄像头)的独立状态对象;tracking.status 事件具有相同的数据结构,当任一独立捕捉源的状态发生变动时均会触发通知。
旧版单源控制方法依然有效,默认作用于对应通道的第一个网络捕捉源:
tracking.setSource切换其类型。pose.setSource切换其协议(尚无该捕捉源时自动创建),并返回分配的端口。pose.setPort用于修改该端口。tracking.setEnabled与pose.setEnabled为网络面部与姿态源的全局总开关。
摄像头捕捉源仅遵从自身的 enabled 状态,可通过 tracking.updateSource 配置;停用期间,其任务开关与模型通道绑定关系完整保留。摄像头推理依赖桌面端的摄像头追踪附加组件,API 不提供附加组件下载方法;桌面端尚未安装该附加组件时,mediapipe 源状态保持为 waiting。
麦克风口型同步
口型同步 利用桌面主机的音频输入设备驱动模型嘴型。音频输入设备列表与音频采集都在运行 Persona 的桌面主机本地完成。原始音频与校准系数只保留在桌面端,既不经过 API 传输,也不会出现在公开设置中。音频分析演算输出的数据亦会同步驱动 参数注入 中列出的音频输入项。
| 方法 | 说明 |
|---|---|
lipSync.state | 获取当前配置、采集状态(off、starting、listening 或 error)、桌面端输入设备列表、实时音量与元音特征采样,以及正在进行的校准会话状态 |
lipSync.configure | 合并更新局部配置项(enabled、deviceId、gain 增益 0 – 30 dB、noiseGate 噪声门 −60 – 0 dBFS、smoothing 平滑度 0 – 0.3 秒),并返回保存后的完整配置 |
lipSync.restart | 在下一帧重启音频采集管线。该调用不会重新激活已关闭的麦克风,亦不会阻塞等待采集启动,应通过轮询 lipSync.state 确认状态 |
lipSync.calibrate | 推进执行一步校准流程并返回最新状态 |
上述配置亦映射至 settings.lipSync,可通过 settings.patch 直接修改。
校准流程使用桌面端当前选定的麦克风,并与桌面控制面板保持状态同步,分为以下步骤:
| 步骤 | 说明 |
|---|---|
start | 开启校准草稿 |
record | 针对特定音素 phoneme 录制 2 秒样本:A、I、U、E、O,或代表环境底噪的 S |
preview | 六个特征录制完成后应用预览 |
save / cancel | 保存生效或放弃更改 |
reset | 使当前麦克风恢复内置默认校准曲线 |
录制指令发起后会立即返回,进度状态应轮询 lipSync.state:返回结果中的 calibration 将报告当前阶段 phase(ready、recording 或 verifying)、正在录制的音素及已完成的音素列表。在不匹配的阶段调用对应步骤将返回 invalid-state 错误。
instance.setLipSync { instanceId?, mode } 用于配置麦克风是否驱动指定模型:always(始终驱动,默认)、when-untracked(仅在面部捕捉丢失时介入)或 off(关闭)。对非模型物体调用将返回 unsupported-for-format 错误。
语音驱动
speech.play 可播放指定音频流,并基于音频能量实时驱动模型口型。该方法仅适用于能力表声明包含 speech 的模型实例,目前支持所有已加载的 Live2D 模型。可用性判断始终基于实例运行时的动态能力声明,而非格式静态推断(如 0.53 及更早版本在旧版 WebGL 渲染管线下不声明该能力)。
| 参数 | 说明 |
|---|---|
url | 音频源地址:支持 https:、http:(本地 TTS 桥接接口)或内联的 data:audio/* 数据 |
volume | 播放音量,可选参数,取值范围 0..1 |
instanceId | 目标实例 ID,可选参数,省略时作用于当前场景的主模型 |
单个模型实例同一时刻仅能播放一段语音,后发调用的语音将自动抢占中断当前播放。调用成功返回即表示音频流已开始解码播放,若无法启动则返回 invalid-state 错误。播放生命周期由 speech.started 与 speech.ended 事件完整包围;亦可调用 speech.stop 提前终止播放。
虚拟形象快捷键
模型自带的 快捷键 由以下三个方法进行读写控制,均支持可选的 modelId 参数,省略时作用于当前场景的主模型:
| 方法 | 说明 |
|---|---|
hotkey.list | 列出指定模型的所有已配置快捷键 |
hotkey.set | 覆写保存整组快捷键配置,服务端进行宽容校验修正 |
hotkey.trigger | 根据指定 ID 模拟触发一条快捷键动作 |
舞台上所有模型均各自维护一套生效的快捷键配置,无论其是否为主模型,亦无论其为 Live2D 还是 VRM 格式:当按下某个全局组合键时,所有绑定了该热键的模型将各自触发对应的动作并在各自模型上生效。若 hotkey.trigger 指向的模型不在当前舞台上,系统将直接忽略该调用,不抛出异常。
Hotkey 配置对象包含四个继承自 VTube Studio 规范的可选属性:
| 字段 | 说明 |
|---|---|
hold | 仅在物理按键按住期间保持表情生效 |
fadeSeconds | 表情或动作的淡入淡出时长,0 – 2 秒;null 表示沿用文件自身的设定。表情属于启用的 表情组 时,以成员的淡入淡出时长为准 |
deactivateAfterSeconds | 表情自动退出的超时时长,针对 Live2D 动作表示最大播放时长,0.1 – 3600 秒;null 表示不自动退出 |
stopsOnLastFrame | Live2D 动作播放至最后一帧时定格保持,直至快捷键再次触发 |
较旧版本的主机不返回这些字段;若在 hotkey.set 中省略某项配置,系统将保留其已有数值,防止旧客户端覆写抹除高级配置。
由于 hotkey.trigger 是单次事件调用、不存在按键松开动作,对于标记为 hold 的快捷键,通过该接口触发将作为状态翻转开关(Toggle)处理。通过 hold 或 deactivateAfterSeconds 临时激活的表情状态,无论通过何种途径触发,均不会随模型状态保存。
Hotkey.accelerator 由最多三个以 + 连接的标记组成,按同时按住的集合触发:修饰键(MODIFIER_TOKENS:Control、Alt、Shift、Super)、Electron 命名的按键、鼠标按键 LeftMouseButton、RightMouseButton 与 MiddleMouseButton,或同一手柄的 Controller* 按钮。由于顺序不影响匹配,比较两个组合时请使用 SDK 的 comboKey,而非直接比较字符串;在界面上展示按键时,可使用 acceleratorLabel(accelerator, app.platform) 按 hello 上报的桌面端平台生成对应的键帽标签数组。
HotkeyState.registered 列出当前在 Persona 处于后台时仍会响应的快捷键:桌面端通过读取按键状态而非向系统注册全局热键来监听快捷键,因此任何开启 global 的组合键(包括单个按键)都会列入。旧版主机仅列出其向系统注册的含 Control、Alt 或 Super 的组合键。
自动化
支持 automations 能力的构建支持查询并远程触发应用中的 自动化工作流,即由热键、系统事件或 API 请求联动触发的一组舞台动作序列;具备 automation-editing 与 automation-transport 能力时,还可读写完整的时间线定义并控制时间线回放。
| 方法 | 说明 |
|---|---|
automation.list | 查询所有已配置的自动化摘要列表 |
automation.run { automationId } | 根据指定 ID 触发执行一条已启用的自动化规则 |
automation.get { automationId } | 返回完整定义 { automation }(AppAutomation,依赖 automation-editing 能力) |
automation.create { automation } | 创建自动化并返回 { automation }(依赖 automation-editing 能力) |
automation.update { automationId, automation } | 替换自动化的时间线与触发器定义并返回 { automation }(依赖 automation-editing 能力) |
automation.delete { automationId } | 删除指定自动化(依赖 automation-editing 能力) |
automation.control { automationId, command, positionMs? } | 控制时间线传输(play、pause、stop、seek、prepare),返回 { run }(依赖 automation-transport 能力) |
automation.status { automationId } | 查询时间线当前运行与各步骤状态 { run }(依赖 automation-transport 能力) |
automation.list 返回轻量摘要字段:id、title、accelerator、registered(当前在 Persona 处于后台时是否仍会响应;旧版主机表示是否已向系统注册)、enabled,以及 actionKinds 和 triggerKinds 两个动作与触发器类型数组,足以支撑控制台渲染操作面板,而无需读取完整时间线。
若 title 为 null,可根据 actionKinds 拼接语义化显示标签(SDK 内置的 automationLabel 工具函数即为此设计)。actionSceneIds 数组与 actionKinds 保持索引对应,记录每个 scene-switch 动作的目标场景 ID(其他类型动作对应位置为 null),以便展示目标场景名称。
每条自动化均为一条时间线序列,actionKinds 数组的顺序不代表实际执行的时间顺序。动作种类采用类别优先命名:
| 类别 | 动作种类 |
|---|---|
| 前置准备(在时间线启动前执行) | scene-switch 与 model-load(对应 AUTOMATION_SETUP_KINDS 与 isAutomationSetup 常量) |
| 临时画面效果 | effect-clip、effect-toggle 与 effect-params |
| 图层显隐与预设 | layer-visibility 与 preset-apply(将当前场景移至其某个预设;场景中不存在该预设时跳过) |
| 歌词字幕与文字 | lyrics-play(在文字图层上按时间播放 .lrc 歌词文件)与 text-set |
| 镜头控制 | camera-pose、camera-reset、camera-motion-play、camera-motion-stop、camera-follow、camera-aim、camera-focus 与 camera-handheld |
| 音频播放控制 | audio-play 与 audio-control |
| 虚拟形象与推流模式 | expression-toggle、motion-play、expression-clear、model-load、model-position 与 stream-mode |
delay动作已废弃移除,时间线上的空白间隙即代表延时等待。- 音频播放不开放独立 API:音频文件解码、回放控制与输出设备管理均运行在桌面本地,外部客户端若需播放音频,应触发或播放包含
audio-play的自动化规则。 - 旧版主机发送的旧动作命名(定义于
LEGACY_AUTOMATION_ACTION_KINDS,涵盖actionKinds与Hotkey.action)在 SDK 客户端接收时会自动归一化映射;亦可通过canonicalActionKind工具函数转换。 triggerKinds列出该规则在热键之外支持的事件触发器类型,目前涵盖scene、model-loaded、motion、face-tracking、microphone与parameter。
具备 automation-editing 能力时,automation.get 返回完整的 AppAutomation(包含 durationMs、autoDuration、带 id/startMs/durationMs/sourceInMs 的 actions、triggers、cooldownMs、accelerator、global 与 enabled):
automation.create与automation.update接受AutomationDefinition(由AutomationDefinitionSchema校验,字段或时间范围不合法时返回invalid-params)。- 新建的自动化默认处于关闭状态(
enabled: false),不绑定快捷键(accelerator: null、global: false),并由服务端重新分配所有 ID,在用户手动启用前不会自动触发。 automation.update会整体替换动作、触发器、时长与冷却时间并重新生成步骤 ID,同时保留已保存的快捷键accelerator、global与enabled开关。- 通过 API 创建、更新或删除自动化不支持撤销,并会清空桌面端时间线编辑器针对该自动化保留的撤销历史。
具备 automation-transport 能力时,automation.control 与 automation.status 可驱动并查询桌面端时间线回放(AutomationRunStatus:{ automationId, phase, positionMs, durationMs, error, steps },当前会话尚未运行、预览或预热过该自动化时 run 为 null):
play会播放完整时间线(即使enabled为false也会播放到底;处于暂停或拖动定位状态时从当前位置继续),pause暂停时间线,prepare预加载媒体与动画素材,seek将播放头移至positionMs并在舞台上实时预览 画面效果片段、镜头机位、图层可见性、设置文字 与 播放歌词,stop停止回放并释放预览状态。- 最近一次控制某条自动化传输的会话持有其传输所有权:若该客户端断开连接,处于暂停、预览或失败状态的运行会自动停止,使快捷键与事件触发器恢复响应;正在播放或预热的运行若随后进入暂停或失败状态,也会自动停止。
未绑定键盘、鼠标或手柄快捷键的自动化规则其 accelerator 字段为 null,仍可通过 automation.run 正常远程触发。处于禁用状态的规则其 enabled 为 false,将忽略所有触发(包含 automation.run,但仍可通过 automation.control 的 play 试播)。automation.run 发起后会立即返回确认,不阻塞等待时间线执行结束。当自动化列表、定义、启用状态或后台触发状态发生改变时,系统将通过 automation.state 事件推送完整的最新摘要列表。
actionKinds 与 triggerKinds 类型均为开放枚举:新版本应用可能会引入当前 SDK
尚未定义的全新动作类型。客户端应作为未知类型宽容处理,避免抛出解析错误;SDK
内置的 automationActionLabel 会将未知动作统一归类为通用展示文案。
应用设置
settings.get 与 settings.patch 用于读取和更新受限白名单内的应用全局设置(窗口置顶、托盘、性能参数、手柄开关等),而非底层原始配置库。
响应结果及 settings.changed 事件中附带只读的窗口尺寸信息:
window.stageSize: { width, height }:舞台视口当前的设备无关像素尺寸,随窗口拉伸实时刷新window.stageReferenceSize: { width, height }:用于校准舞台摆放单位与模型适配的基准尺寸。其高度决定缩放比例:未固定的ScreenPlacement单个 x/y 坐标单位在渲染时对应距离视口中心stageSize.height / stageReferenceSize.height个设备无关像素
渲染管线在任何宽高比下均会填满当前视口窗口。对于 2D 内容与透视 3D 视图,调整窗口宽度仅会在水平方向扩展或裁剪画面,不会重新缩放内容或产生黑边;正交 3D 视图保持其宽度为 abs(orbit.distance)。保存的摆放参数在窗口缩放与应用重启后保持不变;绘制摆放控件的客户端应以当前 stageSize 的宽高比为准。较旧版本的主机可能不返回上述尺寸字段,窗口在桌面上的物理屏幕位置始终对外保密。
性能设置包含 showFps、fpsLimit、effectsQuality 与 renderScale(旧版本可选)。手柄预设配置在设置中为只读属性,需通过专门的 controller.* 方法进行修改。响应结果与 settings.changed 事件中还包含只读的 ui.streamMode(推流模式),以便远程面板对敏感网页 URL 进行遮罩遮蔽(旧版本主机可能省略该字段)。
插件存储
storage.* 为外部插件提供持久化键值存储(KV Storage),以 API 密钥 为命名空间进行数据隔离。使用同一 API 密钥的所有会话共享该存储分区,吊销密钥将同步清空其对应的全部数据。存储的值支持任意合法的 JSON 序列化数据。
| 方法 | 说明 |
|---|---|
storage.get | 读取指定键对应的值。未曾写入过的键返回 value: null |
storage.set | 写入指定键值对 |
storage.delete | 删除指定键。若目标键本身不存在亦返回成功 |
storage.list | 列出当前密钥命名空间下的所有键名(已排序) |
存储配额限制为:单个键名最大 128 字符,单个值序列化后最大 64 KB,每个 API 密钥上限存储 256 个键。若调用 storage.set 超出最大键数配额,接口将返回 invalid-state 错误。
错误代码
当服务端返回错误帧时,persona.call 以携带 code(属于 API_ERROR_CODES)的 PersonaApiError 拒绝:
| 代码 | 说明 |
|---|---|
parse-error | 数据帧非合法的 JSON 文本 |
invalid-request | 请求信封协议封装格式不符合规范 |
unknown-method | 当前运行版本未实现或未开放该方法 |
invalid-params | 请求参数未通过 Schema 格式校验 |
not-found | 请求引用的目标对象 ID 不存在 |
unsupported-for-format | 目标实例格式不支持当前操作(例如对 Live2D 模型调用 MToon 接口) |
conflict | 目标参数租约已被其他活跃会话持有占用 |
renderer-unavailable | 舞台视口无响应(舞台窗口未创建、渲染管线正在重载、已崩溃或请求超时) |
forbidden-path | 请求访问的文件路径不在已授权的插件目录列表内、用户在桌面端拒绝了 asset.import 确认提示,或非本机回环客户端调用了 asset.import / registry.pluginFolders |
invalid-state | 当前系统状态不允许该操作(如尝试删除最后一个场景、存储配额超限、音频初始化失败或模型未开启版本历史) |
internal | 服务端未捕获的内部异常 |
上述错误代码为正式通信协议规范的一部分:客户端将自动丢弃携带未知错误代码的异常帧,因此新增错误代码仅随协议大版本一同发布,常规业务错误均映射至现有错误枚举中。
当客户端自身或底层传输层无法完成 connect() 或 call() 时,则会以携带 reason(属于 CLIENT_ERROR_REASONS)的 PersonaClientError 拒绝:
connect()可能遇到connect-timeout、connection-closed或client-closed(若url本身无法发起连接,例如格式非法,则直接以运行环境的原生异常如TypeError拒绝 Promise,不会同步抛出)。call()可能遇到not-connected、request-timeout、connection-closed或client-closed。
断开连接
SDK 客户端在遇到非预期的网络中断时会自动执行指数退避重连。以下 WebSocket 关闭码表示不可恢复的终止状态,将停止自动重连机制:
| 关闭码 | 常量 | 原因 |
|---|---|---|
4001 | CLOSE_KEY_REVOKED | 当前使用的 API 密钥已被吊销 |
4002 | CLOSE_FORCE_DISCONNECTED | 用户在控制面板中主动断开该会话 |
接收到上述关闭码后,客户端将最终转换至 closed 状态。若初始化时配置了 onClose 回调,终止事件将派发至该回调并跳过 onWarning;若未配置 onClose 则回退派发至 onWarning。标准关闭码 1001(Going Away)不在此列,它代表 Persona 服务端正在正常关闭或重启,客户端将保持重连重试。
吊销密钥将立即丢弃所有待发送的待定消息帧,并以 4001 关闭所有持有该密钥的活跃连接。正在等待舞台渲染管线响应的未决请求将被立即中断取消;已投递至舞台管线的渲染指令可能执行完毕,但其响应将被服务端直接丢弃。
协议版本演进
通信协议内置主版本号(Protocol Version),若客户端与服务端版本不匹配,SDK 将输出警告日志。订阅旧版本 Persona 不支持的事件不会导致致命错误:SDK 将自动回退至逐个独立订阅模式,保留可用的事件通道,并输出警告记录不受支持的事件列表。
当前协议主版本为 4。历史演进中从协议中精简与规范了部分接口,面向旧协议编写的插件需进行相应迁移适配:
| 协议版本 | 变更说明 |
|---|---|
| 2 | 移除 Scene.behavior(视线跟随光标)配置,场景数据模型与 scene.patch 接口中不再包含该属性 |
| 3 | 移除 stage.shockwave 方法,调用该方法将返回 unknown-method 错误 |
| 4 | 将 shortcut.list、shortcut.trigger 与 shortcut.state 重命名为 automation.list、automation.run 与 automation.state;shortcuts 应用能力重命名为 automations,事件与请求参数中统一采用 automationId 与 automations 字段 |
最后更新于 2026年11月4日