@hraness/slopcamera 3.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (441) hide show
  1. package/LICENSE +21 -0
  2. package/NOTICE.md +60 -0
  3. package/PRIVACY.md +46 -0
  4. package/README.md +311 -0
  5. package/SECURITY.md +21 -0
  6. package/apps/desktop/README.md +966 -0
  7. package/apps/desktop/analysis/protocol.ts +223 -0
  8. package/apps/desktop/application/capability-binding.ts +594 -0
  9. package/apps/desktop/application/context.ts +97 -0
  10. package/apps/desktop/application/creative-iteration.ts +1385 -0
  11. package/apps/desktop/application/default-registry.ts +146 -0
  12. package/apps/desktop/application/directing-contract.ts +218 -0
  13. package/apps/desktop/application/directing-plan.ts +178 -0
  14. package/apps/desktop/application/errors.ts +18 -0
  15. package/apps/desktop/application/gateway-port.ts +867 -0
  16. package/apps/desktop/application/html-overlay-browser-runtime.ts +687 -0
  17. package/apps/desktop/application/html-overlay-integrity.ts +337 -0
  18. package/apps/desktop/application/html-overlay-renderer.ts +45 -0
  19. package/apps/desktop/application/index.ts +13 -0
  20. package/apps/desktop/application/operation-completion-checkpoint.ts +333 -0
  21. package/apps/desktop/application/operation-effects.ts +94 -0
  22. package/apps/desktop/application/operation.ts +224 -0
  23. package/apps/desktop/application/operations/analysis/faces.ts +244 -0
  24. package/apps/desktop/application/operations/analysis/music.ts +248 -0
  25. package/apps/desktop/application/operations/analysis/project-auto-zooms.ts +302 -0
  26. package/apps/desktop/application/operations/analysis/project-inactivity.ts +381 -0
  27. package/apps/desktop/application/operations/analysis/scenes.ts +272 -0
  28. package/apps/desktop/application/operations/analysis/shared.ts +202 -0
  29. package/apps/desktop/application/operations/derive/edit-batch.ts +967 -0
  30. package/apps/desktop/application/operations/derive/follow-faces.ts +454 -0
  31. package/apps/desktop/application/operations/edit/bind-candidate-revision.ts +91 -0
  32. package/apps/desktop/application/operations/edit/create-candidate-revision.ts +377 -0
  33. package/apps/desktop/application/operations/edit/create-revision.ts +255 -0
  34. package/apps/desktop/application/operations/edit/freeze-revision.ts +182 -0
  35. package/apps/desktop/application/operations/gateway/image.ts +41 -0
  36. package/apps/desktop/application/operations/gateway/index.ts +17 -0
  37. package/apps/desktop/application/operations/gateway/shared.ts +122 -0
  38. package/apps/desktop/application/operations/gateway/speech.ts +41 -0
  39. package/apps/desktop/application/operations/gateway/transcription.ts +42 -0
  40. package/apps/desktop/application/operations/gateway/video.ts +41 -0
  41. package/apps/desktop/application/operations/index.ts +31 -0
  42. package/apps/desktop/application/operations/iteration/create-candidate.ts +240 -0
  43. package/apps/desktop/application/operations/iteration/create-matrix.ts +117 -0
  44. package/apps/desktop/application/operations/iteration/select.ts +155 -0
  45. package/apps/desktop/application/operations/iteration/shared.ts +250 -0
  46. package/apps/desktop/application/operations/media/audio-effects.ts +376 -0
  47. package/apps/desktop/application/operations/media/binding.ts +79 -0
  48. package/apps/desktop/application/operations/media/capabilities.ts +112 -0
  49. package/apps/desktop/application/operations/media/color-grade.ts +343 -0
  50. package/apps/desktop/application/operations/media/html-overlay.ts +802 -0
  51. package/apps/desktop/application/operations/media/index.ts +8 -0
  52. package/apps/desktop/application/operations/media/ingest.ts +303 -0
  53. package/apps/desktop/application/operations/media/overlay.ts +729 -0
  54. package/apps/desktop/application/operations/media/shared.ts +845 -0
  55. package/apps/desktop/application/operations/media/transform-platform.ts +120 -0
  56. package/apps/desktop/application/operations/project/commit-edits.ts +2054 -0
  57. package/apps/desktop/application/operations/project/promote-selection.ts +495 -0
  58. package/apps/desktop/application/operations/project/snapshot.ts +95 -0
  59. package/apps/desktop/application/operations/recording/index.ts +5 -0
  60. package/apps/desktop/application/operations/recording/pause.ts +34 -0
  61. package/apps/desktop/application/operations/recording/resume.ts +34 -0
  62. package/apps/desktop/application/operations/recording/shared.ts +199 -0
  63. package/apps/desktop/application/operations/recording/start.ts +169 -0
  64. package/apps/desktop/application/operations/recording/stop.ts +34 -0
  65. package/apps/desktop/application/operations/render/bind-candidate-output.ts +324 -0
  66. package/apps/desktop/application/operations/render/materialize-selection.ts +322 -0
  67. package/apps/desktop/application/operations/render/project-caption-plan.ts +287 -0
  68. package/apps/desktop/application/operations/render/project-plan.ts +939 -0
  69. package/apps/desktop/application/operations/render/project-spatial-receipt.ts +70 -0
  70. package/apps/desktop/application/operations/render/project.ts +1922 -0
  71. package/apps/desktop/application/operations/shared.ts +67 -0
  72. package/apps/desktop/application/operations/slopcamera-portable.ts +1188 -0
  73. package/apps/desktop/application/operations/slopcamera-visuals.ts +784 -0
  74. package/apps/desktop/application/operations/spatial-project.ts +209 -0
  75. package/apps/desktop/application/operations/spatial-render.ts +415 -0
  76. package/apps/desktop/application/operations/spatial-scene.ts +97 -0
  77. package/apps/desktop/application/operations/studio.ts +143 -0
  78. package/apps/desktop/application/output-publication-lease.ts +163 -0
  79. package/apps/desktop/application/project-publication-lease.ts +233 -0
  80. package/apps/desktop/application/project-store.ts +196 -0
  81. package/apps/desktop/application/receipts.ts +533 -0
  82. package/apps/desktop/application/registry.ts +182 -0
  83. package/apps/desktop/application/spatial-assets.ts +675 -0
  84. package/apps/desktop/application/spatial-compositor-cadence.ts +23 -0
  85. package/apps/desktop/application/spatial-project-authority.ts +35 -0
  86. package/apps/desktop/application/spatial-project-lease.ts +126 -0
  87. package/apps/desktop/application/spatial-project-render-preparation.ts +225 -0
  88. package/apps/desktop/application/spatial-project-store.ts +286 -0
  89. package/apps/desktop/application/spatial-render-projection.ts +201 -0
  90. package/apps/desktop/application/spatial-render.ts +677 -0
  91. package/apps/desktop/application/spatial-spz.ts +44 -0
  92. package/apps/desktop/application/spatial-world-import.ts +135 -0
  93. package/apps/desktop/application/spatial-world-provenance.ts +46 -0
  94. package/apps/desktop/application/studio-port.ts +58 -0
  95. package/apps/desktop/application/verified-receipt-reconciliation.ts +1574 -0
  96. package/apps/desktop/capture/protocol.ts +689 -0
  97. package/apps/desktop/cli/analyzer.ts +406 -0
  98. package/apps/desktop/cli/args.ts +3181 -0
  99. package/apps/desktop/cli/asset-ingest.ts +747 -0
  100. package/apps/desktop/cli/atomic-render-effects.ts +210 -0
  101. package/apps/desktop/cli/atomic-render-platform.ts +205 -0
  102. package/apps/desktop/cli/atomic-render.ts +50 -0
  103. package/apps/desktop/cli/audio-analysis.ts +252 -0
  104. package/apps/desktop/cli/bounded-map.ts +39 -0
  105. package/apps/desktop/cli/bundle-service.ts +256 -0
  106. package/apps/desktop/cli/capabilities.ts +212 -0
  107. package/apps/desktop/cli/capture-bundle.ts +1117 -0
  108. package/apps/desktop/cli/command-host-resources.ts +251 -0
  109. package/apps/desktop/cli/commands.ts +6836 -0
  110. package/apps/desktop/cli/directing-blob.ts +291 -0
  111. package/apps/desktop/cli/directing-media.ts +517 -0
  112. package/apps/desktop/cli/directing-quote.ts +89 -0
  113. package/apps/desktop/cli/directing-service.ts +288 -0
  114. package/apps/desktop/cli/emoji-assets.ts +538 -0
  115. package/apps/desktop/cli/errors.ts +29 -0
  116. package/apps/desktop/cli/face-analysis-service.ts +940 -0
  117. package/apps/desktop/cli/filter-script.ts +76 -0
  118. package/apps/desktop/cli/gateway-application-port.ts +1142 -0
  119. package/apps/desktop/cli/gateway-credential.ts +81 -0
  120. package/apps/desktop/cli/gateway-media-artifacts.ts +723 -0
  121. package/apps/desktop/cli/gateway-media-catalog.ts +922 -0
  122. package/apps/desktop/cli/gateway-media-service.ts +3106 -0
  123. package/apps/desktop/cli/gateway-media-signature.ts +122 -0
  124. package/apps/desktop/cli/gateway-provider-options.ts +562 -0
  125. package/apps/desktop/cli/gateway-scene-provider.ts +391 -0
  126. package/apps/desktop/cli/help.ts +501 -0
  127. package/apps/desktop/cli/html-overlay-gpu.ts +97 -0
  128. package/apps/desktop/cli/html-overlay-renderer.ts +2478 -0
  129. package/apps/desktop/cli/io.ts +290 -0
  130. package/apps/desktop/cli/main.ts +123 -0
  131. package/apps/desktop/cli/media-effects-service.ts +885 -0
  132. package/apps/desktop/cli/media-ingest-model.ts +364 -0
  133. package/apps/desktop/cli/media-ingest-platform.ts +227 -0
  134. package/apps/desktop/cli/media-ingest-program.ts +200 -0
  135. package/apps/desktop/cli/media-ingest.ts +30 -0
  136. package/apps/desktop/cli/music-analysis-service.ts +434 -0
  137. package/apps/desktop/cli/mutation-lock.ts +530 -0
  138. package/apps/desktop/cli/native-assets.d.ts +12 -0
  139. package/apps/desktop/cli/native-media-runtime.macos.ts +7 -0
  140. package/apps/desktop/cli/overlay-playback.ts +177 -0
  141. package/apps/desktop/cli/paths.ts +265 -0
  142. package/apps/desktop/cli/portable-surface.ts +242 -0
  143. package/apps/desktop/cli/project-camera-receipt.ts +112 -0
  144. package/apps/desktop/cli/project-face-camera.ts +394 -0
  145. package/apps/desktop/cli/project-inactivity-service.ts +552 -0
  146. package/apps/desktop/cli/project-media-integrity.ts +121 -0
  147. package/apps/desktop/cli/project-renderer.ts +1526 -0
  148. package/apps/desktop/cli/project-service.ts +519 -0
  149. package/apps/desktop/cli/project-state-transaction.ts +520 -0
  150. package/apps/desktop/cli/query-limits.ts +1 -0
  151. package/apps/desktop/cli/recording-controller.ts +1567 -0
  152. package/apps/desktop/cli/recording-daemon.ts +931 -0
  153. package/apps/desktop/cli/recording-ref.ts +56 -0
  154. package/apps/desktop/cli/renamed-environment.ts +6 -0
  155. package/apps/desktop/cli/renderer.ts +1439 -0
  156. package/apps/desktop/cli/run-cli-test-helper.ts +60 -0
  157. package/apps/desktop/cli/scene-analysis-service.ts +879 -0
  158. package/apps/desktop/cli/spatial-compositor-verifier.ts +213 -0
  159. package/apps/desktop/cli/spatial-project-service.ts +90 -0
  160. package/apps/desktop/cli/spatial-scene-service.ts +105 -0
  161. package/apps/desktop/cli/spatial-world-service.ts +39 -0
  162. package/apps/desktop/cli/speech-analysis-service.ts +682 -0
  163. package/apps/desktop/cli/studio-assemble.ts +58 -0
  164. package/apps/desktop/cli/studio-command.ts +60 -0
  165. package/apps/desktop/cli/studio-custody.ts +60 -0
  166. package/apps/desktop/cli/studio-encode.ts +216 -0
  167. package/apps/desktop/cli/studio-exr.ts +52 -0
  168. package/apps/desktop/cli/studio-files.ts +179 -0
  169. package/apps/desktop/cli/studio-output-validation.ts +162 -0
  170. package/apps/desktop/cli/studio-process.ts +145 -0
  171. package/apps/desktop/cli/studio-runtime.ts +77 -0
  172. package/apps/desktop/cli/studio-scaffold.ts +70 -0
  173. package/apps/desktop/cli/studio-service.ts +301 -0
  174. package/apps/desktop/cli/studio-spatial-asset.ts +248 -0
  175. package/apps/desktop/cli/studio-template-names.ts +3 -0
  176. package/apps/desktop/cli/studio-workflow.ts +19 -0
  177. package/apps/desktop/cli/time.ts +25 -0
  178. package/apps/desktop/cli/workflow-code.ts +584 -0
  179. package/apps/desktop/cli/workflow-runs.ts +576 -0
  180. package/apps/desktop/code/advanced.ts +139 -0
  181. package/apps/desktop/code/application-node-planner.ts +1288 -0
  182. package/apps/desktop/code/compiler.ts +329 -0
  183. package/apps/desktop/code/contracts.ts +13 -0
  184. package/apps/desktop/code/creative-recipes.ts +94 -0
  185. package/apps/desktop/code/define-workflow.ts +115 -0
  186. package/apps/desktop/code/editing.ts +284 -0
  187. package/apps/desktop/code/file-candidate-provenance.ts +420 -0
  188. package/apps/desktop/code/file-candidate.ts +69 -0
  189. package/apps/desktop/code/graph-builder.ts +10 -0
  190. package/apps/desktop/code/host-resource-policy.ts +55 -0
  191. package/apps/desktop/code/plan-contracts.ts +159 -0
  192. package/apps/desktop/code/planning.ts +361 -0
  193. package/apps/desktop/code/public.ts +134 -0
  194. package/apps/desktop/code/reference-projection.ts +62 -0
  195. package/apps/desktop/code/run-contracts.ts +466 -0
  196. package/apps/desktop/code/run-store.ts +2478 -0
  197. package/apps/desktop/code/runtime-identity.ts +328 -0
  198. package/apps/desktop/code/scheduler.ts +3067 -0
  199. package/apps/desktop/code/semantic-builder.ts +1436 -0
  200. package/apps/desktop/code/source-bundle.ts +1641 -0
  201. package/apps/desktop/code/source-typecheck.ts +211 -0
  202. package/apps/desktop/code/testing.ts +79 -0
  203. package/apps/desktop/code/worker-client.ts +1675 -0
  204. package/apps/desktop/code/worker-effects.ts +141 -0
  205. package/apps/desktop/code/worker-entry.ts +435 -0
  206. package/apps/desktop/code/worker-lease-guardian.ts +179 -0
  207. package/apps/desktop/code/worker-process-identity.ts +484 -0
  208. package/apps/desktop/code/worker-protocol.ts +211 -0
  209. package/apps/desktop/code/workflow-effects.ts +132 -0
  210. package/apps/desktop/contracts/analysis.ts +949 -0
  211. package/apps/desktop/contracts/edit.ts +576 -0
  212. package/apps/desktop/contracts/index.ts +9 -0
  213. package/apps/desktop/contracts/media-effects.ts +139 -0
  214. package/apps/desktop/contracts/project-render.ts +644 -0
  215. package/apps/desktop/contracts/project.ts +740 -0
  216. package/apps/desktop/contracts/recording.ts +1434 -0
  217. package/apps/desktop/contracts/render.ts +334 -0
  218. package/apps/desktop/contracts/runtime.ts +155 -0
  219. package/apps/desktop/contracts/spatial-compositor.ts +58 -0
  220. package/apps/desktop/contracts/spatial-project.ts +159 -0
  221. package/apps/desktop/contracts/spatial-world.ts +48 -0
  222. package/apps/desktop/contracts/video-effects.ts +120 -0
  223. package/apps/desktop/core/alignment-apply.ts +400 -0
  224. package/apps/desktop/core/audio-alignment.ts +466 -0
  225. package/apps/desktop/core/auto-zoom.ts +209 -0
  226. package/apps/desktop/core/canonical-json.ts +14 -0
  227. package/apps/desktop/core/emoji.ts +210 -0
  228. package/apps/desktop/core/events.ts +409 -0
  229. package/apps/desktop/core/face-framing.ts +533 -0
  230. package/apps/desktop/core/face-tracks.ts +326 -0
  231. package/apps/desktop/core/inactivity.ts +137 -0
  232. package/apps/desktop/core/index.ts +30 -0
  233. package/apps/desktop/core/intervals.ts +123 -0
  234. package/apps/desktop/core/montage.ts +236 -0
  235. package/apps/desktop/core/music-analysis.ts +518 -0
  236. package/apps/desktop/core/plan.ts +244 -0
  237. package/apps/desktop/core/project-auto-zoom.ts +75 -0
  238. package/apps/desktop/core/project-camera-spatial.ts +676 -0
  239. package/apps/desktop/core/project-camera.ts +403 -0
  240. package/apps/desktop/core/project-captions.ts +888 -0
  241. package/apps/desktop/core/project-inactivity.ts +125 -0
  242. package/apps/desktop/core/project-metadata.ts +927 -0
  243. package/apps/desktop/core/project-plan.ts +375 -0
  244. package/apps/desktop/core/project-render-plan.ts +303 -0
  245. package/apps/desktop/core/project-time.ts +469 -0
  246. package/apps/desktop/core/render-plan.ts +442 -0
  247. package/apps/desktop/core/scene-cache.ts +174 -0
  248. package/apps/desktop/core/scene-sampling.ts +448 -0
  249. package/apps/desktop/core/spatial-compositor.ts +22 -0
  250. package/apps/desktop/core/spatial-durability.ts +99 -0
  251. package/apps/desktop/core/spatial-project.ts +169 -0
  252. package/apps/desktop/core/spatial-shot-clock.ts +32 -0
  253. package/apps/desktop/core/speech-analysis.ts +333 -0
  254. package/apps/desktop/core/storage.ts +970 -0
  255. package/apps/desktop/core/time-map.ts +91 -0
  256. package/apps/desktop/core/time.ts +61 -0
  257. package/apps/desktop/core/video-effects.ts +660 -0
  258. package/apps/desktop/dist/cli/NebulaSans-Bold-26se8aek.otf +0 -0
  259. package/apps/desktop/dist/cli/NebulaSans-Bold-bcz7y08t.woff2 +0 -0
  260. package/apps/desktop/dist/cli/NebulaSans-Book-5ax05zvn.woff2 +0 -0
  261. package/apps/desktop/dist/cli/NebulaSans-Book-8cenzchw.otf +0 -0
  262. package/apps/desktop/dist/cli/main.js +5086 -0
  263. package/apps/desktop/html-overlay/catalog.ts +171 -0
  264. package/apps/desktop/html-overlay/contracts.ts +372 -0
  265. package/apps/desktop/html-overlay/execution-profile.ts +77 -0
  266. package/apps/desktop/html-overlay/index.ts +98 -0
  267. package/apps/desktop/html-overlay/libraries.ts +263 -0
  268. package/apps/desktop/html-overlay/random.ts +49 -0
  269. package/apps/desktop/html-overlay/runtime.ts +813 -0
  270. package/apps/desktop/html-overlay/scaffolds.ts +792 -0
  271. package/apps/desktop/html-overlay/spark-runtime.ts +88 -0
  272. package/apps/desktop/html-overlay/spatial-splat-runtime.ts +60 -0
  273. package/apps/desktop/html-overlay/spatial.ts +720 -0
  274. package/apps/desktop/studio/assets/README.md +39 -0
  275. package/apps/desktop/studio/assets/contracts.ts +129 -0
  276. package/apps/desktop/studio/assets/network.ts +64 -0
  277. package/apps/desktop/studio/assets/poly-haven.ts +148 -0
  278. package/apps/desktop/studio/drivers/blender_driver.py +466 -0
  279. package/apps/desktop/studio/drivers/cadquery_driver.py +176 -0
  280. package/apps/desktop/studio/education/driver.py +308 -0
  281. package/apps/desktop/studio/education/lesson.py +180 -0
  282. package/apps/desktop/studio/education/toolkit.py +249 -0
  283. package/apps/desktop/workflows/chaptered-demo.ts +48 -0
  284. package/apps/desktop/workflows/creative-iteration.ts +107 -0
  285. package/apps/desktop/workflows/creative-selection.ts +92 -0
  286. package/apps/desktop/workflows/fragments.ts +486 -0
  287. package/apps/desktop/workflows/index.ts +93 -0
  288. package/apps/desktop/workflows/polished-screen-demo.ts +128 -0
  289. package/apps/desktop/workflows/scene-direction.ts +12 -0
  290. package/apps/desktop/workflows/social-variants.ts +75 -0
  291. package/apps/desktop/workflows/talking-head-cleanup.ts +53 -0
  292. package/dist/NebulaSans-Bold-26se8aek.otf +0 -0
  293. package/dist/NebulaSans-Bold-bcz7y08t.woff2 +0 -0
  294. package/dist/NebulaSans-Book-5ax05zvn.woff2 +0 -0
  295. package/dist/NebulaSans-Book-8cenzchw.otf +0 -0
  296. package/dist/cli.js +479 -0
  297. package/dist/code/advanced.js +270 -0
  298. package/dist/code/index.js +2240 -0
  299. package/dist/generate.js +24 -0
  300. package/dist/host-resources.js +26 -0
  301. package/dist/index-42zsesc1.js +2257 -0
  302. package/dist/index-7308egqr.js +48 -0
  303. package/dist/index-8txs6fkn.js +712 -0
  304. package/dist/index-mcy8z0br.js +192 -0
  305. package/dist/index-p63wavx0.js +2029 -0
  306. package/dist/index-r7gdhmsp.js +424 -0
  307. package/dist/index-sh6xbav6.js +1219 -0
  308. package/dist/index-z1w83f81.js +4 -0
  309. package/dist/index-z7239b4h.js +2363 -0
  310. package/dist/index-zfeg9hmw.js +2013 -0
  311. package/dist/index.js +241 -0
  312. package/dist/operations.js +29 -0
  313. package/dist/skill-install-dh0ntqba.js +10 -0
  314. package/dist/vectorize/worker.js +142 -0
  315. package/dist/workflow.js +16 -0
  316. package/docs/README.md +38 -0
  317. package/docs/studio.md +215 -0
  318. package/examples/studio/blender/README.md +26 -0
  319. package/examples/studio/blender/character.py +152 -0
  320. package/examples/studio/blender/cloth.py +101 -0
  321. package/examples/studio/blender/color_chart.py +29 -0
  322. package/examples/studio/blender/fluid.py +78 -0
  323. package/examples/studio/blender/import_model.py +74 -0
  324. package/examples/studio/blender/product.py +53 -0
  325. package/examples/studio/blender/shaded_street.py +481 -0
  326. package/examples/studio/blender/studio_scene.py +147 -0
  327. package/examples/studio/cadquery/README.md +13 -0
  328. package/examples/studio/cadquery/bracket.py +36 -0
  329. package/examples/studio/cadquery/import_step.py +12 -0
  330. package/examples/studio/education/README.md +46 -0
  331. package/examples/studio/education/lesson.json +99 -0
  332. package/examples/studio/education/scene.py +7 -0
  333. package/examples/studio/hybrid-scene.ts +96 -0
  334. package/examples/studio/native-workflow.ts +14 -0
  335. package/examples/studio/vgpu/README.md +64 -0
  336. package/examples/studio/vgpu/heat-field.mjs +290 -0
  337. package/package.json +304 -0
  338. package/packages/scene/src/index.ts +1 -0
  339. package/packages/scene/src/scene.ts +215 -0
  340. package/schema/diagram.schema.json +334 -0
  341. package/skills/slopcamera/SKILL.md +45 -0
  342. package/skills/slopcamera/agents/openai.yaml +4 -0
  343. package/skills/slopcamera/references/customization.md +77 -0
  344. package/skills/slopcamera/references/diagrams.md +153 -0
  345. package/skills/slopcamera/references/directed-scenes.md +42 -0
  346. package/skills/slopcamera/references/directing-video.md +18 -0
  347. package/skills/slopcamera/references/educational-video.md +26 -0
  348. package/skills/slopcamera/references/gateway-media.md +134 -0
  349. package/skills/slopcamera/references/install.md +62 -0
  350. package/skills/slopcamera/references/native-studio.md +31 -0
  351. package/skills/slopcamera/references/reference-led-3d.md +140 -0
  352. package/skills/slopcamera/references/rubber-stamp-examples/poster-example-1.jpg +0 -0
  353. package/skills/slopcamera/references/rubber-stamp-examples/poster-example-2.jpg +0 -0
  354. package/skills/slopcamera/references/rubber-stamp-examples/stamp-style-1.png +0 -0
  355. package/skills/slopcamera/references/rubber-stamp-examples/stamp-style-2.png +0 -0
  356. package/skills/slopcamera/references/rubber-stamp-field-notes.md +144 -0
  357. package/skills/slopcamera/references/vectorization.md +29 -0
  358. package/skills/slopcamera/references/video-projects.md +187 -0
  359. package/skills/slopcamera/references/visual-communication.md +120 -0
  360. package/skills/slopcamera/references/workflows-sdk.md +45 -0
  361. package/skills/slopcamera/scripts/compose-rubber-stamp-field-note.ts +229 -0
  362. package/src/artifacts.ts +106 -0
  363. package/src/assets/fonts/nebula-sans/LICENSE.txt +96 -0
  364. package/src/assets/fonts/nebula-sans/NebulaSans-Bold.otf +0 -0
  365. package/src/assets/fonts/nebula-sans/NebulaSans-Bold.woff2 +0 -0
  366. package/src/assets/fonts/nebula-sans/NebulaSans-Book.otf +0 -0
  367. package/src/assets/fonts/nebula-sans/NebulaSans-Book.woff2 +0 -0
  368. package/src/assets/fonts/nebula-sans/PROVENANCE.md +21 -0
  369. package/src/assets.d.ts +9 -0
  370. package/src/cli.ts +601 -0
  371. package/src/cloud-errors.ts +26 -0
  372. package/src/code/advanced.ts +10 -0
  373. package/src/code/boundary.ts +21 -0
  374. package/src/code/canonical-json.ts +129 -0
  375. package/src/code/compiler.ts +953 -0
  376. package/src/code/contracts.ts +576 -0
  377. package/src/code/define-workflow.ts +334 -0
  378. package/src/code/errors.ts +41 -0
  379. package/src/code/graph-builder.ts +945 -0
  380. package/src/code/index.ts +121 -0
  381. package/src/code/json-snapshot.ts +899 -0
  382. package/src/code/json-utf8.ts +88 -0
  383. package/src/code/portable-builder.ts +136 -0
  384. package/src/code/projection.ts +378 -0
  385. package/src/code/public-operations.ts +450 -0
  386. package/src/code/runtime.ts +580 -0
  387. package/src/code/sha256.ts +36 -0
  388. package/src/config.ts +180 -0
  389. package/src/desktop.ts +253 -0
  390. package/src/fs.ts +10 -0
  391. package/src/generate.ts +704 -0
  392. package/src/host-resource-posix.ts +161 -0
  393. package/src/host-resources.ts +1749 -0
  394. package/src/icons.ts +58 -0
  395. package/src/index.ts +200 -0
  396. package/src/label-layout.ts +130 -0
  397. package/src/layout.ts +413 -0
  398. package/src/lint.ts +127 -0
  399. package/src/mcp/boundary.ts +354 -0
  400. package/src/mcp/index.ts +33 -0
  401. package/src/mcp/server.ts +272 -0
  402. package/src/mcp/tools.ts +963 -0
  403. package/src/mcp/types.ts +71 -0
  404. package/src/operations.ts +775 -0
  405. package/src/parse.ts +861 -0
  406. package/src/process-environment.ts +17 -0
  407. package/src/render.ts +437 -0
  408. package/src/skill-install.ts +49 -0
  409. package/src/spatial-scene/authoring.ts +27 -0
  410. package/src/spatial-scene/camera-track.ts +83 -0
  411. package/src/spatial-scene/contracts.ts +277 -0
  412. package/src/spatial-scene/evaluate.ts +145 -0
  413. package/src/spatial-scene/gltf.ts +558 -0
  414. package/src/spatial-scene/identity.ts +260 -0
  415. package/src/spatial-scene/index.ts +10 -0
  416. package/src/spatial-scene/inspect.ts +68 -0
  417. package/src/spatial-scene/math.ts +280 -0
  418. package/src/spatial-scene/patch.ts +131 -0
  419. package/src/spatial-scene/time.ts +53 -0
  420. package/src/studio/contracts.ts +129 -0
  421. package/src/studio/index.ts +2 -0
  422. package/src/studio/plan.ts +156 -0
  423. package/src/studio/shared.ts +41 -0
  424. package/src/theme.ts +68 -0
  425. package/src/tldr.ts +474 -0
  426. package/src/types.ts +212 -0
  427. package/src/vectorize/archive.ts +101 -0
  428. package/src/vectorize/command.ts +797 -0
  429. package/src/vectorize/index.ts +27 -0
  430. package/src/vectorize/limits.ts +61 -0
  431. package/src/vectorize/metrics.ts +351 -0
  432. package/src/vectorize/pixels.ts +323 -0
  433. package/src/vectorize/supervisor.ts +339 -0
  434. package/src/vectorize/svg.ts +188 -0
  435. package/src/vectorize/tool.ts +542 -0
  436. package/src/vectorize/types.ts +113 -0
  437. package/src/vectorize/vectorize.ts +634 -0
  438. package/src/vectorize/worker-protocol.ts +40 -0
  439. package/src/vectorize/worker.ts +209 -0
  440. package/src/version.ts +1 -0
  441. package/src/workflow.ts +409 -0
@@ -0,0 +1,406 @@
1
+ import { CliError } from "./errors";
2
+ import type { ProcessRunner } from "./io";
3
+
4
+ export interface DetectedInterval {
5
+ readonly endUs: number;
6
+ readonly startUs: number;
7
+ }
8
+
9
+ interface OpenDetection {
10
+ readonly startUs: number;
11
+ durationUs?: number;
12
+ }
13
+
14
+ function secondsToMicroseconds(value: string, label: string): number {
15
+ const seconds = Number(value);
16
+ const microseconds = Math.round(seconds * 1_000_000);
17
+ if (!Number.isFinite(seconds) || !Number.isSafeInteger(microseconds) || microseconds < 0) {
18
+ throw new CliError("invalid-data", `Invalid ${label} timestamp from FFmpeg: ${value}`);
19
+ }
20
+ return microseconds;
21
+ }
22
+
23
+ function parseDetections(
24
+ output: string,
25
+ labels: Readonly<{ readonly duration: RegExp; readonly end: RegExp; readonly start: RegExp }>,
26
+ mediaDurationUs?: number,
27
+ ): readonly DetectedInterval[] {
28
+ const intervals: DetectedInterval[] = [];
29
+ let open: OpenDetection | undefined;
30
+ for (const line of output.split(/\r?\n/u)) {
31
+ const start = labels.start.exec(line);
32
+ if (start?.groups?.value !== undefined) {
33
+ open = { startUs: secondsToMicroseconds(start.groups.value, "start") };
34
+ continue;
35
+ }
36
+ const duration = labels.duration.exec(line);
37
+ if (duration?.groups?.value !== undefined && open !== undefined) {
38
+ open.durationUs = secondsToMicroseconds(duration.groups.value, "duration");
39
+ continue;
40
+ }
41
+ const end = labels.end.exec(line);
42
+ if (end?.groups?.value !== undefined && open !== undefined) {
43
+ const endUs = secondsToMicroseconds(end.groups.value, "end");
44
+ if (endUs >= open.startUs) intervals.push({ endUs, startUs: open.startUs });
45
+ open = undefined;
46
+ }
47
+ }
48
+ if (open !== undefined) {
49
+ const endUs = open.durationUs === undefined
50
+ ? mediaDurationUs
51
+ : open.startUs + open.durationUs;
52
+ if (endUs !== undefined && endUs >= open.startUs) intervals.push({ endUs, startUs: open.startUs });
53
+ }
54
+ return intervals;
55
+ }
56
+
57
+ const NUMBER = String.raw`(?<value>[0-9]+(?:\.[0-9]+)?)`;
58
+
59
+ export function parseFreezeDetectOutput(
60
+ output: string,
61
+ mediaDurationUs?: number,
62
+ ): readonly DetectedInterval[] {
63
+ return parseDetections(output, {
64
+ duration: new RegExp(String.raw`(?:lavfi\.freezedetect\.)?freeze_duration\s*[:=]\s*${NUMBER}`, "u"),
65
+ end: new RegExp(String.raw`(?:lavfi\.freezedetect\.)?freeze_end\s*[:=]\s*${NUMBER}`, "u"),
66
+ start: new RegExp(String.raw`(?:lavfi\.freezedetect\.)?freeze_start\s*[:=]\s*${NUMBER}`, "u"),
67
+ }, mediaDurationUs);
68
+ }
69
+
70
+ export function parseSilenceDetectOutput(
71
+ output: string,
72
+ mediaDurationUs?: number,
73
+ ): readonly DetectedInterval[] {
74
+ return parseDetections(output, {
75
+ duration: new RegExp(String.raw`silence_duration\s*[:=]\s*${NUMBER}`, "u"),
76
+ end: new RegExp(String.raw`silence_end\s*[:=]\s*${NUMBER}`, "u"),
77
+ start: new RegExp(String.raw`silence_start\s*[:=]\s*${NUMBER}`, "u"),
78
+ }, mediaDurationUs);
79
+ }
80
+
81
+ export interface MediaProbeSummary {
82
+ readonly durationUs: number;
83
+ readonly hasAudio: boolean;
84
+ }
85
+
86
+ export interface VisualMediaProbeSummary {
87
+ readonly audioEndUs: number | null;
88
+ readonly audioStartUs: number;
89
+ readonly audioStreamIndex: number | null;
90
+ readonly durationUs: number | null;
91
+ readonly hasAudio: boolean;
92
+ readonly pixelHeight: number;
93
+ readonly pixelWidth: number;
94
+ readonly videoStartUs: number;
95
+ readonly videoStreamIndex: number;
96
+ }
97
+
98
+ function signedSecondsToMicroseconds(value: string, label: string): number {
99
+ const seconds = Number(value);
100
+ const microseconds = Math.round(seconds * 1_000_000);
101
+ if (!Number.isFinite(seconds) || !Number.isSafeInteger(microseconds)) {
102
+ throw new CliError("invalid-data", `Invalid ${label} timestamp from FFprobe: ${value}`);
103
+ }
104
+ return microseconds;
105
+ }
106
+
107
+ function durationTagToMicroseconds(value: unknown, label: string): number | null {
108
+ if (typeof value !== "string") return null;
109
+ const match = /^(?<hours>[0-9]+):(?<minutes>[0-5][0-9]):(?<seconds>[0-5][0-9])(?:\.(?<fraction>[0-9]{1,9}))?$/u.exec(value);
110
+ if (match?.groups === undefined) {
111
+ throw new CliError("invalid-data", `Invalid ${label} duration tag from FFprobe: ${value}`);
112
+ }
113
+ const wholeSeconds = Number(match.groups.hours) * 3_600
114
+ + Number(match.groups.minutes) * 60
115
+ + Number(match.groups.seconds);
116
+ const fraction = match.groups.fraction ?? "";
117
+ const fractionalMicroseconds = Math.round(Number(`0.${fraction}`) * 1_000_000);
118
+ const microseconds = wholeSeconds * 1_000_000 + fractionalMicroseconds;
119
+ if (!Number.isSafeInteger(microseconds) || microseconds <= 0) {
120
+ throw new CliError("invalid-data", `Invalid ${label} duration tag from FFprobe: ${value}`);
121
+ }
122
+ return microseconds;
123
+ }
124
+
125
+ function streamDurationUs(stream: Readonly<Record<string, unknown>>, label: string): number | null {
126
+ if (typeof stream.duration === "string" && stream.duration !== "N/A") {
127
+ const durationUs = secondsToMicroseconds(stream.duration, `${label} duration`);
128
+ if (durationUs <= 0) throw new CliError("invalid-data", `FFprobe reported a non-positive ${label} duration.`);
129
+ return durationUs;
130
+ }
131
+ const tags = stream.tags;
132
+ if (tags === undefined) return null;
133
+ if (typeof tags !== "object" || tags === null || Array.isArray(tags)) {
134
+ throw new CliError("invalid-data", `FFprobe reported invalid ${label} stream tags.`);
135
+ }
136
+ const tagRecord = tags as Readonly<Record<string, unknown>>;
137
+ return durationTagToMicroseconds(tagRecord.DURATION ?? tagRecord.duration, label);
138
+ }
139
+
140
+ function probeStreamIndex(stream: Readonly<Record<string, unknown>>, label: string): number {
141
+ if (!Number.isSafeInteger(stream.index) || (stream.index as number) < 0) {
142
+ throw new CliError("invalid-data", `FFprobe ${label} stream omits a valid absolute index.`);
143
+ }
144
+ return stream.index as number;
145
+ }
146
+
147
+ function isAttachedPicture(stream: Readonly<Record<string, unknown>>): boolean {
148
+ const disposition = stream.disposition;
149
+ if (disposition === undefined) return false;
150
+ if (typeof disposition !== "object" || disposition === null || Array.isArray(disposition)) {
151
+ throw new CliError("invalid-data", "FFprobe video stream has an invalid disposition.");
152
+ }
153
+ const attached = (disposition as Readonly<Record<string, unknown>>).attached_pic;
154
+ if (attached === undefined || attached === false || attached === 0) return false;
155
+ if (attached === true || attached === 1) return true;
156
+ throw new CliError("invalid-data", "FFprobe video stream has an invalid attached-picture disposition.");
157
+ }
158
+
159
+ function selectLowestIndexedStream(
160
+ streams: readonly Readonly<Record<string, unknown>>[],
161
+ type: "audio" | "video",
162
+ ): { readonly index: number; readonly stream: Readonly<Record<string, unknown>> } | undefined {
163
+ return streams
164
+ .filter(stream => stream.codec_type === type && (type !== "video" || !isAttachedPicture(stream)))
165
+ .map(stream => ({ index: probeStreamIndex(stream, type), stream }))
166
+ .sort((left, right) => left.index - right.index)[0];
167
+ }
168
+
169
+ function parseMediaSummaryJson(stdout: string): MediaProbeSummary {
170
+ let value: unknown;
171
+ try {
172
+ value = JSON.parse(stdout);
173
+ } catch {
174
+ throw new CliError("invalid-data", "FFprobe duration output is not valid JSON.");
175
+ }
176
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
177
+ throw new CliError("invalid-data", "FFprobe duration output must be an object.");
178
+ }
179
+ const format = (value as Readonly<Record<string, unknown>>).format;
180
+ if (typeof format !== "object" || format === null || Array.isArray(format)) {
181
+ throw new CliError("invalid-data", "FFprobe duration output omits format.");
182
+ }
183
+ const duration = (format as Readonly<Record<string, unknown>>).duration;
184
+ if (typeof duration !== "string") {
185
+ throw new CliError("invalid-data", "FFprobe duration output omits duration.");
186
+ }
187
+ const streams = (value as Readonly<Record<string, unknown>>).streams;
188
+ if (streams !== undefined && !Array.isArray(streams)) {
189
+ throw new CliError("invalid-data", "FFprobe duration output has invalid streams.");
190
+ }
191
+ const hasAudio = Array.isArray(streams) && streams.some(stream => (
192
+ typeof stream === "object"
193
+ && stream !== null
194
+ && !Array.isArray(stream)
195
+ && (stream as Readonly<Record<string, unknown>>).codec_type === "audio"
196
+ ));
197
+ return { durationUs: secondsToMicroseconds(duration, "duration"), hasAudio };
198
+ }
199
+
200
+ export async function probeMediaSummary(
201
+ ffprobe: string,
202
+ runner: ProcessRunner,
203
+ path: string,
204
+ ): Promise<MediaProbeSummary> {
205
+ const result = await runner.run([
206
+ ffprobe,
207
+ "-v", "error",
208
+ "-show_entries", "format=duration:stream=codec_type",
209
+ "-of", "json",
210
+ path,
211
+ ], { maxOutputBytes: 32_000 });
212
+ if (result.exitCode !== 0) {
213
+ throw new CliError("subprocess", `FFprobe failed for ${path}: ${result.stderr.trim() || `exit ${result.exitCode}`}`);
214
+ }
215
+ return parseMediaSummaryJson(result.stdout);
216
+ }
217
+
218
+ export async function probeVisualMediaSummary(
219
+ ffprobe: string,
220
+ runner: ProcessRunner,
221
+ path: string,
222
+ ): Promise<VisualMediaProbeSummary> {
223
+ const result = await runner.run([
224
+ ffprobe,
225
+ "-v", "error",
226
+ "-show_entries", "format=duration,start_time:stream=index,codec_type,width,height,duration,start_time:stream_disposition=attached_pic:stream_tags=duration",
227
+ "-of", "json",
228
+ path,
229
+ ], { maxOutputBytes: 32_000 });
230
+ if (result.exitCode !== 0) {
231
+ throw new CliError("subprocess", `FFprobe failed for ${path}: ${result.stderr.trim() || `exit ${result.exitCode}`}`);
232
+ }
233
+ let value: unknown;
234
+ try {
235
+ value = JSON.parse(result.stdout);
236
+ } catch {
237
+ throw new CliError("invalid-data", "FFprobe visual-media output is not valid JSON.");
238
+ }
239
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
240
+ throw new CliError("invalid-data", "FFprobe visual-media output must be an object.");
241
+ }
242
+ const record = value as Readonly<Record<string, unknown>>;
243
+ if (!Array.isArray(record.streams)) {
244
+ throw new CliError("invalid-data", "FFprobe visual-media output omits streams.");
245
+ }
246
+ const streams = record.streams.filter((stream): stream is Readonly<Record<string, unknown>> => (
247
+ typeof stream === "object" && stream !== null && !Array.isArray(stream)
248
+ ));
249
+ const selectedVideo = selectLowestIndexedStream(streams, "video");
250
+ if (selectedVideo === undefined) {
251
+ throw new CliError("invalid-data", "Overlay media has no non-attached visual video stream.");
252
+ }
253
+ const video = selectedVideo.stream;
254
+ const selectedAudio = selectLowestIndexedStream(streams, "audio");
255
+ const audio = selectedAudio?.stream;
256
+ const pixelWidth = video?.width;
257
+ const pixelHeight = video?.height;
258
+ if (
259
+ !Number.isSafeInteger(pixelWidth)
260
+ || !Number.isSafeInteger(pixelHeight)
261
+ || (pixelWidth as number) <= 0
262
+ || (pixelHeight as number) <= 0
263
+ || (pixelWidth as number) > 16_384
264
+ || (pixelHeight as number) > 16_384
265
+ || (pixelWidth as number) * (pixelHeight as number) > 134_217_728
266
+ ) {
267
+ throw new CliError("invalid-data", "Overlay intrinsic dimensions exceed the 16384-pixel or 128-megapixel safety limit.");
268
+ }
269
+ const format = record.format;
270
+ const formatDuration = typeof format === "object" && format !== null && !Array.isArray(format)
271
+ ? (format as Readonly<Record<string, unknown>>).duration
272
+ : undefined;
273
+ const startTime = video?.start_time;
274
+ const formatStartTime = typeof format === "object" && format !== null && !Array.isArray(format)
275
+ ? (format as Readonly<Record<string, unknown>>).start_time
276
+ : undefined;
277
+ const hasAudio = selectedAudio !== undefined;
278
+ const formatStartUs = typeof formatStartTime === "string" && formatStartTime !== "N/A"
279
+ ? signedSecondsToMicroseconds(formatStartTime, "format start")
280
+ : 0;
281
+ const videoStartUs = typeof startTime === "string" && startTime !== "N/A"
282
+ ? signedSecondsToMicroseconds(startTime, "video start") - formatStartUs
283
+ : 0;
284
+ const audioStartUs = typeof audio?.start_time === "string" && audio.start_time !== "N/A"
285
+ ? signedSecondsToMicroseconds(audio.start_time, "audio start") - formatStartUs
286
+ : videoStartUs;
287
+ const audioDurationUs = audio === undefined ? null : streamDurationUs(audio, "audio");
288
+ const formatDurationUs = typeof formatDuration === "string" && formatDuration !== "N/A"
289
+ ? secondsToMicroseconds(formatDuration, "format duration")
290
+ : null;
291
+ const normalizedFormatEndUs = formatDurationUs !== null && formatDurationUs > 0
292
+ ? formatDurationUs
293
+ : null;
294
+ const audioEndUs = !hasAudio
295
+ ? null
296
+ : audioDurationUs === null
297
+ ? normalizedFormatEndUs
298
+ : audioStartUs + audioDurationUs;
299
+ if (audioEndUs !== null && (!Number.isSafeInteger(audioEndUs) || audioEndUs <= audioStartUs)) {
300
+ throw new CliError("invalid-data", "FFprobe reported an invalid audio stream end timestamp.");
301
+ }
302
+ const explicitVideoDurationUs = streamDurationUs(video, "video");
303
+ const formatBoundedVideoDurationUs = normalizedFormatEndUs === null
304
+ ? null
305
+ : normalizedFormatEndUs - videoStartUs;
306
+ const durationUs = explicitVideoDurationUs
307
+ ?? (formatBoundedVideoDurationUs !== null && Number.isSafeInteger(formatBoundedVideoDurationUs) && formatBoundedVideoDurationUs > 0
308
+ ? formatBoundedVideoDurationUs
309
+ : null);
310
+ return {
311
+ audioEndUs,
312
+ audioStartUs,
313
+ audioStreamIndex: selectedAudio?.index ?? null,
314
+ durationUs,
315
+ hasAudio,
316
+ pixelHeight: pixelHeight as number,
317
+ pixelWidth: pixelWidth as number,
318
+ videoStartUs,
319
+ videoStreamIndex: selectedVideo.index,
320
+ };
321
+ }
322
+
323
+ export async function probeMediaDuration(
324
+ ffprobe: string,
325
+ runner: ProcessRunner,
326
+ path: string,
327
+ ): Promise<number> {
328
+ return (await probeMediaSummary(ffprobe, runner, path)).durationUs;
329
+ }
330
+
331
+ export interface MediaAnalyzerOptions {
332
+ readonly ffmpeg: string;
333
+ readonly ffprobe: string;
334
+ readonly runner: ProcessRunner;
335
+ }
336
+
337
+ export class FfmpegInactivityAnalyzer {
338
+ readonly #ffmpeg: string;
339
+ readonly #ffprobe: string;
340
+ readonly #runner: ProcessRunner;
341
+
342
+ constructor(options: MediaAnalyzerOptions) {
343
+ this.#ffmpeg = options.ffmpeg;
344
+ this.#ffprobe = options.ffprobe;
345
+ this.#runner = options.runner;
346
+ }
347
+
348
+ async duration(path: string): Promise<number> {
349
+ return await probeMediaDuration(this.#ffprobe, this.#runner, path);
350
+ }
351
+
352
+ async freeze(
353
+ path: string,
354
+ streamIndex: number,
355
+ minDurationUs: number,
356
+ motionThreshold: number,
357
+ sourceOffsetUs = 0,
358
+ ): Promise<readonly DetectedInterval[]> {
359
+ const durationUs = await this.duration(path);
360
+ const result = await this.#runner.run([
361
+ this.#ffmpeg,
362
+ "-hide_banner",
363
+ "-nostdin",
364
+ "-i", path,
365
+ "-map", `0:${streamIndex}`,
366
+ "-vf", `freezedetect=n=${motionThreshold}:d=${minDurationUs / 1_000_000},metadata=mode=print`,
367
+ "-an",
368
+ "-f", "null",
369
+ "-",
370
+ ], { maxOutputBytes: 1_000_000 });
371
+ if (result.exitCode !== 0) {
372
+ throw new CliError("subprocess", `FFmpeg freeze analysis failed for ${path}: ${result.stderr.trim() || `exit ${result.exitCode}`}`);
373
+ }
374
+ return parseFreezeDetectOutput(`${result.stdout}\n${result.stderr}`, durationUs).map(({ startUs, endUs }) => ({
375
+ endUs: endUs + sourceOffsetUs,
376
+ startUs: startUs + sourceOffsetUs,
377
+ }));
378
+ }
379
+
380
+ async silence(
381
+ path: string,
382
+ streamIndex: number,
383
+ minDurationUs: number,
384
+ sourceOffsetUs = 0,
385
+ ): Promise<readonly DetectedInterval[]> {
386
+ const durationUs = await this.duration(path);
387
+ const result = await this.#runner.run([
388
+ this.#ffmpeg,
389
+ "-hide_banner",
390
+ "-nostdin",
391
+ "-i", path,
392
+ "-map", `0:${streamIndex}`,
393
+ "-af", `silencedetect=noise=-45dB:d=${minDurationUs / 1_000_000},ametadata=mode=print`,
394
+ "-vn",
395
+ "-f", "null",
396
+ "-",
397
+ ], { maxOutputBytes: 1_000_000 });
398
+ if (result.exitCode !== 0) {
399
+ throw new CliError("subprocess", `FFmpeg silence analysis failed for ${path}: ${result.stderr.trim() || `exit ${result.exitCode}`}`);
400
+ }
401
+ return parseSilenceDetectOutput(`${result.stdout}\n${result.stderr}`, durationUs).map(({ startUs, endUs }) => ({
402
+ endUs: endUs + sourceOffsetUs,
403
+ startUs: startUs + sourceOffsetUs,
404
+ }));
405
+ }
406
+ }