@biunow/agent-biuart 0.0.0-stage → 0.1.1

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 (377) hide show
  1. package/bin/server.mjs +575 -0
  2. package/data/styles.json +533 -0
  3. package/engine/audit_clip.py +46 -0
  4. package/engine/clip.html +24 -0
  5. package/engine/clip.js +104 -0
  6. package/engine/clip_schema.json +19 -0
  7. package/engine/clips/t1_3b1b.js +203 -0
  8. package/engine/clips/t2_keynote_ui.js +347 -0
  9. package/engine/clips/t3_finance_chart.js +206 -0
  10. package/engine/clips/y1_kurzgesagt.js +183 -0
  11. package/engine/clips/y2_vox.js +150 -0
  12. package/engine/clips/y3_whiteboard.js +209 -0
  13. package/engine/clips/y4_storytime.js +194 -0
  14. package/engine/clips/y5_kinetic_type.js +134 -0
  15. package/engine/compare.py +19 -0
  16. package/engine/demos/_shared/hero/c1_0.png +0 -0
  17. package/engine/demos/_shared/hero/c1_1.png +0 -0
  18. package/engine/demos/_shared/hero/c1_2.png +0 -0
  19. package/engine/demos/_shared/hero/c3_line.png +0 -0
  20. package/engine/demos/_shared/hero.js +96 -0
  21. package/engine/demos/long_scroll/eras.js +23 -0
  22. package/engine/demos/long_scroll/frames/8bit_act/01.png +0 -0
  23. package/engine/demos/long_scroll/frames/8bit_act/02.png +0 -0
  24. package/engine/demos/long_scroll/frames/8bit_act/03.png +0 -0
  25. package/engine/demos/long_scroll/frames/8bit_act/04.png +0 -0
  26. package/engine/demos/long_scroll/frames/8bit_act/05.png +0 -0
  27. package/engine/demos/long_scroll/frames/8bit_act/06.png +0 -0
  28. package/engine/demos/long_scroll/frames/8bit_act/07.png +0 -0
  29. package/engine/demos/long_scroll/frames/8bit_act/08.png +0 -0
  30. package/engine/demos/long_scroll/frames/8bit_act/meta.json +69 -0
  31. package/engine/demos/long_scroll/frames/8bit_walk/01.png +0 -0
  32. package/engine/demos/long_scroll/frames/8bit_walk/02.png +0 -0
  33. package/engine/demos/long_scroll/frames/8bit_walk/03.png +0 -0
  34. package/engine/demos/long_scroll/frames/8bit_walk/04.png +0 -0
  35. package/engine/demos/long_scroll/frames/8bit_walk/05.png +0 -0
  36. package/engine/demos/long_scroll/frames/8bit_walk/06.png +0 -0
  37. package/engine/demos/long_scroll/frames/8bit_walk/07.png +0 -0
  38. package/engine/demos/long_scroll/frames/8bit_walk/08.png +0 -0
  39. package/engine/demos/long_scroll/frames/8bit_walk/meta.json +69 -0
  40. package/engine/demos/long_scroll/frames/egypt_dodge/01.png +0 -0
  41. package/engine/demos/long_scroll/frames/egypt_dodge/02.png +0 -0
  42. package/engine/demos/long_scroll/frames/egypt_dodge/03.png +0 -0
  43. package/engine/demos/long_scroll/frames/egypt_dodge/04.png +0 -0
  44. package/engine/demos/long_scroll/frames/egypt_dodge/05.png +0 -0
  45. package/engine/demos/long_scroll/frames/egypt_dodge/06.png +0 -0
  46. package/engine/demos/long_scroll/frames/egypt_dodge/07.png +0 -0
  47. package/engine/demos/long_scroll/frames/egypt_dodge/08.png +0 -0
  48. package/engine/demos/long_scroll/frames/egypt_dodge/meta.json +69 -0
  49. package/engine/demos/long_scroll/frames/egypt_walk8/01.png +0 -0
  50. package/engine/demos/long_scroll/frames/egypt_walk8/02.png +0 -0
  51. package/engine/demos/long_scroll/frames/egypt_walk8/03.png +0 -0
  52. package/engine/demos/long_scroll/frames/egypt_walk8/04.png +0 -0
  53. package/engine/demos/long_scroll/frames/egypt_walk8/05.png +0 -0
  54. package/engine/demos/long_scroll/frames/egypt_walk8/06.png +0 -0
  55. package/engine/demos/long_scroll/frames/egypt_walk8/07.png +0 -0
  56. package/engine/demos/long_scroll/frames/egypt_walk8/08.png +0 -0
  57. package/engine/demos/long_scroll/frames/egypt_walk8/meta.json +69 -0
  58. package/engine/demos/long_scroll/frames/monet_throw/01.png +0 -0
  59. package/engine/demos/long_scroll/frames/monet_throw/02.png +0 -0
  60. package/engine/demos/long_scroll/frames/monet_throw/03.png +0 -0
  61. package/engine/demos/long_scroll/frames/monet_throw/04.png +0 -0
  62. package/engine/demos/long_scroll/frames/monet_throw/05.png +0 -0
  63. package/engine/demos/long_scroll/frames/monet_throw/06.png +0 -0
  64. package/engine/demos/long_scroll/frames/monet_throw/07.png +0 -0
  65. package/engine/demos/long_scroll/frames/monet_throw/08.png +0 -0
  66. package/engine/demos/long_scroll/frames/monet_throw/meta.json +71 -0
  67. package/engine/demos/long_scroll/frames/monet_walk/01.png +0 -0
  68. package/engine/demos/long_scroll/frames/monet_walk/02.png +0 -0
  69. package/engine/demos/long_scroll/frames/monet_walk/03.png +0 -0
  70. package/engine/demos/long_scroll/frames/monet_walk/04.png +0 -0
  71. package/engine/demos/long_scroll/frames/monet_walk/05.png +0 -0
  72. package/engine/demos/long_scroll/frames/monet_walk/06.png +0 -0
  73. package/engine/demos/long_scroll/frames/monet_walk/07.png +0 -0
  74. package/engine/demos/long_scroll/frames/monet_walk/08.png +0 -0
  75. package/engine/demos/long_scroll/frames/monet_walk/meta.json +71 -0
  76. package/engine/demos/long_scroll/lib/acts.js +87 -0
  77. package/engine/demos/long_scroll/lib/crossing.js +463 -0
  78. package/engine/demos/long_scroll/lib/world.js +143 -0
  79. package/engine/demos/long_scroll/lib/xing2_ding.js +42 -0
  80. package/engine/demos/long_scroll/lib/xing2_jia.js +114 -0
  81. package/engine/demos/long_scroll/lib/xing2_yi.js +133 -0
  82. package/engine/demos/long_scroll/segments/02_egypt.js +234 -0
  83. package/engine/demos/long_scroll/segments/14_8bit.js +118 -0
  84. package/engine/demos/long_scroll/segments/28_monet.js +86 -0
  85. package/engine/demos/t1_3b1b/eras.js +11 -0
  86. package/engine/demos/t1_3b1b/t1_s1.js +101 -0
  87. package/engine/demos/t1_3b1b/t1_s2.js +74 -0
  88. package/engine/demos/t1_3b1b/t1_s3.js +65 -0
  89. package/engine/demos/t2_keynote_ui/eras.js +10 -0
  90. package/engine/demos/t2_keynote_ui/t2_s1.js +57 -0
  91. package/engine/demos/t2_keynote_ui/t2_s2.js +70 -0
  92. package/engine/demos/t2_keynote_ui/t2_s3.js +61 -0
  93. package/engine/demos/t3_finance_chart/eras.js +11 -0
  94. package/engine/demos/t3_finance_chart/t3_s1.js +48 -0
  95. package/engine/demos/t3_finance_chart/t3_s2.js +42 -0
  96. package/engine/demos/t3_finance_chart/t3_s3.js +51 -0
  97. package/engine/demos/y1_kurzgesagt/eras.js +10 -0
  98. package/engine/demos/y1_kurzgesagt/kurzgesagt.js +347 -0
  99. package/engine/demos/y2_vox/eras.js +10 -0
  100. package/engine/demos/y2_vox/vox.js +240 -0
  101. package/engine/demos/y3_whiteboard/eras.js +10 -0
  102. package/engine/demos/y3_whiteboard/whiteboard.js +162 -0
  103. package/engine/demos/y4_storytime/eras.js +14 -0
  104. package/engine/demos/y4_storytime/s1_desk.js +18 -0
  105. package/engine/demos/y4_storytime/s2_screen.js +82 -0
  106. package/engine/demos/y4_storytime/s3_react.js +39 -0
  107. package/engine/demos/y4_storytime/s4_wide.js +16 -0
  108. package/engine/demos/y4_storytime/s5_close.js +18 -0
  109. package/engine/demos/y4_storytime/story.js +25 -0
  110. package/engine/demos/y4_storytime/vo_env.js +2 -0
  111. package/engine/demos/y4_storytime/world.js +73 -0
  112. package/engine/demos/y5_kinetic_type/eras.js +16 -0
  113. package/engine/demos/y5_kinetic_type/k1_title.js +38 -0
  114. package/engine/demos/y5_kinetic_type/k2_complete.js +55 -0
  115. package/engine/demos/y5_kinetic_type/k3_chat.js +47 -0
  116. package/engine/demos/y5_kinetic_type/k4_agent.js +49 -0
  117. package/engine/demos/y5_kinetic_type/kinetic.js +52 -0
  118. package/engine/engine.js +277 -0
  119. package/engine/eras.js +60 -0
  120. package/engine/eras_gallery.js +115 -0
  121. package/engine/eras_style_studies.js +20 -0
  122. package/engine/examples/assets/K/347/272/277/345/233/276_/346/250/252/345/261/217.png +0 -0
  123. package/engine/examples/assets//347/273/210/347/253/257_for/345/276/252/347/216/257/346/261/202/345/222/214.png +0 -0
  124. package/engine/examples/assets//347/273/210/347/253/257_sum/346/261/202/345/222/214.png +0 -0
  125. package/engine/examples/assets//350/220/245/346/224/266/345/233/276_/347/253/226/345/261/217.png +0 -0
  126. package/engine/examples/assets//350/264/242/347/273/217/345/233/276/350/241/250_/346/250/252/345/261/217.png +0 -0
  127. package/engine/examples/t1_3b1b.json +19 -0
  128. package/engine/examples/t2_fullbleed_pulse.json +15 -0
  129. package/engine/examples/t2_keynote_ui.json +15 -0
  130. package/engine/examples/t3_finance_chart.json +29 -0
  131. package/engine/examples/y1_kurzgesagt.json +16 -0
  132. package/engine/examples/y2_vox.json +14 -0
  133. package/engine/examples/y3_whiteboard.json +17 -0
  134. package/engine/examples/y4_storytime.json +52 -0
  135. package/engine/examples/y5_kinetic_type.json +14 -0
  136. package/engine/index.html +42 -0
  137. package/engine/lib/THREE_LICENSE.txt +21 -0
  138. package/engine/lib/brush.js +149 -0
  139. package/engine/lib/camera.js +99 -0
  140. package/engine/lib/chart.js +152 -0
  141. package/engine/lib/collage.js +97 -0
  142. package/engine/lib/diagram.js +264 -0
  143. package/engine/lib/finish.js +70 -0
  144. package/engine/lib/fonts/AlfaSlabOne-400.woff +0 -0
  145. package/engine/lib/fonts/Anton-400.woff +0 -0
  146. package/engine/lib/fonts/ArchivoBlack-400.woff +0 -0
  147. package/engine/lib/fonts/Bangers-400.woff +0 -0
  148. package/engine/lib/fonts/Caveat-600.woff +0 -0
  149. package/engine/lib/fonts/Cinzel-400.woff +0 -0
  150. package/engine/lib/fonts/Cinzel-700.woff +0 -0
  151. package/engine/lib/fonts/CormorantGaramond-500.woff +0 -0
  152. package/engine/lib/fonts/CormorantGaramond-500i.woff +0 -0
  153. package/engine/lib/fonts/CormorantGaramond-700.woff +0 -0
  154. package/engine/lib/fonts/EBGaramond-400.woff +0 -0
  155. package/engine/lib/fonts/EBGaramond-400i.woff +0 -0
  156. package/engine/lib/fonts/EBGaramond-600.woff +0 -0
  157. package/engine/lib/fonts/Exo2-800i.woff +0 -0
  158. package/engine/lib/fonts/GochiHand-400.woff +0 -0
  159. package/engine/lib/fonts/IMFellEnglish-400.woff +0 -0
  160. package/engine/lib/fonts/IMFellEnglish-400i.woff +0 -0
  161. package/engine/lib/fonts/Inter-var.woff +0 -0
  162. package/engine/lib/fonts/JosefinSans-700.woff +0 -0
  163. package/engine/lib/fonts/Kalam-700.woff +0 -0
  164. package/engine/lib/fonts/LICENSES.md +40 -0
  165. package/engine/lib/fonts/LXGWWenKai-500.woff +0 -0
  166. package/engine/lib/fonts/LibreBaskerville-400.woff +0 -0
  167. package/engine/lib/fonts/LibreBaskerville-700.woff +0 -0
  168. package/engine/lib/fonts/LilitaOne-400.woff +0 -0
  169. package/engine/lib/fonts/Marcellus-400.woff +0 -0
  170. package/engine/lib/fonts/NotoSansSC-500.woff +0 -0
  171. package/engine/lib/fonts/NotoSansSC-700.woff +0 -0
  172. package/engine/lib/fonts/NotoSansSC-800.woff +0 -0
  173. package/engine/lib/fonts/NotoSansSC-900.woff +0 -0
  174. package/engine/lib/fonts/NotoSansSC-sub.woff +0 -0
  175. package/engine/lib/fonts/NotoSerifJP-600.woff +0 -0
  176. package/engine/lib/fonts/NotoSerifSC-sub.woff +0 -0
  177. package/engine/lib/fonts/OFL.txt +94 -0
  178. package/engine/lib/fonts/PlayfairDisplay-400i.woff +0 -0
  179. package/engine/lib/fonts/PlayfairDisplay-700.woff +0 -0
  180. package/engine/lib/fonts/PlayfairDisplay-700i.woff +0 -0
  181. package/engine/lib/fonts/Poppins-600.woff +0 -0
  182. package/engine/lib/fonts/Poppins-700.woff +0 -0
  183. package/engine/lib/fonts/Poppins-800.woff +0 -0
  184. package/engine/lib/fonts/PressStart2P-400.woff +0 -0
  185. package/engine/lib/fonts/Righteous-400.woff +0 -0
  186. package/engine/lib/fonts/RobotoCondensed-var.woff +0 -0
  187. package/engine/lib/fonts/Rye-400.woff +0 -0
  188. package/engine/lib/fonts/UnifrakturMaguntia-400.woff +0 -0
  189. package/engine/lib/fonts/cmunrm.woff +0 -0
  190. package/engine/lib/fonts/cmunti.woff +0 -0
  191. package/engine/lib/fonts/index.json +1 -0
  192. package/engine/lib/fonts.js +56 -0
  193. package/engine/lib/kit.js +91 -0
  194. package/engine/lib/media.js +118 -0
  195. package/engine/lib/medium.js +258 -0
  196. package/engine/lib/motion.js +111 -0
  197. package/engine/lib/paint.js +200 -0
  198. package/engine/lib/palettes.js +57 -0
  199. package/engine/lib/post.js +108 -0
  200. package/engine/lib/render.js +189 -0
  201. package/engine/lib/rig.js +390 -0
  202. package/engine/lib/rig_huashu.js +171 -0
  203. package/engine/lib/three.min.js +7 -0
  204. package/engine/lib/toon.js +186 -0
  205. package/engine/lib/typo.js +136 -0
  206. package/engine/lib/ui.js +141 -0
  207. package/engine/lib/util.js +92 -0
  208. package/engine/render.py +157 -0
  209. package/engine/scenes/01_cave.js +364 -0
  210. package/engine/scenes/02_egypt.js +524 -0
  211. package/engine/scenes/03_greek.js +448 -0
  212. package/engine/scenes/04_roman.js +555 -0
  213. package/engine/scenes/05_gothic.js +522 -0
  214. package/engine/scenes/06_renaissance.js +338 -0
  215. package/engine/scenes/08_impressionism.js +206 -0
  216. package/engine/scenes/09_postimp.js +183 -0
  217. package/engine/scenes/10_nouveau.js +334 -0
  218. package/engine/scenes/11_cubism.js +265 -0
  219. package/engine/scenes/12_bauhaus.js +214 -0
  220. package/engine/scenes/13_pop.js +269 -0
  221. package/engine/scenes/14_8bit.js +238 -0
  222. package/engine/scenes/15_raytrace.js +300 -0
  223. package/engine/scenes/16_2026.js +565 -0
  224. package/engine/scenes/17_ink.js +273 -0
  225. package/engine/scenes/18_klimt.js +227 -0
  226. package/engine/scenes/19_munch.js +153 -0
  227. package/engine/scenes/20_dunhuang.js +215 -0
  228. package/engine/scenes/21_kusama.js +124 -0
  229. package/engine/scenes/22_constructivism.js +205 -0
  230. package/engine/scenes/23_dali.js +221 -0
  231. package/engine/scenes/24_hopper.js +150 -0
  232. package/engine/scenes/25_ghibli.js +251 -0
  233. package/engine/scenes/26_vaporwave.js +191 -0
  234. package/engine/scenes/27_kirby.js +255 -0
  235. package/engine/scenes/28_monet.js +176 -0
  236. package/engine/scenes/29_seurat.js +104 -0
  237. package/engine/scenes/30_matisse.js +151 -0
  238. package/engine/scenes/31_haring.js +109 -0
  239. package/engine/scenes/32_rembrandt.js +217 -0
  240. package/engine/scenes/33_rubberhose.js +219 -0
  241. package/engine/scenes/34_shadowpuppet.js +195 -0
  242. package/engine/scenes/35_shinkai.js +197 -0
  243. package/engine/scenes/36_picasso_blue.js +123 -0
  244. package/engine/scenes/38_giotto.js +133 -0
  245. package/engine/scenes/39_piero.js +53 -0
  246. package/engine/scenes/40_raphael.js +96 -0
  247. package/engine/scenes/41_michelangelo.js +112 -0
  248. package/engine/scenes/42_guardi.js +70 -0
  249. package/engine/scenes/43_lorenzetti.js +145 -0
  250. package/engine/scenes/44_cortona.js +86 -0
  251. package/engine/scenes/45_renoir.js +86 -0
  252. package/engine/scenes/46_pissarro.js +82 -0
  253. package/engine/scenes/47_sisley.js +94 -0
  254. package/engine/scenes/48_gauguin.js +107 -0
  255. package/engine/scenes/49_chagall.js +60 -0
  256. package/engine/scenes/50_ma_yuan.js +131 -0
  257. package/engine/scenes/51_persian_miniature.js +149 -0
  258. package/engine/scenes/52_south_park.js +105 -0
  259. package/engine/scenes/53_pixar.js +60 -0
  260. package/engine/scenes/54_ghibli_lab.js +68 -0
  261. package/engine/scenes/55_dunhuang.js +161 -0
  262. package/engine/scenes/index.js +28 -0
  263. package/engine/spec_assets.py +76 -0
  264. package/engine/transitions.js +929 -0
  265. package/engine//346/227/266/344/273/243/344/275/234/350/200/205/350/247/204/350/214/203.md +49 -0
  266. package/lib/host.mjs +754 -0
  267. package/lib/render-bridge.mjs +543 -0
  268. package/lib/render-cli.mjs +98 -0
  269. package/lib/storyboard-lint.mjs +54 -0
  270. package/manifest.json +52 -0
  271. package/package.json +8 -4
  272. package/runtime/package.json +8 -0
  273. package/skills/biuart/SKILL.md +154 -0
  274. package/skills/biuart/references/01-/346/213/206/350/247/243.md +55 -0
  275. package/skills/biuart/references/02-/346/234/272/345/210/266.md +41 -0
  276. package/skills/biuart/references/03-/344/270/200/345/270/247/345/205/210/350/241/214/345/233/233/346/235/241/350/267/257/347/272/277.md +39 -0
  277. package/skills/biuart/references/04-/347/272/257/344/273/243/347/240/201/347/273/230/345/210/266.md +92 -0
  278. package/skills/biuart/references/05-/350/212/202/345/245/217/344/270/216/351/205/215/344/271/220.md +19 -0
  279. package/skills/biuart/references/06-/345/217/243/346/222/255/351/251/261/345/212/250/347/232/204/350/211/272/346/234/257/347/237/255/347/211/207.md +31 -0
  280. package/skills/biuart/references/07-/346/255/243/351/235/242/347/273/217/351/252/214.md +196 -0
  281. package/skills/biuart/references/08-/351/243/216/346/240/274/344/275/234/350/200/205/350/247/204/350/214/203.md +61 -0
  282. package/skills/biuart/references/09-/350/247/206/351/242/221/345/212/250/347/224/273/350/257/255/346/263/225.md +382 -0
  283. package/skills/biuart/references/10-/350/247/222/350/211/262.md +34 -0
  284. package/skills/biuart/references/11-/351/225/277/345/215/267/347/251/277/350/266/212/347/211/207.md +43 -0
  285. package/skills/biuart/references/12-/345/217/243/346/222/255/346/225/264/347/211/207/344/270/216/347/273/217/351/252/214/345/233/236/346/265/201.md +25 -0
  286. package/skills/biuart/references/13-/345/217/243/346/222/255/344/270/216/350/257/255/351/237/263/345/244/215/345/210/273.md +7 -0
  287. package/skills/biuart/references/15-/350/267/250/345/234/272/346/231/257/351/243/216/346/240/274/346/217/220/347/202/274.md +48 -0
  288. package/skills/biuart/references/16-/351/243/216/346/240/274/346/274/224/347/244/27295/345/210/206/345/215/217/350/256/256.md +103 -0
  289. package/skills/biuart/references/about-author.md +99 -0
  290. package/skills/biuart/references/capabilities.md +91 -0
  291. package/skills/biuart/references/compatibility.md +34 -0
  292. package/skills/biuart/references/images.md +97 -0
  293. package/skills/biuart/references/voice-model-review.md +18 -0
  294. package/skills/biuart/references//345/212/250/347/224/273/350/257/255/346/263/225/t1_3b1b.md +122 -0
  295. package/skills/biuart/references//345/212/250/347/224/273/350/257/255/346/263/225/t2_keynote_ui.md +117 -0
  296. package/skills/biuart/references//345/212/250/347/224/273/350/257/255/346/263/225/t3_finance_chart.md +116 -0
  297. package/skills/biuart/references//345/212/250/347/224/273/350/257/255/346/263/225/y1_kurzgesagt.md +193 -0
  298. package/skills/biuart/references//345/212/250/347/224/273/350/257/255/346/263/225/y2_vox.md +195 -0
  299. package/skills/biuart/references//345/212/250/347/224/273/350/257/255/346/263/225/y3_whiteboard.md +190 -0
  300. package/skills/biuart/references//345/212/250/347/224/273/350/257/255/346/263/225/y4_storytime.md +166 -0
  301. package/skills/biuart/references//345/212/250/347/224/273/350/257/255/346/263/225/y5_kinetic_type.md +158 -0
  302. package/skills/biuart/references//345/212/250/347/224/273/350/257/255/346/263/225/y6_presenter_explainer.md +24 -0
  303. package/skills/biuart/references//345/217/243/346/222/255API.md +125 -0
  304. package/skills/biuart/references//350/211/262/346/235/277.md +38 -0
  305. package/skills/biuart/references//350/247/222/350/211/262/347/262/276/347/273/206/345/272/246.md +61 -0
  306. package/skills/biuart/references//351/225/234/345/244/264/350/241/250/346/250/241/346/235/277.md +80 -0
  307. package/skills/biuart/references//351/225/234/345/244/264/350/257/255/350/250/200.md +73 -0
  308. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/01_cave.md +46 -0
  309. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/02_egypt.md +64 -0
  310. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/03_greek.md +50 -0
  311. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/04_roman.md +99 -0
  312. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/05_gothic.md +32 -0
  313. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/06_renaissance.md +41 -0
  314. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/08_impressionism.md +34 -0
  315. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/09_postimp.md +17 -0
  316. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/10_nouveau.md +31 -0
  317. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/11_cubism.md +30 -0
  318. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/12_bauhaus.md +30 -0
  319. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/13_pop.md +29 -0
  320. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/14_8bit.md +27 -0
  321. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/15_raytrace.md +32 -0
  322. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/16_2026.md +55 -0
  323. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/17_ink.md +50 -0
  324. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/18_klimt.md +37 -0
  325. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/19_munch.md +42 -0
  326. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/20_dunhuang.md +49 -0
  327. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/21_kusama.md +32 -0
  328. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/22_constructivism.md +35 -0
  329. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/23_dali.md +29 -0
  330. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/24_hopper.md +30 -0
  331. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/25_ghibli.md +55 -0
  332. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/26_vaporwave.md +27 -0
  333. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/27_kirby.md +30 -0
  334. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/28_monet.md +39 -0
  335. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/29_seurat.md +31 -0
  336. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/30_matisse.md +26 -0
  337. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/31_haring.md +22 -0
  338. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/32_rembrandt.md +29 -0
  339. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/33_rubberhose.md +31 -0
  340. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/34_shadowpuppet.md +40 -0
  341. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/35_shinkai.md +34 -0
  342. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/36_picasso_blue.md +25 -0
  343. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/37_rick_morty.md +48 -0
  344. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/38_giotto.md +67 -0
  345. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/39_piero.md +59 -0
  346. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/40_raphael.md +65 -0
  347. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/41_michelangelo.md +65 -0
  348. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/42_guardi.md +65 -0
  349. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/43_lorenzetti.md +69 -0
  350. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/44_cortona.md +66 -0
  351. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/45_renoir.md +66 -0
  352. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/46_pissarro.md +66 -0
  353. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/47_sisley.md +67 -0
  354. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/48_gauguin.md +66 -0
  355. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/49_chagall.md +59 -0
  356. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/50_ma_yuan.md +68 -0
  357. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/51_persian_miniature.md +66 -0
  358. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/52_south_park.md +65 -0
  359. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/53_pixar.md +61 -0
  360. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/55_dunhuang.md +41 -0
  361. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/INDEX.md +89 -0
  362. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/_/350/275/254/345/234/272_/350/277/201/347/247/273/346/265/213/350/257/225.md +53 -0
  363. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/_/351/207/215/345/201/232/350/277/233/345/272/246.md +37 -0
  364. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/_/351/237/263/350/275/250_/350/211/272/346/234/257/345/217/262/351/200/237/351/200/232.md +135 -0
  365. package/studio/app.js +380 -0
  366. package/studio/assert-panel-permit.mjs +67 -0
  367. package/studio/composer.css +465 -0
  368. package/studio/composer.js +480 -0
  369. package/studio/index.html +97 -0
  370. package/studio/optimize-prompt.mjs +84 -0
  371. package/studio/optimize-prompt.test.mjs +47 -0
  372. package/studio/recipes.mjs +87 -0
  373. package/studio/select-menu.js +450 -0
  374. package/studio/styles.css +71 -0
  375. package/studio/to-english-prompt.mjs +149 -0
  376. package/studio/to-english-prompt.test.mjs +72 -0
  377. package/README.md +0 -3
@@ -0,0 +1,382 @@
1
+ # 09 · 视频动画语法:YouTube 解说 / 科技 / AI / 财经片的 8 种画法
2
+
3
+ 做口播解说片的「动画段」时读这份。它是 8 张语法卡(`references/动画语法/`)的总目录、选型表、跨语法规律、库速查,以及给口播管线用的片段契约。
4
+
5
+ 8 种语法都有可直接渲的示范片(`scripts/engine/demos/<语法>/`,收进来时和实验原片逐像素一致;2026-10-05 修了 `TY.charsIn` 透明度后,y1 示范片标题按原意 0.55s 淡出,那 0.55s 的帧和原片不同)和参数化片段(`scripts/engine/clips/<语法>.js`,喂一份 JSON 就出一段时长精确的视频)。
6
+
7
+ ---
8
+
9
+ ## 一、总览
10
+
11
+ | 语法 | 适用场景 | 一句话核心语法 | 典型镜头时长 | 主缓动 | 主转场 | 卡片 | 示范 |
12
+ |---|---|---|---|---|---|---|---|
13
+ | **y1 Kurzgesagt 扁平科普** | 讲尺度、讲「里面是什么」、讲机制系统;娓娓道来的科普腔 | 把抽象概念画成一个具体的物,放进能无限缩放的发光世界,相机在尺度之间穿行;环境轻轻动,主体在口播节点上变化 | 硬切镜头 7–9s,视觉单元每 4.6–6.7s 换一次 | `MO.k75`=bezier(.75,0,.25,1);循环 `MO.easyEase` | 钻进镜头 `lensReveal`、填满再拉出 `matchCut`(相机对数推拉) | `动画语法/y1_kurzgesagt.md` | `--film demos/y1_kurzgesagt` |
14
+ | **y2 Vox 拼贴** | 有真实档案、新闻、截图、人物的论证;「看这一句」「注意这个数字」 | 论证摆在一张有真实材料的桌面上,相机像调查记者的眼睛在桌上移动,线和笔一顿一顿画上去 | 慢档中位 3.3s(一张卡 3–7s);快档 1.4–1.8s | 相机 `MO.sineInOut` / 长尾 `MO.longTail`;元素 12fps 步进 | 硬切、沿红线平移 `same`、推满照片→硬切 `cut` | `动画语法/y2_vox.md` | `--film demos/y2_vox` |
15
+ | **y3 白板手绘(RSA)** | 推理链、步骤、「为什么」;边讲边推导 | 说一句写一句,相机跟着论证在一张大白板上移动,最后拉远看全图 | 每块停留中位 6.6s | 板上平移 `MO.sineInOut` 1.2–2.4s;远跳 0.8s 甩镜+运动模糊 | 同一块板 `same`(相机运动就是转场),收尾拉远 | `动画语法/y3_whiteboard.md` | `--film demos/y3_whiteboard` |
16
+ | **y4 故事型简笔角色** | 第一人称讲经历、翻车、笑点;观众要的是「这个人」 | 口播是主角,画面是给口播配的表情包:姿势 0.1s 快切后定住,笑点靠切到反应特写并在那一下闭嘴 | ASL 2.43s(中位 1.87s) | 换姿势 `MO.expoOut` 0.1s+`MO.settle` 挤压回弹;角色 24fps | 硬切 `cut`、砸镜 `smash`、甩镜 `whip`、跳近 | `动画语法/y4_storytime.md` | `--film demos/y4_storytime` |
17
+ | **y5 动态文字** | 清单、「X 个阶段」、金句、数字开场、章节卡 | 字就是演员:关键词踩重音砸进来,主词大到一眼读完,画面永远只有一个焦点 | 一小节一个镜头(120BPM 约 2s) | `MO.expoOut` 入场、`MO.springHz` 砸入、退场 `MO.expoIn` 更快 | 冲进色块 `fillZoom`、色带 `bands`、推页 `push` | `动画语法/y5_kinetic_type.md` | `--film demos/y5_kinetic_type` |
18
+ | **t1 3Blue1Brown** | 讲一个机制怎么一步步变成另一个东西:网络、矩阵、梯度、概率 | 黑底上只放正在讲的那一个东西,用 Transform 把上一个概念直接变成下一个,颜色=概念名,几乎不切 | 单个动画 1–3s+停 1s;一个概念 8–20s | `MO.smooth`(6t⁵−15t⁴+10t³),几乎全用它 | Transform 接续(不切)、镜头穿越 `zoomThrough`、`fadeShift` | `动画语法/t1_3b1b.md` | `--film demos/t1_3b1b` |
19
+ | **t2 发布会界面** | 产品/功能发布、版本更新、教程步骤、参数公布 | 一屏一件事,产品截图或实物当主角并推近,名词和数字在口播说到时落定;光斑底、玻璃卡是可选包装,慎用 | 演讲一屏 5–8s;产品快剪 1.5–3s | `MO.spring` bounce 0–0.15、`MO.appleOut` | 模糊推进 `blurPush`、卡片展开 `expandRect` | `动画语法/t2_keynote_ui.md` | `--film demos/t2_keynote_ui` |
20
+ | **t3 财经图表** | 营收、股价、份额、拐点;观众会截图较真的数字 | 先搭坐标系,再让数据长出来,最后只标一件事;数值永远诚实,动画只决定怎么出现 | 一张图 2.5–6s | `MO.quintOut`、折线 `MO.smooth` | 面板横推 `slidePush`、推进局部 `zoomThrough`(live+bScale0)、硬切版式不动 | `动画语法/t3_finance_chart.md` | `--film demos/t3_finance_chart` |
21
+
22
+ 总览图:`assets/动画语法/<语法>_总览.jpg`(每镜一帧)。
23
+
24
+ 示范命令(在 `scripts/` 下):
25
+
26
+ ```sh
27
+ uv run --with playwright python engine/render.py --film demos/y1_kurzgesagt --out y1.mp4 # 渲示范片
28
+ uv run scripts/qa.py --project scripts/engine --film demos/y1_kurzgesagt --out <目录> # 验收(在 skill 根目录跑)
29
+ # 预览:起一个本地服务打开 scripts/engine/index.html?film=demos/y1_kurzgesagt 拖时间轴
30
+ ```
31
+
32
+ 示范片的时长都压到 8 秒左右,是真片节奏的 2.5–3 倍密度,只为在演示里看全语法。真用时按上表的镜头时长放慢。
33
+
34
+ ---
35
+
36
+ ## 二、怎么为一段口播选语法
37
+
38
+ 先看这段口播在干什么,再选画法。一支片子可以分段换语法,但同一段里不混。
39
+
40
+ | 这段口播在…… | 选 | 别选 | 为什么 |
41
+ |---|---|---|---|
42
+ | 讲一个概念、一个机制(「神经网络是怎么……」) | **t1 3b1b**(要推导、有公式)或 **y1 Kurzgesagt**(要尺度、要可爱) | y2(没有真实材料可贴,会变成假档案) | 机制靠形变和尺度讲得清 |
43
+ | 讲新闻、事件、历史,有截图和原话 | **y2 Vox** | y1(扁平卡通冲淡可信度) | 观众要亲眼看到出处 |
44
+ | 讲自己的经历、翻车、笑点 | **y4 storytime** | t2(自带好消息的情绪) | 笑点在反应镜头的停顿里 |
45
+ | 讲清单、几个要点、几个阶段、一句金句 | **y5 动态文字** | t1(没有能变形的对象) | 信息是结构,不是画面 |
46
+ | 讲产品、教程步骤、功能、参数 | **t2 发布会界面**(截图满幅并推近;玻璃卡可选) | t1(玻璃和光斑不承载逻辑,反过来也一样) | 一屏一件事、名词和数字当主角 |
47
+ | 讲数字、增长、走势、对比 | **t3 财经图表** | t2 的大数字(只有一个数时才用它) | 要坐标系和单位,要能被较真 |
48
+ | 边讲边推导、一步一步论证 | **y3 白板** | 一次整屏切换 | 说一句写一句,最后拉远是落点 |
49
+
50
+ 两条兜底:
51
+ - 有真实截图要放 → t2(教程,干净)或 y2(论证,证据感)。截图当主画面、尽量满幅,一律等比放,不裁关键 UI。
52
+ - 一段里只有一个数 → 不画图表,用 t2/y5 的大数字计数,在口播说出数值那一刻落定。
53
+
54
+ ---
55
+
56
+ ## 三、跨语法通用规律
57
+
58
+ 从 8 张卡里提炼的、换语法也成立的规矩。每条后面是出处。
59
+
60
+ 1. **相机只由时间决定,场景按相机矢量重画。** 推拉、平移、穿越都是同一个世界画布在不同相机下重画,所以放大 60 倍也不糊,转场里上一镜继续按时间推相机(`zoomThrough` 的 `live:true`)。(y1 ⑥「关键架构」;y3 ⑥;t1 ④-2)
61
+ 2. **缩放用对数插值,穿过圆形开口要够倍数。** `CAM.zlerp` 让每帧放大同样的倍数,线性插值会前慢后猛;穿进半径 r 的开口,倍数 ≥ 开口中心到最远屏幕角的距离 / r(居中时约 1100/r,`CAM.coverZoom`)。(y1 ⑧-2;t1 ④-2)
62
+ 3. **揭开那一帧对齐拍点或口播词。** 转场从新段起点开始算,要让新画面露出来的那一帧落在小节线上:段起点 = 小节线 − 揭开点 × 转场时长(`MO.onBeat`)。数字要在口播说出数值时落定:计数起点 = 说数字的时刻 − 计数时长。白板开写比对应短语晚约 0.5s。(y5 ④「对位技巧」;t2 ⑤;t3 ⑤;y3 ⑤)
63
+ 4. **先结构、后数据、最后标注。** 坐标系先出、数据后长、标注最后,一镜只标一件事;3b1b 是先 Write 问题再演示;发布会是眉题→产品名→副标题。(t3 ③;t1 ⑤;t2 ③)
64
+ 5. **一屏一个焦点。** 同一时刻只让一个东西入场,其余静止;主词和辅句至少 3:1;背景的饱和度、对比、线宽都比主角低一档。(y5 ⑧-1;t2 ⑤;y4 ⑧-2)
65
+ 6. **入场慢、退场快,落定后要停。** 入场 0.3–0.4s、退场约 0.18s;数字落定后至少停 0.5s,包袱后定住 ≥0.9s,3b1b 每个动画后 wait 约 1s。(y5 ⑤;t3 ⑧-3;y4 ⑤;t1 ⑤)
66
+ 7. **动在事件上,镜头有来有回。** 镜头只在观众视线要去新地方时动:过渡用缓推、横移、拉远(0.6–1.5 秒,缓入缓出,取 Vox、3b1b 实测),快推(0.28 秒推近 18–32%)、砸入(0.17 秒,1.55→0.94→1.0)只给揭晓、反转、关键数字;推进去之后要拉出来或横移开,不连着三镜往里推。每镜同一个动作就是 PPT,不管它是匀速慢推(诺奖文学片 r2,「完全是放ppt的感觉」)还是每镜快推一下(诺奖经济学短片 102 秒推近约 48 次,「次数太多,而且节奏太快了,一点都不smooth」)。数字和大字砸在片子世界里的物上(屏幕、电量条、价签、黑板),不单独起纯色底字卡——盲评里这种字卡和白底图表插页一样被读成「插了一页 PPT」。引擎里现成:`CAM.track`(镜头动作表,不写动作就是缓推)、`MO.slam`(元素砸入),时长常量在 `MO.PULSE`;参数化片段 t2、y1、y2 的 highlight 默认缓推,spec 顶层的 `data` 里写 `"camera": "snap"` 才是快推;没有内置的匀速慢推和呼吸。环境层(Kurzgesagt 的星闪、粒子)可以一直轻轻动;storytime 七成帧完全静止,生命在快切+定住。艺术风格速通是另一回事,画要一直活(见 04 号)。动作表、各语法的镜头基调、次数什么时候要管,见 `镜头语言.md`。(y1 ③、⑧-1;y4 ⑧-1;t2 ③)
67
+ 8. **两层帧率:相机平滑,元素步进。** Vox 相机平滑、纸片/荧光笔/打字按 12fps 一拍二;storytime 角色 24fps、镜头 60fps。全部丝滑像企业宣传片,全部步进会晃。(y2 ③、⑧-1;y4 ③)
68
+ 9. **颜色=概念,强调色少。** 一个颜色讲一个概念(公式里的 W 和连线同是蓝),超过 3–4 种语义色就记不住;Vox 是黑、纸白、一种红,白板是黑加一个橙。(t1 ⑧-3;t3 ⑧-2;y2 ⑧-3;y3 ⑧-3)
69
+ 10. **转场放在换气和换话题处,不放在句子中间。** 甩镜切在两句之间,反应镜头放在沉默里;白板的平移卡新论点;Vox 硬切卡句读。(y4 ⑤;y3 ⑤;y2 ④)
70
+ 11. **审片要查逻辑和数字口径,不只看好不好看。** 实测抓到过的:「涨了 8.7 倍」应为「涨到原来的 8.7 倍」;展开成全屏后又从 0 重数;讲隐藏层却连到了像素;倍数要能从图上的数算出来。(t3 修订表;t2 修订表;t1 ⑥)
71
+ 12. **真实素材当主画面,保持原样。** 有截图、照片、录像、原文就让它满幅或接近满幅,推近到要讲的那块,代码只做解释、标注和运镜(`MD.cover` 满幅+焦点+推近,`MD.print` 冲印件,`MD.label` 黑底撕边标签;参数化片段 t2 的截图卡、y2 的照片默认就是满幅或占画面八九成);截图等比放、不裁关键 UI;数据只改「怎么出现」不改「是多少」;柱一律从 0 起,轴不从 0 起要写明;虚构数据每一镜标「示意数据」,真实数据不许出现这个角标。(t3 ②、⑧-1;片段契约)
72
+
73
+ ---
74
+
75
+ ## 四、库速查(`scripts/engine/lib/`,index.html 和 clip.html 都已加载)
76
+
77
+ | 文件 | 命名空间 | 有什么 |
78
+ |---|---|---|
79
+ | `motion.js` | `MO` | 镜头动作时长 `PULSE`(过渡 push/glide/pull,重音 punch/pan/slam)/`slamK/slam`(砸入 1.55→0.94→1.0)/`pulse`(动作进度)、`seg/at/anim/step`(12fps 步进)、manim `smooth/thereAndBack/rushInto/rushFrom/doubleSmooth/wiggle/lagged`、`sineInOut/cubic*/quart/quint/expo*/backOut/elasticOut`、`bezier` 与 `appleOut/emphasized/k75/easyEase/longTail`、SwiftUI `spring/smoothSpring/snappy/bouncy`、`springHz/settle`、`float`、`invert`(缓动反查)、`beat/onBeat`(拍号对齐)。画布尺寸 `U.setStage/onStage` 在 `util.js` |
80
+ | `camera.js` | `CAM` | `apply/with`、`toScreen/toWorld`、`zlerp`(对数缩放)、`coverZoom`、`anchor`、`pushTo`(推进某点、该点平滑移到中心或原地放大)、`at`(关键帧,沿路径平移)、**`track`(镜头动作表:`push` 缓推(默认)/ `pull` 拉远 / `glide` 找下一件 / `to` 推到指定相机 / `punch` 快推 / `pan` 快移 / `slam` 整帧砸入 / `shake` 震镜 / `cut` 硬切,相机只由 t 算)**、`layer`(视差)、`velocity/motionBlur`(甩镜模糊)、`drift`(手持微漂,只给艺术风格和纯氛围镜头) |
81
+ | `diagram.js` | `DG` | 点列 `cum/len/pointAt/drawPartial`(逐笔描出)/`xform/arcPts/ellipsePts/hand`(手绘抖动)/`revealMask/zigzag`(Reveal 揭开)、Transform `rectPts/circlePts/morph/shape`、颜色 `mix/mixA/rgba`、3b1b 色板 `MANIM`(已 ×1.5 饱和)/`saturate`、`math/write`(manim Write,先描边后填色)、`neuron/edgeEnds/edge/flash`、`indicate/circumscribe/brace`、白板 `board`(笔画时间线+笔间滑移)、`pen`(马克笔) |
82
+ | `typo.js` | `TY` | `text/width/font`、`wrap/fit`(折行;`fit` 缩字号到真放得下:行数 ≤ maxLines 且量过每行宽,单个长英文词也不出框;`soft:true` 放不下返回 `ok:false` 让你换方案,`balance:true` 多行折成等长)、`charsIn`(逐字上浮)、`rise`(遮罩升起)、`pop`、`blurIn`(从模糊浮出)、`typed/typedCount`(打字)、`marker/underline`、`slam`(主词砸入)、`keyword/keywordMarker`(关键词强调)、`fmt/count/tabular`(数字滚动与等宽数字) |
83
+ | `chart.js` | `CH` | `lin/ticks`、`grid/xLabels`(坐标系先出)、`bars`(从 0 长出+同步计数+高亮变灰)、`line/yAt`、`candles`、`callout`(点→引线→文字)、`tag/demoBadge/frame`(经济学人版式) |
84
+ | `ui.js` | `UI` | `mesh`(光斑底)、`grainTex`、`backdrop`、`shadow`、`glass`(毛玻璃卡)、`sheen`(光扫过)、`persp`(伪 3D)、`icon`、`rr/rrPath/scratch` |
85
+ | `collage.js` | `CL` | `paperTile/fillPaper`(纸纹)、`tornEdge/tornRect`(撕边)、`halftone/photo`(网点照片)、`placed/shadowed/slideIn`(倾斜滑入放平)、`tape/pin`、`stringPts/string`(红线)、`highlight`(毛边荧光笔)、`stickerEdge`(剪纸白边) |
86
+ | `media.js` | `MD` | 真实素材当主体:`cover`(满幅铺开,焦点 `fx/fy`、推近 `z`、裁切 `crop`,`fit:'contain'` 整张不裁)、`toScreen`(素材上的点/框 → 画面坐标)、`focusFor/zoomFor`(推近到某一块要几倍)、`print`(冲印件/拍立得:白边、旧纸色、投影、胶带)、`label`(黑底撕边标签,12fps 打字)、`frameAt`(帧序列取帧)、`size`。素材缺失一律报错,不画空白帧 |
87
+ | `toon.js` | `TOON` | `flat`(双色分面)、`glow/vgrad/circle/ellipse`、`bean`(豆子角色,只用于示范片和白模预演,不进成片;参数化片段 y4 已不再调用)与 `LOOKS/look`、`POSES`、`poseAt`(pose-to-pose+回弹)、`blinkAt`、`alive`、`env/mouth`(口型读包络)、`sweat/mark` |
88
+
89
+ 转场在 `transitions.js` 末尾「YouTube 解说语法的转场」一节:`same / lensReveal / matchCut / whip / smash / fillZoom / bands / push / zoomThrough / blurPush / expandRect / slidePush / fadeShift`,每个都写了一句说明和参数。硬切用原有的 `cut`。
90
+
91
+ 引擎相关的小改动:竖屏整片 `render.py --film <名> --width 1080 --height 1920`(或在 eras.js 写 `window.FILM_SIZE = [1080, 1920]`),引擎、转场、相机和各库按当前画布算,35 种艺术风格场景仍只按横屏画过;段的 `clip`(视频帧序列)默认等比铺满,写 `clipDraw(c, frame, lt, t)` 自己摆(推近、焦点、冲印件),帧或图片缺失直接报错、拒绝渲染;段可写 `dur`(秒)代替 `eighths`;`window.BPM` 改节拍;解说片写 `window.PUNCH = 0` 关掉拍点冲击(或单个转场写 `punch`);`window.SCENE_LIBS / SCENE_DIR` 让一支片子把代码放在自己的目录里(demos 就是这么组织的)。
92
+
93
+ **实验时的旧名 → 现在的名字**(读实验归档代码时对照):`YT.camAt→CAM.at`、`YT.camForAnchor→CAM.anchor`、`YT.apply/camera→CAM.apply/with`(相机字段 `zoom/rot` 改成 `z/r`)、`YT.ease.*→MO.*`、`YT.spring(t,f,d)→MO.springHz`、`YT.textIn→TY.charsIn`、`YT.type→TY.typed`、`YT.partial→DG.drawPartial`、`YT.at→DG.pointAt`、`YT.circlePts→DG.ellipsePts`、`YT.paperTile/halftone/tornEdge→CL.*`、`YT.bean/POSES/mouth→TOON.*`、`MN.*→DG.*`(`lerpPts→morph`、`C→MANIM`、`FONT_RM→FONT.rm`)、`GL.*→UI.*`、`MO.textIn→TY.blurIn`、`MO.count/fmt/tabular→TY.*`、`easeOutQuint/easeOutExpo→quintOut/expoOut`、转场 `k_lens→lensReveal`、`k_fill→matchCut`、`hardcut→cut`、y5 的 `zoomThrough→fillZoom`(和 3b1b 的镜头穿越撞名)。
94
+
95
+ 字体:中文黑体统一用 `PuHui-Medium/Bold/Heavy/Black`(开源版实际是思源黑体 Noto Sans SC 500/700/800/900,family 名沿用;见 `lib/fonts.js`),白板用 `LXGWWenKai-500`,两者都是 GB2312 全部 6763 个汉字的子集,换题目一般不用补字。公式 `CMU-rm/it`,发布会 `Inter`,财经数字 `RobotoCondensed`。思源黑/宋 `NotoSansSC/NotoSerifSC` 只含三支示范片用到的字,新内容别用。
96
+
97
+ ---
98
+
99
+ ## 五、片段契约(给口播管线的「动画段」)
100
+
101
+ 口播视频管线(无论你用哪套)在合适的段落调用这 8 种语法做动画段,由管线当导演选语法、从口播词级时间戳算 cue。这一节是双方的约定。
102
+
103
+ ### 入口
104
+
105
+ **口播管线里建议包一层脚本,不要手敲下面这些**:draft 从成片时间轴定时长、出词表和 spec 草稿 → render 解析 word、调本节的 render.py、数帧、换进剪辑工程、冻结 → verify 对章节逐帧核同步。作者自己的管线就是这样接的(那部分未随本仓库开源)。下面是引擎本身的接口。
106
+
107
+ ```sh
108
+ cd <skill>/scripts
109
+ uv run --with playwright python engine/render.py --spec clip.json --out 片段.mp4 # 无声 H.264 yuv420p
110
+ uv run --with playwright python engine/render.py --spec clip.json --alpha --out 片段.mov # ProRes 4444 带透明(不画背景,给管线叠层)
111
+ uv run --with playwright python engine/render.py --spec clip.json --stills 0.5,2,4 --out 静帧/ # 抽帧检查
112
+ # 预览:本地服务打开 scripts/engine/clip.html?spec=examples/t3_finance_chart.json 拖时间轴
113
+ ```
114
+
115
+ - 时长严格等于 `duration`:帧数 = round(duration × fps),第 i 帧的时间是 i / fps。H.264 每秒一个关键帧(GOP = fps),管线的渲染器按秒 seek 不冻帧。
116
+ - **单个片段最多撑 8 秒。** `duration` 超过 8 秒时 render.py 在开头和结尾各打印一次醒目警告,不报错(口播管线里有合法的长片段)。一个片段撑太久会读成一页 PPT:一个版式到底、要点越堆越长、背景从头死到尾。一支片要拆成多镜,每镜一个 spec(或一段 scenes),镜与镜换构图、不换画风(同一个 theme,最多 2 种语法),再拼接(SKILL.md 轨道档第 3–4 步、`references/镜头表模板.md`)。样例 spec 有 8.5–10 秒的,那是一段的写法示范,不是一支片的长度。
117
+ - **全片一套色:`theme`。** 一支片的所有 spec 写同一个 `"theme"`:色板名 `paper`、`poster`、`ink`、`navy`、`bauhaus`、`snow`、`wood`、`chalk`(色值见 `references/色板.md`),或对象 `{"name": "wood", "accent": "#B8452A"}` 只改一两个键,或完整 6 键 `{bg, surface, ink, sub, accent, accent2}`。名字写错、对象缺键(又没写 name)、色值不是 #hex → 启动失败。写了 theme 的语法不画大面积渐变底和霓虹光,辅助色都从这 6 个色派生。不写 theme 时各语法用自己的默认(y1 默认深墨平涂,不再是深紫星空)。t3 另外认旧写法 `"light"`、`"dark"` 和它自己的主题对象;`"paper"` 现在指纸本色板。
118
+ - 宽高和 fps 从 spec 读,默认 1920×1080@30;竖屏写 `width: 1080, height: 1920`(或命令行 `--width 1080 --height 1920` 覆盖 spec),每种语法都有竖屏排版。
119
+ - spec 里的素材路径相对 spec 文件(也可以写绝对路径);render.py 只服务 spec 里点名的文件。认这些字段:`cues[].image`、`cues[].frames`(录像帧序列:一个目录或路径数组)、`data.image`、`data.character`(y4 帧库目录)。路径怎么解析见 `engine/spec_assets.py`。
120
+ - 量这一段:`uv run qa.py --spec <clip.json>`(在 `scripts/` 下;整段当一段量确定性、运动、静止帧对、孤立跳变、耗时,竖屏按画幅缩;2 秒以内单调、平滑的推拉、横移、砸入记作镜头事件,不算跳变)。
121
+ - 交付:`uv run deliver.py 片段.mp4 --spec <clip.json> --out output/`。先过门禁 `film_gate.py`(快速运动帧占比 < 0.035 红灯;中段连续 0.3 秒以上的空画面红灯,片段再短也拦;不复制、非零退出),过了才复制并写 `交付说明.md`,事实段由脚本写。门禁是在 1–2 分钟的成片上标定的,10 秒以内的片段数值噪声大;片段要拼进成片的,在成片上跑 deliver.py。
122
+ - 页面报错(语法文件出错、图片或视频帧不存在)→ 非零退出,不出片。`qa.py --spec` 和 render.py 用同一套素材解析(`engine/spec_assets.py`),`frames` 和角色帧库都认。spec 里有字库没有的汉字只告警(会回退系统字体,换台机器会变样),常用字都在子集里。
123
+
124
+ ### spec
125
+
126
+ ```json
127
+ {
128
+ "grammar": "t3_finance_chart", // 8 选 1:t1_3b1b | t2_keynote_ui | t3_finance_chart | y1_kurzgesagt | y2_vox | y3_whiteboard | y4_storytime | y5_kinetic_type
129
+ "duration": 7, "fps": 30, "width": 1920, "height": 1080,
130
+ "safe": { "top": 0, "bottom": 520 }, // 可选:让开的边(px),见下
131
+ "alpha": false, // 可选:true = 不画背景(render.py --alpha 会自动设上)
132
+ "theme": "wood", // 一支片所有 spec 写同一个:色板名或对象,见上「全片一套色」
133
+ "data": { ... }, // 语法级参数,各语法认的字段见下面每节的「data」行;不认的字段直接忽略
134
+ "cues": [ { "at": 1.2, "kind": "bar", "text": "...", "sub": "...", "data": { ... }, "image": "截图.png", "dur": 1.0 } ]
135
+ }
136
+ ```
137
+
138
+ **cue 的公共字段**(每种语法认哪些见下面各节):
139
+
140
+ | 字段 | 含义 |
141
+ |---|---|
142
+ | `at` | 秒,必填。「揭开那一帧」:元素在 t = at 这一帧第一次可见(动画内部从 at 前一帧起算)。例外:`number` 的 at 是数字**落定**的时刻。cue 不必按时间排序,clip.js 会排;at 超过 duration 的 cue 告警后丢掉(看不到,也不占版面)。 |
143
+ | `kind` | 必填。**写了这个语法不认的 kind 不报错、什么都不画**——对着下面的表写。 |
144
+ | `text` | 主文字:标题、要点、标签、气泡原文、插入镜头的大字。 |
145
+ | `sub` | 辅文字:t2 卡片说明、y5 辅句、y4 气泡里实际显示的短句、y4 插入镜头里他打的那一行。 |
146
+ | `image` | 图片路径,相对 spec 文件(也可写绝对路径、`data:`、`http(s):`)。文件不存在 → 拒绝渲染。 |
147
+ | `frames` / `fps` / `loop` | 录像帧序列(t2 的截图卡、y2 的照片认):一个目录(按文件名排序取 png/jpg/webp)或路径数组;从 at 起按 `fps`(默认 30)播,播完停在最后一帧,`loop: true` 循环。版式按第一帧定。缺帧 → 拒绝渲染。 |
148
+ | `data` | 这个 cue 自己的参数(`index`、`rect`、`icon`……),见各节。 |
149
+ | `dur` | 只有少数 kind 读:t1 的 title/point/equation/line,t3 的 bar/line/candle,y1 的 enter,y4 的 react/insert。其它 kind 写了也不读。 |
150
+
151
+ **`safe`**:`{top, bottom, left, right, fill?}`(px,默认 0)。clip.js 把它和让开后的内容框 `ctx.box = {x, y, w, h}` 传给语法;`fill` 是可选颜色,渲完把让开的边涂成它(竖屏片里让图表成为和相邻 contain 截图同一位置、同一种底的「卡」;`--alpha` 时不涂)。**8 种语法都已接 `top` / `bottom`**(语法对象里都写了 `safe: true`,内容只排在 top..H−bottom 之间:t3 的坐标系与来源行、y2 的相机缩放与画面中心、t1/t2/y1/y3/y5 的版面、y4 的气泡与插入镜头大字);**`left` / `right` 目前没有语法按它排版**,写了只会被 `fill` 涂色、内容照样排到边上。竖屏 1080×1920 的口播片字幕带约在 1400–1520,`bottom` 取 490–570;横屏一般 `bottom` 160–220。新语法要接 safe,照 t3:版式的纵向基准加 `safe.top`、底部元素减 `safe.bottom`,或者直接按 `ctx.box` 排,再在语法对象里写 `safe: true`(没写而 spec 给了 safe 时 clip.js 会 console.warn)。
152
+
153
+ **`number`(大数字)的口径**——只有 t2、t3、y5 认,其它 5 种写了不显示:
154
+
155
+ | 项 | 规定 |
156
+ |---|---|
157
+ | 数值 | `data.value`(数,可负;不写当 0)。从 0 滚到 value(expoOut,先快后慢),负数用真减号「−」,整数部分自动加千分位。 |
158
+ | 格式 | `data.prefix`(如 `"¥"`)、`data.suffix`(如 `"%"`、`" 倍"`,要空格自己写)、`data.decimals`(默认 **0**;t3 的 `spec.data.decimals` 只管柱子标签,**number 不继承**,要小数就在 cue 里再写一遍)。 |
159
+ | 说明 | 写 `text`、`sub`、`data.text` 任一个都行,clip.js 把三者统一。 |
160
+ | 小标签 | `data.label`:t2 画在数字上方,y5 画在页左上;t3 不画。 |
161
+ | 时间 | `at` = 数字落定的时刻。t2、t3 在 at−0.9s 开始滚;y5 在 at−0.7s 换页并开始滚。所以 number 的 at 至少写 0.9(y5 0.7),否则第 0 帧就已经滚了一大半。 |
162
+ | 位置 | t2:单独一屏,上一屏在 at−0.9s 开始退场,不叠在卡上;t3:图区上方专留的一条,右对齐,说明在数字左边;y5:单独一页。 |
163
+
164
+ ### 各语法认的 cue
165
+
166
+ 下面每节第一行是 spec 级 `data`,表里是 cue。「最小 spec」是能渲出一段像样画面的最少写法,复制的是结构,内容按你的题材换;第一个 cue 都是画面事件,不是标题。
167
+
168
+ #### t1_3b1b(3b1b / manim 讲解:公式、曲线、要点)
169
+
170
+ spec 级 data:无。
171
+
172
+ | kind | 字段 | 说明 | 示例 |
173
+ |---|---|---|---|
174
+ | `title` | `text`,`data.color`,`dur` | at 起 Write;再来一个 title 时旧标题上移淡出;太长先缩字号、再折两行。不当开场用,第一帧先出对象 | `{"at":4,"kind":"title","text":"注意力就是加权平均"}` |
175
+ | `equation` | `data.tokens` 或 `text`,`dur`(首个 1.2s,之后 1.5s) | token:`{s, it?, col?, gap?, sub?, sup?, size?}`,`col` 写 manim 色名(`BLUE_C` `YELLOW` `GREEN_C` `TEAL_C` `RED_C`…)或 #hex。只给 text 时自动拆:单个字母斜体、连续字母(softmax)正体。第二个起从上一个 Transform 过来 | `{"at":1,"kind":"equation","text":"softmax(QK)V"}` |
176
+ | `point` | `text`,`dur` | 一句一行 Write,新的出来时旧的变灰。放不下时先让曲线让位(竖屏 50%→30%)、再缩字号(≥0.6 倍),还不够就新要点出来时整块上卷、最早的淡出(会告警) | `{"at":3,"kind":"point","text":"先算相似度"}` |
177
+ | `line` | `data.values`(等距 y)或 `data.points`(`[[x,y],…]`),`text`=曲线标签,`data.color`,`dur` | 坐标系先 Create 再画曲线;第二条起从上一条形变过来。有 line 时横屏左文右图、竖屏上图下文 | `{"at":2,"kind":"line","text":"损失","data":{"values":[9,5,3,2,1.5]}}` |
178
+ | `highlight` | `data.index`(第几个 point,从 0 起,默认最新)或 `data.target:"equation"` | Indicate+黄框留住 | `{"at":5,"kind":"highlight","data":{"index":0}}` |
179
+
180
+ 最小 spec:
181
+ ```json
182
+ {"grammar":"t1_3b1b","duration":6,"cues":[
183
+ {"at":0,"kind":"line","text":"每个词的权重","data":{"values":[1,2,7,2,1]}},
184
+ {"at":1.6,"kind":"equation","text":"softmax(QK)V"},
185
+ {"at":3.4,"kind":"point","text":"越像的词权重越大"},
186
+ {"at":4.6,"kind":"highlight","data":{"target":"equation"}}]}
187
+ ```
188
+
189
+ #### t2_keynote_ui(发布会界面:功能卡、截图卡、大数字)
190
+
191
+ spec 级 data:`eyebrow`(标题上方小字)、`title`、`subtitle`、`accent`(强调色,默认 `#3d6bff`)、`frame`(截图卡的包装:默认 `"full"` 满幅;`"glass"` 是旧版毛玻璃卡,可选、慎用)。
192
+
193
+ | kind | 字段 | 说明 | 示例 |
194
+ |---|---|---|---|
195
+ | `title` | `text`/`sub` 覆盖 data.title/subtitle | at 起从模糊里浮出。不当开场用,先上截图或数字 | `{"at":5,"kind":"title"}` |
196
+ | `card` / `step` / `image`(同义) | `text` 卡标题,`sub` 说明,`image` 截图;`data.step` 指定编号;无图卡可加 `data.icon`(`wave memory agent clock phone layers chart code check play bolt lock`)、`data.value/prefix/suffix/decimals/label`(卡上计数) | 有图(默认 `frame:"full"`):一屏一张,截图满幅铺开(等比不裁;`data.fit:"cover"` 按 `data.focus:[fx,fy]` 裁满),四周垫同图的压暗模糊版;`text`/`sub` 是左下角黑底撕边标签;at 这一帧硬切进来(0.17s 轻砸),上一屏也是满幅截图时同倍率横移 0.30s 换过去。`data.frame:"glass"` 用旧玻璃卡。也认 `frames`(录屏帧)。无图:连着的最多 3 张并排一屏 | `{"at":2,"kind":"card","text":"一句话出图","sub":"不用写提示词","data":{"icon":"bolt"}}` |
197
+ | `highlight` | `data.rect=[x,y,w,h]`(相对截图 0..1),`text` 可选标签,`data.fill`(推近后框占画面的比例,默认 0.42) | 框出当前截图的一块并压暗其余;满幅模式下镜头同时推过去(至少推近 18%,最多 2.6 倍;默认缓推 0.9s,spec 顶层 `data.camera:"snap"` 为快推 0.28s),同一张图上的下一个 highlight 移过去(默认 0.7s,snap 0.30s) | `{"at":5,"kind":"highlight","data":{"rect":[0.6,0.2,0.2,0.1]}}` |
198
+ | `number` | 见上方 number 口径;`data.over: true` | 单独一屏。`data.over: true` 且上一屏是满幅截图:不另起一屏,镜头拉回整张截图、截图压暗、数字砸在上面计数——数字讲的就是这张截图里的事时用它,别切到光斑底 | `{"at":4,"kind":"number","text":"每月活跃用户","data":{"value":1.2,"decimals":1,"suffix":" 亿"}}` |
199
+
200
+ 最小 spec:
201
+ ```json
202
+ {"grammar":"t2_keynote_ui","duration":6,"cues":[
203
+ {"at":0.9,"kind":"number","text":"每月活跃用户","data":{"value":1.2,"decimals":1,"suffix":" 亿"}},
204
+ {"at":2.4,"kind":"card","text":"语音输入","sub":"说完就转成文字","data":{"icon":"wave"}},
205
+ {"at":3.6,"kind":"card","text":"长期记忆","sub":"记得你上次说过什么","data":{"icon":"memory"}}]}
206
+ ```
207
+ 这是没有截图时的写法。有产品截图就用截图卡打头(`{"at":0,"kind":"card","image":"截图.png","text":"…"}`,见 `examples/t2_keynote_ui.json`;两张真实截图满幅+推近+横移,见 `examples/t2_fullbleed_pulse.json`)。
208
+
209
+ #### t3_finance_chart(经济学人式数据图)
210
+
211
+ spec 级 data:`title`、`unit`(副标题:指标与单位;放不下先缩再折两行)、`source`(左下来源;同上,并让开右下角标)、`badge?`(只有写了才画右下角标,如「示意数据」;真实数据别写)、`chart: "bar"|"line"|"candle"`、`series: [{label, value, color?}]` 或 K 线 `[{label, o, h, l, c}]`、`decimals`(柱/点标签,默认 1)、`prefix`、`suffix`、`highlight: {index, text, sub}`、`colors: {main, accent, dim}`、`upDown: "cn"`(红涨绿跌,默认)`|"us"`、`xAxis: "category"|"time"`(柱默认按类目每根写名字,折线/K 线默认按时间抽稀)、`theme`(也可写在 spec 级 `theme`):`"light"`(白底,默认)`|"dark"`(深底浅字)、八套色板名(`"paper"` 现在是纸本色板)或 `{bg, ink, sub, grid, bar, dim, red…}`;没写主题但 `safe.fill` 写了片子的底色时,图表底就用它,深色自动换深底浅字。
212
+
213
+ **图表镜头留在片子的世界里**:图表的底和前后镜头同色系(深色片用 `theme:"dark"` 或把片子底色写进 `safe.fill`),不要在夜景、深色片里突然切到一张白底报表;更好的是把图表画在片子世界里的物上——`--alpha` 出透明片段,贴到片子里的屏幕、黑板、一张纸上。
214
+
215
+ | kind | 字段 | 说明 | 示例 |
216
+ |---|---|---|---|
217
+ | `title` | — | 版式(标题、副标题、来源)出现的时刻。可以不写:不写时版式在第 0 秒随坐标系一起出 | `{"at":0,"kind":"title"}` |
218
+ | `bar` / `line` / `candle` | `dur`(默认按根数);柱状图可写多个 bar,各带 `data.index`(数或数组)=这几根在这一刻才长 | 坐标系→数据长出。柱一律从 0 起;折线/K 线纵轴不从 0 时副标题自动加「纵轴未从 0 开始」;负数柱的数值写在柱底下方、标注往下走;类目名放不下先缩字再错成两行,被标注的那根永远有名字;刻度按步长取小数位 | `{"at":1.2,"kind":"bar"}` |
219
+ | `highlight` | `text`/`sub` 覆盖 data.highlight,`data.index` 第几根 | at 这一帧标注圆点弹出,引线+文字;斜向放会压到别的柱子或数值时改放这根正上方,顶上不够就自动加一档刻度 | `{"at":4,"kind":"highlight","data":{"index":2},"text":"最高"}` |
220
+ | `number` | 见上方 number 口径 | 图区上方专留一条,不压折线线头 | `{"at":5,"kind":"number","text":"最新收盘","data":{"value":259.97,"prefix":"¥","decimals":2}}` |
221
+
222
+ 最小 spec:
223
+ ```json
224
+ {"grammar":"t3_finance_chart","duration":6,"data":{"title":"三家公司的研发投入","unit":"2024 年,亿元","source":"来源:示意数据","badge":"示意数据","chart":"bar",
225
+ "series":[{"label":"甲","value":120},{"label":"乙","value":86},{"label":"丙","value":43}]},"cues":[
226
+ {"at":0.3,"kind":"bar"},{"at":3.5,"kind":"highlight","data":{"index":0},"text":"最多"}]}
227
+ ```
228
+
229
+ #### y1_kurzgesagt(扁平科普:中心物+卫星节点+尺度穿行)
230
+
231
+ spec 级 data:`center`(第一层中心物的名字)、`center_style: {color, shape: "circle"|"rounded"|"hex"|"diamond", ring: true}`(不写就按名字生成一个中性样式:颜色和形状由文字决定、同名同样式、没有轨道环)、`image`(把一张图片裁进中心物,名字移到下方胶囊里)、`flow: true`(节点串成一条链、信号依次流过、带序号,讲「先后」时用)。环境层(星闪、粒子、信号脉冲)一直轻轻动;中心物、节点、标签落定后停住,镜头不慢推。
232
+
233
+ | kind | 字段 | 说明 | 示例 |
234
+ |---|---|---|---|
235
+ | `title` | `text` | 顶部标题逐字上浮;第一个 highlight 或 enter 的 at 起 0.5s 淡出。不当开场用,第一帧先出节点 | `{"at":1,"kind":"title","text":"一次搜索经历了什么"}` |
236
+ | `point` | `text`,`data.color` | 当前这一层的一个卫星节点+标签胶囊。≤3 个排上半圈,≥4 个绕一整圈。标签按当前镜头夹在画内,长标签先缩字 | `{"at":1.4,"kind":"point","text":"分词"}` |
237
+ | `highlight` | `data.index`(只数当前层的 point,从 0 起,默认最新) | 推近到那个节点(约 30%;默认缓推 0.9s,spec 顶层 `data.camera:"snap"` 快推 0.28s),其余变暗;已经推近时,下一个 highlight 同倍率移过去 | `{"at":5,"kind":"highlight","data":{"index":1}}` |
238
+ | `enter` | `data.index`(钻进哪个节点,默认最新),`text`(新中心的名字,默认用节点名),`data.style`(新中心物的 center_style),`dur`(默认 1.6) | 尺度穿行:at 这一帧开始推进,约 at+0.55×dur 满屏同色、切到新一层,at+dur 新中心物拉出完毕;之后的 point 都属于新一层(第一个新 point 的 at 写在 at+dur 之后) | `{"at":4,"kind":"enter","data":{"index":0},"text":"分词器"}` |
239
+
240
+ 最小 spec:
241
+ ```json
242
+ {"grammar":"y1_kurzgesagt","duration":6,"data":{"center":"搜索引擎"},"cues":[
243
+ {"at":0.3,"kind":"point","text":"抓取"},{"at":1.1,"kind":"point","text":"索引"},
244
+ {"at":2.2,"kind":"enter","data":{"index":1},"text":"倒排索引"},
245
+ {"at":4.2,"kind":"point","text":"词 → 网页"}]}
246
+ ```
247
+
248
+ #### y2_vox(拼贴桌面:截图、剪报、红线、荧光笔)
249
+
250
+ spec 级 data:无。
251
+
252
+ | kind | 字段 | 说明 | 示例 |
253
+ |---|---|---|---|
254
+ | `image` / `clip`(同义) | `image` 或 `frames`(录像帧),`text`=压在左下角的黑底撕边标签(12fps 打字),`data.halftone: true` 转灰度网点,`data.fit:"cover"`+`data.focus`+`data.aspect` 按焦点裁满 | at 起滑入桌面;冲印件(白边、旧纸色、投影、胶带),默认等比不裁。镜头停在一张上时它占画面八九成。横屏左→右排、竖屏上→下排,红线先描出去,镜头在 at 前 0.30s 横移过去 | `{"at":1,"kind":"image","image":"截图.png","text":"官网首页"}` |
255
+ | `title` | `text`(空的或纯空格会告警并跳过) | 黑底白字标签条,打字 13 字/秒。适合收尾点题,不当开场 | `{"at":5,"kind":"title","text":"这件事有三条线索"}` |
256
+ | `point` | `text` | 横线索引卡,打字(间隔短会提速到最多 40 字/秒) | `{"at":4,"kind":"point","text":"发布时间比公告早一天"}` |
257
+ | `highlight` | `data.rect=[x,y,w,h]`(相对**当前这张图** 0..1;`fit:"cover"` 时相对裁后的画面) | 荧光笔扫过→红圈→镜头推过去(默认缓推 0.9s,spec 顶层 `data.camera:"snap"` 快推 0.28s;框起点在画外时先推、at 前一帧到位)。rect 目测常偏 20–30%,先 `--stills` 核 | `{"at":2.5,"kind":"highlight","data":{"rect":[0.1,0.2,0.3,0.1]}}` |
258
+
259
+ 最小 spec(y2 要真实材料:没有截图、照片、原文可贴就别选 y2,见第二节):
260
+ ```json
261
+ {"grammar":"y2_vox","duration":6,"cues":[
262
+ {"at":0,"kind":"image","image":"截图.png","text":"官网公告"},
263
+ {"at":1.6,"kind":"highlight","data":{"rect":[0.1,0.2,0.3,0.1]}},
264
+ {"at":4,"kind":"point","text":"两周后官网改了价格"}]}
265
+ ```
266
+
267
+ #### y3_whiteboard(白板手绘:说一句写一句、画图标、圈重点)
268
+
269
+ spec 级 data:无。
270
+
271
+ | kind | 字段 | 说明 | 示例 |
272
+ |---|---|---|---|
273
+ | `title` | `text` | 7.5 字/秒起,赶不上下一个 cue 自动提速。不当开场用,第一笔先画 | `{"at":4,"kind":"title","text":"为什么要写测试"}` |
274
+ | `point` | `text` | 先画小圈当项目符号再写,16 字/秒起 | `{"at":1.5,"kind":"point","text":"改代码时有人替你盯着"}` |
275
+ | `draw` | `data.icon`(`person cat network doc chat bulb check cross screen stack gear target clock chart`;写错会告警、只写说明字),`text`=图标下的说明(放不下先缩字号),`data.arrow: false` 不画箭头 | 和刚写的那条字并排;连续的 draw 用橙箭头连起来 | `{"at":2.5,"kind":"draw","text":"自动检查","data":{"icon":"check"}}` |
276
+ | `image` | `image` | 之字形揭开+手绘框,等比不裁 | `{"at":4,"kind":"image","image":"草图.png"}` |
277
+ | `highlight` | `data.index`(第几个,从 0 起),`data.target`: `"title"` / `"draw"` / `"image"`(默认数 point),`data.style: "underline"` | 橙圈圈住或划线;不写 index = 最新写出的那一条 | `{"at":5,"kind":"highlight","data":{"index":0,"style":"underline"}}` |
278
+
279
+ 最小 spec:
280
+ ```json
281
+ {"grammar":"y3_whiteboard","duration":6,"cues":[
282
+ {"at":0,"kind":"draw","text":"自动检查","data":{"icon":"check"}},
283
+ {"at":1.4,"kind":"point","text":"改代码时有人替你盯着"},
284
+ {"at":3.0,"kind":"draw","text":"敢放心重构","data":{"icon":"gear"}},
285
+ {"at":4.6,"kind":"highlight","data":{"target":"draw","index":0}}]}
286
+ ```
287
+
288
+ #### y4_storytime(豆子角色讲故事:气泡、反应特写、插入镜头)
289
+
290
+ spec 级 data:`character`——**必须是你自己的帧库**(AI 生帧,见 `references/10-角色.md`,交付线见 `references/角色精细度.md`);代码画的预设(`neutral`/`bun`/`author`)和造型对象已停用,写了或不写都启动失败。没有生图能力就别用 y4,换 y2/y5 或 scenes 用手和物讲。帧库写一个目录(render.py 把文件名去扩展名当姿势名:`rest talk point shrug type stiff react back`,`<姿势>_open` 是张嘴帧),也可写 `{"frames": {"talk": "我/talk.png", …}}`;帧图透明底、脚底在图片底边中间,至少要有 rest 或 talk。镜头定住、角色不呼吸,变化靠快切、反应特写砸进来和插入镜头。有 `window.VO_ENV` 就按口播包络对口型,没有就按字数合成。safe 只让字(气泡、插入镜头的大字);角色、桌子、反应特写的脸是图形,竖屏下会伸进字幕带——字幕压在身体上读得清,但别指望它们让开。
291
+
292
+ | kind | 字段 | 说明 | 示例 |
293
+ |---|---|---|---|
294
+ | `point` / `title`(同义) | `text`=口播原文(定张嘴时长,≈6.5 字/秒),`sub`=气泡里实际显示的短句(≤12 字最好;不写才显示 text),`data.pose`: `talk` / `point` / `shrug` / `type` | at 这一帧气泡弹出、开始张嘴 | `{"at":0.1,"kind":"point","text":"我让它帮我改个错别字,","sub":"就改一个字"}` |
295
+ | `highlight` | `data.mark`(默认「?」) | 「?」「!」弹出+摊手担心 | `{"at":4,"kind":"highlight","data":{"mark":"!"}}` |
296
+ | `react` | `dur`(从 at 起算,默认到下一个 cue) | 跳到反应大特写:死鱼眼+汗滴,一言不发 | `{"at":3,"kind":"react"}` |
297
+ | `insert` | `sub`=他在电脑上打的那一行(长了折行,最多 3 行),`text`=砸出来的大字,`data.hit`(**绝对秒**,默认 at+1.3,没有 sub 时 at+0.4),`data.count`+`data.unit`(右上计数器在砸出时停在这个数),`data.app`(窗口标题,默认「AI助手」),`dur`(从 at 起算,默认到下一个 cue) | 切到桌上电脑的屏幕特写:打字→回复像代码墙越滚越快→大字砸出 | `{"at":2,"kind":"insert","sub":"改个错别字","text":"改了 40 个文件","data":{"hit":3.4}}` |
298
+
299
+ 最小 spec:
300
+ ```json
301
+ {"grammar":"y4_storytime","duration":6,"cues":[
302
+ {"at":0.1,"kind":"insert","sub":"把「的」改成「得」","text":"改了 40 个文件","data":{"hit":1.5}},
303
+ {"at":2.6,"kind":"react"},
304
+ {"at":4.0,"kind":"point","text":"我只让它改一个字。","sub":"就改一个字"}]}
305
+ ```
306
+
307
+ #### y5_kinetic_type(动态文字:一个 cue 一页)
308
+
309
+ spec 级 data:`palette: [[底色, 字色], …]`(按页轮换)。
310
+
311
+ | kind | 字段 | 说明 | 示例 |
312
+ |---|---|---|---|
313
+ | `title` / `point` | `text` 主词(太长自动缩字号、最多两行),`sub` 辅句,`data.label`(左上小标签),`data.key`(辅句里要着色的那个词),`data.num`(背景巨型序号) | 主词在 at 这一帧砸进来,换页是色带擦除(at 前 0.3s 开始)。两个以上 point = 清单:画进度轨+背景巨型序号 | `{"at":1.8,"kind":"point","text":"慢","sub":"每次只改一处","data":{"label":"01","key":"一处"}}` |
314
+ | `number` | 见上方 number 口径 | 一页大数字 | `{"at":4,"kind":"number","sub":"一次跑通的比例","data":{"value":87.5,"decimals":1,"suffix":"%"}}` |
315
+ | `highlight` | `data.word`(主词里的词;不给就刷整个主词) | 荧光笔+放大一下;荧光笔和字同色(深蓝底黄字页)时笔下的字反白成底色。word 不在主词里会告警、什么都不做(辅句里的词用 `data.key`) | `{"at":3,"kind":"highlight","data":{"word":"慢"}}` |
316
+
317
+ 最小 spec:
318
+ ```json
319
+ {"grammar":"y5_kinetic_type","duration":5,"cues":[
320
+ {"at":0.7,"kind":"number","sub":"一次跑通的比例","data":{"value":87.5,"decimals":1,"suffix":"%"}},
321
+ {"at":2.2,"kind":"point","text":"慢","sub":"每次只改一处","data":{"key":"一处"}},
322
+ {"at":3.6,"kind":"highlight","data":{"word":"慢"}}]}
323
+ ```
324
+
325
+ ### 样例(`scripts/engine/examples/`)
326
+
327
+ ```sh
328
+ cd <skill>/scripts
329
+ uv run --with playwright python engine/render.py --spec engine/examples/t3_finance_chart.json --out t3.mp4 # 英伟达五个财年营收(10-K 真实数据):柱子分三次长出,各对一个词
330
+ uv run --with playwright python engine/render.py --spec engine/examples/t2_keynote_ui.json --out t2.mp4 # 截图卡打头+框出数字,竖屏截图,再一个大数字
331
+ uv run --with playwright python engine/render.py --spec engine/examples/t1_3b1b.json --out t1.mp4 # 梯度下降:损失曲线先出,公式变形,曲线变形
332
+ uv run --with playwright python engine/render.py --spec engine/examples/y2_vox.json --out y2.mp4 # 截图开场贴桌面、荧光笔+红圈+推近,结尾标签点题
333
+ uv run --with playwright python engine/render.py --spec engine/examples/y3_whiteboard.json --out y3.mp4 # 白板:先画再写,图标与短句交替,最后圈第一个图
334
+ uv run --with playwright python engine/render.py --spec engine/examples/t2_fullbleed_pulse.json --out t2b.mp4 # 两张真实终端截图满幅:推到计时、横移到第二张、拉回整张截图后数字砸在上面收尾(number 的 data.over)
335
+ # 另有 y1_kurzgesagt(一滴海水→钻进一只硅藻)/ y4_storytime(屏幕特写开场)/ y5_kinetic_type(数字砸入开场);任何一份加 --width 1080 --height 1920 出竖屏;样例素材在 examples/assets/:三张图表是 t3 自己渲出的终帧(数字已落定、无播放条、无路径),两张终端截图是真跑 python3 -m timeit 的输出截下来的
336
+ # 样例是写法示范:题材、构图和素材不要原样搬进成片
337
+ ```
338
+
339
+ ### 给管线导演的提醒
340
+
341
+ - 一段动画别塞太多 cue:按第一节的镜头时长,3–8 秒的片段放 2–5 个 cue 最舒服;cue 太密,写字会被迫提速、相机来不及到位。
342
+ - **写 spec 的三条底线**(翻页式 PPT 多半从这里来):第一个 cue 是画面事件(曲线、截图、数据长出、钻入、图标、屏幕特写、数字砸入),不是第 0 秒的 title;文字类 cue(title、point)不超过一半,同一个 kind 不连续出现 3 次;每条上屏的 `text`、`sub` 不超过 14 个字,口播原文交给字幕(y4 写了 `sub` 时 `text` 只定张嘴时长、不上屏,不受此限)。
343
+ - 画面里有字的语法(t1/t3/y3/y5)会和管线的烧录字幕抢视线,叠层时把字幕挪开或这段不烧。
344
+ - 透明模式(`--alpha`)只去掉背景层,元素本身的阴影还在;y2 的纸片、t2 的玻璃卡在透明底上读作「浮在画面上的卡片」。t3 透明底下字带一圈主题底色的光晕(默认白纸黑字=白光晕;`theme:"dark"` 是浅字深光晕),叠在别的画面上也读得清;t1 的白字带深色光晕。
345
+ - **竖屏里贴截图,要框口播正在念的那半句。** 竖屏桌面上一张截图约 900px 宽,网页里 16px 的正文要推近 2–2.5 倍才看得清;框住整段宽字(框宽接近画宽)时红圈放不下,镜头就推不进去。一句话跨两行就拆成两个 highlight,各对一个关键词(2026-10-04 实测:拆开后推近 2.4 倍,字高约 50px)。rect 目测常偏 20–30%,先 `--stills` 渲一张核。
346
+ - **语法文件里的步进动画要从 at 起算。** 「一拍二」之类的步进如果按绝对时间网格取整(`MO.step(t, 12)`),元素会比 at 早最多一格露出(30fps 下早 2 帧)。写成 `MO.step(t − at, 12)`,at 这一帧才是第一帧。y4 的角色帧仍按绝对 24fps 取,cue 落点可能差 1 帧,用前先核。
347
+
348
+ ---
349
+
350
+ ## 六、回归(2026-10-04 收进 skill 时)
351
+
352
+ | 对象 | 结果 |
353
+ |---|---|
354
+ | 16 段原片(`eras.js`)、36 段全风格样片(`--film gallery`) | 改前改后同一时刻 61 帧逐像素一致;qa 全部无报错、确定性 ✓,运动/跳变数字不变,耗时背靠背 21.5 → 22.3 ms/帧(噪声内) |
355
+ | 8 支示范片 vs 实验原片 | 每片 16 个时刻(含转场窗口)逐像素一致;qa 25 段全部无报错、确定性 ✓;运动、跳变、耗时和原工程一致(各片首段起点从 8/16s 变成 0,qa 采样窗口不同,所以首段数字略有出入) |
356
+ | 2026-10-05 终审修复后 | 8 份样例+16 原段+36 样片+8 支示范片共 87 段 qa 全部确定性 ✓、无页面报错;样例静帧只有预期的变化(t2 差 1 色阶=修确定性、y5 深蓝页关键词改橙、y1 标题真的淡出);独立终审 36 份 spec(横屏样例、竖屏、压力、边界、alpha)无 🔴 |
357
+ | 2026-10-10 脉冲镜头、真实素材件、竖屏整片进引擎后 | 16 段原片、36 段全风格样片、8 支示范片、长卷示范,各取 18 个时刻,横屏改前改后逐像素一致(示范片 y4 显式用 `char: 'author'`);9 份样例横竖屏都渲过、qa 确定性 ✓;竖屏测试片的 push / bands / iris / comicPanels 转场按 1080×1920 算对 |
358
+ | 已知的跳变 | y1_s3(42 倍→1 倍拉出中段)、y2_s2/s3(快摇与推满照片)、t1_s3(穿进神经元)、y5 拍点重音——都是设计内的相机推拉或节拍闪,原片里就有。2026-10-10 起 qa 把短于 0.35 秒的单调推拉、横移记作镜头事件:示范片里 t1_s3 的 1.51s、y5 k4_agent 的 2.2s、t3_s1 的 2.1s 改记镜头事件;其余都长于 0.35 秒(或是一拍二的单帧跳),照旧记跳变 |
359
+ | 2026-10-10 门禁与一条命令交付 | qa 改动前后:8 支示范片和 9 份样例 spec 的运动、静止帧对、确定性、框景不变;跳变只少了被认成镜头事件的那些(按事件计:示范片 3 处,样例 t2_keynote_ui 1 处、y4_storytime 3 处、y5_kinetic_type 2 处,都是 0.07–0.34 秒的推拉、砸入或姿势快切),长于 0.35 秒的推拉和一拍二的单帧跳照旧报;合成片(同三张图、每镜 3 秒):每镜匀速慢推 7.5% 快动帧 0.000 红灯,每镜一次 0.3 秒快推 30% 为 0.095 绿灯;整片模式里一次 0.3 秒快推以前记 8 个跳变,现在记 1 个镜头事件,闪一帧白仍记跳变 |
360
+
361
+ ---
362
+
363
+ ## 七、踩过的坑
364
+
365
+ - **(2026-10-04 接入口播管线实测)y2 推近后下一处框在画外,荧光笔在画外开扫。** 观众晚 7 帧才看到。已改:框的起点不在当前镜头里时,镜头先移过去、at 前一帧到位,再揭开;推近的倍数同时受「红圈留在画里」约束(红圈比框宽 1.24 倍、高 1.5 倍)。
366
+ - **(2026-10-04 参数化片段审片)t3 刻度撒谎、类目没名字、大数字压线头。** `fmtTick` 只在步长 <1 时留小数,步长 2.5 时 −2.5/2.5/7.5 被印成 −3/3/8;10 根类目柱竖屏按 `ceil(n/6)` 抽稀,被标注的「第一」恰好没名字;number 固定在图区右上角,上涨的折线线头正好在那。三处都改了(见第五节 t3 一行)。
367
+ - **(同上)y2 文字卡没打完相机就走。** 相机离开只看下一件的 at−0.95。现在按「打完+停 0.5s」才起跑(最晚 at−0.4),间隔短就把打字从 13 字/秒提到最多 40 字/秒。
368
+ - **(同上)普惠体 Medium/Bold 的全角空格字宽是 0。** 源字体(阿里巴巴普惠体 3.0 的 65/85 两个字重)本身就是 0,「美元 纵轴未从 0 开始」粘成一串。`font_subset.py` 抽子集时自动设成和「一」同宽;已有文件用 `--fix-widths` 修过。
369
+ - **(同上)t3 竖屏的标注正好落在烧录字幕带上。** 竖屏图表底部在 y≈1660,标注在 y≈1460,和 1080×1920 片子的字幕(1400–1520)重叠。加了 `safe`。
370
+
371
+ - **(2026-10-05 参数化片段终审)照样例写都对,换成竖屏和真实长度就出画。** 独立终审 33 份 spec(横屏样例、自写竖屏、压力、边界、alpha)查出 12 条 🔴:y2 空 text 让渲染器死循环卡住;y5 深蓝页荧光笔和黄字同色把主词涂没、竖屏长数字出画;t1 竖屏 7 条要点压进字幕带;t3 竖屏副标题与来源行出画、标注压邻柱、透明底叠深色看不见;y1 竖屏标签被切;y3 竖屏说明出画;y4 竖屏打字溢出气泡;t2 同一时刻先后渲差 1 色阶(复用的缓冲带上一帧残留)。另自测出 `TY.charsIn` 不乘外层透明度(y1 标题说好的淡出是一帧消失)、t3 最低负数柱的数值压类目名、`TY.fit` 只数行数不量行宽。规律:**凡是「放不下」的地方都要有退路——先缩、再折、再让位,最后才告警**;只在样例长度上调好的版式,一碰真实口播就破。
372
+
373
+ - **两组实验各写了一个 `window.YT`,API 完全不同。** 合并时按功能拆成 8 个命名空间,并给同名不同义的东西改名:G2 的 `zoomThrough`(冲进色块)→ `fillZoom`,G2 的 `spring(t, freq, decay)` → `MO.springHz`,G1 的 `circlePts`(开口椭圆)→ `DG.ellipsePts`。
374
+ - **woff2 字体过不了字形检查。** 引擎的 `U.loadCmaps` 只会解 WOFF1/TTF,G3 的 woff2 一加载就 console.error,qa 判失败。收进来时统一转成 woff。
375
+ - **全片时间读出来的背景会因为片子在时间轴上的位置不同而换相位。** 发布会示范的光斑原来排在 8–16s,单独成片后构图全变了,用 `T2.PHASE = 8` 保住定稿画面。参数化片段里光斑只读片段时间,不受这个影响。
376
+ - **刻度要把数据整个包住。** `CH.ticks` 只给区间内的整刻度,最大值 130 时最高刻度可能是 100,柱子顶出坐标系;片段里补齐了上下各一档。
377
+ - **系统字体不在 skill 里。** Vox 示范的宋体(Songti SC)、动态文字示范的代码字体(Menlo)用的是 macOS 系统字体,换台机器会变样;参数化片段已全部换成 skill 自带的字体。
378
+
379
+
380
+ ## 口播整片与第9种语法
381
+
382
+ 以上8种已提供参数化片段。另有[讲解员式财经科普](动画语法/y6_presenter_explainer.md),提供语法和整片参考代码,尚无参数化片段。完整口播制作、框景检查和经验回流见[口播整片与经验回流](12-口播整片与经验回流.md)。
@@ -0,0 +1,34 @@
1
+ # 10 · 角色:人用 AI 生帧,代码负责合成
2
+
3
+ 涉及生图或角色图片时,先按[图片能力指南](images.md)选择当前可用工具或导入现有素材;私人角色素材和平台选择不作为所有用户的默认。
4
+
5
+ ## 角色实现的选择
6
+
7
+ 同一角色可用三种方式实现(A、B的并排图见`assets/角色/花叔形象_对比.jpg`;C的效果见Kurzgesagt与白板示范片):
8
+ - **A 代码画**:只用于运动白模、预演和纯几何符号(方块、终端这类本来就是几何的东西)。人、拟人角色、机器人、长了脸的物不用代码画进成片,见`references/角色精细度.md`。
9
+ - **B 已定帧库直接贴**:容易保持角色一致,但需要协调帧库与场景的画风。
10
+ - **C 按该片画风生成动作帧再合成**:用参考图保持身份,绿幕抠图后交给代码控制动作与材质。
11
+
12
+ 真人和拟人角色只用B或C,做完过`references/角色精细度.md`的交付线;没有生图能力就只出手和背影,或不出人。风格卡里保留了各类角色的已知短板。
13
+
14
+ ## B:贴已定帧库
15
+
16
+ - 帧库:你自己已经定稿的角色帧(如挥手、拖拽等,每动作 8 帧透明 PNG;通用动作帧需自行准备;长卷示范附带的三段角色帧见`scripts/engine/demos/long_scroll/frames/`)。
17
+ - 引擎启动时作为图片资源加载;渲染按 `floor(t*9)%8` 换帧——有限动画,不做补间。
18
+ - 以脚底中心为锚点放置;`face=-1` 水平翻转。
19
+ - 给帧加所在片的材质(Vox 加白色剪纸边和投影;笔触类风格可在帧上再过一层细笔触 source-atop)。
20
+
21
+ ## C:按画风生一版
22
+
23
+ 1. **生图**:用 gpt-image 一类支持参考图的生图模型(prompt 写法可参考 [huashu-gpt-image](https://github.com/alchaincyf/huashu-gpt-image)),批量时串行跑。ref = 角色三视图设定稿或已定帧库的母版;prompt 写清:
24
+ - 该画风的**造型语法**(不是只写「XX 风格」):Kurzgesagt 纯色块不描边、同色相深一档做阴影;Vox 黑白网点剪报照片+白色剪纸边;白板黑色马克笔线稿+橙色排线;莫奈短笔触光斑……
25
+ - **姿势与镜头调度对齐**(「侧身朝右伸手指向右边」);要动就一张出多帧 sprite(4×2 八帧,帧数写在开头、「同一角色」锁一致性、只给关键姿势让模型补中间、「每帧站在单元格底部居中、大小一致」)。
26
+ - 绿幕 `#00B140`(白帽白 T 不能用白底)。
27
+ - 定规(以花叔形象为例):**纯白**渔夫帽(模型爱画成浅灰,要写死)、圆框黑眼镜、白 T、卡其短裤、白洞洞鞋、左手腕黑手表、大头小身体。
28
+ 2. **验真**:以实际工具调用记录、输入/输出关联和人工视觉核对为依据;PNG元数据不能证明是哪一个模型生成。素材接入见[图片能力指南](images.md)。
29
+ 3. **抠图切帧**:`scripts/key_split.py`(去绿溢、按列切姿势;白板线稿用 `--white` 只裁不抠、贴进画面用 multiply);需要保留原画面坐标时用 `scripts/key_green.py`。
30
+ 4. **合成**:代码只决定位置、大小、朝向、换帧时机、材质;石子、涟漪、道具等互动物件仍用代码画并对齐到手的位置。
31
+
32
+ ## 什么时候还用代码画
33
+
34
+ 成片里:剪影、背影、手(照所在画风画到位),以及本来就是几何体的东西(方块、终端窗口)。机器人、Q 版小人、火柴人演故事、给物加脸,这几样停用,理由和替代做法见`references/角色精细度.md`。`lib/rig.js` 的少女/猫骨架与 `rig_huashu.js`、`lib/toon.js` 保留:用于运动参考(手在哪、脚在哪,给 AI 帧定锚点)、白模预演,以及艺术史速通这类风格示范里已经定稿的角色。
@@ -0,0 +1,43 @@
1
+ # 11 · 长卷穿越片:一个人从左走到右,穿过一幅幅名画
2
+
3
+ 《花叔穿越名画》(2026-10-05,123.7 秒,24 个世界)用的做法。和艺术史速通(同一个房间换画风)不同,这里是**一条横向长画卷**:每个世界是一段横向延展的画,首尾相接;主角一直往右走,跨过边界那一刻,他的画风和世界一起换。
4
+
5
+ 示范:`scripts/engine/demos/long_scroll/`,收了 3 段(埃及壁画 → 莫奈《日本桥》→ 8-bit 像素),约 15.6 秒。
6
+
7
+ ```sh
8
+ uv run --with playwright python scripts/engine/render.py --film demos/long_scroll --stills 1,5,9 --out 试渲 # 三张静帧
9
+ uv run --with playwright python scripts/engine/render.py --film demos/long_scroll --out long_scroll.mp4 # 整段
10
+ ```
11
+
12
+ 浏览器预览:在 `scripts/engine/` 起一个静态服务,打开 `index.html?film=demos/long_scroll`;`&only=28_monet,14_8bit` 只排这几段,`&v=330` 试别的步速。
13
+
14
+ ## 文件
15
+
16
+ | 文件 | 管什么 |
17
+ |---|---|
18
+ | `eras.js` | 片子入口:加载库、`FILM_ORDER`(段的顺序)、登记帧库、生成一个 `dur = WORLD.total` 的段 |
19
+ | `lib/world.js` | 骨架 `WORLD`:时间轴(走→停下互动→走)、主角行进、相机、按边界裁开的主角、边界、角标。**先读它的头部注释** |
20
+ | `lib/crossing.js` | `XING`:读帧库、画角色帧(`XING.actor`)、笔触材质、莫奈世界 |
21
+ | `lib/acts.js` | `ACT`:小剧本工具(打水漂的石子轨迹等) |
22
+ | `lib/xing2_*.js` | 几段共用的小工具,由段文件开头按需加载 |
23
+ | `segments/<id>.js` | 一个世界一个文件,调用 `WORLD.add({...})` |
24
+ | `frames/<key>/` | 角色帧库:8 张透明 PNG+`meta.json`(每帧脚底锚点 `ax/ay`、尺寸、是否离地 `air`;`ref_h` 是站立身高的像素数) |
25
+
26
+ ## 加一段
27
+
28
+ 1. 在 `segments/` 新建 `<id>.js`,调用 `WORLD.add({ id, year, name, w, hero, acts, back, front, seam })`,接口见 `lib/world.js` 头部注释。世界本身用代码画,优先把 `scenes/<id>.js` 里现成的风格场景改造成横向延展的版本(段宽 2000–2800)。
29
+ 2. 生角色帧:每个世界一张「走路 8 帧」,有互动的再加一张「互动 8 帧」,按该画风让生图模型重画、绿幕、切帧(`scripts/key_split.py`,做法见 10 号),放进 `frames/<key>/`,写好 `meta.json`。
30
+ 3. 把 `<id>` 加进 `eras.js` 的 `FILM_ORDER`。
31
+ 4. 渲静帧核边界两侧,再跑 `qa.py --project scripts/engine --film demos/long_scroll`,确定性必须 ✓。
32
+
33
+ ## 关键约定(全片统一,写死在骨架里)
34
+
35
+ - **地面线 `WORLD.GROUND = 760`,主角站立身高 300,主角在画面 720px 处。** 段两端(x=0 和 x=w 附近 ±150px)地面必须回到 760,地平线尽量落在 480–560,跨边界时两边才接得上。中间可以有桥、台阶(`ground: lx => y`)。
36
+ - **所有事件相对「互动开始」定时。** 用 `WORLD.actT(段)` 拿到互动开始的全片时刻,`r = S.t - WORLD.actT(ME)`;不要写「进段后第几秒」。全片步速后来从 330 提到 560,按这条写的段一处都不用改。
37
+ - **镜头只进不退。** 相机目标 = 主角 x − 720 + 互动时向前让出的 `lead`,取历史最大值再做高斯平滑,所以全程单调、停与起都不顿。互动想让镜头别动,就写 `lead: 0`。
38
+ - **每段的边界用该段的签名语言画**(`seam`:纸边、像素棋盘、彩块分栏线……),这是速通片「转场 = 下一个风格的签名语言」在长卷里的版本。
39
+ - **主角走路帧率随步速同比例**(`hero.fps`),8 帧一个步态循环;需要再过一层该画风的材质时,在段里写 `hero.draw(c, key, i, o, S)` 自己合成,不改共用库。
40
+ - **配乐**:画面先定,音乐后配。每段放整数拍,逐段把速度在 86–104 BPM 之间微调,让每条边界都落在小节第一拍(实测 24 条边界最大误差 11.7ms);人耳听不出 ±8% 的逐段速度差。
41
+ - **不要替主角加没要的梗。** 骨架里有「帽子上摞纪念品」的功能(`FILM_HAT_ITEMS`),容易与场景争夺视觉注意力,默认关闭。
42
+
43
+ 更多证据和数字见 `07-正面经验.md` 第 36–38 条。
@@ -0,0 +1,25 @@
1
+ # 口播整片与经验回流
2
+
3
+ 本页收录口播整片制作中的通用方法;不包含作者的私人反馈档案。片段接口仍见09号,角色见10号,长卷示范见11号。
4
+
5
+ ## 从口播到画面
6
+
7
+ 先确认脚本、口播和逐字时间,再做风格表与高光清单。动作挂关键词(如参考代码的`TM.cue`),不要把每一处时间写死。镜头跟着内容外框移动;字幕区是相机空间的约束,推近时也必须让开。
8
+
9
+ 白板在同一大画布上累计,块首第一笔与相机到位同步;块内再按语速写。用`const B = DG.board(...)`建立画板后,矩形调用`B.line(points, {smooth:false})`避免平滑样条鼓成椭圆。完整清单的阅读时间从最后一项呈现完成开始计算,不能把绘制时间算成可读停留。
10
+
11
+ Vox拼贴先建立物件、关系和相机,再加纸纹与装饰。讲解员片先安排不同版式和景别,后期只挪人物位置补不回单调分镜。
12
+
13
+ ## 验收与冻结
14
+
15
+ `qa.py`提供确定性、效率、动感、流畅及文字框景线索。框景可检测文字裁切、叠字、字幕区及近空白;装饰大字等可能误报,要看对应帧。浅底成片用`subzone_gate.py`补查图形进入字幕带;纹理底不适用这项深色像素阈值。
16
+
17
+ 交付前由没有参与制作的agent独立审片,长片至少两位。问题记录时间码、根因、改动和复验;旧问题回归与新问题发现分开。根据具体问题验收,不追逐总分。连续三轮同类问题仍在且两种修法均无效,回到素材或引擎能力;上游脚本问题回脚本处理。
18
+
19
+ 用户选定后同时冻结代码、时间轴、混音和字幕。候选成片与冻结版保存在项目内,未经确认不覆盖。
20
+
21
+ ## 经验如何回到skill
22
+
23
+ 每轮记录现象→根因→改法→验证→归宿。风格特有问题写对应语法卡,跨风格方法写09号,角色方法写10号,机器可量的写QA。反复出现的坑提炼为开工检查,做成引擎能力后减少文字规则。修改后让独立agent核验,写入CHANGELOG。
24
+
25
+ 项目的私人反馈、个人形象提示词和未公开素材留在项目内;公开skill只收可复用的方法与必要证据。
@@ -0,0 +1,7 @@
1
+ # 13 · 口播与语音复刻
2
+
3
+ 统一入口与配置见[可选语音指南](capabilities.md),接口细节见[口播API](口播API.md)。
4
+
5
+ 已有录音先沿用;需要新配音时,按用户配置选择系统声音或已绑定的复刻音色。`scripts/koubo.py say/train/voices`保留旧调用入口,和`scripts/capabilities.py`共用同一份安装目录外的配置。
6
+
7
+ 每次say只生成一条,不自动执行三候选或ASR。补配保留`--fit/--match`,完成后仍要核实台词、专名、接缝和字幕。具体模型、语速、音色与授权不从本文写死。
@@ -0,0 +1,48 @@
1
+ # 15 · 把艺术语言迁移到新场景
2
+
3
+ 何时读:新增艺术风格、把已有风格用于不同题材、拆分近邻画风,或用户只给艺术家/工作室名时。只查某个已有渲染参数可直接读相应实做卡。这里研究艺术语言;不替代用户的新故事、场景与角色。
4
+
5
+ ## 先分清四件事
6
+
7
+ - **风格语言**:笔触与材料、色彩关系、用光、造型、空间组织。它们应在题材变化后仍有辨识度。
8
+ - **构图倾向**:例如偏置重心、群组联系、尺度差。根据新画幅和事件重新求解,不是固定坐标或每镜同一布局。
9
+ - **内容与母题**:名画里的人物、衣服、桥、船、花园、神祇。除非本次需要,它们不随风格自动进入新作品。
10
+ - **叙事和动作**:谁想做什么、遇到什么阻力、动作如何改变局面。速度、运镜和节拍由内容决定;静谧画风可以画快动作,有限动画也可以有复杂事件。
11
+
12
+ 选定艺术家不是选定某张名画的模板。指定工作室时先定位影片/导演/时期等美术范围:吉卜力和皮克斯都不是全作品共用一套画法。按用户举例与题材缩小范围;确有多种同样合理的方向时,融入既有三方向设定稿供选择,不另加一轮形式化审批。
13
+
14
+ ## 跨作品提炼
15
+
16
+ 初次建立一个范围时,通常并看至少3件原作或3段不同场景的官方片段,尽量覆盖不同题材、尺度或光照。连续帧、同画局部和同构图换色不算独立样本。资料不足就标清缺口,不凑数、不声称已经看过。成熟且已有证据的卡按需补查,不要求每次重新研究。
17
+
18
+ 写一份简短的「风格提要」,放项目镜头表前或旁边:
19
+
20
+ 1. 适用范围与原作出处;作品归属、媒介和时期先核查。
21
+ 2. 3–5条可观察的稳定特征,每条注明哪些参考支持、哪些参考不适用。
22
+ 3. 区分于最近邻风格的两点。例如雷诺阿、毕沙罗、西斯莱不能共用一个碎笔触滤镜就算完成。
23
+ 4. 本次新场景的主体、事件、空间与画幅;依需求重构,不能从参考里顺手拿。
24
+ 5. 要保留的视觉关系、可改变的内容、待验证的技术路线。
25
+
26
+ 把「画里出现了什么」与「画家怎么把它画出来」分开记录。色板写主色关系和明暗组织,不声称某组十六进制是艺术家的固定标准色;3–6个主色不意味着每个像素只准使用这些色。纹理、混色、阴影和反光应服从主色关系。既有颜色偏好与门禁照用;确需例外按现有流程注明题材理由,不偷偷关检测。
27
+
28
+ ## 先验证新场景,再把它做成能力
29
+
30
+ 先按本次题材出设定稿,仍遵循已有三方向机制。人物、动物、道具与背景的造型、边缘、光和材料必须一起处理;不能只给背景换滤镜。渲染路线依当前能力选,说明哪部分用代码、现有素材、角色帧库或其他已获准工具。
31
+
32
+ 第一次把研究卡升级为可迁移配方时,用不同场景做压力测试,通常包括人物行动、无人/物体场景、明显改变尺度或环境的场景。题目可由卡中例子启发,不能把这些例子变成新的固定模板。风景画家能否画角色特写属于待证范围,不提前承诺所有题材都适配。
33
+
34
+ 先核静帧:去掉艺术家名字和名作标志物,形体、色光、笔触、空间是否仍有辨识度?与近邻风格并排,有没有实际差别?然后核动态:动作接触、遮挡、纹理坐标、角色身份、材质统一和正常速度观看。静帧好看不证明动画流畅;文字规划合理不证明画面成立。
35
+
36
+ ## 状态要诚实
37
+
38
+ - **研究配方**:有来源和明确视觉假设,可指导尝试;没有专用实现或画面验证。不能仅凭同名Markdown卡就调用`render.py --solo <id>`。
39
+ - **单场景实做**:有实现、输出与检查记录,仅覆盖那个场景。记录参考参数和失败边界。
40
+ - **跨场景验证**:不同新场景通过独立画面审查,记录已覆盖范围;动画验证另行写清。程序化场景按08号登记,引擎QA与交付门禁照旧。
41
+
42
+ 一个工作室有一个分支通过,不代表整个家族通过。新卡不借用旧样片的星级、性能或验收结论。旧卡里的同房间参数是历史实做证据,只在匹配的场景有参考价值。
43
+
44
+ ## 经验回流
45
+
46
+ 使用前读对应卡的范围、短板与最新实测。完成后在卡中记录日期、任务与场景、来源、实现/输出证据、观察、修法、验证状态和边界。若新证据推翻旧结论,修原句并检查相关路由;若故障可稳定复现,先修工具并测。用户选择记录在品味档案;单次作品特征不升级为所有作品的规则。
47
+
48
+ 本流程来源:2026-10的风格库扩充,用户明确要求关注艺术家整体风格、适配不同创作场景。来源研究与实现假设分开;证据不足的条目保持研究状态。