@oh-story/dsh 0.1.9 → 0.1.10

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.
Files changed (197) hide show
  1. package/README.md +12 -12
  2. package/lib/client.js +204 -72
  3. package/lib/client.js.map +3 -3
  4. package/lib/drama/manifest.json +84 -74
  5. package/lib/drama/skills/short-drama/SKILL.md +2 -2
  6. package/lib/drama/skills/short-drama/scripts/creator_markdown_check.py +14 -0
  7. package/lib/drama/skills/short-drama-assets/references/character-and-look.md +10 -0
  8. package/lib/drama/skills/short-drama-assets/references/continuity-lock.md +6 -9
  9. package/lib/drama/skills/short-drama-assets/references/voice-direction.md +28 -0
  10. package/lib/drama/skills/short-drama-edit/SKILL.md +27 -29
  11. package/lib/drama/skills/short-drama-edit/assets//345/211/252/350/276/221/345/215/225.md +2 -2
  12. package/lib/drama/skills/short-drama-edit/references/cut-craft.md +24 -67
  13. package/lib/drama/skills/short-drama-edit/references/delivery-verify.md +27 -56
  14. package/lib/drama/skills/short-drama-edit/references/generated-footage.md +37 -79
  15. package/lib/drama/skills/short-drama-edit/references/sound-and-subtitles.md +39 -92
  16. package/lib/drama/skills/short-drama-edit/references/stage-contract.md +12 -16
  17. package/lib/drama/skills/short-drama-edit/scripts/edit_tool.py +126 -11
  18. package/lib/drama/skills/short-drama-edit/scripts/selftest.py +64 -0
  19. package/lib/drama/skills/short-drama-image-prompts/SKILL.md +2 -0
  20. package/lib/drama/skills/short-drama-image-prompts/references/common-recipe.md +11 -0
  21. package/lib/drama/skills/short-drama-produce/SKILL.md +5 -1
  22. package/lib/drama/skills/short-drama-produce/references/adapter-contract.md +14 -20
  23. package/lib/drama/skills/short-drama-produce/references/providers/minimax-h3-video.md +8 -26
  24. package/lib/drama/skills/short-drama-produce/references/providers/minimax-speech.md +41 -0
  25. package/lib/drama/skills/short-drama-produce/scripts/provider_adapters.py +142 -1
  26. package/lib/drama/skills/short-drama-review/SKILL.md +2 -3
  27. package/lib/drama/skills/short-drama-review/references/production-quality-gates.md +6 -19
  28. package/lib/drama/skills/short-drama-review/references/rubric-visual-motion.md +9 -35
  29. package/lib/drama/skills/short-drama-storyboard/SKILL.md +10 -6
  30. package/lib/drama/skills/short-drama-storyboard/references/lighting-craft.md +39 -0
  31. package/lib/drama/skills/short-drama-storyboard/references/shot-craft.md +58 -21
  32. package/lib/drama/skills/short-drama-storyboard/references/stage-contract.md +1 -1
  33. package/lib/drama/skills/short-drama-video-prompts/SKILL.md +10 -9
  34. package/lib/drama/skills/short-drama-video-prompts/references/camera-audio-continuity.md +17 -0
  35. package/lib/drama/skills/short-drama-video-prompts/references/minimax-h3.md +12 -38
  36. package/lib/drama/skills/short-drama-video-prompts/references/motion-recipe.md +4 -7
  37. package/lib/drama/skills/short-drama-video-prompts/references/performance-action-timing.md +8 -22
  38. package/lib/drama/skills/short-drama-video-prompts/references/production-prompt-grammar.md +6 -19
  39. package/lib/drama/skills/short-drama-video-prompts/references/seedance-2.0.md +2 -3
  40. package/lib/drama/skills/short-drama-video-prompts/references/seedance-2.5.md +34 -9
  41. package/lib/drama/skills/short-drama-video-prompts/references/stage-contract.md +2 -2
  42. package/lib/drama/skills/short-drama-write/SKILL.md +2 -4
  43. package/lib/index.js +289 -91
  44. package/lib/index.js.map +4 -4
  45. package/lib/novel-to-game/README.md +299 -59
  46. package/lib/novel-to-game/README_ZH.md +299 -56
  47. package/lib/novel-to-game/VERSION +1 -1
  48. package/lib/novel-to-game/examples/jin-ping-mei/build/BUILD_BRIEF.md +3 -1
  49. package/lib/novel-to-game/examples/jin-ping-mei/build/app/RUN.md +11 -3
  50. package/lib/novel-to-game/examples/jin-ping-mei/build/app/css/new-guofeng.css +397 -8
  51. package/lib/novel-to-game/examples/jin-ping-mei/build/app/css/style.css +0 -31
  52. package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/data.js +71 -73
  53. package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/engine.js +78 -89
  54. package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/main.js +37 -14
  55. package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/text.js +5 -5
  56. package/lib/novel-to-game/examples/jin-ping-mei/build/app/package.json +2 -1
  57. package/lib/novel-to-game/examples/jin-ping-mei/qa/README.md +11 -16
  58. package/lib/novel-to-game/examples/jin-ping-mei/qa/verification.json +11 -11
  59. package/lib/novel-to-game/examples/jin-ping-mei/qa/verify_playable_model.mjs +23 -0
  60. package/lib/novel-to-game/manifest.json +77 -87
  61. package/lib/novel-to-game/skills/game-art-direction/SKILL.md +7 -12
  62. package/lib/novel-to-game/skills/game-art-direction/references/art-direction-method.md +27 -106
  63. package/lib/novel-to-game/skills/game-build/SKILL.md +13 -14
  64. package/lib/novel-to-game/skills/game-build/references/blender-asset-workflow.md +24 -0
  65. package/lib/novel-to-game/skills/game-build/references/build-brief-contract.md +45 -82
  66. package/lib/novel-to-game/skills/game-build/references/generative-media-pipeline.md +14 -45
  67. package/lib/novel-to-game/skills/game-build/references/playable-model-contract.md +30 -65
  68. package/lib/novel-to-game/skills/game-build/references/tts-production-contract.md +13 -27
  69. package/lib/novel-to-game/skills/game-concept/SKILL.md +13 -15
  70. package/lib/novel-to-game/skills/game-concept/references/concept-method.md +28 -75
  71. package/lib/novel-to-game/skills/game-qa/SKILL.md +6 -7
  72. package/lib/novel-to-game/skills/game-qa/references/test-design-method.md +9 -5
  73. package/lib/novel-to-game/skills/game-world-design/SKILL.md +12 -16
  74. package/lib/novel-to-game/skills/game-world-design/references/narrative-design-method.md +23 -72
  75. package/lib/novel-to-game/skills/game-world-design/references/numeric-design-method.md +14 -48
  76. package/lib/novel-to-game/skills/game-world-design/references/world-design-method.md +36 -103
  77. package/lib/novel-to-game/skills/novel-game-analyze/SKILL.md +4 -10
  78. package/lib/novel-to-game/skills/novel-game-analyze/references/gameability-protocol.md +4 -4
  79. package/lib/novel-to-game/skills/novel-to-game/SKILL.md +9 -21
  80. package/lib/novel-to-game/skills/novel-to-game/references/intake-method.md +5 -4
  81. package/lib/novel-to-game/skills/novel-to-game/references/pipeline-contract.md +5 -8
  82. package/lib/oh-story/manifest.json +230 -185
  83. package/lib/oh-story/roles/chapter-extractor.md +177 -237
  84. package/lib/oh-story/roles/consistency-checker.md +4 -4
  85. package/lib/oh-story/roles/narrative-writer.md +24 -25
  86. package/lib/oh-story/roles/story-architect.md +5 -5
  87. package/lib/oh-story/roles/story-explorer.md +11 -11
  88. package/lib/oh-story/skills/story/SKILL.md +13 -7
  89. package/lib/oh-story/skills/story/VERSION +1 -1
  90. package/lib/oh-story/skills/story/references/author-memory.md +54 -24
  91. package/lib/oh-story/skills/story/scripts/author_memory_commit.py +934 -170
  92. package/lib/oh-story/skills/story-cover/SKILL.md +10 -1
  93. package/lib/oh-story/skills/story-deslop/SKILL.md +40 -53
  94. package/lib/oh-story/skills/story-deslop/references/anti-ai-writing.md +11 -10
  95. package/lib/oh-story/skills/story-deslop/references/author-memory.md +54 -24
  96. package/lib/oh-story/skills/story-deslop/references/deslop-gates.md +1 -1
  97. package/lib/oh-story/skills/story-deslop/scripts/author_memory_commit.py +934 -170
  98. package/lib/oh-story/skills/story-import/SKILL.md +77 -81
  99. package/lib/oh-story/skills/story-import/references/character-state-reverse.md +1 -1
  100. package/lib/oh-story/skills/story-import/references/state-tracking.md +4 -69
  101. package/lib/oh-story/skills/story-import/references/structure-mapping-long.md +10 -8
  102. package/lib/oh-story/skills/story-import/references/tracking-transaction.md +8 -6
  103. package/lib/oh-story/skills/story-import/scripts/check-outline-contract.js +34 -16
  104. package/lib/oh-story/skills/story-import/scripts/tracking_commit.py +210 -2
  105. package/lib/oh-story/skills/story-import/scripts/wordcount_core.py +3 -0
  106. package/lib/oh-story/skills/story-long-analyze/SKILL.md +91 -258
  107. package/lib/oh-story/skills/story-long-analyze/references/author-facing.md +245 -0
  108. package/lib/oh-story/skills/story-long-analyze/references/deconstruction-notes.md +2 -2
  109. package/lib/oh-story/skills/story-long-analyze/references/inspiration-library.md +105 -0
  110. package/lib/oh-story/skills/story-long-analyze/references/material-decomposition.md +113 -105
  111. package/lib/oh-story/skills/story-long-analyze/references/output-templates.md +169 -125
  112. package/lib/oh-story/skills/story-long-analyze/references/pipeline-ops.md +172 -64
  113. package/lib/oh-story/skills/story-long-analyze/references/semantic-acceptance-fixtures.md +84 -0
  114. package/lib/oh-story/skills/story-long-analyze/references/style-profile-generator.md +42 -132
  115. package/lib/oh-story/skills/story-long-analyze/references/style-profile-protocol.md +5 -5
  116. package/lib/oh-story/skills/story-long-analyze/scripts/build_chapter_index.py +466 -0
  117. package/lib/oh-story/skills/story-long-analyze/scripts/inspect_existing_assets.py +702 -0
  118. package/lib/oh-story/skills/story-long-analyze/scripts/inspiration_index.py +864 -0
  119. package/lib/oh-story/skills/story-long-analyze/scripts/manage_analysis_run.py +1106 -0
  120. package/lib/oh-story/skills/story-long-analyze/scripts/render_relation_chart.py +425 -0
  121. package/lib/oh-story/skills/story-long-scan/SKILL.md +4 -1
  122. package/lib/oh-story/skills/story-long-write/SKILL.md +38 -29
  123. package/lib/oh-story/skills/story-long-write/references/anti-ai-writing.md +11 -10
  124. package/lib/oh-story/skills/story-long-write/references/artifact-protocols.md +25 -20
  125. package/lib/oh-story/skills/story-long-write/references/author-memory.md +54 -24
  126. package/lib/oh-story/skills/story-long-write/references/benchmark-recall.md +3 -3
  127. package/lib/oh-story/skills/story-long-write/references/cross-book-recall.md +26 -0
  128. package/lib/oh-story/skills/story-long-write/references/dialogue-mastery.md +4 -0
  129. package/lib/oh-story/skills/story-long-write/references/emotional-methods.md +2 -2
  130. package/lib/oh-story/skills/story-long-write/references/long-chapter-quality.md +4 -13
  131. package/lib/oh-story/skills/story-long-write/references/outline-structure-theory.md +1 -1
  132. package/lib/oh-story/skills/story-long-write/references/project-files.md +9 -7
  133. package/lib/oh-story/skills/story-long-write/references/reader-contract-and-progression.md +12 -4
  134. package/lib/oh-story/skills/story-long-write/references/reference-index.md +1 -2
  135. package/lib/oh-story/skills/story-long-write/references/tracking-transaction.md +8 -6
  136. package/lib/oh-story/skills/story-long-write/references/workflow-chapter.md +86 -115
  137. package/lib/oh-story/skills/story-long-write/references/workflow-daily.md +55 -120
  138. package/lib/oh-story/skills/story-long-write/references/workflow-revision.md +15 -11
  139. package/lib/oh-story/skills/story-long-write/references/workflow-setup.md +66 -68
  140. package/lib/oh-story/skills/story-long-write/references/writer-prompt-fallback.md +3 -3
  141. package/lib/oh-story/skills/story-long-write/references/writing-craft.md +4 -12
  142. package/lib/oh-story/skills/story-long-write/scripts/author_memory_commit.py +934 -170
  143. package/lib/oh-story/skills/story-long-write/scripts/build_writer_prompt.py +139 -18
  144. package/lib/oh-story/skills/story-long-write/scripts/check-outline-contract.js +34 -16
  145. package/lib/oh-story/skills/story-long-write/scripts/outline_view.py +5 -3
  146. package/lib/oh-story/skills/story-long-write/scripts/storyctl.py +58 -0
  147. package/lib/oh-story/skills/story-long-write/scripts/tracking_commit.py +210 -2
  148. package/lib/oh-story/skills/story-long-write/scripts/wordcount_core.py +3 -0
  149. package/lib/oh-story/skills/story-review/SKILL.md +68 -85
  150. package/lib/oh-story/skills/story-review/references/anti-ai-writing.md +11 -10
  151. package/lib/oh-story/skills/story-review/references/author-memory.md +54 -24
  152. package/lib/oh-story/skills/story-review/references/dialogue-mastery.md +4 -0
  153. package/lib/oh-story/skills/story-review/references/review-quality.md +4 -10
  154. package/lib/oh-story/skills/story-review/references/tracking-transaction.md +8 -6
  155. package/lib/oh-story/skills/story-review/scripts/author_memory_commit.py +934 -170
  156. package/lib/oh-story/skills/story-review/scripts/tracking_commit.py +210 -2
  157. package/lib/oh-story/skills/story-review/scripts/wordcount_core.py +3 -0
  158. package/lib/oh-story/skills/story-setup/SKILL.md +50 -42
  159. package/lib/oh-story/skills/story-setup/references/agent-references/anti-ai-writing.md +11 -10
  160. package/lib/oh-story/skills/story-setup/references/agent-references/deslop-gates.md +1 -1
  161. package/lib/oh-story/skills/story-setup/references/agent-references/dialogue-mastery.md +4 -0
  162. package/lib/oh-story/skills/story-setup/references/agent-references/long-emotional-methods.md +2 -2
  163. package/lib/oh-story/skills/story-setup/references/agent-references/long-quality.md +1 -1
  164. package/lib/oh-story/skills/story-setup/references/agent-references/writing-craft.md +4 -12
  165. package/lib/oh-story/skills/story-setup/references/diagnostics.md +1 -1
  166. package/lib/oh-story/skills/story-short-analyze/SKILL.md +22 -3
  167. package/lib/oh-story/skills/story-short-analyze/references/material-decomposition.md +5 -1
  168. package/lib/oh-story/skills/story-short-scan/SKILL.md +5 -1
  169. package/lib/oh-story/skills/story-short-write/SKILL.md +6 -147
  170. package/lib/oh-story/skills/story-short-write/references/author-memory.md +54 -24
  171. package/lib/oh-story/skills/story-short-write/references/dialogue-mastery.md +4 -0
  172. package/lib/oh-story/skills/story-short-write/references/reference-index.md +2 -0
  173. package/lib/oh-story/skills/story-short-write/references/workflow-design.md +3 -2
  174. package/lib/oh-story/skills/story-short-write/references/workflow-draft.md +126 -0
  175. package/lib/oh-story/skills/story-short-write/references/workflow-revision.md +32 -0
  176. package/lib/oh-story/skills/story-short-write/scripts/author_memory_commit.py +934 -170
  177. package/lib/types/client/drama-production-view.d.ts.map +1 -1
  178. package/lib/types/client/file-activity.d.ts +19 -1
  179. package/lib/types/client/file-activity.d.ts.map +1 -1
  180. package/lib/types/client/index.d.ts.map +1 -1
  181. package/lib/types/client/production-prompts.d.ts +7 -0
  182. package/lib/types/client/production-prompts.d.ts.map +1 -1
  183. package/lib/types/client/production-runtime.d.ts +16 -0
  184. package/lib/types/client/production-runtime.d.ts.map +1 -1
  185. package/lib/types/drama-adapters.d.ts +5 -3
  186. package/lib/types/drama-adapters.d.ts.map +1 -1
  187. package/lib/types/native-hooks.d.ts +52 -0
  188. package/lib/types/native-hooks.d.ts.map +1 -1
  189. package/lib/types/role-identity.d.ts +17 -0
  190. package/lib/types/role-identity.d.ts.map +1 -0
  191. package/lib/types/role-tool.d.ts.map +1 -1
  192. package/lib/types/skill-provider.d.ts.map +1 -1
  193. package/package.json +45 -45
  194. package/lib/novel-to-game/skills/game-world-design/references/dialogue-design-method.md +0 -58
  195. package/lib/novel-to-game/skills/game-world-design/references/game-writing-craft.md +0 -53
  196. package/lib/novel-to-game/skills/novel-to-game/references/intake-benchmark-reference.md +0 -38
  197. package/lib/oh-story/skills/story-long-write/references/state-tracking.md +0 -108
@@ -41,13 +41,21 @@ MAX_ERROR_BODY_BYTES = 64 * 1024
41
41
  TERMINAL_FAILURES = {"failed", "cancelled", "canceled", "timeout", "expired"}
42
42
  SEEDANCE_RATIOS = {"adaptive", "1:1", "3:4", "4:3", "9:16", "16:9", "21:9"}
43
43
  SEEDANCE_REFERENCE_ROLES = {
44
+ "first_frame": "image_url",
45
+ "last_frame": "image_url",
44
46
  "reference_image": "image_url",
45
47
  "reference_video": "video_url",
46
48
  "reference_audio": "audio_url",
47
49
  }
50
+ # One opening frame and one closing frame, because each names a single position
51
+ # in the take. Note what is deliberately absent: the sibling adapter forbids
52
+ # mixing frame conditioning with reference conditioning, and that rule belongs
53
+ # to that provider's reference, not to this one. Do not carry it across.
54
+ SEEDANCE_SINGULAR_ROLES = {"first_frame", "last_frame"}
48
55
  MINIMAX_VIDEO_RATIOS = {"adaptive", "1:1", "3:4", "4:3", "9:16", "16:9", "21:9"}
49
56
  MINIMAX_VIDEO_RESOLUTIONS = {"480P", "768P", "2K"}
50
57
  MINIMAX_VIDEO_PROMPT_LIMIT = 7000
58
+ MINIMAX_SPEECH_TEXT_LIMIT = 5000
51
59
  MINIMAX_VIDEO_ROLES = {
52
60
  "first_frame": "image_url",
53
61
  "last_frame": "image_url",
@@ -369,10 +377,18 @@ def compile_seedance_payload(
369
377
  counters = {"image_url": 0, "video_url": 0, "audio_url": 0}
370
378
  labels = {"image_url": "图片", "video_url": "视频", "audio_url": "音频"}
371
379
  reference_tokens: list[str] = []
380
+ singular_seen: set[str] = set()
372
381
  for role in reference_roles:
373
382
  field = SEEDANCE_REFERENCE_ROLES.get(role)
374
383
  if field is None:
375
384
  raise ValueError(f"unsupported Seedance reference role: {role}")
385
+ if role in SEEDANCE_SINGULAR_ROLES:
386
+ if role in singular_seen:
387
+ raise ValueError(f"Seedance accepts one {role} reference")
388
+ singular_seen.add(role)
389
+ # A frame role still occupies a picture slot, so it keeps counting: the
390
+ # tokens are positional, and skipping one would point every later
391
+ # `@图片N` in the prose at the wrong picture.
376
392
  counters[field] += 1
377
393
  reference_tokens.append(f"@{labels[field]}{counters[field]}")
378
394
  if task_type in {"edit", "extend"} and "reference_video" not in reference_roles:
@@ -738,6 +754,82 @@ def compile_gpt_image_2_payload(job: Mapping[str, Any]) -> dict[str, Any]:
738
754
  }
739
755
 
740
756
 
757
+ MINIMAX_SPEECH_EMOTIONS = {
758
+ "happy", "sad", "angry", "fearful", "disgusted", "surprised", "neutral",
759
+ }
760
+
761
+
762
+ def compile_minimax_speech_payload(job: Mapping[str, Any]) -> dict[str, Any]:
763
+ """Compile a tts job into the official MiniMax speech JSON body.
764
+
765
+ The voice catalogue is deliberately not enumerated here. Which preset voices
766
+ an account can reach depends on the model and the account, no published list
767
+ is authoritative for both, and a list frozen into this file would either
768
+ refuse a voice that works or vouch for one that does not. The document owns
769
+ the value and a reviewer reads it; the adapter only checks its shape.
770
+ """
771
+
772
+ text, parameters = _require_job(job, "tts")
773
+ parameters = _take(
774
+ parameters,
775
+ {"model", "voice_id", "speed", "vol", "pitch", "emotion",
776
+ "sample_rate", "bitrate", "format"},
777
+ )
778
+ model = parameters.pop("model", "")
779
+ if not isinstance(model, str) or not model.strip():
780
+ raise ValueError("MiniMax speech model must be explicitly configured")
781
+ voice_id = parameters.pop("voice_id", "")
782
+ if not isinstance(voice_id, str) or not voice_id.strip() or voice_id != voice_id.strip():
783
+ raise ValueError("MiniMax speech requires a confirmed voice_id")
784
+ if len(text) > MINIMAX_SPEECH_TEXT_LIMIT:
785
+ raise ValueError("MiniMax speech text exceeds the provider limit")
786
+
787
+ target_format = Path(job["outputs"][0]).suffix.casefold().lstrip(".")
788
+ requested_format = parameters.pop("format", target_format)
789
+ if requested_format != target_format or requested_format not in {"mp3", "wav"}:
790
+ raise ValueError("MiniMax output format must match a supported target extension")
791
+ sample_rate = parameters.pop("sample_rate", 32000)
792
+ bitrate = parameters.pop("bitrate", 128000)
793
+ if sample_rate not in {16000, 24000, 32000, 44100}:
794
+ raise ValueError("unsupported MiniMax sample rate")
795
+ if bitrate not in {32000, 64000, 128000, 256000}:
796
+ raise ValueError("unsupported MiniMax bitrate")
797
+
798
+ voice_setting: dict[str, Any] = {"voice_id": voice_id}
799
+ emotion = parameters.pop("emotion", None)
800
+ if emotion is not None:
801
+ if emotion not in MINIMAX_SPEECH_EMOTIONS:
802
+ raise ValueError("unsupported MiniMax speech emotion")
803
+ voice_setting["emotion"] = emotion
804
+ for name, low, high in (("speed", 0.5, 2.0), ("vol", 0.1, 10.0)):
805
+ value = parameters.pop(name, None)
806
+ if value is None:
807
+ continue
808
+ if isinstance(value, bool) or not isinstance(value, (int, float)):
809
+ raise ValueError(f"MiniMax speech {name} must be a number")
810
+ if not low <= float(value) <= high:
811
+ raise ValueError(f"MiniMax speech {name} is outside the supported range")
812
+ voice_setting[name] = float(value)
813
+ pitch = parameters.pop("pitch", None)
814
+ if pitch is not None:
815
+ if isinstance(pitch, bool) or not isinstance(pitch, int) or not -12 <= pitch <= 12:
816
+ raise ValueError("MiniMax speech pitch is outside the supported range")
817
+ voice_setting["pitch"] = pitch
818
+
819
+ return {
820
+ "model": model.strip(),
821
+ "text": text,
822
+ "stream": False,
823
+ "output_format": "hex",
824
+ "voice_setting": voice_setting,
825
+ "audio_setting": {
826
+ "sample_rate": sample_rate,
827
+ "bitrate": bitrate,
828
+ "format": requested_format,
829
+ },
830
+ }
831
+
832
+
741
833
  def compile_minimax_music_payload(job: Mapping[str, Any]) -> dict[str, Any]:
742
834
  """Compile an audio job into the official MiniMax Music 3.0 JSON body."""
743
835
  prompt, parameters = _require_job(job, "music")
@@ -1372,6 +1464,44 @@ def _run_minimax(job: Mapping[str, Any]) -> tuple[Path, str | None]:
1372
1464
  )
1373
1465
 
1374
1466
 
1467
+ def _run_minimax_speech(job: Mapping[str, Any]) -> tuple[Path, str | None]:
1468
+ token = _credential("MINIMAX_API_KEY")
1469
+ body = compile_minimax_speech_payload(job)
1470
+ base = _base_url("MINIMAX_BASE_URL", MINIMAX_BASE_URL)
1471
+ result, _ = _request_json(
1472
+ f"{base}/t2a_v2",
1473
+ provider="minimax-speech",
1474
+ body=body,
1475
+ token=token,
1476
+ )
1477
+ base_resp = result.get("base_resp")
1478
+ if not isinstance(base_resp, Mapping) or base_resp.get("status_code") != 0:
1479
+ raise AdapterFailure(
1480
+ "MiniMax speech synthesis failed",
1481
+ code=_provider_code(result) or "generation_failed",
1482
+ request_id=_safe_token(result.get("trace_id")),
1483
+ )
1484
+ data = result.get("data")
1485
+ audio = data.get("audio") if isinstance(data, Mapping) else None
1486
+ if not isinstance(audio, str) or not audio:
1487
+ raise AdapterFailure(
1488
+ "MiniMax did not return audio data",
1489
+ code="missing_audio",
1490
+ request_id=_safe_token(result.get("trace_id")),
1491
+ )
1492
+ try:
1493
+ content = bytes.fromhex(audio)
1494
+ except ValueError as exc:
1495
+ raise AdapterFailure("MiniMax returned invalid audio data") from exc
1496
+ if not content:
1497
+ raise AdapterFailure("MiniMax returned empty audio data")
1498
+ trace_id = result.get("trace_id")
1499
+ return (
1500
+ _temporary_output(job, job["outputs"][0], content),
1501
+ trace_id if isinstance(trace_id, str) else None,
1502
+ )
1503
+
1504
+
1375
1505
  def _run_minimax_video(job: Mapping[str, Any]) -> tuple[Path, str]:
1376
1506
  token = _credential("MINIMAX_API_KEY")
1377
1507
  base = _base_url("MINIMAX_VIDEO_BASE_URL", MINIMAX_VIDEO_BASE_URL)
@@ -1484,8 +1614,15 @@ def _selftest() -> None:
1484
1614
  "modality": "music", "prompt": "cinematic", "references": [],
1485
1615
  "outputs": ["制作成果/a.mp3"], "parameters": {"lyrics": "[Verse]\nHello"},
1486
1616
  }
1617
+ speech = {
1618
+ "modality": "tts", "prompt": "你们做了多久?", "references": [],
1619
+ "outputs": ["制作成果/a.mp3"],
1620
+ "parameters": {"model": "configured-speech-model", "voice_id": "a-preset"},
1621
+ }
1487
1622
  if compile_gpt_image_2_payload(image)["model"] != OPENAI_MODEL:
1488
1623
  raise RuntimeError("GPT Image 2 self-test failed")
1624
+ if compile_minimax_speech_payload(speech)["voice_setting"]["voice_id"] != "a-preset":
1625
+ raise RuntimeError("MiniMax speech self-test failed")
1489
1626
  seedance = compile_seedance_payload(
1490
1627
  video,
1491
1628
  model="configured-model",
@@ -1553,7 +1690,10 @@ def main() -> int:
1553
1690
  parser.add_argument(
1554
1691
  "provider",
1555
1692
  nargs="?",
1556
- choices=("seedance", "gpt-image-2", "minimax-music", "minimax-h3"),
1693
+ choices=(
1694
+ "seedance", "gpt-image-2", "minimax-music", "minimax-h3",
1695
+ "minimax-speech",
1696
+ ),
1557
1697
  )
1558
1698
  parser.add_argument("--selftest", action="store_true")
1559
1699
  args = parser.parse_args()
@@ -1571,6 +1711,7 @@ def main() -> int:
1571
1711
  "gpt-image-2": _run_openai,
1572
1712
  "minimax-music": _run_minimax,
1573
1713
  "minimax-h3": _run_minimax_video,
1714
+ "minimax-speech": _run_minimax_speech,
1574
1715
  }
1575
1716
  path, provider_job_id = runners[args.provider](job)
1576
1717
  response: dict[str, Any] = {
@@ -71,9 +71,8 @@ license: MIT
71
71
  - 剧本对白、动作、声音、画面文字是否都有画面/声音承载;
72
72
  - 人物、地点、道具状态和镜头起止是否连续;
73
73
  - 提示词是否从准确起点到准确终点;
74
- - 目标模型画音同轨时,可复制正文的声音段是否写成正面闭合事件集:无对白镜不靠 `No dialogue`、
75
- `无对白` 关闭语音通道,完整性声明也不枚举本镜没有的层(`VID-22`、`VID-23`,见
76
- [视觉运动审查表](references/rubric-visual-motion.md));
74
+ - 目标模型画音同轨时,声音内容、时序和发声边界是否与来源一致;无对白镜是否交代底声或静默
75
+ (`VID-22`、`VID-23`,见 [视觉运动审查表](references/rubric-visual-motion.md));
77
76
  - 私有输入、凭据、绝对路径或内部流程文字是否泄漏。
78
77
 
79
78
  缺少必要输入时只停止依赖它的判断,其他问题可以继续汇总。
@@ -71,25 +71,12 @@
71
71
  - 角色名/资产引用进入台词内文;
72
72
  - 音效、环境底噪与对白方向没有来源或相互遮蔽。
73
73
 
74
- 目标模型画音同轨时(`VID-23`),这一节多四条只在同轨条件下成立的核对。四条里只有配乐那条
75
- 有实测后果,其余三条是「正文要如实、完整地交代本镜声音」,按这个理由报,不要替它们编一套
76
- 生成机制:
77
-
78
- - **配乐层在正文里整个缺席**(实测有后果):写了空形式(H3 为 `non_diegetic_music: N/A`)的
79
- 14 次生成没有一次自带配乐,完全不提配乐的 3 次里 2 次返回了自造配乐。这一条按 major 起报。
80
- **空形式本身就是合规写法**:`non_diegetic_music: N/A` 是「本镜没有非画内配乐」的正面陈述,
81
- 不是待填占位符。只有整行不存在时才报,永远不要要求 owner 删掉已经写好的空形式;
82
- - 用排除句代替声轨描述:正文出现 `No dialogue`、`无对白` 而没有正面写出这条声轨由什么组成、
83
- 覆盖多长——问题在于正文没交代本镜该有什么声音,不在于"否定会招来它";
84
- - 完整性声明枚举了本镜没有的层:无对白镜写出
85
- `The audio timeline is complete after the listed ambience, effects and timed dialogue.`
86
- 是一句与本镜事实不符的话;
87
- - 无对白镜从没说清声轨**是什么**:既没有覆盖全时长的底声构成,也没给在场人物一个可见的
88
- 不说话状态(嘴唇闭合)。
89
-
90
- 中间两条同时出现时按一个 finding 报,证据引这两句话本身:它们互相矛盾,本身就是声音契约
91
- 没写清。修订要求写成正面声轨,不能是"再加一句不要对白"。本套件实测未观察到这组写法导致
92
- 模型补出台词,报 finding 时不要这样断言。
74
+ 目标模型画音同轨时(`VID-23`),检查声音内容、时序、发声边界是否符合来源,
75
+ 总结是否错误地引入不存在的声音层。无对白镜也应交代需要的底声或静默。
76
+ H3 无非画内配乐时,`non_diegetic_music: N/A` 是有效的空形式。
77
+
78
+ 按实际遗漏、矛盾与影响报告问题,不因出现 `No dialogue` 或第二个否定句判错,
79
+ 不把 H3 的小样本表现套到所有同轨模型上。相关证据指向同一个问题时合并报告。
93
80
 
94
81
  ### 5. 负面补丁淹没动作
95
82
 
@@ -86,41 +86,15 @@
86
86
  - Does each media reference state its exact purpose, what may be copied, and what
87
87
  must not be copied, rather than treating all visible pixels as authority?
88
88
 
89
- For a copyable body, ask these separately — they are the two rules a rewrite regresses on
90
- most often, because a body that reads "complete" can still carry both defects. Findings here
91
- are about whether the body states this shot's sound and text truthfully and completely; only
92
- the music-layer item below has a measured generation consequence behind it:
93
-
94
- - Does the body carry only what will be filmed (`VID-22`)? Negative action intent must
95
- already be rewritten as a visible positive state. The one permitted negation is the
96
- no-subtitle/caption/dialogue-overlay declaration; a second exclusion clause is a defect,
97
- not extra safety. (The often-repeated reason — that a noun inside a negation gets
98
- rendered — did not reproduce in this suite's probes, so cite the body's own clarity,
99
- not that mechanism, when you raise this.)
100
- - When the target model generates audio in the same pass (`VID-23`), is the sound written
101
- as a closed positive event set — what the track consists of, and across what span —
102
- rather than a list of what must not be heard? Check three failures by name:
103
- - an exclusion clause (`No dialogue`, `无对白`, `no music`) standing in for a positive
104
- soundscape, so the body never says what this shot sounds like;
105
- - a completeness declaration that enumerates a layer this shot does not have. "The audio
106
- timeline is complete after the listed ambience, effects and timed dialogue" on a shot
107
- with no lines states something untrue of this shot. Read the declaration against the
108
- shot's actual layers, not against a template;
109
- - a shot that leaves the non-diegetic music layer unstated. This is the one sound defect
110
- with measured consequences: bodies that omitted the layer came back with an invented
111
- score. **The dialect's empty form satisfies this** — for H3 that is the literal line
112
- `non_diegetic_music: N/A`, which is a correct statement of "no non-diegetic music",
113
- not a placeholder. Raise this only when the layer is missing from the body altogether;
114
- never ask an owner to delete a present empty form;
115
- - a shot with no lines whose body never says what the track *is* for the full duration,
116
- and never gives the on-screen performers a visible non-speaking state.
117
- Report a contradictory pair — an exclusion clause plus a declaration that enumerates the
118
- excluded layer — as one finding against the body's sound contract, and quote both
119
- sentences. Raise it as an internally inconsistent sound contract, which it is; do not
120
- assert that it makes the model invent lines, which this suite has probed and not seen.
121
-
122
- These two apply to a body the review itself is about to ask an owner to rewrite. A revision
123
- request that removes a defect by adding `no ...` has moved the defect, not fixed it.
89
+ For a copyable body (`VID-22`, `VID-23`), check that actions and sound match the
90
+ source and that the timeline accounts for the intended ambience or silence.
91
+ A summary must not introduce a layer absent from the shot. H3's
92
+ `non_diegetic_music: N/A` is a valid empty music layer.
93
+
94
+ Report a concrete contradiction, omission or ambiguity. A negative clause is
95
+ not a defect by itself; do not impose a clause count or assume that negation
96
+ causes the model to generate the excluded content. Keep model-specific
97
+ observations scoped to their tested model and execution path.
124
98
 
125
99
  For a pickup or alternate, ask these separately:
126
100
 
@@ -7,7 +7,8 @@ license: MIT
7
7
  # 短剧分镜与冻结关键帧
8
8
 
9
9
  把剧本和视觉事实转成有镜头职责、空间连续性和可冻结起点的 `剧集/<EP>/分镜.md`。
10
- 每镜使用二级标题 `## SHOT-...`,同镜下用 `### 冻结关键帧提示词` 写起始帧正文。
10
+ 每镜使用二级标题 `## SHOT-...`,同镜下用 `### 冻结关键帧提示词` 写起始帧正文;
11
+ 需要时另加 `### 收尾关键帧提示词` 写终点正文。
11
12
 
12
13
  ## Quick Start
13
14
 
@@ -53,6 +54,9 @@ license: MIT
53
54
  末尾反应;把估时依据简写在本镜「声音」里。具体做法见 [对白估时](references/shot-craft.md#对白估时)。
54
55
  4. 锁定人物朝向、位置、视线、持物、出入口、屏幕方向和必要状态;上游已有会限制动作空间的持续关系时,把关系投影进本镜起点与终点。
55
56
  5. 冻结关键帧只投影镜头起点;删除终点才出现的文字、动作、姿态或道具状态。
57
+ 镜头的职责落在收尾那一下时,另写 `### 收尾关键帧提示词` 投影**终点**——同一格画面的
58
+ 另一端,规则完全对称:删除起点才有、终点已经不在的东西。它是可选的,写法与取舍见
59
+ [首尾成对](references/shot-craft.md#首尾成对)。
56
60
  6. 关键帧成稿后,先从成稿正文读出这一格里需要保持身份、造型或地理的人物、地点和道具,
57
61
  再用同一份清单一次填满三条依据:
58
62
 
@@ -71,11 +75,10 @@ license: MIT
71
75
 
72
76
  - 每镜有唯一职责、明确来源、可见起止状态和合理时长。「来源」以《剧本.md》里真实存在的场景 ID 开头,
73
77
  ID 之后可以跟必要短引文,跨场次的镜头用 `、` 连写多条;`creator_markdown_check.py` 会核对每个 ID 都解析得到。
74
- - **引文是认领,不是背景。** 「来源」里引了哪一句,就等于说这一镜负责拍它。引一个本镜画面里
75
- 根本没有的人做的动作——把「另一个人低头去翻自己的稿子」写进一个只拍某一个人的特写——
76
- 那个动作就从所有人的清单上消失了:没有别的镜头认领它,也没有任何一步报它缺失,
77
- 于是它根本不会被拍出来,而这个缺口只有等人看完成片、问「他的反应呢」才浮出来。
78
- 确实看不见就在「视觉依据」末尾写 `;画外:<类别>「<名称>」`,机械核对认这个写法。
78
+ - 「来源」短引文应对应本镜承担的动作或声音。正文提到画外人物时,可在视觉依据写
79
+ `;画外:<类别>「<名称>」`;这只声明其不在画面,不能代替必要动作的落实。
80
+ 需要看见的动作应另有镜头承载,或说明为何省略。
81
+
79
82
  - 剧本里的每个场景都要有镜头承载。确实决定不拍某一场时,在《分镜.md》正文开头写一行
80
83
  `- 未拍场次:<场景 ID>(理由:……)`,多项用 `;` 连接。SHT-01 一直允许带理由的省略,
81
84
  但省略和漏拍在成稿文档里长得一模一样,所以理由要写下来,而不是留在对话里。
@@ -145,6 +148,7 @@ license: MIT
145
148
  - 关键场次比较导演方案:[场次视觉计划](references/scene-visual-plan.md)
146
149
  - 检查原文是否都有画面承载:[Coverage Audition](references/coverage-audition.md)
147
150
  - 多人、群体和复杂空间调度:[调度手册](references/blocking-playbooks.md)
151
+ - 谁被照亮、怎么写才执行得出:[光的设计](references/lighting-craft.md)
148
152
  - 冻结瞬间、注意中心和可读性:[关键帧手艺](references/keyframe-craft.md)
149
153
  - 漫剧/二维漫画形态的共享画风词汇:[漫剧关键帧词表](references/comic-keyframe-lexicon.md)
150
154
  - 剧本事实到关键帧的完整示例:[剧本到关键帧](references/screenplay-to-keyframe-example.md)
@@ -0,0 +1,39 @@
1
+ # 光的设计
2
+
3
+ ## 分工
4
+
5
+ - 《视觉设定.md》的地点条目记录光源、窗户位置和已经确定的光线状态。
6
+ - 分镜选择本镜的注意中心,说明哪些脸、动作或证据必须可读。
7
+ - 提示词把这些选择写成可观察的画面结果。
8
+
9
+ 开灯、停电和时段变化会改变场景事实,应来自剧本或已接受的视觉设定。
10
+
11
+ ## 按镜头职责设计
12
+
13
+ 先确定观众需要看清什么,再选择亮暗关系、光比与背景分离程度。
14
+ 需要读表情时保留相关面部细节;需要隐藏身份时可以用剪影或遮暗。
15
+ 关注点可以靠亮度、色彩、轮廓或局部对比突出,不要求它总是全画面最亮的部分。
16
+
17
+ 竖屏按实际构图检查人物与背景是否分得开。近景中的脸部光线、多人纵深中的背景光,
18
+ 各自承担不同信息;不要仅按画幅省略环境或默认加轮廓光。
19
+
20
+ ## 把光位与画面效果一起写清
21
+
22
+ 光位术语后补充它在画面上的结果,并明确左右指画面还是人物自身。例如:
23
+
24
+ > 主光来自画面左侧;画面左侧脸颊较亮,另一侧留柔和阴影,眼睛仍可辨认。
25
+
26
+ 仅写「电影感、氛围感强」不足以决定画面。一次图片模型对照中,描述受光结果比只写
27
+ 光位更稳定;这可以作为起步写法,不能据此保证其他模型或视频同样执行。
28
+ 暗部深度、边缘亮光和背景亮度按本镜需要写,不把例子中的效果全部照搬。
29
+
30
+ ## 参考板与跨镜连续性
31
+
32
+ 参考板的均匀照明用于看清形制,不自动成为每个镜头的打光方案。
33
+ 绑定角色板时说明保留身份与造型;本镜的光仍依据场景事实。
34
+
35
+ 同一连续场景维持光源关系与既定色调;视角、取景范围和人物位置变化可以带来正常的
36
+ 画面亮度差异。不要要求所有镜头的平均 RGB 相同。
37
+
38
+ 生成后对比相邻镜头中可比较的脸、衣物或场景表面。曝光和白平衡的小幅偏差交给剪辑
39
+ 校正;光源方向或剧情光态错误回上游修订。测量用于定位差异,是否有问题仍结合画面判断。
@@ -14,8 +14,12 @@
14
14
  3. [场面调度与地理](#场面调度与地理)
15
15
  4. [景别与摄影机动机](#景别与摄影机动机)
16
16
  5. [时长与切镜](#时长与切镜)
17
- 6. [常见问题](#常见问题)
18
- 7. [审查问题](#审查问题)
17
+ 6. [视觉方向选择](#视觉方向选择-sht-07)
18
+ 7. [相连边界](#相连边界-con-01)
19
+ 8. [首尾成对](#首尾成对)
20
+ 9. [一镜到底还是切开](#一镜到底还是切开)
21
+ 10. [常见问题](#常见问题)
22
+ 11. [审查问题](#审查问题)
19
23
 
20
24
  ## 先落实原文,再追求画面
21
25
 
@@ -65,26 +69,13 @@
65
69
  镜头可以负责建立空间、让观众站到某个人物一边、展示证据、暂缓信息、转移权力、
66
70
  表现反应,或让后果无法回避。“中景展示人物说话”不算足够的镜头目的。
67
71
 
68
- ### 承受者也要有一镜
72
+ ### 承受者的反应
69
73
 
70
- 一次打击、否定、揭穿或翻盘,画面上有两个人:**说出它的人,和挨了它的人**。
71
- 只拍前者,观众收到的是一句评价;拍了后者,观众才收到一次事件。
72
-
73
- 这不是「多给一个反应镜头会更好」的锦上添花。剧情上被推翻的那个人如果全程只有后脑、
74
- 只在群像里占几十个像素,观众其实不知道该看谁输——那句最狠的台词就只是一个人在说话,
75
- 爽点不成立。**分镜阶段就要决定谁承受这一下、哪一镜给他**,不要留给剪辑去补,
76
- 因为剪辑只能在已经生成的素材里选,选不出一个没拍过的反应。
77
-
78
- 具体到写法:
79
-
80
- - 台词落点是针对某个在场的人时,检查分镜里有没有一镜的画面主体是**那个人**;
81
- - 没有就补一镜,通常很短(一到两秒足够:停手、抬眼、想开口又闭嘴);
82
- - 承受者不在场时,那一下的后果要落到别的可见东西上(屏幕、门、被推开的文件),
83
- 否则这次打击在画面上没有发生过;
84
- - 群像镜头**不算**承受者反应:一张在四个人里的脸承担不了「他输了」这件事。
85
-
86
- **这条只在剧情确实存在承受者时生效。** 不为每句台词配反应镜头,也不把它变成正反打配额——
87
- 安静的场次、独角戏、纯信息交代不适用。
74
+ **`SHT-27 · reviewed_invariant`**:打击、否定或翻盘需要观众理解其后果时,
75
+ 分镜应安排可读的承受者反应或其他后果载体。
76
+ 可以用独立反应镜、双人镜内的调度、清楚的群像反应、声音或物件状态承载。
77
+ 现有画面已经清楚就不必补镜;需要保留反应或承受者不在场时,注明叙事安排。
78
+ 审查按后果能否被理解判断,不按人数、景别或反应镜数量判断。
88
79
 
89
80
  ### 观众可见性 (`SHT-12`)
90
81
 
@@ -145,6 +136,22 @@
145
136
  要观众读到什么反而没人回答。判断标准始终是必须被读到的信息存在于哪个尺度——证据在
146
137
  指节上就给大特写,后果在两人距离上就不该切近。
147
138
 
139
+ ### 竖屏把可用的景别收窄了
140
+
141
+ 上面那张表是横平竖直的电影景别谱系。**竖屏不是把它裁窄,是让其中两档变得难用**。
142
+
143
+ 机制很简单:远景和全景靠的是**横向铺开的信息**——谁站在谁旁边、队伍有多长、这个人
144
+ 离出口有多远。9:16 的横向只有 16:9 的三分之一强,同样的信息铺进去要么挤成一条,
145
+ 要么小到读不出。所以竖屏短剧的实际用法以中景、近景、特写为主,远景与全景出现得少。
146
+
147
+ 但这**不是禁令,是换一种排法**:竖屏的空间要靠**纵深**而不是横向来交代——前景、中景、
148
+ 后景分层,用门框、桌沿、台阶、人的前后遮挡把关系立起来(见
149
+ [竖屏多人调度](blocking-playbooks.md#1-竖屏多人调度))。做到了这一点,竖屏一样能给全景;
150
+ 做不到就不要用这一档去承担交代空间的职责,改用一个更近的镜头单独给一次。
151
+
152
+ **竖屏的横向视野窄,观众的视线本来就被逼到画面中央**,这既是小景别好用的原因,
153
+ 也是大景别失效的原因——同一件事的两面。
154
+
148
155
  只有注意或关系发生变化时才改变景别和角度。场面声音变大,不等于镜头必须从全景一路
149
156
  推到大特写。反过来,一旦决定切镜,新镜就要在景别、角度或人物关系里至少改变一项;
150
157
  相邻两镜完全同景别、同角度、同关系时,这次切镜没有职责,应当改变收放或并回一镜。
@@ -227,3 +234,33 @@
227
234
  - 是否绑定了准确的造型、观察视角、道具状态、双手状态和文字政策?
228
235
  - 结束边界是否为下一镜提供清楚的开始状态?
229
236
  - 删除或合并本镜,会不会丢失故事意义?
237
+
238
+ ## 首尾成对
239
+
240
+ 终点的可见状态对本镜重要,且目标模型支持尾帧时,可以补写
241
+ `### 收尾关键帧提示词`。它只描述终点,不混入起点或中间动作。
242
+ 若起终状态相同,或变化发生在画外,通常无需另做尾帧。
243
+
244
+ Seedance 2.5 的一个镜头对照中,绑定尾帧改善了末帧落位;这不是所有模型和动作的保证。
245
+ 生成后仍检查中间动作、节奏和终点,不能只比较最后一帧。
246
+
247
+ 当前生产工具从 `分镜.md` 的 `SHOT-...` 只提取「冻结关键帧提示词」,即首帧。
248
+ 要在套件内生产尾帧,交图片提示词阶段建立单独的 `IMG-...` 条目,注明来自本 SHOT 的
249
+ 终点、保留已确认的视觉依据,再以该条目作为 image job 的来源。不得用首帧选择器提交尾帧正文。
250
+ 实际图片生成后按目标方言绑定 `用途:结束帧`。
251
+
252
+ ## 一镜到底还是切开
253
+
254
+ 先看这场戏需要什么,再考虑生成与修订成本。
255
+
256
+ - 连续等待、沉默、空间调度或完整表演,可考虑一镜到底。
257
+ - 需要选择不同表演、突出反应或精确安排切点,可考虑分开生成再剪。
258
+ - 长段生成一处失败可能需要重出更多素材;分开生成则需要额外处理跨镜一致性。
259
+
260
+ 一次 Seedance 2.5 对白场次实测出现过长镜头发声时间过早的问题。
261
+ 有严格落点时应检查目标模型的时序能力并试听,不能保证分成镜头就能锁定每句发声时间。
262
+ 长镜头也可以在剪辑中截取,是否保留完整时长由叙事决定。
263
+
264
+ 多镜容器是在一次生成里安排多个切口;一镜到底则不切镜。
265
+ 容器可减少提交次数,但不自动保证跨镜一致性,也仍可在生成后剪辑。
266
+ 各镜合并时重新整理参考素材与编号,并核对结果中的实际切点。
@@ -38,7 +38,7 @@
38
38
  | SHT-24 | reviewed_invariant | A visual basis describes this frame, not the episode's cast list. Each declared 控制 scope stays within what this frame can carry, and a binding is not carried forward merely because the subject remains in the scene. |
39
39
  | SHT-25 | structural_invariant | Every real reference image a shot binds declares one 用途 from the closed set 身份/造型状态/地理/构图/尺度/效果/起始帧/结束帧/风格, so the shot can say which start frame and which identity/geography/prop pictures a downstream job sends. At most one 起始帧 and one 结束帧 per shot, and 结束帧 requires 起始帧. |
40
40
  | SHT-26 | structural_invariant | A shot's 来源 is its claim on the screenplay: whatever it quotes, this shot is the one that films it. Every 视觉设定 entry the quote calls by name is therefore either in this shot's 视觉依据 or declared 画外 there. Quoting an action performed by someone the frame never shows takes that action off every list — no other shot claims it and nothing reports it missing, so it simply never gets filmed, and the gap only surfaces when a person watches the finished film. The check matches entry names rather than 画面代称, because a 来源 quote comes from 剧本.md; an entry that opted out with `画面代称:无` stays out of this check too. |
41
- | SHT-27 | reviewed_invariant | When a beat lands on a present character — a reversal, a rebuttal, an exposure, a decision that overrules someone — some shot takes that person as its subject. Filming only the speaker delivers a remark; filming the one it lands on delivers an event, and an audience that cannot see who lost does not experience the turn. A group shot does not count: one face among four cannot carry it. Editing cannot supply this later, because editing chooses among shots that exist. Inactive where no one is on the receiving end — quiet scenes, solo work, and plain exposition are not owed a reaction shot, and this is not a shot-reverse-shot quota. |
41
+ | SHT-27 | reviewed_invariant | When understanding a beat requires seeing its effect on a character, provide a readable reaction or consequence. A separate shot, staging within a shared shot, sound, or an object may carry it. Judge legibility against the intended reveal; do not require a shot count or exclude group shots by default. |
42
42
 
43
43
  ### `CON`
44
44
 
@@ -81,17 +81,18 @@ license: MIT
81
81
  8. 写“静态锚点 → 起点 → 唯一动作(触发、接触、落点)→ 次级反应 → 运镜 → 声音 → 终点”,
82
82
  必要时用秒数分段;下一镜从这个终点继续,不另造镜外转换。
83
83
  9. 只在真实参考帧已经说明静态外观时删除重复描述;《视觉设定.md》连续性锁的锁面不在可删之列。
84
- 10. 把限制动作空间的已确认关系写成贯穿本镜的正向可见状态,只安排关系允许的动作通道;只有分镜明确改变关系时才写变化过程。可复制正文的动作边界只用肯定状态句,不用 `no/not/without + 动作` 改写。
84
+ 10. 把限制动作空间的已确认关系写成贯穿本镜的正向可见状态,只安排关系允许的动作通道;只有分镜明确改变关系时才写变化过程。优先用可见状态说明边界,必要时保留明确的排除条件。
85
85
  11. 逐镜读取文字义务。除非剧本或创作者明确要求,正文用本镜已解析的视频提示词语言直接写明任何时刻都不生成非画内字幕、caption 和对白文字叠加,不能只写抽象的“文字层为空”;这条默认与旗帜、标牌、屏幕等画内文字独立。画内 `exact_readable` 逐字写明字符、语言、承载面和位置,不能用全局 `no-text` 覆盖。
86
86
  12. 声音同轨时,把允许的发声按来源、说话人、口语语言和顺序写成完整时间线;每句从原文首字到末字,
87
87
  且逐字对白在单镜可复制正文中只出现一次。视觉动作段只按时间和说话人引用该声音事件,不再抄一遍
88
88
  台词。事件外回到已声明的环境声或静默。Brief、剧本或声音方向已经明确禁止外语前导、语气词、
89
89
  额外人声或重复时,把这些**已确认的发声边界**在完整时间线末尾合并写一次;不靠“只包含”让执行端
90
- 猜,也不自行扩充新的禁用类别。完整时间线声明是声音段落终点,其后不再追加第二组声音排除句,
91
- 且只列本镜实际有的声音层。本镜没有对白时,这条声明里不出现 dialogue,正文也不写 `no dialogue`、
92
- `无对白` 这类排除句,改为正面写出底声的构成与覆盖区间,并把「不说话」写成在场人物的可见状态:
93
- 正面句同时交代了这一镜该有什么声音。配乐层则必须显式关掉,那一条有实测支撑。
94
- 13. 成稿时逐句把 `no/not/without + 动作或状态变化` 改写为当前持续状态或允许动作;直接改正文,不调用工具或生成检查产物。再检查不跨下一镜、不要求互斥动作、不让人物或道具瞬移变形。
90
+ 猜,也不自行扩充新的禁用类别。时间线总结只列本镜实际有的声音层。
91
+ 无对白镜写清底声或静默及其覆盖区间;嘴部动作按剧本表演,不默认强制闭嘴。
92
+ 非画内配乐按目标方言声明,有需要时明确写空。
93
+ 13. 成稿时检查动作、声音和限制条件是否清楚且相容。正面状态有助于表达目标,必要的否定条件
94
+ 可以保留;不按否定句数量判错。确认不跨下一镜、不要求互斥动作、不让人物或道具瞬移变形。
95
+
95
96
  14. 用户要整集就完成整集,镜头组只是内部批次。
96
97
  15. 同一连续时空中相邻正式生成段、且目标档案支持续接时,默认选择“从上一段生成结果续接”;
97
98
  一镜一生成只决定每次装一个镜头,不等于各镜独立文生。只有创作者明确要求独立重生成,或上游
@@ -112,12 +113,12 @@ license: MIT
112
113
  - 运镜与人物动作不争夺注意力;复杂运镜必须有叙事理由。
113
114
  - 声音只写该镜需要的对白、画外音、环境或转场职责,不擅自补歌词。
114
115
  - 非画内字幕、caption 和对白文字叠加默认不生成;正文直接声明全镜任何时刻都不生成这些内容,不用抽象工作流术语代替执行指令。只有剧本或创作者明确要求才开启。画内精确文字是独立允许集合,不因关闭字幕而消失,也不让未批准文字混入。
115
- - 同轨对白/VO/OS 同时写逐字文本、口语语言和发声边界;完整时间线闭合后,不再枚举不存在的语言、语气或声源,也不追加 `no/not/without + 声音类别`。
116
- - 同轨模型下的无对白镜同样要写满声音段:正面写出底声的构成与覆盖区间,把「不说话」写成在场人物的可见状态,完整性声明只列本镜实际有的层,不枚举 dialogue。非画内配乐层显式写空(H3 为 `non_diegetic_music: N/A`)——不写配乐层实测会被模型补上,语音层未观察到同样现象。
116
+ - 同轨对白/VO/OS 同时写逐字文本、口语语言和发声边界;不添加来源没有的声源或重复限制。
117
+ - 无对白镜同样说明底声或静默;时间线总结与实际声音层一致。H3 无非画内配乐时写 `non_diegetic_music: N/A`。
117
118
  - 正文里被引号或 `<d>` 包起来的中文必须逐字来自《剧本.md》,画内标牌文字可来自《视觉设定.md》;
118
119
  分镜自己写下的画内文字与声音同样算数。`creator_markdown_check.py` 会核对四字以上的引文(VID-25)。
119
120
  台词不在剧本里就回到写作技能改剧本,不在提示词里改。
120
- - 上游持续关系只用贯穿状态和允许动作通道表达;不以 `no/not/without + 动作` 重复同一边界,也不给角色冲突动作。
121
+ - 上游持续关系用贯穿状态和允许动作通道表达,避免重复限制或冲突动作。
121
122
  - 本镜命中的连续性锁,锁面原样出现在可复制正文里;颜色、材质、形制这类跨镜不变事实不靠模型记忆。
122
123
  - 正文可直接复制,不含占位符、流程说明、文件路径或 QA 结论。
123
124
 
@@ -80,6 +80,23 @@ Camera behavior 要回答“观众注意为什么在此刻改变”。常见动
80
80
 
81
81
  这里不是同时 lock 和 move。若 transition 改变 shot 已接受的 camera design,仍需 storyboard 同意。
82
82
 
83
+ ### 摄影机与主体的相对运动
84
+
85
+ 主体快跑与摄影机缓推可以同时成立,关键是写清两者的相对关系与画面结果。
86
+ 需要跟随时说明跟随方向和构图;需要人物离开画面时,保留缓推或固定机位也可以。
87
+ 不能为了消除速度差异而改写上游已确定的运镜。
88
+
89
+ ### 运动说明
90
+
91
+ 按本镜需要说明运动方式、方向、速度或触发时机、终点以及要保持的空间关系。
92
+ 与上一节的起点和落点一起核对,不要求每次恰好四项。
93
+
94
+ ### 运镜术语属于方言
95
+
96
+ 推轨、变焦、摇、甩、升降这些词在不同目标模型里的解析并不一致——有的模型的官方指南
97
+ 推荐 `push in` 而完全不收录 `dolly in`。**不要把一个模型上验证过的运镜词表照搬到另一个
98
+ 模型的正文里**;术语与写法以目标模型的方言文档为准,方言里没有记载的词按未验证对待。
99
+
83
100
  ### 非冲突但可能过载
84
101
 
85
102
  pan 同时微调焦点、handheld 带自然呼吸、dolly 配合轻微 tilt 未必矛盾;是否太复杂由 reviewer 结合 purpose 判断,不能靠 camera 动词计数硬挡。