@starreel/mcp 0.1.83 → 0.1.85

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.
package/SKILL.md CHANGED
@@ -206,6 +206,15 @@ content that will be rejected.
206
206
  character with `set_character_voice` only when you actually need it to
207
207
  dub a shot. Always pass that same `voice_id` — never a raw number from
208
208
  somewhere else.
209
+ **In native-audio dramas (`use_clip_audio=true`, the default) binding the
210
+ customer's own authorized voice is how you lock a character's voice**:
211
+ videos generated *after* the binding hand that voice to the video vendor as
212
+ a reference audio, so the character sounds the same in every shot (public
213
+ library voices are TTS-only and are not sent). Trade-off: that character's
214
+ shots stop using the portrait-video anchor, so identity rests on the
215
+ portrait/sheet — have those ready first. Bind **before** `generate_videos`;
216
+ for videos that already exist, use `repair_episode_dialogue`
217
+ (`only_flagged=false`) rather than regenerating whole episodes.
209
218
 
210
219
  6. **Follow the pipeline order — do not skip.** `set_script` → `rewrite_script`
211
220
  → `extract_assets` → portraits **+ sheets** → storyboards → frames → videos.
@@ -685,6 +694,40 @@ constraint is already in the prompt and was measured ineffective). The only
685
694
  real fix is `regenerate_shot_video` on those shots after switching the drama to
686
695
  `seedance-2.5` or `hailuo-3`.
687
696
 
697
+ ### "动作太慢" / "没演出来" / "像快进" — motion speed inside a shot
698
+
699
+ Everything here was measured by comparing versions of the same shot. Work
700
+ through it in this order, per shot (`get_shot_prompts` first — you need the
701
+ current `video_prompt` and what the first frame shows):
702
+
703
+ 1. **Check the shot size before the wording.** Wide / full shots cannot show
704
+ small motion (a face, a hand, an ear): measured motion on wide shots was a
705
+ fraction of the same batch's medium shots. If the action is small, change
706
+ `shot_type` to medium or closer (`update_shot`), then `generate_shot_frame`
707
+ and regenerate the video. Rewording a wide shot was tried twice in the
708
+ measured case and failed both times.
709
+ 2. **Density comes from the number of beats, not verb strength.** Deleting
710
+ "slow / gently / unhurried" was measured to have **no** effect. What worked:
711
+ write the `video_prompt` as beats — about **3 beats for 5 seconds, 2 beats
712
+ for 3 seconds** ("beat 1 … beat 2 … beat 3 …"), so more actually *happens*
713
+ in those seconds. Adding "one continuous take, no cuts" helps keep the
714
+ vendor from cutting inside the clip.
715
+ 3. **Start from the first frame.** The action must continue from the exact
716
+ moment the first frame shows. If the prompt's starting state contradicts the
717
+ frame, the vendor cannot bridge it in one camera move and cuts instead.
718
+ 4. **Move beats and `duration` together.** 3 beats squeezed into 3 seconds
719
+ reads as fast-forward; lengthening a shot without adding beats only makes it
720
+ slower. Then `regenerate_shot_video` (quote first).
721
+
722
+ `speed_factor` (`update_shot`, 0.5–2.0, `null` clears) is **playback speed in
723
+ the final cut only** — free, no regeneration, but it does not change what the
724
+ vendor animated, so it cannot fix "nothing happens". Use it for deliberate slow
725
+ motion; avoid it on dialogue shots (the voice speeds up / slows down too).
726
+
727
+ The platform's default shot breakdown still asks for one continuous action per
728
+ shot. Apply the beat approach shot by shot on complaints; don't rewrite a whole
729
+ episode this way unprompted.
730
+
688
731
  ### "画面里多出一个人 / 多出一件道具" — something appears that shouldn't be there
689
732
 
690
733
  Two completely different causes with opposite fixes. **Look at the shot's own
@@ -95,8 +95,11 @@ export const ENTRY_POINTS = [
95
95
  'set_character_voice(绑到角色;传 voice_id 如 lib:12)',
96
96
  'assign_voices',
97
97
  ],
98
- note: '所有项目默认视频原声(use_clip_audio=true,跳过 TTS);要配音把它设 false,并主动告诉客户可切换。',
99
- flow: 'clone_voice → speak_with_voice(试听) → set_character_voice / assign_voices',
98
+ note: '所有项目默认视频原声(use_clip_audio=true,跳过 TTS);要配音把它设 false,并主动告诉客户可切换。' +
99
+ '★原声剧里 set_character_voice 绑客户自己的授权音色 = 锁声线:之后出的视频把它交给厂商当参考音频,前后镜声线一致;' +
100
+ '代价是该角色的镜不再喂定妆视频锚、身份靠定妆图/设定图。只对绑定之后出的视频生效——先绑再出视频;' +
101
+ '已出好的视频用 repair_episode_dialogue(only_flagged=false)换轨统一,别整集重生。',
102
+ flow: 'clone_voice → speak_with_voice(试听) → set_character_voice(原声剧:在 generate_videos 之前) / assign_voices',
100
103
  },
101
104
  {
102
105
  customer_has: '歌曲 + 歌词(MV)',
@@ -244,6 +247,16 @@ export const REVIEW_GATE_RULE = '三道闸全部免费、服务端强制(跳过
244
247
  export const QA_TOOLS = [
245
248
  { symptom: '话没说完就切 / 台词跑到别的镜上', run: 'scan_dialogue_coverage', then: ['repair_episode_dialogue(首选:换音频不重生,便宜)', 'regenerate_shot_video(特写镜或画面也错时)', 'compose_episode'] },
246
249
  { symptom: '切太快 / 一个镜头里画面跳来跳去', run: 'scan_intra_shot_cuts', then: ['update_project_settings(video_engine 改 seedance-2.5 或 hailuo-3)', 'regenerate_shot_video'] },
250
+ // 「动作太慢」的判据全部来自实测(同剧同镜多版对照):删 slow/缓慢这类措辞没有可测效果;
251
+ // 远景镜的运动量整体只有中景的几分之一;把更多节拍放进同样秒数才真的更有动感。
252
+ // ★只作为逐镜修法给 agent,平台默认拆镜规则不在这里改(等运动量基线攒够再裁决)。
253
+ { symptom: '动作太慢 / 没演出来 / 像快进', run: 'get_shot_prompts(先读 video_prompt 与 first_frame_prompt,看首帧画的是哪一刻)', then: [
254
+ 'update_shot(shot_type:远景/全景演不出表情、手部这类细微动作——要看清就改成中景或更近,再 generate_shot_frame 重出首帧;这是分镜问题,改措辞没用)',
255
+ 'update_shot(video_prompt:按节拍写——约 5 秒写 3 拍、3 秒写 2 拍,「第一拍…第二拍…第三拍…」,让这几秒里发生更多事;只删 slow/缓慢/轻轻这类词实测没有效果;动作必须从首帧画的那一刻往后接,起点与首帧矛盾时厂商会自己剪一刀;可加一句「一镜到底、不切镜」)',
256
+ 'update_shot(duration:动作量与时长同向调——3 拍塞进 3 秒就是「像快进」;反过来,只加长不加拍只会更慢)',
257
+ 'regenerate_shot_video(改完 prompt/时长要重出视频才生效,走报价)',
258
+ 'update_shot(speed_factor:只是成片里变速播放,不改厂商生成的内容——做慢镜氛围用,治不了「没演出来」)',
259
+ ] },
247
260
  { symptom: '动作发生在裁剪窗口之外', run: 'recommend_trim_window', then: ['trim_shot'] },
248
261
  { symptom: '画面多出一个人 / 多出一件道具', run: 'get_storyboards(先看该镜实际用的首帧)', then: ['generate_shot_frame(首帧本身就有→重生首帧再重生视频)', 'split_shot(帧干净、片中长出来→拆成 3~5 秒短镜)'] },
249
262
  { symptom: '出图 / 出视频前想知道哪些镜会被厂商拒', run: 'run_precheck', then: ['update_shot', 'generate_shot_frame'] },
@@ -1156,7 +1156,7 @@ export function registerProduceTools(server, client) {
1156
1156
  const suffix = qs.toString() ? `?${qs.toString()}` : '';
1157
1157
  return jsonResult(await client.produceGet(`/episodes/${episode_id}/dialogue-coverage${suffix}`));
1158
1158
  });
1159
- server.tool('update_shot', '逐镜编辑:改单个分镜的文本内容(景别/动作/台词/画面描述/运镜等)与角色绑定(character_ids)。只传要改的字段、其余不动。' +
1159
+ server.tool('update_shot', '逐镜编辑:改单个分镜的文本内容(景别/动作/台词/画面描述/运镜等)、时长(duration)、成片变速(speed_factor)与角色绑定(character_ids)。只传要改的字段、其余不动。' +
1160
1160
  '**免费**(纯文本写库)。★改 dialogue 会自动失效本镜已生成的 TTS 配音与字幕(需重出 tts);' +
1161
1161
  '改文本不会自动重出图/视频,如需让画面跟上文本改动,改完再 regen 对应镜。用 get_storyboards 查改后结果。' +
1162
1162
  '★★原声镜(厂商原生音频)改 dialogue 后,本镜视频会被标记「待重生」——因为台词是**烤进视频人声**的,' +
@@ -1185,6 +1185,8 @@ export function registerProduceTools(server, client) {
1185
1185
  atmosphere: z.string().optional().describe('氛围'),
1186
1186
  director_note: z.string().optional().describe('导演注释'),
1187
1187
  shot_intent: z.string().optional().describe('这镜为什么存在(叙事意图)'),
1188
+ duration: z.number().positive().optional().describe('本镜时长(秒,可带小数如 2.5)。上限=本剧视频引擎的单镜上限,超出直接拒并告知上限(更长内容用 split_shot 拆镜)。有台词时平台按语速律只抬不降,抬了会在回执 speech_duration_note 里说。★改时长不会自动重出视频:已有视频仍是旧长度,要厂商按新时长出就 regenerate_shot_video(报价按新时长算)。★别拿加长治「动作太慢」——同样的动作摊到更长时间里只会更慢,见 qa_tools「动作太慢」'),
1189
+ speed_factor: z.number().positive().nullable().optional().describe('成片变速:<1 慢镜、>1 快放、null 清除(0.5–2.0,越界被钳到范围内)。只在终拼/剪映导出时变速播放(画面 setpts + 声音 atempo,音高不变),**不重出视频、不扣费**,但会改变本镜在成片里占的时长。适合做慢镜/升格氛围;治不了「动作没演出来」——那是视频内容本身,要改 video_prompt 重出。有台词的镜慎用(人声也跟着变快变慢)'),
1188
1190
  image_prompt: z.string().optional().describe('首帧画面提示词**正文**(全量覆盖本镜现值)。★先 get_shot_prompts 读现值再改;★原样保留其中的 @char:N / @scene:M 引用标记,删了就不注入对应定妆图/场景图。出图时平台会在正文之上再拼身份锚与一致性约束,不必你写。★写法坑:别写「no X / without X / 不要 X / 没有 X」这类否定式约束——图像模型把名词当正向线索,反而把 X 画出来;要正向写出那块画面该有什么(材质/形状/颜色/远近)。保存响应带 image_prompt_negation_advisory 即命中,按其 note 改写'),
1189
1191
  video_prompt: z.string().optional().describe('视频(动态/运镜/表演)提示词**正文**(全量覆盖本镜现值)。★同 image_prompt:先读现值、保留 @char/@scene 标记'),
1190
1192
  first_frame_prompt: z.string().optional().describe('本镜**开始时**画面是什么样(首帧目标状态正文,全量覆盖现值)。送达提示词里作为 [START FRAME] 段排在最前,优先级高于 image_prompt——所以 image_prompt 改了不生效时,往往是这条在压着它。★同 image_prompt:先 get_shot_prompts 读现值、原样保留 @char/@scene 标记'),
@@ -1207,7 +1209,9 @@ export function registerProduceTools(server, client) {
1207
1209
  '★它也是「这一镜台词没念完/念了别的」最经济的修法:用克隆音重配整句并静音原声段,' +
1208
1210
  '**不重新生成视频**——按 TTS 档(千字符)计费,比 regenerate_shot_video(720p 212 点/秒)低几个数量级。' +
1209
1211
  '代价:画面口型是按原音演的,换音后可能对不上;口型看不清的镜(背身/远景/画外)几乎无损,大特写慎用。' +
1210
- '整集批量用 repair_episode_dialogue。', { storyboard_id: z.number().int().positive() }, async ({ storyboard_id }) => jsonResult(await client.producePost(`/storyboards/${storyboard_id}/dialogue-replace`)));
1212
+ '★产物自动写回该镜(返回 persisted:true),但**进不进成片**取决于本集是否每镜都已合成:' +
1213
+ '用 get_dialogue_repair_status 看 productEffective / pendingCompose,为 false 就先补合成再 rerender_episode,' +
1214
+ '否则成片仍是旧音频。整集批量用 repair_episode_dialogue。', { storyboard_id: z.number().int().positive() }, async ({ storyboard_id }) => jsonResult(await client.producePost(`/storyboards/${storyboard_id}/dialogue-replace`)));
1211
1215
  server.tool('repair_episode_dialogue', '★整集批量修「台词没念完/念了别的」。默认只修 scan_dialogue_coverage 判为有缺陷的镜' +
1212
1216
  '(truncated/off_script/extra_speech);minor_gap 那一族是转写误差、原声本来是好的,不动。' +
1213
1217
  '原理与 replace_shot_dialogue 相同:克隆音重配整句 + 静音原声段,**不重新生成视频**——' +
@@ -1314,6 +1318,7 @@ export function registerProduceTools(server, client) {
1314
1318
  // ========== P1 · 整集配音(成片前的强制音频步)==========
1315
1319
  server.tool('assign_voices', '★给本集所有角色分配音色(配音导演 agent 按性别/性格/年龄/角色定位+项目语言选)。' +
1316
1320
  'voiceStyle 不是提取时自动填的——不分配,generate_tts 就没音色。文本步(LLM)后付。' +
1321
+ '已用 set_character_voice 绑了客户自己授权音色的角色会被锁定、不会被改成别的音色。' +
1317
1322
  '后台异步,轮询 get_pipeline_status:assign_voices=done 即完成,再 generate_tts。', { episode_id: z.number().int().positive() }, async ({ episode_id }) => jsonResult(await client.producePost(`/episodes/${episode_id}/assign-voices`)));
1318
1323
  server.tool('generate_tts', '给整集所有对白批量配音(TTS)。成片前的音频步——不配音成片会缺对白。前置:先 assign_voices 给角色分配音色。后台异步,按用量后付不欠费。', { episode_id: z.number().int().positive() }, async ({ episode_id }) => jsonResult(await client.producePost(`/episodes/${episode_id}/tts`)));
1319
1324
  // ========== P1 · MV 子流程(project_type=mv 专用)==========
@@ -1506,7 +1511,17 @@ export function registerProduceTools(server, client) {
1506
1511
  server.tool('list_voices', '列出可用音色:我克隆的私有音色 + 平台公共音色(voice_id/名字/试听样本)。免费。', {}, async () => jsonResult(await client.produceGet('/voice-clones')));
1507
1512
  server.tool('delete_voice', '删除我音色库里的一个克隆音色(平台公共音色不可删)。免费。', { voice_id: z.string().describe('形如 lib:12') }, async ({ voice_id }) => jsonResult(await client.produceDelete(`/voice-clones/${String(voice_id).replace(/^lib:/, '')}`)));
1508
1513
  server.tool('set_character_voice', '把音色绑到某角色,之后 generate_tts 用它给该角色配音。免费。' +
1509
- '只有要出片时才需要这步——克隆和试听都不需要角色。', {
1514
+ '只有要出片时才需要这步——克隆和试听都不需要角色。' +
1515
+ '\n★★【原声剧(use_clip_audio=true,默认)里这一步就是「锁声线」】绑的是**客户自己的授权音色**' +
1516
+ '(clone_voice 克隆的 / 客户上传的,不是公共音色)时,之后生成的视频会把这段声音直接交给视频厂商当参考音频,' +
1517
+ '厂商按它发声、口型天然同步——否则每个组/单镜各自采样嗓音,同一角色前后镜声线会漂。' +
1518
+ '公共音色只用于 TTS 配音,不会交给厂商。' +
1519
+ '\n★代价:该角色出场的镜头生成视频时不再喂定妆视频锚(参考视频的音轨会压过参考音频,只能二选一),' +
1520
+ '人物身份改由定妆图/设定图承担——所以绑之前先确认定妆图、设定图已经到位。' +
1521
+ '\n★只对**绑定之后**生成的视频生效:要先绑、再 generate_videos。已经出好的视频要统一声线,' +
1522
+ '用 repair_episode_dialogue(only_flagged=false,克隆音重配整句、不重生视频、按 TTS 档计费)最省;' +
1523
+ '重生视频(regenerate_shot_video)也行但贵几个数量级。' +
1524
+ '\n★绑好后 assign_voices 不会再覆盖这个角色(客户自己的声音优先级最高)。', {
1510
1525
  character_id: z.number().int().positive(),
1511
1526
  voice_id: z.string().describe('来自 clone_voice / list_voices 的 voice_id(形如 lib:12)'),
1512
1527
  }, async ({ character_id, voice_id }) => jsonResult(await client.producePost(`/characters/${character_id}/voice`, { voice_id })));
package/openapi.json CHANGED
@@ -2,8 +2,8 @@
2
2
  "openapi": "3.1.0",
3
3
  "info": {
4
4
  "title": "StarReel Production API",
5
- "version": "0.1.83",
6
- "description": "Turn a script into a finished, downloadable short-drama episode over REST.\n\nPipeline: script → AI rewrite → cast/scenes/props extraction → storyboards → portraits & sheets + scene plates → keyframes → video shots → TTS → final cut (.mp4).\n\n**Billing is prepaid and agent-safe**: big-ticket stages are quote-then-generate (`quote_*` returns a `quote_id`). For video, quote == actual charge. For images the quote is a *range* — models billed per reference image are priced before those are assembled, so `estimated_points` is the upper bound (size the balance by it and a run never dies half-way) and `typical_points` is the usual cost; fixed-price models return the two equal. Insufficient balance returns 402 — nothing half-runs and the account never goes negative.\n\nAuth: exchange your API key at `POST /v1/agent/token` for a 15-minute bearer token.\n\nGenerated from the @starreel/mcp v0.1.83 tool surface (operationIds match MCP tool names 1:1)."
5
+ "version": "0.1.85",
6
+ "description": "Turn a script into a finished, downloadable short-drama episode over REST.\n\nPipeline: script → AI rewrite → cast/scenes/props extraction → storyboards → portraits & sheets + scene plates → keyframes → video shots → TTS → final cut (.mp4).\n\n**Billing is prepaid and agent-safe**: big-ticket stages are quote-then-generate (`quote_*` returns a `quote_id`). For video, quote == actual charge. For images the quote is a *range* — models billed per reference image are priced before those are assembled, so `estimated_points` is the upper bound (size the balance by it and a run never dies half-way) and `typical_points` is the usual cost; fixed-price models return the two equal. Insufficient balance returns 402 — nothing half-runs and the account never goes negative.\n\nAuth: exchange your API key at `POST /v1/agent/token` for a 15-minute bearer token.\n\nGenerated from the @starreel/mcp v0.1.85 tool surface (operationIds match MCP tool names 1:1)."
7
7
  },
8
8
  "servers": [
9
9
  {
@@ -493,7 +493,7 @@
493
493
  "post": {
494
494
  "operationId": "set_character_voice",
495
495
  "summary": "把音色绑到某角色,之后 generate_tts 用它给该角色配音",
496
- "description": "把音色绑到某角色,之后 generate_tts 用它给该角色配音。免费。只有要出片时才需要这步——克隆和试听都不需要角色。",
496
+ "description": "把音色绑到某角色,之后 generate_tts 用它给该角色配音。免费。只有要出片时才需要这步——克隆和试听都不需要角色。\n★★【原声剧(use_clip_audio=true,默认)里这一步就是「锁声线」】绑的是**客户自己的授权音色**(clone_voice 克隆的 / 客户上传的,不是公共音色)时,之后生成的视频会把这段声音直接交给视频厂商当参考音频,厂商按它发声、口型天然同步——否则每个组/单镜各自采样嗓音,同一角色前后镜声线会漂。公共音色只用于 TTS 配音,不会交给厂商。\n★代价:该角色出场的镜头生成视频时不再喂定妆视频锚(参考视频的音轨会压过参考音频,只能二选一),人物身份改由定妆图/设定图承担——所以绑之前先确认定妆图、设定图已经到位。\n★只对**绑定之后**生成的视频生效:要先绑、再 generate_videos。已经出好的视频要统一声线,用 repair_episode_dialogue(only_flagged=false,克隆音重配整句、不重生视频、按 TTS 档计费)最省;重生视频(regenerate_shot_video)也行但贵几个数量级。\n★绑好后 assign_voices 不会再覆盖这个角色(客户自己的声音优先级最高)。",
497
497
  "tags": [
498
498
  "characters"
499
499
  ],
@@ -2835,7 +2835,7 @@
2835
2835
  "post": {
2836
2836
  "operationId": "assign_voices",
2837
2837
  "summary": "★给本集所有角色分配音色(配音导演 agent 按性别/性格/年龄/角色定位+项目语言选)",
2838
- "description": "★给本集所有角色分配音色(配音导演 agent 按性别/性格/年龄/角色定位+项目语言选)。voiceStyle 不是提取时自动填的——不分配,generate_tts 就没音色。文本步(LLM)后付。后台异步,轮询 get_pipeline_status:assign_voices=done 即完成,再 generate_tts。",
2838
+ "description": "★给本集所有角色分配音色(配音导演 agent 按性别/性格/年龄/角色定位+项目语言选)。voiceStyle 不是提取时自动填的——不分配,generate_tts 就没音色。文本步(LLM)后付。已用 set_character_voice 绑了客户自己授权音色的角色会被锁定、不会被改成别的音色。后台异步,轮询 get_pipeline_status:assign_voices=done 即完成,再 generate_tts。",
2839
2839
  "tags": [
2840
2840
  "episodes"
2841
2841
  ],
@@ -8225,8 +8225,8 @@
8225
8225
  "/storyboards/{storyboard_id}": {
8226
8226
  "put": {
8227
8227
  "operationId": "update_shot",
8228
- "summary": "逐镜编辑:改单个分镜的文本内容(景别/动作/台词/画面描述/运镜等)与角色绑定(character_ids)",
8229
- "description": "逐镜编辑:改单个分镜的文本内容(景别/动作/台词/画面描述/运镜等)与角色绑定(character_ids)。只传要改的字段、其余不动。**免费**(纯文本写库)。★改 dialogue 会自动失效本镜已生成的 TTS 配音与字幕(需重出 tts);改文本不会自动重出图/视频,如需让画面跟上文本改动,改完再 regen 对应镜。用 get_storyboards 查改后结果。★★原声镜(厂商原生音频)改 dialogue 后,本镜视频会被标记「待重生」——因为台词是**烤进视频人声**的,不重生就终拼,成片里念的仍是改动前的台词(典型现象:台词像是跑到了别的镜头上)。compose_episode 会以 advisory `stale_video_after_edit` 列出这些镜;正确处置是先 regenerate_shot_video 再终拼。★也可直接改本镜的四条提示词正文(image_prompt/video_prompt/first_frame_prompt/last_frame_prompt):改前先用 get_shot_prompts 读现值,别凭空覆盖——正文里的 @char:N / @scene:M 是角色/场景参考图的引用标记,删掉本镜就不注入对应定妆图/场景图(形象漂移)。★★【出尾帧被拦下就是来改这里】出尾帧若报「此镜标为状态改变,但没有任何地方说明结束时是什么样子」(TERMINAL_DESC_GATE),修法是把**结束时画面是什么样**写进本镜 last_frame_prompt,然后重新出尾帧。别去重试出图——这类镜(action_motion_class=state_change 却没写终态)的尾帧历史成功率 9.4%,有终态描述的是 40.2%;不补描述就重生,送厂商的提示词里根本没有终态段,画出来仍和首帧一样、还是会被拒,而每次重生都照常扣费。get_shot_prompts 的 terminal_desc_missing=true 就是这个信号。",
8228
+ "summary": "逐镜编辑:改单个分镜的文本内容(景别/动作/台词/画面描述/运镜等)、时长(duration)、成片变速(speed_factor)与角色绑定(character_ids)",
8229
+ "description": "逐镜编辑:改单个分镜的文本内容(景别/动作/台词/画面描述/运镜等)、时长(duration)、成片变速(speed_factor)与角色绑定(character_ids)。只传要改的字段、其余不动。**免费**(纯文本写库)。★改 dialogue 会自动失效本镜已生成的 TTS 配音与字幕(需重出 tts);改文本不会自动重出图/视频,如需让画面跟上文本改动,改完再 regen 对应镜。用 get_storyboards 查改后结果。★★原声镜(厂商原生音频)改 dialogue 后,本镜视频会被标记「待重生」——因为台词是**烤进视频人声**的,不重生就终拼,成片里念的仍是改动前的台词(典型现象:台词像是跑到了别的镜头上)。compose_episode 会以 advisory `stale_video_after_edit` 列出这些镜;正确处置是先 regenerate_shot_video 再终拼。★也可直接改本镜的四条提示词正文(image_prompt/video_prompt/first_frame_prompt/last_frame_prompt):改前先用 get_shot_prompts 读现值,别凭空覆盖——正文里的 @char:N / @scene:M 是角色/场景参考图的引用标记,删掉本镜就不注入对应定妆图/场景图(形象漂移)。★★【出尾帧被拦下就是来改这里】出尾帧若报「此镜标为状态改变,但没有任何地方说明结束时是什么样子」(TERMINAL_DESC_GATE),修法是把**结束时画面是什么样**写进本镜 last_frame_prompt,然后重新出尾帧。别去重试出图——这类镜(action_motion_class=state_change 却没写终态)的尾帧历史成功率 9.4%,有终态描述的是 40.2%;不补描述就重生,送厂商的提示词里根本没有终态段,画出来仍和首帧一样、还是会被拒,而每次重生都照常扣费。get_shot_prompts 的 terminal_desc_missing=true 就是这个信号。",
8230
8230
  "tags": [
8231
8231
  "storyboards"
8232
8232
  ],
@@ -8291,6 +8291,14 @@
8291
8291
  "shot_intent": {
8292
8292
  "type": "string"
8293
8293
  },
8294
+ "duration": {
8295
+ "type": "number",
8296
+ "exclusiveMinimum": 0
8297
+ },
8298
+ "speed_factor": {
8299
+ "type": "number",
8300
+ "exclusiveMinimum": 0
8301
+ },
8294
8302
  "image_prompt": {
8295
8303
  "type": "string"
8296
8304
  },
@@ -8340,7 +8348,7 @@
8340
8348
  "post": {
8341
8349
  "operationId": "replace_shot_dialogue",
8342
8350
  "summary": "换某镜对白音色/声线(转写+克隆重配)",
8343
- "description": "换某镜对白音色/声线(转写+克隆重配)。后台异步,按用量后付不欠费。要求本镜有原声视频+角色声线定妆音。★它也是「这一镜台词没念完/念了别的」最经济的修法:用克隆音重配整句并静音原声段,**不重新生成视频**——按 TTS 档(千字符)计费,比 regenerate_shot_video(720p 212 点/秒)低几个数量级。代价:画面口型是按原音演的,换音后可能对不上;口型看不清的镜(背身/远景/画外)几乎无损,大特写慎用。整集批量用 repair_episode_dialogue。",
8351
+ "description": "换某镜对白音色/声线(转写+克隆重配)。后台异步,按用量后付不欠费。要求本镜有原声视频+角色声线定妆音。★它也是「这一镜台词没念完/念了别的」最经济的修法:用克隆音重配整句并静音原声段,**不重新生成视频**——按 TTS 档(千字符)计费,比 regenerate_shot_video(720p 212 点/秒)低几个数量级。代价:画面口型是按原音演的,换音后可能对不上;口型看不清的镜(背身/远景/画外)几乎无损,大特写慎用。★产物自动写回该镜(返回 persisted:true),但**进不进成片**取决于本集是否每镜都已合成:用 get_dialogue_repair_status 看 productEffective / pendingCompose,为 false 就先补合成再 rerender_episode,否则成片仍是旧音频。整集批量用 repair_episode_dialogue。",
8344
8352
  "tags": [
8345
8353
  "storyboards"
8346
8354
  ],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@starreel/mcp",
3
- "version": "0.1.83",
3
+ "version": "0.1.85",
4
4
  "mcpName": "ai.starreel/starreel",
5
5
  "description": "StarReel MCP server — drive the AI short-drama production pipeline (script → storyboards → frames → video → final cut) from Claude, Cursor, or any MCP client",
6
6
  "license": "MIT",
package/server.json CHANGED
@@ -2,13 +2,13 @@
2
2
  "$schema": "https://static.modelcontextprotocol.io/schemas/2025-09-29/server.schema.json",
3
3
  "name": "ai.starreel/starreel",
4
4
  "description": "Turn a script into a finished, downloadable short-drama episode — via MCP or REST.",
5
- "version": "0.1.83",
5
+ "version": "0.1.85",
6
6
  "websiteUrl": "https://starreel.ai",
7
7
  "packages": [
8
8
  {
9
9
  "registryType": "npm",
10
10
  "identifier": "@starreel/mcp",
11
- "version": "0.1.83",
11
+ "version": "0.1.85",
12
12
  "transport": {
13
13
  "type": "stdio"
14
14
  },