@biunow/agent-biuart 0.0.0-stage → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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,273 @@
|
|
|
1
|
+
// 中国水墨写意(八大山人/齐白石)——纯代码。
|
|
2
|
+
// 管线:①宣纸(缓存)→ ②淡墨远山+朱日(晕染层)→ ③窗/桌:飞白笔触 → ④竹枝(浓墨个字叶,随风摆)
|
|
3
|
+
// → ⑤挂轴里的齐白石虾(游动)→ ⑥猫:赭石没骨晕染+留白+焦墨点斑,八大式白眼
|
|
4
|
+
// → ⑦少女:花青淡彩汉服+藤黄金发+白描面部 → ⑧热气、钤印
|
|
5
|
+
// 「画出来」开场:lt 0→0.45 各笔按序写出、各晕染层从无到有洇开;之后墨晕继续缓慢外扩(墨在纸上晕开)。
|
|
6
|
+
SCENES['17_ink'] = (() => {
|
|
7
|
+
const W = 1920, H = 1080, { clamp, lerp, rng, ease } = U, P = PAINT;
|
|
8
|
+
const { ss } = U;
|
|
9
|
+
|
|
10
|
+
// ---------- 宣纸 ----------
|
|
11
|
+
const paper = () => P.cached('ink_paper', W, H, (g) => {
|
|
12
|
+
g.drawImage(P.texture('xuan', '#efe6d0', { scale: 0.0025, amt: 9, grain: 7, seed: 5 }), 0, 0);
|
|
13
|
+
const r = rng(41);
|
|
14
|
+
g.lineCap = 'round';
|
|
15
|
+
for (let i = 0; i < 2600; i++) { // 纸纤维:短弧,亮暗混合
|
|
16
|
+
const x = r() * W, y = r() * H, a = r() * Math.PI * 2, l = 6 + r() * 26;
|
|
17
|
+
g.strokeStyle = r() < 0.5 ? `rgba(150,125,90,${0.05 + r() * 0.08})` : `rgba(255,252,240,${0.12 + r() * 0.15})`;
|
|
18
|
+
g.lineWidth = 0.6 + r() * 0.8; g.beginPath(); g.moveTo(x, y); g.quadraticCurveTo(x + Math.cos(a + 0.6) * l * 0.5, y + Math.sin(a + 0.6) * l * 0.5, x + Math.cos(a) * l, y + Math.sin(a) * l); g.stroke();
|
|
19
|
+
}
|
|
20
|
+
const vg = g.createRadialGradient(W / 2, H / 2, 500, W / 2, H / 2, 1250); vg.addColorStop(0, 'rgba(0,0,0,0)'); vg.addColorStop(1, 'rgba(120,90,50,.22)');
|
|
21
|
+
g.fillStyle = vg; g.fillRect(0, 0, W, H);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
// 笔、叶、晕染都用库:P.brush(毛笔飞白)、P.leaf(两头尖单笔)、P.inkWash(墨晕洇开)
|
|
25
|
+
const brush = P.brush, leaf = P.leaf;
|
|
26
|
+
const washLayer = (c, key, grow, fn, o) => P.inkWash(c, 'ink_' + key, grow, fn, o);
|
|
27
|
+
|
|
28
|
+
// ---------- 静态笔触表(窗、桌、地) ----------
|
|
29
|
+
const WIN = [
|
|
30
|
+
{ p: [[338, 116], [520, 112], [700, 118], [824, 114]], w: 16, d: 0.06, l: 0.18, dry: 0.55 },
|
|
31
|
+
{ p: [[352, 104], [348, 300], [356, 470], [350, 578]], w: 15, d: 0.1, l: 0.16, dry: 0.5 },
|
|
32
|
+
{ p: [[808, 108], [812, 330], [806, 572]], w: 14, d: 0.14, l: 0.16, dry: 0.6 },
|
|
33
|
+
{ p: [[318, 572], [560, 566], [842, 574]], w: 18, d: 0.18, l: 0.16, dry: 0.45 },
|
|
34
|
+
{ p: [[372, 140], [420, 140], [420, 186]], w: 4, d: 0.22, l: 0.08, dry: 0.3 }, { p: [[788, 140], [740, 140], [740, 186]], w: 4, d: 0.24, l: 0.08, dry: 0.3 },
|
|
35
|
+
{ p: [[372, 546], [420, 546], [420, 500]], w: 4, d: 0.26, l: 0.08, dry: 0.3 }, { p: [[788, 546], [740, 546], [740, 500]], w: 4, d: 0.28, l: 0.08, dry: 0.3 },
|
|
36
|
+
];
|
|
37
|
+
const TABLE = [
|
|
38
|
+
{ p: [[800, 622], [1000, 614], [1212, 620]], w: 22, d: 0.12, l: 0.15, dry: 0.5 },
|
|
39
|
+
{ p: [[820, 640], [1000, 646], [1196, 640]], w: 7, d: 0.2, l: 0.1, dry: 0.4 },
|
|
40
|
+
{ p: [[842, 640], [846, 760], [838, 906]], w: 13, d: 0.18, l: 0.16, dry: 0.65 },
|
|
41
|
+
{ p: [[1176, 640], [1172, 780], [1182, 906]], w: 13, d: 0.22, l: 0.16, dry: 0.65 },
|
|
42
|
+
{ p: [[848, 664], [900, 690], [960, 676]], w: 5, d: 0.26, l: 0.1, dry: 0.4 }, { p: [[1170, 664], [1118, 690], [1058, 676]], w: 5, d: 0.28, l: 0.1, dry: 0.4 },
|
|
43
|
+
{ p: [[300, 912], [700, 904], [1100, 914], [1520, 908]], w: 5, d: 0.3, l: 0.15, dry: 0.85, tone: 0.35 },
|
|
44
|
+
];
|
|
45
|
+
const SKIRT = [
|
|
46
|
+
{ p: [[1244, 630], [1190, 656], [1150, 722], [1118, 820], [1104, 926]], w: 6, dry: 0.3 },
|
|
47
|
+
{ p: [[1420, 612], [1446, 650], [1452, 722], [1440, 762], [1366, 774], [1344, 806], [1352, 926]], w: 6, dry: 0.4 },
|
|
48
|
+
{ p: [[1104, 928], [1220, 934], [1352, 928]], w: 5, dry: 0.6 },
|
|
49
|
+
{ p: [[1232, 668], [1222, 760], [1226, 815]], w: 4, dry: 0.3 }, { p: [[1268, 668], [1262, 760], [1270, 840]], w: 4, dry: 0.3 },
|
|
50
|
+
{ p: [[1160, 770], [1150, 860], [1146, 920]], w: 4, dry: 0.4 }, { p: [[1302, 830], [1308, 880], [1300, 925]], w: 4, dry: 0.4 },
|
|
51
|
+
{ p: [[1350, 434], [1382, 448], [1406, 486], [1418, 546], [1424, 604]], w: 6, dry: 0.35 },
|
|
52
|
+
];
|
|
53
|
+
|
|
54
|
+
// ---------- 远山、朱日 ----------
|
|
55
|
+
function mountains(g) {
|
|
56
|
+
g.save(); g.beginPath(); g.rect(366, 132, 428, 428); g.clip();
|
|
57
|
+
const R1 = rng(3);
|
|
58
|
+
const ridge = (y0, amp, f, seed) => { const pts = []; for (let x = 340; x <= 830; x += 10) pts.push([x, y0 - amp * (0.5 + 0.5 * P.fbm(x * f + seed, seed, 3)) - amp * 0.6 * Math.exp(-Math.pow((x - 560 - seed * 40) / 120, 2))]); return pts; };
|
|
59
|
+
const fill = (pts, a, y1) => { const gr = g.createLinearGradient(0, Math.min(...pts.map(p => p[1])), 0, y1); gr.addColorStop(0, `rgba(40,40,44,${a})`); gr.addColorStop(1, 'rgba(40,40,44,0)'); g.fillStyle = gr; g.beginPath(); pts.forEach((p, i) => i ? g.lineTo(...p) : g.moveTo(...p)); g.lineTo(830, y1); g.lineTo(340, y1); g.closePath(); g.fill(); };
|
|
60
|
+
fill(ridge(380, 120, 0.006, 1), 0.32, 520); fill(ridge(450, 90, 0.009, 2.4), 0.5, 560);
|
|
61
|
+
g.restore();
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// ---------- 竹(窗前,从右上斜入) ----------
|
|
65
|
+
function bamboo(c, t, rev) {
|
|
66
|
+
const sw = Math.sin(t * 2.9) * 0.11 + Math.sin(t * 6.1 + 1) * 0.025;
|
|
67
|
+
const base = [835, 70];
|
|
68
|
+
const rot = (x, y, k) => { const a = sw * k, dx = x - base[0], dy = y - base[1]; return [base[0] + dx * Math.cos(a) - dy * Math.sin(a), base[1] + dx * Math.sin(a) + dy * Math.cos(a)]; };
|
|
69
|
+
// 主枝:分节(每节一笔,节间留白),淡墨
|
|
70
|
+
const nodes = [[835, 70], [760, 150], [690, 215], [620, 268], [550, 312]];
|
|
71
|
+
for (let i = 0; i < nodes.length - 1; i++) {
|
|
72
|
+
const a = rot(...nodes[i], i / 4), b = rot(...nodes[i + 1], (i + 1) / 4);
|
|
73
|
+
const q0 = 0.04, A = [lerp(a[0], b[0], q0), lerp(a[1], b[1], q0)], B = [lerp(a[0], b[0], 0.94), lerp(a[1], b[1], 0.94)];
|
|
74
|
+
brush(c, [A, [lerp(A[0], B[0], .5), lerp(A[1], B[1], .5)], B], { w: 9, tone: 0.5, dry: 0.3, seed: 60 + i, reveal: ss(0.08 + i * 0.03, 0.18 + i * 0.03, rev), head: 0.06, tail: 0.1, bristles: 5 });
|
|
75
|
+
}
|
|
76
|
+
// 叶:个字、介字组,浓墨
|
|
77
|
+
const groups = [[2, -0.2, 0], [3, 0.4, 1], [4, -0.9, 2], [3, 2.2, 3], [4, 0.9, 4]];
|
|
78
|
+
groups.forEach(([ni, a0, gi]) => {
|
|
79
|
+
const np = nodes[Math.min(nodes.length - 1, ni)];
|
|
80
|
+
const p = rot(np[0], np[1], ni / 4); const flut = Math.sin(t * 7 + gi * 1.3) * 0.2;
|
|
81
|
+
const rv = ss(0.2 + gi * 0.04, 0.3 + gi * 0.04, rev); if (rv <= 0) return;
|
|
82
|
+
[[0, 1], [0.45, 0.82], [-0.42, 0.78]].forEach(([da, ls], k) => leaf(c, p[0], p[1], a0 + 1.4 + da + flut * (1 + k * 0.4) + sw * 2, 110 * ls * rv, 15, 0.86));
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// ---------- 挂轴+齐白石虾 ----------
|
|
87
|
+
function scrollStatic(g) {
|
|
88
|
+
g.fillStyle = 'rgba(170,140,95,.32)'; g.fillRect(1560, 240, 230, 640); // 绫边
|
|
89
|
+
g.fillStyle = 'rgba(250,246,234,.9)'; g.fillRect(1580, 290, 190, 540);
|
|
90
|
+
g.fillStyle = 'rgba(60,40,25,.85)'; g.fillRect(1548, 870, 254, 16); g.fillRect(1556, 232, 238, 10);
|
|
91
|
+
g.strokeStyle = 'rgba(60,40,25,.6)'; g.lineWidth = 1.5; g.beginPath(); g.moveTo(1640, 232); g.lineTo(1675, 196); g.lineTo(1710, 232); g.stroke();
|
|
92
|
+
g.fillStyle = '#c23a2b'; g.fillRect(1742, 788, 16, 16);
|
|
93
|
+
}
|
|
94
|
+
function shrimp(c, x, y, ang, s, t, ph) {
|
|
95
|
+
c.save(); c.translate(x, y); c.rotate(ang); c.scale(s, s);
|
|
96
|
+
const flex = Math.sin(t * 7 + ph) * 0.12;
|
|
97
|
+
// 身体:6 节淡墨弧,从头到尾弯曲
|
|
98
|
+
let px = 0, py = 0, a = 0; const segs = [];
|
|
99
|
+
for (let i = 0; i < 6; i++) { a += 0.2 + flex; const l = 13 - i * 1.2; px += Math.cos(a) * l; py += Math.sin(a) * l; segs.push([px, py, a, 11 - i * 1.3]); }
|
|
100
|
+
segs.forEach(([sx, sy, sa, sw], i) => { c.fillStyle = `rgba(30,28,26,${0.22 + i * 0.03})`; c.beginPath(); c.ellipse(sx, sy, 9, sw * 1.05, sa + 0.25, 0, Math.PI * 2); c.fill(); c.strokeStyle = 'rgba(20,18,16,.3)'; c.lineWidth = 2.4; c.beginPath(); c.ellipse(sx, sy, 9, sw * 1.05, sa + 0.25, -1.2, 1.2); c.stroke(); });
|
|
101
|
+
const tl = segs[5]; [-0.5, 0, 0.5].forEach(d => leaf(c, tl[0], tl[1], tl[2] + d + 0.4, 15, 6, 0.4));
|
|
102
|
+
// 头胸甲:淡墨+中间一笔焦墨
|
|
103
|
+
c.fillStyle = 'rgba(30,28,26,.33)'; c.beginPath(); c.ellipse(-10, -2, 17, 10, -0.15, 0, Math.PI * 2); c.fill();
|
|
104
|
+
c.fillStyle = 'rgba(10,10,10,.9)'; c.beginPath(); c.ellipse(-8, -3, 7, 3.2, -0.2, 0, Math.PI * 2); c.fill();
|
|
105
|
+
c.beginPath(); c.arc(-24, -8, 2.6, 0, Math.PI * 2); c.arc(-23, -1, 2.6, 0, Math.PI * 2); c.fill();
|
|
106
|
+
// 须:两长两短,波动
|
|
107
|
+
c.strokeStyle = 'rgba(10,10,10,.8)'; c.lineWidth = 1.1;
|
|
108
|
+
[[-1, 120, 0.9], [1, 105, 1.4], [-1, 40, 2.1], [1, 36, 2.8]].forEach(([sg, L, q]) => { c.beginPath(); c.moveTo(-26, -4); for (let i = 1; i <= 12; i++) { const u = i / 12; c.lineTo(-26 - u * L, -4 + sg * u * L * 0.18 + Math.sin(t * 5 + q + u * 4) * 6 * u); } c.stroke(); });
|
|
109
|
+
// 钳:长臂三节+钳
|
|
110
|
+
[[-0.35, 0], [0.1, 1]].forEach(([da, k]) => { c.strokeStyle = 'rgba(10,10,10,.75)'; c.lineWidth = 1.6; const sw2 = Math.sin(t * 4 + k * 2 + ph) * 0.15; let qx = -20, qy = 4; c.beginPath(); c.moveTo(qx, qy);
|
|
111
|
+
[[22, 2.4], [20, 2.6], [16, 2.9]].forEach(([l, aa]) => { qx += Math.cos(aa + da + sw2) * l; qy += Math.sin(aa + da + sw2) * l; c.lineTo(qx, qy); }); c.stroke();
|
|
112
|
+
c.fillStyle = 'rgba(10,10,10,.82)'; c.beginPath(); c.ellipse(qx - 6, qy + 2, 8, 3, 2.9 + da, 0, Math.PI * 2); c.fill(); });
|
|
113
|
+
// 腿
|
|
114
|
+
c.strokeStyle = 'rgba(20,20,20,.5)'; c.lineWidth = 1; for (let i = 0; i < 5; i++) { const sg = segs[Math.min(4, i)]; c.beginPath(); c.moveTo(sg[0] - 2, sg[1] + 5); c.lineTo(sg[0] - 6 + Math.sin(t * 12 + i) * 2, sg[1] + 14); c.stroke(); }
|
|
115
|
+
c.restore();
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// ---------- 猫(赭石没骨+留白+焦墨点斑+八大白眼) ----------
|
|
119
|
+
function catWash(g, K) {
|
|
120
|
+
g.fillStyle = '#c47a3c'; g.fill(K.body); g.fill(K.head);
|
|
121
|
+
g.lineCap = 'round'; g.lineJoin = 'round'; g.strokeStyle = '#c47a3c'; g.lineWidth = K.tailW; g.stroke(K.tail);
|
|
122
|
+
g.save(); g.globalCompositeOperation = 'destination-out'; g.fill(K.white); K.legs.forEach(l => g.fill(l));
|
|
123
|
+
g.beginPath(); g.ellipse(K.nose[0] - 22, K.nose[1] + 12, 36, 26, 0, 0, Math.PI * 2); g.fill(); g.restore();
|
|
124
|
+
}
|
|
125
|
+
function catInk(c, K, t, rev) {
|
|
126
|
+
const R_ = (pts, o) => brush(c, pts, { ...o, reveal: ss(o.d || 0, (o.d || 0) + 0.18, rev) });
|
|
127
|
+
// 背线、头顶:焦墨几笔
|
|
128
|
+
const b = K.bodyPts;
|
|
129
|
+
R_([b[5], b[4], b[3], b[2]], { w: 12, dry: 0.55, seed: 81, d: 0.12, tone: 0.9 });
|
|
130
|
+
R_([b[2], b[1], b[0]], { w: 8, dry: 0.7, seed: 82, d: 0.18, tone: 0.75 });
|
|
131
|
+
R_([b[6], b[7], b[8]], { w: 5, dry: 0.6, seed: 83, d: 0.2, tone: 0.55 });
|
|
132
|
+
K.stripes.forEach((s, i) => R_([s[0], [(s[0][0] + s[1][0]) / 2 + 3, (s[0][1] + s[1][1]) / 2], s[1]], { w: i < 3 ? 9 : 13, dry: 0.4, seed: 90 + i, d: 0.2 + i * 0.015, tone: 0.92, head: 0.2, tail: 0.6, bristles: 5 }));
|
|
133
|
+
if (rev < 0.25) return;
|
|
134
|
+
c.save(); c.globalAlpha = ss(0.25, 0.4, rev);
|
|
135
|
+
// 耳:两笔焦墨三角
|
|
136
|
+
c.fillStyle = 'rgba(14,12,10,.9)'; K.earInner.forEach(e => { c.beginPath(); c.moveTo(...e[0]); c.lineTo(...e[1]); c.lineTo(...e[2]); c.closePath(); c.fill(); });
|
|
137
|
+
// 头轮廓:一笔淡墨
|
|
138
|
+
c.strokeStyle = 'rgba(20,18,16,.55)'; c.lineWidth = 3; c.stroke(K.head);
|
|
139
|
+
// 八大式白眼:圆眶,瞳点顶到上方(白眼向天)
|
|
140
|
+
K.eyes.forEach((e, i) => { c.strokeStyle = 'rgba(10,10,10,.92)'; c.lineWidth = 2.6; c.beginPath(); c.ellipse(e.x, e.y, K.eyeR * 1.15, K.eyeR * (K.blink ? 0.15 : 1), 0, 0, Math.PI * 2); c.stroke();
|
|
141
|
+
if (!K.blink) { c.fillStyle = 'rgba(8,8,8,.95)'; c.beginPath(); c.arc(e.x + 2.5, e.y - K.eyeR * 0.55 + Math.sin(t * 2) * 1.2, K.eyeR * 0.42, 0, Math.PI * 2); c.fill(); } });
|
|
142
|
+
c.fillStyle = 'rgba(14,12,10,.9)'; c.beginPath(); c.ellipse(K.nose[0], K.nose[1], 6, 4, 0, 0, Math.PI * 2); c.fill();
|
|
143
|
+
c.strokeStyle = 'rgba(14,12,10,.8)'; c.lineWidth = 2; c.beginPath(); c.moveTo(...K.mouth[0]); c.quadraticCurveTo(...K.mouth[1], ...K.mouth[2]); c.stroke();
|
|
144
|
+
K.whiskers.forEach((w, i) => brush(c, [w[0], [(w[0][0] + w[1][0]) / 2, (w[0][1] + w[1][1]) / 2 - 2], w[1]], { w: 2.4, dry: 0.5, bristles: 3, seed: 99 + i, tone: 0.8, head: 0.05, tail: 0.6 }));
|
|
145
|
+
// 腿、爪:淡墨轻勾
|
|
146
|
+
c.strokeStyle = 'rgba(20,18,16,.38)'; c.lineWidth = 2; K.legs.forEach(l => c.stroke(l));
|
|
147
|
+
// 尾:焦墨环纹
|
|
148
|
+
const tp = K.tailPts; [5, 9, 13, 17].forEach((i, k) => { const p = tp[i], q = tp[i + 1], a = Math.atan2(q[1] - p[1], q[0] - p[0]) + Math.PI / 2; brush(c, [[p[0] - Math.cos(a) * 12, p[1] - Math.sin(a) * 12], [p[0] + Math.cos(a) * 12, p[1] + Math.sin(a) * 12]], { w: 8, dry: 0.3, bristles: 4, seed: 120 + k, tone: 0.85 }); });
|
|
149
|
+
c.restore();
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// ---------- 少女 ----------
|
|
153
|
+
function sleeveShape(G) {
|
|
154
|
+
const S = G.A.shoulder, E = G.A.elbow, Hd = G.A.hand;
|
|
155
|
+
const Wr = [lerp(E[0], Hd[0], 0.8), lerp(E[1], Hd[1], 0.8)];
|
|
156
|
+
const low = Math.max(S[1], E[1]) + 120;
|
|
157
|
+
return RIG.smooth([[S[0] + 22, S[1] - 18], [S[0] - 26, S[1] - 6], [E[0] - 22, E[1] - 6], [Wr[0] - 16, Wr[1] - 14], [Wr[0] + 14, Wr[1] + 18], [Wr[0] + 20, Math.max(Wr[1] + 40, low - 30)], [lerp(Wr[0], E[0], 0.5) + 30, low], [E[0] + 40, low - 10], [S[0] + 40, S[1] + 70]]);
|
|
158
|
+
}
|
|
159
|
+
function girlWash(g, G) {
|
|
160
|
+
g.fillStyle = '#6f8aa0'; [G.farSleeve, G.skirt, G.torso].forEach(p => g.fill(p));
|
|
161
|
+
g.save(); g.globalCompositeOperation = 'destination-out'; g.fill(G.bib); g.restore(); // 交领内衫留白
|
|
162
|
+
g.fillStyle = '#7d97ab'; g.fill(sleeveShape(G)); // 广袖与衣身同一层晕染(没骨),只靠线分开
|
|
163
|
+
}
|
|
164
|
+
function girlInk(c, G, t, rev, ch) {
|
|
165
|
+
const A = G.A;
|
|
166
|
+
SKIRT.forEach((s, i) => brush(c, s.p, { w: s.w, dry: s.dry, seed: 200 + i, tone: 0.78, reveal: ss(0.05 + i * 0.02, 0.25 + i * 0.02, rev), head: 0.08, tail: 0.5, bristles: 5 }));
|
|
167
|
+
// 腰带:胭脂红,两条垂带随动作摆(齐白石的一点红)
|
|
168
|
+
const wx = A.waist[0] - 40, wy = A.waist[1] - 8, sw = Math.sin(t * 3.4) * 10;
|
|
169
|
+
brush(c, [[1300, wy - 4], [1360, wy], [1420, wy - 2]], { w: 14, dry: 0.25, seed: 230, col: [190, 40, 40], tone: 0.85, reveal: ss(0.25, 0.4, rev) });
|
|
170
|
+
[[0, 0], [16, 1]].forEach(([o, k]) => brush(c, [[1400 + o, wy + 4], [1408 + o + sw * 0.4, wy + 70], [1404 + o + sw, wy + 150]], { w: 7, dry: 0.4, seed: 240 + k, col: [190, 40, 40], tone: 0.8, reveal: ss(0.3, 0.45, rev), tail: 0.6, bristles: 4 }));
|
|
171
|
+
if (rev < 0.12) return;
|
|
172
|
+
const al = ss(0.12, 0.32, rev);
|
|
173
|
+
c.save(); c.globalAlpha = al;
|
|
174
|
+
// 头发:藤黄晕+几笔淡墨发丝
|
|
175
|
+
c.globalCompositeOperation = 'multiply';
|
|
176
|
+
c.fillStyle = 'rgba(226,170,52,.75)'; [G.hairBack, G.bun, G.bangs].forEach(p => p && c.fill(p));
|
|
177
|
+
c.globalCompositeOperation = 'source-over';
|
|
178
|
+
c.strokeStyle = 'rgba(70,50,20,.55)'; c.lineWidth = 1.6; G.hairLines.forEach(h => c.stroke(h));
|
|
179
|
+
c.lineWidth = 1.4; c.strokeStyle = 'rgba(30,24,16,.7)'; c.stroke(G.hairBack); if (G.bun) c.stroke(G.bun);
|
|
180
|
+
// 发簪
|
|
181
|
+
const bc = G.bunSpiral; c.strokeStyle = 'rgba(14,12,10,.9)'; c.lineWidth = 3.5; c.beginPath(); c.moveTo(bc[0] - 36, bc[1] - 26); c.lineTo(bc[0] + 30, bc[1] + 16); c.stroke();
|
|
182
|
+
c.fillStyle = '#c0392b'; c.beginPath(); c.arc(bc[0] - 38, bc[1] - 28, 6, 0, Math.PI * 2); c.fill();
|
|
183
|
+
// 白描面部:细线勾脸,纸色留白
|
|
184
|
+
c.fillStyle = 'rgba(250,240,224,.9)'; c.fill(G.face); c.fillStyle = 'rgba(246,232,212,.85)'; c.fill(G.neck); c.strokeStyle = 'rgba(18,16,14,.6)'; c.lineWidth = 1.4; c.stroke(G.neck);
|
|
185
|
+
c.strokeStyle = 'rgba(18,16,14,.85)'; c.lineWidth = 1.8; c.stroke(G.face);
|
|
186
|
+
c.save(); c.clip(G.face); c.fillStyle = 'rgba(214,92,92,.16)'; c.filter = 'blur(5px)'; c.beginPath(); c.arc(G.cheek[0] - 4, G.cheek[1] + 2, 10, 0, Math.PI * 2); c.fill(); c.filter = 'none'; c.restore();
|
|
187
|
+
c.fillStyle = 'rgba(226,170,52,.75)'; c.fill(G.bangs); c.strokeStyle = 'rgba(30,24,16,.6)'; c.lineWidth = 1.3; c.stroke(G.bangs);
|
|
188
|
+
c.strokeStyle = 'rgba(12,10,8,.95)'; c.lineWidth = ch.blink ? 2 : 2.4; c.stroke(G.lid);
|
|
189
|
+
if (!ch.blink) { c.fillStyle = 'rgba(12,10,8,.95)'; c.beginPath(); c.ellipse(G.eye.x - 1, G.eye.y + 1.5, 3, 3.6, 0, 0, Math.PI * 2); c.fill(); }
|
|
190
|
+
c.lineWidth = 1.5; c.stroke(G.brow);
|
|
191
|
+
c.fillStyle = '#b8322c'; c.beginPath(); c.arc(G.lips[0][0] + 3, G.lips[0][1] + 3, 3.2, 0, Math.PI * 2); c.fill();
|
|
192
|
+
c.restore();
|
|
193
|
+
}
|
|
194
|
+
function girlArm(c, G, rev) {
|
|
195
|
+
const al = ss(0.12, 0.32, rev); if (al <= 0) return;
|
|
196
|
+
c.save(); c.globalAlpha = al;
|
|
197
|
+
// 广袖:花青淡彩一大片,垂坠
|
|
198
|
+
const sl = sleeveShape(G);
|
|
199
|
+
c.strokeStyle = 'rgba(18,16,14,.7)'; c.lineWidth = 2.2; c.stroke(sl);
|
|
200
|
+
// 手:白描
|
|
201
|
+
c.fillStyle = 'rgba(250,240,224,.95)'; c.fill(G.hand); c.strokeStyle = 'rgba(18,16,14,.8)'; c.lineWidth = 1.6; c.stroke(G.hand);
|
|
202
|
+
// 杯:白瓷,一圈青花
|
|
203
|
+
const cp = G.cup; c.save(); c.translate(cp.x, cp.y); c.rotate(cp.tilt);
|
|
204
|
+
c.beginPath(); c.moveTo(-cp.w / 2, 0); c.lineTo(-cp.w * 0.36, cp.h * 0.9); c.lineTo(cp.w * 0.36, cp.h * 0.9); c.lineTo(cp.w / 2, 0); c.closePath();
|
|
205
|
+
c.fillStyle = 'rgba(252,250,244,.96)'; c.fill(); c.strokeStyle = 'rgba(18,16,14,.85)'; c.lineWidth = 1.8; c.stroke();
|
|
206
|
+
c.strokeStyle = 'rgba(40,70,140,.75)'; c.lineWidth = 4; c.beginPath(); c.moveTo(-cp.w * 0.45, cp.h * 0.28); c.lineTo(cp.w * 0.45, cp.h * 0.28); c.stroke();
|
|
207
|
+
c.restore();
|
|
208
|
+
c.fillStyle = 'rgba(250,240,224,.95)'; c.beginPath(); c.arc(G.thumb[0], G.thumb[1], 6.5, 0, Math.PI * 2); c.fill(); c.strokeStyle = 'rgba(18,16,14,.8)'; c.lineWidth = 1.4; c.stroke();
|
|
209
|
+
c.restore();
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
return {
|
|
213
|
+
draw(c, lt, t) {
|
|
214
|
+
lt += 0.12; // 开场不从一张白纸开始:第 0 帧已经落下前几笔
|
|
215
|
+
const ch = KIT.choreo(lt, t);
|
|
216
|
+
const rev = clamp(lt / 0.45); // 开场「画出来」
|
|
217
|
+
const grow = ss(0, 1.15, lt); // 墨晕外扩
|
|
218
|
+
c.drawImage(paper(), 0, 0);
|
|
219
|
+
// 晕染:远山+朱日
|
|
220
|
+
washLayer(c, 'mtn', ss(0, 0.3, lt) * (0.6 + 0.4 * grow), mountains, { blur: 3, halo: 14, haloA: 0.3 });
|
|
221
|
+
c.save(); c.globalCompositeOperation = 'multiply'; c.globalAlpha = ss(0.1, 0.3, lt); c.filter = `blur(${2 + grow * 3}px)`; c.fillStyle = '#d8553f'; c.beginPath(); c.arc(700, 230, 30 + grow * 3, 0, Math.PI * 2); c.fill(); c.filter = 'none'; c.restore();
|
|
222
|
+
// 雾带:纸色横向晕带缓缓左移,远山时隐时现
|
|
223
|
+
c.save(); c.beginPath(); c.rect(366, 132, 428, 428); c.clip(); c.filter = 'blur(14px)';
|
|
224
|
+
[[420, 46, 0], [500, 34, 1], [330, 28, 2], [460, 30, 3]].forEach(([y, h, k]) => { const x = 900 - ((lt * (150 + k * 40) + k * 230) % 900); c.fillStyle = `rgba(242,234,214,${0.72 * ss(0.15, 0.4, lt)})`; c.beginPath(); c.ellipse(x, y, 230, h, 0, 0, Math.PI * 2); c.fill(); });
|
|
225
|
+
c.filter = 'none'; c.restore();
|
|
226
|
+
// 一只八大式小鸟掠过窗外(两笔翅,每 0.12s 扇一次)
|
|
227
|
+
if (lt > 0.25) { const bx = 820 - (lt - 0.25) * 420, by = 470 - Math.sin(lt * 3) * 26, fl = Math.sin(lt * 52) ;
|
|
228
|
+
c.save(); c.beginPath(); c.rect(366, 132, 428, 428); c.clip(); c.fillStyle = 'rgba(14,12,10,.9)';
|
|
229
|
+
c.beginPath(); c.ellipse(bx, by, 11, 6, -0.2, 0, Math.PI * 2); c.fill(); c.beginPath(); c.arc(bx - 11, by - 4, 5, 0, Math.PI * 2); c.fill();
|
|
230
|
+
leaf(c, bx - 2, by - 2, -1.2 - fl * 0.7, 28, 9, 0.9); leaf(c, bx + 4, by - 1, -0.5 - fl * 0.5, 24, 8, 0.75);
|
|
231
|
+
c.fillStyle = '#f2ead6'; c.beginPath(); c.arc(bx - 13, by - 5, 2, 0, Math.PI * 2); c.fill(); c.restore(); }
|
|
232
|
+
// 静态笔触(写完就缓存)
|
|
233
|
+
const stat = (c2, rv) => { WIN.forEach((s, i) => brush(c2, s.p, { w: s.w, dry: s.dry, seed: 10 + i, reveal: ss(s.d, s.d + s.l, rv), tone: s.tone || 0.88 })); TABLE.forEach((s, i) => brush(c2, s.p, { w: s.w, dry: s.dry, seed: 30 + i, reveal: ss(s.d, s.d + s.l, rv), tone: s.tone || 0.88 })); };
|
|
234
|
+
if (rev < 1) stat(c, rev); else c.drawImage(P.cached('ink_static', W, H, g => stat(g, 1)), 0, 0);
|
|
235
|
+
bamboo(c, t, rev);
|
|
236
|
+
// 挂轴+虾(三只,沿各自弧线游)
|
|
237
|
+
c.save(); c.globalAlpha = ss(0.15, 0.35, lt); scrollStatic(c);
|
|
238
|
+
c.beginPath(); c.rect(1580, 290, 190, 540); c.clip();
|
|
239
|
+
[[1716, 450, 0.5, 0], [1700, 700, 1.4, 1]].forEach(([x, y, a0, k]) => { const u = lt * 1.6 + k * 2; shrimp(c, x - 26 * Math.sin(u * 1.5) - lt * 40, y + Math.sin(u * 2) * 16 - lt * 30, -0.35 + a0 * 0.1 + Math.sin(u * 1.5) * 0.18, 1.45, t, k * 2); });
|
|
240
|
+
c.restore();
|
|
241
|
+
// 猫:赭石晕染 → 焦墨
|
|
242
|
+
const K = RIG.cat({ tail: ch.tail, blink: ch.blink, breathe: ch.breathe });
|
|
243
|
+
c.save(); const ks = new Path2D(); ks.addPath(K.body); ks.addPath(K.head); c.clip(ks); c.drawImage(paper(), 0, 0); c.restore(); // 猫身下先补回纸色:窗台墨线不透过赭石
|
|
244
|
+
washLayer(c, 'cat', ss(0.02, 0.3, lt) * (0.7 + 0.3 * grow), g => catWash(g, K), { blur: 2.5, halo: 9, haloA: 0.28, alpha: 0.78 });
|
|
245
|
+
catInk(c, K, t, rev);
|
|
246
|
+
// 少女:花青淡彩 → 白描与衣纹
|
|
247
|
+
const G = RIG.girl({ cup: ch.cup, sip: ch.sip, breathe: ch.breathe, hair: 'bun' });
|
|
248
|
+
c.save(); const gs = new Path2D(); [G.skirt, G.torso, G.farSleeve].forEach(p => gs.addPath(p)); c.clip(gs); c.drawImage(paper(), 0, 0); c.restore(); // 桌腿、桌面不透过衣裙
|
|
249
|
+
washLayer(c, 'girl', ss(0.0, 0.3, lt) * (0.7 + 0.3 * grow), g => girlWash(g, G), { blur: 2.5, halo: 12, haloA: 0.24, alpha: 0.6 });
|
|
250
|
+
girlInk(c, G, t, rev, ch);
|
|
251
|
+
girlArm(c, G, rev);
|
|
252
|
+
// 热气:两缕淡墨游丝
|
|
253
|
+
if (lt > 0.3) { c.save(); c.globalAlpha = ss(0.3, 0.5, lt);
|
|
254
|
+
[0, 1].forEach(k => { const pts = []; for (let i = 0; i <= 8; i++) { const q = i / 8; pts.push([G.cup.x - 8 + k * 14 + Math.sin(t * 3.5 + q * 5 + k * 2) * 10 * q - q * 40 * ch.cup, G.cup.y - 8 - q * 80]); } brush(c, pts, { w: 3, dry: 0.7, bristles: 3, seed: 300 + k + P.boilSeed(t, 10), tone: 0.45, head: 0.05, tail: 0.8 }); });
|
|
255
|
+
c.restore(); }
|
|
256
|
+
},
|
|
257
|
+
label(c, lt) {
|
|
258
|
+
const a = ss(0.0, 0.25, lt);
|
|
259
|
+
KIT.label(c, { title: '水墨写意', sub: '八大山人 · 齐白石', tFont: '80px "LXGWWenKai-500"', sFont: '30px "LXGWWenKai-500"', tCol: `rgba(14,12,10,${0.92 * a})`, sCol: `rgba(40,34,28,${0.85 * a})`, spacing: 6 });
|
|
260
|
+
// 钤印:朱文方印「白石」,0.32s 盖下(先放大再压实,印泥略洇)
|
|
261
|
+
const q = ss(0.3, 0.4, lt); if (q <= 0) return;
|
|
262
|
+
const s = 1.5 - 0.5 * ease.out(q);
|
|
263
|
+
const seal = P.cached('ink_seal', 80, 80, g => { g.translate(40, 40);
|
|
264
|
+
g.fillStyle = '#c4281e'; g.fillRect(-34, -34, 68, 68);
|
|
265
|
+
g.globalCompositeOperation = 'destination-out'; g.font = '30px "LXGWWenKai-500"'; g.textAlign = 'center'; g.textBaseline = 'middle';
|
|
266
|
+
g.fillText('白', 0, -14); g.fillText('石', 0, 16);
|
|
267
|
+
const r = rng(7); for (let i = 0; i < 40; i++) g.fillRect(-34 + r() * 68, -34 + r() * 68, 1 + r() * 3, 1 + r() * 2); // 印面斑驳
|
|
268
|
+
});
|
|
269
|
+
c.save(); c.translate(1500, 98); c.scale(s, s); c.globalAlpha = Math.min(1, q * 1.6); c.globalCompositeOperation = 'multiply';
|
|
270
|
+
c.drawImage(seal, -40, -40); c.restore();
|
|
271
|
+
},
|
|
272
|
+
};
|
|
273
|
+
})();
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
// 克里姆特金色时期(《吻》《阿黛尔·布洛赫-鲍尔肖像 I》,1907)——纯代码。
|
|
2
|
+
// 管线:①金箔墙(逐像素:斑驳+拉丝+金粉,缓存)→ ②窗:《白桦林》点彩风景 + 黑白方格金框
|
|
3
|
+
// → ③花草地(《吻》崖边的花毯)→ ④桌:维也纳工坊黑白方格 → ⑤猫:橘色螺旋纹+白色小圆环(装饰化)
|
|
4
|
+
// → ⑥少女:金袍(眼形纹、螺旋、同心圆、黑白长方块,平面)+ 写实的脸与手(渐变体积)
|
|
5
|
+
// → ⑦会动的:金粉闪烁、斜向流光扫过、袍上眼睛轮流眨、螺旋转、花点头、窗里落叶
|
|
6
|
+
SCENES['18_klimt'] = (() => {
|
|
7
|
+
const W = 1920, H = 1080, { clamp, lerp, rng } = U, P = PAINT;
|
|
8
|
+
const { ss } = U;
|
|
9
|
+
const C = { goldLo: [120, 78, 18], gold: [196, 148, 52], goldHi: [246, 216, 128], ink: '#1d140c', skin: '#f2d6c2' };
|
|
10
|
+
|
|
11
|
+
// ---------- 金箔(逐像素) ----------
|
|
12
|
+
const goldTex = () => P.cached('kl_gold', W, H, (g) => {
|
|
13
|
+
const img = g.createImageData(W, H), d = img.data, r = rng(19);
|
|
14
|
+
for (let y = 0; y < H; y++) for (let x = 0; x < W; x++) {
|
|
15
|
+
const mott = P.fbm(x * 0.004 + 3, y * 0.004, 4), brush = P.noise(x * 0.003, y * 0.08) * 0.45, gr = (r() - 0.5) * 0.1;
|
|
16
|
+
let f = clamp(0.5 + mott * 0.55 + brush * 0.5 + gr);
|
|
17
|
+
const lo = C.goldLo, mi = C.gold, hi = C.goldHi; let col = f < 0.5 ? P.mix(lo, mi, f * 2) : P.mix(mi, hi, (f - 0.5) * 2);
|
|
18
|
+
const i = (y * W + x) * 4; d[i] = col[0]; d[i + 1] = col[1]; d[i + 2] = col[2]; d[i + 3] = 255;
|
|
19
|
+
}
|
|
20
|
+
g.putImageData(img, 0, 0);
|
|
21
|
+
// 金箔接缝:一片片贴上去的方块
|
|
22
|
+
g.strokeStyle = 'rgba(90,55,10,.18)'; g.lineWidth = 1; for (let y = 0; y < H; y += 96) for (let x = (y / 96 % 2) * 48; x < W; x += 96) g.strokeRect(x + 0.5, y + 0.5, 96, 96);
|
|
23
|
+
});
|
|
24
|
+
// 墙:金箔压暗成《吻》的褐金斑驳底,撒金粉
|
|
25
|
+
const wall = () => P.cached('kl_wall', W, H, (g) => {
|
|
26
|
+
g.drawImage(goldTex(), 0, 0);
|
|
27
|
+
g.globalCompositeOperation = 'multiply';
|
|
28
|
+
const img = P.cached('kl_mott', 480, 270, (h) => { const im = h.createImageData(480, 270), d = im.data; for (let y = 0; y < 270; y++) for (let x = 0; x < 480; x++) { const n = P.fbm(x * 0.012 + 9, y * 0.012, 4); const v = clamp(0.62 + n * 0.7); const i = (y * 480 + x) * 4; d[i] = 255 * v; d[i + 1] = 235 * v; d[i + 2] = 190 * v; d[i + 3] = 255; } h.putImageData(im, 0, 0); });
|
|
29
|
+
g.drawImage(img, 0, 0, W, H);
|
|
30
|
+
g.globalCompositeOperation = 'source-over';
|
|
31
|
+
const r = rng(23); for (let i = 0; i < 9000; i++) { const x = r() * W, y = r() * H, s = 0.6 + r() * 2.2; g.fillStyle = r() < 0.7 ? `rgba(250,226,140,${0.3 + r() * 0.5})` : `rgba(70,40,10,${0.2 + r() * 0.3})`; g.fillRect(x, y, s, s); }
|
|
32
|
+
});
|
|
33
|
+
const DUST = (() => { const r = rng(31), o = []; for (let i = 0; i < 420; i++) o.push([r() * W, r() * H, 1.5 + r() * 3.5, r() * 6.28, 3 + r() * 6]); return o; })();
|
|
34
|
+
|
|
35
|
+
// ---------- 窗:克里姆特《白桦林》 ----------
|
|
36
|
+
const windowArt = () => P.cached('kl_win', W, H, (g) => {
|
|
37
|
+
g.save(); g.beginPath(); g.rect(370, 140, 420, 400); g.clip();
|
|
38
|
+
g.fillStyle = '#5a3a1c'; g.fillRect(370, 140, 420, 400);
|
|
39
|
+
const r = rng(41);
|
|
40
|
+
for (let i = 0; i < 2600; i++) { const x = 370 + r() * 420, y = 140 + r() * 400; const deep = (y - 140) / 400;
|
|
41
|
+
const pal = deep < 0.65 ? ['#c86a2a', '#e09a3a', '#a84c22', '#d8b04a', '#7a8a3a', '#e8c070'] : ['#b8502a', '#d8803a', '#8a3a1a', '#e0a050', '#c86a7a'];
|
|
42
|
+
g.fillStyle = pal[(r() * pal.length) | 0]; g.beginPath(); g.ellipse(x, y, 3 + r() * 5, 2 + r() * 4, r() * 3, 0, Math.PI * 2); g.fill(); }
|
|
43
|
+
[[410, 10], [470, 14], [545, 9], [612, 16], [690, 11], [748, 13]].forEach(([x, w], k) => {
|
|
44
|
+
g.fillStyle = '#efe8da'; g.fillRect(x, 140, w, 400); g.fillStyle = '#2a2018';
|
|
45
|
+
for (let y = 150; y < 540; y += 14 + (k * 7 + y) % 19) g.fillRect(x + ((y * 3) % w) * 0.4, y, w * (0.3 + ((y * 7) % 10) / 20), 3 + (y % 4)); });
|
|
46
|
+
g.restore();
|
|
47
|
+
// 金框+黑白小方格(维也纳分离派)
|
|
48
|
+
g.fillStyle = '#d6a845'; g.fillRect(346, 116, 468, 24); g.fillRect(346, 540, 468, 26); g.fillRect(346, 116, 24, 450); g.fillRect(790, 116, 24, 450);
|
|
49
|
+
for (let x = 350; x < 812; x += 12) { g.fillStyle = ((x / 12) | 0) % 2 ? '#111' : '#f4efe2'; g.fillRect(x, 122, 10, 10); g.fillRect(x, 549, 10, 10); }
|
|
50
|
+
for (let y = 140; y < 540; y += 12) { g.fillStyle = ((y / 12) | 0) % 2 ? '#111' : '#f4efe2'; g.fillRect(352, y, 10, 10); g.fillRect(798, y, 10, 10); }
|
|
51
|
+
g.strokeStyle = C.ink; g.lineWidth = 3; g.strokeRect(346, 116, 468, 450); g.strokeRect(370, 140, 420, 400);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
// ---------- 地:花草地 ----------
|
|
55
|
+
const FLOW = (() => { const r = rng(57), o = []; for (let i = 0; i < 260; i++) { const y = 712 + Math.pow(r(), 0.8) * 370; o.push([r() * W, y, 6 + (y - 700) / 380 * 14 * (0.6 + r() * 0.6), (r() * 5) | 0, r() * 6.28]); } return o.sort((a, b) => a[1] - b[1]); })();
|
|
56
|
+
const FCOL = [['#d8402a', '#f4d65a'], ['#3a5ab0', '#f2eee0'], ['#f2eee0', '#d8402a'], ['#8a4ab0', '#f4d65a'], ['#e08aa0', '#3a5ab0']];
|
|
57
|
+
function meadow(c, t) {
|
|
58
|
+
c.drawImage(P.cached('kl_meadowBase', W, H, (g) => { const gr = g.createLinearGradient(0, 700, 0, H); gr.addColorStop(0, '#2c4a2a'); gr.addColorStop(1, '#1a3020'); g.fillStyle = gr; g.fillRect(0, 700, W, H - 700);
|
|
59
|
+
const r = rng(61); for (let i = 0; i < 1600; i++) { g.strokeStyle = r() < 0.5 ? '#4f7a3a' : '#7aa04a'; g.lineWidth = 2; const x = r() * W, y = 705 + r() * 380; g.beginPath(); g.moveTo(x, y); g.lineTo(x + (r() - .5) * 8, y - 8 - r() * 14); g.stroke(); }
|
|
60
|
+
g.fillStyle = '#d6a845'; g.fillRect(0, 696, W, 8); }), 0, 0);
|
|
61
|
+
FLOW.forEach(([x, y, s, k, ph]) => { const nod = Math.sin(t * 4.2 + ph) * s * 0.35, fc = FCOL[k];
|
|
62
|
+
c.fillStyle = fc[0]; c.beginPath(); c.arc(x + nod, y, s, 0, Math.PI * 2); c.fill();
|
|
63
|
+
c.strokeStyle = fc[1]; c.lineWidth = Math.max(1.5, s * 0.18); c.beginPath(); c.arc(x + nod, y, s * 0.62, 0, Math.PI * 2); c.stroke();
|
|
64
|
+
c.fillStyle = fc[1]; c.beginPath(); c.arc(x + nod, y, s * 0.25, 0, Math.PI * 2); c.fill(); });
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// ---------- 桌:黑白方格(约瑟夫·霍夫曼) ----------
|
|
68
|
+
const table = () => P.cached('kl_table', W, H, (g) => {
|
|
69
|
+
g.fillStyle = '#111'; g.fillRect(810, 616, 400, 36); g.fillRect(836, 652, 348, 50); g.fillRect(842, 700, 26, 205); g.fillRect(1156, 700, 26, 205);
|
|
70
|
+
g.fillStyle = '#f4efe2'; for (let x = 814; x < 1206; x += 16) for (let y = 620; y < 648; y += 16) if (((x - 814) / 16 + (y - 620) / 16) % 2 === 0) g.fillRect(x, y, 12, 12);
|
|
71
|
+
for (let x = 842; x < 1180; x += 22) g.fillRect(x, 662, 14, 30);
|
|
72
|
+
for (let y = 706; y < 900; y += 20) { g.fillRect(848, y, 14, 12); g.fillRect(1162, y, 14, 12); }
|
|
73
|
+
g.fillStyle = '#d6a845'; g.fillRect(810, 612, 400, 6); g.fillRect(836, 698, 348, 5);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
// ---------- 纹样 ----------
|
|
77
|
+
function spiral(c, x, y, R, rot, col, lw = 2.2) { c.strokeStyle = col; c.lineWidth = lw; c.beginPath(); for (let a = 0; a < Math.PI * 5.2; a += 0.22) { const rr = R * a / (Math.PI * 5.2); const px = x + Math.cos(a + rot) * rr, py = y + Math.sin(a + rot) * rr; a ? c.lineTo(px, py) : c.moveTo(px, py); } c.stroke(); }
|
|
78
|
+
function eye(c, x, y, L, open, iris) {
|
|
79
|
+
const h = L * 0.42 * open;
|
|
80
|
+
c.fillStyle = '#f6f0e0'; c.strokeStyle = C.ink; c.lineWidth = 2.2;
|
|
81
|
+
c.beginPath(); c.moveTo(x - L / 2, y); c.quadraticCurveTo(x, y - h * 2, x + L / 2, y); c.quadraticCurveTo(x, y + h * 2, x - L / 2, y); c.closePath(); c.fill(); c.stroke();
|
|
82
|
+
if (open > 0.25) { c.save(); c.clip(); c.fillStyle = iris; c.beginPath(); c.arc(x, y, L * 0.22, 0, Math.PI * 2); c.fill(); c.fillStyle = C.ink; c.beginPath(); c.arc(x, y, L * 0.1, 0, Math.PI * 2); c.fill(); c.restore(); }
|
|
83
|
+
c.beginPath(); c.moveTo(x - L / 2 - 4, y); c.quadraticCurveTo(x, y - L * 0.42 * 2 - 3, x + L / 2 + 4, y); c.stroke(); // 上眼睑弧(不随开合,像埃及荷鲁斯之眼的勾)
|
|
84
|
+
}
|
|
85
|
+
const ROBE = (() => { const r = rng(71), o = []; for (let i = 0; i < 150; i++) { const x = 1090 + r() * 380, y = 420 + r() * 520; o.push({ x, y, k: r(), s: 0.7 + r() * 0.6, ph: r() * 6.28 }); } return o; })();
|
|
86
|
+
function robePattern(c, t, lt) {
|
|
87
|
+
c.drawImage(goldTex(), 0, 0);
|
|
88
|
+
// 下摆的黑白长方块(《吻》男子袍的语言,竖向排)
|
|
89
|
+
const r = rng(77); for (let i = 0; i < 60; i++) { const x = 1100 + r() * 360, y = 640 + r() * 300, w = 10 + r() * 14, h = 26 + r() * 40; c.fillStyle = r() < 0.55 ? '#141010' : '#f4efe2'; c.fillRect(x, y, w, h); c.strokeStyle = '#d6a845'; c.lineWidth = 2; c.strokeRect(x, y, w, h); }
|
|
90
|
+
ROBE.forEach(({ x, y, k, s, ph }, i) => {
|
|
91
|
+
if (k < 0.3) { // 同心圆(彩色)
|
|
92
|
+
const R = 16 * s, cols = [['#c03a2a', '#f4efe2', '#2a4a9a'], ['#2a4a9a', '#d6a845', '#c03a2a'], ['#6a3a8a', '#f4efe2', '#d6a845']][i % 3];
|
|
93
|
+
cols.forEach((col, j) => { c.fillStyle = col; c.beginPath(); c.arc(x, y, R * (1 - j * 0.3), 0, Math.PI * 2); c.fill(); });
|
|
94
|
+
} else if (k < 0.62) { // 深褐底金螺旋,转
|
|
95
|
+
c.fillStyle = '#3a2410'; c.beginPath(); c.arc(x, y, 15 * s, 0, Math.PI * 2); c.fill();
|
|
96
|
+
spiral(c, x, y, 13 * s, t * 5 * (i % 2 ? 1 : -1) + ph, '#f2cf6a', 2);
|
|
97
|
+
} else if (k < 0.84) { // 眼形纹:轮流眨
|
|
98
|
+
const bl = Math.sin(t * 2.2 + ph * 3); const open = bl > 0.86 ? clamp(1 - (bl - 0.86) / 0.07) : 1;
|
|
99
|
+
eye(c, x, y, 34 * s, Math.max(0.08, open), ['#2a4a9a', '#2a7a5a', '#8a2a2a'][i % 3]);
|
|
100
|
+
} else { // 小三角+圆点簇
|
|
101
|
+
c.fillStyle = '#f4efe2'; for (let j = 0; j < 5; j++) { c.beginPath(); c.arc(x + Math.cos(j * 1.26) * 9 * s, y + Math.sin(j * 1.26) * 9 * s, 3.2 * s, 0, Math.PI * 2); c.fill(); }
|
|
102
|
+
c.fillStyle = '#c03a2a'; c.beginPath(); c.arc(x, y, 4 * s, 0, Math.PI * 2); c.fill();
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// ---------- 写实的脸与手:柔和渐变体积,几乎无轮廓线(与平面金袍对比) ----------
|
|
108
|
+
function skin(c, path, cx, cy, R, lightDx = -0.35, lightDy = -0.4) {
|
|
109
|
+
const g = c.createRadialGradient(cx + R * lightDx, cy + R * lightDy, R * 0.1, cx, cy, R * 1.25);
|
|
110
|
+
g.addColorStop(0, '#fbe8da'); g.addColorStop(0.5, '#f0cfb8'); g.addColorStop(0.85, '#d8a88c'); g.addColorStop(1, '#b88068');
|
|
111
|
+
c.fillStyle = g; c.fill(path);
|
|
112
|
+
}
|
|
113
|
+
function face(c, G, ch) {
|
|
114
|
+
skin(c, G.neck, G.A.neck[0] - 8, G.A.neck[1] - 10, 36, -0.5, -0.6);
|
|
115
|
+
c.save(); c.clip(G.neck); c.fillStyle = 'rgba(120,70,50,.28)'; c.filter = 'blur(6px)'; c.beginPath(); c.ellipse(G.A.chin[0] + 20, G.A.chin[1] + 8, 40, 14, 0, 0, Math.PI * 2); c.fill(); c.filter = 'none'; c.restore();
|
|
116
|
+
skin(c, G.face, G.A.headC[0] - 20, G.A.headC[1], 72);
|
|
117
|
+
c.save(); c.clip(G.face); c.filter = 'blur(7px)';
|
|
118
|
+
c.fillStyle = 'rgba(232,120,110,.38)'; c.beginPath(); c.arc(G.cheek[0] - 6, G.cheek[1] - 2, 15, 0, Math.PI * 2); c.fill();
|
|
119
|
+
c.fillStyle = 'rgba(150,90,70,.3)'; c.beginPath(); c.ellipse(G.eye.x + 2, G.eye.y - 2, 14, 8, 0, 0, Math.PI * 2); c.fill(); // 眼窝阴影
|
|
120
|
+
c.filter = 'none'; c.restore();
|
|
121
|
+
// 眼:睫毛浓、半垂(克里姆特女人的倦眼)
|
|
122
|
+
c.strokeStyle = '#3a2216'; c.lineWidth = 2.6; c.stroke(G.lid);
|
|
123
|
+
if (!ch.blink) { c.fillStyle = '#4a3020'; c.beginPath(); c.ellipse(G.eye.x - 1, G.eye.y + 2, 3.4, 3.6, 0, 0, Math.PI * 2); c.fill(); c.fillStyle = 'rgba(255,255,255,.85)'; c.beginPath(); c.arc(G.eye.x - 2.4, G.eye.y + 0.6, 1.1, 0, Math.PI * 2); c.fill(); }
|
|
124
|
+
G.lashes.forEach(l => { c.beginPath(); c.moveTo(...l[0]); c.lineTo(...l[1]); c.lineWidth = 1.8; c.stroke(); });
|
|
125
|
+
c.strokeStyle = 'rgba(120,80,40,.8)'; c.lineWidth = 2; c.stroke(G.brow);
|
|
126
|
+
const lp = G.lips; c.fillStyle = '#b8323a'; c.beginPath(); c.moveTo(...lp[0]); c.quadraticCurveTo(lp[1][0] + 2, lp[1][1] - 2, lp[1][0], lp[1][1]); c.quadraticCurveTo(lp[1][0] + 1, lp[2][1] + 2, lp[2][0], lp[2][1]); c.closePath(); c.fill();
|
|
127
|
+
c.strokeStyle = 'rgba(150,90,70,.55)'; c.lineWidth = 1.2; c.stroke(G.face);
|
|
128
|
+
}
|
|
129
|
+
function hair(c, G, t) {
|
|
130
|
+
const hg = c.createLinearGradient(G.A.headTop[0], G.A.headTop[1], G.A.nape[0], G.A.nape[1] + 30); hg.addColorStop(0, '#f6dc8a'); hg.addColorStop(0.5, '#dcae4a'); hg.addColorStop(1, '#a8782a');
|
|
131
|
+
c.fillStyle = hg; [G.hairBack, G.bun].forEach(p => p && c.fill(p));
|
|
132
|
+
c.strokeStyle = 'rgba(120,80,20,.55)'; c.lineWidth = 1.3; G.hairLines.forEach(h => c.stroke(h));
|
|
133
|
+
if (G.bun) { spiral(c, G.bunSpiral[0], G.bunSpiral[1], 26, 0.5, 'rgba(130,90,25,.75)', 1.6); }
|
|
134
|
+
}
|
|
135
|
+
// 花冠:发间一串小花(《吻》),微微转
|
|
136
|
+
function wreath(c, G, t) {
|
|
137
|
+
const A = G.A, pts = [[A.headTop[0] - 40, A.headTop[1] + 18], [A.headTop[0] - 8, A.headTop[1] + 2], [A.headTop[0] + 28, A.headTop[1] + 6], [A.headTop[0] + 60, A.headTop[1] + 22], [A.headTop[0] + 82, A.headTop[1] + 50]];
|
|
138
|
+
pts.forEach(([x, y], k) => { const fc = FCOL[k % 5], rr = 11; c.save(); c.translate(x, y); c.rotate(t * 1.5 + k);
|
|
139
|
+
c.fillStyle = fc[0]; for (let j = 0; j < 5; j++) { c.beginPath(); c.arc(Math.cos(j * 1.256) * rr * 0.6, Math.sin(j * 1.256) * rr * 0.6, rr * 0.5, 0, Math.PI * 2); c.fill(); }
|
|
140
|
+
c.fillStyle = fc[1]; c.beginPath(); c.arc(0, 0, rr * 0.35, 0, Math.PI * 2); c.fill(); c.restore(); });
|
|
141
|
+
}
|
|
142
|
+
function bangs(c, G) {
|
|
143
|
+
const hg = c.createLinearGradient(G.A.forehead[0], G.A.forehead[1] - 20, G.A.forehead[0] + 70, G.A.forehead[1] + 40); hg.addColorStop(0, '#f8e098'); hg.addColorStop(1, '#c89a3a');
|
|
144
|
+
c.fillStyle = hg; c.fill(G.bangs); c.strokeStyle = 'rgba(120,80,20,.5)'; c.lineWidth = 1.2; c.stroke(G.bangs);
|
|
145
|
+
G.locks.forEach(h => { c.strokeStyle = '#c89a3a'; c.lineWidth = 6; c.stroke(h); });
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// ---------- 猫 ----------
|
|
149
|
+
function cat(c, K, t) {
|
|
150
|
+
const L = P.scratch('kl_cat'), g = L.getContext('2d'); g.reset();
|
|
151
|
+
RIG.drawCat(g, K, { orange: '#d8873a', white: '#f6ecd8', stripe: '#a8501a', line: '#3a2414', lw: 3, eye: '#5aa04a' });
|
|
152
|
+
// 橘色区:金螺旋+红点(装饰化毛色)
|
|
153
|
+
g.save(); g.globalCompositeOperation = 'source-atop';
|
|
154
|
+
const r = rng(91); for (let i = 0; i < 46; i++) { const x = 420 + r() * 260, y = 560 + r() * 340; const inWhite = g.isPointInPath(K.white, x, y); if (inWhite) { g.strokeStyle = ['#3a5ab0', '#d8402a', '#d6a845'][i % 3]; g.lineWidth = 2.4; g.beginPath(); g.arc(x, y, 6, 0, Math.PI * 2); g.stroke(); } else if (g.isPointInPath(K.body, x, y) && !g.isPointInPath(K.head, x, y)) { spiral(g, x, y, 9, t * 2.5 + i, '#f2cf6a', 1.8); } }
|
|
155
|
+
g.restore();
|
|
156
|
+
c.drawImage(L, 0, 0);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return {
|
|
160
|
+
draw(c, lt, t) {
|
|
161
|
+
const ch = KIT.choreo(lt, t);
|
|
162
|
+
c.drawImage(wall(), 0, 0);
|
|
163
|
+
// 金粉闪烁(四角星),并缓缓上浮,保证每帧都在动
|
|
164
|
+
c.save(); c.globalCompositeOperation = 'lighter';
|
|
165
|
+
DUST.forEach(([x0, y0, s, ph, sp]) => { const x = x0 + Math.sin(t * 0.8 + ph) * 14, y = ((y0 - t * 26) % H + H) % H; const tw = Math.sin(t * sp + ph); if (tw < 0.55) return; const a = (tw - 0.55) / 0.45, R = s * (0.6 + a * 1.1);
|
|
166
|
+
c.fillStyle = `rgba(255,236,160,${0.8 * a})`; c.beginPath(); c.moveTo(x, y - R * 2); c.lineTo(x + R * 0.35, y - R * 0.35); c.lineTo(x + R * 2, y); c.lineTo(x + R * 0.35, y + R * 0.35); c.lineTo(x, y + R * 2); c.lineTo(x - R * 0.35, y + R * 0.35); c.lineTo(x - R * 2, y); c.lineTo(x - R * 0.35, y - R * 0.35); c.closePath(); c.fill(); });
|
|
167
|
+
c.restore();
|
|
168
|
+
// 金箔碎片飘落(《吻》背景里的金屑):翻面的小方块和小圆片,保证每一帧都在动
|
|
169
|
+
P.particles(34, 77, t, { x0: 0, x1: W, y0: -30, y1: 720, speed: 150, drift: 36, life: 3.2 }).forEach(p => { c.save(); c.translate(p.x, p.y); c.rotate(p.a); c.scale(1, Math.cos(t * 5 + p.i));
|
|
170
|
+
const s2 = 7 + p.s * 8, g2 = c.createLinearGradient(-s2, -s2, s2, s2); g2.addColorStop(0, '#fbe6a0'); g2.addColorStop(1, '#a8741e'); c.fillStyle = g2;
|
|
171
|
+
if (p.i % 3) c.fillRect(-s2, -s2, s2 * 2, s2 * 2); else { c.beginPath(); c.arc(0, 0, s2, 0, Math.PI * 2); c.fill(); } c.strokeStyle = 'rgba(70,40,10,.6)'; c.lineWidth = 1.2; c.strokeRect && (p.i % 3) && c.strokeRect(-s2, -s2, s2 * 2, s2 * 2); c.restore(); });
|
|
172
|
+
// 窗+落叶
|
|
173
|
+
c.drawImage(windowArt(), 0, 0);
|
|
174
|
+
c.save(); c.beginPath(); c.rect(370, 140, 420, 400); c.clip();
|
|
175
|
+
P.particles(14, 5, t, { x0: 380, x1: 780, y0: 130, y1: 560, speed: 120, drift: 22, life: 2.4 }).forEach(p => { c.save(); c.translate(p.x, p.y); c.rotate(p.a); c.scale(1, Math.cos(t * 6 + p.i)); c.fillStyle = ['#e8a83a', '#d8603a', '#f2d070'][p.i % 3]; c.beginPath(); c.ellipse(0, 0, 9, 5, 0, 0, Math.PI * 2); c.fill(); c.restore(); });
|
|
176
|
+
c.restore();
|
|
177
|
+
meadow(c, t);
|
|
178
|
+
c.drawImage(table(), 0, 0);
|
|
179
|
+
// 流光:斜向亮带匀速扫过整面金墙(角色在之后画,自然挡住)
|
|
180
|
+
const sweep = (c2, x0) => { const gr = c2.createLinearGradient(x0 - 260, 0, x0 + 260, 0); gr.addColorStop(0, 'rgba(255,240,180,0)'); gr.addColorStop(0.5, 'rgba(255,240,180,.24)'); gr.addColorStop(1, 'rgba(255,240,180,0)'); c2.save(); c2.globalCompositeOperation = 'lighter'; c2.transform(1, 0, -0.45, 1, 0, 0); c2.fillStyle = gr; c2.fillRect(x0 - 260 - 600, 0, 520 + 1200, 700); c2.restore(); };
|
|
181
|
+
const sx = lerp(-200, 2300, clamp(lt / 1.15));
|
|
182
|
+
sweep(c, sx);
|
|
183
|
+
// 猫
|
|
184
|
+
const K = RIG.cat({ tail: ch.tail, blink: ch.blink, breathe: ch.breathe });
|
|
185
|
+
cat(c, K, t);
|
|
186
|
+
// 少女:先金袍(剪影里填金+纹样),再写实的脸手
|
|
187
|
+
const G = RIG.girl({ cup: ch.cup, sip: ch.sip, breathe: ch.breathe, hair: 'bun' });
|
|
188
|
+
const R_ = P.scratch('kl_robe'), rg = R_.getContext('2d'); rg.reset();
|
|
189
|
+
const Pt = P.scratch('kl_pat'), pt = Pt.getContext('2d'); pt.reset(); robePattern(pt, t, lt); // 纹样先画满一张,再按剪影一次性 source-in(逐个纹样 source-in 会互相清掉)
|
|
190
|
+
rg.fillStyle = '#000'; [G.farSleeve, G.skirt, G.torso].forEach(p => rg.fill(p));
|
|
191
|
+
rg.globalCompositeOperation = 'source-in'; rg.drawImage(Pt, 0, 0);
|
|
192
|
+
rg.globalCompositeOperation = 'source-atop'; sweep(rg, sx + 260);
|
|
193
|
+
rg.globalCompositeOperation = 'source-over';
|
|
194
|
+
rg.strokeStyle = C.ink; rg.lineWidth = 3; [G.farSleeve, G.skirt, G.torso].forEach(p => rg.stroke(p));
|
|
195
|
+
skin(rg, G.farHand, 1180, 614, 40);
|
|
196
|
+
hair(rg, G, t);
|
|
197
|
+
// 远侧袖口:一圈黑白方格
|
|
198
|
+
face(rg, G, ch); bangs(rg, G); wreath(rg, G, t);
|
|
199
|
+
// 近侧手臂(金袖)在脸前
|
|
200
|
+
rg.save(); rg.beginPath(); rg.rect(0, 0, W, H); rg.clip();
|
|
201
|
+
rg.fillStyle = '#000'; const arm = new Path2D(); arm.addPath(G.upperArm); arm.addPath(G.foreArm);
|
|
202
|
+
rg.save(); rg.clip(arm); rg.drawImage(Pt, 0, 0); rg.restore(); rg.strokeStyle = C.ink; rg.lineWidth = 3; rg.stroke(G.upperArm); rg.stroke(G.foreArm);
|
|
203
|
+
rg.fillStyle = '#141010'; rg.fill(G.cuff); rg.save(); rg.clip(G.cuff); rg.fillStyle = '#f4efe2'; for (let k = 0; k < 40; k++) rg.fillRect(G.A.elbow[0] - 100 + (k % 10) * 20, G.A.elbow[1] - 100 + ((k / 10) | 0) * 50 + (k % 2) * 8, 8, 8); rg.restore();
|
|
204
|
+
rg.restore();
|
|
205
|
+
skin(rg, G.hand, G.A.hand[0], G.A.hand[1], 20);
|
|
206
|
+
// 金杯(黑方格)
|
|
207
|
+
const cp = G.cup; rg.save(); rg.translate(cp.x, cp.y); rg.rotate(cp.tilt);
|
|
208
|
+
rg.beginPath(); rg.moveTo(-cp.w / 2, 0); rg.lineTo(-cp.w * 0.38, cp.h); rg.lineTo(cp.w * 0.38, cp.h); rg.lineTo(cp.w / 2, 0); rg.closePath();
|
|
209
|
+
const cg = rg.createLinearGradient(-cp.w / 2, 0, cp.w / 2, 0); cg.addColorStop(0, '#f6d880'); cg.addColorStop(0.5, '#c8962e'); cg.addColorStop(1, '#8a5a14'); rg.fillStyle = cg; rg.fill(); rg.strokeStyle = C.ink; rg.lineWidth = 2; rg.stroke();
|
|
210
|
+
rg.fillStyle = '#141010'; for (let k = 0; k < 3; k++) rg.fillRect(-cp.w * 0.3 + k * cp.w * 0.24, cp.h * 0.35, 7, 7);
|
|
211
|
+
rg.restore();
|
|
212
|
+
rg.fillStyle = '#f0cfb8'; rg.beginPath(); rg.arc(G.thumb[0], G.thumb[1], 6.5, 0, Math.PI * 2); rg.fill();
|
|
213
|
+
c.drawImage(R_, 0, 0);
|
|
214
|
+
// 热气:金色细螺旋线上升
|
|
215
|
+
c.save(); c.globalAlpha = 0.85; [0, 1].forEach(k => { c.strokeStyle = '#f6e6a8'; c.lineWidth = 2.4; c.beginPath(); for (let i = 0; i <= 30; i++) { const q = i / 30; const x = G.cup.x - 6 + k * 14 - q * 50 * ch.cup + Math.sin(t * 4 + q * 8 + k * 2) * 9 * q, y = G.cup.y - 8 - q * 85; i ? c.lineTo(x, y) : c.moveTo(x, y); } c.stroke(); }); c.restore();
|
|
216
|
+
},
|
|
217
|
+
label(c, lt) {
|
|
218
|
+
c.save();
|
|
219
|
+
c.fillStyle = '#141010'; c.fillRect(1468, 36, 422, 176);
|
|
220
|
+
c.fillStyle = '#d6a845'; c.fillRect(1468, 36, 422, 6); c.fillRect(1468, 206, 422, 6);
|
|
221
|
+
for (let x = 1472; x < 1886; x += 14) { c.fillStyle = ((x - 1472) / 14) % 2 ? '#f4efe2' : '#d6a845'; c.fillRect(x, 48, 9, 9); c.fillRect(x, 192, 9, 9); }
|
|
222
|
+
c.restore();
|
|
223
|
+
const g = c.createLinearGradient(0, 60, 0, 136); g.addColorStop(0, '#fbe6a0'); g.addColorStop(0.5, '#d6a845'); g.addColorStop(1, '#9a6a1c');
|
|
224
|
+
KIT.label(c, { title: '金色时期', sub: 'GUSTAV KLIMT · 1907', tFont: '78px "LXGWWenKai-500"', sFont: '27px "Marcellus-400"', tCol: g, sCol: '#e8cf86', x: 1858, y: 140, sy: 182, spacing: 8 });
|
|
225
|
+
},
|
|
226
|
+
};
|
|
227
|
+
})();
|