@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.
- package/bin/server.mjs +575 -0
- package/data/styles.json +533 -0
- package/engine/audit_clip.py +46 -0
- package/engine/clip.html +24 -0
- package/engine/clip.js +104 -0
- package/engine/clip_schema.json +19 -0
- package/engine/clips/t1_3b1b.js +203 -0
- package/engine/clips/t2_keynote_ui.js +347 -0
- package/engine/clips/t3_finance_chart.js +206 -0
- package/engine/clips/y1_kurzgesagt.js +183 -0
- package/engine/clips/y2_vox.js +150 -0
- package/engine/clips/y3_whiteboard.js +209 -0
- package/engine/clips/y4_storytime.js +194 -0
- package/engine/clips/y5_kinetic_type.js +134 -0
- package/engine/compare.py +19 -0
- package/engine/demos/_shared/hero/c1_0.png +0 -0
- package/engine/demos/_shared/hero/c1_1.png +0 -0
- package/engine/demos/_shared/hero/c1_2.png +0 -0
- package/engine/demos/_shared/hero/c3_line.png +0 -0
- package/engine/demos/_shared/hero.js +96 -0
- package/engine/demos/long_scroll/eras.js +23 -0
- package/engine/demos/long_scroll/frames/8bit_act/01.png +0 -0
- package/engine/demos/long_scroll/frames/8bit_act/02.png +0 -0
- package/engine/demos/long_scroll/frames/8bit_act/03.png +0 -0
- package/engine/demos/long_scroll/frames/8bit_act/04.png +0 -0
- package/engine/demos/long_scroll/frames/8bit_act/05.png +0 -0
- package/engine/demos/long_scroll/frames/8bit_act/06.png +0 -0
- package/engine/demos/long_scroll/frames/8bit_act/07.png +0 -0
- package/engine/demos/long_scroll/frames/8bit_act/08.png +0 -0
- package/engine/demos/long_scroll/frames/8bit_act/meta.json +69 -0
- package/engine/demos/long_scroll/frames/8bit_walk/01.png +0 -0
- package/engine/demos/long_scroll/frames/8bit_walk/02.png +0 -0
- package/engine/demos/long_scroll/frames/8bit_walk/03.png +0 -0
- package/engine/demos/long_scroll/frames/8bit_walk/04.png +0 -0
- package/engine/demos/long_scroll/frames/8bit_walk/05.png +0 -0
- package/engine/demos/long_scroll/frames/8bit_walk/06.png +0 -0
- package/engine/demos/long_scroll/frames/8bit_walk/07.png +0 -0
- package/engine/demos/long_scroll/frames/8bit_walk/08.png +0 -0
- package/engine/demos/long_scroll/frames/8bit_walk/meta.json +69 -0
- package/engine/demos/long_scroll/frames/egypt_dodge/01.png +0 -0
- package/engine/demos/long_scroll/frames/egypt_dodge/02.png +0 -0
- package/engine/demos/long_scroll/frames/egypt_dodge/03.png +0 -0
- package/engine/demos/long_scroll/frames/egypt_dodge/04.png +0 -0
- package/engine/demos/long_scroll/frames/egypt_dodge/05.png +0 -0
- package/engine/demos/long_scroll/frames/egypt_dodge/06.png +0 -0
- package/engine/demos/long_scroll/frames/egypt_dodge/07.png +0 -0
- package/engine/demos/long_scroll/frames/egypt_dodge/08.png +0 -0
- package/engine/demos/long_scroll/frames/egypt_dodge/meta.json +69 -0
- package/engine/demos/long_scroll/frames/egypt_walk8/01.png +0 -0
- package/engine/demos/long_scroll/frames/egypt_walk8/02.png +0 -0
- package/engine/demos/long_scroll/frames/egypt_walk8/03.png +0 -0
- package/engine/demos/long_scroll/frames/egypt_walk8/04.png +0 -0
- package/engine/demos/long_scroll/frames/egypt_walk8/05.png +0 -0
- package/engine/demos/long_scroll/frames/egypt_walk8/06.png +0 -0
- package/engine/demos/long_scroll/frames/egypt_walk8/07.png +0 -0
- package/engine/demos/long_scroll/frames/egypt_walk8/08.png +0 -0
- package/engine/demos/long_scroll/frames/egypt_walk8/meta.json +69 -0
- package/engine/demos/long_scroll/frames/monet_throw/01.png +0 -0
- package/engine/demos/long_scroll/frames/monet_throw/02.png +0 -0
- package/engine/demos/long_scroll/frames/monet_throw/03.png +0 -0
- package/engine/demos/long_scroll/frames/monet_throw/04.png +0 -0
- package/engine/demos/long_scroll/frames/monet_throw/05.png +0 -0
- package/engine/demos/long_scroll/frames/monet_throw/06.png +0 -0
- package/engine/demos/long_scroll/frames/monet_throw/07.png +0 -0
- package/engine/demos/long_scroll/frames/monet_throw/08.png +0 -0
- package/engine/demos/long_scroll/frames/monet_throw/meta.json +71 -0
- package/engine/demos/long_scroll/frames/monet_walk/01.png +0 -0
- package/engine/demos/long_scroll/frames/monet_walk/02.png +0 -0
- package/engine/demos/long_scroll/frames/monet_walk/03.png +0 -0
- package/engine/demos/long_scroll/frames/monet_walk/04.png +0 -0
- package/engine/demos/long_scroll/frames/monet_walk/05.png +0 -0
- package/engine/demos/long_scroll/frames/monet_walk/06.png +0 -0
- package/engine/demos/long_scroll/frames/monet_walk/07.png +0 -0
- package/engine/demos/long_scroll/frames/monet_walk/08.png +0 -0
- package/engine/demos/long_scroll/frames/monet_walk/meta.json +71 -0
- package/engine/demos/long_scroll/lib/acts.js +87 -0
- package/engine/demos/long_scroll/lib/crossing.js +463 -0
- package/engine/demos/long_scroll/lib/world.js +143 -0
- package/engine/demos/long_scroll/lib/xing2_ding.js +42 -0
- package/engine/demos/long_scroll/lib/xing2_jia.js +114 -0
- package/engine/demos/long_scroll/lib/xing2_yi.js +133 -0
- package/engine/demos/long_scroll/segments/02_egypt.js +234 -0
- package/engine/demos/long_scroll/segments/14_8bit.js +118 -0
- package/engine/demos/long_scroll/segments/28_monet.js +86 -0
- package/engine/demos/t1_3b1b/eras.js +11 -0
- package/engine/demos/t1_3b1b/t1_s1.js +101 -0
- package/engine/demos/t1_3b1b/t1_s2.js +74 -0
- package/engine/demos/t1_3b1b/t1_s3.js +65 -0
- package/engine/demos/t2_keynote_ui/eras.js +10 -0
- package/engine/demos/t2_keynote_ui/t2_s1.js +57 -0
- package/engine/demos/t2_keynote_ui/t2_s2.js +70 -0
- package/engine/demos/t2_keynote_ui/t2_s3.js +61 -0
- package/engine/demos/t3_finance_chart/eras.js +11 -0
- package/engine/demos/t3_finance_chart/t3_s1.js +48 -0
- package/engine/demos/t3_finance_chart/t3_s2.js +42 -0
- package/engine/demos/t3_finance_chart/t3_s3.js +51 -0
- package/engine/demos/y1_kurzgesagt/eras.js +10 -0
- package/engine/demos/y1_kurzgesagt/kurzgesagt.js +347 -0
- package/engine/demos/y2_vox/eras.js +10 -0
- package/engine/demos/y2_vox/vox.js +240 -0
- package/engine/demos/y3_whiteboard/eras.js +10 -0
- package/engine/demos/y3_whiteboard/whiteboard.js +162 -0
- package/engine/demos/y4_storytime/eras.js +14 -0
- package/engine/demos/y4_storytime/s1_desk.js +18 -0
- package/engine/demos/y4_storytime/s2_screen.js +82 -0
- package/engine/demos/y4_storytime/s3_react.js +39 -0
- package/engine/demos/y4_storytime/s4_wide.js +16 -0
- package/engine/demos/y4_storytime/s5_close.js +18 -0
- package/engine/demos/y4_storytime/story.js +25 -0
- package/engine/demos/y4_storytime/vo_env.js +2 -0
- package/engine/demos/y4_storytime/world.js +73 -0
- package/engine/demos/y5_kinetic_type/eras.js +16 -0
- package/engine/demos/y5_kinetic_type/k1_title.js +38 -0
- package/engine/demos/y5_kinetic_type/k2_complete.js +55 -0
- package/engine/demos/y5_kinetic_type/k3_chat.js +47 -0
- package/engine/demos/y5_kinetic_type/k4_agent.js +49 -0
- package/engine/demos/y5_kinetic_type/kinetic.js +52 -0
- package/engine/engine.js +277 -0
- package/engine/eras.js +60 -0
- package/engine/eras_gallery.js +115 -0
- package/engine/eras_style_studies.js +20 -0
- package/engine/examples/assets/K/347/272/277/345/233/276_/346/250/252/345/261/217.png +0 -0
- 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
- package/engine/examples/assets//347/273/210/347/253/257_sum/346/261/202/345/222/214.png +0 -0
- package/engine/examples/assets//350/220/245/346/224/266/345/233/276_/347/253/226/345/261/217.png +0 -0
- 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
- package/engine/examples/t1_3b1b.json +19 -0
- package/engine/examples/t2_fullbleed_pulse.json +15 -0
- package/engine/examples/t2_keynote_ui.json +15 -0
- package/engine/examples/t3_finance_chart.json +29 -0
- package/engine/examples/y1_kurzgesagt.json +16 -0
- package/engine/examples/y2_vox.json +14 -0
- package/engine/examples/y3_whiteboard.json +17 -0
- package/engine/examples/y4_storytime.json +52 -0
- package/engine/examples/y5_kinetic_type.json +14 -0
- package/engine/index.html +42 -0
- package/engine/lib/THREE_LICENSE.txt +21 -0
- package/engine/lib/brush.js +149 -0
- package/engine/lib/camera.js +99 -0
- package/engine/lib/chart.js +152 -0
- package/engine/lib/collage.js +97 -0
- package/engine/lib/diagram.js +264 -0
- package/engine/lib/finish.js +70 -0
- package/engine/lib/fonts/AlfaSlabOne-400.woff +0 -0
- package/engine/lib/fonts/Anton-400.woff +0 -0
- package/engine/lib/fonts/ArchivoBlack-400.woff +0 -0
- package/engine/lib/fonts/Bangers-400.woff +0 -0
- package/engine/lib/fonts/Caveat-600.woff +0 -0
- package/engine/lib/fonts/Cinzel-400.woff +0 -0
- package/engine/lib/fonts/Cinzel-700.woff +0 -0
- package/engine/lib/fonts/CormorantGaramond-500.woff +0 -0
- package/engine/lib/fonts/CormorantGaramond-500i.woff +0 -0
- package/engine/lib/fonts/CormorantGaramond-700.woff +0 -0
- package/engine/lib/fonts/EBGaramond-400.woff +0 -0
- package/engine/lib/fonts/EBGaramond-400i.woff +0 -0
- package/engine/lib/fonts/EBGaramond-600.woff +0 -0
- package/engine/lib/fonts/Exo2-800i.woff +0 -0
- package/engine/lib/fonts/GochiHand-400.woff +0 -0
- package/engine/lib/fonts/IMFellEnglish-400.woff +0 -0
- package/engine/lib/fonts/IMFellEnglish-400i.woff +0 -0
- package/engine/lib/fonts/Inter-var.woff +0 -0
- package/engine/lib/fonts/JosefinSans-700.woff +0 -0
- package/engine/lib/fonts/Kalam-700.woff +0 -0
- package/engine/lib/fonts/LICENSES.md +40 -0
- package/engine/lib/fonts/LXGWWenKai-500.woff +0 -0
- package/engine/lib/fonts/LibreBaskerville-400.woff +0 -0
- package/engine/lib/fonts/LibreBaskerville-700.woff +0 -0
- package/engine/lib/fonts/LilitaOne-400.woff +0 -0
- package/engine/lib/fonts/Marcellus-400.woff +0 -0
- package/engine/lib/fonts/NotoSansSC-500.woff +0 -0
- package/engine/lib/fonts/NotoSansSC-700.woff +0 -0
- package/engine/lib/fonts/NotoSansSC-800.woff +0 -0
- package/engine/lib/fonts/NotoSansSC-900.woff +0 -0
- package/engine/lib/fonts/NotoSansSC-sub.woff +0 -0
- package/engine/lib/fonts/NotoSerifJP-600.woff +0 -0
- package/engine/lib/fonts/NotoSerifSC-sub.woff +0 -0
- package/engine/lib/fonts/OFL.txt +94 -0
- package/engine/lib/fonts/PlayfairDisplay-400i.woff +0 -0
- package/engine/lib/fonts/PlayfairDisplay-700.woff +0 -0
- package/engine/lib/fonts/PlayfairDisplay-700i.woff +0 -0
- package/engine/lib/fonts/Poppins-600.woff +0 -0
- package/engine/lib/fonts/Poppins-700.woff +0 -0
- package/engine/lib/fonts/Poppins-800.woff +0 -0
- package/engine/lib/fonts/PressStart2P-400.woff +0 -0
- package/engine/lib/fonts/Righteous-400.woff +0 -0
- package/engine/lib/fonts/RobotoCondensed-var.woff +0 -0
- package/engine/lib/fonts/Rye-400.woff +0 -0
- package/engine/lib/fonts/UnifrakturMaguntia-400.woff +0 -0
- package/engine/lib/fonts/cmunrm.woff +0 -0
- package/engine/lib/fonts/cmunti.woff +0 -0
- package/engine/lib/fonts/index.json +1 -0
- package/engine/lib/fonts.js +56 -0
- package/engine/lib/kit.js +91 -0
- package/engine/lib/media.js +118 -0
- package/engine/lib/medium.js +258 -0
- package/engine/lib/motion.js +111 -0
- package/engine/lib/paint.js +200 -0
- package/engine/lib/palettes.js +57 -0
- package/engine/lib/post.js +108 -0
- package/engine/lib/render.js +189 -0
- package/engine/lib/rig.js +390 -0
- package/engine/lib/rig_huashu.js +171 -0
- package/engine/lib/three.min.js +7 -0
- package/engine/lib/toon.js +186 -0
- package/engine/lib/typo.js +136 -0
- package/engine/lib/ui.js +141 -0
- package/engine/lib/util.js +92 -0
- package/engine/render.py +157 -0
- package/engine/scenes/01_cave.js +364 -0
- package/engine/scenes/02_egypt.js +524 -0
- package/engine/scenes/03_greek.js +448 -0
- package/engine/scenes/04_roman.js +555 -0
- package/engine/scenes/05_gothic.js +522 -0
- package/engine/scenes/06_renaissance.js +338 -0
- package/engine/scenes/08_impressionism.js +206 -0
- package/engine/scenes/09_postimp.js +183 -0
- package/engine/scenes/10_nouveau.js +334 -0
- package/engine/scenes/11_cubism.js +265 -0
- package/engine/scenes/12_bauhaus.js +214 -0
- package/engine/scenes/13_pop.js +269 -0
- package/engine/scenes/14_8bit.js +238 -0
- package/engine/scenes/15_raytrace.js +300 -0
- package/engine/scenes/16_2026.js +565 -0
- package/engine/scenes/17_ink.js +273 -0
- package/engine/scenes/18_klimt.js +227 -0
- package/engine/scenes/19_munch.js +153 -0
- package/engine/scenes/20_dunhuang.js +215 -0
- package/engine/scenes/21_kusama.js +124 -0
- package/engine/scenes/22_constructivism.js +205 -0
- package/engine/scenes/23_dali.js +221 -0
- package/engine/scenes/24_hopper.js +150 -0
- package/engine/scenes/25_ghibli.js +251 -0
- package/engine/scenes/26_vaporwave.js +191 -0
- package/engine/scenes/27_kirby.js +255 -0
- package/engine/scenes/28_monet.js +176 -0
- package/engine/scenes/29_seurat.js +104 -0
- package/engine/scenes/30_matisse.js +151 -0
- package/engine/scenes/31_haring.js +109 -0
- package/engine/scenes/32_rembrandt.js +217 -0
- package/engine/scenes/33_rubberhose.js +219 -0
- package/engine/scenes/34_shadowpuppet.js +195 -0
- package/engine/scenes/35_shinkai.js +197 -0
- package/engine/scenes/36_picasso_blue.js +123 -0
- package/engine/scenes/38_giotto.js +133 -0
- package/engine/scenes/39_piero.js +53 -0
- package/engine/scenes/40_raphael.js +96 -0
- package/engine/scenes/41_michelangelo.js +112 -0
- package/engine/scenes/42_guardi.js +70 -0
- package/engine/scenes/43_lorenzetti.js +145 -0
- package/engine/scenes/44_cortona.js +86 -0
- package/engine/scenes/45_renoir.js +86 -0
- package/engine/scenes/46_pissarro.js +82 -0
- package/engine/scenes/47_sisley.js +94 -0
- package/engine/scenes/48_gauguin.js +107 -0
- package/engine/scenes/49_chagall.js +60 -0
- package/engine/scenes/50_ma_yuan.js +131 -0
- package/engine/scenes/51_persian_miniature.js +149 -0
- package/engine/scenes/52_south_park.js +105 -0
- package/engine/scenes/53_pixar.js +60 -0
- package/engine/scenes/54_ghibli_lab.js +68 -0
- package/engine/scenes/55_dunhuang.js +161 -0
- package/engine/scenes/index.js +28 -0
- package/engine/spec_assets.py +76 -0
- package/engine/transitions.js +929 -0
- package/engine//346/227/266/344/273/243/344/275/234/350/200/205/350/247/204/350/214/203.md +49 -0
- package/lib/host.mjs +754 -0
- package/lib/render-bridge.mjs +543 -0
- package/lib/render-cli.mjs +98 -0
- package/lib/storyboard-lint.mjs +54 -0
- package/manifest.json +52 -0
- package/package.json +8 -4
- package/runtime/package.json +8 -0
- package/skills/biuart/SKILL.md +154 -0
- package/skills/biuart/references/01-/346/213/206/350/247/243.md +55 -0
- package/skills/biuart/references/02-/346/234/272/345/210/266.md +41 -0
- 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
- package/skills/biuart/references/04-/347/272/257/344/273/243/347/240/201/347/273/230/345/210/266.md +92 -0
- package/skills/biuart/references/05-/350/212/202/345/245/217/344/270/216/351/205/215/344/271/220.md +19 -0
- 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
- package/skills/biuart/references/07-/346/255/243/351/235/242/347/273/217/351/252/214.md +196 -0
- 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
- 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
- package/skills/biuart/references/10-/350/247/222/350/211/262.md +34 -0
- package/skills/biuart/references/11-/351/225/277/345/215/267/347/251/277/350/266/212/347/211/207.md +43 -0
- 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
- 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
- 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
- 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
- package/skills/biuart/references/about-author.md +99 -0
- package/skills/biuart/references/capabilities.md +91 -0
- package/skills/biuart/references/compatibility.md +34 -0
- package/skills/biuart/references/images.md +97 -0
- package/skills/biuart/references/voice-model-review.md +18 -0
- package/skills/biuart/references//345/212/250/347/224/273/350/257/255/346/263/225/t1_3b1b.md +122 -0
- package/skills/biuart/references//345/212/250/347/224/273/350/257/255/346/263/225/t2_keynote_ui.md +117 -0
- package/skills/biuart/references//345/212/250/347/224/273/350/257/255/346/263/225/t3_finance_chart.md +116 -0
- package/skills/biuart/references//345/212/250/347/224/273/350/257/255/346/263/225/y1_kurzgesagt.md +193 -0
- package/skills/biuart/references//345/212/250/347/224/273/350/257/255/346/263/225/y2_vox.md +195 -0
- package/skills/biuart/references//345/212/250/347/224/273/350/257/255/346/263/225/y3_whiteboard.md +190 -0
- package/skills/biuart/references//345/212/250/347/224/273/350/257/255/346/263/225/y4_storytime.md +166 -0
- package/skills/biuart/references//345/212/250/347/224/273/350/257/255/346/263/225/y5_kinetic_type.md +158 -0
- package/skills/biuart/references//345/212/250/347/224/273/350/257/255/346/263/225/y6_presenter_explainer.md +24 -0
- package/skills/biuart/references//345/217/243/346/222/255API.md +125 -0
- package/skills/biuart/references//350/211/262/346/235/277.md +38 -0
- package/skills/biuart/references//350/247/222/350/211/262/347/262/276/347/273/206/345/272/246.md +61 -0
- package/skills/biuart/references//351/225/234/345/244/264/350/241/250/346/250/241/346/235/277.md +80 -0
- package/skills/biuart/references//351/225/234/345/244/264/350/257/255/350/250/200.md +73 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/01_cave.md +46 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/02_egypt.md +64 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/03_greek.md +50 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/04_roman.md +99 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/05_gothic.md +32 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/06_renaissance.md +41 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/08_impressionism.md +34 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/09_postimp.md +17 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/10_nouveau.md +31 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/11_cubism.md +30 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/12_bauhaus.md +30 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/13_pop.md +29 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/14_8bit.md +27 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/15_raytrace.md +32 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/16_2026.md +55 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/17_ink.md +50 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/18_klimt.md +37 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/19_munch.md +42 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/20_dunhuang.md +49 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/21_kusama.md +32 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/22_constructivism.md +35 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/23_dali.md +29 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/24_hopper.md +30 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/25_ghibli.md +55 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/26_vaporwave.md +27 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/27_kirby.md +30 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/28_monet.md +39 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/29_seurat.md +31 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/30_matisse.md +26 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/31_haring.md +22 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/32_rembrandt.md +29 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/33_rubberhose.md +31 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/34_shadowpuppet.md +40 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/35_shinkai.md +34 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/36_picasso_blue.md +25 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/37_rick_morty.md +48 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/38_giotto.md +67 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/39_piero.md +59 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/40_raphael.md +65 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/41_michelangelo.md +65 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/42_guardi.md +65 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/43_lorenzetti.md +69 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/44_cortona.md +66 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/45_renoir.md +66 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/46_pissarro.md +66 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/47_sisley.md +67 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/48_gauguin.md +66 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/49_chagall.md +59 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/50_ma_yuan.md +68 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/51_persian_miniature.md +66 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/52_south_park.md +65 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/53_pixar.md +61 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/55_dunhuang.md +41 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/INDEX.md +89 -0
- 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
- 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
- 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
- package/studio/app.js +380 -0
- package/studio/assert-panel-permit.mjs +67 -0
- package/studio/composer.css +465 -0
- package/studio/composer.js +480 -0
- package/studio/index.html +97 -0
- package/studio/optimize-prompt.mjs +84 -0
- package/studio/optimize-prompt.test.mjs +47 -0
- package/studio/recipes.mjs +87 -0
- package/studio/select-menu.js +450 -0
- package/studio/styles.css +71 -0
- package/studio/to-english-prompt.mjs +149 -0
- package/studio/to-english-prompt.test.mjs +72 -0
- 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
|
+
})();
|