@hypit/hypit 0.1.3 → 0.1.5
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/README.md +5 -3
- package/dist/public/caption.d.ts +206 -183
- package/dist/public/composition.d.ts +25 -3
- package/dist/public/endpoint-kit.d.ts +24 -2
- package/dist/public/generation.d.ts +5 -1
- package/dist/public/hyperframes.d.ts +19 -1
- package/dist/public/narrative.d.ts +17 -3
- package/dist/public/performance.d.ts +1590 -0
- package/dist/public/program-space.d.ts +179 -32
- package/dist/public/runtime-kit.d.ts +21 -8
- package/dist/public/sound.d.ts +822 -0
- package/dist/public/speech.d.ts +41 -0
- package/dist/public/studio-adapter.d.ts +107 -16
- package/dist/public/temporal-markup.d.ts +9 -44
- package/dist/public/temporal.d.ts +37 -28
- package/dist/public/{semantic-track.d.ts → timeline.d.ts} +62 -49
- package/examples/README.md +18 -10
- package/examples/minimal-author-package/packages/example-component/preview/preview.svml +19 -12
- package/examples/minimal-author-package/packages/example-component/src/component.ts +5 -5
- package/examples/minimal-author-package/packages/example-component/src/fragment.ts +3 -5
- package/examples/minimal-author-package/packages/example-component/src/manifest.ts +8 -10
- package/examples/minimal-author-package/packages/example-component/src/surface.ts +2 -2
- package/examples/provider-package/README.md +78 -0
- package/examples/provider-package/hypit.runtime.json +12 -0
- package/examples/provider-package/packages/provider-images/package.json +11 -0
- package/examples/provider-package/packages/provider-images/src/activation.ts +24 -0
- package/examples/provider-package/packages/provider-images/src/provider.ts +122 -0
- package/examples/provider-package/packages/provider-images/tsconfig.json +9 -0
- package/examples/semantic-composition/README.md +6 -0
- package/examples/semantic-composition/chat.svml +6 -5
- package/examples/semantic-composition/packages/chat-scene/README.md +3 -3
- package/examples/semantic-composition/packages/chat-scene/src/activation.ts +18 -21
- package/examples/semantic-composition/packages/chat-scene/src/render.ts +4 -4
- package/examples/semantic-composition/packages/performance-styles/README.md +42 -0
- package/examples/semantic-composition/packages/performance-styles/package.json +25 -0
- package/examples/semantic-composition/packages/performance-styles/src/activation.ts +57 -0
- package/examples/semantic-composition/packages/performance-styles/src/render.ts +54 -0
- package/examples/semantic-composition/packages/performance-styles/src/studio.ts +28 -0
- package/examples/semantic-composition/packages/performance-styles/tsconfig.json +18 -0
- package/examples/semantic-composition/packages/responsive-explainer/README.md +16 -9
- package/examples/semantic-composition/packages/responsive-explainer/src/activation.ts +12 -12
- package/examples/semantic-composition/packages/responsive-explainer/src/render.ts +5 -5
- package/examples/semantic-composition/packages/sound-styles/README.md +36 -0
- package/examples/semantic-composition/packages/sound-styles/package.json +25 -0
- package/examples/semantic-composition/packages/sound-styles/src/activation.ts +53 -0
- package/examples/semantic-composition/packages/sound-styles/src/render.ts +14 -0
- package/examples/semantic-composition/packages/sound-styles/tsconfig.json +18 -0
- package/package.json +35 -15
- package/packages/audio-track/README.md +20 -13
- package/packages/audio-track/package.json +1 -1
- package/packages/audio-track/src/component.ts +4 -4
- package/packages/audio-track/src/fragment.ts +6 -5
- package/packages/audio-track/src/index.ts +1 -1
- package/packages/audio-track/src/manifest.ts +17 -16
- package/packages/audio-track/src/program.ts +21 -25
- package/packages/audio-track/src/surface.ts +19 -18
- package/packages/audio-track-studio/README.md +23 -0
- package/packages/audio-track-studio/src/index.ts +33 -19
- package/packages/author-kit/README.md +1 -1
- package/packages/background-removal/README.md +4 -7
- package/packages/browser-capture/package.json +1 -1
- package/packages/build-result/README.md +69 -0
- package/packages/build-result/package.json +2 -1
- package/packages/build-result/src/decode.ts +12 -8
- package/packages/build-result/src/execution-log.ts +17 -0
- package/packages/build-result/src/file-reference.ts +42 -0
- package/packages/build-result/src/index.ts +4 -0
- package/packages/build-result/src/replace-file-windows.ts +58 -0
- package/packages/build-result/src/replace-file.ts +11 -0
- package/packages/build-result/src/store.ts +58 -14
- package/packages/build-result/src/types.ts +41 -8
- package/packages/build-result/src/writer.ts +12 -1
- package/packages/build-result-fs/README.md +23 -1
- package/packages/build-result-s3/README.md +5 -0
- package/packages/build-result-s3/src/repository.ts +23 -5
- package/packages/caption/README.md +61 -73
- package/packages/caption/package.json +3 -2
- package/packages/caption/src/activation.ts +2 -2
- package/packages/caption/src/component.ts +20 -5
- package/packages/caption/src/display.ts +3 -18
- package/packages/caption/src/fragment.ts +3 -7
- package/packages/caption/src/index.ts +6 -5
- package/packages/caption/src/manifest.ts +29 -46
- package/packages/caption/src/style.ts +24 -135
- package/packages/caption/src/surface.ts +12 -92
- package/packages/caption/src/temporalize.ts +18 -53
- package/packages/caption/src/types.ts +8 -35
- package/packages/caption/src/visibility.ts +23 -0
- package/packages/caption-fine/README.md +31 -11
- package/packages/caption-fine/package.json +4 -2
- package/packages/caption-fine/src/component.ts +3 -3
- package/packages/caption-fine/src/fragment.ts +7 -19
- package/packages/caption-fine/src/index.ts +2 -0
- package/packages/caption-fine/src/manifest.ts +27 -18
- package/packages/caption-fine/src/recipe.ts +7 -0
- package/packages/caption-fine/src/render.ts +62 -49
- package/packages/caption-fine/src/schedule.ts +39 -35
- package/packages/caption-fine/src/style.ts +10 -9
- package/packages/caption-fine/src/surface.ts +62 -35
- package/packages/caption-fine/src/types.ts +2 -0
- package/packages/caption-fine-studio/README.md +24 -2
- package/packages/caption-fine-studio/package.json +10 -3
- package/packages/caption-fine-studio/src/activation.ts +3 -3
- package/packages/caption-fine-studio/src/index.ts +61 -40
- package/packages/cli/README.md +81 -3
- package/packages/cli/package.json +1 -0
- package/packages/cli/src/arguments.ts +39 -15
- package/packages/cli/src/build-planning.ts +9 -3
- package/packages/cli/src/command.ts +7 -1
- package/packages/cli/src/commands/environment.ts +66 -27
- package/packages/cli/src/commands/execution.ts +81 -26
- package/packages/cli/src/commands/results.ts +7 -11
- package/packages/cli/src/index.ts +2 -2
- package/packages/cli/src/machine-view.ts +15 -5
- package/packages/cli/src/main.ts +38 -42
- package/packages/cli/src/observation.ts +7 -1
- package/packages/cli/src/output.ts +92 -34
- package/packages/cli/src/result-export.ts +22 -13
- package/packages/cli/src/run-file.ts +19 -8
- package/packages/cli/src/view.ts +64 -18
- package/packages/comment-sticker/README.md +3 -3
- package/packages/comment-sticker/package.json +1 -1
- package/packages/comment-sticker/src/component.ts +4 -4
- package/packages/comment-sticker/src/fragment.ts +5 -4
- package/packages/comment-sticker/src/manifest.ts +7 -6
- package/packages/comment-sticker/src/program.ts +9 -9
- package/packages/comment-sticker/src/surface.ts +6 -7
- package/packages/comment-sticker-studio/src/index.ts +2 -1
- package/packages/compiler-node/src/compiler.ts +1 -0
- package/packages/composition/README.md +21 -0
- package/packages/composition/src/audio-presentation.ts +44 -0
- package/packages/composition/src/index.ts +3 -0
- package/packages/composition/src/schema.ts +8 -3
- package/packages/composition/src/track.ts +15 -1
- package/packages/credential-store-env/README.md +1 -1
- package/packages/deck-track/README.md +3 -3
- package/packages/deck-track/package.json +1 -1
- package/packages/deck-track/src/component.ts +5 -5
- package/packages/deck-track/src/fragment.ts +6 -5
- package/packages/deck-track/src/lower.ts +12 -12
- package/packages/deck-track/src/manifest.ts +8 -7
- package/packages/deck-track/src/program.ts +13 -16
- package/packages/deck-track/src/surface.ts +9 -10
- package/packages/driver-node/src/driver.ts +41 -3
- package/packages/elevenlabs-speech/README.md +27 -0
- package/packages/{provider-xiaomi-mimo → elevenlabs-speech}/package.json +5 -8
- package/packages/elevenlabs-speech/src/activation.ts +26 -0
- package/packages/elevenlabs-speech/src/fragment.ts +11 -0
- package/packages/elevenlabs-speech/src/index.ts +111 -0
- package/packages/elevenlabs-speech/src/surface.ts +167 -0
- package/packages/endpoint-kit/README.md +24 -0
- package/packages/endpoint-kit/src/index.ts +7 -1
- package/packages/estimate/README.md +56 -3
- package/packages/estimate/src/program.ts +7 -8
- package/packages/film/README.md +12 -7
- package/packages/film/package.json +1 -1
- package/packages/film/src/component.ts +4 -4
- package/packages/film/src/fragment.ts +6 -5
- package/packages/film/src/manifest.ts +11 -10
- package/packages/film/src/program.ts +5 -5
- package/packages/film/src/recipe.ts +2 -1
- package/packages/film/src/surface.ts +6 -6
- package/packages/film-studio/package.json +1 -1
- package/packages/film-studio/src/index.ts +2 -2
- package/packages/fishaudio-speech/README.md +33 -0
- package/packages/fishaudio-speech/package.json +21 -0
- package/packages/fishaudio-speech/src/activation.ts +32 -0
- package/packages/fishaudio-speech/src/fragment.ts +11 -0
- package/packages/fishaudio-speech/src/index.ts +156 -0
- package/packages/fishaudio-speech/src/surface.ts +192 -0
- package/packages/fonts-open/README.md +5 -0
- package/packages/fonts-open/package.json +5 -1
- package/packages/fonts-open/src/studio.ts +21 -0
- package/packages/generation/README.md +11 -1
- package/packages/generation/src/mapping.ts +28 -30
- package/packages/gpt-image/README.md +1 -2
- package/packages/grok-imagine/README.md +1 -2
- package/packages/hyperframes/README.md +7 -3
- package/packages/hyperframes/src/browser-program.ts +11 -2
- package/packages/hyperframes/src/document.ts +15 -2
- package/packages/interview-emoji-reveal/README.md +4 -4
- package/packages/interview-emoji-reveal/package.json +1 -1
- package/packages/interview-emoji-reveal/src/component.ts +4 -4
- package/packages/interview-emoji-reveal/src/fragment.ts +6 -5
- package/packages/interview-emoji-reveal/src/manifest.ts +9 -8
- package/packages/interview-emoji-reveal/src/program.ts +14 -14
- package/packages/interview-emoji-reveal/src/surface.ts +8 -9
- package/packages/media-execution/README.md +7 -3
- package/packages/media-execution/src/audio-presentation.ts +23 -0
- package/packages/media-execution/src/execute.ts +2 -0
- package/packages/media-pipeline/README.md +7 -3
- package/packages/media-pipeline/src/audio-plan.ts +4 -1
- package/packages/media-pipeline/src/component.ts +16 -2
- package/packages/media-pipeline/src/manifest.ts +3 -1
- package/packages/media-pipeline/src/types.ts +2 -1
- package/packages/media-track/README.md +14 -47
- package/packages/media-track/package.json +1 -1
- package/packages/media-track/preview/preview.svml +5 -5
- package/packages/media-track/src/author.ts +12 -6
- package/packages/media-track/src/component.ts +10 -16
- package/packages/media-track/src/fragment.ts +8 -7
- package/packages/media-track/src/index.ts +3 -1
- package/packages/media-track/src/lower.ts +7 -7
- package/packages/media-track/src/manifest.ts +16 -38
- package/packages/media-track/src/program.ts +62 -67
- package/packages/media-track/src/sampling.ts +6 -6
- package/packages/media-track/src/sequence.ts +8 -8
- package/packages/media-track/src/surface.ts +25 -43
- package/packages/media-track-studio/README.md +9 -0
- package/packages/media-track-studio/src/index.ts +23 -13
- package/packages/mimo-speech/README.md +1 -1
- package/packages/minimax-h3/README.md +1 -1
- package/packages/nano-banana/README.md +1 -1
- package/packages/narrative/README.md +23 -1
- package/packages/narrative/src/identity.ts +11 -0
- package/packages/narrative/src/index.ts +3 -0
- package/packages/narrative/src/schema.ts +28 -27
- package/packages/narrative/src/selection.ts +52 -0
- package/packages/narrative/src/types.ts +2 -0
- package/packages/package-loader-node/README.md +30 -0
- package/packages/package-loader-node/package.json +5 -2
- package/packages/package-loader-node/src/distribution-resolution.ts +10 -3
- package/packages/package-loader-node/src/index.ts +1 -0
- package/packages/package-loader-node/src/loader.ts +12 -15
- package/packages/package-loader-node/src/location.ts +27 -1
- package/packages/package-loader-node/src/module-scope.ts +183 -0
- package/packages/package-loader-node/src/types.ts +4 -0
- package/packages/performance/README.md +83 -0
- package/packages/performance/package.json +30 -0
- package/packages/performance/src/activation.ts +11 -0
- package/packages/performance/src/component.ts +46 -0
- package/packages/performance/src/index.ts +6 -0
- package/packages/performance/src/manifest.ts +53 -0
- package/packages/{media-track/src/performance.ts → performance/src/media.ts} +9 -10
- package/packages/performance/src/program.ts +51 -0
- package/packages/performance/src/style.ts +35 -0
- package/packages/performance/src/surface.ts +99 -0
- package/packages/performance-studio/README.md +25 -0
- package/packages/performance-studio/package.json +21 -0
- package/packages/performance-studio/src/activation.ts +6 -0
- package/packages/performance-studio/src/index.ts +84 -0
- package/packages/program-space/README.md +9 -18
- package/packages/program-space/src/activation.ts +1 -5
- package/packages/program-space/src/index.ts +2 -11
- package/packages/program-space/src/surface.ts +1 -20
- package/packages/project-context-node/README.md +20 -0
- package/packages/project-context-node/package.json +10 -0
- package/packages/project-context-node/src/index.ts +3 -0
- package/packages/{cli → project-context-node}/src/runtime-selection.ts +7 -2
- package/packages/provider-hyperframes-local/README.md +43 -15
- package/packages/provider-hyperframes-local/src/activation.ts +4 -3
- package/packages/provider-hyperframes-local/src/capture-process.ts +26 -4
- package/packages/provider-hyperframes-local/src/capture.ts +96 -26
- package/packages/provider-hyperframes-local/src/concurrency.ts +86 -0
- package/packages/provider-hyperframes-local/src/opaque-capture.ts +92 -0
- package/packages/provider-hyperframes-local/src/options.ts +2 -0
- package/packages/provider-hyperframes-local/src/program.ts +6 -3
- package/packages/provider-hyperframes-local/src/progress.ts +53 -0
- package/packages/provider-hyperframes-local/src/provider.ts +18 -5
- package/packages/provider-hyperframes-local/src/render.ts +48 -7
- package/packages/provider-hypihub/README.md +48 -17
- package/packages/provider-hypihub/package.json +2 -0
- package/packages/provider-hypihub/src/mapping.ts +31 -7
- package/packages/provider-hypihub/src/oauth.ts +6 -0
- package/packages/provider-hypihub/src/provider.ts +25 -13
- package/packages/provider-hypihub/src/routes.ts +1 -2
- package/packages/provider-hypihub/src/upload.ts +2 -0
- package/packages/provider-media-local/README.md +3 -4
- package/packages/provider-whisperx-local/README.md +57 -0
- package/packages/provider-whisperx-local/src/program.ts +1 -0
- package/packages/provider-whisperx-local/src/provider.ts +3 -0
- package/packages/ranking/README.md +8 -6
- package/packages/ranking/package.json +1 -1
- package/packages/ranking/src/component.ts +6 -6
- package/packages/ranking/src/fragment.ts +11 -7
- package/packages/ranking/src/manifest.ts +21 -14
- package/packages/ranking/src/render.ts +33 -35
- package/packages/ranking/src/schedule.ts +16 -19
- package/packages/ranking/src/surface.ts +12 -13
- package/packages/ranking-studio/README.md +29 -0
- package/packages/ranking-studio/package.json +8 -3
- package/packages/ranking-studio/src/index.ts +71 -12
- package/packages/render-hyperframes/README.md +7 -7
- package/packages/render-hyperframes/package.json +1 -1
- package/packages/render-hyperframes/src/component.ts +11 -1
- package/packages/render-hyperframes/src/fragment.ts +7 -4
- package/packages/render-hyperframes/src/manifest.ts +4 -4
- package/packages/render-hyperframes/src/surface.ts +6 -6
- package/packages/runtime/README.md +8 -1
- package/packages/runtime/src/catalog.ts +2 -0
- package/packages/runtime/src/execution.ts +15 -4
- package/packages/runtime/src/index.ts +2 -1
- package/packages/runtime/src/log.ts +51 -0
- package/packages/runtime/src/types.ts +5 -8
- package/packages/runtime-host-node/README.md +30 -0
- package/packages/runtime-host-node/package.json +1 -0
- package/packages/runtime-host-node/src/index.ts +25 -9
- package/packages/runtime-host-node/src/packages.ts +47 -50
- package/packages/runtime-kit/README.md +5 -0
- package/packages/runtime-kit/src/index.ts +3 -1
- package/packages/runtime-local/README.md +111 -4
- package/packages/runtime-local/src/config.ts +202 -56
- package/packages/runtime-local/src/control.ts +9 -1
- package/packages/runtime-local/src/executor.ts +66 -0
- package/packages/runtime-local/src/host.ts +37 -17
- package/packages/runtime-local/src/log.ts +48 -0
- package/packages/runtime-local/src/programs.ts +41 -25
- package/packages/runtime-local/src/result-writer.ts +2 -0
- package/packages/runtime-local/src/runtime.ts +10 -6
- package/packages/runtime-local/src/supervisor.ts +142 -0
- package/packages/runtime-local/src/types.ts +9 -2
- package/packages/runtime-local/src/worker-process.ts +7 -24
- package/packages/runtime-local/src/worker.ts +55 -83
- package/packages/screen-overlay/README.md +3 -3
- package/packages/screen-overlay/package.json +1 -1
- package/packages/screen-overlay/src/component.ts +3 -3
- package/packages/screen-overlay/src/fragment.ts +5 -4
- package/packages/screen-overlay/src/manifest.ts +7 -6
- package/packages/screen-overlay/src/program.ts +9 -9
- package/packages/screen-overlay/src/surface.ts +6 -7
- package/packages/script/README.md +37 -2
- package/packages/script/src/edit.ts +123 -73
- package/packages/script/src/lexical.ts +40 -6
- package/packages/script/src/manifest.ts +2 -2
- package/packages/script/src/narrative.ts +1 -0
- package/packages/script/src/parser.ts +36 -8
- package/packages/script/src/surface.ts +4 -3
- package/packages/script/src/types.ts +5 -1
- package/packages/script-studio/package.json +9 -3
- package/packages/script-studio/src/index.ts +2 -0
- package/packages/script-studio/src/projection.ts +105 -0
- package/packages/seedance/README.md +30 -1
- package/packages/seedance/src/index.ts +18 -7
- package/packages/seedance/src/surface.ts +17 -4
- package/packages/seedance-kits/README.md +10 -2
- package/packages/seedance-kits/kits/speaker-v1.svs +5 -5
- package/packages/seedream/README.md +1 -1
- package/packages/sound/README.md +81 -0
- package/packages/sound/package.json +25 -0
- package/packages/sound/src/activation.ts +11 -0
- package/packages/sound/src/component.ts +28 -0
- package/packages/sound/src/index.ts +5 -0
- package/packages/sound/src/manifest.ts +47 -0
- package/packages/sound/src/program.ts +84 -0
- package/packages/sound/src/style.ts +34 -0
- package/packages/sound/src/surface.ts +90 -0
- package/packages/sound-studio/README.md +22 -0
- package/packages/sound-studio/package.json +20 -0
- package/packages/sound-studio/src/activation.ts +6 -0
- package/packages/sound-studio/src/index.ts +74 -0
- package/packages/speech/README.md +2 -2
- package/packages/speech-alignment/src/align.ts +45 -21
- package/packages/speech-alignment/src/local.ts +8 -0
- package/packages/speech-alignment/src/locate.ts +1 -1
- package/packages/store-sqlite/README.md +7 -0
- package/packages/store-sqlite/src/store.ts +84 -83
- package/packages/studio/INSPECTOR.md +117 -0
- package/packages/studio/README.md +149 -14
- package/packages/studio/package.json +8 -7
- package/packages/studio/src/build-library.ts +99 -84
- package/packages/studio/src/companion-assembly.ts +1 -0
- package/packages/studio/src/domain.ts +1 -1
- package/packages/studio/src/fallback-companions.ts +3 -3
- package/packages/studio/src/feedback-server.ts +51 -0
- package/packages/studio/src/feedback-store.ts +66 -0
- package/packages/studio/src/feedback.ts +60 -0
- package/packages/studio/src/library-media.ts +19 -0
- package/packages/studio/src/parameter-values.ts +83 -1
- package/packages/studio/src/parameters.ts +132 -43
- package/packages/studio/src/preview/render.ts +5 -1
- package/packages/studio/src/preview/runtime-shim.ts +49 -3
- package/packages/studio/src/programme.ts +14 -30
- package/packages/studio/src/server.ts +66 -34
- package/packages/studio/src/shared.ts +24 -8
- package/packages/studio/src/snapshot.ts +21 -132
- package/packages/studio/src/studio-preflight.ts +3 -3
- package/packages/studio/src/studio-registry.ts +72 -6
- package/packages/studio/src/style.css +342 -190
- package/packages/studio/src/temporal-edit.ts +131 -0
- package/packages/studio/src/ui/artifact-name.ts +80 -0
- package/packages/studio/src/ui/artifact-preview.ts +99 -0
- package/packages/studio/src/ui/comments.ts +233 -0
- package/packages/studio/src/ui/icons.ts +10 -1
- package/packages/studio/src/ui/library.ts +373 -192
- package/packages/studio/src/ui/main.ts +291 -110
- package/packages/studio/src/ui/material-preview.ts +1 -1
- package/packages/studio/src/ui/overlay.ts +31 -26
- package/packages/studio/src/ui/scrub-preview.ts +108 -0
- package/packages/studio/src/ui/sidebar-panel.ts +31 -0
- package/packages/studio/src/ui/stage.ts +188 -9
- package/packages/studio/src/ui/timeline.ts +187 -281
- package/packages/studio/start.ts +19 -5
- package/packages/studio-adapter/README.md +151 -11
- package/packages/studio-adapter/src/index.ts +126 -14
- package/packages/temporal/README.md +6 -6
- package/packages/temporal/package.json +1 -1
- package/packages/temporal/src/component.ts +5 -6
- package/packages/temporal/src/index.ts +8 -6
- package/packages/temporal/src/location.ts +11 -11
- package/packages/temporal/src/projection.ts +19 -19
- package/packages/temporal/src/rational.ts +4 -4
- package/packages/temporal-markup/EDITING.md +183 -0
- package/packages/temporal-markup/README.md +31 -11
- package/packages/temporal-markup/package.json +1 -1
- package/packages/temporal-markup/src/index.ts +20 -25
- package/packages/temporal-markup/src/space.ts +10 -41
- package/packages/timeline/README.md +31 -0
- package/packages/{semantic-track → timeline}/package.json +1 -1
- package/packages/timeline/src/activation.ts +8 -0
- package/packages/timeline/src/component.ts +24 -0
- package/packages/timeline/src/identity.ts +60 -0
- package/packages/timeline/src/index.ts +6 -0
- package/packages/{semantic-track → timeline}/src/location.ts +20 -20
- package/packages/timeline/src/manifest.ts +39 -0
- package/packages/{semantic-track → timeline}/src/projection.ts +14 -14
- package/packages/timeline/src/types.ts +24 -0
- package/packages/timeline-author/README.md +68 -0
- package/packages/{speech-track → timeline-author}/package.json +6 -4
- package/packages/timeline-author/src/activation.ts +22 -0
- package/packages/{speech-track → timeline-author}/src/component.ts +15 -13
- package/packages/{speech-track → timeline-author}/src/fragment.ts +14 -23
- package/packages/timeline-author/src/index.ts +7 -0
- package/packages/timeline-author/src/manifest.ts +78 -0
- package/packages/timeline-author/src/program.ts +107 -0
- package/packages/timeline-author/src/surface.ts +46 -0
- package/packages/timeline-author/src/types.ts +6 -0
- package/packages/typography-track/README.md +4 -4
- package/packages/typography-track/package.json +1 -1
- package/packages/typography-track/src/component.ts +4 -4
- package/packages/typography-track/src/fragment.ts +4 -3
- package/packages/typography-track/src/manifest.ts +11 -9
- package/packages/typography-track/src/program.ts +15 -15
- package/packages/typography-track/src/surface.ts +17 -18
- package/packages/typography-track-studio/package.json +8 -3
- package/packages/typography-track-studio/src/index.ts +5 -1
- package/packages/video-cli/README.md +16 -4
- package/packages/video-cli/package.json +2 -1
- package/packages/video-cli/src/creation.ts +25 -9
- package/packages/video-cli/src/index.ts +1 -1
- package/packages/video-cli/src/studio-distribution.ts +2 -1
- package/packages/volcengine-matting/README.md +3 -3
- package/packages/whisperx/README.md +8 -1
- package/packages/workspace/src/index.ts +2 -0
- package/packages/workspace-fs-node/README.md +4 -1
- package/packages/workspace-fs-node/src/workspace.ts +3 -1
- package/services/whisperx/README.md +14 -0
- package/services/whisperx/pyproject.toml +2 -0
- package/services/whisperx/uv.lock +20 -20
- package/packages/provider-hyperframes-aws-lambda/README.md +0 -30
- package/packages/provider-hyperframes-aws-lambda/package.json +0 -30
- package/packages/provider-hyperframes-aws-lambda/src/activation.ts +0 -97
- package/packages/provider-hyperframes-aws-lambda/src/client.ts +0 -114
- package/packages/provider-hyperframes-aws-lambda/src/index.ts +0 -21
- package/packages/provider-hyperframes-aws-lambda/src/provider.ts +0 -522
- package/packages/provider-kie/README.md +0 -134
- package/packages/provider-kie/package.json +0 -43
- package/packages/provider-kie/src/activation.ts +0 -71
- package/packages/provider-kie/src/index.ts +0 -10
- package/packages/provider-kie/src/mapping.ts +0 -182
- package/packages/provider-kie/src/provider.ts +0 -657
- package/packages/provider-kie/src/routes.ts +0 -150
- package/packages/provider-xiaomi-mimo/README.md +0 -32
- package/packages/provider-xiaomi-mimo/src/activation.ts +0 -57
- package/packages/provider-xiaomi-mimo/src/index.ts +0 -5
- package/packages/provider-xiaomi-mimo/src/provider.ts +0 -214
- package/packages/runtime/src/environment.ts +0 -6
- package/packages/semantic-track/README.md +0 -21
- package/packages/semantic-track/src/activation.ts +0 -8
- package/packages/semantic-track/src/component.ts +0 -24
- package/packages/semantic-track/src/identity.ts +0 -58
- package/packages/semantic-track/src/index.ts +0 -6
- package/packages/semantic-track/src/manifest.ts +0 -38
- package/packages/semantic-track/src/types.ts +0 -26
- package/packages/speech-track/README.md +0 -51
- package/packages/speech-track/src/activation.ts +0 -19
- package/packages/speech-track/src/index.ts +0 -7
- package/packages/speech-track/src/manifest.ts +0 -73
- package/packages/speech-track/src/program.ts +0 -64
- package/packages/speech-track/src/surface.ts +0 -35
- package/packages/speech-track/src/types.ts +0 -6
- package/packages/speech-track-studio/README.md +0 -3
- package/packages/speech-track-studio/package.json +0 -14
- package/packages/speech-track-studio/src/activation.ts +0 -7
- package/packages/speech-track-studio/src/index.ts +0 -40
- /package/packages/{cli → project-context-node}/src/project-context.ts +0 -0
- /package/packages/{speech-track → timeline-author}/preview/Track.png +0 -0
|
@@ -129,7 +129,7 @@ async function audioWaveform(url: string): Promise<string | undefined> {
|
|
|
129
129
|
}
|
|
130
130
|
}
|
|
131
131
|
|
|
132
|
-
function audioPreview(url: string): Promise<string | undefined> {
|
|
132
|
+
export function audioPreview(url: string): Promise<string | undefined> {
|
|
133
133
|
const held = generatedAudio.get(url);
|
|
134
134
|
if (held !== undefined) return held;
|
|
135
135
|
const pending = audioWaveform(url).catch(() => undefined).then((waveform) => {
|
|
@@ -14,12 +14,13 @@ export type Box = {
|
|
|
14
14
|
readonly widthPx: number; readonly heightPx: number;
|
|
15
15
|
};
|
|
16
16
|
|
|
17
|
-
export type Measure = (clipId: string) => Box | undefined;
|
|
17
|
+
export type Measure = (clipId: string) => (Box & { readonly stackOrder: number }) | undefined;
|
|
18
18
|
|
|
19
19
|
export type Overlay = {
|
|
20
20
|
readonly element: SVGSVGElement;
|
|
21
21
|
/** The topmost clip drawn at a point, in client coordinates. */
|
|
22
22
|
hitTest(clientX: number, clientY: number): Clip | undefined;
|
|
23
|
+
hitsAt(clientX: number, clientY: number): readonly Clip[];
|
|
23
24
|
/** Redraw against the picture, once it has mounted or moved. */
|
|
24
25
|
refresh(): void;
|
|
25
26
|
};
|
|
@@ -62,21 +63,24 @@ export function createOverlay(store: Store, measure: Measure): Overlay {
|
|
|
62
63
|
element.setAttribute("class", "stage-overlay");
|
|
63
64
|
element.setAttribute("preserveAspectRatio", "none");
|
|
64
65
|
|
|
65
|
-
let
|
|
66
|
+
let entities: readonly Clip[] = [];
|
|
66
67
|
let canvas = { width: 1, height: 1 };
|
|
67
|
-
let last: { snapshot: StudioSnapshot; selected: Clip | undefined
|
|
68
|
+
let last: { snapshot: StudioSnapshot; selected: Clip | undefined } | undefined;
|
|
68
69
|
|
|
69
70
|
/**
|
|
70
71
|
* The box is measured off the picture rather than restated from the Source:
|
|
71
72
|
* motion moves an element across its span, so only what was drawn knows where
|
|
72
73
|
* it ended up. A Present that has not mounted has no box to draw.
|
|
73
74
|
*/
|
|
74
|
-
const
|
|
75
|
-
const ids = clip.
|
|
76
|
-
|
|
75
|
+
const drawnParts = (clip: Clip) => {
|
|
76
|
+
const ids = clip.renderIds.length > 0 ? clip.renderIds : clip.presentId === undefined ? [] : [clip.presentId];
|
|
77
|
+
return ids.flatMap((id) => {
|
|
77
78
|
const found = measure(id);
|
|
78
79
|
return found === undefined ? [] : [found];
|
|
79
80
|
});
|
|
81
|
+
};
|
|
82
|
+
const drawnBox = (clip: Clip): Box | undefined => {
|
|
83
|
+
const boxes = drawnParts(clip);
|
|
80
84
|
if (boxes.length === 0) return undefined;
|
|
81
85
|
const left = Math.min(...boxes.map((box) => box.xPx));
|
|
82
86
|
const top = Math.min(...boxes.map((box) => box.yPx));
|
|
@@ -87,23 +91,23 @@ export function createOverlay(store: Store, measure: Measure): Overlay {
|
|
|
87
91
|
|
|
88
92
|
const draw = (): void => {
|
|
89
93
|
if (last === undefined) return;
|
|
90
|
-
const { snapshot, selected
|
|
94
|
+
const { snapshot, selected } = last;
|
|
91
95
|
canvas = { width: snapshot.space.canvasWidth, height: snapshot.space.canvasHeight };
|
|
92
96
|
element.setAttribute("viewBox", `0 0 ${canvas.width} ${canvas.height}`);
|
|
93
97
|
element.replaceChildren();
|
|
94
|
-
//
|
|
95
|
-
|
|
98
|
+
// An editing interval can end before its visual representation disappears.
|
|
99
|
+
// The renderer decides which associated parts are visible at this frame.
|
|
100
|
+
entities = snapshot.tracks.flatMap((track) => track.clips);
|
|
96
101
|
|
|
97
102
|
if (selected === undefined) return;
|
|
98
103
|
const tones = intentTones(snapshot);
|
|
99
104
|
const tone = tones.get(selected.authoredId);
|
|
100
|
-
const onScreen = frame >= selected.startFrame && frame < selected.endFrameExclusive;
|
|
101
105
|
const box = drawnBox(selected);
|
|
102
106
|
// A Present that is not on screen at this frame was never drawn, so there
|
|
103
107
|
// is nothing to put a box around.
|
|
104
108
|
if (box === undefined) return;
|
|
105
109
|
const group = document.createElementNS(SVG_NS, "g");
|
|
106
|
-
group.setAttribute("class", `box${
|
|
110
|
+
group.setAttribute("class", `box${tone === undefined ? "" : ` tone-${tone}`}`);
|
|
107
111
|
|
|
108
112
|
group.append(rect(box, "box-content"));
|
|
109
113
|
|
|
@@ -111,34 +115,35 @@ export function createOverlay(store: Store, measure: Measure): Overlay {
|
|
|
111
115
|
label.setAttribute("x", String(box.xPx + 10));
|
|
112
116
|
label.setAttribute("y", String(Math.max(28, box.yPx - 12)));
|
|
113
117
|
label.setAttribute("class", "box-label");
|
|
114
|
-
label.textContent =
|
|
118
|
+
label.textContent = selected.display.title;
|
|
115
119
|
group.append(label);
|
|
116
120
|
element.append(group);
|
|
117
121
|
};
|
|
118
122
|
|
|
119
|
-
store.subscribe(({ snapshot, selection
|
|
123
|
+
store.subscribe(({ snapshot, selection }) => {
|
|
120
124
|
last = {
|
|
121
125
|
snapshot,
|
|
122
126
|
selected: selection.kind === "clip" ? store.clip(selection.clipId) : undefined,
|
|
123
|
-
frame: playhead.frame,
|
|
124
127
|
};
|
|
125
128
|
draw();
|
|
126
129
|
});
|
|
127
130
|
|
|
128
|
-
|
|
129
|
-
element,
|
|
130
|
-
refresh: draw,
|
|
131
|
-
hitTest(clientX, clientY) {
|
|
131
|
+
const hitsAt = (clientX: number, clientY: number): readonly Clip[] => {
|
|
132
132
|
const box = element.getBoundingClientRect();
|
|
133
|
-
if (box.width === 0 || box.height === 0) return
|
|
133
|
+
if (box.width === 0 || box.height === 0) return [];
|
|
134
134
|
const x = (clientX - box.left) / box.width * canvas.width;
|
|
135
135
|
const y = (clientY - box.top) / box.height * canvas.height;
|
|
136
|
-
//
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
});
|
|
142
|
-
|
|
136
|
+
// Hit individual parts, not the empty space inside a group's union box.
|
|
137
|
+
const hits = entities.flatMap((clip) => drawnParts(clip)
|
|
138
|
+
.filter((part) => inside(part, x, y))
|
|
139
|
+
.map((part) => ({ clip, order: part.stackOrder })))
|
|
140
|
+
.sort((left, right) => right.order - left.order);
|
|
141
|
+
return [...new Map(hits.map(({ clip }) => [clip.id, clip])).values()];
|
|
142
|
+
};
|
|
143
|
+
return {
|
|
144
|
+
element,
|
|
145
|
+
refresh: draw,
|
|
146
|
+
hitsAt,
|
|
147
|
+
hitTest: (x, y) => hitsAt(x, y)[0],
|
|
143
148
|
};
|
|
144
149
|
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import type { StudioSnapshot } from "../shared.js";
|
|
2
|
+
import { feedbackClock } from "../feedback.js";
|
|
3
|
+
|
|
4
|
+
type PreviewWindow = Window & {
|
|
5
|
+
__hypitSeekFrame?: (frame: number) => Promise<boolean>;
|
|
6
|
+
__hypitSetMuted?: (muted: boolean) => Promise<boolean>;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
/** One lazy, muted picture for scrubbing; it never changes the main playhead. */
|
|
10
|
+
export function createScrubPreview(container: HTMLElement) {
|
|
11
|
+
const element = document.createElement("div");
|
|
12
|
+
element.className = "scrub-preview";
|
|
13
|
+
element.hidden = true;
|
|
14
|
+
element.innerHTML = '<div class="scrub-preview-picture"><span>Loading frame…</span></div><div class="scrub-preview-time"></div>';
|
|
15
|
+
element.setAttribute("aria-hidden", "true");
|
|
16
|
+
const picture = element.querySelector<HTMLElement>(".scrub-preview-picture")!;
|
|
17
|
+
const status = picture.querySelector<HTMLElement>("span")!;
|
|
18
|
+
const time = element.querySelector<HTMLElement>(".scrub-preview-time")!;
|
|
19
|
+
container.append(element);
|
|
20
|
+
let iframe: HTMLIFrameElement | undefined;
|
|
21
|
+
let revision: number | undefined;
|
|
22
|
+
let ready = false;
|
|
23
|
+
let seeking = false;
|
|
24
|
+
let requested: number | undefined;
|
|
25
|
+
let displayed: number | undefined;
|
|
26
|
+
|
|
27
|
+
const seek = async (): Promise<void> => {
|
|
28
|
+
const current = iframe;
|
|
29
|
+
if (!ready || seeking || current === undefined || requested === undefined || requested === displayed) return;
|
|
30
|
+
seeking = true;
|
|
31
|
+
try {
|
|
32
|
+
while (iframe === current && requested !== undefined && requested !== displayed) {
|
|
33
|
+
const frame: number = requested;
|
|
34
|
+
const target = current.contentWindow as PreviewWindow | null;
|
|
35
|
+
const placed = await target?.__hypitSeekFrame?.(frame);
|
|
36
|
+
if (iframe !== current) return;
|
|
37
|
+
if (!placed) throw new Error("Frame unavailable");
|
|
38
|
+
displayed = frame;
|
|
39
|
+
if (requested === frame) {
|
|
40
|
+
current.style.visibility = "visible";
|
|
41
|
+
status.hidden = true;
|
|
42
|
+
element.dataset.frame = String(frame);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
} catch {
|
|
46
|
+
if (iframe === current) status.textContent = "Frame unavailable";
|
|
47
|
+
} finally {
|
|
48
|
+
if (iframe === current) seeking = false;
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
const hide = (): void => { element.hidden = true; requested = undefined; };
|
|
52
|
+
const clear = (): void => {
|
|
53
|
+
hide(); iframe?.remove(); iframe = undefined; revision = undefined;
|
|
54
|
+
ready = false; seeking = false; displayed = undefined;
|
|
55
|
+
delete element.dataset.frame;
|
|
56
|
+
};
|
|
57
|
+
return {
|
|
58
|
+
hide, clear,
|
|
59
|
+
show(snapshot: StudioSnapshot, frame: number, clientX: number): void {
|
|
60
|
+
if (snapshot.revision !== revision) clear();
|
|
61
|
+
if (iframe === undefined) {
|
|
62
|
+
revision = snapshot.revision;
|
|
63
|
+
const { canvasWidth, canvasHeight } = snapshot.space;
|
|
64
|
+
const scale = Math.min(200 / canvasWidth, 170 / canvasHeight);
|
|
65
|
+
picture.style.width = `${canvasWidth * scale}px`;
|
|
66
|
+
picture.style.height = `${canvasHeight * scale}px`;
|
|
67
|
+
const created = document.createElement("iframe");
|
|
68
|
+
created.title = "Hovered frame";
|
|
69
|
+
created.tabIndex = -1;
|
|
70
|
+
created.setAttribute("sandbox", "allow-scripts allow-same-origin");
|
|
71
|
+
created.setAttribute("allow", "autoplay 'none'");
|
|
72
|
+
created.style.width = `${canvasWidth}px`;
|
|
73
|
+
created.style.height = `${canvasHeight}px`;
|
|
74
|
+
created.style.transform = `scale(${scale})`;
|
|
75
|
+
created.style.visibility = "hidden";
|
|
76
|
+
created.addEventListener("load", () => {
|
|
77
|
+
void (async () => {
|
|
78
|
+
const target = created.contentWindow as PreviewWindow | null;
|
|
79
|
+
await target?.__hypitSetMuted?.(true);
|
|
80
|
+
if (iframe !== created) return;
|
|
81
|
+
ready = true;
|
|
82
|
+
await seek();
|
|
83
|
+
})().catch(() => { if (iframe === created) status.textContent = "Frame unavailable"; });
|
|
84
|
+
});
|
|
85
|
+
created.srcdoc = snapshot.preview.srcdoc;
|
|
86
|
+
iframe = created;
|
|
87
|
+
picture.prepend(created);
|
|
88
|
+
}
|
|
89
|
+
requested = frame;
|
|
90
|
+
element.hidden = false;
|
|
91
|
+
const room = container.getBoundingClientRect();
|
|
92
|
+
const left = Math.max(0, Math.min(clientX - room.left - element.offsetWidth / 2, room.width - element.offsetWidth));
|
|
93
|
+
element.style.left = `${left}px`;
|
|
94
|
+
time.textContent = feedbackClock(frame * snapshot.space.frameRate.denominator / snapshot.space.frameRate.numerator);
|
|
95
|
+
if (frame !== displayed) {
|
|
96
|
+
iframe.style.visibility = "hidden";
|
|
97
|
+
status.textContent = "Loading frame…";
|
|
98
|
+
status.hidden = false;
|
|
99
|
+
delete element.dataset.frame;
|
|
100
|
+
} else {
|
|
101
|
+
iframe.style.visibility = "visible";
|
|
102
|
+
status.hidden = true;
|
|
103
|
+
element.dataset.frame = String(frame);
|
|
104
|
+
}
|
|
105
|
+
void seek();
|
|
106
|
+
},
|
|
107
|
+
};
|
|
108
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { icon } from "./icons.js";
|
|
2
|
+
|
|
3
|
+
/** Shared chrome; each view owns its navigation choices, toolbar and content. */
|
|
4
|
+
export function createSidebarPanel(mark: string, navigationLabel: string) {
|
|
5
|
+
const element = document.createElement("div");
|
|
6
|
+
element.className = "sidebar-panel";
|
|
7
|
+
element.innerHTML = `
|
|
8
|
+
<div class="sidebar-panel-heading"><span class="sidebar-panel-mark" aria-hidden="true">${icon(mark)}</span></div>
|
|
9
|
+
<div class="sidebar-panel-toolbar"></div>
|
|
10
|
+
<nav class="sidebar-panel-nav"></nav>
|
|
11
|
+
<div class="sidebar-panel-content"></div>`;
|
|
12
|
+
const navigation = element.querySelector<HTMLElement>("nav")!;
|
|
13
|
+
navigation.setAttribute("aria-label", navigationLabel);
|
|
14
|
+
return {
|
|
15
|
+
element, navigation,
|
|
16
|
+
toolbar: element.querySelector<HTMLElement>(".sidebar-panel-toolbar")!,
|
|
17
|
+
content: element.querySelector<HTMLElement>(".sidebar-panel-content")!,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function sidebarItem(input: { label: string; icon: string; selected: boolean; select(): void }) {
|
|
22
|
+
const button = document.createElement("button");
|
|
23
|
+
button.type = "button";
|
|
24
|
+
button.className = `sidebar-panel-item${input.selected ? " active" : ""}`;
|
|
25
|
+
button.setAttribute("aria-label", input.label);
|
|
26
|
+
button.setAttribute("aria-pressed", String(input.selected));
|
|
27
|
+
button.title = input.label;
|
|
28
|
+
button.innerHTML = icon(input.icon);
|
|
29
|
+
button.addEventListener("click", input.select);
|
|
30
|
+
return button;
|
|
31
|
+
}
|
|
@@ -1,12 +1,21 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { createArtifactPreview } from "./artifact-preview.js";
|
|
2
|
+
import type { StudioArtifactView, StudioSnapshot } from "../shared.js";
|
|
2
3
|
import { createOverlay } from "./overlay.js";
|
|
3
4
|
import { icon, setIcon } from "./icons.js";
|
|
5
|
+
import { createScrubPreview } from "./scrub-preview.js";
|
|
4
6
|
import type { State, Store } from "./selection.js";
|
|
5
7
|
|
|
6
8
|
export type Stage = {
|
|
7
9
|
readonly element: HTMLElement;
|
|
8
10
|
/** Start or stop playback, however the request arrived. */
|
|
9
11
|
toggle(): void;
|
|
12
|
+
pause(): void;
|
|
13
|
+
/** Change picture interaction while preserving Studio's selection. */
|
|
14
|
+
setReviewMode(enabled: boolean): void;
|
|
15
|
+
/** Return from a Result artifact to the composition player. */
|
|
16
|
+
showComposition(): void;
|
|
17
|
+
openArtifact(artifact: StudioArtifactView): void;
|
|
18
|
+
renameArtifact(artifact: StudioArtifactView): void;
|
|
10
19
|
};
|
|
11
20
|
|
|
12
21
|
/**
|
|
@@ -17,19 +26,25 @@ export type Stage = {
|
|
|
17
26
|
* drives frames, not seconds, and lands on exactly the frame the renderer would
|
|
18
27
|
* photograph.
|
|
19
28
|
*/
|
|
20
|
-
export function createStage(store: Store): Stage {
|
|
29
|
+
export function createStage(store: Store, selectedArtifact: (id: string | undefined) => void): Stage {
|
|
21
30
|
const element = document.createElement("section");
|
|
22
31
|
element.className = "stage";
|
|
23
32
|
element.innerHTML = `
|
|
24
33
|
<div class="stage-heading">
|
|
25
34
|
<div class="stage-title">${icon("preview")}<strong>Preview</strong></div>
|
|
35
|
+
<button type="button" class="stage-return" hidden>Back to composition</button>
|
|
26
36
|
</div>
|
|
27
37
|
<div class="stage-viewport">
|
|
28
38
|
<div class="stage-scaler">
|
|
29
39
|
<iframe title="Preview" sandbox="allow-scripts allow-same-origin" allow="autoplay"></iframe>
|
|
30
40
|
</div>
|
|
31
41
|
</div>
|
|
42
|
+
<div class="stage-progress" hidden>
|
|
43
|
+
<input class="stage-scrubber" type="range" min="0" max="0" value="0" step="0.01" aria-label="Media time" hidden>
|
|
44
|
+
</div>
|
|
32
45
|
<div class="stage-bar">
|
|
46
|
+
<span class="stage-time" hidden></span>
|
|
47
|
+
<div class="stage-transport">
|
|
33
48
|
<button type="button" data-previous aria-label="Previous frame" title="Previous frame">
|
|
34
49
|
${icon("previous")}
|
|
35
50
|
</button>
|
|
@@ -39,6 +54,7 @@ export function createStage(store: Store): Stage {
|
|
|
39
54
|
<button type="button" data-next aria-label="Next frame" title="Next frame">
|
|
40
55
|
${icon("next")}
|
|
41
56
|
</button>
|
|
57
|
+
</div>
|
|
42
58
|
<button type="button" data-mute aria-label="Mute" class="stage-mute">
|
|
43
59
|
<span data-mute-icon>${icon("volume")}</span>
|
|
44
60
|
</button>
|
|
@@ -47,6 +63,7 @@ export function createStage(store: Store): Stage {
|
|
|
47
63
|
const viewport = element.querySelector<HTMLElement>(".stage-viewport")!;
|
|
48
64
|
const scaler = element.querySelector<HTMLElement>(".stage-scaler")!;
|
|
49
65
|
const iframe = element.querySelector<HTMLIFrameElement>("iframe")!;
|
|
66
|
+
let reviewMode = false;
|
|
50
67
|
/**
|
|
51
68
|
* Measure a clip in the rendered picture.
|
|
52
69
|
*
|
|
@@ -57,17 +74,30 @@ export function createStage(store: Store): Stage {
|
|
|
57
74
|
* of its enter and exit, and selecting a clip lands the playhead on exactly
|
|
58
75
|
* the frame where that displacement is largest.
|
|
59
76
|
*/
|
|
60
|
-
const measure = (clipId: string): { xPx: number; yPx: number; widthPx: number; heightPx: number } | undefined => {
|
|
77
|
+
const measure = (clipId: string): { xPx: number; yPx: number; widthPx: number; heightPx: number; stackOrder: number } | undefined => {
|
|
61
78
|
const document_ = iframe.contentDocument;
|
|
62
79
|
if (document_ === null) return undefined;
|
|
63
80
|
const present = document_.querySelector(`[data-hypit-present-id="${CSS.escape(clipId)}"]`);
|
|
81
|
+
if (present === null) return undefined;
|
|
82
|
+
const current = store.current();
|
|
83
|
+
if (current === undefined) return undefined;
|
|
84
|
+
const frameRate = fps(current.snapshot);
|
|
85
|
+
const start = Number(present.getAttribute("data-start"));
|
|
86
|
+
const end = start + Number(present.getAttribute("data-duration"));
|
|
87
|
+
if (current.playhead.frame < Math.round(start * frameRate)
|
|
88
|
+
|| current.playhead.frame >= Math.round(end * frameRate)) return undefined;
|
|
64
89
|
// The present spans the whole canvas; the drawn box is its frame element.
|
|
65
90
|
const drawn = present?.querySelector(`[data-hypit-element-id="${CSS.escape(`${clipId}:frame`)}"]`)
|
|
66
91
|
?? present?.querySelector("[data-hypit-element-id]");
|
|
67
92
|
if (drawn === null || drawn === undefined) return undefined;
|
|
93
|
+
for (let ancestor: Element | null = drawn; ancestor !== null; ancestor = ancestor.parentElement) {
|
|
94
|
+
const style = document_.defaultView!.getComputedStyle(ancestor);
|
|
95
|
+
if (style.display === "none" || style.visibility === "hidden" || Number(style.opacity) === 0) return undefined;
|
|
96
|
+
}
|
|
68
97
|
const box = drawn.getBoundingClientRect();
|
|
69
98
|
if (box.width === 0 && box.height === 0) return undefined;
|
|
70
|
-
return { xPx: box.left, yPx: box.top, widthPx: box.width, heightPx: box.height
|
|
99
|
+
return { xPx: box.left, yPx: box.top, widthPx: box.width, heightPx: box.height,
|
|
100
|
+
stackOrder: Number(document_.defaultView!.getComputedStyle(present).zIndex) || 0 };
|
|
71
101
|
};
|
|
72
102
|
|
|
73
103
|
// The overlay is a sibling of the iframe inside the scaler, so it inherits the
|
|
@@ -78,13 +108,45 @@ export function createStage(store: Store): Stage {
|
|
|
78
108
|
// Clicking the picture selects whatever is drawn under the pointer, which is
|
|
79
109
|
// the third way into the same selection.
|
|
80
110
|
scaler.addEventListener("click", (event) => {
|
|
111
|
+
if (reviewMode) { toggle(); return; }
|
|
81
112
|
const clip = overlay.hitTest(event.clientX, event.clientY);
|
|
82
113
|
if (clip !== undefined) store.select(clip.id, "video");
|
|
83
114
|
else store.clearSelection();
|
|
84
115
|
});
|
|
116
|
+
// A broad component frame can cover smaller elements. Offer all actual
|
|
117
|
+
// Companion hits without special knowledge of captions or any other family.
|
|
118
|
+
let selectionMenu: HTMLElement | undefined;
|
|
119
|
+
const closeSelectionMenu = (): void => { selectionMenu?.remove(); selectionMenu = undefined; };
|
|
120
|
+
scaler.addEventListener("contextmenu", (event) => {
|
|
121
|
+
if (reviewMode) { event.preventDefault(); return; }
|
|
122
|
+
const hits = overlay.hitsAt(event.clientX, event.clientY);
|
|
123
|
+
if (hits.length === 0) return;
|
|
124
|
+
event.preventDefault(); stop(); closeSelectionMenu();
|
|
125
|
+
const menu = document.createElement("div");
|
|
126
|
+
menu.className = "selection-menu";
|
|
127
|
+
menu.setAttribute("role", "menu"); menu.setAttribute("aria-label", "Elements at this point");
|
|
128
|
+
for (const hit of hits) {
|
|
129
|
+
const option = document.createElement("button"); option.type = "button";
|
|
130
|
+
option.setAttribute("role", "menuitem"); option.textContent = hit.display.title;
|
|
131
|
+
option.title = hit.id;
|
|
132
|
+
option.addEventListener("click", () => { store.select(hit.id, "video"); closeSelectionMenu(); });
|
|
133
|
+
menu.append(option);
|
|
134
|
+
}
|
|
135
|
+
element.append(menu);
|
|
136
|
+
menu.style.left = `${Math.max(0, Math.min(event.clientX, window.innerWidth - menu.offsetWidth - 8))}px`;
|
|
137
|
+
menu.style.top = `${Math.max(0, Math.min(event.clientY, window.innerHeight - menu.offsetHeight - 8))}px`;
|
|
138
|
+
selectionMenu = menu; menu.querySelector("button")?.focus();
|
|
139
|
+
});
|
|
140
|
+
document.addEventListener("pointerdown", (event) => {
|
|
141
|
+
if (event.target instanceof Node && !selectionMenu?.contains(event.target)) closeSelectionMenu();
|
|
142
|
+
});
|
|
143
|
+
document.addEventListener("keydown", (event) => { if (event.key === "Escape") closeSelectionMenu(); });
|
|
85
144
|
// The room around the picture is empty in the plainest sense.
|
|
86
145
|
viewport.addEventListener("click", (event) => {
|
|
87
|
-
if (event.target === viewport)
|
|
146
|
+
if (event.target === viewport) {
|
|
147
|
+
if (reviewMode) toggle();
|
|
148
|
+
else store.clearSelection();
|
|
149
|
+
}
|
|
88
150
|
});
|
|
89
151
|
const play = element.querySelector<HTMLButtonElement>("[data-play]")!;
|
|
90
152
|
const previous = element.querySelector<HTMLButtonElement>("[data-previous]")!;
|
|
@@ -152,6 +214,7 @@ export function createStage(store: Store): Stage {
|
|
|
152
214
|
};
|
|
153
215
|
|
|
154
216
|
const toggle = (): void => {
|
|
217
|
+
if (artifactPreview.selected !== undefined) { artifactPreview.toggle(); return; }
|
|
155
218
|
if (state === undefined) return;
|
|
156
219
|
if (playing) { stop(); return; }
|
|
157
220
|
playing = true;
|
|
@@ -172,21 +235,119 @@ export function createStage(store: Store): Stage {
|
|
|
172
235
|
};
|
|
173
236
|
play.addEventListener("click", toggle);
|
|
174
237
|
previous.addEventListener("click", () => {
|
|
175
|
-
if (
|
|
238
|
+
if (artifactPreview.selected !== undefined) artifactPreview.seek((artifactPreview.media?.currentTime ?? 0) - 5);
|
|
239
|
+
else if (state !== undefined) store.seek(state.playhead.frame - 1, "video");
|
|
176
240
|
});
|
|
177
241
|
next.addEventListener("click", () => {
|
|
178
|
-
if (
|
|
242
|
+
if (artifactPreview.selected !== undefined) artifactPreview.seek((artifactPreview.media?.currentTime ?? 0) + 5);
|
|
243
|
+
else if (state !== undefined) store.seek(state.playhead.frame + 1, "video");
|
|
179
244
|
});
|
|
180
245
|
|
|
181
246
|
const applyMuted = (): void => {
|
|
182
247
|
setIcon(muteIcon, muted ? "muted" : "volume");
|
|
183
248
|
mute.setAttribute("aria-label", muted ? "Unmute" : "Mute");
|
|
249
|
+
if (artifactPreview.media !== undefined) artifactPreview.media.muted = muted;
|
|
184
250
|
(iframe.contentWindow as SeekWindow | null)?.__hypitSetMuted?.(muted);
|
|
185
251
|
};
|
|
186
252
|
mute.addEventListener("click", () => { muted = !muted; applyMuted(); });
|
|
187
253
|
|
|
254
|
+
const title = element.querySelector<HTMLElement>(".stage-title strong")!;
|
|
255
|
+
const back = element.querySelector<HTMLButtonElement>(".stage-return")!;
|
|
256
|
+
const scrubber = element.querySelector<HTMLInputElement>(".stage-scrubber")!;
|
|
257
|
+
const progress = element.querySelector<HTMLElement>(".stage-progress")!;
|
|
258
|
+
const scrubPreview = createScrubPreview(progress);
|
|
259
|
+
scrubber.addEventListener("pointermove", (event) => {
|
|
260
|
+
if (!reviewMode || state === undefined || scrubber.disabled || artifactPreview.selected !== undefined) return;
|
|
261
|
+
const box = scrubber.getBoundingClientRect();
|
|
262
|
+
// Native range thumbs travel between their centers, not the input edges.
|
|
263
|
+
const fraction = Math.max(0, Math.min(1, (event.clientX - box.left - 6) / Math.max(1, box.width - 12)));
|
|
264
|
+
const frame = Math.round(fraction * Math.max(0, state.snapshot.space.frameCount - 1));
|
|
265
|
+
scrubPreview.show(state.snapshot, frame, event.clientX);
|
|
266
|
+
});
|
|
267
|
+
scrubber.addEventListener("pointerleave", scrubPreview.hide);
|
|
268
|
+
scrubber.addEventListener("blur", scrubPreview.hide);
|
|
269
|
+
const time = element.querySelector<HTMLElement>(".stage-time")!;
|
|
270
|
+
const transport = element.querySelector<HTMLElement>(".stage-transport")!;
|
|
271
|
+
const clock = (seconds: number): string => {
|
|
272
|
+
const ticks = Math.max(0, Math.round(seconds * 100));
|
|
273
|
+
const whole = Math.floor(ticks / 100);
|
|
274
|
+
return `${Math.floor(whole / 60)}:${String(whole % 60).padStart(2, "0")}.${String(ticks % 100).padStart(2, "0")}`;
|
|
275
|
+
};
|
|
276
|
+
const artifactPreview = createArtifactPreview(() => {
|
|
277
|
+
if (artifactPreview.selected === undefined) return;
|
|
278
|
+
const media = artifactPreview.media;
|
|
279
|
+
const timed = media !== undefined;
|
|
280
|
+
const duration = media !== undefined && Number.isFinite(media.duration) ? media.duration : 0;
|
|
281
|
+
transport.hidden = !timed;
|
|
282
|
+
mute.hidden = !timed;
|
|
283
|
+
progress.hidden = scrubber.hidden = !timed;
|
|
284
|
+
time.hidden = !timed;
|
|
285
|
+
play.disabled = duration <= 0 || media?.error != null;
|
|
286
|
+
previous.disabled = next.disabled = play.disabled;
|
|
287
|
+
scrubber.disabled = duration <= 0;
|
|
288
|
+
scrubber.step = "0.01";
|
|
289
|
+
scrubber.setAttribute("aria-label", "Media time");
|
|
290
|
+
scrubber.max = String(duration);
|
|
291
|
+
scrubber.value = String(media?.currentTime ?? 0);
|
|
292
|
+
time.textContent = `${clock(media?.currentTime ?? 0)} / ${clock(duration)}`;
|
|
293
|
+
setIcon(playIcon, media !== undefined && !media.paused ? "pause" : "play");
|
|
294
|
+
play.setAttribute("aria-label", media !== undefined && !media.paused ? "Pause" : "Play");
|
|
295
|
+
});
|
|
296
|
+
viewport.append(artifactPreview.element);
|
|
297
|
+
const compositionTime = (): void => {
|
|
298
|
+
if (state === undefined || artifactPreview.selected !== undefined) return;
|
|
299
|
+
const rate = fps(state.snapshot);
|
|
300
|
+
progress.hidden = scrubber.hidden = time.hidden = false;
|
|
301
|
+
scrubber.disabled = !ready;
|
|
302
|
+
scrubber.step = String(1 / rate);
|
|
303
|
+
scrubber.max = String(Math.max(0, state.snapshot.space.frameCount - 1) / rate);
|
|
304
|
+
scrubber.value = String(state.playhead.frame / rate);
|
|
305
|
+
scrubber.setAttribute("aria-label", "Composition time");
|
|
306
|
+
time.textContent = `${clock(state.playhead.frame / rate)} / ${clock(state.snapshot.space.frameCount / rate)}`;
|
|
307
|
+
};
|
|
308
|
+
scrubber.addEventListener("input", () => {
|
|
309
|
+
if (artifactPreview.selected !== undefined) artifactPreview.seek(Number(scrubber.value));
|
|
310
|
+
else if (state !== undefined) store.seek(Math.round(Number(scrubber.value) * fps(state.snapshot)), "video");
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
const returnToComposition = (): void => {
|
|
314
|
+
artifactPreview.close();
|
|
315
|
+
selectedArtifact(undefined);
|
|
316
|
+
scaler.hidden = false;
|
|
317
|
+
back.hidden = true;
|
|
318
|
+
compositionTime();
|
|
319
|
+
transport.hidden = mute.hidden = false;
|
|
320
|
+
play.disabled = previous.disabled = next.disabled = false;
|
|
321
|
+
previous.title = "Previous frame";
|
|
322
|
+
previous.setAttribute("aria-label", previous.title);
|
|
323
|
+
next.title = "Next frame";
|
|
324
|
+
next.setAttribute("aria-label", next.title);
|
|
325
|
+
title.textContent = "Preview";
|
|
326
|
+
title.removeAttribute("title");
|
|
327
|
+
setIcon(playIcon, "play");
|
|
328
|
+
play.setAttribute("aria-label", "Play");
|
|
329
|
+
fit();
|
|
330
|
+
if (state !== undefined && ready) seekPicture(state.playhead.frame);
|
|
331
|
+
};
|
|
332
|
+
back.addEventListener("click", returnToComposition);
|
|
333
|
+
|
|
334
|
+
const openArtifact = (artifact: StudioArtifactView): void => {
|
|
335
|
+
stop();
|
|
336
|
+
scaler.hidden = true;
|
|
337
|
+
back.hidden = false;
|
|
338
|
+
title.textContent = artifact.displayName ?? artifact.output;
|
|
339
|
+
title.title = artifact.output;
|
|
340
|
+
previous.title = "Back 5 seconds";
|
|
341
|
+
next.title = "Forward 5 seconds";
|
|
342
|
+
previous.setAttribute("aria-label", previous.title);
|
|
343
|
+
next.setAttribute("aria-label", next.title);
|
|
344
|
+
artifactPreview.open(artifact, muted);
|
|
345
|
+
selectedArtifact(artifact.id);
|
|
346
|
+
};
|
|
347
|
+
|
|
188
348
|
iframe.addEventListener("load", () => {
|
|
189
349
|
ready = true;
|
|
350
|
+
compositionTime();
|
|
190
351
|
if (state !== undefined) seekPicture(state.playhead.frame);
|
|
191
352
|
applyMuted();
|
|
192
353
|
// The box could not be measured until now.
|
|
@@ -197,16 +358,20 @@ export function createStage(store: Store): Stage {
|
|
|
197
358
|
|
|
198
359
|
store.subscribe((value) => {
|
|
199
360
|
const first = state === undefined;
|
|
361
|
+
const moved = state !== undefined && (state.playhead.frame !== value.playhead.frame || state.selection !== value.selection);
|
|
200
362
|
state = value;
|
|
363
|
+
if (moved && value.playhead.origin !== "play" && artifactPreview.selected !== undefined) returnToComposition();
|
|
201
364
|
if (value.snapshot.revision !== mounted) {
|
|
365
|
+
scrubPreview.clear();
|
|
202
366
|
mounted = value.snapshot.revision;
|
|
203
|
-
stop();
|
|
367
|
+
if (artifactPreview.selected === undefined) stop();
|
|
204
368
|
ready = false;
|
|
205
369
|
const preview = value.snapshot.preview;
|
|
206
370
|
iframe.srcdoc = preview.srcdoc;
|
|
207
371
|
fit();
|
|
208
372
|
}
|
|
209
373
|
if (first) fit();
|
|
374
|
+
compositionTime();
|
|
210
375
|
|
|
211
376
|
// Playing and scrubbing are different requests: one lets material run on
|
|
212
377
|
// its own clock, the other moves it. Asking a decoder for a fresh seek
|
|
@@ -227,5 +392,19 @@ export function createStage(store: Store): Stage {
|
|
|
227
392
|
if (playing) overlay.refresh();
|
|
228
393
|
});
|
|
229
394
|
|
|
230
|
-
return { element, toggle
|
|
395
|
+
return { element, toggle, openArtifact,
|
|
396
|
+
setReviewMode(enabled) {
|
|
397
|
+
reviewMode = enabled;
|
|
398
|
+
element.classList.toggle("stage-review", enabled);
|
|
399
|
+
overlay.element.style.display = enabled ? "none" : "";
|
|
400
|
+
closeSelectionMenu();
|
|
401
|
+
if (!enabled) scrubPreview.clear();
|
|
402
|
+
},
|
|
403
|
+
pause() { stop(); artifactPreview.media?.pause(); },
|
|
404
|
+
showComposition() { if (artifactPreview.selected !== undefined) returnToComposition(); },
|
|
405
|
+
renameArtifact(artifact) {
|
|
406
|
+
const selected = artifactPreview.selected;
|
|
407
|
+
if (selected?.build === artifact.build && selected.output === artifact.output) title.textContent = artifact.displayName ?? artifact.output;
|
|
408
|
+
},
|
|
409
|
+
};
|
|
231
410
|
}
|