@oh-story/dsh 0.1.12 → 0.1.13

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 (264) hide show
  1. package/README.md +17 -11
  2. package/lib/client.js +85 -35
  3. package/lib/client.js.map +3 -3
  4. package/lib/drama/manifest.json +41 -36
  5. package/lib/drama/skills/short-drama/scripts/creator_markdown_check.py +340 -13
  6. package/lib/drama/skills/short-drama-assets/references/voice-direction.md +4 -2
  7. package/lib/drama/skills/short-drama-edit/SKILL.md +32 -12
  8. package/lib/drama/skills/short-drama-edit/references/still-cuts.md +90 -0
  9. package/lib/drama/skills/short-drama-edit/scripts/edit_tool.py +1035 -145
  10. package/lib/drama/skills/short-drama-edit/scripts/selftest.py +48 -0
  11. package/lib/drama/skills/short-drama-produce/SKILL.md +6 -1
  12. package/lib/drama/skills/short-drama-produce/references/adapter-contract.md +12 -0
  13. package/lib/drama/skills/short-drama-produce/scripts/production_tool.py +138 -9
  14. package/lib/drama/skills/short-drama-produce/scripts/provider_adapters.py +6 -0
  15. package/lib/drama/skills/short-drama-storyboard/SKILL.md +2 -0
  16. package/lib/drama/skills/short-drama-storyboard/references/production-shot-grammar.md +3 -1
  17. package/lib/drama/skills/short-drama-video-prompts/SKILL.md +7 -0
  18. package/lib/drama/skills/short-drama-video-prompts/references/performance-action-timing.md +14 -0
  19. package/lib/drama/skills/short-drama-video-prompts/references/seedance-2.5.md +19 -6
  20. package/lib/drama/skills/short-drama-video-prompts/references/stage-contract.md +1 -0
  21. package/lib/drama/skills/short-drama-video-prompts/references/target-model-profile.md +5 -0
  22. package/lib/drama/skills/short-drama-video-prompts/references/wan-3.0.md +4 -1
  23. package/lib/index.js +16 -7
  24. package/lib/index.js.map +2 -2
  25. package/lib/novel-to-game/README.md +98 -44
  26. package/lib/novel-to-game/README_ZH.md +100 -46
  27. package/lib/novel-to-game/VERSION +1 -1
  28. package/lib/novel-to-game/examples/jin-ping-mei/build/BUILD_BRIEF.md +27 -202
  29. package/lib/novel-to-game/examples/jin-ping-mei/build/app/RUN.md +23 -115
  30. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/bg/chamber.webp +0 -0
  31. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/bg/court_night.webp +0 -0
  32. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/bg/court_rain.webp +0 -0
  33. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/bg/garden.webp +0 -0
  34. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/bg/hall.webp +0 -0
  35. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/bg/kitchen.webp +0 -0
  36. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/bg/street.webp +0 -0
  37. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/bg/street_dawn.webp +0 -0
  38. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/bg/temple.webp +0 -0
  39. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/cg/yue/moon.webp +0 -0
  40. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/meng/angry.webp +0 -0
  41. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/meng/blush.webp +0 -0
  42. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/meng/neutral.webp +0 -0
  43. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/meng/sad.webp +0 -0
  44. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/meng/smile.webp +0 -0
  45. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/meng/surprised.webp +0 -0
  46. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/pan/angry.webp +0 -0
  47. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/pan/blush.webp +0 -0
  48. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/pan/neutral.webp +0 -0
  49. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/pan/sad.webp +0 -0
  50. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/pan/smile.webp +0 -0
  51. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/pan/surprised.webp +0 -0
  52. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/pinger/angry.webp +0 -0
  53. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/pinger/blush.webp +0 -0
  54. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/pinger/neutral.webp +0 -0
  55. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/pinger/sad.webp +0 -0
  56. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/pinger/smile.webp +0 -0
  57. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/pinger/surprised.webp +0 -0
  58. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/xuee/angry.webp +0 -0
  59. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/xuee/blush.webp +0 -0
  60. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/xuee/neutral.webp +0 -0
  61. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/xuee/sad.webp +0 -0
  62. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/xuee/smile.webp +0 -0
  63. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/xuee/surprised.webp +0 -0
  64. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/yue/angry.webp +0 -0
  65. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/yue/blush.webp +0 -0
  66. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/yue/neutral.webp +0 -0
  67. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/yue/sad.webp +0 -0
  68. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/yue/smile.webp +0 -0
  69. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/sprite/yue/surprised.webp +0 -0
  70. package/lib/novel-to-game/examples/jin-ping-mei/build/app/css/style.css +326 -2503
  71. package/lib/novel-to-game/examples/jin-ping-mei/build/app/index.html +71 -4
  72. package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/adv.js +221 -0
  73. package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/audio.js +113 -257
  74. package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/main.js +511 -3026
  75. package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/menus.js +277 -0
  76. package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/petals.js +67 -0
  77. package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/stage.js +180 -0
  78. package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/store.js +70 -0
  79. package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/story/common.js +198 -0
  80. package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/story/common2.js +204 -0
  81. package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/story/common3.js +198 -0
  82. package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/story/dates.js +186 -0
  83. package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/story/index.js +122 -0
  84. package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/story/meng.js +190 -0
  85. package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/story/pan.js +212 -0
  86. package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/story/pinger.js +198 -0
  87. package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/story/xuee.js +199 -0
  88. package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/story/yue.js +214 -0
  89. package/lib/novel-to-game/examples/jin-ping-mei/build/app/package.json +2 -2
  90. package/lib/novel-to-game/examples/jin-ping-mei/build/art/generated-art.json +182 -45
  91. package/lib/novel-to-game/examples/jin-ping-mei/qa/README.md +7 -17
  92. package/lib/novel-to-game/examples/jin-ping-mei/qa/verification.json +9 -9
  93. package/lib/novel-to-game/manifest.json +303 -78
  94. package/lib/novel-to-game/skills/game-art-direction/references/art-direction-method.md +7 -2
  95. package/lib/novel-to-game/skills/game-concept/references/concept-method.md +2 -0
  96. package/lib/novel-to-game/skills/game-world-design/references/narrative-design-method.md +2 -0
  97. package/lib/novel-to-game/skills/game-world-design/references/world-design-method.md +9 -0
  98. package/lib/types/client/drama-production-view.d.ts +11 -0
  99. package/lib/types/client/drama-production-view.d.ts.map +1 -1
  100. package/lib/types/client/file-activity.d.ts +1 -1
  101. package/lib/types/client/file-activity.d.ts.map +1 -1
  102. package/lib/types/client/production-prompts.d.ts +7 -1
  103. package/lib/types/client/production-prompts.d.ts.map +1 -1
  104. package/lib/types/client/production-runtime.d.ts +7 -2
  105. package/lib/types/client/production-runtime.d.ts.map +1 -1
  106. package/lib/types/drama-adapters.d.ts.map +1 -1
  107. package/lib/types/skill-provider.d.ts.map +1 -1
  108. package/lib/types/video-project.d.ts.map +1 -1
  109. package/lib/video-recap/CHANGELOG.md +108 -1
  110. package/lib/video-recap/README.en.md +18 -14
  111. package/lib/video-recap/README.md +18 -14
  112. package/lib/video-recap/manifest.json +297 -321
  113. package/lib/video-recap/skills/video-assemble/SKILL.md +18 -16
  114. package/lib/video-recap/skills/video-assemble/references/explicit-audio-mix.md +3 -1
  115. package/lib/video-recap/skills/video-assemble/references/jianying/SOURCE.md +5 -5
  116. package/lib/video-recap/skills/video-assemble/references/packaging.md +4 -4
  117. package/lib/video-recap/skills/video-assemble/references/subtitle-track.md +10 -10
  118. package/lib/video-recap/skills/video-assemble/scripts/adoption/audio_mix_binding.py +13 -2
  119. package/lib/video-recap/skills/video-assemble/scripts/adoption/av_clock.py +109 -0
  120. package/lib/video-recap/skills/video-assemble/scripts/adoption/strict_publish.py +4 -1
  121. package/lib/video-recap/skills/video-assemble/scripts/artifacts.py +2 -9
  122. package/lib/video-recap/skills/video-assemble/scripts/assemble.py +188 -51
  123. package/lib/video-recap/skills/video-assemble/scripts/assemble_constants.py +0 -1
  124. package/lib/video-recap/skills/video-assemble/scripts/assembly_contract.py +32 -75
  125. package/lib/video-recap/skills/video-assemble/scripts/assembly_settings.py +8 -15
  126. package/lib/video-recap/skills/video-assemble/scripts/audio_mix.py +202 -161
  127. package/lib/video-recap/skills/video-assemble/scripts/codec_peak.py +112 -0
  128. package/lib/video-recap/skills/video-assemble/scripts/export_jianying.py +10 -101
  129. package/lib/video-recap/skills/video-assemble/scripts/jianying/builders.py +44 -475
  130. package/lib/video-recap/skills/video-assemble/scripts/jianying/model.py +1 -22
  131. package/lib/video-recap/skills/video-assemble/scripts/jianying/templates.py +0 -3
  132. package/lib/video-recap/skills/video-assemble/scripts/jianying/timeline_contract.py +36 -103
  133. package/lib/video-recap/skills/video-assemble/scripts/jianying/tracks.py +0 -8
  134. package/lib/video-recap/skills/video-assemble/scripts/jianying/writer.py +28 -203
  135. package/lib/video-recap/skills/video-assemble/scripts/lib.py +20 -34
  136. package/lib/video-recap/skills/video-assemble/scripts/loudness.py +332 -0
  137. package/lib/video-recap/skills/video-assemble/scripts/media.py +158 -38
  138. package/lib/video-recap/skills/video-assemble/scripts/narration_audio.py +30 -16
  139. package/lib/video-recap/skills/video-assemble/scripts/render_preflight.py +49 -8
  140. package/lib/video-recap/skills/video-assemble/scripts/source_subtitles.py +17 -6
  141. package/lib/video-recap/skills/video-assemble/scripts/subtitles/core.py +24 -2
  142. package/lib/video-recap/skills/video-assemble/scripts/subtitles/track.py +2 -5
  143. package/lib/video-recap/skills/video-assemble/scripts/subtitles/track_binding.py +2 -9
  144. package/lib/video-recap/skills/video-assemble/scripts/timeline.py +12 -34
  145. package/lib/video-recap/skills/video-assemble/scripts/timeline_emit.py +3 -4
  146. package/lib/video-recap/skills/video-assemble/scripts/visual_render.py +28 -2
  147. package/lib/video-recap/skills/video-cut/SKILL.md +37 -11
  148. package/lib/video-recap/skills/video-cut/references/shot-review.md +1 -1
  149. package/lib/video-recap/skills/video-cut/scripts/cut.py +2 -34
  150. package/lib/video-recap/skills/video-cut/scripts/cut_cli.py +96 -124
  151. package/lib/video-recap/skills/video-cut/scripts/cut_contract.py +97 -182
  152. package/lib/video-recap/skills/video-cut/scripts/cut_render.py +177 -166
  153. package/lib/video-recap/skills/video-cut/scripts/frame_grid.py +249 -0
  154. package/lib/video-recap/skills/video-cut/scripts/lib.py +0 -3
  155. package/lib/video-recap/skills/video-cut/scripts/media_geometry.py +173 -7
  156. package/lib/video-recap/skills/video-cut/scripts/sentence_boundaries.py +234 -151
  157. package/lib/video-recap/skills/video-cut/scripts/sentence_gate.py +189 -0
  158. package/lib/video-recap/skills/video-cut/scripts/shot_review.py +2 -6
  159. package/lib/video-recap/skills/video-recap/SKILL.md +24 -27
  160. package/lib/video-recap/skills/video-recap/references/audio-routing.md +8 -6
  161. package/lib/video-recap/skills/video-recap/references/config-playbook.md +8 -11
  162. package/lib/video-recap/skills/video-recap/references/data-schema.md +131 -74
  163. package/lib/video-recap/skills/video-recap/references/resource-library.md +17 -1
  164. package/lib/video-recap/skills/video-recap/scripts/doctor.py +51 -268
  165. package/lib/video-recap/skills/video-recap/scripts/final_qc.py +89 -254
  166. package/lib/video-recap/skills/video-recap/scripts/lib.py +81 -70
  167. package/lib/video-recap/skills/video-recap/scripts/library.py +40 -4
  168. package/lib/video-recap/skills/video-recap/scripts/materials.py +13 -80
  169. package/lib/video-recap/skills/video-recap/scripts/recap_cli.py +49 -17
  170. package/lib/video-recap/skills/video-recap/scripts/recap_inspect.py +1 -3
  171. package/lib/video-recap/skills/video-recap/scripts/recap_runner.py +86 -116
  172. package/lib/video-recap/skills/video-recap/scripts/recap_runtime.py +87 -23
  173. package/lib/video-recap/skills/video-recap/scripts/recap_source.py +0 -39
  174. package/lib/video-recap/skills/video-recap/scripts/recap_stage_qc.py +37 -135
  175. package/lib/video-recap/skills/video-recap/scripts/recap_timeline.py +118 -127
  176. package/lib/video-recap/skills/video-recap/scripts/resources/__init__.py +4 -0
  177. package/lib/video-recap/skills/video-recap/scripts/{resource_lock.py → resources/lock.py} +1 -1
  178. package/lib/video-recap/skills/video-recap/scripts/{project_binding.py → resources/project_binding.py} +78 -17
  179. package/lib/video-recap/skills/video-reference/SKILL.md +108 -0
  180. package/lib/video-recap/skills/video-reference/references/reference-schema.md +139 -0
  181. package/lib/video-recap/skills/video-reference/scripts/lib.py +85 -0
  182. package/lib/video-recap/skills/video-reference/scripts/reference.py +96 -0
  183. package/lib/video-recap/skills/video-reference/scripts/reference_check.py +553 -0
  184. package/lib/video-recap/skills/video-reference/scripts/reference_frames.py +122 -0
  185. package/lib/video-recap/skills/video-reference/scripts/reference_measure.py +253 -0
  186. package/lib/video-recap/skills/video-reference/scripts/reference_profile.py +271 -0
  187. package/lib/video-recap/skills/video-script/SKILL.md +9 -7
  188. package/lib/video-recap/skills/video-script/scripts/agent_text.py +18 -267
  189. package/lib/video-recap/skills/video-script/scripts/deslop_qc.py +12 -30
  190. package/lib/video-recap/skills/video-script/scripts/entry_suggestion.py +125 -0
  191. package/lib/video-recap/skills/video-script/scripts/evidence_bundle.py +2 -26
  192. package/lib/video-recap/skills/video-script/scripts/lib.py +5 -15
  193. package/lib/video-recap/skills/video-script/scripts/lint_summary.py +184 -0
  194. package/lib/video-recap/skills/video-script/scripts/narration_lint.py +120 -100
  195. package/lib/video-recap/skills/video-script/scripts/review.py +3 -34
  196. package/lib/video-recap/skills/video-script/scripts/review_grounding.py +20 -46
  197. package/lib/video-recap/skills/video-script/scripts/review_response.py +120 -258
  198. package/lib/video-recap/skills/video-script/scripts/review_runner.py +2 -10
  199. package/lib/video-recap/skills/video-script/scripts/speech_ownership.py +89 -5
  200. package/lib/video-recap/skills/video-script/scripts/validate.py +26 -34
  201. package/lib/video-recap/skills/video-understanding/SKILL.md +29 -4
  202. package/lib/video-recap/skills/video-understanding/references/data-schema.md +5 -22
  203. package/lib/video-recap/skills/video-understanding/scripts/agent_text.py +24 -121
  204. package/lib/video-recap/skills/video-understanding/scripts/asr.py +11 -5
  205. package/lib/video-recap/skills/video-understanding/scripts/asr_timing_evidence.py +15 -24
  206. package/lib/video-recap/skills/video-understanding/scripts/briefing/builder.py +59 -25
  207. package/lib/video-recap/skills/video-understanding/scripts/briefing/context.py +39 -3
  208. package/lib/video-recap/skills/video-understanding/scripts/briefing/inputs.py +15 -27
  209. package/lib/video-recap/skills/video-understanding/scripts/briefing/timeline.py +136 -37
  210. package/lib/video-recap/skills/video-understanding/scripts/consolidate.py +121 -37
  211. package/lib/video-recap/skills/video-understanding/scripts/detect.py +118 -16
  212. package/lib/video-recap/skills/video-understanding/scripts/index_normalize.py +359 -0
  213. package/lib/video-recap/skills/video-understanding/scripts/lib.py +62 -21
  214. package/lib/video-recap/skills/video-understanding/scripts/storyboard.py +181 -51
  215. package/lib/video-recap/skills/video-understanding/scripts/timeline_fusion.py +0 -26
  216. package/lib/video-recap/skills/video-understanding/scripts/understanding_brief.py +37 -14
  217. package/lib/video-recap/skills/video-understanding/scripts/understanding_cache.py +40 -32
  218. package/lib/video-recap/skills/video-understanding/scripts/understanding_runner.py +100 -127
  219. package/lib/video-recap/skills/video-understanding/scripts/understanding_storyboard.py +182 -30
  220. package/lib/video-recap/skills/video-understanding/scripts/vlm.py +30 -27
  221. package/lib/video-recap/skills/video-voiceover/SKILL.md +19 -12
  222. package/lib/video-recap/skills/video-voiceover/references/index-tts.md +3 -3
  223. package/lib/video-recap/skills/video-voiceover/scripts/approved_text_policy.py +3 -1
  224. package/lib/video-recap/skills/video-voiceover/scripts/dub.py +60 -135
  225. package/lib/video-recap/skills/video-voiceover/scripts/lib.py +9 -34
  226. package/lib/video-recap/skills/video-voiceover/scripts/providers/fish_audio.py +6 -1
  227. package/lib/video-recap/skills/video-voiceover/scripts/tts_audio.py +64 -1
  228. package/lib/video-recap/skills/video-voiceover/scripts/tts_cache.py +99 -0
  229. package/lib/video-recap/skills/video-voiceover/scripts/voiceover.py +177 -200
  230. package/package.json +45 -45
  231. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/cg/group/inner_court_accord_five.webp +0 -0
  232. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/cg/group/public_day15.webp +0 -0
  233. package/lib/novel-to-game/examples/jin-ping-mei/build/app/assets/household/li_jiaoer.webp +0 -0
  234. package/lib/novel-to-game/examples/jin-ping-mei/build/app/css/new-guofeng.css +0 -1494
  235. package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/assets.js +0 -147
  236. package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/data.js +0 -7470
  237. package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/engine.js +0 -13066
  238. package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/text.js +0 -32
  239. package/lib/novel-to-game/examples/jin-ping-mei/qa/playable-model.json +0 -99
  240. package/lib/novel-to-game/examples/jin-ping-mei/qa/verify_playable_model.mjs +0 -152
  241. package/lib/video-recap/skills/video-assemble/references/foreground-compose.md +0 -118
  242. package/lib/video-recap/skills/video-assemble/references/jianying/empty_jy_combination_segment.json +0 -84
  243. package/lib/video-recap/skills/video-assemble/references/jianying/empty_jy_combination_video_material.json +0 -98
  244. package/lib/video-recap/skills/video-assemble/references/jianying/empty_jy_draft.json +0 -204
  245. package/lib/video-recap/skills/video-assemble/references/pair-media.md +0 -74
  246. package/lib/video-recap/skills/video-assemble/scripts/compose_foreground.py +0 -293
  247. package/lib/video-recap/skills/video-assemble/scripts/pair_media.py +0 -216
  248. package/lib/video-recap/skills/video-recap/references/shift-left-qc-schema.md +0 -23
  249. package/lib/video-recap/skills/video-recap/scripts/mimo_qc.py +0 -33
  250. package/lib/video-recap/skills/video-recap/scripts/qc/__init__.py +0 -1
  251. package/lib/video-recap/skills/video-recap/scripts/qc/mimo_client.py +0 -13
  252. package/lib/video-recap/skills/video-recap/scripts/qc/mimo_contract.py +0 -9
  253. package/lib/video-recap/skills/video-recap/scripts/qc/mimo_evidence.py +0 -287
  254. package/lib/video-recap/skills/video-recap/scripts/qc/mimo_observations.py +0 -175
  255. package/lib/video-recap/skills/video-recap/scripts/qc/mimo_payload.py +0 -206
  256. package/lib/video-recap/skills/video-recap/scripts/qc/mimo_report.py +0 -318
  257. package/lib/video-recap/skills/video-recap/scripts/qc/mimo_runner.py +0 -130
  258. package/lib/video-recap/skills/video-recap/scripts/qc_contract.py +0 -320
  259. package/lib/video-recap/skills/video-script/scripts/timeline_fusion.py +0 -108
  260. package/lib/video-recap/skills/video-understanding/scripts/brief.py +0 -9
  261. package/lib/video-recap/skills/video-understanding/scripts/deslop_qc.py +0 -211
  262. package/lib/video-recap/skills/video-understanding/scripts/narration_lint.py +0 -707
  263. package/lib/video-recap/skills/video-understanding/scripts/speech_ownership.py +0 -143
  264. /package/lib/video-recap/skills/video-cut/scripts/{narration_mapping.py → cut_qc.py} +0 -0
@@ -4,15 +4,82 @@
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <meta name="color-scheme" content="light" />
7
- <meta name="description" content="《金瓶梅·风月总账》20日男性第一人称成人后宫关系模拟:五条深线、四幕危机与证据化结局" />
7
+ <meta name="description" content="《金瓶梅·风月总账》18+ 古风恋爱 ADV:一条共通线,五位女主各自的路线与三种结局。" />
8
8
  <title>金瓶梅·风月总账</title>
9
9
  <link rel="icon" href="data:," />
10
10
  <link rel="stylesheet" href="css/style.css" />
11
- <link rel="stylesheet" href="css/new-guofeng.css" />
12
11
  </head>
13
12
  <body>
14
- <div id="app"></div>
15
- <div id="announcer" class="sr-only" aria-live="polite" aria-atomic="true"></div>
13
+ <div id="app">
14
+ <section id="gate" class="screen" hidden>
15
+ <div class="gate-card">
16
+ <div class="gate-seal">18+</div>
17
+ <h1>十八岁以下,止步</h1>
18
+ <p>本作只供成年人游玩,含成人恋爱关系、轻度裸露与亲密场景及成熟主题。所有可进入亲密场景的人物均为成年虚构角色。</p>
19
+ <div class="gate-actions">
20
+ <button id="btn-age-yes" class="btn primary">我已成年,进入</button>
21
+ <button id="btn-age-no" class="btn">离开</button>
22
+ </div>
23
+ </div>
24
+ </section>
25
+
26
+ <section id="title" class="screen" hidden>
27
+ <div class="title-bg"></div>
28
+ <canvas id="petals"></canvas>
29
+ <div class="title-veil"></div>
30
+ <div class="title-logo">
31
+ <h1><span>金瓶梅</span><small>风月总账</small></h1>
32
+ <p>那年春天,五扇门,都为你留过灯。</p>
33
+ </div>
34
+ <nav class="title-menu" aria-label="标题菜单">
35
+ <button data-act="new">开始游戏</button>
36
+ <button data-act="continue">继续</button>
37
+ <button data-act="load">读取</button>
38
+ <button data-act="extras">鉴赏</button>
39
+ <button data-act="config">设置</button>
40
+ <button data-act="exit">退出</button>
41
+ </nav>
42
+ <p class="title-foot">18+ · 成人恋爱 ADV · 点击推进,选择改变她们的心意</p>
43
+ </section>
44
+
45
+ <section id="game" class="screen" hidden>
46
+ <div id="stage">
47
+ <div class="bg" id="bg-a"></div>
48
+ <div class="bg" id="bg-b"></div>
49
+ <div id="sprites"></div>
50
+ <div id="weather"></div>
51
+ <div id="cg"><img alt="" /></div>
52
+ <div id="flash"></div>
53
+ </div>
54
+ <div id="ui">
55
+ <div id="textbox">
56
+ <div id="nameplate"></div>
57
+ <p id="text"></p>
58
+ <span id="next-ind" aria-hidden="true"></span>
59
+ <span id="hint" hidden>点击画面或按空格继续 · 右键隐藏文字 · 滚轮上翻回看</span>
60
+ </div>
61
+ <nav id="quickmenu" aria-label="快捷菜单">
62
+ <button data-act="backlog">回看</button>
63
+ <button data-act="rollback">上一选项</button>
64
+ <button data-act="qsave">快存</button>
65
+ <button data-act="qload">快读</button>
66
+ <button data-act="save">存档</button>
67
+ <button data-act="load">读档</button>
68
+ <button data-act="auto">自动</button>
69
+ <button data-act="skip">快进</button>
70
+ <button data-act="config">设置</button>
71
+ <button data-act="hide">隐藏</button>
72
+ <button data-act="menu">菜单</button>
73
+ </nav>
74
+ </div>
75
+ <div id="choices" tabindex="-1" hidden></div>
76
+ <div id="card" hidden></div>
77
+ <div id="mode-badge" hidden></div>
78
+ </section>
79
+
80
+ <section id="overlay" hidden></section>
81
+ <div id="toast" hidden></div>
82
+ </div>
16
83
  <script type="module" src="js/main.js"></script>
17
84
  </body>
18
85
  </html>
@@ -0,0 +1,221 @@
1
+ // ADV 解释器:把 story/*.js 里的行式剧本解析成指令,再一步步执行到下一处需要玩家的地方。
2
+ // 纯逻辑、无 DOM,浏览器与 node(test/lint_script.mjs)共用。
3
+ //
4
+ // 剧本语法(每行一条):
5
+ // # label 标签
6
+ // 名(表情):台词 说话;名可为 CAST 里的中文名,表情为 平/笑/怒/哀/羞/惊
7
+ // 其他文字 旁白
8
+ // @bg id [fade|cut|flash] 背景 @bgm id|stop @se id @weather rain|petals|none
9
+ // @show id 左|中|右 [表情] 立绘 @hide id|all @fx shake|flash
10
+ // @chapter 标题|副题 章节标题卡(「标题 · 副题」也写入存档名)
11
+ // @cg id | @cg off CG @scene id 题名 / @endscene 回想区段
12
+ // @choice + 若干「- 文本 -> label {yue+1 f:flag} ?yue>=2」
13
+ // @jump label | @if 条件 -> label | @do 效果
14
+ // @branch 共通线终点:按好感开放各院门
15
+ // @ending id 记录并展示结局 @fate 人物 原著命数页 @end 回标题
16
+
17
+ export const EXPR = Object.freeze({ 平: 'neutral', 笑: 'smile', 怒: 'angry', 哀: 'sad', 羞: 'blush', 惊: 'surprised' });
18
+ export const POS = Object.freeze({ 左: 'left', 中: 'center', 右: 'right' });
19
+ export const HEROINES = Object.freeze(['yue', 'pan', 'pinger', 'meng', 'xuee']);
20
+ export const ROUTE_MIN = 3;
21
+
22
+ const SAY = /^([^\s::@#\-][^:]{0,5}?)(?:[((]([平笑怒哀羞惊])[))])?:(.+)$/;
23
+
24
+ function parseEffects(text = '') {
25
+ return text.trim().split(/\s+/).filter(Boolean).map((token) => {
26
+ if (token.startsWith('f:')) return { flag: token.slice(2) };
27
+ const m = token.match(/^(\w+)([+-]\d+)$/);
28
+ if (!m) throw new Error(`效果写法不对:${token}`);
29
+ return { aff: m[1], delta: Number(m[2]) };
30
+ });
31
+ }
32
+
33
+ export function parseCond(text) {
34
+ if (!text) return null;
35
+ return text.split('&').map((part) => {
36
+ const s = part.trim();
37
+ let m = s.match(/^(!?)f:(\w+)$/);
38
+ if (m) return { flag: m[2], not: m[1] === '!' };
39
+ m = s.match(/^(\w+)(>=|<=|>|<|==)(-?\d+)$/);
40
+ if (m) return { aff: m[1], op: m[2], value: Number(m[3]) };
41
+ throw new Error(`条件写法不对:${s}`);
42
+ });
43
+ }
44
+
45
+ export function testCond(cond, vars) {
46
+ if (!cond) return true;
47
+ return cond.every((c) => {
48
+ if (c.flag) return Boolean(vars.flags[c.flag]) !== c.not;
49
+ const v = vars.aff[c.aff] ?? 0;
50
+ return { '>=': v >= c.value, '<=': v <= c.value, '>': v > c.value, '<': v < c.value, '==': v === c.value }[c.op];
51
+ });
52
+ }
53
+
54
+ export function parseScript(sources, cast, speakers = []) {
55
+ const byName = Object.fromEntries(Object.entries(cast).map(([id, c]) => [c.name, id]));
56
+ const labels = {};
57
+ let current = null;
58
+ let pendingChoice = null;
59
+ for (const source of sources) {
60
+ for (const raw of source.split('\n')) {
61
+ const line = raw.trim();
62
+ if (!line || line.startsWith('//')) continue;
63
+ if (line.startsWith('# ')) {
64
+ current = line.slice(2).trim();
65
+ if (labels[current]) throw new Error(`重复标签:${current}`);
66
+ labels[current] = [];
67
+ pendingChoice = null;
68
+ continue;
69
+ }
70
+ if (!current) throw new Error(`标签之外的行:${line}`);
71
+ const list = labels[current];
72
+ if (line.startsWith('- ') && pendingChoice) {
73
+ const m = line.slice(2).match(/^(.+?)\s*->\s*(\w+)\s*(?:\{([^}]*)\})?\s*(?:\?(\S+))?$/);
74
+ if (!m) throw new Error(`选项写法不对:${line}`);
75
+ pendingChoice.options.push({ text: m[1].trim(), target: m[2], effects: parseEffects(m[3]), cond: parseCond(m[4]) });
76
+ continue;
77
+ }
78
+ pendingChoice = null;
79
+ if (line.startsWith('@')) {
80
+ const [op, ...rest] = line.slice(1).split(/\s+/);
81
+ const arg = line.slice(op.length + 2).trim();
82
+ let cmd;
83
+ if (op === 'bg') cmd = { t: 'bg', id: rest[0], fx: rest[1] || 'fade' };
84
+ else if (op === 'bgm') cmd = { t: 'bgm', id: rest[0] === 'stop' ? null : rest[0] };
85
+ else if (op === 'se') cmd = { t: 'se', id: rest[0] };
86
+ else if (op === 'show') cmd = { t: 'show', who: rest[0], pos: POS[rest[1]] || 'center', expr: EXPR[rest[2]] || 'neutral' };
87
+ else if (op === 'hide') cmd = { t: 'hide', who: rest[0] };
88
+ else if (op === 'fx') cmd = { t: 'fx', id: rest[0] };
89
+ else if (op === 'weather') cmd = { t: 'weather', id: rest[0] === 'none' ? null : rest[0] };
90
+ else if (op === 'chapter') { const [title, sub = ''] = arg.split('|'); cmd = { t: 'chapter', title: title.trim(), sub: sub.trim() }; }
91
+ else if (op === 'cg') cmd = { t: 'cg', id: rest[0] === 'off' ? null : rest[0] };
92
+ else if (op === 'scene') cmd = { t: 'scene', id: rest[0], title: rest.slice(1).join(' ') };
93
+ else if (op === 'endscene') cmd = { t: 'endscene' };
94
+ else if (op === 'choice') { cmd = { t: 'choice', options: [] }; pendingChoice = cmd; }
95
+ else if (op === 'jump') cmd = { t: 'jump', target: rest[0] };
96
+ else if (op === 'if') { const m = arg.match(/^(\S+)\s*->\s*(\w+)$/); cmd = { t: 'if', cond: parseCond(m[1]), target: m[2] }; }
97
+ else if (op === 'do') cmd = { t: 'do', effects: parseEffects(arg) };
98
+ else if (op === 'branch') cmd = { t: 'branch' };
99
+ else if (op === 'ending') cmd = { t: 'ending', id: rest[0] };
100
+ else if (op === 'fate') cmd = { t: 'fate', who: rest[0] };
101
+ else if (op === 'end') cmd = { t: 'end' };
102
+ else throw new Error(`未知指令:${line}`);
103
+ list.push(cmd);
104
+ continue;
105
+ }
106
+ const m = line.match(SAY);
107
+ if (m && (byName[m[1]] || speakers.includes(m[1]))) {
108
+ list.push({ t: 'say', who: byName[m[1]] ?? null, name: m[1], expr: m[2] ? EXPR[m[2]] : null, text: m[3].trim() });
109
+ } else {
110
+ list.push({ t: 'say', who: null, name: '', expr: null, text: line });
111
+ }
112
+ }
113
+ }
114
+ for (const [label, list] of Object.entries(labels)) list.forEach((cmd, ip) => { if (cmd.t === 'say') cmd.id = `${label}:${ip}`; });
115
+ return labels;
116
+ }
117
+
118
+ const blankStage = () => ({ bg: null, bgFx: 'fade', sprites: {}, cg: null, bgm: null, weather: null, chapter: '' });
119
+
120
+ export class Story {
121
+ constructor(labels, hooks = {}) {
122
+ this.labels = labels;
123
+ this.hooks = hooks; // onUnlock(kind, id)
124
+ this.reset();
125
+ }
126
+
127
+ reset() {
128
+ this.label = null;
129
+ this.ip = 0;
130
+ this.vars = { aff: Object.fromEntries(HEROINES.map((h) => [h, 0])), flags: {} };
131
+ this.stage = blankStage();
132
+ this.replay = false;
133
+ this.pending = null;
134
+ }
135
+
136
+ start(label = 'start', { replay = false, ip = 0 } = {}) {
137
+ this.reset();
138
+ this.label = label;
139
+ this.ip = ip;
140
+ this.replay = replay;
141
+ }
142
+
143
+ jump(target) {
144
+ if (!this.labels[target]) throw new Error(`跳到不存在的标签:${target}`);
145
+ this.label = target;
146
+ this.ip = 0;
147
+ }
148
+
149
+ apply(effects) {
150
+ for (const e of effects) {
151
+ if (e.flag) this.vars.flags[e.flag] = true;
152
+ else this.vars.aff[e.aff] = (this.vars.aff[e.aff] ?? 0) + e.delta;
153
+ }
154
+ }
155
+
156
+ // 执行到下一个阻塞点并返回它:say / choice / chapter / ending / fate / end
157
+ next() {
158
+ for (let guard = 0; guard < 10000; guard += 1) {
159
+ const list = this.labels[this.label];
160
+ if (!list) throw new Error(`标签缺失:${this.label}`);
161
+ if (this.ip >= list.length) throw new Error(`标签 ${this.label} 没有用 @jump/@end 收尾`);
162
+ const cmd = list[this.ip];
163
+ this.ip += 1;
164
+ const s = this.stage;
165
+ switch (cmd.t) {
166
+ case 'bg': s.bg = cmd.id; s.bgFx = cmd.fx; s.cg = null; break;
167
+ case 'bgm': s.bgm = cmd.id; if (cmd.id) this.hooks.onUnlock?.('music', cmd.id); break;
168
+ case 'se': this.hooks.onSe?.(cmd.id); break;
169
+ case 'fx': this.hooks.onFx?.(cmd.id); break;
170
+ case 'weather': s.weather = cmd.id; break;
171
+ case 'show': s.sprites[cmd.who] = { pos: cmd.pos, expr: cmd.expr }; break;
172
+ case 'hide': if (cmd.who === 'all') s.sprites = {}; else delete s.sprites[cmd.who]; break;
173
+ case 'cg': s.cg = cmd.id; if (cmd.id) this.hooks.onUnlock?.('cg', cmd.id); break;
174
+ case 'scene': if (!this.replay) this.hooks.onUnlock?.('scene', cmd.id); break;
175
+ case 'endscene': if (this.replay) return { type: 'end', replay: true }; break;
176
+ case 'jump': this.jump(cmd.target); break;
177
+ case 'if': if (testCond(cmd.cond, this.vars)) this.jump(cmd.target); break;
178
+ case 'do': this.apply(cmd.effects); break;
179
+ case 'say':
180
+ if (cmd.who && cmd.expr && s.sprites[cmd.who]) s.sprites[cmd.who].expr = cmd.expr;
181
+ return { type: 'say', ...cmd };
182
+ case 'chapter': s.chapter = cmd.sub ? `${cmd.title} · ${cmd.sub}` : cmd.title; return { type: 'chapter', title: cmd.title, sub: cmd.sub };
183
+ case 'choice': {
184
+ const options = cmd.options.map((o, i) => ({ i, text: o.text, enabled: testCond(o.cond, this.vars) }));
185
+ this.pending = cmd.options;
186
+ return { type: 'choice', options };
187
+ }
188
+ case 'branch': {
189
+ const open = HEROINES.filter((h) => this.vars.aff[h] >= ROUTE_MIN);
190
+ if (!open.length) { this.jump('lonely'); break; }
191
+ this.pending = HEROINES.map((h) => ({ target: `${h}_route`, effects: [{ flag: `route_${h}` }] }));
192
+ return { type: 'choice', branch: true, options: HEROINES.map((h, i) => ({ i, who: h, enabled: open.includes(h) })) };
193
+ }
194
+ case 'ending': this.hooks.onUnlock?.('ending', cmd.id); return { type: 'ending', id: cmd.id };
195
+ case 'fate': return { type: 'fate', who: cmd.who };
196
+ case 'end': return { type: 'end' };
197
+ default: throw new Error(`未知指令类型:${cmd.t}`);
198
+ }
199
+ }
200
+ throw new Error('剧本陷入死循环');
201
+ }
202
+
203
+ choose(index) {
204
+ const option = this.pending?.[index];
205
+ if (!option) throw new Error(`没有这个选项:${index}`);
206
+ this.pending = null;
207
+ this.apply(option.effects);
208
+ this.jump(option.target);
209
+ }
210
+
211
+ // 存档:停在阻塞指令上,读档后回退一格重新执行即可还原同一画面
212
+ snapshot() {
213
+ return JSON.parse(JSON.stringify({ label: this.label, ip: this.ip - 1, vars: this.vars, stage: this.stage }));
214
+ }
215
+
216
+ restore(snap) {
217
+ this.reset();
218
+ Object.assign(this, JSON.parse(JSON.stringify({ label: snap.label, ip: snap.ip, vars: snap.vars, stage: snap.stage })));
219
+ if (!this.labels[this.label]) throw new Error('存档指向的剧本已不存在');
220
+ }
221
+ }