@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.
- package/LICENSE +21 -0
- package/NOTICE.md +60 -0
- package/PRIVACY.md +46 -0
- package/README.md +311 -0
- package/SECURITY.md +21 -0
- package/apps/desktop/README.md +966 -0
- package/apps/desktop/analysis/protocol.ts +223 -0
- package/apps/desktop/application/capability-binding.ts +594 -0
- package/apps/desktop/application/context.ts +97 -0
- package/apps/desktop/application/creative-iteration.ts +1385 -0
- package/apps/desktop/application/default-registry.ts +146 -0
- package/apps/desktop/application/directing-contract.ts +218 -0
- package/apps/desktop/application/directing-plan.ts +178 -0
- package/apps/desktop/application/errors.ts +18 -0
- package/apps/desktop/application/gateway-port.ts +867 -0
- package/apps/desktop/application/html-overlay-browser-runtime.ts +687 -0
- package/apps/desktop/application/html-overlay-integrity.ts +337 -0
- package/apps/desktop/application/html-overlay-renderer.ts +45 -0
- package/apps/desktop/application/index.ts +13 -0
- package/apps/desktop/application/operation-completion-checkpoint.ts +333 -0
- package/apps/desktop/application/operation-effects.ts +94 -0
- package/apps/desktop/application/operation.ts +224 -0
- package/apps/desktop/application/operations/analysis/faces.ts +244 -0
- package/apps/desktop/application/operations/analysis/music.ts +248 -0
- package/apps/desktop/application/operations/analysis/project-auto-zooms.ts +302 -0
- package/apps/desktop/application/operations/analysis/project-inactivity.ts +381 -0
- package/apps/desktop/application/operations/analysis/scenes.ts +272 -0
- package/apps/desktop/application/operations/analysis/shared.ts +202 -0
- package/apps/desktop/application/operations/derive/edit-batch.ts +967 -0
- package/apps/desktop/application/operations/derive/follow-faces.ts +454 -0
- package/apps/desktop/application/operations/edit/bind-candidate-revision.ts +91 -0
- package/apps/desktop/application/operations/edit/create-candidate-revision.ts +377 -0
- package/apps/desktop/application/operations/edit/create-revision.ts +255 -0
- package/apps/desktop/application/operations/edit/freeze-revision.ts +182 -0
- package/apps/desktop/application/operations/gateway/image.ts +41 -0
- package/apps/desktop/application/operations/gateway/index.ts +17 -0
- package/apps/desktop/application/operations/gateway/shared.ts +122 -0
- package/apps/desktop/application/operations/gateway/speech.ts +41 -0
- package/apps/desktop/application/operations/gateway/transcription.ts +42 -0
- package/apps/desktop/application/operations/gateway/video.ts +41 -0
- package/apps/desktop/application/operations/index.ts +31 -0
- package/apps/desktop/application/operations/iteration/create-candidate.ts +240 -0
- package/apps/desktop/application/operations/iteration/create-matrix.ts +117 -0
- package/apps/desktop/application/operations/iteration/select.ts +155 -0
- package/apps/desktop/application/operations/iteration/shared.ts +250 -0
- package/apps/desktop/application/operations/media/audio-effects.ts +376 -0
- package/apps/desktop/application/operations/media/binding.ts +79 -0
- package/apps/desktop/application/operations/media/capabilities.ts +112 -0
- package/apps/desktop/application/operations/media/color-grade.ts +343 -0
- package/apps/desktop/application/operations/media/html-overlay.ts +802 -0
- package/apps/desktop/application/operations/media/index.ts +8 -0
- package/apps/desktop/application/operations/media/ingest.ts +303 -0
- package/apps/desktop/application/operations/media/overlay.ts +729 -0
- package/apps/desktop/application/operations/media/shared.ts +845 -0
- package/apps/desktop/application/operations/media/transform-platform.ts +120 -0
- package/apps/desktop/application/operations/project/commit-edits.ts +2054 -0
- package/apps/desktop/application/operations/project/promote-selection.ts +495 -0
- package/apps/desktop/application/operations/project/snapshot.ts +95 -0
- package/apps/desktop/application/operations/recording/index.ts +5 -0
- package/apps/desktop/application/operations/recording/pause.ts +34 -0
- package/apps/desktop/application/operations/recording/resume.ts +34 -0
- package/apps/desktop/application/operations/recording/shared.ts +199 -0
- package/apps/desktop/application/operations/recording/start.ts +169 -0
- package/apps/desktop/application/operations/recording/stop.ts +34 -0
- package/apps/desktop/application/operations/render/bind-candidate-output.ts +324 -0
- package/apps/desktop/application/operations/render/materialize-selection.ts +322 -0
- package/apps/desktop/application/operations/render/project-caption-plan.ts +287 -0
- package/apps/desktop/application/operations/render/project-plan.ts +939 -0
- package/apps/desktop/application/operations/render/project-spatial-receipt.ts +70 -0
- package/apps/desktop/application/operations/render/project.ts +1922 -0
- package/apps/desktop/application/operations/shared.ts +67 -0
- package/apps/desktop/application/operations/slopcamera-portable.ts +1188 -0
- package/apps/desktop/application/operations/slopcamera-visuals.ts +784 -0
- package/apps/desktop/application/operations/spatial-project.ts +209 -0
- package/apps/desktop/application/operations/spatial-render.ts +415 -0
- package/apps/desktop/application/operations/spatial-scene.ts +97 -0
- package/apps/desktop/application/operations/studio.ts +143 -0
- package/apps/desktop/application/output-publication-lease.ts +163 -0
- package/apps/desktop/application/project-publication-lease.ts +233 -0
- package/apps/desktop/application/project-store.ts +196 -0
- package/apps/desktop/application/receipts.ts +533 -0
- package/apps/desktop/application/registry.ts +182 -0
- package/apps/desktop/application/spatial-assets.ts +675 -0
- package/apps/desktop/application/spatial-compositor-cadence.ts +23 -0
- package/apps/desktop/application/spatial-project-authority.ts +35 -0
- package/apps/desktop/application/spatial-project-lease.ts +126 -0
- package/apps/desktop/application/spatial-project-render-preparation.ts +225 -0
- package/apps/desktop/application/spatial-project-store.ts +286 -0
- package/apps/desktop/application/spatial-render-projection.ts +201 -0
- package/apps/desktop/application/spatial-render.ts +677 -0
- package/apps/desktop/application/spatial-spz.ts +44 -0
- package/apps/desktop/application/spatial-world-import.ts +135 -0
- package/apps/desktop/application/spatial-world-provenance.ts +46 -0
- package/apps/desktop/application/studio-port.ts +58 -0
- package/apps/desktop/application/verified-receipt-reconciliation.ts +1574 -0
- package/apps/desktop/capture/protocol.ts +689 -0
- package/apps/desktop/cli/analyzer.ts +406 -0
- package/apps/desktop/cli/args.ts +3181 -0
- package/apps/desktop/cli/asset-ingest.ts +747 -0
- package/apps/desktop/cli/atomic-render-effects.ts +210 -0
- package/apps/desktop/cli/atomic-render-platform.ts +205 -0
- package/apps/desktop/cli/atomic-render.ts +50 -0
- package/apps/desktop/cli/audio-analysis.ts +252 -0
- package/apps/desktop/cli/bounded-map.ts +39 -0
- package/apps/desktop/cli/bundle-service.ts +256 -0
- package/apps/desktop/cli/capabilities.ts +212 -0
- package/apps/desktop/cli/capture-bundle.ts +1117 -0
- package/apps/desktop/cli/command-host-resources.ts +251 -0
- package/apps/desktop/cli/commands.ts +6836 -0
- package/apps/desktop/cli/directing-blob.ts +291 -0
- package/apps/desktop/cli/directing-media.ts +517 -0
- package/apps/desktop/cli/directing-quote.ts +89 -0
- package/apps/desktop/cli/directing-service.ts +288 -0
- package/apps/desktop/cli/emoji-assets.ts +538 -0
- package/apps/desktop/cli/errors.ts +29 -0
- package/apps/desktop/cli/face-analysis-service.ts +940 -0
- package/apps/desktop/cli/filter-script.ts +76 -0
- package/apps/desktop/cli/gateway-application-port.ts +1142 -0
- package/apps/desktop/cli/gateway-credential.ts +81 -0
- package/apps/desktop/cli/gateway-media-artifacts.ts +723 -0
- package/apps/desktop/cli/gateway-media-catalog.ts +922 -0
- package/apps/desktop/cli/gateway-media-service.ts +3106 -0
- package/apps/desktop/cli/gateway-media-signature.ts +122 -0
- package/apps/desktop/cli/gateway-provider-options.ts +562 -0
- package/apps/desktop/cli/gateway-scene-provider.ts +391 -0
- package/apps/desktop/cli/help.ts +501 -0
- package/apps/desktop/cli/html-overlay-gpu.ts +97 -0
- package/apps/desktop/cli/html-overlay-renderer.ts +2478 -0
- package/apps/desktop/cli/io.ts +290 -0
- package/apps/desktop/cli/main.ts +123 -0
- package/apps/desktop/cli/media-effects-service.ts +885 -0
- package/apps/desktop/cli/media-ingest-model.ts +364 -0
- package/apps/desktop/cli/media-ingest-platform.ts +227 -0
- package/apps/desktop/cli/media-ingest-program.ts +200 -0
- package/apps/desktop/cli/media-ingest.ts +30 -0
- package/apps/desktop/cli/music-analysis-service.ts +434 -0
- package/apps/desktop/cli/mutation-lock.ts +530 -0
- package/apps/desktop/cli/native-assets.d.ts +12 -0
- package/apps/desktop/cli/native-media-runtime.macos.ts +7 -0
- package/apps/desktop/cli/overlay-playback.ts +177 -0
- package/apps/desktop/cli/paths.ts +265 -0
- package/apps/desktop/cli/portable-surface.ts +242 -0
- package/apps/desktop/cli/project-camera-receipt.ts +112 -0
- package/apps/desktop/cli/project-face-camera.ts +394 -0
- package/apps/desktop/cli/project-inactivity-service.ts +552 -0
- package/apps/desktop/cli/project-media-integrity.ts +121 -0
- package/apps/desktop/cli/project-renderer.ts +1526 -0
- package/apps/desktop/cli/project-service.ts +519 -0
- package/apps/desktop/cli/project-state-transaction.ts +520 -0
- package/apps/desktop/cli/query-limits.ts +1 -0
- package/apps/desktop/cli/recording-controller.ts +1567 -0
- package/apps/desktop/cli/recording-daemon.ts +931 -0
- package/apps/desktop/cli/recording-ref.ts +56 -0
- package/apps/desktop/cli/renamed-environment.ts +6 -0
- package/apps/desktop/cli/renderer.ts +1439 -0
- package/apps/desktop/cli/run-cli-test-helper.ts +60 -0
- package/apps/desktop/cli/scene-analysis-service.ts +879 -0
- package/apps/desktop/cli/spatial-compositor-verifier.ts +213 -0
- package/apps/desktop/cli/spatial-project-service.ts +90 -0
- package/apps/desktop/cli/spatial-scene-service.ts +105 -0
- package/apps/desktop/cli/spatial-world-service.ts +39 -0
- package/apps/desktop/cli/speech-analysis-service.ts +682 -0
- package/apps/desktop/cli/studio-assemble.ts +58 -0
- package/apps/desktop/cli/studio-command.ts +60 -0
- package/apps/desktop/cli/studio-custody.ts +60 -0
- package/apps/desktop/cli/studio-encode.ts +216 -0
- package/apps/desktop/cli/studio-exr.ts +52 -0
- package/apps/desktop/cli/studio-files.ts +179 -0
- package/apps/desktop/cli/studio-output-validation.ts +162 -0
- package/apps/desktop/cli/studio-process.ts +145 -0
- package/apps/desktop/cli/studio-runtime.ts +77 -0
- package/apps/desktop/cli/studio-scaffold.ts +70 -0
- package/apps/desktop/cli/studio-service.ts +301 -0
- package/apps/desktop/cli/studio-spatial-asset.ts +248 -0
- package/apps/desktop/cli/studio-template-names.ts +3 -0
- package/apps/desktop/cli/studio-workflow.ts +19 -0
- package/apps/desktop/cli/time.ts +25 -0
- package/apps/desktop/cli/workflow-code.ts +584 -0
- package/apps/desktop/cli/workflow-runs.ts +576 -0
- package/apps/desktop/code/advanced.ts +139 -0
- package/apps/desktop/code/application-node-planner.ts +1288 -0
- package/apps/desktop/code/compiler.ts +329 -0
- package/apps/desktop/code/contracts.ts +13 -0
- package/apps/desktop/code/creative-recipes.ts +94 -0
- package/apps/desktop/code/define-workflow.ts +115 -0
- package/apps/desktop/code/editing.ts +284 -0
- package/apps/desktop/code/file-candidate-provenance.ts +420 -0
- package/apps/desktop/code/file-candidate.ts +69 -0
- package/apps/desktop/code/graph-builder.ts +10 -0
- package/apps/desktop/code/host-resource-policy.ts +55 -0
- package/apps/desktop/code/plan-contracts.ts +159 -0
- package/apps/desktop/code/planning.ts +361 -0
- package/apps/desktop/code/public.ts +134 -0
- package/apps/desktop/code/reference-projection.ts +62 -0
- package/apps/desktop/code/run-contracts.ts +466 -0
- package/apps/desktop/code/run-store.ts +2478 -0
- package/apps/desktop/code/runtime-identity.ts +328 -0
- package/apps/desktop/code/scheduler.ts +3067 -0
- package/apps/desktop/code/semantic-builder.ts +1436 -0
- package/apps/desktop/code/source-bundle.ts +1641 -0
- package/apps/desktop/code/source-typecheck.ts +211 -0
- package/apps/desktop/code/testing.ts +79 -0
- package/apps/desktop/code/worker-client.ts +1675 -0
- package/apps/desktop/code/worker-effects.ts +141 -0
- package/apps/desktop/code/worker-entry.ts +435 -0
- package/apps/desktop/code/worker-lease-guardian.ts +179 -0
- package/apps/desktop/code/worker-process-identity.ts +484 -0
- package/apps/desktop/code/worker-protocol.ts +211 -0
- package/apps/desktop/code/workflow-effects.ts +132 -0
- package/apps/desktop/contracts/analysis.ts +949 -0
- package/apps/desktop/contracts/edit.ts +576 -0
- package/apps/desktop/contracts/index.ts +9 -0
- package/apps/desktop/contracts/media-effects.ts +139 -0
- package/apps/desktop/contracts/project-render.ts +644 -0
- package/apps/desktop/contracts/project.ts +740 -0
- package/apps/desktop/contracts/recording.ts +1434 -0
- package/apps/desktop/contracts/render.ts +334 -0
- package/apps/desktop/contracts/runtime.ts +155 -0
- package/apps/desktop/contracts/spatial-compositor.ts +58 -0
- package/apps/desktop/contracts/spatial-project.ts +159 -0
- package/apps/desktop/contracts/spatial-world.ts +48 -0
- package/apps/desktop/contracts/video-effects.ts +120 -0
- package/apps/desktop/core/alignment-apply.ts +400 -0
- package/apps/desktop/core/audio-alignment.ts +466 -0
- package/apps/desktop/core/auto-zoom.ts +209 -0
- package/apps/desktop/core/canonical-json.ts +14 -0
- package/apps/desktop/core/emoji.ts +210 -0
- package/apps/desktop/core/events.ts +409 -0
- package/apps/desktop/core/face-framing.ts +533 -0
- package/apps/desktop/core/face-tracks.ts +326 -0
- package/apps/desktop/core/inactivity.ts +137 -0
- package/apps/desktop/core/index.ts +30 -0
- package/apps/desktop/core/intervals.ts +123 -0
- package/apps/desktop/core/montage.ts +236 -0
- package/apps/desktop/core/music-analysis.ts +518 -0
- package/apps/desktop/core/plan.ts +244 -0
- package/apps/desktop/core/project-auto-zoom.ts +75 -0
- package/apps/desktop/core/project-camera-spatial.ts +676 -0
- package/apps/desktop/core/project-camera.ts +403 -0
- package/apps/desktop/core/project-captions.ts +888 -0
- package/apps/desktop/core/project-inactivity.ts +125 -0
- package/apps/desktop/core/project-metadata.ts +927 -0
- package/apps/desktop/core/project-plan.ts +375 -0
- package/apps/desktop/core/project-render-plan.ts +303 -0
- package/apps/desktop/core/project-time.ts +469 -0
- package/apps/desktop/core/render-plan.ts +442 -0
- package/apps/desktop/core/scene-cache.ts +174 -0
- package/apps/desktop/core/scene-sampling.ts +448 -0
- package/apps/desktop/core/spatial-compositor.ts +22 -0
- package/apps/desktop/core/spatial-durability.ts +99 -0
- package/apps/desktop/core/spatial-project.ts +169 -0
- package/apps/desktop/core/spatial-shot-clock.ts +32 -0
- package/apps/desktop/core/speech-analysis.ts +333 -0
- package/apps/desktop/core/storage.ts +970 -0
- package/apps/desktop/core/time-map.ts +91 -0
- package/apps/desktop/core/time.ts +61 -0
- package/apps/desktop/core/video-effects.ts +660 -0
- package/apps/desktop/dist/cli/NebulaSans-Bold-26se8aek.otf +0 -0
- package/apps/desktop/dist/cli/NebulaSans-Bold-bcz7y08t.woff2 +0 -0
- package/apps/desktop/dist/cli/NebulaSans-Book-5ax05zvn.woff2 +0 -0
- package/apps/desktop/dist/cli/NebulaSans-Book-8cenzchw.otf +0 -0
- package/apps/desktop/dist/cli/main.js +5086 -0
- package/apps/desktop/html-overlay/catalog.ts +171 -0
- package/apps/desktop/html-overlay/contracts.ts +372 -0
- package/apps/desktop/html-overlay/execution-profile.ts +77 -0
- package/apps/desktop/html-overlay/index.ts +98 -0
- package/apps/desktop/html-overlay/libraries.ts +263 -0
- package/apps/desktop/html-overlay/random.ts +49 -0
- package/apps/desktop/html-overlay/runtime.ts +813 -0
- package/apps/desktop/html-overlay/scaffolds.ts +792 -0
- package/apps/desktop/html-overlay/spark-runtime.ts +88 -0
- package/apps/desktop/html-overlay/spatial-splat-runtime.ts +60 -0
- package/apps/desktop/html-overlay/spatial.ts +720 -0
- package/apps/desktop/studio/assets/README.md +39 -0
- package/apps/desktop/studio/assets/contracts.ts +129 -0
- package/apps/desktop/studio/assets/network.ts +64 -0
- package/apps/desktop/studio/assets/poly-haven.ts +148 -0
- package/apps/desktop/studio/drivers/blender_driver.py +466 -0
- package/apps/desktop/studio/drivers/cadquery_driver.py +176 -0
- package/apps/desktop/studio/education/driver.py +308 -0
- package/apps/desktop/studio/education/lesson.py +180 -0
- package/apps/desktop/studio/education/toolkit.py +249 -0
- package/apps/desktop/workflows/chaptered-demo.ts +48 -0
- package/apps/desktop/workflows/creative-iteration.ts +107 -0
- package/apps/desktop/workflows/creative-selection.ts +92 -0
- package/apps/desktop/workflows/fragments.ts +486 -0
- package/apps/desktop/workflows/index.ts +93 -0
- package/apps/desktop/workflows/polished-screen-demo.ts +128 -0
- package/apps/desktop/workflows/scene-direction.ts +12 -0
- package/apps/desktop/workflows/social-variants.ts +75 -0
- package/apps/desktop/workflows/talking-head-cleanup.ts +53 -0
- package/dist/NebulaSans-Bold-26se8aek.otf +0 -0
- package/dist/NebulaSans-Bold-bcz7y08t.woff2 +0 -0
- package/dist/NebulaSans-Book-5ax05zvn.woff2 +0 -0
- package/dist/NebulaSans-Book-8cenzchw.otf +0 -0
- package/dist/cli.js +479 -0
- package/dist/code/advanced.js +270 -0
- package/dist/code/index.js +2240 -0
- package/dist/generate.js +24 -0
- package/dist/host-resources.js +26 -0
- package/dist/index-42zsesc1.js +2257 -0
- package/dist/index-7308egqr.js +48 -0
- package/dist/index-8txs6fkn.js +712 -0
- package/dist/index-mcy8z0br.js +192 -0
- package/dist/index-p63wavx0.js +2029 -0
- package/dist/index-r7gdhmsp.js +424 -0
- package/dist/index-sh6xbav6.js +1219 -0
- package/dist/index-z1w83f81.js +4 -0
- package/dist/index-z7239b4h.js +2363 -0
- package/dist/index-zfeg9hmw.js +2013 -0
- package/dist/index.js +241 -0
- package/dist/operations.js +29 -0
- package/dist/skill-install-dh0ntqba.js +10 -0
- package/dist/vectorize/worker.js +142 -0
- package/dist/workflow.js +16 -0
- package/docs/README.md +38 -0
- package/docs/studio.md +215 -0
- package/examples/studio/blender/README.md +26 -0
- package/examples/studio/blender/character.py +152 -0
- package/examples/studio/blender/cloth.py +101 -0
- package/examples/studio/blender/color_chart.py +29 -0
- package/examples/studio/blender/fluid.py +78 -0
- package/examples/studio/blender/import_model.py +74 -0
- package/examples/studio/blender/product.py +53 -0
- package/examples/studio/blender/shaded_street.py +481 -0
- package/examples/studio/blender/studio_scene.py +147 -0
- package/examples/studio/cadquery/README.md +13 -0
- package/examples/studio/cadquery/bracket.py +36 -0
- package/examples/studio/cadquery/import_step.py +12 -0
- package/examples/studio/education/README.md +46 -0
- package/examples/studio/education/lesson.json +99 -0
- package/examples/studio/education/scene.py +7 -0
- package/examples/studio/hybrid-scene.ts +96 -0
- package/examples/studio/native-workflow.ts +14 -0
- package/examples/studio/vgpu/README.md +64 -0
- package/examples/studio/vgpu/heat-field.mjs +290 -0
- package/package.json +304 -0
- package/packages/scene/src/index.ts +1 -0
- package/packages/scene/src/scene.ts +215 -0
- package/schema/diagram.schema.json +334 -0
- package/skills/slopcamera/SKILL.md +45 -0
- package/skills/slopcamera/agents/openai.yaml +4 -0
- package/skills/slopcamera/references/customization.md +77 -0
- package/skills/slopcamera/references/diagrams.md +153 -0
- package/skills/slopcamera/references/directed-scenes.md +42 -0
- package/skills/slopcamera/references/directing-video.md +18 -0
- package/skills/slopcamera/references/educational-video.md +26 -0
- package/skills/slopcamera/references/gateway-media.md +134 -0
- package/skills/slopcamera/references/install.md +62 -0
- package/skills/slopcamera/references/native-studio.md +31 -0
- package/skills/slopcamera/references/reference-led-3d.md +140 -0
- package/skills/slopcamera/references/rubber-stamp-examples/poster-example-1.jpg +0 -0
- package/skills/slopcamera/references/rubber-stamp-examples/poster-example-2.jpg +0 -0
- package/skills/slopcamera/references/rubber-stamp-examples/stamp-style-1.png +0 -0
- package/skills/slopcamera/references/rubber-stamp-examples/stamp-style-2.png +0 -0
- package/skills/slopcamera/references/rubber-stamp-field-notes.md +144 -0
- package/skills/slopcamera/references/vectorization.md +29 -0
- package/skills/slopcamera/references/video-projects.md +187 -0
- package/skills/slopcamera/references/visual-communication.md +120 -0
- package/skills/slopcamera/references/workflows-sdk.md +45 -0
- package/skills/slopcamera/scripts/compose-rubber-stamp-field-note.ts +229 -0
- package/src/artifacts.ts +106 -0
- package/src/assets/fonts/nebula-sans/LICENSE.txt +96 -0
- package/src/assets/fonts/nebula-sans/NebulaSans-Bold.otf +0 -0
- package/src/assets/fonts/nebula-sans/NebulaSans-Bold.woff2 +0 -0
- package/src/assets/fonts/nebula-sans/NebulaSans-Book.otf +0 -0
- package/src/assets/fonts/nebula-sans/NebulaSans-Book.woff2 +0 -0
- package/src/assets/fonts/nebula-sans/PROVENANCE.md +21 -0
- package/src/assets.d.ts +9 -0
- package/src/cli.ts +601 -0
- package/src/cloud-errors.ts +26 -0
- package/src/code/advanced.ts +10 -0
- package/src/code/boundary.ts +21 -0
- package/src/code/canonical-json.ts +129 -0
- package/src/code/compiler.ts +953 -0
- package/src/code/contracts.ts +576 -0
- package/src/code/define-workflow.ts +334 -0
- package/src/code/errors.ts +41 -0
- package/src/code/graph-builder.ts +945 -0
- package/src/code/index.ts +121 -0
- package/src/code/json-snapshot.ts +899 -0
- package/src/code/json-utf8.ts +88 -0
- package/src/code/portable-builder.ts +136 -0
- package/src/code/projection.ts +378 -0
- package/src/code/public-operations.ts +450 -0
- package/src/code/runtime.ts +580 -0
- package/src/code/sha256.ts +36 -0
- package/src/config.ts +180 -0
- package/src/desktop.ts +253 -0
- package/src/fs.ts +10 -0
- package/src/generate.ts +704 -0
- package/src/host-resource-posix.ts +161 -0
- package/src/host-resources.ts +1749 -0
- package/src/icons.ts +58 -0
- package/src/index.ts +200 -0
- package/src/label-layout.ts +130 -0
- package/src/layout.ts +413 -0
- package/src/lint.ts +127 -0
- package/src/mcp/boundary.ts +354 -0
- package/src/mcp/index.ts +33 -0
- package/src/mcp/server.ts +272 -0
- package/src/mcp/tools.ts +963 -0
- package/src/mcp/types.ts +71 -0
- package/src/operations.ts +775 -0
- package/src/parse.ts +861 -0
- package/src/process-environment.ts +17 -0
- package/src/render.ts +437 -0
- package/src/skill-install.ts +49 -0
- package/src/spatial-scene/authoring.ts +27 -0
- package/src/spatial-scene/camera-track.ts +83 -0
- package/src/spatial-scene/contracts.ts +277 -0
- package/src/spatial-scene/evaluate.ts +145 -0
- package/src/spatial-scene/gltf.ts +558 -0
- package/src/spatial-scene/identity.ts +260 -0
- package/src/spatial-scene/index.ts +10 -0
- package/src/spatial-scene/inspect.ts +68 -0
- package/src/spatial-scene/math.ts +280 -0
- package/src/spatial-scene/patch.ts +131 -0
- package/src/spatial-scene/time.ts +53 -0
- package/src/studio/contracts.ts +129 -0
- package/src/studio/index.ts +2 -0
- package/src/studio/plan.ts +156 -0
- package/src/studio/shared.ts +41 -0
- package/src/theme.ts +68 -0
- package/src/tldr.ts +474 -0
- package/src/types.ts +212 -0
- package/src/vectorize/archive.ts +101 -0
- package/src/vectorize/command.ts +797 -0
- package/src/vectorize/index.ts +27 -0
- package/src/vectorize/limits.ts +61 -0
- package/src/vectorize/metrics.ts +351 -0
- package/src/vectorize/pixels.ts +323 -0
- package/src/vectorize/supervisor.ts +339 -0
- package/src/vectorize/svg.ts +188 -0
- package/src/vectorize/tool.ts +542 -0
- package/src/vectorize/types.ts +113 -0
- package/src/vectorize/vectorize.ts +634 -0
- package/src/vectorize/worker-protocol.ts +40 -0
- package/src/vectorize/worker.ts +209 -0
- package/src/version.ts +1 -0
- package/src/workflow.ts +409 -0
|
@@ -0,0 +1,967 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
CameraMoveIdSchema,
|
|
5
|
+
ClickEffectSchema,
|
|
6
|
+
CursorEffectSchema,
|
|
7
|
+
EasingSchema,
|
|
8
|
+
KeystrokeEffectSchema,
|
|
9
|
+
OverlayIdSchema,
|
|
10
|
+
OverlayOperationSchema,
|
|
11
|
+
ProjectCameraTransformKeyframeSchema,
|
|
12
|
+
ProjectPlacementIdSchema,
|
|
13
|
+
ProjectStreamIdSchema,
|
|
14
|
+
ProjectZoomOperationSchema,
|
|
15
|
+
Sha256Schema,
|
|
16
|
+
SourceIntervalSchema,
|
|
17
|
+
TypedTextEffectSchema,
|
|
18
|
+
ZoomIdSchema,
|
|
19
|
+
ZoomTargetSchema,
|
|
20
|
+
} from "../../../contracts";
|
|
21
|
+
import { canonicalJsonSha256 } from "../../../core/canonical-json";
|
|
22
|
+
import type { OperationDefinition } from "../../operation";
|
|
23
|
+
import { throwIfAborted } from "../shared";
|
|
24
|
+
|
|
25
|
+
export const OrderedProjectEditSchema = z.discriminatedUnion("kind", [
|
|
26
|
+
z.strictObject({
|
|
27
|
+
kind: z.literal("cut"),
|
|
28
|
+
range: SourceIntervalSchema,
|
|
29
|
+
}),
|
|
30
|
+
z.strictObject({
|
|
31
|
+
kind: z.literal("trim"),
|
|
32
|
+
range: SourceIntervalSchema,
|
|
33
|
+
}),
|
|
34
|
+
z.strictObject({
|
|
35
|
+
kind: z.literal("speed"),
|
|
36
|
+
range: SourceIntervalSchema,
|
|
37
|
+
rate: z.number().finite().positive().max(64),
|
|
38
|
+
}),
|
|
39
|
+
z.strictObject({
|
|
40
|
+
kind: z.literal("add-zooms"),
|
|
41
|
+
zooms: z.array(ProjectZoomOperationSchema).min(1).max(10_000),
|
|
42
|
+
}),
|
|
43
|
+
z.strictObject({
|
|
44
|
+
kind: z.literal("add-overlays"),
|
|
45
|
+
overlays: z.array(OverlayOperationSchema).min(1).max(10_000),
|
|
46
|
+
}),
|
|
47
|
+
z.strictObject({
|
|
48
|
+
kind: z.literal("remove-overlays"),
|
|
49
|
+
overlayIds: z.array(OverlayIdSchema).min(1).max(10_000),
|
|
50
|
+
}),
|
|
51
|
+
]).superRefine((edit, context) => {
|
|
52
|
+
if (
|
|
53
|
+
edit.kind === "add-overlays"
|
|
54
|
+
&& new Set(edit.overlays.map(overlay => overlay.overlayId)).size
|
|
55
|
+
!== edit.overlays.length
|
|
56
|
+
) {
|
|
57
|
+
context.addIssue({
|
|
58
|
+
code: "custom",
|
|
59
|
+
message: "One add-overlays edit cannot contain duplicate overlay IDs.",
|
|
60
|
+
path: ["overlays"],
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
if (
|
|
64
|
+
edit.kind === "remove-overlays"
|
|
65
|
+
&& new Set(edit.overlayIds).size !== edit.overlayIds.length
|
|
66
|
+
) {
|
|
67
|
+
context.addIssue({
|
|
68
|
+
code: "custom",
|
|
69
|
+
message: "One remove-overlays edit cannot contain duplicate overlay IDs.",
|
|
70
|
+
path: ["overlayIds"],
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
function refineOrderedOverlayTransitions(
|
|
76
|
+
ordered: readonly (
|
|
77
|
+
| {
|
|
78
|
+
readonly kind: "add-overlays";
|
|
79
|
+
readonly overlays: readonly { readonly overlayId: string }[];
|
|
80
|
+
}
|
|
81
|
+
| {
|
|
82
|
+
readonly kind: "remove-overlays";
|
|
83
|
+
readonly overlayIds: readonly string[];
|
|
84
|
+
}
|
|
85
|
+
)[],
|
|
86
|
+
context: z.RefinementCtx,
|
|
87
|
+
): void {
|
|
88
|
+
const added = new Set<string>();
|
|
89
|
+
for (const [editIndex, edit] of ordered.entries()) {
|
|
90
|
+
if (edit.kind === "remove-overlays") {
|
|
91
|
+
for (const overlayId of edit.overlayIds) added.delete(overlayId);
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
if (edit.kind !== "add-overlays") continue;
|
|
95
|
+
for (const [overlayIndex, overlay] of edit.overlays.entries()) {
|
|
96
|
+
if (added.has(overlay.overlayId)) {
|
|
97
|
+
context.addIssue({
|
|
98
|
+
code: "custom",
|
|
99
|
+
message:
|
|
100
|
+
"An ordered edit batch cannot add the same overlay ID twice without removing it between additions.",
|
|
101
|
+
path: ["ordered", editIndex, "overlays", overlayIndex, "overlayId"],
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
added.add(overlay.overlayId);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export const ProjectEditBatchInputSchema = z.strictObject({
|
|
110
|
+
cutRanges: z.array(SourceIntervalSchema).max(10_000).optional(),
|
|
111
|
+
ordered: z.array(OrderedProjectEditSchema).max(10_000).optional(),
|
|
112
|
+
}).superRefine((input, context) => {
|
|
113
|
+
const total = (input.cutRanges?.length ?? 0) + (input.ordered?.reduce(
|
|
114
|
+
(sum, edit) => {
|
|
115
|
+
switch (edit.kind) {
|
|
116
|
+
case "add-zooms":
|
|
117
|
+
return sum + edit.zooms.length;
|
|
118
|
+
case "add-overlays":
|
|
119
|
+
return sum + edit.overlays.length;
|
|
120
|
+
case "remove-overlays":
|
|
121
|
+
return sum + edit.overlayIds.length;
|
|
122
|
+
case "cut":
|
|
123
|
+
case "speed":
|
|
124
|
+
case "trim":
|
|
125
|
+
return sum + 1;
|
|
126
|
+
default: {
|
|
127
|
+
const exhaustive: never = edit;
|
|
128
|
+
return exhaustive;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
0,
|
|
133
|
+
) ?? 0);
|
|
134
|
+
if (total < 1) {
|
|
135
|
+
context.addIssue({
|
|
136
|
+
code: "custom",
|
|
137
|
+
message: "An edit batch requires at least one explicit edit or derived cut range.",
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
if (total > 10_000) {
|
|
141
|
+
context.addIssue({
|
|
142
|
+
code: "custom",
|
|
143
|
+
message: "An edit batch cannot expand beyond 10,000 ordered edits.",
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
refineOrderedOverlayTransitions(
|
|
147
|
+
(input.ordered ?? []).filter(edit => (
|
|
148
|
+
edit.kind === "add-overlays" || edit.kind === "remove-overlays"
|
|
149
|
+
)),
|
|
150
|
+
context,
|
|
151
|
+
);
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
const ProjectEditBatchBodySchema = z.strictObject({
|
|
155
|
+
kind: z.union([
|
|
156
|
+
z.literal("slopcamera.project-edit-batch"),
|
|
157
|
+
z.literal("studio.project-edit-batch"),
|
|
158
|
+
]),
|
|
159
|
+
ordered: z.array(OrderedProjectEditSchema).min(1).max(10_000),
|
|
160
|
+
schemaVersion: z.literal(1),
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
export const ProjectEditBatchSchema = ProjectEditBatchBodySchema.extend({
|
|
164
|
+
sha256: Sha256Schema,
|
|
165
|
+
}).strict().superRefine((batch, context) => {
|
|
166
|
+
refineOrderedOverlayTransitions(
|
|
167
|
+
batch.ordered.filter(edit => (
|
|
168
|
+
edit.kind === "add-overlays" || edit.kind === "remove-overlays"
|
|
169
|
+
)),
|
|
170
|
+
context,
|
|
171
|
+
);
|
|
172
|
+
const actual = canonicalJsonSha256({
|
|
173
|
+
kind: batch.kind,
|
|
174
|
+
ordered: batch.ordered,
|
|
175
|
+
schemaVersion: batch.schemaVersion,
|
|
176
|
+
});
|
|
177
|
+
if (actual !== batch.sha256) {
|
|
178
|
+
context.addIssue({
|
|
179
|
+
code: "custom",
|
|
180
|
+
message: "Project edit batch hash does not match its ordered edit data.",
|
|
181
|
+
path: ["sha256"],
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
export type OrderedProjectEdit = z.infer<typeof OrderedProjectEditSchema>;
|
|
187
|
+
export type ProjectEditBatchInput = z.infer<typeof ProjectEditBatchInputSchema>;
|
|
188
|
+
export type ProjectEditBatch = z.infer<typeof ProjectEditBatchSchema>;
|
|
189
|
+
|
|
190
|
+
export function deriveProjectEditBatch(
|
|
191
|
+
orderedInput: readonly OrderedProjectEdit[],
|
|
192
|
+
): ProjectEditBatch {
|
|
193
|
+
const body = ProjectEditBatchBodySchema.parse({
|
|
194
|
+
kind: "slopcamera.project-edit-batch",
|
|
195
|
+
ordered: orderedInput,
|
|
196
|
+
schemaVersion: 1,
|
|
197
|
+
});
|
|
198
|
+
return ProjectEditBatchSchema.parse({
|
|
199
|
+
...body,
|
|
200
|
+
sha256: canonicalJsonSha256(body),
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
export const deriveEditBatchOperationDefinition = {
|
|
205
|
+
inputSchema: ProjectEditBatchInputSchema,
|
|
206
|
+
inputSchemaId: "slopcamera.operation.derive.edit-batch.input/v1",
|
|
207
|
+
kind: "derive.edit-batch",
|
|
208
|
+
lifecycle: {
|
|
209
|
+
kind: "pure",
|
|
210
|
+
execute: (context, input) => {
|
|
211
|
+
throwIfAborted(context.abortSignal);
|
|
212
|
+
return Promise.resolve(deriveProjectEditBatch([
|
|
213
|
+
...(input.cutRanges ?? []).map(range => ({ kind: "cut" as const, range })),
|
|
214
|
+
...(input.ordered ?? []),
|
|
215
|
+
]));
|
|
216
|
+
},
|
|
217
|
+
},
|
|
218
|
+
outputSchema: ProjectEditBatchSchema,
|
|
219
|
+
outputSchemaId: "slopcamera.operation.derive.edit-batch.output/v1",
|
|
220
|
+
policy: {
|
|
221
|
+
cache: "content-addressed",
|
|
222
|
+
cancellable: true,
|
|
223
|
+
effect: "pure",
|
|
224
|
+
maxDurationMs: 5_000,
|
|
225
|
+
maxFanOut: 0,
|
|
226
|
+
maxInputBytes: 16 * 1024 * 1024,
|
|
227
|
+
maxOutputBytes: 16 * 1024 * 1024,
|
|
228
|
+
preparation: [],
|
|
229
|
+
resources: [{ amount: 1, resource: "cpu" }],
|
|
230
|
+
resume: "deterministic",
|
|
231
|
+
},
|
|
232
|
+
summarize: output => ({
|
|
233
|
+
fields: {
|
|
234
|
+
edits: output.ordered.length,
|
|
235
|
+
sha256: output.sha256,
|
|
236
|
+
},
|
|
237
|
+
kind: "derive.edit-batch",
|
|
238
|
+
}),
|
|
239
|
+
version: 1,
|
|
240
|
+
} satisfies OperationDefinition<
|
|
241
|
+
"derive.edit-batch",
|
|
242
|
+
ProjectEditBatchInput,
|
|
243
|
+
ProjectEditBatch
|
|
244
|
+
>;
|
|
245
|
+
|
|
246
|
+
export const ProjectMetadataEffectsInputV2Schema = z.strictObject({
|
|
247
|
+
clicks: ClickEffectSchema,
|
|
248
|
+
cursor: CursorEffectSchema,
|
|
249
|
+
keystrokes: KeystrokeEffectSchema,
|
|
250
|
+
metadataPlacementId: ProjectPlacementIdSchema.nullable(),
|
|
251
|
+
typedText: TypedTextEffectSchema,
|
|
252
|
+
}).superRefine((effects, context) => {
|
|
253
|
+
const enabled = effects.clicks.enabled
|
|
254
|
+
|| effects.cursor.enabled
|
|
255
|
+
|| effects.keystrokes.enabled
|
|
256
|
+
|| effects.typedText.enabled;
|
|
257
|
+
if (enabled && effects.metadataPlacementId === null) {
|
|
258
|
+
context.addIssue({
|
|
259
|
+
code: "custom",
|
|
260
|
+
message: "Enabled metadata effects require a non-null metadata placement.",
|
|
261
|
+
path: ["metadataPlacementId"],
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
export const ManualProjectCameraMoveInputV2Schema = z.strictObject({
|
|
267
|
+
cameraMoveId: CameraMoveIdSchema,
|
|
268
|
+
keyframes: z.array(ProjectCameraTransformKeyframeSchema).min(2).max(4_096),
|
|
269
|
+
placementId: ProjectPlacementIdSchema,
|
|
270
|
+
projectRange: SourceIntervalSchema,
|
|
271
|
+
streamId: ProjectStreamIdSchema,
|
|
272
|
+
}).superRefine((move, context) => {
|
|
273
|
+
if (
|
|
274
|
+
move.keyframes[0]?.projectTimeUs !== move.projectRange.startUs
|
|
275
|
+
|| move.keyframes.at(-1)?.projectTimeUs !== move.projectRange.endUs
|
|
276
|
+
) {
|
|
277
|
+
context.addIssue({
|
|
278
|
+
code: "custom",
|
|
279
|
+
message: "Camera move keyframes must exactly match both project range endpoints.",
|
|
280
|
+
path: ["keyframes"],
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
for (let index = 1; index < move.keyframes.length; index += 1) {
|
|
284
|
+
if (
|
|
285
|
+
move.keyframes[index]!.projectTimeUs
|
|
286
|
+
<= move.keyframes[index - 1]!.projectTimeUs
|
|
287
|
+
) {
|
|
288
|
+
context.addIssue({
|
|
289
|
+
code: "custom",
|
|
290
|
+
message: "Camera move keyframe project times must increase strictly.",
|
|
291
|
+
path: ["keyframes", index, "projectTimeUs"],
|
|
292
|
+
});
|
|
293
|
+
break;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
const SetMetadataEffectsEditV2Schema = ProjectMetadataEffectsInputV2Schema
|
|
299
|
+
.extend({
|
|
300
|
+
kind: z.literal("set-metadata-effects"),
|
|
301
|
+
})
|
|
302
|
+
.strict();
|
|
303
|
+
|
|
304
|
+
const AddManualCameraMovesEditV2Schema = z.strictObject({
|
|
305
|
+
cameraMoves: z.array(ManualProjectCameraMoveInputV2Schema).min(1).max(4_096),
|
|
306
|
+
kind: z.literal("add-manual-camera-moves"),
|
|
307
|
+
}).superRefine((edit, context) => {
|
|
308
|
+
if (
|
|
309
|
+
new Set(edit.cameraMoves.map(move => move.cameraMoveId)).size
|
|
310
|
+
!== edit.cameraMoves.length
|
|
311
|
+
) {
|
|
312
|
+
context.addIssue({
|
|
313
|
+
code: "custom",
|
|
314
|
+
message: "One add-manual-camera-moves edit cannot contain duplicate camera move IDs.",
|
|
315
|
+
path: ["cameraMoves"],
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
const RemoveCameraMovesEditV2Schema = z.strictObject({
|
|
321
|
+
cameraMoveIds: z.array(CameraMoveIdSchema).min(1).max(4_096),
|
|
322
|
+
kind: z.literal("remove-camera-moves"),
|
|
323
|
+
}).superRefine((edit, context) => {
|
|
324
|
+
if (new Set(edit.cameraMoveIds).size !== edit.cameraMoveIds.length) {
|
|
325
|
+
context.addIssue({
|
|
326
|
+
code: "custom",
|
|
327
|
+
message: "One remove-camera-moves edit cannot contain duplicate camera move IDs.",
|
|
328
|
+
path: ["cameraMoveIds"],
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
export const OrderedProjectEditV2Schema = z.discriminatedUnion("kind", [
|
|
334
|
+
z.strictObject({
|
|
335
|
+
kind: z.literal("cut"),
|
|
336
|
+
range: SourceIntervalSchema,
|
|
337
|
+
}),
|
|
338
|
+
z.strictObject({
|
|
339
|
+
kind: z.literal("trim"),
|
|
340
|
+
range: SourceIntervalSchema,
|
|
341
|
+
}),
|
|
342
|
+
z.strictObject({
|
|
343
|
+
kind: z.literal("speed"),
|
|
344
|
+
range: SourceIntervalSchema,
|
|
345
|
+
rate: z.number().finite().positive().max(64),
|
|
346
|
+
}),
|
|
347
|
+
z.strictObject({
|
|
348
|
+
kind: z.literal("add-zooms"),
|
|
349
|
+
zooms: z.array(ProjectZoomOperationSchema).min(1).max(10_000),
|
|
350
|
+
}),
|
|
351
|
+
z.strictObject({
|
|
352
|
+
kind: z.literal("add-overlays"),
|
|
353
|
+
overlays: z.array(OverlayOperationSchema).min(1).max(10_000),
|
|
354
|
+
}),
|
|
355
|
+
z.strictObject({
|
|
356
|
+
kind: z.literal("remove-overlays"),
|
|
357
|
+
overlayIds: z.array(OverlayIdSchema).min(1).max(10_000),
|
|
358
|
+
}),
|
|
359
|
+
z.strictObject({
|
|
360
|
+
kind: z.literal("remove-zooms"),
|
|
361
|
+
zoomIds: z.array(ZoomIdSchema).min(1).max(10_000),
|
|
362
|
+
}).superRefine((edit, context) => {
|
|
363
|
+
if (new Set(edit.zoomIds).size !== edit.zoomIds.length) {
|
|
364
|
+
context.addIssue({
|
|
365
|
+
code: "custom",
|
|
366
|
+
message: "One remove-zooms edit cannot contain duplicate zoom IDs.",
|
|
367
|
+
path: ["zoomIds"],
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
}),
|
|
371
|
+
SetMetadataEffectsEditV2Schema,
|
|
372
|
+
AddManualCameraMovesEditV2Schema,
|
|
373
|
+
RemoveCameraMovesEditV2Schema,
|
|
374
|
+
]).superRefine((edit, context) => {
|
|
375
|
+
if (
|
|
376
|
+
edit.kind === "add-overlays"
|
|
377
|
+
&& new Set(edit.overlays.map(overlay => overlay.overlayId)).size
|
|
378
|
+
!== edit.overlays.length
|
|
379
|
+
) {
|
|
380
|
+
context.addIssue({
|
|
381
|
+
code: "custom",
|
|
382
|
+
message: "One add-overlays edit cannot contain duplicate overlay IDs.",
|
|
383
|
+
path: ["overlays"],
|
|
384
|
+
});
|
|
385
|
+
}
|
|
386
|
+
if (
|
|
387
|
+
edit.kind === "remove-overlays"
|
|
388
|
+
&& new Set(edit.overlayIds).size !== edit.overlayIds.length
|
|
389
|
+
) {
|
|
390
|
+
context.addIssue({
|
|
391
|
+
code: "custom",
|
|
392
|
+
message: "One remove-overlays edit cannot contain duplicate overlay IDs.",
|
|
393
|
+
path: ["overlayIds"],
|
|
394
|
+
});
|
|
395
|
+
}
|
|
396
|
+
if (
|
|
397
|
+
edit.kind === "add-zooms"
|
|
398
|
+
&& new Set(edit.zooms.map(zoom => zoom.operation.zoomId)).size
|
|
399
|
+
!== edit.zooms.length
|
|
400
|
+
) {
|
|
401
|
+
context.addIssue({
|
|
402
|
+
code: "custom",
|
|
403
|
+
message: "One add-zooms edit cannot contain duplicate zoom IDs.",
|
|
404
|
+
path: ["zooms"],
|
|
405
|
+
});
|
|
406
|
+
}
|
|
407
|
+
});
|
|
408
|
+
|
|
409
|
+
type OrderedProjectEditV2Input = z.infer<typeof OrderedProjectEditV2Schema>;
|
|
410
|
+
|
|
411
|
+
function refineOrderedV2Transitions(
|
|
412
|
+
ordered: readonly OrderedProjectEditV2Input[],
|
|
413
|
+
context: z.RefinementCtx,
|
|
414
|
+
): void {
|
|
415
|
+
const added = new Set<string>();
|
|
416
|
+
const removed = new Set<string>();
|
|
417
|
+
const addedZooms = new Set<string>();
|
|
418
|
+
const removedZooms = new Set<string>();
|
|
419
|
+
let metadataEffects = 0;
|
|
420
|
+
for (const [editIndex, edit] of ordered.entries()) {
|
|
421
|
+
if (edit.kind === "add-zooms") {
|
|
422
|
+
for (const [zoomIndex, zoom] of edit.zooms.entries()) {
|
|
423
|
+
const zoomId = zoom.operation.zoomId;
|
|
424
|
+
if (addedZooms.has(zoomId)) {
|
|
425
|
+
context.addIssue({
|
|
426
|
+
code: "custom",
|
|
427
|
+
message: "An ordered edit batch cannot add the same zoom ID twice.",
|
|
428
|
+
path: ["ordered", editIndex, "zooms", zoomIndex, "operation", "zoomId"],
|
|
429
|
+
});
|
|
430
|
+
}
|
|
431
|
+
addedZooms.add(zoomId);
|
|
432
|
+
}
|
|
433
|
+
continue;
|
|
434
|
+
}
|
|
435
|
+
if (edit.kind === "remove-zooms") {
|
|
436
|
+
for (const [zoomIndex, zoomId] of edit.zoomIds.entries()) {
|
|
437
|
+
if (removedZooms.has(zoomId)) {
|
|
438
|
+
context.addIssue({
|
|
439
|
+
code: "custom",
|
|
440
|
+
message: "An ordered edit batch cannot remove the same zoom ID twice.",
|
|
441
|
+
path: ["ordered", editIndex, "zoomIds", zoomIndex],
|
|
442
|
+
});
|
|
443
|
+
}
|
|
444
|
+
removedZooms.add(zoomId);
|
|
445
|
+
}
|
|
446
|
+
continue;
|
|
447
|
+
}
|
|
448
|
+
if (edit.kind === "set-metadata-effects") {
|
|
449
|
+
metadataEffects += 1;
|
|
450
|
+
if (metadataEffects > 1) {
|
|
451
|
+
context.addIssue({
|
|
452
|
+
code: "custom",
|
|
453
|
+
message: "An ordered edit batch can replace metadata effects only once.",
|
|
454
|
+
path: ["ordered", editIndex],
|
|
455
|
+
});
|
|
456
|
+
}
|
|
457
|
+
continue;
|
|
458
|
+
}
|
|
459
|
+
if (edit.kind === "add-manual-camera-moves") {
|
|
460
|
+
for (const [moveIndex, move] of edit.cameraMoves.entries()) {
|
|
461
|
+
if (added.has(move.cameraMoveId)) {
|
|
462
|
+
context.addIssue({
|
|
463
|
+
code: "custom",
|
|
464
|
+
message: "An ordered edit batch cannot add the same camera move ID twice.",
|
|
465
|
+
path: ["ordered", editIndex, "cameraMoves", moveIndex, "cameraMoveId"],
|
|
466
|
+
});
|
|
467
|
+
}
|
|
468
|
+
added.add(move.cameraMoveId);
|
|
469
|
+
}
|
|
470
|
+
continue;
|
|
471
|
+
}
|
|
472
|
+
if (edit.kind === "remove-camera-moves") {
|
|
473
|
+
for (const [moveIndex, cameraMoveId] of edit.cameraMoveIds.entries()) {
|
|
474
|
+
if (removed.has(cameraMoveId)) {
|
|
475
|
+
context.addIssue({
|
|
476
|
+
code: "custom",
|
|
477
|
+
message: "An ordered edit batch cannot remove the same camera move ID twice.",
|
|
478
|
+
path: ["ordered", editIndex, "cameraMoveIds", moveIndex],
|
|
479
|
+
});
|
|
480
|
+
}
|
|
481
|
+
removed.add(cameraMoveId);
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
function countV2Edits(input: {
|
|
488
|
+
readonly cutRanges?: readonly unknown[] | undefined;
|
|
489
|
+
readonly ordered?: readonly OrderedProjectEditV2Input[] | undefined;
|
|
490
|
+
}): number {
|
|
491
|
+
return (input.cutRanges?.length ?? 0) + (input.ordered?.reduce(
|
|
492
|
+
(sum, edit) => {
|
|
493
|
+
switch (edit.kind) {
|
|
494
|
+
case "add-zooms":
|
|
495
|
+
return sum + edit.zooms.length;
|
|
496
|
+
case "add-overlays":
|
|
497
|
+
return sum + edit.overlays.length;
|
|
498
|
+
case "remove-overlays":
|
|
499
|
+
return sum + edit.overlayIds.length;
|
|
500
|
+
case "remove-zooms":
|
|
501
|
+
return sum + edit.zoomIds.length;
|
|
502
|
+
case "add-manual-camera-moves":
|
|
503
|
+
return sum + edit.cameraMoves.length;
|
|
504
|
+
case "remove-camera-moves":
|
|
505
|
+
return sum + edit.cameraMoveIds.length;
|
|
506
|
+
case "cut":
|
|
507
|
+
case "set-metadata-effects":
|
|
508
|
+
case "speed":
|
|
509
|
+
case "trim":
|
|
510
|
+
return sum + 1;
|
|
511
|
+
default: {
|
|
512
|
+
const exhaustive: never = edit;
|
|
513
|
+
return exhaustive;
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
},
|
|
517
|
+
0,
|
|
518
|
+
) ?? 0);
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
export const ProjectEditBatchInputV2Schema = z.strictObject({
|
|
522
|
+
cutRanges: z.array(SourceIntervalSchema).max(10_000).optional(),
|
|
523
|
+
ordered: z.array(OrderedProjectEditV2Schema).max(10_000).optional(),
|
|
524
|
+
}).superRefine((input, context) => {
|
|
525
|
+
const total = countV2Edits(input);
|
|
526
|
+
if (total < 1) {
|
|
527
|
+
context.addIssue({
|
|
528
|
+
code: "custom",
|
|
529
|
+
message: "An edit batch requires at least one explicit edit or derived cut range.",
|
|
530
|
+
});
|
|
531
|
+
}
|
|
532
|
+
if (total > 10_000) {
|
|
533
|
+
context.addIssue({
|
|
534
|
+
code: "custom",
|
|
535
|
+
message: "An edit batch cannot expand beyond 10,000 ordered edits.",
|
|
536
|
+
});
|
|
537
|
+
}
|
|
538
|
+
refineOrderedOverlayTransitions(
|
|
539
|
+
(input.ordered ?? []).filter(edit => (
|
|
540
|
+
edit.kind === "add-overlays" || edit.kind === "remove-overlays"
|
|
541
|
+
)),
|
|
542
|
+
context,
|
|
543
|
+
);
|
|
544
|
+
refineOrderedV2Transitions(input.ordered ?? [], context);
|
|
545
|
+
});
|
|
546
|
+
|
|
547
|
+
const ProjectEditBatchBodyV2Schema = z.strictObject({
|
|
548
|
+
kind: z.union([
|
|
549
|
+
z.literal("slopcamera.project-edit-batch"),
|
|
550
|
+
z.literal("studio.project-edit-batch"),
|
|
551
|
+
]),
|
|
552
|
+
ordered: z.array(OrderedProjectEditV2Schema).min(1).max(10_000),
|
|
553
|
+
schemaVersion: z.literal(2),
|
|
554
|
+
});
|
|
555
|
+
|
|
556
|
+
export const ProjectEditBatchV2Schema = ProjectEditBatchBodyV2Schema.extend({
|
|
557
|
+
sha256: Sha256Schema,
|
|
558
|
+
}).strict().superRefine((batch, context) => {
|
|
559
|
+
refineOrderedOverlayTransitions(
|
|
560
|
+
batch.ordered.filter(edit => (
|
|
561
|
+
edit.kind === "add-overlays" || edit.kind === "remove-overlays"
|
|
562
|
+
)),
|
|
563
|
+
context,
|
|
564
|
+
);
|
|
565
|
+
refineOrderedV2Transitions(batch.ordered, context);
|
|
566
|
+
const actual = canonicalJsonSha256({
|
|
567
|
+
kind: batch.kind,
|
|
568
|
+
ordered: batch.ordered,
|
|
569
|
+
schemaVersion: batch.schemaVersion,
|
|
570
|
+
});
|
|
571
|
+
if (actual !== batch.sha256) {
|
|
572
|
+
context.addIssue({
|
|
573
|
+
code: "custom",
|
|
574
|
+
message: "Project edit batch hash does not match its ordered edit data.",
|
|
575
|
+
path: ["sha256"],
|
|
576
|
+
});
|
|
577
|
+
}
|
|
578
|
+
});
|
|
579
|
+
|
|
580
|
+
export type ProjectMetadataEffectsInputV2 = z.infer<
|
|
581
|
+
typeof ProjectMetadataEffectsInputV2Schema
|
|
582
|
+
>;
|
|
583
|
+
export type ManualProjectCameraMoveInputV2 = z.infer<
|
|
584
|
+
typeof ManualProjectCameraMoveInputV2Schema
|
|
585
|
+
>;
|
|
586
|
+
export type OrderedProjectEditV2 = z.infer<typeof OrderedProjectEditV2Schema>;
|
|
587
|
+
export type ProjectEditBatchInputV2 = z.infer<
|
|
588
|
+
typeof ProjectEditBatchInputV2Schema
|
|
589
|
+
>;
|
|
590
|
+
export type ProjectEditBatchV2 = z.infer<typeof ProjectEditBatchV2Schema>;
|
|
591
|
+
|
|
592
|
+
export function deriveProjectEditBatchV2(
|
|
593
|
+
orderedInput: readonly OrderedProjectEditV2[],
|
|
594
|
+
): ProjectEditBatchV2 {
|
|
595
|
+
const body = ProjectEditBatchBodyV2Schema.parse({
|
|
596
|
+
kind: "slopcamera.project-edit-batch",
|
|
597
|
+
ordered: orderedInput,
|
|
598
|
+
schemaVersion: 2,
|
|
599
|
+
});
|
|
600
|
+
return ProjectEditBatchV2Schema.parse({
|
|
601
|
+
...body,
|
|
602
|
+
sha256: canonicalJsonSha256(body),
|
|
603
|
+
});
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
export const deriveEditBatchOperationDefinitionV2 = {
|
|
607
|
+
inputSchema: ProjectEditBatchInputV2Schema,
|
|
608
|
+
inputSchemaId: "slopcamera.operation.derive.edit-batch.input/v2",
|
|
609
|
+
kind: "derive.edit-batch",
|
|
610
|
+
lifecycle: {
|
|
611
|
+
kind: "pure",
|
|
612
|
+
execute: (context, input) => {
|
|
613
|
+
throwIfAborted(context.abortSignal);
|
|
614
|
+
return Promise.resolve(deriveProjectEditBatchV2([
|
|
615
|
+
...(input.cutRanges ?? []).map(range => ({
|
|
616
|
+
kind: "cut" as const,
|
|
617
|
+
range,
|
|
618
|
+
})),
|
|
619
|
+
...(input.ordered ?? []),
|
|
620
|
+
]));
|
|
621
|
+
},
|
|
622
|
+
},
|
|
623
|
+
outputSchema: ProjectEditBatchV2Schema,
|
|
624
|
+
outputSchemaId: "slopcamera.operation.derive.edit-batch.output/v2",
|
|
625
|
+
policy: {
|
|
626
|
+
cache: "content-addressed",
|
|
627
|
+
cancellable: true,
|
|
628
|
+
effect: "pure",
|
|
629
|
+
maxDurationMs: 5_000,
|
|
630
|
+
maxFanOut: 0,
|
|
631
|
+
maxInputBytes: 16 * 1024 * 1024,
|
|
632
|
+
maxOutputBytes: 16 * 1024 * 1024,
|
|
633
|
+
preparation: [],
|
|
634
|
+
resources: [{ amount: 1, resource: "cpu" }],
|
|
635
|
+
resume: "deterministic",
|
|
636
|
+
},
|
|
637
|
+
summarize: output => ({
|
|
638
|
+
fields: {
|
|
639
|
+
edits: output.ordered.length,
|
|
640
|
+
sha256: output.sha256,
|
|
641
|
+
},
|
|
642
|
+
kind: "derive.edit-batch",
|
|
643
|
+
}),
|
|
644
|
+
version: 2,
|
|
645
|
+
} satisfies OperationDefinition<
|
|
646
|
+
"derive.edit-batch",
|
|
647
|
+
ProjectEditBatchInputV2,
|
|
648
|
+
ProjectEditBatchV2
|
|
649
|
+
>;
|
|
650
|
+
|
|
651
|
+
/**
|
|
652
|
+
* Editorial intent for one manual project zoom. Placement, display, recording
|
|
653
|
+
* manifest, and synchronization identities are deliberately absent here (or
|
|
654
|
+
* optional selectors): the project transaction binds them from current
|
|
655
|
+
* host-owned state before execution.
|
|
656
|
+
*/
|
|
657
|
+
export const ManualProjectZoomInputV3Schema = z.strictObject({
|
|
658
|
+
displayId: z.string().min(1).max(256).optional(),
|
|
659
|
+
easing: EasingSchema,
|
|
660
|
+
enterDurationUs: z.number().int().safe().nonnegative(),
|
|
661
|
+
exitDurationUs: z.number().int().safe().nonnegative(),
|
|
662
|
+
placementId: ProjectPlacementIdSchema.optional(),
|
|
663
|
+
range: SourceIntervalSchema,
|
|
664
|
+
scale: z.number().finite().min(1).max(10),
|
|
665
|
+
target: ZoomTargetSchema,
|
|
666
|
+
zoomId: ZoomIdSchema,
|
|
667
|
+
}).superRefine((zoom, context) => {
|
|
668
|
+
if (
|
|
669
|
+
zoom.enterDurationUs + zoom.exitDurationUs
|
|
670
|
+
> zoom.range.endUs - zoom.range.startUs
|
|
671
|
+
) {
|
|
672
|
+
context.addIssue({
|
|
673
|
+
code: "custom",
|
|
674
|
+
message: "Zoom enter and exit durations cannot exceed the zoom range.",
|
|
675
|
+
path: ["enterDurationUs"],
|
|
676
|
+
});
|
|
677
|
+
}
|
|
678
|
+
});
|
|
679
|
+
|
|
680
|
+
const AddManualZoomsEditV3Schema = z.strictObject({
|
|
681
|
+
kind: z.literal("add-manual-zooms"),
|
|
682
|
+
zooms: z.array(ManualProjectZoomInputV3Schema).min(1).max(10_000),
|
|
683
|
+
}).superRefine((edit, context) => {
|
|
684
|
+
if (
|
|
685
|
+
new Set(edit.zooms.map(zoom => zoom.zoomId)).size
|
|
686
|
+
!== edit.zooms.length
|
|
687
|
+
) {
|
|
688
|
+
context.addIssue({
|
|
689
|
+
code: "custom",
|
|
690
|
+
message: "One add-manual-zooms edit cannot contain duplicate zoom IDs.",
|
|
691
|
+
path: ["zooms"],
|
|
692
|
+
});
|
|
693
|
+
}
|
|
694
|
+
});
|
|
695
|
+
|
|
696
|
+
export const OrderedProjectEditV3Schema = z.union([
|
|
697
|
+
OrderedProjectEditV2Schema,
|
|
698
|
+
AddManualZoomsEditV3Schema,
|
|
699
|
+
]);
|
|
700
|
+
|
|
701
|
+
type OrderedProjectEditV3Input = z.infer<typeof OrderedProjectEditV3Schema>;
|
|
702
|
+
|
|
703
|
+
export type ProjectEditNormalizationPhaseV3 =
|
|
704
|
+
| "add"
|
|
705
|
+
| "metadata"
|
|
706
|
+
| "remove"
|
|
707
|
+
| "structural";
|
|
708
|
+
|
|
709
|
+
export function projectEditNormalizationPhaseV3(
|
|
710
|
+
edit: OrderedProjectEditV3Input,
|
|
711
|
+
): ProjectEditNormalizationPhaseV3 {
|
|
712
|
+
switch (edit.kind) {
|
|
713
|
+
case "cut":
|
|
714
|
+
case "speed":
|
|
715
|
+
case "trim":
|
|
716
|
+
return "structural";
|
|
717
|
+
case "add-manual-camera-moves":
|
|
718
|
+
case "add-manual-zooms":
|
|
719
|
+
case "add-overlays":
|
|
720
|
+
case "add-zooms":
|
|
721
|
+
return "add";
|
|
722
|
+
case "remove-camera-moves":
|
|
723
|
+
case "remove-overlays":
|
|
724
|
+
case "remove-zooms":
|
|
725
|
+
return "remove";
|
|
726
|
+
case "set-metadata-effects":
|
|
727
|
+
return "metadata";
|
|
728
|
+
default: {
|
|
729
|
+
const exhaustive: never = edit;
|
|
730
|
+
return exhaustive;
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
const MAX_V3_NORMALIZATION_PHASES = 64;
|
|
736
|
+
|
|
737
|
+
function countV3NormalizationPhases(input: {
|
|
738
|
+
readonly cutRanges?: readonly unknown[] | undefined;
|
|
739
|
+
readonly ordered?: readonly OrderedProjectEditV3Input[] | undefined;
|
|
740
|
+
}): number {
|
|
741
|
+
let count = input.cutRanges?.length === 0 || input.cutRanges === undefined
|
|
742
|
+
? 0
|
|
743
|
+
: 1;
|
|
744
|
+
let prior: ProjectEditNormalizationPhaseV3 | undefined = count === 0
|
|
745
|
+
? undefined
|
|
746
|
+
: "structural";
|
|
747
|
+
for (const edit of input.ordered ?? []) {
|
|
748
|
+
const phase = projectEditNormalizationPhaseV3(edit);
|
|
749
|
+
if (phase !== prior) {
|
|
750
|
+
count += 1;
|
|
751
|
+
prior = phase;
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
return count;
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
function refineOrderedV3Transitions(
|
|
758
|
+
ordered: readonly OrderedProjectEditV3Input[],
|
|
759
|
+
context: z.RefinementCtx,
|
|
760
|
+
): void {
|
|
761
|
+
refineOrderedV2Transitions(
|
|
762
|
+
ordered.filter(
|
|
763
|
+
(edit): edit is OrderedProjectEditV2Input => (
|
|
764
|
+
edit.kind !== "add-manual-zooms"
|
|
765
|
+
),
|
|
766
|
+
),
|
|
767
|
+
context,
|
|
768
|
+
);
|
|
769
|
+
const addedZooms = new Set<string>();
|
|
770
|
+
for (const [editIndex, edit] of ordered.entries()) {
|
|
771
|
+
const zooms = edit.kind === "add-zooms"
|
|
772
|
+
? edit.zooms.map(zoom => ({
|
|
773
|
+
path: ["operation", "zoomId"] as const,
|
|
774
|
+
zoomId: zoom.operation.zoomId,
|
|
775
|
+
}))
|
|
776
|
+
: edit.kind === "add-manual-zooms"
|
|
777
|
+
? edit.zooms.map(zoom => ({
|
|
778
|
+
path: ["zoomId"] as const,
|
|
779
|
+
zoomId: zoom.zoomId,
|
|
780
|
+
}))
|
|
781
|
+
: [];
|
|
782
|
+
for (const [zoomIndex, zoom] of zooms.entries()) {
|
|
783
|
+
if (addedZooms.has(zoom.zoomId)) {
|
|
784
|
+
context.addIssue({
|
|
785
|
+
code: "custom",
|
|
786
|
+
message: "An ordered edit batch cannot add the same zoom ID twice.",
|
|
787
|
+
path: [
|
|
788
|
+
"ordered",
|
|
789
|
+
editIndex,
|
|
790
|
+
"zooms",
|
|
791
|
+
zoomIndex,
|
|
792
|
+
...zoom.path,
|
|
793
|
+
],
|
|
794
|
+
});
|
|
795
|
+
}
|
|
796
|
+
addedZooms.add(zoom.zoomId);
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
function countV3Edits(input: {
|
|
802
|
+
readonly cutRanges?: readonly unknown[] | undefined;
|
|
803
|
+
readonly ordered?: readonly OrderedProjectEditV3Input[] | undefined;
|
|
804
|
+
}): number {
|
|
805
|
+
return (input.cutRanges?.length ?? 0) + (input.ordered?.reduce(
|
|
806
|
+
(sum, edit) => edit.kind === "add-manual-zooms"
|
|
807
|
+
? sum + edit.zooms.length
|
|
808
|
+
: sum + countV2Edits({ ordered: [edit] }),
|
|
809
|
+
0,
|
|
810
|
+
) ?? 0);
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
export const ProjectEditBatchInputV3Schema = z.strictObject({
|
|
814
|
+
cutRanges: z.array(SourceIntervalSchema).max(10_000).optional(),
|
|
815
|
+
ordered: z.array(OrderedProjectEditV3Schema).max(10_000).optional(),
|
|
816
|
+
}).superRefine((input, context) => {
|
|
817
|
+
const total = countV3Edits(input);
|
|
818
|
+
if (total < 1) {
|
|
819
|
+
context.addIssue({
|
|
820
|
+
code: "custom",
|
|
821
|
+
message: "An edit batch requires at least one explicit edit or derived cut range.",
|
|
822
|
+
});
|
|
823
|
+
}
|
|
824
|
+
if (total > 10_000) {
|
|
825
|
+
context.addIssue({
|
|
826
|
+
code: "custom",
|
|
827
|
+
message: "An edit batch cannot expand beyond 10,000 ordered edits.",
|
|
828
|
+
});
|
|
829
|
+
}
|
|
830
|
+
if (
|
|
831
|
+
countV3NormalizationPhases(input)
|
|
832
|
+
> MAX_V3_NORMALIZATION_PHASES
|
|
833
|
+
) {
|
|
834
|
+
context.addIssue({
|
|
835
|
+
code: "custom",
|
|
836
|
+
message:
|
|
837
|
+
`An edit batch cannot contain more than ${String(MAX_V3_NORMALIZATION_PHASES)} ordered normalization phases.`,
|
|
838
|
+
path: ["ordered"],
|
|
839
|
+
});
|
|
840
|
+
}
|
|
841
|
+
refineOrderedOverlayTransitions(
|
|
842
|
+
(input.ordered ?? []).filter(edit => (
|
|
843
|
+
edit.kind === "add-overlays" || edit.kind === "remove-overlays"
|
|
844
|
+
)),
|
|
845
|
+
context,
|
|
846
|
+
);
|
|
847
|
+
refineOrderedV3Transitions(input.ordered ?? [], context);
|
|
848
|
+
});
|
|
849
|
+
|
|
850
|
+
const ProjectEditBatchBodyV3Schema = z.strictObject({
|
|
851
|
+
kind: z.union([
|
|
852
|
+
z.literal("slopcamera.project-edit-batch"),
|
|
853
|
+
z.literal("studio.project-edit-batch"),
|
|
854
|
+
]),
|
|
855
|
+
ordered: z.array(OrderedProjectEditV3Schema).min(1).max(10_000),
|
|
856
|
+
schemaVersion: z.literal(3),
|
|
857
|
+
});
|
|
858
|
+
|
|
859
|
+
export const ProjectEditBatchV3Schema = ProjectEditBatchBodyV3Schema.extend({
|
|
860
|
+
sha256: Sha256Schema,
|
|
861
|
+
}).strict().superRefine((batch, context) => {
|
|
862
|
+
if (countV3Edits({ ordered: batch.ordered }) > 10_000) {
|
|
863
|
+
context.addIssue({
|
|
864
|
+
code: "custom",
|
|
865
|
+
message: "An edit batch cannot expand beyond 10,000 ordered edits.",
|
|
866
|
+
path: ["ordered"],
|
|
867
|
+
});
|
|
868
|
+
}
|
|
869
|
+
if (
|
|
870
|
+
countV3NormalizationPhases({ ordered: batch.ordered })
|
|
871
|
+
> MAX_V3_NORMALIZATION_PHASES
|
|
872
|
+
) {
|
|
873
|
+
context.addIssue({
|
|
874
|
+
code: "custom",
|
|
875
|
+
message:
|
|
876
|
+
`An edit batch cannot contain more than ${String(MAX_V3_NORMALIZATION_PHASES)} ordered normalization phases.`,
|
|
877
|
+
path: ["ordered"],
|
|
878
|
+
});
|
|
879
|
+
}
|
|
880
|
+
refineOrderedOverlayTransitions(
|
|
881
|
+
batch.ordered.filter(edit => (
|
|
882
|
+
edit.kind === "add-overlays" || edit.kind === "remove-overlays"
|
|
883
|
+
)),
|
|
884
|
+
context,
|
|
885
|
+
);
|
|
886
|
+
refineOrderedV3Transitions(batch.ordered, context);
|
|
887
|
+
const actual = canonicalJsonSha256({
|
|
888
|
+
kind: batch.kind,
|
|
889
|
+
ordered: batch.ordered,
|
|
890
|
+
schemaVersion: batch.schemaVersion,
|
|
891
|
+
});
|
|
892
|
+
if (actual !== batch.sha256) {
|
|
893
|
+
context.addIssue({
|
|
894
|
+
code: "custom",
|
|
895
|
+
message: "Project edit batch hash does not match its ordered edit data.",
|
|
896
|
+
path: ["sha256"],
|
|
897
|
+
});
|
|
898
|
+
}
|
|
899
|
+
});
|
|
900
|
+
|
|
901
|
+
export type ManualProjectZoomInputV3 = z.infer<
|
|
902
|
+
typeof ManualProjectZoomInputV3Schema
|
|
903
|
+
>;
|
|
904
|
+
export type OrderedProjectEditV3 = z.infer<typeof OrderedProjectEditV3Schema>;
|
|
905
|
+
export type ProjectEditBatchInputV3 = z.infer<
|
|
906
|
+
typeof ProjectEditBatchInputV3Schema
|
|
907
|
+
>;
|
|
908
|
+
export type ProjectEditBatchV3 = z.infer<typeof ProjectEditBatchV3Schema>;
|
|
909
|
+
|
|
910
|
+
export function deriveProjectEditBatchV3(
|
|
911
|
+
orderedInput: readonly OrderedProjectEditV3[],
|
|
912
|
+
): ProjectEditBatchV3 {
|
|
913
|
+
const body = ProjectEditBatchBodyV3Schema.parse({
|
|
914
|
+
kind: "slopcamera.project-edit-batch",
|
|
915
|
+
ordered: orderedInput,
|
|
916
|
+
schemaVersion: 3,
|
|
917
|
+
});
|
|
918
|
+
return ProjectEditBatchV3Schema.parse({
|
|
919
|
+
...body,
|
|
920
|
+
sha256: canonicalJsonSha256(body),
|
|
921
|
+
});
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
export const deriveEditBatchOperationDefinitionV3 = {
|
|
925
|
+
inputSchema: ProjectEditBatchInputV3Schema,
|
|
926
|
+
inputSchemaId: "slopcamera.operation.derive.edit-batch.input/v3",
|
|
927
|
+
kind: "derive.edit-batch",
|
|
928
|
+
lifecycle: {
|
|
929
|
+
kind: "pure",
|
|
930
|
+
execute: (context, input) => {
|
|
931
|
+
throwIfAborted(context.abortSignal);
|
|
932
|
+
return Promise.resolve(deriveProjectEditBatchV3([
|
|
933
|
+
...(input.cutRanges ?? []).map(range => ({
|
|
934
|
+
kind: "cut" as const,
|
|
935
|
+
range,
|
|
936
|
+
})),
|
|
937
|
+
...(input.ordered ?? []),
|
|
938
|
+
]));
|
|
939
|
+
},
|
|
940
|
+
},
|
|
941
|
+
outputSchema: ProjectEditBatchV3Schema,
|
|
942
|
+
outputSchemaId: "slopcamera.operation.derive.edit-batch.output/v3",
|
|
943
|
+
policy: {
|
|
944
|
+
cache: "content-addressed",
|
|
945
|
+
cancellable: true,
|
|
946
|
+
effect: "pure",
|
|
947
|
+
maxDurationMs: 5_000,
|
|
948
|
+
maxFanOut: 0,
|
|
949
|
+
maxInputBytes: 16 * 1024 * 1024,
|
|
950
|
+
maxOutputBytes: 16 * 1024 * 1024,
|
|
951
|
+
preparation: [],
|
|
952
|
+
resources: [{ amount: 1, resource: "cpu" }],
|
|
953
|
+
resume: "deterministic",
|
|
954
|
+
},
|
|
955
|
+
summarize: output => ({
|
|
956
|
+
fields: {
|
|
957
|
+
edits: output.ordered.length,
|
|
958
|
+
sha256: output.sha256,
|
|
959
|
+
},
|
|
960
|
+
kind: "derive.edit-batch",
|
|
961
|
+
}),
|
|
962
|
+
version: 3,
|
|
963
|
+
} satisfies OperationDefinition<
|
|
964
|
+
"derive.edit-batch",
|
|
965
|
+
ProjectEditBatchInputV3,
|
|
966
|
+
ProjectEditBatchV3
|
|
967
|
+
>;
|