Kun Design Motion Agent 工具:让 AI 直接编辑画布时间轴的 `design_motion_*` 协议与实现解析
人工智能AI Agent自主智能体桌面应用MCP Clients【免费下载链接】KunLocal-first AI agent workspace for coding, writing, design, research, and automation — one runtime for desktop GUI and TUI.项目地址https://gitcode.com/gh_mirrors/de/Kun点击查看免费下载Kun 的 Design 画布在支持静态形状、HTML/SVG 构件与原型导航之后引入了 Figma 风格的 Motion 模式让设计师与 Kun Agent 共享同一条可检查、可寻址的规范化时间轴数据。本文围绕openspec/changes/add-design-motion-mode变更中的design-motion-agent-tools规范讲解 Kun 如何通过一组 Design-only 结构化工具design_motion_set_timeline、design_motion_upsert_keyframes、design_motion_apply_preset、design_motion_delete把时间轴编辑能力交给 Agent同时保证 Agent 生成的运动与手动编辑走同一条验证、持久化、撤销与预览链路。读完你将对工具广告条件、motionOps传输协议、渲染器端幂等执行与操作日志机制有完整认识。一、背景为什么需要Agent 可编辑的运动模式在加入 Motion 模式之前Design 画布已经能创建和排布静态原生形状、HTML 构件、SVG 构件与原型Prototype但缺少可复用的时间轴运动。已有的动画能力都各自为政、不可通用编辑独立 SVG 构件使用声明式 SMIL 动画Prototype 播放只是在 HTML 屏幕之间导航生成的 HTML 中可能含有不透明的 CSS 动画。这些路径都不是可编辑的时间轴模型。变更提案 明确指出新增 Motion 模式的动机正是给设计师和 Kun Agent 一个共享的、可检查的时间轴模型而不是依赖不透明的 CSS、SVG-only SMIL 或独立的视频工作流。关键约束来自 Kun 与渲染器的运行架构Kun 工具无法同步读取渲染器的 Zustand 状态。Kun 工具返回的是持久化、结构化的输出由渲染器回放并应用。因此 设计文档 定下原则运动信息的读取必须来自包含在轮次提示中的有界画布快照canvas snapshot运动信息的变更必须通过专用的、由渲染器应用的操作renderer-applied operations完成。这正是design_motion_*工具族存在的意义。二、工具广告规则只在 GUI Design 画布轮次出现design-motion-agent-tools规范的第一条需求是Kun 只在 GUI Design 画布轮次中广告一个结构化的design_motion工具。它要求当一个 Kun 轮次同时具备 GUI 画布与 Design 模式上下文时design_motion携带规范化的 property、easing、timing、target 与 preset schema 被广告当一个 Kun 轮次未附着在 GUI Design 画布上时design_motion不被广告。在源码中这一条件被实现为工具定义里的shouldAdvertise谓词见 kun/src/adapters/tool/design-motion-tool.tsconst SHOULD_ADVERTISE_DESIGN_MOTION_TOOL (context: { guiDesignCanvas?: boolean guiDesignMode?: boolean }) context.guiDesignCanvas true context.guiDesignMode true四个运动工具set_timeline、upsert_keyframes、apply_preset、delete全部使用该谓词并统一注册到运行时工具目录LocalToolHost.defineTool。这样即使 Model 在非 Design 画布轮次中想调用运动工具也无法从工具列表中拿到它们从机制上杜绝了越界使用。三、核心原则Agent 与手动编辑共享同一个事实来源规范的第二条需求强调Agent 编写的运动操作必须与 Motion 停靠面板的手动编辑走完全相同的验证、变更、持久化、撤销和预览路径绝不能生成第二份 CSS、GSAP 或纯 HTML 时间轴。设计文档 中的决策 1 给出了规范数据模型运动数据以CanvasMotionDocument形式存放在画布文档级别CanvasDocument.motion而非复制进每个形状type CanvasMotionDocument { version: 1 timelines: Recordstring, CanvasMotionTimeline } type CanvasMotionTimeline { id: string frameId: string durationMs: number playback: once | loop | ping-pong tracks: CanvasMotionTrack[] }实际类型定义在 src/renderer/src/design/motion/canvas-motion-types.ts 中CanvasMotionTrack包含稳定 ID、targetShapeId、受支持的属性x、y、rotation、scaleX、scaleY、opacity、操作set | offset | scale、数值基础值、可选 delay/span以及有序的类型化关键帧easing 是一个带标签的联合类型linear、ease-in、ease-out、ease-in-out、hold、cubic-bezier、spring。共享事实来源体现在渲染器执行端Agent 的工具块最终被转换为与手动编辑相同的不可变运动文档替换走同一套 undo/redo 与持久化逻辑详见下文第五节。3.1 场景应用 Agent 预设当一个design_motion操作把有效预设应用到当前快照中的 shape ID 时可编辑的规范轨道canonical tracks出现在 Motion 停靠面板中该变更作为一个操作批次被持久化。这意味着预设不是隐藏的运行时特效而是被编译成与手动创作完全一致的普通轨道。设计文档决策 5 明确了这一点Fade、Move、Scale、Rotate 预设创建与手动创作相同的轨道和关键帧多选时按画布绘制顺序paint order产生确定性错峰stagger重复应用预设会替换匹配的属性轨道而不是追加重复效果。3.2 场景upsert 一个关键帧当design_motion提供了有效的 timeline、target、property、时间戳、类型化数值与 easing 时渲染器创建或更新匹配的关键帧并预览出与手动编辑相同的结果。渲染器执行器中的applyUpsertKeyframes会以targetShapeId property定位轨道再以稳定 ID 或时间戳定位已有关键帧缺失则创建、存在则覆盖——这正是upsert语义。四、四个结构化工具全参考四个工具在 kun/src/adapters/tool/design-motion-tool.ts 中定义统一为toolKind: tool_call、policy: auto的本地工具。所有 schema 都带additionalProperties: false保证参数严格。4.1design_motion_set_timeline创建或更新帧时间轴参数类型约束说明frameIdstring1256 字符必填拥有该时间轴的帧 ID或 Design 快照中显示的稳定 canvas-root IDdurationMsnumber 0且 600_000可选时间轴总时长playbackenumonce/loop/ping-pong可选播放模式工具说明明确提醒Motion 是帧/图层动画它不创建 Prototype 导航、也不编辑独立 SVG 的内部动画。执行端要求durationMs与playback至少提供其一否则报错。4.2design_motion_upsert_keyframesupsert 属性轨道与关键帧参数类型约束说明frameIdstring必填所属帧targetShapeIdstring必填快照中的稳定原生形状 ID或整个构件/运行应用帧容器 IDpropertyenumx/y/rotation/scaleX/scaleY/opacity运动属性operationenumset/offset/scale可选求值结果与目标基础值的组合方式默认setbaseValuenumber[-1_000_000, 1_000_000]可选来自快照的观测基础值渲染器仍是权威delayMsnumber[0, 600_000]可选轨道在所属帧时间轴中的偏移spanMsnumber 0且 600_000可选轨道的时间跨度keyframesarray1256 项必填类型化关键帧数组每个关键帧对象为{ id?, timeMs, value, easing? }timeMs是轨道局部时间0600000msvalue是有限数值绝对值 ≤ 1,000,000easing支持全部七种类型。工具描述要求 Agent 使用快照中的稳定 ID并明确复用此工具编辑既有轨道而不是生成 CSS、GSAP、HTML 动画或 ShapeOps——这是单一事实来源原则在提示词层面的落实。4.3design_motion_apply_preset应用可编辑预设参数类型约束说明frameIdstring必填所属帧targetShapeIdsarray150 项唯一必填目标形状 IDpresetenumfade/move/scale/rotate预设类型directionenumin/out默认in预设是入场还是出场durationMs/delayMs/staggerMsnumber按上述时间约束时长、延迟与错峰distanceX/distanceYnumber有界数值Move 预设的位移量scaleFrom/scaleTonumber[-1000, 1000]Scale 预设起止值degreesnumber有界数值Rotate 预设角度easingobjecteasing 联合 schema预设缓动渲染器端把预设编译为普通轨道详见第五节多选目标按画布绘制顺序排序以产生确定性错峰。4.4design_motion_delete删除时间轴 / 轨道 / 关键帧参数类型说明kindenumtimeline/track/keyframe删除对象层级frameIdstring 必填所属帧trackIdstring 可选或提供targetShapeId property定位轨道targetShapeId/propertystring 可选轨道定位的另一方式keyframeIdstring 可选关键帧定位方式之一timeMsnumber 可选关键帧定位方式之二按时间戳工具说明强调删除已不存在的项是幂等的渲染器应用该操作时依然成功。这为 Agent 的先删再建流程提供了容错。五、motionOps传输协议与 ShapeOps 严格隔离设计文档决策 9 明确指出Kun 为运动新增专用的 Design-only 工具它们返回motionOps而不是现有的ops这样运动请求绝不会意外落入ShapeOpSchema。这一隔离在渲染器端有三层保障见 src/renderer/src/design/canvas/motion-ops/index.tsexport const DESIGN_MOTION_RENDERER_TOOL_NAMES new Set([ design_motion_set_timeline, design_motion_upsert_keyframes, design_motion_apply_preset, design_motion_delete ]) export function extractMotionOpsFromValue(value: unknown): unknown[] { if (!value || typeof value ! object || Array.isArray(value)) return [] const motionOps (value as { motionOps?: unknown }).motionOps return Array.isArray(motionOps) ? motionOps : [] }isDesignMotionRendererToolName只认四个专用工具名extractMotionOpsFromValue只从motionOps键提取操作ops键会被忽略渲染器的工具回放路径在通用形状处理之前把识别出的design_motion_*块分发到executeMotionOps。渲染器工具协议层的分发实现在 src/renderer/src/design/tool-protocol/motion-executor.ts它维护MOTION_PROTOCOL_OP_BY_TOOL映射set_timeline → set-timeline等把单个工具参数包装成{ op, ...args }形式的运动操作或直接透传motionOps数组。配套测试 src/renderer/src/design/canvas/motion-ops/motion-ops.test.ts 验证了这套隔离expect(isDesignMotionRendererToolName(design_motion_upsert_keyframes)).toBe(true) expect(isDesignMotionRendererToolName(design_update_shapes)).toBe(false) expect(extractMotionOpsFromValue({ motionOps: [{ op: delete }] })).toEqual([{ op: delete }]) expect(extractMotionOpsFromValue({ ops: [{ op: delete }] })).toEqual([])5.1 渲染器端 schema 校验渲染器用 Zod 对每个运动操作做严格校验见 src/renderer/src/design/canvas/motion-ops/schema.ts。它复用canvas-motion-types.ts的边界常量并对数值必须是有限数拒绝Infinity/NaN绝对值 ≤ 1,000,000时间戳在[0, 600_000]内easing 必须是七种类型之一cubic-bezier的x1/x2 ∈ [0,1]、y1/y2 ∈ [-10,10]spring的 mass/stiffness/damping/initialVelocity 各有上下界预设目标数 ≤ 50 且必须唯一每个操作块最多 64 个操作MAX_RENDERER_MOTION_OPS_PER_BATCH、参数序列化后最多 256 KiB、ID 最长 256 字符。测试用例覆盖了拒绝Number.POSITIVE_INFINITY关键帧值这类安全边界。六、渲染器执行验证、预算、幂等与操作日志执行核心在 src/renderer/src/design/canvas/motion-ops/executor.ts 的executeMotionOps。它完整落实了规范的第三条需求渲染器在应用 Agent 运动操作之前必须验证目标存在性、帧范围、受支持的属性、有限数值、时长边界、轨道限制与关键帧限制已应用或部分应用的批次必须产出带受影响 ID 与可行动错误信息的操作日志operation-journal结果。6.1 执行前校验与预算executeMotionOps依次检查批次上限motionOps必须是数组且 ≤ 64 项否则返回MOTION_BATCH_LIMIT空载荷完全没有motionOps时返回INVALID_MOTION_OP提示Motion tool output did not contain any motionOps而不是静默落入 ShapeOps 路径字节预算序列化后超过 256 KiB 直接拒绝schema 校验逐项MotionOpSchema.safeParse非法项以INVALID_MOTION_OP记录合法的进入执行队列。6.2 语义校验执行单个操作时executeOne帧校验validateFrameframeId必须存在且为 frame或画布根否则返回MOTION_FRAME_NOT_FOUND并附上当前可用 frame ID 列表作为建议目标校验validateTarget目标必须存在、不能是根形状并且其拥有帧必须与操作的frameId一致——拥有帧通过沿parentId向上遍历解析resolveOwningMotionFrameId而不是信任可能未随重挂载更新的反规范化frameId字段。目标不存在时返回MOTION_TARGET_NOT_FOUND并给出从当前快照中选择该帧内的目标的指导跨帧引用返回MOTION_FRAME_SCOPE预算校验ensureUpsertBudget合并后单轨道关键帧数 ≤ 256、总时间轴 ≤ 100、总轨道 ≤ 2,000、总关键帧 ≤ 20,000且delayMs spanMs取spanMs与关键帧最大时间戳的较大者不超过 600,000ms否则返回MOTION_LIMIT_EXCEEDED。这些边界常量定义在 src/renderer/src/design/motion/canvas-motion-types.ts常量值MAX_CANVAS_MOTION_TIMELINES100MAX_CANVAS_MOTION_TRACKS2,000MAX_CANVAS_MOTION_KEYFRAMES20,000MAX_CANVAS_MOTION_KEYFRAMES_PER_TRACK256MAX_CANVAS_MOTION_DURATION_MS600,000MAX_CANVAS_MOTION_ABSOLUTE_VALUE1,000,000MAX_CANVAS_MOTION_CUBIC_BEZIER_Y_ABS10springmass/stiffness/damping/initialVelocity0.0001~100/0.0001~10_000/≤1_000/≤1_000Kun 侧工具定义同步维护着同一套边界design-motion-tool.ts 中的DESIGN_MOTION_MAX_DURATION_MS、DESIGN_MOTION_MAX_KEYFRAMES_PER_CALL 256、DESIGN_MOTION_MAX_PRESET_TARGETS 50、DESIGN_MOTION_MAX_ARGUMENT_BYTES 256 * 1024、结构化参数节点上限 2,048、深度上限 16并在执行前通过validateStructuredArgumentBudget做参数预算拦截。6.3 语义化与幂等设计文档决策 9 定义了运动的语义化、幂等约定时间轴身份 frame ID手动轨道 frame target property关键帧按稳定 ID 或时间戳 upsert删除缺失项成功。在实现上applyUpsertKeyframes以targetShapeId property定位轨道按 ID 或时间戳定位关键帧executeOne中删除不存在的轨道/关键帧时返回幂等成功affectedIds仍包含帧 ID。一个工具块 一个 undo 组 一条 Canvas 操作日志条目。6.4 不可变文档替换与撤销成功应用任何操作后执行器把累积的运动文档通过useCanvasShapeStore.getState().setMotionDocument(motion, label, selectionBefore)一次性提交为不可变替换因此 undo/redo 与持久化观察到的变更与手动 Motion UI 完全一致决策 7CanvasChange增加可选{ before, after }运动补丁撤销/重做原子地同时应用形状与运动两部分并恢复选择。6.5 操作日志operation-journal执行器通过appendDesignOperationJournalEntry写入一条类型为update_motion的日志条目包含label工具块标签status全部成功为applied部分失败为partialaffectedIds受影响的目标 IDoperations每个包括被拒绝但 schema 合法操作都会记录payload携带rendererReplayKey。测试中可以看到完整断言expect(state.document.operationJournal?.[0]).toMatchObject({ label: tool:motion-1, status: applied, affectedIds: [hero], operations: [{ type: update_motion, targetIds: [frame_home, hero] }] })6.6 回放防护SSE 重放与重挂载不产生重复变更规范的场景成功的 Agent 编辑被重放要求当同一个持久化工具块通过 SSE 重放或渲染器重挂载再次出现时现有画布回放防护必须阻止重复的运动变更与重复日志条目。executeMotionOps的入口首先调用journalForReplayKey若日志中已存在携带相同rendererReplayKey的update_motion操作则直接返回重放结果replayed: true不再执行任何变更——这依赖 Kun 侧持久化 ToolBlock 的 replay key 与渲染器日志条目一一对应从机制上杜绝了Agent 输出在重放时重复叠加效果的风险。七、运动上下文后续轮次如何续编既有动画规范的第四条需求要求Design 轮次提示必须包含有界bounded的活动运动时间轴摘要让 Agent 能够按稳定的 frame、shape、track、keyframe ID 编辑既有运动而不是盲目重建时间轴。实现位于 src/renderer/src/design/canvas/canvas-motion-summary.tsbuildCanvasMotionSummary把完整的运动文档压缩为有界摘要绝不倾倒无界的规范数据摘要上限最多 12 个时间轴、48 条轨道、192 个关键帧、每轨道 12 个关键帧CANVAS_MOTION_SUMMARY_MAX_*常量摘要包含时间轴 ID、frame ID/名称、时长、播放模式、轨道数/关键帧数以及每条轨道的trackId、targetShapeId、targetName、property、operation、baseValue、delay、关键帧数量与逐关键帧的 ID/时间/值/easing超出上限的部分以omittedTimelines/omittedTracks/omittedKeyframes计数呈现摘要还内嵌 reduced-motion 指引自动播放按需禁用、编辑可用、拖动/末态检查确定性。该摘要被接入两条链路画布快照snapshotCanvas在 src/renderer/src/design/canvas/canvas-snapshot.ts 中调用buildCanvasMotionSummary(doc, { preferredFrameId: startId })把有界motion摘要放进快照随轮次提示交给 Agent设计交接/资源面design-project-contract.ts与design-resource-surface.ts同样调用buildCanvasMotionSummary生成交接摘要供下游 Agent 与实现工作流使用。Kun 侧提示词在 kun/src/loop/design-mode.ts 的DESIGN_MODE_INSTRUCTION中明确指引 AgentFRAME/LAYER MOTION当用户要求让既有 Design 画布图层或整个 HTML/运行应用/SVG 帧容器随时间运动时使用被广告的design_motion_*工具与snapshot.motion中的稳定 ID。Motion 编辑规范的按帧时间轴它不生成 CSS/GSAP、不编辑内部 SVG 动画、不创建导航。执行规则进一步要求复用快照中有界的 Motion 时间轴、轨道与关键帧 ID而不是盲目重建效果预设编译为可编辑轨道独立 SVG 的 SMIL 仍是独立内部动画来源。 这正是后续轮次通过稳定标识续编既有运动的落地。八、测试与验证体系任务清单 第 5 组Kun Motion Tools and Context全部完成包含工具定义注册、motionOps提取/回放分发/校验/执行/错误/undo 分组/日志、工具协议注册、快照摘要与提示词接入。验证方面motion-ops.test.ts 覆盖工具名识别、motionOps提取、schema 校验含拒绝非有限值、空载荷报错、时间轴配置持久化、关键帧批量应用与日志、预设保留既有 offset/easing 等场景canvas-motion-summary.test.ts 验证摘要上限与边界行为canvas-snapshot.test.ts 验证快照中的motion摘要结构。任务清单中唯一未完成项7.6 Electron Design-mode 冒烟流程属于 UI 端手动验证不影响工具协议本身的自动化测试覆盖。九、边界与安全设计小结design_motion_*工具族的安全设计可以总结为三层防线 一条隔离广告层仅在guiDesignCanvas guiDesignMode时暴露工具Kun 参数层结构化 schema、字节/节点/深度预算、ID 长度、数值与时间边界在工具执行前拦截渲染器执行层Zod schema、目标/帧/范围语义校验、文档级计数预算、不可变提交、操作日志与 replay key 幂等防护协议隔离motionOps与ops分离运动请求永不落入 ShapeOps 路径。这套设计确保 Agent 即使面对大型画布或错误的目标 ID也只能产生被拒绝 可行动建议或部分应用 日志记录的结果而不会污染规范数据或产生孤儿轨道。十、总结design-motion-agent-tools规范把Agent 可以编辑 Design 画布运动从概念落实为一套可运行、可验证的工程实现四个 Design-only 工具 motionOps传输协议 渲染器语义化幂等执行 有界快照摘要。它的核心价值在于Agent 与设计师操作的是同一条规范化时间轴数据任何一方创建的轨道、关键帧、预设与缓动都可以被另一方直接查看、编辑与继续创作——这正是单一事实来源在 AI 辅助设计场景下的完整落地。若需深入可继续阅读 变更设计文档含全部 12 项设计决策、运动模式 UI 规范以及渲染器运动核心目录 src/renderer/src/design/motion 与 motion-ops 协议目录。赞分享人工智能AI Agent自主智能体桌面应用MCP Clients【免费下载链接】KunLocal-first AI agent workspace for coding, writing, design, research, and automation — one runtime for desktop GUI and TUI.项目地址https://gitcode.com/gh_mirrors/de/Kun点击查看免费下载相关推荐Kun Design Motion 模式实现解析画布时间线动效的数据模型、播放引擎与 Agent 工具链Kun Design Motion 模式实现解析画布时间线动效的数据模型、播放引擎与 Agent 工具链 Kun 的 Design 模式此前只能创建和编排静态人工智能AI Agent自主智能体桌面应用MCP ClientsToonflow 画布操作工具toonflow/tool-canvas完全指南让 AI Agent 直接编排节点流程Toonflow 画布操作工具toonflow/tool canvas完全指南让 AI Agent 直接编排节点流程 本指南围绕 Toonflow 开源人工智能AI 应用AI AgentRAGAI 写作后端桌面应用React时间轴编辑器低代码可视化动画编排工具React时间轴编辑器低代码可视化动画编排工具 React时间轴编辑器是一款基于React生态的低代码可视化组件专注于快速构建时间轴动画编辑界面。通过直观的上一篇Kimi-K2-Thinking-MXFP4性能评测在AMD MI350/MI355上的推理速度提升与精度对比下一篇airi 依赖注入进阶用 VueUse injectLocal / provideLocal 在组件内读回自己提供的值创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考