dsh-drawai 0.4.2 → 0.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (366) hide show
  1. package/README.md +4 -3
  2. package/lib/index.js +7777 -7719
  3. package/lib/motion/asset-pack.js +394 -394
  4. package/lib/motion/assets.js +291 -291
  5. package/lib/motion/demo-assets-lock.js +10 -10
  6. package/lib/motion/mgstyles/vendor/README.md +28 -28
  7. package/lib/motion/mgstyles/vendor/modules/d3/LICENSE +13 -13
  8. package/lib/motion/mgstyles/vendor/modules/d3/dist/d3.min.js +2 -2
  9. package/lib/motion/mgstyles/vendor/modules/opentype.js/LICENSE +20 -20
  10. package/lib/motion/mgstyles/vendor/modules/opentype.js/dist/opentype.mjs +14460 -14460
  11. package/lib/motion/mgstyles/vendor/modules/simplex-noise/LICENSE +21 -21
  12. package/lib/motion/mgstyles/vendor/modules/simplex-noise/dist/esm/simplex-noise.js +465 -465
  13. package/lib/motion/mgstyles/vendor/modules/topojson-client/LICENSE +13 -13
  14. package/lib/motion/mgstyles/vendor/modules/topojson-client/dist/topojson-client.min.js +2 -2
  15. package/lib/motion/render.js +179 -179
  16. package/lib/motion/shotcraft/upstream/SKILL.md +286 -286
  17. package/lib/motion/shotcraft/upstream/assets/lib/Caption.tsx +54 -54
  18. package/lib/motion/shotcraft/upstream/assets/lib/ClipCard.tsx +200 -200
  19. package/lib/motion/shotcraft/upstream/assets/lib/DigitRoll.tsx +45 -45
  20. package/lib/motion/shotcraft/upstream/assets/lib/FlashCut.tsx +20 -20
  21. package/lib/motion/shotcraft/upstream/assets/lib/FlatPanel.tsx +65 -65
  22. package/lib/motion/shotcraft/upstream/assets/lib/PageCam.tsx +151 -151
  23. package/lib/motion/shotcraft/upstream/assets/lib/VerticalTicker.tsx +129 -129
  24. package/lib/motion/shotcraft/upstream/assets/lib/helpers/camera.tsx +75 -75
  25. package/lib/motion/shotcraft/upstream/assets/lib/helpers/motion.ts +40 -40
  26. package/lib/motion/shotcraft/upstream/assets/lib/helpers/rand.ts +11 -11
  27. package/lib/motion/shotcraft/upstream/assets/lib/helpers/shake.ts +10 -10
  28. package/lib/motion/shotcraft/upstream/assets/scripts/build-readme-cover.mjs +49 -49
  29. package/lib/motion/shotcraft/upstream/assets/scripts/capture-template.mjs +210 -210
  30. package/lib/motion/shotcraft/upstream/assets/scripts/sfx-source.py +423 -423
  31. package/lib/motion/shotcraft/upstream/assets/scripts/smoke-render-demos.py +170 -170
  32. package/lib/motion/shotcraft/upstream/assets/scripts/test_sfx_source.py +157 -157
  33. package/lib/motion/shotcraft/upstream/demos/README.md +120 -120
  34. package/lib/motion/shotcraft/upstream/demos/_fixtures/Brand.tsx +112 -112
  35. package/lib/motion/shotcraft/upstream/demos/_fixtures/Fixtures.tsx +647 -647
  36. package/lib/motion/shotcraft/upstream/demos/_fixtures/Look.tsx +316 -316
  37. package/lib/motion/shotcraft/upstream/demos/_fixtures/Motion.tsx +82 -82
  38. package/lib/motion/shotcraft/upstream/demos/_fixtures/PageCam2D.tsx +115 -115
  39. package/lib/motion/shotcraft/upstream/demos/_fixtures/Polish.tsx +243 -243
  40. package/lib/motion/shotcraft/upstream/demos/_textures/live-layout.json +388 -388
  41. package/lib/motion/shotcraft/upstream/demos/camera/basic-3d-scene/Basic3DScene.tsx +250 -250
  42. package/lib/motion/shotcraft/upstream/demos/camera/crash-zoom-punch/CrashImpactReal.tsx +305 -305
  43. package/lib/motion/shotcraft/upstream/demos/camera/crash-zoom-punch/CrashZoomReal.tsx +246 -246
  44. package/lib/motion/shotcraft/upstream/demos/camera/cursor-flyover/CursorFlyover.tsx +390 -390
  45. package/lib/motion/shotcraft/upstream/demos/camera/depth-layer-moves/MultiplaneReal.tsx +138 -138
  46. package/lib/motion/shotcraft/upstream/demos/camera/graze-face-tour/GrazeFaceTour.tsx +542 -542
  47. package/lib/motion/shotcraft/upstream/demos/camera/overhead-camera-moves/OverheadTabletopDrop.tsx +315 -315
  48. package/lib/motion/shotcraft/upstream/demos/camera/overhead-camera-moves/TiltReveal.tsx +299 -299
  49. package/lib/motion/shotcraft/upstream/demos/camera/space-camera-moves/DroneDiveLanding.tsx +173 -173
  50. package/lib/motion/shotcraft/upstream/demos/camera/space-camera-moves/ExplodedView.tsx +348 -348
  51. package/lib/motion/shotcraft/upstream/demos/camera/steep-tilt-glide/SteepTiltGlide.tsx +366 -366
  52. package/lib/motion/shotcraft/upstream/demos/camera/tension-camera-moves/BulletTimeFreezeOrbit.tsx +279 -279
  53. package/lib/motion/shotcraft/upstream/demos/camera/tension-camera-moves/PullBackIsolation.tsx +184 -184
  54. package/lib/motion/shotcraft/upstream/demos/camera/terminal-3d/Terminal3D.tsx +390 -390
  55. package/lib/motion/shotcraft/upstream/demos/data/before-after-slider-scrub/BeforeAfterSliderScrub.tsx +155 -155
  56. package/lib/motion/shotcraft/upstream/demos/data/chart-live-moves/AxisRescaleShockV2.tsx +303 -303
  57. package/lib/motion/shotcraft/upstream/demos/data/chart-live-moves/OscilloscopeStreamV2.tsx +290 -290
  58. package/lib/motion/shotcraft/upstream/demos/data/chart-live-moves/UnitDotSwarmRegroupV2.tsx +278 -278
  59. package/lib/motion/shotcraft/upstream/demos/data/gauge-readout-moves/NeedleSweepSelftest.tsx +307 -307
  60. package/lib/motion/shotcraft/upstream/demos/data/gauge-readout-moves/TapeScrollFixedPointer.tsx +215 -215
  61. package/lib/motion/shotcraft/upstream/demos/data/scroll-brake-moves/BrakeReticleLock.tsx +299 -299
  62. package/lib/motion/shotcraft/upstream/demos/data/scroll-brake-moves/ChangelogScrollBrake.tsx +232 -232
  63. package/lib/motion/shotcraft/upstream/demos/data/timeline-travel/TimelineTravel.tsx +290 -290
  64. package/lib/motion/shotcraft/upstream/demos/effects/assemble-then-type-flyin/AssembleThenTypeFlyin.tsx +273 -273
  65. package/lib/motion/shotcraft/upstream/demos/effects/aurora-bloom-bg-flip/AuroraBloomBgFlip.tsx +167 -167
  66. package/lib/motion/shotcraft/upstream/demos/effects/brand-frame-snap/BrandFrameSnap.tsx +536 -536
  67. package/lib/motion/shotcraft/upstream/demos/effects/fui-hud-moves/ReticleLockOn.tsx +164 -164
  68. package/lib/motion/shotcraft/upstream/demos/effects/glow-flyline-moves/FlylineArc.tsx +175 -175
  69. package/lib/motion/shotcraft/upstream/demos/effects/glow-flyline-moves/GlowOrbAmbient.tsx +197 -197
  70. package/lib/motion/shotcraft/upstream/demos/effects/glow-flyline-moves/OrbFlylineRelay.tsx +241 -241
  71. package/lib/motion/shotcraft/upstream/demos/effects/icon-performance-moves/AttentionBounce.tsx +279 -279
  72. package/lib/motion/shotcraft/upstream/demos/effects/impact-feedback/AnimeImpact.tsx +230 -230
  73. package/lib/motion/shotcraft/upstream/demos/effects/impact-feedback/HitCounter.tsx +345 -345
  74. package/lib/motion/shotcraft/upstream/demos/effects/light-play-moves/SheenSweepRetry.tsx +275 -275
  75. package/lib/motion/shotcraft/upstream/demos/effects/light-play-moves/SpotlightSweepReveal.tsx +229 -229
  76. package/lib/motion/shotcraft/upstream/demos/effects/radial-ripple-phone-chips/RadialRipplePhoneChips.tsx +312 -312
  77. package/lib/motion/shotcraft/upstream/demos/effects/riso-print-hits/RisoMisregistrationHit.tsx +222 -222
  78. package/lib/motion/shotcraft/upstream/demos/effects/scan-bracket-sweep/ScanBracketSweep.tsx +295 -295
  79. package/lib/motion/shotcraft/upstream/demos/effects/scanline-annotate-focus/ScanlineAnnotateFocus.tsx +329 -329
  80. package/lib/motion/shotcraft/upstream/demos/effects/scanline-assemble-flyin/ScanlineAssembleFlyin.tsx +315 -315
  81. package/lib/motion/shotcraft/upstream/demos/effects/slam-entrance-moves/ImpactBurstKit.tsx +264 -264
  82. package/lib/motion/shotcraft/upstream/demos/effects/slam-entrance-moves/KanadaPerspectiveSnap.tsx +260 -260
  83. package/lib/motion/shotcraft/upstream/demos/effects/slam-entrance-moves/ScoreSlam.tsx +263 -263
  84. package/lib/motion/shotcraft/upstream/demos/effects/spotlight-sweep-moves/CornerSpotlightReveal.tsx +123 -123
  85. package/lib/motion/shotcraft/upstream/demos/effects/spotlight-sweep-moves/GlowWakeSleepPanel.tsx +187 -187
  86. package/lib/motion/shotcraft/upstream/demos/effects/spotlight-sweep-moves/SlideSpotlightPan.tsx +175 -175
  87. package/lib/motion/shotcraft/upstream/demos/interaction/autolayout-gap-dial/AutolayoutGapDial.tsx +305 -305
  88. package/lib/motion/shotcraft/upstream/demos/interaction/canvas-materialize-moves/DiagramCascadeBuild.tsx +350 -350
  89. package/lib/motion/shotcraft/upstream/demos/interaction/canvas-materialize-moves/PanelToCanvasMaterialize.tsx +352 -352
  90. package/lib/motion/shotcraft/upstream/demos/interaction/chip-grid-single-select-blackout/ChipGridSingleSelectBlackout.tsx +218 -218
  91. package/lib/motion/shotcraft/upstream/demos/interaction/collab-cursor-moves/CursorCastEnsemble.tsx +297 -297
  92. package/lib/motion/shotcraft/upstream/demos/interaction/glass-pill-dictation-typing/GlassPillDictationTyping.tsx +157 -157
  93. package/lib/motion/shotcraft/upstream/demos/interaction/hashtag-to-pill-materialize/HashtagToPillMaterialize.tsx +218 -218
  94. package/lib/motion/shotcraft/upstream/demos/interaction/picker-carousel-feature-cycle/PickerCarouselFeatureCycle.tsx +202 -202
  95. package/lib/motion/shotcraft/upstream/demos/interaction/segmented-thumb-hero/SegmentedThumbHero.tsx +265 -265
  96. package/lib/motion/shotcraft/upstream/demos/interaction/theme-switch-moves/PaletteThemeRipple.tsx +457 -457
  97. package/lib/motion/shotcraft/upstream/demos/interaction/theme-switch-moves/ThemeSweepToggle.tsx +446 -446
  98. package/lib/motion/shotcraft/upstream/demos/interaction/type-and-filter/TypeAndFilter.tsx +249 -249
  99. package/lib/motion/shotcraft/upstream/demos/interaction/voice-waveform-live/VoiceWaveformLive.tsx +278 -278
  100. package/lib/motion/shotcraft/upstream/demos/opening/crane-rise-reveal/CraneRiseReveal.tsx +332 -332
  101. package/lib/motion/shotcraft/upstream/demos/opening/dataviz-landscape-open/DatavizLandscapeOpen.tsx +358 -358
  102. package/lib/motion/shotcraft/upstream/demos/opening/fracture/Fracture.tsx +201 -201
  103. package/lib/motion/shotcraft/upstream/demos/opening/icon-field-colorize/IconFieldColorize.tsx +200 -200
  104. package/lib/motion/shotcraft/upstream/demos/opening/letterspace-materialize/LetterspaceMaterialize.tsx +208 -208
  105. package/lib/motion/shotcraft/upstream/demos/opening/magician-card-flourish/MagicianCardFlourish.tsx +341 -341
  106. package/lib/motion/shotcraft/upstream/demos/opening/orbit-ring-title-open/OrbitRingTitleOpen.tsx +389 -389
  107. package/lib/motion/shotcraft/upstream/demos/opening/spotlight-hero-card/SpotlightHeroCard.tsx +293 -293
  108. package/lib/motion/shotcraft/upstream/demos/opening/stroke-segment-build/StrokeSegmentBuild.tsx +183 -183
  109. package/lib/motion/shotcraft/upstream/demos/opening/text-as-mask/TextAsMask.tsx +245 -245
  110. package/lib/motion/shotcraft/upstream/demos/outro/grain-dissolve/GrainDissolve.tsx +222 -222
  111. package/lib/motion/shotcraft/upstream/demos/outro/logo-shrink-wordmark-lockup/LogoShrinkWordmarkLockup.tsx +223 -223
  112. package/lib/motion/shotcraft/upstream/demos/outro/neon-triple-marquee/NeonTripleMarquee.tsx +217 -217
  113. package/lib/motion/shotcraft/upstream/demos/outro/outro-group-photo-launch/OutroGroupPhotoLaunch.tsx +343 -343
  114. package/lib/motion/shotcraft/upstream/demos/outro/ui-strip-away-outro/UiStripAwayOutro.tsx +357 -357
  115. package/lib/motion/shotcraft/upstream/demos/outro/ui-to-brand-morph/IconFlipBloomLogo.tsx +187 -187
  116. package/lib/motion/shotcraft/upstream/demos/outro/ui-to-brand-morph/InputMorphsIntoLogo.tsx +333 -333
  117. package/lib/motion/shotcraft/upstream/demos/rhythm/beat-cut-moves/PaparazziFlash.tsx +274 -274
  118. package/lib/motion/shotcraft/upstream/demos/rhythm/beat-step-list-theme-cycle/BeatStepListThemeCycle.tsx +270 -270
  119. package/lib/motion/shotcraft/upstream/demos/rhythm/panel-grid-moves/ComicPanelSplit.tsx +430 -430
  120. package/lib/motion/shotcraft/upstream/demos/rhythm/quad-split-parallel-scenes/QuadSplitParallelScenes.tsx +252 -252
  121. package/lib/motion/shotcraft/upstream/demos/rhythm/rhythm-interrupt-moves/JumpCutPunchIn.tsx +106 -106
  122. package/lib/motion/shotcraft/upstream/demos/rhythm/sakuga-timing-shift/SakugaTimingShift.tsx +288 -288
  123. package/lib/motion/shotcraft/upstream/demos/rhythm/speed-ramp-freeze/FreezeAnnotateReal.tsx +362 -362
  124. package/lib/motion/shotcraft/upstream/demos/rhythm/trailer-grammar-moves/TrailerBumper.tsx +168 -168
  125. package/lib/motion/shotcraft/upstream/demos/transition/bottom-push-stack-wipe/BottomPushStackWipe.tsx +310 -310
  126. package/lib/motion/shotcraft/upstream/demos/transition/card-flip-reveal/CardFlipReveal.tsx +261 -261
  127. package/lib/motion/shotcraft/upstream/demos/transition/card-flock-tumble/CardFlockTumble.tsx +459 -459
  128. package/lib/motion/shotcraft/upstream/demos/transition/circle-match-iris/CircleMatchIris.tsx +294 -294
  129. package/lib/motion/shotcraft/upstream/demos/transition/gradient-transition/GradientTransition.tsx +161 -161
  130. package/lib/motion/shotcraft/upstream/demos/transition/line-carry-transition/LineCarryTransition.tsx +248 -248
  131. package/lib/motion/shotcraft/upstream/demos/transition/mosaic-reframe/MosaicReframe.tsx +359 -359
  132. package/lib/motion/shotcraft/upstream/demos/transition/page-turn-transitions/BarnDoorSplit.tsx +227 -227
  133. package/lib/motion/shotcraft/upstream/demos/transition/print-texture-transitions/InkBleedReveal.tsx +162 -162
  134. package/lib/motion/shotcraft/upstream/demos/transition/shot-transitions/PortalWipeV2.tsx +248 -248
  135. package/lib/motion/shotcraft/upstream/demos/transition/shot-transitions/WhipBrakeReal.tsx +186 -186
  136. package/lib/motion/shotcraft/upstream/demos/transition/tear-streak-transitions/GlitchDisplace.tsx +355 -355
  137. package/lib/motion/shotcraft/upstream/demos/transition/transition-hidden-cut/InvisibleCut.tsx +272 -272
  138. package/lib/motion/shotcraft/upstream/demos/transition/transition-hidden-cut/LightLeakBurn.tsx +262 -262
  139. package/lib/motion/shotcraft/upstream/demos/transition/transition-hidden-cut/VersusSlam.tsx +217 -217
  140. package/lib/motion/shotcraft/upstream/demos/transition/transition-travel/LetterformZoom.tsx +285 -285
  141. package/lib/motion/shotcraft/upstream/demos/transition/white-flash-logo-simplify-cut/WhiteFlashLogoSimplifyCut.tsx +205 -205
  142. package/lib/motion/shotcraft/upstream/demos/transition/wipe-transitions/BlindsSlice.tsx +178 -178
  143. package/lib/motion/shotcraft/upstream/demos/typography/blur-slide/BlurSlide.tsx +147 -147
  144. package/lib/motion/shotcraft/upstream/demos/typography/brace-expand/BraceExpand.tsx +143 -143
  145. package/lib/motion/shotcraft/upstream/demos/typography/brand-ink-open/BrandInkOpen.tsx +134 -134
  146. package/lib/motion/shotcraft/upstream/demos/typography/countdown-arc-scatter/CountdownArcScatter.tsx +217 -217
  147. package/lib/motion/shotcraft/upstream/demos/typography/flying-words/FlyingWords.tsx +198 -198
  148. package/lib/motion/shotcraft/upstream/demos/typography/glitch-cycle/GlitchCycle.tsx +221 -221
  149. package/lib/motion/shotcraft/upstream/demos/typography/gradient-word-sweep/GradientWordSweep.tsx +312 -312
  150. package/lib/motion/shotcraft/upstream/demos/typography/lead-word-zoom-assemble/LeadWordZoomAssemble.tsx +261 -261
  151. package/lib/motion/shotcraft/upstream/demos/typography/marker-underline-title/MarkerUnderlineTitle.tsx +121 -121
  152. package/lib/motion/shotcraft/upstream/demos/typography/outline-word-fill/OutlineWordFill.tsx +153 -153
  153. package/lib/motion/shotcraft/upstream/demos/typography/paper-title-card/PaperTitleCard.tsx +179 -179
  154. package/lib/motion/shotcraft/upstream/demos/typography/pill-chip-slot-cycle-handled/PillChipSlotCycleHandled.tsx +140 -140
  155. package/lib/motion/shotcraft/upstream/demos/typography/pill-slot-cycle/PillSlotCycle.tsx +309 -309
  156. package/lib/motion/shotcraft/upstream/demos/typography/text-column-converge/TextColumnConverge.tsx +191 -191
  157. package/lib/motion/shotcraft/upstream/demos/typography/title-demote-to-label/TitleDemoteToLabel.tsx +292 -292
  158. package/lib/motion/shotcraft/upstream/demos/typography/type-assembly-moves/LetterformDriftAssembly.tsx +135 -135
  159. package/lib/motion/shotcraft/upstream/demos/typography/type-assembly-moves/SplitTextStagger.tsx +124 -124
  160. package/lib/motion/shotcraft/upstream/demos/typography/type-assembly-moves/TextOnPath.tsx +255 -255
  161. package/lib/motion/shotcraft/upstream/demos/typography/type-entrance-moves/LetterDropPhysics.tsx +173 -173
  162. package/lib/motion/shotcraft/upstream/demos/typography/type-rhythm-sync/FontWeightPump.tsx +225 -225
  163. package/lib/motion/shotcraft/upstream/demos/typography/type-rhythm-sync/KaraokeFillSync.tsx +141 -141
  164. package/lib/motion/shotcraft/upstream/demos/typography/typewriter-moves/TypewriterErrorRetype.tsx +137 -137
  165. package/lib/motion/shotcraft/upstream/demos/typography/vertical-word-roll-blur-cycle/VerticalWordRollBlurCycle.tsx +147 -147
  166. package/lib/motion/shotcraft/upstream/demos/typography/word-relay-filmstrip/WordRelayFilmstrip.tsx +409 -409
  167. package/lib/motion/shotcraft/upstream/demos/typography/word-relay-geometry/WordRelayGeometry.tsx +280 -280
  168. package/lib/motion/shotcraft/upstream/demos/ui-entrance/avatar-bracket-carousel/AvatarBracketCarousel.tsx +271 -271
  169. package/lib/motion/shotcraft/upstream/demos/ui-entrance/bezier-source-converge-merge/BezierSourceConvergeMerge.tsx +385 -385
  170. package/lib/motion/shotcraft/upstream/demos/ui-entrance/card-stack/CardStack.tsx +312 -312
  171. package/lib/motion/shotcraft/upstream/demos/ui-entrance/carousel-3d/Carousel3D.tsx +303 -303
  172. package/lib/motion/shotcraft/upstream/demos/ui-entrance/clipcard-looping/ClipCardLooping.tsx +77 -77
  173. package/lib/motion/shotcraft/upstream/demos/ui-entrance/cloner-depth-echo/ClonerDepthEcho.tsx +311 -311
  174. package/lib/motion/shotcraft/upstream/demos/ui-entrance/deck-deal-flyin/DeckDealFlyin.tsx +307 -307
  175. package/lib/motion/shotcraft/upstream/demos/ui-entrance/doc-park-left-pill-deal/DocParkLeftPillDeal.tsx +349 -349
  176. package/lib/motion/shotcraft/upstream/demos/ui-entrance/document-typewriter-reveal/DocumentTypewriterReveal.tsx +255 -255
  177. package/lib/motion/shotcraft/upstream/demos/ui-entrance/draw-svg-trace/DrawSvgTrace.tsx +244 -244
  178. package/lib/motion/shotcraft/upstream/demos/ui-entrance/element-body-moves/ContactShadowLift.tsx +217 -217
  179. package/lib/motion/shotcraft/upstream/demos/ui-entrance/integration-hub-map/IntegrationHubMap.tsx +652 -652
  180. package/lib/motion/shotcraft/upstream/demos/ui-entrance/list-reveal/ListReveal.tsx +153 -153
  181. package/lib/motion/shotcraft/upstream/demos/ui-entrance/list-stack-press/ListStackPress.tsx +238 -238
  182. package/lib/motion/shotcraft/upstream/demos/ui-entrance/neon-frame-forerun/NeonFrameForerun.tsx +324 -324
  183. package/lib/motion/shotcraft/upstream/demos/ui-entrance/neon-frame-orbit-drop/NeonFrameForerunOrbit.tsx +354 -354
  184. package/lib/motion/shotcraft/upstream/demos/ui-entrance/page-waterfall-wall/PageWaterfallWall.tsx +101 -101
  185. package/lib/motion/shotcraft/upstream/demos/ui-entrance/page-waterfall-wall/VerticalTicker.tsx +129 -129
  186. package/lib/motion/shotcraft/upstream/demos/ui-entrance/product-card-progressive-assemble/ProductCardProgressiveAssemble.tsx +297 -297
  187. package/lib/motion/shotcraft/upstream/demos/ui-entrance/radial-wave/RadialWave.tsx +57 -57
  188. package/lib/motion/shotcraft/upstream/demos/ui-entrance/research-card-stack-scroll/ResearchCardStackScroll.tsx +155 -155
  189. package/lib/motion/shotcraft/upstream/demos/ui-entrance/row-embed/RowEmbed.tsx +175 -175
  190. package/lib/motion/shotcraft/upstream/demos/ui-entrance/value-stagger-gradient/ValueStaggerGradient.tsx +153 -153
  191. package/lib/motion/shotcraft/upstream/demos/ui-entrance/wall-reveal-moves/BentoLightUp.tsx +146 -146
  192. package/lib/motion/shotcraft/upstream/demos/ui-entrance/wall-reveal-moves/WireframeDrawOn.tsx +226 -226
  193. package/lib/motion/shotcraft/upstream/gallery/api/library.json +1 -1
  194. package/lib/motion/shotcraft/upstream/references/aesthetic-rules.md +193 -193
  195. package/lib/motion/shotcraft/upstream/references/final-review.md +121 -121
  196. package/lib/motion/shotcraft/upstream/references/guided-free-creation.md +199 -199
  197. package/lib/motion/shotcraft/upstream/references/jianying-export.md +183 -183
  198. package/lib/motion/shotcraft/upstream/references/music-beat-sync.md +257 -257
  199. package/lib/motion/shotcraft/upstream/references/pipeline.md +382 -382
  200. package/lib/motion/shotcraft/upstream/references/publish-upload-post.md +111 -111
  201. package/lib/motion/shotcraft/upstream/references/sequences/promo-energy-arc.md +50 -50
  202. package/lib/motion/shotcraft/upstream/references/sfx-sourcing.md +95 -95
  203. package/lib/motion/shotcraft/upstream/references/shots/camera/basic-3d-scene.md +41 -41
  204. package/lib/motion/shotcraft/upstream/references/shots/camera/crash-zoom-punch.md +52 -52
  205. package/lib/motion/shotcraft/upstream/references/shots/camera/cursor-flyover.md +39 -39
  206. package/lib/motion/shotcraft/upstream/references/shots/camera/depth-layer-moves.md +39 -39
  207. package/lib/motion/shotcraft/upstream/references/shots/camera/graze-face-tour.md +57 -57
  208. package/lib/motion/shotcraft/upstream/references/shots/camera/overhead-camera-moves.md +51 -51
  209. package/lib/motion/shotcraft/upstream/references/shots/camera/space-camera-moves.md +46 -46
  210. package/lib/motion/shotcraft/upstream/references/shots/camera/steep-tilt-glide.md +52 -52
  211. package/lib/motion/shotcraft/upstream/references/shots/camera/tension-camera-moves.md +43 -43
  212. package/lib/motion/shotcraft/upstream/references/shots/camera/terminal-3d.md +42 -42
  213. package/lib/motion/shotcraft/upstream/references/shots/data/before-after-slider-scrub.md +48 -48
  214. package/lib/motion/shotcraft/upstream/references/shots/data/chart-live-moves.md +52 -52
  215. package/lib/motion/shotcraft/upstream/references/shots/data/gauge-readout-moves.md +45 -45
  216. package/lib/motion/shotcraft/upstream/references/shots/data/scroll-brake-moves.md +46 -46
  217. package/lib/motion/shotcraft/upstream/references/shots/data/timeline-travel.md +44 -44
  218. package/lib/motion/shotcraft/upstream/references/shots/effects/assemble-then-type-flyin.md +63 -63
  219. package/lib/motion/shotcraft/upstream/references/shots/effects/aurora-bloom-bg-flip.md +54 -54
  220. package/lib/motion/shotcraft/upstream/references/shots/effects/brand-frame-snap.md +58 -58
  221. package/lib/motion/shotcraft/upstream/references/shots/effects/fui-hud-moves.md +35 -35
  222. package/lib/motion/shotcraft/upstream/references/shots/effects/glow-flyline-moves.md +53 -53
  223. package/lib/motion/shotcraft/upstream/references/shots/effects/icon-performance-moves.md +42 -42
  224. package/lib/motion/shotcraft/upstream/references/shots/effects/impact-feedback.md +50 -50
  225. package/lib/motion/shotcraft/upstream/references/shots/effects/light-play-moves.md +46 -46
  226. package/lib/motion/shotcraft/upstream/references/shots/effects/radial-ripple-phone-chips.md +56 -56
  227. package/lib/motion/shotcraft/upstream/references/shots/effects/riso-print-hits.md +49 -49
  228. package/lib/motion/shotcraft/upstream/references/shots/effects/scan-bracket-sweep.md +50 -50
  229. package/lib/motion/shotcraft/upstream/references/shots/effects/scanline-annotate-focus.md +53 -53
  230. package/lib/motion/shotcraft/upstream/references/shots/effects/scanline-assemble-flyin.md +53 -53
  231. package/lib/motion/shotcraft/upstream/references/shots/effects/slam-entrance-moves.md +55 -55
  232. package/lib/motion/shotcraft/upstream/references/shots/effects/spotlight-sweep-moves.md +52 -52
  233. package/lib/motion/shotcraft/upstream/references/shots/interaction/autolayout-gap-dial.md +60 -60
  234. package/lib/motion/shotcraft/upstream/references/shots/interaction/canvas-materialize-moves.md +57 -57
  235. package/lib/motion/shotcraft/upstream/references/shots/interaction/chip-grid-single-select-blackout.md +51 -51
  236. package/lib/motion/shotcraft/upstream/references/shots/interaction/collab-cursor-moves.md +41 -41
  237. package/lib/motion/shotcraft/upstream/references/shots/interaction/glass-pill-dictation-typing.md +53 -53
  238. package/lib/motion/shotcraft/upstream/references/shots/interaction/hashtag-to-pill-materialize.md +60 -60
  239. package/lib/motion/shotcraft/upstream/references/shots/interaction/picker-carousel-feature-cycle.md +55 -55
  240. package/lib/motion/shotcraft/upstream/references/shots/interaction/segmented-thumb-hero.md +57 -57
  241. package/lib/motion/shotcraft/upstream/references/shots/interaction/theme-switch-moves.md +47 -47
  242. package/lib/motion/shotcraft/upstream/references/shots/interaction/type-and-filter.md +37 -37
  243. package/lib/motion/shotcraft/upstream/references/shots/interaction/voice-waveform-live.md +54 -54
  244. package/lib/motion/shotcraft/upstream/references/shots/opening/brand-ink-open.md +36 -36
  245. package/lib/motion/shotcraft/upstream/references/shots/opening/crane-rise-reveal.md +56 -56
  246. package/lib/motion/shotcraft/upstream/references/shots/opening/dataviz-landscape-open.md +56 -56
  247. package/lib/motion/shotcraft/upstream/references/shots/opening/fracture.md +40 -40
  248. package/lib/motion/shotcraft/upstream/references/shots/opening/icon-field-colorize.md +60 -60
  249. package/lib/motion/shotcraft/upstream/references/shots/opening/letterspace-materialize.md +57 -57
  250. package/lib/motion/shotcraft/upstream/references/shots/opening/magician-card-flourish.md +73 -73
  251. package/lib/motion/shotcraft/upstream/references/shots/opening/orbit-ring-title-open.md +87 -87
  252. package/lib/motion/shotcraft/upstream/references/shots/opening/spotlight-hero-card.md +55 -55
  253. package/lib/motion/shotcraft/upstream/references/shots/opening/stroke-segment-build.md +50 -50
  254. package/lib/motion/shotcraft/upstream/references/shots/opening/text-as-mask.md +59 -59
  255. package/lib/motion/shotcraft/upstream/references/shots/outro/grain-dissolve.md +38 -38
  256. package/lib/motion/shotcraft/upstream/references/shots/outro/logo-shrink-wordmark-lockup.md +38 -38
  257. package/lib/motion/shotcraft/upstream/references/shots/outro/neon-triple-marquee.md +59 -59
  258. package/lib/motion/shotcraft/upstream/references/shots/outro/outro-group-photo-launch.md +39 -39
  259. package/lib/motion/shotcraft/upstream/references/shots/outro/ui-strip-away-outro.md +61 -61
  260. package/lib/motion/shotcraft/upstream/references/shots/outro/ui-to-brand-morph.md +52 -52
  261. package/lib/motion/shotcraft/upstream/references/shots/rhythm/beat-cut-moves.md +50 -50
  262. package/lib/motion/shotcraft/upstream/references/shots/rhythm/beat-step-list-theme-cycle.md +66 -66
  263. package/lib/motion/shotcraft/upstream/references/shots/rhythm/panel-grid-moves.md +43 -43
  264. package/lib/motion/shotcraft/upstream/references/shots/rhythm/quad-split-parallel-scenes.md +38 -38
  265. package/lib/motion/shotcraft/upstream/references/shots/rhythm/rhythm-interrupt-moves.md +38 -38
  266. package/lib/motion/shotcraft/upstream/references/shots/rhythm/sakuga-timing-shift.md +56 -56
  267. package/lib/motion/shotcraft/upstream/references/shots/rhythm/speed-ramp-freeze.md +44 -44
  268. package/lib/motion/shotcraft/upstream/references/shots/rhythm/trailer-grammar-moves.md +38 -38
  269. package/lib/motion/shotcraft/upstream/references/shots/transition/bottom-push-stack-wipe.md +63 -63
  270. package/lib/motion/shotcraft/upstream/references/shots/transition/card-flip-reveal.md +57 -57
  271. package/lib/motion/shotcraft/upstream/references/shots/transition/card-flock-tumble.md +63 -63
  272. package/lib/motion/shotcraft/upstream/references/shots/transition/circle-match-iris.md +58 -58
  273. package/lib/motion/shotcraft/upstream/references/shots/transition/gradient-transition.md +45 -45
  274. package/lib/motion/shotcraft/upstream/references/shots/transition/line-carry-transition.md +55 -55
  275. package/lib/motion/shotcraft/upstream/references/shots/transition/mosaic-reframe.md +49 -49
  276. package/lib/motion/shotcraft/upstream/references/shots/transition/page-turn-transitions.md +42 -42
  277. package/lib/motion/shotcraft/upstream/references/shots/transition/print-texture-transitions.md +42 -42
  278. package/lib/motion/shotcraft/upstream/references/shots/transition/shot-transitions.md +45 -45
  279. package/lib/motion/shotcraft/upstream/references/shots/transition/tear-streak-transitions.md +48 -48
  280. package/lib/motion/shotcraft/upstream/references/shots/transition/transition-hidden-cut.md +55 -55
  281. package/lib/motion/shotcraft/upstream/references/shots/transition/transition-travel.md +43 -43
  282. package/lib/motion/shotcraft/upstream/references/shots/transition/white-flash-logo-simplify-cut.md +41 -41
  283. package/lib/motion/shotcraft/upstream/references/shots/transition/wipe-transitions.md +42 -42
  284. package/lib/motion/shotcraft/upstream/references/shots/typography/blur-slide.md +59 -59
  285. package/lib/motion/shotcraft/upstream/references/shots/typography/brace-expand.md +55 -55
  286. package/lib/motion/shotcraft/upstream/references/shots/typography/countdown-arc-scatter.md +65 -65
  287. package/lib/motion/shotcraft/upstream/references/shots/typography/document-typewriter-reveal.md +42 -42
  288. package/lib/motion/shotcraft/upstream/references/shots/typography/flying-words.md +64 -64
  289. package/lib/motion/shotcraft/upstream/references/shots/typography/glitch-cycle.md +64 -64
  290. package/lib/motion/shotcraft/upstream/references/shots/typography/gradient-word-sweep.md +54 -54
  291. package/lib/motion/shotcraft/upstream/references/shots/typography/lead-word-zoom-assemble.md +91 -91
  292. package/lib/motion/shotcraft/upstream/references/shots/typography/marker-underline-title.md +51 -51
  293. package/lib/motion/shotcraft/upstream/references/shots/typography/outline-word-fill.md +66 -66
  294. package/lib/motion/shotcraft/upstream/references/shots/typography/paper-title-card.md +38 -38
  295. package/lib/motion/shotcraft/upstream/references/shots/typography/pill-chip-slot-cycle-handled.md +66 -66
  296. package/lib/motion/shotcraft/upstream/references/shots/typography/pill-slot-cycle.md +58 -58
  297. package/lib/motion/shotcraft/upstream/references/shots/typography/text-column-converge.md +61 -61
  298. package/lib/motion/shotcraft/upstream/references/shots/typography/title-demote-to-label.md +64 -64
  299. package/lib/motion/shotcraft/upstream/references/shots/typography/type-assembly-moves.md +45 -45
  300. package/lib/motion/shotcraft/upstream/references/shots/typography/type-entrance-moves.md +41 -41
  301. package/lib/motion/shotcraft/upstream/references/shots/typography/type-rhythm-sync.md +51 -51
  302. package/lib/motion/shotcraft/upstream/references/shots/typography/typewriter-moves.md +42 -42
  303. package/lib/motion/shotcraft/upstream/references/shots/typography/vertical-word-roll-blur-cycle.md +63 -63
  304. package/lib/motion/shotcraft/upstream/references/shots/typography/word-relay-filmstrip.md +57 -57
  305. package/lib/motion/shotcraft/upstream/references/shots/typography/word-relay-geometry.md +75 -75
  306. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/avatar-bracket-carousel.md +59 -59
  307. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/bezier-source-converge-merge.md +67 -67
  308. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/card-stack.md +60 -60
  309. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/carousel-3d.md +66 -66
  310. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/cloner-depth-echo.md +40 -40
  311. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/deck-deal-flyin.md +45 -45
  312. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/doc-park-left-pill-deal.md +62 -62
  313. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/draw-svg-trace.md +55 -55
  314. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/element-body-moves.md +37 -37
  315. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/integration-hub-map.md +55 -55
  316. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/list-reveal.md +50 -50
  317. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/list-stack-press.md +43 -43
  318. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/neon-frame-forerun.md +55 -55
  319. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/neon-frame-orbit-drop.md +51 -51
  320. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/page-waterfall-wall.md +51 -51
  321. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/product-card-progressive-assemble.md +56 -56
  322. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/radial-wave.md +49 -49
  323. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/research-card-stack-scroll.md +57 -57
  324. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/row-embed.md +36 -36
  325. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/value-stagger-gradient.md +64 -64
  326. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/wall-reveal-moves.md +47 -47
  327. package/lib/motion/shotcraft/upstream/references/sound-design.md +170 -170
  328. package/lib/motion/shotcraft/upstream/references/workbench.md +157 -157
  329. package/lib/motion/shotcraft/upstream/template/TEMPLATE.md +103 -103
  330. package/lib/motion/shotcraft/upstream/template/THEMES.md +44 -44
  331. package/lib/motion/shotcraft/upstream/template/package.json +20 -20
  332. package/lib/motion/shotcraft/upstream/template/remotion.config.ts +6 -6
  333. package/lib/motion/shotcraft/upstream/template/src/Root.tsx +17 -17
  334. package/lib/motion/shotcraft/upstream/template/src/aifl/Caption.tsx +65 -65
  335. package/lib/motion/shotcraft/upstream/template/src/aifl/DigitRoll.tsx +48 -48
  336. package/lib/motion/shotcraft/upstream/template/src/aifl/FlashCut.tsx +24 -24
  337. package/lib/motion/shotcraft/upstream/template/src/aifl/Main.tsx +192 -192
  338. package/lib/motion/shotcraft/upstream/template/src/aifl/PaperTitleCard.tsx +111 -111
  339. package/lib/motion/shotcraft/upstream/template/src/aifl/live/PageCam.tsx +150 -150
  340. package/lib/motion/shotcraft/upstream/template/src/aifl/live/SceneDetail.tsx +158 -158
  341. package/lib/motion/shotcraft/upstream/template/src/aifl/live/SceneFlyIn.tsx +468 -468
  342. package/lib/motion/shotcraft/upstream/template/src/aifl/live/SceneOpen.tsx +552 -552
  343. package/lib/motion/shotcraft/upstream/template/src/aifl/live/SceneOutroLive.tsx +411 -411
  344. package/lib/motion/shotcraft/upstream/template/src/aifl/live/ScenePapers.tsx +200 -200
  345. package/lib/motion/shotcraft/upstream/template/src/aifl/live/SceneWbr.tsx +324 -324
  346. package/lib/motion/shotcraft/upstream/template/src/aifl/live-layout.json +388 -388
  347. package/lib/motion/shotcraft/upstream/template/src/index.ts +4 -4
  348. package/lib/motion/shotcraft/upstream/template/src/themes/ThemedFilm.tsx +7 -7
  349. package/lib/motion/shotcraft/upstream/template/src/themes/manifest.tsx +68 -68
  350. package/lib/motion/shotcraft/upstream/template/src/themes/palette-assets.json +1 -1
  351. package/lib/motion/shotcraft/upstream/template/src/themes/palette-assets.ts +24 -24
  352. package/lib/motion/shotcraft/upstream/template/src/themes/palettes.json +74 -74
  353. package/lib/motion/shotcraft/upstream/template/src/themes/visual-theme.tsx +91 -91
  354. package/lib/motion/shotcraft/upstream/template/src/workbench.ts +213 -213
  355. package/lib/motion/shotcraft/upstream/template/tsconfig.json +15 -15
  356. package/lib/motion/style-frames.js +306 -306
  357. package/lib/motion/sync.js +214 -214
  358. package/lib/motion-project.js +105 -105
  359. package/lib/motion-render-worker.js +174 -174
  360. package/lib/routing/router.js +222 -222
  361. package/lib/routing/vendor/README.md +96 -96
  362. package/lib/routing/vendor/libavoid-routing.js +753 -753
  363. package/lib/routing/vendor/libavoid.min.js +59 -59
  364. package/lib/video-trace-pool.js +128 -128
  365. package/package.json +1 -1
  366. package/LICENSE +0 -4175
@@ -1,157 +1,157 @@
1
- """Offline behavior checks: python3 -m unittest discover -s assets/scripts -p 'test_sfx_source.py'."""
2
-
3
- import argparse
4
- from contextlib import redirect_stdout
5
- import importlib.util
6
- import io
7
- import json
8
- import math
9
- from pathlib import Path
10
- import shutil
11
- import struct
12
- import tempfile
13
- import unittest
14
- from unittest.mock import patch
15
- import wave
16
-
17
- spec = importlib.util.spec_from_file_location("sfx_source", Path(__file__).with_name("sfx-source.py"))
18
- sfx = importlib.util.module_from_spec(spec)
19
- spec.loader.exec_module(sfx)
20
-
21
-
22
- def player(sid="123", duration="0.5"):
23
- return (f'<div data-sound-id="{sid}" data-username="Recordist" data-title="Paper &amp; card" '
24
- f'data-duration="{duration}" data-num-downloads="42" '
25
- f'data-mp3="https://cdn.freesound.org/previews/0/{sid}_5-lq.mp3"></div>')
26
-
27
-
28
- def result(sid="123", duration="0.5", license="Creative Commons 0"):
29
- return (f'<div class="extra bw-search__result">{player(sid, duration)}'
30
- f'<a href="/people/Recordist/sounds/{sid}/">Paper</a>'
31
- f'<div title="License: {license}"></div>'
32
- '<div aria-label="Average rating of 4.5"></div><span class="bw-rating__count">(12)</span>'
33
- '<div class="max-h-60px-md-50px"><b>Dry</b> paper recorded in a room.</div></div>')
34
-
35
-
36
- class SourceTests(unittest.TestCase):
37
- def test_nested_search_metadata_and_optional_ratings(self):
38
- rows = sfx.parse_search(sfx.Document(result()))
39
- self.assertEqual(rows[0]["title"], "Paper & card")
40
- self.assertEqual(rows[0]["rating_count"], 12)
41
- self.assertEqual(rows[0]["duration_seconds"], 0.5)
42
- self.assertIn("Dry paper", rows[0]["description"])
43
- self.assertTrue(rows[0]["preview_url"].endswith("-hq.mp3"))
44
- self.assertEqual(sfx.stats([]), {"rating": None, "rating_count": None})
45
- detail = sfx.Document('<span class="bw-rating__count">Overall rating (21 ratings)</span>')
46
- self.assertEqual(sfx.stats(list(detail.root.nodes()))["rating_count"], 21)
47
-
48
- def test_empty_results_and_broken_page_are_distinct(self):
49
- self.assertEqual(sfx.parse_search(sfx.Document("<p>No results found</p>")), [])
50
- with self.assertRaises(ValueError):
51
- sfx.parse_search(sfx.Document("<p>Temporarily unavailable</p>"))
52
- with self.assertRaises(ValueError):
53
- sfx.parse_search(sfx.Document('<div class="bw-search__result">markup changed</div>'))
54
-
55
- def test_search_filters_locally_and_keeps_relevance(self):
56
- html = result("123") + result("124", "8") + result("125", license="Attribution NonCommercial") + result("126") + result("123")
57
- args = argparse.Namespace(query="paper", license="cc0", min_duration=0, max_duration=1, pages=1, limit=5, output=None)
58
- with patch.object(sfx, "web_page", return_value=(sfx.Document(html), sfx.SITE)), redirect_stdout(io.StringIO()) as output:
59
- self.assertEqual(sfx.search(args), 0)
60
- self.assertEqual([r["id"] for r in json.loads(output.getvalue())["results"]], ["fs:123", "fs:126"])
61
-
62
- def test_license_urls_versions_and_policy(self):
63
- self.assertEqual(sfx.license_code("http://creativecommons.org/licenses/by/3.0/"), "CC-BY-3.0")
64
- sfx.check_license("CC0-1.0", "cc0")
65
- sfx.check_license("CC-BY-4.0", "by")
66
- for url in ("https://creativecommons.org/licenses/by-nc/4.0/", "https://example.com/licenses/by/4.0/", "", "https://creativecommons.org/licenses/by-sa/4.0/"):
67
- self.assertIsNone(sfx.license_code(url))
68
- for code in (None, "CC-BY-4.0", "BY-NC"):
69
- with self.assertRaises(ValueError):
70
- sfx.check_license(code, "cc0")
71
-
72
- def test_detail_records_actual_license_url(self):
73
- url = "http://creativecommons.org/licenses/by/3.0/"
74
- doc = sfx.Document(player().replace('data-username="Recordist"', 'data-username=""') + f'<a href="{url}">Attribution</a>')
75
- with patch.object(sfx, "web_page", return_value=(doc, sfx.SITE + "/people/Recordist/sounds/123/")):
76
- row = sfx.detail("123")
77
- self.assertEqual(row["license"], "CC-BY-3.0")
78
- self.assertEqual(row["license_url"], url)
79
- self.assertEqual(row["author"], "Recordist")
80
-
81
- def test_unsafe_or_incomplete_metadata_rejected(self):
82
- for bad in ("../x", "fs:-2", "https://example.com/123"):
83
- with self.assertRaises(ValueError):
84
- sfx.sound_id(bad)
85
- for html in (player().replace("cdn.freesound.org", "evil.example"), player(duration="nan")):
86
- with self.assertRaises(ValueError):
87
- sfx.player_data(next(n for n in sfx.Document(html).root.nodes() if n.tag == "div"))
88
-
89
- def test_get_checks_license_before_fetching_audio(self):
90
- with tempfile.TemporaryDirectory() as directory, patch.object(sfx, "detail", return_value={"license": "CC-BY-3.0"}), patch.object(sfx, "request") as request:
91
- with self.assertRaises(ValueError):
92
- sfx.download_one("123", Path(directory), "cc0", [])
93
- request.assert_not_called()
94
-
95
- def test_download_freezes_provenance_and_rejects_modified_files(self):
96
- row = {"id": "fs:123", "license": "CC0-1.0", "preview_url": "https://cdn.freesound.org/previews/0/123_5-hq.mp3"}
97
- with tempfile.TemporaryDirectory() as directory, patch.object(sfx, "detail", return_value=dict(row)), patch.object(sfx, "analyze", return_value={"codec": "mp3"}), patch.object(sfx, "request", return_value=(b"audio", row["preview_url"], "audio/mpeg")):
98
- out = Path(directory)
99
- record = sfx.download_one("123", out, "cc0", [])
100
- self.assertTrue(record["is_preview"])
101
- self.assertEqual(record["sha256"], sfx.digest(out / record["file"]))
102
- (out / record["file"]).write_bytes(b"user edit")
103
- with self.assertRaises(ValueError):
104
- sfx.download_one("123", out, "cc0", [record])
105
- self.assertEqual((out / record["file"]).read_bytes(), b"user edit")
106
-
107
- def test_html_download_does_not_become_audio(self):
108
- row = {"id": "fs:123", "license": "CC0-1.0", "preview_url": "https://cdn.freesound.org/previews/0/123_5-hq.mp3"}
109
- with tempfile.TemporaryDirectory() as directory, patch.object(sfx, "detail", return_value=row), patch.object(sfx, "request", return_value=(b"<html>Error</html>", row["preview_url"], "text/html")):
110
- with self.assertRaises(ValueError):
111
- sfx.download_one("123", Path(directory), "cc0", [])
112
- self.assertFalse((Path(directory) / "fs-123.mp3").exists())
113
-
114
- def test_partial_failure_saves_success_and_returns_nonzero(self):
115
- record = {"id": "fs:123", "file": "fs-123.mp3", "title": "Paper", "author": "Recordist", "page_url": "https://freesound.org/s/123/", "license": "CC0-1.0", "license_url": "https://creativecommons.org/publicdomain/zero/1.0/"}
116
- def download(sid, *args):
117
- if sid == "124":
118
- raise ValueError("license unavailable")
119
- return record
120
- with tempfile.TemporaryDirectory() as directory, patch.object(sfx, "require_audio_tools"), patch.object(sfx, "download_one", side_effect=download), redirect_stdout(io.StringIO()):
121
- args = argparse.Namespace(ids=["123", "124", "123"], out_dir=directory, license="cc0", workers=1)
122
- self.assertEqual(sfx.get(args), 1)
123
- manifest = json.loads((Path(directory) / sfx.MANIFEST).read_text())
124
- self.assertEqual(manifest["assets"], [record])
125
- self.assertIn(record["license_url"], (Path(directory) / sfx.CREDITS).read_text())
126
- self.assertFalse((Path(directory) / ".freesound-download.lock").exists())
127
-
128
- def test_concurrent_manifest_writer_is_rejected(self):
129
- with tempfile.TemporaryDirectory() as directory, patch.object(sfx, "require_audio_tools"):
130
- lock = Path(directory) / ".freesound-download.lock"
131
- lock.touch()
132
- args = argparse.Namespace(ids=["123"], out_dir=directory)
133
- with self.assertRaises(ValueError):
134
- sfx.get(args)
135
- self.assertTrue(lock.exists())
136
-
137
- @unittest.skipUnless(shutil.which("ffmpeg") and shutil.which("ffprobe"), "requires ffmpeg/ffprobe")
138
- def test_measure_delayed_stereo_burst_without_downmix_cancellation(self):
139
- with tempfile.TemporaryDirectory() as directory:
140
- path = Path(directory) / "burst.wav"
141
- with wave.open(str(path), "wb") as audio:
142
- audio.setparams((2, 2, 48000, 0, "NONE", "not compressed"))
143
- values = []
144
- for i in range(48000):
145
- value = int(16384 * math.sin(2 * math.pi * 1000 * i / 48000)) if 12000 <= i < 16800 else 0
146
- values.append(struct.pack("<hh", value, -value))
147
- audio.writeframes(b"".join(values))
148
- result = sfx.analyze(path)
149
- self.assertAlmostEqual(result["duration_seconds"], 1)
150
- self.assertAlmostEqual(result["sample_peak_dbfs"], -6.021, places=2)
151
- self.assertTrue(0.25 <= result["energy_peak_seconds"] <= 0.35)
152
- self.assertAlmostEqual(result["active_start_seconds"], 0.25)
153
- self.assertAlmostEqual(result["active_end_seconds"], 0.35)
154
-
155
-
156
- if __name__ == "__main__":
157
- unittest.main()
1
+ """Offline behavior checks: python3 -m unittest discover -s assets/scripts -p 'test_sfx_source.py'."""
2
+
3
+ import argparse
4
+ from contextlib import redirect_stdout
5
+ import importlib.util
6
+ import io
7
+ import json
8
+ import math
9
+ from pathlib import Path
10
+ import shutil
11
+ import struct
12
+ import tempfile
13
+ import unittest
14
+ from unittest.mock import patch
15
+ import wave
16
+
17
+ spec = importlib.util.spec_from_file_location("sfx_source", Path(__file__).with_name("sfx-source.py"))
18
+ sfx = importlib.util.module_from_spec(spec)
19
+ spec.loader.exec_module(sfx)
20
+
21
+
22
+ def player(sid="123", duration="0.5"):
23
+ return (f'<div data-sound-id="{sid}" data-username="Recordist" data-title="Paper &amp; card" '
24
+ f'data-duration="{duration}" data-num-downloads="42" '
25
+ f'data-mp3="https://cdn.freesound.org/previews/0/{sid}_5-lq.mp3"></div>')
26
+
27
+
28
+ def result(sid="123", duration="0.5", license="Creative Commons 0"):
29
+ return (f'<div class="extra bw-search__result">{player(sid, duration)}'
30
+ f'<a href="/people/Recordist/sounds/{sid}/">Paper</a>'
31
+ f'<div title="License: {license}"></div>'
32
+ '<div aria-label="Average rating of 4.5"></div><span class="bw-rating__count">(12)</span>'
33
+ '<div class="max-h-60px-md-50px"><b>Dry</b> paper recorded in a room.</div></div>')
34
+
35
+
36
+ class SourceTests(unittest.TestCase):
37
+ def test_nested_search_metadata_and_optional_ratings(self):
38
+ rows = sfx.parse_search(sfx.Document(result()))
39
+ self.assertEqual(rows[0]["title"], "Paper & card")
40
+ self.assertEqual(rows[0]["rating_count"], 12)
41
+ self.assertEqual(rows[0]["duration_seconds"], 0.5)
42
+ self.assertIn("Dry paper", rows[0]["description"])
43
+ self.assertTrue(rows[0]["preview_url"].endswith("-hq.mp3"))
44
+ self.assertEqual(sfx.stats([]), {"rating": None, "rating_count": None})
45
+ detail = sfx.Document('<span class="bw-rating__count">Overall rating (21 ratings)</span>')
46
+ self.assertEqual(sfx.stats(list(detail.root.nodes()))["rating_count"], 21)
47
+
48
+ def test_empty_results_and_broken_page_are_distinct(self):
49
+ self.assertEqual(sfx.parse_search(sfx.Document("<p>No results found</p>")), [])
50
+ with self.assertRaises(ValueError):
51
+ sfx.parse_search(sfx.Document("<p>Temporarily unavailable</p>"))
52
+ with self.assertRaises(ValueError):
53
+ sfx.parse_search(sfx.Document('<div class="bw-search__result">markup changed</div>'))
54
+
55
+ def test_search_filters_locally_and_keeps_relevance(self):
56
+ html = result("123") + result("124", "8") + result("125", license="Attribution NonCommercial") + result("126") + result("123")
57
+ args = argparse.Namespace(query="paper", license="cc0", min_duration=0, max_duration=1, pages=1, limit=5, output=None)
58
+ with patch.object(sfx, "web_page", return_value=(sfx.Document(html), sfx.SITE)), redirect_stdout(io.StringIO()) as output:
59
+ self.assertEqual(sfx.search(args), 0)
60
+ self.assertEqual([r["id"] for r in json.loads(output.getvalue())["results"]], ["fs:123", "fs:126"])
61
+
62
+ def test_license_urls_versions_and_policy(self):
63
+ self.assertEqual(sfx.license_code("http://creativecommons.org/licenses/by/3.0/"), "CC-BY-3.0")
64
+ sfx.check_license("CC0-1.0", "cc0")
65
+ sfx.check_license("CC-BY-4.0", "by")
66
+ for url in ("https://creativecommons.org/licenses/by-nc/4.0/", "https://example.com/licenses/by/4.0/", "", "https://creativecommons.org/licenses/by-sa/4.0/"):
67
+ self.assertIsNone(sfx.license_code(url))
68
+ for code in (None, "CC-BY-4.0", "BY-NC"):
69
+ with self.assertRaises(ValueError):
70
+ sfx.check_license(code, "cc0")
71
+
72
+ def test_detail_records_actual_license_url(self):
73
+ url = "http://creativecommons.org/licenses/by/3.0/"
74
+ doc = sfx.Document(player().replace('data-username="Recordist"', 'data-username=""') + f'<a href="{url}">Attribution</a>')
75
+ with patch.object(sfx, "web_page", return_value=(doc, sfx.SITE + "/people/Recordist/sounds/123/")):
76
+ row = sfx.detail("123")
77
+ self.assertEqual(row["license"], "CC-BY-3.0")
78
+ self.assertEqual(row["license_url"], url)
79
+ self.assertEqual(row["author"], "Recordist")
80
+
81
+ def test_unsafe_or_incomplete_metadata_rejected(self):
82
+ for bad in ("../x", "fs:-2", "https://example.com/123"):
83
+ with self.assertRaises(ValueError):
84
+ sfx.sound_id(bad)
85
+ for html in (player().replace("cdn.freesound.org", "evil.example"), player(duration="nan")):
86
+ with self.assertRaises(ValueError):
87
+ sfx.player_data(next(n for n in sfx.Document(html).root.nodes() if n.tag == "div"))
88
+
89
+ def test_get_checks_license_before_fetching_audio(self):
90
+ with tempfile.TemporaryDirectory() as directory, patch.object(sfx, "detail", return_value={"license": "CC-BY-3.0"}), patch.object(sfx, "request") as request:
91
+ with self.assertRaises(ValueError):
92
+ sfx.download_one("123", Path(directory), "cc0", [])
93
+ request.assert_not_called()
94
+
95
+ def test_download_freezes_provenance_and_rejects_modified_files(self):
96
+ row = {"id": "fs:123", "license": "CC0-1.0", "preview_url": "https://cdn.freesound.org/previews/0/123_5-hq.mp3"}
97
+ with tempfile.TemporaryDirectory() as directory, patch.object(sfx, "detail", return_value=dict(row)), patch.object(sfx, "analyze", return_value={"codec": "mp3"}), patch.object(sfx, "request", return_value=(b"audio", row["preview_url"], "audio/mpeg")):
98
+ out = Path(directory)
99
+ record = sfx.download_one("123", out, "cc0", [])
100
+ self.assertTrue(record["is_preview"])
101
+ self.assertEqual(record["sha256"], sfx.digest(out / record["file"]))
102
+ (out / record["file"]).write_bytes(b"user edit")
103
+ with self.assertRaises(ValueError):
104
+ sfx.download_one("123", out, "cc0", [record])
105
+ self.assertEqual((out / record["file"]).read_bytes(), b"user edit")
106
+
107
+ def test_html_download_does_not_become_audio(self):
108
+ row = {"id": "fs:123", "license": "CC0-1.0", "preview_url": "https://cdn.freesound.org/previews/0/123_5-hq.mp3"}
109
+ with tempfile.TemporaryDirectory() as directory, patch.object(sfx, "detail", return_value=row), patch.object(sfx, "request", return_value=(b"<html>Error</html>", row["preview_url"], "text/html")):
110
+ with self.assertRaises(ValueError):
111
+ sfx.download_one("123", Path(directory), "cc0", [])
112
+ self.assertFalse((Path(directory) / "fs-123.mp3").exists())
113
+
114
+ def test_partial_failure_saves_success_and_returns_nonzero(self):
115
+ record = {"id": "fs:123", "file": "fs-123.mp3", "title": "Paper", "author": "Recordist", "page_url": "https://freesound.org/s/123/", "license": "CC0-1.0", "license_url": "https://creativecommons.org/publicdomain/zero/1.0/"}
116
+ def download(sid, *args):
117
+ if sid == "124":
118
+ raise ValueError("license unavailable")
119
+ return record
120
+ with tempfile.TemporaryDirectory() as directory, patch.object(sfx, "require_audio_tools"), patch.object(sfx, "download_one", side_effect=download), redirect_stdout(io.StringIO()):
121
+ args = argparse.Namespace(ids=["123", "124", "123"], out_dir=directory, license="cc0", workers=1)
122
+ self.assertEqual(sfx.get(args), 1)
123
+ manifest = json.loads((Path(directory) / sfx.MANIFEST).read_text())
124
+ self.assertEqual(manifest["assets"], [record])
125
+ self.assertIn(record["license_url"], (Path(directory) / sfx.CREDITS).read_text())
126
+ self.assertFalse((Path(directory) / ".freesound-download.lock").exists())
127
+
128
+ def test_concurrent_manifest_writer_is_rejected(self):
129
+ with tempfile.TemporaryDirectory() as directory, patch.object(sfx, "require_audio_tools"):
130
+ lock = Path(directory) / ".freesound-download.lock"
131
+ lock.touch()
132
+ args = argparse.Namespace(ids=["123"], out_dir=directory)
133
+ with self.assertRaises(ValueError):
134
+ sfx.get(args)
135
+ self.assertTrue(lock.exists())
136
+
137
+ @unittest.skipUnless(shutil.which("ffmpeg") and shutil.which("ffprobe"), "requires ffmpeg/ffprobe")
138
+ def test_measure_delayed_stereo_burst_without_downmix_cancellation(self):
139
+ with tempfile.TemporaryDirectory() as directory:
140
+ path = Path(directory) / "burst.wav"
141
+ with wave.open(str(path), "wb") as audio:
142
+ audio.setparams((2, 2, 48000, 0, "NONE", "not compressed"))
143
+ values = []
144
+ for i in range(48000):
145
+ value = int(16384 * math.sin(2 * math.pi * 1000 * i / 48000)) if 12000 <= i < 16800 else 0
146
+ values.append(struct.pack("<hh", value, -value))
147
+ audio.writeframes(b"".join(values))
148
+ result = sfx.analyze(path)
149
+ self.assertAlmostEqual(result["duration_seconds"], 1)
150
+ self.assertAlmostEqual(result["sample_peak_dbfs"], -6.021, places=2)
151
+ self.assertTrue(0.25 <= result["energy_peak_seconds"] <= 0.35)
152
+ self.assertAlmostEqual(result["active_start_seconds"], 0.25)
153
+ self.assertAlmostEqual(result["active_end_seconds"], 0.35)
154
+
155
+
156
+ if __name__ == "__main__":
157
+ unittest.main()
@@ -1,120 +1,120 @@
1
- # demos/ — 镜头卡参考实现源码
2
-
3
- 多数镜头卡会在“参考实现”中指向本目录;必须先读卡片,再按其明确路径定位准确的
4
- demo 文件,不能只凭卡名假设目录结构。这里的组件是调校过的 Remotion 实现——
5
- **用卡先读准确源码**(SKILL.md 理念 5)。
6
-
7
- `_legacy/` 仅为工作台旧工程保留已下架镜头,不属于当前镜头库,也不供新片选卡;
8
- 它不参与素材库、画廊与样片冒烟扫描,兼容说明见 [`_legacy/README.md`](_legacy/README.md)。
9
-
10
- 使用方式:copy 需要的 .tsx 进你的 Remotion 项目(30fps / 1920×1080),
11
- 注册成 Composition 即可跑。每个组件都 `export const <Stem>: React.FC` 并同时导出
12
- `<大写蛇形>_DURATION`(30fps 帧数),注册时直接用:
13
-
14
- ```tsx
15
- import { BlurSlide, BLUR_SLIDE_DURATION } from './blur-slide/BlurSlide';
16
- <Composition id="BlurSlide" component={BlurSlide}
17
- durationInFrames={BLUR_SLIDE_DURATION} fps={30} width={1920} height={1080} />
18
- ```
19
-
20
- 动画全部是帧的纯函数(无真随机 / 无 Date),逐帧确定性渲染。2026-10 全库做过两轮改版对照,
21
- 每个镜头由作者在原版 / 第一版(质感打磨)/ 第二版(成片级重设计)里择一落版,并去掉了 66 个镜头
22
- (决策记录 `shot-polish/decisions.json`)。随后做了品牌替换:画面里出现的 logo / 品牌名统一是
23
- video-shotcraft,合适的文案换成它的宣传语——拿去给自己的产品用时,把 `Brand.tsx` 的件换成你的标志与文案即可。
24
-
25
- 共享依赖(copy demo 时把用到的一并带上并改 import 路径):
26
-
27
- - `_fixtures/Brand.tsx` — video-shotcraft 品牌件:「镜刻」标志 `<ShotcraftMark>`(可分段描出)、字标
28
- `<ShotcraftWordmark>`、品牌色 `BRAND`、宣传文案库 `PITCH`(规范见 `assets/brand/BRAND.md`)。仅依赖 react。
29
- - `_fixtures/Look.tsx` — 第二轮的视觉系统:8 套调色板 `LOOKS`(暗场 midnight / aurora / ember / graphite / lime,
30
- 亮场 paper / porcelain / sand)、字号阶梯 `TYPE` 与 `type()`、带主光/余光/地平线光带/暗角/颗粒的
31
- 舞台 `<Stage>`、透视网格地面 `<GridFloor>`、确定性浮尘 `<Dust>`、单次扫光 `<Sheen>`、
32
- 逐字/词/行揭示 `<TextReveal>`、`stagger` / `springAt` / `glow`。第二版 demo 都 import 它;依赖 `./Polish`。
33
- - `_fixtures/Polish.tsx` — 质感工具件:贝塞尔缓动 `EASE` / `ramp` / `mix` / `velocity`、按速度的方向性模糊
34
- `SpeedBlur`、`softShadow` / `hairline` / `surface` 材质 helper、`Grain` / `Vignette` / `Backdrop`。仅依赖 remotion + react。
35
- - `_fixtures/Fixtures.tsx` — 假 UI 场景件(FakeDashboard / Card / TitleBlock / G 调色板),侧栏/顶栏是
36
- video-shotcraft 标志与名字(依赖 `./Brand`)。第一版 / 原版落版的 demo 里有二十来个在用。
37
- - `_fixtures/Motion.tsx` — 480×270 设计坐标的 `DesignStage` + E 缓动表 / seg / lerp / rand / useT。
38
- 原版 / 第一版落版的 Motion 系 demo 在用(fracture、bezier-source-converge-merge、radial-wave 等十几个)。
39
- - `_fixtures/PageCam2D.tsx` — 2.5D 页面相机(与 template 的 PageCam 同款坐标数学,self-contained)。
40
- spotlight-hero-card / type-and-filter / row-embed / list-stack-press / outro-group-photo-launch 在用。
41
- - `_textures/` — 真实页面截图与 `live-layout.json`。用到 `staticFile('textures/live/xxx.png')` 的 demo
42
- (crash-zoom-punch 两式 / depth-layer-moves / shot-transitions 急刹甩镜 / speed-ramp-freeze 定格标注 /
43
- spotlight-hero-card / type-and-filter / deck-deal-flyin / row-embed / list-stack-press /
44
- document-typewriter-reveal / page-waterfall-wall / outro-group-photo-launch)要求把 `_textures/` 下的同名文件
45
- 复制到你项目的 `public/textures/live/`。截图代表"产品既有页面"(审美准则 Q1);页头站名已改成
46
- video-shotcraft 标志 + 字标(周报页标题为 Shotcraft Weekly),其余页面内容未动。
47
-
48
- 个别 demo 用到 `@remotion/motion-blur`(CameraMotionBlur),需
49
- `npm i @remotion/motion-blur`。名单(4 个文件 / 4 张卡):
50
-
51
- - `camera/space-camera-moves/DroneDiveLanding.tsx`
52
- - `opening/crane-rise-reveal/CraneRiseReveal.tsx`
53
- - `opening/fracture/Fracture.tsx`
54
- - `opening/magician-card-flourish/MagicianCardFlourish.tsx`
55
-
56
- 其余快速运动一律用按速度量自算的方向模糊(`SpeedBlur` 或局部实现)——CameraMotionBlur 多重采样
57
- 代价高,且在近静止帧会把画面整体染灰/染黄。
58
-
59
- 字体:只用系统字体栈(SF / Helvetica Neue / Iowan Old Style / Avenir Next Condensed / Futura 等 macOS 自带字),
60
- 不依赖 `@remotion/google-fonts`。少数 demo 按本机 SF Pro 实测写死了字宽 / 字心坐标(如 letter-drop-physics、
61
- letterform-zoom、beat-step-list-theme-cycle、pill-chip-slot-cycle-handled),换字体或字号要按注释重测;
62
- 可变字重动画(font-weight-pump)依赖系统可变字体,没有时退化为阶梯字重。
63
-
64
- ## 真实视频素材(ClipCard,assets/lib/ClipCard.tsx)
65
-
66
- 库内 152 张镜头卡原本都假设主体是 DOM/SVG 生成物或页面截图,没有一张能
67
- 直接承载真实 mp4 素材。`assets/lib/ClipCard` 补上这个形态:把一段视频包进
68
- 圆角"卡片",让为矩形卡元素调校过的运镜骨架(spotlight-hero-card /
69
- magician-card-flourish / neon-frame-orbit-drop / quad-split-parallel-scenes)
70
- 原样驱动真实 footage。copy `assets/lib/ClipCard.tsx` 进项目即可用。
71
-
72
- ```tsx
73
- import { ClipCard } from './assets/lib/ClipCard';
74
-
75
- // 素材放 public/clips/demo.mp4;素材短于镜头时传 loopDurationInFrames 开启
76
- // 交叉淡化循环(OffthreadVideo 无 loop prop,播完会冻结)
77
- <ClipCard src="clips/demo.mp4" size={560} caption="AI generated"
78
- loopDurationInFrames={60} durationInFrames={120} />
79
- ```
80
-
81
- | 参数 | 默认 | 说明 |
82
- |------|------|------|
83
- | `src` | 必填 | public/ 下视频路径(staticFile 解析) |
84
- | `caption` / `captionSize` | 无 / 17 | 卡片下方 mono 副行;小卡片/远机位 captionSize 提到 ≥32px(Q11) |
85
- | `size` / `radius` | 560 / 20 | 卡片边长(方形素材)/ 圆角 |
86
- | `muted` | true | `false` 时循环交叉淡化音频互补,不叠双全量音轨 |
87
- | `startFrom` | 0 | 从视频第几帧开始播(修剪) |
88
- | `loopDurationInFrames` | 无 | 视频可播放长度(合成帧)→ 开启循环 |
89
- | `loopCrossfadeInFrames` | 8 | 循环层重叠淡化帧数 |
90
- | `durationInFrames` | Composition 时长 | 包围 shot 时长——**务必传**,否则短 shot 嵌长工程会生成不可见层 |
91
-
92
- 已知坑:
93
- - `durationInFrames` 不传时层数按 Composition 总时长算(短 shot 长工程问题)。
94
- - `startFrom` ≥ 可播放长度、或 step < crossfade 时自动回退单层播放(不循环)。
95
- - 循环素材建议 30fps、方形(运镜骨架按方形卡片标定)。
96
-
97
- 参考 demo:`demos/ui-entrance/clipcard-looping/ClipCardLooping.tsx`
98
- (回归三场景:muted=false 循环、startFrom>0+循环、短 Sequence 长 Composition)。
99
-
100
- ## 测试与验证
101
-
102
- 1. **类型编译**(`pr-checks.yml` verify job):`find demos -name '*.tsx'`
103
- 全部走 `tsc --noEmit --strict`。新增 demo 必须能通过严格编译。
104
- 2. **渲染冒烟**(`assets/scripts/smoke-render-demos.py`):扫描所有带时长
105
- 导出(`_DURATION` / `_DUR`)的 demo,自动生成 `template/src/smoke-root.tsx`
106
- 注册全部,逐个 `remotion still` 渲染首帧,断言输出非空、进程不崩——
107
- 堵住"能编译不能运行"的 demo(如 composition id 非法、运行时 import
108
- 缺失、纹理缺失)。本地跑全量:
109
-
110
- ```bash
111
- # 需要 template 依赖 + motion-blur(CI 里临时装)
112
- cd template && npm ci && npm i --no-save "@remotion/motion-blur@$(node -p "require('./package.json').dependencies.remotion")"
113
- cd .. && python3 assets/scripts/smoke-render-demos.py # 全量
114
- python3 assets/scripts/smoke-render-demos.py --subset BlurSlide,GlitchCycle # 子集
115
- python3 assets/scripts/smoke-render-demos.py --list # 列出可渲染 demo
116
- ```
117
-
118
- `--subset` 指向不存在/未找到的 demo 时脚本退出码为 1(明确报错)。
119
- 需要真实 mp4 素材的 demo(如 ClipCardLooping 用 `public/clips/`)会被跳过
120
- 并在输出里报告,不阻塞全量。
1
+ # demos/ — 镜头卡参考实现源码
2
+
3
+ 多数镜头卡会在“参考实现”中指向本目录;必须先读卡片,再按其明确路径定位准确的
4
+ demo 文件,不能只凭卡名假设目录结构。这里的组件是调校过的 Remotion 实现——
5
+ **用卡先读准确源码**(SKILL.md 理念 5)。
6
+
7
+ `_legacy/` 仅为工作台旧工程保留已下架镜头,不属于当前镜头库,也不供新片选卡;
8
+ 它不参与素材库、画廊与样片冒烟扫描,兼容说明见 [`_legacy/README.md`](_legacy/README.md)。
9
+
10
+ 使用方式:copy 需要的 .tsx 进你的 Remotion 项目(30fps / 1920×1080),
11
+ 注册成 Composition 即可跑。每个组件都 `export const <Stem>: React.FC` 并同时导出
12
+ `<大写蛇形>_DURATION`(30fps 帧数),注册时直接用:
13
+
14
+ ```tsx
15
+ import { BlurSlide, BLUR_SLIDE_DURATION } from './blur-slide/BlurSlide';
16
+ <Composition id="BlurSlide" component={BlurSlide}
17
+ durationInFrames={BLUR_SLIDE_DURATION} fps={30} width={1920} height={1080} />
18
+ ```
19
+
20
+ 动画全部是帧的纯函数(无真随机 / 无 Date),逐帧确定性渲染。2026-10 全库做过两轮改版对照,
21
+ 每个镜头由作者在原版 / 第一版(质感打磨)/ 第二版(成片级重设计)里择一落版,并去掉了 66 个镜头
22
+ (决策记录 `shot-polish/decisions.json`)。随后做了品牌替换:画面里出现的 logo / 品牌名统一是
23
+ video-shotcraft,合适的文案换成它的宣传语——拿去给自己的产品用时,把 `Brand.tsx` 的件换成你的标志与文案即可。
24
+
25
+ 共享依赖(copy demo 时把用到的一并带上并改 import 路径):
26
+
27
+ - `_fixtures/Brand.tsx` — video-shotcraft 品牌件:「镜刻」标志 `<ShotcraftMark>`(可分段描出)、字标
28
+ `<ShotcraftWordmark>`、品牌色 `BRAND`、宣传文案库 `PITCH`(规范见 `assets/brand/BRAND.md`)。仅依赖 react。
29
+ - `_fixtures/Look.tsx` — 第二轮的视觉系统:8 套调色板 `LOOKS`(暗场 midnight / aurora / ember / graphite / lime,
30
+ 亮场 paper / porcelain / sand)、字号阶梯 `TYPE` 与 `type()`、带主光/余光/地平线光带/暗角/颗粒的
31
+ 舞台 `<Stage>`、透视网格地面 `<GridFloor>`、确定性浮尘 `<Dust>`、单次扫光 `<Sheen>`、
32
+ 逐字/词/行揭示 `<TextReveal>`、`stagger` / `springAt` / `glow`。第二版 demo 都 import 它;依赖 `./Polish`。
33
+ - `_fixtures/Polish.tsx` — 质感工具件:贝塞尔缓动 `EASE` / `ramp` / `mix` / `velocity`、按速度的方向性模糊
34
+ `SpeedBlur`、`softShadow` / `hairline` / `surface` 材质 helper、`Grain` / `Vignette` / `Backdrop`。仅依赖 remotion + react。
35
+ - `_fixtures/Fixtures.tsx` — 假 UI 场景件(FakeDashboard / Card / TitleBlock / G 调色板),侧栏/顶栏是
36
+ video-shotcraft 标志与名字(依赖 `./Brand`)。第一版 / 原版落版的 demo 里有二十来个在用。
37
+ - `_fixtures/Motion.tsx` — 480×270 设计坐标的 `DesignStage` + E 缓动表 / seg / lerp / rand / useT。
38
+ 原版 / 第一版落版的 Motion 系 demo 在用(fracture、bezier-source-converge-merge、radial-wave 等十几个)。
39
+ - `_fixtures/PageCam2D.tsx` — 2.5D 页面相机(与 template 的 PageCam 同款坐标数学,self-contained)。
40
+ spotlight-hero-card / type-and-filter / row-embed / list-stack-press / outro-group-photo-launch 在用。
41
+ - `_textures/` — 真实页面截图与 `live-layout.json`。用到 `staticFile('textures/live/xxx.png')` 的 demo
42
+ (crash-zoom-punch 两式 / depth-layer-moves / shot-transitions 急刹甩镜 / speed-ramp-freeze 定格标注 /
43
+ spotlight-hero-card / type-and-filter / deck-deal-flyin / row-embed / list-stack-press /
44
+ document-typewriter-reveal / page-waterfall-wall / outro-group-photo-launch)要求把 `_textures/` 下的同名文件
45
+ 复制到你项目的 `public/textures/live/`。截图代表"产品既有页面"(审美准则 Q1);页头站名已改成
46
+ video-shotcraft 标志 + 字标(周报页标题为 Shotcraft Weekly),其余页面内容未动。
47
+
48
+ 个别 demo 用到 `@remotion/motion-blur`(CameraMotionBlur),需
49
+ `npm i @remotion/motion-blur`。名单(4 个文件 / 4 张卡):
50
+
51
+ - `camera/space-camera-moves/DroneDiveLanding.tsx`
52
+ - `opening/crane-rise-reveal/CraneRiseReveal.tsx`
53
+ - `opening/fracture/Fracture.tsx`
54
+ - `opening/magician-card-flourish/MagicianCardFlourish.tsx`
55
+
56
+ 其余快速运动一律用按速度量自算的方向模糊(`SpeedBlur` 或局部实现)——CameraMotionBlur 多重采样
57
+ 代价高,且在近静止帧会把画面整体染灰/染黄。
58
+
59
+ 字体:只用系统字体栈(SF / Helvetica Neue / Iowan Old Style / Avenir Next Condensed / Futura 等 macOS 自带字),
60
+ 不依赖 `@remotion/google-fonts`。少数 demo 按本机 SF Pro 实测写死了字宽 / 字心坐标(如 letter-drop-physics、
61
+ letterform-zoom、beat-step-list-theme-cycle、pill-chip-slot-cycle-handled),换字体或字号要按注释重测;
62
+ 可变字重动画(font-weight-pump)依赖系统可变字体,没有时退化为阶梯字重。
63
+
64
+ ## 真实视频素材(ClipCard,assets/lib/ClipCard.tsx)
65
+
66
+ 库内 152 张镜头卡原本都假设主体是 DOM/SVG 生成物或页面截图,没有一张能
67
+ 直接承载真实 mp4 素材。`assets/lib/ClipCard` 补上这个形态:把一段视频包进
68
+ 圆角"卡片",让为矩形卡元素调校过的运镜骨架(spotlight-hero-card /
69
+ magician-card-flourish / neon-frame-orbit-drop / quad-split-parallel-scenes)
70
+ 原样驱动真实 footage。copy `assets/lib/ClipCard.tsx` 进项目即可用。
71
+
72
+ ```tsx
73
+ import { ClipCard } from './assets/lib/ClipCard';
74
+
75
+ // 素材放 public/clips/demo.mp4;素材短于镜头时传 loopDurationInFrames 开启
76
+ // 交叉淡化循环(OffthreadVideo 无 loop prop,播完会冻结)
77
+ <ClipCard src="clips/demo.mp4" size={560} caption="AI generated"
78
+ loopDurationInFrames={60} durationInFrames={120} />
79
+ ```
80
+
81
+ | 参数 | 默认 | 说明 |
82
+ |------|------|------|
83
+ | `src` | 必填 | public/ 下视频路径(staticFile 解析) |
84
+ | `caption` / `captionSize` | 无 / 17 | 卡片下方 mono 副行;小卡片/远机位 captionSize 提到 ≥32px(Q11) |
85
+ | `size` / `radius` | 560 / 20 | 卡片边长(方形素材)/ 圆角 |
86
+ | `muted` | true | `false` 时循环交叉淡化音频互补,不叠双全量音轨 |
87
+ | `startFrom` | 0 | 从视频第几帧开始播(修剪) |
88
+ | `loopDurationInFrames` | 无 | 视频可播放长度(合成帧)→ 开启循环 |
89
+ | `loopCrossfadeInFrames` | 8 | 循环层重叠淡化帧数 |
90
+ | `durationInFrames` | Composition 时长 | 包围 shot 时长——**务必传**,否则短 shot 嵌长工程会生成不可见层 |
91
+
92
+ 已知坑:
93
+ - `durationInFrames` 不传时层数按 Composition 总时长算(短 shot 长工程问题)。
94
+ - `startFrom` ≥ 可播放长度、或 step < crossfade 时自动回退单层播放(不循环)。
95
+ - 循环素材建议 30fps、方形(运镜骨架按方形卡片标定)。
96
+
97
+ 参考 demo:`demos/ui-entrance/clipcard-looping/ClipCardLooping.tsx`
98
+ (回归三场景:muted=false 循环、startFrom>0+循环、短 Sequence 长 Composition)。
99
+
100
+ ## 测试与验证
101
+
102
+ 1. **类型编译**(`pr-checks.yml` verify job):`find demos -name '*.tsx'`
103
+ 全部走 `tsc --noEmit --strict`。新增 demo 必须能通过严格编译。
104
+ 2. **渲染冒烟**(`assets/scripts/smoke-render-demos.py`):扫描所有带时长
105
+ 导出(`_DURATION` / `_DUR`)的 demo,自动生成 `template/src/smoke-root.tsx`
106
+ 注册全部,逐个 `remotion still` 渲染首帧,断言输出非空、进程不崩——
107
+ 堵住"能编译不能运行"的 demo(如 composition id 非法、运行时 import
108
+ 缺失、纹理缺失)。本地跑全量:
109
+
110
+ ```bash
111
+ # 需要 template 依赖 + motion-blur(CI 里临时装)
112
+ cd template && npm ci && npm i --no-save "@remotion/motion-blur@$(node -p "require('./package.json').dependencies.remotion")"
113
+ cd .. && python3 assets/scripts/smoke-render-demos.py # 全量
114
+ python3 assets/scripts/smoke-render-demos.py --subset BlurSlide,GlitchCycle # 子集
115
+ python3 assets/scripts/smoke-render-demos.py --list # 列出可渲染 demo
116
+ ```
117
+
118
+ `--subset` 指向不存在/未找到的 demo 时脚本退出码为 1(明确报错)。
119
+ 需要真实 mp4 素材的 demo(如 ClipCardLooping 用 `public/clips/`)会被跳过
120
+ 并在输出里报告,不阻塞全量。