dsh-drawai 0.4.2 → 0.4.4

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.
Files changed (379) hide show
  1. package/README.md +7 -5
  2. package/lib/client.js +142 -16
  3. package/lib/index.js +7945 -7719
  4. package/lib/motion/asset-pack.js +394 -394
  5. package/lib/motion/assets.js +291 -291
  6. package/lib/motion/demo-assets-lock.js +10 -10
  7. package/lib/motion/mgstyles/briefs/23-ink-wash.md +147 -0
  8. package/lib/motion/mgstyles/catalog.d/23-ink-wash.json +28 -0
  9. package/lib/motion/mgstyles/catalog.json +127 -14
  10. package/lib/motion/mgstyles/upstream/demos/23-ink-wash/brush.js +149 -0
  11. package/lib/motion/mgstyles/upstream/demos/23-ink-wash/film.js +202 -0
  12. package/lib/motion/mgstyles/upstream/manifest.json +28 -3
  13. package/lib/motion/mgstyles/upstream/prompts/23-ink-wash.md +59 -0
  14. package/lib/motion/mgstyles/vendor/README.md +28 -28
  15. package/lib/motion/mgstyles/vendor/modules/d3/LICENSE +13 -13
  16. package/lib/motion/mgstyles/vendor/modules/d3/dist/d3.min.js +2 -2
  17. package/lib/motion/mgstyles/vendor/modules/opentype.js/LICENSE +20 -20
  18. package/lib/motion/mgstyles/vendor/modules/opentype.js/dist/opentype.mjs +14460 -14460
  19. package/lib/motion/mgstyles/vendor/modules/simplex-noise/LICENSE +21 -21
  20. package/lib/motion/mgstyles/vendor/modules/simplex-noise/dist/esm/simplex-noise.js +465 -465
  21. package/lib/motion/mgstyles/vendor/modules/topojson-client/LICENSE +13 -13
  22. package/lib/motion/mgstyles/vendor/modules/topojson-client/dist/topojson-client.min.js +2 -2
  23. package/lib/motion/project.js +5 -1
  24. package/lib/motion/qa.js +116 -6
  25. package/lib/motion/render.js +179 -179
  26. package/lib/motion/scene-kit.js +1 -1
  27. package/lib/motion/shotcraft/upstream/SKILL.md +286 -286
  28. package/lib/motion/shotcraft/upstream/assets/lib/Caption.tsx +54 -54
  29. package/lib/motion/shotcraft/upstream/assets/lib/ClipCard.tsx +200 -200
  30. package/lib/motion/shotcraft/upstream/assets/lib/DigitRoll.tsx +45 -45
  31. package/lib/motion/shotcraft/upstream/assets/lib/FlashCut.tsx +20 -20
  32. package/lib/motion/shotcraft/upstream/assets/lib/FlatPanel.tsx +65 -65
  33. package/lib/motion/shotcraft/upstream/assets/lib/PageCam.tsx +151 -151
  34. package/lib/motion/shotcraft/upstream/assets/lib/VerticalTicker.tsx +129 -129
  35. package/lib/motion/shotcraft/upstream/assets/lib/helpers/camera.tsx +75 -75
  36. package/lib/motion/shotcraft/upstream/assets/lib/helpers/motion.ts +40 -40
  37. package/lib/motion/shotcraft/upstream/assets/lib/helpers/rand.ts +11 -11
  38. package/lib/motion/shotcraft/upstream/assets/lib/helpers/shake.ts +10 -10
  39. package/lib/motion/shotcraft/upstream/assets/scripts/build-readme-cover.mjs +49 -49
  40. package/lib/motion/shotcraft/upstream/assets/scripts/capture-template.mjs +210 -210
  41. package/lib/motion/shotcraft/upstream/assets/scripts/sfx-source.py +423 -423
  42. package/lib/motion/shotcraft/upstream/assets/scripts/smoke-render-demos.py +170 -170
  43. package/lib/motion/shotcraft/upstream/assets/scripts/test_sfx_source.py +157 -157
  44. package/lib/motion/shotcraft/upstream/demos/README.md +120 -120
  45. package/lib/motion/shotcraft/upstream/demos/_fixtures/Brand.tsx +112 -112
  46. package/lib/motion/shotcraft/upstream/demos/_fixtures/Fixtures.tsx +647 -647
  47. package/lib/motion/shotcraft/upstream/demos/_fixtures/Look.tsx +316 -316
  48. package/lib/motion/shotcraft/upstream/demos/_fixtures/Motion.tsx +82 -82
  49. package/lib/motion/shotcraft/upstream/demos/_fixtures/PageCam2D.tsx +115 -115
  50. package/lib/motion/shotcraft/upstream/demos/_fixtures/Polish.tsx +243 -243
  51. package/lib/motion/shotcraft/upstream/demos/_textures/live-layout.json +388 -388
  52. package/lib/motion/shotcraft/upstream/demos/camera/basic-3d-scene/Basic3DScene.tsx +250 -250
  53. package/lib/motion/shotcraft/upstream/demos/camera/crash-zoom-punch/CrashImpactReal.tsx +305 -305
  54. package/lib/motion/shotcraft/upstream/demos/camera/crash-zoom-punch/CrashZoomReal.tsx +246 -246
  55. package/lib/motion/shotcraft/upstream/demos/camera/cursor-flyover/CursorFlyover.tsx +390 -390
  56. package/lib/motion/shotcraft/upstream/demos/camera/depth-layer-moves/MultiplaneReal.tsx +138 -138
  57. package/lib/motion/shotcraft/upstream/demos/camera/graze-face-tour/GrazeFaceTour.tsx +542 -542
  58. package/lib/motion/shotcraft/upstream/demos/camera/overhead-camera-moves/OverheadTabletopDrop.tsx +315 -315
  59. package/lib/motion/shotcraft/upstream/demos/camera/overhead-camera-moves/TiltReveal.tsx +299 -299
  60. package/lib/motion/shotcraft/upstream/demos/camera/space-camera-moves/DroneDiveLanding.tsx +173 -173
  61. package/lib/motion/shotcraft/upstream/demos/camera/space-camera-moves/ExplodedView.tsx +348 -348
  62. package/lib/motion/shotcraft/upstream/demos/camera/steep-tilt-glide/SteepTiltGlide.tsx +366 -366
  63. package/lib/motion/shotcraft/upstream/demos/camera/tension-camera-moves/BulletTimeFreezeOrbit.tsx +279 -279
  64. package/lib/motion/shotcraft/upstream/demos/camera/tension-camera-moves/PullBackIsolation.tsx +184 -184
  65. package/lib/motion/shotcraft/upstream/demos/camera/terminal-3d/Terminal3D.tsx +390 -390
  66. package/lib/motion/shotcraft/upstream/demos/data/before-after-slider-scrub/BeforeAfterSliderScrub.tsx +155 -155
  67. package/lib/motion/shotcraft/upstream/demos/data/chart-live-moves/AxisRescaleShockV2.tsx +303 -303
  68. package/lib/motion/shotcraft/upstream/demos/data/chart-live-moves/OscilloscopeStreamV2.tsx +290 -290
  69. package/lib/motion/shotcraft/upstream/demos/data/chart-live-moves/UnitDotSwarmRegroupV2.tsx +278 -278
  70. package/lib/motion/shotcraft/upstream/demos/data/gauge-readout-moves/NeedleSweepSelftest.tsx +307 -307
  71. package/lib/motion/shotcraft/upstream/demos/data/gauge-readout-moves/TapeScrollFixedPointer.tsx +215 -215
  72. package/lib/motion/shotcraft/upstream/demos/data/scroll-brake-moves/BrakeReticleLock.tsx +299 -299
  73. package/lib/motion/shotcraft/upstream/demos/data/scroll-brake-moves/ChangelogScrollBrake.tsx +232 -232
  74. package/lib/motion/shotcraft/upstream/demos/data/timeline-travel/TimelineTravel.tsx +290 -290
  75. package/lib/motion/shotcraft/upstream/demos/effects/assemble-then-type-flyin/AssembleThenTypeFlyin.tsx +273 -273
  76. package/lib/motion/shotcraft/upstream/demos/effects/aurora-bloom-bg-flip/AuroraBloomBgFlip.tsx +167 -167
  77. package/lib/motion/shotcraft/upstream/demos/effects/brand-frame-snap/BrandFrameSnap.tsx +536 -536
  78. package/lib/motion/shotcraft/upstream/demos/effects/fui-hud-moves/ReticleLockOn.tsx +164 -164
  79. package/lib/motion/shotcraft/upstream/demos/effects/glow-flyline-moves/FlylineArc.tsx +175 -175
  80. package/lib/motion/shotcraft/upstream/demos/effects/glow-flyline-moves/GlowOrbAmbient.tsx +197 -197
  81. package/lib/motion/shotcraft/upstream/demos/effects/glow-flyline-moves/OrbFlylineRelay.tsx +241 -241
  82. package/lib/motion/shotcraft/upstream/demos/effects/icon-performance-moves/AttentionBounce.tsx +279 -279
  83. package/lib/motion/shotcraft/upstream/demos/effects/impact-feedback/AnimeImpact.tsx +230 -230
  84. package/lib/motion/shotcraft/upstream/demos/effects/impact-feedback/HitCounter.tsx +345 -345
  85. package/lib/motion/shotcraft/upstream/demos/effects/light-play-moves/SheenSweepRetry.tsx +275 -275
  86. package/lib/motion/shotcraft/upstream/demos/effects/light-play-moves/SpotlightSweepReveal.tsx +229 -229
  87. package/lib/motion/shotcraft/upstream/demos/effects/radial-ripple-phone-chips/RadialRipplePhoneChips.tsx +312 -312
  88. package/lib/motion/shotcraft/upstream/demos/effects/riso-print-hits/RisoMisregistrationHit.tsx +222 -222
  89. package/lib/motion/shotcraft/upstream/demos/effects/scan-bracket-sweep/ScanBracketSweep.tsx +295 -295
  90. package/lib/motion/shotcraft/upstream/demos/effects/scanline-annotate-focus/ScanlineAnnotateFocus.tsx +329 -329
  91. package/lib/motion/shotcraft/upstream/demos/effects/scanline-assemble-flyin/ScanlineAssembleFlyin.tsx +315 -315
  92. package/lib/motion/shotcraft/upstream/demos/effects/slam-entrance-moves/ImpactBurstKit.tsx +264 -264
  93. package/lib/motion/shotcraft/upstream/demos/effects/slam-entrance-moves/KanadaPerspectiveSnap.tsx +260 -260
  94. package/lib/motion/shotcraft/upstream/demos/effects/slam-entrance-moves/ScoreSlam.tsx +263 -263
  95. package/lib/motion/shotcraft/upstream/demos/effects/spotlight-sweep-moves/CornerSpotlightReveal.tsx +123 -123
  96. package/lib/motion/shotcraft/upstream/demos/effects/spotlight-sweep-moves/GlowWakeSleepPanel.tsx +187 -187
  97. package/lib/motion/shotcraft/upstream/demos/effects/spotlight-sweep-moves/SlideSpotlightPan.tsx +175 -175
  98. package/lib/motion/shotcraft/upstream/demos/interaction/autolayout-gap-dial/AutolayoutGapDial.tsx +305 -305
  99. package/lib/motion/shotcraft/upstream/demos/interaction/canvas-materialize-moves/DiagramCascadeBuild.tsx +350 -350
  100. package/lib/motion/shotcraft/upstream/demos/interaction/canvas-materialize-moves/PanelToCanvasMaterialize.tsx +352 -352
  101. package/lib/motion/shotcraft/upstream/demos/interaction/chip-grid-single-select-blackout/ChipGridSingleSelectBlackout.tsx +218 -218
  102. package/lib/motion/shotcraft/upstream/demos/interaction/collab-cursor-moves/CursorCastEnsemble.tsx +297 -297
  103. package/lib/motion/shotcraft/upstream/demos/interaction/glass-pill-dictation-typing/GlassPillDictationTyping.tsx +157 -157
  104. package/lib/motion/shotcraft/upstream/demos/interaction/hashtag-to-pill-materialize/HashtagToPillMaterialize.tsx +218 -218
  105. package/lib/motion/shotcraft/upstream/demos/interaction/picker-carousel-feature-cycle/PickerCarouselFeatureCycle.tsx +202 -202
  106. package/lib/motion/shotcraft/upstream/demos/interaction/segmented-thumb-hero/SegmentedThumbHero.tsx +265 -265
  107. package/lib/motion/shotcraft/upstream/demos/interaction/theme-switch-moves/PaletteThemeRipple.tsx +457 -457
  108. package/lib/motion/shotcraft/upstream/demos/interaction/theme-switch-moves/ThemeSweepToggle.tsx +446 -446
  109. package/lib/motion/shotcraft/upstream/demos/interaction/type-and-filter/TypeAndFilter.tsx +249 -249
  110. package/lib/motion/shotcraft/upstream/demos/interaction/voice-waveform-live/VoiceWaveformLive.tsx +278 -278
  111. package/lib/motion/shotcraft/upstream/demos/opening/crane-rise-reveal/CraneRiseReveal.tsx +332 -332
  112. package/lib/motion/shotcraft/upstream/demos/opening/dataviz-landscape-open/DatavizLandscapeOpen.tsx +358 -358
  113. package/lib/motion/shotcraft/upstream/demos/opening/fracture/Fracture.tsx +201 -201
  114. package/lib/motion/shotcraft/upstream/demos/opening/icon-field-colorize/IconFieldColorize.tsx +200 -200
  115. package/lib/motion/shotcraft/upstream/demos/opening/letterspace-materialize/LetterspaceMaterialize.tsx +208 -208
  116. package/lib/motion/shotcraft/upstream/demos/opening/magician-card-flourish/MagicianCardFlourish.tsx +341 -341
  117. package/lib/motion/shotcraft/upstream/demos/opening/orbit-ring-title-open/OrbitRingTitleOpen.tsx +389 -389
  118. package/lib/motion/shotcraft/upstream/demos/opening/spotlight-hero-card/SpotlightHeroCard.tsx +293 -293
  119. package/lib/motion/shotcraft/upstream/demos/opening/stroke-segment-build/StrokeSegmentBuild.tsx +183 -183
  120. package/lib/motion/shotcraft/upstream/demos/opening/text-as-mask/TextAsMask.tsx +245 -245
  121. package/lib/motion/shotcraft/upstream/demos/outro/grain-dissolve/GrainDissolve.tsx +222 -222
  122. package/lib/motion/shotcraft/upstream/demos/outro/logo-shrink-wordmark-lockup/LogoShrinkWordmarkLockup.tsx +223 -223
  123. package/lib/motion/shotcraft/upstream/demos/outro/neon-triple-marquee/NeonTripleMarquee.tsx +217 -217
  124. package/lib/motion/shotcraft/upstream/demos/outro/outro-group-photo-launch/OutroGroupPhotoLaunch.tsx +343 -343
  125. package/lib/motion/shotcraft/upstream/demos/outro/ui-strip-away-outro/UiStripAwayOutro.tsx +357 -357
  126. package/lib/motion/shotcraft/upstream/demos/outro/ui-to-brand-morph/IconFlipBloomLogo.tsx +187 -187
  127. package/lib/motion/shotcraft/upstream/demos/outro/ui-to-brand-morph/InputMorphsIntoLogo.tsx +333 -333
  128. package/lib/motion/shotcraft/upstream/demos/rhythm/beat-cut-moves/PaparazziFlash.tsx +274 -274
  129. package/lib/motion/shotcraft/upstream/demos/rhythm/beat-step-list-theme-cycle/BeatStepListThemeCycle.tsx +270 -270
  130. package/lib/motion/shotcraft/upstream/demos/rhythm/panel-grid-moves/ComicPanelSplit.tsx +430 -430
  131. package/lib/motion/shotcraft/upstream/demos/rhythm/quad-split-parallel-scenes/QuadSplitParallelScenes.tsx +252 -252
  132. package/lib/motion/shotcraft/upstream/demos/rhythm/rhythm-interrupt-moves/JumpCutPunchIn.tsx +106 -106
  133. package/lib/motion/shotcraft/upstream/demos/rhythm/sakuga-timing-shift/SakugaTimingShift.tsx +288 -288
  134. package/lib/motion/shotcraft/upstream/demos/rhythm/speed-ramp-freeze/FreezeAnnotateReal.tsx +362 -362
  135. package/lib/motion/shotcraft/upstream/demos/rhythm/trailer-grammar-moves/TrailerBumper.tsx +168 -168
  136. package/lib/motion/shotcraft/upstream/demos/transition/bottom-push-stack-wipe/BottomPushStackWipe.tsx +310 -310
  137. package/lib/motion/shotcraft/upstream/demos/transition/card-flip-reveal/CardFlipReveal.tsx +261 -261
  138. package/lib/motion/shotcraft/upstream/demos/transition/card-flock-tumble/CardFlockTumble.tsx +459 -459
  139. package/lib/motion/shotcraft/upstream/demos/transition/circle-match-iris/CircleMatchIris.tsx +294 -294
  140. package/lib/motion/shotcraft/upstream/demos/transition/gradient-transition/GradientTransition.tsx +161 -161
  141. package/lib/motion/shotcraft/upstream/demos/transition/line-carry-transition/LineCarryTransition.tsx +248 -248
  142. package/lib/motion/shotcraft/upstream/demos/transition/mosaic-reframe/MosaicReframe.tsx +359 -359
  143. package/lib/motion/shotcraft/upstream/demos/transition/page-turn-transitions/BarnDoorSplit.tsx +227 -227
  144. package/lib/motion/shotcraft/upstream/demos/transition/print-texture-transitions/InkBleedReveal.tsx +162 -162
  145. package/lib/motion/shotcraft/upstream/demos/transition/shot-transitions/PortalWipeV2.tsx +248 -248
  146. package/lib/motion/shotcraft/upstream/demos/transition/shot-transitions/WhipBrakeReal.tsx +186 -186
  147. package/lib/motion/shotcraft/upstream/demos/transition/tear-streak-transitions/GlitchDisplace.tsx +355 -355
  148. package/lib/motion/shotcraft/upstream/demos/transition/transition-hidden-cut/InvisibleCut.tsx +272 -272
  149. package/lib/motion/shotcraft/upstream/demos/transition/transition-hidden-cut/LightLeakBurn.tsx +262 -262
  150. package/lib/motion/shotcraft/upstream/demos/transition/transition-hidden-cut/VersusSlam.tsx +217 -217
  151. package/lib/motion/shotcraft/upstream/demos/transition/transition-travel/LetterformZoom.tsx +285 -285
  152. package/lib/motion/shotcraft/upstream/demos/transition/white-flash-logo-simplify-cut/WhiteFlashLogoSimplifyCut.tsx +205 -205
  153. package/lib/motion/shotcraft/upstream/demos/transition/wipe-transitions/BlindsSlice.tsx +178 -178
  154. package/lib/motion/shotcraft/upstream/demos/typography/blur-slide/BlurSlide.tsx +147 -147
  155. package/lib/motion/shotcraft/upstream/demos/typography/brace-expand/BraceExpand.tsx +143 -143
  156. package/lib/motion/shotcraft/upstream/demos/typography/brand-ink-open/BrandInkOpen.tsx +134 -134
  157. package/lib/motion/shotcraft/upstream/demos/typography/countdown-arc-scatter/CountdownArcScatter.tsx +217 -217
  158. package/lib/motion/shotcraft/upstream/demos/typography/flying-words/FlyingWords.tsx +198 -198
  159. package/lib/motion/shotcraft/upstream/demos/typography/glitch-cycle/GlitchCycle.tsx +221 -221
  160. package/lib/motion/shotcraft/upstream/demos/typography/gradient-word-sweep/GradientWordSweep.tsx +312 -312
  161. package/lib/motion/shotcraft/upstream/demos/typography/lead-word-zoom-assemble/LeadWordZoomAssemble.tsx +261 -261
  162. package/lib/motion/shotcraft/upstream/demos/typography/marker-underline-title/MarkerUnderlineTitle.tsx +121 -121
  163. package/lib/motion/shotcraft/upstream/demos/typography/outline-word-fill/OutlineWordFill.tsx +153 -153
  164. package/lib/motion/shotcraft/upstream/demos/typography/paper-title-card/PaperTitleCard.tsx +179 -179
  165. package/lib/motion/shotcraft/upstream/demos/typography/pill-chip-slot-cycle-handled/PillChipSlotCycleHandled.tsx +140 -140
  166. package/lib/motion/shotcraft/upstream/demos/typography/pill-slot-cycle/PillSlotCycle.tsx +309 -309
  167. package/lib/motion/shotcraft/upstream/demos/typography/text-column-converge/TextColumnConverge.tsx +191 -191
  168. package/lib/motion/shotcraft/upstream/demos/typography/title-demote-to-label/TitleDemoteToLabel.tsx +292 -292
  169. package/lib/motion/shotcraft/upstream/demos/typography/type-assembly-moves/LetterformDriftAssembly.tsx +135 -135
  170. package/lib/motion/shotcraft/upstream/demos/typography/type-assembly-moves/SplitTextStagger.tsx +124 -124
  171. package/lib/motion/shotcraft/upstream/demos/typography/type-assembly-moves/TextOnPath.tsx +255 -255
  172. package/lib/motion/shotcraft/upstream/demos/typography/type-entrance-moves/LetterDropPhysics.tsx +173 -173
  173. package/lib/motion/shotcraft/upstream/demos/typography/type-rhythm-sync/FontWeightPump.tsx +225 -225
  174. package/lib/motion/shotcraft/upstream/demos/typography/type-rhythm-sync/KaraokeFillSync.tsx +141 -141
  175. package/lib/motion/shotcraft/upstream/demos/typography/typewriter-moves/TypewriterErrorRetype.tsx +137 -137
  176. package/lib/motion/shotcraft/upstream/demos/typography/vertical-word-roll-blur-cycle/VerticalWordRollBlurCycle.tsx +147 -147
  177. package/lib/motion/shotcraft/upstream/demos/typography/word-relay-filmstrip/WordRelayFilmstrip.tsx +409 -409
  178. package/lib/motion/shotcraft/upstream/demos/typography/word-relay-geometry/WordRelayGeometry.tsx +280 -280
  179. package/lib/motion/shotcraft/upstream/demos/ui-entrance/avatar-bracket-carousel/AvatarBracketCarousel.tsx +271 -271
  180. package/lib/motion/shotcraft/upstream/demos/ui-entrance/bezier-source-converge-merge/BezierSourceConvergeMerge.tsx +385 -385
  181. package/lib/motion/shotcraft/upstream/demos/ui-entrance/card-stack/CardStack.tsx +312 -312
  182. package/lib/motion/shotcraft/upstream/demos/ui-entrance/carousel-3d/Carousel3D.tsx +303 -303
  183. package/lib/motion/shotcraft/upstream/demos/ui-entrance/clipcard-looping/ClipCardLooping.tsx +77 -77
  184. package/lib/motion/shotcraft/upstream/demos/ui-entrance/cloner-depth-echo/ClonerDepthEcho.tsx +311 -311
  185. package/lib/motion/shotcraft/upstream/demos/ui-entrance/deck-deal-flyin/DeckDealFlyin.tsx +307 -307
  186. package/lib/motion/shotcraft/upstream/demos/ui-entrance/doc-park-left-pill-deal/DocParkLeftPillDeal.tsx +349 -349
  187. package/lib/motion/shotcraft/upstream/demos/ui-entrance/document-typewriter-reveal/DocumentTypewriterReveal.tsx +255 -255
  188. package/lib/motion/shotcraft/upstream/demos/ui-entrance/draw-svg-trace/DrawSvgTrace.tsx +244 -244
  189. package/lib/motion/shotcraft/upstream/demos/ui-entrance/element-body-moves/ContactShadowLift.tsx +217 -217
  190. package/lib/motion/shotcraft/upstream/demos/ui-entrance/integration-hub-map/IntegrationHubMap.tsx +652 -652
  191. package/lib/motion/shotcraft/upstream/demos/ui-entrance/list-reveal/ListReveal.tsx +153 -153
  192. package/lib/motion/shotcraft/upstream/demos/ui-entrance/list-stack-press/ListStackPress.tsx +238 -238
  193. package/lib/motion/shotcraft/upstream/demos/ui-entrance/neon-frame-forerun/NeonFrameForerun.tsx +324 -324
  194. package/lib/motion/shotcraft/upstream/demos/ui-entrance/neon-frame-orbit-drop/NeonFrameForerunOrbit.tsx +354 -354
  195. package/lib/motion/shotcraft/upstream/demos/ui-entrance/page-waterfall-wall/PageWaterfallWall.tsx +101 -101
  196. package/lib/motion/shotcraft/upstream/demos/ui-entrance/page-waterfall-wall/VerticalTicker.tsx +129 -129
  197. package/lib/motion/shotcraft/upstream/demos/ui-entrance/product-card-progressive-assemble/ProductCardProgressiveAssemble.tsx +297 -297
  198. package/lib/motion/shotcraft/upstream/demos/ui-entrance/radial-wave/RadialWave.tsx +57 -57
  199. package/lib/motion/shotcraft/upstream/demos/ui-entrance/research-card-stack-scroll/ResearchCardStackScroll.tsx +155 -155
  200. package/lib/motion/shotcraft/upstream/demos/ui-entrance/row-embed/RowEmbed.tsx +175 -175
  201. package/lib/motion/shotcraft/upstream/demos/ui-entrance/value-stagger-gradient/ValueStaggerGradient.tsx +153 -153
  202. package/lib/motion/shotcraft/upstream/demos/ui-entrance/wall-reveal-moves/BentoLightUp.tsx +146 -146
  203. package/lib/motion/shotcraft/upstream/demos/ui-entrance/wall-reveal-moves/WireframeDrawOn.tsx +226 -226
  204. package/lib/motion/shotcraft/upstream/gallery/api/library.json +1 -1
  205. package/lib/motion/shotcraft/upstream/references/aesthetic-rules.md +193 -193
  206. package/lib/motion/shotcraft/upstream/references/final-review.md +121 -121
  207. package/lib/motion/shotcraft/upstream/references/guided-free-creation.md +199 -199
  208. package/lib/motion/shotcraft/upstream/references/jianying-export.md +183 -183
  209. package/lib/motion/shotcraft/upstream/references/music-beat-sync.md +257 -257
  210. package/lib/motion/shotcraft/upstream/references/pipeline.md +382 -382
  211. package/lib/motion/shotcraft/upstream/references/publish-upload-post.md +111 -111
  212. package/lib/motion/shotcraft/upstream/references/sequences/promo-energy-arc.md +50 -50
  213. package/lib/motion/shotcraft/upstream/references/sfx-sourcing.md +95 -95
  214. package/lib/motion/shotcraft/upstream/references/shots/camera/basic-3d-scene.md +41 -41
  215. package/lib/motion/shotcraft/upstream/references/shots/camera/crash-zoom-punch.md +52 -52
  216. package/lib/motion/shotcraft/upstream/references/shots/camera/cursor-flyover.md +39 -39
  217. package/lib/motion/shotcraft/upstream/references/shots/camera/depth-layer-moves.md +39 -39
  218. package/lib/motion/shotcraft/upstream/references/shots/camera/graze-face-tour.md +57 -57
  219. package/lib/motion/shotcraft/upstream/references/shots/camera/overhead-camera-moves.md +51 -51
  220. package/lib/motion/shotcraft/upstream/references/shots/camera/space-camera-moves.md +46 -46
  221. package/lib/motion/shotcraft/upstream/references/shots/camera/steep-tilt-glide.md +52 -52
  222. package/lib/motion/shotcraft/upstream/references/shots/camera/tension-camera-moves.md +43 -43
  223. package/lib/motion/shotcraft/upstream/references/shots/camera/terminal-3d.md +42 -42
  224. package/lib/motion/shotcraft/upstream/references/shots/data/before-after-slider-scrub.md +48 -48
  225. package/lib/motion/shotcraft/upstream/references/shots/data/chart-live-moves.md +52 -52
  226. package/lib/motion/shotcraft/upstream/references/shots/data/gauge-readout-moves.md +45 -45
  227. package/lib/motion/shotcraft/upstream/references/shots/data/scroll-brake-moves.md +46 -46
  228. package/lib/motion/shotcraft/upstream/references/shots/data/timeline-travel.md +44 -44
  229. package/lib/motion/shotcraft/upstream/references/shots/effects/assemble-then-type-flyin.md +63 -63
  230. package/lib/motion/shotcraft/upstream/references/shots/effects/aurora-bloom-bg-flip.md +54 -54
  231. package/lib/motion/shotcraft/upstream/references/shots/effects/brand-frame-snap.md +58 -58
  232. package/lib/motion/shotcraft/upstream/references/shots/effects/fui-hud-moves.md +35 -35
  233. package/lib/motion/shotcraft/upstream/references/shots/effects/glow-flyline-moves.md +53 -53
  234. package/lib/motion/shotcraft/upstream/references/shots/effects/icon-performance-moves.md +42 -42
  235. package/lib/motion/shotcraft/upstream/references/shots/effects/impact-feedback.md +50 -50
  236. package/lib/motion/shotcraft/upstream/references/shots/effects/light-play-moves.md +46 -46
  237. package/lib/motion/shotcraft/upstream/references/shots/effects/radial-ripple-phone-chips.md +56 -56
  238. package/lib/motion/shotcraft/upstream/references/shots/effects/riso-print-hits.md +49 -49
  239. package/lib/motion/shotcraft/upstream/references/shots/effects/scan-bracket-sweep.md +50 -50
  240. package/lib/motion/shotcraft/upstream/references/shots/effects/scanline-annotate-focus.md +53 -53
  241. package/lib/motion/shotcraft/upstream/references/shots/effects/scanline-assemble-flyin.md +53 -53
  242. package/lib/motion/shotcraft/upstream/references/shots/effects/slam-entrance-moves.md +55 -55
  243. package/lib/motion/shotcraft/upstream/references/shots/effects/spotlight-sweep-moves.md +52 -52
  244. package/lib/motion/shotcraft/upstream/references/shots/interaction/autolayout-gap-dial.md +60 -60
  245. package/lib/motion/shotcraft/upstream/references/shots/interaction/canvas-materialize-moves.md +57 -57
  246. package/lib/motion/shotcraft/upstream/references/shots/interaction/chip-grid-single-select-blackout.md +51 -51
  247. package/lib/motion/shotcraft/upstream/references/shots/interaction/collab-cursor-moves.md +41 -41
  248. package/lib/motion/shotcraft/upstream/references/shots/interaction/glass-pill-dictation-typing.md +53 -53
  249. package/lib/motion/shotcraft/upstream/references/shots/interaction/hashtag-to-pill-materialize.md +60 -60
  250. package/lib/motion/shotcraft/upstream/references/shots/interaction/picker-carousel-feature-cycle.md +55 -55
  251. package/lib/motion/shotcraft/upstream/references/shots/interaction/segmented-thumb-hero.md +57 -57
  252. package/lib/motion/shotcraft/upstream/references/shots/interaction/theme-switch-moves.md +47 -47
  253. package/lib/motion/shotcraft/upstream/references/shots/interaction/type-and-filter.md +37 -37
  254. package/lib/motion/shotcraft/upstream/references/shots/interaction/voice-waveform-live.md +54 -54
  255. package/lib/motion/shotcraft/upstream/references/shots/opening/brand-ink-open.md +36 -36
  256. package/lib/motion/shotcraft/upstream/references/shots/opening/crane-rise-reveal.md +56 -56
  257. package/lib/motion/shotcraft/upstream/references/shots/opening/dataviz-landscape-open.md +56 -56
  258. package/lib/motion/shotcraft/upstream/references/shots/opening/fracture.md +40 -40
  259. package/lib/motion/shotcraft/upstream/references/shots/opening/icon-field-colorize.md +60 -60
  260. package/lib/motion/shotcraft/upstream/references/shots/opening/letterspace-materialize.md +57 -57
  261. package/lib/motion/shotcraft/upstream/references/shots/opening/magician-card-flourish.md +73 -73
  262. package/lib/motion/shotcraft/upstream/references/shots/opening/orbit-ring-title-open.md +87 -87
  263. package/lib/motion/shotcraft/upstream/references/shots/opening/spotlight-hero-card.md +55 -55
  264. package/lib/motion/shotcraft/upstream/references/shots/opening/stroke-segment-build.md +50 -50
  265. package/lib/motion/shotcraft/upstream/references/shots/opening/text-as-mask.md +59 -59
  266. package/lib/motion/shotcraft/upstream/references/shots/outro/grain-dissolve.md +38 -38
  267. package/lib/motion/shotcraft/upstream/references/shots/outro/logo-shrink-wordmark-lockup.md +38 -38
  268. package/lib/motion/shotcraft/upstream/references/shots/outro/neon-triple-marquee.md +59 -59
  269. package/lib/motion/shotcraft/upstream/references/shots/outro/outro-group-photo-launch.md +39 -39
  270. package/lib/motion/shotcraft/upstream/references/shots/outro/ui-strip-away-outro.md +61 -61
  271. package/lib/motion/shotcraft/upstream/references/shots/outro/ui-to-brand-morph.md +52 -52
  272. package/lib/motion/shotcraft/upstream/references/shots/rhythm/beat-cut-moves.md +50 -50
  273. package/lib/motion/shotcraft/upstream/references/shots/rhythm/beat-step-list-theme-cycle.md +66 -66
  274. package/lib/motion/shotcraft/upstream/references/shots/rhythm/panel-grid-moves.md +43 -43
  275. package/lib/motion/shotcraft/upstream/references/shots/rhythm/quad-split-parallel-scenes.md +38 -38
  276. package/lib/motion/shotcraft/upstream/references/shots/rhythm/rhythm-interrupt-moves.md +38 -38
  277. package/lib/motion/shotcraft/upstream/references/shots/rhythm/sakuga-timing-shift.md +56 -56
  278. package/lib/motion/shotcraft/upstream/references/shots/rhythm/speed-ramp-freeze.md +44 -44
  279. package/lib/motion/shotcraft/upstream/references/shots/rhythm/trailer-grammar-moves.md +38 -38
  280. package/lib/motion/shotcraft/upstream/references/shots/transition/bottom-push-stack-wipe.md +63 -63
  281. package/lib/motion/shotcraft/upstream/references/shots/transition/card-flip-reveal.md +57 -57
  282. package/lib/motion/shotcraft/upstream/references/shots/transition/card-flock-tumble.md +63 -63
  283. package/lib/motion/shotcraft/upstream/references/shots/transition/circle-match-iris.md +58 -58
  284. package/lib/motion/shotcraft/upstream/references/shots/transition/gradient-transition.md +45 -45
  285. package/lib/motion/shotcraft/upstream/references/shots/transition/line-carry-transition.md +55 -55
  286. package/lib/motion/shotcraft/upstream/references/shots/transition/mosaic-reframe.md +49 -49
  287. package/lib/motion/shotcraft/upstream/references/shots/transition/page-turn-transitions.md +42 -42
  288. package/lib/motion/shotcraft/upstream/references/shots/transition/print-texture-transitions.md +42 -42
  289. package/lib/motion/shotcraft/upstream/references/shots/transition/shot-transitions.md +45 -45
  290. package/lib/motion/shotcraft/upstream/references/shots/transition/tear-streak-transitions.md +48 -48
  291. package/lib/motion/shotcraft/upstream/references/shots/transition/transition-hidden-cut.md +55 -55
  292. package/lib/motion/shotcraft/upstream/references/shots/transition/transition-travel.md +43 -43
  293. package/lib/motion/shotcraft/upstream/references/shots/transition/white-flash-logo-simplify-cut.md +41 -41
  294. package/lib/motion/shotcraft/upstream/references/shots/transition/wipe-transitions.md +42 -42
  295. package/lib/motion/shotcraft/upstream/references/shots/typography/blur-slide.md +59 -59
  296. package/lib/motion/shotcraft/upstream/references/shots/typography/brace-expand.md +55 -55
  297. package/lib/motion/shotcraft/upstream/references/shots/typography/countdown-arc-scatter.md +65 -65
  298. package/lib/motion/shotcraft/upstream/references/shots/typography/document-typewriter-reveal.md +42 -42
  299. package/lib/motion/shotcraft/upstream/references/shots/typography/flying-words.md +64 -64
  300. package/lib/motion/shotcraft/upstream/references/shots/typography/glitch-cycle.md +64 -64
  301. package/lib/motion/shotcraft/upstream/references/shots/typography/gradient-word-sweep.md +54 -54
  302. package/lib/motion/shotcraft/upstream/references/shots/typography/lead-word-zoom-assemble.md +91 -91
  303. package/lib/motion/shotcraft/upstream/references/shots/typography/marker-underline-title.md +51 -51
  304. package/lib/motion/shotcraft/upstream/references/shots/typography/outline-word-fill.md +66 -66
  305. package/lib/motion/shotcraft/upstream/references/shots/typography/paper-title-card.md +38 -38
  306. package/lib/motion/shotcraft/upstream/references/shots/typography/pill-chip-slot-cycle-handled.md +66 -66
  307. package/lib/motion/shotcraft/upstream/references/shots/typography/pill-slot-cycle.md +58 -58
  308. package/lib/motion/shotcraft/upstream/references/shots/typography/text-column-converge.md +61 -61
  309. package/lib/motion/shotcraft/upstream/references/shots/typography/title-demote-to-label.md +64 -64
  310. package/lib/motion/shotcraft/upstream/references/shots/typography/type-assembly-moves.md +45 -45
  311. package/lib/motion/shotcraft/upstream/references/shots/typography/type-entrance-moves.md +41 -41
  312. package/lib/motion/shotcraft/upstream/references/shots/typography/type-rhythm-sync.md +51 -51
  313. package/lib/motion/shotcraft/upstream/references/shots/typography/typewriter-moves.md +42 -42
  314. package/lib/motion/shotcraft/upstream/references/shots/typography/vertical-word-roll-blur-cycle.md +63 -63
  315. package/lib/motion/shotcraft/upstream/references/shots/typography/word-relay-filmstrip.md +57 -57
  316. package/lib/motion/shotcraft/upstream/references/shots/typography/word-relay-geometry.md +75 -75
  317. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/avatar-bracket-carousel.md +59 -59
  318. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/bezier-source-converge-merge.md +67 -67
  319. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/card-stack.md +60 -60
  320. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/carousel-3d.md +66 -66
  321. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/cloner-depth-echo.md +40 -40
  322. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/deck-deal-flyin.md +45 -45
  323. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/doc-park-left-pill-deal.md +62 -62
  324. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/draw-svg-trace.md +55 -55
  325. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/element-body-moves.md +37 -37
  326. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/integration-hub-map.md +55 -55
  327. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/list-reveal.md +50 -50
  328. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/list-stack-press.md +43 -43
  329. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/neon-frame-forerun.md +55 -55
  330. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/neon-frame-orbit-drop.md +51 -51
  331. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/page-waterfall-wall.md +51 -51
  332. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/product-card-progressive-assemble.md +56 -56
  333. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/radial-wave.md +49 -49
  334. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/research-card-stack-scroll.md +57 -57
  335. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/row-embed.md +36 -36
  336. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/value-stagger-gradient.md +64 -64
  337. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/wall-reveal-moves.md +47 -47
  338. package/lib/motion/shotcraft/upstream/references/sound-design.md +170 -170
  339. package/lib/motion/shotcraft/upstream/references/workbench.md +157 -157
  340. package/lib/motion/shotcraft/upstream/template/TEMPLATE.md +103 -103
  341. package/lib/motion/shotcraft/upstream/template/THEMES.md +44 -44
  342. package/lib/motion/shotcraft/upstream/template/package.json +20 -20
  343. package/lib/motion/shotcraft/upstream/template/remotion.config.ts +6 -6
  344. package/lib/motion/shotcraft/upstream/template/src/Root.tsx +17 -17
  345. package/lib/motion/shotcraft/upstream/template/src/aifl/Caption.tsx +65 -65
  346. package/lib/motion/shotcraft/upstream/template/src/aifl/DigitRoll.tsx +48 -48
  347. package/lib/motion/shotcraft/upstream/template/src/aifl/FlashCut.tsx +24 -24
  348. package/lib/motion/shotcraft/upstream/template/src/aifl/Main.tsx +192 -192
  349. package/lib/motion/shotcraft/upstream/template/src/aifl/PaperTitleCard.tsx +111 -111
  350. package/lib/motion/shotcraft/upstream/template/src/aifl/live/PageCam.tsx +150 -150
  351. package/lib/motion/shotcraft/upstream/template/src/aifl/live/SceneDetail.tsx +158 -158
  352. package/lib/motion/shotcraft/upstream/template/src/aifl/live/SceneFlyIn.tsx +468 -468
  353. package/lib/motion/shotcraft/upstream/template/src/aifl/live/SceneOpen.tsx +552 -552
  354. package/lib/motion/shotcraft/upstream/template/src/aifl/live/SceneOutroLive.tsx +411 -411
  355. package/lib/motion/shotcraft/upstream/template/src/aifl/live/ScenePapers.tsx +200 -200
  356. package/lib/motion/shotcraft/upstream/template/src/aifl/live/SceneWbr.tsx +324 -324
  357. package/lib/motion/shotcraft/upstream/template/src/aifl/live-layout.json +388 -388
  358. package/lib/motion/shotcraft/upstream/template/src/index.ts +4 -4
  359. package/lib/motion/shotcraft/upstream/template/src/themes/ThemedFilm.tsx +7 -7
  360. package/lib/motion/shotcraft/upstream/template/src/themes/manifest.tsx +68 -68
  361. package/lib/motion/shotcraft/upstream/template/src/themes/palette-assets.json +1 -1
  362. package/lib/motion/shotcraft/upstream/template/src/themes/palette-assets.ts +24 -24
  363. package/lib/motion/shotcraft/upstream/template/src/themes/palettes.json +74 -74
  364. package/lib/motion/shotcraft/upstream/template/src/themes/visual-theme.tsx +91 -91
  365. package/lib/motion/shotcraft/upstream/template/src/workbench.ts +213 -213
  366. package/lib/motion/shotcraft/upstream/template/tsconfig.json +15 -15
  367. package/lib/motion/style-frames.js +306 -306
  368. package/lib/motion/sync.js +214 -214
  369. package/lib/motion-library.js +1 -1
  370. package/lib/motion-project.js +105 -105
  371. package/lib/motion-render-worker.js +174 -174
  372. package/lib/routing/router.js +222 -222
  373. package/lib/routing/vendor/README.md +96 -96
  374. package/lib/routing/vendor/libavoid-routing.js +753 -753
  375. package/lib/routing/vendor/libavoid.min.js +59 -59
  376. package/lib/svg-export.js +1344 -0
  377. package/lib/video-trace-pool.js +128 -128
  378. package/package.json +3 -2
  379. package/LICENSE +0 -4175
@@ -1,359 +1,359 @@
1
- // mosaic-reframe — 12 张瓦片在三种排版间连续变形:规则网格 → feature mosaic → 对角瀑布串。
2
- // 位置 / 宽高 / 旋转各自独立插值(不走 transform 整体缩放),逐片错峰,段间留 hold。
3
- //
4
- // 第二轮重设计(暖沙 · 胶片分镜板):
5
- // - look = sand(米色 · 赤陶)。主体是 video-shotcraft 的一块分镜板(12 个镜头的定帧):12 张程序绘制的
6
- // "胶片照片"(落日海面 / 沙丘 / 拱门 / 雾山 / 泳池 / 柑橘静物 / 棕榈影 / 麦田八式,暖调统一),
7
- // 1920 原生坐标直接排版(不再从 480 设计坐标放大)。
8
- // - 因果:右上角分段控件 Grid / Mosaic / Cascade 是"布局的开关"——赤陶色指示胶囊先滑到下一档
9
- // (父先动),瓦片晚 4f 开始重排(子跟随),让观众看见"一次切换 → 整版重新思考"。
10
- // - 三态三种语气:A 规则网格(档案)→ B feature mosaic(首图占 3×2,压上衬线大字图注 = 策展)
11
- // → C 对角瀑布(每张变成带白边的相纸,-15° 起每张 +3° 递增旋转,像一手牌被摊开 = 态度),
12
- // C 态左下留白处升起衬线大标题「Every shot, in sequence.」,尾帧是一张完整的分镜海报。
13
- // - 运动:每片 x/y 用强 in-out(0.75,0,0.15,1)果断换位,w/h 晚 2f、旋转晚 4f 收敛(位置先到);
14
- // 换位途中按段进度 sin 包络"抬起"(放大 3.5% + 阴影变大变虚),落位贴回;B→C 旋转带一次轻过冲。
15
- // - 错峰:A→B 自左上主图起按序号波浪扫过(先密后疏);B→C 像发牌一样按序号依次摊开。
16
- //
17
- // 时间表(30fps,共 214f):
18
- // 0–22 预备:舞台、页眉与控件在场;12 张照片自左上沿对角线错峰升起(第 0 帧已有首张起始态)
19
- // 22–52 hold A:读网格(全程相机极缓推近 1→1.025)
20
- // 52–64 控件胶囊 Grid→Mosaic(snappy 12f)
21
- // 56–92 A→B 重排:每片 26f,错峰 10f;84–104 主图图注逐词升起
22
- // 92–128 hold B:读 mosaic
23
- // 128–140 控件胶囊 Mosaic→Cascade;图注 128 起退场
24
- // 132–176 B→C 摊牌:每片 30f,等间隔错峰 14f;相纸白边 0→14px;158–186 大标题逐词升起、副行淡入
25
- // 180–214 hold C:海报落定
26
- import React from 'react';
27
- import { useCurrentFrame } from 'remotion';
28
- import { EASE, FONT, Grain, bezier, mix, ramp, softShadow } from '../../_fixtures/Polish';
29
- import { LOOKS, SERIF, Stage, TextReveal, alpha, stagger, type } from '../../_fixtures/Look';
30
- import { BRAND, PITCH, ShotcraftMark } from '../../_fixtures/Brand';
31
-
32
- export const MOSAIC_REFRAME_DURATION = 214;
33
-
34
- const L = LOOKS.sand;
35
- const N = 12;
36
-
37
- // ───────────── 时间常量 ─────────────
38
- const T_AB = 52; // 控件切到 Mosaic
39
- const T_BC = 128; // 控件切到 Cascade
40
- const LAG = 4; // 瓦片晚于控件起跳的帧数(父先动、子跟随)
41
- const D_AB = 26;
42
- const D_BC = 30;
43
- const MOVE = bezier(0.75, 0, 0.15, 1); // 果断换位:慢起 → 急走 → 长尾软落
44
- const ROT_SETTLE = bezier(0.45, 0, 0.3, 1.22); // 旋转晚到并轻过冲一次
45
-
46
- // ───────────── 三套布局(1920×1080 原生像素)─────────────
47
- type Box = { x: number; y: number; w: number; h: number; rot: number };
48
- const X0 = 96, X1 = 1824, Y0 = 212, Y1 = 984; // 内容区:安全边距 96,页眉下方
49
-
50
- // A:4×3 规则网格
51
- const AG = 24;
52
- const AW = (X1 - X0 - 3 * AG) / 4, AH = (Y1 - Y0 - 2 * AG) / 3;
53
- const A: Box[] = Array.from({ length: N }, (_, i) => ({
54
- x: X0 + (i % 4) * (AW + AG), y: Y0 + Math.floor(i / 4) * (AH + AG), w: AW, h: AH, rot: 0,
55
- }));
56
-
57
- // B:6×4 单元格 feature mosaic,首片占 3×2
58
- const BG = 16;
59
- const UW = (X1 - X0 - 5 * BG) / 6, UH = (Y1 - Y0 - 3 * BG) / 4;
60
- const SLOTS: [number, number, number, number][] = [
61
- [0, 0, 3, 2], [3, 0, 1, 1], [4, 0, 1, 1], [5, 0, 1, 1], [3, 1, 2, 1], [5, 1, 1, 1],
62
- [0, 2, 1, 1], [1, 2, 2, 1], [3, 2, 1, 2], [4, 2, 2, 1], [0, 3, 3, 1], [4, 3, 2, 1],
63
- ];
64
- const B: Box[] = SLOTS.map(([c, r, cw, rh]) => ({
65
- x: X0 + c * (UW + BG), y: Y0 + r * (UH + BG), w: cw * UW + (cw - 1) * BG, h: rh * UH + (rh - 1) * BG, rot: 0,
66
- }));
67
-
68
- // C:对角瀑布串——竖幅相纸沿 (850,214)→(1724,930) 摊开,旋转 -15° 起每张 +3° 递增
69
- const CW = 300, CH = 372;
70
- const C: Box[] = Array.from({ length: N }, (_, i) => {
71
- const s = i / (N - 1);
72
- const cx = 850 + 874 * s, cy = 214 + 716 * s;
73
- return { x: cx - CW / 2, y: cy - CH / 2, w: CW, h: CH, rot: -15 + i * 3 };
74
- });
75
-
76
- // ───────────── 照片(程序插画,viewBox 160×100 + slice ≈ object-fit: cover)─────────────
77
- type Kind = 'sun' | 'dune' | 'arch' | 'ridge' | 'pool' | 'citrus' | 'palm' | 'field';
78
- const PHOTOS: { kind: Kind; v: number }[] = [
79
- { kind: 'sun', v: 0 }, { kind: 'dune', v: 0 }, { kind: 'pool', v: 0 }, { kind: 'arch', v: 0 },
80
- { kind: 'ridge', v: 0 }, { kind: 'citrus', v: 0 }, { kind: 'palm', v: 0 }, { kind: 'field', v: 0 },
81
- { kind: 'dune', v: 1 }, { kind: 'arch', v: 1 }, { kind: 'sun', v: 1 }, { kind: 'ridge', v: 1 },
82
- ];
83
-
84
- const Photo: React.FC<{ i: number }> = ({ i }) => {
85
- const { kind, v } = PHOTOS[i];
86
- const id = `mr${i}`;
87
- const g = (stops: [string, number][], vertical = true) => (
88
- <linearGradient id={`${id}g`} x1="0" y1="0" x2={vertical ? 0 : 1} y2={vertical ? 1 : 0}>
89
- {stops.map(([c, o], k) => <stop key={k} offset={o} stopColor={c} />)}
90
- </linearGradient>
91
- );
92
- let body: React.ReactNode = null;
93
- let defs: React.ReactNode = null;
94
- if (kind === 'sun') {
95
- const warm = v === 0;
96
- const sx = warm ? 126 : 80; // 主图的太阳偏右,给左下图注让位
97
- defs = g(warm ? [['#f6c58e', 0], ['#ec8f5b', 0.55], ['#d8643f', 1]] : [['#f4d3b0', 0], ['#e6a07a', 0.6], ['#c97a62', 1]]);
98
- body = (
99
- <>
100
- <rect width="160" height="64" fill={`url(#${id}g)`} />
101
- <circle cx={sx} cy="56" r={warm ? 15 : 11} fill="#fff1d6" />
102
- <circle cx={sx} cy="56" r={warm ? 26 : 20} fill="#fff1d6" opacity="0.18" />
103
- <rect y="60" width="160" height="40" fill={warm ? '#3e4a63' : '#5a5f78'} />
104
- <rect y="60" width="160" height="6" fill={warm ? '#566078' : '#6e728a'} opacity="0.8" />
105
- {[63, 67, 72, 78, 85].map((y, k) => (
106
- <rect key={k} x={sx - (16 - k * 2.2)} y={y} width={2 * (16 - k * 2.2)} height={1.2 + k * 0.2} rx="0.6" fill="#ffe2b4" opacity={0.75 - k * 0.12} />
107
- ))}
108
- </>
109
- );
110
- } else if (kind === 'dune') {
111
- const a = v === 0;
112
- defs = g(a ? [['#f3dcc0', 0], ['#ecc39a', 1]] : [['#e9d2c4', 0], ['#e1b6a0', 1]]);
113
- body = (
114
- <>
115
- <rect width="160" height="100" fill={`url(#${id}g)`} />
116
- <circle cx={a ? 118 : 40} cy="24" r="8" fill="#fff4e2" opacity="0.9" />
117
- <path d="M0 62 C 30 46, 60 44, 92 58 S 140 66, 160 52 V100 H0Z" fill={a ? '#dc9a68' : '#cf8f72'} />
118
- <path d="M0 74 C 40 60, 70 64, 100 76 S 140 82, 160 70 V100 H0Z" fill={a ? '#c4733f' : '#b4705a'} />
119
- <path d="M30 100 C 60 80, 100 78, 160 86 V100Z" fill={a ? '#8f4a2b' : '#7f4c3f'} />
120
- <path d="M0 62 C 30 46, 60 44, 92 58" fill="none" stroke="#fbe3c4" strokeWidth="0.8" opacity="0.7" />
121
- </>
122
- );
123
- } else if (kind === 'arch') {
124
- const a = v === 0;
125
- defs = g(a ? [['#efd2b4', 0], ['#e2b48f', 1]] : [['#e9c9c0', 0], ['#d9a497', 1]], false);
126
- body = (
127
- <>
128
- <rect width="160" height="100" fill={`url(#${id}g)`} />
129
- <path d="M58 100 V52 A22 22 0 0 1 102 52 V100Z" fill={a ? '#6e3f2b' : '#5d3a3a'} />
130
- <path d="M66 100 V56 A14 14 0 0 1 94 56 V100Z" fill={a ? '#f1c795' : '#f0c2a8'} opacity="0.9" />
131
- <polygon points="0,0 70,0 20,100 0,100" fill="#ffffff" opacity="0.12" />
132
- <polygon points="102,100 160,40 160,100" fill={a ? '#b97d58' : '#a8706a'} opacity="0.45" />
133
- <rect y="92" width="160" height="8" fill={a ? '#c08a62' : '#b1817a'} />
134
- </>
135
- );
136
- } else if (kind === 'ridge') {
137
- const a = v === 0;
138
- defs = g(a ? [['#e9e4dc', 0], ['#c9cfd6', 1]] : [['#efe0d0', 0], ['#d7c4b4', 1]]);
139
- body = (
140
- <>
141
- <rect width="160" height="100" fill={`url(#${id}g)`} />
142
- <polygon points="0,62 26,40 46,54 74,28 104,52 126,38 160,56 160,100 0,100" fill={a ? '#a9b4c2' : '#c4ab98'} />
143
- <polygon points="0,74 34,54 62,68 96,46 130,66 160,58 160,100 0,100" fill={a ? '#7d8ca0' : '#a5846c'} />
144
- <polygon points="0,86 40,70 84,84 120,68 160,80 160,100 0,100" fill={a ? '#4f5d72' : '#7a5a46'} />
145
- <rect y="56" width="160" height="10" fill="#ffffff" opacity="0.18" />
146
- </>
147
- );
148
- } else if (kind === 'pool') {
149
- defs = g([['#6cc3c1', 0], ['#2f8c96', 1]]);
150
- body = (
151
- <>
152
- <rect width="160" height="100" fill={`url(#${id}g)`} />
153
- <rect y="0" width="160" height="22" fill="#efe2cf" />
154
- <rect y="20" width="160" height="3" fill="#d9c7ad" />
155
- {[40, 62, 84].map((y, k) => <rect key={k} x="0" y={y} width="160" height="1.6" fill="#ffffff" opacity="0.35" />)}
156
- <path d="M10 50 Q 40 44 70 52 T 130 50" fill="none" stroke="#ffffff" strokeWidth="1.2" opacity="0.5" />
157
- <path d="M30 72 Q 60 66 90 74 T 150 72" fill="none" stroke="#ffffff" strokeWidth="1" opacity="0.4" />
158
- <polygon points="100,23 160,23 160,100 130,100" fill="#1c5f6c" opacity="0.35" />
159
- </>
160
- );
161
- } else if (kind === 'citrus') {
162
- defs = g([['#f1e3cc', 0], ['#e6d1b2', 1]]);
163
- body = (
164
- <>
165
- <rect width="160" height="100" fill={`url(#${id}g)`} />
166
- <rect y="64" width="160" height="36" fill="#c67a45" />
167
- <rect y="64" width="160" height="2" fill="#e29a63" />
168
- <ellipse cx="74" cy="78" rx="44" ry="5" fill="#8d4f2a" opacity="0.4" />
169
- <circle cx="64" cy="60" r="15" fill="#ef8a36" />
170
- <circle cx="90" cy="64" r="11" fill="#f3a246" />
171
- <circle cx="59" cy="55" r="4" fill="#ffd29a" opacity="0.7" />
172
- <circle cx="87" cy="60" r="3" fill="#ffe0b0" opacity="0.7" />
173
- <path d="M64 45 q 5 -6 11 -4 q -4 6 -11 4z" fill="#5d7a4a" />
174
- </>
175
- );
176
- } else if (kind === 'palm') {
177
- defs = g([['#ecc2aa', 0], ['#e0a68c', 1]], false);
178
- body = (
179
- <>
180
- <rect width="160" height="100" fill={`url(#${id}g)`} />
181
- {[0, 1, 2, 3, 4, 5].map((k) => (
182
- <path key={k} d={`M40 10 Q ${60 + k * 14} ${10 + k * 10} ${78 + k * 16} ${28 + k * 14}`} fill="none" stroke="#b97862" strokeWidth={5 - k * 0.4} strokeLinecap="round" opacity="0.55" />
183
- ))}
184
- <path d="M40 10 L 34 100" stroke="#b97862" strokeWidth="3" opacity="0.5" />
185
- <rect y="88" width="160" height="12" fill="#c98d74" />
186
- </>
187
- );
188
- } else {
189
- defs = g([['#f3e1c0', 0], ['#e9c992', 1]]);
190
- body = (
191
- <>
192
- <rect width="160" height="100" fill={`url(#${id}g)`} />
193
- <rect y="0" width="160" height="40" fill="#e8d7bd" />
194
- <circle cx="128" cy="20" r="7" fill="#fff3dc" />
195
- {Array.from({ length: 9 }, (_, k) => (
196
- <path key={k} d={`M80 40 L ${-60 + k * 35} 100`} stroke="#c49a52" strokeWidth={1.4 + k * 0.1} opacity="0.55" />
197
- ))}
198
- <path d="M0 40 H160" stroke="#b9925a" strokeWidth="1" opacity="0.6" />
199
- </>
200
- );
201
- }
202
- return (
203
- <svg width="100%" height="100%" viewBox="0 0 160 100" preserveAspectRatio="xMidYMid slice" style={{ position: 'absolute', inset: 0, display: 'block' }}>
204
- <defs>{defs}</defs>
205
- {body}
206
- </svg>
207
- );
208
- };
209
-
210
- // ───────────── 分段控件(布局开关)─────────────
211
- const SEG = ['Grid', 'Mosaic', 'Cascade'];
212
- const SEG_W = 168, SEG_H = 60, SEG_PAD = 6;
213
- const Segmented: React.FC<{ frame: number }> = ({ frame }) => {
214
- const p1 = ramp(frame, T_AB, 12, EASE.snappy);
215
- const p2 = ramp(frame, T_BC, 12, EASE.snappy);
216
- const pos = p1 + p2; // 0 → 1 → 2
217
- // 胶囊在途中横向拉长(像被拽过去),到位收回
218
- const stretch = 1 + 0.18 * (Math.sin(Math.PI * p1) + Math.sin(Math.PI * p2));
219
- const press = (k: number, t: number) => 1 - 0.05 * Math.sin(Math.PI * ramp(frame, t - 3, 8, EASE.linear)) * (k > 0 ? 1 : 0);
220
- return (
221
- <div style={{
222
- position: 'absolute', right: 96, top: 92, width: SEG_W * 3 + SEG_PAD * 2, height: SEG_H + SEG_PAD * 2, borderRadius: 999,
223
- background: alpha('#ffffff', 0.55), boxShadow: `inset 0 0 0 1px ${L.line}, ${softShadow(6, { color: L.shadow, strength: 0.6 })}`,
224
- }}>
225
- <div style={{
226
- position: 'absolute', top: SEG_PAD, left: SEG_PAD + pos * SEG_W, width: SEG_W, height: SEG_H, borderRadius: 999,
227
- background: L.accent, transform: `scaleX(${stretch.toFixed(4)})`,
228
- boxShadow: `0 6px 16px -6px ${alpha(L.accent, 0.7)}, inset 0 1px 0 rgba(255,255,255,0.25)`,
229
- }} />
230
- {SEG.map((s, k) => {
231
- const on = Math.max(0, 1 - Math.abs(pos - k));
232
- return (
233
- <div key={s} style={{
234
- position: 'absolute', top: SEG_PAD, left: SEG_PAD + k * SEG_W, width: SEG_W, height: SEG_H,
235
- display: 'flex', alignItems: 'center', justifyContent: 'center',
236
- ...type(30, 600), letterSpacing: '-0.01em',
237
- color: on > 0.5 ? L.onAccent : L.ink2,
238
- transform: `scale(${(k === 1 ? press(1, T_AB) : k === 2 ? press(2, T_BC) : 1).toFixed(4)})`,
239
- }}>{s}</div>
240
- );
241
- })}
242
- </div>
243
- );
244
- };
245
-
246
- // 瓦片在某帧的几何:A→B、B→C 两段各自的进度,位置 / 宽高 / 旋转错开收敛
247
- const tileAt = (frame: number, i: number) => {
248
- const sAB = T_AB + LAG + stagger(i, N, 10, EASE.out);
249
- const sBC = T_BC + LAG + stagger(i, N, 14, EASE.linear); // 发牌:等间隔依次摊开
250
- const pAB = ramp(frame, sAB, D_AB, MOVE);
251
- const pBC = ramp(frame, sBC, D_BC, MOVE);
252
- const sAB2 = ramp(frame, sAB + 2, D_AB, MOVE); // 宽高晚 2f
253
- const sBC2 = ramp(frame, sBC + 2, D_BC, MOVE);
254
- const rBC = ramp(frame, sBC + 4, D_BC, ROT_SETTLE); // 旋转晚 4f + 过冲
255
- const a = A[i], b = B[i], c = C[i];
256
- // 以中心插值位置(宽高变化时中心走直线,不会"先长后跑")
257
- const cxA = a.x + a.w / 2, cyA = a.y + a.h / 2, cxB = b.x + b.w / 2, cyB = b.y + b.h / 2, cxC = c.x + c.w / 2, cyC = c.y + c.h / 2;
258
- const cx = mix(mix(cxA, cxB, pAB), cxC, pBC);
259
- const cy = mix(mix(cyA, cyB, pAB), cyC, pBC);
260
- const w = mix(mix(a.w, b.w, sAB2), c.w, sBC2);
261
- const h = mix(mix(a.h, b.h, sAB2), c.h, sBC2);
262
- const rot = mix(0, c.rot, rBC);
263
- const lift = Math.max(Math.sin(Math.PI * pAB), Math.sin(Math.PI * pBC));
264
- return { cx, cy, w, h, rot, lift, pBC: sBC2, moving: pBC > 0 };
265
- };
266
-
267
- export const MosaicReframe: React.FC = () => {
268
- const frame = useCurrentFrame();
269
- const cam = mix(1, 1.025, ramp(frame, 0, 214, EASE.smooth)); // 全程极缓推近
270
-
271
- // 主图图注(B 态):84f 起逐词升起,128f 起退场
272
- const capOut = ramp(frame, T_BC, 10, EASE.exit);
273
- // C 态大标题
274
- const HEAD = 158;
275
-
276
- const tiles = Array.from({ length: N }, (_, i) => ({ i, ...tileAt(frame, i) }));
277
- // 叠放次序:B→C 起按序号(后发的牌压在上面);之前主图最高
278
- const inC = frame >= T_BC + LAG;
279
- const z = (i: number) => (inC ? 10 + i : i === 0 ? 30 : 10);
280
-
281
- return (
282
- <div style={{ position: 'absolute', inset: 0, overflow: 'hidden', fontFamily: FONT.sans }}>
283
- <Stage look={L} keyLight={{ x: 0.28, y: 0.02 }} fill={{ x: 0.9, y: 0.95 }} />
284
-
285
- <div style={{ position: 'absolute', inset: 0, transform: `scale(${cam.toFixed(5)})`, transformOrigin: '50% 46%' }}>
286
- {/* 页眉:品牌标志 + 小写字标 + 分镜板名(标志按亮底 light 版;字标与分镜名同一基线)。
287
- 总宽压在 x≈620 以内——C 态首张相纸的左上角在 x≈650,页眉再长会被它盖住 */}
288
- <div style={{ position: 'absolute', left: 96, top: 92, height: 72, display: 'flex', alignItems: 'center', gap: 18, color: L.ink }}>
289
- <ShotcraftMark size={50} tone="light" />
290
- <div style={{ display: 'flex', alignItems: 'baseline', gap: 20 }}>
291
- <span style={{ fontFamily: BRAND.font, fontSize: 36, fontWeight: 700, letterSpacing: '0.03em', lineHeight: 1 }}>{BRAND.name}</span>
292
- <span style={{ ...type(32, 450), color: L.ink2 }}>Storyboard</span>
293
- </div>
294
- </div>
295
- <Segmented frame={frame} />
296
-
297
- {/* C 态大标题(左下留白处) */}
298
- <div style={{ position: 'absolute', left: 96, top: 676, color: L.ink }}>
299
- <div style={{ ...type(124, 500, { serif: true }), letterSpacing: '-0.035em', lineHeight: 1.0 }}>
300
- <TextReveal text="Every shot," start={HEAD} by="word" variant="rise" each={20} gap={5} />
301
- <br />
302
- <TextReveal text="in sequence." start={HEAD + 6} by="word" variant="rise" each={20} gap={5}
303
- unitStyle={() => ({ fontStyle: 'italic', color: L.accent })} />
304
- </div>
305
- <div style={{
306
- ...type(32, 450), color: L.ink2, marginTop: 26,
307
- opacity: ramp(frame, HEAD + 14, 16, EASE.out), transform: `translateY(${mix(12, 0, ramp(frame, HEAD + 14, 18, EASE.snappy)).toFixed(2)}px)`,
308
- }}>{PITCH.en.taglines[4]}</div>
309
- </div>
310
-
311
- {tiles.map(({ i, cx, cy, w, h, rot, lift, pBC }) => {
312
- // 开场:沿对角线错峰升起(从左上到右下)
313
- const order = (i % 4) + Math.floor(i / 4);
314
- const inP = ramp(frame, stagger(order, 6, 14, EASE.out) - 2, 16, EASE.snappy);
315
- const pad = 14 * pBC; // 相纸白边
316
- const radius = mix(16, 6, pBC);
317
- const scale = mix(0.94, 1, inP) * (1 + 0.035 * lift);
318
- const elev = 6 + 34 * lift + 8 * pBC;
319
- return (
320
- <div key={i} style={{
321
- position: 'absolute', left: cx - w / 2, top: cy - h / 2 + (1 - inP) * 40, width: w, height: h,
322
- transform: `rotate(${rot.toFixed(3)}deg) scale(${scale.toFixed(4)})`,
323
- opacity: inP, zIndex: z(i), borderRadius: radius,
324
- background: L.surface, boxShadow: softShadow(elev, { color: L.shadow, strength: 0.9 + 0.5 * pBC }),
325
- }}>
326
- <div style={{ position: 'absolute', inset: pad, borderRadius: Math.max(2, radius - pad * 0.7), overflow: 'hidden' }}>
327
- <Photo i={i} />
328
- {/* 照片内缘一圈极淡暗边:像冲印的晕影,让亮色照片在米色底上立得住 */}
329
- <div style={{ position: 'absolute', inset: 0, boxShadow: 'inset 0 0 0 1px rgba(60,30,10,0.10), inset 0 -60px 80px -40px rgba(40,20,10,0.18)' }} />
330
- {i === 0 && (
331
- <div style={{
332
- position: 'absolute', inset: 0,
333
- background: 'linear-gradient(200deg, rgba(30,18,10,0) 40%, rgba(30,18,10,0.6) 100%)',
334
- opacity: ramp(frame, T_AB + LAG + 16, 14, EASE.out) * (1 - capOut),
335
- }} />
336
- )}
337
- </div>
338
- {/* 主图图注:B 态的策展语气 */}
339
- {i === 0 && frame >= T_AB + LAG + 20 && capOut < 1 && (
340
- <div style={{ position: 'absolute', left: 44, bottom: 36, color: '#fff8ee', opacity: 1 - capOut }}>
341
- <div style={{ ...type(30, 650, { caps: true }), letterSpacing: '0.16em', color: '#ffd9b8', marginBottom: 10 }}>
342
- <TextReveal text="Featured shot" start={T_AB + LAG + 22} by="word" variant="blur" each={14} />
343
- </div>
344
- <div style={{ ...type(84, 500, { serif: true }), letterSpacing: '-0.03em', textShadow: '0 2px 18px rgba(30,15,5,0.35)' }}>
345
- <TextReveal text="Golden Hour" start={T_AB + LAG + 26} by="word" variant="rise" each={18} gap={5} />
346
- </div>
347
- <div style={{ ...type(32, 450), color: 'rgba(255,248,238,0.82)', marginTop: 8, opacity: ramp(frame, T_AB + LAG + 34, 14, EASE.out) }}>
348
- Shot 01 · Crash zoom · 4.5 s
349
- </div>
350
- </div>
351
- )}
352
- </div>
353
- );
354
- })}
355
- </div>
356
- <Grain opacity={0.05} blend="overlay" />
357
- </div>
358
- );
359
- };
1
+ // mosaic-reframe — 12 张瓦片在三种排版间连续变形:规则网格 → feature mosaic → 对角瀑布串。
2
+ // 位置 / 宽高 / 旋转各自独立插值(不走 transform 整体缩放),逐片错峰,段间留 hold。
3
+ //
4
+ // 第二轮重设计(暖沙 · 胶片分镜板):
5
+ // - look = sand(米色 · 赤陶)。主体是 video-shotcraft 的一块分镜板(12 个镜头的定帧):12 张程序绘制的
6
+ // "胶片照片"(落日海面 / 沙丘 / 拱门 / 雾山 / 泳池 / 柑橘静物 / 棕榈影 / 麦田八式,暖调统一),
7
+ // 1920 原生坐标直接排版(不再从 480 设计坐标放大)。
8
+ // - 因果:右上角分段控件 Grid / Mosaic / Cascade 是"布局的开关"——赤陶色指示胶囊先滑到下一档
9
+ // (父先动),瓦片晚 4f 开始重排(子跟随),让观众看见"一次切换 → 整版重新思考"。
10
+ // - 三态三种语气:A 规则网格(档案)→ B feature mosaic(首图占 3×2,压上衬线大字图注 = 策展)
11
+ // → C 对角瀑布(每张变成带白边的相纸,-15° 起每张 +3° 递增旋转,像一手牌被摊开 = 态度),
12
+ // C 态左下留白处升起衬线大标题「Every shot, in sequence.」,尾帧是一张完整的分镜海报。
13
+ // - 运动:每片 x/y 用强 in-out(0.75,0,0.15,1)果断换位,w/h 晚 2f、旋转晚 4f 收敛(位置先到);
14
+ // 换位途中按段进度 sin 包络"抬起"(放大 3.5% + 阴影变大变虚),落位贴回;B→C 旋转带一次轻过冲。
15
+ // - 错峰:A→B 自左上主图起按序号波浪扫过(先密后疏);B→C 像发牌一样按序号依次摊开。
16
+ //
17
+ // 时间表(30fps,共 214f):
18
+ // 0–22 预备:舞台、页眉与控件在场;12 张照片自左上沿对角线错峰升起(第 0 帧已有首张起始态)
19
+ // 22–52 hold A:读网格(全程相机极缓推近 1→1.025)
20
+ // 52–64 控件胶囊 Grid→Mosaic(snappy 12f)
21
+ // 56–92 A→B 重排:每片 26f,错峰 10f;84–104 主图图注逐词升起
22
+ // 92–128 hold B:读 mosaic
23
+ // 128–140 控件胶囊 Mosaic→Cascade;图注 128 起退场
24
+ // 132–176 B→C 摊牌:每片 30f,等间隔错峰 14f;相纸白边 0→14px;158–186 大标题逐词升起、副行淡入
25
+ // 180–214 hold C:海报落定
26
+ import React from 'react';
27
+ import { useCurrentFrame } from 'remotion';
28
+ import { EASE, FONT, Grain, bezier, mix, ramp, softShadow } from '../../_fixtures/Polish';
29
+ import { LOOKS, SERIF, Stage, TextReveal, alpha, stagger, type } from '../../_fixtures/Look';
30
+ import { BRAND, PITCH, ShotcraftMark } from '../../_fixtures/Brand';
31
+
32
+ export const MOSAIC_REFRAME_DURATION = 214;
33
+
34
+ const L = LOOKS.sand;
35
+ const N = 12;
36
+
37
+ // ───────────── 时间常量 ─────────────
38
+ const T_AB = 52; // 控件切到 Mosaic
39
+ const T_BC = 128; // 控件切到 Cascade
40
+ const LAG = 4; // 瓦片晚于控件起跳的帧数(父先动、子跟随)
41
+ const D_AB = 26;
42
+ const D_BC = 30;
43
+ const MOVE = bezier(0.75, 0, 0.15, 1); // 果断换位:慢起 → 急走 → 长尾软落
44
+ const ROT_SETTLE = bezier(0.45, 0, 0.3, 1.22); // 旋转晚到并轻过冲一次
45
+
46
+ // ───────────── 三套布局(1920×1080 原生像素)─────────────
47
+ type Box = { x: number; y: number; w: number; h: number; rot: number };
48
+ const X0 = 96, X1 = 1824, Y0 = 212, Y1 = 984; // 内容区:安全边距 96,页眉下方
49
+
50
+ // A:4×3 规则网格
51
+ const AG = 24;
52
+ const AW = (X1 - X0 - 3 * AG) / 4, AH = (Y1 - Y0 - 2 * AG) / 3;
53
+ const A: Box[] = Array.from({ length: N }, (_, i) => ({
54
+ x: X0 + (i % 4) * (AW + AG), y: Y0 + Math.floor(i / 4) * (AH + AG), w: AW, h: AH, rot: 0,
55
+ }));
56
+
57
+ // B:6×4 单元格 feature mosaic,首片占 3×2
58
+ const BG = 16;
59
+ const UW = (X1 - X0 - 5 * BG) / 6, UH = (Y1 - Y0 - 3 * BG) / 4;
60
+ const SLOTS: [number, number, number, number][] = [
61
+ [0, 0, 3, 2], [3, 0, 1, 1], [4, 0, 1, 1], [5, 0, 1, 1], [3, 1, 2, 1], [5, 1, 1, 1],
62
+ [0, 2, 1, 1], [1, 2, 2, 1], [3, 2, 1, 2], [4, 2, 2, 1], [0, 3, 3, 1], [4, 3, 2, 1],
63
+ ];
64
+ const B: Box[] = SLOTS.map(([c, r, cw, rh]) => ({
65
+ x: X0 + c * (UW + BG), y: Y0 + r * (UH + BG), w: cw * UW + (cw - 1) * BG, h: rh * UH + (rh - 1) * BG, rot: 0,
66
+ }));
67
+
68
+ // C:对角瀑布串——竖幅相纸沿 (850,214)→(1724,930) 摊开,旋转 -15° 起每张 +3° 递增
69
+ const CW = 300, CH = 372;
70
+ const C: Box[] = Array.from({ length: N }, (_, i) => {
71
+ const s = i / (N - 1);
72
+ const cx = 850 + 874 * s, cy = 214 + 716 * s;
73
+ return { x: cx - CW / 2, y: cy - CH / 2, w: CW, h: CH, rot: -15 + i * 3 };
74
+ });
75
+
76
+ // ───────────── 照片(程序插画,viewBox 160×100 + slice ≈ object-fit: cover)─────────────
77
+ type Kind = 'sun' | 'dune' | 'arch' | 'ridge' | 'pool' | 'citrus' | 'palm' | 'field';
78
+ const PHOTOS: { kind: Kind; v: number }[] = [
79
+ { kind: 'sun', v: 0 }, { kind: 'dune', v: 0 }, { kind: 'pool', v: 0 }, { kind: 'arch', v: 0 },
80
+ { kind: 'ridge', v: 0 }, { kind: 'citrus', v: 0 }, { kind: 'palm', v: 0 }, { kind: 'field', v: 0 },
81
+ { kind: 'dune', v: 1 }, { kind: 'arch', v: 1 }, { kind: 'sun', v: 1 }, { kind: 'ridge', v: 1 },
82
+ ];
83
+
84
+ const Photo: React.FC<{ i: number }> = ({ i }) => {
85
+ const { kind, v } = PHOTOS[i];
86
+ const id = `mr${i}`;
87
+ const g = (stops: [string, number][], vertical = true) => (
88
+ <linearGradient id={`${id}g`} x1="0" y1="0" x2={vertical ? 0 : 1} y2={vertical ? 1 : 0}>
89
+ {stops.map(([c, o], k) => <stop key={k} offset={o} stopColor={c} />)}
90
+ </linearGradient>
91
+ );
92
+ let body: React.ReactNode = null;
93
+ let defs: React.ReactNode = null;
94
+ if (kind === 'sun') {
95
+ const warm = v === 0;
96
+ const sx = warm ? 126 : 80; // 主图的太阳偏右,给左下图注让位
97
+ defs = g(warm ? [['#f6c58e', 0], ['#ec8f5b', 0.55], ['#d8643f', 1]] : [['#f4d3b0', 0], ['#e6a07a', 0.6], ['#c97a62', 1]]);
98
+ body = (
99
+ <>
100
+ <rect width="160" height="64" fill={`url(#${id}g)`} />
101
+ <circle cx={sx} cy="56" r={warm ? 15 : 11} fill="#fff1d6" />
102
+ <circle cx={sx} cy="56" r={warm ? 26 : 20} fill="#fff1d6" opacity="0.18" />
103
+ <rect y="60" width="160" height="40" fill={warm ? '#3e4a63' : '#5a5f78'} />
104
+ <rect y="60" width="160" height="6" fill={warm ? '#566078' : '#6e728a'} opacity="0.8" />
105
+ {[63, 67, 72, 78, 85].map((y, k) => (
106
+ <rect key={k} x={sx - (16 - k * 2.2)} y={y} width={2 * (16 - k * 2.2)} height={1.2 + k * 0.2} rx="0.6" fill="#ffe2b4" opacity={0.75 - k * 0.12} />
107
+ ))}
108
+ </>
109
+ );
110
+ } else if (kind === 'dune') {
111
+ const a = v === 0;
112
+ defs = g(a ? [['#f3dcc0', 0], ['#ecc39a', 1]] : [['#e9d2c4', 0], ['#e1b6a0', 1]]);
113
+ body = (
114
+ <>
115
+ <rect width="160" height="100" fill={`url(#${id}g)`} />
116
+ <circle cx={a ? 118 : 40} cy="24" r="8" fill="#fff4e2" opacity="0.9" />
117
+ <path d="M0 62 C 30 46, 60 44, 92 58 S 140 66, 160 52 V100 H0Z" fill={a ? '#dc9a68' : '#cf8f72'} />
118
+ <path d="M0 74 C 40 60, 70 64, 100 76 S 140 82, 160 70 V100 H0Z" fill={a ? '#c4733f' : '#b4705a'} />
119
+ <path d="M30 100 C 60 80, 100 78, 160 86 V100Z" fill={a ? '#8f4a2b' : '#7f4c3f'} />
120
+ <path d="M0 62 C 30 46, 60 44, 92 58" fill="none" stroke="#fbe3c4" strokeWidth="0.8" opacity="0.7" />
121
+ </>
122
+ );
123
+ } else if (kind === 'arch') {
124
+ const a = v === 0;
125
+ defs = g(a ? [['#efd2b4', 0], ['#e2b48f', 1]] : [['#e9c9c0', 0], ['#d9a497', 1]], false);
126
+ body = (
127
+ <>
128
+ <rect width="160" height="100" fill={`url(#${id}g)`} />
129
+ <path d="M58 100 V52 A22 22 0 0 1 102 52 V100Z" fill={a ? '#6e3f2b' : '#5d3a3a'} />
130
+ <path d="M66 100 V56 A14 14 0 0 1 94 56 V100Z" fill={a ? '#f1c795' : '#f0c2a8'} opacity="0.9" />
131
+ <polygon points="0,0 70,0 20,100 0,100" fill="#ffffff" opacity="0.12" />
132
+ <polygon points="102,100 160,40 160,100" fill={a ? '#b97d58' : '#a8706a'} opacity="0.45" />
133
+ <rect y="92" width="160" height="8" fill={a ? '#c08a62' : '#b1817a'} />
134
+ </>
135
+ );
136
+ } else if (kind === 'ridge') {
137
+ const a = v === 0;
138
+ defs = g(a ? [['#e9e4dc', 0], ['#c9cfd6', 1]] : [['#efe0d0', 0], ['#d7c4b4', 1]]);
139
+ body = (
140
+ <>
141
+ <rect width="160" height="100" fill={`url(#${id}g)`} />
142
+ <polygon points="0,62 26,40 46,54 74,28 104,52 126,38 160,56 160,100 0,100" fill={a ? '#a9b4c2' : '#c4ab98'} />
143
+ <polygon points="0,74 34,54 62,68 96,46 130,66 160,58 160,100 0,100" fill={a ? '#7d8ca0' : '#a5846c'} />
144
+ <polygon points="0,86 40,70 84,84 120,68 160,80 160,100 0,100" fill={a ? '#4f5d72' : '#7a5a46'} />
145
+ <rect y="56" width="160" height="10" fill="#ffffff" opacity="0.18" />
146
+ </>
147
+ );
148
+ } else if (kind === 'pool') {
149
+ defs = g([['#6cc3c1', 0], ['#2f8c96', 1]]);
150
+ body = (
151
+ <>
152
+ <rect width="160" height="100" fill={`url(#${id}g)`} />
153
+ <rect y="0" width="160" height="22" fill="#efe2cf" />
154
+ <rect y="20" width="160" height="3" fill="#d9c7ad" />
155
+ {[40, 62, 84].map((y, k) => <rect key={k} x="0" y={y} width="160" height="1.6" fill="#ffffff" opacity="0.35" />)}
156
+ <path d="M10 50 Q 40 44 70 52 T 130 50" fill="none" stroke="#ffffff" strokeWidth="1.2" opacity="0.5" />
157
+ <path d="M30 72 Q 60 66 90 74 T 150 72" fill="none" stroke="#ffffff" strokeWidth="1" opacity="0.4" />
158
+ <polygon points="100,23 160,23 160,100 130,100" fill="#1c5f6c" opacity="0.35" />
159
+ </>
160
+ );
161
+ } else if (kind === 'citrus') {
162
+ defs = g([['#f1e3cc', 0], ['#e6d1b2', 1]]);
163
+ body = (
164
+ <>
165
+ <rect width="160" height="100" fill={`url(#${id}g)`} />
166
+ <rect y="64" width="160" height="36" fill="#c67a45" />
167
+ <rect y="64" width="160" height="2" fill="#e29a63" />
168
+ <ellipse cx="74" cy="78" rx="44" ry="5" fill="#8d4f2a" opacity="0.4" />
169
+ <circle cx="64" cy="60" r="15" fill="#ef8a36" />
170
+ <circle cx="90" cy="64" r="11" fill="#f3a246" />
171
+ <circle cx="59" cy="55" r="4" fill="#ffd29a" opacity="0.7" />
172
+ <circle cx="87" cy="60" r="3" fill="#ffe0b0" opacity="0.7" />
173
+ <path d="M64 45 q 5 -6 11 -4 q -4 6 -11 4z" fill="#5d7a4a" />
174
+ </>
175
+ );
176
+ } else if (kind === 'palm') {
177
+ defs = g([['#ecc2aa', 0], ['#e0a68c', 1]], false);
178
+ body = (
179
+ <>
180
+ <rect width="160" height="100" fill={`url(#${id}g)`} />
181
+ {[0, 1, 2, 3, 4, 5].map((k) => (
182
+ <path key={k} d={`M40 10 Q ${60 + k * 14} ${10 + k * 10} ${78 + k * 16} ${28 + k * 14}`} fill="none" stroke="#b97862" strokeWidth={5 - k * 0.4} strokeLinecap="round" opacity="0.55" />
183
+ ))}
184
+ <path d="M40 10 L 34 100" stroke="#b97862" strokeWidth="3" opacity="0.5" />
185
+ <rect y="88" width="160" height="12" fill="#c98d74" />
186
+ </>
187
+ );
188
+ } else {
189
+ defs = g([['#f3e1c0', 0], ['#e9c992', 1]]);
190
+ body = (
191
+ <>
192
+ <rect width="160" height="100" fill={`url(#${id}g)`} />
193
+ <rect y="0" width="160" height="40" fill="#e8d7bd" />
194
+ <circle cx="128" cy="20" r="7" fill="#fff3dc" />
195
+ {Array.from({ length: 9 }, (_, k) => (
196
+ <path key={k} d={`M80 40 L ${-60 + k * 35} 100`} stroke="#c49a52" strokeWidth={1.4 + k * 0.1} opacity="0.55" />
197
+ ))}
198
+ <path d="M0 40 H160" stroke="#b9925a" strokeWidth="1" opacity="0.6" />
199
+ </>
200
+ );
201
+ }
202
+ return (
203
+ <svg width="100%" height="100%" viewBox="0 0 160 100" preserveAspectRatio="xMidYMid slice" style={{ position: 'absolute', inset: 0, display: 'block' }}>
204
+ <defs>{defs}</defs>
205
+ {body}
206
+ </svg>
207
+ );
208
+ };
209
+
210
+ // ───────────── 分段控件(布局开关)─────────────
211
+ const SEG = ['Grid', 'Mosaic', 'Cascade'];
212
+ const SEG_W = 168, SEG_H = 60, SEG_PAD = 6;
213
+ const Segmented: React.FC<{ frame: number }> = ({ frame }) => {
214
+ const p1 = ramp(frame, T_AB, 12, EASE.snappy);
215
+ const p2 = ramp(frame, T_BC, 12, EASE.snappy);
216
+ const pos = p1 + p2; // 0 → 1 → 2
217
+ // 胶囊在途中横向拉长(像被拽过去),到位收回
218
+ const stretch = 1 + 0.18 * (Math.sin(Math.PI * p1) + Math.sin(Math.PI * p2));
219
+ const press = (k: number, t: number) => 1 - 0.05 * Math.sin(Math.PI * ramp(frame, t - 3, 8, EASE.linear)) * (k > 0 ? 1 : 0);
220
+ return (
221
+ <div style={{
222
+ position: 'absolute', right: 96, top: 92, width: SEG_W * 3 + SEG_PAD * 2, height: SEG_H + SEG_PAD * 2, borderRadius: 999,
223
+ background: alpha('#ffffff', 0.55), boxShadow: `inset 0 0 0 1px ${L.line}, ${softShadow(6, { color: L.shadow, strength: 0.6 })}`,
224
+ }}>
225
+ <div style={{
226
+ position: 'absolute', top: SEG_PAD, left: SEG_PAD + pos * SEG_W, width: SEG_W, height: SEG_H, borderRadius: 999,
227
+ background: L.accent, transform: `scaleX(${stretch.toFixed(4)})`,
228
+ boxShadow: `0 6px 16px -6px ${alpha(L.accent, 0.7)}, inset 0 1px 0 rgba(255,255,255,0.25)`,
229
+ }} />
230
+ {SEG.map((s, k) => {
231
+ const on = Math.max(0, 1 - Math.abs(pos - k));
232
+ return (
233
+ <div key={s} style={{
234
+ position: 'absolute', top: SEG_PAD, left: SEG_PAD + k * SEG_W, width: SEG_W, height: SEG_H,
235
+ display: 'flex', alignItems: 'center', justifyContent: 'center',
236
+ ...type(30, 600), letterSpacing: '-0.01em',
237
+ color: on > 0.5 ? L.onAccent : L.ink2,
238
+ transform: `scale(${(k === 1 ? press(1, T_AB) : k === 2 ? press(2, T_BC) : 1).toFixed(4)})`,
239
+ }}>{s}</div>
240
+ );
241
+ })}
242
+ </div>
243
+ );
244
+ };
245
+
246
+ // 瓦片在某帧的几何:A→B、B→C 两段各自的进度,位置 / 宽高 / 旋转错开收敛
247
+ const tileAt = (frame: number, i: number) => {
248
+ const sAB = T_AB + LAG + stagger(i, N, 10, EASE.out);
249
+ const sBC = T_BC + LAG + stagger(i, N, 14, EASE.linear); // 发牌:等间隔依次摊开
250
+ const pAB = ramp(frame, sAB, D_AB, MOVE);
251
+ const pBC = ramp(frame, sBC, D_BC, MOVE);
252
+ const sAB2 = ramp(frame, sAB + 2, D_AB, MOVE); // 宽高晚 2f
253
+ const sBC2 = ramp(frame, sBC + 2, D_BC, MOVE);
254
+ const rBC = ramp(frame, sBC + 4, D_BC, ROT_SETTLE); // 旋转晚 4f + 过冲
255
+ const a = A[i], b = B[i], c = C[i];
256
+ // 以中心插值位置(宽高变化时中心走直线,不会"先长后跑")
257
+ const cxA = a.x + a.w / 2, cyA = a.y + a.h / 2, cxB = b.x + b.w / 2, cyB = b.y + b.h / 2, cxC = c.x + c.w / 2, cyC = c.y + c.h / 2;
258
+ const cx = mix(mix(cxA, cxB, pAB), cxC, pBC);
259
+ const cy = mix(mix(cyA, cyB, pAB), cyC, pBC);
260
+ const w = mix(mix(a.w, b.w, sAB2), c.w, sBC2);
261
+ const h = mix(mix(a.h, b.h, sAB2), c.h, sBC2);
262
+ const rot = mix(0, c.rot, rBC);
263
+ const lift = Math.max(Math.sin(Math.PI * pAB), Math.sin(Math.PI * pBC));
264
+ return { cx, cy, w, h, rot, lift, pBC: sBC2, moving: pBC > 0 };
265
+ };
266
+
267
+ export const MosaicReframe: React.FC = () => {
268
+ const frame = useCurrentFrame();
269
+ const cam = mix(1, 1.025, ramp(frame, 0, 214, EASE.smooth)); // 全程极缓推近
270
+
271
+ // 主图图注(B 态):84f 起逐词升起,128f 起退场
272
+ const capOut = ramp(frame, T_BC, 10, EASE.exit);
273
+ // C 态大标题
274
+ const HEAD = 158;
275
+
276
+ const tiles = Array.from({ length: N }, (_, i) => ({ i, ...tileAt(frame, i) }));
277
+ // 叠放次序:B→C 起按序号(后发的牌压在上面);之前主图最高
278
+ const inC = frame >= T_BC + LAG;
279
+ const z = (i: number) => (inC ? 10 + i : i === 0 ? 30 : 10);
280
+
281
+ return (
282
+ <div style={{ position: 'absolute', inset: 0, overflow: 'hidden', fontFamily: FONT.sans }}>
283
+ <Stage look={L} keyLight={{ x: 0.28, y: 0.02 }} fill={{ x: 0.9, y: 0.95 }} />
284
+
285
+ <div style={{ position: 'absolute', inset: 0, transform: `scale(${cam.toFixed(5)})`, transformOrigin: '50% 46%' }}>
286
+ {/* 页眉:品牌标志 + 小写字标 + 分镜板名(标志按亮底 light 版;字标与分镜名同一基线)。
287
+ 总宽压在 x≈620 以内——C 态首张相纸的左上角在 x≈650,页眉再长会被它盖住 */}
288
+ <div style={{ position: 'absolute', left: 96, top: 92, height: 72, display: 'flex', alignItems: 'center', gap: 18, color: L.ink }}>
289
+ <ShotcraftMark size={50} tone="light" />
290
+ <div style={{ display: 'flex', alignItems: 'baseline', gap: 20 }}>
291
+ <span style={{ fontFamily: BRAND.font, fontSize: 36, fontWeight: 700, letterSpacing: '0.03em', lineHeight: 1 }}>{BRAND.name}</span>
292
+ <span style={{ ...type(32, 450), color: L.ink2 }}>Storyboard</span>
293
+ </div>
294
+ </div>
295
+ <Segmented frame={frame} />
296
+
297
+ {/* C 态大标题(左下留白处) */}
298
+ <div style={{ position: 'absolute', left: 96, top: 676, color: L.ink }}>
299
+ <div style={{ ...type(124, 500, { serif: true }), letterSpacing: '-0.035em', lineHeight: 1.0 }}>
300
+ <TextReveal text="Every shot," start={HEAD} by="word" variant="rise" each={20} gap={5} />
301
+ <br />
302
+ <TextReveal text="in sequence." start={HEAD + 6} by="word" variant="rise" each={20} gap={5}
303
+ unitStyle={() => ({ fontStyle: 'italic', color: L.accent })} />
304
+ </div>
305
+ <div style={{
306
+ ...type(32, 450), color: L.ink2, marginTop: 26,
307
+ opacity: ramp(frame, HEAD + 14, 16, EASE.out), transform: `translateY(${mix(12, 0, ramp(frame, HEAD + 14, 18, EASE.snappy)).toFixed(2)}px)`,
308
+ }}>{PITCH.en.taglines[4]}</div>
309
+ </div>
310
+
311
+ {tiles.map(({ i, cx, cy, w, h, rot, lift, pBC }) => {
312
+ // 开场:沿对角线错峰升起(从左上到右下)
313
+ const order = (i % 4) + Math.floor(i / 4);
314
+ const inP = ramp(frame, stagger(order, 6, 14, EASE.out) - 2, 16, EASE.snappy);
315
+ const pad = 14 * pBC; // 相纸白边
316
+ const radius = mix(16, 6, pBC);
317
+ const scale = mix(0.94, 1, inP) * (1 + 0.035 * lift);
318
+ const elev = 6 + 34 * lift + 8 * pBC;
319
+ return (
320
+ <div key={i} style={{
321
+ position: 'absolute', left: cx - w / 2, top: cy - h / 2 + (1 - inP) * 40, width: w, height: h,
322
+ transform: `rotate(${rot.toFixed(3)}deg) scale(${scale.toFixed(4)})`,
323
+ opacity: inP, zIndex: z(i), borderRadius: radius,
324
+ background: L.surface, boxShadow: softShadow(elev, { color: L.shadow, strength: 0.9 + 0.5 * pBC }),
325
+ }}>
326
+ <div style={{ position: 'absolute', inset: pad, borderRadius: Math.max(2, radius - pad * 0.7), overflow: 'hidden' }}>
327
+ <Photo i={i} />
328
+ {/* 照片内缘一圈极淡暗边:像冲印的晕影,让亮色照片在米色底上立得住 */}
329
+ <div style={{ position: 'absolute', inset: 0, boxShadow: 'inset 0 0 0 1px rgba(60,30,10,0.10), inset 0 -60px 80px -40px rgba(40,20,10,0.18)' }} />
330
+ {i === 0 && (
331
+ <div style={{
332
+ position: 'absolute', inset: 0,
333
+ background: 'linear-gradient(200deg, rgba(30,18,10,0) 40%, rgba(30,18,10,0.6) 100%)',
334
+ opacity: ramp(frame, T_AB + LAG + 16, 14, EASE.out) * (1 - capOut),
335
+ }} />
336
+ )}
337
+ </div>
338
+ {/* 主图图注:B 态的策展语气 */}
339
+ {i === 0 && frame >= T_AB + LAG + 20 && capOut < 1 && (
340
+ <div style={{ position: 'absolute', left: 44, bottom: 36, color: '#fff8ee', opacity: 1 - capOut }}>
341
+ <div style={{ ...type(30, 650, { caps: true }), letterSpacing: '0.16em', color: '#ffd9b8', marginBottom: 10 }}>
342
+ <TextReveal text="Featured shot" start={T_AB + LAG + 22} by="word" variant="blur" each={14} />
343
+ </div>
344
+ <div style={{ ...type(84, 500, { serif: true }), letterSpacing: '-0.03em', textShadow: '0 2px 18px rgba(30,15,5,0.35)' }}>
345
+ <TextReveal text="Golden Hour" start={T_AB + LAG + 26} by="word" variant="rise" each={18} gap={5} />
346
+ </div>
347
+ <div style={{ ...type(32, 450), color: 'rgba(255,248,238,0.82)', marginTop: 8, opacity: ramp(frame, T_AB + LAG + 34, 14, EASE.out) }}>
348
+ Shot 01 · Crash zoom · 4.5 s
349
+ </div>
350
+ </div>
351
+ )}
352
+ </div>
353
+ );
354
+ })}
355
+ </div>
356
+ <Grain opacity={0.05} blend="overlay" />
357
+ </div>
358
+ );
359
+ };