@biunow/agent-biuart 0.0.0-stage → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (377) hide show
  1. package/bin/server.mjs +575 -0
  2. package/data/styles.json +533 -0
  3. package/engine/audit_clip.py +46 -0
  4. package/engine/clip.html +24 -0
  5. package/engine/clip.js +104 -0
  6. package/engine/clip_schema.json +19 -0
  7. package/engine/clips/t1_3b1b.js +203 -0
  8. package/engine/clips/t2_keynote_ui.js +347 -0
  9. package/engine/clips/t3_finance_chart.js +206 -0
  10. package/engine/clips/y1_kurzgesagt.js +183 -0
  11. package/engine/clips/y2_vox.js +150 -0
  12. package/engine/clips/y3_whiteboard.js +209 -0
  13. package/engine/clips/y4_storytime.js +194 -0
  14. package/engine/clips/y5_kinetic_type.js +134 -0
  15. package/engine/compare.py +19 -0
  16. package/engine/demos/_shared/hero/c1_0.png +0 -0
  17. package/engine/demos/_shared/hero/c1_1.png +0 -0
  18. package/engine/demos/_shared/hero/c1_2.png +0 -0
  19. package/engine/demos/_shared/hero/c3_line.png +0 -0
  20. package/engine/demos/_shared/hero.js +96 -0
  21. package/engine/demos/long_scroll/eras.js +23 -0
  22. package/engine/demos/long_scroll/frames/8bit_act/01.png +0 -0
  23. package/engine/demos/long_scroll/frames/8bit_act/02.png +0 -0
  24. package/engine/demos/long_scroll/frames/8bit_act/03.png +0 -0
  25. package/engine/demos/long_scroll/frames/8bit_act/04.png +0 -0
  26. package/engine/demos/long_scroll/frames/8bit_act/05.png +0 -0
  27. package/engine/demos/long_scroll/frames/8bit_act/06.png +0 -0
  28. package/engine/demos/long_scroll/frames/8bit_act/07.png +0 -0
  29. package/engine/demos/long_scroll/frames/8bit_act/08.png +0 -0
  30. package/engine/demos/long_scroll/frames/8bit_act/meta.json +69 -0
  31. package/engine/demos/long_scroll/frames/8bit_walk/01.png +0 -0
  32. package/engine/demos/long_scroll/frames/8bit_walk/02.png +0 -0
  33. package/engine/demos/long_scroll/frames/8bit_walk/03.png +0 -0
  34. package/engine/demos/long_scroll/frames/8bit_walk/04.png +0 -0
  35. package/engine/demos/long_scroll/frames/8bit_walk/05.png +0 -0
  36. package/engine/demos/long_scroll/frames/8bit_walk/06.png +0 -0
  37. package/engine/demos/long_scroll/frames/8bit_walk/07.png +0 -0
  38. package/engine/demos/long_scroll/frames/8bit_walk/08.png +0 -0
  39. package/engine/demos/long_scroll/frames/8bit_walk/meta.json +69 -0
  40. package/engine/demos/long_scroll/frames/egypt_dodge/01.png +0 -0
  41. package/engine/demos/long_scroll/frames/egypt_dodge/02.png +0 -0
  42. package/engine/demos/long_scroll/frames/egypt_dodge/03.png +0 -0
  43. package/engine/demos/long_scroll/frames/egypt_dodge/04.png +0 -0
  44. package/engine/demos/long_scroll/frames/egypt_dodge/05.png +0 -0
  45. package/engine/demos/long_scroll/frames/egypt_dodge/06.png +0 -0
  46. package/engine/demos/long_scroll/frames/egypt_dodge/07.png +0 -0
  47. package/engine/demos/long_scroll/frames/egypt_dodge/08.png +0 -0
  48. package/engine/demos/long_scroll/frames/egypt_dodge/meta.json +69 -0
  49. package/engine/demos/long_scroll/frames/egypt_walk8/01.png +0 -0
  50. package/engine/demos/long_scroll/frames/egypt_walk8/02.png +0 -0
  51. package/engine/demos/long_scroll/frames/egypt_walk8/03.png +0 -0
  52. package/engine/demos/long_scroll/frames/egypt_walk8/04.png +0 -0
  53. package/engine/demos/long_scroll/frames/egypt_walk8/05.png +0 -0
  54. package/engine/demos/long_scroll/frames/egypt_walk8/06.png +0 -0
  55. package/engine/demos/long_scroll/frames/egypt_walk8/07.png +0 -0
  56. package/engine/demos/long_scroll/frames/egypt_walk8/08.png +0 -0
  57. package/engine/demos/long_scroll/frames/egypt_walk8/meta.json +69 -0
  58. package/engine/demos/long_scroll/frames/monet_throw/01.png +0 -0
  59. package/engine/demos/long_scroll/frames/monet_throw/02.png +0 -0
  60. package/engine/demos/long_scroll/frames/monet_throw/03.png +0 -0
  61. package/engine/demos/long_scroll/frames/monet_throw/04.png +0 -0
  62. package/engine/demos/long_scroll/frames/monet_throw/05.png +0 -0
  63. package/engine/demos/long_scroll/frames/monet_throw/06.png +0 -0
  64. package/engine/demos/long_scroll/frames/monet_throw/07.png +0 -0
  65. package/engine/demos/long_scroll/frames/monet_throw/08.png +0 -0
  66. package/engine/demos/long_scroll/frames/monet_throw/meta.json +71 -0
  67. package/engine/demos/long_scroll/frames/monet_walk/01.png +0 -0
  68. package/engine/demos/long_scroll/frames/monet_walk/02.png +0 -0
  69. package/engine/demos/long_scroll/frames/monet_walk/03.png +0 -0
  70. package/engine/demos/long_scroll/frames/monet_walk/04.png +0 -0
  71. package/engine/demos/long_scroll/frames/monet_walk/05.png +0 -0
  72. package/engine/demos/long_scroll/frames/monet_walk/06.png +0 -0
  73. package/engine/demos/long_scroll/frames/monet_walk/07.png +0 -0
  74. package/engine/demos/long_scroll/frames/monet_walk/08.png +0 -0
  75. package/engine/demos/long_scroll/frames/monet_walk/meta.json +71 -0
  76. package/engine/demos/long_scroll/lib/acts.js +87 -0
  77. package/engine/demos/long_scroll/lib/crossing.js +463 -0
  78. package/engine/demos/long_scroll/lib/world.js +143 -0
  79. package/engine/demos/long_scroll/lib/xing2_ding.js +42 -0
  80. package/engine/demos/long_scroll/lib/xing2_jia.js +114 -0
  81. package/engine/demos/long_scroll/lib/xing2_yi.js +133 -0
  82. package/engine/demos/long_scroll/segments/02_egypt.js +234 -0
  83. package/engine/demos/long_scroll/segments/14_8bit.js +118 -0
  84. package/engine/demos/long_scroll/segments/28_monet.js +86 -0
  85. package/engine/demos/t1_3b1b/eras.js +11 -0
  86. package/engine/demos/t1_3b1b/t1_s1.js +101 -0
  87. package/engine/demos/t1_3b1b/t1_s2.js +74 -0
  88. package/engine/demos/t1_3b1b/t1_s3.js +65 -0
  89. package/engine/demos/t2_keynote_ui/eras.js +10 -0
  90. package/engine/demos/t2_keynote_ui/t2_s1.js +57 -0
  91. package/engine/demos/t2_keynote_ui/t2_s2.js +70 -0
  92. package/engine/demos/t2_keynote_ui/t2_s3.js +61 -0
  93. package/engine/demos/t3_finance_chart/eras.js +11 -0
  94. package/engine/demos/t3_finance_chart/t3_s1.js +48 -0
  95. package/engine/demos/t3_finance_chart/t3_s2.js +42 -0
  96. package/engine/demos/t3_finance_chart/t3_s3.js +51 -0
  97. package/engine/demos/y1_kurzgesagt/eras.js +10 -0
  98. package/engine/demos/y1_kurzgesagt/kurzgesagt.js +347 -0
  99. package/engine/demos/y2_vox/eras.js +10 -0
  100. package/engine/demos/y2_vox/vox.js +240 -0
  101. package/engine/demos/y3_whiteboard/eras.js +10 -0
  102. package/engine/demos/y3_whiteboard/whiteboard.js +162 -0
  103. package/engine/demos/y4_storytime/eras.js +14 -0
  104. package/engine/demos/y4_storytime/s1_desk.js +18 -0
  105. package/engine/demos/y4_storytime/s2_screen.js +82 -0
  106. package/engine/demos/y4_storytime/s3_react.js +39 -0
  107. package/engine/demos/y4_storytime/s4_wide.js +16 -0
  108. package/engine/demos/y4_storytime/s5_close.js +18 -0
  109. package/engine/demos/y4_storytime/story.js +25 -0
  110. package/engine/demos/y4_storytime/vo_env.js +2 -0
  111. package/engine/demos/y4_storytime/world.js +73 -0
  112. package/engine/demos/y5_kinetic_type/eras.js +16 -0
  113. package/engine/demos/y5_kinetic_type/k1_title.js +38 -0
  114. package/engine/demos/y5_kinetic_type/k2_complete.js +55 -0
  115. package/engine/demos/y5_kinetic_type/k3_chat.js +47 -0
  116. package/engine/demos/y5_kinetic_type/k4_agent.js +49 -0
  117. package/engine/demos/y5_kinetic_type/kinetic.js +52 -0
  118. package/engine/engine.js +277 -0
  119. package/engine/eras.js +60 -0
  120. package/engine/eras_gallery.js +115 -0
  121. package/engine/eras_style_studies.js +20 -0
  122. package/engine/examples/assets/K/347/272/277/345/233/276_/346/250/252/345/261/217.png +0 -0
  123. package/engine/examples/assets//347/273/210/347/253/257_for/345/276/252/347/216/257/346/261/202/345/222/214.png +0 -0
  124. package/engine/examples/assets//347/273/210/347/253/257_sum/346/261/202/345/222/214.png +0 -0
  125. package/engine/examples/assets//350/220/245/346/224/266/345/233/276_/347/253/226/345/261/217.png +0 -0
  126. package/engine/examples/assets//350/264/242/347/273/217/345/233/276/350/241/250_/346/250/252/345/261/217.png +0 -0
  127. package/engine/examples/t1_3b1b.json +19 -0
  128. package/engine/examples/t2_fullbleed_pulse.json +15 -0
  129. package/engine/examples/t2_keynote_ui.json +15 -0
  130. package/engine/examples/t3_finance_chart.json +29 -0
  131. package/engine/examples/y1_kurzgesagt.json +16 -0
  132. package/engine/examples/y2_vox.json +14 -0
  133. package/engine/examples/y3_whiteboard.json +17 -0
  134. package/engine/examples/y4_storytime.json +52 -0
  135. package/engine/examples/y5_kinetic_type.json +14 -0
  136. package/engine/index.html +42 -0
  137. package/engine/lib/THREE_LICENSE.txt +21 -0
  138. package/engine/lib/brush.js +149 -0
  139. package/engine/lib/camera.js +99 -0
  140. package/engine/lib/chart.js +152 -0
  141. package/engine/lib/collage.js +97 -0
  142. package/engine/lib/diagram.js +264 -0
  143. package/engine/lib/finish.js +70 -0
  144. package/engine/lib/fonts/AlfaSlabOne-400.woff +0 -0
  145. package/engine/lib/fonts/Anton-400.woff +0 -0
  146. package/engine/lib/fonts/ArchivoBlack-400.woff +0 -0
  147. package/engine/lib/fonts/Bangers-400.woff +0 -0
  148. package/engine/lib/fonts/Caveat-600.woff +0 -0
  149. package/engine/lib/fonts/Cinzel-400.woff +0 -0
  150. package/engine/lib/fonts/Cinzel-700.woff +0 -0
  151. package/engine/lib/fonts/CormorantGaramond-500.woff +0 -0
  152. package/engine/lib/fonts/CormorantGaramond-500i.woff +0 -0
  153. package/engine/lib/fonts/CormorantGaramond-700.woff +0 -0
  154. package/engine/lib/fonts/EBGaramond-400.woff +0 -0
  155. package/engine/lib/fonts/EBGaramond-400i.woff +0 -0
  156. package/engine/lib/fonts/EBGaramond-600.woff +0 -0
  157. package/engine/lib/fonts/Exo2-800i.woff +0 -0
  158. package/engine/lib/fonts/GochiHand-400.woff +0 -0
  159. package/engine/lib/fonts/IMFellEnglish-400.woff +0 -0
  160. package/engine/lib/fonts/IMFellEnglish-400i.woff +0 -0
  161. package/engine/lib/fonts/Inter-var.woff +0 -0
  162. package/engine/lib/fonts/JosefinSans-700.woff +0 -0
  163. package/engine/lib/fonts/Kalam-700.woff +0 -0
  164. package/engine/lib/fonts/LICENSES.md +40 -0
  165. package/engine/lib/fonts/LXGWWenKai-500.woff +0 -0
  166. package/engine/lib/fonts/LibreBaskerville-400.woff +0 -0
  167. package/engine/lib/fonts/LibreBaskerville-700.woff +0 -0
  168. package/engine/lib/fonts/LilitaOne-400.woff +0 -0
  169. package/engine/lib/fonts/Marcellus-400.woff +0 -0
  170. package/engine/lib/fonts/NotoSansSC-500.woff +0 -0
  171. package/engine/lib/fonts/NotoSansSC-700.woff +0 -0
  172. package/engine/lib/fonts/NotoSansSC-800.woff +0 -0
  173. package/engine/lib/fonts/NotoSansSC-900.woff +0 -0
  174. package/engine/lib/fonts/NotoSansSC-sub.woff +0 -0
  175. package/engine/lib/fonts/NotoSerifJP-600.woff +0 -0
  176. package/engine/lib/fonts/NotoSerifSC-sub.woff +0 -0
  177. package/engine/lib/fonts/OFL.txt +94 -0
  178. package/engine/lib/fonts/PlayfairDisplay-400i.woff +0 -0
  179. package/engine/lib/fonts/PlayfairDisplay-700.woff +0 -0
  180. package/engine/lib/fonts/PlayfairDisplay-700i.woff +0 -0
  181. package/engine/lib/fonts/Poppins-600.woff +0 -0
  182. package/engine/lib/fonts/Poppins-700.woff +0 -0
  183. package/engine/lib/fonts/Poppins-800.woff +0 -0
  184. package/engine/lib/fonts/PressStart2P-400.woff +0 -0
  185. package/engine/lib/fonts/Righteous-400.woff +0 -0
  186. package/engine/lib/fonts/RobotoCondensed-var.woff +0 -0
  187. package/engine/lib/fonts/Rye-400.woff +0 -0
  188. package/engine/lib/fonts/UnifrakturMaguntia-400.woff +0 -0
  189. package/engine/lib/fonts/cmunrm.woff +0 -0
  190. package/engine/lib/fonts/cmunti.woff +0 -0
  191. package/engine/lib/fonts/index.json +1 -0
  192. package/engine/lib/fonts.js +56 -0
  193. package/engine/lib/kit.js +91 -0
  194. package/engine/lib/media.js +118 -0
  195. package/engine/lib/medium.js +258 -0
  196. package/engine/lib/motion.js +111 -0
  197. package/engine/lib/paint.js +200 -0
  198. package/engine/lib/palettes.js +57 -0
  199. package/engine/lib/post.js +108 -0
  200. package/engine/lib/render.js +189 -0
  201. package/engine/lib/rig.js +390 -0
  202. package/engine/lib/rig_huashu.js +171 -0
  203. package/engine/lib/three.min.js +7 -0
  204. package/engine/lib/toon.js +186 -0
  205. package/engine/lib/typo.js +136 -0
  206. package/engine/lib/ui.js +141 -0
  207. package/engine/lib/util.js +92 -0
  208. package/engine/render.py +157 -0
  209. package/engine/scenes/01_cave.js +364 -0
  210. package/engine/scenes/02_egypt.js +524 -0
  211. package/engine/scenes/03_greek.js +448 -0
  212. package/engine/scenes/04_roman.js +555 -0
  213. package/engine/scenes/05_gothic.js +522 -0
  214. package/engine/scenes/06_renaissance.js +338 -0
  215. package/engine/scenes/08_impressionism.js +206 -0
  216. package/engine/scenes/09_postimp.js +183 -0
  217. package/engine/scenes/10_nouveau.js +334 -0
  218. package/engine/scenes/11_cubism.js +265 -0
  219. package/engine/scenes/12_bauhaus.js +214 -0
  220. package/engine/scenes/13_pop.js +269 -0
  221. package/engine/scenes/14_8bit.js +238 -0
  222. package/engine/scenes/15_raytrace.js +300 -0
  223. package/engine/scenes/16_2026.js +565 -0
  224. package/engine/scenes/17_ink.js +273 -0
  225. package/engine/scenes/18_klimt.js +227 -0
  226. package/engine/scenes/19_munch.js +153 -0
  227. package/engine/scenes/20_dunhuang.js +215 -0
  228. package/engine/scenes/21_kusama.js +124 -0
  229. package/engine/scenes/22_constructivism.js +205 -0
  230. package/engine/scenes/23_dali.js +221 -0
  231. package/engine/scenes/24_hopper.js +150 -0
  232. package/engine/scenes/25_ghibli.js +251 -0
  233. package/engine/scenes/26_vaporwave.js +191 -0
  234. package/engine/scenes/27_kirby.js +255 -0
  235. package/engine/scenes/28_monet.js +176 -0
  236. package/engine/scenes/29_seurat.js +104 -0
  237. package/engine/scenes/30_matisse.js +151 -0
  238. package/engine/scenes/31_haring.js +109 -0
  239. package/engine/scenes/32_rembrandt.js +217 -0
  240. package/engine/scenes/33_rubberhose.js +219 -0
  241. package/engine/scenes/34_shadowpuppet.js +195 -0
  242. package/engine/scenes/35_shinkai.js +197 -0
  243. package/engine/scenes/36_picasso_blue.js +123 -0
  244. package/engine/scenes/38_giotto.js +133 -0
  245. package/engine/scenes/39_piero.js +53 -0
  246. package/engine/scenes/40_raphael.js +96 -0
  247. package/engine/scenes/41_michelangelo.js +112 -0
  248. package/engine/scenes/42_guardi.js +70 -0
  249. package/engine/scenes/43_lorenzetti.js +145 -0
  250. package/engine/scenes/44_cortona.js +86 -0
  251. package/engine/scenes/45_renoir.js +86 -0
  252. package/engine/scenes/46_pissarro.js +82 -0
  253. package/engine/scenes/47_sisley.js +94 -0
  254. package/engine/scenes/48_gauguin.js +107 -0
  255. package/engine/scenes/49_chagall.js +60 -0
  256. package/engine/scenes/50_ma_yuan.js +131 -0
  257. package/engine/scenes/51_persian_miniature.js +149 -0
  258. package/engine/scenes/52_south_park.js +105 -0
  259. package/engine/scenes/53_pixar.js +60 -0
  260. package/engine/scenes/54_ghibli_lab.js +68 -0
  261. package/engine/scenes/55_dunhuang.js +161 -0
  262. package/engine/scenes/index.js +28 -0
  263. package/engine/spec_assets.py +76 -0
  264. package/engine/transitions.js +929 -0
  265. package/engine//346/227/266/344/273/243/344/275/234/350/200/205/350/247/204/350/214/203.md +49 -0
  266. package/lib/host.mjs +754 -0
  267. package/lib/render-bridge.mjs +543 -0
  268. package/lib/render-cli.mjs +98 -0
  269. package/lib/storyboard-lint.mjs +54 -0
  270. package/manifest.json +52 -0
  271. package/package.json +8 -4
  272. package/runtime/package.json +8 -0
  273. package/skills/biuart/SKILL.md +154 -0
  274. package/skills/biuart/references/01-/346/213/206/350/247/243.md +55 -0
  275. package/skills/biuart/references/02-/346/234/272/345/210/266.md +41 -0
  276. package/skills/biuart/references/03-/344/270/200/345/270/247/345/205/210/350/241/214/345/233/233/346/235/241/350/267/257/347/272/277.md +39 -0
  277. package/skills/biuart/references/04-/347/272/257/344/273/243/347/240/201/347/273/230/345/210/266.md +92 -0
  278. package/skills/biuart/references/05-/350/212/202/345/245/217/344/270/216/351/205/215/344/271/220.md +19 -0
  279. package/skills/biuart/references/06-/345/217/243/346/222/255/351/251/261/345/212/250/347/232/204/350/211/272/346/234/257/347/237/255/347/211/207.md +31 -0
  280. package/skills/biuart/references/07-/346/255/243/351/235/242/347/273/217/351/252/214.md +196 -0
  281. package/skills/biuart/references/08-/351/243/216/346/240/274/344/275/234/350/200/205/350/247/204/350/214/203.md +61 -0
  282. package/skills/biuart/references/09-/350/247/206/351/242/221/345/212/250/347/224/273/350/257/255/346/263/225.md +382 -0
  283. package/skills/biuart/references/10-/350/247/222/350/211/262.md +34 -0
  284. package/skills/biuart/references/11-/351/225/277/345/215/267/347/251/277/350/266/212/347/211/207.md +43 -0
  285. package/skills/biuart/references/12-/345/217/243/346/222/255/346/225/264/347/211/207/344/270/216/347/273/217/351/252/214/345/233/236/346/265/201.md +25 -0
  286. package/skills/biuart/references/13-/345/217/243/346/222/255/344/270/216/350/257/255/351/237/263/345/244/215/345/210/273.md +7 -0
  287. package/skills/biuart/references/15-/350/267/250/345/234/272/346/231/257/351/243/216/346/240/274/346/217/220/347/202/274.md +48 -0
  288. package/skills/biuart/references/16-/351/243/216/346/240/274/346/274/224/347/244/27295/345/210/206/345/215/217/350/256/256.md +103 -0
  289. package/skills/biuart/references/about-author.md +99 -0
  290. package/skills/biuart/references/capabilities.md +91 -0
  291. package/skills/biuart/references/compatibility.md +34 -0
  292. package/skills/biuart/references/images.md +97 -0
  293. package/skills/biuart/references/voice-model-review.md +18 -0
  294. package/skills/biuart/references//345/212/250/347/224/273/350/257/255/346/263/225/t1_3b1b.md +122 -0
  295. package/skills/biuart/references//345/212/250/347/224/273/350/257/255/346/263/225/t2_keynote_ui.md +117 -0
  296. package/skills/biuart/references//345/212/250/347/224/273/350/257/255/346/263/225/t3_finance_chart.md +116 -0
  297. package/skills/biuart/references//345/212/250/347/224/273/350/257/255/346/263/225/y1_kurzgesagt.md +193 -0
  298. package/skills/biuart/references//345/212/250/347/224/273/350/257/255/346/263/225/y2_vox.md +195 -0
  299. package/skills/biuart/references//345/212/250/347/224/273/350/257/255/346/263/225/y3_whiteboard.md +190 -0
  300. package/skills/biuart/references//345/212/250/347/224/273/350/257/255/346/263/225/y4_storytime.md +166 -0
  301. package/skills/biuart/references//345/212/250/347/224/273/350/257/255/346/263/225/y5_kinetic_type.md +158 -0
  302. package/skills/biuart/references//345/212/250/347/224/273/350/257/255/346/263/225/y6_presenter_explainer.md +24 -0
  303. package/skills/biuart/references//345/217/243/346/222/255API.md +125 -0
  304. package/skills/biuart/references//350/211/262/346/235/277.md +38 -0
  305. package/skills/biuart/references//350/247/222/350/211/262/347/262/276/347/273/206/345/272/246.md +61 -0
  306. package/skills/biuart/references//351/225/234/345/244/264/350/241/250/346/250/241/346/235/277.md +80 -0
  307. package/skills/biuart/references//351/225/234/345/244/264/350/257/255/350/250/200.md +73 -0
  308. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/01_cave.md +46 -0
  309. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/02_egypt.md +64 -0
  310. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/03_greek.md +50 -0
  311. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/04_roman.md +99 -0
  312. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/05_gothic.md +32 -0
  313. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/06_renaissance.md +41 -0
  314. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/08_impressionism.md +34 -0
  315. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/09_postimp.md +17 -0
  316. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/10_nouveau.md +31 -0
  317. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/11_cubism.md +30 -0
  318. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/12_bauhaus.md +30 -0
  319. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/13_pop.md +29 -0
  320. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/14_8bit.md +27 -0
  321. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/15_raytrace.md +32 -0
  322. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/16_2026.md +55 -0
  323. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/17_ink.md +50 -0
  324. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/18_klimt.md +37 -0
  325. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/19_munch.md +42 -0
  326. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/20_dunhuang.md +49 -0
  327. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/21_kusama.md +32 -0
  328. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/22_constructivism.md +35 -0
  329. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/23_dali.md +29 -0
  330. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/24_hopper.md +30 -0
  331. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/25_ghibli.md +55 -0
  332. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/26_vaporwave.md +27 -0
  333. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/27_kirby.md +30 -0
  334. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/28_monet.md +39 -0
  335. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/29_seurat.md +31 -0
  336. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/30_matisse.md +26 -0
  337. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/31_haring.md +22 -0
  338. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/32_rembrandt.md +29 -0
  339. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/33_rubberhose.md +31 -0
  340. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/34_shadowpuppet.md +40 -0
  341. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/35_shinkai.md +34 -0
  342. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/36_picasso_blue.md +25 -0
  343. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/37_rick_morty.md +48 -0
  344. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/38_giotto.md +67 -0
  345. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/39_piero.md +59 -0
  346. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/40_raphael.md +65 -0
  347. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/41_michelangelo.md +65 -0
  348. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/42_guardi.md +65 -0
  349. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/43_lorenzetti.md +69 -0
  350. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/44_cortona.md +66 -0
  351. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/45_renoir.md +66 -0
  352. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/46_pissarro.md +66 -0
  353. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/47_sisley.md +67 -0
  354. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/48_gauguin.md +66 -0
  355. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/49_chagall.md +59 -0
  356. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/50_ma_yuan.md +68 -0
  357. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/51_persian_miniature.md +66 -0
  358. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/52_south_park.md +65 -0
  359. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/53_pixar.md +61 -0
  360. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/55_dunhuang.md +41 -0
  361. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/INDEX.md +89 -0
  362. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/_/350/275/254/345/234/272_/350/277/201/347/247/273/346/265/213/350/257/225.md +53 -0
  363. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/_/351/207/215/345/201/232/350/277/233/345/272/246.md +37 -0
  364. package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/_/351/237/263/350/275/250_/350/211/272/346/234/257/345/217/262/351/200/237/351/200/232.md +135 -0
  365. package/studio/app.js +380 -0
  366. package/studio/assert-panel-permit.mjs +67 -0
  367. package/studio/composer.css +465 -0
  368. package/studio/composer.js +480 -0
  369. package/studio/index.html +97 -0
  370. package/studio/optimize-prompt.mjs +84 -0
  371. package/studio/optimize-prompt.test.mjs +47 -0
  372. package/studio/recipes.mjs +87 -0
  373. package/studio/select-menu.js +450 -0
  374. package/studio/styles.css +71 -0
  375. package/studio/to-english-prompt.mjs +149 -0
  376. package/studio/to-english-prompt.test.mjs +72 -0
  377. package/README.md +0 -3
@@ -0,0 +1,251 @@
1
+ // 1988 吉卜力式手绘水彩背景美术(宫崎骏/男鹿和雄的夏日房间)——纯代码。
2
+ // 管线:①缓存底版:纸 → 水彩洗染 wash(中点位移变形的多边形 × 多层低 α multiply 叠色 + 每层描一圈淡边 = 水痕边)
3
+ // → 窗外蓝天、积雨云(白色不透明+底部蓝灰透明叠色)、远山、草坡、大樟树;室内灰泥墙、木地板、扫帚、小架子
4
+ // → ②会动的母题(白纱窗帘被风鼓起、窗外草叶成片摆、云慢慢飘、树冠轻摇、墙上树影光斑闪、桌上雏菊点头、发丝与红蝴蝶结飘)
5
+ // → ③角色:赛璐璐两色(基色+「路径减去朝光平移的自身」得到的月牙阴影)+暖褐细线
6
+ SCENES['25_ghibli'] = (() => {
7
+ const W = 1920, H = 1080, { clamp, lerp, ease, rng } = U, P = PAINT, TAU = Math.PI * 2;
8
+ const FLOOR = 720, WIN = [370, 140, 420, 400];
9
+ const LINE = '#6a4a38';
10
+
11
+ // 水彩:P.watercolor(中点位移多边形 × 多层低 α multiply + 水痕边)、P.deform、P.rectPts / P.ellipsePts
12
+ const deform = P.deform, wash = P.watercolor, rect = P.rectPts, ellipsePts = P.ellipsePts;
13
+ const fillPts = (g, pts) => { g.beginPath(); pts.forEach((q, i) => i ? g.lineTo(q[0], q[1]) : g.moveTo(q[0], q[1])); g.closePath(); };
14
+
15
+ // ---------- 云(缓存精灵):白色不透明块 + 底部蓝灰透明叠 ----------
16
+ const cloud = (key, w, h, seed) => P.cached('gh_cloud_' + key, w, h, (g) => {
17
+ const r = rng(seed), puffs = [];
18
+ for (let i = 0; i < 16; i++) { const x = w * (0.15 + r() * 0.7), base = h * 0.78, yy = base - Math.sin((x / w) * Math.PI) * h * (0.35 + r() * 0.3); puffs.push([x, yy, 30 + r() * 46]); }
19
+ puffs.push([w * 0.5, h * 0.72, w * 0.36]);
20
+ puffs.forEach(([x, y, rr], i) => wash(g, ellipsePts(x, y, rr, rr * 0.82, 14), '#ffffff', { layers: 3, alpha: 0.9, amp: 6, seed: seed + i, edge: 0, blend: 'source-over' }));
21
+ g.save(); g.globalCompositeOperation = 'source-atop';
22
+ const sh = g.createLinearGradient(0, h * 0.35, 0, h); sh.addColorStop(0, 'rgba(150,175,205,0)'); sh.addColorStop(1, 'rgba(120,145,190,.75)'); g.fillStyle = sh; g.fillRect(0, 0, w, h);
23
+ g.restore();
24
+ });
25
+ // 大樟树(缓存精灵,轻摇时绕树根转)
26
+ const tree = () => P.cached('gh_tree', 300, 360, (g) => {
27
+ g.fillStyle = '#4a3a2a'; g.fillRect(140, 210, 22, 150);
28
+ const r = rng(77);
29
+ for (let i = 0; i < 22; i++) { const x = 150 + (r() - .5) * 220, y = 150 + (r() - .5) * 170, rr = 34 + r() * 40;
30
+ wash(g, ellipsePts(x, y, rr, rr * 0.8, 12), i % 3 ? '#3f7a3a' : '#2a5a32', { layers: 3, alpha: 0.6, amp: 10, seed: i + 5, edge: 0.15, blend: 'source-over' }); }
31
+ for (let i = 0; i < 14; i++) { const x = 120 + (r() - .5) * 180, y = 110 + (r() - .5) * 120, rr = 18 + r() * 22;
32
+ wash(g, ellipsePts(x, y, rr, rr * 0.7, 10), '#8cc65a', { layers: 2, alpha: 0.45, amp: 6, seed: i + 50, edge: 0, blend: 'source-over' }); }
33
+ });
34
+
35
+ // ---------- ① 底版 ----------
36
+ const bg = () => P.cached('gh_bg', W, H, (g) => {
37
+ g.drawImage(P.texture('gh_paper', '#fbf6ea', { scale: 0.02, amt: 6, grain: 10, seed: 3 }), 0, 0);
38
+ // 室内:暖灰泥墙——窗边亮、角落暗的渐变洗染 → 再叠 28 块大幅变形的透明色晕(暖黄/粉/蓝灰交替 = 透明叠色)
39
+ const wl = g.createRadialGradient(580, 340, 100, 700, 420, 1500); wl.addColorStop(0, '#fbf3e0'); wl.addColorStop(0.6, '#f1e1bf'); wl.addColorStop(1, '#dcc49a');
40
+ wash(g, rect(-20, -20, W + 40, FLOOR + 30), '#efdcb4', { layers: 5, alpha: 0.4, amp: 12, seed: 2, edge: 0, fill: wl });
41
+ { const r = rng(404), tints = ['#f2c48a', '#e9b4a2', '#b9c9d8', '#f3dca0', '#d6ae80', '#c8d4b0'];
42
+ for (let i = 0; i < 28; i++) { const x = r() * W, y = r() * 600, rx = 90 + r() * 220, ry = 60 + r() * 160;
43
+ if (x > 340 && x < 820 && y > 110 && y < 560) continue;
44
+ wash(g, ellipsePts(x, y, rx, ry, 10), tints[i % tints.length], { layers: 3, alpha: 0.045, amp: 40, seed: 100 + i, edge: 0.04 }); } }
45
+ wash(g, [[1700, -20], [1940, -20], [1940, 740], [1620, 740], [1680, 400]], '#b89a6c', { layers: 4, alpha: 0.06, amp: 60, seed: 3, edge: 0.03 }); // 右角落暗
46
+ wash(g, [[-20, -20], [200, -20], [140, 400], [220, 740], [-20, 740]], '#b89a6c', { layers: 4, alpha: 0.06, amp: 60, seed: 4, edge: 0.03 });
47
+ // 木护墙板(腰线以下竖板,逐块不同色调)
48
+ { const r = rng(505); for (let x = -10; x < W; x += 64) wash(g, rect(x, 588, 62, FLOOR - 588), ['#c08a56', '#b47e4c', '#c99460', '#ad7848'][(r() * 4) | 0], { layers: 3, alpha: 0.32, amp: 3, seed: 200 + x, edge: 0.12 }); }
49
+ wash(g, rect(-20, 576, W + 40, 16), '#8a5a34', { layers: 3, alpha: 0.4, amp: 2, seed: 7, edge: 0.15 });
50
+ // 地板:逐条木板洗染
51
+ { const r = rng(606); let y = FLOOR; for (let k = 0; k < 8; k++) { const h = 26 + k * 12; wash(g, rect(-20, y, W + 40, h), ['#a86e3a', '#9a6232', '#b07a44', '#a06836'][(r() * 4) | 0], { layers: 3, alpha: 0.5, amp: 3, seed: 300 + k, edge: 0.14 }); y += h; } }
52
+ // 窗投到地上的暖光斑(软边、带窗棂十字影)
53
+ g.save(); g.globalCompositeOperation = 'screen'; g.filter = 'blur(10px)'; g.fillStyle = 'rgba(255,236,180,.55)';
54
+ g.beginPath(); g.moveTo(400, 740); g.lineTo(800, 740); g.lineTo(930, 1040); g.lineTo(450, 1040); g.closePath(); g.fill(); g.restore();
55
+ g.save(); g.globalCompositeOperation = 'multiply'; g.filter = 'blur(6px)'; g.fillStyle = 'rgba(190,150,110,.5)';
56
+ g.beginPath(); g.moveTo(596, 740); g.lineTo(606, 740); g.lineTo(700, 1040); g.lineTo(684, 1040); g.closePath(); g.fill(); g.fillRect(420, 880, 470, 10); g.restore();
57
+ wash(g, rect(-20, FLOOR - 26, W + 40, 26), '#9a6a40', { layers: 4, alpha: 0.25, amp: 4, seed: 6, edge: 0.1 }); // 踢脚板
58
+ // 窗外:蓝天(渐变洗染)
59
+ g.save(); g.beginPath(); g.rect(...WIN); g.clip();
60
+ const sky = g.createLinearGradient(0, 140, 0, 440); sky.addColorStop(0, '#3a86d4'); sky.addColorStop(1, '#bfe2f4');
61
+ wash(g, rect(360, 130, 440, 330), '#5a9ad8', { layers: 5, alpha: 0.5, amp: 6, seed: 7, edge: 0, blend: 'source-over', fill: sky });
62
+ // 远山(蓝绿)
63
+ wash(g, [[360, 430], [420, 400], [500, 410], [560, 385], [640, 402], [720, 380], [800, 400], [800, 470], [360, 470]], '#7aa6a0', { layers: 5, alpha: 0.35, amp: 6, seed: 8, edge: 0.12 });
64
+ // 草坡(亮绿 → 深绿)
65
+ const gr = g.createLinearGradient(0, 430, 0, 540); gr.addColorStop(0, '#9ccc5a'); gr.addColorStop(1, '#4c8a3a');
66
+ wash(g, [[360, 450], [480, 432], [620, 446], [800, 428], [800, 560], [360, 560]], '#6aa848', { layers: 6, alpha: 0.5, amp: 6, seed: 9, edge: 0.1, blend: 'source-over', fill: gr });
67
+ g.restore();
68
+ // 窗框(白漆木,蓝绿阴影)+窗台
69
+ const frame = [[346, 116, 468, 24], [346, 116, 24, 446], [790, 116, 24, 446], [575, 140, 10, 400], [370, 330, 420, 9]];
70
+ frame.forEach(([x, y, w, h], i) => wash(g, rect(x, y, w, h), '#f6f1e2', { layers: 3, alpha: 0.95, amp: 2, seed: 20 + i, edge: 0.2, blend: 'source-over' }));
71
+ frame.forEach(([x, y, w, h], i) => wash(g, rect(x + w * 0.55, y, w * 0.45, h), '#9fb8c0', { layers: 2, alpha: 0.25, amp: 2, seed: 30 + i, edge: 0 }));
72
+ wash(g, rect(326, 540, 508, 28), '#f3ecd8', { layers: 3, alpha: 0.95, amp: 2, seed: 40, edge: 0.2, blend: 'source-over' });
73
+ wash(g, rect(326, 556, 508, 12), '#a8b7b8', { layers: 2, alpha: 0.35, amp: 2, seed: 41, edge: 0 });
74
+ // 窗帘杆
75
+ g.strokeStyle = '#6a4a30'; g.lineWidth = 7; g.lineCap = 'round'; g.beginPath(); g.moveTo(300, 98); g.lineTo(860, 98); g.stroke();
76
+ // 墙上小木架+瓶罐、挂着的干花束
77
+ wash(g, rect(1540, 300, 260, 14), '#8a5a34', { layers: 3, alpha: 0.6, amp: 2, seed: 50, edge: 0.15 });
78
+ [[1560, 240, 34, 60, '#6a9ac0'], [1610, 262, 40, 38, '#d8a050'], [1670, 236, 28, 64, '#9ab86a'], [1720, 254, 46, 46, '#c86a50']].forEach(([x, y, w, h, col], i) => wash(g, rect(x, y, w, h), col, { layers: 4, alpha: 0.3, amp: 4, seed: 60 + i, edge: 0.15 }));
79
+ // 靠墙的扫帚(致敬魔女宅急便)
80
+ g.save(); g.translate(1760, 330); g.rotate(0.12);
81
+ wash(g, rect(-7, 0, 14, 470), '#7a5030', { layers: 3, alpha: 0.5, amp: 2, seed: 70, edge: 0.2 });
82
+ wash(g, [[-10, 460], [10, 460], [46, 620], [-46, 620]], '#c89a4a', { layers: 4, alpha: 0.45, amp: 5, seed: 71, edge: 0.2 });
83
+ g.strokeStyle = 'rgba(120,80,30,.6)'; g.lineWidth = 1.5; for (let k = -5; k <= 5; k++) { g.beginPath(); g.moveTo(k * 2, 470); g.lineTo(k * 8.5, 616); g.stroke(); }
84
+ g.fillStyle = '#c84a3a'; g.fillRect(-12, 452, 24, 10); g.restore();
85
+ // 桌(木)+白桌布,椅子
86
+ wash(g, rect(842, 640, 22, 265), '#8a5a34', { layers: 3, alpha: 0.6, amp: 3, seed: 80, edge: 0.15 });
87
+ wash(g, rect(1160, 640, 22, 265), '#8a5a34', { layers: 3, alpha: 0.6, amp: 3, seed: 81, edge: 0.15 });
88
+ wash(g, rect(1436, 470, 18, 440), '#7a4c2a', { layers: 3, alpha: 0.6, amp: 3, seed: 82, edge: 0.15 });
89
+ wash(g, rect(1474, 478, 18, 430), '#7a4c2a', { layers: 3, alpha: 0.6, amp: 3, seed: 83, edge: 0.15 });
90
+ wash(g, rect(1290, 744, 210, 16), '#8a5a34', { layers: 3, alpha: 0.6, amp: 3, seed: 84, edge: 0.15 });
91
+ // 整体:纸纹颗粒(颜料在纸凹处沉积)
92
+ g.save(); g.globalCompositeOperation = 'multiply'; g.globalAlpha = 0.3; g.drawImage(P.texture('gh_gran', '#f4efe2', { scale: 0.06, amt: 18, grain: 26, seed: 9 }), 0, 0); g.restore();
93
+ });
94
+ // 桌布(垂边随风轻摆,每帧画)
95
+ function tablecloth(c, lt) {
96
+ const sw = Math.sin(lt * 5) * 5;
97
+ const pts = [[800, 612], [1214, 612], [1222, 700 + sw], [1150, 712 - sw], [1060, 704 + sw], [980, 714 - sw], [890, 704 + sw], [804, 712 - sw]];
98
+ wash(c, pts, '#fffdf6', { layers: 2, alpha: 0.95, amp: 3, seed: 90, edge: 0.25, blend: 'source-over' });
99
+ wash(c, pts.map(([x, y]) => [x, y + (y > 640 ? 0 : 30)]), '#b8c8d8', { layers: 2, alpha: 0.18, amp: 3, seed: 91, edge: 0 });
100
+ }
101
+
102
+ // ---------- ② 窗帘:白纱两幅,下摆被风往屋里鼓 ----------
103
+ function curtain(c, side, lt) {
104
+ const x0 = side < 0 ? 300 : 860, inner = side < 0 ? 420 : 740;
105
+ const gust = 0.5 + 0.5 * Math.sin(lt * 5.4 + (side < 0 ? 0 : 1.3));
106
+ const pts = [], N = 14;
107
+ for (let i = 0; i <= N; i++) { const q = i / N, y = 100 + q * 500, bulge = q * q * (60 + 150 * gust), w = Math.sin(lt * 9 + q * 6 + side) * 16 * q;
108
+ pts.push([inner + side * 0 - side * (bulge * 0.15) + w + (side < 0 ? 1 : -1) * bulge * 0.9, y]); }
109
+ for (let i = N; i >= 0; i--) { const q = i / N, y = 100 + q * 500 + (i === N ? 0 : 0); pts.push([x0 + (side < 0 ? -1 : 1) * q * 30 * gust, y + Math.sin(lt * 6 + q * 4) * 4]); }
110
+ c.save(); c.globalAlpha = 0.85;
111
+ wash(c, pts, '#ffffff', { layers: 3, alpha: 0.42, amp: 4, seed: side < 0 ? 101 : 102, edge: 0, blend: 'source-over' });
112
+ c.restore();
113
+ // 褶线(蓝灰透明,跟随鼓起)
114
+ c.save(); c.globalCompositeOperation = 'multiply'; c.strokeStyle = 'rgba(150,175,200,.45)'; c.lineWidth = 3; c.lineCap = 'round';
115
+ for (let k = 1; k < 4; k++) { const f = k / 4; c.beginPath(); for (let i = 0; i <= 10; i++) { const q = i / 10; const a = pts[Math.round(q * N)], b = pts[2 * N + 1 - Math.round(q * N)]; const x = lerp(b[0], a[0], f), y = lerp(b[1], a[1], f); i ? c.lineTo(x, y) : c.moveTo(x, y); } c.stroke(); }
116
+ c.restore();
117
+ }
118
+ // 窗外草叶:成片同向摆(风是一阵一阵的)
119
+ function grass(c, t) {
120
+ c.save(); c.beginPath(); c.rect(...WIN); c.clip(); c.lineCap = 'round';
121
+ const r = rng(5), cols = ['#5c9a3e', '#7fb84a', '#3f7a32', '#9ccc5a', '#4a8a3a'];
122
+ for (let i = 0; i < 360; i++) {
123
+ const x = 360 + r() * 440, y = 470 + r() * 75, h = 16 + r() * 26 + (y - 470) * 0.35, ph = r() * TAU;
124
+ const wind = Math.sin(t * 3.1 - x * 0.018) * 0.5 + 0.5, sway = (0.25 + wind * 0.75) * h * 0.55 + Math.sin(t * 9 + ph) * 2;
125
+ c.strokeStyle = cols[i % 5]; c.lineWidth = 2 + r() * 2;
126
+ c.beginPath(); c.moveTo(x, y); c.quadraticCurveTo(x + sway * 0.3, y - h * 0.6, x + sway, y - h); c.stroke();
127
+ }
128
+ c.restore();
129
+ }
130
+ // 墙上的树影光斑(komorebi):暖黄亮斑用 screen 叠,位置随噪声慢漂、亮度闪
131
+ function komorebi(c, t) {
132
+ c.save(); c.globalCompositeOperation = 'screen';
133
+ const r = rng(33);
134
+ for (let i = 0; i < 34; i++) {
135
+ const bx = 830 + r() * 380, by = 160 + r() * 420, rr = 10 + r() * 26;
136
+ const x = bx + P.noise(i * 1.3, t * 0.9) * 26, y = by + P.noise(i * 2.1 + 5, t * 0.9) * 18, a = 0.18 + 0.22 * (0.5 + 0.5 * Math.sin(t * 5 + i * 1.7));
137
+ const gg = c.createRadialGradient(x, y, 0, x, y, rr); gg.addColorStop(0, `rgba(255,236,170,${a})`); gg.addColorStop(1, 'rgba(255,236,170,0)'); c.fillStyle = gg; c.beginPath(); c.ellipse(x, y, rr * 1.3, rr, 0.4, 0, TAU); c.fill();
138
+ }
139
+ c.restore();
140
+ }
141
+ // 桌上雏菊(玻璃瓶),花头点头
142
+ function daisies(c, t) {
143
+ const vx = 900, vy = 612;
144
+ c.save(); c.fillStyle = 'rgba(190,220,230,.55)'; c.beginPath(); c.moveTo(vx - 16, vy); c.quadraticCurveTo(vx - 22, vy - 30, vx - 10, vy - 46); c.lineTo(vx + 10, vy - 46); c.quadraticCurveTo(vx + 22, vy - 30, vx + 16, vy); c.closePath(); c.fill();
145
+ c.strokeStyle = 'rgba(90,120,140,.6)'; c.lineWidth = 1.5; c.stroke();
146
+ [[-30, -120, 0], [6, -140, 1.3], [34, -112, 2.1], [-8, -100, 3.2]].forEach(([dx, dy, ph]) => {
147
+ const sw = Math.sin(t * 3.2 + ph) * 7, hx = vx + dx + sw, hy = vy + dy + Math.abs(sw) * 0.2;
148
+ c.strokeStyle = '#5a8a3a'; c.lineWidth = 3; c.beginPath(); c.moveTo(vx + dx * 0.2, vy - 40); c.quadraticCurveTo(vx + dx * 0.6, vy + dy * 0.5, hx, hy); c.stroke();
149
+ c.fillStyle = '#fffdf4'; for (let k = 0; k < 10; k++) { const a = k / 10 * TAU + ph; c.beginPath(); c.ellipse(hx + Math.cos(a) * 9, hy + Math.sin(a) * 6, 7, 3, a, 0, TAU); c.fill(); }
150
+ c.fillStyle = '#f2b830'; c.beginPath(); c.arc(hx, hy, 5, 0, TAU); c.fill();
151
+ });
152
+ c.restore();
153
+ }
154
+
155
+ // ---------- ③ 赛璐璐角色 ----------
156
+ // 赛璐珞两色:P.cel——背光侧(光从左上来,阴影带宽 (dx,dy))一道月牙阴影+暖褐细线
157
+ const cel = (c, p, base, shade, dx = 9, dy = 6, line = true) => P.cel(c, p, base, shade, null, { sd: 1, lx: -dx, ly: -dy, line: LINE, lw: line ? 2.4 : 0 });
158
+ const GP = { skin: '#fde6d2', skinS: '#efbfa4', hair: '#f8dc8c', hairS: '#d9a95a', dress: '#3f8590', dressS: '#2b6470', white: '#fffaf0', whiteS: '#d8dde4', bow: '#d93a30', bowS: '#a0261f' };
159
+ function girl(c, G, ch, lt, t) {
160
+ c.save(); c.lineJoin = 'round'; c.lineCap = 'round';
161
+ cel(c, G.farSleeve, GP.dress, GP.dressS); cel(c, G.farCuff, GP.white, GP.whiteS); cel(c, G.farHand, GP.skin, GP.skinS, 4, 3);
162
+ // 长发(被风吹向右后方)
163
+ const wind = Math.sin(lt * 3.2) * 0.5 + 0.5;
164
+ const nape = G.A.nape, hd = G.A.headC;
165
+ const flow = new Path2D(); const fp = [[hd[0] + 30, hd[1] - 40], [nape[0] + 50 + wind * 14, nape[1] - 30], [nape[0] + 78 + wind * 30, nape[1] + 40 + Math.sin(t * 6) * 6], [nape[0] + 60 + wind * 26, nape[1] + 120 + Math.sin(t * 5 + 1) * 8], [nape[0] + 20, nape[1] + 130], [nape[0] - 6, nape[1] + 40], [hd[0] + 4, hd[1] + 10]];
166
+ const fpath = RIG.smooth(fp); cel(c, fpath, GP.hair, GP.hairS, 10, 4);
167
+ cel(c, G.skirt, GP.dress, GP.dressS, 16, 8);
168
+ c.strokeStyle = GP.dressS; c.lineWidth = 3; G.folds.forEach(f => c.stroke(f));
169
+ cel(c, G.apronSkirt, GP.white, GP.whiteS, 10, 6);
170
+ cel(c, G.shoe, '#6a3a24', '#4a2414', 4, 2);
171
+ cel(c, G.torso, GP.dress, GP.dressS, 14, 6); cel(c, G.bib, GP.white, GP.whiteS, 6, 4);
172
+ cel(c, G.neck, GP.skin, GP.skinS, 6, 2);
173
+ cel(c, G.hairBack, GP.hair, GP.hairS, 10, 6);
174
+ cel(c, G.face, GP.skin, GP.skinS, 10, 4);
175
+ c.save(); c.clip(G.face); c.fillStyle = 'rgba(240,140,130,.35)'; c.beginPath(); c.ellipse(G.cheek[0], G.cheek[1], 12, 7, 0, 0, TAU); c.fill(); c.restore();
176
+ cel(c, G.bangs, GP.hair, GP.hairS, 6, 6);
177
+ c.strokeStyle = GP.hairS; c.lineWidth = 2; G.hairLines.forEach(h => c.stroke(h));
178
+ // 红蝴蝶结(后脑上方),飘带随风
179
+ const bc = [G.A.headTop[0] + 46, G.A.headTop[1] + 14];
180
+ const tails = [[bc[0] + 6, bc[1] + 8], [bc[0] + 40 + wind * 18, bc[1] + 44 + Math.sin(t * 8) * 6], [bc[0] + 26 + wind * 10, bc[1] + 54], [bc[0] + 2, bc[1] + 14]];
181
+ cel(c, RIG.smooth(tails), GP.bow, GP.bowS, 4, 3);
182
+ [[-1, -0.5], [1, 0.4]].forEach(([s, rot]) => { const p = new Path2D(); p.ellipse(bc[0] + s * 24, bc[1] - 4, 26, 15, rot, 0, TAU); cel(c, p, GP.bow, GP.bowS, 5, 4); });
183
+ { const p = new Path2D(); p.arc(bc[0], bc[1], 9, 0, TAU); cel(c, p, GP.bow, GP.bowS, 2, 2); }
184
+ // 五官(吉卜力式:大而简单的眼)
185
+ if (ch.blink) { c.strokeStyle = LINE; c.lineWidth = 3; c.beginPath(); c.arc(G.eye.x, G.eye.y - 2, 7, 0.2, Math.PI - 0.2); c.stroke(); }
186
+ else { c.fillStyle = '#3a2a24'; c.beginPath(); c.ellipse(G.eye.x - 1, G.eye.y + 1, 5, 7.5, 0, 0, TAU); c.fill(); c.fillStyle = '#5a8ac8'; c.beginPath(); c.ellipse(G.eye.x - 1, G.eye.y + 3, 3.5, 4, 0, 0, TAU); c.fill(); c.fillStyle = '#fff'; c.beginPath(); c.arc(G.eye.x - 2.5, G.eye.y - 2, 2, 0, TAU); c.fill();
187
+ c.strokeStyle = LINE; c.lineWidth = 2.8; c.stroke(G.lid); }
188
+ c.strokeStyle = '#c08a40'; c.lineWidth = 2.4; c.stroke(G.brow);
189
+ c.strokeStyle = '#a8443a'; c.lineWidth = 2.2; c.beginPath(); c.moveTo(...G.lips[0]); c.lineTo(G.lips[1][0] - 1, G.lips[1][1] + 2); c.stroke();
190
+ cel(c, G.upperArm, GP.dress, GP.dressS, 8, 6); cel(c, G.foreArm, GP.dress, GP.dressS, 8, 6); cel(c, G.cuff, GP.white, GP.whiteS, 4, 3);
191
+ cel(c, G.hand, GP.skin, GP.skinS, 4, 3);
192
+ RIG.drawCup(c, G.cup, { body: '#fdf8ee', rim: '#7a4a2a', line: LINE, lw: 2.2, hw: 6 });
193
+ c.save(); c.translate(G.cup.x, G.cup.y); c.rotate(G.cup.tilt); c.strokeStyle = '#5a8ac8'; c.lineWidth = 3; c.beginPath(); c.moveTo(-G.cup.w * 0.45, G.cup.h * 0.35); c.lineTo(G.cup.w * 0.45, G.cup.h * 0.35); c.stroke(); c.restore();
194
+ c.fillStyle = GP.skin; c.beginPath(); c.arc(G.thumb[0], G.thumb[1], 7, 0, TAU); c.fill(); c.strokeStyle = LINE; c.lineWidth = 2; c.stroke();
195
+ c.restore();
196
+ }
197
+ function cat(c, K) {
198
+ const O = '#f3a24c', OS = '#d27a2c', Wt = '#fffaf2', WS = '#e2d8ca';
199
+ c.save(); c.lineJoin = 'round'; c.lineCap = 'round';
200
+ c.strokeStyle = LINE; c.lineWidth = K.tailW + 5; c.stroke(K.tail); c.strokeStyle = O; c.lineWidth = K.tailW; c.stroke(K.tail);
201
+ const tip = K.tailPts[K.tailPts.length - 1]; c.fillStyle = Wt; c.beginPath(); c.arc(tip[0], tip[1], K.tailW / 2, 0, TAU); c.fill();
202
+ cel(c, K.body, O, OS, 18, 10);
203
+ c.save(); c.clip(K.body); c.strokeStyle = '#c8682a'; c.lineWidth = 8; K.stripes.slice(3).forEach(s => { c.beginPath(); c.moveTo(...s[0]); c.lineTo(...s[1]); c.stroke(); }); c.restore();
204
+ K.legs.forEach(l => cel(c, l, Wt, WS, 6, 3));
205
+ c.save(); c.clip(K.body); cel(c, K.white, Wt, WS, 10, 6, false); c.restore();
206
+ cel(c, K.head, O, OS, 12, 8);
207
+ c.save(); c.clip(K.head); c.fillStyle = Wt; c.beginPath(); c.ellipse(K.nose[0] - 22, K.nose[1] + 12, 36, 26, 0, 0, TAU); c.fill(); c.restore();
208
+ c.strokeStyle = LINE; c.lineWidth = 2.4; c.stroke(K.head);
209
+ c.fillStyle = '#f2a8a0'; K.earInner.forEach(e => { c.beginPath(); e.forEach((p, i) => i ? c.lineTo(...p) : c.moveTo(...p)); c.fill(); });
210
+ c.strokeStyle = '#c8682a'; c.lineWidth = 6; K.stripes.slice(0, 3).forEach(s => { c.beginPath(); c.moveTo(...s[0]); c.lineTo(...s[1]); c.stroke(); });
211
+ K.eyes.forEach(e => { if (K.blink) { c.strokeStyle = LINE; c.lineWidth = 3; c.beginPath(); c.arc(e.x, e.y - 2, 8, 0.2, Math.PI - 0.2); c.stroke(); }
212
+ else { c.fillStyle = '#2a1a12'; c.beginPath(); c.ellipse(e.x, e.y, 6, 8, 0, 0, TAU); c.fill(); c.fillStyle = '#fff'; c.beginPath(); c.arc(e.x - 2, e.y - 3, 2.4, 0, TAU); c.fill(); } });
213
+ c.fillStyle = '#d8746a'; c.beginPath(); c.arc(K.nose[0], K.nose[1], 5, 0, TAU); c.fill();
214
+ c.strokeStyle = LINE; c.lineWidth = 2; c.beginPath(); c.moveTo(...K.mouth[0]); c.quadraticCurveTo(...K.mouth[1], ...K.mouth[2]); c.stroke();
215
+ c.lineWidth = 1.4; K.whiskers.forEach(w => { c.beginPath(); c.moveTo(...w[0]); c.lineTo(...w[1]); c.stroke(); });
216
+ c.restore();
217
+ }
218
+
219
+ // 角色用的透明色晕层(multiply 叠在角色上,做出水彩填色的深浅不匀)
220
+ const charBloom = () => P.cached('gh_charBloom', W, H, (g) => { const r = rng(808); for (let i = 0; i < 40; i++) { const x = 380 + r() * 1120, y = 280 + r() * 660; wash(g, ellipsePts(x, y, 30 + r() * 70, 24 + r() * 50, 9), ['#e8b890', '#a8c0d8', '#f0d0a0', '#c8a8c0'][i % 4], { layers: 2, alpha: 0.1, amp: 16, seed: 900 + i, edge: 0.08 }); } });
221
+ return {
222
+ draw(c, lt, t) {
223
+ const ch = P.choreo(lt, t);
224
+ c.drawImage(bg(), 0, 0);
225
+ // 窗外:云飘、树摇、草摆(都在窗洞里)
226
+ c.save(); c.beginPath(); c.rect(...WIN); c.clip();
227
+ c.drawImage(cloud('a', 380, 230, 11), 300 + t * 22, 150); c.drawImage(cloud('b', 260, 160, 23), 590 + t * 30, 210);
228
+ c.save(); c.translate(700, 540); c.rotate(Math.sin(t * 2.4) * 0.025); c.drawImage(tree(), -150, -360); c.restore();
229
+ c.restore();
230
+ grass(c, t);
231
+ // 窗框中梃压在外景上(从底版里再取一次窗框条,保证树和云在框后)
232
+ c.save(); c.beginPath(); [[575, 140, 10, 400], [370, 330, 420, 9]].forEach(r => c.rect(...r)); c.clip(); c.drawImage(bg(), 0, 0); c.restore();
233
+ komorebi(c, t);
234
+ curtain(c, -1, lt); curtain(c, 1, lt);
235
+ tablecloth(c, lt);
236
+ daisies(c, t);
237
+ // 角色先画进离屏,再把水彩颗粒+透明色晕按角色剪影 multiply 上去:赛璐璐平涂变成「水彩填色」
238
+ const L = P.scratch('ghChars'), cl = L.getContext('2d'); cl.reset(); cl.clearRect(0, 0, W, H);
239
+ const K = RIG.cat({ tail: ch.tail, blink: ch.blink, breathe: ch.breathe });
240
+ cat(cl, K);
241
+ const G = RIG.girl({ cup: ch.cup, sip: ch.sip, breathe: ch.breathe, hair: 'long' });
242
+ girl(cl, G, ch, lt, t);
243
+ c.drawImage(L, 0, 0);
244
+ // 水彩肌理只「乘」在角色上:纹理层 destination-in 角色剪影 → multiply 叠回(source-atop 会把纸色盖上去,人物整体发白,第一版踩到)
245
+ P.textureInside(c, L, mg => { mg.globalAlpha = 0.8; mg.drawImage(P.texture('gh_gran', '#f4efe2', { scale: 0.06, amt: 18, grain: 26, seed: 9 }), 0, 0); mg.globalAlpha = 1; mg.drawImage(charBloom(), 0, 0); }, { key: 'ghCharTex' });
246
+ P.steam(c, t, G.cup.x, G.cup.y - 8, { h: 60, n: 2, color: 'rgba(255,255,255,.75)', width: 3.5, spread: 12, wobble: 8 });
247
+ // 柔光:窗口方向一层暖色 screen 光晕
248
+ c.save(); c.globalCompositeOperation = 'screen'; const lg = c.createRadialGradient(580, 340, 60, 580, 340, 900); lg.addColorStop(0, 'rgba(255,240,200,.28)'); lg.addColorStop(1, 'rgba(255,240,200,0)'); c.fillStyle = lg; c.fillRect(0, 0, W, H); c.restore();
249
+ },
250
+ };
251
+ })();
@@ -0,0 +1,191 @@
1
+ // 2011 蒸汽波 / 赛博霓虹——纯代码。
2
+ // 管线:①先把整幅画进离屏 S:深紫渐变墙+洋红透视网格地面(滚动)+窗里落日(横条切口上移)与青色网格、棕榈剪影摇
3
+ // +自绘灯管字「カフェ」霓虹招牌(按帧哈希闪)+Win95 对话框 TEA.EXE 进度条+大理石胸像 +角色(深色平涂+粉/青双色轮廓辉光)
4
+ // → ②VHS 后期:RGB 三通道分离错位(multiply 取单通道 → lighter 合成)+跟踪噪声带下滚(带内横向撕裂)+扫描线 + OSD(PLAY ▶、时间码)
5
+ SCENES['26_vaporwave'] = (() => {
6
+ const W = 1920, H = 1080, { clamp, lerp, ease, rng } = U, P = PAINT, TAU = Math.PI * 2;
7
+ const FLOOR = 720;
8
+ const C = { pink: '#ff4fd8', hot: '#ff2f8f', cyan: '#3ff6ff', purple: '#2a0b4a', deep: '#12052a', violet: '#7a2ae0', yellow: '#ffd84a', orange: '#ff8a3a' };
9
+ const glowLine = P.glowStroke; // 霓虹灯管:shadowBlur 辉光+近白芯线
10
+
11
+ // ---------- 静态底版:墙、窗框灯管、胸像底座 ----------
12
+ const bg = () => P.cached('vw_bg', W, H, (g) => {
13
+ const wg = g.createLinearGradient(0, 0, 0, FLOOR); wg.addColorStop(0, '#0d0322'); wg.addColorStop(0.7, '#2c0b52'); wg.addColorStop(1, '#4a0f6a'); g.fillStyle = wg; g.fillRect(0, 0, W, FLOOR);
14
+ // 墙上淡淡的竖向渐变色带(粉→青),像霓虹打在墙上
15
+ const bl = g.createRadialGradient(580, 340, 60, 580, 340, 760); bl.addColorStop(0, 'rgba(255,79,216,.35)'); bl.addColorStop(1, 'rgba(255,79,216,0)'); g.fillStyle = bl; g.fillRect(0, 0, W, FLOOR);
16
+ const br = g.createRadialGradient(1000, 220, 20, 1000, 220, 520); br.addColorStop(0, 'rgba(63,246,255,.22)'); br.addColorStop(1, 'rgba(63,246,255,0)'); g.fillStyle = br; g.fillRect(0, 0, W, FLOOR);
17
+ g.fillStyle = '#08020f'; g.fillRect(0, FLOOR, W, H - FLOOR);
18
+ // 墙脚灯带
19
+ g.beginPath(); g.moveTo(0, FLOOR); g.lineTo(W, FLOOR); glowLine(g, C.cyan, 4, 18);
20
+ // 椅子:黑色亚克力+粉色边灯
21
+ g.fillStyle = '#1a0830'; g.fillRect(1436, 470, 18, 440); g.fillRect(1474, 478, 18, 430); g.fillRect(1290, 744, 210, 16);
22
+ g.beginPath(); g.rect(1436, 470, 18, 440); g.rect(1474, 478, 18, 430); glowLine(g, C.pink, 2, 10);
23
+ });
24
+
25
+ // ---------- 窗里的落日 ----------
26
+ function sunset(c, t) {
27
+ c.save(); c.beginPath(); c.rect(370, 140, 420, 400); c.clip();
28
+ const sk = c.createLinearGradient(0, 140, 0, 470); sk.addColorStop(0, '#1a0640'); sk.addColorStop(0.55, '#a0207a'); sk.addColorStop(1, '#ff7a5a'); c.fillStyle = sk; c.fillRect(370, 140, 420, 330);
29
+ // 太阳:黄→洋红渐变,横条切口随时间上移(越往下切口越宽)
30
+ const sx = 580, sy = 400, sr = 118;
31
+ c.save(); c.beginPath(); c.arc(sx, sy, sr, 0, TAU); c.clip();
32
+ const sg = c.createLinearGradient(0, sy - sr, 0, sy + sr); sg.addColorStop(0, C.yellow); sg.addColorStop(0.5, C.orange); sg.addColorStop(1, C.hot); c.fillStyle = sg; c.fillRect(sx - sr, sy - sr, sr * 2, sr * 2);
33
+ c.globalCompositeOperation = 'destination-out';
34
+ const ph = (t * 0.9) % 1;
35
+ for (let k = 0; k < 7; k++) { const q = (k + ph) / 7, y = sy + sr * (q * 1.1 - 0.05), h = 2 + q * q * 16; c.fillRect(sx - sr, y, sr * 2, h); }
36
+ c.restore();
37
+ // 地平线上的线框山
38
+ c.beginPath(); c.moveTo(370, 470); [[420, 430], [470, 452], [520, 410], [560, 460], [640, 420], [700, 448], [760, 418], [790, 440]].forEach(p => c.lineTo(...p)); c.lineTo(790, 470);
39
+ c.fillStyle = '#1a0636'; c.fill(); glowLine(c, C.pink, 2.5, 10);
40
+ // 地面网格(青)往观众方向滚动
41
+ c.fillStyle = '#0b0220'; c.fillRect(370, 470, 420, 70);
42
+ c.save(); c.beginPath(); c.rect(370, 470, 420, 70); c.clip(); c.strokeStyle = C.cyan; c.lineWidth = 1.6; c.shadowColor = C.cyan; c.shadowBlur = 8;
43
+ for (let i = -10; i <= 10; i++) { c.beginPath(); c.moveTo(580 + i * 12, 470); c.lineTo(580 + i * 70, 540); c.stroke(); }
44
+ const sc = (t * 1.6) % 1; for (let k = 0; k < 8; k++) { const d = k + 1 - sc, y = 470 + 70 * (1 / (1 + 6 / (d * d + 0.01))) ; c.beginPath(); c.moveTo(370, y); c.lineTo(790, y); c.stroke(); }
45
+ c.restore();
46
+ // 棕榈剪影(左右各一,摇)
47
+ [[400, 540, 1], [770, 540, -1]].forEach(([x, y, s], k) => {
48
+ const sw = Math.sin(t * 2.2 + k * 1.4) * 0.06;
49
+ c.save(); c.translate(x, y); c.rotate(sw * s); c.fillStyle = '#0a0216'; c.strokeStyle = '#0a0216';
50
+ c.lineWidth = 10; c.lineCap = 'round'; c.beginPath(); c.moveTo(0, 0); c.quadraticCurveTo(s * 18, -120, s * 6, -230); c.stroke();
51
+ for (let f = 0; f < 7; f++) { const a = -Math.PI / 2 + (f - 3) * 0.45 + Math.sin(t * 3 + f) * 0.05, L = 70 + (f % 3) * 16; c.save(); c.translate(s * 6, -230); c.rotate(a); c.beginPath(); c.moveTo(0, 0); c.quadraticCurveTo(L * 0.5, -14, L, 12); c.quadraticCurveTo(L * 0.5, 4, 0, 4); c.fill(); c.restore(); }
52
+ c.restore(); });
53
+ c.restore();
54
+ // 窗框:青色灯管
55
+ c.beginPath(); c.rect(360, 130, 440, 420); glowLine(c, C.cyan, 6, 26); c.beginPath(); c.rect(360, 130, 440, 420); c.strokeStyle = '#e8ffff'; c.lineWidth = 2; c.stroke();
56
+ c.fillStyle = '#1a0830'; c.fillRect(330, 550, 500, 22); c.beginPath(); c.moveTo(330, 550); c.lineTo(830, 550); glowLine(c, C.pink, 3, 14);
57
+ }
58
+
59
+ // ---------- 地面:洋红透视网格(滚动) ----------
60
+ function floorGrid(c, t) {
61
+ c.save(); c.beginPath(); c.rect(0, FLOOR, W, H - FLOOR); c.clip();
62
+ const VX = 960, VY = 600; c.strokeStyle = C.pink; c.shadowColor = C.pink; c.shadowBlur = 12; c.lineWidth = 2.5;
63
+ for (let i = -16; i <= 16; i++) { c.beginPath(); c.moveTo(VX + i * 160 * (FLOOR - VY) / (H - VY), FLOOR); c.lineTo(VX + i * 160, H); c.stroke(); }
64
+ const ph = (t * 1.3) % 1;
65
+ for (let k = 0; k < 14; k++) { const d = k + 1 - ph, y = VY + 520 / d; if (y < FLOOR || y > H + 4) continue; c.lineWidth = 1.2 + 2.4 * (y - FLOOR) / (H - FLOOR); c.beginPath(); c.moveTo(0, y); c.lineTo(W, y); c.stroke(); }
66
+ c.restore();
67
+ }
68
+
69
+ // ---------- 霓虹灯管字「カフェ」(自绘折线,不依赖字体) ----------
70
+ const KANA = {
71
+ 'カ': [[[0.12, 0.34], [0.86, 0.34], [0.84, 0.62], [0.74, 0.94], [0.6, 0.86]], [[0.46, 0.08], [0.42, 0.5], [0.3, 0.78], [0.12, 0.96]]],
72
+ 'フ': [[[0.12, 0.24], [0.86, 0.24], [0.8, 0.56], [0.62, 0.82], [0.34, 0.96]]],
73
+ 'ェ': [[[0.28, 0.46], [0.72, 0.46]], [[0.5, 0.46], [0.5, 0.86]], [[0.18, 0.86], [0.82, 0.86]]],
74
+ };
75
+ function neonSign(c, t) {
76
+ const f = Math.floor(t * 30), on = (k) => { const h = U.hash(f, k); return !(h < 0.07 || (k === 1 && h < 0.22 && (f % 17) < 5)); };
77
+ const x0 = 868, y0 = 150, s = 104;
78
+ // 灯管底板
79
+ c.fillStyle = 'rgba(10,2,20,.55)'; c.fillRect(x0 - 18, y0 - 18, s * 3 + 24, s + 70);
80
+ [...'カフェ'].forEach((ch, k) => {
81
+ const lit = on(k), col = k === 1 ? C.cyan : C.pink;
82
+ KANA[ch].forEach(st => { c.beginPath(); st.forEach(([u, v], i) => { const x = x0 + k * s + u * (s - 14), y = y0 + v * s; i ? c.lineTo(x, y) : c.moveTo(x, y); });
83
+ c.lineJoin = 'round'; c.lineCap = 'round';
84
+ if (lit) { glowLine(c, col, 9, 30); c.strokeStyle = '#fff4fd'; c.lineWidth = 3; c.stroke(); } else { c.strokeStyle = 'rgba(120,60,120,.6)'; c.lineWidth = 6; c.stroke(); } });
85
+ });
86
+ // 小字 TEA ROOM(字体霓虹)
87
+ c.save(); c.font = '34px "Righteous-400"'; c.letterSpacing = '10px'; c.textBaseline = 'alphabetic';
88
+ c.shadowColor = C.yellow; c.shadowBlur = on(5) ? 18 : 0; c.fillStyle = on(5) ? '#fff2b0' : 'rgba(140,110,60,.6)'; c.fillText('TEA ROOM', x0 + 34, y0 + s + 44); c.restore();
89
+ }
90
+
91
+ // ---------- Win95 对话框 TEA.EXE ----------
92
+ function dialog(c, lt) {
93
+ const x = 26, y = 330, w = 300, h = 168;
94
+ c.save(); c.fillStyle = '#c0c0c0'; c.fillRect(x, y, w, h);
95
+ c.fillStyle = '#ffffff'; c.fillRect(x, y, w, 3); c.fillRect(x, y, 3, h); c.fillStyle = '#404040'; c.fillRect(x, y + h - 3, w, 3); c.fillRect(x + w - 3, y, 3, h);
96
+ const tg = c.createLinearGradient(x, 0, x + w, 0); tg.addColorStop(0, '#000080'); tg.addColorStop(1, '#1084d0'); c.fillStyle = tg; c.fillRect(x + 6, y + 6, w - 12, 30);
97
+ c.font = '18px "Poppins-700"'; c.fillStyle = '#fff'; c.textBaseline = 'middle'; c.fillText('TEA.EXE', x + 14, y + 22);
98
+ c.fillStyle = '#c0c0c0'; c.fillRect(x + w - 32, y + 10, 22, 20); c.fillStyle = '#000'; c.font = '16px "Poppins-700"'; c.fillText('×', x + w - 26, y + 20);
99
+ c.font = '17px "Poppins-600"'; c.fillStyle = '#000'; c.fillText('Brewing tea... ' + Math.min(99, Math.floor(18 + lt * 70)) + '%', x + 16, y + 64);
100
+ c.fillStyle = '#fff'; c.fillRect(x + 16, y + 86, w - 32, 26); c.fillStyle = '#808080'; c.fillRect(x + 16, y + 86, w - 32, 2);
101
+ const n = Math.min(17, Math.floor(3 + lt * 14)); c.fillStyle = '#000080'; for (let i = 0; i < n; i++) c.fillRect(x + 20 + i * 15.5, y + 90, 12, 18);
102
+ c.fillStyle = '#c0c0c0'; c.fillRect(x + w / 2 - 44, y + 124, 88, 30); c.fillStyle = '#fff'; c.fillRect(x + w / 2 - 44, y + 124, 88, 2); c.fillStyle = '#404040'; c.fillRect(x + w / 2 - 44, y + 152, 88, 2);
103
+ c.fillStyle = '#000'; c.font = '16px "Poppins-600"'; c.fillText('OK', x + w / 2 - 12, y + 140);
104
+ c.restore();
105
+ }
106
+
107
+ // ---------- 桌+大理石胸像 ----------
108
+ function table(c, t) {
109
+ c.fillStyle = '#0e0420'; c.fillRect(810, 618, 400, 28); c.fillRect(842, 646, 20, 259); c.fillRect(1160, 646, 20, 259);
110
+ c.beginPath(); c.moveTo(810, 618); c.lineTo(1210, 618); glowLine(c, C.cyan, 3, 16);
111
+ c.beginPath(); c.moveTo(810, 646); c.lineTo(1210, 646); glowLine(c, C.pink, 2, 10);
112
+ // 胸像(朝右的侧脸剪影+大理石渐变+粉青轮廓光)
113
+ const bust = new Path2D(); const bx = 900, by = 618;
114
+ [[-48, 0], [-50, -22], [-30, -38], [-18, -44], [-16, -62], [-24, -76], [-26, -100], [-18, -122], [0, -132], [20, -128], [30, -112], [36, -100], [44, -92], [38, -86], [42, -78], [36, -72], [36, -62], [24, -58], [20, -46], [34, -38], [52, -22], [50, 0]].forEach(([x, y], i) => i ? bust.lineTo(bx + x, by + y) : bust.moveTo(bx + x, by + y)); bust.closePath();
115
+ const mg = c.createLinearGradient(bx - 50, by - 130, bx + 50, by); mg.addColorStop(0, '#f6eefa'); mg.addColorStop(0.6, '#c9b8d8'); mg.addColorStop(1, '#8a6aa8'); c.fillStyle = mg; c.fill(bust);
116
+ c.save(); c.clip(bust); c.strokeStyle = 'rgba(140,110,160,.5)'; c.lineWidth = 1.2; [[[-40, -10], [-10, -40], [10, -70]], [[20, -20], [30, -50]], [[-20, -90], [0, -110]]].forEach(v => { c.beginPath(); v.forEach(([x, y], i) => i ? c.lineTo(bx + x, by + y) : c.moveTo(bx + x, by + y)); c.stroke(); }); c.restore();
117
+ c.strokeStyle = 'rgba(255,79,216,.9)'; c.lineWidth = 2.5; c.shadowColor = C.pink; c.shadowBlur = 14; c.stroke(bust); c.shadowBlur = 0;
118
+ c.fillStyle = '#5a3a7a'; c.beginPath(); c.arc(bx + 22, by - 98, 3, 0, TAU); c.fill();
119
+ // 胸像戴的复古太阳镜(梗)
120
+ c.fillStyle = '#111'; c.fillRect(bx + 8, by - 104, 34, 9); c.fillStyle = C.cyan; c.fillRect(bx + 12, by - 102, 26, 2);
121
+ }
122
+
123
+ // ---------- 角色:深色平涂 → 双色轮廓辉光 ----------
124
+ function girl(c, G, ch, t) {
125
+ const pal = { skin: '#f4c4d8', skinS: '#b8789e', hair: '#ffe08a', hairS: '#d89a5a', top: '#8f7cf6', topS: '#5a44c8', skirt: '#4fd0e0', skirtS: '#2a7a9a' };
126
+ c.save(); c.lineJoin = 'round'; c.lineCap = 'round';
127
+ const fill = (p, a, b, x0 = 1100, x1 = 1460) => { if (!p) return; const g = c.createLinearGradient(x0, 0, x1, 0); g.addColorStop(0, a); g.addColorStop(1, b); c.fillStyle = g; c.fill(p); };
128
+ fill(G.farSleeve, pal.topS, pal.topS); fill(G.farHand, pal.skinS, pal.skinS);
129
+ fill(G.skirt, pal.skirt, pal.skirtS);
130
+ c.save(); c.clip(G.skirt); c.strokeStyle = 'rgba(20,40,80,.35)'; c.lineWidth = 3; for (let x = 1100; x < 1460; x += 22) { c.beginPath(); c.moveTo(x, 640); c.lineTo(x - 30, 940); c.stroke(); } c.restore(); // 百褶
131
+ fill(G.shoe, '#fff', '#c8c8ff');
132
+ fill(G.torso, pal.top, pal.topS, 1290, 1420);
133
+ fill(G.neck, pal.skin, pal.skinS, 1286, 1324);
134
+ { const nk = G.A.neck; c.fillStyle = '#ffffff'; c.beginPath(); c.moveTo(nk[0] - 22, nk[1] - 4); c.lineTo(nk[0] + 26, nk[1]); c.lineTo(nk[0] + 4, nk[1] + 34); c.closePath(); c.fill(); c.fillStyle = C.cyan; c.fillRect(nk[0] - 4, nk[1] + 40, 6, 120); } // 白领口+青色拉链线
135
+ fill(G.hairBack, pal.hair, pal.hairS, 1260, 1410); fill(G.bun, pal.hair, pal.hairS);
136
+ // 发圈(粉)
137
+ c.strokeStyle = C.hot; c.lineWidth = 8; c.beginPath(); c.arc(G.bunSpiral[0] - 18, G.bunSpiral[1] + 6, 14, -1.2, 1.6); c.stroke();
138
+ fill(G.face, pal.skin, pal.skinS, 1250, 1330); fill(G.bangs, pal.hair, pal.hairS, 1250, 1335);
139
+ c.strokeStyle = 'rgba(200,120,60,.6)'; c.lineWidth = 2; G.hairLines.forEach(h => c.stroke(h));
140
+ if (ch.blink) { c.strokeStyle = '#2a0a3a'; c.lineWidth = 2.6; c.stroke(G.lid); }
141
+ else { c.fillStyle = '#2a0a3a'; c.beginPath(); c.ellipse(G.eye.x - 1, G.eye.y + 1, 4, 5.5, 0, 0, TAU); c.fill(); c.fillStyle = C.cyan; c.beginPath(); c.arc(G.eye.x - 2, G.eye.y - 1, 1.6, 0, TAU); c.fill(); c.strokeStyle = '#2a0a3a'; c.lineWidth = 2.4; c.stroke(G.lid); }
142
+ c.fillStyle = C.hot; c.beginPath(); c.moveTo(...G.lips[0]); c.lineTo(...G.lips[1]); c.lineTo(...G.lips[2]); c.closePath(); c.fill();
143
+ fill(G.upperArm, pal.top, pal.topS, 1200, 1380); fill(G.foreArm, pal.top, pal.topS, 1200, 1380); fill(G.cuff, '#fff', '#d8c8ff', 1200, 1300); fill(G.hand, pal.skin, pal.skinS, 1180, 1260);
144
+ RIG.drawCup(c, G.cup, { body: '#1a0830', rim: '#ff9ad6', hw: 6 });
145
+ c.save(); c.translate(G.cup.x, G.cup.y); c.rotate(G.cup.tilt); c.beginPath(); c.moveTo(-G.cup.w / 2, 0); c.lineTo(-G.cup.w * 0.42, G.cup.h); c.lineTo(G.cup.w * 0.42, G.cup.h); c.lineTo(G.cup.w / 2, 0); glowLine(c, C.cyan, 2, 10); c.restore();
146
+ c.fillStyle = pal.skin; c.beginPath(); c.arc(G.thumb[0], G.thumb[1], 7, 0, TAU); c.fill();
147
+ // 轮廓辉光:朝窗(左)的一侧粉、背面青——同一条路径描两次,用 clip 半屏分色
148
+ const outline = [G.skirt, G.torso, G.face, G.hairBack, G.bun, G.upperArm, G.foreArm];
149
+ [[C.pink, 0, 1290], [C.cyan, 1290, W]].forEach(([col, a, b]) => { c.save(); c.beginPath(); c.rect(a, 0, b - a, H); c.clip(); c.shadowColor = col; c.shadowBlur = 16; c.strokeStyle = col; c.lineWidth = 3; outline.forEach(p => p && c.stroke(p)); c.restore(); });
150
+ c.restore();
151
+ }
152
+ function cat(c, K) {
153
+ c.save(); c.lineCap = 'round'; c.lineJoin = 'round';
154
+ c.strokeStyle = '#ff9a4a'; c.lineWidth = K.tailW; c.stroke(K.tail);
155
+ const tip = K.tailPts[K.tailPts.length - 1]; c.fillStyle = '#fff0fa'; c.beginPath(); c.arc(tip[0], tip[1], K.tailW / 2, 0, TAU); c.fill();
156
+ const og = c.createLinearGradient(420, 0, 660, 0); og.addColorStop(0, '#ffb070'); og.addColorStop(1, '#c0502a'); c.fillStyle = og; c.fill(K.body);
157
+ K.legs.forEach(l => { c.fillStyle = '#fff0fa'; c.fill(l); }); c.fillStyle = '#fff0fa'; c.fill(K.white);
158
+ c.fillStyle = og; c.fill(K.head);
159
+ c.save(); c.clip(K.head); c.fillStyle = '#fff0fa'; c.beginPath(); c.ellipse(K.nose[0] - 22, K.nose[1] + 12, 36, 26, 0, 0, TAU); c.fill(); c.restore();
160
+ c.strokeStyle = '#a03a1a'; c.lineWidth = 7; K.stripes.forEach(s => { c.beginPath(); c.moveTo(...s[0]); c.lineTo(...s[1]); c.stroke(); });
161
+ c.fillStyle = '#ff9ad6'; K.earInner.forEach(e => { c.beginPath(); e.forEach((p, i) => i ? c.lineTo(...p) : c.moveTo(...p)); c.fill(); });
162
+ K.eyes.forEach(e => { if (K.blink) { c.strokeStyle = '#2a0a3a'; c.lineWidth = 3; c.beginPath(); c.moveTo(e.x - 8, e.y); c.lineTo(e.x + 8, e.y); c.stroke(); }
163
+ else { c.shadowColor = C.cyan; c.shadowBlur = 10; c.fillStyle = C.cyan; c.beginPath(); c.arc(e.x, e.y, 8, 0, TAU); c.fill(); c.shadowBlur = 0; c.fillStyle = '#12052a'; c.beginPath(); c.ellipse(e.x + 2, e.y, 2.4, 6.5, 0, 0, TAU); c.fill(); } });
164
+ c.fillStyle = C.hot; c.beginPath(); c.arc(K.nose[0], K.nose[1], 5, 0, TAU); c.fill();
165
+ c.strokeStyle = '#ffe8ff'; c.lineWidth = 1.4; K.whiskers.forEach(w => { c.beginPath(); c.moveTo(...w[0]); c.lineTo(...w[1]); c.stroke(); });
166
+ [[C.pink, 0, 560], [C.cyan, 560, 900]].forEach(([col, a, b]) => { c.save(); c.beginPath(); c.rect(a, 0, b - a, H); c.clip(); c.shadowColor = col; c.shadowBlur = 14; c.strokeStyle = col; c.lineWidth = 3; [K.body, K.head].forEach(p => c.stroke(p)); c.restore(); });
167
+ c.restore();
168
+ }
169
+
170
+ // ---------- ② VHS 后期:P.vhs(RGB 通道分离+跟踪噪声带撕裂+扫描线+OSD+暗角) ----------
171
+ const vhs = (c, S, t, lt) => P.vhs(c, S, t, lt, { osd: { label: 'PLAY', date: 'SEP. 04 2011', clock: '23:59' } });
172
+
173
+ return {
174
+ draw(c, lt, t) {
175
+ const ch = P.choreo(lt, t);
176
+ const S = P.scratch('vwS'), g = S.getContext('2d'); g.reset();
177
+ g.drawImage(bg(), 0, 0);
178
+ floorGrid(g, t);
179
+ sunset(g, t);
180
+ neonSign(g, t);
181
+ dialog(g, lt);
182
+ table(g, t);
183
+ const K = RIG.cat({ tail: ch.tail, blink: ch.blink, breathe: ch.breathe });
184
+ cat(g, K);
185
+ const G = RIG.girl({ cup: ch.cup, sip: ch.sip, breathe: ch.breathe });
186
+ girl(g, G, ch, t);
187
+ P.steam(g, t, G.cup.x, G.cup.y - 8, { h: 60, n: 2, color: 'rgba(63,246,255,.85)', width: 3, spread: 12, wobble: 8 });
188
+ vhs(c, S, t, lt);
189
+ },
190
+ };
191
+ })();