@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,209 @@
1
+ import { z } from "zod";
2
+
3
+ import { createBoundedJsonValueSnapshot } from "../../../../src/code/json-snapshot";
4
+ import { parseSpatialScene, spatialSceneSha256 } from "../../../../src/spatial-scene/index";
5
+ import { SpatialDigestSchema, SpatialScenePatchV1Schema, SpatialShotV1Schema } from "../../../../src/spatial-scene/contracts";
6
+ import {
7
+ SPATIAL_PROJECT_LIMITS,
8
+ SpatialCandidateIdSchema,
9
+ SpatialCandidateSchema,
10
+ SpatialCandidateSelectionSchema,
11
+ SpatialProjectArtifactSchema,
12
+ SpatialProjectBasisSchema,
13
+ SpatialProjectHeadV2Schema,
14
+ SpatialProjectLegacySchema,
15
+ SpatialProjectMutationOutputSchema,
16
+ SpatialProjectSceneSourceSchema,
17
+ SpatialShotRetargetSchema,
18
+ SpatialTransactionIdSchema,
19
+ type SpatialProjectMutationOutput,
20
+ } from "../../contracts/spatial-project";
21
+ export { SpatialProjectMutationOutputSchema, SpatialProjectSceneDiffSchema, type SpatialProjectMutationOutput } from "../../contracts/spatial-project";
22
+ import { VideoProjectIdSchema } from "../../contracts/project";
23
+ import { canonicalJson } from "../../core/canonical-json";
24
+ import {
25
+ addSpatialCandidate,
26
+ applySpatialProjectScenePatch,
27
+ restoreSpatialProjectScene,
28
+ selectSpatialCandidate,
29
+ spatialCandidateStatus,
30
+ spatialProjectDocumentText,
31
+ type SpatialProjectContents,
32
+ type SpatialProjectSceneDiff,
33
+ } from "../../core/spatial-project";
34
+ import { ApplicationError } from "../errors";
35
+ import type { OperationDefinition, OperationExecutionContext, OperationKind, OperationPolicy } from "../operation";
36
+ import { spatialProjectStorePorts } from "../spatial-project-authority";
37
+ import {
38
+ commitSpatialProjectRevision,
39
+ migrateSpatialProject,
40
+ readSpatialProjectAuthority,
41
+ reconcileSpatialProjectCommit,
42
+ type SpatialProjectAuthority,
43
+ type SpatialProjectStorePorts,
44
+ } from "../spatial-project-store";
45
+
46
+ const mutationBase = {
47
+ project: VideoProjectIdSchema,
48
+ expected: SpatialProjectBasisSchema,
49
+ transactionId: SpatialTransactionIdSchema,
50
+ };
51
+ function boundedInput<Schema extends z.ZodType>(schema: Schema, maximumBytes = SPATIAL_PROJECT_LIMITS.documentBytes) {
52
+ return z.preprocess(input => createBoundedJsonValueSnapshot(input, maximumBytes, "spatial operation input", { maximumDepth: 48, maximumValues: 2_000_000 }).value, schema);
53
+ }
54
+ export const SpatialProjectSnapshotInputSchema = boundedInput(z.strictObject({ project: VideoProjectIdSchema, expected: SpatialProjectBasisSchema.optional() }), 1_024);
55
+ export const SpatialProjectMigrateInputSchema = boundedInput(z.strictObject({
56
+ ...mutationBase,
57
+ scenes: z.array(SpatialProjectSceneSourceSchema).max(SPATIAL_PROJECT_LIMITS.scenes),
58
+ shots: z.array(SpatialShotV1Schema).max(SPATIAL_PROJECT_LIMITS.shots),
59
+ }));
60
+ export const SpatialProjectPatchInputSchema = boundedInput(z.strictObject({ ...mutationBase, patch: SpatialScenePatchV1Schema, retarget: SpatialShotRetargetSchema }));
61
+ export const SpatialProjectRestoreInputSchema = boundedInput(z.strictObject({ ...mutationBase,
62
+ expectedSceneSha256: SpatialDigestSchema, restoreSceneSha256: SpatialDigestSchema, retarget: SpatialShotRetargetSchema,
63
+ }));
64
+ export const SpatialProjectAddShotInputSchema = boundedInput(z.strictObject({
65
+ ...mutationBase,
66
+ shot: SpatialShotV1Schema,
67
+ source: SpatialProjectSceneSourceSchema.optional(),
68
+ }));
69
+ export const SpatialProjectAddCandidateInputSchema = boundedInput(z.strictObject({ ...mutationBase, candidate: SpatialCandidateSchema }));
70
+ export const SpatialProjectSelectCandidateInputSchema = boundedInput(z.strictObject({ ...mutationBase, candidateId: SpatialCandidateIdSchema }));
71
+ export const SpatialProjectReconcileInputSchema = boundedInput(z.strictObject({ project: VideoProjectIdSchema, attempt: SpatialProjectArtifactSchema.refine(value => value.path.startsWith("spatial/attempts/")) }));
72
+
73
+ const snapshotBase = {
74
+ projectId: VideoProjectIdSchema,
75
+ basis: SpatialProjectBasisSchema,
76
+ legacy: SpatialProjectLegacySchema,
77
+ scenes: z.array(SpatialProjectSceneSourceSchema).max(SPATIAL_PROJECT_LIMITS.scenes),
78
+ shots: z.array(SpatialShotV1Schema).max(SPATIAL_PROJECT_LIMITS.shots),
79
+ candidates: z.array(SpatialCandidateSchema).max(SPATIAL_PROJECT_LIMITS.candidates),
80
+ selections: z.array(SpatialCandidateSelectionSchema.extend({ status: z.enum(["current", "stale"]) })).max(SPATIAL_PROJECT_LIMITS.shots),
81
+ };
82
+ export const SpatialProjectSnapshotOutputSchema = z.discriminatedUnion("version", [
83
+ z.strictObject({ ...snapshotBase, version: z.literal(1) }),
84
+ z.strictObject({ ...snapshotBase, version: z.literal(2), head: SpatialProjectHeadV2Schema }),
85
+ ]).superRefine((snapshot, context) => {
86
+ if (snapshot.basis.version !== snapshot.version || (snapshot.version === 2 && snapshot.head.projectRevisionSha256 !== snapshot.basis.sha256)) context.addIssue({ code: "custom", message: "Snapshot basis must match its exact authority version and head." });
87
+ });
88
+ export type SpatialProjectSnapshotInput = z.infer<typeof SpatialProjectSnapshotInputSchema>;
89
+ export type SpatialProjectSnapshotOutput = z.infer<typeof SpatialProjectSnapshotOutputSchema>;
90
+ export type SpatialProjectMigrateInput = z.infer<typeof SpatialProjectMigrateInputSchema>;
91
+ export type SpatialProjectPatchInput = z.infer<typeof SpatialProjectPatchInputSchema>;
92
+ export type SpatialProjectRestoreInput = z.infer<typeof SpatialProjectRestoreInputSchema>;
93
+ export type SpatialProjectAddShotInput = z.infer<typeof SpatialProjectAddShotInputSchema>;
94
+ export type SpatialProjectAddCandidateInput = z.infer<typeof SpatialProjectAddCandidateInputSchema>;
95
+ export type SpatialProjectSelectCandidateInput = z.infer<typeof SpatialProjectSelectCandidateInputSchema>;
96
+ export type SpatialProjectReconcileInput = z.infer<typeof SpatialProjectReconcileInputSchema>;
97
+
98
+ async function ownedPorts(context: OperationExecutionContext, project: string, mode: "read" | "write" = "write"): Promise<SpatialProjectStorePorts> {
99
+ const ports = await spatialProjectStorePorts(context.application, project);
100
+ return { ...ports, custody: { ...ports.custody, assertHeld: async () => {
101
+ await ports.custody.assertHeld();
102
+ if (mode === "write") await context.workflow?.beforePublication();
103
+ } } };
104
+ }
105
+ function requireSpatial(current: SpatialProjectAuthority): SpatialProjectContents {
106
+ if (current.version !== 2) throw new ApplicationError("conflict", "This mutation requires V2 spatial authority; migrate the checked V1 project first.");
107
+ return current.contents;
108
+ }
109
+ const mutationPolicy: OperationPolicy = {
110
+ cache: "none", cancellable: true, effect: "project-mutation", maxDurationMs: 120_000, maxFanOut: 0,
111
+ maxInputBytes: SPATIAL_PROJECT_LIMITS.documentBytes, maxOutputBytes: 2 * 1024 * 1024,
112
+ preparation: ["project-state"], resources: [{ amount: 1, resource: "local-io" }, { amount: 1, resource: "project-publication" }],
113
+ resume: "ambiguous-after-dispatch",
114
+ };
115
+ function mutationDefinition<Kind extends OperationKind, Input>(
116
+ kind: Kind,
117
+ inputSchema: z.ZodType<Input>,
118
+ execute: (context: OperationExecutionContext, input: Input) => Promise<SpatialProjectMutationOutput>,
119
+ ): OperationDefinition<Kind, Input, SpatialProjectMutationOutput> {
120
+ return {
121
+ kind, version: 1, inputSchema, inputSchemaId: `slopcamera.operation.${kind}.input/v1`,
122
+ outputSchema: SpatialProjectMutationOutputSchema, outputSchemaId: `slopcamera.operation.${kind}.output/v1`,
123
+ lifecycle: { kind: "project-transaction", execute: async (context, input) => await execute(context, inputSchema.parse(input)) },
124
+ policy: mutationPolicy,
125
+ receiptReference: output => output.kind === "completed" ? output.settlement.path : undefined,
126
+ summarize: output => ({ kind, fields: { disposition: output.kind, ...(output.kind === "completed" ? { projectRevisionSha256: output.projectRevisionSha256 } : { message: output.message }) } }),
127
+ };
128
+ }
129
+
130
+ export const spatialProjectSnapshotOperationDefinition: OperationDefinition<"spatial.project.snapshot", SpatialProjectSnapshotInput, SpatialProjectSnapshotOutput> = {
131
+ kind: "spatial.project.snapshot", version: 1,
132
+ inputSchema: SpatialProjectSnapshotInputSchema, inputSchemaId: "slopcamera.operation.spatial.project.snapshot.input/v1",
133
+ outputSchema: SpatialProjectSnapshotOutputSchema, outputSchemaId: "slopcamera.operation.spatial.project.snapshot.output/v1",
134
+ lifecycle: { kind: "local-artifact", execute: async (context, input) => {
135
+ const request = SpatialProjectSnapshotInputSchema.parse(input);
136
+ if (context.abortSignal.aborted) throw new ApplicationError("cancelled", "Spatial snapshot cancelled.");
137
+ const ports = await ownedPorts(context, request.project, "read");
138
+ const current = await readSpatialProjectAuthority(ports);
139
+ await ports.custody.assertHeld();
140
+ if (context.abortSignal.aborted) throw new ApplicationError("cancelled", "Spatial snapshot cancelled.");
141
+ if (request.expected !== undefined && canonicalJson(request.expected) !== canonicalJson(current.basis)) throw new ApplicationError("conflict", "Spatial snapshot basis is stale.");
142
+ const result = SpatialProjectSnapshotOutputSchema.parse({
143
+ projectId: current.contents.legacy.project.projectId, version: current.version, basis: current.basis,
144
+ ...current.contents,
145
+ selections: current.contents.selections.map(selection => {
146
+ const candidate = current.contents.candidates.find(value => value.candidateId === selection.candidateId);
147
+ if (candidate === undefined) throw new ApplicationError("invalid-data", "Selected spatial candidate is absent.");
148
+ return { ...selection, status: spatialCandidateStatus(current.contents, candidate) };
149
+ }),
150
+ ...(current.version === 2 ? { head: current.head } : {}),
151
+ });
152
+ if (new TextEncoder().encode(spatialProjectDocumentText(result)).byteLength > SPATIAL_PROJECT_LIMITS.documentBytes) throw new ApplicationError("invalid-data", "Spatial snapshot exceeds its 32 MiB output budget.");
153
+ return result;
154
+ } },
155
+ policy: { ...mutationPolicy, effect: "local-read", cache: "none", maxInputBytes: 1_024, maxOutputBytes: SPATIAL_PROJECT_LIMITS.documentBytes, resume: "deterministic" },
156
+ summarize: output => ({ kind: "spatial.project.snapshot", fields: { projectId: output.projectId, version: output.version, projectRevisionSha256: output.basis.sha256, scenes: output.scenes.length, shots: output.shots.length } }),
157
+ };
158
+
159
+ export const spatialProjectMigrateOperationDefinition = mutationDefinition("spatial.project.migrate", SpatialProjectMigrateInputSchema, async (context, input) => {
160
+ const ports = await ownedPorts(context, input.project);
161
+ return SpatialProjectMutationOutputSchema.parse({ projectId: input.project, ...await migrateSpatialProject({ ports, expected: input.expected, transactionId: input.transactionId, scenes: input.scenes, shots: input.shots, signal: context.abortSignal }) });
162
+ });
163
+ export const spatialProjectPatchOperationDefinition = mutationDefinition("spatial.project.patch", SpatialProjectPatchInputSchema, async (context, input) => {
164
+ const ports = await ownedPorts(context, input.project);
165
+ let diff: SpatialProjectSceneDiff | undefined;
166
+ const result = await commitSpatialProjectRevision({ ports, expected: input.expected, transactionId: input.transactionId, signal: context.abortSignal, change: current => {
167
+ const patch = applySpatialProjectScenePatch(requireSpatial(current), input.patch, input.retarget);
168
+ diff = patch.diff;
169
+ return patch.contents;
170
+ } });
171
+ return SpatialProjectMutationOutputSchema.parse({ projectId: input.project, ...result, ...(result.kind === "completed" && diff !== undefined ? { diff } : {}) });
172
+ });
173
+ export const spatialProjectRestoreOperationDefinition = mutationDefinition("spatial.project.restore", SpatialProjectRestoreInputSchema, async (context, input) => {
174
+ const ports = await ownedPorts(context, input.project);
175
+ let diff: SpatialProjectSceneDiff | undefined;
176
+ const result = await commitSpatialProjectRevision({ ports, expected: input.expected, transactionId: input.transactionId, signal: context.abortSignal, change: current => {
177
+ const restored = restoreSpatialProjectScene(requireSpatial(current), input.expectedSceneSha256, input.restoreSceneSha256, input.retarget);
178
+ diff = restored.diff;
179
+ return restored.contents;
180
+ } });
181
+ return SpatialProjectMutationOutputSchema.parse({ projectId: input.project, ...result, ...(result.kind === "completed" && diff !== undefined ? { diff } : {}) });
182
+ });
183
+ export const spatialProjectAddShotOperationDefinition = mutationDefinition("spatial.project.add-shot", SpatialProjectAddShotInputSchema, async (context, input) => {
184
+ const ports = await ownedPorts(context, input.project);
185
+ return SpatialProjectMutationOutputSchema.parse({ projectId: input.project, ...await commitSpatialProjectRevision({ ports, expected: input.expected, transactionId: input.transactionId, signal: context.abortSignal, change: current => {
186
+ const contents = requireSpatial(current);
187
+ if (contents.shots.some(shot => shot.shotId === input.shot.shotId)) throw new ApplicationError("conflict", "Shot identity already exists.");
188
+ let scenes = contents.scenes;
189
+ if (input.source !== undefined) {
190
+ const document = parseSpatialScene(input.source.document);
191
+ const digest = spatialSceneSha256(document);
192
+ if (digest !== input.source.sceneSha256 || digest !== input.shot.sceneSha256) throw new ApplicationError("invalid-data", "New shot must bind its exact source scene.");
193
+ if (!scenes.some(scene => scene.sceneSha256 === digest)) scenes = [...scenes, { document, sceneSha256: digest }];
194
+ }
195
+ return { ...contents, scenes, shots: [...contents.shots, input.shot] };
196
+ } }) });
197
+ });
198
+ export const spatialProjectAddCandidateOperationDefinition = mutationDefinition("spatial.project.add-candidate", SpatialProjectAddCandidateInputSchema, async (context, input) => {
199
+ const ports = await ownedPorts(context, input.project);
200
+ return SpatialProjectMutationOutputSchema.parse({ projectId: input.project, ...await commitSpatialProjectRevision({ ports, expected: input.expected, transactionId: input.transactionId, signal: context.abortSignal, change: current => addSpatialCandidate(requireSpatial(current), input.candidate) }) });
201
+ });
202
+ export const spatialProjectSelectCandidateOperationDefinition = mutationDefinition("spatial.project.select-candidate", SpatialProjectSelectCandidateInputSchema, async (context, input) => {
203
+ const ports = await ownedPorts(context, input.project);
204
+ return SpatialProjectMutationOutputSchema.parse({ projectId: input.project, ...await commitSpatialProjectRevision({ ports, expected: input.expected, transactionId: input.transactionId, signal: context.abortSignal, change: current => selectSpatialCandidate(requireSpatial(current), input.candidateId) }) });
205
+ });
206
+ export const spatialProjectReconcileOperationDefinition = mutationDefinition("spatial.project.reconcile", SpatialProjectReconcileInputSchema, async (context, input) => {
207
+ const ports = await ownedPorts(context, input.project);
208
+ return SpatialProjectMutationOutputSchema.parse({ projectId: input.project, ...await reconcileSpatialProjectCommit({ ports, attempt: input.attempt }) });
209
+ });
@@ -0,0 +1,415 @@
1
+ import { constants } from "node:fs";
2
+ import { mkdtemp, open, rm } from "node:fs/promises";
3
+ import { dirname, join, posix, relative } from "node:path";
4
+
5
+ import { z } from "zod";
6
+
7
+ import { createBoundedJsonValueSnapshot } from "../../../../src/code/json-snapshot";
8
+ import { SPATIAL_SCENE_LIMITS, SpatialAssetIdSchema, SpatialDigestSchema } from "../../../../src/spatial-scene/contracts";
9
+ import { parseSpatialScene, spatialSceneSha256 } from "../../../../src/spatial-scene/identity";
10
+ import { spatialAssetClosureDigests } from "../../../../src/spatial-scene/identity";
11
+ import { evaluateSpatialScene } from "../../../../src/spatial-scene/evaluate";
12
+ import { ensurePhysicalPrivateDirectoryWithin } from "../../cli/paths";
13
+ import { canonicalJson, canonicalJsonSha256, sha256Hex } from "../../core/canonical-json";
14
+ import { createNodeSpatialDurability } from "../../core/spatial-durability";
15
+ import { createNodeBundleFileSystem, saveImmutableText } from "../../core/storage";
16
+ import { createSpatialOverlayBatch, PreparedSpatialAssetSchema, SPATIAL_OVERLAY_LIMITS } from "../../html-overlay/spatial";
17
+ import { assertHtmlOverlayGpuEvidenceProfile, HtmlOverlayGpuEvidenceSchema } from "../../html-overlay/execution-profile";
18
+ import { createHtmlOverlayExecutionBundle, HtmlOverlayExecutionIntegritySchema } from "../html-overlay-integrity";
19
+ import { exactCapabilityByName } from "../capability-binding";
20
+ import type { ApplicationContext } from "../context";
21
+ import { ApplicationError } from "../errors";
22
+ import { bindHtmlOverlayBrowserRuntime, HtmlOverlayBrowserRuntimeBindingSchema } from "../html-overlay-browser-runtime";
23
+ import type { OperationDefinition, OperationExecutionContext } from "../operation";
24
+ import { writeOperationCompletionCheckpoint } from "../operation-completion-checkpoint";
25
+ import { SpatialRenderRequestSchema, SpatialRenderOutputSchema, SpatialRenderReceiptSchema, SpatialRenderFailure, SPATIAL_RENDER_LIMITS, renderSpatialScene, planSpatialRender, verifySpatialEncodedVideo, spatialRenderCapabilityNames } from "../spatial-render";
26
+ import type { OperationCheckpointExecutionIdentity } from "../operation-completion-checkpoint";
27
+ import { MediaCapabilityBindingsSchema, bindExpectedMediaCapabilities } from "./media/capabilities";
28
+ import {
29
+ MediaArtifactReferenceSchema, MediaArtifactRequestSchema, bindRepositoryMedia, loadRepositoryMedia,
30
+ createMediaOperationWorkspace, publishContentAddressedMedia, type MediaArtifactReference, type MediaOperationWorkspace,
31
+ } from "./media/shared";
32
+ import { throwIfAborted } from "./shared";
33
+
34
+ const MAXIMUM_ASSET_BYTES = 256 * 1024 * 1024;
35
+ const AssetBindingSchema = z.strictObject({ assetId: SpatialAssetIdSchema, artifact: MediaArtifactReferenceSchema });
36
+ const requestShape = z.strictObject({
37
+ source: MediaArtifactRequestSchema,
38
+ assets: z.array(AssetBindingSchema).max(SPATIAL_SCENE_LIMITS.assets).optional(),
39
+ request: SpatialRenderRequestSchema,
40
+ sceneSha256: SpatialDigestSchema.optional(),
41
+ capabilityBindings: MediaCapabilityBindingsSchema.optional(),
42
+ browserRuntime: HtmlOverlayBrowserRuntimeBindingSchema.optional(),
43
+ });
44
+ const captured = (input: unknown) => createBoundedJsonValueSnapshot(input, 16 * 1024 * 1024, "spatial render request", { maximumDepth: 48, maximumValues: 500_000 }).value;
45
+ export const SpatialRenderInputSchema = z.preprocess(captured, requestShape);
46
+ export const BoundSpatialRenderInputSchema = z.preprocess(captured, requestShape.extend({
47
+ source: MediaArtifactReferenceSchema,
48
+ assets: z.array(AssetBindingSchema).max(SPATIAL_SCENE_LIMITS.assets),
49
+ sceneSha256: SpatialDigestSchema,
50
+ capabilityBindings: MediaCapabilityBindingsSchema,
51
+ browserRuntime: HtmlOverlayBrowserRuntimeBindingSchema,
52
+ }));
53
+ export type SpatialRenderInput = z.infer<typeof SpatialRenderInputSchema>;
54
+ export type BoundSpatialRenderInput = z.infer<typeof BoundSpatialRenderInputSchema>;
55
+
56
+ function sourceDocument(data: Uint8Array) {
57
+ try { return parseSpatialScene(JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(data))); }
58
+ catch (error) { throw new ApplicationError("invalid-data", `Invalid spatial source: ${error instanceof Error ? error.message : String(error)}`); }
59
+ }
60
+
61
+ /** The source grants access only to its bounded, root-contained declared closure. */
62
+ export async function bindSpatialRenderInput(application: ApplicationContext, input: unknown, signal = new AbortController().signal, bindRuntime: typeof bindHtmlOverlayBrowserRuntime = bindHtmlOverlayBrowserRuntime): Promise<BoundSpatialRenderInput> {
63
+ const parsed = SpatialRenderInputSchema.parse(input);
64
+ const source = await loadRepositoryMedia(application, parsed.source, signal, SPATIAL_SCENE_LIMITS.sourceBytes);
65
+ const scene = sourceDocument(source.data);
66
+ const plan = planSpatialRender(scene, parsed.request);
67
+ const sceneSha256 = spatialSceneSha256(scene);
68
+ if (parsed.sceneSha256 !== undefined && parsed.sceneSha256 !== sceneSha256) throw new ApplicationError("conflict", "Scene source changed after planning.");
69
+ if (scene.assets.reduce((sum, asset) => sum + asset.payload.bytes, 0) > MAXIMUM_ASSET_BYTES) throw new ApplicationError("invalid-data", "Scene asset closure exceeds 256 MiB.");
70
+ const supplied = parsed.assets === undefined ? undefined : new Map(parsed.assets.map(item => [item.assetId, item.artifact]));
71
+ if (supplied !== undefined && (supplied.size !== parsed.assets!.length || supplied.size !== scene.assets.length || scene.assets.some(asset => !supplied.has(asset.assetId)))) throw new ApplicationError("invalid-data", "Asset bindings must name every declared asset exactly once.");
72
+ const assets: z.infer<typeof AssetBindingSchema>[] = [];
73
+ for (const asset of scene.assets) {
74
+ const request = supplied?.get(asset.assetId) ?? {
75
+ ...asset.payload, path: posix.join(posix.dirname(source.artifact.path), asset.payload.path),
76
+ };
77
+ if (request.sha256 !== asset.payload.sha256 || request.bytes !== asset.payload.bytes) throw new ApplicationError("conflict", `Asset ${asset.assetId} does not match its source manifest.`);
78
+ const bound = await bindRepositoryMedia(application, request, signal, asset.payload.bytes);
79
+ assets.push({ assetId: asset.assetId, artifact: bound.artifact });
80
+ }
81
+ const capabilityBindings = await bindExpectedMediaCapabilities(application, spatialRenderCapabilityNames(plan), parsed.capabilityBindings);
82
+ const browserRuntime = await bindRuntime(exactCapabilityByName(capabilityBindings, "html-browser"), signal);
83
+ if (parsed.browserRuntime !== undefined && canonicalJson(parsed.browserRuntime) !== canonicalJson(browserRuntime)) throw new ApplicationError("conflict", "Browser runtime changed after scene planning.");
84
+ return BoundSpatialRenderInputSchema.parse({ ...parsed, source: source.artifact, assets, sceneSha256, capabilityBindings, browserRuntime });
85
+ }
86
+
87
+ async function writePrivateFile(path: string, bytes: Uint8Array): Promise<void> {
88
+ const handle = await open(path, constants.O_CREAT | constants.O_EXCL | constants.O_WRONLY | constants.O_NOFOLLOW, 0o600);
89
+ try { await handle.writeFile(bytes); await handle.sync(); } finally { await handle.close(); }
90
+ }
91
+
92
+ const definitionIdentity = {
93
+ kind: "scene.render", version: 1,
94
+ inputSchemaId: "slopcamera.operation.scene.render.input/v1", outputSchemaId: "slopcamera.operation.scene.render.output/v1",
95
+ } as const;
96
+
97
+ const ATTEMPT_FILE = "spatial-render-attempt.v1.json";
98
+ const RESULT_FILE = "spatial-render-result.v1.json";
99
+ const MAXIMUM_MARKER_BYTES = 2 * 1024 * 1024;
100
+ const executionIdentitySchema = z.strictObject({
101
+ kind: z.literal("scene.render"), version: z.literal(1),
102
+ inputSchemaId: z.literal(definitionIdentity.inputSchemaId), outputSchemaId: z.literal(definitionIdentity.outputSchemaId),
103
+ nodeKey: z.string().min(1).max(255), nodePlanSha256: SpatialDigestSchema, runId: z.string().min(1).max(256),
104
+ });
105
+ const markerBase = { schemaVersion: z.literal(1), identity: executionIdentitySchema, inputSha256: SpatialDigestSchema };
106
+ const attemptSchema = z.strictObject({ ...markerBase, kind: z.literal("slopcamera.spatial-render-operation-attempt"), originalSceneArtifact: MediaArtifactReferenceSchema });
107
+ const resultSchema = z.strictObject({ ...markerBase, kind: z.literal("slopcamera.spatial-render-operation-result"), output: SpatialRenderOutputSchema });
108
+
109
+ /** Trusted test ports are never part of a serialized render request. */
110
+ export interface SpatialRenderOperationDependencies {
111
+ readonly bindBrowserRuntime?: typeof bindHtmlOverlayBrowserRuntime;
112
+ readonly createWorkspace?: typeof createMediaOperationWorkspace;
113
+ readonly createDirectory?: typeof mkdtemp;
114
+ readonly removeDirectory?: (path: string) => Promise<void>;
115
+ readonly publishOriginal?: typeof publishContentAddressedMedia;
116
+ readonly render?: typeof renderSpatialScene;
117
+ readonly checkpoint?: typeof writeOperationCompletionCheckpoint;
118
+ }
119
+ function originalArtifact(application: ApplicationContext, source: MediaArtifactReference): MediaArtifactReference {
120
+ return MediaArtifactReferenceSchema.parse({ bytes: source.bytes, sha256: source.sha256,
121
+ path: relative(application.paths.repositoryRoot, join(dirname(application.paths.artifactRoot), "generated/media-operations/outputs", `${source.sha256}.json`)) });
122
+ }
123
+ function operationIdentity(context: OperationExecutionContext) {
124
+ const workflow = context.workflow;
125
+ return workflow === undefined ? undefined : executionIdentitySchema.parse({ ...definitionIdentity,
126
+ nodeKey: workflow.nodeKey, nodePlanSha256: workflow.nodePlanSha256, runId: workflow.runId });
127
+ }
128
+ async function immutableMarker(application: ApplicationContext, workspace: string, path: string, value: unknown): Promise<"created" | "exists"> {
129
+ const text = `${canonicalJson(value)}\n`;
130
+ const bytes = new TextEncoder().encode(text).length;
131
+ if (bytes > MAXIMUM_MARKER_BYTES) throw new ApplicationError("invalid-data", "Spatial render recovery marker exceeds its byte budget.");
132
+ const digest = sha256Hex(text);
133
+ const disposition = await saveImmutableText(createNodeBundleFileSystem(workspace), path, text, digest);
134
+ await createNodeSpatialDurability(application.paths.repositoryRoot).syncExactFile(relative(application.paths.repositoryRoot, join(workspace, path)), { bytes, sha256: digest });
135
+ return disposition;
136
+ }
137
+
138
+ export async function executeSpatialRender(context: OperationExecutionContext, input: SpatialRenderInput, dependencies: SpatialRenderOperationDependencies = {}) {
139
+ if (context.workflow !== undefined) BoundSpatialRenderInputSchema.parse(input);
140
+ const bound = await bindSpatialRenderInput(context.application, input, context.abortSignal, dependencies.bindBrowserRuntime);
141
+ const source = await loadRepositoryMedia(context.application, bound.source, context.abortSignal, SPATIAL_SCENE_LIMITS.sourceBytes);
142
+ const scene = sourceDocument(source.data);
143
+ const identity = operationIdentity(context), inputSha256 = canonicalJsonSha256(bound);
144
+ let workspace: MediaOperationWorkspace | undefined, directory: string | undefined;
145
+ let completed: z.infer<typeof SpatialRenderOutputSchema> | undefined, uncertainPublication: MediaArtifactReference | undefined;
146
+ let stage = "preparation", failure: unknown, failed = false, resultRetentionAttempted = false;
147
+ const cleanupErrors: unknown[] = [], retained: MediaArtifactReference[] = [];
148
+ const beforePublication = async () => {
149
+ await context.application.hostResourceLease?.assertOwned();
150
+ throwIfAborted(context.abortSignal);
151
+ };
152
+ try {
153
+ workspace = await (dependencies.createWorkspace ?? createMediaOperationWorkspace)(context);
154
+ if (identity !== undefined) {
155
+ await context.workflow!.beforePublication();
156
+ await beforePublication();
157
+ const disposition = await immutableMarker(context.application, workspace.path, ATTEMPT_FILE, attemptSchema.parse({
158
+ kind: "slopcamera.spatial-render-operation-attempt", schemaVersion: 1, identity, inputSha256,
159
+ originalSceneArtifact: originalArtifact(context.application, source.artifact),
160
+ }));
161
+ if (disposition === "exists") throw new ApplicationError("ambiguous", "This exact spatial render attempt already started; reconcile its retained evidence instead of rendering again.");
162
+ }
163
+ directory = await (dependencies.createDirectory ?? mkdtemp)(join(workspace.path, "spatial-source-"));
164
+ const assetRoot = await ensurePhysicalPrivateDirectoryWithin(directory, "assets");
165
+ const writtenPaths = new Map<string, string>();
166
+ for (const asset of scene.assets) {
167
+ const artifact = bound.assets.find(item => item.assetId === asset.assetId)!.artifact;
168
+ const loaded = await loadRepositoryMedia(context.application, artifact, context.abortSignal, asset.payload.bytes);
169
+ const previous = writtenPaths.get(asset.payload.path);
170
+ if (previous !== undefined) {
171
+ if (previous !== artifact.sha256) throw new ApplicationError("conflict", "Two scene assets declare different bytes at one path.");
172
+ continue;
173
+ }
174
+ const parent = dirname(asset.payload.path);
175
+ if (parent !== ".") await ensurePhysicalPrivateDirectoryWithin(assetRoot, parent);
176
+ await writePrivateFile(join(assetRoot, asset.payload.path), loaded.data);
177
+ writtenPaths.set(asset.payload.path, artifact.sha256);
178
+ }
179
+ const originalPath = join(directory, "original.scene.json");
180
+ await writePrivateFile(originalPath, source.data);
181
+ stage = "source-publication";
182
+ uncertainPublication = originalArtifact(context.application, source.artifact);
183
+ const originalSceneArtifact = (await (dependencies.publishOriginal ?? publishContentAddressedMedia)({ context, beforePublication, extension: ".json", stagedPath: originalPath, maximumBytes: SPATIAL_SCENE_LIMITS.sourceBytes })).artifact;
184
+ if (canonicalJson(originalSceneArtifact) !== canonicalJson(uncertainPublication)) throw new ApplicationError("incompatible", "Published original spatial source differs from its prospective content address.");
185
+ await createNodeSpatialDurability(context.application.paths.repositoryRoot).syncExactFile(originalSceneArtifact.path, originalSceneArtifact);
186
+ retained.push(originalSceneArtifact);
187
+ uncertainPublication = undefined;
188
+ stage = "render";
189
+ completed = SpatialRenderOutputSchema.parse(createBoundedJsonValueSnapshot(await (dependencies.render ?? renderSpatialScene)(context, {
190
+ scene, assetRoot, request: bound.request, originalSceneArtifact,
191
+ capabilityBindings: bound.capabilityBindings, browserRuntime: bound.browserRuntime,
192
+ }), MAXIMUM_MARKER_BYTES, "completed spatial render").value);
193
+ stage = "checkpoint";
194
+ if (identity !== undefined) {
195
+ resultRetentionAttempted = true;
196
+ await immutableMarker(context.application, workspace.path, RESULT_FILE, resultSchema.parse({
197
+ kind: "slopcamera.spatial-render-operation-result", schemaVersion: 1, identity, inputSha256, output: completed,
198
+ }));
199
+ }
200
+ await (dependencies.checkpoint ?? writeOperationCompletionCheckpoint)(context, definitionIdentity, completed);
201
+ } catch (error) {
202
+ failure = error; failed = true;
203
+ if (error instanceof SpatialRenderFailure) {
204
+ uncertainPublication ??= error.evidence.uncertainPublication;
205
+ if (completed === undefined && error.evidence.completion !== undefined) completed = SpatialRenderOutputSchema.parse(createBoundedJsonValueSnapshot(error.evidence.completion, MAXIMUM_MARKER_BYTES, "spatial failure completion").value);
206
+ }
207
+ if (completed !== undefined && identity !== undefined && workspace !== undefined && !resultRetentionAttempted) {
208
+ // Retain a service completion even when its own cleanup failed. This is
209
+ // immutable evidence publication, never render or provider replay.
210
+ resultRetentionAttempted = true;
211
+ try { await immutableMarker(context.application, workspace.path, RESULT_FILE, resultSchema.parse({
212
+ kind: "slopcamera.spatial-render-operation-result", schemaVersion: 1, identity, inputSha256, output: completed,
213
+ })); } catch (settlementError) { cleanupErrors.push(settlementError); }
214
+ }
215
+ }
216
+ finally {
217
+ if (directory !== undefined) try { await (dependencies.removeDirectory ?? (async path => { await rm(path, { recursive: true, force: true }); }))(directory); } catch (error) { cleanupErrors.push(error); }
218
+ if (workspace !== undefined) try { await workspace.dispose(); } catch (error) { cleanupErrors.push(error); }
219
+ }
220
+ if (failed || cleanupErrors.length > 0) {
221
+ const cause = cleanupErrors.length === 0 ? failure : new AggregateError([...(failed ? [failure] : []), ...cleanupErrors], "Spatial render operation failed during execution or cleanup.");
222
+ const evidence = {
223
+ stage: failed ? stage : "cleanup", retainedInputArtifacts: retained,
224
+ ...(uncertainPublication === undefined ? {} : { uncertainPublication }), ...(completed === undefined ? {} : { completion: completed }),
225
+ ...(identity === undefined || workspace === undefined ? {} : { attemptPath: relative(context.application.paths.repositoryRoot, join(workspace.path, ATTEMPT_FILE)) }),
226
+ ...(failure instanceof ApplicationError ? { causeDetails: failure.details } : {}),
227
+ };
228
+ const error = new ApplicationError(uncertainPublication !== undefined || completed !== undefined ? "ambiguous" : failure instanceof ApplicationError ? failure.code : "internal",
229
+ cause instanceof Error ? cause.message : "Spatial rendering failed.", { spatialRenderOperation: evidence, cleanupErrors: cleanupErrors.map(error => error instanceof Error ? error.message : String(error)) });
230
+ error.cause = cause;
231
+ throw error;
232
+ }
233
+ if (completed === undefined) throw new ApplicationError("internal", "Spatial rendering completed without an output.");
234
+ return completed;
235
+ }
236
+
237
+ /** Missing durable attempt proves no publication was admitted; an existing attempt never authorizes replay. */
238
+ export async function recoverSpatialRenderAttempt(application: ApplicationContext, exactInput: unknown, identityInput: OperationCheckpointExecutionIdentity,
239
+ workspaceDirectory: string, signal: AbortSignal): Promise<{ kind: "retry" } | { kind: "ambiguous"; message: string } | { kind: "completed"; output: z.infer<typeof SpatialRenderOutputSchema>; receiptReference: string; summary: { artifactSha256: string; frameCount: number } }> {
240
+ throwIfAborted(signal);
241
+ const input = BoundSpatialRenderInputSchema.parse(exactInput);
242
+ const identity = executionIdentitySchema.parse(createBoundedJsonValueSnapshot(identityInput, 2_048, "spatial recovery identity").value);
243
+ const workspace = await createMediaOperationWorkspace({ application, abortSignal: signal, workflow: { ...identity, workspaceDirectory, beforePublication: async () => { throw new ApplicationError("internal", "Read-only spatial attempt recovery must not publish."); } } });
244
+ const fs = createNodeBundleFileSystem(workspace.path);
245
+ const read = async (path: string) => {
246
+ let text: string;
247
+ try { text = await fs.readText(path, MAXIMUM_MARKER_BYTES); }
248
+ catch (error) { if (error instanceof Error && "code" in error && error.code === "ENOENT") return undefined; throw error; }
249
+ const value = createBoundedJsonValueSnapshot(JSON.parse(text), MAXIMUM_MARKER_BYTES, "spatial recovery marker").value;
250
+ if (text !== `${canonicalJson(value)}\n`) throw new ApplicationError("incompatible", "Spatial recovery marker is not canonical immutable JSON.");
251
+ await createNodeSpatialDurability(application.paths.repositoryRoot).syncExactFile(relative(application.paths.repositoryRoot, join(workspace.path, path)), { bytes: new TextEncoder().encode(text).length, sha256: sha256Hex(text) });
252
+ return value;
253
+ };
254
+ const attemptValue = await read(ATTEMPT_FILE);
255
+ if (attemptValue === undefined) return { kind: "retry" };
256
+ const attempt = attemptSchema.parse(attemptValue);
257
+ if (canonicalJson(attempt.identity) !== canonicalJson(identity) || attempt.inputSha256 !== canonicalJsonSha256(input)
258
+ || canonicalJson(attempt.originalSceneArtifact) !== canonicalJson(originalArtifact(application, input.source))) throw new ApplicationError("incompatible", "Spatial attempt belongs to another exact execution or input.");
259
+ const resultValue = await read(RESULT_FILE);
260
+ throwIfAborted(signal);
261
+ if (resultValue === undefined) return { kind: "ambiguous", message: "Spatial rendering started but has no verified completion; preserve its original source and immutable artifacts. Automatic replay is disabled." };
262
+ const result = resultSchema.parse(resultValue);
263
+ if (canonicalJson(result.identity) !== canonicalJson(identity) || result.inputSha256 !== attempt.inputSha256) throw new ApplicationError("incompatible", "Spatial retained result belongs to another exact execution.");
264
+ const output = await recoverSpatialRenderOutput(application, input, result.output, identity, signal);
265
+ return { kind: "completed", output, receiptReference: output.receipt.path, summary: { artifactSha256: output.artifact.sha256, frameCount: output.render.frameCount } };
266
+ }
267
+
268
+ export const spatialRenderOperationDefinition = {
269
+ ...definitionIdentity,
270
+ inputSchema: SpatialRenderInputSchema, outputSchema: SpatialRenderOutputSchema,
271
+ lifecycle: { kind: "local-artifact", execute: executeSpatialRender },
272
+ policy: {
273
+ cache: "exact-run", cancellable: true, effect: "local-derived-write", maxDurationMs: 900_000,
274
+ maxFanOut: 0, maxInputBytes: 16 * 1024 * 1024, maxOutputBytes: 2 * 1024 * 1024,
275
+ preparation: ["local-media"], resources: [
276
+ { amount: 1, resource: "cpu" }, { amount: 1, resource: "local-io" }, { amount: 1, resource: "browser" },
277
+ { amount: 1, resource: "ffmpeg" }, { amount: 1, resource: "output-publication" },
278
+ ], resume: "verified-receipt",
279
+ },
280
+ receiptReference: output => output.receipt.path,
281
+ summarize: output => ({ kind: "scene.render", fields: { artifactSha256: output.artifact.sha256, frameCount: output.render.frameCount } }),
282
+ } satisfies OperationDefinition<"scene.render", SpatialRenderInput, z.infer<typeof SpatialRenderOutputSchema>>;
283
+
284
+ /** Reconcile immutable evidence without reopening mutable original paths or rendering again. */
285
+ export async function recoverSpatialRenderOutput(application: ApplicationContext, exactInput: unknown, outputInput: unknown,
286
+ identityInput: OperationCheckpointExecutionIdentity, signal: AbortSignal) {
287
+ throwIfAborted(signal);
288
+ const identity = executionIdentitySchema.parse(createBoundedJsonValueSnapshot(identityInput, 2_048, "spatial recovery identity").value);
289
+ const input = BoundSpatialRenderInputSchema.parse(exactInput);
290
+ const output = SpatialRenderOutputSchema.parse(createBoundedJsonValueSnapshot(outputInput, MAXIMUM_MARKER_BYTES, "spatial recovery output").value);
291
+ const equal = (left: unknown, right: unknown, message: string) => {
292
+ if (left === undefined || right === undefined) { if (left !== right) throw new ApplicationError("incompatible", message); return; }
293
+ if (canonicalJson(left) !== canonicalJson(right)) throw new ApplicationError("incompatible", message);
294
+ };
295
+ const durability = createNodeSpatialDurability(application.paths.repositoryRoot);
296
+ const readJson = async (artifact: z.infer<typeof MediaArtifactReferenceSchema>, maximumBytes: number) => {
297
+ throwIfAborted(signal);
298
+ const loaded = await loadRepositoryMedia(application, artifact, signal, maximumBytes);
299
+ const text = new TextDecoder("utf-8", { fatal: true }).decode(loaded.data);
300
+ const value = createBoundedJsonValueSnapshot(JSON.parse(text), maximumBytes, "spatial immutable recovery JSON", { maximumDepth: 48, maximumValues: 2_000_000 }).value;
301
+ if (text !== `${canonicalJson(value)}\n`) throw new ApplicationError("incompatible", "Spatial recovery artifact is not canonical immutable JSON.");
302
+ await durability.syncExactFile(artifact.path, artifact);
303
+ return value;
304
+ };
305
+ const receipt = SpatialRenderReceiptSchema.parse(await readJson(output.receipt, 1024 * 1024));
306
+ equal(receipt.output, output.artifact, "Spatial checkpoint output differs from its receipt.");
307
+ equal(receipt.source.canonicalScene, output.sceneSource, "Spatial canonical source differs from its receipt.");
308
+ equal(receipt.source.retainedAssets, output.retainedAssets, "Spatial retained closure differs from its receipt.");
309
+ equal(receipt.render, output.render, "Spatial render summary differs from its receipt.");
310
+ equal(receipt.workflow, { nodeKey: identity.nodeKey, nodePlanSha256: identity.nodePlanSha256, runId: identity.runId }, "Spatial receipt belongs to another workflow node.");
311
+ const original = receipt.source.originalSceneArtifact;
312
+ if (original === undefined || original.sha256 !== input.source.sha256 || original.bytes !== input.source.bytes) throw new ApplicationError("incompatible", "Spatial receipt does not retain the exact original source bytes.");
313
+ const originalScene = sourceDocument((await loadRepositoryMedia(application, original, signal, SPATIAL_SCENE_LIMITS.sourceBytes)).data);
314
+ await durability.syncExactFile(original.path, original);
315
+ const scene = parseSpatialScene(await readJson(output.sceneSource, SPATIAL_SCENE_LIMITS.sourceBytes + 1));
316
+ equal(scene, originalScene, "Spatial canonical source disagrees with its original bytes.");
317
+ const plan = planSpatialRender(scene, input.request);
318
+ equal(receipt.sceneSha256, input.sceneSha256, "Spatial receipt is for another authored scene.");
319
+ equal(plan.sceneSha256, input.sceneSha256, "Spatial source identity does not match the exact input.");
320
+ equal(receipt.request, plan.request, "Spatial receipt has a different render request.");
321
+ equal(receipt.requestSha256, plan.requestSha256, "Spatial request digest is invalid.");
322
+ assertHtmlOverlayGpuEvidenceProfile(plan.request.executionProfile, receipt.runtime.gpuEvidence);
323
+ equal(receipt.source.sourceManifests, spatialAssetClosureDigests(scene.assets), "Spatial manifest closure digest is invalid.");
324
+ if (output.retainedAssets.length !== scene.assets.length || new Set(output.retainedAssets.map(asset => asset.assetId)).size !== scene.assets.length) throw new ApplicationError("incompatible", "Spatial retained asset closure is incomplete or duplicated.");
325
+ if (input.assets.length !== scene.assets.length || new Set(input.assets.map(asset => asset.assetId)).size !== scene.assets.length) throw new ApplicationError("incompatible", "Bound spatial asset closure is incomplete or duplicated.");
326
+ for (const manifest of scene.assets) {
327
+ const asset = output.retainedAssets.find(item => item.assetId === manifest.assetId);
328
+ const boundAsset = input.assets.find(item => item.assetId === manifest.assetId);
329
+ if (asset === undefined || boundAsset === undefined || asset.originalPath !== manifest.payload.path
330
+ || asset.manifestSha256 !== receipt.source.sourceManifests[manifest.assetId]
331
+ || asset.artifact.sha256 !== manifest.payload.sha256 || asset.artifact.bytes !== manifest.payload.bytes
332
+ || boundAsset.artifact.sha256 !== manifest.payload.sha256 || boundAsset.artifact.bytes !== manifest.payload.bytes) throw new ApplicationError("incompatible", "Spatial retained asset does not match its exact source.");
333
+ await bindRepositoryMedia(application, asset.artifact, signal, manifest.payload.bytes);
334
+ await durability.syncExactFile(asset.artifact.path, asset.artifact);
335
+ }
336
+ equal(await readJson(receipt.runtime.artifact, SPATIAL_RENDER_LIMITS.metadataBytes), input.browserRuntime, "Spatial runtime bytes differ from the exact input.");
337
+ equal(receipt.runtime.rootSha256, input.browserRuntime.manifest.rootSha256, "Spatial runtime root differs from the exact input.");
338
+ equal(receipt.runtime.capabilities, input.capabilityBindings, "Spatial native capabilities differ from the exact input.");
339
+ equal(input.capabilityBindings.map(capability => capability.name), spatialRenderCapabilityNames(plan), "Spatial capabilities do not match the exact required capability set.");
340
+ equal(receipt.calibratedSourceDimensions, { width: plan.width, height: plan.height }, "Spatial calibrated source dimensions differ from the plan.");
341
+ equal(receipt.color, { output: plan.request.mode.kind === "beauty" ? "srgb" : "rgba8-data", alpha: plan.request.mode.kind === "beauty" ? "straight" : "binary-validity", toneMapping: "none" }, "Spatial output color evidence differs from the request.");
342
+ equal(receipt.timing.outputDurationUs, plan.outputDurationUs, "Spatial output duration differs from the exact frame clock.");
343
+ equal(receipt.contactSheet, plan.request.selection.kind === "contact-sheet" ? { fit: "contain", resampling: plan.request.mode.kind === "beauty" ? "lanczos3" : "nearest-data", calibratedProjectionResized: false } : undefined, "Spatial contact sheet policy differs from the exact request.");
344
+ if (receipt.samples.length !== plan.samples.length || output.render.frameCount !== plan.samples.length
345
+ || output.render.width !== plan.outputWidth || output.render.height !== plan.outputHeight || output.render.kind !== plan.request.selection.kind) throw new ApplicationError("incompatible", "Spatial output dimensions or sample count differ from the plan.");
346
+ const evaluatedSample = (index: number) => {
347
+ const sample = plan.samples[index]!;
348
+ const evidence = receipt.samples[index]!;
349
+ equal(evidence.sample, sample, "Spatial sample timestamp differs from its absolute clock.");
350
+ const state = evaluateSpatialScene(scene, { cameraId: plan.request.cameraId, timeUs: sample.timeUs,
351
+ ...(plan.request.overrides === undefined ? {} : { overrides: plan.request.overrides }),
352
+ ...(plan.request.cameraPoseOverride === undefined ? {} : { cameraPoseOverride: plan.request.cameraPoseOverride }),
353
+ });
354
+ equal(evidence.stateSha256, state.stateSha256, "Spatial evaluated state differs from its authored source.");
355
+ equal(evidence.viewSha256, state.viewSha256, "Spatial evaluated camera differs from its render request.");
356
+ return state;
357
+ };
358
+ await bindRepositoryMedia(application, output.artifact, signal, plan.costs.outputBytesBound);
359
+ await durability.syncExactFile(output.artifact.path, output.artifact);
360
+ const batchSchema = z.strictObject({
361
+ gpuEvidence: HtmlOverlayGpuEvidenceSchema.optional(),
362
+ metadata: z.unknown(), metadataSha256: SpatialDigestSchema, executionIntegrity: HtmlOverlayExecutionIntegritySchema,
363
+ libraryLocks: z.array(z.unknown()).min(1).max(3), preparedAssets: z.array(PreparedSpatialAssetSchema).max(SPATIAL_OVERLAY_LIMITS.preparedAssets),
364
+ preparation: z.strictObject({ kind: z.literal("slopcamera.spatial-asset-preparation"), schemaVersion: z.literal(1), sourceManifests: z.record(SpatialAssetIdSchema, SpatialDigestSchema),
365
+ preparedSha256: SpatialDigestSchema, sourceBytes: z.number().int().safe().min(0).max(MAXIMUM_ASSET_BYTES), outputBytes: z.number().int().safe().min(0).max(MAXIMUM_ASSET_BYTES), profiles: z.array(z.string().min(1).max(256)).max(1_024) }),
366
+ samples: SpatialRenderReceiptSchema.shape.samples,
367
+ });
368
+ if ((plan.request.executionProfile === undefined && receipt.batches.length !== Math.ceil(plan.samples.length / SPATIAL_RENDER_LIMITS.batchFrames))
369
+ || new Set(receipt.batches.map(batch => batch.path)).size !== receipt.batches.length) throw new ApplicationError("incompatible", "Spatial batch partitions are incomplete or duplicated.");
370
+ let metadataBytes = 0, offset = 0;
371
+ for (const artifact of receipt.batches) {
372
+ metadataBytes += artifact.bytes;
373
+ if (metadataBytes > SPATIAL_RENDER_LIMITS.metadataBytes) throw new ApplicationError("incompatible", "Spatial batch closure exceeds its total metadata budget.");
374
+ const batch = batchSchema.parse(await readJson(artifact, SPATIAL_RENDER_LIMITS.metadataBytes));
375
+ const length = plan.request.executionProfile === undefined ? Math.min(SPATIAL_RENDER_LIMITS.batchFrames, plan.samples.length - offset) : batch.samples.length;
376
+ if (length < 1 || length > SPATIAL_RENDER_LIMITS.batchFrames || offset + length > plan.samples.length
377
+ || Math.floor(offset / SPATIAL_RENDER_LIMITS.batchFrames) !== Math.floor((offset + length - 1) / SPATIAL_RENDER_LIMITS.batchFrames)) throw new ApplicationError("incompatible", "Spatial batch crosses its exact bounded preparation window.");
378
+ const snapshots = plan.samples.slice(offset, offset + length).map((_, index) => evaluatedSample(offset + index));
379
+ const expectedBatch = createSpatialOverlayBatch({ snapshots,
380
+ ...(plan.request.executionProfile === undefined ? {} : { executionProfile: plan.request.executionProfile }),
381
+ mode: plan.request.mode, frameRate: plan.request.selection.kind === "video" ? plan.request.selection.frameRate : { numerator: 1, denominator: 1 }, preparedAssets: batch.preparedAssets });
382
+ equal(batch.metadata, expectedBatch.metadata, "Spatial batch metadata differs from the exact scene samples.");
383
+ equal(batch.metadataSha256, expectedBatch.metadataSha256, "Spatial batch metadata digest is invalid.");
384
+ const execution = createHtmlOverlayExecutionBundle(expectedBatch.authoring, input.browserRuntime, plan.request.executionProfile);
385
+ assertHtmlOverlayGpuEvidenceProfile(plan.request.executionProfile, batch.gpuEvidence);
386
+ equal(batch.gpuEvidence, receipt.runtime.gpuEvidence, "Spatial batch hardware identity differs from its completion receipt.");
387
+ equal(batch.executionIntegrity, execution.integrity, "Spatial batch execution integrity differs from its exact authored runtime.");
388
+ equal(batch.libraryLocks, execution.libraryLocks, "Spatial batch library locks differ from the qualified runtime.");
389
+ equal(batch.samples, receipt.samples.slice(offset, offset + length), "Spatial batch sample partition differs from the completion receipt.");
390
+ equal(batch.preparation.sourceManifests, receipt.source.sourceManifests, "Spatial batch source manifest closure is invalid.");
391
+ equal(batch.preparation.preparedSha256, canonicalJsonSha256(batch.preparedAssets), "Spatial batch prepared content digest is invalid.");
392
+ equal(batch.preparation.sourceBytes, scene.assets.reduce((sum, asset) => sum + asset.payload.bytes, 0), "Spatial batch source byte count is invalid.");
393
+ if (plan.request.executionProfile !== undefined) equal(batch.preparation.outputBytes, expectedBatch.authoring.resources.reduce((sum, resource) => sum + resource.bytes, 0), "Spatial batch prepared resource byte count is invalid.");
394
+ offset += length;
395
+ }
396
+ if (offset !== plan.samples.length) throw new ApplicationError("incompatible", "Spatial batch partitions do not cover every exact sample.");
397
+ equal(receipt.costs, { ...plan.costs, actualPngBytes: receipt.samples.reduce((sum, sample) => sum + sample.pngBytes, 0), actualBatchMetadataBytes: metadataBytes }, "Spatial receipt costs differ from its exact retained artifact counts.");
398
+ if (receipt.costs.actualPngBytes > plan.costs.pngBytesBound || receipt.samples.some(sample => sample.pngBytes < 1)) throw new ApplicationError("incompatible", "Spatial frame byte accounting exceeds the admitted bound.");
399
+ for (const [index, artifact] of receipt.frameArtifacts.entries()) {
400
+ await bindRepositoryMedia(application, artifact, signal, plan.costs.pngBytesBound);
401
+ await durability.syncExactFile(artifact.path, artifact);
402
+ const sample = receipt.samples[index];
403
+ if (sample === undefined || artifact.sha256 !== sample.pngSha256 || artifact.bytes !== sample.pngBytes) throw new ApplicationError("incompatible", "Retained frame differs from the rendered sample.");
404
+ }
405
+ if (plan.request.selection.kind === "frame") equal(output.artifact, receipt.frameArtifacts[0], "Primary spatial frame must equal its retained sample artifact.");
406
+ if (plan.request.selection.kind === "video") {
407
+ if (receipt.frameArtifacts.length !== 0) throw new ApplicationError("incompatible", "Spatial video must not claim unrelated retained frame artifacts.");
408
+ if (receipt.encodedProbe === undefined) throw new ApplicationError("incompatible", "Spatial video lacks actual encoded evidence.");
409
+ equal(verifySpatialEncodedVideo(plan, await readJson(receipt.encodedProbe, SPATIAL_RENDER_LIMITS.probeBytes)), output.render.encodedEvidence, "Spatial encoded timing evidence does not match the retained probe.");
410
+ } else if (receipt.frameArtifacts.length !== plan.samples.length || receipt.encodedProbe !== undefined) throw new ApplicationError("incompatible", "Spatial raster output lacks exact retained frame evidence.");
411
+ throwIfAborted(signal);
412
+ return output;
413
+ }
414
+
415
+ export { SpatialRenderRequestSchema, SpatialRenderOutputSchema };