screenwright 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.
Files changed (106) hide show
  1. package/LICENSE +21 -0
  2. package/assets/click-ripple.svg +3 -0
  3. package/assets/cursor-default.svg +10 -0
  4. package/assets/cursor-pointer.svg +40 -0
  5. package/dist/bin/screenwright.d.ts +3 -0
  6. package/dist/bin/screenwright.d.ts.map +1 -0
  7. package/dist/bin/screenwright.js +18 -0
  8. package/dist/bin/screenwright.js.map +1 -0
  9. package/dist/src/commands/compose.d.ts +3 -0
  10. package/dist/src/commands/compose.d.ts.map +1 -0
  11. package/dist/src/commands/compose.js +154 -0
  12. package/dist/src/commands/compose.js.map +1 -0
  13. package/dist/src/commands/generate.d.ts +3 -0
  14. package/dist/src/commands/generate.d.ts.map +1 -0
  15. package/dist/src/commands/generate.js +70 -0
  16. package/dist/src/commands/generate.js.map +1 -0
  17. package/dist/src/commands/init.d.ts +3 -0
  18. package/dist/src/commands/init.d.ts.map +1 -0
  19. package/dist/src/commands/init.js +49 -0
  20. package/dist/src/commands/init.js.map +1 -0
  21. package/dist/src/commands/preview.d.ts +3 -0
  22. package/dist/src/commands/preview.d.ts.map +1 -0
  23. package/dist/src/commands/preview.js +62 -0
  24. package/dist/src/commands/preview.js.map +1 -0
  25. package/dist/src/composition/CursorOverlay.d.ts +11 -0
  26. package/dist/src/composition/CursorOverlay.d.ts.map +1 -0
  27. package/dist/src/composition/CursorOverlay.js +29 -0
  28. package/dist/src/composition/CursorOverlay.js.map +1 -0
  29. package/dist/src/composition/DemoVideo.d.ts +8 -0
  30. package/dist/src/composition/DemoVideo.d.ts.map +1 -0
  31. package/dist/src/composition/DemoVideo.js +18 -0
  32. package/dist/src/composition/DemoVideo.js.map +1 -0
  33. package/dist/src/composition/NarrationTrack.d.ts +9 -0
  34. package/dist/src/composition/NarrationTrack.d.ts.map +1 -0
  35. package/dist/src/composition/NarrationTrack.js +8 -0
  36. package/dist/src/composition/NarrationTrack.js.map +1 -0
  37. package/dist/src/composition/cursor-path.d.ts +31 -0
  38. package/dist/src/composition/cursor-path.d.ts.map +1 -0
  39. package/dist/src/composition/cursor-path.js +78 -0
  40. package/dist/src/composition/cursor-path.js.map +1 -0
  41. package/dist/src/composition/remotion-root.d.ts +3 -0
  42. package/dist/src/composition/remotion-root.d.ts.map +1 -0
  43. package/dist/src/composition/remotion-root.js +34 -0
  44. package/dist/src/composition/remotion-root.js.map +1 -0
  45. package/dist/src/composition/render.d.ts +8 -0
  46. package/dist/src/composition/render.d.ts.map +1 -0
  47. package/dist/src/composition/render.js +24 -0
  48. package/dist/src/composition/render.js.map +1 -0
  49. package/dist/src/config/config-schema.d.ts +40 -0
  50. package/dist/src/config/config-schema.d.ts.map +1 -0
  51. package/dist/src/config/config-schema.js +13 -0
  52. package/dist/src/config/config-schema.js.map +1 -0
  53. package/dist/src/config/defaults.d.ts +4 -0
  54. package/dist/src/config/defaults.d.ts.map +1 -0
  55. package/dist/src/config/defaults.js +17 -0
  56. package/dist/src/config/defaults.js.map +1 -0
  57. package/dist/src/generator/prompts.d.ts +3 -0
  58. package/dist/src/generator/prompts.d.ts.map +1 -0
  59. package/dist/src/generator/prompts.js +125 -0
  60. package/dist/src/generator/prompts.js.map +1 -0
  61. package/dist/src/generator/scenario-generator.d.ts +46 -0
  62. package/dist/src/generator/scenario-generator.d.ts.map +1 -0
  63. package/dist/src/generator/scenario-generator.js +86 -0
  64. package/dist/src/generator/scenario-generator.js.map +1 -0
  65. package/dist/src/index.d.ts +7 -0
  66. package/dist/src/index.d.ts.map +1 -0
  67. package/dist/src/index.js +2 -0
  68. package/dist/src/index.js.map +1 -0
  69. package/dist/src/runtime/action-helpers.d.ts +19 -0
  70. package/dist/src/runtime/action-helpers.d.ts.map +1 -0
  71. package/dist/src/runtime/action-helpers.js +138 -0
  72. package/dist/src/runtime/action-helpers.js.map +1 -0
  73. package/dist/src/runtime/instrumented-page.d.ts +21 -0
  74. package/dist/src/runtime/instrumented-page.d.ts.map +1 -0
  75. package/dist/src/runtime/instrumented-page.js +48 -0
  76. package/dist/src/runtime/instrumented-page.js.map +1 -0
  77. package/dist/src/runtime/timeline-collector.d.ts +20 -0
  78. package/dist/src/runtime/timeline-collector.d.ts.map +1 -0
  79. package/dist/src/runtime/timeline-collector.js +40 -0
  80. package/dist/src/runtime/timeline-collector.js.map +1 -0
  81. package/dist/src/timeline/schema.d.ts +297 -0
  82. package/dist/src/timeline/schema.d.ts.map +1 -0
  83. package/dist/src/timeline/schema.js +72 -0
  84. package/dist/src/timeline/schema.js.map +1 -0
  85. package/dist/src/timeline/types.d.ts +67 -0
  86. package/dist/src/timeline/types.d.ts.map +1 -0
  87. package/dist/src/timeline/types.js +2 -0
  88. package/dist/src/timeline/types.js.map +1 -0
  89. package/dist/src/version.d.ts +2 -0
  90. package/dist/src/version.d.ts.map +1 -0
  91. package/dist/src/version.js +2 -0
  92. package/dist/src/version.js.map +1 -0
  93. package/dist/src/voiceover/narration-timing.d.ts +12 -0
  94. package/dist/src/voiceover/narration-timing.d.ts.map +1 -0
  95. package/dist/src/voiceover/narration-timing.js +25 -0
  96. package/dist/src/voiceover/narration-timing.js.map +1 -0
  97. package/dist/src/voiceover/piper-engine.d.ts +6 -0
  98. package/dist/src/voiceover/piper-engine.d.ts.map +1 -0
  99. package/dist/src/voiceover/piper-engine.js +48 -0
  100. package/dist/src/voiceover/piper-engine.js.map +1 -0
  101. package/dist/src/voiceover/voice-models.d.ts +18 -0
  102. package/dist/src/voiceover/voice-models.d.ts.map +1 -0
  103. package/dist/src/voiceover/voice-models.js +123 -0
  104. package/dist/src/voiceover/voice-models.js.map +1 -0
  105. package/dist/tsconfig.tsbuildinfo +1 -0
  106. package/package.json +69 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Guillaume Dupuy
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.
@@ -0,0 +1,3 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 40 40">
2
+ <circle cx="20" cy="20" r="18" fill="none" stroke="rgba(59, 130, 246, 0.6)" stroke-width="2"/>
3
+ </svg>
@@ -0,0 +1,10 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <!-- Generator: Adobe Illustrator 18.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
3
+ <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
4
+ <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
5
+ viewBox="0 0 28 28" enable-background="new 0 0 28 28" xml:space="preserve">
6
+ <polygon fill="#FFFFFF" points="8.2,20.9 8.2,4.9 19.8,16.5 13,16.5 12.6,16.6 "/>
7
+ <polygon fill="#FFFFFF" points="17.3,21.6 13.7,23.1 9,12 12.7,10.5 "/>
8
+ <rect x="12.5" y="13.6" transform="matrix(0.9221 -0.3871 0.3871 0.9221 -5.7605 6.5909)" width="2" height="8"/>
9
+ <polygon points="9.2,7.3 9.2,18.5 12.2,15.6 12.6,15.5 17.4,15.5 "/>
10
+ </svg>
@@ -0,0 +1,40 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <!-- Generator: Adobe Illustrator 18.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
3
+ <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
4
+ <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
5
+ viewBox="0 0 32 32" enable-background="new 0 0 32 32" xml:space="preserve">
6
+ <g>
7
+ <defs>
8
+ <rect id="SVGID_1_" width="32" height="32"/>
9
+ </defs>
10
+ <clipPath id="SVGID_2_">
11
+ <use xlink:href="#SVGID_1_" overflow="visible"/>
12
+ </clipPath>
13
+ <path clip-path="url(#SVGID_2_)" fill="#FFFFFF" d="M11.3,20.4c-0.3-0.4-0.6-1.1-1.2-2c-0.3-0.5-1.2-1.5-1.5-1.9
14
+ c-0.2-0.4-0.2-0.6-0.1-1c0.1-0.6,0.7-1.1,1.4-1.1c0.5,0,1,0.4,1.4,0.7c0.2,0.2,0.5,0.6,0.7,0.8c0.2,0.2,0.2,0.3,0.4,0.5
15
+ c0.2,0.3,0.3,0.5,0.2,0.1c-0.1-0.5-0.2-1.3-0.4-2.1c-0.1-0.6-0.2-0.7-0.3-1.1c-0.1-0.5-0.2-0.8-0.3-1.3c-0.1-0.3-0.2-1.1-0.3-1.5
16
+ c-0.1-0.5-0.1-1.4,0.3-1.8c0.3-0.3,0.9-0.4,1.3-0.2c0.5,0.3,0.8,1,0.9,1.3c0.2,0.5,0.4,1.2,0.5,2c0.2,1,0.5,2.5,0.5,2.8
17
+ c0-0.4-0.1-1.1,0-1.5c0.1-0.3,0.3-0.7,0.7-0.8c0.3-0.1,0.6-0.1,0.9-0.1c0.3,0.1,0.6,0.3,0.8,0.5c0.4,0.6,0.4,1.9,0.4,1.8
18
+ c0.1-0.4,0.1-1.2,0.3-1.6c0.1-0.2,0.5-0.4,0.7-0.5c0.3-0.1,0.7-0.1,1,0c0.2,0,0.6,0.3,0.7,0.5c0.2,0.3,0.3,1.3,0.4,1.7
19
+ c0,0.1,0.1-0.4,0.3-0.7c0.4-0.6,1.8-0.8,1.9,0.6c0,0.7,0,0.6,0,1.1c0,0.5,0,0.8,0,1.2c0,0.4-0.1,1.3-0.2,1.7
20
+ c-0.1,0.3-0.4,1-0.7,1.4c0,0-1.1,1.2-1.2,1.8c-0.1,0.6-0.1,0.6-0.1,1c0,0.4,0.1,0.9,0.1,0.9s-0.8,0.1-1.2,0c-0.4-0.1-0.9-0.8-1-1.1
21
+ c-0.2-0.3-0.5-0.3-0.7,0c-0.2,0.4-0.7,1.1-1.1,1.1c-0.7,0.1-2.1,0-3.1,0c0,0,0.2-1-0.2-1.4c-0.3-0.3-0.8-0.8-1.1-1.1L11.3,20.4z"/>
22
+
23
+ <path clip-path="url(#SVGID_2_)" fill="none" stroke="#000000" stroke-width="0.75" stroke-linecap="round" stroke-linejoin="round" d="
24
+ M11.3,20.4c-0.3-0.4-0.6-1.1-1.2-2c-0.3-0.5-1.2-1.5-1.5-1.9c-0.2-0.4-0.2-0.6-0.1-1c0.1-0.6,0.7-1.1,1.4-1.1c0.5,0,1,0.4,1.4,0.7
25
+ c0.2,0.2,0.5,0.6,0.7,0.8c0.2,0.2,0.2,0.3,0.4,0.5c0.2,0.3,0.3,0.5,0.2,0.1c-0.1-0.5-0.2-1.3-0.4-2.1c-0.1-0.6-0.2-0.7-0.3-1.1
26
+ c-0.1-0.5-0.2-0.8-0.3-1.3c-0.1-0.3-0.2-1.1-0.3-1.5c-0.1-0.5-0.1-1.4,0.3-1.8c0.3-0.3,0.9-0.4,1.3-0.2c0.5,0.3,0.8,1,0.9,1.3
27
+ c0.2,0.5,0.4,1.2,0.5,2c0.2,1,0.5,2.5,0.5,2.8c0-0.4-0.1-1.1,0-1.5c0.1-0.3,0.3-0.7,0.7-0.8c0.3-0.1,0.6-0.1,0.9-0.1
28
+ c0.3,0.1,0.6,0.3,0.8,0.5c0.4,0.6,0.4,1.9,0.4,1.8c0.1-0.4,0.1-1.2,0.3-1.6c0.1-0.2,0.5-0.4,0.7-0.5c0.3-0.1,0.7-0.1,1,0
29
+ c0.2,0,0.6,0.3,0.7,0.5c0.2,0.3,0.3,1.3,0.4,1.7c0,0.1,0.1-0.4,0.3-0.7c0.4-0.6,1.8-0.8,1.9,0.6c0,0.7,0,0.6,0,1.1
30
+ c0,0.5,0,0.8,0,1.2c0,0.4-0.1,1.3-0.2,1.7c-0.1,0.3-0.4,1-0.7,1.4c0,0-1.1,1.2-1.2,1.8c-0.1,0.6-0.1,0.6-0.1,1
31
+ c0,0.4,0.1,0.9,0.1,0.9s-0.8,0.1-1.2,0c-0.4-0.1-0.9-0.8-1-1.1c-0.2-0.3-0.5-0.3-0.7,0c-0.2,0.4-0.7,1.1-1.1,1.1
32
+ c-0.7,0.1-2.1,0-3.1,0c0,0,0.2-1-0.2-1.4c-0.3-0.3-0.8-0.8-1.1-1.1L11.3,20.4z"/>
33
+
34
+ <line clip-path="url(#SVGID_2_)" fill="none" stroke="#000000" stroke-width="0.75" stroke-linecap="round" x1="19.6" y1="20.7" x2="19.6" y2="17.3"/>
35
+
36
+ <line clip-path="url(#SVGID_2_)" fill="none" stroke="#000000" stroke-width="0.75" stroke-linecap="round" x1="17.6" y1="20.7" x2="17.5" y2="17.3"/>
37
+
38
+ <line clip-path="url(#SVGID_2_)" fill="none" stroke="#000000" stroke-width="0.75" stroke-linecap="round" x1="15.6" y1="17.3" x2="15.6" y2="20.7"/>
39
+ </g>
40
+ </svg>
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=screenwright.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"screenwright.d.ts","sourceRoot":"","sources":["../../bin/screenwright.ts"],"names":[],"mappings":""}
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from 'commander';
3
+ import { VERSION } from '../src/version.js';
4
+ import { initCommand } from '../src/commands/init.js';
5
+ import { generateCommand } from '../src/commands/generate.js';
6
+ import { composeCommand } from '../src/commands/compose.js';
7
+ import { previewCommand } from '../src/commands/preview.js';
8
+ const program = new Command();
9
+ program
10
+ .name('screenwright')
11
+ .description('Turn Playwright E2E tests into polished product demo videos')
12
+ .version(VERSION);
13
+ program.addCommand(initCommand);
14
+ program.addCommand(generateCommand);
15
+ program.addCommand(composeCommand);
16
+ program.addCommand(previewCommand);
17
+ program.parse();
18
+ //# sourceMappingURL=screenwright.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"screenwright.js","sourceRoot":"","sources":["../../bin/screenwright.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAE5D,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,cAAc,CAAC;KACpB,WAAW,CAAC,6DAA6D,CAAC;KAC1E,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;AAChC,OAAO,CAAC,UAAU,CAAC,eAAe,CAAC,CAAC;AACpC,OAAO,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC;AACnC,OAAO,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC;AAEnC,OAAO,CAAC,KAAK,EAAE,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ export declare const composeCommand: Command;
3
+ //# sourceMappingURL=compose.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compose.d.ts","sourceRoot":"","sources":["../../../src/commands/compose.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAWpC,eAAO,MAAM,cAAc,SA+IvB,CAAC"}
@@ -0,0 +1,154 @@
1
+ import { Command } from 'commander';
2
+ import { resolve, basename } from 'node:path';
3
+ import { access, mkdir, rm, stat } from 'node:fs/promises';
4
+ import { pathToFileURL } from 'node:url';
5
+ import ora from 'ora';
6
+ import chalk from 'chalk';
7
+ import { runScenario } from '../runtime/instrumented-page.js';
8
+ import { generateNarration } from '../voiceover/narration-timing.js';
9
+ import { ensureDependencies } from '../voiceover/voice-models.js';
10
+ import { renderDemoVideo } from '../composition/render.js';
11
+ export const composeCommand = new Command('compose')
12
+ .description('Record and compose final demo video')
13
+ .argument('<scenario>', 'Path to demo scenario file')
14
+ .option('--out <path>', 'Output path for final MP4')
15
+ .option('--resolution <res>', 'Video resolution', '1280x720')
16
+ .option('--no-voiceover', 'Disable voiceover')
17
+ .option('--no-cursor', 'Disable cursor overlay')
18
+ .option('--keep-temp', 'Keep temporary files')
19
+ .action(async (scenario, opts) => {
20
+ const scenarioPath = resolve(scenario);
21
+ const [width, height] = opts.resolution.split('x').map(Number);
22
+ if (!width || !height) {
23
+ console.error(chalk.red('Invalid resolution format. Use WIDTHxHEIGHT (e.g., 1280x720)'));
24
+ process.exit(1);
25
+ }
26
+ // Verify scenario file exists
27
+ try {
28
+ await access(scenarioPath);
29
+ }
30
+ catch {
31
+ console.error(chalk.red(`Scenario file not found: ${scenarioPath}`));
32
+ console.error(chalk.dim('Run "screenwright generate --test <path>" to create one.'));
33
+ process.exit(1);
34
+ }
35
+ const outputDir = resolve(opts.out ? resolve(opts.out, '..') : './output');
36
+ const outputPath = opts.out
37
+ ? resolve(opts.out)
38
+ : resolve(outputDir, `${basename(scenarioPath, '.ts')}.mp4`);
39
+ await mkdir(outputDir, { recursive: true });
40
+ // 1. Load scenario module
41
+ let spinner = ora('Loading scenario').start();
42
+ let scenarioFn;
43
+ try {
44
+ const mod = await import(pathToFileURL(scenarioPath).href);
45
+ scenarioFn = mod.default;
46
+ if (typeof scenarioFn !== 'function') {
47
+ spinner.fail('Invalid scenario file');
48
+ console.error(chalk.red('Scenario must export a default async function.'));
49
+ console.error(chalk.dim('Example: export default async function scenario(sw) { ... }'));
50
+ process.exit(1);
51
+ }
52
+ spinner.succeed('Scenario loaded');
53
+ }
54
+ catch (err) {
55
+ spinner.fail('Failed to load scenario');
56
+ console.error(chalk.red(err.message));
57
+ if (err.message.includes('SyntaxError') || err.message.includes('Cannot find')) {
58
+ console.error(chalk.dim('Make sure the scenario is valid TypeScript and has been compiled.'));
59
+ }
60
+ process.exit(1);
61
+ }
62
+ // 2. Run scenario in Playwright
63
+ spinner = ora('Recording scenario in Playwright').start();
64
+ let timeline, tempDir;
65
+ try {
66
+ const result = await runScenario(scenarioFn, {
67
+ scenarioFile: scenarioPath,
68
+ testFile: scenarioPath,
69
+ viewport: { width, height },
70
+ });
71
+ timeline = result.timeline;
72
+ tempDir = result.tempDir;
73
+ spinner.succeed(`Recorded ${timeline.events.length} events`);
74
+ }
75
+ catch (err) {
76
+ spinner.fail('Recording failed');
77
+ if (err.message.includes('Executable doesn\'t exist') || err.message.includes('browserType.launch')) {
78
+ console.error(chalk.red('Playwright browsers not installed.'));
79
+ console.error(chalk.dim('Run: npx playwright install chromium'));
80
+ }
81
+ else if (err.message.includes('net::ERR_CONNECTION_REFUSED')) {
82
+ console.error(chalk.red('Could not connect to the app.'));
83
+ console.error(chalk.dim('Make sure your dev server is running.'));
84
+ }
85
+ else if (err.message.includes('Timeout') || err.message.includes('waiting for')) {
86
+ console.error(chalk.red('Timed out waiting for an element.'));
87
+ console.error(chalk.dim('Check that selectors in the scenario match your app.'));
88
+ }
89
+ else {
90
+ console.error(chalk.red(err.message));
91
+ }
92
+ process.exit(1);
93
+ }
94
+ // 3. Generate voiceover (if enabled)
95
+ let finalTimeline = timeline;
96
+ if (opts.voiceover !== false) {
97
+ const narrationCount = timeline.events.filter(e => e.type === 'narration').length;
98
+ if (narrationCount > 0) {
99
+ spinner = ora(`Generating voiceover (${narrationCount} segments)`).start();
100
+ try {
101
+ const { modelPath } = await ensureDependencies();
102
+ finalTimeline = await generateNarration(timeline, {
103
+ tempDir,
104
+ modelPath,
105
+ });
106
+ spinner.succeed(`Generated ${narrationCount} voiceover segments`);
107
+ }
108
+ catch (err) {
109
+ spinner.warn('Voiceover generation failed — continuing without audio');
110
+ console.error(chalk.dim(err.message));
111
+ console.error(chalk.dim('Tip: use --no-voiceover to skip, or re-run "screenwright init".'));
112
+ }
113
+ }
114
+ }
115
+ // 4. Render final video via Remotion
116
+ spinner = ora('Composing final video').start();
117
+ try {
118
+ await renderDemoVideo({
119
+ timeline: finalTimeline,
120
+ outputPath,
121
+ });
122
+ spinner.succeed('Video composed');
123
+ }
124
+ catch (err) {
125
+ spinner.fail('Composition failed');
126
+ if (err.message.includes('memory') || err.message.includes('OOM')) {
127
+ console.error(chalk.red('Out of memory during rendering.'));
128
+ console.error(chalk.dim('Try a lower resolution: --resolution 1280x720'));
129
+ }
130
+ else {
131
+ console.error(chalk.red(err.message));
132
+ }
133
+ process.exit(1);
134
+ }
135
+ // 5. Cleanup
136
+ if (!opts.keepTemp) {
137
+ await rm(tempDir, { recursive: true, force: true });
138
+ }
139
+ else {
140
+ console.log(chalk.dim(`Temp files kept at: ${tempDir}`));
141
+ }
142
+ // 6. Report
143
+ const fileStats = await stat(outputPath);
144
+ const sizeMB = (fileStats.size / (1024 * 1024)).toFixed(1);
145
+ const durationSec = (finalTimeline.metadata.videoDurationMs / 1000).toFixed(0);
146
+ const mins = Math.floor(Number(durationSec) / 60);
147
+ const secs = Number(durationSec) % 60;
148
+ console.log('');
149
+ console.log(chalk.green(` Demo video saved to: ${outputPath}`));
150
+ console.log(chalk.dim(` Duration: ${mins}:${String(secs).padStart(2, '0')}`));
151
+ console.log(chalk.dim(` Size: ${sizeMB} MB`));
152
+ console.log(chalk.dim(` Events: ${finalTimeline.events.length}`));
153
+ });
154
+ //# sourceMappingURL=compose.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compose.js","sourceRoot":"","sources":["../../../src/commands/compose.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ export declare const generateCommand: Command;
3
+ //# sourceMappingURL=generate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../../src/commands/generate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAOpC,eAAO,MAAM,eAAe,SAyCxB,CAAC"}
@@ -0,0 +1,70 @@
1
+ import { Command } from 'commander';
2
+ import { resolve, basename } from 'node:path';
3
+ import { readFile, mkdir } from 'node:fs/promises';
4
+ import chalk from 'chalk';
5
+ import ora from 'ora';
6
+ import { prepareGeneration, validateScenarioCode } from '../generator/scenario-generator.js';
7
+ export const generateCommand = new Command('generate')
8
+ .description('Generate demo scenario from a Playwright test')
9
+ .option('--test <path>', 'Path to Playwright test file')
10
+ .option('--validate <path>', 'Validate an existing scenario file')
11
+ .option('--out <path>', 'Output path for generated scenario')
12
+ .option('--narration-style <style>', 'Narration style: brief or detailed', 'detailed')
13
+ .option('--app-description <desc>', 'Brief description of the app for context')
14
+ .action(async (opts) => {
15
+ if (opts.validate) {
16
+ await runValidation(resolve(opts.validate));
17
+ return;
18
+ }
19
+ if (!opts.test) {
20
+ console.error(chalk.red('Error: either --test or --validate is required'));
21
+ process.exit(1);
22
+ }
23
+ const testPath = resolve(opts.test);
24
+ const outDir = resolve(opts.out ? resolve(opts.out, '..') : './demos');
25
+ const outPath = opts.out
26
+ ? resolve(opts.out)
27
+ : resolve(outDir, `${basename(testPath, '.spec.ts')}-demo.ts`);
28
+ await mkdir(outDir, { recursive: true });
29
+ const spinner = ora('Reading test file...').start();
30
+ const { systemPrompt, userPrompt } = await prepareGeneration({
31
+ testPath,
32
+ narrationStyle: opts.narrationStyle,
33
+ appDescription: opts.appDescription,
34
+ });
35
+ spinner.succeed('Test file loaded');
36
+ console.log('\n=== System Prompt ===');
37
+ console.log(systemPrompt);
38
+ console.log('\n=== User Prompt ===');
39
+ console.log(userPrompt);
40
+ console.log(`\n${chalk.cyan('Output path:')} ${outPath}`);
41
+ console.log('Pipe the above prompts to an LLM, then save the response to the output path.');
42
+ console.log('Or use the /screenwright skill in Claude Code for automatic generation.');
43
+ });
44
+ async function runValidation(scenarioPath) {
45
+ const spinner = ora('Reading scenario file...').start();
46
+ let code;
47
+ try {
48
+ code = await readFile(scenarioPath, 'utf-8');
49
+ }
50
+ catch (err) {
51
+ spinner.fail(`Cannot read ${scenarioPath}: ${err.message}`);
52
+ process.exit(1);
53
+ }
54
+ spinner.succeed('Scenario file loaded');
55
+ const result = validateScenarioCode(code);
56
+ for (const e of result.errors) {
57
+ console.log(chalk.red(` ERROR [${e.code}]: ${e.message}`));
58
+ }
59
+ for (const w of result.warnings) {
60
+ console.log(chalk.yellow(` WARN [${w.code}]: ${w.message}`));
61
+ }
62
+ if (result.valid) {
63
+ console.log(chalk.green(' Scenario is valid.'));
64
+ process.exit(0);
65
+ }
66
+ else {
67
+ process.exit(1);
68
+ }
69
+ }
70
+ //# sourceMappingURL=generate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate.js","sourceRoot":"","sources":["../../../src/commands/generate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ export declare const initCommand: Command;
3
+ //# sourceMappingURL=init.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../src/commands/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAQpC,eAAO,MAAM,WAAW,SAyCpB,CAAC"}
@@ -0,0 +1,49 @@
1
+ import { Command } from 'commander';
2
+ import { writeFile, access } from 'node:fs/promises';
3
+ import { resolve } from 'node:path';
4
+ import ora from 'ora';
5
+ import chalk from 'chalk';
6
+ import { defaultConfig, serializeConfig } from '../config/defaults.js';
7
+ import { ensureDependencies } from '../voiceover/voice-models.js';
8
+ export const initCommand = new Command('init')
9
+ .description('Bootstrap config and download voice model')
10
+ .option('--voice <model>', 'Voice model to use', 'en_US-amy-medium')
11
+ .option('--skip-voice-download', 'Skip downloading the voice model')
12
+ .action(async (opts) => {
13
+ const configPath = resolve(process.cwd(), 'screenwright.config.ts');
14
+ // Config file
15
+ let configExists = false;
16
+ try {
17
+ await access(configPath);
18
+ configExists = true;
19
+ }
20
+ catch {
21
+ // doesn't exist
22
+ }
23
+ if (configExists) {
24
+ console.log(chalk.dim('screenwright.config.ts already exists, skipping.'));
25
+ }
26
+ else {
27
+ const config = { ...defaultConfig, voice: opts.voice };
28
+ await writeFile(configPath, serializeConfig(config), 'utf-8');
29
+ console.log(chalk.green('Created screenwright.config.ts'));
30
+ }
31
+ // Voice model
32
+ if (!opts.skipVoiceDownload) {
33
+ const spinner = ora('Downloading Piper TTS and voice model').start();
34
+ try {
35
+ await ensureDependencies(opts.voice);
36
+ spinner.succeed('Piper TTS and voice model ready');
37
+ }
38
+ catch (err) {
39
+ spinner.warn('Could not download voice model');
40
+ console.error(chalk.dim(err.message));
41
+ console.error(chalk.dim('Voiceover will be unavailable. Re-run "screenwright init" to retry.'));
42
+ console.error(chalk.dim('Use --no-voiceover with compose to skip voiceover.'));
43
+ }
44
+ }
45
+ console.log('');
46
+ console.log(chalk.green('Screenwright initialized.'));
47
+ console.log(chalk.dim('Next: screenwright generate --test <path>'));
48
+ });
49
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../../src/commands/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACvE,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAElE,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,OAAO,CAAC,MAAM,CAAC;KAC3C,WAAW,CAAC,2CAA2C,CAAC;KACxD,MAAM,CAAC,iBAAiB,EAAE,oBAAoB,EAAE,kBAAkB,CAAC;KACnE,MAAM,CAAC,uBAAuB,EAAE,kCAAkC,CAAC;KACnE,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;IACrB,MAAM,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,wBAAwB,CAAC,CAAC;IAEpE,cAAc;IACd,IAAI,YAAY,GAAG,KAAK,CAAC;IACzB,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,UAAU,CAAC,CAAC;QACzB,YAAY,GAAG,IAAI,CAAC;IACtB,CAAC;IAAC,MAAM,CAAC;QACP,gBAAgB;IAClB,CAAC;IAED,IAAI,YAAY,EAAE,CAAC;QACjB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,kDAAkD,CAAC,CAAC,CAAC;IAC7E,CAAC;SAAM,CAAC;QACN,MAAM,MAAM,GAAG,EAAE,GAAG,aAAa,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC;QACvD,MAAM,SAAS,CAAC,UAAU,EAAE,eAAe,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,CAAC;QAC9D,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,gCAAgC,CAAC,CAAC,CAAC;IAC7D,CAAC;IAED,cAAc;IACd,IAAI,CAAC,IAAI,CAAC,iBAAiB,EAAE,CAAC;QAC5B,MAAM,OAAO,GAAG,GAAG,CAAC,uCAAuC,CAAC,CAAC,KAAK,EAAE,CAAC;QACrE,IAAI,CAAC;YACH,MAAM,kBAAkB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACrC,OAAO,CAAC,OAAO,CAAC,iCAAiC,CAAC,CAAC;QACrD,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAClB,OAAO,CAAC,IAAI,CAAC,gCAAgC,CAAC,CAAC;YAC/C,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;YACtC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,qEAAqE,CAAC,CAAC,CAAC;YAChG,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,oDAAoD,CAAC,CAAC,CAAC;QACjF,CAAC;IACH,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,2BAA2B,CAAC,CAAC,CAAC;IACtD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,2CAA2C,CAAC,CAAC,CAAC;AACtE,CAAC,CAAC,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ export declare const previewCommand: Command;
3
+ //# sourceMappingURL=preview.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preview.d.ts","sourceRoot":"","sources":["../../../src/commands/preview.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAQpC,eAAO,MAAM,cAAc,SAwDvB,CAAC"}
@@ -0,0 +1,62 @@
1
+ import { Command } from 'commander';
2
+ import { resolve, basename } from 'node:path';
3
+ import { access, mkdir, copyFile } from 'node:fs/promises';
4
+ import { pathToFileURL } from 'node:url';
5
+ import ora from 'ora';
6
+ import chalk from 'chalk';
7
+ import { runScenario } from '../runtime/instrumented-page.js';
8
+ export const previewCommand = new Command('preview')
9
+ .description('Quick preview without cursor overlay or voiceover')
10
+ .argument('<scenario>', 'Path to demo scenario file')
11
+ .option('--out <path>', 'Output path for preview video')
12
+ .action(async (scenario, opts) => {
13
+ const scenarioPath = resolve(scenario);
14
+ try {
15
+ await access(scenarioPath);
16
+ }
17
+ catch {
18
+ console.error(chalk.red(`Scenario file not found: ${scenarioPath}`));
19
+ console.error(chalk.dim('Run "screenwright generate --test <path>" to create one.'));
20
+ process.exit(1);
21
+ }
22
+ const outputDir = resolve(opts.out ? resolve(opts.out, '..') : './output');
23
+ const outputPath = opts.out
24
+ ? resolve(opts.out)
25
+ : resolve(outputDir, `${basename(scenarioPath, '.ts')}-preview.webm`);
26
+ await mkdir(outputDir, { recursive: true });
27
+ // 1. Load scenario module
28
+ let spinner = ora('Loading scenario').start();
29
+ let scenarioFn;
30
+ try {
31
+ const mod = await import(pathToFileURL(scenarioPath).href);
32
+ scenarioFn = mod.default;
33
+ if (typeof scenarioFn !== 'function') {
34
+ spinner.fail('Invalid scenario file');
35
+ console.error(chalk.red('Scenario must export a default async function.'));
36
+ process.exit(1);
37
+ }
38
+ spinner.succeed('Scenario loaded');
39
+ }
40
+ catch (err) {
41
+ spinner.fail('Failed to load scenario');
42
+ console.error(chalk.red(err.message));
43
+ process.exit(1);
44
+ }
45
+ // 2. Run scenario
46
+ spinner = ora('Recording preview').start();
47
+ try {
48
+ const { videoFile, timeline } = await runScenario(scenarioFn, {
49
+ scenarioFile: scenarioPath,
50
+ testFile: scenarioPath,
51
+ });
52
+ await copyFile(videoFile, outputPath);
53
+ spinner.succeed(`Preview saved to: ${outputPath}`);
54
+ console.log(chalk.dim(` ${timeline.events.length} events recorded`));
55
+ }
56
+ catch (err) {
57
+ spinner.fail('Recording failed');
58
+ console.error(chalk.red(err.message));
59
+ process.exit(1);
60
+ }
61
+ });
62
+ //# sourceMappingURL=preview.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preview.js","sourceRoot":"","sources":["../../../src/commands/preview.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import React from 'react';
2
+ import type { ActionEvent } from '../timeline/types.js';
3
+ import { type CursorEventWithWaypoints } from './cursor-path.js';
4
+ interface Props {
5
+ cursorEvents: CursorEventWithWaypoints[];
6
+ clickEvents: ActionEvent[];
7
+ fps: number;
8
+ }
9
+ export declare const CursorOverlay: React.FC<Props>;
10
+ export {};
11
+ //# sourceMappingURL=CursorOverlay.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CursorOverlay.d.ts","sourceRoot":"","sources":["../../../src/composition/CursorOverlay.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAqB,KAAK,wBAAwB,EAAE,MAAM,kBAAkB,CAAC;AAGpF,UAAU,KAAK;IACb,YAAY,EAAE,wBAAwB,EAAE,CAAC;IACzC,WAAW,EAAE,WAAW,EAAE,CAAC;IAC3B,GAAG,EAAE,MAAM,CAAC;CACb;AAED,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,KAAK,CAqDzC,CAAC"}
@@ -0,0 +1,29 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useCurrentFrame } from 'remotion';
3
+ import { getCursorPosition } from './cursor-path.js';
4
+ import { interpolate } from 'remotion';
5
+ export const CursorOverlay = ({ cursorEvents, clickEvents, fps }) => {
6
+ const frame = useCurrentFrame();
7
+ const timeMs = (frame / fps) * 1000;
8
+ const { x, y } = getCursorPosition(cursorEvents, timeMs);
9
+ // Click ripple effect
10
+ const activeClick = clickEvents.find(e => timeMs >= e.timestampMs && timeMs <= e.timestampMs + 300);
11
+ const rippleProgress = activeClick ? timeMs - activeClick.timestampMs : 0;
12
+ return (_jsxs("div", { style: { position: 'absolute', inset: 0, pointerEvents: 'none' }, children: [_jsx("svg", { width: "24", height: "24", viewBox: "0 0 24 24", style: {
13
+ position: 'absolute',
14
+ left: x - 4,
15
+ top: y - 2,
16
+ filter: 'drop-shadow(1px 1px 2px rgba(0,0,0,0.3))',
17
+ }, children: _jsx("path", { d: "M5.5 3.21V20.8a.5.5 0 0 0 .85.36l4.86-4.86h6.18a.5.5 0 0 0 .36-.86L5.86 3.21a.5.5 0 0 0-.36.0z", fill: "white", stroke: "black", strokeWidth: "1.5" }) }), activeClick && (_jsx("div", { style: {
18
+ position: 'absolute',
19
+ left: x - 20,
20
+ top: y - 20,
21
+ width: 40,
22
+ height: 40,
23
+ borderRadius: '50%',
24
+ border: '2px solid rgba(59, 130, 246, 0.6)',
25
+ opacity: interpolate(rippleProgress, [0, 300], [1, 0]),
26
+ transform: `scale(${interpolate(rippleProgress, [0, 300], [0.5, 1.5])})`,
27
+ } }))] }));
28
+ };
29
+ //# sourceMappingURL=CursorOverlay.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CursorOverlay.js","sourceRoot":"","sources":["../../../src/composition/CursorOverlay.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAE3C,OAAO,EAAE,iBAAiB,EAAiC,MAAM,kBAAkB,CAAC;AACpF,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAQvC,MAAM,CAAC,MAAM,aAAa,GAAoB,CAAC,EAAE,YAAY,EAAE,WAAW,EAAE,GAAG,EAAE,EAAE,EAAE;IACnF,MAAM,KAAK,GAAG,eAAe,EAAE,CAAC;IAChC,MAAM,MAAM,GAAG,CAAC,KAAK,GAAG,GAAG,CAAC,GAAG,IAAI,CAAC;IAEpC,MAAM,EAAE,CAAC,EAAE,CAAC,EAAE,GAAG,iBAAiB,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;IAEzD,sBAAsB;IACtB,MAAM,WAAW,GAAG,WAAW,CAAC,IAAI,CAClC,CAAC,CAAC,EAAE,CAAC,MAAM,IAAI,CAAC,CAAC,WAAW,IAAI,MAAM,IAAI,CAAC,CAAC,WAAW,GAAG,GAAG,CAC9D,CAAC;IAEF,MAAM,cAAc,GAAG,WAAW,CAAC,CAAC,CAAC,MAAM,GAAG,WAAW,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;IAE1E,OAAO,CACL,eAAK,KAAK,EAAE,EAAE,QAAQ,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,EAAE,aAAa,EAAE,MAAM,EAAE,aAEnE,cACE,KAAK,EAAC,IAAI,EACV,MAAM,EAAC,IAAI,EACX,OAAO,EAAC,WAAW,EACnB,KAAK,EAAE;oBACL,QAAQ,EAAE,UAAU;oBACpB,IAAI,EAAE,CAAC,GAAG,CAAC;oBACX,GAAG,EAAE,CAAC,GAAG,CAAC;oBACV,MAAM,EAAE,0CAA0C;iBACnD,YAED,eACE,CAAC,EAAC,gGAAgG,EAClG,IAAI,EAAC,OAAO,EACZ,MAAM,EAAC,OAAO,EACd,WAAW,EAAC,KAAK,GACjB,GACE,EAGL,WAAW,IAAI,CACd,cACE,KAAK,EAAE;oBACL,QAAQ,EAAE,UAAU;oBACpB,IAAI,EAAE,CAAC,GAAG,EAAE;oBACZ,GAAG,EAAE,CAAC,GAAG,EAAE;oBACX,KAAK,EAAE,EAAE;oBACT,MAAM,EAAE,EAAE;oBACV,YAAY,EAAE,KAAK;oBACnB,MAAM,EAAE,mCAAmC;oBAC3C,OAAO,EAAE,WAAW,CAAC,cAAc,EAAE,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;oBACtD,SAAS,EAAE,SAAS,WAAW,CAAC,cAAc,EAAE,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,GAAG;iBACzE,GACD,CACH,IACG,CACP,CAAC;AACJ,CAAC,CAAC"}
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ import type { ValidatedTimeline } from '../timeline/schema.js';
3
+ interface Props {
4
+ timeline: ValidatedTimeline;
5
+ }
6
+ export declare const DemoVideo: React.FC<Props>;
7
+ export {};
8
+ //# sourceMappingURL=DemoVideo.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DemoVideo.d.ts","sourceRoot":"","sources":["../../../src/composition/DemoVideo.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAK/D,UAAU,KAAK;IACb,QAAQ,EAAE,iBAAiB,CAAC;CAC7B;AAED,eAAO,MAAM,SAAS,EAAE,KAAK,CAAC,EAAE,CAAC,KAAK,CAkCrC,CAAC"}
@@ -0,0 +1,18 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { OffthreadVideo } from 'remotion';
3
+ import { CursorOverlay } from './CursorOverlay.js';
4
+ import { NarrationTrack } from './NarrationTrack.js';
5
+ import { precomputeCursorPaths } from './cursor-path.js';
6
+ export const DemoVideo = ({ timeline }) => {
7
+ const fps = 30;
8
+ const cursorEvents = precomputeCursorPaths(timeline.events.filter((e) => e.type === 'cursor_target'));
9
+ const clickEvents = timeline.events.filter((e) => e.type === 'action' && e.action === 'click');
10
+ const narrations = timeline.events.filter((e) => e.type === 'narration');
11
+ return (_jsxs("div", { style: {
12
+ position: 'relative',
13
+ width: timeline.metadata.viewport.width,
14
+ height: timeline.metadata.viewport.height,
15
+ overflow: 'hidden',
16
+ }, children: [_jsx(OffthreadVideo, { src: timeline.metadata.videoFile }), _jsx(CursorOverlay, { cursorEvents: cursorEvents, clickEvents: clickEvents, fps: fps }), _jsx(NarrationTrack, { narrations: narrations, fps: fps })] }));
17
+ };
18
+ //# sourceMappingURL=DemoVideo.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DemoVideo.js","sourceRoot":"","sources":["../../../src/composition/DemoVideo.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAG1C,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAMzD,MAAM,CAAC,MAAM,SAAS,GAAoB,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE;IACzD,MAAM,GAAG,GAAG,EAAE,CAAC;IAEf,MAAM,YAAY,GAAG,qBAAqB,CACxC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAA0B,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,eAAe,CAAC,CAClF,CAAC;IAEF,MAAM,WAAW,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,CACxC,CAAC,CAAC,EAAoB,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,QAAQ,IAAI,CAAC,CAAC,MAAM,KAAK,OAAO,CACrE,CAAC;IAEF,MAAM,UAAU,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,CACvC,CAAC,CAAC,EAAuB,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,WAAW,CACnD,CAAC;IAEF,OAAO,CACL,eACE,KAAK,EAAE;YACL,QAAQ,EAAE,UAAU;YACpB,KAAK,EAAE,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK;YACvC,MAAM,EAAE,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM;YACzC,QAAQ,EAAE,QAAQ;SACnB,aAGD,KAAC,cAAc,IAAC,GAAG,EAAE,QAAQ,CAAC,QAAQ,CAAC,SAAS,GAAI,EAGpD,KAAC,aAAa,IAAC,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,GAAG,EAAE,GAAG,GAAI,EAGjF,KAAC,cAAc,IAAC,UAAU,EAAE,UAAU,EAAE,GAAG,EAAE,GAAG,GAAI,IAChD,CACP,CAAC;AACJ,CAAC,CAAC"}
@@ -0,0 +1,9 @@
1
+ import React from 'react';
2
+ import type { NarrationEvent } from '../timeline/types.js';
3
+ interface Props {
4
+ narrations: NarrationEvent[];
5
+ fps: number;
6
+ }
7
+ export declare const NarrationTrack: React.FC<Props>;
8
+ export {};
9
+ //# sourceMappingURL=NarrationTrack.d.ts.map