@officexapp/vidfarm-devcli 0.21.10

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 (516) hide show
  1. package/.agents/skills/dollarplatoon-skill/SKILL.md +1227 -0
  2. package/.agents/skills/editor-capabilities/SKILL.md +182 -0
  3. package/.agents/skills/editor-capabilities/references/re-theme-walkthrough.md +58 -0
  4. package/.agents/skills/embedded-captions/CATALOG.md +93 -0
  5. package/.agents/skills/embedded-captions/SKILL.md +286 -0
  6. package/.agents/skills/embedded-captions/assets/brand/CDPR-fankit-terms.txt +35 -0
  7. package/.agents/skills/embedded-captions/assets/brand/cyberpunk-widths.json +115 -0
  8. package/.agents/skills/embedded-captions/assets/fonts/char-widths.json +2211 -0
  9. package/.agents/skills/embedded-captions/assets/strokefonts/HersheyScript1.svg +242 -0
  10. package/.agents/skills/embedded-captions/assets/strokefonts/HersheyScriptMed.svg +242 -0
  11. package/.agents/skills/embedded-captions/dna/README.md +148 -0
  12. package/.agents/skills/embedded-captions/dna/chrome.json +68 -0
  13. package/.agents/skills/embedded-captions/dna/cream.json +69 -0
  14. package/.agents/skills/embedded-captions/dna/documentary.json +62 -0
  15. package/.agents/skills/embedded-captions/dna/editorial.json +70 -0
  16. package/.agents/skills/embedded-captions/dna/glitch.json +82 -0
  17. package/.agents/skills/embedded-captions/dna/ink.json +65 -0
  18. package/.agents/skills/embedded-captions/dna/keynote.json +62 -0
  19. package/.agents/skills/embedded-captions/dna/loud.json +75 -0
  20. package/.agents/skills/embedded-captions/dna/neon.json +58 -0
  21. package/.agents/skills/embedded-captions/dna/velocity.json +89 -0
  22. package/.agents/skills/embedded-captions/modes/cinematic/README.md +48 -0
  23. package/.agents/skills/embedded-captions/modes/cinematic/_archive/champion/spec.md +98 -0
  24. package/.agents/skills/embedded-captions/modes/cinematic/_archive/champion/template.html +188 -0
  25. package/.agents/skills/embedded-captions/modes/cinematic/_archive/memory-wall/spec.md +134 -0
  26. package/.agents/skills/embedded-captions/modes/cinematic/_archive/memory-wall/template.html +179 -0
  27. package/.agents/skills/embedded-captions/modes/cinematic/_archive/portrait-header/spec.md +81 -0
  28. package/.agents/skills/embedded-captions/modes/cinematic/_archive/portrait-header/template.html +170 -0
  29. package/.agents/skills/embedded-captions/modes/cinematic/cinematic-cream/spec.md +16 -0
  30. package/.agents/skills/embedded-captions/modes/cinematic/cinematic-cream/template.html +226 -0
  31. package/.agents/skills/embedded-captions/modes/cinematic/engine.html +355 -0
  32. package/.agents/skills/embedded-captions/modes/standard/_anatomy.md +233 -0
  33. package/.agents/skills/embedded-captions/modes/standard/_motion.md +192 -0
  34. package/.agents/skills/embedded-captions/modes/standard/fonts/build-fonts-css.cjs +97 -0
  35. package/.agents/skills/embedded-captions/references/aesthetic-principles.md +168 -0
  36. package/.agents/skills/embedded-captions/references/anti-patterns.md +188 -0
  37. package/.agents/skills/embedded-captions/references/bespoke-vs-presets.md +178 -0
  38. package/.agents/skills/embedded-captions/references/caption-grouping.md +130 -0
  39. package/.agents/skills/embedded-captions/references/composition-craft.md +522 -0
  40. package/.agents/skills/embedded-captions/references/direction-catalog.md +138 -0
  41. package/.agents/skills/embedded-captions/references/example-renders/champion.html +371 -0
  42. package/.agents/skills/embedded-captions/references/example-renders/memory-wall.html +334 -0
  43. package/.agents/skills/embedded-captions/references/failure-modes.md +145 -0
  44. package/.agents/skills/embedded-captions/references/layout-heuristics.md +238 -0
  45. package/.agents/skills/embedded-captions/references/motion-vocabulary.md +148 -0
  46. package/.agents/skills/embedded-captions/references/rail.md +68 -0
  47. package/.agents/skills/embedded-captions/references/reference-bar.md +47 -0
  48. package/.agents/skills/embedded-captions/references/scene-types.md +94 -0
  49. package/.agents/skills/embedded-captions/references/test-set.md +66 -0
  50. package/.agents/skills/embedded-captions/references/typographic-moves.md +266 -0
  51. package/.agents/skills/embedded-captions/references/typography-presets.md +63 -0
  52. package/.agents/skills/embedded-captions/scripts/audio-envelope.cjs +95 -0
  53. package/.agents/skills/embedded-captions/scripts/check-occlusion.cjs +250 -0
  54. package/.agents/skills/embedded-captions/scripts/check-overflow.cjs +194 -0
  55. package/.agents/skills/embedded-captions/scripts/check-rail-climax.cjs +233 -0
  56. package/.agents/skills/embedded-captions/scripts/check-timing.cjs +173 -0
  57. package/.agents/skills/embedded-captions/scripts/fill-timings.cjs +124 -0
  58. package/.agents/skills/embedded-captions/scripts/fit-fonts.cjs +158 -0
  59. package/.agents/skills/embedded-captions/scripts/gen-stroke-path.py +46 -0
  60. package/.agents/skills/embedded-captions/scripts/inject-fonts.cjs +169 -0
  61. package/.agents/skills/embedded-captions/scripts/lib-dna.cjs +201 -0
  62. package/.agents/skills/embedded-captions/scripts/make-cinematic.cjs +1205 -0
  63. package/.agents/skills/embedded-captions/scripts/make-composition.cjs +404 -0
  64. package/.agents/skills/embedded-captions/scripts/make-theme.cjs +8781 -0
  65. package/.agents/skills/embedded-captions/scripts/matte.cjs +294 -0
  66. package/.agents/skills/embedded-captions/scripts/measure-layout.cjs +293 -0
  67. package/.agents/skills/embedded-captions/scripts/prepare.sh +39 -0
  68. package/.agents/skills/embedded-captions/scripts/preview-frames.cjs +268 -0
  69. package/.agents/skills/embedded-captions/scripts/render-and-composite.sh +509 -0
  70. package/.agents/skills/embedded-captions/scripts/render-theme.sh +34 -0
  71. package/.agents/skills/embedded-captions/scripts/safe-zones.cjs +813 -0
  72. package/.agents/skills/embedded-captions/scripts/transcribe.cjs +349 -0
  73. package/.agents/skills/embedded-captions/themes/PORTING.md +49 -0
  74. package/.agents/skills/embedded-captions/themes/README.md +244 -0
  75. package/.agents/skills/embedded-captions/themes/anchor.json +27 -0
  76. package/.agents/skills/embedded-captions/themes/arcade.json +51 -0
  77. package/.agents/skills/embedded-captions/themes/aurora.json +41 -0
  78. package/.agents/skills/embedded-captions/themes/biolume.json +35 -0
  79. package/.agents/skills/embedded-captions/themes/brush.json +74 -0
  80. package/.agents/skills/embedded-captions/themes/chalkboard.json +52 -0
  81. package/.agents/skills/embedded-captions/themes/dossier.json +56 -0
  82. package/.agents/skills/embedded-captions/themes/graffiti.json +62 -0
  83. package/.agents/skills/embedded-captions/themes/hologram.json +41 -0
  84. package/.agents/skills/embedded-captions/themes/inkwater.json +43 -0
  85. package/.agents/skills/embedded-captions/themes/laser.json +46 -0
  86. package/.agents/skills/embedded-captions/themes/lastpage.json +33 -0
  87. package/.agents/skills/embedded-captions/themes/neonsign.json +53 -0
  88. package/.agents/skills/embedded-captions/themes/nightcity.json +56 -0
  89. package/.agents/skills/embedded-captions/themes/ordnance.json +54 -0
  90. package/.agents/skills/embedded-captions/themes/papercut.json +37 -0
  91. package/.agents/skills/embedded-captions/themes/popup.json +46 -0
  92. package/.agents/skills/embedded-captions/themes/ransom.json +62 -0
  93. package/.agents/skills/embedded-captions/themes/scoreboard.json +54 -0
  94. package/.agents/skills/embedded-captions/themes/spectrum.json +46 -0
  95. package/.agents/skills/embedded-captions/themes/stardust.json +29 -0
  96. package/.agents/skills/embedded-captions/themes/stomp.json +43 -0
  97. package/.agents/skills/embedded-captions/themes/terminal.json +49 -0
  98. package/.agents/skills/embedded-captions/themes/thunder.json +44 -0
  99. package/.agents/skills/embedded-captions/themes/transit.json +44 -0
  100. package/.agents/skills/embedded-captions/themes/vhs.json +47 -0
  101. package/.agents/skills/faceless-explainer/SKILL.md +209 -0
  102. package/.agents/skills/faceless-explainer/references/cut-catalog.md +215 -0
  103. package/.agents/skills/faceless-explainer/references/motion-language.md +156 -0
  104. package/.agents/skills/faceless-explainer/references/story-design.md +248 -0
  105. package/.agents/skills/faceless-explainer/references/visual-design.md +146 -0
  106. package/.agents/skills/faceless-explainer/scripts/assemble-index.mjs +570 -0
  107. package/.agents/skills/faceless-explainer/scripts/audio.mjs +260 -0
  108. package/.agents/skills/faceless-explainer/scripts/build-frame.mjs +536 -0
  109. package/.agents/skills/faceless-explainer/scripts/captions.mjs +508 -0
  110. package/.agents/skills/faceless-explainer/scripts/lib/assets.mjs +55 -0
  111. package/.agents/skills/faceless-explainer/scripts/lib/dimensions.mjs +45 -0
  112. package/.agents/skills/faceless-explainer/scripts/lib/storyboard.mjs +249 -0
  113. package/.agents/skills/faceless-explainer/scripts/lib/tokens.mjs +204 -0
  114. package/.agents/skills/faceless-explainer/scripts/lib/transition-registry.mjs +38 -0
  115. package/.agents/skills/faceless-explainer/scripts/lib/transitions.json +71 -0
  116. package/.agents/skills/faceless-explainer/scripts/transitions.mjs +320 -0
  117. package/.agents/skills/faceless-explainer/sub-agents/frame-worker.md +75 -0
  118. package/.agents/skills/farmville-saas-ux/SKILL.md +156 -0
  119. package/.agents/skills/farmville-saas-ux/assets/starter.html +294 -0
  120. package/.agents/skills/farmville-saas-ux/references/components.md +340 -0
  121. package/.agents/skills/farmville-saas-ux/references/porting-guide.md +121 -0
  122. package/.agents/skills/farmville-saas-ux/references/tokens.md +271 -0
  123. package/.agents/skills/flockposter/LICENSE +17 -0
  124. package/.agents/skills/flockposter/README.md +72 -0
  125. package/.agents/skills/flockposter/SKILL.md +562 -0
  126. package/.agents/skills/flockposter/examples/cli-instagram-reel.sh +21 -0
  127. package/.agents/skills/flockposter/examples/cli-multi-platform.json +69 -0
  128. package/.agents/skills/flockposter/examples/cli-tiktok-upload-only.sh +22 -0
  129. package/.agents/skills/flockposter/examples/cli-x-thread.sh +17 -0
  130. package/.agents/skills/flockposter/examples/cli-youtube-short.sh +21 -0
  131. package/.agents/skills/flockposter/examples/public-api-instagram-reel.json +28 -0
  132. package/.agents/skills/general-video/SKILL.md +143 -0
  133. package/.agents/skills/hyperframes/SKILL.md +160 -0
  134. package/.agents/skills/hyperframes-animation/SKILL.md +84 -0
  135. package/.agents/skills/hyperframes-animation/adapters/animate-text.md +64 -0
  136. package/.agents/skills/hyperframes-animation/adapters/animejs.md +114 -0
  137. package/.agents/skills/hyperframes-animation/adapters/css-animations.md +143 -0
  138. package/.agents/skills/hyperframes-animation/adapters/gsap-easing-and-stagger.md +118 -0
  139. package/.agents/skills/hyperframes-animation/adapters/gsap-timeline-and-labels.md +96 -0
  140. package/.agents/skills/hyperframes-animation/adapters/gsap-transforms-and-perf.md +96 -0
  141. package/.agents/skills/hyperframes-animation/adapters/gsap.md +105 -0
  142. package/.agents/skills/hyperframes-animation/adapters/html-in-canvas-patterns.md +507 -0
  143. package/.agents/skills/hyperframes-animation/adapters/lottie.md +117 -0
  144. package/.agents/skills/hyperframes-animation/adapters/three.md +131 -0
  145. package/.agents/skills/hyperframes-animation/adapters/typegpu.md +178 -0
  146. package/.agents/skills/hyperframes-animation/adapters/waapi.md +101 -0
  147. package/.agents/skills/hyperframes-animation/blueprints/comparison-split.md +27 -0
  148. package/.agents/skills/hyperframes-animation/blueprints/constellation-hub.md +44 -0
  149. package/.agents/skills/hyperframes-animation/blueprints/cta-morph-press.md +28 -0
  150. package/.agents/skills/hyperframes-animation/blueprints/cursor-ui-demo.md +57 -0
  151. package/.agents/skills/hyperframes-animation/blueprints/dataviz-countup.md +46 -0
  152. package/.agents/skills/hyperframes-animation/blueprints/device-surface-showcase.md +53 -0
  153. package/.agents/skills/hyperframes-animation/blueprints/grid-card-assemble.md +66 -0
  154. package/.agents/skills/hyperframes-animation/blueprints/kinetic-type-beats.md +78 -0
  155. package/.agents/skills/hyperframes-animation/blueprints/logo-assemble-lockup.md +69 -0
  156. package/.agents/skills/hyperframes-animation/blueprints/overwhelm-surround.md +28 -0
  157. package/.agents/skills/hyperframes-animation/blueprints/spatial-pan-stations.md +37 -0
  158. package/.agents/skills/hyperframes-animation/blueprints/ticker-takeover.md +29 -0
  159. package/.agents/skills/hyperframes-animation/blueprints/titlecard-reveal.md +42 -0
  160. package/.agents/skills/hyperframes-animation/blueprints/typewriter-reveal.md +51 -0
  161. package/.agents/skills/hyperframes-animation/blueprints/video-text-pivot.md +30 -0
  162. package/.agents/skills/hyperframes-animation/blueprints-index.md +146 -0
  163. package/.agents/skills/hyperframes-animation/examples/assets/avatars/02.avif +0 -0
  164. package/.agents/skills/hyperframes-animation/examples/assets/brands/github.avif +0 -0
  165. package/.agents/skills/hyperframes-animation/examples/assets/brands/nvidia.avif +0 -0
  166. package/.agents/skills/hyperframes-animation/examples/assets/brands/visa.avif +0 -0
  167. package/.agents/skills/hyperframes-animation/examples/assets/brands/zoominfo.avif +0 -0
  168. package/.agents/skills/hyperframes-animation/examples/brand-reveal-assemble-zoom.html +382 -0
  169. package/.agents/skills/hyperframes-animation/examples/comparison-split-cards.html +649 -0
  170. package/.agents/skills/hyperframes-animation/examples/concept-demo-decode-pan.html +520 -0
  171. package/.agents/skills/hyperframes-animation/examples/cta-morph-press.html +468 -0
  172. package/.agents/skills/hyperframes-animation/examples/cta-orbit-collapse.html +1298 -0
  173. package/.agents/skills/hyperframes-animation/examples/demo-page-scroll-spotlight.html +759 -0
  174. package/.agents/skills/hyperframes-animation/examples/hook-counter-burst.html +729 -0
  175. package/.agents/skills/hyperframes-animation/examples/messaging-multi-phrase.html +352 -0
  176. package/.agents/skills/hyperframes-animation/examples/metric-video-text-pivot.html +779 -0
  177. package/.agents/skills/hyperframes-animation/examples/problem-mockup-overwhelm.html +1374 -0
  178. package/.agents/skills/hyperframes-animation/examples/proof-logo-chain.html +861 -0
  179. package/.agents/skills/hyperframes-animation/examples/takeover-ticker-displace.html +347 -0
  180. package/.agents/skills/hyperframes-animation/examples/workflow-approve-press.html +606 -0
  181. package/.agents/skills/hyperframes-animation/rules/3d-page-scroll.md +227 -0
  182. package/.agents/skills/hyperframes-animation/rules/3d-text-depth-layers.md +297 -0
  183. package/.agents/skills/hyperframes-animation/rules/ai-tracking-box.md +382 -0
  184. package/.agents/skills/hyperframes-animation/rules/ambient-glow-bloom.md +305 -0
  185. package/.agents/skills/hyperframes-animation/rules/asr-keyword-glow.md +286 -0
  186. package/.agents/skills/hyperframes-animation/rules/avatar-cloud-network.md +371 -0
  187. package/.agents/skills/hyperframes-animation/rules/camera-cursor-tracking.md +246 -0
  188. package/.agents/skills/hyperframes-animation/rules/card-morph-anchor.md +267 -0
  189. package/.agents/skills/hyperframes-animation/rules/center-outward-expansion.md +227 -0
  190. package/.agents/skills/hyperframes-animation/rules/context-sensitive-cursor.md +257 -0
  191. package/.agents/skills/hyperframes-animation/rules/coordinate-target-zoom.md +332 -0
  192. package/.agents/skills/hyperframes-animation/rules/counting-dynamic-scale.md +283 -0
  193. package/.agents/skills/hyperframes-animation/rules/css-marker-patterns.md +373 -0
  194. package/.agents/skills/hyperframes-animation/rules/cursor-click-ripple.md +262 -0
  195. package/.agents/skills/hyperframes-animation/rules/depth-of-field-blur.md +313 -0
  196. package/.agents/skills/hyperframes-animation/rules/depth-scatter-assemble.md +303 -0
  197. package/.agents/skills/hyperframes-animation/rules/discrete-text-sequence.md +273 -0
  198. package/.agents/skills/hyperframes-animation/rules/dynamic-content-sequencing.md +307 -0
  199. package/.agents/skills/hyperframes-animation/rules/gsap-effects.md +299 -0
  200. package/.agents/skills/hyperframes-animation/rules/hacker-flip-3d.md +223 -0
  201. package/.agents/skills/hyperframes-animation/rules/kinetic-beat-slam.md +183 -0
  202. package/.agents/skills/hyperframes-animation/rules/motion-blur-streak.md +328 -0
  203. package/.agents/skills/hyperframes-animation/rules/multi-phase-camera.md +273 -0
  204. package/.agents/skills/hyperframes-animation/rules/orbit-3d-entry.md +301 -0
  205. package/.agents/skills/hyperframes-animation/rules/physics-press-reaction.md +350 -0
  206. package/.agents/skills/hyperframes-animation/rules/press-release-spring.md +296 -0
  207. package/.agents/skills/hyperframes-animation/rules/reactive-displacement.md +277 -0
  208. package/.agents/skills/hyperframes-animation/rules/scale-swap-transition.md +298 -0
  209. package/.agents/skills/hyperframes-animation/rules/sine-wave-loop.md +278 -0
  210. package/.agents/skills/hyperframes-animation/rules/split-tilt-cards.md +277 -0
  211. package/.agents/skills/hyperframes-animation/rules/spring-pop-entrance.md +273 -0
  212. package/.agents/skills/hyperframes-animation/rules/stat-bars-and-fills.md +156 -0
  213. package/.agents/skills/hyperframes-animation/rules/svg-icon-enrichment.md +329 -0
  214. package/.agents/skills/hyperframes-animation/rules/svg-path-draw.md +274 -0
  215. package/.agents/skills/hyperframes-animation/rules/vertical-spring-ticker.md +239 -0
  216. package/.agents/skills/hyperframes-animation/rules/viewport-change.md +349 -0
  217. package/.agents/skills/hyperframes-animation/rules-index.md +86 -0
  218. package/.agents/skills/hyperframes-animation/scripts/animation-map.mjs +606 -0
  219. package/.agents/skills/hyperframes-animation/scripts/package-loader.mjs +288 -0
  220. package/.agents/skills/hyperframes-animation/scripts/package-loader.test.mjs +62 -0
  221. package/.agents/skills/hyperframes-animation/techniques.md +507 -0
  222. package/.agents/skills/hyperframes-animation/transitions/TRANSITION-REGISTRY.md +167 -0
  223. package/.agents/skills/hyperframes-animation/transitions/catalog.md +127 -0
  224. package/.agents/skills/hyperframes-animation/transitions/css-3d.md +12 -0
  225. package/.agents/skills/hyperframes-animation/transitions/css-blur.md +51 -0
  226. package/.agents/skills/hyperframes-animation/transitions/css-cover.md +43 -0
  227. package/.agents/skills/hyperframes-animation/transitions/css-destruction.md +95 -0
  228. package/.agents/skills/hyperframes-animation/transitions/css-dissolve.md +66 -0
  229. package/.agents/skills/hyperframes-animation/transitions/css-distortion.md +45 -0
  230. package/.agents/skills/hyperframes-animation/transitions/css-grid.md +10 -0
  231. package/.agents/skills/hyperframes-animation/transitions/css-light.md +49 -0
  232. package/.agents/skills/hyperframes-animation/transitions/css-mechanical.md +30 -0
  233. package/.agents/skills/hyperframes-animation/transitions/css-other.md +25 -0
  234. package/.agents/skills/hyperframes-animation/transitions/css-push.md +41 -0
  235. package/.agents/skills/hyperframes-animation/transitions/css-radial.md +37 -0
  236. package/.agents/skills/hyperframes-animation/transitions/css-scale.md +24 -0
  237. package/.agents/skills/hyperframes-animation/transitions/overview.md +153 -0
  238. package/.agents/skills/hyperframes-cli/SKILL.md +113 -0
  239. package/.agents/skills/hyperframes-cli/references/doctor-browser.md +45 -0
  240. package/.agents/skills/hyperframes-cli/references/init-and-scaffold.md +55 -0
  241. package/.agents/skills/hyperframes-cli/references/lambda.md +132 -0
  242. package/.agents/skills/hyperframes-cli/references/lint-validate-inspect.md +121 -0
  243. package/.agents/skills/hyperframes-cli/references/preview-render.md +149 -0
  244. package/.agents/skills/hyperframes-cli/references/upgrade-info-misc.md +75 -0
  245. package/.agents/skills/hyperframes-core/SKILL.md +78 -0
  246. package/.agents/skills/hyperframes-core/references/composition-patterns.md +263 -0
  247. package/.agents/skills/hyperframes-core/references/data-attributes.md +70 -0
  248. package/.agents/skills/hyperframes-core/references/determinism-rules.md +68 -0
  249. package/.agents/skills/hyperframes-core/references/full-screen-motion.md +62 -0
  250. package/.agents/skills/hyperframes-core/references/minimal-composition.md +66 -0
  251. package/.agents/skills/hyperframes-core/references/script-format.md +49 -0
  252. package/.agents/skills/hyperframes-core/references/storyboard-format.md +95 -0
  253. package/.agents/skills/hyperframes-core/references/sub-compositions.md +237 -0
  254. package/.agents/skills/hyperframes-core/references/subagent-dispatch.md +41 -0
  255. package/.agents/skills/hyperframes-core/references/tailwind.md +125 -0
  256. package/.agents/skills/hyperframes-core/references/tracks-and-clips.md +76 -0
  257. package/.agents/skills/hyperframes-core/references/variables-and-media.md +90 -0
  258. package/.agents/skills/hyperframes-creative/SKILL.md +70 -0
  259. package/.agents/skills/hyperframes-creative/frame-presets/biennale-yellow/FRAME.md +289 -0
  260. package/.agents/skills/hyperframes-creative/frame-presets/biennale-yellow/caption-skin.html +221 -0
  261. package/.agents/skills/hyperframes-creative/frame-presets/biennale-yellow/frame-showcase.html +1214 -0
  262. package/.agents/skills/hyperframes-creative/frame-presets/blockframe/FRAME.md +275 -0
  263. package/.agents/skills/hyperframes-creative/frame-presets/blockframe/caption-skin.html +224 -0
  264. package/.agents/skills/hyperframes-creative/frame-presets/blockframe/frame-showcase.html +1347 -0
  265. package/.agents/skills/hyperframes-creative/frame-presets/blue-professional/FRAME.md +307 -0
  266. package/.agents/skills/hyperframes-creative/frame-presets/blue-professional/caption-skin.html +223 -0
  267. package/.agents/skills/hyperframes-creative/frame-presets/blue-professional/frame-showcase.html +1372 -0
  268. package/.agents/skills/hyperframes-creative/frame-presets/bold-poster/FRAME.md +275 -0
  269. package/.agents/skills/hyperframes-creative/frame-presets/bold-poster/caption-skin.html +230 -0
  270. package/.agents/skills/hyperframes-creative/frame-presets/bold-poster/frame-showcase.html +1140 -0
  271. package/.agents/skills/hyperframes-creative/frame-presets/broadside/FRAME.md +284 -0
  272. package/.agents/skills/hyperframes-creative/frame-presets/broadside/caption-skin.html +225 -0
  273. package/.agents/skills/hyperframes-creative/frame-presets/broadside/frame-showcase.html +1166 -0
  274. package/.agents/skills/hyperframes-creative/frame-presets/capsule/FRAME.md +284 -0
  275. package/.agents/skills/hyperframes-creative/frame-presets/capsule/caption-skin.html +224 -0
  276. package/.agents/skills/hyperframes-creative/frame-presets/capsule/frame-showcase.html +1465 -0
  277. package/.agents/skills/hyperframes-creative/frame-presets/cartesian/FRAME.md +278 -0
  278. package/.agents/skills/hyperframes-creative/frame-presets/cartesian/caption-skin.html +222 -0
  279. package/.agents/skills/hyperframes-creative/frame-presets/cartesian/frame-showcase.html +1263 -0
  280. package/.agents/skills/hyperframes-creative/frame-presets/claude/FRAME.md +277 -0
  281. package/.agents/skills/hyperframes-creative/frame-presets/claude/caption-skin.html +224 -0
  282. package/.agents/skills/hyperframes-creative/frame-presets/claude/frame-showcase.html +1439 -0
  283. package/.agents/skills/hyperframes-creative/frame-presets/cobalt-grid/FRAME.md +265 -0
  284. package/.agents/skills/hyperframes-creative/frame-presets/cobalt-grid/caption-skin.html +238 -0
  285. package/.agents/skills/hyperframes-creative/frame-presets/cobalt-grid/frame-showcase.html +1468 -0
  286. package/.agents/skills/hyperframes-creative/frame-presets/coral/FRAME.md +314 -0
  287. package/.agents/skills/hyperframes-creative/frame-presets/coral/caption-skin.html +226 -0
  288. package/.agents/skills/hyperframes-creative/frame-presets/coral/frame-showcase.html +1268 -0
  289. package/.agents/skills/hyperframes-creative/frame-presets/creative-mode/FRAME.md +333 -0
  290. package/.agents/skills/hyperframes-creative/frame-presets/creative-mode/caption-skin.html +227 -0
  291. package/.agents/skills/hyperframes-creative/frame-presets/creative-mode/frame-showcase.html +1330 -0
  292. package/.agents/skills/hyperframes-creative/frame-presets/daisy-days/FRAME.md +274 -0
  293. package/.agents/skills/hyperframes-creative/frame-presets/daisy-days/caption-skin.html +230 -0
  294. package/.agents/skills/hyperframes-creative/frame-presets/daisy-days/frame-showcase.html +1444 -0
  295. package/.agents/skills/hyperframes-creative/frame-presets/editorial-forest/FRAME.md +265 -0
  296. package/.agents/skills/hyperframes-creative/frame-presets/editorial-forest/caption-skin.html +223 -0
  297. package/.agents/skills/hyperframes-creative/frame-presets/editorial-forest/frame-showcase.html +1273 -0
  298. package/.agents/skills/hyperframes-creative/palettes/bold-energetic.md +14 -0
  299. package/.agents/skills/hyperframes-creative/palettes/clean-corporate.md +14 -0
  300. package/.agents/skills/hyperframes-creative/palettes/dark-premium.md +14 -0
  301. package/.agents/skills/hyperframes-creative/palettes/jewel-rich.md +14 -0
  302. package/.agents/skills/hyperframes-creative/palettes/monochrome.md +14 -0
  303. package/.agents/skills/hyperframes-creative/palettes/nature-earth.md +14 -0
  304. package/.agents/skills/hyperframes-creative/palettes/neon-electric.md +14 -0
  305. package/.agents/skills/hyperframes-creative/palettes/pastel-soft.md +14 -0
  306. package/.agents/skills/hyperframes-creative/palettes/warm-editorial.md +14 -0
  307. package/.agents/skills/hyperframes-creative/references/audio-reactive.md +76 -0
  308. package/.agents/skills/hyperframes-creative/references/beat-direction.md +164 -0
  309. package/.agents/skills/hyperframes-creative/references/composition-patterns.md +199 -0
  310. package/.agents/skills/hyperframes-creative/references/data-in-motion.md +19 -0
  311. package/.agents/skills/hyperframes-creative/references/design-adherence.md +19 -0
  312. package/.agents/skills/hyperframes-creative/references/design-picker.md +123 -0
  313. package/.agents/skills/hyperframes-creative/references/design-spec.md +55 -0
  314. package/.agents/skills/hyperframes-creative/references/house-style.md +73 -0
  315. package/.agents/skills/hyperframes-creative/references/motion-principles.md +150 -0
  316. package/.agents/skills/hyperframes-creative/references/narration.md +92 -0
  317. package/.agents/skills/hyperframes-creative/references/prompt-expansion.md +68 -0
  318. package/.agents/skills/hyperframes-creative/references/typography.md +218 -0
  319. package/.agents/skills/hyperframes-creative/references/video-composition.md +63 -0
  320. package/.agents/skills/hyperframes-creative/references/visual-styles.md +457 -0
  321. package/.agents/skills/hyperframes-creative/scripts/contrast-report.mjs +353 -0
  322. package/.agents/skills/hyperframes-creative/scripts/extract-audio-data.py +188 -0
  323. package/.agents/skills/hyperframes-creative/scripts/package-loader.mjs +288 -0
  324. package/.agents/skills/hyperframes-creative/scripts/package-loader.test.mjs +62 -0
  325. package/.agents/skills/hyperframes-creative/templates/design-picker.html +1432 -0
  326. package/.agents/skills/hyperframes-keyframes/SKILL.md +237 -0
  327. package/.agents/skills/hyperframes-keyframes/agents/openai.yaml +4 -0
  328. package/.agents/skills/hyperframes-keyframes/references/keyframe-patterns.md +106 -0
  329. package/.agents/skills/motion-graphics/SKILL.md +172 -0
  330. package/.agents/skills/motion-graphics/agents/builder.md +40 -0
  331. package/.agents/skills/motion-graphics/agents/director.md +53 -0
  332. package/.agents/skills/motion-graphics/agents/finalize.md +17 -0
  333. package/.agents/skills/motion-graphics/catalog-map.md +40 -0
  334. package/.agents/skills/motion-graphics/categories/asset-fusion/module.md +37 -0
  335. package/.agents/skills/motion-graphics/categories/charts/module.md +21 -0
  336. package/.agents/skills/motion-graphics/categories/kinetic-type/module.md +19 -0
  337. package/.agents/skills/motion-graphics/categories/logo-reveal/module.md +17 -0
  338. package/.agents/skills/motion-graphics/categories/lower-thirds/module.md +16 -0
  339. package/.agents/skills/motion-graphics/categories/maps/bake-basemap.mjs +273 -0
  340. package/.agents/skills/motion-graphics/categories/maps/module.md +61 -0
  341. package/.agents/skills/motion-graphics/categories/news/module.md +56 -0
  342. package/.agents/skills/motion-graphics/categories/stat/module.md +21 -0
  343. package/.agents/skills/motion-graphics/categories/tweet/module.md +16 -0
  344. package/.agents/skills/motion-graphics/categories/webpage/module.md +21 -0
  345. package/.agents/skills/motion-graphics/grounding/PROTOCOL.md +64 -0
  346. package/.agents/skills/motion-graphics/grounding/locate.mjs +227 -0
  347. package/.agents/skills/motion-graphics/phases/source/guide.md +21 -0
  348. package/.agents/skills/motion-graphics/references/builder-contract.md +38 -0
  349. package/.agents/skills/motion-graphics/references/motion-vocabulary.md +43 -0
  350. package/.agents/skills/motion-graphics/references/shot-plan-ir.md +54 -0
  351. package/.agents/skills/motion-graphics/samples/asset-fusion/_ref-circle-highlight.html +306 -0
  352. package/.agents/skills/music/SKILL.md +416 -0
  353. package/.agents/skills/music/references/api_reference.md +519 -0
  354. package/.agents/skills/music/references/installation.md +65 -0
  355. package/.agents/skills/product-launch-video/SKILL.md +208 -0
  356. package/.agents/skills/product-launch-video/references/cut-catalog.md +220 -0
  357. package/.agents/skills/product-launch-video/references/motion-language.md +156 -0
  358. package/.agents/skills/product-launch-video/references/story-design.md +373 -0
  359. package/.agents/skills/product-launch-video/references/visual-design.md +126 -0
  360. package/.agents/skills/product-launch-video/scripts/assemble-index.mjs +570 -0
  361. package/.agents/skills/product-launch-video/scripts/audio.mjs +260 -0
  362. package/.agents/skills/product-launch-video/scripts/build-frame.mjs +536 -0
  363. package/.agents/skills/product-launch-video/scripts/captions.mjs +508 -0
  364. package/.agents/skills/product-launch-video/scripts/lib/assets.mjs +55 -0
  365. package/.agents/skills/product-launch-video/scripts/lib/dimensions.mjs +45 -0
  366. package/.agents/skills/product-launch-video/scripts/lib/pad-frame-duration.mjs +36 -0
  367. package/.agents/skills/product-launch-video/scripts/lib/pad-frame-duration.test.mjs +76 -0
  368. package/.agents/skills/product-launch-video/scripts/lib/storyboard.mjs +249 -0
  369. package/.agents/skills/product-launch-video/scripts/lib/tokens.mjs +204 -0
  370. package/.agents/skills/product-launch-video/scripts/lib/transition-registry.mjs +38 -0
  371. package/.agents/skills/product-launch-video/scripts/lib/transitions.json +71 -0
  372. package/.agents/skills/product-launch-video/scripts/stage-assets.mjs +39 -0
  373. package/.agents/skills/product-launch-video/scripts/transitions.mjs +327 -0
  374. package/.agents/skills/product-launch-video/sub-agents/frame-worker.md +75 -0
  375. package/.agents/skills/slideshow/SKILL.md +550 -0
  376. package/.agents/skills/slideshow/references/standalone-harness.md +1020 -0
  377. package/.agents/skills/talking-head-recut/NOTICE.md +39 -0
  378. package/.agents/skills/talking-head-recut/SKILL.md +1195 -0
  379. package/.agents/skills/talking-head-recut/assets/vendor/gsap.min.js +10 -0
  380. package/.agents/skills/talking-head-recut/references/DESIGN_INDEX.md +145 -0
  381. package/.agents/skills/talking-head-recut/references/frames/clean.html +92 -0
  382. package/.agents/skills/talking-head-recut/references/frames/hairline.html +171 -0
  383. package/.agents/skills/talking-head-recut/references/frames/polaroid.html +131 -0
  384. package/.agents/skills/talking-head-recut/references/layouts/overlay.html +164 -0
  385. package/.agents/skills/talking-head-recut/references/layouts/pip.html +143 -0
  386. package/.agents/skills/talking-head-recut/references/layouts/split.html +121 -0
  387. package/.agents/skills/talking-head-recut/references/layouts/stack.html +109 -0
  388. package/.agents/skills/talking-head-recut/references/styles/academic.html +172 -0
  389. package/.agents/skills/talking-head-recut/references/styles/audit.html +170 -0
  390. package/.agents/skills/talking-head-recut/references/styles/editorial.html +189 -0
  391. package/.agents/skills/talking-head-recut/references/styles/geom.html +181 -0
  392. package/.agents/skills/talking-head-recut/references/styles/minimal.html +130 -0
  393. package/.agents/skills/talking-head-recut/references/styles/spotlight.html +142 -0
  394. package/.agents/skills/talking-head-recut/references/styles/swiss.html +188 -0
  395. package/.agents/skills/talking-head-recut/references/styles/terminal.html +196 -0
  396. package/.agents/skills/talking-head-recut/references/styles/whiteboard.html +170 -0
  397. package/.agents/skills/talking-head-recut/references/styles/xhs.html +206 -0
  398. package/.agents/skills/text-to-speech/SKILL.md +226 -0
  399. package/.agents/skills/text-to-speech/references/installation.md +90 -0
  400. package/.agents/skills/text-to-speech/references/streaming.md +307 -0
  401. package/.agents/skills/text-to-speech/references/voice-settings.md +115 -0
  402. package/.agents/skills/vidfarm-director/SKILL.md +179 -0
  403. package/.agents/skills/vidfarm-director/recipes/find-and-fork-template.md +16 -0
  404. package/.agents/skills/vidfarm-director/recipes/local-edit-render-approve.md +13 -0
  405. package/.agents/skills/vidfarm-director/recipes/onboard-a-new-director.md +13 -0
  406. package/.agents/skills/vidfarm-director/recipes/retheme-template.md +17 -0
  407. package/.agents/skills/vidfarm-director/references/assets-and-sourcing.md +117 -0
  408. package/.agents/skills/vidfarm-director/references/automation-and-local-dev.md +276 -0
  409. package/.agents/skills/vidfarm-director/references/core-workflows.md +301 -0
  410. package/.agents/skills/vidfarm-director/references/editor-workflows.md +367 -0
  411. package/.agents/skills/vidfarm-director/references/onboarding.md +28 -0
  412. package/.agents/skills/vidfarm-director/references/primitives.md +307 -0
  413. package/.agents/skills/vidfarm-director/references/rest-api.md +84 -0
  414. package/.agents/skills/vidfarm-media/SKILL.md +158 -0
  415. package/.agents/skills/vidfarm-media/references/tts.md +111 -0
  416. package/.agents/skills/vidfarm-media/scripts/audio.mjs +628 -0
  417. package/.agents/skills/vidfarm-media/scripts/wait-bgm.mjs +31 -0
  418. package/.agents/skills/website-to-video/SKILL.md +145 -0
  419. package/.agents/skills/website-to-video/assets/sfx/CREDITS.md +35 -0
  420. package/.agents/skills/website-to-video/assets/sfx/manifest.json +97 -0
  421. package/.agents/skills/website-to-video/references/beat-builder-guide.md +263 -0
  422. package/.agents/skills/website-to-video/references/capabilities.md +713 -0
  423. package/.agents/skills/website-to-video/references/step-0-capture.md +55 -0
  424. package/.agents/skills/website-to-video/references/step-1-design.md +333 -0
  425. package/.agents/skills/website-to-video/references/step-2-brief.md +178 -0
  426. package/.agents/skills/website-to-video/references/step-3-storyboard.md +572 -0
  427. package/.agents/skills/website-to-video/references/step-4-vo.md +225 -0
  428. package/.agents/skills/website-to-video/references/step-5-build.md +483 -0
  429. package/.agents/skills/website-to-video/references/step-6-validate.md +341 -0
  430. package/.agents/skills/website-to-video/scripts/w2h-verify.mjs +759 -0
  431. package/README.md +97 -0
  432. package/SKILL.director.md +1644 -0
  433. package/SKILL.md +83 -0
  434. package/demo/README.md +28 -0
  435. package/demo/dist/app.css +1 -0
  436. package/demo/dist/app.js +968 -0
  437. package/demo/dist/chunks/chunk-3OT2D42H.js +1 -0
  438. package/demo/dist/chunks/chunk-DXB73IDG.js +1 -0
  439. package/demo/dist/chunks/domEditingLayers-AT7G6F4L-ZTHJHB7R.js +1 -0
  440. package/demo/dist/chunks/hyperframes-player-7HKH6NSO.js +459 -0
  441. package/demo/dist/chunks/lib-XAQ37YOE.js +1 -0
  442. package/demo/dist/chunks/src-TJ2QYA4U.js +207 -0
  443. package/demo/dist/favicon.ico +0 -0
  444. package/demo/dist/icons/timeline/audio.svg +7 -0
  445. package/demo/dist/icons/timeline/captions.svg +5 -0
  446. package/demo/dist/icons/timeline/composition.svg +12 -0
  447. package/demo/dist/icons/timeline/image.svg +18 -0
  448. package/demo/dist/icons/timeline/music.svg +10 -0
  449. package/demo/dist/icons/timeline/text.svg +3 -0
  450. package/demo/dist/index.html +16 -0
  451. package/dist/src/cli.js +7258 -0
  452. package/dist/src/devcli/auth-store.js +67 -0
  453. package/dist/src/devcli/captions.js +310 -0
  454. package/dist/src/devcli/clip-store.js +368 -0
  455. package/dist/src/devcli/clips.js +1138 -0
  456. package/dist/src/devcli/composition-edit.js +1292 -0
  457. package/dist/src/devcli/cost-mode.js +149 -0
  458. package/dist/src/devcli/doctor.js +192 -0
  459. package/dist/src/devcli/hyperframes-cli.js +118 -0
  460. package/dist/src/devcli/local-backend.js +167 -0
  461. package/dist/src/devcli/local-frontend-server.js +681 -0
  462. package/dist/src/devcli/local-render.js +136 -0
  463. package/dist/src/devcli/skills.js +476 -0
  464. package/dist/src/devcli/speech.js +178 -0
  465. package/dist/src/devcli/stills.js +249 -0
  466. package/dist/src/devcli/telemetry.js +236 -0
  467. package/dist/src/devcli/timeline-edit.js +490 -0
  468. package/dist/src/devcli/transitions.js +205 -0
  469. package/dist/src/hyperframes/composition.js +780 -0
  470. package/dist/src/lib/crypto.js +45 -0
  471. package/dist/src/lib/dev-log.js +54 -0
  472. package/dist/src/lib/display-name.js +11 -0
  473. package/dist/src/lib/ids.js +24 -0
  474. package/dist/src/lib/images.js +19 -0
  475. package/dist/src/lib/json.js +15 -0
  476. package/dist/src/lib/package-root.js +47 -0
  477. package/dist/src/lib/render-media-prep.js +293 -0
  478. package/dist/src/lib/template-paths.js +28 -0
  479. package/dist/src/lib/time.js +7 -0
  480. package/dist/src/lib/url-clean.js +85 -0
  481. package/dist/src/services/captions.js +123 -0
  482. package/dist/src/services/clip-curation/cost.js +116 -0
  483. package/dist/src/services/clip-curation/ffmpeg.js +352 -0
  484. package/dist/src/services/clip-curation/gemini.js +418 -0
  485. package/dist/src/services/clip-curation/hunt.js +470 -0
  486. package/dist/src/services/clip-curation/index.js +19 -0
  487. package/dist/src/services/clip-curation/local-agent.js +248 -0
  488. package/dist/src/services/clip-curation/media-select.js +152 -0
  489. package/dist/src/services/clip-curation/presets.js +20 -0
  490. package/dist/src/services/clip-curation/presets.v1.json +59 -0
  491. package/dist/src/services/clip-curation/query.js +167 -0
  492. package/dist/src/services/clip-curation/refine.js +165 -0
  493. package/dist/src/services/clip-curation/scan.js +189 -0
  494. package/dist/src/services/clip-curation/source-naming.js +131 -0
  495. package/dist/src/services/clip-curation/taxonomy.js +73 -0
  496. package/dist/src/services/clip-curation/taxonomy.v1.json +102 -0
  497. package/dist/src/services/clip-curation/types.js +7 -0
  498. package/dist/src/services/composition-lint.js +199 -0
  499. package/dist/src/services/provider-errors.js +128 -0
  500. package/dist/src/services/speech.js +629 -0
  501. package/package.json +154 -0
  502. package/public/assets/discover-client-app.js +1 -0
  503. package/public/assets/favicon.ico +0 -0
  504. package/public/assets/file-directory-app.js +89 -0
  505. package/public/assets/homepage-app.js +54 -0
  506. package/public/assets/homepage-client-app.js +80 -0
  507. package/public/assets/landing-page-client-app.js +87 -0
  508. package/public/assets/logo-vidfarm.png +0 -0
  509. package/public/assets/page-runtime-client-app.js +94 -0
  510. package/public/assets/placeholders/scene-placeholder.png +0 -0
  511. package/public/serve-shells/editor.html +3146 -0
  512. package/public/serve-shells/library-files.html +3450 -0
  513. package/public/serve-shells/library-raws.html +4404 -0
  514. package/public/serve-shells/tools-clipper.html +3991 -0
  515. package/public/serve-shells/tools-image.html +5584 -0
  516. package/public/serve-shells/tools-video.html +4404 -0
@@ -0,0 +1,123 @@
1
+ // Turns a transcript into animated-caption cues. Shared by the devcli
2
+ // `captions` command group, the /editor chat agent's set_captions action, and
3
+ // any server surface that wants captions from STT output. Pure — no network,
4
+ // no filesystem — so it is safe to import from the devcli.
5
+ //
6
+ // A "cue" is one caption layer on the timeline: a short run of words shown
7
+ // together (CapCut-style pages of ~3-5 words), with per-word windows relative
8
+ // to the cue start driving the animation. Word timings come from the provider
9
+ // when available (openai whisper-1) and are char-weight estimated inside each
10
+ // segment otherwise (gemini estimates, hand-typed text) — see
11
+ // estimateCaptionWords.
12
+ import { estimateCaptionWords } from "../hyperframes/composition.js";
13
+ const CUE_TAIL_SEC = 0.12;
14
+ const MIN_WORD_SPAN_SEC = 0.05;
15
+ /** Flattens transcript segments into absolute-timed words, estimating windows
16
+ * for segments the provider left word-less (or entirely time-less — those
17
+ * distribute across fallbackDurationSec). */
18
+ export function transcriptWordTimeline(segments, fallbackDurationSec) {
19
+ const words = [];
20
+ const timeless = segments.filter((segment) => typeof segment.start_sec !== "number");
21
+ for (const segment of segments) {
22
+ if (segment.words?.length) {
23
+ words.push(...segment.words.map((word) => ({ ...word, text: word.text.trim() })).filter((word) => word.text));
24
+ continue;
25
+ }
26
+ let base;
27
+ let span;
28
+ if (typeof segment.start_sec === "number") {
29
+ base = segment.start_sec;
30
+ span = typeof segment.end_sec === "number" && segment.end_sec > segment.start_sec
31
+ ? segment.end_sec - segment.start_sec
32
+ : 0;
33
+ }
34
+ else {
35
+ // No timings at all (plain-text providers): spread the blob across the
36
+ // caller-provided window so captions still land somewhere sensible.
37
+ base = 0;
38
+ span = Number.isFinite(fallbackDurationSec) && fallbackDurationSec > 0 && timeless.length
39
+ ? fallbackDurationSec / timeless.length
40
+ : 0;
41
+ if (timeless.length > 1) {
42
+ base = (span || 0) * timeless.indexOf(segment);
43
+ }
44
+ }
45
+ const estimated = estimateCaptionWords(segment.text, span);
46
+ words.push(...estimated.map((word) => ({
47
+ text: word.text,
48
+ start_sec: base + word.start,
49
+ end_sec: base + word.end
50
+ })));
51
+ }
52
+ return words
53
+ .filter((word) => Number.isFinite(word.start_sec) && Number.isFinite(word.end_sec) && word.end_sec > word.start_sec)
54
+ .sort((a, b) => a.start_sec - b.start_sec);
55
+ }
56
+ export function buildCaptionCues(segments, options) {
57
+ const words = transcriptWordTimeline(segments, options?.fallbackDurationSec);
58
+ return cuesFromWordTimeline(words, options);
59
+ }
60
+ export function cuesFromWordTimeline(words, options) {
61
+ const maxWords = Math.max(1, Math.round(options?.maxWordsPerCue ?? 4));
62
+ const maxDuration = Math.max(0.4, options?.maxCueDurationSec ?? 2.6);
63
+ const gapBreak = Math.max(0.15, options?.gapBreakSec ?? 0.6);
64
+ const offset = Number.isFinite(options?.offsetSec) ? options?.offsetSec : 0;
65
+ const cues = [];
66
+ let bucket = [];
67
+ const flush = () => {
68
+ if (!bucket.length)
69
+ return;
70
+ const start = bucket[0].start_sec;
71
+ const end = bucket[bucket.length - 1].end_sec + CUE_TAIL_SEC;
72
+ cues.push({
73
+ text: bucket.map((word) => word.text).join(" "),
74
+ start: round3(start + offset),
75
+ duration: round3(Math.max(MIN_WORD_SPAN_SEC * bucket.length, end - start)),
76
+ words: bucket.map((word) => ({
77
+ text: word.text,
78
+ start: round3(Math.max(0, word.start_sec - start)),
79
+ end: round3(Math.max(word.start_sec - start + MIN_WORD_SPAN_SEC, word.end_sec - start))
80
+ }))
81
+ });
82
+ bucket = [];
83
+ };
84
+ for (const word of words) {
85
+ if (bucket.length) {
86
+ const cueStart = bucket[0].start_sec;
87
+ const previous = bucket[bucket.length - 1];
88
+ const silence = word.start_sec - previous.end_sec;
89
+ const wouldRun = word.end_sec - cueStart;
90
+ const sentenceBreak = /[.!?…]["')\]]?$/.test(previous.text);
91
+ if (bucket.length >= maxWords || silence > gapBreak || wouldRun > maxDuration || sentenceBreak) {
92
+ flush();
93
+ }
94
+ }
95
+ bucket.push(word);
96
+ }
97
+ flush();
98
+ // Clamp each cue against the next so consecutive caption layers never
99
+ // overlap on the shared track (one-clip-per-(track,time) invariant).
100
+ for (let index = 0; index < cues.length - 1; index += 1) {
101
+ const cue = cues[index];
102
+ const next = cues[index + 1];
103
+ const maxEnd = next.start - 0.02;
104
+ if (cue.start + cue.duration > maxEnd) {
105
+ cue.duration = round3(Math.max(MIN_WORD_SPAN_SEC, maxEnd - cue.start));
106
+ }
107
+ }
108
+ return cues.filter((cue) => cue.duration > 0);
109
+ }
110
+ /** Cues straight from plain text spread across a window — the no-transcript
111
+ * path (AI-authored captions, manual cue text). */
112
+ export function cuesFromText(text, startSec, durationSec, options) {
113
+ const words = estimateCaptionWords(text, durationSec).map((word) => ({
114
+ text: word.text,
115
+ start_sec: startSec + word.start,
116
+ end_sec: startSec + word.end
117
+ }));
118
+ return cuesFromWordTimeline(words, options);
119
+ }
120
+ function round3(value) {
121
+ return Number(value.toFixed(3));
122
+ }
123
+ //# sourceMappingURL=captions.js.map
@@ -0,0 +1,116 @@
1
+ // Cost estimation for a scan — surfaced BEFORE every scan (success criterion #6)
2
+ // and used by the devcli --dry-run gate. Provider/model-aware: prices the
3
+ // resolved tagging model (gemini / openai gpt-5.4-nano / openrouter gemini) plus
4
+ // the embedding model. BYOK: this is the LLM spend the user pays directly.
5
+ function envPrice(envKey, fallback) {
6
+ const v = Number(process.env[envKey]);
7
+ return Number.isFinite(v) && v > 0 ? v : fallback;
8
+ }
9
+ // Approximate list prices, USD per 1M tokens (overridable via env). Estimates —
10
+ // the real bill comes from the user's provider account.
11
+ const MODEL_PRICING = {
12
+ "gemini-2.5-flash-lite": { input: envPrice("VIDFARM_PRICE_FLASH_LITE_INPUT", 0.1), output: envPrice("VIDFARM_PRICE_FLASH_LITE_OUTPUT", 0.4) },
13
+ "gemini-2.5-flash": { input: envPrice("VIDFARM_PRICE_FLASH_INPUT", 0.3), output: envPrice("VIDFARM_PRICE_FLASH_OUTPUT", 2.5) },
14
+ // OpenRouter adds a small markup over Google's list price.
15
+ "google/gemini-2.5-flash": { input: envPrice("VIDFARM_PRICE_OR_FLASH_INPUT", 0.315), output: envPrice("VIDFARM_PRICE_OR_FLASH_OUTPUT", 2.625) },
16
+ "gpt-5.4-nano": { input: envPrice("VIDFARM_PRICE_GPT5_NANO_INPUT", 0.05), output: envPrice("VIDFARM_PRICE_GPT5_NANO_OUTPUT", 0.4) },
17
+ // Nvidia lite clipping model (minimaxai/minimax-m3) — approximate, env-overridable.
18
+ "minimaxai/minimax-m3": { input: envPrice("VIDFARM_PRICE_NVIDIA_MINIMAX_INPUT", 0.15), output: envPrice("VIDFARM_PRICE_NVIDIA_MINIMAX_OUTPUT", 0.6) }
19
+ };
20
+ const DEFAULT_TAG_PRICING = { input: 0.15, output: 0.6 };
21
+ const EMBED_PRICING = {
22
+ "gemini-embedding-001": envPrice("VIDFARM_PRICE_EMBEDDING_INPUT", 0.15),
23
+ "text-embedding-3-small": envPrice("VIDFARM_PRICE_OPENAI_EMBEDDING_INPUT", 0.02)
24
+ };
25
+ // Low-res image tokens: Gemini media_resolution LOW = 66/frame; OpenAI
26
+ // low-detail ≈ 85/frame. Audio ~32 tok/sec (Gemini only — OpenAI/OpenRouter
27
+ // chat models don't take the raw audio clip, so those skip it).
28
+ function imageTokensPerFrame(provider) {
29
+ return provider === "openai" ? 85 : 66;
30
+ }
31
+ const PROMPT_OVERHEAD_TOKENS = 280;
32
+ const AUDIO_TOKENS_PER_SEC = 32;
33
+ // OpenAI's nano reasoning model emits more output tokens than Gemini's terse JSON.
34
+ function outputTokensPerScene(provider) {
35
+ return provider === "openai" ? 350 : 150;
36
+ }
37
+ const EMBEDDING_TOKENS_PER_SCENE = 60;
38
+ const DEFAULT_AVG_SCENE_SEC = 4;
39
+ export function estimateScanCostFromScenes(scenes, opts) {
40
+ const durationSec = scenes.reduce((acc, s) => acc + s.duration_sec, 0);
41
+ const avgSceneSec = scenes.length ? durationSec / scenes.length : DEFAULT_AVG_SCENE_SEC;
42
+ return compute({ ...normalize(opts), durationSec, scenes: scenes.length, avgSceneSec });
43
+ }
44
+ export function estimateScanCostFromDuration(durationSec, opts) {
45
+ const avgSceneSec = opts.avgSceneSec ?? DEFAULT_AVG_SCENE_SEC;
46
+ const scenes = Math.max(1, Math.ceil(durationSec / avgSceneSec));
47
+ return compute({ ...normalize(opts), durationSec, scenes, avgSceneSec });
48
+ }
49
+ function normalize(opts) {
50
+ const provider = opts.provider ?? "gemini";
51
+ const tagModelId = opts.tagModelId ?? defaultTagModel(provider, opts.tier);
52
+ return {
53
+ tier: opts.tier,
54
+ provider,
55
+ tagModelId,
56
+ embedModelId: opts.embedModelId ?? null,
57
+ framesPerScene: opts.framesPerScene ?? 2,
58
+ includeAudio: opts.includeAudio ?? true
59
+ };
60
+ }
61
+ function defaultTagModel(provider, tier) {
62
+ if (provider === "openai")
63
+ return "gpt-5.4-nano";
64
+ if (provider === "openrouter")
65
+ return "google/gemini-2.5-flash";
66
+ if (provider === "nvidia")
67
+ return "minimaxai/minimax-m3";
68
+ return tier === "flash" ? "gemini-2.5-flash" : "gemini-2.5-flash-lite";
69
+ }
70
+ function compute(input) {
71
+ const { provider, tagModelId, embedModelId, framesPerScene, includeAudio, durationSec, scenes, avgSceneSec } = input;
72
+ // Audio is only sent to Gemini (native audio input).
73
+ const audioTokensPerScene = includeAudio && provider === "gemini" ? Math.round(avgSceneSec * AUDIO_TOKENS_PER_SEC) : 0;
74
+ const taggingInputPerScene = framesPerScene * imageTokensPerFrame(provider) + PROMPT_OVERHEAD_TOKENS + audioTokensPerScene;
75
+ const taggingInputTokens = taggingInputPerScene * scenes;
76
+ const taggingOutputTokens = outputTokensPerScene(provider) * scenes;
77
+ const embeddingTokens = embedModelId ? EMBEDDING_TOKENS_PER_SCENE * scenes : 0;
78
+ const tagPrice = MODEL_PRICING[tagModelId] ?? DEFAULT_TAG_PRICING;
79
+ const embedPrice = embedModelId ? EMBED_PRICING[embedModelId] ?? 0.15 : 0;
80
+ const usd = (taggingInputTokens / 1_000_000) * tagPrice.input +
81
+ (taggingOutputTokens / 1_000_000) * tagPrice.output +
82
+ (embeddingTokens / 1_000_000) * embedPrice;
83
+ const hours = durationSec / 3600;
84
+ const usdPerHour = hours > 0 ? usd / hours : usd;
85
+ return {
86
+ tier: input.tier,
87
+ provider,
88
+ tag_model: tagModelId,
89
+ embed_model: embedModelId,
90
+ duration_sec: round2(durationSec),
91
+ estimated_scenes: scenes,
92
+ frames_per_scene: framesPerScene,
93
+ tagging_input_tokens: taggingInputTokens,
94
+ tagging_output_tokens: taggingOutputTokens,
95
+ embedding_tokens: embeddingTokens,
96
+ usd: round4(usd),
97
+ usd_per_source_hour: round4(usdPerHour)
98
+ };
99
+ }
100
+ /** Human-readable one-liner for the CLI / API. */
101
+ export function formatCostEstimate(est) {
102
+ const mins = (est.duration_sec / 60).toFixed(1);
103
+ return [
104
+ `~$${est.usd.toFixed(3)} for ${mins} min`,
105
+ `(${est.estimated_scenes} scenes · ${est.tag_model}${est.embed_model ? ` + ${est.embed_model}` : " · no embeddings"})`,
106
+ `≈ $${est.usd_per_source_hour.toFixed(3)}/source-hour`,
107
+ `| tokens: ${est.tagging_input_tokens.toLocaleString()} in + ${est.tagging_output_tokens.toLocaleString()} out + ${est.embedding_tokens.toLocaleString()} embed`
108
+ ].join(" ");
109
+ }
110
+ function round2(n) {
111
+ return Math.round(n * 100) / 100;
112
+ }
113
+ function round4(n) {
114
+ return Math.round(n * 10000) / 10000;
115
+ }
116
+ //# sourceMappingURL=cost.js.map
@@ -0,0 +1,352 @@
1
+ // ffmpeg/ffprobe helpers for clip curation — scene detection, keyframe/clip/
2
+ // thumbnail extraction, per-scene audio for ASR. Same flags on devcli (local
3
+ // ffmpeg-static) and cloud (bundled ffmpeg-static in the scan Lambda), so both
4
+ // targets cut identical clips. Resolution order matches the rest of the repo:
5
+ // HYPERFRAMES_FFMPEG_PATH/FFPROBE env → ffmpeg-static/ffprobe-static → PATH.
6
+ import { spawn } from "node:child_process";
7
+ import { existsSync, mkdirSync } from "node:fs";
8
+ import path from "node:path";
9
+ let cachedFfmpeg;
10
+ let cachedFfprobe;
11
+ export async function resolveFfmpeg() {
12
+ if (cachedFfmpeg !== undefined)
13
+ return cachedFfmpeg ?? "ffmpeg";
14
+ const envPath = process.env.HYPERFRAMES_FFMPEG_PATH?.trim();
15
+ if (envPath && existsSync(envPath))
16
+ return (cachedFfmpeg = envPath);
17
+ try {
18
+ const mod = (await import("ffmpeg-static"));
19
+ const resolved = typeof mod === "string" ? mod : mod.default;
20
+ if (typeof resolved === "string" && resolved && existsSync(resolved))
21
+ return (cachedFfmpeg = resolved);
22
+ }
23
+ catch {
24
+ /* fall through to PATH */
25
+ }
26
+ cachedFfmpeg = null;
27
+ return "ffmpeg";
28
+ }
29
+ export async function resolveFfprobe() {
30
+ if (cachedFfprobe !== undefined)
31
+ return cachedFfprobe ?? "ffprobe";
32
+ const envPath = process.env.HYPERFRAMES_FFPROBE_PATH?.trim() ?? process.env.FFPROBE_PATH?.trim();
33
+ if (envPath && existsSync(envPath))
34
+ return (cachedFfprobe = envPath);
35
+ try {
36
+ const mod = (await import("ffprobe-static"));
37
+ const p = (mod.path ?? mod.default?.path);
38
+ if (typeof p === "string" && p && existsSync(p))
39
+ return (cachedFfprobe = p);
40
+ }
41
+ catch {
42
+ /* fall through to PATH */
43
+ }
44
+ cachedFfprobe = null;
45
+ return "ffprobe";
46
+ }
47
+ /** True if a usable ffmpeg is available (bundled or on PATH). */
48
+ export async function hasFfmpeg() {
49
+ const bin = await resolveFfmpeg();
50
+ const { code } = await run(bin, ["-version"]).catch(() => ({ code: 1, stdout: "", stderr: "" }));
51
+ return code === 0;
52
+ }
53
+ function run(bin, args) {
54
+ return new Promise((resolve, reject) => {
55
+ const child = spawn(bin, args, { stdio: ["ignore", "pipe", "pipe"] });
56
+ let stdout = "";
57
+ let stderr = "";
58
+ child.stdout.on("data", (d) => (stdout += d.toString()));
59
+ child.stderr.on("data", (d) => (stderr += d.toString()));
60
+ child.on("error", reject);
61
+ child.on("close", (code) => resolve({ code: code ?? 0, stdout, stderr }));
62
+ });
63
+ }
64
+ /** Probe a source video for duration/dimensions/codec/size/fps. */
65
+ export async function probeVideo(videoPath) {
66
+ const ffprobe = await resolveFfprobe();
67
+ const { stdout } = await run(ffprobe, [
68
+ "-v", "error",
69
+ "-print_format", "json",
70
+ "-show_format",
71
+ "-show_streams",
72
+ videoPath
73
+ ]);
74
+ let parsed = {};
75
+ try {
76
+ parsed = JSON.parse(stdout || "{}");
77
+ }
78
+ catch {
79
+ parsed = {};
80
+ }
81
+ const streams = Array.isArray(parsed.streams) ? parsed.streams : [];
82
+ const video = streams.find((s) => s.codec_type === "video");
83
+ const format = parsed.format ?? {};
84
+ const duration = Number(format.duration ?? video?.duration ?? 0) || 0;
85
+ let fps = null;
86
+ if (video?.avg_frame_rate && typeof video.avg_frame_rate === "string") {
87
+ const [num, den] = video.avg_frame_rate.split("/").map(Number);
88
+ if (num && den)
89
+ fps = num / den;
90
+ }
91
+ return {
92
+ duration_sec: duration,
93
+ width: video?.width ?? null,
94
+ height: video?.height ?? null,
95
+ codec: video?.codec_name ?? null,
96
+ size_bytes: format.size ? Number(format.size) : null,
97
+ fps
98
+ };
99
+ }
100
+ /**
101
+ * Detect scene boundaries with the portable `select='gt(scene,T)',showinfo`
102
+ * pass, parsing pts_time from ffmpeg's stderr. Falls back to fixed-interval
103
+ * chunking when nothing is detected (e.g. a single continuous take), so a scan
104
+ * always yields clips. Same command shape on devcli and cloud. With
105
+ * opts.windows set, each window is detected independently and scene times are
106
+ * offset back into source time.
107
+ */
108
+ export async function detectScenes(videoPath, opts = {}) {
109
+ const duration = opts.durationSec ?? (await probeVideo(videoPath)).duration_sec;
110
+ if (!Number.isFinite(duration) || duration <= 0)
111
+ return [];
112
+ const windows = (opts.windows ?? [])
113
+ .map((w) => ({ start_sec: Math.max(0, w.start_sec), end_sec: Math.min(w.end_sec, duration) }))
114
+ .filter((w) => w.end_sec - w.start_sec > 0.25);
115
+ if (windows.length === 0) {
116
+ return detectScenesInSpan(videoPath, { ...opts, durationSec: duration, spanStart: 0, spanEnd: duration, indexOffset: 0 });
117
+ }
118
+ const scenes = [];
119
+ for (const window of windows) {
120
+ const detected = await detectScenesInSpan(videoPath, {
121
+ ...opts,
122
+ durationSec: duration,
123
+ spanStart: window.start_sec,
124
+ spanEnd: window.end_sec,
125
+ indexOffset: scenes.length
126
+ });
127
+ scenes.push(...detected);
128
+ }
129
+ return scenes;
130
+ }
131
+ async function detectScenesInSpan(videoPath, opts) {
132
+ const threshold = opts.threshold ?? 0.3;
133
+ // Preserve very short detected shots as independent candidates. Absorbing a
134
+ // 2-10 frame flash into its neighbour makes it impossible for prompt/OCR
135
+ // refinement to reject that flash later. 50ms only de-duplicates effectively
136
+ // identical detector timestamps.
137
+ const minScene = opts.minSceneSec ?? 0.05;
138
+ const maxScene = opts.maxSceneSec ?? 8;
139
+ const { spanStart, spanEnd } = opts;
140
+ const spanDuration = spanEnd - spanStart;
141
+ if (!Number.isFinite(spanDuration) || spanDuration <= 0)
142
+ return [];
143
+ const ffmpeg = await resolveFfmpeg();
144
+ // -ss/-t BEFORE -i: input-seek so only the window is decoded. pts_time then
145
+ // restarts near 0, so cuts are offset back by spanStart below.
146
+ const seekArgs = spanStart > 0 || spanEnd < (opts.durationSec ?? Infinity)
147
+ ? ["-ss", spanStart.toFixed(3), "-t", spanDuration.toFixed(3)]
148
+ : [];
149
+ const { stderr } = await run(ffmpeg, [
150
+ "-hide_banner",
151
+ ...seekArgs,
152
+ "-i", videoPath,
153
+ "-filter:v", `select='gt(scene,${threshold})',showinfo`,
154
+ "-f", "null",
155
+ "-"
156
+ ]);
157
+ const cuts = [];
158
+ const re = /pts_time:([0-9.]+)/g;
159
+ let m;
160
+ while ((m = re.exec(stderr)) !== null) {
161
+ const t = Number(m[1]) + (seekArgs.length ? spanStart : 0);
162
+ if (Number.isFinite(t) && t > spanStart && t < spanEnd)
163
+ cuts.push(t);
164
+ }
165
+ cuts.sort((a, b) => a - b);
166
+ // Build [spanStart, cut1, cut2, …, spanEnd] boundaries.
167
+ let bounds = [spanStart, ...cuts, spanEnd];
168
+ // If nothing detected, chunk at maxScene.
169
+ if (cuts.length === 0) {
170
+ bounds = [spanStart];
171
+ for (let t = spanStart + maxScene; t < spanEnd; t += maxScene)
172
+ bounds.push(t);
173
+ bounds.push(spanEnd);
174
+ }
175
+ // Merge boundaries closer than minScene.
176
+ const merged = [bounds[0]];
177
+ for (let i = 1; i < bounds.length; i++) {
178
+ if (bounds[i] - merged[merged.length - 1] >= minScene || i === bounds.length - 1) {
179
+ merged.push(bounds[i]);
180
+ }
181
+ }
182
+ const scenes = [];
183
+ for (let i = 0; i < merged.length - 1; i++) {
184
+ let start = merged[i];
185
+ const end = merged[i + 1];
186
+ // Split over-long scenes so clips stay usable and tagging stays cheap.
187
+ const span = end - start;
188
+ if (span > maxScene) {
189
+ const chunks = Math.ceil(span / maxScene);
190
+ const step = span / chunks;
191
+ for (let c = 0; c < chunks; c++) {
192
+ const s = start + c * step;
193
+ const e = c === chunks - 1 ? end : s + step;
194
+ scenes.push(makeScene(opts.indexOffset + scenes.length, s, e));
195
+ }
196
+ }
197
+ else {
198
+ scenes.push(makeScene(opts.indexOffset + scenes.length, start, end));
199
+ }
200
+ }
201
+ return scenes;
202
+ }
203
+ function makeScene(index, start, end) {
204
+ const s = Math.max(0, start);
205
+ const e = Math.max(s + 0.01, end);
206
+ return { index, start_time_sec: round3(s), end_time_sec: round3(e), duration_sec: round3(e - s) };
207
+ }
208
+ /** Extract up to `count` small keyframe JPEGs across a scene (for low-cost tagging). */
209
+ export async function extractKeyframes(input) {
210
+ const count = Math.max(1, Math.min(3, input.count ?? 2));
211
+ const width = input.width ?? 384;
212
+ mkdirSync(input.outDir, { recursive: true });
213
+ const ffmpeg = await resolveFfmpeg();
214
+ const { start_time_sec: start, duration_sec: dur } = input.scene;
215
+ // Sample points inside the clip, avoiding the very edges.
216
+ const points = count === 1
217
+ ? [start + dur / 2]
218
+ : Array.from({ length: count }, (_, i) => start + dur * ((i + 1) / (count + 1)));
219
+ const vf = input.cropFilter ? `${input.cropFilter},scale=${width}:-2` : `scale=${width}:-2`;
220
+ const outPaths = [];
221
+ for (let i = 0; i < points.length; i++) {
222
+ const out = path.join(input.outDir, `scene-${input.scene.index}-kf${i}.jpg`);
223
+ const { code } = await run(ffmpeg, [
224
+ "-y",
225
+ "-ss", points[i].toFixed(3),
226
+ "-i", input.videoPath,
227
+ "-frames:v", "1",
228
+ "-vf", vf,
229
+ "-q:v", "5",
230
+ out
231
+ ]);
232
+ if (code === 0 && existsSync(out))
233
+ outPaths.push(out);
234
+ }
235
+ return outPaths;
236
+ }
237
+ /** Cut the scene into a standalone mp4 (re-encoded for frame-accurate boundaries). */
238
+ export async function extractClip(input) {
239
+ mkdirSync(path.dirname(input.outPath), { recursive: true });
240
+ const ffmpeg = await resolveFfmpeg();
241
+ const { start_time_sec: start, duration_sec: dur } = input.scene;
242
+ // A crop cannot ride on stream-copy — force the re-encode path when present.
243
+ const args = input.reencode === false && !input.cropFilter
244
+ ? ["-y", "-ss", start.toFixed(3), "-i", input.videoPath, "-t", dur.toFixed(3), "-c", "copy", "-avoid_negative_ts", "make_zero", input.outPath]
245
+ : [
246
+ "-y",
247
+ "-ss", start.toFixed(3),
248
+ "-i", input.videoPath,
249
+ "-t", dur.toFixed(3),
250
+ ...(input.cropFilter ? ["-vf", input.cropFilter] : []),
251
+ "-c:v", "libx264", "-preset", "veryfast", "-crf", "23", "-pix_fmt", "yuv420p",
252
+ "-c:a", "aac", "-b:a", "128k",
253
+ "-movflags", "+faststart",
254
+ input.outPath
255
+ ];
256
+ const { code, stderr } = await run(ffmpeg, args);
257
+ const ok = code === 0 && existsSync(input.outPath);
258
+ if (!ok) {
259
+ input.onError?.(`ffmpeg exit ${code}: ${stderr.slice(-500).replace(/\s+/g, " ").trim()}`);
260
+ }
261
+ return ok;
262
+ }
263
+ /**
264
+ * Trim EXACTLY [start, start+dur] of the source's AUDIO into a standalone
265
+ * `.m4a` (AAC) file — the audio-only twin of {@link extractClip}. The video
266
+ * track is dropped (`-vn`) so the result is a small, editor-placeable audio raw
267
+ * (e.g. clipping the soundtrack out of a copyright-free YouTube video). Returns
268
+ * false if the source has no audio track (ffmpeg exits non-zero with no output).
269
+ */
270
+ export async function extractAudioClip(input) {
271
+ mkdirSync(path.dirname(input.outPath), { recursive: true });
272
+ const ffmpeg = await resolveFfmpeg();
273
+ const { start_time_sec: start, duration_sec: dur } = input.scene;
274
+ const { code, stderr } = await run(ffmpeg, [
275
+ "-y",
276
+ "-ss", start.toFixed(3),
277
+ "-i", input.videoPath,
278
+ "-t", dur.toFixed(3),
279
+ "-vn",
280
+ "-c:a", "aac", "-b:a", "192k",
281
+ "-movflags", "+faststart",
282
+ input.outPath
283
+ ]);
284
+ const ok = code === 0 && existsSync(input.outPath);
285
+ if (!ok)
286
+ input.onError?.(`ffmpeg exit ${code}: ${stderr.slice(-500).replace(/\s+/g, " ").trim()}`);
287
+ return ok;
288
+ }
289
+ /**
290
+ * A static waveform PNG for an audio clip — its "thumbnail" so an audio-only raw
291
+ * still shows something in the raws gallery (there is no video frame to grab).
292
+ * Best-effort; returns false if the source has no audio to plot.
293
+ */
294
+ export async function extractWaveformThumbnail(input) {
295
+ mkdirSync(path.dirname(input.outPath), { recursive: true });
296
+ const ffmpeg = await resolveFfmpeg();
297
+ const { start_time_sec: start, duration_sec: dur } = input.scene;
298
+ const w = input.width ?? 320;
299
+ const h = input.height ?? 200;
300
+ const { code } = await run(ffmpeg, [
301
+ "-y",
302
+ "-ss", start.toFixed(3),
303
+ "-i", input.videoPath,
304
+ "-t", dur.toFixed(3),
305
+ "-filter_complex", `showwavespic=s=${w}x${h}:colors=#e2a63a`,
306
+ "-frames:v", "1",
307
+ input.outPath
308
+ ]);
309
+ return code === 0 && existsSync(input.outPath);
310
+ }
311
+ /** Single representative thumbnail for the scene. */
312
+ export async function extractThumbnail(input) {
313
+ mkdirSync(path.dirname(input.outPath), { recursive: true });
314
+ const ffmpeg = await resolveFfmpeg();
315
+ const mid = input.scene.start_time_sec + input.scene.duration_sec / 2;
316
+ const vf = input.cropFilter
317
+ ? `${input.cropFilter},scale=${input.width ?? 320}:-2`
318
+ : `scale=${input.width ?? 320}:-2`;
319
+ const { code } = await run(ffmpeg, [
320
+ "-y",
321
+ "-ss", mid.toFixed(3),
322
+ "-i", input.videoPath,
323
+ "-frames:v", "1",
324
+ "-vf", vf,
325
+ "-q:v", "3",
326
+ input.outPath
327
+ ]);
328
+ return code === 0 && existsSync(input.outPath);
329
+ }
330
+ /** Extract a small mono/16k audio clip for the scene (feeds Gemini ASR). Returns null if no audio track. */
331
+ export async function extractSceneAudio(input) {
332
+ mkdirSync(path.dirname(input.outPath), { recursive: true });
333
+ const ffmpeg = await resolveFfmpeg();
334
+ const { start_time_sec: start, duration_sec: dur } = input.scene;
335
+ const { code } = await run(ffmpeg, [
336
+ "-y",
337
+ "-ss", start.toFixed(3),
338
+ "-i", input.videoPath,
339
+ "-t", dur.toFixed(3),
340
+ "-vn",
341
+ "-ac", "1",
342
+ "-ar", "16000",
343
+ "-c:a", "libmp3lame",
344
+ "-b:a", "32k",
345
+ input.outPath
346
+ ]);
347
+ return code === 0 && existsSync(input.outPath) ? input.outPath : null;
348
+ }
349
+ function round3(n) {
350
+ return Math.round(n * 1000) / 1000;
351
+ }
352
+ //# sourceMappingURL=ffmpeg.js.map