@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,197 @@
|
|
|
1
|
+
// 2016 新海诚光影 —— 纯代码。
|
|
2
|
+
// 管线:①天空(极透明的蓝渐变+积雨云:逐团球体打光+暖色受光边,缓慢翻涌)+电线杆/电线/远处屋顶 + 飞机拉线
|
|
3
|
+
// → ②写实背景(墙面冷暖渐变、木地板反光、桌椅盆栽)→ ③窗玻璃水珠(折射天空、高光、一颗慢慢滑下)
|
|
4
|
+
// → ④赛璐珞角色:每个部件「底色 → 背光侧硬阴影 → 受光侧亮边 → 细描线」,阴影/亮边用「自身减去平移后的自身」算(evenodd 反选)
|
|
5
|
+
// → ⑤丁达尔光柱+光尘 → ⑥镜头光晕(星芒、彩色光斑沿太阳-画心连线、横向拉丝)→ ⑦缩小糊化 screen 回叠=泛光
|
|
6
|
+
SCENES['35_shinkai'] = (() => {
|
|
7
|
+
const W = 1920, H = 1080, { clamp, lerp, rng } = U, P = PAINT;
|
|
8
|
+
const SUN = [712, 196], GL = [360, 132, 800, 548];
|
|
9
|
+
// ---------- 赛璐珞上色 ----------
|
|
10
|
+
const cel = P.cel; // 赛璐珞:底色 → 背光侧硬阴影带(自身减去平移后的自身)→ 受光侧亮边 → 细描线
|
|
11
|
+
// ---------- 天空与积雨云 ----------
|
|
12
|
+
const cloudBlobs = (() => { const r = rng(808), out = [];
|
|
13
|
+
// 主塔:底部宽、向上收、顶部铁砧略右偏;外加两团小云
|
|
14
|
+
for (let i = 0; i < 70; i++) { const h = Math.pow(r(), 0.8); const y = 540 - h * 360, w = h > 0.85 ? 300 : lerp(240, 110, h); out.push({ x: 590 + (r() - 0.5) * w * 1.5 + h * 50, y: y + (r() - 0.5) * 30, r: lerp(64, 34, h) * (0.7 + r() * 0.6), ph: r() * 6 }); }
|
|
15
|
+
for (let i = 0; i < 12; i++) out.push({ x: 410 + r() * 90, y: 290 + r() * 50, r: 22 + r() * 22, ph: r() * 6 });
|
|
16
|
+
return out.sort((a, b) => b.y - a.y); })();
|
|
17
|
+
function sky(c, t) {
|
|
18
|
+
c.save(); c.beginPath(); c.rect(GL[0], GL[1], GL[2] - GL[0], GL[3] - GL[1]); c.clip();
|
|
19
|
+
const sg = c.createLinearGradient(0, GL[1], 0, GL[3]); sg.addColorStop(0, '#1360d0'); sg.addColorStop(0.45, '#3f9bf0'); sg.addColorStop(0.85, '#a8dcff'); sg.addColorStop(1, '#e4f6ff');
|
|
20
|
+
c.fillStyle = sg; c.fillRect(GL[0], GL[1], 440, 416);
|
|
21
|
+
// 积雨云:离屏 → ①所有团块画蓝灰剪影(暗部)②每团一个偏向太阳的亮球(受光面)③整层糊 3px 再叠 55% 清晰层(软而不糊)
|
|
22
|
+
const drift = t * 10, CL = P.scratch('skCloud'), cg = CL.getContext('2d'); cg.reset();
|
|
23
|
+
const at = b => [b.x + drift, b.y - Math.sin(t * 0.8 + b.ph) * 3, b.r * (1 + 0.05 * Math.sin(t * 1.3 + b.ph))];
|
|
24
|
+
cloudBlobs.forEach(b => { const [x, y, r] = at(b); const g = cg.createLinearGradient(0, y - r, 0, y + r); g.addColorStop(0, '#b7c6e6'); g.addColorStop(1, '#8297c6'); cg.fillStyle = g; cg.beginPath(); cg.arc(x, y, r, 0, 7); cg.fill(); });
|
|
25
|
+
cloudBlobs.forEach(b => { const [x, y, r] = at(b); const ox = x + r * 0.22, oy = y - r * 0.3, rr = r * 0.82;
|
|
26
|
+
const g = cg.createRadialGradient(ox + rr * 0.3, oy - rr * 0.3, rr * 0.05, ox, oy, rr); g.addColorStop(0, '#ffffff'); g.addColorStop(0.6, '#f6f8ff'); g.addColorStop(0.9, '#e2e9fa'); g.addColorStop(1, 'rgba(226,233,250,0)');
|
|
27
|
+
cg.fillStyle = g; cg.beginPath(); cg.arc(ox, oy, rr, 0, 7); cg.fill(); });
|
|
28
|
+
c.save(); c.filter = 'blur(3px)'; c.drawImage(CL, 0, 0); c.restore(); c.globalAlpha = 0.55; c.drawImage(CL, 0, 0); c.globalAlpha = 1;
|
|
29
|
+
// 远处屋顶与电线杆(逆光、雾蓝)
|
|
30
|
+
c.fillStyle = '#7d9cc6'; c.beginPath(); c.moveTo(360, 548); [[360, 500], [420, 500], [420, 480], [470, 480], [480, 462], [540, 462], [545, 490], [610, 490], [615, 470], [690, 470], [700, 495], [760, 495], [760, 476], [800, 476], [800, 548]].forEach(p => c.lineTo(...p)); c.fill();
|
|
31
|
+
c.fillStyle = '#5f7fae'; c.fillRect(708, 300, 8, 250); c.fillRect(690, 318, 46, 6); c.fillRect(694, 338, 38, 5);
|
|
32
|
+
c.strokeStyle = 'rgba(50,70,110,.8)'; c.lineWidth = 1.6; [[318, 330], [338, 352], [321, 400]].forEach(([y0, y1], k) => { c.beginPath(); c.moveTo(360, y1 + 30 + k * 6); c.quadraticCurveTo(540, y1 + 60, 712, y0); c.quadraticCurveTo(760, y0 + 10, 800, y0 + 18 + k * 4); c.stroke(); });
|
|
33
|
+
// 飞机拉线:从左往右飞,线在身后变宽变淡
|
|
34
|
+
const px = 380 + (t * 140) % 520, py = 196 - (px - 380) * 0.05;
|
|
35
|
+
const ctg = c.createLinearGradient(px - 260, 0, px, 0); ctg.addColorStop(0, 'rgba(255,255,255,0)'); ctg.addColorStop(1, 'rgba(255,255,255,.9)');
|
|
36
|
+
c.strokeStyle = ctg; c.lineWidth = 3; c.beginPath(); c.moveTo(px - 260, py + 13); c.lineTo(px, py); c.stroke(); c.fillStyle = '#ffffff'; c.beginPath(); c.arc(px + 3, py, 2.5, 0, 7); c.fill();
|
|
37
|
+
// 鸟群:三只,翅膀 V 形扇动
|
|
38
|
+
for (let k = 0; k < 3; k++) { const bx = 470 + t * 90 + k * 34, by = 250 + k * 14 + Math.sin(t * 3 + k) * 6, f = Math.sin(t * 16 + k * 2) * 6; c.strokeStyle = '#3a4a6a'; c.lineWidth = 2; c.beginPath(); c.moveTo(bx - 9, by - f); c.lineTo(bx, by); c.lineTo(bx + 9, by - f); c.stroke(); }
|
|
39
|
+
c.restore();
|
|
40
|
+
}
|
|
41
|
+
// ---------- 静态室内(缓存) ----------
|
|
42
|
+
const room = () => P.cached('sk_room', W, H, (g) => {
|
|
43
|
+
const wg = g.createLinearGradient(0, 0, W, 0); wg.addColorStop(0, '#f2ece2'); wg.addColorStop(0.45, '#e9e4dc'); wg.addColorStop(1, '#bfc3d2'); g.fillStyle = wg; g.fillRect(0, 0, W, 720);
|
|
44
|
+
const vg = g.createLinearGradient(0, 0, 0, 720); vg.addColorStop(0, 'rgba(120,130,170,.25)'); vg.addColorStop(0.5, 'rgba(0,0,0,0)'); g.fillStyle = vg; g.fillRect(0, 0, W, 720);
|
|
45
|
+
// 踢脚线+木地板(透视板缝、反光)
|
|
46
|
+
g.fillStyle = '#d8d4cc'; g.fillRect(0, 700, W, 18);
|
|
47
|
+
const fg = g.createLinearGradient(0, 718, 0, H); fg.addColorStop(0, '#9a6a48'); fg.addColorStop(1, '#6a4430'); g.fillStyle = fg; g.fillRect(0, 718, W, H - 718);
|
|
48
|
+
g.strokeStyle = 'rgba(60,36,20,.45)'; g.lineWidth = 2; for (let i = -20; i <= 20; i++) { g.beginPath(); g.moveTo(960 + i * 70, 718); g.lineTo(960 + i * 190, H); g.stroke(); }
|
|
49
|
+
// 窗:铝框推拉窗(窗洞、框、中梃、窗台)
|
|
50
|
+
g.fillStyle = '#d4d2d4'; g.fillRect(330, 104, 500, 470); g.fillStyle = '#f6f6f8'; g.fillRect(342, 116, 476, 448);
|
|
51
|
+
g.fillStyle = '#b8bcc8'; g.fillRect(352, 124, 456, 432);
|
|
52
|
+
g.fillStyle = '#eef0f4'; g.fillRect(570, 124, 22, 432); g.fillStyle = '#c6cad4'; g.fillRect(588, 124, 4, 432);
|
|
53
|
+
g.fillStyle = '#fbfbfc'; g.fillRect(316, 562, 530, 22); g.fillStyle = '#c4c4cc'; g.fillRect(316, 584, 530, 8);
|
|
54
|
+
// 墙上:挂历和一张照片(写实的小细节)
|
|
55
|
+
g.fillStyle = '#ffffff'; g.fillRect(1580, 250, 150, 200); g.fillStyle = '#e2534a'; g.fillRect(1580, 250, 150, 40); g.fillStyle = '#9aa0b0'; for (let i = 0; i < 5; i++) for (let j = 0; j < 7; j++) g.fillRect(1592 + j * 19, 304 + i * 26, 12, 12);
|
|
56
|
+
// 桌:浅木书桌
|
|
57
|
+
g.fillStyle = '#7a5236'; g.fillRect(836, 650, 26, 255); g.fillRect(1160, 650, 26, 255);
|
|
58
|
+
g.fillStyle = '#c99a68'; g.fillRect(806, 612, 410, 30); g.fillStyle = '#f0cf9c'; g.fillRect(806, 612, 410, 6); g.fillStyle = '#8e623e'; g.fillRect(806, 638, 410, 14);
|
|
59
|
+
// 椅
|
|
60
|
+
g.fillStyle = '#8e623e'; g.fillRect(1430, 470, 18, 440); g.fillRect(1478, 480, 18, 430); g.fillRect(1426, 470, 74, 60);
|
|
61
|
+
g.fillStyle = '#b8865a'; g.fillRect(1426, 470, 74, 8);
|
|
62
|
+
// 桌上:书
|
|
63
|
+
g.fillStyle = '#3d5a8e'; g.fillRect(1040, 594, 110, 18); g.fillStyle = '#f2ecdc'; g.fillRect(1044, 590, 102, 6); g.fillStyle = '#c94f4a'; g.fillRect(1052, 578, 90, 14);
|
|
64
|
+
});
|
|
65
|
+
// ---------- 少女(逐部件赛璐珞) ----------
|
|
66
|
+
const SK = { b: '#ffe8dc', s: '#f2b6a8', r: '#fffaf4' }, HR = { b: '#f8d681', s: '#d8a050', r: '#fff6d6' }, WT = { b: '#fbfbfe', s: '#b9c3dc', r: '#ffffff' }, NV = { b: '#2c3a66', s: '#1b2446', r: '#5a6ea8' };
|
|
67
|
+
function girl(c, G, t, lt) {
|
|
68
|
+
const L = '#6a4632', o = { line: L };
|
|
69
|
+
cel(c, G.farSleeve, WT.b, WT.s, null, o); cel(c, G.farHand, SK.b, SK.s, null, o);
|
|
70
|
+
cel(c, G.skirt, NV.b, NV.s, NV.r, { ...o, sd: 30 });
|
|
71
|
+
c.save(); c.clip(G.skirt); c.strokeStyle = '#141a33'; c.lineWidth = 2.5; [[1170, 700, 1140, 925], [1210, 690, 1190, 930], [1250, 680, 1244, 930], [1290, 680, 1296, 925], [1330, 760, 1346, 925]].forEach(([a, b, c2, d]) => { c.beginPath(); c.moveTo(a, b); c.lineTo(c2, d); c.stroke(); }); c.restore();
|
|
72
|
+
cel(c, G.shoe, '#3a2a24', '#22160f', null, o);
|
|
73
|
+
cel(c, G.torso, WT.b, WT.s, WT.r, { ...o, sd: 26 });
|
|
74
|
+
// 水手领(背后的大方领,藏青+两道白线)
|
|
75
|
+
const nape = G.A.nape, bk = G.A.back, nk = G.A.neck;
|
|
76
|
+
const col = RIG.smooth([[nk[0] - 8, nk[1] - 6], [nape[0] + 10, nape[1] - 4], [bk[0] + 6, bk[1] - 20], [bk[0] - 4, bk[1] + 30], [nk[0] + 40, nk[1] + 70], [nk[0] + 6, nk[1] + 30]]);
|
|
77
|
+
cel(c, col, NV.b, NV.s, NV.r, { ...o, sd: 14 });
|
|
78
|
+
c.save(); c.clip(col); c.strokeStyle = '#f2f4fa'; c.lineWidth = 3; c.stroke(RIG.smooth([[nk[0] + 4, nk[1] + 6], [nape[0] + 12, nape[1] + 8], [bk[0] - 6, bk[1] - 14], [bk[0] - 14, bk[1] + 18], [nk[0] + 38, nk[1] + 58], [nk[0] + 12, nk[1] + 28]])); c.restore();
|
|
79
|
+
// 红领巾结
|
|
80
|
+
const ch = G.A.chest; const tie = RIG.smooth([[nk[0] - 8, nk[1] + 14], [nk[0] + 16, nk[1] + 18], [ch[0] + 10, ch[1] + 10], [ch[0] - 4, ch[1] + 50], [ch[0] - 16, ch[1] + 8]]);
|
|
81
|
+
cel(c, tie, '#e04454', '#a8243a', '#ff8a96', { ...o, sd: 10, rw: 4 });
|
|
82
|
+
cel(c, G.neck, SK.b, SK.s, null, { ...o, sd: 14 });
|
|
83
|
+
cel(c, G.hairBack, HR.b, HR.s, HR.r, { ...o, line: '#8a5a2a', sd: 26, rw: 9 }); cel(c, G.bun, HR.b, HR.s, HR.r, { ...o, line: '#8a5a2a', sd: 16 });
|
|
84
|
+
// 天使环:后脑一道亮带
|
|
85
|
+
c.save(); c.clip(G.hairBack); c.strokeStyle = 'rgba(255,250,226,.85)'; c.lineWidth = 9; c.beginPath(); c.arc(G.A.headC[0] + 10, G.A.headC[1] + 10, 64, -2.2, -0.6); c.stroke(); c.restore();
|
|
86
|
+
cel(c, G.face, SK.b, SK.s, null, { ...o, sd: 10 });
|
|
87
|
+
c.save(); c.clip(G.face); c.fillStyle = 'rgba(255,140,140,.35)'; c.beginPath(); c.ellipse(G.cheek[0] - 4, G.cheek[1], 16, 9, 0, 0, 7); c.fill(); c.restore();
|
|
88
|
+
c.fillStyle = SK.b; c.beginPath(); c.ellipse(G.ear[0], G.ear[1], 8, 12, 0.2, 0, 7); c.fill(); c.strokeStyle = L; c.lineWidth = 1.8; c.stroke();
|
|
89
|
+
cel(c, G.bangs, HR.b, HR.s, HR.r, { ...o, line: '#8a5a2a', sd: 12, rw: 6 });
|
|
90
|
+
c.strokeStyle = 'rgba(170,110,50,.7)'; c.lineWidth = 1.6; G.hairLines.forEach(h => c.stroke(h));
|
|
91
|
+
// 被窗口吹动的发丝
|
|
92
|
+
const wind = Math.sin(t * 3.2) * 6 + Math.sin(t * 7.1) * 2;
|
|
93
|
+
c.save(); c.translate(wind * 0.5, 0); G.locks.forEach(h => { c.strokeStyle = '#8a5a2a'; c.lineWidth = 8; c.stroke(h); c.strokeStyle = HR.b; c.lineWidth = 5.5; c.stroke(h); }); c.restore();
|
|
94
|
+
c.strokeStyle = HR.s; c.lineWidth = 3; for (let k = 0; k < 3; k++) { const s = G.A.nape; c.beginPath(); c.moveTo(s[0] + 10 + k * 8, s[1] - 10); c.quadraticCurveTo(s[0] + 26 + k * 8 + wind, s[1] + 30, s[0] + 18 + k * 10 + wind * 1.6, s[1] + 70); c.stroke(); }
|
|
95
|
+
// 动画眼:大、纵向渐变虹膜、两颗高光;眼睑粗
|
|
96
|
+
const e = G.eye, bl = P.choreo(lt, t).blink;
|
|
97
|
+
if (bl) { c.strokeStyle = '#3a2418'; c.lineWidth = 3.2; c.beginPath(); c.moveTo(e.x - 9, e.y + 3); c.quadraticCurveTo(e.x, e.y + 7, e.x + 9, e.y + 3); c.stroke(); }
|
|
98
|
+
else {
|
|
99
|
+
const ig = c.createLinearGradient(0, e.y - 12, 0, e.y + 12); ig.addColorStop(0, '#1f3f7a'); ig.addColorStop(0.6, '#3f7fd0'); ig.addColorStop(1, '#9fd4ff');
|
|
100
|
+
c.fillStyle = '#ffffff'; c.beginPath(); c.ellipse(e.x, e.y + 1, 8, 12, 0, 0, 7); c.fill();
|
|
101
|
+
c.fillStyle = ig; c.beginPath(); c.ellipse(e.x - 1.5, e.y + 2, 6.5, 11, 0, 0, 7); c.fill();
|
|
102
|
+
c.fillStyle = '#ffffff'; c.beginPath(); c.arc(e.x - 3.5, e.y - 3, 2.6, 0, 7); c.fill(); c.beginPath(); c.arc(e.x + 1, e.y + 7, 1.3, 0, 7); c.fill();
|
|
103
|
+
c.strokeStyle = '#3a2418'; c.lineWidth = 3.4; c.lineCap = 'round'; c.beginPath(); c.moveTo(e.x - 10, e.y - 7); c.quadraticCurveTo(e.x, e.y - 14, e.x + 9, e.y - 9); c.stroke();
|
|
104
|
+
c.lineWidth = 2; c.beginPath(); c.moveTo(e.x - 10, e.y - 7); c.lineTo(e.x - 15, e.y - 11); c.stroke();
|
|
105
|
+
}
|
|
106
|
+
c.strokeStyle = '#a07040'; c.lineWidth = 2; c.stroke(G.brow);
|
|
107
|
+
c.fillStyle = '#e07a78'; c.beginPath(); c.moveTo(...G.lips[0]); c.lineTo(...G.lips[1]); c.lineTo(...G.lips[2]); c.closePath(); c.fill();
|
|
108
|
+
// 近侧手臂(白短袖改长袖:17 岁端庄款)
|
|
109
|
+
cel(c, G.upperArm, WT.b, WT.s, WT.r, { ...o, sd: 16 }); cel(c, G.foreArm, WT.b, WT.s, WT.r, { ...o, sd: 12 }); cel(c, G.cuff, NV.b, NV.s, null, { ...o, sd: 8 });
|
|
110
|
+
cel(c, G.hand, SK.b, SK.s, SK.r, { ...o, sd: 8, rw: 3 });
|
|
111
|
+
const cp = G.cup; c.save(); c.translate(cp.x, cp.y); c.rotate(cp.tilt);
|
|
112
|
+
const cup = RIG.smooth([[-22, 0], [-19, 32], [0, 40], [19, 32], [22, 0]]); cel(c, cup, '#ffffff', '#c6d0e6', null, { ...o, sd: 10 });
|
|
113
|
+
c.strokeStyle = '#ffffff'; c.lineWidth = 6; c.beginPath(); c.arc(25, 15, 10, -1.3, 1.5); c.stroke(); c.strokeStyle = L; c.lineWidth = 1.6; c.stroke();
|
|
114
|
+
c.fillStyle = '#c98a4a'; c.beginPath(); c.ellipse(0, 1, 20, 4.5, 0, 0, 7); c.fill(); c.restore();
|
|
115
|
+
c.fillStyle = SK.b; c.beginPath(); c.arc(G.thumb[0], G.thumb[1], 7, 0, 7); c.fill(); c.strokeStyle = L; c.lineWidth = 1.8; c.stroke();
|
|
116
|
+
}
|
|
117
|
+
function cat(c, K, t) {
|
|
118
|
+
const o = { line: '#7a4a28', lw: 2.2 };
|
|
119
|
+
const OR = { b: '#f4a758', s: '#c8743a', r: '#fff0c8' }, WH = { b: '#fff8ee', s: '#c6cce2', r: '#ffffff' };
|
|
120
|
+
// 尾
|
|
121
|
+
c.save(); c.lineCap = 'round'; c.strokeStyle = o.line; c.lineWidth = K.tailW + 4; c.stroke(K.tail); c.strokeStyle = OR.b; c.lineWidth = K.tailW; c.stroke(K.tail);
|
|
122
|
+
c.strokeStyle = OR.s; c.lineWidth = K.tailW * 0.45; c.save(); c.translate(4, 5); c.stroke(K.tail); c.restore();
|
|
123
|
+
const tip = K.tailPts[K.tailPts.length - 1]; c.fillStyle = WH.b; c.beginPath(); c.arc(tip[0], tip[1], K.tailW / 2, 0, 7); c.fill(); c.restore();
|
|
124
|
+
const body = RIG.smooth(K.bodyPts);
|
|
125
|
+
cel(c, body, OR.b, OR.s, OR.r, { ...o, sd: 34, rw: 8, lx: 0.5, ly: 1 }); // 猫在窗下:背光,暗部在下侧
|
|
126
|
+
c.save(); c.clip(body); c.strokeStyle = '#d07a34'; c.lineWidth = 8; c.lineCap = 'round'; K.stripes.slice(3).forEach(s => { c.beginPath(); c.moveTo(...s[0]); c.lineTo(...s[1]); c.stroke(); });
|
|
127
|
+
cel(c, RIG.smooth([[566, 700], [612, 690], [642, 742], [636, 830], [596, 870], [560, 800]]), WH.b, WH.s, null, { ...o, lw: 0, sd: 18, lx: 0.5, ly: 1 }); c.restore();
|
|
128
|
+
c.strokeStyle = o.line; c.lineWidth = 2.2; c.stroke(body);
|
|
129
|
+
[[588, 812], [634, 814]].forEach(([x, y]) => cel(c, RIG.taper([x, y], [x, 890], 30, 30), WH.b, WH.s, null, { ...o, sd: 10, lx: 0.5, ly: 1 }));
|
|
130
|
+
cel(c, K.head, OR.b, OR.s, OR.r, { ...o, sd: 22, rw: 8, lx: 0.5, ly: 1 });
|
|
131
|
+
c.save(); c.clip(K.head); c.strokeStyle = '#d07a34'; c.lineWidth = 7; c.lineCap = 'round'; K.stripes.slice(0, 3).forEach(s => { c.beginPath(); c.moveTo(...s[0]); c.lineTo(...s[1]); c.stroke(); });
|
|
132
|
+
c.fillStyle = WH.b; c.beginPath(); c.ellipse(K.nose[0] - 24, K.nose[1] + 12, 36, 25, 0, 0, 7); c.fill(); c.restore();
|
|
133
|
+
c.fillStyle = '#f6b0b0'; K.earInner.forEach(e => { c.beginPath(); e.forEach((p, i) => i ? c.lineTo(...p) : c.moveTo(...p)); c.fill(); });
|
|
134
|
+
K.eyes.forEach(e => { if (K.blink) { c.strokeStyle = '#3a2418'; c.lineWidth = 3; c.beginPath(); c.arc(e.x, e.y, 9, 0.2, Math.PI - 0.2); c.stroke(); return; }
|
|
135
|
+
const g = c.createLinearGradient(0, e.y - 10, 0, e.y + 10); g.addColorStop(0, '#5a8a2a'); g.addColorStop(1, '#d8f080'); c.fillStyle = g; c.beginPath(); c.ellipse(e.x, e.y, 9, 11, 0, 0, 7); c.fill();
|
|
136
|
+
c.fillStyle = '#1a1a1a'; c.beginPath(); c.ellipse(e.x + 1.5, e.y, 3, 8, 0, 0, 7); c.fill(); c.fillStyle = '#fff'; c.beginPath(); c.arc(e.x - 2.5, e.y - 4, 2.4, 0, 7); c.fill(); c.strokeStyle = '#3a2418'; c.lineWidth = 2; c.beginPath(); c.ellipse(e.x, e.y, 9, 11, 0, 0, 7); c.stroke(); });
|
|
137
|
+
c.fillStyle = '#e88a8a'; c.beginPath(); c.arc(K.nose[0], K.nose[1], 5, 0, 7); c.fill();
|
|
138
|
+
c.strokeStyle = '#7a4a28'; c.lineWidth = 2; c.beginPath(); c.moveTo(...K.mouth[0]); c.quadraticCurveTo(...K.mouth[1], ...K.mouth[2]); c.stroke();
|
|
139
|
+
c.lineWidth = 1.2; c.strokeStyle = 'rgba(255,255,255,.9)'; K.whiskers.forEach(w => { c.beginPath(); c.moveTo(...w[0]); c.lineTo(...w[1]); c.stroke(); });
|
|
140
|
+
// 逆光:猫的头顶和背上沿一圈亮边(窗在它头顶)
|
|
141
|
+
c.save(); c.globalCompositeOperation = 'lighter'; c.strokeStyle = 'rgba(255,220,160,.55)'; c.lineWidth = 4; c.save(); c.clip(K.head); c.translate(0, 5); c.stroke(K.head); c.restore(); c.save(); c.clip(body); c.translate(4, 6); c.stroke(body); c.restore(); c.restore();
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return {
|
|
145
|
+
draw(c, lt, t) {
|
|
146
|
+
const ch = P.choreo(lt, t);
|
|
147
|
+
c.drawImage(room(), 0, 0);
|
|
148
|
+
sky(c, t);
|
|
149
|
+
// 窗玻璃:水珠(折射一小块天空+下沿暗边+左上高光),一颗沿玻璃滑下
|
|
150
|
+
const dr = rng(64);
|
|
151
|
+
for (let i = 0; i < 20; i++) { let x = 366 + dr() * 428, y = 140 + dr() * 400, r = 2 + dr() * 3.5; if (i === 0) { r = 8; x = 470; y = 180 + clamp(lt - 0.2) * 220; }
|
|
152
|
+
if (x > 566 && x < 596) continue;
|
|
153
|
+
c.strokeStyle = 'rgba(30,60,120,.45)'; c.lineWidth = 1.4; c.beginPath(); c.arc(x, y, r, 0.3, Math.PI - 0.3); c.stroke();
|
|
154
|
+
c.fillStyle = 'rgba(220,240,255,.22)'; c.beginPath(); c.arc(x, y, r, 0, 7); c.fill();
|
|
155
|
+
c.fillStyle = '#ffffff'; c.beginPath(); c.arc(x - r * 0.35, y - r * 0.35, r * 0.28, 0, 7); c.fill();
|
|
156
|
+
if (i === 0) { c.strokeStyle = 'rgba(220,240,255,.45)'; c.lineWidth = 3; c.beginPath(); c.moveTo(x, y - 10); c.lineTo(x, 180); c.stroke(); } }
|
|
157
|
+
// 窗帘:右侧白纱,随风鼓起(贝塞尔边缘按时间摆)
|
|
158
|
+
const wv = Math.sin(t * 2.6) * 22 + Math.sin(t * 5.3) * 6;
|
|
159
|
+
const cur = new Path2D(); cur.moveTo(760, 108); cur.lineTo(840, 108); cur.bezierCurveTo(850, 260, 830 + wv * 0.3, 420, 846, 600); cur.lineTo(760 - wv, 600); cur.bezierCurveTo(720 - wv * 1.4, 430, 760 - wv * 0.6, 260, 760, 108); cur.closePath();
|
|
160
|
+
c.fillStyle = 'rgba(255,255,255,.55)'; c.fill(cur); c.strokeStyle = 'rgba(200,210,230,.6)'; c.lineWidth = 2; for (let k = 0; k < 4; k++) { c.beginPath(); c.moveTo(775 + k * 18, 110); c.bezierCurveTo(780 + k * 18, 300, 770 + k * 16 - wv * (0.4 + k * 0.1), 460, 770 + k * 20 - wv * (0.8 - k * 0.15), 598); c.stroke(); }
|
|
161
|
+
// 地板上的窗形光斑(暖,投影平行四边形)+桌面一角受光
|
|
162
|
+
c.save(); c.globalCompositeOperation = 'screen';
|
|
163
|
+
c.drawImage(P.cached('sk_floorlight', W, H, (g) => { g.filter = 'blur(14px)'; g.fillStyle = 'rgba(255,214,150,.6)'; g.beginPath(); g.moveTo(560, 740); g.lineTo(980, 740); g.lineTo(1240, 1040); g.lineTo(720, 1040); g.closePath(); g.fill();
|
|
164
|
+
g.fillStyle = 'rgba(80,60,40,1)'; g.globalCompositeOperation = 'destination-out'; g.beginPath(); g.moveTo(760, 740); g.lineTo(790, 740); g.lineTo(990, 1040); g.lineTo(950, 1040); g.closePath(); g.fill(); }), 0, 0);
|
|
165
|
+
c.fillStyle = 'rgba(255,214,150,.3)'; c.fillRect(806, 612, 300, 26);
|
|
166
|
+
// 墙上窗形光斑(右上→右下的平行四边形)+窗帘的影子在里面摆
|
|
167
|
+
const WL = P.scratch('skWallLight'), wlg = WL.getContext('2d'); wlg.reset(); wlg.filter = 'blur(10px)';
|
|
168
|
+
wlg.fillStyle = 'rgba(255,222,170,.55)'; wlg.beginPath(); wlg.moveTo(980, 150); wlg.lineTo(1330, 230); wlg.lineTo(1330, 600); wlg.lineTo(980, 560); wlg.closePath(); wlg.fill();
|
|
169
|
+
wlg.globalCompositeOperation = 'destination-out'; wlg.fillStyle = '#000'; wlg.beginPath(); wlg.moveTo(1140, 186); wlg.lineTo(1166, 192); wlg.lineTo(1166, 580); wlg.lineTo(1140, 578); wlg.fill();
|
|
170
|
+
const cs = Math.sin(t * 2.6) * 30 + Math.sin(t * 5.3) * 8; wlg.globalAlpha = 0.7; wlg.beginPath(); wlg.moveTo(1240 + cs * 0.3, 200); wlg.bezierCurveTo(1230 + cs, 330, 1250 - cs * 0.4, 460, 1220 + cs, 600); wlg.lineTo(1340, 600); wlg.lineTo(1340, 200); wlg.fill();
|
|
171
|
+
c.drawImage(WL, 0, 0);
|
|
172
|
+
c.restore();
|
|
173
|
+
// 盆栽(叶子随风摆)
|
|
174
|
+
const sway = Math.sin(t * 2.6) * 0.06;
|
|
175
|
+
c.fillStyle = '#e8e2d6'; c.fillRect(872, 566, 56, 46); c.fillStyle = '#c9c0b0'; c.fillRect(900, 566, 28, 46);
|
|
176
|
+
[[-0.8, 60], [-0.3, 74], [0.2, 70], [0.7, 58], [-1.2, 44], [1.1, 46]].forEach(([a, l], k) => { c.save(); c.translate(900, 566); c.rotate(a + sway * (1 + k * 0.3)); const leaf = new Path2D(); leaf.ellipse(0, -l * 0.6, 13, l * 0.55, 0, 0, 7); cel(c, leaf, '#5fae5a', '#2f7a42', '#b8f09a', { line: '#2a5a32', lw: 1.6, sd: 7, rw: 3 }); c.restore(); });
|
|
177
|
+
// 角色
|
|
178
|
+
const K = RIG.cat({ tail: ch.tail, blink: ch.blink, breathe: ch.breathe });
|
|
179
|
+
const G = RIG.girl({ cup: ch.cup, sip: ch.sip, breathe: ch.breathe, hair: 'bun' });
|
|
180
|
+
cat(c, K, t); girl(c, G, t, lt);
|
|
181
|
+
P.steam(c, t, G.cup.x, G.cup.y - 6, { h: 60, n: 2, color: 'rgba(255,255,255,.7)', width: 3, spread: 12, wobble: 8 });
|
|
182
|
+
// 丁达尔光柱(缓存的模糊楔形,按时间轻微闪动)+光尘
|
|
183
|
+
c.save(); c.globalCompositeOperation = 'screen';
|
|
184
|
+
const beams = P.cached('sk_beams', W, H, (g) => { g.filter = 'blur(18px)'; [[380, 130, 470, 130, 1060, 1000, 860, 1000, 0.32], [520, 130, 600, 130, 1220, 980, 1080, 1000, 0.22], [640, 130, 790, 130, 1450, 900, 1240, 1000, 0.26]].forEach(([a, b, c2, d, e, f, gx, h, al]) => {
|
|
185
|
+
const lg = g.createLinearGradient(a, b, e, f); lg.addColorStop(0, `rgba(255,240,205,${al})`); lg.addColorStop(1, 'rgba(255,240,205,0)'); g.fillStyle = lg; g.beginPath(); g.moveTo(a, b); g.lineTo(c2, d); g.lineTo(e, f); g.lineTo(gx, h); g.closePath(); g.fill(); }); });
|
|
186
|
+
c.globalAlpha = 0.75 + 0.25 * Math.sin(t * 3.4); c.drawImage(beams, 0, 0); c.globalAlpha = 1;
|
|
187
|
+
const motes = P.particles(60, 91, t * 0.5, { x0: 480, x1: 1300, y0: 980, y1: 140, speed: 30, drift: 30, life: 8 });
|
|
188
|
+
motes.forEach((m, i) => { const tw = 0.5 + 0.5 * Math.sin(t * 6 + i * 1.3); const rr = 1.5 + m.s * 3; const g2 = c.createRadialGradient(m.x, m.y, 0, m.x, m.y, rr * 2.5); g2.addColorStop(0, `rgba(255,250,230,${0.8 * tw})`); g2.addColorStop(1, 'rgba(255,250,230,0)'); c.fillStyle = g2; c.beginPath(); c.arc(m.x, m.y, rr * 2.5, 0, 7); c.fill(); });
|
|
189
|
+
c.restore();
|
|
190
|
+
// 镜头光晕(P.lensFlare:太阳核、慢转星芒、横向拉丝、沿太阳→画心的六边形光斑)+泛光(P.bloom:缩小糊化 screen 回叠)
|
|
191
|
+
P.lensFlare(c, SUN, t);
|
|
192
|
+
P.bloom(c, { key: 'skBloom' });
|
|
193
|
+
// 整体色调:高光偏暖、暗部偏蓝(新海诚的冷暖分离)
|
|
194
|
+
c.save(); c.globalCompositeOperation = 'soft-light'; const tg = c.createLinearGradient(0, 0, W, H); tg.addColorStop(0, 'rgba(255,220,170,.35)'); tg.addColorStop(1, 'rgba(80,120,220,.35)'); c.fillStyle = tg; c.fillRect(0, 0, W, H); c.restore();
|
|
195
|
+
},
|
|
196
|
+
};
|
|
197
|
+
})();
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
// 1903 毕加索蓝色时期 —— 纯代码。
|
|
2
|
+
// 管线:①蓝单色平涂底稿(墙/地/窗外夜海)→ ②宽而干的笔触重画(区域蓝色板,墙竖刷、地横刷,不沸腾)
|
|
3
|
+
// → ③角色:骨架整体拉长变瘦(El Greco 式:绕脚底 scale(0.88,1.09)),平涂+小笔触,披肩罩头 → ④普鲁士蓝粗轮廓(只取看得见的线)
|
|
4
|
+
// → ⑤会动的:缓慢呼吸(幅度×2、频率×0.45)、窗外海浪横移、月光碎影闪、热气慢升 → ⑥画布纹+冷暗角
|
|
5
|
+
SCENES['36_picasso_blue'] = (() => {
|
|
6
|
+
const W = 1920, H = 1080, { clamp, lerp, rng } = U, P = PAINT;
|
|
7
|
+
const C = { navy: '#132240', prus: '#1d3866', cob: '#2d5a94', cer: '#6b8fb6', pale: '#b6c8d8', teal: '#3b6878', ochre: '#8c7a54', line: '#0c1830' };
|
|
8
|
+
// 拉长变瘦(El Greco 式):RIG 原生非等比缩放,以脚底为轴——路径、锚点、杯子一起变,线宽不被压扁
|
|
9
|
+
const GSTR = { sx: 0.84, sy: 1.12, anchor: [1240, 932] }, CSTR = { sx: 0.82, sy: 1.14, anchor: [540, 905] };
|
|
10
|
+
|
|
11
|
+
function base(g) {
|
|
12
|
+
g.fillStyle = C.prus; g.fillRect(0, 0, W, 720);
|
|
13
|
+
const wg = g.createLinearGradient(0, 0, W, 0); wg.addColorStop(0, 'rgba(110,145,185,.35)'); wg.addColorStop(0.6, 'rgba(0,0,0,0)'); wg.addColorStop(1, 'rgba(5,10,25,.45)'); g.fillStyle = wg; g.fillRect(0, 0, W, 720);
|
|
14
|
+
g.fillStyle = '#4a6c94'; g.fillRect(0, 720, W, 360);
|
|
15
|
+
const fg = g.createLinearGradient(0, 720, 0, H); fg.addColorStop(0, 'rgba(10,20,40,.4)'); fg.addColorStop(1, 'rgba(150,175,200,.25)'); g.fillStyle = fg; g.fillRect(0, 720, W, 360);
|
|
16
|
+
// 窗:夜海+月
|
|
17
|
+
g.fillStyle = '#7d9cbc'; g.fillRect(340, 110, 480, 460);
|
|
18
|
+
const sk = g.createLinearGradient(0, 130, 0, 400); sk.addColorStop(0, '#1a2f58'); sk.addColorStop(1, '#4f74a4'); g.fillStyle = sk; g.fillRect(360, 130, 440, 270);
|
|
19
|
+
g.fillStyle = '#16284c'; g.fillRect(360, 400, 440, 150);
|
|
20
|
+
g.fillStyle = '#c9d6e2'; g.beginPath(); g.arc(670, 220, 30, 0, 7); g.fill();
|
|
21
|
+
g.fillStyle = '#7d9cbc'; g.fillRect(572, 130, 16, 420); g.fillRect(360, 330, 440, 12);
|
|
22
|
+
g.fillStyle = '#91aecb'; g.fillRect(320, 560, 520, 24);
|
|
23
|
+
}
|
|
24
|
+
function table(g) {
|
|
25
|
+
g.fillStyle = '#20406c'; g.fillRect(806, 614, 408, 34); g.fillStyle = '#16305a'; g.fillRect(826, 648, 368, 40); g.fillRect(842, 688, 22, 216); g.fillRect(1156, 688, 22, 216);
|
|
26
|
+
g.fillStyle = '#1a3460'; g.fillRect(1430, 470, 18, 440); g.fillRect(1478, 480, 18, 430); for (let k = 0; k < 3; k++) g.fillRect(1434, 520 + k * 70, 60, 12);
|
|
27
|
+
// 桌上:一只水罐和一块面包(蓝色时期静物的穷与静)
|
|
28
|
+
g.fillStyle = '#9fb6cc'; g.beginPath(); g.moveTo(880, 614); g.quadraticCurveTo(860, 560, 886, 530); g.lineTo(914, 530); g.quadraticCurveTo(940, 560, 920, 614); g.closePath(); g.fill();
|
|
29
|
+
g.fillStyle = '#6c7f8e'; g.beginPath(); g.ellipse(1040, 604, 50, 14, 0, 0, 7); g.fill();
|
|
30
|
+
}
|
|
31
|
+
const SW = {
|
|
32
|
+
wall: P.swatch(['#1d3866', '#24457a', '#163056', '#2e5a94', '#20406e', '#3b6878'], 0.8),
|
|
33
|
+
floor: P.swatch(['#4a6c94', '#587ca2', '#3e5f86', '#6b8fb6', '#456a8a'], 0.75),
|
|
34
|
+
win: P.swatch(['#7d9cbc', '#8eaac6', '#6f90b2'], 0.6),
|
|
35
|
+
};
|
|
36
|
+
// 第一版 cell16/len40/w14 满墙竖刷=「下雨/毛毯」,像印象派。蓝色时期是宽、长、低对比的刷面:cell34 len110 w34,色板混底 0.8,再糊 3px。
|
|
37
|
+
const stat = () => P.cached('bp_static', W, H, (g, cv) => {
|
|
38
|
+
const b = P.canvas(), bg = b.getContext('2d'); base(bg); g.drawImage(b, 0, 0);
|
|
39
|
+
P.strokes(g, b, { cell: 34, len: 110, width: 34, seed: 12, t: 0, boil: 0, outline: 0, jitterCol: 4,
|
|
40
|
+
angle: (x, y) => y > 720 ? 0.05 * P.noise(x * 0.01, y * 0.01) : -Math.PI / 2 + 0.5 * P.noise(x * 0.003, y * 0.003),
|
|
41
|
+
palette: (x, y, col, r) => (y > 720 ? SW.floor(col, r) : SW.wall(col, r)),
|
|
42
|
+
mask: (x, y) => !(x > 330 && x < 830 && y > 100 && y < 595) && Math.abs(y - 720) > 20 });
|
|
43
|
+
{ const tmp = P.canvas(), tg = tmp.getContext('2d'); tg.filter = 'blur(7px)'; tg.drawImage(cv, 0, 0); g.globalAlpha = 0.8; g.drawImage(tmp, 0, 0); g.globalAlpha = 1; }
|
|
44
|
+
// 干刷:笔触末端露底的细丝(很淡)
|
|
45
|
+
const r = rng(9); g.globalAlpha = 0.07; g.strokeStyle = '#a8c0d6'; g.lineWidth = 1.2;
|
|
46
|
+
for (let i = 0; i < 900; i++) { const x = r() * W, y = r() * H; if (x > 330 && x < 830 && y > 100 && y < 595) continue; const a = y > 720 ? 0 : -Math.PI / 2, L = 30 + r() * 60; g.beginPath(); g.moveTo(x, y); g.lineTo(x + Math.cos(a) * L, y + Math.sin(a) * L); g.stroke(); }
|
|
47
|
+
g.globalAlpha = 1;
|
|
48
|
+
// 窗:保留清楚的框,只给框上小刷痕
|
|
49
|
+
g.drawImage(b, 320, 100, 520, 500, 320, 100, 520, 500);
|
|
50
|
+
g.save(); g.beginPath(); g.rect(320, 100, 520, 500); g.clip();
|
|
51
|
+
P.strokes(g, b, { cell: 9, len: 20, width: 8, seed: 13, t: 0, boil: 0, outline: 0, jitterCol: 8, angle: (x, y) => (x > 560 && x < 600) ? -Math.PI / 2 : 0.03,
|
|
52
|
+
palette: (x, y, col, r) => SW.win(col, r), mask: (x, y) => !(x > 362 && x < 798 && y > 132 && y < 548) || (x > 572 && x < 588) || (y > 330 && y < 342) });
|
|
53
|
+
g.restore();
|
|
54
|
+
// 桌:单独一层+小笔触
|
|
55
|
+
const tb = P.canvas(), tbg = tb.getContext('2d'); table(tbg); tbg.save(); tbg.globalCompositeOperation = 'source-atop';
|
|
56
|
+
P.strokes(tbg, tb, { cell: 9, len: 26, width: 9, seed: 14, t: 0, boil: 0, outline: 0, jitterCol: 10, alphaMask: true, angle: (x, y) => y > 690 ? -Math.PI / 2 : 0.02 }); tbg.restore(); g.drawImage(tb, 0, 0);
|
|
57
|
+
// 环境轮廓(普鲁士蓝粗线,不抖)
|
|
58
|
+
g.strokeStyle = C.line; g.lineWidth = 5; g.lineJoin = 'round';
|
|
59
|
+
[[340, 110, 480, 460], [360, 130, 440, 420], [806, 614, 408, 34], [826, 648, 368, 40], [842, 688, 22, 216], [1156, 688, 22, 216]].forEach(r_ => g.strokeRect(...r_));
|
|
60
|
+
g.beginPath(); g.moveTo(0, 720); g.lineTo(806, 720); g.moveTo(1214, 720); g.lineTo(W, 720); g.stroke();
|
|
61
|
+
g.beginPath(); g.moveTo(880, 614); g.quadraticCurveTo(860, 560, 886, 530); g.lineTo(914, 530); g.quadraticCurveTo(940, 560, 920, 614); g.stroke();
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
const girlPal = { skin: '#90a9be', hair: '#cbd8e0', hairLine: '#5f7896', dress: '#1e3a6a', sleeve: '#24457a', fold: '#10223f', cuff: '#24457a', cheek: null, lip: '#4a6a8c', iris: '#0c1830', line: C.line, lw: 5, cupBody: '#c6d4e0', cupRim: '#2d4a6e', shoe: '#0c1830', browC: '#2a3a52' };
|
|
65
|
+
const catPal = { orange: '#4f719a', white: '#b6c8d8', stripe: '#273f66', line: C.line, lw: 5, eye: '#c9d6e2', earInner: '#6b8fb6', noseC: '#4a6a8c', whisker: '#c9d6e2' };
|
|
66
|
+
|
|
67
|
+
return {
|
|
68
|
+
draw(c, lt, t) {
|
|
69
|
+
const br = Math.sin(t * 1.8) * 0.026; // 缓慢而深的呼吸
|
|
70
|
+
const cup = 0.5 - 0.5 * Math.cos(Math.min(1, lt / 1.25) * Math.PI); // 端杯也慢
|
|
71
|
+
const tail = Math.sin(t * 2.2) * 0.3;
|
|
72
|
+
c.drawImage(stat(), 0, 0);
|
|
73
|
+
// 窗外:海浪(横向短笔,左移)+月光碎影(闪)
|
|
74
|
+
c.save(); c.beginPath(); c.rect(360, 400, 440, 150); c.clip();
|
|
75
|
+
const wr = rng(5); c.lineCap = 'round';
|
|
76
|
+
for (let i = 0; i < 70; i++) { const y = 405 + wr() * 140, sp = 20 + (y - 400) * 0.25, x = 360 + ((wr() * 520 - t * sp) % 520 + 520) % 520 - 40;
|
|
77
|
+
c.strokeStyle = wr() < 0.5 ? 'rgba(90,125,170,.8)' : 'rgba(30,55,95,.9)'; c.lineWidth = 3 + (y - 400) * 0.04; c.beginPath(); c.moveTo(x, y); c.lineTo(x + 26 + (y - 400) * 0.2, y + 1); c.stroke(); }
|
|
78
|
+
for (let k = 0; k < 14; k++) { const y = 410 + k * 10, tw = 0.5 + 0.5 * Math.sin(t * 5 + k * 1.9), w = (10 + k * 4) * tw; c.fillStyle = `rgba(205,220,235,${0.35 + 0.5 * tw})`; c.fillRect(670 - w / 2 + Math.sin(t * 2 + k) * 6, y, w, 3); }
|
|
79
|
+
c.restore();
|
|
80
|
+
// 云:一条苍白的长云缓慢横过月亮
|
|
81
|
+
c.save(); c.beginPath(); c.rect(360, 130, 440, 270); c.clip(); c.fillStyle = 'rgba(150,175,205,.45)'; const cx = 400 + t * 45; c.beginPath(); c.ellipse(cx, 236, 130, 14, -0.04, 0, 7); c.fill(); c.beginPath(); c.ellipse(cx + 90, 250, 90, 9, 0, 0, 7); c.fill(); c.restore();
|
|
82
|
+
// 角色
|
|
83
|
+
const K = RIG.cat({ tail, blink: 0, breathe: br * 1.4, ...CSTR });
|
|
84
|
+
const G = RIG.girl({ cup, sip: 0, breathe: br, hair: 'down', ...GSTR });
|
|
85
|
+
const L = P.scratch('bpChars'), lg = L.getContext('2d'); lg.reset();
|
|
86
|
+
RIG.drawCat(lg, K, { ...catPal, lw: 0 });
|
|
87
|
+
lg.save();
|
|
88
|
+
RIG.drawGirl(lg, G, { ...girlPal, mode: 'fill' });
|
|
89
|
+
// 披肩:从头顶罩下,盖住后脑与肩背,落到腰
|
|
90
|
+
const ht = G.A.headTop, fh = G.A.forehead, np = G.A.nape, bk = G.A.back, wa = G.A.waist, sh = G.A.shoulder;
|
|
91
|
+
const shawl = RIG.smooth([[fh[0] + 14, fh[1] - 22], [ht[0] + 10, ht[1] - 26], [ht[0] + 80, ht[1] + 4], [np[0] + 50, np[1] + 10], [bk[0] + 24, bk[1] + 20], [wa[0] + 70, wa[1] - 10], [wa[0] + 20, wa[1] - 40], [sh[0] + 10, sh[1] + 30], [np[0] - 10, np[1] + 10], [ht[0] + 30, ht[1] + 40], [fh[0] + 30, fh[1] - 4]]);
|
|
92
|
+
lg.fillStyle = '#6b8fb6'; lg.fill(shawl);
|
|
93
|
+
// 端杯的手:长指(El Greco 式),手指绕杯
|
|
94
|
+
lg.fillStyle = girlPal.skin; const hd = G.A.hand; for (let k = 0; k < 3; k++) { lg.save(); lg.translate(hd[0], hd[1]); lg.rotate(-2.4 + k * 0.28); lg.beginPath(); lg.ellipse(18, 0, 22, 4.5, 0, 0, 7); lg.fill(); lg.restore(); }
|
|
95
|
+
lg.restore();
|
|
96
|
+
// 小笔触肌理(只在角色上)
|
|
97
|
+
lg.save(); lg.globalCompositeOperation = 'source-atop';
|
|
98
|
+
P.strokes(lg, L, { cell: 7, len: 18, width: 6, seed: 21, t: 0, boil: 0, outline: 0, jitterCol: 14, alphaMask: true,
|
|
99
|
+
angle: (x, y) => x < 760 ? -Math.PI / 2 + 0.6 * Math.sin(y * 0.02) : -Math.PI / 2 + 0.25 * Math.sin(x * 0.03) });
|
|
100
|
+
// 冷光:左上来的微弱亮、右下沉暗
|
|
101
|
+
let vg = lg.createLinearGradient(1150, 250, 1480, 900); vg.addColorStop(0, 'rgba(190,210,230,.18)'); vg.addColorStop(1, 'rgba(5,12,30,.45)'); lg.fillStyle = vg; lg.fillRect(1050, 150, 500, 820);
|
|
102
|
+
vg = lg.createLinearGradient(420, 560, 700, 920); vg.addColorStop(0, 'rgba(190,210,230,.12)'); vg.addColorStop(1, 'rgba(5,12,30,.4)'); lg.fillStyle = vg; lg.fillRect(360, 500, 380, 420);
|
|
103
|
+
lg.restore();
|
|
104
|
+
c.drawImage(L, 0, 0);
|
|
105
|
+
// 粗轮廓:只取看得见的线(猫、少女各自在拉长后的坐标里算)
|
|
106
|
+
c.drawImage(RIG.visibleLines('bpCat', (g, lc) => RIG.drawCat(g, K, { ...catPal, line: lc, whisker: lc }), C.line, [330, 480, 760, 940]), 0, 0);
|
|
107
|
+
c.drawImage(RIG.visibleLines('bpGirl', (g, lc) => { RIG.drawGirl(g, G, { ...girlPal, line: lc });
|
|
108
|
+
g.fillStyle = '#6b8fb6'; g.fill(shawl); g.strokeStyle = lc; g.lineWidth = 5; g.stroke(shawl); }, C.line, [1040, 150, 1540, 960]), 0, 0);
|
|
109
|
+
// 披肩褶:几道深蓝长线
|
|
110
|
+
c.save(); c.save(); c.clip(shawl); c.strokeStyle = 'rgba(20,40,80,.6)'; c.lineWidth = 4; c.lineCap = 'round';
|
|
111
|
+
[[0, 0], [24, 10], [48, 22]].forEach(([dx, dy]) => { c.beginPath(); c.moveTo(ht[0] + 30 + dx, ht[1] + dy); c.quadraticCurveTo(np[0] + 30 + dx, np[1] + 40, bk[0] + dx * 0.3, bk[1] + 60 + dy); c.stroke(); }); c.restore();
|
|
112
|
+
c.restore();
|
|
113
|
+
// 热气:慢
|
|
114
|
+
const cpp = [G.cup.x, G.cup.y];
|
|
115
|
+
P.steam(c, t * 0.5, cpp[0], cpp[1] - 8, { h: 70, n: 2, color: 'rgba(200,215,230,.55)', width: 3.5, spread: 12, wobble: 10 });
|
|
116
|
+
// 画布纹+冷暗角
|
|
117
|
+
c.drawImage(P.cached('bp_over', W, H, (g) => {
|
|
118
|
+
g.strokeStyle = 'rgba(10,20,40,.06)'; g.lineWidth = 1; for (let x = 0; x < W; x += 4) { g.beginPath(); g.moveTo(x, 0); g.lineTo(x, H); g.stroke(); } for (let y = 0; y < H; y += 4) { g.beginPath(); g.moveTo(0, y); g.lineTo(W, y); g.stroke(); }
|
|
119
|
+
const v = g.createRadialGradient(900, 520, 380, 960, 540, 1150); v.addColorStop(0, 'rgba(5,10,25,0)'); v.addColorStop(1, 'rgba(5,10,25,.6)'); g.fillStyle = v; g.fillRect(0, 0, W, H);
|
|
120
|
+
}), 0, 0);
|
|
121
|
+
},
|
|
122
|
+
};
|
|
123
|
+
})();
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
// 乔托(斯克罗威尼礼拜堂湿壁画):群青天、重量感的袍、视线连接人物、斜置的建筑体块、灰泥与一天的活接缝。
|
|
2
|
+
// 题材(新构图,不搬名作):码头仓库门口,两位搬运工把一只大木箱交接,第三人低头看着箱角。
|
|
3
|
+
// 原作锚定(scripts/analyze/fetch_reference.py 拉的公版图,色值与签名见 配方卡):群青天 #3a5a9a→#8fa4c8、土红/赭/橄榄绿袍、
|
|
4
|
+
// 灰粉建筑 #c9b9ae、金边装饰带、人物视线互相咬合、衣褶大块明暗;整体粉白哑光。
|
|
5
|
+
// 管线:plate(干净的形:天→岩坡→建筑→人→箱)→ MEDIUM.fresco(轻糊+石灰罩+灰泥相乘+针孔接缝)→ 装饰边框 → 动作。
|
|
6
|
+
SCENES['38_giotto'] = (() => {
|
|
7
|
+
const W = 1920, H = 1080, { clamp, lerp, rng, ss } = U, P = PAINT, M = MEDIUM, TAU = Math.PI * 2;
|
|
8
|
+
let plate, pg;
|
|
9
|
+
const ease = x => { x = clamp(x); return x * x * (3 - 2 * x); };
|
|
10
|
+
|
|
11
|
+
function sky(g) {
|
|
12
|
+
const gr = g.createLinearGradient(0, 0, 0, 620); gr.addColorStop(0, '#2347a0'); gr.addColorStop(0.5, '#3f68b8'); gr.addColorStop(1, '#a9c0e6');
|
|
13
|
+
g.fillStyle = gr; g.fillRect(0, 0, W, H);
|
|
14
|
+
// 群青是一层层罩的:大尺度斜向软斑(fbm),不是横条
|
|
15
|
+
const r = rng(11);
|
|
16
|
+
for (let i = 0; i < 140; i++) { const x = r() * W, y = r() * 600, rx = 90 + r() * 260, ry = 24 + r() * 70; g.save(); g.translate(x, y); g.rotate(-0.25 + (r() - .5) * 0.5); g.filter = 'blur(14px)';
|
|
17
|
+
g.fillStyle = `rgba(${r() < 0.55 ? '24,52,132' : '170,190,232'},${0.06 + r() * 0.09})`; g.beginPath(); g.ellipse(0, 0, rx, ry, 0, 0, TAU); g.fill(); g.restore(); }
|
|
18
|
+
g.filter = 'none';
|
|
19
|
+
// 金星点(原作天幕有星)
|
|
20
|
+
for (let i = 0; i < 26; i++) { const x = 60 + r() * (W - 120), y = 40 + r() * 330, s = 5 + r() * 4; g.fillStyle = 'rgba(224,190,100,.85)'; g.beginPath();
|
|
21
|
+
for (let k = 0; k < 8; k++) { const a = k / 8 * TAU, rr = k % 2 ? s * 0.4 : s; g.lineTo(x + Math.cos(a) * rr, y + Math.sin(a) * rr); } g.closePath(); g.fill(); }
|
|
22
|
+
}
|
|
23
|
+
function rocks(g) { // 乔托的岩坡:斜向的大块面,亮面朝左上,暗面朝下,边缘有「梯田」台阶
|
|
24
|
+
const poly = (pts, c0, c1) => { const gr = g.createLinearGradient(pts[0][0], pts[0][1], pts[2][0], pts[2][1] + 120); gr.addColorStop(0, c0); gr.addColorStop(1, c1);
|
|
25
|
+
g.fillStyle = gr; g.beginPath(); pts.forEach((p, i) => i ? g.lineTo(p[0], p[1]) : g.moveTo(p[0], p[1])); g.closePath(); g.fill(); M.outline(g, [...pts, pts[0]], { w: [2, 3.4, 2], col: '#6e5a4a', a: 0.6 }); };
|
|
26
|
+
poly([[0, 420], [340, 300], [620, 410], [700, 640], [0, 700]], '#c4b79c', '#8e8068');
|
|
27
|
+
poly([[0, 560], [420, 470], [640, 620], [700, 700], [0, 760]], '#b4a487', '#7f7058');
|
|
28
|
+
poly([[300, 420], [560, 330], [760, 470], [640, 620], [420, 470]], '#d1c6ac', '#a1937a');
|
|
29
|
+
g.fillStyle = 'rgba(80,100,50,.55)'; [[60, 640, 120], [250, 600, 90], [470, 640, 80]].forEach(([x, y, w]) => { g.beginPath(); g.ellipse(x, y, w, 20, -0.15, 0, TAU); g.fill(); });
|
|
30
|
+
g.strokeStyle = 'rgba(70,90,45,.9)'; g.lineWidth = 3; // 一棵小树,几笔叶团
|
|
31
|
+
g.beginPath(); g.moveTo(520, 440); g.lineTo(522, 360); g.stroke(); g.fillStyle = '#5f7a43'; [[522, 340, 34], [498, 372, 26], [548, 368, 26]].forEach(([x, y, rr]) => { g.beginPath(); g.arc(x, y, rr, 0, TAU); g.fill(); });
|
|
32
|
+
}
|
|
33
|
+
function building(g) { // 仓库:两个可见立面(正面+斜侧),透视故意不统一(前期文艺复兴之前的「舞台盒」),带拱门和垛口
|
|
34
|
+
const front = [[1040, 250], [1620, 250], [1620, 860], [1040, 860]], side = [[1620, 250], [1810, 190], [1810, 820], [1620, 860]];
|
|
35
|
+
let gr = g.createLinearGradient(1040, 0, 1620, 0); gr.addColorStop(0, '#d9c9bd'); gr.addColorStop(1, '#bcab9f'); g.fillStyle = gr; g.beginPath(); front.forEach((p, i) => i ? g.lineTo(p[0], p[1]) : g.moveTo(p[0], p[1])); g.fill();
|
|
36
|
+
gr = g.createLinearGradient(1620, 0, 1810, 0); gr.addColorStop(0, '#9c8b82'); gr.addColorStop(1, '#7d6d66'); g.fillStyle = gr; g.beginPath(); side.forEach((p, i) => i ? g.lineTo(p[0], p[1]) : g.moveTo(p[0], p[1])); g.fill();
|
|
37
|
+
// 檐下装饰带:红白相间的菱格(科斯马蒂式)
|
|
38
|
+
g.fillStyle = '#8c3d34'; g.fillRect(1040, 262, 580, 30); g.fillStyle = '#ead9aa'; for (let x = 1052; x < 1610; x += 36) { g.beginPath(); g.moveTo(x, 277); g.lineTo(x + 12, 266); g.lineTo(x + 24, 277); g.lineTo(x + 12, 288); g.closePath(); g.fill(); }
|
|
39
|
+
// 侧面小窗
|
|
40
|
+
g.fillStyle = '#4a3a30'; [[1685, 380], [1685, 560]].forEach(([x, y]) => { g.beginPath(); g.moveTo(x, y + 80); g.lineTo(x, y + 20); g.arc(x + 24, y + 20, 24, Math.PI, 0); g.lineTo(x + 48, y + 80); g.fill(); });
|
|
41
|
+
// 垛口
|
|
42
|
+
for (let i = 0; i < 6; i++) { const x = 1050 + i * 98; g.fillStyle = '#cdbdb0'; g.fillRect(x, 200, 62, 52); M.outline(g, [[x, 252], [x, 200], [x + 62, 200], [x + 62, 252]], { w: [2, 3, 2], col: '#6e5a4a', a: 0.6 }); }
|
|
43
|
+
// 石砌水平缝(不画方格,画几道长缝,缝处有错位)
|
|
44
|
+
g.strokeStyle = 'rgba(110,90,78,.28)'; g.lineWidth = 2; for (let y = 300; y < 860; y += 62) { g.beginPath(); g.moveTo(1040, y); g.lineTo(1620, y + (y % 124 ? 2 : -2)); g.stroke(); }
|
|
45
|
+
// 拱门:金边环+深洞
|
|
46
|
+
const cx = 1290, top = 330, w = 250;
|
|
47
|
+
g.fillStyle = '#e4d3aa'; g.beginPath(); g.moveTo(cx - w / 2 - 26, 860); g.lineTo(cx - w / 2 - 26, top + w / 2); g.arc(cx, top + w / 2, w / 2 + 26, Math.PI, 0); g.lineTo(cx + w / 2 + 26, 860); g.closePath(); g.fill();
|
|
48
|
+
gr = g.createLinearGradient(0, top, 0, 860); gr.addColorStop(0, '#4a3a30'); gr.addColorStop(1, '#7a634e'); g.fillStyle = gr;
|
|
49
|
+
g.beginPath(); g.moveTo(cx - w / 2, 860); g.lineTo(cx - w / 2, top + w / 2); g.arc(cx, top + w / 2, w / 2, Math.PI, 0); g.lineTo(cx + w / 2, 860); g.closePath(); g.fill();
|
|
50
|
+
g.strokeStyle = '#c9a24b'; g.lineWidth = 7; g.beginPath(); g.arc(cx, top + w / 2, w / 2 + 14, Math.PI, 0); g.stroke();
|
|
51
|
+
// 门洞里的暗处有几袋货
|
|
52
|
+
g.fillStyle = '#6b5846'; [[cx - 70, 800, 54], [cx + 22, 810, 60]].forEach(([x, y, s]) => { g.beginPath(); g.ellipse(x, y, s, s * 0.7, 0, 0, TAU); g.fill(); });
|
|
53
|
+
M.outline(g, [...front, front[0]], { w: [2.4, 3.6, 2.4], col: '#5f4a3d', a: 0.7 }); M.outline(g, [...side, side[0]], { w: [2.4, 3.6, 2.4], col: '#5f4a3d', a: 0.7 });
|
|
54
|
+
// 墙脚台阶
|
|
55
|
+
g.fillStyle = '#b5a592'; g.fillRect(1010, 860, 840, 26); g.fillStyle = '#9a8a78'; g.fillRect(1010, 886, 840, 16);
|
|
56
|
+
}
|
|
57
|
+
function ground(g) {
|
|
58
|
+
const gr = g.createLinearGradient(0, 760, 0, H); gr.addColorStop(0, '#b9a56e'); gr.addColorStop(0.5, '#9a8754'); gr.addColorStop(1, '#6a5a36'); g.fillStyle = gr; g.fillRect(0, 760, W, H - 760);
|
|
59
|
+
// 远处水带(码头边):一条冷青带,岩坡脚下
|
|
60
|
+
const wg = g.createLinearGradient(0, 735, 0, 790); wg.addColorStop(0, '#7f9fb4'); wg.addColorStop(1, '#5f8294'); g.fillStyle = wg; g.fillRect(0, 735, 1010, 52);
|
|
61
|
+
g.strokeStyle = 'rgba(230,240,245,.5)'; g.lineWidth = 2; for (let i = 0; i < 18; i++) { const x = 40 + i * 52, y = 745 + (i % 3) * 14; g.beginPath(); g.moveTo(x, y); g.quadraticCurveTo(x + 14, y - 3, x + 30, y); g.stroke(); }
|
|
62
|
+
// 土路的亮带与车辙
|
|
63
|
+
g.fillStyle = 'rgba(214,194,140,.55)'; g.beginPath(); g.moveTo(0, 820); g.quadraticCurveTo(520, 780, 1010, 830); g.lineTo(1010, 930); g.quadraticCurveTo(500, 900, 0, 960); g.fill();
|
|
64
|
+
const r = rng(5); for (let i = 0; i < 420; i++) { g.fillStyle = `rgba(${r() < 0.5 ? '84,64,36' : '214,198,150'},${0.1 + r() * 0.18})`; g.fillRect(r() * W, 790 + r() * 290, 6 + r() * 44, 2 + r() * 2); }
|
|
65
|
+
// 草簇与石子
|
|
66
|
+
g.strokeStyle = '#4d6a36'; g.lineWidth = 2.4; for (let i = 0; i < 26; i++) { const x = r() * W, y = 960 + r() * 100; for (let k = -2; k <= 2; k++) { g.beginPath(); g.moveTo(x, y); g.quadraticCurveTo(x + k * 5, y - 14, x + k * 9, y - 26 - r() * 8); g.stroke(); } }
|
|
67
|
+
g.fillStyle = '#8c7e66'; for (let i = 0; i < 26; i++) { g.beginPath(); g.ellipse(r() * W, 900 + r() * 170, 7 + r() * 12, 4 + r() * 6, 0, 0, TAU); g.fill(); }
|
|
68
|
+
// 门边的麻袋和木桶(货)
|
|
69
|
+
[[1460, 905, 62], [1550, 915, 54]].forEach(([x, y, s2]) => { const sg = g.createLinearGradient(x - s2, 0, x + s2, 0); sg.addColorStop(0, '#d8c79a'); sg.addColorStop(1, '#a89468'); g.fillStyle = sg; g.beginPath(); g.moveTo(x - s2 * 0.8, y); g.quadraticCurveTo(x - s2, y - s2 * 1.1, x, y - s2 * 1.3); g.quadraticCurveTo(x + s2, y - s2 * 1.1, x + s2 * 0.8, y); g.closePath(); g.fill(); g.strokeStyle = 'rgba(90,70,48,.7)'; g.lineWidth = 3; g.stroke(); g.beginPath(); g.moveTo(x - s2 * 0.35, y - s2 * 1.1); g.quadraticCurveTo(x, y - s2 * 0.9, x + s2 * 0.35, y - s2 * 1.1); g.stroke(); });
|
|
70
|
+
const bgd = g.createLinearGradient(1640, 0, 1760, 0); bgd.addColorStop(0, '#9a6a3c'); bgd.addColorStop(1, '#6e4724'); g.fillStyle = bgd; g.fillRect(1640, 790, 120, 130); g.beginPath(); g.ellipse(1700, 790, 60, 14, 0, 0, TAU); g.fill(); g.strokeStyle = '#3d3a36'; g.lineWidth = 6; [820, 880].forEach(y => { g.beginPath(); g.moveTo(1640, y); g.lineTo(1760, y); g.stroke(); });
|
|
71
|
+
}
|
|
72
|
+
function build() {
|
|
73
|
+
plate = P.canvas(); pg = plate.getContext('2d');
|
|
74
|
+
sky(pg); rocks(pg); building(pg); ground(pg);
|
|
75
|
+
}
|
|
76
|
+
const GROUND = M.plaster('giotto', { base: '#d8cdb6', seed: 9, seams: [[[0, 372], [380, 380], [760, 366], [1120, 378], [1500, 368], [1920, 376]], [[640, 0], [652, 190], [630, 372]]] });
|
|
77
|
+
|
|
78
|
+
// 木箱:有体积(正面+顶面),箱角包铁
|
|
79
|
+
function crate(c, x, y, s, tilt) {
|
|
80
|
+
c.save(); c.translate(x, y); c.rotate(tilt);
|
|
81
|
+
const w = 150 * s, h = 110 * s, d = 28 * s;
|
|
82
|
+
c.fillStyle = '#a77b49'; c.fillRect(-w / 2, -h / 2, w, h);
|
|
83
|
+
c.fillStyle = '#c59a62'; c.beginPath(); c.moveTo(-w / 2, -h / 2); c.lineTo(-w / 2 + d, -h / 2 - d); c.lineTo(w / 2 + d, -h / 2 - d); c.lineTo(w / 2, -h / 2); c.fill();
|
|
84
|
+
c.fillStyle = '#7d5a31'; c.beginPath(); c.moveTo(w / 2, -h / 2); c.lineTo(w / 2 + d, -h / 2 - d); c.lineTo(w / 2 + d, h / 2 - d); c.lineTo(w / 2, h / 2); c.fill();
|
|
85
|
+
c.strokeStyle = 'rgba(70,45,25,.55)'; c.lineWidth = 2 * s; for (let k = 1; k < 4; k++) { c.beginPath(); c.moveTo(-w / 2, -h / 2 + k * h / 4); c.lineTo(w / 2, -h / 2 + k * h / 4); c.stroke(); }
|
|
86
|
+
c.strokeStyle = '#3f3a36'; c.lineWidth = 7 * s; c.strokeRect(-w / 2 + 4, -h / 2 + 4, w - 8, h - 8);
|
|
87
|
+
c.beginPath(); c.moveTo(-w / 2, -h / 2); c.lineTo(w / 2, h / 2); c.stroke();
|
|
88
|
+
M.outline(c, [[-w / 2, -h / 2], [w / 2, -h / 2], [w / 2, h / 2], [-w / 2, h / 2], [-w / 2, -h / 2]], { w: [2.4, 3.2, 2.4], col: '#4a2f22', a: 0.8 });
|
|
89
|
+
c.restore();
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function draw(c, lt, t) {
|
|
93
|
+
if (!plate) build();
|
|
94
|
+
const tt = clamp(lt, 0, 6);
|
|
95
|
+
const hand = ease((tt - 0.6) / 3.2); // 箱子从左到右交接(0.6→3.8s),之后右边的人接稳、放下
|
|
96
|
+
const settle = ease((tt - 3.8) / 1.4);
|
|
97
|
+
const g = pg;
|
|
98
|
+
// 动态的形画到 plate 副本:背景 plate 不动,人物每帧画在 live 上
|
|
99
|
+
const live = P.scratch('giotto_live'), lg = live.getContext('2d'); lg.reset(); lg.drawImage(plate, 0, 0);
|
|
100
|
+
// 人物:左搬运工(赭红袍+深绿披风)、右搬运工(橄榄绿袍+土红披风)、门边低头者(青灰袍)
|
|
101
|
+
const bx = lerp(800, 890, hand), by = lerp(735, 748, hand) + Math.sin(hand * Math.PI) * -34 + settle * 38, tilt = Math.sin(hand * Math.PI) * -0.07;
|
|
102
|
+
const boxTop = [bx, by];
|
|
103
|
+
M.figure(lg, { hemK: 0.82, halo: true, beard: false, x: 745, y: 905, h: 480, face: 1, lean: 0.10 + 0.07 * (1 - ease(hand * 1.4)), bow: 0.4, t: tt, seed: 1, sway: 0.3,
|
|
104
|
+
robe: ['#f0a98c', '#cf5f4a', '#8c3430'], mantle: ['#7da07c', '#4f7456', '#2f4f3c'], under: '#ecdcae', skin: '#e2b48a', hair: '#5b3a22',
|
|
105
|
+
gaze: [bx + 30, by - 20], hands: [[bx - 74, by + 14], [bx - 74, by - 24]] });
|
|
106
|
+
M.figure(lg, { hemK: 1.12, halo: true, beard: false, x: 1030, y: 915, h: 500, face: -1, lean: 0.06 + 0.1 * ss(0.2, 0.9, hand), bow: 0.5, t: tt, seed: 2, sway: 0.3,
|
|
107
|
+
robe: ['#bccb8d', '#86a05c', '#4c6a3a'], mantle: ['#d28a6e', '#a8553f', '#6f3329'], under: '#efe2b8', skin: '#d9a97e', hair: '#3b2a1c',
|
|
108
|
+
gaze: [bx, by - 12], hands: [[bx + 74, by + 16 + settle * 6], [bx + 74, by - 24]] });
|
|
109
|
+
crate(lg, bx, by, 1, tilt);
|
|
110
|
+
// 前景手要压在箱前:重画两只手
|
|
111
|
+
// 第三人:站在左岩坡边,低头
|
|
112
|
+
M.figure(lg, { hemK: 0.7, halo: true, x: 330, y: 885, h: 430, face: 1, lean: 0.05, bow: 0.9, t: tt, seed: 3, sway: 0.35,
|
|
113
|
+
robe: ['#b8c6d0', '#8399ab', '#53677d'], under: '#e9dcb4', skin: '#dcae85', hair: '#6b4b30', gaze: [bx - 120, by + 20], hands: [[430, 720], [445, 762]] });
|
|
114
|
+
// 箱子落地时扬起的一点灰
|
|
115
|
+
const dust = ss(3.7, 4.0, tt) * (1 - ss(4.0, 5.4, tt));
|
|
116
|
+
if (dust > 0) { lg.fillStyle = `rgba(210,190,150,${0.35 * dust})`; for (let i = 0; i < 9; i++) { const a = i / 9 * TAU; lg.beginPath(); lg.ellipse(bx + Math.cos(a) * 90 * (0.5 + dust), 868 + Math.sin(a) * 8, 22, 9, 0, 0, TAU); lg.fill(); } }
|
|
117
|
+
// 一只鸟横过天(慢慢,不抢戏)
|
|
118
|
+
const bt = ss(0.2, 5.8, tt), bxp = lerp(-60, 1000, bt), byp = 130 + Math.sin(bt * 9) * 14;
|
|
119
|
+
lg.strokeStyle = 'rgba(240,235,220,.9)'; lg.lineWidth = 3; lg.beginPath(); lg.moveTo(bxp - 16, byp + Math.sin(tt * 11) * 6); lg.quadraticCurveTo(bxp, byp - 8, bxp + 16, byp + Math.sin(tt * 11 + 1) * 6); lg.stroke();
|
|
120
|
+
|
|
121
|
+
M.fresco(c, live, { ground: GROUND, chalk: 0.07, soften: 0.7, plasterAlpha: 0.5, sat: 1.12 });
|
|
122
|
+
// 装饰边框:深红带+金线+菱形 cosmati 纹(原作每幅都被这样一条带框住)
|
|
123
|
+
c.save(); c.lineWidth = 1;
|
|
124
|
+
c.fillStyle = '#7b2f2a'; c.fillRect(0, 0, W, 34); c.fillRect(0, H - 34, W, 34); c.fillRect(0, 0, 34, H); c.fillRect(W - 34, 0, 34, H);
|
|
125
|
+
c.strokeStyle = '#d7b35c'; c.lineWidth = 3; c.strokeRect(34, 34, W - 68, H - 68);
|
|
126
|
+
c.fillStyle = '#e8d6a0'; for (let x = 60; x < W - 40; x += 44) { [[x, 17], [x, H - 17]].forEach(([a, b]) => { c.beginPath(); c.moveTo(a, b - 8); c.lineTo(a + 10, b); c.lineTo(a, b + 8); c.lineTo(a - 10, b); c.fill(); }); }
|
|
127
|
+
for (let y = 60; y < H - 40; y += 44) { [[17, y], [W - 17, y]].forEach(([a, b]) => { c.beginPath(); c.moveTo(a, b - 10); c.lineTo(a + 8, b); c.lineTo(a, b + 10); c.lineTo(a - 8, b); c.fill(); }); }
|
|
128
|
+
c.restore();
|
|
129
|
+
// 边缘剥落:灰泥外圈略亮、角上几处脱落(只在边框与天空,不碰人物)
|
|
130
|
+
c.save(); c.globalCompositeOperation = 'screen'; const vg = c.createRadialGradient(W / 2, H / 2, 600, W / 2, H / 2, 1180); vg.addColorStop(0, 'rgba(255,245,225,0)'); vg.addColorStop(1, 'rgba(255,245,225,.12)'); c.fillStyle = vg; c.fillRect(0, 0, W, H); c.restore();
|
|
131
|
+
}
|
|
132
|
+
return { draw };
|
|
133
|
+
})();
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
SCENES['39_piero']=(()=>{
|
|
2
|
+
const TAU=Math.PI*2; let bg,grain,raw;
|
|
3
|
+
const rng=(s)=>()=>{s=(Math.imul(s,1664525)+1013904223)|0;return (s>>>0)/4294967296;};
|
|
4
|
+
function path(c,d,col,st,lw=2){const p=new Path2D(d);if(col){c.fillStyle=col;c.fill(p);}if(st){c.strokeStyle=st;c.lineWidth=lw;c.stroke(p);}return p;}
|
|
5
|
+
function poly(c,pts,col,st,lw=2){c.beginPath();pts.forEach((p,i)=>i?c.lineTo(...p):c.moveTo(...p));c.closePath();if(col){c.fillStyle=col;c.fill();}if(st){c.strokeStyle=st;c.lineWidth=lw;c.stroke();}}
|
|
6
|
+
function el(c,x,y,rx,ry,col,st,lw=2){c.beginPath();c.ellipse(x,y,rx,ry,0,0,TAU);if(col){c.fillStyle=col;c.fill();}if(st){c.strokeStyle=st;c.lineWidth=lw;c.stroke();}}
|
|
7
|
+
function line(c,pts,col,w=2){c.beginPath();pts.forEach((p,i)=>i?c.lineTo(...p):c.moveTo(...p));c.strokeStyle=col;c.lineWidth=w;c.stroke();}
|
|
8
|
+
function grad(c,x,y,X,Y,colors){const g=c.createLinearGradient(x,y,X,Y);colors.forEach((a,i)=>g.addColorStop(i/(colors.length-1),a));return g;}
|
|
9
|
+
function layer(fn){let a=document.createElement('canvas');a.width=1920;a.height=1080;fn(a.getContext('2d'));return a;}
|
|
10
|
+
function finish(c){if(!grain)grain=layer(g=>{let r=rng(7891);for(let i=0;i<21000;i++){g.fillStyle=i%3?'rgba(49,32,22,.045)':'rgba(255,248,220,.08)';let x=r()*1920,y=r()*1080;g.fillRect(x,y,1+r()*2.4,1+r()*1.5);}});c.drawImage(grain,0,0);}
|
|
11
|
+
|
|
12
|
+
function back(c){
|
|
13
|
+
c.fillStyle=grad(c,0,0,0,1080,['#c3d4d3','#e0e0cd']);c.fillRect(0,0,1920,1080);
|
|
14
|
+
// A contemporary measuring hall, ordered through repeated intervals rather than antique iconography.
|
|
15
|
+
c.fillStyle='#d9d2b9';c.fillRect(0,80,1920,660);
|
|
16
|
+
for(let x=100;x<1920;x+=420){c.fillStyle='#718c8c';c.fillRect(x,153,274,451);c.fillStyle=grad(c,0,150,0,610,['#b5cccf','#edf0d8']);c.fillRect(x+14,166,246,424);for(let j=0;j<3;j++)line(c,[[x+15,270+j*105],[x+259,270+j*105]],'#d7d8c4',7);line(c,[[x+138,165],[x+138,590]],'#d6d8c6',9);}
|
|
17
|
+
poly(c,[[0,0],[1920,0],[1920,84],[0,84]],'#6b827e');c.fillStyle='#eee5cd';c.fillRect(0,78,1920,23);
|
|
18
|
+
for(let x=20;x<1920;x+=420){c.fillStyle=grad(c,x,0,x+64,0,['#b1b19b','#e8e0c7','#c4bea8']);c.fillRect(x,101,64,620);c.fillStyle='#b3ac97';c.fillRect(x-10,690,85,37);}
|
|
19
|
+
poly(c,[[0,735],[1920,735],[1920,1080],[0,1080]],'#d2c5a5');
|
|
20
|
+
const vx=1010,vy=550;for(let x=-1800;x<4200;x+=260)line(c,[[vx+(x-vx)*.38,735],[x,1080]],'#a89e85',2);for(let y of [762,803,861,945,1060])line(c,[[0,y],[1920,y]],'#a89e85',2);
|
|
21
|
+
// Stacked instruments inhabit different measured planes.
|
|
22
|
+
poly(c,[[1310,718],[1650,682],[1820,754],[1485,811]],'#d3d0b8','#9a9f90',2);poly(c,[[1485,811],[1820,754],[1820,970],[1485,1042]],'#a6b0a3');poly(c,[[1310,718],[1485,811],[1485,1042],[1310,935]],'#b8b9a3');
|
|
23
|
+
for(let y=836;y<1010;y+=42)line(c,[[1504,y],[1793,y-60]],'#81968f',3);
|
|
24
|
+
c.fillStyle='#b7a889';c.fillRect(120,689,375,226);poly(c,[[120,689],[354,638],[535,682],[300,739]],'#e5d5b0');poly(c,[[300,739],[535,682],[535,910],[300,966]],'#8e9d90');
|
|
25
|
+
let r=rng(391);for(let i=0;i<1400;i++){c.fillStyle=i%2?'rgba(255,255,228,.06)':'rgba(70,91,83,.04)';c.fillRect(r()*1920,r()*1080,1+r()*18,1);}
|
|
26
|
+
}
|
|
27
|
+
function sphere(c,x,y,r,col){let g=c.createRadialGradient(x-r*.4,y-r*.45,2,x,y,r);g.addColorStop(0,'#f3ebcc');g.addColorStop(.45,col);g.addColorStop(1,'#647d77');el(c,x,y,r,r,g);}
|
|
28
|
+
return {draw(dst,lt){if(!raw)raw=layer(()=>{});const c=raw.getContext('2d',{willReadFrequently:true});c.reset();if(!bg)bg=layer(back);c.drawImage(bg,0,0);const t=lt;
|
|
29
|
+
el(c,878,927,341,62,'rgba(85,100,88,.14)');
|
|
30
|
+
// Plinth, precisely vertical axis and a suspended mechanical planetary model.
|
|
31
|
+
poly(c,[[560,868],[898,802],[1180,880],[829,971]],'#ded8bb','#88988a',2);poly(c,[[560,868],[829,971],[829,1053],[560,947]],'#b2b79e');poly(c,[[829,971],[1180,880],[1180,964],[829,1053]],'#8e9c8b');
|
|
32
|
+
c.fillStyle=grad(c,835,0,902,0,['#7c968b','#d8d9bd','#a4b19c']);c.fillRect(835,533,67,359);el(c,868,893,113,29,'#bec4aa','#819589',3);
|
|
33
|
+
c.save();c.translate(868,444);
|
|
34
|
+
// Meridian rings, with alternate back and front arcs around the central orb.
|
|
35
|
+
c.save();c.rotate(-.35+t*.18);for(let i=0;i<3;i++){c.beginPath();c.ellipse(0,0,287-i*7,310-i*7,0,0,TAU);c.strokeStyle=i===1?'#d9c79a':'#7e8a71';c.lineWidth=i===1?13:3;c.stroke();}for(let j=0;j<64;j++){let a=j*TAU/64;line(c,[[Math.cos(a)*292,Math.sin(a)*315],[Math.cos(a)*(j%4?280:272),Math.sin(a)*(j%4?303:295)]],'#8a8f74',2);}c.restore();
|
|
36
|
+
const a=t*.43,px=Math.cos(a)*251,py=Math.sin(a)*87;
|
|
37
|
+
c.beginPath();c.ellipse(0,0,318,111,-.15,Math.PI,TAU);c.strokeStyle='#a89e79';c.lineWidth=10;c.stroke();
|
|
38
|
+
line(c,[[0,0],[px,py]],'#8f987d',9);if(py<0)sphere(c,px,py,43,'#b87959');
|
|
39
|
+
sphere(c,0,0,119,'#c5b979');
|
|
40
|
+
// Very restrained latitude bands maintain rounded, clear volume.
|
|
41
|
+
c.save();c.beginPath();c.arc(0,0,119,0,TAU);c.clip();for(let y=-80;y<110;y+=40)el(c,0,y,118,25,null,'rgba(100,120,94,.17)',2);c.restore();
|
|
42
|
+
if(py>=0)sphere(c,px,py,43,'#b87959');
|
|
43
|
+
c.beginPath();c.ellipse(0,0,318,111,-.15,0,Math.PI);c.strokeStyle='#d0bd8f';c.lineWidth=10;c.stroke();
|
|
44
|
+
const b=-t*.69+1.4;let qx=Math.cos(b)*173,qy=Math.sin(b)*260;
|
|
45
|
+
c.save();c.rotate(.68);c.beginPath();c.ellipse(0,0,173,260,0,0,TAU);c.strokeStyle='#9da98d';c.lineWidth=5;c.stroke();sphere(c,qx,qy,20,'#9ab6af');c.restore();
|
|
46
|
+
el(c,0,-325,10,10,'#a39d76');el(c,0,325,10,10,'#a39d76');c.restore();
|
|
47
|
+
// Displaced secondary objects form unequal but balanced intervals.
|
|
48
|
+
sphere(c,1606,640,85,'#9aafa3');el(c,1606,727,91,13,'#8d9a88');
|
|
49
|
+
c.save();c.translate(327,625);c.rotate(-.12+Math.sin(t*.45)*.045);poly(c,[[-125,-12],[108,-12],[108,16],[-125,16]],'#83988e','#687d76',2);el(c,111,0,14,35,'#5e7877','#c5c8af',7);for(let i=-105;i<100;i+=22)line(c,[[i,-9],[i,4]],'#d9d9be',2);c.restore();
|
|
50
|
+
for(let i=0;i<24;i++){let y=330+(i*39)%400,x=200+(i*127)%1450;el(c,x+Math.sin(t*.35+i)*6,y-((t*5+i*13)%27),1.2,1.2,'rgba(255,255,230,.32)');}
|
|
51
|
+
finish(c);dst.drawImage(raw,0,0);dst.save();dst.globalAlpha=0.18;PAINT.strokes(dst,raw,{cell:7,len:9,width:4,jitterCol:5,angle:(x,y)=>-.45,seed:39,boil:0,outline:0});dst.restore();
|
|
52
|
+
}};
|
|
53
|
+
})();
|