dsh-drawai 0.4.2 → 0.4.3

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 (366) hide show
  1. package/README.md +4 -3
  2. package/lib/index.js +7777 -7719
  3. package/lib/motion/asset-pack.js +394 -394
  4. package/lib/motion/assets.js +291 -291
  5. package/lib/motion/demo-assets-lock.js +10 -10
  6. package/lib/motion/mgstyles/vendor/README.md +28 -28
  7. package/lib/motion/mgstyles/vendor/modules/d3/LICENSE +13 -13
  8. package/lib/motion/mgstyles/vendor/modules/d3/dist/d3.min.js +2 -2
  9. package/lib/motion/mgstyles/vendor/modules/opentype.js/LICENSE +20 -20
  10. package/lib/motion/mgstyles/vendor/modules/opentype.js/dist/opentype.mjs +14460 -14460
  11. package/lib/motion/mgstyles/vendor/modules/simplex-noise/LICENSE +21 -21
  12. package/lib/motion/mgstyles/vendor/modules/simplex-noise/dist/esm/simplex-noise.js +465 -465
  13. package/lib/motion/mgstyles/vendor/modules/topojson-client/LICENSE +13 -13
  14. package/lib/motion/mgstyles/vendor/modules/topojson-client/dist/topojson-client.min.js +2 -2
  15. package/lib/motion/render.js +179 -179
  16. package/lib/motion/shotcraft/upstream/SKILL.md +286 -286
  17. package/lib/motion/shotcraft/upstream/assets/lib/Caption.tsx +54 -54
  18. package/lib/motion/shotcraft/upstream/assets/lib/ClipCard.tsx +200 -200
  19. package/lib/motion/shotcraft/upstream/assets/lib/DigitRoll.tsx +45 -45
  20. package/lib/motion/shotcraft/upstream/assets/lib/FlashCut.tsx +20 -20
  21. package/lib/motion/shotcraft/upstream/assets/lib/FlatPanel.tsx +65 -65
  22. package/lib/motion/shotcraft/upstream/assets/lib/PageCam.tsx +151 -151
  23. package/lib/motion/shotcraft/upstream/assets/lib/VerticalTicker.tsx +129 -129
  24. package/lib/motion/shotcraft/upstream/assets/lib/helpers/camera.tsx +75 -75
  25. package/lib/motion/shotcraft/upstream/assets/lib/helpers/motion.ts +40 -40
  26. package/lib/motion/shotcraft/upstream/assets/lib/helpers/rand.ts +11 -11
  27. package/lib/motion/shotcraft/upstream/assets/lib/helpers/shake.ts +10 -10
  28. package/lib/motion/shotcraft/upstream/assets/scripts/build-readme-cover.mjs +49 -49
  29. package/lib/motion/shotcraft/upstream/assets/scripts/capture-template.mjs +210 -210
  30. package/lib/motion/shotcraft/upstream/assets/scripts/sfx-source.py +423 -423
  31. package/lib/motion/shotcraft/upstream/assets/scripts/smoke-render-demos.py +170 -170
  32. package/lib/motion/shotcraft/upstream/assets/scripts/test_sfx_source.py +157 -157
  33. package/lib/motion/shotcraft/upstream/demos/README.md +120 -120
  34. package/lib/motion/shotcraft/upstream/demos/_fixtures/Brand.tsx +112 -112
  35. package/lib/motion/shotcraft/upstream/demos/_fixtures/Fixtures.tsx +647 -647
  36. package/lib/motion/shotcraft/upstream/demos/_fixtures/Look.tsx +316 -316
  37. package/lib/motion/shotcraft/upstream/demos/_fixtures/Motion.tsx +82 -82
  38. package/lib/motion/shotcraft/upstream/demos/_fixtures/PageCam2D.tsx +115 -115
  39. package/lib/motion/shotcraft/upstream/demos/_fixtures/Polish.tsx +243 -243
  40. package/lib/motion/shotcraft/upstream/demos/_textures/live-layout.json +388 -388
  41. package/lib/motion/shotcraft/upstream/demos/camera/basic-3d-scene/Basic3DScene.tsx +250 -250
  42. package/lib/motion/shotcraft/upstream/demos/camera/crash-zoom-punch/CrashImpactReal.tsx +305 -305
  43. package/lib/motion/shotcraft/upstream/demos/camera/crash-zoom-punch/CrashZoomReal.tsx +246 -246
  44. package/lib/motion/shotcraft/upstream/demos/camera/cursor-flyover/CursorFlyover.tsx +390 -390
  45. package/lib/motion/shotcraft/upstream/demos/camera/depth-layer-moves/MultiplaneReal.tsx +138 -138
  46. package/lib/motion/shotcraft/upstream/demos/camera/graze-face-tour/GrazeFaceTour.tsx +542 -542
  47. package/lib/motion/shotcraft/upstream/demos/camera/overhead-camera-moves/OverheadTabletopDrop.tsx +315 -315
  48. package/lib/motion/shotcraft/upstream/demos/camera/overhead-camera-moves/TiltReveal.tsx +299 -299
  49. package/lib/motion/shotcraft/upstream/demos/camera/space-camera-moves/DroneDiveLanding.tsx +173 -173
  50. package/lib/motion/shotcraft/upstream/demos/camera/space-camera-moves/ExplodedView.tsx +348 -348
  51. package/lib/motion/shotcraft/upstream/demos/camera/steep-tilt-glide/SteepTiltGlide.tsx +366 -366
  52. package/lib/motion/shotcraft/upstream/demos/camera/tension-camera-moves/BulletTimeFreezeOrbit.tsx +279 -279
  53. package/lib/motion/shotcraft/upstream/demos/camera/tension-camera-moves/PullBackIsolation.tsx +184 -184
  54. package/lib/motion/shotcraft/upstream/demos/camera/terminal-3d/Terminal3D.tsx +390 -390
  55. package/lib/motion/shotcraft/upstream/demos/data/before-after-slider-scrub/BeforeAfterSliderScrub.tsx +155 -155
  56. package/lib/motion/shotcraft/upstream/demos/data/chart-live-moves/AxisRescaleShockV2.tsx +303 -303
  57. package/lib/motion/shotcraft/upstream/demos/data/chart-live-moves/OscilloscopeStreamV2.tsx +290 -290
  58. package/lib/motion/shotcraft/upstream/demos/data/chart-live-moves/UnitDotSwarmRegroupV2.tsx +278 -278
  59. package/lib/motion/shotcraft/upstream/demos/data/gauge-readout-moves/NeedleSweepSelftest.tsx +307 -307
  60. package/lib/motion/shotcraft/upstream/demos/data/gauge-readout-moves/TapeScrollFixedPointer.tsx +215 -215
  61. package/lib/motion/shotcraft/upstream/demos/data/scroll-brake-moves/BrakeReticleLock.tsx +299 -299
  62. package/lib/motion/shotcraft/upstream/demos/data/scroll-brake-moves/ChangelogScrollBrake.tsx +232 -232
  63. package/lib/motion/shotcraft/upstream/demos/data/timeline-travel/TimelineTravel.tsx +290 -290
  64. package/lib/motion/shotcraft/upstream/demos/effects/assemble-then-type-flyin/AssembleThenTypeFlyin.tsx +273 -273
  65. package/lib/motion/shotcraft/upstream/demos/effects/aurora-bloom-bg-flip/AuroraBloomBgFlip.tsx +167 -167
  66. package/lib/motion/shotcraft/upstream/demos/effects/brand-frame-snap/BrandFrameSnap.tsx +536 -536
  67. package/lib/motion/shotcraft/upstream/demos/effects/fui-hud-moves/ReticleLockOn.tsx +164 -164
  68. package/lib/motion/shotcraft/upstream/demos/effects/glow-flyline-moves/FlylineArc.tsx +175 -175
  69. package/lib/motion/shotcraft/upstream/demos/effects/glow-flyline-moves/GlowOrbAmbient.tsx +197 -197
  70. package/lib/motion/shotcraft/upstream/demos/effects/glow-flyline-moves/OrbFlylineRelay.tsx +241 -241
  71. package/lib/motion/shotcraft/upstream/demos/effects/icon-performance-moves/AttentionBounce.tsx +279 -279
  72. package/lib/motion/shotcraft/upstream/demos/effects/impact-feedback/AnimeImpact.tsx +230 -230
  73. package/lib/motion/shotcraft/upstream/demos/effects/impact-feedback/HitCounter.tsx +345 -345
  74. package/lib/motion/shotcraft/upstream/demos/effects/light-play-moves/SheenSweepRetry.tsx +275 -275
  75. package/lib/motion/shotcraft/upstream/demos/effects/light-play-moves/SpotlightSweepReveal.tsx +229 -229
  76. package/lib/motion/shotcraft/upstream/demos/effects/radial-ripple-phone-chips/RadialRipplePhoneChips.tsx +312 -312
  77. package/lib/motion/shotcraft/upstream/demos/effects/riso-print-hits/RisoMisregistrationHit.tsx +222 -222
  78. package/lib/motion/shotcraft/upstream/demos/effects/scan-bracket-sweep/ScanBracketSweep.tsx +295 -295
  79. package/lib/motion/shotcraft/upstream/demos/effects/scanline-annotate-focus/ScanlineAnnotateFocus.tsx +329 -329
  80. package/lib/motion/shotcraft/upstream/demos/effects/scanline-assemble-flyin/ScanlineAssembleFlyin.tsx +315 -315
  81. package/lib/motion/shotcraft/upstream/demos/effects/slam-entrance-moves/ImpactBurstKit.tsx +264 -264
  82. package/lib/motion/shotcraft/upstream/demos/effects/slam-entrance-moves/KanadaPerspectiveSnap.tsx +260 -260
  83. package/lib/motion/shotcraft/upstream/demos/effects/slam-entrance-moves/ScoreSlam.tsx +263 -263
  84. package/lib/motion/shotcraft/upstream/demos/effects/spotlight-sweep-moves/CornerSpotlightReveal.tsx +123 -123
  85. package/lib/motion/shotcraft/upstream/demos/effects/spotlight-sweep-moves/GlowWakeSleepPanel.tsx +187 -187
  86. package/lib/motion/shotcraft/upstream/demos/effects/spotlight-sweep-moves/SlideSpotlightPan.tsx +175 -175
  87. package/lib/motion/shotcraft/upstream/demos/interaction/autolayout-gap-dial/AutolayoutGapDial.tsx +305 -305
  88. package/lib/motion/shotcraft/upstream/demos/interaction/canvas-materialize-moves/DiagramCascadeBuild.tsx +350 -350
  89. package/lib/motion/shotcraft/upstream/demos/interaction/canvas-materialize-moves/PanelToCanvasMaterialize.tsx +352 -352
  90. package/lib/motion/shotcraft/upstream/demos/interaction/chip-grid-single-select-blackout/ChipGridSingleSelectBlackout.tsx +218 -218
  91. package/lib/motion/shotcraft/upstream/demos/interaction/collab-cursor-moves/CursorCastEnsemble.tsx +297 -297
  92. package/lib/motion/shotcraft/upstream/demos/interaction/glass-pill-dictation-typing/GlassPillDictationTyping.tsx +157 -157
  93. package/lib/motion/shotcraft/upstream/demos/interaction/hashtag-to-pill-materialize/HashtagToPillMaterialize.tsx +218 -218
  94. package/lib/motion/shotcraft/upstream/demos/interaction/picker-carousel-feature-cycle/PickerCarouselFeatureCycle.tsx +202 -202
  95. package/lib/motion/shotcraft/upstream/demos/interaction/segmented-thumb-hero/SegmentedThumbHero.tsx +265 -265
  96. package/lib/motion/shotcraft/upstream/demos/interaction/theme-switch-moves/PaletteThemeRipple.tsx +457 -457
  97. package/lib/motion/shotcraft/upstream/demos/interaction/theme-switch-moves/ThemeSweepToggle.tsx +446 -446
  98. package/lib/motion/shotcraft/upstream/demos/interaction/type-and-filter/TypeAndFilter.tsx +249 -249
  99. package/lib/motion/shotcraft/upstream/demos/interaction/voice-waveform-live/VoiceWaveformLive.tsx +278 -278
  100. package/lib/motion/shotcraft/upstream/demos/opening/crane-rise-reveal/CraneRiseReveal.tsx +332 -332
  101. package/lib/motion/shotcraft/upstream/demos/opening/dataviz-landscape-open/DatavizLandscapeOpen.tsx +358 -358
  102. package/lib/motion/shotcraft/upstream/demos/opening/fracture/Fracture.tsx +201 -201
  103. package/lib/motion/shotcraft/upstream/demos/opening/icon-field-colorize/IconFieldColorize.tsx +200 -200
  104. package/lib/motion/shotcraft/upstream/demos/opening/letterspace-materialize/LetterspaceMaterialize.tsx +208 -208
  105. package/lib/motion/shotcraft/upstream/demos/opening/magician-card-flourish/MagicianCardFlourish.tsx +341 -341
  106. package/lib/motion/shotcraft/upstream/demos/opening/orbit-ring-title-open/OrbitRingTitleOpen.tsx +389 -389
  107. package/lib/motion/shotcraft/upstream/demos/opening/spotlight-hero-card/SpotlightHeroCard.tsx +293 -293
  108. package/lib/motion/shotcraft/upstream/demos/opening/stroke-segment-build/StrokeSegmentBuild.tsx +183 -183
  109. package/lib/motion/shotcraft/upstream/demos/opening/text-as-mask/TextAsMask.tsx +245 -245
  110. package/lib/motion/shotcraft/upstream/demos/outro/grain-dissolve/GrainDissolve.tsx +222 -222
  111. package/lib/motion/shotcraft/upstream/demos/outro/logo-shrink-wordmark-lockup/LogoShrinkWordmarkLockup.tsx +223 -223
  112. package/lib/motion/shotcraft/upstream/demos/outro/neon-triple-marquee/NeonTripleMarquee.tsx +217 -217
  113. package/lib/motion/shotcraft/upstream/demos/outro/outro-group-photo-launch/OutroGroupPhotoLaunch.tsx +343 -343
  114. package/lib/motion/shotcraft/upstream/demos/outro/ui-strip-away-outro/UiStripAwayOutro.tsx +357 -357
  115. package/lib/motion/shotcraft/upstream/demos/outro/ui-to-brand-morph/IconFlipBloomLogo.tsx +187 -187
  116. package/lib/motion/shotcraft/upstream/demos/outro/ui-to-brand-morph/InputMorphsIntoLogo.tsx +333 -333
  117. package/lib/motion/shotcraft/upstream/demos/rhythm/beat-cut-moves/PaparazziFlash.tsx +274 -274
  118. package/lib/motion/shotcraft/upstream/demos/rhythm/beat-step-list-theme-cycle/BeatStepListThemeCycle.tsx +270 -270
  119. package/lib/motion/shotcraft/upstream/demos/rhythm/panel-grid-moves/ComicPanelSplit.tsx +430 -430
  120. package/lib/motion/shotcraft/upstream/demos/rhythm/quad-split-parallel-scenes/QuadSplitParallelScenes.tsx +252 -252
  121. package/lib/motion/shotcraft/upstream/demos/rhythm/rhythm-interrupt-moves/JumpCutPunchIn.tsx +106 -106
  122. package/lib/motion/shotcraft/upstream/demos/rhythm/sakuga-timing-shift/SakugaTimingShift.tsx +288 -288
  123. package/lib/motion/shotcraft/upstream/demos/rhythm/speed-ramp-freeze/FreezeAnnotateReal.tsx +362 -362
  124. package/lib/motion/shotcraft/upstream/demos/rhythm/trailer-grammar-moves/TrailerBumper.tsx +168 -168
  125. package/lib/motion/shotcraft/upstream/demos/transition/bottom-push-stack-wipe/BottomPushStackWipe.tsx +310 -310
  126. package/lib/motion/shotcraft/upstream/demos/transition/card-flip-reveal/CardFlipReveal.tsx +261 -261
  127. package/lib/motion/shotcraft/upstream/demos/transition/card-flock-tumble/CardFlockTumble.tsx +459 -459
  128. package/lib/motion/shotcraft/upstream/demos/transition/circle-match-iris/CircleMatchIris.tsx +294 -294
  129. package/lib/motion/shotcraft/upstream/demos/transition/gradient-transition/GradientTransition.tsx +161 -161
  130. package/lib/motion/shotcraft/upstream/demos/transition/line-carry-transition/LineCarryTransition.tsx +248 -248
  131. package/lib/motion/shotcraft/upstream/demos/transition/mosaic-reframe/MosaicReframe.tsx +359 -359
  132. package/lib/motion/shotcraft/upstream/demos/transition/page-turn-transitions/BarnDoorSplit.tsx +227 -227
  133. package/lib/motion/shotcraft/upstream/demos/transition/print-texture-transitions/InkBleedReveal.tsx +162 -162
  134. package/lib/motion/shotcraft/upstream/demos/transition/shot-transitions/PortalWipeV2.tsx +248 -248
  135. package/lib/motion/shotcraft/upstream/demos/transition/shot-transitions/WhipBrakeReal.tsx +186 -186
  136. package/lib/motion/shotcraft/upstream/demos/transition/tear-streak-transitions/GlitchDisplace.tsx +355 -355
  137. package/lib/motion/shotcraft/upstream/demos/transition/transition-hidden-cut/InvisibleCut.tsx +272 -272
  138. package/lib/motion/shotcraft/upstream/demos/transition/transition-hidden-cut/LightLeakBurn.tsx +262 -262
  139. package/lib/motion/shotcraft/upstream/demos/transition/transition-hidden-cut/VersusSlam.tsx +217 -217
  140. package/lib/motion/shotcraft/upstream/demos/transition/transition-travel/LetterformZoom.tsx +285 -285
  141. package/lib/motion/shotcraft/upstream/demos/transition/white-flash-logo-simplify-cut/WhiteFlashLogoSimplifyCut.tsx +205 -205
  142. package/lib/motion/shotcraft/upstream/demos/transition/wipe-transitions/BlindsSlice.tsx +178 -178
  143. package/lib/motion/shotcraft/upstream/demos/typography/blur-slide/BlurSlide.tsx +147 -147
  144. package/lib/motion/shotcraft/upstream/demos/typography/brace-expand/BraceExpand.tsx +143 -143
  145. package/lib/motion/shotcraft/upstream/demos/typography/brand-ink-open/BrandInkOpen.tsx +134 -134
  146. package/lib/motion/shotcraft/upstream/demos/typography/countdown-arc-scatter/CountdownArcScatter.tsx +217 -217
  147. package/lib/motion/shotcraft/upstream/demos/typography/flying-words/FlyingWords.tsx +198 -198
  148. package/lib/motion/shotcraft/upstream/demos/typography/glitch-cycle/GlitchCycle.tsx +221 -221
  149. package/lib/motion/shotcraft/upstream/demos/typography/gradient-word-sweep/GradientWordSweep.tsx +312 -312
  150. package/lib/motion/shotcraft/upstream/demos/typography/lead-word-zoom-assemble/LeadWordZoomAssemble.tsx +261 -261
  151. package/lib/motion/shotcraft/upstream/demos/typography/marker-underline-title/MarkerUnderlineTitle.tsx +121 -121
  152. package/lib/motion/shotcraft/upstream/demos/typography/outline-word-fill/OutlineWordFill.tsx +153 -153
  153. package/lib/motion/shotcraft/upstream/demos/typography/paper-title-card/PaperTitleCard.tsx +179 -179
  154. package/lib/motion/shotcraft/upstream/demos/typography/pill-chip-slot-cycle-handled/PillChipSlotCycleHandled.tsx +140 -140
  155. package/lib/motion/shotcraft/upstream/demos/typography/pill-slot-cycle/PillSlotCycle.tsx +309 -309
  156. package/lib/motion/shotcraft/upstream/demos/typography/text-column-converge/TextColumnConverge.tsx +191 -191
  157. package/lib/motion/shotcraft/upstream/demos/typography/title-demote-to-label/TitleDemoteToLabel.tsx +292 -292
  158. package/lib/motion/shotcraft/upstream/demos/typography/type-assembly-moves/LetterformDriftAssembly.tsx +135 -135
  159. package/lib/motion/shotcraft/upstream/demos/typography/type-assembly-moves/SplitTextStagger.tsx +124 -124
  160. package/lib/motion/shotcraft/upstream/demos/typography/type-assembly-moves/TextOnPath.tsx +255 -255
  161. package/lib/motion/shotcraft/upstream/demos/typography/type-entrance-moves/LetterDropPhysics.tsx +173 -173
  162. package/lib/motion/shotcraft/upstream/demos/typography/type-rhythm-sync/FontWeightPump.tsx +225 -225
  163. package/lib/motion/shotcraft/upstream/demos/typography/type-rhythm-sync/KaraokeFillSync.tsx +141 -141
  164. package/lib/motion/shotcraft/upstream/demos/typography/typewriter-moves/TypewriterErrorRetype.tsx +137 -137
  165. package/lib/motion/shotcraft/upstream/demos/typography/vertical-word-roll-blur-cycle/VerticalWordRollBlurCycle.tsx +147 -147
  166. package/lib/motion/shotcraft/upstream/demos/typography/word-relay-filmstrip/WordRelayFilmstrip.tsx +409 -409
  167. package/lib/motion/shotcraft/upstream/demos/typography/word-relay-geometry/WordRelayGeometry.tsx +280 -280
  168. package/lib/motion/shotcraft/upstream/demos/ui-entrance/avatar-bracket-carousel/AvatarBracketCarousel.tsx +271 -271
  169. package/lib/motion/shotcraft/upstream/demos/ui-entrance/bezier-source-converge-merge/BezierSourceConvergeMerge.tsx +385 -385
  170. package/lib/motion/shotcraft/upstream/demos/ui-entrance/card-stack/CardStack.tsx +312 -312
  171. package/lib/motion/shotcraft/upstream/demos/ui-entrance/carousel-3d/Carousel3D.tsx +303 -303
  172. package/lib/motion/shotcraft/upstream/demos/ui-entrance/clipcard-looping/ClipCardLooping.tsx +77 -77
  173. package/lib/motion/shotcraft/upstream/demos/ui-entrance/cloner-depth-echo/ClonerDepthEcho.tsx +311 -311
  174. package/lib/motion/shotcraft/upstream/demos/ui-entrance/deck-deal-flyin/DeckDealFlyin.tsx +307 -307
  175. package/lib/motion/shotcraft/upstream/demos/ui-entrance/doc-park-left-pill-deal/DocParkLeftPillDeal.tsx +349 -349
  176. package/lib/motion/shotcraft/upstream/demos/ui-entrance/document-typewriter-reveal/DocumentTypewriterReveal.tsx +255 -255
  177. package/lib/motion/shotcraft/upstream/demos/ui-entrance/draw-svg-trace/DrawSvgTrace.tsx +244 -244
  178. package/lib/motion/shotcraft/upstream/demos/ui-entrance/element-body-moves/ContactShadowLift.tsx +217 -217
  179. package/lib/motion/shotcraft/upstream/demos/ui-entrance/integration-hub-map/IntegrationHubMap.tsx +652 -652
  180. package/lib/motion/shotcraft/upstream/demos/ui-entrance/list-reveal/ListReveal.tsx +153 -153
  181. package/lib/motion/shotcraft/upstream/demos/ui-entrance/list-stack-press/ListStackPress.tsx +238 -238
  182. package/lib/motion/shotcraft/upstream/demos/ui-entrance/neon-frame-forerun/NeonFrameForerun.tsx +324 -324
  183. package/lib/motion/shotcraft/upstream/demos/ui-entrance/neon-frame-orbit-drop/NeonFrameForerunOrbit.tsx +354 -354
  184. package/lib/motion/shotcraft/upstream/demos/ui-entrance/page-waterfall-wall/PageWaterfallWall.tsx +101 -101
  185. package/lib/motion/shotcraft/upstream/demos/ui-entrance/page-waterfall-wall/VerticalTicker.tsx +129 -129
  186. package/lib/motion/shotcraft/upstream/demos/ui-entrance/product-card-progressive-assemble/ProductCardProgressiveAssemble.tsx +297 -297
  187. package/lib/motion/shotcraft/upstream/demos/ui-entrance/radial-wave/RadialWave.tsx +57 -57
  188. package/lib/motion/shotcraft/upstream/demos/ui-entrance/research-card-stack-scroll/ResearchCardStackScroll.tsx +155 -155
  189. package/lib/motion/shotcraft/upstream/demos/ui-entrance/row-embed/RowEmbed.tsx +175 -175
  190. package/lib/motion/shotcraft/upstream/demos/ui-entrance/value-stagger-gradient/ValueStaggerGradient.tsx +153 -153
  191. package/lib/motion/shotcraft/upstream/demos/ui-entrance/wall-reveal-moves/BentoLightUp.tsx +146 -146
  192. package/lib/motion/shotcraft/upstream/demos/ui-entrance/wall-reveal-moves/WireframeDrawOn.tsx +226 -226
  193. package/lib/motion/shotcraft/upstream/gallery/api/library.json +1 -1
  194. package/lib/motion/shotcraft/upstream/references/aesthetic-rules.md +193 -193
  195. package/lib/motion/shotcraft/upstream/references/final-review.md +121 -121
  196. package/lib/motion/shotcraft/upstream/references/guided-free-creation.md +199 -199
  197. package/lib/motion/shotcraft/upstream/references/jianying-export.md +183 -183
  198. package/lib/motion/shotcraft/upstream/references/music-beat-sync.md +257 -257
  199. package/lib/motion/shotcraft/upstream/references/pipeline.md +382 -382
  200. package/lib/motion/shotcraft/upstream/references/publish-upload-post.md +111 -111
  201. package/lib/motion/shotcraft/upstream/references/sequences/promo-energy-arc.md +50 -50
  202. package/lib/motion/shotcraft/upstream/references/sfx-sourcing.md +95 -95
  203. package/lib/motion/shotcraft/upstream/references/shots/camera/basic-3d-scene.md +41 -41
  204. package/lib/motion/shotcraft/upstream/references/shots/camera/crash-zoom-punch.md +52 -52
  205. package/lib/motion/shotcraft/upstream/references/shots/camera/cursor-flyover.md +39 -39
  206. package/lib/motion/shotcraft/upstream/references/shots/camera/depth-layer-moves.md +39 -39
  207. package/lib/motion/shotcraft/upstream/references/shots/camera/graze-face-tour.md +57 -57
  208. package/lib/motion/shotcraft/upstream/references/shots/camera/overhead-camera-moves.md +51 -51
  209. package/lib/motion/shotcraft/upstream/references/shots/camera/space-camera-moves.md +46 -46
  210. package/lib/motion/shotcraft/upstream/references/shots/camera/steep-tilt-glide.md +52 -52
  211. package/lib/motion/shotcraft/upstream/references/shots/camera/tension-camera-moves.md +43 -43
  212. package/lib/motion/shotcraft/upstream/references/shots/camera/terminal-3d.md +42 -42
  213. package/lib/motion/shotcraft/upstream/references/shots/data/before-after-slider-scrub.md +48 -48
  214. package/lib/motion/shotcraft/upstream/references/shots/data/chart-live-moves.md +52 -52
  215. package/lib/motion/shotcraft/upstream/references/shots/data/gauge-readout-moves.md +45 -45
  216. package/lib/motion/shotcraft/upstream/references/shots/data/scroll-brake-moves.md +46 -46
  217. package/lib/motion/shotcraft/upstream/references/shots/data/timeline-travel.md +44 -44
  218. package/lib/motion/shotcraft/upstream/references/shots/effects/assemble-then-type-flyin.md +63 -63
  219. package/lib/motion/shotcraft/upstream/references/shots/effects/aurora-bloom-bg-flip.md +54 -54
  220. package/lib/motion/shotcraft/upstream/references/shots/effects/brand-frame-snap.md +58 -58
  221. package/lib/motion/shotcraft/upstream/references/shots/effects/fui-hud-moves.md +35 -35
  222. package/lib/motion/shotcraft/upstream/references/shots/effects/glow-flyline-moves.md +53 -53
  223. package/lib/motion/shotcraft/upstream/references/shots/effects/icon-performance-moves.md +42 -42
  224. package/lib/motion/shotcraft/upstream/references/shots/effects/impact-feedback.md +50 -50
  225. package/lib/motion/shotcraft/upstream/references/shots/effects/light-play-moves.md +46 -46
  226. package/lib/motion/shotcraft/upstream/references/shots/effects/radial-ripple-phone-chips.md +56 -56
  227. package/lib/motion/shotcraft/upstream/references/shots/effects/riso-print-hits.md +49 -49
  228. package/lib/motion/shotcraft/upstream/references/shots/effects/scan-bracket-sweep.md +50 -50
  229. package/lib/motion/shotcraft/upstream/references/shots/effects/scanline-annotate-focus.md +53 -53
  230. package/lib/motion/shotcraft/upstream/references/shots/effects/scanline-assemble-flyin.md +53 -53
  231. package/lib/motion/shotcraft/upstream/references/shots/effects/slam-entrance-moves.md +55 -55
  232. package/lib/motion/shotcraft/upstream/references/shots/effects/spotlight-sweep-moves.md +52 -52
  233. package/lib/motion/shotcraft/upstream/references/shots/interaction/autolayout-gap-dial.md +60 -60
  234. package/lib/motion/shotcraft/upstream/references/shots/interaction/canvas-materialize-moves.md +57 -57
  235. package/lib/motion/shotcraft/upstream/references/shots/interaction/chip-grid-single-select-blackout.md +51 -51
  236. package/lib/motion/shotcraft/upstream/references/shots/interaction/collab-cursor-moves.md +41 -41
  237. package/lib/motion/shotcraft/upstream/references/shots/interaction/glass-pill-dictation-typing.md +53 -53
  238. package/lib/motion/shotcraft/upstream/references/shots/interaction/hashtag-to-pill-materialize.md +60 -60
  239. package/lib/motion/shotcraft/upstream/references/shots/interaction/picker-carousel-feature-cycle.md +55 -55
  240. package/lib/motion/shotcraft/upstream/references/shots/interaction/segmented-thumb-hero.md +57 -57
  241. package/lib/motion/shotcraft/upstream/references/shots/interaction/theme-switch-moves.md +47 -47
  242. package/lib/motion/shotcraft/upstream/references/shots/interaction/type-and-filter.md +37 -37
  243. package/lib/motion/shotcraft/upstream/references/shots/interaction/voice-waveform-live.md +54 -54
  244. package/lib/motion/shotcraft/upstream/references/shots/opening/brand-ink-open.md +36 -36
  245. package/lib/motion/shotcraft/upstream/references/shots/opening/crane-rise-reveal.md +56 -56
  246. package/lib/motion/shotcraft/upstream/references/shots/opening/dataviz-landscape-open.md +56 -56
  247. package/lib/motion/shotcraft/upstream/references/shots/opening/fracture.md +40 -40
  248. package/lib/motion/shotcraft/upstream/references/shots/opening/icon-field-colorize.md +60 -60
  249. package/lib/motion/shotcraft/upstream/references/shots/opening/letterspace-materialize.md +57 -57
  250. package/lib/motion/shotcraft/upstream/references/shots/opening/magician-card-flourish.md +73 -73
  251. package/lib/motion/shotcraft/upstream/references/shots/opening/orbit-ring-title-open.md +87 -87
  252. package/lib/motion/shotcraft/upstream/references/shots/opening/spotlight-hero-card.md +55 -55
  253. package/lib/motion/shotcraft/upstream/references/shots/opening/stroke-segment-build.md +50 -50
  254. package/lib/motion/shotcraft/upstream/references/shots/opening/text-as-mask.md +59 -59
  255. package/lib/motion/shotcraft/upstream/references/shots/outro/grain-dissolve.md +38 -38
  256. package/lib/motion/shotcraft/upstream/references/shots/outro/logo-shrink-wordmark-lockup.md +38 -38
  257. package/lib/motion/shotcraft/upstream/references/shots/outro/neon-triple-marquee.md +59 -59
  258. package/lib/motion/shotcraft/upstream/references/shots/outro/outro-group-photo-launch.md +39 -39
  259. package/lib/motion/shotcraft/upstream/references/shots/outro/ui-strip-away-outro.md +61 -61
  260. package/lib/motion/shotcraft/upstream/references/shots/outro/ui-to-brand-morph.md +52 -52
  261. package/lib/motion/shotcraft/upstream/references/shots/rhythm/beat-cut-moves.md +50 -50
  262. package/lib/motion/shotcraft/upstream/references/shots/rhythm/beat-step-list-theme-cycle.md +66 -66
  263. package/lib/motion/shotcraft/upstream/references/shots/rhythm/panel-grid-moves.md +43 -43
  264. package/lib/motion/shotcraft/upstream/references/shots/rhythm/quad-split-parallel-scenes.md +38 -38
  265. package/lib/motion/shotcraft/upstream/references/shots/rhythm/rhythm-interrupt-moves.md +38 -38
  266. package/lib/motion/shotcraft/upstream/references/shots/rhythm/sakuga-timing-shift.md +56 -56
  267. package/lib/motion/shotcraft/upstream/references/shots/rhythm/speed-ramp-freeze.md +44 -44
  268. package/lib/motion/shotcraft/upstream/references/shots/rhythm/trailer-grammar-moves.md +38 -38
  269. package/lib/motion/shotcraft/upstream/references/shots/transition/bottom-push-stack-wipe.md +63 -63
  270. package/lib/motion/shotcraft/upstream/references/shots/transition/card-flip-reveal.md +57 -57
  271. package/lib/motion/shotcraft/upstream/references/shots/transition/card-flock-tumble.md +63 -63
  272. package/lib/motion/shotcraft/upstream/references/shots/transition/circle-match-iris.md +58 -58
  273. package/lib/motion/shotcraft/upstream/references/shots/transition/gradient-transition.md +45 -45
  274. package/lib/motion/shotcraft/upstream/references/shots/transition/line-carry-transition.md +55 -55
  275. package/lib/motion/shotcraft/upstream/references/shots/transition/mosaic-reframe.md +49 -49
  276. package/lib/motion/shotcraft/upstream/references/shots/transition/page-turn-transitions.md +42 -42
  277. package/lib/motion/shotcraft/upstream/references/shots/transition/print-texture-transitions.md +42 -42
  278. package/lib/motion/shotcraft/upstream/references/shots/transition/shot-transitions.md +45 -45
  279. package/lib/motion/shotcraft/upstream/references/shots/transition/tear-streak-transitions.md +48 -48
  280. package/lib/motion/shotcraft/upstream/references/shots/transition/transition-hidden-cut.md +55 -55
  281. package/lib/motion/shotcraft/upstream/references/shots/transition/transition-travel.md +43 -43
  282. package/lib/motion/shotcraft/upstream/references/shots/transition/white-flash-logo-simplify-cut.md +41 -41
  283. package/lib/motion/shotcraft/upstream/references/shots/transition/wipe-transitions.md +42 -42
  284. package/lib/motion/shotcraft/upstream/references/shots/typography/blur-slide.md +59 -59
  285. package/lib/motion/shotcraft/upstream/references/shots/typography/brace-expand.md +55 -55
  286. package/lib/motion/shotcraft/upstream/references/shots/typography/countdown-arc-scatter.md +65 -65
  287. package/lib/motion/shotcraft/upstream/references/shots/typography/document-typewriter-reveal.md +42 -42
  288. package/lib/motion/shotcraft/upstream/references/shots/typography/flying-words.md +64 -64
  289. package/lib/motion/shotcraft/upstream/references/shots/typography/glitch-cycle.md +64 -64
  290. package/lib/motion/shotcraft/upstream/references/shots/typography/gradient-word-sweep.md +54 -54
  291. package/lib/motion/shotcraft/upstream/references/shots/typography/lead-word-zoom-assemble.md +91 -91
  292. package/lib/motion/shotcraft/upstream/references/shots/typography/marker-underline-title.md +51 -51
  293. package/lib/motion/shotcraft/upstream/references/shots/typography/outline-word-fill.md +66 -66
  294. package/lib/motion/shotcraft/upstream/references/shots/typography/paper-title-card.md +38 -38
  295. package/lib/motion/shotcraft/upstream/references/shots/typography/pill-chip-slot-cycle-handled.md +66 -66
  296. package/lib/motion/shotcraft/upstream/references/shots/typography/pill-slot-cycle.md +58 -58
  297. package/lib/motion/shotcraft/upstream/references/shots/typography/text-column-converge.md +61 -61
  298. package/lib/motion/shotcraft/upstream/references/shots/typography/title-demote-to-label.md +64 -64
  299. package/lib/motion/shotcraft/upstream/references/shots/typography/type-assembly-moves.md +45 -45
  300. package/lib/motion/shotcraft/upstream/references/shots/typography/type-entrance-moves.md +41 -41
  301. package/lib/motion/shotcraft/upstream/references/shots/typography/type-rhythm-sync.md +51 -51
  302. package/lib/motion/shotcraft/upstream/references/shots/typography/typewriter-moves.md +42 -42
  303. package/lib/motion/shotcraft/upstream/references/shots/typography/vertical-word-roll-blur-cycle.md +63 -63
  304. package/lib/motion/shotcraft/upstream/references/shots/typography/word-relay-filmstrip.md +57 -57
  305. package/lib/motion/shotcraft/upstream/references/shots/typography/word-relay-geometry.md +75 -75
  306. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/avatar-bracket-carousel.md +59 -59
  307. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/bezier-source-converge-merge.md +67 -67
  308. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/card-stack.md +60 -60
  309. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/carousel-3d.md +66 -66
  310. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/cloner-depth-echo.md +40 -40
  311. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/deck-deal-flyin.md +45 -45
  312. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/doc-park-left-pill-deal.md +62 -62
  313. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/draw-svg-trace.md +55 -55
  314. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/element-body-moves.md +37 -37
  315. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/integration-hub-map.md +55 -55
  316. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/list-reveal.md +50 -50
  317. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/list-stack-press.md +43 -43
  318. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/neon-frame-forerun.md +55 -55
  319. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/neon-frame-orbit-drop.md +51 -51
  320. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/page-waterfall-wall.md +51 -51
  321. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/product-card-progressive-assemble.md +56 -56
  322. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/radial-wave.md +49 -49
  323. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/research-card-stack-scroll.md +57 -57
  324. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/row-embed.md +36 -36
  325. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/value-stagger-gradient.md +64 -64
  326. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/wall-reveal-moves.md +47 -47
  327. package/lib/motion/shotcraft/upstream/references/sound-design.md +170 -170
  328. package/lib/motion/shotcraft/upstream/references/workbench.md +157 -157
  329. package/lib/motion/shotcraft/upstream/template/TEMPLATE.md +103 -103
  330. package/lib/motion/shotcraft/upstream/template/THEMES.md +44 -44
  331. package/lib/motion/shotcraft/upstream/template/package.json +20 -20
  332. package/lib/motion/shotcraft/upstream/template/remotion.config.ts +6 -6
  333. package/lib/motion/shotcraft/upstream/template/src/Root.tsx +17 -17
  334. package/lib/motion/shotcraft/upstream/template/src/aifl/Caption.tsx +65 -65
  335. package/lib/motion/shotcraft/upstream/template/src/aifl/DigitRoll.tsx +48 -48
  336. package/lib/motion/shotcraft/upstream/template/src/aifl/FlashCut.tsx +24 -24
  337. package/lib/motion/shotcraft/upstream/template/src/aifl/Main.tsx +192 -192
  338. package/lib/motion/shotcraft/upstream/template/src/aifl/PaperTitleCard.tsx +111 -111
  339. package/lib/motion/shotcraft/upstream/template/src/aifl/live/PageCam.tsx +150 -150
  340. package/lib/motion/shotcraft/upstream/template/src/aifl/live/SceneDetail.tsx +158 -158
  341. package/lib/motion/shotcraft/upstream/template/src/aifl/live/SceneFlyIn.tsx +468 -468
  342. package/lib/motion/shotcraft/upstream/template/src/aifl/live/SceneOpen.tsx +552 -552
  343. package/lib/motion/shotcraft/upstream/template/src/aifl/live/SceneOutroLive.tsx +411 -411
  344. package/lib/motion/shotcraft/upstream/template/src/aifl/live/ScenePapers.tsx +200 -200
  345. package/lib/motion/shotcraft/upstream/template/src/aifl/live/SceneWbr.tsx +324 -324
  346. package/lib/motion/shotcraft/upstream/template/src/aifl/live-layout.json +388 -388
  347. package/lib/motion/shotcraft/upstream/template/src/index.ts +4 -4
  348. package/lib/motion/shotcraft/upstream/template/src/themes/ThemedFilm.tsx +7 -7
  349. package/lib/motion/shotcraft/upstream/template/src/themes/manifest.tsx +68 -68
  350. package/lib/motion/shotcraft/upstream/template/src/themes/palette-assets.json +1 -1
  351. package/lib/motion/shotcraft/upstream/template/src/themes/palette-assets.ts +24 -24
  352. package/lib/motion/shotcraft/upstream/template/src/themes/palettes.json +74 -74
  353. package/lib/motion/shotcraft/upstream/template/src/themes/visual-theme.tsx +91 -91
  354. package/lib/motion/shotcraft/upstream/template/src/workbench.ts +213 -213
  355. package/lib/motion/shotcraft/upstream/template/tsconfig.json +15 -15
  356. package/lib/motion/style-frames.js +306 -306
  357. package/lib/motion/sync.js +214 -214
  358. package/lib/motion-project.js +105 -105
  359. package/lib/motion-render-worker.js +174 -174
  360. package/lib/routing/router.js +222 -222
  361. package/lib/routing/vendor/README.md +96 -96
  362. package/lib/routing/vendor/libavoid-routing.js +753 -753
  363. package/lib/routing/vendor/libavoid.min.js +59 -59
  364. package/lib/video-trace-pool.js +128 -128
  365. package/package.json +1 -1
  366. package/LICENSE +0 -4175
@@ -1,457 +1,457 @@
1
- // 组合:命令面板 × 深浅涟漪(palette-theme-ripple)——第二轮重设计:video-shotcraft 样片画廊 · 关灯
2
- //
3
- // 设计决定:
4
- // - 主体:满屏的 video-shotcraft 样片画廊(品牌轮由虚构音乐库 Overtone 换来,版式逐像素不变)——
5
- // 112px「Gallery」大标题、5 张 259px 程序化镜头缩略图(同一批缩略图在深浅两版里完全不变,只换 UI 外壳——
6
- // 真实产品的深色模式就是这样)、底部正在预览的样片播放条。侧栏标志 = 「镜刻」ShotcraftMark(随主题换反白版)。
7
- // - look = custom:浅版冷瓷灰白 + 珊瑚红强调;深版近黑石墨 + 同色相更亮的珊瑚。强调色只给选中态 / 播放进度 / 涟漪。
8
- // - 因果链(组合命门):⌘K 面板落下 → 人手节奏打 "dark"(不等间隔)→ 回车 → 面板像老电视关机一样
9
- // 先纵向压成一条亮线、再横向收成一个亮点 → 亮点在原地钉 5f → 深色涟漪**从这个点**荡开换肤。
10
- // 收缩点 = 面板中心 = 涟漪圆心 ORIGIN;收缩完成帧 = 亮点帧,亮点结束帧 = 涟漪起始帧 RIPPLE。
11
- // - 涟漪:3px 白热环 + 珊瑚外辉 + 内侧白辉,外加一道晚 4f 的淡回声环;深版从圆心 1.035→1 收拢"坐实"。
12
- // 深版落定后专辑封面在暗场里各自投下一圈同色辉光(只有深色模式才看得见的光)。
13
- // - 相机:打字时极缓推向面板(1→1.03),涟漪荡开时顺势呼一口气退回 1,hold 段再 1→1.012 极缓推。
14
- //
15
- // 时间表(30fps,共 156f):
16
- // 0–10 静置:浅色样片画廊(播放进度在走,画面不死)
17
- // 10–18 压暗 + 虚化背景(8f EASE.out);12 面板弹簧落下(damping 17,一次轻过冲)
18
- // 24–37 打字 d·a·r·k(24/28/31/37,人手不等间隔);匹配字母逐个加粗,37 首行进入选中态
19
- // 46 回车:首行闪一下、↵ 键帽按下
20
- // 48–56 CRT 关机式收缩:48–52 纵向压成亮线(ease-in),52–56 横向收成亮点;背景同步去虚化
21
- // 56–61 亮点钉在 ORIGIN(因果钉扎)
22
- // 61–95 深色涟漪荡开(34f,强 ease-out:起步猛、边缘越走越缓)+ 回声环;相机 1.03→1
23
- // 95–156 hold:深色定格,封面辉光亮起(95–112),进度条继续走,相机 1→1.012
24
- import React from 'react';
25
- import { AbsoluteFill, useCurrentFrame } from 'remotion';
26
- import { EASE, FONT, Grain, Vignette, bezier, mix, ramp } from '../../_fixtures/Polish';
27
- import { alpha, springAt } from '../../_fixtures/Look';
28
- import { BRAND, ShotcraftMark } from '../../_fixtures/Brand';
29
-
30
- export const PALETTE_THEME_RIPPLE_DURATION = 156;
31
-
32
- // ───────────── 时间轴 ─────────────
33
- const DIM0 = 10;
34
- const PANEL_IN = 12;
35
- const TYPE_FRAMES = [24, 28, 31, 37]; // d a r k —— 人手节奏:起手快、r→k 犹豫一下
36
- const ENTER = 46;
37
- const SQUASH = 48; // 纵向压线开始
38
- const LINE = 52; // 压成线 → 开始横向收点
39
- const DOT = 56; // 收成点(= 亮点帧)
40
- const RIPPLE = 61; // 亮点钉 5f 后涟漪起跳(组合命门:圆心 = 收缩点)
41
- const RIPPLE_END = 95;
42
- const ORIGIN = { x: 960, y: 452 }; // 面板中心 = 收缩点 = 涟漪圆心
43
- const MAX_R = 1260; // 圆心到最远角 ≈1150px,留出相机推进余量
44
-
45
- const QUERY = 'dark';
46
-
47
- // ───────────── 两套外壳(同布局,逐键映射)─────────────
48
- type Theme = {
49
- dark: boolean; bg: string; side: string; surface: string; chip: string; line: string;
50
- ink: string; ink2: string; ink3: string; accent: string; bar: string;
51
- };
52
- const LIGHT: Theme = {
53
- dark: false, bg: '#f1f2f4', side: '#e8eaed', surface: '#ffffff', chip: '#e3e6ea', line: 'rgba(15,20,30,0.08)',
54
- ink: '#0f1217', ink2: '#5a616e', ink3: '#9aa1ad', accent: '#f2483a', bar: 'rgba(248,249,250,0.92)',
55
- };
56
- const DARK: Theme = {
57
- dark: true, bg: '#0b0d10', side: '#08090b', surface: '#15181c', chip: '#1b1f24', line: 'rgba(255,255,255,0.07)',
58
- ink: '#f3f4f6', ink2: '#939aa7', ink3: '#59606c', accent: '#ff5f48', bar: 'rgba(16,18,22,0.94)',
59
- };
60
-
61
- // ───────────── 程序化镜头缩略图(深浅两版共用,不随主题变)─────────────
62
- type Album = { t: string; a: string; glow: string; Art: React.FC };
63
- const ArtLowTide: React.FC = () => (
64
- <div style={{ position: 'absolute', inset: 0, background: 'linear-gradient(180deg, #0f2747 0%, #1d5f74 58%, #e7a874 100%)' }}>
65
- <div style={{ position: 'absolute', left: '30%', top: '30%', width: '40%', height: '40%', borderRadius: '50%', background: 'radial-gradient(circle at 50% 40%, #ffe6bd, #f7b57a)', boxShadow: '0 0 40px rgba(255,200,140,0.6)' }} />
66
- <div style={{ position: 'absolute', left: 0, right: 0, top: '62%', bottom: 0, background: 'repeating-linear-gradient(180deg, rgba(10,30,55,0.92) 0px, rgba(10,30,55,0.92) 7px, rgba(255,200,150,0.35) 7px, rgba(255,200,150,0.35) 9px)' }} />
67
- </div>
68
- );
69
- const ArtPaperMoons: React.FC = () => (
70
- <div style={{ position: 'absolute', inset: 0, background: '#f1d8c2' }}>
71
- <div style={{ position: 'absolute', left: '12%', top: '18%', width: '52%', height: '52%', borderRadius: '50%', background: '#e46a4e' }} />
72
- <div style={{ position: 'absolute', left: '36%', top: '34%', width: '52%', height: '52%', borderRadius: '50%', background: '#253a63', mixBlendMode: 'multiply' }} />
73
- <div style={{ position: 'absolute', left: '58%', top: '12%', width: '22%', height: '22%', borderRadius: '50%', background: '#f4b23e' }} />
74
- </div>
75
- );
76
- const ArtNeonOrchard: React.FC = () => (
77
- <div style={{ position: 'absolute', inset: 0, background: 'linear-gradient(150deg, #ff2f7d 0%, #ff8a3a 100%)', overflow: 'hidden' }}>
78
- <svg viewBox="0 0 100 100" width="100%" height="100%" style={{ position: 'absolute', inset: 0 }}>
79
- {Array.from({ length: 9 }, (_, i) => <line key={`h${i}`} x1={0} x2={100} y1={55 + i * i * 0.6} y2={55 + i * i * 0.6} stroke="rgba(255,255,255,0.45)" strokeWidth={0.5} />)}
80
- {Array.from({ length: 11 }, (_, i) => <line key={`v${i}`} x1={50} y1={55} x2={-50 + i * 20} y2={100} stroke="rgba(255,255,255,0.45)" strokeWidth={0.5} />)}
81
- <circle cx={50} cy={38} r={17} fill="#ffe14d" />
82
- {[0, 1, 2, 3].map((i) => <rect key={i} x={30} y={40 + i * 4} width={40} height={1.6} fill="#ff4f6e" />)}
83
- </svg>
84
- </div>
85
- );
86
- const ArtStaticBloom: React.FC = () => (
87
- <div style={{ position: 'absolute', inset: 0, background: 'radial-gradient(circle at 50% 50%, #2c5a3e, #142b1f)' }}>
88
- <svg viewBox="0 0 100 100" width="100%" height="100%" style={{ position: 'absolute', inset: 0 }}>
89
- {Array.from({ length: 8 }, (_, i) => {
90
- const a = (i / 8) * Math.PI * 2;
91
- return <circle key={i} cx={50 + Math.cos(a) * 17} cy={50 + Math.sin(a) * 17} r={13} fill="#9fe48c" opacity={0.85} style={{ mixBlendMode: 'screen' }} />;
92
- })}
93
- <circle cx={50} cy={50} r={9} fill="#f4f8cc" />
94
- </svg>
95
- </div>
96
- );
97
- const ArtNightSwim: React.FC = () => (
98
- <div style={{ position: 'absolute', inset: 0, background: '#060a14', overflow: 'hidden' }}>
99
- <div style={{ position: 'absolute', inset: '-20%', transform: 'rotate(-28deg)', background: 'repeating-linear-gradient(90deg, rgba(70,120,255,0.0) 0px, rgba(70,120,255,0.0) 16px, rgba(70,140,255,0.75) 16px, rgba(70,140,255,0.75) 22px)' }} />
100
- <div style={{ position: 'absolute', right: '16%', top: '14%', width: '16%', height: '16%', borderRadius: '50%', background: '#eef3ff', boxShadow: '0 0 24px rgba(220,230,255,0.8)' }} />
101
- </div>
102
- );
103
- const ArtGlassHarbor: React.FC = () => (
104
- <div style={{ position: 'absolute', inset: 0, background: 'linear-gradient(160deg, #19c3b4 0%, #2a3d9e 100%)' }}>
105
- <svg viewBox="0 0 100 100" width="100%" height="100%" style={{ position: 'absolute', inset: 0 }}>
106
- {[14, 24, 34, 44].map((r) => <circle key={r} cx={30} cy={70} r={r} fill="none" stroke="rgba(255,255,255,0.4)" strokeWidth={1.2} />)}
107
- </svg>
108
- </div>
109
- );
110
-
111
- const ALBUMS: Album[] = [
112
- { t: 'Horizon Push', a: 'Camera · 2.5D', glow: '#f2a46e', Art: ArtLowTide },
113
- { t: 'Ink Press', a: 'Opening', glow: '#e46a4e', Art: ArtPaperMoons },
114
- { t: 'Neon Marquee', a: 'Outro', glow: '#ff5a6a', Art: ArtNeonOrchard },
115
- { t: 'Glow Bloom', a: 'Effects', glow: '#7ed67a', Art: ArtStaticBloom },
116
- { t: 'Whip Pan', a: 'Transition', glow: '#5c8cff', Art: ArtNightSwim },
117
- ];
118
- const ROW2: { Art: React.FC; hue: number }[] = [
119
- { Art: ArtNightSwim, hue: 140 }, { Art: ArtStaticBloom, hue: -60 }, { Art: ArtLowTide, hue: 40 }, { Art: ArtNeonOrchard, hue: 160 }, { Art: ArtPaperMoons, hue: 180 },
120
- ];
121
-
122
- // ───────────── 布局 ─────────────
123
- const SIDE_W = 350;
124
- const MAIN_X = 430;
125
- const MAIN_W = 1920 - MAIN_X - 112;
126
- const TILE_GAP = 36;
127
- const TILE = (MAIN_W - TILE_GAP * 4) / 5;
128
- const ROW1_Y = 300;
129
- const ROW2_Y = ROW1_Y + TILE + 130;
130
- const BAR_H = 124;
131
-
132
- // 16 网格线性图标
133
- const Ic: React.FC<{ d: string[]; color: string; size?: number; w?: number }> = ({ d, color, size = 28, w = 1.6 }) => (
134
- <svg width={size} height={size} viewBox="0 0 16 16" fill="none" style={{ display: 'block', flex: 'none' }}>
135
- {d.map((p, i) => <path key={i} d={p} stroke={color} strokeWidth={w} strokeLinecap="round" strokeLinejoin="round" />)}
136
- </svg>
137
- );
138
- const I = {
139
- play: ['M5 3.5v9l7-4.5z'],
140
- grid: ['M2.5 2.5h4.5v4.5h-4.5z', 'M9 2.5h4.5v4.5h-4.5z', 'M2.5 9h4.5v4.5h-4.5z', 'M9 9h4.5v4.5h-4.5z'],
141
- radio: ['M8 9.5a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3z', 'M4.8 4.8a4.5 4.5 0 0 0 0 6.4', 'M11.2 4.8a4.5 4.5 0 0 1 0 6.4'],
142
- lib: ['M3 2.5v11', 'M6 2.5v11', 'M9 3l3.5 10'],
143
- sliders: ['M2.5 4.5h11', 'M2.5 11.5h11', 'M5.5 2.5v4', 'M10.5 9.5v4'],
144
- list: ['M2.5 4h11', 'M2.5 8h11', 'M2.5 12h7'],
145
- moon: ['M13 9.6A5.5 5.5 0 1 1 6.4 3a4.4 4.4 0 0 0 6.6 6.6z'],
146
- half: ['M8 2.5a5.5 5.5 0 1 0 0 11 5.5 5.5 0 0 0 0-11z', 'M8 2.5v11'],
147
- gear: ['M8 10a2 2 0 1 0 0-4 2 2 0 0 0 0 4z', 'M8 1.8v1.6M8 12.6v1.6M1.8 8h1.6M12.6 8h1.6M3.6 3.6l1.1 1.1M11.3 11.3l1.1 1.1M3.6 12.4l1.1-1.1M11.3 4.7l1.1-1.1'],
148
- search: ['M7 11.5a4.5 4.5 0 1 0 0-9 4.5 4.5 0 0 0 0 9z', 'm10.5 10.5 3 3'],
149
- prev: ['M4 3.5v9', 'M12.5 3.5v9l-6.5-4.5z'],
150
- next: ['M12 3.5v9', 'M3.5 3.5v9l6.5-4.5z'],
151
- };
152
-
153
- // ───────────── 整个 App(两版主题共用这一份布局)─────────────
154
- const App: React.FC<{ th: Theme; frame: number; artGlow: number }> = ({ th, frame, artGlow }) => {
155
- const prog = 0.34 + frame * 0.0009; // 播放进度一直在走
156
- return (
157
- <div style={{ position: 'absolute', inset: 0, background: th.bg, fontFamily: FONT.sans, color: th.ink, overflow: 'hidden' }}>
158
- {/* 侧栏 */}
159
- <div style={{ position: 'absolute', left: 0, top: 0, bottom: 0, width: SIDE_W, background: th.side, borderRight: `1px solid ${th.line}`, padding: '64px 0 0 104px', boxSizing: 'border-box' }}>
160
- <div style={{ display: 'flex', alignItems: 'center', gap: 14, marginBottom: 64 }}>
161
- {/* 「镜刻」标志:亮版墨框 / 深版反白框,琥珀斜切不变(标志本身不加底块与渐变) */}
162
- <ShotcraftMark size={44} tone={th.dark ? 'dark' : 'light'} />
163
- <span style={{ fontFamily: BRAND.font, fontSize: 34, fontWeight: 700, letterSpacing: '0.01em' }}>{BRAND.short}</span>
164
- </div>
165
- {[
166
- { l: 'Home', i: I.play },
167
- { l: 'Shot cards', i: I.grid },
168
- { l: 'Workbench', i: I.sliders },
169
- { l: 'Gallery', i: I.lib, on: true },
170
- { l: 'Renders', i: I.list },
171
- ].map((n) => (
172
- <div key={n.l} style={{
173
- display: 'flex', alignItems: 'center', gap: 18, height: 64, marginLeft: -18, marginRight: 34, paddingLeft: 18, borderRadius: 14,
174
- background: n.on ? (th.dark ? 'rgba(255,255,255,0.06)' : 'rgba(15,20,30,0.06)') : 'transparent',
175
- color: n.on ? th.ink : th.ink2, fontSize: 28, fontWeight: n.on ? 650 : 500,
176
- }}>
177
- <Ic d={n.i} color={n.on ? th.accent : th.ink3} />
178
- {n.l}
179
- </div>
180
- ))}
181
- </div>
182
-
183
- {/* 标题区 */}
184
- <div style={{ position: 'absolute', left: MAIN_X, top: 70, fontSize: 112, fontWeight: 800, letterSpacing: '-0.045em', lineHeight: 1 }}>Gallery</div>
185
- <div style={{ position: 'absolute', left: MAIN_X, top: 208, display: 'flex', gap: 12 }}>
186
- {['All shots', 'Camera', 'Outro', 'Made for you'].map((c, i) => (
187
- <div key={c} style={{
188
- padding: '10px 24px', borderRadius: 999, fontSize: 26, fontWeight: i === 0 ? 650 : 500,
189
- background: i === 0 ? th.ink : th.chip, color: i === 0 ? th.bg : th.ink2,
190
- }}>{c}</div>
191
- ))}
192
- </div>
193
- <div style={{ position: 'absolute', right: 112, top: 222, fontSize: 26, color: th.ink3, fontWeight: 500 }}>1080p · 30fps · sorted by recent</div>
194
-
195
- {/* 第一排封面 */}
196
- {ALBUMS.map((al, i) => {
197
- const x = MAIN_X + i * (TILE + TILE_GAP);
198
- return (
199
- <React.Fragment key={al.t}>
200
- {th.dark && (
201
- <div style={{
202
- position: 'absolute', left: x - 90, top: ROW1_Y - 30, width: TILE + 180, height: TILE + 170,
203
- background: `radial-gradient(ellipse 50% 50% at 50% 55%, ${alpha(al.glow, 0.5 * artGlow)} 0%, ${alpha(al.glow, 0)} 70%)`,
204
- }} />
205
- )}
206
- <div style={{
207
- position: 'absolute', left: x, top: ROW1_Y, width: TILE, height: TILE, borderRadius: 18, overflow: 'hidden',
208
- boxShadow: th.dark ? 'inset 0 0 0 1px rgba(255,255,255,0.08), 0 20px 40px -18px rgba(0,0,0,0.9)' : '0 1px 2px rgba(15,20,30,0.08), 0 18px 36px -18px rgba(15,20,30,0.35)',
209
- }}>
210
- <al.Art />
211
- </div>
212
- <div style={{ position: 'absolute', left: x, top: ROW1_Y + TILE + 22, fontSize: 30, fontWeight: 650, letterSpacing: '-0.02em' }}>{al.t}</div>
213
- <div style={{ position: 'absolute', left: x, top: ROW1_Y + TILE + 62, fontSize: 25, color: th.ink2 }}>{al.a}</div>
214
- </React.Fragment>
215
- );
216
- })}
217
- {/* 第二排封面(被播放条截断,只做纵深) */}
218
- {ROW2.map((r, i) => (
219
- <div key={i} style={{
220
- position: 'absolute', left: MAIN_X + i * (TILE + TILE_GAP), top: ROW2_Y, width: TILE, height: TILE, borderRadius: 18, overflow: 'hidden',
221
- filter: `hue-rotate(${r.hue}deg) saturate(0.85)`,
222
- }}>
223
- <r.Art />
224
- </div>
225
- ))}
226
-
227
- {/* 正在播放条 */}
228
- <div style={{
229
- position: 'absolute', left: 0, right: 0, bottom: 0, height: BAR_H, background: th.bar, borderTop: `1px solid ${th.line}`,
230
- display: 'flex', alignItems: 'center', padding: '0 104px 0 104px', boxSizing: 'border-box',
231
- boxShadow: th.dark ? '0 -20px 40px rgba(0,0,0,0.5)' : '0 -16px 40px rgba(15,20,30,0.06)',
232
- }}>
233
- <div style={{ position: 'relative', width: 76, height: 76, borderRadius: 12, overflow: 'hidden', flex: 'none' }}><ArtGlassHarbor /></div>
234
- <div style={{ marginLeft: 22, width: 330 }}>
235
- <div style={{ fontSize: 28, fontWeight: 650, letterSpacing: '-0.02em' }}>Launch Film</div>
236
- <div style={{ fontSize: 23, color: th.ink2, marginTop: 4 }}>Preview · Shot 04</div>
237
- </div>
238
- <div style={{ display: 'flex', alignItems: 'center', gap: 34, marginLeft: 120 }}>
239
- <Ic d={I.prev} color={th.ink2} size={30} w={1.8} />
240
- <div style={{ width: 66, height: 66, borderRadius: 33, background: th.ink, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
241
- <svg width={26} height={26} viewBox="0 0 16 16"><rect x={4} y={3} width={2.6} height={10} rx={1} fill={th.bg} /><rect x={9.4} y={3} width={2.6} height={10} rx={1} fill={th.bg} /></svg>
242
- </div>
243
- <Ic d={I.next} color={th.ink2} size={30} w={1.8} />
244
- </div>
245
- <div style={{ marginLeft: 70, flex: 1, display: 'flex', alignItems: 'center', gap: 20, fontSize: 22, color: th.ink3, fontVariantNumeric: 'tabular-nums' }}>
246
- <span>{`0:${String(Math.floor(22 + frame / 30)).padStart(2, '0')}`}</span>
247
- <div style={{ position: 'relative', flex: 1, height: 6, borderRadius: 3, background: th.chip }}>
248
- <div style={{ position: 'absolute', left: 0, top: 0, bottom: 0, width: `${prog * 100}%`, borderRadius: 3, background: th.accent, boxShadow: th.dark ? `0 0 12px ${alpha(th.accent, 0.6)}` : 'none' }} />
249
- </div>
250
- <span style={{ marginRight: 4 }}>0:48</span>
251
- </div>
252
- </div>
253
- </div>
254
- );
255
- };
256
-
257
- const Kbd: React.FC<{ children: React.ReactNode; on?: number; press?: number }> = ({ children, on = 0, press = 0 }) => (
258
- <span style={{
259
- display: 'inline-flex', alignItems: 'center', justifyContent: 'center', minWidth: 40, height: 40, padding: '0 10px', boxSizing: 'border-box',
260
- borderRadius: 9, fontSize: 21, fontWeight: 600, color: on > 0.5 ? '#ffffff' : '#7a818d',
261
- background: on > 0.5 ? 'rgba(255,255,255,0.22)' : '#eef0f3',
262
- boxShadow: on > 0.5 ? `inset 0 ${-2 + press * 2}px 0 rgba(0,0,0,0.18)` : 'inset 0 -2px 0 rgba(15,20,30,0.08), inset 0 0 0 1px rgba(15,20,30,0.06)',
263
- transform: `translateY(${(press * 2).toFixed(2)}px)`,
264
- }}>{children}</span>
265
- );
266
-
267
- const RIPPLE_EASE = bezier(0.2, 0.55, 0.3, 1); // 强 ease-out:起步猛,边缘越走越缓(但圆形全程读得出)
268
-
269
- export const PaletteThemeRipple: React.FC = () => {
270
- const f = useCurrentFrame();
271
-
272
- // ── 背景压暗 / 虚化:面板在时生效,收缩时同步退去 ──
273
- const dim = ramp(f, DIM0, 8, EASE.out) * (1 - ramp(f, SQUASH, DOT - SQUASH, EASE.swift));
274
-
275
- // ── 面板:弹簧落下 → CRT 关机式收缩(先 Y 后 X)──
276
- const drop = f < PANEL_IN ? 0 : springAt(f, PANEL_IN, { damping: 17, stiffness: 190 });
277
- const sy = f < SQUASH ? 1 : mix(1, 0.012, ramp(f, SQUASH, LINE - SQUASH, EASE.exit));
278
- const sx = f < LINE ? 1 : mix(1, 0.008, ramp(f, LINE, DOT - LINE, EASE.exit));
279
- const collapsing = f >= SQUASH;
280
- const contentO = 1 - ramp(f, SQUASH, 3, EASE.linear); // 内容在压扁时先熄
281
- const glare = ramp(f, SQUASH, LINE - SQUASH, EASE.linear); // 压扁过程面板越来越白热
282
- const panelMounted = f >= PANEL_IN && f < DOT;
283
-
284
- // ── 输入 ──
285
- const typed = TYPE_FRAMES.filter((t) => f >= t).length;
286
- const charIn = (i: number) => ramp(f, TYPE_FRAMES[i], 4, EASE.snappy);
287
- const selT = ramp(f, TYPE_FRAMES[3], 5, EASE.out);
288
- const enterPress = ramp(f, ENTER, 2, EASE.linear) * (1 - ramp(f, ENTER + 2, 4, EASE.out));
289
- const caretOn = f < TYPE_FRAMES[3] + 2 ? true : Math.floor((f - TYPE_FRAMES[3]) / 8) % 2 === 1 ? false : true;
290
-
291
- // ── 亮点(钉在收缩点)──
292
- const dotOn = f >= LINE + 2 && f < RIPPLE + 4;
293
- const dotA = f < DOT ? ramp(f, LINE + 2, DOT - LINE - 2, EASE.linear) : 1 - ramp(f, RIPPLE, 4, EASE.linear);
294
- const dotPulse = 1 + 0.18 * Math.sin(Math.max(0, f - DOT) * 0.9) * (f >= DOT && f < RIPPLE ? 1 : 0);
295
-
296
- // ── 涟漪 ──
297
- const rAt = (fr: number, start: number) => mix(6, MAX_R, ramp(fr, start, RIPPLE_END - RIPPLE, RIPPLE_EASE));
298
- const r = rAt(f, RIPPLE);
299
- const r2 = rAt(f, RIPPLE + 4) * 0.96;
300
- const rippling = f >= RIPPLE && f < RIPPLE_END;
301
- const darkOn = f >= RIPPLE;
302
- const done = f >= RIPPLE_END;
303
- const ringO = 1 - ramp(f, RIPPLE + 6, RIPPLE_END - RIPPLE - 6, EASE.out);
304
- const darkScale = mix(1.035, 1, ramp(f, RIPPLE, 26, EASE.snappy));
305
- const artGlow = ramp(f, RIPPLE_END, 17, EASE.out);
306
-
307
- // ── 相机:打字时推向面板,涟漪时呼气退回,hold 极缓推 ──
308
- const push = ramp(f, PANEL_IN, ENTER - PANEL_IN, EASE.swift);
309
- const exhale = ramp(f, RIPPLE, 30, EASE.smooth);
310
- const holdPush = ramp(f, RIPPLE_END, PALETTE_THEME_RIPPLE_DURATION - RIPPLE_END, EASE.swift);
311
- const z = 1 + 0.03 * push * (1 - exhale) + 0.012 * holdPush;
312
-
313
- const rows = [
314
- { icon: I.moon, label: 'Switch to dark appearance', hint: '⇧⌘D' },
315
- { icon: I.half, label: 'Match system appearance', hint: 'Theme' },
316
- { icon: I.gear, label: 'Appearance settings…', hint: 'Settings' },
317
- ];
318
- const label0 = (txt: string) => {
319
- const at = txt.indexOf(QUERY);
320
- return (
321
- <>
322
- {txt.slice(0, at)}
323
- {QUERY.split('').map((c, i) => (
324
- <span key={i} style={{ fontWeight: i < typed ? 750 : 500, color: i < typed ? (selT > 0.5 ? '#ffffff' : '#0f1217') : undefined }}>{c}</span>
325
- ))}
326
- {txt.slice(at + QUERY.length)}
327
- </>
328
- );
329
- };
330
-
331
- const PW = 980;
332
- const PH = 420;
333
- const panelY = mix(-46, 0, drop);
334
- const panelS = mix(0.94, 1, drop);
335
-
336
- return (
337
- <AbsoluteFill style={{ background: DARK.bg, overflow: 'hidden' }}>
338
- <div style={{ position: 'absolute', inset: 0, transformOrigin: `${ORIGIN.x}px ${ORIGIN.y}px`, transform: `scale(${z.toFixed(4)})` }}>
339
- {/* 浅色层:涟漪荡完卸载 */}
340
- {!done && (
341
- <div style={{ position: 'absolute', inset: 0, filter: dim > 0.01 ? `blur(${(dim * 7).toFixed(2)}px) saturate(${(1 - 0.25 * dim).toFixed(3)})` : undefined }}>
342
- <App th={LIGHT} frame={f} artGlow={0} />
343
- <div style={{ position: 'absolute', inset: 0, opacity: dim, background: 'radial-gradient(ellipse 70% 70% at 50% 42%, rgba(18,22,32,0.30) 0%, rgba(12,14,22,0.55) 100%)' }} />
344
- </div>
345
- )}
346
-
347
- {/* 深色层:从收缩点被圆形 clip 揭开 */}
348
- {darkOn && (
349
- <div style={{ position: 'absolute', inset: 0, clipPath: done ? undefined : `circle(${r.toFixed(1)}px at ${ORIGIN.x}px ${ORIGIN.y}px)` }}>
350
- <div style={{ position: 'absolute', inset: 0, transformOrigin: `${ORIGIN.x}px ${ORIGIN.y}px`, transform: darkScale !== 1 ? `scale(${darkScale.toFixed(4)})` : undefined }}>
351
- <App th={DARK} frame={f} artGlow={artGlow} />
352
- </div>
353
- </div>
354
- )}
355
-
356
- {/* 涟漪环:白热 3px + 珊瑚外辉 + 内侧白辉;晚 4f 的回声环 */}
357
- {rippling && (
358
- <>
359
- <div style={{
360
- position: 'absolute', left: ORIGIN.x - r2, top: ORIGIN.y - r2, width: r2 * 2, height: r2 * 2, borderRadius: '50%', boxSizing: 'border-box',
361
- border: '1.5px solid rgba(255,190,170,0.5)', opacity: ringO * 0.6,
362
- }} />
363
- <div style={{
364
- position: 'absolute', left: ORIGIN.x - r, top: ORIGIN.y - r, width: r * 2, height: r * 2, borderRadius: '50%', boxSizing: 'border-box',
365
- border: '3px solid rgba(255,246,240,0.95)', opacity: ringO,
366
- boxShadow: `0 0 34px 6px ${alpha(DARK.accent, 0.55)}, 0 0 90px 20px ${alpha(DARK.accent, 0.22)}, inset 0 0 30px rgba(255,255,255,0.3)`,
367
- }} />
368
- </>
369
- )}
370
-
371
- {/* 亮点 */}
372
- {dotOn && (
373
- <>
374
- {/* 横向变形光斑:CRT 收线留下的余辉,随亮点一起衰减 */}
375
- <div style={{
376
- position: 'absolute', left: ORIGIN.x - 420, top: ORIGIN.y - 3, width: 840, height: 6, borderRadius: 3, opacity: dotA * 0.8,
377
- background: `linear-gradient(90deg, rgba(255,255,255,0) 0%, ${alpha(DARK.accent, 0.5)} 30%, rgba(255,250,245,0.95) 50%, ${alpha(DARK.accent, 0.5)} 70%, rgba(255,255,255,0) 100%)`,
378
- transform: `scaleX(${(0.4 + 0.6 * (1 - ramp(f, DOT, RIPPLE - DOT + 4, EASE.out))).toFixed(3)})`, filter: 'blur(1.5px)',
379
- }} />
380
- <div style={{
381
- position: 'absolute', left: ORIGIN.x - 13, top: ORIGIN.y - 13, width: 26, height: 26, borderRadius: 13, background: '#ffffff',
382
- opacity: dotA, transform: `scale(${dotPulse.toFixed(3)})`,
383
- boxShadow: `0 0 0 5px rgba(255,255,255,0.35), 0 0 36px 14px ${alpha(DARK.accent, 0.75)}, 0 0 120px 40px rgba(255,255,255,0.4)`,
384
- }} />
385
- </>
386
- )}
387
-
388
- {/* ⌘K 命令面板 */}
389
- {panelMounted && (
390
- <div style={{
391
- position: 'absolute', left: ORIGIN.x - PW / 2, top: ORIGIN.y - PH / 2 + (collapsing ? 0 : panelY), width: PW, height: PH,
392
- transformOrigin: '50% 50%', transform: `scale(${(collapsing ? sx : panelS).toFixed(4)}, ${(collapsing ? sy : panelS).toFixed(4)})`,
393
- opacity: ramp(f, PANEL_IN, 4, EASE.linear),
394
- borderRadius: collapsing ? 22 * Math.min(1, sy * 6) : 22, overflow: 'hidden',
395
- background: collapsing ? `rgba(${Math.round(mix(255, 255, glare))},${Math.round(mix(255, 250, glare))},${Math.round(mix(255, 246, glare))},1)` : 'linear-gradient(180deg, rgba(255,255,255,0.98), rgba(250,251,252,0.97))',
396
- boxShadow: collapsing
397
- ? `0 0 ${(30 + 60 * glare).toFixed(1)}px ${(6 + 10 * glare).toFixed(1)}px rgba(255,255,255,${(0.4 + 0.4 * glare).toFixed(3)}), 0 0 120px 20px ${alpha(DARK.accent, 0.35 * glare)}`
398
- : 'inset 0 1px 0 #ffffff, 0 0 0 1px rgba(15,20,30,0.08), 0 50px 100px -30px rgba(6,8,14,0.6), 0 18px 40px -12px rgba(6,8,14,0.35)',
399
- fontFamily: FONT.sans, color: '#0f1217',
400
- }}>
401
- <div style={{ opacity: contentO }}>
402
- {/* 输入行 */}
403
- <div style={{ height: 104, display: 'flex', alignItems: 'center', gap: 22, padding: '0 34px', borderBottom: '1px solid rgba(15,20,30,0.07)' }}>
404
- <Ic d={I.search} color="#9aa1ad" size={34} w={1.7} />
405
- <div style={{ display: 'flex', alignItems: 'center', fontSize: 46, fontWeight: 550, letterSpacing: '-0.025em' }}>
406
- {QUERY.split('').map((c, i) => (
407
- <span key={i} style={{
408
- display: f >= TYPE_FRAMES[i] ? 'inline-block' : 'none',
409
- opacity: charIn(i), transform: `translateY(${((1 - charIn(i)) * 10).toFixed(2)}px)`,
410
- }}>{c}</span>
411
- ))}
412
- <span style={{ width: 3, height: 50, marginLeft: 3, borderRadius: 2, background: LIGHT.accent, opacity: caretOn ? 1 : 0 }} />
413
- {typed === 0 && <span style={{ color: '#a7adb8', marginLeft: 10, fontWeight: 450 }}>Search commands…</span>}
414
- </div>
415
- <span style={{ marginLeft: 'auto' }}><Kbd>esc</Kbd></span>
416
- </div>
417
- {/* 结果 */}
418
- <div style={{ padding: '14px 16px', display: 'flex', flexDirection: 'column', gap: 6 }}>
419
- {rows.map((row, i) => {
420
- const on = i === 0 ? selT : 0;
421
- const dimRow = i === 0 ? 0 : 0.4 * Math.min(1, typed / 4);
422
- return (
423
- <div key={i} style={{
424
- position: 'relative', height: 82, borderRadius: 16, display: 'flex', alignItems: 'center', gap: 22, padding: '0 20px',
425
- background: on > 0 ? `rgba(242,72,58,${(on * (0.94 + 0.06 * enterPress)).toFixed(3)})` : 'transparent',
426
- boxShadow: on > 0.5 ? `0 10px 24px -10px ${alpha(LIGHT.accent, 0.7)}${enterPress > 0 ? `, 0 0 0 ${(4 * enterPress).toFixed(1)}px ${alpha(LIGHT.accent, 0.25)}` : ''}` : 'none',
427
- color: on > 0.5 ? '#ffffff' : '#262b33', opacity: 1 - dimRow, fontSize: 32, fontWeight: 520, letterSpacing: '-0.015em',
428
- }}>
429
- <div style={{
430
- width: 50, height: 50, borderRadius: 13, display: 'flex', alignItems: 'center', justifyContent: 'center', flex: 'none',
431
- background: on > 0.5 ? 'rgba(255,255,255,0.2)' : '#eef0f3',
432
- }}>
433
- <Ic d={row.icon} color={on > 0.5 ? '#ffffff' : '#5a616e'} size={28} w={1.7} />
434
- </div>
435
- <span>{i === 0 ? label0(row.label) : row.label}</span>
436
- <span style={{ marginLeft: 'auto', display: 'flex', gap: 8, alignItems: 'center' }}>
437
- {i === 0
438
- ? <><Kbd on={on}>⇧⌘D</Kbd><Kbd on={on} press={enterPress}>↵</Kbd></>
439
- : <span style={{ fontSize: 23, color: '#9aa1ad' }}>{row.hint}</span>}
440
- </span>
441
- </div>
442
- );
443
- })}
444
- </div>
445
- {/* 页脚提示 */}
446
- <div style={{ position: 'absolute', left: 0, right: 0, bottom: 0, height: 52, borderTop: '1px solid rgba(15,20,30,0.06)', background: '#f7f8f9', display: 'flex', alignItems: 'center', padding: '0 34px', gap: 26, fontSize: 21, color: '#9aa1ad' }}>
447
- <span>↑↓ Navigate</span><span>↵ Run</span><span style={{ marginLeft: 'auto' }}>Shotcraft Commands</span>
448
- </div>
449
- </div>
450
- </div>
451
- )}
452
- </div>
453
- <Vignette strength={mix(0.12, 0.42, ramp(f, RIPPLE, 24, EASE.out))} color="#06080c" inner={0.5} />
454
- <Grain opacity={0.05} blend="overlay" />
455
- </AbsoluteFill>
456
- );
457
- };
1
+ // 组合:命令面板 × 深浅涟漪(palette-theme-ripple)——第二轮重设计:video-shotcraft 样片画廊 · 关灯
2
+ //
3
+ // 设计决定:
4
+ // - 主体:满屏的 video-shotcraft 样片画廊(品牌轮由虚构音乐库 Overtone 换来,版式逐像素不变)——
5
+ // 112px「Gallery」大标题、5 张 259px 程序化镜头缩略图(同一批缩略图在深浅两版里完全不变,只换 UI 外壳——
6
+ // 真实产品的深色模式就是这样)、底部正在预览的样片播放条。侧栏标志 = 「镜刻」ShotcraftMark(随主题换反白版)。
7
+ // - look = custom:浅版冷瓷灰白 + 珊瑚红强调;深版近黑石墨 + 同色相更亮的珊瑚。强调色只给选中态 / 播放进度 / 涟漪。
8
+ // - 因果链(组合命门):⌘K 面板落下 → 人手节奏打 "dark"(不等间隔)→ 回车 → 面板像老电视关机一样
9
+ // 先纵向压成一条亮线、再横向收成一个亮点 → 亮点在原地钉 5f → 深色涟漪**从这个点**荡开换肤。
10
+ // 收缩点 = 面板中心 = 涟漪圆心 ORIGIN;收缩完成帧 = 亮点帧,亮点结束帧 = 涟漪起始帧 RIPPLE。
11
+ // - 涟漪:3px 白热环 + 珊瑚外辉 + 内侧白辉,外加一道晚 4f 的淡回声环;深版从圆心 1.035→1 收拢"坐实"。
12
+ // 深版落定后专辑封面在暗场里各自投下一圈同色辉光(只有深色模式才看得见的光)。
13
+ // - 相机:打字时极缓推向面板(1→1.03),涟漪荡开时顺势呼一口气退回 1,hold 段再 1→1.012 极缓推。
14
+ //
15
+ // 时间表(30fps,共 156f):
16
+ // 0–10 静置:浅色样片画廊(播放进度在走,画面不死)
17
+ // 10–18 压暗 + 虚化背景(8f EASE.out);12 面板弹簧落下(damping 17,一次轻过冲)
18
+ // 24–37 打字 d·a·r·k(24/28/31/37,人手不等间隔);匹配字母逐个加粗,37 首行进入选中态
19
+ // 46 回车:首行闪一下、↵ 键帽按下
20
+ // 48–56 CRT 关机式收缩:48–52 纵向压成亮线(ease-in),52–56 横向收成亮点;背景同步去虚化
21
+ // 56–61 亮点钉在 ORIGIN(因果钉扎)
22
+ // 61–95 深色涟漪荡开(34f,强 ease-out:起步猛、边缘越走越缓)+ 回声环;相机 1.03→1
23
+ // 95–156 hold:深色定格,封面辉光亮起(95–112),进度条继续走,相机 1→1.012
24
+ import React from 'react';
25
+ import { AbsoluteFill, useCurrentFrame } from 'remotion';
26
+ import { EASE, FONT, Grain, Vignette, bezier, mix, ramp } from '../../_fixtures/Polish';
27
+ import { alpha, springAt } from '../../_fixtures/Look';
28
+ import { BRAND, ShotcraftMark } from '../../_fixtures/Brand';
29
+
30
+ export const PALETTE_THEME_RIPPLE_DURATION = 156;
31
+
32
+ // ───────────── 时间轴 ─────────────
33
+ const DIM0 = 10;
34
+ const PANEL_IN = 12;
35
+ const TYPE_FRAMES = [24, 28, 31, 37]; // d a r k —— 人手节奏:起手快、r→k 犹豫一下
36
+ const ENTER = 46;
37
+ const SQUASH = 48; // 纵向压线开始
38
+ const LINE = 52; // 压成线 → 开始横向收点
39
+ const DOT = 56; // 收成点(= 亮点帧)
40
+ const RIPPLE = 61; // 亮点钉 5f 后涟漪起跳(组合命门:圆心 = 收缩点)
41
+ const RIPPLE_END = 95;
42
+ const ORIGIN = { x: 960, y: 452 }; // 面板中心 = 收缩点 = 涟漪圆心
43
+ const MAX_R = 1260; // 圆心到最远角 ≈1150px,留出相机推进余量
44
+
45
+ const QUERY = 'dark';
46
+
47
+ // ───────────── 两套外壳(同布局,逐键映射)─────────────
48
+ type Theme = {
49
+ dark: boolean; bg: string; side: string; surface: string; chip: string; line: string;
50
+ ink: string; ink2: string; ink3: string; accent: string; bar: string;
51
+ };
52
+ const LIGHT: Theme = {
53
+ dark: false, bg: '#f1f2f4', side: '#e8eaed', surface: '#ffffff', chip: '#e3e6ea', line: 'rgba(15,20,30,0.08)',
54
+ ink: '#0f1217', ink2: '#5a616e', ink3: '#9aa1ad', accent: '#f2483a', bar: 'rgba(248,249,250,0.92)',
55
+ };
56
+ const DARK: Theme = {
57
+ dark: true, bg: '#0b0d10', side: '#08090b', surface: '#15181c', chip: '#1b1f24', line: 'rgba(255,255,255,0.07)',
58
+ ink: '#f3f4f6', ink2: '#939aa7', ink3: '#59606c', accent: '#ff5f48', bar: 'rgba(16,18,22,0.94)',
59
+ };
60
+
61
+ // ───────────── 程序化镜头缩略图(深浅两版共用,不随主题变)─────────────
62
+ type Album = { t: string; a: string; glow: string; Art: React.FC };
63
+ const ArtLowTide: React.FC = () => (
64
+ <div style={{ position: 'absolute', inset: 0, background: 'linear-gradient(180deg, #0f2747 0%, #1d5f74 58%, #e7a874 100%)' }}>
65
+ <div style={{ position: 'absolute', left: '30%', top: '30%', width: '40%', height: '40%', borderRadius: '50%', background: 'radial-gradient(circle at 50% 40%, #ffe6bd, #f7b57a)', boxShadow: '0 0 40px rgba(255,200,140,0.6)' }} />
66
+ <div style={{ position: 'absolute', left: 0, right: 0, top: '62%', bottom: 0, background: 'repeating-linear-gradient(180deg, rgba(10,30,55,0.92) 0px, rgba(10,30,55,0.92) 7px, rgba(255,200,150,0.35) 7px, rgba(255,200,150,0.35) 9px)' }} />
67
+ </div>
68
+ );
69
+ const ArtPaperMoons: React.FC = () => (
70
+ <div style={{ position: 'absolute', inset: 0, background: '#f1d8c2' }}>
71
+ <div style={{ position: 'absolute', left: '12%', top: '18%', width: '52%', height: '52%', borderRadius: '50%', background: '#e46a4e' }} />
72
+ <div style={{ position: 'absolute', left: '36%', top: '34%', width: '52%', height: '52%', borderRadius: '50%', background: '#253a63', mixBlendMode: 'multiply' }} />
73
+ <div style={{ position: 'absolute', left: '58%', top: '12%', width: '22%', height: '22%', borderRadius: '50%', background: '#f4b23e' }} />
74
+ </div>
75
+ );
76
+ const ArtNeonOrchard: React.FC = () => (
77
+ <div style={{ position: 'absolute', inset: 0, background: 'linear-gradient(150deg, #ff2f7d 0%, #ff8a3a 100%)', overflow: 'hidden' }}>
78
+ <svg viewBox="0 0 100 100" width="100%" height="100%" style={{ position: 'absolute', inset: 0 }}>
79
+ {Array.from({ length: 9 }, (_, i) => <line key={`h${i}`} x1={0} x2={100} y1={55 + i * i * 0.6} y2={55 + i * i * 0.6} stroke="rgba(255,255,255,0.45)" strokeWidth={0.5} />)}
80
+ {Array.from({ length: 11 }, (_, i) => <line key={`v${i}`} x1={50} y1={55} x2={-50 + i * 20} y2={100} stroke="rgba(255,255,255,0.45)" strokeWidth={0.5} />)}
81
+ <circle cx={50} cy={38} r={17} fill="#ffe14d" />
82
+ {[0, 1, 2, 3].map((i) => <rect key={i} x={30} y={40 + i * 4} width={40} height={1.6} fill="#ff4f6e" />)}
83
+ </svg>
84
+ </div>
85
+ );
86
+ const ArtStaticBloom: React.FC = () => (
87
+ <div style={{ position: 'absolute', inset: 0, background: 'radial-gradient(circle at 50% 50%, #2c5a3e, #142b1f)' }}>
88
+ <svg viewBox="0 0 100 100" width="100%" height="100%" style={{ position: 'absolute', inset: 0 }}>
89
+ {Array.from({ length: 8 }, (_, i) => {
90
+ const a = (i / 8) * Math.PI * 2;
91
+ return <circle key={i} cx={50 + Math.cos(a) * 17} cy={50 + Math.sin(a) * 17} r={13} fill="#9fe48c" opacity={0.85} style={{ mixBlendMode: 'screen' }} />;
92
+ })}
93
+ <circle cx={50} cy={50} r={9} fill="#f4f8cc" />
94
+ </svg>
95
+ </div>
96
+ );
97
+ const ArtNightSwim: React.FC = () => (
98
+ <div style={{ position: 'absolute', inset: 0, background: '#060a14', overflow: 'hidden' }}>
99
+ <div style={{ position: 'absolute', inset: '-20%', transform: 'rotate(-28deg)', background: 'repeating-linear-gradient(90deg, rgba(70,120,255,0.0) 0px, rgba(70,120,255,0.0) 16px, rgba(70,140,255,0.75) 16px, rgba(70,140,255,0.75) 22px)' }} />
100
+ <div style={{ position: 'absolute', right: '16%', top: '14%', width: '16%', height: '16%', borderRadius: '50%', background: '#eef3ff', boxShadow: '0 0 24px rgba(220,230,255,0.8)' }} />
101
+ </div>
102
+ );
103
+ const ArtGlassHarbor: React.FC = () => (
104
+ <div style={{ position: 'absolute', inset: 0, background: 'linear-gradient(160deg, #19c3b4 0%, #2a3d9e 100%)' }}>
105
+ <svg viewBox="0 0 100 100" width="100%" height="100%" style={{ position: 'absolute', inset: 0 }}>
106
+ {[14, 24, 34, 44].map((r) => <circle key={r} cx={30} cy={70} r={r} fill="none" stroke="rgba(255,255,255,0.4)" strokeWidth={1.2} />)}
107
+ </svg>
108
+ </div>
109
+ );
110
+
111
+ const ALBUMS: Album[] = [
112
+ { t: 'Horizon Push', a: 'Camera · 2.5D', glow: '#f2a46e', Art: ArtLowTide },
113
+ { t: 'Ink Press', a: 'Opening', glow: '#e46a4e', Art: ArtPaperMoons },
114
+ { t: 'Neon Marquee', a: 'Outro', glow: '#ff5a6a', Art: ArtNeonOrchard },
115
+ { t: 'Glow Bloom', a: 'Effects', glow: '#7ed67a', Art: ArtStaticBloom },
116
+ { t: 'Whip Pan', a: 'Transition', glow: '#5c8cff', Art: ArtNightSwim },
117
+ ];
118
+ const ROW2: { Art: React.FC; hue: number }[] = [
119
+ { Art: ArtNightSwim, hue: 140 }, { Art: ArtStaticBloom, hue: -60 }, { Art: ArtLowTide, hue: 40 }, { Art: ArtNeonOrchard, hue: 160 }, { Art: ArtPaperMoons, hue: 180 },
120
+ ];
121
+
122
+ // ───────────── 布局 ─────────────
123
+ const SIDE_W = 350;
124
+ const MAIN_X = 430;
125
+ const MAIN_W = 1920 - MAIN_X - 112;
126
+ const TILE_GAP = 36;
127
+ const TILE = (MAIN_W - TILE_GAP * 4) / 5;
128
+ const ROW1_Y = 300;
129
+ const ROW2_Y = ROW1_Y + TILE + 130;
130
+ const BAR_H = 124;
131
+
132
+ // 16 网格线性图标
133
+ const Ic: React.FC<{ d: string[]; color: string; size?: number; w?: number }> = ({ d, color, size = 28, w = 1.6 }) => (
134
+ <svg width={size} height={size} viewBox="0 0 16 16" fill="none" style={{ display: 'block', flex: 'none' }}>
135
+ {d.map((p, i) => <path key={i} d={p} stroke={color} strokeWidth={w} strokeLinecap="round" strokeLinejoin="round" />)}
136
+ </svg>
137
+ );
138
+ const I = {
139
+ play: ['M5 3.5v9l7-4.5z'],
140
+ grid: ['M2.5 2.5h4.5v4.5h-4.5z', 'M9 2.5h4.5v4.5h-4.5z', 'M2.5 9h4.5v4.5h-4.5z', 'M9 9h4.5v4.5h-4.5z'],
141
+ radio: ['M8 9.5a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3z', 'M4.8 4.8a4.5 4.5 0 0 0 0 6.4', 'M11.2 4.8a4.5 4.5 0 0 1 0 6.4'],
142
+ lib: ['M3 2.5v11', 'M6 2.5v11', 'M9 3l3.5 10'],
143
+ sliders: ['M2.5 4.5h11', 'M2.5 11.5h11', 'M5.5 2.5v4', 'M10.5 9.5v4'],
144
+ list: ['M2.5 4h11', 'M2.5 8h11', 'M2.5 12h7'],
145
+ moon: ['M13 9.6A5.5 5.5 0 1 1 6.4 3a4.4 4.4 0 0 0 6.6 6.6z'],
146
+ half: ['M8 2.5a5.5 5.5 0 1 0 0 11 5.5 5.5 0 0 0 0-11z', 'M8 2.5v11'],
147
+ gear: ['M8 10a2 2 0 1 0 0-4 2 2 0 0 0 0 4z', 'M8 1.8v1.6M8 12.6v1.6M1.8 8h1.6M12.6 8h1.6M3.6 3.6l1.1 1.1M11.3 11.3l1.1 1.1M3.6 12.4l1.1-1.1M11.3 4.7l1.1-1.1'],
148
+ search: ['M7 11.5a4.5 4.5 0 1 0 0-9 4.5 4.5 0 0 0 0 9z', 'm10.5 10.5 3 3'],
149
+ prev: ['M4 3.5v9', 'M12.5 3.5v9l-6.5-4.5z'],
150
+ next: ['M12 3.5v9', 'M3.5 3.5v9l6.5-4.5z'],
151
+ };
152
+
153
+ // ───────────── 整个 App(两版主题共用这一份布局)─────────────
154
+ const App: React.FC<{ th: Theme; frame: number; artGlow: number }> = ({ th, frame, artGlow }) => {
155
+ const prog = 0.34 + frame * 0.0009; // 播放进度一直在走
156
+ return (
157
+ <div style={{ position: 'absolute', inset: 0, background: th.bg, fontFamily: FONT.sans, color: th.ink, overflow: 'hidden' }}>
158
+ {/* 侧栏 */}
159
+ <div style={{ position: 'absolute', left: 0, top: 0, bottom: 0, width: SIDE_W, background: th.side, borderRight: `1px solid ${th.line}`, padding: '64px 0 0 104px', boxSizing: 'border-box' }}>
160
+ <div style={{ display: 'flex', alignItems: 'center', gap: 14, marginBottom: 64 }}>
161
+ {/* 「镜刻」标志:亮版墨框 / 深版反白框,琥珀斜切不变(标志本身不加底块与渐变) */}
162
+ <ShotcraftMark size={44} tone={th.dark ? 'dark' : 'light'} />
163
+ <span style={{ fontFamily: BRAND.font, fontSize: 34, fontWeight: 700, letterSpacing: '0.01em' }}>{BRAND.short}</span>
164
+ </div>
165
+ {[
166
+ { l: 'Home', i: I.play },
167
+ { l: 'Shot cards', i: I.grid },
168
+ { l: 'Workbench', i: I.sliders },
169
+ { l: 'Gallery', i: I.lib, on: true },
170
+ { l: 'Renders', i: I.list },
171
+ ].map((n) => (
172
+ <div key={n.l} style={{
173
+ display: 'flex', alignItems: 'center', gap: 18, height: 64, marginLeft: -18, marginRight: 34, paddingLeft: 18, borderRadius: 14,
174
+ background: n.on ? (th.dark ? 'rgba(255,255,255,0.06)' : 'rgba(15,20,30,0.06)') : 'transparent',
175
+ color: n.on ? th.ink : th.ink2, fontSize: 28, fontWeight: n.on ? 650 : 500,
176
+ }}>
177
+ <Ic d={n.i} color={n.on ? th.accent : th.ink3} />
178
+ {n.l}
179
+ </div>
180
+ ))}
181
+ </div>
182
+
183
+ {/* 标题区 */}
184
+ <div style={{ position: 'absolute', left: MAIN_X, top: 70, fontSize: 112, fontWeight: 800, letterSpacing: '-0.045em', lineHeight: 1 }}>Gallery</div>
185
+ <div style={{ position: 'absolute', left: MAIN_X, top: 208, display: 'flex', gap: 12 }}>
186
+ {['All shots', 'Camera', 'Outro', 'Made for you'].map((c, i) => (
187
+ <div key={c} style={{
188
+ padding: '10px 24px', borderRadius: 999, fontSize: 26, fontWeight: i === 0 ? 650 : 500,
189
+ background: i === 0 ? th.ink : th.chip, color: i === 0 ? th.bg : th.ink2,
190
+ }}>{c}</div>
191
+ ))}
192
+ </div>
193
+ <div style={{ position: 'absolute', right: 112, top: 222, fontSize: 26, color: th.ink3, fontWeight: 500 }}>1080p · 30fps · sorted by recent</div>
194
+
195
+ {/* 第一排封面 */}
196
+ {ALBUMS.map((al, i) => {
197
+ const x = MAIN_X + i * (TILE + TILE_GAP);
198
+ return (
199
+ <React.Fragment key={al.t}>
200
+ {th.dark && (
201
+ <div style={{
202
+ position: 'absolute', left: x - 90, top: ROW1_Y - 30, width: TILE + 180, height: TILE + 170,
203
+ background: `radial-gradient(ellipse 50% 50% at 50% 55%, ${alpha(al.glow, 0.5 * artGlow)} 0%, ${alpha(al.glow, 0)} 70%)`,
204
+ }} />
205
+ )}
206
+ <div style={{
207
+ position: 'absolute', left: x, top: ROW1_Y, width: TILE, height: TILE, borderRadius: 18, overflow: 'hidden',
208
+ boxShadow: th.dark ? 'inset 0 0 0 1px rgba(255,255,255,0.08), 0 20px 40px -18px rgba(0,0,0,0.9)' : '0 1px 2px rgba(15,20,30,0.08), 0 18px 36px -18px rgba(15,20,30,0.35)',
209
+ }}>
210
+ <al.Art />
211
+ </div>
212
+ <div style={{ position: 'absolute', left: x, top: ROW1_Y + TILE + 22, fontSize: 30, fontWeight: 650, letterSpacing: '-0.02em' }}>{al.t}</div>
213
+ <div style={{ position: 'absolute', left: x, top: ROW1_Y + TILE + 62, fontSize: 25, color: th.ink2 }}>{al.a}</div>
214
+ </React.Fragment>
215
+ );
216
+ })}
217
+ {/* 第二排封面(被播放条截断,只做纵深) */}
218
+ {ROW2.map((r, i) => (
219
+ <div key={i} style={{
220
+ position: 'absolute', left: MAIN_X + i * (TILE + TILE_GAP), top: ROW2_Y, width: TILE, height: TILE, borderRadius: 18, overflow: 'hidden',
221
+ filter: `hue-rotate(${r.hue}deg) saturate(0.85)`,
222
+ }}>
223
+ <r.Art />
224
+ </div>
225
+ ))}
226
+
227
+ {/* 正在播放条 */}
228
+ <div style={{
229
+ position: 'absolute', left: 0, right: 0, bottom: 0, height: BAR_H, background: th.bar, borderTop: `1px solid ${th.line}`,
230
+ display: 'flex', alignItems: 'center', padding: '0 104px 0 104px', boxSizing: 'border-box',
231
+ boxShadow: th.dark ? '0 -20px 40px rgba(0,0,0,0.5)' : '0 -16px 40px rgba(15,20,30,0.06)',
232
+ }}>
233
+ <div style={{ position: 'relative', width: 76, height: 76, borderRadius: 12, overflow: 'hidden', flex: 'none' }}><ArtGlassHarbor /></div>
234
+ <div style={{ marginLeft: 22, width: 330 }}>
235
+ <div style={{ fontSize: 28, fontWeight: 650, letterSpacing: '-0.02em' }}>Launch Film</div>
236
+ <div style={{ fontSize: 23, color: th.ink2, marginTop: 4 }}>Preview · Shot 04</div>
237
+ </div>
238
+ <div style={{ display: 'flex', alignItems: 'center', gap: 34, marginLeft: 120 }}>
239
+ <Ic d={I.prev} color={th.ink2} size={30} w={1.8} />
240
+ <div style={{ width: 66, height: 66, borderRadius: 33, background: th.ink, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
241
+ <svg width={26} height={26} viewBox="0 0 16 16"><rect x={4} y={3} width={2.6} height={10} rx={1} fill={th.bg} /><rect x={9.4} y={3} width={2.6} height={10} rx={1} fill={th.bg} /></svg>
242
+ </div>
243
+ <Ic d={I.next} color={th.ink2} size={30} w={1.8} />
244
+ </div>
245
+ <div style={{ marginLeft: 70, flex: 1, display: 'flex', alignItems: 'center', gap: 20, fontSize: 22, color: th.ink3, fontVariantNumeric: 'tabular-nums' }}>
246
+ <span>{`0:${String(Math.floor(22 + frame / 30)).padStart(2, '0')}`}</span>
247
+ <div style={{ position: 'relative', flex: 1, height: 6, borderRadius: 3, background: th.chip }}>
248
+ <div style={{ position: 'absolute', left: 0, top: 0, bottom: 0, width: `${prog * 100}%`, borderRadius: 3, background: th.accent, boxShadow: th.dark ? `0 0 12px ${alpha(th.accent, 0.6)}` : 'none' }} />
249
+ </div>
250
+ <span style={{ marginRight: 4 }}>0:48</span>
251
+ </div>
252
+ </div>
253
+ </div>
254
+ );
255
+ };
256
+
257
+ const Kbd: React.FC<{ children: React.ReactNode; on?: number; press?: number }> = ({ children, on = 0, press = 0 }) => (
258
+ <span style={{
259
+ display: 'inline-flex', alignItems: 'center', justifyContent: 'center', minWidth: 40, height: 40, padding: '0 10px', boxSizing: 'border-box',
260
+ borderRadius: 9, fontSize: 21, fontWeight: 600, color: on > 0.5 ? '#ffffff' : '#7a818d',
261
+ background: on > 0.5 ? 'rgba(255,255,255,0.22)' : '#eef0f3',
262
+ boxShadow: on > 0.5 ? `inset 0 ${-2 + press * 2}px 0 rgba(0,0,0,0.18)` : 'inset 0 -2px 0 rgba(15,20,30,0.08), inset 0 0 0 1px rgba(15,20,30,0.06)',
263
+ transform: `translateY(${(press * 2).toFixed(2)}px)`,
264
+ }}>{children}</span>
265
+ );
266
+
267
+ const RIPPLE_EASE = bezier(0.2, 0.55, 0.3, 1); // 强 ease-out:起步猛,边缘越走越缓(但圆形全程读得出)
268
+
269
+ export const PaletteThemeRipple: React.FC = () => {
270
+ const f = useCurrentFrame();
271
+
272
+ // ── 背景压暗 / 虚化:面板在时生效,收缩时同步退去 ──
273
+ const dim = ramp(f, DIM0, 8, EASE.out) * (1 - ramp(f, SQUASH, DOT - SQUASH, EASE.swift));
274
+
275
+ // ── 面板:弹簧落下 → CRT 关机式收缩(先 Y 后 X)──
276
+ const drop = f < PANEL_IN ? 0 : springAt(f, PANEL_IN, { damping: 17, stiffness: 190 });
277
+ const sy = f < SQUASH ? 1 : mix(1, 0.012, ramp(f, SQUASH, LINE - SQUASH, EASE.exit));
278
+ const sx = f < LINE ? 1 : mix(1, 0.008, ramp(f, LINE, DOT - LINE, EASE.exit));
279
+ const collapsing = f >= SQUASH;
280
+ const contentO = 1 - ramp(f, SQUASH, 3, EASE.linear); // 内容在压扁时先熄
281
+ const glare = ramp(f, SQUASH, LINE - SQUASH, EASE.linear); // 压扁过程面板越来越白热
282
+ const panelMounted = f >= PANEL_IN && f < DOT;
283
+
284
+ // ── 输入 ──
285
+ const typed = TYPE_FRAMES.filter((t) => f >= t).length;
286
+ const charIn = (i: number) => ramp(f, TYPE_FRAMES[i], 4, EASE.snappy);
287
+ const selT = ramp(f, TYPE_FRAMES[3], 5, EASE.out);
288
+ const enterPress = ramp(f, ENTER, 2, EASE.linear) * (1 - ramp(f, ENTER + 2, 4, EASE.out));
289
+ const caretOn = f < TYPE_FRAMES[3] + 2 ? true : Math.floor((f - TYPE_FRAMES[3]) / 8) % 2 === 1 ? false : true;
290
+
291
+ // ── 亮点(钉在收缩点)──
292
+ const dotOn = f >= LINE + 2 && f < RIPPLE + 4;
293
+ const dotA = f < DOT ? ramp(f, LINE + 2, DOT - LINE - 2, EASE.linear) : 1 - ramp(f, RIPPLE, 4, EASE.linear);
294
+ const dotPulse = 1 + 0.18 * Math.sin(Math.max(0, f - DOT) * 0.9) * (f >= DOT && f < RIPPLE ? 1 : 0);
295
+
296
+ // ── 涟漪 ──
297
+ const rAt = (fr: number, start: number) => mix(6, MAX_R, ramp(fr, start, RIPPLE_END - RIPPLE, RIPPLE_EASE));
298
+ const r = rAt(f, RIPPLE);
299
+ const r2 = rAt(f, RIPPLE + 4) * 0.96;
300
+ const rippling = f >= RIPPLE && f < RIPPLE_END;
301
+ const darkOn = f >= RIPPLE;
302
+ const done = f >= RIPPLE_END;
303
+ const ringO = 1 - ramp(f, RIPPLE + 6, RIPPLE_END - RIPPLE - 6, EASE.out);
304
+ const darkScale = mix(1.035, 1, ramp(f, RIPPLE, 26, EASE.snappy));
305
+ const artGlow = ramp(f, RIPPLE_END, 17, EASE.out);
306
+
307
+ // ── 相机:打字时推向面板,涟漪时呼气退回,hold 极缓推 ──
308
+ const push = ramp(f, PANEL_IN, ENTER - PANEL_IN, EASE.swift);
309
+ const exhale = ramp(f, RIPPLE, 30, EASE.smooth);
310
+ const holdPush = ramp(f, RIPPLE_END, PALETTE_THEME_RIPPLE_DURATION - RIPPLE_END, EASE.swift);
311
+ const z = 1 + 0.03 * push * (1 - exhale) + 0.012 * holdPush;
312
+
313
+ const rows = [
314
+ { icon: I.moon, label: 'Switch to dark appearance', hint: '⇧⌘D' },
315
+ { icon: I.half, label: 'Match system appearance', hint: 'Theme' },
316
+ { icon: I.gear, label: 'Appearance settings…', hint: 'Settings' },
317
+ ];
318
+ const label0 = (txt: string) => {
319
+ const at = txt.indexOf(QUERY);
320
+ return (
321
+ <>
322
+ {txt.slice(0, at)}
323
+ {QUERY.split('').map((c, i) => (
324
+ <span key={i} style={{ fontWeight: i < typed ? 750 : 500, color: i < typed ? (selT > 0.5 ? '#ffffff' : '#0f1217') : undefined }}>{c}</span>
325
+ ))}
326
+ {txt.slice(at + QUERY.length)}
327
+ </>
328
+ );
329
+ };
330
+
331
+ const PW = 980;
332
+ const PH = 420;
333
+ const panelY = mix(-46, 0, drop);
334
+ const panelS = mix(0.94, 1, drop);
335
+
336
+ return (
337
+ <AbsoluteFill style={{ background: DARK.bg, overflow: 'hidden' }}>
338
+ <div style={{ position: 'absolute', inset: 0, transformOrigin: `${ORIGIN.x}px ${ORIGIN.y}px`, transform: `scale(${z.toFixed(4)})` }}>
339
+ {/* 浅色层:涟漪荡完卸载 */}
340
+ {!done && (
341
+ <div style={{ position: 'absolute', inset: 0, filter: dim > 0.01 ? `blur(${(dim * 7).toFixed(2)}px) saturate(${(1 - 0.25 * dim).toFixed(3)})` : undefined }}>
342
+ <App th={LIGHT} frame={f} artGlow={0} />
343
+ <div style={{ position: 'absolute', inset: 0, opacity: dim, background: 'radial-gradient(ellipse 70% 70% at 50% 42%, rgba(18,22,32,0.30) 0%, rgba(12,14,22,0.55) 100%)' }} />
344
+ </div>
345
+ )}
346
+
347
+ {/* 深色层:从收缩点被圆形 clip 揭开 */}
348
+ {darkOn && (
349
+ <div style={{ position: 'absolute', inset: 0, clipPath: done ? undefined : `circle(${r.toFixed(1)}px at ${ORIGIN.x}px ${ORIGIN.y}px)` }}>
350
+ <div style={{ position: 'absolute', inset: 0, transformOrigin: `${ORIGIN.x}px ${ORIGIN.y}px`, transform: darkScale !== 1 ? `scale(${darkScale.toFixed(4)})` : undefined }}>
351
+ <App th={DARK} frame={f} artGlow={artGlow} />
352
+ </div>
353
+ </div>
354
+ )}
355
+
356
+ {/* 涟漪环:白热 3px + 珊瑚外辉 + 内侧白辉;晚 4f 的回声环 */}
357
+ {rippling && (
358
+ <>
359
+ <div style={{
360
+ position: 'absolute', left: ORIGIN.x - r2, top: ORIGIN.y - r2, width: r2 * 2, height: r2 * 2, borderRadius: '50%', boxSizing: 'border-box',
361
+ border: '1.5px solid rgba(255,190,170,0.5)', opacity: ringO * 0.6,
362
+ }} />
363
+ <div style={{
364
+ position: 'absolute', left: ORIGIN.x - r, top: ORIGIN.y - r, width: r * 2, height: r * 2, borderRadius: '50%', boxSizing: 'border-box',
365
+ border: '3px solid rgba(255,246,240,0.95)', opacity: ringO,
366
+ boxShadow: `0 0 34px 6px ${alpha(DARK.accent, 0.55)}, 0 0 90px 20px ${alpha(DARK.accent, 0.22)}, inset 0 0 30px rgba(255,255,255,0.3)`,
367
+ }} />
368
+ </>
369
+ )}
370
+
371
+ {/* 亮点 */}
372
+ {dotOn && (
373
+ <>
374
+ {/* 横向变形光斑:CRT 收线留下的余辉,随亮点一起衰减 */}
375
+ <div style={{
376
+ position: 'absolute', left: ORIGIN.x - 420, top: ORIGIN.y - 3, width: 840, height: 6, borderRadius: 3, opacity: dotA * 0.8,
377
+ background: `linear-gradient(90deg, rgba(255,255,255,0) 0%, ${alpha(DARK.accent, 0.5)} 30%, rgba(255,250,245,0.95) 50%, ${alpha(DARK.accent, 0.5)} 70%, rgba(255,255,255,0) 100%)`,
378
+ transform: `scaleX(${(0.4 + 0.6 * (1 - ramp(f, DOT, RIPPLE - DOT + 4, EASE.out))).toFixed(3)})`, filter: 'blur(1.5px)',
379
+ }} />
380
+ <div style={{
381
+ position: 'absolute', left: ORIGIN.x - 13, top: ORIGIN.y - 13, width: 26, height: 26, borderRadius: 13, background: '#ffffff',
382
+ opacity: dotA, transform: `scale(${dotPulse.toFixed(3)})`,
383
+ boxShadow: `0 0 0 5px rgba(255,255,255,0.35), 0 0 36px 14px ${alpha(DARK.accent, 0.75)}, 0 0 120px 40px rgba(255,255,255,0.4)`,
384
+ }} />
385
+ </>
386
+ )}
387
+
388
+ {/* ⌘K 命令面板 */}
389
+ {panelMounted && (
390
+ <div style={{
391
+ position: 'absolute', left: ORIGIN.x - PW / 2, top: ORIGIN.y - PH / 2 + (collapsing ? 0 : panelY), width: PW, height: PH,
392
+ transformOrigin: '50% 50%', transform: `scale(${(collapsing ? sx : panelS).toFixed(4)}, ${(collapsing ? sy : panelS).toFixed(4)})`,
393
+ opacity: ramp(f, PANEL_IN, 4, EASE.linear),
394
+ borderRadius: collapsing ? 22 * Math.min(1, sy * 6) : 22, overflow: 'hidden',
395
+ background: collapsing ? `rgba(${Math.round(mix(255, 255, glare))},${Math.round(mix(255, 250, glare))},${Math.round(mix(255, 246, glare))},1)` : 'linear-gradient(180deg, rgba(255,255,255,0.98), rgba(250,251,252,0.97))',
396
+ boxShadow: collapsing
397
+ ? `0 0 ${(30 + 60 * glare).toFixed(1)}px ${(6 + 10 * glare).toFixed(1)}px rgba(255,255,255,${(0.4 + 0.4 * glare).toFixed(3)}), 0 0 120px 20px ${alpha(DARK.accent, 0.35 * glare)}`
398
+ : 'inset 0 1px 0 #ffffff, 0 0 0 1px rgba(15,20,30,0.08), 0 50px 100px -30px rgba(6,8,14,0.6), 0 18px 40px -12px rgba(6,8,14,0.35)',
399
+ fontFamily: FONT.sans, color: '#0f1217',
400
+ }}>
401
+ <div style={{ opacity: contentO }}>
402
+ {/* 输入行 */}
403
+ <div style={{ height: 104, display: 'flex', alignItems: 'center', gap: 22, padding: '0 34px', borderBottom: '1px solid rgba(15,20,30,0.07)' }}>
404
+ <Ic d={I.search} color="#9aa1ad" size={34} w={1.7} />
405
+ <div style={{ display: 'flex', alignItems: 'center', fontSize: 46, fontWeight: 550, letterSpacing: '-0.025em' }}>
406
+ {QUERY.split('').map((c, i) => (
407
+ <span key={i} style={{
408
+ display: f >= TYPE_FRAMES[i] ? 'inline-block' : 'none',
409
+ opacity: charIn(i), transform: `translateY(${((1 - charIn(i)) * 10).toFixed(2)}px)`,
410
+ }}>{c}</span>
411
+ ))}
412
+ <span style={{ width: 3, height: 50, marginLeft: 3, borderRadius: 2, background: LIGHT.accent, opacity: caretOn ? 1 : 0 }} />
413
+ {typed === 0 && <span style={{ color: '#a7adb8', marginLeft: 10, fontWeight: 450 }}>Search commands…</span>}
414
+ </div>
415
+ <span style={{ marginLeft: 'auto' }}><Kbd>esc</Kbd></span>
416
+ </div>
417
+ {/* 结果 */}
418
+ <div style={{ padding: '14px 16px', display: 'flex', flexDirection: 'column', gap: 6 }}>
419
+ {rows.map((row, i) => {
420
+ const on = i === 0 ? selT : 0;
421
+ const dimRow = i === 0 ? 0 : 0.4 * Math.min(1, typed / 4);
422
+ return (
423
+ <div key={i} style={{
424
+ position: 'relative', height: 82, borderRadius: 16, display: 'flex', alignItems: 'center', gap: 22, padding: '0 20px',
425
+ background: on > 0 ? `rgba(242,72,58,${(on * (0.94 + 0.06 * enterPress)).toFixed(3)})` : 'transparent',
426
+ boxShadow: on > 0.5 ? `0 10px 24px -10px ${alpha(LIGHT.accent, 0.7)}${enterPress > 0 ? `, 0 0 0 ${(4 * enterPress).toFixed(1)}px ${alpha(LIGHT.accent, 0.25)}` : ''}` : 'none',
427
+ color: on > 0.5 ? '#ffffff' : '#262b33', opacity: 1 - dimRow, fontSize: 32, fontWeight: 520, letterSpacing: '-0.015em',
428
+ }}>
429
+ <div style={{
430
+ width: 50, height: 50, borderRadius: 13, display: 'flex', alignItems: 'center', justifyContent: 'center', flex: 'none',
431
+ background: on > 0.5 ? 'rgba(255,255,255,0.2)' : '#eef0f3',
432
+ }}>
433
+ <Ic d={row.icon} color={on > 0.5 ? '#ffffff' : '#5a616e'} size={28} w={1.7} />
434
+ </div>
435
+ <span>{i === 0 ? label0(row.label) : row.label}</span>
436
+ <span style={{ marginLeft: 'auto', display: 'flex', gap: 8, alignItems: 'center' }}>
437
+ {i === 0
438
+ ? <><Kbd on={on}>⇧⌘D</Kbd><Kbd on={on} press={enterPress}>↵</Kbd></>
439
+ : <span style={{ fontSize: 23, color: '#9aa1ad' }}>{row.hint}</span>}
440
+ </span>
441
+ </div>
442
+ );
443
+ })}
444
+ </div>
445
+ {/* 页脚提示 */}
446
+ <div style={{ position: 'absolute', left: 0, right: 0, bottom: 0, height: 52, borderTop: '1px solid rgba(15,20,30,0.06)', background: '#f7f8f9', display: 'flex', alignItems: 'center', padding: '0 34px', gap: 26, fontSize: 21, color: '#9aa1ad' }}>
447
+ <span>↑↓ Navigate</span><span>↵ Run</span><span style={{ marginLeft: 'auto' }}>Shotcraft Commands</span>
448
+ </div>
449
+ </div>
450
+ </div>
451
+ )}
452
+ </div>
453
+ <Vignette strength={mix(0.12, 0.42, ramp(f, RIPPLE, 24, EASE.out))} color="#06080c" inner={0.5} />
454
+ <Grain opacity={0.05} blend="overlay" />
455
+ </AbsoluteFill>
456
+ );
457
+ };