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,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
+ 并在输出里报告,不阻塞全量。