dsh-drawai 0.3.4 → 0.4.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/LICENSE +4154 -0
- package/README.md +49 -11
- package/lib/audio-media.js +150 -0
- package/lib/audio-service.js +66 -0
- package/lib/canvas-format.js +134 -0
- package/lib/client.js +5090 -184
- package/lib/comfyui-default-workflow.mjs +1825 -0
- package/lib/comfyui-workflow.mjs +426 -0
- package/lib/document-commands.js +12 -0
- package/lib/document-core.js +29 -0
- package/lib/drawing-runner.js +6 -4
- package/lib/drawing-tasks.js +26 -0
- package/lib/ffmpeg-manager.js +1056 -0
- package/lib/imagegen.mjs +596 -0
- package/lib/index.js +1762 -129
- package/lib/media.js +26 -13
- package/lib/mgstyle-core.js +75 -0
- package/lib/motion/apply.js +181 -0
- package/lib/motion/asset-pack-lock.js +10 -0
- package/lib/motion/asset-pack.js +335 -0
- package/lib/motion/assets.js +291 -0
- package/lib/motion/audio.js +103 -0
- package/lib/motion/audiolevel.js +63 -0
- package/lib/motion/audiomix.js +144 -0
- package/lib/motion/beats.js +338 -0
- package/lib/motion/builtin-assets.js +62 -0
- package/lib/motion/canvas-spec.js +442 -0
- package/lib/motion/capture.js +95 -0
- package/lib/motion/cards.js +80 -0
- package/lib/motion/collect.js +449 -0
- package/lib/motion/delivery.js +140 -0
- package/lib/motion/edge-speech.py +90 -0
- package/lib/motion/entry.jsx +73 -0
- package/lib/motion/export.js +200 -0
- package/lib/motion/ffmpeg.js +43 -0
- package/lib/motion/fonts.js +71 -0
- package/lib/motion/jobs.js +117 -0
- package/lib/motion/json.js +4 -0
- package/lib/motion/media-catalog.js +59 -0
- package/lib/motion/mgstyles/BRIEF-TEMPLATE.md +63 -0
- package/lib/motion/mgstyles/briefs/01-flat-vector.md +104 -0
- package/lib/motion/mgstyles/briefs/02-line-art.md +97 -0
- package/lib/motion/mgstyles/briefs/03-isometric.md +108 -0
- package/lib/motion/mgstyles/briefs/05-cel-boil.md +145 -0
- package/lib/motion/mgstyles/briefs/06-collage.md +149 -0
- package/lib/motion/mgstyles/briefs/07-liquid.md +106 -0
- package/lib/motion/mgstyles/briefs/08-morph.md +111 -0
- package/lib/motion/mgstyles/briefs/09-bauhaus.md +150 -0
- package/lib/motion/mgstyles/briefs/10-synthwave.md +151 -0
- package/lib/motion/mgstyles/briefs/12-aurora-glass.md +147 -0
- package/lib/motion/mgstyles/briefs/18-hanazi.md +140 -0
- package/lib/motion/mgstyles/briefs/19-paperclip.md +156 -0
- package/lib/motion/mgstyles/briefs/20-pixel.md +118 -0
- package/lib/motion/mgstyles/briefs/22-hud.md +118 -0
- package/lib/motion/mgstyles/catalog.d/01-flat-vector.json +34 -0
- package/lib/motion/mgstyles/catalog.d/02-line-art.json +34 -0
- package/lib/motion/mgstyles/catalog.d/03-isometric.json +35 -0
- package/lib/motion/mgstyles/catalog.d/05-cel-boil.json +28 -0
- package/lib/motion/mgstyles/catalog.d/06-collage.json +28 -0
- package/lib/motion/mgstyles/catalog.d/07-liquid.json +28 -0
- package/lib/motion/mgstyles/catalog.d/08-morph.json +28 -0
- package/lib/motion/mgstyles/catalog.d/09-bauhaus.json +28 -0
- package/lib/motion/mgstyles/catalog.d/10-synthwave.json +28 -0
- package/lib/motion/mgstyles/catalog.d/12-aurora-glass.json +28 -0
- package/lib/motion/mgstyles/catalog.d/18-hanazi.json +28 -0
- package/lib/motion/mgstyles/catalog.d/19-paperclip.json +28 -0
- package/lib/motion/mgstyles/catalog.d/20-pixel.json +28 -0
- package/lib/motion/mgstyles/catalog.d/22-hud.json +28 -0
- package/lib/motion/mgstyles/catalog.json +1356 -0
- package/lib/motion/mgstyles/upstream/README.md +147 -0
- package/lib/motion/mgstyles/upstream/README.zh-CN.md +147 -0
- package/lib/motion/mgstyles/upstream/demos/01-flat-vector/cues.json +1 -0
- package/lib/motion/mgstyles/upstream/demos/01-flat-vector/index.html +712 -0
- package/lib/motion/mgstyles/upstream/demos/02-line-art/cues.json +331 -0
- package/lib/motion/mgstyles/upstream/demos/02-line-art/film.js +676 -0
- package/lib/motion/mgstyles/upstream/demos/02-line-art/index.html +18 -0
- package/lib/motion/mgstyles/upstream/demos/02-line-art/tools/dump_timing.mjs +26 -0
- package/lib/motion/mgstyles/upstream/demos/03-isometric/cues.json +109 -0
- package/lib/motion/mgstyles/upstream/demos/03-isometric/index.html +25 -0
- package/lib/motion/mgstyles/upstream/demos/03-isometric/js/anim.js +82 -0
- package/lib/motion/mgstyles/upstream/demos/03-isometric/js/main.js +219 -0
- package/lib/motion/mgstyles/upstream/demos/03-isometric/js/night5.js +180 -0
- package/lib/motion/mgstyles/upstream/demos/03-isometric/js/render.js +202 -0
- package/lib/motion/mgstyles/upstream/demos/03-isometric/js/title.js +167 -0
- package/lib/motion/mgstyles/upstream/demos/03-isometric/js/title5.js +294 -0
- package/lib/motion/mgstyles/upstream/demos/03-isometric/js/ui.js +141 -0
- package/lib/motion/mgstyles/upstream/demos/03-isometric/js/world.js +1399 -0
- package/lib/motion/mgstyles/upstream/demos/05-cel-boil/cues.json +157 -0
- package/lib/motion/mgstyles/upstream/demos/05-cel-boil/index.html +34 -0
- package/lib/motion/mgstyles/upstream/demos/05-cel-boil/js/engine.js +326 -0
- package/lib/motion/mgstyles/upstream/demos/05-cel-boil/js/scene.js +2036 -0
- package/lib/motion/mgstyles/upstream/demos/06-collage/assets/gen/layout.json +157 -0
- package/lib/motion/mgstyles/upstream/demos/06-collage/cues.json +80 -0
- package/lib/motion/mgstyles/upstream/demos/06-collage/index.html +889 -0
- package/lib/motion/mgstyles/upstream/demos/07-liquid/cues.json +100 -0
- package/lib/motion/mgstyles/upstream/demos/07-liquid/index.html +108 -0
- package/lib/motion/mgstyles/upstream/demos/07-liquid/js/engine.js +153 -0
- package/lib/motion/mgstyles/upstream/demos/07-liquid/js/links.js +64 -0
- package/lib/motion/mgstyles/upstream/demos/07-liquid/js/lookdev.js +46 -0
- package/lib/motion/mgstyles/upstream/demos/07-liquid/js/scene.js +963 -0
- package/lib/motion/mgstyles/upstream/demos/07-liquid/js/shaders.js +647 -0
- package/lib/motion/mgstyles/upstream/demos/07-liquid/js/textsdf.js +114 -0
- package/lib/motion/mgstyles/upstream/demos/07-liquid/js/type.js +50 -0
- package/lib/motion/mgstyles/upstream/demos/08-morph/cues.json +131 -0
- package/lib/motion/mgstyles/upstream/demos/08-morph/glyphs.json +1 -0
- package/lib/motion/mgstyles/upstream/demos/08-morph/index.html +901 -0
- package/lib/motion/mgstyles/upstream/demos/09-bauhaus/cues.json +270 -0
- package/lib/motion/mgstyles/upstream/demos/09-bauhaus/film.js +697 -0
- package/lib/motion/mgstyles/upstream/demos/09-bauhaus/index.html +12 -0
- package/lib/motion/mgstyles/upstream/demos/10-synthwave/cues.json +44 -0
- package/lib/motion/mgstyles/upstream/demos/10-synthwave/index.html +1028 -0
- package/lib/motion/mgstyles/upstream/demos/12-aurora-glass/cues.json +67 -0
- package/lib/motion/mgstyles/upstream/demos/12-aurora-glass/index.html +16 -0
- package/lib/motion/mgstyles/upstream/demos/12-aurora-glass/main.js +967 -0
- package/lib/motion/mgstyles/upstream/demos/12-aurora-glass/shaders.js +468 -0
- package/lib/motion/mgstyles/upstream/demos/18-hanazi/cues.json +117 -0
- package/lib/motion/mgstyles/upstream/demos/18-hanazi/index.html +541 -0
- package/lib/motion/mgstyles/upstream/demos/19-paperclip/assets/countries-110m.json +1 -0
- package/lib/motion/mgstyles/upstream/demos/19-paperclip/assets/stickers/meta.json +34 -0
- package/lib/motion/mgstyles/upstream/demos/19-paperclip/cues.json +285 -0
- package/lib/motion/mgstyles/upstream/demos/19-paperclip/index.html +599 -0
- package/lib/motion/mgstyles/upstream/demos/20-pixel/cues.json +42 -0
- package/lib/motion/mgstyles/upstream/demos/20-pixel/film.js +914 -0
- package/lib/motion/mgstyles/upstream/demos/20-pixel/index.html +18 -0
- package/lib/motion/mgstyles/upstream/demos/22-hud/cues.json +108 -0
- package/lib/motion/mgstyles/upstream/demos/22-hud/index.html +125 -0
- package/lib/motion/mgstyles/upstream/demos/22-hud/js/holo.js +275 -0
- package/lib/motion/mgstyles/upstream/demos/22-hud/js/hud.js +855 -0
- package/lib/motion/mgstyles/upstream/demos/22-hud/js/post.js +150 -0
- package/lib/motion/mgstyles/upstream/demos/22-hud/js/util.js +65 -0
- package/lib/motion/mgstyles/upstream/demos/22-hud/js/v5.js +142 -0
- package/lib/motion/mgstyles/upstream/harness/render.mjs +319 -0
- package/lib/motion/mgstyles/upstream/manifest.json +269 -0
- package/lib/motion/mgstyles/upstream/prompts/01-flat-vector.md +98 -0
- package/lib/motion/mgstyles/upstream/prompts/02-line-art.md +95 -0
- package/lib/motion/mgstyles/upstream/prompts/03-isometric.md +97 -0
- package/lib/motion/mgstyles/upstream/prompts/05-cel-boil.md +95 -0
- package/lib/motion/mgstyles/upstream/prompts/06-collage.md +95 -0
- package/lib/motion/mgstyles/upstream/prompts/07-liquid.md +98 -0
- package/lib/motion/mgstyles/upstream/prompts/08-morph.md +95 -0
- package/lib/motion/mgstyles/upstream/prompts/09-bauhaus.md +96 -0
- package/lib/motion/mgstyles/upstream/prompts/10-synthwave.md +95 -0
- package/lib/motion/mgstyles/upstream/prompts/12-aurora-glass.md +96 -0
- package/lib/motion/mgstyles/upstream/prompts/18-hanazi.md +95 -0
- package/lib/motion/mgstyles/upstream/prompts/19-paperclip.md +96 -0
- package/lib/motion/mgstyles/upstream/prompts/20-pixel.md +96 -0
- package/lib/motion/mgstyles/upstream/prompts/22-hud.md +95 -0
- package/lib/motion/mgstyles/upstream/rubric.md +51 -0
- package/lib/motion/mgstyles/upstream/template.md +36 -0
- package/lib/motion/pixelqa.js +198 -0
- package/lib/motion/preview.js +97 -0
- package/lib/motion/project.js +395 -0
- package/lib/motion/qa.js +290 -0
- package/lib/motion/reference-media.jsx +10 -0
- package/lib/motion/render-settings.js +112 -0
- package/lib/motion/render.js +161 -0
- package/lib/motion/runtime/package-lock.json +3058 -0
- package/lib/motion/runtime/package.json +16 -0
- package/lib/motion/scene-kit.js +183 -0
- package/lib/motion/sfx.js +232 -0
- package/lib/motion/shotcraft/ClipCard.tsx +204 -0
- package/lib/motion/shotcraft/catalog.json +2461 -0
- package/lib/motion/shotcraft/upstream/SKILL.md +286 -0
- package/lib/motion/shotcraft/upstream/assets/lib/Caption.tsx +54 -0
- package/lib/motion/shotcraft/upstream/assets/lib/ClipCard.tsx +200 -0
- package/lib/motion/shotcraft/upstream/assets/lib/DigitRoll.tsx +45 -0
- package/lib/motion/shotcraft/upstream/assets/lib/FlashCut.tsx +20 -0
- package/lib/motion/shotcraft/upstream/assets/lib/FlatPanel.tsx +65 -0
- package/lib/motion/shotcraft/upstream/assets/lib/PageCam.tsx +151 -0
- package/lib/motion/shotcraft/upstream/assets/lib/VerticalTicker.tsx +129 -0
- package/lib/motion/shotcraft/upstream/assets/lib/helpers/camera.tsx +75 -0
- package/lib/motion/shotcraft/upstream/assets/lib/helpers/motion.ts +40 -0
- package/lib/motion/shotcraft/upstream/assets/lib/helpers/rand.ts +11 -0
- package/lib/motion/shotcraft/upstream/assets/lib/helpers/shake.ts +10 -0
- package/lib/motion/shotcraft/upstream/assets/scripts/__pycache__/sfx-source.cpython-313.pyc +0 -0
- package/lib/motion/shotcraft/upstream/assets/scripts/build-readme-cover.mjs +49 -0
- package/lib/motion/shotcraft/upstream/assets/scripts/capture-template.mjs +210 -0
- package/lib/motion/shotcraft/upstream/assets/scripts/sfx-source.py +423 -0
- package/lib/motion/shotcraft/upstream/assets/scripts/smoke-render-demos.py +170 -0
- package/lib/motion/shotcraft/upstream/assets/scripts/test_sfx_source.py +157 -0
- package/lib/motion/shotcraft/upstream/demos/README.md +120 -0
- package/lib/motion/shotcraft/upstream/demos/_fixtures/Brand.tsx +112 -0
- package/lib/motion/shotcraft/upstream/demos/_fixtures/Fixtures.tsx +647 -0
- package/lib/motion/shotcraft/upstream/demos/_fixtures/Look.tsx +316 -0
- package/lib/motion/shotcraft/upstream/demos/_fixtures/Motion.tsx +82 -0
- package/lib/motion/shotcraft/upstream/demos/_fixtures/PageCam2D.tsx +115 -0
- package/lib/motion/shotcraft/upstream/demos/_fixtures/Polish.tsx +243 -0
- package/lib/motion/shotcraft/upstream/demos/_textures/live-layout.json +389 -0
- package/lib/motion/shotcraft/upstream/demos/camera/basic-3d-scene/Basic3DScene.tsx +250 -0
- package/lib/motion/shotcraft/upstream/demos/camera/crash-zoom-punch/CrashImpactReal.tsx +305 -0
- package/lib/motion/shotcraft/upstream/demos/camera/crash-zoom-punch/CrashZoomReal.tsx +246 -0
- package/lib/motion/shotcraft/upstream/demos/camera/cursor-flyover/CursorFlyover.tsx +390 -0
- package/lib/motion/shotcraft/upstream/demos/camera/depth-layer-moves/MultiplaneReal.tsx +138 -0
- package/lib/motion/shotcraft/upstream/demos/camera/graze-face-tour/GrazeFaceTour.tsx +542 -0
- package/lib/motion/shotcraft/upstream/demos/camera/overhead-camera-moves/OverheadTabletopDrop.tsx +315 -0
- package/lib/motion/shotcraft/upstream/demos/camera/overhead-camera-moves/TiltReveal.tsx +299 -0
- package/lib/motion/shotcraft/upstream/demos/camera/space-camera-moves/DroneDiveLanding.tsx +173 -0
- package/lib/motion/shotcraft/upstream/demos/camera/space-camera-moves/ExplodedView.tsx +348 -0
- package/lib/motion/shotcraft/upstream/demos/camera/steep-tilt-glide/SteepTiltGlide.tsx +366 -0
- package/lib/motion/shotcraft/upstream/demos/camera/tension-camera-moves/BulletTimeFreezeOrbit.tsx +279 -0
- package/lib/motion/shotcraft/upstream/demos/camera/tension-camera-moves/PullBackIsolation.tsx +184 -0
- package/lib/motion/shotcraft/upstream/demos/camera/terminal-3d/Terminal3D.tsx +390 -0
- package/lib/motion/shotcraft/upstream/demos/data/before-after-slider-scrub/BeforeAfterSliderScrub.tsx +155 -0
- package/lib/motion/shotcraft/upstream/demos/data/chart-live-moves/AxisRescaleShockV2.tsx +303 -0
- package/lib/motion/shotcraft/upstream/demos/data/chart-live-moves/OscilloscopeStreamV2.tsx +290 -0
- package/lib/motion/shotcraft/upstream/demos/data/chart-live-moves/UnitDotSwarmRegroupV2.tsx +278 -0
- package/lib/motion/shotcraft/upstream/demos/data/gauge-readout-moves/NeedleSweepSelftest.tsx +307 -0
- package/lib/motion/shotcraft/upstream/demos/data/gauge-readout-moves/TapeScrollFixedPointer.tsx +215 -0
- package/lib/motion/shotcraft/upstream/demos/data/scroll-brake-moves/BrakeReticleLock.tsx +299 -0
- package/lib/motion/shotcraft/upstream/demos/data/scroll-brake-moves/ChangelogScrollBrake.tsx +232 -0
- package/lib/motion/shotcraft/upstream/demos/data/timeline-travel/TimelineTravel.tsx +290 -0
- package/lib/motion/shotcraft/upstream/demos/effects/assemble-then-type-flyin/AssembleThenTypeFlyin.tsx +273 -0
- package/lib/motion/shotcraft/upstream/demos/effects/aurora-bloom-bg-flip/AuroraBloomBgFlip.tsx +167 -0
- package/lib/motion/shotcraft/upstream/demos/effects/brand-frame-snap/BrandFrameSnap.tsx +536 -0
- package/lib/motion/shotcraft/upstream/demos/effects/fui-hud-moves/ReticleLockOn.tsx +164 -0
- package/lib/motion/shotcraft/upstream/demos/effects/glow-flyline-moves/FlylineArc.tsx +175 -0
- package/lib/motion/shotcraft/upstream/demos/effects/glow-flyline-moves/GlowOrbAmbient.tsx +197 -0
- package/lib/motion/shotcraft/upstream/demos/effects/glow-flyline-moves/OrbFlylineRelay.tsx +241 -0
- package/lib/motion/shotcraft/upstream/demos/effects/icon-performance-moves/AttentionBounce.tsx +279 -0
- package/lib/motion/shotcraft/upstream/demos/effects/impact-feedback/AnimeImpact.tsx +230 -0
- package/lib/motion/shotcraft/upstream/demos/effects/impact-feedback/HitCounter.tsx +345 -0
- package/lib/motion/shotcraft/upstream/demos/effects/light-play-moves/SheenSweepRetry.tsx +275 -0
- package/lib/motion/shotcraft/upstream/demos/effects/light-play-moves/SpotlightSweepReveal.tsx +229 -0
- package/lib/motion/shotcraft/upstream/demos/effects/radial-ripple-phone-chips/RadialRipplePhoneChips.tsx +312 -0
- package/lib/motion/shotcraft/upstream/demos/effects/riso-print-hits/RisoMisregistrationHit.tsx +222 -0
- package/lib/motion/shotcraft/upstream/demos/effects/scan-bracket-sweep/ScanBracketSweep.tsx +295 -0
- package/lib/motion/shotcraft/upstream/demos/effects/scanline-annotate-focus/ScanlineAnnotateFocus.tsx +329 -0
- package/lib/motion/shotcraft/upstream/demos/effects/scanline-assemble-flyin/ScanlineAssembleFlyin.tsx +315 -0
- package/lib/motion/shotcraft/upstream/demos/effects/slam-entrance-moves/ImpactBurstKit.tsx +264 -0
- package/lib/motion/shotcraft/upstream/demos/effects/slam-entrance-moves/KanadaPerspectiveSnap.tsx +260 -0
- package/lib/motion/shotcraft/upstream/demos/effects/slam-entrance-moves/ScoreSlam.tsx +263 -0
- package/lib/motion/shotcraft/upstream/demos/effects/spotlight-sweep-moves/CornerSpotlightReveal.tsx +123 -0
- package/lib/motion/shotcraft/upstream/demos/effects/spotlight-sweep-moves/GlowWakeSleepPanel.tsx +187 -0
- package/lib/motion/shotcraft/upstream/demos/effects/spotlight-sweep-moves/SlideSpotlightPan.tsx +175 -0
- package/lib/motion/shotcraft/upstream/demos/interaction/autolayout-gap-dial/AutolayoutGapDial.tsx +305 -0
- package/lib/motion/shotcraft/upstream/demos/interaction/canvas-materialize-moves/DiagramCascadeBuild.tsx +350 -0
- package/lib/motion/shotcraft/upstream/demos/interaction/canvas-materialize-moves/PanelToCanvasMaterialize.tsx +352 -0
- package/lib/motion/shotcraft/upstream/demos/interaction/chip-grid-single-select-blackout/ChipGridSingleSelectBlackout.tsx +218 -0
- package/lib/motion/shotcraft/upstream/demos/interaction/collab-cursor-moves/CursorCastEnsemble.tsx +297 -0
- package/lib/motion/shotcraft/upstream/demos/interaction/glass-pill-dictation-typing/GlassPillDictationTyping.tsx +157 -0
- package/lib/motion/shotcraft/upstream/demos/interaction/hashtag-to-pill-materialize/HashtagToPillMaterialize.tsx +218 -0
- package/lib/motion/shotcraft/upstream/demos/interaction/picker-carousel-feature-cycle/PickerCarouselFeatureCycle.tsx +202 -0
- package/lib/motion/shotcraft/upstream/demos/interaction/segmented-thumb-hero/SegmentedThumbHero.tsx +265 -0
- package/lib/motion/shotcraft/upstream/demos/interaction/theme-switch-moves/PaletteThemeRipple.tsx +457 -0
- package/lib/motion/shotcraft/upstream/demos/interaction/theme-switch-moves/ThemeSweepToggle.tsx +446 -0
- package/lib/motion/shotcraft/upstream/demos/interaction/type-and-filter/TypeAndFilter.tsx +249 -0
- package/lib/motion/shotcraft/upstream/demos/interaction/voice-waveform-live/VoiceWaveformLive.tsx +278 -0
- package/lib/motion/shotcraft/upstream/demos/opening/crane-rise-reveal/CraneRiseReveal.tsx +332 -0
- package/lib/motion/shotcraft/upstream/demos/opening/dataviz-landscape-open/DatavizLandscapeOpen.tsx +358 -0
- package/lib/motion/shotcraft/upstream/demos/opening/fracture/Fracture.tsx +201 -0
- package/lib/motion/shotcraft/upstream/demos/opening/icon-field-colorize/IconFieldColorize.tsx +200 -0
- package/lib/motion/shotcraft/upstream/demos/opening/letterspace-materialize/LetterspaceMaterialize.tsx +208 -0
- package/lib/motion/shotcraft/upstream/demos/opening/magician-card-flourish/MagicianCardFlourish.tsx +341 -0
- package/lib/motion/shotcraft/upstream/demos/opening/orbit-ring-title-open/OrbitRingTitleOpen.tsx +389 -0
- package/lib/motion/shotcraft/upstream/demos/opening/spotlight-hero-card/SpotlightHeroCard.tsx +293 -0
- package/lib/motion/shotcraft/upstream/demos/opening/stroke-segment-build/StrokeSegmentBuild.tsx +183 -0
- package/lib/motion/shotcraft/upstream/demos/opening/text-as-mask/TextAsMask.tsx +245 -0
- package/lib/motion/shotcraft/upstream/demos/outro/grain-dissolve/GrainDissolve.tsx +222 -0
- package/lib/motion/shotcraft/upstream/demos/outro/logo-shrink-wordmark-lockup/LogoShrinkWordmarkLockup.tsx +223 -0
- package/lib/motion/shotcraft/upstream/demos/outro/neon-triple-marquee/NeonTripleMarquee.tsx +217 -0
- package/lib/motion/shotcraft/upstream/demos/outro/outro-group-photo-launch/OutroGroupPhotoLaunch.tsx +343 -0
- package/lib/motion/shotcraft/upstream/demos/outro/ui-strip-away-outro/UiStripAwayOutro.tsx +357 -0
- package/lib/motion/shotcraft/upstream/demos/outro/ui-to-brand-morph/IconFlipBloomLogo.tsx +187 -0
- package/lib/motion/shotcraft/upstream/demos/outro/ui-to-brand-morph/InputMorphsIntoLogo.tsx +333 -0
- package/lib/motion/shotcraft/upstream/demos/rhythm/beat-cut-moves/PaparazziFlash.tsx +274 -0
- package/lib/motion/shotcraft/upstream/demos/rhythm/beat-step-list-theme-cycle/BeatStepListThemeCycle.tsx +270 -0
- package/lib/motion/shotcraft/upstream/demos/rhythm/panel-grid-moves/ComicPanelSplit.tsx +430 -0
- package/lib/motion/shotcraft/upstream/demos/rhythm/quad-split-parallel-scenes/QuadSplitParallelScenes.tsx +252 -0
- package/lib/motion/shotcraft/upstream/demos/rhythm/rhythm-interrupt-moves/JumpCutPunchIn.tsx +106 -0
- package/lib/motion/shotcraft/upstream/demos/rhythm/sakuga-timing-shift/SakugaTimingShift.tsx +288 -0
- package/lib/motion/shotcraft/upstream/demos/rhythm/speed-ramp-freeze/FreezeAnnotateReal.tsx +362 -0
- package/lib/motion/shotcraft/upstream/demos/rhythm/trailer-grammar-moves/TrailerBumper.tsx +168 -0
- package/lib/motion/shotcraft/upstream/demos/transition/bottom-push-stack-wipe/BottomPushStackWipe.tsx +310 -0
- package/lib/motion/shotcraft/upstream/demos/transition/card-flip-reveal/CardFlipReveal.tsx +261 -0
- package/lib/motion/shotcraft/upstream/demos/transition/card-flock-tumble/CardFlockTumble.tsx +459 -0
- package/lib/motion/shotcraft/upstream/demos/transition/circle-match-iris/CircleMatchIris.tsx +294 -0
- package/lib/motion/shotcraft/upstream/demos/transition/gradient-transition/GradientTransition.tsx +161 -0
- package/lib/motion/shotcraft/upstream/demos/transition/line-carry-transition/LineCarryTransition.tsx +248 -0
- package/lib/motion/shotcraft/upstream/demos/transition/mosaic-reframe/MosaicReframe.tsx +359 -0
- package/lib/motion/shotcraft/upstream/demos/transition/page-turn-transitions/BarnDoorSplit.tsx +227 -0
- package/lib/motion/shotcraft/upstream/demos/transition/print-texture-transitions/InkBleedReveal.tsx +162 -0
- package/lib/motion/shotcraft/upstream/demos/transition/shot-transitions/PortalWipeV2.tsx +248 -0
- package/lib/motion/shotcraft/upstream/demos/transition/shot-transitions/WhipBrakeReal.tsx +186 -0
- package/lib/motion/shotcraft/upstream/demos/transition/tear-streak-transitions/GlitchDisplace.tsx +355 -0
- package/lib/motion/shotcraft/upstream/demos/transition/transition-hidden-cut/InvisibleCut.tsx +272 -0
- package/lib/motion/shotcraft/upstream/demos/transition/transition-hidden-cut/LightLeakBurn.tsx +262 -0
- package/lib/motion/shotcraft/upstream/demos/transition/transition-hidden-cut/VersusSlam.tsx +217 -0
- package/lib/motion/shotcraft/upstream/demos/transition/transition-travel/LetterformZoom.tsx +285 -0
- package/lib/motion/shotcraft/upstream/demos/transition/white-flash-logo-simplify-cut/WhiteFlashLogoSimplifyCut.tsx +205 -0
- package/lib/motion/shotcraft/upstream/demos/transition/wipe-transitions/BlindsSlice.tsx +178 -0
- package/lib/motion/shotcraft/upstream/demos/typography/blur-slide/BlurSlide.tsx +147 -0
- package/lib/motion/shotcraft/upstream/demos/typography/brace-expand/BraceExpand.tsx +143 -0
- package/lib/motion/shotcraft/upstream/demos/typography/brand-ink-open/BrandInkOpen.tsx +134 -0
- package/lib/motion/shotcraft/upstream/demos/typography/countdown-arc-scatter/CountdownArcScatter.tsx +217 -0
- package/lib/motion/shotcraft/upstream/demos/typography/flying-words/FlyingWords.tsx +198 -0
- package/lib/motion/shotcraft/upstream/demos/typography/glitch-cycle/GlitchCycle.tsx +221 -0
- package/lib/motion/shotcraft/upstream/demos/typography/gradient-word-sweep/GradientWordSweep.tsx +312 -0
- package/lib/motion/shotcraft/upstream/demos/typography/lead-word-zoom-assemble/LeadWordZoomAssemble.tsx +261 -0
- package/lib/motion/shotcraft/upstream/demos/typography/marker-underline-title/MarkerUnderlineTitle.tsx +121 -0
- package/lib/motion/shotcraft/upstream/demos/typography/outline-word-fill/OutlineWordFill.tsx +153 -0
- package/lib/motion/shotcraft/upstream/demos/typography/paper-title-card/PaperTitleCard.tsx +179 -0
- package/lib/motion/shotcraft/upstream/demos/typography/pill-chip-slot-cycle-handled/PillChipSlotCycleHandled.tsx +140 -0
- package/lib/motion/shotcraft/upstream/demos/typography/pill-slot-cycle/PillSlotCycle.tsx +309 -0
- package/lib/motion/shotcraft/upstream/demos/typography/text-column-converge/TextColumnConverge.tsx +191 -0
- package/lib/motion/shotcraft/upstream/demos/typography/title-demote-to-label/TitleDemoteToLabel.tsx +292 -0
- package/lib/motion/shotcraft/upstream/demos/typography/type-assembly-moves/LetterformDriftAssembly.tsx +135 -0
- package/lib/motion/shotcraft/upstream/demos/typography/type-assembly-moves/SplitTextStagger.tsx +124 -0
- package/lib/motion/shotcraft/upstream/demos/typography/type-assembly-moves/TextOnPath.tsx +255 -0
- package/lib/motion/shotcraft/upstream/demos/typography/type-entrance-moves/LetterDropPhysics.tsx +173 -0
- package/lib/motion/shotcraft/upstream/demos/typography/type-rhythm-sync/FontWeightPump.tsx +225 -0
- package/lib/motion/shotcraft/upstream/demos/typography/type-rhythm-sync/KaraokeFillSync.tsx +141 -0
- package/lib/motion/shotcraft/upstream/demos/typography/typewriter-moves/TypewriterErrorRetype.tsx +137 -0
- package/lib/motion/shotcraft/upstream/demos/typography/vertical-word-roll-blur-cycle/VerticalWordRollBlurCycle.tsx +147 -0
- package/lib/motion/shotcraft/upstream/demos/typography/word-relay-filmstrip/WordRelayFilmstrip.tsx +409 -0
- package/lib/motion/shotcraft/upstream/demos/typography/word-relay-geometry/WordRelayGeometry.tsx +280 -0
- package/lib/motion/shotcraft/upstream/demos/ui-entrance/avatar-bracket-carousel/AvatarBracketCarousel.tsx +271 -0
- package/lib/motion/shotcraft/upstream/demos/ui-entrance/bezier-source-converge-merge/BezierSourceConvergeMerge.tsx +385 -0
- package/lib/motion/shotcraft/upstream/demos/ui-entrance/card-stack/CardStack.tsx +312 -0
- package/lib/motion/shotcraft/upstream/demos/ui-entrance/carousel-3d/Carousel3D.tsx +303 -0
- package/lib/motion/shotcraft/upstream/demos/ui-entrance/clipcard-looping/ClipCardLooping.tsx +77 -0
- package/lib/motion/shotcraft/upstream/demos/ui-entrance/cloner-depth-echo/ClonerDepthEcho.tsx +311 -0
- package/lib/motion/shotcraft/upstream/demos/ui-entrance/deck-deal-flyin/DeckDealFlyin.tsx +307 -0
- package/lib/motion/shotcraft/upstream/demos/ui-entrance/doc-park-left-pill-deal/DocParkLeftPillDeal.tsx +349 -0
- package/lib/motion/shotcraft/upstream/demos/ui-entrance/document-typewriter-reveal/DocumentTypewriterReveal.tsx +255 -0
- package/lib/motion/shotcraft/upstream/demos/ui-entrance/draw-svg-trace/DrawSvgTrace.tsx +244 -0
- package/lib/motion/shotcraft/upstream/demos/ui-entrance/element-body-moves/ContactShadowLift.tsx +217 -0
- package/lib/motion/shotcraft/upstream/demos/ui-entrance/integration-hub-map/IntegrationHubMap.tsx +652 -0
- package/lib/motion/shotcraft/upstream/demos/ui-entrance/list-reveal/ListReveal.tsx +153 -0
- package/lib/motion/shotcraft/upstream/demos/ui-entrance/list-stack-press/ListStackPress.tsx +238 -0
- package/lib/motion/shotcraft/upstream/demos/ui-entrance/neon-frame-forerun/NeonFrameForerun.tsx +324 -0
- package/lib/motion/shotcraft/upstream/demos/ui-entrance/neon-frame-orbit-drop/NeonFrameForerunOrbit.tsx +354 -0
- package/lib/motion/shotcraft/upstream/demos/ui-entrance/page-waterfall-wall/PageWaterfallWall.tsx +101 -0
- package/lib/motion/shotcraft/upstream/demos/ui-entrance/page-waterfall-wall/VerticalTicker.tsx +129 -0
- package/lib/motion/shotcraft/upstream/demos/ui-entrance/product-card-progressive-assemble/ProductCardProgressiveAssemble.tsx +297 -0
- package/lib/motion/shotcraft/upstream/demos/ui-entrance/radial-wave/RadialWave.tsx +57 -0
- package/lib/motion/shotcraft/upstream/demos/ui-entrance/research-card-stack-scroll/ResearchCardStackScroll.tsx +155 -0
- package/lib/motion/shotcraft/upstream/demos/ui-entrance/row-embed/RowEmbed.tsx +175 -0
- package/lib/motion/shotcraft/upstream/demos/ui-entrance/value-stagger-gradient/ValueStaggerGradient.tsx +153 -0
- package/lib/motion/shotcraft/upstream/demos/ui-entrance/wall-reveal-moves/BentoLightUp.tsx +146 -0
- package/lib/motion/shotcraft/upstream/demos/ui-entrance/wall-reveal-moves/WireframeDrawOn.tsx +226 -0
- package/lib/motion/shotcraft/upstream/gallery/api/library.json +1 -0
- package/lib/motion/shotcraft/upstream/manifest.json +2715 -0
- package/lib/motion/shotcraft/upstream/references/aesthetic-rules.md +193 -0
- package/lib/motion/shotcraft/upstream/references/final-review.md +121 -0
- package/lib/motion/shotcraft/upstream/references/guided-free-creation.md +199 -0
- package/lib/motion/shotcraft/upstream/references/jianying-export.md +183 -0
- package/lib/motion/shotcraft/upstream/references/music-beat-sync.md +257 -0
- package/lib/motion/shotcraft/upstream/references/pipeline.md +382 -0
- package/lib/motion/shotcraft/upstream/references/publish-upload-post.md +111 -0
- package/lib/motion/shotcraft/upstream/references/sequences/promo-energy-arc.md +50 -0
- package/lib/motion/shotcraft/upstream/references/sfx-sourcing.md +95 -0
- package/lib/motion/shotcraft/upstream/references/shots/camera/basic-3d-scene.md +41 -0
- package/lib/motion/shotcraft/upstream/references/shots/camera/crash-zoom-punch.md +52 -0
- package/lib/motion/shotcraft/upstream/references/shots/camera/cursor-flyover.md +39 -0
- package/lib/motion/shotcraft/upstream/references/shots/camera/depth-layer-moves.md +39 -0
- package/lib/motion/shotcraft/upstream/references/shots/camera/graze-face-tour.md +57 -0
- package/lib/motion/shotcraft/upstream/references/shots/camera/overhead-camera-moves.md +51 -0
- package/lib/motion/shotcraft/upstream/references/shots/camera/space-camera-moves.md +46 -0
- package/lib/motion/shotcraft/upstream/references/shots/camera/steep-tilt-glide.md +52 -0
- package/lib/motion/shotcraft/upstream/references/shots/camera/tension-camera-moves.md +43 -0
- package/lib/motion/shotcraft/upstream/references/shots/camera/terminal-3d.md +42 -0
- package/lib/motion/shotcraft/upstream/references/shots/data/before-after-slider-scrub.md +48 -0
- package/lib/motion/shotcraft/upstream/references/shots/data/chart-live-moves.md +52 -0
- package/lib/motion/shotcraft/upstream/references/shots/data/gauge-readout-moves.md +45 -0
- package/lib/motion/shotcraft/upstream/references/shots/data/scroll-brake-moves.md +46 -0
- package/lib/motion/shotcraft/upstream/references/shots/data/timeline-travel.md +44 -0
- package/lib/motion/shotcraft/upstream/references/shots/effects/assemble-then-type-flyin.md +63 -0
- package/lib/motion/shotcraft/upstream/references/shots/effects/aurora-bloom-bg-flip.md +54 -0
- package/lib/motion/shotcraft/upstream/references/shots/effects/brand-frame-snap.md +58 -0
- package/lib/motion/shotcraft/upstream/references/shots/effects/fui-hud-moves.md +35 -0
- package/lib/motion/shotcraft/upstream/references/shots/effects/glow-flyline-moves.md +53 -0
- package/lib/motion/shotcraft/upstream/references/shots/effects/icon-performance-moves.md +42 -0
- package/lib/motion/shotcraft/upstream/references/shots/effects/impact-feedback.md +50 -0
- package/lib/motion/shotcraft/upstream/references/shots/effects/light-play-moves.md +46 -0
- package/lib/motion/shotcraft/upstream/references/shots/effects/radial-ripple-phone-chips.md +56 -0
- package/lib/motion/shotcraft/upstream/references/shots/effects/riso-print-hits.md +49 -0
- package/lib/motion/shotcraft/upstream/references/shots/effects/scan-bracket-sweep.md +50 -0
- package/lib/motion/shotcraft/upstream/references/shots/effects/scanline-annotate-focus.md +53 -0
- package/lib/motion/shotcraft/upstream/references/shots/effects/scanline-assemble-flyin.md +53 -0
- package/lib/motion/shotcraft/upstream/references/shots/effects/slam-entrance-moves.md +55 -0
- package/lib/motion/shotcraft/upstream/references/shots/effects/spotlight-sweep-moves.md +52 -0
- package/lib/motion/shotcraft/upstream/references/shots/interaction/autolayout-gap-dial.md +60 -0
- package/lib/motion/shotcraft/upstream/references/shots/interaction/canvas-materialize-moves.md +57 -0
- package/lib/motion/shotcraft/upstream/references/shots/interaction/chip-grid-single-select-blackout.md +51 -0
- package/lib/motion/shotcraft/upstream/references/shots/interaction/collab-cursor-moves.md +41 -0
- package/lib/motion/shotcraft/upstream/references/shots/interaction/glass-pill-dictation-typing.md +53 -0
- package/lib/motion/shotcraft/upstream/references/shots/interaction/hashtag-to-pill-materialize.md +60 -0
- package/lib/motion/shotcraft/upstream/references/shots/interaction/picker-carousel-feature-cycle.md +55 -0
- package/lib/motion/shotcraft/upstream/references/shots/interaction/segmented-thumb-hero.md +57 -0
- package/lib/motion/shotcraft/upstream/references/shots/interaction/theme-switch-moves.md +47 -0
- package/lib/motion/shotcraft/upstream/references/shots/interaction/type-and-filter.md +37 -0
- package/lib/motion/shotcraft/upstream/references/shots/interaction/voice-waveform-live.md +54 -0
- package/lib/motion/shotcraft/upstream/references/shots/opening/brand-ink-open.md +36 -0
- package/lib/motion/shotcraft/upstream/references/shots/opening/crane-rise-reveal.md +56 -0
- package/lib/motion/shotcraft/upstream/references/shots/opening/dataviz-landscape-open.md +56 -0
- package/lib/motion/shotcraft/upstream/references/shots/opening/fracture.md +40 -0
- package/lib/motion/shotcraft/upstream/references/shots/opening/icon-field-colorize.md +60 -0
- package/lib/motion/shotcraft/upstream/references/shots/opening/letterspace-materialize.md +57 -0
- package/lib/motion/shotcraft/upstream/references/shots/opening/magician-card-flourish.md +73 -0
- package/lib/motion/shotcraft/upstream/references/shots/opening/orbit-ring-title-open.md +87 -0
- package/lib/motion/shotcraft/upstream/references/shots/opening/spotlight-hero-card.md +55 -0
- package/lib/motion/shotcraft/upstream/references/shots/opening/stroke-segment-build.md +50 -0
- package/lib/motion/shotcraft/upstream/references/shots/opening/text-as-mask.md +59 -0
- package/lib/motion/shotcraft/upstream/references/shots/outro/grain-dissolve.md +38 -0
- package/lib/motion/shotcraft/upstream/references/shots/outro/logo-shrink-wordmark-lockup.md +38 -0
- package/lib/motion/shotcraft/upstream/references/shots/outro/neon-triple-marquee.md +59 -0
- package/lib/motion/shotcraft/upstream/references/shots/outro/outro-group-photo-launch.md +39 -0
- package/lib/motion/shotcraft/upstream/references/shots/outro/ui-strip-away-outro.md +61 -0
- package/lib/motion/shotcraft/upstream/references/shots/outro/ui-to-brand-morph.md +52 -0
- package/lib/motion/shotcraft/upstream/references/shots/rhythm/beat-cut-moves.md +50 -0
- package/lib/motion/shotcraft/upstream/references/shots/rhythm/beat-step-list-theme-cycle.md +66 -0
- package/lib/motion/shotcraft/upstream/references/shots/rhythm/panel-grid-moves.md +43 -0
- package/lib/motion/shotcraft/upstream/references/shots/rhythm/quad-split-parallel-scenes.md +38 -0
- package/lib/motion/shotcraft/upstream/references/shots/rhythm/rhythm-interrupt-moves.md +38 -0
- package/lib/motion/shotcraft/upstream/references/shots/rhythm/sakuga-timing-shift.md +56 -0
- package/lib/motion/shotcraft/upstream/references/shots/rhythm/speed-ramp-freeze.md +44 -0
- package/lib/motion/shotcraft/upstream/references/shots/rhythm/trailer-grammar-moves.md +38 -0
- package/lib/motion/shotcraft/upstream/references/shots/transition/bottom-push-stack-wipe.md +63 -0
- package/lib/motion/shotcraft/upstream/references/shots/transition/card-flip-reveal.md +57 -0
- package/lib/motion/shotcraft/upstream/references/shots/transition/card-flock-tumble.md +63 -0
- package/lib/motion/shotcraft/upstream/references/shots/transition/circle-match-iris.md +58 -0
- package/lib/motion/shotcraft/upstream/references/shots/transition/gradient-transition.md +45 -0
- package/lib/motion/shotcraft/upstream/references/shots/transition/line-carry-transition.md +55 -0
- package/lib/motion/shotcraft/upstream/references/shots/transition/mosaic-reframe.md +49 -0
- package/lib/motion/shotcraft/upstream/references/shots/transition/page-turn-transitions.md +42 -0
- package/lib/motion/shotcraft/upstream/references/shots/transition/print-texture-transitions.md +42 -0
- package/lib/motion/shotcraft/upstream/references/shots/transition/shot-transitions.md +45 -0
- package/lib/motion/shotcraft/upstream/references/shots/transition/tear-streak-transitions.md +48 -0
- package/lib/motion/shotcraft/upstream/references/shots/transition/transition-hidden-cut.md +55 -0
- package/lib/motion/shotcraft/upstream/references/shots/transition/transition-travel.md +43 -0
- package/lib/motion/shotcraft/upstream/references/shots/transition/white-flash-logo-simplify-cut.md +41 -0
- package/lib/motion/shotcraft/upstream/references/shots/transition/wipe-transitions.md +42 -0
- package/lib/motion/shotcraft/upstream/references/shots/typography/blur-slide.md +59 -0
- package/lib/motion/shotcraft/upstream/references/shots/typography/brace-expand.md +55 -0
- package/lib/motion/shotcraft/upstream/references/shots/typography/countdown-arc-scatter.md +65 -0
- package/lib/motion/shotcraft/upstream/references/shots/typography/document-typewriter-reveal.md +42 -0
- package/lib/motion/shotcraft/upstream/references/shots/typography/flying-words.md +64 -0
- package/lib/motion/shotcraft/upstream/references/shots/typography/glitch-cycle.md +64 -0
- package/lib/motion/shotcraft/upstream/references/shots/typography/gradient-word-sweep.md +54 -0
- package/lib/motion/shotcraft/upstream/references/shots/typography/lead-word-zoom-assemble.md +91 -0
- package/lib/motion/shotcraft/upstream/references/shots/typography/marker-underline-title.md +51 -0
- package/lib/motion/shotcraft/upstream/references/shots/typography/outline-word-fill.md +66 -0
- package/lib/motion/shotcraft/upstream/references/shots/typography/paper-title-card.md +38 -0
- package/lib/motion/shotcraft/upstream/references/shots/typography/pill-chip-slot-cycle-handled.md +66 -0
- package/lib/motion/shotcraft/upstream/references/shots/typography/pill-slot-cycle.md +58 -0
- package/lib/motion/shotcraft/upstream/references/shots/typography/text-column-converge.md +61 -0
- package/lib/motion/shotcraft/upstream/references/shots/typography/title-demote-to-label.md +64 -0
- package/lib/motion/shotcraft/upstream/references/shots/typography/type-assembly-moves.md +45 -0
- package/lib/motion/shotcraft/upstream/references/shots/typography/type-entrance-moves.md +41 -0
- package/lib/motion/shotcraft/upstream/references/shots/typography/type-rhythm-sync.md +51 -0
- package/lib/motion/shotcraft/upstream/references/shots/typography/typewriter-moves.md +42 -0
- package/lib/motion/shotcraft/upstream/references/shots/typography/vertical-word-roll-blur-cycle.md +63 -0
- package/lib/motion/shotcraft/upstream/references/shots/typography/word-relay-filmstrip.md +57 -0
- package/lib/motion/shotcraft/upstream/references/shots/typography/word-relay-geometry.md +75 -0
- package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/avatar-bracket-carousel.md +59 -0
- package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/bezier-source-converge-merge.md +67 -0
- package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/card-stack.md +60 -0
- package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/carousel-3d.md +66 -0
- package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/cloner-depth-echo.md +40 -0
- package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/deck-deal-flyin.md +45 -0
- package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/doc-park-left-pill-deal.md +62 -0
- package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/draw-svg-trace.md +55 -0
- package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/element-body-moves.md +37 -0
- package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/integration-hub-map.md +55 -0
- package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/list-reveal.md +50 -0
- package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/list-stack-press.md +43 -0
- package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/neon-frame-forerun.md +55 -0
- package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/neon-frame-orbit-drop.md +51 -0
- package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/page-waterfall-wall.md +51 -0
- package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/product-card-progressive-assemble.md +56 -0
- package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/radial-wave.md +49 -0
- package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/research-card-stack-scroll.md +57 -0
- package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/row-embed.md +36 -0
- package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/value-stagger-gradient.md +64 -0
- package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/wall-reveal-moves.md +47 -0
- package/lib/motion/shotcraft/upstream/references/sound-design.md +170 -0
- package/lib/motion/shotcraft/upstream/references/workbench.md +157 -0
- package/lib/motion/shotcraft/upstream/template/TEMPLATE.md +103 -0
- package/lib/motion/shotcraft/upstream/template/THEMES.md +44 -0
- package/lib/motion/shotcraft/upstream/template/package.json +20 -0
- package/lib/motion/shotcraft/upstream/template/remotion.config.ts +6 -0
- package/lib/motion/shotcraft/upstream/template/src/Root.tsx +17 -0
- package/lib/motion/shotcraft/upstream/template/src/aifl/Caption.tsx +65 -0
- package/lib/motion/shotcraft/upstream/template/src/aifl/DigitRoll.tsx +48 -0
- package/lib/motion/shotcraft/upstream/template/src/aifl/FlashCut.tsx +24 -0
- package/lib/motion/shotcraft/upstream/template/src/aifl/Main.tsx +192 -0
- package/lib/motion/shotcraft/upstream/template/src/aifl/PaperTitleCard.tsx +111 -0
- package/lib/motion/shotcraft/upstream/template/src/aifl/live/PageCam.tsx +150 -0
- package/lib/motion/shotcraft/upstream/template/src/aifl/live/SceneDetail.tsx +158 -0
- package/lib/motion/shotcraft/upstream/template/src/aifl/live/SceneFlyIn.tsx +468 -0
- package/lib/motion/shotcraft/upstream/template/src/aifl/live/SceneOpen.tsx +552 -0
- package/lib/motion/shotcraft/upstream/template/src/aifl/live/SceneOutroLive.tsx +411 -0
- package/lib/motion/shotcraft/upstream/template/src/aifl/live/ScenePapers.tsx +200 -0
- package/lib/motion/shotcraft/upstream/template/src/aifl/live/SceneWbr.tsx +324 -0
- package/lib/motion/shotcraft/upstream/template/src/aifl/live-layout.json +389 -0
- package/lib/motion/shotcraft/upstream/template/src/index.ts +4 -0
- package/lib/motion/shotcraft/upstream/template/src/themes/ThemedFilm.tsx +7 -0
- package/lib/motion/shotcraft/upstream/template/src/themes/manifest.tsx +68 -0
- package/lib/motion/shotcraft/upstream/template/src/themes/palette-assets.json +1 -0
- package/lib/motion/shotcraft/upstream/template/src/themes/palette-assets.ts +24 -0
- package/lib/motion/shotcraft/upstream/template/src/themes/palettes.json +74 -0
- package/lib/motion/shotcraft/upstream/template/src/themes/visual-theme.tsx +91 -0
- package/lib/motion/shotcraft/upstream/template/src/workbench.ts +213 -0
- package/lib/motion/shotcraft/upstream/template/tsconfig.json +15 -0
- package/lib/motion/spec.js +113 -0
- package/lib/motion/style-engine.js +153 -0
- package/lib/motion/style-frames.js +271 -0
- package/lib/motion/sync.js +214 -0
- package/lib/motion/theme.js +121 -0
- package/lib/motion/video-runtime.js +192 -0
- package/lib/motion/voice.js +417 -0
- package/lib/motion-agent-files.js +82 -0
- package/lib/motion-agent-protocol.js +66 -0
- package/lib/motion-agent-tools.js +196 -0
- package/lib/motion-agent.js +171 -0
- package/lib/motion-capture.js +93 -0
- package/lib/motion-core.js +238 -0
- package/lib/motion-film-review.js +71 -0
- package/lib/motion-library.js +210 -0
- package/lib/motion-planner.js +254 -0
- package/lib/motion-project.js +87 -0
- package/lib/motion-render-worker.js +153 -0
- package/lib/motion-session.js +32 -0
- package/lib/motion-source.js +49 -0
- package/lib/motion-tasks.js +452 -0
- package/lib/motion-vision.js +44 -0
- package/lib/mxfile.js +27 -7
- package/lib/routing/node-runtime.js +14 -0
- package/lib/routing/router.js +211 -0
- package/lib/routing/vendor/README.md +96 -0
- package/lib/routing/vendor/libavoid-routing.js +753 -0
- package/lib/routing/vendor/libavoid.min.js +59 -0
- package/lib/shotcard-core.js +39 -0
- package/lib/shotcard-reference.js +56 -0
- package/lib/style-kernel.js +37 -3
- package/lib/task-patches.js +26 -2
- package/lib/video-export.js +49 -22
- package/package.json +34 -4
|
@@ -0,0 +1,963 @@
|
|
|
1
|
+
// 07-liquid — choreography. Every primitive is a closed-form function of t (seeded, no state).
|
|
2
|
+
import { baseState } from './lookdev.js';
|
|
3
|
+
|
|
4
|
+
const PI = Math.PI;
|
|
5
|
+
export const clamp = (x, a = 0, b = 1) => Math.min(b, Math.max(a, x));
|
|
6
|
+
export const lerp = (a, b, t) => a + (b - a) * t;
|
|
7
|
+
export const inv = (a, b, x) => clamp((x - a) / (b - a));
|
|
8
|
+
export const smooth = (t) => t * t * (3 - 2 * t);
|
|
9
|
+
export function bezier(x1, y1, x2, y2) {
|
|
10
|
+
const cx = 3 * x1, bx = 3 * (x2 - x1) - cx, ax = 1 - cx - bx;
|
|
11
|
+
const cy = 3 * y1, by = 3 * (y2 - y1) - cy, ay = 1 - cy - by;
|
|
12
|
+
const X = (s) => ((ax * s + bx) * s + cx) * s, Y = (s) => ((ay * s + by) * s + cy) * s, dX = (s) => (3 * ax * s + 2 * bx) * s + cx;
|
|
13
|
+
return (x) => {
|
|
14
|
+
if (x <= 0) return 0; if (x >= 1) return 1;
|
|
15
|
+
let lo = 0, hi = 1, s = x;
|
|
16
|
+
for (let i = 0; i < 12; i++) {
|
|
17
|
+
const e = X(s) - x;
|
|
18
|
+
if (Math.abs(e) < 1e-7) break;
|
|
19
|
+
if (e > 0) hi = s; else lo = s;
|
|
20
|
+
const d = dX(s);
|
|
21
|
+
s = Math.abs(d) > 1e-6 ? s - e / d : (lo + hi) / 2;
|
|
22
|
+
if (s <= lo || s >= hi) s = (lo + hi) / 2;
|
|
23
|
+
}
|
|
24
|
+
return Y(s);
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
export const flung = bezier(0.22, 1, 0.36, 1); // the brief's "thrown" ease
|
|
28
|
+
const inOut = bezier(0.65, 0, 0.35, 1);
|
|
29
|
+
const easeIn = bezier(0.5, 0, 0.9, 0.4);
|
|
30
|
+
const outSoft = bezier(0.33, 0.9, 0.4, 1);
|
|
31
|
+
const frontEase = bezier(0.28, 0.55, 0.42, 1);
|
|
32
|
+
// damped step response 0 -> 1 (overshoots)
|
|
33
|
+
function spring(t, f = 4, z = 0.3) {
|
|
34
|
+
if (t <= 0) return 0;
|
|
35
|
+
const w = 2 * PI * f, wd = w * Math.sqrt(1 - z * z);
|
|
36
|
+
return 1 - Math.exp(-z * w * t) * (Math.cos(wd * t) + (z * w / wd) * Math.sin(wd * t));
|
|
37
|
+
}
|
|
38
|
+
function wob(t, f, decay) { return t <= 0 ? 0 : Math.exp(-t / decay) * Math.sin(2 * PI * f * t); }
|
|
39
|
+
function rng(seed) { let a = seed >>> 0; return () => { a |= 0; a = (a + 0x6d2b79f5) | 0; let t = Math.imul(a ^ (a >>> 15), 1 | a); t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t; return ((t ^ (t >>> 14)) >>> 0) / 4294967296; }; }
|
|
40
|
+
|
|
41
|
+
// camera keys: t, zoom, centre x, centre y (Catmull-Rom, continuous velocity)
|
|
42
|
+
const CAM = [
|
|
43
|
+
// round 1: open in macro on the pour bulb (~560 px wide), tilt down with the fall, crown fills ~38 % of the frame at
|
|
44
|
+
// 0.40, then pull back across P2-P4 to the wide framing at 1.70
|
|
45
|
+
[-0.5, 5.4, 640, 382], [0.0, 5.3, 640, 398], [0.167, 4.9, 640, 452], [0.30, 3.8, 642, 690], [0.42, 3.3, 648, 800],
|
|
46
|
+
[0.8, 2.6, 1010, 832], [1.2, 2.15, 745, 812], // r2 s2 P8: ~1.15-1.2x tighter over P2-P3
|
|
47
|
+
[1.7, 1.6, 880, 758], [2.4, 1.64, 925, 764], [3.05, 1.72, 960, 764], [3.6, 1.46, 960, 590],
|
|
48
|
+
[4.0, 1.42, 960, 640], [4.6, 1.2, 960, 560], [5.0, 1.13, 960, 548], [5.9, 1.0, 960, 540], [8.0, 1.0, 960, 540],
|
|
49
|
+
[10.0, 1.0, 960, 540], [10.5, 1.0, 960, 540],
|
|
50
|
+
];
|
|
51
|
+
function camAt(t) {
|
|
52
|
+
let i = 1;
|
|
53
|
+
while (i < CAM.length - 2 && t > CAM[i + 1][0]) i++;
|
|
54
|
+
const k0 = CAM[i - 1], k1 = CAM[i], k2 = CAM[i + 1], k3 = CAM[i + 2];
|
|
55
|
+
const u = Math.min(1, Math.max(0, (t - k1[0]) / (k2[0] - k1[0])));
|
|
56
|
+
const out = [];
|
|
57
|
+
for (let c = 1; c < 4; c++) {
|
|
58
|
+
// non-uniform Catmull-Rom tangents
|
|
59
|
+
const m1 = (k2[c] - k0[c]) / (k2[0] - k0[0]) * (k2[0] - k1[0]);
|
|
60
|
+
const m2 = (k3[c] - k1[c]) / (k3[0] - k1[0]) * (k2[0] - k1[0]);
|
|
61
|
+
const u2 = u * u, u3 = u2 * u;
|
|
62
|
+
out.push((2 * u3 - 3 * u2 + 1) * k1[c] + (u3 - 2 * u2 + u) * m1 + (-2 * u3 + 3 * u2) * k2[c] + (u3 - u2) * m2);
|
|
63
|
+
}
|
|
64
|
+
return out;
|
|
65
|
+
}
|
|
66
|
+
export const FY = 872, HOR = 786; // contact line, horizon
|
|
67
|
+
const G = 5000; // gravity px/s^2 (droplets, leaps, drips)
|
|
68
|
+
|
|
69
|
+
// ball helper: vertical stretch sv (>1 tall, <1 flat), resting on floor if onFloor
|
|
70
|
+
function ball(S, x, y, r, u, sv = 1, ang = PI / 2) { if (r > 0.3) S.balls.push(S._lk ? { x, y, r, u, s: sv, a: ang, lk: S._lk, main: S._main, la: S._la, note: S._note } : { x, y, r, u, s: sv, a: ang }); }
|
|
71
|
+
function seg(S, ax, ay, bx, by, ra, rb, u) { if (Math.max(ra, rb) > 0.35) S.segs.push(S._lk ? { ax, ay, bx, by, ra, rb, u, lk: S._lk } : { ax, ay, bx, by, ra, rb, u }); }
|
|
72
|
+
// reel v5 link tags: tag(S, ['dot'], 'dot', a, note) marks the next primitives; the one pushed while main is set is the principal
|
|
73
|
+
function tag(S, lk, main = null, a = 1, note = '') { if (!S.lnk) return; S._lk = lk; S._main = main; S._la = a; S._note = note; }
|
|
74
|
+
function untag(S) { if (S.lnk) { S._lk = null; S._main = null; } }
|
|
75
|
+
|
|
76
|
+
// ballistic droplet that lands on the floor and becomes a bead (or melts into a puddle)
|
|
77
|
+
function makeDroplet(o) {
|
|
78
|
+
// o: x0 y0 vx vy r u tEmit [tGrow] [melt(xHit) -> bool] [life]
|
|
79
|
+
o.fy = o.fy ?? 0; o.r *= 1 + o.fy / 180; // r2 s2: depth scale 0.8-1.17
|
|
80
|
+
const dy = FY + o.fy - o.r - o.y0;
|
|
81
|
+
const tf = (o.vy + Math.sqrt(o.vy * o.vy + 2 * G * dy)) / G; // vy is upward positive here
|
|
82
|
+
o.tHit = o.tEmit + tf; o.xHit = o.x0 + o.vx * tf;
|
|
83
|
+
o.melt = o.melt ? o.melt(o.xHit, o.tHit) : false;
|
|
84
|
+
o.vHit = -o.vy + G * tf;
|
|
85
|
+
return o;
|
|
86
|
+
}
|
|
87
|
+
function emitDroplet(S, d, t, extra = {}) {
|
|
88
|
+
const grow = d.tGrow ?? 0.066;
|
|
89
|
+
if (t < d.tEmit - grow) return;
|
|
90
|
+
let r = d.r;
|
|
91
|
+
if (t < d.tEmit) { // crown bulging out of the parent before it detaches
|
|
92
|
+
const k = inv(d.tEmit - grow, d.tEmit, t);
|
|
93
|
+
r *= 0.4 + 0.6 * k;
|
|
94
|
+
ball(S, d.x0, d.y0 + (1 - k) * 10, r, d.u, 1);
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
if (t < d.tHit) {
|
|
98
|
+
const tt = t - d.tEmit;
|
|
99
|
+
const x = d.x0 + d.vx * tt, y = d.y0 - d.vy * tt + 0.5 * G * tt * tt;
|
|
100
|
+
const vx = d.vx, vy = -d.vy + G * tt, sp = Math.hypot(vx, vy);
|
|
101
|
+
const sv = 1 + Math.min(0.45, sp / 5200);
|
|
102
|
+
const ang = Math.atan2(vy, vx);
|
|
103
|
+
ball(S, x, y, r, d.u, sv, ang);
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
const tl = t - d.tHit;
|
|
107
|
+
if (d.melt) { r *= 1 - smooth(inv(0, 0.12, tl)); if (r < 0.5) return; }
|
|
108
|
+
if (d.absorb !== undefined && t > d.absorb) r *= 1 - smooth(inv(d.absorb, d.absorb + 0.12, t));
|
|
109
|
+
if (r < 0.5) return;
|
|
110
|
+
const sv = 1.25 + (0.62 - 1.25) * spring(tl, 7, 0.38);
|
|
111
|
+
let x = d.xHit;
|
|
112
|
+
if (d.follow) x += d.follow(t);
|
|
113
|
+
ball(S, x, FY + d.fy - r * sv + 0.5, r, d.u, sv);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export function createFilm(cues, word, opts = {}) {
|
|
117
|
+
const V5 = !!opts.v5;
|
|
118
|
+
const R = rng(20260927);
|
|
119
|
+
const rr = (a, b) => a + (b - a) * R();
|
|
120
|
+
|
|
121
|
+
// ================= RAIN: four drops =================
|
|
122
|
+
const drops = [
|
|
123
|
+
{ id: 'P1', x: 640, r: 56, u: 0.05, tLand: cues.landings[0].t, z: 0.5 },
|
|
124
|
+
{ id: 'P2', x: 1250, r: 46, u: 0.62, tLand: cues.landings[1].t, z: 0.5 },
|
|
125
|
+
{ id: 'P3', x: 405, r: 42, u: 0.95, tLand: cues.landings[2].t, z: 0.5 },
|
|
126
|
+
{ id: 'P4', x: 960, r: 74, u: 0.36, tLand: cues.landings[3].t, z: 0.62 },
|
|
127
|
+
];
|
|
128
|
+
const SV_PUD = 0.5; // resting puddle stretch (flat lens)
|
|
129
|
+
// landing squash: contact frame already squashing; overshoot below the resting lens is halved (no "hot-dog" pancake)
|
|
130
|
+
const svLand = (d, tl) => { const s = 1.3 + (SV_PUD - 1.3) * spring(tl + 1.3 / 30, 6, d.z); return s < SV_PUD ? SV_PUD - (SV_PUD - s) * 0.45 : s; };
|
|
131
|
+
// splash crown: a fan of tapered tendrils flung out of the splat (edges lean out, centre stands up). Each tip beads
|
|
132
|
+
// up on a thinning neck and pinches off 2-3 frames after impact (secondary droplets); the stub recoils with a rebound bump.
|
|
133
|
+
const TEN_T = 0.27;
|
|
134
|
+
const tendrils = drops.map((d) => {
|
|
135
|
+
const big = d.id === 'P4', n = big ? 7 : 5, out = [];
|
|
136
|
+
for (let k = 0; k < n; k++) {
|
|
137
|
+
const c = (k / (n - 1)) * 2 - 1 + rr(-0.07, 0.07);
|
|
138
|
+
const ang = c * 0.95 + rr(-0.12, 0.12); // radians from vertical
|
|
139
|
+
const L = d.r * (0.9 + 0.5 * Math.abs(c)) * rr(0.72, 1.22) * (big ? 1.08 : 1);
|
|
140
|
+
const tDet = 0.07 + rr(0, 1.1 / 30) + 0.02 * Math.abs(c);
|
|
141
|
+
out.push({ c, ang, L, tDet, rb: d.r * rr(0.1, 0.135) * rr(0.6, 1.4) });
|
|
142
|
+
}
|
|
143
|
+
return out;
|
|
144
|
+
});
|
|
145
|
+
function tendrilState(d, w, tl) {
|
|
146
|
+
if (tl < 0 || tl > TEN_T) return null;
|
|
147
|
+
const sv = svLand(d, tl), ax = d.r / sv, ay = d.r * sv, cy = FY - ay + 1;
|
|
148
|
+
const bx = d.x + w.c * ax * 0.46;
|
|
149
|
+
const by = cy - ay * Math.sqrt(Math.max(0, 1 - (w.c * 0.46) ** 2)) + ay * 0.45; // rooted just inside the splat top
|
|
150
|
+
let len, pinch = 0, bead = 0;
|
|
151
|
+
if (tl < w.tDet) {
|
|
152
|
+
const k = inv(0, w.tDet, tl);
|
|
153
|
+
len = w.L * flung(k); pinch = smooth(inv(0.45, 1, k)); bead = 0.55 + 0.45 * k;
|
|
154
|
+
} else {
|
|
155
|
+
const q = 1 - spring(tl - w.tDet, 5, 0.34); // recoil; negative lobe = rebound bump
|
|
156
|
+
len = w.L * 0.62 * (q >= 0 ? q : -0.45 * q) * (1 - smooth(inv(0.17, TEN_T, tl)));
|
|
157
|
+
}
|
|
158
|
+
const dx = Math.sin(w.ang), dy = -Math.cos(w.ang);
|
|
159
|
+
const droop = 0.22 * len * Math.abs(dx); // gravity bends leaning tendrils into arcs
|
|
160
|
+
const mx = bx + dx * len * 0.5, my = by + dy * len * 0.5 + droop * 0.25;
|
|
161
|
+
const tx = bx + dx * len, ty = by + dy * len + droop;
|
|
162
|
+
const ra = d.r * 0.16 * (1 - 0.3 * Math.abs(w.c)), rm = lerp(ra * 0.55, ra * 0.42, pinch), rt = lerp(rm * 0.8, d.r * 0.035, pinch);
|
|
163
|
+
return { bx, by, mx, my, tx, ty, ra, rm, rt, bead: bead * w.rb, len };
|
|
164
|
+
}
|
|
165
|
+
const crown = [];
|
|
166
|
+
drops.forEach((d, di) => {
|
|
167
|
+
const big = d.id === 'P4';
|
|
168
|
+
const melt = (xh) => Math.abs(xh - d.x) < d.r / SV_PUD * 0.85;
|
|
169
|
+
tendrils[di].forEach((w) => { // tip beads -> ballistic droplets
|
|
170
|
+
const s = tendrilState(d, w, w.tDet - 1e-4);
|
|
171
|
+
const ang = w.ang + rr(-0.21, 0.21), sp = rr(480, 760) * rr(0.75, 1.25) * (big ? 1.15 : 1);
|
|
172
|
+
const x0 = s.tx + Math.sin(w.ang) * w.rb, y0 = s.ty - Math.cos(w.ang) * w.rb, fy = rr(-36, 30); // r2 s2 P8: scattered in depth
|
|
173
|
+
const T = rr(6, 8.5) / 30 * (big ? 1.15 : 1), vy = (0.5 * G * T * T - (FY + fy - w.rb - y0)) / T;
|
|
174
|
+
crown.push(makeDroplet({
|
|
175
|
+
x0, y0, vx: Math.sin(ang) * sp * 1.1, vy, fy,
|
|
176
|
+
r: w.rb, u: d.u + rr(-0.05, 0.05), tEmit: d.tLand + w.tDet, tGrow: 0.001, owner: di, melt,
|
|
177
|
+
}));
|
|
178
|
+
});
|
|
179
|
+
for (let i = 0; i < (big ? 3 : 2); i++) { // fine spray from the splat rim
|
|
180
|
+
const side = i % 2 ? 1 : -1;
|
|
181
|
+
crown.push(makeDroplet({
|
|
182
|
+
x0: d.x + side * d.r * rr(0.9, 1.4), y0: FY - d.r * 0.55, vx: side * rr(320, big ? 820 : 640), vy: rr(520, big ? 1100 : 900),
|
|
183
|
+
r: rr(3.5, big ? 8 : 6), u: d.u + rr(-0.05, 0.05), tEmit: d.tLand + 2 / 30 + rr(0, 1 / 30), tGrow: 0.03, owner: di, melt, fy: rr(-36, 30),
|
|
184
|
+
}));
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
// landed beads closer than 15 px merge (the later one soaks into the earlier one) -> no dashed rows
|
|
188
|
+
{ const land = crown.filter((c) => !c.melt).sort((a, b) => a.tHit - b.tHit);
|
|
189
|
+
land.forEach((c, i) => { for (let j = 0; j < i; j++) { const o = land[j]; if (!o.melt && Math.hypot(c.xHit - o.xHit, c.fy - o.fy) < 15 + c.r + o.r) { c.melt = true; break; } } }); }
|
|
190
|
+
|
|
191
|
+
// ================= FUSE: puddles hop into the centre mass =================
|
|
192
|
+
const MX = 960, GH = 5000, TH = 0.34;
|
|
193
|
+
const hops = [
|
|
194
|
+
{ who: 0, tc: cues.merges[0] }, // P1 from the left, triggered by P4's landing
|
|
195
|
+
{ who: 2, tc: cues.merges[1] }, // P3 from far left
|
|
196
|
+
{ who: 1, tc: cues.merges[2] }, // P2 from the right, trailing bead tied by a thread that snaps
|
|
197
|
+
];
|
|
198
|
+
hops.forEach((h) => { const d = drops[h.who]; h.side = Math.sign(d.x - MX); h.tTake = h.tc - TH; h.x0 = d.x; h.x1 = MX + h.side * 42; h.vy = GH * TH / 2 + 60 / TH; });
|
|
199
|
+
const hopOf = (i) => hops.find((h) => h.who === i);
|
|
200
|
+
function mergeK(i, t) { const h = hopOf(i); return smooth(inv(h.tc - 0.02, h.tc + 0.16, t)); }
|
|
201
|
+
function massShift(t) { let s = 0; for (const h of hops) s += h.side * 20 * wob(t - h.tc, 2.8, 0.22); return s; }
|
|
202
|
+
function massR(t) { let a = drops[3].r ** 2; for (const h of hops) a += drops[h.who].r ** 2 * mergeK(h.who, t); return Math.sqrt(a); }
|
|
203
|
+
// merged drops keep swirling inside the mass as coloured 'ghosts' (marbled interior, silhouette unchanged)
|
|
204
|
+
function ghosts(S, t, cx, cy, R, sv, fade = 1) {
|
|
205
|
+
hops.forEach((h, j) => {
|
|
206
|
+
const k = smooth(inv(h.tc + 0.02, h.tc + 0.3, t)) * fade;
|
|
207
|
+
if (k <= 0.01) return;
|
|
208
|
+
const a = j * 2.1 + 1.5 * (t - h.tc) + h.side * 0.9;
|
|
209
|
+
const rg = Math.min(drops[h.who].r * 0.9, R * 0.62);
|
|
210
|
+
// streak along the orbit tangent -> marbled swirl
|
|
211
|
+
const gx = cx + Math.cos(a) * 0.40 * R / sv, gy = cy + Math.sin(a) * 0.34 * R * sv;
|
|
212
|
+
const gb = { x: gx, y: gy, r: rg, u: drops[h.who].u, s: 1.7, a: a + PI / 2 + (sv < 0.8 ? 0 : 0), ghost: true, amt: 0.85 * k };
|
|
213
|
+
if (S._lk) gb.lk = S._lk;
|
|
214
|
+
S.balls.push(gb);
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
// ballistic hop: take-off centre height yb, lands onto the mass (slightly lower) at tc
|
|
218
|
+
const hLow = (h) => ({ ...h, vy: h.vy * 0.8 }); // s3: trailing bead on a flatter arc
|
|
219
|
+
function hopPos(h, r, tt) {
|
|
220
|
+
const yb = FY - r * 0.92, yl = FY - 50;
|
|
221
|
+
const x = lerp(h.x0, h.x1, tt / TH);
|
|
222
|
+
const y = yb - h.vy * tt + 0.5 * GH * tt * tt + (yl - yb) * (tt / TH);
|
|
223
|
+
const vx = (h.x1 - h.x0) / TH, vy = -h.vy + GH * tt + (yl - yb) / TH;
|
|
224
|
+
return { x, y, vx, vy };
|
|
225
|
+
}
|
|
226
|
+
// floor beads get pulled into their owner as it gathers itself to jump (P4's at the big leap)
|
|
227
|
+
crown.forEach((c) => {
|
|
228
|
+
if (c.melt) return;
|
|
229
|
+
const i = c.owner, d = drops[i];
|
|
230
|
+
const tA = i === 3 ? cues.leap - 0.3 : hopOf(i).tTake - 0.14;
|
|
231
|
+
c.follow = (t) => (d.x + Math.sign(c.xHit - d.x) * d.r * 1.2 - c.xHit) * flung(inv(tA, tA + 0.16, t));
|
|
232
|
+
c.absorb = tA + 0.1;
|
|
233
|
+
if (Math.abs(c.xHit - d.x) > 420) { c.follow = null; c.absorb = 99; }
|
|
234
|
+
});
|
|
235
|
+
const sat = { tSnap: hopOf(1).tTake + 0.13 };
|
|
236
|
+
|
|
237
|
+
// ================= LEAP: the merged mass jumps, thread snaps, lands =================
|
|
238
|
+
const tLeap = cues.leap, tApex = cues.apex, tImpact = 4.0;
|
|
239
|
+
const GL = 3750; // leap gravity (surface-tension jump reads floatier)
|
|
240
|
+
const vLeap = GL * (tApex - tLeap); // apex exactly at tApex
|
|
241
|
+
const massRLeap = 118, heroR = 132;
|
|
242
|
+
const leapY0 = FY - massRLeap * 1.0;
|
|
243
|
+
function sphereY(t) { const tt = t - tLeap; return leapY0 - vLeap * tt + 0.5 * GL * tt * tt; }
|
|
244
|
+
const tThread = cues.thread_snap;
|
|
245
|
+
const remR = 36;
|
|
246
|
+
// impact crown: big spray that leads the flood
|
|
247
|
+
const spray = [];
|
|
248
|
+
for (let i = 0; i < 14; i++) {
|
|
249
|
+
const side = i % 2 ? 1 : -1;
|
|
250
|
+
spray.push({ x0: MX + side * rr(40, 260), y0: FY - rr(30, 90), vx: side * rr(80, 700), vy: rr(1500, 2700), r: rr(9, 26), u: rr(0.2, 0.9), t0: tImpact + rr(1, 3) / 30 });
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// ================= FLOOD =================
|
|
254
|
+
// round 1: three diagonal sheets launched from the impact point, alternating L->R / R->L / L->R; faster fronts and
|
|
255
|
+
// earlier drain so full immersion lasts ~0.45 s
|
|
256
|
+
const mkDir = (dx) => { const l = Math.hypot(dx, 1); return [dx / l, -1 / l]; };
|
|
257
|
+
const dir = mkDir(0.42); // violet (main) sheet: drives the blob reveal
|
|
258
|
+
const aOf = (x, y) => x * dir[0] + y * dir[1];
|
|
259
|
+
const bOf = (x, y) => -dir[1] * x + dir[0] * y;
|
|
260
|
+
function sheet(delay, rdelay, u, amp, freq, ph0, lean, dx, dur = 0.46) {
|
|
261
|
+
const d = dx === undefined ? dir : mkDir(dx);
|
|
262
|
+
const A = (x, y) => x * d[0] + y * d[1], B = (x, y) => -d[1] * x + d[0] * y;
|
|
263
|
+
const vis = [[220, 260], [1700, 260], [220, 1040], [1700, 1040]];
|
|
264
|
+
const all = [[-40, -80], [1960, -80], [-40, 1200], [1960, 1200]];
|
|
265
|
+
const aStart = Math.min(...vis.map(([x, y]) => A(x, y))) - 60, aImp = A(MX, FY - 20);
|
|
266
|
+
const aEnd = Math.max(...all.map(([x, y]) => A(x, y))) + 330, aLow = Math.min(...all.map(([x, y]) => A(x, y))) - 400;
|
|
267
|
+
const bs = all.map(([x, y]) => B(x, y)), bLo = Math.min(...bs) + 150, bHi = Math.max(...bs) - 150;
|
|
268
|
+
const bump0 = Math.max(380, aImp - aStart + 170), bumpC = B(MX, FY);
|
|
269
|
+
const t0 = tImpact + 0.035 + delay, t1 = t0 + dur;
|
|
270
|
+
const r0 = cues.reveal_start + rdelay, r1 = r0 + 0.6;
|
|
271
|
+
const frontAt = (t) => lerp(aStart, aEnd, frontEase(inv(t0, t1, t))) + 700 * smooth(inv(t1, t1 + 0.3, t));
|
|
272
|
+
const backAt = (t) => lerp(aLow, aEnd + 260, inOut(inv(r0, r1, t)));
|
|
273
|
+
return (t) => {
|
|
274
|
+
if (t < t0 || t > r1 + 0.02) return { on: false, front: 0, back: 0, phase: 0, amp: 0, freq: 0, lean: 0, u };
|
|
275
|
+
const front = frontAt(t), back = backAt(t);
|
|
276
|
+
const bumpAt = (t) => bump0 * smooth(inv(t0 - 0.01, t0 + 0.13, t)) * (1 - smooth(inv(t0 + 0.1, t0 + 0.45, t))); // s4: mound rises over ~4 f
|
|
277
|
+
const bump = bumpAt(t);
|
|
278
|
+
const vel = Math.max(Math.abs(frontAt(t + 1 / 60) - frontAt(t - 1 / 60)) + Math.abs(bumpAt(t + 1 / 60) - bumpAt(t - 1 / 60)),
|
|
279
|
+
Math.abs(backAt(t + 1 / 60) - backAt(t - 1 / 60))) * 0.5 + 6; // px per frame (+ wave travel)
|
|
280
|
+
return { on: true, front, back, phase: ph0 + t * 5.2, amp, freq, lean, u, dx: d[0], dy: d[1], bump, bumpC, vel, bLo, bHi };
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
const sheetV = sheet(0.0, 0.14, 0.9, 80, 0.0115, 0.3, 0.02, 0.42, 0.62); // s4: slower front (peak diff /1.3) // main field (violet) L->R, fuses with blobs
|
|
284
|
+
const sheetO = sheet(0.07, 0.07, 0.06, 85, 0.0102, 2.1, -0.03, -0.55); // tangerine R->L
|
|
285
|
+
const sheetP = sheet(0.14, 0.0, 0.46, 90, 0.0125, 4.4, 0.04, 0.3); // hot pink L->R, top sheet (crisp)
|
|
286
|
+
// droplets flung ahead of each sheet's front (coloured like their sheet, drawn in the main field)
|
|
287
|
+
const lead = [];
|
|
288
|
+
[[0.0, 0.88], [0.1, 0.08], [0.2, 0.48]].forEach(([delay, u], li) => {
|
|
289
|
+
for (let i = 0; i < 7; i++) lead.push({ delay, u: u + rr(-0.05, 0.05), bf: rr(0.02, 0.98), ahead: rr(60, 220), r: rr(8, 22), ph: rr(0, 6) });
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
// ================= LOGO =================
|
|
293
|
+
const L = word.letters;
|
|
294
|
+
const letterU = [0.04, 0.26, 0.5, 0.86];
|
|
295
|
+
const tSnap = cues.logo_snap;
|
|
296
|
+
// blobs left behind by the receding violet sheet, one cluster per letter
|
|
297
|
+
const clusters = L.map((l, i) => {
|
|
298
|
+
const w = l.bbox[2] - l.bbox[0], h = l.bbox[3] - l.bbox[1];
|
|
299
|
+
const cx = (l.bbox[0] + l.bbox[2]) / 2, cy = i === 1 || i === 2 ? (l.bbox[1] + l.bbox[3]) / 2 : (word.massY ?? word.baseY - 100);
|
|
300
|
+
const main = [74, 52, 64, 64][i];
|
|
301
|
+
return {
|
|
302
|
+
i, cx, cy: i === 3 ? cy + 10 : cy, u: letterU[i],
|
|
303
|
+
parts: [
|
|
304
|
+
{ dx: 0, dy: 0, r: main, sx: rr(-70, 70), sy: rr(-60, 20) },
|
|
305
|
+
{ dx: rr(-0.3, 0.3) * w, dy: -h * 0.28, r: main * 0.46, sx: rr(-120, 120), sy: rr(-150, -60) },
|
|
306
|
+
{ dx: rr(-0.3, 0.3) * w, dy: h * 0.22, r: main * 0.36, sx: rr(-120, 120), sy: rr(-40, 60) },
|
|
307
|
+
],
|
|
308
|
+
tFree: 0,
|
|
309
|
+
};
|
|
310
|
+
});
|
|
311
|
+
clusters.forEach((c) => {
|
|
312
|
+
const aTop = aOf(c.cx, c.cy - c.parts[0].r) + 150;
|
|
313
|
+
for (let tt = cues.reveal_start; tt < cues.reveal_start + 1.2; tt += 1 / 240) { const sh = sheetV(tt); if (sh.on && sh.back > aTop) { c.tFree = tt; break; } }
|
|
314
|
+
if (!c.tFree) c.tFree = cues.reveal_start + 0.6;
|
|
315
|
+
});
|
|
316
|
+
// droplets thrown off the letters at the snap (secondary, 2-3 frames late)
|
|
317
|
+
// the fused mass (6.2-6.4): four seed blobs squeezed into one horizontal bar centred on the x-height band
|
|
318
|
+
const massY = word.massY ?? word.baseY - 100, SLOT = 0.55; // v5 sets word.massY (CJK ink centre)
|
|
319
|
+
const slotX = L.map((l) => 960 + (l.sx0 - 960) * SLOT);
|
|
320
|
+
const MASS = { hx: 104, vy: 60 }; // semi-axes of each slot's ellipse at the squat
|
|
321
|
+
// r2 P1: on frames 189-191 the bar pinches three necks at the future letter gaps (each slot becomes a near-round bead)
|
|
322
|
+
const hxP = slotX.map((x, i) => 0.5 * Math.min(i > 0 ? x - slotX[i - 1] : 1e9, i < 3 ? slotX[i + 1] - x : 1e9) * 0.96);
|
|
323
|
+
const vyP = MASS.vy * 1.18;
|
|
324
|
+
const snapDrops = [];
|
|
325
|
+
for (let i = 0; i < 15; i++) {
|
|
326
|
+
const li = i % 4, side = li < 2 ? (R() < 0.8 ? -1 : 1) : (R() < 0.8 ? 1 : -1);
|
|
327
|
+
const x0 = lerp(L[li].bbox[0], L[li].bbox[2], rr(0.15, 0.85)), y0 = massY + rr(-60, 70), r = rr(4, 11);
|
|
328
|
+
const T = rr(8, 14) / 30, dy = FY - r - y0, vy = (0.5 * G * T * T - dy) / T;
|
|
329
|
+
snapDrops.push(makeDroplet({ x0, y0, vx: side * rr(260, 980), vy, r, u: letterU[li], tEmit: tSnap + rr(1, 2.2) / 30, tGrow: 0.03, melt: () => true, fy: rr(-4, 22) }));
|
|
330
|
+
}
|
|
331
|
+
// gooey bridges between neighbouring letters, stretched by the burst, snapping on the cue
|
|
332
|
+
const tBridge = cues.letter_bridge_snap;
|
|
333
|
+
const inkRow = (li, y, fromRight) => {
|
|
334
|
+
const b = L[li].bbox;
|
|
335
|
+
if (fromRight) { for (let x = Math.round(b[2]); x > b[0]; x--) if (word.sd(li, x, y) < -6) return x; }
|
|
336
|
+
else { for (let x = Math.round(b[0]); x < b[2]; x++) if (word.sd(li, x, y) < -6) return x; }
|
|
337
|
+
return fromRight ? b[2] : b[0];
|
|
338
|
+
};
|
|
339
|
+
const bridges = [0, 1, 2].map((i) => ({ i, j: i + 1, y: massY + [20, -10, 15][i], xa: inkRow(i, massY + [20, -10, 15][i], true) - 16, xb: inkRow(i + 1, massY + [20, -10, 15][i], false) + 16, r: [21, 18, 20][i] }));
|
|
340
|
+
// hanging drips under letters (living micro-motion) + the hero drip from the p's descender
|
|
341
|
+
const dripSpots = [
|
|
342
|
+
{ li: 0, fx: 0.40, len: 26, r: 10, t0: 7.0 },
|
|
343
|
+
{ li: 1, fx: 0.30, len: 16, r: 8, t0: 7.25 },
|
|
344
|
+
{ li: 2, fx: 0.52, len: 30, r: 11, t0: 7.1 },
|
|
345
|
+
].filter((d) => !(V5 && d.li === 1)).map((d) => { // v5.1: 态's spot becomes the fat drip
|
|
346
|
+
const l = L[d.li]; const x = lerp(l.bbox[0], l.bbox[2], d.fx);
|
|
347
|
+
return { ...d, x, y: (word.bottomAt(d.li, x) ?? l.bbox[3]) - 4 };
|
|
348
|
+
});
|
|
349
|
+
const pL = L[3];
|
|
350
|
+
let pxBest = (pL.bbox[0] + pL.bbox[2]) / 2, pyBest = -1;
|
|
351
|
+
for (let x = pL.bbox[0]; x < pL.bbox[2]; x += 2) { const y = word.bottomAt(3, x); if (y !== null && y > pyBest) { pyBest = y; pxBest = x; } }
|
|
352
|
+
// descender foot: find centre of the lowest run
|
|
353
|
+
let x0r = pxBest, x1r = pxBest;
|
|
354
|
+
while (word.bottomAt(3, x0r - 2) !== null && word.bottomAt(3, x0r - 2) >= pyBest - 3) x0r -= 2;
|
|
355
|
+
while (word.bottomAt(3, x1r + 2) !== null && word.bottomAt(3, x1r + 2) >= pyBest - 3) x1r += 2;
|
|
356
|
+
const hero = { x: (x0r + x1r) / 2, y: pyBest - 6, rMax: 25, tLand: cues.drip_land };
|
|
357
|
+
// bulb position at snap, solve free fall so the drip lands exactly on the cue
|
|
358
|
+
hero.ySnap = hero.y + 78; hero.vSnap = 240;
|
|
359
|
+
{ const dy = FY - hero.rMax * 1.1 - hero.ySnap; const tf = (-hero.vSnap + Math.sqrt(hero.vSnap ** 2 + 2 * G * dy)) / G; hero.tSnap = hero.tLand - tf; }
|
|
360
|
+
hero.tStart = hero.tSnap - 0.85;
|
|
361
|
+
// reel v5.1: the OUT hand-off is a fat glossy drop (>= 120 px across at the snap) that swells under 态's 心 hook
|
|
362
|
+
// (x 760, where the next film's disc falls in), snaps at 8.27 and falls straight out through the bottom of the frame
|
|
363
|
+
// (no puddle); the reel detaches it at ~8.35-8.45 while it is still falling on screen
|
|
364
|
+
const fat = { x: 760, rMax: 64, tStart: 7.2, tSnap: 8.27, vSnap: 180, u: letterU[1] };
|
|
365
|
+
fat.y = (word.bottomAt(1, fat.x) ?? L[1].bbox[3]) - 6;
|
|
366
|
+
fat.ySnap = fat.y + 118; // bulb centre at the snap
|
|
367
|
+
fat.at = (tt) => fat.ySnap + fat.vSnap * tt + 0.5 * G * tt * tt;
|
|
368
|
+
fat.tFloor = fat.tSnap + (-fat.vSnap + Math.sqrt(fat.vSnap ** 2 + 2 * G * (FY - fat.ySnap))) / G; // passes the floor line
|
|
369
|
+
const splat = [];
|
|
370
|
+
for (let i = 0; i < 4; i++) {
|
|
371
|
+
const side = i % 2 ? 1 : -1;
|
|
372
|
+
splat.push(makeDroplet({ x0: hero.x + side * rr(10, 30), y0: FY - 10, vx: side * rr(120, 330), vy: rr(260, 520), r: rr(3, 5.5), u: 0.84, tEmit: hero.tLand + 2 / 30, tGrow: 0.05 }));
|
|
373
|
+
}
|
|
374
|
+
// time each sheet's front / back edge crosses the frame centre (for sound transients)
|
|
375
|
+
const aC = aOf(960, 560);
|
|
376
|
+
const crossT = (fn, key) => { for (let tt = 3.9; tt < 6.2; tt += 1 / 240) { const sh = fn(tt); if (sh.on && sh[key] > aC) return tt; } return null; };
|
|
377
|
+
const sheetCross = [sheetV, sheetO, sheetP].map((fn) => ({ in: crossT(fn, 'front'), out: crossT(fn, 'back') }));
|
|
378
|
+
const floodBub = [];
|
|
379
|
+
for (let i = 0; i < 30; i++) floodBub.push({ x: rr(260, 1660), y0: rr(560, 1120), sp: rr(240, 520), r: rr(1.6, 4.6), t0: rr(4.14, 4.62), dur: rr(0.45, 0.8), wob: rr(3, 10), wf: rr(8, 16), ph: rr(0, 6) });
|
|
380
|
+
// soda carbonation: bubbles rising inside the letter stems, popping at the top
|
|
381
|
+
const bubbles = [];
|
|
382
|
+
L.forEach((l, li) => {
|
|
383
|
+
const cols = [];
|
|
384
|
+
for (let x = l.bbox[0] + 6; x < l.bbox[2] - 6; x += 3) {
|
|
385
|
+
let y = l.bbox[3] - 4, bottom = null, top = null;
|
|
386
|
+
for (; y > l.bbox[1]; y -= 2) { const d = word.sd(li, x, y); if (d < -9) { if (bottom === null) bottom = y; top = y; } else if (bottom !== null) break; }
|
|
387
|
+
if (bottom !== null && bottom - top > 90) cols.push({ x, bottom, top });
|
|
388
|
+
}
|
|
389
|
+
for (let j = 0; j < 7 && cols.length; j++) {
|
|
390
|
+
const c = cols[Math.floor(R() * cols.length)];
|
|
391
|
+
bubbles.push({ li, x: c.x, y0: c.bottom - 4, y1: c.top + 10, sp: rr(38, 62), r: rr(3.4, 7.2), ph: R(), t0: tSnap + 0.35 + rr(0, 0.9), wob: rr(1.5, 3.5), wf: rr(5, 9) });
|
|
392
|
+
}
|
|
393
|
+
});
|
|
394
|
+
const KICKS = [7.2, 7.4, 8.0];
|
|
395
|
+
const JELLY_HITS = [[7.2, 0.07, 1], [7.6, 0.035, 1], [8.0, 0.05, 1], [8.4, 0.045, -1], [8.8, 0.03, 1], [9.2, 0.018, 1]]; // half-time snare 7.2, kicks 7.4 / 8.0 in the drop
|
|
396
|
+
window.__cuesOut = {
|
|
397
|
+
sheetCross, jelly: [7.2, 8.0],
|
|
398
|
+
drip_snap: hero.tSnap, drip_land: hero.tLand, heroX: hero.x,
|
|
399
|
+
crown: crown.map((c) => ({ t: c.tHit, x: c.xHit, r: c.r, melt: c.melt })),
|
|
400
|
+
snapDrops: snapDrops.map((c) => ({ t: c.tHit, x: c.xHit, r: c.r })),
|
|
401
|
+
splat: splat.map((c) => ({ t: c.tHit, x: c.xHit, r: c.r })),
|
|
402
|
+
clusterFree: clusters.map((c) => c.tFree), satSnap: sat.tSnap, impact: tImpact,
|
|
403
|
+
};
|
|
404
|
+
|
|
405
|
+
// =====================================================================
|
|
406
|
+
return function film(t) {
|
|
407
|
+
const S = baseState(t);
|
|
408
|
+
S.floorY = FY; S.horizon = HOR;
|
|
409
|
+
if (V5) S.lnk = {};
|
|
410
|
+
// v5.1 grade (shader #define V5): the set sinks to near-black plum during the gather / held breath, the title liquid
|
|
411
|
+
// (lighter body, brighter diffuse, hotter speculars; 动 violet -> bright pink-violet) switches on under the split flash
|
|
412
|
+
if (V5) { const lift = smooth(inv(tSnap - 1 / 60, tSnap + 1.5 / 30, t));
|
|
413
|
+
// w: the fat drip falls in front of the set, so its floor reflection fades out once it lets go (band around its x)
|
|
414
|
+
S.v5 = [smooth(inv(6.05, 6.38, t)), lift, lift, smooth(inv(fat.tSnap, fat.tSnap + 0.1, t))]; S.v5b = [fat.x, 130, 0, 0]; }
|
|
415
|
+
|
|
416
|
+
// ---------------- camera ----------------
|
|
417
|
+
const cz = camAt(t);
|
|
418
|
+
let punch = 0.016 * wob(t - tImpact, 3.0, 0.2);
|
|
419
|
+
drops.forEach((d, i) => { punch += (i === 3 ? 0.022 : 0.013) * wob(t - d.tLand, 3.2, 0.16); });
|
|
420
|
+
let zmul = 1;
|
|
421
|
+
if (t >= tSnap) {
|
|
422
|
+
const ts = t - tSnap;
|
|
423
|
+
zmul = ts < 2 / 30 ? lerp(1, 1.07, outSoft(ts * 15)) : ts < 14 / 30 ? lerp(1.07, 1.02, inOut(inv(2 / 30, 14 / 30, ts))) : 1.02; // s4: harder punch
|
|
424
|
+
zmul += 0.045 * (0.5 - 0.5 * Math.cos(PI * inv(tSnap + 14 / 30, 10.0, t))); // r2 P3: push to ~1.065 // easeInOutSine push
|
|
425
|
+
}
|
|
426
|
+
S.cam = { zoom: cz[0] * (1 + punch) * zmul, px: cz[1], py: cz[2] - 60 * (zmul - 1), ox: 0, oy: 0 };
|
|
427
|
+
|
|
428
|
+
// ---------------- goo ----------------
|
|
429
|
+
S.k = 0.1;
|
|
430
|
+
if (t > 5.2) S.k = lerp(0.062, 0.105, smooth(inv(tSnap, tSnap + 0.2, t)));
|
|
431
|
+
if (t > 5.2 && t < 5.9) S.k = lerp(0.1, 0.062, smooth(inv(5.2, 5.9, t)));
|
|
432
|
+
|
|
433
|
+
// ================= POUR (P1) =================
|
|
434
|
+
const P1 = drops[0];
|
|
435
|
+
const tPS = cues.pour_snap;
|
|
436
|
+
const pourGeo = (tt) => {
|
|
437
|
+
const bottom = 454 + 45 * tt + 2500 * tt * tt, v = 45 + 5000 * tt;
|
|
438
|
+
const neckPull = tt < tPS ? Math.pow(tt / tPS, 1.6) : 0;
|
|
439
|
+
const sv = 1 + 0.26 * clamp(v / 2045) + 0.16 * neckPull;
|
|
440
|
+
const cy = bottom - P1.r * sv, top = cy - P1.r * sv * 0.82;
|
|
441
|
+
return { bottom, v, neckPull, sv, cy, top, pinchY: top - 34 - 30 * neckPull };
|
|
442
|
+
};
|
|
443
|
+
if (t < P1.tLand) {
|
|
444
|
+
const bottom = 454 + 45 * t + 2500 * t * t, v = 45 + 5000 * t;
|
|
445
|
+
const neckPull = t < tPS ? Math.pow(t / tPS, 1.6) : 0;
|
|
446
|
+
const sv = 1 + 0.26 * clamp(v / 2045) + 0.16 * neckPull;
|
|
447
|
+
const cy = bottom - P1.r * sv;
|
|
448
|
+
tag(S, ['dot'], 'dot', 1, 'pour bulb (macro drop, ball lens)');
|
|
449
|
+
ball(S, P1.x, cy, P1.r, P1.u, sv);
|
|
450
|
+
tag(S, ['dot']);
|
|
451
|
+
// round 1: the bulb is a ball lens — a small inverted 'drop' wordmark is refracted inside it (logo in frame 1)
|
|
452
|
+
const wb = word.bbox, ww = wb[2] - wb[0];
|
|
453
|
+
S.lens = [P1.x, cy, P1.r / sv, P1.r * sv, (wb[0] + wb[2]) / 2 - word.offX, (wb[1] + wb[3]) / 2 - word.offY, ww / 0.92, 0.72 * (1 - smooth(inv(0.25, 0.35, t)))];
|
|
454
|
+
if (t < tPS) {
|
|
455
|
+
// stretched neck: thick thread from above thinning into a pinch just above the bulb
|
|
456
|
+
const top = cy - P1.r * sv * 0.82;
|
|
457
|
+
const pinchY = top - 34 - 30 * neckPull;
|
|
458
|
+
untag(S); seg(S, P1.x, -90, P1.x, pinchY, 25, lerp(8, 1.2, neckPull), P1.u + 0.02); tag(S, ['dot']);
|
|
459
|
+
seg(S, P1.x, pinchY, P1.x, top + 8, lerp(8, 1.2, neckPull), lerp(16, 12, neckPull), P1.u);
|
|
460
|
+
} else {
|
|
461
|
+
// lower stub recoils into the bulb (2-3 frame rebound) — teardrop tail
|
|
462
|
+
const k = spring(t - tPS, 7, 0.45);
|
|
463
|
+
const top = cy - P1.r * sv * 0.8;
|
|
464
|
+
const len = 42 * (1 - k);
|
|
465
|
+
if (len > 1) seg(S, P1.x, top - len, P1.x, top + 6, 3.5 * (1 - k) + 1, 13, P1.u);
|
|
466
|
+
ball(S, P1.x, top - len, 5 * (1 - k * 0.8), P1.u);
|
|
467
|
+
}
|
|
468
|
+
untag(S);
|
|
469
|
+
}
|
|
470
|
+
if (t >= tPS && t < 1.4) {
|
|
471
|
+
// upper thread: snaps back up with overshoot, then the pour is pulled out of frame
|
|
472
|
+
const endSnap = pourGeo(tPS - 1e-4).pinchY;
|
|
473
|
+
const k = spring(t - tPS, 5.5, 0.32);
|
|
474
|
+
const end = endSnap - 58 * k - 1500 * easeIn(inv(0.34, 1.2, t));
|
|
475
|
+
if (end > -80) {
|
|
476
|
+
seg(S, P1.x, -90, P1.x, end, 25 - 6 * inv(0.3, 1.2, t), 7 + 3 * k, P1.u + 0.02);
|
|
477
|
+
ball(S, P1.x, end, 9 + 3 * k, P1.u + 0.02);
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
// ================= drops falling, landing, hopping =================
|
|
482
|
+
drops.forEach((d, i) => {
|
|
483
|
+
if (i === 0 && t < d.tLand) return;
|
|
484
|
+
if (t < d.tLand) {
|
|
485
|
+
const tau = d.tLand - t, vL = 2500, Gd = 4200;
|
|
486
|
+
if (tau > 0.52) return;
|
|
487
|
+
const bottom = FY - vL * tau + 0.5 * Gd * tau * tau, v = vL - Gd * tau;
|
|
488
|
+
const sv = 1 + 0.30 * clamp(v / vL);
|
|
489
|
+
const cy = bottom - d.r * sv;
|
|
490
|
+
if (i === 3) tag(S, ['dot'], 'dot', 1, 'falling drop P4 (becomes the mass)');
|
|
491
|
+
ball(S, d.x, cy, d.r, d.u, sv);
|
|
492
|
+
if (i === 3) tag(S, ['dot']);
|
|
493
|
+
const lag = 0.03 * v;
|
|
494
|
+
ball(S, d.x, cy - d.r * sv * 0.9 - lag, d.r * 0.32, d.u, 1.3);
|
|
495
|
+
seg(S, d.x, cy - d.r * 0.3, d.x, cy - d.r * sv * 0.9 - lag, d.r * 0.5, d.r * 0.18, d.u);
|
|
496
|
+
untag(S);
|
|
497
|
+
return;
|
|
498
|
+
}
|
|
499
|
+
if (t >= 4.0) return;
|
|
500
|
+
const tl = t - d.tLand;
|
|
501
|
+
if (i === 3 && t <= tLeap - 0.25) tag(S, ['dot']); // v5: P4's own crown goes with the dot
|
|
502
|
+
// crown arms
|
|
503
|
+
tendrils[i].forEach((w) => {
|
|
504
|
+
const a = tendrilState(d, w, tl); if (!a || a.len < 1) return;
|
|
505
|
+
seg(S, a.bx, a.by, a.mx, a.my, a.ra, a.rm, d.u); seg(S, a.mx, a.my, a.tx, a.ty, a.rm, a.rt, d.u);
|
|
506
|
+
if (a.bead > 0.5) ball(S, a.tx + Math.sin(w.ang) * a.bead * 0.8, a.ty - Math.cos(w.ang) * a.bead * 0.8, a.bead, d.u, 1.12, w.ang - PI / 2);
|
|
507
|
+
});
|
|
508
|
+
untag(S);
|
|
509
|
+
if (i === 3) {
|
|
510
|
+
if (t > tLeap - 0.25) return; // the mass is handled by the leap block
|
|
511
|
+
const r = massR(t);
|
|
512
|
+
let sv = svLand(d, tl);
|
|
513
|
+
for (const h of hops) sv += 0.16 * wob(t - h.tc, 3.6, 0.2);
|
|
514
|
+
tag(S, ['dot'], 'dot', 1, 'the mass: P4 puddle swallowing the hoppers (flat lens)');
|
|
515
|
+
ball(S, MX + massShift(t), FY - r * sv + 1.0, r, d.u, sv);
|
|
516
|
+
tag(S, ['dot']);
|
|
517
|
+
ghosts(S, t, MX + massShift(t), FY - r * sv + 1.0, r, sv);
|
|
518
|
+
untag(S);
|
|
519
|
+
return;
|
|
520
|
+
}
|
|
521
|
+
const h = hopOf(i);
|
|
522
|
+
const r = d.r;
|
|
523
|
+
// trailing secondary droplet: same arc, 3 frames late, a third of the size
|
|
524
|
+
const emitHopper = (rs, delay, uOff) => {
|
|
525
|
+
const tt = t - delay - h.tTake, rr_ = r * rs;
|
|
526
|
+
if (V5 && i === 1 && rs === 1 && tt >= 0) tag(S, ['hop'], 'hop', tt < TH ? 1 : 1 - smooth(inv(0, 0.12, t - delay - h.tc)), 'hopper P2 (ballistic blob merging into the mass)');
|
|
527
|
+
const res = hopBody(rs, tt, rr_, uOff, delay);
|
|
528
|
+
untag(S);
|
|
529
|
+
return res;
|
|
530
|
+
};
|
|
531
|
+
const hopBody = (rs, tt, rr_, uOff, delay) => {
|
|
532
|
+
if (tt < -0.1) { // resting puddle
|
|
533
|
+
if (rs < 1) return; // bead is part of the puddle until it launches
|
|
534
|
+
const sv = svLand(d, tl);
|
|
535
|
+
ball(S, h.x0, FY - rr_ * sv + 1, rr_, d.u, sv);
|
|
536
|
+
return;
|
|
537
|
+
}
|
|
538
|
+
if (tt < 0) { // anticipation: squat, gather toward the jump
|
|
539
|
+
const k = inv(-0.1, 0, tt);
|
|
540
|
+
const sv = lerp(rs < 1 ? 0.62 : SV_PUD, 0.40, smooth(k));
|
|
541
|
+
const x = rs < 1 ? h.x0 - h.side * r * 1.25 : h.x0 + h.side * 8 * k;
|
|
542
|
+
ball(S, x, FY - rr_ * sv + 1, rr_, d.u + uOff, sv);
|
|
543
|
+
return;
|
|
544
|
+
}
|
|
545
|
+
if (tt < TH) { // flight
|
|
546
|
+
const P = hopPos(rs < 1 ? hLow(h) : h, rr_, tt);
|
|
547
|
+
const sp = Math.hypot(P.vx, P.vy);
|
|
548
|
+
let sv = 1 + 0.26 * Math.min(1, sp / 1400) + 0.35 * Math.exp(-tt / 0.05);
|
|
549
|
+
sv = lerp(sv, 0.74, smooth(inv(TH - 0.06, TH, tt))); // s3: flattens against the host on the way in
|
|
550
|
+
ball(S, P.x, P.y, rr_, d.u + uOff, sv, Math.atan2(P.vy, P.vx));
|
|
551
|
+
if (tt < 0.09 && rs === 1) { // take-off neck to the floor, snapping
|
|
552
|
+
const k = tt / 0.09;
|
|
553
|
+
seg(S, h.x0, FY - 6, lerp(h.x0, P.x, 0.5), lerp(FY - 6, P.y, 0.5), lerp(rr_ * 0.5, 8, k), lerp(rr_ * 0.4, 0.6, k), d.u);
|
|
554
|
+
}
|
|
555
|
+
return;
|
|
556
|
+
}
|
|
557
|
+
const tm = t - delay - h.tc; // merging into the mass
|
|
558
|
+
// round 1: contact squash to 0.6 h in 2 f, sink into the host over 4-5 f (no head-and-beak bump on top), and a
|
|
559
|
+
// bump travelling across the host's top (~33 px/frame)
|
|
560
|
+
const k = smooth(inv(0, 0.15, tm)), ks = smooth(inv(0, 0.05, tm)), kd = smooth(inv(0.0, 0.15, tm));
|
|
561
|
+
const P = hopPos(rs < 1 ? hLow(h) : h, rr_, TH);
|
|
562
|
+
const x = lerp(P.x, MX + massShift(t), k * 0.8), y = lerp(P.y + rr_ * 0.35 * ks, FY - massR(t) * 0.42, kd);
|
|
563
|
+
const rm = rr_ * Math.sqrt(1 - k);
|
|
564
|
+
ball(S, x, y, rm, d.u + uOff, lerp(0.74, 0.55, ks) * (1 - 0.1 * k));
|
|
565
|
+
if (rs === 1 && tm > 0.02 && tm < 0.2) {
|
|
566
|
+
const kb = inv(0.02, 0.2, tm);
|
|
567
|
+
ball(S, lerp(P.x, MX - h.side * 90, kb) + massShift(t), P.y + rr_ * 0.45 + 6 * kb, rr_ * 0.55 * Math.sin(PI * kb), d.u + uOff, 0.7);
|
|
568
|
+
}
|
|
569
|
+
};
|
|
570
|
+
emitHopper(1, 0, 0);
|
|
571
|
+
emitHopper(0.27, 0.17, 0.03);
|
|
572
|
+
// P2: thread from the trailing bead to the jumping puddle stretches and snaps (2-3 frame rebound)
|
|
573
|
+
if (i === 1) {
|
|
574
|
+
const tt = t - h.tTake;
|
|
575
|
+
if (V5) tag(S, ['hop']);
|
|
576
|
+
if (tt > 0 && tt < 0.4) {
|
|
577
|
+
const P = hopPos(h, r, Math.min(tt, TH));
|
|
578
|
+
const bx = h.x0 - h.side * r * 1.25, by = FY - r * 0.34 * 0.5;
|
|
579
|
+
if (t < sat.tSnap) {
|
|
580
|
+
const k = inv(h.tTake, sat.tSnap, t);
|
|
581
|
+
const mx = lerp(bx, P.x, 0.5), my = lerp(by, P.y, 0.5) + 10;
|
|
582
|
+
const rm = lerp(6, 0.6, Math.pow(k, 0.8));
|
|
583
|
+
seg(S, bx, by, mx, my, 7, rm, d.u + 0.03);
|
|
584
|
+
seg(S, mx, my, P.x - h.side * -r * 0.3, P.y + r * 0.3, rm, 10, d.u);
|
|
585
|
+
} else {
|
|
586
|
+
const k = spring(t - sat.tSnap, 7, 0.4);
|
|
587
|
+
const f = 0.45 * (1 - k);
|
|
588
|
+
if (f > 0.02) {
|
|
589
|
+
seg(S, bx, by, lerp(bx, P.x, f), lerp(by, P.y, f), 6, 2.5, d.u + 0.03);
|
|
590
|
+
seg(S, P.x, P.y + r * 0.4, lerp(P.x, bx, f), lerp(P.y, by, f), 9, 2.5, d.u);
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
untag(S);
|
|
595
|
+
}
|
|
596
|
+
});
|
|
597
|
+
// crown droplets / beads
|
|
598
|
+
crown.forEach((c) => { if (t < 4.05) { if (c.owner === 3) tag(S, ['dot']); emitDroplet(S, c, t); untag(S); } });
|
|
599
|
+
|
|
600
|
+
// ================= LEAP =================
|
|
601
|
+
if (t >= tLeap - 0.25 && t < tImpact + 0.3) {
|
|
602
|
+
const u = 0.36;
|
|
603
|
+
if (t < tLeap) {
|
|
604
|
+
// anticipation: gather into a dome, then a quick squat
|
|
605
|
+
const k = inOut(inv(tLeap - 0.25, tLeap - 0.07, t));
|
|
606
|
+
let sv = lerp(SV_PUD, 0.86, k);
|
|
607
|
+
sv = lerp(sv, 0.55, smooth(inv(tLeap - 0.08, tLeap, t)));
|
|
608
|
+
const r = lerp(massR(t), massRLeap, k);
|
|
609
|
+
tag(S, ['dot'], 'dot', 1, 'the mass gathering into a dome');
|
|
610
|
+
ball(S, MX, FY - r * sv + 1, r, u, sv);
|
|
611
|
+
tag(S, ['dot']);
|
|
612
|
+
ghosts(S, t, MX, FY - r * sv + 1, r, sv);
|
|
613
|
+
untag(S);
|
|
614
|
+
} else if (t < tImpact) {
|
|
615
|
+
const tt = t - tLeap;
|
|
616
|
+
const y = sphereY(t);
|
|
617
|
+
const vy = -vLeap + GL * tt;
|
|
618
|
+
const r = lerp(massRLeap, heroR, smooth(inv(tLeap, tApex, t)));
|
|
619
|
+
let sv = 1 + 0.36 * Math.exp(-tt / 0.12) * Math.cos(tt * 18) + 0.10 * wob(tt - 0.08, 3.4, 0.35) + 0.14 * smooth(inv(tApex + 0.1, tImpact, t));
|
|
620
|
+
// s3 P8: +-5 % jelly wobble at 3 Hz around the apex
|
|
621
|
+
sv += 0.05 * Math.sin(2 * PI * 3 * (t - tApex)) * smooth(inv(tApex - 0.35, tApex - 0.12, t)) * (1 - smooth(inv(tApex + 0.2, tApex + 0.32, t)));
|
|
622
|
+
// s3 P8: the four palette colours swirl through the interior as 3-4 curling bands (shader uSw)
|
|
623
|
+
S.sw = [MX, y, r * 1.02, 0.82 * smooth(inv(tLeap + 0.04, tLeap + 0.3, t)) * (1 - smooth(inv(tImpact - 0.03, tImpact + 0.02, t)))];
|
|
624
|
+
tag(S, ['dot'], 'dot', 1, 'hero sphere leaping (swirl bands inside)');
|
|
625
|
+
ball(S, MX, y, r, u, sv);
|
|
626
|
+
tag(S, ['dot']);
|
|
627
|
+
ghosts(S, t, MX, y, r * 0.95, sv);
|
|
628
|
+
// jelly wobble lobes (surface modes)
|
|
629
|
+
const wa = 0.5 + 0.5 * Math.exp(-tt / 0.4);
|
|
630
|
+
for (let j = 0; j < 3; j++) {
|
|
631
|
+
const ang = j * 2.1 + tt * (1.6 + j * 0.4);
|
|
632
|
+
ball(S, MX + Math.cos(ang) * r * 0.55, y + Math.sin(ang) * r * 0.55, r * 0.42 * wa, u + 0.04 * (j - 1), 1);
|
|
633
|
+
}
|
|
634
|
+
untag(S);
|
|
635
|
+
// remnant puddle + stretched thread
|
|
636
|
+
const remSv = 0.5 + 0.25 * wob(t - tThread, 6, 0.2);
|
|
637
|
+
const remR2 = remR * (1 - smooth(inv(tImpact - 0.08, tImpact, t)));
|
|
638
|
+
ball(S, MX, FY - remR2 * remSv + 1, remR2, u + 0.05, remSv);
|
|
639
|
+
const sb = y + r * sv * 0.85, rt = FY - remR2 * remSv * 1.6;
|
|
640
|
+
if (t < tThread) {
|
|
641
|
+
const k = inv(tLeap, tThread, t);
|
|
642
|
+
const my = lerp(sb, rt, 0.55);
|
|
643
|
+
const rm = lerp(14, 0.7, Math.pow(k, 0.9));
|
|
644
|
+
tag(S, ['dot']); seg(S, MX, sb - 10, MX, my, lerp(38, 16, k), rm, u); untag(S);
|
|
645
|
+
seg(S, MX, my, MX, rt + 6, rm, lerp(22, 12, k), u + 0.04);
|
|
646
|
+
} else {
|
|
647
|
+
const k = spring(t - tThread, 6.5, 0.36);
|
|
648
|
+
const up = (rt - sb) * 0.45 * (1 - k);
|
|
649
|
+
if (up > 2) {
|
|
650
|
+
tag(S, ['dot']); seg(S, MX, sb - 8, MX, sb + up, 14, 3, u); untag(S);
|
|
651
|
+
seg(S, MX, rt - up, MX, rt + 6, 3, 12, u + 0.04);
|
|
652
|
+
ball(S, MX, rt - up, 4, u + 0.04);
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
} else {
|
|
656
|
+
// impact: splat that feeds the rising flood
|
|
657
|
+
const tl = t - tImpact;
|
|
658
|
+
const sv = 1.15 + (0.3 - 1.15) * spring(tl, 5, 0.5);
|
|
659
|
+
const drain = 1 - smooth(inv(0.05, 0.19, tl)); // s4: splat drains into the flood (no ellipse outline under the sheets)
|
|
660
|
+
tag(S, ['dot'], 'dot', drain, 'impact splat draining into the flood');
|
|
661
|
+
if (drain > 0.02) ball(S, MX, FY - heroR * sv * drain, heroR * (1 + 0.3 * smooth(inv(0, 0.2, tl))) * drain, 0.4, sv);
|
|
662
|
+
untag(S);
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
// impact spray
|
|
666
|
+
spray.forEach((d) => {
|
|
667
|
+
if (t < d.t0 || t > 5.0) return;
|
|
668
|
+
const tt = t - d.t0;
|
|
669
|
+
const x = d.x0 + d.vx * tt, y = d.y0 - d.vy * tt + 0.5 * G * tt * tt;
|
|
670
|
+
const vy = -d.vy + G * tt;
|
|
671
|
+
const r = d.r * smooth(inv(0, 0.05, tt));
|
|
672
|
+
ball(S, x, y, r, d.u, 1 + Math.min(0.5, Math.hypot(d.vx, vy) / 5000), Math.atan2(vy, d.vx));
|
|
673
|
+
});
|
|
674
|
+
|
|
675
|
+
// ================= FLOOD =================
|
|
676
|
+
S.flood = { on: false, front: 0, back: 0, phase: 0, amp: 0, freq: 0, lean: 0, u: 0 };
|
|
677
|
+
const shV = sheetV(t);
|
|
678
|
+
S.overlays = [shV, sheetO(t), sheetP(t)];
|
|
679
|
+
// droplets leading each front
|
|
680
|
+
lead.forEach((d) => {
|
|
681
|
+
const sh = [sheetV, sheetO, sheetP][d.delay === 0 ? 0 : d.delay < 0.15 ? 1 : 2](t);
|
|
682
|
+
if (!sh.on) return;
|
|
683
|
+
const t0 = tImpact - 0.03 + d.delay;
|
|
684
|
+
const tt = t - t0;
|
|
685
|
+
if (tt < 0.05 || tt > 0.6) return;
|
|
686
|
+
const b = lerp(sh.bLo, sh.bHi, d.bf);
|
|
687
|
+
const ahead = d.ahead * Math.sin(PI * inv(0.05, 0.6, tt));
|
|
688
|
+
const a = sh.front + ahead + 60;
|
|
689
|
+
const x = a * sh.dx - b * sh.dy, y = a * sh.dy + b * sh.dx;
|
|
690
|
+
ball(S, x, y, d.r * Math.sin(PI * inv(0.05, 0.6, tt)), d.u, 1.35, Math.atan2(sh.dy, sh.dx));
|
|
691
|
+
});
|
|
692
|
+
|
|
693
|
+
// ================= LOGO BLOBS (left behind by the violet sheet) =================
|
|
694
|
+
const tRevealV = cues.reveal_start; // violet back edge starts rising
|
|
695
|
+
if (t > 4.12 && t < tSnap) {
|
|
696
|
+
const fk = inOut(inv(tSnap - 0.3, tSnap - 1 / 30, t)); // fuse into the bar
|
|
697
|
+
const squat = smooth(inv(tSnap - 0.2, tSnap - 1 / 30, t));
|
|
698
|
+
clusters.forEach((c) => {
|
|
699
|
+
const tFree = c.tFree;
|
|
700
|
+
const gk = flung(inv(tFree - 0.05, tSnap - 0.2, t)); // gather
|
|
701
|
+
const squeeze = smooth(inv(tSnap - 0.22, tSnap - 0.02, t));
|
|
702
|
+
const vanish = smooth(inv(tSnap - 0.01, tSnap + 0.11, t));
|
|
703
|
+
c.parts.forEach((p, j) => {
|
|
704
|
+
const lagk = flung(inv(tFree - 0.05 + j * 0.08, tSnap - 0.2 + j * 0.03, t)); // secondary blobs 2-3 frames late
|
|
705
|
+
const k = j === 0 ? gk : lagk;
|
|
706
|
+
let x = c.cx + lerp(p.sx + p.dx, p.dx * 0.25, k);
|
|
707
|
+
let y = c.cy + lerp(p.sy + p.dy, p.dy * 0.25, k);
|
|
708
|
+
// tug upward by the receding sheet, then rebound
|
|
709
|
+
const tug = t < tFree ? 1 : 0;
|
|
710
|
+
const reb = t >= tFree ? wob(t - tFree, 3.2, 0.22) : 0;
|
|
711
|
+
y += -30 * tug * inv(tFree - 0.3, tFree, t) - 22 * reb;
|
|
712
|
+
let r = p.r * (1 - 0.14 * squeeze * 0) * (1 - vanish * 0);
|
|
713
|
+
// round 1: the seeds are the subject of the immersion — they condense inside the violet sheet once its front
|
|
714
|
+
// has passed, and drift up toward their letter slots, seen backlit through the sheets above
|
|
715
|
+
if (t < tFree) {
|
|
716
|
+
const shv = sheetV(t);
|
|
717
|
+
r *= shv.on ? smooth(inv(0, 220, shv.front - aOf(c.cx, c.cy))) : 0;
|
|
718
|
+
const pre = 1 - smooth(inv(4.12, tFree, t));
|
|
719
|
+
x += (p.sx * 1.3 + (c.i - 1.5) * 70) * pre; y += 190 * pre;
|
|
720
|
+
}
|
|
721
|
+
let sv = 1 + 0.35 * tug * inv(tFree - 0.3, tFree, t) - 0.18 * reb - 0.16 * squeeze;
|
|
722
|
+
if (fk > 0) {
|
|
723
|
+
const hx0 = r / sv, vy0 = r * sv;
|
|
724
|
+
const tx = slotX[c.i] + (j ? p.dx * 0.1 : 0), ty = massY;
|
|
725
|
+
x = lerp(x, tx, fk); y = lerp(y, ty, fk);
|
|
726
|
+
let hx = j ? hx0 * (1 - fk) : lerp(hx0, MASS.hx * (1 + 0.06 * squat), fk), vy = j ? vy0 * (1 - fk) : lerp(vy0, MASS.vy * (1 - 0.15 * squat), fk);
|
|
727
|
+
const pn = inOut(inv(tSnap - 3.5 / 30, tSnap - 0.6 / 30, t)); // r2: pinch the necks
|
|
728
|
+
if (!j && pn > 0) { hx = lerp(hx, hxP[c.i], pn); vy = lerp(vy, vyP, pn); }
|
|
729
|
+
if (hx < 0.5) return;
|
|
730
|
+
r = Math.sqrt(hx * vy); sv = Math.sqrt(vy / hx);
|
|
731
|
+
}
|
|
732
|
+
if (V5 && j === 0) {
|
|
733
|
+
const lk = [];
|
|
734
|
+
if (c.i === 3 && fk < 0.5) lk.push('dot');
|
|
735
|
+
if (fk > 0) lk.push('bar');
|
|
736
|
+
if (lk.length) tag(S, lk, c.i === 3 && fk < 0.5 ? 'dot' : null,
|
|
737
|
+
lerp(0.4, 1, smooth(inv(tFree - 0.15, tFree + 0.05, t))) * (1 - smooth(inv(0.1, 0.5, fk))), 'seed blob of 动 (freed by the violet sheet)');
|
|
738
|
+
if (fk > 0) S.lnk.bar = { a: smooth(inv(0.35, 0.8, fk)), note: 'fused liquid bar that splits into the title' };
|
|
739
|
+
}
|
|
740
|
+
if (V5 && j > 0) { // the seed's satellite lobes go with it (and with the bar while fusing)
|
|
741
|
+
const lk = [];
|
|
742
|
+
if (c.i === 3 && fk < 0.5) lk.push('dot');
|
|
743
|
+
if (fk > 0) lk.push('bar~'); // '~' = hidden with the bar, not part of its reported geometry
|
|
744
|
+
if (lk.length) tag(S, lk);
|
|
745
|
+
}
|
|
746
|
+
ball(S, x, y, r, c.u, sv);
|
|
747
|
+
if (S.lnk && j === 0 && !(c.i === 3 && fk < 0.5)) untag(S);
|
|
748
|
+
if (S.lnk && j === 0 && c.i === 3 && fk < 0.5) S._main = null;
|
|
749
|
+
if (j === 0 && t < tFree + 0.02 && t > tFree - 0.35) {
|
|
750
|
+
// neck to the receding sheet above
|
|
751
|
+
const sh = sheetV(t);
|
|
752
|
+
if (sh.on) {
|
|
753
|
+
const k2 = inv(tFree - 0.35, tFree, t);
|
|
754
|
+
const topY = y - r * sv * 0.8;
|
|
755
|
+
const edgeY = topY - lerp(20, 130, k2);
|
|
756
|
+
const rm = lerp(18, 0.6, Math.pow(k2, 0.8));
|
|
757
|
+
seg(S, x, topY + 6, x + 4, (topY + edgeY) / 2, lerp(26, 12, k2), rm, c.u);
|
|
758
|
+
seg(S, x + 4, (topY + edgeY) / 2, x + 6, edgeY - 40, rm, lerp(30, 16, k2), 0.85);
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
untag(S);
|
|
762
|
+
});
|
|
763
|
+
});
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
// ================= LETTERS =================
|
|
767
|
+
// letterless until the drop. On frame 192 the bar splits: each slot's ellipse morphs into its letter SDF over 3 frames
|
|
768
|
+
// (1-frame stagger L->R) while the letters are flung out to their places on a spring (overshoot 112% w / 92% h).
|
|
769
|
+
if (t >= tSnap) {
|
|
770
|
+
const ts = t - tSnap;
|
|
771
|
+
const pos = [];
|
|
772
|
+
L.forEach((l, i) => {
|
|
773
|
+
// r2 P1 "split, don't grow": the word unfolds about (960, massY) from the bar (glyph scale = spacing scale, so glyphs
|
|
774
|
+
// never overlap); each letter is born from its bead in 2 f (0.6 f stagger) -> frame 194 reads 'drop'
|
|
775
|
+
const tl = ts; // one shared unfold (a stagger would let o run into p)
|
|
776
|
+
const m = clamp((ts * 30 - 0.6 * i + 1.5) / 2);
|
|
777
|
+
const P = tl > 0 ? spring(tl, 4, 0.35) : 0;
|
|
778
|
+
const x = 960 + (l.sx0 - 960) * lerp(SLOT, 1, P);
|
|
779
|
+
const gs = lerp(SLOT, 1, P <= 1 ? P : 1 + 0.25 * (P - 1));
|
|
780
|
+
const sq = m * smooth(clamp((P - 0.95) / 0.36)); // 112 % w / 92 % h about the letter's own centre, once apart
|
|
781
|
+
// r2 s2 P3: the jelly word answers the groove: a wobble wave on each beat of the outro, L->R (R->L from the p when
|
|
782
|
+
// the drip lands at 8.40), decaying toward the final hold -> the end card has events, not just slow drift
|
|
783
|
+
let jelly = 0;
|
|
784
|
+
for (const [tk, ak, dk] of JELLY_HITS) jelly += ak * wob(t - tk - (dk > 0 ? i : 3 - i) * 0.04, 3.4, 0.22);
|
|
785
|
+
const breathe = 0.025 * Math.sin(2 * PI * 0.7 * (t - 6.9) - i * PI / 2) * smooth(inv(6.9, 7.6, t)); // r2 P3: +-2.5 %
|
|
786
|
+
const sxJ = 1 + 0.12 * sq + jelly + breathe, syJ = 1 - 0.08 * sq + breathe - jelly * 0.6;
|
|
787
|
+
let dy = tl > 0 ? -18 * (1 - spring(tl, 3.4, 0.45)) * m : 0;
|
|
788
|
+
if (V5 && i === 1) dy += t < fat.tSnap ? 5 * smooth(inv(7.5, fat.tSnap, t)) : 5 * (1 - spring(t - fat.tSnap, 3.2, 0.28)); // v5.1
|
|
789
|
+
const gooWob = 3.2 * Math.exp(-Math.max(0, tl) / 0.35) + 0.9 + 0.5 * smooth(inv(6.9, 7.5, t)); // r2 s2: livelier skin
|
|
790
|
+
const yc = massY + (l.sy0 - massY) * gs + dy;
|
|
791
|
+
const y = yc + (1 - syJ) * (l.bbox[3] - l.sy0) * 0.9 * gs;
|
|
792
|
+
pos.push({ x, y: yc, gs });
|
|
793
|
+
S.letters.push({
|
|
794
|
+
x, y, px: l.px, py: l.py, grow: 3 * (1 - smooth(inv(0, 0.15, Math.max(0, tl)))), u: letterU[i], sx: gs * sxJ, sy: gs * syJ,
|
|
795
|
+
a: tl > 0 ? 0.012 * wob(tl, 2.4, 0.4) * (i % 2 ? 1 : -1) : 0, on: true, m: Math.max(1e-3, m), wob: gooWob, wph: t * 7.0 + i * 1.7,
|
|
796
|
+
ell: [x, massY + dy, hxP[i] * (1 + 0.4 * m), vyP * (1 + 0.4 * m)],
|
|
797
|
+
});
|
|
798
|
+
});
|
|
799
|
+
// r2: the three necks thin and snap L->R one frame apart (between frames 192/193, 193/194, 194/195); stubs recoil
|
|
800
|
+
bridges.forEach((br) => {
|
|
801
|
+
const Pa = pos[br.i], Pb = pos[br.j], la = L[br.i], lb = L[br.j];
|
|
802
|
+
const A = [Pa.x + (br.xa - la.sx0) * Pa.gs, Pa.y + (br.y - la.sy0) * Pa.gs];
|
|
803
|
+
const B = [Pb.x + (br.xb - lb.sx0) * Pb.gs, Pb.y + (br.y - lb.sy0) * Pb.gs];
|
|
804
|
+
const tBr = tSnap + (br.i + 0.5) / 30;
|
|
805
|
+
if (t < tBr) {
|
|
806
|
+
const k = inv(tSnap, tBr, t);
|
|
807
|
+
const rm = lerp(br.r * 0.85, 1.0, Math.pow(k, 0.6));
|
|
808
|
+
const M = [(A[0] + B[0]) / 2, (A[1] + B[1]) / 2 + 6 * k];
|
|
809
|
+
const ra = br.r * 1.1 * Pa.gs;
|
|
810
|
+
seg(S, A[0], A[1], M[0], M[1], ra, rm, letterU[br.i]); seg(S, M[0], M[1], B[0], B[1], rm, ra, letterU[br.j]);
|
|
811
|
+
} else if (t < tBr + 0.3) {
|
|
812
|
+
const tt = t - tBr, k = spring(tt, 7, 0.35);
|
|
813
|
+
const half = [(B[0] - A[0]) / 2, (B[1] - A[1]) / 2];
|
|
814
|
+
const ra = br.r * (1 - 0.5 * smooth(inv(0, 0.25, tt)));
|
|
815
|
+
seg(S, A[0], A[1], A[0] + half[0] * (1 - k) * 0.8, A[1] + half[1] * (1 - k) + 6, ra, 2.5 + 3 * (1 - k), letterU[br.i]);
|
|
816
|
+
seg(S, B[0], B[1], B[0] - half[0] * (1 - k) * 0.8, B[1] - half[1] * (1 - k) + 6, ra, 2.5 + 3 * (1 - k), letterU[br.j]);
|
|
817
|
+
}
|
|
818
|
+
});
|
|
819
|
+
snapDrops.forEach((d) => emitDroplet(S, d, t));
|
|
820
|
+
}
|
|
821
|
+
// hanging drips (grow slowly, never fall) — living hold
|
|
822
|
+
dripSpots.forEach((d) => {
|
|
823
|
+
if (t < d.t0) return;
|
|
824
|
+
const k = outSoft(inv(d.t0, 10.2, t));
|
|
825
|
+
const len = d.len * k, r = d.r * (0.4 + 0.6 * smooth(inv(d.t0, d.t0 + 0.6, t)));
|
|
826
|
+
const sway = 1.5 * Math.sin(t * 3 + d.li);
|
|
827
|
+
if (len + r < 3) return;
|
|
828
|
+
seg(S, d.x, d.y - 8, d.x + sway * 0.5, d.y + len, r * 1.25, r * 0.55, letterU[d.li]);
|
|
829
|
+
ball(S, d.x + sway, d.y + len + r * 0.35, r * (0.6 + 0.4 * k), letterU[d.li], 1.12);
|
|
830
|
+
});
|
|
831
|
+
// v5.1: fat drip under 态 (the dot's OUT): swell 7.2-8.27, neck thins and snaps 8.27, free fall out of the frame
|
|
832
|
+
if (V5 && t > fat.tStart) {
|
|
833
|
+
const u = fat.u;
|
|
834
|
+
if (t < fat.tSnap) {
|
|
835
|
+
const k = inv(fat.tStart, fat.tSnap, t), sag = easeIn(k);
|
|
836
|
+
const br = fat.rMax * (0.25 + 0.75 * smooth(inv(0, 0.85, k)));
|
|
837
|
+
const sv = 1 + 0.12 * sag;
|
|
838
|
+
const by = lerp(fat.y + br * 0.95, fat.ySnap, sag); // beads up under the stroke, then sags on a lengthening neck
|
|
839
|
+
const top = by - br * sv * 0.8, A = fat.y - 12, M = (A + top) / 2;
|
|
840
|
+
const rn = lerp(26, 2.5, Math.pow(inv(0.55, 1, k), 1.4));
|
|
841
|
+
tag(S, ['dot']);
|
|
842
|
+
if (top > A + 4) { seg(S, fat.x, A, fat.x, M, 30, rn, u); seg(S, fat.x, M, fat.x, top, rn, br * 0.6, u); }
|
|
843
|
+
tag(S, ['dot'], 'dot', smooth(inv(0, 0.2, k)), 'fat drip swelling under 态 (OUT: snaps 8.27, falls out of frame)');
|
|
844
|
+
ball(S, fat.x, by, br, u, sv);
|
|
845
|
+
untag(S);
|
|
846
|
+
} else {
|
|
847
|
+
const tt = t - fat.tSnap, y = fat.at(tt), v = fat.vSnap + G * tt;
|
|
848
|
+
if (y - fat.rMax * 1.3 < 1250) {
|
|
849
|
+
const sv = 1 + 0.12 * Math.exp(-tt / 0.12) * Math.cos(2 * PI * 6 * tt) + 0.06 * clamp(v / 2500); // teardrop -> round, jiggles
|
|
850
|
+
tag(S, ['dot'], 'dot', 1, 'fat drip falling from 态 (out through the bottom edge)');
|
|
851
|
+
ball(S, fat.x, y, fat.rMax, u, sv);
|
|
852
|
+
tag(S, ['dot']);
|
|
853
|
+
const len = 46 * (1 - spring(tt, 7, 0.45)); // the snapped tail recoils into the drop
|
|
854
|
+
if (len > 1) seg(S, fat.x, y - fat.rMax * sv - len, fat.x, y - fat.rMax * 0.6, 3, 16, u);
|
|
855
|
+
untag(S);
|
|
856
|
+
}
|
|
857
|
+
if (tt < 0.6) { // stub on 态 recoils (rebound)
|
|
858
|
+
const k = spring(tt, 6, 0.33), len = 44 * (1 - k) + 3;
|
|
859
|
+
seg(S, fat.x, fat.y - 10, fat.x, fat.y + len, 24, 5 + 4 * (1 - k), u);
|
|
860
|
+
}
|
|
861
|
+
if (t > fat.tFloor) S.tagRev = { x: fat.x, y: FY, age: t - fat.tFloor, amp: 1 }; // tagline wipes in in its wake
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
// hero drip from the p descender
|
|
865
|
+
if (!V5 && t > hero.tStart) {
|
|
866
|
+
const u = letterU[3];
|
|
867
|
+
if (t < hero.tSnap) {
|
|
868
|
+
const k = inv(hero.tStart, hero.tSnap, t);
|
|
869
|
+
const kk = easeIn(k);
|
|
870
|
+
const by = lerp(hero.y + 8, hero.ySnap, kk);
|
|
871
|
+
const br = hero.rMax * (0.35 + 0.65 * smooth(inv(0, 0.55, k)));
|
|
872
|
+
const neckY = lerp(hero.y + 6, by - br * 0.9, 0.5);
|
|
873
|
+
const rn = lerp(16, 2.2, Math.pow(inv(0.35, 1, k), 1.2));
|
|
874
|
+
seg(S, hero.x, hero.y - 10, hero.x, neckY, 22, rn, u);
|
|
875
|
+
tag(S, ['dot']); seg(S, hero.x, neckY, hero.x, by - br * 0.5, rn, br * 0.7, u);
|
|
876
|
+
tag(S, ['dot'], 'dot', smooth(inv(0, 0.25, k)), 'drip bulb swelling under 动');
|
|
877
|
+
ball(S, hero.x, by, br, u, 1 + 0.18 * kk);
|
|
878
|
+
untag(S);
|
|
879
|
+
} else if (t < hero.tLand) {
|
|
880
|
+
const tt = t - hero.tSnap;
|
|
881
|
+
const y = hero.ySnap + hero.vSnap * tt + 0.5 * G * tt * tt;
|
|
882
|
+
const v = hero.vSnap + G * tt;
|
|
883
|
+
const sv = 1.12 + 0.2 * clamp(v / 1400);
|
|
884
|
+
tag(S, ['dot'], 'dot', 1, 'drip falling from 动');
|
|
885
|
+
ball(S, hero.x, y, hero.rMax, u, sv);
|
|
886
|
+
tag(S, ['dot']);
|
|
887
|
+
// tail recoils into the falling drop
|
|
888
|
+
const k = spring(tt, 8, 0.45);
|
|
889
|
+
const len = 30 * (1 - k);
|
|
890
|
+
if (len > 1) seg(S, hero.x, y - hero.rMax * sv - len, hero.x, y - hero.rMax * 0.6, 2, 8, u);
|
|
891
|
+
untag(S);
|
|
892
|
+
} else {
|
|
893
|
+
const tl = t - hero.tLand;
|
|
894
|
+
const sv = 1.3 + (0.42 - 1.3) * spring(tl, 5.5, 0.4);
|
|
895
|
+
const r = hero.rMax * (1 + 0.1 * smooth(inv(0, 0.3, tl)));
|
|
896
|
+
tag(S, ['dot'], 'dot', 1, 'drip landed: glossy puddle lens + ripple');
|
|
897
|
+
ball(S, hero.x, FY - r * sv + 0.5, r, u, sv);
|
|
898
|
+
untag(S);
|
|
899
|
+
S.rip = { x: hero.x, y: FY, age: tl, amp: 1 };
|
|
900
|
+
if (V5) S.ripDot = true;
|
|
901
|
+
}
|
|
902
|
+
// stub on the descender recoils after the snap (rebound 2-3 frames)
|
|
903
|
+
if (t >= hero.tSnap && t < hero.tSnap + 0.6) {
|
|
904
|
+
const k = spring(t - hero.tSnap, 6, 0.33);
|
|
905
|
+
const len = 40 * (1 - k) + 3;
|
|
906
|
+
seg(S, hero.x, hero.y - 10, hero.x, hero.y + len, 18, 4 + 3 * (1 - k), u);
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
if (!V5) splat.forEach((d) => emitDroplet(S, d, t));
|
|
910
|
+
|
|
911
|
+
// ---------------- light: glint sweep after the snap ----------------
|
|
912
|
+
const g2 = inv(9.0, 9.0 + 10 / 30, t);
|
|
913
|
+
const glint1 = t > cues.glint - 0.1 && t < cues.glint + 0.8;
|
|
914
|
+
const kd = smooth(inv(6.9, 10.0, t)); // r2 s2 P3: the key softbox travels during the end card -> speculars slide over the letters
|
|
915
|
+
S.key = { x: -0.78 + 0.06 * Math.sin(t * 0.6) + 0.30 * kd, y: -0.95 + 0.12 * kd,
|
|
916
|
+
glint: glint1 ? lerp(-900, 1700, inOut(inv(cues.glint - 0.1, cues.glint + 0.75, t))) : lerp(-300, 1900, inOut(g2)),
|
|
917
|
+
glintAmp: glint1 ? 1 : (g2 > 0 && g2 < 1 ? 2.2 * Math.sin(PI * g2) : 0) }; // r2 P3: bold 9.0 glint
|
|
918
|
+
{ const f = (t - tSnap) * 30; if (f >= 0 && f < 2.5) { S.key.glint = lerp(-200, 1300, f / 2.5); S.key.glintAmp = 2.8 * (1 - 0.5 * f / 2.5); } } // r2: 2 f specular pop
|
|
919
|
+
const gA = inv(3.72, 3.72 + 6 / 30, t); // s3 P8: strip light rakes the falling hero sphere (6 f)
|
|
920
|
+
if (gA > 0 && gA < 1) { S.key.glint = 0.8 * MX - 0.6 * sphereY(t) + lerp(-300, 300, inOut(gA)); S.key.glintAmp = 2.4 * Math.sin(PI * gA); }
|
|
921
|
+
S.bloom = 0.55 + 0.45 * Math.exp(-Math.max(0, t - tSnap) / 0.25) * (t > tSnap ? 1 : 0);
|
|
922
|
+
const gap = smooth(inv(tSnap - 0.2, tSnap - 1 / 30, t)) * (t < tSnap ? 1 : 0);
|
|
923
|
+
S.spot = 1.0 - 0.55 * gap;
|
|
924
|
+
if (t >= tSnap) S.spot = 1.12 + 0.45 * Math.exp(-(t - tSnap) / 0.15); // r2: small lift; the ring carries the hit
|
|
925
|
+
{ // r2 P1: radial light ring from behind the bar (0 -> 1400 px in 8 f, flung) + backlit crown sheet (gone in 10 f)
|
|
926
|
+
const tr = t - tSnap;
|
|
927
|
+
if (tr >= 0 && tr < 0.6) {
|
|
928
|
+
const ur = inv(0, 10 / 30, tr), kr = 1 - (1 - ur) * (1 - ur); // expo-ish out: energy spread over 4-5 f
|
|
929
|
+
S.ring = [960, massY + 10, 40 + 1360 * kr, 0.62 * (1 - 0.45 * kr) * (1 - smooth(inv(5 / 30, 12 / 30, tr)))];
|
|
930
|
+
const kc = flung(inv(0, 3 / 30, tr)), fc = smooth(inv(3 / 30, 9 / 30, tr));
|
|
931
|
+
if (tr < 9 / 30) S.crown = [960, massY - 30, 350 * kc * (1 - 0.6 * fc), (1 - fc) * smooth(inv(0, 1 / 30, tr))];
|
|
932
|
+
}
|
|
933
|
+
// r2 P3: living end card: cyc spot drifts +-80 px, backdrop parallax 8 px against the letters
|
|
934
|
+
const ek = 0.5 - 0.5 * Math.cos(PI * inv(6.6, 10.0, t));
|
|
935
|
+
S.caus = smooth(inv(6.55, 7.2, t)) * (1 + (!V5 && t > cues.drip_land ? 1.6 * Math.exp(-(t - cues.drip_land) / 0.45) : 0)); // r2 s2: the drip's splash flares the wall caustics
|
|
936
|
+
S.par = [8 * ek, -5 * ek, 80 * Math.sin(2 * PI * (t - 6.6) / 3.0) * smooth(inv(6.6, 7.4, t)), 18 * Math.sin(2 * PI * (t - 6.6) / 4.0) * smooth(inv(6.6, 7.4, t))];
|
|
937
|
+
}
|
|
938
|
+
for (const kt of KICKS) S.spot += 0.14 * Math.exp(-Math.max(0, t - kt) / 0.14) * (t >= kt ? 1 : 0);
|
|
939
|
+
// exposure (EV) applied in post
|
|
940
|
+
S.flash = -0.8 * gap; // s4: deeper held breath (-0.8 EV)
|
|
941
|
+
if (t >= tSnap) { const f = (t - tSnap) * 30; S.flash = f < 1 ? 0.9 : f < 2 ? 0.65 : 0.65 * (1 - smooth(inv(2, 8, f))); } // r2: +0.6 EV (ring does the rest)
|
|
942
|
+
S.bubbles = [];
|
|
943
|
+
bubbles.forEach((b) => {
|
|
944
|
+
if (t < b.t0) return;
|
|
945
|
+
const len = b.y0 - b.y1, per = len / b.sp + 0.25;
|
|
946
|
+
const ph = ((t - b.t0) / per + b.ph) % 1;
|
|
947
|
+
const k = ph * per * b.sp / len; // 0..1 along the rise (last 0.25 s = gap)
|
|
948
|
+
if (k > 1) return;
|
|
949
|
+
const l = S.letters[b.li]; if (!l) return;
|
|
950
|
+
const y = lerp(b.y0, b.y1, k) + (l.y - L[b.li].sy0), x = b.x + b.wob * Math.sin((t - b.t0) * b.wf + b.ph * 6);
|
|
951
|
+
const a = smooth(inv(0, 0.12, k)) * (1 - smooth(inv(0.88, 1, k))) * smooth(inv(b.t0, b.t0 + 0.3, t));
|
|
952
|
+
S.bubbles.push([x, y, b.r * (0.8 + 0.4 * k), a]);
|
|
953
|
+
});
|
|
954
|
+
// round 1: sharp micro-bubbles rising through the flood (drawn only where liquid covers the pixel)
|
|
955
|
+
floodBub.forEach((b) => {
|
|
956
|
+
const tt = t - b.t0; if (tt < 0 || tt > b.dur) return;
|
|
957
|
+
const y = b.y0 - b.sp * tt - 160 * tt * tt, x = b.x + b.wob * Math.sin(tt * b.wf + b.ph);
|
|
958
|
+
if (S.bubbles.length < 32) S.bubbles.push([x, y, b.r * (1 + 0.5 * tt), smooth(inv(0, 0.06, tt)) * (1 - smooth(inv(b.dur - 0.12, b.dur, tt)))]);
|
|
959
|
+
});
|
|
960
|
+
S.halo = t >= tSnap ? smooth(inv(tSnap, tSnap + 0.08, t)) * (0.55 + 0.45 * Math.exp(-(t - tSnap) / 0.3)) : 0;
|
|
961
|
+
return S;
|
|
962
|
+
};
|
|
963
|
+
}
|