@hypit/hypit 0.1.4 → 0.1.6
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 +4 -2
- 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 +77 -15
- 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 +8 -1
- package/examples/semantic-composition/chat.svml +6 -5
- package/examples/semantic-composition/hypit.runtime.json +1 -1
- 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 +28 -17
- 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 +11 -0
- package/packages/build-result/src/decode.ts +2 -0
- package/packages/build-result/src/execution-log.ts +17 -0
- package/packages/build-result/src/index.ts +1 -0
- package/packages/build-result/src/store.ts +14 -1
- package/packages/build-result/src/types.ts +3 -0
- package/packages/build-result-s3/src/repository.ts +4 -0
- 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 +21 -9
- 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 +26 -17
- package/packages/caption-fine/src/recipe.ts +7 -0
- package/packages/caption-fine/src/render.ts +14 -13
- 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 +3 -1
- package/packages/caption-fine-studio/src/activation.ts +3 -3
- package/packages/caption-fine-studio/src/index.ts +54 -42
- package/packages/cli/README.md +57 -4
- package/packages/cli/package.json +1 -0
- package/packages/cli/src/arguments.ts +25 -6
- package/packages/cli/src/build-planning.ts +3 -2
- package/packages/cli/src/command.ts +6 -0
- package/packages/cli/src/commands/environment.ts +28 -18
- 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 +3 -2
- package/packages/cli/src/main.ts +34 -42
- package/packages/cli/src/observation.ts +7 -1
- package/packages/cli/src/output.ts +65 -23
- package/packages/cli/src/view.ts +66 -19
- 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/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/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 +10 -7
- 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/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 +16 -11
- 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/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 +22 -26
- package/packages/ranking/src/schedule.ts +16 -19
- package/packages/ranking/src/surface.ts +12 -13
- package/packages/ranking-studio/README.md +18 -0
- package/packages/ranking-studio/src/index.ts +61 -9
- 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/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 +24 -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 +109 -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 +2 -1
- package/packages/runtime-local/src/result-writer.ts +2 -0
- package/packages/runtime-local/src/runtime.ts +8 -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 +30 -5
- package/packages/script/src/manifest.ts +4 -3
- package/packages/script/src/narrative.ts +1 -0
- package/packages/script/src/parser.ts +45 -6
- package/packages/script/src/surface.ts +4 -3
- package/packages/script/src/types.ts +1 -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 +7 -1
- 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/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 +15 -2
- package/packages/studio/LOCALIZATION.md +98 -0
- package/packages/studio/README.md +101 -14
- package/packages/studio/locales/en.json +197 -0
- package/packages/studio/locales/zh-CN.json +191 -0
- package/packages/studio/package.json +8 -7
- 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/localization-node.ts +46 -0
- package/packages/studio/src/localization.ts +85 -0
- package/packages/studio/src/parameter-values.ts +43 -1
- package/packages/studio/src/parameters.ts +114 -24
- 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 +10 -6
- package/packages/studio/src/shared.ts +4 -2
- package/packages/studio/src/snapshot.ts +21 -132
- package/packages/studio/src/studio-preflight.ts +3 -3
- package/packages/studio/src/studio-registry.ts +50 -6
- package/packages/studio/src/style.css +223 -50
- package/packages/studio/src/ui/artifact-name.ts +8 -6
- package/packages/studio/src/ui/artifact-preview.ts +5 -4
- package/packages/studio/src/ui/code.ts +17 -16
- package/packages/studio/src/ui/comments.ts +234 -0
- package/packages/studio/src/ui/dropdown.ts +68 -0
- package/packages/studio/src/ui/i18n.ts +109 -0
- package/packages/studio/src/ui/icons.ts +6 -0
- package/packages/studio/src/ui/library.ts +76 -65
- package/packages/studio/src/ui/main.ts +223 -211
- package/packages/studio/src/ui/overlay.ts +12 -8
- package/packages/studio/src/ui/scrub-preview.ts +110 -0
- package/packages/studio/src/ui/stage.ts +93 -29
- package/packages/studio/src/ui/timeline.ts +190 -118
- package/packages/studio/start.ts +41 -22
- package/packages/studio-adapter/README.md +130 -11
- package/packages/studio-adapter/src/index.ts +100 -13
- 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 +2 -2
- package/packages/temporal-markup/README.md +27 -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/video-cli/README.md +4 -1
- package/packages/video-cli/package.json +2 -1
- package/packages/video-cli/src/creation.ts +14 -4
- 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 +1 -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
|
@@ -9,24 +9,32 @@ content identity or hidden output metadata.
|
|
|
9
9
|
|
|
10
10
|
Normalized transparent videos displayed by Media or project components use the ordinary video path.
|
|
11
11
|
The engine decodes them to PNG frames with alpha, then Chrome blends them with lower layers and
|
|
12
|
-
the authored Canvas background.
|
|
13
|
-
the
|
|
12
|
+
the authored Canvas background. Final frames use fast PNG encoding after Chrome has composited
|
|
13
|
+
the image onto an opaque canvas (black beneath the authored background). This trades intermediate
|
|
14
|
+
compression effort for speed without JPEG frame compression. Source alpha, CSS filters, canvas and
|
|
15
|
+
WebGL remain part of the browser composition. The returned MP4 contains the completed composition.
|
|
14
16
|
|
|
15
17
|
Runtime configuration separates work size from shared capacity:
|
|
16
18
|
|
|
17
19
|
- `defaultConcurrency` limits whole render requests admitted by the Endpoint's Runtime capacity resource.
|
|
18
20
|
- Optional `browserCapacity` limits Chrome slots shared by all render Needs in the same `pool`.
|
|
19
|
-
Each Need reserves its
|
|
20
|
-
than this budget reports a configuration error
|
|
21
|
+
Each Need reserves its fixed count or automatic ceiling atomically with the whole-request slot.
|
|
22
|
+
An explicit count larger than this budget reports a configuration error. Auto fits its ceiling
|
|
23
|
+
to the shared budget before admission.
|
|
21
24
|
Both reservations last for the whole Need, including preparation and final encoding. Closing one
|
|
22
25
|
Chrome early does not release part of that reservation. Without `browserCapacity`, admission uses
|
|
23
26
|
the whole-request limit alone.
|
|
24
27
|
- `workers` controls independent Chrome processes inside one admitted render. Explicit counts are
|
|
25
|
-
honored, capped only by selected frame count. `auto`
|
|
26
|
-
|
|
28
|
+
honored, capped only by selected frame count. `auto` starts below its ceiling, then compares useful
|
|
29
|
+
capture batches before adding another browser. Insufficient benefit or falling throughput retires
|
|
30
|
+
surplus browsers between batches. Completed frames are retained; there is no calibration render.
|
|
31
|
+
- Optional `maxWorkers` sets the automatic ceiling. Without it, the Provider leaves two CPU slots
|
|
32
|
+
and half the machine/container memory for other work, budgeting about 1.5 GiB per Chrome process.
|
|
33
|
+
Auto also caps the reservation to the number of roughly one-second batches in the selected range.
|
|
27
34
|
|
|
28
35
|
The Runtime Profile configures these controls through the Provider because they are deployment policy.
|
|
29
|
-
|
|
36
|
+
The automatic ceiling is fixed at activation, and range sizing is identical in admission and execution.
|
|
37
|
+
Actual concurrency adapts inside that reservation; it is not a machine-wide history or performance database. It never
|
|
30
38
|
renders program audio; `@hypit/provider-media-local` separately prepares `TimelineAudio` and muxes
|
|
31
39
|
the final media.
|
|
32
40
|
|
|
@@ -48,11 +56,16 @@ For a Runtime Profile, place `pool` on the Endpoint entry and these Provider set
|
|
|
48
56
|
This configuration admits one 4-worker request at a time under its 6-browser budget even though
|
|
49
57
|
the whole-request limit is 2. Two 4-worker requests would need 8 browser slots. Choose budgets from
|
|
50
58
|
the actual machine and shared workloads; the example is not an automatic tuning recommendation.
|
|
51
|
-
|
|
59
|
+
New Builds use the edited Provider configuration; active Builds retain their selected configuration.
|
|
60
|
+
Restart Studio if its existing session needs to load the edited Profile.
|
|
52
61
|
|
|
53
62
|
`browserGpu` picks Chrome's rasterizer and defaults to `hardware`. Set `software` without a usable
|
|
54
63
|
GPU, or `auto` to let the engine decide. Capture uses screenshots and independent browser processes;
|
|
55
|
-
the CLI's automatic worker and drawElement policies do not override the count.
|
|
64
|
+
the CLI's automatic worker and drawElement policies do not override the count. The opaque screenshot
|
|
65
|
+
adapter uses the engine's public session, video injector and page seek protocol plus Chrome CDP.
|
|
66
|
+
It waits for seek completion, dynamic images/fonts and the page compositor before capturing PNGs.
|
|
67
|
+
The pinned engine couples its PNG session setup to transparent export, so this adapter initializes
|
|
68
|
+
an opaque session and chooses PNG separately at capture. It does not patch engine methods or files.
|
|
56
69
|
|
|
57
70
|
The Runtime Adapter also declares one managed browser program. `programs up` invokes the pinned
|
|
58
71
|
HyperFrames CLI's `browser ensure`; its probe resolves and starts that browser and checks
|
|
@@ -71,8 +84,12 @@ const visual = await renderHyperframesVisual(
|
|
|
71
84
|
|
|
72
85
|
Omit `range` for the complete document. Ranges are zero-based and half-open on the original
|
|
73
86
|
programme clock. At 30 fps, `[240, 360)` returns 120 frames covering seconds 8–12.
|
|
74
|
-
`onProgress` reports
|
|
75
|
-
|
|
87
|
+
`onProgress` reports resource staging, source decoding, the requested range, per-worker frame counts, browser PIDs,
|
|
88
|
+
encoding, storage and elapsed time to direct executor callers. The Provider reduces parallel worker
|
|
89
|
+
events to a single phase and aggregate count through `context.reportProgress`. CLI status and follow
|
|
90
|
+
display that activity without `--verbose`. Counter writes are coalesced to about once per second;
|
|
91
|
+
phase changes and completed counts are reported promptly. Local activity belongs to the running
|
|
92
|
+
Command, not a remote Operation or a repeatedly rewritten Result manifest.
|
|
76
93
|
`processTimeoutMs` defaults to 30 minutes and starts one deadline before resource preparation. It
|
|
77
94
|
covers resource reads, Surface validation, rendering and output storage. `signal` can end the same
|
|
78
95
|
execution earlier. ResourceStore I/O and Surface probes receive the cancellation signal; a custom
|
|
@@ -95,10 +112,13 @@ cleanup. A completed worker closes its Chrome immediately.
|
|
|
95
112
|
One call stages the HTML and every declared asset once. Typed Surface validation includes a complete
|
|
96
113
|
decoded-frame count, even for a short render interval. The renderer then finds source-frame windows
|
|
97
114
|
needed by that interval, merges overlapping windows, and extracts them one source/window at a time.
|
|
98
|
-
Decoded PNGs are shared by all workers in this call. Each worker initializes its own page
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
115
|
+
Decoded PNGs are shared by all workers in this call. Each worker initializes its own page, then takes
|
|
116
|
+
short contiguous frame batches from the render's in-memory queue. A free worker can continue with
|
|
117
|
+
another batch instead of waiting for a worker assigned a more expensive passage. Batches span at
|
|
118
|
+
most about one second and preserve the original absolute frame times. Output numbering starts at
|
|
119
|
+
zero; final H.264 encoding runs once after all workers finish. This division is internal to one
|
|
120
|
+
render call; it does not create or resume Builds. Extra workers help only while aggregate throughput
|
|
121
|
+
improves. Staging, validation, source extraction and final encoding still contribute their own cost.
|
|
102
122
|
|
|
103
123
|
Each call has its own temporary directory, local server port and Chrome processes. Separate renders
|
|
104
124
|
do not share staged files or decoded PNGs. Exact compiler sampling markers retain loops, holds and
|
|
@@ -127,3 +147,11 @@ Direct `renderHyperframesVisual()` calls do not enter Runtime's shared admission
|
|
|
127
147
|
|
|
128
148
|
The current package executes trusted official code in a local process. It is not a sandbox for
|
|
129
149
|
untrusted documents or community renderer implementations.
|
|
150
|
+
|
|
151
|
+
Provider calls forward renderer diagnostics through `context.reportDiagnostic`. The initial record
|
|
152
|
+
states the frame count, worker policy/ceiling, capture path, quality, GPU mode and selected encoder.
|
|
153
|
+
Phase timings, concurrency changes and per-worker seek/preparation/PNG totals are recorded once
|
|
154
|
+
per phase, decision or finished worker. Disposable capture-process
|
|
155
|
+
stdout/stderr are streamed as diagnostics and drained before the call returns; existing output limits
|
|
156
|
+
still apply. Phase changes cover preparation, decoding, browser startup, capture, encoding and storage.
|
|
157
|
+
`hypit logs <build-id>` retains those records after temporary rendering files have been removed.
|
|
@@ -21,7 +21,7 @@ const localHyperframesRuntimeAdapter = createRuntimeEndpointAdapterFacet({
|
|
|
21
21
|
if (context.pool === undefined) throw new Error("local HyperFrames Provider Pool is required");
|
|
22
22
|
const config = runtimeConfigObject(context.config, "local HyperFrames");
|
|
23
23
|
runtimeConfigExact(config, [
|
|
24
|
-
"nodePath", "hyperframesCliPath", "ffprobePath", "ffmpegPath", "workers", "quality", "browserGpu",
|
|
24
|
+
"nodePath", "hyperframesCliPath", "ffprobePath", "ffmpegPath", "workers", "maxWorkers", "quality", "browserGpu",
|
|
25
25
|
"defaultConcurrency", "browserCapacity", "initializationTimeoutMs", "frameTimeoutMs", "processTimeoutMs", "maxProcessOutputBytes", "maxRenderedBytes",
|
|
26
26
|
], "local HyperFrames");
|
|
27
27
|
runtimeConfigString(config.nodePath, "HyperFrames nodePath");
|
|
@@ -43,11 +43,12 @@ const localHyperframesRuntimeAdapter = createRuntimeEndpointAdapterFacet({
|
|
|
43
43
|
const configuredCli = runtimeConfigString(config.hyperframesCliPath, "HyperFrames hyperframesCliPath");
|
|
44
44
|
const configuredFfprobe = runtimeConfigString(config.ffprobePath, "HyperFrames ffprobePath");
|
|
45
45
|
const nodePath = resolveRuntimeExecutable(context.dataRoot, configuredNode ?? process.execPath);
|
|
46
|
-
const hyperframesCliPath = resolveRuntimeExecutable(context.dataRoot, configuredCli ?? defaultHyperframesCliPath());
|
|
46
|
+
const hyperframesCliPath = () => resolveRuntimeExecutable(context.dataRoot, configuredCli ?? defaultHyperframesCliPath());
|
|
47
47
|
const configuredFfmpeg = runtimeConfigString(config.ffmpegPath, "HyperFrames ffmpegPath");
|
|
48
48
|
const ffmpegPath = resolveRuntimeExecutable(context.dataRoot, configuredFfmpeg ?? "ffmpeg");
|
|
49
49
|
const ffprobePath = resolveRuntimeExecutable(context.dataRoot, configuredFfprobe ?? "ffprobe");
|
|
50
50
|
const defaultConcurrency = runtimeConfigPositiveInteger(config.defaultConcurrency, "HyperFrames defaultConcurrency");
|
|
51
|
+
const maxWorkers = runtimeConfigPositiveInteger(config.maxWorkers, "HyperFrames maxWorkers");
|
|
51
52
|
const browserCapacity = runtimeConfigPositiveInteger(config.browserCapacity, "HyperFrames browserCapacity");
|
|
52
53
|
const initializationTimeoutMs = runtimeConfigPositiveInteger(config.initializationTimeoutMs, "HyperFrames initializationTimeoutMs");
|
|
53
54
|
const frameTimeoutMs = runtimeConfigPositiveInteger(config.frameTimeoutMs, "HyperFrames frameTimeoutMs");
|
|
@@ -59,10 +60,10 @@ const localHyperframesRuntimeAdapter = createRuntimeEndpointAdapterFacet({
|
|
|
59
60
|
instance: context.instance,
|
|
60
61
|
pool: context.pool,
|
|
61
62
|
nodePath,
|
|
62
|
-
hyperframesCliPath,
|
|
63
63
|
ffprobePath,
|
|
64
64
|
ffmpegPath,
|
|
65
65
|
...(workers === undefined ? {} : { workers: workers as HyperframesWorkers }),
|
|
66
|
+
...(maxWorkers === undefined ? {} : { maxWorkers }),
|
|
66
67
|
...(quality === undefined ? {} : { quality: quality as HyperframesQuality }),
|
|
67
68
|
...(browserGpu === undefined ? {} : { browserGpu: browserGpu as HyperframesBrowserGpu }),
|
|
68
69
|
...(defaultConcurrency === undefined ? {} : { defaultConcurrency }),
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ExecutionDiagnostic } from "@hypit/runtime";
|
|
1
2
|
import { execFile, spawn } from "node:child_process";
|
|
2
3
|
import { promisify } from "node:util";
|
|
3
4
|
import { fileURLToPath } from "node:url";
|
|
@@ -11,7 +12,17 @@ const cleanupMs = 5_000;
|
|
|
11
12
|
/** Chrome starts its own process group, so stopping only the Node child is insufficient. */
|
|
12
13
|
async function killRenderTree(pid: number): Promise<void> {
|
|
13
14
|
if (process.platform === "win32") {
|
|
14
|
-
|
|
15
|
+
try {
|
|
16
|
+
await exec("taskkill", ["/PID", String(pid), "/T", "/F"], { windowsHide: true, timeout: cleanupMs });
|
|
17
|
+
} catch (error) {
|
|
18
|
+
// The worker may exit after reporting completion, before taskkill opens it.
|
|
19
|
+
// Ask the OS whether it is gone; localized taskkill output is not an API.
|
|
20
|
+
try { process.kill(pid, 0); }
|
|
21
|
+
catch (probeError) {
|
|
22
|
+
if ((probeError as NodeJS.ErrnoException).code === "ESRCH") return;
|
|
23
|
+
}
|
|
24
|
+
throw error;
|
|
25
|
+
}
|
|
15
26
|
return;
|
|
16
27
|
}
|
|
17
28
|
const { stdout } = await exec("ps", ["-A", "-o", "pid=,ppid="], { timeout: cleanupMs });
|
|
@@ -47,6 +58,7 @@ export async function runCaptureProcess(
|
|
|
47
58
|
signal: AbortSignal,
|
|
48
59
|
onProgress: (event: HyperframesRenderProgress) => void,
|
|
49
60
|
entry = new URL("./capture-worker.ts", import.meta.url),
|
|
61
|
+
onDiagnostic?: (diagnostic: ExecutionDiagnostic) => Promise<void>,
|
|
50
62
|
): Promise<void> {
|
|
51
63
|
signal.throwIfAborted();
|
|
52
64
|
await new Promise<void>((resolve, reject) => {
|
|
@@ -58,6 +70,7 @@ export async function runCaptureProcess(
|
|
|
58
70
|
let completed = false;
|
|
59
71
|
let outputBytes = 0;
|
|
60
72
|
let stderr = "";
|
|
73
|
+
let diagnostics = Promise.resolve();
|
|
61
74
|
let grace: ReturnType<typeof setTimeout> | undefined;
|
|
62
75
|
let killing: Promise<void> | undefined;
|
|
63
76
|
const kill = () => {
|
|
@@ -80,8 +93,16 @@ export async function runCaptureProcess(
|
|
|
80
93
|
if (error) stderr = `${stderr}${chunk.toString()}`.slice(-32_000);
|
|
81
94
|
if (outputBytes > input.config.maxProcessOutputBytes) stop(new Error("HyperFrames process output exceeded the configured limit"));
|
|
82
95
|
};
|
|
83
|
-
child.stdout
|
|
84
|
-
|
|
96
|
+
for (const [stream, pipe] of [["stdout", child.stdout], ["stderr", child.stderr]] as const) {
|
|
97
|
+
pipe?.setEncoding("utf8");
|
|
98
|
+
pipe?.on("data", (text: string) => {
|
|
99
|
+
log(Buffer.from(text), stream === "stderr");
|
|
100
|
+
if (onDiagnostic !== undefined && text.trim()) {
|
|
101
|
+
diagnostics = diagnostics.then(() => onDiagnostic({ stream, level: "info", message: text.trimEnd() }))
|
|
102
|
+
.catch((error) => stop(error instanceof Error ? error : new Error(String(error))));
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
}
|
|
85
106
|
child.on("message", (value: { type: string; event?: HyperframesRenderProgress; error?: string }) => {
|
|
86
107
|
if (value.type === "progress" && value.event !== undefined) {
|
|
87
108
|
try { onProgress(value.event); } catch (error) { stop(error instanceof Error ? error : new Error(String(error))); }
|
|
@@ -98,7 +119,8 @@ export async function runCaptureProcess(
|
|
|
98
119
|
child.on("close", () => {
|
|
99
120
|
if (grace !== undefined) clearTimeout(grace);
|
|
100
121
|
signal.removeEventListener("abort", abort);
|
|
101
|
-
void (killing ?? Promise.resolve()).then(() => {
|
|
122
|
+
void (killing ?? Promise.resolve()).then(async () => {
|
|
123
|
+
await diagnostics;
|
|
102
124
|
if (failure !== undefined) reject(failure);
|
|
103
125
|
else if (!completed) reject(new Error(`HyperFrames process exited before completion: ${stderr}`));
|
|
104
126
|
else resolve();
|
|
@@ -6,6 +6,9 @@ import type { HyperframesRenderProgress, resolveExecutionOptions } from "./rende
|
|
|
6
6
|
import { assert, runProcess } from "./process.js";
|
|
7
7
|
import { verifyOutput } from "./output.js";
|
|
8
8
|
import { distributeFrameRange, sourceFrameAt, sourceWindows, videoSlots } from "./sampling.js";
|
|
9
|
+
import { renderWorkerLimit } from "./render.js";
|
|
10
|
+
import { CaptureConcurrency } from "./concurrency.js";
|
|
11
|
+
import { createOpaqueFrameCapture } from "./opaque-capture.js";
|
|
9
12
|
|
|
10
13
|
export type CaptureInput = {
|
|
11
14
|
readonly document: HyperframesDocument;
|
|
@@ -22,8 +25,14 @@ export async function captureStagedVisual(input: CaptureInput, controller: Abort
|
|
|
22
25
|
const { document, range, config, directory: work } = input;
|
|
23
26
|
const signal = controller.signal;
|
|
24
27
|
const frameCount = range.endFrameExclusive - range.startFrame;
|
|
25
|
-
const tasks = distributeFrameRange(range, config.workers);
|
|
26
28
|
const fps = { num: document.frameRate.numerator, den: document.frameRate.denominator };
|
|
29
|
+
const limit = renderWorkerLimit(config, frameCount, fps.num / fps.den);
|
|
30
|
+
const concurrency = new CaptureConcurrency(limit, config.workers === "auto");
|
|
31
|
+
// Short contiguous batches retain sequential capture while allowing free browsers
|
|
32
|
+
// to help with expensive passages. This queue exists only inside this render.
|
|
33
|
+
const batchCount = Math.max(limit, Math.ceil(frameCount / Math.max(1, Math.round(fps.num / fps.den))));
|
|
34
|
+
const batches = distributeFrameRange(range, batchCount);
|
|
35
|
+
let nextBatch = 0;
|
|
27
36
|
const started = performance.now();
|
|
28
37
|
const elapsedMs = () => Math.round(performance.now() - started);
|
|
29
38
|
const engine = await import(input.engineModule) as typeof import("@hyperframes/engine");
|
|
@@ -65,7 +74,11 @@ export async function captureStagedVisual(input: CaptureInput, controller: Abort
|
|
|
65
74
|
const sources = new Map<string, { frames: Map<number, string>; width: number; height: number }>();
|
|
66
75
|
let sourceFrames = 0;
|
|
67
76
|
// One source at a time bounds decoder pressure independently of browser concurrency.
|
|
68
|
-
|
|
77
|
+
const windows = sourceWindows(slots, range);
|
|
78
|
+
const sourceTotal = windows.reduce((sum, source) => sum + source.windows.reduce((count, window) =>
|
|
79
|
+
count + window.endFrameExclusive - window.startFrame, 0), 0);
|
|
80
|
+
if (sourceTotal > 0) onProgress({ phase: "decoding", completed: 0, total: sourceTotal, elapsedMs: elapsedMs() });
|
|
81
|
+
for (const source of windows) {
|
|
69
82
|
const path = resolve(work, source.src);
|
|
70
83
|
assert(path.startsWith(`${work}${sep}`), "HyperFrames source is outside the staged project");
|
|
71
84
|
const frames = new Map<number, string>();
|
|
@@ -86,6 +99,7 @@ export async function captureStagedVisual(input: CaptureInput, controller: Abort
|
|
|
86
99
|
width = extracted.metadata.width;
|
|
87
100
|
height = extracted.metadata.height;
|
|
88
101
|
sourceFrames += count;
|
|
102
|
+
onProgress({ phase: "decoding", completed: sourceFrames, total: sourceTotal, elapsedMs: elapsedMs() });
|
|
89
103
|
}
|
|
90
104
|
sources.set(source.src, { frames, width, height });
|
|
91
105
|
}
|
|
@@ -109,9 +123,24 @@ export async function captureStagedVisual(input: CaptureInput, controller: Abort
|
|
|
109
123
|
const serverUrl = server.url;
|
|
110
124
|
const outputFrames = join(work, "frames");
|
|
111
125
|
await mkdir(outputFrames);
|
|
112
|
-
onProgress?.({ phase: "prepared", workers:
|
|
113
|
-
const
|
|
126
|
+
onProgress?.({ phase: "prepared", workers: concurrency.target, sourceFrames, elapsedMs: elapsedMs() });
|
|
127
|
+
const jobs: Promise<void>[] = [];
|
|
128
|
+
let active = 0, open = 0, initializing = 0, capturedFrames = 0;
|
|
129
|
+
let startupMs = 0;
|
|
130
|
+
const launch = (): void => {
|
|
131
|
+
const worker = jobs.length;
|
|
132
|
+
jobs.push(runWorker(worker));
|
|
133
|
+
// Failure stops all jobs promptly; all jobs are still awaited below.
|
|
134
|
+
void jobs[worker]!.catch(() => {});
|
|
135
|
+
};
|
|
136
|
+
const runWorker = async (worker: number): Promise<void> => {
|
|
114
137
|
let session: Session | undefined;
|
|
138
|
+
let ready = false;
|
|
139
|
+
active++;
|
|
140
|
+
open++;
|
|
141
|
+
initializing++;
|
|
142
|
+
const launched = performance.now();
|
|
143
|
+
let setupMs = 0;
|
|
115
144
|
try {
|
|
116
145
|
signal.throwIfAborted();
|
|
117
146
|
const directory = join(work, `worker-${worker}`);
|
|
@@ -120,7 +149,9 @@ export async function captureStagedVisual(input: CaptureInput, controller: Abort
|
|
|
120
149
|
frameSrcResolver: (path) => new URL(relative(work, path).split(sep).map(encodeURIComponent).join("/"), `${serverUrl}/`).href,
|
|
121
150
|
});
|
|
122
151
|
session = await engine.createCaptureSession(serverUrl, directory, {
|
|
123
|
-
|
|
152
|
+
// Engine initialization couples PNG to transparent-export mode. Use
|
|
153
|
+
// its opaque session setup; our capture adapter writes lossless PNG.
|
|
154
|
+
...document.canvas, fps, format: "jpeg",
|
|
124
155
|
compositionDurationSeconds: document.frameCount * fps.den / fps.num,
|
|
125
156
|
skipReadinessVideoIds: slots.map((slot) => slot.id),
|
|
126
157
|
videoMetadataHints: slots.flatMap((slot) => {
|
|
@@ -132,38 +163,77 @@ export async function captureStagedVisual(input: CaptureInput, controller: Abort
|
|
|
132
163
|
signal.throwIfAborted();
|
|
133
164
|
const activeSession = session;
|
|
134
165
|
const browserPid = session.browser.process()?.pid;
|
|
135
|
-
onProgress?.({ phase: "worker-initializing", worker, range
|
|
166
|
+
onProgress?.({ phase: "worker-initializing", worker, range, browserPid, elapsedMs: elapsedMs() });
|
|
136
167
|
await stage(`worker ${worker} initialization`, config.initializationTimeoutMs, () => engine.initializeSession(activeSession));
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
onProgress?.({ phase: "worker-start", worker, range
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
168
|
+
const captureFrame = await createOpaqueFrameCapture(activeSession);
|
|
169
|
+
setupMs = performance.now() - launched;
|
|
170
|
+
startupMs = Math.max(startupMs, setupMs);
|
|
171
|
+
ready = true;
|
|
172
|
+
initializing--;
|
|
173
|
+
if (initializing === 0) concurrency.settled(performance.now());
|
|
174
|
+
onProgress?.({ phase: "worker-start", worker, range, browserPid, elapsedMs: elapsedMs() });
|
|
175
|
+
let completed = 0;
|
|
176
|
+
let lastProgressAt = performance.now();
|
|
177
|
+
const timing = { seekMs: 0, prepareMs: 0, screenshotMs: 0 };
|
|
178
|
+
while (true) {
|
|
179
|
+
// Retire only between complete batches, before claiming more work.
|
|
180
|
+
if (active > concurrency.target) break;
|
|
181
|
+
const batch = batches[nextBatch++];
|
|
182
|
+
if (batch === undefined) break;
|
|
183
|
+
for (let frame = batch.startFrame; frame < batch.endFrameExclusive; frame++) {
|
|
184
|
+
signal.throwIfAborted();
|
|
185
|
+
const captured = await stage(`worker ${worker} frame ${frame}`, config.frameTimeoutMs, () => captureFrame(frame));
|
|
186
|
+
timing.seekMs += captured.seekMs;
|
|
187
|
+
timing.prepareMs += captured.prepareMs;
|
|
188
|
+
timing.screenshotMs += captured.screenshotMs;
|
|
189
|
+
await writeFile(join(outputFrames, `${String(frame - range.startFrame).padStart(9, "0")}.png`), captured.buffer);
|
|
190
|
+
completed++;
|
|
191
|
+
capturedFrames++;
|
|
192
|
+
if (performance.now() - lastProgressAt >= 1_000) {
|
|
193
|
+
onProgress({ phase: "worker-progress", worker, completed, elapsedMs: elapsedMs() });
|
|
194
|
+
lastProgressAt = performance.now();
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
const decision = concurrency.complete({ now: performance.now(), frames: batch.endFrameExclusive - batch.startFrame,
|
|
198
|
+
remainingFrames: frameCount - capturedFrames, startupMs, active: initializing === 0 ? active : 0 });
|
|
199
|
+
if (decision !== undefined) {
|
|
200
|
+
console.log(`Capture auto: ${active} -> ${decision.workers} browsers; ${decision.fps.toFixed(1)} frames/s; ${decision.reason}`);
|
|
201
|
+
while (active < decision.workers && open < limit && nextBatch < batches.length) launch();
|
|
202
|
+
}
|
|
154
203
|
}
|
|
155
|
-
|
|
204
|
+
console.log(`Capture worker ${worker}: ${completed} frames; startup ${Math.round(setupMs)} ms; `
|
|
205
|
+
+ `seek ${Math.round(timing.seekMs)} ms; prepare ${Math.round(timing.prepareMs)} ms; PNG ${Math.round(timing.screenshotMs)} ms`);
|
|
206
|
+
onProgress({ phase: "worker-complete", worker, completed, browserPid, elapsedMs: elapsedMs() });
|
|
156
207
|
} catch (error) {
|
|
157
208
|
controller.abort(error);
|
|
158
209
|
throw error;
|
|
159
210
|
} finally {
|
|
211
|
+
active--;
|
|
212
|
+
if (!ready) initializing--;
|
|
160
213
|
if (session !== undefined) await close(session);
|
|
214
|
+
open--;
|
|
215
|
+
// A restoring decision can wait for a retiring Chrome to release its
|
|
216
|
+
// slot. Closing processes still count against the reserved ceiling.
|
|
217
|
+
if (!signal.aborted && active < concurrency.target && open < limit && nextBatch < batches.length) launch();
|
|
161
218
|
}
|
|
162
|
-
}
|
|
219
|
+
};
|
|
220
|
+
const initialWorkers = concurrency.target;
|
|
221
|
+
console.log(`Capture: opaque fast PNG; ${config.workers === "auto" ? "auto" : "fixed"} workers ${initialWorkers}, limit ${limit}`);
|
|
222
|
+
for (let i = 0; i < initialWorkers; i++) launch();
|
|
223
|
+
// New workers can join while earlier jobs run; collect every launched job.
|
|
224
|
+
let awaited = 0;
|
|
225
|
+
let failure: unknown;
|
|
226
|
+
while (awaited < jobs.length) {
|
|
227
|
+
const pending = jobs.slice(awaited);
|
|
228
|
+
awaited = jobs.length;
|
|
229
|
+
const results = await Promise.allSettled(pending);
|
|
230
|
+
for (const result of results) if (result.status === "rejected") failure ??= result.reason;
|
|
231
|
+
}
|
|
232
|
+
if (failure !== undefined) throw failure;
|
|
163
233
|
signal.throwIfAborted();
|
|
164
|
-
for (const result of results) if (result.status === "rejected") throw result.reason;
|
|
165
234
|
await Promise.all(closing.values());
|
|
166
235
|
const output = join(work, "visual.mp4");
|
|
236
|
+
onProgress({ phase: "encoding", elapsedMs: elapsedMs() });
|
|
167
237
|
const crf = { draft: 28, standard: 23, high: 18 }[config.quality];
|
|
168
238
|
await runProcess({ executable: config.ffmpegPath,
|
|
169
239
|
argv: ["-v", "error", "-y", "-framerate", `${fps.num}/${fps.den}`, "-i", join(outputFrames, "%09d.png"),
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { availableParallelism, totalmem } from "node:os";
|
|
2
|
+
|
|
3
|
+
function hostMemory(): number {
|
|
4
|
+
const constrained = process.constrainedMemory?.() ?? 0;
|
|
5
|
+
return constrained > 0 ? Math.min(totalmem(), constrained) : totalmem();
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/** Stable reservation ceiling. Actual load tuning happens inside the admitted render. */
|
|
9
|
+
export function autoWorkerLimit(cpu = availableParallelism(), memory = hostMemory()): number {
|
|
10
|
+
// Chrome owns raster surfaces, decoded media and the JS heap in separate
|
|
11
|
+
// processes. Leave half the memory and two CPU slots to the host/other stages.
|
|
12
|
+
const byMemory = Math.floor(memory / 2 / (1.5 * 1024 ** 3));
|
|
13
|
+
return Math.max(1, Math.min(Math.max(1, cpu - 2), byMemory));
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Online throughput comparison of useful capture batches. All samples and
|
|
18
|
+
* decisions die with this attempt. A change never invalidates captured frames.
|
|
19
|
+
*/
|
|
20
|
+
export class CaptureConcurrency {
|
|
21
|
+
target: number;
|
|
22
|
+
private since: number | undefined;
|
|
23
|
+
private frames = 0;
|
|
24
|
+
private batches = 0;
|
|
25
|
+
private baseline: { workers: number; rate: number } | undefined;
|
|
26
|
+
private previousRate: number | undefined;
|
|
27
|
+
private growth = true;
|
|
28
|
+
|
|
29
|
+
constructor(readonly limit: number, readonly automatic: boolean) {
|
|
30
|
+
this.target = automatic ? Math.max(1, Math.ceil(limit / 2)) : limit;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
settled(now: number): void {
|
|
34
|
+
this.since = now;
|
|
35
|
+
this.frames = 0;
|
|
36
|
+
this.batches = 0;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
complete(input: { now: number; frames: number; remainingFrames: number; startupMs: number; active: number }):
|
|
40
|
+
{ workers: number; reason: string; fps: number } | undefined {
|
|
41
|
+
if (!this.automatic) return;
|
|
42
|
+
if (input.active !== this.target) { this.since = undefined; return; }
|
|
43
|
+
if (this.since === undefined) { this.settled(input.now); return; }
|
|
44
|
+
this.frames += input.frames;
|
|
45
|
+
this.batches++;
|
|
46
|
+
const elapsed = input.now - this.since;
|
|
47
|
+
// At least two batches per worker and a browser startup's worth of useful
|
|
48
|
+
// work amortize short fluctuations. No synthetic calibration is rendered.
|
|
49
|
+
if (this.batches < this.target * 2 || elapsed < Math.max(1_000, input.startupMs)) return;
|
|
50
|
+
const rate = this.frames * 1_000 / elapsed;
|
|
51
|
+
let next = this.target;
|
|
52
|
+
let reason = "";
|
|
53
|
+
if (this.baseline !== undefined) {
|
|
54
|
+
const before = this.baseline;
|
|
55
|
+
this.baseline = undefined;
|
|
56
|
+
const added = this.target > before.workers;
|
|
57
|
+
if (rate < before.rate * (added ? 1.05 : 0.95)) {
|
|
58
|
+
next = before.workers;
|
|
59
|
+
reason = added ? "extra browser did not improve throughput" : "fewer browsers reduced throughput";
|
|
60
|
+
this.growth = false;
|
|
61
|
+
}
|
|
62
|
+
} else if (this.previousRate !== undefined && rate < this.previousRate * 0.7 && this.target > 1
|
|
63
|
+
&& input.remainingFrames > this.frames * 2) {
|
|
64
|
+
// A slower passage is not proof of contention. Compare fewer browsers
|
|
65
|
+
// on subsequent useful work and restore the old count if it is worse.
|
|
66
|
+
this.baseline = { workers: this.target, rate };
|
|
67
|
+
next--;
|
|
68
|
+
reason = "compare fewer browsers after throughput changed";
|
|
69
|
+
this.growth = false;
|
|
70
|
+
}
|
|
71
|
+
if (next === this.target && this.growth && next < this.limit
|
|
72
|
+
&& input.remainingFrames / rate * 1_000 > input.startupMs * (next + 1) * 2) {
|
|
73
|
+
// A new browser must have enough remaining work to repay its startup,
|
|
74
|
+
// even if its ideal contribution is only 1/(N+1) of current throughput.
|
|
75
|
+
this.baseline = { workers: this.target, rate };
|
|
76
|
+
next++;
|
|
77
|
+
reason = "remaining capture can amortize another browser";
|
|
78
|
+
}
|
|
79
|
+
this.previousRate = rate;
|
|
80
|
+
this.settled(input.now);
|
|
81
|
+
if (next === this.target) return;
|
|
82
|
+
this.target = next;
|
|
83
|
+
this.since = undefined;
|
|
84
|
+
return { workers: next, reason, fps: rate };
|
|
85
|
+
}
|
|
86
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import type { CaptureSession, HfProtocol } from "@hyperframes/engine";
|
|
2
|
+
import { getCdpSession } from "@hyperframes/engine";
|
|
3
|
+
|
|
4
|
+
/** The optional completion hooks supplied by the pinned Hyperframes page runtime. */
|
|
5
|
+
type RenderWindow = Window & {
|
|
6
|
+
__hf: HfProtocol & { colorGrading?: { waitForActiveLuts?: () => Promise<void> } };
|
|
7
|
+
__hfWaitForSeekCompletion?: () => Promise<void>;
|
|
8
|
+
__hf_page_composite_pending?: boolean;
|
|
9
|
+
__hf_page_composite_prepare?: () => Promise<void>;
|
|
10
|
+
__hf_page_composite_resolve?: () => void;
|
|
11
|
+
__hypitBrowserProgramError?: string;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* A screenshot adapter for this Provider's opaque MP4 output. Session lifecycle,
|
|
16
|
+
* the page's seek protocol and the video injector remain engine-owned. Encoding
|
|
17
|
+
* the already-composited frame as a fast PNG does not change source alpha.
|
|
18
|
+
* No engine/session methods are replaced and no installed dependency is patched.
|
|
19
|
+
*/
|
|
20
|
+
export async function createOpaqueFrameCapture(session: CaptureSession) {
|
|
21
|
+
const { page, options } = session;
|
|
22
|
+
const cdp = await getCdpSession(page);
|
|
23
|
+
// MP4 has no alpha channel. The authored Canvas paints over this final matte.
|
|
24
|
+
await cdp.send("Emulation.setDefaultBackgroundColorOverride", { color: { r: 0, g: 0, b: 0, a: 1 } });
|
|
25
|
+
// These decoded image handles belong to this page, just like its DOM. Retain
|
|
26
|
+
// only URLs used by inline background images; changing a style can need a load
|
|
27
|
+
// even after initializeSession has finished its initial resource readiness.
|
|
28
|
+
await page.evaluate(() => {
|
|
29
|
+
const decoded = new Map<string, Promise<void>>();
|
|
30
|
+
(window as unknown as { __hypitPrepareImages: () => Promise<void> }).__hypitPrepareImages = async () => {
|
|
31
|
+
const pending: Promise<unknown>[] = [];
|
|
32
|
+
if (document.fonts.status === "loading") pending.push(document.fonts.ready);
|
|
33
|
+
for (const image of Array.from(document.images)) {
|
|
34
|
+
if (!image.complete) pending.push(image.decode());
|
|
35
|
+
}
|
|
36
|
+
for (const element of Array.from(document.querySelectorAll<HTMLElement>('[style*="background"]'))) {
|
|
37
|
+
const background = element.style.backgroundImage;
|
|
38
|
+
for (const match of background.matchAll(/url\(\s*(?:"((?:\\.|[^"])*)"|'((?:\\.|[^'])*)'|([^)]*))\s*\)/gu)) {
|
|
39
|
+
const url = (match[1] ?? match[2] ?? match[3] ?? "").trim();
|
|
40
|
+
if (!url) continue;
|
|
41
|
+
let ready = decoded.get(url);
|
|
42
|
+
if (ready === undefined) {
|
|
43
|
+
const image = new Image();
|
|
44
|
+
image.src = url;
|
|
45
|
+
ready = image.decode();
|
|
46
|
+
decoded.set(url, ready);
|
|
47
|
+
}
|
|
48
|
+
pending.push(ready);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
await Promise.all(pending);
|
|
52
|
+
};
|
|
53
|
+
});
|
|
54
|
+
return async (frame: number) => {
|
|
55
|
+
const time = frame * options.fps.den / options.fps.num;
|
|
56
|
+
const start = performance.now();
|
|
57
|
+
await page.evaluate(async t => {
|
|
58
|
+
const w = window as unknown as RenderWindow;
|
|
59
|
+
await w.__hf.seek(t);
|
|
60
|
+
}, time);
|
|
61
|
+
const sought = performance.now();
|
|
62
|
+
await session.onBeforeCapture?.(page, time);
|
|
63
|
+
const composite = await page.evaluate(async () => {
|
|
64
|
+
const w = window as unknown as RenderWindow & { __hypitPrepareImages: () => Promise<void> };
|
|
65
|
+
await w.__hfWaitForSeekCompletion?.();
|
|
66
|
+
await w.__hf.colorGrading?.waitForActiveLuts?.();
|
|
67
|
+
await w.__hypitPrepareImages();
|
|
68
|
+
if (w.__hypitBrowserProgramError !== undefined) throw new Error(w.__hypitBrowserProgramError);
|
|
69
|
+
if (w.__hf_page_composite_pending) {
|
|
70
|
+
await w.__hf_page_composite_prepare?.();
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
return false;
|
|
74
|
+
});
|
|
75
|
+
if (composite) {
|
|
76
|
+
// The runtime's shader compositor needs a paint between preparing its DOM
|
|
77
|
+
// layers and resolving them. A 1 px capture flushes Chrome's compositor.
|
|
78
|
+
await cdp.send("Page.captureScreenshot", {
|
|
79
|
+
format: "jpeg", quality: 1, clip: { x: 0, y: 0, width: 1, height: 1, scale: 1 },
|
|
80
|
+
});
|
|
81
|
+
await page.evaluate(() => (window as unknown as RenderWindow).__hf_page_composite_resolve?.());
|
|
82
|
+
}
|
|
83
|
+
const prepared = performance.now();
|
|
84
|
+
const result = await cdp.send("Page.captureScreenshot", {
|
|
85
|
+
format: "png", optimizeForSpeed: true, fromSurface: true,
|
|
86
|
+
captureBeyondViewport: options.captureBeyondViewport ?? false,
|
|
87
|
+
clip: { x: 0, y: 0, width: options.width, height: options.height, scale: options.deviceScaleFactor ?? 1 },
|
|
88
|
+
});
|
|
89
|
+
return { buffer: Buffer.from(result.data, "base64"),
|
|
90
|
+
seekMs: sought - start, prepareMs: prepared - sought, screenshotMs: performance.now() - prepared };
|
|
91
|
+
};
|
|
92
|
+
}
|
|
@@ -8,6 +8,8 @@ export type HyperframesExecutionOptions = {
|
|
|
8
8
|
readonly ffmpegPath?: string;
|
|
9
9
|
/** Parallel Chrome workers inside one render. This is separate from Provider request concurrency. */
|
|
10
10
|
readonly workers?: HyperframesWorkers;
|
|
11
|
+
/** Upper bound for auto's browser reservation; explicit workers remain fixed. */
|
|
12
|
+
readonly maxWorkers?: number;
|
|
11
13
|
readonly quality?: HyperframesQuality;
|
|
12
14
|
/** Chrome's rasterizer, default hardware. Use software without a usable GPU. */
|
|
13
15
|
readonly browserGpu?: HyperframesBrowserGpu;
|
|
@@ -22,13 +22,16 @@ export function localHyperframesBrowserProgram(
|
|
|
22
22
|
input: {
|
|
23
23
|
readonly id: string;
|
|
24
24
|
readonly nodePath: string;
|
|
25
|
-
readonly hyperframesCliPath: string;
|
|
25
|
+
readonly hyperframesCliPath: string | (() => string);
|
|
26
26
|
readonly ffprobePath: string;
|
|
27
27
|
readonly ffmpegPath?: string;
|
|
28
28
|
},
|
|
29
29
|
): ManagedProgram {
|
|
30
|
+
const cliPath = () => typeof input.hyperframesCliPath === "string" ? input.hyperframesCliPath : input.hyperframesCliPath();
|
|
30
31
|
const probeBrowser = async (): Promise<ManagedProgramState> => {
|
|
31
|
-
|
|
32
|
+
let executable: string;
|
|
33
|
+
try { executable = cliPath(); } catch (error) { return { state: "down", detail: error instanceof Error ? error.message : String(error) }; }
|
|
34
|
+
const located = await run(input.nodePath, [executable, "browser", "path"]);
|
|
32
35
|
if (!located.ok) return { state: "down", detail: `HyperFrames browser is unavailable: ${located.output}` };
|
|
33
36
|
const path = located.output.trim();
|
|
34
37
|
if (path.length === 0 || path.includes("\n") || path.includes("\r")) {
|
|
@@ -44,7 +47,7 @@ export function localHyperframesBrowserProgram(
|
|
|
44
47
|
id: input.id,
|
|
45
48
|
installation: {
|
|
46
49
|
probe: probeBrowser,
|
|
47
|
-
commands
|
|
50
|
+
get commands() { return [{ command: input.nodePath, args: [cliPath(), "browser", "ensure"] }]; },
|
|
48
51
|
},
|
|
49
52
|
async probe(): Promise<ManagedProgramState> {
|
|
50
53
|
const browser = await probeBrowser();
|