dsh-drawai 0.4.2 → 0.4.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -5
- package/lib/client.js +142 -16
- package/lib/index.js +7945 -7719
- package/lib/motion/asset-pack.js +394 -394
- package/lib/motion/assets.js +291 -291
- package/lib/motion/demo-assets-lock.js +10 -10
- package/lib/motion/mgstyles/briefs/23-ink-wash.md +147 -0
- package/lib/motion/mgstyles/catalog.d/23-ink-wash.json +28 -0
- package/lib/motion/mgstyles/catalog.json +127 -14
- package/lib/motion/mgstyles/upstream/demos/23-ink-wash/brush.js +149 -0
- package/lib/motion/mgstyles/upstream/demos/23-ink-wash/film.js +202 -0
- package/lib/motion/mgstyles/upstream/manifest.json +28 -3
- package/lib/motion/mgstyles/upstream/prompts/23-ink-wash.md +59 -0
- package/lib/motion/mgstyles/vendor/README.md +28 -28
- package/lib/motion/mgstyles/vendor/modules/d3/LICENSE +13 -13
- package/lib/motion/mgstyles/vendor/modules/d3/dist/d3.min.js +2 -2
- package/lib/motion/mgstyles/vendor/modules/opentype.js/LICENSE +20 -20
- package/lib/motion/mgstyles/vendor/modules/opentype.js/dist/opentype.mjs +14460 -14460
- package/lib/motion/mgstyles/vendor/modules/simplex-noise/LICENSE +21 -21
- package/lib/motion/mgstyles/vendor/modules/simplex-noise/dist/esm/simplex-noise.js +465 -465
- package/lib/motion/mgstyles/vendor/modules/topojson-client/LICENSE +13 -13
- package/lib/motion/mgstyles/vendor/modules/topojson-client/dist/topojson-client.min.js +2 -2
- package/lib/motion/project.js +5 -1
- package/lib/motion/qa.js +116 -6
- package/lib/motion/render.js +179 -179
- package/lib/motion/scene-kit.js +1 -1
- package/lib/motion/shotcraft/upstream/SKILL.md +286 -286
- package/lib/motion/shotcraft/upstream/assets/lib/Caption.tsx +54 -54
- package/lib/motion/shotcraft/upstream/assets/lib/ClipCard.tsx +200 -200
- package/lib/motion/shotcraft/upstream/assets/lib/DigitRoll.tsx +45 -45
- package/lib/motion/shotcraft/upstream/assets/lib/FlashCut.tsx +20 -20
- package/lib/motion/shotcraft/upstream/assets/lib/FlatPanel.tsx +65 -65
- package/lib/motion/shotcraft/upstream/assets/lib/PageCam.tsx +151 -151
- package/lib/motion/shotcraft/upstream/assets/lib/VerticalTicker.tsx +129 -129
- package/lib/motion/shotcraft/upstream/assets/lib/helpers/camera.tsx +75 -75
- package/lib/motion/shotcraft/upstream/assets/lib/helpers/motion.ts +40 -40
- package/lib/motion/shotcraft/upstream/assets/lib/helpers/rand.ts +11 -11
- package/lib/motion/shotcraft/upstream/assets/lib/helpers/shake.ts +10 -10
- package/lib/motion/shotcraft/upstream/assets/scripts/build-readme-cover.mjs +49 -49
- package/lib/motion/shotcraft/upstream/assets/scripts/capture-template.mjs +210 -210
- package/lib/motion/shotcraft/upstream/assets/scripts/sfx-source.py +423 -423
- package/lib/motion/shotcraft/upstream/assets/scripts/smoke-render-demos.py +170 -170
- package/lib/motion/shotcraft/upstream/assets/scripts/test_sfx_source.py +157 -157
- package/lib/motion/shotcraft/upstream/demos/README.md +120 -120
- package/lib/motion/shotcraft/upstream/demos/_fixtures/Brand.tsx +112 -112
- package/lib/motion/shotcraft/upstream/demos/_fixtures/Fixtures.tsx +647 -647
- package/lib/motion/shotcraft/upstream/demos/_fixtures/Look.tsx +316 -316
- package/lib/motion/shotcraft/upstream/demos/_fixtures/Motion.tsx +82 -82
- package/lib/motion/shotcraft/upstream/demos/_fixtures/PageCam2D.tsx +115 -115
- package/lib/motion/shotcraft/upstream/demos/_fixtures/Polish.tsx +243 -243
- package/lib/motion/shotcraft/upstream/demos/_textures/live-layout.json +388 -388
- package/lib/motion/shotcraft/upstream/demos/camera/basic-3d-scene/Basic3DScene.tsx +250 -250
- package/lib/motion/shotcraft/upstream/demos/camera/crash-zoom-punch/CrashImpactReal.tsx +305 -305
- package/lib/motion/shotcraft/upstream/demos/camera/crash-zoom-punch/CrashZoomReal.tsx +246 -246
- package/lib/motion/shotcraft/upstream/demos/camera/cursor-flyover/CursorFlyover.tsx +390 -390
- package/lib/motion/shotcraft/upstream/demos/camera/depth-layer-moves/MultiplaneReal.tsx +138 -138
- package/lib/motion/shotcraft/upstream/demos/camera/graze-face-tour/GrazeFaceTour.tsx +542 -542
- package/lib/motion/shotcraft/upstream/demos/camera/overhead-camera-moves/OverheadTabletopDrop.tsx +315 -315
- package/lib/motion/shotcraft/upstream/demos/camera/overhead-camera-moves/TiltReveal.tsx +299 -299
- package/lib/motion/shotcraft/upstream/demos/camera/space-camera-moves/DroneDiveLanding.tsx +173 -173
- package/lib/motion/shotcraft/upstream/demos/camera/space-camera-moves/ExplodedView.tsx +348 -348
- package/lib/motion/shotcraft/upstream/demos/camera/steep-tilt-glide/SteepTiltGlide.tsx +366 -366
- package/lib/motion/shotcraft/upstream/demos/camera/tension-camera-moves/BulletTimeFreezeOrbit.tsx +279 -279
- package/lib/motion/shotcraft/upstream/demos/camera/tension-camera-moves/PullBackIsolation.tsx +184 -184
- package/lib/motion/shotcraft/upstream/demos/camera/terminal-3d/Terminal3D.tsx +390 -390
- package/lib/motion/shotcraft/upstream/demos/data/before-after-slider-scrub/BeforeAfterSliderScrub.tsx +155 -155
- package/lib/motion/shotcraft/upstream/demos/data/chart-live-moves/AxisRescaleShockV2.tsx +303 -303
- package/lib/motion/shotcraft/upstream/demos/data/chart-live-moves/OscilloscopeStreamV2.tsx +290 -290
- package/lib/motion/shotcraft/upstream/demos/data/chart-live-moves/UnitDotSwarmRegroupV2.tsx +278 -278
- package/lib/motion/shotcraft/upstream/demos/data/gauge-readout-moves/NeedleSweepSelftest.tsx +307 -307
- package/lib/motion/shotcraft/upstream/demos/data/gauge-readout-moves/TapeScrollFixedPointer.tsx +215 -215
- package/lib/motion/shotcraft/upstream/demos/data/scroll-brake-moves/BrakeReticleLock.tsx +299 -299
- package/lib/motion/shotcraft/upstream/demos/data/scroll-brake-moves/ChangelogScrollBrake.tsx +232 -232
- package/lib/motion/shotcraft/upstream/demos/data/timeline-travel/TimelineTravel.tsx +290 -290
- package/lib/motion/shotcraft/upstream/demos/effects/assemble-then-type-flyin/AssembleThenTypeFlyin.tsx +273 -273
- package/lib/motion/shotcraft/upstream/demos/effects/aurora-bloom-bg-flip/AuroraBloomBgFlip.tsx +167 -167
- package/lib/motion/shotcraft/upstream/demos/effects/brand-frame-snap/BrandFrameSnap.tsx +536 -536
- package/lib/motion/shotcraft/upstream/demos/effects/fui-hud-moves/ReticleLockOn.tsx +164 -164
- package/lib/motion/shotcraft/upstream/demos/effects/glow-flyline-moves/FlylineArc.tsx +175 -175
- package/lib/motion/shotcraft/upstream/demos/effects/glow-flyline-moves/GlowOrbAmbient.tsx +197 -197
- package/lib/motion/shotcraft/upstream/demos/effects/glow-flyline-moves/OrbFlylineRelay.tsx +241 -241
- package/lib/motion/shotcraft/upstream/demos/effects/icon-performance-moves/AttentionBounce.tsx +279 -279
- package/lib/motion/shotcraft/upstream/demos/effects/impact-feedback/AnimeImpact.tsx +230 -230
- package/lib/motion/shotcraft/upstream/demos/effects/impact-feedback/HitCounter.tsx +345 -345
- package/lib/motion/shotcraft/upstream/demos/effects/light-play-moves/SheenSweepRetry.tsx +275 -275
- package/lib/motion/shotcraft/upstream/demos/effects/light-play-moves/SpotlightSweepReveal.tsx +229 -229
- package/lib/motion/shotcraft/upstream/demos/effects/radial-ripple-phone-chips/RadialRipplePhoneChips.tsx +312 -312
- package/lib/motion/shotcraft/upstream/demos/effects/riso-print-hits/RisoMisregistrationHit.tsx +222 -222
- package/lib/motion/shotcraft/upstream/demos/effects/scan-bracket-sweep/ScanBracketSweep.tsx +295 -295
- package/lib/motion/shotcraft/upstream/demos/effects/scanline-annotate-focus/ScanlineAnnotateFocus.tsx +329 -329
- package/lib/motion/shotcraft/upstream/demos/effects/scanline-assemble-flyin/ScanlineAssembleFlyin.tsx +315 -315
- package/lib/motion/shotcraft/upstream/demos/effects/slam-entrance-moves/ImpactBurstKit.tsx +264 -264
- package/lib/motion/shotcraft/upstream/demos/effects/slam-entrance-moves/KanadaPerspectiveSnap.tsx +260 -260
- package/lib/motion/shotcraft/upstream/demos/effects/slam-entrance-moves/ScoreSlam.tsx +263 -263
- package/lib/motion/shotcraft/upstream/demos/effects/spotlight-sweep-moves/CornerSpotlightReveal.tsx +123 -123
- package/lib/motion/shotcraft/upstream/demos/effects/spotlight-sweep-moves/GlowWakeSleepPanel.tsx +187 -187
- package/lib/motion/shotcraft/upstream/demos/effects/spotlight-sweep-moves/SlideSpotlightPan.tsx +175 -175
- package/lib/motion/shotcraft/upstream/demos/interaction/autolayout-gap-dial/AutolayoutGapDial.tsx +305 -305
- package/lib/motion/shotcraft/upstream/demos/interaction/canvas-materialize-moves/DiagramCascadeBuild.tsx +350 -350
- package/lib/motion/shotcraft/upstream/demos/interaction/canvas-materialize-moves/PanelToCanvasMaterialize.tsx +352 -352
- package/lib/motion/shotcraft/upstream/demos/interaction/chip-grid-single-select-blackout/ChipGridSingleSelectBlackout.tsx +218 -218
- package/lib/motion/shotcraft/upstream/demos/interaction/collab-cursor-moves/CursorCastEnsemble.tsx +297 -297
- package/lib/motion/shotcraft/upstream/demos/interaction/glass-pill-dictation-typing/GlassPillDictationTyping.tsx +157 -157
- package/lib/motion/shotcraft/upstream/demos/interaction/hashtag-to-pill-materialize/HashtagToPillMaterialize.tsx +218 -218
- package/lib/motion/shotcraft/upstream/demos/interaction/picker-carousel-feature-cycle/PickerCarouselFeatureCycle.tsx +202 -202
- package/lib/motion/shotcraft/upstream/demos/interaction/segmented-thumb-hero/SegmentedThumbHero.tsx +265 -265
- package/lib/motion/shotcraft/upstream/demos/interaction/theme-switch-moves/PaletteThemeRipple.tsx +457 -457
- package/lib/motion/shotcraft/upstream/demos/interaction/theme-switch-moves/ThemeSweepToggle.tsx +446 -446
- package/lib/motion/shotcraft/upstream/demos/interaction/type-and-filter/TypeAndFilter.tsx +249 -249
- package/lib/motion/shotcraft/upstream/demos/interaction/voice-waveform-live/VoiceWaveformLive.tsx +278 -278
- package/lib/motion/shotcraft/upstream/demos/opening/crane-rise-reveal/CraneRiseReveal.tsx +332 -332
- package/lib/motion/shotcraft/upstream/demos/opening/dataviz-landscape-open/DatavizLandscapeOpen.tsx +358 -358
- package/lib/motion/shotcraft/upstream/demos/opening/fracture/Fracture.tsx +201 -201
- package/lib/motion/shotcraft/upstream/demos/opening/icon-field-colorize/IconFieldColorize.tsx +200 -200
- package/lib/motion/shotcraft/upstream/demos/opening/letterspace-materialize/LetterspaceMaterialize.tsx +208 -208
- package/lib/motion/shotcraft/upstream/demos/opening/magician-card-flourish/MagicianCardFlourish.tsx +341 -341
- package/lib/motion/shotcraft/upstream/demos/opening/orbit-ring-title-open/OrbitRingTitleOpen.tsx +389 -389
- package/lib/motion/shotcraft/upstream/demos/opening/spotlight-hero-card/SpotlightHeroCard.tsx +293 -293
- package/lib/motion/shotcraft/upstream/demos/opening/stroke-segment-build/StrokeSegmentBuild.tsx +183 -183
- package/lib/motion/shotcraft/upstream/demos/opening/text-as-mask/TextAsMask.tsx +245 -245
- package/lib/motion/shotcraft/upstream/demos/outro/grain-dissolve/GrainDissolve.tsx +222 -222
- package/lib/motion/shotcraft/upstream/demos/outro/logo-shrink-wordmark-lockup/LogoShrinkWordmarkLockup.tsx +223 -223
- package/lib/motion/shotcraft/upstream/demos/outro/neon-triple-marquee/NeonTripleMarquee.tsx +217 -217
- package/lib/motion/shotcraft/upstream/demos/outro/outro-group-photo-launch/OutroGroupPhotoLaunch.tsx +343 -343
- package/lib/motion/shotcraft/upstream/demos/outro/ui-strip-away-outro/UiStripAwayOutro.tsx +357 -357
- package/lib/motion/shotcraft/upstream/demos/outro/ui-to-brand-morph/IconFlipBloomLogo.tsx +187 -187
- package/lib/motion/shotcraft/upstream/demos/outro/ui-to-brand-morph/InputMorphsIntoLogo.tsx +333 -333
- package/lib/motion/shotcraft/upstream/demos/rhythm/beat-cut-moves/PaparazziFlash.tsx +274 -274
- package/lib/motion/shotcraft/upstream/demos/rhythm/beat-step-list-theme-cycle/BeatStepListThemeCycle.tsx +270 -270
- package/lib/motion/shotcraft/upstream/demos/rhythm/panel-grid-moves/ComicPanelSplit.tsx +430 -430
- package/lib/motion/shotcraft/upstream/demos/rhythm/quad-split-parallel-scenes/QuadSplitParallelScenes.tsx +252 -252
- package/lib/motion/shotcraft/upstream/demos/rhythm/rhythm-interrupt-moves/JumpCutPunchIn.tsx +106 -106
- package/lib/motion/shotcraft/upstream/demos/rhythm/sakuga-timing-shift/SakugaTimingShift.tsx +288 -288
- package/lib/motion/shotcraft/upstream/demos/rhythm/speed-ramp-freeze/FreezeAnnotateReal.tsx +362 -362
- package/lib/motion/shotcraft/upstream/demos/rhythm/trailer-grammar-moves/TrailerBumper.tsx +168 -168
- package/lib/motion/shotcraft/upstream/demos/transition/bottom-push-stack-wipe/BottomPushStackWipe.tsx +310 -310
- package/lib/motion/shotcraft/upstream/demos/transition/card-flip-reveal/CardFlipReveal.tsx +261 -261
- package/lib/motion/shotcraft/upstream/demos/transition/card-flock-tumble/CardFlockTumble.tsx +459 -459
- package/lib/motion/shotcraft/upstream/demos/transition/circle-match-iris/CircleMatchIris.tsx +294 -294
- package/lib/motion/shotcraft/upstream/demos/transition/gradient-transition/GradientTransition.tsx +161 -161
- package/lib/motion/shotcraft/upstream/demos/transition/line-carry-transition/LineCarryTransition.tsx +248 -248
- package/lib/motion/shotcraft/upstream/demos/transition/mosaic-reframe/MosaicReframe.tsx +359 -359
- package/lib/motion/shotcraft/upstream/demos/transition/page-turn-transitions/BarnDoorSplit.tsx +227 -227
- package/lib/motion/shotcraft/upstream/demos/transition/print-texture-transitions/InkBleedReveal.tsx +162 -162
- package/lib/motion/shotcraft/upstream/demos/transition/shot-transitions/PortalWipeV2.tsx +248 -248
- package/lib/motion/shotcraft/upstream/demos/transition/shot-transitions/WhipBrakeReal.tsx +186 -186
- package/lib/motion/shotcraft/upstream/demos/transition/tear-streak-transitions/GlitchDisplace.tsx +355 -355
- package/lib/motion/shotcraft/upstream/demos/transition/transition-hidden-cut/InvisibleCut.tsx +272 -272
- package/lib/motion/shotcraft/upstream/demos/transition/transition-hidden-cut/LightLeakBurn.tsx +262 -262
- package/lib/motion/shotcraft/upstream/demos/transition/transition-hidden-cut/VersusSlam.tsx +217 -217
- package/lib/motion/shotcraft/upstream/demos/transition/transition-travel/LetterformZoom.tsx +285 -285
- package/lib/motion/shotcraft/upstream/demos/transition/white-flash-logo-simplify-cut/WhiteFlashLogoSimplifyCut.tsx +205 -205
- package/lib/motion/shotcraft/upstream/demos/transition/wipe-transitions/BlindsSlice.tsx +178 -178
- package/lib/motion/shotcraft/upstream/demos/typography/blur-slide/BlurSlide.tsx +147 -147
- package/lib/motion/shotcraft/upstream/demos/typography/brace-expand/BraceExpand.tsx +143 -143
- package/lib/motion/shotcraft/upstream/demos/typography/brand-ink-open/BrandInkOpen.tsx +134 -134
- package/lib/motion/shotcraft/upstream/demos/typography/countdown-arc-scatter/CountdownArcScatter.tsx +217 -217
- package/lib/motion/shotcraft/upstream/demos/typography/flying-words/FlyingWords.tsx +198 -198
- package/lib/motion/shotcraft/upstream/demos/typography/glitch-cycle/GlitchCycle.tsx +221 -221
- package/lib/motion/shotcraft/upstream/demos/typography/gradient-word-sweep/GradientWordSweep.tsx +312 -312
- package/lib/motion/shotcraft/upstream/demos/typography/lead-word-zoom-assemble/LeadWordZoomAssemble.tsx +261 -261
- package/lib/motion/shotcraft/upstream/demos/typography/marker-underline-title/MarkerUnderlineTitle.tsx +121 -121
- package/lib/motion/shotcraft/upstream/demos/typography/outline-word-fill/OutlineWordFill.tsx +153 -153
- package/lib/motion/shotcraft/upstream/demos/typography/paper-title-card/PaperTitleCard.tsx +179 -179
- package/lib/motion/shotcraft/upstream/demos/typography/pill-chip-slot-cycle-handled/PillChipSlotCycleHandled.tsx +140 -140
- package/lib/motion/shotcraft/upstream/demos/typography/pill-slot-cycle/PillSlotCycle.tsx +309 -309
- package/lib/motion/shotcraft/upstream/demos/typography/text-column-converge/TextColumnConverge.tsx +191 -191
- package/lib/motion/shotcraft/upstream/demos/typography/title-demote-to-label/TitleDemoteToLabel.tsx +292 -292
- package/lib/motion/shotcraft/upstream/demos/typography/type-assembly-moves/LetterformDriftAssembly.tsx +135 -135
- package/lib/motion/shotcraft/upstream/demos/typography/type-assembly-moves/SplitTextStagger.tsx +124 -124
- package/lib/motion/shotcraft/upstream/demos/typography/type-assembly-moves/TextOnPath.tsx +255 -255
- package/lib/motion/shotcraft/upstream/demos/typography/type-entrance-moves/LetterDropPhysics.tsx +173 -173
- package/lib/motion/shotcraft/upstream/demos/typography/type-rhythm-sync/FontWeightPump.tsx +225 -225
- package/lib/motion/shotcraft/upstream/demos/typography/type-rhythm-sync/KaraokeFillSync.tsx +141 -141
- package/lib/motion/shotcraft/upstream/demos/typography/typewriter-moves/TypewriterErrorRetype.tsx +137 -137
- package/lib/motion/shotcraft/upstream/demos/typography/vertical-word-roll-blur-cycle/VerticalWordRollBlurCycle.tsx +147 -147
- package/lib/motion/shotcraft/upstream/demos/typography/word-relay-filmstrip/WordRelayFilmstrip.tsx +409 -409
- package/lib/motion/shotcraft/upstream/demos/typography/word-relay-geometry/WordRelayGeometry.tsx +280 -280
- package/lib/motion/shotcraft/upstream/demos/ui-entrance/avatar-bracket-carousel/AvatarBracketCarousel.tsx +271 -271
- package/lib/motion/shotcraft/upstream/demos/ui-entrance/bezier-source-converge-merge/BezierSourceConvergeMerge.tsx +385 -385
- package/lib/motion/shotcraft/upstream/demos/ui-entrance/card-stack/CardStack.tsx +312 -312
- package/lib/motion/shotcraft/upstream/demos/ui-entrance/carousel-3d/Carousel3D.tsx +303 -303
- package/lib/motion/shotcraft/upstream/demos/ui-entrance/clipcard-looping/ClipCardLooping.tsx +77 -77
- package/lib/motion/shotcraft/upstream/demos/ui-entrance/cloner-depth-echo/ClonerDepthEcho.tsx +311 -311
- package/lib/motion/shotcraft/upstream/demos/ui-entrance/deck-deal-flyin/DeckDealFlyin.tsx +307 -307
- package/lib/motion/shotcraft/upstream/demos/ui-entrance/doc-park-left-pill-deal/DocParkLeftPillDeal.tsx +349 -349
- package/lib/motion/shotcraft/upstream/demos/ui-entrance/document-typewriter-reveal/DocumentTypewriterReveal.tsx +255 -255
- package/lib/motion/shotcraft/upstream/demos/ui-entrance/draw-svg-trace/DrawSvgTrace.tsx +244 -244
- package/lib/motion/shotcraft/upstream/demos/ui-entrance/element-body-moves/ContactShadowLift.tsx +217 -217
- package/lib/motion/shotcraft/upstream/demos/ui-entrance/integration-hub-map/IntegrationHubMap.tsx +652 -652
- package/lib/motion/shotcraft/upstream/demos/ui-entrance/list-reveal/ListReveal.tsx +153 -153
- package/lib/motion/shotcraft/upstream/demos/ui-entrance/list-stack-press/ListStackPress.tsx +238 -238
- package/lib/motion/shotcraft/upstream/demos/ui-entrance/neon-frame-forerun/NeonFrameForerun.tsx +324 -324
- package/lib/motion/shotcraft/upstream/demos/ui-entrance/neon-frame-orbit-drop/NeonFrameForerunOrbit.tsx +354 -354
- package/lib/motion/shotcraft/upstream/demos/ui-entrance/page-waterfall-wall/PageWaterfallWall.tsx +101 -101
- package/lib/motion/shotcraft/upstream/demos/ui-entrance/page-waterfall-wall/VerticalTicker.tsx +129 -129
- package/lib/motion/shotcraft/upstream/demos/ui-entrance/product-card-progressive-assemble/ProductCardProgressiveAssemble.tsx +297 -297
- package/lib/motion/shotcraft/upstream/demos/ui-entrance/radial-wave/RadialWave.tsx +57 -57
- package/lib/motion/shotcraft/upstream/demos/ui-entrance/research-card-stack-scroll/ResearchCardStackScroll.tsx +155 -155
- package/lib/motion/shotcraft/upstream/demos/ui-entrance/row-embed/RowEmbed.tsx +175 -175
- package/lib/motion/shotcraft/upstream/demos/ui-entrance/value-stagger-gradient/ValueStaggerGradient.tsx +153 -153
- package/lib/motion/shotcraft/upstream/demos/ui-entrance/wall-reveal-moves/BentoLightUp.tsx +146 -146
- package/lib/motion/shotcraft/upstream/demos/ui-entrance/wall-reveal-moves/WireframeDrawOn.tsx +226 -226
- package/lib/motion/shotcraft/upstream/gallery/api/library.json +1 -1
- package/lib/motion/shotcraft/upstream/references/aesthetic-rules.md +193 -193
- package/lib/motion/shotcraft/upstream/references/final-review.md +121 -121
- package/lib/motion/shotcraft/upstream/references/guided-free-creation.md +199 -199
- package/lib/motion/shotcraft/upstream/references/jianying-export.md +183 -183
- package/lib/motion/shotcraft/upstream/references/music-beat-sync.md +257 -257
- package/lib/motion/shotcraft/upstream/references/pipeline.md +382 -382
- package/lib/motion/shotcraft/upstream/references/publish-upload-post.md +111 -111
- package/lib/motion/shotcraft/upstream/references/sequences/promo-energy-arc.md +50 -50
- package/lib/motion/shotcraft/upstream/references/sfx-sourcing.md +95 -95
- package/lib/motion/shotcraft/upstream/references/shots/camera/basic-3d-scene.md +41 -41
- package/lib/motion/shotcraft/upstream/references/shots/camera/crash-zoom-punch.md +52 -52
- package/lib/motion/shotcraft/upstream/references/shots/camera/cursor-flyover.md +39 -39
- package/lib/motion/shotcraft/upstream/references/shots/camera/depth-layer-moves.md +39 -39
- package/lib/motion/shotcraft/upstream/references/shots/camera/graze-face-tour.md +57 -57
- package/lib/motion/shotcraft/upstream/references/shots/camera/overhead-camera-moves.md +51 -51
- package/lib/motion/shotcraft/upstream/references/shots/camera/space-camera-moves.md +46 -46
- package/lib/motion/shotcraft/upstream/references/shots/camera/steep-tilt-glide.md +52 -52
- package/lib/motion/shotcraft/upstream/references/shots/camera/tension-camera-moves.md +43 -43
- package/lib/motion/shotcraft/upstream/references/shots/camera/terminal-3d.md +42 -42
- package/lib/motion/shotcraft/upstream/references/shots/data/before-after-slider-scrub.md +48 -48
- package/lib/motion/shotcraft/upstream/references/shots/data/chart-live-moves.md +52 -52
- package/lib/motion/shotcraft/upstream/references/shots/data/gauge-readout-moves.md +45 -45
- package/lib/motion/shotcraft/upstream/references/shots/data/scroll-brake-moves.md +46 -46
- package/lib/motion/shotcraft/upstream/references/shots/data/timeline-travel.md +44 -44
- package/lib/motion/shotcraft/upstream/references/shots/effects/assemble-then-type-flyin.md +63 -63
- package/lib/motion/shotcraft/upstream/references/shots/effects/aurora-bloom-bg-flip.md +54 -54
- package/lib/motion/shotcraft/upstream/references/shots/effects/brand-frame-snap.md +58 -58
- package/lib/motion/shotcraft/upstream/references/shots/effects/fui-hud-moves.md +35 -35
- package/lib/motion/shotcraft/upstream/references/shots/effects/glow-flyline-moves.md +53 -53
- package/lib/motion/shotcraft/upstream/references/shots/effects/icon-performance-moves.md +42 -42
- package/lib/motion/shotcraft/upstream/references/shots/effects/impact-feedback.md +50 -50
- package/lib/motion/shotcraft/upstream/references/shots/effects/light-play-moves.md +46 -46
- package/lib/motion/shotcraft/upstream/references/shots/effects/radial-ripple-phone-chips.md +56 -56
- package/lib/motion/shotcraft/upstream/references/shots/effects/riso-print-hits.md +49 -49
- package/lib/motion/shotcraft/upstream/references/shots/effects/scan-bracket-sweep.md +50 -50
- package/lib/motion/shotcraft/upstream/references/shots/effects/scanline-annotate-focus.md +53 -53
- package/lib/motion/shotcraft/upstream/references/shots/effects/scanline-assemble-flyin.md +53 -53
- package/lib/motion/shotcraft/upstream/references/shots/effects/slam-entrance-moves.md +55 -55
- package/lib/motion/shotcraft/upstream/references/shots/effects/spotlight-sweep-moves.md +52 -52
- package/lib/motion/shotcraft/upstream/references/shots/interaction/autolayout-gap-dial.md +60 -60
- package/lib/motion/shotcraft/upstream/references/shots/interaction/canvas-materialize-moves.md +57 -57
- package/lib/motion/shotcraft/upstream/references/shots/interaction/chip-grid-single-select-blackout.md +51 -51
- package/lib/motion/shotcraft/upstream/references/shots/interaction/collab-cursor-moves.md +41 -41
- package/lib/motion/shotcraft/upstream/references/shots/interaction/glass-pill-dictation-typing.md +53 -53
- package/lib/motion/shotcraft/upstream/references/shots/interaction/hashtag-to-pill-materialize.md +60 -60
- package/lib/motion/shotcraft/upstream/references/shots/interaction/picker-carousel-feature-cycle.md +55 -55
- package/lib/motion/shotcraft/upstream/references/shots/interaction/segmented-thumb-hero.md +57 -57
- package/lib/motion/shotcraft/upstream/references/shots/interaction/theme-switch-moves.md +47 -47
- package/lib/motion/shotcraft/upstream/references/shots/interaction/type-and-filter.md +37 -37
- package/lib/motion/shotcraft/upstream/references/shots/interaction/voice-waveform-live.md +54 -54
- package/lib/motion/shotcraft/upstream/references/shots/opening/brand-ink-open.md +36 -36
- package/lib/motion/shotcraft/upstream/references/shots/opening/crane-rise-reveal.md +56 -56
- package/lib/motion/shotcraft/upstream/references/shots/opening/dataviz-landscape-open.md +56 -56
- package/lib/motion/shotcraft/upstream/references/shots/opening/fracture.md +40 -40
- package/lib/motion/shotcraft/upstream/references/shots/opening/icon-field-colorize.md +60 -60
- package/lib/motion/shotcraft/upstream/references/shots/opening/letterspace-materialize.md +57 -57
- package/lib/motion/shotcraft/upstream/references/shots/opening/magician-card-flourish.md +73 -73
- package/lib/motion/shotcraft/upstream/references/shots/opening/orbit-ring-title-open.md +87 -87
- package/lib/motion/shotcraft/upstream/references/shots/opening/spotlight-hero-card.md +55 -55
- package/lib/motion/shotcraft/upstream/references/shots/opening/stroke-segment-build.md +50 -50
- package/lib/motion/shotcraft/upstream/references/shots/opening/text-as-mask.md +59 -59
- package/lib/motion/shotcraft/upstream/references/shots/outro/grain-dissolve.md +38 -38
- package/lib/motion/shotcraft/upstream/references/shots/outro/logo-shrink-wordmark-lockup.md +38 -38
- package/lib/motion/shotcraft/upstream/references/shots/outro/neon-triple-marquee.md +59 -59
- package/lib/motion/shotcraft/upstream/references/shots/outro/outro-group-photo-launch.md +39 -39
- package/lib/motion/shotcraft/upstream/references/shots/outro/ui-strip-away-outro.md +61 -61
- package/lib/motion/shotcraft/upstream/references/shots/outro/ui-to-brand-morph.md +52 -52
- package/lib/motion/shotcraft/upstream/references/shots/rhythm/beat-cut-moves.md +50 -50
- package/lib/motion/shotcraft/upstream/references/shots/rhythm/beat-step-list-theme-cycle.md +66 -66
- package/lib/motion/shotcraft/upstream/references/shots/rhythm/panel-grid-moves.md +43 -43
- package/lib/motion/shotcraft/upstream/references/shots/rhythm/quad-split-parallel-scenes.md +38 -38
- package/lib/motion/shotcraft/upstream/references/shots/rhythm/rhythm-interrupt-moves.md +38 -38
- package/lib/motion/shotcraft/upstream/references/shots/rhythm/sakuga-timing-shift.md +56 -56
- package/lib/motion/shotcraft/upstream/references/shots/rhythm/speed-ramp-freeze.md +44 -44
- package/lib/motion/shotcraft/upstream/references/shots/rhythm/trailer-grammar-moves.md +38 -38
- package/lib/motion/shotcraft/upstream/references/shots/transition/bottom-push-stack-wipe.md +63 -63
- package/lib/motion/shotcraft/upstream/references/shots/transition/card-flip-reveal.md +57 -57
- package/lib/motion/shotcraft/upstream/references/shots/transition/card-flock-tumble.md +63 -63
- package/lib/motion/shotcraft/upstream/references/shots/transition/circle-match-iris.md +58 -58
- package/lib/motion/shotcraft/upstream/references/shots/transition/gradient-transition.md +45 -45
- package/lib/motion/shotcraft/upstream/references/shots/transition/line-carry-transition.md +55 -55
- package/lib/motion/shotcraft/upstream/references/shots/transition/mosaic-reframe.md +49 -49
- package/lib/motion/shotcraft/upstream/references/shots/transition/page-turn-transitions.md +42 -42
- package/lib/motion/shotcraft/upstream/references/shots/transition/print-texture-transitions.md +42 -42
- package/lib/motion/shotcraft/upstream/references/shots/transition/shot-transitions.md +45 -45
- package/lib/motion/shotcraft/upstream/references/shots/transition/tear-streak-transitions.md +48 -48
- package/lib/motion/shotcraft/upstream/references/shots/transition/transition-hidden-cut.md +55 -55
- package/lib/motion/shotcraft/upstream/references/shots/transition/transition-travel.md +43 -43
- package/lib/motion/shotcraft/upstream/references/shots/transition/white-flash-logo-simplify-cut.md +41 -41
- package/lib/motion/shotcraft/upstream/references/shots/transition/wipe-transitions.md +42 -42
- package/lib/motion/shotcraft/upstream/references/shots/typography/blur-slide.md +59 -59
- package/lib/motion/shotcraft/upstream/references/shots/typography/brace-expand.md +55 -55
- package/lib/motion/shotcraft/upstream/references/shots/typography/countdown-arc-scatter.md +65 -65
- package/lib/motion/shotcraft/upstream/references/shots/typography/document-typewriter-reveal.md +42 -42
- package/lib/motion/shotcraft/upstream/references/shots/typography/flying-words.md +64 -64
- package/lib/motion/shotcraft/upstream/references/shots/typography/glitch-cycle.md +64 -64
- package/lib/motion/shotcraft/upstream/references/shots/typography/gradient-word-sweep.md +54 -54
- package/lib/motion/shotcraft/upstream/references/shots/typography/lead-word-zoom-assemble.md +91 -91
- package/lib/motion/shotcraft/upstream/references/shots/typography/marker-underline-title.md +51 -51
- package/lib/motion/shotcraft/upstream/references/shots/typography/outline-word-fill.md +66 -66
- package/lib/motion/shotcraft/upstream/references/shots/typography/paper-title-card.md +38 -38
- package/lib/motion/shotcraft/upstream/references/shots/typography/pill-chip-slot-cycle-handled.md +66 -66
- package/lib/motion/shotcraft/upstream/references/shots/typography/pill-slot-cycle.md +58 -58
- package/lib/motion/shotcraft/upstream/references/shots/typography/text-column-converge.md +61 -61
- package/lib/motion/shotcraft/upstream/references/shots/typography/title-demote-to-label.md +64 -64
- package/lib/motion/shotcraft/upstream/references/shots/typography/type-assembly-moves.md +45 -45
- package/lib/motion/shotcraft/upstream/references/shots/typography/type-entrance-moves.md +41 -41
- package/lib/motion/shotcraft/upstream/references/shots/typography/type-rhythm-sync.md +51 -51
- package/lib/motion/shotcraft/upstream/references/shots/typography/typewriter-moves.md +42 -42
- package/lib/motion/shotcraft/upstream/references/shots/typography/vertical-word-roll-blur-cycle.md +63 -63
- package/lib/motion/shotcraft/upstream/references/shots/typography/word-relay-filmstrip.md +57 -57
- package/lib/motion/shotcraft/upstream/references/shots/typography/word-relay-geometry.md +75 -75
- package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/avatar-bracket-carousel.md +59 -59
- package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/bezier-source-converge-merge.md +67 -67
- package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/card-stack.md +60 -60
- package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/carousel-3d.md +66 -66
- package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/cloner-depth-echo.md +40 -40
- package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/deck-deal-flyin.md +45 -45
- package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/doc-park-left-pill-deal.md +62 -62
- package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/draw-svg-trace.md +55 -55
- package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/element-body-moves.md +37 -37
- package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/integration-hub-map.md +55 -55
- package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/list-reveal.md +50 -50
- package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/list-stack-press.md +43 -43
- package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/neon-frame-forerun.md +55 -55
- package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/neon-frame-orbit-drop.md +51 -51
- package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/page-waterfall-wall.md +51 -51
- package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/product-card-progressive-assemble.md +56 -56
- package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/radial-wave.md +49 -49
- package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/research-card-stack-scroll.md +57 -57
- package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/row-embed.md +36 -36
- package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/value-stagger-gradient.md +64 -64
- package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/wall-reveal-moves.md +47 -47
- package/lib/motion/shotcraft/upstream/references/sound-design.md +170 -170
- package/lib/motion/shotcraft/upstream/references/workbench.md +157 -157
- package/lib/motion/shotcraft/upstream/template/TEMPLATE.md +103 -103
- package/lib/motion/shotcraft/upstream/template/THEMES.md +44 -44
- package/lib/motion/shotcraft/upstream/template/package.json +20 -20
- package/lib/motion/shotcraft/upstream/template/remotion.config.ts +6 -6
- package/lib/motion/shotcraft/upstream/template/src/Root.tsx +17 -17
- package/lib/motion/shotcraft/upstream/template/src/aifl/Caption.tsx +65 -65
- package/lib/motion/shotcraft/upstream/template/src/aifl/DigitRoll.tsx +48 -48
- package/lib/motion/shotcraft/upstream/template/src/aifl/FlashCut.tsx +24 -24
- package/lib/motion/shotcraft/upstream/template/src/aifl/Main.tsx +192 -192
- package/lib/motion/shotcraft/upstream/template/src/aifl/PaperTitleCard.tsx +111 -111
- package/lib/motion/shotcraft/upstream/template/src/aifl/live/PageCam.tsx +150 -150
- package/lib/motion/shotcraft/upstream/template/src/aifl/live/SceneDetail.tsx +158 -158
- package/lib/motion/shotcraft/upstream/template/src/aifl/live/SceneFlyIn.tsx +468 -468
- package/lib/motion/shotcraft/upstream/template/src/aifl/live/SceneOpen.tsx +552 -552
- package/lib/motion/shotcraft/upstream/template/src/aifl/live/SceneOutroLive.tsx +411 -411
- package/lib/motion/shotcraft/upstream/template/src/aifl/live/ScenePapers.tsx +200 -200
- package/lib/motion/shotcraft/upstream/template/src/aifl/live/SceneWbr.tsx +324 -324
- package/lib/motion/shotcraft/upstream/template/src/aifl/live-layout.json +388 -388
- package/lib/motion/shotcraft/upstream/template/src/index.ts +4 -4
- package/lib/motion/shotcraft/upstream/template/src/themes/ThemedFilm.tsx +7 -7
- package/lib/motion/shotcraft/upstream/template/src/themes/manifest.tsx +68 -68
- package/lib/motion/shotcraft/upstream/template/src/themes/palette-assets.json +1 -1
- package/lib/motion/shotcraft/upstream/template/src/themes/palette-assets.ts +24 -24
- package/lib/motion/shotcraft/upstream/template/src/themes/palettes.json +74 -74
- package/lib/motion/shotcraft/upstream/template/src/themes/visual-theme.tsx +91 -91
- package/lib/motion/shotcraft/upstream/template/src/workbench.ts +213 -213
- package/lib/motion/shotcraft/upstream/template/tsconfig.json +15 -15
- package/lib/motion/style-frames.js +306 -306
- package/lib/motion/sync.js +214 -214
- package/lib/motion-library.js +1 -1
- package/lib/motion-project.js +105 -105
- package/lib/motion-render-worker.js +174 -174
- package/lib/routing/router.js +222 -222
- package/lib/routing/vendor/README.md +96 -96
- package/lib/routing/vendor/libavoid-routing.js +753 -753
- package/lib/routing/vendor/libavoid.min.js +59 -59
- package/lib/svg-export.js +1344 -0
- package/lib/video-trace-pool.js +128 -128
- package/package.json +3 -2
- 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 & 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 & 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
|
+
并在输出里报告,不阻塞全量。
|