screenwright 0.1.44 → 0.2.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 (67) hide show
  1. package/dist/src/commands/compose.d.ts.map +1 -1
  2. package/dist/src/commands/compose.js +60 -41
  3. package/dist/src/commands/compose.js.map +1 -1
  4. package/dist/src/commands/preview.d.ts.map +1 -1
  5. package/dist/src/commands/preview.js +9 -12
  6. package/dist/src/commands/preview.js.map +1 -1
  7. package/dist/src/composition/DemoVideo.d.ts.map +1 -1
  8. package/dist/src/composition/DemoVideo.js +24 -78
  9. package/dist/src/composition/DemoVideo.js.map +1 -1
  10. package/dist/src/composition/frame-resolve.d.ts +37 -0
  11. package/dist/src/composition/frame-resolve.d.ts.map +1 -0
  12. package/dist/src/composition/frame-resolve.js +114 -0
  13. package/dist/src/composition/frame-resolve.js.map +1 -0
  14. package/dist/src/composition/remotion-root.d.ts.map +1 -1
  15. package/dist/src/composition/remotion-root.js +7 -14
  16. package/dist/src/composition/remotion-root.js.map +1 -1
  17. package/dist/src/composition/render.d.ts.map +1 -1
  18. package/dist/src/composition/render.js +2 -6
  19. package/dist/src/composition/render.js.map +1 -1
  20. package/dist/src/index.d.ts +1 -1
  21. package/dist/src/index.d.ts.map +1 -1
  22. package/dist/src/runtime/action-helpers.d.ts +15 -5
  23. package/dist/src/runtime/action-helpers.d.ts.map +1 -1
  24. package/dist/src/runtime/action-helpers.js +218 -60
  25. package/dist/src/runtime/action-helpers.js.map +1 -1
  26. package/dist/src/runtime/instrumented-page.d.ts +3 -2
  27. package/dist/src/runtime/instrumented-page.d.ts.map +1 -1
  28. package/dist/src/runtime/instrumented-page.js +105 -101
  29. package/dist/src/runtime/instrumented-page.js.map +1 -1
  30. package/dist/src/runtime/narration-preprocess.d.ts +30 -0
  31. package/dist/src/runtime/narration-preprocess.d.ts.map +1 -0
  32. package/dist/src/runtime/narration-preprocess.js +79 -0
  33. package/dist/src/runtime/narration-preprocess.js.map +1 -0
  34. package/dist/src/runtime/timeline-collector.d.ts +1 -7
  35. package/dist/src/runtime/timeline-collector.d.ts.map +1 -1
  36. package/dist/src/runtime/timeline-collector.js +2 -17
  37. package/dist/src/runtime/timeline-collector.js.map +1 -1
  38. package/dist/src/timeline/schema.d.ts +143 -162
  39. package/dist/src/timeline/schema.d.ts.map +1 -1
  40. package/dist/src/timeline/schema.js +12 -18
  41. package/dist/src/timeline/schema.js.map +1 -1
  42. package/dist/src/timeline/types.d.ts +15 -18
  43. package/dist/src/timeline/types.d.ts.map +1 -1
  44. package/dist/src/timeline/types.js.map +1 -1
  45. package/dist/src/version.d.ts +1 -1
  46. package/dist/src/version.d.ts.map +1 -1
  47. package/dist/src/version.js +1 -1
  48. package/dist/src/version.js.map +1 -1
  49. package/dist/tsconfig.tsbuildinfo +1 -1
  50. package/package.json +1 -1
  51. package/skill/SKILL.md +3 -3
  52. package/dist/src/composition/SceneSlide.d.ts +0 -12
  53. package/dist/src/composition/SceneSlide.d.ts.map +0 -1
  54. package/dist/src/composition/SceneSlide.js +0 -71
  55. package/dist/src/composition/SceneSlide.js.map +0 -1
  56. package/dist/src/composition/frame-lookup.d.ts +0 -8
  57. package/dist/src/composition/frame-lookup.d.ts.map +0 -1
  58. package/dist/src/composition/frame-lookup.js +0 -26
  59. package/dist/src/composition/frame-lookup.js.map +0 -1
  60. package/dist/src/composition/time-remap.d.ts +0 -83
  61. package/dist/src/composition/time-remap.d.ts.map +0 -1
  62. package/dist/src/composition/time-remap.js +0 -200
  63. package/dist/src/composition/time-remap.js.map +0 -1
  64. package/dist/src/voiceover/narration-timing.d.ts +0 -18
  65. package/dist/src/voiceover/narration-timing.d.ts.map +0 -1
  66. package/dist/src/voiceover/narration-timing.js +0 -40
  67. package/dist/src/voiceover/narration-timing.js.map +0 -1
@@ -1,5 +1,6 @@
1
1
  import type { Timeline } from '../timeline/types.js';
2
2
  import { type ScreenwrightHelpers } from './action-helpers.js';
3
+ import type { PregeneratedNarration } from './narration-preprocess.js';
3
4
  export type ScenarioFn = (sw: ScreenwrightHelpers) => Promise<void>;
4
5
  export interface RunOptions {
5
6
  scenarioFile: string;
@@ -11,12 +12,12 @@ export interface RunOptions {
11
12
  colorScheme?: 'light' | 'dark';
12
13
  locale?: string;
13
14
  timezoneId?: string;
14
- captureMode?: 'frames' | 'video';
15
+ pregenerated?: PregeneratedNarration[];
15
16
  }
16
17
  export interface RunResult {
17
18
  timeline: Timeline;
18
- videoFile?: string;
19
19
  tempDir: string;
20
+ narrationCount: number;
20
21
  }
21
22
  export declare function runScenario(scenario: ScenarioFn, opts: RunOptions): Promise<RunResult>;
22
23
  //# sourceMappingURL=instrumented-page.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"instrumented-page.d.ts","sourceRoot":"","sources":["../../../src/runtime/instrumented-page.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,QAAQ,EAAc,MAAM,sBAAsB,CAAC;AAEjE,OAAO,EAAiB,KAAK,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAE9E,MAAM,MAAM,UAAU,GAAG,CAAC,EAAE,EAAE,mBAAmB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAEpE,MAAM,WAAW,UAAU;IACzB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7C,WAAW,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC;CAClC;AAED,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE,QAAQ,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,wBAAsB,WAAW,CAAC,QAAQ,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC,CAkK5F"}
1
+ {"version":3,"file":"instrumented-page.d.ts","sourceRoot":"","sources":["../../../src/runtime/instrumented-page.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,QAAQ,EAAmC,MAAM,sBAAsB,CAAC;AAEtF,OAAO,EAAiB,KAAK,mBAAmB,EAAyB,MAAM,qBAAqB,CAAC;AACrG,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAEvE,MAAM,MAAM,UAAU,GAAG,CAAC,EAAE,EAAE,mBAAmB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAEpE,MAAM,WAAW,UAAU;IACzB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7C,WAAW,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,qBAAqB,EAAE,CAAC;CACxC;AAED,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE,QAAQ,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;CACxB;AASD,wBAAsB,WAAW,CAAC,QAAQ,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC,CAkK5F"}
@@ -4,25 +4,26 @@ import { tmpdir } from 'node:os';
4
4
  import { join } from 'node:path';
5
5
  import { TimelineCollector } from './timeline-collector.js';
6
6
  import { createHelpers } from './action-helpers.js';
7
+ const FRAME_INTERVAL_MS = 1000 / 30;
8
+ const DPR = 2;
9
+ function sleep(ms) {
10
+ return new Promise(r => setTimeout(r, Math.max(0, ms)));
11
+ }
7
12
  export async function runScenario(scenario, opts) {
8
13
  const viewport = opts.viewport ?? { width: 1280, height: 720 };
9
- const DPR = 2;
10
14
  const tempDir = await mkdtemp(join(tmpdir(), 'screenwright-'));
11
- const captureMode = opts.captureMode ?? 'frames';
15
+ const framesDir = join(tempDir, 'frames');
16
+ await mkdir(framesDir, { recursive: true });
12
17
  const browser = await chromium.launch({
13
18
  args: ['--disable-gpu', '--font-render-hinting=none', '--disable-lcd-text'],
14
19
  });
15
- const contextOpts = {
20
+ const context = await browser.newContext({
16
21
  viewport,
17
22
  deviceScaleFactor: DPR,
18
23
  colorScheme: opts.colorScheme ?? 'light',
19
24
  locale: opts.locale ?? 'en-US',
20
25
  timezoneId: opts.timezoneId ?? 'America/New_York',
21
- };
22
- if (captureMode === 'video') {
23
- contextOpts.recordVideo = { dir: tempDir, size: viewport };
24
- }
25
- const context = await browser.newContext(contextOpts);
26
+ });
26
27
  // Hide the native cursor so only the Screenwright overlay cursor appears
27
28
  await context.addInitScript(`
28
29
  const s = document.createElement('style');
@@ -31,119 +32,122 @@ export async function runScenario(scenario, opts) {
31
32
  `);
32
33
  const page = await context.newPage();
33
34
  const collector = new TimelineCollector();
34
- let frameManifest;
35
- let cdpSession;
36
- let frameCounter = 0;
37
- let capturing = false;
35
+ const manifest = [];
36
+ const transitionMarkers = [];
37
+ // Narration queue from pre-generated audio
38
+ const narrationQueue = opts.pregenerated ? [...opts.pregenerated] : [];
39
+ let narrationConsumed = 0;
40
+ // Virtual clock: each frame = exactly 1000/30 ms
41
+ let virtualFrameIndex = 0;
42
+ let frameFileCounter = 0;
43
+ // Capture loop state
44
+ let captureRunning = false;
38
45
  let pendingScreenshot = Promise.resolve();
39
- let captureSnapshot;
40
- if (captureMode === 'frames') {
41
- const framesDir = join(tempDir, 'frames');
42
- const snapshotsDir = join(tempDir, 'snapshots');
43
- await mkdir(framesDir, { recursive: true });
44
- await mkdir(snapshotsDir, { recursive: true });
45
- frameManifest = [];
46
- let snapshotCounter = 0;
47
- captureSnapshot = async () => {
48
- snapshotCounter++;
49
- const filename = `snapshot-${String(snapshotCounter).padStart(6, '0')}.jpg`;
50
- await page.screenshot({ path: join(snapshotsDir, filename), type: 'jpeg', quality: 90 });
51
- return `snapshots/${filename}`;
52
- };
53
- cdpSession = await context.newCDPSession(page);
54
- // Hybrid approach: CDP screencast detects WHEN the page changes (high fps,
55
- // low overhead). On each change we take a page.screenshot() which captures
56
- // at the full deviceScaleFactor resolution (2×). The screencast pixel data
57
- // itself is discarded — it only serves as a timing signal.
58
- cdpSession.on('Page.screencastFrame', (params) => {
59
- cdpSession.send('Page.screencastFrameAck', { sessionId: params.sessionId }).catch(() => { });
60
- if (capturing)
61
- return;
62
- capturing = true;
63
- const capturedAt = collector.elapsed();
64
- pendingScreenshot = (async () => {
65
- try {
66
- frameCounter++;
67
- const filename = `frame-${String(frameCounter).padStart(6, '0')}.jpg`;
68
- const filePath = join(framesDir, filename);
69
- await page.screenshot({ path: filePath, type: 'jpeg', quality: 90 });
70
- frameManifest.push({
71
- timestampMs: capturedAt,
72
- file: `frames/${filename}`,
73
- });
74
- }
75
- catch {
76
- // Page may not be ready or is closing
77
- }
78
- capturing = false;
79
- })();
80
- });
81
- }
82
- collector.start();
83
- if (cdpSession) {
84
- await cdpSession.send('Page.startScreencast', {
85
- format: 'jpeg',
86
- quality: 10,
87
- maxWidth: viewport.width,
88
- maxHeight: viewport.height,
89
- everyNthFrame: 1,
90
- });
91
- }
92
- const sw = createHelpers(page, collector, captureSnapshot ? { captureSnapshot } : undefined);
93
- let videoFile;
94
- try {
95
- await scenario(sw);
96
- // Stop screencast and flush pending captures
97
- if (cdpSession) {
98
- await page.waitForTimeout(100);
99
- await cdpSession.send('Page.stopScreencast').catch(() => { });
100
- await pendingScreenshot;
101
- // Take one final 2× screenshot
46
+ async function runCaptureLoop() {
47
+ captureRunning = true;
48
+ while (captureRunning) {
49
+ const start = performance.now();
50
+ frameFileCounter++;
51
+ const filename = `frame-${String(frameFileCounter).padStart(6, '0')}.jpg`;
102
52
  try {
103
- frameCounter++;
104
- const filename = `frame-${String(frameCounter).padStart(6, '0')}.jpg`;
105
- const filePath = join(join(tempDir, 'frames'), filename);
106
- await page.screenshot({ path: filePath, type: 'jpeg', quality: 90 });
107
- frameManifest.push({
108
- timestampMs: collector.elapsed(),
109
- file: `frames/${filename}`,
110
- });
53
+ await page.screenshot({ path: join(framesDir, filename), type: 'jpeg', quality: 90 });
54
+ manifest.push({ type: 'frame', file: `frames/${filename}` });
55
+ virtualFrameIndex++;
111
56
  }
112
57
  catch {
113
- // Page may already be closing
58
+ // Page may not be ready or is closing
114
59
  }
115
- await cdpSession.detach().catch(() => { });
60
+ const elapsed = performance.now() - start;
61
+ await sleep(FRAME_INTERVAL_MS - elapsed);
62
+ }
63
+ }
64
+ async function pauseCapture() {
65
+ captureRunning = false;
66
+ await pendingScreenshot;
67
+ }
68
+ function resumeCapture() {
69
+ if (!captureRunning) {
70
+ pendingScreenshot = runCaptureLoop();
71
+ }
72
+ }
73
+ async function captureOneFrame() {
74
+ frameFileCounter++;
75
+ const filename = `frame-${String(frameFileCounter).padStart(6, '0')}.jpg`;
76
+ await page.screenshot({ path: join(framesDir, filename), type: 'jpeg', quality: 90 });
77
+ const file = `frames/${filename}`;
78
+ manifest.push({ type: 'frame', file });
79
+ virtualFrameIndex++;
80
+ return file;
81
+ }
82
+ function addHold(file, count) {
83
+ if (count <= 0)
84
+ return;
85
+ manifest.push({ type: 'hold', file, count });
86
+ virtualFrameIndex += count;
87
+ }
88
+ function addTransitionMarker(marker) {
89
+ transitionMarkers.push(marker);
90
+ }
91
+ function popNarration() {
92
+ if (narrationQueue.length === 0) {
93
+ throw new Error('No pre-generated narrations remaining in queue');
94
+ }
95
+ narrationConsumed++;
96
+ return narrationQueue.shift();
97
+ }
98
+ function currentTimeMs() {
99
+ return virtualFrameIndex * FRAME_INTERVAL_MS;
100
+ }
101
+ const ctx = {
102
+ pauseCapture,
103
+ resumeCapture,
104
+ captureOneFrame,
105
+ addHold,
106
+ addTransitionMarker,
107
+ popNarration,
108
+ currentTimeMs,
109
+ get manifest() { return manifest; },
110
+ transitionPending: false,
111
+ get narrationCount() { return narrationConsumed; },
112
+ };
113
+ // Expose transitionMarkers for the back-to-back transition warning hack
114
+ ctx._transitionMarkers = transitionMarkers;
115
+ const sw = createHelpers(page, collector, ctx);
116
+ try {
117
+ // Start capture loop
118
+ resumeCapture();
119
+ await scenario(sw);
120
+ // Stop capture loop and flush
121
+ await pauseCapture();
122
+ // Take one final frame
123
+ try {
124
+ await captureOneFrame();
125
+ }
126
+ catch {
127
+ // Page may already be closing
116
128
  }
117
- // Close page to finalize video
118
- await page.close();
119
- if (captureMode === 'video') {
120
- const video = page.video();
121
- videoFile = video ? await video.path() : undefined;
129
+ // Warn about trailing transition
130
+ if (ctx.transitionPending) {
131
+ console.warn('sw.transition() at end of scenario with no following content — discarding marker.');
132
+ transitionMarkers.pop();
133
+ ctx.transitionPending = false;
122
134
  }
123
135
  }
124
136
  finally {
125
- // Ensure browser resources are always cleaned up (idempotent if already closed)
126
137
  await page.close().catch(() => { });
127
138
  await context.close().catch(() => { });
128
139
  await browser.close().catch(() => { });
129
140
  }
130
- const videoDurationMs = collector.getEvents()
131
- .filter(e => e.type !== 'transition')
132
- .reduce((max, e) => {
133
- const ts = e.timestampMs + ('durationMs' in e ? (e.durationMs ?? 0) : 0);
134
- return Math.max(max, ts);
135
- }, 0);
136
141
  const timeline = collector.finalize({
137
142
  testFile: opts.testFile,
138
143
  scenarioFile: opts.scenarioFile,
139
144
  recordedAt: new Date().toISOString(),
140
145
  viewport,
141
- videoDurationMs,
142
- videoFile,
143
- frameManifest,
146
+ frameManifest: manifest,
147
+ transitionMarkers,
144
148
  });
145
149
  const timelinePath = join(tempDir, 'timeline.json');
146
150
  await writeFile(timelinePath, JSON.stringify(timeline, null, 2));
147
- return { timeline, videoFile, tempDir };
151
+ return { timeline, tempDir, narrationCount: narrationConsumed };
148
152
  }
149
153
  //# sourceMappingURL=instrumented-page.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"instrumented-page.js","sourceRoot":"","sources":["../../../src/runtime/instrumented-page.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"instrumented-page.js","sourceRoot":"","sources":["../../../src/runtime/instrumented-page.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ import type { ScreenwrightHelpers } from './action-helpers.js';
2
+ import type { OpenaiVoice } from '../config/config-schema.js';
3
+ export type ScenarioFn = (sw: ScreenwrightHelpers) => Promise<void>;
4
+ export interface PregeneratedNarration {
5
+ text: string;
6
+ audioFile: string;
7
+ durationMs: number;
8
+ }
9
+ export interface PreprocessOptions {
10
+ tempDir: string;
11
+ ttsProvider?: 'piper' | 'openai';
12
+ modelPath?: string;
13
+ openaiVoice?: OpenaiVoice;
14
+ openaiTtsInstructions?: string;
15
+ }
16
+ /**
17
+ * Run the scenario with a stub sw that collects narration texts in order.
18
+ * All page interactions are no-ops.
19
+ */
20
+ export declare function extractNarrations(scenarioFn: ScenarioFn): Promise<string[]>;
21
+ /**
22
+ * Pre-generate all narration audio files in parallel.
23
+ */
24
+ export declare function pregenerateNarrations(texts: string[], opts: PreprocessOptions): Promise<PregeneratedNarration[]>;
25
+ /**
26
+ * Validate that the number of narrations consumed during recording matches
27
+ * the number pre-generated during preprocessing.
28
+ */
29
+ export declare function validateNarrationCount(pregenerated: number, consumed: number): void;
30
+ //# sourceMappingURL=narration-preprocess.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"narration-preprocess.d.ts","sourceRoot":"","sources":["../../../src/runtime/narration-preprocess.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAG/D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAE9D,MAAM,MAAM,UAAU,GAAG,CAAC,EAAE,EAAE,mBAAmB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAEpE,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,qBAAqB,CAAC,EAAE,MAAM,CAAC;CAChC;AA0BD;;;GAGG;AACH,wBAAsB,iBAAiB,CAAC,UAAU,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAgBjF;AAED;;GAEG;AACH,wBAAsB,qBAAqB,CACzC,KAAK,EAAE,MAAM,EAAE,EACf,IAAI,EAAE,iBAAiB,GACtB,OAAO,CAAC,qBAAqB,EAAE,CAAC,CAWlC;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAOnF"}
@@ -0,0 +1,79 @@
1
+ import { join } from 'node:path';
2
+ import { synthesize as piperSynthesize } from '../voiceover/piper-engine.js';
3
+ import { synthesize as openaiSynthesize } from '../voiceover/openai-engine.js';
4
+ /**
5
+ * Recursive proxy that returns async no-ops for any property/method access.
6
+ * Handles arbitrary page.evaluate(), page.waitForSelector(), etc.
7
+ */
8
+ function noopPageProxy() {
9
+ const handler = {
10
+ get(_target, prop) {
11
+ // Prevent infinite thenable loop: await checks .then, which must be
12
+ // undefined so the proxy isn't treated as a thenable.
13
+ if (prop === 'then')
14
+ return undefined;
15
+ return new Proxy(function () { }, {
16
+ apply() {
17
+ return Promise.resolve(new Proxy({}, handler));
18
+ },
19
+ get(_t, p) {
20
+ if (p === 'then')
21
+ return undefined;
22
+ return new Proxy(function () { }, this);
23
+ },
24
+ });
25
+ },
26
+ };
27
+ return new Proxy({}, handler);
28
+ }
29
+ /**
30
+ * Run the scenario with a stub sw that collects narration texts in order.
31
+ * All page interactions are no-ops.
32
+ */
33
+ export async function extractNarrations(scenarioFn) {
34
+ const narrations = [];
35
+ const stub = {
36
+ page: noopPageProxy(),
37
+ navigate: async (_url, opts) => { if (opts?.narration)
38
+ narrations.push(opts.narration); },
39
+ click: async (_sel, opts) => { if (opts?.narration)
40
+ narrations.push(opts.narration); },
41
+ fill: async (_sel, _v, opts) => { if (opts?.narration)
42
+ narrations.push(opts.narration); },
43
+ hover: async (_sel, opts) => { if (opts?.narration)
44
+ narrations.push(opts.narration); },
45
+ press: async (_key, opts) => { if (opts?.narration)
46
+ narrations.push(opts.narration); },
47
+ wait: async () => { },
48
+ narrate: async (text) => { narrations.push(text); },
49
+ scene: async () => { },
50
+ transition: async () => { },
51
+ };
52
+ await scenarioFn(stub);
53
+ return narrations;
54
+ }
55
+ /**
56
+ * Pre-generate all narration audio files in parallel.
57
+ */
58
+ export async function pregenerateNarrations(texts, opts) {
59
+ const provider = opts.ttsProvider ?? 'piper';
60
+ const ext = provider === 'openai' ? '.mp3' : '.wav';
61
+ return Promise.all(texts.map(async (text, i) => {
62
+ const outputPath = join(opts.tempDir, `narration-${i}${ext}`);
63
+ const result = provider === 'openai'
64
+ ? await openaiSynthesize(text, outputPath, opts.openaiVoice, opts.openaiTtsInstructions)
65
+ : await piperSynthesize(text, outputPath, opts.modelPath);
66
+ return { text, audioFile: result.audioPath, durationMs: result.durationMs };
67
+ }));
68
+ }
69
+ /**
70
+ * Validate that the number of narrations consumed during recording matches
71
+ * the number pre-generated during preprocessing.
72
+ */
73
+ export function validateNarrationCount(pregenerated, consumed) {
74
+ if (pregenerated !== consumed) {
75
+ throw new Error(`Scenario produced ${pregenerated} narrations during preprocessing but ${consumed} during recording. ` +
76
+ `Conditional narration is not supported.`);
77
+ }
78
+ }
79
+ //# sourceMappingURL=narration-preprocess.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"narration-preprocess.js","sourceRoot":"","sources":["../../../src/runtime/narration-preprocess.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,UAAU,IAAI,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAC7E,OAAO,EAAE,UAAU,IAAI,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAmB/E;;;GAGG;AACH,SAAS,aAAa;IACpB,MAAM,OAAO,GAAyB;QACpC,GAAG,CAAC,OAAO,EAAE,IAAI;YACf,oEAAoE;YACpE,sDAAsD;YACtD,IAAI,IAAI,KAAK,MAAM;gBAAE,OAAO,SAAS,CAAC;YACtC,OAAO,IAAI,KAAK,CAAC,cAAa,CAAC,EAAE;gBAC/B,KAAK;oBACH,OAAO,OAAO,CAAC,OAAO,CAAC,IAAI,KAAK,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC,CAAC;gBACjD,CAAC;gBACD,GAAG,CAAC,EAAE,EAAE,CAAC;oBACP,IAAI,CAAC,KAAK,MAAM;wBAAE,OAAO,SAAS,CAAC;oBACnC,OAAO,IAAI,KAAK,CAAC,cAAa,CAAC,EAAE,IAA4B,CAAC,CAAC;gBACjE,CAAC;aACF,CAAC,CAAC;QACL,CAAC;KACF,CAAC;IACF,OAAO,IAAI,KAAK,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;AAChC,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,UAAsB;IAC5D,MAAM,UAAU,GAAa,EAAE,CAAC;IAChC,MAAM,IAAI,GAAwB;QAChC,IAAI,EAAE,aAAa,EAAE;QACrB,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,IAAK,EAAE,EAAE,GAAG,IAAI,IAAI,EAAE,SAAS;YAAE,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;QAC1F,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,IAAK,EAAE,EAAE,GAAG,IAAI,IAAI,EAAE,SAAS;YAAE,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;QACvF,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,EAAE,IAAK,EAAE,EAAE,GAAG,IAAI,IAAI,EAAE,SAAS;YAAE,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;QAC1F,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,IAAK,EAAE,EAAE,GAAG,IAAI,IAAI,EAAE,SAAS;YAAE,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;QACvF,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,IAAK,EAAE,EAAE,GAAG,IAAI,IAAI,EAAE,SAAS;YAAE,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;QACvF,IAAI,EAAE,KAAK,IAAI,EAAE,GAAE,CAAC;QACpB,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,GAAG,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACnD,KAAK,EAAE,KAAK,IAAI,EAAE,GAAE,CAAC;QACrB,UAAU,EAAE,KAAK,IAAI,EAAE,GAAE,CAAC;KAC3B,CAAC;IACF,MAAM,UAAU,CAAC,IAAI,CAAC,CAAC;IACvB,OAAO,UAAU,CAAC;AACpB,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,KAAe,EACf,IAAuB;IAEvB,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,IAAI,OAAO,CAAC;IAC7C,MAAM,GAAG,GAAG,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC;IAEpD,OAAO,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE;QAC7C,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,aAAa,CAAC,GAAG,GAAG,EAAE,CAAC,CAAC;QAC9D,MAAM,MAAM,GAAG,QAAQ,KAAK,QAAQ;YAClC,CAAC,CAAC,MAAM,gBAAgB,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,qBAAqB,CAAC;YACxF,CAAC,CAAC,MAAM,eAAe,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;QAC5D,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,CAAC,SAAS,EAAE,UAAU,EAAE,MAAM,CAAC,UAAU,EAAE,CAAC;IAC9E,CAAC,CAAC,CAAC,CAAC;AACN,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,sBAAsB,CAAC,YAAoB,EAAE,QAAgB;IAC3E,IAAI,YAAY,KAAK,QAAQ,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CACb,qBAAqB,YAAY,wCAAwC,QAAQ,qBAAqB;YACtG,yCAAyC,CAC1C,CAAC;IACJ,CAAC;AACH,CAAC"}
@@ -2,18 +2,12 @@ import type { Timeline, TimelineMetadata, TimelineEvent } from '../timeline/type
2
2
  type PartialEvent = {
3
3
  type: string;
4
4
  id?: string;
5
- timestampMs?: number;
5
+ timestampMs: number;
6
6
  [key: string]: unknown;
7
7
  };
8
8
  export declare class TimelineCollector {
9
9
  private events;
10
10
  private counter;
11
- private startTime;
12
- private excludedMs;
13
- start(): void;
14
- elapsed(): number;
15
- /** Subtract wall-clock time that shouldn't count as scenario time (e.g. screenshot I/O). */
16
- excludeTime(ms: number): void;
17
11
  nextId(): string;
18
12
  emit(event: PartialEvent): string;
19
13
  getEvents(): readonly TimelineEvent[];
@@ -1 +1 @@
1
- {"version":3,"file":"timeline-collector.d.ts","sourceRoot":"","sources":["../../../src/runtime/timeline-collector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAGtF,KAAK,YAAY,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,CAAC;AAEhG,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,OAAO,CAAK;IACpB,OAAO,CAAC,SAAS,CAAuB;IACxC,OAAO,CAAC,UAAU,CAAK;IAEvB,KAAK,IAAI,IAAI;IAIb,OAAO,IAAI,MAAM;IAKjB,4FAA4F;IAC5F,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAI7B,MAAM,IAAI,MAAM;IAIhB,IAAI,CAAC,KAAK,EAAE,YAAY,GAAG,MAAM;IAQjC,SAAS,IAAI,SAAS,aAAa,EAAE;IAIrC,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,GAAG,QAAQ;CAc/C"}
1
+ {"version":3,"file":"timeline-collector.d.ts","sourceRoot":"","sources":["../../../src/runtime/timeline-collector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAGtF,KAAK,YAAY,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,CAAC;AAE/F,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,OAAO,CAAK;IAEpB,MAAM,IAAI,MAAM;IAIhB,IAAI,CAAC,KAAK,EAAE,YAAY,GAAG,MAAM;IAOjC,SAAS,IAAI,SAAS,aAAa,EAAE;IAIrC,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,GAAG,QAAQ;CAc/C"}
@@ -2,27 +2,12 @@ import { timelineSchema } from '../timeline/schema.js';
2
2
  export class TimelineCollector {
3
3
  events = [];
4
4
  counter = 0;
5
- startTime = null;
6
- excludedMs = 0;
7
- start() {
8
- this.startTime = performance.now();
9
- }
10
- elapsed() {
11
- if (this.startTime === null)
12
- throw new Error('TimelineCollector not started');
13
- return Math.round(performance.now() - this.startTime - this.excludedMs);
14
- }
15
- /** Subtract wall-clock time that shouldn't count as scenario time (e.g. screenshot I/O). */
16
- excludeTime(ms) {
17
- this.excludedMs += ms;
18
- }
19
5
  nextId() {
20
6
  return `ev-${String(++this.counter).padStart(3, '0')}`;
21
7
  }
22
8
  emit(event) {
23
9
  const id = event.id ?? this.nextId();
24
- const timestampMs = event.timestampMs ?? this.elapsed();
25
- const full = { ...event, id, timestampMs };
10
+ const full = { ...event, id };
26
11
  this.events.push(full);
27
12
  return id;
28
13
  }
@@ -31,7 +16,7 @@ export class TimelineCollector {
31
16
  }
32
17
  finalize(metadata) {
33
18
  const timeline = {
34
- version: 1,
19
+ version: 2,
35
20
  metadata,
36
21
  events: [...this.events],
37
22
  };
@@ -1 +1 @@
1
- {"version":3,"file":"timeline-collector.js","sourceRoot":"","sources":["../../../src/runtime/timeline-collector.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAIvD,MAAM,OAAO,iBAAiB;IACpB,MAAM,GAAoB,EAAE,CAAC;IAC7B,OAAO,GAAG,CAAC,CAAC;IACZ,SAAS,GAAkB,IAAI,CAAC;IAChC,UAAU,GAAG,CAAC,CAAC;IAEvB,KAAK;QACH,IAAI,CAAC,SAAS,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;IACrC,CAAC;IAED,OAAO;QACL,IAAI,IAAI,CAAC,SAAS,KAAK,IAAI;YAAE,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;QAC9E,OAAO,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC;IAC1E,CAAC;IAED,4FAA4F;IAC5F,WAAW,CAAC,EAAU;QACpB,IAAI,CAAC,UAAU,IAAI,EAAE,CAAC;IACxB,CAAC;IAED,MAAM;QACJ,OAAO,MAAM,MAAM,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC;IACzD,CAAC;IAED,IAAI,CAAC,KAAmB;QACtB,MAAM,EAAE,GAAG,KAAK,CAAC,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;QACrC,MAAM,WAAW,GAAG,KAAK,CAAC,WAAW,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;QACxD,MAAM,IAAI,GAAG,EAAE,GAAG,KAAK,EAAE,EAAE,EAAE,WAAW,EAAmB,CAAC;QAC5D,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACvB,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,SAAS;QACP,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;IAED,QAAQ,CAAC,QAA0B;QACjC,MAAM,QAAQ,GAAa;YACzB,OAAO,EAAE,CAAC;YACV,QAAQ;YACR,MAAM,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC;SACzB,CAAC;QAEF,MAAM,MAAM,GAAG,cAAc,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;QAClD,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,MAAM,IAAI,KAAK,CAAC,qBAAqB,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QAC/D,CAAC;QAED,OAAO,QAAQ,CAAC;IAClB,CAAC;CACF"}
1
+ {"version":3,"file":"timeline-collector.js","sourceRoot":"","sources":["../../../src/runtime/timeline-collector.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAIvD,MAAM,OAAO,iBAAiB;IACpB,MAAM,GAAoB,EAAE,CAAC;IAC7B,OAAO,GAAG,CAAC,CAAC;IAEpB,MAAM;QACJ,OAAO,MAAM,MAAM,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC;IACzD,CAAC;IAED,IAAI,CAAC,KAAmB;QACtB,MAAM,EAAE,GAAG,KAAK,CAAC,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;QACrC,MAAM,IAAI,GAAG,EAAE,GAAG,KAAK,EAAE,EAAE,EAAmB,CAAC;QAC/C,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACvB,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,SAAS;QACP,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;IAED,QAAQ,CAAC,QAA0B;QACjC,MAAM,QAAQ,GAAa;YACzB,OAAO,EAAE,CAAC;YACV,QAAQ;YACR,MAAM,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC;SACzB,CAAC;QAEF,MAAM,MAAM,GAAG,cAAc,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;QAClD,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,MAAM,IAAI,KAAK,CAAC,qBAAqB,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QAC/D,CAAC;QAED,OAAO,QAAQ,CAAC;IAClB,CAAC;CACF"}