@kvman/kvvideo 0.0.0-stage → 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 +21 -0
- package/README.md +10 -2
- package/dist/api.d.ts +105 -0
- package/dist/api.d.ts.map +1 -0
- package/dist/api.js +2 -0
- package/dist/api.js.map +1 -0
- package/dist/brand/brand.d.ts +17 -0
- package/dist/brand/brand.d.ts.map +1 -0
- package/dist/brand/brand.js +44 -0
- package/dist/brand/brand.js.map +1 -0
- package/dist/browser/channels.d.ts +6 -0
- package/dist/browser/channels.d.ts.map +1 -0
- package/dist/browser/channels.js +5 -0
- package/dist/browser/channels.js.map +1 -0
- package/dist/browser/launch.d.ts +6 -0
- package/dist/browser/launch.d.ts.map +1 -0
- package/dist/browser/launch.js +14 -0
- package/dist/browser/launch.js.map +1 -0
- package/dist/browser/start-browser.d.ts +5 -0
- package/dist/browser/start-browser.d.ts.map +1 -0
- package/dist/browser/start-browser.js +17 -0
- package/dist/browser/start-browser.js.map +1 -0
- package/dist/compose/ass-file.d.ts +17 -0
- package/dist/compose/ass-file.d.ts.map +1 -0
- package/dist/compose/ass-file.js +65 -0
- package/dist/compose/ass-file.js.map +1 -0
- package/dist/compose/background.d.ts +23 -0
- package/dist/compose/background.d.ts.map +1 -0
- package/dist/compose/background.js +31 -0
- package/dist/compose/background.js.map +1 -0
- package/dist/compose/camera.d.ts +32 -0
- package/dist/compose/camera.d.ts.map +1 -0
- package/dist/compose/camera.js +98 -0
- package/dist/compose/camera.js.map +1 -0
- package/dist/compose/caption-font.d.ts +8 -0
- package/dist/compose/caption-font.d.ts.map +1 -0
- package/dist/compose/caption-font.js +24 -0
- package/dist/compose/caption-font.js.map +1 -0
- package/dist/compose/compose-drawing.d.ts +19 -0
- package/dist/compose/compose-drawing.d.ts.map +1 -0
- package/dist/compose/compose-drawing.js +38 -0
- package/dist/compose/compose-drawing.js.map +1 -0
- package/dist/compose/compose-input.d.ts +187 -0
- package/dist/compose/compose-input.d.ts.map +1 -0
- package/dist/compose/compose-input.js +76 -0
- package/dist/compose/compose-input.js.map +1 -0
- package/dist/compose/compose-plan.d.ts +36 -0
- package/dist/compose/compose-plan.d.ts.map +1 -0
- package/dist/compose/compose-plan.js +55 -0
- package/dist/compose/compose-plan.js.map +1 -0
- package/dist/compose/compose-size.d.ts +50 -0
- package/dist/compose/compose-size.d.ts.map +1 -0
- package/dist/compose/compose-size.js +72 -0
- package/dist/compose/compose-size.js.map +1 -0
- package/dist/compose/drawn-images.d.ts +19 -0
- package/dist/compose/drawn-images.d.ts.map +1 -0
- package/dist/compose/drawn-images.js +75 -0
- package/dist/compose/drawn-images.js.map +1 -0
- package/dist/compose/final-pass.d.ts +34 -0
- package/dist/compose/final-pass.d.ts.map +1 -0
- package/dist/compose/final-pass.js +106 -0
- package/dist/compose/final-pass.js.map +1 -0
- package/dist/compose/frame-layout.d.ts +30 -0
- package/dist/compose/frame-layout.d.ts.map +1 -0
- package/dist/compose/frame-layout.js +33 -0
- package/dist/compose/frame-layout.js.map +1 -0
- package/dist/compose/overlays.d.ts +20 -0
- package/dist/compose/overlays.d.ts.map +1 -0
- package/dist/compose/overlays.js +30 -0
- package/dist/compose/overlays.js.map +1 -0
- package/dist/compose/page-again.d.ts +26 -0
- package/dist/compose/page-again.d.ts.map +1 -0
- package/dist/compose/page-again.js +50 -0
- package/dist/compose/page-again.js.map +1 -0
- package/dist/compose/player-copies.d.ts +10 -0
- package/dist/compose/player-copies.d.ts.map +1 -0
- package/dist/compose/player-copies.js +34 -0
- package/dist/compose/player-copies.js.map +1 -0
- package/dist/compose/register-compose.d.ts +3 -0
- package/dist/compose/register-compose.d.ts.map +1 -0
- package/dist/compose/register-compose.js +151 -0
- package/dist/compose/register-compose.js.map +1 -0
- package/dist/compose/render.d.ts +25 -0
- package/dist/compose/render.d.ts.map +1 -0
- package/dist/compose/render.js +61 -0
- package/dist/compose/render.js.map +1 -0
- package/dist/compose/scene-args.d.ts +37 -0
- package/dist/compose/scene-args.d.ts.map +1 -0
- package/dist/compose/scene-args.js +103 -0
- package/dist/compose/scene-args.js.map +1 -0
- package/dist/compose/scene-look.d.ts +31 -0
- package/dist/compose/scene-look.d.ts.map +1 -0
- package/dist/compose/scene-look.js +46 -0
- package/dist/compose/scene-look.js.map +1 -0
- package/dist/compose/scene-plan.d.ts +26 -0
- package/dist/compose/scene-plan.d.ts.map +1 -0
- package/dist/compose/scene-plan.js +34 -0
- package/dist/compose/scene-plan.js.map +1 -0
- package/dist/compose/sound-effects.d.ts +23 -0
- package/dist/compose/sound-effects.d.ts.map +1 -0
- package/dist/compose/sound-effects.js +40 -0
- package/dist/compose/sound-effects.js.map +1 -0
- package/dist/compose/srt.d.ts +3 -0
- package/dist/compose/srt.d.ts.map +1 -0
- package/dist/compose/srt.js +10 -0
- package/dist/compose/srt.js.map +1 -0
- package/dist/compose/transitions.d.ts +16 -0
- package/dist/compose/transitions.d.ts.map +1 -0
- package/dist/compose/transitions.js +38 -0
- package/dist/compose/transitions.js.map +1 -0
- package/dist/connector.d.ts +132 -0
- package/dist/connector.d.ts.map +1 -0
- package/dist/connector.js +63 -0
- package/dist/connector.js.map +1 -0
- package/dist/files/answer-path.d.ts +3 -0
- package/dist/files/answer-path.d.ts.map +1 -0
- package/dist/files/answer-path.js +6 -0
- package/dist/files/answer-path.js.map +1 -0
- package/dist/files/place-output.d.ts +8 -0
- package/dist/files/place-output.d.ts.map +1 -0
- package/dist/files/place-output.js +24 -0
- package/dist/files/place-output.js.map +1 -0
- package/dist/files/sidecar.d.ts +209 -0
- package/dist/files/sidecar.d.ts.map +1 -0
- package/dist/files/sidecar.js +66 -0
- package/dist/files/sidecar.js.map +1 -0
- package/dist/files/workspace-paths.d.ts +7 -0
- package/dist/files/workspace-paths.d.ts.map +1 -0
- package/dist/files/workspace-paths.js +48 -0
- package/dist/files/workspace-paths.js.map +1 -0
- package/dist/fonts/bundled-fonts.d.ts +10 -0
- package/dist/fonts/bundled-fonts.d.ts.map +1 -0
- package/dist/fonts/bundled-fonts.js +10 -0
- package/dist/fonts/bundled-fonts.js.map +1 -0
- package/dist/fonts/font-family.d.ts +2 -0
- package/dist/fonts/font-family.d.ts.map +1 -0
- package/dist/fonts/font-family.js +43 -0
- package/dist/fonts/font-family.js.map +1 -0
- package/dist/fonts/register-fonts.d.ts +3 -0
- package/dist/fonts/register-fonts.d.ts.map +1 -0
- package/dist/fonts/register-fonts.js +12 -0
- package/dist/fonts/register-fonts.js.map +1 -0
- package/dist/guide.d.ts +3 -0
- package/dist/guide.d.ts.map +1 -0
- package/dist/guide.js +6 -0
- package/dist/guide.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +30 -0
- package/dist/index.js.map +1 -0
- package/dist/narration/alignment.d.ts +15 -0
- package/dist/narration/alignment.d.ts.map +1 -0
- package/dist/narration/alignment.js +21 -0
- package/dist/narration/alignment.js.map +1 -0
- package/dist/narration/captions.d.ts +28 -0
- package/dist/narration/captions.d.ts.map +1 -0
- package/dist/narration/captions.js +70 -0
- package/dist/narration/captions.js.map +1 -0
- package/dist/narration/join-args.d.ts +3 -0
- package/dist/narration/join-args.d.ts.map +1 -0
- package/dist/narration/join-args.js +19 -0
- package/dist/narration/join-args.js.map +1 -0
- package/dist/narration/narration-cache.d.ts +25 -0
- package/dist/narration/narration-cache.d.ts.map +1 -0
- package/dist/narration/narration-cache.js +36 -0
- package/dist/narration/narration-cache.js.map +1 -0
- package/dist/narration/piper.d.ts +4 -0
- package/dist/narration/piper.d.ts.map +1 -0
- package/dist/narration/piper.js +13 -0
- package/dist/narration/piper.js.map +1 -0
- package/dist/narration/pronunciations.d.ts +11 -0
- package/dist/narration/pronunciations.d.ts.map +1 -0
- package/dist/narration/pronunciations.js +40 -0
- package/dist/narration/pronunciations.js.map +1 -0
- package/dist/narration/register-narration.d.ts +25 -0
- package/dist/narration/register-narration.d.ts.map +1 -0
- package/dist/narration/register-narration.js +103 -0
- package/dist/narration/register-narration.js.map +1 -0
- package/dist/narration/register-voice.d.ts +27 -0
- package/dist/narration/register-voice.d.ts.map +1 -0
- package/dist/narration/register-voice.js +82 -0
- package/dist/narration/register-voice.js.map +1 -0
- package/dist/narration/sentence-speaker.d.ts +35 -0
- package/dist/narration/sentence-speaker.d.ts.map +1 -0
- package/dist/narration/sentence-speaker.js +44 -0
- package/dist/narration/sentence-speaker.js.map +1 -0
- package/dist/narration/speech-services.d.ts +39 -0
- package/dist/narration/speech-services.d.ts.map +1 -0
- package/dist/narration/speech-services.js +67 -0
- package/dist/narration/speech-services.js.map +1 -0
- package/dist/narration/voice-args.d.ts +3 -0
- package/dist/narration/voice-args.d.ts.map +1 -0
- package/dist/narration/voice-args.js +10 -0
- package/dist/narration/voice-args.js.map +1 -0
- package/dist/problems.d.ts +12 -0
- package/dist/problems.d.ts.map +1 -0
- package/dist/problems.js +19 -0
- package/dist/problems.js.map +1 -0
- package/dist/programs/kill-tree.d.ts +16 -0
- package/dist/programs/kill-tree.d.ts.map +1 -0
- package/dist/programs/kill-tree.js +28 -0
- package/dist/programs/kill-tree.js.map +1 -0
- package/dist/programs/media-duration.d.ts +22 -0
- package/dist/programs/media-duration.d.ts.map +1 -0
- package/dist/programs/media-duration.js +23 -0
- package/dist/programs/media-duration.js.map +1 -0
- package/dist/programs/piped-program.d.ts +7 -0
- package/dist/programs/piped-program.d.ts.map +1 -0
- package/dist/programs/piped-program.js +45 -0
- package/dist/programs/piped-program.js.map +1 -0
- package/dist/programs/programs.d.ts +6 -0
- package/dist/programs/programs.d.ts.map +1 -0
- package/dist/programs/programs.js +6 -0
- package/dist/programs/programs.js.map +1 -0
- package/dist/programs/run-program.d.ts +23 -0
- package/dist/programs/run-program.d.ts.map +1 -0
- package/dist/programs/run-program.js +47 -0
- package/dist/programs/run-program.js.map +1 -0
- package/dist/record/address.d.ts +5 -0
- package/dist/record/address.d.ts.map +1 -0
- package/dist/record/address.js +26 -0
- package/dist/record/address.js.map +1 -0
- package/dist/record/cursor-script.d.ts +3 -0
- package/dist/record/cursor-script.d.ts.map +1 -0
- package/dist/record/cursor-script.js +59 -0
- package/dist/record/cursor-script.js.map +1 -0
- package/dist/record/encoder-args.d.ts +3 -0
- package/dist/record/encoder-args.d.ts.map +1 -0
- package/dist/record/encoder-args.js +13 -0
- package/dist/record/encoder-args.js.map +1 -0
- package/dist/record/frame-writer.d.ts +8 -0
- package/dist/record/frame-writer.d.ts.map +1 -0
- package/dist/record/frame-writer.js +30 -0
- package/dist/record/frame-writer.js.map +1 -0
- package/dist/record/motion.d.ts +19 -0
- package/dist/record/motion.d.ts.map +1 -0
- package/dist/record/motion.js +59 -0
- package/dist/record/motion.js.map +1 -0
- package/dist/record/narration-cues.d.ts +14 -0
- package/dist/record/narration-cues.d.ts.map +1 -0
- package/dist/record/narration-cues.js +12 -0
- package/dist/record/narration-cues.js.map +1 -0
- package/dist/record/own-port.d.ts +2 -0
- package/dist/record/own-port.d.ts.map +1 -0
- package/dist/record/own-port.js +23 -0
- package/dist/record/own-port.js.map +1 -0
- package/dist/record/page-ready.d.ts +4 -0
- package/dist/record/page-ready.d.ts.map +1 -0
- package/dist/record/page-ready.js +15 -0
- package/dist/record/page-ready.js.map +1 -0
- package/dist/record/page-route.d.ts +13 -0
- package/dist/record/page-route.d.ts.map +1 -0
- package/dist/record/page-route.js +64 -0
- package/dist/record/page-route.js.map +1 -0
- package/dist/record/pointer.d.ts +8 -0
- package/dist/record/pointer.d.ts.map +1 -0
- package/dist/record/pointer.js +24 -0
- package/dist/record/pointer.js.map +1 -0
- package/dist/record/recorder.d.ts +34 -0
- package/dist/record/recorder.d.ts.map +1 -0
- package/dist/record/recorder.js +99 -0
- package/dist/record/recorder.js.map +1 -0
- package/dist/record/register-record.d.ts +3 -0
- package/dist/record/register-record.d.ts.map +1 -0
- package/dist/record/register-record.js +83 -0
- package/dist/record/register-record.js.map +1 -0
- package/dist/record/run-step.d.ts +20 -0
- package/dist/record/run-step.d.ts.map +1 -0
- package/dist/record/run-step.js +69 -0
- package/dist/record/run-step.js.map +1 -0
- package/dist/record/screencast.d.ts +9 -0
- package/dist/record/screencast.d.ts.map +1 -0
- package/dist/record/screencast.js +38 -0
- package/dist/record/screencast.js.map +1 -0
- package/dist/record/steps.d.ts +124 -0
- package/dist/record/steps.d.ts.map +1 -0
- package/dist/record/steps.js +47 -0
- package/dist/record/steps.js.map +1 -0
- package/dist/register-with-kvcoder.d.ts +3 -0
- package/dist/register-with-kvcoder.d.ts.map +1 -0
- package/dist/register-with-kvcoder.js +15 -0
- package/dist/register-with-kvcoder.js.map +1 -0
- package/dist/review/analysis.d.ts +19 -0
- package/dist/review/analysis.d.ts.map +1 -0
- package/dist/review/analysis.js +36 -0
- package/dist/review/analysis.js.map +1 -0
- package/dist/review/frames.d.ts +9 -0
- package/dist/review/frames.d.ts.map +1 -0
- package/dist/review/frames.js +28 -0
- package/dist/review/frames.js.map +1 -0
- package/dist/review/register-review.d.ts +24 -0
- package/dist/review/register-review.d.ts.map +1 -0
- package/dist/review/register-review.js +81 -0
- package/dist/review/register-review.js.map +1 -0
- package/dist/review/sheet-args.d.ts +11 -0
- package/dist/review/sheet-args.d.ts.map +1 -0
- package/dist/review/sheet-args.js +24 -0
- package/dist/review/sheet-args.js.map +1 -0
- package/dist/settings.d.ts +33 -0
- package/dist/settings.d.ts.map +1 -0
- package/dist/settings.js +29 -0
- package/dist/settings.js.map +1 -0
- package/dist/setup/browser-readiness.d.ts +14 -0
- package/dist/setup/browser-readiness.d.ts.map +1 -0
- package/dist/setup/browser-readiness.js +16 -0
- package/dist/setup/browser-readiness.js.map +1 -0
- package/dist/setup/ffmpeg-readiness.d.ts +19 -0
- package/dist/setup/ffmpeg-readiness.d.ts.map +1 -0
- package/dist/setup/ffmpeg-readiness.js +33 -0
- package/dist/setup/ffmpeg-readiness.js.map +1 -0
- package/dist/setup/narration-readiness.d.ts +21 -0
- package/dist/setup/narration-readiness.d.ts.map +1 -0
- package/dist/setup/narration-readiness.js +18 -0
- package/dist/setup/narration-readiness.js.map +1 -0
- package/dist/setup/register-setup.d.ts +3 -0
- package/dist/setup/register-setup.d.ts.map +1 -0
- package/dist/setup/register-setup.js +51 -0
- package/dist/setup/register-setup.js.map +1 -0
- package/dist/ui.d.ts +3 -0
- package/dist/ui.d.ts.map +1 -0
- package/dist/ui.js +26 -0
- package/dist/ui.js.map +1 -0
- package/dist/video-start.d.ts +3 -0
- package/dist/video-start.d.ts.map +1 -0
- package/dist/video-start.js +28 -0
- package/dist/video-start.js.map +1 -0
- package/dist/web/components/player.css +2 -0
- package/dist/web/components/player.js +55 -0
- package/docs/guide.md +28 -0
- package/fonts/Amiri-Bold.ttf +0 -0
- package/fonts/IBMPlexSansArabic-Bold.ttf +0 -0
- package/fonts/Lato-Bold.ttf +0 -0
- package/fonts/OFL-Amiri.txt +94 -0
- package/fonts/OFL-IBMPlexSansArabic.txt +93 -0
- package/fonts/OFL-Lato.txt +93 -0
- package/fonts/OFL-Poppins.txt +93 -0
- package/fonts/Poppins-Bold.ttf +0 -0
- package/locales/ar.json +48 -0
- package/locales/en.json +48 -0
- package/package.json +73 -3
- package/sounds/SOURCES.md +13 -0
- package/sounds/click.wav +0 -0
- package/sounds/keys.wav +0 -0
- package/sounds/pop.wav +0 -0
- package/sounds/whoosh.wav +0 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ahmed Deif
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @kvman/kvvideo
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The [kvman](https://github.com/ibndeif/kvman) extension that makes any kind of video from a chat (a lesson, an explainer, a tutorial, a promotion, a story, a social clip): it records websites and HTML pages in the installed Chrome or Edge, narrates a script with ElevenLabs, OpenAI, or Piper, and joins them with burned-in captions into an MP4 with ffmpeg. It is bundled with kvman, and needs `@kvman/kvcoder` and `@kvman/kvwebui`. Type `/video` in a chat to turn it on.
|
|
4
|
+
|
|
5
|
+
## Fonts
|
|
6
|
+
|
|
7
|
+
`fonts/` holds Amiri, IBM Plex Sans Arabic, Lato, and Poppins in their bold weights, each under the SIL Open Font License beside it.
|
|
8
|
+
|
|
9
|
+
## License
|
|
10
|
+
|
|
11
|
+
MIT
|
package/dist/api.d.ts
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import type { z } from '@kvman/sdk';
|
|
2
|
+
import type { composeInputSchema, composeOutputSchema } from './compose/compose-input.ts';
|
|
3
|
+
import type { narrateInputSchema, narrateOutputSchema } from './narration/register-narration.ts';
|
|
4
|
+
import type { recordInputSchema, recordOutputSchema } from './record/steps.ts';
|
|
5
|
+
import type { reviewOutputSchema } from './review/register-review.ts';
|
|
6
|
+
import type { voiceInputSchema, voiceOutputSchema } from './narration/register-voice.ts';
|
|
7
|
+
import type { Brand } from './brand/brand.ts';
|
|
8
|
+
import type { BrowserChoice, NarrationService } from './settings.ts';
|
|
9
|
+
type Empty = Record<string, never>;
|
|
10
|
+
type Channel = 'chrome' | 'msedge';
|
|
11
|
+
declare module '@kvman/sdk' {
|
|
12
|
+
interface Commands {
|
|
13
|
+
'kvvideo.video.start': {
|
|
14
|
+
input: {
|
|
15
|
+
sessionId: string;
|
|
16
|
+
argument: string;
|
|
17
|
+
};
|
|
18
|
+
output: Empty;
|
|
19
|
+
};
|
|
20
|
+
'kvvideo.video.compose': {
|
|
21
|
+
input: z.input<typeof composeInputSchema>;
|
|
22
|
+
output: z.output<typeof composeOutputSchema>;
|
|
23
|
+
};
|
|
24
|
+
'kvvideo.narration.make': {
|
|
25
|
+
input: z.input<typeof narrateInputSchema>;
|
|
26
|
+
output: z.output<typeof narrateOutputSchema>;
|
|
27
|
+
};
|
|
28
|
+
'kvvideo.clip.record': {
|
|
29
|
+
input: z.input<typeof recordInputSchema>;
|
|
30
|
+
output: z.output<typeof recordOutputSchema>;
|
|
31
|
+
};
|
|
32
|
+
'kvvideo.brand.set': {
|
|
33
|
+
input: Brand;
|
|
34
|
+
output: Empty;
|
|
35
|
+
};
|
|
36
|
+
'kvvideo.voice.make': {
|
|
37
|
+
input: z.input<typeof voiceInputSchema>;
|
|
38
|
+
output: z.output<typeof voiceOutputSchema>;
|
|
39
|
+
};
|
|
40
|
+
'kvvideo.video.review': {
|
|
41
|
+
input: {
|
|
42
|
+
file: string;
|
|
43
|
+
};
|
|
44
|
+
output: z.output<typeof reviewOutputSchema>;
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
interface Queries {
|
|
48
|
+
'kvvideo.setup.get': {
|
|
49
|
+
input: Empty;
|
|
50
|
+
output: {
|
|
51
|
+
ffmpeg: {
|
|
52
|
+
ready: boolean;
|
|
53
|
+
version: string | null;
|
|
54
|
+
missing: string[];
|
|
55
|
+
};
|
|
56
|
+
browser: {
|
|
57
|
+
ready: boolean;
|
|
58
|
+
channel: Channel | null;
|
|
59
|
+
};
|
|
60
|
+
narration: {
|
|
61
|
+
service: NarrationService | null;
|
|
62
|
+
ready: boolean;
|
|
63
|
+
missing: string | null;
|
|
64
|
+
};
|
|
65
|
+
};
|
|
66
|
+
};
|
|
67
|
+
'kvvideo.ui.get': {
|
|
68
|
+
input: Empty;
|
|
69
|
+
output: {
|
|
70
|
+
pages: unknown[];
|
|
71
|
+
nav: unknown[];
|
|
72
|
+
panels: unknown[];
|
|
73
|
+
status: unknown[];
|
|
74
|
+
configuration: unknown;
|
|
75
|
+
};
|
|
76
|
+
};
|
|
77
|
+
'kvvideo.font.list': {
|
|
78
|
+
input: Empty;
|
|
79
|
+
output: {
|
|
80
|
+
name: string;
|
|
81
|
+
scripts: ('latin' | 'arabic')[];
|
|
82
|
+
}[];
|
|
83
|
+
};
|
|
84
|
+
'kvvideo.brand.get': {
|
|
85
|
+
input: Empty;
|
|
86
|
+
output: Brand | null;
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
interface Settings {
|
|
90
|
+
'kvvideo.narration.service': NarrationService | null;
|
|
91
|
+
'kvvideo.narration.voice': string | null;
|
|
92
|
+
'kvvideo.narration.model': string | null;
|
|
93
|
+
'kvvideo.narration.pronunciations': {
|
|
94
|
+
word: string;
|
|
95
|
+
say: string;
|
|
96
|
+
}[];
|
|
97
|
+
'kvvideo.brand': Brand | null;
|
|
98
|
+
'kvvideo.browser': BrowserChoice;
|
|
99
|
+
'kvvideo.programs.ffmpeg': string;
|
|
100
|
+
'kvvideo.programs.ffprobe': string;
|
|
101
|
+
'kvvideo.programs.piper': string;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
export {};
|
|
105
|
+
//# sourceMappingURL=api.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
|
package/dist/api.js
ADDED
package/dist/api.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { z, type Ctx } from '@kvman/sdk';
|
|
2
|
+
export declare const brandSchema: z.ZodObject<{
|
|
3
|
+
logo: z.ZodNullable<z.ZodString>;
|
|
4
|
+
colors: z.ZodObject<{
|
|
5
|
+
primary: z.ZodString;
|
|
6
|
+
background: z.ZodString;
|
|
7
|
+
text: z.ZodString;
|
|
8
|
+
}, z.core.$strict>;
|
|
9
|
+
font: z.ZodNullable<z.ZodString>;
|
|
10
|
+
}, z.core.$strict>;
|
|
11
|
+
/** A workspace's brand. */
|
|
12
|
+
export type Brand = z.output<typeof brandSchema>;
|
|
13
|
+
export declare const logoExtensions: string[];
|
|
14
|
+
/** Checks a brand's files and font in the workspace `root`. */
|
|
15
|
+
export declare function checkBrand(root: string, brand: Brand): void;
|
|
16
|
+
export declare function registerBrand(ctx: Ctx): void;
|
|
17
|
+
//# sourceMappingURL=brand.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"brand.d.ts","sourceRoot":"","sources":["../../src/brand/brand.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,KAAK,GAAG,EAAE,MAAM,YAAY,CAAC;AASzC,eAAO,MAAM,WAAW;;;;;;;;kBAItB,CAAC;AAEH,2BAA2B;AAC3B,MAAM,MAAM,KAAK,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,WAAW,CAAC,CAAC;AAEjD,eAAO,MAAM,cAAc,UAA6C,CAAC;AAEzE,+DAA+D;AAC/D,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,GAAG,IAAI,CAG3D;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,GAAG,GAAG,IAAI,CAuB5C"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { z } from '@kvman/sdk';
|
|
2
|
+
import { captionFont } from "../compose/caption-font.js";
|
|
3
|
+
import { inputPath } from "../files/workspace-paths.js";
|
|
4
|
+
// The workspace's brand (plan 16 §16.2 and §16.4; ADR 0115, 21 and 43): its logo, colours, and font, read with
|
|
5
|
+
// `video brand` and set with `video brand-set` without asking, since the person agreed to it in the script.
|
|
6
|
+
const colour = z.string().regex(/^#[0-9a-fA-F]{6}$/, 'A colour is #RRGGBB.');
|
|
7
|
+
export const brandSchema = z.strictObject({
|
|
8
|
+
logo: z.string().min(1).max(1000).nullable().describe('A .png, .svg, .jpg, or .webp file in the workspace, or null.'),
|
|
9
|
+
colors: z.strictObject({ primary: colour, background: colour, text: colour }),
|
|
10
|
+
font: z.string().min(1).max(1000).nullable().describe('A bundled font (video fonts), a .ttf or .otf file in the workspace, or null.'),
|
|
11
|
+
});
|
|
12
|
+
export const logoExtensions = ['.png', '.svg', '.jpg', '.jpeg', '.webp'];
|
|
13
|
+
/** Checks a brand's files and font in the workspace `root`. */
|
|
14
|
+
export function checkBrand(root, brand) {
|
|
15
|
+
if (brand.logo !== null)
|
|
16
|
+
inputPath(root, brand.logo, logoExtensions);
|
|
17
|
+
if (brand.font !== null)
|
|
18
|
+
captionFont(root, brand.font, []);
|
|
19
|
+
}
|
|
20
|
+
export function registerBrand(ctx) {
|
|
21
|
+
ctx.registerSetting('kvvideo.brand', { description: "The workspace's brand for its videos: a logo file, the primary, background, and text colours, and a font; null for none.", schema: brandSchema.nullable(), default: null });
|
|
22
|
+
ctx.registerQuery('kvvideo.brand.get', {
|
|
23
|
+
description: "Gives the workspace's brand for videos: its logo, colours, and font, or null.",
|
|
24
|
+
input: z.strictObject({}),
|
|
25
|
+
output: brandSchema.nullable(),
|
|
26
|
+
public: true,
|
|
27
|
+
timeoutMs: 60_000,
|
|
28
|
+
handle: async () => ctx.settings.get('kvvideo.brand'),
|
|
29
|
+
});
|
|
30
|
+
ctx.registerCommand('kvvideo.brand.set', {
|
|
31
|
+
description: "Sets the workspace's brand for videos: its logo, colours, and font.",
|
|
32
|
+
input: brandSchema,
|
|
33
|
+
output: z.strictObject({}),
|
|
34
|
+
public: true,
|
|
35
|
+
retries: 0,
|
|
36
|
+
timeoutMs: 60_000,
|
|
37
|
+
handle: async (input) => {
|
|
38
|
+
checkBrand(ctx.job.workspace.path, input);
|
|
39
|
+
await ctx.settings.set('kvvideo.brand', input, { scope: 'workspace' });
|
|
40
|
+
return {};
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=brand.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"brand.js","sourceRoot":"","sources":["../../src/brand/brand.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAY,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AACzD,OAAO,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAExD,+GAA+G;AAC/G,4GAA4G;AAE5G,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,mBAAmB,EAAE,sBAAsB,CAAC,CAAC;AAE7E,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,CAAC,YAAY,CAAC;IACxC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,8DAA8D,CAAC;IACrH,MAAM,EAAE,CAAC,CAAC,YAAY,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IAC7E,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,8EAA8E,CAAC;CACtI,CAAC,CAAC;AAKH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;AAEzE,+DAA+D;AAC/D,MAAM,UAAU,UAAU,CAAC,IAAY,EAAE,KAAY;IACnD,IAAI,KAAK,CAAC,IAAI,KAAK,IAAI;QAAE,SAAS,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC;IACrE,IAAI,KAAK,CAAC,IAAI,KAAK,IAAI;QAAE,WAAW,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;AAC7D,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,GAAQ;IACpC,GAAG,CAAC,eAAe,CAAC,eAAe,EAAE,EAAE,WAAW,EAAE,0HAA0H,EAAE,MAAM,EAAE,WAAW,CAAC,QAAQ,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;IACjO,GAAG,CAAC,aAAa,CAAC,mBAAmB,EAAE;QACrC,WAAW,EAAE,+EAA+E;QAC5F,KAAK,EAAE,CAAC,CAAC,YAAY,CAAC,EAAE,CAAC;QACzB,MAAM,EAAE,WAAW,CAAC,QAAQ,EAAE;QAC9B,MAAM,EAAE,IAAI;QACZ,SAAS,EAAE,MAAM;QACjB,MAAM,EAAE,KAAK,IAAI,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,eAAe,CAAC;KACtD,CAAC,CAAC;IACH,GAAG,CAAC,eAAe,CAAC,mBAAmB,EAAE;QACvC,WAAW,EAAE,qEAAqE;QAClF,KAAK,EAAE,WAAW;QAClB,MAAM,EAAE,CAAC,CAAC,YAAY,CAAC,EAAE,CAAC;QAC1B,MAAM,EAAE,IAAI;QACZ,OAAO,EAAE,CAAC;QACV,SAAS,EAAE,MAAM;QACjB,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE;YACtB,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;YAC1C,MAAM,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,eAAe,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAC;YACvE,OAAO,EAAE,CAAC;QACZ,CAAC;KACF,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { BrowserChoice } from '../settings.ts';
|
|
2
|
+
/** An installed browser that Playwright can drive. */
|
|
3
|
+
export type Channel = 'chrome' | 'msedge';
|
|
4
|
+
/** The channels a choice tries, in order (plan 16 §16.4). */
|
|
5
|
+
export declare function channelsOf(choice: BrowserChoice): Channel[];
|
|
6
|
+
//# sourceMappingURL=channels.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"channels.d.ts","sourceRoot":"","sources":["../../src/browser/channels.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAEpD,sDAAsD;AACtD,MAAM,MAAM,OAAO,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAE1C,6DAA6D;AAC7D,wBAAgB,UAAU,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,EAAE,CAE3D"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"channels.js","sourceRoot":"","sources":["../../src/browser/channels.ts"],"names":[],"mappings":"AAKA,6DAA6D;AAC7D,MAAM,UAAU,UAAU,CAAC,MAAqB;IAC9C,OAAO,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;AAC7D,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { Browser } from 'playwright-core';
|
|
2
|
+
import type { Channel } from './channels.ts';
|
|
3
|
+
export declare function launchChannel(channel: Channel): Promise<Browser>;
|
|
4
|
+
/** The browser that draws a scene's frames and overlays, at one pixel per CSS pixel (ADR 0115, 36). */
|
|
5
|
+
export declare function launchDrawing(channel: Channel): Promise<Browser>;
|
|
6
|
+
//# sourceMappingURL=launch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"launch.d.ts","sourceRoot":"","sources":["../../src/browser/launch.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAO7C,wBAAsB,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAGtE;AAED,uGAAuG;AACvG,wBAAsB,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAGtE"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// The installed Chrome or Edge, driven headless through playwright-core (ADR 0107, 9): no browser is downloaded. It
|
|
2
|
+
// draws at 2× density, so the screencast's frames are twice the page's CSS size (ADR 0115, 8).
|
|
3
|
+
// playwright-core is imported when a browser starts, not when kvvideo loads, since every worker loads kvvideo and
|
|
4
|
+
// most never record.
|
|
5
|
+
export async function launchChannel(channel) {
|
|
6
|
+
const { chromium } = await import('playwright-core');
|
|
7
|
+
return chromium.launch({ channel, headless: true, args: ['--force-device-scale-factor=2'] });
|
|
8
|
+
}
|
|
9
|
+
/** The browser that draws a scene's frames and overlays, at one pixel per CSS pixel (ADR 0115, 36). */
|
|
10
|
+
export async function launchDrawing(channel) {
|
|
11
|
+
const { chromium } = await import('playwright-core');
|
|
12
|
+
return chromium.launch({ channel, headless: true });
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=launch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"launch.js","sourceRoot":"","sources":["../../src/browser/launch.ts"],"names":[],"mappings":"AAGA,oHAAoH;AACpH,+FAA+F;AAC/F,kHAAkH;AAClH,qBAAqB;AAErB,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,OAAgB;IAClD,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,MAAM,CAAC,iBAAiB,CAAC,CAAC;IACrD,OAAO,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,+BAA+B,CAAC,EAAE,CAAC,CAAC;AAC/F,CAAC;AAED,uGAAuG;AACvG,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,OAAgB;IAClD,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,MAAM,CAAC,iBAAiB,CAAC,CAAC;IACrD,OAAO,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;AACtD,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { BrowserChoice } from '../settings.ts';
|
|
2
|
+
import { type Channel } from './channels.ts';
|
|
3
|
+
/** The first channel of the choice that starts, or `kvvideo/BROWSER_MISSING` with the channels tried (plan 16 §16.5). */
|
|
4
|
+
export declare function startBrowser<Started>(choice: BrowserChoice, launch: (channel: Channel) => Promise<Started>): Promise<Started>;
|
|
5
|
+
//# sourceMappingURL=start-browser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"start-browser.d.ts","sourceRoot":"","sources":["../../src/browser/start-browser.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,EAAc,KAAK,OAAO,EAAE,MAAM,eAAe,CAAC;AAEzD,yHAAyH;AACzH,wBAAsB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAWnI"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { kvvideoProblem } from "../problems.js";
|
|
2
|
+
import { channelsOf } from "./channels.js";
|
|
3
|
+
/** The first channel of the choice that starts, or `kvvideo/BROWSER_MISSING` with the channels tried (plan 16 §16.5). */
|
|
4
|
+
export async function startBrowser(choice, launch) {
|
|
5
|
+
const channels = channelsOf(choice);
|
|
6
|
+
const reasons = [];
|
|
7
|
+
for (const channel of channels) {
|
|
8
|
+
try {
|
|
9
|
+
return await launch(channel);
|
|
10
|
+
}
|
|
11
|
+
catch (error) {
|
|
12
|
+
reasons.push(`${channel}: ${error instanceof Error ? (error.message.split('\n')[0] ?? '') : String(error)}`);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
throw kvvideoProblem('BROWSER_MISSING', `No installed browser could start (${reasons.join('; ')}); install Google Chrome or Microsoft Edge.`, { channels });
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=start-browser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"start-browser.js","sourceRoot":"","sources":["../../src/browser/start-browser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAEhD,OAAO,EAAE,UAAU,EAAgB,MAAM,eAAe,CAAC;AAEzD,yHAAyH;AACzH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAU,MAAqB,EAAE,MAA8C;IAC/G,MAAM,QAAQ,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC;IACpC,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,IAAI,CAAC;YACH,OAAO,MAAM,MAAM,CAAC,OAAO,CAAC,CAAC;QAC/B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,IAAI,CAAC,GAAG,OAAO,KAAK,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAC/G,CAAC;IACH,CAAC;IACD,MAAM,cAAc,CAAC,iBAAiB,EAAE,qCAAqC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,6CAA6C,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC;AAC9J,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Caption } from '../narration/captions.ts';
|
|
2
|
+
export type CaptionLook = 'boxed' | 'outline' | 'highlight';
|
|
3
|
+
export type CaptionStyle = {
|
|
4
|
+
width: number;
|
|
5
|
+
height: number;
|
|
6
|
+
family: string;
|
|
7
|
+
size: number | undefined;
|
|
8
|
+
position: 'bottom' | 'top';
|
|
9
|
+
look: CaptionLook;
|
|
10
|
+
highlight: string;
|
|
11
|
+
};
|
|
12
|
+
/** A caption's text as ASS shows it: no override braces, no backslashes, one line. */
|
|
13
|
+
export declare function assText(text: string): string;
|
|
14
|
+
/** `#RRGGBB` as an ASS colour, `&HAABBGGRR`, opaque. */
|
|
15
|
+
export declare function assColour(colour: string): string;
|
|
16
|
+
export declare function assFile(style: CaptionStyle, captions: readonly Caption[]): string;
|
|
17
|
+
//# sourceMappingURL=ass-file.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ass-file.d.ts","sourceRoot":"","sources":["../../src/compose/ass-file.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAC;AAQxD,MAAM,MAAM,WAAW,GAAG,OAAO,GAAG,SAAS,GAAG,WAAW,CAAC;AAE5D,MAAM,MAAM,YAAY,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IAAC,QAAQ,EAAE,QAAQ,GAAG,KAAK,CAAC;IAAC,IAAI,EAAE,WAAW,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC;AAWzK,sFAAsF;AACtF,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE5C;AAED,wDAAwD;AACxD,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEhD;AAiCD,wBAAgB,OAAO,CAAC,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,SAAS,OAAO,EAAE,GAAG,MAAM,CAoBjF"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
function timeOf(ms) {
|
|
2
|
+
const centiseconds = Math.floor(ms / 10);
|
|
3
|
+
const hours = Math.floor(centiseconds / 360_000);
|
|
4
|
+
const minutes = Math.floor(centiseconds / 6000) % 60;
|
|
5
|
+
const seconds = Math.floor(centiseconds / 100) % 60;
|
|
6
|
+
const pad = (value) => String(value).padStart(2, '0');
|
|
7
|
+
return `${String(hours)}:${pad(minutes)}:${pad(seconds)}.${pad(centiseconds % 100)}`;
|
|
8
|
+
}
|
|
9
|
+
/** A caption's text as ASS shows it: no override braces, no backslashes, one line. */
|
|
10
|
+
export function assText(text) {
|
|
11
|
+
return text.replace(/[{}\\]/g, '').replace(/\s+/g, ' ').trim();
|
|
12
|
+
}
|
|
13
|
+
/** `#RRGGBB` as an ASS colour, `&HAABBGGRR`, opaque. */
|
|
14
|
+
export function assColour(colour) {
|
|
15
|
+
return `&H00${`${colour.slice(5, 7)}${colour.slice(3, 5)}${colour.slice(1, 3)}`.toUpperCase()}`;
|
|
16
|
+
}
|
|
17
|
+
const box = '&H59000000';
|
|
18
|
+
function styleLine(name, style, primary, secondary) {
|
|
19
|
+
const size = style.size ?? Math.round(style.height / 18);
|
|
20
|
+
const alignment = style.position === 'top' ? 8 : 2;
|
|
21
|
+
const margin = Math.round(style.height * 0.06);
|
|
22
|
+
const family = style.family.replace(/,/g, ' ');
|
|
23
|
+
const border = style.look === 'outline' ? `0,0,1,3,0` : `0,0,3,${String(Math.round(size / 3))},0`;
|
|
24
|
+
const outline = style.look === 'outline' ? '&H00000000' : box;
|
|
25
|
+
const back = style.look === 'outline' ? '&H00000000' : box;
|
|
26
|
+
return `Style: ${name},${family},${String(size)},${primary},${secondary},${outline},${back},0,0,0,0,100,100,${border},${String(alignment)},40,40,${String(margin)},-1`;
|
|
27
|
+
}
|
|
28
|
+
// A line's words, each held as ASS karaoke from the line's start: the words already spoken take the primary colour.
|
|
29
|
+
function karaoke(caption) {
|
|
30
|
+
const centiseconds = (ms) => Math.max(0, Math.round(ms / 10));
|
|
31
|
+
const first = caption.words[0]?.startMs ?? caption.startMs;
|
|
32
|
+
const parts = first > caption.startMs ? [`{\\k${String(centiseconds(first - caption.startMs))}}`] : [];
|
|
33
|
+
caption.words.forEach((word, index) => {
|
|
34
|
+
const next = caption.words[index + 1]?.startMs ?? caption.endMs;
|
|
35
|
+
parts.push(`{\\k${String(centiseconds(next - word.startMs))}}${assText(word.text)}${index === caption.words.length - 1 ? '' : ' '}`);
|
|
36
|
+
});
|
|
37
|
+
return parts.join('');
|
|
38
|
+
}
|
|
39
|
+
function dialogue(style, caption) {
|
|
40
|
+
const timed = style.look === 'highlight' && caption.words !== undefined && caption.words.length > 0;
|
|
41
|
+
const text = timed && caption.words !== undefined ? karaoke({ ...caption, words: caption.words }) : assText(caption.text);
|
|
42
|
+
return `Dialogue: 0,${timeOf(caption.startMs)},${timeOf(caption.endMs)},${timed ? 'Spoken' : 'Default'},,0,0,0,,${text}`;
|
|
43
|
+
}
|
|
44
|
+
export function assFile(style, captions) {
|
|
45
|
+
const white = '&H00FFFFFF';
|
|
46
|
+
return [
|
|
47
|
+
'[Script Info]',
|
|
48
|
+
'ScriptType: v4.00+',
|
|
49
|
+
`PlayResX: ${String(style.width)}`,
|
|
50
|
+
`PlayResY: ${String(style.height)}`,
|
|
51
|
+
'WrapStyle: 0',
|
|
52
|
+
'ScaledBorderAndShadow: yes',
|
|
53
|
+
'',
|
|
54
|
+
'[V4+ Styles]',
|
|
55
|
+
'Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding',
|
|
56
|
+
styleLine('Default', style, white, white),
|
|
57
|
+
...(style.look === 'highlight' ? [styleLine('Spoken', style, assColour(style.highlight), white)] : []),
|
|
58
|
+
'',
|
|
59
|
+
'[Events]',
|
|
60
|
+
'Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text',
|
|
61
|
+
...captions.map((caption) => dialogue(style, caption)),
|
|
62
|
+
'',
|
|
63
|
+
].join('\n');
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=ass-file.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ass-file.js","sourceRoot":"","sources":["../../src/compose/ass-file.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { Brand } from '../brand/brand.ts';
|
|
2
|
+
import type { Size } from './frame-layout.ts';
|
|
3
|
+
export type Background = {
|
|
4
|
+
kind: 'image';
|
|
5
|
+
file: string;
|
|
6
|
+
} | {
|
|
7
|
+
kind: 'gradient';
|
|
8
|
+
from: string;
|
|
9
|
+
to: string;
|
|
10
|
+
};
|
|
11
|
+
/** `colour` mixed with `share` of `other`, as #rrggbb. */
|
|
12
|
+
export declare function mixed(colour: string, other: string, share: number): string;
|
|
13
|
+
/** The scene's background, from its `background` (a colour or an image file already checked) and the brand. */
|
|
14
|
+
export declare function backgroundOf(background: {
|
|
15
|
+
colour: string;
|
|
16
|
+
} | {
|
|
17
|
+
file: string;
|
|
18
|
+
} | undefined, brand: Brand | null): Background;
|
|
19
|
+
/** ffmpeg's input for the background, `lengthMs` long at 30 frames a second. */
|
|
20
|
+
export declare function backgroundInput(background: Background, size: Size, lengthMs: number): string[];
|
|
21
|
+
/** The filter that makes the background input the picture's size. */
|
|
22
|
+
export declare function backgroundFit(background: Background, size: Size): string;
|
|
23
|
+
//# sourceMappingURL=background.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"background.d.ts","sourceRoot":"","sources":["../../src/compose/background.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAM9C,MAAM,MAAM,UAAU,GAAG;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC;AAI1G,0DAA0D;AAC1D,wBAAgB,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAG1E;AAED,+GAA+G;AAC/G,wBAAgB,YAAY,CAAC,UAAU,EAAE;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,EAAE,KAAK,EAAE,KAAK,GAAG,IAAI,GAAG,UAAU,CAK3H;AAID,gFAAgF;AAChF,wBAAgB,eAAe,CAAC,UAAU,EAAE,UAAU,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAK9F;AAED,qEAAqE;AACrE,wBAAgB,aAAa,CAAC,UAAU,EAAE,UAAU,EAAE,IAAI,EAAE,IAAI,GAAG,MAAM,CAIxE"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
const channels = (colour) => [1, 3, 5].map((at) => Number.parseInt(colour.slice(at, at + 2), 16));
|
|
2
|
+
/** `colour` mixed with `share` of `other`, as #rrggbb. */
|
|
3
|
+
export function mixed(colour, other, share) {
|
|
4
|
+
const [base, added] = [channels(colour), channels(other)];
|
|
5
|
+
return `#${base.map((value, index) => Math.round(value * (1 - share) + (added[index] ?? 0) * share).toString(16).padStart(2, '0')).join('')}`;
|
|
6
|
+
}
|
|
7
|
+
/** The scene's background, from its `background` (a colour or an image file already checked) and the brand. */
|
|
8
|
+
export function backgroundOf(background, brand) {
|
|
9
|
+
if (background !== undefined && 'file' in background)
|
|
10
|
+
return { kind: 'image', file: background.file };
|
|
11
|
+
const colour = background?.colour ?? brand?.colors.background;
|
|
12
|
+
if (colour === undefined)
|
|
13
|
+
return { kind: 'gradient', from: '#0F172A', to: '#1E293B' };
|
|
14
|
+
return { kind: 'gradient', from: colour, to: brand === null ? colour : mixed(colour, brand.colors.primary, 0.18) };
|
|
15
|
+
}
|
|
16
|
+
const seconds = (ms) => (ms / 1000).toFixed(3);
|
|
17
|
+
/** ffmpeg's input for the background, `lengthMs` long at 30 frames a second. */
|
|
18
|
+
export function backgroundInput(background, size, lengthMs) {
|
|
19
|
+
const { width, height } = size;
|
|
20
|
+
if (background.kind === 'image')
|
|
21
|
+
return ['-loop', '1', '-framerate', '30', '-t', seconds(lengthMs), '-i', background.file];
|
|
22
|
+
const hex = (colour) => `0x${colour.slice(1)}`;
|
|
23
|
+
return ['-f', 'lavfi', '-t', seconds(lengthMs), '-i', `gradients=s=${String(width)}x${String(height)}:r=30:c0=${hex(background.from)}:c1=${hex(background.to)}:x0=0:y0=0:x1=${String(width)}:y1=${String(height)}:n=2:speed=0`];
|
|
24
|
+
}
|
|
25
|
+
/** The filter that makes the background input the picture's size. */
|
|
26
|
+
export function backgroundFit(background, size) {
|
|
27
|
+
const { width, height } = size;
|
|
28
|
+
const fit = background.kind === 'image' ? `scale=${String(width)}:${String(height)}:force_original_aspect_ratio=increase,crop=${String(width)}:${String(height)},` : '';
|
|
29
|
+
return `${fit}fps=30,format=yuv420p`;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=background.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"background.js","sourceRoot":"","sources":["../../src/compose/background.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { Action } from '../record/steps.ts';
|
|
2
|
+
export type View = {
|
|
3
|
+
x: number;
|
|
4
|
+
y: number;
|
|
5
|
+
zoom: number;
|
|
6
|
+
};
|
|
7
|
+
/** One move of the view, from its start to its end. */
|
|
8
|
+
export type Shot = {
|
|
9
|
+
startMs: number;
|
|
10
|
+
endMs: number;
|
|
11
|
+
from: View;
|
|
12
|
+
to: View;
|
|
13
|
+
easing: 'cubic' | 'even';
|
|
14
|
+
};
|
|
15
|
+
export type CameraPlan = {
|
|
16
|
+
width: number;
|
|
17
|
+
height: number;
|
|
18
|
+
start: View;
|
|
19
|
+
shots: Shot[];
|
|
20
|
+
};
|
|
21
|
+
/** The camera of a recording of `width` × `height` CSS pixels, from its actions. */
|
|
22
|
+
export declare function cameraOfActions(actions: readonly Action[], width: number, height: number): CameraPlan;
|
|
23
|
+
/** An image's slow zoom over `lengthMs`; its size is the input's, read by ffmpeg. */
|
|
24
|
+
export declare function imageZoom(lengthMs: number): CameraPlan;
|
|
25
|
+
/** The view at `ms`. */
|
|
26
|
+
export declare function viewAt(plan: CameraPlan, ms: number): View;
|
|
27
|
+
/**
|
|
28
|
+
* The `perspective` filter that shows the plan's view of a frame `scale` times the plan's size, or of the input's own
|
|
29
|
+
* size for an image's zoom. `offsetMs` is where the part starts in the recording; the frames are at 30 a second.
|
|
30
|
+
*/
|
|
31
|
+
export declare function perspectiveFilter(plan: CameraPlan, scale: number | 'input', offsetMs: number): string;
|
|
32
|
+
//# sourceMappingURL=camera.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"camera.d.ts","sourceRoot":"","sources":["../../src/compose/camera.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAO,MAAM,oBAAoB,CAAC;AAQtD,MAAM,MAAM,IAAI,GAAG;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAE1D,uDAAuD;AACvD,MAAM,MAAM,IAAI,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,IAAI,CAAC;IAAC,EAAE,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,OAAO,GAAG,MAAM,CAAA;CAAE,CAAC;AAEtG,MAAM,MAAM,UAAU,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,IAAI,EAAE,CAAA;CAAE,CAAC;AAiBvF,oFAAoF;AACpF,wBAAgB,eAAe,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,UAAU,CAuBrG;AAED,qFAAqF;AACrF,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,UAAU,CAEtD;AAID,wBAAwB;AACxB,wBAAgB,MAAM,CAAC,IAAI,EAAE,UAAU,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI,CAczD;AAmBD;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAarG"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
const maximumZoom = 1.6;
|
|
2
|
+
const panMs = 600;
|
|
3
|
+
const runGapMs = 2500;
|
|
4
|
+
const holdMs = 1500;
|
|
5
|
+
const outMs = 800;
|
|
6
|
+
const leastInMs = 400;
|
|
7
|
+
const whole = (width, height) => ({ x: width / 2, y: height / 2, zoom: 1 });
|
|
8
|
+
function stopView(box, width, height) {
|
|
9
|
+
const zoom = Math.max(1, Math.min(maximumZoom, (0.8 * width) / box.width, (0.8 * height) / box.height));
|
|
10
|
+
const keep = (center, side) => Math.min(Math.max(center, side / (2 * zoom)), side - side / (2 * zoom));
|
|
11
|
+
return { x: keep(box.x + box.width / 2, width), y: keep(box.y + box.height / 2, height), zoom };
|
|
12
|
+
}
|
|
13
|
+
/** The camera of a recording of `width` × `height` CSS pixels, from its actions. */
|
|
14
|
+
export function cameraOfActions(actions, width, height) {
|
|
15
|
+
const start = whole(width, height);
|
|
16
|
+
const shots = [];
|
|
17
|
+
let current = start;
|
|
18
|
+
let lastEndMs;
|
|
19
|
+
const easeOut = (endMs) => {
|
|
20
|
+
shots.push({ startMs: endMs + holdMs, endMs: endMs + holdMs + outMs, from: current, to: start, easing: 'cubic' });
|
|
21
|
+
current = start;
|
|
22
|
+
};
|
|
23
|
+
for (const action of actions) {
|
|
24
|
+
if ((action.do !== 'click' && action.do !== 'type') || action.box === undefined || action.actMs === undefined)
|
|
25
|
+
continue;
|
|
26
|
+
const target = stopView(action.box, width, height);
|
|
27
|
+
if (lastEndMs !== undefined && action.atMs - lastEndMs <= runGapMs) {
|
|
28
|
+
shots.push({ startMs: action.atMs, endMs: action.atMs + panMs, from: current, to: target, easing: 'cubic' });
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
if (lastEndMs !== undefined)
|
|
32
|
+
easeOut(lastEndMs);
|
|
33
|
+
shots.push({ startMs: action.atMs, endMs: Math.max(action.actMs, action.atMs + leastInMs), from: current, to: target, easing: 'cubic' });
|
|
34
|
+
}
|
|
35
|
+
current = target;
|
|
36
|
+
lastEndMs = action.endMs;
|
|
37
|
+
}
|
|
38
|
+
if (lastEndMs !== undefined)
|
|
39
|
+
easeOut(lastEndMs);
|
|
40
|
+
return { width, height, start, shots };
|
|
41
|
+
}
|
|
42
|
+
/** An image's slow zoom over `lengthMs`; its size is the input's, read by ffmpeg. */
|
|
43
|
+
export function imageZoom(lengthMs) {
|
|
44
|
+
return { width: 1, height: 1, start: whole(1, 1), shots: [{ startMs: 0, endMs: lengthMs, from: whole(1, 1), to: { ...whole(1, 1), zoom: 1.08 }, easing: 'even' }] };
|
|
45
|
+
}
|
|
46
|
+
const cubic = (share) => (share < 0.5 ? 4 * share ** 3 : 1 - (-2 * share + 2) ** 3 / 2);
|
|
47
|
+
/** The view at `ms`. */
|
|
48
|
+
export function viewAt(plan, ms) {
|
|
49
|
+
let view = plan.start;
|
|
50
|
+
for (const shot of plan.shots) {
|
|
51
|
+
if (ms < shot.startMs)
|
|
52
|
+
break;
|
|
53
|
+
if (ms >= shot.endMs) {
|
|
54
|
+
view = shot.to;
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
const share = (ms - shot.startMs) / (shot.endMs - shot.startMs);
|
|
58
|
+
const eased = shot.easing === 'even' ? share : cubic(share);
|
|
59
|
+
const between = (key) => shot.from[key] + (shot.to[key] - shot.from[key]) * eased;
|
|
60
|
+
return { x: between('x'), y: between('y'), zoom: between('zoom') };
|
|
61
|
+
}
|
|
62
|
+
return view;
|
|
63
|
+
}
|
|
64
|
+
const number = (value) => String(Math.round(value * 10_000) / 10_000);
|
|
65
|
+
// One part of the view (x, y, or zoom) as an ffmpeg expression of the time `T` in ms.
|
|
66
|
+
function partExpression(plan, key, time) {
|
|
67
|
+
let expression = number(plan.shots.at(-1)?.to[key] ?? plan.start[key]);
|
|
68
|
+
for (let index = plan.shots.length - 1; index >= 0; index -= 1) {
|
|
69
|
+
const shot = plan.shots[index];
|
|
70
|
+
if (shot === undefined)
|
|
71
|
+
continue;
|
|
72
|
+
const before = number(plan.shots[index - 1]?.to[key] ?? plan.start[key]);
|
|
73
|
+
const share = `((${time}-${number(shot.startMs)})/${number(shot.endMs - shot.startMs)})`;
|
|
74
|
+
const eased = shot.easing === 'even' ? share : `if(lt(${share},0.5),4*pow(${share},3),1-pow(-2*${share}+2,3)/2)`;
|
|
75
|
+
const moving = `(${number(shot.from[key])}+${number(shot.to[key] - shot.from[key])}*${eased})`;
|
|
76
|
+
expression = `if(lt(${time},${number(shot.startMs)}),${before},if(lt(${time},${number(shot.endMs)}),${moving},${expression}))`;
|
|
77
|
+
}
|
|
78
|
+
return expression;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* The `perspective` filter that shows the plan's view of a frame `scale` times the plan's size, or of the input's own
|
|
82
|
+
* size for an image's zoom. `offsetMs` is where the part starts in the recording; the frames are at 30 a second.
|
|
83
|
+
*/
|
|
84
|
+
export function perspectiveFilter(plan, scale, offsetMs) {
|
|
85
|
+
const time = `(in*1000/30+${number(offsetMs)})`;
|
|
86
|
+
const zoom = partExpression(plan, 'zoom', time);
|
|
87
|
+
const [pageWidth, pageHeight] = scale === 'input' ? ['W', 'H'] : [number(plan.width * scale), number(plan.height * scale)];
|
|
88
|
+
const factor = scale === 'input' ? 'W' : number(scale);
|
|
89
|
+
const factorY = scale === 'input' ? 'H' : number(scale);
|
|
90
|
+
const halfWidth = `(${pageWidth}/(2*${zoom}))`;
|
|
91
|
+
const halfHeight = `(${pageHeight}/(2*${zoom}))`;
|
|
92
|
+
const left = `clip(${partExpression(plan, 'x', time)}*${factor}-${halfWidth},0,${pageWidth}-2*${halfWidth})`;
|
|
93
|
+
const top = `clip(${partExpression(plan, 'y', time)}*${factorY}-${halfHeight},0,${pageHeight}-2*${halfHeight})`;
|
|
94
|
+
const right = `${left}+2*${halfWidth}`;
|
|
95
|
+
const bottom = `${top}+2*${halfHeight}`;
|
|
96
|
+
return `perspective=x0='${left}':y0='${top}':x1='${right}':y1='${top}':x2='${left}':y2='${bottom}':x3='${right}':y3='${bottom}':interpolation=cubic:sense=source:eval=frame`;
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=camera.js.map
|