@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,704 @@
1
+ import { createHash, randomUUID } from "node:crypto"
2
+ import { link, rm, writeFile } from "node:fs/promises"
3
+ import { dirname, extname, resolve } from "node:path"
4
+ import { SlopcameraCloudError } from "./cloud-errors.js"
5
+
6
+ export const slopcameraGatewayApiBaseUrl =
7
+ "https://ai-gateway.vercel.sh/v4/ai" as const
8
+
9
+ export const slopcameraImageModels = Object.freeze([
10
+ "openai/gpt-image-1.5",
11
+ "recraft/recraft-v4.1-utility",
12
+ ] as const)
13
+
14
+ export const slopcameraResponseMediaTypes = Object.freeze([
15
+ "image/png",
16
+ "image/jpeg",
17
+ "image/webp",
18
+ ] as const)
19
+
20
+ export const slopcameraMaximumPromptBytes = 32 * 1024
21
+ export const slopcameraMaximumRawImageBytes = 64 * 1024 * 1024
22
+
23
+ export type SlopcameraImageModel = string
24
+ export type SlopcameraResponseMediaType =
25
+ (typeof slopcameraResponseMediaTypes)[number]
26
+ export type SlopcameraGatewayCredentialSource =
27
+ | "AI_GATEWAY_API_KEY"
28
+ | "VERCEL_OIDC_TOKEN"
29
+
30
+ export interface SlopcameraGatewayCredentialStatus {
31
+ readonly available: boolean
32
+ readonly source: SlopcameraGatewayCredentialSource | null
33
+ }
34
+
35
+ export interface GenerateSlopcameraImageInput {
36
+ readonly model: SlopcameraImageModel
37
+ readonly prompt: string
38
+ readonly signal?: AbortSignal
39
+ readonly timeoutMs?: number
40
+ }
41
+
42
+ export interface GeneratedSlopcameraImage {
43
+ readonly image: {
44
+ readonly base64: string
45
+ readonly mediaType: SlopcameraResponseMediaType
46
+ }
47
+ readonly model: SlopcameraImageModel
48
+ readonly provider: "vercel-ai-gateway"
49
+ readonly requestId: string
50
+ readonly warnings: readonly string[]
51
+ }
52
+
53
+ export interface GeneratedSlopcameraImageFile {
54
+ readonly bytes: number
55
+ readonly mediaType: SlopcameraResponseMediaType
56
+ readonly model: SlopcameraImageModel
57
+ readonly outputPath: string
58
+ readonly provider: "vercel-ai-gateway"
59
+ readonly requestId: string
60
+ readonly sha256: string
61
+ readonly warnings: readonly string[]
62
+ }
63
+
64
+ type SlopcameraEnvironment = Readonly<Record<string, string | undefined>>
65
+ type SlopcameraGatewayFetch = (
66
+ input: string | URL | Request,
67
+ init?: RequestInit,
68
+ ) => Promise<Response>
69
+
70
+ interface GatewayProvider {
71
+ imageModel(modelId: string): unknown
72
+ }
73
+
74
+ interface GatewayRuntime {
75
+ createGateway(settings: Readonly<{
76
+ apiKey: string
77
+ baseURL: typeof slopcameraGatewayApiBaseUrl
78
+ fetch: SlopcameraGatewayFetch
79
+ }>): GatewayProvider
80
+ generateImage(input: Readonly<Record<string, unknown>>): Promise<unknown>
81
+ }
82
+
83
+ export interface SlopcameraGenerateDependencies {
84
+ readonly environment?: SlopcameraEnvironment
85
+ readonly fetch?: SlopcameraGatewayFetch
86
+ readonly loadRuntime?: () => Promise<GatewayRuntime>
87
+ readonly maximumResponseBytes?: number
88
+ }
89
+
90
+ const defaultGenerationTimeoutMs = 5 * 60_000
91
+ const maximumGenerationTimeoutMs = 30 * 60_000
92
+ const defaultMaximumGatewayResponseBytes = 96 * 1024 * 1024
93
+
94
+ function invalidArgument(message: string): never {
95
+ throw new SlopcameraCloudError("INVALID_ARGUMENT", message)
96
+ }
97
+
98
+ function credentialValue(value: string): string {
99
+ if (
100
+ value.length < 16 ||
101
+ value.length > 16 * 1024 ||
102
+ value.trim() !== value ||
103
+ /[^\x21-\x7e]/u.test(value)
104
+ ) {
105
+ throw new SlopcameraCloudError(
106
+ "AUTHENTICATION_REQUIRED",
107
+ "The selected Vercel AI Gateway credential is invalid.",
108
+ )
109
+ }
110
+ return value
111
+ }
112
+
113
+ function environment(
114
+ injected: SlopcameraEnvironment | undefined,
115
+ ): SlopcameraEnvironment {
116
+ return injected ?? process.env
117
+ }
118
+
119
+ function resolveGatewayCredential(
120
+ injected: SlopcameraEnvironment | undefined,
121
+ ): Readonly<{
122
+ source: SlopcameraGatewayCredentialSource
123
+ token: string
124
+ }> {
125
+ const values = environment(injected)
126
+ if (values.AI_GATEWAY_API_KEY !== undefined) {
127
+ return {
128
+ source: "AI_GATEWAY_API_KEY",
129
+ token: credentialValue(values.AI_GATEWAY_API_KEY),
130
+ }
131
+ }
132
+ if (values.VERCEL_OIDC_TOKEN !== undefined) {
133
+ return {
134
+ source: "VERCEL_OIDC_TOKEN",
135
+ token: credentialValue(values.VERCEL_OIDC_TOKEN),
136
+ }
137
+ }
138
+ throw new SlopcameraCloudError(
139
+ "AUTHENTICATION_REQUIRED",
140
+ "Set AI_GATEWAY_API_KEY or run Slopcamera through `vercel env run -- …` with VERCEL_OIDC_TOKEN available.",
141
+ )
142
+ }
143
+
144
+ export function slopcameraGatewayCredentialStatus(
145
+ injected?: SlopcameraEnvironment,
146
+ ): SlopcameraGatewayCredentialStatus {
147
+ const values = environment(injected)
148
+ if (values.AI_GATEWAY_API_KEY !== undefined) {
149
+ credentialValue(values.AI_GATEWAY_API_KEY)
150
+ return { available: true, source: "AI_GATEWAY_API_KEY" }
151
+ }
152
+ if (values.VERCEL_OIDC_TOKEN !== undefined) {
153
+ credentialValue(values.VERCEL_OIDC_TOKEN)
154
+ return { available: true, source: "VERCEL_OIDC_TOKEN" }
155
+ }
156
+ return { available: false, source: null }
157
+ }
158
+
159
+ function validateModel(value: unknown): string {
160
+ if (
161
+ typeof value !== "string" ||
162
+ value.length < 3 ||
163
+ value.length > 256 ||
164
+ !/^[a-z0-9][a-z0-9._-]*\/[a-z0-9][a-z0-9._:-]*$/iu.test(value)
165
+ ) {
166
+ invalidArgument("Model must be a bounded Vercel AI Gateway provider/model id.")
167
+ }
168
+ return value
169
+ }
170
+
171
+ function validatePrompt(value: unknown): string {
172
+ if (
173
+ typeof value !== "string" ||
174
+ value.trim().length === 0 ||
175
+ /[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f]/u.test(value) ||
176
+ Buffer.byteLength(value, "utf8") > slopcameraMaximumPromptBytes
177
+ ) {
178
+ invalidArgument(
179
+ `Prompt must be non-empty and no more than ${slopcameraMaximumPromptBytes} UTF-8 bytes.`,
180
+ )
181
+ }
182
+ return value
183
+ }
184
+
185
+ function validateTimeout(value: number | undefined): number {
186
+ const timeout = value ?? defaultGenerationTimeoutMs
187
+ if (
188
+ !Number.isSafeInteger(timeout) ||
189
+ timeout < 1_000 ||
190
+ timeout > maximumGenerationTimeoutMs
191
+ ) {
192
+ invalidArgument(
193
+ `timeoutMs must be an integer from 1000 through ${maximumGenerationTimeoutMs}.`,
194
+ )
195
+ }
196
+ return timeout
197
+ }
198
+
199
+ function isObject(value: unknown): value is Record<string, unknown> {
200
+ return (
201
+ (typeof value === "object" && value !== null) ||
202
+ typeof value === "function"
203
+ )
204
+ }
205
+
206
+ function parseFunction(
207
+ value: unknown,
208
+ ): (input: Readonly<Record<string, unknown>>) => Promise<unknown> {
209
+ if (typeof value !== "function") {
210
+ throw new SlopcameraCloudError(
211
+ "GENERATION_FAILED",
212
+ "The Vercel AI Gateway runtime is unavailable.",
213
+ )
214
+ }
215
+ return value as (
216
+ input: Readonly<Record<string, unknown>>,
217
+ ) => Promise<unknown>
218
+ }
219
+
220
+ function disableAiSdkWarningLogging(): void {
221
+ (
222
+ globalThis as typeof globalThis & {
223
+ AI_SDK_LOG_WARNINGS?: false
224
+ }
225
+ ).AI_SDK_LOG_WARNINGS = false
226
+ }
227
+
228
+ function assertGenerationActive(signal: AbortSignal): void {
229
+ if (signal.aborted) {
230
+ throw new SlopcameraCloudError(
231
+ "GENERATION_FAILED",
232
+ "Vercel AI Gateway image generation was cancelled or exceeded its deadline.",
233
+ )
234
+ }
235
+ }
236
+
237
+ async function loadDefaultGatewayRuntime(): Promise<GatewayRuntime> {
238
+ let aiModule: unknown
239
+ let gatewayModule: unknown
240
+ try {
241
+ ;[aiModule, gatewayModule] = await Promise.all([
242
+ import("ai-v7"),
243
+ import("@ai-sdk/gateway-v4"),
244
+ ])
245
+ } catch {
246
+ throw new SlopcameraCloudError(
247
+ "GENERATION_FAILED",
248
+ "The Vercel AI Gateway runtime is unavailable.",
249
+ )
250
+ }
251
+ if (!isObject(aiModule) || !isObject(gatewayModule)) {
252
+ throw new SlopcameraCloudError(
253
+ "GENERATION_FAILED",
254
+ "The Vercel AI Gateway runtime is unavailable.",
255
+ )
256
+ }
257
+ const generateImage = parseFunction(aiModule.generateImage)
258
+ if (typeof gatewayModule.createGateway !== "function") {
259
+ throw new SlopcameraCloudError(
260
+ "GENERATION_FAILED",
261
+ "The Vercel AI Gateway runtime is unavailable.",
262
+ )
263
+ }
264
+ const createGateway = gatewayModule.createGateway as (
265
+ settings: Readonly<Record<string, unknown>>,
266
+ ) => unknown
267
+ return {
268
+ createGateway: settings => {
269
+ const provider = createGateway(settings)
270
+ if (!isObject(provider) || typeof provider.imageModel !== "function") {
271
+ throw new SlopcameraCloudError(
272
+ "GENERATION_FAILED",
273
+ "The Vercel AI Gateway runtime is unavailable.",
274
+ )
275
+ }
276
+ const imageModel = provider.imageModel as (modelId: string) => unknown
277
+ return { imageModel: modelId => imageModel.call(provider, modelId) }
278
+ },
279
+ generateImage,
280
+ }
281
+ }
282
+
283
+ function gatewayUrl(input: string | URL | Request): URL {
284
+ try {
285
+ if (input instanceof Request) return new URL(input.url)
286
+ if (input instanceof URL) return new URL(input.href)
287
+ return new URL(input, slopcameraGatewayApiBaseUrl)
288
+ } catch {
289
+ throw new SlopcameraCloudError(
290
+ "GENERATION_FAILED",
291
+ "The Vercel AI Gateway request was rejected.",
292
+ )
293
+ }
294
+ }
295
+
296
+ function canonicalGatewayInput(
297
+ input: string | URL | Request,
298
+ url: URL,
299
+ ): URL | Request {
300
+ if (!(input instanceof Request)) return url
301
+
302
+ // Snapshot the Request's internal data, then bind it to the URL that was
303
+ // actually validated. Never forward a foreign Request subclass directly.
304
+ const snapshot = new Request(input)
305
+ const body = snapshot.method === "GET" || snapshot.method === "HEAD"
306
+ ? undefined
307
+ : snapshot.body ?? undefined
308
+ const requestInit: RequestInit & { duplex?: "half" } = {
309
+ headers: snapshot.headers,
310
+ method: snapshot.method,
311
+ signal: snapshot.signal,
312
+ ...(body === undefined ? {} : { body, duplex: "half" }),
313
+ }
314
+ return new Request(url.href, requestInit)
315
+ }
316
+
317
+ function boundedResponse(response: Response, maximumBytes: number): Response {
318
+ const declared = response.headers.get("content-length")
319
+ if (declared !== null) {
320
+ const value = Number(declared)
321
+ if (!Number.isSafeInteger(value) || value < 0 || value > maximumBytes) {
322
+ void response.body?.cancel().catch(() => undefined)
323
+ throw new SlopcameraCloudError(
324
+ "GENERATION_INVALID_RESPONSE",
325
+ "Vercel AI Gateway returned an invalid bounded response.",
326
+ )
327
+ }
328
+ }
329
+ if (response.body === null) return response
330
+ const reader = response.body.getReader()
331
+ let bytes = 0
332
+ const body = new ReadableStream<Uint8Array>({
333
+ cancel: async reason => await reader.cancel(reason),
334
+ pull: async controller => {
335
+ try {
336
+ const next = await reader.read()
337
+ if (next.done) {
338
+ reader.releaseLock()
339
+ controller.close()
340
+ return
341
+ }
342
+ bytes += next.value.byteLength
343
+ if (bytes > maximumBytes) {
344
+ await reader.cancel().catch(() => undefined)
345
+ controller.error(
346
+ new SlopcameraCloudError(
347
+ "GENERATION_INVALID_RESPONSE",
348
+ "Vercel AI Gateway returned an invalid bounded response.",
349
+ ),
350
+ )
351
+ return
352
+ }
353
+ controller.enqueue(next.value)
354
+ } catch {
355
+ controller.error(
356
+ new SlopcameraCloudError(
357
+ "GENERATION_INVALID_RESPONSE",
358
+ "Vercel AI Gateway returned an invalid bounded response.",
359
+ ),
360
+ )
361
+ }
362
+ },
363
+ })
364
+ return new Response(body, {
365
+ headers: response.headers,
366
+ status: response.status,
367
+ statusText: response.statusText,
368
+ })
369
+ }
370
+
371
+ export function createFixedGatewayFetch(
372
+ options: Readonly<{
373
+ fetch?: SlopcameraGatewayFetch
374
+ maximumResponseBytes?: number
375
+ }> = {},
376
+ ): SlopcameraGatewayFetch {
377
+ const fetchImplementation = options.fetch ?? globalThis.fetch
378
+ const maximumResponseBytes =
379
+ options.maximumResponseBytes ?? defaultMaximumGatewayResponseBytes
380
+ if (
381
+ !Number.isSafeInteger(maximumResponseBytes) ||
382
+ maximumResponseBytes < 1 ||
383
+ maximumResponseBytes > 1024 * 1024 * 1024
384
+ ) {
385
+ invalidArgument("maximumResponseBytes is outside the supported range.")
386
+ }
387
+ const fixed = new URL(slopcameraGatewayApiBaseUrl)
388
+ return async (input, init) => {
389
+ const url = gatewayUrl(input)
390
+ if (
391
+ url.origin !== fixed.origin ||
392
+ (url.pathname !== fixed.pathname &&
393
+ !url.pathname.startsWith(`${fixed.pathname}/`)) ||
394
+ url.username !== "" ||
395
+ url.password !== ""
396
+ ) {
397
+ throw new SlopcameraCloudError(
398
+ "GENERATION_FAILED",
399
+ "The Vercel AI Gateway request was rejected.",
400
+ )
401
+ }
402
+ const canonicalInput = canonicalGatewayInput(input, url)
403
+ let response: Response
404
+ try {
405
+ response = await fetchImplementation(canonicalInput, {
406
+ ...init,
407
+ redirect: "error",
408
+ })
409
+ } catch (error) {
410
+ if (error instanceof SlopcameraCloudError) throw error
411
+ throw new SlopcameraCloudError(
412
+ "GENERATION_FAILED",
413
+ "Vercel AI Gateway image generation failed; the request was not retried.",
414
+ )
415
+ }
416
+ if (response.redirected || (response.status >= 300 && response.status < 400)) {
417
+ await response.body?.cancel().catch(() => undefined)
418
+ throw new SlopcameraCloudError(
419
+ "GENERATION_FAILED",
420
+ "The Vercel AI Gateway request was rejected.",
421
+ )
422
+ }
423
+ return boundedResponse(response, maximumResponseBytes)
424
+ }
425
+ }
426
+
427
+ function combineSignals(
428
+ caller: AbortSignal | undefined,
429
+ timeoutMs: number,
430
+ ): Readonly<{
431
+ dispose(): void
432
+ interruption: Promise<never>
433
+ signal: AbortSignal
434
+ }> {
435
+ const controller = new AbortController()
436
+ const abort = (): void => controller.abort(caller?.reason)
437
+ let rejectInterruption: ((error: SlopcameraCloudError) => void) | undefined
438
+ const interruption = new Promise<never>((_resolve, reject) => {
439
+ rejectInterruption = reject
440
+ })
441
+ const rejectOnAbort = (): void => {
442
+ rejectInterruption?.(new SlopcameraCloudError(
443
+ "GENERATION_FAILED",
444
+ "Vercel AI Gateway image generation was cancelled or exceeded its deadline.",
445
+ ))
446
+ }
447
+ controller.signal.addEventListener("abort", rejectOnAbort, { once: true })
448
+ if (caller?.aborted === true) abort()
449
+ caller?.addEventListener("abort", abort, { once: true })
450
+ const timer = setTimeout(() => controller.abort(), timeoutMs)
451
+ return {
452
+ dispose: () => {
453
+ clearTimeout(timer)
454
+ caller?.removeEventListener("abort", abort)
455
+ controller.signal.removeEventListener("abort", rejectOnAbort)
456
+ rejectInterruption = undefined
457
+ },
458
+ interruption,
459
+ signal: controller.signal,
460
+ }
461
+ }
462
+
463
+ function mediaType(value: unknown): SlopcameraResponseMediaType {
464
+ if (
465
+ typeof value !== "string" ||
466
+ !slopcameraResponseMediaTypes.includes(value as SlopcameraResponseMediaType)
467
+ ) {
468
+ throw new SlopcameraCloudError(
469
+ "GENERATION_INVALID_RESPONSE",
470
+ "Vercel AI Gateway returned an unsupported image type.",
471
+ )
472
+ }
473
+ return value as SlopcameraResponseMediaType
474
+ }
475
+
476
+ function validImageBytes(
477
+ bytes: Uint8Array,
478
+ type: SlopcameraResponseMediaType,
479
+ ): boolean {
480
+ if (
481
+ bytes.byteLength < 12 ||
482
+ bytes.byteLength > slopcameraMaximumRawImageBytes
483
+ ) {
484
+ return false
485
+ }
486
+ if (type === "image/png") {
487
+ return Buffer.from(bytes.subarray(0, 8)).equals(
488
+ Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]),
489
+ )
490
+ }
491
+ if (type === "image/jpeg") {
492
+ return (
493
+ bytes[0] === 0xff &&
494
+ bytes[1] === 0xd8 &&
495
+ bytes.at(-2) === 0xff &&
496
+ bytes.at(-1) === 0xd9
497
+ )
498
+ }
499
+ return (
500
+ bytes.byteLength >= 16 &&
501
+ Buffer.from(bytes.subarray(0, 4)).toString("ascii") === "RIFF" &&
502
+ Buffer.from(bytes).readUInt32LE(4) === bytes.byteLength - 8 &&
503
+ Buffer.from(bytes.subarray(8, 12)).toString("ascii") === "WEBP" &&
504
+ ["VP8 ", "VP8L", "VP8X"].includes(
505
+ Buffer.from(bytes.subarray(12, 16)).toString("ascii"),
506
+ )
507
+ )
508
+ }
509
+
510
+ function warningReceipt(value: unknown): string {
511
+ let type = "provider-warning"
512
+ let detail = "Provider warning"
513
+ if (typeof value === "string") {
514
+ detail = value
515
+ } else if (isObject(value)) {
516
+ if (typeof value.type === "string" && value.type.length <= 64) {
517
+ type = value.type.replace(/[^a-z0-9._-]/giu, "-") || type
518
+ }
519
+ if (typeof value.message === "string") detail = value.message
520
+ else if (typeof value.details === "string") detail = value.details
521
+ }
522
+ return `${type} sha256:${createHash("sha256").update(detail).digest("hex")}`
523
+ }
524
+
525
+ function parseResult(
526
+ value: unknown,
527
+ model: string,
528
+ ): Readonly<{ bytes: Uint8Array; response: GeneratedSlopcameraImage }> {
529
+ if (!isObject(value) || !Array.isArray(value.images) || value.images.length !== 1) {
530
+ throw new SlopcameraCloudError(
531
+ "GENERATION_INVALID_RESPONSE",
532
+ "Vercel AI Gateway did not return exactly one image.",
533
+ )
534
+ }
535
+ const image = value.images[0]
536
+ if (!isObject(image) || !(image.uint8Array instanceof Uint8Array)) {
537
+ throw new SlopcameraCloudError(
538
+ "GENERATION_INVALID_RESPONSE",
539
+ "Vercel AI Gateway returned an invalid bounded image.",
540
+ )
541
+ }
542
+ const type = mediaType(image.mediaType)
543
+ if (!validImageBytes(image.uint8Array, type)) {
544
+ throw new SlopcameraCloudError(
545
+ "GENERATION_INVALID_RESPONSE",
546
+ "Vercel AI Gateway returned an invalid bounded image.",
547
+ )
548
+ }
549
+ const gateway = isObject(value.providerMetadata) &&
550
+ isObject(value.providerMetadata.gateway)
551
+ ? value.providerMetadata.gateway
552
+ : undefined
553
+ const foreignGenerationId = gateway !== undefined &&
554
+ typeof gateway.generationId === "string" &&
555
+ gateway.generationId.length > 0 &&
556
+ gateway.generationId.length <= 256 &&
557
+ !/[\u0000-\u001f\u007f]/u.test(gateway.generationId)
558
+ ? gateway.generationId
559
+ : randomUUID()
560
+ const requestId = `sha256:${createHash("sha256")
561
+ .update("slopcamera.gateway-generation-id/v1\0")
562
+ .update(foreignGenerationId)
563
+ .digest("hex")}`
564
+ const warnings = Array.isArray(value.warnings)
565
+ ? value.warnings.slice(0, 100).map(warningReceipt)
566
+ : []
567
+ return {
568
+ bytes: image.uint8Array,
569
+ response: {
570
+ image: {
571
+ base64: Buffer.from(image.uint8Array).toString("base64"),
572
+ mediaType: type,
573
+ },
574
+ model,
575
+ provider: "vercel-ai-gateway",
576
+ requestId,
577
+ warnings,
578
+ },
579
+ }
580
+ }
581
+
582
+ async function performGeneration(
583
+ input: GenerateSlopcameraImageInput,
584
+ dependencies: SlopcameraGenerateDependencies,
585
+ ): Promise<Readonly<{
586
+ bytes: Uint8Array
587
+ response: GeneratedSlopcameraImage
588
+ }>> {
589
+ const model = validateModel(input.model)
590
+ const prompt = validatePrompt(input.prompt)
591
+ const credential = resolveGatewayCredential(dependencies.environment)
592
+ const timeout = combineSignals(input.signal, validateTimeout(input.timeoutMs))
593
+ try {
594
+ const generation = (async () => {
595
+ assertGenerationActive(timeout.signal)
596
+ // Raw AI SDK warnings may contain provider-controlled details. Slopcamera
597
+ // emits only allowlisted warning kinds and message hashes.
598
+ disableAiSdkWarningLogging()
599
+ const runtime = await (dependencies.loadRuntime ?? loadDefaultGatewayRuntime)()
600
+ assertGenerationActive(timeout.signal)
601
+ const provider = runtime.createGateway({
602
+ apiKey: credential.token,
603
+ baseURL: slopcameraGatewayApiBaseUrl,
604
+ fetch: createFixedGatewayFetch({
605
+ ...(dependencies.fetch === undefined ? {} : { fetch: dependencies.fetch }),
606
+ ...(dependencies.maximumResponseBytes === undefined
607
+ ? {}
608
+ : { maximumResponseBytes: dependencies.maximumResponseBytes }),
609
+ }),
610
+ })
611
+ assertGenerationActive(timeout.signal)
612
+ const generated = await runtime.generateImage({
613
+ abortSignal: timeout.signal,
614
+ maxRetries: 0,
615
+ model: provider.imageModel(model),
616
+ n: 1,
617
+ prompt,
618
+ })
619
+ return parseResult(generated, model)
620
+ })()
621
+ return await Promise.race([generation, timeout.interruption])
622
+ } catch (error) {
623
+ if (error instanceof SlopcameraCloudError) throw error
624
+ throw new SlopcameraCloudError(
625
+ "GENERATION_FAILED",
626
+ "Vercel AI Gateway image generation failed; the request was not retried.",
627
+ )
628
+ } finally {
629
+ timeout.dispose()
630
+ }
631
+ }
632
+
633
+ export async function generateSlopcameraImage(
634
+ input: GenerateSlopcameraImageInput,
635
+ dependencies: SlopcameraGenerateDependencies = {},
636
+ ): Promise<GeneratedSlopcameraImage> {
637
+ return (await performGeneration(input, dependencies)).response
638
+ }
639
+
640
+ function expectedMediaType(outputPath: string): SlopcameraResponseMediaType {
641
+ const extension = extname(outputPath).toLocaleLowerCase("en-US")
642
+ if (extension === ".png") return "image/png"
643
+ if (extension === ".jpg" || extension === ".jpeg") return "image/jpeg"
644
+ if (extension === ".webp") return "image/webp"
645
+ invalidArgument("Output path must end in .png, .jpg, .jpeg, or .webp.")
646
+ }
647
+
648
+ async function atomicImageWrite(
649
+ outputPath: string,
650
+ bytes: Uint8Array,
651
+ ): Promise<string> {
652
+ const absolutePath = resolve(outputPath)
653
+ const temporaryPath = resolve(
654
+ dirname(absolutePath),
655
+ `.${randomUUID()}.slopcamera-generate.tmp`,
656
+ )
657
+ try {
658
+ await writeFile(temporaryPath, bytes, { flag: "wx" })
659
+ // A same-directory hard link atomically publishes only when the output is
660
+ // absent. Concurrent writers cannot replace one another's selected asset.
661
+ await link(temporaryPath, absolutePath)
662
+ return absolutePath
663
+ } catch {
664
+ throw new SlopcameraCloudError(
665
+ "OUTPUT_WRITE_FAILED",
666
+ "Slopcamera could not atomically write the generated image.",
667
+ )
668
+ } finally {
669
+ await rm(temporaryPath, { force: true }).catch(() => undefined)
670
+ }
671
+ }
672
+
673
+ export async function generateSlopcameraImageFile(
674
+ input: GenerateSlopcameraImageInput & { readonly outputPath: string },
675
+ dependencies: SlopcameraGenerateDependencies = {},
676
+ ): Promise<GeneratedSlopcameraImageFile> {
677
+ if (
678
+ typeof input.outputPath !== "string" ||
679
+ input.outputPath.length < 1 ||
680
+ input.outputPath.length > 4_096 ||
681
+ input.outputPath.includes("\0")
682
+ ) {
683
+ invalidArgument("Output path must be a non-empty local path.")
684
+ }
685
+ const expected = expectedMediaType(input.outputPath)
686
+ const generated = await performGeneration(input, dependencies)
687
+ if (generated.response.image.mediaType !== expected) {
688
+ throw new SlopcameraCloudError(
689
+ "GENERATION_INVALID_RESPONSE",
690
+ `Generated ${generated.response.image.mediaType} does not match the requested ${expected} output path.`,
691
+ )
692
+ }
693
+ const outputPath = await atomicImageWrite(input.outputPath, generated.bytes)
694
+ return {
695
+ bytes: generated.bytes.byteLength,
696
+ mediaType: generated.response.image.mediaType,
697
+ model: generated.response.model,
698
+ outputPath,
699
+ provider: generated.response.provider,
700
+ requestId: generated.response.requestId,
701
+ sha256: createHash("sha256").update(generated.bytes).digest("hex"),
702
+ warnings: generated.response.warnings,
703
+ }
704
+ }