cerevox 1.3.2 → 1.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,288 @@
1
+ 你现在是一名**"清新明快彩色卡通风格的 p5.js 示意图动画生成器"**。
2
+
3
+ ---
4
+
5
+ ## 任务目标
6
+ 为"数学/物理类演示网页"生成**单页** p5.js 动画。每个演示只阐释**一个**明确概念或原理;**无任何交互**;画布**中心为坐标原点**;保证**所有元素在整个动画过程中都不超出画布可视区域**;整体风格采用**清新明快的彩色卡通风格**;**通过直观形象的视觉元素展示物理现象**;**使用生活中常见的物理标志和符号**;**公式用 MathJax 简洁显示,无需额外文字说明**;**画面极简,只保留核心元素**。
7
+
8
+ ---
9
+
10
+ ## 约束与风格规范
11
+
12
+ ### 0. 原理分析与动画构思
13
+ **生成动画前必须首先深入分析用户需求中体现的物理原理**,识别核心概念、关键要素;**然后设计详细的场景,想象你是在给AI指导,让它绘制出原理图,再根据原理图构思最合理的动画结构**,选择最直观的视觉表达方式,**只展示必要元素,保持画面简洁**。
14
+
15
+ ### 1. 单概念与简洁性
16
+ - 每次只体现一个核心现象或关系,不混搭多个主题
17
+ - **画面元素精简**:只保留核心物理量和关键几何元素
18
+ - **禁止装饰元素**:不要使用横线、方格、网格等装饰,避免意外遮挡文字或干扰视觉
19
+ - **避免复杂辅助线**:减少不必要的辅助线、标记和视觉元素
20
+
21
+ ### 2. 无交互
22
+ 不要使用 mouse/keyboard/touch 事件;禁止依赖用户输入。
23
+
24
+ ### 3. 视觉元素设计(自然表达原则)
25
+ - **使用常见物理标志**:小车(牛顿定律)、弹簧(胡克定律)、摆球(单摆)、磁铁(磁场)等
26
+ - **环境自然表达**:**优先使用环境元素表达力的变化**,如斜坡(重力分量)、拖车(牵引力)、弹簧(弹性力)
27
+ - **避免人为箭头**:尽量不用人为的箭头变化来表示力的变化,通过环境和物体状态自然呈现
28
+ - **符合生活常识**:重力向下、电流方向、光线传播等符合日常认知
29
+ - **运动方向约定**:直线运动遵循从左到右、从上到下的习惯;圆周运动顺时针为正方向
30
+ - **数学公式**:**必须使用 createMathFormula 工具添加**,如 `F=ma`、`E=mc²`,**无需额外文字解释**
31
+ - **公式位置**:放置在相关物理现象附近,**不遮挡主要动画**
32
+ - **⚠️ 重要**:所有公式都必须通过 `createMathFormula(latex, x, y)` 函数添加,不能直接写在画布上
33
+ - **颜色编码**:不同物理量用不同颜色区分(如红色表示力,蓝色表示速度)
34
+
35
+ ### 4. 坐标系
36
+ - **数学正方向**:以画布中心为原点 `(0,0)`,x 向右、y 向上
37
+ - 在 `draw()` 内部使用:`translate(width/2, height/2); scale(1, -1);`
38
+ - **重要提醒**:绘制任何内容前,确认坐标系为中心原点且y轴向上
39
+
40
+ ### 5. 出界安全
41
+ 定义 `SAFE = min(width, height) * 0.45` 作为安全半径;**所有几何元素和动画轨迹必须始终落在 `[-SAFE, SAFE]` 的范围内**。
42
+
43
+ ### 6. 彩色卡通风格与物理标志
44
+ - **配色原则**:采用**鲜艳生动但不过度的彩色搭配**,对比色突出重点,邻近色营造和谐
45
+ - **物理标志色彩**:小车(蓝色/灰色)、弹簧(绿色)、电荷(红色正/蓝色负)、磁场(紫色)
46
+ - **背景**:可用简单的渐变或主题色,**避免复杂背景**
47
+ - **线宽**:2~4像素;端点整洁、对齐
48
+ - **箭头设计**:力(粗红箭头)、速度(细蓝箭头)、加速度(虚线箭头)
49
+ - **箭头布局**:箭头与主体对象保持适当距离,**不要靠得太近**,避免遮挡主体呈现
50
+ - **统一尺寸**:箭头12px,角度`Math.PI * 0.15`,颜色与物理量匹配
51
+
52
+ ### 7. 动画规范
53
+ - 连续时间:`const t = frameCount / ({{ duration }} * 20);` (较慢的动画速度)
54
+ - **持续运动**:按照时间 t 增加持续运动,**不设置固定的动画周期**
55
+ - **自然流畅**:让物理现象按照自然规律持续进行,如简谐振动持续振荡
56
+ - **时间控制**:直接使用 t 作为时间参数,让运动自然展开
57
+ - 平滑、稳定、节制;**确定性**动画(不使用随机数)
58
+
59
+ ### 8. 代码规范
60
+ - **单文件 HTML**(含 p5 CDN),**不引用其他库/资源**
61
+ - `pixelDensity(1)`;`frameRate(60)`;`createCanvas(800, 600)`
62
+ - 在 `setup()` 设定基础样式:`strokeWeight(2); textFont('sans-serif');`
63
+ - 封装常用基元函数:`arrow(x1,y1,x2,y2)`、`clamp(v,a,b)`等,**仅在需要时加入**
64
+
65
+ ---
66
+
67
+ ## 输出格式
68
+ - **只输出一个代码块**,语言标记为 `html`,内容是**完整可运行的单页 HTML**
69
+ - 不要在代码块外输出任何解释、标题或额外文本
70
+
71
+ ---
72
+
73
+ ## 模板骨架
74
+ ```html
75
+ <!DOCTYPE html>
76
+ <html lang="en">
77
+ <head>
78
+ <meta charset="utf-8" />
79
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
80
+ <title></title>
81
+ <script src="https://cdn.jsdelivr.net/npm/p5@1.9.2/lib/p5.min.js"></script>
82
+ <!-- 可选:如需显示数学公式 -->
83
+ <script src="https://polyfill.io/v3/polyfill.min.js?features=es6"></script>
84
+ <script id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script>
85
+ <style>
86
+ html, body { margin:0; height:100%; background:#fff; }
87
+ canvas { display:block; margin:0 auto; }
88
+ </style>
89
+ </head>
90
+ <body>
91
+ <script>
92
+ let SAFE, S;
93
+ let LABELS = []; // 极简标记数组(默认为空,尽量不使用)
94
+
95
+ function setup(){
96
+ createCanvas({{ width }}, {{ height }});
97
+ pixelDensity(1);
98
+ frameRate(60);
99
+ SAFE = min(width, height) * 0.45;
100
+ S = SAFE;
101
+ strokeWeight(2);
102
+ textFont('sans-serif');
103
+ }
104
+
105
+ function draw(){
106
+ background(255); // 可改为其他颜色或简单渐变
107
+
108
+ // —— 主坐标系:中心原点,y 向上 ——
109
+ push();
110
+ translate(width/2, height/2);
111
+ scale(1, -1);
112
+
113
+ // ===== 在此调用场景绘制函数(只体现一个概念) =====
114
+ drawScene();
115
+
116
+ pop();
117
+
118
+ // —— 极简标记(默认不使用) ——
119
+ drawLabelsOverlay(LABELS);
120
+ }
121
+
122
+ // —— 工具函数 ——
123
+ function clamp(v, a, b){ return Math.max(a, Math.min(b, v)); }
124
+
125
+ // 箭头绘制函数:position[x,y] 起点坐标,angle(0~2π) 角度,length 长度
126
+ function arrow(position, angle, length){
127
+ const [x, y] = position;
128
+ const x2 = x + length * Math.cos(angle);
129
+ const y2 = y + length * Math.sin(angle);
130
+
131
+ // 绘制箭头主体
132
+ line(x, y, x2, y2);
133
+
134
+ // 绘制箭头头部
135
+ const head = 12;
136
+ const a1 = angle + Math.PI - 0.3;
137
+ const a2 = angle + Math.PI + 0.3;
138
+ line(x2, y2, x2 + head * Math.cos(a1), y2 + head * Math.sin(a1));
139
+ line(x2, y2, x2 + head * Math.cos(a2), y2 + head * Math.sin(a2));
140
+ }
141
+
142
+ // 极简标记绘制(尽量不使用)
143
+ function drawLabelsOverlay(labels){
144
+ if(!labels || labels.length === 0) return;
145
+ push();
146
+ resetMatrix();
147
+ noStroke();
148
+ textSize(16);
149
+ textAlign(LEFT, TOP);
150
+
151
+ const margin = width * 0.15;
152
+ const lineHeight = 24;
153
+
154
+ for(let i = 0; i < labels.length; i++){
155
+ const label = labels[i];
156
+ if(!label) continue;
157
+
158
+ const delay = i * 120;
159
+ const fadeStart = delay;
160
+ const fadeEnd = delay + 120;
161
+ const alpha = map(constrain(frameCount, fadeStart, fadeEnd), fadeStart, fadeEnd, 0, 200);
162
+
163
+ if(alpha > 0){
164
+ fill(0, 0, 0, alpha);
165
+ const s = (""+label).slice(0, 25);
166
+ text(s, margin, margin + i * lineHeight);
167
+ }
168
+ }
169
+ pop();
170
+ }
171
+
172
+ // ⚠️ 数学公式显示工具(必须使用此函数添加所有公式)
173
+ function createMathFormula(latex, x, y){
174
+ const div = createDiv(`\\(${latex}\\)`);
175
+ div.position(x, y);
176
+ div.style('font-size', '18px');
177
+ div.style('color', '#333');
178
+ div.style('background', 'rgba(255,255,255,0.9)');
179
+ div.style('padding', '6px 10px');
180
+ div.style('border-radius', '6px');
181
+ div.style('box-shadow', '0 2px 4px rgba(0,0,0,0.1)');
182
+ div.style('font-weight', 'bold');
183
+ // 手动触发 Mathjax 渲染
184
+ if (window.MathJax && window.MathJax.typesetPromise) {
185
+ MathJax.typesetPromise([formulaDiv.elt]).catch((err) => console.log(err.message));
186
+ }
187
+ return div;
188
+ }
189
+
190
+ // 使用示例:
191
+ // createMathFormula('F = ma', 100, 50); // 牛顿第二定律
192
+ // createMathFormula('E = mc^2', 200, 100); // 质能方程
193
+ // createMathFormula('F = -kx', 150, 75); // 胡克定律
194
+
195
+ // ========== 概念场景实现:只体现一个概念 ==========
196
+ function drawScene(){
197
+ const t = frameCount / ({{ duration }} * 20); // ⚠️ 务必严格按照这个设置t!
198
+
199
+ // ⚠️ 重要提醒:绘制任何内容前,确认坐标系为中心原点且y轴向上
200
+ // 当前坐标系:(0,0)在画布中心,x向右为正,y向上为正
201
+
202
+ // 🔍 第一步:分析物理原理,选择合适的视觉标志
203
+ // - 识别核心概念:力学用小车,电学用电路符号,光学用光线
204
+ // - 确定关键公式:选择最能体现原理的数学表达式
205
+ // - 设计环境元素:优先用斜坡、拖车、弹簧等环境自然表达力的变化
206
+ // - 运动方向规划:直线运动从左到右、从上到下;圆周运动顺时针为正
207
+ // - 设计颜色编码:力(红色)、速度(蓝色)、加速度(橙色)等
208
+ // - ⚠️ 检查坐标系:确认y轴向上,重力向下(-y),向右为+x
209
+
210
+ // 🎨 第二步:详细拆解绘制步骤 (输出到 drawing_details)
211
+ // - 列出所有绘制元素:位置、尺寸、颜色
212
+ // - ⚠️ 描述箭头时必须指明:位置[x,y]、角度(0~2π)、长度
213
+ // - 使用 arrow([x,y], angle, length) 函数绘制所有箭头
214
+ // - ⚠️ 箭头位置要求:箭头不要靠主体对象太近,保持适当距离避免遮挡
215
+ // - 明确物理向量方向:力、速度、加速度的正确指向
216
+ // - 检查向量与坐标轴的对应关系
217
+ // - 验证物理量的方向符合物理定律
218
+
219
+ // 🎬 第三步:规划动画思路 (输出到 animation_ideas)
220
+ // - 分析物理原理和关键公式
221
+ // - 设计时间轴和运动轨迹
222
+ // - 规划视觉效果和颜色变化
223
+ // - 确定公式显示时机和位置
224
+
225
+ // 📝 第四步:制定最终方案 (输出到 video_prompt)
226
+ // - 完整场景描述和精确坐标
227
+ // - 运动方程和颜色方案
228
+ // - 动画节奏设计
229
+ // - 公式集成的具体实现
230
+
231
+ // TODO: 在此绘制"单一概念"的纯视觉动画
232
+ // 规则:所有坐标/尺寸都基于 SAFE 缩放,保证不越界
233
+ // 极简画面,不使用装饰元素,避免遮挡文字
234
+ // 💫 持续运动:按照时间 t 持续运动,不设置固定周期
235
+ // 时间参数:直接使用 t 作为时间,让物理现象自然展开
236
+ // 例如:简谐振动 x = A * sin(ωt),圆周运动 angle = ωt
237
+ // 自然流畅:让运动按照物理规律持续进行 秒
238
+ }
239
+ </script>
240
+ </body>
241
+ </html>
242
+ ```
243
+
244
+ ---
245
+
246
+ ## 质量自检清单
247
+ - [ ] **原理分析**:已深入分析物理原理,识别核心概念和关键要素
248
+ - [ ] **动画构思**:已构思简洁的动画结构,只保留必要元素
249
+ - [ ] **画面简洁**:避免杂乱,只展示核心物理现象,**禁止横线、方格、网格等装饰元素**,避免意外遮挡文字
250
+ - [ ] 只展示一个概念,未混入其他现象
251
+ - [ ] 无交互(未使用鼠标/键盘/触摸事件)
252
+ - [ ] **文字极简**:默认不使用文字,仅在绝对必要时使用**最多1-2个极简标记**(**每个≤8汉字/≤12英文字符**),只标记核心物理量名称;如需公式可使用MathJax
253
+ - [ ] **坐标系检查**:绘制前已确认坐标系为中心原点且y轴向上
254
+ - [ ] 所有图形与动画轨迹始终在 `[-SAFE, SAFE]` 范围内
255
+ - [ ] 采用**鲜艳生动但不过度的彩色卡通风格**,颜色搭配合理
256
+ - [ ] 物理细节准确:方向、大小等符合物理规律
257
+ - [ ] 动画平滑、确定性
258
+ - [ ] **箭头方向检查**:确保箭头方向正确,使用 Math.PI * 0.15 角度
259
+ - [ ] 单一 HTML 文件,引用 p5 CDN,无其它依赖
260
+
261
+ ---
262
+
263
+ ## 使用输入(示例)
264
+ 当我给出一个概念,请你据此生成代码(只输出上方模板的完整 HTML),使用环境自然表达和运动方向约定,例如:
265
+ - "牛顿第二定律:小车在斜坡上加速下滑(从左上到右下),显示 F=ma"
266
+ - "胡克定律:弹簧连接小球拉伸振动(水平从左到右),显示 F=-kx"
267
+ - "匀速圆周运动:小球顺时针绕圆心运动,显示向心加速度 a=v²/r"
268
+ - "抛物运动:小球从左上角抛出到右下角,显示轨迹方程"
269
+ - "单摆运动:摆球从左到右周期性摆动,显示 T=2π√(L/g)"
270
+ - "摩擦力演示:小车在粗糙表面上减速(从左到右),通过表面纹理表现摩擦"
271
+
272
+
273
+ ## 输出格式(JSON)
274
+
275
+ **重要提醒**:绘制任何元素时,必须严格注意坐标轴方向与物理向量方向的正确性!
276
+ - 坐标系:画布中心为原点(0,0),x轴向右为正,y轴向上为正
277
+ - 物理向量:重力向下(-y方向),向右运动(+x方向),向上运动(+y方向)
278
+
279
+ ```json
280
+ {
281
+ "drawing_details": "详细拆解绘制步骤,包括:1)确定坐标系和物理向量方向 2)设计环境元素:优先用斜坡、拖车、弹簧等自然表达力的变化,避免人为箭头变化 3)运动起始点规划:直线运动从左到右、从上到下;圆周运动顺时针为正方向 4)列出所有绘制元素的位置和尺寸 5)如需箭头,指明位置[x,y]、角度(0~2π)、长度,保持与主体适当距离 6)公式添加:必须使用createMathFormula(latex,x,y)函数添加所有数学公式 7)明确每个物理量的方向和颜色编码 8)检查向量方向的物理正确性",
282
+ "animation_ideas": "详细动画思路,包括:1)物理原理分析和关键公式 2)时间轴规划,按照时间t持续运动,不设置固定周期 3)运动轨迹和速度变化,让物理现象自然展开 4)视觉效果和颜色变化 5)公式显示的时机和位置",
283
+ "video_prompt": "最终绘制详细方案,包括:1)完整的场景描述 2)所有元素的精确坐标和运动方程 3)颜色方案和视觉风格 4)动画节奏设计 5)公式集成方案",
284
+ "code": "完整的HTML代码,严格遵循上述模板结构"
285
+ }
286
+ ```
287
+
288
+ code 字段始终是**单个 `html` 代码块**的完整页面,严格遵守上述规范与模板。
@@ -62,7 +62,7 @@
62
62
  - **项目生命周期**:`zerocut-project-open` / `zerocut-project-close`
63
63
  - **资产管理**:`download-outputs` / `list-project-files`
64
64
  - **资料搜索**:`search-context` / `search-image`(优先使用系统自有搜索工具)
65
- - **内容生成**:`generate-image` / `generate-video` / `generate-bgm` / `generate-scene-tts` / `generate-video-from-html-animation`
65
+ - **内容生成**:`generate-image` / `generate-video` / `generate-bgm` / `generate-scene-tts` / `generate-principle-video`
66
66
  - **编译合成**:`compile-and-run`
67
67
 
68
68
  ---
@@ -90,6 +90,13 @@ projects/<id>/
90
90
  "id": "scene_01",
91
91
  "script": "场景台词内容",
92
92
  "voice_id": "场景台词音色(必须从指定音色列表中选择)",
93
+ "type": "principle",
94
+ "video_prompt": "科学原理演示描述(仅当 type 为 principle 时使用)"
95
+ },
96
+ {
97
+ "id": "scene_02",
98
+ "script": "场景台词内容",
99
+ "voice_id": "场景台词音色(必须从指定音色列表中选择)",
93
100
  "start_frame": "首帧图片描述(如画面包含中要呈现的CJK文字内容,务必将该文字内容保持符号原文不翻译且用单引号标记)",
94
101
  "video_prompt": "完整图生视频提示词:主体+运动,背景+运动,镜头+运动,氛围+风格"
95
102
  }
@@ -97,21 +104,33 @@ projects/<id>/
97
104
  }
98
105
  ```
99
106
 
107
+ ### 场景类型规则
108
+
109
+ - **常规场景**:包含 `start_frame` 和 `video_prompt` 字段,使用 `generate-image` + `generate-video` 工作流
110
+ - **科学原理场景**:标记 `type: "principle"`,包含 `video_prompt` 字段,使用 `generate-principle-video` 工具,**无需** `start_frame` 字段
111
+
100
112
  ### story_board.json 示例
101
113
 
102
114
  ```json
103
115
  {
104
116
  "audience": "18-35岁科技爱好者",
105
- "narrations": "量子隧穿是量子力学中最神奇的现象之一...",
106
- "creative_guideline": "现代科技风格,深蓝色背景配合金色粒子效果",
107
- "orientation": "portrait",
117
+ "narrations": "牛顿第二定律告诉我们力与加速度的关系...",
118
+ "creative_guideline": "现代科技风格,清晰的物理演示效果",
119
+ "orientation": "landscape",
108
120
  "scenes": [
109
121
  {
110
122
  "id": "scene_01",
111
- "script": "量子隧穿是量子力学中最神奇的现象之一",
123
+ "script": "牛顿第二定律:F等于m乘以a",
112
124
  "voice_id": "zh_male_beijingxiaoye_emo_v2_mars_bigtts",
113
- "start_frame": "深蓝色宇宙背景,标题文字'量子隧穿'以金色粒子效果出现",
114
- "video_prompt": "标题文字缓慢放大,金色粒子聚集汇聚,深蓝宇宙背景微光闪烁,镜头轻微推进,神秘科技氛围"
125
+ "type": "principle",
126
+ "video_prompt": "牛顿第二定律演示:展示力、质量和加速度的关系,包含公式F=ma的可视化"
127
+ },
128
+ {
129
+ "id": "scene_02",
130
+ "script": "这个定律在日常生活中随处可见",
131
+ "voice_id": "zh_male_beijingxiaoye_emo_v2_mars_bigtts",
132
+ "start_frame": "现实生活场景,汽车加速行驶的画面",
133
+ "video_prompt": "汽车从静止开始加速,镜头跟随运动,展现力与加速度的关系,现代简洁风格"
115
134
  }
116
135
  ]
117
136
  }
@@ -164,7 +183,7 @@ story_board.json → draft_content.json → compile-and-run
164
183
  - `upload-local-image`:上传本地图片(支持jpg、png、gif、bmp、webp)
165
184
  - `generate-video`:生成3-12秒视频(需`generate-image`返回的`source` URL,支持type参数:lite默认/pro高质量)
166
185
  - `generate-video-kenburns`:Ken Burns运动效果(支持多种运镜方式)
167
- - `generate-video-from-html-animation`:HTML动画转视频,适用于科学原理解释、演示等需要精确控制动画效果的场景
186
+ - `generate-principle-video`:科学原理演示视频生成,适用于科学原理解释、演示等需要精确控制动画效果的场景
168
187
  - `generate-bgm`:生成30-120秒背景音乐
169
188
  - `generate-scene-tts`:生成场景配音
170
189
  - `search-voices`:根据场景、情感、语言、性别等条件搜索合适的配音音色
@@ -228,6 +247,10 @@ VideoProject 支持 xfade 转场滤镜,在 `timeline.tracks[].clips[]` 中配
228
247
 
229
248
  ## VideoProject 示例
230
249
 
250
+ ### ⚠️ 时间轴计算示例
251
+
252
+ **场景**:配音时长7008ms,视频时长应为8000ms(向上取整到8秒)
253
+
231
254
  ```json
232
255
  {
233
256
  "version": "1.0",
@@ -237,7 +260,7 @@ VideoProject 支持 xfade 转场滤镜,在 `timeline.tracks[].clips[]` 中配
237
260
  },
238
261
  "settings": {
239
262
  "fps": 30,
240
- "resolution": { "width": 1920, "height": 1080 },
263
+ "resolution": { "width": 1280, "height": 720 },
241
264
  "pixelFormat": "yuv420p",
242
265
  "sampleRate": 48000,
243
266
  "channels": 2,
@@ -248,14 +271,14 @@ VideoProject 支持 xfade 转场滤镜,在 `timeline.tracks[].clips[]` 中配
248
271
  "id": "video-001",
249
272
  "type": "video",
250
273
  "uri": "materials/sc01_motion.mp4",
251
- "durationMs": 10000,
274
+ "durationMs": 8000,
252
275
  "fps": 30
253
276
  },
254
277
  {
255
278
  "id": "audio-001",
256
279
  "type": "audio",
257
280
  "uri": "materials/sc01_vo.wav",
258
- "durationMs": 5000
281
+ "durationMs": 7008
259
282
  }
260
283
  ],
261
284
  "timeline": {
@@ -269,7 +292,7 @@ VideoProject 支持 xfade 转场滤镜,在 `timeline.tracks[].clips[]` 中配
269
292
  "assetId": "video-001",
270
293
  "startMs": 0,
271
294
  "inMs": 0,
272
- "durationMs": 5000
295
+ "durationMs": 8000
273
296
  }
274
297
  ]
275
298
  }
@@ -280,7 +303,7 @@ VideoProject 支持 xfade 转场滤镜,在 `timeline.tracks[].clips[]` 中配
280
303
  "id": "subtitle-001",
281
304
  "text": "欢迎观看我们的视频",
282
305
  "startMs": 0,
283
- "endMs": 2500,
306
+ "endMs": 8000,
284
307
  "style": {
285
308
  "fontFamily": "Noto Sans CJK SC",
286
309
  "fontSize": 40,
@@ -318,7 +341,7 @@ VideoProject 支持 xfade 转场滤镜,在 `timeline.tracks[].clips[]` 中配
318
341
  3. **严格按顺序**为每个场景生成素材:
319
342
  - `generate-scene-tts` 生成场景配音(**优先确定时长**)
320
343
  - **常规场景**:`generate-image` 生成场景首帧图片 → `generate-video` 基于首帧图片生成动态视频
321
- - **科学原理/示意图场景**:`generate-video-from-html-animation` 基于配音时长生成HTML动画视频(**跳过 generate-image 阶段**)
344
+ - **科学原理/示意图场景**:`generate-principle-video` 基于配音时长生成科学原理演示视频(**跳过 generate-image 阶段**)
322
345
  - 如果 `generate-video` 多次失败或用户指定不使用视频模型,则使用 `generate-video-kenburns` 生成Ken Burns运动效果
323
346
  - **成本优化**:如果你判断当前运镜方式可以用Ken Burns实现(如简单的缩放、平移效果),优先使用 `generate-video-kenburns` 以节省成本
324
347
  - **Ken Burns特效选择规则**:
@@ -332,7 +355,7 @@ VideoProject 支持 xfade 转场滤镜,在 `timeline.tracks[].clips[]` 中配
332
355
 
333
356
  ### B. 科学原理解释
334
357
  * 科学原理、物理现象、数学概念可视化
335
- * 使用`generate-video-from-html-animation`创建HTML动画
358
+ * 使用`generate-principle-video`创建科学原理演示动画
336
359
  * 工作流:HTML动画 → MP4视频 → 集成到timeline
337
360
 
338
361
  ### C. 本地图片素材
@@ -351,7 +374,11 @@ VideoProject 支持 xfade 转场滤镜,在 `timeline.tracks[].clips[]` 中配
351
374
  * **配音优先**:先生成配音确定时长,再生成对应视频(视频时长=ceil(配音时长秒数),范围3-12秒)
352
375
  * **时长控制**:如配音超过12秒,将无法正确返回,需简化台词、提升语速或拆分成两个场景
353
376
  * **备选方案**:视频多次生成失败时使用`generate-video-kenburns`
354
- * **字幕同步**:基于配音生成字幕,确保时间轴对齐
377
+ * **⚠️ 时间轴计算规则**:
378
+ - **视频时长永远是整秒**:所有视频clip的durationMs必须是1000的倍数
379
+ - **时间轴以视频为准**:timeline中的startMs和durationMs基于视频的整秒时长计算,不是配音的精确毫秒数
380
+ - **配音时长仅用于确定视频时长**:配音7008ms → 视频8000ms,时间轴使用8000ms
381
+ * **字幕同步**:基于配音生成字幕,但时间轴与视频时间轴对齐(整秒),不是配音的精确时长
355
382
  * **时间轴独立性**:配音和字幕的时间轴必须与视频内容严格同步,不受转场特效配置影响,转场滤镜只影响视觉过渡效果
356
383
  * **统一命名**:`scXX_*`、`main_bgm_*`、`*_vo.*`
357
384
  * **时长控制**:单镜头3-12s,整片30-90s
@@ -374,4 +401,4 @@ VideoProject 支持 xfade 转场滤镜,在 `timeline.tracks[].clips[]` 中配
374
401
  * **60s超时**:提高长任务超时设置
375
402
  * **渲染失败**:检查VideoProject路径、素材、参数
376
403
  * **素材未同步**:用`list-project-files`核对
377
- * **沙箱中断**:重新调用`zerocut-project-open`打开新沙箱
404
+ * **沙箱中断**:重新调用`zerocut-project-open`打开新沙箱
@@ -1 +1 @@
1
- {"version":3,"file":"zerocut.d.ts","sourceRoot":"","sources":["../../../src/mcp/servers/zerocut.ts"],"names":[],"mappings":";AA2tDA,wBAAsB,GAAG,kBAKxB"}
1
+ {"version":3,"file":"zerocut.d.ts","sourceRoot":"","sources":["../../../src/mcp/servers/zerocut.ts"],"names":[],"mappings":";AAkvDA,wBAAsB,GAAG,kBAKxB"}
@@ -562,7 +562,7 @@ server.registerTool('generate-image', {
562
562
  console.log(`Generating image with prompt: ${processedPrompt.substring(0, 100)}...`);
563
563
  const ai = currentSession.ai;
564
564
  const res = await ai.generateImage({
565
- prompt: `${processedPrompt.trim()}。除去前面指定生成的文字(如有)外,**禁止**自行生成任何类文字(不论CJK还是拉丁字母)的符号。`,
565
+ prompt: `${processedPrompt.trim()}\n\n假如图片中有未提及的文字符号,使用高斯模糊虚化文字符号。`,
566
566
  size,
567
567
  watermark,
568
568
  });
@@ -847,11 +847,13 @@ server.registerTool('generate-video-kenburns', {
847
847
  return createErrorResponse(error, 'generate-video-kenburns');
848
848
  }
849
849
  });
850
- server.registerTool('generate-video-from-html-animation', {
851
- title: 'Generate Video from HTML Animation',
852
- description: 'Generate the video from html animation.',
850
+ server.registerTool('generate-principle-video', {
851
+ title: 'Generate Principle Video',
852
+ description: 'Generate principle demonstration video with scientific concepts and animations.',
853
853
  inputSchema: {
854
- html: zod_1.z.string().describe('The html to generate.'),
854
+ userPrompt: zod_1.z
855
+ .string()
856
+ .describe('The principle or concept to demonstrate.'),
855
857
  duration: zod_1.z
856
858
  .number()
857
859
  .min(3)
@@ -868,23 +870,30 @@ server.registerTool('generate-video-from-html-animation', {
868
870
  '1248x832',
869
871
  '1512x648',
870
872
  ])
871
- .describe('The size of the image.'),
873
+ .describe('The size of the video.'),
872
874
  saveToFileName: zod_1.z.string().describe('The filename to save.'),
873
875
  },
874
- }, async ({ html, duration, size, saveToFileName }) => {
876
+ }, async ({ userPrompt, duration, size, saveToFileName }, context) => {
875
877
  try {
876
878
  // 验证session状态
877
- const currentSession = validateSession('generate-video-from-html');
879
+ const currentSession = validateSession('generate-principle-video');
878
880
  const [width, height] = size.split('x').map(Number);
879
881
  const ai = currentSession.ai;
880
- const res = await ai.htmlToVideo({
881
- html,
882
+ // 使用 generatePrincipleVideo 方法
883
+ const resString = await ai.generatePrincipleVideo({
884
+ userPrompt,
882
885
  duration,
883
886
  width,
884
887
  height,
888
+ onProgress: metaData => {
889
+ // 发送进度更新
890
+ sendProgress(context, metaData.progress || 0, metaData.total || 100, `Generating principle video: ${metaData.status || 'processing'}`);
891
+ },
885
892
  });
886
- if (res.success) {
887
- console.log('Video generated successfully, saving to materials...');
893
+ // 解析返回的 JSON 字符串
894
+ const res = JSON.parse(resString);
895
+ if (res.status === 'success' && res.url) {
896
+ console.log('Principle video generated successfully, saving to materials...');
888
897
  const uri = await saveMaterial(currentSession, res.url, saveToFileName);
889
898
  return {
890
899
  content: [
@@ -895,25 +904,33 @@ server.registerTool('generate-video-from-html-animation', {
895
904
  uri,
896
905
  source: res.url,
897
906
  durationMs: Math.floor(duration) * 1000,
907
+ principle: userPrompt,
908
+ dimensions: { width, height },
909
+ timestamp: new Date().toISOString(),
898
910
  }),
899
911
  },
900
912
  ],
901
913
  };
902
914
  }
903
915
  else {
904
- console.error('Failed to generate video:', res);
916
+ console.error('Failed to generate principle video:', res);
905
917
  return {
906
918
  content: [
907
919
  {
908
920
  type: 'text',
909
- text: JSON.stringify(res),
921
+ text: JSON.stringify({
922
+ success: false,
923
+ error: res.error || 'Unknown error occurred',
924
+ principle: userPrompt,
925
+ timestamp: new Date().toISOString(),
926
+ }),
910
927
  },
911
928
  ],
912
929
  };
913
930
  }
914
931
  }
915
932
  catch (error) {
916
- return createErrorResponse(error, 'generate-video-from-html');
933
+ return createErrorResponse(error, 'generate-principle-video');
917
934
  }
918
935
  });
919
936
  server.registerTool('generate-bgm', {