@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,542 @@
1
+ import { createHash, randomUUID } from "node:crypto"
2
+ import { constants } from "node:fs"
3
+ import {
4
+ chmod,
5
+ mkdir,
6
+ open,
7
+ realpath,
8
+ rename,
9
+ rm,
10
+ writeFile,
11
+ type FileHandle,
12
+ } from "node:fs/promises"
13
+ import { homedir } from "node:os"
14
+ import { dirname, join, resolve } from "node:path"
15
+ import { extractVTracerArchive } from "./archive.js"
16
+ import { runBoundedCommand } from "./command.js"
17
+ import { type VectorizeDeadline } from "./limits.js"
18
+ import { sha256 } from "./metrics.js"
19
+ import { VectorizeError } from "./types.js"
20
+
21
+ export const VTRACER_VERSION = "0.6.4"
22
+
23
+ interface VTracerRelease {
24
+ readonly archiveSha256: string
25
+ readonly binarySha256: string
26
+ readonly format: "tar.gz" | "zip"
27
+ readonly url: string
28
+ }
29
+
30
+ const frozenRelease = (release: VTracerRelease): Readonly<VTracerRelease> =>
31
+ Object.freeze(release)
32
+
33
+ /**
34
+ * Hashes were independently recomputed from the five official GitHub release
35
+ * assets and their extracted binaries on 2026-07-25.
36
+ */
37
+ export const vtracerReleases = Object.freeze({
38
+ "darwin-arm64": frozenRelease({
39
+ archiveSha256: "4a597fd2df8b961d60620df40a7436109427d86e5c028758e6e8796b02d3d996",
40
+ binarySha256: "77e495bbe212448240387fba3b6d8bc62ba20ecfb6f3c22967e51600f1cc6e66",
41
+ format: "tar.gz",
42
+ url: `https://github.com/visioncortex/vtracer/releases/download/${VTRACER_VERSION}/vtracer-aarch64-apple-darwin.tar.gz`,
43
+ }),
44
+ "darwin-x64": frozenRelease({
45
+ archiveSha256: "f0d755292c2602d772d63d658a3498b23eca8b5620d4b92a991bd035d5abed16",
46
+ binarySha256: "0f9f88f989b757e27973a5c4b42665153070183d0787656ee8af2249ab326b78",
47
+ format: "tar.gz",
48
+ url: `https://github.com/visioncortex/vtracer/releases/download/${VTRACER_VERSION}/vtracer-x86_64-apple-darwin.tar.gz`,
49
+ }),
50
+ "linux-arm64": frozenRelease({
51
+ archiveSha256: "cbd05ad4f491d12dd139ada61485ca1d24db9f981cbe1658632a083cd0ac1a71",
52
+ binarySha256: "a4b33b6c4066a6b9187802c6efc8b89e211318e12a17164b9d1dd1f29ac5e502",
53
+ format: "tar.gz",
54
+ url: `https://github.com/visioncortex/vtracer/releases/download/${VTRACER_VERSION}/vtracer-aarch64-unknown-linux-musl.tar.gz`,
55
+ }),
56
+ "linux-x64": frozenRelease({
57
+ archiveSha256: "9290ba0c90e224d6d212836dff5491407c1718bcb72f80b2b5a4a01816df5e40",
58
+ binarySha256: "6f31499257076bd94de3e976844cf7ca5643f1e194a2bf0599b13f3719452aec",
59
+ format: "tar.gz",
60
+ url: `https://github.com/visioncortex/vtracer/releases/download/${VTRACER_VERSION}/vtracer-x86_64-unknown-linux-musl.tar.gz`,
61
+ }),
62
+ "win32-x64": frozenRelease({
63
+ archiveSha256: "6b5bc17a6b017129ee40461df254f65d16f3b494c001a8541d41861066b716bf",
64
+ binarySha256: "4ad8d35e566cd15caf582063b8349bd082b8fa2bd461e99d116fc63ad8fdeca0",
65
+ format: "zip",
66
+ url: `https://github.com/visioncortex/vtracer/releases/download/${VTRACER_VERSION}/vtracer-x86_64-pc-windows-msvc.zip`,
67
+ }),
68
+ }) satisfies Readonly<Record<string, Readonly<VTracerRelease>>>
69
+
70
+ export interface VTracerTool {
71
+ /**
72
+ * A conversion-private executable copied through one verified source handle.
73
+ * Callers must remove its containing conversion directory when finished.
74
+ */
75
+ readonly path: string
76
+ readonly sha256: string
77
+ readonly source: "official-release" | "override"
78
+ readonly version: string
79
+ }
80
+
81
+ const MAX_ARCHIVE_BYTES = 4 * 1_024 * 1_024
82
+ const MAX_TOOL_BYTES = 16 * 1_024 * 1_024
83
+ const FILE_CHUNK_BYTES = 64 * 1_024
84
+
85
+ function renamedEnvironmentValue(canonical: `SLOPCAMERA_${string}`): string | undefined {
86
+ return process.env[canonical]
87
+ }
88
+
89
+ export async function ensureVTracer(
90
+ deadline: VectorizeDeadline,
91
+ privateDirectory: string,
92
+ cacheDirectory?: string,
93
+ ): Promise<VTracerTool> {
94
+ const override = renamedEnvironmentValue("SLOPCAMERA_VTRACER_PATH")
95
+ if (override !== undefined) {
96
+ return copyAndInspectVTracer(
97
+ resolve(override),
98
+ resolve(privateDirectory),
99
+ "override",
100
+ deadline,
101
+ )
102
+ }
103
+
104
+ const key = `${process.platform}-${process.arch}`
105
+ const release = vtracerReleases[key as keyof typeof vtracerReleases]
106
+ if (release === undefined) {
107
+ throw new VectorizeError(
108
+ "tool_platform",
109
+ `VTracer is not pinned for ${process.platform}/${process.arch}.`,
110
+ { arch: process.arch, platform: process.platform },
111
+ )
112
+ }
113
+
114
+ const cacheRoot = resolve(cacheDirectory ?? defaultCacheDirectory())
115
+ const suffix = process.platform === "win32" ? ".exe" : ""
116
+ const toolPath = join(
117
+ cacheRoot,
118
+ "tools",
119
+ `vtracer-${VTRACER_VERSION}-${process.platform}-${process.arch}${suffix}`,
120
+ )
121
+ const cachedHash = await hashCachedTool(toolPath, deadline)
122
+ if (cachedHash !== release.binarySha256) {
123
+ await removeInvalidCachedTool(toolPath)
124
+ await installOfficialVTracer(toolPath, release, deadline)
125
+ }
126
+
127
+ return copyAndInspectVTracer(
128
+ toolPath,
129
+ resolve(privateDirectory),
130
+ "official-release",
131
+ deadline,
132
+ release.binarySha256,
133
+ )
134
+ }
135
+
136
+ function defaultCacheDirectory(): string {
137
+ const explicit = renamedEnvironmentValue("SLOPCAMERA_CACHE_DIR")
138
+ if (explicit !== undefined && explicit.trim() !== "") return explicit
139
+ if (process.platform === "win32") {
140
+ return join(process.env.LOCALAPPDATA ?? homedir(), "slopcamera")
141
+ }
142
+ if (process.platform === "darwin") return join(homedir(), "Library", "Caches", "slopcamera")
143
+ return join(process.env.XDG_CACHE_HOME ?? join(homedir(), ".cache"), "slopcamera")
144
+ }
145
+
146
+ async function installOfficialVTracer(
147
+ toolPath: string,
148
+ release: Readonly<VTracerRelease>,
149
+ deadline: VectorizeDeadline,
150
+ ): Promise<void> {
151
+ deadline.assert("VTracer download")
152
+ const archive = await downloadBounded(release.url, deadline, MAX_ARCHIVE_BYTES)
153
+ const archiveSha256 = sha256(archive)
154
+ if (archiveSha256 !== release.archiveSha256) {
155
+ throw new VectorizeError(
156
+ "tool_integrity",
157
+ `VTracer archive checksum mismatch: ${archiveSha256}`,
158
+ { actual: archiveSha256, expected: release.archiveSha256 },
159
+ )
160
+ }
161
+ const binary = extractVTracerArchive(archive, release.format)
162
+ if (binary.byteLength < 1 || binary.byteLength > MAX_TOOL_BYTES) {
163
+ throw new VectorizeError(
164
+ "tool_integrity",
165
+ "VTracer binary exceeds its verified installation limit.",
166
+ { bytes: binary.byteLength, maximumBytes: MAX_TOOL_BYTES },
167
+ )
168
+ }
169
+ const binarySha256 = sha256(binary)
170
+ if (binarySha256 !== release.binarySha256) {
171
+ throw new VectorizeError(
172
+ "tool_integrity",
173
+ `VTracer binary checksum mismatch: ${binarySha256}`,
174
+ { actual: binarySha256, expected: release.binarySha256 },
175
+ )
176
+ }
177
+
178
+ deadline.assert("VTracer installation")
179
+ await mkdir(dirname(toolPath), { recursive: true })
180
+ const stagedPath = `${toolPath}.${randomUUID()}.tmp`
181
+ try {
182
+ await writeFile(stagedPath, binary, { flag: "wx", mode: 0o700 })
183
+ if (process.platform !== "win32") await chmod(stagedPath, 0o500)
184
+ deadline.assert("VTracer installation")
185
+ try {
186
+ await rename(stagedPath, toolPath)
187
+ } catch (error) {
188
+ const concurrentHash = await hashCachedTool(toolPath, deadline)
189
+ if (concurrentHash === release.binarySha256) {
190
+ await rm(stagedPath, { force: true })
191
+ } else {
192
+ throw error
193
+ }
194
+ }
195
+ } catch (error) {
196
+ await rm(stagedPath, { force: true })
197
+ if (error instanceof VectorizeError) throw error
198
+ throw new VectorizeError(
199
+ "tool_integrity",
200
+ "Could not publish the verified VTracer binary.",
201
+ {},
202
+ { cause: error },
203
+ )
204
+ }
205
+
206
+ const installedHash = await hashCachedTool(toolPath, deadline)
207
+ if (installedHash !== release.binarySha256) {
208
+ throw new VectorizeError(
209
+ "tool_integrity",
210
+ "Installed VTracer differs from the verified release binary.",
211
+ { actual: installedHash, expected: release.binarySha256 },
212
+ )
213
+ }
214
+ }
215
+
216
+ async function copyAndInspectVTracer(
217
+ sourcePath: string,
218
+ privateDirectory: string,
219
+ source: VTracerTool["source"],
220
+ deadline: VectorizeDeadline,
221
+ expectedSha256?: string,
222
+ ): Promise<VTracerTool> {
223
+ deadline.assert("VTracer private copy")
224
+ await mkdir(privateDirectory, { mode: 0o700, recursive: true })
225
+ const suffix = process.platform === "win32" ? ".exe" : ""
226
+ const privatePath = join(privateDirectory, `vtracer-${randomUUID()}${suffix}`)
227
+ const failureCode = source === "official-release" ? "tool_integrity" : "tool_version"
228
+ let sourceHandle: FileHandle | undefined
229
+ let targetHandle: FileHandle | undefined
230
+ let copiedSha256: string
231
+ try {
232
+ const resolvedSourcePath = await realpath(sourcePath)
233
+ deadline.assert("VTracer private copy")
234
+ sourceHandle = await open(resolvedSourcePath, boundedReadFlags())
235
+ const metadata = await sourceHandle.stat()
236
+ assertBoundedRegularTool(metadata, sourcePath)
237
+ targetHandle = await open(privatePath, "wx", 0o500)
238
+ copiedSha256 = await copyAndHash(
239
+ sourceHandle,
240
+ targetHandle,
241
+ MAX_TOOL_BYTES,
242
+ deadline,
243
+ )
244
+ await targetHandle.sync()
245
+ deadline.assert("VTracer private copy")
246
+ } catch (error) {
247
+ if (error instanceof VectorizeError) throw error
248
+ throw new VectorizeError(
249
+ failureCode,
250
+ "VTracer could not be copied into the private conversion directory.",
251
+ {},
252
+ { cause: error },
253
+ )
254
+ } finally {
255
+ await Promise.allSettled([sourceHandle?.close(), targetHandle?.close()])
256
+ }
257
+
258
+ try {
259
+ if (copiedSha256.length === 0) {
260
+ throw new VectorizeError(failureCode, "VTracer executable is empty.")
261
+ }
262
+ if (expectedSha256 !== undefined && copiedSha256 !== expectedSha256) {
263
+ throw new VectorizeError(
264
+ "tool_integrity",
265
+ "VTracer changed before it could be copied for conversion.",
266
+ { actual: copiedSha256, expected: expectedSha256 },
267
+ )
268
+ }
269
+ if (process.platform !== "win32") await chmod(privatePath, 0o500)
270
+ const privateSha256 = await hashRegularFile(
271
+ privatePath,
272
+ MAX_TOOL_BYTES,
273
+ deadline,
274
+ failureCode,
275
+ )
276
+ if (privateSha256 !== copiedSha256) {
277
+ throw new VectorizeError(
278
+ "tool_integrity",
279
+ "The private VTracer copy failed its integrity check.",
280
+ { actual: privateSha256, expected: copiedSha256 },
281
+ )
282
+ }
283
+ return inspectVTracer(
284
+ privatePath,
285
+ source,
286
+ deadline,
287
+ copiedSha256,
288
+ expectedSha256,
289
+ )
290
+ } catch (error) {
291
+ await rm(privatePath, { force: true })
292
+ throw error
293
+ }
294
+ }
295
+
296
+ async function inspectVTracer(
297
+ path: string,
298
+ source: VTracerTool["source"],
299
+ deadline: VectorizeDeadline,
300
+ copiedSha256: string,
301
+ expectedSha256?: string,
302
+ ): Promise<VTracerTool> {
303
+ deadline.assert("VTracer inspection")
304
+ const { stderr, stdout } = await runBoundedCommand(
305
+ [path, "--version"],
306
+ deadline.remainingMs(),
307
+ "tool_version",
308
+ )
309
+ if (!new RegExp(`\\b${VTRACER_VERSION.replaceAll(".", "\\.")}\\b`, "u").test(`${stdout}\n${stderr}`)) {
310
+ throw new VectorizeError(
311
+ "tool_version",
312
+ `Expected VTracer ${VTRACER_VERSION}.`,
313
+ )
314
+ }
315
+ const afterInspectionSha256 = await hashRegularFile(
316
+ path,
317
+ MAX_TOOL_BYTES,
318
+ deadline,
319
+ "tool_integrity",
320
+ )
321
+ if (
322
+ afterInspectionSha256 !== copiedSha256 ||
323
+ (expectedSha256 !== undefined && afterInspectionSha256 !== expectedSha256)
324
+ ) {
325
+ throw new VectorizeError(
326
+ "tool_integrity",
327
+ "The private VTracer executable changed during inspection.",
328
+ {
329
+ actual: afterInspectionSha256,
330
+ expected: expectedSha256 ?? copiedSha256,
331
+ },
332
+ )
333
+ }
334
+ return {
335
+ path,
336
+ sha256: afterInspectionSha256,
337
+ source,
338
+ version: VTRACER_VERSION,
339
+ }
340
+ }
341
+
342
+ async function hashCachedTool(
343
+ path: string,
344
+ deadline: VectorizeDeadline,
345
+ ): Promise<string | undefined> {
346
+ try {
347
+ return await hashRegularFile(
348
+ path,
349
+ MAX_TOOL_BYTES,
350
+ deadline,
351
+ "tool_integrity",
352
+ )
353
+ } catch (error) {
354
+ if (error instanceof VectorizeError && error.code === "timeout") throw error
355
+ if (isFileSystemError(error, "ENOENT")) return undefined
356
+ return undefined
357
+ }
358
+ }
359
+
360
+ async function removeInvalidCachedTool(path: string): Promise<void> {
361
+ try {
362
+ await rm(path, { force: true })
363
+ } catch (error) {
364
+ throw new VectorizeError(
365
+ "tool_integrity",
366
+ "Could not remove an invalid cached VTracer binary.",
367
+ {},
368
+ { cause: error },
369
+ )
370
+ }
371
+ }
372
+
373
+ async function hashRegularFile(
374
+ path: string,
375
+ maximumBytes: number,
376
+ deadline: VectorizeDeadline,
377
+ failureCode: "tool_integrity" | "tool_version",
378
+ ): Promise<string> {
379
+ let handle: FileHandle | undefined
380
+ try {
381
+ deadline.assert("VTracer hash")
382
+ const resolvedPath = await realpath(path)
383
+ deadline.assert("VTracer hash")
384
+ handle = await open(resolvedPath, boundedReadFlags())
385
+ const metadata = await handle.stat()
386
+ if (!metadata.isFile() || metadata.size < 1 || metadata.size > maximumBytes) {
387
+ throw new VectorizeError(
388
+ failureCode,
389
+ "VTracer must be a non-empty regular file within its size limit.",
390
+ { bytes: metadata.size, maximumBytes },
391
+ )
392
+ }
393
+ const hash = createHash("sha256")
394
+ const buffer = Buffer.allocUnsafe(Math.min(FILE_CHUNK_BYTES, maximumBytes + 1))
395
+ let bytes = 0
396
+ while (true) {
397
+ deadline.assert("VTracer hash")
398
+ const maximumRead = Math.min(buffer.byteLength, maximumBytes - bytes + 1)
399
+ const { bytesRead } = await handle.read(buffer, 0, maximumRead, null)
400
+ if (bytesRead === 0) break
401
+ bytes += bytesRead
402
+ if (bytes > maximumBytes) {
403
+ throw new VectorizeError(
404
+ failureCode,
405
+ "VTracer grew beyond its executable size limit while being hashed.",
406
+ { bytes, maximumBytes },
407
+ )
408
+ }
409
+ hash.update(buffer.subarray(0, bytesRead))
410
+ }
411
+ deadline.assert("VTracer hash")
412
+ return hash.digest("hex")
413
+ } catch (error) {
414
+ if (error instanceof VectorizeError) throw error
415
+ throw new VectorizeError(
416
+ failureCode,
417
+ "VTracer executable could not be read safely.",
418
+ {},
419
+ { cause: error },
420
+ )
421
+ } finally {
422
+ await handle?.close().catch(() => undefined)
423
+ }
424
+ }
425
+
426
+ async function copyAndHash(
427
+ source: FileHandle,
428
+ target: FileHandle,
429
+ maximumBytes: number,
430
+ deadline: VectorizeDeadline,
431
+ ): Promise<string> {
432
+ const hash = createHash("sha256")
433
+ const buffer = Buffer.allocUnsafe(Math.min(FILE_CHUNK_BYTES, maximumBytes + 1))
434
+ let bytes = 0
435
+ while (true) {
436
+ deadline.assert("VTracer private copy")
437
+ const maximumRead = Math.min(buffer.byteLength, maximumBytes - bytes + 1)
438
+ const { bytesRead } = await source.read(buffer, 0, maximumRead, null)
439
+ if (bytesRead === 0) break
440
+ bytes += bytesRead
441
+ if (bytes > maximumBytes) {
442
+ throw new VectorizeError(
443
+ "tool_integrity",
444
+ "VTracer grew beyond its executable size limit while being copied.",
445
+ { bytes, maximumBytes },
446
+ )
447
+ }
448
+ hash.update(buffer.subarray(0, bytesRead))
449
+ let written = 0
450
+ while (written < bytesRead) {
451
+ const result = await target.write(
452
+ buffer,
453
+ written,
454
+ bytesRead - written,
455
+ null,
456
+ )
457
+ if (result.bytesWritten < 1) {
458
+ throw new VectorizeError(
459
+ "tool_integrity",
460
+ "VTracer private copy stopped before completion.",
461
+ )
462
+ }
463
+ written += result.bytesWritten
464
+ }
465
+ }
466
+ return bytes === 0 ? "" : hash.digest("hex")
467
+ }
468
+
469
+ function assertBoundedRegularTool(
470
+ metadata: Awaited<ReturnType<FileHandle["stat"]>>,
471
+ path: string,
472
+ ): void {
473
+ if (!metadata.isFile() || metadata.size < 1 || metadata.size > MAX_TOOL_BYTES) {
474
+ throw new VectorizeError(
475
+ "tool_version",
476
+ `VTracer must be a non-empty regular file: ${path}`,
477
+ { bytes: metadata.size, maximumBytes: MAX_TOOL_BYTES },
478
+ )
479
+ }
480
+ }
481
+
482
+ async function downloadBounded(
483
+ url: string,
484
+ deadline: VectorizeDeadline,
485
+ maximumBytes: number,
486
+ ): Promise<Uint8Array> {
487
+ const controller = new AbortController()
488
+ const timer = setTimeout(() => controller.abort(), deadline.remainingMs())
489
+ try {
490
+ const response = await fetch(url, {
491
+ headers: { "user-agent": "hraness-slopcamera-vectorizer" },
492
+ redirect: "follow",
493
+ signal: controller.signal,
494
+ })
495
+ if (!response.ok || response.body === null) {
496
+ throw new VectorizeError(
497
+ "tool_download",
498
+ `Could not download VTracer: ${response.status} ${response.statusText}`,
499
+ )
500
+ }
501
+ const declaredLength = Number.parseInt(response.headers.get("content-length") ?? "", 10)
502
+ if (Number.isFinite(declaredLength) && declaredLength > maximumBytes) {
503
+ throw new VectorizeError("tool_download", "VTracer archive exceeds its download limit.")
504
+ }
505
+ const chunks: Uint8Array[] = []
506
+ const reader = response.body.getReader()
507
+ let bytes = 0
508
+ while (true) {
509
+ deadline.assert("VTracer download")
510
+ const { done, value } = await reader.read()
511
+ if (done) break
512
+ bytes += value.byteLength
513
+ if (bytes > maximumBytes) {
514
+ await reader.cancel()
515
+ throw new VectorizeError("tool_download", "VTracer archive exceeds its download limit.")
516
+ }
517
+ chunks.push(value)
518
+ }
519
+ return Uint8Array.from(Buffer.concat(chunks, bytes))
520
+ } catch (error) {
521
+ if (error instanceof VectorizeError) throw error
522
+ if (controller.signal.aborted) {
523
+ throw new VectorizeError("timeout", "VTracer download exceeded the conversion time limit.")
524
+ }
525
+ throw new VectorizeError("tool_download", "Could not download VTracer.", {}, { cause: error })
526
+ } finally {
527
+ clearTimeout(timer)
528
+ }
529
+ }
530
+
531
+ function isFileSystemError(error: unknown, code: string): boolean {
532
+ return (
533
+ error instanceof Error &&
534
+ "code" in error &&
535
+ (error as NodeJS.ErrnoException).code === code
536
+ )
537
+ }
538
+
539
+ function boundedReadFlags(): number {
540
+ if (process.platform === "win32") return constants.O_RDONLY
541
+ return constants.O_RDONLY | constants.O_NONBLOCK | constants.O_NOFOLLOW
542
+ }
@@ -0,0 +1,113 @@
1
+ export const vectorizeProfileNames = ["balanced", "detailed", "photo"] as const
2
+
3
+ export type VectorizeProfile = (typeof vectorizeProfileNames)[number]
4
+ export type VectorizeRepresentation = "color-paths" | "alpha-mask"
5
+ export type VectorizeOutputMode = "color" | "duotone"
6
+ export type VectorizeInput = string | Uint8Array | ArrayBuffer
7
+
8
+ export interface VectorizeLimits {
9
+ readonly maxDecodedPixels: number
10
+ readonly maxDimension: number
11
+ readonly maxDurationMs: number
12
+ readonly maxInputBytes: number
13
+ readonly maxOutputBytes: number
14
+ readonly maxPaths: number
15
+ }
16
+
17
+ export interface VectorizeOptions {
18
+ /**
19
+ * Pixels below this alpha byte are removed before tracing. Slopcamera also
20
+ * evaluates an alpha-preserving candidate when the removed mass is material.
21
+ */
22
+ readonly alphaCutoff?: number
23
+ /** Directory used for the checksum-pinned VTracer binary. */
24
+ readonly cacheDirectory?: string
25
+ /** Replace traced colors with a primary and secondary color. */
26
+ readonly duotone?: readonly [primary: string, secondary: string]
27
+ /**
28
+ * Advanced host authority inherited by the isolated worker and tracer.
29
+ * At most sixteen unique open descriptors are accepted. Values are never
30
+ * recorded in provenance or receipts.
31
+ */
32
+ readonly inheritedFileDescriptors?: readonly number[]
33
+ /** Bound a conversion more tightly than the package hard limits. */
34
+ readonly limits?: Partial<VectorizeLimits>
35
+ /** Atomically replace this file after every quality gate succeeds. */
36
+ readonly outputPath?: string
37
+ }
38
+
39
+ export type VectorizeErrorCode =
40
+ | "input_limit"
41
+ | "invalid_input"
42
+ | "output_limit"
43
+ | "quality_limit"
44
+ | "timeout"
45
+ | "tool_download"
46
+ | "tool_integrity"
47
+ | "tool_platform"
48
+ | "tool_version"
49
+ | "trace_failed"
50
+ | "unsafe_svg"
51
+
52
+ export class VectorizeError extends Error {
53
+ readonly code: VectorizeErrorCode
54
+ readonly details: Readonly<Record<string, unknown>>
55
+
56
+ constructor(
57
+ code: VectorizeErrorCode,
58
+ message: string,
59
+ details: Readonly<Record<string, unknown>> = {},
60
+ options?: ErrorOptions,
61
+ ) {
62
+ super(message, options)
63
+ this.name = "VectorizeError"
64
+ this.code = code
65
+ this.details = details
66
+ }
67
+ }
68
+
69
+ export interface VectorizeQualityReceipt {
70
+ readonly alphaRmse: number
71
+ readonly colorRmse: number
72
+ readonly outsideAlphaRatio: number
73
+ readonly sampleHeight: number
74
+ readonly sampleWidth: number
75
+ readonly supportRecall: number
76
+ }
77
+
78
+ export interface VectorizeProvenance {
79
+ readonly arch: NodeJS.Architecture
80
+ readonly platform: NodeJS.Platform
81
+ readonly sharp: string
82
+ /** Sorted version metadata reported by the loaded Sharp runtime. */
83
+ readonly sharpVersions: Readonly<Record<string, string>>
84
+ readonly vips: string
85
+ readonly vtracerSha256: string
86
+ readonly vtracerSource: "official-release" | "override"
87
+ readonly vtracerVersion: string
88
+ }
89
+
90
+ export interface VectorizeReceipt {
91
+ readonly alphaCutoff: number
92
+ readonly bytes: number
93
+ readonly candidatesEvaluated: number
94
+ readonly format: string
95
+ readonly height: number
96
+ readonly inputBytes: number
97
+ readonly outputMode: VectorizeOutputMode
98
+ readonly pathCount: number
99
+ readonly profile: VectorizeProfile
100
+ readonly provenance: VectorizeProvenance
101
+ readonly quality: VectorizeQualityReceipt
102
+ readonly receiptVersion: 1
103
+ readonly representation: VectorizeRepresentation
104
+ readonly sourceSha256: string
105
+ readonly svgSha256: string
106
+ readonly width: number
107
+ }
108
+
109
+ export interface VectorizeResult {
110
+ readonly outputPath: string | null
111
+ readonly receipt: VectorizeReceipt
112
+ readonly svg: string
113
+ }