@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,326 @@
|
|
|
1
|
+
import {
|
|
2
|
+
FaceAnalysisFrameResultSchema,
|
|
3
|
+
FaceTrackIdSchema,
|
|
4
|
+
FaceTrackSchema,
|
|
5
|
+
FaceTrackingConfigSchema,
|
|
6
|
+
RawFaceDetectionFramesSchema,
|
|
7
|
+
type FaceAnalysisFrameResult,
|
|
8
|
+
type FaceTrack,
|
|
9
|
+
type FaceTrackId,
|
|
10
|
+
type FaceTrackingConfig,
|
|
11
|
+
type NormalizedTopLeftRect,
|
|
12
|
+
type RawFaceDetection,
|
|
13
|
+
type RawFaceDetectionFrame,
|
|
14
|
+
type TrackedFaceDetection,
|
|
15
|
+
} from "../contracts/analysis";
|
|
16
|
+
|
|
17
|
+
export interface FaceDetectionPort<Request> {
|
|
18
|
+
detect(request: Request): Promise<RawFaceDetectionFrame>;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export type AnalyzedFaceFrameResult = Extract<FaceAnalysisFrameResult, { readonly state: "analyzed" }>;
|
|
22
|
+
|
|
23
|
+
export type FaceAssociationResult = Readonly<{
|
|
24
|
+
results: readonly AnalyzedFaceFrameResult[];
|
|
25
|
+
tracks: readonly FaceTrack[];
|
|
26
|
+
}>;
|
|
27
|
+
|
|
28
|
+
type TrackObservation = Readonly<{
|
|
29
|
+
assetTimeUs: number;
|
|
30
|
+
confidence: number;
|
|
31
|
+
rect: NormalizedTopLeftRect;
|
|
32
|
+
}>;
|
|
33
|
+
|
|
34
|
+
type MutableTrack = {
|
|
35
|
+
observations: TrackObservation[];
|
|
36
|
+
trackId: FaceTrackId;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const INVALID_MATCH_COST = 1_000_000_000;
|
|
40
|
+
const UNMATCHED_TRACK_COST = 10;
|
|
41
|
+
const MAX_TRACKS = 100_000;
|
|
42
|
+
|
|
43
|
+
function compareNumber(left: number, right: number): number {
|
|
44
|
+
return left < right ? -1 : left > right ? 1 : 0;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function compareRects(left: NormalizedTopLeftRect, right: NormalizedTopLeftRect): number {
|
|
48
|
+
return (
|
|
49
|
+
compareNumber(left.x, right.x)
|
|
50
|
+
|| compareNumber(left.y, right.y)
|
|
51
|
+
|| compareNumber(left.width, right.width)
|
|
52
|
+
|| compareNumber(left.height, right.height)
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function compareDetections(left: RawFaceDetection, right: RawFaceDetection): number {
|
|
57
|
+
return compareRects(left.rect, right.rect) || compareNumber(right.confidence, left.confidence);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function selectedDetections(
|
|
61
|
+
frame: RawFaceDetectionFrame,
|
|
62
|
+
config: FaceTrackingConfig,
|
|
63
|
+
): Readonly<{ detections: readonly RawFaceDetection[]; discardedDetections: number }> {
|
|
64
|
+
const aboveConfidence = frame.detections
|
|
65
|
+
.filter(detection => detection.confidence >= config.minimumConfidence)
|
|
66
|
+
.sort((left, right) => (
|
|
67
|
+
compareNumber(right.confidence, left.confidence)
|
|
68
|
+
|| compareRects(left.rect, right.rect)
|
|
69
|
+
));
|
|
70
|
+
const detections = aboveConfidence
|
|
71
|
+
.slice(0, config.maximumFacesPerFrame)
|
|
72
|
+
.sort(compareDetections);
|
|
73
|
+
return {
|
|
74
|
+
detections,
|
|
75
|
+
discardedDetections: frame.detections.length - detections.length,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function center(rect: NormalizedTopLeftRect): Readonly<{ x: number; y: number }> {
|
|
80
|
+
return { x: rect.x + rect.width / 2, y: rect.y + rect.height / 2 };
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function clamp(value: number, minimum: number, maximum: number): number {
|
|
84
|
+
return Math.min(maximum, Math.max(minimum, value));
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function predictedRect(track: MutableTrack, assetTimeUs: number): NormalizedTopLeftRect {
|
|
88
|
+
const last = track.observations.at(-1);
|
|
89
|
+
if (last === undefined) throw new TypeError(`Face track ${track.trackId} has no observations.`);
|
|
90
|
+
const prior = track.observations.at(-2);
|
|
91
|
+
if (prior === undefined || last.assetTimeUs === prior.assetTimeUs) return last.rect;
|
|
92
|
+
const elapsedUs = assetTimeUs - last.assetTimeUs;
|
|
93
|
+
const observationDeltaUs = last.assetTimeUs - prior.assetTimeUs;
|
|
94
|
+
const lastCenter = center(last.rect);
|
|
95
|
+
const priorCenter = center(prior.rect);
|
|
96
|
+
const predictedCenterX = lastCenter.x + ((lastCenter.x - priorCenter.x) / observationDeltaUs) * elapsedUs;
|
|
97
|
+
const predictedCenterY = lastCenter.y + ((lastCenter.y - priorCenter.y) / observationDeltaUs) * elapsedUs;
|
|
98
|
+
return {
|
|
99
|
+
height: last.rect.height,
|
|
100
|
+
width: last.rect.width,
|
|
101
|
+
x: clamp(predictedCenterX - last.rect.width / 2, 0, 1 - last.rect.width),
|
|
102
|
+
y: clamp(predictedCenterY - last.rect.height / 2, 0, 1 - last.rect.height),
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export function normalizedRectIou(
|
|
107
|
+
left: NormalizedTopLeftRect,
|
|
108
|
+
right: NormalizedTopLeftRect,
|
|
109
|
+
): number {
|
|
110
|
+
const intersectionWidth = Math.max(
|
|
111
|
+
0,
|
|
112
|
+
Math.min(left.x + left.width, right.x + right.width) - Math.max(left.x, right.x),
|
|
113
|
+
);
|
|
114
|
+
const intersectionHeight = Math.max(
|
|
115
|
+
0,
|
|
116
|
+
Math.min(left.y + left.height, right.y + right.height) - Math.max(left.y, right.y),
|
|
117
|
+
);
|
|
118
|
+
const intersection = intersectionWidth * intersectionHeight;
|
|
119
|
+
if (intersection === 0) return 0;
|
|
120
|
+
return intersection / (left.width * left.height + right.width * right.height - intersection);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function centerDistance(left: NormalizedTopLeftRect, right: NormalizedTopLeftRect): number {
|
|
124
|
+
const leftCenter = center(left);
|
|
125
|
+
const rightCenter = center(right);
|
|
126
|
+
return Math.hypot(leftCenter.x - rightCenter.x, leftCenter.y - rightCenter.y);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function associationCost(
|
|
130
|
+
track: MutableTrack,
|
|
131
|
+
detection: RawFaceDetection,
|
|
132
|
+
assetTimeUs: number,
|
|
133
|
+
config: FaceTrackingConfig,
|
|
134
|
+
): number {
|
|
135
|
+
const predicted = predictedRect(track, assetTimeUs);
|
|
136
|
+
const iou = normalizedRectIou(predicted, detection.rect);
|
|
137
|
+
const distance = centerDistance(predicted, detection.rect);
|
|
138
|
+
if (iou < config.minimumIou && distance > config.maximumCenterDistance) {
|
|
139
|
+
return INVALID_MATCH_COST;
|
|
140
|
+
}
|
|
141
|
+
const normalizedDistance = Math.min(1, distance / config.maximumCenterDistance);
|
|
142
|
+
return config.iouWeight * (1 - iou) + (1 - config.iouWeight) * normalizedDistance;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Minimum-cost row assignment for a rectangular matrix with at least as many
|
|
147
|
+
* columns as rows. Iteration order is deliberate so equal-cost solutions are
|
|
148
|
+
* stable after tracks and detections have been canonically ordered.
|
|
149
|
+
*/
|
|
150
|
+
function minimumCostAssignment(costs: readonly (readonly number[])[]): readonly number[] {
|
|
151
|
+
const rowCount = costs.length;
|
|
152
|
+
if (rowCount === 0) return [];
|
|
153
|
+
const columnCount = costs[0]?.length ?? 0;
|
|
154
|
+
if (columnCount < rowCount || costs.some(row => row.length !== columnCount)) {
|
|
155
|
+
throw new TypeError("Face association cost matrix must be rectangular with enough columns.");
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const rowPotential = Array.from({ length: rowCount + 1 }, () => 0);
|
|
159
|
+
const columnPotential = Array.from({ length: columnCount + 1 }, () => 0);
|
|
160
|
+
const matchedRowByColumn = Array.from({ length: columnCount + 1 }, () => 0);
|
|
161
|
+
const predecessorColumn = Array.from({ length: columnCount + 1 }, () => 0);
|
|
162
|
+
|
|
163
|
+
for (let row = 1; row <= rowCount; row += 1) {
|
|
164
|
+
matchedRowByColumn[0] = row;
|
|
165
|
+
let currentColumn = 0;
|
|
166
|
+
const minimumReducedCost = Array.from({ length: columnCount + 1 }, () => Number.POSITIVE_INFINITY);
|
|
167
|
+
const used = Array.from({ length: columnCount + 1 }, () => false);
|
|
168
|
+
do {
|
|
169
|
+
used[currentColumn] = true;
|
|
170
|
+
const currentRow = matchedRowByColumn[currentColumn]!;
|
|
171
|
+
let delta = Number.POSITIVE_INFINITY;
|
|
172
|
+
let nextColumn = 0;
|
|
173
|
+
for (let column = 1; column <= columnCount; column += 1) {
|
|
174
|
+
if (used[column]) continue;
|
|
175
|
+
const reducedCost = costs[currentRow - 1]![column - 1]!
|
|
176
|
+
- rowPotential[currentRow]!
|
|
177
|
+
- columnPotential[column]!;
|
|
178
|
+
if (reducedCost < minimumReducedCost[column]!) {
|
|
179
|
+
minimumReducedCost[column] = reducedCost;
|
|
180
|
+
predecessorColumn[column] = currentColumn;
|
|
181
|
+
}
|
|
182
|
+
if (
|
|
183
|
+
minimumReducedCost[column]! < delta
|
|
184
|
+
|| (minimumReducedCost[column] === delta && column < nextColumn)
|
|
185
|
+
) {
|
|
186
|
+
delta = minimumReducedCost[column]!;
|
|
187
|
+
nextColumn = column;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
if (!Number.isFinite(delta) || nextColumn === 0) {
|
|
191
|
+
throw new TypeError("Face association could not find a finite assignment.");
|
|
192
|
+
}
|
|
193
|
+
for (let column = 0; column <= columnCount; column += 1) {
|
|
194
|
+
if (used[column]) {
|
|
195
|
+
const matchedRow = matchedRowByColumn[column]!;
|
|
196
|
+
rowPotential[matchedRow] = rowPotential[matchedRow]! + delta;
|
|
197
|
+
columnPotential[column] = columnPotential[column]! - delta;
|
|
198
|
+
} else {
|
|
199
|
+
minimumReducedCost[column] = minimumReducedCost[column]! - delta;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
currentColumn = nextColumn;
|
|
203
|
+
} while (matchedRowByColumn[currentColumn] !== 0);
|
|
204
|
+
|
|
205
|
+
do {
|
|
206
|
+
const previousColumn = predecessorColumn[currentColumn]!;
|
|
207
|
+
matchedRowByColumn[currentColumn] = matchedRowByColumn[previousColumn]!;
|
|
208
|
+
currentColumn = previousColumn;
|
|
209
|
+
} while (currentColumn !== 0);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const assignedColumnByRow = Array.from({ length: rowCount }, () => -1);
|
|
213
|
+
for (let column = 1; column <= columnCount; column += 1) {
|
|
214
|
+
const row = matchedRowByColumn[column]!;
|
|
215
|
+
if (row !== 0) assignedColumnByRow[row - 1] = column - 1;
|
|
216
|
+
}
|
|
217
|
+
return assignedColumnByRow;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function trackId(index: number): FaceTrackId {
|
|
221
|
+
return FaceTrackIdSchema.parse(`face_${String(index).padStart(8, "0")}`);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function maximumObservedGapUs(observations: readonly TrackObservation[]): number {
|
|
225
|
+
let maximum = 0;
|
|
226
|
+
for (let index = 1; index < observations.length; index += 1) {
|
|
227
|
+
maximum = Math.max(maximum, observations[index]!.assetTimeUs - observations[index - 1]!.assetTimeUs);
|
|
228
|
+
}
|
|
229
|
+
return maximum;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Associates local detector boxes by geometry only. Input frame and detection
|
|
234
|
+
* order do not influence the output; births receive deterministic IDs in
|
|
235
|
+
* asset-time and top-left geometry order.
|
|
236
|
+
*/
|
|
237
|
+
export function associateFaceDetections(
|
|
238
|
+
framesInput: unknown,
|
|
239
|
+
configInput: unknown,
|
|
240
|
+
): FaceAssociationResult {
|
|
241
|
+
const config = FaceTrackingConfigSchema.parse(configInput);
|
|
242
|
+
const frames = [...RawFaceDetectionFramesSchema.parse(framesInput)]
|
|
243
|
+
.sort((left, right) => left.assetTimeUs - right.assetTimeUs);
|
|
244
|
+
for (let index = 1; index < frames.length; index += 1) {
|
|
245
|
+
if (frames[index]!.assetTimeUs === frames[index - 1]!.assetTimeUs) {
|
|
246
|
+
throw new TypeError("Raw face detection frame times must be unique.");
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
const tracks: MutableTrack[] = [];
|
|
251
|
+
const results: AnalyzedFaceFrameResult[] = [];
|
|
252
|
+
|
|
253
|
+
for (const frame of frames) {
|
|
254
|
+
const selected = selectedDetections(frame, config);
|
|
255
|
+
const activeTracks = tracks
|
|
256
|
+
.filter((track) => {
|
|
257
|
+
const last = track.observations.at(-1);
|
|
258
|
+
return last !== undefined && frame.assetTimeUs - last.assetTimeUs <= config.maximumGapUs;
|
|
259
|
+
})
|
|
260
|
+
.sort((left, right) => left.trackId.localeCompare(right.trackId));
|
|
261
|
+
|
|
262
|
+
const costs = activeTracks.map((track) => [
|
|
263
|
+
...selected.detections.map(detection => associationCost(track, detection, frame.assetTimeUs, config)),
|
|
264
|
+
...activeTracks.map(() => UNMATCHED_TRACK_COST),
|
|
265
|
+
]);
|
|
266
|
+
const assignedColumns = minimumCostAssignment(costs);
|
|
267
|
+
const matchedDetectionIndexes = new Set<number>();
|
|
268
|
+
const detections: TrackedFaceDetection[] = [];
|
|
269
|
+
|
|
270
|
+
for (let trackIndex = 0; trackIndex < activeTracks.length; trackIndex += 1) {
|
|
271
|
+
const detectionIndex = assignedColumns[trackIndex]!;
|
|
272
|
+
const track = activeTracks[trackIndex]!;
|
|
273
|
+
const detection = selected.detections[detectionIndex];
|
|
274
|
+
if (
|
|
275
|
+
detection === undefined
|
|
276
|
+
|| detectionIndex >= selected.detections.length
|
|
277
|
+
|| costs[trackIndex]![detectionIndex]! >= INVALID_MATCH_COST
|
|
278
|
+
) {
|
|
279
|
+
continue;
|
|
280
|
+
}
|
|
281
|
+
matchedDetectionIndexes.add(detectionIndex);
|
|
282
|
+
track.observations.push({
|
|
283
|
+
assetTimeUs: frame.assetTimeUs,
|
|
284
|
+
confidence: detection.confidence,
|
|
285
|
+
rect: detection.rect,
|
|
286
|
+
});
|
|
287
|
+
detections.push({ ...detection, trackId: track.trackId });
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
for (let detectionIndex = 0; detectionIndex < selected.detections.length; detectionIndex += 1) {
|
|
291
|
+
if (matchedDetectionIndexes.has(detectionIndex)) continue;
|
|
292
|
+
if (tracks.length >= MAX_TRACKS) {
|
|
293
|
+
throw new RangeError(`Face association exceeds the ${MAX_TRACKS} track evidence limit.`);
|
|
294
|
+
}
|
|
295
|
+
const detection = selected.detections[detectionIndex]!;
|
|
296
|
+
const created: MutableTrack = {
|
|
297
|
+
observations: [{
|
|
298
|
+
assetTimeUs: frame.assetTimeUs,
|
|
299
|
+
confidence: detection.confidence,
|
|
300
|
+
rect: detection.rect,
|
|
301
|
+
}],
|
|
302
|
+
trackId: trackId(tracks.length + 1),
|
|
303
|
+
};
|
|
304
|
+
tracks.push(created);
|
|
305
|
+
detections.push({ ...detection, trackId: created.trackId });
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
results.push(FaceAnalysisFrameResultSchema.parse({
|
|
309
|
+
assetTimeUs: frame.assetTimeUs,
|
|
310
|
+
detections: detections.sort((left, right) => left.trackId.localeCompare(right.trackId)),
|
|
311
|
+
discardedDetections: selected.discardedDetections,
|
|
312
|
+
state: "analyzed",
|
|
313
|
+
}) as AnalyzedFaceFrameResult);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
return {
|
|
317
|
+
results,
|
|
318
|
+
tracks: tracks.map((track) => FaceTrackSchema.parse({
|
|
319
|
+
firstSeenAssetTimeUs: track.observations[0]!.assetTimeUs,
|
|
320
|
+
lastSeenAssetTimeUs: track.observations.at(-1)!.assetTimeUs,
|
|
321
|
+
maximumObservedGapUs: maximumObservedGapUs(track.observations),
|
|
322
|
+
observationCount: track.observations.length,
|
|
323
|
+
trackId: track.trackId,
|
|
324
|
+
})),
|
|
325
|
+
};
|
|
326
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AnalyzerEvidenceV1Schema,
|
|
3
|
+
InactivityPlannerConfigSchema,
|
|
4
|
+
type AnalyzerEvidenceV1,
|
|
5
|
+
type InactivityPlannerConfig,
|
|
6
|
+
} from "../contracts/render";
|
|
7
|
+
import type { SourceInterval } from "../contracts/edit";
|
|
8
|
+
import type { RecordingEventV1 } from "../contracts/recording";
|
|
9
|
+
import { clipIntervals, expandIntervals, intersectManyIntervalSets, subtractIntervals } from "./intervals";
|
|
10
|
+
|
|
11
|
+
export const DEFAULT_MINIMUM_FREEZE_CONFIDENCE = 0.9;
|
|
12
|
+
|
|
13
|
+
export interface AutomaticInactivityPlan {
|
|
14
|
+
readonly cuts: readonly SourceInterval[];
|
|
15
|
+
readonly candidateCount: number;
|
|
16
|
+
readonly protectedInteractionCount: number;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export type InactivityInteractionSource =
|
|
20
|
+
| "mouse.click"
|
|
21
|
+
| "key.activity"
|
|
22
|
+
| "typing.input"
|
|
23
|
+
| "focus.changed"
|
|
24
|
+
| "cursor.movement";
|
|
25
|
+
|
|
26
|
+
export interface InactivityInteractionInterval {
|
|
27
|
+
readonly range: SourceInterval;
|
|
28
|
+
readonly source: InactivityInteractionSource;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function recordingInteractionIntervals(
|
|
32
|
+
events: readonly RecordingEventV1[],
|
|
33
|
+
cursorMovementThresholdPx: number,
|
|
34
|
+
): readonly InactivityInteractionInterval[] {
|
|
35
|
+
const explicit = events.flatMap((event) => {
|
|
36
|
+
switch (event.type) {
|
|
37
|
+
case "mouse.click":
|
|
38
|
+
case "key.activity":
|
|
39
|
+
case "typing.input":
|
|
40
|
+
case "focus.changed":
|
|
41
|
+
return [{
|
|
42
|
+
range: { startUs: event.sourceTimeUs, endUs: event.sourceTimeUs + 1 },
|
|
43
|
+
source: event.type,
|
|
44
|
+
}];
|
|
45
|
+
case "cursor.sample":
|
|
46
|
+
case "window.snapshot":
|
|
47
|
+
case "window.changed":
|
|
48
|
+
case "display.topology":
|
|
49
|
+
case "lifecycle.marker":
|
|
50
|
+
case "diagnostic.dropped-events":
|
|
51
|
+
return [];
|
|
52
|
+
default:
|
|
53
|
+
return [];
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
const priorCursorByDisplay = new Map<string, Extract<RecordingEventV1, { readonly type: "cursor.sample" }>>();
|
|
57
|
+
const movement: InactivityInteractionInterval[] = [];
|
|
58
|
+
for (const event of [...events].sort((left, right) => left.sourceTimeUs - right.sourceTimeUs || left.sequence - right.sequence)) {
|
|
59
|
+
if (event.type !== "cursor.sample") continue;
|
|
60
|
+
const prior = priorCursorByDisplay.get(event.displayId);
|
|
61
|
+
if (
|
|
62
|
+
prior !== undefined
|
|
63
|
+
&& Math.hypot(event.position.x - prior.position.x, event.position.y - prior.position.y) > cursorMovementThresholdPx
|
|
64
|
+
&& event.sourceTimeUs > prior.sourceTimeUs
|
|
65
|
+
) {
|
|
66
|
+
movement.push({
|
|
67
|
+
range: { startUs: prior.sourceTimeUs, endUs: event.sourceTimeUs + 1 },
|
|
68
|
+
source: "cursor.movement",
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
priorCursorByDisplay.set(event.displayId, event);
|
|
72
|
+
}
|
|
73
|
+
return [...explicit, ...movement].sort((left, right) => (
|
|
74
|
+
left.range.startUs - right.range.startUs
|
|
75
|
+
|| left.range.endUs - right.range.endUs
|
|
76
|
+
|| left.source.localeCompare(right.source)
|
|
77
|
+
));
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export interface MappedInactivityEvidence {
|
|
81
|
+
readonly audioIntervals: readonly (readonly SourceInterval[])[];
|
|
82
|
+
readonly displayIntervals: readonly (readonly SourceInterval[])[];
|
|
83
|
+
readonly interactionIntervals: readonly SourceInterval[];
|
|
84
|
+
readonly sourceDurationUs: number;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export function planMappedInactivityCuts(
|
|
88
|
+
evidence: MappedInactivityEvidence,
|
|
89
|
+
configInput: InactivityPlannerConfig,
|
|
90
|
+
): AutomaticInactivityPlan {
|
|
91
|
+
const config = InactivityPlannerConfigSchema.parse(configInput);
|
|
92
|
+
const sourceBounds = { startUs: 0, endUs: evidence.sourceDurationUs };
|
|
93
|
+
let candidates = clipIntervals(intersectManyIntervalSets(evidence.displayIntervals), sourceBounds);
|
|
94
|
+
if (config.requireAudioSilence) {
|
|
95
|
+
if (evidence.audioIntervals.length === 0) {
|
|
96
|
+
return { cuts: [], candidateCount: candidates.length, protectedInteractionCount: 0 };
|
|
97
|
+
}
|
|
98
|
+
candidates = intersectManyIntervalSets([candidates, ...evidence.audioIntervals]);
|
|
99
|
+
}
|
|
100
|
+
const edgeHandled = candidates.flatMap(({ startUs, endUs }) => {
|
|
101
|
+
const handled = { startUs: startUs + config.edgeHandleUs, endUs: endUs - config.edgeHandleUs };
|
|
102
|
+
return handled.endUs > handled.startUs ? [handled] : [];
|
|
103
|
+
});
|
|
104
|
+
const protectedInteractions = expandIntervals(
|
|
105
|
+
evidence.interactionIntervals,
|
|
106
|
+
config.interactionHandleUs,
|
|
107
|
+
config.interactionHandleUs,
|
|
108
|
+
sourceBounds,
|
|
109
|
+
);
|
|
110
|
+
const cuts = clipIntervals(subtractIntervals(edgeHandled, protectedInteractions), sourceBounds)
|
|
111
|
+
.filter(({ startUs, endUs }) => endUs - startUs >= config.minimumCutUs);
|
|
112
|
+
return {
|
|
113
|
+
candidateCount: candidates.length,
|
|
114
|
+
cuts,
|
|
115
|
+
protectedInteractionCount: protectedInteractions.length,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export function planAutomaticInactivityCuts(
|
|
120
|
+
evidenceInput: AnalyzerEvidenceV1,
|
|
121
|
+
events: readonly RecordingEventV1[],
|
|
122
|
+
configInput: InactivityPlannerConfig,
|
|
123
|
+
): AutomaticInactivityPlan {
|
|
124
|
+
const evidence = AnalyzerEvidenceV1Schema.parse(evidenceInput);
|
|
125
|
+
const config = InactivityPlannerConfigSchema.parse(configInput);
|
|
126
|
+
const minimumFreezeConfidence = config.minimumFreezeConfidence ?? DEFAULT_MINIMUM_FREEZE_CONFIDENCE;
|
|
127
|
+
const displaySets = evidence.displays.map(({ intervals }) => intervals
|
|
128
|
+
.filter(({ confidence }) => confidence >= minimumFreezeConfidence)
|
|
129
|
+
.map(({ range }) => range));
|
|
130
|
+
return planMappedInactivityCuts({
|
|
131
|
+
audioIntervals: evidence.audio.map(({ intervals }) => intervals.map(({ range }) => range)),
|
|
132
|
+
displayIntervals: displaySets,
|
|
133
|
+
interactionIntervals: recordingInteractionIntervals(events, config.cursorMovementThresholdPx)
|
|
134
|
+
.map(({ range }) => range),
|
|
135
|
+
sourceDurationUs: evidence.sourceDurationUs,
|
|
136
|
+
}, config);
|
|
137
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export * from "./auto-zoom";
|
|
2
|
+
export * from "./audio-alignment";
|
|
3
|
+
export * from "./alignment-apply";
|
|
4
|
+
export * from "./canonical-json";
|
|
5
|
+
export * from "./emoji";
|
|
6
|
+
export * from "./events";
|
|
7
|
+
export * from "./face-framing";
|
|
8
|
+
export * from "./face-tracks";
|
|
9
|
+
export * from "./inactivity";
|
|
10
|
+
export * from "./intervals";
|
|
11
|
+
export * from "./plan";
|
|
12
|
+
export * from "./music-analysis";
|
|
13
|
+
export * from "./montage";
|
|
14
|
+
export * from "./project-plan";
|
|
15
|
+
export * from "./project-camera";
|
|
16
|
+
export * from "./project-camera-spatial";
|
|
17
|
+
export * from "./project-captions";
|
|
18
|
+
export * from "./project-inactivity";
|
|
19
|
+
export * from "./project-metadata";
|
|
20
|
+
export * from "./project-render-plan";
|
|
21
|
+
export * from "./project-time";
|
|
22
|
+
export * from "./project-auto-zoom";
|
|
23
|
+
export * from "./scene-cache";
|
|
24
|
+
export * from "./scene-sampling";
|
|
25
|
+
export * from "./render-plan";
|
|
26
|
+
export * from "./storage";
|
|
27
|
+
export * from "./speech-analysis";
|
|
28
|
+
export * from "./time";
|
|
29
|
+
export * from "./time-map";
|
|
30
|
+
export * from "./video-effects";
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import type { SourceInterval } from "../contracts/edit";
|
|
2
|
+
|
|
3
|
+
function compareIntervals(left: SourceInterval, right: SourceInterval): number {
|
|
4
|
+
return left.startUs - right.startUs || left.endUs - right.endUs;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function intervalDurationUs(interval: SourceInterval): number {
|
|
8
|
+
return interval.endUs - interval.startUs;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function unionIntervals(intervals: readonly SourceInterval[]): readonly SourceInterval[] {
|
|
12
|
+
if (intervals.length === 0) return [];
|
|
13
|
+
const ordered = [...intervals].sort(compareIntervals);
|
|
14
|
+
const result: SourceInterval[] = [];
|
|
15
|
+
for (const interval of ordered) {
|
|
16
|
+
if (interval.endUs <= interval.startUs) continue;
|
|
17
|
+
const prior = result.at(-1);
|
|
18
|
+
if (prior === undefined || interval.startUs > prior.endUs) {
|
|
19
|
+
result.push({ startUs: interval.startUs, endUs: interval.endUs });
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
if (interval.endUs > prior.endUs) {
|
|
23
|
+
result[result.length - 1] = { startUs: prior.startUs, endUs: interval.endUs };
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return result;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function intersectIntervals(
|
|
30
|
+
left: readonly SourceInterval[],
|
|
31
|
+
right: readonly SourceInterval[],
|
|
32
|
+
): readonly SourceInterval[] {
|
|
33
|
+
const normalizedLeft = unionIntervals(left);
|
|
34
|
+
const normalizedRight = unionIntervals(right);
|
|
35
|
+
const result: SourceInterval[] = [];
|
|
36
|
+
let leftIndex = 0;
|
|
37
|
+
let rightIndex = 0;
|
|
38
|
+
while (leftIndex < normalizedLeft.length && rightIndex < normalizedRight.length) {
|
|
39
|
+
const leftInterval = normalizedLeft[leftIndex];
|
|
40
|
+
const rightInterval = normalizedRight[rightIndex];
|
|
41
|
+
if (leftInterval === undefined || rightInterval === undefined) break;
|
|
42
|
+
const startUs = Math.max(leftInterval.startUs, rightInterval.startUs);
|
|
43
|
+
const endUs = Math.min(leftInterval.endUs, rightInterval.endUs);
|
|
44
|
+
if (endUs > startUs) result.push({ startUs, endUs });
|
|
45
|
+
if (leftInterval.endUs <= rightInterval.endUs) leftIndex += 1;
|
|
46
|
+
else rightIndex += 1;
|
|
47
|
+
}
|
|
48
|
+
return result;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function intersectManyIntervalSets(
|
|
52
|
+
sets: readonly (readonly SourceInterval[])[],
|
|
53
|
+
): readonly SourceInterval[] {
|
|
54
|
+
if (sets.length === 0) return [];
|
|
55
|
+
const first = sets[0];
|
|
56
|
+
if (first === undefined) return [];
|
|
57
|
+
return sets.slice(1).reduce<readonly SourceInterval[]>(
|
|
58
|
+
(result, intervals) => intersectIntervals(result, intervals),
|
|
59
|
+
unionIntervals(first),
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function subtractIntervals(
|
|
64
|
+
source: readonly SourceInterval[],
|
|
65
|
+
removed: readonly SourceInterval[],
|
|
66
|
+
): readonly SourceInterval[] {
|
|
67
|
+
const normalizedSource = unionIntervals(source);
|
|
68
|
+
const normalizedRemoved = unionIntervals(removed);
|
|
69
|
+
const result: SourceInterval[] = [];
|
|
70
|
+
let removedIndex = 0;
|
|
71
|
+
for (const sourceInterval of normalizedSource) {
|
|
72
|
+
let cursor = sourceInterval.startUs;
|
|
73
|
+
while (
|
|
74
|
+
removedIndex < normalizedRemoved.length
|
|
75
|
+
&& (normalizedRemoved[removedIndex]?.endUs ?? Number.POSITIVE_INFINITY) <= cursor
|
|
76
|
+
) {
|
|
77
|
+
removedIndex += 1;
|
|
78
|
+
}
|
|
79
|
+
let scanIndex = removedIndex;
|
|
80
|
+
while (scanIndex < normalizedRemoved.length) {
|
|
81
|
+
const cut = normalizedRemoved[scanIndex];
|
|
82
|
+
if (cut === undefined || cut.startUs >= sourceInterval.endUs) break;
|
|
83
|
+
if (cut.startUs > cursor) {
|
|
84
|
+
result.push({ startUs: cursor, endUs: Math.min(cut.startUs, sourceInterval.endUs) });
|
|
85
|
+
}
|
|
86
|
+
cursor = Math.max(cursor, cut.endUs);
|
|
87
|
+
if (cursor >= sourceInterval.endUs) break;
|
|
88
|
+
scanIndex += 1;
|
|
89
|
+
}
|
|
90
|
+
if (cursor < sourceInterval.endUs) result.push({ startUs: cursor, endUs: sourceInterval.endUs });
|
|
91
|
+
}
|
|
92
|
+
return result;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export function clipIntervals(
|
|
96
|
+
intervals: readonly SourceInterval[],
|
|
97
|
+
bounds: SourceInterval,
|
|
98
|
+
): readonly SourceInterval[] {
|
|
99
|
+
return intersectIntervals(intervals, [bounds]);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export function expandIntervals(
|
|
103
|
+
intervals: readonly SourceInterval[],
|
|
104
|
+
beforeUs: number,
|
|
105
|
+
afterUs: number,
|
|
106
|
+
bounds: SourceInterval,
|
|
107
|
+
): readonly SourceInterval[] {
|
|
108
|
+
return unionIntervals(intervals.map((interval) => ({
|
|
109
|
+
startUs: Math.max(bounds.startUs, interval.startUs - beforeUs),
|
|
110
|
+
endUs: Math.min(bounds.endUs, interval.endUs + afterUs),
|
|
111
|
+
})));
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export function intervalContains(container: SourceInterval, candidate: SourceInterval): boolean {
|
|
115
|
+
return container.startUs <= candidate.startUs && container.endUs >= candidate.endUs;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export function intervalsContain(
|
|
119
|
+
containers: readonly SourceInterval[],
|
|
120
|
+
candidate: SourceInterval,
|
|
121
|
+
): boolean {
|
|
122
|
+
return containers.some((container) => intervalContains(container, candidate));
|
|
123
|
+
}
|