--- title: 0.3.0 版本规划:元素类型扩展与遗留清障 --- # 0.3.0 版本规划:元素类型扩展与遗留清障 > 0.1.0 打通「模型 → AnimationSpec IR → MP4」全链路,0.2.0 把工作台「亮出来」(可视面板 + 视频预览 + 后台渲染 + 会话恢复)。 > 0.3.0 的主题是**元素类型扩展**:IR 目前只能表达 4 种图层(text / rect / circle / image),教学动画里最常见的箭头、坐标轴、分组、代码、公式都表达不了;同时清掉文档里依然挂账的遗留项(group 图层、编排收口、面板只读、素材导入)。 --- ## 1. 遗留问题盘点与处置 ### 1.1 README「已知限制与说明」逐条处置 | # | 已知限制 | 现状核实 | 0.3.0 处置 | | --- | --- | --- | --- | | 1 | 图层类型支持 `text / rect / circle / image`,`group` 预留未实现 | `codegen.ts` 里 `COMPONENT.group = null`,遇 group 图层整层跳过 | **实现,本版本主体之一**(见 §2 M0)。教学动画常需要「一组元素整体移动/缩放」,codegen 按 children 组合 Motion Canvas 节点即可;validate 同步放开引用校验 | | 2 | 旁白 / 字幕轨道预留未实现(TTS 与音画对齐) | IR 字段仍在,无任何消费方 | **继续推迟到 0.4**。TTS 依赖外部服务与授权,且音画对齐要改渲染管线的音频轨;0.3.0 的 audio 图层只做「背景音乐/音效」这类静态音轨(见 §2.5),不与旁白绑定 | | 3 | 工作台面板只读(0.2.0 M2 范围,P2 交互未做) | 卡片只展示状态与产物,「撤销这步 / 预览第 N 幕」按钮不存在 | **P1 评估实现**。按设计草案 §6 路径 2:按钮 → `agent.followup()` 生成结构化指令 → 模型回合执行(零新增机制,改动天然落事件流、可回放)。loopback RPC 直改 spec 继续留 0.4 | | 4 | `/dsh-anim/media` 放行规则(outputDir 内或回执精确路径 + 扩展名白名单) | 这是安全边界,工作正常 | 维持文档,无代码动作。新增 svg/audio 产物时扩展名白名单已覆盖(见 web.ts `MEDIA_TYPES`) | | 5 | 插件事件与宿主会话日志的关系(sidecar + 修复脚本) | 0.2.0 已改 sidecar,`repair-session-log.py` 就位 | 维持。宿主若开放 `ignorable` 写入再评估切回,无代码动作 | | 6 | 渲染依赖 Motion Canvas 3.17 编辑器 UI 自动化,单次约 4 秒编辑器加载 | `runtime.ts` 每次渲染起 vite + 开浏览器 | **P1 低成本优化**:渲染前端预热/复用浏览器实例省掉加载等待(见 §5);改动大则维持现状,稳定性优先 | | 7 | Windows `dsh plugin add` 的 pnpm 转发问题 | 文档已有绕过方案 | 维持文档,无代码动作 | ### 1.2 0.2.0「明确不做(推到 0.3+)」逐项处置 | # | 项 | 0.3.0 处置 | | --- | --- | --- | | 1 | TTS 旁白与音画对齐 | **继续推迟到 0.4**(理由见 1.1 #2),写进 §8 明确不做 | | 2 | 字幕轨道 | **跟随 audio 图层评估**:audio 图层落地(背景音轨)后,字幕可作为配套的「音轨时间轴」顺带做;否则继续推迟。0.2.0 结论「字幕脱离旁白没有独立价值」仍成立 | | 3 | loopback RPC 直改 spec | **继续留 0.4**。面板 P2 交互走 `agent.followup()`(1.1 #3),两条路径产出的事件完全相同,UI 不用改 | | 4 | Remotion / Manim 渲染 Provider | **继续推迟**。渲染 seam(注册表 + `provideRenderer`)已就绪,但多后端维护成本高;本轮集中把 Motion Canvas 单后端的元素覆盖做厚 | | 5 | 场景 camera(平移/缩放) | 已正式放弃(最终 IR 无此字段),不挂账 | | 6 | store 快照优化 | 维持观察(几十场景 fold 微秒级) | | 7 | `anim_asset_import` | **本轮实现(P1)**。元素类型扩展后素材需求变大(svg 图形 / 本地图片 / 音频),补上资产登记工具与校验(见 §2.5) | ### 1.3 代码内挂账(注释里自己承认的欠账) | # | 项 | 证据 | 0.3.0 处置 | | --- | --- | --- | --- | | 1 | `group` 图层类型未实现 | `codegen.ts` `COMPONENT.group = null`(「MVP 未实现分组」) | **实现**(§2 M0) | | 2 | 图层类型枚举三处维护、易漂移 | `types.ts` LayerType / `validate.ts` LAYER_TYPES / `register.ts` anim_draft_scene 描述 | 新增类型时三处同步;冒烟加「枚举一致性」断言(§2.3) | | 3 | `anim_draft_scene` 工具描述只列 `text\|rect\|circle\|image` | `register.ts` 描述字符串 | 新增类型后同步更新(模型必读的工具文档) | | 4 | 0.2.0 遗留真机复验未闭环 | 0.2.0 规划 §6/§8 标记「待复验」 | 0.3.0 开工前先复验:重启 dsh 复核事件持久化 + 产物显示;`dsh web` 真机看卡片实貌与视频播放。作为新元素类型验收的基线 | ### 1.4 真机实测确认的新问题:圆形画不出来 **现象**:真机 `dsh web` 会话里模型写 `circle` 图层,出片后圆形经常不显示(画不出来)。 **根因(代码层已确认)**: 1. `LayerProps` 类型对**所有图层**开放 `width / height / radius`,而 `codegen.ts` 里 `circle` 的属性白名单只有 `size / fill / stroke / lineWidth`——模型按 rect 的习惯写 `width/height`(或把 `radius` 当圆的半径写)时,这些属性被「不支持 → 降级警告 → 丢弃」; 2. Motion Canvas `Circle` 的默认 `size` 是 0,丢弃尺寸属性后得到 0×0 的圆 → 不可见。警告只进回执文本,模型不逐条处理就静默产残片。 **处置(并入 M0,随元素类型扩展一起修)**: - codegen 对 `circle` 做尺寸属性**别名归一**:`width` / `height`(同值或仅一个)→ `size`;`radius` / `r` → `size = radius×2`; - **缺省 size 兜底**:仍没有尺寸时给默认值(如 100)并显式警告,杜绝「0×0 不可见」; - validate 对无尺寸的 circle 加软警告;`anim_draft_scene` 工具描述写明 circle 用 `size`(不要用 width/height/radius); - 冒烟加回归:circle 写 `width/height/radius/缺省` 四种形态,断言生成的 TSX 均含合法 `size` 且带警告。 --- ## 2. 本版本主体:元素类型扩展 ### 2.1 现状与目标 - **现状**:`LayerType = 'text' | 'rect' | 'circle' | 'image' | 'group'`,其中 group 未实现;codegen 映射 Txt / Rect / Circle / Img。 - **目标**:把 IR 能表达的元素从 4 种撑到 10+ 种,覆盖教学动画的常见形态:分组、箭头/坐标轴、强调图形、任意矢量图、代码块、数学公式、音轨。 - **零新增依赖**:Motion Canvas 2d 3.17 已导出 Line / Polyline / Polygon / Ellipse / Star / Path / Svg / Code / Icon / Audio 等节点(`@motion-canvas/2d` 单包,渲染适配器直接 import),本轮不做任何新渲染后端。 ### 2.2 类型与映射表 | 类型 | MC 节点 | 关键 props(IR 层) | 教学动画用途 | 优先级 | | --- | --- | --- | --- | --- | | `group` | 父 Node(`view.add` 子节点到组) | `children: LayerId[]`(字段已有,本轮启用) | 整组移动/缩放/淡入淡出——最常用,0.2.0 M3 欠账 | **P0** | | `line` | `Line`(`points` 数组) | `points: [x,y][]`、`lineWidth`、`stroke`、`start/end`(划线进度) | 坐标轴、连线、下划线、刻度 | **P0** | | `arrow` | `Line` + 端点箭头(MC `Line` 无内建箭头,用 `Icon`/`Path` 兜底) | 同 line + `endArrow?: boolean` | 指向性示意(流程图、梯度方向) | **P0** | | `ellipse` | `Ellipse` | `width/height`、`fill`、`stroke` | 椭圆遮罩、轨道示意 | **P1** | | `star` | `Star` | `size`、`points`(角数)、`fill` | 强调符号、高亮标记 | **P1** | | `polygon` | `Polygon` | `points`、`fill`、`stroke` | 三角/多边形(流程图节点形状) | **P1** | | `svg` | `Svg` | `src`(assetId 或内联 SVG 字符串)、`width/height` | 任意矢量图形(公式、图标、logo) | **P1** | | `code` | `Code` + `LezerHighlighter`(`@lezer/*` 语言包) | `code: string`、`language`(typescript/python/json/html/css…)、`fontSize` | 代码演示课(语法高亮) | **P2 ✅** | | `math` | `Latex`(mathjax-full 随 `@motion-canvas/2d` 依赖,零新增) | `tex: string`、`fontSize`、`fill` | 数学推导课(公式排版) | **P2 ✅** | | `audio` | 渲染后 ffmpeg 音轨 mux(MC 的 Audio 节点不参与帧合成) | `src`(assetId)、`loop`、`volume` | 背景音乐 / 音效 | 顺延 0.4 | > 优先级口径:P0 本版本必做;P1 本版本目标;P2 视排期,做不了写进 §8 或顺延 0.4,不硬凑。 ### 2.3 每个类型的四张面(实现要点) 新增一个类型要同步过四个面,缺一即「validate 放行了但渲染跳过」或「渲染生成了但模型不知道」: 1. **types.ts**:`LayerType` 联合 + `LayerProps` 增字段(索引签名已允许开放扩展); 2. **validate.ts**:`LAYER_TYPES` 集合 + 按类型的 props 校验(如 `line.points` 必须是成对数字数组、`svg.src` 非空、`code.language` 在白名单); 3. **codegen.ts**:`STATIC_PROPS` / `COMPONENT` / `ANIMATABLE` 三张表 + 特殊生成逻辑(group 组合、line points 数组转 MC 的 `[...vec2]`、code 高亮 import); 4. **register.ts**:`anim_draft_scene` 的 scene 描述更新(模型必读)+ `anim_create_spec`/回执文案如有涉及。 冒烟测试加一条「**类型枚举一致性**」断言:`types.ts` 的 LayerType、`validate.ts` 的 LAYER_TYPES、codegen 的 COMPONENT/STATIC_PROPS 三处集合一致,防止以后再漂移。 ### 2.4 关键设计决策 - **group = 图层容器,不做成独立节点**:`children` 引用场景内其他 `LayerId`,codegen 生成一个父节点包住子节点;变换属性(x/y/scale/rotation/opacity)落到父节点,子图层自己的轨道动画不受影响。validate 校验 children 引用存在、无环、不跨场景(场景内作用域)。 - **新增类型全部兼容现有 IR 契约**:中心原点坐标系、场景内绝对毫秒、一切动画进 `tracks`——不搞「特殊动画类型」特例,微调面板与 patch 引擎零改动。 - **不支持的属性仍降级为警告,不阻断渲染**(沿用 0.2.0 策略)。 - **code / math 走「MC 原生节点 + 生成期装配」而不是运行期后端依赖**:code 用 MC 自带 `Code` 节点 + `LezerHighlighter`(`@motion-canvas/2d/lib/code` 深路径导出),语言解析器来自 `@lezer/javascript`(TS/JSX 用 dialect 配置派生,包内无 `@lezer/typescript`)/python/json/html/css——这些包作为插件依赖装入根 node_modules,渲染项目经 workDir junction 解析,生成物只在 spec 里出现带 `language` 的 code 图层时才产出 `code-highlight.ts`(无 code 图层的项目不依赖语言包);math 用 MC 原生 `Latex` 节点(mathjax-full 是 `@motion-canvas/2d` 自带依赖,真正零新增)——IR 层依然不引入任何渲染库依赖。 ### 2.5 资产管线(配合元素扩展,P1) - **`anim_asset_import` 工具**:登记 assets(kind: image / svg / audio / font)+ 校验(src 存在或 http 可达、扩展名白名单、alt 可选),返回 assetId; - **图层 props 支持 assetId 引用**:`image.src` / `svg.src` / `audio.src` 可写 `asset:`,codegen 生成前把资产复制进 workDir 随项目物化(本地文件)或按 URL 透传(http); - 与 `/dsh-anim/media` 放行边界一致:资产不出 outputDir 时天然可服务,`anim_asset_import` 回执里的路径进媒体索引。 --- ## 3. 编排收口(0.2.0 M3 欠账) 0.2.0 规划 M3 只落了 group(又顺延到本版本 §2),preset 编排未做: - **`anim-studio` agent preset**:固定本插件工具集(9 个 `anim_*`)+ 分镜方法论系统提示词段(「如何写教学分镜脚本」「如何安排讲解节奏」); - 验收:`dsh web` 新会话选该 preset 后,一句话主题 → 自动走 diagnose → create → plan → draft → preview → render 全流程出片。 --- ## 4. 面板最简交互(P1,待真机拆包实证后落地) 把 0.2.0 的「只读面板」推进一步(不做多): - 「撤销这步 / 预览第 N 幕 / 渲染成片」按钮 → 生成结构化指令 → 下一个模型回合执行(设计草案 §6 路径 2); - 机制已核实:host 侧 `Agent.followup()/steer()`(`@deepseek-ai/dsh-agent`,`source: { kind: 'plugin' }` 可归因到插件)就是入口,改动天然落事件流、可回放; - **阻塞点**:client(浏览器)要触达 host 的 agent inbox,需走 dsh client-connection 的 RPC/loopback(agentPreset.* 同款通道),该 API 的确切形态未拆包实证。**本轮不做**:M0/M1 已把元素与资产链路做厚,这条交互链路在真机拆包 `@deepseek-ai/dsh-client-connection` 并验证后才能可靠落地,避免基于猜测写死 API。 已落地的相关机制:`anim_undo` 的 inverse 回喂、preset 方法论里写明「用 anim_patch 微调」,模型侧已有完整闭环。 --- ## 5. 渲染与性能(P1,先测再动) - **浏览器实例预热/复用**:`runtime.ts` 每次渲染都起 vite + 开无头浏览器,编辑器加载约 4 秒是纯等待。评估「插件生命周期内复用浏览器实例 / 渲染前预热页面」,省掉固定开销; - 约束:不降低 headless 稳定性(Edge 152 + SwiftShader 现状优先),改动大就维持现状,只把测量结论写进 README。 --- ## 6. 里程碑与验收 | 里程碑 | 内容 | 验收标准 | | --- | --- | --- | | **M0 元素基础** | `group` + `line` + `arrow` + `ellipse` 四类实现(四张面全过);类型枚举一致性冒烟断言;examples 新增一幕用上 group/line | `pnpm smoke` 全绿;`examples/hello-gradient` 用新类型渲出 MP4(中文正常);`dsh web` 真机复验通过 | | **M1 图形集扩充** | `star` + `polygon` + `svg` + `anim_asset_import`(资产登记 + assetId 引用 + 物化) | 新类型端到端出片;资产导入后可被图层引用并在成片中渲染 | | **M2 编排收口 + 面板交互** | `anim-studio` preset + 系统提示词段;面板「撤销/预览/渲染」按钮走 `agent.followup()` | 新会话一句话出片;点「撤销上一步」驱动一次真实 patch | | **M3 收口** | `code` / `math` 落地(audio 顺延 0.4,写进 §8);README 已知限制刷新;0.3.0 离线打包验证 | 文档与实现一致;offline-packager 打出的 tgz 装上新元素可用 | 版本内顺序:M0 → M1 → M2 → M3。peer 依赖维持 `>=0.1.5-rc.2`。 ## 7. 风险 | 风险 | 等级 | 应对 | | --- | --- | --- | | group 容器在 MC 的变换层级与 IR 契约有偏差(子图层坐标系、z-order 与组内外关系) | 中 | M0 先用单例真机验证再铺;z-order 语义写进 types 注释 | | line/arrow 的 `points` 数组与现有「数值关键帧插值」模型不兼容(数组无法逐元素插值) | 中 | points 只做静态 props + 整体变换动画(x/y/scale/rotation),不承诺 points 逐点动画;写进工具描述 | | code/math 的排版质量不可控(高亮、换行、公式缩放) | 中 | P2 且可回退:math 走 svg 内嵌(KaTeX 生成期),质量与渲染解耦 | | audio 需改渲染管线(ffmpeg 混音)与产物契约 | 中 | P2 谨慎:先做「背景音轨 + ffmpeg `-i` mux」,TTS/音画对齐不碰 | | 图层类型枚举三处漂移 | 低 | 冒烟「枚举一致性」断言(§2.3) | | dsh 0.1.x 破坏性变更(持续风险) | 持续 | 锁 verified 版本;IR / 工具层与宿主解耦的既有策略不变 | ## 8. 明确不做(推到 0.4+) TTS 旁白与音画对齐、字幕轨道(若 audio 图层落地则顺带评估)、**audio 图层(静态音轨 + ffmpeg mux,需改渲染管线与产物契约,0.3.0 顺延)**、loopback RPC 直改 spec、Remotion / Manim 渲染 Provider、场景相机、store 快照优化、画布拖拽式编辑(时间线/关键帧直接拖)、3D / 粒子效果。 --- ## 9. 实施进度 分支:`feat/0.3.0-elements`。 | 项 | 状态 | 说明 | | --- | --- | --- | | 0.3.0 规划 | ✅ 完成 | 本文件:遗留盘点 + 元素类型扩展 + 里程碑 | | 1.4 圆形渲染修复 | ✅ 代码完成 | 根因:circle 属性白名单缺 width/height/radius,MC Circle 无尺寸即 0×0。修复:width/height 原生透传、radius/r→size×2、缺省 size=100 兜底、无色兜底主题色;validate 加软警告;冒烟四形态回归 | | M0 元素基础(group/line/arrow/ellipse) | ✅ 代码完成 | types/validate/codegen 三处同步 + 工具描述更新;group=Node 容器(成员 `.add()` 挂载、单层分组、冲突降级);line/arrow 用 Curve 内建 start/end/endArrow/arrowSize;ellipse=Circle+width/height;动画目标集合改为按类型派生(顺带修掉「对无该 signal 的节点发动画 → 运行时崩溃」隐患)。`pnpm smoke` 22 项全绿、typecheck 全绿、宿主挂载冒烟通过 | | examples 更新 | ✅ 完成 | hello-gradient 第 2 幕:横轴改 line(end 轨道画线)+ 新增下降方向 arrow;小球改 radius 写法(修复的直接演示)。第 3 幕新增 star(强调星,spring 弹入)与 svg(内嵌对勾)。第 4 幕(0.3.0 M3)新增 math 更新公式 + python 版 code 更新规则,供真机复验高亮与公式排版。`generate.ts` 输出警告与 TSX 正确 | | M1 图形集扩充 | ✅ 代码完成 | star→Path(codegen 内置五角星 path,MC 3.17 无 Star 组件);polygon→MC Polygon(正多边形,sides+size+radius 圆角,修正规划的 points 方案);svg→MC SVG(内嵌字符串);**`anim_asset_import` 工具**(第 10 个工具):本地文件复制进 `outputDir/assets/` + patch 进 spec.assets + 事件;image.src 支持 `asset:` 引用 → 渲染前复制进项目 `public/assets/` 并换成根 URL,http URL 原样透传;client 补 AssetCard。冒烟 25 项全绿、typecheck 全绿、宿主挂载 10 工具/10 卡片通过 | | M2 编排收口 + 面板交互 | 🟡 preset 完成,面板交互移真机 | **anim-studio preset 完成**(`config/agent-presets/anim-studio/`:preset.yml 显示名 + agent.cordis.yml 挂官方 dsh-persona 写导演身份与分镜方法论;工具宿主层全局注册故不重复挂载插件)。冒烟新增 preset 文件/锚点校验,26 项全绿。**面板按钮**(client 触达 host agent 的 RPC)待真机拆包 `dsh-client-connection` 后落地,见 §4 | | M3 收口 | 🟡 code/math 完成,audio 顺延 | **code 图层**:MC `Code` 节点 + `LezerHighlighter`(`@motion-canvas/2d/lib/code`);`language` → 高亮器(typescript/ts/tsx/javascript/js/jsx/python/py/json/html/css,大小写不敏感),`{{片段}}` 原生着色;带语言才生成 `code-highlight.ts`(@lezer/* 五包入依赖,`@lezer/typescript` 不存在、TS 由 `@lezer/javascript` dialect 派生);无 language 纯文本不染色不告警。**math 图层**:MC `Latex` 节点(mathjax-full 随 2d 依赖零新增),tex 透传 + fill 兜底。validate 补 code/math 软体检(缺内容警告、language 非字符串硬错)。工具描述与 preset persona 同步 code/math。版本升 **0.3.0**,README 已知限制刷新(含打包产物名 0.3.0.tgz)。冒烟 28 项全绿、typecheck 全绿、宿主挂载通过;含 code/math 的生成项目经 vite 实测编译、@lezer/* 与 2d/lib/code 深路径解析真实可用。**audio 顺延 0.4**(§8)。离线打包验证待用户环境(沙箱无 dsh CLI / offline-packager) | | 真机复验(待用户环境) | ⬜ 待办 | 沙箱无浏览器:圆形渲染修复与 line/arrow/ellipse 需在 `dsh web` 真机出片复核;`examples/hello-gradient` 的 `pnpm render` 是手动诊断入口 | | 全库代码体检 + 同日修复(2026-09-15) | ✅ 完成 | 体检结果与修复记录都在 `docs/0.3.x-优化清单.md`(O1~O19:14 项已修复、5 项按清单维持现状)。**对账清账**:§2.3/§6 M0 的「类型枚举一致性冒烟断言」与 §2.4 的「validate 校验 group children」两处承诺已在本轮落地(清单 O14/O15);另修复体检发现的 `anim_render` 的 `scenes` 参数只进契约不进实现(O1)、渲染并发互斥 + 随机端口(O2)、事件 sink 会话归因(O3)等。基线刷新:typecheck 五包全绿、smoke 28→34 项全绿、宿主挂载冒烟通过 |