@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,802 @@
1
+ import { createHash } from "node:crypto";
2
+ import { constants } from "node:fs";
3
+ import { mkdtemp, open, rm } from "node:fs/promises";
4
+ import { join, relative } from "node:path";
5
+
6
+ import { z } from "zod";
7
+
8
+ import {
9
+ OverlayOperationSchema,
10
+ RepositoryRelativePathSchema,
11
+ Sha256Schema,
12
+ SourceIntervalSchema,
13
+ type OverlayOperation,
14
+ } from "../../../contracts";
15
+ import {
16
+ buildProjectOutputTimeMap,
17
+ canonicalJsonSha256,
18
+ mapProjectIntervalToOutputSlices,
19
+ } from "../../../core";
20
+ import {
21
+ HtmlOverlayAuthoringInputSchema,
22
+ HtmlOverlayCanvasSchema,
23
+ HtmlOverlayDeclaredResourceSchema,
24
+ HtmlOverlayDeclaredResourcesSchema,
25
+ HtmlOverlayInlineDocumentSchema,
26
+ HtmlOverlayActiveLibraryLocksSchema,
27
+ HtmlOverlayLibraryLocksSchema,
28
+ HtmlOverlayLibrarySelectionSchema,
29
+ HtmlOverlayParametersSchema,
30
+ HtmlOverlayTimingSchema,
31
+ getApprovedHtmlOverlayLibraryLock,
32
+ htmlOverlayFrameCount,
33
+ type HtmlOverlayAuthoringInput,
34
+ } from "../../../html-overlay";
35
+ import { probeVisualMediaSummary } from "../../../cli/analyzer";
36
+ import { ingestGeneratedVideoOverlayAsset } from "../../../cli/asset-ingest";
37
+ import { resolveAnimatedPlaybackWindow } from "../../../cli/overlay-playback";
38
+ import type { ApplicationContext } from "../../context";
39
+ import { exactCapabilityByName } from "../../capability-binding";
40
+ import { ApplicationError } from "../../errors";
41
+ import { GatewayOutputArtifactReferenceSchema } from "../../gateway-port";
42
+ import { bindHtmlOverlayBrowserRuntime } from "../../html-overlay-browser-runtime";
43
+ import {
44
+ HtmlOverlayExecutionIntegritySchema,
45
+ createHtmlOverlayExecutionBundle,
46
+ } from "../../html-overlay-integrity";
47
+ import {
48
+ SLOPCAMERA_APPLICATION_TOOL_VERSION,
49
+ type OperationDefinition,
50
+ } from "../../operation";
51
+ import { writeOperationCompletionCheckpoint } from "../../operation-completion-checkpoint";
52
+ import { openLeasedProjectSnapshot } from "../../project-publication-lease";
53
+ import { assertProjectGeneration } from "../../project-store";
54
+ import { ProjectReferenceSchema, throwIfAborted } from "../shared";
55
+ import {
56
+ MediaCapabilityBindingsSchema,
57
+ assertMediaCapabilities,
58
+ bindExpectedMediaCapabilities,
59
+ bindMediaCapabilities,
60
+ mediaCapabilityCommand,
61
+ mediaCapabilityRunner,
62
+ mediaCapabilityVersion,
63
+ } from "./capabilities";
64
+ import {
65
+ MediaArtifactReferenceSchema,
66
+ MediaArtifactRequestSchema,
67
+ AbortBoundApplicationRunner,
68
+ bindRepositoryMedia,
69
+ createMediaOperationWorkspace,
70
+ loadRepositoryMedia,
71
+ publishContentAddressedReceipt,
72
+ } from "./shared";
73
+ import {
74
+ MediaOverlayLayoutSchema,
75
+ MediaOverlayOutputSchema,
76
+ type MediaOverlayOutput,
77
+ } from "./overlay";
78
+
79
+ export const MAXIMUM_HTML_OVERLAY_DOCUMENT_BYTES = 2 * 1024 * 1024;
80
+ export const MAXIMUM_HTML_OVERLAY_RESOURCE_BYTES = 128 * 1024 * 1024;
81
+ export const MAXIMUM_HTML_OVERLAY_OUTPUT_BYTES = 512 * 1024 * 1024;
82
+ const HTML_OVERLAY_CAPABILITIES = [
83
+ "ffmpeg",
84
+ "ffprobe",
85
+ "html-browser",
86
+ ] as const;
87
+
88
+ const HtmlOverlayDocumentRequestSchema = z.union([
89
+ HtmlOverlayInlineDocumentSchema,
90
+ z.strictObject({ path: RepositoryRelativePathSchema }),
91
+ MediaArtifactReferenceSchema,
92
+ ]);
93
+
94
+ const BoundHtmlOverlayDocumentSchema = z.union([
95
+ HtmlOverlayInlineDocumentSchema,
96
+ MediaArtifactReferenceSchema,
97
+ ]);
98
+
99
+ const HtmlOverlayResourceArtifactRequestSchema = z.union([
100
+ MediaArtifactRequestSchema,
101
+ GatewayOutputArtifactReferenceSchema,
102
+ ]);
103
+
104
+ const HtmlOverlayResourceRequestSchema = HtmlOverlayDeclaredResourceSchema
105
+ .omit({ bytes: true, sha256: true })
106
+ .extend({ artifact: HtmlOverlayResourceArtifactRequestSchema })
107
+ .strict();
108
+
109
+ const BoundHtmlOverlayResourceRequestSchema =
110
+ HtmlOverlayDeclaredResourceSchema
111
+ .extend({ artifact: MediaArtifactReferenceSchema })
112
+ .strict();
113
+
114
+ export const HtmlOverlayInputSchema = z.strictObject({
115
+ canvas: HtmlOverlayCanvasSchema,
116
+ capabilityBindings: MediaCapabilityBindingsSchema.optional(),
117
+ document: HtmlOverlayDocumentRequestSchema,
118
+ identityKey: z.string().min(1).max(128).optional(),
119
+ layout: MediaOverlayLayoutSchema,
120
+ libraries: HtmlOverlayLibrarySelectionSchema.default([]),
121
+ parameters: HtmlOverlayParametersSchema.default({}),
122
+ project: ProjectReferenceSchema,
123
+ range: SourceIntervalSchema,
124
+ resources: z.array(HtmlOverlayResourceRequestSchema).max(64).default([]),
125
+ seed: z.number().int().min(0).max(0xffff_ffff).default(0),
126
+ timing: HtmlOverlayTimingSchema,
127
+ });
128
+
129
+ export const BoundHtmlOverlayInputSchema = HtmlOverlayInputSchema
130
+ .omit({ document: true, resources: true })
131
+ .extend({
132
+ document: BoundHtmlOverlayDocumentSchema,
133
+ resources: z.array(BoundHtmlOverlayResourceRequestSchema).max(64),
134
+ })
135
+ .strict();
136
+
137
+ export const HtmlOverlayReceiptSchema = z.strictObject({
138
+ artifact: MediaArtifactReferenceSchema,
139
+ browserVersion: z.string().min(1).max(512),
140
+ createdAt: z.string().datetime({ offset: true }),
141
+ // Optional only so persisted v1 Slopcamera receipts remain readable after the
142
+ // product rename. Every new Slopcamera render publishes this evidence.
143
+ executionIntegrity: HtmlOverlayExecutionIntegritySchema.optional(),
144
+ exactInputSha256: Sha256Schema,
145
+ ffmpegVersion: z.string().min(1).max(512),
146
+ ffprobeVersion: z.string().min(1).max(512),
147
+ frameCount: z.number().int().safe().positive(),
148
+ kind: z.union([
149
+ z.literal("slopcamera.html-overlay-preparation-receipt"),
150
+ z.literal("studio.html-overlay-preparation-receipt"),
151
+ ]),
152
+ libraryLocks: HtmlOverlayLibraryLocksSchema,
153
+ libraryLocksSha256: Sha256Schema,
154
+ operationSha256: Sha256Schema,
155
+ overlayId: z.string().min(1).max(128),
156
+ projectGenerationSha256: Sha256Schema,
157
+ projectId: ProjectReferenceSchema,
158
+ schemaVersion: z.literal(1),
159
+ });
160
+
161
+ export const HtmlOverlayOutputSchema = MediaOverlayOutputSchema;
162
+
163
+ export type HtmlOverlayInput = z.infer<typeof HtmlOverlayInputSchema>;
164
+ export type HtmlOverlayInputRequest = z.input<typeof HtmlOverlayInputSchema>;
165
+ export type BoundHtmlOverlayInput = z.infer<typeof BoundHtmlOverlayInputSchema>;
166
+ export type HtmlOverlayOutput = MediaOverlayOutput;
167
+
168
+ export interface HtmlOverlayOperationDependencies {
169
+ readonly bindBrowserRuntime?: typeof bindHtmlOverlayBrowserRuntime;
170
+ readonly ingest?: typeof ingestGeneratedVideoOverlayAsset;
171
+ readonly probe?: typeof probeVisualMediaSummary;
172
+ readonly toolVersion?: string;
173
+ }
174
+
175
+ function normalizeHtmlOverlayResourceArtifact(
176
+ resource: z.infer<typeof HtmlOverlayResourceRequestSchema>,
177
+ ): z.infer<typeof MediaArtifactRequestSchema> {
178
+ if (!("mediaType" in resource.artifact)) return resource.artifact;
179
+ if (resource.artifact.mediaType !== resource.mediaType) {
180
+ throw new ApplicationError(
181
+ "invalid-data",
182
+ `HTML overlay resource ${resource.name} declares ${resource.mediaType} but its generated artifact is ${resource.artifact.mediaType}.`,
183
+ );
184
+ }
185
+ return MediaArtifactReferenceSchema.parse({
186
+ bytes: resource.artifact.bytes,
187
+ path: resource.artifact.path,
188
+ sha256: resource.artifact.sha256,
189
+ });
190
+ }
191
+
192
+ async function bindHtmlOverlayDocument(
193
+ application: ApplicationContext,
194
+ document: z.infer<typeof HtmlOverlayDocumentRequestSchema>,
195
+ signal: AbortSignal,
196
+ ): Promise<z.infer<typeof BoundHtmlOverlayDocumentSchema>> {
197
+ if ("html" in document) return document;
198
+ return (
199
+ await bindRepositoryMedia(
200
+ application,
201
+ document,
202
+ signal,
203
+ MAXIMUM_HTML_OVERLAY_DOCUMENT_BYTES,
204
+ )
205
+ ).artifact;
206
+ }
207
+
208
+ function visibleOutputDurationUs(
209
+ plan: Parameters<typeof buildProjectOutputTimeMap>[0],
210
+ range: z.infer<typeof SourceIntervalSchema>,
211
+ ): number {
212
+ return mapProjectIntervalToOutputSlices(
213
+ buildProjectOutputTimeMap(plan),
214
+ range,
215
+ ).reduce(
216
+ (total, slice) => total + slice.output.endUs - slice.output.startUs,
217
+ 0,
218
+ );
219
+ }
220
+
221
+ export async function bindHtmlOverlayInput(
222
+ application: ApplicationContext,
223
+ input: unknown,
224
+ signal: AbortSignal,
225
+ ): Promise<BoundHtmlOverlayInput> {
226
+ const parsed = HtmlOverlayInputSchema.parse(input);
227
+ const [document, resources, capabilityBindings] = await Promise.all([
228
+ bindHtmlOverlayDocument(
229
+ application,
230
+ parsed.document,
231
+ signal,
232
+ ),
233
+ Promise.all(parsed.resources.map(async resource => ({
234
+ ...resource,
235
+ artifact: (
236
+ await bindRepositoryMedia(
237
+ application,
238
+ normalizeHtmlOverlayResourceArtifact(resource),
239
+ signal,
240
+ MAXIMUM_HTML_OVERLAY_RESOURCE_BYTES,
241
+ )
242
+ ).artifact,
243
+ }))),
244
+ bindExpectedMediaCapabilities(
245
+ application,
246
+ HTML_OVERLAY_CAPABILITIES,
247
+ parsed.capabilityBindings,
248
+ ),
249
+ ]);
250
+ const exactResources = HtmlOverlayDeclaredResourcesSchema.parse(
251
+ resources.map(({ artifact, ...resource }) => ({
252
+ ...resource,
253
+ bytes: artifact.bytes,
254
+ sha256: artifact.sha256,
255
+ })),
256
+ );
257
+ const artifactByResourceName = new Map(
258
+ resources.map(resource => [resource.name, resource.artifact] as const),
259
+ );
260
+ return BoundHtmlOverlayInputSchema.parse({
261
+ ...parsed,
262
+ capabilityBindings,
263
+ document,
264
+ resources: exactResources.map(resource => ({
265
+ ...resource,
266
+ artifact: artifactByResourceName.get(resource.name),
267
+ })),
268
+ });
269
+ }
270
+
271
+ function decodeHtml(bytes: Uint8Array): string {
272
+ let html: string;
273
+ try {
274
+ html = new TextDecoder("utf-8", { fatal: true }).decode(bytes);
275
+ } catch {
276
+ throw new ApplicationError(
277
+ "invalid-data",
278
+ "The HTML overlay document must be valid UTF-8.",
279
+ );
280
+ }
281
+ if (html.trim() === "") {
282
+ throw new ApplicationError("invalid-data", "The HTML overlay document is empty.");
283
+ }
284
+ return html;
285
+ }
286
+
287
+ async function sha256PhysicalFile(
288
+ path: string,
289
+ signal: AbortSignal,
290
+ ): Promise<string> {
291
+ const handle = await open(
292
+ path,
293
+ constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0),
294
+ );
295
+ try {
296
+ const before = await handle.stat();
297
+ if (!before.isFile() || before.size <= 0) {
298
+ throw new ApplicationError("invalid-data", "Rendered HTML overlay is empty.");
299
+ }
300
+ const hash = createHash("sha256");
301
+ const buffer = Buffer.allocUnsafe(1024 * 1024);
302
+ let offset = 0;
303
+ while (offset < before.size) {
304
+ throwIfAborted(signal);
305
+ const result = await handle.read(
306
+ buffer,
307
+ 0,
308
+ Math.min(buffer.byteLength, before.size - offset),
309
+ offset,
310
+ );
311
+ if (result.bytesRead === 0) break;
312
+ hash.update(buffer.subarray(0, result.bytesRead));
313
+ offset += result.bytesRead;
314
+ }
315
+ const after = await handle.stat();
316
+ if (
317
+ offset !== before.size
318
+ || after.dev !== before.dev
319
+ || after.ino !== before.ino
320
+ || after.size !== before.size
321
+ || after.mtimeMs !== before.mtimeMs
322
+ || after.ctimeMs !== before.ctimeMs
323
+ ) {
324
+ throw new ApplicationError(
325
+ "conflict",
326
+ "Rendered HTML overlay changed while it was being verified.",
327
+ );
328
+ }
329
+ return hash.digest("hex");
330
+ } finally {
331
+ await handle.close();
332
+ }
333
+ }
334
+
335
+ const AlphaVideoProbeSchema = z.object({
336
+ streams: z.array(z.object({
337
+ codec_name: z.string(),
338
+ height: z.number().int().positive(),
339
+ pix_fmt: z.string(),
340
+ width: z.number().int().positive(),
341
+ })).min(1),
342
+ });
343
+
344
+ async function assertAlphaVideo(
345
+ application: ApplicationContext,
346
+ bindings: NonNullable<BoundHtmlOverlayInput["capabilityBindings"]>,
347
+ path: string,
348
+ canvas: BoundHtmlOverlayInput["canvas"],
349
+ signal: AbortSignal,
350
+ ): Promise<void> {
351
+ const result = await new AbortBoundApplicationRunner(
352
+ mediaCapabilityRunner(application, bindings),
353
+ signal,
354
+ ).run([
355
+ mediaCapabilityCommand(bindings, "ffprobe"),
356
+ "-v",
357
+ "error",
358
+ "-select_streams",
359
+ "v:0",
360
+ "-show_entries",
361
+ "stream=codec_name,pix_fmt,width,height",
362
+ "-of",
363
+ "json",
364
+ path,
365
+ ], {
366
+ maxOutputBytes: 64 * 1024,
367
+ stdin: "ignore",
368
+ timeoutMs: 30_000,
369
+ });
370
+ if (result.exitCode !== 0) {
371
+ throw new ApplicationError(
372
+ "invalid-data",
373
+ "Rendered HTML overlay could not be inspected as an alpha video.",
374
+ );
375
+ }
376
+ let unknown: unknown;
377
+ try {
378
+ unknown = JSON.parse(result.stdout);
379
+ } catch {
380
+ throw new ApplicationError(
381
+ "invalid-data",
382
+ "Rendered HTML overlay inspection returned invalid JSON.",
383
+ );
384
+ }
385
+ const stream = AlphaVideoProbeSchema.parse(unknown).streams[0]!;
386
+ if (
387
+ stream.codec_name !== "qtrle"
388
+ || stream.pix_fmt !== "argb"
389
+ || stream.width !== canvas.width
390
+ || stream.height !== canvas.height
391
+ ) {
392
+ throw new ApplicationError(
393
+ "invalid-data",
394
+ "Rendered HTML overlay must be a canvas-sized qtrle/argb alpha video.",
395
+ { stream },
396
+ );
397
+ }
398
+ }
399
+
400
+ function overlayOperationId(
401
+ input: BoundHtmlOverlayInput,
402
+ authoring: HtmlOverlayAuthoringInput,
403
+ assetSha256: string,
404
+ ): string {
405
+ return `overlay_${canonicalJsonSha256({
406
+ assetSha256,
407
+ authoring,
408
+ domain: "studio.media-html-overlay-operation/v1",
409
+ identityKey: input.identityKey ?? null,
410
+ layout: input.layout,
411
+ project: input.project,
412
+ range: input.range,
413
+ }).slice(0, 32)}`;
414
+ }
415
+
416
+ export function createHtmlOverlayOperationDefinition(
417
+ dependencies: HtmlOverlayOperationDependencies = {},
418
+ ): OperationDefinition<"media.html-overlay", HtmlOverlayInput, HtmlOverlayOutput> {
419
+ const ingest = dependencies.ingest ?? ingestGeneratedVideoOverlayAsset;
420
+ const probe = dependencies.probe ?? probeVisualMediaSummary;
421
+ const bindBrowserRuntime = dependencies.bindBrowserRuntime
422
+ ?? bindHtmlOverlayBrowserRuntime;
423
+ const toolVersion = dependencies.toolVersion ?? SLOPCAMERA_APPLICATION_TOOL_VERSION;
424
+ return {
425
+ inputSchema: HtmlOverlayInputSchema,
426
+ inputSchemaId: "slopcamera.operation.media.html-overlay.input/v1",
427
+ kind: "media.html-overlay",
428
+ lifecycle: {
429
+ kind: "local-artifact",
430
+ execute: async (context, input) => {
431
+ throwIfAborted(context.abortSignal);
432
+ const boundInput = await bindHtmlOverlayInput(
433
+ context.application,
434
+ input,
435
+ context.abortSignal,
436
+ );
437
+ await assertMediaCapabilities(
438
+ context,
439
+ context.application,
440
+ boundInput.capabilityBindings,
441
+ HTML_OVERLAY_CAPABILITIES,
442
+ );
443
+ const bindings = boundInput.capabilityBindings
444
+ ?? await bindMediaCapabilities(
445
+ context.application,
446
+ HTML_OVERLAY_CAPABILITIES,
447
+ );
448
+ const renderer = context.application.htmlOverlayRenderer;
449
+ if (renderer === undefined) {
450
+ throw new ApplicationError(
451
+ "unavailable",
452
+ "This Slopcamera host does not provide an HTML-overlay browser renderer.",
453
+ );
454
+ }
455
+ const snapshot = await openLeasedProjectSnapshot(
456
+ context.application,
457
+ boundInput.project,
458
+ );
459
+ assertProjectGeneration(
460
+ context.expectedProjectGeneration,
461
+ snapshot.generation,
462
+ );
463
+ if (boundInput.range.endUs > snapshot.plan.timelineDurationUs) {
464
+ throw new ApplicationError(
465
+ "usage",
466
+ "HTML overlay range exceeds the project timeline.",
467
+ );
468
+ }
469
+ const outputDurationUs = visibleOutputDurationUs(
470
+ snapshot.plan,
471
+ boundInput.range,
472
+ );
473
+ if (outputDurationUs <= 0) {
474
+ throw new ApplicationError(
475
+ "conflict",
476
+ "HTML overlay range has no visible kept output time.",
477
+ );
478
+ }
479
+ if (boundInput.timing.durationUs !== outputDurationUs) {
480
+ throw new ApplicationError(
481
+ "conflict",
482
+ "HTML overlay timing duration must equal the range's visible output duration.",
483
+ {
484
+ actualDurationUs: boundInput.timing.durationUs,
485
+ expectedDurationUs: outputDurationUs,
486
+ },
487
+ );
488
+ }
489
+ const [html, resources] = await Promise.all([
490
+ "html" in boundInput.document
491
+ ? Promise.resolve(boundInput.document.html)
492
+ : loadRepositoryMedia(
493
+ context.application,
494
+ boundInput.document,
495
+ context.abortSignal,
496
+ MAXIMUM_HTML_OVERLAY_DOCUMENT_BYTES,
497
+ ).then(document => decodeHtml(document.data)),
498
+ Promise.all(boundInput.resources.map(async resource => ({
499
+ ...resource,
500
+ absolutePath: (
501
+ await bindRepositoryMedia(
502
+ context.application,
503
+ resource.artifact,
504
+ context.abortSignal,
505
+ MAXIMUM_HTML_OVERLAY_RESOURCE_BYTES,
506
+ )
507
+ ).absolutePath,
508
+ }))),
509
+ ]);
510
+ const authoring = HtmlOverlayAuthoringInputSchema.parse({
511
+ canvas: boundInput.canvas,
512
+ html,
513
+ kind: "slopcamera.html-overlay",
514
+ libraries: boundInput.libraries,
515
+ parameters: boundInput.parameters,
516
+ resources: resources.map(resource => ({
517
+ bytes: resource.bytes,
518
+ mediaType: resource.mediaType,
519
+ name: resource.name,
520
+ sha256: resource.sha256,
521
+ ...(resource.transport === undefined ? {} : { transport: resource.transport }),
522
+ urlPath: resource.urlPath,
523
+ })),
524
+ schemaVersion: 1,
525
+ seed: boundInput.seed,
526
+ timing: boundInput.timing,
527
+ });
528
+ const workspace = await createMediaOperationWorkspace(context);
529
+ const renderDirectory = await mkdtemp(join(workspace.path, "html-overlay-"));
530
+ try {
531
+ const browserRuntime = await bindBrowserRuntime(
532
+ exactCapabilityByName(bindings, "html-browser"),
533
+ context.abortSignal,
534
+ );
535
+ const expectedExecutionIntegrity = createHtmlOverlayExecutionBundle(
536
+ authoring,
537
+ browserRuntime,
538
+ ).integrity;
539
+ const rendered = await renderer.renderFrames({
540
+ authoring,
541
+ browserRuntime,
542
+ outputDirectory: renderDirectory,
543
+ resources,
544
+ }, context.abortSignal);
545
+ const executionIntegrity = HtmlOverlayExecutionIntegritySchema.parse(
546
+ rendered.executionIntegrity,
547
+ );
548
+ if (
549
+ canonicalJsonSha256(executionIntegrity)
550
+ !== canonicalJsonSha256(expectedExecutionIntegrity)
551
+ ) {
552
+ throw new ApplicationError(
553
+ "conflict",
554
+ "HTML-overlay renderer returned integrity evidence that does not match the planned browser execution.",
555
+ );
556
+ }
557
+ const libraryLocks = HtmlOverlayActiveLibraryLocksSchema.parse(
558
+ rendered.libraryLocks,
559
+ );
560
+ const expectedLibraryLocks = authoring.libraries.map(
561
+ getApprovedHtmlOverlayLibraryLock,
562
+ );
563
+ if (
564
+ canonicalJsonSha256(libraryLocks)
565
+ !== canonicalJsonSha256(expectedLibraryLocks)
566
+ ) {
567
+ throw new ApplicationError(
568
+ "conflict",
569
+ "HTML-overlay renderer returned library locks that do not exactly match the authoring selection.",
570
+ );
571
+ }
572
+ const expectedFrames = htmlOverlayFrameCount(authoring.timing);
573
+ if (rendered.frameCount !== expectedFrames) {
574
+ throw new ApplicationError(
575
+ "conflict",
576
+ "HTML-overlay renderer returned an unexpected frame count.",
577
+ );
578
+ }
579
+ const outputPath = join(renderDirectory, "overlay.mov");
580
+ const ffmpegCommand = [
581
+ mediaCapabilityCommand(bindings, "ffmpeg"),
582
+ "-hide_banner",
583
+ "-loglevel",
584
+ "error",
585
+ "-nostdin",
586
+ "-n",
587
+ "-framerate",
588
+ String(authoring.timing.fps),
589
+ "-start_number",
590
+ "0",
591
+ "-i",
592
+ rendered.framePattern,
593
+ "-frames:v",
594
+ String(rendered.frameCount),
595
+ "-an",
596
+ "-c:v",
597
+ "qtrle",
598
+ "-pix_fmt",
599
+ "argb",
600
+ "-movflags",
601
+ "+faststart",
602
+ outputPath,
603
+ ] as const;
604
+ const encode = await new AbortBoundApplicationRunner(
605
+ mediaCapabilityRunner(context.application, bindings),
606
+ context.abortSignal,
607
+ ).run(ffmpegCommand, {
608
+ cwd: renderDirectory,
609
+ maxOutputBytes: 1024 * 1024,
610
+ stdin: "ignore",
611
+ timeoutMs: 60 * 60_000,
612
+ });
613
+ if (encode.exitCode !== 0) {
614
+ throw new ApplicationError(
615
+ "invalid-data",
616
+ `FFmpeg could not encode the HTML overlay: ${encode.stderr.slice(0, 2_000)}`,
617
+ );
618
+ }
619
+ await assertAlphaVideo(
620
+ context.application,
621
+ bindings,
622
+ outputPath,
623
+ authoring.canvas,
624
+ context.abortSignal,
625
+ );
626
+ const sourceSha256 = await sha256PhysicalFile(
627
+ outputPath,
628
+ context.abortSignal,
629
+ );
630
+ await context.workflow?.beforePublication();
631
+ throwIfAborted(context.abortSignal);
632
+ const ingested = await ingest(
633
+ snapshot.openProject.directory.path,
634
+ {
635
+ command: ffmpegCommand,
636
+ generator: "slopcamera-html-overlay",
637
+ generatorVersion: toolVersion,
638
+ path: outputPath,
639
+ sourceSha256,
640
+ },
641
+ );
642
+ const assetPath = join(
643
+ snapshot.openProject.directory.path,
644
+ ingested.path,
645
+ );
646
+ const artifact = (
647
+ await bindRepositoryMedia(
648
+ context.application,
649
+ {
650
+ path: relative(
651
+ context.application.paths.repositoryRoot,
652
+ assetPath,
653
+ ),
654
+ },
655
+ context.abortSignal,
656
+ MAXIMUM_HTML_OVERLAY_OUTPUT_BYTES,
657
+ )
658
+ ).artifact;
659
+ const visual = await probe(
660
+ mediaCapabilityCommand(bindings, "ffprobe"),
661
+ new AbortBoundApplicationRunner(
662
+ mediaCapabilityRunner(context.application, bindings),
663
+ context.abortSignal,
664
+ ),
665
+ assetPath,
666
+ );
667
+ if (
668
+ visual.durationUs === null
669
+ || visual.durationUs <= 0
670
+ || visual.hasAudio
671
+ || visual.pixelWidth !== authoring.canvas.width
672
+ || visual.pixelHeight !== authoring.canvas.height
673
+ ) {
674
+ throw new ApplicationError(
675
+ "invalid-data",
676
+ "Generated HTML overlay has invalid duration, dimensions, or audio streams.",
677
+ );
678
+ }
679
+ const playbackWindow = resolveAnimatedPlaybackWindow({
680
+ mediaDurationUs: visual.durationUs,
681
+ outputDurationUs,
682
+ playbackRate: 1,
683
+ sourceInUs: 0,
684
+ sourceOutUs: undefined,
685
+ });
686
+ const source = {
687
+ asset: {
688
+ bytes: ingested.bytes,
689
+ mediaType: ingested.mediaType,
690
+ path: ingested.path,
691
+ provenance: ingested.provenance,
692
+ sha256: ingested.sha256,
693
+ },
694
+ audioPolicy: { kind: "mute" as const },
695
+ kind: "video" as const,
696
+ playback: {
697
+ audioEndUs: null,
698
+ audioStartUs: 0,
699
+ audioStreamIndex: null,
700
+ endBehavior: "hide" as const,
701
+ playbackRate: 1,
702
+ streamStartUs: visual.videoStartUs,
703
+ videoStreamIndex: visual.videoStreamIndex,
704
+ ...playbackWindow,
705
+ },
706
+ };
707
+ const operation = OverlayOperationSchema.parse({
708
+ ...boundInput.layout,
709
+ coordinateSpace: "output-pixels",
710
+ intrinsicSize: {
711
+ height: authoring.canvas.height,
712
+ width: authoring.canvas.width,
713
+ },
714
+ overlayId: overlayOperationId(
715
+ boundInput,
716
+ authoring,
717
+ artifact.sha256,
718
+ ),
719
+ range: boundInput.range,
720
+ source,
721
+ }) satisfies OverlayOperation;
722
+ const receiptBody = HtmlOverlayReceiptSchema.parse({
723
+ artifact,
724
+ browserVersion: mediaCapabilityVersion(bindings, "html-browser"),
725
+ createdAt: context.application.clock.now().toISOString(),
726
+ executionIntegrity,
727
+ exactInputSha256: canonicalJsonSha256(boundInput),
728
+ ffmpegVersion: mediaCapabilityVersion(bindings, "ffmpeg"),
729
+ ffprobeVersion: mediaCapabilityVersion(bindings, "ffprobe"),
730
+ frameCount: rendered.frameCount,
731
+ kind: "slopcamera.html-overlay-preparation-receipt",
732
+ libraryLocks,
733
+ libraryLocksSha256: canonicalJsonSha256(libraryLocks),
734
+ operationSha256: canonicalJsonSha256(operation),
735
+ overlayId: operation.overlayId,
736
+ projectGenerationSha256: snapshot.generation.generationSha256,
737
+ projectId: snapshot.project.projectId,
738
+ schemaVersion: 1,
739
+ });
740
+ const receipt = await publishContentAddressedReceipt({
741
+ context,
742
+ receipt: receiptBody,
743
+ workspace,
744
+ });
745
+ const output = MediaOverlayOutputSchema.parse({
746
+ artifact,
747
+ created: ingested.created,
748
+ operation,
749
+ receipt,
750
+ });
751
+ await writeOperationCompletionCheckpoint(context, {
752
+ inputSchemaId: "slopcamera.operation.media.html-overlay.input/v1",
753
+ kind: "media.html-overlay",
754
+ outputSchemaId: "slopcamera.operation.media.html-overlay.output/v1",
755
+ version: 1,
756
+ }, output);
757
+ return output;
758
+ } finally {
759
+ await rm(renderDirectory, { force: true, recursive: true });
760
+ await workspace.dispose();
761
+ }
762
+ },
763
+ },
764
+ outputSchema: MediaOverlayOutputSchema,
765
+ outputSchemaId: "slopcamera.operation.media.html-overlay.output/v1",
766
+ policy: {
767
+ cache: "exact-run",
768
+ cancellable: true,
769
+ effect: "local-derived-write",
770
+ maxDurationMs: 60 * 60_000,
771
+ maxFanOut: 0,
772
+ maxInputBytes: 3 * 1024 * 1024,
773
+ maxOutputBytes: 2 * 1024 * 1024,
774
+ preparation: ["project-state", "local-media"],
775
+ resources: [
776
+ { amount: 1, resource: "browser" },
777
+ { amount: 1, resource: "cpu" },
778
+ { amount: 1, resource: "ffmpeg" },
779
+ { amount: 1, resource: "local-io" },
780
+ { amount: 1, resource: "network" },
781
+ { amount: 1, resource: "output-publication" },
782
+ ],
783
+ resume: "verified-receipt",
784
+ },
785
+ receiptReference: output => output.receipt.path,
786
+ summarize: output => ({
787
+ fields: {
788
+ bytes: output.artifact.bytes,
789
+ created: output.created,
790
+ kind: "html",
791
+ overlayId: output.operation.overlayId,
792
+ receipt: output.receipt.path,
793
+ sha256: output.artifact.sha256,
794
+ },
795
+ kind: "media.html-overlay",
796
+ }),
797
+ version: 1,
798
+ };
799
+ }
800
+
801
+ export const htmlOverlayOperationDefinition =
802
+ createHtmlOverlayOperationDefinition();