dsh-drawai 0.3.4 → 0.4.1

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 (538) hide show
  1. package/LICENSE +4154 -0
  2. package/README.md +49 -11
  3. package/lib/audio-media.js +150 -0
  4. package/lib/audio-service.js +66 -0
  5. package/lib/canvas-format.js +134 -0
  6. package/lib/client.js +5090 -184
  7. package/lib/comfyui-default-workflow.mjs +1825 -0
  8. package/lib/comfyui-workflow.mjs +426 -0
  9. package/lib/document-commands.js +12 -0
  10. package/lib/document-core.js +29 -0
  11. package/lib/drawing-runner.js +6 -4
  12. package/lib/drawing-tasks.js +26 -0
  13. package/lib/ffmpeg-manager.js +1056 -0
  14. package/lib/imagegen.mjs +596 -0
  15. package/lib/index.js +1762 -129
  16. package/lib/media.js +26 -13
  17. package/lib/mgstyle-core.js +75 -0
  18. package/lib/motion/apply.js +181 -0
  19. package/lib/motion/asset-pack-lock.js +10 -0
  20. package/lib/motion/asset-pack.js +335 -0
  21. package/lib/motion/assets.js +291 -0
  22. package/lib/motion/audio.js +103 -0
  23. package/lib/motion/audiolevel.js +63 -0
  24. package/lib/motion/audiomix.js +144 -0
  25. package/lib/motion/beats.js +338 -0
  26. package/lib/motion/builtin-assets.js +62 -0
  27. package/lib/motion/canvas-spec.js +442 -0
  28. package/lib/motion/capture.js +95 -0
  29. package/lib/motion/cards.js +80 -0
  30. package/lib/motion/collect.js +449 -0
  31. package/lib/motion/delivery.js +140 -0
  32. package/lib/motion/edge-speech.py +90 -0
  33. package/lib/motion/entry.jsx +73 -0
  34. package/lib/motion/export.js +200 -0
  35. package/lib/motion/ffmpeg.js +43 -0
  36. package/lib/motion/fonts.js +71 -0
  37. package/lib/motion/jobs.js +117 -0
  38. package/lib/motion/json.js +4 -0
  39. package/lib/motion/media-catalog.js +59 -0
  40. package/lib/motion/mgstyles/BRIEF-TEMPLATE.md +63 -0
  41. package/lib/motion/mgstyles/briefs/01-flat-vector.md +104 -0
  42. package/lib/motion/mgstyles/briefs/02-line-art.md +97 -0
  43. package/lib/motion/mgstyles/briefs/03-isometric.md +108 -0
  44. package/lib/motion/mgstyles/briefs/05-cel-boil.md +145 -0
  45. package/lib/motion/mgstyles/briefs/06-collage.md +149 -0
  46. package/lib/motion/mgstyles/briefs/07-liquid.md +106 -0
  47. package/lib/motion/mgstyles/briefs/08-morph.md +111 -0
  48. package/lib/motion/mgstyles/briefs/09-bauhaus.md +150 -0
  49. package/lib/motion/mgstyles/briefs/10-synthwave.md +151 -0
  50. package/lib/motion/mgstyles/briefs/12-aurora-glass.md +147 -0
  51. package/lib/motion/mgstyles/briefs/18-hanazi.md +140 -0
  52. package/lib/motion/mgstyles/briefs/19-paperclip.md +156 -0
  53. package/lib/motion/mgstyles/briefs/20-pixel.md +118 -0
  54. package/lib/motion/mgstyles/briefs/22-hud.md +118 -0
  55. package/lib/motion/mgstyles/catalog.d/01-flat-vector.json +34 -0
  56. package/lib/motion/mgstyles/catalog.d/02-line-art.json +34 -0
  57. package/lib/motion/mgstyles/catalog.d/03-isometric.json +35 -0
  58. package/lib/motion/mgstyles/catalog.d/05-cel-boil.json +28 -0
  59. package/lib/motion/mgstyles/catalog.d/06-collage.json +28 -0
  60. package/lib/motion/mgstyles/catalog.d/07-liquid.json +28 -0
  61. package/lib/motion/mgstyles/catalog.d/08-morph.json +28 -0
  62. package/lib/motion/mgstyles/catalog.d/09-bauhaus.json +28 -0
  63. package/lib/motion/mgstyles/catalog.d/10-synthwave.json +28 -0
  64. package/lib/motion/mgstyles/catalog.d/12-aurora-glass.json +28 -0
  65. package/lib/motion/mgstyles/catalog.d/18-hanazi.json +28 -0
  66. package/lib/motion/mgstyles/catalog.d/19-paperclip.json +28 -0
  67. package/lib/motion/mgstyles/catalog.d/20-pixel.json +28 -0
  68. package/lib/motion/mgstyles/catalog.d/22-hud.json +28 -0
  69. package/lib/motion/mgstyles/catalog.json +1356 -0
  70. package/lib/motion/mgstyles/upstream/README.md +147 -0
  71. package/lib/motion/mgstyles/upstream/README.zh-CN.md +147 -0
  72. package/lib/motion/mgstyles/upstream/demos/01-flat-vector/cues.json +1 -0
  73. package/lib/motion/mgstyles/upstream/demos/01-flat-vector/index.html +712 -0
  74. package/lib/motion/mgstyles/upstream/demos/02-line-art/cues.json +331 -0
  75. package/lib/motion/mgstyles/upstream/demos/02-line-art/film.js +676 -0
  76. package/lib/motion/mgstyles/upstream/demos/02-line-art/index.html +18 -0
  77. package/lib/motion/mgstyles/upstream/demos/02-line-art/tools/dump_timing.mjs +26 -0
  78. package/lib/motion/mgstyles/upstream/demos/03-isometric/cues.json +109 -0
  79. package/lib/motion/mgstyles/upstream/demos/03-isometric/index.html +25 -0
  80. package/lib/motion/mgstyles/upstream/demos/03-isometric/js/anim.js +82 -0
  81. package/lib/motion/mgstyles/upstream/demos/03-isometric/js/main.js +219 -0
  82. package/lib/motion/mgstyles/upstream/demos/03-isometric/js/night5.js +180 -0
  83. package/lib/motion/mgstyles/upstream/demos/03-isometric/js/render.js +202 -0
  84. package/lib/motion/mgstyles/upstream/demos/03-isometric/js/title.js +167 -0
  85. package/lib/motion/mgstyles/upstream/demos/03-isometric/js/title5.js +294 -0
  86. package/lib/motion/mgstyles/upstream/demos/03-isometric/js/ui.js +141 -0
  87. package/lib/motion/mgstyles/upstream/demos/03-isometric/js/world.js +1399 -0
  88. package/lib/motion/mgstyles/upstream/demos/05-cel-boil/cues.json +157 -0
  89. package/lib/motion/mgstyles/upstream/demos/05-cel-boil/index.html +34 -0
  90. package/lib/motion/mgstyles/upstream/demos/05-cel-boil/js/engine.js +326 -0
  91. package/lib/motion/mgstyles/upstream/demos/05-cel-boil/js/scene.js +2036 -0
  92. package/lib/motion/mgstyles/upstream/demos/06-collage/assets/gen/layout.json +157 -0
  93. package/lib/motion/mgstyles/upstream/demos/06-collage/cues.json +80 -0
  94. package/lib/motion/mgstyles/upstream/demos/06-collage/index.html +889 -0
  95. package/lib/motion/mgstyles/upstream/demos/07-liquid/cues.json +100 -0
  96. package/lib/motion/mgstyles/upstream/demos/07-liquid/index.html +108 -0
  97. package/lib/motion/mgstyles/upstream/demos/07-liquid/js/engine.js +153 -0
  98. package/lib/motion/mgstyles/upstream/demos/07-liquid/js/links.js +64 -0
  99. package/lib/motion/mgstyles/upstream/demos/07-liquid/js/lookdev.js +46 -0
  100. package/lib/motion/mgstyles/upstream/demos/07-liquid/js/scene.js +963 -0
  101. package/lib/motion/mgstyles/upstream/demos/07-liquid/js/shaders.js +647 -0
  102. package/lib/motion/mgstyles/upstream/demos/07-liquid/js/textsdf.js +114 -0
  103. package/lib/motion/mgstyles/upstream/demos/07-liquid/js/type.js +50 -0
  104. package/lib/motion/mgstyles/upstream/demos/08-morph/cues.json +131 -0
  105. package/lib/motion/mgstyles/upstream/demos/08-morph/glyphs.json +1 -0
  106. package/lib/motion/mgstyles/upstream/demos/08-morph/index.html +901 -0
  107. package/lib/motion/mgstyles/upstream/demos/09-bauhaus/cues.json +270 -0
  108. package/lib/motion/mgstyles/upstream/demos/09-bauhaus/film.js +697 -0
  109. package/lib/motion/mgstyles/upstream/demos/09-bauhaus/index.html +12 -0
  110. package/lib/motion/mgstyles/upstream/demos/10-synthwave/cues.json +44 -0
  111. package/lib/motion/mgstyles/upstream/demos/10-synthwave/index.html +1028 -0
  112. package/lib/motion/mgstyles/upstream/demos/12-aurora-glass/cues.json +67 -0
  113. package/lib/motion/mgstyles/upstream/demos/12-aurora-glass/index.html +16 -0
  114. package/lib/motion/mgstyles/upstream/demos/12-aurora-glass/main.js +967 -0
  115. package/lib/motion/mgstyles/upstream/demos/12-aurora-glass/shaders.js +468 -0
  116. package/lib/motion/mgstyles/upstream/demos/18-hanazi/cues.json +117 -0
  117. package/lib/motion/mgstyles/upstream/demos/18-hanazi/index.html +541 -0
  118. package/lib/motion/mgstyles/upstream/demos/19-paperclip/assets/countries-110m.json +1 -0
  119. package/lib/motion/mgstyles/upstream/demos/19-paperclip/assets/stickers/meta.json +34 -0
  120. package/lib/motion/mgstyles/upstream/demos/19-paperclip/cues.json +285 -0
  121. package/lib/motion/mgstyles/upstream/demos/19-paperclip/index.html +599 -0
  122. package/lib/motion/mgstyles/upstream/demos/20-pixel/cues.json +42 -0
  123. package/lib/motion/mgstyles/upstream/demos/20-pixel/film.js +914 -0
  124. package/lib/motion/mgstyles/upstream/demos/20-pixel/index.html +18 -0
  125. package/lib/motion/mgstyles/upstream/demos/22-hud/cues.json +108 -0
  126. package/lib/motion/mgstyles/upstream/demos/22-hud/index.html +125 -0
  127. package/lib/motion/mgstyles/upstream/demos/22-hud/js/holo.js +275 -0
  128. package/lib/motion/mgstyles/upstream/demos/22-hud/js/hud.js +855 -0
  129. package/lib/motion/mgstyles/upstream/demos/22-hud/js/post.js +150 -0
  130. package/lib/motion/mgstyles/upstream/demos/22-hud/js/util.js +65 -0
  131. package/lib/motion/mgstyles/upstream/demos/22-hud/js/v5.js +142 -0
  132. package/lib/motion/mgstyles/upstream/harness/render.mjs +319 -0
  133. package/lib/motion/mgstyles/upstream/manifest.json +269 -0
  134. package/lib/motion/mgstyles/upstream/prompts/01-flat-vector.md +98 -0
  135. package/lib/motion/mgstyles/upstream/prompts/02-line-art.md +95 -0
  136. package/lib/motion/mgstyles/upstream/prompts/03-isometric.md +97 -0
  137. package/lib/motion/mgstyles/upstream/prompts/05-cel-boil.md +95 -0
  138. package/lib/motion/mgstyles/upstream/prompts/06-collage.md +95 -0
  139. package/lib/motion/mgstyles/upstream/prompts/07-liquid.md +98 -0
  140. package/lib/motion/mgstyles/upstream/prompts/08-morph.md +95 -0
  141. package/lib/motion/mgstyles/upstream/prompts/09-bauhaus.md +96 -0
  142. package/lib/motion/mgstyles/upstream/prompts/10-synthwave.md +95 -0
  143. package/lib/motion/mgstyles/upstream/prompts/12-aurora-glass.md +96 -0
  144. package/lib/motion/mgstyles/upstream/prompts/18-hanazi.md +95 -0
  145. package/lib/motion/mgstyles/upstream/prompts/19-paperclip.md +96 -0
  146. package/lib/motion/mgstyles/upstream/prompts/20-pixel.md +96 -0
  147. package/lib/motion/mgstyles/upstream/prompts/22-hud.md +95 -0
  148. package/lib/motion/mgstyles/upstream/rubric.md +51 -0
  149. package/lib/motion/mgstyles/upstream/template.md +36 -0
  150. package/lib/motion/pixelqa.js +198 -0
  151. package/lib/motion/preview.js +97 -0
  152. package/lib/motion/project.js +395 -0
  153. package/lib/motion/qa.js +290 -0
  154. package/lib/motion/reference-media.jsx +10 -0
  155. package/lib/motion/render-settings.js +112 -0
  156. package/lib/motion/render.js +161 -0
  157. package/lib/motion/runtime/package-lock.json +3058 -0
  158. package/lib/motion/runtime/package.json +16 -0
  159. package/lib/motion/scene-kit.js +183 -0
  160. package/lib/motion/sfx.js +232 -0
  161. package/lib/motion/shotcraft/ClipCard.tsx +204 -0
  162. package/lib/motion/shotcraft/catalog.json +2461 -0
  163. package/lib/motion/shotcraft/upstream/SKILL.md +286 -0
  164. package/lib/motion/shotcraft/upstream/assets/lib/Caption.tsx +54 -0
  165. package/lib/motion/shotcraft/upstream/assets/lib/ClipCard.tsx +200 -0
  166. package/lib/motion/shotcraft/upstream/assets/lib/DigitRoll.tsx +45 -0
  167. package/lib/motion/shotcraft/upstream/assets/lib/FlashCut.tsx +20 -0
  168. package/lib/motion/shotcraft/upstream/assets/lib/FlatPanel.tsx +65 -0
  169. package/lib/motion/shotcraft/upstream/assets/lib/PageCam.tsx +151 -0
  170. package/lib/motion/shotcraft/upstream/assets/lib/VerticalTicker.tsx +129 -0
  171. package/lib/motion/shotcraft/upstream/assets/lib/helpers/camera.tsx +75 -0
  172. package/lib/motion/shotcraft/upstream/assets/lib/helpers/motion.ts +40 -0
  173. package/lib/motion/shotcraft/upstream/assets/lib/helpers/rand.ts +11 -0
  174. package/lib/motion/shotcraft/upstream/assets/lib/helpers/shake.ts +10 -0
  175. package/lib/motion/shotcraft/upstream/assets/scripts/__pycache__/sfx-source.cpython-313.pyc +0 -0
  176. package/lib/motion/shotcraft/upstream/assets/scripts/build-readme-cover.mjs +49 -0
  177. package/lib/motion/shotcraft/upstream/assets/scripts/capture-template.mjs +210 -0
  178. package/lib/motion/shotcraft/upstream/assets/scripts/sfx-source.py +423 -0
  179. package/lib/motion/shotcraft/upstream/assets/scripts/smoke-render-demos.py +170 -0
  180. package/lib/motion/shotcraft/upstream/assets/scripts/test_sfx_source.py +157 -0
  181. package/lib/motion/shotcraft/upstream/demos/README.md +120 -0
  182. package/lib/motion/shotcraft/upstream/demos/_fixtures/Brand.tsx +112 -0
  183. package/lib/motion/shotcraft/upstream/demos/_fixtures/Fixtures.tsx +647 -0
  184. package/lib/motion/shotcraft/upstream/demos/_fixtures/Look.tsx +316 -0
  185. package/lib/motion/shotcraft/upstream/demos/_fixtures/Motion.tsx +82 -0
  186. package/lib/motion/shotcraft/upstream/demos/_fixtures/PageCam2D.tsx +115 -0
  187. package/lib/motion/shotcraft/upstream/demos/_fixtures/Polish.tsx +243 -0
  188. package/lib/motion/shotcraft/upstream/demos/_textures/live-layout.json +389 -0
  189. package/lib/motion/shotcraft/upstream/demos/camera/basic-3d-scene/Basic3DScene.tsx +250 -0
  190. package/lib/motion/shotcraft/upstream/demos/camera/crash-zoom-punch/CrashImpactReal.tsx +305 -0
  191. package/lib/motion/shotcraft/upstream/demos/camera/crash-zoom-punch/CrashZoomReal.tsx +246 -0
  192. package/lib/motion/shotcraft/upstream/demos/camera/cursor-flyover/CursorFlyover.tsx +390 -0
  193. package/lib/motion/shotcraft/upstream/demos/camera/depth-layer-moves/MultiplaneReal.tsx +138 -0
  194. package/lib/motion/shotcraft/upstream/demos/camera/graze-face-tour/GrazeFaceTour.tsx +542 -0
  195. package/lib/motion/shotcraft/upstream/demos/camera/overhead-camera-moves/OverheadTabletopDrop.tsx +315 -0
  196. package/lib/motion/shotcraft/upstream/demos/camera/overhead-camera-moves/TiltReveal.tsx +299 -0
  197. package/lib/motion/shotcraft/upstream/demos/camera/space-camera-moves/DroneDiveLanding.tsx +173 -0
  198. package/lib/motion/shotcraft/upstream/demos/camera/space-camera-moves/ExplodedView.tsx +348 -0
  199. package/lib/motion/shotcraft/upstream/demos/camera/steep-tilt-glide/SteepTiltGlide.tsx +366 -0
  200. package/lib/motion/shotcraft/upstream/demos/camera/tension-camera-moves/BulletTimeFreezeOrbit.tsx +279 -0
  201. package/lib/motion/shotcraft/upstream/demos/camera/tension-camera-moves/PullBackIsolation.tsx +184 -0
  202. package/lib/motion/shotcraft/upstream/demos/camera/terminal-3d/Terminal3D.tsx +390 -0
  203. package/lib/motion/shotcraft/upstream/demos/data/before-after-slider-scrub/BeforeAfterSliderScrub.tsx +155 -0
  204. package/lib/motion/shotcraft/upstream/demos/data/chart-live-moves/AxisRescaleShockV2.tsx +303 -0
  205. package/lib/motion/shotcraft/upstream/demos/data/chart-live-moves/OscilloscopeStreamV2.tsx +290 -0
  206. package/lib/motion/shotcraft/upstream/demos/data/chart-live-moves/UnitDotSwarmRegroupV2.tsx +278 -0
  207. package/lib/motion/shotcraft/upstream/demos/data/gauge-readout-moves/NeedleSweepSelftest.tsx +307 -0
  208. package/lib/motion/shotcraft/upstream/demos/data/gauge-readout-moves/TapeScrollFixedPointer.tsx +215 -0
  209. package/lib/motion/shotcraft/upstream/demos/data/scroll-brake-moves/BrakeReticleLock.tsx +299 -0
  210. package/lib/motion/shotcraft/upstream/demos/data/scroll-brake-moves/ChangelogScrollBrake.tsx +232 -0
  211. package/lib/motion/shotcraft/upstream/demos/data/timeline-travel/TimelineTravel.tsx +290 -0
  212. package/lib/motion/shotcraft/upstream/demos/effects/assemble-then-type-flyin/AssembleThenTypeFlyin.tsx +273 -0
  213. package/lib/motion/shotcraft/upstream/demos/effects/aurora-bloom-bg-flip/AuroraBloomBgFlip.tsx +167 -0
  214. package/lib/motion/shotcraft/upstream/demos/effects/brand-frame-snap/BrandFrameSnap.tsx +536 -0
  215. package/lib/motion/shotcraft/upstream/demos/effects/fui-hud-moves/ReticleLockOn.tsx +164 -0
  216. package/lib/motion/shotcraft/upstream/demos/effects/glow-flyline-moves/FlylineArc.tsx +175 -0
  217. package/lib/motion/shotcraft/upstream/demos/effects/glow-flyline-moves/GlowOrbAmbient.tsx +197 -0
  218. package/lib/motion/shotcraft/upstream/demos/effects/glow-flyline-moves/OrbFlylineRelay.tsx +241 -0
  219. package/lib/motion/shotcraft/upstream/demos/effects/icon-performance-moves/AttentionBounce.tsx +279 -0
  220. package/lib/motion/shotcraft/upstream/demos/effects/impact-feedback/AnimeImpact.tsx +230 -0
  221. package/lib/motion/shotcraft/upstream/demos/effects/impact-feedback/HitCounter.tsx +345 -0
  222. package/lib/motion/shotcraft/upstream/demos/effects/light-play-moves/SheenSweepRetry.tsx +275 -0
  223. package/lib/motion/shotcraft/upstream/demos/effects/light-play-moves/SpotlightSweepReveal.tsx +229 -0
  224. package/lib/motion/shotcraft/upstream/demos/effects/radial-ripple-phone-chips/RadialRipplePhoneChips.tsx +312 -0
  225. package/lib/motion/shotcraft/upstream/demos/effects/riso-print-hits/RisoMisregistrationHit.tsx +222 -0
  226. package/lib/motion/shotcraft/upstream/demos/effects/scan-bracket-sweep/ScanBracketSweep.tsx +295 -0
  227. package/lib/motion/shotcraft/upstream/demos/effects/scanline-annotate-focus/ScanlineAnnotateFocus.tsx +329 -0
  228. package/lib/motion/shotcraft/upstream/demos/effects/scanline-assemble-flyin/ScanlineAssembleFlyin.tsx +315 -0
  229. package/lib/motion/shotcraft/upstream/demos/effects/slam-entrance-moves/ImpactBurstKit.tsx +264 -0
  230. package/lib/motion/shotcraft/upstream/demos/effects/slam-entrance-moves/KanadaPerspectiveSnap.tsx +260 -0
  231. package/lib/motion/shotcraft/upstream/demos/effects/slam-entrance-moves/ScoreSlam.tsx +263 -0
  232. package/lib/motion/shotcraft/upstream/demos/effects/spotlight-sweep-moves/CornerSpotlightReveal.tsx +123 -0
  233. package/lib/motion/shotcraft/upstream/demos/effects/spotlight-sweep-moves/GlowWakeSleepPanel.tsx +187 -0
  234. package/lib/motion/shotcraft/upstream/demos/effects/spotlight-sweep-moves/SlideSpotlightPan.tsx +175 -0
  235. package/lib/motion/shotcraft/upstream/demos/interaction/autolayout-gap-dial/AutolayoutGapDial.tsx +305 -0
  236. package/lib/motion/shotcraft/upstream/demos/interaction/canvas-materialize-moves/DiagramCascadeBuild.tsx +350 -0
  237. package/lib/motion/shotcraft/upstream/demos/interaction/canvas-materialize-moves/PanelToCanvasMaterialize.tsx +352 -0
  238. package/lib/motion/shotcraft/upstream/demos/interaction/chip-grid-single-select-blackout/ChipGridSingleSelectBlackout.tsx +218 -0
  239. package/lib/motion/shotcraft/upstream/demos/interaction/collab-cursor-moves/CursorCastEnsemble.tsx +297 -0
  240. package/lib/motion/shotcraft/upstream/demos/interaction/glass-pill-dictation-typing/GlassPillDictationTyping.tsx +157 -0
  241. package/lib/motion/shotcraft/upstream/demos/interaction/hashtag-to-pill-materialize/HashtagToPillMaterialize.tsx +218 -0
  242. package/lib/motion/shotcraft/upstream/demos/interaction/picker-carousel-feature-cycle/PickerCarouselFeatureCycle.tsx +202 -0
  243. package/lib/motion/shotcraft/upstream/demos/interaction/segmented-thumb-hero/SegmentedThumbHero.tsx +265 -0
  244. package/lib/motion/shotcraft/upstream/demos/interaction/theme-switch-moves/PaletteThemeRipple.tsx +457 -0
  245. package/lib/motion/shotcraft/upstream/demos/interaction/theme-switch-moves/ThemeSweepToggle.tsx +446 -0
  246. package/lib/motion/shotcraft/upstream/demos/interaction/type-and-filter/TypeAndFilter.tsx +249 -0
  247. package/lib/motion/shotcraft/upstream/demos/interaction/voice-waveform-live/VoiceWaveformLive.tsx +278 -0
  248. package/lib/motion/shotcraft/upstream/demos/opening/crane-rise-reveal/CraneRiseReveal.tsx +332 -0
  249. package/lib/motion/shotcraft/upstream/demos/opening/dataviz-landscape-open/DatavizLandscapeOpen.tsx +358 -0
  250. package/lib/motion/shotcraft/upstream/demos/opening/fracture/Fracture.tsx +201 -0
  251. package/lib/motion/shotcraft/upstream/demos/opening/icon-field-colorize/IconFieldColorize.tsx +200 -0
  252. package/lib/motion/shotcraft/upstream/demos/opening/letterspace-materialize/LetterspaceMaterialize.tsx +208 -0
  253. package/lib/motion/shotcraft/upstream/demos/opening/magician-card-flourish/MagicianCardFlourish.tsx +341 -0
  254. package/lib/motion/shotcraft/upstream/demos/opening/orbit-ring-title-open/OrbitRingTitleOpen.tsx +389 -0
  255. package/lib/motion/shotcraft/upstream/demos/opening/spotlight-hero-card/SpotlightHeroCard.tsx +293 -0
  256. package/lib/motion/shotcraft/upstream/demos/opening/stroke-segment-build/StrokeSegmentBuild.tsx +183 -0
  257. package/lib/motion/shotcraft/upstream/demos/opening/text-as-mask/TextAsMask.tsx +245 -0
  258. package/lib/motion/shotcraft/upstream/demos/outro/grain-dissolve/GrainDissolve.tsx +222 -0
  259. package/lib/motion/shotcraft/upstream/demos/outro/logo-shrink-wordmark-lockup/LogoShrinkWordmarkLockup.tsx +223 -0
  260. package/lib/motion/shotcraft/upstream/demos/outro/neon-triple-marquee/NeonTripleMarquee.tsx +217 -0
  261. package/lib/motion/shotcraft/upstream/demos/outro/outro-group-photo-launch/OutroGroupPhotoLaunch.tsx +343 -0
  262. package/lib/motion/shotcraft/upstream/demos/outro/ui-strip-away-outro/UiStripAwayOutro.tsx +357 -0
  263. package/lib/motion/shotcraft/upstream/demos/outro/ui-to-brand-morph/IconFlipBloomLogo.tsx +187 -0
  264. package/lib/motion/shotcraft/upstream/demos/outro/ui-to-brand-morph/InputMorphsIntoLogo.tsx +333 -0
  265. package/lib/motion/shotcraft/upstream/demos/rhythm/beat-cut-moves/PaparazziFlash.tsx +274 -0
  266. package/lib/motion/shotcraft/upstream/demos/rhythm/beat-step-list-theme-cycle/BeatStepListThemeCycle.tsx +270 -0
  267. package/lib/motion/shotcraft/upstream/demos/rhythm/panel-grid-moves/ComicPanelSplit.tsx +430 -0
  268. package/lib/motion/shotcraft/upstream/demos/rhythm/quad-split-parallel-scenes/QuadSplitParallelScenes.tsx +252 -0
  269. package/lib/motion/shotcraft/upstream/demos/rhythm/rhythm-interrupt-moves/JumpCutPunchIn.tsx +106 -0
  270. package/lib/motion/shotcraft/upstream/demos/rhythm/sakuga-timing-shift/SakugaTimingShift.tsx +288 -0
  271. package/lib/motion/shotcraft/upstream/demos/rhythm/speed-ramp-freeze/FreezeAnnotateReal.tsx +362 -0
  272. package/lib/motion/shotcraft/upstream/demos/rhythm/trailer-grammar-moves/TrailerBumper.tsx +168 -0
  273. package/lib/motion/shotcraft/upstream/demos/transition/bottom-push-stack-wipe/BottomPushStackWipe.tsx +310 -0
  274. package/lib/motion/shotcraft/upstream/demos/transition/card-flip-reveal/CardFlipReveal.tsx +261 -0
  275. package/lib/motion/shotcraft/upstream/demos/transition/card-flock-tumble/CardFlockTumble.tsx +459 -0
  276. package/lib/motion/shotcraft/upstream/demos/transition/circle-match-iris/CircleMatchIris.tsx +294 -0
  277. package/lib/motion/shotcraft/upstream/demos/transition/gradient-transition/GradientTransition.tsx +161 -0
  278. package/lib/motion/shotcraft/upstream/demos/transition/line-carry-transition/LineCarryTransition.tsx +248 -0
  279. package/lib/motion/shotcraft/upstream/demos/transition/mosaic-reframe/MosaicReframe.tsx +359 -0
  280. package/lib/motion/shotcraft/upstream/demos/transition/page-turn-transitions/BarnDoorSplit.tsx +227 -0
  281. package/lib/motion/shotcraft/upstream/demos/transition/print-texture-transitions/InkBleedReveal.tsx +162 -0
  282. package/lib/motion/shotcraft/upstream/demos/transition/shot-transitions/PortalWipeV2.tsx +248 -0
  283. package/lib/motion/shotcraft/upstream/demos/transition/shot-transitions/WhipBrakeReal.tsx +186 -0
  284. package/lib/motion/shotcraft/upstream/demos/transition/tear-streak-transitions/GlitchDisplace.tsx +355 -0
  285. package/lib/motion/shotcraft/upstream/demos/transition/transition-hidden-cut/InvisibleCut.tsx +272 -0
  286. package/lib/motion/shotcraft/upstream/demos/transition/transition-hidden-cut/LightLeakBurn.tsx +262 -0
  287. package/lib/motion/shotcraft/upstream/demos/transition/transition-hidden-cut/VersusSlam.tsx +217 -0
  288. package/lib/motion/shotcraft/upstream/demos/transition/transition-travel/LetterformZoom.tsx +285 -0
  289. package/lib/motion/shotcraft/upstream/demos/transition/white-flash-logo-simplify-cut/WhiteFlashLogoSimplifyCut.tsx +205 -0
  290. package/lib/motion/shotcraft/upstream/demos/transition/wipe-transitions/BlindsSlice.tsx +178 -0
  291. package/lib/motion/shotcraft/upstream/demos/typography/blur-slide/BlurSlide.tsx +147 -0
  292. package/lib/motion/shotcraft/upstream/demos/typography/brace-expand/BraceExpand.tsx +143 -0
  293. package/lib/motion/shotcraft/upstream/demos/typography/brand-ink-open/BrandInkOpen.tsx +134 -0
  294. package/lib/motion/shotcraft/upstream/demos/typography/countdown-arc-scatter/CountdownArcScatter.tsx +217 -0
  295. package/lib/motion/shotcraft/upstream/demos/typography/flying-words/FlyingWords.tsx +198 -0
  296. package/lib/motion/shotcraft/upstream/demos/typography/glitch-cycle/GlitchCycle.tsx +221 -0
  297. package/lib/motion/shotcraft/upstream/demos/typography/gradient-word-sweep/GradientWordSweep.tsx +312 -0
  298. package/lib/motion/shotcraft/upstream/demos/typography/lead-word-zoom-assemble/LeadWordZoomAssemble.tsx +261 -0
  299. package/lib/motion/shotcraft/upstream/demos/typography/marker-underline-title/MarkerUnderlineTitle.tsx +121 -0
  300. package/lib/motion/shotcraft/upstream/demos/typography/outline-word-fill/OutlineWordFill.tsx +153 -0
  301. package/lib/motion/shotcraft/upstream/demos/typography/paper-title-card/PaperTitleCard.tsx +179 -0
  302. package/lib/motion/shotcraft/upstream/demos/typography/pill-chip-slot-cycle-handled/PillChipSlotCycleHandled.tsx +140 -0
  303. package/lib/motion/shotcraft/upstream/demos/typography/pill-slot-cycle/PillSlotCycle.tsx +309 -0
  304. package/lib/motion/shotcraft/upstream/demos/typography/text-column-converge/TextColumnConverge.tsx +191 -0
  305. package/lib/motion/shotcraft/upstream/demos/typography/title-demote-to-label/TitleDemoteToLabel.tsx +292 -0
  306. package/lib/motion/shotcraft/upstream/demos/typography/type-assembly-moves/LetterformDriftAssembly.tsx +135 -0
  307. package/lib/motion/shotcraft/upstream/demos/typography/type-assembly-moves/SplitTextStagger.tsx +124 -0
  308. package/lib/motion/shotcraft/upstream/demos/typography/type-assembly-moves/TextOnPath.tsx +255 -0
  309. package/lib/motion/shotcraft/upstream/demos/typography/type-entrance-moves/LetterDropPhysics.tsx +173 -0
  310. package/lib/motion/shotcraft/upstream/demos/typography/type-rhythm-sync/FontWeightPump.tsx +225 -0
  311. package/lib/motion/shotcraft/upstream/demos/typography/type-rhythm-sync/KaraokeFillSync.tsx +141 -0
  312. package/lib/motion/shotcraft/upstream/demos/typography/typewriter-moves/TypewriterErrorRetype.tsx +137 -0
  313. package/lib/motion/shotcraft/upstream/demos/typography/vertical-word-roll-blur-cycle/VerticalWordRollBlurCycle.tsx +147 -0
  314. package/lib/motion/shotcraft/upstream/demos/typography/word-relay-filmstrip/WordRelayFilmstrip.tsx +409 -0
  315. package/lib/motion/shotcraft/upstream/demos/typography/word-relay-geometry/WordRelayGeometry.tsx +280 -0
  316. package/lib/motion/shotcraft/upstream/demos/ui-entrance/avatar-bracket-carousel/AvatarBracketCarousel.tsx +271 -0
  317. package/lib/motion/shotcraft/upstream/demos/ui-entrance/bezier-source-converge-merge/BezierSourceConvergeMerge.tsx +385 -0
  318. package/lib/motion/shotcraft/upstream/demos/ui-entrance/card-stack/CardStack.tsx +312 -0
  319. package/lib/motion/shotcraft/upstream/demos/ui-entrance/carousel-3d/Carousel3D.tsx +303 -0
  320. package/lib/motion/shotcraft/upstream/demos/ui-entrance/clipcard-looping/ClipCardLooping.tsx +77 -0
  321. package/lib/motion/shotcraft/upstream/demos/ui-entrance/cloner-depth-echo/ClonerDepthEcho.tsx +311 -0
  322. package/lib/motion/shotcraft/upstream/demos/ui-entrance/deck-deal-flyin/DeckDealFlyin.tsx +307 -0
  323. package/lib/motion/shotcraft/upstream/demos/ui-entrance/doc-park-left-pill-deal/DocParkLeftPillDeal.tsx +349 -0
  324. package/lib/motion/shotcraft/upstream/demos/ui-entrance/document-typewriter-reveal/DocumentTypewriterReveal.tsx +255 -0
  325. package/lib/motion/shotcraft/upstream/demos/ui-entrance/draw-svg-trace/DrawSvgTrace.tsx +244 -0
  326. package/lib/motion/shotcraft/upstream/demos/ui-entrance/element-body-moves/ContactShadowLift.tsx +217 -0
  327. package/lib/motion/shotcraft/upstream/demos/ui-entrance/integration-hub-map/IntegrationHubMap.tsx +652 -0
  328. package/lib/motion/shotcraft/upstream/demos/ui-entrance/list-reveal/ListReveal.tsx +153 -0
  329. package/lib/motion/shotcraft/upstream/demos/ui-entrance/list-stack-press/ListStackPress.tsx +238 -0
  330. package/lib/motion/shotcraft/upstream/demos/ui-entrance/neon-frame-forerun/NeonFrameForerun.tsx +324 -0
  331. package/lib/motion/shotcraft/upstream/demos/ui-entrance/neon-frame-orbit-drop/NeonFrameForerunOrbit.tsx +354 -0
  332. package/lib/motion/shotcraft/upstream/demos/ui-entrance/page-waterfall-wall/PageWaterfallWall.tsx +101 -0
  333. package/lib/motion/shotcraft/upstream/demos/ui-entrance/page-waterfall-wall/VerticalTicker.tsx +129 -0
  334. package/lib/motion/shotcraft/upstream/demos/ui-entrance/product-card-progressive-assemble/ProductCardProgressiveAssemble.tsx +297 -0
  335. package/lib/motion/shotcraft/upstream/demos/ui-entrance/radial-wave/RadialWave.tsx +57 -0
  336. package/lib/motion/shotcraft/upstream/demos/ui-entrance/research-card-stack-scroll/ResearchCardStackScroll.tsx +155 -0
  337. package/lib/motion/shotcraft/upstream/demos/ui-entrance/row-embed/RowEmbed.tsx +175 -0
  338. package/lib/motion/shotcraft/upstream/demos/ui-entrance/value-stagger-gradient/ValueStaggerGradient.tsx +153 -0
  339. package/lib/motion/shotcraft/upstream/demos/ui-entrance/wall-reveal-moves/BentoLightUp.tsx +146 -0
  340. package/lib/motion/shotcraft/upstream/demos/ui-entrance/wall-reveal-moves/WireframeDrawOn.tsx +226 -0
  341. package/lib/motion/shotcraft/upstream/gallery/api/library.json +1 -0
  342. package/lib/motion/shotcraft/upstream/manifest.json +2715 -0
  343. package/lib/motion/shotcraft/upstream/references/aesthetic-rules.md +193 -0
  344. package/lib/motion/shotcraft/upstream/references/final-review.md +121 -0
  345. package/lib/motion/shotcraft/upstream/references/guided-free-creation.md +199 -0
  346. package/lib/motion/shotcraft/upstream/references/jianying-export.md +183 -0
  347. package/lib/motion/shotcraft/upstream/references/music-beat-sync.md +257 -0
  348. package/lib/motion/shotcraft/upstream/references/pipeline.md +382 -0
  349. package/lib/motion/shotcraft/upstream/references/publish-upload-post.md +111 -0
  350. package/lib/motion/shotcraft/upstream/references/sequences/promo-energy-arc.md +50 -0
  351. package/lib/motion/shotcraft/upstream/references/sfx-sourcing.md +95 -0
  352. package/lib/motion/shotcraft/upstream/references/shots/camera/basic-3d-scene.md +41 -0
  353. package/lib/motion/shotcraft/upstream/references/shots/camera/crash-zoom-punch.md +52 -0
  354. package/lib/motion/shotcraft/upstream/references/shots/camera/cursor-flyover.md +39 -0
  355. package/lib/motion/shotcraft/upstream/references/shots/camera/depth-layer-moves.md +39 -0
  356. package/lib/motion/shotcraft/upstream/references/shots/camera/graze-face-tour.md +57 -0
  357. package/lib/motion/shotcraft/upstream/references/shots/camera/overhead-camera-moves.md +51 -0
  358. package/lib/motion/shotcraft/upstream/references/shots/camera/space-camera-moves.md +46 -0
  359. package/lib/motion/shotcraft/upstream/references/shots/camera/steep-tilt-glide.md +52 -0
  360. package/lib/motion/shotcraft/upstream/references/shots/camera/tension-camera-moves.md +43 -0
  361. package/lib/motion/shotcraft/upstream/references/shots/camera/terminal-3d.md +42 -0
  362. package/lib/motion/shotcraft/upstream/references/shots/data/before-after-slider-scrub.md +48 -0
  363. package/lib/motion/shotcraft/upstream/references/shots/data/chart-live-moves.md +52 -0
  364. package/lib/motion/shotcraft/upstream/references/shots/data/gauge-readout-moves.md +45 -0
  365. package/lib/motion/shotcraft/upstream/references/shots/data/scroll-brake-moves.md +46 -0
  366. package/lib/motion/shotcraft/upstream/references/shots/data/timeline-travel.md +44 -0
  367. package/lib/motion/shotcraft/upstream/references/shots/effects/assemble-then-type-flyin.md +63 -0
  368. package/lib/motion/shotcraft/upstream/references/shots/effects/aurora-bloom-bg-flip.md +54 -0
  369. package/lib/motion/shotcraft/upstream/references/shots/effects/brand-frame-snap.md +58 -0
  370. package/lib/motion/shotcraft/upstream/references/shots/effects/fui-hud-moves.md +35 -0
  371. package/lib/motion/shotcraft/upstream/references/shots/effects/glow-flyline-moves.md +53 -0
  372. package/lib/motion/shotcraft/upstream/references/shots/effects/icon-performance-moves.md +42 -0
  373. package/lib/motion/shotcraft/upstream/references/shots/effects/impact-feedback.md +50 -0
  374. package/lib/motion/shotcraft/upstream/references/shots/effects/light-play-moves.md +46 -0
  375. package/lib/motion/shotcraft/upstream/references/shots/effects/radial-ripple-phone-chips.md +56 -0
  376. package/lib/motion/shotcraft/upstream/references/shots/effects/riso-print-hits.md +49 -0
  377. package/lib/motion/shotcraft/upstream/references/shots/effects/scan-bracket-sweep.md +50 -0
  378. package/lib/motion/shotcraft/upstream/references/shots/effects/scanline-annotate-focus.md +53 -0
  379. package/lib/motion/shotcraft/upstream/references/shots/effects/scanline-assemble-flyin.md +53 -0
  380. package/lib/motion/shotcraft/upstream/references/shots/effects/slam-entrance-moves.md +55 -0
  381. package/lib/motion/shotcraft/upstream/references/shots/effects/spotlight-sweep-moves.md +52 -0
  382. package/lib/motion/shotcraft/upstream/references/shots/interaction/autolayout-gap-dial.md +60 -0
  383. package/lib/motion/shotcraft/upstream/references/shots/interaction/canvas-materialize-moves.md +57 -0
  384. package/lib/motion/shotcraft/upstream/references/shots/interaction/chip-grid-single-select-blackout.md +51 -0
  385. package/lib/motion/shotcraft/upstream/references/shots/interaction/collab-cursor-moves.md +41 -0
  386. package/lib/motion/shotcraft/upstream/references/shots/interaction/glass-pill-dictation-typing.md +53 -0
  387. package/lib/motion/shotcraft/upstream/references/shots/interaction/hashtag-to-pill-materialize.md +60 -0
  388. package/lib/motion/shotcraft/upstream/references/shots/interaction/picker-carousel-feature-cycle.md +55 -0
  389. package/lib/motion/shotcraft/upstream/references/shots/interaction/segmented-thumb-hero.md +57 -0
  390. package/lib/motion/shotcraft/upstream/references/shots/interaction/theme-switch-moves.md +47 -0
  391. package/lib/motion/shotcraft/upstream/references/shots/interaction/type-and-filter.md +37 -0
  392. package/lib/motion/shotcraft/upstream/references/shots/interaction/voice-waveform-live.md +54 -0
  393. package/lib/motion/shotcraft/upstream/references/shots/opening/brand-ink-open.md +36 -0
  394. package/lib/motion/shotcraft/upstream/references/shots/opening/crane-rise-reveal.md +56 -0
  395. package/lib/motion/shotcraft/upstream/references/shots/opening/dataviz-landscape-open.md +56 -0
  396. package/lib/motion/shotcraft/upstream/references/shots/opening/fracture.md +40 -0
  397. package/lib/motion/shotcraft/upstream/references/shots/opening/icon-field-colorize.md +60 -0
  398. package/lib/motion/shotcraft/upstream/references/shots/opening/letterspace-materialize.md +57 -0
  399. package/lib/motion/shotcraft/upstream/references/shots/opening/magician-card-flourish.md +73 -0
  400. package/lib/motion/shotcraft/upstream/references/shots/opening/orbit-ring-title-open.md +87 -0
  401. package/lib/motion/shotcraft/upstream/references/shots/opening/spotlight-hero-card.md +55 -0
  402. package/lib/motion/shotcraft/upstream/references/shots/opening/stroke-segment-build.md +50 -0
  403. package/lib/motion/shotcraft/upstream/references/shots/opening/text-as-mask.md +59 -0
  404. package/lib/motion/shotcraft/upstream/references/shots/outro/grain-dissolve.md +38 -0
  405. package/lib/motion/shotcraft/upstream/references/shots/outro/logo-shrink-wordmark-lockup.md +38 -0
  406. package/lib/motion/shotcraft/upstream/references/shots/outro/neon-triple-marquee.md +59 -0
  407. package/lib/motion/shotcraft/upstream/references/shots/outro/outro-group-photo-launch.md +39 -0
  408. package/lib/motion/shotcraft/upstream/references/shots/outro/ui-strip-away-outro.md +61 -0
  409. package/lib/motion/shotcraft/upstream/references/shots/outro/ui-to-brand-morph.md +52 -0
  410. package/lib/motion/shotcraft/upstream/references/shots/rhythm/beat-cut-moves.md +50 -0
  411. package/lib/motion/shotcraft/upstream/references/shots/rhythm/beat-step-list-theme-cycle.md +66 -0
  412. package/lib/motion/shotcraft/upstream/references/shots/rhythm/panel-grid-moves.md +43 -0
  413. package/lib/motion/shotcraft/upstream/references/shots/rhythm/quad-split-parallel-scenes.md +38 -0
  414. package/lib/motion/shotcraft/upstream/references/shots/rhythm/rhythm-interrupt-moves.md +38 -0
  415. package/lib/motion/shotcraft/upstream/references/shots/rhythm/sakuga-timing-shift.md +56 -0
  416. package/lib/motion/shotcraft/upstream/references/shots/rhythm/speed-ramp-freeze.md +44 -0
  417. package/lib/motion/shotcraft/upstream/references/shots/rhythm/trailer-grammar-moves.md +38 -0
  418. package/lib/motion/shotcraft/upstream/references/shots/transition/bottom-push-stack-wipe.md +63 -0
  419. package/lib/motion/shotcraft/upstream/references/shots/transition/card-flip-reveal.md +57 -0
  420. package/lib/motion/shotcraft/upstream/references/shots/transition/card-flock-tumble.md +63 -0
  421. package/lib/motion/shotcraft/upstream/references/shots/transition/circle-match-iris.md +58 -0
  422. package/lib/motion/shotcraft/upstream/references/shots/transition/gradient-transition.md +45 -0
  423. package/lib/motion/shotcraft/upstream/references/shots/transition/line-carry-transition.md +55 -0
  424. package/lib/motion/shotcraft/upstream/references/shots/transition/mosaic-reframe.md +49 -0
  425. package/lib/motion/shotcraft/upstream/references/shots/transition/page-turn-transitions.md +42 -0
  426. package/lib/motion/shotcraft/upstream/references/shots/transition/print-texture-transitions.md +42 -0
  427. package/lib/motion/shotcraft/upstream/references/shots/transition/shot-transitions.md +45 -0
  428. package/lib/motion/shotcraft/upstream/references/shots/transition/tear-streak-transitions.md +48 -0
  429. package/lib/motion/shotcraft/upstream/references/shots/transition/transition-hidden-cut.md +55 -0
  430. package/lib/motion/shotcraft/upstream/references/shots/transition/transition-travel.md +43 -0
  431. package/lib/motion/shotcraft/upstream/references/shots/transition/white-flash-logo-simplify-cut.md +41 -0
  432. package/lib/motion/shotcraft/upstream/references/shots/transition/wipe-transitions.md +42 -0
  433. package/lib/motion/shotcraft/upstream/references/shots/typography/blur-slide.md +59 -0
  434. package/lib/motion/shotcraft/upstream/references/shots/typography/brace-expand.md +55 -0
  435. package/lib/motion/shotcraft/upstream/references/shots/typography/countdown-arc-scatter.md +65 -0
  436. package/lib/motion/shotcraft/upstream/references/shots/typography/document-typewriter-reveal.md +42 -0
  437. package/lib/motion/shotcraft/upstream/references/shots/typography/flying-words.md +64 -0
  438. package/lib/motion/shotcraft/upstream/references/shots/typography/glitch-cycle.md +64 -0
  439. package/lib/motion/shotcraft/upstream/references/shots/typography/gradient-word-sweep.md +54 -0
  440. package/lib/motion/shotcraft/upstream/references/shots/typography/lead-word-zoom-assemble.md +91 -0
  441. package/lib/motion/shotcraft/upstream/references/shots/typography/marker-underline-title.md +51 -0
  442. package/lib/motion/shotcraft/upstream/references/shots/typography/outline-word-fill.md +66 -0
  443. package/lib/motion/shotcraft/upstream/references/shots/typography/paper-title-card.md +38 -0
  444. package/lib/motion/shotcraft/upstream/references/shots/typography/pill-chip-slot-cycle-handled.md +66 -0
  445. package/lib/motion/shotcraft/upstream/references/shots/typography/pill-slot-cycle.md +58 -0
  446. package/lib/motion/shotcraft/upstream/references/shots/typography/text-column-converge.md +61 -0
  447. package/lib/motion/shotcraft/upstream/references/shots/typography/title-demote-to-label.md +64 -0
  448. package/lib/motion/shotcraft/upstream/references/shots/typography/type-assembly-moves.md +45 -0
  449. package/lib/motion/shotcraft/upstream/references/shots/typography/type-entrance-moves.md +41 -0
  450. package/lib/motion/shotcraft/upstream/references/shots/typography/type-rhythm-sync.md +51 -0
  451. package/lib/motion/shotcraft/upstream/references/shots/typography/typewriter-moves.md +42 -0
  452. package/lib/motion/shotcraft/upstream/references/shots/typography/vertical-word-roll-blur-cycle.md +63 -0
  453. package/lib/motion/shotcraft/upstream/references/shots/typography/word-relay-filmstrip.md +57 -0
  454. package/lib/motion/shotcraft/upstream/references/shots/typography/word-relay-geometry.md +75 -0
  455. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/avatar-bracket-carousel.md +59 -0
  456. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/bezier-source-converge-merge.md +67 -0
  457. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/card-stack.md +60 -0
  458. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/carousel-3d.md +66 -0
  459. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/cloner-depth-echo.md +40 -0
  460. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/deck-deal-flyin.md +45 -0
  461. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/doc-park-left-pill-deal.md +62 -0
  462. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/draw-svg-trace.md +55 -0
  463. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/element-body-moves.md +37 -0
  464. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/integration-hub-map.md +55 -0
  465. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/list-reveal.md +50 -0
  466. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/list-stack-press.md +43 -0
  467. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/neon-frame-forerun.md +55 -0
  468. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/neon-frame-orbit-drop.md +51 -0
  469. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/page-waterfall-wall.md +51 -0
  470. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/product-card-progressive-assemble.md +56 -0
  471. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/radial-wave.md +49 -0
  472. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/research-card-stack-scroll.md +57 -0
  473. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/row-embed.md +36 -0
  474. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/value-stagger-gradient.md +64 -0
  475. package/lib/motion/shotcraft/upstream/references/shots/ui-entrance/wall-reveal-moves.md +47 -0
  476. package/lib/motion/shotcraft/upstream/references/sound-design.md +170 -0
  477. package/lib/motion/shotcraft/upstream/references/workbench.md +157 -0
  478. package/lib/motion/shotcraft/upstream/template/TEMPLATE.md +103 -0
  479. package/lib/motion/shotcraft/upstream/template/THEMES.md +44 -0
  480. package/lib/motion/shotcraft/upstream/template/package.json +20 -0
  481. package/lib/motion/shotcraft/upstream/template/remotion.config.ts +6 -0
  482. package/lib/motion/shotcraft/upstream/template/src/Root.tsx +17 -0
  483. package/lib/motion/shotcraft/upstream/template/src/aifl/Caption.tsx +65 -0
  484. package/lib/motion/shotcraft/upstream/template/src/aifl/DigitRoll.tsx +48 -0
  485. package/lib/motion/shotcraft/upstream/template/src/aifl/FlashCut.tsx +24 -0
  486. package/lib/motion/shotcraft/upstream/template/src/aifl/Main.tsx +192 -0
  487. package/lib/motion/shotcraft/upstream/template/src/aifl/PaperTitleCard.tsx +111 -0
  488. package/lib/motion/shotcraft/upstream/template/src/aifl/live/PageCam.tsx +150 -0
  489. package/lib/motion/shotcraft/upstream/template/src/aifl/live/SceneDetail.tsx +158 -0
  490. package/lib/motion/shotcraft/upstream/template/src/aifl/live/SceneFlyIn.tsx +468 -0
  491. package/lib/motion/shotcraft/upstream/template/src/aifl/live/SceneOpen.tsx +552 -0
  492. package/lib/motion/shotcraft/upstream/template/src/aifl/live/SceneOutroLive.tsx +411 -0
  493. package/lib/motion/shotcraft/upstream/template/src/aifl/live/ScenePapers.tsx +200 -0
  494. package/lib/motion/shotcraft/upstream/template/src/aifl/live/SceneWbr.tsx +324 -0
  495. package/lib/motion/shotcraft/upstream/template/src/aifl/live-layout.json +389 -0
  496. package/lib/motion/shotcraft/upstream/template/src/index.ts +4 -0
  497. package/lib/motion/shotcraft/upstream/template/src/themes/ThemedFilm.tsx +7 -0
  498. package/lib/motion/shotcraft/upstream/template/src/themes/manifest.tsx +68 -0
  499. package/lib/motion/shotcraft/upstream/template/src/themes/palette-assets.json +1 -0
  500. package/lib/motion/shotcraft/upstream/template/src/themes/palette-assets.ts +24 -0
  501. package/lib/motion/shotcraft/upstream/template/src/themes/palettes.json +74 -0
  502. package/lib/motion/shotcraft/upstream/template/src/themes/visual-theme.tsx +91 -0
  503. package/lib/motion/shotcraft/upstream/template/src/workbench.ts +213 -0
  504. package/lib/motion/shotcraft/upstream/template/tsconfig.json +15 -0
  505. package/lib/motion/spec.js +113 -0
  506. package/lib/motion/style-engine.js +153 -0
  507. package/lib/motion/style-frames.js +271 -0
  508. package/lib/motion/sync.js +214 -0
  509. package/lib/motion/theme.js +121 -0
  510. package/lib/motion/video-runtime.js +192 -0
  511. package/lib/motion/voice.js +417 -0
  512. package/lib/motion-agent-files.js +82 -0
  513. package/lib/motion-agent-protocol.js +66 -0
  514. package/lib/motion-agent-tools.js +196 -0
  515. package/lib/motion-agent.js +171 -0
  516. package/lib/motion-capture.js +93 -0
  517. package/lib/motion-core.js +238 -0
  518. package/lib/motion-film-review.js +71 -0
  519. package/lib/motion-library.js +210 -0
  520. package/lib/motion-planner.js +254 -0
  521. package/lib/motion-project.js +87 -0
  522. package/lib/motion-render-worker.js +153 -0
  523. package/lib/motion-session.js +32 -0
  524. package/lib/motion-source.js +49 -0
  525. package/lib/motion-tasks.js +452 -0
  526. package/lib/motion-vision.js +44 -0
  527. package/lib/mxfile.js +27 -7
  528. package/lib/routing/node-runtime.js +14 -0
  529. package/lib/routing/router.js +211 -0
  530. package/lib/routing/vendor/README.md +96 -0
  531. package/lib/routing/vendor/libavoid-routing.js +753 -0
  532. package/lib/routing/vendor/libavoid.min.js +59 -0
  533. package/lib/shotcard-core.js +39 -0
  534. package/lib/shotcard-reference.js +56 -0
  535. package/lib/style-kernel.js +37 -3
  536. package/lib/task-patches.js +26 -2
  537. package/lib/video-export.js +49 -22
  538. package/package.json +34 -4
@@ -0,0 +1,62 @@
1
+ // Small original, deterministic assets for common motion-graphics treatments.
2
+ // Generated locally; the project owns its copy and users can edit it freely.
3
+ import { createHash } from 'node:crypto'
4
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'
5
+ import { join } from 'node:path'
6
+ import { readAssets, writeAssets } from './assets.js'
7
+ import { parseProjectJson } from './json.js'
8
+
9
+ const paper = `<svg xmlns="http://www.w3.org/2000/svg" width="512" height="512" viewBox="0 0 512 512"><filter id="n"><feTurbulence type="fractalNoise" baseFrequency="0.55" numOctaves="4" seed="11" stitchTiles="stitch"/><feColorMatrix type="saturate" values="0"/></filter><rect width="512" height="512" fill="#eee5d3"/><rect width="512" height="512" filter="url(#n)" opacity=".16" style="mix-blend-mode:multiply"/></svg>`
10
+ const grain = `<svg xmlns="http://www.w3.org/2000/svg" width="256" height="256" viewBox="0 0 256 256"><filter id="n"><feTurbulence type="fractalNoise" baseFrequency="0.9" numOctaves="3" seed="23" stitchTiles="stitch"/><feColorMatrix type="saturate" values="0"/></filter><rect width="256" height="256" filter="url(#n)"/></svg>`
11
+ const grid = `<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128" viewBox="0 0 128 128"><path d="M0 0H128 M0 0V128 M32 0V128 M64 0V128 M96 0V128 M0 32H128 M0 64H128 M0 96H128" fill="none" stroke="#ffffff" stroke-opacity=".22" stroke-width="1"/></svg>`
12
+
13
+ // 16-bit mono PCM; deterministic oscillator/noise with short fades at both ends.
14
+ function wave(seconds, sample) {
15
+ const rate = 44100, count = Math.floor(rate * seconds), data = Buffer.alloc(44 + count * 2)
16
+ data.write('RIFF', 0); data.writeUInt32LE(data.length - 8, 4); data.write('WAVEfmt ', 8)
17
+ data.writeUInt32LE(16, 16); data.writeUInt16LE(1, 20); data.writeUInt16LE(1, 22)
18
+ data.writeUInt32LE(rate, 24); data.writeUInt32LE(rate * 2, 28); data.writeUInt16LE(2, 32); data.writeUInt16LE(16, 34)
19
+ data.write('data', 36); data.writeUInt32LE(count * 2, 40)
20
+ let state = 20261106, smooth = 0
21
+ for (let i = 0; i < count; i++) {
22
+ state = (Math.imul(state, 1664525) + 1013904223) >>> 0
23
+ const noise = state / 2147483648 - 1
24
+ smooth += (noise - smooth) * .15
25
+ const t = i / rate, envelope = Math.min(1, t / .012, (seconds - t) / .06)
26
+ const value = Math.max(-1, Math.min(1, sample(t, seconds, smooth) * envelope))
27
+ data.writeInt16LE(Math.round(value * 32767), 44 + i * 2)
28
+ }
29
+ return data
30
+ }
31
+
32
+ const ASSETS = [
33
+ { file: 'builtin/paper.svg', caption: '暖色纸张纹理,可平铺', kind: 'vector', data: () => Buffer.from(paper) },
34
+ { file: 'builtin/grain.svg', caption: '灰度颗粒叠层,建议低不透明度混合', kind: 'vector', data: () => Buffer.from(grain) },
35
+ { file: 'builtin/grid.svg', caption: '透明白色网格,可平铺', kind: 'vector', data: () => Buffer.from(grid) },
36
+ { file: 'builtin/whoosh.wav', caption: '合成的短扫过声', kind: 'audio', seconds: .6, data: () => wave(.6, (t, d, n) => n * .75 * Math.sin(Math.PI * t / d)) },
37
+ { file: 'builtin/impact.wav', caption: '合成的短低频落点声', kind: 'audio', seconds: .4, data: () => wave(.4, (t, d, n) => (Math.sin(2 * Math.PI * (115 * t - 70 * t * t)) * .55 + n * .18) * Math.exp(-10 * t)) },
38
+ ]
39
+
40
+ export function writeBuiltinAssets(projectDir) {
41
+ const dir = join(projectDir, 'assets'), index = join(dir, 'manifest.json'), added = []
42
+ // Never repair a damaged user manifest by overwriting it with an empty one.
43
+ if (existsSync(index)) {
44
+ try { if (!Array.isArray(parseProjectJson(readFileSync(index, 'utf8')).items)) return added } catch { return added }
45
+ }
46
+ const manifest = readAssets(projectDir)
47
+ for (const item of ASSETS) {
48
+ const target = join(dir, item.file), data = item.data()
49
+ const sha256 = createHash('sha256').update(data).digest('hex')
50
+ mkdirSync(join(dir, 'builtin'), { recursive: true })
51
+ if (!existsSync(target)) writeFileSync(target, data)
52
+ // Do not replace or mislabel a user-edited file on a repeated create.
53
+ if (createHash('sha256').update(readFileSync(target)).digest('hex') !== sha256) continue
54
+ if (manifest.items.some((entry) => entry.file === item.file)) continue
55
+ manifest.items.push({ id: 'drawai-' + item.file.slice(8).replace(/\.[^.]+$/, ''), file: item.file,
56
+ bytes: data.length, sha256, kind: item.kind, caption: item.caption,
57
+ source: 'DrawAI 原创程序生成(MIT)', ...(item.seconds ? { seconds: item.seconds } : {}) })
58
+ added.push(item.file)
59
+ }
60
+ if (added.length) writeAssets(projectDir, manifest)
61
+ return added
62
+ }
@@ -0,0 +1,442 @@
1
+ /**
2
+ * 画布上的「视频规格三块」:分镜表 / 风格 / 旁白。
3
+ *
4
+ * 为什么要有这个模块:分镜表以前只活在对话里(或 storyboard.md 里),
5
+ * 于是模型很容易把"每一镜"写成画布上的**一个文本节点**——八镜就是八条,
6
+ * 排版一散,人看不出这是一张表;`motion_project create` 也无从读它。
7
+ *
8
+ * 这里的约定(与 docs/motion-video-playbook.md §4.1 对齐,实现以本文件为准):
9
+ *
10
+ * 【分镜表】 一张 Markdown 六列表:镜头 | 帧区间 | 镜头卡 | 这一镜要做什么 |
11
+ * 屏幕上出现什么 | 文案 / 声音。时长写成 `172f`(帧)或 `7.2s`。
12
+ * 【风格】 一行一个键值:page #F7F3EA / serif "Noto Serif SC" / materials: kraft
13
+ * 【旁白】 `## shot-N` 分节,一句一行(交给 motion_voice 合成)
14
+ *
15
+ * **一张就是一张**:同一张画布上出现第二个【分镜表】、或者一堆"一镜一个节点",
16
+ * 都在 validate 里报错 —— 这是这个流程最容易走偏的地方。
17
+ */
18
+ export const SPEC_MARKERS = {
19
+ storyboard: '【分镜表】',
20
+ style: '【风格】',
21
+ narration: '【旁白】',
22
+ }
23
+
24
+ const SEPARATOR = /^\|?\s*:?-{2,}:?\s*(\|\s*:?-{2,}:?\s*)*\|?$/
25
+ const TIME_PREFIX = /^\d+(?:\.\d+)?\s*(?:–|—|-|~|至)\s*\d+(?:\.\d+)?\s*s?\b/
26
+
27
+ export function specNodeOf(doc, marker) {
28
+ const nodes = Array.isArray(doc?.nodes) ? doc.nodes : []
29
+ for (const node of nodes) {
30
+ const label = typeof node.label === 'string' ? node.label : ''
31
+ if (firstLine(label) === marker) return node
32
+ }
33
+ return null
34
+ }
35
+
36
+ function firstLine(label) {
37
+ return String(label || '').trim().split('\n')[0].trim()
38
+ }
39
+
40
+ function cellText(raw) {
41
+ return String(raw === undefined || raw === null ? '' : raw)
42
+ .replace(/\*\*/g, '')
43
+ .replace(/`/g, '')
44
+ .trim()
45
+ }
46
+
47
+ // Cells are stored in the Markdown label so the canvas, AI and video project
48
+ // share one source of truth. Escape backslashes first, then pipes and newlines;
49
+ // a cell can therefore be edited without creating a new row or column.
50
+ export function escapeStoryboardCell(value) {
51
+ return String(value === undefined || value === null ? '' : value)
52
+ .replace(/\\/g, '\\\\')
53
+ .replace(/\|/g, '\\|')
54
+ .replace(/\r\n?/g, '\n')
55
+ .replace(/\n/g, '\\n')
56
+ }
57
+
58
+ // 行尾不带 `|` 也认:手写的表经常漏最后一竖。反斜杠只解码表格约定的
59
+ // 三种转义,其他反斜杠保留,以兼容已有文档中的路径等普通文本。
60
+ function rowCells(line, escaped = false) {
61
+ let text = String(line || '').trim()
62
+ if (text.startsWith('|')) text = text.slice(1)
63
+ if (!escaped) {
64
+ if (text.endsWith('|')) text = text.slice(0, -1)
65
+ return text.split('|').map(cellText)
66
+ }
67
+ const cells = []
68
+ let cell = ''
69
+ let lastWasSeparator = false
70
+ for (let index = 0; index < text.length; index += 1) {
71
+ const char = text[index]
72
+ if (char === '\\' && index + 1 < text.length) {
73
+ const next = text[index + 1]
74
+ if (next === '\\' || next === '|' || next === 'n') {
75
+ cell += next === 'n' ? '\n' : next
76
+ index += 1
77
+ lastWasSeparator = false
78
+ continue
79
+ }
80
+ }
81
+ if (char === '|') {
82
+ cells.push(cell.trim())
83
+ cell = ''
84
+ lastWasSeparator = true
85
+ } else {
86
+ cell += char
87
+ if (!/\s/.test(char)) lastWasSeparator = false
88
+ }
89
+ }
90
+ if (!lastWasSeparator || cell.trim().length > 0) cells.push(cell.trim())
91
+ return cells
92
+ }
93
+
94
+ /**
95
+ * 找出三块规格节点,并顺手诊断"分镜被拆成多条"这件事。
96
+ * @returns {{storyboard: object|null, style: object|null, narration: object|null, split: object[], extras: object[]}}
97
+ */
98
+ export function findSpecNodes(doc) {
99
+ const nodes = Array.isArray(doc?.nodes) ? doc.nodes : []
100
+ const out = { storyboard: null, style: null, narration: null, split: [], extras: [] }
101
+ for (const node of nodes) {
102
+ const label = typeof node.label === 'string' ? node.label : ''
103
+ const head = firstLine(label)
104
+ if (head === SPEC_MARKERS.storyboard) {
105
+ if (out.storyboard === null) out.storyboard = node
106
+ else out.extras.push(node)
107
+ continue
108
+ }
109
+ if (head === SPEC_MARKERS.style) {
110
+ if (out.style === null) out.style = node
111
+ else out.extras.push(node)
112
+ continue
113
+ }
114
+ if (head === SPEC_MARKERS.narration) {
115
+ if (out.narration === null) out.narration = node
116
+ else out.extras.push(node)
117
+ continue
118
+ }
119
+ // 一镜一节点的痕迹:以时间区间开头、带「|」的一行字("0.0–0.5s 静物|…")。
120
+ if (TIME_PREFIX.test(head) && /[||]/.test(label)) out.split.push(node)
121
+ }
122
+ return out
123
+ }
124
+
125
+ /** 把 `172f` / `7.2s` / `0–35f` / `0.0–0.5s` 解析成帧。 */
126
+ export function parseFrames(raw, fps = 30) {
127
+ const text = String(raw || '').replace(/\s+/g, '').replace(/帧/g, 'f')
128
+ const rate = Number(fps) > 0 ? Number(fps) : 30
129
+ const single = text.match(/^(\d+(?:\.\d+)?)(f|s)?$/)
130
+ if (single) {
131
+ const value = Number(single[1])
132
+ const unit = single[2] || 'f'
133
+ return { startFrame: null, endFrame: null, durationFrames: Math.max(1, Math.round(unit === 's' ? value * rate : value)) }
134
+ }
135
+ const span = text.match(/^(\d+(?:\.\d+)?)(f|s)?(?:–|—|-|~|至)(\d+(?:\.\d+)?)(f|s)?$/)
136
+ if (!span) return null
137
+ const unit = span[4] || span[2] || 'f'
138
+ const toFrames = (value) => Math.round(unit === 's' ? Number(value) * rate : Number(value))
139
+ // "0.0–0.5s":区间是**端点**(0 到 0.5 秒),不是"从 0 开始持续 0.5 秒"。
140
+ const a = toFrames(span[1])
141
+ const b = toFrames(span[3])
142
+ return { startFrame: Math.min(a, b), endFrame: Math.max(a, b), durationFrames: Math.abs(b - a) + (unit === 's' ? 0 : 1) }
143
+ }
144
+
145
+ function shotIdOf(raw, index) {
146
+ const text = cellText(raw)
147
+ const num = text.match(/(\d+)/)
148
+ return num ? 'shot-' + String(Number(num[1])) : 'shot-' + (index + 1)
149
+ }
150
+
151
+ /**
152
+ * 解析【分镜表】节点里的那张 Markdown 表。
153
+ * @returns {{rows: object[], problems: string[]}}
154
+ */
155
+ export function parseStoryboard(label, options = {}) {
156
+ const fps = Number(options.fps) > 0 ? Number(options.fps) : 30
157
+ const escaped = options.escaped === true
158
+ const lines = String(label || '').split('\n')
159
+ const tableLines = lines.filter((line) => line.trim().startsWith('|'))
160
+ const problems = []
161
+ const rows = []
162
+ if (tableLines.length === 0) {
163
+ problems.push('【分镜表】里没有 Markdown 表格(每行以 | 开头)')
164
+ return { rows, problems }
165
+ }
166
+ const body = tableLines.filter((line) => SEPARATOR.test(line.trim()) === false)
167
+ const header = body.shift()
168
+ const headerCells = rowCells(header, escaped)
169
+ if (headerCells.length !== 6) problems.push('表头应该是六列(镜头 | 帧区间 | 镜头卡 | 这一镜要做什么 | 屏幕上出现什么 | 文案 / 声音),现在是 ' + headerCells.length + ' 列')
170
+ let cursor = 0
171
+ for (const line of body) {
172
+ const cells = rowCells(line, escaped)
173
+ if (cells.length === 0) continue
174
+ if (cells.length !== 6) {
175
+ problems.push('第 ' + (rows.length + 1) + ' 行有 ' + cells.length + ' 列(应为 6 列):' + line.trim().slice(0, 40))
176
+ }
177
+ const shot = shotIdOf(cells[0], rows.length)
178
+ const frames = parseFrames(cellText(cells[1]), fps)
179
+ const durationFrames = frames === null ? 0 : frames.durationFrames
180
+ const startFrame = frames === null || frames.startFrame === null ? cursor : frames.startFrame
181
+ if (frames === null) problems.push(shot + ' 的帧区间读不出来("' + cells[1] + '"):写成 `0–35f` 或 `1.5s`')
182
+ rows.push({
183
+ shot,
184
+ startFrame,
185
+ durationFrames,
186
+ endFrame: startFrame + Math.max(0, durationFrames) - 1,
187
+ card: cells[2] === '—' || cells[2] === '-' ? '' : cells[2],
188
+ intent: cells[3] === '—' ? '' : cells[3],
189
+ onScreen: cells[4] === '—' ? '' : cells[4],
190
+ copy: cells[5] === '—' ? '' : cells[5],
191
+ })
192
+ cursor = startFrame + Math.max(1, durationFrames)
193
+ }
194
+ return { rows, problems }
195
+ }
196
+
197
+ /** 【风格】节点:`page #F7F3EA`、`serif "Noto Serif SC"`、`materials: kraft, ink`。 */
198
+ export function parseStyle(label) {
199
+ const tokens = {}
200
+ const fonts = {}
201
+ const materials = []
202
+ const problems = []
203
+ for (const raw of String(label || '').split('\n')) {
204
+ const line = raw.trim()
205
+ if (line.length === 0 || line === SPEC_MARKERS.style) continue
206
+ const pair = line.match(/^([A-Za-z][A-Za-z0-9_-]*)\s*[:=]?\s+(.+)$/)
207
+ if (!pair) continue
208
+ const key = pair[1].toLowerCase()
209
+ const value = pair[2].trim().replace(/^["'「]|["'」]$/g, '')
210
+ if (key === 'materials') {
211
+ materials.push(...value.split(/[,,、]/).map((item) => item.trim()).filter(Boolean))
212
+ continue
213
+ }
214
+ if (key === 'serif' || key === 'sans' || key === 'mono' || key === 'font') {
215
+ fonts[key === 'font' ? 'sans' : key] = value
216
+ continue
217
+ }
218
+ // 一行里塞了多个键(`page #F7F3EA accent #C0FF00`)非常常见,而且解析起来没有歧义:
219
+ // 直接全收下。旧版把这种行判成"不是颜色",错误信息指向完全错误的地方。
220
+ const pairs = [...line.matchAll(/([A-Za-z][A-Za-z0-9_-]*)\s*[:=]?\s*(#[0-9a-f]{3,8})\b/gi)]
221
+ if (pairs.length > 0) {
222
+ for (const match of pairs) tokens[match[1].toLowerCase()] = match[2]
223
+ continue
224
+ }
225
+ problems.push('【风格】里 "' + line.slice(0, 40) + '" 没认出颜色或字体(写成 `page #F7F3EA` 或 `serif "Noto Serif SC"`)')
226
+ }
227
+ return { tokens, fonts, materials, problems }
228
+ }
229
+
230
+ /** 【旁白】节点:`## shot-1` 分节,每句一行。 */
231
+ export function parseNarration(label) {
232
+ const sections = []
233
+ const problems = []
234
+ let current = null
235
+ for (const raw of String(label || '').split('\n')) {
236
+ const line = raw.trim()
237
+ if (line.length === 0 || line === SPEC_MARKERS.narration) continue
238
+ const heading = line.match(/^#{1,3}\s*(shot[-\s]?\d+)\s*$/i)
239
+ if (heading) {
240
+ current = { shot: 'shot-' + String(Number(heading[1].match(/\d+/)[0])), lines: [] }
241
+ sections.push(current)
242
+ continue
243
+ }
244
+ if (current === null) {
245
+ problems.push('【旁白】里 "' + line.slice(0, 24) + '" 前面没有 ## shot-N 分节')
246
+ continue
247
+ }
248
+ current.lines.push(line)
249
+ }
250
+ return { sections, problems }
251
+ }
252
+
253
+ /**
254
+ * 读画布上的规格三块。`fps` 用来把 `0.5s` 换算成帧(优先用视频节点上存的值)。
255
+ */
256
+ export function readCanvasSpec(doc, options = {}) {
257
+ const found = findSpecNodes(doc)
258
+ const fps = Number(options.fps) > 0 ? Number(options.fps) : 30
259
+ const storyboard = found.storyboard ? parseStoryboard(found.storyboard.label, {
260
+ fps, escaped: found.storyboard.data?.drawaiTableEscaped === '1',
261
+ }) : { rows: [], problems: [] }
262
+ const style = found.style ? parseStyle(found.style.label) : { tokens: {}, fonts: {}, materials: [], problems: [] }
263
+ const narration = found.narration ? parseNarration(found.narration.label) : { sections: [], problems: [] }
264
+ const problems = [
265
+ ...(found.storyboard ? [] : ['画布上还没有【分镜表】节点:先 motion_spec{action:"scaffold"} 建一张,再往里填各镜']),
266
+ ...storyboard.problems,
267
+ ...style.problems,
268
+ ...narration.problems,
269
+ ]
270
+ if (found.split.length > 0) {
271
+ problems.push('分镜被拆成了 ' + found.split.length + ' 个节点(' + found.split.map((node) => node.id).join(', ')
272
+ + '):分镜表只能有一张,用一张表把每一镜写成一行')
273
+ }
274
+ if (found.extras.length > 0) {
275
+ problems.push('有多余的规格节点(' + found.extras.map((node) => node.id).join(', ') + '):【分镜表】/【风格】/【旁白】各只该有一个')
276
+ }
277
+ return { storyboard: storyboard.rows, style, narration, problems, nodes: { storyboard: found.storyboard?.id ?? null, style: found.style?.id ?? null, narration: found.narration?.id ?? null } }
278
+ }
279
+
280
+ /**
281
+ * 校验画布规格跟视频节点对不对得上(motion_spec{action:"validate"} 的结果)。
282
+ * @returns {{errors: string[], warnings: string[]}}
283
+ */
284
+ export function validateCanvasSpec(doc, options = {}) {
285
+ const spec = options.spec || {}
286
+ const fps = Number(spec.fps) > 0 ? Number(spec.fps) : 30
287
+ const totalFrames = Number(spec.totalFrames) > 0 ? Number(spec.totalFrames) : (Number(spec.duration) > 0 ? Math.round(Number(spec.duration) * fps) : 0)
288
+ const read = readCanvasSpec(doc, { fps })
289
+ const errors = []
290
+ const warnings = []
291
+ const found = findSpecNodes(doc)
292
+ if (found.split.length > 0) errors.push('分镜表被拆成了 ' + found.split.length + ' 条:' + found.split.map((node) => node.id).join(', ') + '(只留一张【分镜表】)')
293
+ if (found.extras.length > 0) errors.push('重复的规格节点:' + found.extras.map((node) => node.id).join(', '))
294
+ if (found.storyboard === null) errors.push('缺【分镜表】节点')
295
+ const rows = read.storyboard
296
+ if (found.storyboard !== null) {
297
+ if (rows.length === 0) errors.push('【分镜表】里没有数据行')
298
+ let cursor = 0
299
+ for (const [index, row] of rows.entries()) {
300
+ if (row.shot !== 'shot-' + (index + 1)) errors.push('镜号要连号:第 ' + (index + 1) + ' 行是 ' + row.shot)
301
+ if (row.durationFrames <= 0) errors.push(row.shot + ' 没有有效时长')
302
+ if (row.startFrame !== cursor) warnings.push(row.shot + ' 从第 ' + row.startFrame + ' 帧开始,但上一镜结束在 ' + (cursor - 1) + ' 帧(表里的帧区间要连续)')
303
+ cursor = row.startFrame + Math.max(1, row.durationFrames)
304
+ if (!row.intent) warnings.push(row.shot + ' 没写"这一镜要做什么"')
305
+ if (!row.onScreen) warnings.push(row.shot + ' 没写"屏幕上出现什么"')
306
+ }
307
+ if (totalFrames > 0 && cursor !== totalFrames) {
308
+ const delta = totalFrames - cursor
309
+ errors.push('各镜加起来是 ' + cursor + ' 帧,视频节点是 ' + totalFrames + ' 帧(' + (delta > 0 ? '少 ' : '多 ') + Math.abs(delta) + ' 帧):'
310
+ + '两者必须相等。两种改法任选:把' + (delta > 0 ? '最后一镜延长 ' + delta + ' 帧' : '镜头删减/缩短共 ' + (-delta) + ' 帧')
311
+ + ',或把视频节点时长改成 ' + (cursor / fps) + ' 秒(motion_project create 的 spec.duration,现有工程改 timeline.json 的 durationInFrames)')
312
+ }
313
+ }
314
+ if (read.style.tokens && Object.keys(read.style.tokens).length === 0 && found.style !== null) {
315
+ warnings.push('【风格】里没有认出任何颜色(写成 `page #F7F3EA`)')
316
+ }
317
+ return { errors, warnings, read }
318
+ }
319
+
320
+ /** 一行分镜 → 表格行(帧区间写成 `0–35f`)。 */
321
+ export function storyboardRowLine(row) {
322
+ const start = Number(row.startFrame) || 0
323
+ const duration = Math.max(1, Number(row.durationFrames) || 1)
324
+ return '| ' + [row.shot, start + '–' + (start + duration - 1) + 'f', row.card || '—', row.intent || '—', row.onScreen || '—', row.copy || '—']
325
+ .map(escapeStoryboardCell).join(' | ') + ' |'
326
+ }
327
+
328
+ export const STORYBOARD_HEADER = '| 镜头 | 帧区间 | 镜头卡 | 这一镜要做什么 | 屏幕上出现什么 | 文案 / 声音 |\n| --- | --- | --- | --- | --- | --- |'
329
+
330
+ /**
331
+ * 把外部给的分镜(数组或 markdown)排成一张表。
332
+ * 数组项的 frames / duration 优先;否则在 totalFrames 里均分。
333
+ */
334
+ export function storyboardTable(input, options = {}) {
335
+ const fps = Number(options.fps) > 0 ? Number(options.fps) : 30
336
+ if (typeof input === 'string') {
337
+ const text = input.trim().replace(/^【分镜表】\s*\n/, '')
338
+ if (text.startsWith('|')) {
339
+ const lines = text.split('\n')
340
+ // A complete Markdown table already contains its header and separator.
341
+ // Row-only input still receives the canonical header as before.
342
+ if (lines.length > 1 && SEPARATOR.test(lines[1].trim())) return text
343
+ return STORYBOARD_HEADER + '\n' + text
344
+ }
345
+ }
346
+ const list = Array.isArray(input) ? input : []
347
+ const total = Number(options.totalFrames) > 0 ? Number(options.totalFrames) : 0
348
+ const per = list.length > 0 && total > 0 ? Math.floor(total / list.length) : Math.round(fps * 2)
349
+ const rows = []
350
+ let cursor = 0
351
+ list.forEach((item, index) => {
352
+ const row = typeof item === 'string' ? { intent: item } : (item || {})
353
+ const own = Number(row.durationFrames) > 0 ? Number(row.durationFrames) : (Number(row.frames) > 0 ? Number(row.frames) : per)
354
+ const duration = index === list.length - 1 && total > 0 ? Math.max(1, total - cursor) : Math.max(1, own)
355
+ rows.push({
356
+ shot: 'shot-' + (index + 1),
357
+ startFrame: cursor,
358
+ durationFrames: duration,
359
+ card: row.card || '',
360
+ intent: row.intent || row.what || row.beats || '',
361
+ onScreen: row.onScreen || row.screen || '',
362
+ copy: row.copy || '',
363
+ })
364
+ cursor += duration
365
+ })
366
+ return STORYBOARD_HEADER + '\n' + rows.map(storyboardRowLine).join('\n')
367
+ }
368
+
369
+ export function styleTemplate(style) {
370
+ if (typeof style === 'string' && style.trim().length > 0) return SPEC_MARKERS.style + '\n' + style.trim()
371
+ const palette = (style && style.palette) || {}
372
+ const fonts = (style && style.fonts) || {}
373
+ const lines = [SPEC_MARKERS.style]
374
+ for (const key of ['page', 'text', 'muted', 'accent', 'surface', 'field', 'border']) {
375
+ if (palette[key]) lines.push(key + ' ' + palette[key])
376
+ }
377
+ if (fonts.display) lines.push('serif "' + fonts.display + '"')
378
+ if (fonts.text) lines.push('sans "' + fonts.text + '"')
379
+ if (fonts.mono) lines.push('mono "' + fonts.mono + '"')
380
+ if (style && Array.isArray(style.materials) && style.materials.length) lines.push('materials: ' + style.materials.join(', '))
381
+ if (lines.length === 1) {
382
+ lines.push('page #F7F3EA', 'text #2B2B2B', 'muted #8A8578', 'accent #C0392B', 'border #D9D3C3')
383
+ }
384
+ return lines.join('\n')
385
+ }
386
+
387
+ const SPEC_WIDTH = { storyboard: 700, style: 440, narration: 440 }
388
+
389
+ /**
390
+ * 生成规格区的 diagram_apply ops:优先放视频左侧,空间不足时择优放到右侧。
391
+ *
392
+ * 只在缺的时候建:已经有【分镜表】就不再建第二张(那正是要避免的事)。
393
+ */
394
+ export function scaffoldOps(doc, options = {}) {
395
+ const found = findSpecNodes(doc)
396
+ const video = options.videoNode || null
397
+ const pending = []
398
+ const push = (marker, label, width, data) => {
399
+ // Estimate wrapped monospace lines as well as explicit newlines, including wide CJK characters.
400
+ const capacity = Math.max(1, Math.floor((width - 24) / 7.2))
401
+ const lines = label.split('\n').reduce((sum, line) => {
402
+ const cells = Array.from(line).reduce((n, char) => n + (char.codePointAt(0) >= 0x2e80 ? 2 : 1), 0)
403
+ return sum + Math.max(1, Math.ceil(cells / capacity))
404
+ }, 0)
405
+ pending.push({ marker, label, width, data, height: Math.max(80, Math.min(2000, 28 + lines * 18)) })
406
+ }
407
+ if (found.storyboard === null) push(SPEC_MARKERS.storyboard, SPEC_MARKERS.storyboard + '\n' + storyboardTable(options.storyboard || [], options), SPEC_WIDTH.storyboard,
408
+ typeof options.storyboard === 'string' ? undefined : { drawaiTableEscaped: '1' })
409
+ if (found.style === null) push(SPEC_MARKERS.style, options.style === undefined ? styleTemplate(options.styleKit || null) : styleTemplate(options.style), SPEC_WIDTH.style)
410
+ if (found.narration === null && options.narration !== undefined) {
411
+ push(SPEC_MARKERS.narration, SPEC_MARKERS.narration + '\n' + String(options.narration).trim(), SPEC_WIDTH.narration)
412
+ }
413
+ const validVideo = video && Number.isFinite(Number(video.x)) && Number.isFinite(Number(video.y))
414
+ const baseY = validVideo ? Math.max(40, Number(video.y) - 380) : 170
415
+ const width = Math.max(0, ...pending.map(item => item.width))
416
+ const height = pending.reduce((sum, item) => sum + item.height, 0) + Math.max(0, pending.length - 1) * 56
417
+ const candidates = validVideo
418
+ ? [Number(video.x) - width - 140, Number(video.x) + Math.max(0, Number(video.w) || 0) + 140].filter(x => x >= 40)
419
+ : [60]
420
+ const obstacles = (Array.isArray(doc?.nodes) ? doc.nodes : []).filter(node =>
421
+ Number.isFinite(Number(node.x)) && Number.isFinite(Number(node.y)) && Number(node.w) > 0 && Number(node.h) > 0)
422
+ const placement = candidates.map((x, index) => {
423
+ let y = baseY
424
+ // Keep the entire column clear of existing nodes; shift past any blocking rectangles.
425
+ for (let attempt = 0; attempt <= obstacles.length; attempt++) {
426
+ const hits = obstacles.filter(node => x < Number(node.x) + Number(node.w) + 50 && x + width + 50 > Number(node.x)
427
+ && y < Number(node.y) + Number(node.h) + 50 && y + height + 50 > Number(node.y))
428
+ if (!hits.length) break
429
+ y = Math.max(...hits.map(node => Number(node.y) + Number(node.h) + 50))
430
+ }
431
+ return { x, y, score: y - baseY + index * 10 }
432
+ }).sort((a, b) => a.score - b.score)[0] || { x: 60, y: baseY }
433
+ let y = placement.y
434
+ const ops = pending.map(item => {
435
+ const op = { op: 'addNode', shape: 'text', label: item.label, x: placement.x, y, w: item.width, h: item.height,
436
+ style: 'rounded=0;whiteSpace=wrap;html=1;fontSize=12;align=left;verticalAlign=top;fontFamily=monospace;fillColor=none;strokeColor=#c8c2b4;' }
437
+ if (item.data) op.data = item.data
438
+ y += item.height + 56
439
+ return op
440
+ })
441
+ return { ops, created: pending.map(item => item.marker), already: [found.storyboard ? SPEC_MARKERS.storyboard : '', found.style ? SPEC_MARKERS.style : '', found.narration ? SPEC_MARKERS.narration : ''].filter(Boolean) }
442
+ }
@@ -0,0 +1,95 @@
1
+ // 页面截屏:把一段 HTML 模板(或一个网址)在无头浏览器里渲染成 PNG,再进工程 assets/。
2
+ //
3
+ // 为什么要它:写产品界面镜头时,最费时间的不是动画,是"图从哪来"。
4
+ // 上游 skill 用一个 Playwright 脚本截模板;这里不引入 Playwright,
5
+ // 直接复用 Remotion 已经在用的 Chrome/Edge 二进制做一次性截屏。
6
+
7
+ import { existsSync, mkdirSync, statSync, writeFileSync } from 'node:fs'
8
+ import { join } from 'node:path'
9
+ import { execFile } from 'node:child_process'
10
+ import { promisify } from 'node:util'
11
+ import { pathToFileURL } from 'node:url'
12
+ import { captureAsset } from './assets.js'
13
+
14
+ const exec = promisify(execFile)
15
+
16
+ const POSIX = [
17
+ '/usr/bin/google-chrome',
18
+ '/usr/bin/chromium',
19
+ '/usr/bin/chromium-browser',
20
+ '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',
21
+ ]
22
+
23
+ const WINDOWS = [
24
+ 'C:/Program Files/Google/Chrome/Application/chrome.exe',
25
+ 'C:/Program Files (x86)/Google/Chrome/Application/chrome.exe',
26
+ 'C:/Program Files (x86)/Microsoft/Edge/Application/msedge.exe',
27
+ 'C:/Program Files/Microsoft/Edge/Application/msedge.exe',
28
+ ]
29
+
30
+ export function browserExecutable() {
31
+ const explicit = process.env.DRAWAI_CHROME_PATH
32
+ const list = [explicit, ...(process.platform === 'win32' ? WINDOWS : POSIX)].filter(Boolean)
33
+ for (const candidate of list) if (existsSync(candidate)) return candidate
34
+ throw new Error('找不到 Chrome / Edge:设 DRAWAI_CHROME_PATH 指向可执行文件后再试')
35
+ }
36
+
37
+ function clamp(value, min, max) {
38
+ const number = Number(value)
39
+ if (!Number.isFinite(number)) return min
40
+ return Math.max(min, Math.min(max, Math.round(number)))
41
+ }
42
+
43
+ function tail(error) {
44
+ const text = String(error?.stderr || error?.message || error)
45
+ const lines = text.split(/\r?\n/).filter((line) => line.trim())
46
+ return lines.slice(-2).join(' ') || '未知错误'
47
+ }
48
+
49
+ // 返回 assets/ 里的条目(与 motion_assets capture 同一种形状)。
50
+ export async function capturePage(dir, options = {}) {
51
+ const width = clamp(options.width || 1440, 320, 2560)
52
+ const height = clamp(options.height || 900, 240, 2560)
53
+ const scale = clamp(options.scale || 2, 1, 3)
54
+ const wait = clamp(options.wait ?? 1200, 0, 20000)
55
+ const name = String(options.name || 'page-' + Date.now()).replace(/[\\/:*?"<>|]/g, '-')
56
+ const work = join(dir, '.out', 'capture')
57
+ mkdirSync(work, { recursive: true })
58
+
59
+ let target
60
+ if (options.url) {
61
+ target = String(options.url)
62
+ if (!/^https?:|^file:/i.test(target)) throw new Error('url 必须是 http(s) 或 file: 开头')
63
+ } else if (options.html) {
64
+ const file = join(work, name + '.html')
65
+ writeFileSync(file, String(options.html), 'utf8')
66
+ target = pathToFileURL(file).href
67
+ } else {
68
+ throw new Error('page 需要 url 或 html(直接给 HTML 源文本更常见)')
69
+ }
70
+
71
+ const png = join(work, name + '.png')
72
+ const base = ['--disable-gpu', '--hide-scrollbars', '--no-first-run', '--no-default-browser-check',
73
+ '--force-device-scale-factor=' + scale, '--window-size=' + width + ',' + height,
74
+ '--virtual-time-budget=' + wait, '--screenshot=' + png]
75
+ const attempts = [['--headless=new', ...base, target], ['--headless', ...base, target]]
76
+ let failure
77
+ for (const args of attempts) {
78
+ try {
79
+ await exec(browserExecutable(), args, { windowsHide: true, timeout: 120000, maxBuffer: 8 * 1024 * 1024 })
80
+ failure = undefined
81
+ break
82
+ } catch (error) {
83
+ failure = error
84
+ }
85
+ }
86
+ if (failure) throw new Error('截屏失败:' + tail(failure))
87
+ if (!existsSync(png) || statSync(png).size < 1024) throw new Error('截屏没有产生图片(页面可能是空白或加载失败)')
88
+
89
+ const asset = await captureAsset(dir, png, {
90
+ name,
91
+ caption: options.caption || (options.url ? '页面截图 ' + target : 'HTML 模板截图'),
92
+ source: options.url ? 'page:' + target : 'page:html',
93
+ })
94
+ return { ...asset, viewport: { width, height, scale }, url: target }
95
+ }