@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,234 @@
1
+ // 02_egypt · 古埃及墓室壁画(约公元前 1350 年,新王国)—— 横向「分栏壁画」世界
2
+ // 世界=墓室墙上的三层分栏(register):顶上 kheker 饰带+彩块边;上栏是美杜姆群鹅、有翼日盘、纸莎草丛里惊飞的水鸟(内巴蒙猎禽图的母题)和象形文字栏;
3
+ // 540 处一道彩块分栏线(地平线);中栏是他走的这一层(供桌、尖底罐、蓝莲花);760 处彩块地线;下栏是尼罗河之字形水纹、游鱼、蓝莲。
4
+ // 画法沿用 scenes/02_egypt.js:灰泥墙底+平涂色块+深色勾线+四色彩块边框+象形字库+整幅 multiply 壁画表面(斑驳、发丝裂纹、颗粒)。
5
+ // 活:水纹流动、鱼游、水鸟扑翅、群鹅点头啄食、纸莎草摇、日盘脉动。
6
+ // 互动:圣甲虫推着太阳球从前面滚来,他埃及舞者式跳起让开,球和圣甲虫从他脚下滚过去、一路滚出画外;他回头看、得意地叉腰。
7
+ // 圣甲虫推着球走开,帽子保持纯白,不累积纪念品
8
+ if (!window.XJ) { const x = new XMLHttpRequest(); x.open('GET', 'demos/long_scroll/lib/xing2_jia.js', false); x.send(); (0, eval)(x.responseText + '\n//# sourceURL=demos/long_scroll/lib/xing2_jia.js'); }
9
+ (() => {
10
+ const { clamp, lerp, rng, ss } = U, P = PAINT, TAU = Math.PI * 2, H = 1080, W = 1920;
11
+ const w = 2100, OX = 160, WW = w + 2 * OX, G = WORLD.GROUND, REG = 540;
12
+ const WALK = { st: [49.0, 23.6, -1.4, -53.7, 51.4, 27.0, -22.6, -55.4], fps: 12.6 }; // 支撑脚 x(身高300)与步速330时的帧率,从走路帧逐帧量出
13
+ const K = { walk: 'egypt_walk8', act: 'egypt_dodge' };
14
+ const AT = 1000, DUR = 1.6;
15
+ const AX = AT + WORLD.V * 0.11; // 他互动时实际站的位置(XJ.glide 缓停滑过的那一小段之后)
16
+ const T_HIT = 0.6, V_SC = 650; // 互动内秒:球滚到他脚下;圣甲虫速度(px/s,与步速无关)。加快甲虫并拉长腾空时间,让整只甲虫在角色落地前通过
17
+ const C = { wall: [234, 220, 184], wall2: [216, 197, 151], line: '#2a1810', rule: '#9a2b22', red: '#b8322a', blue: '#2a58a8', green: '#2e8a55', yellow: '#e2b13a', black: '#231a14',
18
+ gold: '#e0ab38', cream: '#f2ead6', white: '#f6f2e8', terra: '#d4936a', lapis: '#2c56b0', turq: '#3fa6a0', water: '#2f5fa8', papy: '#3f8a4a', papyL: '#7ab45a' };
19
+ const BAND = [C.red, C.blue, C.yellow, C.green];
20
+ const poly = (g, pts, close = true) => { g.beginPath(); pts.forEach((p, i) => i ? g.lineTo(p[0], p[1]) : g.moveTo(p[0], p[1])); if (close) g.closePath(); };
21
+ const fs = (g, fill, stroke, lw = 2.5) => { if (fill) { g.fillStyle = fill; g.fill(); } if (stroke) { g.strokeStyle = stroke; g.lineWidth = lw; g.stroke(); } };
22
+
23
+ // ---------- 象形文字(字形取自 scenes/02_egypt.js) ----------
24
+ const GL = {
25
+ ankh: { h: 60, cols: [C.blue, C.green, C.black, C.red], d(g) { g.lineWidth = 3.6; g.beginPath(); g.ellipse(0, -17, 8, 11, 0, 0, 7); g.moveTo(-16, -3); g.lineTo(16, -3); g.moveTo(0, -5); g.lineTo(0, 29); g.stroke(); } },
26
+ sun: { h: 40, cols: [C.black, C.blue, C.red], d(g) { g.lineWidth = 3; g.beginPath(); g.arc(0, 0, 15, 0, 7); g.stroke(); g.beginPath(); g.arc(0, 0, 4, 0, 7); g.fill(); } },
27
+ bread: { h: 26, cols: [C.red, C.blue, C.green], d(g) { g.beginPath(); g.arc(0, 9, 19, Math.PI, 0); g.closePath(); g.stroke(); g.beginPath(); g.moveTo(-12, 4); g.lineTo(12, 4); g.stroke(); } },
28
+ reed: { h: 62, cols: [C.black, C.green, C.red], d(g) { g.beginPath(); g.moveTo(-2, 29); g.quadraticCurveTo(-11, 0, 1, -29); g.quadraticCurveTo(7, -2, 4, 29); g.stroke(); g.beginPath(); g.moveTo(1, -29); g.quadraticCurveTo(9, -31, 10, -24); g.stroke(); } },
29
+ owl: { h: 60, cols: [C.black, C.blue], d(g) { g.beginPath(); g.ellipse(3, 6, 12, 19, 0.1, 0, 7); g.stroke(); g.beginPath(); g.arc(-2, -18, 10, 0, 7); g.stroke(); g.beginPath(); g.arc(-6, -19, 2.4, 0, 7); g.arc(2, -19, 2.4, 0, 7); g.fill(); g.beginPath(); g.moveTo(-2, -14); g.lineTo(-3, -9); g.moveTo(9, 22); g.lineTo(18, 29); g.moveTo(-3, 24); g.lineTo(-5, 30); g.moveTo(4, 24); g.lineTo(3, 30); g.stroke(); } },
30
+ falcon: { h: 60, cols: [C.black, C.red, C.blue], d(g) { g.beginPath(); g.arc(-6, -20, 7, 0, 7); g.fill(); poly(g, [[-12, -21], [-19, -16], [-11, -15]]); g.fill(); g.beginPath(); g.ellipse(2, 1, 10, 20, -0.35, 0, 7); g.stroke(); poly(g, [[8, 16], [20, 30], [6, 27]]); g.fill(); g.beginPath(); g.moveTo(-3, 19); g.lineTo(-5, 30); g.moveTo(2, 19); g.lineTo(1, 30); g.moveTo(-1, -8); g.quadraticCurveTo(10, 0, 12, 14); g.stroke(); } },
31
+ eye: { h: 36, cols: [C.green, C.black, C.blue], d(g) { g.beginPath(); g.moveTo(-18, 0); g.quadraticCurveTo(0, -12, 18, 0); g.quadraticCurveTo(0, 9, -18, 0); g.stroke(); g.beginPath(); g.arc(0, -1, 4.5, 0, 7); g.fill(); g.beginPath(); g.moveTo(-18, -12); g.quadraticCurveTo(0, -20, 20, -11); g.moveTo(-4, 6); g.lineTo(-6, 16); g.moveTo(6, 5); g.quadraticCurveTo(14, 18, 4, 16); g.stroke(); } },
32
+ cartouche: { h: 74, cols: [C.black, C.red], d(g) { g.beginPath(); g.ellipse(0, -2, 15, 31, 0, 0, 7); g.stroke(); g.beginPath(); g.moveTo(-14, 33); g.lineTo(14, 33); g.stroke(); g.lineWidth = 2; g.beginPath(); g.arc(0, -18, 5, 0, 7); g.moveTo(-7, -2); g.lineTo(7, -2); g.moveTo(-6, 8); g.lineTo(-3, 13); g.lineTo(0, 8); g.lineTo(3, 13); g.lineTo(6, 8); g.stroke(); } },
33
+ snake: { h: 30, cols: [C.green, C.black, C.red], d(g) { g.lineWidth = 3.2; g.beginPath(); g.moveTo(22, 8); g.bezierCurveTo(10, -4, 4, 14, -6, 6); g.bezierCurveTo(-14, 0, -16, -4, -20, -2); g.stroke(); g.beginPath(); g.moveTo(-20, -2); g.lineTo(-23, -9); g.moveTo(-17, -3); g.lineTo(-15, -10); g.stroke(); } },
34
+ seated: { h: 58, cols: [C.red, C.black, C.blue], d(g) { g.beginPath(); g.arc(-2, -21, 6.5, 0, 7); g.fill(); poly(g, [[-6, -13], [4, -13], [6, 6], [16, 8], [17, 18], [-10, 18], [-10, 2]]); g.fill(); g.beginPath(); g.moveTo(-6, -8); g.lineTo(-17, -16); g.stroke(); g.beginPath(); g.moveTo(-14, 26); g.lineTo(18, 26); g.stroke(); } },
35
+ djed: { h: 62, cols: [C.blue, C.green], d(g) { g.beginPath(); g.moveTo(-6, 29); g.lineTo(-6, -10); g.moveTo(6, 29); g.lineTo(6, -10); for (let k = 0; k < 4; k++) { g.moveTo(-13, -12 - k * 5); g.lineTo(13, -12 - k * 5); } g.moveTo(-12, 29); g.lineTo(12, 29); g.stroke(); } },
36
+ jug: { h: 50, cols: [C.red, C.green, C.blue], d(g) { g.beginPath(); g.moveTo(-6, -22); g.lineTo(6, -22); g.lineTo(5, -14); g.quadraticCurveTo(16, -6, 12, 12); g.quadraticCurveTo(8, 22, 0, 22); g.quadraticCurveTo(-8, 22, -12, 12); g.quadraticCurveTo(-16, -6, -5, -14); g.closePath(); g.stroke(); g.beginPath(); g.moveTo(-10, 0); g.lineTo(10, 0); g.stroke(); } },
37
+ lotus: { h: 56, cols: [C.green, C.blue], d(g) { g.beginPath(); g.moveTo(0, 27); g.lineTo(0, -6); g.stroke(); poly(g, [[0, -6], [-12, -18], [-6, -26], [0, -16], [6, -26], [12, -18]]); g.stroke(); } },
38
+ nfr: { h: 56, cols: [C.black, C.red], d(g) { g.beginPath(); g.ellipse(0, 12, 10, 14, 0, 0, 7); g.moveTo(0, -2); g.lineTo(0, -26); g.moveTo(-6, -18); g.lineTo(6, -18); g.moveTo(-6, -12); g.lineTo(6, -12); g.stroke(); } },
39
+ water: { h: 30, cols: [C.blue], d(g) { g.lineWidth = 2.6; for (let r = -1; r <= 1; r++) { g.beginPath(); for (let i = 0; i <= 16; i++) { const x = -21 + i * 2.625, y = r * 9 + (i % 2 < 1 ? -3 : 3); i ? g.lineTo(x, y) : g.moveTo(x, y); } g.stroke(); } } },
40
+ feather: { h: 60, cols: [C.blue, C.green, C.black], d(g) { g.beginPath(); g.moveTo(-2, 29); g.quadraticCurveTo(-8, -10, 4, -29); g.quadraticCurveTo(12, -18, 6, 0); g.quadraticCurveTo(3, 15, 2, 29); g.stroke(); } },
41
+ };
42
+ const GN = Object.keys(GL);
43
+ const glyphCols = (g, xs, y0, y1, seed) => { const r = rng(seed); g.lineCap = 'round';
44
+ xs.forEach(x => { g.strokeStyle = C.rule; g.lineWidth = 2.6; g.beginPath(); g.moveTo(x, y0); g.lineTo(x, y1); g.stroke(); });
45
+ for (let k = 0; k < xs.length - 1; k++) { const cx = (xs[k] + xs[k + 1]) / 2, s = (xs[k + 1] - xs[k]) / 78; let y = y0 + 8, prev = '';
46
+ while (true) { let n; do { n = GN[(r() * GN.length) | 0]; } while (n === prev); prev = n; const gl = GL[n]; if (y + gl.h * s > y1) break;
47
+ g.save(); g.translate(cx, y + gl.h * s / 2); g.scale(s, s); const col = gl.cols[(r() * gl.cols.length) | 0]; g.strokeStyle = col; g.fillStyle = col; g.lineWidth = 3.1; g.lineJoin = 'round'; gl.d(g); g.restore(); y += gl.h * s + 7; } } };
48
+ // 彩块边(水平/竖直),块间黑缝
49
+ function blocks(g, x0, y0, x1, y1, len, off = 0) {
50
+ const hor = (x1 - x0) > (y1 - y0), L = hor ? x1 - x0 : y1 - y0;
51
+ g.fillStyle = C.cream; g.fillRect(x0, y0, x1 - x0, y1 - y0);
52
+ for (let s = 0, k = off; s < L; s += len, k++) { g.fillStyle = BAND[k % 4];
53
+ if (hor) g.fillRect(x0 + s + 3, y0 + 3, Math.min(len - 6, L - s - 3), y1 - y0 - 6); else g.fillRect(x0 + 3, y0 + s + 3, x1 - x0 - 6, Math.min(len - 6, L - s - 3));
54
+ g.fillStyle = C.black; if (hor) g.fillRect(x0 + s, y0, 2, y1 - y0); else g.fillRect(x0, y0 + s, x1 - x0, 2); }
55
+ g.strokeStyle = C.black; g.lineWidth = 2; g.strokeRect(x0, y0, x1 - x0, y1 - y0);
56
+ }
57
+ function jar(g, cx, y0, s) {
58
+ g.save(); g.translate(cx, y0); g.scale(s, s);
59
+ poly(g, [[-26, 256], [-20, 256], [10, 196], [4, 196]]); fs(g, C.white, C.line, 2); poly(g, [[26, 256], [20, 256], [-10, 196], [-4, 196]]); fs(g, C.white, C.line, 2);
60
+ g.fillStyle = C.white; g.fillRect(-24, 198, 48, 6); g.strokeStyle = C.line; g.strokeRect(-24, 198, 48, 6);
61
+ g.beginPath(); g.moveTo(-10, 30); g.bezierCurveTo(-40, 50, -38, 120, -20, 180); g.quadraticCurveTo(-6, 222, 0, 228); g.quadraticCurveTo(6, 222, 20, 180); g.bezierCurveTo(38, 120, 40, 50, 10, 30); g.closePath(); fs(g, C.terra, C.line, 2.5);
62
+ g.save(); g.clip(); g.fillStyle = C.green; g.fillRect(-40, 52, 80, 6); g.fillStyle = C.blue; g.fillRect(-40, 58, 80, 4);
63
+ g.fillStyle = '#2f9a8a'; for (let x = -36; x < 36; x += 9) { poly(g, [[x, 62], [x + 9, 62], [x + 4.5, 82]]); g.fill(); } g.restore();
64
+ g.fillStyle = C.terra; g.fillRect(-9, 18, 18, 14); g.strokeStyle = C.line; g.lineWidth = 2; g.strokeRect(-9, 18, 18, 14);
65
+ g.beginPath(); g.moveTo(-14, 20); g.quadraticCurveTo(-14, -6, 0, -6); g.quadraticCurveTo(14, -6, 14, 20); g.closePath(); fs(g, '#3a302a', C.line, 2);
66
+ g.restore();
67
+ }
68
+ // 供桌:苇席桌上摞面包、蓝莲、鸭、葡萄
69
+ function offering(g, x, y) {
70
+ g.fillStyle = C.yellow; g.fillRect(x - 70, y - 120, 140, 10); g.strokeStyle = C.line; g.lineWidth = 2; g.strokeRect(x - 70, y - 120, 140, 10);
71
+ g.fillStyle = C.yellow; g.fillRect(x - 8, y - 110, 16, 110); g.strokeRect(x - 8, y - 110, 16, 110); g.fillRect(x - 30, y - 8, 60, 8); g.strokeRect(x - 30, y - 8, 60, 8);
72
+ [[-52, -136, C.terra], [-20, -140, C.yellow], [14, -138, C.terra], [44, -134, '#c8802a']].forEach(([dx, dy, col]) => { g.beginPath(); g.ellipse(x + dx, y + dy, 18, 12, 0, 0, TAU); fs(g, col, C.line, 2); });
73
+ g.beginPath(); g.ellipse(x - 4, y - 166, 40, 13, 0, 0, TAU); fs(g, '#e8e0cc', C.line, 2);
74
+ for (let k = 0; k < 7; k++) { g.beginPath(); g.arc(x + 40 + (k % 3) * 9, y - 176 + Math.floor(k / 3) * 9, 5, 0, TAU); fs(g, '#5a3a7a', C.line, 1.2); }
75
+ // 蓝莲两朵从桌上垂下
76
+ [[-60, 1], [60, -1]].forEach(([dx, sg]) => { g.strokeStyle = C.green; g.lineWidth = 3; g.beginPath(); g.moveTo(x + dx * 0.6, y - 120); g.quadraticCurveTo(x + dx * 1.3, y - 80, x + dx * 1.2, y - 30); g.stroke();
77
+ poly(g, [[x + dx * 1.2, y - 30], [x + dx * 1.2 - 12, y - 4], [x + dx * 1.2, y - 12], [x + dx * 1.2 + 12, y - 4]]); fs(g, C.blue, C.line, 1.6); void sg; });
78
+ }
79
+
80
+ // ---------- 静态层(世界坐标 +OX,缓存) ----------
81
+ const WALLTEX = () => P.cached('je_walltex', WW, H, g => {
82
+ const hw = Math.ceil(WW / 2), hh = H / 2, s = P.canvas(hw, hh), sg = s.getContext('2d'), img = sg.createImageData(hw, hh), d = img.data, r = rng(13);
83
+ for (let y = 0; y < hh; y++) for (let x = 0; x < hw; x++) { const n = P.fbm(x * 0.007 + 3, y * 0.007, 4), m = P.fbm(x * 0.05, y * 0.05 + 9, 2), k = (y * hw + x) * 4;
84
+ const col = P.mix(C.wall, C.wall2, clamp(0.35 - n * 1.2)); const v = 1 + m * 0.05 + (r() - 0.5) * 0.04; d[k] = col[0] * v; d[k + 1] = col[1] * v; d[k + 2] = col[2] * v; d[k + 3] = 255; }
85
+ sg.putImageData(img, 0, 0); g.imageSmoothingQuality = 'high'; g.drawImage(s, 0, 0, WW, H);
86
+ });
87
+ const SURF = () => P.cached('je_surface', WW, H, g => { // 壁画表面(multiply):斑驳+发丝裂纹+颗粒
88
+ const hw = Math.ceil(WW / 2), hh = H / 2, s = P.canvas(hw, hh), sg = s.getContext('2d'), img = sg.createImageData(hw, hh), d = img.data, r = rng(99);
89
+ for (let y = 0; y < hh; y++) for (let x = 0; x < hw; x++) { const n = P.fbm(x * 0.012 + 40, y * 0.012, 4), m = P.fbm(x * 0.06, y * 0.06 + 9, 2), v = 243 + n * 30 + m * 12 + (r() - 0.5) * 18, k = (y * hw + x) * 4; d[k] = v; d[k + 1] = v - 6; d[k + 2] = v - 16; d[k + 3] = 255; }
90
+ sg.putImageData(img, 0, 0); g.drawImage(s, 0, 0, WW, H);
91
+ const rr = rng(5); for (let q = 0; q < 9; q++) { let x = rr() * WW, y = rr() < 0.5 ? 0 : rr() * H, a = rr() * TAU; g.strokeStyle = 'rgba(90,70,50,.5)'; g.lineWidth = 1.1; g.beginPath(); g.moveTo(x, y); for (let k = 0; k < 34; k++) { a += (rr() - 0.5) * 0.7; x += Math.cos(a) * 14; y += Math.sin(a) * 14; g.lineTo(x, y); } g.stroke(); }
92
+ for (let x = 0; x < WW; x += W) g.drawImage(P.grain('eg_specks', 0.018, [70, 50, 30], 0.4), x, 0);
93
+ });
94
+ const GEESE = [[300, 498, 1], [520, 498, -1], [700, 498, 1]]; // 美杜姆群鹅(世界 x、脚底 y、朝向)
95
+ const PAPY = [1260, 1760]; // 纸莎草丛 x 范围(上栏)
96
+ const DISC = [880, 210];
97
+ const STATIC = () => P.cached('je_static', WW, H, g => {
98
+ g.drawImage(WALLTEX(), 0, 0); const X = x => x + OX;
99
+ // 顶:kheker 饰带(束起的芦苇头)+彩块边
100
+ g.fillStyle = C.cream; g.fillRect(0, 0, WW, 74);
101
+ for (let x = 0, k = 0; x < WW; x += 34, k++) { g.beginPath(); g.moveTo(x + 6, 74); g.lineTo(x + 6, 26); g.quadraticCurveTo(x + 17, 0, x + 28, 26); g.lineTo(x + 28, 74); g.closePath(); fs(g, [C.red, C.blue, C.green][k % 3], C.black, 2);
102
+ g.fillStyle = C.cream; g.fillRect(x + 12, 34, 10, 8); g.fillStyle = C.yellow; g.beginPath(); g.arc(x + 17, 22, 5, 0, TAU); g.fill(); }
103
+ blocks(g, 0, 74, WW, 96, 44, 0);
104
+ // 上栏:象形字栏(三组)
105
+ glyphCols(g, [X(-120), X(-44), X(32), X(108)], 112, 500, 1350);
106
+ glyphCols(g, [X(1060), X(1132), X(1204)], 112, 520, 1351);
107
+ glyphCols(g, [X(1880), X(1956), X(2032), X(2108), X(2184)], 112, 520, 1352);
108
+ // 有翼日盘的翅膀(静态部分;日盘本身每帧画以便脉动)
109
+ const [dx, dy] = [X(DISC[0]), DISC[1]];
110
+ for (const sg2 of [-1, 1]) { for (let r2 = 0; r2 < 3; r2++) { g.beginPath(); g.moveTo(dx + sg2 * 40, dy - 10 + r2 * 12); g.quadraticCurveTo(dx + sg2 * 150, dy - 34 + r2 * 18, dx + sg2 * (250 - r2 * 40), dy - 4 + r2 * 18); g.lineTo(dx + sg2 * (240 - r2 * 40), dy + 12 + r2 * 18); g.quadraticCurveTo(dx + sg2 * 140, dy - 6 + r2 * 18, dx + sg2 * 40, dy + 6 + r2 * 12); g.closePath(); fs(g, [C.blue, C.green, C.red][r2], C.black, 2); }
111
+ for (let f = 0; f < 9; f++) { g.strokeStyle = C.black; g.lineWidth = 1.4; g.beginPath(); g.moveTo(dx + sg2 * (60 + f * 22), dy - 18); g.lineTo(dx + sg2 * (60 + f * 22), dy + 40); g.stroke(); } }
112
+ // 上栏底的水带(纸莎草下的沼泽)
113
+ g.fillStyle = C.water; g.fillRect(X(1180), 500, 680, 40); g.strokeStyle = C.black; g.lineWidth = 2; g.strokeRect(X(1180), 500, 680, 40);
114
+ // 540 分栏线、760 地线:彩块带
115
+ blocks(g, 0, REG - 8, WW, REG + 8, 38, 1);
116
+ blocks(g, 0, G, WW, G + 16, 38, 2);
117
+ // 中栏:尖底罐、供桌(他走过时在身后)
118
+ jar(g, X(250), G - 256 * 0.86, 0.86); jar(g, X(330), G - 256 * 0.8, 0.8);
119
+ offering(g, X(620), G);
120
+ jar(g, X(1660), G - 256 * 0.86, 0.86);
121
+ offering(g, X(1880), G);
122
+ glyphCols(g, [X(1420), X(1490), X(1560)], 562, 740, 1353);
123
+ // 下栏:尼罗河(水色带+黑色之字水纹另画动态)+底部护墙裙
124
+ g.fillStyle = C.water; g.fillRect(0, G + 16, WW, 230);
125
+ blocks(g, 0, G + 246, WW, G + 262, 38, 3);
126
+ g.fillStyle = '#7a2a1c'; g.fillRect(0, G + 262, WW, H - G - 262); g.fillStyle = C.black; g.fillRect(0, G + 290, WW, 6); g.fillStyle = C.yellow; g.fillRect(0, G + 296, WW, 3);
127
+ });
128
+
129
+ // ---------- 动态母题 ----------
130
+ function goose(c, x, y, fx, t, k) { // 美杜姆鹅:侧身、平涂、勾线;点头啄食
131
+ const peck = Math.max(0, Math.sin(t * 2.2 + k * 2.1)) ** 3;
132
+ c.save(); c.translate(x, y); c.scale(fx * 1.2, 1.2);
133
+ c.strokeStyle = C.line; c.lineWidth = 2; c.beginPath(); c.moveTo(-6, -14); c.lineTo(-10, 0); c.moveTo(6, -14); c.lineTo(10, 0); c.stroke();
134
+ c.fillStyle = C.red; c.fillRect(-16, -2, 12, 3); c.fillRect(6, -2, 12, 3);
135
+ c.beginPath(); c.moveTo(-60, -48); c.quadraticCurveTo(-30, -78, 20, -66); c.quadraticCurveTo(44, -56, 40, -36); c.quadraticCurveTo(20, -12, -30, -16); c.quadraticCurveTo(-56, -22, -60, -48); c.closePath(); fs(c, '#d8c8a8', C.line, 2);
136
+ c.save(); c.clip(); c.fillStyle = '#8a6a4a'; c.fillRect(-60, -80, 120, 26); c.strokeStyle = '#4a3a2a'; c.lineWidth = 1.4; for (let i = 0; i < 6; i++) { c.beginPath(); c.moveTo(-50 + i * 14, -64); c.lineTo(-40 + i * 14, -52); c.stroke(); } c.restore();
137
+ c.save(); c.translate(30, -58); c.rotate(peck * 0.9);
138
+ c.beginPath(); c.moveTo(-6, 4); c.quadraticCurveTo(0, -40, 10, -56); c.lineTo(20, -54); c.quadraticCurveTo(12, -34, 8, 6); c.closePath(); fs(c, '#a8886a', C.line, 1.8);
139
+ c.beginPath(); c.ellipse(16, -58, 11, 8, 0, 0, TAU); fs(c, '#6a5a4a', C.line, 1.6); poly(c, [[24, -60], [40, -56], [24, -52]]); fs(c, '#d86a2a', C.line, 1.2);
140
+ c.fillStyle = '#fff'; c.beginPath(); c.arc(18, -60, 2.4, 0, TAU); c.fill();
141
+ c.restore(); c.restore();
142
+ }
143
+ function papyrus(c, x0, x1, t, camX) { // 纸莎草丛:茎+伞形花头,成片摇;水鸟从丛中惊飞
144
+ const r = rng(77);
145
+ for (let i = 0; i < 26; i++) { const bx = lerp(x0, x1, r()) - camX, top = 170 + r() * 120, sw = Math.sin(t * 1.4 + i * 0.7) * 10 * (0.5 + r() * 0.5);
146
+ if (bx < -100 || bx > W + 100) { r(); continue; }
147
+ c.strokeStyle = C.papy; c.lineWidth = 4; c.beginPath(); c.moveTo(bx, 500); c.quadraticCurveTo(bx + sw * 0.3, (500 + top) / 2, bx + sw, top); c.stroke();
148
+ c.save(); c.translate(bx + sw, top); c.rotate(sw * 0.02); poly(c, [[0, 0], [-34, -46], [34, -46]]); fs(c, i % 3 ? C.papyL : C.papy, C.line, 2);
149
+ c.strokeStyle = C.line; c.lineWidth = 1.2; for (let k = -2; k <= 2; k++) { c.beginPath(); c.moveTo(0, 0); c.lineTo(k * 15, -46); c.stroke(); } c.fillStyle = C.yellow; c.fillRect(-34, -50, 68, 5); c.restore(); }
150
+ // 水鸟:在纸莎草上方绕圈扑翅(两套翅膀姿态,10fps 交替)
151
+ for (let k = 0; k < 6; k++) { const ph = t * 0.9 + k * 1.05, bx = (x0 + x1) / 2 + Math.cos(ph) * 220 + (k - 2.5) * 30 - camX, by = 200 + Math.sin(ph * 1.3) * 60 + k * 8; if (bx < -60 || bx > W + 60) continue;
152
+ const up = Math.floor(t * 10 + k) % 2, fx = Math.sin(ph) < 0 ? 1 : -1;
153
+ c.save(); c.translate(bx, by); c.scale(fx, 1); c.beginPath(); c.ellipse(0, 0, 18, 8, 0, 0, TAU); fs(c, k % 2 ? C.white : '#5a8ab0', C.line, 1.6);
154
+ c.beginPath(); c.arc(18, -4, 6, 0, TAU); fs(c, k % 2 ? C.green : '#2a3a5a', C.line, 1.4); poly(c, [[23, -4], [32, -2], [23, 0]]); fs(c, C.yellow, null);
155
+ poly(c, up ? [[-6, -2], [-16, -30], [6, -4]] : [[-6, 2], [-18, 22], [6, 4]]); fs(c, k % 2 ? '#c8d8e8' : '#3a6a9a', C.line, 1.4); c.restore(); }
156
+ }
157
+ function nile(c, t, camX) { // 下栏:黑色之字水纹向左流,鱼游,蓝莲点头
158
+ const y0 = G + 30, y1 = G + 236, step = 26, off = (t * 60) % (step * 2);
159
+ c.save(); c.strokeStyle = '#13213f'; c.lineWidth = 3; c.lineJoin = 'miter';
160
+ for (let y = y0; y < y1; y += 30) { c.beginPath(); const sh = ((y / 30) % 2) * step; for (let x = -step * 2 - off + sh - (camX % (step * 2)); x < W + step * 2; x += step) { const yy = y + ((Math.round((x + off - sh + camX) / step)) % 2 ? 9 : -9); x === -step * 2 - off + sh - (camX % (step * 2)) ? c.moveTo(x, yy) : c.lineTo(x, yy); } c.stroke(); }
161
+ c.restore();
162
+ const r = rng(19);
163
+ for (let k = 0; k < 9; k++) { const sp = 30 + r() * 40, dir = r() < 0.5 ? -1 : 1, base = r() * (w + 400) - 200, fy = y0 + 30 + r() * 160;
164
+ let wx = base + dir * sp * t; wx = ((wx + 300) % (w + 600) + (w + 600)) % (w + 600) - 300; const fx = wx - camX; if (fx < -80 || fx > W + 80) continue;
165
+ const wig = Math.sin(t * 9 + k) * 0.12;
166
+ c.save(); c.translate(fx, fy); c.scale(dir, 1); c.rotate(wig * 0.3);
167
+ c.beginPath(); c.ellipse(0, 0, 30, 14, 0, 0, TAU); fs(c, k % 2 ? '#8aa0b8' : '#c8a060', C.black, 1.8);
168
+ poly(c, [[-26, 0], [-44, -12 + wig * 30], [-44, 12 + wig * 30]]); fs(c, k % 2 ? '#8aa0b8' : '#c8a060', C.black, 1.6);
169
+ c.strokeStyle = C.black; c.lineWidth = 1.2; c.beginPath(); c.moveTo(-10, -12); c.quadraticCurveTo(4, -22, 18, -10); c.stroke(); c.fillStyle = '#fff'; c.beginPath(); c.arc(18, -3, 3.2, 0, TAU); c.fill(); c.fillStyle = C.black; c.beginPath(); c.arc(19, -3, 1.6, 0, TAU); c.fill();
170
+ c.restore(); }
171
+ for (let k = 0; k < 14; k++) { const lx = k * 170 + 40 - camX; if (lx < -40 || lx > W + 40) continue; const nod = Math.sin(t * 2 + k) * 0.12;
172
+ c.save(); c.translate(lx, G + 18); c.rotate(nod); c.strokeStyle = C.green; c.lineWidth = 3; c.beginPath(); c.moveTo(0, 30); c.lineTo(0, -10); c.stroke();
173
+ poly(c, [[0, -8], [-14, -36], [-5, -30], [0, -44], [5, -30], [14, -36]]); fs(c, k % 2 ? C.blue : C.white, C.line, 1.6); c.restore(); }
174
+ }
175
+ // 有翼日盘:红盘+两条圣蛇,光晕脉动
176
+ function disc(c, x, y, t) { const pu = 0.5 + 0.5 * Math.sin(t * TAU / 0.9);
177
+ const hg = c.createRadialGradient(x, y, 30, x, y, 80 + 20 * pu); hg.addColorStop(0, `rgba(255,180,80,${0.35 * pu + 0.1})`); hg.addColorStop(1, 'rgba(255,170,70,0)'); c.fillStyle = hg; c.fillRect(x - 110, y - 110, 220, 220);
178
+ c.beginPath(); c.arc(x, y, 34, 0, TAU); fs(c, '#c8372b', '#7a1c14', 3);
179
+ for (const s of [-1, 1]) { c.beginPath(); c.moveTo(x + s * 30, y + 26); c.quadraticCurveTo(x + s * 44, y + 6, x + s * 38, y - 14); c.lineWidth = 6; c.strokeStyle = C.gold; c.stroke(); c.beginPath(); c.arc(x + s * 38, y - 16, 6, 0, TAU); fs(c, C.gold, C.black, 1.4); } }
180
+
181
+ // ---------- 圣甲虫(背视:青金石身、绿松石鞘翅),头朝左推着红色太阳球滚 ----------
182
+ function scarab(c, x, y, s, t) {
183
+ c.save(); c.translate(x, y); c.scale(s, s); c.lineCap = 'round'; c.lineJoin = 'round'; c.rotate(-Math.PI / 2);
184
+ const pose = Math.floor(t * 15) % 2;
185
+ c.strokeStyle = '#141a30'; c.lineWidth = 3; // 腿:两套姿态交替
186
+ const legs = pose ? [[-14, -16, -26], [0, -18, -6], [14, -14, 18]] : [[-14, -14, -32], [0, -19, 2], [14, -18, 24]];
187
+ legs.forEach(([ly, lx, ex]) => { for (const sg of [-1, 1]) { c.beginPath(); c.moveTo(sg * 10, ly + 14); c.lineTo(sg * 24, ly + 14 + (ex - ly) * 0.3); c.lineTo(sg * 30, ly + 24 + (pose ? 3 : -3) * sg); c.stroke(); } void lx; });
188
+ c.beginPath(); c.ellipse(0, 8, 17, 23, 0, 0, TAU); fs(c, C.lapis, '#0d1430', 2.2);
189
+ c.beginPath(); c.moveTo(0, -12); c.lineTo(0, 30); c.stroke();
190
+ c.fillStyle = C.turq; c.beginPath(); c.ellipse(-7, 6, 4, 13, 0.1, 0, TAU); c.fill(); c.beginPath(); c.ellipse(7, 6, 4, 13, -0.1, 0, TAU); c.fill();
191
+ c.beginPath(); c.ellipse(0, -18, 12, 8, 0, 0, TAU); fs(c, '#3a68c4', '#0d1430', 2);
192
+ c.beginPath(); c.moveTo(-10, -24); for (let k = 0; k < 5; k++) c.lineTo(-10 + k * 5, -28 - (k % 2) * 4); c.lineTo(10, -24); fs(c, '#3a68c4', '#0d1430', 1.6);
193
+ const by = -52, br = 23; // 日球:在头前,随滚动转
194
+ c.beginPath(); c.arc(0, by, br, 0, TAU); fs(c, '#c8302a', '#3a0c08', 2.2);
195
+ c.save(); c.clip(); c.fillStyle = '#f2c23a'; for (let k = 0; k < 6; k++) { const a = t * 10 + k * 1.05; c.beginPath(); c.arc(Math.cos(a) * br * 0.55, by + Math.sin(a) * br * 0.55, 3.4, 0, TAU); c.fill(); } c.restore();
196
+ c.restore();
197
+ }
198
+ // 圣甲虫在世界里的位置(ta = 互动内秒):一直往左滚,从他脚下穿过、滚出画外
199
+ const SC_S = 1.9, scX = ta => AX + 52 * SC_S + V_SC * (T_HIT - ta); // 圣甲虫身体中心;球在它左边 52*SC_S,T_HIT 时球正好滚到他脚下
200
+ function scarabWorld(c, s, seg) {
201
+ const ta = XJ.ta(seg, s); if (ta < -3 || ta > 6) return;
202
+ const x = scX(ta) - s.camX; if (x < -200 || x > W + 150) return;
203
+ scarab(c, x, G - 23 * SC_S - 3, SC_S, s.t);
204
+ }
205
+ // ---------- 主角材质:灰泥墙面斑驳 multiply(只在人身上),白保持白 ----------
206
+ const heroMat = (g, ww, hh, i) => {
207
+ XJ.texInside(g, ww, hh, (tg, w2, h2) => { const S = SURF(); tg.drawImage(S, -((i * 137) % 600) - 200, -300); });
208
+ };
209
+
210
+ WORLD.add({
211
+ id: '02_egypt', year: -1350, name: '古埃及壁画', w, burst: 'jia_egypt', labelColor: 'rgba(42,24,16,.85)',
212
+ hero: { walk: K.walk, h: 300, fps: WALK.fps, // 一个步态循环 8 帧(4 帧一步);帧率按量出的步幅定,脚底锁见 XJ.walkLock
213
+ shadow: null, draw(c, key, i, o, S) { if (key === K.act) { const gw = XJ.glideWalk(S, DUR, WALK.fps, 8, 0.22, true); if (gw != null) { key = K.walk; i = gw; } } if (key === K.walk) o.lock = (S.act ? 0 : XJ.walkLock({ w }, S, i, WALK.st, WALK.fps)); XJ.actor(c, key, i, o, 'egypt', heroMat); } },
214
+ acts: [{ at: AT, dur: DUR, key: K.act, lead: 0, ...XJ.glide(DUR),
215
+ frame: XJ.actFrame([[0, 1], [0.22, 2], [0.3, 3], [0.42, 4], [1.04, 5], [1.2, 6], [1.4, 7]]),
216
+ y: (lx, u) => G - 140 * Math.sin(Math.PI * clamp((u - 0.22) / 0.9)) }],
217
+ back(c, s) {
218
+ c.drawImage(STATIC(), -OX - s.camX, 0);
219
+ if (XJ.vis(s, DISC[0], 400)) disc(c, DISC[0] - s.camX, DISC[1], s.t);
220
+ GEESE.forEach(([x, y, f], k) => { if (XJ.vis(s, x, 120)) goose(c, x - s.camX, y, f, s.t, k); });
221
+ papyrus(c, PAPY[0], PAPY[1], s.t, s.camX);
222
+ nile(c, s.t, s.camX);
223
+ scarabWorld(c, s, this);
224
+ c.save(); c.globalCompositeOperation = 'multiply'; c.drawImage(SURF(), -OX - s.camX, 0); c.restore();
225
+ },
226
+ front(c, s) {
227
+ // 跳起时脚下扬起的一点金色尘(埃及式:小三角点)
228
+ const ta = XJ.ta(this, s);
229
+ if (ta > 1.1 && ta < 1.5) { const q = (ta - 1.1) / 0.4, x = AX - s.camX; c.save(); c.globalAlpha = 1 - q; c.fillStyle = C.gold; for (let k = 0; k < 8; k++) { const a = Math.PI + (k / 7) * Math.PI, d = 30 + q * 60; c.beginPath(); c.arc(x + Math.cos(a) * d, G - 6 + Math.sin(a) * d * 0.3, 4, 0, TAU); c.fill(); } c.restore(); }
230
+ },
231
+ // 进入埃及的边界:一条竖向四色彩块边(墓室壁画的边框语言)
232
+ seam(c, y, sx, t) { const k = Math.floor((y + 1000) / 36), yy = (y + 1000) % 36; c.fillStyle = yy < 3 ? C.black : BAND[k % 4]; c.fillRect(sx - 10, y, 20, 6); c.fillStyle = C.black; c.fillRect(sx - 12, y, 2, 6); c.fillRect(sx + 10, y, 2, 6); },
233
+ });
234
+ })();
@@ -0,0 +1,118 @@
1
+ // 21 · 1980s 8-bit 像素游戏(通用 8-bit 语法,不指向任何一款游戏:夜晚紫色天空、像素星空和月亮、远山剪影、萤火虫、浮空木平台、星星方块、宝箱)。
2
+ // 互动:跳起来顶星星方块,方块一跳,弹出一枚转着的像素金币,升到顶点闪一下消失,100 飘起、HUD 金币 7→8、分数 +100;他落地仰头再欢呼一跳。所有事件相对互动定时。
3
+ // 画法沿用 skill 场景 14_8bit:整个世界在 1/8 分辨率画布上逐像素画(1 低像素 = 8 屏幕像素),imageSmoothing 关掉放大;天空交界用 (x+y)%2 棋盘抖动(NES 做渐变的唯一办法)。
4
+ // 花叔=AI 生的像素小人帧,代码再按 6px 网格降采样、alpha 二值化(去抗锯齿),保证是真·硬边像素。
5
+ (() => {
6
+ if (!window.D4) { const x = new XMLHttpRequest(); x.open('GET', 'demos/long_scroll/lib/xing2_ding.js', false); x.send(); (0, eval)(x.responseText); }
7
+ const W = 1920, H = 1080, TAU = Math.PI * 2, { clamp, lerp, ss, ease } = U, P = PAINT;
8
+ const SW = 2000, PX = 8, LW = SW / PX, LH = H / PX, G = 760, GR = G / PX, AT = 900, DUR = 1.6;
9
+ const BX = Math.round(AT / PX) - 4, BY = 33; // 星星方块(低分辨率格):x 在他头顶,y 33..41 → 屏幕 264..328
10
+ const PAL = { sky0: '#140c38', sky1: '#2a1660', sky2: '#4a2a8a', sky3: '#7a46a8', white: '#fcfcfc', black: '#000000', star: '#fcf4b8', moon: '#fce8a8', moonD: '#d8b868', mtn: '#1c1448', mtnL: '#3c2c78', pine: '#0c0a24', stone: '#3c4a6c', stoneD: '#24304c', stoneL: '#6a7ca0', moss: '#3cb87c', mossL: '#8cf0a8', wood: '#a8642c', woodD: '#5c3014', woodL: '#e09c54', blk: '#2c5cd8', blkD: '#183898', blkL: '#7cacfc', gold: '#f8d040', coin: '#f8d878', coinD: '#e45c10', chest: '#b4602c', fly: '#d8fc6c' };
11
+ const WALK = '8bit_walk', ACTK = '8bit_act';
12
+ const REAL = ACTK === '8bit_act';
13
+ const tab = (u, T) => { let f = T[0][1]; for (const [a, i] of T) if (u >= a) f = i; return f; };
14
+ // 0 站 1 蹲 2 起跳举拳 3 顶 4 下落 5 落地 6 仰头 7 欢呼
15
+ const HF = REAL ? [[0, 0], [0.08, 1], [0.2, 2], [0.32, 3], [0.46, 4], [0.6, 5], [0.72, 6], [1.1, 7]] : [[0, 0], [0.08, 2], [0.2, 4], [0.32, 5], [0.46, 7], [0.6, 9], [0.72, 0], [1.1, 6]];
16
+ const J0 = 0.2, J1 = 0.6, T_HIT = (J0 + J1) / 2, T_TOP = T_HIT + 0.5, T_SCORE = T_TOP + 0.08; // 跳 0.2→0.6,最高点顶砖;金币升 0.5s 到顶闪没
17
+
18
+ // ---------- 字符位图 ----------
19
+ const BMP = {
20
+ star: ['...#....', '...#....', '.#####..', '..###...', '..#.#...', '.#...#..', '........', '........'],
21
+ moon: ['...####...', '.##....##.', '#.......##', '#........#', '#.....#..#', '#........#', '#.#......#', '.##....##.', '...####...'],
22
+ chest: ['.########.', '#oooooooo#', '#oooooooo#', '##########', '#ooooYYooo', '#oooYYYYoo', '#oooooooo#', '##########'],
23
+ cloud: ['....######......', '..##......##.....', '.#..........###..', '#...............#', '.################'],
24
+ };
25
+ const bmp = (g, rows, x, y, col) => { g.fillStyle = col; rows.forEach((r, j) => { for (let i = 0; i < r.length; i++) if (r[i] === '#') g.fillRect(x + i, y + j, 1, 1); }); };
26
+ const dither = (g, x0, x1, y0, y1, a, b) => { for (let y = y0; y < y1; y++) for (let x = x0; x < x1; x++) { g.fillStyle = (x + y) % 2 ? a : b; g.fillRect(x, y, 1, 1); } };
27
+
28
+ // ---------- 静态世界(低分辨率,缓存) ----------
29
+ let LO = null;
30
+ function build() {
31
+ if (LO) return LO;
32
+ const cv = P.canvas(LW, LH), g = cv.getContext('2d'), r = U.rng(85);
33
+ // 夜空:四档紫,交界棋盘抖动(NES 渐变)
34
+ [[0, PAL.sky0], [22, PAL.sky1], [44, PAL.sky2], [60, PAL.sky3]].forEach(([y, col], k, A) => { g.fillStyle = col; g.fillRect(0, y, LW, (A[k + 1] ? A[k + 1][0] : GR) - y); if (k) dither(g, 0, LW, y - 2, y, A[k - 1][1], col); });
35
+ // 静态小星(单像素),大月亮(带坑)
36
+ for (let k = 0; k < 160; k++) { const x = (r() * LW) | 0, y = (r() * 52) | 0; g.fillStyle = r() < 0.7 ? '#b8a8e8' : PAL.star; g.fillRect(x, y, 1, 1); }
37
+ { const mx = 176, my = 8; for (let y = 0; y < 14; y++) for (let x = 0; x < 14; x++) { const d = Math.hypot(x - 6.5, y - 6.5); if (d < 7) { g.fillStyle = d > 6 ? PAL.moonD : PAL.moon; g.fillRect(mx + x, my + y, 1, 1); } } g.fillStyle = PAL.moonD; [[4, 4, 2], [9, 8, 2], [5, 10, 1]].forEach(([x, y, w]) => g.fillRect(mx + x, my + y, w, w)); }
38
+ // 远山剪影(锯齿+亮边),地平线 68 → 屏幕 544
39
+ for (let x = 0; x < LW; x++) { const top = Math.round(60 - 10 * Math.abs(Math.sin(x * 0.045)) - 6 * Math.abs(Math.sin(x * 0.13 + 1))); g.fillStyle = PAL.mtn; g.fillRect(x, top, 1, 68 - top); g.fillStyle = PAL.mtnL; g.fillRect(x, top, 1, 1); }
40
+ // 中景:松树剪影带
41
+ g.fillStyle = PAL.pine; g.fillRect(0, 68, LW, GR - 68);
42
+ for (let x = 2; x < LW; x += 5 + ((r() * 4) | 0)) { const h = 10 + ((r() * 10) | 0); for (let j = 0; j < h; j++) { const w = Math.max(0, Math.floor((j / h) * 4)); g.fillRect(x - w, 70 - h + j, 2 * w + 1, 1); } }
43
+ // 地面:苔藓石阶(顶一行亮苔,下面石块错缝)
44
+ for (let y = GR; y < LH; y += 6) for (let x = (y / 6) % 2 ? 0 : -5; x < LW; x += 10) { g.fillStyle = PAL.stone; g.fillRect(x, y, 10, 6); g.fillStyle = PAL.stoneL; g.fillRect(x, y, 10, 1); g.fillStyle = PAL.stoneD; g.fillRect(x + 9, y, 1, 6); g.fillRect(x, y + 5, 10, 1); }
45
+ for (let x = 0; x < LW; x++) { g.fillStyle = PAL.moss; g.fillRect(x, GR, 1, 2); if ((x * 7) % 5 === 0) { g.fillStyle = PAL.mossL; g.fillRect(x, GR - 1, 1, 1); } }
46
+ // 浮空木平台(两端木桩):星星方块两侧、远处两块;一块上放宝箱
47
+ const plank = (x, y, n) => { for (let k = 0; k < n; k++) { g.fillStyle = PAL.wood; g.fillRect(x + k * 6, y, 6, 4); g.fillStyle = PAL.woodL; g.fillRect(x + k * 6, y, 6, 1); g.fillStyle = PAL.woodD; g.fillRect(x + k * 6 + 5, y, 1, 4); g.fillRect(x + k * 6, y + 3, 6, 1); } g.fillStyle = PAL.black; g.fillRect(x - 1, y, 1, 4); g.fillRect(x + n * 6, y, 1, 4); };
48
+ plank(BX - 20, BY + 2, 3); plank(BX + 9, BY + 2, 3); plank(20, 48, 4); plank(170, 46, 5);
49
+ const C2 = { '#': PAL.black, o: PAL.chest, Y: PAL.gold }; BMP.chest.forEach((row, j) => [...row].forEach((ch, i) => { if (C2[ch]) { g.fillStyle = C2[ch]; g.fillRect(182 + i, 38 + j, 1, 1); } }));
50
+ return (LO = cv);
51
+ }
52
+
53
+ // ---------- 低分辨率坐标 → 屏幕:全部对齐同一张 8px 网格(随相机整体平移) ----------
54
+ const sx = (lx, camX) => lx * PX - camX;
55
+ function qblock(c, camX, t, bump, used) { // 星星方块:蓝块+黄星,星星呼吸闪;被顶过后变灰
56
+ const x = sx(BX, camX), y = BY * PX - bump * PX;
57
+ c.fillStyle = PAL.black; c.fillRect(x, y, 8 * PX, 8 * PX);
58
+ c.fillStyle = used ? '#5c5c74' : PAL.blk; c.fillRect(x, y, 7 * PX, 7 * PX);
59
+ c.fillStyle = used ? '#8c8ca4' : PAL.blkL; c.fillRect(x, y, 7 * PX, PX); c.fillRect(x, y, PX, 7 * PX);
60
+ c.fillStyle = used ? '#3c3c50' : PAL.blkD; c.fillRect(x + 6 * PX, y + PX, PX, 6 * PX); c.fillRect(x + PX, y + 6 * PX, 6 * PX, PX);
61
+ if (!used) { c.save(); c.translate(x, y + PX); c.scale(PX, PX); bmp(c, BMP.star, 0, 0, Math.floor(t * 6) % 3 ? PAL.gold : '#fcfcd0'); c.restore(); }
62
+ }
63
+ function coin(c, x, y, t, s = 1) { // 像素金币:宽度 8/6/2/6 循环 = 翻转
64
+ const ph = Math.floor(t * 8) % 4, w = [8, 6, 3, 6][ph], h = 12, u = 4 * s; // 8fps 翻转,最窄也留 3 格(审片:细条一闪看不出是金币) c.fillStyle = PAL.black; c.fillRect(x - w * u / 2 - u, y - h * u - u, w * u + 2 * u, h * u + 2 * u);
65
+ c.fillStyle = PAL.coinD; c.fillRect(x - w * u / 2, y - h * u, w * u, h * u);
66
+ if (w > 3) { c.fillStyle = PAL.coin; c.fillRect(x - w * u / 2 + u, y - h * u + u, Math.max(u, w * u - 3 * u), h * u - 3 * u); c.fillStyle = '#fcfcfc'; c.fillRect(x - w * u / 2 + u, y - h * u + 2 * u, u, 4 * u); }
67
+ }
68
+ function hud(c, coins, score) {
69
+ c.save(); c.font = '36px "PressStart2P-400"'; c.textBaseline = 'top'; c.fillStyle = '#000'; const T = (s, x, y) => { c.fillStyle = '#000'; c.fillText(s, x + 6, y + 6); c.fillStyle = '#fcfcfc'; c.fillText(s, x, y); };
70
+ T('HUASHU', 60, 40); T(String(score).padStart(6, '0'), 60, 88); T('×' + String(coins).padStart(2, '0'), 470, 88); coin(c, 444, 128, 0, 0.75);
71
+ c.restore();
72
+ }
73
+
74
+ // ---------- 花叔像素化:6px 网格降采样+alpha 二值化 ----------
75
+ const pix = (key, i) => D4.frameCanvas(key, i, 'px6', im => {
76
+ const s = 300 / XING.SPR[key].meta.ref_h, k = s / 6, w = Math.max(1, Math.round(im.width * k)), h = Math.max(1, Math.round(im.height * k));
77
+ const cv = P.canvas(w, h), g = cv.getContext('2d', { willReadFrequently: true }); g.imageSmoothingEnabled = false; g.drawImage(im, 0, 0, w, h); // 最近邻:像素画源图的色块不被平均成泥
78
+ const d = g.getImageData(0, 0, w, h), q = d.data; for (let j = 0; j < q.length; j += 4) { if (q[j + 3] < 120) q[j + 3] = 0; else { q[j + 3] = 255; for (let m = 0; m < 3; m++) q[j + m] = Math.round(q[j + m] / 36) * 36; } } g.putImageData(d, 0, 0);
79
+ cv.k = w / im.width; cv.pixel = true; cv.pad = 0; return cv;
80
+ });
81
+ const apexTop = () => { const f = XING.SPR[ACTK].meta.frames[HF[3][1]], s = 300 / XING.SPR[ACTK].meta.ref_h; return f.ay * s; }; // 顶砖那帧:脚底到拳头顶的高度
82
+
83
+ WORLD.add({
84
+ id: '14_8bit', year: '1980s', name: '8-bit 像素游戏', w: SW, burst: 'vg', labelColor: 'rgba(252,252,252,.95)',
85
+ hero: { walk: WALK, h: 300, shadow: null, draw(c, key, i, o, S) { D4.drawFrame(c, key, i, o, pix(key, i)); } },
86
+ acts: [{ at: AT, dur: DUR, key: ACTK, lead: 140, frame: u => Math.min(tab(u, HF), XING.nFrames(ACTK) - 1),
87
+ // 跳:J0→J1 抛物线,最高点拳头正好顶到砖底;欢呼时再小跳一下
88
+ y: (lx, u) => { const q = clamp((u - J0) / (J1 - J0)); const lift = Math.max(0, (G - (BY + 8) * PX) - apexTop()); return G - Math.sin(q * Math.PI) * lift - (u > 1.1 && u < 1.4 ? Math.sin((u - 1.1) / 0.3 * Math.PI) * 40 : 0); } }],
89
+ back(c, s) {
90
+ const lo = build(); c.save(); c.imageSmoothingEnabled = false;
91
+ const ox = Math.floor(s.camX / PX), fx = s.camX - ox * PX;
92
+ c.drawImage(lo, ox, 0, LW - ox, LH, -fx, 0, (LW - ox) * PX, H); c.restore();
93
+ c.imageSmoothingEnabled = false;
94
+ // 闪烁星:一部分星 6fps 亮灭(整像素)
95
+ for (let k = 0; k < 40; k++) { const lx = U.hash(k, 11) * LW, ly = U.hash(k, 12) * 50; if (U.hash(k, Math.floor(s.t * 6)) < 0.5) continue; const X = sx(lx | 0, s.camX * 0.3 / 1) , Y = (ly | 0) * PX; c.fillStyle = PAL.star; c.fillRect(Math.round(X / PX) * PX, Y, PX, PX); c.fillRect(Math.round(X / PX) * PX - PX, Y + 0, PX * 3, PX * 0 + 2); }
96
+ // 夜云:深紫像素云整格左移
97
+ for (let k = 0; k < 5; k++) { const lx = ((k * 61 + 300 - Math.floor(s.t * 3)) % 320 + 320) % 320 - 20, ly = 14 + (k * 9) % 26; c.save(); c.translate(Math.round(sx(lx, s.camX * 0.6) / PX) * PX, ly * PX); c.scale(PX, PX); c.fillStyle = '#3a2470'; c.fillRect(1, 1, 15, 3); c.fillRect(4, 0, 7, 1); bmp(c, BMP.cloud, 0, 0, '#5a3c98'); c.restore(); }
98
+ // 流星:每 2.4 秒一颗,斜着划过(拖 5 格尾巴)
99
+ { const ph = (s.t % 2.4) / 0.5; if (ph < 1) { const hx = 40 + ((Math.floor(s.t / 2.4) * 67) % 160), lx = hx + ph * 30, ly = 6 + ph * 12; for (let k = 0; k < 6; k++) { c.fillStyle = k ? `rgba(252,244,184,${1 - k / 6})` : '#fff'; c.fillRect(Math.round(sx(lx - k * 2, s.camX * 0.3)), Math.round((ly - k * 0.8)) * PX, PX, PX); } } }
100
+ // 萤火虫:12 只在草丛上方慢飘、按自己的节奏亮灭
101
+ for (let k = 0; k < 12; k++) { const lx = U.hash(k, 21) * LW + Math.sin(s.t * 0.8 + k) * 4, ly = GR - 4 - U.hash(k, 22) * 14 + Math.sin(s.t * 1.3 + k * 2) * 2, on = Math.sin(s.t * 3 + k * 1.7) > 0.2; if (!on) continue; c.fillStyle = PAL.fly; c.fillRect(Math.round(sx(lx, s.camX) / PX) * PX, Math.round(ly) * PX, PX, PX); c.fillStyle = 'rgba(216,252,108,.3)'; c.fillRect(Math.round(sx(lx, s.camX) / PX) * PX - PX, Math.round(ly) * PX - PX, 3 * PX, 3 * PX); }
102
+ // 宝箱盖子一开一合,冒一颗金光
103
+ { const op = Math.floor(s.t * 1.5) % 2, X = sx(182, s.camX), Y = 38 * PX; if (op) { c.fillStyle = PAL.gold; c.fillRect(X + 3 * PX, Y - 2 * PX, 4 * PX, PX); c.fillStyle = '#fff'; c.fillRect(X + 4 * PX, Y - 4 * PX, PX, PX); } }
104
+ // 星星方块:被顶时上跳 2 格再落回,之后变成用过的灰块
105
+ const u = D4.since(this, s), bump = u > T_HIT && u < T_HIT + 0.16 ? Math.round(Math.sin((u - T_HIT) / 0.16 * Math.PI) * 2) : 0;
106
+ qblock(c, s.camX, s.t, bump, u > T_HIT);
107
+ // 金币:从砖顶弹出、转着上升(减速)→ 顶点闪一下消失(像素十字星)
108
+ const cx = sx(BX + 4, s.camX), cy0 = BY * PX;
109
+ if (u > T_HIT && u < T_TOP) { const q = (u - T_HIT) / (T_TOP - T_HIT); coin(c, cx, Math.round((cy0 - ease.out(q) * 130) / 4) * 4, s.t, 1.5); }
110
+ if (u >= T_TOP && u < T_TOP + 0.24) { const q = (u - T_TOP) / 0.24, r = Math.round((8 + q * 40) / 4) * 4; c.fillStyle = q < 0.5 ? '#fcfcfc' : PAL.coin; [[0, -1], [0, 1], [-1, 0], [1, 0]].forEach(([dx, dy]) => c.fillRect(cx + dx * r - 4, cy0 - 150 + dy * r - 4, 8, 8)); c.fillRect(cx - 4, cy0 - 150 - 4, 8, 8); }
111
+ if (u > T_SCORE && u < T_SCORE + 0.7) { c.save(); c.font = '30px "PressStart2P-400"'; c.fillStyle = '#fcfcfc'; c.globalAlpha = 1 - clamp((u - T_SCORE - 0.45) / 0.25); c.fillText('100', cx + 50, cy0 - 70 - (u - T_SCORE) * 60); c.restore(); }
112
+ hud(c, u >= T_SCORE ? 8 : 7, u >= T_SCORE ? 2100 : 2000);
113
+ c.imageSmoothingEnabled = true;
114
+ },
115
+ // 边界:一列一列的像素方块(黑白相间的格子边)
116
+ seam(c, y, sxp, t) { const q = Math.round(sxp / PX) * PX, row = Math.floor(y / PX); c.fillStyle = row % 2 ? '#000' : '#fcfcfc'; c.fillRect(q - PX, y, PX, 6); c.fillStyle = row % 2 ? '#fcfcfc' : '#000'; c.fillRect(q, y, PX, 6); },
117
+ });
118
+ })();
@@ -0,0 +1,86 @@
1
+ // 1899 莫奈《睡莲池上的日本桥》。世界=吉维尼花园横向展开:柳荫、绿色拱桥、桥顶垂下的紫藤、满池睡莲、水面光斑、蜻蜓。
2
+ // 互动(示范动作):桥顶打水漂,灰白扁石跳 4 下,间隔一次比一次长、弧一次比一次高,涟漪逐个扩散;第 4 下的水花里浮上一朵和池里一样的睡莲,他欢呼。
3
+ // 画法:XING.monetWorld(底稿→区域色板短笔触、桥与近栏杆单独一层、睡莲每片预画);人物用 XING 的 monet 材质(短笔触+光斑按世界坐标滑过)。
4
+ if (!window.YI) { const x = new XMLHttpRequest(); x.open('GET', 'demos/long_scroll/lib/xing2_yi.js', false); x.send(); (0, eval)(x.responseText + '\n//# sourceURL=demos/long_scroll/lib/xing2_yi.js'); }
5
+ (() => {
6
+ const W = 1920, H = 1080, TAU = Math.PI * 2, { clamp, lerp, ss } = U, P = PAINT, G = WORLD.GROUND;
7
+ const SW = 2150, AT = 760;
8
+ const MO = { key: 'yi_m', x0: 0, w: SW, waterTop: 560, bridge: { x0: 320, x1: 1200, yEnd: G, lift: 165 }, pond: [300, 1240], groundY: G };
9
+ const M = () => XING.monetWorld(MO);
10
+ // 事件按「互动开始后的秒数」r 定时(r = S.t - WORLD.actT(ME))。示范节奏:4 跳拉开到 1.36 秒、间隔递增(0.22/0.30/0.38/0.46),弧一次比一次高
11
+ let ME = null; const TA = 0;
12
+ const THROW = [[0, 0], [0.18, 1], [0.36, 2], [0.44, 3], [0.5, 4], [0.66, 5]], REL = 0.5;
13
+ const throwFrame = u => { let f = 0; for (const [tt, i] of THROW) if (u >= tt) f = i; return f; };
14
+ // 石子:出手后跳 4 下(世界坐标、动作内秒),越跳越近越大;第 4 下溅起睡莲
15
+ const HOPS = [{ x: AT + 170, y: 790, t: REL + 0.22, s: 0.5 }, { x: AT + 290, y: 850, t: REL + 0.52, s: 0.62, peak: 110 }, { x: AT + 390, y: 915, t: REL + 0.9, s: 0.74, peak: 150 }, { x: AT + 460, y: 985, t: REL + 1.36, s: 0.86, peak: 190 }];
16
+ const HIT = HOPS[3].t, DUR = HIT + 0.2;
17
+ const frameAt = u => u < 0.66 ? throwFrame(u) : u < HIT ? 5 : 6;
18
+ const plan = () => { const from = ACT.stoneFrom(AT, M().deckY(AT), 300); return { t0: TA + REL, from, s0: 0.4, firstArc: 90, hops: HOPS.map(h => ({ ...h, t: TA + h.t })) }; };
19
+ // 石子:莫奈笔触的灰白扁石(淡紫阴影+奶白高光的短笔),转着飞;拖尾是几笔奶白水沫
20
+ function stone(c, st, trail) { if (!st) return; const sc = 1 + st.s * 1.3, flat = Math.abs(Math.cos(st.spin)) * 0.5 + 0.28;
21
+ c.save(); c.lineCap = 'round';
22
+ if (trail) for (let k = 1; k <= 5; k++) { const p = trail(k * 0.02); if (!p) break; c.strokeStyle = '#fffbea'; c.globalAlpha = 0.45 * (1 - k / 6); c.lineWidth = 6 * sc * (1 - k / 7); c.beginPath(); c.moveTo(p.x, p.y); c.lineTo(p.x + 3, p.y); c.stroke(); }
23
+ c.globalAlpha = 1; c.translate(st.x, st.y);
24
+ c.fillStyle = 'rgba(70,72,120,.28)'; c.beginPath(); c.ellipse(2, 5, 13 * sc, 4 * sc, 0, 0, TAU); c.fill();
25
+ [['#8a88a0', 0, 2, 13, 0.0], ['#b8b4c4', -2, 0, 11, -0.2], ['#d8d4e0', 1, -1.5, 8, 0.15], ['#efeaf2', -3, -2.5, 5, -0.1], ['#fffbea', -4, -3.4, 3, 0]].forEach(([col, dx, dy, L, a]) => {
26
+ c.strokeStyle = col; c.lineWidth = 7 * sc * flat; c.beginPath(); c.moveTo((dx - L / 2) * sc, (dy + a * 10) * sc * flat); c.lineTo((dx + L / 2) * sc, (dy - a * 10) * sc * flat); c.stroke(); });
27
+ c.restore(); }
28
+ // 冒出的睡莲:和池里每片同一个画法、同一个尺寸(monetWorld 的叶托+花→同参数短笔触重画),缓存
29
+ let BLOOM = null;
30
+ function bloomImg() { if (BLOOM) return BLOOM; const s = 0.22 + 0.78 * clamp((985 - 560) / (H - 560)), rx = 36 * s * 1.7, ry = rx * (0.24 + 0.1 * s), pw = Math.ceil(rx * 2 + 16), ph = Math.ceil(ry * 2 + 34 * s + 16);
31
+ const cc = P.canvas(pw, ph), q = cc.getContext('2d'), cx = pw / 2, cy = ph - ry - 8, notch = 1.2;
32
+ q.fillStyle = '#7aa85a'; q.beginPath(); q.ellipse(cx, cy, rx, ry, 0, notch + 0.35, notch + TAU - 0.35); q.lineTo(cx, cy); q.closePath(); q.fill();
33
+ q.fillStyle = 'rgba(40,70,60,0.35)'; q.beginPath(); q.ellipse(cx, cy + ry * 0.25, rx * 0.95, ry * 0.7, 0, 0, Math.PI); q.fill();
34
+ const fr = 11 * s * 1.6 + 3; q.fillStyle = '#f2a6bf'; q.beginPath(); q.ellipse(cx + rx * 0.15, cy - fr * 0.5, fr * 1.4, fr * 0.8, 0, 0, TAU); q.fill(); q.fillStyle = '#fff0f2'; q.beginPath(); q.ellipse(cx + rx * 0.15, cy - fr * 0.8, fr * 0.6, fr * 0.45, 0, 0, TAU); q.fill();
35
+ const out = P.canvas(pw, ph), og = out.getContext('2d'); og.drawImage(cc, 0, 0); og.globalCompositeOperation = 'source-atop';
36
+ XING.strokes(og, cc, { cell: Math.max(3, 5 * s + 1), len: 10 * s + 5, width: 3 * s + 1.6, seed: 4242, alphaMask: true, alphaMin: 100, angle: (x, y, rr) => (rr() - 0.5) * 0.4,
37
+ palette: (x, y, col, rr) => { const L = col[0] * 0.3 + col[1] * 0.59 + col[2] * 0.11; return col[1] > col[0] + 10 ? P.mix(P.hex(['#5f8f4a', '#7fae5a', '#9cc070', '#b4cc78', '#4a7a5a', '#c8d880'][(rr() * 6) | 0]), col, 0.3) : (L > 170 ? P.mix(P.hex(['#fff2f4', '#f7d0dc', '#fbf4e8', '#f0a0b8'][(rr() * 4) | 0]), col, 0.4) : null); } });
38
+ out.ax = cx; out.ay = cy; return BLOOM = out; }
39
+
40
+ // 紫藤:从桥顶上方的架子垂下的淡紫花串(点列,由大到小,随风摆)
41
+ function wisteria(c, camX, t) {
42
+ const B = MO.bridge, deck = M().deckY; c.save();
43
+ // 紫藤架:桥上方一道拱形绿架,缀着叶子
44
+ c.lineCap = 'round'; c.strokeStyle = '#4f9a72'; c.lineWidth = 8; c.beginPath(); for (let wx = B.x0 + 40; wx <= B.x1 - 40; wx += 10) { const y = deck(wx) - 235; wx === B.x0 + 40 ? c.moveTo(wx - camX, y) : c.lineTo(wx - camX, y); } c.stroke();
45
+ [B.x0 + 40, B.x1 - 40].forEach(wx => { c.beginPath(); c.moveTo(wx - camX, deck(wx) - 235); c.lineTo(wx - camX, deck(wx) - 10); c.stroke(); });
46
+ for (let k = 0; k < 40; k++) { const wx = B.x0 + 50 + k * (B.x1 - B.x0 - 100) / 39, x = wx - camX + Math.sin(t * 1.8 + k) * 2; if (x < -40 || x > W + 40) continue; c.fillStyle = ['#6f9a40', '#9cbf58', '#4f7f3a'][k % 3]; c.beginPath(); c.ellipse(x, deck(wx) - 238 + (k % 3) * 5, 16, 7, (k % 5) * 0.6, 0, TAU); c.fill(); }
47
+ for (let k = 0; k < 18; k++) { const wx = B.x0 + 70 + k * ((B.x1 - B.x0 - 140) / 17), x = wx - camX; if (x < -60 || x > W + 60) continue;
48
+ const top = deck(wx) - 230, L = 7 + (k * 7) % 6, sw = Math.sin(t * 2.4 + 0.9 * k) * 8;
49
+ for (let i = 0; i < L; i++) { const q = i / L, r = 9 * (1 - q * 0.7); c.fillStyle = ['#b8a0d8', '#d0bce8', '#9a84c8', '#e4d4f0'][(i + k) % 4]; c.globalAlpha = 0.92; c.beginPath(); c.ellipse(x + sw * q * q + Math.sin(i * 2.1 + k) * 4, top + i * 11, r, r * 0.8, 0, 0, TAU); c.fill(); } }
50
+ c.restore();
51
+ }
52
+ // 蜻蜓:在水面上方折线飞,翅膀闪
53
+ function dragonflies(c, camX, t) {
54
+ c.save(); for (let k = 0; k < 3; k++) { const ph = k * 2.3, x = 700 + k * 380 + Math.sin(t * 0.9 + ph) * 160 + Math.sin(t * 3.1 + ph) * 30 - camX, y = 640 + k * 70 + Math.sin(t * 1.7 + ph) * 40;
55
+ c.strokeStyle = '#3a6a8a'; c.lineWidth = 4; c.lineCap = 'round'; c.beginPath(); c.moveTo(x - 18, y); c.lineTo(x + 14, y); c.stroke();
56
+ const f = 0.5 + 0.5 * Math.sin(t * 40 + k); c.fillStyle = 'rgba(230,240,255,.75)'; [[-1, -1], [1, -1]].forEach(([a]) => { c.beginPath(); c.ellipse(x + 2 + a * 4, y - 6 * f, 12, 3.5, a * 0.4, 0, TAU); c.fill(); }); }
57
+ c.restore();
58
+ }
59
+
60
+ WORLD.add(ME = { id: '28_monet', year: 1899, name: '莫奈《睡莲池上的日本桥》', w: SW, burst: 'monet', labelColor: 'rgba(16,22,40,.92)',
61
+ hero: { walk: 'monet_walk', mat: 'monet', shadow: 'rgba(60,70,120,.18)', draw(c, key, i, o) { YI.whitenHat(key); XING.actor(c, key, i, o); } },
62
+ ground: lx => M().deckY(lx),
63
+ acts: [{ at: AT, dur: DUR, key: 'monet_throw', frame: frameAt, lead: 0 }],
64
+ back(c, S) {
65
+ const lt = S.t - WORLD.actT(ME), pl = plan();
66
+ YI.edge(c, M().bg, S.camX, SW);
67
+ XING.monetBack(c, M(), S.camX, lt, { hops: pl.hops.map((p, i) => ({ x: p.x, y: p.y, t: p.t, s: p.s, big: i === 3 })) });
68
+ dragonflies(c, S.camX, lt);
69
+ wisteria(c, S.camX, lt);
70
+ // 第 4 下:水花里冒出一朵睡莲——叶托先浮上来,花一瓣瓣弹开,落定后随涟漪轻轻摇
71
+ if (lt >= HIT + 0.06) { const a = lt - HIT - 0.06, x = HOPS[3].x - S.camX, y = HOPS[3].y, im = bloomImg(), rise = U.ease.out(clamp(a / 0.45)), bob = Math.sin(a * 9) * 3 * Math.exp(-a * 2);
72
+ if (x > -200 && x < W + 200) { c.save(); c.globalAlpha = clamp(a / 0.15); c.translate(x, y + (1 - rise) * 14 + bob); c.scale(1, 0.3 + 0.7 * rise); c.drawImage(im, -im.ax, -im.ay); c.restore(); } }
73
+ },
74
+ front(c, S) {
75
+ const lt = S.t - WORLD.actT(ME), u = S.act ? S.act.u : -1;
76
+ XING.monetFront(c, M(), S.camX, lt, [200, 1600, 2000]);
77
+ { const pl = plan(), sh = p => p ? { ...p, x: p.x - S.camX } : null; stone(c, sh(XING.stone(lt, pl)), dt => sh(XING.stone(lt - dt, pl))); }
78
+ },
79
+ // 进入本段的边界:印象派短笔触(粉、蓝、绿、奶白),微微颤
80
+ seam(c, y, sx, t) {
81
+ const k = Math.floor(y / 6), cols = ['#f2a6bf', '#9db5e0', '#9cc070', '#fff2d4', '#b7a6d8', '#8fdcae'];
82
+ c.save(); c.lineCap = 'round'; c.strokeStyle = cols[k % 6]; c.lineWidth = 7; const a = -0.5 + U.hash(k, 3) * 0.6, L = 12 + U.hash(k, 4) * 10, x = sx + (U.hash(k, 6) - 0.5) * 10 + Math.sin(t * 4 + k) * 1.5;
83
+ c.beginPath(); c.moveTo(x - Math.cos(a) * L / 2, y + 3 - Math.sin(a) * L / 2); c.lineTo(x + Math.cos(a) * L / 2, y + 3 + Math.sin(a) * L / 2); c.stroke(); c.restore();
84
+ },
85
+ });
86
+ })();
@@ -0,0 +1,11 @@
1
+ // 示范 · 3b1b / manim 式讲解「神经网络一层是怎么把像素变成『猫』的」(8 秒三镜)。语法卡:references/动画语法/t1_3b1b.md
2
+ // 预览 index.html?film=demos/t1_3b1b 渲染 render.py --film demos/t1_3b1b --out t1.mp4
3
+ // 镜头 1→2 无转场:首帧 = 上一镜末帧,Transform 接续(100 个像素变成一列神经元)。镜头 2→3 穿进一个隐藏层神经元看它在找什么。
4
+ window.PUNCH = 0;
5
+ window.SCENE_DIR = 'demos/t1_3b1b';
6
+ window.ERAS = [
7
+ { id: 't1_s1', dur: 2.6 },
8
+ { id: 't1_s2', dur: 2.8 },
9
+ // cx,cy = 目标神经元在镜头 2 末帧的屏幕位置(r = 22×1.1);live:镜头 2 自己在转场里继续推相机(矢量重画)
10
+ { id: 't1_s3', dur: 2.6, transition: { type: 'zoomThrough', dur: 0.75, cx: 850, cy: 391.5, zoom: 48, r0: 24.2, live: true, focus: [640, 585] } },
11
+ ];
@@ -0,0 +1,101 @@
1
+ // t1 · 3b1b 式:「神经网络一层是怎么把像素变成『猫』的」
2
+ // 镜头 1(2.6s):一张 10×10 的猫图逐格出现 → 每格写上亮度 → 100 个像素 Transform 成一列输入神经元(16 个可见+⋮)
3
+ // 本文件同时放 t1 三个镜头共用的数据与布局(window.T1),后面的镜头直接用。
4
+ (() => {
5
+ const { clamp, lerp, hash } = U;
6
+ const C = DG.MANIM;
7
+
8
+ // ---------- 共用数据 ----------
9
+ const CAT = [
10
+ '0000000000',
11
+ '0600000060',
12
+ '0870000780',
13
+ '0899999980',
14
+ '0929999290',
15
+ '0999999990',
16
+ '0999449990',
17
+ '0099999900',
18
+ '0007887000',
19
+ '0000000000'];
20
+ const PIX = []; for (let r = 0; r < 10; r++) for (let q = 0; q < 10; q++) { const d = +CAT[r][q]; PIX.push(d ? clamp(d / 10 + (hash(r, q) - 0.5) * 0.08, 0, 1) : 0); }
21
+ // 「猫」神经元的权重:猫形处为正(蓝),猫形外一圈为负(红),眼睛处为负(猫的眼睛是暗的)
22
+ const WTS = PIX.map((v, i) => {
23
+ const r = (i / 10) | 0, q = i % 10;
24
+ if (+CAT[r][q] === 2) return -0.55;
25
+ if (v > 0.5) return 0.55 + 0.4 * hash(q, r + 7);
26
+ let near = false; for (let dr = -1; dr <= 1; dr++) for (let dq = -1; dq <= 1; dq++) { const rr = r + dr, qq = q + dq; if (rr >= 0 && rr < 10 && qq >= 0 && qq < 10 && PIX[rr * 10 + qq] > 0.5) near = true; }
27
+ return near ? -0.6 - 0.3 * hash(r, q + 3) : -0.12 * hash(q, r);
28
+ });
29
+
30
+ // ---------- 布局(屏幕 px;1 manim 单位 = 135px) ----------
31
+ const GRID = { cx: 960, cy: 545, cell: 52 };
32
+ const cellXY = i => [GRID.cx + ((i % 10) - 4.5) * GRID.cell, GRID.cy + (((i / 10) | 0) - 4.5) * GRID.cell];
33
+ const IN_X = 330, IN_R = 17;
34
+ const VIS = Array.from({ length: 16 }, (_, k) => Math.round(k * 99 / 15)); // 可见的 16 个输入
35
+ const inY = j => 540 + (j - 7.5) * 44 + (j >= 8 ? 30 : -30);
36
+ const HID_X = 900, HID_R = 22, HID_N = 10, hidY = j => 540 + (j - 4.5) * 70;
37
+ const OUT_X = 1470, OUT_R = 32, OUT = [{ y: 400, name: '猫', a: 0.92 }, { y: 540, name: '狗', a: 0.07 }, { y: 680, name: '鸟', a: 0.03 }];
38
+ const HID_A = [0.82, 0.12, 0.95, 0.3, 0.64, 0.06, 0.71, 0.22, 0.88, 0.41];
39
+ const W1 = (j, k) => Math.sin(j * 12.9898 + k * 78.233) * 0.5 + (hash(j, k + 11) - 0.5) * 1.1; // 输入→隐藏
40
+ const W2 = (k, o) => [[0.9, -0.5, 0.95, -0.2, 0.7, -0.8, 0.85, -0.3, 0.8, 0.1], [-0.6, 0.4, -0.7, 0.5, -0.2, 0.6, -0.5, 0.3, -0.4, 0.2], [-0.3, 0.2, -0.5, 0.6, -0.6, 0.4, -0.2, 0.7, -0.5, 0.3]][o][k];
41
+
42
+ // 输入列(S1 结束、S2 全程都要画)
43
+ const drawInputs = (c, a = 1) => {
44
+ VIS.forEach((pi, j) => DG.neuron(c, IN_X, inY(j), IN_R, PIX[pi] * a, { sa: a }));
45
+ c.save(); c.fillStyle = `rgba(255,255,255,${a})`; for (let d = -1; d <= 1; d++) { c.beginPath(); c.arc(IN_X, 540 + d * 16, 4, 0, Math.PI * 2); c.fill(); } c.restore();
46
+ };
47
+ const drawBrace = (c, p) => {
48
+ DG.brace(c, IN_X - 34, inY(0) - IN_R, inY(15) + IN_R, { p: MO.smooth(p), lw: 3 });
49
+ c.save(); c.translate(IN_X - 92, 540); c.rotate(-Math.PI / 2);
50
+ DG.write(c, '100 个输入', 0, 0, 40, p, { align: 'center' }); c.restore();
51
+ };
52
+ window.T1 = { PIX, WTS, CAT, GRID, cellXY, IN_X, IN_R, VIS, inY, HID_X, HID_R, HID_N, hidY, OUT_X, OUT_R, OUT, HID_A, W1, W2, drawInputs, drawBrace };
53
+
54
+ // ---------- 镜头 1 ----------
55
+ const DUR = 2.6;
56
+ SCENES['t1_s1'] = {
57
+ draw(c, lt) {
58
+ c.fillStyle = '#000'; c.fillRect(0, 0, 1920, 1080);
59
+ // 相机:前 1.4s 绕网格极慢推近 1→1.025,Transform 开始时 smooth 拉回 1(镜头 2 首帧要逐像素对上)
60
+ const z = 1 + 0.025 * MO.smooth(MO.seg(lt, 0, 1.4)) * (1 - MO.smooth(MO.seg(lt, 1.4, 2.2)));
61
+ c.save(); c.translate(960, 545); c.scale(z, z); c.translate(-960, -545);
62
+ // 标题:Write(linear,<15 个字 1 秒)
63
+ const out = MO.smooth(MO.seg(lt, 1.4, 1.9)); // FadeOut(shift=UP)
64
+ c.save(); c.globalAlpha = 1 - out; c.translate(0, -40 * out);
65
+ DG.write(c, '一张 10×10 的「猫」', 960, 150, 58, MO.seg(lt, 0.1, 1.1));
66
+ c.restore();
67
+
68
+ const morph = MO.seg(lt, 1.45, 2.55); // 100 个子 Transform,LaggedStart 0.01
69
+ const appear = MO.seg(lt, 0.0, 0.9);
70
+ const order = i => ((i % 10) + ((i / 10) | 0)); // 按对角线出现,像扫描
71
+ for (let i = 0; i < 100; i++) {
72
+ const [x, y] = cellXY(i), v = PIX[i];
73
+ const qa = MO.smooth(clamp(appear * 1.6 - order(i) / 18 * 0.6));
74
+ if (qa <= 0) continue;
75
+ const qm = MO.smooth(MO.lagged(i, 100, morph, 0.01));
76
+ const j = VIS.indexOf(i), vis = j >= 0;
77
+ // 不可见的像素:飞向中间的 ⋮ 并缩成点
78
+ const tx = IN_X, ty = vis ? inY(j) : 540 + (((i * 7) % 3) - 1) * 16, tr = vis ? IN_R : 3;
79
+ const s = GRID.cell * (0.92 + 0.08 * qa);
80
+ const A = DG.rectPts(x, y, s, s, 48), B = DG.circlePts(tx, ty, tr, 48);
81
+ const pts = qm > 0 ? DG.morph(A, B, qm) : A;
82
+ const fadeHidden = vis ? 1 : 1 - clamp((qm - 0.6) / 0.4);
83
+ if (qm >= 1) { if (vis) DG.neuron(c, tx, ty, IN_R, v); continue; } // 落定后用真圆画:镜头 2 首帧逐像素接得上(48 边形与 arc 抗锯齿不同)
84
+ c.save(); c.globalAlpha = qa * fadeHidden;
85
+ DG.shape(c, pts, { fill: `rgba(255,255,255,${v})`, stroke: `rgba(255,255,255,${lerp(0.22, 1, qm)})`, lw: lerp(1, 2, qm) });
86
+ c.restore();
87
+ // 亮度数字(0.7s 起淡入,Transform 开始时淡出)
88
+ const na = clamp((lt - 0.7) / 0.3) * (1 - clamp((lt - 1.35) / 0.2));
89
+ if (na > 0) { c.save(); c.globalAlpha = na; c.font = `20px "${DG.FONT.rm}"`; c.textAlign = 'center'; c.fillStyle = v > 0.55 ? '#000' : C.GREY_B; c.fillText(v.toFixed(1), x, y + 7); c.restore(); }
90
+ }
91
+ // 底部说明:FadeIn(shift=UP),随标题一起淡出
92
+ const la = MO.smooth(MO.seg(lt, 0.55, 1.15)) * (1 - out);
93
+ if (la > 0) { c.save(); c.globalAlpha = la; c.font = `600 38px "${DG.FONT.zh}"`; c.textAlign = 'center'; c.fillStyle = C.GREY_A; c.fillText('每个像素 = 一个 0 到 1 之间的数', 960, 905 + 24 * (1 - la)); c.restore(); }
94
+ // ⋮ 与大括号
95
+ const dots = MO.smooth(MO.seg(lt, 2.25, 2.55));
96
+ if (dots > 0) { c.save(); c.fillStyle = '#fff'; c.globalAlpha = dots; for (let d = -1; d <= 1; d++) { c.beginPath(); c.arc(IN_X, 540 + d * 16, 4, 0, Math.PI * 2); c.fill(); } c.restore(); }
97
+ T1.drawBrace(c, MO.seg(lt, 1.95, 2.6));
98
+ c.restore();
99
+ },
100
+ };
101
+ })();