@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,676 @@
1
+ import type {
2
+ Easing,
3
+ ProjectCameraKeyframe,
4
+ ProjectCameraSegment,
5
+ ProjectPlacementId,
6
+ ProjectStreamId,
7
+ Rect,
8
+ SourceInterval,
9
+ } from "../contracts";
10
+ import { evaluateEasingProgress } from "./project-camera";
11
+
12
+ export interface ProjectCameraSpatialLayer {
13
+ readonly keyframeGroups: readonly Readonly<{
14
+ readonly keyframes: readonly ProjectCameraKeyframe[];
15
+ readonly zoomId: ProjectCameraKeyframe["zoomId"];
16
+ }>[];
17
+ readonly segments: readonly ProjectCameraSegment[];
18
+ }
19
+
20
+ export type ProjectCameraSpatialIndex = ReadonlyMap<
21
+ string,
22
+ ProjectCameraSpatialLayer
23
+ >;
24
+
25
+ export interface ProjectCameraSpatialAlgebra<Value> {
26
+ readonly add: (left: Value, right: Value) => Value;
27
+ readonly constant: (value: number) => Value;
28
+ readonly divide: (left: Value, right: Value) => Value;
29
+ readonly easing: (
30
+ easing: Easing,
31
+ progress: Value,
32
+ ) => Value;
33
+ readonly exponential: (value: Value) => Value;
34
+ readonly maximum: (left: Value, right: Value) => Value;
35
+ readonly minimum: (left: Value, right: Value) => Value;
36
+ readonly multiply: (left: Value, right: Value) => Value;
37
+ readonly selectRange: (
38
+ clock: Value,
39
+ range: SourceInterval,
40
+ end: "inclusive" | "exclusive",
41
+ active: Value,
42
+ fallback: Value,
43
+ ) => Value;
44
+ readonly subtract: (left: Value, right: Value) => Value;
45
+ }
46
+
47
+ export interface ProjectCameraSpatialViewport<Value> {
48
+ readonly height: Value;
49
+ readonly width: Value;
50
+ readonly x: Value;
51
+ readonly y: Value;
52
+ }
53
+
54
+ function cameraLayerKey(
55
+ placementId: ProjectPlacementId | string,
56
+ streamId: ProjectStreamId | string,
57
+ ): string {
58
+ return `${placementId}\u0000${streamId}`;
59
+ }
60
+
61
+ /**
62
+ * Prepare immutable, deterministically ordered camera paths once. The same
63
+ * layer program is evaluated numerically for metadata and symbolically for
64
+ * FFmpeg, preventing those two spatial pipelines from drifting apart.
65
+ */
66
+ export function buildProjectCameraSpatialIndex(
67
+ input: Readonly<{
68
+ readonly cameraKeyframes: readonly ProjectCameraKeyframe[];
69
+ readonly cameraSegments: readonly ProjectCameraSegment[];
70
+ }>,
71
+ ): ProjectCameraSpatialIndex {
72
+ const mutable = new Map<string, {
73
+ keyframes: ProjectCameraKeyframe[];
74
+ segments: ProjectCameraSegment[];
75
+ }>();
76
+ for (const keyframe of input.cameraKeyframes) {
77
+ const key = cameraLayerKey(keyframe.placementId, keyframe.streamId);
78
+ const layer = mutable.get(key) ?? { keyframes: [], segments: [] };
79
+ layer.keyframes.push(keyframe);
80
+ mutable.set(key, layer);
81
+ }
82
+ for (const segment of input.cameraSegments) {
83
+ const key = cameraLayerKey(segment.placementId, segment.streamId);
84
+ const layer = mutable.get(key) ?? { keyframes: [], segments: [] };
85
+ layer.segments.push(segment);
86
+ mutable.set(key, layer);
87
+ }
88
+
89
+ const prepared = new Map<string, ProjectCameraSpatialLayer>();
90
+ for (const [key, layer] of mutable) {
91
+ const byZoom = new Map<
92
+ ProjectCameraKeyframe["zoomId"],
93
+ ProjectCameraKeyframe[]
94
+ >();
95
+ for (const keyframe of layer.keyframes) {
96
+ const group = byZoom.get(keyframe.zoomId) ?? [];
97
+ group.push(keyframe);
98
+ byZoom.set(keyframe.zoomId, group);
99
+ }
100
+ const keyframeGroups = [...byZoom.entries()].map((
101
+ [zoomId, keyframes],
102
+ ) => ({
103
+ keyframes: keyframes.sort((left, right) => (
104
+ left.outputTimeUs - right.outputTimeUs
105
+ )),
106
+ zoomId,
107
+ })).sort((left, right) => (
108
+ left.keyframes[0]!.outputTimeUs - right.keyframes[0]!.outputTimeUs
109
+ || left.zoomId.localeCompare(right.zoomId)
110
+ ));
111
+ layer.segments.sort((left, right) => (
112
+ left.outputRange.startUs - right.outputRange.startUs
113
+ || left.outputRange.endUs - right.outputRange.endUs
114
+ || left.projectRange.startUs - right.projectRange.startUs
115
+ || left.cameraMoveId.localeCompare(right.cameraMoveId)
116
+ ));
117
+ prepared.set(key, {
118
+ keyframeGroups,
119
+ segments: layer.segments,
120
+ });
121
+ }
122
+ return prepared;
123
+ }
124
+
125
+ export function projectCameraSpatialLayer(
126
+ index: ProjectCameraSpatialIndex,
127
+ placementId: ProjectPlacementId | string,
128
+ streamId: ProjectStreamId | string,
129
+ ): ProjectCameraSpatialLayer | null {
130
+ return index.get(cameraLayerKey(placementId, streamId)) ?? null;
131
+ }
132
+
133
+ export function assertProjectCameraSpatialLayerGeometry(
134
+ layer: ProjectCameraSpatialLayer | null,
135
+ pixelWidth: number,
136
+ pixelHeight: number,
137
+ label: string,
138
+ ): void {
139
+ if (layer === null) return;
140
+ const keyframesMatch = layer.keyframeGroups.every(group => (
141
+ group.keyframes.every(keyframe => (
142
+ keyframe.layerPixelWidth === pixelWidth
143
+ && keyframe.layerPixelHeight === pixelHeight
144
+ ))
145
+ ));
146
+ const segmentsMatch = layer.segments.every(segment => (
147
+ segment.layerPixelWidth === pixelWidth
148
+ && segment.layerPixelHeight === pixelHeight
149
+ ));
150
+ if (!keyframesMatch || !segmentsMatch) {
151
+ throw new TypeError(`Camera geometry no longer matches layer ${label}.`);
152
+ }
153
+ }
154
+
155
+ export function projectCameraSegmentsOverlapping(
156
+ segments: readonly ProjectCameraSegment[],
157
+ range: SourceInterval,
158
+ ): readonly ProjectCameraSegment[] {
159
+ let lower = 0;
160
+ let upper = segments.length;
161
+ while (lower < upper) {
162
+ const middle = Math.floor((lower + upper) / 2);
163
+ if (segments[middle]!.outputRange.endUs <= range.startUs) {
164
+ lower = middle + 1;
165
+ } else {
166
+ upper = middle;
167
+ }
168
+ }
169
+ const overlapping: ProjectCameraSegment[] = [];
170
+ for (let index = lower; index < segments.length; index += 1) {
171
+ const segment = segments[index]!;
172
+ if (segment.outputRange.startUs >= range.endUs) break;
173
+ overlapping.push(segment);
174
+ }
175
+ return overlapping;
176
+ }
177
+
178
+ function activeKeyframeGroupAt(
179
+ groups: ProjectCameraSpatialLayer["keyframeGroups"],
180
+ outputTimeUs: number,
181
+ ): ProjectCameraSpatialLayer["keyframeGroups"][number] | null {
182
+ let lower = 0;
183
+ let upper = groups.length;
184
+ while (lower < upper) {
185
+ const middle = Math.floor((lower + upper) / 2);
186
+ if (groups[middle]!.keyframes[0]!.outputTimeUs <= outputTimeUs) {
187
+ lower = middle + 1;
188
+ } else {
189
+ upper = middle;
190
+ }
191
+ }
192
+ const group = groups[lower - 1];
193
+ if (
194
+ group === undefined
195
+ || outputTimeUs < group.keyframes[0]!.outputTimeUs
196
+ || outputTimeUs >= group.keyframes.at(-1)!.outputTimeUs
197
+ ) {
198
+ return null;
199
+ }
200
+ let rightLower = 0;
201
+ let rightUpper = group.keyframes.length;
202
+ while (rightLower < rightUpper) {
203
+ const middle = Math.floor((rightLower + rightUpper) / 2);
204
+ if (group.keyframes[middle]!.outputTimeUs <= outputTimeUs) {
205
+ rightLower = middle + 1;
206
+ } else {
207
+ rightUpper = middle;
208
+ }
209
+ }
210
+ const rightIndex = Math.max(1, rightLower);
211
+ return {
212
+ keyframes: [
213
+ group.keyframes[rightIndex - 1]!,
214
+ group.keyframes[rightIndex]!,
215
+ ],
216
+ zoomId: group.zoomId,
217
+ };
218
+ }
219
+
220
+ function activeSegmentAt(
221
+ segments: readonly ProjectCameraSegment[],
222
+ outputTimeUs: number,
223
+ ): ProjectCameraSegment | null {
224
+ let lower = 0;
225
+ let upper = segments.length;
226
+ while (lower < upper) {
227
+ const middle = Math.floor((lower + upper) / 2);
228
+ if (segments[middle]!.outputRange.endUs <= outputTimeUs) {
229
+ lower = middle + 1;
230
+ } else {
231
+ upper = middle;
232
+ }
233
+ }
234
+ const segment = segments[lower];
235
+ if (
236
+ segment === undefined
237
+ || segment.outputRange.startUs > outputTimeUs
238
+ || outputTimeUs >= segment.outputRange.endUs
239
+ ) {
240
+ return null;
241
+ }
242
+ const projectTimeUs = segment.projectRange.startUs + (
243
+ outputTimeUs - segment.outputRange.startUs
244
+ ) * (
245
+ (segment.projectRange.endUs - segment.projectRange.startUs)
246
+ / (segment.outputRange.endUs - segment.outputRange.startUs)
247
+ );
248
+ let transformLower = 0;
249
+ let transformUpper = segment.transforms.length;
250
+ while (transformLower < transformUpper) {
251
+ const middle = Math.floor((transformLower + transformUpper) / 2);
252
+ if (
253
+ segment.transforms[middle]!.activeProjectRange.endUs
254
+ < projectTimeUs
255
+ ) {
256
+ transformLower = middle + 1;
257
+ } else {
258
+ transformUpper = middle;
259
+ }
260
+ }
261
+ const transform = segment.transforms[transformLower];
262
+ if (
263
+ transform === undefined
264
+ || transform.activeProjectRange.startUs > projectTimeUs
265
+ ) {
266
+ throw new TypeError(
267
+ `Camera segment ${segment.cameraMoveId} does not cover its output clock.`,
268
+ );
269
+ }
270
+ return {
271
+ ...segment,
272
+ transforms: [transform],
273
+ };
274
+ }
275
+
276
+ /**
277
+ * Narrow a prepared layer to the at-most-one zoom leg and camera transform
278
+ * active at a numeric output time. Project plans make both families disjoint
279
+ * per layer, so metadata evaluation stays logarithmic in the authored edit
280
+ * count instead of multiplying events by every camera move.
281
+ */
282
+ export function projectCameraSpatialLayerAtOutputTime(
283
+ layer: ProjectCameraSpatialLayer | null,
284
+ outputTimeUs: number,
285
+ ): ProjectCameraSpatialLayer | null {
286
+ if (layer === null) return null;
287
+ const keyframeGroup = activeKeyframeGroupAt(
288
+ layer.keyframeGroups,
289
+ outputTimeUs,
290
+ );
291
+ const segment = activeSegmentAt(layer.segments, outputTimeUs);
292
+ if (keyframeGroup === null && segment === null) return null;
293
+ return {
294
+ keyframeGroups: keyframeGroup === null ? [] : [keyframeGroup],
295
+ segments: segment === null ? [] : [segment],
296
+ };
297
+ }
298
+
299
+ function interpolate<Value>(
300
+ from: number,
301
+ to: number,
302
+ easing: Easing,
303
+ progress: Value,
304
+ algebra: ProjectCameraSpatialAlgebra<Value>,
305
+ ): Value {
306
+ if (from === to) return algebra.constant(from);
307
+ return algebra.add(
308
+ algebra.constant(from),
309
+ algebra.multiply(
310
+ algebra.constant(to - from),
311
+ algebra.easing(easing, progress),
312
+ ),
313
+ );
314
+ }
315
+
316
+ function clamp<Value>(
317
+ value: Value,
318
+ minimum: Value,
319
+ maximum: Value,
320
+ algebra: ProjectCameraSpatialAlgebra<Value>,
321
+ ): Value {
322
+ return algebra.minimum(maximum, algebra.maximum(minimum, value));
323
+ }
324
+
325
+ function keyframeField<Value>(
326
+ group: ProjectCameraSpatialLayer["keyframeGroups"][number],
327
+ field: keyof Rect,
328
+ outputTimeUs: Value,
329
+ algebra: ProjectCameraSpatialAlgebra<Value>,
330
+ ): Value {
331
+ const keyframes = group.keyframes;
332
+ let value = algebra.constant(keyframes.at(-1)!.viewport[field]);
333
+ for (let index = keyframes.length - 1; index > 0; index -= 1) {
334
+ const left = keyframes[index - 1]!;
335
+ const right = keyframes[index]!;
336
+ if (right.outputTimeUs <= left.outputTimeUs) continue;
337
+ const progress = algebra.divide(
338
+ algebra.subtract(
339
+ outputTimeUs,
340
+ algebra.constant(left.outputTimeUs),
341
+ ),
342
+ algebra.constant(right.outputTimeUs - left.outputTimeUs),
343
+ );
344
+ value = algebra.selectRange(
345
+ outputTimeUs,
346
+ { endUs: right.outputTimeUs, startUs: left.outputTimeUs },
347
+ "exclusive",
348
+ interpolate(
349
+ left.viewport[field],
350
+ right.viewport[field],
351
+ right.easing,
352
+ progress,
353
+ algebra,
354
+ ),
355
+ value,
356
+ );
357
+ }
358
+ return value;
359
+ }
360
+
361
+ function applyKeyframeGroups<Value>(
362
+ layer: ProjectCameraSpatialLayer,
363
+ pixelWidth: number,
364
+ pixelHeight: number,
365
+ outputTimeUs: Value,
366
+ algebra: ProjectCameraSpatialAlgebra<Value>,
367
+ ): ProjectCameraSpatialViewport<Value> {
368
+ let viewport: ProjectCameraSpatialViewport<Value> = {
369
+ height: algebra.constant(pixelHeight),
370
+ width: algebra.constant(pixelWidth),
371
+ x: algebra.constant(0),
372
+ y: algebra.constant(0),
373
+ };
374
+ for (const group of layer.keyframeGroups) {
375
+ const first = group.keyframes[0]!;
376
+ const last = group.keyframes.at(-1)!;
377
+ const range = {
378
+ endUs: last.outputTimeUs,
379
+ startUs: first.outputTimeUs,
380
+ };
381
+ viewport = {
382
+ height: algebra.selectRange(
383
+ outputTimeUs,
384
+ range,
385
+ "exclusive",
386
+ keyframeField(group, "height", outputTimeUs, algebra),
387
+ viewport.height,
388
+ ),
389
+ width: algebra.selectRange(
390
+ outputTimeUs,
391
+ range,
392
+ "exclusive",
393
+ keyframeField(group, "width", outputTimeUs, algebra),
394
+ viewport.width,
395
+ ),
396
+ x: algebra.selectRange(
397
+ outputTimeUs,
398
+ range,
399
+ "exclusive",
400
+ keyframeField(group, "x", outputTimeUs, algebra),
401
+ viewport.x,
402
+ ),
403
+ y: algebra.selectRange(
404
+ outputTimeUs,
405
+ range,
406
+ "exclusive",
407
+ keyframeField(group, "y", outputTimeUs, algebra),
408
+ viewport.y,
409
+ ),
410
+ };
411
+ }
412
+ return viewport;
413
+ }
414
+
415
+ function segmentPoseField<Value>(
416
+ segment: ProjectCameraSegment,
417
+ field: "centerX" | "centerY" | "zoom",
418
+ projectTimeUs: Value,
419
+ algebra: ProjectCameraSpatialAlgebra<Value>,
420
+ ): Value {
421
+ const last = segment.transforms.at(-1)!;
422
+ let value = algebra.constant(last.toPose[field]);
423
+ for (let index = segment.transforms.length - 1; index >= 0; index -= 1) {
424
+ const transform = segment.transforms[index]!;
425
+ const interpolation = transform.interpolationProjectRange;
426
+ const progress = algebra.divide(
427
+ algebra.subtract(
428
+ projectTimeUs,
429
+ algebra.constant(interpolation.startUs),
430
+ ),
431
+ algebra.constant(interpolation.endUs - interpolation.startUs),
432
+ );
433
+ const interpolated = field === "zoom"
434
+ ? clamp(
435
+ algebra.exponential(algebra.add(
436
+ algebra.constant(Math.log(transform.fromPose.zoom)),
437
+ algebra.multiply(
438
+ algebra.constant(
439
+ Math.log(transform.toPose.zoom)
440
+ - Math.log(transform.fromPose.zoom),
441
+ ),
442
+ algebra.easing(transform.outgoingEasing, progress),
443
+ ),
444
+ )),
445
+ algebra.constant(1),
446
+ algebra.constant(10),
447
+ algebra,
448
+ )
449
+ : interpolate(
450
+ transform.fromPose[field],
451
+ transform.toPose[field],
452
+ transform.outgoingEasing,
453
+ progress,
454
+ algebra,
455
+ );
456
+ value = algebra.selectRange(
457
+ projectTimeUs,
458
+ transform.activeProjectRange,
459
+ "inclusive",
460
+ interpolated,
461
+ value,
462
+ );
463
+ }
464
+ return value;
465
+ }
466
+
467
+ function applySegment<Value>(
468
+ viewport: ProjectCameraSpatialViewport<Value>,
469
+ segment: ProjectCameraSegment,
470
+ pixelWidth: number,
471
+ pixelHeight: number,
472
+ outputTimeUs: Value,
473
+ algebra: ProjectCameraSpatialAlgebra<Value>,
474
+ ): ProjectCameraSpatialViewport<Value> {
475
+ const projectDurationUs = (
476
+ segment.projectRange.endUs - segment.projectRange.startUs
477
+ );
478
+ const outputDurationUs = (
479
+ segment.outputRange.endUs - segment.outputRange.startUs
480
+ );
481
+ const projectTimeUs = algebra.add(
482
+ algebra.constant(segment.projectRange.startUs),
483
+ algebra.multiply(
484
+ algebra.subtract(
485
+ outputTimeUs,
486
+ algebra.constant(segment.outputRange.startUs),
487
+ ),
488
+ algebra.constant(projectDurationUs / outputDurationUs),
489
+ ),
490
+ );
491
+ const zoom = segmentPoseField(
492
+ segment,
493
+ "zoom",
494
+ projectTimeUs,
495
+ algebra,
496
+ );
497
+ const halfViewport = algebra.divide(
498
+ algebra.constant(1),
499
+ algebra.multiply(algebra.constant(2), zoom),
500
+ );
501
+ const maximumCenter = algebra.subtract(algebra.constant(1), halfViewport);
502
+ const centerX = algebra.minimum(
503
+ maximumCenter,
504
+ algebra.maximum(
505
+ halfViewport,
506
+ segmentPoseField(segment, "centerX", projectTimeUs, algebra),
507
+ ),
508
+ );
509
+ const centerY = algebra.minimum(
510
+ maximumCenter,
511
+ algebra.maximum(
512
+ halfViewport,
513
+ segmentPoseField(segment, "centerY", projectTimeUs, algebra),
514
+ ),
515
+ );
516
+ const width = algebra.divide(algebra.constant(pixelWidth), zoom);
517
+ const height = algebra.divide(algebra.constant(pixelHeight), zoom);
518
+ const active = {
519
+ height,
520
+ width,
521
+ x: algebra.subtract(
522
+ algebra.multiply(algebra.constant(pixelWidth), centerX),
523
+ algebra.divide(width, algebra.constant(2)),
524
+ ),
525
+ y: algebra.subtract(
526
+ algebra.multiply(algebra.constant(pixelHeight), centerY),
527
+ algebra.divide(height, algebra.constant(2)),
528
+ ),
529
+ };
530
+ return {
531
+ height: algebra.selectRange(
532
+ outputTimeUs,
533
+ segment.outputRange,
534
+ "exclusive",
535
+ active.height,
536
+ viewport.height,
537
+ ),
538
+ width: algebra.selectRange(
539
+ outputTimeUs,
540
+ segment.outputRange,
541
+ "exclusive",
542
+ active.width,
543
+ viewport.width,
544
+ ),
545
+ x: algebra.selectRange(
546
+ outputTimeUs,
547
+ segment.outputRange,
548
+ "exclusive",
549
+ active.x,
550
+ viewport.x,
551
+ ),
552
+ y: algebra.selectRange(
553
+ outputTimeUs,
554
+ segment.outputRange,
555
+ "exclusive",
556
+ active.y,
557
+ viewport.y,
558
+ ),
559
+ };
560
+ }
561
+
562
+ function constrainViewport<Value>(
563
+ viewport: ProjectCameraSpatialViewport<Value>,
564
+ pixelWidth: number,
565
+ pixelHeight: number,
566
+ algebra: ProjectCameraSpatialAlgebra<Value>,
567
+ ): ProjectCameraSpatialViewport<Value> {
568
+ const width = clamp(
569
+ viewport.width,
570
+ algebra.constant(pixelWidth / 10),
571
+ algebra.constant(pixelWidth),
572
+ algebra,
573
+ );
574
+ const height = clamp(
575
+ viewport.height,
576
+ algebra.constant(pixelHeight / 10),
577
+ algebra.constant(pixelHeight),
578
+ algebra,
579
+ );
580
+ return {
581
+ height,
582
+ width,
583
+ x: clamp(
584
+ viewport.x,
585
+ algebra.constant(0),
586
+ algebra.subtract(algebra.constant(pixelWidth), width),
587
+ algebra,
588
+ ),
589
+ y: clamp(
590
+ viewport.y,
591
+ algebra.constant(0),
592
+ algebra.subtract(algebra.constant(pixelHeight), height),
593
+ algebra,
594
+ ),
595
+ };
596
+ }
597
+
598
+ /**
599
+ * Evaluate the final viewport for one prepared video layer at one output
600
+ * clock value. Manual and face-derived segments intentionally override legacy
601
+ * metadata zoom keyframes while active, matching the renderer's composition.
602
+ */
603
+ export function evaluateProjectCameraSpatialViewport<Value>(
604
+ layer: ProjectCameraSpatialLayer | null,
605
+ input: Readonly<{
606
+ readonly outputTimeUs: Value;
607
+ readonly pixelHeight: number;
608
+ readonly pixelWidth: number;
609
+ }>,
610
+ algebra: ProjectCameraSpatialAlgebra<Value>,
611
+ ): ProjectCameraSpatialViewport<Value> {
612
+ if (layer === null) {
613
+ return {
614
+ height: algebra.constant(input.pixelHeight),
615
+ width: algebra.constant(input.pixelWidth),
616
+ x: algebra.constant(0),
617
+ y: algebra.constant(0),
618
+ };
619
+ }
620
+ let viewport = applyKeyframeGroups(
621
+ layer,
622
+ input.pixelWidth,
623
+ input.pixelHeight,
624
+ input.outputTimeUs,
625
+ algebra,
626
+ );
627
+ for (const segment of layer.segments) {
628
+ viewport = applySegment(
629
+ viewport,
630
+ segment,
631
+ input.pixelWidth,
632
+ input.pixelHeight,
633
+ input.outputTimeUs,
634
+ algebra,
635
+ );
636
+ }
637
+ return constrainViewport(
638
+ viewport,
639
+ input.pixelWidth,
640
+ input.pixelHeight,
641
+ algebra,
642
+ );
643
+ }
644
+
645
+ const NUMBER_ALGEBRA: ProjectCameraSpatialAlgebra<number> = {
646
+ add: (left, right) => left + right,
647
+ constant: value => value,
648
+ divide: (left, right) => left / right,
649
+ easing: evaluateEasingProgress,
650
+ exponential: Math.exp,
651
+ maximum: Math.max,
652
+ minimum: Math.min,
653
+ multiply: (left, right) => left * right,
654
+ selectRange: (clock, range, end, active, fallback) => (
655
+ clock >= range.startUs
656
+ && (end === "inclusive" ? clock <= range.endUs : clock < range.endUs)
657
+ ? active
658
+ : fallback
659
+ ),
660
+ subtract: (left, right) => left - right,
661
+ };
662
+
663
+ export function evaluateProjectCameraSpatialViewportAt(
664
+ layer: ProjectCameraSpatialLayer | null,
665
+ input: Readonly<{
666
+ readonly outputTimeUs: number;
667
+ readonly pixelHeight: number;
668
+ readonly pixelWidth: number;
669
+ }>,
670
+ ): Rect {
671
+ return evaluateProjectCameraSpatialViewport(
672
+ layer,
673
+ input,
674
+ NUMBER_ALGEBRA,
675
+ );
676
+ }