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,389 +1,389 @@
1
- // orbit-ring-title-open — 环形卡阵标题开场
2
- // 八张 16:9 内容卡按 45° 均布在椭圆上匀速公转(卡身永不倾斜,纵深只由 sin(θ) 给出缩放、
3
- // z 序、景深与明暗),入场期卡内容冻结首帧、环撑开落定后统一开播;居中标题逐字解糊下沉落定,
4
- // 关键词全部到位那一刻荧光马克块自左横扫铺满(扫过处字色反白为墨),mono 副行随后浮出。
5
- //
6
- // 第二轮重设计(石墨夜 · 荧光笔):
7
- // - look = lime:石墨暗场 + 荧光黄绿。马克块从"黄色便利贴"变成一支荧光笔——暗场里唯一的高饱和色块,
8
- // 只给关键词「每一个动效」。八张卡全部换成暗色产品卡(深石墨底 + 发丝线 + 顶部内高光),
9
- // 卡内小动效统一用荧光绿做唯一强调,卡内字只做纹理(读的是标题)。
10
- // - 标题从 64px 单行改成两级:上行 64px 次级灰「让镜头卡替你想好」,下行 156px「每一个动效」做主角;
11
- // 马克块扫过时用两层裁切让字从白翻成墨色(反白在块的前沿同步发生,读作"被荧光笔划过")。
12
- // - 空间:椭圆轨道本身画成一圈极淡的发丝线(入场时描出来),卡的纵深除了 ±12% 缩放,
13
- // 远处(上方)的卡再压暗 + 轻微失焦,近处(下方)全亮全清——环有前后,标题在焦平面上。
14
- // 标题后垫一团暗色 scrim,保证卡从背后经过时标题始终压得住。
15
- // - 收尾:原版末段整行失焦退场做交棒;单镜头演示改为停在完整海报(HANDOFF_EXIT 开关保留退场逻辑)。
16
- //
17
- // 时间表(30fps,共 150f):
18
- // 0–24 环从 0.62 撑开到满径(snappy)+ 逐卡淡入;轨道发丝线 0–30 描出
19
- // 24 八张卡同时开播(冻结首帧 → 正常时间轴)
20
- // 10–40 上行逐字解糊下沉(错峰 1f)
21
- // 18–52 下行大字逐字解糊下沉(错峰 2f,更重更慢)
22
- // 50–64 荧光马克块横扫(弹簧,damping 20),扫过处字反白为墨
23
- // 60–76 副行(标志 + video-shotcraft + mono 代号)浮出
24
- // 76–150 hold:环持续匀速公转 + 整体极缓推近 2.5%;最后 2.5s 是一张完整海报
25
- import React from 'react';
26
- import { AbsoluteFill, Easing, Freeze, interpolate, useCurrentFrame, useVideoConfig } from 'remotion';
27
- import { EASE, FONT, ramp } from '../../_fixtures/Polish';
28
- import { LOOKS, Stage, alpha, springAt } from '../../_fixtures/Look';
29
- import { BRAND, ShotcraftMark } from '../../_fixtures/Brand';
30
-
31
- export const ORBIT_RING_TITLE_OPEN_DURATION = 150; // 5s @30fps
32
-
33
- const L = LOOKS.lime;
34
- const LIME = L.accent;
35
-
36
- // ---- 环 ----
37
- const RX = 720; // 椭圆长半轴
38
- const RY = 380; // 椭圆短半轴(RY/RX≈0.53 → 读作俯视的环,不是正圆转盘)
39
- const CW = 400; // 卡宽(16:9)
40
- const CH = 225;
41
- const N = 8;
42
- const ROT_SPEED = 0.3; // rad/s,正值 = 顺时针
43
- const RING_IN = 24; // f:从中心撑开到满径
44
- const RING_SCALE_FROM = 0.62;
45
- const PLAY_START = 24; // f:环撑开后卡内容才开播
46
- const DEPTH_SCALE = 0.12; // 近大远小幅度(底部近、顶部远)
47
-
48
- // ---- 标题 ----
49
- const LINE1 = '让镜头卡替你想好';
50
- const LINE2 = '每一个动效';
51
- const S1 = 64;
52
- const S2 = 156;
53
- const MARKER_AT = 50; // 下行末字视觉到位那一刻起扫
54
- // 副行 = video-shotcraft 标志 + 小写字标 + mono 产品代号(不写卡片数:会过时)
55
- const KICKER = 'SHOT RECIPE CARDS';
56
- const HANDOFF_EXIT = false; // true = 末段整行失焦淡出、环继续转着交棒下一镜(成片里接下一镜时打开)
57
- const EXIT_AT = 118;
58
-
59
- const SANS = `${FONT.sans.replace('Arial, sans-serif', '')}"PingFang SC", "Hiragino Sans GB", sans-serif`;
60
- const MONO = FONT.mono;
61
- const INK = L.ink;
62
- const DIM = '#8d937f';
63
-
64
- // ── 卡内占位内容(暗色产品卡,960×540 作画后整体缩到卡宽)──────────────────
65
- const F = (frame: number, a: number, b: number, ease = Easing.out(Easing.cubic)) =>
66
- interpolate(frame, [a, b], [0, 1], { extrapolateLeft: 'clamp', extrapolateRight: 'clamp', easing: ease });
67
-
68
- const Pad: React.FC<{ children: React.ReactNode; bg?: string }> = ({ children, bg = L.surface }) => (
69
- <div style={{ position: 'absolute', inset: 0, background: bg, padding: 60, fontFamily: SANS, boxSizing: 'border-box' }}>{children}</div>
70
- );
71
-
72
- const T: React.FC<{ size: number; color?: string; weight?: number; mono?: boolean; style?: React.CSSProperties; children: React.ReactNode }> = ({
73
- size, color = INK, weight = 500, mono, style, children,
74
- }) => (
75
- <div style={{
76
- fontSize: size, color, fontWeight: weight, fontFamily: mono ? MONO : SANS,
77
- letterSpacing: mono ? 0 : size >= 40 ? '-0.035em' : '-0.01em', lineHeight: 1.2, whiteSpace: 'nowrap', ...style,
78
- }}>{children}</div>
79
- );
80
- const Caps: React.FC<{ children: React.ReactNode; color?: string }> = ({ children, color = DIM }) => (
81
- <div style={{ fontSize: 24, fontWeight: 650, letterSpacing: '0.16em', color }}>{children}</div>
82
- );
83
-
84
- /** 1 荧光笔扫读 */
85
- const TileSweep: React.FC = () => {
86
- const f = useCurrentFrame();
87
- const s = F(f, 14, 32, EASE.snappy);
88
- return (
89
- <Pad>
90
- <Caps>RELEASE NOTES · 4.2</Caps>
91
- <div style={{ position: 'relative', display: 'inline-block', marginTop: 40 }}>
92
- <div style={{ position: 'absolute', left: -12, right: -12, top: 4, bottom: 0, background: LIME, borderRadius: 4, transformOrigin: 'left center', transform: `scaleX(${s})` }} />
93
- <T size={58} weight={700} color={s > 0.6 ? L.onAccent : INK} style={{ position: 'relative' }}>Motion, considered.</T>
94
- </div>
95
- <T size={30} color={DIM} weight={450} style={{ marginTop: 34 }}>Every card ships with timing, easing</T>
96
- <T size={30} color={DIM} weight={450} style={{ marginTop: 8 }}>and a validated reference build.</T>
97
- </Pad>
98
- );
99
- };
100
-
101
- /** 2 指标 + sparkline 描线 */
102
- const SPARK = 'M8 118 L118 92 L228 104 L338 56 L448 68 L558 20 L632 34';
103
- const TileMetric: React.FC = () => {
104
- const f = useCurrentFrame();
105
- const draw = F(f, 10, 46, EASE.smooth);
106
- const val = 128 + Math.round(F(f, 8, 40, Easing.out(Easing.quad)) * 84);
107
- const chip = F(f, 34, 46);
108
- return (
109
- <Pad>
110
- <div style={{ display: 'flex', alignItems: 'center', gap: 18 }}>
111
- <Caps>RENDERS / DAY</Caps>
112
- <div style={{ fontSize: 24, fontWeight: 650, color: L.onAccent, background: LIME, padding: '4px 12px', borderRadius: 999, opacity: chip, transform: `translateY(${(1 - chip) * 8}px)` }}>+18.4%</div>
113
- </div>
114
- <div style={{ fontSize: 140, fontWeight: 700, color: INK, letterSpacing: '-0.045em', fontVariantNumeric: 'tabular-nums', lineHeight: 1.1, fontFamily: SANS }}>{val}</div>
115
- <svg width={640} height={140} viewBox="0 0 640 140" style={{ marginTop: 8, overflow: 'visible' }}>
116
- <defs>
117
- <linearGradient id="orto-area" x1="0" y1="0" x2="0" y2="1">
118
- <stop offset="0" stopColor={LIME} stopOpacity={0.28} />
119
- <stop offset="1" stopColor={LIME} stopOpacity={0} />
120
- </linearGradient>
121
- </defs>
122
- <path d={`${SPARK} L632 140 L8 140 Z`} fill="url(#orto-area)" opacity={draw} />
123
- <path d={SPARK} fill="none" stroke="rgba(220,255,170,0.12)" strokeWidth={8} strokeLinecap="round" strokeLinejoin="round" />
124
- <path d={SPARK} fill="none" stroke={LIME} strokeWidth={8} strokeLinecap="round" strokeLinejoin="round" pathLength={1} strokeDasharray={1} strokeDashoffset={1 - draw} />
125
- </svg>
126
- </Pad>
127
- );
128
- };
129
-
130
- /** 3 竖向步骤清单逐条勾选 */
131
- const STEPS = ['Draft the storyboard', 'Pick shot cards', 'Tune easing curves', 'Render & review'];
132
- const TileSteps: React.FC = () => {
133
- const f = useCurrentFrame();
134
- return (
135
- <Pad bg={L.surface2}>
136
- <div style={{ display: 'flex', flexDirection: 'column', gap: 32 }}>
137
- {STEPS.map((label, i) => {
138
- const on = F(f, 8 + i * 9, 22 + i * 9);
139
- const tick = F(f, 12 + i * 9, 22 + i * 9, EASE.overshoot);
140
- return (
141
- <div key={i} style={{ display: 'flex', alignItems: 'center', gap: 26 }}>
142
- <div style={{
143
- width: 46, height: 46, borderRadius: 23, flex: 'none', boxSizing: 'border-box',
144
- background: on > 0.6 ? LIME : 'transparent', border: on > 0.6 ? 'none' : '3px solid rgba(220,255,170,0.18)',
145
- display: 'flex', alignItems: 'center', justifyContent: 'center',
146
- }}>
147
- <svg width={26} height={26} viewBox="0 0 24 24" style={{ transform: `scale(${tick})` }}>
148
- <path d="M5 12.5 L10 17 L19 7.5" fill="none" stroke={L.onAccent} strokeWidth={3.2} strokeLinecap="round" strokeLinejoin="round" />
149
- </svg>
150
- </div>
151
- <T size={38} weight={on > 0.6 ? 600 : 500} color={on > 0.6 ? INK : '#5f6556'}>{label}</T>
152
- </div>
153
- );
154
- })}
155
- </div>
156
- </Pad>
157
- );
158
- };
159
-
160
- /** 4 路线描线 + 落点钉针(暗网格地图底) */
161
- const ROUTE = 'M40 380 C 200 380 190 210 340 200 C 500 190 500 90 700 70';
162
- const TileRoute: React.FC = () => {
163
- const f = useCurrentFrame();
164
- const draw = F(f, 6, 42, EASE.smooth);
165
- const pin = springAt(f, 36, { damping: 12 });
166
- const tag = F(f, 42, 54);
167
- return (
168
- <Pad bg={L.surface2}>
169
- <div style={{ position: 'absolute', inset: 0, backgroundImage: 'linear-gradient(rgba(220,255,170,0.06) 2px, transparent 2px), linear-gradient(90deg, rgba(220,255,170,0.06) 2px, transparent 2px)', backgroundSize: '80px 80px' }} />
170
- <svg width={848} height={428} viewBox="0 0 848 428" style={{ position: 'relative', overflow: 'visible' }}>
171
- <path d={ROUTE} fill="none" stroke="rgba(220,255,170,0.14)" strokeWidth={10} strokeLinecap="round" />
172
- <path d={ROUTE} fill="none" stroke={LIME} strokeWidth={10} strokeLinecap="round" pathLength={1} strokeDasharray={1} strokeDashoffset={1 - draw} />
173
- <circle cx={40} cy={380} r={14} fill={L.surface2} stroke={LIME} strokeWidth={6} />
174
- <g transform={`translate(700 70) scale(${pin})`}>
175
- <circle r={36} fill={alpha(LIME, 0.2)} />
176
- <circle r={24} fill={LIME} />
177
- <circle r={9} fill={L.onAccent} />
178
- </g>
179
- </svg>
180
- <div style={{ position: 'absolute', left: 470, top: 64, padding: '10px 18px', borderRadius: 12, background: '#262a20', boxShadow: '0 0 0 2px rgba(220,255,170,0.1), 0 10px 24px rgba(0,0,0,0.4)', opacity: tag, transform: `translateY(${(1 - tag) * 10}px)` }}>
181
- <T size={28} weight={600}>ETA 12 min</T>
182
- </div>
183
- </Pad>
184
- );
185
- };
186
-
187
- /** 5 终端打字(打字是机械匀速语义,逐字线性揭示) */
188
- const TERM = [
189
- { t: '$ npx remotion render Open', c: '#e8ecdf' },
190
- { t: '✓ Bundled in 2.1s', c: LIME },
191
- { t: ' Rendering frames 0–149', c: '#8d937f' },
192
- { t: '✓ Done → out/open.mp4', c: LIME },
193
- ];
194
- const TileTerminal: React.FC = () => {
195
- const f = useCurrentFrame();
196
- return (
197
- <Pad bg="#0b0c09">
198
- <div style={{ display: 'flex', gap: 14, marginBottom: 34 }}>
199
- {[0.5, 0.3, 0.2].map((o, i) => <div key={i} style={{ width: 20, height: 20, borderRadius: 10, background: `rgba(220,255,170,${o})` }} />)}
200
- </div>
201
- <div style={{ display: 'flex', flexDirection: 'column', gap: 18 }}>
202
- <T size={30} mono color={LIME}>~/shotcraft</T>
203
- {TERM.map((row, i) => {
204
- const p = F(f, 8 + i * 11, 20 + i * 11, Easing.linear);
205
- const n = Math.round(row.t.length * p);
206
- return <T key={i} size={30} mono color={row.c} style={{ height: 37 }}>{row.t.slice(0, n)}</T>;
207
- })}
208
- </div>
209
- </Pad>
210
- );
211
- };
212
-
213
- /** 6 线稿描画(点阵纸底) */
214
- const SKETCH = ['M80 380 L768 380', 'M140 380 L200 90 L648 90 L708 380', 'M280 90 L280 380', 'M500 90 L500 380'];
215
- const TileSketch: React.FC = () => {
216
- const f = useCurrentFrame();
217
- return (
218
- <Pad>
219
- <div style={{ position: 'absolute', inset: 0, backgroundImage: 'radial-gradient(circle, rgba(220,255,170,0.14) 2px, transparent 2.5px)', backgroundSize: '40px 40px' }} />
220
- <svg width={848} height={428} viewBox="0 0 848 428" style={{ position: 'relative' }}>
221
- {SKETCH.map((d, i) => <path key={`g${i}`} d={d} fill="none" stroke="rgba(220,255,170,0.12)" strokeWidth={7} strokeLinecap="round" />)}
222
- {SKETCH.map((d, i) => {
223
- const p = F(f, 6 + i * 10, 24 + i * 10, EASE.smooth);
224
- return <path key={i} d={d} fill="none" stroke={i === 1 ? LIME : INK} strokeWidth={7} strokeLinecap="round" strokeLinejoin="round" pathLength={1} strokeDasharray={1} strokeDashoffset={1 - p} />;
225
- })}
226
- </svg>
227
- </Pad>
228
- );
229
- };
230
-
231
- /** 7 卡片缩成胶囊(主体让位) */
232
- const TileShrink: React.FC = () => {
233
- const f = useCurrentFrame();
234
- const p = F(f, 16, 44, EASE.smooth);
235
- const cont = F(f, 28, 50);
236
- return (
237
- <Pad bg={L.surface2}>
238
- <div style={{
239
- position: 'absolute', left: 60, top: 60, width: 840 - 690 * p, height: 420 - 342 * p, borderRadius: 16 + 30 * p,
240
- background: '#262a20', boxShadow: '0 0 0 2px rgba(220,255,170,0.08), 0 12px 28px rgba(0,0,0,0.35)', overflow: 'hidden',
241
- display: 'flex', alignItems: p > 0.6 ? 'center' : 'flex-start', justifyContent: p > 0.6 ? 'center' : 'flex-start',
242
- padding: p > 0.6 ? 0 : 40, boxSizing: 'border-box',
243
- }}>
244
- {p <= 0.6 ? (
245
- <div style={{ opacity: 1 - p / 0.6 }}>
246
- <Caps>WEEKLY SUMMARY</Caps>
247
- <T size={46} weight={700} style={{ marginTop: 18 }}>12 shots approved</T>
248
- <T size={28} color={DIM} weight={450} style={{ marginTop: 10 }}>3 pending review · 1 re-render</T>
249
- </div>
250
- ) : (
251
- <T size={30} weight={600} color={LIME} style={{ opacity: (p - 0.6) / 0.4 }}>Summary</T>
252
- )}
253
- </div>
254
- <div style={{ position: 'absolute', left: 260, top: 150, opacity: cont, transform: `translateX(${(1 - cont) * 24}px)` }}>
255
- <T size={48} weight={700}>Q3 launch plan</T>
256
- <T size={28} color={DIM} weight={450} style={{ marginTop: 14 }}>Owner · Studio team</T>
257
- <T size={28} color={DIM} weight={450} style={{ marginTop: 6 }}>Due Oct 18</T>
258
- </div>
259
- </Pad>
260
- );
261
- };
262
-
263
- /** 8 冲击字卡 */
264
- const TileImpact: React.FC = () => {
265
- const f = useCurrentFrame();
266
- const p = springAt(f, 8, { damping: 13, mass: 0.7 });
267
- return (
268
- <Pad bg="#0f110c">
269
- <div style={{ position: 'absolute', inset: 0, display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', gap: 22 }}>
270
- <div style={{ fontSize: 30, fontWeight: 650, color: LIME, letterSpacing: '0.4em', fontFamily: SANS }}>2026 · Q3</div>
271
- <div style={{ fontSize: 150, fontWeight: 850, letterSpacing: '-0.05em', color: INK, fontFamily: SANS, transform: `scale(${0.72 + p * 0.28})`, opacity: Math.min(1, p) }}>GO LIVE</div>
272
- </div>
273
- </Pad>
274
- );
275
- };
276
-
277
- const TILES: React.FC[] = [TileSweep, TileShrink, TileMetric, TileRoute, TileSteps, TileTerminal, TileSketch, TileImpact];
278
-
279
- // ── 标题逐字:位移只占前 1/3,解糊走满(同起不同终 = blur-slide 的手感)──
280
- const charStyle = (frame: number, at: number, size: number, dur: number): React.CSSProperties => {
281
- const pMain = ramp(frame, at, dur, EASE.out);
282
- const pTravel = ramp(frame, at, dur / 3, EASE.out);
283
- return {
284
- display: 'inline-block', whiteSpace: 'pre', transformOrigin: '50% 55%', opacity: pMain,
285
- filter: pMain < 1 ? `blur(${((1 - pMain) * (size / 6)).toFixed(2)}px)` : undefined,
286
- transform: `translateY(${((1 - pTravel) * size * 0.22).toFixed(2)}px)`,
287
- };
288
- };
289
-
290
- // ── 主体 ───────────────────────────────────────────────────────────────────
291
- export const OrbitRingTitleOpen: React.FC = () => {
292
- const frame = useCurrentFrame();
293
- const { fps } = useVideoConfig();
294
- const t = frame / fps;
295
-
296
- const ringIn = ramp(frame, 0, RING_IN, EASE.snappy);
297
- const ringScale = RING_SCALE_FROM + (1 - RING_SCALE_FROM) * ringIn;
298
- const rot = t * ROT_SPEED;
299
- const track = ramp(frame, 0, 30, EASE.out);
300
- const push = 1 + 0.025 * ramp(frame, 40, 110, EASE.smooth); // hold 段极缓推近
301
-
302
- const marker = Math.min(1.03, springAt(frame, MARKER_AT, { damping: 20, stiffness: 190 }));
303
- const kickerIn = ramp(frame, 60, 16, EASE.out);
304
- const exitQ = HANDOFF_EXIT ? ramp(frame, EXIT_AT, 10, EASE.exit) : 0;
305
- const titleExit: React.CSSProperties = { opacity: 1 - exitQ, filter: exitQ > 0.01 ? `blur(${(exitQ * 6.5).toFixed(2)}px)` : undefined };
306
-
307
- const l1 = Array.from(LINE1);
308
- const l2 = Array.from(LINE2);
309
- const line2 = (color: string) => l2.map((ch, j) => <span key={j} style={{ ...charStyle(frame, 18 + j * 2, S2, 32), color }}>{ch}</span>);
310
- // 马克块比字宽出左右各 0.14em:块前沿在字盒里的位置 = (m·(W+0.28em) − 0.14em) / W,W ≈ 5.05em
311
- const edge = Math.min(1, Math.max(0, (Math.min(1, marker) * 5.33 - 0.14) / 5.05));
312
- const clipR = ((1 - edge) * 100).toFixed(2);
313
- const clipL = (edge * 100).toFixed(2);
314
-
315
- return (
316
- <AbsoluteFill style={{ background: L.bg[1], fontFamily: SANS }}>
317
- <Stage look={L} keyLight={{ x: 0.5, y: 0.0 }} fill={null} intensity={0.5} vignette={0.62}>
318
- {/* 标题背后的暗 scrim:卡从背后经过时标题始终压得住 */}
319
- <div style={{ position: 'absolute', left: 360, top: 300, width: 1200, height: 480, background: `radial-gradient(ellipse 50% 50% at 50% 50%, ${alpha('#050604', 0.75)} 0%, ${alpha('#050604', 0)} 70%)` }} />
320
- </Stage>
321
-
322
- <AbsoluteFill style={{ transform: `scale(${push})` }}>
323
- {/* 椭圆轨道发丝线:入场时描出来,给环一个看得见的几何 */}
324
- <svg width={1920} height={1080} style={{ position: 'absolute', inset: 0 }}>
325
- <ellipse cx={960} cy={540} rx={RX * ringScale} ry={RY * ringScale} fill="none" stroke={alpha(LIME, 0.16)} strokeWidth={1.5}
326
- pathLength={1} strokeDasharray="1" strokeDashoffset={1 - track} />
327
- </svg>
328
-
329
- {TILES.map((Comp, i) => {
330
- const theta = -Math.PI / 2 + (i * Math.PI * 2) / N + rot;
331
- const x = 960 + Math.cos(theta) * RX * ringScale;
332
- const y = 540 + Math.sin(theta) * RY * ringScale;
333
- const depth = Math.sin(theta); // +1 = 画面下方(近),−1 = 上方(远)
334
- const s = 1 + DEPTH_SCALE * depth;
335
- const op = ramp(frame, 2 + i * 1.5, 11, EASE.out);
336
- const grow = 0.9 + 0.1 * op;
337
- const far = Math.max(0, -depth); // 远处:压暗 + 轻微失焦
338
- const elev = 14 + 12 * depth;
339
- return (
340
- <div key={i} style={{
341
- position: 'absolute', left: x - (CW * s) / 2, top: y - (CH * s) / 2, width: CW * s, height: CH * s,
342
- borderRadius: 14, overflow: 'hidden', opacity: op, transform: `scale(${grow})`, zIndex: 10 + Math.round(depth * 5),
343
- boxShadow: `inset 0 1px 0 rgba(255,255,255,0.08), 0 0 0 1px ${L.line}, 0 ${(elev * 0.6).toFixed(1)}px ${(elev * 1.6).toFixed(1)}px rgba(0,0,0,${(0.45 + 0.2 * depth).toFixed(2)})`,
344
- filter: far > 0.05 ? `blur(${(far * 1.6).toFixed(2)}px)` : undefined,
345
- }}>
346
- {/* 卡内按 960×540 作画再整体缩到卡宽——内容组件不需要知道自己被缩小了 */}
347
- <div style={{ position: 'absolute', left: 0, top: 0, width: 960, height: 540, transform: `scale(${(CW * s) / 960})`, transformOrigin: 'top left' }}>
348
- <Freeze frame={Math.max(0, frame - PLAY_START)}>
349
- <Comp />
350
- </Freeze>
351
- </div>
352
- {/* 纵深明暗:远处压暗、近处带一点顶光 */}
353
- <div style={{ position: 'absolute', inset: 0, background: `linear-gradient(180deg, rgba(255,255,255,${(0.04 * Math.max(0, depth)).toFixed(3)}) 0%, rgba(5,6,4,${(0.5 * far).toFixed(3)}) 100%), rgba(5,6,4,${(0.25 * far).toFixed(3)})` }} />
354
- </div>
355
- );
356
- })}
357
-
358
- {/* 卡与标题之间的暗 scrim(在卡之上、字之下):近处卡从标题背后经过时被压暗,字始终压得住 */}
359
- <div style={{ position: 'absolute', left: 260, top: 250, width: 1400, height: 560, zIndex: 25, background: `radial-gradient(ellipse 50% 50% at 50% 50%, ${alpha('#060705', 0.82)} 0%, ${alpha('#060705', 0.55)} 45%, ${alpha('#060705', 0)} 72%)` }} />
360
-
361
- {/* 标题:上行次级灰、下行主角大字 + 荧光马克 */}
362
- <div style={{ position: 'absolute', left: 0, right: 0, top: 336, textAlign: 'center', zIndex: 30, ...titleExit }}>
363
- <div style={{ fontSize: S1, fontWeight: 500, letterSpacing: '0.02em', color: '#b7bdaa', whiteSpace: 'nowrap', lineHeight: 1 }}>
364
- {l1.map((ch, i) => <span key={i} style={charStyle(frame, 10 + i, S1, 27)}>{ch}</span>)}
365
- </div>
366
- <div style={{ marginTop: 34, display: 'inline-block', position: 'relative', fontSize: S2, fontWeight: 600, letterSpacing: '0.01em', lineHeight: 1.12, whiteSpace: 'nowrap' }}>
367
- {/* 马克块:自左横扫铺满(垫在字下) */}
368
- <span aria-hidden style={{
369
- position: 'absolute', left: '-0.14em', right: '-0.14em', top: '0.1em', bottom: '0.04em', background: LIME, borderRadius: 8,
370
- transformOrigin: 'left center', transform: `scaleX(${marker.toFixed(4)})`, boxShadow: marker > 0.02 ? `0 0 60px ${alpha(LIME, 0.28)}` : undefined,
371
- }} />
372
- {/* 两层字:块的前沿左边是墨色、右边是白色——扫过即反白 */}
373
- <span style={{ position: 'relative', display: 'inline-block', clipPath: `inset(-20% 0 -20% ${clipL}%)`, color: INK }}>{line2(INK)}</span>
374
- <span aria-hidden style={{ position: 'absolute', left: 0, top: 0, display: 'inline-block', clipPath: `inset(-20% ${clipR}% -20% 0)` }}>{line2(L.onAccent)}</span>
375
- </div>
376
- <div style={{
377
- marginTop: 40, display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 16, whiteSpace: 'pre',
378
- opacity: kickerIn, transform: `translateY(${((1 - kickerIn) * 12).toFixed(2)}px)`,
379
- }}>
380
- <ShotcraftMark size={44} tone="dark" />
381
- <span style={{ fontFamily: BRAND.font, fontSize: 30, fontWeight: 700, letterSpacing: '0.03em', color: INK, lineHeight: 1 }}>{BRAND.name}</span>
382
- <span style={{ fontFamily: MONO, fontSize: 26, fontWeight: 600, color: DIM, lineHeight: 1 }}>·</span>
383
- <span style={{ fontFamily: MONO, fontSize: 26, fontWeight: 600, letterSpacing: '0.2em', marginRight: '-0.2em', color: DIM, lineHeight: 1 }}>{KICKER}</span>
384
- </div>
385
- </div>
386
- </AbsoluteFill>
387
- </AbsoluteFill>
388
- );
389
- };
1
+ // orbit-ring-title-open — 环形卡阵标题开场
2
+ // 八张 16:9 内容卡按 45° 均布在椭圆上匀速公转(卡身永不倾斜,纵深只由 sin(θ) 给出缩放、
3
+ // z 序、景深与明暗),入场期卡内容冻结首帧、环撑开落定后统一开播;居中标题逐字解糊下沉落定,
4
+ // 关键词全部到位那一刻荧光马克块自左横扫铺满(扫过处字色反白为墨),mono 副行随后浮出。
5
+ //
6
+ // 第二轮重设计(石墨夜 · 荧光笔):
7
+ // - look = lime:石墨暗场 + 荧光黄绿。马克块从"黄色便利贴"变成一支荧光笔——暗场里唯一的高饱和色块,
8
+ // 只给关键词「每一个动效」。八张卡全部换成暗色产品卡(深石墨底 + 发丝线 + 顶部内高光),
9
+ // 卡内小动效统一用荧光绿做唯一强调,卡内字只做纹理(读的是标题)。
10
+ // - 标题从 64px 单行改成两级:上行 64px 次级灰「让镜头卡替你想好」,下行 156px「每一个动效」做主角;
11
+ // 马克块扫过时用两层裁切让字从白翻成墨色(反白在块的前沿同步发生,读作"被荧光笔划过")。
12
+ // - 空间:椭圆轨道本身画成一圈极淡的发丝线(入场时描出来),卡的纵深除了 ±12% 缩放,
13
+ // 远处(上方)的卡再压暗 + 轻微失焦,近处(下方)全亮全清——环有前后,标题在焦平面上。
14
+ // 标题后垫一团暗色 scrim,保证卡从背后经过时标题始终压得住。
15
+ // - 收尾:原版末段整行失焦退场做交棒;单镜头演示改为停在完整海报(HANDOFF_EXIT 开关保留退场逻辑)。
16
+ //
17
+ // 时间表(30fps,共 150f):
18
+ // 0–24 环从 0.62 撑开到满径(snappy)+ 逐卡淡入;轨道发丝线 0–30 描出
19
+ // 24 八张卡同时开播(冻结首帧 → 正常时间轴)
20
+ // 10–40 上行逐字解糊下沉(错峰 1f)
21
+ // 18–52 下行大字逐字解糊下沉(错峰 2f,更重更慢)
22
+ // 50–64 荧光马克块横扫(弹簧,damping 20),扫过处字反白为墨
23
+ // 60–76 副行(标志 + video-shotcraft + mono 代号)浮出
24
+ // 76–150 hold:环持续匀速公转 + 整体极缓推近 2.5%;最后 2.5s 是一张完整海报
25
+ import React from 'react';
26
+ import { AbsoluteFill, Easing, Freeze, interpolate, useCurrentFrame, useVideoConfig } from 'remotion';
27
+ import { EASE, FONT, ramp } from '../../_fixtures/Polish';
28
+ import { LOOKS, Stage, alpha, springAt } from '../../_fixtures/Look';
29
+ import { BRAND, ShotcraftMark } from '../../_fixtures/Brand';
30
+
31
+ export const ORBIT_RING_TITLE_OPEN_DURATION = 150; // 5s @30fps
32
+
33
+ const L = LOOKS.lime;
34
+ const LIME = L.accent;
35
+
36
+ // ---- 环 ----
37
+ const RX = 720; // 椭圆长半轴
38
+ const RY = 380; // 椭圆短半轴(RY/RX≈0.53 → 读作俯视的环,不是正圆转盘)
39
+ const CW = 400; // 卡宽(16:9)
40
+ const CH = 225;
41
+ const N = 8;
42
+ const ROT_SPEED = 0.3; // rad/s,正值 = 顺时针
43
+ const RING_IN = 24; // f:从中心撑开到满径
44
+ const RING_SCALE_FROM = 0.62;
45
+ const PLAY_START = 24; // f:环撑开后卡内容才开播
46
+ const DEPTH_SCALE = 0.12; // 近大远小幅度(底部近、顶部远)
47
+
48
+ // ---- 标题 ----
49
+ const LINE1 = '让镜头卡替你想好';
50
+ const LINE2 = '每一个动效';
51
+ const S1 = 64;
52
+ const S2 = 156;
53
+ const MARKER_AT = 50; // 下行末字视觉到位那一刻起扫
54
+ // 副行 = video-shotcraft 标志 + 小写字标 + mono 产品代号(不写卡片数:会过时)
55
+ const KICKER = 'SHOT RECIPE CARDS';
56
+ const HANDOFF_EXIT = false; // true = 末段整行失焦淡出、环继续转着交棒下一镜(成片里接下一镜时打开)
57
+ const EXIT_AT = 118;
58
+
59
+ const SANS = `${FONT.sans.replace('Arial, sans-serif', '')}"PingFang SC", "Hiragino Sans GB", sans-serif`;
60
+ const MONO = FONT.mono;
61
+ const INK = L.ink;
62
+ const DIM = '#8d937f';
63
+
64
+ // ── 卡内占位内容(暗色产品卡,960×540 作画后整体缩到卡宽)──────────────────
65
+ const F = (frame: number, a: number, b: number, ease = Easing.out(Easing.cubic)) =>
66
+ interpolate(frame, [a, b], [0, 1], { extrapolateLeft: 'clamp', extrapolateRight: 'clamp', easing: ease });
67
+
68
+ const Pad: React.FC<{ children: React.ReactNode; bg?: string }> = ({ children, bg = L.surface }) => (
69
+ <div style={{ position: 'absolute', inset: 0, background: bg, padding: 60, fontFamily: SANS, boxSizing: 'border-box' }}>{children}</div>
70
+ );
71
+
72
+ const T: React.FC<{ size: number; color?: string; weight?: number; mono?: boolean; style?: React.CSSProperties; children: React.ReactNode }> = ({
73
+ size, color = INK, weight = 500, mono, style, children,
74
+ }) => (
75
+ <div style={{
76
+ fontSize: size, color, fontWeight: weight, fontFamily: mono ? MONO : SANS,
77
+ letterSpacing: mono ? 0 : size >= 40 ? '-0.035em' : '-0.01em', lineHeight: 1.2, whiteSpace: 'nowrap', ...style,
78
+ }}>{children}</div>
79
+ );
80
+ const Caps: React.FC<{ children: React.ReactNode; color?: string }> = ({ children, color = DIM }) => (
81
+ <div style={{ fontSize: 24, fontWeight: 650, letterSpacing: '0.16em', color }}>{children}</div>
82
+ );
83
+
84
+ /** 1 荧光笔扫读 */
85
+ const TileSweep: React.FC = () => {
86
+ const f = useCurrentFrame();
87
+ const s = F(f, 14, 32, EASE.snappy);
88
+ return (
89
+ <Pad>
90
+ <Caps>RELEASE NOTES · 4.2</Caps>
91
+ <div style={{ position: 'relative', display: 'inline-block', marginTop: 40 }}>
92
+ <div style={{ position: 'absolute', left: -12, right: -12, top: 4, bottom: 0, background: LIME, borderRadius: 4, transformOrigin: 'left center', transform: `scaleX(${s})` }} />
93
+ <T size={58} weight={700} color={s > 0.6 ? L.onAccent : INK} style={{ position: 'relative' }}>Motion, considered.</T>
94
+ </div>
95
+ <T size={30} color={DIM} weight={450} style={{ marginTop: 34 }}>Every card ships with timing, easing</T>
96
+ <T size={30} color={DIM} weight={450} style={{ marginTop: 8 }}>and a validated reference build.</T>
97
+ </Pad>
98
+ );
99
+ };
100
+
101
+ /** 2 指标 + sparkline 描线 */
102
+ const SPARK = 'M8 118 L118 92 L228 104 L338 56 L448 68 L558 20 L632 34';
103
+ const TileMetric: React.FC = () => {
104
+ const f = useCurrentFrame();
105
+ const draw = F(f, 10, 46, EASE.smooth);
106
+ const val = 128 + Math.round(F(f, 8, 40, Easing.out(Easing.quad)) * 84);
107
+ const chip = F(f, 34, 46);
108
+ return (
109
+ <Pad>
110
+ <div style={{ display: 'flex', alignItems: 'center', gap: 18 }}>
111
+ <Caps>RENDERS / DAY</Caps>
112
+ <div style={{ fontSize: 24, fontWeight: 650, color: L.onAccent, background: LIME, padding: '4px 12px', borderRadius: 999, opacity: chip, transform: `translateY(${(1 - chip) * 8}px)` }}>+18.4%</div>
113
+ </div>
114
+ <div style={{ fontSize: 140, fontWeight: 700, color: INK, letterSpacing: '-0.045em', fontVariantNumeric: 'tabular-nums', lineHeight: 1.1, fontFamily: SANS }}>{val}</div>
115
+ <svg width={640} height={140} viewBox="0 0 640 140" style={{ marginTop: 8, overflow: 'visible' }}>
116
+ <defs>
117
+ <linearGradient id="orto-area" x1="0" y1="0" x2="0" y2="1">
118
+ <stop offset="0" stopColor={LIME} stopOpacity={0.28} />
119
+ <stop offset="1" stopColor={LIME} stopOpacity={0} />
120
+ </linearGradient>
121
+ </defs>
122
+ <path d={`${SPARK} L632 140 L8 140 Z`} fill="url(#orto-area)" opacity={draw} />
123
+ <path d={SPARK} fill="none" stroke="rgba(220,255,170,0.12)" strokeWidth={8} strokeLinecap="round" strokeLinejoin="round" />
124
+ <path d={SPARK} fill="none" stroke={LIME} strokeWidth={8} strokeLinecap="round" strokeLinejoin="round" pathLength={1} strokeDasharray={1} strokeDashoffset={1 - draw} />
125
+ </svg>
126
+ </Pad>
127
+ );
128
+ };
129
+
130
+ /** 3 竖向步骤清单逐条勾选 */
131
+ const STEPS = ['Draft the storyboard', 'Pick shot cards', 'Tune easing curves', 'Render & review'];
132
+ const TileSteps: React.FC = () => {
133
+ const f = useCurrentFrame();
134
+ return (
135
+ <Pad bg={L.surface2}>
136
+ <div style={{ display: 'flex', flexDirection: 'column', gap: 32 }}>
137
+ {STEPS.map((label, i) => {
138
+ const on = F(f, 8 + i * 9, 22 + i * 9);
139
+ const tick = F(f, 12 + i * 9, 22 + i * 9, EASE.overshoot);
140
+ return (
141
+ <div key={i} style={{ display: 'flex', alignItems: 'center', gap: 26 }}>
142
+ <div style={{
143
+ width: 46, height: 46, borderRadius: 23, flex: 'none', boxSizing: 'border-box',
144
+ background: on > 0.6 ? LIME : 'transparent', border: on > 0.6 ? 'none' : '3px solid rgba(220,255,170,0.18)',
145
+ display: 'flex', alignItems: 'center', justifyContent: 'center',
146
+ }}>
147
+ <svg width={26} height={26} viewBox="0 0 24 24" style={{ transform: `scale(${tick})` }}>
148
+ <path d="M5 12.5 L10 17 L19 7.5" fill="none" stroke={L.onAccent} strokeWidth={3.2} strokeLinecap="round" strokeLinejoin="round" />
149
+ </svg>
150
+ </div>
151
+ <T size={38} weight={on > 0.6 ? 600 : 500} color={on > 0.6 ? INK : '#5f6556'}>{label}</T>
152
+ </div>
153
+ );
154
+ })}
155
+ </div>
156
+ </Pad>
157
+ );
158
+ };
159
+
160
+ /** 4 路线描线 + 落点钉针(暗网格地图底) */
161
+ const ROUTE = 'M40 380 C 200 380 190 210 340 200 C 500 190 500 90 700 70';
162
+ const TileRoute: React.FC = () => {
163
+ const f = useCurrentFrame();
164
+ const draw = F(f, 6, 42, EASE.smooth);
165
+ const pin = springAt(f, 36, { damping: 12 });
166
+ const tag = F(f, 42, 54);
167
+ return (
168
+ <Pad bg={L.surface2}>
169
+ <div style={{ position: 'absolute', inset: 0, backgroundImage: 'linear-gradient(rgba(220,255,170,0.06) 2px, transparent 2px), linear-gradient(90deg, rgba(220,255,170,0.06) 2px, transparent 2px)', backgroundSize: '80px 80px' }} />
170
+ <svg width={848} height={428} viewBox="0 0 848 428" style={{ position: 'relative', overflow: 'visible' }}>
171
+ <path d={ROUTE} fill="none" stroke="rgba(220,255,170,0.14)" strokeWidth={10} strokeLinecap="round" />
172
+ <path d={ROUTE} fill="none" stroke={LIME} strokeWidth={10} strokeLinecap="round" pathLength={1} strokeDasharray={1} strokeDashoffset={1 - draw} />
173
+ <circle cx={40} cy={380} r={14} fill={L.surface2} stroke={LIME} strokeWidth={6} />
174
+ <g transform={`translate(700 70) scale(${pin})`}>
175
+ <circle r={36} fill={alpha(LIME, 0.2)} />
176
+ <circle r={24} fill={LIME} />
177
+ <circle r={9} fill={L.onAccent} />
178
+ </g>
179
+ </svg>
180
+ <div style={{ position: 'absolute', left: 470, top: 64, padding: '10px 18px', borderRadius: 12, background: '#262a20', boxShadow: '0 0 0 2px rgba(220,255,170,0.1), 0 10px 24px rgba(0,0,0,0.4)', opacity: tag, transform: `translateY(${(1 - tag) * 10}px)` }}>
181
+ <T size={28} weight={600}>ETA 12 min</T>
182
+ </div>
183
+ </Pad>
184
+ );
185
+ };
186
+
187
+ /** 5 终端打字(打字是机械匀速语义,逐字线性揭示) */
188
+ const TERM = [
189
+ { t: '$ npx remotion render Open', c: '#e8ecdf' },
190
+ { t: '✓ Bundled in 2.1s', c: LIME },
191
+ { t: ' Rendering frames 0–149', c: '#8d937f' },
192
+ { t: '✓ Done → out/open.mp4', c: LIME },
193
+ ];
194
+ const TileTerminal: React.FC = () => {
195
+ const f = useCurrentFrame();
196
+ return (
197
+ <Pad bg="#0b0c09">
198
+ <div style={{ display: 'flex', gap: 14, marginBottom: 34 }}>
199
+ {[0.5, 0.3, 0.2].map((o, i) => <div key={i} style={{ width: 20, height: 20, borderRadius: 10, background: `rgba(220,255,170,${o})` }} />)}
200
+ </div>
201
+ <div style={{ display: 'flex', flexDirection: 'column', gap: 18 }}>
202
+ <T size={30} mono color={LIME}>~/shotcraft</T>
203
+ {TERM.map((row, i) => {
204
+ const p = F(f, 8 + i * 11, 20 + i * 11, Easing.linear);
205
+ const n = Math.round(row.t.length * p);
206
+ return <T key={i} size={30} mono color={row.c} style={{ height: 37 }}>{row.t.slice(0, n)}</T>;
207
+ })}
208
+ </div>
209
+ </Pad>
210
+ );
211
+ };
212
+
213
+ /** 6 线稿描画(点阵纸底) */
214
+ const SKETCH = ['M80 380 L768 380', 'M140 380 L200 90 L648 90 L708 380', 'M280 90 L280 380', 'M500 90 L500 380'];
215
+ const TileSketch: React.FC = () => {
216
+ const f = useCurrentFrame();
217
+ return (
218
+ <Pad>
219
+ <div style={{ position: 'absolute', inset: 0, backgroundImage: 'radial-gradient(circle, rgba(220,255,170,0.14) 2px, transparent 2.5px)', backgroundSize: '40px 40px' }} />
220
+ <svg width={848} height={428} viewBox="0 0 848 428" style={{ position: 'relative' }}>
221
+ {SKETCH.map((d, i) => <path key={`g${i}`} d={d} fill="none" stroke="rgba(220,255,170,0.12)" strokeWidth={7} strokeLinecap="round" />)}
222
+ {SKETCH.map((d, i) => {
223
+ const p = F(f, 6 + i * 10, 24 + i * 10, EASE.smooth);
224
+ return <path key={i} d={d} fill="none" stroke={i === 1 ? LIME : INK} strokeWidth={7} strokeLinecap="round" strokeLinejoin="round" pathLength={1} strokeDasharray={1} strokeDashoffset={1 - p} />;
225
+ })}
226
+ </svg>
227
+ </Pad>
228
+ );
229
+ };
230
+
231
+ /** 7 卡片缩成胶囊(主体让位) */
232
+ const TileShrink: React.FC = () => {
233
+ const f = useCurrentFrame();
234
+ const p = F(f, 16, 44, EASE.smooth);
235
+ const cont = F(f, 28, 50);
236
+ return (
237
+ <Pad bg={L.surface2}>
238
+ <div style={{
239
+ position: 'absolute', left: 60, top: 60, width: 840 - 690 * p, height: 420 - 342 * p, borderRadius: 16 + 30 * p,
240
+ background: '#262a20', boxShadow: '0 0 0 2px rgba(220,255,170,0.08), 0 12px 28px rgba(0,0,0,0.35)', overflow: 'hidden',
241
+ display: 'flex', alignItems: p > 0.6 ? 'center' : 'flex-start', justifyContent: p > 0.6 ? 'center' : 'flex-start',
242
+ padding: p > 0.6 ? 0 : 40, boxSizing: 'border-box',
243
+ }}>
244
+ {p <= 0.6 ? (
245
+ <div style={{ opacity: 1 - p / 0.6 }}>
246
+ <Caps>WEEKLY SUMMARY</Caps>
247
+ <T size={46} weight={700} style={{ marginTop: 18 }}>12 shots approved</T>
248
+ <T size={28} color={DIM} weight={450} style={{ marginTop: 10 }}>3 pending review · 1 re-render</T>
249
+ </div>
250
+ ) : (
251
+ <T size={30} weight={600} color={LIME} style={{ opacity: (p - 0.6) / 0.4 }}>Summary</T>
252
+ )}
253
+ </div>
254
+ <div style={{ position: 'absolute', left: 260, top: 150, opacity: cont, transform: `translateX(${(1 - cont) * 24}px)` }}>
255
+ <T size={48} weight={700}>Q3 launch plan</T>
256
+ <T size={28} color={DIM} weight={450} style={{ marginTop: 14 }}>Owner · Studio team</T>
257
+ <T size={28} color={DIM} weight={450} style={{ marginTop: 6 }}>Due Oct 18</T>
258
+ </div>
259
+ </Pad>
260
+ );
261
+ };
262
+
263
+ /** 8 冲击字卡 */
264
+ const TileImpact: React.FC = () => {
265
+ const f = useCurrentFrame();
266
+ const p = springAt(f, 8, { damping: 13, mass: 0.7 });
267
+ return (
268
+ <Pad bg="#0f110c">
269
+ <div style={{ position: 'absolute', inset: 0, display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', gap: 22 }}>
270
+ <div style={{ fontSize: 30, fontWeight: 650, color: LIME, letterSpacing: '0.4em', fontFamily: SANS }}>2026 · Q3</div>
271
+ <div style={{ fontSize: 150, fontWeight: 850, letterSpacing: '-0.05em', color: INK, fontFamily: SANS, transform: `scale(${0.72 + p * 0.28})`, opacity: Math.min(1, p) }}>GO LIVE</div>
272
+ </div>
273
+ </Pad>
274
+ );
275
+ };
276
+
277
+ const TILES: React.FC[] = [TileSweep, TileShrink, TileMetric, TileRoute, TileSteps, TileTerminal, TileSketch, TileImpact];
278
+
279
+ // ── 标题逐字:位移只占前 1/3,解糊走满(同起不同终 = blur-slide 的手感)──
280
+ const charStyle = (frame: number, at: number, size: number, dur: number): React.CSSProperties => {
281
+ const pMain = ramp(frame, at, dur, EASE.out);
282
+ const pTravel = ramp(frame, at, dur / 3, EASE.out);
283
+ return {
284
+ display: 'inline-block', whiteSpace: 'pre', transformOrigin: '50% 55%', opacity: pMain,
285
+ filter: pMain < 1 ? `blur(${((1 - pMain) * (size / 6)).toFixed(2)}px)` : undefined,
286
+ transform: `translateY(${((1 - pTravel) * size * 0.22).toFixed(2)}px)`,
287
+ };
288
+ };
289
+
290
+ // ── 主体 ───────────────────────────────────────────────────────────────────
291
+ export const OrbitRingTitleOpen: React.FC = () => {
292
+ const frame = useCurrentFrame();
293
+ const { fps } = useVideoConfig();
294
+ const t = frame / fps;
295
+
296
+ const ringIn = ramp(frame, 0, RING_IN, EASE.snappy);
297
+ const ringScale = RING_SCALE_FROM + (1 - RING_SCALE_FROM) * ringIn;
298
+ const rot = t * ROT_SPEED;
299
+ const track = ramp(frame, 0, 30, EASE.out);
300
+ const push = 1 + 0.025 * ramp(frame, 40, 110, EASE.smooth); // hold 段极缓推近
301
+
302
+ const marker = Math.min(1.03, springAt(frame, MARKER_AT, { damping: 20, stiffness: 190 }));
303
+ const kickerIn = ramp(frame, 60, 16, EASE.out);
304
+ const exitQ = HANDOFF_EXIT ? ramp(frame, EXIT_AT, 10, EASE.exit) : 0;
305
+ const titleExit: React.CSSProperties = { opacity: 1 - exitQ, filter: exitQ > 0.01 ? `blur(${(exitQ * 6.5).toFixed(2)}px)` : undefined };
306
+
307
+ const l1 = Array.from(LINE1);
308
+ const l2 = Array.from(LINE2);
309
+ const line2 = (color: string) => l2.map((ch, j) => <span key={j} style={{ ...charStyle(frame, 18 + j * 2, S2, 32), color }}>{ch}</span>);
310
+ // 马克块比字宽出左右各 0.14em:块前沿在字盒里的位置 = (m·(W+0.28em) − 0.14em) / W,W ≈ 5.05em
311
+ const edge = Math.min(1, Math.max(0, (Math.min(1, marker) * 5.33 - 0.14) / 5.05));
312
+ const clipR = ((1 - edge) * 100).toFixed(2);
313
+ const clipL = (edge * 100).toFixed(2);
314
+
315
+ return (
316
+ <AbsoluteFill style={{ background: L.bg[1], fontFamily: SANS }}>
317
+ <Stage look={L} keyLight={{ x: 0.5, y: 0.0 }} fill={null} intensity={0.5} vignette={0.62}>
318
+ {/* 标题背后的暗 scrim:卡从背后经过时标题始终压得住 */}
319
+ <div style={{ position: 'absolute', left: 360, top: 300, width: 1200, height: 480, background: `radial-gradient(ellipse 50% 50% at 50% 50%, ${alpha('#050604', 0.75)} 0%, ${alpha('#050604', 0)} 70%)` }} />
320
+ </Stage>
321
+
322
+ <AbsoluteFill style={{ transform: `scale(${push})` }}>
323
+ {/* 椭圆轨道发丝线:入场时描出来,给环一个看得见的几何 */}
324
+ <svg width={1920} height={1080} style={{ position: 'absolute', inset: 0 }}>
325
+ <ellipse cx={960} cy={540} rx={RX * ringScale} ry={RY * ringScale} fill="none" stroke={alpha(LIME, 0.16)} strokeWidth={1.5}
326
+ pathLength={1} strokeDasharray="1" strokeDashoffset={1 - track} />
327
+ </svg>
328
+
329
+ {TILES.map((Comp, i) => {
330
+ const theta = -Math.PI / 2 + (i * Math.PI * 2) / N + rot;
331
+ const x = 960 + Math.cos(theta) * RX * ringScale;
332
+ const y = 540 + Math.sin(theta) * RY * ringScale;
333
+ const depth = Math.sin(theta); // +1 = 画面下方(近),−1 = 上方(远)
334
+ const s = 1 + DEPTH_SCALE * depth;
335
+ const op = ramp(frame, 2 + i * 1.5, 11, EASE.out);
336
+ const grow = 0.9 + 0.1 * op;
337
+ const far = Math.max(0, -depth); // 远处:压暗 + 轻微失焦
338
+ const elev = 14 + 12 * depth;
339
+ return (
340
+ <div key={i} style={{
341
+ position: 'absolute', left: x - (CW * s) / 2, top: y - (CH * s) / 2, width: CW * s, height: CH * s,
342
+ borderRadius: 14, overflow: 'hidden', opacity: op, transform: `scale(${grow})`, zIndex: 10 + Math.round(depth * 5),
343
+ boxShadow: `inset 0 1px 0 rgba(255,255,255,0.08), 0 0 0 1px ${L.line}, 0 ${(elev * 0.6).toFixed(1)}px ${(elev * 1.6).toFixed(1)}px rgba(0,0,0,${(0.45 + 0.2 * depth).toFixed(2)})`,
344
+ filter: far > 0.05 ? `blur(${(far * 1.6).toFixed(2)}px)` : undefined,
345
+ }}>
346
+ {/* 卡内按 960×540 作画再整体缩到卡宽——内容组件不需要知道自己被缩小了 */}
347
+ <div style={{ position: 'absolute', left: 0, top: 0, width: 960, height: 540, transform: `scale(${(CW * s) / 960})`, transformOrigin: 'top left' }}>
348
+ <Freeze frame={Math.max(0, frame - PLAY_START)}>
349
+ <Comp />
350
+ </Freeze>
351
+ </div>
352
+ {/* 纵深明暗:远处压暗、近处带一点顶光 */}
353
+ <div style={{ position: 'absolute', inset: 0, background: `linear-gradient(180deg, rgba(255,255,255,${(0.04 * Math.max(0, depth)).toFixed(3)}) 0%, rgba(5,6,4,${(0.5 * far).toFixed(3)}) 100%), rgba(5,6,4,${(0.25 * far).toFixed(3)})` }} />
354
+ </div>
355
+ );
356
+ })}
357
+
358
+ {/* 卡与标题之间的暗 scrim(在卡之上、字之下):近处卡从标题背后经过时被压暗,字始终压得住 */}
359
+ <div style={{ position: 'absolute', left: 260, top: 250, width: 1400, height: 560, zIndex: 25, background: `radial-gradient(ellipse 50% 50% at 50% 50%, ${alpha('#060705', 0.82)} 0%, ${alpha('#060705', 0.55)} 45%, ${alpha('#060705', 0)} 72%)` }} />
360
+
361
+ {/* 标题:上行次级灰、下行主角大字 + 荧光马克 */}
362
+ <div style={{ position: 'absolute', left: 0, right: 0, top: 336, textAlign: 'center', zIndex: 30, ...titleExit }}>
363
+ <div style={{ fontSize: S1, fontWeight: 500, letterSpacing: '0.02em', color: '#b7bdaa', whiteSpace: 'nowrap', lineHeight: 1 }}>
364
+ {l1.map((ch, i) => <span key={i} style={charStyle(frame, 10 + i, S1, 27)}>{ch}</span>)}
365
+ </div>
366
+ <div style={{ marginTop: 34, display: 'inline-block', position: 'relative', fontSize: S2, fontWeight: 600, letterSpacing: '0.01em', lineHeight: 1.12, whiteSpace: 'nowrap' }}>
367
+ {/* 马克块:自左横扫铺满(垫在字下) */}
368
+ <span aria-hidden style={{
369
+ position: 'absolute', left: '-0.14em', right: '-0.14em', top: '0.1em', bottom: '0.04em', background: LIME, borderRadius: 8,
370
+ transformOrigin: 'left center', transform: `scaleX(${marker.toFixed(4)})`, boxShadow: marker > 0.02 ? `0 0 60px ${alpha(LIME, 0.28)}` : undefined,
371
+ }} />
372
+ {/* 两层字:块的前沿左边是墨色、右边是白色——扫过即反白 */}
373
+ <span style={{ position: 'relative', display: 'inline-block', clipPath: `inset(-20% 0 -20% ${clipL}%)`, color: INK }}>{line2(INK)}</span>
374
+ <span aria-hidden style={{ position: 'absolute', left: 0, top: 0, display: 'inline-block', clipPath: `inset(-20% ${clipR}% -20% 0)` }}>{line2(L.onAccent)}</span>
375
+ </div>
376
+ <div style={{
377
+ marginTop: 40, display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 16, whiteSpace: 'pre',
378
+ opacity: kickerIn, transform: `translateY(${((1 - kickerIn) * 12).toFixed(2)}px)`,
379
+ }}>
380
+ <ShotcraftMark size={44} tone="dark" />
381
+ <span style={{ fontFamily: BRAND.font, fontSize: 30, fontWeight: 700, letterSpacing: '0.03em', color: INK, lineHeight: 1 }}>{BRAND.name}</span>
382
+ <span style={{ fontFamily: MONO, fontSize: 26, fontWeight: 600, color: DIM, lineHeight: 1 }}>·</span>
383
+ <span style={{ fontFamily: MONO, fontSize: 26, fontWeight: 600, letterSpacing: '0.2em', marginRight: '-0.2em', color: DIM, lineHeight: 1 }}>{KICKER}</span>
384
+ </div>
385
+ </div>
386
+ </AbsoluteFill>
387
+ </AbsoluteFill>
388
+ );
389
+ };