@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,740 @@
1
+ import { z } from "zod";
2
+
3
+ import {
4
+ CameraMoveIdSchema,
5
+ CameraPoseSchema,
6
+ ClickEffectSchema,
7
+ EditPlanIdSchema,
8
+ EasingSchema,
9
+ KeystrokeEffectSchema,
10
+ OverlayOperationSchema,
11
+ SourceIntervalSchema,
12
+ SpeedRangeSchema,
13
+ TypedTextEffectSchema,
14
+ CursorEffectSchema,
15
+ ZoomOperationSchema,
16
+ } from "./edit";
17
+ import {
18
+ IsoTimestampSchema,
19
+ MicrosecondsSchema,
20
+ PositiveMicrosecondsSchema,
21
+ RecordingIdSchema,
22
+ RepositoryRelativePathSchema,
23
+ Sha256Schema,
24
+ TrackIdSchema,
25
+ type ReadonlyInferred,
26
+ } from "./recording";
27
+
28
+ const ID_SUFFIX = /^[a-z0-9][a-z0-9_-]{7,63}$/u;
29
+
30
+ function projectId(prefix: string) {
31
+ return z.string().refine(
32
+ value => value.startsWith(prefix) && ID_SUFFIX.test(value.slice(prefix.length)),
33
+ `Expected an opaque ${prefix} identifier.`,
34
+ );
35
+ }
36
+
37
+ export const VideoProjectIdSchema = projectId("project_").brand<"VideoProjectId">();
38
+ export const ProjectAssetIdSchema = projectId("asset_").brand<"ProjectAssetId">();
39
+ export const ProjectStreamIdSchema = projectId("stream_").brand<"ProjectStreamId">();
40
+ export const ProjectPlacementIdSchema = projectId("placement_").brand<"ProjectPlacementId">();
41
+ export const AnalysisIdSchema = projectId("analysis_").brand<"AnalysisId">();
42
+ export const ProjectEditDecisionIdSchema = projectId("decision_").brand<"ProjectEditDecisionId">();
43
+
44
+ export const ProjectMediaSegmentSchema = z.strictObject({
45
+ assetRange: SourceIntervalSchema,
46
+ bytes: z.number().int().safe().positive(),
47
+ codec: z.string().min(1).max(128),
48
+ container: z.string().min(1).max(64),
49
+ fileRange: SourceIntervalSchema,
50
+ path: RepositoryRelativePathSchema,
51
+ sha256: Sha256Schema,
52
+ streamIndex: z.number().int().safe().nonnegative(),
53
+ }).superRefine((segment, context) => {
54
+ if (
55
+ segment.assetRange.endUs - segment.assetRange.startUs
56
+ !== segment.fileRange.endUs - segment.fileRange.startUs
57
+ ) {
58
+ context.addIssue({
59
+ code: "custom",
60
+ message: "Project media segment asset and file ranges must have equal duration.",
61
+ });
62
+ }
63
+ });
64
+
65
+ const StreamBaseShape = {
66
+ label: z.string().min(1).max(512),
67
+ segments: z.array(ProjectMediaSegmentSchema).min(1),
68
+ streamId: ProjectStreamIdSchema,
69
+ } as const;
70
+
71
+ export const ProjectVideoStreamSchema = z.strictObject({
72
+ ...StreamBaseShape,
73
+ frameRate: z.number().finite().positive().max(1_000),
74
+ kind: z.literal("video"),
75
+ pixelHeight: z.number().int().safe().positive().max(16_384),
76
+ pixelWidth: z.number().int().safe().positive().max(16_384),
77
+ role: z.enum(["screen", "camera", "b-roll", "other"]),
78
+ }).superRefine((stream, context) => {
79
+ if (stream.pixelWidth * stream.pixelHeight > 134_217_728) {
80
+ context.addIssue({ code: "custom", message: "Project video stream exceeds the 128-megapixel safety limit." });
81
+ }
82
+ });
83
+
84
+ export const ProjectAudioStreamSchema = z.strictObject({
85
+ ...StreamBaseShape,
86
+ channels: z.number().int().safe().positive().max(64),
87
+ kind: z.literal("audio"),
88
+ role: z.enum(["system-audio", "microphone", "portable-audio", "music", "dialogue", "other"]),
89
+ sampleRateHz: z.number().int().safe().positive().max(768_000),
90
+ });
91
+
92
+ export const ProjectMediaStreamSchema = z.discriminatedUnion("kind", [
93
+ ProjectVideoStreamSchema,
94
+ ProjectAudioStreamSchema,
95
+ ]);
96
+
97
+ export const ProjectAssetSourceSchema = z.discriminatedUnion("kind", [
98
+ z.strictObject({
99
+ kind: z.literal("recording"),
100
+ recordingId: RecordingIdSchema,
101
+ trackIds: z.array(TrackIdSchema).min(1),
102
+ }),
103
+ z.strictObject({
104
+ importedAt: IsoTimestampSchema,
105
+ kind: z.literal("imported"),
106
+ originalName: z.string().min(1).max(1_024),
107
+ sourceSha256: Sha256Schema,
108
+ }),
109
+ z.strictObject({
110
+ generator: z.string().min(1).max(256),
111
+ generatorVersion: z.string().min(1).max(128),
112
+ kind: z.literal("generated"),
113
+ sourceSha256: Sha256Schema,
114
+ }),
115
+ ]);
116
+
117
+ export const ProjectAssetRoleSchema = z.enum([
118
+ "screen",
119
+ "camera",
120
+ "b-roll",
121
+ "system-audio",
122
+ "microphone",
123
+ "portable-audio",
124
+ "music",
125
+ "dialogue",
126
+ "other",
127
+ ]);
128
+
129
+ function segmentsAreOrdered(segments: readonly z.infer<typeof ProjectMediaSegmentSchema>[]): boolean {
130
+ let priorEndUs = -1;
131
+ for (const segment of segments) {
132
+ if (segment.assetRange.startUs < priorEndUs) return false;
133
+ priorEndUs = segment.assetRange.endUs;
134
+ }
135
+ return true;
136
+ }
137
+
138
+ export const ProjectAssetV1Schema = z.strictObject({
139
+ assetId: ProjectAssetIdSchema,
140
+ createdAt: IsoTimestampSchema,
141
+ durationUs: PositiveMicrosecondsSchema,
142
+ label: z.string().min(1).max(512),
143
+ role: ProjectAssetRoleSchema,
144
+ source: ProjectAssetSourceSchema,
145
+ streams: z.array(ProjectMediaStreamSchema).min(1),
146
+ }).superRefine((asset, context) => {
147
+ const integrityByPath = new Map<string, { readonly bytes: number; readonly sha256: string }>();
148
+ if (new Set(asset.streams.map(stream => stream.streamId)).size !== asset.streams.length) {
149
+ context.addIssue({ code: "custom", message: "Project stream IDs must be unique within an asset." });
150
+ }
151
+ for (const stream of asset.streams) {
152
+ for (const segment of stream.segments) {
153
+ const prior = integrityByPath.get(segment.path);
154
+ if (prior !== undefined && (prior.bytes !== segment.bytes || prior.sha256 !== segment.sha256)) {
155
+ context.addIssue({
156
+ code: "custom",
157
+ message: `Segments for ${segment.path} must agree on whole-file integrity.`,
158
+ });
159
+ }
160
+ integrityByPath.set(segment.path, { bytes: segment.bytes, sha256: segment.sha256 });
161
+ }
162
+ if (!segmentsAreOrdered(stream.segments)) {
163
+ context.addIssue({
164
+ code: "custom",
165
+ message: `Segments for ${stream.streamId} must be ordered and non-overlapping.`,
166
+ });
167
+ }
168
+ if (stream.segments.some(segment => segment.assetRange.endUs > asset.durationUs)) {
169
+ context.addIssue({
170
+ code: "custom",
171
+ message: `Segments for ${stream.streamId} exceed the asset duration.`,
172
+ });
173
+ }
174
+ }
175
+ const hasVideo = asset.streams.some(stream => stream.kind === "video");
176
+ const hasAudio = asset.streams.some(stream => stream.kind === "audio");
177
+ if ((asset.role === "screen" || asset.role === "camera" || asset.role === "b-roll") && !hasVideo) {
178
+ context.addIssue({ code: "custom", message: `Asset role ${asset.role} requires a video stream.` });
179
+ }
180
+ if (
181
+ (asset.role === "system-audio"
182
+ || asset.role === "microphone"
183
+ || asset.role === "portable-audio"
184
+ || asset.role === "music"
185
+ || asset.role === "dialogue")
186
+ && !hasAudio
187
+ ) {
188
+ context.addIssue({ code: "custom", message: `Asset role ${asset.role} requires an audio stream.` });
189
+ }
190
+ });
191
+
192
+ export const SyncAnchorSchema = z.strictObject({
193
+ assetTimeUs: MicrosecondsSchema,
194
+ projectTimeUs: MicrosecondsSchema,
195
+ });
196
+
197
+ export const SyncProvenanceSchema = z.discriminatedUnion("kind", [
198
+ z.strictObject({ kind: z.literal("identity") }),
199
+ z.strictObject({
200
+ kind: z.literal("unverified"),
201
+ reason: z.enum(["initial-placement", "insufficient-evidence"]),
202
+ }),
203
+ z.strictObject({
204
+ kind: z.literal("manual"),
205
+ note: z.string().min(1).max(2_048).optional(),
206
+ }),
207
+ z.strictObject({
208
+ analysisId: AnalysisIdSchema,
209
+ confidence: z.number().finite().min(0).max(1),
210
+ kind: z.literal("audio-alignment"),
211
+ maxResidualUs: MicrosecondsSchema,
212
+ }),
213
+ ]);
214
+
215
+ export const ProjectSyncMapSchema = z.strictObject({
216
+ anchors: z.array(SyncAnchorSchema).min(2).max(4_096),
217
+ provenance: SyncProvenanceSchema,
218
+ }).superRefine((map, context) => {
219
+ for (let index = 1; index < map.anchors.length; index += 1) {
220
+ const prior = map.anchors[index - 1]!;
221
+ const current = map.anchors[index]!;
222
+ if (current.assetTimeUs <= prior.assetTimeUs) {
223
+ context.addIssue({ code: "custom", message: "Sync anchor asset times must increase strictly." });
224
+ return;
225
+ }
226
+ if (current.projectTimeUs <= prior.projectTimeUs) {
227
+ context.addIssue({ code: "custom", message: "Sync anchor project times must increase strictly." });
228
+ return;
229
+ }
230
+ }
231
+ });
232
+
233
+ export const ProjectVideoCropSchema = z.discriminatedUnion("kind", [
234
+ z.strictObject({ kind: z.literal("none") }),
235
+ z.strictObject({
236
+ bottom: z.number().finite().min(0).max(1),
237
+ kind: z.literal("normalized-insets"),
238
+ left: z.number().finite().min(0).max(1),
239
+ right: z.number().finite().min(0).max(1),
240
+ top: z.number().finite().min(0).max(1),
241
+ }).superRefine((crop, context) => {
242
+ if (crop.left + crop.right >= 1) {
243
+ context.addIssue({ code: "custom", message: "Project video horizontal crop insets must leave visible content." });
244
+ }
245
+ if (crop.top + crop.bottom >= 1) {
246
+ context.addIssue({ code: "custom", message: "Project video vertical crop insets must leave visible content." });
247
+ }
248
+ }),
249
+ ]);
250
+
251
+ export const ProjectVideoPresentationSchema = z.discriminatedUnion("enabled", [
252
+ z.strictObject({ enabled: z.literal(false) }),
253
+ z.strictObject({
254
+ blendMode: z.enum(["normal", "multiply", "screen", "overlay", "darken", "lighten"]),
255
+ crop: ProjectVideoCropSchema,
256
+ enabled: z.literal(true),
257
+ fit: z.enum(["contain", "cover", "fill"]),
258
+ layer: z.number().int().safe(),
259
+ layout: z.discriminatedUnion("kind", [
260
+ z.strictObject({
261
+ height: z.number().finite().positive().max(1),
262
+ kind: z.literal("normalized"),
263
+ width: z.number().finite().positive().max(1),
264
+ x: z.number().finite().min(0).max(1),
265
+ y: z.number().finite().min(0).max(1),
266
+ }).superRefine((layout, context) => {
267
+ if (layout.x + layout.width > 1 || layout.y + layout.height > 1) {
268
+ context.addIssue({ code: "custom", message: "Normalized video layout must stay inside the output canvas." });
269
+ }
270
+ }),
271
+ z.strictObject({
272
+ height: z.number().finite().positive().max(16_384),
273
+ kind: z.literal("output-pixels"),
274
+ width: z.number().finite().positive().max(16_384),
275
+ x: z.number().finite().nonnegative().max(16_384),
276
+ y: z.number().finite().nonnegative().max(16_384),
277
+ }).superRefine((layout, context) => {
278
+ if (layout.width * layout.height > 134_217_728) {
279
+ context.addIssue({ code: "custom", message: "Video layout exceeds the 128-megapixel safety limit." });
280
+ }
281
+ }),
282
+ ]),
283
+ opacity: z.number().finite().min(0).max(1),
284
+ }),
285
+ ]);
286
+
287
+ export const ProjectAudioPresentationSchema = z.discriminatedUnion("enabled", [
288
+ z.strictObject({ enabled: z.literal(false) }),
289
+ z.strictObject({
290
+ enabled: z.literal(true),
291
+ gainDb: z.number().finite().min(-96).max(24),
292
+ pan: z.number().finite().min(-1).max(1),
293
+ }),
294
+ ]);
295
+
296
+ export const ProjectPlacementV1Schema = z.strictObject({
297
+ assetId: ProjectAssetIdSchema,
298
+ assetRange: SourceIntervalSchema,
299
+ audio: z.array(z.strictObject({
300
+ presentation: ProjectAudioPresentationSchema,
301
+ streamId: ProjectStreamIdSchema,
302
+ })),
303
+ enabled: z.boolean(),
304
+ placementId: ProjectPlacementIdSchema,
305
+ sync: ProjectSyncMapSchema,
306
+ video: z.array(z.strictObject({
307
+ presentation: ProjectVideoPresentationSchema,
308
+ streamId: ProjectStreamIdSchema,
309
+ })),
310
+ }).superRefine((placement, context) => {
311
+ const first = placement.sync.anchors[0]!;
312
+ const last = placement.sync.anchors.at(-1)!;
313
+ if (
314
+ first.assetTimeUs !== placement.assetRange.startUs
315
+ || last.assetTimeUs !== placement.assetRange.endUs
316
+ ) {
317
+ context.addIssue({
318
+ code: "custom",
319
+ message: "The first and last sync anchors must equal the placement asset range.",
320
+ });
321
+ }
322
+ const streamIds = [...placement.video, ...placement.audio].map(stream => stream.streamId);
323
+ if (new Set(streamIds).size !== streamIds.length) {
324
+ context.addIssue({ code: "custom", message: "A placement may configure each stream at most once." });
325
+ }
326
+ });
327
+
328
+ const AnalysisReferenceBaseShape = {
329
+ analysisId: AnalysisIdSchema,
330
+ createdAt: IsoTimestampSchema,
331
+ path: RepositoryRelativePathSchema,
332
+ sha256: Sha256Schema,
333
+ } as const;
334
+
335
+ export const ProjectAnalysisReferenceSchema = z.discriminatedUnion("kind", [
336
+ z.strictObject({
337
+ ...AnalysisReferenceBaseShape,
338
+ confidence: z.number().finite().min(0).max(1),
339
+ driftPpm: z.number().finite(),
340
+ kind: z.literal("audio-alignment"),
341
+ referencePlacementId: ProjectPlacementIdSchema,
342
+ targetPlacementId: ProjectPlacementIdSchema,
343
+ }),
344
+ z.strictObject({
345
+ ...AnalysisReferenceBaseShape,
346
+ audioStreams: z.number().int().safe().nonnegative(),
347
+ displayStreams: z.number().int().safe().positive(),
348
+ kind: z.literal("inactivity"),
349
+ projectStructureSha256: Sha256Schema,
350
+ recommendedRanges: z.number().int().safe().nonnegative(),
351
+ }),
352
+ z.strictObject({
353
+ ...AnalysisReferenceBaseShape,
354
+ assetId: ProjectAssetIdSchema,
355
+ keyRegions: z.number().int().safe().nonnegative(),
356
+ kind: z.literal("music"),
357
+ musicRegions: z.number().int().safe().nonnegative(),
358
+ streamId: ProjectStreamIdSchema,
359
+ tempoRegions: z.number().int().safe().nonnegative(),
360
+ }),
361
+ z.strictObject({
362
+ ...AnalysisReferenceBaseShape,
363
+ assetId: ProjectAssetIdSchema,
364
+ kind: z.literal("scenes"),
365
+ model: z.string().min(1).max(256),
366
+ sceneCount: z.number().int().safe().nonnegative(),
367
+ streamIds: z.array(ProjectStreamIdSchema).min(1).max(8),
368
+ }),
369
+ z.strictObject({
370
+ ...AnalysisReferenceBaseShape,
371
+ analyzedFrames: z.number().int().safe().nonnegative().max(250_000),
372
+ assetId: ProjectAssetIdSchema,
373
+ kind: z.literal("faces"),
374
+ localOnly: z.literal(true),
375
+ streamId: ProjectStreamIdSchema,
376
+ subjectIntegritySha256: Sha256Schema,
377
+ trackCount: z.number().int().safe().nonnegative().max(100_000),
378
+ }),
379
+ z.strictObject({
380
+ ...AnalysisReferenceBaseShape,
381
+ assetId: ProjectAssetIdSchema,
382
+ fillerCount: z.number().int().safe().nonnegative(),
383
+ kind: z.literal("speech"),
384
+ streamId: ProjectStreamIdSchema,
385
+ wordCount: z.number().int().safe().nonnegative(),
386
+ }),
387
+ ]);
388
+
389
+ export const VideoProjectV1Schema = z.strictObject({
390
+ analyses: z.array(ProjectAnalysisReferenceSchema),
391
+ assets: z.array(ProjectAssetV1Schema),
392
+ createdAt: IsoTimestampSchema,
393
+ currentEditPlanPath: RepositoryRelativePathSchema.nullable(),
394
+ kind: z.union([
395
+ z.literal("slopcamera.video-project"),
396
+ z.literal("studio.video-project"),
397
+ ]),
398
+ name: z.string().min(1).max(512),
399
+ placements: z.array(ProjectPlacementV1Schema),
400
+ projectId: VideoProjectIdSchema,
401
+ referencePlacementId: ProjectPlacementIdSchema,
402
+ schemaVersion: z.literal(1),
403
+ timeline: z.strictObject({
404
+ durationUs: PositiveMicrosecondsSchema,
405
+ timebase: z.literal("microseconds"),
406
+ }),
407
+ updatedAt: IsoTimestampSchema,
408
+ }).superRefine((project, context) => {
409
+ if (Date.parse(project.updatedAt) < Date.parse(project.createdAt)) {
410
+ context.addIssue({ code: "custom", message: "updatedAt cannot precede createdAt." });
411
+ }
412
+ const assetIds = project.assets.map(asset => asset.assetId);
413
+ const placementIds = project.placements.map(placement => placement.placementId);
414
+ const analysisIds = project.analyses.map(analysis => analysis.analysisId);
415
+ for (const [label, ids] of [
416
+ ["Project asset IDs", assetIds.map(String)],
417
+ ["Project placement IDs", placementIds.map(String)],
418
+ ["Project analysis IDs", analysisIds.map(String)],
419
+ ] as const) {
420
+ if (new Set<string>(ids).size !== ids.length) {
421
+ context.addIssue({ code: "custom", message: `${label} must be unique.` });
422
+ }
423
+ }
424
+ const knownPlacements = new Set(placementIds);
425
+ if (!knownPlacements.has(project.referencePlacementId)) {
426
+ context.addIssue({ code: "custom", message: "referencePlacementId must identify a project placement." });
427
+ }
428
+ for (const placement of project.placements) {
429
+ const asset = project.assets.find(candidate => candidate.assetId === placement.assetId);
430
+ if (asset === undefined) {
431
+ context.addIssue({ code: "custom", message: `Placement ${placement.placementId} references an unknown asset.` });
432
+ continue;
433
+ }
434
+ if (placement.assetRange.endUs > asset.durationUs) {
435
+ context.addIssue({ code: "custom", message: `Placement ${placement.placementId} exceeds its asset duration.` });
436
+ }
437
+ if (placement.sync.anchors.some(anchor => anchor.projectTimeUs > project.timeline.durationUs)) {
438
+ context.addIssue({ code: "custom", message: `Placement ${placement.placementId} exceeds the project timeline.` });
439
+ }
440
+ for (const configured of placement.video) {
441
+ const stream = asset.streams.find(candidate => candidate.streamId === configured.streamId);
442
+ if (stream === undefined || stream.kind !== "video") {
443
+ context.addIssue({ code: "custom", message: `Placement ${placement.placementId} configures an unknown video stream.` });
444
+ }
445
+ }
446
+ for (const configured of placement.audio) {
447
+ const stream = asset.streams.find(candidate => candidate.streamId === configured.streamId);
448
+ if (stream === undefined || stream.kind !== "audio") {
449
+ context.addIssue({ code: "custom", message: `Placement ${placement.placementId} configures an unknown audio stream.` });
450
+ }
451
+ }
452
+ }
453
+ for (const analysis of project.analyses) {
454
+ if (analysis.kind === "audio-alignment") {
455
+ if (!knownPlacements.has(analysis.referencePlacementId) || !knownPlacements.has(analysis.targetPlacementId)) {
456
+ context.addIssue({ code: "custom", message: `Alignment ${analysis.analysisId} references an unknown placement.` });
457
+ }
458
+ } else if (analysis.kind !== "inactivity") {
459
+ const asset = project.assets.find(candidate => candidate.assetId === analysis.assetId);
460
+ if (asset === undefined) {
461
+ context.addIssue({ code: "custom", message: `Analysis ${analysis.analysisId} references an unknown asset.` });
462
+ continue;
463
+ }
464
+ const requiredStreamIds = analysis.kind === "scenes" ? analysis.streamIds : [analysis.streamId];
465
+ const requiredKind = analysis.kind === "scenes" || analysis.kind === "faces" ? "video" : "audio";
466
+ if (new Set(requiredStreamIds).size !== requiredStreamIds.length) {
467
+ context.addIssue({ code: "custom", message: `Analysis ${analysis.analysisId} stream IDs must be unique.` });
468
+ }
469
+ for (const streamId of requiredStreamIds) {
470
+ const stream = asset.streams.find(candidate => candidate.streamId === streamId);
471
+ if (stream === undefined || stream.kind !== requiredKind) {
472
+ context.addIssue({
473
+ code: "custom",
474
+ message: `Analysis ${analysis.analysisId} requires a ${requiredKind} stream on its asset.`,
475
+ });
476
+ }
477
+ }
478
+ }
479
+ }
480
+ });
481
+
482
+ export const ProjectZoomOperationSchema = z.strictObject({
483
+ operation: ZoomOperationSchema,
484
+ placementId: ProjectPlacementIdSchema,
485
+ });
486
+
487
+ export const ProjectCameraTransformKeyframeSchema = z.strictObject({
488
+ outgoingEasing: EasingSchema,
489
+ pose: CameraPoseSchema,
490
+ projectTimeUs: MicrosecondsSchema,
491
+ });
492
+
493
+ const FaceTrackReferenceIdSchema = z.string()
494
+ .regex(/^face_[a-z0-9][a-z0-9_-]{7,63}$/u)
495
+ .brand<"FaceTrackReferenceId">();
496
+
497
+ export const ProjectCameraMoveOriginSchema = z.discriminatedUnion("kind", [
498
+ z.strictObject({ kind: z.literal("manual") }),
499
+ z.strictObject({
500
+ analysisId: AnalysisIdSchema,
501
+ analysisSha256: Sha256Schema,
502
+ assetId: ProjectAssetIdSchema,
503
+ assetRange: SourceIntervalSchema,
504
+ kind: z.literal("face-analysis"),
505
+ outputAspectRatio: z.number().finite().positive().max(100).nullable(),
506
+ streamId: ProjectStreamIdSchema,
507
+ subjectIntegritySha256: Sha256Schema,
508
+ trackIds: z.array(FaceTrackReferenceIdSchema).min(1).max(64),
509
+ }).superRefine((origin, context) => {
510
+ if (new Set(origin.trackIds).size !== origin.trackIds.length) {
511
+ context.addIssue({ code: "custom", message: "Face-analysis camera track IDs must be unique." });
512
+ }
513
+ }),
514
+ ]);
515
+
516
+ export const ProjectCameraMoveSchema = z.strictObject({
517
+ binding: z.strictObject({
518
+ geometrySha256: Sha256Schema,
519
+ syncSha256: Sha256Schema,
520
+ }),
521
+ cameraMoveId: CameraMoveIdSchema,
522
+ keyframes: z.array(ProjectCameraTransformKeyframeSchema).min(2).max(4_096),
523
+ origin: ProjectCameraMoveOriginSchema,
524
+ placementId: ProjectPlacementIdSchema,
525
+ projectRange: SourceIntervalSchema,
526
+ streamId: ProjectStreamIdSchema,
527
+ }).superRefine((move, context) => {
528
+ if (
529
+ move.keyframes[0]?.projectTimeUs !== move.projectRange.startUs
530
+ || move.keyframes.at(-1)?.projectTimeUs !== move.projectRange.endUs
531
+ ) {
532
+ context.addIssue({
533
+ code: "custom",
534
+ message: "Camera move keyframes must exactly match both project range endpoints.",
535
+ });
536
+ }
537
+ for (let index = 1; index < move.keyframes.length; index += 1) {
538
+ if (move.keyframes[index]!.projectTimeUs <= move.keyframes[index - 1]!.projectTimeUs) {
539
+ context.addIssue({
540
+ code: "custom",
541
+ message: "Camera move keyframe project times must increase strictly.",
542
+ });
543
+ break;
544
+ }
545
+ }
546
+ if (move.origin.kind === "face-analysis" && move.origin.streamId !== move.streamId) {
547
+ context.addIssue({
548
+ code: "custom",
549
+ message: "Face-analysis camera provenance must identify the camera move stream.",
550
+ });
551
+ }
552
+ });
553
+
554
+ export const ProjectEditDerivationSchema = z.strictObject({
555
+ decisionId: ProjectEditDecisionIdSchema,
556
+ operation: z.enum(["cut", "speed", "trim"]),
557
+ origin: z.discriminatedUnion("kind", [
558
+ z.strictObject({ kind: z.literal("manual") }),
559
+ z.strictObject({
560
+ analysisId: AnalysisIdSchema,
561
+ assetId: ProjectAssetIdSchema,
562
+ assetRange: SourceIntervalSchema,
563
+ kind: z.literal("asset-analysis"),
564
+ placementId: ProjectPlacementIdSchema,
565
+ syncMapSha256: Sha256Schema,
566
+ }),
567
+ z.strictObject({
568
+ analysisId: AnalysisIdSchema,
569
+ inputDigest: Sha256Schema,
570
+ kind: z.literal("project-analysis"),
571
+ projectStructureSha256: Sha256Schema,
572
+ }),
573
+ ]),
574
+ projectRange: SourceIntervalSchema,
575
+ });
576
+
577
+ export const ProjectEditPlanV1Schema = z.strictObject({
578
+ baseSpeed: z.number().finite().positive().max(64),
579
+ cameraMoves: z.array(ProjectCameraMoveSchema).max(4_096),
580
+ createdAt: IsoTimestampSchema,
581
+ effects: z.strictObject({
582
+ clicks: ClickEffectSchema,
583
+ cursor: CursorEffectSchema,
584
+ keystrokes: KeystrokeEffectSchema,
585
+ metadataPlacementId: ProjectPlacementIdSchema.nullable(),
586
+ typedText: TypedTextEffectSchema,
587
+ }),
588
+ derivations: z.array(ProjectEditDerivationSchema),
589
+ keep: z.array(SourceIntervalSchema),
590
+ kind: z.union([
591
+ z.literal("slopcamera.project-edit-plan"),
592
+ z.literal("studio.project-edit-plan"),
593
+ ]),
594
+ overlays: z.array(OverlayOperationSchema),
595
+ planId: EditPlanIdSchema,
596
+ projectId: VideoProjectIdSchema,
597
+ projectStructureSha256: Sha256Schema,
598
+ schemaVersion: z.literal(1),
599
+ speed: z.array(SpeedRangeSchema),
600
+ timelineDurationUs: PositiveMicrosecondsSchema,
601
+ updatedAt: IsoTimestampSchema,
602
+ zooms: z.array(ProjectZoomOperationSchema),
603
+ }).superRefine((plan, context) => {
604
+ if (Date.parse(plan.updatedAt) < Date.parse(plan.createdAt)) {
605
+ context.addIssue({ code: "custom", message: "updatedAt cannot precede createdAt." });
606
+ }
607
+ let priorKeepEndUs = -1;
608
+ for (const interval of plan.keep) {
609
+ if (interval.startUs <= priorKeepEndUs) {
610
+ context.addIssue({ code: "custom", message: "Project keep intervals must be sorted, disjoint, and non-adjacent." });
611
+ break;
612
+ }
613
+ priorKeepEndUs = interval.endUs;
614
+ if (interval.endUs > plan.timelineDurationUs) {
615
+ context.addIssue({ code: "custom", message: "Project keep intervals cannot exceed the project timeline." });
616
+ }
617
+ }
618
+ let priorSpeedEndUs = -1;
619
+ for (const speed of plan.speed) {
620
+ if (speed.range.startUs < priorSpeedEndUs) {
621
+ context.addIssue({ code: "custom", message: "Project speed ranges must be sorted and non-overlapping." });
622
+ break;
623
+ }
624
+ priorSpeedEndUs = speed.range.endUs;
625
+ if (!plan.keep.some(keep => keep.startUs <= speed.range.startUs && keep.endUs >= speed.range.endUs)) {
626
+ context.addIssue({ code: "custom", message: "Every project speed range must be contained in one keep interval." });
627
+ }
628
+ if (speed.rate === plan.baseSpeed) {
629
+ context.addIssue({ code: "custom", message: "Project speed ranges equal to baseSpeed are redundant." });
630
+ }
631
+ }
632
+ for (const operation of [
633
+ ...plan.overlays.map(item => ({ range: item.range })),
634
+ ...plan.zooms.map(zoom => ({ range: zoom.operation.range })),
635
+ ...plan.cameraMoves.map(move => ({ range: move.projectRange })),
636
+ ]) {
637
+ if (operation.range.endUs > plan.timelineDurationUs) {
638
+ context.addIssue({ code: "custom", message: "Timed project operations cannot exceed the project timeline." });
639
+ }
640
+ if (!plan.keep.some(keep => keep.startUs < operation.range.endUs && keep.endUs > operation.range.startUs)) {
641
+ context.addIssue({ code: "custom", message: "Timed project operations must overlap kept project time." });
642
+ }
643
+ }
644
+ if (new Set(plan.overlays.map(overlay => overlay.overlayId)).size !== plan.overlays.length) {
645
+ context.addIssue({ code: "custom", message: "Project overlay IDs must be unique." });
646
+ }
647
+ if (new Set(plan.zooms.map(zoom => zoom.operation.zoomId)).size !== plan.zooms.length) {
648
+ context.addIssue({ code: "custom", message: "Project zoom IDs must be unique." });
649
+ }
650
+ if (new Set(plan.cameraMoves.map(move => move.cameraMoveId)).size !== plan.cameraMoves.length) {
651
+ context.addIssue({ code: "custom", message: "Project camera move IDs must be unique." });
652
+ }
653
+ const priorCameraEndByLayer = new Map<string, number>();
654
+ const priorCameraByLayer = new Map<string, ProjectCameraMove>();
655
+ for (const move of [...plan.cameraMoves].sort((left, right) => (
656
+ left.placementId.localeCompare(right.placementId)
657
+ || left.streamId.localeCompare(right.streamId)
658
+ || left.projectRange.startUs - right.projectRange.startUs
659
+ || left.projectRange.endUs - right.projectRange.endUs
660
+ ))) {
661
+ const layer = `${move.placementId}\u0000${move.streamId}`;
662
+ const priorEndUs = priorCameraEndByLayer.get(layer);
663
+ if (priorEndUs !== undefined && move.projectRange.startUs < priorEndUs) {
664
+ context.addIssue({
665
+ code: "custom",
666
+ message: "Project camera moves on the same placement and stream must not overlap.",
667
+ });
668
+ break;
669
+ }
670
+ const priorMove = priorCameraByLayer.get(layer);
671
+ if (
672
+ priorMove !== undefined
673
+ && priorMove.projectRange.endUs === move.projectRange.startUs
674
+ ) {
675
+ const priorPose = priorMove.keyframes.at(-1)!.pose;
676
+ const nextPose = move.keyframes[0]!.pose;
677
+ if (
678
+ priorPose.space !== nextPose.space
679
+ || priorPose.centerX !== nextPose.centerX
680
+ || priorPose.centerY !== nextPose.centerY
681
+ || priorPose.zoom !== nextPose.zoom
682
+ ) {
683
+ context.addIssue({
684
+ code: "custom",
685
+ message: "Adjacent project camera moves on one layer must share their endpoint pose.",
686
+ });
687
+ break;
688
+ }
689
+ }
690
+ priorCameraEndByLayer.set(layer, move.projectRange.endUs);
691
+ priorCameraByLayer.set(layer, move);
692
+ }
693
+ const priorZoomEndByLayer = new Map<string, number>();
694
+ for (const zoom of [...plan.zooms].sort((left, right) => (
695
+ left.placementId.localeCompare(right.placementId)
696
+ || left.operation.displayId.localeCompare(right.operation.displayId)
697
+ || left.operation.range.startUs - right.operation.range.startUs
698
+ || left.operation.range.endUs - right.operation.range.endUs
699
+ ))) {
700
+ const layer = `${zoom.placementId}\u0000${zoom.operation.displayId}`;
701
+ const priorEndUs = priorZoomEndByLayer.get(layer);
702
+ if (priorEndUs !== undefined && zoom.operation.range.startUs < priorEndUs) {
703
+ context.addIssue({
704
+ code: "custom",
705
+ message: "Project zooms on the same placement and display must not overlap.",
706
+ });
707
+ break;
708
+ }
709
+ priorZoomEndByLayer.set(layer, zoom.operation.range.endUs);
710
+ }
711
+ if (new Set(plan.derivations.map(derivation => derivation.decisionId)).size !== plan.derivations.length) {
712
+ context.addIssue({ code: "custom", message: "Project edit decision IDs must be unique." });
713
+ }
714
+ if (plan.derivations.some(derivation => derivation.projectRange.endUs > plan.timelineDurationUs)) {
715
+ context.addIssue({ code: "custom", message: "Project edit derivations cannot exceed the project timeline." });
716
+ }
717
+ });
718
+
719
+ export type VideoProjectId = z.infer<typeof VideoProjectIdSchema>;
720
+ export type ProjectAssetId = z.infer<typeof ProjectAssetIdSchema>;
721
+ export type ProjectStreamId = z.infer<typeof ProjectStreamIdSchema>;
722
+ export type ProjectPlacementId = z.infer<typeof ProjectPlacementIdSchema>;
723
+ export type AnalysisId = z.infer<typeof AnalysisIdSchema>;
724
+ export type ProjectAssetV1 = ReadonlyInferred<typeof ProjectAssetV1Schema>;
725
+ export type ProjectPlacementV1 = ReadonlyInferred<typeof ProjectPlacementV1Schema>;
726
+ export type ProjectSyncMap = ReadonlyInferred<typeof ProjectSyncMapSchema>;
727
+ export type SyncAnchor = ReadonlyInferred<typeof SyncAnchorSchema>;
728
+ export type VideoProjectV1 = ReadonlyInferred<typeof VideoProjectV1Schema>;
729
+ export type ProjectCameraMove = ReadonlyInferred<typeof ProjectCameraMoveSchema>;
730
+ export type ProjectCameraTransformKeyframe = ReadonlyInferred<typeof ProjectCameraTransformKeyframeSchema>;
731
+ export type ProjectZoomOperation = ReadonlyInferred<typeof ProjectZoomOperationSchema>;
732
+ export type ProjectEditPlanV1 = ReadonlyInferred<typeof ProjectEditPlanV1Schema>;
733
+
734
+ export function parseVideoProjectV1(input: unknown): VideoProjectV1 {
735
+ return VideoProjectV1Schema.parse(input);
736
+ }
737
+
738
+ export function parseProjectEditPlanV1(input: unknown): ProjectEditPlanV1 {
739
+ return ProjectEditPlanV1Schema.parse(input);
740
+ }