@hypit/hypit 0.0.1 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +26 -0
- package/README.md +142 -0
- package/bin/hypit.mjs +46 -0
- package/dist/public/artifact.d.ts +75 -0
- package/dist/public/author-kit.d.ts +559 -0
- package/dist/public/browser-capture.d.ts +56 -0
- package/dist/public/caption.d.ts +751 -0
- package/dist/public/composition.d.ts +672 -0
- package/dist/public/endpoint-kit.d.ts +366 -0
- package/dist/public/generation.d.ts +591 -0
- package/dist/public/hyperframes.d.ts +774 -0
- package/dist/public/media.d.ts +708 -0
- package/dist/public/model-kit.d.ts +523 -0
- package/dist/public/narrative.d.ts +315 -0
- package/dist/public/program-space.d.ts +193 -0
- package/dist/public/runtime-kit.d.ts +427 -0
- package/dist/public/semantic-track.d.ts +418 -0
- package/dist/public/spatial.d.ts +1193 -0
- package/dist/public/speech.d.ts +391 -0
- package/dist/public/studio-adapter.d.ts +686 -0
- package/dist/public/svs.d.ts +311 -0
- package/dist/public/temporal-markup.d.ts +343 -0
- package/dist/public/temporal.d.ts +497 -0
- package/dist/public/text.d.ts +817 -0
- package/dist/public/visual-ir.d.ts +98 -0
- package/docs/public/hypit-logo-dark.svg +36 -0
- package/docs/public/hypit-logo-light.svg +38 -0
- package/examples/README.md +24 -0
- package/examples/minimal-author-package/README.md +18 -0
- package/examples/minimal-author-package/packages/example-component/README.md +44 -0
- package/examples/minimal-author-package/packages/example-component/package.json +27 -0
- package/examples/minimal-author-package/packages/example-component/preview/Box.png +0 -0
- package/examples/minimal-author-package/packages/example-component/preview/build.svrun +6 -0
- package/examples/minimal-author-package/packages/example-component/preview/preview.svml +47 -0
- package/examples/minimal-author-package/packages/example-component/preview/recipes.svs +8 -0
- package/examples/minimal-author-package/packages/example-component/src/activation.ts +10 -0
- package/examples/minimal-author-package/packages/example-component/src/component.ts +44 -0
- package/examples/minimal-author-package/packages/example-component/src/fragment.ts +32 -0
- package/examples/minimal-author-package/packages/example-component/src/index.ts +6 -0
- package/examples/minimal-author-package/packages/example-component/src/manifest.ts +82 -0
- package/examples/minimal-author-package/packages/example-component/src/style.ts +13 -0
- package/examples/minimal-author-package/packages/example-component/src/surface.ts +41 -0
- package/examples/minimal-author-package/packages/example-component/src/temporal.ts +6 -0
- package/examples/minimal-author-package/packages/example-component/tsconfig.json +18 -0
- package/examples/semantic-composition/README.md +35 -0
- package/examples/semantic-composition/chat.svml +25 -0
- package/examples/semantic-composition/chat.svrun +6 -0
- package/examples/semantic-composition/chat.svs +4 -0
- package/examples/semantic-composition/hypit.runtime.json +8 -0
- package/examples/semantic-composition/packages/chat-scene/README.md +29 -0
- package/examples/semantic-composition/packages/chat-scene/package.json +11 -0
- package/examples/semantic-composition/packages/chat-scene/src/activation.ts +112 -0
- package/examples/semantic-composition/packages/chat-scene/src/render.ts +64 -0
- package/examples/semantic-composition/packages/chat-scene/tsconfig.json +18 -0
- package/examples/semantic-composition/packages/responsive-explainer/README.md +45 -0
- package/examples/semantic-composition/packages/responsive-explainer/package.json +11 -0
- package/examples/semantic-composition/packages/responsive-explainer/src/activation.ts +90 -0
- package/examples/semantic-composition/packages/responsive-explainer/src/render.ts +68 -0
- package/examples/semantic-composition/packages/responsive-explainer/tsconfig.json +18 -0
- package/package.json +263 -5
- package/packages/artifact/README.md +10 -0
- package/packages/artifact/package.json +16 -0
- package/packages/artifact/src/activation.ts +8 -0
- package/packages/artifact/src/index.ts +24 -0
- package/packages/audio-track/README.md +43 -0
- package/packages/audio-track/package.json +36 -0
- package/packages/audio-track/src/activation.ts +20 -0
- package/packages/audio-track/src/component.ts +40 -0
- package/packages/audio-track/src/fragment.ts +63 -0
- package/packages/audio-track/src/index.ts +7 -0
- package/packages/audio-track/src/manifest.ts +151 -0
- package/packages/audio-track/src/program.ts +254 -0
- package/packages/audio-track/src/surface.ts +187 -0
- package/packages/audio-track/src/types.ts +62 -0
- package/packages/audio-track-studio/README.md +3 -0
- package/packages/audio-track-studio/package.json +14 -0
- package/packages/audio-track-studio/src/activation.ts +7 -0
- package/packages/audio-track-studio/src/index.ts +72 -0
- package/packages/author-kit/README.md +31 -0
- package/packages/author-kit/package.json +16 -0
- package/packages/author-kit/src/index.ts +59 -0
- package/packages/background-removal/README.md +29 -0
- package/packages/background-removal/package.json +16 -0
- package/packages/background-removal/src/activation.ts +18 -0
- package/packages/background-removal/src/component.ts +32 -0
- package/packages/background-removal/src/fragment.ts +18 -0
- package/packages/background-removal/src/index.ts +6 -0
- package/packages/background-removal/src/manifest.ts +45 -0
- package/packages/background-removal/src/program.ts +19 -0
- package/packages/background-removal/src/surface.ts +27 -0
- package/packages/background-removal/src/types.ts +5 -0
- package/packages/browser-capture/README.md +82 -0
- package/packages/browser-capture/package.json +15 -0
- package/packages/browser-capture/src/browser.ts +19 -0
- package/packages/browser-capture/src/index.ts +198 -0
- package/packages/build-result/package.json +13 -0
- package/packages/build-result/src/decode.ts +286 -0
- package/packages/build-result/src/index.ts +25 -0
- package/packages/build-result/src/store.ts +505 -0
- package/packages/build-result/src/types.ts +354 -0
- package/packages/build-result/src/writer.ts +184 -0
- package/packages/build-result-fs/README.md +29 -0
- package/packages/build-result-fs/package.json +17 -0
- package/packages/build-result-fs/src/activation.ts +62 -0
- package/packages/build-result-fs/src/index.ts +1 -0
- package/packages/build-result-kit/README.md +10 -0
- package/packages/build-result-kit/package.json +15 -0
- package/packages/build-result-kit/src/index.ts +144 -0
- package/packages/build-result-s3/README.md +49 -0
- package/packages/build-result-s3/package.json +19 -0
- package/packages/build-result-s3/src/activation.ts +71 -0
- package/packages/build-result-s3/src/client.ts +254 -0
- package/packages/build-result-s3/src/index.ts +4 -0
- package/packages/build-result-s3/src/repository.ts +361 -0
- package/packages/caption/README.md +77 -0
- package/packages/caption/package.json +28 -0
- package/packages/caption/src/activation.ts +17 -0
- package/packages/caption/src/component.ts +38 -0
- package/packages/caption/src/display.ts +111 -0
- package/packages/caption/src/error.ts +9 -0
- package/packages/caption/src/fragment.ts +26 -0
- package/packages/caption/src/index.ts +33 -0
- package/packages/caption/src/manifest.ts +97 -0
- package/packages/caption/src/style.ts +170 -0
- package/packages/caption/src/surface.ts +96 -0
- package/packages/caption/src/temporalize.ts +124 -0
- package/packages/caption/src/types.ts +71 -0
- package/packages/caption-fine/README.md +108 -0
- package/packages/caption-fine/package.json +30 -0
- package/packages/caption-fine/preview/Track.png +0 -0
- package/packages/caption-fine/src/activation.ts +32 -0
- package/packages/caption-fine/src/component.ts +58 -0
- package/packages/caption-fine/src/fragment.ts +112 -0
- package/packages/caption-fine/src/index.ts +19 -0
- package/packages/caption-fine/src/manifest.ts +383 -0
- package/packages/caption-fine/src/recipe.ts +120 -0
- package/packages/caption-fine/src/render.ts +1133 -0
- package/packages/caption-fine/src/schedule.ts +126 -0
- package/packages/caption-fine/src/spacing.ts +69 -0
- package/packages/caption-fine/src/style.ts +370 -0
- package/packages/caption-fine/src/surface.ts +152 -0
- package/packages/caption-fine/src/types.ts +191 -0
- package/packages/caption-fine-studio/README.md +3 -0
- package/packages/caption-fine-studio/package.json +15 -0
- package/packages/caption-fine-studio/src/activation.ts +7 -0
- package/packages/caption-fine-studio/src/index.ts +163 -0
- package/packages/cli/README.md +51 -0
- package/packages/cli/package.json +33 -0
- package/packages/cli/src/arguments.ts +605 -0
- package/packages/cli/src/build-planning.ts +460 -0
- package/packages/cli/src/command.ts +202 -0
- package/packages/cli/src/commands/environment.ts +391 -0
- package/packages/cli/src/commands/execution.ts +321 -0
- package/packages/cli/src/commands/results.ts +187 -0
- package/packages/cli/src/commands/types.ts +9 -0
- package/packages/cli/src/distribution.ts +74 -0
- package/packages/cli/src/index.ts +30 -0
- package/packages/cli/src/machine-view.ts +28 -0
- package/packages/cli/src/main.ts +654 -0
- package/packages/cli/src/oauth.ts +228 -0
- package/packages/cli/src/observation.ts +203 -0
- package/packages/cli/src/output.ts +1007 -0
- package/packages/cli/src/paths.ts +7 -0
- package/packages/cli/src/project-context.ts +38 -0
- package/packages/cli/src/reachability.ts +91 -0
- package/packages/cli/src/result-export.ts +148 -0
- package/packages/cli/src/result-query.ts +46 -0
- package/packages/cli/src/run-file.ts +186 -0
- package/packages/cli/src/runtime-port.ts +13 -0
- package/packages/cli/src/runtime-selection.ts +94 -0
- package/packages/cli/src/runtime-view.ts +15 -0
- package/packages/cli/src/source-discovery.ts +150 -0
- package/packages/cli/src/source-packages.ts +91 -0
- package/packages/cli/src/view.ts +228 -0
- package/packages/comment-sticker/README.md +41 -0
- package/packages/comment-sticker/package.json +29 -0
- package/packages/comment-sticker/preview/Track.png +0 -0
- package/packages/comment-sticker/src/activation.ts +32 -0
- package/packages/comment-sticker/src/author.ts +148 -0
- package/packages/comment-sticker/src/component.ts +97 -0
- package/packages/comment-sticker/src/fragment.ts +124 -0
- package/packages/comment-sticker/src/index.ts +8 -0
- package/packages/comment-sticker/src/manifest.ts +373 -0
- package/packages/comment-sticker/src/program.ts +610 -0
- package/packages/comment-sticker/src/surface.ts +172 -0
- package/packages/comment-sticker/src/types.ts +109 -0
- package/packages/comment-sticker-studio/README.md +3 -0
- package/packages/comment-sticker-studio/package.json +14 -0
- package/packages/comment-sticker-studio/src/activation.ts +7 -0
- package/packages/comment-sticker-studio/src/index.ts +132 -0
- package/packages/compiler-markup-node/README.md +12 -0
- package/packages/compiler-markup-node/package.json +22 -0
- package/packages/compiler-markup-node/src/index.ts +59 -0
- package/packages/compiler-node/README.md +60 -0
- package/packages/compiler-node/package.json +25 -0
- package/packages/compiler-node/src/compiler.ts +207 -0
- package/packages/compiler-node/src/error.ts +11 -0
- package/packages/compiler-node/src/graph-query.ts +51 -0
- package/packages/compiler-node/src/index.ts +27 -0
- package/packages/compiler-node/src/modules.ts +107 -0
- package/packages/compiler-node/src/run.ts +355 -0
- package/packages/component-kit/README.md +97 -0
- package/packages/component-kit/package.json +13 -0
- package/packages/component-kit/src/index.ts +155 -0
- package/packages/composition/README.md +53 -0
- package/packages/composition/package.json +29 -0
- package/packages/composition/src/activation.ts +3 -0
- package/packages/composition/src/component.ts +10 -0
- package/packages/composition/src/index.ts +18 -0
- package/packages/composition/src/manifest.ts +13 -0
- package/packages/composition/src/schema.ts +194 -0
- package/packages/composition/src/track.ts +1403 -0
- package/packages/core/README.md +22 -0
- package/packages/core/package.json +13 -0
- package/packages/core/src/error.ts +12 -0
- package/packages/core/src/graph.ts +341 -0
- package/packages/core/src/index.ts +32 -0
- package/packages/core/src/link.ts +240 -0
- package/packages/core/src/machine.ts +60 -0
- package/packages/core/src/plan.ts +504 -0
- package/packages/core/src/reducer.ts +428 -0
- package/packages/core/src/reference.ts +25 -0
- package/packages/core/src/slice.ts +108 -0
- package/packages/credential-store-env/README.md +11 -0
- package/packages/credential-store-env/package.json +17 -0
- package/packages/credential-store-env/src/activation.ts +25 -0
- package/packages/credential-store-env/src/index.ts +23 -0
- package/packages/credential-store-os/README.md +13 -0
- package/packages/credential-store-os/package.json +22 -0
- package/packages/credential-store-os/runtime/windows-credential.ps1 +59 -0
- package/packages/credential-store-os/src/activation.ts +32 -0
- package/packages/credential-store-os/src/index.ts +2 -0
- package/packages/credential-store-os/src/store.ts +196 -0
- package/packages/deck-track/README.md +52 -0
- package/packages/deck-track/package.json +35 -0
- package/packages/deck-track/preview/DepthStack.png +0 -0
- package/packages/deck-track/src/activation.ts +32 -0
- package/packages/deck-track/src/author.ts +217 -0
- package/packages/deck-track/src/component.ts +86 -0
- package/packages/deck-track/src/fragment.ts +148 -0
- package/packages/deck-track/src/index.ts +16 -0
- package/packages/deck-track/src/lower.ts +370 -0
- package/packages/deck-track/src/manifest.ts +438 -0
- package/packages/deck-track/src/program.ts +367 -0
- package/packages/deck-track/src/surface.ts +286 -0
- package/packages/deck-track/src/types.ts +119 -0
- package/packages/deck-track-studio/README.md +3 -0
- package/packages/deck-track-studio/package.json +14 -0
- package/packages/deck-track-studio/src/activation.ts +7 -0
- package/packages/deck-track-studio/src/index.ts +134 -0
- package/packages/driver-node/README.md +23 -0
- package/packages/driver-node/package.json +18 -0
- package/packages/driver-node/src/driver.ts +616 -0
- package/packages/driver-node/src/index.ts +10 -0
- package/packages/driver-node/src/planning.ts +67 -0
- package/packages/driver-node/src/registry.ts +234 -0
- package/packages/driver-node/src/resources.ts +36 -0
- package/packages/driver-node/src/types.ts +69 -0
- package/packages/elaborator/README.md +74 -0
- package/packages/elaborator/package.json +16 -0
- package/packages/elaborator/src/author.ts +308 -0
- package/packages/elaborator/src/fragment.ts +505 -0
- package/packages/elaborator/src/frontend-facet.ts +30 -0
- package/packages/elaborator/src/index.ts +78 -0
- package/packages/elaborator/src/source.ts +608 -0
- package/packages/endpoint-kit/README.md +111 -0
- package/packages/endpoint-kit/package.json +14 -0
- package/packages/endpoint-kit/src/index.ts +488 -0
- package/packages/estimate/README.md +32 -0
- package/packages/estimate/package.json +20 -0
- package/packages/estimate/src/activation.ts +11 -0
- package/packages/estimate/src/index.ts +16 -0
- package/packages/estimate/src/manifest.ts +34 -0
- package/packages/estimate/src/policy.ts +70 -0
- package/packages/estimate/src/program.ts +196 -0
- package/packages/estimate/src/types.ts +15 -0
- package/packages/film/README.md +49 -0
- package/packages/film/package.json +34 -0
- package/packages/film/src/activation.ts +16 -0
- package/packages/film/src/component.ts +61 -0
- package/packages/film/src/fragment.ts +83 -0
- package/packages/film/src/index.ts +11 -0
- package/packages/film/src/manifest.ts +152 -0
- package/packages/film/src/program.ts +110 -0
- package/packages/film/src/recipe.ts +24 -0
- package/packages/film/src/surface.ts +146 -0
- package/packages/film/src/types.ts +26 -0
- package/packages/film-studio/package.json +16 -0
- package/packages/film-studio/src/activation.ts +8 -0
- package/packages/film-studio/src/index.ts +17 -0
- package/packages/fonts-open/README.md +77 -0
- package/packages/fonts-open/package.json +130 -0
- package/packages/fonts-open/src/activation.ts +30 -0
- package/packages/fonts-open/src/catalog.ts +317 -0
- package/packages/fonts-open/src/index.ts +13 -0
- package/packages/fonts-open/src/manifest.ts +83 -0
- package/packages/fonts-open/src/surface.ts +239 -0
- package/packages/generation/README.md +19 -0
- package/packages/generation/package.json +23 -0
- package/packages/generation/src/activation.ts +9 -0
- package/packages/generation/src/component.ts +77 -0
- package/packages/generation/src/identity.ts +80 -0
- package/packages/generation/src/index.ts +79 -0
- package/packages/generation/src/manifest.ts +65 -0
- package/packages/generation/src/mapping.ts +231 -0
- package/packages/generation/src/ports.ts +222 -0
- package/packages/generation/src/request.ts +427 -0
- package/packages/generation/src/schema.ts +62 -0
- package/packages/generation/src/types.ts +17 -0
- package/packages/gpt-image/README.md +54 -0
- package/packages/gpt-image/package.json +34 -0
- package/packages/gpt-image/src/activation.ts +39 -0
- package/packages/gpt-image/src/fragment.ts +101 -0
- package/packages/gpt-image/src/index.ts +203 -0
- package/packages/gpt-image/src/surface.ts +194 -0
- package/packages/gpt-image-kits/README.md +44 -0
- package/packages/gpt-image-kits/kits/phone-ugc-v1.svs +34 -0
- package/packages/gpt-image-kits/package.json +15 -0
- package/packages/grok-imagine/README.md +21 -0
- package/packages/grok-imagine/package.json +21 -0
- package/packages/grok-imagine/src/activation.ts +29 -0
- package/packages/grok-imagine/src/index.ts +174 -0
- package/packages/grok-imagine/src/surface.ts +149 -0
- package/packages/host/README.md +5 -0
- package/packages/host/package.json +10 -0
- package/packages/host/src/facet.ts +6 -0
- package/packages/host/src/frontend.ts +56 -0
- package/packages/host/src/index.ts +9 -0
- package/packages/hyperframes/README.md +69 -0
- package/packages/hyperframes/package.json +36 -0
- package/packages/hyperframes/src/activation.ts +8 -0
- package/packages/hyperframes/src/browser-program.ts +79 -0
- package/packages/hyperframes/src/component.ts +32 -0
- package/packages/hyperframes/src/document.ts +827 -0
- package/packages/hyperframes/src/fragment.ts +32 -0
- package/packages/hyperframes/src/index.ts +13 -0
- package/packages/hyperframes/src/manifest.ts +67 -0
- package/packages/hyperframes/src/project.ts +118 -0
- package/packages/hyperframes/src/text.ts +1179 -0
- package/packages/hyperframes/src/types.ts +38 -0
- package/packages/image-compose/README.md +25 -0
- package/packages/image-compose/package.json +18 -0
- package/packages/image-compose/src/activation.ts +21 -0
- package/packages/image-compose/src/component.ts +100 -0
- package/packages/image-compose/src/fragment.ts +54 -0
- package/packages/image-compose/src/index.ts +10 -0
- package/packages/image-compose/src/manifest.ts +119 -0
- package/packages/image-compose/src/program.ts +75 -0
- package/packages/image-compose/src/surface.ts +83 -0
- package/packages/image-compose/src/types.ts +22 -0
- package/packages/image-transform/README.md +29 -0
- package/packages/image-transform/package.json +21 -0
- package/packages/image-transform/src/activation.ts +33 -0
- package/packages/image-transform/src/component.ts +67 -0
- package/packages/image-transform/src/fragment.ts +25 -0
- package/packages/image-transform/src/index.ts +13 -0
- package/packages/image-transform/src/manifest.ts +209 -0
- package/packages/image-transform/src/program.ts +23 -0
- package/packages/image-transform/src/surface.ts +216 -0
- package/packages/image-transform/src/types.ts +20 -0
- package/packages/interview-emoji-reveal/README.md +39 -0
- package/packages/interview-emoji-reveal/package.json +23 -0
- package/packages/interview-emoji-reveal/preview/Track.png +0 -0
- package/packages/interview-emoji-reveal/src/activation.ts +14 -0
- package/packages/interview-emoji-reveal/src/component.ts +45 -0
- package/packages/interview-emoji-reveal/src/fragment.ts +62 -0
- package/packages/interview-emoji-reveal/src/index.ts +16 -0
- package/packages/interview-emoji-reveal/src/manifest.ts +174 -0
- package/packages/interview-emoji-reveal/src/program.ts +242 -0
- package/packages/interview-emoji-reveal/src/style.ts +47 -0
- package/packages/interview-emoji-reveal/src/surface.ts +110 -0
- package/packages/interview-emoji-reveal/src/types.ts +52 -0
- package/packages/markup/README.md +81 -0
- package/packages/markup/package.json +16 -0
- package/packages/markup/src/element.ts +39 -0
- package/packages/markup/src/error.ts +20 -0
- package/packages/markup/src/frontend.ts +518 -0
- package/packages/markup/src/host-facet.ts +115 -0
- package/packages/markup/src/index.ts +25 -0
- package/packages/markup/src/registry.ts +83 -0
- package/packages/markup/src/syntax.ts +271 -0
- package/packages/markup/src/types.ts +246 -0
- package/packages/media/README.md +37 -0
- package/packages/media/package.json +19 -0
- package/packages/media/src/activation.ts +38 -0
- package/packages/media/src/component.ts +16 -0
- package/packages/media/src/frame-range.ts +33 -0
- package/packages/media/src/identity.ts +227 -0
- package/packages/media/src/index.ts +15 -0
- package/packages/media/src/manifest.ts +122 -0
- package/packages/media/src/render.ts +140 -0
- package/packages/media/src/schema.ts +69 -0
- package/packages/media/src/surface.ts +150 -0
- package/packages/media/src/types.ts +121 -0
- package/packages/media-execution/README.md +28 -0
- package/packages/media-execution/package.json +17 -0
- package/packages/media-execution/src/execute.ts +1322 -0
- package/packages/media-execution/src/index.ts +16 -0
- package/packages/media-execution/src/probe.ts +315 -0
- package/packages/media-execution/src/surface.ts +286 -0
- package/packages/media-execution/src/toolchain.ts +81 -0
- package/packages/media-execution/src/webp.ts +200 -0
- package/packages/media-pipeline/README.md +113 -0
- package/packages/media-pipeline/package.json +27 -0
- package/packages/media-pipeline/src/activation.ts +47 -0
- package/packages/media-pipeline/src/audio-plan.ts +113 -0
- package/packages/media-pipeline/src/component.ts +373 -0
- package/packages/media-pipeline/src/fragment.ts +167 -0
- package/packages/media-pipeline/src/index.ts +46 -0
- package/packages/media-pipeline/src/manifest.ts +653 -0
- package/packages/media-pipeline/src/operations.ts +248 -0
- package/packages/media-pipeline/src/selection.ts +110 -0
- package/packages/media-pipeline/src/surface.ts +389 -0
- package/packages/media-pipeline/src/types.ts +175 -0
- package/packages/media-track/README.md +197 -0
- package/packages/media-track/package.json +29 -0
- package/packages/media-track/preview/Track.png +0 -0
- package/packages/media-track/preview/build.svrun +5 -0
- package/packages/media-track/preview/flush.png +0 -0
- package/packages/media-track/preview/preview.svml +47 -0
- package/packages/media-track/preview/recipes.svs +23 -0
- package/packages/media-track/preview/rounded.png +0 -0
- package/packages/media-track/src/activation.ts +20 -0
- package/packages/media-track/src/author.ts +317 -0
- package/packages/media-track/src/component.ts +162 -0
- package/packages/media-track/src/fragment.ts +57 -0
- package/packages/media-track/src/index.ts +65 -0
- package/packages/media-track/src/layers.ts +308 -0
- package/packages/media-track/src/lower.ts +335 -0
- package/packages/media-track/src/manifest.ts +624 -0
- package/packages/media-track/src/motion.ts +387 -0
- package/packages/media-track/src/performance.ts +37 -0
- package/packages/media-track/src/presentation.ts +35 -0
- package/packages/media-track/src/program.ts +565 -0
- package/packages/media-track/src/sampling.ts +118 -0
- package/packages/media-track/src/sequence.ts +403 -0
- package/packages/media-track/src/sounds.ts +71 -0
- package/packages/media-track/src/surface.ts +668 -0
- package/packages/media-track/src/types.ts +311 -0
- package/packages/media-track-studio/README.md +3 -0
- package/packages/media-track-studio/package.json +15 -0
- package/packages/media-track-studio/src/activation.ts +7 -0
- package/packages/media-track-studio/src/index.ts +235 -0
- package/packages/mimo-speech/README.md +33 -0
- package/packages/mimo-speech/package.json +21 -0
- package/packages/mimo-speech/src/activation.ts +32 -0
- package/packages/mimo-speech/src/fragment.ts +11 -0
- package/packages/mimo-speech/src/index.ts +160 -0
- package/packages/mimo-speech/src/surface.ts +193 -0
- package/packages/minimax-h3/README.md +21 -0
- package/packages/minimax-h3/package.json +21 -0
- package/packages/minimax-h3/src/activation.ts +14 -0
- package/packages/minimax-h3/src/index.ts +188 -0
- package/packages/minimax-h3/src/surface.ts +87 -0
- package/packages/model-kit/README.md +52 -0
- package/packages/model-kit/package.json +19 -0
- package/packages/model-kit/src/index.ts +728 -0
- package/packages/nano-banana/README.md +23 -0
- package/packages/nano-banana/package.json +21 -0
- package/packages/nano-banana/src/activation.ts +14 -0
- package/packages/nano-banana/src/index.ts +172 -0
- package/packages/nano-banana/src/surface.ts +120 -0
- package/packages/narrative/README.md +7 -0
- package/packages/narrative/package.json +17 -0
- package/packages/narrative/src/activation.ts +7 -0
- package/packages/narrative/src/component.ts +33 -0
- package/packages/narrative/src/identity.ts +131 -0
- package/packages/narrative/src/index.ts +11 -0
- package/packages/narrative/src/manifest.ts +30 -0
- package/packages/narrative/src/schema.ts +89 -0
- package/packages/narrative/src/types.ts +141 -0
- package/packages/package-loader-node/README.md +23 -0
- package/packages/package-loader-node/package.json +15 -0
- package/packages/package-loader-node/src/contribution.ts +97 -0
- package/packages/package-loader-node/src/distribution-resolution.ts +146 -0
- package/packages/package-loader-node/src/index.ts +27 -0
- package/packages/package-loader-node/src/loader.ts +301 -0
- package/packages/package-loader-node/src/location.ts +279 -0
- package/packages/package-loader-node/src/types.ts +60 -0
- package/packages/program-space/README.md +20 -0
- package/packages/program-space/package.json +17 -0
- package/packages/program-space/src/activation.ts +19 -0
- package/packages/program-space/src/index.ts +107 -0
- package/packages/program-space/src/surface.ts +55 -0
- package/packages/protocol/README.md +11 -0
- package/packages/protocol/package.json +10 -0
- package/packages/protocol/src/build-id.ts +52 -0
- package/packages/protocol/src/build.ts +265 -0
- package/packages/protocol/src/canonical.ts +37 -0
- package/packages/protocol/src/error.ts +11 -0
- package/packages/protocol/src/identity.ts +59 -0
- package/packages/protocol/src/index.ts +9 -0
- package/packages/protocol/src/module.ts +67 -0
- package/packages/protocol/src/value.ts +88 -0
- package/packages/provider-hyperframes-aws-lambda/README.md +30 -0
- package/packages/provider-hyperframes-aws-lambda/package.json +30 -0
- package/packages/provider-hyperframes-aws-lambda/src/activation.ts +97 -0
- package/packages/provider-hyperframes-aws-lambda/src/client.ts +114 -0
- package/packages/provider-hyperframes-aws-lambda/src/index.ts +21 -0
- package/packages/provider-hyperframes-aws-lambda/src/provider.ts +522 -0
- package/packages/provider-hyperframes-local/README.md +129 -0
- package/packages/provider-hyperframes-local/package.json +34 -0
- package/packages/provider-hyperframes-local/src/activation.ts +107 -0
- package/packages/provider-hyperframes-local/src/capture-process.ts +110 -0
- package/packages/provider-hyperframes-local/src/capture-worker.ts +17 -0
- package/packages/provider-hyperframes-local/src/capture.ts +184 -0
- package/packages/provider-hyperframes-local/src/index.ts +10 -0
- package/packages/provider-hyperframes-local/src/options.ts +19 -0
- package/packages/provider-hyperframes-local/src/output.ts +73 -0
- package/packages/provider-hyperframes-local/src/process.ts +83 -0
- package/packages/provider-hyperframes-local/src/program.ts +58 -0
- package/packages/provider-hyperframes-local/src/provider.ts +62 -0
- package/packages/provider-hyperframes-local/src/render.ts +114 -0
- package/packages/provider-hyperframes-local/src/sampling.ts +89 -0
- package/packages/provider-hypihub/README.md +143 -0
- package/packages/provider-hypihub/package.json +26 -0
- package/packages/provider-hypihub/src/activation.ts +91 -0
- package/packages/provider-hypihub/src/index.ts +2 -0
- package/packages/provider-hypihub/src/mapping.ts +145 -0
- package/packages/provider-hypihub/src/oauth.ts +113 -0
- package/packages/provider-hypihub/src/provider.ts +566 -0
- package/packages/provider-hypihub/src/routes.ts +134 -0
- package/packages/provider-hypihub/src/upload.ts +402 -0
- package/packages/provider-image-opencv-local/README.md +16 -0
- package/packages/provider-image-opencv-local/package.json +27 -0
- package/packages/provider-image-opencv-local/runtime/raster_execute.py +299 -0
- package/packages/provider-image-opencv-local/src/activation.ts +61 -0
- package/packages/provider-image-opencv-local/src/deployment.ts +68 -0
- package/packages/provider-image-opencv-local/src/index.ts +2 -0
- package/packages/provider-image-opencv-local/src/program.ts +60 -0
- package/packages/provider-image-opencv-local/src/provider.ts +155 -0
- package/packages/provider-kie/README.md +134 -0
- package/packages/provider-kie/package.json +43 -0
- package/packages/provider-kie/src/activation.ts +71 -0
- package/packages/provider-kie/src/index.ts +10 -0
- package/packages/provider-kie/src/mapping.ts +182 -0
- package/packages/provider-kie/src/provider.ts +657 -0
- package/packages/provider-kie/src/routes.ts +150 -0
- package/packages/provider-media-local/README.md +58 -0
- package/packages/provider-media-local/package.json +28 -0
- package/packages/provider-media-local/src/activation.ts +65 -0
- package/packages/provider-media-local/src/index.ts +2 -0
- package/packages/provider-media-local/src/program.ts +19 -0
- package/packages/provider-media-local/src/provider.ts +150 -0
- package/packages/provider-whisperx-local/README.md +44 -0
- package/packages/provider-whisperx-local/package.json +27 -0
- package/packages/provider-whisperx-local/src/activation.ts +93 -0
- package/packages/provider-whisperx-local/src/index.ts +5 -0
- package/packages/provider-whisperx-local/src/program.ts +157 -0
- package/packages/provider-whisperx-local/src/provider.ts +191 -0
- package/packages/provider-xiaomi-mimo/README.md +32 -0
- package/packages/provider-xiaomi-mimo/package.json +24 -0
- package/packages/provider-xiaomi-mimo/src/activation.ts +57 -0
- package/packages/provider-xiaomi-mimo/src/index.ts +5 -0
- package/packages/provider-xiaomi-mimo/src/provider.ts +214 -0
- package/packages/ranking/README.md +67 -0
- package/packages/ranking/package.json +33 -0
- package/packages/ranking/preview/Column.svg +29 -0
- package/packages/ranking/preview/TierBoard.png +0 -0
- package/packages/ranking/preview/TierBoard.svg +36 -0
- package/packages/ranking/preview/TopThree.png +0 -0
- package/packages/ranking/src/activation.ts +38 -0
- package/packages/ranking/src/component.ts +271 -0
- package/packages/ranking/src/fragment.ts +206 -0
- package/packages/ranking/src/index.ts +26 -0
- package/packages/ranking/src/manifest.ts +807 -0
- package/packages/ranking/src/render.ts +698 -0
- package/packages/ranking/src/schedule.ts +895 -0
- package/packages/ranking/src/style.ts +272 -0
- package/packages/ranking/src/surface.ts +322 -0
- package/packages/ranking/src/tier.ts +176 -0
- package/packages/ranking/src/types.ts +277 -0
- package/packages/ranking-studio/README.md +3 -0
- package/packages/ranking-studio/package.json +14 -0
- package/packages/ranking-studio/src/activation.ts +7 -0
- package/packages/ranking-studio/src/index.ts +255 -0
- package/packages/raster/README.md +7 -0
- package/packages/raster/package.json +14 -0
- package/packages/raster/src/activation.ts +7 -0
- package/packages/raster/src/index.ts +7 -0
- package/packages/raster/src/manifest.ts +14 -0
- package/packages/raster/src/program.ts +128 -0
- package/packages/raster/src/schema.ts +53 -0
- package/packages/raster/src/types.ts +61 -0
- package/packages/render-hyperframes/README.md +58 -0
- package/packages/render-hyperframes/package.json +33 -0
- package/packages/render-hyperframes/src/activation.ts +18 -0
- package/packages/render-hyperframes/src/component.ts +37 -0
- package/packages/render-hyperframes/src/fragment.ts +73 -0
- package/packages/render-hyperframes/src/index.ts +6 -0
- package/packages/render-hyperframes/src/manifest.ts +100 -0
- package/packages/render-hyperframes/src/product.ts +29 -0
- package/packages/render-hyperframes/src/surface.ts +65 -0
- package/packages/resource-store-fs/README.md +13 -0
- package/packages/resource-store-fs/package.json +14 -0
- package/packages/resource-store-fs/src/index.ts +2 -0
- package/packages/resource-store-fs/src/store.ts +154 -0
- package/packages/resource-store-s3/README.md +15 -0
- package/packages/resource-store-s3/package.json +15 -0
- package/packages/resource-store-s3/src/client.ts +138 -0
- package/packages/resource-store-s3/src/index.ts +10 -0
- package/packages/resource-store-s3/src/store.ts +258 -0
- package/packages/run/README.md +23 -0
- package/packages/run/package.json +16 -0
- package/packages/run/src/candidate.ts +33 -0
- package/packages/run/src/facet.ts +59 -0
- package/packages/run/src/frontend-facet.ts +23 -0
- package/packages/run/src/frontend.ts +62 -0
- package/packages/run/src/graph.ts +65 -0
- package/packages/run/src/index.ts +33 -0
- package/packages/run/src/registry.ts +24 -0
- package/packages/run/src/resolve.ts +213 -0
- package/packages/run/src/types.ts +147 -0
- package/packages/run-markup/README.md +60 -0
- package/packages/run-markup/package.json +22 -0
- package/packages/run-markup/src/activation.ts +10 -0
- package/packages/run-markup/src/frontend.ts +16 -0
- package/packages/run-markup/src/index.ts +5 -0
- package/packages/run-markup/src/syntax.ts +304 -0
- package/packages/runtime/README.md +39 -0
- package/packages/runtime/package.json +15 -0
- package/packages/runtime/src/capacity.ts +51 -0
- package/packages/runtime/src/catalog.ts +30 -0
- package/packages/runtime/src/credentials.ts +124 -0
- package/packages/runtime/src/environment.ts +6 -0
- package/packages/runtime/src/execution.ts +125 -0
- package/packages/runtime/src/index.ts +24 -0
- package/packages/runtime/src/operations.ts +99 -0
- package/packages/runtime/src/scheduler.ts +281 -0
- package/packages/runtime/src/submission.ts +24 -0
- package/packages/runtime/src/types.ts +157 -0
- package/packages/runtime-host-node/README.md +25 -0
- package/packages/runtime-host-node/package.json +19 -0
- package/packages/runtime-host-node/src/index.ts +421 -0
- package/packages/runtime-host-node/src/packages.ts +158 -0
- package/packages/runtime-kit/README.md +42 -0
- package/packages/runtime-kit/package.json +16 -0
- package/packages/runtime-kit/src/index.ts +307 -0
- package/packages/runtime-kit/src/request-deadline.ts +17 -0
- package/packages/runtime-local/README.md +119 -0
- package/packages/runtime-local/package.json +33 -0
- package/packages/runtime-local/src/actions.ts +20 -0
- package/packages/runtime-local/src/config.ts +1229 -0
- package/packages/runtime-local/src/control.ts +120 -0
- package/packages/runtime-local/src/credentials.ts +61 -0
- package/packages/runtime-local/src/host.ts +174 -0
- package/packages/runtime-local/src/index.ts +36 -0
- package/packages/runtime-local/src/process-control.ts +59 -0
- package/packages/runtime-local/src/process-logs.ts +33 -0
- package/packages/runtime-local/src/programs.ts +441 -0
- package/packages/runtime-local/src/result-writer.ts +246 -0
- package/packages/runtime-local/src/runtime.ts +342 -0
- package/packages/runtime-local/src/types.ts +100 -0
- package/packages/runtime-local/src/worker-process.ts +343 -0
- package/packages/runtime-local/src/worker.ts +449 -0
- package/packages/screen-overlay/README.md +17 -0
- package/packages/screen-overlay/package.json +31 -0
- package/packages/screen-overlay/preview/Track.png +0 -0
- package/packages/screen-overlay/src/activation.ts +15 -0
- package/packages/screen-overlay/src/component.ts +20 -0
- package/packages/screen-overlay/src/fragment.ts +40 -0
- package/packages/screen-overlay/src/index.ts +7 -0
- package/packages/screen-overlay/src/manifest.ts +305 -0
- package/packages/screen-overlay/src/program.ts +321 -0
- package/packages/screen-overlay/src/surface.ts +90 -0
- package/packages/screen-overlay/src/types.ts +69 -0
- package/packages/screen-overlay-studio/README.md +3 -0
- package/packages/screen-overlay-studio/package.json +14 -0
- package/packages/screen-overlay-studio/src/activation.ts +7 -0
- package/packages/screen-overlay-studio/src/index.ts +80 -0
- package/packages/script/README.md +137 -0
- package/packages/script/package.json +22 -0
- package/packages/script/src/activation.ts +20 -0
- package/packages/script/src/edit.ts +174 -0
- package/packages/script/src/error.ts +13 -0
- package/packages/script/src/format.ts +83 -0
- package/packages/script/src/index.ts +20 -0
- package/packages/script/src/lexical.ts +133 -0
- package/packages/script/src/manifest.ts +95 -0
- package/packages/script/src/narrative.ts +232 -0
- package/packages/script/src/parser.ts +850 -0
- package/packages/script/src/surface.ts +132 -0
- package/packages/script/src/types.ts +125 -0
- package/packages/script-studio/package.json +13 -0
- package/packages/script-studio/src/activation.ts +8 -0
- package/packages/script-studio/src/index.ts +61 -0
- package/packages/seedance/README.md +19 -0
- package/packages/seedance/package.json +22 -0
- package/packages/seedance/src/activation.ts +38 -0
- package/packages/seedance/src/fragment.ts +46 -0
- package/packages/seedance/src/index.ts +329 -0
- package/packages/seedance/src/surface.ts +355 -0
- package/packages/seedance-kits/README.md +153 -0
- package/packages/seedance-kits/kits/broll-v1.svs +52 -0
- package/packages/seedance-kits/kits/call-v1.svs +55 -0
- package/packages/seedance-kits/kits/camera-reference-v1.svs +9 -0
- package/packages/seedance-kits/kits/motion-reference-v1.svs +9 -0
- package/packages/seedance-kits/kits/podcast-v1.svs +55 -0
- package/packages/seedance-kits/kits/speaker-v1.svs +136 -0
- package/packages/seedance-kits/kits/street-interview-v1.svs +49 -0
- package/packages/seedance-kits/package.json +24 -0
- package/packages/seedream/README.md +21 -0
- package/packages/seedream/package.json +21 -0
- package/packages/seedream/src/activation.ts +12 -0
- package/packages/seedream/src/index.ts +162 -0
- package/packages/seedream/src/surface.ts +84 -0
- package/packages/semantic-take-adjust/package.json +21 -0
- package/packages/semantic-take-adjust/src/activation.ts +22 -0
- package/packages/semantic-take-adjust/src/component.ts +31 -0
- package/packages/semantic-take-adjust/src/fragment.ts +24 -0
- package/packages/semantic-take-adjust/src/index.ts +12 -0
- package/packages/semantic-take-adjust/src/manifest.ts +57 -0
- package/packages/semantic-take-adjust/src/program.ts +49 -0
- package/packages/semantic-take-adjust/src/surface.ts +96 -0
- package/packages/semantic-take-adjust/src/types.ts +9 -0
- package/packages/semantic-track/README.md +21 -0
- package/packages/semantic-track/package.json +22 -0
- package/packages/semantic-track/src/activation.ts +8 -0
- package/packages/semantic-track/src/component.ts +24 -0
- package/packages/semantic-track/src/identity.ts +58 -0
- package/packages/semantic-track/src/index.ts +6 -0
- package/packages/semantic-track/src/location.ts +81 -0
- package/packages/semantic-track/src/manifest.ts +38 -0
- package/packages/semantic-track/src/projection.ts +71 -0
- package/packages/semantic-track/src/types.ts +26 -0
- package/packages/source/README.md +13 -0
- package/packages/source/package.json +13 -0
- package/packages/source/src/header.ts +80 -0
- package/packages/source/src/index.ts +17 -0
- package/packages/source/src/unit.ts +38 -0
- package/packages/spatial/README.md +77 -0
- package/packages/spatial/package.json +24 -0
- package/packages/spatial/src/activation.ts +43 -0
- package/packages/spatial/src/author.ts +59 -0
- package/packages/spatial/src/component.ts +45 -0
- package/packages/spatial/src/fragment.ts +36 -0
- package/packages/spatial/src/geometry.ts +238 -0
- package/packages/spatial/src/index.ts +37 -0
- package/packages/spatial/src/manifest.ts +341 -0
- package/packages/spatial/src/region-timeline.ts +69 -0
- package/packages/spatial/src/schema.ts +47 -0
- package/packages/spatial/src/surface.ts +319 -0
- package/packages/spatial/src/types.ts +101 -0
- package/packages/speech/README.md +16 -0
- package/packages/speech/package.json +19 -0
- package/packages/speech/src/activation.ts +7 -0
- package/packages/speech/src/component.ts +43 -0
- package/packages/speech/src/identity.ts +73 -0
- package/packages/speech/src/index.ts +6 -0
- package/packages/speech/src/manifest.ts +30 -0
- package/packages/speech/src/materialize.ts +103 -0
- package/packages/speech/src/schema.ts +42 -0
- package/packages/speech/src/types.ts +54 -0
- package/packages/speech-alignment/README.md +29 -0
- package/packages/speech-alignment/package.json +25 -0
- package/packages/speech-alignment/src/activation.ts +8 -0
- package/packages/speech-alignment/src/align.ts +235 -0
- package/packages/speech-alignment/src/component.ts +37 -0
- package/packages/speech-alignment/src/error.ts +9 -0
- package/packages/speech-alignment/src/index.ts +7 -0
- package/packages/speech-alignment/src/local.ts +64 -0
- package/packages/speech-alignment/src/locate.ts +473 -0
- package/packages/speech-alignment/src/manifest.ts +37 -0
- package/packages/speech-alignment/src/normalize.ts +79 -0
- package/packages/speech-alignment/src/types.ts +30 -0
- package/packages/speech-evidence/README.md +3 -0
- package/packages/speech-evidence/package.json +16 -0
- package/packages/speech-evidence/src/activation.ts +3 -0
- package/packages/speech-evidence/src/index.ts +102 -0
- package/packages/speech-track/README.md +51 -0
- package/packages/speech-track/package.json +28 -0
- package/packages/speech-track/preview/Track.png +0 -0
- package/packages/speech-track/src/activation.ts +19 -0
- package/packages/speech-track/src/component.ts +45 -0
- package/packages/speech-track/src/fragment.ts +74 -0
- package/packages/speech-track/src/index.ts +7 -0
- package/packages/speech-track/src/manifest.ts +73 -0
- package/packages/speech-track/src/program.ts +64 -0
- package/packages/speech-track/src/surface.ts +35 -0
- package/packages/speech-track/src/types.ts +6 -0
- package/packages/speech-track-studio/README.md +3 -0
- package/packages/speech-track-studio/package.json +14 -0
- package/packages/speech-track-studio/src/activation.ts +7 -0
- package/packages/speech-track-studio/src/index.ts +40 -0
- package/packages/store-sqlite/README.md +14 -0
- package/packages/store-sqlite/package.json +18 -0
- package/packages/store-sqlite/src/index.ts +2 -0
- package/packages/store-sqlite/src/store.ts +1101 -0
- package/packages/studio/README.md +125 -0
- package/packages/studio/index.html +10 -0
- package/packages/studio/package.json +50 -0
- package/packages/studio/src/build-library.ts +281 -0
- package/packages/studio/src/companion-assembly.ts +39 -0
- package/packages/studio/src/compile.ts +166 -0
- package/packages/studio/src/domain.ts +139 -0
- package/packages/studio/src/execute.ts +57 -0
- package/packages/studio/src/fallback-companions.ts +98 -0
- package/packages/studio/src/observe.ts +202 -0
- package/packages/studio/src/parameter-values.ts +81 -0
- package/packages/studio/src/parameters.ts +550 -0
- package/packages/studio/src/preview/render.ts +51 -0
- package/packages/studio/src/preview/runtime-shim.ts +184 -0
- package/packages/studio/src/programme.ts +276 -0
- package/packages/studio/src/run.ts +85 -0
- package/packages/studio/src/server.ts +725 -0
- package/packages/studio/src/session.ts +111 -0
- package/packages/studio/src/shared.ts +315 -0
- package/packages/studio/src/snapshot.ts +454 -0
- package/packages/studio/src/source-transaction.ts +57 -0
- package/packages/studio/src/storyboard.ts +133 -0
- package/packages/studio/src/studio-preflight.ts +198 -0
- package/packages/studio/src/studio-registry.ts +406 -0
- package/packages/studio/src/studio-trace.ts +136 -0
- package/packages/studio/src/style.css +1525 -0
- package/packages/studio/src/surface-preview.ts +35 -0
- package/packages/studio/src/temporal-graph.ts +227 -0
- package/packages/studio/src/ui/code.ts +450 -0
- package/packages/studio/src/ui/icons.ts +51 -0
- package/packages/studio/src/ui/library.ts +378 -0
- package/packages/studio/src/ui/main.ts +1001 -0
- package/packages/studio/src/ui/markers.ts +152 -0
- package/packages/studio/src/ui/material-preview.ts +176 -0
- package/packages/studio/src/ui/overlay.ts +144 -0
- package/packages/studio/src/ui/resize.ts +74 -0
- package/packages/studio/src/ui/selection.ts +178 -0
- package/packages/studio/src/ui/stage.ts +231 -0
- package/packages/studio/src/ui/syntax.ts +195 -0
- package/packages/studio/src/ui/timeline.ts +1041 -0
- package/packages/studio/src/ui/writeback.ts +10 -0
- package/packages/studio/src/ui/zoom.ts +129 -0
- package/packages/studio/start.ts +143 -0
- package/packages/studio-adapter/README.md +186 -0
- package/packages/studio-adapter/package.json +14 -0
- package/packages/studio-adapter/src/index.ts +850 -0
- package/packages/svs/README.md +37 -0
- package/packages/svs/package.json +21 -0
- package/packages/svs/src/activation.ts +11 -0
- package/packages/svs/src/format.ts +16 -0
- package/packages/svs/src/frontend.ts +33 -0
- package/packages/svs/src/index.ts +5 -0
- package/packages/svs/src/manifest.ts +17 -0
- package/packages/svs/src/parser.ts +279 -0
- package/packages/svs/src/types.ts +26 -0
- package/packages/temporal/README.md +31 -0
- package/packages/temporal/package.json +20 -0
- package/packages/temporal/src/activation.ts +9 -0
- package/packages/temporal/src/component.ts +68 -0
- package/packages/temporal/src/index.ts +110 -0
- package/packages/temporal/src/location.ts +67 -0
- package/packages/temporal/src/projection.ts +280 -0
- package/packages/temporal/src/rational.ts +80 -0
- package/packages/temporal/src/sample.ts +43 -0
- package/packages/temporal/src/schedule.ts +52 -0
- package/packages/temporal/src/types.ts +124 -0
- package/packages/temporal-markup/README.md +75 -0
- package/packages/temporal-markup/package.json +18 -0
- package/packages/temporal-markup/src/index.ts +537 -0
- package/packages/temporal-markup/src/space.ts +59 -0
- package/packages/text/README.md +59 -0
- package/packages/text/package.json +21 -0
- package/packages/text/src/activation.ts +33 -0
- package/packages/text/src/component.ts +72 -0
- package/packages/text/src/fragment.ts +57 -0
- package/packages/text/src/frontend.ts +39 -0
- package/packages/text/src/index.ts +27 -0
- package/packages/text/src/manifest.ts +170 -0
- package/packages/text/src/program.ts +418 -0
- package/packages/text/src/surface.ts +212 -0
- package/packages/text/src/svs.ts +189 -0
- package/packages/text/src/types.ts +82 -0
- package/packages/transport-aws-lambda/README.md +20 -0
- package/packages/transport-aws-lambda/package.json +14 -0
- package/packages/transport-aws-lambda/src/index.ts +131 -0
- package/packages/typography-track/README.md +50 -0
- package/packages/typography-track/package.json +34 -0
- package/packages/typography-track/preview/Mask.png +0 -0
- package/packages/typography-track/preview/Track.png +0 -0
- package/packages/typography-track/src/activation.ts +36 -0
- package/packages/typography-track/src/component.ts +93 -0
- package/packages/typography-track/src/fragment.ts +30 -0
- package/packages/typography-track/src/index.ts +11 -0
- package/packages/typography-track/src/manifest.ts +556 -0
- package/packages/typography-track/src/program.ts +622 -0
- package/packages/typography-track/src/surface.ts +842 -0
- package/packages/typography-track/src/types.ts +109 -0
- package/packages/typography-track-studio/README.md +3 -0
- package/packages/typography-track-studio/package.json +14 -0
- package/packages/typography-track-studio/src/activation.ts +7 -0
- package/packages/typography-track-studio/src/index.ts +116 -0
- package/packages/validation/README.md +11 -0
- package/packages/validation/package.json +15 -0
- package/packages/validation/src/index.ts +100 -0
- package/packages/video-cli/README.md +181 -0
- package/packages/video-cli/package.json +37 -0
- package/packages/video-cli/src/capture.ts +174 -0
- package/packages/video-cli/src/cli.ts +109 -0
- package/packages/video-cli/src/compiler.ts +32 -0
- package/packages/video-cli/src/creation.ts +449 -0
- package/packages/video-cli/src/distribution.ts +88 -0
- package/packages/video-cli/src/index.ts +50 -0
- package/packages/video-cli/src/media.ts +701 -0
- package/packages/video-cli/src/package-selection.ts +34 -0
- package/packages/video-cli/src/process.ts +71 -0
- package/packages/video-cli/src/studio-distribution.ts +19 -0
- package/packages/video-cli/src/transcript.ts +71 -0
- package/packages/video-cli/src/vocabulary.ts +386 -0
- package/packages/visual-ir/README.md +36 -0
- package/packages/visual-ir/package.json +16 -0
- package/packages/visual-ir/src/activation.ts +3 -0
- package/packages/visual-ir/src/index.ts +7 -0
- package/packages/visual-ir/src/style.ts +222 -0
- package/packages/volcengine-matting/README.md +89 -0
- package/packages/volcengine-matting/package.json +16 -0
- package/packages/volcengine-matting/src/activation.ts +13 -0
- package/packages/volcengine-matting/src/index.ts +45 -0
- package/packages/volcengine-matting/src/surface.ts +48 -0
- package/packages/whisperx/README.md +34 -0
- package/packages/whisperx/package.json +28 -0
- package/packages/whisperx/src/activation.ts +18 -0
- package/packages/whisperx/src/component.ts +64 -0
- package/packages/whisperx/src/evidence.ts +69 -0
- package/packages/whisperx/src/fragment.ts +76 -0
- package/packages/whisperx/src/index.ts +14 -0
- package/packages/whisperx/src/manifest.ts +92 -0
- package/packages/whisperx/src/surface.ts +90 -0
- package/packages/whisperx/src/transcript.ts +97 -0
- package/packages/whisperx/src/types.ts +9 -0
- package/packages/workspace/README.md +4 -0
- package/packages/workspace/package.json +14 -0
- package/packages/workspace/src/index.ts +38 -0
- package/packages/workspace-fs-node/README.md +13 -0
- package/packages/workspace-fs-node/package.json +15 -0
- package/packages/workspace-fs-node/src/index.ts +6 -0
- package/packages/workspace-fs-node/src/workspace.ts +226 -0
- package/packages/yt-dlp/README.md +31 -0
- package/packages/yt-dlp/package.json +10 -0
- package/packages/yt-dlp/src/download.ts +104 -0
- package/packages/yt-dlp/src/index.ts +1 -0
- package/services/image-opencv/README.md +33 -0
- package/services/image-opencv/package.json +14 -0
- package/services/image-opencv/pyproject.toml +13 -0
- package/services/image-opencv/uv.lock +56 -0
- package/services/whisperx/README.md +82 -0
- package/services/whisperx/package.json +15 -0
- package/services/whisperx/pyproject.toml +26 -0
- package/services/whisperx/src/hypit_whisperx_service/__init__.py +6 -0
- package/services/whisperx/src/hypit_whisperx_service/__main__.py +29 -0
- package/services/whisperx/src/hypit_whisperx_service/application.py +88 -0
- package/services/whisperx/src/hypit_whisperx_service/audio.py +66 -0
- package/services/whisperx/src/hypit_whisperx_service/check.py +35 -0
- package/services/whisperx/src/hypit_whisperx_service/config.py +81 -0
- package/services/whisperx/src/hypit_whisperx_service/engine.py +173 -0
- package/services/whisperx/src/hypit_whisperx_service/prepare.py +19 -0
- package/services/whisperx/src/hypit_whisperx_service/resources.py +41 -0
- package/services/whisperx/src/hypit_whisperx_service/server.py +101 -0
- package/services/whisperx/uv.lock +3381 -0
- package/services/yt-dlp/README.md +19 -0
- package/services/yt-dlp/package.json +14 -0
- package/services/yt-dlp/pyproject.toml +13 -0
- package/services/yt-dlp/uv.lock +23 -0
- package/index.js +0 -1
|
@@ -0,0 +1,701 @@
|
|
|
1
|
+
import { mkdir, mkdtemp, readFile, rename, rm, stat } from "node:fs/promises";
|
|
2
|
+
import { tmpdir } from "node:os";
|
|
3
|
+
import { dirname, extname, join, resolve } from "node:path";
|
|
4
|
+
|
|
5
|
+
import type { CliIo } from "@hypit/cli";
|
|
6
|
+
import { downloadVideo, isVideoUrl } from "@hypit/yt-dlp";
|
|
7
|
+
import sharp from "sharp";
|
|
8
|
+
|
|
9
|
+
import { runProcess, runProcessOutput, runProcessWithInput } from "./process.js";
|
|
10
|
+
import { phraseRanges, readTranscript, wordsAt } from "./transcript.js";
|
|
11
|
+
import type { FrameWords, TranscriptWord } from "./transcript.js";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Local views of media at chosen times and scales. Transcript annotations use the same seconds as
|
|
15
|
+
* the input media. These commands expose evidence; editorial interpretation belongs to the author.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
export const mediaCommands = ["probe", "cut", "frames", "tile", "tiles", "boundaries", "fetch"] as const;
|
|
19
|
+
export type MediaCommand = typeof mediaCommands[number];
|
|
20
|
+
|
|
21
|
+
function assert(condition: unknown, message: string): asserts condition {
|
|
22
|
+
if (!condition) throw new Error(message);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function isMediaCommand(value: string | undefined): value is MediaCommand {
|
|
26
|
+
return (mediaCommands as readonly string[]).includes(value ?? "");
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function round(value: number): number { return Number(value.toFixed(3)); }
|
|
30
|
+
function clamp(value: number, low: number, high: number): number { return Math.max(low, Math.min(high, value)); }
|
|
31
|
+
|
|
32
|
+
// ---------------------------------------------------------------------------------------------------
|
|
33
|
+
// Arguments
|
|
34
|
+
|
|
35
|
+
type Parsed = {
|
|
36
|
+
readonly positionals: readonly string[];
|
|
37
|
+
readonly options: ReadonlyMap<string, string>;
|
|
38
|
+
readonly flags: ReadonlySet<string>;
|
|
39
|
+
readonly json: boolean;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
function parseArguments(argv: readonly string[], allowed: readonly string[], allowedFlags: readonly string[] = []): Parsed {
|
|
43
|
+
const positionals: string[] = [];
|
|
44
|
+
const options = new Map<string, string>();
|
|
45
|
+
const flags = new Set<string>();
|
|
46
|
+
let json = false;
|
|
47
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
48
|
+
const item = argv[index]!;
|
|
49
|
+
if (item === "--json") { json = true; continue; }
|
|
50
|
+
if (item === "--debug" || item === "--verbose" || item === "--no-color") continue;
|
|
51
|
+
if (item === "--color") { index += 1; continue; }
|
|
52
|
+
if (!item.startsWith("--")) { positionals.push(item); continue; }
|
|
53
|
+
if (allowedFlags.includes(item)) {
|
|
54
|
+
if (flags.has(item)) throw new Error(`${item} cannot be repeated`);
|
|
55
|
+
flags.add(item);
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
if (!allowed.includes(item)) throw new Error(`unknown option ${item}`);
|
|
59
|
+
if (options.has(item)) throw new Error(`${item} cannot be repeated`);
|
|
60
|
+
const value = argv[index + 1];
|
|
61
|
+
if (value === undefined || (value.startsWith("--") && value.length > 2)) throw new Error(`${item} requires a value`);
|
|
62
|
+
options.set(item, value);
|
|
63
|
+
index += 1;
|
|
64
|
+
}
|
|
65
|
+
return { positionals, options, flags, json };
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function required(parsed: Parsed, option: string, hint: string): string {
|
|
69
|
+
const value = parsed.options.get(option);
|
|
70
|
+
if (value === undefined) throw new Error(`${option} is required: ${hint}`);
|
|
71
|
+
return value;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function secondsOption(parsed: Parsed, option: string, fallback?: number): number {
|
|
75
|
+
const raw = parsed.options.get(option);
|
|
76
|
+
if (raw === undefined) {
|
|
77
|
+
if (fallback !== undefined) return fallback;
|
|
78
|
+
throw new Error(`${option} is required: a time in seconds`);
|
|
79
|
+
}
|
|
80
|
+
const value = Number(raw);
|
|
81
|
+
assert(Number.isFinite(value) && value >= 0, `${option} must be a non-negative number of seconds, got ${raw}`);
|
|
82
|
+
return value;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function integerOption(parsed: Parsed, option: string, fallback: number, low: number): number {
|
|
86
|
+
const raw = parsed.options.get(option);
|
|
87
|
+
if (raw === undefined) return fallback;
|
|
88
|
+
const value = Number(raw);
|
|
89
|
+
assert(Number.isSafeInteger(value) && value >= low, `${option} must be a whole number of at least ${low}, got ${raw}`);
|
|
90
|
+
return value;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function numberOption(parsed: Parsed, option: string, fallback: number, low: number, high: number): number {
|
|
94
|
+
const raw = parsed.options.get(option);
|
|
95
|
+
if (raw === undefined) return fallback;
|
|
96
|
+
const value = Number(raw);
|
|
97
|
+
assert(Number.isFinite(value) && value >= low && value <= high, `${option} must be between ${low} and ${high}, got ${raw}`);
|
|
98
|
+
return value;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function secondsList(raw: string, option: string, minimum: number): number[] {
|
|
102
|
+
const parts = raw.split(",").map((item) => item.trim());
|
|
103
|
+
assert(parts.length >= minimum && parts.every((item) => item.length > 0), `${option} must list at least ${minimum} seconds, got ${raw}`);
|
|
104
|
+
const values = parts.map(Number);
|
|
105
|
+
assert(values.every((value) => Number.isFinite(value) && value >= 0), `${option} must list non-negative seconds, got ${raw}`);
|
|
106
|
+
return values;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
async function sourceFile(parsed: Parsed, cwd: string): Promise<string> {
|
|
110
|
+
const [source] = parsed.positionals;
|
|
111
|
+
assert(source !== undefined, "name the media file first");
|
|
112
|
+
assert(parsed.positionals.length === 1, "media commands take exactly one media file");
|
|
113
|
+
const path = resolve(cwd, source);
|
|
114
|
+
assert(await stat(path).then((item) => item.isFile(), () => false), `cannot read ${path}`);
|
|
115
|
+
return path;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
async function destination(parsed: Parsed, cwd: string, hint: string): Promise<string> {
|
|
119
|
+
const to = resolve(cwd, required(parsed, "--to", hint));
|
|
120
|
+
assert(!(await stat(to).then(() => true, () => false)), `Destination ${to} already exists`);
|
|
121
|
+
await mkdir(dirname(to), { recursive: true });
|
|
122
|
+
return to;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
async function destinationDirectory(parsed: Parsed, cwd: string, hint: string): Promise<string> {
|
|
126
|
+
const to = resolve(cwd, required(parsed, "--to", hint));
|
|
127
|
+
assert(!(await stat(to).then(() => true, () => false)), `Destination ${to} already exists`);
|
|
128
|
+
await mkdir(dirname(to), { recursive: true });
|
|
129
|
+
return to;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// ---------------------------------------------------------------------------------------------------
|
|
133
|
+
// ffmpeg
|
|
134
|
+
|
|
135
|
+
export type MediaProbe = {
|
|
136
|
+
readonly duration: number;
|
|
137
|
+
readonly width: number;
|
|
138
|
+
readonly height: number;
|
|
139
|
+
readonly frameRate: number;
|
|
140
|
+
readonly hasAudio: boolean;
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
export async function probeMedia(path: string): Promise<MediaProbe> {
|
|
144
|
+
const raw = await runProcess("ffprobe", [
|
|
145
|
+
"-v", "error", "-show_entries", "format=duration:stream=codec_type,width,height,r_frame_rate", "-of", "json", path,
|
|
146
|
+
]);
|
|
147
|
+
const parsed = JSON.parse(raw.toString("utf8")) as {
|
|
148
|
+
format?: { duration?: string };
|
|
149
|
+
streams?: readonly { codec_type?: string; width?: number; height?: number; r_frame_rate?: string }[];
|
|
150
|
+
};
|
|
151
|
+
const video = parsed.streams?.find((item) => item.codec_type === "video");
|
|
152
|
+
const duration = Number(parsed.format?.duration);
|
|
153
|
+
assert(Number.isFinite(duration) && duration > 0, `${path}: duration is unavailable`);
|
|
154
|
+
assert(video?.width !== undefined && video.height !== undefined, `${path}: no video stream`);
|
|
155
|
+
// ffprobe reports the rate as a ratio; a still image reports none.
|
|
156
|
+
const ratio = (video.r_frame_rate ?? "").split("/");
|
|
157
|
+
const rate = Number(ratio[0]) / Number(ratio[1] ?? 1);
|
|
158
|
+
return {
|
|
159
|
+
duration: round(duration),
|
|
160
|
+
width: video.width,
|
|
161
|
+
height: video.height,
|
|
162
|
+
frameRate: Number.isFinite(rate) && rate > 0 ? round(rate) : 0,
|
|
163
|
+
hasAudio: parsed.streams?.some((item) => item.codec_type === "audio") ?? false,
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Open `source` on the frame at `at` seconds.
|
|
169
|
+
*
|
|
170
|
+
* `-ss` after `-i` alone decodes every frame up to the mark; `-ss` before `-i` alone lands on the
|
|
171
|
+
* keyframe before it. Jumping to two seconds early and decoding the short run-up lands on the exact
|
|
172
|
+
* frame: measured on a 1080p source nine minutes in, the same JPEG to the byte, 11.6 s to 0.2 s.
|
|
173
|
+
*/
|
|
174
|
+
const SEEK_RUN_UP = 2;
|
|
175
|
+
function openAt(source: string, at: number): readonly string[] {
|
|
176
|
+
const jump = Math.max(0, at - SEEK_RUN_UP);
|
|
177
|
+
const runUp = at - jump;
|
|
178
|
+
return [...(jump > 0 ? ["-ss", String(round(jump))] : []), "-i", source, ...(runUp > 0 ? ["-ss", String(round(runUp))] : [])];
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// JPEG is a full-range format; web video is routinely full-range YUV and the encoder refuses it
|
|
182
|
+
// unless told which it is writing (`Non full-range YUV is non-standard`).
|
|
183
|
+
const JPEG = ["-pix_fmt", "yuvj420p", "-q:v", "3"] as const;
|
|
184
|
+
|
|
185
|
+
const GLYPHS: Readonly<Record<string, readonly string[]>> = {
|
|
186
|
+
"0": ["11111", "10001", "10011", "10101", "11001", "10001", "11111"],
|
|
187
|
+
"1": ["00100", "01100", "00100", "00100", "00100", "00100", "01110"],
|
|
188
|
+
"2": ["11110", "00001", "00001", "11110", "10000", "10000", "11111"],
|
|
189
|
+
"3": ["11110", "00001", "00001", "01110", "00001", "00001", "11110"],
|
|
190
|
+
"4": ["10010", "10010", "10010", "11111", "00010", "00010", "00010"],
|
|
191
|
+
"5": ["11111", "10000", "10000", "11110", "00001", "00001", "11110"],
|
|
192
|
+
"6": ["01111", "10000", "10000", "11110", "10001", "10001", "01110"],
|
|
193
|
+
"7": ["11111", "00001", "00010", "00100", "01000", "01000", "01000"],
|
|
194
|
+
"8": ["01110", "10001", "10001", "01110", "10001", "10001", "01110"],
|
|
195
|
+
"9": ["01110", "10001", "10001", "01111", "00001", "00001", "11110"],
|
|
196
|
+
":": ["00000", "00100", "00100", "00000", "00100", "00100", "00000"],
|
|
197
|
+
".": ["00000", "00000", "00000", "00000", "00000", "00100", "00100"],
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
function timecode(seconds: number): string {
|
|
201
|
+
const milliseconds = Math.max(0, Math.round(seconds * 1_000));
|
|
202
|
+
const hours = Math.floor(milliseconds / 3_600_000);
|
|
203
|
+
const minutes = Math.floor(milliseconds / 60_000) % 60;
|
|
204
|
+
const wholeSeconds = Math.floor(milliseconds / 1_000) % 60;
|
|
205
|
+
const remainder = milliseconds % 1_000;
|
|
206
|
+
return `${String(hours).padStart(2, "0")}:${String(minutes).padStart(2, "0")}:${String(wholeSeconds).padStart(2, "0")}.${String(remainder).padStart(3, "0")}`;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
type RasterLabel = {
|
|
210
|
+
readonly width: number;
|
|
211
|
+
readonly height: number;
|
|
212
|
+
readonly bytes: Buffer;
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
/** A tiny built-in numeric face keeps evidence labels available even when ffmpeg lacks drawtext. */
|
|
216
|
+
function rasterLabel(text: string, requestedWidth?: number): RasterLabel {
|
|
217
|
+
const scale = requestedWidth === undefined
|
|
218
|
+
? 3
|
|
219
|
+
: clamp(Math.min(Math.floor((requestedWidth - 8) / (text.length * 6)), Math.floor(requestedWidth / 240) + 1), 1, 3);
|
|
220
|
+
const padding = scale * 2;
|
|
221
|
+
const naturalWidth = padding * 2 + text.length * 6 * scale - scale;
|
|
222
|
+
const width = Math.max(requestedWidth ?? naturalWidth, naturalWidth);
|
|
223
|
+
const rawHeight = padding * 2 + 7 * scale;
|
|
224
|
+
const height = rawHeight + rawHeight % 2;
|
|
225
|
+
const bytes = Buffer.alloc(width * height * 3, 12);
|
|
226
|
+
let left = padding;
|
|
227
|
+
for (const character of text) {
|
|
228
|
+
const glyph = GLYPHS[character];
|
|
229
|
+
assert(glyph !== undefined, `cannot draw time label character ${character}`);
|
|
230
|
+
for (let row = 0; row < glyph.length; row += 1) {
|
|
231
|
+
for (let column = 0; column < glyph[row]!.length; column += 1) {
|
|
232
|
+
if (glyph[row]![column] !== "1") continue;
|
|
233
|
+
for (let y = 0; y < scale; y += 1) {
|
|
234
|
+
for (let x = 0; x < scale; x += 1) {
|
|
235
|
+
const pixel = ((padding + row * scale + y) * width + left + column * scale + x) * 3;
|
|
236
|
+
bytes[pixel] = 245;
|
|
237
|
+
bytes[pixel + 1] = 245;
|
|
238
|
+
bytes[pixel + 2] = 245;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
left += 6 * scale;
|
|
244
|
+
}
|
|
245
|
+
return { width, height, bytes };
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
function rawVideoInput(label: RasterLabel, frameRate: number): readonly string[] {
|
|
249
|
+
return [
|
|
250
|
+
"-f", "rawvideo", "-pixel_format", "rgb24", "-video_size", `${label.width}x${label.height}`,
|
|
251
|
+
"-framerate", String(frameRate), "-i", "pipe:0",
|
|
252
|
+
];
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
export async function cutClip(
|
|
256
|
+
source: string,
|
|
257
|
+
start: number,
|
|
258
|
+
end: number,
|
|
259
|
+
target: string,
|
|
260
|
+
labelInfo?: Pick<MediaProbe, "frameRate">,
|
|
261
|
+
): Promise<void> {
|
|
262
|
+
assert(end > start, `the clip must end after it starts (${start} to ${end})`);
|
|
263
|
+
const seconds = round(end - start);
|
|
264
|
+
const common = ["-c:v", "libx264", "-preset", "veryfast", "-crf", "23", "-c:a", "aac", "-b:a", "96k", "-movflags", "+faststart"];
|
|
265
|
+
if (labelInfo === undefined) {
|
|
266
|
+
await runProcess("ffmpeg", [
|
|
267
|
+
"-hide_banner", "-loglevel", "error", "-y", ...openAt(source, start), "-t", String(seconds), ...common, target,
|
|
268
|
+
]);
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
const temporary = await mkdtemp(join(tmpdir(), "hypit-labeled-clip-"));
|
|
272
|
+
const clean = join(temporary, "clean.mp4");
|
|
273
|
+
try {
|
|
274
|
+
await cutClip(source, start, end, clean);
|
|
275
|
+
const rate = clamp(Math.ceil(labelInfo.frameRate || 10), 1, 30);
|
|
276
|
+
const count = Math.max(1, Math.ceil(seconds * rate));
|
|
277
|
+
const first = rasterLabel(timecode(start));
|
|
278
|
+
function* labels(): Iterable<Uint8Array> {
|
|
279
|
+
yield first.bytes;
|
|
280
|
+
for (let index = 1; index < count; index += 1) yield rasterLabel(timecode(start + index / rate)).bytes;
|
|
281
|
+
}
|
|
282
|
+
await runProcessWithInput("ffmpeg", [
|
|
283
|
+
"-hide_banner", "-loglevel", "error", "-y", "-i", clean, ...rawVideoInput(first, rate),
|
|
284
|
+
"-t", String(seconds), "-filter_complex", "[0:v][1:v]overlay=8:8:eof_action=repeat[v]",
|
|
285
|
+
"-map", "[v]", "-map", "0:a?", ...common, target,
|
|
286
|
+
], labels());
|
|
287
|
+
} finally {
|
|
288
|
+
await rm(temporary, { recursive: true, force: true });
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
export async function cutFrame(source: string, at: number, target: string, labelTime = false): Promise<number> {
|
|
293
|
+
if (!labelTime) {
|
|
294
|
+
const jump = Math.max(0, at - SEEK_RUN_UP);
|
|
295
|
+
const output = await runProcessOutput("ffmpeg", [
|
|
296
|
+
"-hide_banner", "-loglevel", "info", "-y", "-copyts", "-start_at_zero",
|
|
297
|
+
...(jump > 0 ? ["-ss", String(jump)] : []), "-i", source,
|
|
298
|
+
"-vf", `trim=start=${at},showinfo`, "-frames:v", "1", "-fps_mode", "passthrough", ...JPEG, target,
|
|
299
|
+
]);
|
|
300
|
+
const base = /config in time_base:\s*(\d+)\/(\d+)/u.exec(output.stderr);
|
|
301
|
+
const pts = /\bn:\s*0\s+pts:\s*(-?\d+)/u.exec(output.stderr);
|
|
302
|
+
assert(base !== null && pts !== null, `no video frame exists at or after ${at} s`);
|
|
303
|
+
return Number(pts[1]) * Number(base[1]) / Number(base[2]);
|
|
304
|
+
}
|
|
305
|
+
const temporary = await mkdtemp(join(tmpdir(), "hypit-labeled-frame-"));
|
|
306
|
+
const clean = join(temporary, "clean.jpg");
|
|
307
|
+
try {
|
|
308
|
+
const actual = await cutFrame(source, at, clean);
|
|
309
|
+
const label = rasterLabel(timecode(actual));
|
|
310
|
+
await runProcessWithInput("ffmpeg", [
|
|
311
|
+
"-hide_banner", "-loglevel", "error", "-y", "-i", clean, ...rawVideoInput(label, 1),
|
|
312
|
+
"-filter_complex", "[0:v][1:v]overlay=8:8[out]", "-map", "[out]", "-frames:v", "1", ...JPEG, target,
|
|
313
|
+
], label.bytes);
|
|
314
|
+
return actual;
|
|
315
|
+
} finally {
|
|
316
|
+
await rm(temporary, { recursive: true, force: true });
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
const TILE_COLUMNS = 3;
|
|
321
|
+
const TILE_CELL_WIDTH = 480;
|
|
322
|
+
/** A compact overview default. Callers choose denser samples for fast changes. */
|
|
323
|
+
export function tileFrameCount(seconds: number): number { return clamp(Math.round(seconds * 1.5), 4, 9); }
|
|
324
|
+
|
|
325
|
+
export function tileSampleTimes(start: number, end: number, frameCount: number): readonly number[] {
|
|
326
|
+
assert(end > start, `the stretch must end after it starts (${start} to ${end})`);
|
|
327
|
+
assert(Number.isSafeInteger(frameCount) && frameCount >= 2, "a grid needs at least two frames");
|
|
328
|
+
return Array.from({ length: frameCount }, (_, index) => round(start + (index + 0.5) * (end - start) / frameCount));
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
function escapeMarkup(value: string): string {
|
|
332
|
+
return value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">");
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
async function frameLabel(at: number, width: number, words?: FrameWords): Promise<Buffer> {
|
|
336
|
+
const lines = [timecode(at)];
|
|
337
|
+
if (words !== undefined) {
|
|
338
|
+
lines.push(words.active.length === 0 ? "No timed word at this frame" : words.active.map((word) =>
|
|
339
|
+
`<b>${escapeMarkup(word.text)}</b> ${word.start!.toFixed(3)}–${word.end!.toFixed(3)} s`).join("\n"));
|
|
340
|
+
if (words.context.length > 0) lines.push(words.context.map((word) => words.active.includes(word)
|
|
341
|
+
? `<span foreground="#ffdc80"><b>${escapeMarkup(word.text)}</b></span>` : escapeMarkup(word.text)).join(" "));
|
|
342
|
+
}
|
|
343
|
+
const text = await sharp({ text: {
|
|
344
|
+
text: `<span foreground="#f5f5f5">${lines.join("\n")}</span>`,
|
|
345
|
+
font: `sans ${Math.max(12, Math.round(width / 28))}`, width: width - 16, rgba: true, wrap: "word-char",
|
|
346
|
+
} }).png().toBuffer({ resolveWithObject: true });
|
|
347
|
+
return sharp({ create: { width, height: text.info.height + 16, channels: 3, background: "#0c0c0c" } })
|
|
348
|
+
.composite([{ input: text.data, left: 8, top: 8 }]).png().toBuffer();
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
type SampledFrame = { readonly requestedAt: number; readonly at: number; readonly words?: FrameWords };
|
|
352
|
+
|
|
353
|
+
export async function tileFrames(
|
|
354
|
+
source: string,
|
|
355
|
+
times: readonly number[],
|
|
356
|
+
target: string,
|
|
357
|
+
cellWidth: number,
|
|
358
|
+
columns: number,
|
|
359
|
+
words?: readonly TranscriptWord[],
|
|
360
|
+
): Promise<readonly SampledFrame[]> {
|
|
361
|
+
assert(times.length >= 1, "a grid needs at least one frame");
|
|
362
|
+
const temporary = await mkdtemp(join(tmpdir(), "hypit-tile-"));
|
|
363
|
+
try {
|
|
364
|
+
const frames: SampledFrame[] = [];
|
|
365
|
+
const cells: { picture: Buffer; label: Buffer; height: number; labelHeight: number }[] = [];
|
|
366
|
+
for (let index = 0; index < times.length; index += 1) {
|
|
367
|
+
const at = times[index]!;
|
|
368
|
+
const path = join(temporary, `${index}.jpg`);
|
|
369
|
+
const actual = await cutFrame(source, at, path);
|
|
370
|
+
const frameWords = words === undefined ? undefined : wordsAt(words, actual);
|
|
371
|
+
frames.push({ requestedAt: at, at: actual, ...(frameWords === undefined ? {} : { words: frameWords }) });
|
|
372
|
+
const picture = await sharp(path).resize({ width: cellWidth }).png().toBuffer({ resolveWithObject: true });
|
|
373
|
+
const label = await frameLabel(actual, cellWidth, frameWords);
|
|
374
|
+
const labelHeight = (await sharp(label).metadata()).height!;
|
|
375
|
+
cells.push({ picture: picture.data, height: picture.info.height, label, labelHeight });
|
|
376
|
+
}
|
|
377
|
+
const rows = Math.ceil(times.length / columns);
|
|
378
|
+
const pictureHeight = Math.max(...cells.map((cell) => cell.height));
|
|
379
|
+
const rowHeight = pictureHeight + Math.max(...cells.map((cell) => cell.labelHeight));
|
|
380
|
+
await sharp({ create: {
|
|
381
|
+
width: columns * (cellWidth + 8) + 8, height: rows * (rowHeight + 8) + 8,
|
|
382
|
+
channels: 3, background: "#0c0c0c",
|
|
383
|
+
} }).composite(cells.flatMap((cell, index) => {
|
|
384
|
+
const left = 8 + (index % columns) * (cellWidth + 8);
|
|
385
|
+
const top = 8 + Math.floor(index / columns) * (rowHeight + 8);
|
|
386
|
+
return [{ input: cell.picture, left, top }, { input: cell.label, left, top: top + pictureHeight }];
|
|
387
|
+
})).jpeg({ quality: 90 }).toFile(target);
|
|
388
|
+
return frames;
|
|
389
|
+
} finally {
|
|
390
|
+
await rm(temporary, { recursive: true, force: true });
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
/**
|
|
395
|
+
* Adjacent-frame visual change candidates. Scores are mechanical evidence, not editorial shots.
|
|
396
|
+
*/
|
|
397
|
+
const DEFAULT_BOUNDARY_RATE = 12;
|
|
398
|
+
const DEFAULT_BOUNDARY_THRESHOLD = 0.1;
|
|
399
|
+
export type VisualBoundary = { readonly at: number; readonly score: number };
|
|
400
|
+
export async function visualBoundaries(
|
|
401
|
+
source: string,
|
|
402
|
+
sampleRate = DEFAULT_BOUNDARY_RATE,
|
|
403
|
+
threshold = DEFAULT_BOUNDARY_THRESHOLD,
|
|
404
|
+
): Promise<readonly VisualBoundary[]> {
|
|
405
|
+
const bytes = await runProcess("ffmpeg", [
|
|
406
|
+
"-hide_banner", "-loglevel", "error", "-i", source, "-vf", `fps=${sampleRate},scale=32:32,format=rgb24`, "-f", "rawvideo", "-",
|
|
407
|
+
]);
|
|
408
|
+
const stride = 32 * 32 * 3;
|
|
409
|
+
const frames: Uint8Array[] = [];
|
|
410
|
+
for (let index = 0; index + stride <= bytes.byteLength; index += stride) frames.push(bytes.subarray(index, index + stride));
|
|
411
|
+
const candidates: VisualBoundary[] = [];
|
|
412
|
+
for (let index = 1; index < frames.length; index += 1) {
|
|
413
|
+
const before = frames[index - 1]!;
|
|
414
|
+
const after = frames[index]!;
|
|
415
|
+
let total = 0;
|
|
416
|
+
for (let byte = 0; byte < after.length; byte += 1) total += Math.abs(after[byte]! - before[byte]!);
|
|
417
|
+
const score = total / after.length / 255;
|
|
418
|
+
if (score >= threshold) candidates.push({ at: round(index / sampleRate), score: round(score) });
|
|
419
|
+
}
|
|
420
|
+
return candidates;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
// ---------------------------------------------------------------------------------------------------
|
|
424
|
+
// Commands
|
|
425
|
+
|
|
426
|
+
const SAMPLE_OPTIONS = ["--start", "--end", "--at", "--every", "--transcript", "--around", "--occurrence", "--padding"];
|
|
427
|
+
|
|
428
|
+
async function transcriptOption(parsed: Parsed, cwd: string): Promise<readonly TranscriptWord[] | undefined> {
|
|
429
|
+
const path = parsed.options.get("--transcript");
|
|
430
|
+
return path === undefined ? undefined : readTranscript(resolve(cwd, path));
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
export function intervalSamples(start: number, end: number, every: number): readonly number[] {
|
|
434
|
+
assert(Number.isFinite(start) && start >= 0 && Number.isFinite(end) && end > start, "a sample range needs 0 <= start < end");
|
|
435
|
+
assert(Number.isFinite(every) && every >= 0.001, "--every must be at least 0.001 seconds");
|
|
436
|
+
return Array.from({ length: Math.ceil((end - start) / every) }, (_, index) => round(start + index * every))
|
|
437
|
+
.filter((time) => time < end);
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
function sampleRange(parsed: Parsed, duration: number, words?: readonly TranscriptWord[]): { start: number; end: number } {
|
|
441
|
+
const around = parsed.options.get("--around");
|
|
442
|
+
if (around !== undefined) {
|
|
443
|
+
assert(words !== undefined, "--around requires --transcript");
|
|
444
|
+
assert(!parsed.options.has("--start") && !parsed.options.has("--end"), "choose --around or --start/--end");
|
|
445
|
+
const matches = phraseRanges(words, around);
|
|
446
|
+
assert(matches.length > 0, `No timed phrase matches ${JSON.stringify(around)}`);
|
|
447
|
+
assert(matches.length === 1 || parsed.options.has("--occurrence"),
|
|
448
|
+
`The phrase occurs ${matches.length} times: ${matches.map((match, index) => `${index + 1}: ${match.start}–${match.end}s`).join(", ")}. Choose --occurrence <n> or --start/--end.`);
|
|
449
|
+
const occurrence = integerOption(parsed, "--occurrence", 1, 1);
|
|
450
|
+
const match = matches[occurrence - 1];
|
|
451
|
+
assert(match !== undefined, `--occurrence ${occurrence} is beyond the ${matches.length} matches`);
|
|
452
|
+
const padding = secondsOption(parsed, "--padding", 0.3);
|
|
453
|
+
const start = Math.max(0, round(match.start - padding));
|
|
454
|
+
const end = Math.min(duration, round(match.end + padding));
|
|
455
|
+
assert(end > start, "the phrase lies outside the input media; use its matching transcript");
|
|
456
|
+
return { start, end };
|
|
457
|
+
}
|
|
458
|
+
assert(!parsed.options.has("--occurrence") && !parsed.options.has("--padding"), "--occurrence and --padding apply to --around");
|
|
459
|
+
const start = secondsOption(parsed, "--start", 0);
|
|
460
|
+
const end = secondsOption(parsed, "--end", duration);
|
|
461
|
+
assert(end > start && end <= duration, `range must satisfy 0 <= start < end <= ${duration} s`);
|
|
462
|
+
return { start, end };
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
function sampleTimes(parsed: Parsed, duration: number, words?: readonly TranscriptWord[], requireEvery = false): readonly number[] {
|
|
466
|
+
const at = parsed.options.get("--at");
|
|
467
|
+
if (at !== undefined) {
|
|
468
|
+
for (const key of ["--start", "--end", "--every", "--frames", "--around", "--occurrence", "--padding"]) {
|
|
469
|
+
assert(!parsed.options.has(key), `--at cannot be combined with ${key}`);
|
|
470
|
+
}
|
|
471
|
+
const times = secondsList(at, "--at", 1);
|
|
472
|
+
assert(times.every((time) => time < duration), `a frame time must be before the end of the file (${duration} s)`);
|
|
473
|
+
assert(times.every((time, index) => index === 0 || time > times[index - 1]!), "sample times must be strictly increasing");
|
|
474
|
+
return times;
|
|
475
|
+
}
|
|
476
|
+
const { start, end } = sampleRange(parsed, duration, words);
|
|
477
|
+
const every = parsed.options.get("--every");
|
|
478
|
+
assert(every === undefined || !parsed.options.has("--frames"), "choose --every or --frames");
|
|
479
|
+
assert(!requireEvery || every !== undefined, "frames requires --at <s,s,…> or --every <seconds>");
|
|
480
|
+
const times = every === undefined
|
|
481
|
+
? tileSampleTimes(start, end, integerOption(parsed, "--frames", tileFrameCount(end - start), 2))
|
|
482
|
+
: intervalSamples(start, end, Number(every));
|
|
483
|
+
assert(times.length > 0 && times.every((time) => time < duration), "the range needs sample times before the media ends");
|
|
484
|
+
assert(times.every((time, index) => index === 0 || time > times[index - 1]!), "sample times must be distinct to the nearest millisecond");
|
|
485
|
+
return times;
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
async function probe(argv: readonly string[], io: CliIo, cwd: string): Promise<void> {
|
|
489
|
+
const parsed = parseArguments(argv, []);
|
|
490
|
+
const source = await sourceFile(parsed, cwd);
|
|
491
|
+
const info = await probeMedia(source);
|
|
492
|
+
if (parsed.json) { io.write(`${JSON.stringify({ path: source, ...info }, null, 2)}\n`); return; }
|
|
493
|
+
io.write(`${source}\n ${info.duration} s ${info.width}×${info.height} ${info.frameRate > 0 ? `${info.frameRate} fps` : "still"} ${info.hasAudio ? "with audio" : "no audio"}\n`);
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
async function cut(argv: readonly string[], io: CliIo, cwd: string): Promise<void> {
|
|
497
|
+
const parsed = parseArguments(argv, ["--start", "--end", "--to"], ["--label-time"]);
|
|
498
|
+
const source = await sourceFile(parsed, cwd);
|
|
499
|
+
const start = secondsOption(parsed, "--start", 0);
|
|
500
|
+
const info = await probeMedia(source);
|
|
501
|
+
const end = secondsOption(parsed, "--end", info.duration);
|
|
502
|
+
assert(end <= info.duration + 0.001, `--end ${end} is past the end of the file (${info.duration} s)`);
|
|
503
|
+
const target = await destination(parsed, cwd, "the clip to write, for example notes/hook.mp4");
|
|
504
|
+
const labeled = parsed.flags.has("--label-time");
|
|
505
|
+
await cutClip(source, start, end, target, labeled ? info : undefined);
|
|
506
|
+
if (parsed.json) { io.write(`${JSON.stringify({ path: target, start, end, seconds: round(end - start), labeled }, null, 2)}\n`); return; }
|
|
507
|
+
io.write(`${target}\n ${start} s to ${end} s (${round(end - start)} s)${labeled ? ", source time visible" : ""}\n`);
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
async function frames(argv: readonly string[], io: CliIo, cwd: string): Promise<void> {
|
|
511
|
+
const parsed = parseArguments(argv, [...SAMPLE_OPTIONS, "--to"], ["--label-time"]);
|
|
512
|
+
const source = await sourceFile(parsed, cwd);
|
|
513
|
+
const info = await probeMedia(source);
|
|
514
|
+
const words = await transcriptOption(parsed, cwd);
|
|
515
|
+
const times = sampleTimes(parsed, info.duration, words, true);
|
|
516
|
+
const to = await destinationDirectory(parsed, cwd, "the new directory to write the frames into");
|
|
517
|
+
const staging = await mkdtemp(join(dirname(to), ".hypit-frames-"));
|
|
518
|
+
const labeled = parsed.flags.has("--label-time") || words !== undefined;
|
|
519
|
+
const written: (SampledFrame & { readonly path: string })[] = [];
|
|
520
|
+
try {
|
|
521
|
+
for (const time of times) {
|
|
522
|
+
const name = `frame-${time.toFixed(3).replace(".", "_")}s.jpg`;
|
|
523
|
+
const frame = words === undefined
|
|
524
|
+
? { requestedAt: time, at: await cutFrame(source, time, join(staging, name), labeled) }
|
|
525
|
+
: (await tileFrames(source, [time], join(staging, name), info.width, 1, words))[0]!;
|
|
526
|
+
written.push({ ...frame, path: join(to, name) });
|
|
527
|
+
}
|
|
528
|
+
await rename(staging, to);
|
|
529
|
+
} catch (error) {
|
|
530
|
+
await rm(staging, { recursive: true, force: true });
|
|
531
|
+
throw error;
|
|
532
|
+
}
|
|
533
|
+
if (parsed.json) { io.write(`${JSON.stringify({ directory: to, labeled, frames: written }, null, 2)}\n`); return; }
|
|
534
|
+
io.write(`${to}\n ${written.length} ${labeled ? "time-labeled " : ""}${written.length === 1 ? "frame" : "frames"} from ${written[0]!.at} s to ${written.at(-1)!.at} s\n`);
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
async function tile(argv: readonly string[], io: CliIo, cwd: string): Promise<void> {
|
|
538
|
+
const parsed = parseArguments(argv, [...SAMPLE_OPTIONS, "--frames", "--cell", "--columns", "--to"]);
|
|
539
|
+
const source = await sourceFile(parsed, cwd);
|
|
540
|
+
const info = await probeMedia(source);
|
|
541
|
+
const words = await transcriptOption(parsed, cwd);
|
|
542
|
+
const times = sampleTimes(parsed, info.duration, words);
|
|
543
|
+
// Preserve source width unless an exceptionally tiny input needs room for a legible timecode.
|
|
544
|
+
const cell = integerOption(parsed, "--cell", Math.max(80, Math.min(TILE_CELL_WIDTH, info.width)), 80);
|
|
545
|
+
const columns = integerOption(parsed, "--columns", TILE_COLUMNS, 1);
|
|
546
|
+
const target = await destination(parsed, cwd, "the grid image to write, for example notes/hook-grid.jpg");
|
|
547
|
+
const frames = await tileFrames(source, times, target, cell, columns, words);
|
|
548
|
+
const rows = Math.ceil(times.length / columns);
|
|
549
|
+
if (parsed.json) { io.write(`${JSON.stringify({ path: target, samples: times, columns, rows, cellWidth: cell, frames }, null, 2)}\n`); return; }
|
|
550
|
+
io.write(`${target}\n ${times.length} labeled frames, ${columns}×${rows}, ${cell} px cells\n ${times.map((at) => `${at} s`).join(" ")}\n`);
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
type TileRange = {
|
|
554
|
+
readonly id?: string;
|
|
555
|
+
readonly start: number;
|
|
556
|
+
readonly end: number;
|
|
557
|
+
readonly frames?: number;
|
|
558
|
+
readonly every?: number;
|
|
559
|
+
};
|
|
560
|
+
|
|
561
|
+
function tileRange(value: unknown, index: number, duration: number): TileRange {
|
|
562
|
+
assert(typeof value === "object" && value !== null && !Array.isArray(value), `range ${index + 1} must be an object`);
|
|
563
|
+
const raw = value as Record<string, unknown>;
|
|
564
|
+
assert(typeof raw.start === "number" && Number.isFinite(raw.start) && raw.start >= 0, `range ${index + 1}.start must be non-negative seconds`);
|
|
565
|
+
assert(typeof raw.end === "number" && Number.isFinite(raw.end) && raw.end > raw.start, `range ${index + 1}.end must be after its start`);
|
|
566
|
+
assert(raw.end <= duration, `range ${index + 1}.end is past the end of the file (${duration} s)`);
|
|
567
|
+
assert(raw.id === undefined || (typeof raw.id === "string" && /^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(raw.id)), `range ${index + 1}.id must be a safe file name`);
|
|
568
|
+
assert(raw.frames === undefined || (Number.isSafeInteger(raw.frames) && (raw.frames as number) >= 2), `range ${index + 1}.frames must be a whole number of at least 2`);
|
|
569
|
+
assert(raw.every === undefined || (typeof raw.every === "number" && Number.isFinite(raw.every) && raw.every >= 0.001), `range ${index + 1}.every must be at least 0.001 seconds`);
|
|
570
|
+
assert(raw.frames === undefined || raw.every === undefined, `range ${index + 1} must choose frames or every`);
|
|
571
|
+
return { start: raw.start, end: raw.end, ...(raw.id === undefined ? {} : { id: raw.id as string }),
|
|
572
|
+
...(raw.frames === undefined ? {} : { frames: raw.frames as number }), ...(raw.every === undefined ? {} : { every: raw.every as number }) };
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
async function tiles(argv: readonly string[], io: CliIo, cwd: string): Promise<void> {
|
|
576
|
+
const parsed = parseArguments(argv, [...SAMPLE_OPTIONS, "--ranges", "--frames", "--cell", "--columns", "--rows", "--to"]);
|
|
577
|
+
const source = await sourceFile(parsed, cwd);
|
|
578
|
+
const info = await probeMedia(source);
|
|
579
|
+
const words = await transcriptOption(parsed, cwd);
|
|
580
|
+
const rangesPath = parsed.options.get("--ranges");
|
|
581
|
+
let ranges: { id?: string; start: number; end: number; times: readonly number[] }[];
|
|
582
|
+
if (rangesPath === undefined) {
|
|
583
|
+
const times = sampleTimes(parsed, info.duration, words);
|
|
584
|
+
const range = parsed.options.has("--at")
|
|
585
|
+
? { start: times[0]!, end: times.at(-1)! }
|
|
586
|
+
: sampleRange(parsed, info.duration, words);
|
|
587
|
+
ranges = [{ ...range, times }];
|
|
588
|
+
} else {
|
|
589
|
+
for (const key of ["--start", "--end", "--at", "--around", "--padding", "--occurrence"]) {
|
|
590
|
+
assert(!parsed.options.has(key), `--ranges cannot be combined with ${key}`);
|
|
591
|
+
}
|
|
592
|
+
assert(!parsed.options.has("--frames") || !parsed.options.has("--every"), "choose --frames or --every");
|
|
593
|
+
const raw = JSON.parse(await readFile(resolve(cwd, rangesPath), "utf8")) as unknown;
|
|
594
|
+
assert(Array.isArray(raw) && raw.length > 0, `${rangesPath} must contain a non-empty JSON array`);
|
|
595
|
+
ranges = raw.map((value, index) => {
|
|
596
|
+
const range = tileRange(value, index, info.duration);
|
|
597
|
+
const options = new Map(parsed.options);
|
|
598
|
+
options.set("--start", String(range.start)); options.set("--end", String(range.end));
|
|
599
|
+
if (range.frames !== undefined) { options.delete("--every"); options.set("--frames", String(range.frames)); }
|
|
600
|
+
if (range.every !== undefined) { options.delete("--frames"); options.set("--every", String(range.every)); }
|
|
601
|
+
return { ...range, times: sampleTimes({ ...parsed, options }, info.duration, words) };
|
|
602
|
+
});
|
|
603
|
+
const ids = ranges.flatMap((range) => range.id === undefined ? [] : [range.id]);
|
|
604
|
+
assert(new Set(ids).size === ids.length, "range ids must be unique");
|
|
605
|
+
}
|
|
606
|
+
const cell = integerOption(parsed, "--cell", Math.max(80, Math.min(TILE_CELL_WIDTH, info.width)), 80);
|
|
607
|
+
const columns = integerOption(parsed, "--columns", TILE_COLUMNS, 1);
|
|
608
|
+
const rows = integerOption(parsed, "--rows", 3, 1);
|
|
609
|
+
const perPage = columns * rows;
|
|
610
|
+
const to = await destinationDirectory(parsed, cwd, "the new directory to write the grids into");
|
|
611
|
+
const staging = await mkdtemp(join(dirname(to), ".hypit-tiles-"));
|
|
612
|
+
const written: { id?: string; start: number; end: number; samples: readonly number[]; path: string; frames: readonly SampledFrame[] }[] = [];
|
|
613
|
+
try {
|
|
614
|
+
for (const [index, range] of ranges.entries()) {
|
|
615
|
+
const stem = range.id ?? `${range.start.toFixed(3).replace(".", "_")}s-${range.end.toFixed(3).replace(".", "_")}s`;
|
|
616
|
+
for (let offset = 0; offset < range.times.length; offset += perPage) {
|
|
617
|
+
const times = range.times.slice(offset, offset + perPage);
|
|
618
|
+
const page = range.times.length > perPage ? `-p${String(offset / perPage + 1).padStart(3, "0")}` : "";
|
|
619
|
+
const name = `${String(index + 1).padStart(3, "0")}-${stem}${page}.jpg`;
|
|
620
|
+
const frames = await tileFrames(source, times, join(staging, name), cell, columns, words);
|
|
621
|
+
written.push({ ...(range.id === undefined ? {} : { id: range.id }), start: range.start, end: range.end,
|
|
622
|
+
samples: times, path: join(to, name), frames });
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
await rename(staging, to);
|
|
626
|
+
} catch (error) {
|
|
627
|
+
await rm(staging, { recursive: true, force: true });
|
|
628
|
+
throw error;
|
|
629
|
+
}
|
|
630
|
+
if (parsed.json) { io.write(`${JSON.stringify({ directory: to, columns, rows, cellWidth: cell, grids: written }, null, 2)}\n`); return; }
|
|
631
|
+
io.write(`${to}\n ${written.length} time-labeled ${written.length === 1 ? "grid" : "grids"}\n`);
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
async function boundaries(argv: readonly string[], io: CliIo, cwd: string): Promise<void> {
|
|
635
|
+
const parsed = parseArguments(argv, ["--rate", "--threshold"]);
|
|
636
|
+
const source = await sourceFile(parsed, cwd);
|
|
637
|
+
const rate = numberOption(parsed, "--rate", DEFAULT_BOUNDARY_RATE, 1, 120);
|
|
638
|
+
const threshold = numberOption(parsed, "--threshold", DEFAULT_BOUNDARY_THRESHOLD, 0, 1);
|
|
639
|
+
const candidates = await visualBoundaries(source, rate, threshold);
|
|
640
|
+
if (parsed.json) { io.write(`${JSON.stringify({ path: source, sampleRate: rate, threshold, candidates }, null, 2)}\n`); return; }
|
|
641
|
+
const shown = candidates.slice(0, 40);
|
|
642
|
+
const remaining = candidates.length - shown.length;
|
|
643
|
+
io.write(`${source}\n ${candidates.length} visual-change ${candidates.length === 1 ? "candidate" : "candidates"} at ${rate} samples/s; scores are not shot labels\n${
|
|
644
|
+
shown.map((candidate) => ` ${candidate.at} s score ${candidate.score}`).join("\n")}${remaining > 0 ? `\n … ${remaining} more; --json returns all candidates` : ""}\n`);
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
async function fetch(argv: readonly string[], io: CliIo, cwd: string): Promise<void> {
|
|
648
|
+
const parsed = parseArguments(argv, ["--to"]);
|
|
649
|
+
const [url] = parsed.positionals;
|
|
650
|
+
assert(url !== undefined && isVideoUrl(url), "name an http or https link first");
|
|
651
|
+
assert(parsed.positionals.length === 1, "fetch takes exactly one link");
|
|
652
|
+
const target = await destination(parsed, cwd, "the video file to write, for example reference/source.mp4");
|
|
653
|
+
assert([".mp4", ".mkv", ".webm", ".mov"].includes(extname(target).toLowerCase()), "--to must end in .mp4, .mkv, .webm or .mov");
|
|
654
|
+
await downloadVideo(url, target);
|
|
655
|
+
const info = await probeMedia(target);
|
|
656
|
+
if (parsed.json) { io.write(`${JSON.stringify({ path: target, url, ...info }, null, 2)}\n`); return; }
|
|
657
|
+
io.write(`${target}\n ${info.duration} s ${info.width}×${info.height} ${info.hasAudio ? "with audio" : "no audio"}\n`);
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
// ---------------------------------------------------------------------------------------------------
|
|
661
|
+
// Entry
|
|
662
|
+
|
|
663
|
+
export function writeMediaHelp(io: CliIo, topic?: MediaCommand): void {
|
|
664
|
+
const sections: Record<MediaCommand, readonly string[]> = {
|
|
665
|
+
probe: [" hypit media probe <file>", " Duration, size, frame rate and whether there is audio."],
|
|
666
|
+
cut: [" hypit media cut <file> --start <s> --end <s> [--label-time] --to <clip.mp4>",
|
|
667
|
+
" One exact stretch. --label-time visibly overlays absolute source time on the evidence copy."],
|
|
668
|
+
frames: [" hypit media frames <file> (--at <s,s,…> | --every <s>) [--start <s> --end <s>] [--label-time] [--transcript <json>] --to <dir>",
|
|
669
|
+
" Individual frames named by source time; --transcript adds word times and context below each picture."],
|
|
670
|
+
tile: [" hypit media tile <file> [--start <s> --end <s> | --at <s,s,…>] [--every <s> | --frames <n>] [--transcript <json>] [--cell <px>] [--columns <n>] --to <grid.jpg>",
|
|
671
|
+
" One grid. --every samples from start, excluding end; --frames chooses evenly spaced midpoints."],
|
|
672
|
+
tiles: [" hypit media tiles <file> [--start <s> --end <s> | --at <s,s,…> | --ranges <json>] [--every <s> | --frames <n>] [--transcript <json>] [--cell <px>] [--columns <n>] [--rows <n>] --to <dir>",
|
|
673
|
+
" Paginated grids (3 rows by default). Range files contain { start, end, id?, frames?, every? }."],
|
|
674
|
+
boundaries: [" hypit media boundaries <file> [--rate <samples/s>] [--threshold <0..1>]",
|
|
675
|
+
" Mechanical adjacent-frame change candidates with scores; never editorial shot labels."],
|
|
676
|
+
fetch: [" hypit media fetch <url> --to <video.mp4>", " A link turned into a file with the pinned yt-dlp, video and audio together."],
|
|
677
|
+
};
|
|
678
|
+
const chosen = topic === undefined ? mediaCommands : [topic];
|
|
679
|
+
io.write(`hypit media\nInspect media at chosen times and scales. Local work; no Runtime Profile, no request, no state.\n\n${
|
|
680
|
+
chosen.map((item) => sections[item].join("\n")).join("\n\n")}\n\nFrames and grids accept --around <phrase> with --transcript instead of --start/--end.\n`
|
|
681
|
+
+ "Use --occurrence <n> for a repeated phrase; --padding <s> adds time on each side (default 0.3).\n"
|
|
682
|
+
+ "Transcript times must share the input media's clock. An untimed gap is labeled as such, without inferring silence.\n"
|
|
683
|
+
+ "Commands that create evidence write only what --to names and refuse to overwrite. Add --json for the complete machine view.\n");
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
export async function runMediaCli(argv: readonly string[], io: CliIo, cwd = process.cwd()): Promise<void> {
|
|
687
|
+
const command = argv[1];
|
|
688
|
+
if (command === undefined || command === "--help" || argv.includes("--help")) {
|
|
689
|
+
writeMediaHelp(io, isMediaCommand(command) ? command : undefined);
|
|
690
|
+
return;
|
|
691
|
+
}
|
|
692
|
+
assert(isMediaCommand(command), `unknown media command ${command}; one of ${mediaCommands.join(", ")}`);
|
|
693
|
+
const rest = argv.slice(2);
|
|
694
|
+
if (command === "probe") await probe(rest, io, cwd);
|
|
695
|
+
else if (command === "cut") await cut(rest, io, cwd);
|
|
696
|
+
else if (command === "frames") await frames(rest, io, cwd);
|
|
697
|
+
else if (command === "tile") await tile(rest, io, cwd);
|
|
698
|
+
else if (command === "tiles") await tiles(rest, io, cwd);
|
|
699
|
+
else if (command === "boundaries") await boundaries(rest, io, cwd);
|
|
700
|
+
else await fetch(rest, io, cwd);
|
|
701
|
+
}
|