@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,939 @@
1
+ import {
2
+ lstat,
3
+ realpath,
4
+ } from "node:fs/promises";
5
+ import {
6
+ isAbsolute,
7
+ join,
8
+ relative,
9
+ sep,
10
+ } from "node:path";
11
+
12
+ import { z } from "zod";
13
+
14
+ import {
15
+ ProjectAssetIdSchema,
16
+ ProjectCaptionRequestSchema,
17
+ ProjectPlacementIdSchema,
18
+ ProjectStreamIdSchema,
19
+ RecordingIdSchema,
20
+ RepositoryRelativePathSchema,
21
+ Sha256Schema,
22
+ SpeechAnalysisV1Schema,
23
+ type ProjectCaptionRequest,
24
+ type ProjectRenderPlanV1,
25
+ type SpeechAnalysisV1,
26
+ type VideoProjectV1,
27
+ } from "../../../contracts";
28
+ import {
29
+ assertProjectRenderPlanComposition,
30
+ canonicalJson,
31
+ canonicalJsonSha256,
32
+ compileProjectCaptionCues,
33
+ compileProjectRenderPlan,
34
+ createNodeBundleFileSystem,
35
+ hashPlacementSync,
36
+ hashProjectStructure,
37
+ sha256Hex,
38
+ type BundleFileSystem,
39
+ type ProjectMetadataContext,
40
+ type ProjectRenderSettings,
41
+ } from "../../../core";
42
+ import {
43
+ loadRecordingEvents,
44
+ openRecording,
45
+ } from "../../../cli/bundle-service";
46
+ import type { ApplicationContext } from "../../context";
47
+ import { ApplicationError } from "../../errors";
48
+ import type { OperationDefinition } from "../../operation";
49
+ import {
50
+ ProjectEditRevisionDocumentSchema,
51
+ ProjectEditRevisionRenderInputSchema,
52
+ ProjectRenderPlanDocumentSchema,
53
+ ProjectRenderPlanReferenceSchema,
54
+ RenderableProjectEditRevisionReferenceSchema,
55
+ type ProjectEditRevisionDocument,
56
+ type ProjectEditRevisionRenderInput,
57
+ type ProjectRenderPlanDocument,
58
+ type ProjectRenderPlanReference,
59
+ type RenderableProjectEditRevisionReference,
60
+ } from "../../receipts";
61
+ import { throwIfAborted } from "../shared";
62
+ import {
63
+ prepareProjectCaptionPlan,
64
+ type PreparedProjectCaptionArtifact,
65
+ type PreparedProjectCaptionPlan,
66
+ } from "./project-caption-plan";
67
+
68
+ const MAXIMUM_PROJECT_RENDER_PLAN_BYTES = 256 * 1024 * 1024;
69
+
70
+ export const ProjectRenderSettingsSchema = z.strictObject({
71
+ background: z.string().regex(/^#[0-9a-fA-F]{8}$/u).optional(),
72
+ frameRate: z.number().finite().positive().max(240).optional(),
73
+ });
74
+
75
+ export const ProjectRenderSettingsV2Schema = ProjectRenderSettingsSchema.extend({
76
+ captions: ProjectCaptionRequestSchema,
77
+ }).strict();
78
+
79
+ export const ProjectCaptionBindingSchema = z.strictObject({
80
+ analysisId: ProjectCaptionRequestSchema.shape.analysisId,
81
+ analysisPath: RepositoryRelativePathSchema,
82
+ analysisSha256: Sha256Schema,
83
+ assetId: ProjectAssetIdSchema,
84
+ placementId: ProjectPlacementIdSchema,
85
+ placementSyncSha256: Sha256Schema,
86
+ streamId: ProjectStreamIdSchema,
87
+ subjectIntegritySha256: Sha256Schema,
88
+ wordCount: z.number().int().safe().positive().max(1_000_000),
89
+ });
90
+
91
+ export const ProjectRenderMetadataBindingSchema = z.strictObject({
92
+ eventsSha256: Sha256Schema,
93
+ manifestSha256: Sha256Schema,
94
+ placementId: ProjectPlacementIdSchema,
95
+ recordingId: RecordingIdSchema,
96
+ });
97
+
98
+ export const ProjectRenderPlanInputSchema = z.strictObject({
99
+ metadataBindings: z.array(ProjectRenderMetadataBindingSchema).max(256).optional(),
100
+ revision: ProjectEditRevisionRenderInputSchema,
101
+ settings: ProjectRenderSettingsSchema.optional(),
102
+ }).superRefine((input, context) => {
103
+ if (input.metadataBindings === undefined) return;
104
+ for (let index = 0; index < input.metadataBindings.length; index += 1) {
105
+ const current = input.metadataBindings[index]!;
106
+ const previous = input.metadataBindings[index - 1];
107
+ if (
108
+ previous !== undefined
109
+ && previous.placementId.localeCompare(current.placementId) >= 0
110
+ ) {
111
+ context.addIssue({
112
+ code: "custom",
113
+ message: "Render metadata bindings must have unique sorted placement IDs.",
114
+ path: ["metadataBindings", index, "placementId"],
115
+ });
116
+ }
117
+ }
118
+ });
119
+
120
+ export const ProjectRenderPlanInputV2Schema = z.strictObject({
121
+ captionBinding: ProjectCaptionBindingSchema.optional(),
122
+ metadataBindings: z.array(ProjectRenderMetadataBindingSchema).max(256).optional(),
123
+ revision: ProjectEditRevisionRenderInputSchema,
124
+ settings: ProjectRenderSettingsV2Schema,
125
+ }).superRefine((input, context) => {
126
+ if (input.metadataBindings === undefined) return;
127
+ for (let index = 0; index < input.metadataBindings.length; index += 1) {
128
+ const current = input.metadataBindings[index]!;
129
+ const previous = input.metadataBindings[index - 1];
130
+ if (
131
+ previous !== undefined
132
+ && previous.placementId.localeCompare(current.placementId) >= 0
133
+ ) {
134
+ context.addIssue({
135
+ code: "custom",
136
+ message: "Render metadata bindings must have unique sorted placement IDs.",
137
+ path: ["metadataBindings", index, "placementId"],
138
+ });
139
+ }
140
+ }
141
+ });
142
+
143
+ export const ProjectRenderPlanOutputSchema = ProjectRenderPlanReferenceSchema;
144
+
145
+ export type ProjectRenderPlanInput = z.infer<
146
+ typeof ProjectRenderPlanInputSchema
147
+ >;
148
+ export type ProjectRenderPlanInputV2 = z.infer<
149
+ typeof ProjectRenderPlanInputV2Schema
150
+ >;
151
+ export type ProjectRenderPlanOutput = ProjectRenderPlanReference;
152
+
153
+ export function hashProjectCaptionSource(input: {
154
+ readonly binding: z.infer<typeof ProjectCaptionBindingSchema>;
155
+ readonly output: ProjectRenderPlanV1["output"];
156
+ readonly projectEditPlanSha256: string;
157
+ readonly revisionSha256: string;
158
+ readonly style: ProjectCaptionRequest["style"];
159
+ }): string {
160
+ return canonicalJsonSha256({
161
+ ...input,
162
+ domain: "slopcamera.social-caption-source/v1",
163
+ });
164
+ }
165
+
166
+ function isWithin(root: string, candidate: string): boolean {
167
+ const pathFromRoot = relative(root, candidate);
168
+ return pathFromRoot === "" || (
169
+ pathFromRoot !== ".."
170
+ && !pathFromRoot.startsWith(`..${sep}`)
171
+ && !isAbsolute(pathFromRoot)
172
+ );
173
+ }
174
+
175
+ export async function exactProjectDirectory(
176
+ application: ApplicationContext,
177
+ projectId: string,
178
+ ): Promise<string> {
179
+ let root: string;
180
+ try {
181
+ root = await realpath(application.paths.projectRoot);
182
+ } catch {
183
+ throw new ApplicationError(
184
+ "not-found",
185
+ "The project root does not exist.",
186
+ );
187
+ }
188
+ const requested = join(root, projectId);
189
+ let details;
190
+ try {
191
+ details = await lstat(requested);
192
+ } catch {
193
+ throw new ApplicationError("not-found", `Project does not exist: ${projectId}`);
194
+ }
195
+ if (details.isSymbolicLink() || !details.isDirectory()) {
196
+ throw new ApplicationError(
197
+ "unsafe-path",
198
+ `Project must be a physical directory: ${projectId}`,
199
+ );
200
+ }
201
+ const directory = await realpath(requested);
202
+ if (!isWithin(root, directory) || directory === root) {
203
+ throw new ApplicationError(
204
+ "unsafe-path",
205
+ `Project directory escapes the configured project root: ${projectId}`,
206
+ );
207
+ }
208
+ return directory;
209
+ }
210
+
211
+ export function renderableProjectEditRevisionReference(
212
+ input: ProjectEditRevisionRenderInput,
213
+ ): RenderableProjectEditRevisionReference {
214
+ return RenderableProjectEditRevisionReferenceSchema.parse({
215
+ artifact: input.artifact,
216
+ baseGeneration: input.baseGeneration,
217
+ kind: input.kind,
218
+ outputGeometrySha256: input.outputGeometrySha256,
219
+ pixelHeight: input.pixelHeight,
220
+ pixelWidth: input.pixelWidth,
221
+ planId: input.planId,
222
+ projectEditPlanSha256: input.projectEditPlanSha256,
223
+ projectId: input.projectId,
224
+ projectSha256: input.projectSha256,
225
+ projectStructureSha256: input.projectStructureSha256,
226
+ revisionSha256: input.revisionSha256,
227
+ schemaVersion: input.schemaVersion,
228
+ });
229
+ }
230
+
231
+ function parseJson(text: string, label: string): unknown {
232
+ try {
233
+ return JSON.parse(text) as unknown;
234
+ } catch {
235
+ throw new ApplicationError("invalid-data", `${label} is not valid JSON.`);
236
+ }
237
+ }
238
+
239
+ function utf8Bytes(text: string): number {
240
+ return new TextEncoder().encode(text).byteLength;
241
+ }
242
+
243
+ export async function loadExactProjectEditRevision(
244
+ application: ApplicationContext,
245
+ input: ProjectEditRevisionRenderInput,
246
+ ): Promise<{
247
+ readonly directory: string;
248
+ readonly document: ProjectEditRevisionDocument;
249
+ readonly fileSystem: BundleFileSystem;
250
+ readonly reference: RenderableProjectEditRevisionReference;
251
+ }> {
252
+ const reference = renderableProjectEditRevisionReference(input);
253
+ const directory = await exactProjectDirectory(
254
+ application,
255
+ reference.projectId,
256
+ );
257
+ const fileSystem = createNodeBundleFileSystem(directory);
258
+ const text = await fileSystem.readText(reference.artifact.path);
259
+ if (
260
+ utf8Bytes(text) !== reference.artifact.bytes
261
+ || sha256Hex(text) !== reference.artifact.sha256
262
+ ) {
263
+ throw new ApplicationError(
264
+ "conflict",
265
+ "Immutable project edit revision artifact failed its byte and SHA-256 identity.",
266
+ );
267
+ }
268
+ const document = ProjectEditRevisionDocumentSchema.parse(
269
+ parseJson(text, "Project edit revision artifact"),
270
+ );
271
+ if (text !== `${canonicalJson(document)}\n`) {
272
+ throw new ApplicationError(
273
+ "conflict",
274
+ "Immutable project edit revision artifact is not its canonical document.",
275
+ );
276
+ }
277
+ if (
278
+ document.project.projectId !== reference.projectId
279
+ || document.projectEditPlan.planId !== reference.planId
280
+ || document.projectSha256 !== reference.projectSha256
281
+ || document.projectEditPlanSha256 !== reference.projectEditPlanSha256
282
+ || document.revisionSha256 !== reference.revisionSha256
283
+ || hashProjectStructure(document.project)
284
+ !== reference.projectStructureSha256
285
+ ) {
286
+ throw new ApplicationError(
287
+ "conflict",
288
+ "Immutable project edit revision reference does not match its frozen documents.",
289
+ );
290
+ }
291
+ return { directory, document, fileSystem, reference };
292
+ }
293
+
294
+ function renderSettings(
295
+ input: z.infer<typeof ProjectRenderSettingsSchema> | undefined,
296
+ reference: RenderableProjectEditRevisionReference,
297
+ metadata: readonly ProjectMetadataContext[],
298
+ ): ProjectRenderSettings {
299
+ return {
300
+ ...(input?.background === undefined ? {} : { background: input.background }),
301
+ ...(input?.frameRate === undefined ? {} : { frameRate: input.frameRate }),
302
+ metadata,
303
+ pixelHeight: reference.pixelHeight,
304
+ pixelWidth: reference.pixelWidth,
305
+ };
306
+ }
307
+
308
+ async function projectMetadata(
309
+ artifactRoot: string,
310
+ project: VideoProjectV1,
311
+ plan: ProjectEditRevisionDocument["projectEditPlan"],
312
+ ): Promise<{
313
+ readonly bindings: readonly z.infer<typeof ProjectRenderMetadataBindingSchema>[];
314
+ readonly contexts: readonly ProjectMetadataContext[];
315
+ }> {
316
+ const placementIds = new Set<string>(
317
+ plan.zooms.map(zoom => zoom.placementId),
318
+ );
319
+ if (
320
+ (
321
+ plan.effects.clicks.enabled
322
+ || plan.effects.cursor.enabled
323
+ || plan.effects.keystrokes.enabled
324
+ || plan.effects.typedText.enabled
325
+ )
326
+ && plan.effects.metadataPlacementId !== null
327
+ ) {
328
+ placementIds.add(plan.effects.metadataPlacementId);
329
+ }
330
+ const loaded = await Promise.all([...placementIds].sort().map(async placementId => {
331
+ const placement = project.placements.find(
332
+ candidate => candidate.placementId === placementId,
333
+ );
334
+ if (placement === undefined) {
335
+ throw new ApplicationError(
336
+ "not-found",
337
+ `Unknown project metadata placement: ${placementId}`,
338
+ );
339
+ }
340
+ const asset = project.assets.find(
341
+ candidate => candidate.assetId === placement.assetId,
342
+ );
343
+ if (asset?.source.kind !== "recording") {
344
+ throw new ApplicationError(
345
+ "conflict",
346
+ `Placement ${placement.placementId} is not backed by a Slopcamera recording with window and input metadata.`,
347
+ );
348
+ }
349
+ const recording = await openRecording(artifactRoot, asset.source.recordingId);
350
+ const events = await loadRecordingEvents(recording);
351
+ return {
352
+ binding: ProjectRenderMetadataBindingSchema.parse({
353
+ eventsSha256: canonicalJsonSha256(events),
354
+ manifestSha256: canonicalJsonSha256(recording.manifest),
355
+ placementId: placement.placementId,
356
+ recordingId: asset.source.recordingId,
357
+ }),
358
+ context: {
359
+ events,
360
+ manifest: recording.manifest,
361
+ placementId: placement.placementId,
362
+ },
363
+ };
364
+ }));
365
+ return {
366
+ bindings: loaded.map(item => item.binding),
367
+ contexts: loaded.map(item => item.context),
368
+ };
369
+ }
370
+
371
+ interface LoadedProjectCaptions {
372
+ readonly analysis: SpeechAnalysisV1;
373
+ readonly binding: z.infer<typeof ProjectCaptionBindingSchema>;
374
+ }
375
+
376
+ async function projectCaptions(
377
+ revision: Awaited<ReturnType<typeof loadExactProjectEditRevision>>,
378
+ requestInput: ProjectCaptionRequest,
379
+ ): Promise<LoadedProjectCaptions> {
380
+ const request = ProjectCaptionRequestSchema.parse(requestInput);
381
+ const project = revision.document.project;
382
+ const reference = project.analyses.find(candidate => (
383
+ candidate.kind === "speech"
384
+ && candidate.analysisId === request.analysisId
385
+ ));
386
+ if (reference === undefined || reference.kind !== "speech") {
387
+ throw new ApplicationError(
388
+ "not-found",
389
+ `Unknown project speech analysis: ${request.analysisId}`,
390
+ );
391
+ }
392
+ const placement = project.placements.find(candidate => (
393
+ candidate.placementId === request.placementId
394
+ ));
395
+ if (placement === undefined) {
396
+ throw new ApplicationError(
397
+ "not-found",
398
+ `Unknown caption placement: ${request.placementId}`,
399
+ );
400
+ }
401
+ if (!placement.enabled || placement.assetId !== reference.assetId) {
402
+ throw new ApplicationError(
403
+ "conflict",
404
+ "Caption placement must be enabled and contain the analyzed audio asset.",
405
+ );
406
+ }
407
+ const configuredAudio = placement.audio.find(candidate => (
408
+ candidate.streamId === reference.streamId
409
+ ));
410
+ if (configuredAudio?.presentation.enabled !== true) {
411
+ throw new ApplicationError(
412
+ "conflict",
413
+ "Caption source audio must be enabled and audible on the selected placement.",
414
+ );
415
+ }
416
+ const asset = project.assets.find(candidate => (
417
+ candidate.assetId === reference.assetId
418
+ ));
419
+ const stream = asset?.streams.find(candidate => (
420
+ candidate.streamId === reference.streamId
421
+ ));
422
+ if (asset === undefined || stream?.kind !== "audio") {
423
+ throw new ApplicationError(
424
+ "conflict",
425
+ "Caption speech analysis no longer identifies a project audio stream.",
426
+ );
427
+ }
428
+
429
+ let text: string;
430
+ let analysis: SpeechAnalysisV1;
431
+ try {
432
+ text = await revision.fileSystem.readText(reference.path);
433
+ analysis = SpeechAnalysisV1Schema.parse(
434
+ parseJson(text, "Speech analysis artifact"),
435
+ );
436
+ } catch (error) {
437
+ if (error instanceof ApplicationError) throw error;
438
+ throw new ApplicationError(
439
+ "invalid-data",
440
+ `Speech analysis ${reference.analysisId} is unreadable or invalid.`,
441
+ );
442
+ }
443
+ if (
444
+ text !== `${canonicalJson(analysis)}\n`
445
+ || sha256Hex(text) !== reference.sha256
446
+ || analysis.analysisId !== reference.analysisId
447
+ || analysis.subject.assetId !== reference.assetId
448
+ || analysis.subject.streamId !== reference.streamId
449
+ || analysis.durationUs !== asset.durationUs
450
+ ) {
451
+ throw new ApplicationError(
452
+ "conflict",
453
+ `Speech analysis ${reference.analysisId} is stale or failed its exact identity check.`,
454
+ );
455
+ }
456
+ const subjectIntegritySha256 = canonicalJsonSha256({
457
+ assetDurationUs: asset.durationUs,
458
+ stream,
459
+ });
460
+ if (analysis.subject.integritySha256 !== subjectIntegritySha256) {
461
+ throw new ApplicationError(
462
+ "conflict",
463
+ `Speech analysis ${reference.analysisId} no longer matches its audio stream.`,
464
+ );
465
+ }
466
+ if (
467
+ analysis.result.status !== "transcribed"
468
+ || analysis.result.words.length === 0
469
+ ) {
470
+ throw new ApplicationError(
471
+ "unsupported-plan",
472
+ "Caption export requires a speech analysis with timed words.",
473
+ );
474
+ }
475
+ if (
476
+ reference.wordCount !== analysis.result.words.length
477
+ || reference.fillerCount !== analysis.result.fillers.length
478
+ ) {
479
+ throw new ApplicationError(
480
+ "invalid-data",
481
+ `Speech analysis reference ${reference.analysisId} disagrees with its artifact counts.`,
482
+ );
483
+ }
484
+ return {
485
+ analysis,
486
+ binding: ProjectCaptionBindingSchema.parse({
487
+ analysisId: reference.analysisId,
488
+ analysisPath: reference.path,
489
+ analysisSha256: reference.sha256,
490
+ assetId: reference.assetId,
491
+ placementId: placement.placementId,
492
+ placementSyncSha256: hashPlacementSync(placement),
493
+ streamId: reference.streamId,
494
+ subjectIntegritySha256,
495
+ wordCount: analysis.result.words.length,
496
+ }),
497
+ };
498
+ }
499
+
500
+ export async function bindProjectRenderPlanInput(
501
+ application: ApplicationContext,
502
+ input: unknown,
503
+ ): Promise<ProjectRenderPlanInput> {
504
+ const parsed = ProjectRenderPlanInputSchema.parse(input);
505
+ const revision = await loadExactProjectEditRevision(
506
+ application,
507
+ parsed.revision,
508
+ );
509
+ const metadata = await projectMetadata(
510
+ application.paths.artifactRoot,
511
+ revision.document.project,
512
+ revision.document.projectEditPlan,
513
+ );
514
+ return ProjectRenderPlanInputSchema.parse({
515
+ ...parsed,
516
+ metadataBindings: metadata.bindings,
517
+ });
518
+ }
519
+
520
+ export async function bindProjectRenderPlanInputV2(
521
+ application: ApplicationContext,
522
+ input: unknown,
523
+ ): Promise<ProjectRenderPlanInputV2> {
524
+ const parsed = ProjectRenderPlanInputV2Schema.parse(input);
525
+ const revision = await loadExactProjectEditRevision(
526
+ application,
527
+ parsed.revision,
528
+ );
529
+ const [metadata, captions] = await Promise.all([
530
+ projectMetadata(
531
+ application.paths.artifactRoot,
532
+ revision.document.project,
533
+ revision.document.projectEditPlan,
534
+ ),
535
+ projectCaptions(revision, parsed.settings.captions),
536
+ ]);
537
+ return ProjectRenderPlanInputV2Schema.parse({
538
+ ...parsed,
539
+ captionBinding: captions.binding,
540
+ metadataBindings: metadata.bindings,
541
+ });
542
+ }
543
+
544
+ function projectRenderPlanDocument(
545
+ plan: ProjectRenderPlanV1,
546
+ revision: ProjectEditRevisionDocument,
547
+ reference: RenderableProjectEditRevisionReference,
548
+ ): ProjectRenderPlanDocument {
549
+ return ProjectRenderPlanDocumentSchema.parse({
550
+ kind: "slopcamera.project-render-plan-document",
551
+ outputGeometrySha256: reference.outputGeometrySha256,
552
+ plan: assertProjectRenderPlanComposition(plan),
553
+ projectEditPlanSha256: revision.projectEditPlanSha256,
554
+ projectSha256: revision.projectSha256,
555
+ renderPlanSha256: canonicalJsonSha256(plan),
556
+ revisionSha256: revision.revisionSha256,
557
+ schemaVersion: 1,
558
+ });
559
+ }
560
+
561
+ export async function loadExactProjectRenderPlan(
562
+ application: ApplicationContext,
563
+ referenceInput: ProjectRenderPlanReference,
564
+ ): Promise<{
565
+ readonly directory: string;
566
+ readonly document: ProjectRenderPlanDocument;
567
+ readonly fileSystem: BundleFileSystem;
568
+ readonly reference: ProjectRenderPlanReference;
569
+ }> {
570
+ const reference = ProjectRenderPlanReferenceSchema.parse(referenceInput);
571
+ const directory = await exactProjectDirectory(
572
+ application,
573
+ reference.projectId,
574
+ );
575
+ const fileSystem = createNodeBundleFileSystem(directory);
576
+ const text = await fileSystem.readText(reference.artifact.path);
577
+ if (
578
+ utf8Bytes(text) !== reference.artifact.bytes
579
+ || sha256Hex(text) !== reference.artifact.sha256
580
+ ) {
581
+ throw new ApplicationError(
582
+ "conflict",
583
+ "Immutable project render plan artifact failed its byte and SHA-256 identity.",
584
+ );
585
+ }
586
+ const document = ProjectRenderPlanDocumentSchema.parse(
587
+ parseJson(text, "Project render plan artifact"),
588
+ );
589
+ if (
590
+ text !== `${canonicalJson(document)}\n`
591
+ || document.plan.projectId !== reference.projectId
592
+ || document.plan.planSha256 !== reference.planSha256
593
+ || document.outputGeometrySha256 !== reference.outputGeometrySha256
594
+ || document.projectEditPlanSha256 !== reference.projectEditPlanSha256
595
+ || document.projectSha256 !== reference.projectSha256
596
+ || document.renderPlanSha256 !== reference.renderPlanSha256
597
+ || document.revisionSha256 !== reference.revisionSha256
598
+ ) {
599
+ throw new ApplicationError(
600
+ "conflict",
601
+ "Immutable project render plan reference does not match its exact document.",
602
+ );
603
+ }
604
+ assertProjectRenderPlanComposition(document.plan);
605
+ return { directory, document, fileSystem, reference };
606
+ }
607
+
608
+ async function publishProjectRenderPlan(
609
+ application: ApplicationContext,
610
+ beforePublication: (() => Promise<void>) | undefined,
611
+ revision: Awaited<ReturnType<typeof loadExactProjectEditRevision>>,
612
+ plan: ProjectRenderPlanV1,
613
+ ): Promise<ProjectRenderPlanReference> {
614
+ const document = projectRenderPlanDocument(
615
+ plan,
616
+ revision.document,
617
+ revision.reference,
618
+ );
619
+ const contents = `${canonicalJson(document)}\n`;
620
+ const artifact = {
621
+ bytes: utf8Bytes(contents),
622
+ path: "",
623
+ sha256: sha256Hex(contents),
624
+ };
625
+ if (artifact.bytes > MAXIMUM_PROJECT_RENDER_PLAN_BYTES) {
626
+ throw new ApplicationError(
627
+ "unsupported-plan",
628
+ "Project render plan exceeds the 256 MiB structured-artifact limit.",
629
+ { artifactBytes: artifact.bytes },
630
+ );
631
+ }
632
+ const reference = ProjectRenderPlanReferenceSchema.parse({
633
+ artifact: {
634
+ ...artifact,
635
+ path: `renders/plans/${artifact.sha256}.json`,
636
+ },
637
+ kind: "slopcamera.project-render-plan-reference",
638
+ outputGeometrySha256: revision.reference.outputGeometrySha256,
639
+ planSha256: plan.planSha256,
640
+ projectEditPlanSha256: revision.document.projectEditPlanSha256,
641
+ projectId: revision.document.project.projectId,
642
+ projectSha256: revision.document.projectSha256,
643
+ renderPlanSha256: document.renderPlanSha256,
644
+ revisionSha256: revision.document.revisionSha256,
645
+ schemaVersion: 1,
646
+ });
647
+ if (revision.fileSystem.writeTextNoReplace === undefined) {
648
+ throw new ApplicationError(
649
+ "internal",
650
+ "Project storage does not support immutable render-plan publication.",
651
+ );
652
+ }
653
+ await beforePublication?.();
654
+ await revision.fileSystem.writeTextNoReplace(
655
+ reference.artifact.path,
656
+ contents,
657
+ );
658
+ const published = await loadExactProjectRenderPlan(
659
+ application,
660
+ reference,
661
+ );
662
+ if (canonicalJson(published.document) !== canonicalJson(document)) {
663
+ throw new ApplicationError(
664
+ "conflict",
665
+ "Published project render plan contains different bytes.",
666
+ );
667
+ }
668
+ return reference;
669
+ }
670
+
671
+ async function publishProjectCaptionArtifacts(
672
+ revision: Awaited<ReturnType<typeof loadExactProjectEditRevision>>,
673
+ artifacts: readonly PreparedProjectCaptionArtifact[],
674
+ signal: AbortSignal,
675
+ ): Promise<void> {
676
+ if (revision.fileSystem.writeTextNoReplace === undefined) {
677
+ throw new ApplicationError(
678
+ "internal",
679
+ "Project storage does not support immutable caption-asset publication.",
680
+ );
681
+ }
682
+ for (const artifact of artifacts) {
683
+ throwIfAborted(signal);
684
+ const disposition = await revision.fileSystem.writeTextNoReplace(
685
+ artifact.path,
686
+ artifact.contents,
687
+ );
688
+ const installed = await revision.fileSystem.readText(artifact.path);
689
+ if (
690
+ installed !== artifact.contents
691
+ || sha256Hex(installed) !== artifact.sha256
692
+ ) {
693
+ throw new ApplicationError(
694
+ "conflict",
695
+ disposition === "exists"
696
+ ? `Caption asset path already contains different bytes: ${artifact.path}`
697
+ : `Published caption asset failed read-back verification: ${artifact.path}`,
698
+ );
699
+ }
700
+ }
701
+ }
702
+
703
+ export const projectRenderPlanOperationDefinition = {
704
+ inputSchema: ProjectRenderPlanInputSchema,
705
+ inputSchemaId: "slopcamera.operation.render.project-plan.input/v1",
706
+ kind: "render.project-plan",
707
+ lifecycle: {
708
+ kind: "local-artifact",
709
+ execute: async (context, input) => {
710
+ throwIfAborted(context.abortSignal);
711
+ if (
712
+ context.workflow !== undefined
713
+ && input.metadataBindings === undefined
714
+ ) {
715
+ throw new ApplicationError(
716
+ "incompatible",
717
+ "Workflow render planning requires exact recording-metadata bindings.",
718
+ );
719
+ }
720
+ const revision = await loadExactProjectEditRevision(
721
+ context.application,
722
+ input.revision,
723
+ );
724
+ const metadata = await projectMetadata(
725
+ context.application.paths.artifactRoot,
726
+ revision.document.project,
727
+ revision.document.projectEditPlan,
728
+ );
729
+ if (
730
+ input.metadataBindings !== undefined
731
+ && canonicalJson(input.metadataBindings) !== canonicalJson(metadata.bindings)
732
+ ) {
733
+ throw new ApplicationError(
734
+ "conflict",
735
+ "Recording metadata changed after the render-plan node was bound.",
736
+ );
737
+ }
738
+ let plan;
739
+ try {
740
+ plan = compileProjectRenderPlan(
741
+ revision.document.project,
742
+ revision.document.projectEditPlan,
743
+ renderSettings(input.settings, revision.reference, metadata.contexts),
744
+ );
745
+ } catch (error) {
746
+ if (error instanceof TypeError) {
747
+ throw new ApplicationError("conflict", error.message);
748
+ }
749
+ throw error;
750
+ }
751
+ throwIfAborted(context.abortSignal);
752
+ const workflow = context.workflow;
753
+ return await publishProjectRenderPlan(
754
+ context.application,
755
+ workflow === undefined
756
+ ? undefined
757
+ : () => workflow.beforePublication(),
758
+ revision,
759
+ plan,
760
+ );
761
+ },
762
+ },
763
+ outputSchema: ProjectRenderPlanOutputSchema,
764
+ outputSchemaId: "slopcamera.operation.render.project-plan.output/v1",
765
+ policy: {
766
+ cache: "content-addressed",
767
+ cancellable: true,
768
+ effect: "local-derived-write",
769
+ maxDurationMs: 2 * 60_000,
770
+ maxFanOut: 0,
771
+ maxInputBytes: 256 * 1_024,
772
+ maxOutputBytes: 8_192,
773
+ preparation: ["recording-metadata"],
774
+ resources: [
775
+ { amount: 1, resource: "cpu" },
776
+ { amount: 1, resource: "local-io" },
777
+ ],
778
+ resume: "deterministic",
779
+ },
780
+ receiptReference: output => output.artifact.path,
781
+ summarize: output => ({
782
+ fields: {
783
+ planArtifactSha256: output.artifact.sha256,
784
+ planSha256: output.planSha256,
785
+ projectId: output.projectId,
786
+ revisionSha256: output.revisionSha256,
787
+ },
788
+ kind: "render.project-plan",
789
+ }),
790
+ version: 1,
791
+ } satisfies OperationDefinition<
792
+ "render.project-plan",
793
+ ProjectRenderPlanInput,
794
+ ProjectRenderPlanOutput
795
+ >;
796
+
797
+ export const projectRenderPlanOperationDefinitionV2 = {
798
+ inputSchema: ProjectRenderPlanInputV2Schema,
799
+ inputSchemaId: "slopcamera.operation.render.project-plan.input/v2",
800
+ kind: "render.project-plan",
801
+ lifecycle: {
802
+ kind: "local-artifact",
803
+ execute: async (context, input) => {
804
+ throwIfAborted(context.abortSignal);
805
+ if (
806
+ context.workflow !== undefined
807
+ && (
808
+ input.captionBinding === undefined
809
+ || input.metadataBindings === undefined
810
+ )
811
+ ) {
812
+ throw new ApplicationError(
813
+ "incompatible",
814
+ "Workflow captioned render planning requires exact caption and recording-metadata bindings.",
815
+ );
816
+ }
817
+ const revision = await loadExactProjectEditRevision(
818
+ context.application,
819
+ input.revision,
820
+ );
821
+ const [metadata, captions] = await Promise.all([
822
+ projectMetadata(
823
+ context.application.paths.artifactRoot,
824
+ revision.document.project,
825
+ revision.document.projectEditPlan,
826
+ ),
827
+ projectCaptions(revision, input.settings.captions),
828
+ ]);
829
+ if (
830
+ input.metadataBindings !== undefined
831
+ && canonicalJson(input.metadataBindings) !== canonicalJson(metadata.bindings)
832
+ ) {
833
+ throw new ApplicationError(
834
+ "conflict",
835
+ "Recording metadata changed after the render-plan node was bound.",
836
+ );
837
+ }
838
+ if (
839
+ input.captionBinding !== undefined
840
+ && canonicalJson(input.captionBinding) !== canonicalJson(captions.binding)
841
+ ) {
842
+ throw new ApplicationError(
843
+ "conflict",
844
+ "Caption source changed after the render-plan node was bound.",
845
+ );
846
+ }
847
+
848
+ let basePlan: ProjectRenderPlanV1;
849
+ try {
850
+ basePlan = compileProjectRenderPlan(
851
+ revision.document.project,
852
+ revision.document.projectEditPlan,
853
+ renderSettings(input.settings, revision.reference, metadata.contexts),
854
+ );
855
+ } catch (error) {
856
+ if (error instanceof TypeError) {
857
+ throw new ApplicationError("conflict", error.message);
858
+ }
859
+ throw error;
860
+ }
861
+
862
+ let prepared: PreparedProjectCaptionPlan;
863
+ try {
864
+ const cues = compileProjectCaptionCues({
865
+ analysis: captions.analysis,
866
+ output: basePlan.output,
867
+ placementId: input.settings.captions.placementId,
868
+ plan: revision.document.projectEditPlan,
869
+ project: revision.document.project,
870
+ });
871
+ prepared = prepareProjectCaptionPlan({
872
+ cues,
873
+ plan: basePlan,
874
+ sourceSha256: hashProjectCaptionSource({
875
+ binding: captions.binding,
876
+ output: basePlan.output,
877
+ projectEditPlanSha256: revision.document.projectEditPlanSha256,
878
+ revisionSha256: revision.document.revisionSha256,
879
+ style: input.settings.captions.style,
880
+ }),
881
+ style: input.settings.captions.style,
882
+ });
883
+ } catch (error) {
884
+ if (error instanceof TypeError || error instanceof RangeError) {
885
+ throw new ApplicationError("unsupported-plan", error.message);
886
+ }
887
+ throw error;
888
+ }
889
+ const plan = prepared.plan;
890
+
891
+ throwIfAborted(context.abortSignal);
892
+ await context.workflow?.beforePublication();
893
+ throwIfAborted(context.abortSignal);
894
+ await publishProjectCaptionArtifacts(
895
+ revision,
896
+ prepared.artifacts,
897
+ context.abortSignal,
898
+ );
899
+ return await publishProjectRenderPlan(
900
+ context.application,
901
+ undefined,
902
+ revision,
903
+ plan,
904
+ );
905
+ },
906
+ },
907
+ outputSchema: ProjectRenderPlanOutputSchema,
908
+ outputSchemaId: "slopcamera.operation.render.project-plan.output/v2",
909
+ policy: {
910
+ cache: "content-addressed",
911
+ cancellable: true,
912
+ effect: "local-derived-write",
913
+ maxDurationMs: 2 * 60_000,
914
+ maxFanOut: 0,
915
+ maxInputBytes: 256 * 1_024,
916
+ maxOutputBytes: 8_192,
917
+ preparation: ["recording-metadata"],
918
+ resources: [
919
+ { amount: 1, resource: "cpu" },
920
+ { amount: 1, resource: "local-io" },
921
+ ],
922
+ resume: "deterministic",
923
+ },
924
+ receiptReference: output => output.artifact.path,
925
+ summarize: output => ({
926
+ fields: {
927
+ planArtifactSha256: output.artifact.sha256,
928
+ planSha256: output.planSha256,
929
+ projectId: output.projectId,
930
+ revisionSha256: output.revisionSha256,
931
+ },
932
+ kind: "render.project-plan",
933
+ }),
934
+ version: 2,
935
+ } satisfies OperationDefinition<
936
+ "render.project-plan",
937
+ ProjectRenderPlanInputV2,
938
+ ProjectRenderPlanOutput
939
+ >;