@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,533 @@
1
+ import { z } from "zod";
2
+
3
+ import {
4
+ FaceAnalysisFrameResultSchema,
5
+ FaceTrackIdSchema,
6
+ NormalizedTopLeftRectSchema,
7
+ type FaceTrackId,
8
+ type NormalizedTopLeftRect,
9
+ } from "../contracts/analysis";
10
+ import { SourceIntervalSchema } from "../contracts/edit";
11
+ import { MicrosecondsSchema, type ReadonlyInferred } from "../contracts/recording";
12
+
13
+ export const PreparedLayerFaceMappingSchema = z.strictObject({
14
+ crop: z.discriminatedUnion("kind", [
15
+ z.strictObject({ kind: z.literal("none") }),
16
+ z.strictObject({
17
+ bottom: z.number().finite().min(0).max(1),
18
+ kind: z.literal("normalized-insets"),
19
+ left: z.number().finite().min(0).max(1),
20
+ right: z.number().finite().min(0).max(1),
21
+ top: z.number().finite().min(0).max(1),
22
+ }).superRefine((crop, context) => {
23
+ if (crop.left + crop.right >= 1 || crop.top + crop.bottom >= 1) {
24
+ context.addIssue({ code: "custom", message: "Prepared-layer crop must leave visible source content." });
25
+ }
26
+ }),
27
+ ]),
28
+ fit: z.enum(["contain", "cover", "fill"]),
29
+ layerPixelHeight: z.number().int().safe().positive().max(16_384),
30
+ layerPixelWidth: z.number().int().safe().positive().max(16_384),
31
+ sourceDisplayAspect: z.number().finite().positive().max(100),
32
+ }).superRefine((mapping, context) => {
33
+ if (mapping.layerPixelWidth * mapping.layerPixelHeight > 134_217_728) {
34
+ context.addIssue({ code: "custom", message: "Prepared face layer exceeds the 128-megapixel safety limit." });
35
+ }
36
+ });
37
+
38
+ export const PreparedTrackedFaceDetectionSchema = z.strictObject({
39
+ confidence: z.number().finite().min(0).max(1),
40
+ rect: NormalizedTopLeftRectSchema,
41
+ trackId: FaceTrackIdSchema,
42
+ });
43
+
44
+ export const PreparedFaceFrameSchema = z.discriminatedUnion("state", [
45
+ z.strictObject({
46
+ assetTimeUs: MicrosecondsSchema,
47
+ detections: z.array(PreparedTrackedFaceDetectionSchema).max(256),
48
+ space: z.literal("prepared-video-layer-normalized-v1"),
49
+ state: z.literal("analyzed"),
50
+ }),
51
+ z.strictObject({
52
+ assetTimeUs: MicrosecondsSchema,
53
+ errorCode: z.string().regex(/^[a-z0-9][a-z0-9-]{0,127}$/u),
54
+ space: z.literal("prepared-video-layer-normalized-v1"),
55
+ state: z.literal("failed"),
56
+ }),
57
+ ]);
58
+
59
+ export const FaceFramingGapPolicySchema = z.discriminatedUnion("kind", [
60
+ z.strictObject({ kind: z.literal("fallback") }),
61
+ z.strictObject({ kind: z.literal("fail") }),
62
+ z.strictObject({
63
+ kind: z.literal("hold"),
64
+ maximumHoldUs: MicrosecondsSchema,
65
+ whenExpired: z.enum(["fallback", "fail"]),
66
+ }),
67
+ ]);
68
+
69
+ export const FaceFramingConfigSchema = z.strictObject({
70
+ gapPolicy: FaceFramingGapPolicySchema,
71
+ headroomRatio: z.number().finite().nonnegative().max(4),
72
+ maximumZoom: z.number().finite().min(1).max(10),
73
+ paddingRatio: z.number().finite().nonnegative().max(4),
74
+ requireAllSelectedFaces: z.boolean(),
75
+ simplificationTolerance: z.number().finite().nonnegative().max(1),
76
+ smoothingTimeUs: MicrosecondsSchema,
77
+ });
78
+
79
+ export const FaceFramingInputSchema = z.strictObject({
80
+ config: FaceFramingConfigSchema,
81
+ frames: z.array(PreparedFaceFrameSchema).max(250_000),
82
+ range: SourceIntervalSchema,
83
+ trackIds: z.array(FaceTrackIdSchema).min(1).max(64),
84
+ }).superRefine((input, context) => {
85
+ if (new Set(input.trackIds).size !== input.trackIds.length) {
86
+ context.addIssue({ code: "custom", message: "Face framing track IDs must be unique." });
87
+ }
88
+ });
89
+
90
+ export const FaceFramingViewportSchema = NormalizedTopLeftRectSchema.superRefine((viewport, context) => {
91
+ if (Math.abs(viewport.width - viewport.height) > 1e-12) {
92
+ context.addIssue({ code: "custom", message: "Prepared-layer face viewport must be square in normalized space." });
93
+ }
94
+ });
95
+
96
+ export const FaceFramingKeyframeSchema = z.strictObject({
97
+ assetTimeUs: MicrosecondsSchema,
98
+ source: z.enum(["fallback", "held", "observed"]),
99
+ viewport: FaceFramingViewportSchema,
100
+ visibleTrackIds: z.array(FaceTrackIdSchema).max(64),
101
+ zoom: z.number().finite().min(1).max(10),
102
+ }).superRefine((keyframe, context) => {
103
+ if (Math.abs(keyframe.zoom * keyframe.viewport.width - 1) > 1e-9) {
104
+ context.addIssue({ code: "custom", message: "Face framing zoom must be the inverse viewport width." });
105
+ }
106
+ if (new Set(keyframe.visibleTrackIds).size !== keyframe.visibleTrackIds.length) {
107
+ context.addIssue({ code: "custom", message: "Face framing visible track IDs must be unique." });
108
+ }
109
+ });
110
+
111
+ export type PreparedLayerFaceMapping = ReadonlyInferred<typeof PreparedLayerFaceMappingSchema>;
112
+ export type PreparedTrackedFaceDetection = ReadonlyInferred<typeof PreparedTrackedFaceDetectionSchema>;
113
+ export type PreparedFaceFrame = ReadonlyInferred<typeof PreparedFaceFrameSchema>;
114
+ export type FaceFramingGapPolicy = ReadonlyInferred<typeof FaceFramingGapPolicySchema>;
115
+ export type FaceFramingConfig = ReadonlyInferred<typeof FaceFramingConfigSchema>;
116
+ export type FaceFramingInput = ReadonlyInferred<typeof FaceFramingInputSchema>;
117
+ export type FaceFramingViewport = ReadonlyInferred<typeof FaceFramingViewportSchema>;
118
+ export type FaceFramingKeyframe = ReadonlyInferred<typeof FaceFramingKeyframeSchema>;
119
+
120
+ function clamp(value: number, minimum: number, maximum: number): number {
121
+ return Math.min(maximum, Math.max(minimum, value));
122
+ }
123
+
124
+ function intersectNormalizedRects(
125
+ left: NormalizedTopLeftRect,
126
+ right: NormalizedTopLeftRect,
127
+ ): NormalizedTopLeftRect | null {
128
+ const x = Math.max(left.x, right.x);
129
+ const y = Math.max(left.y, right.y);
130
+ const endX = Math.min(left.x + left.width, right.x + right.width);
131
+ const endY = Math.min(left.y + left.height, right.y + right.height);
132
+ if (endX <= x || endY <= y) return null;
133
+ return NormalizedTopLeftRectSchema.parse({
134
+ height: endY - y,
135
+ width: endX - x,
136
+ x,
137
+ y,
138
+ });
139
+ }
140
+
141
+ /**
142
+ * Maps a canonical oriented-source face box through the exact crop and fit
143
+ * geometry used to prepare a video layer. A fully cropped or covered box
144
+ * returns null; a partial box is clipped to the visible prepared layer.
145
+ */
146
+ export function mapSourceFaceRectToPreparedLayer(
147
+ rectInput: unknown,
148
+ mappingInput: unknown,
149
+ ): NormalizedTopLeftRect | null {
150
+ const rect = NormalizedTopLeftRectSchema.parse(rectInput);
151
+ const mapping = PreparedLayerFaceMappingSchema.parse(mappingInput);
152
+ const crop = mapping.crop.kind === "none"
153
+ ? { height: 1, width: 1, x: 0, y: 0 }
154
+ : {
155
+ height: 1 - mapping.crop.top - mapping.crop.bottom,
156
+ width: 1 - mapping.crop.left - mapping.crop.right,
157
+ x: mapping.crop.left,
158
+ y: mapping.crop.top,
159
+ };
160
+ const visibleSource = intersectNormalizedRects(rect, crop);
161
+ if (visibleSource === null) return null;
162
+ const croppedFace = {
163
+ height: visibleSource.height / crop.height,
164
+ width: visibleSource.width / crop.width,
165
+ x: (visibleSource.x - crop.x) / crop.width,
166
+ y: (visibleSource.y - crop.y) / crop.height,
167
+ };
168
+ const croppedDisplayAspect = mapping.sourceDisplayAspect * crop.width / crop.height;
169
+ const layerAspect = mapping.layerPixelWidth / mapping.layerPixelHeight;
170
+
171
+ let contentHeight = 1;
172
+ let contentWidth = 1;
173
+ if (mapping.fit === "contain") {
174
+ if (croppedDisplayAspect >= layerAspect) {
175
+ contentHeight = layerAspect / croppedDisplayAspect;
176
+ } else {
177
+ contentWidth = croppedDisplayAspect / layerAspect;
178
+ }
179
+ } else if (mapping.fit === "cover") {
180
+ if (croppedDisplayAspect >= layerAspect) {
181
+ contentWidth = croppedDisplayAspect / layerAspect;
182
+ } else {
183
+ contentHeight = layerAspect / croppedDisplayAspect;
184
+ }
185
+ }
186
+
187
+ const mapped = {
188
+ height: croppedFace.height * contentHeight,
189
+ width: croppedFace.width * contentWidth,
190
+ x: (1 - contentWidth) / 2 + croppedFace.x * contentWidth,
191
+ y: (1 - contentHeight) / 2 + croppedFace.y * contentHeight,
192
+ };
193
+ const clippedX = clamp(mapped.x, 0, 1);
194
+ const clippedY = clamp(mapped.y, 0, 1);
195
+ const clippedEndX = clamp(mapped.x + mapped.width, 0, 1);
196
+ const clippedEndY = clamp(mapped.y + mapped.height, 0, 1);
197
+ if (clippedEndX <= clippedX || clippedEndY <= clippedY) return null;
198
+ return NormalizedTopLeftRectSchema.parse({
199
+ height: clippedEndY - clippedY,
200
+ width: clippedEndX - clippedX,
201
+ x: clippedX,
202
+ y: clippedY,
203
+ });
204
+ }
205
+
206
+ /**
207
+ * Computes display aspect after encoded pixel aspect ratio and orientation are
208
+ * applied to the coordinate provenance stored with face evidence.
209
+ */
210
+ export function faceCoordinateDisplayAspect(coordinateSpace: Readonly<{
211
+ pixelHeight: number;
212
+ pixelWidth: number;
213
+ rotationDegrees: 0 | 90 | 180 | 270;
214
+ sampleAspectRatio: Readonly<{ denominator: number; numerator: number }>;
215
+ }>): number {
216
+ const sampleAspectRatio = coordinateSpace.sampleAspectRatio.numerator
217
+ / coordinateSpace.sampleAspectRatio.denominator;
218
+ const swapsAxes = coordinateSpace.rotationDegrees === 90 || coordinateSpace.rotationDegrees === 270;
219
+ return swapsAxes
220
+ ? coordinateSpace.pixelWidth / (coordinateSpace.pixelHeight * sampleAspectRatio)
221
+ : (coordinateSpace.pixelWidth * sampleAspectRatio) / coordinateSpace.pixelHeight;
222
+ }
223
+
224
+ export function mapFaceResultsToPreparedLayer(
225
+ resultsInput: unknown,
226
+ mappingInput: unknown,
227
+ ): readonly PreparedFaceFrame[] {
228
+ const results = z.array(FaceAnalysisFrameResultSchema).max(250_000).parse(resultsInput);
229
+ const mapping = PreparedLayerFaceMappingSchema.parse(mappingInput);
230
+ return results.map((result): PreparedFaceFrame => {
231
+ if (result.state === "failed") {
232
+ return PreparedFaceFrameSchema.parse({
233
+ assetTimeUs: result.assetTimeUs,
234
+ errorCode: result.errorCode,
235
+ space: "prepared-video-layer-normalized-v1",
236
+ state: "failed",
237
+ });
238
+ }
239
+ return PreparedFaceFrameSchema.parse({
240
+ assetTimeUs: result.assetTimeUs,
241
+ detections: result.detections.flatMap((detection) => {
242
+ const rect = mapSourceFaceRectToPreparedLayer(detection.rect, mapping);
243
+ return rect === null ? [] : [{ confidence: detection.confidence, rect, trackId: detection.trackId }];
244
+ }),
245
+ space: "prepared-video-layer-normalized-v1",
246
+ state: "analyzed",
247
+ });
248
+ });
249
+ }
250
+
251
+ export function unionNormalizedFaceRects(
252
+ rectsInput: readonly NormalizedTopLeftRect[],
253
+ ): NormalizedTopLeftRect {
254
+ const rects = z.array(NormalizedTopLeftRectSchema).min(1).max(256).parse(rectsInput);
255
+ const x = Math.min(...rects.map(rect => rect.x));
256
+ const y = Math.min(...rects.map(rect => rect.y));
257
+ const endX = Math.max(...rects.map(rect => rect.x + rect.width));
258
+ const endY = Math.max(...rects.map(rect => rect.y + rect.height));
259
+ return NormalizedTopLeftRectSchema.parse({ height: endY - y, width: endX - x, x, y });
260
+ }
261
+
262
+ export function faceFramingViewport(
263
+ rectsInput: readonly NormalizedTopLeftRect[],
264
+ configInput: unknown,
265
+ ): FaceFramingViewport {
266
+ const config = FaceFramingConfigSchema.parse(configInput);
267
+ const union = unionNormalizedFaceRects(rectsInput);
268
+ const horizontalPadding = union.width * config.paddingRatio;
269
+ const topPadding = union.height * (config.paddingRatio + config.headroomRatio);
270
+ const bottomPadding = union.height * config.paddingRatio;
271
+ const expanded = {
272
+ height: union.height + topPadding + bottomPadding,
273
+ width: union.width + horizontalPadding * 2,
274
+ x: union.x - horizontalPadding,
275
+ y: union.y - topPadding,
276
+ };
277
+ const side = Math.min(1, Math.max(expanded.width, expanded.height, 1 / config.maximumZoom));
278
+ const centerX = clamp(expanded.x + expanded.width / 2, side / 2, 1 - side / 2);
279
+ const centerY = clamp(expanded.y + expanded.height / 2, side / 2, 1 - side / 2);
280
+ return FaceFramingViewportSchema.parse({
281
+ height: side,
282
+ width: side,
283
+ x: centerX - side / 2,
284
+ y: centerY - side / 2,
285
+ });
286
+ }
287
+
288
+ function viewportZoom(viewport: FaceFramingViewport): number {
289
+ return 1 / viewport.width;
290
+ }
291
+
292
+ function smoothViewport(
293
+ prior: FaceFramingViewport,
294
+ target: FaceFramingViewport,
295
+ elapsedUs: number,
296
+ smoothingTimeUs: number,
297
+ ): FaceFramingViewport {
298
+ if (smoothingTimeUs === 0 || elapsedUs <= 0) return target;
299
+ const alpha = 1 - Math.exp(-elapsedUs / smoothingTimeUs);
300
+ const priorCenterX = prior.x + prior.width / 2;
301
+ const priorCenterY = prior.y + prior.height / 2;
302
+ const targetCenterX = target.x + target.width / 2;
303
+ const targetCenterY = target.y + target.height / 2;
304
+ const zoom = Math.exp(
305
+ Math.log(viewportZoom(prior))
306
+ + alpha * (Math.log(viewportZoom(target)) - Math.log(viewportZoom(prior))),
307
+ );
308
+ const side = 1 / zoom;
309
+ const centerX = clamp(priorCenterX + alpha * (targetCenterX - priorCenterX), side / 2, 1 - side / 2);
310
+ const centerY = clamp(priorCenterY + alpha * (targetCenterY - priorCenterY), side / 2, 1 - side / 2);
311
+ return FaceFramingViewportSchema.parse({
312
+ height: side,
313
+ width: side,
314
+ x: centerX - side / 2,
315
+ y: centerY - side / 2,
316
+ });
317
+ }
318
+
319
+ function fallbackOrThrow(
320
+ policy: FaceFramingGapPolicy,
321
+ assetTimeUs: number,
322
+ ): "fallback" {
323
+ if (policy.kind === "fail" || (policy.kind === "hold" && policy.whenExpired === "fail")) {
324
+ throw new TypeError(`Selected face evidence is unavailable at asset time ${assetTimeUs}.`);
325
+ }
326
+ return "fallback";
327
+ }
328
+
329
+ function visibleTrackKey(keyframe: FaceFramingKeyframe): string {
330
+ return keyframe.visibleTrackIds.join("\u0000");
331
+ }
332
+
333
+ function interpolationError(
334
+ keyframes: readonly FaceFramingKeyframe[],
335
+ start: number,
336
+ end: number,
337
+ candidate: number,
338
+ ): number {
339
+ const first = keyframes[start]!;
340
+ const last = keyframes[end]!;
341
+ const current = keyframes[candidate]!;
342
+ const durationUs = last.assetTimeUs - first.assetTimeUs;
343
+ if (durationUs <= 0) return Number.POSITIVE_INFINITY;
344
+ const progress = (current.assetTimeUs - first.assetTimeUs) / durationUs;
345
+ const firstCenterX = first.viewport.x + first.viewport.width / 2;
346
+ const firstCenterY = first.viewport.y + first.viewport.height / 2;
347
+ const lastCenterX = last.viewport.x + last.viewport.width / 2;
348
+ const lastCenterY = last.viewport.y + last.viewport.height / 2;
349
+ const expectedCenterX = firstCenterX + progress * (lastCenterX - firstCenterX);
350
+ const expectedCenterY = firstCenterY + progress * (lastCenterY - firstCenterY);
351
+ const expectedLogZoom = Math.log(first.zoom) + progress * (Math.log(last.zoom) - Math.log(first.zoom));
352
+ const currentCenterX = current.viewport.x + current.viewport.width / 2;
353
+ const currentCenterY = current.viewport.y + current.viewport.height / 2;
354
+ return Math.max(
355
+ Math.abs(currentCenterX - expectedCenterX),
356
+ Math.abs(currentCenterY - expectedCenterY),
357
+ Math.abs(Math.log(current.zoom) - expectedLogZoom),
358
+ );
359
+ }
360
+
361
+ function retainSimplifiedSegment(
362
+ keyframes: readonly FaceFramingKeyframe[],
363
+ start: number,
364
+ end: number,
365
+ tolerance: number,
366
+ retained: Set<number>,
367
+ ): void {
368
+ if (end - start <= 1) return;
369
+ let furthestIndex = -1;
370
+ let furthestError = -1;
371
+ for (let index = start + 1; index < end; index += 1) {
372
+ const error = interpolationError(keyframes, start, end, index);
373
+ if (error > furthestError) {
374
+ furthestError = error;
375
+ furthestIndex = index;
376
+ }
377
+ }
378
+ if (furthestIndex < 0 || furthestError <= tolerance) return;
379
+ retained.add(furthestIndex);
380
+ retainSimplifiedSegment(keyframes, start, furthestIndex, tolerance, retained);
381
+ retainSimplifiedSegment(keyframes, furthestIndex, end, tolerance, retained);
382
+ }
383
+
384
+ export function simplifyFaceFramingKeyframes(
385
+ keyframesInput: unknown,
386
+ toleranceInput: unknown,
387
+ ): readonly FaceFramingKeyframe[] {
388
+ const keyframes = z.array(FaceFramingKeyframeSchema).max(250_002).parse(keyframesInput);
389
+ const tolerance = z.number().finite().nonnegative().max(1).parse(toleranceInput);
390
+ if (keyframes.length <= 2) return keyframes;
391
+ for (let index = 1; index < keyframes.length; index += 1) {
392
+ if (keyframes[index]!.assetTimeUs <= keyframes[index - 1]!.assetTimeUs) {
393
+ throw new TypeError("Face framing keyframe times must increase strictly.");
394
+ }
395
+ }
396
+
397
+ const mandatory = new Set<number>([0, keyframes.length - 1]);
398
+ for (let index = 1; index < keyframes.length - 1; index += 1) {
399
+ const prior = keyframes[index - 1]!;
400
+ const current = keyframes[index]!;
401
+ const next = keyframes[index + 1]!;
402
+ if (
403
+ current.source !== prior.source
404
+ || current.source !== next.source
405
+ || visibleTrackKey(current) !== visibleTrackKey(prior)
406
+ || visibleTrackKey(current) !== visibleTrackKey(next)
407
+ ) {
408
+ mandatory.add(index);
409
+ }
410
+ }
411
+
412
+ const boundaries = [...mandatory].sort((left, right) => left - right);
413
+ for (let index = 1; index < boundaries.length; index += 1) {
414
+ retainSimplifiedSegment(
415
+ keyframes,
416
+ boundaries[index - 1]!,
417
+ boundaries[index]!,
418
+ tolerance,
419
+ mandatory,
420
+ );
421
+ }
422
+ return [...mandatory].sort((left, right) => left - right).map(index => keyframes[index]!);
423
+ }
424
+
425
+ function keyframe(
426
+ assetTimeUs: number,
427
+ source: FaceFramingKeyframe["source"],
428
+ viewport: FaceFramingViewport,
429
+ visibleTrackIds: readonly FaceTrackId[],
430
+ ): FaceFramingKeyframe {
431
+ return FaceFramingKeyframeSchema.parse({
432
+ assetTimeUs,
433
+ source,
434
+ viewport,
435
+ visibleTrackIds: [...visibleTrackIds].sort((left, right) => left.localeCompare(right)),
436
+ zoom: viewportZoom(viewport),
437
+ });
438
+ }
439
+
440
+ /**
441
+ * Produces prepared-layer camera evidence. Center is smoothed linearly while
442
+ * zoom is smoothed in log space, which makes push-ins and pull-outs perceptually
443
+ * symmetric.
444
+ */
445
+ export function planFaceFraming(inputValue: unknown): readonly FaceFramingKeyframe[] {
446
+ const input = FaceFramingInputSchema.parse(inputValue);
447
+ const frames = [...input.frames]
448
+ .filter(frame => frame.assetTimeUs >= input.range.startUs && frame.assetTimeUs < input.range.endUs)
449
+ .sort((left, right) => left.assetTimeUs - right.assetTimeUs);
450
+ for (let index = 1; index < frames.length; index += 1) {
451
+ if (frames[index]!.assetTimeUs === frames[index - 1]!.assetTimeUs) {
452
+ throw new TypeError("Prepared face frame times must be unique.");
453
+ }
454
+ }
455
+ const selectedTrackIds = [...input.trackIds].sort((left, right) => left.localeCompare(right));
456
+ const selectedTrackIdSet = new Set(selectedTrackIds);
457
+ const fallbackViewport = FaceFramingViewportSchema.parse({ height: 1, width: 1, x: 0, y: 0 });
458
+ const planned: FaceFramingKeyframe[] = [];
459
+ let lastObservedViewport: FaceFramingViewport | null = null;
460
+ let lastObservedAssetTimeUs: number | null = null;
461
+
462
+ for (const frame of frames) {
463
+ const visible = frame.state === "analyzed"
464
+ ? frame.detections
465
+ .filter(detection => selectedTrackIdSet.has(detection.trackId))
466
+ .sort((left, right) => left.trackId.localeCompare(right.trackId))
467
+ : [];
468
+ const hasRequiredFaces = visible.length > 0 && (
469
+ !input.config.requireAllSelectedFaces || visible.length === selectedTrackIds.length
470
+ );
471
+ let source: FaceFramingKeyframe["source"];
472
+ let target: FaceFramingViewport;
473
+ if (hasRequiredFaces) {
474
+ target = faceFramingViewport(visible.map(detection => detection.rect), input.config);
475
+ lastObservedViewport = target;
476
+ lastObservedAssetTimeUs = frame.assetTimeUs;
477
+ source = "observed";
478
+ } else if (
479
+ input.config.gapPolicy.kind === "hold"
480
+ && lastObservedViewport !== null
481
+ && lastObservedAssetTimeUs !== null
482
+ && frame.assetTimeUs - lastObservedAssetTimeUs <= input.config.gapPolicy.maximumHoldUs
483
+ ) {
484
+ target = lastObservedViewport;
485
+ source = "held";
486
+ } else {
487
+ fallbackOrThrow(input.config.gapPolicy, frame.assetTimeUs);
488
+ target = fallbackViewport;
489
+ source = "fallback";
490
+ }
491
+
492
+ const prior = planned.at(-1);
493
+ const viewport = source === "held" || prior === undefined
494
+ ? target
495
+ : smoothViewport(
496
+ prior.viewport,
497
+ target,
498
+ frame.assetTimeUs - prior.assetTimeUs,
499
+ input.config.smoothingTimeUs,
500
+ );
501
+ planned.push(keyframe(
502
+ frame.assetTimeUs,
503
+ source,
504
+ viewport,
505
+ visible.map(detection => detection.trackId),
506
+ ));
507
+ }
508
+
509
+ if (planned.length === 0) {
510
+ fallbackOrThrow(input.config.gapPolicy, input.range.startUs);
511
+ planned.push(keyframe(input.range.startUs, "fallback", fallbackViewport, []));
512
+ } else if (planned[0]!.assetTimeUs > input.range.startUs) {
513
+ planned.unshift(keyframe(
514
+ input.range.startUs,
515
+ "held",
516
+ planned[0]!.viewport,
517
+ planned[0]!.visibleTrackIds,
518
+ ));
519
+ }
520
+ if (planned.at(-1)!.assetTimeUs < input.range.endUs) {
521
+ planned.push(keyframe(
522
+ input.range.endUs,
523
+ "held",
524
+ planned.at(-1)!.viewport,
525
+ planned.at(-1)!.visibleTrackIds,
526
+ ));
527
+ }
528
+ if (planned.length === 1) {
529
+ planned.push(keyframe(input.range.endUs, "held", planned[0]!.viewport, planned[0]!.visibleTrackIds));
530
+ }
531
+
532
+ return simplifyFaceFramingKeyframes(planned, input.config.simplificationTolerance);
533
+ }