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,542 +1,542 @@
1
- // graze-face-tour v3 —— 源片 clickup-30.mp4 约 28.5–33s:
2
- // 相机大倾角贴着 UI 表面游走特写,三段接力:侧栏树 → 顶部 tab 条 → 列表行。
3
- // v2(用户意见):页面文字初始悬浮在界面上空(3D 抬高),空中时在 UI 面上
4
- // 投模糊同形软影;随镜头推进先后落贴回界面,影子随高度收敛消失。
5
- // v3 质感升级:
6
- // - 灰阶骨架 UI(Helvetica 回退、5px 粗边框图标、CSS 三角)→ 出版级浅色产品 UI:系统字体栈、
7
- // 字重层级、统一线性 SVG 图标、3px 发丝线(界面按 ~2.7x 排版,等效 1px)、单一靛紫强调色
8
- // (选中行 / List 视图 / 徽标),与霓虹缘光同色系。
9
- // - 品牌轮:界面就是 video-shotcraft 的工作区——侧栏标志 + 字标、活动 tab 的标志图标,
10
- // 树 / 卡片 / 任务行的内容换成镜头配方卡、分镜、渲染队列(行数与文字长度按原版保持)。
11
- // - 运镜不再"段段刹停":中段匀速巡航、首段缓起、末段缓落,交叉淡化窗口里相机继续外推
12
- // (旧版淡化期 t 被钳住 = 每次接力都有 7f 静止),并带 ±1° 的缓慢滚转,持续"低飞"。
13
- // - 同形软影改纯色压暗(不再是灰字重影),落地瞬间收成贴地接触影;背景霓虹框改发光描边、
14
- // 随相机反向视差漂移;暗角改带色相的深色,不再把亮面 UI 压成脏灰;加暗场颗粒。
15
- import React from 'react';
16
- import { AbsoluteFill, useCurrentFrame } from 'remotion';
17
- import { FONT, Grain, Vignette, bezier } from '../../_fixtures/Polish';
18
- import { ShotcraftMark, ShotcraftWordmark } from '../../_fixtures/Brand';
19
-
20
- export const GRAZE_FACE_TOUR_DURATION = 150; // 三段 × 50f
21
-
22
- const INK = '#17181c';
23
- const INK2 = '#5d6068';
24
- const INK3 = '#9a9ca5';
25
- const LINE = 'rgba(20,22,28,0.085)';
26
- const SURF = '#f8f8f9';
27
- const SIDE = '#f2f2f4';
28
- const ACC = '#7457f5';
29
- const ACC_SOFT = 'rgba(116,87,245,0.11)';
30
- const SANS = FONT.sans;
31
-
32
- const easeFall = bezier(0.5, 0.05, 0.6, 1); // 加速下落、末端软着陆
33
-
34
- /* ---------- 悬浮 + 同形软影 ----------
35
- * h=悬浮高度(px)。文字整体向上(屏幕上-左)抬起,原位置留一份纯色压暗的同形投影:
36
- * 高处影大、糊、淡、偏移远;h→0 时收成贴地接触影并消失。 */
37
- const FloatWrap: React.FC<{ h: number; children: React.ReactNode }> = ({ h, children }) => (
38
- <div style={{ position: 'relative' }}>
39
- {h > 1.5 && (
40
- <div style={{
41
- position: 'absolute', inset: 0,
42
- transform: `translate(${h * 0.22}px, ${h * 0.42}px) scale(${1 + h * 0.0011})`,
43
- filter: `brightness(0) blur(${2 + h * 0.09}px)`,
44
- opacity: Math.min(0.22, 0.08 + h * 0.0026),
45
- pointerEvents: 'none',
46
- }}>{children}</div>
47
- )}
48
- <div style={{ transform: `translate(${-h * 0.34}px, ${-h * 0.78}px)` }}>{children}</div>
49
- </div>
50
- );
51
-
52
- /* 每行的悬浮高度:land = 该行贴回完成的段内时刻(0..1),之前从 H 高度加速落下 */
53
- const liftOf = (t: number, land: number, H = 120) => {
54
- const FALL = 0.34;
55
- const p = Math.min(1, Math.max(0, (t - (land - FALL)) / FALL));
56
- return (1 - easeFall(p)) * H;
57
- };
58
-
59
- /* ---------- 线性图标(24 视框,界面按 ~2.7x 排版,描边 1.7 ≈ 屏幕 4px) ---------- */
60
- type IconName = 'doc' | 'folder' | 'more' | 'chevR' | 'chevD' | 'home' | 'inbox' | 'building' | 'users'
61
- | 'target' | 'search' | 'list' | 'grid' | 'square' | 'dot';
62
- const PATHS: Record<IconName, string> = {
63
- doc: 'M7 3h7l4 4v14H7zM14 3v4h4M9.5 12h6M9.5 15.5h6',
64
- folder: 'M3.5 7.5a2 2 0 0 1 2-2h4l2 2h7a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2h-13a2 2 0 0 1-2-2z',
65
- more: 'M6 12h.01M12 12h.01M18 12h.01',
66
- chevR: 'M9.5 6l6 6-6 6',
67
- chevD: 'M6 9.5l6 6 6-6',
68
- home: 'M4 11l8-6.5 8 6.5M6.5 9.5V19h11V9.5',
69
- inbox: 'M4 13.5l2.5-8h11l2.5 8v5H4zM4 13.5h4.5l1.2 2h4.6l1.2-2H20',
70
- building: 'M5 20V5.5h9V20M14 9.5h5V20M8 9h3M8 12.5h3M8 16h3M3.5 20h17',
71
- users: 'M9 11a3 3 0 1 0 0-6 3 3 0 0 0 0 6zM3.5 19a5.5 5.5 0 0 1 11 0M16 5.5a3 3 0 0 1 0 5.5M17.5 14a5 5 0 0 1 3 5',
72
- target: 'M12 20a8 8 0 1 0 0-16 8 8 0 0 0 0 16zM12 16a4 4 0 1 0 0-8 4 4 0 0 0 0 8zM12 12h.01',
73
- search: 'M11 18a7 7 0 1 0 0-14 7 7 0 0 0 0 14zM20 20l-4-4',
74
- list: 'M8.5 6.5h11M8.5 12h11M8.5 17.5h11M4.5 6.5h.01M4.5 12h.01M4.5 17.5h.01',
75
- grid: 'M4.5 4.5h6v6h-6zM13.5 4.5h6v6h-6zM4.5 13.5h6v6h-6zM13.5 13.5h6v6h-6z',
76
- square: 'M5 5h14v14H5z',
77
- dot: 'M12 12h.01',
78
- };
79
- const Icon: React.FC<{ name: IconName; size?: number; color?: string; sw?: number; dashed?: boolean }> = ({
80
- name, size = 50, color = INK3, sw = 1.7, dashed,
81
- }) => (
82
- <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke={color} strokeWidth={name === 'more' || name === 'dot' ? 3.2 : sw}
83
- strokeLinecap="round" strokeLinejoin="round" strokeDasharray={dashed ? '2.6 2.4' : undefined} style={{ flex: 'none' }}>
84
- <path d={PATHS[name]} />
85
- </svg>
86
- );
87
-
88
- /* 空间徽标:低饱和色块 + 字母 */
89
- const SpaceChip: React.FC<{ letter: string; hue: string }> = ({ letter, hue }) => (
90
- <div style={{
91
- width: 60, height: 60, borderRadius: 16, background: hue, flex: 'none',
92
- display: 'flex', alignItems: 'center', justifyContent: 'center',
93
- fontFamily: SANS, fontWeight: 700, fontSize: 32, color: '#fff', letterSpacing: '-0.02em',
94
- boxShadow: 'inset 0 2px 0 rgba(255,255,255,0.25)',
95
- }}>{letter}</div>
96
- );
97
-
98
- type RowIcon = 'tri' | 'triOpen' | 'doc' | 'folder' | 'dash' | undefined;
99
-
100
- const TreeRow: React.FC<{
101
- depth: number; label: string; icon?: RowIcon; chip?: string; count?: string; size?: number;
102
- }> = ({ depth, label, icon, chip, count, size = 56 }) => (
103
- <div style={{
104
- display: 'flex', alignItems: 'center', gap: 26, paddingLeft: 40 + depth * 90,
105
- height: size * 2.1,
106
- }}>
107
- {icon === 'tri' && <Icon name="chevR" size={44} color={INK3} />}
108
- {icon === 'triOpen' && <Icon name="chevD" size={44} color={INK2} />}
109
- {icon === 'doc' && <Icon name="doc" color={INK3} />}
110
- {icon === 'folder' && <Icon name="folder" color={INK3} />}
111
- {icon === 'dash' && <Icon name="square" color={INK3} dashed />}
112
- {chip && <SpaceChip letter={chip} hue={{ O: '#8a7cf0', C: '#4fb39a', T: '#e39a5b' }[chip] ?? '#9a9ca5'} />}
113
- <div style={{ fontFamily: SANS, fontSize: size, color: INK, fontWeight: 500, letterSpacing: '-0.012em' }}>{label}</div>
114
- {count && (
115
- <div style={{
116
- marginLeft: 'auto', marginRight: 80, fontFamily: SANS, fontSize: size * 0.78, color: INK3, fontWeight: 500,
117
- fontVariantNumeric: 'tabular-nums',
118
- }}>{count}</div>
119
- )}
120
- </div>
121
- );
122
-
123
- const RecentCard: React.FC<{ title: string; sub: string; meta: string; w?: number }> = ({ title, sub, meta, w = 880 }) => (
124
- <div style={{
125
- width: w, border: `3px solid ${LINE}`, borderRadius: 26, padding: '34px 42px',
126
- display: 'flex', flexDirection: 'column', gap: 14, background: '#fff', boxSizing: 'border-box',
127
- boxShadow: '0 3px 6px rgba(16,18,24,0.04), 0 18px 40px -14px rgba(16,18,24,0.12)',
128
- }}>
129
- <div style={{ display: 'flex', alignItems: 'center', gap: 22 }}>
130
- <Icon name="doc" size={52} color={INK2} />
131
- <div style={{ fontFamily: SANS, fontSize: 50, color: INK, fontWeight: 650, letterSpacing: '-0.02em' }}>{title}</div>
132
- </div>
133
- <div style={{ display: 'flex', alignItems: 'center', gap: 18, paddingLeft: 74, fontFamily: SANS, fontSize: 38, color: INK3 }}>
134
- <span style={{ color: INK2 }}>{sub}</span>
135
- <span>·</span>
136
- <span>{meta}</span>
137
- </div>
138
- </div>
139
- );
140
-
141
- const Tabs: React.FC<{ items: string[]; size: number }> = ({ items, size }) => (
142
- <div style={{ display: 'flex', gap: 80, fontFamily: SANS, fontSize: size, letterSpacing: '-0.012em' }}>
143
- {items.map((it, i) => (
144
- <div key={it} style={{ position: 'relative', color: i === 0 ? INK : INK3, fontWeight: i === 0 ? 650 : 500 }}>
145
- {it}
146
- {i === 0 && <div style={{ position: 'absolute', left: 0, right: 0, bottom: -22, height: 5, borderRadius: 3, background: ACC }} />}
147
- </div>
148
- ))}
149
- </div>
150
- );
151
-
152
- const ViewSwitch: React.FC<{ size: number }> = ({ size }) => (
153
- <div style={{ display: 'flex', gap: 30, alignItems: 'center' }}>
154
- <div style={{
155
- display: 'flex', alignItems: 'center', gap: 16, padding: '20px 40px', background: ACC_SOFT, borderRadius: 18,
156
- border: '3px solid rgba(116,87,245,0.22)', fontFamily: SANS, fontSize: size, color: ACC, fontWeight: 650,
157
- }}><Icon name="list" size={size * 0.95} color={ACC} />List</div>
158
- <div style={{ display: 'flex', alignItems: 'center', gap: 16, fontFamily: SANS, fontSize: size, color: INK3, fontWeight: 500 }}>
159
- <Icon name="grid" size={size * 0.95} color={INK3} />Gallery
160
- </div>
161
- </div>
162
- );
163
-
164
- /* 场景 A:侧栏 SPACES 树 + 右侧 Recent 卡
165
- * 树行/卡片按镜头行进方向(自上而下)先后从空中落贴回界面 */
166
- const SceneTree: React.FC<{ t?: number }> = ({ t = 1 }) => {
167
- const L = (i: number, n = 14) => liftOf(t, 0.22 + (i / n) * 0.62, 130);
168
- const rows: [number, string, RowIcon, string | undefined, string | undefined][] = [
169
- [0, 'Shot recipes', 'doc', undefined, undefined],
170
- [0, 'Storyboards', 'doc', undefined, undefined],
171
- [0, 'Renders', 'doc', undefined, undefined],
172
- [0, 'More', 'dash', undefined, undefined],
173
- [0, 'Opening', 'tri', 'O', undefined],
174
- [0, 'Camera moves', 'tri', 'C', undefined],
175
- [0, 'Transitions', 'triOpen', 'T', undefined],
176
- [1, 'Recipe handbook', 'doc', undefined, undefined],
177
- [1, 'Whip pans', 'folder', undefined, undefined],
178
- [1, 'Match cuts', 'folder', undefined, undefined],
179
- [2, 'Match cuts', 'doc', undefined, undefined],
180
- [2, 'Takes', 'dash', undefined, '56'],
181
- [2, 'Demos', 'dash', undefined, '8'],
182
- [2, 'Frames', 'dash', undefined, '256'],
183
- ];
184
- return (
185
- <div style={{ width: 2900, height: 2400, background: SURF, display: 'flex' }}>
186
- <div style={{ width: 1500, borderRight: `3px solid ${LINE}`, paddingTop: 60, background: SIDE }}>
187
- {rows.slice(0, 4).map((r, i) => (
188
- <FloatWrap key={r[1] + i} h={L(i)}>
189
- <TreeRow depth={r[0]} label={r[1]} icon={r[2]} chip={r[3]} count={r[4]} />
190
- </FloatWrap>
191
- ))}
192
- <div style={{ height: 90 }} />
193
- <FloatWrap h={L(4)}>
194
- <div style={{ paddingLeft: 48, fontFamily: SANS, fontSize: 40, letterSpacing: '0.14em', color: INK3, fontWeight: 650 }}>SPACES</div>
195
- </FloatWrap>
196
- <div style={{ height: 30 }} />
197
- {rows.slice(4).map((r, i) => (
198
- <FloatWrap key={r[1] + i} h={L(i + 4.6)}>
199
- <TreeRow depth={r[0]} label={r[1]} icon={r[2]} chip={r[3]} count={r[4]} />
200
- </FloatWrap>
201
- ))}
202
- </div>
203
- <div style={{ flex: 1, paddingTop: 100, paddingLeft: 110 }}>
204
- <FloatWrap h={liftOf(t, 0.3, 150)}>
205
- <Tabs items={['Recent', 'Favorites']} size={52} />
206
- </FloatWrap>
207
- <div style={{ height: 70 }} />
208
- <div style={{ display: 'flex', flexDirection: 'column', gap: 44 }}>
209
- <FloatWrap h={liftOf(t, 0.42, 170)}>
210
- <RecentCard title="Launch film" sub="Storyboard v3" meta="Edited 2h ago" />
211
- </FloatWrap>
212
- <FloatWrap h={liftOf(t, 0.55, 170)}>
213
- <RecentCard title="Add shot · crash zoom" sub="Camera moves" meta="Yesterday" />
214
- </FloatWrap>
215
- </div>
216
- <div style={{ height: 110 }} />
217
- <FloatWrap h={liftOf(t, 0.68, 150)}>
218
- <Tabs items={['Todo', 'Comments', 'Done']} size={50} />
219
- </FloatWrap>
220
- <div style={{ height: 60 }} />
221
- <FloatWrap h={liftOf(t, 0.8, 150)}>
222
- <ViewSwitch size={46} />
223
- </FloatWrap>
224
- </div>
225
- </div>
226
- );
227
- };
228
-
229
- /* 场景 B:顶部 tab 条 + 左上侧栏导航
230
- * tab 条、video-shotcraft 字标、Home 行、侧栏项先后从空中贴落 */
231
- const NAV: [IconName, string][] = [['inbox', 'Inbox'], ['building', 'Company'], ['users', 'People & Teams'], ['target', 'Goals'], ['doc', 'Docs']];
232
- const SceneTopNav: React.FC<{ t?: number }> = ({ t = 1 }) => (
233
- <div style={{ width: 3000, height: 2100, background: SURF, borderRadius: 48 }}>
234
- <div style={{
235
- height: 150, borderBottom: `3px solid ${LINE}`, display: 'flex', alignItems: 'center',
236
- gap: 110, paddingLeft: 90, fontFamily: SANS, fontSize: 52, color: INK, background: SIDE, borderRadius: '48px 48px 0 0',
237
- }}>
238
- {['Shot recipe cards', 'Launch film', 'Beat-synced cuts', 'Render queue'].map((tb, i) => (
239
- <FloatWrap key={tb} h={liftOf(t, 0.2 + i * 0.1, 140)}>
240
- <div style={{
241
- display: 'flex', alignItems: 'center', gap: 22, fontWeight: i === 1 ? 650 : 500, color: i === 1 ? INK : INK2,
242
- letterSpacing: '-0.012em', opacity: i > 1 ? 0.8 : 1,
243
- ...(i === 1 ? { background: '#fff', padding: '18px 34px', borderRadius: 18, border: `3px solid ${LINE}`, boxShadow: '0 6px 16px -8px rgba(16,18,24,0.18)' } : {}),
244
- }}>
245
- {i === 1
246
- ? <ShotcraftMark size={40} tone="light" />
247
- : <Icon name="doc" size={44} color={INK3} />}
248
- {tb}
249
- </div>
250
- </FloatWrap>
251
- ))}
252
- </div>
253
- <div style={{ display: 'flex' }}>
254
- <div style={{ width: 1250, padding: '70px 70px 0', background: SIDE, height: 1950, boxSizing: 'border-box', borderBottomLeftRadius: 48 }}>
255
- <FloatWrap h={liftOf(t, 0.34, 150)}>
256
- <div style={{ display: 'flex', alignItems: 'center', gap: 28 }}>
257
- <ShotcraftWordmark size={56} tone="light" markScale={1.5} gap={24} />
258
- <div style={{
259
- marginLeft: 'auto', width: 120, height: 84, border: `3px solid ${LINE}`, borderRadius: 22, background: '#fff',
260
- display: 'flex', alignItems: 'center', justifyContent: 'center',
261
- }}><Icon name="search" size={44} color={INK2} /></div>
262
- </div>
263
- </FloatWrap>
264
- <div style={{ height: 60 }} />
265
- <FloatWrap h={liftOf(t, 0.46, 160)}>
266
- <div style={{
267
- display: 'flex', alignItems: 'center', gap: 30, background: ACC_SOFT,
268
- border: '3px solid rgba(116,87,245,0.2)', borderRadius: 24, padding: '28px 40px',
269
- }}>
270
- <Icon name="home" size={54} color={ACC} sw={1.9} />
271
- <div style={{ fontFamily: SANS, fontSize: 54, color: INK, fontWeight: 650, letterSpacing: '-0.015em' }}>Home</div>
272
- <div style={{
273
- marginLeft: 'auto', minWidth: 62, height: 62, borderRadius: 31, background: ACC,
274
- color: '#fff', fontFamily: SANS, fontSize: 36, fontWeight: 700, fontVariantNumeric: 'tabular-nums',
275
- display: 'flex', alignItems: 'center', justifyContent: 'center',
276
- }}>3</div>
277
- </div>
278
- </FloatWrap>
279
- {NAV.map(([ic, tb], i) => (
280
- <FloatWrap key={tb} h={liftOf(t, 0.55 + i * 0.08, 140)}>
281
- <div style={{ display: 'flex', alignItems: 'center', gap: 30, height: 128, paddingLeft: 40 }}>
282
- <Icon name={ic} size={52} color={INK3} />
283
- <div style={{ fontFamily: SANS, fontSize: 52, color: INK2, fontWeight: 500, letterSpacing: '-0.012em' }}>{tb}</div>
284
- </div>
285
- </FloatWrap>
286
- ))}
287
- </div>
288
- <div style={{ flex: 1, borderLeft: `3px solid ${LINE}`, padding: '70px 90px 0' }}>
289
- <FloatWrap h={liftOf(t, 0.4, 150)}>
290
- <div style={{ display: 'flex', alignItems: 'center', gap: 30, color: INK3, fontFamily: SANS, fontSize: 48 }}>
291
- <Icon name="chevR" size={44} color={INK3} />
292
- <Icon name="home" size={46} color={INK3} />
293
- <div style={{ color: INK2, fontWeight: 500 }}>Home</div>
294
- </div>
295
- </FloatWrap>
296
- <div style={{ height: 80 }} />
297
- <FloatWrap h={liftOf(t, 0.58, 180)}>
298
- <div style={{ fontFamily: SANS, fontSize: 128, fontWeight: 750, color: INK, letterSpacing: '-0.04em', lineHeight: 1 }}>Home</div>
299
- </FloatWrap>
300
- <div style={{ height: 80 }} />
301
- <FloatWrap h={liftOf(t, 0.74, 160)}>
302
- <div style={{
303
- display: 'flex', alignItems: 'center', gap: 30, border: `3px solid ${LINE}`,
304
- borderRadius: 26, padding: '32px 44px', background: '#fff', width: 1100, boxSizing: 'border-box',
305
- boxShadow: '0 3px 6px rgba(16,18,24,0.04), 0 18px 40px -14px rgba(16,18,24,0.14)',
306
- }}>
307
- <Icon name="search" size={50} color={INK3} />
308
- <div style={{ fontFamily: SANS, fontSize: 46, color: INK3 }}>Search shots, recipes…</div>
309
- <div style={{
310
- marginLeft: 'auto', padding: '8px 18px', borderRadius: 12, border: `3px solid ${LINE}`,
311
- fontFamily: FONT.mono, fontSize: 34, color: INK3,
312
- }}>⌘K</div>
313
- </div>
314
- </FloatWrap>
315
- </div>
316
- </div>
317
- </div>
318
- );
319
-
320
- /* 场景 C:列表行(TODAY / TASK NAME 区)——Todo 头/TODAY 徽章/任务行自上而下先后贴落 */
321
- const TASKS = [
322
- { n: 'Render launch film', who: '#8a7cf0', due: 'Today', p: 0.72 },
323
- { n: 'Add shot: crash zoom', who: '#4fb39a', due: 'Today', p: 0.45 },
324
- { n: 'Beat-sync the cuts', who: '#e39a5b', due: 'Tomorrow', p: 0.3 },
325
- { n: 'Export JianYing draft', who: '#6aa6e8', due: 'Fri', p: 0.86 },
326
- ];
327
- const SceneListRows: React.FC<{ t?: number }> = ({ t = 1 }) => (
328
- <div style={{ width: 2900, height: 2200, background: SURF, paddingTop: 60 }}>
329
- <FloatWrap h={liftOf(t, 0.22, 150)}>
330
- <div style={{ paddingLeft: 120 }}><Tabs items={['Todo', 'Comments', 'Done', 'Delegated']} size={52} /></div>
331
- </FloatWrap>
332
- <div style={{ height: 66 }} />
333
- <FloatWrap h={liftOf(t, 0.32, 150)}>
334
- <div style={{ display: 'flex', alignItems: 'center', paddingLeft: 120 }}>
335
- <ViewSwitch size={48} />
336
- <div style={{ marginLeft: 500, display: 'flex', gap: 70, color: INK3, fontFamily: SANS, fontSize: 44, fontWeight: 500 }}>
337
- <div>Filter</div><div>Group</div><div>Sort</div>
338
- </div>
339
- </div>
340
- </FloatWrap>
341
- <div style={{ height: 40, borderBottom: `3px solid ${LINE}`, marginLeft: 120, marginRight: 120 }} />
342
- <div style={{ height: 60 }} />
343
- <FloatWrap h={liftOf(t, 0.44, 160)}>
344
- <div style={{
345
- marginLeft: 120, display: 'inline-flex', alignItems: 'center', gap: 16, padding: '18px 40px', background: ACC_SOFT,
346
- borderRadius: 16, fontFamily: SANS, fontSize: 40, letterSpacing: '0.12em', color: ACC, fontWeight: 700,
347
- }}><Icon name="chevD" size={38} color={ACC} sw={2.2} />TODAY</div>
348
- </FloatWrap>
349
- <div style={{ height: 60 }} />
350
- <FloatWrap h={liftOf(t, 0.54, 150)}>
351
- <div style={{ display: 'flex', paddingLeft: 120, paddingRight: 120, fontFamily: SANS, fontSize: 38, letterSpacing: '0.12em', color: INK3, fontWeight: 600 }}>
352
- <div>TASK NAME</div>
353
- <div style={{ marginLeft: 'auto', width: 520 }}>PROGRESS</div>
354
- <div style={{ width: 260, textAlign: 'right' }}>DUE</div>
355
- </div>
356
- </FloatWrap>
357
- <div style={{ height: 30 }} />
358
- {TASKS.map((tk, i) => (
359
- <FloatWrap key={tk.n} h={liftOf(t, 0.62 + i * 0.09, 160)}>
360
- <div style={{
361
- display: 'flex', alignItems: 'center', gap: 40, height: 170, marginLeft: 120, marginRight: 120,
362
- borderBottom: `3px solid ${LINE}`,
363
- }}>
364
- <div style={{ width: 42, height: 42, borderRadius: 13, border: `4px solid ${i === 0 ? ACC : 'rgba(20,22,28,0.22)'}`, background: i === 0 ? ACC_SOFT : 'transparent', boxSizing: 'border-box' }} />
365
- <div style={{ fontFamily: SANS, fontSize: 56, color: INK, fontWeight: 550, letterSpacing: '-0.015em' }}>{tk.n}</div>
366
- <div style={{ marginLeft: 'auto', width: 64, height: 64, borderRadius: 32, background: tk.who, border: '5px solid #fff', boxShadow: '0 0 0 3px rgba(20,22,28,0.06)' }} />
367
- <div style={{ width: 400, height: 16, borderRadius: 8, background: 'rgba(20,22,28,0.07)', overflow: 'hidden' }}>
368
- <div style={{ width: `${tk.p * 100}%`, height: '100%', borderRadius: 8, background: i === 0 ? ACC : 'rgba(20,22,28,0.28)' }} />
369
- </div>
370
- <div style={{ width: 220, textAlign: 'right', fontFamily: SANS, fontSize: 44, color: tk.due === 'Today' ? ACC : INK3, fontWeight: 550 }}>{tk.due}</div>
371
- <Icon name="more" size={50} color={INK3} />
372
- </div>
373
- </FloatWrap>
374
- ))}
375
- </div>
376
- );
377
-
378
- /* ---------- 3D 摄影 ---------- */
379
-
380
- type Cam = {
381
- rx: number; ry: number; rz: number; scale: number;
382
- x: [number, number]; y: [number, number];
383
- };
384
-
385
- // 巡航曲线:首段缓起(前 30% 二次加速接匀速)、末段缓落、中段匀速;u 超出 [0,1](交叉淡化
386
- // 窗口)时按端点斜率线性外推,相机在淡化里继续飞,接力处不再刹停
387
- const cruise = (u: number, first: boolean, last: boolean) => {
388
- const A = 0.3;
389
- const k = 1 / (1 - (first ? A / 2 : 0) - (last ? A / 2 : 0));
390
- const inPart = (x: number) => (x < A ? (x * x) / (2 * A) : x - A / 2);
391
- if (first && u <= A) return k * inPart(Math.max(0, u));
392
- if (last && u >= 1 - A) return 1 - k * inPart(Math.max(0, 1 - u));
393
- return first ? k * inPart(u) : k * u;
394
- };
395
-
396
- const Plane: React.FC<{
397
- cam: Cam; p: number; edge?: 'left' | 'top'; children: React.ReactNode;
398
- }> = ({ cam, p, edge = 'left', children }) => {
399
- const x = cam.x[0] + (cam.x[1] - cam.x[0]) * p;
400
- const y = cam.y[0] + (cam.y[1] - cam.y[0]) * p;
401
- const roll = cam.rz + (p - 0.5) * 2; // ±1° 缓慢滚转
402
- return (
403
- <AbsoluteFill style={{ perspective: 1050, perspectiveOrigin: '50% 46%' }}>
404
- <div style={{
405
- position: 'absolute', left: '50%', top: '50%', width: 0, height: 0,
406
- transformStyle: 'preserve-3d',
407
- transform: `scale(${cam.scale}) rotateX(${cam.rx}deg) rotateY(${cam.ry}deg) rotateZ(${roll}deg)`,
408
- }}>
409
- <div style={{ position: 'absolute', transform: `translate3d(${x}px, ${y}px, 0)` }}>
410
- <div style={{ position: 'relative', transform: 'translate(-50%, -50%)' }}>
411
- {/* 屏幕边缘霓虹缘光:外晕 + 贴边细亮线 */}
412
- {edge === 'left' ? (
413
- <>
414
- <div style={{
415
- position: 'absolute', left: -80, top: -40, width: 120, height: '104%',
416
- background: 'linear-gradient(185deg, #ff7ab8, #a46cff 55%, #6a4dff)',
417
- filter: 'blur(70px)', opacity: 0.85,
418
- }} />
419
- <div style={{
420
- position: 'absolute', left: -7, top: 0, width: 6, height: '100%', borderRadius: 3,
421
- background: 'linear-gradient(180deg, #ffc2de, #b99bff)', filter: 'blur(2px)', opacity: 0.95,
422
- }} />
423
- </>
424
- ) : (
425
- <>
426
- <div style={{
427
- position: 'absolute', left: -40, top: -80, width: '104%', height: 120,
428
- background: 'linear-gradient(90deg, #ff7ab8, #a46cff 55%, #6a4dff)',
429
- filter: 'blur(70px)', opacity: 0.8,
430
- }} />
431
- <div style={{
432
- position: 'absolute', left: 48, top: -7, width: 'calc(100% - 96px)', height: 6, borderRadius: 3,
433
- background: 'linear-gradient(90deg, #ffc2de, #b99bff)', filter: 'blur(2px)', opacity: 0.9,
434
- }} />
435
- </>
436
- )}
437
- {children}
438
- {/* 远端压暗:贴面透视里远处渐暗(比 v2 轻,亮面不发脏) */}
439
- <div style={{
440
- position: 'absolute', inset: 0,
441
- background: edge === 'left'
442
- ? 'linear-gradient(105deg, rgba(8,6,18,0) 34%, rgba(8,6,18,0.22) 75%, rgba(8,6,18,0.5) 100%)'
443
- : 'linear-gradient(175deg, rgba(8,6,18,0) 38%, rgba(8,6,18,0.2) 80%, rgba(8,6,18,0.45) 100%)',
444
- pointerEvents: 'none',
445
- }} />
446
- </div>
447
- </div>
448
- </div>
449
- </AbsoluteFill>
450
- );
451
- };
452
-
453
- /* 背景霓虹框(暗场道具):发光细描边,随镜头行进反向视差漂移 */
454
- const NeonRects: React.FC<{ drift: number }> = ({ drift }) => {
455
- const box = (c: string, a: number): React.CSSProperties => ({
456
- position: 'absolute', borderRadius: 32, border: `3px solid ${c}`, opacity: a,
457
- boxShadow: `0 0 24px ${c}, inset 0 0 18px ${c}`, filter: 'blur(3px)',
458
- });
459
- return (
460
- <AbsoluteFill style={{ overflow: 'hidden' }}>
461
- <div style={{ ...box('#b04dff', 0.42), left: -140 + drift * 60, top: 240, width: 620, height: 380 }} />
462
- <div style={{ ...box('#ff4da8', 0.32), left: 60 + drift * 36, top: 700, width: 420, height: 260 }} />
463
- <div style={{ ...box('#7b4dff', 0.3), right: -180 - drift * 44, top: -80, width: 560, height: 340 }} />
464
- </AbsoluteFill>
465
- );
466
- };
467
-
468
- // 平移目标以内容坐标 (cx,cy) 给出:translate = (W/2-cx, H/2-cy)
469
- const SEGS: { cam: Cam; edge: 'left' | 'top'; render: (t: number) => React.ReactNode }[] = [
470
- {
471
- // 侧栏树:从树顶(SPACES 附近)贴面滑到树底(Components/Patterns/Tokens)
472
- cam: { rx: 12, ry: 30, rz: -6, scale: 0.95, x: [1450 - 950, 1450 - 880], y: [1200 - 1050, 1200 - 1850] },
473
- edge: 'left', render: (t) => <SceneTree t={t} />,
474
- },
475
- {
476
- // 顶栏 tab 条 → 右区 Home 大标题
477
- cam: { rx: 20, ry: -20, rz: 6, scale: 0.95, x: [1500 - 800, 1500 - 2000], y: [1050 - 350, 1050 - 800] },
478
- edge: 'top', render: (t) => <SceneTopNav t={t} />,
479
- },
480
- {
481
- // 列表行:沿 TASK NAME 行右扫
482
- cam: { rx: 14, ry: 28, rz: -5, scale: 1.05, x: [1450 - 900, 1450 - 680], y: [1100 - 620, 1100 - 1240] },
483
- edge: 'left', render: (t) => <SceneListRows t={t} />,
484
- },
485
- ];
486
-
487
- const SEG_LEN = 50; // 每段 50 帧,总 150
488
- const FADE = 7;
489
-
490
- const Stage: React.FC = () => {
491
- const frame = useCurrentFrame();
492
- return (
493
- <AbsoluteFill style={{ background: '#07060c' }}>
494
- {SEGS.map((s, i) => {
495
- const start = i * SEG_LEN;
496
- const local = frame - start;
497
- if (local < -FADE || local > SEG_LEN + FADE) return null;
498
- const u = local / SEG_LEN; // 不钳:淡化窗口里相机继续外推
499
- const t = Math.min(1, Math.max(0, u)); // 内容(贴落进度)照旧钳位
500
- const p = cruise(u, i === 0, i === SEGS.length - 1);
501
- // 相邻段交叉淡化:后段在边界前 [-FADE,0] 淡入、前段在 [SEG_LEN-FADE, SEG_LEN] 淡出,边界帧无纯黑
502
- const fadeIn = i === 0 ? 1 : Math.min(1, Math.max(0, (local + FADE) / FADE));
503
- const fadeOut = i === SEGS.length - 1 ? 1 : Math.min(1, Math.max(0, (SEG_LEN - local) / FADE));
504
- return (
505
- <AbsoluteFill key={i} style={{ opacity: Math.min(fadeIn, fadeOut) }}>
506
- <NeonRects drift={p} />
507
- <Plane cam={s.cam} p={p} edge={s.edge}>{s.render(t)}</Plane>
508
- </AbsoluteFill>
509
- );
510
- })}
511
- </AbsoluteFill>
512
- );
513
- };
514
-
515
- export const GrazeFaceTour: React.FC = () => {
516
- const frame = useCurrentFrame();
517
- // 浅景深焦点带:焦点椭圆随段落平滑移动(段间 10f 过渡,不跳)
518
- const FX = [44, 40, 46];
519
- const FY = [46, 40, 50];
520
- const k1 = Math.min(1, Math.max(0, (frame - SEG_LEN + 5) / 10));
521
- const k2 = Math.min(1, Math.max(0, (frame - 2 * SEG_LEN + 5) / 10));
522
- const kk = k1 + k2; // 0→1→2:段 A→B→C 的焦点
523
- const lerpArr = (a: number[]) => (kk <= 1 ? a[0] + (a[1] - a[0]) * kk : a[1] + (a[2] - a[1]) * (kk - 1));
524
- const focusX = lerpArr(FX);
525
- const focusY = lerpArr(FY);
526
- return (
527
- <AbsoluteFill style={{ background: '#07060c' }}>
528
- <Stage />
529
- {/* 屏幕空间浅景深:焦点带外整体模糊 */}
530
- <AbsoluteFill style={{
531
- filter: 'blur(15px)',
532
- WebkitMaskImage: `radial-gradient(ellipse 58% 52% at ${focusX}% ${focusY}%, transparent 34%, rgba(0,0,0,0.85) 72%, black 92%)`,
533
- maskImage: `radial-gradient(ellipse 58% 52% at ${focusX}% ${focusY}%, transparent 34%, rgba(0,0,0,0.85) 72%, black 92%)`,
534
- }}>
535
- <Stage />
536
- </AbsoluteFill>
537
- {/* 带色相的暗角(不再把亮面压成灰)+ 暗场颗粒 */}
538
- <Vignette strength={0.62} inner={0.42} color="#06040e" cx={focusX / 100} cy={focusY / 100} />
539
- <Grain opacity={0.06} blend="soft-light" />
540
- </AbsoluteFill>
541
- );
542
- };
1
+ // graze-face-tour v3 —— 源片 clickup-30.mp4 约 28.5–33s:
2
+ // 相机大倾角贴着 UI 表面游走特写,三段接力:侧栏树 → 顶部 tab 条 → 列表行。
3
+ // v2(用户意见):页面文字初始悬浮在界面上空(3D 抬高),空中时在 UI 面上
4
+ // 投模糊同形软影;随镜头推进先后落贴回界面,影子随高度收敛消失。
5
+ // v3 质感升级:
6
+ // - 灰阶骨架 UI(Helvetica 回退、5px 粗边框图标、CSS 三角)→ 出版级浅色产品 UI:系统字体栈、
7
+ // 字重层级、统一线性 SVG 图标、3px 发丝线(界面按 ~2.7x 排版,等效 1px)、单一靛紫强调色
8
+ // (选中行 / List 视图 / 徽标),与霓虹缘光同色系。
9
+ // - 品牌轮:界面就是 video-shotcraft 的工作区——侧栏标志 + 字标、活动 tab 的标志图标,
10
+ // 树 / 卡片 / 任务行的内容换成镜头配方卡、分镜、渲染队列(行数与文字长度按原版保持)。
11
+ // - 运镜不再"段段刹停":中段匀速巡航、首段缓起、末段缓落,交叉淡化窗口里相机继续外推
12
+ // (旧版淡化期 t 被钳住 = 每次接力都有 7f 静止),并带 ±1° 的缓慢滚转,持续"低飞"。
13
+ // - 同形软影改纯色压暗(不再是灰字重影),落地瞬间收成贴地接触影;背景霓虹框改发光描边、
14
+ // 随相机反向视差漂移;暗角改带色相的深色,不再把亮面 UI 压成脏灰;加暗场颗粒。
15
+ import React from 'react';
16
+ import { AbsoluteFill, useCurrentFrame } from 'remotion';
17
+ import { FONT, Grain, Vignette, bezier } from '../../_fixtures/Polish';
18
+ import { ShotcraftMark, ShotcraftWordmark } from '../../_fixtures/Brand';
19
+
20
+ export const GRAZE_FACE_TOUR_DURATION = 150; // 三段 × 50f
21
+
22
+ const INK = '#17181c';
23
+ const INK2 = '#5d6068';
24
+ const INK3 = '#9a9ca5';
25
+ const LINE = 'rgba(20,22,28,0.085)';
26
+ const SURF = '#f8f8f9';
27
+ const SIDE = '#f2f2f4';
28
+ const ACC = '#7457f5';
29
+ const ACC_SOFT = 'rgba(116,87,245,0.11)';
30
+ const SANS = FONT.sans;
31
+
32
+ const easeFall = bezier(0.5, 0.05, 0.6, 1); // 加速下落、末端软着陆
33
+
34
+ /* ---------- 悬浮 + 同形软影 ----------
35
+ * h=悬浮高度(px)。文字整体向上(屏幕上-左)抬起,原位置留一份纯色压暗的同形投影:
36
+ * 高处影大、糊、淡、偏移远;h→0 时收成贴地接触影并消失。 */
37
+ const FloatWrap: React.FC<{ h: number; children: React.ReactNode }> = ({ h, children }) => (
38
+ <div style={{ position: 'relative' }}>
39
+ {h > 1.5 && (
40
+ <div style={{
41
+ position: 'absolute', inset: 0,
42
+ transform: `translate(${h * 0.22}px, ${h * 0.42}px) scale(${1 + h * 0.0011})`,
43
+ filter: `brightness(0) blur(${2 + h * 0.09}px)`,
44
+ opacity: Math.min(0.22, 0.08 + h * 0.0026),
45
+ pointerEvents: 'none',
46
+ }}>{children}</div>
47
+ )}
48
+ <div style={{ transform: `translate(${-h * 0.34}px, ${-h * 0.78}px)` }}>{children}</div>
49
+ </div>
50
+ );
51
+
52
+ /* 每行的悬浮高度:land = 该行贴回完成的段内时刻(0..1),之前从 H 高度加速落下 */
53
+ const liftOf = (t: number, land: number, H = 120) => {
54
+ const FALL = 0.34;
55
+ const p = Math.min(1, Math.max(0, (t - (land - FALL)) / FALL));
56
+ return (1 - easeFall(p)) * H;
57
+ };
58
+
59
+ /* ---------- 线性图标(24 视框,界面按 ~2.7x 排版,描边 1.7 ≈ 屏幕 4px) ---------- */
60
+ type IconName = 'doc' | 'folder' | 'more' | 'chevR' | 'chevD' | 'home' | 'inbox' | 'building' | 'users'
61
+ | 'target' | 'search' | 'list' | 'grid' | 'square' | 'dot';
62
+ const PATHS: Record<IconName, string> = {
63
+ doc: 'M7 3h7l4 4v14H7zM14 3v4h4M9.5 12h6M9.5 15.5h6',
64
+ folder: 'M3.5 7.5a2 2 0 0 1 2-2h4l2 2h7a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2h-13a2 2 0 0 1-2-2z',
65
+ more: 'M6 12h.01M12 12h.01M18 12h.01',
66
+ chevR: 'M9.5 6l6 6-6 6',
67
+ chevD: 'M6 9.5l6 6 6-6',
68
+ home: 'M4 11l8-6.5 8 6.5M6.5 9.5V19h11V9.5',
69
+ inbox: 'M4 13.5l2.5-8h11l2.5 8v5H4zM4 13.5h4.5l1.2 2h4.6l1.2-2H20',
70
+ building: 'M5 20V5.5h9V20M14 9.5h5V20M8 9h3M8 12.5h3M8 16h3M3.5 20h17',
71
+ users: 'M9 11a3 3 0 1 0 0-6 3 3 0 0 0 0 6zM3.5 19a5.5 5.5 0 0 1 11 0M16 5.5a3 3 0 0 1 0 5.5M17.5 14a5 5 0 0 1 3 5',
72
+ target: 'M12 20a8 8 0 1 0 0-16 8 8 0 0 0 0 16zM12 16a4 4 0 1 0 0-8 4 4 0 0 0 0 8zM12 12h.01',
73
+ search: 'M11 18a7 7 0 1 0 0-14 7 7 0 0 0 0 14zM20 20l-4-4',
74
+ list: 'M8.5 6.5h11M8.5 12h11M8.5 17.5h11M4.5 6.5h.01M4.5 12h.01M4.5 17.5h.01',
75
+ grid: 'M4.5 4.5h6v6h-6zM13.5 4.5h6v6h-6zM4.5 13.5h6v6h-6zM13.5 13.5h6v6h-6z',
76
+ square: 'M5 5h14v14H5z',
77
+ dot: 'M12 12h.01',
78
+ };
79
+ const Icon: React.FC<{ name: IconName; size?: number; color?: string; sw?: number; dashed?: boolean }> = ({
80
+ name, size = 50, color = INK3, sw = 1.7, dashed,
81
+ }) => (
82
+ <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke={color} strokeWidth={name === 'more' || name === 'dot' ? 3.2 : sw}
83
+ strokeLinecap="round" strokeLinejoin="round" strokeDasharray={dashed ? '2.6 2.4' : undefined} style={{ flex: 'none' }}>
84
+ <path d={PATHS[name]} />
85
+ </svg>
86
+ );
87
+
88
+ /* 空间徽标:低饱和色块 + 字母 */
89
+ const SpaceChip: React.FC<{ letter: string; hue: string }> = ({ letter, hue }) => (
90
+ <div style={{
91
+ width: 60, height: 60, borderRadius: 16, background: hue, flex: 'none',
92
+ display: 'flex', alignItems: 'center', justifyContent: 'center',
93
+ fontFamily: SANS, fontWeight: 700, fontSize: 32, color: '#fff', letterSpacing: '-0.02em',
94
+ boxShadow: 'inset 0 2px 0 rgba(255,255,255,0.25)',
95
+ }}>{letter}</div>
96
+ );
97
+
98
+ type RowIcon = 'tri' | 'triOpen' | 'doc' | 'folder' | 'dash' | undefined;
99
+
100
+ const TreeRow: React.FC<{
101
+ depth: number; label: string; icon?: RowIcon; chip?: string; count?: string; size?: number;
102
+ }> = ({ depth, label, icon, chip, count, size = 56 }) => (
103
+ <div style={{
104
+ display: 'flex', alignItems: 'center', gap: 26, paddingLeft: 40 + depth * 90,
105
+ height: size * 2.1,
106
+ }}>
107
+ {icon === 'tri' && <Icon name="chevR" size={44} color={INK3} />}
108
+ {icon === 'triOpen' && <Icon name="chevD" size={44} color={INK2} />}
109
+ {icon === 'doc' && <Icon name="doc" color={INK3} />}
110
+ {icon === 'folder' && <Icon name="folder" color={INK3} />}
111
+ {icon === 'dash' && <Icon name="square" color={INK3} dashed />}
112
+ {chip && <SpaceChip letter={chip} hue={{ O: '#8a7cf0', C: '#4fb39a', T: '#e39a5b' }[chip] ?? '#9a9ca5'} />}
113
+ <div style={{ fontFamily: SANS, fontSize: size, color: INK, fontWeight: 500, letterSpacing: '-0.012em' }}>{label}</div>
114
+ {count && (
115
+ <div style={{
116
+ marginLeft: 'auto', marginRight: 80, fontFamily: SANS, fontSize: size * 0.78, color: INK3, fontWeight: 500,
117
+ fontVariantNumeric: 'tabular-nums',
118
+ }}>{count}</div>
119
+ )}
120
+ </div>
121
+ );
122
+
123
+ const RecentCard: React.FC<{ title: string; sub: string; meta: string; w?: number }> = ({ title, sub, meta, w = 880 }) => (
124
+ <div style={{
125
+ width: w, border: `3px solid ${LINE}`, borderRadius: 26, padding: '34px 42px',
126
+ display: 'flex', flexDirection: 'column', gap: 14, background: '#fff', boxSizing: 'border-box',
127
+ boxShadow: '0 3px 6px rgba(16,18,24,0.04), 0 18px 40px -14px rgba(16,18,24,0.12)',
128
+ }}>
129
+ <div style={{ display: 'flex', alignItems: 'center', gap: 22 }}>
130
+ <Icon name="doc" size={52} color={INK2} />
131
+ <div style={{ fontFamily: SANS, fontSize: 50, color: INK, fontWeight: 650, letterSpacing: '-0.02em' }}>{title}</div>
132
+ </div>
133
+ <div style={{ display: 'flex', alignItems: 'center', gap: 18, paddingLeft: 74, fontFamily: SANS, fontSize: 38, color: INK3 }}>
134
+ <span style={{ color: INK2 }}>{sub}</span>
135
+ <span>·</span>
136
+ <span>{meta}</span>
137
+ </div>
138
+ </div>
139
+ );
140
+
141
+ const Tabs: React.FC<{ items: string[]; size: number }> = ({ items, size }) => (
142
+ <div style={{ display: 'flex', gap: 80, fontFamily: SANS, fontSize: size, letterSpacing: '-0.012em' }}>
143
+ {items.map((it, i) => (
144
+ <div key={it} style={{ position: 'relative', color: i === 0 ? INK : INK3, fontWeight: i === 0 ? 650 : 500 }}>
145
+ {it}
146
+ {i === 0 && <div style={{ position: 'absolute', left: 0, right: 0, bottom: -22, height: 5, borderRadius: 3, background: ACC }} />}
147
+ </div>
148
+ ))}
149
+ </div>
150
+ );
151
+
152
+ const ViewSwitch: React.FC<{ size: number }> = ({ size }) => (
153
+ <div style={{ display: 'flex', gap: 30, alignItems: 'center' }}>
154
+ <div style={{
155
+ display: 'flex', alignItems: 'center', gap: 16, padding: '20px 40px', background: ACC_SOFT, borderRadius: 18,
156
+ border: '3px solid rgba(116,87,245,0.22)', fontFamily: SANS, fontSize: size, color: ACC, fontWeight: 650,
157
+ }}><Icon name="list" size={size * 0.95} color={ACC} />List</div>
158
+ <div style={{ display: 'flex', alignItems: 'center', gap: 16, fontFamily: SANS, fontSize: size, color: INK3, fontWeight: 500 }}>
159
+ <Icon name="grid" size={size * 0.95} color={INK3} />Gallery
160
+ </div>
161
+ </div>
162
+ );
163
+
164
+ /* 场景 A:侧栏 SPACES 树 + 右侧 Recent 卡
165
+ * 树行/卡片按镜头行进方向(自上而下)先后从空中落贴回界面 */
166
+ const SceneTree: React.FC<{ t?: number }> = ({ t = 1 }) => {
167
+ const L = (i: number, n = 14) => liftOf(t, 0.22 + (i / n) * 0.62, 130);
168
+ const rows: [number, string, RowIcon, string | undefined, string | undefined][] = [
169
+ [0, 'Shot recipes', 'doc', undefined, undefined],
170
+ [0, 'Storyboards', 'doc', undefined, undefined],
171
+ [0, 'Renders', 'doc', undefined, undefined],
172
+ [0, 'More', 'dash', undefined, undefined],
173
+ [0, 'Opening', 'tri', 'O', undefined],
174
+ [0, 'Camera moves', 'tri', 'C', undefined],
175
+ [0, 'Transitions', 'triOpen', 'T', undefined],
176
+ [1, 'Recipe handbook', 'doc', undefined, undefined],
177
+ [1, 'Whip pans', 'folder', undefined, undefined],
178
+ [1, 'Match cuts', 'folder', undefined, undefined],
179
+ [2, 'Match cuts', 'doc', undefined, undefined],
180
+ [2, 'Takes', 'dash', undefined, '56'],
181
+ [2, 'Demos', 'dash', undefined, '8'],
182
+ [2, 'Frames', 'dash', undefined, '256'],
183
+ ];
184
+ return (
185
+ <div style={{ width: 2900, height: 2400, background: SURF, display: 'flex' }}>
186
+ <div style={{ width: 1500, borderRight: `3px solid ${LINE}`, paddingTop: 60, background: SIDE }}>
187
+ {rows.slice(0, 4).map((r, i) => (
188
+ <FloatWrap key={r[1] + i} h={L(i)}>
189
+ <TreeRow depth={r[0]} label={r[1]} icon={r[2]} chip={r[3]} count={r[4]} />
190
+ </FloatWrap>
191
+ ))}
192
+ <div style={{ height: 90 }} />
193
+ <FloatWrap h={L(4)}>
194
+ <div style={{ paddingLeft: 48, fontFamily: SANS, fontSize: 40, letterSpacing: '0.14em', color: INK3, fontWeight: 650 }}>SPACES</div>
195
+ </FloatWrap>
196
+ <div style={{ height: 30 }} />
197
+ {rows.slice(4).map((r, i) => (
198
+ <FloatWrap key={r[1] + i} h={L(i + 4.6)}>
199
+ <TreeRow depth={r[0]} label={r[1]} icon={r[2]} chip={r[3]} count={r[4]} />
200
+ </FloatWrap>
201
+ ))}
202
+ </div>
203
+ <div style={{ flex: 1, paddingTop: 100, paddingLeft: 110 }}>
204
+ <FloatWrap h={liftOf(t, 0.3, 150)}>
205
+ <Tabs items={['Recent', 'Favorites']} size={52} />
206
+ </FloatWrap>
207
+ <div style={{ height: 70 }} />
208
+ <div style={{ display: 'flex', flexDirection: 'column', gap: 44 }}>
209
+ <FloatWrap h={liftOf(t, 0.42, 170)}>
210
+ <RecentCard title="Launch film" sub="Storyboard v3" meta="Edited 2h ago" />
211
+ </FloatWrap>
212
+ <FloatWrap h={liftOf(t, 0.55, 170)}>
213
+ <RecentCard title="Add shot · crash zoom" sub="Camera moves" meta="Yesterday" />
214
+ </FloatWrap>
215
+ </div>
216
+ <div style={{ height: 110 }} />
217
+ <FloatWrap h={liftOf(t, 0.68, 150)}>
218
+ <Tabs items={['Todo', 'Comments', 'Done']} size={50} />
219
+ </FloatWrap>
220
+ <div style={{ height: 60 }} />
221
+ <FloatWrap h={liftOf(t, 0.8, 150)}>
222
+ <ViewSwitch size={46} />
223
+ </FloatWrap>
224
+ </div>
225
+ </div>
226
+ );
227
+ };
228
+
229
+ /* 场景 B:顶部 tab 条 + 左上侧栏导航
230
+ * tab 条、video-shotcraft 字标、Home 行、侧栏项先后从空中贴落 */
231
+ const NAV: [IconName, string][] = [['inbox', 'Inbox'], ['building', 'Company'], ['users', 'People & Teams'], ['target', 'Goals'], ['doc', 'Docs']];
232
+ const SceneTopNav: React.FC<{ t?: number }> = ({ t = 1 }) => (
233
+ <div style={{ width: 3000, height: 2100, background: SURF, borderRadius: 48 }}>
234
+ <div style={{
235
+ height: 150, borderBottom: `3px solid ${LINE}`, display: 'flex', alignItems: 'center',
236
+ gap: 110, paddingLeft: 90, fontFamily: SANS, fontSize: 52, color: INK, background: SIDE, borderRadius: '48px 48px 0 0',
237
+ }}>
238
+ {['Shot recipe cards', 'Launch film', 'Beat-synced cuts', 'Render queue'].map((tb, i) => (
239
+ <FloatWrap key={tb} h={liftOf(t, 0.2 + i * 0.1, 140)}>
240
+ <div style={{
241
+ display: 'flex', alignItems: 'center', gap: 22, fontWeight: i === 1 ? 650 : 500, color: i === 1 ? INK : INK2,
242
+ letterSpacing: '-0.012em', opacity: i > 1 ? 0.8 : 1,
243
+ ...(i === 1 ? { background: '#fff', padding: '18px 34px', borderRadius: 18, border: `3px solid ${LINE}`, boxShadow: '0 6px 16px -8px rgba(16,18,24,0.18)' } : {}),
244
+ }}>
245
+ {i === 1
246
+ ? <ShotcraftMark size={40} tone="light" />
247
+ : <Icon name="doc" size={44} color={INK3} />}
248
+ {tb}
249
+ </div>
250
+ </FloatWrap>
251
+ ))}
252
+ </div>
253
+ <div style={{ display: 'flex' }}>
254
+ <div style={{ width: 1250, padding: '70px 70px 0', background: SIDE, height: 1950, boxSizing: 'border-box', borderBottomLeftRadius: 48 }}>
255
+ <FloatWrap h={liftOf(t, 0.34, 150)}>
256
+ <div style={{ display: 'flex', alignItems: 'center', gap: 28 }}>
257
+ <ShotcraftWordmark size={56} tone="light" markScale={1.5} gap={24} />
258
+ <div style={{
259
+ marginLeft: 'auto', width: 120, height: 84, border: `3px solid ${LINE}`, borderRadius: 22, background: '#fff',
260
+ display: 'flex', alignItems: 'center', justifyContent: 'center',
261
+ }}><Icon name="search" size={44} color={INK2} /></div>
262
+ </div>
263
+ </FloatWrap>
264
+ <div style={{ height: 60 }} />
265
+ <FloatWrap h={liftOf(t, 0.46, 160)}>
266
+ <div style={{
267
+ display: 'flex', alignItems: 'center', gap: 30, background: ACC_SOFT,
268
+ border: '3px solid rgba(116,87,245,0.2)', borderRadius: 24, padding: '28px 40px',
269
+ }}>
270
+ <Icon name="home" size={54} color={ACC} sw={1.9} />
271
+ <div style={{ fontFamily: SANS, fontSize: 54, color: INK, fontWeight: 650, letterSpacing: '-0.015em' }}>Home</div>
272
+ <div style={{
273
+ marginLeft: 'auto', minWidth: 62, height: 62, borderRadius: 31, background: ACC,
274
+ color: '#fff', fontFamily: SANS, fontSize: 36, fontWeight: 700, fontVariantNumeric: 'tabular-nums',
275
+ display: 'flex', alignItems: 'center', justifyContent: 'center',
276
+ }}>3</div>
277
+ </div>
278
+ </FloatWrap>
279
+ {NAV.map(([ic, tb], i) => (
280
+ <FloatWrap key={tb} h={liftOf(t, 0.55 + i * 0.08, 140)}>
281
+ <div style={{ display: 'flex', alignItems: 'center', gap: 30, height: 128, paddingLeft: 40 }}>
282
+ <Icon name={ic} size={52} color={INK3} />
283
+ <div style={{ fontFamily: SANS, fontSize: 52, color: INK2, fontWeight: 500, letterSpacing: '-0.012em' }}>{tb}</div>
284
+ </div>
285
+ </FloatWrap>
286
+ ))}
287
+ </div>
288
+ <div style={{ flex: 1, borderLeft: `3px solid ${LINE}`, padding: '70px 90px 0' }}>
289
+ <FloatWrap h={liftOf(t, 0.4, 150)}>
290
+ <div style={{ display: 'flex', alignItems: 'center', gap: 30, color: INK3, fontFamily: SANS, fontSize: 48 }}>
291
+ <Icon name="chevR" size={44} color={INK3} />
292
+ <Icon name="home" size={46} color={INK3} />
293
+ <div style={{ color: INK2, fontWeight: 500 }}>Home</div>
294
+ </div>
295
+ </FloatWrap>
296
+ <div style={{ height: 80 }} />
297
+ <FloatWrap h={liftOf(t, 0.58, 180)}>
298
+ <div style={{ fontFamily: SANS, fontSize: 128, fontWeight: 750, color: INK, letterSpacing: '-0.04em', lineHeight: 1 }}>Home</div>
299
+ </FloatWrap>
300
+ <div style={{ height: 80 }} />
301
+ <FloatWrap h={liftOf(t, 0.74, 160)}>
302
+ <div style={{
303
+ display: 'flex', alignItems: 'center', gap: 30, border: `3px solid ${LINE}`,
304
+ borderRadius: 26, padding: '32px 44px', background: '#fff', width: 1100, boxSizing: 'border-box',
305
+ boxShadow: '0 3px 6px rgba(16,18,24,0.04), 0 18px 40px -14px rgba(16,18,24,0.14)',
306
+ }}>
307
+ <Icon name="search" size={50} color={INK3} />
308
+ <div style={{ fontFamily: SANS, fontSize: 46, color: INK3 }}>Search shots, recipes…</div>
309
+ <div style={{
310
+ marginLeft: 'auto', padding: '8px 18px', borderRadius: 12, border: `3px solid ${LINE}`,
311
+ fontFamily: FONT.mono, fontSize: 34, color: INK3,
312
+ }}>⌘K</div>
313
+ </div>
314
+ </FloatWrap>
315
+ </div>
316
+ </div>
317
+ </div>
318
+ );
319
+
320
+ /* 场景 C:列表行(TODAY / TASK NAME 区)——Todo 头/TODAY 徽章/任务行自上而下先后贴落 */
321
+ const TASKS = [
322
+ { n: 'Render launch film', who: '#8a7cf0', due: 'Today', p: 0.72 },
323
+ { n: 'Add shot: crash zoom', who: '#4fb39a', due: 'Today', p: 0.45 },
324
+ { n: 'Beat-sync the cuts', who: '#e39a5b', due: 'Tomorrow', p: 0.3 },
325
+ { n: 'Export JianYing draft', who: '#6aa6e8', due: 'Fri', p: 0.86 },
326
+ ];
327
+ const SceneListRows: React.FC<{ t?: number }> = ({ t = 1 }) => (
328
+ <div style={{ width: 2900, height: 2200, background: SURF, paddingTop: 60 }}>
329
+ <FloatWrap h={liftOf(t, 0.22, 150)}>
330
+ <div style={{ paddingLeft: 120 }}><Tabs items={['Todo', 'Comments', 'Done', 'Delegated']} size={52} /></div>
331
+ </FloatWrap>
332
+ <div style={{ height: 66 }} />
333
+ <FloatWrap h={liftOf(t, 0.32, 150)}>
334
+ <div style={{ display: 'flex', alignItems: 'center', paddingLeft: 120 }}>
335
+ <ViewSwitch size={48} />
336
+ <div style={{ marginLeft: 500, display: 'flex', gap: 70, color: INK3, fontFamily: SANS, fontSize: 44, fontWeight: 500 }}>
337
+ <div>Filter</div><div>Group</div><div>Sort</div>
338
+ </div>
339
+ </div>
340
+ </FloatWrap>
341
+ <div style={{ height: 40, borderBottom: `3px solid ${LINE}`, marginLeft: 120, marginRight: 120 }} />
342
+ <div style={{ height: 60 }} />
343
+ <FloatWrap h={liftOf(t, 0.44, 160)}>
344
+ <div style={{
345
+ marginLeft: 120, display: 'inline-flex', alignItems: 'center', gap: 16, padding: '18px 40px', background: ACC_SOFT,
346
+ borderRadius: 16, fontFamily: SANS, fontSize: 40, letterSpacing: '0.12em', color: ACC, fontWeight: 700,
347
+ }}><Icon name="chevD" size={38} color={ACC} sw={2.2} />TODAY</div>
348
+ </FloatWrap>
349
+ <div style={{ height: 60 }} />
350
+ <FloatWrap h={liftOf(t, 0.54, 150)}>
351
+ <div style={{ display: 'flex', paddingLeft: 120, paddingRight: 120, fontFamily: SANS, fontSize: 38, letterSpacing: '0.12em', color: INK3, fontWeight: 600 }}>
352
+ <div>TASK NAME</div>
353
+ <div style={{ marginLeft: 'auto', width: 520 }}>PROGRESS</div>
354
+ <div style={{ width: 260, textAlign: 'right' }}>DUE</div>
355
+ </div>
356
+ </FloatWrap>
357
+ <div style={{ height: 30 }} />
358
+ {TASKS.map((tk, i) => (
359
+ <FloatWrap key={tk.n} h={liftOf(t, 0.62 + i * 0.09, 160)}>
360
+ <div style={{
361
+ display: 'flex', alignItems: 'center', gap: 40, height: 170, marginLeft: 120, marginRight: 120,
362
+ borderBottom: `3px solid ${LINE}`,
363
+ }}>
364
+ <div style={{ width: 42, height: 42, borderRadius: 13, border: `4px solid ${i === 0 ? ACC : 'rgba(20,22,28,0.22)'}`, background: i === 0 ? ACC_SOFT : 'transparent', boxSizing: 'border-box' }} />
365
+ <div style={{ fontFamily: SANS, fontSize: 56, color: INK, fontWeight: 550, letterSpacing: '-0.015em' }}>{tk.n}</div>
366
+ <div style={{ marginLeft: 'auto', width: 64, height: 64, borderRadius: 32, background: tk.who, border: '5px solid #fff', boxShadow: '0 0 0 3px rgba(20,22,28,0.06)' }} />
367
+ <div style={{ width: 400, height: 16, borderRadius: 8, background: 'rgba(20,22,28,0.07)', overflow: 'hidden' }}>
368
+ <div style={{ width: `${tk.p * 100}%`, height: '100%', borderRadius: 8, background: i === 0 ? ACC : 'rgba(20,22,28,0.28)' }} />
369
+ </div>
370
+ <div style={{ width: 220, textAlign: 'right', fontFamily: SANS, fontSize: 44, color: tk.due === 'Today' ? ACC : INK3, fontWeight: 550 }}>{tk.due}</div>
371
+ <Icon name="more" size={50} color={INK3} />
372
+ </div>
373
+ </FloatWrap>
374
+ ))}
375
+ </div>
376
+ );
377
+
378
+ /* ---------- 3D 摄影 ---------- */
379
+
380
+ type Cam = {
381
+ rx: number; ry: number; rz: number; scale: number;
382
+ x: [number, number]; y: [number, number];
383
+ };
384
+
385
+ // 巡航曲线:首段缓起(前 30% 二次加速接匀速)、末段缓落、中段匀速;u 超出 [0,1](交叉淡化
386
+ // 窗口)时按端点斜率线性外推,相机在淡化里继续飞,接力处不再刹停
387
+ const cruise = (u: number, first: boolean, last: boolean) => {
388
+ const A = 0.3;
389
+ const k = 1 / (1 - (first ? A / 2 : 0) - (last ? A / 2 : 0));
390
+ const inPart = (x: number) => (x < A ? (x * x) / (2 * A) : x - A / 2);
391
+ if (first && u <= A) return k * inPart(Math.max(0, u));
392
+ if (last && u >= 1 - A) return 1 - k * inPart(Math.max(0, 1 - u));
393
+ return first ? k * inPart(u) : k * u;
394
+ };
395
+
396
+ const Plane: React.FC<{
397
+ cam: Cam; p: number; edge?: 'left' | 'top'; children: React.ReactNode;
398
+ }> = ({ cam, p, edge = 'left', children }) => {
399
+ const x = cam.x[0] + (cam.x[1] - cam.x[0]) * p;
400
+ const y = cam.y[0] + (cam.y[1] - cam.y[0]) * p;
401
+ const roll = cam.rz + (p - 0.5) * 2; // ±1° 缓慢滚转
402
+ return (
403
+ <AbsoluteFill style={{ perspective: 1050, perspectiveOrigin: '50% 46%' }}>
404
+ <div style={{
405
+ position: 'absolute', left: '50%', top: '50%', width: 0, height: 0,
406
+ transformStyle: 'preserve-3d',
407
+ transform: `scale(${cam.scale}) rotateX(${cam.rx}deg) rotateY(${cam.ry}deg) rotateZ(${roll}deg)`,
408
+ }}>
409
+ <div style={{ position: 'absolute', transform: `translate3d(${x}px, ${y}px, 0)` }}>
410
+ <div style={{ position: 'relative', transform: 'translate(-50%, -50%)' }}>
411
+ {/* 屏幕边缘霓虹缘光:外晕 + 贴边细亮线 */}
412
+ {edge === 'left' ? (
413
+ <>
414
+ <div style={{
415
+ position: 'absolute', left: -80, top: -40, width: 120, height: '104%',
416
+ background: 'linear-gradient(185deg, #ff7ab8, #a46cff 55%, #6a4dff)',
417
+ filter: 'blur(70px)', opacity: 0.85,
418
+ }} />
419
+ <div style={{
420
+ position: 'absolute', left: -7, top: 0, width: 6, height: '100%', borderRadius: 3,
421
+ background: 'linear-gradient(180deg, #ffc2de, #b99bff)', filter: 'blur(2px)', opacity: 0.95,
422
+ }} />
423
+ </>
424
+ ) : (
425
+ <>
426
+ <div style={{
427
+ position: 'absolute', left: -40, top: -80, width: '104%', height: 120,
428
+ background: 'linear-gradient(90deg, #ff7ab8, #a46cff 55%, #6a4dff)',
429
+ filter: 'blur(70px)', opacity: 0.8,
430
+ }} />
431
+ <div style={{
432
+ position: 'absolute', left: 48, top: -7, width: 'calc(100% - 96px)', height: 6, borderRadius: 3,
433
+ background: 'linear-gradient(90deg, #ffc2de, #b99bff)', filter: 'blur(2px)', opacity: 0.9,
434
+ }} />
435
+ </>
436
+ )}
437
+ {children}
438
+ {/* 远端压暗:贴面透视里远处渐暗(比 v2 轻,亮面不发脏) */}
439
+ <div style={{
440
+ position: 'absolute', inset: 0,
441
+ background: edge === 'left'
442
+ ? 'linear-gradient(105deg, rgba(8,6,18,0) 34%, rgba(8,6,18,0.22) 75%, rgba(8,6,18,0.5) 100%)'
443
+ : 'linear-gradient(175deg, rgba(8,6,18,0) 38%, rgba(8,6,18,0.2) 80%, rgba(8,6,18,0.45) 100%)',
444
+ pointerEvents: 'none',
445
+ }} />
446
+ </div>
447
+ </div>
448
+ </div>
449
+ </AbsoluteFill>
450
+ );
451
+ };
452
+
453
+ /* 背景霓虹框(暗场道具):发光细描边,随镜头行进反向视差漂移 */
454
+ const NeonRects: React.FC<{ drift: number }> = ({ drift }) => {
455
+ const box = (c: string, a: number): React.CSSProperties => ({
456
+ position: 'absolute', borderRadius: 32, border: `3px solid ${c}`, opacity: a,
457
+ boxShadow: `0 0 24px ${c}, inset 0 0 18px ${c}`, filter: 'blur(3px)',
458
+ });
459
+ return (
460
+ <AbsoluteFill style={{ overflow: 'hidden' }}>
461
+ <div style={{ ...box('#b04dff', 0.42), left: -140 + drift * 60, top: 240, width: 620, height: 380 }} />
462
+ <div style={{ ...box('#ff4da8', 0.32), left: 60 + drift * 36, top: 700, width: 420, height: 260 }} />
463
+ <div style={{ ...box('#7b4dff', 0.3), right: -180 - drift * 44, top: -80, width: 560, height: 340 }} />
464
+ </AbsoluteFill>
465
+ );
466
+ };
467
+
468
+ // 平移目标以内容坐标 (cx,cy) 给出:translate = (W/2-cx, H/2-cy)
469
+ const SEGS: { cam: Cam; edge: 'left' | 'top'; render: (t: number) => React.ReactNode }[] = [
470
+ {
471
+ // 侧栏树:从树顶(SPACES 附近)贴面滑到树底(Components/Patterns/Tokens)
472
+ cam: { rx: 12, ry: 30, rz: -6, scale: 0.95, x: [1450 - 950, 1450 - 880], y: [1200 - 1050, 1200 - 1850] },
473
+ edge: 'left', render: (t) => <SceneTree t={t} />,
474
+ },
475
+ {
476
+ // 顶栏 tab 条 → 右区 Home 大标题
477
+ cam: { rx: 20, ry: -20, rz: 6, scale: 0.95, x: [1500 - 800, 1500 - 2000], y: [1050 - 350, 1050 - 800] },
478
+ edge: 'top', render: (t) => <SceneTopNav t={t} />,
479
+ },
480
+ {
481
+ // 列表行:沿 TASK NAME 行右扫
482
+ cam: { rx: 14, ry: 28, rz: -5, scale: 1.05, x: [1450 - 900, 1450 - 680], y: [1100 - 620, 1100 - 1240] },
483
+ edge: 'left', render: (t) => <SceneListRows t={t} />,
484
+ },
485
+ ];
486
+
487
+ const SEG_LEN = 50; // 每段 50 帧,总 150
488
+ const FADE = 7;
489
+
490
+ const Stage: React.FC = () => {
491
+ const frame = useCurrentFrame();
492
+ return (
493
+ <AbsoluteFill style={{ background: '#07060c' }}>
494
+ {SEGS.map((s, i) => {
495
+ const start = i * SEG_LEN;
496
+ const local = frame - start;
497
+ if (local < -FADE || local > SEG_LEN + FADE) return null;
498
+ const u = local / SEG_LEN; // 不钳:淡化窗口里相机继续外推
499
+ const t = Math.min(1, Math.max(0, u)); // 内容(贴落进度)照旧钳位
500
+ const p = cruise(u, i === 0, i === SEGS.length - 1);
501
+ // 相邻段交叉淡化:后段在边界前 [-FADE,0] 淡入、前段在 [SEG_LEN-FADE, SEG_LEN] 淡出,边界帧无纯黑
502
+ const fadeIn = i === 0 ? 1 : Math.min(1, Math.max(0, (local + FADE) / FADE));
503
+ const fadeOut = i === SEGS.length - 1 ? 1 : Math.min(1, Math.max(0, (SEG_LEN - local) / FADE));
504
+ return (
505
+ <AbsoluteFill key={i} style={{ opacity: Math.min(fadeIn, fadeOut) }}>
506
+ <NeonRects drift={p} />
507
+ <Plane cam={s.cam} p={p} edge={s.edge}>{s.render(t)}</Plane>
508
+ </AbsoluteFill>
509
+ );
510
+ })}
511
+ </AbsoluteFill>
512
+ );
513
+ };
514
+
515
+ export const GrazeFaceTour: React.FC = () => {
516
+ const frame = useCurrentFrame();
517
+ // 浅景深焦点带:焦点椭圆随段落平滑移动(段间 10f 过渡,不跳)
518
+ const FX = [44, 40, 46];
519
+ const FY = [46, 40, 50];
520
+ const k1 = Math.min(1, Math.max(0, (frame - SEG_LEN + 5) / 10));
521
+ const k2 = Math.min(1, Math.max(0, (frame - 2 * SEG_LEN + 5) / 10));
522
+ const kk = k1 + k2; // 0→1→2:段 A→B→C 的焦点
523
+ const lerpArr = (a: number[]) => (kk <= 1 ? a[0] + (a[1] - a[0]) * kk : a[1] + (a[2] - a[1]) * (kk - 1));
524
+ const focusX = lerpArr(FX);
525
+ const focusY = lerpArr(FY);
526
+ return (
527
+ <AbsoluteFill style={{ background: '#07060c' }}>
528
+ <Stage />
529
+ {/* 屏幕空间浅景深:焦点带外整体模糊 */}
530
+ <AbsoluteFill style={{
531
+ filter: 'blur(15px)',
532
+ WebkitMaskImage: `radial-gradient(ellipse 58% 52% at ${focusX}% ${focusY}%, transparent 34%, rgba(0,0,0,0.85) 72%, black 92%)`,
533
+ maskImage: `radial-gradient(ellipse 58% 52% at ${focusX}% ${focusY}%, transparent 34%, rgba(0,0,0,0.85) 72%, black 92%)`,
534
+ }}>
535
+ <Stage />
536
+ </AbsoluteFill>
537
+ {/* 带色相的暗角(不再把亮面压成灰)+ 暗场颗粒 */}
538
+ <Vignette strength={0.62} inner={0.42} color="#06040e" cx={focusX / 100} cy={focusY / 100} />
539
+ <Grain opacity={0.06} blend="soft-light" />
540
+ </AbsoluteFill>
541
+ );
542
+ };