@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
package/engine/clip.js ADDED
@@ -0,0 +1,104 @@
1
+ // 参数化片段运行时:一份 spec(JSON)→ 一段时长严格等于 spec.duration 的动画。给口播视频管线当「动画段」用。
2
+ // 契约见 references/09-视频动画语法.md「片段契约」。和 engine.js 的区别:没有段落表/转场,一个语法一个 draw(c, t, ctx),画布尺寸从 spec 读(竖屏也行)。
3
+ //
4
+ // spec.finish(可选):成片质感层,预设 soft / film / punch / clean 或对象,见 lib/finish.js;alpha 模式忽略。
5
+ // spec = { grammar, duration, fps=30, width=1920, height=1080, safe?: {top,bottom,left,right(px,留给字幕/平台 UI), fill?(让开的边涂这个色)}, theme?, alpha?, data?, cues: [{at, kind, text?, sub?, data?, image?, frames?, fps?, dur?}] }
6
+ // spec.theme:全片共用的色板(lib/palettes.js)——名字(paper poster ink navy bauhaus snow wood chalk)、{name, 要覆盖的键}、或完整 6 键 {bg, surface, ink, sub, accent, accent2}。
7
+ // 解析成 ctx.pal(完整 6 键+name),各语法按它上色;名字写错 / 缺键 → 启动失败。不写 → ctx.pal = null,各语法用自己的默认配色。
8
+ // 语法可以声明 legacyTheme(theme) → true:这个 theme 是它自己的旧写法(t3 的 'light' / 'dark' / 旧主题对象),不当色板解析,语法照旧读 ctx.theme。
9
+ // 素材路径(render.py 用 spec_assets.py 核存在并改写):cue.image、cue.frames(帧序列:目录或路径数组)、data.image、data.character.frames(y4 帧库)。
10
+ // 任何一张加载失败 → 启动失败、拒绝渲染(不出空白帧)。语法里取素材:ctx.still(q) = 这条 cue 的静态图(有 frames 时是第一帧),ctx.frame(q, t) = t 时刻该画的那一帧。
11
+ // 语法文件 clips/<grammar>.js 注册 CLIPS[grammar] = { init?(ctx), draw(c, t, ctx), safe?: true(按 ctx.safe / ctx.box 排版了才写,否则 spec.safe 会告警) }。
12
+ // 对齐约定(CLIP.lt):cue 的「揭开那一帧」= at 所在的那一帧——元素在 t = at 这一帧第一次可见,动画内部时间从 at − 1 帧起算。
13
+ (() => {
14
+ const cv = document.getElementById('c'), c = cv.getContext('2d');
15
+ window.__canvas = cv;
16
+ window.CLIPS = window.CLIPS || {};
17
+ const C = window.CLIP = {};
18
+ const fail = msg => { window.__bootFailed = msg; console.error('CLIP BOOT FAILED\n' + msg); };
19
+
20
+ // ---------- 给语法文件用的小工具 ----------
21
+ // 片内时间:cue 在 at 这一帧第一次可见
22
+ C.lt = (t, at, fps) => t - at + 1 / fps;
23
+ // 进度:从 at 起 dur 秒走完 0→1(at 这一帧已经 >0)
24
+ C.p = (t, at, dur, fps) => U.clamp(C.lt(t, at, fps) / dur);
25
+ // 等比放进框里(contain,不裁):返回 {x, y, w, h}
26
+ C.fit = (iw, ih, bx, by, bw, bh) => { const s = Math.min(bw / iw, bh / ih); const w = iw * s, h = ih * s; return { x: bx + (bw - w) / 2, y: by + (bh - h) / 2, w, h, s }; };
27
+ // 归一化矩形 [x,y,w,h](0..1,相对图片)→ 画面矩形
28
+ C.sub = (r, box) => ({ x: box.x + r[0] * box.w, y: box.y + r[1] * box.h, w: r[2] * box.w, h: r[3] * box.h });
29
+ C.text = (cue, ...fallback) => (cue && (cue.text ?? cue.data?.text)) ?? fallback.find(v => v != null) ?? '';
30
+
31
+ async function boot() {
32
+ let spec = window.CLIP_SPEC;
33
+ if (!spec) { // 预览:?spec=<相对 engine 的路径>
34
+ const u = new URLSearchParams(location.search).get('spec');
35
+ if (!u) return fail('没有 spec:render.py --spec 会注入 window.CLIP_SPEC;预览用 clip.html?spec=examples/<名>.json');
36
+ spec = await (await fetch(u)).json();
37
+ const base = u.replace(/[^/]*$/, '');
38
+ const fix = p => p && !/^(data:|https?:|\/)/.test(p) ? base + p : p; // 预览模式:frames 要写成路径数组(浏览器列不了目录),帧库要写 {frames: {姿势: 路径}}
39
+ (spec.cues || []).forEach(q => { if (q.image) q.image = fix(q.image); if (Array.isArray(q.frames)) q.frames = q.frames.map(fix); });
40
+ if (spec.data && spec.data.image) spec.data.image = fix(spec.data.image);
41
+ const ch = spec.data && spec.data.character; if (ch && typeof ch === 'object' && ch.frames && typeof ch.frames === 'object') for (const k in ch.frames) ch.frames[k] = fix(ch.frames[k]);
42
+ }
43
+ if (location.search.includes('render=1')) document.body.classList.add('render');
44
+ const W = spec.width || 1920, H = spec.height || 1080, FPS = spec.fps || 30;
45
+ if (!spec.grammar) return fail('spec 缺 grammar');
46
+ if (!(spec.duration > 0)) return fail('spec.duration 必须 > 0');
47
+ cv.width = W; cv.height = H; U.setStage(W, H);
48
+ // 语法文件(同步 XHR + eval,带 sourceURL,报错能定位)
49
+ const x = new XMLHttpRequest(); x.open('GET', `clips/${spec.grammar}.js`, false);
50
+ try { x.send(); } catch (e) { return fail('请求语法文件失败 ' + e); }
51
+ if (x.status !== 200) return fail(`没有这个语法:clips/${spec.grammar}.js(HTTP ${x.status})`);
52
+ try { (0, eval)(x.responseText + `\n//# sourceURL=clips/${spec.grammar}.js`); } catch (e) { return fail(`clips/${spec.grammar}.js 执行出错 ${e.stack || e}`); }
53
+ const G = CLIPS[spec.grammar]; if (!G || typeof G.draw !== 'function') return fail(`clips/${spec.grammar}.js 没注册 CLIPS['${spec.grammar}'] = { draw }`);
54
+ // 主题色板:在加载素材之前核,写错就别白等图片
55
+ let pal = null;
56
+ if (!(G.legacyTheme && G.legacyTheme(spec.theme))) { try { pal = PAL.resolve(spec.theme); } catch (e) { return fail(e.message); } }
57
+ // 成片质感层(spec.finish):写错预设名就别白等图片
58
+ let fin = null; try { fin = FINISH.resolve(spec.finish); } catch (e) { return fail(e.message); }
59
+ // 图片
60
+ const IMG = {}, urls = new Set();
61
+ for (const q of (spec.cues || [])) {
62
+ if (q.image) urls.add(q.image);
63
+ if (q.frames != null) { if (!Array.isArray(q.frames) || !q.frames.length) return fail(`cue ${q.kind} at=${q.at} 的 frames 要是非空的路径数组(render.py 会把目录展开成数组;预览模式只认数组)`); q.frames.forEach(f => urls.add(f)); }
64
+ }
65
+ if (spec.data && spec.data.image) urls.add(spec.data.image);
66
+ const chr = spec.data && spec.data.character;
67
+ if (chr && typeof chr === 'object') { if (!chr.frames || typeof chr.frames !== 'object' || Array.isArray(chr.frames)) return fail('data.character 写成对象时要有 frames: {姿势名: 图片路径}(或在 render.py 里给一个帧库目录)');
68
+ Object.values(chr.frames).forEach(f => urls.add(f)); }
69
+ try { await Promise.all([...urls].map(u => new Promise((res, rej) => { const im = new Image(); im.onload = () => { IMG[u] = im; res(); }; im.onerror = () => rej(u); im.src = u; }))); }
70
+ catch (u) { return fail('图片加载失败:' + u); }
71
+ // 字体+字形检查(spec 里的字缺字形只警告:回退系统字体照样能渲,但换台机器会变样)
72
+ for (const f of (window.FONT_FACES || [])) { const ff = new FontFace(f.family, `url(${f.url})`, f.desc || {}); await ff.load(); document.fonts.add(ff); }
73
+ await document.fonts.ready; await U.loadCmaps();
74
+ const cues0 = (spec.cues || []).map((q, i) => ({ ...q, i, at: +q.at || 0 })).sort((a, b) => a.at - b.at || a.i - b.i);
75
+ for (const q of cues0) if (q.at > spec.duration + 1e-9) console.warn(`cue ${q.kind} at=${q.at} 超出片段时长 ${spec.duration}s,看不到,已丢掉(不占版面)`);
76
+ const cues = cues0.filter(q => q.at <= spec.duration + 1e-9); // 看不到的 cue 不进语法:否则照样占排版位置、进度轨照样数它
77
+ // number 的说明字段各语法以前各认各的(t2/t3 认 text,y5 认 sub),写错了不报错只是没字。统一:text 与 sub 互为别名,data.text 也算
78
+ for (const q of cues) if (q.kind === 'number') { const cap = q.text ?? q.sub ?? (q.data && q.data.text); if (cap != null) { q.text = cap; q.sub = cap; } }
79
+ const safe = { top: 0, bottom: 0, left: 0, right: 0, ...(spec.safe || {}) }; // 让开的边(px):管线烧录字幕、平台 UI 压在这里,带字的语法不往里排
80
+ const box = { x: safe.left, y: safe.top, w: W - safe.left - safe.right, h: H - safe.top - safe.bottom }; // 让开之后的内容框,语法排版用它(ctx.box)
81
+ const ctx = { spec, data: spec.data || {}, theme: spec.theme || {}, pal, cues, W, H, FPS, u: Math.min(W, H) / 1080, portrait: H > W, alpha: !!spec.alpha, IMG, dur: spec.duration, safe, box,
82
+ of: (...kinds) => cues.filter(q => kinds.includes(q.kind)), lt: (t, at) => C.lt(t, at, FPS), p: (t, at, d) => C.p(t, at, d, FPS),
83
+ // 素材:still = 定版式用的那张(image,或 frames 的第一帧);frame = t 时刻画哪一帧(frames 从 at 起按 q.fps(默认 30)播,播完停在最后一帧,q.loop 循环)
84
+ still: q => q && (q.image ? IMG[q.image] : q.frames ? IMG[q.frames[0]] : null),
85
+ frame: (q, t) => !q ? null : q.frames ? MD.frameAt(q.frames.map(f => IMG[f]), t - q.at, q.fps || 30, !!q.loop) : q.image ? IMG[q.image] : null };
86
+ if (G.fonts) { const txt = cues.map(q => [q.text, q.sub, q.data && q.data.text].filter(Boolean).join('')).join('') + JSON.stringify(spec.data || {});
87
+ for (const fam of G.fonts) { const miss = U.missingGlyphs(fam, [...txt].filter(ch => ch.codePointAt(0) >= 0x2E80).join('')); /* 只查汉字与全角符号:拉丁/希腊/数学符号各语法另有字体 */ if (miss.length) console.warn(`字体「${fam}」缺字:${miss.join('')}(会回退系统字体;常用字已在 GB2312 子集里,生僻字用 scripts/font_subset.py --text 补)`); } }
88
+ if (spec.safe && (safe.top || safe.bottom || safe.left || safe.right) && !G.safe)
89
+ console.warn(`语法 ${spec.grammar} 还没接 safe(语法对象里没有 safe: true),spec.safe 被忽略:字幕带可能压在字上`);
90
+ if (G.init) G.init(ctx);
91
+ window.CLIP_CTX = ctx;
92
+ window.__total = spec.duration; window.__fps = FPS; window.__size = [W, H];
93
+ // safe.fill:让开的边涂成这个颜色(竖屏片把图表做成和相邻 contain 素材同一块「卡片」,外面是片子的底色);透明模式下不涂
94
+ const band = (safe.fill && !spec.alpha) ? (cc => { cc.fillStyle = safe.fill; const { top: t0, bottom: b0, left: l0, right: r0 } = safe;
95
+ if (t0) cc.fillRect(0, 0, W, t0); if (b0) cc.fillRect(0, H - b0, W, b0); if (l0) cc.fillRect(0, 0, l0, H); if (r0) cc.fillRect(W - r0, 0, r0, H); }) : null;
96
+ window.renderFrame = t => { c.setTransform(1, 0, 0, 1, 0, 0); c.clearRect(0, 0, W, H); c.save(); G.draw(c, t, ctx); c.restore(); if (fin && !spec.alpha) FINISH.apply(c, t, fin, W, H, FPS); if (band) band(c); };
97
+ window.prepare = async () => {};
98
+ window.__ready = true;
99
+ window.renderFrame(0);
100
+ const sc = document.getElementById('scrub'), tt = document.getElementById('tt'); sc.max = spec.duration; sc.step = 1 / FPS;
101
+ sc.oninput = () => { window.renderFrame(+sc.value); tt.textContent = (+sc.value).toFixed(3); };
102
+ }
103
+ boot().catch(e => fail(String(e && e.stack || e)));
104
+ })();
@@ -0,0 +1,19 @@
1
+ {
2
+ "_说明": "参数化片段 spec 的字段表,clip_lint.py 读它。来源是各 clips/<语法>.js 头注释;改语法时同步改这里。cue.data 里写了表外的键只是告警(语法可能认得更多)。",
3
+ "common": {
4
+ "spec": ["grammar", "duration", "fps", "width", "height", "safe", "theme", "alpha", "data", "cues", "finish"],
5
+ "cue": ["at", "kind", "text", "sub", "data", "image", "frames", "fps", "loop", "dur"],
6
+ "themes": ["paper", "poster", "ink", "navy", "bauhaus", "snow", "wood", "chalk"],
7
+ "finish": ["clean", "soft", "film", "punch"]
8
+ },
9
+ "grammars": {
10
+ "t1_3b1b": { "kinds": ["title", "equation", "point", "line", "highlight"], "specData": ["camera"], "cueData": ["tokens", "col", "color", "values", "points", "target", "index", "dur"], "needs": { "equation": ["text|data.tokens"], "point": ["text"], "title": ["text"], "line": ["data.values|data.points"] } },
11
+ "t2_keynote_ui": { "kinds": ["title", "card", "step", "image", "highlight", "number"], "specData": ["eyebrow", "title", "subtitle", "accent", "frame", "camera"], "cueData": ["step", "fit", "focus", "icon", "value", "prefix", "suffix", "decimals", "label", "rect", "fill", "over", "frame", "text"], "needs": { "number": ["data.value"], "highlight": ["data.rect"] } },
12
+ "t3_finance_chart": { "kinds": ["title", "bar", "line", "candle", "highlight", "number"], "specData": ["title", "unit", "source", "badge", "chart", "series", "decimals", "prefix", "suffix", "highlight", "colors", "upDown", "theme", "camera"], "cueData": ["index", "value", "prefix", "suffix", "decimals", "text", "sub"], "needs": {}, "specNeeds": ["data.series"] },
13
+ "y1_kurzgesagt": { "kinds": ["title", "point", "highlight", "enter"], "specData": ["center", "center_style", "image", "flow", "camera"], "cueData": ["color", "index", "style"], "needs": { "point": ["text"], "title": ["text"] } },
14
+ "y2_vox": { "kinds": ["image", "clip", "title", "point", "highlight"], "specData": ["camera"], "cueData": ["halftone", "fit", "focus", "aspect", "rect"], "needs": { "highlight": ["data.rect"], "title": ["text"], "point": ["text"] } },
15
+ "y3_whiteboard": { "kinds": ["title", "point", "draw", "image", "highlight"], "specData": ["camera"], "cueData": ["icon", "arrow", "index", "target", "style"], "needs": { "draw": ["data.icon"], "point": ["text"], "title": ["text"] } },
16
+ "y4_storytime": { "kinds": ["title", "point", "highlight", "react", "insert"], "specData": ["character", "camera"], "cueData": ["pose", "mark", "hit", "count", "unit"], "needs": {}, "specNeeds": ["data.character"] },
17
+ "y5_kinetic_type": { "kinds": ["title", "point", "number", "highlight"], "specData": ["palette", "camera"], "cueData": ["label", "key", "word", "value", "prefix", "suffix", "decimals", "num"], "needs": { "number": ["data.value"], "point": ["text"], "title": ["text"] } }
18
+ }
19
+ }
@@ -0,0 +1,203 @@
1
+ // 片段 · 3b1b / manim 式讲解(t1):纯黑底,一次只放正在讲的那一个东西;字和公式都是 Write(先描边后填色),缓动一律 smooth。
2
+ // 招牌是 Transform:上一个概念直接变成下一个,不切、不淡出重来。
3
+ // cues:title(at 这一帧开始 Write;再来一个 title 时旧标题 FadeOut 上移;太长先缩字号、再折两行)
4
+ // equation(data.tokens = DG.math 的 token 数组,或只给 text;颜色=概念名:col 写 'BLUE_C' 等 manim 色名或 #hex)
5
+ // 第二个起的 equation 不重新 Write,而是从上一个 Transform 过来(TransformMatchingTex:同名符号移到新位置,对不上的淡出/淡入;默认 1.5s)
6
+ // point(要点一句一行,Write;新要点出来时旧的变灰)
7
+ // line(坐标系先 Create,再画曲线:data.values = [y...](等距)或 data.points = [[x,y]...];text = 曲线标签;data.color)
8
+ // 第二个起的 line 是 Transform:上一条曲线逐点(按弧长对齐重采样)形变成这一条,颜色和标签一起换,坐标系不动
9
+ // highlight(Indicate+黄色框住并留住:data.index = 第几个要点(只数 point,从 0 起;默认最新);data.target = 'equation' 时框公式)
10
+ // 布局:有 line 时横屏左文右图、竖屏上图下文;要点块在剩下的高度里竖直居中。safe:内容只排在 top..H−bottom 之间。
11
+ // 公式太宽就整体缩字号(所有公式同一字号,Transform 时不跳),竖屏长公式不出画。
12
+ // 字形:CMU 斜体把 θ 画成 ϑ,θ 改用 EB Garamond 斜体(闭合的 θ);连续两个以上的字母(softmax、ReLU)按正体单词排,单个字母才是斜体变量。
13
+ // alpha:透明底时字外面描一圈深色边,压在亮画面上也看得见。
14
+ // spec.theme(全片色板 ctx.pal):底 bg、字 ink、变灰的旧要点和坐标轴 sub、强调框与 Indicate accent、默认曲线色 accent2;
15
+ // cue 里写的 manim 色名也映射进色板(YELLOW/GOLD/ORANGE/RED/MAROON/PINK → accent,BLUE/TEAL/GREEN/PURPLE → accent2,GREY → sub,WHITE → ink),#hex 照写的用。
16
+ CLIPS.t1_3b1b = (() => {
17
+ const { clamp, lerp } = U;
18
+ let M, L, INK = '#fff';
19
+ const col = v => !v ? null : M[v] || v;
20
+ // 全片色板时 manim 色名 → 色板里的色(只认 DG.MANIM 里有的名字;#hex 原样)
21
+ const palMap = p => { const m = { ...DG.MANIM };
22
+ for (const k in m) m[k] = /^(YELLOW|GOLD|ORANGE|RED|MAROON|PINK)/.test(k) ? p.accent : /^(BLUE|TEAL|GREEN|PURPLE)/.test(k) ? p.accent2 : /^GRE[YA]_[AB]$/.test(k) ? PAL.mix(p.sub, p.ink, 0.4) : /^GRE[YA]/.test(k) ? p.sub : k === 'WHITE' ? p.ink : k === 'BLACK' ? p.bg : m[k];
23
+ return m; };
24
+ const isZh = ch => ch.codePointAt(0) >= 0x2E80;
25
+ // 一段字 → token:汉字/全角走普惠体;连续 ≥2 个字母是单词(正体);单个字母斜体;其余(数字、符号、希腊字母)正体
26
+ const toks = text => (String(text).match(/[A-Za-z]{2,}|./gu) || []).flatMap(s => s.length > 1 && !/[a-z]/.test(s) ? [...s] : [s]) // 全大写的一串(QK)是几个变量,拆开
27
+ .map(s => ({ s, zh: isZh(s), it: /^[a-zA-Z]$/.test(s), gap: 0 }));
28
+ // θ 用 EB Garamond 斜体画(CMU 的 θ 是 ϑ 字形)。只换这一个 token 的字体:逐 token 调 DG.math,期间临时改 DG.FONT
29
+ const THETA = /[θΘ]/;
30
+ const withFont = (tk, fn) => { if (!THETA.test(tk.s)) return fn(tk); const o = { ...DG.FONT }; DG.FONT.it = DG.FONT.rm = 'EBGaramond-400i';
31
+ try { return fn({ ...tk, zh: false, it: true }); } finally { Object.assign(DG.FONT, o); } };
32
+ const layoutT = (c, tokens, size) => { let x = 0; return tokens.map(tk => { const w = withFont(tk, t2 => DG.layout(c, [{ ...t2, gap: 0 }], size)[0].w), sz = (tk.size || 1) * size;
33
+ const r = { x, w }; x += w + (tk.gap != null ? tk.gap : sz * 0.06); return r; }); };
34
+ const widthT = (c, tokens, size) => { const l = layoutT(c, tokens, size); return l.length ? l[l.length - 1].x + l[l.length - 1].w : 0; };
35
+ // Write 一串 token(等价于 DG.math 整串调用:token 间按 manim LaggedStart 错开),返回每个 token 的屏幕 {x, w}
36
+ const writeT = (c, tokens, x, y, size, p, { align = 'center', col: cl = '#fff' } = {}) => {
37
+ const Lt = layoutT(c, tokens, size), tot = Lt.length ? Lt[Lt.length - 1].x + Lt[Lt.length - 1].w : 0, x0 = align === 'center' ? x - tot / 2 : align === 'right' ? x - tot : x;
38
+ const n = tokens.length, r = Math.min(4 / (n + 1), 0.2);
39
+ tokens.forEach((tk, i) => { const q = MO.lagged(i, n, clamp(p), r); if (q > 0) withFont(tk, t2 => DG.math(c, [t2], x0 + Lt[i].x, y, size, { p: q, align: 'left', col: cl })); });
40
+ return Lt.map(l => ({ x: x0 + l.x, w: l.w }));
41
+ };
42
+ // 按弧长等分重采样成 n 个点(Transform 前两条曲线要点数相同、起点对齐)
43
+ const resample = (pts, n) => { const cum = DG.cum(pts), T = cum[cum.length - 1]; return Array.from({ length: n }, (_, i) => DG.pointAt(pts, cum, T * i / (n - 1))); };
44
+ // 折行但各行等长(不让一个字母/单词孤零零挂到下一行)
45
+ const balance = (g, text, maxW, font) => { const n = TY.wrap(g, text, maxW, font).length; if (n < 2) return [text];
46
+ let lo = maxW * 0.4, hi = maxW; for (let k = 0; k < 14; k++) { const m = (lo + hi) / 2; if (TY.wrap(g, text, m, font).length > n) lo = m; else hi = m; } return TY.wrap(g, text, hi, font); };
47
+ // 标题:先缩字号放一行(最小 0.75),放不下就等长折行(竖屏最多 3 行、横屏 2 行),再缩到每行放得下
48
+ const titleLines = (c, text, maxW, size, maxLines) => {
49
+ let s = size; while (s > size * 0.75 && widthT(c, toks(text), s) > maxW) s *= 0.95;
50
+ if (widthT(c, toks(text), s) <= maxW) return { size: s, lines: [text] };
51
+ s = size * 0.9; let lines = balance(c, text, maxW, `${s}px "PuHui-Medium"`);
52
+ while (lines.length > maxLines) { s *= 0.94; lines = balance(c, text, maxW, `${s}px "PuHui-Medium"`); }
53
+ while (s > size * 0.45 && Math.max(...lines.map(l => widthT(c, toks(l), s))) > maxW) s *= 0.95;
54
+ return { size: s, lines };
55
+ };
56
+ let BUF;
57
+ return {
58
+ fonts: ['PuHui-Medium'],
59
+ safe: true,
60
+ init(ctx) {
61
+ M = ctx.pal ? palMap(ctx.pal) : DG.MANIM; INK = ctx.pal ? ctx.pal.ink : '#fff'; DG.FONT.zh = 'PuHui-Medium'; // 任意中文:普惠体(思源宋子集只有示范片用到的字)
62
+ const { W, H, u, safe } = ctx, g = document.createElement('canvas').getContext('2d');
63
+ const pad = (ctx.portrait ? 70 : 140) * u, yTop = safe.top, yBot = H - safe.bottom - (ctx.portrait ? 90 : 70) * u;
64
+ const hasLine = ctx.of('line').length > 0, hasEq = ctx.of('equation').length > 0;
65
+ // 标题
66
+ const titles = ctx.of('title').map(q => ({ q, ...titleLines(g, q.text || '', W - 2 * pad, (ctx.portrait ? 72 : 62) * u, ctx.portrait ? 3 : 2) }));
67
+ const tH = titles.length ? Math.max(...titles.map(z => z.lines.length * z.size * 1.25)) : 0;
68
+ const titleY = yTop + (ctx.portrait ? 170 : 130) * u;
69
+ let y = titles.length ? titleY + tH : yTop + 90 * u;
70
+ let eqSz = (ctx.portrait ? 72 : 66) * u;
71
+ for (const q of ctx.of('equation')) { const tk = q.data && q.data.tokens ? q.data.tokens : toks(q.text || ''), w = widthT(g, tk, eqSz) + 60 * u; if (w > W - 2 * pad) eqSz *= (W - 2 * pad) / w; }
72
+ const eqY = y + eqSz * (titles.length ? 1.15 : 0.9);
73
+ if (hasEq) y = eqY + eqSz * 0.6;
74
+ y += 30 * u;
75
+ // 要点:预先折行(每条可能多行)
76
+ const size0 = (hasLine ? (ctx.portrait ? 56 : 50) : (ctx.portrait ? 62 : 58)) * u;
77
+ let text, plot = null;
78
+ if (hasLine && ctx.portrait) { plot = { x: pad + 20 * u, y: y + 20 * u, w: W - 2 * pad - 20 * u, h: (yBot - y) * 0.5 }; text = { x: pad, y0: plot.y + plot.h + 70 * u, y1: yBot, w: W - 2 * pad }; }
79
+ else if (hasLine) { plot = { x: W * 0.52, y: y + 20 * u, w: W * 0.48 - pad, h: yBot - y - 40 * u }; text = { x: pad, y0: y, y1: yBot, w: W * 0.47 - pad }; }
80
+ else text = { x: pad, y0: y, y1: yBot, w: W - 2 * pad };
81
+ // 要点放不下(竖屏有曲线、要点多):先让曲线让位(竖屏 50% → 最少 30%),再缩字号(最小 0.6 倍),不压进 safe.bottom
82
+ let points, blockH, size = size0; const gapP = 36 * u, room = yBot - y;
83
+ for (let k = 1; ; k *= 0.94) {
84
+ size = size0 * k;
85
+ points = ctx.of('point').map(q => { const lines = balance(g, q.text || '', text.w - 50 * u, `${size}px "PuHui-Medium"`); return { q, lines, h: lines.length * size * 1.35 }; });
86
+ blockH = points.reduce((s, p) => s + p.h + gapP, 0) - gapP;
87
+ if (plot && ctx.portrait) { plot.h = Math.max(room * 0.3, Math.min(room * 0.5, room - 110 * u - blockH)); text.y0 = plot.y + plot.h + 70 * u; }
88
+ if (blockH <= text.y1 - text.y0 || k < 0.6) break;
89
+ }
90
+ if (blockH > text.y1 - text.y0 + 1) console.warn(`t1:${points.length} 条要点缩到 0.6 倍字号仍放不下(超出 ${Math.round(blockH - (text.y1 - text.y0))}px):新要点出来时整块上卷、最早的淡出;想全留在屏上就删几条或拆成两段`);
91
+ let py = text.y0 + Math.max(0, (text.y1 - text.y0 - blockH) / 2) * (hasLine && !ctx.portrait ? 1 : 0.6); // 要点块竖直居中(竖屏略偏上)
92
+ for (const p of points) { p.y = py + size; py += p.h + gapP; p.need = Math.max(0, py - gapP - text.y1); } // need:这一条出来时整块要上卷多少才不越过 y1
93
+ // 曲线:坐标统一用所有 line 的数据范围(Transform 时坐标系不动)
94
+ const lines = ctx.of('line').map(q => { const d = q.data || {}; return { q, d, pts0: d.points || (d.values || []).map((v, i) => [i, v]) }; }).filter(l => l.pts0.length >= 2);
95
+ if (plot && lines.length) {
96
+ const all = lines.flatMap(l => l.pts0), xs = all.map(p => p[0]), ys = all.map(p => p[1]);
97
+ const x0 = Math.min(...xs), x1 = Math.max(...xs), y0 = Math.min(0, ...ys); let y1 = Math.max(...ys); if (y1 === y0) y1 = y0 + 1;
98
+ plot.X = v => plot.x + (v - x0) / ((x1 - x0) || 1) * plot.w; plot.Y = v => plot.y + plot.h - (v - y0) / (y1 - y0) * plot.h * 0.9;
99
+ for (const l of lines) { const [lx0, lx1] = [Math.min(...l.pts0.map(p => p[0])), Math.max(...l.pts0.map(p => p[0]))];
100
+ // 每条曲线横向铺满坐标系(不同 line 的 x 量纲可以不同:损失-参数 → 损失-步数)
101
+ l.scr = l.pts0.map(([px, py]) => [plot.x + (px - lx0) / ((lx1 - lx0) || 1) * plot.w, plot.Y(py)]); l.rs = resample(l.scr, 160); }
102
+ }
103
+ L = { titleY, titles, eqY, eqSz, text, plot, points, size, lines };
104
+ },
105
+ draw(c0, t, ctx) {
106
+ const { W, H, u } = ctx;
107
+ const c = ctx.alpha ? (BUF = BUF || document.createElement('canvas'), BUF.width = W, BUF.height = H, BUF.getContext('2d')) : c0;
108
+ if (!ctx.alpha) { c.fillStyle = ctx.pal ? ctx.pal.bg : '#000'; c.fillRect(0, 0, W, H); }
109
+ // ---- 标题(同一时间只有一个,换标题 = 旧的上移淡出、新的 Write) ----
110
+ L.titles.forEach((z, i) => {
111
+ const q = z.q, nx = L.titles[i + 1], out = nx ? MO.smooth(MO.seg(t, nx.q.at - 0.45, nx.q.at)) : 0; if (out >= 1 || ctx.lt(t, q.at) <= 0) return;
112
+ const n = [...(q.text || '')].length, dur = q.dur || clamp(n / 14, 0.6, 1.6);
113
+ c.save(); c.globalAlpha = 1 - out; c.translate(0, -50 * u * out);
114
+ z.lines.forEach((ln, k) => writeT(c, toks(ln), W / 2, L.titleY + k * z.size * 1.25, z.size, ctx.p(t, q.at + k * dur / z.lines.length, dur / z.lines.length), { col: col(q.data && q.data.color) || INK }));
115
+ c.restore();
116
+ });
117
+ // ---- 公式:第一个 Write,之后每个从上一个 TransformMatchingTex 过来 ----
118
+ let eqBox = null;
119
+ const eqs = ctx.of('equation').map(q => (q.data && q.data.tokens ? q.data.tokens : toks(q.text || '')).map(k => ({ ...k, col: col(k.col) })));
120
+ const eqCues = ctx.of('equation'), sz = L.eqSz;
121
+ let k = -1; eqCues.forEach((q, i) => { if (ctx.lt(t, q.at) > 0) k = i; });
122
+ if (k >= 0) {
123
+ const q = eqCues[k], tk = eqs[k], Ln = layoutT(c, tk, sz), tot = Ln.length ? Ln[Ln.length - 1].x + Ln[Ln.length - 1].w : 0, x0 = W / 2 - tot / 2;
124
+ if (k === 0) writeT(c, tk, W / 2, L.eqY, sz, ctx.p(t, q.at, q.dur || 1.2), { col: INK });
125
+ else {
126
+ const p = MO.smooth(ctx.p(t, q.at, q.dur || 1.5)), old = eqs[k - 1], Lo = layoutT(c, old, sz), toto = Lo.length ? Lo[Lo.length - 1].x + Lo[Lo.length - 1].w : 0, xo = W / 2 - toto / 2;
127
+ const used = new Set(), from = tk.map(nt => { const j = old.findIndex((ot, jj) => !used.has(jj) && ot.s === nt.s && (ot.sub || '') === (nt.sub || '') && (ot.sup || '') === (nt.sup || '')); if (j >= 0) used.add(j); return j; });
128
+ const one = (tok, x, a, cl) => { if (a <= 0) return; c.save(); c.globalAlpha *= a; withFont(tok, t2 => DG.math(c, [{ ...t2, col: cl }], x, L.eqY, sz, { p: 1, align: 'left' })); c.restore(); };
129
+ old.forEach((ot, j) => { if (!used.has(j)) { c.save(); c.translate(0, -30 * u * p); one(ot, xo + Lo[j].x, 1 - clamp(p * 1.6), ot.col || INK); c.restore(); } }); // 对不上的旧符号:淡出上移
130
+ tk.forEach((nt, i) => { const j = from[i];
131
+ if (j >= 0) one(nt, lerp(xo + Lo[j].x, x0 + Ln[i].x, p), 1, DG.mix(old[j].col || INK, nt.col || INK, p)); // 同名符号:移到新位置,颜色插值
132
+ else { c.save(); c.translate(0, 30 * u * (1 - p)); one(nt, x0 + Ln[i].x, clamp((p - 0.35) / 0.65), nt.col || INK); c.restore(); } }); // 新符号:淡入
133
+ }
134
+ if (Ln.length) eqBox = { x: x0 - 20 * u, y: L.eqY - sz * 0.95, w: tot + 40 * u, h: sz * 1.35 };
135
+ }
136
+ // ---- 坐标系+曲线:第一条 Create,之后每条从上一条逐点形变过来 ----
137
+ const P = L.plot;
138
+ if (P && L.lines.length) {
139
+ const l0 = L.lines[0];
140
+ if (ctx.lt(t, l0.q.at) > 0) {
141
+ const ap = MO.smooth(ctx.p(t, l0.q.at, 0.6)), lw = 3 * u;
142
+ c.save(); c.strokeStyle = M.GREY_B; c.lineWidth = lw; c.lineCap = 'round';
143
+ c.beginPath(); c.moveTo(P.x, P.Y(0)); c.lineTo(P.x + P.w * ap, P.Y(0)); c.moveTo(P.x, P.y + P.h); c.lineTo(P.x, P.y + P.h - P.h * ap); c.stroke();
144
+ c.globalAlpha = ap; for (let kk = 1; kk <= 4; kk++) { const xx = P.x + P.w * kk / 4; c.beginPath(); c.moveTo(xx, P.Y(0) - 8 * u); c.lineTo(xx, P.Y(0) + 8 * u); c.stroke(); }
145
+ c.restore();
146
+ let j = 0; L.lines.forEach((l, i) => { if (ctx.lt(t, l.q.at) > 0) j = i; });
147
+ const l = L.lines[j], lc = col(l.d.color) || M.BLUE_C;
148
+ c.save(); c.lineWidth = 5 * u; c.lineJoin = 'round'; c.lineCap = 'round';
149
+ if (j === 0) {
150
+ const cp = MO.smooth(ctx.p(t, l.q.at + 0.5, l.q.dur || 1.4));
151
+ if (cp > 0) { const cum = DG.cum(l.scr); c.strokeStyle = lc; const tip = DG.drawPartial(c, l.scr, cum, cum[cum.length - 1] * cp);
152
+ if (cp < 1) DG.neuron(c, tip[0], tip[1], 10 * u, 1, { fill: lc, stroke: INK, lw: 2 * u }); }
153
+ label(c, l, MO.smooth(MO.seg(cp, 0.8, 1)), lc, u);
154
+ } else {
155
+ const pv = L.lines[j - 1], p = MO.smooth(ctx.p(t, l.q.at, l.q.dur || 1.5)), pc = col(pv.d.color) || M.BLUE_C;
156
+ const pts = DG.morph(pv.rs, l.rs, p); c.strokeStyle = DG.mix(pc, lc, p); c.beginPath(); pts.forEach((q, i) => i ? c.lineTo(q[0], q[1]) : c.moveTo(q[0], q[1])); c.stroke();
157
+ label(c, pv, 1 - clamp(p * 2), pc, u); label(c, l, clamp(p * 2 - 1), lc, u);
158
+ }
159
+ c.restore();
160
+ }
161
+ }
162
+ // ---- 要点 ----
163
+ const hl = ctx.of('highlight'), size = L.size;
164
+ const target = h => h.data && h.data.target === 'equation' ? -2 : h.data && h.data.index != null ? h.data.index : L.points.filter(p => p.q.at <= h.at).length - 1;
165
+ const roll = Math.max(0, ...L.points.map(p => p.need * MO.smooth(ctx.p(t, p.q.at - 0.3, 0.4)))); // 放不下时:新要点出来前 0.3s 整块上卷,越过顶的淡出
166
+ L.points.forEach((it0, i) => {
167
+ const q = it0.q; if (ctx.lt(t, q.at) <= 0) return;
168
+ const it = roll ? { ...it0, y: it0.y - roll } : it0, over = L.text.y0 - (it.y - size);
169
+ if (over > 0 && clamp(1 - over / (size * 1.2)) <= 0) return;
170
+ c.save(); if (over > 0) c.globalAlpha *= clamp(1 - over / (size * 1.2));
171
+ const nx = L.points[i + 1], h = [...hl].reverse().find(z => target(z) === i && t >= z.at - 1e-6) || null, hOther = hl.some(z => t >= z.at && target(z) !== i && z.at > (h ? h.at : -1));
172
+ const dimN = nx ? MO.smooth(ctx.p(t, nx.q.at, 0.4)) : 0;
173
+ const n = [...(q.text || '')].length, dur = q.dur || clamp(n / 16, 0.6, 1.8);
174
+ // Indicate:放大 1.2、染黄、回来;之后这一条保持黄色(被强调的留住),其余变灰
175
+ const ip = h && !hOther ? ctx.p(t, h.at, 0.8) : 0, ind = DG.indicate(ip), keep = h && !hOther ? MO.smooth(clamp(ip * 2)) : 0;
176
+ const dim = keep > 0 ? 0 : dimN;
177
+ const base = DG.mixA(DG.mixA(INK, M.GREY_C, dim), M.YELLOW, Math.max(keep, ind.k)), colr = DG.rgba(base);
178
+ const bx = L.text.x + 14 * u, by = it.y - size * 0.36;
179
+ c.save(); c.translate(bx, by); c.scale(ind.s, ind.s); c.translate(-bx, -by);
180
+ DG.neuron(c, bx, by, 12 * u, 1 - dim * 0.6, { lw: 2 * u, stroke: colr, fill: col(q.data && q.data.color) || M.BLUE_C, sa: MO.smooth(ctx.p(t, q.at, 0.3)) });
181
+ let wMax = 0;
182
+ it.lines.forEach((ln, kk) => { const r = writeT(c, toks(ln), L.text.x + 50 * u, it.y + kk * size * 1.35, size, ctx.p(t, q.at + kk * dur / it.lines.length, dur / it.lines.length), { align: 'left', col: colr });
183
+ if (r.length) wMax = Math.max(wMax, r[r.length - 1].x + r[r.length - 1].w - (L.text.x + 50 * u)); });
184
+ c.restore();
185
+ if (h && !hOther) box(c, L.text.x - 16 * u, it.y - size * 1.05, wMax + 90 * u, it.lines.length * size * 1.35 + 18 * u, ctx.lt(t, h.at), u);
186
+ c.restore();
187
+ });
188
+ const he = [...hl].reverse().find(z => target(z) === -2 && t >= z.at);
189
+ if (he && eqBox && !hl.some(z => t >= z.at && z.at > he.at)) box(c, eqBox.x, eqBox.y, eqBox.w, eqBox.h, ctx.lt(t, he.at), u);
190
+ if (ctx.alpha) { c0.save(); c0.shadowColor = 'rgba(0,0,0,0.9)'; c0.shadowBlur = 10 * u; c0.drawImage(BUF, 0, 0); c0.shadowBlur = 3 * u; c0.drawImage(BUF, 0, 0); c0.restore(); }
191
+ },
192
+ };
193
+ // 曲线标签:放在曲线末端上方
194
+ function label(c, l, a, colr, u) { if (!l.q.text || a <= 0) return; const e = l.scr[l.scr.length - 1];
195
+ c.save(); c.globalAlpha *= a; c.font = `${40 * u}px "PuHui-Medium"`; c.fillStyle = colr; c.textAlign = 'right'; c.fillText(l.q.text, e[0], e[1] - 30 * u); c.restore(); }
196
+ // 强调框:Circumscribe 先绕一圈(1s),同时 SurroundingRectangle 画出来并留住(末帧有焦点)
197
+ function box(c, x, y, w, h, lt, u) {
198
+ if (lt <= 0) return; DG.circumscribe(c, x - 8 * u, y - 8 * u, w + 16 * u, h + 16 * u, MO.seg(lt, 0, 1.0), { lw: 4 * u, col: M.YELLOW });
199
+ const p = MO.smooth(MO.seg(lt, 0.3, 1.0)); if (p <= 0) return;
200
+ const pts = DG.rectPts(x + w / 2, y + h / 2, w, h, 120); c.save(); c.strokeStyle = M.YELLOW; c.lineWidth = 3 * u; c.lineJoin = 'round';
201
+ DG.drawPartial(c, [...pts, pts[0]], DG.cum([...pts, pts[0]]), DG.len([...pts, pts[0]]) * p); c.restore();
202
+ }
203
+ })();