@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,466 @@
1
+ import {
2
+ AlignmentCandidateSchema,
3
+ AudioAlignmentAnalysisV1Schema,
4
+ type AlignmentCandidate,
5
+ type AnalysisSubject,
6
+ type AudioAlignmentAnalysisV1,
7
+ } from "../contracts/analysis";
8
+
9
+ const EPSILON = 1e-12;
10
+ const DEFAULT_MINIMUM_CORRELATION = 0.55;
11
+ const DEFAULT_AMBIGUITY_MARGIN = 0.08;
12
+ const DEFAULT_DISTINCT_PEAK_US = 100_000;
13
+ const MAX_CORRELATION_SAMPLES = 4_096;
14
+
15
+ export interface EnvelopeSeries {
16
+ readonly hopUs: number;
17
+ readonly startUs?: number;
18
+ readonly values: readonly number[];
19
+ }
20
+
21
+ export interface AudioAlignmentOptions {
22
+ readonly ambiguityMargin?: number;
23
+ readonly distinctPeakUs?: number;
24
+ readonly maxOffsetUs?: number;
25
+ readonly minimumCorrelation?: number;
26
+ }
27
+
28
+ export interface AnalyzeAudioAlignmentInput {
29
+ readonly analysisId: string;
30
+ readonly config: AudioAlignmentAnalysisV1["config"];
31
+ readonly createdAt: string;
32
+ readonly inputDigest: string;
33
+ readonly options?: AudioAlignmentOptions;
34
+ readonly reference: AnalysisSubject;
35
+ readonly referenceEnvelope: EnvelopeSeries;
36
+ readonly target: AnalysisSubject;
37
+ readonly targetEnvelope: EnvelopeSeries;
38
+ readonly tool: AudioAlignmentAnalysisV1["tool"];
39
+ }
40
+
41
+ interface LagScore {
42
+ readonly lagSamples: number;
43
+ readonly overlapSamples: number;
44
+ readonly score: number;
45
+ }
46
+
47
+ interface LocalMatch extends LagScore {
48
+ readonly ambiguity: number;
49
+ readonly referenceSample: number;
50
+ readonly targetSample: number;
51
+ readonly windowSamples: number;
52
+ }
53
+
54
+ interface FittedCandidate {
55
+ readonly candidate: AlignmentCandidate;
56
+ readonly matches: readonly LocalMatch[];
57
+ readonly score: number;
58
+ }
59
+
60
+ function clamp(value: number, minimum: number, maximum: number): number {
61
+ return Math.min(maximum, Math.max(minimum, value));
62
+ }
63
+
64
+ function median(values: readonly number[]): number {
65
+ if (values.length === 0) return 0;
66
+ const ordered = [...values].sort((left, right) => left - right);
67
+ const middle = Math.floor(ordered.length / 2);
68
+ return ordered.length % 2 === 0
69
+ ? ((ordered[middle - 1] ?? 0) + (ordered[middle] ?? 0)) / 2
70
+ : ordered[middle] ?? 0;
71
+ }
72
+
73
+ function assertSeries(series: EnvelopeSeries, label: string): Required<EnvelopeSeries> {
74
+ if (!Number.isSafeInteger(series.hopUs) || series.hopUs <= 0) {
75
+ throw new TypeError(`${label} envelope hopUs must be a positive safe integer.`);
76
+ }
77
+ const startUs = series.startUs ?? 0;
78
+ if (!Number.isSafeInteger(startUs) || startUs < 0) {
79
+ throw new TypeError(`${label} envelope startUs must be a nonnegative safe integer.`);
80
+ }
81
+ if (series.values.some(value => !Number.isFinite(value))) {
82
+ throw new TypeError(`${label} envelope values must be finite.`);
83
+ }
84
+ return { hopUs: series.hopUs, startUs, values: series.values };
85
+ }
86
+
87
+ function variance(values: readonly number[]): number {
88
+ if (values.length === 0) return 0;
89
+ const mean = values.reduce((sum, value) => sum + value, 0) / values.length;
90
+ return values.reduce((sum, value) => sum + (value - mean) ** 2, 0) / values.length;
91
+ }
92
+
93
+ /**
94
+ * Pearson correlation at a lag where a positive lag means the matching target
95
+ * feature occurs later than the reference feature.
96
+ */
97
+ export function envelopeCorrelationAtLag(
98
+ reference: readonly number[],
99
+ target: readonly number[],
100
+ lagSamples: number,
101
+ maximumSamples = MAX_CORRELATION_SAMPLES,
102
+ ): LagScore {
103
+ if (!Number.isSafeInteger(lagSamples)) throw new TypeError("lagSamples must be a safe integer.");
104
+ const referenceStart = Math.max(0, -lagSamples);
105
+ const targetStart = Math.max(0, lagSamples);
106
+ const overlapSamples = Math.min(reference.length - referenceStart, target.length - targetStart);
107
+ if (overlapSamples < 2) return { lagSamples, overlapSamples: Math.max(0, overlapSamples), score: -1 };
108
+
109
+ const stride = Math.max(1, Math.ceil(overlapSamples / maximumSamples));
110
+ let count = 0;
111
+ let referenceSum = 0;
112
+ let targetSum = 0;
113
+ for (let offset = 0; offset < overlapSamples; offset += stride) {
114
+ const left = reference[referenceStart + offset] ?? 0;
115
+ const right = target[targetStart + offset] ?? 0;
116
+ count += 1;
117
+ referenceSum += left;
118
+ targetSum += right;
119
+ }
120
+ const referenceMean = referenceSum / count;
121
+ const targetMean = targetSum / count;
122
+ let covariance = 0;
123
+ let referenceEnergy = 0;
124
+ let targetEnergy = 0;
125
+ for (let offset = 0; offset < overlapSamples; offset += stride) {
126
+ const left = (reference[referenceStart + offset] ?? 0) - referenceMean;
127
+ const right = (target[targetStart + offset] ?? 0) - targetMean;
128
+ covariance += left * right;
129
+ referenceEnergy += left * left;
130
+ targetEnergy += right * right;
131
+ }
132
+ const denominator = Math.sqrt(Math.max(0, referenceEnergy) * Math.max(0, targetEnergy));
133
+ return {
134
+ lagSamples,
135
+ overlapSamples,
136
+ score: denominator <= EPSILON ? -1 : clamp(covariance / denominator, -1, 1),
137
+ };
138
+ }
139
+
140
+ function scanLags(
141
+ reference: readonly number[],
142
+ target: readonly number[],
143
+ minimumLag: number,
144
+ maximumLag: number,
145
+ ): readonly LagScore[] {
146
+ const width = Math.max(0, maximumLag - minimumLag + 1);
147
+ const coarseStride = Math.max(1, Math.ceil(width / 4_001));
148
+ const coarse: LagScore[] = [];
149
+ for (let lag = minimumLag; lag <= maximumLag; lag += coarseStride) {
150
+ coarse.push(envelopeCorrelationAtLag(reference, target, lag));
151
+ }
152
+ if (coarseStride === 1) return coarse;
153
+
154
+ const promising = [...coarse]
155
+ .sort((left, right) => right.score - left.score || left.lagSamples - right.lagSamples)
156
+ .slice(0, 8);
157
+ const refinedLags = new Set<number>();
158
+ for (const candidate of promising) {
159
+ for (
160
+ let lag = Math.max(minimumLag, candidate.lagSamples - coarseStride);
161
+ lag <= Math.min(maximumLag, candidate.lagSamples + coarseStride);
162
+ lag += 1
163
+ ) refinedLags.add(lag);
164
+ }
165
+ return [...refinedLags].sort((left, right) => left - right)
166
+ .map(lag => envelopeCorrelationAtLag(reference, target, lag));
167
+ }
168
+
169
+ function distinctPeaks(scores: readonly LagScore[], separationSamples: number): readonly LagScore[] {
170
+ const ordered = [...scores].sort((left, right) => right.score - left.score || left.lagSamples - right.lagSamples);
171
+ const selected: LagScore[] = [];
172
+ for (const score of ordered) {
173
+ if (selected.every(candidate => Math.abs(candidate.lagSamples - score.lagSamples) >= separationSamples)) {
174
+ selected.push(score);
175
+ if (selected.length === 32) break;
176
+ }
177
+ }
178
+ return selected;
179
+ }
180
+
181
+ function ambiguity(best: number, competitor: number | undefined, margin: number): number {
182
+ if (competitor === undefined || competitor < -0.5) return 0;
183
+ if (margin <= 0) return competitor >= best ? 1 : 0;
184
+ return clamp((competitor - (best - margin)) / margin, 0, 1);
185
+ }
186
+
187
+ function windowCorrelation(
188
+ reference: readonly number[],
189
+ target: readonly number[],
190
+ referenceCenter: number,
191
+ lagSamples: number,
192
+ windowSamples: number,
193
+ ): LagScore {
194
+ const half = Math.max(1, Math.floor(windowSamples / 2));
195
+ const referenceStart = Math.max(0, referenceCenter - half);
196
+ const referenceEnd = Math.min(reference.length, referenceCenter + half);
197
+ const targetStart = referenceStart + lagSamples;
198
+ const targetEnd = referenceEnd + lagSamples;
199
+ if (targetStart < 0 || targetEnd > target.length || referenceEnd - referenceStart < 2) {
200
+ return { lagSamples, overlapSamples: 0, score: -1 };
201
+ }
202
+ const correlation = envelopeCorrelationAtLag(
203
+ reference.slice(referenceStart, referenceEnd),
204
+ target.slice(targetStart, targetEnd),
205
+ 0,
206
+ );
207
+ return { ...correlation, lagSamples };
208
+ }
209
+
210
+ function localMatches(
211
+ reference: readonly number[],
212
+ target: readonly number[],
213
+ initialLag: number,
214
+ windowSamples: number,
215
+ maximumDriftSamples: number,
216
+ ambiguityMargin: number,
217
+ ): readonly LocalMatch[] {
218
+ const half = Math.max(2, Math.floor(windowSamples / 2));
219
+ const minimumCenter = Math.max(half, half - initialLag + maximumDriftSamples);
220
+ const maximumCenter = Math.min(
221
+ reference.length - half,
222
+ target.length - half - initialLag - maximumDriftSamples,
223
+ );
224
+ if (maximumCenter < minimumCenter) return [];
225
+ const desiredMatches = Math.max(2, Math.min(32, Math.ceil((maximumCenter - minimumCenter + 1) / Math.max(1, windowSamples))));
226
+ const centers = new Set<number>();
227
+ for (let index = 0; index < desiredMatches; index += 1) {
228
+ const ratio = desiredMatches === 1 ? 0.5 : index / (desiredMatches - 1);
229
+ centers.add(Math.round(minimumCenter + ratio * (maximumCenter - minimumCenter)));
230
+ }
231
+
232
+ const matches: LocalMatch[] = [];
233
+ for (const referenceCenter of [...centers].sort((left, right) => left - right)) {
234
+ const candidates: LagScore[] = [];
235
+ for (let delta = -maximumDriftSamples; delta <= maximumDriftSamples; delta += 1) {
236
+ candidates.push(windowCorrelation(reference, target, referenceCenter, initialLag + delta, windowSamples));
237
+ }
238
+ const ranked = candidates.sort((left, right) => right.score - left.score || left.lagSamples - right.lagSamples);
239
+ const best = ranked[0];
240
+ if (best === undefined || best.score <= 0) continue;
241
+ const competitor = ranked.find(candidate => Math.abs(candidate.lagSamples - best.lagSamples) >= 2);
242
+ matches.push({
243
+ ...best,
244
+ ambiguity: ambiguity(best.score, competitor?.score, ambiguityMargin),
245
+ referenceSample: referenceCenter,
246
+ targetSample: referenceCenter + best.lagSamples,
247
+ windowSamples,
248
+ });
249
+ }
250
+ return matches;
251
+ }
252
+
253
+ function theilSen(matches: readonly LocalMatch[]): { readonly intercept: number; readonly slope: number } {
254
+ if (matches.length < 2) {
255
+ const only = matches[0];
256
+ return { intercept: only === undefined ? 0 : only.targetSample - only.referenceSample, slope: 1 };
257
+ }
258
+ const slopes: number[] = [];
259
+ for (let leftIndex = 0; leftIndex < matches.length; leftIndex += 1) {
260
+ for (let rightIndex = leftIndex + 1; rightIndex < matches.length; rightIndex += 1) {
261
+ const left = matches[leftIndex]!;
262
+ const right = matches[rightIndex]!;
263
+ const denominator = right.referenceSample - left.referenceSample;
264
+ if (denominator > 0) slopes.push((right.targetSample - left.targetSample) / denominator);
265
+ }
266
+ }
267
+ const slope = median(slopes);
268
+ return {
269
+ intercept: median(matches.map(match => match.targetSample - slope * match.referenceSample)),
270
+ slope,
271
+ };
272
+ }
273
+
274
+ function candidateIdentifier(rank: number): AlignmentCandidate["candidateId"] {
275
+ return `candidate_alignment${String(rank + 1).padStart(4, "0")}` as AlignmentCandidate["candidateId"];
276
+ }
277
+
278
+ function fitCandidate(
279
+ reference: Required<EnvelopeSeries>,
280
+ target: Required<EnvelopeSeries>,
281
+ peak: LagScore,
282
+ competitorScore: number | undefined,
283
+ rank: number,
284
+ config: AudioAlignmentAnalysisV1["config"],
285
+ options: Required<Pick<AudioAlignmentOptions, "ambiguityMargin" | "distinctPeakUs" | "minimumCorrelation">>,
286
+ ): FittedCandidate {
287
+ const hopUs = reference.hopUs;
288
+ const windowSamples = Math.max(4, Math.round(config.windowUs / hopUs));
289
+ const durationSamples = Math.min(reference.values.length, target.values.length);
290
+ const maximumDriftSamples = Math.max(2, Math.ceil(durationSamples * config.maxDriftPpm / 1_000_000) + 1);
291
+ let matches = localMatches(
292
+ reference.values,
293
+ target.values,
294
+ peak.lagSamples,
295
+ windowSamples,
296
+ maximumDriftSamples,
297
+ options.ambiguityMargin,
298
+ );
299
+ if (matches.length < 2) {
300
+ const referenceStart = Math.max(0, -peak.lagSamples);
301
+ const targetStart = Math.max(0, peak.lagSamples);
302
+ const overlap = Math.max(2, peak.overlapSamples);
303
+ matches = [
304
+ {
305
+ ...peak,
306
+ ambiguity: ambiguity(peak.score, competitorScore, options.ambiguityMargin),
307
+ referenceSample: referenceStart,
308
+ targetSample: targetStart,
309
+ windowSamples: Math.min(windowSamples, overlap),
310
+ },
311
+ {
312
+ ...peak,
313
+ ambiguity: ambiguity(peak.score, competitorScore, options.ambiguityMargin),
314
+ referenceSample: referenceStart + overlap - 1,
315
+ targetSample: targetStart + overlap - 1,
316
+ windowSamples: Math.min(windowSamples, overlap),
317
+ },
318
+ ];
319
+ }
320
+ const fitted = theilSen(matches);
321
+ const driftPpm = (fitted.slope - 1) * 1_000_000;
322
+ const residualsUs = matches.map(match => Math.abs(
323
+ match.targetSample - (fitted.intercept + fitted.slope * match.referenceSample)
324
+ ) * hopUs);
325
+ const referenceOverlapStart = Math.max(0, Math.ceil(-fitted.intercept / Math.max(EPSILON, fitted.slope)));
326
+ const referenceOverlapEnd = Math.min(
327
+ reference.values.length - 1,
328
+ Math.floor((target.values.length - 1 - fitted.intercept) / Math.max(EPSILON, fitted.slope)),
329
+ );
330
+ const anchorReferenceSamples = referenceOverlapEnd > referenceOverlapStart
331
+ ? [referenceOverlapStart, referenceOverlapEnd]
332
+ : [matches[0]!.referenceSample, matches.at(-1)!.referenceSample];
333
+ const anchors = anchorReferenceSamples.map(referenceSample => ({
334
+ referenceAssetTimeUs: Math.round(reference.startUs + referenceSample * hopUs),
335
+ targetAssetTimeUs: Math.max(0, Math.round(target.startUs + (fitted.intercept + fitted.slope * referenceSample) * hopUs)),
336
+ }));
337
+ const candidateAmbiguity = ambiguity(peak.score, competitorScore, options.ambiguityMargin);
338
+ const residualPenalty = 1 - clamp(median(residualsUs) / Math.max(config.windowUs / 4, hopUs), 0, 1);
339
+ const overlapUs = Math.max(0, (referenceOverlapEnd - referenceOverlapStart) * hopUs);
340
+ const overlapFactor = clamp(overlapUs / Math.max(config.minimumOverlapUs, 1), 0, 1);
341
+ const correlationConfidence = clamp((peak.score - options.minimumCorrelation) / Math.max(0.001, 1 - options.minimumCorrelation), 0, 1);
342
+ const confidence = clamp(
343
+ 0.55 * correlationConfidence + 0.25 * residualPenalty + 0.2 * overlapFactor,
344
+ 0,
345
+ 1,
346
+ );
347
+ const firstAnchor = anchors[0]!;
348
+ const initialOffsetUs = firstAnchor.targetAssetTimeUs - firstAnchor.referenceAssetTimeUs;
349
+ const candidate = AlignmentCandidateSchema.parse({
350
+ ambiguity: candidateAmbiguity,
351
+ anchors,
352
+ autoApplicable: confidence >= 0.8
353
+ && candidateAmbiguity <= 0.2
354
+ && Math.abs(driftPpm) <= config.maxDriftPpm,
355
+ candidateId: candidateIdentifier(rank),
356
+ confidence,
357
+ driftPpm: clamp(driftPpm, -100_000, 100_000),
358
+ initialOffsetUs,
359
+ maxResidualUs: Math.round(Math.max(...residualsUs, 0)),
360
+ medianResidualUs: Math.round(median(residualsUs)),
361
+ overlapUs: Math.round(overlapUs),
362
+ peakRatio: peak.score <= 0
363
+ ? 0
364
+ : peak.score / Math.max(EPSILON, Math.max(0, competitorScore ?? 0)),
365
+ });
366
+ return { candidate, matches, score: peak.score };
367
+ }
368
+
369
+ /** Analyze already-decoded numeric envelopes without filesystem or process effects. */
370
+ export function analyzeAudioAlignment(input: AnalyzeAudioAlignmentInput): AudioAlignmentAnalysisV1 {
371
+ const reference = assertSeries(input.referenceEnvelope, "Reference");
372
+ const target = assertSeries(input.targetEnvelope, "Target");
373
+ if (reference.hopUs !== target.hopUs) {
374
+ throw new TypeError("Alignment envelopes must use the same hopUs.");
375
+ }
376
+ const hopUs = reference.hopUs;
377
+ const minimumOverlapSamples = Math.max(2, Math.ceil(input.config.minimumOverlapUs / hopUs));
378
+ const base = {
379
+ analysisId: input.analysisId,
380
+ config: input.config,
381
+ createdAt: input.createdAt,
382
+ inputDigest: input.inputDigest,
383
+ kind: "slopcamera.audio-alignment-analysis" as const,
384
+ reference: input.reference,
385
+ schemaVersion: 1 as const,
386
+ target: input.target,
387
+ tool: input.tool,
388
+ };
389
+ const noMatch = (
390
+ reason: "insufficient-overlap" | "low-correlation" | "silent-input" | "unrelated-input",
391
+ diagnostic: string,
392
+ ): AudioAlignmentAnalysisV1 => AudioAlignmentAnalysisV1Schema.parse({
393
+ ...base,
394
+ matches: [],
395
+ result: { diagnostics: [diagnostic], reason, status: "no-match" },
396
+ });
397
+
398
+ if (Math.min(reference.values.length, target.values.length) < minimumOverlapSamples) {
399
+ return noMatch("insufficient-overlap", "The feature series do not contain the configured minimum overlap.");
400
+ }
401
+ if (variance(reference.values) <= EPSILON || variance(target.values) <= EPSILON) {
402
+ return noMatch("silent-input", "At least one feature series has no usable variation.");
403
+ }
404
+
405
+ const options = {
406
+ ambiguityMargin: input.options?.ambiguityMargin ?? DEFAULT_AMBIGUITY_MARGIN,
407
+ distinctPeakUs: input.options?.distinctPeakUs ?? DEFAULT_DISTINCT_PEAK_US,
408
+ minimumCorrelation: input.options?.minimumCorrelation ?? DEFAULT_MINIMUM_CORRELATION,
409
+ };
410
+ if (!Number.isFinite(options.ambiguityMargin) || options.ambiguityMargin < 0 || options.ambiguityMargin > 2) {
411
+ throw new TypeError("ambiguityMargin must be finite and between zero and two.");
412
+ }
413
+ if (!Number.isSafeInteger(options.distinctPeakUs) || options.distinctPeakUs < 0) {
414
+ throw new TypeError("distinctPeakUs must be a nonnegative safe integer.");
415
+ }
416
+ if (!Number.isFinite(options.minimumCorrelation) || options.minimumCorrelation < -1 || options.minimumCorrelation > 1) {
417
+ throw new TypeError("minimumCorrelation must be finite and between negative one and one.");
418
+ }
419
+ if (
420
+ input.options?.maxOffsetUs !== undefined
421
+ && (!Number.isSafeInteger(input.options.maxOffsetUs) || input.options.maxOffsetUs < 0)
422
+ ) {
423
+ throw new TypeError("maxOffsetUs must be a nonnegative safe integer.");
424
+ }
425
+ const maxPossibleLag = Math.max(reference.values.length, target.values.length) - minimumOverlapSamples;
426
+ const configuredMaximum = input.options?.maxOffsetUs === undefined
427
+ ? maxPossibleLag
428
+ : Math.min(maxPossibleLag, Math.floor(input.options.maxOffsetUs / hopUs));
429
+ const scores = scanLags(reference.values, target.values, -configuredMaximum, configuredMaximum)
430
+ .filter(score => score.overlapSamples >= minimumOverlapSamples);
431
+ const peaks = distinctPeaks(scores, Math.max(2, Math.ceil(options.distinctPeakUs / hopUs)));
432
+ const best = peaks[0];
433
+ if (best === undefined || best.score < options.minimumCorrelation) {
434
+ return noMatch(
435
+ best === undefined || best.score < 0.15 ? "unrelated-input" : "low-correlation",
436
+ `The strongest normalized envelope correlation was ${best?.score.toFixed(4) ?? "unavailable"}.`,
437
+ );
438
+ }
439
+
440
+ const competitive = peaks.filter(peak => peak.score >= Math.max(options.minimumCorrelation, best.score - options.ambiguityMargin));
441
+ const selectedPeaks = competitive.length > 1 ? competitive.slice(0, 32) : [best];
442
+ const fitted = selectedPeaks.map((peak, rank) => fitCandidate(
443
+ reference,
444
+ target,
445
+ peak,
446
+ peaks.find(candidate => candidate !== peak)?.score,
447
+ rank,
448
+ input.config,
449
+ options,
450
+ ));
451
+ const matches = fitted[0]!.matches.map(match => ({
452
+ ambiguity: match.ambiguity,
453
+ confidence: clamp((match.score + 1) / 2, 0, 1),
454
+ referenceAssetTimeUs: Math.round(reference.startUs + match.referenceSample * hopUs),
455
+ targetAssetTimeUs: Math.round(target.startUs + match.targetSample * hopUs),
456
+ windowUs: Math.round(match.windowSamples * hopUs),
457
+ }));
458
+ const candidates = fitted.map(item => item.candidate);
459
+ return AudioAlignmentAnalysisV1Schema.parse({
460
+ ...base,
461
+ matches,
462
+ result: competitive.length > 1
463
+ ? { candidates, reason: "periodic-or-competing-matches", status: "ambiguous" }
464
+ : { candidates, status: "matched" },
465
+ });
466
+ }
@@ -0,0 +1,209 @@
1
+ import {
2
+ AutomaticZoomPlannerConfigSchema,
3
+ AutomaticZoomSchema,
4
+ type AutomaticZoom,
5
+ type AutomaticZoomPlannerConfig,
6
+ type ZoomTarget,
7
+ } from "../contracts/edit";
8
+ import type { RecordingEventV1 } from "../contracts/recording";
9
+ import { findWindowAtTime } from "./events";
10
+
11
+ type Intent = Readonly<{
12
+ atUs: number;
13
+ confidence: number;
14
+ displayId: string;
15
+ priority: number;
16
+ reason: AutomaticZoom["reason"];
17
+ target: ZoomTarget;
18
+ }>;
19
+
20
+ type IntentGroup = Readonly<{
21
+ firstUs: number;
22
+ intents: readonly Intent[];
23
+ lastUs: number;
24
+ }>;
25
+
26
+ function intentsFromEvents(events: readonly RecordingEventV1[]): readonly Intent[] {
27
+ return events.flatMap((event): readonly Intent[] => {
28
+ if (event.type === "mouse.click" && event.phase === "down") {
29
+ return [{
30
+ atUs: event.sourceTimeUs,
31
+ confidence: 0.9,
32
+ displayId: event.displayId,
33
+ priority: 2,
34
+ reason: "click",
35
+ target: { kind: "point", point: event.position },
36
+ }];
37
+ }
38
+ if (event.type === "typing.input") {
39
+ const displayId = findWindowAtTime(
40
+ events,
41
+ { kind: "window-id", windowId: event.input.windowId },
42
+ event.sourceTimeUs,
43
+ )?.displayId;
44
+ if (displayId === undefined) return [];
45
+ return [{
46
+ atUs: event.sourceTimeUs,
47
+ confidence: 1,
48
+ displayId,
49
+ priority: 4,
50
+ reason: "typing",
51
+ target: { kind: "rect", rect: {
52
+ height: event.input.bounds.height + 48,
53
+ width: event.input.bounds.width + 48,
54
+ x: event.input.bounds.x - 24,
55
+ y: event.input.bounds.y - 24,
56
+ } },
57
+ }];
58
+ }
59
+ if (event.type === "focus.changed" && event.target.kind !== "none") {
60
+ const displayId = findWindowAtTime(
61
+ events,
62
+ { kind: "window-id", windowId: event.target.windowId },
63
+ event.sourceTimeUs,
64
+ )?.displayId;
65
+ if (displayId === undefined) return [];
66
+ return [{
67
+ atUs: event.sourceTimeUs,
68
+ confidence: 0.95,
69
+ displayId,
70
+ priority: 3,
71
+ reason: "focus",
72
+ target: { kind: "rect", rect: {
73
+ height: event.target.bounds.height + 48,
74
+ width: event.target.bounds.width + 48,
75
+ x: event.target.bounds.x - 24,
76
+ y: event.target.bounds.y - 24,
77
+ } },
78
+ }];
79
+ }
80
+ if (event.type === "window.changed" && event.change.kind === "focused") {
81
+ return [{
82
+ atUs: event.sourceTimeUs,
83
+ confidence: 0.8,
84
+ displayId: event.change.window.displayId,
85
+ priority: 1,
86
+ reason: "window-change",
87
+ target: { kind: "rect", rect: {
88
+ height: event.change.window.bounds.height + 32,
89
+ width: event.change.window.bounds.width + 32,
90
+ x: event.change.window.bounds.x - 16,
91
+ y: event.change.window.bounds.y - 16,
92
+ } },
93
+ }];
94
+ }
95
+ return [];
96
+ }).sort((left, right) => left.atUs - right.atUs || right.priority - left.priority);
97
+ }
98
+
99
+ function groupIntents(intents: readonly Intent[], config: AutomaticZoomPlannerConfig): readonly IntentGroup[] {
100
+ const groupsByDisplay = new Map<string, IntentGroup[]>();
101
+ for (const intent of intents) {
102
+ const groups = groupsByDisplay.get(intent.displayId) ?? [];
103
+ const prior = groups.at(-1);
104
+ if (
105
+ prior === undefined
106
+ || prior.intents[0]?.displayId !== intent.displayId
107
+ || intent.atUs - prior.lastUs > config.intentMergeGapUs
108
+ || intent.atUs - prior.firstUs > config.maxDurationUs
109
+ ) {
110
+ groups.push({ firstUs: intent.atUs, intents: [intent], lastUs: intent.atUs });
111
+ } else {
112
+ groups[groups.length - 1] = {
113
+ firstUs: prior.firstUs,
114
+ intents: [...prior.intents, intent],
115
+ lastUs: intent.atUs,
116
+ };
117
+ }
118
+ groupsByDisplay.set(intent.displayId, groups);
119
+ }
120
+ return [...groupsByDisplay.values()].flat()
121
+ .sort((left, right) => (
122
+ left.firstUs - right.firstUs
123
+ || (left.intents[0]?.displayId ?? "").localeCompare(right.intents[0]?.displayId ?? "")
124
+ ));
125
+ }
126
+
127
+ function strongestIntent(group: IntentGroup): Intent {
128
+ const intent = [...group.intents].sort((left, right) => right.priority - left.priority || right.atUs - left.atUs)[0];
129
+ if (intent === undefined) throw new Error("Automatic zoom group cannot be empty.");
130
+ return intent;
131
+ }
132
+
133
+ export function planAutomaticZooms(
134
+ events: readonly RecordingEventV1[],
135
+ sourceDurationUs: number,
136
+ configInput: AutomaticZoomPlannerConfig,
137
+ ): readonly AutomaticZoom[] {
138
+ const config = AutomaticZoomPlannerConfigSchema.parse(configInput);
139
+ if (!Number.isSafeInteger(sourceDurationUs) || sourceDurationUs < 0) {
140
+ throw new RangeError("sourceDurationUs must be a non-negative safe integer.");
141
+ }
142
+ const groups = groupIntents(intentsFromEvents(events), config);
143
+ const ranges = groups.map((group) => {
144
+ let startUs = Math.max(0, group.firstUs - config.preHandleUs);
145
+ let endUs = Math.min(sourceDurationUs, group.lastUs + config.postHandleUs);
146
+ if (endUs - startUs < config.minDurationUs) {
147
+ const missingUs = config.minDurationUs - (endUs - startUs);
148
+ const beforeUs = Math.min(startUs, Math.floor(missingUs / 2));
149
+ startUs -= beforeUs;
150
+ endUs = Math.min(sourceDurationUs, endUs + missingUs - beforeUs);
151
+ startUs = Math.max(0, endUs - config.minDurationUs);
152
+ }
153
+ if (endUs - startUs > config.maxDurationUs) endUs = startUs + config.maxDurationUs;
154
+ return { endUs, group, startUs };
155
+ }).filter(({ endUs, startUs }) => endUs > startUs);
156
+
157
+ const suppressedByDisplay = new Map<string, typeof ranges>();
158
+ for (const range of ranges) {
159
+ const displayId = strongestIntent(range.group).displayId;
160
+ const suppressed = suppressedByDisplay.get(displayId) ?? [];
161
+ const prior = suppressed.at(-1);
162
+ if (prior === undefined || range.startUs >= prior.endUs) {
163
+ suppressed.push(range);
164
+ suppressedByDisplay.set(displayId, suppressed);
165
+ continue;
166
+ }
167
+ const combinedGroup: IntentGroup = {
168
+ firstUs: prior.group.firstUs,
169
+ intents: [...prior.group.intents, ...range.group.intents],
170
+ lastUs: range.group.lastUs,
171
+ };
172
+ const mergedEndUs = Math.min(
173
+ sourceDurationUs,
174
+ prior.startUs + config.maxDurationUs,
175
+ Math.max(prior.endUs, range.endUs, prior.startUs + config.minDurationUs),
176
+ );
177
+ suppressed[suppressed.length - 1] = { endUs: mergedEndUs, group: combinedGroup, startUs: prior.startUs };
178
+ if (range.endUs > mergedEndUs) {
179
+ suppressed.push({ ...range, startUs: mergedEndUs });
180
+ }
181
+ suppressedByDisplay.set(displayId, suppressed);
182
+ }
183
+
184
+ const suppressed = [...suppressedByDisplay.values()].flat()
185
+ .filter(({ endUs, startUs }) => endUs > startUs)
186
+ .sort((left, right) => (
187
+ left.startUs - right.startUs
188
+ || strongestIntent(left.group).displayId.localeCompare(strongestIntent(right.group).displayId)
189
+ ));
190
+ return suppressed.map(({ startUs, endUs, group }, index) => {
191
+ const intent = strongestIntent(group);
192
+ const durationUs = endUs - startUs;
193
+ const enterDurationUs = Math.min(config.enterDurationUs, Math.floor(durationUs / 2));
194
+ const exitDurationUs = Math.min(config.exitDurationUs, durationUs - enterDurationUs);
195
+ return AutomaticZoomSchema.parse({
196
+ confidence: intent.confidence,
197
+ displayId: intent.displayId,
198
+ easing: { kind: "ease-in-out" },
199
+ enterDurationUs,
200
+ exitDurationUs,
201
+ kind: "automatic",
202
+ range: { startUs, endUs },
203
+ reason: intent.reason,
204
+ scale: Math.min(config.scale, config.maxScale),
205
+ target: intent.target,
206
+ zoomId: `zoom_auto${String(index + 1).padStart(4, "0")}`,
207
+ });
208
+ });
209
+ }
@@ -0,0 +1,14 @@
1
+ /** Desktop compatibility façade for the canonical SDK identity primitives. */
2
+ export {
3
+ boundedCanonicalJson,
4
+ boundedCanonicalJsonFingerprint,
5
+ boundedCanonicalJsonSha256,
6
+ canonicalJson,
7
+ canonicalJsonFingerprint,
8
+ canonicalJsonSha256,
9
+ compareUtf16Strings,
10
+ sha256Hex,
11
+ type CanonicalJsonBounds,
12
+ type CanonicalJsonValue,
13
+ type CanonicalJsonFingerprint,
14
+ } from "@hraness/slopcamera/code/advanced";