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,348 +1,348 @@
1
- // exploded-view|爆炸分解(第二轮重设计)
2
- // 手法不变:整页带 3D 倾斜,构件沿 Z 轴错峰炸开、悬停一拍让层间视差读出深度,再逆序合体落锤收口。
3
- //
4
- // 设计决定
5
- // - look:porcelain(冷白 · 钴蓝)。Apple 发布会式的"拆给你看":机位改成 3/4 轴测(rotateX 54° +
6
- // rotateZ −32°),页面平躺像一块放在台面上的主板,层沿页面法线向上叠起——比原版正面微倾的
7
- // "浮起"更像真正的爆炸图。
8
- // - 主体:video-shotcraft 的动效工作台:外壳底板 → 侧栏(品牌标志)→ 命令栏 → 三张渲染指标卡 →
9
- // 渲染量图表 → AI 助手面板,6 层、每层都是真实 UI(大数字、钴蓝图表),底板上留着各构件的虚线插槽。
10
- // - 标注:悬停时右侧一列编号标注(发布会式 callout):锚点 → 折线引线描出 → 标题 44px + 说明 30px
11
- // 逐条升起;锚点按 3D 投影实时算出,跟着机位环绕走。
12
- // - 合体:标注先撤,层逆序 ease-in 砸回,落锤不做抖屏(Q3),改成整组 8px 下沉回弹 + 底板接触影
13
- // 一紧,合体后一道扫光掠过整页(Q4:只给主角一次);最后左上角落 video-shotcraft 字标 + 一行标题,尾帧是海报。
14
- //
15
- // 时间表(30fps,共 170f)
16
- // 0–24 建立:已合体的页面(0.56 倍),极缓推近 + 环绕起步;18–24 预备(层整体下压 6px,蓄力)
17
- // 22–62 机位拉远 0.56→0.47 并下移,给升起的层堆留出画面(106–136 合体时推回)
18
- // 24–62 炸开:5 层弹簧错峰上升(damping 15,一次可见过冲),间隔 5f,越高的层越晚到
19
- // 30–104 悬停环绕:rotateZ −32°→−22°、rotateX 54°→50°(smooth),层间视差读出深度
20
- // 52–86 标注:每条 8f 描线 + 12f 升起,间隔 6f;86–104 hold
21
- // 104–114 标注撤出(ease-in,2f 错峰)
22
- // 108–132 合体:逆序 ease-in 每层 14f,间隔 3f;132f 最后一层落座
23
- // 132–142 落锤:整组下沉 8px 阻尼回弹、接触影收紧;136–160 扫光一次
24
- // 140–170 字标淡入、标题「Built in layers.」逐词升起 → hold,尾帧海报
25
- import React from 'react';
26
- import { AbsoluteFill, useCurrentFrame } from 'remotion';
27
- import { LOOKS, Sheen, Stage, TextReveal, alpha, springAt, type } from '../../_fixtures/Look';
28
- import { EASE, FONT, mix, ramp } from '../../_fixtures/Polish';
29
- import { BRAND, ShotcraftMark, ShotcraftWordmark } from '../../_fixtures/Brand';
30
-
31
- export const EXPLODED_VIEW_DURATION = 170;
32
-
33
- const L = LOOKS.porcelain;
34
- const W = 1600;
35
- const H = 1000;
36
- const R = 26; // 页面圆角
37
- const PERSP = 2400;
38
-
39
- const EXPLODE = 24;
40
- const STAGGER = 5;
41
- const ASSEMBLE = 108;
42
- const BACK = 3; // 合体错峰
43
- const BACK_DUR = 14;
44
-
45
- type Layer = {
46
- key: string; x: number; y: number; w: number; h: number; z: number; r: number; side: 'L' | 'R';
47
- label: { n: string; t: string; d: string };
48
- };
49
-
50
- // 层(页面坐标 + 炸开高度);order = 数组下标(底 → 顶)
51
- const LAYERS: Layer[] = [
52
- { key: 'side', x: 0, y: 0, w: 288, h: H, z: 150, r: R, side: 'L', label: { n: '01', t: 'Navigation', d: 'Every shot, one click away' } },
53
- { key: 'chart', x: 320, y: 410, w: 860, h: 558, z: 270, r: 22, side: 'L', label: { n: '02', t: 'Insights', d: 'Renders, timing and pace' } },
54
- { key: 'ai', x: 1204, y: 410, w: 364, h: 558, z: 400, r: 22, side: 'R', label: { n: '03', t: 'Assistant', d: 'Drafts shots you approve' } },
55
- { key: 'kpi', x: 320, y: 130, w: W - 352, h: 250, z: 520, r: 22, side: 'R', label: { n: '04', t: 'Live metrics', d: 'Updated every second' } },
56
- { key: 'top', x: 288, y: 0, w: W - 288, h: 100, z: 640, r: 0, side: 'R', label: { n: '05', t: 'Command bar', d: 'Add a shot in one line' } },
57
- ];
58
- const N = LAYERS.length;
59
-
60
- // ───────────── 各层 UI(页面坐标系内,相对层左上) ─────────────
61
- const ink = (c: string, s: number, w: number, extra: React.CSSProperties = {}): React.CSSProperties => ({ ...type(s, w), color: c, ...extra });
62
-
63
- const SideUI: React.FC = () => (
64
- <div style={{ position: 'absolute', inset: 0, background: '#f6f8fc', borderRight: `2px solid ${L.line}` }}>
65
- <div style={{ position: 'absolute', left: 34, top: 32, display: 'flex', alignItems: 'center', gap: 14 }}>
66
- <ShotcraftMark size={44} tone="light" style={{ flex: 'none' }} />
67
- <div style={{ ...ink(L.ink, 32, 700), fontFamily: BRAND.font, letterSpacing: '0.03em' }}>{BRAND.short}</div>
68
- </div>
69
- {['Shots', 'Storyboard', 'Timeline', 'Sound', 'Renders', 'Settings'].map((n, i) => (
70
- <div key={n} style={{
71
- position: 'absolute', left: 20, right: 20, top: 120 + i * 70, height: 56, borderRadius: 14, display: 'flex', alignItems: 'center',
72
- padding: '0 18px', gap: 14, background: i === 0 ? alpha(L.accent, 0.1) : undefined,
73
- }}>
74
- <div style={{ width: 22, height: 22, borderRadius: 7, border: `3px solid ${i === 0 ? L.accent : L.ink3}`, boxSizing: 'border-box' }} />
75
- <div style={ink(i === 0 ? L.accent : L.ink2, 26, i === 0 ? 700 : 550)}>{n}</div>
76
- {i === 0 && <div style={{ marginLeft: 'auto', ...ink('#fff', 20, 700), background: L.accent, borderRadius: 999, padding: '2px 12px' }}>24</div>}
77
- </div>
78
- ))}
79
- </div>
80
- );
81
-
82
- const TopUI: React.FC = () => (
83
- <div style={{ position: 'absolute', inset: 0, background: '#ffffff', borderBottom: `2px solid ${L.line}`, display: 'flex', alignItems: 'center', padding: '0 32px', gap: 24 }}>
84
- <div style={{ flex: 1, height: 58, borderRadius: 16, background: L.surface2, boxShadow: `inset 0 0 0 2px ${L.line}`, display: 'flex', alignItems: 'center', padding: '0 22px', gap: 14 }}>
85
- <svg width={26} height={26} viewBox="0 0 24 24" fill="none" stroke={L.ink3} strokeWidth={2.4} strokeLinecap="round"><circle cx={11} cy={11} r={7} /><path d="M20 20l-4-4" /></svg>
86
- <div style={ink(L.ink3, 26, 500)}>Add a shot or search recipes…</div>
87
- <div style={{ marginLeft: 'auto', ...ink(L.ink3, 22, 600, { fontFamily: FONT.mono }), padding: '4px 12px', borderRadius: 8, boxShadow: `inset 0 0 0 2px ${L.line}` }}>⌘K</div>
88
- </div>
89
- <div style={{ width: 52, height: 52, borderRadius: 26, background: 'linear-gradient(135deg,#7aa2ff,#2f5bff)' }} />
90
- </div>
91
- );
92
-
93
- const KPIS = [
94
- { k: 'Avg. render time', v: '1m 42s', d: '−31%' },
95
- { k: 'Shots rendered', v: '2,184', d: '+12%' },
96
- { k: 'Cuts on the beat', v: '98.2%', d: '+0.6' },
97
- ];
98
- const KpiUI: React.FC = () => (
99
- <div style={{ position: 'absolute', inset: 0, display: 'flex', gap: 24 }}>
100
- {KPIS.map((k, i) => (
101
- <div key={k.k} style={{ flex: 1, borderRadius: 22, background: '#fff', boxShadow: `inset 0 0 0 2px ${L.line}`, padding: '34px 36px', boxSizing: 'border-box' }}>
102
- <div style={ink(L.ink2, 26, 600)}>{k.k}</div>
103
- <div style={{ display: 'flex', alignItems: 'baseline', gap: 14, marginTop: 22 }}>
104
- <div style={ink(L.ink, 68, 780, { whiteSpace: 'nowrap' })}>{k.v}</div>
105
- <div style={ink(i === 0 ? L.accent2 : L.accent, 28, 700)}>{k.d}</div>
106
- </div>
107
- </div>
108
- ))}
109
- </div>
110
- );
111
-
112
- const VOL = [30, 34, 31, 42, 48, 45, 56, 61, 52, 66, 72, 69, 80, 76, 88];
113
- const ChartUI: React.FC = () => {
114
- const cw = 860 - 72;
115
- const ch = 330;
116
- const pts = VOL.map((v, i) => [(i / (VOL.length - 1)) * cw, ch - (v / 100) * ch] as const);
117
- const line = pts.map(([x, y], i) => `${i ? 'L' : 'M'}${x.toFixed(1)},${y.toFixed(1)}`).join(' ');
118
- return (
119
- <div style={{ position: 'absolute', inset: 0, borderRadius: 22, background: '#fff', boxShadow: `inset 0 0 0 2px ${L.line}`, padding: '34px 36px', boxSizing: 'border-box' }}>
120
- <div style={{ display: 'flex', alignItems: 'baseline', gap: 18 }}>
121
- <div style={ink(L.ink, 36, 750)}>Render volume</div>
122
- <div style={ink(L.ink3, 24, 550)}>Last 14 days</div>
123
- </div>
124
- <svg width={cw} height={ch + 10} style={{ position: 'absolute', left: 36, top: 150, overflow: 'visible' }}>
125
- <defs>
126
- <linearGradient id="xv-area" x1="0" y1="0" x2="0" y2="1">
127
- <stop offset="0" stopColor={L.accent} stopOpacity={0.22} />
128
- <stop offset="1" stopColor={L.accent} stopOpacity={0} />
129
- </linearGradient>
130
- </defs>
131
- {[0, 0.33, 0.66, 1].map((g) => <line key={g} x1={0} x2={cw} y1={ch * g} y2={ch * g} stroke={L.line} strokeWidth={2} />)}
132
- <path d={`${line} L${cw},${ch} L0,${ch} Z`} fill="url(#xv-area)" />
133
- <path d={line} fill="none" stroke={L.accent} strokeWidth={6} strokeLinejoin="round" strokeLinecap="round" />
134
- <circle cx={pts[pts.length - 1][0]} cy={pts[pts.length - 1][1]} r={11} fill="#fff" stroke={L.accent} strokeWidth={6} />
135
- </svg>
136
- </div>
137
- );
138
- };
139
-
140
- const AiUI: React.FC = () => (
141
- <div style={{
142
- position: 'absolute', inset: 0, borderRadius: 22, padding: '30px 28px', boxSizing: 'border-box',
143
- background: `linear-gradient(180deg, #ffffff 0%, ${alpha(L.accent, 0.06)} 100%)`, boxShadow: `inset 0 0 0 2px ${alpha(L.accent, 0.35)}`,
144
- }}>
145
- <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
146
- <div style={{ width: 30, height: 30, borderRadius: 10, background: `linear-gradient(135deg, #7aa2ff, ${L.accent})` }} />
147
- <div style={ink(L.ink, 30, 750)}>Assistant</div>
148
- </div>
149
- <div style={{ marginTop: 26, borderRadius: 18, background: L.surface2, padding: '18px 20px', ...ink(L.ink2, 24, 500), lineHeight: 1.35 }}>
150
- Hero shot lands 6f late. Snap the cut to the kick?
151
- </div>
152
- <div style={{ marginTop: 16, borderRadius: 18, background: '#fff', boxShadow: `inset 0 0 0 2px ${L.line}`, padding: '18px 20px', ...ink(L.ink, 24, 550), lineHeight: 1.35 }}>
153
- “Moved the crash zoom to f240, right on the beat, and…”
154
- </div>
155
- <div style={{ position: 'absolute', left: 28, right: 28, bottom: 28, display: 'flex', gap: 12 }}>
156
- <div style={{ flex: 1, height: 58, borderRadius: 16, background: L.accent, ...ink('#fff', 24, 700), display: 'flex', alignItems: 'center', justifyContent: 'center' }}>Approve</div>
157
- <div style={{ flex: 1, height: 58, borderRadius: 16, boxShadow: `inset 0 0 0 2px ${L.line}`, ...ink(L.ink2, 24, 650), display: 'flex', alignItems: 'center', justifyContent: 'center' }}>Edit</div>
158
- </div>
159
- </div>
160
- );
161
-
162
- const LAYER_UI: Record<string, React.FC> = { side: SideUI, top: TopUI, kpi: KpiUI, chart: ChartUI, ai: AiUI };
163
-
164
- // ───────────── 机位与投影 ─────────────
165
- type Cam = { rx: number; rz: number; s: number; cx: number; cy: number };
166
- const camAt = (f: number): Cam => {
167
- const orbit = ramp(f, 30, 74, EASE.smooth);
168
- const push = ramp(f, 0, 170, EASE.smooth);
169
- const outro = ramp(f, 132, 30, EASE.smooth); // 合体后机位右移,给左上角标题让位
170
- // 机位跟着层堆的高度走:炸开时整组下移,让最高的层也留在画里;合体后回升
171
- const tall = ramp(f, 22, 40, EASE.smooth) * (1 - ramp(f, 106, 30, EASE.smooth));
172
- return {
173
- rx: mix(54, 50, orbit),
174
- rz: mix(-34, -32, ramp(f, 0, 30, EASE.out)) + 10 * orbit,
175
- s: mix(0.56, 0.47, tall) * mix(1, 1.04, push), // 炸开时拉远给层堆留画面,合体后推回
176
- cx: mix(-20, 190, outro),
177
- cy: mix(40, 180, tall) + 70 * outro,
178
- };
179
- };
180
- // 页面点 (px,py,pz) → 屏幕坐标:与 CSS transform `translate(cx,cy) scale(s) rotateX(rx) rotateZ(rz)` +
181
- // perspective(PERSP) 同一套矩阵(origin = 页面中心 = 屏幕中心)
182
- const project = (c: Cam, px: number, py: number, pz: number) => {
183
- const X = px - W / 2, Y = py - H / 2;
184
- const a = (c.rz * Math.PI) / 180, b = (c.rx * Math.PI) / 180;
185
- const x1 = X * Math.cos(a) - Y * Math.sin(a);
186
- const y1 = X * Math.sin(a) + Y * Math.cos(a);
187
- const y2 = y1 * Math.cos(b) - pz * Math.sin(b);
188
- const z2 = y1 * Math.sin(b) + pz * Math.cos(b);
189
- const x4 = x1 * c.s + c.cx, y4 = y2 * c.s + c.cy;
190
- const k = PERSP / (PERSP - z2);
191
- return { x: 960 + x4 * k, y: 540 + y4 * k };
192
- };
193
-
194
- // 每层炸开进度:弹簧上升 × 逆序 ease-in 合体
195
- const layerP = (f: number, i: number) => {
196
- const up = springAt(f, EXPLODE + i * STAGGER, { damping: 15, stiffness: 120 });
197
- const down = ramp(f, ASSEMBLE + (N - 1 - i) * BACK, BACK_DUR, EASE.exit);
198
- return up * (1 - down);
199
- };
200
- const CLOSE = ASSEMBLE + (N - 1) * BACK + BACK_DUR; // 合体落座帧 = 134
201
-
202
- export const ExplodedView: React.FC = () => {
203
- const f = useCurrentFrame();
204
- const cam = camAt(f);
205
- // 预备:层整体下压;落锤:整组下沉回弹
206
- const crouch = -6 * (ramp(f, 18, 6, EASE.out) * (1 - ramp(f, EXPLODE, 6, EASE.out)));
207
- const since = f - CLOSE;
208
- const thud = since >= 0 ? 8 * Math.exp(-since / 3) * Math.cos(since * 0.9) : 0;
209
- const spread = ramp(f, EXPLODE, 30, EASE.out) * (1 - ramp(f, ASSEMBLE, CLOSE - ASSEMBLE, EASE.exit));
210
- const sheen = ramp(f, CLOSE + 4, 24, EASE.swift);
211
-
212
- return (
213
- <AbsoluteFill style={{ overflow: 'hidden', fontFamily: FONT.sans }}>
214
- <Stage look={L} keyLight={{ x: 0.36, y: 0.05 }} fill={{ x: 0.85, y: 0.9 }} />
215
-
216
- <AbsoluteFill style={{ perspective: PERSP }}>
217
- <div style={{
218
- position: 'absolute', left: 960 - W / 2, top: 540 - H / 2, width: W, height: H, transformStyle: 'preserve-3d',
219
- transform: `translate(${cam.cx}px, ${cam.cy + thud}px) scale(${cam.s}) rotateX(${cam.rx}deg) rotateZ(${cam.rz}deg)`,
220
- }}>
221
- {/* 台面接触影:整页落在台面上的大软影(炸开时变淡,落锤时一紧) */}
222
- <div style={{
223
- position: 'absolute', left: -20, top: 10, width: W + 40, height: H + 40, borderRadius: R + 20,
224
- background: alpha(L.shadow, 0.28 - 0.08 * spread + 0.06 * Math.max(0, thud / 8)),
225
- filter: `blur(${40 - 10 * Math.max(0, thud / 8)}px)`, transform: 'translateZ(-30px) translate(30px, 40px)',
226
- }} />
227
- {/* 底板厚度 */}
228
- <div style={{ position: 'absolute', inset: 0, borderRadius: R, background: '#c9d3e6', transform: 'translateZ(-14px)' }} />
229
- {/* 底板:页面背景 + 构件插槽虚线 */}
230
- <div style={{ position: 'absolute', inset: 0, borderRadius: R, overflow: 'hidden', background: `linear-gradient(160deg, #f3f6fb 0%, ${L.bg[2]} 100%)`, boxShadow: `inset 0 0 0 2px ${L.line}` }}>
231
- {LAYERS.map((ly) => (
232
- <div key={ly.key} style={{
233
- position: 'absolute', left: ly.x + 10, top: ly.y + 10, width: ly.w - 20, height: ly.h - 20, borderRadius: Math.max(10, ly.r - 6),
234
- border: `3px dashed ${alpha(L.accent, 0.28)}`, background: alpha(L.accent, 0.03), boxSizing: 'border-box', opacity: Math.min(1, spread * 2),
235
- }} />
236
- ))}
237
- {/* 扫光:合体后一次(裁进底板圆角) */}
238
- <Sheen progress={sheen} color="#ffffff" strength={0.6} width={0.18} />
239
- </div>
240
- {/* 层投到底板上的影:随高度下移、变虚、变淡(主光左上 → 影向右下) */}
241
- {LAYERS.map((ly, i) => {
242
- const p = Math.max(0, layerP(f, i));
243
- if (p < 0.01) return null;
244
- const h = ly.z * p;
245
- return (
246
- <div key={`sh-${ly.key}`} style={{
247
- position: 'absolute', left: ly.x + h * 0.18, top: ly.y + h * 0.26, width: ly.w, height: ly.h, borderRadius: ly.r,
248
- background: alpha(L.shadow, 0.3), filter: `blur(${(10 + h * 0.09).toFixed(1)}px)`, opacity: Math.min(1, p * 1.5) * (0.8 - h / 1400),
249
- transform: 'translateZ(1px)',
250
- }} />
251
- );
252
- })}
253
- {/* 可动层:沿法线升起;背后一片厚度边(钴蓝灰) */}
254
- {LAYERS.map((ly, i) => {
255
- const p = layerP(f, i);
256
- const z = ly.z * p + 2;
257
- const UI = LAYER_UI[ly.key];
258
- const box: React.CSSProperties = { position: 'absolute', left: ly.x, top: ly.y, width: ly.w, height: ly.h, borderRadius: ly.r };
259
- const lifted = Math.min(1, Math.max(0, p) * 4);
260
- return (
261
- <React.Fragment key={ly.key}>
262
- {lifted > 0.02 && <div style={{ ...box, background: '#b9c6de', transform: `translateZ(${Math.max(2.5, z - 8 + crouch).toFixed(2)}px)` }} />}
263
- <div style={{
264
- ...box, overflow: 'hidden', transform: `translateZ(${(z + crouch).toFixed(2)}px)`,
265
- boxShadow: lifted > 0.02 ? `0 0 0 2px ${alpha('#ffffff', 0.9 * lifted)}` : undefined,
266
- }}>
267
- <UI />
268
- </div>
269
- </React.Fragment>
270
- );
271
- })}
272
- </div>
273
- </AbsoluteFill>
274
-
275
- {/* 标注:锚点(层右缘中点的 3D 投影)→ 折线引线 → 编号 + 标题 + 说明 */}
276
- <Callouts f={f} cam={cam} />
277
-
278
- {/* 收尾标题 */}
279
- <div style={{ position: 'absolute', left: 120, top: 104 }}>
280
- <div style={{ opacity: ramp(f, 140, 14, EASE.out) }}><ShotcraftWordmark size={30} tone="light" markScale={1.6} gap={14} /></div>
281
- <div style={{ ...type(96, 780), color: L.ink, marginTop: 18 }}>
282
- <TextReveal text="Built in layers." by="word" variant="rise" start={144} each={18} gap={5} />
283
- </div>
284
- <div style={{ ...type(36, 450), color: L.ink2, marginTop: 22, opacity: ramp(f, 156, 14, EASE.out), transform: `translateY(${(1 - ramp(f, 156, 14, EASE.out)) * 16}px)` }}>
285
- Every shot, tuned in one place.
286
- </div>
287
- </div>
288
- </AbsoluteFill>
289
- );
290
- };
291
-
292
- // 标注分左右两栏:左栏贴层的最左角、右栏贴最右角,引线水平拉出、到栏前一折
293
- const COL = { L: 470, R: 1450 }; // 左栏右对齐线 / 右栏左对齐线
294
- const Callouts: React.FC<{ f: number; cam: Cam }> = ({ f, cam }) => {
295
- const items = LAYERS.map((ly, i) => {
296
- const z = ly.z * layerP(f, i) + 2;
297
- const cs = [[ly.x, ly.y], [ly.x + ly.w, ly.y], [ly.x, ly.y + ly.h], [ly.x + ly.w, ly.y + ly.h]].map(([x, y]) => project(cam, x, y, z));
298
- // 锚点:靠外一侧的两个角取中点(即外缘中点),读作"这一层"
299
- cs.sort((u, v) => (ly.side === 'L' ? u.x - v.x : v.x - u.x));
300
- const a = { x: (cs[0].x + cs[1].x) / 2, y: (cs[0].y + cs[1].y) / 2 };
301
- return { ly, i, a };
302
- });
303
- const placed: { it: (typeof items)[number]; y: number }[] = [];
304
- (['L', 'R'] as const).forEach((sd) => {
305
- const col = items.filter((it) => it.ly.side === sd).sort((u, v) => u.a.y - v.a.y);
306
- const ys: number[] = [];
307
- col.forEach((it, k) => { ys[k] = k === 0 ? Math.max(150, it.a.y) : Math.max(ys[k - 1] + 140, it.a.y); });
308
- const over = (ys[ys.length - 1] ?? 0) - 940;
309
- col.forEach((it, k) => placed.push({ it, y: ys[k] - Math.max(0, over) }));
310
- });
311
- return (
312
- <AbsoluteFill style={{ pointerEvents: 'none' }}>
313
- {placed.map(({ it, y: ly }) => {
314
- const start = 52 + it.i * 6;
315
- const draw = ramp(f, start, 8, EASE.out);
316
- const rise = ramp(f, start + 6, 12, EASE.snappy);
317
- const out = ramp(f, 104 + (N - 1 - it.i) * 2, 8, EASE.exit);
318
- if (draw <= 0 || out >= 1) return null;
319
- const L_ = it.ly.side === 'L';
320
- const ax = it.a.x, ay = it.a.y;
321
- const ex = L_ ? COL.L + 24 : COL.R - 24; // 引线终点
322
- const kx = L_ ? Math.min(ax - 40, ex + 70) : Math.max(ax + 40, ex - 70); // 折点:栏前 70px
323
- const len = Math.abs(kx - ax) + Math.hypot(ex - kx, ly - ay);
324
- const lab = it.ly.label;
325
- return (
326
- <React.Fragment key={it.ly.key}>
327
- <svg width={1920} height={1080} style={{ position: 'absolute', inset: 0, opacity: 1 - out }}>
328
- <path d={`M${ax},${ay} L${kx},${ay} L${ex},${ly}`} fill="none" stroke={L.accent} strokeWidth={2.5}
329
- strokeDasharray={`${len} ${len}`} strokeDashoffset={len * (1 - draw)} strokeLinejoin="round" />
330
- <circle cx={ax} cy={ay} r={9 * Math.min(1, draw * 3)} fill={L.accent} stroke="#fff" strokeWidth={4} />
331
- </svg>
332
- <div style={{
333
- position: 'absolute', top: ly - 34, opacity: rise * (1 - out),
334
- ...(L_ ? { right: 1920 - COL.L, textAlign: 'right' as const } : { left: COL.R }),
335
- transform: `translateY(${(1 - rise) * 22 + out * -10}px)`,
336
- }}>
337
- <div style={{ display: 'flex', alignItems: 'baseline', gap: 14, justifyContent: L_ ? 'flex-end' : 'flex-start' }}>
338
- <span style={{ ...type(26, 700, { mono: true }), color: L.accent }}>{lab.n}</span>
339
- <span style={{ ...type(44, 760), color: L.ink }}>{lab.t}</span>
340
- </div>
341
- <div style={{ ...type(30, 450), color: L.ink2, marginTop: 6, whiteSpace: 'nowrap' }}>{lab.d}</div>
342
- </div>
343
- </React.Fragment>
344
- );
345
- })}
346
- </AbsoluteFill>
347
- );
348
- };
1
+ // exploded-view|爆炸分解(第二轮重设计)
2
+ // 手法不变:整页带 3D 倾斜,构件沿 Z 轴错峰炸开、悬停一拍让层间视差读出深度,再逆序合体落锤收口。
3
+ //
4
+ // 设计决定
5
+ // - look:porcelain(冷白 · 钴蓝)。Apple 发布会式的"拆给你看":机位改成 3/4 轴测(rotateX 54° +
6
+ // rotateZ −32°),页面平躺像一块放在台面上的主板,层沿页面法线向上叠起——比原版正面微倾的
7
+ // "浮起"更像真正的爆炸图。
8
+ // - 主体:video-shotcraft 的动效工作台:外壳底板 → 侧栏(品牌标志)→ 命令栏 → 三张渲染指标卡 →
9
+ // 渲染量图表 → AI 助手面板,6 层、每层都是真实 UI(大数字、钴蓝图表),底板上留着各构件的虚线插槽。
10
+ // - 标注:悬停时右侧一列编号标注(发布会式 callout):锚点 → 折线引线描出 → 标题 44px + 说明 30px
11
+ // 逐条升起;锚点按 3D 投影实时算出,跟着机位环绕走。
12
+ // - 合体:标注先撤,层逆序 ease-in 砸回,落锤不做抖屏(Q3),改成整组 8px 下沉回弹 + 底板接触影
13
+ // 一紧,合体后一道扫光掠过整页(Q4:只给主角一次);最后左上角落 video-shotcraft 字标 + 一行标题,尾帧是海报。
14
+ //
15
+ // 时间表(30fps,共 170f)
16
+ // 0–24 建立:已合体的页面(0.56 倍),极缓推近 + 环绕起步;18–24 预备(层整体下压 6px,蓄力)
17
+ // 22–62 机位拉远 0.56→0.47 并下移,给升起的层堆留出画面(106–136 合体时推回)
18
+ // 24–62 炸开:5 层弹簧错峰上升(damping 15,一次可见过冲),间隔 5f,越高的层越晚到
19
+ // 30–104 悬停环绕:rotateZ −32°→−22°、rotateX 54°→50°(smooth),层间视差读出深度
20
+ // 52–86 标注:每条 8f 描线 + 12f 升起,间隔 6f;86–104 hold
21
+ // 104–114 标注撤出(ease-in,2f 错峰)
22
+ // 108–132 合体:逆序 ease-in 每层 14f,间隔 3f;132f 最后一层落座
23
+ // 132–142 落锤:整组下沉 8px 阻尼回弹、接触影收紧;136–160 扫光一次
24
+ // 140–170 字标淡入、标题「Built in layers.」逐词升起 → hold,尾帧海报
25
+ import React from 'react';
26
+ import { AbsoluteFill, useCurrentFrame } from 'remotion';
27
+ import { LOOKS, Sheen, Stage, TextReveal, alpha, springAt, type } from '../../_fixtures/Look';
28
+ import { EASE, FONT, mix, ramp } from '../../_fixtures/Polish';
29
+ import { BRAND, ShotcraftMark, ShotcraftWordmark } from '../../_fixtures/Brand';
30
+
31
+ export const EXPLODED_VIEW_DURATION = 170;
32
+
33
+ const L = LOOKS.porcelain;
34
+ const W = 1600;
35
+ const H = 1000;
36
+ const R = 26; // 页面圆角
37
+ const PERSP = 2400;
38
+
39
+ const EXPLODE = 24;
40
+ const STAGGER = 5;
41
+ const ASSEMBLE = 108;
42
+ const BACK = 3; // 合体错峰
43
+ const BACK_DUR = 14;
44
+
45
+ type Layer = {
46
+ key: string; x: number; y: number; w: number; h: number; z: number; r: number; side: 'L' | 'R';
47
+ label: { n: string; t: string; d: string };
48
+ };
49
+
50
+ // 层(页面坐标 + 炸开高度);order = 数组下标(底 → 顶)
51
+ const LAYERS: Layer[] = [
52
+ { key: 'side', x: 0, y: 0, w: 288, h: H, z: 150, r: R, side: 'L', label: { n: '01', t: 'Navigation', d: 'Every shot, one click away' } },
53
+ { key: 'chart', x: 320, y: 410, w: 860, h: 558, z: 270, r: 22, side: 'L', label: { n: '02', t: 'Insights', d: 'Renders, timing and pace' } },
54
+ { key: 'ai', x: 1204, y: 410, w: 364, h: 558, z: 400, r: 22, side: 'R', label: { n: '03', t: 'Assistant', d: 'Drafts shots you approve' } },
55
+ { key: 'kpi', x: 320, y: 130, w: W - 352, h: 250, z: 520, r: 22, side: 'R', label: { n: '04', t: 'Live metrics', d: 'Updated every second' } },
56
+ { key: 'top', x: 288, y: 0, w: W - 288, h: 100, z: 640, r: 0, side: 'R', label: { n: '05', t: 'Command bar', d: 'Add a shot in one line' } },
57
+ ];
58
+ const N = LAYERS.length;
59
+
60
+ // ───────────── 各层 UI(页面坐标系内,相对层左上) ─────────────
61
+ const ink = (c: string, s: number, w: number, extra: React.CSSProperties = {}): React.CSSProperties => ({ ...type(s, w), color: c, ...extra });
62
+
63
+ const SideUI: React.FC = () => (
64
+ <div style={{ position: 'absolute', inset: 0, background: '#f6f8fc', borderRight: `2px solid ${L.line}` }}>
65
+ <div style={{ position: 'absolute', left: 34, top: 32, display: 'flex', alignItems: 'center', gap: 14 }}>
66
+ <ShotcraftMark size={44} tone="light" style={{ flex: 'none' }} />
67
+ <div style={{ ...ink(L.ink, 32, 700), fontFamily: BRAND.font, letterSpacing: '0.03em' }}>{BRAND.short}</div>
68
+ </div>
69
+ {['Shots', 'Storyboard', 'Timeline', 'Sound', 'Renders', 'Settings'].map((n, i) => (
70
+ <div key={n} style={{
71
+ position: 'absolute', left: 20, right: 20, top: 120 + i * 70, height: 56, borderRadius: 14, display: 'flex', alignItems: 'center',
72
+ padding: '0 18px', gap: 14, background: i === 0 ? alpha(L.accent, 0.1) : undefined,
73
+ }}>
74
+ <div style={{ width: 22, height: 22, borderRadius: 7, border: `3px solid ${i === 0 ? L.accent : L.ink3}`, boxSizing: 'border-box' }} />
75
+ <div style={ink(i === 0 ? L.accent : L.ink2, 26, i === 0 ? 700 : 550)}>{n}</div>
76
+ {i === 0 && <div style={{ marginLeft: 'auto', ...ink('#fff', 20, 700), background: L.accent, borderRadius: 999, padding: '2px 12px' }}>24</div>}
77
+ </div>
78
+ ))}
79
+ </div>
80
+ );
81
+
82
+ const TopUI: React.FC = () => (
83
+ <div style={{ position: 'absolute', inset: 0, background: '#ffffff', borderBottom: `2px solid ${L.line}`, display: 'flex', alignItems: 'center', padding: '0 32px', gap: 24 }}>
84
+ <div style={{ flex: 1, height: 58, borderRadius: 16, background: L.surface2, boxShadow: `inset 0 0 0 2px ${L.line}`, display: 'flex', alignItems: 'center', padding: '0 22px', gap: 14 }}>
85
+ <svg width={26} height={26} viewBox="0 0 24 24" fill="none" stroke={L.ink3} strokeWidth={2.4} strokeLinecap="round"><circle cx={11} cy={11} r={7} /><path d="M20 20l-4-4" /></svg>
86
+ <div style={ink(L.ink3, 26, 500)}>Add a shot or search recipes…</div>
87
+ <div style={{ marginLeft: 'auto', ...ink(L.ink3, 22, 600, { fontFamily: FONT.mono }), padding: '4px 12px', borderRadius: 8, boxShadow: `inset 0 0 0 2px ${L.line}` }}>⌘K</div>
88
+ </div>
89
+ <div style={{ width: 52, height: 52, borderRadius: 26, background: 'linear-gradient(135deg,#7aa2ff,#2f5bff)' }} />
90
+ </div>
91
+ );
92
+
93
+ const KPIS = [
94
+ { k: 'Avg. render time', v: '1m 42s', d: '−31%' },
95
+ { k: 'Shots rendered', v: '2,184', d: '+12%' },
96
+ { k: 'Cuts on the beat', v: '98.2%', d: '+0.6' },
97
+ ];
98
+ const KpiUI: React.FC = () => (
99
+ <div style={{ position: 'absolute', inset: 0, display: 'flex', gap: 24 }}>
100
+ {KPIS.map((k, i) => (
101
+ <div key={k.k} style={{ flex: 1, borderRadius: 22, background: '#fff', boxShadow: `inset 0 0 0 2px ${L.line}`, padding: '34px 36px', boxSizing: 'border-box' }}>
102
+ <div style={ink(L.ink2, 26, 600)}>{k.k}</div>
103
+ <div style={{ display: 'flex', alignItems: 'baseline', gap: 14, marginTop: 22 }}>
104
+ <div style={ink(L.ink, 68, 780, { whiteSpace: 'nowrap' })}>{k.v}</div>
105
+ <div style={ink(i === 0 ? L.accent2 : L.accent, 28, 700)}>{k.d}</div>
106
+ </div>
107
+ </div>
108
+ ))}
109
+ </div>
110
+ );
111
+
112
+ const VOL = [30, 34, 31, 42, 48, 45, 56, 61, 52, 66, 72, 69, 80, 76, 88];
113
+ const ChartUI: React.FC = () => {
114
+ const cw = 860 - 72;
115
+ const ch = 330;
116
+ const pts = VOL.map((v, i) => [(i / (VOL.length - 1)) * cw, ch - (v / 100) * ch] as const);
117
+ const line = pts.map(([x, y], i) => `${i ? 'L' : 'M'}${x.toFixed(1)},${y.toFixed(1)}`).join(' ');
118
+ return (
119
+ <div style={{ position: 'absolute', inset: 0, borderRadius: 22, background: '#fff', boxShadow: `inset 0 0 0 2px ${L.line}`, padding: '34px 36px', boxSizing: 'border-box' }}>
120
+ <div style={{ display: 'flex', alignItems: 'baseline', gap: 18 }}>
121
+ <div style={ink(L.ink, 36, 750)}>Render volume</div>
122
+ <div style={ink(L.ink3, 24, 550)}>Last 14 days</div>
123
+ </div>
124
+ <svg width={cw} height={ch + 10} style={{ position: 'absolute', left: 36, top: 150, overflow: 'visible' }}>
125
+ <defs>
126
+ <linearGradient id="xv-area" x1="0" y1="0" x2="0" y2="1">
127
+ <stop offset="0" stopColor={L.accent} stopOpacity={0.22} />
128
+ <stop offset="1" stopColor={L.accent} stopOpacity={0} />
129
+ </linearGradient>
130
+ </defs>
131
+ {[0, 0.33, 0.66, 1].map((g) => <line key={g} x1={0} x2={cw} y1={ch * g} y2={ch * g} stroke={L.line} strokeWidth={2} />)}
132
+ <path d={`${line} L${cw},${ch} L0,${ch} Z`} fill="url(#xv-area)" />
133
+ <path d={line} fill="none" stroke={L.accent} strokeWidth={6} strokeLinejoin="round" strokeLinecap="round" />
134
+ <circle cx={pts[pts.length - 1][0]} cy={pts[pts.length - 1][1]} r={11} fill="#fff" stroke={L.accent} strokeWidth={6} />
135
+ </svg>
136
+ </div>
137
+ );
138
+ };
139
+
140
+ const AiUI: React.FC = () => (
141
+ <div style={{
142
+ position: 'absolute', inset: 0, borderRadius: 22, padding: '30px 28px', boxSizing: 'border-box',
143
+ background: `linear-gradient(180deg, #ffffff 0%, ${alpha(L.accent, 0.06)} 100%)`, boxShadow: `inset 0 0 0 2px ${alpha(L.accent, 0.35)}`,
144
+ }}>
145
+ <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
146
+ <div style={{ width: 30, height: 30, borderRadius: 10, background: `linear-gradient(135deg, #7aa2ff, ${L.accent})` }} />
147
+ <div style={ink(L.ink, 30, 750)}>Assistant</div>
148
+ </div>
149
+ <div style={{ marginTop: 26, borderRadius: 18, background: L.surface2, padding: '18px 20px', ...ink(L.ink2, 24, 500), lineHeight: 1.35 }}>
150
+ Hero shot lands 6f late. Snap the cut to the kick?
151
+ </div>
152
+ <div style={{ marginTop: 16, borderRadius: 18, background: '#fff', boxShadow: `inset 0 0 0 2px ${L.line}`, padding: '18px 20px', ...ink(L.ink, 24, 550), lineHeight: 1.35 }}>
153
+ “Moved the crash zoom to f240, right on the beat, and…”
154
+ </div>
155
+ <div style={{ position: 'absolute', left: 28, right: 28, bottom: 28, display: 'flex', gap: 12 }}>
156
+ <div style={{ flex: 1, height: 58, borderRadius: 16, background: L.accent, ...ink('#fff', 24, 700), display: 'flex', alignItems: 'center', justifyContent: 'center' }}>Approve</div>
157
+ <div style={{ flex: 1, height: 58, borderRadius: 16, boxShadow: `inset 0 0 0 2px ${L.line}`, ...ink(L.ink2, 24, 650), display: 'flex', alignItems: 'center', justifyContent: 'center' }}>Edit</div>
158
+ </div>
159
+ </div>
160
+ );
161
+
162
+ const LAYER_UI: Record<string, React.FC> = { side: SideUI, top: TopUI, kpi: KpiUI, chart: ChartUI, ai: AiUI };
163
+
164
+ // ───────────── 机位与投影 ─────────────
165
+ type Cam = { rx: number; rz: number; s: number; cx: number; cy: number };
166
+ const camAt = (f: number): Cam => {
167
+ const orbit = ramp(f, 30, 74, EASE.smooth);
168
+ const push = ramp(f, 0, 170, EASE.smooth);
169
+ const outro = ramp(f, 132, 30, EASE.smooth); // 合体后机位右移,给左上角标题让位
170
+ // 机位跟着层堆的高度走:炸开时整组下移,让最高的层也留在画里;合体后回升
171
+ const tall = ramp(f, 22, 40, EASE.smooth) * (1 - ramp(f, 106, 30, EASE.smooth));
172
+ return {
173
+ rx: mix(54, 50, orbit),
174
+ rz: mix(-34, -32, ramp(f, 0, 30, EASE.out)) + 10 * orbit,
175
+ s: mix(0.56, 0.47, tall) * mix(1, 1.04, push), // 炸开时拉远给层堆留画面,合体后推回
176
+ cx: mix(-20, 190, outro),
177
+ cy: mix(40, 180, tall) + 70 * outro,
178
+ };
179
+ };
180
+ // 页面点 (px,py,pz) → 屏幕坐标:与 CSS transform `translate(cx,cy) scale(s) rotateX(rx) rotateZ(rz)` +
181
+ // perspective(PERSP) 同一套矩阵(origin = 页面中心 = 屏幕中心)
182
+ const project = (c: Cam, px: number, py: number, pz: number) => {
183
+ const X = px - W / 2, Y = py - H / 2;
184
+ const a = (c.rz * Math.PI) / 180, b = (c.rx * Math.PI) / 180;
185
+ const x1 = X * Math.cos(a) - Y * Math.sin(a);
186
+ const y1 = X * Math.sin(a) + Y * Math.cos(a);
187
+ const y2 = y1 * Math.cos(b) - pz * Math.sin(b);
188
+ const z2 = y1 * Math.sin(b) + pz * Math.cos(b);
189
+ const x4 = x1 * c.s + c.cx, y4 = y2 * c.s + c.cy;
190
+ const k = PERSP / (PERSP - z2);
191
+ return { x: 960 + x4 * k, y: 540 + y4 * k };
192
+ };
193
+
194
+ // 每层炸开进度:弹簧上升 × 逆序 ease-in 合体
195
+ const layerP = (f: number, i: number) => {
196
+ const up = springAt(f, EXPLODE + i * STAGGER, { damping: 15, stiffness: 120 });
197
+ const down = ramp(f, ASSEMBLE + (N - 1 - i) * BACK, BACK_DUR, EASE.exit);
198
+ return up * (1 - down);
199
+ };
200
+ const CLOSE = ASSEMBLE + (N - 1) * BACK + BACK_DUR; // 合体落座帧 = 134
201
+
202
+ export const ExplodedView: React.FC = () => {
203
+ const f = useCurrentFrame();
204
+ const cam = camAt(f);
205
+ // 预备:层整体下压;落锤:整组下沉回弹
206
+ const crouch = -6 * (ramp(f, 18, 6, EASE.out) * (1 - ramp(f, EXPLODE, 6, EASE.out)));
207
+ const since = f - CLOSE;
208
+ const thud = since >= 0 ? 8 * Math.exp(-since / 3) * Math.cos(since * 0.9) : 0;
209
+ const spread = ramp(f, EXPLODE, 30, EASE.out) * (1 - ramp(f, ASSEMBLE, CLOSE - ASSEMBLE, EASE.exit));
210
+ const sheen = ramp(f, CLOSE + 4, 24, EASE.swift);
211
+
212
+ return (
213
+ <AbsoluteFill style={{ overflow: 'hidden', fontFamily: FONT.sans }}>
214
+ <Stage look={L} keyLight={{ x: 0.36, y: 0.05 }} fill={{ x: 0.85, y: 0.9 }} />
215
+
216
+ <AbsoluteFill style={{ perspective: PERSP }}>
217
+ <div style={{
218
+ position: 'absolute', left: 960 - W / 2, top: 540 - H / 2, width: W, height: H, transformStyle: 'preserve-3d',
219
+ transform: `translate(${cam.cx}px, ${cam.cy + thud}px) scale(${cam.s}) rotateX(${cam.rx}deg) rotateZ(${cam.rz}deg)`,
220
+ }}>
221
+ {/* 台面接触影:整页落在台面上的大软影(炸开时变淡,落锤时一紧) */}
222
+ <div style={{
223
+ position: 'absolute', left: -20, top: 10, width: W + 40, height: H + 40, borderRadius: R + 20,
224
+ background: alpha(L.shadow, 0.28 - 0.08 * spread + 0.06 * Math.max(0, thud / 8)),
225
+ filter: `blur(${40 - 10 * Math.max(0, thud / 8)}px)`, transform: 'translateZ(-30px) translate(30px, 40px)',
226
+ }} />
227
+ {/* 底板厚度 */}
228
+ <div style={{ position: 'absolute', inset: 0, borderRadius: R, background: '#c9d3e6', transform: 'translateZ(-14px)' }} />
229
+ {/* 底板:页面背景 + 构件插槽虚线 */}
230
+ <div style={{ position: 'absolute', inset: 0, borderRadius: R, overflow: 'hidden', background: `linear-gradient(160deg, #f3f6fb 0%, ${L.bg[2]} 100%)`, boxShadow: `inset 0 0 0 2px ${L.line}` }}>
231
+ {LAYERS.map((ly) => (
232
+ <div key={ly.key} style={{
233
+ position: 'absolute', left: ly.x + 10, top: ly.y + 10, width: ly.w - 20, height: ly.h - 20, borderRadius: Math.max(10, ly.r - 6),
234
+ border: `3px dashed ${alpha(L.accent, 0.28)}`, background: alpha(L.accent, 0.03), boxSizing: 'border-box', opacity: Math.min(1, spread * 2),
235
+ }} />
236
+ ))}
237
+ {/* 扫光:合体后一次(裁进底板圆角) */}
238
+ <Sheen progress={sheen} color="#ffffff" strength={0.6} width={0.18} />
239
+ </div>
240
+ {/* 层投到底板上的影:随高度下移、变虚、变淡(主光左上 → 影向右下) */}
241
+ {LAYERS.map((ly, i) => {
242
+ const p = Math.max(0, layerP(f, i));
243
+ if (p < 0.01) return null;
244
+ const h = ly.z * p;
245
+ return (
246
+ <div key={`sh-${ly.key}`} style={{
247
+ position: 'absolute', left: ly.x + h * 0.18, top: ly.y + h * 0.26, width: ly.w, height: ly.h, borderRadius: ly.r,
248
+ background: alpha(L.shadow, 0.3), filter: `blur(${(10 + h * 0.09).toFixed(1)}px)`, opacity: Math.min(1, p * 1.5) * (0.8 - h / 1400),
249
+ transform: 'translateZ(1px)',
250
+ }} />
251
+ );
252
+ })}
253
+ {/* 可动层:沿法线升起;背后一片厚度边(钴蓝灰) */}
254
+ {LAYERS.map((ly, i) => {
255
+ const p = layerP(f, i);
256
+ const z = ly.z * p + 2;
257
+ const UI = LAYER_UI[ly.key];
258
+ const box: React.CSSProperties = { position: 'absolute', left: ly.x, top: ly.y, width: ly.w, height: ly.h, borderRadius: ly.r };
259
+ const lifted = Math.min(1, Math.max(0, p) * 4);
260
+ return (
261
+ <React.Fragment key={ly.key}>
262
+ {lifted > 0.02 && <div style={{ ...box, background: '#b9c6de', transform: `translateZ(${Math.max(2.5, z - 8 + crouch).toFixed(2)}px)` }} />}
263
+ <div style={{
264
+ ...box, overflow: 'hidden', transform: `translateZ(${(z + crouch).toFixed(2)}px)`,
265
+ boxShadow: lifted > 0.02 ? `0 0 0 2px ${alpha('#ffffff', 0.9 * lifted)}` : undefined,
266
+ }}>
267
+ <UI />
268
+ </div>
269
+ </React.Fragment>
270
+ );
271
+ })}
272
+ </div>
273
+ </AbsoluteFill>
274
+
275
+ {/* 标注:锚点(层右缘中点的 3D 投影)→ 折线引线 → 编号 + 标题 + 说明 */}
276
+ <Callouts f={f} cam={cam} />
277
+
278
+ {/* 收尾标题 */}
279
+ <div style={{ position: 'absolute', left: 120, top: 104 }}>
280
+ <div style={{ opacity: ramp(f, 140, 14, EASE.out) }}><ShotcraftWordmark size={30} tone="light" markScale={1.6} gap={14} /></div>
281
+ <div style={{ ...type(96, 780), color: L.ink, marginTop: 18 }}>
282
+ <TextReveal text="Built in layers." by="word" variant="rise" start={144} each={18} gap={5} />
283
+ </div>
284
+ <div style={{ ...type(36, 450), color: L.ink2, marginTop: 22, opacity: ramp(f, 156, 14, EASE.out), transform: `translateY(${(1 - ramp(f, 156, 14, EASE.out)) * 16}px)` }}>
285
+ Every shot, tuned in one place.
286
+ </div>
287
+ </div>
288
+ </AbsoluteFill>
289
+ );
290
+ };
291
+
292
+ // 标注分左右两栏:左栏贴层的最左角、右栏贴最右角,引线水平拉出、到栏前一折
293
+ const COL = { L: 470, R: 1450 }; // 左栏右对齐线 / 右栏左对齐线
294
+ const Callouts: React.FC<{ f: number; cam: Cam }> = ({ f, cam }) => {
295
+ const items = LAYERS.map((ly, i) => {
296
+ const z = ly.z * layerP(f, i) + 2;
297
+ const cs = [[ly.x, ly.y], [ly.x + ly.w, ly.y], [ly.x, ly.y + ly.h], [ly.x + ly.w, ly.y + ly.h]].map(([x, y]) => project(cam, x, y, z));
298
+ // 锚点:靠外一侧的两个角取中点(即外缘中点),读作"这一层"
299
+ cs.sort((u, v) => (ly.side === 'L' ? u.x - v.x : v.x - u.x));
300
+ const a = { x: (cs[0].x + cs[1].x) / 2, y: (cs[0].y + cs[1].y) / 2 };
301
+ return { ly, i, a };
302
+ });
303
+ const placed: { it: (typeof items)[number]; y: number }[] = [];
304
+ (['L', 'R'] as const).forEach((sd) => {
305
+ const col = items.filter((it) => it.ly.side === sd).sort((u, v) => u.a.y - v.a.y);
306
+ const ys: number[] = [];
307
+ col.forEach((it, k) => { ys[k] = k === 0 ? Math.max(150, it.a.y) : Math.max(ys[k - 1] + 140, it.a.y); });
308
+ const over = (ys[ys.length - 1] ?? 0) - 940;
309
+ col.forEach((it, k) => placed.push({ it, y: ys[k] - Math.max(0, over) }));
310
+ });
311
+ return (
312
+ <AbsoluteFill style={{ pointerEvents: 'none' }}>
313
+ {placed.map(({ it, y: ly }) => {
314
+ const start = 52 + it.i * 6;
315
+ const draw = ramp(f, start, 8, EASE.out);
316
+ const rise = ramp(f, start + 6, 12, EASE.snappy);
317
+ const out = ramp(f, 104 + (N - 1 - it.i) * 2, 8, EASE.exit);
318
+ if (draw <= 0 || out >= 1) return null;
319
+ const L_ = it.ly.side === 'L';
320
+ const ax = it.a.x, ay = it.a.y;
321
+ const ex = L_ ? COL.L + 24 : COL.R - 24; // 引线终点
322
+ const kx = L_ ? Math.min(ax - 40, ex + 70) : Math.max(ax + 40, ex - 70); // 折点:栏前 70px
323
+ const len = Math.abs(kx - ax) + Math.hypot(ex - kx, ly - ay);
324
+ const lab = it.ly.label;
325
+ return (
326
+ <React.Fragment key={it.ly.key}>
327
+ <svg width={1920} height={1080} style={{ position: 'absolute', inset: 0, opacity: 1 - out }}>
328
+ <path d={`M${ax},${ay} L${kx},${ay} L${ex},${ly}`} fill="none" stroke={L.accent} strokeWidth={2.5}
329
+ strokeDasharray={`${len} ${len}`} strokeDashoffset={len * (1 - draw)} strokeLinejoin="round" />
330
+ <circle cx={ax} cy={ay} r={9 * Math.min(1, draw * 3)} fill={L.accent} stroke="#fff" strokeWidth={4} />
331
+ </svg>
332
+ <div style={{
333
+ position: 'absolute', top: ly - 34, opacity: rise * (1 - out),
334
+ ...(L_ ? { right: 1920 - COL.L, textAlign: 'right' as const } : { left: COL.R }),
335
+ transform: `translateY(${(1 - rise) * 22 + out * -10}px)`,
336
+ }}>
337
+ <div style={{ display: 'flex', alignItems: 'baseline', gap: 14, justifyContent: L_ ? 'flex-end' : 'flex-start' }}>
338
+ <span style={{ ...type(26, 700, { mono: true }), color: L.accent }}>{lab.n}</span>
339
+ <span style={{ ...type(44, 760), color: L.ink }}>{lab.t}</span>
340
+ </div>
341
+ <div style={{ ...type(30, 450), color: L.ink2, marginTop: 6, whiteSpace: 'nowrap' }}>{lab.d}</div>
342
+ </div>
343
+ </React.Fragment>
344
+ );
345
+ })}
346
+ </AbsoluteFill>
347
+ );
348
+ };