@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,524 @@
|
|
|
1
|
+
// 公元前 1350 年 埃及墓室壁画(阿马尔纳时期)——纯代码。
|
|
2
|
+
// 管线:①静态层(灰泥墙+彩色几何边框+象形文字栏+窗/阿顿日盘+陶罐/供桌/椅)缓存
|
|
3
|
+
// → ②会动的母题(阿顿光线末端小手一张一合、水纹象形字流动、圣甲虫推日球)
|
|
4
|
+
// → ③角色:埃及程式(侧脸正面眼、正面肩、平涂+深色勾线)→ ④壁画表面(斑驳 multiply+裂纹+颗粒)
|
|
5
|
+
SCENES['02_egypt'] = (() => {
|
|
6
|
+
const W = 1920, H = 1080, { clamp, lerp } = U, P = PAINT;
|
|
7
|
+
const C = {
|
|
8
|
+
wall: '#eadcb8', wall2: '#d8c597', line: '#2a1810', rule: '#9a2b22',
|
|
9
|
+
red: '#b8322a', blue: '#2a58a8', green: '#2e8a55', yellow: '#e2b13a', black: '#231a14',
|
|
10
|
+
gold: '#e0ab38', goldD: '#a8741c', goldL: '#f3d27a', navy: '#1c2236', cream: '#f2ead6', white: '#f6f2e8',
|
|
11
|
+
skin: '#e6b282', skinD: '#c98d5c', terra: '#d4936a', lapis: '#2c56b0', turq: '#3fa6a0',
|
|
12
|
+
catO: '#e08a3c', catS: '#b45a1c', catW: '#f6efe0',
|
|
13
|
+
};
|
|
14
|
+
const BAND = [C.red, C.blue, C.yellow, C.green]; // 埃及边框四色
|
|
15
|
+
|
|
16
|
+
// ---------------- 小工具 ----------------
|
|
17
|
+
const poly = (g, pts, close = true) => { g.beginPath(); pts.forEach((p, i) => i ? g.lineTo(p[0], p[1]) : g.moveTo(p[0], p[1])); if (close) g.closePath(); };
|
|
18
|
+
const fs = (g, fill, stroke, lw = 2.5) => { if (fill) { g.fillStyle = fill; g.fill(); } if (stroke) { g.strokeStyle = stroke; g.lineWidth = lw; g.stroke(); } };
|
|
19
|
+
const sm = (pts, closed = true) => RIG.smooth(pts, closed);
|
|
20
|
+
|
|
21
|
+
// ---------------- 象形文字字形库(原点居中,约 50px 宽;h = 占位高度) ----------------
|
|
22
|
+
// 每个字形:{h, cols:[可选颜色], d(g) };g 已设好 strokeStyle/fillStyle/lineWidth
|
|
23
|
+
const GL = {
|
|
24
|
+
ankh: { h: 60, cols: [C.blue, C.green, C.black, C.red], d(g) { g.lineWidth = 3.6; g.beginPath(); g.ellipse(0, -17, 8, 11, 0, 0, 7); g.moveTo(-16, -3); g.lineTo(16, -3); g.moveTo(0, -5); g.lineTo(0, 29); g.stroke(); } },
|
|
25
|
+
sun: { h: 40, cols: [C.black, C.blue, C.red], d(g) { g.lineWidth = 3; g.beginPath(); g.arc(0, 0, 15, 0, 7); g.stroke(); g.beginPath(); g.arc(0, 0, 4, 0, 7); g.fill(); } },
|
|
26
|
+
bread: { h: 26, cols: [C.red, C.blue, C.green], d(g) { g.beginPath(); g.arc(0, 9, 19, Math.PI, 0); g.closePath(); g.stroke(); g.beginPath(); g.moveTo(-12, 4); g.lineTo(12, 4); g.stroke(); } },
|
|
27
|
+
reed: { h: 62, cols: [C.black, C.green, C.red], d(g) { g.beginPath(); g.moveTo(-2, 29); g.quadraticCurveTo(-11, 0, 1, -29); g.quadraticCurveTo(7, -2, 4, 29); g.stroke(); g.beginPath(); g.moveTo(1, -29); g.quadraticCurveTo(9, -31, 10, -24); g.stroke(); } },
|
|
28
|
+
owl: { h: 60, cols: [C.black, C.blue], d(g) { g.beginPath(); g.ellipse(3, 6, 12, 19, 0.1, 0, 7); g.stroke(); g.beginPath(); g.arc(-2, -18, 10, 0, 7); g.stroke(); g.beginPath(); g.arc(-6, -19, 2.4, 0, 7); g.arc(2, -19, 2.4, 0, 7); g.fill(); g.beginPath(); g.moveTo(-2, -14); g.lineTo(-3, -9); g.moveTo(9, 22); g.lineTo(18, 29); g.moveTo(-3, 24); g.lineTo(-5, 30); g.moveTo(4, 24); g.lineTo(3, 30); g.stroke(); } },
|
|
29
|
+
falcon: { h: 60, cols: [C.black, C.red, C.blue], d(g) { g.beginPath(); g.arc(-6, -20, 7, 0, 7); g.fill(); poly(g, [[-12, -21], [-19, -16], [-11, -15]]); g.fill(); g.beginPath(); g.ellipse(2, 1, 10, 20, -0.35, 0, 7); g.stroke(); poly(g, [[8, 16], [20, 30], [6, 27]]); g.fill(); g.beginPath(); g.moveTo(-3, 19); g.lineTo(-5, 30); g.moveTo(2, 19); g.lineTo(1, 30); g.moveTo(-1, -8); g.quadraticCurveTo(10, 0, 12, 14); g.stroke(); } },
|
|
30
|
+
heron: { h: 64, cols: [C.green, C.black, C.blue], d(g) { g.beginPath(); g.moveTo(-20, -22); g.lineTo(-8, -26); g.quadraticCurveTo(0, -28, -1, -18); g.quadraticCurveTo(-6, -8, 2, -2); g.stroke(); g.beginPath(); g.ellipse(8, 4, 13, 8, 0.4, 0, 7); g.stroke(); g.beginPath(); g.moveTo(4, 11); g.lineTo(2, 31); g.moveTo(10, 11); g.lineTo(12, 31); g.moveTo(18, 9); g.lineTo(24, 14); g.stroke(); } },
|
|
31
|
+
snake: { h: 30, cols: [C.green, C.black, C.red], d(g) { g.lineWidth = 3.2; g.beginPath(); g.moveTo(22, 8); g.bezierCurveTo(10, -4, 4, 14, -6, 6); g.bezierCurveTo(-14, 0, -16, -4, -20, -2); g.stroke(); g.beginPath(); g.moveTo(-20, -2); g.lineTo(-23, -9); g.moveTo(-17, -3); g.lineTo(-15, -10); g.stroke(); } },
|
|
32
|
+
eye: { h: 36, cols: [C.green, C.black, C.blue], d(g) { g.beginPath(); g.moveTo(-18, 0); g.quadraticCurveTo(0, -12, 18, 0); g.quadraticCurveTo(0, 9, -18, 0); g.stroke(); g.beginPath(); g.arc(0, -1, 4.5, 0, 7); g.fill(); g.beginPath(); g.moveTo(-18, -12); g.quadraticCurveTo(0, -20, 20, -11); g.moveTo(-4, 6); g.lineTo(-6, 16); g.moveTo(6, 5); g.quadraticCurveTo(14, 18, 4, 16); g.stroke(); } },
|
|
33
|
+
cartouche: { h: 74, cols: [C.black, C.red], d(g) { g.beginPath(); g.ellipse(0, -2, 15, 31, 0, 0, 7); g.stroke(); g.beginPath(); g.moveTo(-14, 33); g.lineTo(14, 33); g.stroke(); g.lineWidth = 2; g.beginPath(); g.arc(0, -18, 5, 0, 7); g.moveTo(-7, -2); g.lineTo(7, -2); g.moveTo(-6, 8); g.lineTo(-3, 13); g.lineTo(0, 8); g.lineTo(3, 13); g.lineTo(6, 8); g.stroke(); } },
|
|
34
|
+
scarab: { h: 46, cols: [C.blue, C.black], d(g) { g.beginPath(); g.ellipse(0, 6, 10, 14, 0, 0, 7); g.fill(); g.beginPath(); g.arc(0, -11, 6, 0, 7); g.fill(); g.beginPath(); for (const s of [-1, 1]) for (const k of [-1, 0, 1]) { g.moveTo(s * 9, 6 + k * 8); g.lineTo(s * 17, 2 + k * 11); } g.stroke(); } },
|
|
35
|
+
seated: { h: 58, cols: [C.red, C.black, C.blue], d(g) { g.beginPath(); g.arc(-2, -21, 6.5, 0, 7); g.fill(); poly(g, [[-6, -13], [4, -13], [6, 6], [16, 8], [17, 18], [-10, 18], [-10, 2]]); g.fill(); g.beginPath(); g.moveTo(-6, -8); g.lineTo(-17, -16); g.stroke(); g.beginPath(); g.moveTo(-14, 26); g.lineTo(18, 26); g.stroke(); } },
|
|
36
|
+
leg: { h: 50, cols: [C.green, C.black, C.red], d(g) { poly(g, [[-3, -24], [6, -24], [6, 18], [16, 22], [16, 26], [-4, 26]]); g.stroke(); } },
|
|
37
|
+
arm: { h: 24, cols: [C.black, C.red], d(g) { poly(g, [[-22, -4], [10, -4], [16, -8], [22, -6], [16, 2], [-22, 4]]); g.stroke(); } },
|
|
38
|
+
basket: { h: 26, cols: [C.blue, C.green, C.black], d(g) { g.beginPath(); g.moveTo(-20, -4); g.lineTo(20, -4); g.quadraticCurveTo(18, 12, 0, 12); g.quadraticCurveTo(-18, 12, -20, -4); g.stroke(); g.beginPath(); g.arc(22, 2, 5, -1.5, 1.6); g.stroke(); } },
|
|
39
|
+
house: { h: 36, cols: [C.black, C.red], d(g) { g.beginPath(); g.moveTo(-6, 14); g.lineTo(-18, 14); g.lineTo(-18, -14); g.lineTo(18, -14); g.lineTo(18, 14); g.lineTo(6, 14); g.stroke(); } },
|
|
40
|
+
strokes: { h: 34, cols: [C.red, C.black], d(g) { g.beginPath(); for (const x of [-8, 0, 8]) { g.moveTo(x, -14); g.lineTo(x, 14); } g.stroke(); } },
|
|
41
|
+
feather: { h: 60, cols: [C.blue, C.green, C.black], d(g) { g.beginPath(); g.moveTo(-2, 29); g.quadraticCurveTo(-8, -10, 4, -29); g.quadraticCurveTo(12, -18, 6, 0); g.quadraticCurveTo(3, 15, 2, 29); g.stroke(); } },
|
|
42
|
+
djed: { h: 62, cols: [C.blue, C.green], d(g) { g.beginPath(); g.moveTo(-6, 29); g.lineTo(-6, -10); g.moveTo(6, 29); g.lineTo(6, -10); for (let k = 0; k < 4; k++) { g.moveTo(-13, -12 - k * 5); g.lineTo(13, -12 - k * 5); } g.moveTo(-12, 29); g.lineTo(12, 29); g.stroke(); } },
|
|
43
|
+
shen: { h: 42, cols: [C.red, C.blue], d(g) { g.beginPath(); g.arc(0, -4, 13, 0, 7); g.stroke(); g.beginPath(); g.moveTo(-14, 13); g.lineTo(14, 13); g.stroke(); } },
|
|
44
|
+
jug: { h: 50, cols: [C.red, C.green, C.blue], d(g) { g.beginPath(); g.moveTo(-6, -22); g.lineTo(6, -22); g.lineTo(5, -14); g.quadraticCurveTo(16, -6, 12, 12); g.quadraticCurveTo(8, 22, 0, 22); g.quadraticCurveTo(-8, 22, -12, 12); g.quadraticCurveTo(-16, -6, -5, -14); g.closePath(); g.stroke(); g.beginPath(); g.moveTo(-10, 0); g.lineTo(10, 0); g.stroke(); } },
|
|
45
|
+
lotus: { h: 56, cols: [C.green, C.blue], d(g) { g.beginPath(); g.moveTo(0, 27); g.lineTo(0, -6); g.stroke(); poly(g, [[0, -6], [-12, -18], [-6, -26], [0, -16], [6, -26], [12, -18]]); g.stroke(); } },
|
|
46
|
+
nfr: { h: 56, cols: [C.black, C.red], d(g) { g.beginPath(); g.ellipse(0, 12, 10, 14, 0, 0, 7); g.moveTo(0, -2); g.lineTo(0, -26); g.moveTo(-6, -18); g.lineTo(6, -18); g.moveTo(-6, -12); g.lineTo(6, -12); g.stroke(); } },
|
|
47
|
+
mouth: { h: 20, cols: [C.red], d(g) { g.beginPath(); g.moveTo(-18, 0); g.quadraticCurveTo(0, -9, 18, 0); g.quadraticCurveTo(0, 9, -18, 0); g.stroke(); } },
|
|
48
|
+
water: { h: 30, cols: [C.blue], water: true, d(g, ph = 0) { g.lineWidth = 2.6; for (let r = -1; r <= 1; r++) { g.beginPath(); for (let i = 0; i <= 16; i++) { const x = -21 + i * 2.625, y = r * 9 + ((i + ph) % 2 < 1 ? -3 : 3); i ? g.lineTo(x, y) : g.moveTo(x, y); } g.stroke(); } } },
|
|
49
|
+
};
|
|
50
|
+
const GN = Object.keys(GL);
|
|
51
|
+
// 栏位:[分栏线 x 列表, y0, y1](照原片量的位置)
|
|
52
|
+
const GROUPS = [[[78, 154, 230, 306], 66, 566], [[852, 932, 1012, 1092, 1172], 66, 452], [[1560, 1637, 1713, 1790, 1866], 252, 882], [[298, 366], 614, 886]];
|
|
53
|
+
const GLYPHS = (() => { // 种子化排布,模块初始化时算好(水纹字要单独动起来,需要知道位置)
|
|
54
|
+
const r = U.rng(1350), out = [];
|
|
55
|
+
GROUPS.forEach(([xs, y0, y1]) => { for (let k = 0; k < xs.length - 1; k++) {
|
|
56
|
+
const used = {};
|
|
57
|
+
const cx = (xs[k] + xs[k + 1]) / 2; let y = y0 + 8, prev = '';
|
|
58
|
+
while (true) {
|
|
59
|
+
let n; do { n = GN[(r() * GN.length) | 0]; } while (n === prev || used[n] > 2 || ((n === 'scarab' || n === 'water') && r() < 0.6)); prev = n; used[n] = (used[n] || 0) + 1;
|
|
60
|
+
const gl = GL[n], s = (xs[k + 1] - xs[k]) / 78 * (1.0 + r() * 0.14);
|
|
61
|
+
if (y + gl.h * s > y1) break;
|
|
62
|
+
out.push({ n, x: cx + (r() - 0.5) * 4, y: y + gl.h * s / 2, s, col: gl.cols[(r() * gl.cols.length) | 0], ph: r() * 2 });
|
|
63
|
+
y += gl.h * s + 6 + r() * 5;
|
|
64
|
+
}
|
|
65
|
+
} });
|
|
66
|
+
// 保证有 ≥6 个水纹字(它们是会流动的那批),不够就把扁字形换成水纹
|
|
67
|
+
let nw = out.filter(q => q.n === 'water').length;
|
|
68
|
+
for (const q of out) { if (nw >= 6) break; if (['mouth', 'bread', 'basket', 'arm', 'strokes'].includes(q.n)) { q.n = 'water'; q.col = C.blue; nw++; } }
|
|
69
|
+
return out;
|
|
70
|
+
})();
|
|
71
|
+
const drawGlyph = (g, q, ph = 0, rv = 1) => { g.save(); g.translate(q.x, q.y); g.scale(q.s, q.s); g.strokeStyle = q.col; g.fillStyle = q.col; g.lineWidth = 3.1; g.lineCap = 'round'; g.lineJoin = 'round';
|
|
72
|
+
if (rv < 1) { g.setLineDash([Math.max(0.01, rv * 95), 999]); if (rv < 0.55) g.fillStyle = 'rgba(0,0,0,0)'; }
|
|
73
|
+
GL[q.n].d(g, ph); g.restore(); };
|
|
74
|
+
// 「铭文被写出来」:每 0.12s 从打乱的字表里取 4 个字(分散在各栏),擦掉→按笔画描出(dash 揭示),笔迹先是亮金再落回原色
|
|
75
|
+
const WRITERS = (() => { const r = U.rng(77), idx = GLYPHS.map((q, i) => i).filter(i => !GL[GLYPHS[i].n].water); for (let i = idx.length - 1; i > 0; i--) { const j = (r() * (i + 1)) | 0; [idx[i], idx[j]] = [idx[j], idx[i]]; } return idx; })();
|
|
76
|
+
const WRITE_SLOT = 0.12, WRITE_DUR = 0.36, WRITE_N = 6;
|
|
77
|
+
function writeGlyphs(c, lt) {
|
|
78
|
+
const wall = P.texture('eg_wall', C.wall), s0 = Math.floor(lt / WRITE_SLOT);
|
|
79
|
+
for (let s = Math.max(0, s0 - 2); s <= s0; s++) for (let m = 0; m < WRITE_N; m++) {
|
|
80
|
+
const q = GLYPHS[WRITERS[(s * WRITE_N + m) % WRITERS.length]], p = clamp((lt - s * WRITE_SLOT) / WRITE_DUR);
|
|
81
|
+
if (p >= 1) continue;
|
|
82
|
+
const w = 64 * q.s, h = (GL[q.n].h + 10) * q.s, x0 = q.x - w / 2, y0 = q.y - h / 2;
|
|
83
|
+
c.drawImage(wall, x0, y0, w, h, x0, y0, w, h);
|
|
84
|
+
const glow = 1 - p, col = P.rgb(P.mix(P.hex(q.col), [246, 200, 70], glow * 0.85));
|
|
85
|
+
c.save(); c.shadowColor = `rgba(255,200,80,${0.9 * glow})`; c.shadowBlur = 10 * glow;
|
|
86
|
+
drawGlyph(c, { ...q, col }, q.ph, Math.min(1, p * 1.35));
|
|
87
|
+
c.restore();
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// ---------------- 彩色几何边框 ----------------
|
|
92
|
+
function blocks(g, x0, y0, x1, y1, len, off = 0) { // 沿长边排彩块,块间米白细缝,外框黑线
|
|
93
|
+
const hor = (x1 - x0) > (y1 - y0), L = hor ? x1 - x0 : y1 - y0;
|
|
94
|
+
g.fillStyle = C.cream; g.fillRect(x0, y0, x1 - x0, y1 - y0);
|
|
95
|
+
for (let s = 0, k = off; s < L; s += len, k++) {
|
|
96
|
+
g.fillStyle = BAND[k % 4];
|
|
97
|
+
if (hor) g.fillRect(x0 + s + 3, y0 + 3, Math.min(len - 6, L - s - 3), y1 - y0 - 6); else g.fillRect(x0 + 3, y0 + s + 3, x1 - x0 - 6, Math.min(len - 6, L - s - 3));
|
|
98
|
+
g.fillStyle = C.black; if (hor) g.fillRect(x0 + s, y0, 2, y1 - y0); else g.fillRect(x0, y0 + s, x1 - x0, 2);
|
|
99
|
+
}
|
|
100
|
+
g.strokeStyle = C.black; g.lineWidth = 2; g.strokeRect(x0, y0, x1 - x0, y1 - y0);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// ---------------- 静态层 ----------------
|
|
104
|
+
const DISK = [580, 266];
|
|
105
|
+
function staticLayer(g) {
|
|
106
|
+
// 灰泥墙:底色+斑驳+颗粒
|
|
107
|
+
g.drawImage(P.texture('eg_wall', C.wall, { scale: 0.0035, amt: 16, grain: 12, dark: C.wall2, seed: 13 }), 0, 0);
|
|
108
|
+
// 象形文字栏:分栏红线+字形
|
|
109
|
+
g.lineCap = 'round';
|
|
110
|
+
GROUPS.forEach(([xs, y0, y1]) => xs.forEach(x => { g.strokeStyle = C.rule; g.lineWidth = 2.6; g.beginPath(); g.moveTo(x, y0); g.lineTo(x, y1); g.stroke(); }));
|
|
111
|
+
GLYPHS.forEach(q => { if (!GL[q.n].water) drawGlyph(g, q); });
|
|
112
|
+
// —— 窗 ——
|
|
113
|
+
// 檐口(cavetto):上宽下窄的竖条纹弧面
|
|
114
|
+
const top = [338, 822], bot = [362, 798], cy0 = 128, cy1 = 172, st = [C.blue, C.white, C.red, C.white, C.green, C.white];
|
|
115
|
+
const n = 30;
|
|
116
|
+
for (let i = 0; i < n; i++) {
|
|
117
|
+
const a = i / n, b = (i + 1) / n;
|
|
118
|
+
poly(g, [[lerp(top[0], top[1], a), cy0], [lerp(top[0], top[1], b), cy0], [lerp(bot[0], bot[1], b), cy1], [lerp(bot[0], bot[1], a), cy1]]);
|
|
119
|
+
g.fillStyle = st[i % 6]; g.fill();
|
|
120
|
+
}
|
|
121
|
+
g.strokeStyle = C.black; g.lineWidth = 1.5;
|
|
122
|
+
for (let i = 0; i <= n; i++) { const a = i / n; g.beginPath(); g.moveTo(lerp(top[0], top[1], a), cy0); g.lineTo(lerp(bot[0], bot[1], a), cy1); g.stroke(); }
|
|
123
|
+
// 檐口内凹的阴影(上部暗一点)
|
|
124
|
+
const cg = g.createLinearGradient(0, cy0, 0, cy1); cg.addColorStop(0, 'rgba(40,20,10,.28)'); cg.addColorStop(0.5, 'rgba(40,20,10,0)'); g.fillStyle = cg;
|
|
125
|
+
poly(g, [[top[0], cy0], [top[1], cy0], [bot[1], cy1], [bot[0], cy1]]); g.fill();
|
|
126
|
+
g.fillStyle = C.gold; g.fillRect(334, 118, 492, 11); g.strokeStyle = C.black; g.lineWidth = 2; g.strokeRect(334, 118, 492, 11);
|
|
127
|
+
g.fillStyle = C.gold; g.fillRect(358, 172, 444, 13); g.strokeRect(358, 172, 444, 13);
|
|
128
|
+
g.fillStyle = C.goldD; for (let x = 364; x < 798; x += 14) g.fillRect(x, 175, 6, 7);
|
|
129
|
+
// 窗框:彩块(左、右、下)+顶部蓝带
|
|
130
|
+
blocks(g, 378, 185, 408, 560, 40, 1); blocks(g, 772, 185, 802, 560, 40, 3); blocks(g, 378, 530, 802, 560, 40, 0);
|
|
131
|
+
g.fillStyle = C.blue; g.fillRect(408, 185, 364, 15); g.strokeStyle = C.black; g.strokeRect(408, 185, 364, 15);
|
|
132
|
+
// 窗内:白底(略带灰泥纹)
|
|
133
|
+
g.fillStyle = '#f2ede1'; g.fillRect(408, 200, 364, 330);
|
|
134
|
+
g.globalAlpha = 0.25; g.drawImage(P.texture('eg_wall', C.wall), 408, 200, 364, 330, 408, 200, 364, 330); g.globalAlpha = 1;
|
|
135
|
+
g.fillStyle = C.blue; g.fillRect(408, 200, 364, 9); g.fillRect(762, 200, 10, 30); poly(g, [[740, 209], [772, 209], [772, 222]]); g.fill();
|
|
136
|
+
g.strokeStyle = C.black; g.lineWidth = 2; g.strokeRect(408, 200, 364, 330);
|
|
137
|
+
// 阿顿日盘+圣蛇+安卡
|
|
138
|
+
g.beginPath(); g.arc(DISK[0], DISK[1], 46, 0, 7); g.fillStyle = '#c8372b'; g.fill(); g.lineWidth = 3; g.strokeStyle = '#7a1c14'; g.stroke();
|
|
139
|
+
g.beginPath(); g.arc(DISK[0], DISK[1], 38, 0, 7); g.strokeStyle = 'rgba(255,200,150,.35)'; g.lineWidth = 2; g.stroke();
|
|
140
|
+
g.fillStyle = C.gold; g.beginPath(); g.ellipse(580, 300, 7, 10, 0, 0, 7); g.fill(); g.strokeStyle = C.black; g.lineWidth = 1.6; g.stroke();
|
|
141
|
+
g.beginPath(); g.moveTo(580, 290); g.quadraticCurveTo(592, 305, 580, 318); g.lineWidth = 4; g.strokeStyle = C.gold; g.stroke();
|
|
142
|
+
drawGlyph(g, { n: 'ankh', x: 580, y: 332, s: 0.42, col: C.blue });
|
|
143
|
+
// —— 左侧尖底陶罐 ×2,桌边小罐 ——
|
|
144
|
+
jar(g, 108, 644, 1); jar(g, 212, 644, 1); jar(g, 886, 714, 0.72);
|
|
145
|
+
// —— 供桌 ——
|
|
146
|
+
poly(g, [[975, 660], [962, 702], [984, 748], [984, 792], [950, 862], [930, 900], [1090, 900], [1070, 862], [1036, 792], [1036, 748], [1058, 702], [1045, 660]]); fs(g, C.white, C.line, 2.5);
|
|
147
|
+
g.save(); g.clip(); g.fillStyle = C.blue; g.fillRect(940, 752, 140, 10); g.fillStyle = C.red; g.fillRect(940, 768, 140, 10); g.restore();
|
|
148
|
+
g.strokeStyle = 'rgba(140,110,80,.5)'; g.lineWidth = 1.5; g.beginPath(); g.moveTo(1000, 800); g.quadraticCurveTo(990, 850, 960, 890); g.stroke();
|
|
149
|
+
g.fillStyle = C.white; g.fillRect(820, 640, 380, 20); g.strokeStyle = C.line; g.lineWidth = 2.5; g.strokeRect(820, 640, 380, 20);
|
|
150
|
+
g.strokeStyle = C.red; g.lineWidth = 2; g.beginPath(); g.moveTo(824, 655); g.lineTo(1196, 655); g.stroke();
|
|
151
|
+
// 供品:白圆锥面包、金碟、蓝葡萄、绿荷叶盘
|
|
152
|
+
poly(g, [[836, 640], [844, 590], [852, 568], [860, 590], [870, 640]]); fs(g, C.white, C.line, 2.2);
|
|
153
|
+
g.beginPath(); g.moveTo(870, 640); g.quadraticCurveTo(872, 604, 908, 602); g.quadraticCurveTo(944, 604, 946, 640); g.closePath(); fs(g, C.gold, C.line, 2.2);
|
|
154
|
+
g.beginPath(); g.arc(908, 626, 5, 0, 7); g.strokeStyle = C.goldD; g.lineWidth = 2; g.stroke();
|
|
155
|
+
[[892, 600], [906, 600], [920, 600], [899, 587], [913, 587], [906, 574], [885, 588], [927, 588], [892, 575], [920, 575], [906, 561]].forEach(([x, y]) => { g.beginPath(); g.arc(x, y, 8, 0, 7); fs(g, '#2c4aa0', '#141a3a', 1.5); g.fillStyle = 'rgba(160,190,255,.6)'; g.beginPath(); g.arc(x - 2.5, y - 2.5, 2.2, 0, 7); g.fill(); });
|
|
156
|
+
g.beginPath(); g.ellipse(888, 541, 52, 9, 0, 0, 7); fs(g, C.green, C.line, 2); g.strokeStyle = '#1f6a40'; g.lineWidth = 1.5; g.beginPath(); g.moveTo(842, 541); g.lineTo(934, 541); g.stroke();
|
|
157
|
+
// —— 椅子(金色细腿椅,椅背红蓝块) ——
|
|
158
|
+
chair(g);
|
|
159
|
+
// 脚边蓝碗
|
|
160
|
+
g.beginPath(); g.moveTo(1342, 878); g.lineTo(1418, 878); g.quadraticCurveTo(1412, 900, 1380, 900); g.quadraticCurveTo(1348, 900, 1342, 878); fs(g, '#3a78c8', C.line, 2);
|
|
161
|
+
g.beginPath(); g.ellipse(1380, 878, 38, 5, 0, 0, 7); fs(g, '#8cc0ee', C.line, 1.6);
|
|
162
|
+
// —— 地线与底部多层饰带 ——
|
|
163
|
+
g.fillStyle = C.black; g.fillRect(0, 898, W, 6);
|
|
164
|
+
g.fillStyle = C.cream; g.fillRect(0, 904, W, 106);
|
|
165
|
+
blocks(g, -20, 914, W + 20, 948, 64, 0);
|
|
166
|
+
g.fillStyle = C.yellow; g.fillRect(0, 961, W, 15); g.fillStyle = C.red; g.fillRect(0, 984, W, 14);
|
|
167
|
+
g.fillStyle = C.black; [912, 960, 977, 983, 999, 1008].forEach(y => g.fillRect(0, y, W, 1.6));
|
|
168
|
+
// 深蓝带(细颗粒)
|
|
169
|
+
g.fillStyle = C.navy; g.fillRect(0, 1010, W, 70);
|
|
170
|
+
const r = U.rng(7); for (let i = 0; i < 2600; i++) { g.fillStyle = r() < 0.5 ? 'rgba(90,100,140,.35)' : 'rgba(5,8,20,.45)'; g.fillRect(r() * W, 1010 + r() * 70, 1 + r() * 2, 1 + r() * 2); }
|
|
171
|
+
// —— 顶部与两侧彩色边框 ——
|
|
172
|
+
blocks(g, -10, 6, W + 10, 40, 56, 2);
|
|
173
|
+
blocks(g, 32, 40, 58, 898, 46, 1); blocks(g, 1890, 40, 1916, 898, 46, 3);
|
|
174
|
+
}
|
|
175
|
+
function jar(g, cx, y0, s) {
|
|
176
|
+
g.save(); g.translate(cx, y0); g.scale(s, s);
|
|
177
|
+
// 支架(X 形白腿)
|
|
178
|
+
g.strokeStyle = C.line; g.lineWidth = 2.5; g.fillStyle = C.white;
|
|
179
|
+
poly(g, [[-26, 256], [-20, 256], [10, 196], [4, 196]]); fs(g, C.white, C.line, 2); poly(g, [[26, 256], [20, 256], [-10, 196], [-4, 196]]); fs(g, C.white, C.line, 2);
|
|
180
|
+
g.fillRect(-24, 198, 48, 6); g.strokeRect(-24, 198, 48, 6);
|
|
181
|
+
// 罐身:圆肩、尖底
|
|
182
|
+
g.beginPath(); g.moveTo(-10, 30); g.bezierCurveTo(-40, 50, -38, 120, -20, 180); g.quadraticCurveTo(-6, 222, 0, 228); g.quadraticCurveTo(6, 222, 20, 180); g.bezierCurveTo(38, 120, 40, 50, 10, 30); g.closePath(); fs(g, C.terra, C.line, 2.5);
|
|
183
|
+
g.save(); g.clip();
|
|
184
|
+
g.fillStyle = C.green; g.fillRect(-40, 52, 80, 6); g.fillStyle = C.blue; g.fillRect(-40, 58, 80, 4);
|
|
185
|
+
g.fillStyle = '#2f9a8a'; for (let x = -36; x < 36; x += 9) { poly(g, [[x, 62], [x + 9, 62], [x + 4.5, 82]]); g.fill(); }
|
|
186
|
+
g.strokeStyle = 'rgba(80,40,20,.6)'; g.lineWidth = 1.6; [[150], [158]].forEach(([y]) => { g.beginPath(); g.moveTo(-40, y); g.lineTo(40, y); g.stroke(); });
|
|
187
|
+
g.fillStyle = 'rgba(255,230,200,.25)'; g.beginPath(); g.ellipse(-14, 110, 6, 40, 0, 0, 7); g.fill();
|
|
188
|
+
g.restore();
|
|
189
|
+
// 颈与盖
|
|
190
|
+
g.fillStyle = C.terra; g.fillRect(-9, 18, 18, 14); g.strokeStyle = C.line; g.lineWidth = 2; g.strokeRect(-9, 18, 18, 14);
|
|
191
|
+
g.beginPath(); g.moveTo(-14, 20); g.quadraticCurveTo(-14, -6, 0, -6); g.quadraticCurveTo(14, -6, 14, 20); g.closePath(); fs(g, '#3a302a', C.line, 2);
|
|
192
|
+
g.restore();
|
|
193
|
+
}
|
|
194
|
+
function chair(g) {
|
|
195
|
+
g.lineJoin = 'round';
|
|
196
|
+
// 后腿、前腿(收腰的金腿+红白条纹狮爪座)
|
|
197
|
+
const leg = (x) => { g.beginPath(); g.moveTo(x - 9, 748); g.bezierCurveTo(x - 16, 790, x - 4, 830, x - 12, 872); g.lineTo(x + 12, 872); g.bezierCurveTo(x + 4, 830, x + 16, 790, x + 9, 748); g.closePath(); fs(g, C.gold, C.line, 2.4);
|
|
198
|
+
g.fillStyle = C.white; g.fillRect(x - 16, 872, 32, 26); g.strokeStyle = C.line; g.lineWidth = 2; g.strokeRect(x - 16, 872, 32, 26); g.fillStyle = C.red; g.fillRect(x - 16, 878, 32, 5); g.fillRect(x - 16, 888, 32, 5); };
|
|
199
|
+
leg(1458); leg(1312);
|
|
200
|
+
// 座下竖栏+横档
|
|
201
|
+
g.fillStyle = C.gold; for (let x = 1330; x < 1446; x += 20) { g.fillRect(x, 750, 7, 54); g.strokeStyle = C.line; g.lineWidth = 1.4; g.strokeRect(x, 750, 7, 54); }
|
|
202
|
+
g.fillRect(1300, 802, 170, 8); g.strokeRect(1300, 802, 170, 8);
|
|
203
|
+
// 椅背:竖柱(红蓝块)
|
|
204
|
+
g.beginPath(); g.moveTo(1476, 742); g.lineTo(1478, 478); g.quadraticCurveTo(1480, 458, 1492, 458); g.quadraticCurveTo(1504, 460, 1500, 478); g.lineTo(1498, 742); g.closePath(); fs(g, C.gold, C.line, 2.4);
|
|
205
|
+
for (let k = 0; k < 9; k++) { g.fillStyle = k % 2 ? C.blue : C.red; g.fillRect(1483, 494 + k * 28, 10, 13); }
|
|
206
|
+
// 座面
|
|
207
|
+
g.fillStyle = C.gold; g.fillRect(1292, 734, 210, 16); g.strokeStyle = C.line; g.lineWidth = 2.4; g.strokeRect(1292, 734, 210, 16);
|
|
208
|
+
g.fillStyle = C.red; for (let x = 1300; x < 1496; x += 24) g.fillRect(x, 739, 10, 6);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// ---------------- 壁画表面:斑驳(multiply)+裂纹+颗粒 ----------------
|
|
212
|
+
const surface = () => P.cached('eg_surface', W, H, (g) => {
|
|
213
|
+
const img = g.createImageData(W, H), d = img.data, r = U.rng(99);
|
|
214
|
+
for (let y = 0; y < H; y += 2) for (let x = 0; x < W; x += 2) {
|
|
215
|
+
const n = P.fbm(x * 0.006 + 40, y * 0.006, 4), m = P.fbm(x * 0.03, y * 0.03 + 9, 2);
|
|
216
|
+
const v = 243 + n * 30 + m * 12 + (r() - 0.5) * 18;
|
|
217
|
+
for (const [dx, dy] of [[0, 0], [1, 0], [0, 1], [1, 1]]) { const i = ((y + dy) * W + x + dx) * 4; d[i] = v; d[i + 1] = v - 6; d[i + 2] = v - 16; d[i + 3] = 255; }
|
|
218
|
+
}
|
|
219
|
+
g.putImageData(img, 0, 0);
|
|
220
|
+
// 发丝裂纹(墙面老化,跨过人物)
|
|
221
|
+
const rr = U.rng(5);
|
|
222
|
+
[[0, 610, 0.1], [700, 0, 1.3], [1210, 0, 1.1], [1500, 980, -0.9], [380, 1080, -1.2], [1920, 420, 2.9]].forEach(([x, y, a0]) => {
|
|
223
|
+
g.strokeStyle = 'rgba(90,70,50,.55)'; g.lineWidth = 1.1; let a = a0;
|
|
224
|
+
g.beginPath(); g.moveTo(x, y); for (let s = 0; s < 34; s++) { a += (rr() - 0.5) * 0.7; x += Math.cos(a) * 14; y += Math.sin(a) * 14; g.lineTo(x, y); if (rr() < 0.08) { g.moveTo(x, y); } } g.stroke();
|
|
225
|
+
});
|
|
226
|
+
});
|
|
227
|
+
const specks = () => P.grain('eg_specks', 0.018, [70, 50, 30], 0.4);
|
|
228
|
+
|
|
229
|
+
// ---------------- 阿顿光线:末端小手一张一合 ----------------
|
|
230
|
+
const HANDS = [[444, 322], [436, 358], [428, 402], [440, 462], [446, 508], [492, 512], [538, 498], [612, 470], [680, 452], [712, 424], [732, 390], [746, 356], [748, 326]];
|
|
231
|
+
function handAt(g, x, y, ang, open, col = '#b4452c') {
|
|
232
|
+
g.save(); g.translate(x, y); g.rotate(ang);
|
|
233
|
+
g.fillStyle = col; g.strokeStyle = '#5a1c10'; g.lineWidth = 1.3;
|
|
234
|
+
g.scale(1.35, 1.35);
|
|
235
|
+
g.lineCap = 'round'; g.lineWidth = 4.2;
|
|
236
|
+
g.scale(0.9 + 0.3 * open, 0.9 + 0.3 * open);
|
|
237
|
+
for (let k = 0; k < 4; k++) { const a = (k - 1.5) * (0.03 + open * 0.42); g.beginPath(); g.moveTo(Math.cos(a) * 5, Math.sin(a) * 5); g.lineTo(Math.cos(a) * (12.5 + open * 1.5), Math.sin(a) * (12.5 + open * 1.5)); g.strokeStyle = '#5a1c10'; g.lineWidth = 5.6; g.stroke(); g.strokeStyle = col; g.lineWidth = 3.4; g.stroke(); }
|
|
238
|
+
g.beginPath(); g.moveTo(1, -5); g.lineTo(5, -10 - open * 3); g.strokeStyle = '#5a1c10'; g.lineWidth = 5.4; g.stroke(); g.strokeStyle = col; g.lineWidth = 3.2; g.stroke();
|
|
239
|
+
g.beginPath(); g.ellipse(0, 0, 8, 6.6, 0, 0, 7); g.fillStyle = col; g.fill(); g.strokeStyle = '#5a1c10'; g.lineWidth = 1.2; g.stroke();
|
|
240
|
+
g.beginPath(); g.moveTo(-9, 0); g.lineTo(-14, 0); g.strokeStyle = col; g.lineWidth = 4; g.stroke(); // 手腕
|
|
241
|
+
g.restore();
|
|
242
|
+
}
|
|
243
|
+
function rays(c, lt, t) {
|
|
244
|
+
c.save(); c.lineCap = 'round';
|
|
245
|
+
// 日盘脉动光晕(周期 0.45s)
|
|
246
|
+
const pu = 0.5 + 0.5 * Math.sin(lt * Math.PI * 2 / 0.45);
|
|
247
|
+
c.save(); c.beginPath(); c.rect(408, 200, 364, 330); c.clip();
|
|
248
|
+
const hg = c.createRadialGradient(DISK[0], DISK[1], 46, DISK[0], DISK[1], 70 + 30 * pu); hg.addColorStop(0, `rgba(255,180,80,${0.5 * pu + 0.12})`); hg.addColorStop(1, 'rgba(255,170,70,0)');
|
|
249
|
+
c.fillStyle = hg; c.beginPath(); c.arc(DISK[0], DISK[1], 100 + 30 * pu, 0, 7); c.fill();
|
|
250
|
+
c.beginPath(); c.arc(DISK[0], DISK[1], 52 + 6 * pu, 0, 7); c.strokeStyle = `rgba(255,214,110,${0.75 * pu})`; c.lineWidth = 5; c.stroke();
|
|
251
|
+
c.beginPath(); c.arc(DISK[0], DISK[1], 46, 0, 7); c.fillStyle = '#c8372b'; c.fill(); c.lineWidth = 3; c.strokeStyle = '#7a1c14'; c.stroke();
|
|
252
|
+
c.fillStyle = C.gold; c.beginPath(); c.ellipse(580, 300, 7, 10, 0, 0, 7); c.fill(); c.strokeStyle = C.black; c.lineWidth = 1.6; c.stroke();
|
|
253
|
+
c.restore();
|
|
254
|
+
const ray = (ex0, ey0, k, long) => {
|
|
255
|
+
// 光线沿扇形依次伸缩(波沿 k 传播),末端 ±9%
|
|
256
|
+
const ext = 1 + 0.09 * Math.sin(lt * Math.PI * 2 / 0.45 - k * 0.55);
|
|
257
|
+
let ex = DISK[0] + (ex0 - DISK[0]) * ext, ey = DISK[1] + (ey0 - DISK[1]) * ext; if (!long) { ex = clamp(ex, 428, 752); ey = Math.min(ey, 512); }
|
|
258
|
+
const wob = Math.sin(t * 7 + k * 1.3) * 3, wx = ex + wob, wy = ey + Math.cos(t * 6 + k) * 2;
|
|
259
|
+
const ang = Math.atan2(wy - DISK[1], wx - DISK[0]);
|
|
260
|
+
c.strokeStyle = '#c23a2a'; c.lineWidth = (long ? 2.6 : 2.2) + 1.6 * (ext - 0.91) / 0.18;
|
|
261
|
+
c.beginPath(); c.moveTo(DISK[0] + Math.cos(ang) * 44, DISK[1] + Math.sin(ang) * 44); c.lineTo(wx - Math.cos(ang) * 6, wy - Math.sin(ang) * 6); c.stroke();
|
|
262
|
+
const open = 0.5 + 0.5 * Math.sin(lt * Math.PI * 2 / 0.4 + k * 0.9);
|
|
263
|
+
handAt(c, wx, wy, ang, open);
|
|
264
|
+
return [wx, wy, ang];
|
|
265
|
+
};
|
|
266
|
+
c.save(); c.beginPath(); c.rect(408, 200, 364, 330); c.clip();
|
|
267
|
+
HANDS.forEach(([x, y], k) => ray(x, y, k, false));
|
|
268
|
+
c.restore();
|
|
269
|
+
// 两条长光线的窗内段(窗外段与小手在画猫之后补,压在猫上)
|
|
270
|
+
LONG.forEach(([x, y, k]) => { const wx = x + Math.sin(t * 7 + k * 1.3) * 3, wy = y + Math.cos(t * 6 + k) * 2, ang = Math.atan2(wy - DISK[1], wx - DISK[0]);
|
|
271
|
+
c.strokeStyle = '#c23a2a'; c.lineWidth = 2.6; c.beginPath(); c.moveTo(DISK[0] + Math.cos(ang) * 44, DISK[1] + Math.sin(ang) * 44); c.lineTo(lerp(DISK[0], wx, 0.64), lerp(DISK[1], wy, 0.64)); c.stroke(); });
|
|
272
|
+
c.restore();
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// ---------------- 圣甲虫推日球 ----------------
|
|
276
|
+
function scarab(c, lt) {
|
|
277
|
+
let x = 800 + 642 * (lt - 0.394); x = ((x + 120) % 2160 + 2160) % 2160 - 120;
|
|
278
|
+
const y = 1044, bx = x + 54, br = 23, rot = bx / br, pose = Math.floor(lt * 15) % 2;
|
|
279
|
+
c.save(); c.lineCap = 'round'; c.lineJoin = 'round';
|
|
280
|
+
c.translate(x + 27, y); c.scale(1.22, 1.22); c.translate(-x - 27, -y);
|
|
281
|
+
// 日球:红底黄点,随前进滚动
|
|
282
|
+
c.beginPath(); c.arc(bx, y - 2, br, 0, 7); c.fillStyle = '#c8302a'; c.fill(); c.strokeStyle = '#3a0c08'; c.lineWidth = 2.2; c.stroke();
|
|
283
|
+
c.save(); c.clip(); c.fillStyle = '#f2c23a';
|
|
284
|
+
for (let k = 0; k < 9; k++) { const a = rot + k * 0.698, rr = k % 3 === 0 ? 0 : 14; const px = bx + Math.cos(a) * rr, py = y - 2 + Math.sin(a) * rr * 0.9; if (k % 3 === 0 && k) continue; c.beginPath(); c.arc(px, py, 3.6, 0, 7); c.fill(); }
|
|
285
|
+
c.restore();
|
|
286
|
+
// 腿:两套姿态,每 4 帧(60fps)换一次
|
|
287
|
+
c.strokeStyle = '#141a30'; c.lineWidth = 3;
|
|
288
|
+
const legs = pose ? [[-14, -16, -26], [0, -18, -6], [14, -14, 18]] : [[-14, -14, -32], [0, -19, 2], [14, -18, 24]];
|
|
289
|
+
legs.forEach(([lx, ly, ex], i) => { for (const s of [-1, 1]) { const q = s * (i === 1 ? 1 : (pose ? 1 : -1)); c.beginPath(); c.moveTo(x + lx, y); c.lineTo(x + lx + (ex - lx) * 0.5, y + s * (ly - 4)); c.lineTo(x + ex + q * 2, y + s * (ly + 4)); c.stroke(); } });
|
|
290
|
+
// 前足顶着球
|
|
291
|
+
c.beginPath(); c.moveTo(x + 26, y - 4); c.lineTo(bx - br + 2, y - 12 + pose * 3); c.moveTo(x + 26, y + 4); c.lineTo(bx - br + 1, y + 8 - pose * 3); c.stroke();
|
|
292
|
+
// 身体:青金石蓝+绿松石鞘翅高光
|
|
293
|
+
c.beginPath(); c.ellipse(x - 4, y, 24, 17, 0, 0, 7); c.fillStyle = C.lapis; c.fill(); c.strokeStyle = '#0d1430'; c.lineWidth = 2.2; c.stroke();
|
|
294
|
+
c.beginPath(); c.moveTo(x - 28, y); c.lineTo(x + 18, y); c.stroke();
|
|
295
|
+
c.fillStyle = C.turq; c.beginPath(); c.ellipse(x - 8, y - 8, 12, 4, -0.1, 0, 7); c.fill(); c.beginPath(); c.ellipse(x - 8, y + 8, 12, 4, 0.1, 0, 7); c.fill();
|
|
296
|
+
c.beginPath(); c.ellipse(x + 22, y, 8, 11, 0, 0, 7); c.fillStyle = '#3a68c4'; c.fill(); c.strokeStyle = '#0d1430'; c.stroke();
|
|
297
|
+
c.fillStyle = C.gold; c.beginPath(); c.arc(x + 25, y, 3, 0, 7); c.fill();
|
|
298
|
+
c.restore();
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// ---------------- 巴斯特坐姿的橘白猫 ----------------
|
|
302
|
+
const CAT_S = 0.85, CAT_ANCHOR = [540, 898];
|
|
303
|
+
const catPt = (x, y) => [CAT_ANCHOR[0] + (x - CAT_ANCHOR[0]) * CAT_S, CAT_ANCHOR[1] + (y - CAT_ANCHOR[1]) * CAT_S];
|
|
304
|
+
const LONG = [[...catPt(540, 676), 20], [...catPt(668, 626), 21]]; // 两条长光线的末端:跟着猫头缩放
|
|
305
|
+
function cat(c, K, ch) {
|
|
306
|
+
const L = C.line, hc = K.headC, br = ch.breathe * 260;
|
|
307
|
+
const B = (x, y) => [x, y - (y < 800 ? br * (800 - y) / 130 : 0)];
|
|
308
|
+
c.save(); c.lineJoin = 'round'; c.lineCap = 'round';
|
|
309
|
+
// 以脚底 (540,898) 为锚整体缩到 0.85:耳尖从 y≈530 落到 ≈585,和窗框底边(y≈560)留出空隙
|
|
310
|
+
c.translate(CAT_ANCHOR[0], CAT_ANCHOR[1]); c.scale(CAT_S, CAT_S); c.translate(-CAT_ANCHOR[0], -CAT_ANCHOR[1]);
|
|
311
|
+
// 尾巴:从臀后绕向身前
|
|
312
|
+
const tp = K.tailPts;
|
|
313
|
+
c.strokeStyle = L; c.lineWidth = 24; c.beginPath(); tp.forEach((p, i) => i ? c.lineTo(p[0], p[1] - 4) : c.moveTo(p[0], p[1] - 4)); c.stroke();
|
|
314
|
+
c.strokeStyle = C.catO; c.lineWidth = 19; c.stroke();
|
|
315
|
+
c.strokeStyle = C.catS; c.lineWidth = 4;
|
|
316
|
+
for (let i = 3; i < tp.length - 3; i += 3) { const a = tp[i], b = tp[i + 1], ang = Math.atan2(b[1] - a[1], b[0] - a[0]) + Math.PI / 2; c.beginPath(); c.moveTo(a[0] + Math.cos(ang) * 8, a[1] - 4 + Math.sin(ang) * 8); c.lineTo(a[0] - Math.cos(ang) * 8, a[1] - 4 - Math.sin(ang) * 8); c.stroke(); }
|
|
317
|
+
const tip = tp[tp.length - 1]; c.fillStyle = C.catW; c.beginPath(); c.arc(tip[0], tip[1] - 4, 9, 0, 7); c.fill(); c.strokeStyle = L; c.lineWidth = 2; c.beginPath(); c.arc(tip[0], tip[1] - 4, 10.5, -1.2, 1.9); c.stroke();
|
|
318
|
+
// 身体:挺直上身、圆臀;前腿并在剪影里(胸口到前爪一整片白)
|
|
319
|
+
const body = sm([[568, 666], [538, 690], [506, 726], [482, 772], [468, 818], [464, 860], [474, 897], [560, 899], [666, 899], [663, 862], [659, 800], [654, 744], [646, 706], [640, 680]].map(p => B(...p)));
|
|
320
|
+
const cw = sm([B(616, 688), B(640, 678), B(650, 716), B(656, 790), [661, 860], [666, 899], [598, 899], [600, 850], [604, 790], B(610, 736)]);
|
|
321
|
+
c.fillStyle = C.catO; c.fill(body);
|
|
322
|
+
c.save(); c.clip(body);
|
|
323
|
+
c.fillStyle = C.catW; c.fill(cw);
|
|
324
|
+
c.strokeStyle = C.catS; c.lineWidth = 6;
|
|
325
|
+
[[[548, 690], [532, 716]], [[524, 704], [508, 736]], [[500, 730], [484, 766]], [[480, 764], [466, 800]], [[464, 806], [456, 840]], [[558, 716], [542, 748]], [[536, 744], [520, 780]], [[512, 776], [498, 812]], [[578, 742], [566, 770]]].forEach(([a, b]) => { c.beginPath(); c.moveTo(...B(...a)); c.quadraticCurveTo(a[0] - 14, (a[1] + b[1]) / 2, ...B(...b)); c.stroke(); });
|
|
326
|
+
// 后腿(大腿弧)+腿上条纹
|
|
327
|
+
c.strokeStyle = C.catS; c.lineWidth = 5; [[496, 850, 512, 826], [520, 836, 536, 812], [546, 830, 560, 810], [568, 836, 578, 818]].forEach(([a, b, x2, y2]) => { c.beginPath(); c.moveTo(a, b); c.lineTo(x2, y2); c.stroke(); });
|
|
328
|
+
c.strokeStyle = L; c.lineWidth = 2.6; c.beginPath(); c.moveTo(492, 897); c.bezierCurveTo(484, 830, 552, 796, 598, 852); c.stroke();
|
|
329
|
+
// 两条前腿的分界、前爪趾线
|
|
330
|
+
c.lineWidth = 2.2; c.beginPath(); c.moveTo(631, 792); c.quadraticCurveTo(634, 850, 632, 899); c.stroke();
|
|
331
|
+
c.beginPath(); c.moveTo(604, 800); c.quadraticCurveTo(600, 850, 601, 899); c.stroke();
|
|
332
|
+
c.lineWidth = 1.4; for (const x of [612, 621, 642, 652]) { c.beginPath(); c.moveTo(x, 890); c.lineTo(x, 898); c.stroke(); }
|
|
333
|
+
c.restore();
|
|
334
|
+
c.strokeStyle = L; c.lineWidth = 2.8; c.stroke(body);
|
|
335
|
+
// 后爪(白)
|
|
336
|
+
c.beginPath(); c.ellipse(574, 893, 22, 6.5, 0, 0, 7); c.fillStyle = C.catW; c.fill(); c.lineWidth = 2.2; c.stroke();
|
|
337
|
+
// 头:侧脸、高耸尖耳
|
|
338
|
+
const Hd = (x, y) => [hc[0] + x, hc[1] + y];
|
|
339
|
+
// 耳朵抖:每 ~0.38s 一次 0.1s 的快速一抖(两耳错相),绕耳根中点转
|
|
340
|
+
const twitch = (ph) => { const f = (ch.lt * 2.6 + ph) % 1; return f < 0.26 ? Math.sin(f / 0.26 * Math.PI) : 0; };
|
|
341
|
+
const earRot = (e, a) => { const bx = (e[0][0] + e[2][0]) / 2, by = (e[0][1] + e[2][1]) / 2, cs = Math.cos(a), sn = Math.sin(a); return e.map(([x, y]) => [bx + (x - bx) * cs - (y - by) * sn, by + (x - bx) * sn + (y - by) * cs]); };
|
|
342
|
+
const ear1 = earRot([Hd(-40, -26), Hd(-30, -84), Hd(-8, -36)], -0.38 * twitch(0.1)), ear2 = earRot([Hd(4, -38), Hd(22, -90), Hd(36, -28)], 0.32 * twitch(0.6));
|
|
343
|
+
[ear1, ear2].forEach((e, k) => { poly(c, e); fs(c, C.catO, L, 2.6); poly(c, [[lerp(e[0][0], e[1][0], 0.2) + 4, lerp(e[0][1], e[1][1], 0.2)], [lerp(e[0][0], e[1][0], 0.85) + (k ? 2 : 3), lerp(e[0][1], e[1][1], 0.85) + 4], [lerp(e[2][0], e[1][0], 0.2) - 3, lerp(e[2][1], e[1][1], 0.2)]]); c.fillStyle = '#e99a86'; c.fill(); });
|
|
344
|
+
const head = sm([Hd(-44, 40), Hd(-50, 4), Hd(-38, -30), Hd(-6, -40), Hd(30, -32), Hd(52, -16), Hd(64, 2), Hd(72, 14), Hd(68, 30), Hd(52, 44), Hd(22, 52), Hd(-10, 52)]);
|
|
345
|
+
c.fillStyle = C.catO; c.fill(head);
|
|
346
|
+
c.save(); c.clip(head);
|
|
347
|
+
c.fillStyle = C.catW; c.beginPath(); c.ellipse(...Hd(54, 34), 30, 22, -0.2, 0, 7); c.fill(); c.beginPath(); c.ellipse(...Hd(30, 52), 30, 12, 0, 0, 7); c.fill();
|
|
348
|
+
c.strokeStyle = C.catS; c.lineWidth = 4.5; [[-8, -38, -4, -20], [6, -40, 8, -22], [18, -36, 20, -20], [-34, -6, -18, 0], [-36, 10, -20, 12]].forEach(([a, b, x2, y2]) => { c.beginPath(); c.moveTo(...Hd(a, b)); c.lineTo(...Hd(x2, y2)); c.stroke(); });
|
|
349
|
+
c.restore();
|
|
350
|
+
c.strokeStyle = L; c.lineWidth = 2.8; c.stroke(head);
|
|
351
|
+
// 正面眼(埃及式杏仁大眼+眼线拖尾)
|
|
352
|
+
const e = Hd(32, -8);
|
|
353
|
+
if (K.blink) { c.strokeStyle = L; c.lineWidth = 3; c.beginPath(); c.moveTo(e[0] - 14, e[1]); c.quadraticCurveTo(e[0], e[1] + 5, e[0] + 14, e[1]); c.stroke(); }
|
|
354
|
+
else {
|
|
355
|
+
c.beginPath(); c.moveTo(e[0] - 15, e[1]); c.quadraticCurveTo(e[0], e[1] - 13, e[0] + 15, e[1] - 1); c.quadraticCurveTo(e[0], e[1] + 10, e[0] - 15, e[1]); c.closePath(); fs(c, '#e8cf4a', L, 2.6);
|
|
356
|
+
c.fillStyle = L; c.beginPath(); c.ellipse(e[0] + 2, e[1] - 1, 3, 7, 0, 0, 7); c.fill();
|
|
357
|
+
}
|
|
358
|
+
c.strokeStyle = L; c.lineWidth = 3.4; c.beginPath(); c.moveTo(e[0] - 15, e[1]); c.lineTo(e[0] - 30, e[1] - 3); c.stroke();
|
|
359
|
+
// 鼻、嘴、胡须
|
|
360
|
+
poly(c, [Hd(66, 8), Hd(73, 9), Hd(70, 15)]); c.fillStyle = '#d0706a'; c.fill();
|
|
361
|
+
c.strokeStyle = L; c.lineWidth = 2; c.beginPath(); c.moveTo(...Hd(70, 15)); c.quadraticCurveTo(...Hd(66, 26), ...Hd(58, 28)); c.stroke();
|
|
362
|
+
c.lineWidth = 1.2; [[60, 22, 104, 12], [60, 26, 106, 28], [58, 30, 100, 40]].forEach(([a, b, x2, y2]) => { c.beginPath(); c.moveTo(...Hd(a, b)); c.lineTo(...Hd(x2, y2)); c.stroke(); });
|
|
363
|
+
// 金耳环
|
|
364
|
+
c.strokeStyle = C.gold; c.lineWidth = 3.4; c.beginPath(); c.arc(...Hd(-28, -18), 7, 0.3, 5.9); c.stroke();
|
|
365
|
+
// 彩色项圈(红蓝金)+荷鲁斯之眼坠子
|
|
366
|
+
const clipU = new Path2D(); clipU.addPath(body); clipU.addPath(head);
|
|
367
|
+
c.save(); c.clip(clipU);
|
|
368
|
+
const col = [B(556, 664), B(600, 690), B(652, 694)];
|
|
369
|
+
[[C.gold, 22], [C.red, 16], [C.blue, 9], [C.gold, 3]].forEach(([cc, w]) => { c.strokeStyle = cc; c.lineWidth = w; c.beginPath(); c.moveTo(...col[0]); c.quadraticCurveTo(...col[1], ...col[2]); c.stroke(); });
|
|
370
|
+
c.strokeStyle = L; c.lineWidth = 1.6; for (const s of [-1, 1]) { c.beginPath(); c.moveTo(col[0][0], col[0][1] + s * 11); c.quadraticCurveTo(col[1][0], col[1][1] + s * 11, col[2][0], col[2][1] + s * 11); c.stroke(); }
|
|
371
|
+
c.fillStyle = C.gold; for (let q = 0.1; q < 1; q += 0.12) { const x = (1 - q) * (1 - q) * col[0][0] + 2 * q * (1 - q) * col[1][0] + q * q * col[2][0], y = (1 - q) * (1 - q) * col[0][1] + 2 * q * (1 - q) * col[1][1] + q * q * col[2][1]; c.beginPath(); c.arc(x, y + 15, 3, 0, 7); c.fill(); }
|
|
372
|
+
c.restore();
|
|
373
|
+
const pd = B(640, 742);
|
|
374
|
+
c.strokeStyle = C.goldD; c.lineWidth = 2; c.beginPath(); c.moveTo(col[2][0] - 14, col[2][1] + 8); c.lineTo(pd[0], pd[1] - 14); c.stroke();
|
|
375
|
+
c.beginPath(); c.arc(pd[0], pd[1], 13, 0, 7); fs(c, C.gold, L, 2);
|
|
376
|
+
c.beginPath(); c.moveTo(pd[0] - 8, pd[1]); c.quadraticCurveTo(pd[0], pd[1] - 6, pd[0] + 8, pd[1]); c.quadraticCurveTo(pd[0], pd[1] + 5, pd[0] - 8, pd[1]); fs(c, '#f4f0e4', '#14204a', 1.5);
|
|
377
|
+
c.fillStyle = '#14204a'; c.beginPath(); c.arc(pd[0], pd[1], 2.4, 0, 7); c.fill();
|
|
378
|
+
c.strokeStyle = '#14204a'; c.lineWidth = 1.6; c.beginPath(); c.moveTo(pd[0] - 1, pd[1] + 3); c.lineTo(pd[0] - 3, pd[1] + 9); c.stroke();
|
|
379
|
+
c.restore();
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
// ---------------- 少女:埃及程式(侧脸正面眼、正面双肩、白亚麻长裙、宽领项圈、金发辫) ----------------
|
|
383
|
+
const DY = -25;
|
|
384
|
+
function girl(c, G, ch) {
|
|
385
|
+
const L = C.line, tilt = G.tilt, nk = [1300, 425 + DY], cs = Math.cos(tilt), sn = Math.sin(tilt);
|
|
386
|
+
const HP = (x, y) => { const X = x - nk[0], Y = y + DY - nk[1]; return [nk[0] + X * cs - Y * sn, nk[1] + X * sn + Y * cs]; };
|
|
387
|
+
const TB = (x, y) => [x, y + DY + (y < 600 ? ch.breathe * 150 * (600 - y) / 170 : 0)];
|
|
388
|
+
const T = (x, y) => [x, y + DY];
|
|
389
|
+
c.save(); c.lineJoin = 'round'; c.lineCap = 'round';
|
|
390
|
+
// 躯干(正面化双肩;亚麻半透明:先肤色再罩白)
|
|
391
|
+
const torso = sm([[1270, 466], [1298, 450], [1340, 447], [1420, 454], [1452, 474], [1452, 530], [1440, 590], [1432, 616], [1300, 616], [1288, 560], [1280, 504]].map(p => TB(...p)));
|
|
392
|
+
// 长裙下摆:膝前垂直落到脚踝
|
|
393
|
+
const skirt = sm([[1300, 600], [1238, 620], [1186, 642], [1156, 670], [1145, 724], [1140, 800], [1134, 905], [1262, 905], [1270, 820], [1282, 762], [1330, 754], [1462, 758], [1470, 700], [1452, 640], [1432, 602]].map(p => T(...p)));
|
|
394
|
+
// 脚(赤足,侧面)
|
|
395
|
+
[[1198, 1118], [1170, 1092]].forEach(([hx, tx], k) => { const y0 = 900 - 0; const f = sm([[hx + 10, y0 - 22], [hx + 14, y0 - 6], [hx + 6, y0], [tx + 4, y0], [tx - 2, y0 - 6], [tx + 10, y0 - 12], [hx - 30, y0 - 20]]); c.fillStyle = k ? C.skin : C.skinD; c.fill(f); c.strokeStyle = L; c.lineWidth = 2.2; c.stroke(f); });
|
|
396
|
+
c.fillStyle = C.skin; c.fill(torso);
|
|
397
|
+
c.globalAlpha = 0.9; c.fillStyle = C.white; c.fill(torso); c.fill(skirt); c.globalAlpha = 1;
|
|
398
|
+
// 褶:裙身扇形细褶(从腰往膝、再垂到下摆)
|
|
399
|
+
c.save(); c.clip(skirt); c.strokeStyle = 'rgba(120,96,70,.5)'; c.lineWidth = 1.3;
|
|
400
|
+
for (let i = 0; i <= 26; i++) { const a = i / 26; c.beginPath(); c.moveTo(lerp(1290, 1460, a), 600 + DY); c.bezierCurveTo(lerp(1200, 1460, a), lerp(650, 752, a) + DY, lerp(1150, 1272, a), lerp(700, 790, a) + DY, lerp(1134, 1262, a), 905 + DY); c.stroke(); }
|
|
401
|
+
c.strokeStyle = 'rgba(90,60,40,.55)'; c.lineWidth = 1.8; c.beginPath(); c.moveTo(1170, 686 + DY); c.quadraticCurveTo(1320, 700 + DY, 1462, 742 + DY); c.stroke();
|
|
402
|
+
c.restore();
|
|
403
|
+
c.save(); c.clip(torso); c.strokeStyle = 'rgba(120,96,70,.45)'; c.lineWidth = 1.2;
|
|
404
|
+
for (let x = 1290; x < 1455; x += 9) { c.beginPath(); c.moveTo(x, 470 + DY); c.quadraticCurveTo(x + 6, 540 + DY, x + 2, 620 + DY); c.stroke(); }
|
|
405
|
+
c.fillStyle = 'rgba(255,255,255,.0)'; c.restore();
|
|
406
|
+
c.strokeStyle = L; c.lineWidth = 2.4; c.stroke(skirt); c.stroke(torso);
|
|
407
|
+
// 腰带(红色细带,垂两条带尾)
|
|
408
|
+
c.strokeStyle = C.red; c.lineWidth = 6; c.beginPath(); c.moveTo(...T(1298, 604)); c.quadraticCurveTo(...T(1370, 616), ...T(1440, 606)); c.stroke();
|
|
409
|
+
c.lineWidth = 4; c.beginPath(); c.moveTo(...T(1306, 606)); c.lineTo(...T(1292, 660)); c.moveTo(...T(1316, 607)); c.lineTo(...T(1310, 664)); c.stroke();
|
|
410
|
+
// 宽领项圈(同心色带+水滴坠)
|
|
411
|
+
const cc = TB(1358, 440);
|
|
412
|
+
const bands = [[C.blue, 50, 24], [C.red, 60, 32], [C.green, 70, 40], [C.gold, 80, 48], [C.blue, 88, 55]];
|
|
413
|
+
for (let k = bands.length - 1; k >= 0; k--) { const [col, rx, ry] = bands[k]; c.beginPath(); c.ellipse(cc[0], cc[1], rx + 4, ry + 4, 0.05, 0, Math.PI); c.lineTo(cc[0] - rx - 4, cc[1]); c.fillStyle = col; c.fill(); }
|
|
414
|
+
c.strokeStyle = L; c.lineWidth = 1.2; bands.forEach(([, rx, ry]) => { c.beginPath(); c.ellipse(cc[0], cc[1], rx + 4, ry + 4, 0.05, 0.05, Math.PI - 0.05); c.stroke(); });
|
|
415
|
+
for (let a = 0.12; a < Math.PI - 0.1; a += 0.17) { const x = cc[0] + Math.cos(a) * 99, y = cc[1] + Math.sin(a) * 66; c.save(); c.translate(x, y); c.rotate(a - Math.PI / 2); c.beginPath(); c.moveTo(-4, -6); c.quadraticCurveTo(-5, 4, 0, 7); c.quadraticCurveTo(5, 4, 4, -6); c.closePath(); c.fillStyle = (Math.round(a / 0.17) % 2) ? C.red : C.blue; c.fill(); c.lineWidth = 1; c.stroke(); c.restore(); }
|
|
416
|
+
// 后侧手臂:沿身侧下垂,前臂搭在腿上(金臂环、手镯)
|
|
417
|
+
const sh2 = TB(1446, 478), el2 = T(1452, 612), hd2 = T(1300, 662);
|
|
418
|
+
c.fillStyle = C.skin; c.strokeStyle = L; c.lineWidth = 2.4;
|
|
419
|
+
const ua = RIG.taper(sh2, el2, 36, 28, 4), fa = RIG.taper(el2, hd2, 28, 20, 2);
|
|
420
|
+
c.fill(ua); c.stroke(ua); c.fill(fa); c.stroke(fa);
|
|
421
|
+
const hand2 = sm([[hd2[0] + 14, hd2[1] - 10], [hd2[0] - 14, hd2[1] - 8], [hd2[0] - 36, hd2[1] - 2], [hd2[0] - 38, hd2[1] + 5], [hd2[0] - 10, hd2[1] + 9], [hd2[0] + 14, hd2[1] + 9]]); c.fill(hand2); c.stroke(hand2);
|
|
422
|
+
c.lineWidth = 1.2; for (const s of [-3, 2]) { c.beginPath(); c.moveTo(hd2[0] - 12, hd2[1] + s); c.lineTo(hd2[0] - 34, hd2[1] + s + 2); c.stroke(); }
|
|
423
|
+
const band = (A, B, q, w) => { const x = lerp(A[0], B[0], q), y = lerp(A[1], B[1], q), a = Math.atan2(B[1] - A[1], B[0] - A[0]) + Math.PI / 2; c.strokeStyle = C.gold; c.lineWidth = 8; c.beginPath(); c.moveTo(x + Math.cos(a) * w, y + Math.sin(a) * w); c.lineTo(x - Math.cos(a) * w, y - Math.sin(a) * w); c.stroke(); c.strokeStyle = C.blue; c.lineWidth = 2.5; c.stroke(); };
|
|
424
|
+
band(sh2, el2, 0.32, 19); band(el2, hd2, 0.84, 12);
|
|
425
|
+
// 颈、脸
|
|
426
|
+
const neck = sm([[1286, 400], [1316, 400], [1326, 450], [1288, 452]].map(p => T(...p)));
|
|
427
|
+
c.fillStyle = C.skin; c.fill(neck); c.strokeStyle = L; c.lineWidth = 2.2; c.stroke(neck);
|
|
428
|
+
// 假发:头顶到肩后的金色编发(一束束竖向、分节)
|
|
429
|
+
const wig = sm([[1258, 322], [1266, 298], [1300, 283], [1348, 285], [1388, 304], [1410, 342], [1416, 400], [1422, 470], [1418, 548], [1396, 556], [1372, 548], [1360, 470], [1344, 432], [1328, 404], [1316, 372], [1312, 336], [1290, 324]].map(p => HP(...p)));
|
|
430
|
+
c.fillStyle = '#9a6a18'; c.fill(wig);
|
|
431
|
+
c.save(); c.clip(wig);
|
|
432
|
+
// 一束束竖向编发:每束 = 金色圆头长条+斜向分节(人字纹),末端长短错落
|
|
433
|
+
for (let i = 0; i < 15; i++) {
|
|
434
|
+
const x0 = 1260 + i * 11, yEnd = (i < 5 ? 420 : 560) - (i * 37 % 23);
|
|
435
|
+
const pts = []; for (let y = 284; y <= yEnd; y += 8) pts.push(HP(x0 + (y > 420 ? (y - 420) * 0.06 : 0), y));
|
|
436
|
+
c.strokeStyle = '#7a4e10'; c.lineWidth = 11.5; c.beginPath(); pts.forEach((p, k) => k ? c.lineTo(...p) : c.moveTo(...p)); c.stroke();
|
|
437
|
+
c.strokeStyle = (i % 3 === 1) ? C.goldL : C.gold; c.lineWidth = 8.5; c.stroke();
|
|
438
|
+
c.strokeStyle = '#8a5a12'; c.lineWidth = 1.4;
|
|
439
|
+
for (let k = 1; k < pts.length; k++) { const p = pts[k], side = k % 2 ? 1 : -1; c.beginPath(); c.moveTo(p[0] - 4.2, p[1] - 3 * side); c.lineTo(p[0] + 4.2, p[1] + 3 * side); c.stroke(); }
|
|
440
|
+
}
|
|
441
|
+
c.restore();
|
|
442
|
+
c.strokeStyle = L; c.lineWidth = 2.4; c.stroke(wig);
|
|
443
|
+
// 脸(rig 侧脸轮廓)
|
|
444
|
+
c.fillStyle = C.skin; c.fill(G.face); c.strokeStyle = L; c.lineWidth = 2.4; c.stroke(G.face);
|
|
445
|
+
// 耳+大金耳环
|
|
446
|
+
c.beginPath(); c.ellipse(G.ear[0] - 2, G.ear[1], 7, 11, 0.2, 0, 7); fs(c, C.skin, L, 1.8);
|
|
447
|
+
c.beginPath(); c.arc(G.ear[0] - 2, G.ear[1] + 22, 9, 0, 7); fs(c, C.gold, L, 1.8); c.beginPath(); c.arc(G.ear[0] - 2, G.ear[1] + 22, 3.5, 0, 7); c.fillStyle = C.red; c.fill();
|
|
448
|
+
// 金发箍+后垂带
|
|
449
|
+
const hb = [HP(1260, 314), HP(1300, 300), HP(1352, 302), HP(1398, 324)];
|
|
450
|
+
c.strokeStyle = L; c.lineWidth = 15; c.beginPath(); c.moveTo(...hb[0]); c.bezierCurveTo(...hb[1], ...hb[2], ...hb[3]); c.stroke();
|
|
451
|
+
c.strokeStyle = C.gold; c.lineWidth = 11; c.stroke(); c.strokeStyle = C.goldL; c.lineWidth = 3; c.stroke();
|
|
452
|
+
const kn = HP(1402, 326), kt = HP(1440, 392), kt2 = HP(1430, 410);
|
|
453
|
+
poly(c, [kn, kt, kt2, HP(1396, 340)]); fs(c, C.gold, L, 1.8);
|
|
454
|
+
c.fillStyle = C.blue; c.beginPath(); c.arc(...HP(1262, 314), 5, 0, 7); c.fill();
|
|
455
|
+
// 正面眼(杏仁形、黑眼线拖尾、长眉)
|
|
456
|
+
const ex = G.eye.x + 2, ey = G.eye.y;
|
|
457
|
+
if (ch.blink) { c.strokeStyle = L; c.lineWidth = 3; c.beginPath(); c.moveTo(ex - 11, ey); c.quadraticCurveTo(ex, ey + 4, ex + 12, ey); c.stroke(); }
|
|
458
|
+
else {
|
|
459
|
+
c.beginPath(); c.moveTo(ex - 11, ey); c.quadraticCurveTo(ex, ey - 9, ex + 12, ey - 1); c.quadraticCurveTo(ex, ey + 6, ex - 11, ey); c.closePath(); fs(c, '#fbf7ee', null);
|
|
460
|
+
c.fillStyle = '#1a120c'; c.beginPath(); c.arc(ex - 1, ey - 1.5, 4.2, 0, 7); c.fill();
|
|
461
|
+
}
|
|
462
|
+
c.strokeStyle = '#140c08'; c.lineWidth = 3.2; c.beginPath(); c.moveTo(ex - 12, ey); c.quadraticCurveTo(ex, ey - 10, ex + 12, ey - 1); c.lineTo(ex + 30, ey - 3); c.stroke();
|
|
463
|
+
c.lineWidth = 1.8; c.beginPath(); c.moveTo(ex - 10, ey + 1); c.quadraticCurveTo(ex, ey + 6, ex + 14, ey + 1); c.stroke();
|
|
464
|
+
c.lineWidth = 3; c.beginPath(); c.moveTo(ex - 12, ey - 12); c.quadraticCurveTo(ex + 4, ey - 19, ex + 26, ey - 12); c.stroke();
|
|
465
|
+
// 唇
|
|
466
|
+
c.fillStyle = '#b6443a'; c.beginPath(); c.moveTo(...G.lips[0]); c.lineTo(...G.lips[1]); c.lineTo(...G.lips[2]); c.closePath(); c.fill();
|
|
467
|
+
// 近侧手臂:从前肩抬到嘴边端杯(自己的 IK,肘向下垂)
|
|
468
|
+
// 手托在杯身下(握杯脚),而不是 rig 默认的杯侧:肘才能像设定稿那样垂到胸前
|
|
469
|
+
const cpp = G.cup, hd = [cpp.x + 4 - Math.sin(cpp.tilt) * 40, cpp.y + Math.cos(cpp.tilt) * 42];
|
|
470
|
+
const sh = TB(1282, 476);
|
|
471
|
+
const { E } = RIG.ik2(sh, hd, 140, 160, -1);
|
|
472
|
+
const ua1 = RIG.taper(sh, E, 38, 30, 4), fa1 = RIG.taper(E, hd, 30, 22, 2);
|
|
473
|
+
c.fillStyle = C.skin; c.strokeStyle = L; c.lineWidth = 2.4; c.fill(ua1); c.stroke(ua1); c.fill(fa1); c.stroke(fa1);
|
|
474
|
+
band(sh, E, 0.4, 19); band(E, hd, 0.8, 13);
|
|
475
|
+
// 蓝色莲花杯
|
|
476
|
+
const cp = G.cup;
|
|
477
|
+
c.save(); c.translate(cp.x, cp.y); c.rotate(cp.tilt);
|
|
478
|
+
c.beginPath(); c.moveTo(-26, 0); c.quadraticCurveTo(-22, 26, -5, 34); c.lineTo(-4, 44); c.quadraticCurveTo(-14, 46, -14, 50); c.lineTo(14, 50); c.quadraticCurveTo(14, 46, 4, 44); c.lineTo(5, 34); c.quadraticCurveTo(22, 26, 26, 0); c.closePath(); fs(c, '#2f62c4', L, 2.2);
|
|
479
|
+
c.strokeStyle = '#8ab8f0'; c.lineWidth = 1.6; [[-14, 2, -4, 30], [0, 1, 0, 32], [14, 2, 4, 30]].forEach(([a, b, x2, y2]) => { c.beginPath(); c.moveTo(a, b); c.quadraticCurveTo((a + x2) / 2 + (a < 0 ? -4 : a > 0 ? 4 : 0), 18, x2, y2); c.stroke(); });
|
|
480
|
+
c.beginPath(); c.ellipse(0, 0, 26, 4.5, 0, 0, 7); fs(c, '#1c3f8a', L, 1.8);
|
|
481
|
+
c.restore();
|
|
482
|
+
// 手:握杯
|
|
483
|
+
const hf = sm([[hd[0] - 20, hd[1] - 4], [hd[0] - 8, hd[1] - 10], [hd[0] + 10, hd[1] - 8], [hd[0] + 16, hd[1] + 6], [hd[0] + 2, hd[1] + 14], [hd[0] - 18, hd[1] + 6]]);
|
|
484
|
+
c.fillStyle = C.skin; c.fill(hf); c.strokeStyle = L; c.lineWidth = 2.2; c.stroke(hf);
|
|
485
|
+
c.lineWidth = 1.2; for (const s of [-4, 2]) { c.beginPath(); c.moveTo(hd[0] - 18, hd[1] + s); c.lineTo(hd[0] - 4, hd[1] + s + 1); c.stroke(); }
|
|
486
|
+
c.restore();
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
return {
|
|
490
|
+
init() { P.cached('eg_static', W, H, staticLayer); surface(); specks(); },
|
|
491
|
+
draw(c, lt, t) {
|
|
492
|
+
const ch = P.choreo(lt, t);
|
|
493
|
+
c.drawImage(P.cached('eg_static', W, H, staticLayer), 0, 0);
|
|
494
|
+
// 水纹象形字:zigzag 相位流动(12fps 步进,像手绘逐张)
|
|
495
|
+
const wp = Math.floor(lt * 12) * 0.5; // 每 1/12s 走半个齿,4 步一循环(0.33s)
|
|
496
|
+
GLYPHS.forEach(q => { if (GL[q.n].water) drawGlyph(c, q, wp + q.ph); });
|
|
497
|
+
rays(c, lt, t);
|
|
498
|
+
writeGlyphs(c, lt);
|
|
499
|
+
ch.lt = lt;
|
|
500
|
+
const K = RIG.cat({ tail: ch.tail * 2.1 + 0.25 * Math.sin(t * 9.5), blink: ch.blink, breathe: ch.breathe, dy: -5 });
|
|
501
|
+
cat(c, K, ch);
|
|
502
|
+
// 两条长光线要压在猫上
|
|
503
|
+
c.save(); c.lineCap = 'round';
|
|
504
|
+
LONG.forEach(([x, y, k]) => {
|
|
505
|
+
const wx = x + Math.sin(t * 7 + k * 1.3) * 3, wy = y + Math.cos(t * 6 + k) * 2, ang = Math.atan2(wy - DISK[1], wx - DISK[0]);
|
|
506
|
+
c.strokeStyle = '#c23a2a'; c.lineWidth = 2.6; c.beginPath(); c.moveTo(lerp(DISK[0], wx, 0.62), lerp(DISK[1], wy, 0.62)); c.lineTo(wx - Math.cos(ang) * 6, wy - Math.sin(ang) * 6); c.stroke();
|
|
507
|
+
handAt(c, wx, wy, ang, 0.5 + 0.5 * Math.sin(lt * Math.PI * 2 / 0.4 + k * 0.9)); // 开合幅度在 handAt 里已放大
|
|
508
|
+
drawGlyph(c, { n: 'ankh', x: wx + Math.cos(ang) * 16, y: wy + Math.sin(ang) * 16 + 4, s: 0.36, col: C.blue });
|
|
509
|
+
});
|
|
510
|
+
c.restore();
|
|
511
|
+
// 少女:杯基本一直在嘴边(原片如此),choreo 的举杯只走最后一小段+小口啜饮
|
|
512
|
+
// 端杯:先按 choreo 举到嘴边;lt>0.35 起每 0.6s 一个循环:杯离嘴下放(cup 1→0.62)再举回,杯在嘴边时仰头大口喝(倾角到 ~0.2rad)
|
|
513
|
+
let cupV = lerp(0.8, 1, ch.cup), sipV = ch.sip;
|
|
514
|
+
if (lt > 0.35) { const u = (lt - 0.35) / 0.6; cupV = 1 - 0.46 * (1 - Math.cos(u * Math.PI * 2)) / 2; }
|
|
515
|
+
sipV += 0.3 * clamp((cupV - 0.78) / 0.22) * (0.65 + 0.35 * Math.sin(lt * 13));
|
|
516
|
+
const G = RIG.girl({ cup: cupV, sip: sipV, breathe: ch.breathe, dy: DY, hair: 'down' });
|
|
517
|
+
girl(c, G, ch);
|
|
518
|
+
scarab(c, lt);
|
|
519
|
+
// 壁画表面:斑驳 multiply + 颗粒
|
|
520
|
+
c.save(); c.globalCompositeOperation = 'multiply'; c.drawImage(surface(), 0, 0); c.restore();
|
|
521
|
+
c.drawImage(specks(), 0, 0);
|
|
522
|
+
},
|
|
523
|
+
};
|
|
524
|
+
})();
|