dsh-drawai 0.4.1 → 0.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (365) hide show
  1. package/README.md +96 -253
  2. package/lib/client.js +28 -7
  3. package/lib/index.js +474 -97
  4. package/lib/motion/asset-pack.js +109 -50
  5. package/lib/motion/assets.js +291 -291
  6. package/lib/motion/demo-assets-lock.js +10 -0
  7. package/lib/motion/mgstyles/vendor/README.md +28 -0
  8. package/lib/motion/mgstyles/vendor/modules/d3/LICENSE +13 -0
  9. package/lib/motion/mgstyles/vendor/modules/d3/dist/d3.min.js +2 -0
  10. package/lib/motion/mgstyles/vendor/modules/opentype.js/LICENSE +20 -0
  11. package/lib/motion/mgstyles/vendor/modules/opentype.js/dist/opentype.mjs +14460 -0
  12. package/lib/motion/mgstyles/vendor/modules/simplex-noise/LICENSE +21 -0
  13. package/lib/motion/mgstyles/vendor/modules/simplex-noise/dist/esm/simplex-noise.js +466 -0
  14. package/lib/motion/mgstyles/vendor/modules/topojson-client/LICENSE +13 -0
  15. package/lib/motion/mgstyles/vendor/modules/topojson-client/dist/topojson-client.min.js +2 -0
  16. package/lib/motion/preview.js +10 -3
  17. package/lib/motion/render.js +19 -1
  18. package/lib/motion/shotcraft/upstream/SKILL.md +286 -286
  19. package/lib/motion/shotcraft/upstream/assets/lib/Caption.tsx +54 -54
  20. package/lib/motion/shotcraft/upstream/assets/lib/ClipCard.tsx +200 -200
  21. package/lib/motion/shotcraft/upstream/assets/lib/DigitRoll.tsx +45 -45
  22. package/lib/motion/shotcraft/upstream/assets/lib/FlashCut.tsx +20 -20
  23. package/lib/motion/shotcraft/upstream/assets/lib/FlatPanel.tsx +65 -65
  24. package/lib/motion/shotcraft/upstream/assets/lib/PageCam.tsx +151 -151
  25. package/lib/motion/shotcraft/upstream/assets/lib/VerticalTicker.tsx +129 -129
  26. package/lib/motion/shotcraft/upstream/assets/lib/helpers/camera.tsx +75 -75
  27. package/lib/motion/shotcraft/upstream/assets/lib/helpers/motion.ts +40 -40
  28. package/lib/motion/shotcraft/upstream/assets/lib/helpers/rand.ts +11 -11
  29. package/lib/motion/shotcraft/upstream/assets/lib/helpers/shake.ts +10 -10
  30. package/lib/motion/shotcraft/upstream/assets/scripts/build-readme-cover.mjs +49 -49
  31. package/lib/motion/shotcraft/upstream/assets/scripts/capture-template.mjs +210 -210
  32. package/lib/motion/shotcraft/upstream/assets/scripts/sfx-source.py +423 -423
  33. package/lib/motion/shotcraft/upstream/assets/scripts/smoke-render-demos.py +170 -170
  34. package/lib/motion/shotcraft/upstream/assets/scripts/test_sfx_source.py +157 -157
  35. package/lib/motion/shotcraft/upstream/demos/README.md +120 -120
  36. package/lib/motion/shotcraft/upstream/demos/_fixtures/Brand.tsx +112 -112
  37. package/lib/motion/shotcraft/upstream/demos/_fixtures/Fixtures.tsx +647 -647
  38. package/lib/motion/shotcraft/upstream/demos/_fixtures/Look.tsx +316 -316
  39. package/lib/motion/shotcraft/upstream/demos/_fixtures/Motion.tsx +82 -82
  40. package/lib/motion/shotcraft/upstream/demos/_fixtures/PageCam2D.tsx +115 -115
  41. package/lib/motion/shotcraft/upstream/demos/_fixtures/Polish.tsx +243 -243
  42. package/lib/motion/shotcraft/upstream/demos/_textures/live-layout.json +388 -388
  43. package/lib/motion/shotcraft/upstream/demos/camera/basic-3d-scene/Basic3DScene.tsx +250 -250
  44. package/lib/motion/shotcraft/upstream/demos/camera/crash-zoom-punch/CrashImpactReal.tsx +305 -305
  45. package/lib/motion/shotcraft/upstream/demos/camera/crash-zoom-punch/CrashZoomReal.tsx +246 -246
  46. package/lib/motion/shotcraft/upstream/demos/camera/cursor-flyover/CursorFlyover.tsx +390 -390
  47. package/lib/motion/shotcraft/upstream/demos/camera/depth-layer-moves/MultiplaneReal.tsx +138 -138
  48. package/lib/motion/shotcraft/upstream/demos/camera/graze-face-tour/GrazeFaceTour.tsx +542 -542
  49. package/lib/motion/shotcraft/upstream/demos/camera/overhead-camera-moves/OverheadTabletopDrop.tsx +315 -315
  50. package/lib/motion/shotcraft/upstream/demos/camera/overhead-camera-moves/TiltReveal.tsx +299 -299
  51. package/lib/motion/shotcraft/upstream/demos/camera/space-camera-moves/DroneDiveLanding.tsx +173 -173
  52. package/lib/motion/shotcraft/upstream/demos/camera/space-camera-moves/ExplodedView.tsx +348 -348
  53. package/lib/motion/shotcraft/upstream/demos/camera/steep-tilt-glide/SteepTiltGlide.tsx +366 -366
  54. package/lib/motion/shotcraft/upstream/demos/camera/tension-camera-moves/BulletTimeFreezeOrbit.tsx +279 -279
  55. package/lib/motion/shotcraft/upstream/demos/camera/tension-camera-moves/PullBackIsolation.tsx +184 -184
  56. package/lib/motion/shotcraft/upstream/demos/camera/terminal-3d/Terminal3D.tsx +390 -390
  57. package/lib/motion/shotcraft/upstream/demos/data/before-after-slider-scrub/BeforeAfterSliderScrub.tsx +155 -155
  58. package/lib/motion/shotcraft/upstream/demos/data/chart-live-moves/AxisRescaleShockV2.tsx +303 -303
  59. package/lib/motion/shotcraft/upstream/demos/data/chart-live-moves/OscilloscopeStreamV2.tsx +290 -290
  60. package/lib/motion/shotcraft/upstream/demos/data/chart-live-moves/UnitDotSwarmRegroupV2.tsx +278 -278
  61. package/lib/motion/shotcraft/upstream/demos/data/gauge-readout-moves/NeedleSweepSelftest.tsx +307 -307
  62. package/lib/motion/shotcraft/upstream/demos/data/gauge-readout-moves/TapeScrollFixedPointer.tsx +215 -215
  63. package/lib/motion/shotcraft/upstream/demos/data/scroll-brake-moves/BrakeReticleLock.tsx +299 -299
  64. package/lib/motion/shotcraft/upstream/demos/data/scroll-brake-moves/ChangelogScrollBrake.tsx +232 -232
  65. package/lib/motion/shotcraft/upstream/demos/data/timeline-travel/TimelineTravel.tsx +290 -290
  66. package/lib/motion/shotcraft/upstream/demos/effects/assemble-then-type-flyin/AssembleThenTypeFlyin.tsx +273 -273
  67. package/lib/motion/shotcraft/upstream/demos/effects/aurora-bloom-bg-flip/AuroraBloomBgFlip.tsx +167 -167
  68. package/lib/motion/shotcraft/upstream/demos/effects/brand-frame-snap/BrandFrameSnap.tsx +536 -536
  69. package/lib/motion/shotcraft/upstream/demos/effects/fui-hud-moves/ReticleLockOn.tsx +164 -164
  70. package/lib/motion/shotcraft/upstream/demos/effects/glow-flyline-moves/FlylineArc.tsx +175 -175
  71. package/lib/motion/shotcraft/upstream/demos/effects/glow-flyline-moves/GlowOrbAmbient.tsx +197 -197
  72. package/lib/motion/shotcraft/upstream/demos/effects/glow-flyline-moves/OrbFlylineRelay.tsx +241 -241
  73. package/lib/motion/shotcraft/upstream/demos/effects/icon-performance-moves/AttentionBounce.tsx +279 -279
  74. package/lib/motion/shotcraft/upstream/demos/effects/impact-feedback/AnimeImpact.tsx +230 -230
  75. package/lib/motion/shotcraft/upstream/demos/effects/impact-feedback/HitCounter.tsx +345 -345
  76. package/lib/motion/shotcraft/upstream/demos/effects/light-play-moves/SheenSweepRetry.tsx +275 -275
  77. package/lib/motion/shotcraft/upstream/demos/effects/light-play-moves/SpotlightSweepReveal.tsx +229 -229
  78. package/lib/motion/shotcraft/upstream/demos/effects/radial-ripple-phone-chips/RadialRipplePhoneChips.tsx +312 -312
  79. package/lib/motion/shotcraft/upstream/demos/effects/riso-print-hits/RisoMisregistrationHit.tsx +222 -222
  80. package/lib/motion/shotcraft/upstream/demos/effects/scan-bracket-sweep/ScanBracketSweep.tsx +295 -295
  81. package/lib/motion/shotcraft/upstream/demos/effects/scanline-annotate-focus/ScanlineAnnotateFocus.tsx +329 -329
  82. package/lib/motion/shotcraft/upstream/demos/effects/scanline-assemble-flyin/ScanlineAssembleFlyin.tsx +315 -315
  83. package/lib/motion/shotcraft/upstream/demos/effects/slam-entrance-moves/ImpactBurstKit.tsx +264 -264
  84. package/lib/motion/shotcraft/upstream/demos/effects/slam-entrance-moves/KanadaPerspectiveSnap.tsx +260 -260
  85. package/lib/motion/shotcraft/upstream/demos/effects/slam-entrance-moves/ScoreSlam.tsx +263 -263
  86. package/lib/motion/shotcraft/upstream/demos/effects/spotlight-sweep-moves/CornerSpotlightReveal.tsx +123 -123
  87. package/lib/motion/shotcraft/upstream/demos/effects/spotlight-sweep-moves/GlowWakeSleepPanel.tsx +187 -187
  88. package/lib/motion/shotcraft/upstream/demos/effects/spotlight-sweep-moves/SlideSpotlightPan.tsx +175 -175
  89. package/lib/motion/shotcraft/upstream/demos/interaction/autolayout-gap-dial/AutolayoutGapDial.tsx +305 -305
  90. package/lib/motion/shotcraft/upstream/demos/interaction/canvas-materialize-moves/DiagramCascadeBuild.tsx +350 -350
  91. package/lib/motion/shotcraft/upstream/demos/interaction/canvas-materialize-moves/PanelToCanvasMaterialize.tsx +352 -352
  92. package/lib/motion/shotcraft/upstream/demos/interaction/chip-grid-single-select-blackout/ChipGridSingleSelectBlackout.tsx +218 -218
  93. package/lib/motion/shotcraft/upstream/demos/interaction/collab-cursor-moves/CursorCastEnsemble.tsx +297 -297
  94. package/lib/motion/shotcraft/upstream/demos/interaction/glass-pill-dictation-typing/GlassPillDictationTyping.tsx +157 -157
  95. package/lib/motion/shotcraft/upstream/demos/interaction/hashtag-to-pill-materialize/HashtagToPillMaterialize.tsx +218 -218
  96. package/lib/motion/shotcraft/upstream/demos/interaction/picker-carousel-feature-cycle/PickerCarouselFeatureCycle.tsx +202 -202
  97. package/lib/motion/shotcraft/upstream/demos/interaction/segmented-thumb-hero/SegmentedThumbHero.tsx +265 -265
  98. package/lib/motion/shotcraft/upstream/demos/interaction/theme-switch-moves/PaletteThemeRipple.tsx +457 -457
  99. package/lib/motion/shotcraft/upstream/demos/interaction/theme-switch-moves/ThemeSweepToggle.tsx +446 -446
  100. package/lib/motion/shotcraft/upstream/demos/interaction/type-and-filter/TypeAndFilter.tsx +249 -249
  101. package/lib/motion/shotcraft/upstream/demos/interaction/voice-waveform-live/VoiceWaveformLive.tsx +278 -278
  102. package/lib/motion/shotcraft/upstream/demos/opening/crane-rise-reveal/CraneRiseReveal.tsx +332 -332
  103. package/lib/motion/shotcraft/upstream/demos/opening/dataviz-landscape-open/DatavizLandscapeOpen.tsx +358 -358
  104. package/lib/motion/shotcraft/upstream/demos/opening/fracture/Fracture.tsx +201 -201
  105. package/lib/motion/shotcraft/upstream/demos/opening/icon-field-colorize/IconFieldColorize.tsx +200 -200
  106. package/lib/motion/shotcraft/upstream/demos/opening/letterspace-materialize/LetterspaceMaterialize.tsx +208 -208
  107. package/lib/motion/shotcraft/upstream/demos/opening/magician-card-flourish/MagicianCardFlourish.tsx +341 -341
  108. package/lib/motion/shotcraft/upstream/demos/opening/orbit-ring-title-open/OrbitRingTitleOpen.tsx +389 -389
  109. package/lib/motion/shotcraft/upstream/demos/opening/spotlight-hero-card/SpotlightHeroCard.tsx +293 -293
  110. package/lib/motion/shotcraft/upstream/demos/opening/stroke-segment-build/StrokeSegmentBuild.tsx +183 -183
  111. package/lib/motion/shotcraft/upstream/demos/opening/text-as-mask/TextAsMask.tsx +245 -245
  112. package/lib/motion/shotcraft/upstream/demos/outro/grain-dissolve/GrainDissolve.tsx +222 -222
  113. package/lib/motion/shotcraft/upstream/demos/outro/logo-shrink-wordmark-lockup/LogoShrinkWordmarkLockup.tsx +223 -223
  114. package/lib/motion/shotcraft/upstream/demos/outro/neon-triple-marquee/NeonTripleMarquee.tsx +217 -217
  115. package/lib/motion/shotcraft/upstream/demos/outro/outro-group-photo-launch/OutroGroupPhotoLaunch.tsx +343 -343
  116. package/lib/motion/shotcraft/upstream/demos/outro/ui-strip-away-outro/UiStripAwayOutro.tsx +357 -357
  117. package/lib/motion/shotcraft/upstream/demos/outro/ui-to-brand-morph/IconFlipBloomLogo.tsx +187 -187
  118. package/lib/motion/shotcraft/upstream/demos/outro/ui-to-brand-morph/InputMorphsIntoLogo.tsx +333 -333
  119. package/lib/motion/shotcraft/upstream/demos/rhythm/beat-cut-moves/PaparazziFlash.tsx +274 -274
  120. package/lib/motion/shotcraft/upstream/demos/rhythm/beat-step-list-theme-cycle/BeatStepListThemeCycle.tsx +270 -270
  121. package/lib/motion/shotcraft/upstream/demos/rhythm/panel-grid-moves/ComicPanelSplit.tsx +430 -430
  122. package/lib/motion/shotcraft/upstream/demos/rhythm/quad-split-parallel-scenes/QuadSplitParallelScenes.tsx +252 -252
  123. package/lib/motion/shotcraft/upstream/demos/rhythm/rhythm-interrupt-moves/JumpCutPunchIn.tsx +106 -106
  124. package/lib/motion/shotcraft/upstream/demos/rhythm/sakuga-timing-shift/SakugaTimingShift.tsx +288 -288
  125. package/lib/motion/shotcraft/upstream/demos/rhythm/speed-ramp-freeze/FreezeAnnotateReal.tsx +362 -362
  126. package/lib/motion/shotcraft/upstream/demos/rhythm/trailer-grammar-moves/TrailerBumper.tsx +168 -168
  127. package/lib/motion/shotcraft/upstream/demos/transition/bottom-push-stack-wipe/BottomPushStackWipe.tsx +310 -310
  128. package/lib/motion/shotcraft/upstream/demos/transition/card-flip-reveal/CardFlipReveal.tsx +261 -261
  129. package/lib/motion/shotcraft/upstream/demos/transition/card-flock-tumble/CardFlockTumble.tsx +459 -459
  130. package/lib/motion/shotcraft/upstream/demos/transition/circle-match-iris/CircleMatchIris.tsx +294 -294
  131. package/lib/motion/shotcraft/upstream/demos/transition/gradient-transition/GradientTransition.tsx +161 -161
  132. package/lib/motion/shotcraft/upstream/demos/transition/line-carry-transition/LineCarryTransition.tsx +248 -248
  133. package/lib/motion/shotcraft/upstream/demos/transition/mosaic-reframe/MosaicReframe.tsx +359 -359
  134. package/lib/motion/shotcraft/upstream/demos/transition/page-turn-transitions/BarnDoorSplit.tsx +227 -227
  135. package/lib/motion/shotcraft/upstream/demos/transition/print-texture-transitions/InkBleedReveal.tsx +162 -162
  136. package/lib/motion/shotcraft/upstream/demos/transition/shot-transitions/PortalWipeV2.tsx +248 -248
  137. package/lib/motion/shotcraft/upstream/demos/transition/shot-transitions/WhipBrakeReal.tsx +186 -186
  138. package/lib/motion/shotcraft/upstream/demos/transition/tear-streak-transitions/GlitchDisplace.tsx +355 -355
  139. package/lib/motion/shotcraft/upstream/demos/transition/transition-hidden-cut/InvisibleCut.tsx +272 -272
  140. package/lib/motion/shotcraft/upstream/demos/transition/transition-hidden-cut/LightLeakBurn.tsx +262 -262
  141. package/lib/motion/shotcraft/upstream/demos/transition/transition-hidden-cut/VersusSlam.tsx +217 -217
  142. package/lib/motion/shotcraft/upstream/demos/transition/transition-travel/LetterformZoom.tsx +285 -285
  143. package/lib/motion/shotcraft/upstream/demos/transition/white-flash-logo-simplify-cut/WhiteFlashLogoSimplifyCut.tsx +205 -205
  144. package/lib/motion/shotcraft/upstream/demos/transition/wipe-transitions/BlindsSlice.tsx +178 -178
  145. package/lib/motion/shotcraft/upstream/demos/typography/blur-slide/BlurSlide.tsx +147 -147
  146. package/lib/motion/shotcraft/upstream/demos/typography/brace-expand/BraceExpand.tsx +143 -143
  147. package/lib/motion/shotcraft/upstream/demos/typography/brand-ink-open/BrandInkOpen.tsx +134 -134
  148. package/lib/motion/shotcraft/upstream/demos/typography/countdown-arc-scatter/CountdownArcScatter.tsx +217 -217
  149. package/lib/motion/shotcraft/upstream/demos/typography/flying-words/FlyingWords.tsx +198 -198
  150. package/lib/motion/shotcraft/upstream/demos/typography/glitch-cycle/GlitchCycle.tsx +221 -221
  151. package/lib/motion/shotcraft/upstream/demos/typography/gradient-word-sweep/GradientWordSweep.tsx +312 -312
  152. package/lib/motion/shotcraft/upstream/demos/typography/lead-word-zoom-assemble/LeadWordZoomAssemble.tsx +261 -261
  153. package/lib/motion/shotcraft/upstream/demos/typography/marker-underline-title/MarkerUnderlineTitle.tsx +121 -121
  154. package/lib/motion/shotcraft/upstream/demos/typography/outline-word-fill/OutlineWordFill.tsx +153 -153
  155. package/lib/motion/shotcraft/upstream/demos/typography/paper-title-card/PaperTitleCard.tsx +179 -179
  156. package/lib/motion/shotcraft/upstream/demos/typography/pill-chip-slot-cycle-handled/PillChipSlotCycleHandled.tsx +140 -140
  157. package/lib/motion/shotcraft/upstream/demos/typography/pill-slot-cycle/PillSlotCycle.tsx +309 -309
  158. package/lib/motion/shotcraft/upstream/demos/typography/text-column-converge/TextColumnConverge.tsx +191 -191
  159. package/lib/motion/shotcraft/upstream/demos/typography/title-demote-to-label/TitleDemoteToLabel.tsx +292 -292
  160. package/lib/motion/shotcraft/upstream/demos/typography/type-assembly-moves/LetterformDriftAssembly.tsx +135 -135
  161. package/lib/motion/shotcraft/upstream/demos/typography/type-assembly-moves/SplitTextStagger.tsx +124 -124
  162. package/lib/motion/shotcraft/upstream/demos/typography/type-assembly-moves/TextOnPath.tsx +255 -255
  163. package/lib/motion/shotcraft/upstream/demos/typography/type-entrance-moves/LetterDropPhysics.tsx +173 -173
  164. package/lib/motion/shotcraft/upstream/demos/typography/type-rhythm-sync/FontWeightPump.tsx +225 -225
  165. package/lib/motion/shotcraft/upstream/demos/typography/type-rhythm-sync/KaraokeFillSync.tsx +141 -141
  166. package/lib/motion/shotcraft/upstream/demos/typography/typewriter-moves/TypewriterErrorRetype.tsx +137 -137
  167. package/lib/motion/shotcraft/upstream/demos/typography/vertical-word-roll-blur-cycle/VerticalWordRollBlurCycle.tsx +147 -147
  168. package/lib/motion/shotcraft/upstream/demos/typography/word-relay-filmstrip/WordRelayFilmstrip.tsx +409 -409
  169. package/lib/motion/shotcraft/upstream/demos/typography/word-relay-geometry/WordRelayGeometry.tsx +280 -280
  170. package/lib/motion/shotcraft/upstream/demos/ui-entrance/avatar-bracket-carousel/AvatarBracketCarousel.tsx +271 -271
  171. package/lib/motion/shotcraft/upstream/demos/ui-entrance/bezier-source-converge-merge/BezierSourceConvergeMerge.tsx +385 -385
  172. package/lib/motion/shotcraft/upstream/demos/ui-entrance/card-stack/CardStack.tsx +312 -312
  173. package/lib/motion/shotcraft/upstream/demos/ui-entrance/carousel-3d/Carousel3D.tsx +303 -303
  174. package/lib/motion/shotcraft/upstream/demos/ui-entrance/clipcard-looping/ClipCardLooping.tsx +77 -77
  175. package/lib/motion/shotcraft/upstream/demos/ui-entrance/cloner-depth-echo/ClonerDepthEcho.tsx +311 -311
  176. package/lib/motion/shotcraft/upstream/demos/ui-entrance/deck-deal-flyin/DeckDealFlyin.tsx +307 -307
  177. package/lib/motion/shotcraft/upstream/demos/ui-entrance/doc-park-left-pill-deal/DocParkLeftPillDeal.tsx +349 -349
  178. package/lib/motion/shotcraft/upstream/demos/ui-entrance/document-typewriter-reveal/DocumentTypewriterReveal.tsx +255 -255
  179. package/lib/motion/shotcraft/upstream/demos/ui-entrance/draw-svg-trace/DrawSvgTrace.tsx +244 -244
  180. package/lib/motion/shotcraft/upstream/demos/ui-entrance/element-body-moves/ContactShadowLift.tsx +217 -217
  181. package/lib/motion/shotcraft/upstream/demos/ui-entrance/integration-hub-map/IntegrationHubMap.tsx +652 -652
  182. package/lib/motion/shotcraft/upstream/demos/ui-entrance/list-reveal/ListReveal.tsx +153 -153
  183. package/lib/motion/shotcraft/upstream/demos/ui-entrance/list-stack-press/ListStackPress.tsx +238 -238
  184. package/lib/motion/shotcraft/upstream/demos/ui-entrance/neon-frame-forerun/NeonFrameForerun.tsx +324 -324
  185. package/lib/motion/shotcraft/upstream/demos/ui-entrance/neon-frame-orbit-drop/NeonFrameForerunOrbit.tsx +354 -354
  186. package/lib/motion/shotcraft/upstream/demos/ui-entrance/page-waterfall-wall/PageWaterfallWall.tsx +101 -101
  187. package/lib/motion/shotcraft/upstream/demos/ui-entrance/page-waterfall-wall/VerticalTicker.tsx +129 -129
  188. package/lib/motion/shotcraft/upstream/demos/ui-entrance/product-card-progressive-assemble/ProductCardProgressiveAssemble.tsx +297 -297
  189. package/lib/motion/shotcraft/upstream/demos/ui-entrance/radial-wave/RadialWave.tsx +57 -57
  190. package/lib/motion/shotcraft/upstream/demos/ui-entrance/research-card-stack-scroll/ResearchCardStackScroll.tsx +155 -155
  191. package/lib/motion/shotcraft/upstream/demos/ui-entrance/row-embed/RowEmbed.tsx +175 -175
  192. package/lib/motion/shotcraft/upstream/demos/ui-entrance/value-stagger-gradient/ValueStaggerGradient.tsx +153 -153
  193. package/lib/motion/shotcraft/upstream/demos/ui-entrance/wall-reveal-moves/BentoLightUp.tsx +146 -146
  194. package/lib/motion/shotcraft/upstream/demos/ui-entrance/wall-reveal-moves/WireframeDrawOn.tsx +226 -226
  195. package/lib/motion/shotcraft/upstream/gallery/api/library.json +1 -1
  196. package/lib/motion/shotcraft/upstream/references/aesthetic-rules.md +193 -193
  197. package/lib/motion/shotcraft/upstream/references/final-review.md +121 -121
  198. package/lib/motion/shotcraft/upstream/references/guided-free-creation.md +199 -199
  199. package/lib/motion/shotcraft/upstream/references/jianying-export.md +183 -183
  200. package/lib/motion/shotcraft/upstream/references/music-beat-sync.md +257 -257
  201. package/lib/motion/shotcraft/upstream/references/pipeline.md +382 -382
  202. package/lib/motion/shotcraft/upstream/references/publish-upload-post.md +111 -111
  203. package/lib/motion/shotcraft/upstream/references/sequences/promo-energy-arc.md +50 -50
  204. package/lib/motion/shotcraft/upstream/references/sfx-sourcing.md +95 -95
  205. package/lib/motion/shotcraft/upstream/references/shots/camera/basic-3d-scene.md +41 -41
  206. package/lib/motion/shotcraft/upstream/references/shots/camera/crash-zoom-punch.md +52 -52
  207. package/lib/motion/shotcraft/upstream/references/shots/camera/cursor-flyover.md +39 -39
  208. package/lib/motion/shotcraft/upstream/references/shots/camera/depth-layer-moves.md +39 -39
  209. package/lib/motion/shotcraft/upstream/references/shots/camera/graze-face-tour.md +57 -57
  210. package/lib/motion/shotcraft/upstream/references/shots/camera/overhead-camera-moves.md +51 -51
  211. package/lib/motion/shotcraft/upstream/references/shots/camera/space-camera-moves.md +46 -46
  212. package/lib/motion/shotcraft/upstream/references/shots/camera/steep-tilt-glide.md +52 -52
  213. package/lib/motion/shotcraft/upstream/references/shots/camera/tension-camera-moves.md +43 -43
  214. package/lib/motion/shotcraft/upstream/references/shots/camera/terminal-3d.md +42 -42
  215. package/lib/motion/shotcraft/upstream/references/shots/data/before-after-slider-scrub.md +48 -48
  216. package/lib/motion/shotcraft/upstream/references/shots/data/chart-live-moves.md +52 -52
  217. package/lib/motion/shotcraft/upstream/references/shots/data/gauge-readout-moves.md +45 -45
  218. package/lib/motion/shotcraft/upstream/references/shots/data/scroll-brake-moves.md +46 -46
  219. package/lib/motion/shotcraft/upstream/references/shots/data/timeline-travel.md +44 -44
  220. package/lib/motion/shotcraft/upstream/references/shots/effects/assemble-then-type-flyin.md +63 -63
  221. package/lib/motion/shotcraft/upstream/references/shots/effects/aurora-bloom-bg-flip.md +54 -54
  222. package/lib/motion/shotcraft/upstream/references/shots/effects/brand-frame-snap.md +58 -58
  223. package/lib/motion/shotcraft/upstream/references/shots/effects/fui-hud-moves.md +35 -35
  224. package/lib/motion/shotcraft/upstream/references/shots/effects/glow-flyline-moves.md +53 -53
  225. package/lib/motion/shotcraft/upstream/references/shots/effects/icon-performance-moves.md +42 -42
  226. package/lib/motion/shotcraft/upstream/references/shots/effects/impact-feedback.md +50 -50
  227. package/lib/motion/shotcraft/upstream/references/shots/effects/light-play-moves.md +46 -46
  228. package/lib/motion/shotcraft/upstream/references/shots/effects/radial-ripple-phone-chips.md +56 -56
  229. package/lib/motion/shotcraft/upstream/references/shots/effects/riso-print-hits.md +49 -49
  230. package/lib/motion/shotcraft/upstream/references/shots/effects/scan-bracket-sweep.md +50 -50
  231. package/lib/motion/shotcraft/upstream/references/shots/effects/scanline-annotate-focus.md +53 -53
  232. package/lib/motion/shotcraft/upstream/references/shots/effects/scanline-assemble-flyin.md +53 -53
  233. package/lib/motion/shotcraft/upstream/references/shots/effects/slam-entrance-moves.md +55 -55
  234. package/lib/motion/shotcraft/upstream/references/shots/effects/spotlight-sweep-moves.md +52 -52
  235. package/lib/motion/shotcraft/upstream/references/shots/interaction/autolayout-gap-dial.md +60 -60
  236. package/lib/motion/shotcraft/upstream/references/shots/interaction/canvas-materialize-moves.md +57 -57
  237. package/lib/motion/shotcraft/upstream/references/shots/interaction/chip-grid-single-select-blackout.md +51 -51
  238. package/lib/motion/shotcraft/upstream/references/shots/interaction/collab-cursor-moves.md +41 -41
  239. package/lib/motion/shotcraft/upstream/references/shots/interaction/glass-pill-dictation-typing.md +53 -53
  240. package/lib/motion/shotcraft/upstream/references/shots/interaction/hashtag-to-pill-materialize.md +60 -60
  241. package/lib/motion/shotcraft/upstream/references/shots/interaction/picker-carousel-feature-cycle.md +55 -55
  242. package/lib/motion/shotcraft/upstream/references/shots/interaction/segmented-thumb-hero.md +57 -57
  243. package/lib/motion/shotcraft/upstream/references/shots/interaction/theme-switch-moves.md +47 -47
  244. package/lib/motion/shotcraft/upstream/references/shots/interaction/type-and-filter.md +37 -37
  245. package/lib/motion/shotcraft/upstream/references/shots/interaction/voice-waveform-live.md +54 -54
  246. package/lib/motion/shotcraft/upstream/references/shots/opening/brand-ink-open.md +36 -36
  247. package/lib/motion/shotcraft/upstream/references/shots/opening/crane-rise-reveal.md +56 -56
  248. package/lib/motion/shotcraft/upstream/references/shots/opening/dataviz-landscape-open.md +56 -56
  249. package/lib/motion/shotcraft/upstream/references/shots/opening/fracture.md +40 -40
  250. package/lib/motion/shotcraft/upstream/references/shots/opening/icon-field-colorize.md +60 -60
  251. package/lib/motion/shotcraft/upstream/references/shots/opening/letterspace-materialize.md +57 -57
  252. package/lib/motion/shotcraft/upstream/references/shots/opening/magician-card-flourish.md +73 -73
  253. package/lib/motion/shotcraft/upstream/references/shots/opening/orbit-ring-title-open.md +87 -87
  254. package/lib/motion/shotcraft/upstream/references/shots/opening/spotlight-hero-card.md +55 -55
  255. package/lib/motion/shotcraft/upstream/references/shots/opening/stroke-segment-build.md +50 -50
  256. package/lib/motion/shotcraft/upstream/references/shots/opening/text-as-mask.md +59 -59
  257. package/lib/motion/shotcraft/upstream/references/shots/outro/grain-dissolve.md +38 -38
  258. package/lib/motion/shotcraft/upstream/references/shots/outro/logo-shrink-wordmark-lockup.md +38 -38
  259. package/lib/motion/shotcraft/upstream/references/shots/outro/neon-triple-marquee.md +59 -59
  260. package/lib/motion/shotcraft/upstream/references/shots/outro/outro-group-photo-launch.md +39 -39
  261. package/lib/motion/shotcraft/upstream/references/shots/outro/ui-strip-away-outro.md +61 -61
  262. package/lib/motion/shotcraft/upstream/references/shots/outro/ui-to-brand-morph.md +52 -52
  263. package/lib/motion/shotcraft/upstream/references/shots/rhythm/beat-cut-moves.md +50 -50
  264. package/lib/motion/shotcraft/upstream/references/shots/rhythm/beat-step-list-theme-cycle.md +66 -66
  265. package/lib/motion/shotcraft/upstream/references/shots/rhythm/panel-grid-moves.md +43 -43
  266. package/lib/motion/shotcraft/upstream/references/shots/rhythm/quad-split-parallel-scenes.md +38 -38
  267. package/lib/motion/shotcraft/upstream/references/shots/rhythm/rhythm-interrupt-moves.md +38 -38
  268. package/lib/motion/shotcraft/upstream/references/shots/rhythm/sakuga-timing-shift.md +56 -56
  269. package/lib/motion/shotcraft/upstream/references/shots/rhythm/speed-ramp-freeze.md +44 -44
  270. package/lib/motion/shotcraft/upstream/references/shots/rhythm/trailer-grammar-moves.md +38 -38
  271. package/lib/motion/shotcraft/upstream/references/shots/transition/bottom-push-stack-wipe.md +63 -63
  272. package/lib/motion/shotcraft/upstream/references/shots/transition/card-flip-reveal.md +57 -57
  273. package/lib/motion/shotcraft/upstream/references/shots/transition/card-flock-tumble.md +63 -63
  274. package/lib/motion/shotcraft/upstream/references/shots/transition/circle-match-iris.md +58 -58
  275. package/lib/motion/shotcraft/upstream/references/shots/transition/gradient-transition.md +45 -45
  276. package/lib/motion/shotcraft/upstream/references/shots/transition/line-carry-transition.md +55 -55
  277. package/lib/motion/shotcraft/upstream/references/shots/transition/mosaic-reframe.md +49 -49
  278. package/lib/motion/shotcraft/upstream/references/shots/transition/page-turn-transitions.md +42 -42
  279. package/lib/motion/shotcraft/upstream/references/shots/transition/print-texture-transitions.md +42 -42
  280. package/lib/motion/shotcraft/upstream/references/shots/transition/shot-transitions.md +45 -45
  281. package/lib/motion/shotcraft/upstream/references/shots/transition/tear-streak-transitions.md +48 -48
  282. package/lib/motion/shotcraft/upstream/references/shots/transition/transition-hidden-cut.md +55 -55
  283. package/lib/motion/shotcraft/upstream/references/shots/transition/transition-travel.md +43 -43
  284. package/lib/motion/shotcraft/upstream/references/shots/transition/white-flash-logo-simplify-cut.md +41 -41
  285. package/lib/motion/shotcraft/upstream/references/shots/transition/wipe-transitions.md +42 -42
  286. package/lib/motion/shotcraft/upstream/references/shots/typography/blur-slide.md +59 -59
  287. package/lib/motion/shotcraft/upstream/references/shots/typography/brace-expand.md +55 -55
  288. package/lib/motion/shotcraft/upstream/references/shots/typography/countdown-arc-scatter.md +65 -65
  289. package/lib/motion/shotcraft/upstream/references/shots/typography/document-typewriter-reveal.md +42 -42
  290. package/lib/motion/shotcraft/upstream/references/shots/typography/flying-words.md +64 -64
  291. package/lib/motion/shotcraft/upstream/references/shots/typography/glitch-cycle.md +64 -64
  292. package/lib/motion/shotcraft/upstream/references/shots/typography/gradient-word-sweep.md +54 -54
  293. package/lib/motion/shotcraft/upstream/references/shots/typography/lead-word-zoom-assemble.md +91 -91
  294. package/lib/motion/shotcraft/upstream/references/shots/typography/marker-underline-title.md +51 -51
  295. package/lib/motion/shotcraft/upstream/references/shots/typography/outline-word-fill.md +66 -66
  296. package/lib/motion/shotcraft/upstream/references/shots/typography/paper-title-card.md +38 -38
  297. package/lib/motion/shotcraft/upstream/references/shots/typography/pill-chip-slot-cycle-handled.md +66 -66
  298. package/lib/motion/shotcraft/upstream/references/shots/typography/pill-slot-cycle.md +58 -58
  299. package/lib/motion/shotcraft/upstream/references/shots/typography/text-column-converge.md +61 -61
  300. package/lib/motion/shotcraft/upstream/references/shots/typography/title-demote-to-label.md +64 -64
  301. package/lib/motion/shotcraft/upstream/references/shots/typography/type-assembly-moves.md +45 -45
  302. package/lib/motion/shotcraft/upstream/references/shots/typography/type-entrance-moves.md +41 -41
  303. package/lib/motion/shotcraft/upstream/references/shots/typography/type-rhythm-sync.md +51 -51
  304. package/lib/motion/shotcraft/upstream/references/shots/typography/typewriter-moves.md +42 -42
  305. package/lib/motion/shotcraft/upstream/references/shots/typography/vertical-word-roll-blur-cycle.md +63 -63
  306. package/lib/motion/shotcraft/upstream/references/shots/typography/word-relay-filmstrip.md +57 -57
  307. package/lib/motion/shotcraft/upstream/references/shots/typography/word-relay-geometry.md +75 -75
  308. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/avatar-bracket-carousel.md +59 -59
  309. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/bezier-source-converge-merge.md +67 -67
  310. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/card-stack.md +60 -60
  311. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/carousel-3d.md +66 -66
  312. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/cloner-depth-echo.md +40 -40
  313. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/deck-deal-flyin.md +45 -45
  314. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/doc-park-left-pill-deal.md +62 -62
  315. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/draw-svg-trace.md +55 -55
  316. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/element-body-moves.md +37 -37
  317. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/integration-hub-map.md +55 -55
  318. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/list-reveal.md +50 -50
  319. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/list-stack-press.md +43 -43
  320. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/neon-frame-forerun.md +55 -55
  321. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/neon-frame-orbit-drop.md +51 -51
  322. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/page-waterfall-wall.md +51 -51
  323. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/product-card-progressive-assemble.md +56 -56
  324. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/radial-wave.md +49 -49
  325. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/research-card-stack-scroll.md +57 -57
  326. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/row-embed.md +36 -36
  327. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/value-stagger-gradient.md +64 -64
  328. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/wall-reveal-moves.md +47 -47
  329. package/lib/motion/shotcraft/upstream/references/sound-design.md +170 -170
  330. package/lib/motion/shotcraft/upstream/references/workbench.md +157 -157
  331. package/lib/motion/shotcraft/upstream/template/TEMPLATE.md +103 -103
  332. package/lib/motion/shotcraft/upstream/template/THEMES.md +44 -44
  333. package/lib/motion/shotcraft/upstream/template/package.json +20 -20
  334. package/lib/motion/shotcraft/upstream/template/remotion.config.ts +6 -6
  335. package/lib/motion/shotcraft/upstream/template/src/Root.tsx +17 -17
  336. package/lib/motion/shotcraft/upstream/template/src/aifl/Caption.tsx +65 -65
  337. package/lib/motion/shotcraft/upstream/template/src/aifl/DigitRoll.tsx +48 -48
  338. package/lib/motion/shotcraft/upstream/template/src/aifl/FlashCut.tsx +24 -24
  339. package/lib/motion/shotcraft/upstream/template/src/aifl/Main.tsx +192 -192
  340. package/lib/motion/shotcraft/upstream/template/src/aifl/PaperTitleCard.tsx +111 -111
  341. package/lib/motion/shotcraft/upstream/template/src/aifl/live/PageCam.tsx +150 -150
  342. package/lib/motion/shotcraft/upstream/template/src/aifl/live/SceneDetail.tsx +158 -158
  343. package/lib/motion/shotcraft/upstream/template/src/aifl/live/SceneFlyIn.tsx +468 -468
  344. package/lib/motion/shotcraft/upstream/template/src/aifl/live/SceneOpen.tsx +552 -552
  345. package/lib/motion/shotcraft/upstream/template/src/aifl/live/SceneOutroLive.tsx +411 -411
  346. package/lib/motion/shotcraft/upstream/template/src/aifl/live/ScenePapers.tsx +200 -200
  347. package/lib/motion/shotcraft/upstream/template/src/aifl/live/SceneWbr.tsx +324 -324
  348. package/lib/motion/shotcraft/upstream/template/src/aifl/live-layout.json +388 -388
  349. package/lib/motion/shotcraft/upstream/template/src/index.ts +4 -4
  350. package/lib/motion/shotcraft/upstream/template/src/themes/ThemedFilm.tsx +7 -7
  351. package/lib/motion/shotcraft/upstream/template/src/themes/manifest.tsx +68 -68
  352. package/lib/motion/shotcraft/upstream/template/src/themes/palette-assets.json +1 -1
  353. package/lib/motion/shotcraft/upstream/template/src/themes/palette-assets.ts +24 -24
  354. package/lib/motion/shotcraft/upstream/template/src/themes/palettes.json +74 -74
  355. package/lib/motion/shotcraft/upstream/template/src/themes/visual-theme.tsx +91 -91
  356. package/lib/motion/shotcraft/upstream/template/src/workbench.ts +213 -213
  357. package/lib/motion/shotcraft/upstream/template/tsconfig.json +15 -15
  358. package/lib/motion/style-frames.js +47 -12
  359. package/lib/motion-project.js +22 -3
  360. package/lib/motion-render-worker.js +31 -9
  361. package/lib/routing/router.js +12 -1
  362. package/lib/style-kernel.js +16 -6
  363. package/lib/video-trace-pool.js +128 -128
  364. package/package.json +1 -1
  365. 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
+ };