@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,522 @@
|
|
|
1
|
+
// 1290 哥特泥金手抄本——纯代码。
|
|
2
|
+
// 管线:①静态层(羊皮纸+逐像素金箔+菱格压花+哥特尖拱/小尖塔/彩窗/桌/宝座/拉丁文栏)缓存
|
|
3
|
+
// → ②金箔掩膜(从静态层按「金色度」逐像素分类得到)→ ③每帧:彩窗闪烁、藤蔓花饰摇摆、斜向高光扫过(只落在金上)
|
|
4
|
+
// → ④角色:平涂+粗墨线(光环、金发、红袍金细条、蓝斗篷、金杯),稚拙人脸猫拎着老鼠 → ⑤蜗牛爬、老鼠跑、金杯闪光
|
|
5
|
+
SCENES['05_gothic'] = (() => {
|
|
6
|
+
const W = 1920, H = 1080, { clamp, lerp } = U, P = PAINT;
|
|
7
|
+
const INK = '#2b1a12';
|
|
8
|
+
const C = {
|
|
9
|
+
parch: '#ecdfc0', parchDk: '#c9ae80', gold: '#d9a63a', goldHi: '#f8de86', goldLo: '#9c6a1a',
|
|
10
|
+
red: '#c3262e', redDk: '#7e1318', blue: '#24449e', blueDk: '#142a6a', pink: '#e7a3aa', green: '#55a03c', greenDk: '#2f6e26',
|
|
11
|
+
white: '#f8f2e2', wood: '#8a5a2c', woodDk: '#5a3818', skin: '#f5dcc2', hair: '#e9b746', hairDk: '#9a6618',
|
|
12
|
+
};
|
|
13
|
+
const ease = U.ease.inOut;
|
|
14
|
+
const R_ = (seed) => U.rng(seed);
|
|
15
|
+
|
|
16
|
+
// ---------- 小工具 ----------
|
|
17
|
+
const F = (c, p, fill, line = INK, lw = 3) => { if (!p) return; if (fill) { c.fillStyle = fill; c.fill(p); } if (line && lw) { c.strokeStyle = line; c.lineWidth = lw; c.stroke(p); } };
|
|
18
|
+
const poly = (pts, closed = true) => { const p = new Path2D(); pts.forEach((q, i) => i ? p.lineTo(q[0], q[1]) : p.moveTo(q[0], q[1])); if (closed) p.closePath(); return p; };
|
|
19
|
+
// 尖拱:xl..xr,起拱线 ys,底 yb,半径 r(>宽/2 才是尖的)
|
|
20
|
+
const arch = (xl, xr, ys, yb, r) => {
|
|
21
|
+
const p = new Path2D(), w = xr - xl, mid = (xl + xr) / 2, h = Math.sqrt(r * r - (r - w / 2) ** 2);
|
|
22
|
+
const a1 = Math.atan2(-h, mid - (xl + r)), a2 = Math.atan2(-h, mid - (xr - r));
|
|
23
|
+
p.moveTo(xl, yb); p.lineTo(xl, ys); p.arc(xl + r, ys, r, Math.PI, a1 + Math.PI * 2); p.arc(xr - r, ys, r, a2, 0); p.lineTo(xr, yb); p.closePath(); return p;
|
|
24
|
+
};
|
|
25
|
+
const dot = (c, x, y, r, fill, line = INK, lw = 1.5) => { c.beginPath(); c.arc(x, y, r, 0, Math.PI * 2); if (fill) { c.fillStyle = fill; c.fill(); } if (line) { c.strokeStyle = line; c.lineWidth = lw; c.stroke(); } };
|
|
26
|
+
|
|
27
|
+
// ---------- 金箔:逐像素(大尺度斑驳+横向打磨细纹+颗粒+左上受光) ----------
|
|
28
|
+
const goldTex = () => P.cached('goth_goldTex', W, H, (g) => {
|
|
29
|
+
const x0 = 290, x1 = 1480, y0 = 20, y1 = 960, img = g.createImageData(W, H), d = img.data, r = R_(5);
|
|
30
|
+
const lo = P.hex(C.goldLo), mid = P.hex(C.gold), hi = P.hex(C.goldHi);
|
|
31
|
+
for (let y = y0; y < y1; y++) for (let x = x0; x < x1; x++) {
|
|
32
|
+
const big = P.fbm(x * 0.0035, y * 0.0035 + 7, 3);
|
|
33
|
+
const brush = P.noise(x * 0.004, y * 0.09) * 0.5 + P.noise(x * 0.012, y * 0.25) * 0.3; // 横向打磨纹
|
|
34
|
+
const light = 0.18 - (x - x0) / (x1 - x0) * 0.12 - (y - y0) / (y1 - y0) * 0.16;
|
|
35
|
+
let f = 0.52 + big * 0.42 + brush * 0.22 + light + (r() - .5) * 0.10;
|
|
36
|
+
f = clamp(f, 0, 1);
|
|
37
|
+
const c0 = f < 0.5 ? P.mix(lo, mid, f * 2) : P.mix(mid, hi, (f - 0.5) * 2);
|
|
38
|
+
const i = (y * W + x) * 4; d[i] = c0[0]; d[i + 1] = c0[1]; d[i + 2] = c0[2]; d[i + 3] = 255;
|
|
39
|
+
}
|
|
40
|
+
g.putImageData(img, 0, 0);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
// ---------- 几何 ----------
|
|
44
|
+
const PANEL = poly([[328, 255], [328, 205], [580, 66], [830, 205], [985, 96], [1135, 205], [1285, 96], [1440, 205], [1440, 255], [1440, 895], [328, 895]]);
|
|
45
|
+
const WIN = arch(362, 798, 360, 540, 240);
|
|
46
|
+
const LANCETS = [arch(392, 565, 414, 532, 131), arch(595, 768, 414, 532, 131)];
|
|
47
|
+
|
|
48
|
+
// 羊皮纸+边缘做旧
|
|
49
|
+
function parchment(g) {
|
|
50
|
+
g.drawImage(P.texture('goth_parch', C.parch, { scale: 0.0028, amt: 20, grain: 9, dark: C.parchDk, seed: 3 }), 0, 0);
|
|
51
|
+
const v = g.createRadialGradient(W / 2, H / 2, 380, W / 2, H / 2, 1150);
|
|
52
|
+
v.addColorStop(0, 'rgba(120,80,30,0)'); v.addColorStop(1, 'rgba(110,70,25,.5)');
|
|
53
|
+
g.fillStyle = v; g.fillRect(0, 0, W, H);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// 菱格压花:深线+错 1px 亮线 = 刻进金箔的感觉;菱心四点压印(上亮下暗)
|
|
57
|
+
function lattice(g) {
|
|
58
|
+
const s = 46;
|
|
59
|
+
g.save(); g.clip(PANEL);
|
|
60
|
+
g.drawImage(goldTex(), 0, 0);
|
|
61
|
+
g.lineWidth = 1.6;
|
|
62
|
+
for (const [col, off] of [['rgba(255,240,180,.55)', 1.2], ['rgba(110,66,10,.55)', 0]]) {
|
|
63
|
+
g.strokeStyle = col; g.beginPath();
|
|
64
|
+
for (let k = -40; k < 80; k++) { const u = k * s; g.moveTo(u - 1200 + off, 1200 + off); g.lineTo(u + 1200 + off, -1200 + off); g.moveTo(u - 1200 + off, -1200 + off); g.lineTo(u + 1200 + off, 1200 + off); }
|
|
65
|
+
g.stroke();
|
|
66
|
+
}
|
|
67
|
+
for (let a = -10; a < 70; a++) for (let b = -40; b < 40; b++) {
|
|
68
|
+
const u = (a + 0.5) * s, v = (b + 0.5) * s, x = (u + v) / 2, y = (u - v) / 2;
|
|
69
|
+
if (x < 320 || x > 1450 || y < 60 || y > 900) continue;
|
|
70
|
+
for (const [dx, dy] of [[-5, 0], [5, 0], [0, -5], [0, 5]]) {
|
|
71
|
+
g.fillStyle = 'rgba(255,245,200,.7)'; g.beginPath(); g.arc(x + dx - .6, y + dy - .6, 1.9, 0, 7); g.fill();
|
|
72
|
+
g.fillStyle = 'rgba(120,70,10,.55)'; g.beginPath(); g.arc(x + dx + .7, y + dy + .7, 1.5, 0, 7); g.fill();
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
// 金箔接缝:几条极淡的方块拼接线(金箔是一片片贴上去的)
|
|
76
|
+
g.strokeStyle = 'rgba(120,75,15,.18)'; g.lineWidth = 1;
|
|
77
|
+
for (let x = 328 + 118; x < 1440; x += 118) { g.beginPath(); g.moveTo(x, 60); g.lineTo(x + 3, 895); g.stroke(); }
|
|
78
|
+
for (let y = 140; y < 895; y += 125) { g.beginPath(); g.moveTo(328, y); g.lineTo(1440, y + 2); g.stroke(); }
|
|
79
|
+
g.restore();
|
|
80
|
+
g.strokeStyle = INK; g.lineWidth = 3; g.stroke(PANEL);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// 山墙、小尖塔、侧柱、下边框、草地
|
|
84
|
+
function architecture(g) {
|
|
85
|
+
const band = (pts, col, w) => {
|
|
86
|
+
g.lineJoin = 'miter'; g.lineCap = 'butt';
|
|
87
|
+
g.strokeStyle = INK; g.lineWidth = w + 6; g.beginPath(); pts.forEach((p, i) => i ? g.lineTo(...p) : g.moveTo(...p)); g.stroke();
|
|
88
|
+
g.strokeStyle = col; g.lineWidth = w; g.stroke();
|
|
89
|
+
// 白点
|
|
90
|
+
for (let i = 0; i < pts.length - 1; i++) { const [a, b] = [pts[i], pts[i + 1]], L = Math.hypot(b[0] - a[0], b[1] - a[1]), n = Math.floor(L / 22);
|
|
91
|
+
for (let k = 1; k < n; k++) { const q = k / n; dot(g, lerp(a[0], b[0], q), lerp(a[1], b[1], q), 2.6, '#fff', null); } }
|
|
92
|
+
// 卷叶饰金球(沿外沿)
|
|
93
|
+
for (let i = 0; i < pts.length - 1; i++) { const [a, b] = [pts[i], pts[i + 1]], L = Math.hypot(b[0] - a[0], b[1] - a[1]), n = Math.floor(L / 34);
|
|
94
|
+
const nx = (b[1] - a[1]) / L, ny = -(b[0] - a[0]) / L, sg = ny < 0 ? 1 : -1;
|
|
95
|
+
for (let k = 1; k < n; k++) { const q = k / n; dot(g, lerp(a[0], b[0], q) + nx * sg * (w / 2 + 9), lerp(a[1], b[1], q) + ny * sg * (w / 2 + 9), 6, C.gold, INK, 2); } }
|
|
96
|
+
};
|
|
97
|
+
band([[322, 196], [580, 52], [838, 196]], C.pink, 30);
|
|
98
|
+
band([[836, 196], [985, 82], [1135, 196]], C.blue, 26);
|
|
99
|
+
band([[1135, 196], [1285, 82], [1446, 196]], C.blue, 26);
|
|
100
|
+
// 三叶拱(中、右山墙之下):深金描线
|
|
101
|
+
g.strokeStyle = 'rgba(110,66,10,.8)'; g.lineWidth = 3;
|
|
102
|
+
for (const cx of [985, 1285]) { g.beginPath(); g.arc(cx - 88, 262, 62, Math.PI * 1.05, Math.PI * 1.85); g.arc(cx, 205, 70, Math.PI * 1.12, Math.PI * 1.88); g.arc(cx + 88, 262, 62, Math.PI * 1.15, Math.PI * 1.95); g.stroke(); }
|
|
103
|
+
// 吊坠尖
|
|
104
|
+
for (const x of [835, 1135]) { const p = poly([[x - 16, 238], [x + 16, 238], [x, 282]]); F(g, p, C.white, INK, 2.5); dot(g, x, 252, 4.5, C.red, null); }
|
|
105
|
+
// 十字顶饰
|
|
106
|
+
for (const [x, y] of [[580, 30], [985, 60], [1285, 60]]) { g.fillStyle = C.gold; g.strokeStyle = INK; g.lineWidth = 2; g.fillRect(x - 4, y - 22, 8, 30); g.strokeRect(x - 4, y - 22, 8, 30); g.fillRect(x - 12, y - 14, 24, 7); g.strokeRect(x - 12, y - 14, 24, 7); }
|
|
107
|
+
// 小尖塔
|
|
108
|
+
for (const [x, top, bot] of [[312, 68, 248], [835, 92, 236], [1135, 92, 236], [1455, 68, 248]]) {
|
|
109
|
+
const sw = 22, shaftTop = top + 62;
|
|
110
|
+
g.fillStyle = C.white; g.fillRect(x - sw / 2, shaftTop, sw, bot - shaftTop);
|
|
111
|
+
g.fillStyle = C.blue; for (const dx of [-5, 3]) g.fillRect(x + dx, shaftTop + 8, 3, bot - shaftTop - 16);
|
|
112
|
+
g.strokeStyle = INK; g.lineWidth = 2.5; g.strokeRect(x - sw / 2, shaftTop, sw, bot - shaftTop);
|
|
113
|
+
F(g, poly([[x - 15, shaftTop], [x, top], [x + 15, shaftTop]]), C.red, INK, 2.5);
|
|
114
|
+
g.fillStyle = C.gold; g.fillRect(x - 15, shaftTop - 2, 30, 7); g.strokeRect(x - 15, shaftTop - 2, 30, 7);
|
|
115
|
+
dot(g, x, top - 4, 5, C.gold, INK, 2);
|
|
116
|
+
}
|
|
117
|
+
// 侧柱:红/蓝/粉方块+白点
|
|
118
|
+
const cols = [C.red, C.blue, C.pink, C.blue];
|
|
119
|
+
for (const x0 of [298, 1440]) for (let y = 250, k = 0; y < 945; y += 31, k++) {
|
|
120
|
+
g.fillStyle = cols[k % 4]; g.fillRect(x0, y, 30, 31); g.strokeStyle = INK; g.lineWidth = 2; g.strokeRect(x0, y, 30, 31);
|
|
121
|
+
dot(g, x0 + 15, y + 15.5, 4, '#fff', null);
|
|
122
|
+
}
|
|
123
|
+
g.fillStyle = C.gold; g.fillRect(296, 240, 34, 12); g.fillRect(1438, 240, 34, 12); g.strokeStyle = INK; g.strokeRect(296, 240, 34, 12); g.strokeRect(1438, 240, 34, 12);
|
|
124
|
+
// 草地
|
|
125
|
+
g.fillStyle = C.green; g.fillRect(328, 892, 1112, 53);
|
|
126
|
+
g.fillStyle = C.greenDk; g.fillRect(328, 892, 1112, 5);
|
|
127
|
+
const r = R_(11); g.strokeStyle = C.greenDk; g.lineWidth = 2;
|
|
128
|
+
for (let i = 0; i < 90; i++) { const x = 340 + r() * 1090, y = 905 + r() * 34; g.beginPath(); g.moveTo(x - 4, y - 6); g.lineTo(x, y + 2); g.lineTo(x + 5, y - 7); g.stroke(); }
|
|
129
|
+
for (const x of [1000, 1040, 1052, 1085, 1118, 1180, 760, 690]) { const y = 900 + (x % 7); for (let k = 0; k < 5; k++) dot(g, x + Math.cos(k * 1.26) * 4, y + Math.sin(k * 1.26) * 4, 2.4, '#fff', null); dot(g, x, y, 2, '#f2c230', null); }
|
|
130
|
+
// 下边框:红蓝相间+白波浪
|
|
131
|
+
for (let x = 322, k = 0; x < 1440; x += 52, k++) {
|
|
132
|
+
const w = Math.min(52, 1440 - x); g.fillStyle = k % 2 ? C.blue : C.red; g.fillRect(x, 945, w, 26);
|
|
133
|
+
g.strokeStyle = '#fff'; g.lineWidth = 2; g.beginPath(); for (let s = 0; s <= w - 10; s += 2) { const yy = 958 + Math.sin(s / (w - 10) * Math.PI * 2) * 4; s ? g.lineTo(x + 5 + s, yy) : g.moveTo(x + 5, yy); } g.stroke();
|
|
134
|
+
g.strokeStyle = INK; g.lineWidth = 2; g.strokeRect(x, 945, w, 26);
|
|
135
|
+
}
|
|
136
|
+
g.lineWidth = 3; g.strokeRect(298, 943, 1172, 30);
|
|
137
|
+
for (const [x, y] of [[310, 958], [1458, 958]]) { g.fillStyle = C.gold; g.fillRect(x - 13, y - 13, 26, 26); g.strokeStyle = INK; g.strokeRect(x - 13, y - 13, 26, 26); }
|
|
138
|
+
dot(g, 1468, 968, 8, C.gold, INK, 2);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// 尖拱窗:四叶玫瑰窗+两扇柳叶窗的红蓝菱格彩玻璃
|
|
142
|
+
function windowStatic(g) {
|
|
143
|
+
g.save(); g.shadowColor = 'rgba(80,40,0,.35)'; g.shadowOffsetX = 5; g.shadowOffsetY = 5; F(g, WIN, '#f6eedb', INK, 4); g.restore();
|
|
144
|
+
g.strokeStyle = INK; g.lineWidth = 3; g.stroke(WIN);
|
|
145
|
+
// 内圈细线
|
|
146
|
+
const inner = arch(374, 786, 362, 540, 228); g.strokeStyle = 'rgba(140,110,70,.5)'; g.lineWidth = 2; g.stroke(inner);
|
|
147
|
+
// 四叶玫瑰窗
|
|
148
|
+
const rc = [580, 222];
|
|
149
|
+
const q = new Path2D(); for (let k = 0; k < 4; k++) { const a = k * Math.PI / 2 - Math.PI / 2; q.moveTo(rc[0] + Math.cos(a) * 33 + 30, rc[1] + Math.sin(a) * 33); q.arc(rc[0] + Math.cos(a) * 33, rc[1] + Math.sin(a) * 33, 30, 0, Math.PI * 2); }
|
|
150
|
+
F(g, q, C.red, INK, 3);
|
|
151
|
+
for (let k = 0; k < 4; k++) { const a = k * Math.PI / 2 - Math.PI / 2; dot(g, rc[0] + Math.cos(a) * 33, rc[1] + Math.sin(a) * 33, 20, C.blue, INK, 2.5); dot(g, rc[0] + Math.cos(a) * 33, rc[1] + Math.sin(a) * 33, 6, C.gold, INK, 1.5); }
|
|
152
|
+
dot(g, rc[0], rc[1], 13, C.gold, INK, 2.5);
|
|
153
|
+
for (const [dx, dy] of [[0, -9], [-9, 6], [9, 6]]) dot(g, 578 + dx, 316 + dy, 8, C.blue, INK, 2);
|
|
154
|
+
// 柳叶窗:红蓝菱格+金铅条+白点
|
|
155
|
+
LANCETS.forEach((L, li) => {
|
|
156
|
+
g.save(); g.clip(L);
|
|
157
|
+
const s = 38;
|
|
158
|
+
for (let a = -30; a < 60; a++) for (let b = -30; b < 30; b++) {
|
|
159
|
+
const u = a * s, v = b * s, x = (u + v) / 2, y = (u - v) / 2;
|
|
160
|
+
if (x < 370 || x > 790 || y < 260 || y > 560) continue;
|
|
161
|
+
const dm = poly([[x, y - s / 2], [x + s / 2, y], [x, y + s / 2], [x - s / 2, y]]);
|
|
162
|
+
g.fillStyle = (a + b) % 2 ? C.red : C.blue; g.fill(dm);
|
|
163
|
+
if ((a + b) % 2 === 0) for (const [dx, dy] of [[-4, 0], [4, 0], [0, -4], [0, 4], [0, 0]]) dot(g, x + dx, y + dy, 1.8, '#fff', null);
|
|
164
|
+
else dot(g, x, y, 4, C.gold, null);
|
|
165
|
+
}
|
|
166
|
+
// 铅条:沿菱形边(x+y、x−y 为常数的两族斜线)
|
|
167
|
+
g.strokeStyle = C.gold; g.lineWidth = 3; g.beginPath();
|
|
168
|
+
for (let k = -60; k < 120; k++) { const c0 = (k + 0.5) * s; g.moveTo(c0 - 1000, 1000); g.lineTo(c0 + 1000, -1000); g.moveTo(c0 - 1000, -1000); g.lineTo(c0 + 1000, 1000); }
|
|
169
|
+
g.stroke(); g.restore();
|
|
170
|
+
F(g, L, null, INK, 4);
|
|
171
|
+
});
|
|
172
|
+
// 窗台
|
|
173
|
+
const sill = new Path2D(); sill.rect(345, 538, 470, 24); F(g, sill, C.pink, INK, 3);
|
|
174
|
+
g.fillStyle = 'rgba(255,255,255,.5)'; g.fillRect(350, 542, 460, 4);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// 桌(白桌布+蓝竖条+扇贝边)、宝座、面包、刀
|
|
178
|
+
function furniture(g) {
|
|
179
|
+
// 支架腿(A 字)
|
|
180
|
+
g.lineCap = 'round';
|
|
181
|
+
for (const x of [872, 1142]) for (const [a, b] of [[-26, 18], [26, -18]]) { g.strokeStyle = INK; g.lineWidth = 15; g.beginPath(); g.moveTo(x + b, 715); g.lineTo(x + a, 898); g.stroke(); g.strokeStyle = C.wood; g.lineWidth = 10; g.stroke(); }
|
|
182
|
+
for (const x of [872, 1142]) { g.fillStyle = C.wood; g.fillRect(x - 22, 830, 44, 8); g.strokeStyle = INK; g.lineWidth = 2; g.strokeRect(x - 22, 830, 44, 8); }
|
|
183
|
+
// 桌面
|
|
184
|
+
const top = poly([[805, 578], [1215, 578], [1210, 645], [810, 645]]); F(g, top, C.white, INK, 3);
|
|
185
|
+
g.fillStyle = 'rgba(150,140,120,.18)'; g.fillRect(810, 630, 400, 14);
|
|
186
|
+
g.strokeStyle = C.blue; g.lineWidth = 2.5; for (const x of [828, 836, 1184, 1192]) { g.beginPath(); g.moveTo(x, 580); g.lineTo(x + (x < 1000 ? 2 : -2), 644); g.stroke(); }
|
|
187
|
+
// 垂布:扇贝下摆
|
|
188
|
+
const cl = new Path2D(); cl.moveTo(812, 645); cl.lineTo(1208, 645); cl.lineTo(1205, 712);
|
|
189
|
+
for (let x = 1205; x > 815; x -= 26) cl.quadraticCurveTo(x - 13, 742, x - 26, 712);
|
|
190
|
+
cl.closePath(); F(g, cl, C.white, INK, 3);
|
|
191
|
+
g.save(); g.clip(cl);
|
|
192
|
+
g.strokeStyle = 'rgba(36,68,158,.8)'; g.lineWidth = 2; for (let x = 822; x < 1205; x += 26) { g.beginPath(); g.moveTo(x, 648); g.quadraticCurveTo(x + 3, 690, x + 1, 735); g.stroke(); }
|
|
193
|
+
g.strokeStyle = 'rgba(150,140,120,.45)'; g.lineWidth = 1.5; for (let x = 834; x < 1205; x += 26) { g.beginPath(); g.moveTo(x, 650); g.lineTo(x + 2, 725); g.stroke(); }
|
|
194
|
+
g.restore();
|
|
195
|
+
for (let x = 826; x < 1200; x += 13) dot(g, x, 700, 2.3, C.red, null);
|
|
196
|
+
// 面包+刀
|
|
197
|
+
const br = new Path2D(); br.ellipse(880, 616, 34, 19, 0, 0, Math.PI * 2); F(g, br, '#d9a058', INK, 2.5);
|
|
198
|
+
g.strokeStyle = '#8a5524'; g.lineWidth = 2.5; g.beginPath(); g.moveTo(880, 600); g.lineTo(880, 632); g.moveTo(862, 616); g.quadraticCurveTo(880, 606, 898, 616); g.stroke();
|
|
199
|
+
g.strokeStyle = INK; g.lineWidth = 6; g.beginPath(); g.moveTo(1106, 636); g.lineTo(1140, 632); g.stroke(); g.strokeStyle = '#7a4a20'; g.lineWidth = 4; g.stroke();
|
|
200
|
+
g.strokeStyle = INK; g.lineWidth = 4; g.beginPath(); g.moveTo(1140, 632); g.lineTo(1186, 627); g.stroke(); g.strokeStyle = '#d8d8d8'; g.lineWidth = 2.5; g.stroke();
|
|
201
|
+
// 宝座:绿靠背+金顶球、红坐垫、粉色基座+蓝尖拱
|
|
202
|
+
const back = poly([[1438, 430], [1478, 430], [1480, 748], [1438, 748]]); F(g, back, '#3c8a3a', INK, 3);
|
|
203
|
+
g.strokeStyle = 'rgba(255,255,255,.3)'; g.lineWidth = 3; g.beginPath(); g.moveTo(1446, 440); g.lineTo(1446, 740); g.stroke();
|
|
204
|
+
dot(g, 1458, 422, 9, C.gold, INK, 2); dot(g, 1478, 460, 7, C.gold, INK, 2);
|
|
205
|
+
const base = poly([[1302, 748], [1482, 748], [1482, 882], [1302, 882]]); F(g, base, C.pink, INK, 3);
|
|
206
|
+
for (let k = 0; k < 4; k++) { const x = 1318 + k * 40; F(g, arch(x, x + 26, 790, 872, 17), C.blue, INK, 2.5); }
|
|
207
|
+
F(g, poly([[1296, 880], [1488, 880], [1488, 898], [1296, 898]]), C.gold, INK, 2.5);
|
|
208
|
+
F(g, poly([[1300, 726], [1484, 726], [1486, 750], [1300, 750]]), C.red, INK, 3);
|
|
209
|
+
dot(g, 1484, 735, 7, C.gold, INK, 2);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// 正文栏:格线、红蓝笔花、蓝底金字首字母 H、哥特体拉丁文(句首红字=朱批)
|
|
213
|
+
const LINES = [['ic sedet homo', 1640], ['cum poculo suo', 1640], ['et bibit. Cattus', 1515], ['eum spectat.', 1515], ['Cattus semper', 1515], ['spectat. Nemo', 1515], ['scit quare. Mus', 1515], ['autem scit et', 1515], ['tacet in eternum.', 1515]];
|
|
214
|
+
function textColumn(g) {
|
|
215
|
+
g.strokeStyle = 'rgba(150,110,70,.28)'; g.lineWidth = 1.2;
|
|
216
|
+
for (let k = 0; k < 10; k++) { const y = 300 + k * 62; g.beginPath(); g.moveTo(1495, y); g.lineTo(1895, y); g.stroke(); }
|
|
217
|
+
g.beginPath(); g.moveTo(1505, 240); g.lineTo(1505, 920); g.stroke(); g.beginPath(); g.moveTo(1888, 240); g.lineTo(1888, 920); g.stroke();
|
|
218
|
+
// 笔花
|
|
219
|
+
g.lineWidth = 2; g.strokeStyle = C.red; g.beginPath(); for (let y = 235; y < 500; y += 2) { const x = 1497 + Math.sin(y * 0.09) * 6; y === 235 ? g.moveTo(x, y) : g.lineTo(x, y); } g.stroke();
|
|
220
|
+
g.strokeStyle = C.blue; g.beginPath(); for (let y = 260; y < 330; y += 2) { const x = 1506 + Math.sin(y * 0.11 + 1) * 5; y === 260 ? g.moveTo(x, y) : g.lineTo(x, y); } g.stroke();
|
|
221
|
+
// 首字母 H
|
|
222
|
+
g.save(); g.shadowColor = 'rgba(60,30,0,.3)'; g.shadowOffsetX = 3; g.shadowOffsetY = 3; g.fillStyle = C.gold; g.fillRect(1508, 304, 120, 118); g.restore();
|
|
223
|
+
g.fillStyle = C.blue; g.fillRect(1517, 313, 102, 100); g.strokeStyle = INK; g.lineWidth = 2.5; g.strokeRect(1508, 304, 120, 118); g.strokeRect(1517, 313, 102, 100);
|
|
224
|
+
g.strokeStyle = 'rgba(255,255,255,.85)'; g.lineWidth = 1.6;
|
|
225
|
+
for (const [x, y, s] of [[1600, 330, 1], [1532, 395, -1], [1600, 396, 1]]) { g.beginPath(); for (let a = 0; a < 9; a += 0.25) { const rr = 1 + a * 1.4; const px = x + Math.cos(a * s) * rr, py = y + Math.sin(a * s) * rr; a ? g.lineTo(px, py) : g.moveTo(px, py); } g.stroke(); }
|
|
226
|
+
for (let k = 0; k < 7; k++) dot(g, 1528 + k * 13, 320, 1.6, '#fff', null);
|
|
227
|
+
g.font = '118px "UnifrakturMaguntia-400"'; g.textAlign = 'center'; g.textBaseline = 'alphabetic';
|
|
228
|
+
g.lineWidth = 6; g.strokeStyle = INK; g.strokeText('H', 1568, 404); g.fillStyle = C.gold; g.fillText('H', 1568, 404);
|
|
229
|
+
g.fillStyle = 'rgba(255,245,200,.6)'; g.font = '118px "UnifrakturMaguntia-400"'; g.save(); g.beginPath(); g.rect(1517, 313, 102, 46); g.clip(); g.fillText('H', 1567, 403); g.restore();
|
|
230
|
+
// 正文
|
|
231
|
+
g.textAlign = 'left'; g.font = '44px "UnifrakturMaguntia-400"';
|
|
232
|
+
LINES.forEach(([s, x], k) => {
|
|
233
|
+
const y = 350 + k * 62; let cx = x;
|
|
234
|
+
for (const word of s.split(' ')) {
|
|
235
|
+
const red = /^(Cattus|Nemo|Mus)/.test(word);
|
|
236
|
+
g.fillStyle = red ? C.red : '#2a1c12';
|
|
237
|
+
g.fillText(word, cx, y); cx += g.measureText(word + ' ').width;
|
|
238
|
+
}
|
|
239
|
+
if (k === 3) { // 行尾填充波折线
|
|
240
|
+
g.lineWidth = 2.4; g.strokeStyle = C.red; g.beginPath(); for (let i = 0; i <= 10; i++) g.lineTo(cx + 6 + i * 11, y - 14 + (i % 2) * 12); g.stroke();
|
|
241
|
+
g.strokeStyle = C.blue; g.beginPath(); for (let i = 0; i <= 10; i++) g.lineTo(cx + 12 + i * 11, y - 14 + (i % 2) * 12); g.stroke();
|
|
242
|
+
}
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// 小骑士(页边滑稽画)
|
|
247
|
+
function knight(g) {
|
|
248
|
+
g.save(); g.translate(760, 1010);
|
|
249
|
+
F(g, poly([[-10, -8], [10, -8], [14, 26], [-14, 26]]), C.red, INK, 2.5);
|
|
250
|
+
g.strokeStyle = INK; g.lineWidth = 6; g.lineCap = 'round'; g.beginPath(); g.moveTo(-6, 24); g.lineTo(-14, 48); g.moveTo(6, 24); g.lineTo(18, 44); g.stroke();
|
|
251
|
+
g.strokeStyle = '#d0d0d8'; g.lineWidth = 3.5; g.stroke();
|
|
252
|
+
const helm = new Path2D(); helm.rect(-12, -34, 24, 26); F(g, helm, '#c8ccd6', INK, 2.5);
|
|
253
|
+
g.fillStyle = INK; g.fillRect(-8, -24, 16, 3);
|
|
254
|
+
F(g, poly([[6, -6], [30, -6], [30, 14], [18, 26], [6, 14]]), C.blue, INK, 2.5);
|
|
255
|
+
g.strokeStyle = '#fff'; g.lineWidth = 3; g.beginPath(); g.moveTo(18, -2); g.lineTo(18, 20); g.moveTo(10, 6); g.lineTo(26, 6); g.stroke();
|
|
256
|
+
g.restore();
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
const STATIC = () => P.cached('goth_static', W, H, (g) => { parchment(g); lattice(g); architecture(g); windowStatic(g); furniture(g); textColumn(g); knight(g); });
|
|
260
|
+
// 金色度掩膜(只让高光落在金上)
|
|
261
|
+
const MASK = () => P.cached('goth_mask', W, H, (g) => {
|
|
262
|
+
const s = STATIC().getContext('2d').getImageData(0, 0, W, H).data, img = g.createImageData(W, H), d = img.data;
|
|
263
|
+
for (let i = 0; i < W * H * 4; i += 4) {
|
|
264
|
+
const r = s[i], gg = s[i + 1], b = s[i + 2];
|
|
265
|
+
const k = clamp((r - b - 70) / 50) * clamp((gg - b - 30) / 40) * clamp((r - 140) / 40);
|
|
266
|
+
d[i] = d[i + 1] = d[i + 2] = 255; d[i + 3] = k * 255;
|
|
267
|
+
}
|
|
268
|
+
g.putImageData(img, 0, 0);
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
// ---------- 藤蔓花饰(每帧画,枝条与叶子各自轻摇) ----------
|
|
272
|
+
const VINES = (() => {
|
|
273
|
+
const L = [], B = [];
|
|
274
|
+
for (let y = 30; y <= 990; y += 8) L.push([172 + 48 * Math.sin(y * 0.0125) + 18 * Math.sin(y * 0.033 + 1), y]);
|
|
275
|
+
for (let x = 230; x <= 1900; x += 8) B.push([x, 1012 + 26 * Math.sin(x * 0.011) + 10 * Math.sin(x * 0.035 + 2) - (x > 1500 ? (x - 1500) * 0.06 : 0)]);
|
|
276
|
+
const joinL = [[L[L.length - 1][0], L[L.length - 1][1]], [200, 1005], [230, B[0][1]]];
|
|
277
|
+
return [L.concat(joinL.slice(1)), B];
|
|
278
|
+
})();
|
|
279
|
+
const LEAFCOL = [C.blue, C.red, C.gold, C.blue, C.red];
|
|
280
|
+
function ivy(c, x, y, a, s, col) { // 三瓣常春藤叶/喇叭花:哥特页边最常见的叶饰
|
|
281
|
+
c.save(); c.translate(x, y); c.rotate(a); c.scale(s, s);
|
|
282
|
+
const p = new Path2D(); p.moveTo(0, 0); p.quadraticCurveTo(-10, -6, -14, -18); p.quadraticCurveTo(-6, -14, -2, -22); p.quadraticCurveTo(0, -30, 2, -22);
|
|
283
|
+
p.quadraticCurveTo(6, -14, 14, -18); p.quadraticCurveTo(10, -6, 0, 0); p.closePath();
|
|
284
|
+
c.fillStyle = col; c.fill(p); c.strokeStyle = INK; c.lineWidth = 1.6 / s; c.stroke(p);
|
|
285
|
+
c.restore();
|
|
286
|
+
}
|
|
287
|
+
function vines(c, t) {
|
|
288
|
+
c.save(); c.lineCap = 'round'; c.lineJoin = 'round';
|
|
289
|
+
VINES.forEach((pts, vi) => {
|
|
290
|
+
const sway = (i) => [Math.sin(t * 2.6 + i * 0.09 + vi) * 5, Math.cos(t * 2.1 + i * 0.07) * 4];
|
|
291
|
+
const pp = pts.map((p, i) => { const s = sway(i); return [p[0] + s[0], p[1] + s[1]]; });
|
|
292
|
+
c.strokeStyle = '#3a2416'; c.lineWidth = 2.6; c.beginPath(); pp.forEach((p, i) => i ? c.lineTo(...p) : c.moveTo(...p)); c.stroke();
|
|
293
|
+
const r = R_(31 + vi * 7);
|
|
294
|
+
for (let i = 3, k = 0; i < pp.length - 3; i += 3 + ((r() * 3) | 0), k++) {
|
|
295
|
+
const p = pp[i], q = pp[i + 1], ta = Math.atan2(q[1] - p[1], q[0] - p[0]), side = k % 2 ? 1 : -1;
|
|
296
|
+
const na = ta + side * (Math.PI / 2 - 0.5);
|
|
297
|
+
const L = 18 + r() * 16, sw = Math.sin(t * 3.6 + k * 1.7 + vi) * 0.42;
|
|
298
|
+
const ex = p[0] + Math.cos(na + sw * 0.5) * L, ey = p[1] + Math.sin(na + sw * 0.5) * L;
|
|
299
|
+
c.strokeStyle = '#3a2416'; c.lineWidth = 1.6; c.beginPath(); c.moveTo(p[0], p[1]); c.quadraticCurveTo(p[0] + Math.cos(na) * L * 0.6 + side * 4, p[1] + Math.sin(na) * L * 0.6, ex, ey); c.stroke();
|
|
300
|
+
if (r() < 0.62) ivy(c, ex, ey, na + Math.PI / 2 + sw, 1.05 + r() * 0.4, LEAFCOL[(k + vi) % 5]);
|
|
301
|
+
else { dot(c, ex, ey, 5.5, C.gold, INK, 1.4); c.strokeStyle = '#3a2416'; c.lineWidth = 1; for (let h = -1; h <= 1; h++) { const a2 = na + h * 0.6 + sw; c.beginPath(); c.moveTo(ex + Math.cos(a2) * 6, ey + Math.sin(a2) * 6); c.lineTo(ex + Math.cos(a2) * 13, ey + Math.sin(a2) * 13); c.stroke(); } }
|
|
302
|
+
}
|
|
303
|
+
});
|
|
304
|
+
c.restore();
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// ---------- 动态金:斜向高光 ----------
|
|
308
|
+
const K_SLANT = 0.45;
|
|
309
|
+
const sweepX = (lt) => lerp(150, 1650, clamp((lt - 0.08) / 1.15)); // 匀速:0.3s 就扫到窗边,0.9s 扫过少女
|
|
310
|
+
function goldSweep(c, lt) {
|
|
311
|
+
const xc = sweepX(lt), bx = Math.round(xc - 460), bw = 920, s = P.scratch('gothSweep'), g = s.getContext('2d');
|
|
312
|
+
g.clearRect(0, 0, W, H); g.globalCompositeOperation = 'source-over';
|
|
313
|
+
const gr = g.createLinearGradient(xc - 170, 540 - 170 * K_SLANT, xc + 170, 540 + 170 * K_SLANT);
|
|
314
|
+
gr.addColorStop(0, 'rgba(255,240,190,0)'); gr.addColorStop(0.25, 'rgba(255,236,170,.32)'); gr.addColorStop(0.47, 'rgba(255,252,230,.85)');
|
|
315
|
+
gr.addColorStop(0.53, 'rgba(255,252,230,.85)'); gr.addColorStop(0.75, 'rgba(255,236,170,.32)'); gr.addColorStop(1, 'rgba(255,240,190,0)');
|
|
316
|
+
g.fillStyle = gr; g.fillRect(bx, 0, bw, H);
|
|
317
|
+
g.globalCompositeOperation = 'destination-in'; g.drawImage(MASK(), bx, 0, bw, H, bx, 0, bw, H); g.globalCompositeOperation = 'source-over';
|
|
318
|
+
c.save(); c.globalCompositeOperation = 'lighter'; c.globalAlpha = 0.85; c.drawImage(s, bx, 0, bw, H, bx, 0, bw, H); c.restore();
|
|
319
|
+
}
|
|
320
|
+
const glint = (c, x, y, s, a = 1) => { // 四角星闪光
|
|
321
|
+
if (s <= 0.02) return; c.save(); c.globalCompositeOperation = 'lighter'; c.globalAlpha = a; c.fillStyle = '#fff6d0';
|
|
322
|
+
c.beginPath(); c.moveTo(x, y - 18 * s); c.quadraticCurveTo(x, y, x + 18 * s, y); c.quadraticCurveTo(x, y, x, y + 18 * s); c.quadraticCurveTo(x, y, x - 18 * s, y); c.quadraticCurveTo(x, y, x, y - 18 * s); c.fill();
|
|
323
|
+
c.globalAlpha = a * 0.5; c.beginPath(); c.arc(x, y, 6 * s, 0, 7); c.fill(); c.restore();
|
|
324
|
+
};
|
|
325
|
+
const SPARKS = [[452, 640], [760, 330], [930, 470], [1090, 300], [1250, 520], [700, 780], [1010, 820], [1380, 330], [560, 115], [1300, 150], [1568, 360]];
|
|
326
|
+
const nearSweep = (x, y, lt) => { const u = x + K_SLANT * (y - 540); return clamp(1 - Math.abs(u - sweepX(lt)) / 70); };
|
|
327
|
+
|
|
328
|
+
// 彩窗闪烁:几块菱格轮流亮起
|
|
329
|
+
function glassTwinkle(c, t) {
|
|
330
|
+
c.save(); c.globalCompositeOperation = 'lighter';
|
|
331
|
+
LANCETS.forEach((L, li) => { c.save(); c.clip(L);
|
|
332
|
+
for (let k = 0; k < 40; k++) { const h = U.hash(k, li + 3), x = (li ? 600 : 396) + U.hash(k, 9 + li) * 170, y = 300 + h * 230;
|
|
333
|
+
const a = Math.max(0, Math.sin(t * 5 + h * 40)); if (a < 0.6) continue;
|
|
334
|
+
const gr = c.createRadialGradient(x, y, 0, x, y, 22); gr.addColorStop(0, `rgba(255,255,255,${(a - 0.6) * 1.1})`); gr.addColorStop(1, 'rgba(255,255,255,0)'); c.fillStyle = gr; c.fillRect(x - 22, y - 22, 44, 44); }
|
|
335
|
+
c.restore(); });
|
|
336
|
+
c.restore();
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
// ---------- 少女:哥特圣像画法 ----------
|
|
340
|
+
function girl(c, G, lt, t, ch) {
|
|
341
|
+
const A = G.A;
|
|
342
|
+
c.save(); c.lineJoin = 'round'; c.lineCap = 'round';
|
|
343
|
+
// 光环(头后)
|
|
344
|
+
const hc = [A.headC[0] + 16, A.headC[1] - 22], hr = 114;
|
|
345
|
+
const hg = c.createRadialGradient(hc[0] - 30, hc[1] - 30, 10, hc[0], hc[1], hr);
|
|
346
|
+
hg.addColorStop(0, '#fbe597'); hg.addColorStop(0.6, '#e2b445'); hg.addColorStop(1, '#b98222');
|
|
347
|
+
c.fillStyle = hg; c.beginPath(); c.arc(hc[0], hc[1], hr, 0, 7); c.fill(); c.strokeStyle = INK; c.lineWidth = 3; c.stroke();
|
|
348
|
+
c.strokeStyle = C.red; c.lineWidth = 3; c.beginPath(); c.arc(hc[0], hc[1], hr - 9, 0, 7); c.stroke();
|
|
349
|
+
for (let k = 0; k < 36; k++) { const a = k / 36 * Math.PI * 2; dot(c, hc[0] + Math.cos(a) * (hr - 18), hc[1] + Math.sin(a) * (hr - 18), 2.3, '#fff3c0', 'rgba(120,70,10,.6)', 1); }
|
|
350
|
+
const hs = nearSweep(hc[0], hc[1], lt); if (hs > 0) { c.save(); c.globalCompositeOperation = 'lighter'; c.globalAlpha = hs * 0.5; c.fillStyle = '#fff4c8'; c.beginPath(); c.arc(hc[0], hc[1], hr, 0, 7); c.fill(); c.restore(); }
|
|
351
|
+
// 长金发(背后,波浪)
|
|
352
|
+
const nape = A.nape, sw = Math.sin(t * 2.4) * 3;
|
|
353
|
+
const hair = RIG.smooth([[nape[0] + 30, nape[1] - 100], [nape[0] + 58, nape[1] - 40], [nape[0] + 72, nape[1] + 30], [nape[0] + 84 + sw, nape[1] + 110], [nape[0] + 78 + sw, nape[1] + 190], [nape[0] + 92 + sw, nape[1] + 250],
|
|
354
|
+
[nape[0] + 62 + sw, nape[1] + 262], [nape[0] + 50, nape[1] + 200], [nape[0] + 34, nape[1] + 120], [nape[0] + 10, nape[1] + 50], [nape[0] - 20, nape[1] + 10]]);
|
|
355
|
+
F(c, hair, C.hair, INK, 3);
|
|
356
|
+
c.strokeStyle = C.hairDk; c.lineWidth = 2;
|
|
357
|
+
for (let k = 0; k < 4; k++) { c.beginPath(); for (let s = 0; s <= 20; s++) { const q = s / 20, x = nape[0] + 30 + k * 12 + Math.sin(q * 9 + k) * 6 + q * 30, y = nape[1] - 60 + q * 300; s ? c.lineTo(x, y) : c.moveTo(x, y); } c.stroke(); }
|
|
358
|
+
// 远侧袖、手
|
|
359
|
+
F(c, G.farSleeve, C.red); F(c, G.farCuff, C.gold); F(c, G.farHand, C.skin);
|
|
360
|
+
// 裙:红+金细竖条+金下摆
|
|
361
|
+
F(c, G.skirt, C.red, INK, 3.5);
|
|
362
|
+
c.save(); c.clip(G.skirt); c.strokeStyle = 'rgba(240,190,80,.75)'; c.lineWidth = 1.6;
|
|
363
|
+
for (let x = 1080; x < 1470; x += 20) { c.beginPath(); c.moveTo(x, 600); c.quadraticCurveTo(x - 14, 780, x - 22, 940); c.stroke(); }
|
|
364
|
+
c.strokeStyle = C.redDk; c.lineWidth = 3; G.folds.forEach(f => c.stroke(f));
|
|
365
|
+
c.strokeStyle = C.gold; c.lineWidth = 12; c.beginPath(); c.moveTo(1090, 924); c.quadraticCurveTo(1230, 940, 1360, 924); c.stroke();
|
|
366
|
+
c.restore();
|
|
367
|
+
F(c, G.shoe, '#3a2418', INK, 2.5);
|
|
368
|
+
// 躯干
|
|
369
|
+
F(c, G.torso, C.red, INK, 3.5);
|
|
370
|
+
c.save(); c.clip(G.torso); c.strokeStyle = 'rgba(240,190,80,.75)'; c.lineWidth = 1.6; for (let x = 1280; x < 1440; x += 20) { c.beginPath(); c.moveTo(x, 420); c.lineTo(x + 6, 630); c.stroke(); } c.restore();
|
|
371
|
+
// 蓝斗篷:从后肩垂到座位,金边
|
|
372
|
+
const b = A.back, cloak = RIG.smooth([[A.nape[0] - 6, A.nape[1] + 12], [A.nape[0] + 40, A.nape[1] + 22], [b[0] + 30, b[1] + 10], [b[0] + 44, b[1] + 140], [b[0] + 46, b[1] + 230], [b[0] + 10, b[1] + 236], [b[0] + 4, b[1] + 120], [b[0] - 18, b[1] + 10], [A.nape[0] - 10, A.nape[1] + 40]]);
|
|
373
|
+
F(c, cloak, C.blue, INK, 3.5);
|
|
374
|
+
c.save(); c.clip(cloak); c.strokeStyle = C.blueDk; c.lineWidth = 3; for (let k = 0; k < 3; k++) { c.beginPath(); c.moveTo(b[0] + 6 + k * 12, b[1] - 20); c.quadraticCurveTo(b[0] + 18 + k * 12, b[1] + 100, b[0] + 14 + k * 12, b[1] + 230); c.stroke(); } c.restore();
|
|
375
|
+
c.strokeStyle = C.gold; c.lineWidth = 4; c.beginPath(); c.moveTo(A.nape[0] - 8, A.nape[1] + 30); c.quadraticCurveTo(b[0] - 14, b[1] + 20, b[0] + 6, b[1] + 232); c.stroke();
|
|
376
|
+
// 领口金边
|
|
377
|
+
F(c, G.neck, C.skin, INK, 2.5);
|
|
378
|
+
c.strokeStyle = C.gold; c.lineWidth = 5; c.beginPath(); c.moveTo(A.neck[0] - 18, A.neck[1] + 2); c.quadraticCurveTo(A.neck[0] + 6, A.neck[1] + 18, A.neck[0] + 30, A.neck[1] - 2); c.stroke();
|
|
379
|
+
// 头
|
|
380
|
+
F(c, G.hairBack, C.hair, INK, 3);
|
|
381
|
+
F(c, G.face, C.skin, INK, 3);
|
|
382
|
+
c.save(); c.clip(G.face); c.fillStyle = 'rgba(232,110,110,.55)'; c.beginPath(); c.arc(G.cheek[0] - 4, G.cheek[1], 12, 0, 7); c.fill(); c.restore();
|
|
383
|
+
c.fillStyle = C.skin; c.beginPath(); c.ellipse(G.ear[0], G.ear[1], 8, 12, 0.2, 0, 7); c.fill(); c.strokeStyle = INK; c.lineWidth = 2; c.stroke();
|
|
384
|
+
F(c, G.bangs, C.hair, INK, 3);
|
|
385
|
+
c.strokeStyle = C.hairDk; c.lineWidth = 2; G.hairLines.forEach(h => c.stroke(h));
|
|
386
|
+
G.locks.forEach(h => { c.strokeStyle = INK; c.lineWidth = 9; c.stroke(h); c.strokeStyle = C.hair; c.lineWidth = 6; c.stroke(h); });
|
|
387
|
+
// 五官:哥特圣像的杏眼、细眉、小红唇
|
|
388
|
+
const closed = ch.blink || ch.cup > 0.86;
|
|
389
|
+
if (closed) { c.strokeStyle = INK; c.lineWidth = 2.6; c.beginPath(); c.arc(G.eye.x, G.eye.y - 2, 7, 0.3, Math.PI - 0.3); c.stroke(); }
|
|
390
|
+
else {
|
|
391
|
+
c.fillStyle = '#fff'; c.beginPath(); c.ellipse(G.eye.x, G.eye.y, 9, 5, -0.1, 0, 7); c.fill(); c.strokeStyle = INK; c.lineWidth = 2.2; c.stroke();
|
|
392
|
+
c.fillStyle = '#3a2a1c'; c.beginPath(); c.arc(G.eye.x - 3, G.eye.y, 3.6, 0, 7); c.fill();
|
|
393
|
+
c.strokeStyle = INK; c.lineWidth = 2.6; c.stroke(G.lid);
|
|
394
|
+
}
|
|
395
|
+
c.strokeStyle = '#8a5a20'; c.lineWidth = 2.2; c.stroke(G.brow);
|
|
396
|
+
c.fillStyle = '#c0303a'; c.beginPath(); c.moveTo(...G.lips[0]); c.lineTo(...G.lips[1]); c.lineTo(...G.lips[2]); c.closePath(); c.fill();
|
|
397
|
+
// 近侧手臂:红袖+金袖口
|
|
398
|
+
F(c, G.upperArm, C.red, INK, 3.5); F(c, G.foreArm, C.red, INK, 3.5); F(c, G.cuff, C.gold, INK, 2.5);
|
|
399
|
+
F(c, G.hand, C.skin, INK, 2.5);
|
|
400
|
+
chalice(c, G.cup, lt, t);
|
|
401
|
+
c.fillStyle = C.skin; c.beginPath(); c.arc(G.thumb[0], G.thumb[1], 7, 0, 7); c.fill(); c.strokeStyle = INK; c.lineWidth = 2; c.stroke();
|
|
402
|
+
c.restore();
|
|
403
|
+
}
|
|
404
|
+
// 金圣杯:杯口在 cup.x,cup.y;杯身半椭圆+节+杯脚;红酒
|
|
405
|
+
function chalice(c, cup, lt, t) {
|
|
406
|
+
c.save(); c.translate(cup.x, cup.y); c.rotate(cup.tilt || 0);
|
|
407
|
+
const w = 52, gg = c.createLinearGradient(-w / 2, 0, w / 2, 0); gg.addColorStop(0, '#a87020'); gg.addColorStop(0.35, '#fbe08a'); gg.addColorStop(0.6, '#e0ad40'); gg.addColorStop(1, '#8a5a14');
|
|
408
|
+
const bowl = new Path2D(); bowl.moveTo(-w / 2, 0); bowl.bezierCurveTo(-w / 2, 26, -10, 36, 0, 36); bowl.bezierCurveTo(10, 36, w / 2, 26, w / 2, 0); bowl.closePath();
|
|
409
|
+
F(c, bowl, gg, INK, 2.5);
|
|
410
|
+
const stem = poly([[-5, 34], [5, 34], [4, 58], [-4, 58]]); F(c, stem, gg, INK, 2);
|
|
411
|
+
const knot = new Path2D(); knot.ellipse(0, 46, 9, 5, 0, 0, 7); F(c, knot, '#f0c860', INK, 2);
|
|
412
|
+
const foot = new Path2D(); foot.moveTo(-20, 66); foot.quadraticCurveTo(0, 50, 20, 66); foot.closePath(); F(c, foot, gg, INK, 2);
|
|
413
|
+
const rim = new Path2D(); rim.ellipse(0, 0, w / 2, 7, 0, 0, 7); F(c, rim, '#7a1018', INK, 2.2);
|
|
414
|
+
c.fillStyle = 'rgba(255,255,255,.45)'; c.beginPath(); c.ellipse(-8, -1.5, 9, 2, 0, 0, 7); c.fill();
|
|
415
|
+
c.restore();
|
|
416
|
+
// 闪光:杯沿一颗四角星
|
|
417
|
+
const tw = Math.max(0, Math.sin(t * 7 + 1)); glint(c, cup.x + 18, cup.y - 4, 0.5 + tw * 0.5, 0.5 + tw * 0.5);
|
|
418
|
+
// 热气(细墨线弯曲上升)
|
|
419
|
+
c.save(); c.globalAlpha = 0.7; P.steam(c, t, cup.x, cup.y - 12, { h: 64, n: 3, color: 'rgba(120,110,100,.9)', width: 2.2, spread: 10, wobble: 7 }); c.restore();
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
// ---------- 猫:手抄本里的稚拙人脸猫,拎着老鼠 ----------
|
|
423
|
+
function cat(c, K, t, ch) {
|
|
424
|
+
const O = '#e3913e', ODk = '#b45a18', Wt = C.white;
|
|
425
|
+
c.save(); c.lineJoin = 'round'; c.lineCap = 'round';
|
|
426
|
+
// 尾巴(环纹)
|
|
427
|
+
c.strokeStyle = INK; c.lineWidth = K.tailW + 6; c.stroke(K.tail); c.strokeStyle = O; c.lineWidth = K.tailW; c.stroke(K.tail);
|
|
428
|
+
const tp = K.tailPts; c.strokeStyle = ODk; c.lineWidth = 6;
|
|
429
|
+
for (let i = 3; i < tp.length - 1; i += 3) { const a = Math.atan2(tp[i + 1][1] - tp[i][1], tp[i + 1][0] - tp[i][0]) + Math.PI / 2; c.beginPath(); c.moveTo(tp[i][0] - Math.cos(a) * 11, tp[i][1] - Math.sin(a) * 11); c.lineTo(tp[i][0] + Math.cos(a) * 11, tp[i][1] + Math.sin(a) * 11); c.stroke(); }
|
|
430
|
+
// 身体
|
|
431
|
+
const body = RIG.smooth(K.bodyPts); F(c, body, O, INK, 3.5);
|
|
432
|
+
c.save(); c.clip(body);
|
|
433
|
+
c.strokeStyle = ODk; c.lineWidth = 7;
|
|
434
|
+
for (let k = 0; k < 7; k++) { const y = 700 + k * 28; c.beginPath(); c.moveTo(418, y + 8); c.quadraticCurveTo(470, y - 10, 520, y + 14); c.stroke(); }
|
|
435
|
+
c.fillStyle = Wt; c.fill(K.white);
|
|
436
|
+
c.restore();
|
|
437
|
+
// 后腿团(坐姿大腿)
|
|
438
|
+
c.strokeStyle = INK; c.lineWidth = 2.5; c.beginPath(); c.arc(505, 840, 52, Math.PI * 1.05, Math.PI * 1.9); c.stroke();
|
|
439
|
+
// 前腿:一条着地,一条抬起拎老鼠
|
|
440
|
+
c.fillStyle = Wt; c.fill(K.legs[0]); c.strokeStyle = INK; c.lineWidth = 3; c.stroke(K.legs[0]);
|
|
441
|
+
for (let k = -1; k <= 1; k++) { c.beginPath(); c.moveTo(584 + k * 7, 880); c.lineTo(584 + k * 7, 892); c.lineWidth = 1.6; c.stroke(); }
|
|
442
|
+
const sh = [632, 744], pw = [664, 778];
|
|
443
|
+
const arm = RIG.limb(sh, pw, 32, 26); F(c, arm, Wt, INK, 3);
|
|
444
|
+
// 老鼠:尾巴挂在爪子上,钟摆摆动
|
|
445
|
+
const sw = Math.sin(t * 5.5) * 0.32, ml = 56, mx = pw[0] + Math.sin(sw) * ml, my = pw[1] + Math.cos(sw) * ml;
|
|
446
|
+
c.strokeStyle = '#6a4a40'; c.lineWidth = 2; c.beginPath(); c.moveTo(pw[0], pw[1] + 6); c.quadraticCurveTo(pw[0] + Math.sin(sw) * 30 + 6, pw[1] + 30, mx, my - 12); c.stroke();
|
|
447
|
+
c.save(); c.translate(mx, my); c.rotate(-sw);
|
|
448
|
+
const mb = new Path2D(); mb.ellipse(0, 6, 10, 17, 0, 0, 7); F(c, mb, '#4c3e38', INK, 2);
|
|
449
|
+
dot(c, -8, 20, 5, '#4c3e38', INK, 1.5); dot(c, 8, 20, 5, '#4c3e38', INK, 1.5); dot(c, 0, 24, 2, '#e8a0a0', null);
|
|
450
|
+
c.strokeStyle = '#4c3e38'; c.lineWidth = 3; c.beginPath(); c.moveTo(-6, 4); c.lineTo(-12, 12 + Math.sin(t * 9) * 3); c.moveTo(6, 4); c.lineTo(12, 12 - Math.sin(t * 9) * 3); c.stroke();
|
|
451
|
+
c.restore();
|
|
452
|
+
c.fillStyle = Wt; c.beginPath(); c.ellipse(pw[0], pw[1] + 2, 15, 12, 0.3, 0, 7); c.fill(); c.strokeStyle = INK; c.lineWidth = 2.5; c.stroke();
|
|
453
|
+
// 头:橘色,稚拙的人脸
|
|
454
|
+
F(c, K.head, O, INK, 3.5);
|
|
455
|
+
c.fillStyle = '#f2a8a0'; K.earInner.forEach(e => { c.beginPath(); e.forEach((p, i) => i ? c.lineTo(...p) : c.moveTo(...p)); c.fill(); });
|
|
456
|
+
c.save(); c.clip(K.head);
|
|
457
|
+
c.strokeStyle = ODk; c.lineWidth = 6; K.stripes.slice(0, 3).forEach(s => { c.beginPath(); c.moveTo(...s[0]); c.lineTo(...s[1]); c.stroke(); });
|
|
458
|
+
const hc = K.headC, fx = hc[0] + 10, fy = hc[1] + 6;
|
|
459
|
+
c.fillStyle = '#f7e6cc'; c.beginPath(); c.ellipse(fx, fy + 6, 42, 34, 0, 0, 7); c.fill();
|
|
460
|
+
c.restore();
|
|
461
|
+
// 脸颊红晕
|
|
462
|
+
c.fillStyle = 'rgba(232,110,110,.45)'; dot(c, fx - 26, fy + 14, 9, 'rgba(232,110,110,.45)', null); dot(c, fx + 28, fy + 12, 9, 'rgba(232,110,110,.45)', null);
|
|
463
|
+
// 眼:杏眼斜睨(瞳孔挤到右边看少女),厚上眼皮
|
|
464
|
+
const eyes = [[fx - 18, fy - 6], [fx + 18, fy - 8]];
|
|
465
|
+
eyes.forEach(([x, y], k) => {
|
|
466
|
+
if (ch.blink) { c.strokeStyle = INK; c.lineWidth = 2.5; c.beginPath(); c.moveTo(x - 10, y); c.lineTo(x + 10, y); c.stroke(); return; }
|
|
467
|
+
c.fillStyle = '#fff'; c.beginPath(); c.ellipse(x, y, 11, 7, 0, 0, 7); c.fill(); c.strokeStyle = INK; c.lineWidth = 2; c.stroke();
|
|
468
|
+
dot(c, x + 5, y + 1, 4.2, '#2a1c12', null);
|
|
469
|
+
c.lineWidth = 3; c.beginPath(); c.moveTo(x - 12, y - 2); c.quadraticCurveTo(x, y - 9, x + 12, y - 3); c.stroke();
|
|
470
|
+
c.lineWidth = 2; c.beginPath(); c.moveTo(x - 10, y - 15 - k * 2); c.quadraticCurveTo(x, y - 20 - k * 3, x + 11, y - 15 + k * 2); c.stroke();
|
|
471
|
+
});
|
|
472
|
+
// 鼻、撇嘴、胡须
|
|
473
|
+
c.strokeStyle = INK; c.lineWidth = 2; c.beginPath(); c.moveTo(fx + 1, fy + 2); c.quadraticCurveTo(fx + 5, fy + 12, fx - 1, fy + 14); c.stroke();
|
|
474
|
+
c.lineWidth = 2.4; c.beginPath(); c.moveTo(fx - 12, fy + 28); c.quadraticCurveTo(fx, fy + 20, fx + 12, fy + 27); c.stroke();
|
|
475
|
+
c.lineWidth = 1.4; for (const [a, b] of [[[fx + 34, fy + 14], [fx + 80, fy + 6]], [[fx + 34, fy + 20], [fx + 78, fy + 26]], [[fx - 34, fy + 16], [fx - 74, fy + 10]], [[fx - 34, fy + 22], [fx - 72, fy + 28]]]) { c.beginPath(); c.moveTo(...a); c.lineTo(...b); c.stroke(); }
|
|
476
|
+
c.restore();
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
// ---------- 蜗牛、老鼠 ----------
|
|
480
|
+
function snail(c, lt, t) {
|
|
481
|
+
const x = 912 - 62 * lt, y = 1040, st = Math.sin(t * 6) * 4;
|
|
482
|
+
c.save(); c.lineJoin = 'round';
|
|
483
|
+
const body = new Path2D(); body.moveTo(x + 52, y + 26); body.lineTo(x - 54 - st, y + 26); body.quadraticCurveTo(x - 70 - st, y + 22, x - 62 - st, y + 6); body.quadraticCurveTo(x - 40, y + 4, x - 10, y + 12); body.lineTo(x + 52, y + 18); body.closePath();
|
|
484
|
+
F(c, body, '#aab6cc', INK, 2.5);
|
|
485
|
+
c.strokeStyle = INK; c.lineWidth = 2.4; const ex = x - 58 - st;
|
|
486
|
+
for (const [dx, dy] of [[-12, -30], [2, -34]]) { const wob = Math.sin(t * 8 + dx) * 3; c.beginPath(); c.moveTo(ex + 4, y + 8); c.quadraticCurveTo(ex + dx * 0.5, y - 10, ex + dx + wob, y + dy); c.stroke(); dot(c, ex + dx + wob, y + dy, 3.5, INK, null); }
|
|
487
|
+
const shell = new Path2D(); shell.arc(x + 4, y - 10, 34, 0, 7); F(c, shell, '#e3a447', INK, 3);
|
|
488
|
+
c.strokeStyle = '#9a5a1a'; c.lineWidth = 3; c.beginPath(); for (let a = 0; a < 15; a += 0.2) { const r = 2 + a * 2.05; const px = x + 4 + Math.cos(a) * r, py = y - 10 + Math.sin(a) * r; a ? c.lineTo(px, py) : c.moveTo(px, py); } c.stroke();
|
|
489
|
+
c.restore();
|
|
490
|
+
}
|
|
491
|
+
function runMouse(c, lt, t) {
|
|
492
|
+
const q = clamp((lt - 0.12) / 1.05), x = lerp(1890, 1530, q), y = 898, leg = Math.sin(t * 40);
|
|
493
|
+
c.save(); c.lineCap = 'round';
|
|
494
|
+
c.fillStyle = 'rgba(80,50,20,.18)'; c.beginPath(); c.ellipse(x, y + 12, 30, 5, 0, 0, 7); c.fill();
|
|
495
|
+
c.strokeStyle = '#3a2a24'; c.lineWidth = 2; c.beginPath(); c.moveTo(x + 22, y); c.bezierCurveTo(x + 50, y - 12 + Math.sin(t * 14) * 6, x + 60, y + 10, x + 82, y - 4 + Math.sin(t * 14 + 1) * 6); c.stroke();
|
|
496
|
+
c.lineWidth = 3; c.beginPath(); c.moveTo(x - 10, y + 4); c.lineTo(x - 16 - leg * 7, y + 12); c.moveTo(x + 12, y + 4); c.lineTo(x + 16 + leg * 7, y + 12); c.stroke();
|
|
497
|
+
const b = new Path2D(); b.ellipse(x, y - 2, 25, 12, 0, 0, 7); F(c, b, '#3e302c', INK, 1.5);
|
|
498
|
+
const hd = new Path2D(); hd.moveTo(x - 14, y - 10); hd.quadraticCurveTo(x - 30, y - 8, x - 38, y + 2); hd.quadraticCurveTo(x - 24, y + 6, x - 12, y + 6); hd.closePath(); F(c, hd, '#3e302c', INK, 1.5);
|
|
499
|
+
dot(c, x - 16, y - 13, 6, '#5a4640', INK, 1.2); dot(c, x - 30, y - 2, 1.6, '#fff', null);
|
|
500
|
+
c.restore();
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
return {
|
|
504
|
+
init() { STATIC(); MASK(); },
|
|
505
|
+
draw(c, lt, t) {
|
|
506
|
+
const ch = P.choreo(lt, t);
|
|
507
|
+
c.drawImage(STATIC(), 0, 0);
|
|
508
|
+
glassTwinkle(c, t);
|
|
509
|
+
goldSweep(c, lt);
|
|
510
|
+
SPARKS.forEach(([x, y], k) => { const n = nearSweep(x, y, lt); if (n > 0) glint(c, x, y, 0.4 + n * 0.8, n); });
|
|
511
|
+
vines(c, t);
|
|
512
|
+
snail(c, lt, t);
|
|
513
|
+
runMouse(c, lt, t);
|
|
514
|
+
const K = RIG.cat({ tail: ch.tail, blink: ch.blink, breathe: ch.breathe });
|
|
515
|
+
cat(c, K, t, ch);
|
|
516
|
+
const G = RIG.girl({ cup: ch.cup, sip: ch.sip, hair: 'long', breathe: ch.breathe });
|
|
517
|
+
girl(c, G, lt, t, ch);
|
|
518
|
+
// 做旧:极淡的颗粒
|
|
519
|
+
c.drawImage(P.grain('goth', 0.05, [90, 60, 20], 0.16), 0, 0);
|
|
520
|
+
},
|
|
521
|
+
};
|
|
522
|
+
})();
|