@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,169 @@
1
+ import {
2
+ applySpatialScenePatch,
3
+ parseSpatialScene,
4
+ spatialSceneSha256,
5
+ validateSpatialShot,
6
+ } from "../../../src/spatial-scene/index";
7
+ import { z } from "zod";
8
+ import { createBoundedJsonValueSnapshot, deepFreezeJson } from "../../../src/code/json-snapshot";
9
+ import { SpatialDigestSchema, SpatialScenePatchV1Schema, SpatialShotV1Schema, type SpatialShotV1 } from "../../../src/spatial-scene/contracts";
10
+ import {
11
+ SpatialCandidateSchema,
12
+ SpatialCandidateSelectionSchema,
13
+ SPATIAL_PROJECT_LIMITS,
14
+ SpatialProjectArtifactSchema,
15
+ SpatialProjectRevisionV2Schema,
16
+ SpatialProjectLegacySchema,
17
+ SpatialProjectSceneSourceSchema,
18
+ SpatialShotRetargetSchema,
19
+ type SpatialCandidate,
20
+ type SpatialProjectArtifact,
21
+ type SpatialProjectLegacy,
22
+ type SpatialProjectRevisionV2,
23
+ type SpatialProjectSceneSource,
24
+ type SpatialShotRetarget,
25
+ } from "../contracts/spatial-project";
26
+ import { canonicalJson, canonicalJsonSha256, sha256Hex } from "./canonical-json";
27
+ import { hashProjectStructure } from "./project-plan";
28
+
29
+ export interface SpatialProjectContents {
30
+ readonly legacy: SpatialProjectLegacy;
31
+ readonly scenes: readonly SpatialProjectSceneSource[];
32
+ readonly shots: readonly SpatialShotV1[];
33
+ readonly candidates: readonly SpatialCandidate[];
34
+ readonly selections: readonly { readonly shotId: string; readonly candidateId: string }[];
35
+ }
36
+ export const SpatialProjectContentsSchema = z.strictObject({
37
+ legacy: SpatialProjectLegacySchema,
38
+ scenes: z.array(SpatialProjectSceneSourceSchema).max(SPATIAL_PROJECT_LIMITS.scenes),
39
+ shots: z.array(SpatialShotV1Schema).max(SPATIAL_PROJECT_LIMITS.shots),
40
+ candidates: z.array(SpatialCandidateSchema).max(SPATIAL_PROJECT_LIMITS.candidates),
41
+ selections: z.array(SpatialCandidateSelectionSchema).max(SPATIAL_PROJECT_LIMITS.shots),
42
+ });
43
+ function capture(input: unknown, maximumBytes = SPATIAL_PROJECT_LIMITS.documentBytes) {
44
+ return createBoundedJsonValueSnapshot(input, maximumBytes, "spatial project value", { maximumDepth: 48, maximumValues: 2_000_000 }).value;
45
+ }
46
+ export function spatialProjectDocumentText(value: unknown): string {
47
+ return `${canonicalJson(capture(value))}\n`;
48
+ }
49
+ export function spatialProjectArtifact(area: "scenes" | "revisions" | "attempts" | "receipts", text: string): SpatialProjectArtifact {
50
+ const sha256 = sha256Hex(text);
51
+ return SpatialProjectArtifactSchema.parse({ path: `spatial/${area}/${sha256}.json`, sha256, bytes: new TextEncoder().encode(text).byteLength });
52
+ }
53
+ export function spatialProjectRevisionSha256(input: unknown): string {
54
+ return canonicalJsonSha256({ domain: "slopcamera.spatial-project-revision/v2", revision: SpatialProjectRevisionV2Schema.parse(capture(input)) });
55
+ }
56
+ export function spatialShotSha256(input: unknown): string {
57
+ return canonicalJsonSha256({ domain: "slopcamera.spatial-shot/v1", shot: SpatialShotV1Schema.parse(capture(input)) });
58
+ }
59
+ export function validateSpatialProjectContents(input: SpatialProjectContents): SpatialProjectContents {
60
+ const captured = SpatialProjectContentsSchema.parse(capture(input, SPATIAL_PROJECT_LIMITS.documentBytes + SPATIAL_PROJECT_LIMITS.totalSceneBytes));
61
+ const legacy = captured.legacy;
62
+ if (legacy.projectEditPlan.projectId !== legacy.project.projectId
63
+ || legacy.projectEditPlan.projectStructureSha256 !== hashProjectStructure(legacy.project)) {
64
+ throw new Error("Frozen V1 plan does not bind its exact project structure.");
65
+ }
66
+ const scenes = captured.scenes.map(source => {
67
+ const parsed = SpatialProjectSceneSourceSchema.parse(source);
68
+ const document = parseSpatialScene(parsed.document);
69
+ if (spatialSceneSha256(document) !== parsed.sceneSha256) throw new Error("Scene source digest mismatch.");
70
+ return SpatialProjectSceneSourceSchema.parse({ sceneSha256: parsed.sceneSha256, document });
71
+ });
72
+ const shots = captured.shots;
73
+ for (const shot of shots) {
74
+ const source = scenes.find(scene => scene.sceneSha256 === shot.sceneSha256);
75
+ if (source === undefined) throw new Error("Shot source is absent from the project.");
76
+ validateSpatialShot(source.document, shot);
77
+ }
78
+ // The admitted candidate owns its values across later asynchronous IO. A
79
+ // trusted caller retaining the original object cannot mutate this snapshot.
80
+ return deepFreezeJson({
81
+ legacy, scenes, shots,
82
+ candidates: captured.candidates,
83
+ selections: captured.selections,
84
+ });
85
+ }
86
+ export function spatialProjectLegacyProjection(contents: SpatialProjectContents): SpatialProjectLegacy {
87
+ validateSpatialProjectContents(contents);
88
+ return structuredClone(contents.legacy);
89
+ }
90
+ export function spatialCandidateStatus(contents: SpatialProjectContents, candidate: SpatialCandidate): "current" | "stale" {
91
+ const shot = contents.shots.find(value => value.shotId === candidate.derivation.shotId);
92
+ return shot !== undefined && shot.sceneSha256 === candidate.derivation.sceneSha256
93
+ && spatialShotSha256(shot) === candidate.derivation.shotSha256 ? "current" : "stale";
94
+ }
95
+ export interface SpatialProjectSceneDiff {
96
+ readonly beforeSceneSha256: string;
97
+ readonly afterSceneSha256: string;
98
+ readonly affectedShotIds: readonly string[];
99
+ readonly untouchedShotIds: readonly string[];
100
+ readonly selectedCandidates: readonly { readonly shotId: string; readonly candidateId: string; readonly status: "current" | "stale" }[];
101
+ }
102
+ function retargetSpatialProjectScene(current: SpatialProjectContents, beforeSceneSha256: string, afterSceneSha256: string, retargetInput: SpatialShotRetarget) {
103
+ const retarget = SpatialShotRetargetSchema.parse(capture(retargetInput));
104
+ const eligible = current.shots.filter(shot => shot.sceneSha256 === beforeSceneSha256);
105
+ const ids = retarget.kind === "all" ? eligible.map(shot => shot.shotId) : retarget.shotIds;
106
+ if (ids.length === 0 || new Set(ids).size !== ids.length || ids.some(id => !eligible.some(shot => shot.shotId === id))) {
107
+ throw new Error("Retarget must explicitly name unique shots of the exact source scene.");
108
+ }
109
+ const contents = validateSpatialProjectContents({ ...current, shots: current.shots.map(shot => ids.includes(shot.shotId) ? { ...shot, sceneSha256: afterSceneSha256 } : shot) });
110
+ return deepFreezeJson({ contents, diff: {
111
+ beforeSceneSha256, afterSceneSha256, affectedShotIds: [...ids].sort(),
112
+ untouchedShotIds: current.shots.filter(shot => !ids.includes(shot.shotId)).map(shot => shot.shotId).sort(),
113
+ selectedCandidates: contents.selections.map(selection => {
114
+ const candidate = contents.candidates.find(value => value.candidateId === selection.candidateId);
115
+ if (candidate === undefined) throw new Error("Selected candidate is absent.");
116
+ return { ...selection, status: spatialCandidateStatus(contents, candidate) };
117
+ }),
118
+ } });
119
+ }
120
+ /** Creates a revision candidate; project-level CAS is performed only by publication. */
121
+ export function applySpatialProjectScenePatch(
122
+ input: SpatialProjectContents,
123
+ patchInput: unknown,
124
+ retargetInput: SpatialShotRetarget,
125
+ ): { readonly contents: SpatialProjectContents; readonly diff: SpatialProjectSceneDiff } {
126
+ const current = validateSpatialProjectContents(input);
127
+ const patch = SpatialScenePatchV1Schema.parse(capture(patchInput));
128
+ const source = current.scenes.find(scene => scene.sceneSha256 === patch.expectedSceneSha256);
129
+ if (source === undefined) throw new Error("Expected source scene is absent.");
130
+ const document = applySpatialScenePatch(source.document, patch).scene;
131
+ const sceneSha256 = spatialSceneSha256(document);
132
+ return retargetSpatialProjectScene({
133
+ ...current,
134
+ scenes: current.scenes.some(scene => scene.sceneSha256 === sceneSha256) ? current.scenes
135
+ : [...current.scenes, SpatialProjectSceneSourceSchema.parse({ sceneSha256, document })],
136
+ }, patch.expectedSceneSha256, sceneSha256, retargetInput);
137
+ }
138
+ /** Explicit rollback of selected shot source bindings, never automatic head rollback or replay. */
139
+ export function restoreSpatialProjectScene(
140
+ input: SpatialProjectContents,
141
+ expectedSceneSha256Input: unknown,
142
+ restoreSceneSha256Input: unknown,
143
+ retargetInput: SpatialShotRetarget,
144
+ ): { readonly contents: SpatialProjectContents; readonly diff: SpatialProjectSceneDiff } {
145
+ const current = validateSpatialProjectContents(input);
146
+ const expectedSceneSha256 = SpatialDigestSchema.parse(capture(expectedSceneSha256Input));
147
+ const restoreSceneSha256 = SpatialDigestSchema.parse(capture(restoreSceneSha256Input));
148
+ const source = current.scenes.find(scene => scene.sceneSha256 === expectedSceneSha256);
149
+ const restored = current.scenes.find(scene => scene.sceneSha256 === restoreSceneSha256);
150
+ if (source === undefined || restored === undefined) throw new Error("Restore requires both exact scene revisions to be retained in the current project.");
151
+ if (source.document.sceneId !== restored.document.sceneId) throw new Error("Restore must select a retained revision of the same authored scene identity.");
152
+ if (expectedSceneSha256 === restoreSceneSha256) throw new Error("Restore requires a different retained scene revision.");
153
+ return retargetSpatialProjectScene(current, expectedSceneSha256, restoreSceneSha256, retargetInput);
154
+ }
155
+ /** Register exact provenance; this function neither generates nor buys media. */
156
+ export function addSpatialCandidate(input: SpatialProjectContents, candidateInput: unknown): SpatialProjectContents {
157
+ const candidate = SpatialCandidateSchema.parse(capture(candidateInput));
158
+ if (input.candidates.some(value => value.candidateId === candidate.candidateId)) throw new Error("Candidate identity is immutable and already exists.");
159
+ if (spatialCandidateStatus(input, candidate) !== "current") throw new Error("New candidate must bind the exact current shot and source scene.");
160
+ return { ...input, candidates: [...input.candidates, candidate] };
161
+ }
162
+ export function selectSpatialCandidate(input: SpatialProjectContents, candidateId: string): SpatialProjectContents {
163
+ const candidate = input.candidates.find(value => value.candidateId === candidateId);
164
+ if (candidate === undefined || spatialCandidateStatus(input, candidate) !== "current") throw new Error("Only a current verified candidate can be selected.");
165
+ return { ...input, selections: [...input.selections.filter(selection => selection.shotId !== candidate.derivation.shotId), { shotId: candidate.derivation.shotId, candidateId }] };
166
+ }
167
+ export function spatialProjectContents(revision: SpatialProjectRevisionV2, scenes: readonly SpatialProjectSceneSource[]): SpatialProjectContents {
168
+ return validateSpatialProjectContents({ legacy: revision.legacy, scenes, shots: revision.shots, candidates: revision.candidates, selections: revision.selections });
169
+ }
@@ -0,0 +1,32 @@
1
+ import { z } from "zod";
2
+
3
+ import { deepFreezeJson } from "../../../src/code/json-snapshot";
4
+ import { SPATIAL_SCENE_LIMITS, SpatialTimeUsSchema } from "../../../src/spatial-scene/contracts";
5
+ import { parseSpatialValue, SpatialSceneError } from "../../../src/spatial-scene/identity";
6
+
7
+ export const SpatialShotRenderClockSchema = z.strictObject({
8
+ kind: z.literal("shot"), sceneStartUs: SpatialTimeUsSchema,
9
+ playback: z.enum(["once", "loop", "freeze"]),
10
+ });
11
+ export type SpatialShotRenderClock = Readonly<z.infer<typeof SpatialShotRenderClockSchema>>;
12
+ const RequestSchema = z.strictObject({
13
+ clock: SpatialShotRenderClockSchema,
14
+ relativeTimeUs: z.strictObject({ numerator: z.string().regex(/^(?:0|[1-9][0-9]{0,23})$/u), denominator: z.string().regex(/^[1-9][0-9]{0,12}$/u) }),
15
+ sceneDurationUs: SpatialTimeUsSchema.refine(value => value > 0),
16
+ });
17
+
18
+ /** Exact shot-local → scene clock mapping occurs before the sole author-time quantization. */
19
+ export function spatialShotSceneTime(input: unknown) {
20
+ const request = parseSpatialValue(RequestSchema, input, "spatial shot clock");
21
+ const d = BigInt(request.relativeTimeUs.denominator), relative = BigInt(request.relativeTimeUs.numerator);
22
+ const end = BigInt(request.sceneDurationUs) * d;
23
+ if (request.clock.sceneStartUs >= request.sceneDurationUs || relative > BigInt(SPATIAL_SCENE_LIMITS.durationUs) * d) throw new SpatialSceneError("invalid-data", "Shot clock start or relative sample exceeds its bounded duration.");
24
+ let n = BigInt(request.clock.sceneStartUs) * d + relative;
25
+ if (request.clock.playback === "loop") n %= end;
26
+ else if (request.clock.playback === "freeze") n = n > end ? end : n;
27
+ else if (n >= end) throw new SpatialSceneError("invalid-data", "Once shot sample lies outside the exact half-open scene duration.");
28
+ let a = n, b = d;
29
+ while (b !== 0n) { const remainder = a % b; a = b; b = remainder; }
30
+ return deepFreezeJson({ exactTimeUs: { numerator: String(n / a), denominator: String(d / a) },
31
+ timeUs: Number((2n * n + d) / (2n * d)) });
32
+ }
@@ -0,0 +1,333 @@
1
+ import {
2
+ FillerCandidateSchema,
3
+ SpeechAnalysisV1Schema,
4
+ TranscriptWordSchema,
5
+ type AnalysisSubject,
6
+ type FillerCandidate,
7
+ type MusicAnalysisV1,
8
+ type SpeechAnalysisV1,
9
+ } from "../contracts/analysis";
10
+
11
+ type SourceRange = { readonly endUs: number; readonly startUs: number };
12
+ type TranscribedResult = Extract<SpeechAnalysisV1["result"], { readonly status: "transcribed" }>;
13
+ type TranscriptWord = TranscribedResult["words"][number];
14
+ type SpeechUtterance = TranscribedResult["utterances"][number];
15
+
16
+ const FILLED_PAUSES = new Set(["ah", "eh", "er", "erm", "hm", "hmm", "mm", "uh", "uhh", "um", "umm"]);
17
+ const CONTEXTUAL_FILLERS = new Set(["actually", "like", "well"]);
18
+ const PHRASE_FILLERS = [
19
+ { confidence: 0.97, tokens: ["you", "know"] },
20
+ { confidence: 0.97, tokens: ["i", "mean"] },
21
+ { confidence: 0.93, tokens: ["sort", "of"] },
22
+ { confidence: 0.9, tokens: ["kind", "of"] },
23
+ { confidence: 0.92, tokens: ["basically"] },
24
+ { confidence: 0.91, tokens: ["literally"] },
25
+ ] as const;
26
+
27
+ export interface SpeechWordInput {
28
+ readonly confidence: number;
29
+ readonly range: SourceRange;
30
+ readonly speaker?: string | null;
31
+ readonly text: string;
32
+ }
33
+
34
+ export interface MusicProtectionRegion {
35
+ readonly range: SourceRange;
36
+ }
37
+
38
+ export interface DetectedFillerSpan {
39
+ readonly classification: FillerCandidate["classification"];
40
+ readonly lexicalConfidence: number;
41
+ readonly wordEndExclusive: number;
42
+ readonly wordStart: number;
43
+ }
44
+
45
+ export interface AnalyzeSpeechInput {
46
+ readonly analysisId: string;
47
+ readonly config: SpeechAnalysisV1["config"];
48
+ readonly createdAt: string;
49
+ readonly detectedLanguage: string;
50
+ readonly durationUs: number;
51
+ readonly inputDigest: string;
52
+ readonly musicRegions?: readonly MusicProtectionRegion[] | MusicAnalysisV1["musicRegions"];
53
+ readonly subject: AnalysisSubject;
54
+ readonly tool: SpeechAnalysisV1["tool"];
55
+ readonly words: readonly SpeechWordInput[];
56
+ }
57
+
58
+ function clamp(value: number, minimum = 0, maximum = 1): number {
59
+ return Math.min(maximum, Math.max(minimum, value));
60
+ }
61
+
62
+ function normalizedToken(text: string): string {
63
+ return text.normalize("NFKC").toLocaleLowerCase("en-US")
64
+ .replace(/^[^\p{L}\p{N}]+|[^\p{L}\p{N}]+$/gu, "");
65
+ }
66
+
67
+ function hasFalseStartMarker(text: string): boolean {
68
+ return /(?:-|–|—|\.\.)$/u.test(text.trim());
69
+ }
70
+
71
+ function phraseAt(tokens: readonly string[], index: number): DetectedFillerSpan | null {
72
+ for (const phrase of PHRASE_FILLERS) {
73
+ if (phrase.tokens.every((token, offset) => tokens[index + offset] === token)) {
74
+ return {
75
+ classification: "phrase-filler",
76
+ lexicalConfidence: phrase.confidence,
77
+ wordEndExclusive: index + phrase.tokens.length,
78
+ wordStart: index,
79
+ };
80
+ }
81
+ }
82
+ return null;
83
+ }
84
+
85
+ function spansOverlap(left: DetectedFillerSpan, right: DetectedFillerSpan): boolean {
86
+ return left.wordStart < right.wordEndExclusive && right.wordStart < left.wordEndExclusive;
87
+ }
88
+
89
+ /** Merge adjacent detections of the same class without crossing a lexical gap. */
90
+ export function mergeFillerSpans(
91
+ spans: readonly DetectedFillerSpan[],
92
+ ): readonly DetectedFillerSpan[] {
93
+ const ordered = [...spans].sort((left, right) => left.wordStart - right.wordStart
94
+ || right.wordEndExclusive - left.wordEndExclusive
95
+ || left.classification.localeCompare(right.classification));
96
+ const merged: DetectedFillerSpan[] = [];
97
+ for (const span of ordered) {
98
+ const prior = merged.at(-1);
99
+ if (
100
+ prior !== undefined
101
+ && prior.classification === span.classification
102
+ && span.wordStart <= prior.wordEndExclusive
103
+ ) {
104
+ merged[merged.length - 1] = {
105
+ classification: prior.classification,
106
+ lexicalConfidence: Math.min(prior.lexicalConfidence, span.lexicalConfidence),
107
+ wordEndExclusive: Math.max(prior.wordEndExclusive, span.wordEndExclusive),
108
+ wordStart: prior.wordStart,
109
+ };
110
+ } else if (prior === undefined || !spansOverlap(prior, span)) {
111
+ merged.push(span);
112
+ }
113
+ }
114
+ return merged;
115
+ }
116
+
117
+ /** Classify lexical filler spans. A standalone `like` is always contextual. */
118
+ export function classifyFillerWords(words: readonly Pick<SpeechWordInput, "text">[]): readonly DetectedFillerSpan[] {
119
+ const tokens = words.map(word => normalizedToken(word.text));
120
+ const primary: DetectedFillerSpan[] = [];
121
+ for (let index = 0; index < words.length;) {
122
+ if (FILLED_PAUSES.has(tokens[index] ?? "")) {
123
+ let end = index + 1;
124
+ while (end < words.length && FILLED_PAUSES.has(tokens[end] ?? "")) end += 1;
125
+ primary.push({
126
+ classification: "filled-pause",
127
+ lexicalConfidence: 0.99,
128
+ wordEndExclusive: end,
129
+ wordStart: index,
130
+ });
131
+ index = end;
132
+ continue;
133
+ }
134
+ const phrase = phraseAt(tokens, index);
135
+ if (phrase !== null) {
136
+ primary.push(phrase);
137
+ index = phrase.wordEndExclusive;
138
+ continue;
139
+ }
140
+ if (hasFalseStartMarker(words[index]?.text ?? "")) {
141
+ primary.push({
142
+ classification: "false-start",
143
+ lexicalConfidence: 0.94,
144
+ wordEndExclusive: index + 1,
145
+ wordStart: index,
146
+ });
147
+ index += 1;
148
+ continue;
149
+ }
150
+ if (CONTEXTUAL_FILLERS.has(tokens[index] ?? "")) {
151
+ primary.push({
152
+ classification: "contextual",
153
+ lexicalConfidence: tokens[index] === "like" ? 0.82 : 0.76,
154
+ wordEndExclusive: index + 1,
155
+ wordStart: index,
156
+ });
157
+ }
158
+ index += 1;
159
+ }
160
+
161
+ const repetitions: DetectedFillerSpan[] = [];
162
+ for (let index = 1; index < tokens.length; index += 1) {
163
+ const token = tokens[index] ?? "";
164
+ if (token === "" || token !== tokens[index - 1]) continue;
165
+ const repetition: DetectedFillerSpan = {
166
+ classification: "repetition",
167
+ lexicalConfidence: 0.96,
168
+ wordEndExclusive: index + 1,
169
+ wordStart: index,
170
+ };
171
+ if (!primary.some(span => spansOverlap(span, repetition))) repetitions.push(repetition);
172
+ }
173
+ return mergeFillerSpans([...primary, ...repetitions]);
174
+ }
175
+
176
+ function rangesOverlap(left: SourceRange, right: SourceRange): boolean {
177
+ return left.startUs < right.endUs && right.startUs < left.endUs;
178
+ }
179
+
180
+ function transcriptWords(words: readonly SpeechWordInput[], durationUs: number): readonly TranscriptWord[] {
181
+ const ordered = [...words].sort((left, right) => left.range.startUs - right.range.startUs
182
+ || left.range.endUs - right.range.endUs
183
+ || left.text.localeCompare(right.text));
184
+ const parsed = ordered.map((word, wordIndex) => TranscriptWordSchema.parse({
185
+ confidence: word.confidence,
186
+ range: word.range,
187
+ speaker: word.speaker ?? null,
188
+ text: word.text,
189
+ wordIndex,
190
+ }));
191
+ for (let index = 0; index < parsed.length; index += 1) {
192
+ const word = parsed[index]!;
193
+ if (word.range.endUs > durationUs) throw new RangeError("Transcript words must fit inside durationUs.");
194
+ if (index > 0 && word.range.startUs < parsed[index - 1]!.range.endUs) {
195
+ throw new RangeError("Transcript words must not overlap.");
196
+ }
197
+ }
198
+ return parsed;
199
+ }
200
+
201
+ function joinWords(words: readonly TranscriptWord[]): string {
202
+ return words.map(word => word.text).join(" ").replace(/\s+([,.;:!?])/gu, "$1");
203
+ }
204
+
205
+ /** Group words on speaker changes and one-second transcript gaps. */
206
+ export function deriveSpeechUtterances(
207
+ words: readonly TranscriptWord[],
208
+ maximumGapUs = 1_000_000,
209
+ ): readonly SpeechUtterance[] {
210
+ if (!Number.isSafeInteger(maximumGapUs) || maximumGapUs < 0) {
211
+ throw new TypeError("maximumGapUs must be a nonnegative safe integer.");
212
+ }
213
+ const groups: { end: number; start: number }[] = [];
214
+ for (let index = 0; index < words.length; index += 1) {
215
+ const word = words[index]!;
216
+ const priorWord = words[index - 1];
217
+ const priorGroup = groups.at(-1);
218
+ if (
219
+ priorWord === undefined
220
+ || priorGroup === undefined
221
+ || word.range.startUs - priorWord.range.endUs > maximumGapUs
222
+ || word.speaker !== priorWord.speaker
223
+ ) {
224
+ groups.push({ end: index + 1, start: index });
225
+ } else {
226
+ priorGroup.end = index + 1;
227
+ }
228
+ }
229
+ return groups.map(group => {
230
+ const selected = words.slice(group.start, group.end);
231
+ return {
232
+ range: { endUs: selected.at(-1)!.range.endUs, startUs: selected[0]!.range.startUs },
233
+ text: joinWords(selected),
234
+ wordEndExclusive: group.end,
235
+ wordStart: group.start,
236
+ };
237
+ });
238
+ }
239
+
240
+ function fillerIdentifier(index: number): FillerCandidate["candidateId"] {
241
+ return `filler_candidate${String(index + 1).padStart(4, "0")}` as FillerCandidate["candidateId"];
242
+ }
243
+
244
+ /** Build conservative cut suggestions from lexical spans and acoustic gaps. */
245
+ export function buildFillerCandidates(
246
+ words: readonly TranscriptWord[],
247
+ config: SpeechAnalysisV1["config"],
248
+ durationUs: number,
249
+ musicRegions: readonly MusicProtectionRegion[] = [],
250
+ ): readonly FillerCandidate[] {
251
+ const spans = classifyFillerWords(words);
252
+ const candidates: FillerCandidate[] = [];
253
+ for (const span of spans) {
254
+ const selected = words.slice(span.wordStart, span.wordEndExclusive);
255
+ const first = selected[0];
256
+ const last = selected.at(-1);
257
+ if (first === undefined || last === undefined) continue;
258
+ const range = { endUs: last.range.endUs, startUs: first.range.startUs };
259
+ const transcriptConfidence = Math.min(...selected.map(word => word.confidence));
260
+ const confidence = clamp(span.lexicalConfidence * transcriptConfidence);
261
+ if (confidence < config.minimumFillerConfidence) continue;
262
+ const prior = words[span.wordStart - 1];
263
+ const next = words[span.wordEndExclusive];
264
+ const beforeGapUs = prior === undefined ? range.startUs : Math.max(0, range.startUs - prior.range.endUs);
265
+ const afterGapUs = next === undefined ? Math.max(0, durationUs - range.endUs) : Math.max(0, next.range.startUs - range.endUs);
266
+ const boundaryScale = Math.max(1, config.speechHandleUs);
267
+ const acousticBoundaryConfidence = config.speechHandleUs === 0
268
+ ? 1
269
+ : Math.min(clamp(beforeGapUs / boundaryScale), clamp(afterGapUs / boundaryScale));
270
+ const contextual = span.classification === "contextual";
271
+ const proposedCut = {
272
+ endUs: Math.min(durationUs, range.endUs + Math.min(config.speechHandleUs, afterGapUs)),
273
+ startUs: Math.max(0, range.startUs - Math.min(config.speechHandleUs, beforeGapUs)),
274
+ };
275
+ const musicProtected = musicRegions.some(region =>
276
+ rangesOverlap(range, region.range) || rangesOverlap(proposedCut, region.range));
277
+ const recommendedCut = musicProtected || contextual ? null : proposedCut;
278
+ const autoApplicable = recommendedCut !== null
279
+ && !musicProtected
280
+ && !contextual
281
+ && confidence >= 0.9
282
+ && acousticBoundaryConfidence >= 0.8;
283
+ candidates.push(FillerCandidateSchema.parse({
284
+ acousticBoundaryConfidence,
285
+ autoApplicable,
286
+ candidateId: fillerIdentifier(candidates.length),
287
+ classification: span.classification,
288
+ confidence,
289
+ musicProtected,
290
+ range,
291
+ recommendedCut,
292
+ text: joinWords(selected),
293
+ wordEndExclusive: span.wordEndExclusive,
294
+ wordStart: span.wordStart,
295
+ }));
296
+ }
297
+ return candidates;
298
+ }
299
+
300
+ /** Analyze an owned word transcript into safe, inspectable filler suggestions. */
301
+ export function analyzeSpeech(input: AnalyzeSpeechInput): SpeechAnalysisV1 {
302
+ if (!Number.isSafeInteger(input.durationUs) || input.durationUs < 0) {
303
+ throw new TypeError("durationUs must be a nonnegative safe integer.");
304
+ }
305
+ const base = {
306
+ analysisId: input.analysisId,
307
+ config: input.config,
308
+ createdAt: input.createdAt,
309
+ durationUs: input.durationUs,
310
+ inputDigest: input.inputDigest,
311
+ kind: "slopcamera.speech-analysis" as const,
312
+ schemaVersion: 1 as const,
313
+ subject: input.subject,
314
+ tool: input.tool,
315
+ };
316
+ if (input.words.length === 0) {
317
+ return SpeechAnalysisV1Schema.parse({
318
+ ...base,
319
+ result: { detectedLanguage: input.detectedLanguage || null, reason: "no-speech", status: "no-speech" },
320
+ });
321
+ }
322
+ const words = transcriptWords(input.words, input.durationUs);
323
+ return SpeechAnalysisV1Schema.parse({
324
+ ...base,
325
+ result: {
326
+ detectedLanguage: input.detectedLanguage,
327
+ fillers: buildFillerCandidates(words, input.config, input.durationUs, input.musicRegions ?? []),
328
+ status: "transcribed",
329
+ utterances: deriveSpeechUtterances(words),
330
+ words,
331
+ },
332
+ });
333
+ }