@biunow/agent-biuart 0.0.0-stage → 0.1.0

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,74 @@
1
+ // t1 · 镜头 2(2.8s):一层网络。连线按权重着色(蓝正红负、线宽 ∝ |w|³)逐条画出 → 公式 Write →
2
+ // 黄色信号沿连线闪过(ShowPassingFlash)→ 隐藏层按激活值变亮 → 输出层「猫」最亮 → Indicate → 激活 0.95 的隐藏神经元描边染黄,镜头推进它。
3
+ // 开头一帧与镜头 1 的最后一帧逐像素相同(Transform 接续,没有切)。
4
+ (() => {
5
+ const { clamp, lerp } = U;
6
+ const C = DG.MANIM;
7
+ const DUR = 2.8;
8
+ const CAM_END = { x: 1000, y: 500, z: 1.1 };
9
+ const TGT = { k: 2 }; // 要推进去看的隐藏层神经元(激活 0.95 的那个)
10
+ const camAt = lt => {
11
+ if (lt <= DUR) { const k = MO.smooth(clamp(lt / DUR)); return { x: lerp(960, CAM_END.x, k), y: lerp(540, CAM_END.y, k), z: lerp(1, CAM_END.z, k) }; }
12
+ // 转场期间(lt>时长):绕目标神经元的屏幕位置继续推相机,矢量重画;与 eras.js 里 zoomThrough 的 dur/zoom 一致
13
+ const T = window.T1, wx = T.HID_X, wy = T.hidY(TGT.k);
14
+ const tr = ERAS.find(e => e.id === 't1_s3').transition, e = MO.smooth(clamp((lt - DUR) / tr.dur));
15
+ return CAM.pushTo(CAM_END, wx, wy, CAM_END.z * tr.zoom, e, 0); // k=0:目标在屏幕上原地不动,只放大
16
+ };
17
+ SCENES['t1_s2'] = {
18
+ camAt,
19
+ draw(c, lt) {
20
+ const T = window.T1;
21
+ c.fillStyle = '#000'; c.fillRect(0, 0, 1920, 1080);
22
+ const cam = camAt(lt);
23
+ CAM.with(c, cam, (c) => {
24
+ const inE = T.VIS.map((pi, j) => [T.IN_X, T.inY(j)]);
25
+ const hid = Array.from({ length: T.HID_N }, (_, k) => [T.HID_X, T.hidY(k)]);
26
+ // ---- 连线:ShowCreation,LaggedStart lag 0.006 ----
27
+ const e1p = MO.seg(lt, 0.15, 0.95), e2p = MO.seg(lt, 0.55, 1.05);
28
+ const n1 = inE.length * hid.length;
29
+ inE.forEach((a, j) => hid.forEach((b, k) => {
30
+ const i = j * hid.length + k, q = MO.smooth(MO.lagged(i, n1, e1p, 0.006));
31
+ DG.edge(c, DG.edgeEnds(a[0], a[1], T.IN_R, b[0], b[1], T.HID_R), T.W1(j, k), q, { alpha: 0.7, maxW: 3 });
32
+ }));
33
+ hid.forEach((a, k) => T.OUT.forEach((o, m) => {
34
+ const q = MO.smooth(MO.lagged(k * 3 + m, 30, e2p, 0.02));
35
+ DG.edge(c, DG.edgeEnds(a[0], a[1], T.HID_R, T.OUT_X, o.y, T.OUT_R), T.W2(k, m), q, { alpha: 0.8, maxW: 3.4 });
36
+ }));
37
+ // ---- 信号:连线复制一份染黄、线宽 ×1.5,ShowPassingFlash(time_width 2),按输入行错开 ----
38
+ const f1 = MO.seg(lt, 0.95, 1.75);
39
+ if (f1 > 0 && f1 < 1) inE.forEach((a, j) => { if (T.PIX[T.VIS[j]] < 0.3) return; hid.forEach((b, k) => {
40
+ const q = MO.smooth(MO.lagged(j, 16, f1, 0.04)); const [lo, hi] = DG.flash(q); if (hi <= lo) return;
41
+ const e = DG.edgeEnds(a[0], a[1], T.IN_R, b[0], b[1], T.HID_R);
42
+ c.save(); c.strokeStyle = C.YELLOW; c.globalAlpha = 0.85; c.lineWidth = 3; c.beginPath(); c.moveTo(lerp(e[0], e[2], lo), lerp(e[1], e[3], lo)); c.lineTo(lerp(e[0], e[2], hi), lerp(e[1], e[3], hi)); c.stroke(); c.restore();
43
+ }); });
44
+ const f2 = MO.seg(lt, 1.6, 2.25);
45
+ if (f2 > 0 && f2 < 1) hid.forEach((a, k) => { if (T.HID_A[k] < 0.4) return; T.OUT.forEach((o, m) => {
46
+ const q = MO.smooth(MO.lagged(k, 10, f2, 0.05)); const [lo, hi] = DG.flash(q); if (hi <= lo) return;
47
+ const e = DG.edgeEnds(a[0], a[1], T.HID_R, T.OUT_X, o.y, T.OUT_R);
48
+ c.save(); c.strokeStyle = C.YELLOW; c.globalAlpha = 0.9; c.lineWidth = 4.5; c.beginPath(); c.moveTo(lerp(e[0], e[2], lo), lerp(e[1], e[3], lo)); c.lineTo(lerp(e[0], e[2], hi), lerp(e[1], e[3], hi)); c.stroke(); c.restore();
49
+ }); });
50
+ // ---- 神经元 ----
51
+ T.drawInputs(c); T.drawBrace(c, 1);
52
+ const ha = MO.seg(lt, 0.0, 0.55), hf = MO.seg(lt, 1.3, 1.95);
53
+ const pick = MO.smooth(MO.seg(lt, 2.3, 2.6)); // 末尾:目标隐藏神经元描边染黄(「我们来看这一个」),相机随后推进去
54
+ hid.forEach((b, k) => { const q = MO.smooth(MO.lagged(k, 10, ha, 0.05)); if (q <= 0) return;
55
+ const hk = k === TGT.k ? pick : 0;
56
+ c.save(); c.globalAlpha = q; DG.neuron(c, b[0] + 24 * (1 - q), b[1], T.HID_R, T.HID_A[k] * MO.smooth(MO.lagged(k, 10, hf, 0.08)), { stroke: DG.mix('#ffffff', C.YELLOW, hk), lw: 2 + 2 * hk }); c.restore(); });
57
+ const oa = MO.seg(lt, 0.2, 0.7), of = MO.seg(lt, 1.95, 2.4);
58
+ T.OUT.forEach((o, m) => { const q = MO.smooth(MO.lagged(m, 3, oa, 0.2)); if (q <= 0) return;
59
+ const fill = o.a * MO.smooth(of);
60
+ c.save(); c.globalAlpha = q; DG.neuron(c, T.OUT_X + 24 * (1 - q), o.y, T.OUT_R, fill, { lw: 2.5 });
61
+ // 标签+数值;「猫」Indicate:放大 1.2、染黄、回来
62
+ const ind = m === 0 ? DG.indicate(MO.seg(lt, 2.0, 2.45)) : { s: 1, k: 0 };
63
+ c.translate(T.OUT_X + 62, o.y + 15); c.scale(ind.s, ind.s);
64
+ c.font = `600 46px "${DG.FONT.zh}"`; c.fillStyle = DG.mix('#ffffff', C.YELLOW, ind.k); c.textAlign = 'left'; c.fillText(o.name, 0, 0);
65
+ if (of > 0) { c.font = `40px "${DG.FONT.rm}"`; c.fillStyle = DG.mix(C.GREY_B, C.YELLOW, ind.k); c.globalAlpha = q * clamp(of * 2); c.fillText(TY.fmt(fill, 2), 62, 0); }
66
+ c.restore(); });
67
+ });
68
+ // 公式(不随相机动:屏幕固定层),颜色编码:黄=激活,蓝=权重
69
+ const Y = C.YELLOW, B = C.BLUE_C;
70
+ DG.math(c, [{ s: 'a', it: true, col: Y, sup: '(1)' }, { s: '=', gap: 14 }, { s: 'σ', it: true, gap: 4 }, { s: '(', gap: 6 }, { s: 'W', it: true, col: B, gap: 8 },
71
+ { s: 'a', it: true, col: Y, sup: '(0)', gap: 14 }, { s: '+', gap: 14 }, { s: 'b', it: true }, { s: ')' }], 960, 112, 64, { p: MO.seg(lt, 0.3, 1.3) });
72
+ },
73
+ };
74
+ })();
@@ -0,0 +1,65 @@
1
+ // t1 · 镜头 3(2.6s,前 0.75s 是「镜头穿进隐藏层神经元」转场):
2
+ // 神经元内部 = 它连向 100 个像素的权重图(蓝正红负,长得像猫脸)→ 像素图滑进来叠上去(逐格相乘)→ 100 格收拢成一个数 →
3
+ // σ 压到 0.95(= 镜头 2 里它的亮度)→ 「像猫脸」;最后 0.6s 停住给观众读。3b1b 原片讲隐藏层也是这样把权重画成图。
4
+ (() => {
5
+ const { clamp, lerp } = U;
6
+ const C = DG.MANIM;
7
+ const WG = { cx: 640, cy: 585, cell: 44 };
8
+ const cxy = (g, i) => [g.cx + ((i % 10) - 4.5) * g.cell, g.cy + (((i / 10) | 0) - 4.5) * g.cell];
9
+ const wcol = (w, a = 1) => DG.rgba(w >= 0 ? C.BLUE_C : C.RED_C, clamp(Math.abs(w)) * a);
10
+ const NEU = { x: 1460, y: 585, r: 78 };
11
+ SCENES['t1_s3'] = {
12
+ draw(c, lt) {
13
+ const T = window.T1;
14
+ c.fillStyle = '#000'; c.fillRect(0, 0, 1920, 1080);
15
+ DG.write(c, '这个神经元在找什么?', 960, 135, 58, MO.seg(lt, 0.75, 1.5));
16
+ const appear = MO.seg(lt, 0.0, 0.7), slideIn = MO.seg(lt, 0.7, 0.95), merge = MO.seg(lt, 0.95, 1.3), collapse = MO.seg(lt, 1.35, 1.75);
17
+ // ---- 权重图 ----
18
+ for (let i = 0; i < 100; i++) {
19
+ const [x, y] = cxy(WG, i), w = T.WTS[i], v = T.PIX[i];
20
+ const qa = MO.smooth(MO.lagged(i, 100, appear, 0.008)); if (qa <= 0) continue;
21
+ const qm = MO.smooth(merge), qc = MO.smooth(MO.lagged(i, 100, collapse, 0.008));
22
+ // 相乘后的颜色:w·a(只有猫形处的亮像素还亮着蓝,背景被乘成接近 0)
23
+ const prod = w * (v > 0 ? v : 0.06);
24
+ const fill = DG.mix(DG.mixA(w >= 0 ? C.BLUE_C : C.RED_C, '#000000', 1 - clamp(Math.abs(w))), DG.mixA(prod >= 0 ? C.BLUE_C : C.RED_C, '#000000', 1 - clamp(Math.abs(prod) * 1.3)), qm);
25
+ const s = WG.cell * lerp(0.94, 0.3, qc) * qa;
26
+ const px = lerp(x, NEU.x, qc), py = lerp(y, NEU.y, qc);
27
+ if (qc > 0) { const g = 0.28 * MO.smooth(clamp(qc * 1.5)), gs = WG.cell * 0.94; // 收拢后原位留一张淡的权重图(它在找的图案)
28
+ c.save(); c.globalAlpha = g; c.fillStyle = DG.mix(w >= 0 ? C.BLUE_C : C.RED_C, '#000000', 1 - clamp(Math.abs(w))); c.fillRect(x - gs / 2, y - gs / 2, gs, gs); c.restore(); }
29
+ c.save(); c.globalAlpha = 1 - clamp((qc - 0.75) / 0.25);
30
+ c.fillStyle = fill; c.fillRect(px - s / 2, py - s / 2, s, s);
31
+ c.strokeStyle = 'rgba(255,255,255,.18)'; c.lineWidth = 1; c.strokeRect(px - s / 2, py - s / 2, s, s); c.restore();
32
+ }
33
+ // 说明(FadeIn shift=UP),合并时淡出
34
+ const la = MO.smooth(MO.seg(lt, 0.75, 1.1)); // 图例留到片尾(相乘后还要靠它读颜色)
35
+ if (la > 0) { c.save(); c.globalAlpha = la; c.font = `600 34px "${DG.FONT.zh}"`; c.textAlign = 'center';
36
+ c.fillStyle = C.BLUE_C; c.fillText('蓝 = 希望这里亮', WG.cx - 120, 885 + 20 * (1 - la)); c.fillStyle = C.RED_C; c.fillText('红 = 希望这里暗', WG.cx + 150, 885 + 20 * (1 - la)); c.restore(); }
37
+ // ---- 像素图:从右边 FadeIn,再整体移到权重图上(Transform 位置),叠上后淡出成「相乘」 ----
38
+ if (slideIn > 0 && merge < 1) {
39
+ const qs = MO.smooth(slideIn), qm = MO.smooth(merge);
40
+ const gx = lerp(lerp(1340, 1290, qs), WG.cx, qm);
41
+ for (let i = 0; i < 100; i++) {
42
+ const v = T.PIX[i], x = gx + ((i % 10) - 4.5) * WG.cell, y = WG.cy + (((i / 10) | 0) - 4.5) * WG.cell, s = WG.cell * 0.94;
43
+ c.save(); c.globalAlpha = qs * (1 - qm * 0.9); c.fillStyle = `rgba(255,255,255,${v})`; c.fillRect(x - s / 2, y - s / 2, s, s);
44
+ c.strokeStyle = 'rgba(255,255,255,.25)'; c.lineWidth = 1; c.strokeRect(x - s / 2, y - s / 2, s, s); c.restore();
45
+ }
46
+ c.save(); c.globalAlpha = qs * (1 - qm); c.font = `64px "${DG.FONT.rm}"`; c.fillStyle = '#fff'; c.textAlign = 'center'; c.fillText('×', (WG.cx + 5 * WG.cell + gx - 5 * WG.cell) / 2, WG.cy + 22); c.restore();
47
+ }
48
+ // ---- 收拢成一个神经元:加权求和 → σ → 0.92 ----
49
+ const nq = MO.smooth(MO.seg(lt, 1.3, 1.6));
50
+ if (nq > 0) {
51
+ const fillA = 0.95 * MO.smooth(MO.seg(lt, 1.65, 2.0)); // = 镜头 2 里它的激活值 0.95
52
+ const ind = DG.indicate(MO.seg(lt, 1.9, 2.3));
53
+ c.save(); c.translate(NEU.x, NEU.y); c.scale(ind.s, ind.s); c.translate(-NEU.x, -NEU.y); c.globalAlpha = nq;
54
+ DG.neuron(c, NEU.x, NEU.y, NEU.r * (0.6 + 0.4 * nq), fillA, { lw: 3, stroke: DG.mix('#ffffff', C.YELLOW, ind.k) });
55
+ c.restore();
56
+ c.save(); c.globalAlpha = nq; c.textAlign = 'center';
57
+ c.font = `600 52px "${DG.FONT.zh}"`; c.fillStyle = DG.mix('#ffffff', C.YELLOW, ind.k); c.fillText('像猫脸', NEU.x, NEU.y - NEU.r - 34);
58
+ c.font = `48px "${DG.FONT.rm}"`; c.fillStyle = C.GREY_A; c.fillText(TY.fmt(fillA, 2), NEU.x, NEU.y + NEU.r + 62);
59
+ c.restore();
60
+ }
61
+ DG.math(c, [{ s: 'σ', it: true }, { s: '(', gap: 4 }, { s: 'Σ', gap: 6 }, { s: 'w', it: true, col: C.BLUE_C, sub: 'i', gap: 2 }, { s: 'a', it: true, col: C.YELLOW, sub: 'i', gap: 12 },
62
+ { s: '+', gap: 12 }, { s: 'b', it: true }, { s: ')', gap: 14 }, { s: '=', gap: 14 }, { s: TY.fmt(0.95 * MO.smooth(MO.seg(lt, 1.65, 2.0)), 2) }], 1180, 965, 54, { p: MO.seg(lt, 1.45, 1.95) });
63
+ },
64
+ };
65
+ })();
@@ -0,0 +1,10 @@
1
+ // 示范 · 发布会式(Apple keynote / 产品发布 UI)「Plover 2 的三个功能」(8 秒三镜,产品与数字虚构)。语法卡:references/动画语法/t2_keynote_ui.md
2
+ // 预览 index.html?film=demos/t2_keynote_ui 渲染 render.py --film demos/t2_keynote_ui --out t2.mp4
3
+ // 光斑底只依赖全片时间 t,三个镜头之间无缝;卡片 → 全屏是共享元素展开(rect = 中间卡在镜头 2 末帧的屏幕矩形)。
4
+ window.PUNCH = 0;
5
+ window.SCENE_DIR = 'demos/t2_keynote_ui';
6
+ window.ERAS = [
7
+ { id: 't2_s1', dur: 2.6 },
8
+ { id: 't2_s2', dur: 3.0, transition: { type: 'blurPush', dur: 0.55 } },
9
+ { id: 't2_s3', dur: 2.4, transition: { type: 'expandRect', dur: 0.6, rect: { x: 705.6, y: 252.6, w: 508.8, h: 614.8 }, r: 38 } },
10
+ ];
@@ -0,0 +1,57 @@
1
+ // t2 · 发布会式:「一个 AI 产品发布:三个功能卡片」
2
+ // 镜头 1(2.6s):深色底上柔和光斑缓慢漂移;眉题 → 产品名(模糊→清晰+上移,渐变字,光扫过)→ 一句话副标题。相机极慢推近。
3
+ // 本文件同时放 t2 共用的东西(window.T2):光斑底、字体、颜色。
4
+ (() => {
5
+ const { clamp, lerp } = U;
6
+ const W = 1920, H = 1080;
7
+ const BASE = '#050508';
8
+ const BLOBS = [ // 色相取 Stripe 渐变一系(紫/蓝/青)+ 一点暖色;周期避开 5s(HIG:避免 ~0.2Hz 持续摆动)
9
+ { x: 430, y: 300, r: 760, col: [150, 90, 238], a: 0.75, ax: 220, ay: 120, period: 11, ph: 0 },
10
+ { x: 1520, y: 260, r: 700, col: [56, 104, 255], a: 0.7, ax: 200, ay: 160, period: 13, ph: 2.1 },
11
+ { x: 1320, y: 930, r: 560, col: [120, 214, 255], a: 0.5, ax: 260, ay: 100, period: 9.5, ph: 4 },
12
+ { x: 520, y: 960, r: 520, col: [255, 96, 84], a: 0.42, ax: 180, ay: 90, period: 12, ph: 1.3 },
13
+ ];
14
+ const SANS = '"Inter", "NotoSansSC"', ZH = '"NotoSansSC"';
15
+ // 光斑底:只依赖全片时间 t,三个镜头之间无缝(换镜头时背景不跳)
16
+ const bg = (c, t, { dim = 0.38 } = {}) => {
17
+ UI.mesh(c, t, { base: BASE, blobs: BLOBS, blur: 90, scale: 0.25, grain: 0.035, key: 't2mesh' });
18
+ // 中心压暗一点,给白字留对比
19
+ const g = c.createRadialGradient(W / 2, H / 2, 100, W / 2, H / 2, 1000); g.addColorStop(0, `rgba(0,0,0,${dim})`); g.addColorStop(1, 'rgba(0,0,0,0.1)');
20
+ c.fillStyle = g; c.fillRect(0, 0, W, H);
21
+ };
22
+ // 大字:字距收紧 −0.02em(苹果/Linear 官网 64px 以上 −0.015~−0.03em)
23
+ const track = (c, size, em = -0.02) => { c.letterSpacing = (size * em).toFixed(2) + 'px'; };
24
+ // 光斑漂移、卡片漂浮、图标律动都读全片时间 t。PHASE:沿用实验时这支片排在 8–16s 的相位,保持定稿画面的构图(换题目时删掉或随便改)
25
+ const PHASE = 8;
26
+ window.T2 = { bg, SANS, ZH, track, BASE, PHASE };
27
+
28
+ const DUR = 2.6;
29
+ SCENES['t2_s1'] = {
30
+ draw(c, lt, t) {
31
+ t += T2.PHASE;
32
+ bg(c, t);
33
+ // 相机匀速慢推:1.0 → 1.045(整镜线性,发布会片的慢推不减速,减速到停会让画面「死」掉)
34
+ const s = lerp(1, 1.045, lt / (DUR + 0.55));
35
+ c.save(); c.translate(W / 2, H / 2); c.scale(s, s); c.translate(-W / 2, -H / 2);
36
+ c.textAlign = 'center'; c.textBaseline = 'alphabetic';
37
+ // 眉题
38
+ c.font = `500 34px ${ZH}`; c.fillStyle = '#a7a7b4'; c.letterSpacing = '6px';
39
+ TY.blurIn(c, '全 新 发 布', W / 2, 372, MO.appleOut(MO.seg(lt, 0.1, 0.8)), { blur: 10, dy: 16 });
40
+ // 产品名:渐变字画进离屏 → 光扫过(source-atop 只亮在字上)→ 模糊→清晰贴回
41
+ const p = MO.appleOut(MO.seg(lt, 0.3, 1.3));
42
+ if (p > 0) {
43
+ const tx = UI.scratch('t2title', W, 420), g = tx.getContext('2d'); g.reset();
44
+ g.font = `600 220px ${SANS}`; track(g, 220); g.textAlign = 'center'; g.textBaseline = 'alphabetic';
45
+ const gr = g.createLinearGradient(600, 0, 1320, 0); gr.addColorStop(0, '#ffffff'); gr.addColorStop(0.55, '#ddd2ff'); gr.addColorStop(1, '#a8dcff');
46
+ g.fillStyle = gr; g.fillText('Plover 2', W / 2, 300);
47
+ UI.sheen(g, null, MO.seg(lt, 1.25, 2.15), { x0: 560, x1: 1360, width: 140, angle: -0.38, alpha: 0.85, comp: 'source-atop' });
48
+ c.save(); c.globalAlpha = clamp(p * 1.5); const b = (1 - p) * 26; if (b > 0.3) c.filter = `blur(${b.toFixed(1)}px)`;
49
+ c.drawImage(tx, 0, 620 - 300 + (1 - p) * 40); c.restore(); // 纹理基线 y=300 → 屏幕 y=620
50
+ }
51
+ // 副标题
52
+ c.font = `400 50px ${ZH}`; c.fillStyle = '#c9c9d4'; c.letterSpacing = '1px';
53
+ TY.blurIn(c, '会思考、会记忆、会动手的 AI 助手', W / 2, 740, MO.appleOut(MO.seg(lt, 0.7, 1.6)), { blur: 12, dy: 22 });
54
+ c.restore();
55
+ },
56
+ };
57
+ })();
@@ -0,0 +1,70 @@
1
+ // t2 · 镜头 2(3.0s):三张毛玻璃功能卡片在 3D 空间入场(弹簧,bounce 0.15,错开 0.1s),绕 Y 轴转正;
2
+ // 卡上数字计数;整组持续漂浮;光扫过三张卡;最后中间卡「被选中」(放大,其余后退变暗),接共享元素展开。
3
+ (() => {
4
+ const { clamp, lerp } = U;
5
+ const W = 1920, H = 1080;
6
+ const CW = 480, CH_ = 580, GAP = 52, CY = 560, R = 36;
7
+ const CARDS = [
8
+ { icon: 'wave', title: '实时语音', desc: '像打电话一样自然地打断和追问', num: 320, dec: 0, unit: 'ms', label: '端到端延迟' },
9
+ { icon: 'memory', title: '长期记忆', desc: '记得你说过的每一个偏好', num: 100, dec: 0, unit: '万', label: 'tokens 上下文' },
10
+ { icon: 'agent', title: '自主执行', desc: '拆解任务、调用工具、交付结果', num: 87, dec: 0, unit: '%', label: '任务一次完成率' },
11
+ ];
12
+ const DUR = 3.0, FOCUS = 2.15; // 2.15s 起中间卡被选中
13
+ // 每张卡在 lt 时刻的状态(屏幕中心、旋转、缩放、透明),转场也要用中间卡的最终矩形
14
+ const state = (i, lt, t) => {
15
+ const t0 = 0.05 + i * 0.1; // 错开 0.1s
16
+ const sp = MO.spring(lt - t0, { duration: 0.75, bounce: 0.15 });
17
+ const f = MO.smooth(MO.seg(lt, FOCUS, FOCUS + 0.6));
18
+ const floatAmp = lerp(1, i === 1 ? 0 : 0.6, f); // 被选中的卡停止漂浮,好让转场从一个稳定的矩形展开
19
+ const cx = 960 + (i - 1) * (CW + GAP) + (i - 1) * 40 * f;
20
+ const cy = CY + (1 - sp) * 170 + MO.float(t, 7, 3.4 + i * 0.45, i * 2) * floatAmp;
21
+ const ry = (1 - sp) * (i - 1 || 0.001) * -0.55 + 0.06 * Math.sin(t * 0.9 + i) * floatAmp + (i - 1) * 0.12 * f;
22
+ const sc = (0.9 + 0.1 * sp) * (i === 1 ? lerp(1, 1.06, f) : lerp(1, 0.94, f));
23
+ const a = clamp((lt - t0) / 0.25) * (i === 1 ? 1 : lerp(1, 0.45, f));
24
+ return { cx, cy, ry, sc, a, t0 };
25
+ };
26
+ const cardRectAt = (lt, t) => { const s = state(1, lt, t); return { x: s.cx - CW * s.sc / 2, y: s.cy - CH_ * s.sc / 2, w: CW * s.sc, h: CH_ * s.sc }; };
27
+
28
+ SCENES['t2_s2'] = {
29
+ cardRectAt, CW, CH: CH_,
30
+ draw(c, lt, t) {
31
+ t += T2.PHASE;
32
+ const bgc = UI.scratch('t2bg', W, H), bgx = bgc.getContext('2d');
33
+ T2.bg(bgx, t); c.drawImage(bgc, 0, 0);
34
+ const bd = UI.backdrop(bgc, { blur: 40, key: 't2bd' });
35
+ // 先画两侧再画中间(中间卡在最上层)
36
+ [0, 2, 1].forEach(i => {
37
+ const S = state(i, lt, t); if (S.a <= 0) return;
38
+ const d = CARDS[i], cw = CW * S.sc, ch = CH_ * S.sc;
39
+ // 卡片纹理:毛玻璃(按卡片的屏幕位置取样背景)+内容
40
+ const tex = UI.scratch('t2card' + i, CW + 120, CH_ + 120), g = tex.getContext('2d'); g.reset();
41
+ const ox = 60, oy = 60;
42
+ UI.glass(g, { x: ox, y: oy, w: CW, h: CH_, r: R, bd, sample: { x: S.cx - cw / 2, y: S.cy - ch / 2, w: cw, h: ch }, tint: 0.075, stroke: 0.2, light: 0.14, shadow: false });
43
+ g.save(); g.translate(ox, oy);
44
+ // 图标底:同心圆角(子圆角 = 父圆角 − 内边距)
45
+ const pad = 44; g.fillStyle = 'rgba(255,255,255,0.09)'; g.beginPath(); g.roundRect(pad, pad, 96, 96, R - 14); g.fill();
46
+ UI.icon(g, d.icon, pad + 48, pad + 48, 60, '#f2f2f7', t);
47
+ g.textBaseline = 'alphabetic'; g.textAlign = 'left';
48
+ g.font = `600 50px ${T2.ZH}`; g.fillStyle = '#f5f5f7'; g.fillText(d.title, pad, 230);
49
+ g.font = `400 28px ${T2.ZH}`; g.fillStyle = 'rgba(235,235,245,0.62)'; g.fillText(d.desc, pad, 278);
50
+ // 分隔线
51
+ g.fillStyle = 'rgba(255,255,255,0.12)'; g.fillRect(pad, 330, CW - pad * 2, 1.5);
52
+ // 大数字:卡片落定后 0.25s 起计数 0.9s(easeOutExpo,最后一位慢慢落定),等宽排布不抖
53
+ const v = TY.count(lt, S.t0 + 0.35, 0.9, 0, d.num);
54
+ g.font = `600 132px ${T2.SANS}`; T2.track(g, 132, -0.03); g.fillStyle = '#ffffff';
55
+ const nw = TY.tabular(g, TY.fmt(v, d.dec), pad, 488);
56
+ g.letterSpacing = '0px'; g.font = `500 52px ${T2.SANS}`; g.fillStyle = 'rgba(235,235,245,0.7)'; g.fillText(d.unit, pad + nw + 10, 488);
57
+ g.font = `400 28px ${T2.ZH}`; g.fillStyle = 'rgba(235,235,245,0.55)'; g.fillText(d.label, pad, 535);
58
+ g.restore();
59
+ // 光扫过:1.2–2.0s 从左到右扫过整组(每张卡按自己的屏幕位置算进度,看起来是同一道光)
60
+ const sp = MO.seg(lt, 1.15, 2.05), gx = lerp(-200, W + 200, sp), lx = (gx - (S.cx - cw / 2)) / cw;
61
+ if (sp > 0 && sp < 1) UI.sheen(g, UI.rrPath(ox, oy, CW, CH_, R), clamp((lx + 0.35) / 1.7), { x0: ox, x1: ox + CW, width: 110, angle: -0.35, alpha: 0.22 });
62
+ // 阴影(按屏幕投影后的尺寸)+透视贴图
63
+ c.save(); c.globalAlpha = S.a;
64
+ UI.shadow(c, S.cx - cw / 2 + 10, S.cy - ch / 2 + 20, cw - 20, ch - 20, R, { blur: 80, oy: 40, alpha: 0.55 });
65
+ UI.persp(c, tex, { cx: S.cx, cy: S.cy, w: (CW + 120) * S.sc, h: (CH_ + 120) * S.sc, ry: S.ry, persp: 1800, strip: 3, shade: 0.4 });
66
+ c.restore();
67
+ });
68
+ },
69
+ };
70
+ })();
@@ -0,0 +1,61 @@
1
+ // t2 · 镜头 3(2.4s,前 0.6s 是中间卡「展开成全屏」的共享元素转场):
2
+ // 我们「进到了长期记忆这张卡里」——底是同一块毛玻璃;超大数字(与卡片同口径,不重数);下方一块向后倾斜的对话面板,气泡依次弹起;最后产品落版。
3
+ (() => {
4
+ const { clamp, lerp } = U;
5
+ const W = 1920, H = 1080;
6
+ const PW = 1180, PH = 360;
7
+ SCENES['t2_s3'] = {
8
+ draw(c, lt, t) {
9
+ t += T2.PHASE;
10
+ const bgc = UI.scratch('t2bg3', W, H), bgx = bgc.getContext('2d');
11
+ T2.bg(bgx, t, { dim: 0.25 });
12
+ const bd = UI.backdrop(bgc, { blur: 40, key: 't2bd3' });
13
+ // 全屏毛玻璃 = 卡片的质地放大到全屏(与转场里展开的卡片同一种材料)
14
+ c.drawImage(bd, 0, 0, W, H); c.fillStyle = 'rgba(255,255,255,0.075)'; c.fillRect(0, 0, W, H);
15
+ const tg = c.createLinearGradient(0, 0, 0, H * 0.5); tg.addColorStop(0, 'rgba(255,255,255,0.10)'); tg.addColorStop(1, 'rgba(255,255,255,0)'); c.fillStyle = tg; c.fillRect(0, 0, W, H * 0.5);
16
+ // 卡片抬头留在左上(展开前它就在卡片的这个位置,观众知道自己在哪)
17
+ c.fillStyle = 'rgba(255,255,255,0.09)'; c.beginPath(); c.roundRect(120, 96, 84, 84, 20); c.fill();
18
+ UI.icon(c, 'memory', 162, 138, 52, '#f2f2f7', t);
19
+ c.font = `600 44px ${T2.ZH}`; c.fillStyle = '#f5f5f7'; c.textBaseline = 'alphabetic'; c.textAlign = 'left'; c.fillText('长期记忆', 232, 154);
20
+ // 超大数字:和卡片上同一个口径「100万」,不重新计数(卡片刚数过一遍,展开后再从 0 数会让叙事打嗝)——卡片里的数字放大成主角
21
+ const pin = MO.appleOut(MO.seg(lt, 0.0, 0.5));
22
+ c.save(); c.textBaseline = 'alphabetic'; c.textAlign = 'left';
23
+ c.font = `600 230px ${T2.SANS}`; T2.track(c, 230, -0.03); const w1 = c.measureText('100').width;
24
+ c.letterSpacing = '0px'; c.font = `600 150px ${T2.ZH}`; const w2 = c.measureText('万').width;
25
+ c.font = `500 56px ${T2.SANS}`; const w3 = c.measureText('tokens').width;
26
+ const x0 = W / 2 - (w1 + w2 + w3 + 34) / 2, by = 400 - (1 - pin) * 20;
27
+ c.font = `600 230px ${T2.SANS}`; T2.track(c, 230, -0.03); c.fillStyle = '#ffffff'; c.fillText('100', x0, by);
28
+ c.letterSpacing = '0px'; c.font = `600 150px ${T2.ZH}`; c.fillText('万', x0 + w1 + 6, by);
29
+ c.font = `500 56px ${T2.SANS}`; c.fillStyle = 'rgba(235,235,245,0.7)'; c.fillText('tokens', x0 + w1 + w2 + 34, by);
30
+ c.restore();
31
+ c.font = `400 34px ${T2.ZH}`; c.fillStyle = 'rgba(235,235,245,0.6)'; c.textAlign = 'center';
32
+ TY.blurIn(c, '上下文窗口 —— 一年的对话,它都记得', W / 2, 478, MO.appleOut(MO.seg(lt, 0.35, 0.95)), { blur: 8, dy: 14 });
33
+ // 对话面板(纹理 → 绕 X 轴后倾),气泡按 spring 依次弹起;面板整体缓慢上浮
34
+ const tex = UI.scratch('t2panel', PW, PH), g = tex.getContext('2d'); g.reset();
35
+ g.fillStyle = 'rgba(12,12,20,0.55)'; g.beginPath(); g.roundRect(0, 0, PW, PH, 30); g.fill();
36
+ g.strokeStyle = 'rgba(255,255,255,0.16)'; g.lineWidth = 2; g.stroke();
37
+ const bubble = (k, text, right, y, t0) => {
38
+ const s = MO.spring(lt - t0, { duration: 0.5, bounce: 0.15 }); if (lt <= t0) return;
39
+ g.save(); g.globalAlpha = clamp((lt - t0) / 0.2); g.font = `400 34px ${T2.ZH}`;
40
+ const tw = g.measureText(text).width, bw = tw + 64, bh = 74, bx = right ? PW - 48 - bw : 48, by = y + (1 - s) * 40;
41
+ g.translate(bx + (right ? bw : 0), by + bh); g.scale(lerp(0.85, 1, s), lerp(0.85, 1, s)); g.translate(-(bx + (right ? bw : 0)), -(by + bh));
42
+ g.fillStyle = right ? '#3d6bff' : 'rgba(255,255,255,0.14)'; g.beginPath(); g.roundRect(bx, by, bw, bh, 37); g.fill();
43
+ g.fillStyle = '#fff'; g.textBaseline = 'middle'; g.fillText(text, bx + 32, by + bh / 2 + 2); g.restore();
44
+ void k;
45
+ };
46
+ bubble(0, '还记得我上个月说的旅行计划吗?', true, 36, 0.45);
47
+ bubble(1, '记得:五月去京都,预算两万,不坐红眼航班。', false, 134, 0.8);
48
+ bubble(2, '那帮我订吧。', true, 232, 1.15);
49
+ // 输入中光标闪(持续小动作)
50
+ if (lt > 1.35) { g.fillStyle = `rgba(255,255,255,${0.35 + 0.35 * Math.sin(lt * 9)})`; for (let k = 0; k < 3; k++) { g.beginPath(); g.arc(90 + k * 26, 330, 7, 0, Math.PI * 2); g.fill(); } }
51
+ const pp = MO.spring(lt - 0.3, { duration: 0.8, bounce: 0 });
52
+ c.save(); c.globalAlpha = clamp((lt - 0.3) / 0.3);
53
+ UI.persp(c, tex, { cx: W / 2, cy: 725 + (1 - pp) * 120 - 8 * MO.smooth(clamp(lt / 2.4)), w: PW, h: PH, rx: lerp(0.55, 0.32, pp), persp: 1500, strip: 2 });
54
+ c.restore();
55
+ // 落版:品牌名 + 上线信息
56
+ c.textAlign = 'center'; c.font = `600 40px ${T2.SANS}`; T2.track(c, 40, -0.01); c.fillStyle = '#ffffff';
57
+ TY.blurIn(c, 'Plover 2 · 今天起可用', W / 2, 972, MO.appleOut(MO.seg(lt, 1.2, 1.8)), { blur: 10, dy: 12 }); // 1.8s 落定,停 0.6s;y=972 在字幕安全区内
58
+ c.letterSpacing = '0px';
59
+ },
60
+ };
61
+ })();
@@ -0,0 +1,11 @@
1
+ // 示范 · 财经图表(经济学人 / 财经频道)「深算科技营收与股价」(8 秒三镜,公司与数据全部虚构,每镜标「示意数据」)。语法卡:references/动画语法/t3_finance_chart.md
2
+ // 预览 index.html?film=demos/t3_finance_chart 渲染 render.py --film demos/t3_finance_chart --out t3.mp4
3
+ // 镜头 2→3:相机绕股价线最新点推近(矢量重画、屏幕位置不动),穿进最近 20 日 K 线。
4
+ window.PUNCH = 0;
5
+ window.SCENE_DIR = 'demos/t3_finance_chart';
6
+ window.ERAS = [
7
+ { id: 't3_s1', dur: 2.8 },
8
+ { id: 't3_s2', dur: 2.7, transition: { type: 'slidePush', dur: 0.5, bar: '#E3120B' } },
9
+ { id: 't3_s3', dur: 2.5, transition: { type: 'zoomThrough', dur: 0.6, cx: 1530, cy: 297.65, zoom: 6, live: true, bScale0: 0.6, bg: '#FFFFFF',
10
+ get focus() { return SCENES.t3_s3.focus; } } }, // focus = 最新一根 K 线
11
+ ];
@@ -0,0 +1,48 @@
1
+ // t3 · 财经图表:「某虚构 AI 公司 5 年营收增长与股价」(数据全部虚构,每一镜角落标「示意数据」)
2
+ // 镜头 1(2.8s):版式先出(顶红线+红色小旗+标题+单位)→ 网格从左往右画出(零线最深)→ 柱子从 0 依次长出、数值同步计数 →
3
+ // 高亮最后一根(其余变灰)→ 标注「8.7 倍」。本文件同时放 t3 共用的版式与数据(window.T3)。
4
+ (() => {
5
+ const { clamp, lerp, rng } = U;
6
+ const W = 1920, H = 1080;
7
+ // 颜色:经济学人图表色板(2017 图表风格指南)
8
+ const COL = { red: '#E3120B', blue: '#006BA2', blue2: '#3EBCD2', grey: '#758D99', dim: '#C6D2D8', ink: '#0C0C0C', sub: '#4F5B61', grid: 'rgba(12,12,12,0.13)', bg: '#FFFFFF', up: '#E3120B', down: '#1B9E5A', gold: '#EBB434' };
9
+ const CN = '"NotoSansSC"', NUM = '"RobotoCondensed", "NotoSansSC"';
10
+ const F = { x: 170, y: 270, w: 1580, h: 610 }; // 绘图区
11
+ // ---- 虚构数据 ----
12
+ const REV = [{ y: 2021, v: 12.4 }, { y: 2022, v: 19.8 }, { y: 2023, v: 34.6 }, { y: 2024, v: 61.2 }, { y: 2025, v: 107.9 }];
13
+ // 月收盘价 60 个点:带种子的随机游走,2022 回撤、2023-03 跳涨,再整体缩放到 38 → 286.4
14
+ const PRICE = (() => { const r = rng(2025), a = []; let v = 0;
15
+ for (let m = 0; m < 60; m++) { const drift = m < 12 ? 0.02 : m < 24 ? -0.035 : m === 26 ? 0.35 : 0.045; v += drift + (r() - 0.5) * 0.11; a.push(v); }
16
+ const e = a.map(Math.exp), k0 = e[0], k1 = e[59], out = e.map(x => 38 + (x - k0) / (k1 - k0) * (286.4 - 38));
17
+ out[58] = 242; return out; })(); // 末点 = 最新价 286.4,倒数第二个月收盘 = 日 K 起点 242(两镜数字对得上)
18
+ // 最近 20 个交易日 K 线:从 242 走到 286.4(+18.3%),有涨有跌
19
+ const KL = (() => { const r = rng(77), out = []; let c = 242;
20
+ for (let i = 0; i < 20; i++) { const tgt = 242 + (286.4 - 242) * (i + 1) / 20; const o = c; const cl = i === 19 ? 286.4 : tgt + (r() - 0.5) * 9 + (i % 5 === 3 ? -7 : 0);
21
+ const hi = Math.max(o, cl) + 1.5 + r() * 4, lo = Math.min(o, cl) - 1.5 - r() * 4; out.push({ o, c: cl, h: hi, l: lo, vol: 0.4 + r() * 0.6 + (Math.abs(cl - o) / 10) }); c = cl; }
22
+ return out; })();
23
+
24
+ // ---- 版式(每镜都画):经济学人式整页版式 CH.frame(顶部红线、左上红色小旗、标题、副标题=单位、来源、示意数据角标)----
25
+ const frame = (c, lt, { title, sub, source = '来源:示意数据,公司与数字均为虚构' } = {}) => CH.frame(c, lt, { title, sub, source, font: CN, red: COL.red, ink: COL.ink, subCol: COL.sub });
26
+ window.T3 = { COL, CN, NUM, F, REV, PRICE, KL, frame };
27
+
28
+ // ---- 镜头 1 ----
29
+ const yS = CH.lin(0, 120, F.y + F.h, F.y);
30
+ const xs = REV.map((d, i) => F.x + 130 + i * ((F.w - 330) / 4));
31
+ SCENES['t3_s1'] = {
32
+ draw(c, lt) {
33
+ c.fillStyle = T3.COL.bg; c.fillRect(0, 0, 1920, 1080);
34
+ const z = 1 + 0.03 * lt / 2.8; // 匀速慢推 1→1.03(财经频道图表镜头的常规呼吸感)
35
+ c.save(); c.translate(960, 575); c.scale(z, z); c.translate(-960, -575);
36
+ frame(c, lt, { title: '深算科技:营收五年涨到原来的近 9 倍', sub: '年营收,亿元' });
37
+ CH.grid(c, F, [0, 30, 60, 90, 120], yS, MO.seg(lt, 0.25, 0.85), { col: COL.grid, zeroCol: COL.ink, font: `400 30px ${NUM}`, labelCol: '#5b666b', side: 'right', lw: 1.5, zeroLw: 3 });
38
+ CH.xLabels(c, REV.map((d, i) => ({ x: xs[i], label: String(d.y) })), F.y + F.h + 50, MO.seg(lt, 0.45, 1.0), { font: `400 32px ${NUM}`, col: '#3a4246' });
39
+ const hiP = MO.smooth(MO.seg(lt, 1.95, 2.35));
40
+ const tops = CH.bars(c, REV.map((d, i) => ({ x: xs[i], v: d.v })), yS, 150, MO.seg(lt, 0.65, 1.95),
41
+ { lag: 0.22, col: COL.blue, hi: lt > 1.95 ? 4 : -1, hiP, hiCol: COL.blue, dimCol: COL.dim, fmt: v => v.toFixed(1), font: `600 34px ${NUM}`, labelCol: COL.ink });
42
+ // 标注:最后一根柱旁,点 → 引线 → 两行字(数字先说,比较后说)
43
+ CH.callout(c, lt, 2.15, { x: xs[4] - 75, y: tops[4][1], tx: xs[4] - 330, ty: yS(96), lines: ['8.7 倍', '2025 年 107.9 亿 ÷ 2021 年 12.4 亿'],
44
+ col: COL.ink, dotCol: COL.red, font: `700 54px ${NUM}`, font2: `400 28px ${CN}`, align: 'right', r: 9 });
45
+ c.restore();
46
+ },
47
+ };
48
+ })();
@@ -0,0 +1,42 @@
1
+ // t3 · 镜头 2(2.7s,开头 0.5s 是面板横推转场):股价折线。网格先出 → 折线按时间从左画到右(头部圆点+价格跟随)→
2
+ // 画过 2023 年 3 月时弹出事件标注(一镜只标一件事) → 相机缓慢推向最新一个点;转场期间继续推近(矢量重画),穿进 K 线镜头。
3
+ (() => {
4
+ const { clamp, lerp } = U;
5
+ const W = 1920, H = 1080;
6
+ const DUR = 2.7;
7
+ SCENES['t3_s2'] = {
8
+ draw(c, lt) {
9
+ const { COL, CN, NUM, F, PRICE, frame } = T3;
10
+ const yS = CH.lin(0, 300, F.y + F.h, F.y), xm = m => F.x + m / 59 * (F.w - 220);
11
+ const pts = PRICE.map((v, m) => [xm(m), yS(v)]);
12
+ const P = pts[59];
13
+ // 相机:镜头内 1 → 1.05,转场期间(lt > DUR)指数推近到 ×6,始终绕最新点(屏幕位置不动)
14
+ const tr = ERAS.find(e => e.id === 't3_s3').transition;
15
+ const z = lt <= DUR ? lerp(1, 1.05, MO.smooth(lt / DUR)) : 1.05 * Math.pow(tr.zoom / 1.05, MO.smooth(clamp((lt - DUR) / tr.dur)));
16
+ c.fillStyle = COL.bg; c.fillRect(0, 0, W, H);
17
+ c.save(); c.translate(P[0], P[1]); c.scale(z, z); c.translate(-P[0], -P[1]);
18
+ frame(c, lt, { title: '股价:先跌后涨,五年涨到原来的 7.5 倍', sub: '月收盘价,元' });
19
+ CH.grid(c, F, [0, 100, 200, 300], yS, MO.seg(lt, 0.2, 0.75), { col: COL.grid, zeroCol: COL.ink, font: `400 30px ${NUM}`, labelCol: '#5b666b', side: 'right', lw: 1.5, zeroLw: 3 });
20
+ CH.xLabels(c, [2021, 2022, 2023, 2024, 2025].map((y, i) => ({ x: xm(i * 12 + 5.5), label: String(y) })), F.y + F.h + 50, MO.seg(lt, 0.3, 0.8), { font: `400 32px ${NUM}`, col: '#3a4246' });
21
+ // 年份分隔短刻度
22
+ c.save(); c.strokeStyle = 'rgba(12,12,12,.35)'; c.lineWidth = 2; c.globalAlpha = MO.seg(lt, 0.3, 0.6);
23
+ for (let y = 1; y < 5; y++) { const x = xm(y * 12 - 0.5); c.beginPath(); c.moveTo(x, F.y + F.h); c.lineTo(x, F.y + F.h + 14); c.stroke(); } c.restore();
24
+ // 折线:0.45–1.95s 按时间画出(smooth:起步和落定都慢,最后一个价格「落」在点上)
25
+ const lp = MO.smooth(MO.seg(lt, 0.45, 1.95));
26
+ const hp = CH.line(c, pts, lp, { col: COL.red, lw: 5, headR: 9, area: { top: F.y, base: F.y + F.h, c0: 'rgba(227,18,11,0.14)', c1: 'rgba(227,18,11,0)' } });
27
+ if (hp) { // 价格标签跟着头走(等宽数字,不抖)
28
+ const v = yS.inv(hp[1]);
29
+ c.save(); c.globalAlpha = 1 - clamp((lt - DUR) / 0.2); // 推进转场一开始就收掉,免得和下一镜右上的价格叠影
30
+ c.font = `700 38px ${NUM}`; c.fillStyle = COL.red; c.textAlign = 'left'; c.textBaseline = 'middle';
31
+ TY.tabular(c, '¥' + v.toFixed(0), hp[0] + 22, hp[1] - 4); c.restore();
32
+ }
33
+ // 事件标注:线头经过 2023 年 3 月(第 26 个月)时触发
34
+ const m26 = xm(26), tHit = 0.45 + 1.5 * invSmooth((m26 - pts[0][0]) / (pts[59][0] - pts[0][0]));
35
+ CH.callout(c, lt, tHit, { x: m26, y: pts[26][1], tx: m26 - 30, ty: pts[26][1] - 150, lines: ['2023.3', '发布自研大模型'], col: COL.ink, dotCol: COL.ink,
36
+ font: `700 34px ${NUM}`, font2: `400 30px ${CN}`, align: 'right', r: 8 });
37
+ c.restore();
38
+ },
39
+ };
40
+ // smooth 的反函数(二分),用于「线头到达某个 x 的时刻」
41
+ function invSmooth(y) { let a = 0, b = 1; for (let i = 0; i < 30; i++) { const m = (a + b) / 2; if (MO.smooth(m) < y) a = m; else b = m; } return (a + b) / 2; }
42
+ })();
@@ -0,0 +1,51 @@
1
+ // t3 · 镜头 3(2.5s,前 0.6s 是从上一镜最新点「推进来」的转场):最近 20 个交易日 K 线。
2
+ // 价格区网格先出 → K 线逐根长出(红涨绿跌,A 股惯例)、成交量同步 → 右上价格跟着最新一根滚动 → 起点参考虚线+区间涨幅标注 → 停 0.75s。
3
+ // (审片后删掉了 5 日均线:2 秒里读不完 K 线+均线+量+括注)
4
+ (() => {
5
+ const { clamp, lerp } = U;
6
+ const W = 1920, H = 1080;
7
+ const L = (() => {
8
+ const { F, KL } = T3;
9
+ const lo = Math.min(...KL.map(k => k.l)), hi = Math.max(...KL.map(k => k.h));
10
+ const ticks = CH.ticks(lo - 4, hi + 4, 4), y0 = ticks[0], y1 = ticks[ticks.length - 1];
11
+ const PB = F.y + F.h * 0.74; // 价格区底
12
+ const yS = CH.lin(y0, y1, PB, F.y + 10);
13
+ const xs = KL.map((_, i) => F.x + 40 + i * ((F.w - 330) / 19));
14
+ return { ticks, yS, xs, PB, VB: F.y + F.h, VT: F.y + F.h * 0.8 };
15
+ })();
16
+ SCENES['t3_s3'] = {
17
+ focus: [L.xs[19], L.yS(286.4)],
18
+ draw(c, lt) {
19
+ const { COL, CN, NUM, F, KL, frame } = T3;
20
+ c.fillStyle = COL.bg; c.fillRect(0, 0, 1920, 1080);
21
+ const z = 1 + 0.03 * lt / 2.5; // 匀速慢推 1→1.03
22
+ c.save(); c.translate(960, 575); c.scale(z, z); c.translate(-960, -575);
23
+ frame(c, lt + 0.6, { title: '最近 20 个交易日:涨了 18.3%', sub: '日 K 线,元 红涨绿跌(A 股惯例) 纵轴未从 0 开始' });
24
+ const PF = { x: F.x, y: F.y, w: F.w, h: L.PB - F.y };
25
+ CH.grid(c, PF, L.ticks, L.yS, MO.seg(lt, 0.1, 0.6), { col: COL.grid, zeroCol: COL.grid, font: `400 30px ${NUM}`, labelCol: '#5b666b', side: 'right', lw: 1.5 });
26
+ // 成交量区基线
27
+ c.fillStyle = COL.ink; c.fillRect(F.x, L.VB - 1, F.w * MO.quintOut(MO.seg(lt, 0.1, 0.6)), 2);
28
+ c.save(); c.font = `400 26px ${CN}`; c.fillStyle = '#7c868b'; c.textAlign = 'right'; c.globalAlpha = MO.seg(lt, 0.3, 0.6); c.fillText('成交量', F.x + F.w, L.VB - 14); c.restore(); // 放右下角空处,不压 K 线
29
+ // K 线 + 成交量:逐根(lag 0.06),0.2–1.3s
30
+ const kp = MO.seg(lt, 0.2, 1.3);
31
+ CH.candles(c, KL, L.xs, L.yS, 30, kp, { up: COL.up, down: COL.down, lag: 0.06 });
32
+ const VMAX = Math.max(...KL.map(k => k.vol));
33
+ KL.forEach((k, i) => { const q = MO.quintOut(MO.lagged(i, 20, kp, 0.06)); if (q <= 0) return;
34
+ const h = (L.VB - L.VT - 6) * k.vol / VMAX * q; // 按最大量归一,量柱不顶到价格区
35
+ c.fillStyle = k.c >= k.o ? 'rgba(227,18,11,.35)' : 'rgba(27,158,90,.35)'; c.fillRect(L.xs[i] - 15, L.VB - h, 30, h); });
36
+ // 右上价格:跟着「最新出现的那根」滚动;涨跌色 = 相对区间起点
37
+ let n = 0; for (let i = 0; i < 20; i++) if (MO.lagged(i, 20, kp, 0.06) > 0) n = i;
38
+ const qn = MO.quintOut(MO.lagged(n, 20, kp, 0.06)), v = lt < 0.2 ? 242 : lerp(KL[n].o, KL[n].c, qn), pct = (v / 242 - 1) * 100;
39
+ c.save(); c.textAlign = 'right'; c.textBaseline = 'alphabetic'; c.font = `700 76px ${NUM}`; c.fillStyle = pct >= 0 ? COL.up : COL.down;
40
+ TY.tabular(c, '¥' + v.toFixed(2), W - 80, 150, { align: 'right' });
41
+ c.font = `700 40px ${NUM}`; TY.tabular(c, (pct >= 0 ? '▲ +' : '▼ ') + pct.toFixed(1) + '%', W - 80, 205, { align: 'right' }); c.restore();
42
+ // 起点参考虚线 + 区间涨幅括注
43
+ const rp = MO.quintOut(MO.seg(lt, 1.35, 1.75)); // 1.75s 落定,停 0.75s 给人读
44
+ if (rp > 0) { const y = L.yS(242); c.save(); c.setLineDash([10, 8]); c.strokeStyle = COL.sub; c.lineWidth = 2; c.beginPath(); c.moveTo(L.xs[0], y); c.lineTo(lerp(L.xs[0], L.xs[19] + 60, rp), y); c.stroke(); c.setLineDash([]);
45
+ const x = L.xs[19] + 60, yt = L.yS(286.4); c.strokeStyle = COL.up; c.lineWidth = 3; c.beginPath(); c.moveTo(x, y); c.lineTo(x, lerp(y, yt, rp)); c.stroke();
46
+ c.globalAlpha = MO.seg(lt, 1.5, 1.8); c.font = `700 40px ${NUM}`; c.fillStyle = COL.up; c.fillText('+18.3%', x + 14, (y + yt) / 2 + 14);
47
+ c.font = `400 26px ${CN}`; c.fillStyle = COL.sub; c.textAlign = 'right'; c.fillText('区间起点 ¥242', x - 14, y + 32); c.restore(); }
48
+ c.restore();
49
+ },
50
+ };
51
+ })();
@@ -0,0 +1,10 @@
1
+ // 示范 · Kurzgesagt 式扁平科普「AI 是怎么学会认猫的」(8 秒三镜)。语法卡:references/动画语法/y1_kurzgesagt.md
2
+ // 预览 index.html?film=demos/y1_kurzgesagt 渲染 render.py --film demos/y1_kurzgesagt --out y1.mp4
3
+ // 镜头按口播切,dur 用秒;解说片不要拍点冲击(PUNCH = 0)。相机运动全在场景里按时间算(CAM),转场只管 A、B 怎么合。
4
+ window.PUNCH = 0;
5
+ window.SCENE_LIBS = ['demos/_shared/hero.js', 'demos/y1_kurzgesagt/kurzgesagt.js'];
6
+ window.ERAS = [
7
+ { id: 'y1_s1', dur: 2.6 }, // 夜晚山坡:5 层视差慢推,机器人扫描猫
8
+ { id: 'y1_s2', dur: 2.7, transition: { type: 'lensReveal', dur: 1.0, lens: t => Y1.lensAt(t) } }, // 钻进镜头:相机指数推进眼睛,眼睛里是下一个世界
9
+ { id: 'y1_s3', dur: 2.7, transition: { type: 'matchCut', dur: 0.9 } }, // 填满再拉出:推满黄色输出节点 → 从黄色的眼睛里拉出
10
+ ];