@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,949 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import {
|
|
3
|
+
SCENE_UPLOAD_POLICY,
|
|
4
|
+
SceneDescriptionSchema,
|
|
5
|
+
} from "@hraness/slopcamera/scene";
|
|
6
|
+
|
|
7
|
+
import { SourceIntervalSchema } from "./edit";
|
|
8
|
+
import {
|
|
9
|
+
AnalysisIdSchema,
|
|
10
|
+
ProjectAssetIdSchema,
|
|
11
|
+
ProjectPlacementIdSchema,
|
|
12
|
+
ProjectStreamIdSchema,
|
|
13
|
+
VideoProjectIdSchema,
|
|
14
|
+
} from "./project";
|
|
15
|
+
import {
|
|
16
|
+
IsoTimestampSchema,
|
|
17
|
+
MicrosecondsSchema,
|
|
18
|
+
PositiveMicrosecondsSchema,
|
|
19
|
+
RecordingIdSchema,
|
|
20
|
+
RepositoryRelativePathSchema,
|
|
21
|
+
Sha256Schema,
|
|
22
|
+
type ReadonlyInferred,
|
|
23
|
+
} from "./recording";
|
|
24
|
+
|
|
25
|
+
const ANALYSIS_ID_SUFFIX = /^[a-z0-9][a-z0-9_-]{7,63}$/u;
|
|
26
|
+
|
|
27
|
+
function analysisEntityId(prefix: string) {
|
|
28
|
+
return z.string().refine(
|
|
29
|
+
value => value.startsWith(prefix) && ANALYSIS_ID_SUFFIX.test(value.slice(prefix.length)),
|
|
30
|
+
`Expected an opaque ${prefix} identifier.`,
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export const AlignmentCandidateIdSchema = analysisEntityId("candidate_").brand<"AlignmentCandidateId">();
|
|
35
|
+
export const SceneIdSchema = analysisEntityId("scene_").brand<"SceneId">();
|
|
36
|
+
export const SceneSampleIdSchema = analysisEntityId("sample_").brand<"SceneSampleId">();
|
|
37
|
+
export const FillerCandidateIdSchema = analysisEntityId("filler_").brand<"FillerCandidateId">();
|
|
38
|
+
export const FaceTrackIdSchema = analysisEntityId("face_").brand<"FaceTrackId">();
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* A unit-space rectangle after source orientation has been applied. The origin
|
|
42
|
+
* is the top-left of the displayed frame, x grows right, and y grows down.
|
|
43
|
+
*/
|
|
44
|
+
export const NormalizedTopLeftRectSchema = z.strictObject({
|
|
45
|
+
height: z.number().finite().positive().max(1),
|
|
46
|
+
width: z.number().finite().positive().max(1),
|
|
47
|
+
x: z.number().finite().min(0).max(1),
|
|
48
|
+
y: z.number().finite().min(0).max(1),
|
|
49
|
+
}).superRefine((rect, context) => {
|
|
50
|
+
if (rect.x + rect.width > 1) {
|
|
51
|
+
context.addIssue({ code: "custom", message: "Normalized rectangle exceeds the right frame edge." });
|
|
52
|
+
}
|
|
53
|
+
if (rect.y + rect.height > 1) {
|
|
54
|
+
context.addIssue({ code: "custom", message: "Normalized rectangle exceeds the bottom frame edge." });
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
export const RawFaceDetectionSchema = z.strictObject({
|
|
59
|
+
confidence: z.number().finite().min(0).max(1),
|
|
60
|
+
rect: NormalizedTopLeftRectSchema,
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
export const RawFaceDetectionFrameSchema = z.strictObject({
|
|
64
|
+
assetTimeUs: MicrosecondsSchema,
|
|
65
|
+
detections: z.array(RawFaceDetectionSchema).max(512),
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
export const RawFaceDetectionFramesSchema = z.array(RawFaceDetectionFrameSchema).max(250_000);
|
|
69
|
+
|
|
70
|
+
export const FaceTrackingConfigSchema = z.strictObject({
|
|
71
|
+
iouWeight: z.number().finite().min(0).max(1),
|
|
72
|
+
maximumCenterDistance: z.number().finite().positive().max(2),
|
|
73
|
+
maximumFacesPerFrame: z.number().int().safe().positive().max(256),
|
|
74
|
+
maximumGapUs: MicrosecondsSchema,
|
|
75
|
+
minimumConfidence: z.number().finite().min(0).max(1),
|
|
76
|
+
minimumIou: z.number().finite().min(0).max(1),
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
export const FaceAnalysisConfigSchema = z.strictObject({
|
|
80
|
+
sampleIntervalUs: PositiveMicrosecondsSchema,
|
|
81
|
+
tracking: FaceTrackingConfigSchema,
|
|
82
|
+
}).superRefine((config, context) => {
|
|
83
|
+
if (config.tracking.maximumGapUs < config.sampleIntervalUs) {
|
|
84
|
+
context.addIssue({
|
|
85
|
+
code: "custom",
|
|
86
|
+
message: "Face tracking maximumGapUs must span at least one sample interval.",
|
|
87
|
+
path: ["tracking", "maximumGapUs"],
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
export const FaceAnalysisBackendSchema = z.discriminatedUnion("kind", [
|
|
93
|
+
z.strictObject({
|
|
94
|
+
architecture: z.string().min(1).max(64),
|
|
95
|
+
kind: z.literal("apple-vision"),
|
|
96
|
+
osBuild: z.string().min(1).max(128),
|
|
97
|
+
requestRevision: z.number().int().safe().positive(),
|
|
98
|
+
runtimeVersion: z.string().min(1).max(128),
|
|
99
|
+
}),
|
|
100
|
+
z.strictObject({
|
|
101
|
+
kind: z.literal("local-model"),
|
|
102
|
+
model: z.strictObject({
|
|
103
|
+
name: z.string().min(1).max(256),
|
|
104
|
+
sha256: Sha256Schema,
|
|
105
|
+
version: z.string().min(1).max(128),
|
|
106
|
+
}),
|
|
107
|
+
runtime: z.strictObject({
|
|
108
|
+
name: z.string().min(1).max(128),
|
|
109
|
+
version: z.string().min(1).max(128),
|
|
110
|
+
}),
|
|
111
|
+
}),
|
|
112
|
+
]);
|
|
113
|
+
|
|
114
|
+
export const TrackedFaceDetectionSchema = RawFaceDetectionSchema.extend({
|
|
115
|
+
trackId: FaceTrackIdSchema,
|
|
116
|
+
}).strict();
|
|
117
|
+
|
|
118
|
+
export const FaceAnalysisFrameResultSchema = z.discriminatedUnion("state", [
|
|
119
|
+
z.strictObject({
|
|
120
|
+
assetTimeUs: MicrosecondsSchema,
|
|
121
|
+
detections: z.array(TrackedFaceDetectionSchema).max(256),
|
|
122
|
+
discardedDetections: z.number().int().safe().nonnegative().max(512),
|
|
123
|
+
state: z.literal("analyzed"),
|
|
124
|
+
}).superRefine((frame, context) => {
|
|
125
|
+
const trackIds = frame.detections.map(detection => detection.trackId);
|
|
126
|
+
if (new Set(trackIds).size !== trackIds.length) {
|
|
127
|
+
context.addIssue({ code: "custom", message: "A face track may occur only once in an analyzed frame." });
|
|
128
|
+
}
|
|
129
|
+
if (trackIds.some((trackId, index) => index > 0 && trackId <= trackIds[index - 1]!)) {
|
|
130
|
+
context.addIssue({ code: "custom", message: "Analyzed frame detections must be ordered by track ID." });
|
|
131
|
+
}
|
|
132
|
+
}),
|
|
133
|
+
z.strictObject({
|
|
134
|
+
assetTimeUs: MicrosecondsSchema,
|
|
135
|
+
errorCode: z.string().regex(/^[a-z0-9][a-z0-9-]{0,127}$/u),
|
|
136
|
+
state: z.literal("failed"),
|
|
137
|
+
}),
|
|
138
|
+
]);
|
|
139
|
+
|
|
140
|
+
export const FaceTrackSchema = z.strictObject({
|
|
141
|
+
firstSeenAssetTimeUs: MicrosecondsSchema,
|
|
142
|
+
lastSeenAssetTimeUs: MicrosecondsSchema,
|
|
143
|
+
maximumObservedGapUs: MicrosecondsSchema,
|
|
144
|
+
observationCount: z.number().int().safe().positive().max(250_000),
|
|
145
|
+
trackId: FaceTrackIdSchema,
|
|
146
|
+
}).superRefine((track, context) => {
|
|
147
|
+
if (track.lastSeenAssetTimeUs < track.firstSeenAssetTimeUs) {
|
|
148
|
+
context.addIssue({ code: "custom", message: "Face track last-seen time cannot precede first-seen time." });
|
|
149
|
+
}
|
|
150
|
+
if (track.observationCount === 1 && track.maximumObservedGapUs !== 0) {
|
|
151
|
+
context.addIssue({ code: "custom", message: "A one-observation face track cannot contain an observed gap." });
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
export const AnalysisSubjectSchema = z.strictObject({
|
|
156
|
+
assetId: ProjectAssetIdSchema,
|
|
157
|
+
integritySha256: Sha256Schema,
|
|
158
|
+
streamId: ProjectStreamIdSchema,
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
export const AnalysisToolSchema = z.strictObject({
|
|
162
|
+
name: z.string().min(1).max(128),
|
|
163
|
+
profile: z.string().min(1).max(128),
|
|
164
|
+
version: z.string().min(1).max(128),
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Immutable local face-box evidence. Track IDs describe only geometry
|
|
169
|
+
* continuity between sampled frames; they are not people or biometric
|
|
170
|
+
* identities.
|
|
171
|
+
*/
|
|
172
|
+
export const FaceAnalysisV1Schema = z.strictObject({
|
|
173
|
+
analysisId: AnalysisIdSchema,
|
|
174
|
+
backend: FaceAnalysisBackendSchema,
|
|
175
|
+
config: FaceAnalysisConfigSchema,
|
|
176
|
+
coordinateSpace: z.strictObject({
|
|
177
|
+
encodedPixelHeight: z.number().int().safe().positive().max(16_384),
|
|
178
|
+
encodedPixelWidth: z.number().int().safe().positive().max(16_384),
|
|
179
|
+
mirroredHorizontally: z.boolean(),
|
|
180
|
+
origin: z.literal("top-left"),
|
|
181
|
+
pixelHeight: z.number().int().safe().positive().max(16_384),
|
|
182
|
+
pixelWidth: z.number().int().safe().positive().max(16_384),
|
|
183
|
+
rotationDegrees: z.union([z.literal(0), z.literal(90), z.literal(180), z.literal(270)]),
|
|
184
|
+
sampleAspectRatio: z.strictObject({
|
|
185
|
+
denominator: z.number().int().safe().positive().max(1_000_000),
|
|
186
|
+
numerator: z.number().int().safe().positive().max(1_000_000),
|
|
187
|
+
}),
|
|
188
|
+
units: z.literal("normalized"),
|
|
189
|
+
xAxis: z.literal("right"),
|
|
190
|
+
yAxis: z.literal("down"),
|
|
191
|
+
}).superRefine((coordinateSpace, context) => {
|
|
192
|
+
if (
|
|
193
|
+
coordinateSpace.pixelWidth * coordinateSpace.pixelHeight > 134_217_728
|
|
194
|
+
|| coordinateSpace.encodedPixelWidth * coordinateSpace.encodedPixelHeight > 134_217_728
|
|
195
|
+
) {
|
|
196
|
+
context.addIssue({ code: "custom", message: "Face analysis source exceeds the 128-megapixel safety limit." });
|
|
197
|
+
}
|
|
198
|
+
const swapsAxes = coordinateSpace.rotationDegrees === 90 || coordinateSpace.rotationDegrees === 270;
|
|
199
|
+
const expectedWidth = swapsAxes ? coordinateSpace.encodedPixelHeight : coordinateSpace.encodedPixelWidth;
|
|
200
|
+
const expectedHeight = swapsAxes ? coordinateSpace.encodedPixelWidth : coordinateSpace.encodedPixelHeight;
|
|
201
|
+
if (coordinateSpace.pixelWidth !== expectedWidth || coordinateSpace.pixelHeight !== expectedHeight) {
|
|
202
|
+
context.addIssue({
|
|
203
|
+
code: "custom",
|
|
204
|
+
message: "Oriented face-analysis pixel dimensions must agree with encoded dimensions and rotation.",
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
}),
|
|
208
|
+
coverage: z.strictObject({
|
|
209
|
+
analyzedFrames: z.number().int().safe().nonnegative().max(250_000),
|
|
210
|
+
failedFrames: z.number().int().safe().nonnegative().max(250_000),
|
|
211
|
+
range: SourceIntervalSchema,
|
|
212
|
+
requestedFrames: z.number().int().safe().positive().max(250_000),
|
|
213
|
+
}),
|
|
214
|
+
createdAt: IsoTimestampSchema,
|
|
215
|
+
durationUs: PositiveMicrosecondsSchema,
|
|
216
|
+
inputDigest: Sha256Schema,
|
|
217
|
+
kind: z.union([
|
|
218
|
+
z.literal("slopcamera.face-analysis"),
|
|
219
|
+
z.literal("studio.face-analysis"),
|
|
220
|
+
]),
|
|
221
|
+
privacy: z.strictObject({
|
|
222
|
+
biometricIdentification: z.literal("not-performed"),
|
|
223
|
+
execution: z.literal("local-only"),
|
|
224
|
+
storedEvidence: z.literal("bounding-boxes-only"),
|
|
225
|
+
tracking: z.literal("geometry-continuity-only"),
|
|
226
|
+
}),
|
|
227
|
+
results: z.array(FaceAnalysisFrameResultSchema).min(1).max(250_000),
|
|
228
|
+
schemaVersion: z.literal(1),
|
|
229
|
+
subject: AnalysisSubjectSchema,
|
|
230
|
+
tool: AnalysisToolSchema,
|
|
231
|
+
tracks: z.array(FaceTrackSchema).max(100_000),
|
|
232
|
+
}).superRefine((analysis, context) => {
|
|
233
|
+
if (analysis.coverage.range.endUs > analysis.durationUs) {
|
|
234
|
+
context.addIssue({ code: "custom", message: "Face analysis coverage exceeds the subject duration." });
|
|
235
|
+
}
|
|
236
|
+
if (analysis.results.length !== analysis.coverage.requestedFrames) {
|
|
237
|
+
context.addIssue({ code: "custom", message: "Face analysis result count must equal requested coverage frames." });
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
const analyzedResults = analysis.results.filter(result => result.state === "analyzed");
|
|
241
|
+
const failedResults = analysis.results.filter(result => result.state === "failed");
|
|
242
|
+
if (
|
|
243
|
+
analyzedResults.length !== analysis.coverage.analyzedFrames
|
|
244
|
+
|| failedResults.length !== analysis.coverage.failedFrames
|
|
245
|
+
|| analysis.coverage.analyzedFrames + analysis.coverage.failedFrames !== analysis.coverage.requestedFrames
|
|
246
|
+
) {
|
|
247
|
+
context.addIssue({ code: "custom", message: "Face analysis coverage counts must match frame result states." });
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
let priorResultTimeUs = -1;
|
|
251
|
+
const observations = new Map<string, number[]>();
|
|
252
|
+
for (const result of analysis.results) {
|
|
253
|
+
if (result.assetTimeUs <= priorResultTimeUs) {
|
|
254
|
+
context.addIssue({ code: "custom", message: "Face analysis frame results must increase strictly in asset time." });
|
|
255
|
+
break;
|
|
256
|
+
}
|
|
257
|
+
if (
|
|
258
|
+
result.assetTimeUs < analysis.coverage.range.startUs
|
|
259
|
+
|| result.assetTimeUs >= analysis.coverage.range.endUs
|
|
260
|
+
) {
|
|
261
|
+
context.addIssue({ code: "custom", message: "Face analysis frame result falls outside the coverage range." });
|
|
262
|
+
}
|
|
263
|
+
priorResultTimeUs = result.assetTimeUs;
|
|
264
|
+
if (result.state === "failed") continue;
|
|
265
|
+
if (result.detections.length > analysis.config.tracking.maximumFacesPerFrame) {
|
|
266
|
+
context.addIssue({ code: "custom", message: "Face analysis frame exceeds its configured face limit." });
|
|
267
|
+
}
|
|
268
|
+
for (const detection of result.detections) {
|
|
269
|
+
if (detection.confidence < analysis.config.tracking.minimumConfidence) {
|
|
270
|
+
context.addIssue({ code: "custom", message: "Persisted face detection is below the configured confidence floor." });
|
|
271
|
+
}
|
|
272
|
+
const trackObservations = observations.get(detection.trackId) ?? [];
|
|
273
|
+
trackObservations.push(result.assetTimeUs);
|
|
274
|
+
observations.set(detection.trackId, trackObservations);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
const trackIds = analysis.tracks.map(track => track.trackId);
|
|
279
|
+
if (new Set(trackIds).size !== trackIds.length) {
|
|
280
|
+
context.addIssue({ code: "custom", message: "Face analysis track IDs must be unique." });
|
|
281
|
+
}
|
|
282
|
+
if (trackIds.some((trackId, index) => index > 0 && trackId <= trackIds[index - 1]!)) {
|
|
283
|
+
context.addIssue({ code: "custom", message: "Face analysis tracks must be ordered by track ID." });
|
|
284
|
+
}
|
|
285
|
+
if (observations.size !== analysis.tracks.length) {
|
|
286
|
+
context.addIssue({ code: "custom", message: "Face analysis tracks must exactly summarize observed detections." });
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
for (const track of analysis.tracks) {
|
|
290
|
+
const times = observations.get(track.trackId);
|
|
291
|
+
if (times === undefined || times.length === 0) {
|
|
292
|
+
context.addIssue({ code: "custom", message: `Face track ${track.trackId} has no observed detections.` });
|
|
293
|
+
continue;
|
|
294
|
+
}
|
|
295
|
+
let maximumObservedGapUs = 0;
|
|
296
|
+
for (let index = 1; index < times.length; index += 1) {
|
|
297
|
+
maximumObservedGapUs = Math.max(maximumObservedGapUs, times[index]! - times[index - 1]!);
|
|
298
|
+
}
|
|
299
|
+
if (
|
|
300
|
+
track.firstSeenAssetTimeUs !== times[0]
|
|
301
|
+
|| track.lastSeenAssetTimeUs !== times.at(-1)
|
|
302
|
+
|| track.observationCount !== times.length
|
|
303
|
+
|| track.maximumObservedGapUs !== maximumObservedGapUs
|
|
304
|
+
) {
|
|
305
|
+
context.addIssue({ code: "custom", message: `Face track ${track.trackId} summary does not match its detections.` });
|
|
306
|
+
}
|
|
307
|
+
if (maximumObservedGapUs > analysis.config.tracking.maximumGapUs) {
|
|
308
|
+
context.addIssue({ code: "custom", message: `Face track ${track.trackId} exceeds the configured geometry gap.` });
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
const MappedFreezeIntervalSchema = z.strictObject({
|
|
314
|
+
assetRange: SourceIntervalSchema,
|
|
315
|
+
confidence: z.number().finite().min(0).max(1),
|
|
316
|
+
meanFrameDifference: z.number().finite().nonnegative(),
|
|
317
|
+
projectRange: SourceIntervalSchema,
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
const MappedSilenceIntervalSchema = z.strictObject({
|
|
321
|
+
assetRange: SourceIntervalSchema,
|
|
322
|
+
peakDb: z.number().finite(),
|
|
323
|
+
projectRange: SourceIntervalSchema,
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
const ProjectInactivityStreamBaseShape = {
|
|
327
|
+
placementAssetRange: SourceIntervalSchema,
|
|
328
|
+
placementId: ProjectPlacementIdSchema,
|
|
329
|
+
subject: AnalysisSubjectSchema,
|
|
330
|
+
syncMapSha256: Sha256Schema,
|
|
331
|
+
} as const;
|
|
332
|
+
|
|
333
|
+
export const ProjectInactivityDisplayEvidenceSchema = z.strictObject({
|
|
334
|
+
...ProjectInactivityStreamBaseShape,
|
|
335
|
+
intervals: z.array(MappedFreezeIntervalSchema).max(100_000),
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
export const ProjectInactivityAudioEvidenceSchema = z.strictObject({
|
|
339
|
+
...ProjectInactivityStreamBaseShape,
|
|
340
|
+
intervals: z.array(MappedSilenceIntervalSchema).max(100_000),
|
|
341
|
+
});
|
|
342
|
+
|
|
343
|
+
export const ProjectInteractionEvidenceSchema = z.strictObject({
|
|
344
|
+
assetRange: SourceIntervalSchema,
|
|
345
|
+
projectRange: SourceIntervalSchema,
|
|
346
|
+
source: z.enum([
|
|
347
|
+
"mouse.click",
|
|
348
|
+
"key.activity",
|
|
349
|
+
"typing.input",
|
|
350
|
+
"focus.changed",
|
|
351
|
+
"cursor.movement",
|
|
352
|
+
]),
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
export const ProjectInactivityConfigSchema = z.strictObject({
|
|
356
|
+
cursorMovementThresholdPx: z.number().finite().positive(),
|
|
357
|
+
edgeHandleUs: MicrosecondsSchema,
|
|
358
|
+
interactionHandleUs: MicrosecondsSchema,
|
|
359
|
+
minimumCutUs: MicrosecondsSchema,
|
|
360
|
+
minimumFreezeConfidence: z.number().finite().min(0).max(1),
|
|
361
|
+
motionThreshold: z.number().finite().min(0).max(1),
|
|
362
|
+
requireAudioSilence: z.boolean(),
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
/**
|
|
366
|
+
* Immutable project-clock evidence for inactivity decisions. Asset ranges retain
|
|
367
|
+
* analyzer provenance; paired project ranges retain the exact accepted sync map
|
|
368
|
+
* used when the analysis was produced.
|
|
369
|
+
*/
|
|
370
|
+
export const ProjectInactivityAnalysisV1Schema = z.strictObject({
|
|
371
|
+
analysisId: AnalysisIdSchema,
|
|
372
|
+
audio: z.array(ProjectInactivityAudioEvidenceSchema).max(256),
|
|
373
|
+
config: ProjectInactivityConfigSchema,
|
|
374
|
+
createdAt: IsoTimestampSchema,
|
|
375
|
+
displays: z.array(ProjectInactivityDisplayEvidenceSchema).min(1).max(256),
|
|
376
|
+
durationUs: MicrosecondsSchema,
|
|
377
|
+
inputDigest: Sha256Schema,
|
|
378
|
+
interactions: z.array(ProjectInteractionEvidenceSchema).max(1_000_000),
|
|
379
|
+
kind: z.union([
|
|
380
|
+
z.literal("slopcamera.project-inactivity-analysis"),
|
|
381
|
+
z.literal("studio.project-inactivity-analysis"),
|
|
382
|
+
]),
|
|
383
|
+
projectId: VideoProjectIdSchema,
|
|
384
|
+
projectStructureSha256: Sha256Schema,
|
|
385
|
+
referenceRecording: z.strictObject({
|
|
386
|
+
assetId: ProjectAssetIdSchema,
|
|
387
|
+
placementId: ProjectPlacementIdSchema,
|
|
388
|
+
recordingId: RecordingIdSchema,
|
|
389
|
+
syncMapSha256: Sha256Schema,
|
|
390
|
+
}).nullable(),
|
|
391
|
+
result: z.strictObject({
|
|
392
|
+
candidateCount: z.number().int().safe().nonnegative(),
|
|
393
|
+
protectedInteractionCount: z.number().int().safe().nonnegative(),
|
|
394
|
+
recommendedRanges: z.array(SourceIntervalSchema).max(100_000),
|
|
395
|
+
}),
|
|
396
|
+
schemaVersion: z.literal(1),
|
|
397
|
+
tool: AnalysisToolSchema,
|
|
398
|
+
}).superRefine((analysis, context) => {
|
|
399
|
+
const evidence = [...analysis.displays, ...analysis.audio];
|
|
400
|
+
const identities = evidence.map(item => `${item.placementId}:${item.subject.streamId}`);
|
|
401
|
+
if (new Set(identities).size !== identities.length) {
|
|
402
|
+
context.addIssue({ code: "custom", message: "Project inactivity placement-stream evidence must be unique." });
|
|
403
|
+
}
|
|
404
|
+
for (const stream of evidence) {
|
|
405
|
+
let priorAssetEndUs = -1;
|
|
406
|
+
let priorProjectEndUs = -1;
|
|
407
|
+
for (const interval of stream.intervals) {
|
|
408
|
+
if (
|
|
409
|
+
interval.assetRange.startUs < stream.placementAssetRange.startUs
|
|
410
|
+
|| interval.assetRange.endUs > stream.placementAssetRange.endUs
|
|
411
|
+
) {
|
|
412
|
+
context.addIssue({
|
|
413
|
+
code: "custom",
|
|
414
|
+
message: `Inactivity evidence for ${stream.subject.streamId} exceeds its placement asset range.`,
|
|
415
|
+
});
|
|
416
|
+
}
|
|
417
|
+
if (interval.projectRange.endUs > analysis.durationUs) {
|
|
418
|
+
context.addIssue({
|
|
419
|
+
code: "custom",
|
|
420
|
+
message: `Inactivity evidence for ${stream.subject.streamId} exceeds the project duration.`,
|
|
421
|
+
});
|
|
422
|
+
}
|
|
423
|
+
if (
|
|
424
|
+
interval.assetRange.startUs < priorAssetEndUs
|
|
425
|
+
|| interval.projectRange.startUs < priorProjectEndUs
|
|
426
|
+
) {
|
|
427
|
+
context.addIssue({
|
|
428
|
+
code: "custom",
|
|
429
|
+
message: `Inactivity evidence for ${stream.subject.streamId} must be ordered in both clocks.`,
|
|
430
|
+
});
|
|
431
|
+
break;
|
|
432
|
+
}
|
|
433
|
+
priorAssetEndUs = interval.assetRange.endUs;
|
|
434
|
+
priorProjectEndUs = interval.projectRange.endUs;
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
let priorInteractionProjectUs = -1;
|
|
438
|
+
for (const interaction of analysis.interactions) {
|
|
439
|
+
if (interaction.projectRange.endUs > analysis.durationUs) {
|
|
440
|
+
context.addIssue({ code: "custom", message: "Interaction evidence exceeds the project duration." });
|
|
441
|
+
}
|
|
442
|
+
if (interaction.projectRange.startUs < priorInteractionProjectUs) {
|
|
443
|
+
context.addIssue({ code: "custom", message: "Interaction evidence must be ordered by project time." });
|
|
444
|
+
break;
|
|
445
|
+
}
|
|
446
|
+
priorInteractionProjectUs = interaction.projectRange.startUs;
|
|
447
|
+
}
|
|
448
|
+
if (!rangesAreOrderedAndDisjoint(analysis.result.recommendedRanges.map(range => ({ range })))) {
|
|
449
|
+
context.addIssue({ code: "custom", message: "Recommended inactivity ranges must be ordered and disjoint." });
|
|
450
|
+
}
|
|
451
|
+
if (analysis.result.recommendedRanges.some(range => range.endUs > analysis.durationUs)) {
|
|
452
|
+
context.addIssue({ code: "custom", message: "Recommended inactivity ranges exceed the project duration." });
|
|
453
|
+
}
|
|
454
|
+
if (!analysis.config.requireAudioSilence && analysis.audio.length !== 0) {
|
|
455
|
+
context.addIssue({ code: "custom", message: "Audio evidence must be empty when silence protection is disabled." });
|
|
456
|
+
}
|
|
457
|
+
});
|
|
458
|
+
|
|
459
|
+
export const AlignmentMatchSchema = z.strictObject({
|
|
460
|
+
ambiguity: z.number().finite().min(0).max(1),
|
|
461
|
+
confidence: z.number().finite().min(0).max(1),
|
|
462
|
+
referenceAssetTimeUs: MicrosecondsSchema,
|
|
463
|
+
targetAssetTimeUs: MicrosecondsSchema,
|
|
464
|
+
windowUs: MicrosecondsSchema,
|
|
465
|
+
});
|
|
466
|
+
|
|
467
|
+
export const AssetClockAnchorSchema = z.strictObject({
|
|
468
|
+
referenceAssetTimeUs: MicrosecondsSchema,
|
|
469
|
+
targetAssetTimeUs: MicrosecondsSchema,
|
|
470
|
+
});
|
|
471
|
+
|
|
472
|
+
export const AlignmentCandidateSchema = z.strictObject({
|
|
473
|
+
ambiguity: z.number().finite().min(0).max(1),
|
|
474
|
+
anchors: z.array(AssetClockAnchorSchema).min(2).max(4_096),
|
|
475
|
+
autoApplicable: z.boolean(),
|
|
476
|
+
candidateId: AlignmentCandidateIdSchema,
|
|
477
|
+
confidence: z.number().finite().min(0).max(1),
|
|
478
|
+
driftPpm: z.number().finite().min(-100_000).max(100_000),
|
|
479
|
+
initialOffsetUs: z.number().int().safe(),
|
|
480
|
+
maxResidualUs: MicrosecondsSchema,
|
|
481
|
+
medianResidualUs: MicrosecondsSchema,
|
|
482
|
+
overlapUs: MicrosecondsSchema,
|
|
483
|
+
peakRatio: z.number().finite().nonnegative(),
|
|
484
|
+
}).superRefine((candidate, context) => {
|
|
485
|
+
for (let index = 1; index < candidate.anchors.length; index += 1) {
|
|
486
|
+
const prior = candidate.anchors[index - 1]!;
|
|
487
|
+
const current = candidate.anchors[index]!;
|
|
488
|
+
if (current.targetAssetTimeUs <= prior.targetAssetTimeUs) {
|
|
489
|
+
context.addIssue({ code: "custom", message: "Candidate target anchors must increase strictly." });
|
|
490
|
+
return;
|
|
491
|
+
}
|
|
492
|
+
if (current.referenceAssetTimeUs <= prior.referenceAssetTimeUs) {
|
|
493
|
+
context.addIssue({ code: "custom", message: "Candidate reference anchors must increase strictly." });
|
|
494
|
+
return;
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
if (candidate.autoApplicable && (candidate.confidence < 0.8 || candidate.ambiguity > 0.2)) {
|
|
498
|
+
context.addIssue({
|
|
499
|
+
code: "custom",
|
|
500
|
+
message: "Auto-applicable alignment candidates require high confidence and low ambiguity.",
|
|
501
|
+
});
|
|
502
|
+
}
|
|
503
|
+
});
|
|
504
|
+
|
|
505
|
+
export const AudioAlignmentAnalysisV1Schema = z.strictObject({
|
|
506
|
+
analysisId: AnalysisIdSchema,
|
|
507
|
+
config: z.strictObject({
|
|
508
|
+
analysisSampleRateHz: z.number().int().safe().min(8_000).max(96_000),
|
|
509
|
+
maxDriftPpm: z.number().finite().positive().max(100_000),
|
|
510
|
+
minimumOverlapUs: MicrosecondsSchema,
|
|
511
|
+
windowUs: MicrosecondsSchema,
|
|
512
|
+
}),
|
|
513
|
+
createdAt: IsoTimestampSchema,
|
|
514
|
+
inputDigest: Sha256Schema,
|
|
515
|
+
kind: z.union([
|
|
516
|
+
z.literal("slopcamera.audio-alignment-analysis"),
|
|
517
|
+
z.literal("studio.audio-alignment-analysis"),
|
|
518
|
+
]),
|
|
519
|
+
matches: z.array(AlignmentMatchSchema).max(100_000),
|
|
520
|
+
reference: AnalysisSubjectSchema,
|
|
521
|
+
result: z.discriminatedUnion("status", [
|
|
522
|
+
z.strictObject({
|
|
523
|
+
candidates: z.array(AlignmentCandidateSchema).min(1).max(32),
|
|
524
|
+
status: z.literal("matched"),
|
|
525
|
+
}),
|
|
526
|
+
z.strictObject({
|
|
527
|
+
candidates: z.array(AlignmentCandidateSchema).min(2).max(32),
|
|
528
|
+
reason: z.literal("periodic-or-competing-matches"),
|
|
529
|
+
status: z.literal("ambiguous"),
|
|
530
|
+
}),
|
|
531
|
+
z.strictObject({
|
|
532
|
+
diagnostics: z.array(z.string().min(1).max(1_024)).max(64),
|
|
533
|
+
reason: z.enum(["insufficient-overlap", "low-correlation", "silent-input", "unrelated-input"]),
|
|
534
|
+
status: z.literal("no-match"),
|
|
535
|
+
}),
|
|
536
|
+
]),
|
|
537
|
+
schemaVersion: z.literal(1),
|
|
538
|
+
target: AnalysisSubjectSchema,
|
|
539
|
+
tool: AnalysisToolSchema,
|
|
540
|
+
}).superRefine((analysis, context) => {
|
|
541
|
+
if (
|
|
542
|
+
analysis.reference.assetId === analysis.target.assetId
|
|
543
|
+
&& analysis.reference.streamId === analysis.target.streamId
|
|
544
|
+
) {
|
|
545
|
+
context.addIssue({ code: "custom", message: "Alignment subjects must identify different streams." });
|
|
546
|
+
}
|
|
547
|
+
let priorReferenceUs = -1;
|
|
548
|
+
let priorTargetUs = -1;
|
|
549
|
+
for (const match of analysis.matches) {
|
|
550
|
+
if (
|
|
551
|
+
match.referenceAssetTimeUs < priorReferenceUs
|
|
552
|
+
|| match.targetAssetTimeUs < priorTargetUs
|
|
553
|
+
) {
|
|
554
|
+
context.addIssue({ code: "custom", message: "Alignment matches must be ordered in both asset clocks." });
|
|
555
|
+
break;
|
|
556
|
+
}
|
|
557
|
+
priorReferenceUs = match.referenceAssetTimeUs;
|
|
558
|
+
priorTargetUs = match.targetAssetTimeUs;
|
|
559
|
+
}
|
|
560
|
+
});
|
|
561
|
+
|
|
562
|
+
function rangesAreOrderedAndDisjoint(
|
|
563
|
+
values: readonly { readonly range: { readonly startUs: number; readonly endUs: number } }[],
|
|
564
|
+
): boolean {
|
|
565
|
+
let priorEndUs = -1;
|
|
566
|
+
for (const value of values) {
|
|
567
|
+
if (value.range.startUs < priorEndUs) return false;
|
|
568
|
+
priorEndUs = value.range.endUs;
|
|
569
|
+
}
|
|
570
|
+
return true;
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
export const MusicPresenceRegionSchema = z.strictObject({
|
|
574
|
+
confidence: z.number().finite().min(0).max(1),
|
|
575
|
+
range: SourceIntervalSchema,
|
|
576
|
+
});
|
|
577
|
+
|
|
578
|
+
export const TempoAlternativeSchema = z.strictObject({
|
|
579
|
+
bpm: z.number().finite().min(20).max(400),
|
|
580
|
+
confidence: z.number().finite().min(0).max(1),
|
|
581
|
+
});
|
|
582
|
+
|
|
583
|
+
export const TempoRegionSchema = z.strictObject({
|
|
584
|
+
alternatives: z.array(TempoAlternativeSchema).max(4),
|
|
585
|
+
beatTimesUs: z.array(MicrosecondsSchema).max(250_000),
|
|
586
|
+
bpm: z.number().finite().min(20).max(400),
|
|
587
|
+
changeFromPrevious: z.strictObject({
|
|
588
|
+
confidence: z.number().finite().min(0).max(1),
|
|
589
|
+
deltaBpm: z.number().finite(),
|
|
590
|
+
}).nullable(),
|
|
591
|
+
confidence: z.number().finite().min(0).max(1),
|
|
592
|
+
meter: z.enum(["2/4", "3/4", "4/4", "6/8", "unknown"]),
|
|
593
|
+
range: SourceIntervalSchema,
|
|
594
|
+
}).superRefine((region, context) => {
|
|
595
|
+
let priorBeatUs = -1;
|
|
596
|
+
for (const beatUs of region.beatTimesUs) {
|
|
597
|
+
if (beatUs <= priorBeatUs) {
|
|
598
|
+
context.addIssue({ code: "custom", message: "Beat times must increase strictly." });
|
|
599
|
+
return;
|
|
600
|
+
}
|
|
601
|
+
if (beatUs < region.range.startUs || beatUs >= region.range.endUs) {
|
|
602
|
+
context.addIssue({ code: "custom", message: "Beat times must fall inside their tempo region." });
|
|
603
|
+
return;
|
|
604
|
+
}
|
|
605
|
+
priorBeatUs = beatUs;
|
|
606
|
+
}
|
|
607
|
+
});
|
|
608
|
+
|
|
609
|
+
export const MusicalKeySchema = z.discriminatedUnion("kind", [
|
|
610
|
+
z.strictObject({ kind: z.literal("unknown") }),
|
|
611
|
+
z.strictObject({
|
|
612
|
+
kind: z.literal("key"),
|
|
613
|
+
mode: z.enum(["major", "minor"]),
|
|
614
|
+
pitchClass: z.number().int().min(0).max(11),
|
|
615
|
+
}),
|
|
616
|
+
]);
|
|
617
|
+
|
|
618
|
+
export const KeyRegionSchema = z.strictObject({
|
|
619
|
+
alternate: z.strictObject({
|
|
620
|
+
confidence: z.number().finite().min(0).max(1),
|
|
621
|
+
key: MusicalKeySchema,
|
|
622
|
+
}).nullable(),
|
|
623
|
+
changeConfidence: z.number().finite().min(0).max(1).nullable(),
|
|
624
|
+
confidence: z.number().finite().min(0).max(1),
|
|
625
|
+
key: MusicalKeySchema,
|
|
626
|
+
range: SourceIntervalSchema,
|
|
627
|
+
});
|
|
628
|
+
|
|
629
|
+
export const MusicAnalysisV1Schema = z.strictObject({
|
|
630
|
+
analysisId: AnalysisIdSchema,
|
|
631
|
+
config: z.strictObject({
|
|
632
|
+
hopSize: z.number().int().safe().positive(),
|
|
633
|
+
minimumMusicUs: MicrosecondsSchema,
|
|
634
|
+
sampleRateHz: z.number().int().safe().min(8_000).max(192_000),
|
|
635
|
+
tempoWindowUs: MicrosecondsSchema,
|
|
636
|
+
windowSize: z.number().int().safe().positive(),
|
|
637
|
+
}),
|
|
638
|
+
createdAt: IsoTimestampSchema,
|
|
639
|
+
durationUs: MicrosecondsSchema,
|
|
640
|
+
inputDigest: Sha256Schema,
|
|
641
|
+
keyRegions: z.array(KeyRegionSchema).max(100_000),
|
|
642
|
+
kind: z.union([
|
|
643
|
+
z.literal("slopcamera.music-analysis"),
|
|
644
|
+
z.literal("studio.music-analysis"),
|
|
645
|
+
]),
|
|
646
|
+
musicRegions: z.array(MusicPresenceRegionSchema).max(100_000),
|
|
647
|
+
schemaVersion: z.literal(1),
|
|
648
|
+
subject: AnalysisSubjectSchema,
|
|
649
|
+
tempoRegions: z.array(TempoRegionSchema).max(100_000),
|
|
650
|
+
tool: AnalysisToolSchema,
|
|
651
|
+
}).superRefine((analysis, context) => {
|
|
652
|
+
for (const [label, regions] of [
|
|
653
|
+
["Music", analysis.musicRegions],
|
|
654
|
+
["Tempo", analysis.tempoRegions],
|
|
655
|
+
["Key", analysis.keyRegions],
|
|
656
|
+
] as const) {
|
|
657
|
+
if (!rangesAreOrderedAndDisjoint(regions)) {
|
|
658
|
+
context.addIssue({ code: "custom", message: `${label} regions must be ordered and non-overlapping.` });
|
|
659
|
+
}
|
|
660
|
+
if (regions.some(region => region.range.endUs > analysis.durationUs)) {
|
|
661
|
+
context.addIssue({ code: "custom", message: `${label} regions exceed the analyzed duration.` });
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
if (analysis.tempoRegions[0]?.changeFromPrevious !== null && analysis.tempoRegions.length > 0) {
|
|
665
|
+
context.addIssue({ code: "custom", message: "The first tempo region cannot be a tempo change." });
|
|
666
|
+
}
|
|
667
|
+
if (analysis.keyRegions[0]?.changeConfidence !== null && analysis.keyRegions.length > 0) {
|
|
668
|
+
context.addIssue({ code: "custom", message: "The first key region cannot be a key change." });
|
|
669
|
+
}
|
|
670
|
+
});
|
|
671
|
+
|
|
672
|
+
export const SceneFrameSampleSchema = z.strictObject({
|
|
673
|
+
actualAssetTimeUs: MicrosecondsSchema,
|
|
674
|
+
bytes: z.number().int().safe().positive().max(20_000_000),
|
|
675
|
+
perceptualHash: z.string().regex(/^[a-f0-9]{16}$/u),
|
|
676
|
+
path: RepositoryRelativePathSchema,
|
|
677
|
+
reasons: z.array(z.enum(["boundary", "middle", "event", "maximum-gap", "motion"])).min(1),
|
|
678
|
+
requestedAssetTimeUs: MicrosecondsSchema,
|
|
679
|
+
sampleId: SceneSampleIdSchema,
|
|
680
|
+
sha256: Sha256Schema,
|
|
681
|
+
});
|
|
682
|
+
|
|
683
|
+
export { SceneDescriptionSchema };
|
|
684
|
+
|
|
685
|
+
export const DescribedSceneSchema = z.strictObject({
|
|
686
|
+
boundaryConfidence: z.number().finite().min(0).max(1),
|
|
687
|
+
description: SceneDescriptionSchema,
|
|
688
|
+
range: SourceIntervalSchema,
|
|
689
|
+
sampleIds: z.array(SceneSampleIdSchema).min(1).max(12),
|
|
690
|
+
sceneId: SceneIdSchema,
|
|
691
|
+
});
|
|
692
|
+
|
|
693
|
+
export const SceneBatchSchema = z.strictObject({
|
|
694
|
+
batchKey: Sha256Schema,
|
|
695
|
+
errorCode: z.string().regex(/^[a-z0-9][a-z0-9-]{0,127}$/u).nullable(),
|
|
696
|
+
imageBytes: z.number().int().safe().nonnegative().max(6_000_000),
|
|
697
|
+
imageCount: z.number().int().safe().nonnegative().max(12),
|
|
698
|
+
sceneIds: z.array(SceneIdSchema).min(1).max(4),
|
|
699
|
+
state: z.enum(["planned", "dispatching", "complete", "ambiguous", "failed"]),
|
|
700
|
+
}).superRefine((batch, context) => {
|
|
701
|
+
const isFailure = batch.state === "ambiguous" || batch.state === "failed";
|
|
702
|
+
if (isFailure !== (batch.errorCode !== null)) {
|
|
703
|
+
context.addIssue({
|
|
704
|
+
code: "custom",
|
|
705
|
+
message: "Scene batch failure states and error codes must agree.",
|
|
706
|
+
path: ["errorCode"],
|
|
707
|
+
});
|
|
708
|
+
}
|
|
709
|
+
if (new Set(batch.sceneIds).size !== batch.sceneIds.length) {
|
|
710
|
+
context.addIssue({ code: "custom", message: "Scene batch scene IDs must be unique.", path: ["sceneIds"] });
|
|
711
|
+
}
|
|
712
|
+
if ((batch.imageBytes === 0) !== (batch.imageCount === 0)) {
|
|
713
|
+
context.addIssue({
|
|
714
|
+
code: "custom",
|
|
715
|
+
message: "Scene batch image count and byte size must either both be zero or both be positive.",
|
|
716
|
+
});
|
|
717
|
+
}
|
|
718
|
+
if (batch.state !== "planned" && (batch.imageBytes === 0 || batch.imageCount === 0)) {
|
|
719
|
+
context.addIssue({
|
|
720
|
+
code: "custom",
|
|
721
|
+
message: "A dispatched scene batch must identify at least one materialized image.",
|
|
722
|
+
});
|
|
723
|
+
}
|
|
724
|
+
});
|
|
725
|
+
|
|
726
|
+
export const SceneAnalysisV1Schema = z.strictObject({
|
|
727
|
+
analysisId: AnalysisIdSchema,
|
|
728
|
+
batches: z.array(SceneBatchSchema).max(10_000),
|
|
729
|
+
cloudUpload: z.strictObject({
|
|
730
|
+
acknowledgedAt: IsoTimestampSchema,
|
|
731
|
+
policy: z.literal(SCENE_UPLOAD_POLICY),
|
|
732
|
+
}),
|
|
733
|
+
createdAt: IsoTimestampSchema,
|
|
734
|
+
durationUs: MicrosecondsSchema,
|
|
735
|
+
inputDigest: Sha256Schema,
|
|
736
|
+
kind: z.union([
|
|
737
|
+
z.literal("slopcamera.scene-analysis"),
|
|
738
|
+
z.literal("studio.scene-analysis"),
|
|
739
|
+
]),
|
|
740
|
+
model: z.strictObject({
|
|
741
|
+
aiSdkVersion: z.string().min(1).max(128),
|
|
742
|
+
gateway: z.literal("vercel-ai-gateway"),
|
|
743
|
+
promptSha256: Sha256Schema,
|
|
744
|
+
promptVersion: z.string().min(1).max(128),
|
|
745
|
+
requestedModel: z.string().min(1).max(256),
|
|
746
|
+
resolvedModel: z.string().min(1).max(256).nullable(),
|
|
747
|
+
samplingVersion: z.string().min(1).max(128),
|
|
748
|
+
}),
|
|
749
|
+
samples: z.array(SceneFrameSampleSchema).max(100_000),
|
|
750
|
+
scenes: z.array(DescribedSceneSchema).max(100_000),
|
|
751
|
+
schemaVersion: z.literal(1),
|
|
752
|
+
subjects: z.array(AnalysisSubjectSchema).min(1).max(8),
|
|
753
|
+
usage: z.strictObject({
|
|
754
|
+
inputTokens: z.number().int().safe().nonnegative(),
|
|
755
|
+
outputTokens: z.number().int().safe().nonnegative(),
|
|
756
|
+
uploadedBytes: z.number().int().safe().nonnegative(),
|
|
757
|
+
uploadedImages: z.number().int().safe().nonnegative(),
|
|
758
|
+
}),
|
|
759
|
+
}).superRefine((analysis, context) => {
|
|
760
|
+
if (!rangesAreOrderedAndDisjoint(analysis.scenes)) {
|
|
761
|
+
context.addIssue({ code: "custom", message: "Described scenes must be ordered and non-overlapping." });
|
|
762
|
+
}
|
|
763
|
+
if (analysis.scenes.some(scene => scene.range.endUs > analysis.durationUs)) {
|
|
764
|
+
context.addIssue({ code: "custom", message: "Described scenes exceed the analyzed duration." });
|
|
765
|
+
}
|
|
766
|
+
const samplesById = new Map(analysis.samples.map(sample => [sample.sampleId, sample]));
|
|
767
|
+
if (samplesById.size !== analysis.samples.length) {
|
|
768
|
+
context.addIssue({ code: "custom", message: "Scene sample IDs must be unique." });
|
|
769
|
+
}
|
|
770
|
+
if (new Set(analysis.scenes.map(scene => scene.sceneId)).size !== analysis.scenes.length) {
|
|
771
|
+
context.addIssue({ code: "custom", message: "Scene IDs must be unique." });
|
|
772
|
+
}
|
|
773
|
+
if (new Set(analysis.batches.map(batch => batch.batchKey)).size !== analysis.batches.length) {
|
|
774
|
+
context.addIssue({ code: "custom", message: "Scene batch keys must be unique." });
|
|
775
|
+
}
|
|
776
|
+
const batchedSceneIds = analysis.batches.flatMap(batch => batch.sceneIds);
|
|
777
|
+
if (new Set(batchedSceneIds).size !== batchedSceneIds.length) {
|
|
778
|
+
context.addIssue({ code: "custom", message: "A scene may belong to only one analysis batch." });
|
|
779
|
+
}
|
|
780
|
+
for (const scene of analysis.scenes) {
|
|
781
|
+
for (const sampleId of scene.sampleIds) {
|
|
782
|
+
const sample = samplesById.get(sampleId);
|
|
783
|
+
if (sample === undefined) {
|
|
784
|
+
context.addIssue({ code: "custom", message: `Scene ${scene.sceneId} references an unknown sample.` });
|
|
785
|
+
} else if (
|
|
786
|
+
sample.actualAssetTimeUs < scene.range.startUs
|
|
787
|
+
|| sample.actualAssetTimeUs >= scene.range.endUs
|
|
788
|
+
) {
|
|
789
|
+
context.addIssue({ code: "custom", message: `Scene ${scene.sceneId} has a sample outside its range.` });
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
});
|
|
794
|
+
|
|
795
|
+
export const TranscriptWordSchema = z.strictObject({
|
|
796
|
+
confidence: z.number().finite().min(0).max(1),
|
|
797
|
+
range: SourceIntervalSchema,
|
|
798
|
+
speaker: z.string().min(1).max(128).nullable(),
|
|
799
|
+
text: z.string().min(1).max(256),
|
|
800
|
+
wordIndex: z.number().int().safe().nonnegative(),
|
|
801
|
+
});
|
|
802
|
+
|
|
803
|
+
export const SpeechUtteranceSchema = z.strictObject({
|
|
804
|
+
range: SourceIntervalSchema,
|
|
805
|
+
text: z.string().min(1).max(16_384),
|
|
806
|
+
wordEndExclusive: z.number().int().safe().positive(),
|
|
807
|
+
wordStart: z.number().int().safe().nonnegative(),
|
|
808
|
+
});
|
|
809
|
+
|
|
810
|
+
export const FillerCandidateSchema = z.strictObject({
|
|
811
|
+
acousticBoundaryConfidence: z.number().finite().min(0).max(1),
|
|
812
|
+
autoApplicable: z.boolean(),
|
|
813
|
+
candidateId: FillerCandidateIdSchema,
|
|
814
|
+
classification: z.enum(["filled-pause", "phrase-filler", "contextual", "repetition", "false-start"]),
|
|
815
|
+
confidence: z.number().finite().min(0).max(1),
|
|
816
|
+
musicProtected: z.boolean(),
|
|
817
|
+
range: SourceIntervalSchema,
|
|
818
|
+
recommendedCut: SourceIntervalSchema.nullable(),
|
|
819
|
+
text: z.string().min(1).max(1_024),
|
|
820
|
+
wordEndExclusive: z.number().int().safe().positive(),
|
|
821
|
+
wordStart: z.number().int().safe().nonnegative(),
|
|
822
|
+
}).superRefine((candidate, context) => {
|
|
823
|
+
if (candidate.wordEndExclusive <= candidate.wordStart) {
|
|
824
|
+
context.addIssue({ code: "custom", message: "Filler word range must be nonempty." });
|
|
825
|
+
}
|
|
826
|
+
if (
|
|
827
|
+
candidate.recommendedCut !== null
|
|
828
|
+
&& (
|
|
829
|
+
candidate.recommendedCut.startUs > candidate.range.startUs
|
|
830
|
+
|| candidate.recommendedCut.endUs < candidate.range.endUs
|
|
831
|
+
)
|
|
832
|
+
) {
|
|
833
|
+
context.addIssue({ code: "custom", message: "A recommended filler cut must contain the detected filler range." });
|
|
834
|
+
}
|
|
835
|
+
if (candidate.autoApplicable && (
|
|
836
|
+
candidate.recommendedCut === null
|
|
837
|
+
|| candidate.musicProtected
|
|
838
|
+
|| candidate.classification === "contextual"
|
|
839
|
+
|| candidate.confidence < 0.9
|
|
840
|
+
|| candidate.acousticBoundaryConfidence < 0.8
|
|
841
|
+
)) {
|
|
842
|
+
context.addIssue({
|
|
843
|
+
code: "custom",
|
|
844
|
+
message: "Auto-applicable fillers require a safe cut, strong evidence, and no music protection.",
|
|
845
|
+
});
|
|
846
|
+
}
|
|
847
|
+
});
|
|
848
|
+
|
|
849
|
+
export const SpeechAnalysisV1Schema = z.strictObject({
|
|
850
|
+
analysisId: AnalysisIdSchema,
|
|
851
|
+
config: z.strictObject({
|
|
852
|
+
language: z.string().min(1).max(64),
|
|
853
|
+
minimumFillerConfidence: z.number().finite().min(0).max(1),
|
|
854
|
+
speechHandleUs: MicrosecondsSchema,
|
|
855
|
+
}),
|
|
856
|
+
createdAt: IsoTimestampSchema,
|
|
857
|
+
durationUs: MicrosecondsSchema,
|
|
858
|
+
inputDigest: Sha256Schema,
|
|
859
|
+
kind: z.union([
|
|
860
|
+
z.literal("slopcamera.speech-analysis"),
|
|
861
|
+
z.literal("studio.speech-analysis"),
|
|
862
|
+
]),
|
|
863
|
+
result: z.discriminatedUnion("status", [
|
|
864
|
+
z.strictObject({
|
|
865
|
+
detectedLanguage: z.string().min(1).max(64),
|
|
866
|
+
fillers: z.array(FillerCandidateSchema).max(100_000),
|
|
867
|
+
status: z.literal("transcribed"),
|
|
868
|
+
utterances: z.array(SpeechUtteranceSchema).max(100_000),
|
|
869
|
+
words: z.array(TranscriptWordSchema).max(1_000_000),
|
|
870
|
+
}),
|
|
871
|
+
z.strictObject({
|
|
872
|
+
detectedLanguage: z.string().min(1).max(64).nullable(),
|
|
873
|
+
reason: z.literal("no-speech"),
|
|
874
|
+
status: z.literal("no-speech"),
|
|
875
|
+
}),
|
|
876
|
+
]),
|
|
877
|
+
schemaVersion: z.literal(1),
|
|
878
|
+
subject: AnalysisSubjectSchema,
|
|
879
|
+
tool: AnalysisToolSchema,
|
|
880
|
+
}).superRefine((analysis, context) => {
|
|
881
|
+
if (analysis.result.status === "no-speech") return;
|
|
882
|
+
const { fillers, utterances, words } = analysis.result;
|
|
883
|
+
if (!rangesAreOrderedAndDisjoint(words)) {
|
|
884
|
+
context.addIssue({ code: "custom", message: "Transcript words must be ordered and non-overlapping." });
|
|
885
|
+
}
|
|
886
|
+
if (words.some((word, index) => word.wordIndex !== index || word.range.endUs > analysis.durationUs)) {
|
|
887
|
+
context.addIssue({ code: "custom", message: "Transcript word indices must be contiguous and ranges bounded." });
|
|
888
|
+
}
|
|
889
|
+
if (!rangesAreOrderedAndDisjoint(fillers)) {
|
|
890
|
+
context.addIssue({ code: "custom", message: "Filler candidates must be ordered and non-overlapping." });
|
|
891
|
+
}
|
|
892
|
+
for (const filler of fillers) {
|
|
893
|
+
if (filler.wordEndExclusive > words.length) {
|
|
894
|
+
context.addIssue({ code: "custom", message: `Filler ${filler.candidateId} exceeds the transcript word range.` });
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
for (const utterance of utterances) {
|
|
898
|
+
if (
|
|
899
|
+
utterance.wordEndExclusive <= utterance.wordStart
|
|
900
|
+
|| utterance.wordEndExclusive > words.length
|
|
901
|
+
|| utterance.range.endUs > analysis.durationUs
|
|
902
|
+
) {
|
|
903
|
+
context.addIssue({ code: "custom", message: "Speech utterance word and time ranges must be valid." });
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
});
|
|
907
|
+
|
|
908
|
+
export type AnalysisSubject = ReadonlyInferred<typeof AnalysisSubjectSchema>;
|
|
909
|
+
export type AlignmentCandidate = ReadonlyInferred<typeof AlignmentCandidateSchema>;
|
|
910
|
+
export type AudioAlignmentAnalysisV1 = ReadonlyInferred<typeof AudioAlignmentAnalysisV1Schema>;
|
|
911
|
+
export type FaceAnalysisConfig = ReadonlyInferred<typeof FaceAnalysisConfigSchema>;
|
|
912
|
+
export type FaceAnalysisFrameResult = ReadonlyInferred<typeof FaceAnalysisFrameResultSchema>;
|
|
913
|
+
export type FaceAnalysisV1 = ReadonlyInferred<typeof FaceAnalysisV1Schema>;
|
|
914
|
+
export type FaceTrack = ReadonlyInferred<typeof FaceTrackSchema>;
|
|
915
|
+
export type FaceTrackId = ReadonlyInferred<typeof FaceTrackIdSchema>;
|
|
916
|
+
export type FaceTrackingConfig = ReadonlyInferred<typeof FaceTrackingConfigSchema>;
|
|
917
|
+
export type NormalizedTopLeftRect = ReadonlyInferred<typeof NormalizedTopLeftRectSchema>;
|
|
918
|
+
export type RawFaceDetection = ReadonlyInferred<typeof RawFaceDetectionSchema>;
|
|
919
|
+
export type RawFaceDetectionFrame = ReadonlyInferred<typeof RawFaceDetectionFrameSchema>;
|
|
920
|
+
export type TrackedFaceDetection = ReadonlyInferred<typeof TrackedFaceDetectionSchema>;
|
|
921
|
+
export type ProjectInactivityAnalysisV1 = ReadonlyInferred<typeof ProjectInactivityAnalysisV1Schema>;
|
|
922
|
+
export type MusicAnalysisV1 = ReadonlyInferred<typeof MusicAnalysisV1Schema>;
|
|
923
|
+
export type SceneAnalysisV1 = ReadonlyInferred<typeof SceneAnalysisV1Schema>;
|
|
924
|
+
export type SpeechAnalysisV1 = ReadonlyInferred<typeof SpeechAnalysisV1Schema>;
|
|
925
|
+
export type FillerCandidate = ReadonlyInferred<typeof FillerCandidateSchema>;
|
|
926
|
+
|
|
927
|
+
export function parseAudioAlignmentAnalysisV1(input: unknown): AudioAlignmentAnalysisV1 {
|
|
928
|
+
return AudioAlignmentAnalysisV1Schema.parse(input);
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
export function parseFaceAnalysisV1(input: unknown): FaceAnalysisV1 {
|
|
932
|
+
return FaceAnalysisV1Schema.parse(input);
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
export function parseProjectInactivityAnalysisV1(input: unknown): ProjectInactivityAnalysisV1 {
|
|
936
|
+
return ProjectInactivityAnalysisV1Schema.parse(input);
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
export function parseMusicAnalysisV1(input: unknown): MusicAnalysisV1 {
|
|
940
|
+
return MusicAnalysisV1Schema.parse(input);
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
export function parseSceneAnalysisV1(input: unknown): SceneAnalysisV1 {
|
|
944
|
+
return SceneAnalysisV1Schema.parse(input);
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
export function parseSpeechAnalysisV1(input: unknown): SpeechAnalysisV1 {
|
|
948
|
+
return SpeechAnalysisV1Schema.parse(input);
|
|
949
|
+
}
|