dsh-drawai 0.4.2 → 0.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (366) hide show
  1. package/README.md +4 -3
  2. package/lib/index.js +7777 -7719
  3. package/lib/motion/asset-pack.js +394 -394
  4. package/lib/motion/assets.js +291 -291
  5. package/lib/motion/demo-assets-lock.js +10 -10
  6. package/lib/motion/mgstyles/vendor/README.md +28 -28
  7. package/lib/motion/mgstyles/vendor/modules/d3/LICENSE +13 -13
  8. package/lib/motion/mgstyles/vendor/modules/d3/dist/d3.min.js +2 -2
  9. package/lib/motion/mgstyles/vendor/modules/opentype.js/LICENSE +20 -20
  10. package/lib/motion/mgstyles/vendor/modules/opentype.js/dist/opentype.mjs +14460 -14460
  11. package/lib/motion/mgstyles/vendor/modules/simplex-noise/LICENSE +21 -21
  12. package/lib/motion/mgstyles/vendor/modules/simplex-noise/dist/esm/simplex-noise.js +465 -465
  13. package/lib/motion/mgstyles/vendor/modules/topojson-client/LICENSE +13 -13
  14. package/lib/motion/mgstyles/vendor/modules/topojson-client/dist/topojson-client.min.js +2 -2
  15. package/lib/motion/render.js +179 -179
  16. package/lib/motion/shotcraft/upstream/SKILL.md +286 -286
  17. package/lib/motion/shotcraft/upstream/assets/lib/Caption.tsx +54 -54
  18. package/lib/motion/shotcraft/upstream/assets/lib/ClipCard.tsx +200 -200
  19. package/lib/motion/shotcraft/upstream/assets/lib/DigitRoll.tsx +45 -45
  20. package/lib/motion/shotcraft/upstream/assets/lib/FlashCut.tsx +20 -20
  21. package/lib/motion/shotcraft/upstream/assets/lib/FlatPanel.tsx +65 -65
  22. package/lib/motion/shotcraft/upstream/assets/lib/PageCam.tsx +151 -151
  23. package/lib/motion/shotcraft/upstream/assets/lib/VerticalTicker.tsx +129 -129
  24. package/lib/motion/shotcraft/upstream/assets/lib/helpers/camera.tsx +75 -75
  25. package/lib/motion/shotcraft/upstream/assets/lib/helpers/motion.ts +40 -40
  26. package/lib/motion/shotcraft/upstream/assets/lib/helpers/rand.ts +11 -11
  27. package/lib/motion/shotcraft/upstream/assets/lib/helpers/shake.ts +10 -10
  28. package/lib/motion/shotcraft/upstream/assets/scripts/build-readme-cover.mjs +49 -49
  29. package/lib/motion/shotcraft/upstream/assets/scripts/capture-template.mjs +210 -210
  30. package/lib/motion/shotcraft/upstream/assets/scripts/sfx-source.py +423 -423
  31. package/lib/motion/shotcraft/upstream/assets/scripts/smoke-render-demos.py +170 -170
  32. package/lib/motion/shotcraft/upstream/assets/scripts/test_sfx_source.py +157 -157
  33. package/lib/motion/shotcraft/upstream/demos/README.md +120 -120
  34. package/lib/motion/shotcraft/upstream/demos/_fixtures/Brand.tsx +112 -112
  35. package/lib/motion/shotcraft/upstream/demos/_fixtures/Fixtures.tsx +647 -647
  36. package/lib/motion/shotcraft/upstream/demos/_fixtures/Look.tsx +316 -316
  37. package/lib/motion/shotcraft/upstream/demos/_fixtures/Motion.tsx +82 -82
  38. package/lib/motion/shotcraft/upstream/demos/_fixtures/PageCam2D.tsx +115 -115
  39. package/lib/motion/shotcraft/upstream/demos/_fixtures/Polish.tsx +243 -243
  40. package/lib/motion/shotcraft/upstream/demos/_textures/live-layout.json +388 -388
  41. package/lib/motion/shotcraft/upstream/demos/camera/basic-3d-scene/Basic3DScene.tsx +250 -250
  42. package/lib/motion/shotcraft/upstream/demos/camera/crash-zoom-punch/CrashImpactReal.tsx +305 -305
  43. package/lib/motion/shotcraft/upstream/demos/camera/crash-zoom-punch/CrashZoomReal.tsx +246 -246
  44. package/lib/motion/shotcraft/upstream/demos/camera/cursor-flyover/CursorFlyover.tsx +390 -390
  45. package/lib/motion/shotcraft/upstream/demos/camera/depth-layer-moves/MultiplaneReal.tsx +138 -138
  46. package/lib/motion/shotcraft/upstream/demos/camera/graze-face-tour/GrazeFaceTour.tsx +542 -542
  47. package/lib/motion/shotcraft/upstream/demos/camera/overhead-camera-moves/OverheadTabletopDrop.tsx +315 -315
  48. package/lib/motion/shotcraft/upstream/demos/camera/overhead-camera-moves/TiltReveal.tsx +299 -299
  49. package/lib/motion/shotcraft/upstream/demos/camera/space-camera-moves/DroneDiveLanding.tsx +173 -173
  50. package/lib/motion/shotcraft/upstream/demos/camera/space-camera-moves/ExplodedView.tsx +348 -348
  51. package/lib/motion/shotcraft/upstream/demos/camera/steep-tilt-glide/SteepTiltGlide.tsx +366 -366
  52. package/lib/motion/shotcraft/upstream/demos/camera/tension-camera-moves/BulletTimeFreezeOrbit.tsx +279 -279
  53. package/lib/motion/shotcraft/upstream/demos/camera/tension-camera-moves/PullBackIsolation.tsx +184 -184
  54. package/lib/motion/shotcraft/upstream/demos/camera/terminal-3d/Terminal3D.tsx +390 -390
  55. package/lib/motion/shotcraft/upstream/demos/data/before-after-slider-scrub/BeforeAfterSliderScrub.tsx +155 -155
  56. package/lib/motion/shotcraft/upstream/demos/data/chart-live-moves/AxisRescaleShockV2.tsx +303 -303
  57. package/lib/motion/shotcraft/upstream/demos/data/chart-live-moves/OscilloscopeStreamV2.tsx +290 -290
  58. package/lib/motion/shotcraft/upstream/demos/data/chart-live-moves/UnitDotSwarmRegroupV2.tsx +278 -278
  59. package/lib/motion/shotcraft/upstream/demos/data/gauge-readout-moves/NeedleSweepSelftest.tsx +307 -307
  60. package/lib/motion/shotcraft/upstream/demos/data/gauge-readout-moves/TapeScrollFixedPointer.tsx +215 -215
  61. package/lib/motion/shotcraft/upstream/demos/data/scroll-brake-moves/BrakeReticleLock.tsx +299 -299
  62. package/lib/motion/shotcraft/upstream/demos/data/scroll-brake-moves/ChangelogScrollBrake.tsx +232 -232
  63. package/lib/motion/shotcraft/upstream/demos/data/timeline-travel/TimelineTravel.tsx +290 -290
  64. package/lib/motion/shotcraft/upstream/demos/effects/assemble-then-type-flyin/AssembleThenTypeFlyin.tsx +273 -273
  65. package/lib/motion/shotcraft/upstream/demos/effects/aurora-bloom-bg-flip/AuroraBloomBgFlip.tsx +167 -167
  66. package/lib/motion/shotcraft/upstream/demos/effects/brand-frame-snap/BrandFrameSnap.tsx +536 -536
  67. package/lib/motion/shotcraft/upstream/demos/effects/fui-hud-moves/ReticleLockOn.tsx +164 -164
  68. package/lib/motion/shotcraft/upstream/demos/effects/glow-flyline-moves/FlylineArc.tsx +175 -175
  69. package/lib/motion/shotcraft/upstream/demos/effects/glow-flyline-moves/GlowOrbAmbient.tsx +197 -197
  70. package/lib/motion/shotcraft/upstream/demos/effects/glow-flyline-moves/OrbFlylineRelay.tsx +241 -241
  71. package/lib/motion/shotcraft/upstream/demos/effects/icon-performance-moves/AttentionBounce.tsx +279 -279
  72. package/lib/motion/shotcraft/upstream/demos/effects/impact-feedback/AnimeImpact.tsx +230 -230
  73. package/lib/motion/shotcraft/upstream/demos/effects/impact-feedback/HitCounter.tsx +345 -345
  74. package/lib/motion/shotcraft/upstream/demos/effects/light-play-moves/SheenSweepRetry.tsx +275 -275
  75. package/lib/motion/shotcraft/upstream/demos/effects/light-play-moves/SpotlightSweepReveal.tsx +229 -229
  76. package/lib/motion/shotcraft/upstream/demos/effects/radial-ripple-phone-chips/RadialRipplePhoneChips.tsx +312 -312
  77. package/lib/motion/shotcraft/upstream/demos/effects/riso-print-hits/RisoMisregistrationHit.tsx +222 -222
  78. package/lib/motion/shotcraft/upstream/demos/effects/scan-bracket-sweep/ScanBracketSweep.tsx +295 -295
  79. package/lib/motion/shotcraft/upstream/demos/effects/scanline-annotate-focus/ScanlineAnnotateFocus.tsx +329 -329
  80. package/lib/motion/shotcraft/upstream/demos/effects/scanline-assemble-flyin/ScanlineAssembleFlyin.tsx +315 -315
  81. package/lib/motion/shotcraft/upstream/demos/effects/slam-entrance-moves/ImpactBurstKit.tsx +264 -264
  82. package/lib/motion/shotcraft/upstream/demos/effects/slam-entrance-moves/KanadaPerspectiveSnap.tsx +260 -260
  83. package/lib/motion/shotcraft/upstream/demos/effects/slam-entrance-moves/ScoreSlam.tsx +263 -263
  84. package/lib/motion/shotcraft/upstream/demos/effects/spotlight-sweep-moves/CornerSpotlightReveal.tsx +123 -123
  85. package/lib/motion/shotcraft/upstream/demos/effects/spotlight-sweep-moves/GlowWakeSleepPanel.tsx +187 -187
  86. package/lib/motion/shotcraft/upstream/demos/effects/spotlight-sweep-moves/SlideSpotlightPan.tsx +175 -175
  87. package/lib/motion/shotcraft/upstream/demos/interaction/autolayout-gap-dial/AutolayoutGapDial.tsx +305 -305
  88. package/lib/motion/shotcraft/upstream/demos/interaction/canvas-materialize-moves/DiagramCascadeBuild.tsx +350 -350
  89. package/lib/motion/shotcraft/upstream/demos/interaction/canvas-materialize-moves/PanelToCanvasMaterialize.tsx +352 -352
  90. package/lib/motion/shotcraft/upstream/demos/interaction/chip-grid-single-select-blackout/ChipGridSingleSelectBlackout.tsx +218 -218
  91. package/lib/motion/shotcraft/upstream/demos/interaction/collab-cursor-moves/CursorCastEnsemble.tsx +297 -297
  92. package/lib/motion/shotcraft/upstream/demos/interaction/glass-pill-dictation-typing/GlassPillDictationTyping.tsx +157 -157
  93. package/lib/motion/shotcraft/upstream/demos/interaction/hashtag-to-pill-materialize/HashtagToPillMaterialize.tsx +218 -218
  94. package/lib/motion/shotcraft/upstream/demos/interaction/picker-carousel-feature-cycle/PickerCarouselFeatureCycle.tsx +202 -202
  95. package/lib/motion/shotcraft/upstream/demos/interaction/segmented-thumb-hero/SegmentedThumbHero.tsx +265 -265
  96. package/lib/motion/shotcraft/upstream/demos/interaction/theme-switch-moves/PaletteThemeRipple.tsx +457 -457
  97. package/lib/motion/shotcraft/upstream/demos/interaction/theme-switch-moves/ThemeSweepToggle.tsx +446 -446
  98. package/lib/motion/shotcraft/upstream/demos/interaction/type-and-filter/TypeAndFilter.tsx +249 -249
  99. package/lib/motion/shotcraft/upstream/demos/interaction/voice-waveform-live/VoiceWaveformLive.tsx +278 -278
  100. package/lib/motion/shotcraft/upstream/demos/opening/crane-rise-reveal/CraneRiseReveal.tsx +332 -332
  101. package/lib/motion/shotcraft/upstream/demos/opening/dataviz-landscape-open/DatavizLandscapeOpen.tsx +358 -358
  102. package/lib/motion/shotcraft/upstream/demos/opening/fracture/Fracture.tsx +201 -201
  103. package/lib/motion/shotcraft/upstream/demos/opening/icon-field-colorize/IconFieldColorize.tsx +200 -200
  104. package/lib/motion/shotcraft/upstream/demos/opening/letterspace-materialize/LetterspaceMaterialize.tsx +208 -208
  105. package/lib/motion/shotcraft/upstream/demos/opening/magician-card-flourish/MagicianCardFlourish.tsx +341 -341
  106. package/lib/motion/shotcraft/upstream/demos/opening/orbit-ring-title-open/OrbitRingTitleOpen.tsx +389 -389
  107. package/lib/motion/shotcraft/upstream/demos/opening/spotlight-hero-card/SpotlightHeroCard.tsx +293 -293
  108. package/lib/motion/shotcraft/upstream/demos/opening/stroke-segment-build/StrokeSegmentBuild.tsx +183 -183
  109. package/lib/motion/shotcraft/upstream/demos/opening/text-as-mask/TextAsMask.tsx +245 -245
  110. package/lib/motion/shotcraft/upstream/demos/outro/grain-dissolve/GrainDissolve.tsx +222 -222
  111. package/lib/motion/shotcraft/upstream/demos/outro/logo-shrink-wordmark-lockup/LogoShrinkWordmarkLockup.tsx +223 -223
  112. package/lib/motion/shotcraft/upstream/demos/outro/neon-triple-marquee/NeonTripleMarquee.tsx +217 -217
  113. package/lib/motion/shotcraft/upstream/demos/outro/outro-group-photo-launch/OutroGroupPhotoLaunch.tsx +343 -343
  114. package/lib/motion/shotcraft/upstream/demos/outro/ui-strip-away-outro/UiStripAwayOutro.tsx +357 -357
  115. package/lib/motion/shotcraft/upstream/demos/outro/ui-to-brand-morph/IconFlipBloomLogo.tsx +187 -187
  116. package/lib/motion/shotcraft/upstream/demos/outro/ui-to-brand-morph/InputMorphsIntoLogo.tsx +333 -333
  117. package/lib/motion/shotcraft/upstream/demos/rhythm/beat-cut-moves/PaparazziFlash.tsx +274 -274
  118. package/lib/motion/shotcraft/upstream/demos/rhythm/beat-step-list-theme-cycle/BeatStepListThemeCycle.tsx +270 -270
  119. package/lib/motion/shotcraft/upstream/demos/rhythm/panel-grid-moves/ComicPanelSplit.tsx +430 -430
  120. package/lib/motion/shotcraft/upstream/demos/rhythm/quad-split-parallel-scenes/QuadSplitParallelScenes.tsx +252 -252
  121. package/lib/motion/shotcraft/upstream/demos/rhythm/rhythm-interrupt-moves/JumpCutPunchIn.tsx +106 -106
  122. package/lib/motion/shotcraft/upstream/demos/rhythm/sakuga-timing-shift/SakugaTimingShift.tsx +288 -288
  123. package/lib/motion/shotcraft/upstream/demos/rhythm/speed-ramp-freeze/FreezeAnnotateReal.tsx +362 -362
  124. package/lib/motion/shotcraft/upstream/demos/rhythm/trailer-grammar-moves/TrailerBumper.tsx +168 -168
  125. package/lib/motion/shotcraft/upstream/demos/transition/bottom-push-stack-wipe/BottomPushStackWipe.tsx +310 -310
  126. package/lib/motion/shotcraft/upstream/demos/transition/card-flip-reveal/CardFlipReveal.tsx +261 -261
  127. package/lib/motion/shotcraft/upstream/demos/transition/card-flock-tumble/CardFlockTumble.tsx +459 -459
  128. package/lib/motion/shotcraft/upstream/demos/transition/circle-match-iris/CircleMatchIris.tsx +294 -294
  129. package/lib/motion/shotcraft/upstream/demos/transition/gradient-transition/GradientTransition.tsx +161 -161
  130. package/lib/motion/shotcraft/upstream/demos/transition/line-carry-transition/LineCarryTransition.tsx +248 -248
  131. package/lib/motion/shotcraft/upstream/demos/transition/mosaic-reframe/MosaicReframe.tsx +359 -359
  132. package/lib/motion/shotcraft/upstream/demos/transition/page-turn-transitions/BarnDoorSplit.tsx +227 -227
  133. package/lib/motion/shotcraft/upstream/demos/transition/print-texture-transitions/InkBleedReveal.tsx +162 -162
  134. package/lib/motion/shotcraft/upstream/demos/transition/shot-transitions/PortalWipeV2.tsx +248 -248
  135. package/lib/motion/shotcraft/upstream/demos/transition/shot-transitions/WhipBrakeReal.tsx +186 -186
  136. package/lib/motion/shotcraft/upstream/demos/transition/tear-streak-transitions/GlitchDisplace.tsx +355 -355
  137. package/lib/motion/shotcraft/upstream/demos/transition/transition-hidden-cut/InvisibleCut.tsx +272 -272
  138. package/lib/motion/shotcraft/upstream/demos/transition/transition-hidden-cut/LightLeakBurn.tsx +262 -262
  139. package/lib/motion/shotcraft/upstream/demos/transition/transition-hidden-cut/VersusSlam.tsx +217 -217
  140. package/lib/motion/shotcraft/upstream/demos/transition/transition-travel/LetterformZoom.tsx +285 -285
  141. package/lib/motion/shotcraft/upstream/demos/transition/white-flash-logo-simplify-cut/WhiteFlashLogoSimplifyCut.tsx +205 -205
  142. package/lib/motion/shotcraft/upstream/demos/transition/wipe-transitions/BlindsSlice.tsx +178 -178
  143. package/lib/motion/shotcraft/upstream/demos/typography/blur-slide/BlurSlide.tsx +147 -147
  144. package/lib/motion/shotcraft/upstream/demos/typography/brace-expand/BraceExpand.tsx +143 -143
  145. package/lib/motion/shotcraft/upstream/demos/typography/brand-ink-open/BrandInkOpen.tsx +134 -134
  146. package/lib/motion/shotcraft/upstream/demos/typography/countdown-arc-scatter/CountdownArcScatter.tsx +217 -217
  147. package/lib/motion/shotcraft/upstream/demos/typography/flying-words/FlyingWords.tsx +198 -198
  148. package/lib/motion/shotcraft/upstream/demos/typography/glitch-cycle/GlitchCycle.tsx +221 -221
  149. package/lib/motion/shotcraft/upstream/demos/typography/gradient-word-sweep/GradientWordSweep.tsx +312 -312
  150. package/lib/motion/shotcraft/upstream/demos/typography/lead-word-zoom-assemble/LeadWordZoomAssemble.tsx +261 -261
  151. package/lib/motion/shotcraft/upstream/demos/typography/marker-underline-title/MarkerUnderlineTitle.tsx +121 -121
  152. package/lib/motion/shotcraft/upstream/demos/typography/outline-word-fill/OutlineWordFill.tsx +153 -153
  153. package/lib/motion/shotcraft/upstream/demos/typography/paper-title-card/PaperTitleCard.tsx +179 -179
  154. package/lib/motion/shotcraft/upstream/demos/typography/pill-chip-slot-cycle-handled/PillChipSlotCycleHandled.tsx +140 -140
  155. package/lib/motion/shotcraft/upstream/demos/typography/pill-slot-cycle/PillSlotCycle.tsx +309 -309
  156. package/lib/motion/shotcraft/upstream/demos/typography/text-column-converge/TextColumnConverge.tsx +191 -191
  157. package/lib/motion/shotcraft/upstream/demos/typography/title-demote-to-label/TitleDemoteToLabel.tsx +292 -292
  158. package/lib/motion/shotcraft/upstream/demos/typography/type-assembly-moves/LetterformDriftAssembly.tsx +135 -135
  159. package/lib/motion/shotcraft/upstream/demos/typography/type-assembly-moves/SplitTextStagger.tsx +124 -124
  160. package/lib/motion/shotcraft/upstream/demos/typography/type-assembly-moves/TextOnPath.tsx +255 -255
  161. package/lib/motion/shotcraft/upstream/demos/typography/type-entrance-moves/LetterDropPhysics.tsx +173 -173
  162. package/lib/motion/shotcraft/upstream/demos/typography/type-rhythm-sync/FontWeightPump.tsx +225 -225
  163. package/lib/motion/shotcraft/upstream/demos/typography/type-rhythm-sync/KaraokeFillSync.tsx +141 -141
  164. package/lib/motion/shotcraft/upstream/demos/typography/typewriter-moves/TypewriterErrorRetype.tsx +137 -137
  165. package/lib/motion/shotcraft/upstream/demos/typography/vertical-word-roll-blur-cycle/VerticalWordRollBlurCycle.tsx +147 -147
  166. package/lib/motion/shotcraft/upstream/demos/typography/word-relay-filmstrip/WordRelayFilmstrip.tsx +409 -409
  167. package/lib/motion/shotcraft/upstream/demos/typography/word-relay-geometry/WordRelayGeometry.tsx +280 -280
  168. package/lib/motion/shotcraft/upstream/demos/ui-entrance/avatar-bracket-carousel/AvatarBracketCarousel.tsx +271 -271
  169. package/lib/motion/shotcraft/upstream/demos/ui-entrance/bezier-source-converge-merge/BezierSourceConvergeMerge.tsx +385 -385
  170. package/lib/motion/shotcraft/upstream/demos/ui-entrance/card-stack/CardStack.tsx +312 -312
  171. package/lib/motion/shotcraft/upstream/demos/ui-entrance/carousel-3d/Carousel3D.tsx +303 -303
  172. package/lib/motion/shotcraft/upstream/demos/ui-entrance/clipcard-looping/ClipCardLooping.tsx +77 -77
  173. package/lib/motion/shotcraft/upstream/demos/ui-entrance/cloner-depth-echo/ClonerDepthEcho.tsx +311 -311
  174. package/lib/motion/shotcraft/upstream/demos/ui-entrance/deck-deal-flyin/DeckDealFlyin.tsx +307 -307
  175. package/lib/motion/shotcraft/upstream/demos/ui-entrance/doc-park-left-pill-deal/DocParkLeftPillDeal.tsx +349 -349
  176. package/lib/motion/shotcraft/upstream/demos/ui-entrance/document-typewriter-reveal/DocumentTypewriterReveal.tsx +255 -255
  177. package/lib/motion/shotcraft/upstream/demos/ui-entrance/draw-svg-trace/DrawSvgTrace.tsx +244 -244
  178. package/lib/motion/shotcraft/upstream/demos/ui-entrance/element-body-moves/ContactShadowLift.tsx +217 -217
  179. package/lib/motion/shotcraft/upstream/demos/ui-entrance/integration-hub-map/IntegrationHubMap.tsx +652 -652
  180. package/lib/motion/shotcraft/upstream/demos/ui-entrance/list-reveal/ListReveal.tsx +153 -153
  181. package/lib/motion/shotcraft/upstream/demos/ui-entrance/list-stack-press/ListStackPress.tsx +238 -238
  182. package/lib/motion/shotcraft/upstream/demos/ui-entrance/neon-frame-forerun/NeonFrameForerun.tsx +324 -324
  183. package/lib/motion/shotcraft/upstream/demos/ui-entrance/neon-frame-orbit-drop/NeonFrameForerunOrbit.tsx +354 -354
  184. package/lib/motion/shotcraft/upstream/demos/ui-entrance/page-waterfall-wall/PageWaterfallWall.tsx +101 -101
  185. package/lib/motion/shotcraft/upstream/demos/ui-entrance/page-waterfall-wall/VerticalTicker.tsx +129 -129
  186. package/lib/motion/shotcraft/upstream/demos/ui-entrance/product-card-progressive-assemble/ProductCardProgressiveAssemble.tsx +297 -297
  187. package/lib/motion/shotcraft/upstream/demos/ui-entrance/radial-wave/RadialWave.tsx +57 -57
  188. package/lib/motion/shotcraft/upstream/demos/ui-entrance/research-card-stack-scroll/ResearchCardStackScroll.tsx +155 -155
  189. package/lib/motion/shotcraft/upstream/demos/ui-entrance/row-embed/RowEmbed.tsx +175 -175
  190. package/lib/motion/shotcraft/upstream/demos/ui-entrance/value-stagger-gradient/ValueStaggerGradient.tsx +153 -153
  191. package/lib/motion/shotcraft/upstream/demos/ui-entrance/wall-reveal-moves/BentoLightUp.tsx +146 -146
  192. package/lib/motion/shotcraft/upstream/demos/ui-entrance/wall-reveal-moves/WireframeDrawOn.tsx +226 -226
  193. package/lib/motion/shotcraft/upstream/gallery/api/library.json +1 -1
  194. package/lib/motion/shotcraft/upstream/references/aesthetic-rules.md +193 -193
  195. package/lib/motion/shotcraft/upstream/references/final-review.md +121 -121
  196. package/lib/motion/shotcraft/upstream/references/guided-free-creation.md +199 -199
  197. package/lib/motion/shotcraft/upstream/references/jianying-export.md +183 -183
  198. package/lib/motion/shotcraft/upstream/references/music-beat-sync.md +257 -257
  199. package/lib/motion/shotcraft/upstream/references/pipeline.md +382 -382
  200. package/lib/motion/shotcraft/upstream/references/publish-upload-post.md +111 -111
  201. package/lib/motion/shotcraft/upstream/references/sequences/promo-energy-arc.md +50 -50
  202. package/lib/motion/shotcraft/upstream/references/sfx-sourcing.md +95 -95
  203. package/lib/motion/shotcraft/upstream/references/shots/camera/basic-3d-scene.md +41 -41
  204. package/lib/motion/shotcraft/upstream/references/shots/camera/crash-zoom-punch.md +52 -52
  205. package/lib/motion/shotcraft/upstream/references/shots/camera/cursor-flyover.md +39 -39
  206. package/lib/motion/shotcraft/upstream/references/shots/camera/depth-layer-moves.md +39 -39
  207. package/lib/motion/shotcraft/upstream/references/shots/camera/graze-face-tour.md +57 -57
  208. package/lib/motion/shotcraft/upstream/references/shots/camera/overhead-camera-moves.md +51 -51
  209. package/lib/motion/shotcraft/upstream/references/shots/camera/space-camera-moves.md +46 -46
  210. package/lib/motion/shotcraft/upstream/references/shots/camera/steep-tilt-glide.md +52 -52
  211. package/lib/motion/shotcraft/upstream/references/shots/camera/tension-camera-moves.md +43 -43
  212. package/lib/motion/shotcraft/upstream/references/shots/camera/terminal-3d.md +42 -42
  213. package/lib/motion/shotcraft/upstream/references/shots/data/before-after-slider-scrub.md +48 -48
  214. package/lib/motion/shotcraft/upstream/references/shots/data/chart-live-moves.md +52 -52
  215. package/lib/motion/shotcraft/upstream/references/shots/data/gauge-readout-moves.md +45 -45
  216. package/lib/motion/shotcraft/upstream/references/shots/data/scroll-brake-moves.md +46 -46
  217. package/lib/motion/shotcraft/upstream/references/shots/data/timeline-travel.md +44 -44
  218. package/lib/motion/shotcraft/upstream/references/shots/effects/assemble-then-type-flyin.md +63 -63
  219. package/lib/motion/shotcraft/upstream/references/shots/effects/aurora-bloom-bg-flip.md +54 -54
  220. package/lib/motion/shotcraft/upstream/references/shots/effects/brand-frame-snap.md +58 -58
  221. package/lib/motion/shotcraft/upstream/references/shots/effects/fui-hud-moves.md +35 -35
  222. package/lib/motion/shotcraft/upstream/references/shots/effects/glow-flyline-moves.md +53 -53
  223. package/lib/motion/shotcraft/upstream/references/shots/effects/icon-performance-moves.md +42 -42
  224. package/lib/motion/shotcraft/upstream/references/shots/effects/impact-feedback.md +50 -50
  225. package/lib/motion/shotcraft/upstream/references/shots/effects/light-play-moves.md +46 -46
  226. package/lib/motion/shotcraft/upstream/references/shots/effects/radial-ripple-phone-chips.md +56 -56
  227. package/lib/motion/shotcraft/upstream/references/shots/effects/riso-print-hits.md +49 -49
  228. package/lib/motion/shotcraft/upstream/references/shots/effects/scan-bracket-sweep.md +50 -50
  229. package/lib/motion/shotcraft/upstream/references/shots/effects/scanline-annotate-focus.md +53 -53
  230. package/lib/motion/shotcraft/upstream/references/shots/effects/scanline-assemble-flyin.md +53 -53
  231. package/lib/motion/shotcraft/upstream/references/shots/effects/slam-entrance-moves.md +55 -55
  232. package/lib/motion/shotcraft/upstream/references/shots/effects/spotlight-sweep-moves.md +52 -52
  233. package/lib/motion/shotcraft/upstream/references/shots/interaction/autolayout-gap-dial.md +60 -60
  234. package/lib/motion/shotcraft/upstream/references/shots/interaction/canvas-materialize-moves.md +57 -57
  235. package/lib/motion/shotcraft/upstream/references/shots/interaction/chip-grid-single-select-blackout.md +51 -51
  236. package/lib/motion/shotcraft/upstream/references/shots/interaction/collab-cursor-moves.md +41 -41
  237. package/lib/motion/shotcraft/upstream/references/shots/interaction/glass-pill-dictation-typing.md +53 -53
  238. package/lib/motion/shotcraft/upstream/references/shots/interaction/hashtag-to-pill-materialize.md +60 -60
  239. package/lib/motion/shotcraft/upstream/references/shots/interaction/picker-carousel-feature-cycle.md +55 -55
  240. package/lib/motion/shotcraft/upstream/references/shots/interaction/segmented-thumb-hero.md +57 -57
  241. package/lib/motion/shotcraft/upstream/references/shots/interaction/theme-switch-moves.md +47 -47
  242. package/lib/motion/shotcraft/upstream/references/shots/interaction/type-and-filter.md +37 -37
  243. package/lib/motion/shotcraft/upstream/references/shots/interaction/voice-waveform-live.md +54 -54
  244. package/lib/motion/shotcraft/upstream/references/shots/opening/brand-ink-open.md +36 -36
  245. package/lib/motion/shotcraft/upstream/references/shots/opening/crane-rise-reveal.md +56 -56
  246. package/lib/motion/shotcraft/upstream/references/shots/opening/dataviz-landscape-open.md +56 -56
  247. package/lib/motion/shotcraft/upstream/references/shots/opening/fracture.md +40 -40
  248. package/lib/motion/shotcraft/upstream/references/shots/opening/icon-field-colorize.md +60 -60
  249. package/lib/motion/shotcraft/upstream/references/shots/opening/letterspace-materialize.md +57 -57
  250. package/lib/motion/shotcraft/upstream/references/shots/opening/magician-card-flourish.md +73 -73
  251. package/lib/motion/shotcraft/upstream/references/shots/opening/orbit-ring-title-open.md +87 -87
  252. package/lib/motion/shotcraft/upstream/references/shots/opening/spotlight-hero-card.md +55 -55
  253. package/lib/motion/shotcraft/upstream/references/shots/opening/stroke-segment-build.md +50 -50
  254. package/lib/motion/shotcraft/upstream/references/shots/opening/text-as-mask.md +59 -59
  255. package/lib/motion/shotcraft/upstream/references/shots/outro/grain-dissolve.md +38 -38
  256. package/lib/motion/shotcraft/upstream/references/shots/outro/logo-shrink-wordmark-lockup.md +38 -38
  257. package/lib/motion/shotcraft/upstream/references/shots/outro/neon-triple-marquee.md +59 -59
  258. package/lib/motion/shotcraft/upstream/references/shots/outro/outro-group-photo-launch.md +39 -39
  259. package/lib/motion/shotcraft/upstream/references/shots/outro/ui-strip-away-outro.md +61 -61
  260. package/lib/motion/shotcraft/upstream/references/shots/outro/ui-to-brand-morph.md +52 -52
  261. package/lib/motion/shotcraft/upstream/references/shots/rhythm/beat-cut-moves.md +50 -50
  262. package/lib/motion/shotcraft/upstream/references/shots/rhythm/beat-step-list-theme-cycle.md +66 -66
  263. package/lib/motion/shotcraft/upstream/references/shots/rhythm/panel-grid-moves.md +43 -43
  264. package/lib/motion/shotcraft/upstream/references/shots/rhythm/quad-split-parallel-scenes.md +38 -38
  265. package/lib/motion/shotcraft/upstream/references/shots/rhythm/rhythm-interrupt-moves.md +38 -38
  266. package/lib/motion/shotcraft/upstream/references/shots/rhythm/sakuga-timing-shift.md +56 -56
  267. package/lib/motion/shotcraft/upstream/references/shots/rhythm/speed-ramp-freeze.md +44 -44
  268. package/lib/motion/shotcraft/upstream/references/shots/rhythm/trailer-grammar-moves.md +38 -38
  269. package/lib/motion/shotcraft/upstream/references/shots/transition/bottom-push-stack-wipe.md +63 -63
  270. package/lib/motion/shotcraft/upstream/references/shots/transition/card-flip-reveal.md +57 -57
  271. package/lib/motion/shotcraft/upstream/references/shots/transition/card-flock-tumble.md +63 -63
  272. package/lib/motion/shotcraft/upstream/references/shots/transition/circle-match-iris.md +58 -58
  273. package/lib/motion/shotcraft/upstream/references/shots/transition/gradient-transition.md +45 -45
  274. package/lib/motion/shotcraft/upstream/references/shots/transition/line-carry-transition.md +55 -55
  275. package/lib/motion/shotcraft/upstream/references/shots/transition/mosaic-reframe.md +49 -49
  276. package/lib/motion/shotcraft/upstream/references/shots/transition/page-turn-transitions.md +42 -42
  277. package/lib/motion/shotcraft/upstream/references/shots/transition/print-texture-transitions.md +42 -42
  278. package/lib/motion/shotcraft/upstream/references/shots/transition/shot-transitions.md +45 -45
  279. package/lib/motion/shotcraft/upstream/references/shots/transition/tear-streak-transitions.md +48 -48
  280. package/lib/motion/shotcraft/upstream/references/shots/transition/transition-hidden-cut.md +55 -55
  281. package/lib/motion/shotcraft/upstream/references/shots/transition/transition-travel.md +43 -43
  282. package/lib/motion/shotcraft/upstream/references/shots/transition/white-flash-logo-simplify-cut.md +41 -41
  283. package/lib/motion/shotcraft/upstream/references/shots/transition/wipe-transitions.md +42 -42
  284. package/lib/motion/shotcraft/upstream/references/shots/typography/blur-slide.md +59 -59
  285. package/lib/motion/shotcraft/upstream/references/shots/typography/brace-expand.md +55 -55
  286. package/lib/motion/shotcraft/upstream/references/shots/typography/countdown-arc-scatter.md +65 -65
  287. package/lib/motion/shotcraft/upstream/references/shots/typography/document-typewriter-reveal.md +42 -42
  288. package/lib/motion/shotcraft/upstream/references/shots/typography/flying-words.md +64 -64
  289. package/lib/motion/shotcraft/upstream/references/shots/typography/glitch-cycle.md +64 -64
  290. package/lib/motion/shotcraft/upstream/references/shots/typography/gradient-word-sweep.md +54 -54
  291. package/lib/motion/shotcraft/upstream/references/shots/typography/lead-word-zoom-assemble.md +91 -91
  292. package/lib/motion/shotcraft/upstream/references/shots/typography/marker-underline-title.md +51 -51
  293. package/lib/motion/shotcraft/upstream/references/shots/typography/outline-word-fill.md +66 -66
  294. package/lib/motion/shotcraft/upstream/references/shots/typography/paper-title-card.md +38 -38
  295. package/lib/motion/shotcraft/upstream/references/shots/typography/pill-chip-slot-cycle-handled.md +66 -66
  296. package/lib/motion/shotcraft/upstream/references/shots/typography/pill-slot-cycle.md +58 -58
  297. package/lib/motion/shotcraft/upstream/references/shots/typography/text-column-converge.md +61 -61
  298. package/lib/motion/shotcraft/upstream/references/shots/typography/title-demote-to-label.md +64 -64
  299. package/lib/motion/shotcraft/upstream/references/shots/typography/type-assembly-moves.md +45 -45
  300. package/lib/motion/shotcraft/upstream/references/shots/typography/type-entrance-moves.md +41 -41
  301. package/lib/motion/shotcraft/upstream/references/shots/typography/type-rhythm-sync.md +51 -51
  302. package/lib/motion/shotcraft/upstream/references/shots/typography/typewriter-moves.md +42 -42
  303. package/lib/motion/shotcraft/upstream/references/shots/typography/vertical-word-roll-blur-cycle.md +63 -63
  304. package/lib/motion/shotcraft/upstream/references/shots/typography/word-relay-filmstrip.md +57 -57
  305. package/lib/motion/shotcraft/upstream/references/shots/typography/word-relay-geometry.md +75 -75
  306. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/avatar-bracket-carousel.md +59 -59
  307. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/bezier-source-converge-merge.md +67 -67
  308. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/card-stack.md +60 -60
  309. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/carousel-3d.md +66 -66
  310. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/cloner-depth-echo.md +40 -40
  311. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/deck-deal-flyin.md +45 -45
  312. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/doc-park-left-pill-deal.md +62 -62
  313. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/draw-svg-trace.md +55 -55
  314. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/element-body-moves.md +37 -37
  315. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/integration-hub-map.md +55 -55
  316. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/list-reveal.md +50 -50
  317. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/list-stack-press.md +43 -43
  318. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/neon-frame-forerun.md +55 -55
  319. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/neon-frame-orbit-drop.md +51 -51
  320. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/page-waterfall-wall.md +51 -51
  321. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/product-card-progressive-assemble.md +56 -56
  322. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/radial-wave.md +49 -49
  323. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/research-card-stack-scroll.md +57 -57
  324. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/row-embed.md +36 -36
  325. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/value-stagger-gradient.md +64 -64
  326. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/wall-reveal-moves.md +47 -47
  327. package/lib/motion/shotcraft/upstream/references/sound-design.md +170 -170
  328. package/lib/motion/shotcraft/upstream/references/workbench.md +157 -157
  329. package/lib/motion/shotcraft/upstream/template/TEMPLATE.md +103 -103
  330. package/lib/motion/shotcraft/upstream/template/THEMES.md +44 -44
  331. package/lib/motion/shotcraft/upstream/template/package.json +20 -20
  332. package/lib/motion/shotcraft/upstream/template/remotion.config.ts +6 -6
  333. package/lib/motion/shotcraft/upstream/template/src/Root.tsx +17 -17
  334. package/lib/motion/shotcraft/upstream/template/src/aifl/Caption.tsx +65 -65
  335. package/lib/motion/shotcraft/upstream/template/src/aifl/DigitRoll.tsx +48 -48
  336. package/lib/motion/shotcraft/upstream/template/src/aifl/FlashCut.tsx +24 -24
  337. package/lib/motion/shotcraft/upstream/template/src/aifl/Main.tsx +192 -192
  338. package/lib/motion/shotcraft/upstream/template/src/aifl/PaperTitleCard.tsx +111 -111
  339. package/lib/motion/shotcraft/upstream/template/src/aifl/live/PageCam.tsx +150 -150
  340. package/lib/motion/shotcraft/upstream/template/src/aifl/live/SceneDetail.tsx +158 -158
  341. package/lib/motion/shotcraft/upstream/template/src/aifl/live/SceneFlyIn.tsx +468 -468
  342. package/lib/motion/shotcraft/upstream/template/src/aifl/live/SceneOpen.tsx +552 -552
  343. package/lib/motion/shotcraft/upstream/template/src/aifl/live/SceneOutroLive.tsx +411 -411
  344. package/lib/motion/shotcraft/upstream/template/src/aifl/live/ScenePapers.tsx +200 -200
  345. package/lib/motion/shotcraft/upstream/template/src/aifl/live/SceneWbr.tsx +324 -324
  346. package/lib/motion/shotcraft/upstream/template/src/aifl/live-layout.json +388 -388
  347. package/lib/motion/shotcraft/upstream/template/src/index.ts +4 -4
  348. package/lib/motion/shotcraft/upstream/template/src/themes/ThemedFilm.tsx +7 -7
  349. package/lib/motion/shotcraft/upstream/template/src/themes/manifest.tsx +68 -68
  350. package/lib/motion/shotcraft/upstream/template/src/themes/palette-assets.json +1 -1
  351. package/lib/motion/shotcraft/upstream/template/src/themes/palette-assets.ts +24 -24
  352. package/lib/motion/shotcraft/upstream/template/src/themes/palettes.json +74 -74
  353. package/lib/motion/shotcraft/upstream/template/src/themes/visual-theme.tsx +91 -91
  354. package/lib/motion/shotcraft/upstream/template/src/workbench.ts +213 -213
  355. package/lib/motion/shotcraft/upstream/template/tsconfig.json +15 -15
  356. package/lib/motion/style-frames.js +306 -306
  357. package/lib/motion/sync.js +214 -214
  358. package/lib/motion-project.js +105 -105
  359. package/lib/motion-render-worker.js +174 -174
  360. package/lib/routing/router.js +222 -222
  361. package/lib/routing/vendor/README.md +96 -96
  362. package/lib/routing/vendor/libavoid-routing.js +753 -753
  363. package/lib/routing/vendor/libavoid.min.js +59 -59
  364. package/lib/video-trace-pool.js +128 -128
  365. package/package.json +1 -1
  366. package/LICENSE +0 -4175
@@ -1,106 +1,106 @@
1
1
  /* 由 tools/build.mjs 生成 —— 请勿直接编辑;改 src/ 下的源文件。 */
2
- import { existsSync, mkdirSync, writeFileSync, readFileSync, realpathSync } from 'node:fs'
3
- import { join, dirname, resolve, relative, isAbsolute } from 'node:path'
4
- import { fileURLToPath } from 'node:url'
5
- import { videoRuntimeRequire } from './motion/video-runtime.js'
6
- import { validateMotionSources, sceneComponentPath } from './motion-source.js'
7
- import { shotcraftModuleMap } from './motion-library.js'
8
- import { enforceMotionCards } from './motion-library.js'
9
- import { enforceMgStyle } from './motion-library.js'
10
- import { validateMotionPlan } from './motion-core.js'
11
- import { parseProjectJson } from './motion/json.js'
12
-
13
- // Agent projects are edited on disk. Read their sources before validating or
14
- // building; never restore a stale inline source over an agent's changes.
15
- export function readMotionProject(directory, input) {
16
- const root=realpathSync(directory)
17
- const read=(name)=>{
18
- const file=realpathSync(join(root,name)),rel=relative(root,file)
19
- if(isAbsolute(rel)||rel==='..'||/^\.\.[\\/]/.test(rel))throw new Error('工程文件超出任务目录')
20
- return readFileSync(file,'utf8')
21
- }
22
- const raw=parseProjectJson(read('composition.json'))
23
- if(!Array.isArray(raw.shots))throw new Error('工程缺少 shots 分镜')
24
- raw.shots=raw.shots.map((shot,index)=>({...shot,sceneSource:read('scene-'+index+'.tsx'),
25
- ...(shot.sceneComponents?{sceneComponents:shot.sceneComponents.map(c=>({...c,source:read(sceneComponentPath('shot-'+(index+1),c.id))}))}:{})}))
26
- return enforceMgStyle(enforceMotionCards(validateMotionSources(validateMotionPlan(raw,input)),input),input)
27
- }
28
-
29
- // 入口与运行时 JSX 的源文件在插件里,但它们**必须被复制到工程目录**再引用:
30
- // Remotion 的 webpack 只给 .tsx?/.ts 挂 esbuild-loader,配 .jsx? 的那条规则显式
31
- // exclude /node_modules/ —— 插件装在 profile 的 node_modules 下时,入口 JSX 会被当成
32
- // 普通文本解析,报 "Unexpected token (<AbsoluteFill>)"(issue #21、#22)。
33
- const RUNTIME_ENTRY = fileURLToPath(new URL('./motion/entry.jsx', import.meta.url))
34
- const RUNTIME_REFERENCE = fileURLToPath(new URL('./motion/reference-media.jsx', import.meta.url))
35
- const GENERATED_HEADER = '// 由 dsh-drawai 生成,请勿手改;插件更新后会按源文件重新生成。\n'
36
-
37
- // 只在内容变化时写盘:保持 mtime 稳定,bundle 缓存才不会每次重建。
38
- function writeGenerated(file, source) {
39
- const desired = GENERATED_HEADER + source
40
- if (existsSync(file) && readFileSync(file, 'utf8') === desired) return
41
- mkdirSync(dirname(file), { recursive: true })
42
- writeFileSync(file, desired)
43
- }
44
-
45
- export function prepareMotionProject(composition, directory, options = {}) {
46
- validateMotionSources(composition)
47
- mkdirSync(directory, { recursive: true })
48
- const imports = [], entries = []
49
- composition.shots.forEach((shot, index) => {
50
- if (shot.recipeId !== 'scene') return
51
- const name = 'scene-' + index + '.tsx'
52
- if(!options.preserveSources)writeFileSync(join(directory, name), shot.sceneSource)
53
- for (const component of shot.sceneComponents || []) {
54
- const file = join(directory, sceneComponentPath(shot.id, component.id))
55
- mkdirSync(dirname(file), { recursive: true })
56
- if(!options.preserveSources)writeFileSync(file, component.source)
57
- }
58
- imports.push(`import Scene${index} from './${name}';`)
59
- entries.push(`${JSON.stringify(shot.id)}:Scene${index}`)
60
- })
61
- writeGenerated(join(directory, 'entry.gen.jsx'), readFileSync(RUNTIME_ENTRY, 'utf8'))
62
- writeGenerated(join(directory, 'reference-media.gen.jsx'), readFileSync(RUNTIME_REFERENCE, 'utf8'))
63
- const entryPoint = join(directory, 'index.jsx')
64
- const entrySource = `import {registerMotionRoot} from './entry.gen.jsx';\n${imports.join('\n')}\nregisterMotionRoot({${entries.join(',')}});\n`
65
- // 入口本身就是生成的:内容变了(换插件路径、增删镜头)就重写,不看 preserveSources。
66
- if(!existsSync(entryPoint) || readFileSync(entryPoint, 'utf8') !== entrySource)writeFileSync(entryPoint, entrySource)
67
- if(!options.preserveSources)writeFileSync(join(directory, 'composition.json'), JSON.stringify(composition, null, 2))
68
- if (composition.production && !options.preserveSources) {
69
- writeFileSync(join(directory, 'design.json'), JSON.stringify(composition.production, null, 2))
70
- writeFileSync(join(directory, 'storyboard.json'), JSON.stringify(composition.shots.map(({ sceneSource: _source, sceneComponents, ...shot }) => ({ ...shot,
71
- ...(sceneComponents ? { components: sceneComponents.map(({ source: _code, ...component }) => component) } : {}) })), null, 2))
72
- }
73
- const alias = Object.fromEntries(Object.entries(shotcraftModuleMap()).map(([name, url]) => [name + '$', fileURLToPath(url)]))
74
- // Demos use paths relative to the upstream repository. Generated components
75
- // live elsewhere: resolve known library paths without rewriting their source.
76
- const library = shotcraftModuleMap()
77
- const libraryImports = { apply(compiler) {
78
- compiler.hooks.normalModuleFactory.tap('DrawAiShotcraftImports', (factory) => {
79
- factory.hooks.beforeResolve.tap('DrawAiShotcraftImports', (request) => {
80
- if (!request?.request?.startsWith('.')) return
81
- const local = relative(resolve(directory), resolve(request.context))
82
- if (isAbsolute(local) || local === '..' || /^\.\.[\\/]/.test(local)) return
83
- const stem = resolve(request.context, request.request)
84
- if (['', '.tsx', '.ts', '.jsx', '.js', '/index.tsx', '/index.ts', '/index.js'].some((ext) => existsSync(stem + ext))) return
85
- const path = request.request.replaceAll('\\', '/').replace(/^(?:\.\.?\/)+/, '').replace(/\.(tsx?|jsx?)$/, '')
86
- const name = path.startsWith('demos/') ? '@shotcraft/' + path
87
- : path.startsWith('_fixtures/') ? '@shotcraft/demos/' + path
88
- : path.startsWith('assets/lib/') ? '@shotcraft/lib/' + path.slice('assets/lib/'.length)
89
- : path.startsWith('lib/') ? '@shotcraft/' + path : ''
90
- if (Object.hasOwn(library, name)) request.request = fileURLToPath(library[name])
91
- })
92
- })
93
- } }
94
- alias['@drawai/motion$'] = join(directory, 'reference-media.gen.jsx')
95
- // Resolve the runtime lazily: creating a project only writes its files, and
96
- // the video runtime may not be initialized yet (it is installed on first use).
97
- const runtimeModules = () => {
98
- const require = videoRuntimeRequire(options.runtimeDirectory)
99
- return [...new Set(['react', 'remotion', '@remotion/motion-blur'].map((name) => dirname(require.resolve(name + '/package.json')).replace(/[\\/]@remotion[\\/][^\\/]+$/, '').replace(/[\\/](?:react|remotion)$/, '')))]
100
- }
101
- return { entryPoint, webpackOverride: (config) => {
102
- const modules = runtimeModules()
103
- return { ...config, plugins: [...(config.plugins || []), libraryImports], resolve: { ...config.resolve,
104
- alias: { ...config.resolve?.alias, ...alias }, modules: [...modules, ...(config.resolve?.modules || ['node_modules'])] } }
105
- } }
106
- }
2
+ import { existsSync, mkdirSync, writeFileSync, readFileSync, realpathSync } from 'node:fs'
3
+ import { join, dirname, resolve, relative, isAbsolute } from 'node:path'
4
+ import { fileURLToPath } from 'node:url'
5
+ import { videoRuntimeRequire } from './motion/video-runtime.js'
6
+ import { validateMotionSources, sceneComponentPath } from './motion-source.js'
7
+ import { shotcraftModuleMap } from './motion-library.js'
8
+ import { enforceMotionCards } from './motion-library.js'
9
+ import { enforceMgStyle } from './motion-library.js'
10
+ import { validateMotionPlan } from './motion-core.js'
11
+ import { parseProjectJson } from './motion/json.js'
12
+
13
+ // Agent projects are edited on disk. Read their sources before validating or
14
+ // building; never restore a stale inline source over an agent's changes.
15
+ export function readMotionProject(directory, input) {
16
+ const root=realpathSync(directory)
17
+ const read=(name)=>{
18
+ const file=realpathSync(join(root,name)),rel=relative(root,file)
19
+ if(isAbsolute(rel)||rel==='..'||/^\.\.[\\/]/.test(rel))throw new Error('工程文件超出任务目录')
20
+ return readFileSync(file,'utf8')
21
+ }
22
+ const raw=parseProjectJson(read('composition.json'))
23
+ if(!Array.isArray(raw.shots))throw new Error('工程缺少 shots 分镜')
24
+ raw.shots=raw.shots.map((shot,index)=>({...shot,sceneSource:read('scene-'+index+'.tsx'),
25
+ ...(shot.sceneComponents?{sceneComponents:shot.sceneComponents.map(c=>({...c,source:read(sceneComponentPath('shot-'+(index+1),c.id))}))}:{})}))
26
+ return enforceMgStyle(enforceMotionCards(validateMotionSources(validateMotionPlan(raw,input)),input),input)
27
+ }
28
+
29
+ // 入口与运行时 JSX 的源文件在插件里,但它们**必须被复制到工程目录**再引用:
30
+ // Remotion 的 webpack 只给 .tsx?/.ts 挂 esbuild-loader,配 .jsx? 的那条规则显式
31
+ // exclude /node_modules/ —— 插件装在 profile 的 node_modules 下时,入口 JSX 会被当成
32
+ // 普通文本解析,报 "Unexpected token (<AbsoluteFill>)"(issue #21、#22)。
33
+ const RUNTIME_ENTRY = fileURLToPath(new URL('./motion/entry.jsx', import.meta.url))
34
+ const RUNTIME_REFERENCE = fileURLToPath(new URL('./motion/reference-media.jsx', import.meta.url))
35
+ const GENERATED_HEADER = '// 由 dsh-drawai 生成,请勿手改;插件更新后会按源文件重新生成。\n'
36
+
37
+ // 只在内容变化时写盘:保持 mtime 稳定,bundle 缓存才不会每次重建。
38
+ function writeGenerated(file, source) {
39
+ const desired = GENERATED_HEADER + source
40
+ if (existsSync(file) && readFileSync(file, 'utf8') === desired) return
41
+ mkdirSync(dirname(file), { recursive: true })
42
+ writeFileSync(file, desired)
43
+ }
44
+
45
+ export function prepareMotionProject(composition, directory, options = {}) {
46
+ validateMotionSources(composition)
47
+ mkdirSync(directory, { recursive: true })
48
+ const imports = [], entries = []
49
+ composition.shots.forEach((shot, index) => {
50
+ if (shot.recipeId !== 'scene') return
51
+ const name = 'scene-' + index + '.tsx'
52
+ if(!options.preserveSources)writeFileSync(join(directory, name), shot.sceneSource)
53
+ for (const component of shot.sceneComponents || []) {
54
+ const file = join(directory, sceneComponentPath(shot.id, component.id))
55
+ mkdirSync(dirname(file), { recursive: true })
56
+ if(!options.preserveSources)writeFileSync(file, component.source)
57
+ }
58
+ imports.push(`import Scene${index} from './${name}';`)
59
+ entries.push(`${JSON.stringify(shot.id)}:Scene${index}`)
60
+ })
61
+ writeGenerated(join(directory, 'entry.gen.jsx'), readFileSync(RUNTIME_ENTRY, 'utf8'))
62
+ writeGenerated(join(directory, 'reference-media.gen.jsx'), readFileSync(RUNTIME_REFERENCE, 'utf8'))
63
+ const entryPoint = join(directory, 'index.jsx')
64
+ const entrySource = `import {registerMotionRoot} from './entry.gen.jsx';\n${imports.join('\n')}\nregisterMotionRoot({${entries.join(',')}});\n`
65
+ // 入口本身就是生成的:内容变了(换插件路径、增删镜头)就重写,不看 preserveSources。
66
+ if(!existsSync(entryPoint) || readFileSync(entryPoint, 'utf8') !== entrySource)writeFileSync(entryPoint, entrySource)
67
+ if(!options.preserveSources)writeFileSync(join(directory, 'composition.json'), JSON.stringify(composition, null, 2))
68
+ if (composition.production && !options.preserveSources) {
69
+ writeFileSync(join(directory, 'design.json'), JSON.stringify(composition.production, null, 2))
70
+ writeFileSync(join(directory, 'storyboard.json'), JSON.stringify(composition.shots.map(({ sceneSource: _source, sceneComponents, ...shot }) => ({ ...shot,
71
+ ...(sceneComponents ? { components: sceneComponents.map(({ source: _code, ...component }) => component) } : {}) })), null, 2))
72
+ }
73
+ const alias = Object.fromEntries(Object.entries(shotcraftModuleMap()).map(([name, url]) => [name + '$', fileURLToPath(url)]))
74
+ // Demos use paths relative to the upstream repository. Generated components
75
+ // live elsewhere: resolve known library paths without rewriting their source.
76
+ const library = shotcraftModuleMap()
77
+ const libraryImports = { apply(compiler) {
78
+ compiler.hooks.normalModuleFactory.tap('DrawAiShotcraftImports', (factory) => {
79
+ factory.hooks.beforeResolve.tap('DrawAiShotcraftImports', (request) => {
80
+ if (!request?.request?.startsWith('.')) return
81
+ const local = relative(resolve(directory), resolve(request.context))
82
+ if (isAbsolute(local) || local === '..' || /^\.\.[\\/]/.test(local)) return
83
+ const stem = resolve(request.context, request.request)
84
+ if (['', '.tsx', '.ts', '.jsx', '.js', '/index.tsx', '/index.ts', '/index.js'].some((ext) => existsSync(stem + ext))) return
85
+ const path = request.request.replaceAll('\\', '/').replace(/^(?:\.\.?\/)+/, '').replace(/\.(tsx?|jsx?)$/, '')
86
+ const name = path.startsWith('demos/') ? '@shotcraft/' + path
87
+ : path.startsWith('_fixtures/') ? '@shotcraft/demos/' + path
88
+ : path.startsWith('assets/lib/') ? '@shotcraft/lib/' + path.slice('assets/lib/'.length)
89
+ : path.startsWith('lib/') ? '@shotcraft/' + path : ''
90
+ if (Object.hasOwn(library, name)) request.request = fileURLToPath(library[name])
91
+ })
92
+ })
93
+ } }
94
+ alias['@drawai/motion$'] = join(directory, 'reference-media.gen.jsx')
95
+ // Resolve the runtime lazily: creating a project only writes its files, and
96
+ // the video runtime may not be initialized yet (it is installed on first use).
97
+ const runtimeModules = () => {
98
+ const require = videoRuntimeRequire(options.runtimeDirectory)
99
+ return [...new Set(['react', 'remotion', '@remotion/motion-blur'].map((name) => dirname(require.resolve(name + '/package.json')).replace(/[\\/]@remotion[\\/][^\\/]+$/, '').replace(/[\\/](?:react|remotion)$/, '')))]
100
+ }
101
+ return { entryPoint, webpackOverride: (config) => {
102
+ const modules = runtimeModules()
103
+ return { ...config, plugins: [...(config.plugins || []), libraryImports], resolve: { ...config.resolve,
104
+ alias: { ...config.resolve?.alias, ...alias }, modules: [...modules, ...(config.resolve?.modules || ['node_modules'])] } }
105
+ } }
106
+ }
@@ -1,175 +1,175 @@
1
1
  /* 由 tools/build.mjs 生成 —— 请勿直接编辑;改 src/ 下的源文件。 */
2
- import { ensureVideoRuntime, videoRuntimeRequire } from './motion/video-runtime.js'
3
- import { existsSync, rmSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'
4
- import { dirname, join, relative, isAbsolute, resolve } from 'node:path'
5
- import { createHash } from 'node:crypto'
6
- import { prepareMotionProject } from './motion-project.js'
7
- import { runFfmpeg } from './motion/ffmpeg.js'
8
-
9
- let cancelled = false, running = false
10
- const runtimeAbort = new AbortController()
11
- let cancel = () => {}
12
- const send = (message) => { if (process.connected) process.send(message) }
13
- process.on('message', async (request) => {
14
- if (request.type === 'cancel') { cancelled = true; runtimeAbort.abort(new Error('已取消动效生成')); cancel(); return }
15
- if (running) return
16
- running = true
17
- let browser
18
- const outDir = request.bundleDir || join(dirname(request.output), 'bundle')
19
- const cacheFile = join(outDir, '.drawai-bundle-key')
20
- try {
21
- const runtimeDirectory = await ensureVideoRuntime({signal:runtimeAbort.signal, onProgress:message => send({type:'progress', ...message, progress:0})})
22
- if (cancelled) throw new Error('已取消动效生成')
23
- const require = videoRuntimeRequire(runtimeDirectory)
24
- const { bundle } = require('@remotion/bundler')
25
- const { openBrowser, selectComposition, renderMedia, renderStill, makeCancelSignal } = require('@remotion/renderer')
26
- const cancellation = makeCancelSignal()
27
- const cancelSignal = cancellation.cancelSignal
28
- cancel = cancellation.cancel
29
- // 同一个工程连续预览/渲染时复用上次的 bundle:预览从 30 秒降到 3 秒,
30
- // 改一个场景文件只会让 key 变化一次。request.bundleKey 由调用方按源码计算。
31
- const reuse = request.reuseBundle === true && request.bundleKey && existsSync(join(outDir, 'index.html'))
32
- && existsSync(cacheFile) && readFileSync(cacheFile, 'utf8').trim() === request.bundleKey
33
- let serveUrl
34
- if (reuse) {
35
- serveUrl = outDir
36
- send({ type: 'progress', phase: 'bundling', progress: .1 })
37
- } else {
38
- const project = prepareMotionProject(request.composition, request.projectDirectory || join(dirname(request.output), 'project'), {preserveSources:request.preserveSources===true, runtimeDirectory})
39
- serveUrl = await bundle({ ...project, outDir, ignoreRegisterRootWarning: true,
40
- publicDir: request.publicDir, onProgress: (progress) => send({ type: 'progress', phase: 'bundling', progress: progress / 100 * .1 }) })
41
- const index = join(outDir, 'index.html')
42
- writeFileSync(index, readFileSync(index, 'utf8').replace('<head>', '<head><meta http-equiv="Content-Security-Policy" content="default-src \'self\' blob: data:; script-src \'self\' \'unsafe-inline\' \'unsafe-eval\'; style-src \'self\' \'unsafe-inline\'; connect-src \'self\'; img-src \'self\' blob: data:; media-src \'self\' blob:; frame-src \'none\'; object-src \'none\'">'))
43
- if (request.bundleKey) writeFileSync(cacheFile, request.bundleKey)
44
- }
45
- if (cancelled) throw new Error('已取消动效生成')
46
- // Use a configured browser, or a local browser before downloading Chromium.
47
- // 参数名必须是 puppeteerInstance:@remotion/renderer 4.x 只认这个名字,
48
- // 写成 browserInstance 会被静默忽略,然后它自己去下载 chrome-headless-shell(内网/无外网必炸)。
49
- // 同时把 browserExecutable 一并传下去:万一实例没用上,也还有本机浏览器可退回,不去联网。
50
- const candidates = [
51
- request.browserExecutable, process.env.DRAWAI_CHROME_PATH,
52
- // Windows
53
- 'C:/Program Files/Google/Chrome/Application/chrome.exe', 'C:/Program Files (x86)/Microsoft/Edge/Application/msedge.exe',
54
- // macOS(插件装在 Mac 上时,浏览器不在 PATH 里,也不在 Windows 的默认位置)
55
- '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',
56
- '/Applications/Chromium.app/Contents/MacOS/Chromium',
57
- '/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge',
58
- // Linux
59
- '/usr/bin/google-chrome', '/usr/bin/chromium', '/usr/bin/chromium-browser', '/usr/bin/microsoft-edge',
60
- ]
61
- const browserExecutable = candidates.find((path) => path && existsSync(path))
62
- if (!browserExecutable) {
63
- // 没有本机浏览器时 Remotion 会去下载 chrome-headless-shell:内网/无外网会卡很久。
64
- // 先把这件事说出来,别让它看起来像"卡死"(issue #22)。
65
- send({ type: 'progress', phase: 'browser', progress: 0, message: '没找到本机 Chrome / Edge,正在下载内置浏览器;首次会慢一些' })
66
- }
67
- browser = await openBrowser('chrome', { browserExecutable, logLevel: 'error' }).catch((error) => {
68
- const detail = error?.message || String(error)
69
- throw new Error(browserExecutable
70
- ? `打开本机浏览器失败(${browserExecutable}):${detail}`
71
- : `未找到本机 Chrome / Edge,下载 chrome-headless-shell 也失败:${detail}。请安装 Chrome,或用 DRAWAI_CHROME_PATH 指定浏览器路径。`)
72
- })
73
- if (cancelled) throw new Error('已取消动效生成')
74
- const inputProps = { plan: request.composition, assets: request.assets }
75
- const composition = await selectComposition({ serveUrl, id: 'DrawAiMotion', inputProps, puppeteerInstance: browser, browserExecutable })
76
- if(request.operation==='compile'){send({type:'done',compiled:true});return}
77
- send({ type: 'progress', phase: 'reviewing', progress: .1 })
78
- const qaDirectory = request.qaDirectory || join(dirname(request.output), 'qa'); mkdirSync(qaDirectory, { recursive: true })
79
- const audioCues = Array.isArray(request.composition?.audio) ? request.composition.audio : []
80
- const qa = { status: 'render-checks-passed', visualReview: 'manual-required', audio: audioCues.length ? 'mixed:' + audioCues.length : 'silent', frames: [], warnings: [] }
81
- if(request.operation==='still'){
82
- const frames=[]
83
- for(const frame of request.frames){
84
- if(!Number.isInteger(frame)||frame<0||frame>=composition.durationInFrames)throw new Error('截图帧超出成片')
85
- const filename='agent-frame-'+frame+'.png'
86
- await renderStill({serveUrl,composition,inputProps,output:join(qaDirectory,filename),frame,puppeteerInstance:browser,browserExecutable,cancelSignal,logLevel:'error'})
87
- frames.push({frame,filename,sha256:createHash('sha256').update(readFileSync(join(qaDirectory,filename))).digest('hex')})
88
- }
89
- send({type:'done',frames});return
90
- }
91
- for (const shot of request.composition.shots) {
92
- const hashes = []
93
- for (const fraction of (shot.motionCards?.length ? [0, .25, .5, .75, .98] : [.25, .7])) {
94
- const frame = shot.startFrame + Math.min(shot.durationFrames - 1, Math.floor(shot.durationFrames * fraction))
95
- const filename = shot.id + '-' + frame + '.png'
96
- await renderStill({ serveUrl, composition, inputProps, output: join(qaDirectory, filename), frame, puppeteerInstance: browser, browserExecutable, cancelSignal, logLevel: 'error', timeoutInMilliseconds: 30000 })
97
- const bytes = readFileSync(join(qaDirectory, filename))
98
- const hash = createHash('sha256').update(bytes).digest('hex'); hashes.push(hash)
99
- qa.frames.push({ shotId: shot.id, frame, filename, fraction, sha256: hash })
100
- }
101
- if (hashes[0] === hashes[1]) qa.warnings.push(shot.id + ': 两张采样帧相同,请检查主运动或停留段')
102
- }
103
- // 渲染规格随请求进来(由 render.js 的 resolveRenderSettings 解析过):
104
- // 编码参数、色彩标签、超采样倍数、并发都在这里唯一地落到 renderMedia 上。
105
- const settings = request.render || {}
106
- qa.render = settings
107
- writeFileSync(join(qaDirectory, 'report.json'), JSON.stringify(qa, null, 2))
108
- const scale = Number(settings.scale) > 1 ? Math.round(Number(settings.scale)) : 1
109
- const finalOutput = request.output
110
- // 超采样:Remotion 的 scale 是「渲成更大」,不会替你缩回来。
111
- // 所以大图先落到临时文件,再用一次 lanczos + bt709 的母版编码缩回目标尺寸。
112
- const rawOutput = scale > 1 ? join(dirname(finalOutput), '.supersample.mp4') : finalOutput
113
- const startedAt = Date.now()
114
- let seenFrames = 0
115
- const totalFrames = request.frameRange
116
- ? request.frameRange[1] - request.frameRange[0] + 1
117
- : composition.durationInFrames
118
- await renderMedia({ serveUrl, composition, inputProps, outputLocation: rawOutput,
119
- codec: settings.codec || 'h264',
120
- ...(settings.crf ? { crf: settings.crf } : {}),
121
- ...(settings.preset ? { x264Preset: settings.preset } : {}),
122
- ...(settings.pixelFormat ? { pixelFormat: settings.pixelFormat } : {}),
123
- ...(settings.colorSpace ? { colorSpace: settings.colorSpace } : {}),
124
- ...(settings.audioBitrate ? { audioBitrate: settings.audioBitrate } : {}),
125
- scale,
126
- concurrency: settings.concurrency || 2,
127
- ...(request.frameRange?{frameRange:request.frameRange}:{}),
128
- puppeteerInstance: browser, browserExecutable, cancelSignal, logLevel: 'error',
129
- onProgress: ({ progress, renderedFrames }) => {
130
- const done = Number(renderedFrames) || 0
131
- if (done > seenFrames) seenFrames = done
132
- const elapsed = (Date.now() - startedAt) / 1000
133
- const perFrame = seenFrames > 0 ? elapsed / seenFrames : null
134
- // 单帧耗时是「样本数该开多大」的唯一依据:没有它,超采样只能靠猜。
135
- send({ type: 'progress', phase: 'rendering', progress: .1 + progress * .85,
136
- frames: { done: seenFrames, total: totalFrames,
137
- perFrameSeconds: perFrame ? Math.round(perFrame * 1000) / 1000 : null,
138
- etaSeconds: perFrame ? Math.round(perFrame * Math.max(totalFrames - seenFrames, 0)) : null } })
139
- } })
140
- if (scale > 1) {
141
- send({ type: 'progress', phase: 'encoding', progress: .96 })
142
- // 这一趟本来就是重编码,顺手把 bt709 三标签补全。
143
- // 注意:这个 ffmpeg 构建里 -color_primaries / -color_trc 当**输出选项**不生效
144
- // (连续实测:只剩 colorspace 标签,primaries/trc 仍是 unknown),必须走 setparams 滤镜改帧元数据。
145
- const colorFilter = settings.colorSpace === 'bt709'
146
- ? ',setparams=color_primaries=bt709:color_trc=bt709:colorspace=bt709' : ''
147
- await runFfmpeg(['-i', rawOutput,
148
- '-vf', 'scale=' + composition.width + ':' + composition.height + ':flags=lanczos+accurate_rnd+full_chroma_int' + colorFilter,
149
- '-c:v', 'libx264', '-crf', String(settings.crf || 14), '-preset', String(settings.preset || 'slow'),
150
- '-profile:v', 'high', '-pix_fmt', 'yuv420p',
151
- '-colorspace', 'bt709', '-color_primaries', 'bt709', '-color_trc', 'bt709',
152
- '-c:a', 'copy', '-movflags', '+faststart', finalOutput],
153
- { cwd: dirname(finalOutput), log: join(dirname(finalOutput), 'encode.log'), timeoutMs: 900000 })
154
- rmSync(rawOutput, { force: true })
155
- qa.supersample = { from: composition.width * scale + 'x' + composition.height * scale, to: composition.width + 'x' + composition.height }
156
- qa.colorTags = settings.colorSpace === 'bt709' ? 'bt709(三标签齐全)' : '未标注'
157
- } else if (settings.colorSpace === 'bt709') {
158
- // Remotion 只写 colorspace,primaries/trc 留 unknown;要齐全只能再重编一次,
159
- // 而重编会让画质掉一代——所以 1× 下宁可把这件事说清楚,不偷偷多编一遍。
160
- qa.colorTags = '仅 colorspace=bt709(primaries/trc 为 unknown;母版级标签请设 render.scale=2)'
161
- qa.warnings.push('色彩标签只写了 colorspace:要 primaries/trc 齐全(严格 QC)请用 render.scale=2,那一趟重编码会一并补齐')
162
- }
163
- const posterShot = request.composition.shots.find((shot) => shot.referenceIds.length) || request.composition.shots[0]
164
- await renderStill({ serveUrl, composition, inputProps, output: request.poster,
165
- frame: posterShot.startFrame + Math.floor(posterShot.durationFrames / 2), puppeteerInstance: browser, browserExecutable, cancelSignal, logLevel: 'error' })
166
- writeFileSync(join(qaDirectory, 'report.json'), JSON.stringify(qa, null, 2))
167
- send({ type: 'done', qa })
168
- } catch (error) { send({ type: 'error', error: error.message || String(error) }); process.exitCode = 1 }
169
- finally {
170
- await browser?.close({ silent: true }).catch(() => {})
171
- const cleanup = relative(resolve(dirname(request.output)), resolve(outDir))
172
- if (request.keepBundle !== true && cleanup === 'bundle' && !isAbsolute(cleanup)) rmSync(outDir, { recursive: true, force: true })
173
- process.disconnect()
174
- }
175
- })
2
+ import { ensureVideoRuntime, videoRuntimeRequire } from './motion/video-runtime.js'
3
+ import { existsSync, rmSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'
4
+ import { dirname, join, relative, isAbsolute, resolve } from 'node:path'
5
+ import { createHash } from 'node:crypto'
6
+ import { prepareMotionProject } from './motion-project.js'
7
+ import { runFfmpeg } from './motion/ffmpeg.js'
8
+
9
+ let cancelled = false, running = false
10
+ const runtimeAbort = new AbortController()
11
+ let cancel = () => {}
12
+ const send = (message) => { if (process.connected) process.send(message) }
13
+ process.on('message', async (request) => {
14
+ if (request.type === 'cancel') { cancelled = true; runtimeAbort.abort(new Error('已取消动效生成')); cancel(); return }
15
+ if (running) return
16
+ running = true
17
+ let browser
18
+ const outDir = request.bundleDir || join(dirname(request.output), 'bundle')
19
+ const cacheFile = join(outDir, '.drawai-bundle-key')
20
+ try {
21
+ const runtimeDirectory = await ensureVideoRuntime({signal:runtimeAbort.signal, onProgress:message => send({type:'progress', ...message, progress:0})})
22
+ if (cancelled) throw new Error('已取消动效生成')
23
+ const require = videoRuntimeRequire(runtimeDirectory)
24
+ const { bundle } = require('@remotion/bundler')
25
+ const { openBrowser, selectComposition, renderMedia, renderStill, makeCancelSignal } = require('@remotion/renderer')
26
+ const cancellation = makeCancelSignal()
27
+ const cancelSignal = cancellation.cancelSignal
28
+ cancel = cancellation.cancel
29
+ // 同一个工程连续预览/渲染时复用上次的 bundle:预览从 30 秒降到 3 秒,
30
+ // 改一个场景文件只会让 key 变化一次。request.bundleKey 由调用方按源码计算。
31
+ const reuse = request.reuseBundle === true && request.bundleKey && existsSync(join(outDir, 'index.html'))
32
+ && existsSync(cacheFile) && readFileSync(cacheFile, 'utf8').trim() === request.bundleKey
33
+ let serveUrl
34
+ if (reuse) {
35
+ serveUrl = outDir
36
+ send({ type: 'progress', phase: 'bundling', progress: .1 })
37
+ } else {
38
+ const project = prepareMotionProject(request.composition, request.projectDirectory || join(dirname(request.output), 'project'), {preserveSources:request.preserveSources===true, runtimeDirectory})
39
+ serveUrl = await bundle({ ...project, outDir, ignoreRegisterRootWarning: true,
40
+ publicDir: request.publicDir, onProgress: (progress) => send({ type: 'progress', phase: 'bundling', progress: progress / 100 * .1 }) })
41
+ const index = join(outDir, 'index.html')
42
+ writeFileSync(index, readFileSync(index, 'utf8').replace('<head>', '<head><meta http-equiv="Content-Security-Policy" content="default-src \'self\' blob: data:; script-src \'self\' \'unsafe-inline\' \'unsafe-eval\'; style-src \'self\' \'unsafe-inline\'; connect-src \'self\'; img-src \'self\' blob: data:; media-src \'self\' blob:; frame-src \'none\'; object-src \'none\'">'))
43
+ if (request.bundleKey) writeFileSync(cacheFile, request.bundleKey)
44
+ }
45
+ if (cancelled) throw new Error('已取消动效生成')
46
+ // Use a configured browser, or a local browser before downloading Chromium.
47
+ // 参数名必须是 puppeteerInstance:@remotion/renderer 4.x 只认这个名字,
48
+ // 写成 browserInstance 会被静默忽略,然后它自己去下载 chrome-headless-shell(内网/无外网必炸)。
49
+ // 同时把 browserExecutable 一并传下去:万一实例没用上,也还有本机浏览器可退回,不去联网。
50
+ const candidates = [
51
+ request.browserExecutable, process.env.DRAWAI_CHROME_PATH,
52
+ // Windows
53
+ 'C:/Program Files/Google/Chrome/Application/chrome.exe', 'C:/Program Files (x86)/Microsoft/Edge/Application/msedge.exe',
54
+ // macOS(插件装在 Mac 上时,浏览器不在 PATH 里,也不在 Windows 的默认位置)
55
+ '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',
56
+ '/Applications/Chromium.app/Contents/MacOS/Chromium',
57
+ '/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge',
58
+ // Linux
59
+ '/usr/bin/google-chrome', '/usr/bin/chromium', '/usr/bin/chromium-browser', '/usr/bin/microsoft-edge',
60
+ ]
61
+ const browserExecutable = candidates.find((path) => path && existsSync(path))
62
+ if (!browserExecutable) {
63
+ // 没有本机浏览器时 Remotion 会去下载 chrome-headless-shell:内网/无外网会卡很久。
64
+ // 先把这件事说出来,别让它看起来像"卡死"(issue #22)。
65
+ send({ type: 'progress', phase: 'browser', progress: 0, message: '没找到本机 Chrome / Edge,正在下载内置浏览器;首次会慢一些' })
66
+ }
67
+ browser = await openBrowser('chrome', { browserExecutable, logLevel: 'error' }).catch((error) => {
68
+ const detail = error?.message || String(error)
69
+ throw new Error(browserExecutable
70
+ ? `打开本机浏览器失败(${browserExecutable}):${detail}`
71
+ : `未找到本机 Chrome / Edge,下载 chrome-headless-shell 也失败:${detail}。请安装 Chrome,或用 DRAWAI_CHROME_PATH 指定浏览器路径。`)
72
+ })
73
+ if (cancelled) throw new Error('已取消动效生成')
74
+ const inputProps = { plan: request.composition, assets: request.assets }
75
+ const composition = await selectComposition({ serveUrl, id: 'DrawAiMotion', inputProps, puppeteerInstance: browser, browserExecutable })
76
+ if(request.operation==='compile'){send({type:'done',compiled:true});return}
77
+ send({ type: 'progress', phase: 'reviewing', progress: .1 })
78
+ const qaDirectory = request.qaDirectory || join(dirname(request.output), 'qa'); mkdirSync(qaDirectory, { recursive: true })
79
+ const audioCues = Array.isArray(request.composition?.audio) ? request.composition.audio : []
80
+ const qa = { status: 'render-checks-passed', visualReview: 'manual-required', audio: audioCues.length ? 'mixed:' + audioCues.length : 'silent', frames: [], warnings: [] }
81
+ if(request.operation==='still'){
82
+ const frames=[]
83
+ for(const frame of request.frames){
84
+ if(!Number.isInteger(frame)||frame<0||frame>=composition.durationInFrames)throw new Error('截图帧超出成片')
85
+ const filename='agent-frame-'+frame+'.png'
86
+ await renderStill({serveUrl,composition,inputProps,output:join(qaDirectory,filename),frame,puppeteerInstance:browser,browserExecutable,cancelSignal,logLevel:'error'})
87
+ frames.push({frame,filename,sha256:createHash('sha256').update(readFileSync(join(qaDirectory,filename))).digest('hex')})
88
+ }
89
+ send({type:'done',frames});return
90
+ }
91
+ for (const shot of request.composition.shots) {
92
+ const hashes = []
93
+ for (const fraction of (shot.motionCards?.length ? [0, .25, .5, .75, .98] : [.25, .7])) {
94
+ const frame = shot.startFrame + Math.min(shot.durationFrames - 1, Math.floor(shot.durationFrames * fraction))
95
+ const filename = shot.id + '-' + frame + '.png'
96
+ await renderStill({ serveUrl, composition, inputProps, output: join(qaDirectory, filename), frame, puppeteerInstance: browser, browserExecutable, cancelSignal, logLevel: 'error', timeoutInMilliseconds: 30000 })
97
+ const bytes = readFileSync(join(qaDirectory, filename))
98
+ const hash = createHash('sha256').update(bytes).digest('hex'); hashes.push(hash)
99
+ qa.frames.push({ shotId: shot.id, frame, filename, fraction, sha256: hash })
100
+ }
101
+ if (hashes[0] === hashes[1]) qa.warnings.push(shot.id + ': 两张采样帧相同,请检查主运动或停留段')
102
+ }
103
+ // 渲染规格随请求进来(由 render.js 的 resolveRenderSettings 解析过):
104
+ // 编码参数、色彩标签、超采样倍数、并发都在这里唯一地落到 renderMedia 上。
105
+ const settings = request.render || {}
106
+ qa.render = settings
107
+ writeFileSync(join(qaDirectory, 'report.json'), JSON.stringify(qa, null, 2))
108
+ const scale = Number(settings.scale) > 1 ? Math.round(Number(settings.scale)) : 1
109
+ const finalOutput = request.output
110
+ // 超采样:Remotion 的 scale 是「渲成更大」,不会替你缩回来。
111
+ // 所以大图先落到临时文件,再用一次 lanczos + bt709 的母版编码缩回目标尺寸。
112
+ const rawOutput = scale > 1 ? join(dirname(finalOutput), '.supersample.mp4') : finalOutput
113
+ const startedAt = Date.now()
114
+ let seenFrames = 0
115
+ const totalFrames = request.frameRange
116
+ ? request.frameRange[1] - request.frameRange[0] + 1
117
+ : composition.durationInFrames
118
+ await renderMedia({ serveUrl, composition, inputProps, outputLocation: rawOutput,
119
+ codec: settings.codec || 'h264',
120
+ ...(settings.crf ? { crf: settings.crf } : {}),
121
+ ...(settings.preset ? { x264Preset: settings.preset } : {}),
122
+ ...(settings.pixelFormat ? { pixelFormat: settings.pixelFormat } : {}),
123
+ ...(settings.colorSpace ? { colorSpace: settings.colorSpace } : {}),
124
+ ...(settings.audioBitrate ? { audioBitrate: settings.audioBitrate } : {}),
125
+ scale,
126
+ concurrency: settings.concurrency || 2,
127
+ ...(request.frameRange?{frameRange:request.frameRange}:{}),
128
+ puppeteerInstance: browser, browserExecutable, cancelSignal, logLevel: 'error',
129
+ onProgress: ({ progress, renderedFrames }) => {
130
+ const done = Number(renderedFrames) || 0
131
+ if (done > seenFrames) seenFrames = done
132
+ const elapsed = (Date.now() - startedAt) / 1000
133
+ const perFrame = seenFrames > 0 ? elapsed / seenFrames : null
134
+ // 单帧耗时是「样本数该开多大」的唯一依据:没有它,超采样只能靠猜。
135
+ send({ type: 'progress', phase: 'rendering', progress: .1 + progress * .85,
136
+ frames: { done: seenFrames, total: totalFrames,
137
+ perFrameSeconds: perFrame ? Math.round(perFrame * 1000) / 1000 : null,
138
+ etaSeconds: perFrame ? Math.round(perFrame * Math.max(totalFrames - seenFrames, 0)) : null } })
139
+ } })
140
+ if (scale > 1) {
141
+ send({ type: 'progress', phase: 'encoding', progress: .96 })
142
+ // 这一趟本来就是重编码,顺手把 bt709 三标签补全。
143
+ // 注意:这个 ffmpeg 构建里 -color_primaries / -color_trc 当**输出选项**不生效
144
+ // (连续实测:只剩 colorspace 标签,primaries/trc 仍是 unknown),必须走 setparams 滤镜改帧元数据。
145
+ const colorFilter = settings.colorSpace === 'bt709'
146
+ ? ',setparams=color_primaries=bt709:color_trc=bt709:colorspace=bt709' : ''
147
+ await runFfmpeg(['-i', rawOutput,
148
+ '-vf', 'scale=' + composition.width + ':' + composition.height + ':flags=lanczos+accurate_rnd+full_chroma_int' + colorFilter,
149
+ '-c:v', 'libx264', '-crf', String(settings.crf || 14), '-preset', String(settings.preset || 'slow'),
150
+ '-profile:v', 'high', '-pix_fmt', 'yuv420p',
151
+ '-colorspace', 'bt709', '-color_primaries', 'bt709', '-color_trc', 'bt709',
152
+ '-c:a', 'copy', '-movflags', '+faststart', finalOutput],
153
+ { cwd: dirname(finalOutput), log: join(dirname(finalOutput), 'encode.log'), timeoutMs: 900000 })
154
+ rmSync(rawOutput, { force: true })
155
+ qa.supersample = { from: composition.width * scale + 'x' + composition.height * scale, to: composition.width + 'x' + composition.height }
156
+ qa.colorTags = settings.colorSpace === 'bt709' ? 'bt709(三标签齐全)' : '未标注'
157
+ } else if (settings.colorSpace === 'bt709') {
158
+ // Remotion 只写 colorspace,primaries/trc 留 unknown;要齐全只能再重编一次,
159
+ // 而重编会让画质掉一代——所以 1× 下宁可把这件事说清楚,不偷偷多编一遍。
160
+ qa.colorTags = '仅 colorspace=bt709(primaries/trc 为 unknown;母版级标签请设 render.scale=2)'
161
+ qa.warnings.push('色彩标签只写了 colorspace:要 primaries/trc 齐全(严格 QC)请用 render.scale=2,那一趟重编码会一并补齐')
162
+ }
163
+ const posterShot = request.composition.shots.find((shot) => shot.referenceIds.length) || request.composition.shots[0]
164
+ await renderStill({ serveUrl, composition, inputProps, output: request.poster,
165
+ frame: posterShot.startFrame + Math.floor(posterShot.durationFrames / 2), puppeteerInstance: browser, browserExecutable, cancelSignal, logLevel: 'error' })
166
+ writeFileSync(join(qaDirectory, 'report.json'), JSON.stringify(qa, null, 2))
167
+ send({ type: 'done', qa })
168
+ } catch (error) { send({ type: 'error', error: error.message || String(error) }); process.exitCode = 1 }
169
+ finally {
170
+ await browser?.close({ silent: true }).catch(() => {})
171
+ const cleanup = relative(resolve(dirname(request.output)), resolve(outDir))
172
+ if (request.keepBundle !== true && cleanup === 'bundle' && !isAbsolute(cleanup)) rmSync(outDir, { recursive: true, force: true })
173
+ process.disconnect()
174
+ }
175
+ })