@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,248 @@
1
+ import { lstat, opendir } from "node:fs/promises";
2
+ import { join, relative } from "node:path";
3
+ import sharp from "sharp";
4
+ import { z } from "zod";
5
+ import { boundedCanonicalJsonSha256 } from "../../../src/code/canonical-json";
6
+ import { createBoundedJsonValueSnapshot } from "../../../src/code/json-snapshot";
7
+ import { SpatialAssetIdSchema, SpatialAssetInterpretationSchema, SpatialAssetManifestSchema, SpatialDigestSchema, SpatialPayloadSchema, type SpatialAssetManifest } from "../../../src/spatial-scene/contracts";
8
+ import { parseSpatialGlb, SPATIAL_GLB_PROFILE } from "../../../src/spatial-scene/gltf";
9
+ import { parseStudioPlan, StudioPathSchema, StudioRenderSchema, validateStudioReceipt } from "../../../src/studio";
10
+ import { ExactCapabilityBindingsSchema } from "../application/capability-binding";
11
+ import type { ApplicationContext } from "../application/context";
12
+ import { bindRepositoryMedia, loadRepositoryMedia, MediaArtifactReferenceSchema, type MediaArtifactReference } from "../application/operations/media/shared";
13
+ import { StudioRunOutputSchema } from "../application/studio-port";
14
+ import { createNodeBundleFileSystem } from "../core/storage";
15
+ import { CliError } from "./errors";
16
+ import { ensurePhysicalPrivateDirectoryWithin } from "./paths";
17
+ import { verifyStudioFramehash } from "./studio-encode";
18
+ import { studioBytesSha256, studioJson } from "./studio-files";
19
+ import { studioStorageRoot, type createStudioService } from "./studio-service";
20
+
21
+ const DOCUMENT_BYTES = 32 * 1024 * 1024;
22
+ const ASSET_BYTES = 128 * 1024 * 1024;
23
+ const hash = (value: unknown) => boundedCanonicalJsonSha256(value, { maximumBytes: DOCUMENT_BYTES, maximumDepth: 48, maximumValues: 1_000_000 });
24
+ const captured = (value: unknown) => createBoundedJsonValueSnapshot(value, DOCUMENT_BYTES, "studio asset document", { maximumDepth: 48, maximumValues: 1_000_000 }).value;
25
+ export const StudioSpatialAssetSelectionSchema = z.strictObject({
26
+ jobId: z.string().regex(/^studio_[a-zA-Z0-9][a-zA-Z0-9_-]{0,120}$/u), outputId: z.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9_-]{0,127}$/u),
27
+ representation: z.enum(["native", "encoded-video"]), frame: z.number().int().nonnegative().max(999_999).optional(),
28
+ }).refine(value => value.representation !== "encoded-video" || value.frame === undefined, "Encoded videos select the complete sequence, not one frame.");
29
+ export type StudioSpatialAssetSelection = z.infer<typeof StudioSpatialAssetSelectionSchema>;
30
+ export const StudioSpatialAssetReceiptSchema = z.strictObject({
31
+ kind: z.literal("slopcamera.studio-spatial-asset-receipt"), schemaVersion: z.literal(1),
32
+ selection: StudioSpatialAssetSelectionSchema, assetId: SpatialAssetIdSchema,
33
+ nativeReceipt: MediaArtifactReferenceSchema, planSha256: SpatialDigestSchema, bundleSha256: SpatialDigestSchema,
34
+ nativeOutputsSha256: SpatialDigestSchema, encodeReceipt: MediaArtifactReferenceSchema.optional(),
35
+ artifact: MediaArtifactReferenceSchema, payload: SpatialPayloadSchema, interpretation: SpatialAssetInterpretationSchema,
36
+ compatibility: z.enum([SPATIAL_GLB_PROFILE, "slopcamera.spatial-png-srgb8-v1", "slopcamera.spatial-studio-rgb-video-v1"]),
37
+ }).superRefine((value, context) => {
38
+ const image = value.compatibility === "slopcamera.spatial-png-srgb8-v1" && value.interpretation.kind === "image" && value.interpretation.mimeType === "image/png";
39
+ const model = value.compatibility === SPATIAL_GLB_PROFILE && value.interpretation.kind === "gltf" && value.interpretation.format === "glb";
40
+ const video = value.compatibility === "slopcamera.spatial-studio-rgb-video-v1" && value.interpretation.kind === "video";
41
+ const extension = model ? "glb" : image ? "png" : video && value.interpretation.kind === "video" && value.interpretation.alpha === "straight" ? "mov" : "mp4";
42
+ if ((!image && !model && !video) || video !== (value.selection.representation === "encoded-video") || video !== (value.encodeReceipt !== undefined)
43
+ || value.payload.sha256 !== value.artifact.sha256 || value.payload.bytes !== value.artifact.bytes || value.payload.path !== `studio/${value.artifact.sha256}.${extension}`) {
44
+ context.addIssue({ code: "custom", message: "Studio asset payload, interpretation, representation and compatibility evidence disagree." });
45
+ }
46
+ });
47
+ export type StudioSpatialAssetReceipt = z.infer<typeof StudioSpatialAssetReceiptSchema>;
48
+ export interface StudioSpatialAssetAdmissionInput {
49
+ readonly application: ApplicationContext;
50
+ readonly service: Pick<ReturnType<typeof createStudioService>, "inspect">;
51
+ readonly selection: StudioSpatialAssetSelection; readonly assetId: string; readonly signal: AbortSignal;
52
+ beforePublication(): Promise<void>;
53
+ }
54
+ export interface StudioSpatialAssetAdmission {
55
+ readonly asset: SpatialAssetManifest;
56
+ readonly binding: { readonly assetId: string; readonly artifact: MediaArtifactReference };
57
+ readonly receipt: MediaArtifactReference; readonly document: StudioSpatialAssetReceipt;
58
+ }
59
+
60
+ // This is the retained encoder's closed v1 evidence shape. Admission rederives
61
+ // source/settings identity and verifies its files; it does not bind or run tools.
62
+ const encodeRequestSchema = z.strictObject({
63
+ kind: z.literal("slopcamera.studio-encode-request"), schemaVersion: z.literal(1), planSha256: SpatialDigestSchema, nativeReceipt: MediaArtifactReferenceSchema,
64
+ jobId: z.string(), outputId: z.string(), render: StudioRenderSchema,
65
+ frames: z.array(z.strictObject({ path: StudioPathSchema, frame: z.number().int().nonnegative(), sha256: SpatialDigestSchema, bytes: z.number().int().safe().positive() })).min(1).max(216_000),
66
+ profile: z.enum(["rgb8-lossless-h264-v1", "rgba8-lossless-qtrle-v1"]), conversion: z.enum(["identity-uint8", "ffmpeg-no-dither-uint16-to-uint8-v1"]),
67
+ colorSpace: z.literal("srgb"), alpha: z.enum(["opaque", "straight"]), tools: ExactCapabilityBindingsSchema,
68
+ limits: z.strictObject({ timeoutMs: z.number().int().positive().max(300_000), maximumOutputBytes: z.number().int().positive().max(512 * 1024 * 1024) }),
69
+ });
70
+ const encodeReceiptSchema = z.strictObject({
71
+ kind: z.literal("slopcamera.studio-encode-receipt"), schemaVersion: z.literal(1), requestSha256: SpatialDigestSchema, request: encodeRequestSchema,
72
+ artifact: MediaArtifactReferenceSchema, verification: z.strictObject({ frameCount: z.number().int().positive(), canonicalFrameSha256: SpatialDigestSchema,
73
+ sourceFramehash: MediaArtifactReferenceSchema, videoFramehash: MediaArtifactReferenceSchema, probe: MediaArtifactReferenceSchema }),
74
+ });
75
+ const encodedProbeSchema = z.object({ streams: z.array(z.object({
76
+ codec_type: z.literal("video"), codec_name: z.string(), pix_fmt: z.string(), width: z.number().int(), height: z.number().int(),
77
+ avg_frame_rate: z.string().max(32), time_base: z.string().max(32), start_pts: z.literal(0), duration_ts: z.number().int().safe().positive(), nb_read_frames: z.string().max(16),
78
+ color_range: z.string().max(32).optional(), color_space: z.string().max(32).optional(), color_transfer: z.string().max(32).optional(), color_primaries: z.string().max(32).optional(),
79
+ })).length(1) });
80
+ const absent = (error: unknown) => error instanceof Error && "code" in error && error.code === "ENOENT";
81
+ function unsupported(message: string): never { throw new CliError("unsupported-plan", message); }
82
+ function conflict(message: string): never { throw new CliError("conflict", message); }
83
+
84
+ /** Untagged pixels use the authored sRGB interpretation; conflicting explicit tags reject. */
85
+ function assertSrgbPngTags(bytes: Uint8Array): void {
86
+ const data = Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength);
87
+ if (data.length < 33 || data.subarray(0, 8).toString("hex") !== "89504e470d0a1a0a") unsupported("Expected a bounded PNG image.");
88
+ let cursor = 8, count = 0;
89
+ while (cursor < data.length) {
90
+ if (++count > 65_536 || cursor + 12 > data.length) unsupported("PNG chunk envelope exceeds its bounded profile.");
91
+ const length = data.readUInt32BE(cursor), type = data.toString("ascii", cursor + 4, cursor + 8);
92
+ if (length > data.length - cursor - 12) unsupported("PNG chunk exceeds its retained bytes.");
93
+ if (type === "gAMA" && (length !== 4 || data.readUInt32BE(cursor + 8) !== 45455)) unsupported("PNG gamma contradicts its declared sRGB interpretation.");
94
+ if (type === "cHRM" && (length !== 32 || [31270,32900,64000,33000,30000,60000,15000,6000].some((value, i) => data.readUInt32BE(cursor + 8 + i * 4) !== value))) unsupported("PNG primaries contradict its declared sRGB interpretation.");
95
+ if (type === "sRGB" && (length !== 1 || data[cursor + 8]! > 3)) unsupported("PNG sRGB intent is invalid.");
96
+ cursor += length + 12;
97
+ }
98
+ }
99
+
100
+ /** Admit an existing native output or completed encode into the existing scene asset contract. */
101
+ export async function admitStudioSpatialAsset(input: StudioSpatialAssetAdmissionInput): Promise<StudioSpatialAssetAdmission> {
102
+ const selection = StudioSpatialAssetSelectionSchema.parse(captured(input.selection)), assetId = SpatialAssetIdSchema.parse(input.assetId);
103
+ const { application, signal } = input;
104
+ const fence = async () => {
105
+ if (signal.aborted) throw new CliError("cancelled", "Studio asset admission was cancelled.");
106
+ await application.hostResourceLease?.assertOwned(); await input.beforePublication(); await application.hostResourceLease?.assertOwned();
107
+ if (signal.aborted) throw new CliError("cancelled", "Studio asset admission was cancelled.");
108
+ };
109
+ await fence();
110
+ const native = StudioRunOutputSchema.parse(await input.service.inspect(selection.jobId));
111
+ const root = await studioStorageRoot(application), jobRoot = join(root, "jobs", selection.jobId), jobFs = createNodeBundleFileSystem(jobRoot);
112
+ const plan = parseStudioPlan(JSON.parse(await jobFs.readText("plan.json", DOCUMENT_BYTES)) as unknown);
113
+ const original = validateStudioReceipt({ plan, receipt: native.document });
114
+ if (original.state !== "succeeded" || original.jobId !== selection.jobId) unsupported("Scene assets require a successful retained Studio job.");
115
+ const expectedReceiptPath = relative(application.paths.repositoryRoot, join(jobRoot, "receipt.json"));
116
+ if (native.receipt.path !== expectedReceiptPath) conflict("Native receipt is outside its exact retained job.");
117
+ const evidence: MediaArtifactReference[] = [];
118
+ const load = async (reference: MediaArtifactReference, maximumBytes = DOCUMENT_BYTES) => {
119
+ const result = await loadRepositoryMedia(application, reference, signal, maximumBytes); evidence.push(result.artifact); return result.data;
120
+ };
121
+ const json = async (reference: MediaArtifactReference) => captured(JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(await load(reference))) as unknown);
122
+ if (studioJson(await json(native.receipt)) !== studioJson(original)) conflict("Native receipt bytes disagree with inspection.");
123
+ const spec = plan.job.outputs.find(item => item.id === selection.outputId);
124
+ if (spec === undefined) unsupported("The requested output ID is not declared by this Studio job.");
125
+ const selected = original.outputs.filter(item => item.outputId === selection.outputId).sort((a, b) => (a.frame ?? 0) - (b.frame ?? 0));
126
+ let artifact: MediaArtifactReference, interpretation: StudioSpatialAssetReceipt["interpretation"], compatibility: StudioSpatialAssetReceipt["compatibility"], encodeReceipt: MediaArtifactReference | undefined;
127
+ let extension: string;
128
+ if (selection.representation === "native") {
129
+ if (spec.kind === "sequence" ? selection.frame === undefined : selection.frame !== undefined) unsupported("Native sequences require an exact --frame; native files do not accept --frame.");
130
+ const files = selected.filter(item => selection.frame === undefined || item.frame === selection.frame);
131
+ if (files.length !== 1) unsupported("The selection must name exactly one retained output file.");
132
+ const file = files[0]!;
133
+ artifact = MediaArtifactReferenceSchema.parse({ path: relative(application.paths.repositoryRoot, join(jobRoot, "outputs", file.path)), sha256: file.sha256, bytes: file.bytes });
134
+ const bytes = await load(artifact, ASSET_BYTES);
135
+ if (spec.format === "glb" && spec.interpretation.kind === "model") {
136
+ if (spec.interpretation.sourceSpace.handedness !== "right") unsupported("Spatial GLB admission requires declared right-handed source coordinates.");
137
+ const space = spec.interpretation.sourceSpace;
138
+ const metersPerUnit = { meters: 1, centimeters: 0.01, millimeters: 0.001 }[space.units];
139
+ try {
140
+ const geometry = parseSpatialGlb(bytes).evaluate({ metersPerUnit, sourceUp: space.upAxis, timeUs: 0, materialMode: "source" });
141
+ for (const image of geometry.images) {
142
+ if (image.mimeType === "image/png") assertSrgbPngTags(image.bytes);
143
+ const decoder = sharp(image.bytes, { limitInputPixels: 33_554_432, failOn: "warning" }), metadata = await decoder.metadata();
144
+ if ((metadata.format !== "png" && metadata.format !== "jpeg") || (metadata.pages ?? 1) !== 1 || metadata.orientation !== undefined && metadata.orientation !== 1
145
+ || metadata.depth !== "uchar" || metadata.icc !== undefined || metadata.width !== image.width || metadata.height !== image.height || image.width > 8192 || image.height > 8192) unsupported("GLB base-color textures must fit the scene's unrotated 8-bit SDR image profile.");
146
+ await decoder.raw().toBuffer();
147
+ }
148
+ } catch (error) {
149
+ unsupported(`GLB is outside ${SPATIAL_GLB_PROFILE}: ${error instanceof Error ? error.message.slice(0, 2_048) : "invalid GLB"}. Keep detailed rigs and unsupported materials in native Studio.`);
150
+ }
151
+ interpretation = { kind: "gltf", format: "glb", metersPerUnit, sourceUp: space.upAxis };
152
+ compatibility = SPATIAL_GLB_PROFILE; extension = "glb";
153
+ } else if (spec.format === "png" && spec.interpretation.kind === "raster") {
154
+ const info = spec.interpretation, render = plan.job.render!;
155
+ if (info.semantic !== "color" || info.colorSpace !== "srgb" || info.dataType !== "uint8" || !["opaque", "straight"].includes(info.alpha)
156
+ || info.channels.join(",") !== (info.alpha === "straight" ? "R,G,B,A" : "R,G,B")) unsupported("Spatial images require an 8-bit sRGB RGB or straight RGBA PNG; preserve higher precision and data passes as native outputs.");
157
+ assertSrgbPngTags(bytes);
158
+ const image = sharp(bytes, { limitInputPixels: 33_554_432, failOn: "warning" }), metadata = await image.metadata();
159
+ if (metadata.format !== "png" || (metadata.pages ?? 1) !== 1 || metadata.orientation !== undefined && metadata.orientation !== 1 || metadata.depth !== "uchar" || metadata.icc !== undefined
160
+ || metadata.width !== render.width || metadata.height !== render.height || metadata.width > 8192 || metadata.height > 8192 || metadata.channels !== info.channels.length || Boolean(metadata.hasAlpha) !== (info.alpha === "straight")) unsupported("PNG pixels, dimensions or color metadata differ from the supported scene interpretation.");
161
+ await image.raw().toBuffer();
162
+ interpretation = { kind: "image", mimeType: "image/png", width: render.width, height: render.height, colorSpace: "srgb", alpha: info.alpha === "straight" ? "straight" : "opaque" };
163
+ compatibility = "slopcamera.spatial-png-srgb8-v1"; extension = "png";
164
+ } else unsupported("Native scene admission currently supports GLB and color PNG. Use explicit studio encode before admitting a PNG sequence as video.");
165
+ } else {
166
+ const raster = spec.interpretation, render = plan.job.render;
167
+ if (spec.kind !== "sequence" || spec.format !== "png" || raster.kind !== "raster" || render === undefined || raster.semantic !== "color" || raster.colorSpace !== "srgb"
168
+ || !["uint8", "uint16"].includes(raster.dataType) || !["opaque", "straight"].includes(raster.alpha) || raster.channels.join(",") !== (raster.alpha === "straight" ? "R,G,B,A" : "R,G,B")) unsupported("Encoded-video admission requires a declared sRGB PNG sequence and its completed studio encode receipt.");
169
+ const candidates: { receipt: MediaArtifactReference; document: z.infer<typeof encodeReceiptSchema> }[] = [];
170
+ let entries = 0, documentBytes = 0;
171
+ let derivatives;
172
+ try {
173
+ const path = join(jobRoot, "derivatives"), stat = await lstat(path);
174
+ if (!stat.isDirectory() || stat.isSymbolicLink()) conflict("Studio derivatives require the exact physical job directory.");
175
+ derivatives = await opendir(path);
176
+ } catch (error) { if (!absent(error)) throw error; }
177
+ if (derivatives !== undefined) {
178
+ for await (const entry of derivatives) {
179
+ await fence();
180
+ if (++entries > 64 || !entry.isDirectory() || !/^[a-f0-9]{64}$/u.test(entry.name)) conflict("Studio derivative inventory is invalid or exceeds 64 entries.");
181
+ const path = `derivatives/${entry.name}/receipt.json`;
182
+ let integrity;
183
+ try { integrity = await jobFs.inspectFile!(path, DOCUMENT_BYTES - documentBytes); } catch (error) { if (absent(error)) continue; throw error; }
184
+ documentBytes += integrity.bytes;
185
+ const receipt = { path: relative(application.paths.repositoryRoot, join(jobRoot, path)), ...integrity };
186
+ const document = encodeReceiptSchema.parse(await json(receipt));
187
+ if (document.requestSha256 !== entry.name || hash(document.request) !== entry.name || document.request.jobId !== selection.jobId) conflict("Retained encode identity differs from its exact job and request directory.");
188
+ if (document.request.outputId === selection.outputId) candidates.push({ receipt, document });
189
+ }
190
+ }
191
+ if (candidates.length === 0) unsupported("No completed encoded video exists for this output. Run studio encode explicitly first.");
192
+ if (candidates.length !== 1) conflict(`More than one completed encode matches; choose an unambiguous retained job. Matching request identities: ${candidates.map(item => item.document.requestSha256).join(", ")}`);
193
+ const candidate = candidates[0]!, encoded = candidate.document, request = encoded.request, alpha = raster.alpha === "straight";
194
+ encodeReceipt = candidate.receipt;
195
+ const frames = selected.map(item => ({ path: item.path, frame: item.frame!, sha256: item.sha256, bytes: item.bytes }));
196
+ const expected = { ...request, planSha256: plan.planSha256, nativeReceipt: native.receipt, jobId: selection.jobId, outputId: selection.outputId, render, frames,
197
+ profile: alpha ? "rgba8-lossless-qtrle-v1" : "rgb8-lossless-h264-v1", conversion: raster.dataType === "uint16" ? "ffmpeg-no-dither-uint16-to-uint8-v1" : "identity-uint8", colorSpace: "srgb", alpha: alpha ? "straight" : "opaque",
198
+ limits: { timeoutMs: Math.min(plan.job.limits.timeoutSeconds * 1000, 300_000), maximumOutputBytes: Math.min(plan.job.limits.maximumOutputBytes, 512 * 1024 * 1024) } };
199
+ if (hash(expected) !== encoded.requestSha256 || request.tools.length !== 2 || !request.tools.some(tool => tool.name === "ffmpeg") || !request.tools.some(tool => tool.name === "ffprobe")) conflict("Encoded video no longer matches its native sources, settings or tool evidence.");
200
+ const directory = join(jobRoot, "derivatives", encoded.requestSha256), fs = createNodeBundleFileSystem(directory);
201
+ const intent = { path: relative(application.paths.repositoryRoot, join(directory, "intent.json")), ...await fs.inspectFile!("intent.json", DOCUMENT_BYTES) };
202
+ if (studioJson(await json(intent)) !== studioJson({ kind: "slopcamera.studio-encode-intent", schemaVersion: 1, requestSha256: encoded.requestSha256, request })) conflict("Encode receipt differs from its retained immutable intent.");
203
+ extension = alpha ? "mov" : "mp4";
204
+ const files = [[encoded.artifact, `video.${extension}`], [encoded.verification.sourceFramehash, "source.framehash"], [encoded.verification.videoFramehash, "video.framehash"], [encoded.verification.probe, "probe.json"]] as const;
205
+ for (const [reference, name] of files) if (reference.path !== relative(application.paths.repositoryRoot, join(directory, name))) conflict("Encode evidence is outside its exact derivative directory.");
206
+ artifact = encoded.artifact;
207
+ const video = await load(artifact, Math.min(ASSET_BYTES, request.limits.maximumOutputBytes));
208
+ if (video.length < 12 || new TextDecoder().decode(video.subarray(4, 8)) !== "ftyp") unsupported("Encoded video must be self-contained ISO-BMFF MP4 or QuickTime.");
209
+ const text = async (ref: MediaArtifactReference) => new TextDecoder("utf-8", { fatal: true }).decode(await load(ref, 4_194_304));
210
+ const firstHash = verifyStudioFramehash(await text(encoded.verification.sourceFramehash), render, alpha);
211
+ if (firstHash !== encoded.verification.canonicalFrameSha256 || firstHash !== verifyStudioFramehash(await text(encoded.verification.videoFramehash), render, alpha)
212
+ || encoded.verification.frameCount !== frames.length) conflict("Encoded pixel evidence differs from the retained native sequence.");
213
+ const stream = encodedProbeSchema.parse(await json(encoded.verification.probe)).streams[0]!;
214
+ const rate = /^([1-9]\d*)\/([1-9]\d*)$/u.exec(stream.avg_frame_rate), base = /^([1-9]\d*)\/([1-9]\d*)$/u.exec(stream.time_base);
215
+ const matchesColor = alpha
216
+ ? (stream.color_transfer === undefined || ["unknown", "iec61966-2-1"].includes(stream.color_transfer))
217
+ && (stream.color_primaries === undefined || ["unknown", "bt709"].includes(stream.color_primaries))
218
+ && (stream.color_space === undefined || ["unknown", "gbr"].includes(stream.color_space))
219
+ && (stream.color_range === undefined || ["unknown", "pc"].includes(stream.color_range))
220
+ : stream.color_range === "pc" && stream.color_space === "gbr" && stream.color_transfer === "iec61966-2-1" && stream.color_primaries === "bt709";
221
+ if (rate === null || base === null || stream.width !== render.width || stream.height !== render.height || stream.codec_name !== (alpha ? "qtrle" : "h264") || stream.pix_fmt !== (alpha ? "argb" : "gbrp")
222
+ || !matchesColor || stream.nb_read_frames !== String(frames.length) || BigInt(rate[1]!) * BigInt(render.frameRate.denominator) !== BigInt(rate[2]!) * BigInt(render.frameRate.numerator)
223
+ || BigInt(stream.duration_ts) * BigInt(base[1]!) * BigInt(render.frameRate.numerator) !== BigInt(frames.length) * BigInt(render.frameRate.denominator) * BigInt(base[2]!)) conflict("Encoded probe evidence differs from the source's exact video clock and pixel profile.");
224
+ const n = BigInt(frames.length) * BigInt(render.frameRate.denominator) * 1_000_000n, d = BigInt(render.frameRate.numerator);
225
+ interpretation = { kind: "video", width: render.width, height: render.height, colorSpace: "srgb", alpha: alpha ? "straight" : "opaque", durationUs: Number((2n * n + d) / (2n * d)), frameRate: render.frameRate };
226
+ compatibility = "slopcamera.spatial-studio-rgb-video-v1";
227
+ }
228
+ const document = StudioSpatialAssetReceiptSchema.parse({ kind: "slopcamera.studio-spatial-asset-receipt", schemaVersion: 1, selection, assetId,
229
+ nativeReceipt: native.receipt, planSha256: plan.planSha256, bundleSha256: plan.bundleSha256, nativeOutputsSha256: hash(selected),
230
+ ...(encodeReceipt === undefined ? {} : { encodeReceipt }), artifact, payload: { path: `studio/${artifact.sha256}.${extension}`, sha256: artifact.sha256, bytes: artifact.bytes }, interpretation, compatibility });
231
+ const verify = async () => {
232
+ await fence();
233
+ if (studioJson(StudioRunOutputSchema.parse(await input.service.inspect(selection.jobId))) !== studioJson(native)
234
+ || studioJson(parseStudioPlan(JSON.parse(await jobFs.readText("plan.json", DOCUMENT_BYTES)) as unknown)) !== studioJson(plan)) conflict("Native source provenance changed during asset admission.");
235
+ for (const reference of evidence) await bindRepositoryMedia(application, reference, signal, Math.max(ASSET_BYTES, DOCUMENT_BYTES));
236
+ };
237
+ await verify();
238
+ const directory = await ensurePhysicalPrivateDirectoryWithin(root, `assets/${hash(document)}`), fs = createNodeBundleFileSystem(directory), serialized = studioJson(document);
239
+ const disposition = await fs.writeTextNoReplace!("receipt.json", serialized, verify);
240
+ if (disposition !== "created" && await fs.readText("receipt.json", DOCUMENT_BYTES) !== serialized) conflict("Retained scene asset admission receipt conflicts with its immutable identity.");
241
+ await verify();
242
+ const receipt = MediaArtifactReferenceSchema.parse({ path: relative(application.paths.repositoryRoot, join(directory, "receipt.json")), ...await fs.inspectFile!("receipt.json", DOCUMENT_BYTES) });
243
+ if (receipt.sha256 !== studioBytesSha256(serialized) || receipt.bytes !== Buffer.byteLength(serialized)) conflict("Retained admission receipt changed before completion.");
244
+ await fence();
245
+ const asset = SpatialAssetManifestSchema.parse({ assetId, payload: document.payload, interpretation: document.interpretation, dependencies: [],
246
+ provenance: { source: selection.representation === "encoded-video" ? "derived" : "generated", description: `Studio ${selection.jobId}/${selection.outputId}${selection.frame === undefined ? "" : ` frame ${selection.frame}`}; ${compatibility}`, receiptSha256: receipt.sha256 } });
247
+ return { asset, binding: { assetId, artifact }, receipt, document };
248
+ }
@@ -0,0 +1,3 @@
1
+ /** Keep CLI parsing independent from embedded native source and runtime imports. */
2
+ export const STUDIO_TEMPLATES = ["blender-product", "blender-character", "blender-shaded-street", "blender-cloth", "blender-fluid", "cadquery-bracket", "manim-lesson"] as const;
3
+ export type StudioTemplate = typeof STUDIO_TEMPLATES[number];
@@ -0,0 +1,19 @@
1
+ import { resolve } from "node:path";
2
+ import type { ApplicationContext } from "../application/context";
3
+ import type { StudioWorkflowOptions } from "./args";
4
+ import { createStudioService } from "./studio-service";
5
+
6
+ /** An invocation-scoped host envelope is never serialized into the authored graph or a reusable grant. */
7
+ export function withStudioWorkflowApplication(application: ApplicationContext, options: StudioWorkflowOptions): ApplicationContext {
8
+ const selected = options.studio;
9
+ if (selected === undefined) return application;
10
+ const service = createStudioService({ application, selection: {
11
+ threads: 1,
12
+ ...(selected.python === undefined ? {} : { python: resolve(application.paths.repositoryRoot, selected.python) }),
13
+ ...(selected.blender === undefined ? {} : { blender: resolve(application.paths.repositoryRoot, selected.blender) }),
14
+ } });
15
+ return { ...application, studioPort: service.port,
16
+ ...(selected.allowTrustedCode ? { studioAuthorization: { authorize: async request => /^studio_[a-zA-Z0-9][a-zA-Z0-9_-]{0,120}$/u.test(request.jobId)
17
+ && /^[a-f0-9]{64}$/u.test(request.planSha256) && /^[a-f0-9]{64}$/u.test(request.bundleSha256) } } : {}),
18
+ };
19
+ }
@@ -0,0 +1,25 @@
1
+ import { parseTimeLiteral } from "../core";
2
+ import { CliError } from "./errors";
3
+
4
+ export function parseCliTime(value: string, fps?: number): number {
5
+ const frames = /^([0-9]+)f$/u.exec(value.trim());
6
+ if (frames !== null) {
7
+ if (fps === undefined) {
8
+ throw new CliError("usage", `Frame time ${value} requires --fps.`);
9
+ }
10
+ if (!Number.isFinite(fps) || fps <= 0 || fps > 1_000) {
11
+ throw new CliError("usage", "--fps must be a finite number greater than 0 and at most 1000.");
12
+ }
13
+ const frame = Number(frames[1]);
14
+ const microseconds = Math.round(frame * 1_000_000 / fps);
15
+ if (!Number.isSafeInteger(frame) || !Number.isSafeInteger(microseconds)) {
16
+ throw new CliError("usage", `Frame time is outside the safe range: ${value}`);
17
+ }
18
+ return microseconds;
19
+ }
20
+ try {
21
+ return parseTimeLiteral(value);
22
+ } catch (error) {
23
+ throw new CliError("usage", error instanceof Error ? error.message : String(error));
24
+ }
25
+ }