@biunow/agent-biuart 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/server.mjs +575 -0
- package/data/styles.json +533 -0
- package/engine/audit_clip.py +46 -0
- package/engine/clip.html +24 -0
- package/engine/clip.js +104 -0
- package/engine/clip_schema.json +19 -0
- package/engine/clips/t1_3b1b.js +203 -0
- package/engine/clips/t2_keynote_ui.js +347 -0
- package/engine/clips/t3_finance_chart.js +206 -0
- package/engine/clips/y1_kurzgesagt.js +183 -0
- package/engine/clips/y2_vox.js +150 -0
- package/engine/clips/y3_whiteboard.js +209 -0
- package/engine/clips/y4_storytime.js +194 -0
- package/engine/clips/y5_kinetic_type.js +134 -0
- package/engine/compare.py +19 -0
- package/engine/demos/_shared/hero/c1_0.png +0 -0
- package/engine/demos/_shared/hero/c1_1.png +0 -0
- package/engine/demos/_shared/hero/c1_2.png +0 -0
- package/engine/demos/_shared/hero/c3_line.png +0 -0
- package/engine/demos/_shared/hero.js +96 -0
- package/engine/demos/long_scroll/eras.js +23 -0
- package/engine/demos/long_scroll/frames/8bit_act/01.png +0 -0
- package/engine/demos/long_scroll/frames/8bit_act/02.png +0 -0
- package/engine/demos/long_scroll/frames/8bit_act/03.png +0 -0
- package/engine/demos/long_scroll/frames/8bit_act/04.png +0 -0
- package/engine/demos/long_scroll/frames/8bit_act/05.png +0 -0
- package/engine/demos/long_scroll/frames/8bit_act/06.png +0 -0
- package/engine/demos/long_scroll/frames/8bit_act/07.png +0 -0
- package/engine/demos/long_scroll/frames/8bit_act/08.png +0 -0
- package/engine/demos/long_scroll/frames/8bit_act/meta.json +69 -0
- package/engine/demos/long_scroll/frames/8bit_walk/01.png +0 -0
- package/engine/demos/long_scroll/frames/8bit_walk/02.png +0 -0
- package/engine/demos/long_scroll/frames/8bit_walk/03.png +0 -0
- package/engine/demos/long_scroll/frames/8bit_walk/04.png +0 -0
- package/engine/demos/long_scroll/frames/8bit_walk/05.png +0 -0
- package/engine/demos/long_scroll/frames/8bit_walk/06.png +0 -0
- package/engine/demos/long_scroll/frames/8bit_walk/07.png +0 -0
- package/engine/demos/long_scroll/frames/8bit_walk/08.png +0 -0
- package/engine/demos/long_scroll/frames/8bit_walk/meta.json +69 -0
- package/engine/demos/long_scroll/frames/egypt_dodge/01.png +0 -0
- package/engine/demos/long_scroll/frames/egypt_dodge/02.png +0 -0
- package/engine/demos/long_scroll/frames/egypt_dodge/03.png +0 -0
- package/engine/demos/long_scroll/frames/egypt_dodge/04.png +0 -0
- package/engine/demos/long_scroll/frames/egypt_dodge/05.png +0 -0
- package/engine/demos/long_scroll/frames/egypt_dodge/06.png +0 -0
- package/engine/demos/long_scroll/frames/egypt_dodge/07.png +0 -0
- package/engine/demos/long_scroll/frames/egypt_dodge/08.png +0 -0
- package/engine/demos/long_scroll/frames/egypt_dodge/meta.json +69 -0
- package/engine/demos/long_scroll/frames/egypt_walk8/01.png +0 -0
- package/engine/demos/long_scroll/frames/egypt_walk8/02.png +0 -0
- package/engine/demos/long_scroll/frames/egypt_walk8/03.png +0 -0
- package/engine/demos/long_scroll/frames/egypt_walk8/04.png +0 -0
- package/engine/demos/long_scroll/frames/egypt_walk8/05.png +0 -0
- package/engine/demos/long_scroll/frames/egypt_walk8/06.png +0 -0
- package/engine/demos/long_scroll/frames/egypt_walk8/07.png +0 -0
- package/engine/demos/long_scroll/frames/egypt_walk8/08.png +0 -0
- package/engine/demos/long_scroll/frames/egypt_walk8/meta.json +69 -0
- package/engine/demos/long_scroll/frames/monet_throw/01.png +0 -0
- package/engine/demos/long_scroll/frames/monet_throw/02.png +0 -0
- package/engine/demos/long_scroll/frames/monet_throw/03.png +0 -0
- package/engine/demos/long_scroll/frames/monet_throw/04.png +0 -0
- package/engine/demos/long_scroll/frames/monet_throw/05.png +0 -0
- package/engine/demos/long_scroll/frames/monet_throw/06.png +0 -0
- package/engine/demos/long_scroll/frames/monet_throw/07.png +0 -0
- package/engine/demos/long_scroll/frames/monet_throw/08.png +0 -0
- package/engine/demos/long_scroll/frames/monet_throw/meta.json +71 -0
- package/engine/demos/long_scroll/frames/monet_walk/01.png +0 -0
- package/engine/demos/long_scroll/frames/monet_walk/02.png +0 -0
- package/engine/demos/long_scroll/frames/monet_walk/03.png +0 -0
- package/engine/demos/long_scroll/frames/monet_walk/04.png +0 -0
- package/engine/demos/long_scroll/frames/monet_walk/05.png +0 -0
- package/engine/demos/long_scroll/frames/monet_walk/06.png +0 -0
- package/engine/demos/long_scroll/frames/monet_walk/07.png +0 -0
- package/engine/demos/long_scroll/frames/monet_walk/08.png +0 -0
- package/engine/demos/long_scroll/frames/monet_walk/meta.json +71 -0
- package/engine/demos/long_scroll/lib/acts.js +87 -0
- package/engine/demos/long_scroll/lib/crossing.js +463 -0
- package/engine/demos/long_scroll/lib/world.js +143 -0
- package/engine/demos/long_scroll/lib/xing2_ding.js +42 -0
- package/engine/demos/long_scroll/lib/xing2_jia.js +114 -0
- package/engine/demos/long_scroll/lib/xing2_yi.js +133 -0
- package/engine/demos/long_scroll/segments/02_egypt.js +234 -0
- package/engine/demos/long_scroll/segments/14_8bit.js +118 -0
- package/engine/demos/long_scroll/segments/28_monet.js +86 -0
- package/engine/demos/t1_3b1b/eras.js +11 -0
- package/engine/demos/t1_3b1b/t1_s1.js +101 -0
- package/engine/demos/t1_3b1b/t1_s2.js +74 -0
- package/engine/demos/t1_3b1b/t1_s3.js +65 -0
- package/engine/demos/t2_keynote_ui/eras.js +10 -0
- package/engine/demos/t2_keynote_ui/t2_s1.js +57 -0
- package/engine/demos/t2_keynote_ui/t2_s2.js +70 -0
- package/engine/demos/t2_keynote_ui/t2_s3.js +61 -0
- package/engine/demos/t3_finance_chart/eras.js +11 -0
- package/engine/demos/t3_finance_chart/t3_s1.js +48 -0
- package/engine/demos/t3_finance_chart/t3_s2.js +42 -0
- package/engine/demos/t3_finance_chart/t3_s3.js +51 -0
- package/engine/demos/y1_kurzgesagt/eras.js +10 -0
- package/engine/demos/y1_kurzgesagt/kurzgesagt.js +347 -0
- package/engine/demos/y2_vox/eras.js +10 -0
- package/engine/demos/y2_vox/vox.js +240 -0
- package/engine/demos/y3_whiteboard/eras.js +10 -0
- package/engine/demos/y3_whiteboard/whiteboard.js +162 -0
- package/engine/demos/y4_storytime/eras.js +14 -0
- package/engine/demos/y4_storytime/s1_desk.js +18 -0
- package/engine/demos/y4_storytime/s2_screen.js +82 -0
- package/engine/demos/y4_storytime/s3_react.js +39 -0
- package/engine/demos/y4_storytime/s4_wide.js +16 -0
- package/engine/demos/y4_storytime/s5_close.js +18 -0
- package/engine/demos/y4_storytime/story.js +25 -0
- package/engine/demos/y4_storytime/vo_env.js +2 -0
- package/engine/demos/y4_storytime/world.js +73 -0
- package/engine/demos/y5_kinetic_type/eras.js +16 -0
- package/engine/demos/y5_kinetic_type/k1_title.js +38 -0
- package/engine/demos/y5_kinetic_type/k2_complete.js +55 -0
- package/engine/demos/y5_kinetic_type/k3_chat.js +47 -0
- package/engine/demos/y5_kinetic_type/k4_agent.js +49 -0
- package/engine/demos/y5_kinetic_type/kinetic.js +52 -0
- package/engine/engine.js +277 -0
- package/engine/eras.js +60 -0
- package/engine/eras_gallery.js +115 -0
- package/engine/eras_style_studies.js +20 -0
- package/engine/examples/assets/K/347/272/277/345/233/276_/346/250/252/345/261/217.png +0 -0
- package/engine/examples/assets//347/273/210/347/253/257_for/345/276/252/347/216/257/346/261/202/345/222/214.png +0 -0
- package/engine/examples/assets//347/273/210/347/253/257_sum/346/261/202/345/222/214.png +0 -0
- package/engine/examples/assets//350/220/245/346/224/266/345/233/276_/347/253/226/345/261/217.png +0 -0
- package/engine/examples/assets//350/264/242/347/273/217/345/233/276/350/241/250_/346/250/252/345/261/217.png +0 -0
- package/engine/examples/t1_3b1b.json +19 -0
- package/engine/examples/t2_fullbleed_pulse.json +15 -0
- package/engine/examples/t2_keynote_ui.json +15 -0
- package/engine/examples/t3_finance_chart.json +29 -0
- package/engine/examples/y1_kurzgesagt.json +16 -0
- package/engine/examples/y2_vox.json +14 -0
- package/engine/examples/y3_whiteboard.json +17 -0
- package/engine/examples/y4_storytime.json +52 -0
- package/engine/examples/y5_kinetic_type.json +14 -0
- package/engine/index.html +42 -0
- package/engine/lib/THREE_LICENSE.txt +21 -0
- package/engine/lib/brush.js +149 -0
- package/engine/lib/camera.js +99 -0
- package/engine/lib/chart.js +152 -0
- package/engine/lib/collage.js +97 -0
- package/engine/lib/diagram.js +264 -0
- package/engine/lib/finish.js +70 -0
- package/engine/lib/fonts/AlfaSlabOne-400.woff +0 -0
- package/engine/lib/fonts/Anton-400.woff +0 -0
- package/engine/lib/fonts/ArchivoBlack-400.woff +0 -0
- package/engine/lib/fonts/Bangers-400.woff +0 -0
- package/engine/lib/fonts/Caveat-600.woff +0 -0
- package/engine/lib/fonts/Cinzel-400.woff +0 -0
- package/engine/lib/fonts/Cinzel-700.woff +0 -0
- package/engine/lib/fonts/CormorantGaramond-500.woff +0 -0
- package/engine/lib/fonts/CormorantGaramond-500i.woff +0 -0
- package/engine/lib/fonts/CormorantGaramond-700.woff +0 -0
- package/engine/lib/fonts/EBGaramond-400.woff +0 -0
- package/engine/lib/fonts/EBGaramond-400i.woff +0 -0
- package/engine/lib/fonts/EBGaramond-600.woff +0 -0
- package/engine/lib/fonts/Exo2-800i.woff +0 -0
- package/engine/lib/fonts/GochiHand-400.woff +0 -0
- package/engine/lib/fonts/IMFellEnglish-400.woff +0 -0
- package/engine/lib/fonts/IMFellEnglish-400i.woff +0 -0
- package/engine/lib/fonts/Inter-var.woff +0 -0
- package/engine/lib/fonts/JosefinSans-700.woff +0 -0
- package/engine/lib/fonts/Kalam-700.woff +0 -0
- package/engine/lib/fonts/LICENSES.md +40 -0
- package/engine/lib/fonts/LXGWWenKai-500.woff +0 -0
- package/engine/lib/fonts/LibreBaskerville-400.woff +0 -0
- package/engine/lib/fonts/LibreBaskerville-700.woff +0 -0
- package/engine/lib/fonts/LilitaOne-400.woff +0 -0
- package/engine/lib/fonts/Marcellus-400.woff +0 -0
- package/engine/lib/fonts/NotoSansSC-500.woff +0 -0
- package/engine/lib/fonts/NotoSansSC-700.woff +0 -0
- package/engine/lib/fonts/NotoSansSC-800.woff +0 -0
- package/engine/lib/fonts/NotoSansSC-900.woff +0 -0
- package/engine/lib/fonts/NotoSansSC-sub.woff +0 -0
- package/engine/lib/fonts/NotoSerifJP-600.woff +0 -0
- package/engine/lib/fonts/NotoSerifSC-sub.woff +0 -0
- package/engine/lib/fonts/OFL.txt +94 -0
- package/engine/lib/fonts/PlayfairDisplay-400i.woff +0 -0
- package/engine/lib/fonts/PlayfairDisplay-700.woff +0 -0
- package/engine/lib/fonts/PlayfairDisplay-700i.woff +0 -0
- package/engine/lib/fonts/Poppins-600.woff +0 -0
- package/engine/lib/fonts/Poppins-700.woff +0 -0
- package/engine/lib/fonts/Poppins-800.woff +0 -0
- package/engine/lib/fonts/PressStart2P-400.woff +0 -0
- package/engine/lib/fonts/Righteous-400.woff +0 -0
- package/engine/lib/fonts/RobotoCondensed-var.woff +0 -0
- package/engine/lib/fonts/Rye-400.woff +0 -0
- package/engine/lib/fonts/UnifrakturMaguntia-400.woff +0 -0
- package/engine/lib/fonts/cmunrm.woff +0 -0
- package/engine/lib/fonts/cmunti.woff +0 -0
- package/engine/lib/fonts/index.json +1 -0
- package/engine/lib/fonts.js +56 -0
- package/engine/lib/kit.js +91 -0
- package/engine/lib/media.js +118 -0
- package/engine/lib/medium.js +258 -0
- package/engine/lib/motion.js +111 -0
- package/engine/lib/paint.js +200 -0
- package/engine/lib/palettes.js +57 -0
- package/engine/lib/post.js +108 -0
- package/engine/lib/render.js +189 -0
- package/engine/lib/rig.js +390 -0
- package/engine/lib/rig_huashu.js +171 -0
- package/engine/lib/three.min.js +7 -0
- package/engine/lib/toon.js +186 -0
- package/engine/lib/typo.js +136 -0
- package/engine/lib/ui.js +141 -0
- package/engine/lib/util.js +92 -0
- package/engine/render.py +157 -0
- package/engine/scenes/01_cave.js +364 -0
- package/engine/scenes/02_egypt.js +524 -0
- package/engine/scenes/03_greek.js +448 -0
- package/engine/scenes/04_roman.js +555 -0
- package/engine/scenes/05_gothic.js +522 -0
- package/engine/scenes/06_renaissance.js +338 -0
- package/engine/scenes/08_impressionism.js +206 -0
- package/engine/scenes/09_postimp.js +183 -0
- package/engine/scenes/10_nouveau.js +334 -0
- package/engine/scenes/11_cubism.js +265 -0
- package/engine/scenes/12_bauhaus.js +214 -0
- package/engine/scenes/13_pop.js +269 -0
- package/engine/scenes/14_8bit.js +238 -0
- package/engine/scenes/15_raytrace.js +300 -0
- package/engine/scenes/16_2026.js +565 -0
- package/engine/scenes/17_ink.js +273 -0
- package/engine/scenes/18_klimt.js +227 -0
- package/engine/scenes/19_munch.js +153 -0
- package/engine/scenes/20_dunhuang.js +215 -0
- package/engine/scenes/21_kusama.js +124 -0
- package/engine/scenes/22_constructivism.js +205 -0
- package/engine/scenes/23_dali.js +221 -0
- package/engine/scenes/24_hopper.js +150 -0
- package/engine/scenes/25_ghibli.js +251 -0
- package/engine/scenes/26_vaporwave.js +191 -0
- package/engine/scenes/27_kirby.js +255 -0
- package/engine/scenes/28_monet.js +176 -0
- package/engine/scenes/29_seurat.js +104 -0
- package/engine/scenes/30_matisse.js +151 -0
- package/engine/scenes/31_haring.js +109 -0
- package/engine/scenes/32_rembrandt.js +217 -0
- package/engine/scenes/33_rubberhose.js +219 -0
- package/engine/scenes/34_shadowpuppet.js +195 -0
- package/engine/scenes/35_shinkai.js +197 -0
- package/engine/scenes/36_picasso_blue.js +123 -0
- package/engine/scenes/38_giotto.js +133 -0
- package/engine/scenes/39_piero.js +53 -0
- package/engine/scenes/40_raphael.js +96 -0
- package/engine/scenes/41_michelangelo.js +112 -0
- package/engine/scenes/42_guardi.js +70 -0
- package/engine/scenes/43_lorenzetti.js +145 -0
- package/engine/scenes/44_cortona.js +86 -0
- package/engine/scenes/45_renoir.js +86 -0
- package/engine/scenes/46_pissarro.js +82 -0
- package/engine/scenes/47_sisley.js +94 -0
- package/engine/scenes/48_gauguin.js +107 -0
- package/engine/scenes/49_chagall.js +60 -0
- package/engine/scenes/50_ma_yuan.js +131 -0
- package/engine/scenes/51_persian_miniature.js +149 -0
- package/engine/scenes/52_south_park.js +105 -0
- package/engine/scenes/53_pixar.js +60 -0
- package/engine/scenes/54_ghibli_lab.js +68 -0
- package/engine/scenes/55_dunhuang.js +161 -0
- package/engine/scenes/index.js +28 -0
- package/engine/spec_assets.py +76 -0
- package/engine/transitions.js +929 -0
- package/engine//346/227/266/344/273/243/344/275/234/350/200/205/350/247/204/350/214/203.md +49 -0
- package/lib/host.mjs +754 -0
- package/lib/render-bridge.mjs +543 -0
- package/lib/render-cli.mjs +98 -0
- package/lib/storyboard-lint.mjs +54 -0
- package/manifest.json +52 -0
- package/package.json +8 -4
- package/runtime/package.json +8 -0
- package/skills/biuart/SKILL.md +154 -0
- package/skills/biuart/references/01-/346/213/206/350/247/243.md +55 -0
- package/skills/biuart/references/02-/346/234/272/345/210/266.md +41 -0
- package/skills/biuart/references/03-/344/270/200/345/270/247/345/205/210/350/241/214/345/233/233/346/235/241/350/267/257/347/272/277.md +39 -0
- package/skills/biuart/references/04-/347/272/257/344/273/243/347/240/201/347/273/230/345/210/266.md +92 -0
- package/skills/biuart/references/05-/350/212/202/345/245/217/344/270/216/351/205/215/344/271/220.md +19 -0
- package/skills/biuart/references/06-/345/217/243/346/222/255/351/251/261/345/212/250/347/232/204/350/211/272/346/234/257/347/237/255/347/211/207.md +31 -0
- package/skills/biuart/references/07-/346/255/243/351/235/242/347/273/217/351/252/214.md +196 -0
- package/skills/biuart/references/08-/351/243/216/346/240/274/344/275/234/350/200/205/350/247/204/350/214/203.md +61 -0
- package/skills/biuart/references/09-/350/247/206/351/242/221/345/212/250/347/224/273/350/257/255/346/263/225.md +382 -0
- package/skills/biuart/references/10-/350/247/222/350/211/262.md +34 -0
- package/skills/biuart/references/11-/351/225/277/345/215/267/347/251/277/350/266/212/347/211/207.md +43 -0
- package/skills/biuart/references/12-/345/217/243/346/222/255/346/225/264/347/211/207/344/270/216/347/273/217/351/252/214/345/233/236/346/265/201.md +25 -0
- package/skills/biuart/references/13-/345/217/243/346/222/255/344/270/216/350/257/255/351/237/263/345/244/215/345/210/273.md +7 -0
- package/skills/biuart/references/15-/350/267/250/345/234/272/346/231/257/351/243/216/346/240/274/346/217/220/347/202/274.md +48 -0
- package/skills/biuart/references/16-/351/243/216/346/240/274/346/274/224/347/244/27295/345/210/206/345/215/217/350/256/256.md +103 -0
- package/skills/biuart/references/about-author.md +99 -0
- package/skills/biuart/references/capabilities.md +91 -0
- package/skills/biuart/references/compatibility.md +34 -0
- package/skills/biuart/references/images.md +97 -0
- package/skills/biuart/references/voice-model-review.md +18 -0
- package/skills/biuart/references//345/212/250/347/224/273/350/257/255/346/263/225/t1_3b1b.md +122 -0
- package/skills/biuart/references//345/212/250/347/224/273/350/257/255/346/263/225/t2_keynote_ui.md +117 -0
- package/skills/biuart/references//345/212/250/347/224/273/350/257/255/346/263/225/t3_finance_chart.md +116 -0
- package/skills/biuart/references//345/212/250/347/224/273/350/257/255/346/263/225/y1_kurzgesagt.md +193 -0
- package/skills/biuart/references//345/212/250/347/224/273/350/257/255/346/263/225/y2_vox.md +195 -0
- package/skills/biuart/references//345/212/250/347/224/273/350/257/255/346/263/225/y3_whiteboard.md +190 -0
- package/skills/biuart/references//345/212/250/347/224/273/350/257/255/346/263/225/y4_storytime.md +166 -0
- package/skills/biuart/references//345/212/250/347/224/273/350/257/255/346/263/225/y5_kinetic_type.md +158 -0
- package/skills/biuart/references//345/212/250/347/224/273/350/257/255/346/263/225/y6_presenter_explainer.md +24 -0
- package/skills/biuart/references//345/217/243/346/222/255API.md +125 -0
- package/skills/biuart/references//350/211/262/346/235/277.md +38 -0
- package/skills/biuart/references//350/247/222/350/211/262/347/262/276/347/273/206/345/272/246.md +61 -0
- package/skills/biuart/references//351/225/234/345/244/264/350/241/250/346/250/241/346/235/277.md +80 -0
- package/skills/biuart/references//351/225/234/345/244/264/350/257/255/350/250/200.md +73 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/01_cave.md +46 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/02_egypt.md +64 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/03_greek.md +50 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/04_roman.md +99 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/05_gothic.md +32 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/06_renaissance.md +41 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/08_impressionism.md +34 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/09_postimp.md +17 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/10_nouveau.md +31 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/11_cubism.md +30 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/12_bauhaus.md +30 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/13_pop.md +29 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/14_8bit.md +27 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/15_raytrace.md +32 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/16_2026.md +55 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/17_ink.md +50 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/18_klimt.md +37 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/19_munch.md +42 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/20_dunhuang.md +49 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/21_kusama.md +32 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/22_constructivism.md +35 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/23_dali.md +29 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/24_hopper.md +30 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/25_ghibli.md +55 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/26_vaporwave.md +27 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/27_kirby.md +30 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/28_monet.md +39 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/29_seurat.md +31 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/30_matisse.md +26 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/31_haring.md +22 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/32_rembrandt.md +29 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/33_rubberhose.md +31 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/34_shadowpuppet.md +40 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/35_shinkai.md +34 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/36_picasso_blue.md +25 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/37_rick_morty.md +48 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/38_giotto.md +67 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/39_piero.md +59 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/40_raphael.md +65 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/41_michelangelo.md +65 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/42_guardi.md +65 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/43_lorenzetti.md +69 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/44_cortona.md +66 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/45_renoir.md +66 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/46_pissarro.md +66 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/47_sisley.md +67 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/48_gauguin.md +66 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/49_chagall.md +59 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/50_ma_yuan.md +68 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/51_persian_miniature.md +66 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/52_south_park.md +65 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/53_pixar.md +61 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/55_dunhuang.md +41 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/INDEX.md +89 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/_/350/275/254/345/234/272_/350/277/201/347/247/273/346/265/213/350/257/225.md +53 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/_/351/207/215/345/201/232/350/277/233/345/272/246.md +37 -0
- package/skills/biuart/references//351/243/216/346/240/274/351/205/215/346/226/271/_/351/237/263/350/275/250_/350/211/272/346/234/257/345/217/262/351/200/237/351/200/232.md +135 -0
- package/studio/app.js +380 -0
- package/studio/assert-panel-permit.mjs +67 -0
- package/studio/composer.css +465 -0
- package/studio/composer.js +480 -0
- package/studio/index.html +97 -0
- package/studio/optimize-prompt.mjs +84 -0
- package/studio/optimize-prompt.test.mjs +47 -0
- package/studio/recipes.mjs +87 -0
- package/studio/select-menu.js +450 -0
- package/studio/styles.css +71 -0
- package/studio/to-english-prompt.mjs +149 -0
- package/studio/to-english-prompt.test.mjs +72 -0
- package/README.md +0 -3
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
// t1 · 镜头 2(2.8s):一层网络。连线按权重着色(蓝正红负、线宽 ∝ |w|³)逐条画出 → 公式 Write →
|
|
2
|
+
// 黄色信号沿连线闪过(ShowPassingFlash)→ 隐藏层按激活值变亮 → 输出层「猫」最亮 → Indicate → 激活 0.95 的隐藏神经元描边染黄,镜头推进它。
|
|
3
|
+
// 开头一帧与镜头 1 的最后一帧逐像素相同(Transform 接续,没有切)。
|
|
4
|
+
(() => {
|
|
5
|
+
const { clamp, lerp } = U;
|
|
6
|
+
const C = DG.MANIM;
|
|
7
|
+
const DUR = 2.8;
|
|
8
|
+
const CAM_END = { x: 1000, y: 500, z: 1.1 };
|
|
9
|
+
const TGT = { k: 2 }; // 要推进去看的隐藏层神经元(激活 0.95 的那个)
|
|
10
|
+
const camAt = lt => {
|
|
11
|
+
if (lt <= DUR) { const k = MO.smooth(clamp(lt / DUR)); return { x: lerp(960, CAM_END.x, k), y: lerp(540, CAM_END.y, k), z: lerp(1, CAM_END.z, k) }; }
|
|
12
|
+
// 转场期间(lt>时长):绕目标神经元的屏幕位置继续推相机,矢量重画;与 eras.js 里 zoomThrough 的 dur/zoom 一致
|
|
13
|
+
const T = window.T1, wx = T.HID_X, wy = T.hidY(TGT.k);
|
|
14
|
+
const tr = ERAS.find(e => e.id === 't1_s3').transition, e = MO.smooth(clamp((lt - DUR) / tr.dur));
|
|
15
|
+
return CAM.pushTo(CAM_END, wx, wy, CAM_END.z * tr.zoom, e, 0); // k=0:目标在屏幕上原地不动,只放大
|
|
16
|
+
};
|
|
17
|
+
SCENES['t1_s2'] = {
|
|
18
|
+
camAt,
|
|
19
|
+
draw(c, lt) {
|
|
20
|
+
const T = window.T1;
|
|
21
|
+
c.fillStyle = '#000'; c.fillRect(0, 0, 1920, 1080);
|
|
22
|
+
const cam = camAt(lt);
|
|
23
|
+
CAM.with(c, cam, (c) => {
|
|
24
|
+
const inE = T.VIS.map((pi, j) => [T.IN_X, T.inY(j)]);
|
|
25
|
+
const hid = Array.from({ length: T.HID_N }, (_, k) => [T.HID_X, T.hidY(k)]);
|
|
26
|
+
// ---- 连线:ShowCreation,LaggedStart lag 0.006 ----
|
|
27
|
+
const e1p = MO.seg(lt, 0.15, 0.95), e2p = MO.seg(lt, 0.55, 1.05);
|
|
28
|
+
const n1 = inE.length * hid.length;
|
|
29
|
+
inE.forEach((a, j) => hid.forEach((b, k) => {
|
|
30
|
+
const i = j * hid.length + k, q = MO.smooth(MO.lagged(i, n1, e1p, 0.006));
|
|
31
|
+
DG.edge(c, DG.edgeEnds(a[0], a[1], T.IN_R, b[0], b[1], T.HID_R), T.W1(j, k), q, { alpha: 0.7, maxW: 3 });
|
|
32
|
+
}));
|
|
33
|
+
hid.forEach((a, k) => T.OUT.forEach((o, m) => {
|
|
34
|
+
const q = MO.smooth(MO.lagged(k * 3 + m, 30, e2p, 0.02));
|
|
35
|
+
DG.edge(c, DG.edgeEnds(a[0], a[1], T.HID_R, T.OUT_X, o.y, T.OUT_R), T.W2(k, m), q, { alpha: 0.8, maxW: 3.4 });
|
|
36
|
+
}));
|
|
37
|
+
// ---- 信号:连线复制一份染黄、线宽 ×1.5,ShowPassingFlash(time_width 2),按输入行错开 ----
|
|
38
|
+
const f1 = MO.seg(lt, 0.95, 1.75);
|
|
39
|
+
if (f1 > 0 && f1 < 1) inE.forEach((a, j) => { if (T.PIX[T.VIS[j]] < 0.3) return; hid.forEach((b, k) => {
|
|
40
|
+
const q = MO.smooth(MO.lagged(j, 16, f1, 0.04)); const [lo, hi] = DG.flash(q); if (hi <= lo) return;
|
|
41
|
+
const e = DG.edgeEnds(a[0], a[1], T.IN_R, b[0], b[1], T.HID_R);
|
|
42
|
+
c.save(); c.strokeStyle = C.YELLOW; c.globalAlpha = 0.85; c.lineWidth = 3; c.beginPath(); c.moveTo(lerp(e[0], e[2], lo), lerp(e[1], e[3], lo)); c.lineTo(lerp(e[0], e[2], hi), lerp(e[1], e[3], hi)); c.stroke(); c.restore();
|
|
43
|
+
}); });
|
|
44
|
+
const f2 = MO.seg(lt, 1.6, 2.25);
|
|
45
|
+
if (f2 > 0 && f2 < 1) hid.forEach((a, k) => { if (T.HID_A[k] < 0.4) return; T.OUT.forEach((o, m) => {
|
|
46
|
+
const q = MO.smooth(MO.lagged(k, 10, f2, 0.05)); const [lo, hi] = DG.flash(q); if (hi <= lo) return;
|
|
47
|
+
const e = DG.edgeEnds(a[0], a[1], T.HID_R, T.OUT_X, o.y, T.OUT_R);
|
|
48
|
+
c.save(); c.strokeStyle = C.YELLOW; c.globalAlpha = 0.9; c.lineWidth = 4.5; c.beginPath(); c.moveTo(lerp(e[0], e[2], lo), lerp(e[1], e[3], lo)); c.lineTo(lerp(e[0], e[2], hi), lerp(e[1], e[3], hi)); c.stroke(); c.restore();
|
|
49
|
+
}); });
|
|
50
|
+
// ---- 神经元 ----
|
|
51
|
+
T.drawInputs(c); T.drawBrace(c, 1);
|
|
52
|
+
const ha = MO.seg(lt, 0.0, 0.55), hf = MO.seg(lt, 1.3, 1.95);
|
|
53
|
+
const pick = MO.smooth(MO.seg(lt, 2.3, 2.6)); // 末尾:目标隐藏神经元描边染黄(「我们来看这一个」),相机随后推进去
|
|
54
|
+
hid.forEach((b, k) => { const q = MO.smooth(MO.lagged(k, 10, ha, 0.05)); if (q <= 0) return;
|
|
55
|
+
const hk = k === TGT.k ? pick : 0;
|
|
56
|
+
c.save(); c.globalAlpha = q; DG.neuron(c, b[0] + 24 * (1 - q), b[1], T.HID_R, T.HID_A[k] * MO.smooth(MO.lagged(k, 10, hf, 0.08)), { stroke: DG.mix('#ffffff', C.YELLOW, hk), lw: 2 + 2 * hk }); c.restore(); });
|
|
57
|
+
const oa = MO.seg(lt, 0.2, 0.7), of = MO.seg(lt, 1.95, 2.4);
|
|
58
|
+
T.OUT.forEach((o, m) => { const q = MO.smooth(MO.lagged(m, 3, oa, 0.2)); if (q <= 0) return;
|
|
59
|
+
const fill = o.a * MO.smooth(of);
|
|
60
|
+
c.save(); c.globalAlpha = q; DG.neuron(c, T.OUT_X + 24 * (1 - q), o.y, T.OUT_R, fill, { lw: 2.5 });
|
|
61
|
+
// 标签+数值;「猫」Indicate:放大 1.2、染黄、回来
|
|
62
|
+
const ind = m === 0 ? DG.indicate(MO.seg(lt, 2.0, 2.45)) : { s: 1, k: 0 };
|
|
63
|
+
c.translate(T.OUT_X + 62, o.y + 15); c.scale(ind.s, ind.s);
|
|
64
|
+
c.font = `600 46px "${DG.FONT.zh}"`; c.fillStyle = DG.mix('#ffffff', C.YELLOW, ind.k); c.textAlign = 'left'; c.fillText(o.name, 0, 0);
|
|
65
|
+
if (of > 0) { c.font = `40px "${DG.FONT.rm}"`; c.fillStyle = DG.mix(C.GREY_B, C.YELLOW, ind.k); c.globalAlpha = q * clamp(of * 2); c.fillText(TY.fmt(fill, 2), 62, 0); }
|
|
66
|
+
c.restore(); });
|
|
67
|
+
});
|
|
68
|
+
// 公式(不随相机动:屏幕固定层),颜色编码:黄=激活,蓝=权重
|
|
69
|
+
const Y = C.YELLOW, B = C.BLUE_C;
|
|
70
|
+
DG.math(c, [{ s: 'a', it: true, col: Y, sup: '(1)' }, { s: '=', gap: 14 }, { s: 'σ', it: true, gap: 4 }, { s: '(', gap: 6 }, { s: 'W', it: true, col: B, gap: 8 },
|
|
71
|
+
{ s: 'a', it: true, col: Y, sup: '(0)', gap: 14 }, { s: '+', gap: 14 }, { s: 'b', it: true }, { s: ')' }], 960, 112, 64, { p: MO.seg(lt, 0.3, 1.3) });
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
})();
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
// t1 · 镜头 3(2.6s,前 0.75s 是「镜头穿进隐藏层神经元」转场):
|
|
2
|
+
// 神经元内部 = 它连向 100 个像素的权重图(蓝正红负,长得像猫脸)→ 像素图滑进来叠上去(逐格相乘)→ 100 格收拢成一个数 →
|
|
3
|
+
// σ 压到 0.95(= 镜头 2 里它的亮度)→ 「像猫脸」;最后 0.6s 停住给观众读。3b1b 原片讲隐藏层也是这样把权重画成图。
|
|
4
|
+
(() => {
|
|
5
|
+
const { clamp, lerp } = U;
|
|
6
|
+
const C = DG.MANIM;
|
|
7
|
+
const WG = { cx: 640, cy: 585, cell: 44 };
|
|
8
|
+
const cxy = (g, i) => [g.cx + ((i % 10) - 4.5) * g.cell, g.cy + (((i / 10) | 0) - 4.5) * g.cell];
|
|
9
|
+
const wcol = (w, a = 1) => DG.rgba(w >= 0 ? C.BLUE_C : C.RED_C, clamp(Math.abs(w)) * a);
|
|
10
|
+
const NEU = { x: 1460, y: 585, r: 78 };
|
|
11
|
+
SCENES['t1_s3'] = {
|
|
12
|
+
draw(c, lt) {
|
|
13
|
+
const T = window.T1;
|
|
14
|
+
c.fillStyle = '#000'; c.fillRect(0, 0, 1920, 1080);
|
|
15
|
+
DG.write(c, '这个神经元在找什么?', 960, 135, 58, MO.seg(lt, 0.75, 1.5));
|
|
16
|
+
const appear = MO.seg(lt, 0.0, 0.7), slideIn = MO.seg(lt, 0.7, 0.95), merge = MO.seg(lt, 0.95, 1.3), collapse = MO.seg(lt, 1.35, 1.75);
|
|
17
|
+
// ---- 权重图 ----
|
|
18
|
+
for (let i = 0; i < 100; i++) {
|
|
19
|
+
const [x, y] = cxy(WG, i), w = T.WTS[i], v = T.PIX[i];
|
|
20
|
+
const qa = MO.smooth(MO.lagged(i, 100, appear, 0.008)); if (qa <= 0) continue;
|
|
21
|
+
const qm = MO.smooth(merge), qc = MO.smooth(MO.lagged(i, 100, collapse, 0.008));
|
|
22
|
+
// 相乘后的颜色:w·a(只有猫形处的亮像素还亮着蓝,背景被乘成接近 0)
|
|
23
|
+
const prod = w * (v > 0 ? v : 0.06);
|
|
24
|
+
const fill = DG.mix(DG.mixA(w >= 0 ? C.BLUE_C : C.RED_C, '#000000', 1 - clamp(Math.abs(w))), DG.mixA(prod >= 0 ? C.BLUE_C : C.RED_C, '#000000', 1 - clamp(Math.abs(prod) * 1.3)), qm);
|
|
25
|
+
const s = WG.cell * lerp(0.94, 0.3, qc) * qa;
|
|
26
|
+
const px = lerp(x, NEU.x, qc), py = lerp(y, NEU.y, qc);
|
|
27
|
+
if (qc > 0) { const g = 0.28 * MO.smooth(clamp(qc * 1.5)), gs = WG.cell * 0.94; // 收拢后原位留一张淡的权重图(它在找的图案)
|
|
28
|
+
c.save(); c.globalAlpha = g; c.fillStyle = DG.mix(w >= 0 ? C.BLUE_C : C.RED_C, '#000000', 1 - clamp(Math.abs(w))); c.fillRect(x - gs / 2, y - gs / 2, gs, gs); c.restore(); }
|
|
29
|
+
c.save(); c.globalAlpha = 1 - clamp((qc - 0.75) / 0.25);
|
|
30
|
+
c.fillStyle = fill; c.fillRect(px - s / 2, py - s / 2, s, s);
|
|
31
|
+
c.strokeStyle = 'rgba(255,255,255,.18)'; c.lineWidth = 1; c.strokeRect(px - s / 2, py - s / 2, s, s); c.restore();
|
|
32
|
+
}
|
|
33
|
+
// 说明(FadeIn shift=UP),合并时淡出
|
|
34
|
+
const la = MO.smooth(MO.seg(lt, 0.75, 1.1)); // 图例留到片尾(相乘后还要靠它读颜色)
|
|
35
|
+
if (la > 0) { c.save(); c.globalAlpha = la; c.font = `600 34px "${DG.FONT.zh}"`; c.textAlign = 'center';
|
|
36
|
+
c.fillStyle = C.BLUE_C; c.fillText('蓝 = 希望这里亮', WG.cx - 120, 885 + 20 * (1 - la)); c.fillStyle = C.RED_C; c.fillText('红 = 希望这里暗', WG.cx + 150, 885 + 20 * (1 - la)); c.restore(); }
|
|
37
|
+
// ---- 像素图:从右边 FadeIn,再整体移到权重图上(Transform 位置),叠上后淡出成「相乘」 ----
|
|
38
|
+
if (slideIn > 0 && merge < 1) {
|
|
39
|
+
const qs = MO.smooth(slideIn), qm = MO.smooth(merge);
|
|
40
|
+
const gx = lerp(lerp(1340, 1290, qs), WG.cx, qm);
|
|
41
|
+
for (let i = 0; i < 100; i++) {
|
|
42
|
+
const v = T.PIX[i], x = gx + ((i % 10) - 4.5) * WG.cell, y = WG.cy + (((i / 10) | 0) - 4.5) * WG.cell, s = WG.cell * 0.94;
|
|
43
|
+
c.save(); c.globalAlpha = qs * (1 - qm * 0.9); c.fillStyle = `rgba(255,255,255,${v})`; c.fillRect(x - s / 2, y - s / 2, s, s);
|
|
44
|
+
c.strokeStyle = 'rgba(255,255,255,.25)'; c.lineWidth = 1; c.strokeRect(x - s / 2, y - s / 2, s, s); c.restore();
|
|
45
|
+
}
|
|
46
|
+
c.save(); c.globalAlpha = qs * (1 - qm); c.font = `64px "${DG.FONT.rm}"`; c.fillStyle = '#fff'; c.textAlign = 'center'; c.fillText('×', (WG.cx + 5 * WG.cell + gx - 5 * WG.cell) / 2, WG.cy + 22); c.restore();
|
|
47
|
+
}
|
|
48
|
+
// ---- 收拢成一个神经元:加权求和 → σ → 0.92 ----
|
|
49
|
+
const nq = MO.smooth(MO.seg(lt, 1.3, 1.6));
|
|
50
|
+
if (nq > 0) {
|
|
51
|
+
const fillA = 0.95 * MO.smooth(MO.seg(lt, 1.65, 2.0)); // = 镜头 2 里它的激活值 0.95
|
|
52
|
+
const ind = DG.indicate(MO.seg(lt, 1.9, 2.3));
|
|
53
|
+
c.save(); c.translate(NEU.x, NEU.y); c.scale(ind.s, ind.s); c.translate(-NEU.x, -NEU.y); c.globalAlpha = nq;
|
|
54
|
+
DG.neuron(c, NEU.x, NEU.y, NEU.r * (0.6 + 0.4 * nq), fillA, { lw: 3, stroke: DG.mix('#ffffff', C.YELLOW, ind.k) });
|
|
55
|
+
c.restore();
|
|
56
|
+
c.save(); c.globalAlpha = nq; c.textAlign = 'center';
|
|
57
|
+
c.font = `600 52px "${DG.FONT.zh}"`; c.fillStyle = DG.mix('#ffffff', C.YELLOW, ind.k); c.fillText('像猫脸', NEU.x, NEU.y - NEU.r - 34);
|
|
58
|
+
c.font = `48px "${DG.FONT.rm}"`; c.fillStyle = C.GREY_A; c.fillText(TY.fmt(fillA, 2), NEU.x, NEU.y + NEU.r + 62);
|
|
59
|
+
c.restore();
|
|
60
|
+
}
|
|
61
|
+
DG.math(c, [{ s: 'σ', it: true }, { s: '(', gap: 4 }, { s: 'Σ', gap: 6 }, { s: 'w', it: true, col: C.BLUE_C, sub: 'i', gap: 2 }, { s: 'a', it: true, col: C.YELLOW, sub: 'i', gap: 12 },
|
|
62
|
+
{ s: '+', gap: 12 }, { s: 'b', it: true }, { s: ')', gap: 14 }, { s: '=', gap: 14 }, { s: TY.fmt(0.95 * MO.smooth(MO.seg(lt, 1.65, 2.0)), 2) }], 1180, 965, 54, { p: MO.seg(lt, 1.45, 1.95) });
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
})();
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// 示范 · 发布会式(Apple keynote / 产品发布 UI)「Plover 2 的三个功能」(8 秒三镜,产品与数字虚构)。语法卡:references/动画语法/t2_keynote_ui.md
|
|
2
|
+
// 预览 index.html?film=demos/t2_keynote_ui 渲染 render.py --film demos/t2_keynote_ui --out t2.mp4
|
|
3
|
+
// 光斑底只依赖全片时间 t,三个镜头之间无缝;卡片 → 全屏是共享元素展开(rect = 中间卡在镜头 2 末帧的屏幕矩形)。
|
|
4
|
+
window.PUNCH = 0;
|
|
5
|
+
window.SCENE_DIR = 'demos/t2_keynote_ui';
|
|
6
|
+
window.ERAS = [
|
|
7
|
+
{ id: 't2_s1', dur: 2.6 },
|
|
8
|
+
{ id: 't2_s2', dur: 3.0, transition: { type: 'blurPush', dur: 0.55 } },
|
|
9
|
+
{ id: 't2_s3', dur: 2.4, transition: { type: 'expandRect', dur: 0.6, rect: { x: 705.6, y: 252.6, w: 508.8, h: 614.8 }, r: 38 } },
|
|
10
|
+
];
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
// t2 · 发布会式:「一个 AI 产品发布:三个功能卡片」
|
|
2
|
+
// 镜头 1(2.6s):深色底上柔和光斑缓慢漂移;眉题 → 产品名(模糊→清晰+上移,渐变字,光扫过)→ 一句话副标题。相机极慢推近。
|
|
3
|
+
// 本文件同时放 t2 共用的东西(window.T2):光斑底、字体、颜色。
|
|
4
|
+
(() => {
|
|
5
|
+
const { clamp, lerp } = U;
|
|
6
|
+
const W = 1920, H = 1080;
|
|
7
|
+
const BASE = '#050508';
|
|
8
|
+
const BLOBS = [ // 色相取 Stripe 渐变一系(紫/蓝/青)+ 一点暖色;周期避开 5s(HIG:避免 ~0.2Hz 持续摆动)
|
|
9
|
+
{ x: 430, y: 300, r: 760, col: [150, 90, 238], a: 0.75, ax: 220, ay: 120, period: 11, ph: 0 },
|
|
10
|
+
{ x: 1520, y: 260, r: 700, col: [56, 104, 255], a: 0.7, ax: 200, ay: 160, period: 13, ph: 2.1 },
|
|
11
|
+
{ x: 1320, y: 930, r: 560, col: [120, 214, 255], a: 0.5, ax: 260, ay: 100, period: 9.5, ph: 4 },
|
|
12
|
+
{ x: 520, y: 960, r: 520, col: [255, 96, 84], a: 0.42, ax: 180, ay: 90, period: 12, ph: 1.3 },
|
|
13
|
+
];
|
|
14
|
+
const SANS = '"Inter", "NotoSansSC"', ZH = '"NotoSansSC"';
|
|
15
|
+
// 光斑底:只依赖全片时间 t,三个镜头之间无缝(换镜头时背景不跳)
|
|
16
|
+
const bg = (c, t, { dim = 0.38 } = {}) => {
|
|
17
|
+
UI.mesh(c, t, { base: BASE, blobs: BLOBS, blur: 90, scale: 0.25, grain: 0.035, key: 't2mesh' });
|
|
18
|
+
// 中心压暗一点,给白字留对比
|
|
19
|
+
const g = c.createRadialGradient(W / 2, H / 2, 100, W / 2, H / 2, 1000); g.addColorStop(0, `rgba(0,0,0,${dim})`); g.addColorStop(1, 'rgba(0,0,0,0.1)');
|
|
20
|
+
c.fillStyle = g; c.fillRect(0, 0, W, H);
|
|
21
|
+
};
|
|
22
|
+
// 大字:字距收紧 −0.02em(苹果/Linear 官网 64px 以上 −0.015~−0.03em)
|
|
23
|
+
const track = (c, size, em = -0.02) => { c.letterSpacing = (size * em).toFixed(2) + 'px'; };
|
|
24
|
+
// 光斑漂移、卡片漂浮、图标律动都读全片时间 t。PHASE:沿用实验时这支片排在 8–16s 的相位,保持定稿画面的构图(换题目时删掉或随便改)
|
|
25
|
+
const PHASE = 8;
|
|
26
|
+
window.T2 = { bg, SANS, ZH, track, BASE, PHASE };
|
|
27
|
+
|
|
28
|
+
const DUR = 2.6;
|
|
29
|
+
SCENES['t2_s1'] = {
|
|
30
|
+
draw(c, lt, t) {
|
|
31
|
+
t += T2.PHASE;
|
|
32
|
+
bg(c, t);
|
|
33
|
+
// 相机匀速慢推:1.0 → 1.045(整镜线性,发布会片的慢推不减速,减速到停会让画面「死」掉)
|
|
34
|
+
const s = lerp(1, 1.045, lt / (DUR + 0.55));
|
|
35
|
+
c.save(); c.translate(W / 2, H / 2); c.scale(s, s); c.translate(-W / 2, -H / 2);
|
|
36
|
+
c.textAlign = 'center'; c.textBaseline = 'alphabetic';
|
|
37
|
+
// 眉题
|
|
38
|
+
c.font = `500 34px ${ZH}`; c.fillStyle = '#a7a7b4'; c.letterSpacing = '6px';
|
|
39
|
+
TY.blurIn(c, '全 新 发 布', W / 2, 372, MO.appleOut(MO.seg(lt, 0.1, 0.8)), { blur: 10, dy: 16 });
|
|
40
|
+
// 产品名:渐变字画进离屏 → 光扫过(source-atop 只亮在字上)→ 模糊→清晰贴回
|
|
41
|
+
const p = MO.appleOut(MO.seg(lt, 0.3, 1.3));
|
|
42
|
+
if (p > 0) {
|
|
43
|
+
const tx = UI.scratch('t2title', W, 420), g = tx.getContext('2d'); g.reset();
|
|
44
|
+
g.font = `600 220px ${SANS}`; track(g, 220); g.textAlign = 'center'; g.textBaseline = 'alphabetic';
|
|
45
|
+
const gr = g.createLinearGradient(600, 0, 1320, 0); gr.addColorStop(0, '#ffffff'); gr.addColorStop(0.55, '#ddd2ff'); gr.addColorStop(1, '#a8dcff');
|
|
46
|
+
g.fillStyle = gr; g.fillText('Plover 2', W / 2, 300);
|
|
47
|
+
UI.sheen(g, null, MO.seg(lt, 1.25, 2.15), { x0: 560, x1: 1360, width: 140, angle: -0.38, alpha: 0.85, comp: 'source-atop' });
|
|
48
|
+
c.save(); c.globalAlpha = clamp(p * 1.5); const b = (1 - p) * 26; if (b > 0.3) c.filter = `blur(${b.toFixed(1)}px)`;
|
|
49
|
+
c.drawImage(tx, 0, 620 - 300 + (1 - p) * 40); c.restore(); // 纹理基线 y=300 → 屏幕 y=620
|
|
50
|
+
}
|
|
51
|
+
// 副标题
|
|
52
|
+
c.font = `400 50px ${ZH}`; c.fillStyle = '#c9c9d4'; c.letterSpacing = '1px';
|
|
53
|
+
TY.blurIn(c, '会思考、会记忆、会动手的 AI 助手', W / 2, 740, MO.appleOut(MO.seg(lt, 0.7, 1.6)), { blur: 12, dy: 22 });
|
|
54
|
+
c.restore();
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
})();
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
// t2 · 镜头 2(3.0s):三张毛玻璃功能卡片在 3D 空间入场(弹簧,bounce 0.15,错开 0.1s),绕 Y 轴转正;
|
|
2
|
+
// 卡上数字计数;整组持续漂浮;光扫过三张卡;最后中间卡「被选中」(放大,其余后退变暗),接共享元素展开。
|
|
3
|
+
(() => {
|
|
4
|
+
const { clamp, lerp } = U;
|
|
5
|
+
const W = 1920, H = 1080;
|
|
6
|
+
const CW = 480, CH_ = 580, GAP = 52, CY = 560, R = 36;
|
|
7
|
+
const CARDS = [
|
|
8
|
+
{ icon: 'wave', title: '实时语音', desc: '像打电话一样自然地打断和追问', num: 320, dec: 0, unit: 'ms', label: '端到端延迟' },
|
|
9
|
+
{ icon: 'memory', title: '长期记忆', desc: '记得你说过的每一个偏好', num: 100, dec: 0, unit: '万', label: 'tokens 上下文' },
|
|
10
|
+
{ icon: 'agent', title: '自主执行', desc: '拆解任务、调用工具、交付结果', num: 87, dec: 0, unit: '%', label: '任务一次完成率' },
|
|
11
|
+
];
|
|
12
|
+
const DUR = 3.0, FOCUS = 2.15; // 2.15s 起中间卡被选中
|
|
13
|
+
// 每张卡在 lt 时刻的状态(屏幕中心、旋转、缩放、透明),转场也要用中间卡的最终矩形
|
|
14
|
+
const state = (i, lt, t) => {
|
|
15
|
+
const t0 = 0.05 + i * 0.1; // 错开 0.1s
|
|
16
|
+
const sp = MO.spring(lt - t0, { duration: 0.75, bounce: 0.15 });
|
|
17
|
+
const f = MO.smooth(MO.seg(lt, FOCUS, FOCUS + 0.6));
|
|
18
|
+
const floatAmp = lerp(1, i === 1 ? 0 : 0.6, f); // 被选中的卡停止漂浮,好让转场从一个稳定的矩形展开
|
|
19
|
+
const cx = 960 + (i - 1) * (CW + GAP) + (i - 1) * 40 * f;
|
|
20
|
+
const cy = CY + (1 - sp) * 170 + MO.float(t, 7, 3.4 + i * 0.45, i * 2) * floatAmp;
|
|
21
|
+
const ry = (1 - sp) * (i - 1 || 0.001) * -0.55 + 0.06 * Math.sin(t * 0.9 + i) * floatAmp + (i - 1) * 0.12 * f;
|
|
22
|
+
const sc = (0.9 + 0.1 * sp) * (i === 1 ? lerp(1, 1.06, f) : lerp(1, 0.94, f));
|
|
23
|
+
const a = clamp((lt - t0) / 0.25) * (i === 1 ? 1 : lerp(1, 0.45, f));
|
|
24
|
+
return { cx, cy, ry, sc, a, t0 };
|
|
25
|
+
};
|
|
26
|
+
const cardRectAt = (lt, t) => { const s = state(1, lt, t); return { x: s.cx - CW * s.sc / 2, y: s.cy - CH_ * s.sc / 2, w: CW * s.sc, h: CH_ * s.sc }; };
|
|
27
|
+
|
|
28
|
+
SCENES['t2_s2'] = {
|
|
29
|
+
cardRectAt, CW, CH: CH_,
|
|
30
|
+
draw(c, lt, t) {
|
|
31
|
+
t += T2.PHASE;
|
|
32
|
+
const bgc = UI.scratch('t2bg', W, H), bgx = bgc.getContext('2d');
|
|
33
|
+
T2.bg(bgx, t); c.drawImage(bgc, 0, 0);
|
|
34
|
+
const bd = UI.backdrop(bgc, { blur: 40, key: 't2bd' });
|
|
35
|
+
// 先画两侧再画中间(中间卡在最上层)
|
|
36
|
+
[0, 2, 1].forEach(i => {
|
|
37
|
+
const S = state(i, lt, t); if (S.a <= 0) return;
|
|
38
|
+
const d = CARDS[i], cw = CW * S.sc, ch = CH_ * S.sc;
|
|
39
|
+
// 卡片纹理:毛玻璃(按卡片的屏幕位置取样背景)+内容
|
|
40
|
+
const tex = UI.scratch('t2card' + i, CW + 120, CH_ + 120), g = tex.getContext('2d'); g.reset();
|
|
41
|
+
const ox = 60, oy = 60;
|
|
42
|
+
UI.glass(g, { x: ox, y: oy, w: CW, h: CH_, r: R, bd, sample: { x: S.cx - cw / 2, y: S.cy - ch / 2, w: cw, h: ch }, tint: 0.075, stroke: 0.2, light: 0.14, shadow: false });
|
|
43
|
+
g.save(); g.translate(ox, oy);
|
|
44
|
+
// 图标底:同心圆角(子圆角 = 父圆角 − 内边距)
|
|
45
|
+
const pad = 44; g.fillStyle = 'rgba(255,255,255,0.09)'; g.beginPath(); g.roundRect(pad, pad, 96, 96, R - 14); g.fill();
|
|
46
|
+
UI.icon(g, d.icon, pad + 48, pad + 48, 60, '#f2f2f7', t);
|
|
47
|
+
g.textBaseline = 'alphabetic'; g.textAlign = 'left';
|
|
48
|
+
g.font = `600 50px ${T2.ZH}`; g.fillStyle = '#f5f5f7'; g.fillText(d.title, pad, 230);
|
|
49
|
+
g.font = `400 28px ${T2.ZH}`; g.fillStyle = 'rgba(235,235,245,0.62)'; g.fillText(d.desc, pad, 278);
|
|
50
|
+
// 分隔线
|
|
51
|
+
g.fillStyle = 'rgba(255,255,255,0.12)'; g.fillRect(pad, 330, CW - pad * 2, 1.5);
|
|
52
|
+
// 大数字:卡片落定后 0.25s 起计数 0.9s(easeOutExpo,最后一位慢慢落定),等宽排布不抖
|
|
53
|
+
const v = TY.count(lt, S.t0 + 0.35, 0.9, 0, d.num);
|
|
54
|
+
g.font = `600 132px ${T2.SANS}`; T2.track(g, 132, -0.03); g.fillStyle = '#ffffff';
|
|
55
|
+
const nw = TY.tabular(g, TY.fmt(v, d.dec), pad, 488);
|
|
56
|
+
g.letterSpacing = '0px'; g.font = `500 52px ${T2.SANS}`; g.fillStyle = 'rgba(235,235,245,0.7)'; g.fillText(d.unit, pad + nw + 10, 488);
|
|
57
|
+
g.font = `400 28px ${T2.ZH}`; g.fillStyle = 'rgba(235,235,245,0.55)'; g.fillText(d.label, pad, 535);
|
|
58
|
+
g.restore();
|
|
59
|
+
// 光扫过:1.2–2.0s 从左到右扫过整组(每张卡按自己的屏幕位置算进度,看起来是同一道光)
|
|
60
|
+
const sp = MO.seg(lt, 1.15, 2.05), gx = lerp(-200, W + 200, sp), lx = (gx - (S.cx - cw / 2)) / cw;
|
|
61
|
+
if (sp > 0 && sp < 1) UI.sheen(g, UI.rrPath(ox, oy, CW, CH_, R), clamp((lx + 0.35) / 1.7), { x0: ox, x1: ox + CW, width: 110, angle: -0.35, alpha: 0.22 });
|
|
62
|
+
// 阴影(按屏幕投影后的尺寸)+透视贴图
|
|
63
|
+
c.save(); c.globalAlpha = S.a;
|
|
64
|
+
UI.shadow(c, S.cx - cw / 2 + 10, S.cy - ch / 2 + 20, cw - 20, ch - 20, R, { blur: 80, oy: 40, alpha: 0.55 });
|
|
65
|
+
UI.persp(c, tex, { cx: S.cx, cy: S.cy, w: (CW + 120) * S.sc, h: (CH_ + 120) * S.sc, ry: S.ry, persp: 1800, strip: 3, shade: 0.4 });
|
|
66
|
+
c.restore();
|
|
67
|
+
});
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
})();
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
// t2 · 镜头 3(2.4s,前 0.6s 是中间卡「展开成全屏」的共享元素转场):
|
|
2
|
+
// 我们「进到了长期记忆这张卡里」——底是同一块毛玻璃;超大数字(与卡片同口径,不重数);下方一块向后倾斜的对话面板,气泡依次弹起;最后产品落版。
|
|
3
|
+
(() => {
|
|
4
|
+
const { clamp, lerp } = U;
|
|
5
|
+
const W = 1920, H = 1080;
|
|
6
|
+
const PW = 1180, PH = 360;
|
|
7
|
+
SCENES['t2_s3'] = {
|
|
8
|
+
draw(c, lt, t) {
|
|
9
|
+
t += T2.PHASE;
|
|
10
|
+
const bgc = UI.scratch('t2bg3', W, H), bgx = bgc.getContext('2d');
|
|
11
|
+
T2.bg(bgx, t, { dim: 0.25 });
|
|
12
|
+
const bd = UI.backdrop(bgc, { blur: 40, key: 't2bd3' });
|
|
13
|
+
// 全屏毛玻璃 = 卡片的质地放大到全屏(与转场里展开的卡片同一种材料)
|
|
14
|
+
c.drawImage(bd, 0, 0, W, H); c.fillStyle = 'rgba(255,255,255,0.075)'; c.fillRect(0, 0, W, H);
|
|
15
|
+
const tg = c.createLinearGradient(0, 0, 0, H * 0.5); tg.addColorStop(0, 'rgba(255,255,255,0.10)'); tg.addColorStop(1, 'rgba(255,255,255,0)'); c.fillStyle = tg; c.fillRect(0, 0, W, H * 0.5);
|
|
16
|
+
// 卡片抬头留在左上(展开前它就在卡片的这个位置,观众知道自己在哪)
|
|
17
|
+
c.fillStyle = 'rgba(255,255,255,0.09)'; c.beginPath(); c.roundRect(120, 96, 84, 84, 20); c.fill();
|
|
18
|
+
UI.icon(c, 'memory', 162, 138, 52, '#f2f2f7', t);
|
|
19
|
+
c.font = `600 44px ${T2.ZH}`; c.fillStyle = '#f5f5f7'; c.textBaseline = 'alphabetic'; c.textAlign = 'left'; c.fillText('长期记忆', 232, 154);
|
|
20
|
+
// 超大数字:和卡片上同一个口径「100万」,不重新计数(卡片刚数过一遍,展开后再从 0 数会让叙事打嗝)——卡片里的数字放大成主角
|
|
21
|
+
const pin = MO.appleOut(MO.seg(lt, 0.0, 0.5));
|
|
22
|
+
c.save(); c.textBaseline = 'alphabetic'; c.textAlign = 'left';
|
|
23
|
+
c.font = `600 230px ${T2.SANS}`; T2.track(c, 230, -0.03); const w1 = c.measureText('100').width;
|
|
24
|
+
c.letterSpacing = '0px'; c.font = `600 150px ${T2.ZH}`; const w2 = c.measureText('万').width;
|
|
25
|
+
c.font = `500 56px ${T2.SANS}`; const w3 = c.measureText('tokens').width;
|
|
26
|
+
const x0 = W / 2 - (w1 + w2 + w3 + 34) / 2, by = 400 - (1 - pin) * 20;
|
|
27
|
+
c.font = `600 230px ${T2.SANS}`; T2.track(c, 230, -0.03); c.fillStyle = '#ffffff'; c.fillText('100', x0, by);
|
|
28
|
+
c.letterSpacing = '0px'; c.font = `600 150px ${T2.ZH}`; c.fillText('万', x0 + w1 + 6, by);
|
|
29
|
+
c.font = `500 56px ${T2.SANS}`; c.fillStyle = 'rgba(235,235,245,0.7)'; c.fillText('tokens', x0 + w1 + w2 + 34, by);
|
|
30
|
+
c.restore();
|
|
31
|
+
c.font = `400 34px ${T2.ZH}`; c.fillStyle = 'rgba(235,235,245,0.6)'; c.textAlign = 'center';
|
|
32
|
+
TY.blurIn(c, '上下文窗口 —— 一年的对话,它都记得', W / 2, 478, MO.appleOut(MO.seg(lt, 0.35, 0.95)), { blur: 8, dy: 14 });
|
|
33
|
+
// 对话面板(纹理 → 绕 X 轴后倾),气泡按 spring 依次弹起;面板整体缓慢上浮
|
|
34
|
+
const tex = UI.scratch('t2panel', PW, PH), g = tex.getContext('2d'); g.reset();
|
|
35
|
+
g.fillStyle = 'rgba(12,12,20,0.55)'; g.beginPath(); g.roundRect(0, 0, PW, PH, 30); g.fill();
|
|
36
|
+
g.strokeStyle = 'rgba(255,255,255,0.16)'; g.lineWidth = 2; g.stroke();
|
|
37
|
+
const bubble = (k, text, right, y, t0) => {
|
|
38
|
+
const s = MO.spring(lt - t0, { duration: 0.5, bounce: 0.15 }); if (lt <= t0) return;
|
|
39
|
+
g.save(); g.globalAlpha = clamp((lt - t0) / 0.2); g.font = `400 34px ${T2.ZH}`;
|
|
40
|
+
const tw = g.measureText(text).width, bw = tw + 64, bh = 74, bx = right ? PW - 48 - bw : 48, by = y + (1 - s) * 40;
|
|
41
|
+
g.translate(bx + (right ? bw : 0), by + bh); g.scale(lerp(0.85, 1, s), lerp(0.85, 1, s)); g.translate(-(bx + (right ? bw : 0)), -(by + bh));
|
|
42
|
+
g.fillStyle = right ? '#3d6bff' : 'rgba(255,255,255,0.14)'; g.beginPath(); g.roundRect(bx, by, bw, bh, 37); g.fill();
|
|
43
|
+
g.fillStyle = '#fff'; g.textBaseline = 'middle'; g.fillText(text, bx + 32, by + bh / 2 + 2); g.restore();
|
|
44
|
+
void k;
|
|
45
|
+
};
|
|
46
|
+
bubble(0, '还记得我上个月说的旅行计划吗?', true, 36, 0.45);
|
|
47
|
+
bubble(1, '记得:五月去京都,预算两万,不坐红眼航班。', false, 134, 0.8);
|
|
48
|
+
bubble(2, '那帮我订吧。', true, 232, 1.15);
|
|
49
|
+
// 输入中光标闪(持续小动作)
|
|
50
|
+
if (lt > 1.35) { g.fillStyle = `rgba(255,255,255,${0.35 + 0.35 * Math.sin(lt * 9)})`; for (let k = 0; k < 3; k++) { g.beginPath(); g.arc(90 + k * 26, 330, 7, 0, Math.PI * 2); g.fill(); } }
|
|
51
|
+
const pp = MO.spring(lt - 0.3, { duration: 0.8, bounce: 0 });
|
|
52
|
+
c.save(); c.globalAlpha = clamp((lt - 0.3) / 0.3);
|
|
53
|
+
UI.persp(c, tex, { cx: W / 2, cy: 725 + (1 - pp) * 120 - 8 * MO.smooth(clamp(lt / 2.4)), w: PW, h: PH, rx: lerp(0.55, 0.32, pp), persp: 1500, strip: 2 });
|
|
54
|
+
c.restore();
|
|
55
|
+
// 落版:品牌名 + 上线信息
|
|
56
|
+
c.textAlign = 'center'; c.font = `600 40px ${T2.SANS}`; T2.track(c, 40, -0.01); c.fillStyle = '#ffffff';
|
|
57
|
+
TY.blurIn(c, 'Plover 2 · 今天起可用', W / 2, 972, MO.appleOut(MO.seg(lt, 1.2, 1.8)), { blur: 10, dy: 12 }); // 1.8s 落定,停 0.6s;y=972 在字幕安全区内
|
|
58
|
+
c.letterSpacing = '0px';
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
})();
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// 示范 · 财经图表(经济学人 / 财经频道)「深算科技营收与股价」(8 秒三镜,公司与数据全部虚构,每镜标「示意数据」)。语法卡:references/动画语法/t3_finance_chart.md
|
|
2
|
+
// 预览 index.html?film=demos/t3_finance_chart 渲染 render.py --film demos/t3_finance_chart --out t3.mp4
|
|
3
|
+
// 镜头 2→3:相机绕股价线最新点推近(矢量重画、屏幕位置不动),穿进最近 20 日 K 线。
|
|
4
|
+
window.PUNCH = 0;
|
|
5
|
+
window.SCENE_DIR = 'demos/t3_finance_chart';
|
|
6
|
+
window.ERAS = [
|
|
7
|
+
{ id: 't3_s1', dur: 2.8 },
|
|
8
|
+
{ id: 't3_s2', dur: 2.7, transition: { type: 'slidePush', dur: 0.5, bar: '#E3120B' } },
|
|
9
|
+
{ id: 't3_s3', dur: 2.5, transition: { type: 'zoomThrough', dur: 0.6, cx: 1530, cy: 297.65, zoom: 6, live: true, bScale0: 0.6, bg: '#FFFFFF',
|
|
10
|
+
get focus() { return SCENES.t3_s3.focus; } } }, // focus = 最新一根 K 线
|
|
11
|
+
];
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// t3 · 财经图表:「某虚构 AI 公司 5 年营收增长与股价」(数据全部虚构,每一镜角落标「示意数据」)
|
|
2
|
+
// 镜头 1(2.8s):版式先出(顶红线+红色小旗+标题+单位)→ 网格从左往右画出(零线最深)→ 柱子从 0 依次长出、数值同步计数 →
|
|
3
|
+
// 高亮最后一根(其余变灰)→ 标注「8.7 倍」。本文件同时放 t3 共用的版式与数据(window.T3)。
|
|
4
|
+
(() => {
|
|
5
|
+
const { clamp, lerp, rng } = U;
|
|
6
|
+
const W = 1920, H = 1080;
|
|
7
|
+
// 颜色:经济学人图表色板(2017 图表风格指南)
|
|
8
|
+
const COL = { red: '#E3120B', blue: '#006BA2', blue2: '#3EBCD2', grey: '#758D99', dim: '#C6D2D8', ink: '#0C0C0C', sub: '#4F5B61', grid: 'rgba(12,12,12,0.13)', bg: '#FFFFFF', up: '#E3120B', down: '#1B9E5A', gold: '#EBB434' };
|
|
9
|
+
const CN = '"NotoSansSC"', NUM = '"RobotoCondensed", "NotoSansSC"';
|
|
10
|
+
const F = { x: 170, y: 270, w: 1580, h: 610 }; // 绘图区
|
|
11
|
+
// ---- 虚构数据 ----
|
|
12
|
+
const REV = [{ y: 2021, v: 12.4 }, { y: 2022, v: 19.8 }, { y: 2023, v: 34.6 }, { y: 2024, v: 61.2 }, { y: 2025, v: 107.9 }];
|
|
13
|
+
// 月收盘价 60 个点:带种子的随机游走,2022 回撤、2023-03 跳涨,再整体缩放到 38 → 286.4
|
|
14
|
+
const PRICE = (() => { const r = rng(2025), a = []; let v = 0;
|
|
15
|
+
for (let m = 0; m < 60; m++) { const drift = m < 12 ? 0.02 : m < 24 ? -0.035 : m === 26 ? 0.35 : 0.045; v += drift + (r() - 0.5) * 0.11; a.push(v); }
|
|
16
|
+
const e = a.map(Math.exp), k0 = e[0], k1 = e[59], out = e.map(x => 38 + (x - k0) / (k1 - k0) * (286.4 - 38));
|
|
17
|
+
out[58] = 242; return out; })(); // 末点 = 最新价 286.4,倒数第二个月收盘 = 日 K 起点 242(两镜数字对得上)
|
|
18
|
+
// 最近 20 个交易日 K 线:从 242 走到 286.4(+18.3%),有涨有跌
|
|
19
|
+
const KL = (() => { const r = rng(77), out = []; let c = 242;
|
|
20
|
+
for (let i = 0; i < 20; i++) { const tgt = 242 + (286.4 - 242) * (i + 1) / 20; const o = c; const cl = i === 19 ? 286.4 : tgt + (r() - 0.5) * 9 + (i % 5 === 3 ? -7 : 0);
|
|
21
|
+
const hi = Math.max(o, cl) + 1.5 + r() * 4, lo = Math.min(o, cl) - 1.5 - r() * 4; out.push({ o, c: cl, h: hi, l: lo, vol: 0.4 + r() * 0.6 + (Math.abs(cl - o) / 10) }); c = cl; }
|
|
22
|
+
return out; })();
|
|
23
|
+
|
|
24
|
+
// ---- 版式(每镜都画):经济学人式整页版式 CH.frame(顶部红线、左上红色小旗、标题、副标题=单位、来源、示意数据角标)----
|
|
25
|
+
const frame = (c, lt, { title, sub, source = '来源:示意数据,公司与数字均为虚构' } = {}) => CH.frame(c, lt, { title, sub, source, font: CN, red: COL.red, ink: COL.ink, subCol: COL.sub });
|
|
26
|
+
window.T3 = { COL, CN, NUM, F, REV, PRICE, KL, frame };
|
|
27
|
+
|
|
28
|
+
// ---- 镜头 1 ----
|
|
29
|
+
const yS = CH.lin(0, 120, F.y + F.h, F.y);
|
|
30
|
+
const xs = REV.map((d, i) => F.x + 130 + i * ((F.w - 330) / 4));
|
|
31
|
+
SCENES['t3_s1'] = {
|
|
32
|
+
draw(c, lt) {
|
|
33
|
+
c.fillStyle = T3.COL.bg; c.fillRect(0, 0, 1920, 1080);
|
|
34
|
+
const z = 1 + 0.03 * lt / 2.8; // 匀速慢推 1→1.03(财经频道图表镜头的常规呼吸感)
|
|
35
|
+
c.save(); c.translate(960, 575); c.scale(z, z); c.translate(-960, -575);
|
|
36
|
+
frame(c, lt, { title: '深算科技:营收五年涨到原来的近 9 倍', sub: '年营收,亿元' });
|
|
37
|
+
CH.grid(c, F, [0, 30, 60, 90, 120], yS, MO.seg(lt, 0.25, 0.85), { col: COL.grid, zeroCol: COL.ink, font: `400 30px ${NUM}`, labelCol: '#5b666b', side: 'right', lw: 1.5, zeroLw: 3 });
|
|
38
|
+
CH.xLabels(c, REV.map((d, i) => ({ x: xs[i], label: String(d.y) })), F.y + F.h + 50, MO.seg(lt, 0.45, 1.0), { font: `400 32px ${NUM}`, col: '#3a4246' });
|
|
39
|
+
const hiP = MO.smooth(MO.seg(lt, 1.95, 2.35));
|
|
40
|
+
const tops = CH.bars(c, REV.map((d, i) => ({ x: xs[i], v: d.v })), yS, 150, MO.seg(lt, 0.65, 1.95),
|
|
41
|
+
{ lag: 0.22, col: COL.blue, hi: lt > 1.95 ? 4 : -1, hiP, hiCol: COL.blue, dimCol: COL.dim, fmt: v => v.toFixed(1), font: `600 34px ${NUM}`, labelCol: COL.ink });
|
|
42
|
+
// 标注:最后一根柱旁,点 → 引线 → 两行字(数字先说,比较后说)
|
|
43
|
+
CH.callout(c, lt, 2.15, { x: xs[4] - 75, y: tops[4][1], tx: xs[4] - 330, ty: yS(96), lines: ['8.7 倍', '2025 年 107.9 亿 ÷ 2021 年 12.4 亿'],
|
|
44
|
+
col: COL.ink, dotCol: COL.red, font: `700 54px ${NUM}`, font2: `400 28px ${CN}`, align: 'right', r: 9 });
|
|
45
|
+
c.restore();
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
})();
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// t3 · 镜头 2(2.7s,开头 0.5s 是面板横推转场):股价折线。网格先出 → 折线按时间从左画到右(头部圆点+价格跟随)→
|
|
2
|
+
// 画过 2023 年 3 月时弹出事件标注(一镜只标一件事) → 相机缓慢推向最新一个点;转场期间继续推近(矢量重画),穿进 K 线镜头。
|
|
3
|
+
(() => {
|
|
4
|
+
const { clamp, lerp } = U;
|
|
5
|
+
const W = 1920, H = 1080;
|
|
6
|
+
const DUR = 2.7;
|
|
7
|
+
SCENES['t3_s2'] = {
|
|
8
|
+
draw(c, lt) {
|
|
9
|
+
const { COL, CN, NUM, F, PRICE, frame } = T3;
|
|
10
|
+
const yS = CH.lin(0, 300, F.y + F.h, F.y), xm = m => F.x + m / 59 * (F.w - 220);
|
|
11
|
+
const pts = PRICE.map((v, m) => [xm(m), yS(v)]);
|
|
12
|
+
const P = pts[59];
|
|
13
|
+
// 相机:镜头内 1 → 1.05,转场期间(lt > DUR)指数推近到 ×6,始终绕最新点(屏幕位置不动)
|
|
14
|
+
const tr = ERAS.find(e => e.id === 't3_s3').transition;
|
|
15
|
+
const z = lt <= DUR ? lerp(1, 1.05, MO.smooth(lt / DUR)) : 1.05 * Math.pow(tr.zoom / 1.05, MO.smooth(clamp((lt - DUR) / tr.dur)));
|
|
16
|
+
c.fillStyle = COL.bg; c.fillRect(0, 0, W, H);
|
|
17
|
+
c.save(); c.translate(P[0], P[1]); c.scale(z, z); c.translate(-P[0], -P[1]);
|
|
18
|
+
frame(c, lt, { title: '股价:先跌后涨,五年涨到原来的 7.5 倍', sub: '月收盘价,元' });
|
|
19
|
+
CH.grid(c, F, [0, 100, 200, 300], yS, MO.seg(lt, 0.2, 0.75), { col: COL.grid, zeroCol: COL.ink, font: `400 30px ${NUM}`, labelCol: '#5b666b', side: 'right', lw: 1.5, zeroLw: 3 });
|
|
20
|
+
CH.xLabels(c, [2021, 2022, 2023, 2024, 2025].map((y, i) => ({ x: xm(i * 12 + 5.5), label: String(y) })), F.y + F.h + 50, MO.seg(lt, 0.3, 0.8), { font: `400 32px ${NUM}`, col: '#3a4246' });
|
|
21
|
+
// 年份分隔短刻度
|
|
22
|
+
c.save(); c.strokeStyle = 'rgba(12,12,12,.35)'; c.lineWidth = 2; c.globalAlpha = MO.seg(lt, 0.3, 0.6);
|
|
23
|
+
for (let y = 1; y < 5; y++) { const x = xm(y * 12 - 0.5); c.beginPath(); c.moveTo(x, F.y + F.h); c.lineTo(x, F.y + F.h + 14); c.stroke(); } c.restore();
|
|
24
|
+
// 折线:0.45–1.95s 按时间画出(smooth:起步和落定都慢,最后一个价格「落」在点上)
|
|
25
|
+
const lp = MO.smooth(MO.seg(lt, 0.45, 1.95));
|
|
26
|
+
const hp = CH.line(c, pts, lp, { col: COL.red, lw: 5, headR: 9, area: { top: F.y, base: F.y + F.h, c0: 'rgba(227,18,11,0.14)', c1: 'rgba(227,18,11,0)' } });
|
|
27
|
+
if (hp) { // 价格标签跟着头走(等宽数字,不抖)
|
|
28
|
+
const v = yS.inv(hp[1]);
|
|
29
|
+
c.save(); c.globalAlpha = 1 - clamp((lt - DUR) / 0.2); // 推进转场一开始就收掉,免得和下一镜右上的价格叠影
|
|
30
|
+
c.font = `700 38px ${NUM}`; c.fillStyle = COL.red; c.textAlign = 'left'; c.textBaseline = 'middle';
|
|
31
|
+
TY.tabular(c, '¥' + v.toFixed(0), hp[0] + 22, hp[1] - 4); c.restore();
|
|
32
|
+
}
|
|
33
|
+
// 事件标注:线头经过 2023 年 3 月(第 26 个月)时触发
|
|
34
|
+
const m26 = xm(26), tHit = 0.45 + 1.5 * invSmooth((m26 - pts[0][0]) / (pts[59][0] - pts[0][0]));
|
|
35
|
+
CH.callout(c, lt, tHit, { x: m26, y: pts[26][1], tx: m26 - 30, ty: pts[26][1] - 150, lines: ['2023.3', '发布自研大模型'], col: COL.ink, dotCol: COL.ink,
|
|
36
|
+
font: `700 34px ${NUM}`, font2: `400 30px ${CN}`, align: 'right', r: 8 });
|
|
37
|
+
c.restore();
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
// smooth 的反函数(二分),用于「线头到达某个 x 的时刻」
|
|
41
|
+
function invSmooth(y) { let a = 0, b = 1; for (let i = 0; i < 30; i++) { const m = (a + b) / 2; if (MO.smooth(m) < y) a = m; else b = m; } return (a + b) / 2; }
|
|
42
|
+
})();
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// t3 · 镜头 3(2.5s,前 0.6s 是从上一镜最新点「推进来」的转场):最近 20 个交易日 K 线。
|
|
2
|
+
// 价格区网格先出 → K 线逐根长出(红涨绿跌,A 股惯例)、成交量同步 → 右上价格跟着最新一根滚动 → 起点参考虚线+区间涨幅标注 → 停 0.75s。
|
|
3
|
+
// (审片后删掉了 5 日均线:2 秒里读不完 K 线+均线+量+括注)
|
|
4
|
+
(() => {
|
|
5
|
+
const { clamp, lerp } = U;
|
|
6
|
+
const W = 1920, H = 1080;
|
|
7
|
+
const L = (() => {
|
|
8
|
+
const { F, KL } = T3;
|
|
9
|
+
const lo = Math.min(...KL.map(k => k.l)), hi = Math.max(...KL.map(k => k.h));
|
|
10
|
+
const ticks = CH.ticks(lo - 4, hi + 4, 4), y0 = ticks[0], y1 = ticks[ticks.length - 1];
|
|
11
|
+
const PB = F.y + F.h * 0.74; // 价格区底
|
|
12
|
+
const yS = CH.lin(y0, y1, PB, F.y + 10);
|
|
13
|
+
const xs = KL.map((_, i) => F.x + 40 + i * ((F.w - 330) / 19));
|
|
14
|
+
return { ticks, yS, xs, PB, VB: F.y + F.h, VT: F.y + F.h * 0.8 };
|
|
15
|
+
})();
|
|
16
|
+
SCENES['t3_s3'] = {
|
|
17
|
+
focus: [L.xs[19], L.yS(286.4)],
|
|
18
|
+
draw(c, lt) {
|
|
19
|
+
const { COL, CN, NUM, F, KL, frame } = T3;
|
|
20
|
+
c.fillStyle = COL.bg; c.fillRect(0, 0, 1920, 1080);
|
|
21
|
+
const z = 1 + 0.03 * lt / 2.5; // 匀速慢推 1→1.03
|
|
22
|
+
c.save(); c.translate(960, 575); c.scale(z, z); c.translate(-960, -575);
|
|
23
|
+
frame(c, lt + 0.6, { title: '最近 20 个交易日:涨了 18.3%', sub: '日 K 线,元 红涨绿跌(A 股惯例) 纵轴未从 0 开始' });
|
|
24
|
+
const PF = { x: F.x, y: F.y, w: F.w, h: L.PB - F.y };
|
|
25
|
+
CH.grid(c, PF, L.ticks, L.yS, MO.seg(lt, 0.1, 0.6), { col: COL.grid, zeroCol: COL.grid, font: `400 30px ${NUM}`, labelCol: '#5b666b', side: 'right', lw: 1.5 });
|
|
26
|
+
// 成交量区基线
|
|
27
|
+
c.fillStyle = COL.ink; c.fillRect(F.x, L.VB - 1, F.w * MO.quintOut(MO.seg(lt, 0.1, 0.6)), 2);
|
|
28
|
+
c.save(); c.font = `400 26px ${CN}`; c.fillStyle = '#7c868b'; c.textAlign = 'right'; c.globalAlpha = MO.seg(lt, 0.3, 0.6); c.fillText('成交量', F.x + F.w, L.VB - 14); c.restore(); // 放右下角空处,不压 K 线
|
|
29
|
+
// K 线 + 成交量:逐根(lag 0.06),0.2–1.3s
|
|
30
|
+
const kp = MO.seg(lt, 0.2, 1.3);
|
|
31
|
+
CH.candles(c, KL, L.xs, L.yS, 30, kp, { up: COL.up, down: COL.down, lag: 0.06 });
|
|
32
|
+
const VMAX = Math.max(...KL.map(k => k.vol));
|
|
33
|
+
KL.forEach((k, i) => { const q = MO.quintOut(MO.lagged(i, 20, kp, 0.06)); if (q <= 0) return;
|
|
34
|
+
const h = (L.VB - L.VT - 6) * k.vol / VMAX * q; // 按最大量归一,量柱不顶到价格区
|
|
35
|
+
c.fillStyle = k.c >= k.o ? 'rgba(227,18,11,.35)' : 'rgba(27,158,90,.35)'; c.fillRect(L.xs[i] - 15, L.VB - h, 30, h); });
|
|
36
|
+
// 右上价格:跟着「最新出现的那根」滚动;涨跌色 = 相对区间起点
|
|
37
|
+
let n = 0; for (let i = 0; i < 20; i++) if (MO.lagged(i, 20, kp, 0.06) > 0) n = i;
|
|
38
|
+
const qn = MO.quintOut(MO.lagged(n, 20, kp, 0.06)), v = lt < 0.2 ? 242 : lerp(KL[n].o, KL[n].c, qn), pct = (v / 242 - 1) * 100;
|
|
39
|
+
c.save(); c.textAlign = 'right'; c.textBaseline = 'alphabetic'; c.font = `700 76px ${NUM}`; c.fillStyle = pct >= 0 ? COL.up : COL.down;
|
|
40
|
+
TY.tabular(c, '¥' + v.toFixed(2), W - 80, 150, { align: 'right' });
|
|
41
|
+
c.font = `700 40px ${NUM}`; TY.tabular(c, (pct >= 0 ? '▲ +' : '▼ ') + pct.toFixed(1) + '%', W - 80, 205, { align: 'right' }); c.restore();
|
|
42
|
+
// 起点参考虚线 + 区间涨幅括注
|
|
43
|
+
const rp = MO.quintOut(MO.seg(lt, 1.35, 1.75)); // 1.75s 落定,停 0.75s 给人读
|
|
44
|
+
if (rp > 0) { const y = L.yS(242); c.save(); c.setLineDash([10, 8]); c.strokeStyle = COL.sub; c.lineWidth = 2; c.beginPath(); c.moveTo(L.xs[0], y); c.lineTo(lerp(L.xs[0], L.xs[19] + 60, rp), y); c.stroke(); c.setLineDash([]);
|
|
45
|
+
const x = L.xs[19] + 60, yt = L.yS(286.4); c.strokeStyle = COL.up; c.lineWidth = 3; c.beginPath(); c.moveTo(x, y); c.lineTo(x, lerp(y, yt, rp)); c.stroke();
|
|
46
|
+
c.globalAlpha = MO.seg(lt, 1.5, 1.8); c.font = `700 40px ${NUM}`; c.fillStyle = COL.up; c.fillText('+18.3%', x + 14, (y + yt) / 2 + 14);
|
|
47
|
+
c.font = `400 26px ${CN}`; c.fillStyle = COL.sub; c.textAlign = 'right'; c.fillText('区间起点 ¥242', x - 14, y + 32); c.restore(); }
|
|
48
|
+
c.restore();
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
})();
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// 示范 · Kurzgesagt 式扁平科普「AI 是怎么学会认猫的」(8 秒三镜)。语法卡:references/动画语法/y1_kurzgesagt.md
|
|
2
|
+
// 预览 index.html?film=demos/y1_kurzgesagt 渲染 render.py --film demos/y1_kurzgesagt --out y1.mp4
|
|
3
|
+
// 镜头按口播切,dur 用秒;解说片不要拍点冲击(PUNCH = 0)。相机运动全在场景里按时间算(CAM),转场只管 A、B 怎么合。
|
|
4
|
+
window.PUNCH = 0;
|
|
5
|
+
window.SCENE_LIBS = ['demos/_shared/hero.js', 'demos/y1_kurzgesagt/kurzgesagt.js'];
|
|
6
|
+
window.ERAS = [
|
|
7
|
+
{ id: 'y1_s1', dur: 2.6 }, // 夜晚山坡:5 层视差慢推,机器人扫描猫
|
|
8
|
+
{ id: 'y1_s2', dur: 2.7, transition: { type: 'lensReveal', dur: 1.0, lens: t => Y1.lensAt(t) } }, // 钻进镜头:相机指数推进眼睛,眼睛里是下一个世界
|
|
9
|
+
{ id: 'y1_s3', dur: 2.7, transition: { type: 'matchCut', dur: 0.9 } }, // 填满再拉出:推满黄色输出节点 → 从黄色的眼睛里拉出
|
|
10
|
+
];
|