@kenkaiiii/gg-editor 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +453 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +173 -0
- package/dist/cli.js.map +1 -0
- package/dist/core/ass.d.ts +75 -0
- package/dist/core/ass.d.ts.map +1 -0
- package/dist/core/ass.js +128 -0
- package/dist/core/ass.js.map +1 -0
- package/dist/core/ass.test.d.ts +2 -0
- package/dist/core/ass.test.d.ts.map +1 -0
- package/dist/core/ass.test.js +112 -0
- package/dist/core/ass.test.js.map +1 -0
- package/dist/core/audio-cleanup.d.ts +16 -0
- package/dist/core/audio-cleanup.d.ts.map +1 -0
- package/dist/core/audio-cleanup.js +79 -0
- package/dist/core/audio-cleanup.js.map +1 -0
- package/dist/core/audio-cleanup.test.d.ts +2 -0
- package/dist/core/audio-cleanup.test.d.ts.map +1 -0
- package/dist/core/audio-cleanup.test.js +41 -0
- package/dist/core/audio-cleanup.test.js.map +1 -0
- package/dist/core/audio-mix.d.ts +89 -0
- package/dist/core/audio-mix.d.ts.map +1 -0
- package/dist/core/audio-mix.js +156 -0
- package/dist/core/audio-mix.js.map +1 -0
- package/dist/core/audio-mix.test.d.ts +2 -0
- package/dist/core/audio-mix.test.d.ts.map +1 -0
- package/dist/core/audio-mix.test.js +91 -0
- package/dist/core/audio-mix.test.js.map +1 -0
- package/dist/core/auth/anthropic.d.ts +4 -0
- package/dist/core/auth/anthropic.d.ts.map +1 -0
- package/dist/core/auth/anthropic.js +78 -0
- package/dist/core/auth/anthropic.js.map +1 -0
- package/dist/core/auth/index.d.ts +7 -0
- package/dist/core/auth/index.d.ts.map +1 -0
- package/dist/core/auth/index.js +6 -0
- package/dist/core/auth/index.js.map +1 -0
- package/dist/core/auth/login.d.ts +13 -0
- package/dist/core/auth/login.d.ts.map +1 -0
- package/dist/core/auth/login.js +188 -0
- package/dist/core/auth/login.js.map +1 -0
- package/dist/core/auth/openai.d.ts +4 -0
- package/dist/core/auth/openai.d.ts.map +1 -0
- package/dist/core/auth/openai.js +170 -0
- package/dist/core/auth/openai.js.map +1 -0
- package/dist/core/auth/pkce.d.ts +5 -0
- package/dist/core/auth/pkce.d.ts.map +1 -0
- package/dist/core/auth/pkce.js +17 -0
- package/dist/core/auth/pkce.js.map +1 -0
- package/dist/core/auth/storage.d.ts +29 -0
- package/dist/core/auth/storage.d.ts.map +1 -0
- package/dist/core/auth/storage.js +127 -0
- package/dist/core/auth/storage.js.map +1 -0
- package/dist/core/auth/types.d.ts +22 -0
- package/dist/core/auth/types.d.ts.map +1 -0
- package/dist/core/auth/types.js +12 -0
- package/dist/core/auth/types.js.map +1 -0
- package/dist/core/clustering.d.ts +52 -0
- package/dist/core/clustering.d.ts.map +1 -0
- package/dist/core/clustering.js +163 -0
- package/dist/core/clustering.js.map +1 -0
- package/dist/core/clustering.test.d.ts +2 -0
- package/dist/core/clustering.test.d.ts.map +1 -0
- package/dist/core/clustering.test.js +112 -0
- package/dist/core/clustering.test.js.map +1 -0
- package/dist/core/color-match.d.ts +19 -0
- package/dist/core/color-match.d.ts.map +1 -0
- package/dist/core/color-match.js +118 -0
- package/dist/core/color-match.js.map +1 -0
- package/dist/core/color-match.test.d.ts +2 -0
- package/dist/core/color-match.test.d.ts.map +1 -0
- package/dist/core/color-match.test.js +40 -0
- package/dist/core/color-match.test.js.map +1 -0
- package/dist/core/ducking.d.ts +37 -0
- package/dist/core/ducking.d.ts.map +1 -0
- package/dist/core/ducking.js +71 -0
- package/dist/core/ducking.js.map +1 -0
- package/dist/core/ducking.test.d.ts +2 -0
- package/dist/core/ducking.test.d.ts.map +1 -0
- package/dist/core/ducking.test.js +38 -0
- package/dist/core/ducking.test.js.map +1 -0
- package/dist/core/edl-roundtrip.test.d.ts +2 -0
- package/dist/core/edl-roundtrip.test.d.ts.map +1 -0
- package/dist/core/edl-roundtrip.test.js +171 -0
- package/dist/core/edl-roundtrip.test.js.map +1 -0
- package/dist/core/edl.d.ts +41 -0
- package/dist/core/edl.d.ts.map +1 -0
- package/dist/core/edl.js +56 -0
- package/dist/core/edl.js.map +1 -0
- package/dist/core/edl.test.d.ts +2 -0
- package/dist/core/edl.test.d.ts.map +1 -0
- package/dist/core/edl.test.js +62 -0
- package/dist/core/edl.test.js.map +1 -0
- package/dist/core/envelope-sync.d.ts +52 -0
- package/dist/core/envelope-sync.d.ts.map +1 -0
- package/dist/core/envelope-sync.js +169 -0
- package/dist/core/envelope-sync.js.map +1 -0
- package/dist/core/envelope-sync.test.d.ts +2 -0
- package/dist/core/envelope-sync.test.d.ts.map +1 -0
- package/dist/core/envelope-sync.test.js +70 -0
- package/dist/core/envelope-sync.test.js.map +1 -0
- package/dist/core/fcpxml-roundtrip.test.d.ts +2 -0
- package/dist/core/fcpxml-roundtrip.test.d.ts.map +1 -0
- package/dist/core/fcpxml-roundtrip.test.js +251 -0
- package/dist/core/fcpxml-roundtrip.test.js.map +1 -0
- package/dist/core/fcpxml.d.ts +172 -0
- package/dist/core/fcpxml.d.ts.map +1 -0
- package/dist/core/fcpxml.js +406 -0
- package/dist/core/fcpxml.js.map +1 -0
- package/dist/core/fcpxml.test.d.ts +2 -0
- package/dist/core/fcpxml.test.d.ts.map +1 -0
- package/dist/core/fcpxml.test.js +360 -0
- package/dist/core/fcpxml.test.js.map +1 -0
- package/dist/core/filler-words.d.ts +107 -0
- package/dist/core/filler-words.d.ts.map +1 -0
- package/dist/core/filler-words.js +221 -0
- package/dist/core/filler-words.js.map +1 -0
- package/dist/core/filler-words.test.d.ts +2 -0
- package/dist/core/filler-words.test.d.ts.map +1 -0
- package/dist/core/filler-words.test.js +177 -0
- package/dist/core/filler-words.test.js.map +1 -0
- package/dist/core/format.d.ts +36 -0
- package/dist/core/format.d.ts.map +1 -0
- package/dist/core/format.js +57 -0
- package/dist/core/format.js.map +1 -0
- package/dist/core/format.test.d.ts +2 -0
- package/dist/core/format.test.d.ts.map +1 -0
- package/dist/core/format.test.js +81 -0
- package/dist/core/format.test.js.map +1 -0
- package/dist/core/frames.d.ts +35 -0
- package/dist/core/frames.d.ts.map +1 -0
- package/dist/core/frames.js +64 -0
- package/dist/core/frames.js.map +1 -0
- package/dist/core/hook-analysis.d.ts +90 -0
- package/dist/core/hook-analysis.d.ts.map +1 -0
- package/dist/core/hook-analysis.js +222 -0
- package/dist/core/hook-analysis.js.map +1 -0
- package/dist/core/hook-analysis.test.d.ts +2 -0
- package/dist/core/hook-analysis.test.d.ts.map +1 -0
- package/dist/core/hook-analysis.test.js +130 -0
- package/dist/core/hook-analysis.test.js.map +1 -0
- package/dist/core/hosts/detect.d.ts +17 -0
- package/dist/core/hosts/detect.d.ts.map +1 -0
- package/dist/core/hosts/detect.js +64 -0
- package/dist/core/hosts/detect.js.map +1 -0
- package/dist/core/hosts/detect.test.d.ts +2 -0
- package/dist/core/hosts/detect.test.d.ts.map +1 -0
- package/dist/core/hosts/detect.test.js +17 -0
- package/dist/core/hosts/detect.test.js.map +1 -0
- package/dist/core/hosts/index.d.ts +13 -0
- package/dist/core/hosts/index.d.ts.map +1 -0
- package/dist/core/hosts/index.js +30 -0
- package/dist/core/hosts/index.js.map +1 -0
- package/dist/core/hosts/lazy.d.ts +53 -0
- package/dist/core/hosts/lazy.d.ts.map +1 -0
- package/dist/core/hosts/lazy.js +125 -0
- package/dist/core/hosts/lazy.js.map +1 -0
- package/dist/core/hosts/lazy.test.d.ts +2 -0
- package/dist/core/hosts/lazy.test.d.ts.map +1 -0
- package/dist/core/hosts/lazy.test.js +117 -0
- package/dist/core/hosts/lazy.test.js.map +1 -0
- package/dist/core/hosts/none/adapter.d.ts +74 -0
- package/dist/core/hosts/none/adapter.d.ts.map +1 -0
- package/dist/core/hosts/none/adapter.js +99 -0
- package/dist/core/hosts/none/adapter.js.map +1 -0
- package/dist/core/hosts/premiere/adapter.d.ts +87 -0
- package/dist/core/hosts/premiere/adapter.d.ts.map +1 -0
- package/dist/core/hosts/premiere/adapter.js +218 -0
- package/dist/core/hosts/premiere/adapter.js.map +1 -0
- package/dist/core/hosts/premiere/bridge-source.d.ts +26 -0
- package/dist/core/hosts/premiere/bridge-source.d.ts.map +1 -0
- package/dist/core/hosts/premiere/bridge-source.js +326 -0
- package/dist/core/hosts/premiere/bridge-source.js.map +1 -0
- package/dist/core/hosts/premiere/bridge-source.test.d.ts +2 -0
- package/dist/core/hosts/premiere/bridge-source.test.d.ts.map +1 -0
- package/dist/core/hosts/premiere/bridge-source.test.js +36 -0
- package/dist/core/hosts/premiere/bridge-source.test.js.map +1 -0
- package/dist/core/hosts/premiere/bridge.d.ts +38 -0
- package/dist/core/hosts/premiere/bridge.d.ts.map +1 -0
- package/dist/core/hosts/premiere/bridge.js +238 -0
- package/dist/core/hosts/premiere/bridge.js.map +1 -0
- package/dist/core/hosts/premiere/http-bridge.d.ts +47 -0
- package/dist/core/hosts/premiere/http-bridge.d.ts.map +1 -0
- package/dist/core/hosts/premiere/http-bridge.js +82 -0
- package/dist/core/hosts/premiere/http-bridge.js.map +1 -0
- package/dist/core/hosts/premiere/http-bridge.test.d.ts +2 -0
- package/dist/core/hosts/premiere/http-bridge.test.d.ts.map +1 -0
- package/dist/core/hosts/premiere/http-bridge.test.js +113 -0
- package/dist/core/hosts/premiere/http-bridge.test.js.map +1 -0
- package/dist/core/hosts/premiere/ws-bridge.d.ts +91 -0
- package/dist/core/hosts/premiere/ws-bridge.d.ts.map +1 -0
- package/dist/core/hosts/premiere/ws-bridge.js +303 -0
- package/dist/core/hosts/premiere/ws-bridge.js.map +1 -0
- package/dist/core/hosts/premiere/ws-bridge.test.d.ts +2 -0
- package/dist/core/hosts/premiere/ws-bridge.test.d.ts.map +1 -0
- package/dist/core/hosts/premiere/ws-bridge.test.js +146 -0
- package/dist/core/hosts/premiere/ws-bridge.test.js.map +1 -0
- package/dist/core/hosts/resolve/adapter.d.ts +99 -0
- package/dist/core/hosts/resolve/adapter.d.ts.map +1 -0
- package/dist/core/hosts/resolve/adapter.js +187 -0
- package/dist/core/hosts/resolve/adapter.js.map +1 -0
- package/dist/core/hosts/resolve/bridge-source.d.ts +17 -0
- package/dist/core/hosts/resolve/bridge-source.d.ts.map +1 -0
- package/dist/core/hosts/resolve/bridge-source.js +660 -0
- package/dist/core/hosts/resolve/bridge-source.js.map +1 -0
- package/dist/core/hosts/resolve/bridge.d.ts +51 -0
- package/dist/core/hosts/resolve/bridge.d.ts.map +1 -0
- package/dist/core/hosts/resolve/bridge.integration.test.d.ts +2 -0
- package/dist/core/hosts/resolve/bridge.integration.test.d.ts.map +1 -0
- package/dist/core/hosts/resolve/bridge.integration.test.js +472 -0
- package/dist/core/hosts/resolve/bridge.integration.test.js.map +1 -0
- package/dist/core/hosts/resolve/bridge.js +270 -0
- package/dist/core/hosts/resolve/bridge.js.map +1 -0
- package/dist/core/hosts/resolve/bridge.test.d.ts +2 -0
- package/dist/core/hosts/resolve/bridge.test.d.ts.map +1 -0
- package/dist/core/hosts/resolve/bridge.test.js +50 -0
- package/dist/core/hosts/resolve/bridge.test.js.map +1 -0
- package/dist/core/hosts/types.d.ts +167 -0
- package/dist/core/hosts/types.d.ts.map +1 -0
- package/dist/core/hosts/types.js +27 -0
- package/dist/core/hosts/types.js.map +1 -0
- package/dist/core/keyframes.d.ts +35 -0
- package/dist/core/keyframes.d.ts.map +1 -0
- package/dist/core/keyframes.js +90 -0
- package/dist/core/keyframes.js.map +1 -0
- package/dist/core/keyframes.test.d.ts +2 -0
- package/dist/core/keyframes.test.d.ts.map +1 -0
- package/dist/core/keyframes.test.js +73 -0
- package/dist/core/keyframes.test.js.map +1 -0
- package/dist/core/keyword-captions.d.ts +75 -0
- package/dist/core/keyword-captions.d.ts.map +1 -0
- package/dist/core/keyword-captions.js +285 -0
- package/dist/core/keyword-captions.js.map +1 -0
- package/dist/core/keyword-captions.test.d.ts +2 -0
- package/dist/core/keyword-captions.test.d.ts.map +1 -0
- package/dist/core/keyword-captions.test.js +90 -0
- package/dist/core/keyword-captions.test.js.map +1 -0
- package/dist/core/loudness.d.ts +52 -0
- package/dist/core/loudness.d.ts.map +1 -0
- package/dist/core/loudness.js +120 -0
- package/dist/core/loudness.js.map +1 -0
- package/dist/core/loudness.test.d.ts +2 -0
- package/dist/core/loudness.test.d.ts.map +1 -0
- package/dist/core/loudness.test.js +34 -0
- package/dist/core/loudness.test.js.map +1 -0
- package/dist/core/marker-colors.d.ts +39 -0
- package/dist/core/marker-colors.d.ts.map +1 -0
- package/dist/core/marker-colors.js +83 -0
- package/dist/core/marker-colors.js.map +1 -0
- package/dist/core/marker-colors.test.d.ts +2 -0
- package/dist/core/marker-colors.test.d.ts.map +1 -0
- package/dist/core/marker-colors.test.js +116 -0
- package/dist/core/marker-colors.test.js.map +1 -0
- package/dist/core/media/ffmpeg.d.ts +27 -0
- package/dist/core/media/ffmpeg.d.ts.map +1 -0
- package/dist/core/media/ffmpeg.js +53 -0
- package/dist/core/media/ffmpeg.js.map +1 -0
- package/dist/core/multicam.d.ts +40 -0
- package/dist/core/multicam.d.ts.map +1 -0
- package/dist/core/multicam.js +77 -0
- package/dist/core/multicam.js.map +1 -0
- package/dist/core/multicam.test.d.ts +2 -0
- package/dist/core/multicam.test.d.ts.map +1 -0
- package/dist/core/multicam.test.js +56 -0
- package/dist/core/multicam.test.js.map +1 -0
- package/dist/core/punch-in.d.ts +72 -0
- package/dist/core/punch-in.d.ts.map +1 -0
- package/dist/core/punch-in.js +133 -0
- package/dist/core/punch-in.js.map +1 -0
- package/dist/core/punch-in.test.d.ts +2 -0
- package/dist/core/punch-in.test.d.ts.map +1 -0
- package/dist/core/punch-in.test.js +118 -0
- package/dist/core/punch-in.test.js.map +1 -0
- package/dist/core/reformat.d.ts +26 -0
- package/dist/core/reformat.d.ts.map +1 -0
- package/dist/core/reformat.js +31 -0
- package/dist/core/reformat.js.map +1 -0
- package/dist/core/reformat.test.d.ts +2 -0
- package/dist/core/reformat.test.d.ts.map +1 -0
- package/dist/core/reformat.test.js +29 -0
- package/dist/core/reformat.test.js.map +1 -0
- package/dist/core/reorder.d.ts +42 -0
- package/dist/core/reorder.d.ts.map +1 -0
- package/dist/core/reorder.js +80 -0
- package/dist/core/reorder.js.map +1 -0
- package/dist/core/reorder.test.d.ts +2 -0
- package/dist/core/reorder.test.d.ts.map +1 -0
- package/dist/core/reorder.test.js +88 -0
- package/dist/core/reorder.test.js.map +1 -0
- package/dist/core/review.d.ts +38 -0
- package/dist/core/review.d.ts.map +1 -0
- package/dist/core/review.js +128 -0
- package/dist/core/review.js.map +1 -0
- package/dist/core/review.test.d.ts +2 -0
- package/dist/core/review.test.d.ts.map +1 -0
- package/dist/core/review.test.js +76 -0
- package/dist/core/review.test.js.map +1 -0
- package/dist/core/sessions.d.ts +40 -0
- package/dist/core/sessions.d.ts.map +1 -0
- package/dist/core/sessions.js +61 -0
- package/dist/core/sessions.js.map +1 -0
- package/dist/core/sfx-on-cuts.d.ts +60 -0
- package/dist/core/sfx-on-cuts.d.ts.map +1 -0
- package/dist/core/sfx-on-cuts.js +90 -0
- package/dist/core/sfx-on-cuts.js.map +1 -0
- package/dist/core/sfx-on-cuts.test.d.ts +2 -0
- package/dist/core/sfx-on-cuts.test.d.ts.map +1 -0
- package/dist/core/sfx-on-cuts.test.js +53 -0
- package/dist/core/sfx-on-cuts.test.js.map +1 -0
- package/dist/core/silence.d.ts +41 -0
- package/dist/core/silence.d.ts.map +1 -0
- package/dist/core/silence.js +104 -0
- package/dist/core/silence.js.map +1 -0
- package/dist/core/silence.test.d.ts +2 -0
- package/dist/core/silence.test.d.ts.map +1 -0
- package/dist/core/silence.test.js +143 -0
- package/dist/core/silence.test.js.map +1 -0
- package/dist/core/skills-loader.d.ts +34 -0
- package/dist/core/skills-loader.d.ts.map +1 -0
- package/dist/core/skills-loader.js +80 -0
- package/dist/core/skills-loader.js.map +1 -0
- package/dist/core/skills-loader.test.d.ts +2 -0
- package/dist/core/skills-loader.test.d.ts.map +1 -0
- package/dist/core/skills-loader.test.js +68 -0
- package/dist/core/skills-loader.test.js.map +1 -0
- package/dist/core/skin-grade.d.ts +62 -0
- package/dist/core/skin-grade.d.ts.map +1 -0
- package/dist/core/skin-grade.js +270 -0
- package/dist/core/skin-grade.js.map +1 -0
- package/dist/core/skin-grade.test.d.ts +2 -0
- package/dist/core/skin-grade.test.d.ts.map +1 -0
- package/dist/core/skin-grade.test.js +182 -0
- package/dist/core/skin-grade.test.js.map +1 -0
- package/dist/core/speaker-changes.d.ts +30 -0
- package/dist/core/speaker-changes.d.ts.map +1 -0
- package/dist/core/speaker-changes.js +19 -0
- package/dist/core/speaker-changes.js.map +1 -0
- package/dist/core/speaker-changes.test.d.ts +2 -0
- package/dist/core/speaker-changes.test.d.ts.map +1 -0
- package/dist/core/speaker-changes.test.js +46 -0
- package/dist/core/speaker-changes.test.js.map +1 -0
- package/dist/core/speed-ramp.d.ts +60 -0
- package/dist/core/speed-ramp.d.ts.map +1 -0
- package/dist/core/speed-ramp.js +113 -0
- package/dist/core/speed-ramp.js.map +1 -0
- package/dist/core/speed-ramp.test.d.ts +2 -0
- package/dist/core/speed-ramp.test.d.ts.map +1 -0
- package/dist/core/speed-ramp.test.js +74 -0
- package/dist/core/speed-ramp.test.js.map +1 -0
- package/dist/core/srt.d.ts +56 -0
- package/dist/core/srt.d.ts.map +1 -0
- package/dist/core/srt.js +90 -0
- package/dist/core/srt.js.map +1 -0
- package/dist/core/srt.test.d.ts +2 -0
- package/dist/core/srt.test.d.ts.map +1 -0
- package/dist/core/srt.test.js +107 -0
- package/dist/core/srt.test.js.map +1 -0
- package/dist/core/stabilize.d.ts +15 -0
- package/dist/core/stabilize.d.ts.map +1 -0
- package/dist/core/stabilize.js +69 -0
- package/dist/core/stabilize.js.map +1 -0
- package/dist/core/styles-loader.d.ts +33 -0
- package/dist/core/styles-loader.d.ts.map +1 -0
- package/dist/core/styles-loader.js +67 -0
- package/dist/core/styles-loader.js.map +1 -0
- package/dist/core/styles-loader.test.d.ts +2 -0
- package/dist/core/styles-loader.test.d.ts.map +1 -0
- package/dist/core/styles-loader.test.js +72 -0
- package/dist/core/styles-loader.test.js.map +1 -0
- package/dist/core/text-overlay.d.ts +76 -0
- package/dist/core/text-overlay.d.ts.map +1 -0
- package/dist/core/text-overlay.js +233 -0
- package/dist/core/text-overlay.js.map +1 -0
- package/dist/core/text-overlay.test.d.ts +2 -0
- package/dist/core/text-overlay.test.d.ts.map +1 -0
- package/dist/core/text-overlay.test.js +103 -0
- package/dist/core/text-overlay.test.js.map +1 -0
- package/dist/core/vision.d.ts +53 -0
- package/dist/core/vision.d.ts.map +1 -0
- package/dist/core/vision.js +150 -0
- package/dist/core/vision.js.map +1 -0
- package/dist/core/vision.test.d.ts +2 -0
- package/dist/core/vision.test.d.ts.map +1 -0
- package/dist/core/vision.test.js +76 -0
- package/dist/core/vision.test.js.map +1 -0
- package/dist/core/whisper.d.ts +188 -0
- package/dist/core/whisper.d.ts.map +1 -0
- package/dist/core/whisper.js +380 -0
- package/dist/core/whisper.js.map +1 -0
- package/dist/core/whisper.test.d.ts +2 -0
- package/dist/core/whisper.test.d.ts.map +1 -0
- package/dist/core/whisper.test.js +262 -0
- package/dist/core/whisper.test.js.map +1 -0
- package/dist/director/delegate-tool.d.ts +22 -0
- package/dist/director/delegate-tool.d.ts.map +1 -0
- package/dist/director/delegate-tool.js +62 -0
- package/dist/director/delegate-tool.js.map +1 -0
- package/dist/director/delegate-tool.test.d.ts +2 -0
- package/dist/director/delegate-tool.test.d.ts.map +1 -0
- package/dist/director/delegate-tool.test.js +38 -0
- package/dist/director/delegate-tool.test.js.map +1 -0
- package/dist/director/director-prompt.d.ts +7 -0
- package/dist/director/director-prompt.d.ts.map +1 -0
- package/dist/director/director-prompt.js +52 -0
- package/dist/director/director-prompt.js.map +1 -0
- package/dist/director/director.d.ts +16 -0
- package/dist/director/director.d.ts.map +1 -0
- package/dist/director/director.js +28 -0
- package/dist/director/director.js.map +1 -0
- package/dist/director/executor.d.ts +19 -0
- package/dist/director/executor.d.ts.map +1 -0
- package/dist/director/executor.js +93 -0
- package/dist/director/executor.js.map +1 -0
- package/dist/director/index.d.ts +6 -0
- package/dist/director/index.d.ts.map +1 -0
- package/dist/director/index.js +5 -0
- package/dist/director/index.js.map +1 -0
- package/dist/director/types.d.ts +38 -0
- package/dist/director/types.d.ts.map +1 -0
- package/dist/director/types.js +2 -0
- package/dist/director/types.js.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/skills.d.ts +18 -0
- package/dist/skills.d.ts.map +1 -0
- package/dist/skills.js +674 -0
- package/dist/skills.js.map +1 -0
- package/dist/system-prompt.d.ts +35 -0
- package/dist/system-prompt.d.ts.map +1 -0
- package/dist/system-prompt.js +478 -0
- package/dist/system-prompt.js.map +1 -0
- package/dist/system-prompt.test.d.ts +2 -0
- package/dist/system-prompt.test.d.ts.map +1 -0
- package/dist/system-prompt.test.js +87 -0
- package/dist/system-prompt.test.js.map +1 -0
- package/dist/tools/add-fades.d.ts +13 -0
- package/dist/tools/add-fades.d.ts.map +1 -0
- package/dist/tools/add-fades.js +88 -0
- package/dist/tools/add-fades.js.map +1 -0
- package/dist/tools/add-marker.d.ts +31 -0
- package/dist/tools/add-marker.d.ts.map +1 -0
- package/dist/tools/add-marker.js +56 -0
- package/dist/tools/add-marker.js.map +1 -0
- package/dist/tools/add-sfx-at-cuts.d.ts +24 -0
- package/dist/tools/add-sfx-at-cuts.d.ts.map +1 -0
- package/dist/tools/add-sfx-at-cuts.js +120 -0
- package/dist/tools/add-sfx-at-cuts.js.map +1 -0
- package/dist/tools/add-track.d.ts +13 -0
- package/dist/tools/add-track.d.ts.map +1 -0
- package/dist/tools/add-track.js +26 -0
- package/dist/tools/add-track.js.map +1 -0
- package/dist/tools/analyze-hook.d.ts +28 -0
- package/dist/tools/analyze-hook.d.ts.map +1 -0
- package/dist/tools/analyze-hook.js +126 -0
- package/dist/tools/analyze-hook.js.map +1 -0
- package/dist/tools/append-clip.d.ts +10 -0
- package/dist/tools/append-clip.d.ts.map +1 -0
- package/dist/tools/append-clip.js +27 -0
- package/dist/tools/append-clip.js.map +1 -0
- package/dist/tools/apply-lut.d.ts +11 -0
- package/dist/tools/apply-lut.d.ts.map +1 -0
- package/dist/tools/apply-lut.js +33 -0
- package/dist/tools/apply-lut.js.map +1 -0
- package/dist/tools/burn-subtitles.d.ts +28 -0
- package/dist/tools/burn-subtitles.d.ts.map +1 -0
- package/dist/tools/burn-subtitles.js +87 -0
- package/dist/tools/burn-subtitles.js.map +1 -0
- package/dist/tools/clean-audio.d.ts +18 -0
- package/dist/tools/clean-audio.d.ts.map +1 -0
- package/dist/tools/clean-audio.js +54 -0
- package/dist/tools/clean-audio.js.map +1 -0
- package/dist/tools/clone-timeline.d.ts +9 -0
- package/dist/tools/clone-timeline.d.ts.map +1 -0
- package/dist/tools/clone-timeline.js +28 -0
- package/dist/tools/clone-timeline.js.map +1 -0
- package/dist/tools/cluster-takes.d.ts +11 -0
- package/dist/tools/cluster-takes.d.ts.map +1 -0
- package/dist/tools/cluster-takes.js +71 -0
- package/dist/tools/cluster-takes.js.map +1 -0
- package/dist/tools/color-match.d.ts +16 -0
- package/dist/tools/color-match.d.ts.map +1 -0
- package/dist/tools/color-match.js +55 -0
- package/dist/tools/color-match.js.map +1 -0
- package/dist/tools/compose-layered.d.ts +47 -0
- package/dist/tools/compose-layered.d.ts.map +1 -0
- package/dist/tools/compose-layered.js +103 -0
- package/dist/tools/compose-layered.js.map +1 -0
- package/dist/tools/compose-thumbnail.d.ts +35 -0
- package/dist/tools/compose-thumbnail.d.ts.map +1 -0
- package/dist/tools/compose-thumbnail.js +130 -0
- package/dist/tools/compose-thumbnail.js.map +1 -0
- package/dist/tools/concat-videos.d.ts +18 -0
- package/dist/tools/concat-videos.d.ts.map +1 -0
- package/dist/tools/concat-videos.js +79 -0
- package/dist/tools/concat-videos.js.map +1 -0
- package/dist/tools/copy-grade.d.ts +10 -0
- package/dist/tools/copy-grade.d.ts.map +1 -0
- package/dist/tools/copy-grade.js +29 -0
- package/dist/tools/copy-grade.js.map +1 -0
- package/dist/tools/create-timeline.d.ts +12 -0
- package/dist/tools/create-timeline.d.ts.map +1 -0
- package/dist/tools/create-timeline.js +35 -0
- package/dist/tools/create-timeline.js.map +1 -0
- package/dist/tools/crossfade-videos.d.ts +49 -0
- package/dist/tools/crossfade-videos.d.ts.map +1 -0
- package/dist/tools/crossfade-videos.js +121 -0
- package/dist/tools/crossfade-videos.js.map +1 -0
- package/dist/tools/cut-at.d.ts +10 -0
- package/dist/tools/cut-at.d.ts.map +1 -0
- package/dist/tools/cut-at.js +24 -0
- package/dist/tools/cut-at.js.map +1 -0
- package/dist/tools/cut-filler-words.d.ts +27 -0
- package/dist/tools/cut-filler-words.d.ts.map +1 -0
- package/dist/tools/cut-filler-words.js +165 -0
- package/dist/tools/cut-filler-words.js.map +1 -0
- package/dist/tools/detect-silence.d.ts +13 -0
- package/dist/tools/detect-silence.d.ts.map +1 -0
- package/dist/tools/detect-silence.js +98 -0
- package/dist/tools/detect-silence.js.map +1 -0
- package/dist/tools/detect-speaker-changes.d.ts +9 -0
- package/dist/tools/detect-speaker-changes.d.ts.map +1 -0
- package/dist/tools/detect-speaker-changes.js +42 -0
- package/dist/tools/detect-speaker-changes.js.map +1 -0
- package/dist/tools/dry-run.d.ts +23 -0
- package/dist/tools/dry-run.d.ts.map +1 -0
- package/dist/tools/dry-run.js +66 -0
- package/dist/tools/dry-run.js.map +1 -0
- package/dist/tools/dry-run.test.d.ts +2 -0
- package/dist/tools/dry-run.test.d.ts.map +1 -0
- package/dist/tools/dry-run.test.js +66 -0
- package/dist/tools/dry-run.test.js.map +1 -0
- package/dist/tools/duck-audio.d.ts +16 -0
- package/dist/tools/duck-audio.d.ts.map +1 -0
- package/dist/tools/duck-audio.js +73 -0
- package/dist/tools/duck-audio.js.map +1 -0
- package/dist/tools/extract-audio.d.ts +10 -0
- package/dist/tools/extract-audio.d.ts.map +1 -0
- package/dist/tools/extract-audio.js +30 -0
- package/dist/tools/extract-audio.js.map +1 -0
- package/dist/tools/extract-frame.d.ts +12 -0
- package/dist/tools/extract-frame.d.ts.map +1 -0
- package/dist/tools/extract-frame.js +63 -0
- package/dist/tools/extract-frame.js.map +1 -0
- package/dist/tools/generate-gif.d.ts +13 -0
- package/dist/tools/generate-gif.d.ts.map +1 -0
- package/dist/tools/generate-gif.js +94 -0
- package/dist/tools/generate-gif.js.map +1 -0
- package/dist/tools/get-markers.d.ts +13 -0
- package/dist/tools/get-markers.d.ts.map +1 -0
- package/dist/tools/get-markers.js +71 -0
- package/dist/tools/get-markers.js.map +1 -0
- package/dist/tools/get-timeline.d.ts +9 -0
- package/dist/tools/get-timeline.d.ts.map +1 -0
- package/dist/tools/get-timeline.js +43 -0
- package/dist/tools/get-timeline.js.map +1 -0
- package/dist/tools/grade-skin-tones.d.ts +31 -0
- package/dist/tools/grade-skin-tones.d.ts.map +1 -0
- package/dist/tools/grade-skin-tones.js +92 -0
- package/dist/tools/grade-skin-tones.js.map +1 -0
- package/dist/tools/host-info.d.ts +7 -0
- package/dist/tools/host-info.d.ts.map +1 -0
- package/dist/tools/host-info.js +33 -0
- package/dist/tools/host-info.js.map +1 -0
- package/dist/tools/host-tools.test.d.ts +2 -0
- package/dist/tools/host-tools.test.d.ts.map +1 -0
- package/dist/tools/host-tools.test.js +83 -0
- package/dist/tools/host-tools.test.js.map +1 -0
- package/dist/tools/import-edl.d.ts +9 -0
- package/dist/tools/import-edl.d.ts.map +1 -0
- package/dist/tools/import-edl.js +25 -0
- package/dist/tools/import-edl.js.map +1 -0
- package/dist/tools/import-subtitles.d.ts +9 -0
- package/dist/tools/import-subtitles.d.ts.map +1 -0
- package/dist/tools/import-subtitles.js +31 -0
- package/dist/tools/import-subtitles.js.map +1 -0
- package/dist/tools/import-to-media-pool.d.ts +10 -0
- package/dist/tools/import-to-media-pool.d.ts.map +1 -0
- package/dist/tools/import-to-media-pool.js +27 -0
- package/dist/tools/import-to-media-pool.js.map +1 -0
- package/dist/tools/index.d.ts +94 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +242 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/index.test.d.ts +2 -0
- package/dist/tools/index.test.d.ts.map +1 -0
- package/dist/tools/index.test.js +128 -0
- package/dist/tools/index.test.js.map +1 -0
- package/dist/tools/insert-broll.d.ts +13 -0
- package/dist/tools/insert-broll.d.ts.map +1 -0
- package/dist/tools/insert-broll.js +56 -0
- package/dist/tools/insert-broll.js.map +1 -0
- package/dist/tools/ken-burns.d.ts +26 -0
- package/dist/tools/ken-burns.d.ts.map +1 -0
- package/dist/tools/ken-burns.js +125 -0
- package/dist/tools/ken-burns.js.map +1 -0
- package/dist/tools/list-render-presets.d.ts +7 -0
- package/dist/tools/list-render-presets.d.ts.map +1 -0
- package/dist/tools/list-render-presets.js +30 -0
- package/dist/tools/list-render-presets.js.map +1 -0
- package/dist/tools/match-clip-color.d.ts +29 -0
- package/dist/tools/match-clip-color.d.ts.map +1 -0
- package/dist/tools/match-clip-color.js +99 -0
- package/dist/tools/match-clip-color.js.map +1 -0
- package/dist/tools/measure-loudness.d.ts +8 -0
- package/dist/tools/measure-loudness.d.ts.map +1 -0
- package/dist/tools/measure-loudness.js +40 -0
- package/dist/tools/measure-loudness.js.map +1 -0
- package/dist/tools/mix-audio.d.ts +46 -0
- package/dist/tools/mix-audio.d.ts.map +1 -0
- package/dist/tools/mix-audio.js +101 -0
- package/dist/tools/mix-audio.js.map +1 -0
- package/dist/tools/multicam-sync.d.ts +14 -0
- package/dist/tools/multicam-sync.d.ts.map +1 -0
- package/dist/tools/multicam-sync.js +75 -0
- package/dist/tools/multicam-sync.js.map +1 -0
- package/dist/tools/new-tools.test.d.ts +2 -0
- package/dist/tools/new-tools.test.d.ts.map +1 -0
- package/dist/tools/new-tools.test.js +511 -0
- package/dist/tools/new-tools.test.js.map +1 -0
- package/dist/tools/normalize-loudness.d.ts +21 -0
- package/dist/tools/normalize-loudness.d.ts.map +1 -0
- package/dist/tools/normalize-loudness.js +94 -0
- package/dist/tools/normalize-loudness.js.map +1 -0
- package/dist/tools/open-page.d.ts +17 -0
- package/dist/tools/open-page.d.ts.map +1 -0
- package/dist/tools/open-page.js +27 -0
- package/dist/tools/open-page.js.map +1 -0
- package/dist/tools/overlay-watermark.d.ts +28 -0
- package/dist/tools/overlay-watermark.d.ts.map +1 -0
- package/dist/tools/overlay-watermark.js +98 -0
- package/dist/tools/overlay-watermark.js.map +1 -0
- package/dist/tools/pick-best-takes.d.ts +20 -0
- package/dist/tools/pick-best-takes.d.ts.map +1 -0
- package/dist/tools/pick-best-takes.js +147 -0
- package/dist/tools/pick-best-takes.js.map +1 -0
- package/dist/tools/post-tools.test.d.ts +2 -0
- package/dist/tools/post-tools.test.d.ts.map +1 -0
- package/dist/tools/post-tools.test.js +83 -0
- package/dist/tools/post-tools.test.js.map +1 -0
- package/dist/tools/pre-render-check.d.ts +23 -0
- package/dist/tools/pre-render-check.d.ts.map +1 -0
- package/dist/tools/pre-render-check.js +134 -0
- package/dist/tools/pre-render-check.js.map +1 -0
- package/dist/tools/probe-media.d.ts +8 -0
- package/dist/tools/probe-media.d.ts.map +1 -0
- package/dist/tools/probe-media.js +32 -0
- package/dist/tools/probe-media.js.map +1 -0
- package/dist/tools/punch-in.d.ts +30 -0
- package/dist/tools/punch-in.d.ts.map +1 -0
- package/dist/tools/punch-in.js +130 -0
- package/dist/tools/punch-in.js.map +1 -0
- package/dist/tools/read-skill.d.ts +9 -0
- package/dist/tools/read-skill.d.ts.map +1 -0
- package/dist/tools/read-skill.js +24 -0
- package/dist/tools/read-skill.js.map +1 -0
- package/dist/tools/read-transcript.d.ts +14 -0
- package/dist/tools/read-transcript.d.ts.map +1 -0
- package/dist/tools/read-transcript.js +85 -0
- package/dist/tools/read-transcript.js.map +1 -0
- package/dist/tools/read-transcript.test.d.ts +2 -0
- package/dist/tools/read-transcript.test.d.ts.map +1 -0
- package/dist/tools/read-transcript.test.js +136 -0
- package/dist/tools/read-transcript.test.js.map +1 -0
- package/dist/tools/reformat-timeline.d.ts +25 -0
- package/dist/tools/reformat-timeline.d.ts.map +1 -0
- package/dist/tools/reformat-timeline.js +60 -0
- package/dist/tools/reformat-timeline.js.map +1 -0
- package/dist/tools/render.d.ts +10 -0
- package/dist/tools/render.d.ts.map +1 -0
- package/dist/tools/render.js +26 -0
- package/dist/tools/render.js.map +1 -0
- package/dist/tools/reorder-timeline.d.ts +12 -0
- package/dist/tools/reorder-timeline.d.ts.map +1 -0
- package/dist/tools/reorder-timeline.js +65 -0
- package/dist/tools/reorder-timeline.js.map +1 -0
- package/dist/tools/replace-clip.d.ts +10 -0
- package/dist/tools/replace-clip.d.ts.map +1 -0
- package/dist/tools/replace-clip.js +28 -0
- package/dist/tools/replace-clip.js.map +1 -0
- package/dist/tools/review-edit.d.ts +23 -0
- package/dist/tools/review-edit.d.ts.map +1 -0
- package/dist/tools/review-edit.js +47 -0
- package/dist/tools/review-edit.js.map +1 -0
- package/dist/tools/ripple-delete.d.ts +11 -0
- package/dist/tools/ripple-delete.d.ts.map +1 -0
- package/dist/tools/ripple-delete.js +27 -0
- package/dist/tools/ripple-delete.js.map +1 -0
- package/dist/tools/save-project.d.ts +7 -0
- package/dist/tools/save-project.d.ts.map +1 -0
- package/dist/tools/save-project.js +22 -0
- package/dist/tools/save-project.js.map +1 -0
- package/dist/tools/score-shot.d.ts +18 -0
- package/dist/tools/score-shot.d.ts.map +1 -0
- package/dist/tools/score-shot.js +127 -0
- package/dist/tools/score-shot.js.map +1 -0
- package/dist/tools/set-clip-speed.d.ts +10 -0
- package/dist/tools/set-clip-speed.d.ts.map +1 -0
- package/dist/tools/set-clip-speed.js +28 -0
- package/dist/tools/set-clip-speed.js.map +1 -0
- package/dist/tools/set-clip-volume.d.ts +10 -0
- package/dist/tools/set-clip-volume.d.ts.map +1 -0
- package/dist/tools/set-clip-volume.js +33 -0
- package/dist/tools/set-clip-volume.js.map +1 -0
- package/dist/tools/set-primary-correction.d.ts +14 -0
- package/dist/tools/set-primary-correction.d.ts.map +1 -0
- package/dist/tools/set-primary-correction.js +45 -0
- package/dist/tools/set-primary-correction.js.map +1 -0
- package/dist/tools/smart-reframe.d.ts +22 -0
- package/dist/tools/smart-reframe.d.ts.map +1 -0
- package/dist/tools/smart-reframe.js +39 -0
- package/dist/tools/smart-reframe.js.map +1 -0
- package/dist/tools/speed-ramp.d.ts +14 -0
- package/dist/tools/speed-ramp.d.ts.map +1 -0
- package/dist/tools/speed-ramp.js +71 -0
- package/dist/tools/speed-ramp.js.map +1 -0
- package/dist/tools/stabilize-video.d.ts +12 -0
- package/dist/tools/stabilize-video.d.ts.map +1 -0
- package/dist/tools/stabilize-video.js +63 -0
- package/dist/tools/stabilize-video.js.map +1 -0
- package/dist/tools/transcribe.d.ts +29 -0
- package/dist/tools/transcribe.d.ts.map +1 -0
- package/dist/tools/transcribe.js +116 -0
- package/dist/tools/transcribe.js.map +1 -0
- package/dist/tools/transition-videos.d.ts +29 -0
- package/dist/tools/transition-videos.d.ts.map +1 -0
- package/dist/tools/transition-videos.js +129 -0
- package/dist/tools/transition-videos.js.map +1 -0
- package/dist/tools/write-ass.d.ts +34 -0
- package/dist/tools/write-ass.d.ts.map +1 -0
- package/dist/tools/write-ass.js +101 -0
- package/dist/tools/write-ass.js.map +1 -0
- package/dist/tools/write-edl.d.ts +24 -0
- package/dist/tools/write-edl.d.ts.map +1 -0
- package/dist/tools/write-edl.js +59 -0
- package/dist/tools/write-edl.js.map +1 -0
- package/dist/tools/write-fcpxml.d.ts +20 -0
- package/dist/tools/write-fcpxml.d.ts.map +1 -0
- package/dist/tools/write-fcpxml.js +52 -0
- package/dist/tools/write-fcpxml.js.map +1 -0
- package/dist/tools/write-keyword-captions.d.ts +36 -0
- package/dist/tools/write-keyword-captions.d.ts.map +1 -0
- package/dist/tools/write-keyword-captions.js +183 -0
- package/dist/tools/write-keyword-captions.js.map +1 -0
- package/dist/tools/write-lower-third.d.ts +34 -0
- package/dist/tools/write-lower-third.d.ts.map +1 -0
- package/dist/tools/write-lower-third.js +52 -0
- package/dist/tools/write-lower-third.js.map +1 -0
- package/dist/tools/write-srt.d.ts +20 -0
- package/dist/tools/write-srt.d.ts.map +1 -0
- package/dist/tools/write-srt.js +72 -0
- package/dist/tools/write-srt.js.map +1 -0
- package/dist/tools/write-title-card.d.ts +25 -0
- package/dist/tools/write-title-card.d.ts.map +1 -0
- package/dist/tools/write-title-card.js +57 -0
- package/dist/tools/write-title-card.js.map +1 -0
- package/dist/types.d.ts +83 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/dist/ui/App.d.ts +44 -0
- package/dist/ui/App.d.ts.map +1 -0
- package/dist/ui/App.js +454 -0
- package/dist/ui/App.js.map +1 -0
- package/dist/ui/components/Banner.d.ts +13 -0
- package/dist/ui/components/Banner.d.ts.map +1 -0
- package/dist/ui/components/Banner.js +59 -0
- package/dist/ui/components/Banner.js.map +1 -0
- package/dist/ui/components/Footer.d.ts +19 -0
- package/dist/ui/components/Footer.d.ts.map +1 -0
- package/dist/ui/components/Footer.js +20 -0
- package/dist/ui/components/Footer.js.map +1 -0
- package/dist/ui/components/Header.d.ts +16 -0
- package/dist/ui/components/Header.d.ts.map +1 -0
- package/dist/ui/components/Header.js +12 -0
- package/dist/ui/components/Header.js.map +1 -0
- package/dist/ui/components/InputBox.d.ts +21 -0
- package/dist/ui/components/InputBox.d.ts.map +1 -0
- package/dist/ui/components/InputBox.js +81 -0
- package/dist/ui/components/InputBox.js.map +1 -0
- package/dist/ui/components/Message.d.ts +14 -0
- package/dist/ui/components/Message.d.ts.map +1 -0
- package/dist/ui/components/Message.js +24 -0
- package/dist/ui/components/Message.js.map +1 -0
- package/dist/ui/components/SlashMenu.d.ts +19 -0
- package/dist/ui/components/SlashMenu.d.ts.map +1 -0
- package/dist/ui/components/SlashMenu.js +33 -0
- package/dist/ui/components/SlashMenu.js.map +1 -0
- package/dist/ui/components/SlashMenu.test.d.ts +2 -0
- package/dist/ui/components/SlashMenu.test.d.ts.map +1 -0
- package/dist/ui/components/SlashMenu.test.js +23 -0
- package/dist/ui/components/SlashMenu.test.js.map +1 -0
- package/dist/ui/components/Spinner.d.ts +6 -0
- package/dist/ui/components/Spinner.d.ts.map +1 -0
- package/dist/ui/components/Spinner.js +16 -0
- package/dist/ui/components/Spinner.js.map +1 -0
- package/dist/ui/components/ToolCallLine.d.ts +16 -0
- package/dist/ui/components/ToolCallLine.d.ts.map +1 -0
- package/dist/ui/components/ToolCallLine.js +35 -0
- package/dist/ui/components/ToolCallLine.js.map +1 -0
- package/dist/ui/render.d.ts +9 -0
- package/dist/ui/render.d.ts.map +1 -0
- package/dist/ui/render.js +56 -0
- package/dist/ui/render.js.map +1 -0
- package/dist/ui/spinner-frames.d.ts +3 -0
- package/dist/ui/spinner-frames.d.ts.map +1 -0
- package/dist/ui/spinner-frames.js +16 -0
- package/dist/ui/spinner-frames.js.map +1 -0
- package/dist/ui/theme.d.ts +27 -0
- package/dist/ui/theme.d.ts.map +1 -0
- package/dist/ui/theme.js +26 -0
- package/dist/ui/theme.js.map +1 -0
- package/package.json +50 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export interface TransientResult {
|
|
2
|
+
path: string;
|
|
3
|
+
/** Seconds from file start where the first audible event begins, or null. */
|
|
4
|
+
transientSec: number | null;
|
|
5
|
+
}
|
|
6
|
+
export interface MulticamSyncResult {
|
|
7
|
+
/** Path used as the t=0 reference (transient closest to file start). */
|
|
8
|
+
reference: string;
|
|
9
|
+
results: Array<{
|
|
10
|
+
path: string;
|
|
11
|
+
/** Positive = file starts later than reference. null = no transient detected. */
|
|
12
|
+
offsetSec: number | null;
|
|
13
|
+
transientSec: number | null;
|
|
14
|
+
}>;
|
|
15
|
+
thresholdDb: number;
|
|
16
|
+
/** Set if any input had no detectable transient. */
|
|
17
|
+
warning?: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Detect the first transient (end of leading silence) in a media file.
|
|
21
|
+
*
|
|
22
|
+
* Runs `silencedetect` with a strict noise floor and a long min-silence so the
|
|
23
|
+
* lead-in counts as silence; the first `silence_end` is the first audible event.
|
|
24
|
+
*/
|
|
25
|
+
export declare function detectFirstTransient(inputPath: string, opts?: {
|
|
26
|
+
thresholdDb?: number;
|
|
27
|
+
minSilenceSec?: number;
|
|
28
|
+
signal?: AbortSignal;
|
|
29
|
+
}): Promise<TransientResult>;
|
|
30
|
+
/**
|
|
31
|
+
* Align 2+ inputs by their first transient. Pick the input with the smallest
|
|
32
|
+
* transient as reference (transient at t=0 in the synced timeline). Other
|
|
33
|
+
* offsets = transient[i] - reference.transient.
|
|
34
|
+
*/
|
|
35
|
+
export declare function multicamSync(inputPaths: string[], opts?: {
|
|
36
|
+
thresholdDb?: number;
|
|
37
|
+
minSilenceSec?: number;
|
|
38
|
+
signal?: AbortSignal;
|
|
39
|
+
}): Promise<MulticamSyncResult>;
|
|
40
|
+
//# sourceMappingURL=multicam.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"multicam.d.ts","sourceRoot":"","sources":["../../src/core/multicam.ts"],"names":[],"mappings":"AAWA,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,6EAA6E;IAC7E,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAED,MAAM,WAAW,kBAAkB;IACjC,wEAAwE;IACxE,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,KAAK,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,iFAAiF;QACjF,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;QACzB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;KAC7B,CAAC,CAAC;IACH,WAAW,EAAE,MAAM,CAAC;IACpB,oDAAoD;IACpD,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;GAKG;AACH,wBAAsB,oBAAoB,CACxC,SAAS,EAAE,MAAM,EACjB,IAAI,GAAE;IAAE,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,WAAW,CAAA;CAAO,GAChF,OAAO,CAAC,eAAe,CAAC,CAyB1B;AAED;;;;GAIG;AACH,wBAAsB,YAAY,CAChC,UAAU,EAAE,MAAM,EAAE,EACpB,IAAI,GAAE;IAAE,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,WAAW,CAAA;CAAO,GAChF,OAAO,CAAC,kBAAkB,CAAC,CA2C7B"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Multicam clap-sync — first-transient alignment via ffmpeg silencedetect.
|
|
3
|
+
*
|
|
4
|
+
* v1 limitation: works only when each take starts with a clap, slate, or sharp
|
|
5
|
+
* sound louder than the surrounding lead-in silence. For dialogue-only takes
|
|
6
|
+
* with no slate, this tool can't align — that needs cross-correlation, deferred
|
|
7
|
+
* to a future v2 (would require an FFT lib or numpy).
|
|
8
|
+
*/
|
|
9
|
+
import { runFfmpeg } from "./media/ffmpeg.js";
|
|
10
|
+
import { parseSilenceDetect } from "./silence.js";
|
|
11
|
+
/**
|
|
12
|
+
* Detect the first transient (end of leading silence) in a media file.
|
|
13
|
+
*
|
|
14
|
+
* Runs `silencedetect` with a strict noise floor and a long min-silence so the
|
|
15
|
+
* lead-in counts as silence; the first `silence_end` is the first audible event.
|
|
16
|
+
*/
|
|
17
|
+
export async function detectFirstTransient(inputPath, opts = {}) {
|
|
18
|
+
const thresholdDb = opts.thresholdDb ?? -40;
|
|
19
|
+
const minSilenceSec = opts.minSilenceSec ?? 0.5;
|
|
20
|
+
const r = await runFfmpeg([
|
|
21
|
+
"-i",
|
|
22
|
+
inputPath,
|
|
23
|
+
"-af",
|
|
24
|
+
`silencedetect=noise=${thresholdDb}dB:d=${minSilenceSec}`,
|
|
25
|
+
"-f",
|
|
26
|
+
"null",
|
|
27
|
+
"-",
|
|
28
|
+
], { signal: opts.signal });
|
|
29
|
+
if (r.code !== 0) {
|
|
30
|
+
return { path: inputPath, transientSec: null };
|
|
31
|
+
}
|
|
32
|
+
const ranges = parseSilenceDetect(r.stderr);
|
|
33
|
+
// The first range's endSec is the first transient (end of lead-in silence).
|
|
34
|
+
const first = ranges[0];
|
|
35
|
+
return {
|
|
36
|
+
path: inputPath,
|
|
37
|
+
transientSec: first ? first.endSec : null,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Align 2+ inputs by their first transient. Pick the input with the smallest
|
|
42
|
+
* transient as reference (transient at t=0 in the synced timeline). Other
|
|
43
|
+
* offsets = transient[i] - reference.transient.
|
|
44
|
+
*/
|
|
45
|
+
export async function multicamSync(inputPaths, opts = {}) {
|
|
46
|
+
if (inputPaths.length === 0) {
|
|
47
|
+
throw new Error("multicamSync: inputs is empty");
|
|
48
|
+
}
|
|
49
|
+
const thresholdDb = opts.thresholdDb ?? -40;
|
|
50
|
+
const transients = await Promise.all(inputPaths.map((p) => detectFirstTransient(p, {
|
|
51
|
+
thresholdDb,
|
|
52
|
+
minSilenceSec: opts.minSilenceSec,
|
|
53
|
+
signal: opts.signal,
|
|
54
|
+
})));
|
|
55
|
+
// Pick reference: smallest finite transient. If all null, fall back to first.
|
|
56
|
+
const withTransient = transients.filter((t) => t.transientSec !== null);
|
|
57
|
+
const reference = withTransient.length > 0
|
|
58
|
+
? withTransient.reduce((acc, t) => t.transientSec < acc.transientSec ? t : acc)
|
|
59
|
+
: transients[0];
|
|
60
|
+
const refSec = reference.transientSec ?? 0;
|
|
61
|
+
const results = transients.map((t) => ({
|
|
62
|
+
path: t.path,
|
|
63
|
+
transientSec: t.transientSec,
|
|
64
|
+
offsetSec: t.transientSec === null ? null : +(t.transientSec - refSec).toFixed(6),
|
|
65
|
+
}));
|
|
66
|
+
const missing = results.filter((r) => r.offsetSec === null);
|
|
67
|
+
const warning = missing.length > 0
|
|
68
|
+
? `no transient detected for ${missing.length} of ${results.length} input(s); manual alignment needed`
|
|
69
|
+
: undefined;
|
|
70
|
+
return {
|
|
71
|
+
reference: reference.path,
|
|
72
|
+
results,
|
|
73
|
+
thresholdDb,
|
|
74
|
+
warning,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=multicam.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"multicam.js","sourceRoot":"","sources":["../../src/core/multicam.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAC9C,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAsBlD;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,SAAiB,EACjB,OAA+E,EAAE;IAEjF,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,IAAI,CAAC,EAAE,CAAC;IAC5C,MAAM,aAAa,GAAG,IAAI,CAAC,aAAa,IAAI,GAAG,CAAC;IAChD,MAAM,CAAC,GAAG,MAAM,SAAS,CACvB;QACE,IAAI;QACJ,SAAS;QACT,KAAK;QACL,uBAAuB,WAAW,QAAQ,aAAa,EAAE;QACzD,IAAI;QACJ,MAAM;QACN,GAAG;KACJ,EACD,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CACxB,CAAC;IACF,IAAI,CAAC,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;QACjB,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC;IACjD,CAAC;IACD,MAAM,MAAM,GAAG,kBAAkB,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;IAC5C,4EAA4E;IAC5E,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;IACxB,OAAO;QACL,IAAI,EAAE,SAAS;QACf,YAAY,EAAE,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI;KAC1C,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,UAAoB,EACpB,OAA+E,EAAE;IAEjF,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;IACnD,CAAC;IACD,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,IAAI,CAAC,EAAE,CAAC;IAC5C,MAAM,UAAU,GAAG,MAAM,OAAO,CAAC,GAAG,CAClC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CACnB,oBAAoB,CAAC,CAAC,EAAE;QACtB,WAAW;QACX,aAAa,EAAE,IAAI,CAAC,aAAa;QACjC,MAAM,EAAE,IAAI,CAAC,MAAM;KACpB,CAAC,CACH,CACF,CAAC;IAEF,8EAA8E;IAC9E,MAAM,aAAa,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,YAAY,KAAK,IAAI,CAAC,CAAC;IACxE,MAAM,SAAS,GACb,aAAa,CAAC,MAAM,GAAG,CAAC;QACtB,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAC7B,CAAC,CAAC,YAAuB,GAAI,GAAG,CAAC,YAAuB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CACpE;QACH,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;IACpB,MAAM,MAAM,GAAG,SAAS,CAAC,YAAY,IAAI,CAAC,CAAC;IAE3C,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACrC,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,YAAY,EAAE,CAAC,CAAC,YAAY;QAC5B,SAAS,EAAE,CAAC,CAAC,YAAY,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY,GAAG,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;KAClF,CAAC,CAAC,CAAC;IAEJ,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,KAAK,IAAI,CAAC,CAAC;IAC5D,MAAM,OAAO,GACX,OAAO,CAAC,MAAM,GAAG,CAAC;QAChB,CAAC,CAAC,6BAA6B,OAAO,CAAC,MAAM,OAAO,OAAO,CAAC,MAAM,oCAAoC;QACtG,CAAC,CAAC,SAAS,CAAC;IAEhB,OAAO;QACL,SAAS,EAAE,SAAS,CAAC,IAAI;QACzB,OAAO;QACP,WAAW;QACX,OAAO;KACR,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"multicam.test.d.ts","sourceRoot":"","sources":["../../src/core/multicam.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { describe, expect, it, vi, beforeEach } from "vitest";
|
|
2
|
+
import * as ffmpeg from "./media/ffmpeg.js";
|
|
3
|
+
import { multicamSync } from "./multicam.js";
|
|
4
|
+
function silenceStderr(endSec) {
|
|
5
|
+
if (endSec === null)
|
|
6
|
+
return "";
|
|
7
|
+
return `[silencedetect @ 0x1] silence_start: 0.0\n[silencedetect @ 0x1] silence_end: ${endSec} | silence_duration: ${endSec}\n`;
|
|
8
|
+
}
|
|
9
|
+
describe("multicamSync", () => {
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
vi.restoreAllMocks();
|
|
12
|
+
});
|
|
13
|
+
it("picks the input with the smallest transient as reference", async () => {
|
|
14
|
+
// a=2.0s, b=0.5s, c=1.2s — b should be reference (smallest).
|
|
15
|
+
const map = { "/a.wav": 2.0, "/b.wav": 0.5, "/c.wav": 1.2 };
|
|
16
|
+
vi.spyOn(ffmpeg, "runFfmpeg").mockImplementation(async (args) => {
|
|
17
|
+
const path = args[args.indexOf("-i") + 1];
|
|
18
|
+
return { code: 0, stdout: "", stderr: silenceStderr(map[path] ?? null) };
|
|
19
|
+
});
|
|
20
|
+
const r = await multicamSync(["/a.wav", "/b.wav", "/c.wav"]);
|
|
21
|
+
expect(r.reference).toBe("/b.wav");
|
|
22
|
+
expect(r.warning).toBeUndefined();
|
|
23
|
+
const byPath = Object.fromEntries(r.results.map((x) => [x.path, x.offsetSec]));
|
|
24
|
+
expect(byPath["/b.wav"]).toBe(0);
|
|
25
|
+
expect(byPath["/a.wav"]).toBeCloseTo(1.5);
|
|
26
|
+
expect(byPath["/c.wav"]).toBeCloseTo(0.7);
|
|
27
|
+
});
|
|
28
|
+
it("emits a warning and null offset for files with no transient", async () => {
|
|
29
|
+
const map = { "/x.wav": 1.0, "/y.wav": null };
|
|
30
|
+
vi.spyOn(ffmpeg, "runFfmpeg").mockImplementation(async (args) => {
|
|
31
|
+
const path = args[args.indexOf("-i") + 1];
|
|
32
|
+
return { code: 0, stdout: "", stderr: silenceStderr(map[path] ?? null) };
|
|
33
|
+
});
|
|
34
|
+
const r = await multicamSync(["/x.wav", "/y.wav"]);
|
|
35
|
+
expect(r.reference).toBe("/x.wav");
|
|
36
|
+
const yResult = r.results.find((x) => x.path === "/y.wav");
|
|
37
|
+
expect(yResult?.offsetSec).toBeNull();
|
|
38
|
+
expect(yResult?.transientSec).toBeNull();
|
|
39
|
+
expect(r.warning).toMatch(/no transient detected for 1 of 2/);
|
|
40
|
+
});
|
|
41
|
+
it("trivially handles a single-file input", async () => {
|
|
42
|
+
vi.spyOn(ffmpeg, "runFfmpeg").mockResolvedValue({
|
|
43
|
+
code: 0,
|
|
44
|
+
stdout: "",
|
|
45
|
+
stderr: silenceStderr(0.8),
|
|
46
|
+
});
|
|
47
|
+
const r = await multicamSync(["/solo.wav"]);
|
|
48
|
+
expect(r.reference).toBe("/solo.wav");
|
|
49
|
+
expect(r.results).toHaveLength(1);
|
|
50
|
+
expect(r.results[0].offsetSec).toBe(0);
|
|
51
|
+
});
|
|
52
|
+
it("rejects empty input", async () => {
|
|
53
|
+
await expect(multicamSync([])).rejects.toThrow(/empty/);
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
//# sourceMappingURL=multicam.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"multicam.test.js","sourceRoot":"","sources":["../../src/core/multicam.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Punch-in (digital zoom on cuts) — the canonical YouTuber trick to
|
|
3
|
+
* disguise jump cuts on a single-camera talking head. Cut filler →
|
|
4
|
+
* punch in slightly on the kept side → the head-jerk vanishes.
|
|
5
|
+
*
|
|
6
|
+
* We implement this with an ffmpeg `crop` filter whose width / height /
|
|
7
|
+
* x / y values are EXPRESSIONS that depend on `t` (current frame
|
|
8
|
+
* timestamp). Outside any punch range, expressions evaluate to a
|
|
9
|
+
* full-frame crop (no-op). Inside a range, they evaluate to a centered
|
|
10
|
+
* sub-frame crop, then a `scale` brings it back to the original size.
|
|
11
|
+
*
|
|
12
|
+
* One ffmpeg pass, no segmenting + concat — fast and simple.
|
|
13
|
+
*
|
|
14
|
+
* The math, for a punch range with zoom Z (>1, e.g. 1.10 = 10% punch):
|
|
15
|
+
* crop_w = floor(iw / Z)
|
|
16
|
+
* crop_h = floor(ih / Z)
|
|
17
|
+
* crop_x = floor((iw - crop_w) / 2)
|
|
18
|
+
* crop_y = floor((ih - crop_h) / 2)
|
|
19
|
+
*
|
|
20
|
+
* To stitch multiple ranges into a single expression, we wrap each
|
|
21
|
+
* tier in `if(between(t, a, b), <punched>, <prev>)`, falling back to a
|
|
22
|
+
* full-frame crop outside any range.
|
|
23
|
+
*
|
|
24
|
+
* Pure logic; the tool wrapper handles ffmpeg invocation.
|
|
25
|
+
*/
|
|
26
|
+
export interface PunchInRange {
|
|
27
|
+
/** Range start (seconds, inclusive). */
|
|
28
|
+
startSec: number;
|
|
29
|
+
/** Range end (seconds, inclusive). */
|
|
30
|
+
endSec: number;
|
|
31
|
+
/**
|
|
32
|
+
* Zoom multiplier. 1.10 = 10% punch (subtle, the YouTuber default).
|
|
33
|
+
* 1.0 = no zoom (effectively skipped). Clamped to [1.0, 2.0].
|
|
34
|
+
*/
|
|
35
|
+
zoom: number;
|
|
36
|
+
}
|
|
37
|
+
export interface PunchInOptions {
|
|
38
|
+
/**
|
|
39
|
+
* Default zoom for ranges where `zoom` is omitted. Default 1.10.
|
|
40
|
+
* 1.05 is barely perceptible; 1.15 is a clear pop; >1.20 looks like
|
|
41
|
+
* an effect rather than a hidden cut.
|
|
42
|
+
*/
|
|
43
|
+
defaultZoom?: number;
|
|
44
|
+
/**
|
|
45
|
+
* Optional smoothing window (seconds) at each edge to prevent the
|
|
46
|
+
* crop from snapping. The crop gradually ramps from 1.0 → zoom over
|
|
47
|
+
* `rampSec` at the start, and back at the end. Default 0 (instant).
|
|
48
|
+
* Use ~0.08s for subtle, ~0.15s for a noticeable push-in.
|
|
49
|
+
*/
|
|
50
|
+
rampSec?: number;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Build the `-vf` value for ffmpeg that applies all punch ranges in
|
|
54
|
+
* order. Returns the empty string if there are no ranges (no-op
|
|
55
|
+
* caller can decide whether to skip ffmpeg altogether).
|
|
56
|
+
*
|
|
57
|
+
* The filter is structured as `crop=W:H:X:Y,scale=iw_orig:ih_orig`,
|
|
58
|
+
* where W/H/X/Y are nested if-expressions evaluated per-frame.
|
|
59
|
+
*/
|
|
60
|
+
export declare function buildPunchInFilter(ranges: PunchInRange[], origWidth: number, origHeight: number, opts?: PunchInOptions): string;
|
|
61
|
+
/**
|
|
62
|
+
* Auto-derive punch-in ranges from a list of cut points (e.g. the
|
|
63
|
+
* timestamps of every silence-cut or filler-cut). One short punch
|
|
64
|
+
* after each cut hides the discontinuity.
|
|
65
|
+
*
|
|
66
|
+
* @param cutPoints Seconds where cuts happen.
|
|
67
|
+
* @param totalSec Media duration (so the last range gets clipped).
|
|
68
|
+
* @param holdSec How long each punch lasts after the cut. Default 1.5s.
|
|
69
|
+
* @param zoom Zoom multiplier. Default 1.10.
|
|
70
|
+
*/
|
|
71
|
+
export declare function punchInsAfterCuts(cutPoints: number[], totalSec: number, holdSec?: number, zoom?: number): PunchInRange[];
|
|
72
|
+
//# sourceMappingURL=punch-in.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"punch-in.d.ts","sourceRoot":"","sources":["../../src/core/punch-in.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,MAAM,WAAW,YAAY;IAC3B,wCAAwC;IACxC,QAAQ,EAAE,MAAM,CAAC;IACjB,sCAAsC;IACtC,MAAM,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,cAAc;IAC7B;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;OAKG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,YAAY,EAAE,EACtB,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,IAAI,GAAE,cAAmB,GACxB,MAAM,CAqCR;AA+BD;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,MAAM,EAAE,EACnB,QAAQ,EAAE,MAAM,EAChB,OAAO,SAAM,EACb,IAAI,SAAM,GACT,YAAY,EAAE,CAYhB"}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Punch-in (digital zoom on cuts) — the canonical YouTuber trick to
|
|
3
|
+
* disguise jump cuts on a single-camera talking head. Cut filler →
|
|
4
|
+
* punch in slightly on the kept side → the head-jerk vanishes.
|
|
5
|
+
*
|
|
6
|
+
* We implement this with an ffmpeg `crop` filter whose width / height /
|
|
7
|
+
* x / y values are EXPRESSIONS that depend on `t` (current frame
|
|
8
|
+
* timestamp). Outside any punch range, expressions evaluate to a
|
|
9
|
+
* full-frame crop (no-op). Inside a range, they evaluate to a centered
|
|
10
|
+
* sub-frame crop, then a `scale` brings it back to the original size.
|
|
11
|
+
*
|
|
12
|
+
* One ffmpeg pass, no segmenting + concat — fast and simple.
|
|
13
|
+
*
|
|
14
|
+
* The math, for a punch range with zoom Z (>1, e.g. 1.10 = 10% punch):
|
|
15
|
+
* crop_w = floor(iw / Z)
|
|
16
|
+
* crop_h = floor(ih / Z)
|
|
17
|
+
* crop_x = floor((iw - crop_w) / 2)
|
|
18
|
+
* crop_y = floor((ih - crop_h) / 2)
|
|
19
|
+
*
|
|
20
|
+
* To stitch multiple ranges into a single expression, we wrap each
|
|
21
|
+
* tier in `if(between(t, a, b), <punched>, <prev>)`, falling back to a
|
|
22
|
+
* full-frame crop outside any range.
|
|
23
|
+
*
|
|
24
|
+
* Pure logic; the tool wrapper handles ffmpeg invocation.
|
|
25
|
+
*/
|
|
26
|
+
/**
|
|
27
|
+
* Build the `-vf` value for ffmpeg that applies all punch ranges in
|
|
28
|
+
* order. Returns the empty string if there are no ranges (no-op
|
|
29
|
+
* caller can decide whether to skip ffmpeg altogether).
|
|
30
|
+
*
|
|
31
|
+
* The filter is structured as `crop=W:H:X:Y,scale=iw_orig:ih_orig`,
|
|
32
|
+
* where W/H/X/Y are nested if-expressions evaluated per-frame.
|
|
33
|
+
*/
|
|
34
|
+
export function buildPunchInFilter(ranges, origWidth, origHeight, opts = {}) {
|
|
35
|
+
if (origWidth <= 0 || origHeight <= 0) {
|
|
36
|
+
throw new Error("origWidth and origHeight must be positive");
|
|
37
|
+
}
|
|
38
|
+
const defaultZoom = clampZoom(opts.defaultZoom ?? 1.1);
|
|
39
|
+
const ramp = Math.max(0, opts.rampSec ?? 0);
|
|
40
|
+
const cleaned = ranges
|
|
41
|
+
.map((r) => ({
|
|
42
|
+
startSec: r.startSec,
|
|
43
|
+
endSec: r.endSec,
|
|
44
|
+
zoom: clampZoom(r.zoom || defaultZoom),
|
|
45
|
+
}))
|
|
46
|
+
.filter((r) => r.endSec > r.startSec && r.zoom > 1.0001)
|
|
47
|
+
.sort((a, b) => a.startSec - b.startSec);
|
|
48
|
+
if (cleaned.length === 0)
|
|
49
|
+
return "";
|
|
50
|
+
// We construct one expression for the crop WIDTH and one for HEIGHT.
|
|
51
|
+
// X/Y are derived as (orig - crop) / 2 inside ffmpeg's expression
|
|
52
|
+
// language so we don't need to repeat the zoom logic.
|
|
53
|
+
//
|
|
54
|
+
// Effective per-range zoom (with ramp):
|
|
55
|
+
// rampedZoom(t) = 1 + (Z - 1) * clamp01(min((t - a)/ramp, (b - t)/ramp))
|
|
56
|
+
// when ramp > 0; otherwise just Z.
|
|
57
|
+
const widthExpr = buildSizeExpr(cleaned, "iw", ramp);
|
|
58
|
+
const heightExpr = buildSizeExpr(cleaned, "ih", ramp);
|
|
59
|
+
// x,y center the crop. ffmpeg: `(iw-out_w)/2`, `(ih-out_h)/2` — using
|
|
60
|
+
// the special vars `out_w` / `out_h` that reference the crop's own
|
|
61
|
+
// width / height expressions.
|
|
62
|
+
const cropFilter = `crop=w='${widthExpr}':h='${heightExpr}':x='(iw-out_w)/2':y='(ih-out_h)/2'`;
|
|
63
|
+
// Re-scale the (smaller) crop back to the source resolution so the
|
|
64
|
+
// output stream stays the same size as the input. Use lanczos for
|
|
65
|
+
// sharp upscale.
|
|
66
|
+
const scaleFilter = `scale=${origWidth}:${origHeight}:flags=lanczos`;
|
|
67
|
+
return `${cropFilter},${scaleFilter}`;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Build a piecewise expression for either the cropped width or height.
|
|
71
|
+
* `dim` is the ffmpeg variable for the source size ("iw" / "ih").
|
|
72
|
+
*/
|
|
73
|
+
function buildSizeExpr(ranges, dim, ramp) {
|
|
74
|
+
// Outside any range, the cropped dimension == source dimension (no-op).
|
|
75
|
+
let expr = dim;
|
|
76
|
+
// Build from the LAST range backwards so each `if(cond, then, else)`
|
|
77
|
+
// wraps the previously-built else-branch.
|
|
78
|
+
for (let i = ranges.length - 1; i >= 0; i--) {
|
|
79
|
+
const { startSec, endSec, zoom } = ranges[i];
|
|
80
|
+
const a = fmt(startSec);
|
|
81
|
+
const b = fmt(endSec);
|
|
82
|
+
let zExpr;
|
|
83
|
+
if (ramp > 0) {
|
|
84
|
+
// 1 + (Z-1) * clamp01(min((t-a)/ramp, (b-t)/ramp))
|
|
85
|
+
const r = fmt(ramp);
|
|
86
|
+
const factor = `clip(min((t-${a})/${r}\\,(${b}-t)/${r})\\,0\\,1)`;
|
|
87
|
+
zExpr = `(1+${fmt(zoom - 1)}*${factor})`;
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
zExpr = fmt(zoom);
|
|
91
|
+
}
|
|
92
|
+
// Cropped dim = source / zoom.
|
|
93
|
+
const inside = `${dim}/${zExpr}`;
|
|
94
|
+
expr = `if(between(t\\,${a}\\,${b})\\,${inside}\\,${expr})`;
|
|
95
|
+
}
|
|
96
|
+
return expr;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Auto-derive punch-in ranges from a list of cut points (e.g. the
|
|
100
|
+
* timestamps of every silence-cut or filler-cut). One short punch
|
|
101
|
+
* after each cut hides the discontinuity.
|
|
102
|
+
*
|
|
103
|
+
* @param cutPoints Seconds where cuts happen.
|
|
104
|
+
* @param totalSec Media duration (so the last range gets clipped).
|
|
105
|
+
* @param holdSec How long each punch lasts after the cut. Default 1.5s.
|
|
106
|
+
* @param zoom Zoom multiplier. Default 1.10.
|
|
107
|
+
*/
|
|
108
|
+
export function punchInsAfterCuts(cutPoints, totalSec, holdSec = 1.5, zoom = 1.1) {
|
|
109
|
+
const sorted = [...cutPoints].filter((t) => t >= 0 && t < totalSec).sort((a, b) => a - b);
|
|
110
|
+
const out = [];
|
|
111
|
+
for (let i = 0; i < sorted.length; i++) {
|
|
112
|
+
const start = sorted[i];
|
|
113
|
+
// Don't run a punch into the next cut.
|
|
114
|
+
const next = sorted[i + 1] ?? totalSec;
|
|
115
|
+
const end = Math.min(start + holdSec, next, totalSec);
|
|
116
|
+
if (end - start < 0.1)
|
|
117
|
+
continue; // skip tiny/no-op ranges
|
|
118
|
+
out.push({ startSec: start, endSec: end, zoom });
|
|
119
|
+
}
|
|
120
|
+
return out;
|
|
121
|
+
}
|
|
122
|
+
function fmt(n) {
|
|
123
|
+
if (!Number.isFinite(n))
|
|
124
|
+
return "0";
|
|
125
|
+
// Use 4 decimals; trim trailing zeros for shorter expressions.
|
|
126
|
+
return Number(n.toFixed(4)).toString();
|
|
127
|
+
}
|
|
128
|
+
function clampZoom(z) {
|
|
129
|
+
if (!Number.isFinite(z))
|
|
130
|
+
return 1;
|
|
131
|
+
return Math.max(1.0, Math.min(2.0, z));
|
|
132
|
+
}
|
|
133
|
+
//# sourceMappingURL=punch-in.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"punch-in.js","sourceRoot":"","sources":["../../src/core/punch-in.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AA8BH;;;;;;;GAOG;AACH,MAAM,UAAU,kBAAkB,CAChC,MAAsB,EACtB,SAAiB,EACjB,UAAkB,EAClB,OAAuB,EAAE;IAEzB,IAAI,SAAS,IAAI,CAAC,IAAI,UAAU,IAAI,CAAC,EAAE,CAAC;QACtC,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;IAC/D,CAAC;IACD,MAAM,WAAW,GAAG,SAAS,CAAC,IAAI,CAAC,WAAW,IAAI,GAAG,CAAC,CAAC;IACvD,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,OAAO,IAAI,CAAC,CAAC,CAAC;IAE5C,MAAM,OAAO,GAAG,MAAM;SACnB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACX,QAAQ,EAAE,CAAC,CAAC,QAAQ;QACpB,MAAM,EAAE,CAAC,CAAC,MAAM;QAChB,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC,IAAI,IAAI,WAAW,CAAC;KACvC,CAAC,CAAC;SACF,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,IAAI,GAAG,MAAM,CAAC;SACvD,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC;IAE3C,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAEpC,qEAAqE;IACrE,kEAAkE;IAClE,sDAAsD;IACtD,EAAE;IACF,wCAAwC;IACxC,2EAA2E;IAC3E,qCAAqC;IACrC,MAAM,SAAS,GAAG,aAAa,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IACrD,MAAM,UAAU,GAAG,aAAa,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IAEtD,sEAAsE;IACtE,mEAAmE;IACnE,8BAA8B;IAC9B,MAAM,UAAU,GAAG,WAAW,SAAS,QAAQ,UAAU,qCAAqC,CAAC;IAC/F,mEAAmE;IACnE,kEAAkE;IAClE,iBAAiB;IACjB,MAAM,WAAW,GAAG,SAAS,SAAS,IAAI,UAAU,gBAAgB,CAAC;IACrE,OAAO,GAAG,UAAU,IAAI,WAAW,EAAE,CAAC;AACxC,CAAC;AAED;;;GAGG;AACH,SAAS,aAAa,CAAC,MAAsB,EAAE,GAAgB,EAAE,IAAY;IAC3E,wEAAwE;IACxE,IAAI,IAAI,GAAW,GAAG,CAAC;IACvB,qEAAqE;IACrE,0CAA0C;IAC1C,KAAK,IAAI,CAAC,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC5C,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;QAC7C,MAAM,CAAC,GAAG,GAAG,CAAC,QAAQ,CAAC,CAAC;QACxB,MAAM,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC;QACtB,IAAI,KAAa,CAAC;QAClB,IAAI,IAAI,GAAG,CAAC,EAAE,CAAC;YACb,mDAAmD;YACnD,MAAM,CAAC,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC;YACpB,MAAM,MAAM,GAAG,eAAe,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,YAAY,CAAC;YAClE,KAAK,GAAG,MAAM,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,MAAM,GAAG,CAAC;QAC3C,CAAC;aAAM,CAAC;YACN,KAAK,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC;QACpB,CAAC;QACD,+BAA+B;QAC/B,MAAM,MAAM,GAAG,GAAG,GAAG,IAAI,KAAK,EAAE,CAAC;QACjC,IAAI,GAAG,kBAAkB,CAAC,MAAM,CAAC,OAAO,MAAM,MAAM,IAAI,GAAG,CAAC;IAC9D,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,iBAAiB,CAC/B,SAAmB,EACnB,QAAgB,EAChB,OAAO,GAAG,GAAG,EACb,IAAI,GAAG,GAAG;IAEV,MAAM,MAAM,GAAG,CAAC,GAAG,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAC1F,MAAM,GAAG,GAAmB,EAAE,CAAC;IAC/B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACvC,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;QACxB,uCAAuC;QACvC,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,QAAQ,CAAC;QACvC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,GAAG,OAAO,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;QACtD,IAAI,GAAG,GAAG,KAAK,GAAG,GAAG;YAAE,SAAS,CAAC,yBAAyB;QAC1D,GAAG,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;IACnD,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,GAAG,CAAC,CAAS;IACpB,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;QAAE,OAAO,GAAG,CAAC;IACpC,+DAA+D;IAC/D,OAAO,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;AACzC,CAAC;AAED,SAAS,SAAS,CAAC,CAAS;IAC1B,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;QAAE,OAAO,CAAC,CAAC;IAClC,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC;AACzC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"punch-in.test.d.ts","sourceRoot":"","sources":["../../src/core/punch-in.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { buildPunchInFilter, punchInsAfterCuts } from "./punch-in.js";
|
|
3
|
+
describe("buildPunchInFilter", () => {
|
|
4
|
+
it("returns empty string when there are no ranges", () => {
|
|
5
|
+
expect(buildPunchInFilter([], 1920, 1080)).toBe("");
|
|
6
|
+
});
|
|
7
|
+
it("emits a crop+scale filter for a single range", () => {
|
|
8
|
+
const f = buildPunchInFilter([{ startSec: 1, endSec: 2, zoom: 1.1 }], 1920, 1080);
|
|
9
|
+
expect(f).toContain("crop=");
|
|
10
|
+
expect(f).toContain("scale=1920:1080");
|
|
11
|
+
expect(f).toContain("between(t");
|
|
12
|
+
// Centered crop math:
|
|
13
|
+
expect(f).toContain("(iw-out_w)/2");
|
|
14
|
+
expect(f).toContain("(ih-out_h)/2");
|
|
15
|
+
// Inside the range, width = iw / zoom
|
|
16
|
+
expect(f).toContain("iw/1.1");
|
|
17
|
+
expect(f).toContain("ih/1.1");
|
|
18
|
+
});
|
|
19
|
+
it("nests multiple ranges into a single piecewise expression", () => {
|
|
20
|
+
const f = buildPunchInFilter([
|
|
21
|
+
{ startSec: 1, endSec: 2, zoom: 1.1 },
|
|
22
|
+
{ startSec: 5, endSec: 6, zoom: 1.2 },
|
|
23
|
+
], 1920, 1080);
|
|
24
|
+
// Both zoom levels appear:
|
|
25
|
+
expect(f).toContain("iw/1.1");
|
|
26
|
+
expect(f).toContain("iw/1.2");
|
|
27
|
+
// And both ranges:
|
|
28
|
+
expect(f).toContain("between(t\\,1\\,2)");
|
|
29
|
+
expect(f).toContain("between(t\\,5\\,6)");
|
|
30
|
+
});
|
|
31
|
+
it("falls through to a no-op (full source size) outside ranges", () => {
|
|
32
|
+
const f = buildPunchInFilter([{ startSec: 1, endSec: 2, zoom: 1.1 }], 1920, 1080);
|
|
33
|
+
// The ELSE branch of the outermost if() should reference iw / ih.
|
|
34
|
+
// Walk: if(between(t,1,2), iw/1.1, iw)
|
|
35
|
+
expect(f).toMatch(/iw\/1\.1\\,iw/);
|
|
36
|
+
expect(f).toMatch(/ih\/1\.1\\,ih/);
|
|
37
|
+
});
|
|
38
|
+
it("clamps zoom into [1.0, 2.0]", () => {
|
|
39
|
+
// 9.0 should clamp to 2.0; 0.5 should clamp to 1.0 (and then be filtered out).
|
|
40
|
+
const f = buildPunchInFilter([
|
|
41
|
+
{ startSec: 1, endSec: 2, zoom: 9.0 },
|
|
42
|
+
{ startSec: 3, endSec: 4, zoom: 0.5 },
|
|
43
|
+
], 1920, 1080);
|
|
44
|
+
expect(f).toContain("iw/2");
|
|
45
|
+
// The 0.5-zoom range collapses to a no-op and should be dropped:
|
|
46
|
+
expect(f).not.toContain("between(t\\,3\\,4)");
|
|
47
|
+
});
|
|
48
|
+
it("uses defaultZoom when an explicit zoom is missing or 0", () => {
|
|
49
|
+
const f = buildPunchInFilter([{ startSec: 1, endSec: 2, zoom: 0 }], 1920, 1080, {
|
|
50
|
+
defaultZoom: 1.15,
|
|
51
|
+
});
|
|
52
|
+
expect(f).toContain("iw/1.15");
|
|
53
|
+
});
|
|
54
|
+
it("applies a ramp expression when rampSec > 0", () => {
|
|
55
|
+
const f = buildPunchInFilter([{ startSec: 1, endSec: 2, zoom: 1.1 }], 1920, 1080, {
|
|
56
|
+
rampSec: 0.1,
|
|
57
|
+
});
|
|
58
|
+
expect(f).toContain("clip(");
|
|
59
|
+
expect(f).toContain("min(");
|
|
60
|
+
// Constant zoom term should NOT appear when ramping:
|
|
61
|
+
expect(f).not.toContain("iw/1.1,");
|
|
62
|
+
});
|
|
63
|
+
it("rejects non-positive source dimensions", () => {
|
|
64
|
+
expect(() => buildPunchInFilter([{ startSec: 0, endSec: 1, zoom: 1.1 }], 0, 1080)).toThrow();
|
|
65
|
+
expect(() => buildPunchInFilter([{ startSec: 0, endSec: 1, zoom: 1.1 }], 1920, -1)).toThrow();
|
|
66
|
+
});
|
|
67
|
+
it("drops zero-duration / inverted ranges", () => {
|
|
68
|
+
const f = buildPunchInFilter([
|
|
69
|
+
{ startSec: 1, endSec: 1, zoom: 1.1 },
|
|
70
|
+
{ startSec: 5, endSec: 4, zoom: 1.1 },
|
|
71
|
+
{ startSec: 10, endSec: 11, zoom: 1.1 },
|
|
72
|
+
], 1920, 1080);
|
|
73
|
+
expect(f).toContain("between(t\\,10\\,11)");
|
|
74
|
+
expect(f).not.toContain("between(t\\,1\\,1)");
|
|
75
|
+
expect(f).not.toContain("between(t\\,5\\,4)");
|
|
76
|
+
});
|
|
77
|
+
it("emits ranges sorted by start time even when caller passes them out of order", () => {
|
|
78
|
+
const f = buildPunchInFilter([
|
|
79
|
+
{ startSec: 5, endSec: 6, zoom: 1.2 },
|
|
80
|
+
{ startSec: 1, endSec: 2, zoom: 1.1 },
|
|
81
|
+
], 1920, 1080);
|
|
82
|
+
// Outer if should be the first sorted range; inner else handles the second.
|
|
83
|
+
const idx1 = f.indexOf("between(t\\,1\\,2)");
|
|
84
|
+
const idx5 = f.indexOf("between(t\\,5\\,6)");
|
|
85
|
+
expect(idx1).toBeGreaterThanOrEqual(0);
|
|
86
|
+
expect(idx5).toBeGreaterThanOrEqual(0);
|
|
87
|
+
expect(idx1).toBeLessThan(idx5);
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
describe("punchInsAfterCuts", () => {
|
|
91
|
+
it("emits a punch range starting at each cut", () => {
|
|
92
|
+
const ranges = punchInsAfterCuts([2, 5, 9], 12, 1.5, 1.1);
|
|
93
|
+
expect(ranges).toEqual([
|
|
94
|
+
{ startSec: 2, endSec: 3.5, zoom: 1.1 },
|
|
95
|
+
{ startSec: 5, endSec: 6.5, zoom: 1.1 },
|
|
96
|
+
{ startSec: 9, endSec: 10.5, zoom: 1.1 },
|
|
97
|
+
]);
|
|
98
|
+
});
|
|
99
|
+
it("never overlaps the next cut", () => {
|
|
100
|
+
const ranges = punchInsAfterCuts([2, 2.4], 10, 1.5, 1.1);
|
|
101
|
+
expect(ranges[0].endSec).toBe(2.4);
|
|
102
|
+
expect(ranges[1].startSec).toBe(2.4);
|
|
103
|
+
});
|
|
104
|
+
it("clips the last range at totalSec", () => {
|
|
105
|
+
const ranges = punchInsAfterCuts([8.5], 9, 1.5, 1.1);
|
|
106
|
+
expect(ranges[0].endSec).toBe(9);
|
|
107
|
+
});
|
|
108
|
+
it("filters out cuts outside [0, totalSec)", () => {
|
|
109
|
+
const ranges = punchInsAfterCuts([-1, 0, 5, 11, 12], 10);
|
|
110
|
+
expect(ranges.map((r) => r.startSec)).toEqual([0, 5]);
|
|
111
|
+
});
|
|
112
|
+
it("drops sub-100ms residual ranges", () => {
|
|
113
|
+
// cut at 9.95 with totalSec 10 → 0.05s window — too small.
|
|
114
|
+
const ranges = punchInsAfterCuts([9.95], 10, 1.5, 1.1);
|
|
115
|
+
expect(ranges).toEqual([]);
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
//# sourceMappingURL=punch-in.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"punch-in.test.js","sourceRoot":"","sources":["../../src/core/punch-in.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Aspect-ratio reformat presets for short-form / vertical / square exports.
|
|
3
|
+
*
|
|
4
|
+
* Used by the `reformat_timeline` tool to derive the FCPXML format spec
|
|
5
|
+
* (width × height) for a new timeline. The tool then emits an FCPXML that
|
|
6
|
+
* imports as a fresh timeline at the target aspect; the user's NLE handles
|
|
7
|
+
* the actual reframing (Resolve Smart Reframe, Premiere Auto Reframe).
|
|
8
|
+
*
|
|
9
|
+
* The chosen base resolutions are the platform-canonical defaults:
|
|
10
|
+
* - 9:16 → 1080×1920 (TikTok / Reels / Shorts)
|
|
11
|
+
* - 1:1 → 1080×1080 (Instagram feed)
|
|
12
|
+
* - 4:5 → 1080×1350 (Instagram portrait feed)
|
|
13
|
+
* - 16:9 → 1920×1080 (long-form horizontal)
|
|
14
|
+
* - 4:3 → 1440×1080 (legacy / old-school cuts)
|
|
15
|
+
*/
|
|
16
|
+
export type ReformatPreset = "9:16" | "1:1" | "4:5" | "16:9" | "4:3";
|
|
17
|
+
export interface ReformatSpec {
|
|
18
|
+
preset: ReformatPreset;
|
|
19
|
+
width: number;
|
|
20
|
+
height: number;
|
|
21
|
+
/** Suggested label for use in clip / sequence names. */
|
|
22
|
+
label: string;
|
|
23
|
+
}
|
|
24
|
+
export declare function reformatSpec(preset: ReformatPreset): ReformatSpec;
|
|
25
|
+
export declare const REFORMAT_PRESETS: ReformatPreset[];
|
|
26
|
+
//# sourceMappingURL=reformat.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reformat.d.ts","sourceRoot":"","sources":["../../src/core/reformat.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,KAAK,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,CAAC;AAErE,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,cAAc,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,wDAAwD;IACxD,KAAK,EAAE,MAAM,CAAC;CACf;AAUD,wBAAgB,YAAY,CAAC,MAAM,EAAE,cAAc,GAAG,YAAY,CAQjE;AAED,eAAO,MAAM,gBAAgB,EAA2B,cAAc,EAAE,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Aspect-ratio reformat presets for short-form / vertical / square exports.
|
|
3
|
+
*
|
|
4
|
+
* Used by the `reformat_timeline` tool to derive the FCPXML format spec
|
|
5
|
+
* (width × height) for a new timeline. The tool then emits an FCPXML that
|
|
6
|
+
* imports as a fresh timeline at the target aspect; the user's NLE handles
|
|
7
|
+
* the actual reframing (Resolve Smart Reframe, Premiere Auto Reframe).
|
|
8
|
+
*
|
|
9
|
+
* The chosen base resolutions are the platform-canonical defaults:
|
|
10
|
+
* - 9:16 → 1080×1920 (TikTok / Reels / Shorts)
|
|
11
|
+
* - 1:1 → 1080×1080 (Instagram feed)
|
|
12
|
+
* - 4:5 → 1080×1350 (Instagram portrait feed)
|
|
13
|
+
* - 16:9 → 1920×1080 (long-form horizontal)
|
|
14
|
+
* - 4:3 → 1440×1080 (legacy / old-school cuts)
|
|
15
|
+
*/
|
|
16
|
+
const PRESETS = {
|
|
17
|
+
"9:16": { preset: "9:16", width: 1080, height: 1920, label: "Vertical 9:16" },
|
|
18
|
+
"1:1": { preset: "1:1", width: 1080, height: 1080, label: "Square 1:1" },
|
|
19
|
+
"4:5": { preset: "4:5", width: 1080, height: 1350, label: "Portrait 4:5" },
|
|
20
|
+
"16:9": { preset: "16:9", width: 1920, height: 1080, label: "Horizontal 16:9" },
|
|
21
|
+
"4:3": { preset: "4:3", width: 1440, height: 1080, label: "Classic 4:3" },
|
|
22
|
+
};
|
|
23
|
+
export function reformatSpec(preset) {
|
|
24
|
+
const spec = PRESETS[preset];
|
|
25
|
+
if (!spec) {
|
|
26
|
+
throw new Error(`unknown reformat preset: ${preset}; valid: ${Object.keys(PRESETS).join(", ")}`);
|
|
27
|
+
}
|
|
28
|
+
return spec;
|
|
29
|
+
}
|
|
30
|
+
export const REFORMAT_PRESETS = Object.keys(PRESETS);
|
|
31
|
+
//# sourceMappingURL=reformat.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reformat.js","sourceRoot":"","sources":["../../src/core/reformat.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAYH,MAAM,OAAO,GAAyC;IACpD,MAAM,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,eAAe,EAAE;IAC7E,KAAK,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,YAAY,EAAE;IACxE,KAAK,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,cAAc,EAAE;IAC1E,MAAM,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,iBAAiB,EAAE;IAC/E,KAAK,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,aAAa,EAAE;CAC1E,CAAC;AAEF,MAAM,UAAU,YAAY,CAAC,MAAsB;IACjD,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC7B,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,MAAM,IAAI,KAAK,CACb,4BAA4B,MAAM,YAAY,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAChF,CAAC;IACJ,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,CAAC,MAAM,gBAAgB,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAqB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reformat.test.d.ts","sourceRoot":"","sources":["../../src/core/reformat.test.ts"],"names":[],"mappings":""}
|