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.
- package/LICENSE +21 -0
- package/assets/click-ripple.svg +3 -0
- package/assets/cursor-default.svg +10 -0
- package/assets/cursor-pointer.svg +40 -0
- package/dist/bin/screenwright.d.ts +3 -0
- package/dist/bin/screenwright.d.ts.map +1 -0
- package/dist/bin/screenwright.js +18 -0
- package/dist/bin/screenwright.js.map +1 -0
- package/dist/src/commands/compose.d.ts +3 -0
- package/dist/src/commands/compose.d.ts.map +1 -0
- package/dist/src/commands/compose.js +154 -0
- package/dist/src/commands/compose.js.map +1 -0
- package/dist/src/commands/generate.d.ts +3 -0
- package/dist/src/commands/generate.d.ts.map +1 -0
- package/dist/src/commands/generate.js +70 -0
- package/dist/src/commands/generate.js.map +1 -0
- package/dist/src/commands/init.d.ts +3 -0
- package/dist/src/commands/init.d.ts.map +1 -0
- package/dist/src/commands/init.js +49 -0
- package/dist/src/commands/init.js.map +1 -0
- package/dist/src/commands/preview.d.ts +3 -0
- package/dist/src/commands/preview.d.ts.map +1 -0
- package/dist/src/commands/preview.js +62 -0
- package/dist/src/commands/preview.js.map +1 -0
- package/dist/src/composition/CursorOverlay.d.ts +11 -0
- package/dist/src/composition/CursorOverlay.d.ts.map +1 -0
- package/dist/src/composition/CursorOverlay.js +29 -0
- package/dist/src/composition/CursorOverlay.js.map +1 -0
- package/dist/src/composition/DemoVideo.d.ts +8 -0
- package/dist/src/composition/DemoVideo.d.ts.map +1 -0
- package/dist/src/composition/DemoVideo.js +18 -0
- package/dist/src/composition/DemoVideo.js.map +1 -0
- package/dist/src/composition/NarrationTrack.d.ts +9 -0
- package/dist/src/composition/NarrationTrack.d.ts.map +1 -0
- package/dist/src/composition/NarrationTrack.js +8 -0
- package/dist/src/composition/NarrationTrack.js.map +1 -0
- package/dist/src/composition/cursor-path.d.ts +31 -0
- package/dist/src/composition/cursor-path.d.ts.map +1 -0
- package/dist/src/composition/cursor-path.js +78 -0
- package/dist/src/composition/cursor-path.js.map +1 -0
- package/dist/src/composition/remotion-root.d.ts +3 -0
- package/dist/src/composition/remotion-root.d.ts.map +1 -0
- package/dist/src/composition/remotion-root.js +34 -0
- package/dist/src/composition/remotion-root.js.map +1 -0
- package/dist/src/composition/render.d.ts +8 -0
- package/dist/src/composition/render.d.ts.map +1 -0
- package/dist/src/composition/render.js +24 -0
- package/dist/src/composition/render.js.map +1 -0
- package/dist/src/config/config-schema.d.ts +40 -0
- package/dist/src/config/config-schema.d.ts.map +1 -0
- package/dist/src/config/config-schema.js +13 -0
- package/dist/src/config/config-schema.js.map +1 -0
- package/dist/src/config/defaults.d.ts +4 -0
- package/dist/src/config/defaults.d.ts.map +1 -0
- package/dist/src/config/defaults.js +17 -0
- package/dist/src/config/defaults.js.map +1 -0
- package/dist/src/generator/prompts.d.ts +3 -0
- package/dist/src/generator/prompts.d.ts.map +1 -0
- package/dist/src/generator/prompts.js +125 -0
- package/dist/src/generator/prompts.js.map +1 -0
- package/dist/src/generator/scenario-generator.d.ts +46 -0
- package/dist/src/generator/scenario-generator.d.ts.map +1 -0
- package/dist/src/generator/scenario-generator.js +86 -0
- package/dist/src/generator/scenario-generator.js.map +1 -0
- package/dist/src/index.d.ts +7 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +2 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/runtime/action-helpers.d.ts +19 -0
- package/dist/src/runtime/action-helpers.d.ts.map +1 -0
- package/dist/src/runtime/action-helpers.js +138 -0
- package/dist/src/runtime/action-helpers.js.map +1 -0
- package/dist/src/runtime/instrumented-page.d.ts +21 -0
- package/dist/src/runtime/instrumented-page.d.ts.map +1 -0
- package/dist/src/runtime/instrumented-page.js +48 -0
- package/dist/src/runtime/instrumented-page.js.map +1 -0
- package/dist/src/runtime/timeline-collector.d.ts +20 -0
- package/dist/src/runtime/timeline-collector.d.ts.map +1 -0
- package/dist/src/runtime/timeline-collector.js +40 -0
- package/dist/src/runtime/timeline-collector.js.map +1 -0
- package/dist/src/timeline/schema.d.ts +297 -0
- package/dist/src/timeline/schema.d.ts.map +1 -0
- package/dist/src/timeline/schema.js +72 -0
- package/dist/src/timeline/schema.js.map +1 -0
- package/dist/src/timeline/types.d.ts +67 -0
- package/dist/src/timeline/types.d.ts.map +1 -0
- package/dist/src/timeline/types.js +2 -0
- package/dist/src/timeline/types.js.map +1 -0
- package/dist/src/version.d.ts +2 -0
- package/dist/src/version.d.ts.map +1 -0
- package/dist/src/version.js +2 -0
- package/dist/src/version.js.map +1 -0
- package/dist/src/voiceover/narration-timing.d.ts +12 -0
- package/dist/src/voiceover/narration-timing.d.ts.map +1 -0
- package/dist/src/voiceover/narration-timing.js +25 -0
- package/dist/src/voiceover/narration-timing.js.map +1 -0
- package/dist/src/voiceover/piper-engine.d.ts +6 -0
- package/dist/src/voiceover/piper-engine.d.ts.map +1 -0
- package/dist/src/voiceover/piper-engine.js +48 -0
- package/dist/src/voiceover/piper-engine.js.map +1 -0
- package/dist/src/voiceover/voice-models.d.ts +18 -0
- package/dist/src/voiceover/voice-models.d.ts.map +1 -0
- package/dist/src/voiceover/voice-models.js +123 -0
- package/dist/src/voiceover/voice-models.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +69 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NarrationTrack.d.ts","sourceRoot":"","sources":["../../../src/composition/NarrationTrack.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D,UAAU,KAAK;IACb,UAAU,EAAE,cAAc,EAAE,CAAC;IAC7B,GAAG,EAAE,MAAM,CAAC;CACb;AAED,eAAO,MAAM,cAAc,EAAE,KAAK,CAAC,EAAE,CAAC,KAAK,CAY1C,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { Audio, Sequence } from 'remotion';
|
|
3
|
+
export const NarrationTrack = ({ narrations, fps }) => {
|
|
4
|
+
return (_jsx(_Fragment, { children: narrations
|
|
5
|
+
.filter(n => n.audioFile)
|
|
6
|
+
.map((n, i) => (_jsx(Sequence, { from: Math.round((n.timestampMs / 1000) * fps), children: _jsx(Audio, { src: n.audioFile }) }, n.id))) }));
|
|
7
|
+
};
|
|
8
|
+
//# sourceMappingURL=NarrationTrack.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NarrationTrack.js","sourceRoot":"","sources":["../../../src/composition/NarrationTrack.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAc,MAAM,UAAU,CAAC;AAQvD,MAAM,CAAC,MAAM,cAAc,GAAoB,CAAC,EAAE,UAAU,EAAE,GAAG,EAAE,EAAE,EAAE;IACrE,OAAO,CACL,4BACG,UAAU;aACR,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;aACxB,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CACb,KAAC,QAAQ,IAAY,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,GAAG,IAAI,CAAC,GAAG,GAAG,CAAC,YACjE,KAAC,KAAK,IAAC,GAAG,EAAE,CAAC,CAAC,SAAU,GAAI,IADf,CAAC,CAAC,EAAE,CAER,CACZ,CAAC,GACH,CACJ,CAAC;AACJ,CAAC,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { CursorTargetEvent } from '../timeline/types.js';
|
|
2
|
+
interface Point {
|
|
3
|
+
x: number;
|
|
4
|
+
y: number;
|
|
5
|
+
}
|
|
6
|
+
export interface CursorWaypoint {
|
|
7
|
+
x: number;
|
|
8
|
+
y: number;
|
|
9
|
+
t: number;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Pre-compute waypoints along a bezier curve for a cursor movement event.
|
|
13
|
+
* Returns N waypoints (default 20) for smooth interpolation.
|
|
14
|
+
*/
|
|
15
|
+
export declare function computeWaypoints(from: Point, to: Point, steps?: number): CursorWaypoint[];
|
|
16
|
+
export interface CursorEventWithWaypoints extends CursorTargetEvent {
|
|
17
|
+
waypoints: CursorWaypoint[];
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Pre-compute waypoints for all cursor events in a timeline.
|
|
21
|
+
* Called once before rendering — Remotion components index into
|
|
22
|
+
* the waypoints array by progress.
|
|
23
|
+
*/
|
|
24
|
+
export declare function precomputeCursorPaths(events: CursorTargetEvent[]): CursorEventWithWaypoints[];
|
|
25
|
+
/**
|
|
26
|
+
* Find cursor position at a given time in milliseconds.
|
|
27
|
+
* Searches through cursor events with precomputed waypoints.
|
|
28
|
+
*/
|
|
29
|
+
export declare function getCursorPosition(events: CursorEventWithWaypoints[], timeMs: number): Point;
|
|
30
|
+
export {};
|
|
31
|
+
//# sourceMappingURL=cursor-path.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cursor-path.d.ts","sourceRoot":"","sources":["../../../src/composition/cursor-path.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAE9D,UAAU,KAAK;IACb,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AAmCD,MAAM,WAAW,cAAc;IAC7B,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,SAAK,GAAG,cAAc,EAAE,CAcrF;AAED,MAAM,WAAW,wBAAyB,SAAQ,iBAAiB;IACjE,SAAS,EAAE,cAAc,EAAE,CAAC;CAC7B;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,iBAAiB,EAAE,GAAG,wBAAwB,EAAE,CAQ7F;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,wBAAwB,EAAE,EAClC,MAAM,EAAE,MAAM,GACb,KAAK,CAwBP"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generate bezier control points for natural cursor movement.
|
|
3
|
+
* Produces a slightly curved path with randomized control points
|
|
4
|
+
* to avoid perfectly straight lines.
|
|
5
|
+
*/
|
|
6
|
+
function bezierControlPoints(from, to) {
|
|
7
|
+
const dx = to.x - from.x;
|
|
8
|
+
const dy = to.y - from.y;
|
|
9
|
+
// Perpendicular offset for curve (5-15% of distance)
|
|
10
|
+
const dist = Math.sqrt(dx * dx + dy * dy);
|
|
11
|
+
const offset = dist * (0.05 + Math.random() * 0.1);
|
|
12
|
+
// Normal vector
|
|
13
|
+
const nx = -dy / (dist || 1);
|
|
14
|
+
const ny = dx / (dist || 1);
|
|
15
|
+
// Place control points at 1/3 and 2/3 along the path with perpendicular offset
|
|
16
|
+
const sign = Math.random() > 0.5 ? 1 : -1;
|
|
17
|
+
return [
|
|
18
|
+
{ x: from.x + dx * 0.33 + nx * offset * sign, y: from.y + dy * 0.33 + ny * offset * sign },
|
|
19
|
+
{ x: from.x + dx * 0.66 - nx * offset * sign * 0.5, y: from.y + dy * 0.66 - ny * offset * sign * 0.5 },
|
|
20
|
+
];
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Evaluate cubic bezier at parameter t (0..1).
|
|
24
|
+
*/
|
|
25
|
+
function cubicBezier(t, p0, p1, p2, p3) {
|
|
26
|
+
const u = 1 - t;
|
|
27
|
+
return u * u * u * p0 + 3 * u * u * t * p1 + 3 * u * t * t * p2 + t * t * t * p3;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Pre-compute waypoints along a bezier curve for a cursor movement event.
|
|
31
|
+
* Returns N waypoints (default 20) for smooth interpolation.
|
|
32
|
+
*/
|
|
33
|
+
export function computeWaypoints(from, to, steps = 20) {
|
|
34
|
+
const [cp1, cp2] = bezierControlPoints(from, to);
|
|
35
|
+
const waypoints = [];
|
|
36
|
+
for (let i = 0; i <= steps; i++) {
|
|
37
|
+
const t = i / steps;
|
|
38
|
+
waypoints.push({
|
|
39
|
+
x: cubicBezier(t, from.x, cp1.x, cp2.x, to.x),
|
|
40
|
+
y: cubicBezier(t, from.y, cp1.y, cp2.y, to.y),
|
|
41
|
+
t,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
return waypoints;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Pre-compute waypoints for all cursor events in a timeline.
|
|
48
|
+
* Called once before rendering — Remotion components index into
|
|
49
|
+
* the waypoints array by progress.
|
|
50
|
+
*/
|
|
51
|
+
export function precomputeCursorPaths(events) {
|
|
52
|
+
return events.map(event => ({
|
|
53
|
+
...event,
|
|
54
|
+
waypoints: computeWaypoints({ x: event.fromX, y: event.fromY }, { x: event.toX, y: event.toY }),
|
|
55
|
+
}));
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Find cursor position at a given time in milliseconds.
|
|
59
|
+
* Searches through cursor events with precomputed waypoints.
|
|
60
|
+
*/
|
|
61
|
+
export function getCursorPosition(events, timeMs) {
|
|
62
|
+
// Find active movement
|
|
63
|
+
const active = events.find(e => timeMs >= e.timestampMs && timeMs <= e.timestampMs + e.moveDurationMs);
|
|
64
|
+
if (active) {
|
|
65
|
+
const progress = (timeMs - active.timestampMs) / active.moveDurationMs;
|
|
66
|
+
const idx = Math.min(active.waypoints.length - 1, Math.floor(progress * (active.waypoints.length - 1)));
|
|
67
|
+
return active.waypoints[idx];
|
|
68
|
+
}
|
|
69
|
+
// Hold at last known position
|
|
70
|
+
const past = events.filter(e => e.timestampMs + e.moveDurationMs <= timeMs);
|
|
71
|
+
const last = past[past.length - 1];
|
|
72
|
+
if (last) {
|
|
73
|
+
return { x: last.toX, y: last.toY };
|
|
74
|
+
}
|
|
75
|
+
// Default: center of viewport
|
|
76
|
+
return { x: 640, y: 360 };
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=cursor-path.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cursor-path.js","sourceRoot":"","sources":["../../../src/composition/cursor-path.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remotion-root.d.ts","sourceRoot":"","sources":["../../../src/composition/remotion-root.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAU1B,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAyChC,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { Composition } from 'remotion';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
import { DemoVideo } from './DemoVideo.js';
|
|
5
|
+
import { timelineSchema } from '../timeline/schema.js';
|
|
6
|
+
const propsSchema = z.object({
|
|
7
|
+
timeline: timelineSchema,
|
|
8
|
+
});
|
|
9
|
+
export const RemotionRoot = () => {
|
|
10
|
+
return (_jsx(_Fragment, { children: _jsx(Composition, { id: "DemoVideo", lazyComponent: () => Promise.resolve({ default: DemoVideo }), schema: propsSchema, durationInFrames: 300, fps: 30, width: 1280, height: 720, defaultProps: {
|
|
11
|
+
timeline: {
|
|
12
|
+
version: 1,
|
|
13
|
+
metadata: {
|
|
14
|
+
testFile: '',
|
|
15
|
+
scenarioFile: '',
|
|
16
|
+
recordedAt: new Date().toISOString(),
|
|
17
|
+
viewport: { width: 1280, height: 720 },
|
|
18
|
+
videoDurationMs: 0,
|
|
19
|
+
videoFile: '',
|
|
20
|
+
},
|
|
21
|
+
events: [],
|
|
22
|
+
},
|
|
23
|
+
}, calculateMetadata: ({ props }) => {
|
|
24
|
+
const fps = 30;
|
|
25
|
+
const durationInFrames = Math.max(30, Math.ceil((props.timeline.metadata.videoDurationMs / 1000) * fps));
|
|
26
|
+
return {
|
|
27
|
+
durationInFrames,
|
|
28
|
+
fps,
|
|
29
|
+
width: props.timeline.metadata.viewport.width,
|
|
30
|
+
height: props.timeline.metadata.viewport.height,
|
|
31
|
+
};
|
|
32
|
+
} }) }));
|
|
33
|
+
};
|
|
34
|
+
//# sourceMappingURL=remotion-root.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remotion-root.js","sourceRoot":"","sources":["../../../src/composition/remotion-root.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAEvD,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,CAAC;IAC3B,QAAQ,EAAE,cAAc;CACzB,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,YAAY,GAAa,GAAG,EAAE;IACzC,OAAO,CACL,4BACE,KAAC,WAAW,IACV,EAAE,EAAC,WAAW,EACd,aAAa,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,SAAgB,EAAE,CAAC,EACnE,MAAM,EAAE,WAAW,EACnB,gBAAgB,EAAE,GAAG,EACrB,GAAG,EAAE,EAAE,EACP,KAAK,EAAE,IAAI,EACX,MAAM,EAAE,GAAG,EACX,YAAY,EAAE;gBACZ,QAAQ,EAAE;oBACR,OAAO,EAAE,CAAU;oBACnB,QAAQ,EAAE;wBACR,QAAQ,EAAE,EAAE;wBACZ,YAAY,EAAE,EAAE;wBAChB,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;wBACpC,QAAQ,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE;wBACtC,eAAe,EAAE,CAAC;wBAClB,SAAS,EAAE,EAAE;qBACd;oBACD,MAAM,EAAE,EAAE;iBACX;aACF,EACD,iBAAiB,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE;gBAC/B,MAAM,GAAG,GAAG,EAAE,CAAC;gBACf,MAAM,gBAAgB,GAAG,IAAI,CAAC,GAAG,CAC/B,EAAE,EACF,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,eAAe,GAAG,IAAI,CAAC,GAAG,GAAG,CAAC,CAClE,CAAC;gBACF,OAAO;oBACL,gBAAgB;oBAChB,GAAG;oBACH,KAAK,EAAE,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK;oBAC7C,MAAM,EAAE,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM;iBAChD,CAAC;YACJ,CAAC,GACD,GACD,CACJ,CAAC;AACJ,CAAC,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Timeline } from '../timeline/types.js';
|
|
2
|
+
export interface RenderOptions {
|
|
3
|
+
timeline: Timeline;
|
|
4
|
+
outputPath: string;
|
|
5
|
+
entryPoint?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function renderDemoVideo(opts: RenderOptions): Promise<string>;
|
|
8
|
+
//# sourceMappingURL=render.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../../src/composition/render.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAErD,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,QAAQ,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,wBAAsB,eAAe,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CAuB1E"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { bundle } from '@remotion/bundler';
|
|
2
|
+
import { renderMedia, selectComposition } from '@remotion/renderer';
|
|
3
|
+
import { resolve } from 'node:path';
|
|
4
|
+
export async function renderDemoVideo(opts) {
|
|
5
|
+
const entryPoint = opts.entryPoint ?? resolve(import.meta.dirname, 'remotion-root.js');
|
|
6
|
+
const bundlePath = await bundle({
|
|
7
|
+
entryPoint,
|
|
8
|
+
// Remotion bundles with webpack — no extra config needed
|
|
9
|
+
});
|
|
10
|
+
const composition = await selectComposition({
|
|
11
|
+
serveUrl: bundlePath,
|
|
12
|
+
id: 'DemoVideo',
|
|
13
|
+
inputProps: { timeline: opts.timeline },
|
|
14
|
+
});
|
|
15
|
+
await renderMedia({
|
|
16
|
+
composition,
|
|
17
|
+
serveUrl: bundlePath,
|
|
18
|
+
codec: 'h264',
|
|
19
|
+
outputLocation: opts.outputPath,
|
|
20
|
+
inputProps: { timeline: opts.timeline },
|
|
21
|
+
});
|
|
22
|
+
return opts.outputPath;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=render.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render.js","sourceRoot":"","sources":["../../../src/composition/render.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC3C,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACpE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AASpC,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,IAAmB;IACvD,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,kBAAkB,CAAC,CAAC;IAEvF,MAAM,UAAU,GAAG,MAAM,MAAM,CAAC;QAC9B,UAAU;QACV,yDAAyD;KAC1D,CAAC,CAAC;IAEH,MAAM,WAAW,GAAG,MAAM,iBAAiB,CAAC;QAC1C,QAAQ,EAAE,UAAU;QACpB,EAAE,EAAE,WAAW;QACf,UAAU,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE;KACxC,CAAC,CAAC;IAEH,MAAM,WAAW,CAAC;QAChB,WAAW;QACX,QAAQ,EAAE,UAAU;QACpB,KAAK,EAAE,MAAM;QACb,cAAc,EAAE,IAAI,CAAC,UAAU;QAC/B,UAAU,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE;KACxC,CAAC,CAAC;IAEH,OAAO,IAAI,CAAC,UAAU,CAAC;AACzB,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const configSchema: z.ZodObject<{
|
|
3
|
+
voice: z.ZodDefault<z.ZodString>;
|
|
4
|
+
resolution: z.ZodDefault<z.ZodObject<{
|
|
5
|
+
width: z.ZodNumber;
|
|
6
|
+
height: z.ZodNumber;
|
|
7
|
+
}, "strip", z.ZodTypeAny, {
|
|
8
|
+
width: number;
|
|
9
|
+
height: number;
|
|
10
|
+
}, {
|
|
11
|
+
width: number;
|
|
12
|
+
height: number;
|
|
13
|
+
}>>;
|
|
14
|
+
outputDir: z.ZodDefault<z.ZodString>;
|
|
15
|
+
locale: z.ZodDefault<z.ZodString>;
|
|
16
|
+
colorScheme: z.ZodDefault<z.ZodEnum<["light", "dark"]>>;
|
|
17
|
+
timezoneId: z.ZodDefault<z.ZodString>;
|
|
18
|
+
}, "strip", z.ZodTypeAny, {
|
|
19
|
+
voice: string;
|
|
20
|
+
resolution: {
|
|
21
|
+
width: number;
|
|
22
|
+
height: number;
|
|
23
|
+
};
|
|
24
|
+
outputDir: string;
|
|
25
|
+
locale: string;
|
|
26
|
+
colorScheme: "light" | "dark";
|
|
27
|
+
timezoneId: string;
|
|
28
|
+
}, {
|
|
29
|
+
voice?: string | undefined;
|
|
30
|
+
resolution?: {
|
|
31
|
+
width: number;
|
|
32
|
+
height: number;
|
|
33
|
+
} | undefined;
|
|
34
|
+
outputDir?: string | undefined;
|
|
35
|
+
locale?: string | undefined;
|
|
36
|
+
colorScheme?: "light" | "dark" | undefined;
|
|
37
|
+
timezoneId?: string | undefined;
|
|
38
|
+
}>;
|
|
39
|
+
export type ScreenwrightConfig = z.infer<typeof configSchema>;
|
|
40
|
+
//# sourceMappingURL=config-schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-schema.d.ts","sourceRoot":"","sources":["../../../src/config/config-schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAUvB,CAAC;AAEH,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export const configSchema = z.object({
|
|
3
|
+
voice: z.string().default('en_US-amy-medium'),
|
|
4
|
+
resolution: z.object({
|
|
5
|
+
width: z.number().int().positive(),
|
|
6
|
+
height: z.number().int().positive(),
|
|
7
|
+
}).default({ width: 1280, height: 720 }),
|
|
8
|
+
outputDir: z.string().default('./output'),
|
|
9
|
+
locale: z.string().default('en-US'),
|
|
10
|
+
colorScheme: z.enum(['light', 'dark']).default('light'),
|
|
11
|
+
timezoneId: z.string().default('America/New_York'),
|
|
12
|
+
});
|
|
13
|
+
//# sourceMappingURL=config-schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-schema.js","sourceRoot":"","sources":["../../../src/config/config-schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,CAAC,MAAM,CAAC;IACnC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,kBAAkB,CAAC;IAC7C,UAAU,EAAE,CAAC,CAAC,MAAM,CAAC;QACnB,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;QAClC,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;KACpC,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC;IACxC,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC;IACzC,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC;IACnC,WAAW,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC;IACvD,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,kBAAkB,CAAC;CACnD,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"defaults.d.ts","sourceRoot":"","sources":["../../../src/config/defaults.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAE7D,eAAO,MAAM,aAAa,EAAE,kBAO3B,CAAC;AAEF,wBAAgB,eAAe,CAAC,MAAM,EAAE,kBAAkB,GAAG,MAAM,CAOlE"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export const defaultConfig = {
|
|
2
|
+
voice: 'en_US-amy-medium',
|
|
3
|
+
resolution: { width: 1280, height: 720 },
|
|
4
|
+
outputDir: './output',
|
|
5
|
+
locale: 'en-US',
|
|
6
|
+
colorScheme: 'light',
|
|
7
|
+
timezoneId: 'America/New_York',
|
|
8
|
+
};
|
|
9
|
+
export function serializeConfig(config) {
|
|
10
|
+
return `import type { ScreenwrightConfig } from 'screenwright';
|
|
11
|
+
|
|
12
|
+
const config: ScreenwrightConfig = ${JSON.stringify(config, null, 2)};
|
|
13
|
+
|
|
14
|
+
export default config;
|
|
15
|
+
`;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=defaults.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"defaults.js","sourceRoot":"","sources":["../../../src/config/defaults.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,aAAa,GAAuB;IAC/C,KAAK,EAAE,kBAAkB;IACzB,UAAU,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE;IACxC,SAAS,EAAE,UAAU;IACrB,MAAM,EAAE,OAAO;IACf,WAAW,EAAE,OAAO;IACpB,UAAU,EAAE,kBAAkB;CAC/B,CAAC;AAEF,MAAM,UAAU,eAAe,CAAC,MAA0B;IACxD,OAAO;;qCAE4B,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;;;CAGnE,CAAC;AACF,CAAC"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export declare const SYSTEM_PROMPT = "You are Screenwright, a tool that converts Playwright E2E tests into cinematic product demo scenarios.\n\nGiven a Playwright test file, generate a new TypeScript file that uses the Screenwright helpers API to create a polished demo with:\n- Natural pacing (deliberate waits between actions)\n- Human-friendly data (replace faker/test data with realistic values)\n- Narration cues (explain what's happening to the viewer)\n- Scene boundaries (organize the demo into logical chapters)\n\nThe output must be a valid TypeScript file with a default export function that takes a ScreenwrightHelpers parameter.\n\nAvailable helpers:\n- sw.scene(title, description?) \u2014 mark a scene/chapter boundary\n- sw.navigate(url, { narration? }) \u2014 navigate to a URL\n- sw.click(selector, { narration? }) \u2014 click an element\n- sw.fill(selector, value, { narration? }) \u2014 type into an input\n- sw.hover(selector, { narration? }) \u2014 hover over an element\n- sw.press(key, { narration? }) \u2014 press a keyboard key\n- sw.wait(ms) \u2014 pause for pacing\n- sw.narrate(text) \u2014 speak narration without an action\n\nRules:\n1. Import only ScreenwrightHelpers from 'screenwright'\n2. Export a default async function\n3. Replace ALL test/faker data with realistic human-friendly values\n4. Add narration to key actions explaining what the user is doing\n5. Add sw.wait() calls between logical steps for pacing\n6. Use sw.scene() to organize into 2-5 scenes\n7. Keep the same user flow as the original test\n8. Do NOT include assertions \u2014 this is a demo, not a test\n\nOutput format \u2014 always follow this exact structure:\n\n```typescript\nimport type { ScreenwrightHelpers } from 'screenwright';\n\nexport default async function scenario(sw: ScreenwrightHelpers) {\n // Scene 1\n await sw.scene('...');\n // ... actions ...\n\n // Scene 2\n await sw.scene('...');\n // ... actions ...\n}\n```\n\nCommon mistakes \u2014 do NOT do any of these:\n- Do NOT use page.click(), page.fill(), or any page.* methods \u2014 use sw.click(), sw.fill() etc.\n- Do NOT import expect, assert, or any test library\n- Do NOT call expect() or assert()\n- Do NOT use page.evaluate() or page.waitForSelector()\n- Do NOT add test(), describe(), or beforeEach() wrappers\n- Do NOT use page.locator().click() \u2014 use sw.click(selector) directly";
|
|
2
|
+
export declare function buildUserPrompt(testSource: string, narrationStyle: 'brief' | 'detailed', appDescription?: string): string;
|
|
3
|
+
//# sourceMappingURL=prompts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../../../src/generator/prompts.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,aAAa,yyEAoD4C,CAAC;AAEvE,wBAAgB,eAAe,CAC7B,UAAU,EAAE,MAAM,EAClB,cAAc,EAAE,OAAO,GAAG,UAAU,EACpC,cAAc,CAAC,EAAE,MAAM,GACtB,MAAM,CAuER"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
export const SYSTEM_PROMPT = `You are Screenwright, a tool that converts Playwright E2E tests into cinematic product demo scenarios.
|
|
2
|
+
|
|
3
|
+
Given a Playwright test file, generate a new TypeScript file that uses the Screenwright helpers API to create a polished demo with:
|
|
4
|
+
- Natural pacing (deliberate waits between actions)
|
|
5
|
+
- Human-friendly data (replace faker/test data with realistic values)
|
|
6
|
+
- Narration cues (explain what's happening to the viewer)
|
|
7
|
+
- Scene boundaries (organize the demo into logical chapters)
|
|
8
|
+
|
|
9
|
+
The output must be a valid TypeScript file with a default export function that takes a ScreenwrightHelpers parameter.
|
|
10
|
+
|
|
11
|
+
Available helpers:
|
|
12
|
+
- sw.scene(title, description?) — mark a scene/chapter boundary
|
|
13
|
+
- sw.navigate(url, { narration? }) — navigate to a URL
|
|
14
|
+
- sw.click(selector, { narration? }) — click an element
|
|
15
|
+
- sw.fill(selector, value, { narration? }) — type into an input
|
|
16
|
+
- sw.hover(selector, { narration? }) — hover over an element
|
|
17
|
+
- sw.press(key, { narration? }) — press a keyboard key
|
|
18
|
+
- sw.wait(ms) — pause for pacing
|
|
19
|
+
- sw.narrate(text) — speak narration without an action
|
|
20
|
+
|
|
21
|
+
Rules:
|
|
22
|
+
1. Import only ScreenwrightHelpers from 'screenwright'
|
|
23
|
+
2. Export a default async function
|
|
24
|
+
3. Replace ALL test/faker data with realistic human-friendly values
|
|
25
|
+
4. Add narration to key actions explaining what the user is doing
|
|
26
|
+
5. Add sw.wait() calls between logical steps for pacing
|
|
27
|
+
6. Use sw.scene() to organize into 2-5 scenes
|
|
28
|
+
7. Keep the same user flow as the original test
|
|
29
|
+
8. Do NOT include assertions — this is a demo, not a test
|
|
30
|
+
|
|
31
|
+
Output format — always follow this exact structure:
|
|
32
|
+
|
|
33
|
+
\`\`\`typescript
|
|
34
|
+
import type { ScreenwrightHelpers } from 'screenwright';
|
|
35
|
+
|
|
36
|
+
export default async function scenario(sw: ScreenwrightHelpers) {
|
|
37
|
+
// Scene 1
|
|
38
|
+
await sw.scene('...');
|
|
39
|
+
// ... actions ...
|
|
40
|
+
|
|
41
|
+
// Scene 2
|
|
42
|
+
await sw.scene('...');
|
|
43
|
+
// ... actions ...
|
|
44
|
+
}
|
|
45
|
+
\`\`\`
|
|
46
|
+
|
|
47
|
+
Common mistakes — do NOT do any of these:
|
|
48
|
+
- Do NOT use page.click(), page.fill(), or any page.* methods — use sw.click(), sw.fill() etc.
|
|
49
|
+
- Do NOT import expect, assert, or any test library
|
|
50
|
+
- Do NOT call expect() or assert()
|
|
51
|
+
- Do NOT use page.evaluate() or page.waitForSelector()
|
|
52
|
+
- Do NOT add test(), describe(), or beforeEach() wrappers
|
|
53
|
+
- Do NOT use page.locator().click() — use sw.click(selector) directly`;
|
|
54
|
+
export function buildUserPrompt(testSource, narrationStyle, appDescription) {
|
|
55
|
+
let prompt = `Convert this Playwright test into a Screenwright demo scenario.
|
|
56
|
+
|
|
57
|
+
Narration style: ${narrationStyle}
|
|
58
|
+
${narrationStyle === 'brief' ? 'Use short, concise narration (1 sentence per narration cue).' : 'Use detailed narration that explains each step clearly.'}
|
|
59
|
+
|
|
60
|
+
${appDescription ? `App context: ${appDescription}\n\n` : ''}Here is an example conversion for reference:
|
|
61
|
+
|
|
62
|
+
Input:
|
|
63
|
+
\`\`\`typescript
|
|
64
|
+
import { test, expect } from '@playwright/test';
|
|
65
|
+
|
|
66
|
+
test('checkout flow', async ({ page }) => {
|
|
67
|
+
await page.goto('http://localhost:3000');
|
|
68
|
+
await page.click('[data-testid="product-laptop"]');
|
|
69
|
+
await page.click('[data-testid="add-to-cart"]');
|
|
70
|
+
await page.fill('[data-testid="email"]', 'test@example.com');
|
|
71
|
+
await page.click('[data-testid="checkout"]');
|
|
72
|
+
await expect(page.locator('.confirmation')).toBeVisible();
|
|
73
|
+
});
|
|
74
|
+
\`\`\`
|
|
75
|
+
|
|
76
|
+
Output:
|
|
77
|
+
\`\`\`typescript
|
|
78
|
+
import type { ScreenwrightHelpers } from 'screenwright';
|
|
79
|
+
|
|
80
|
+
export default async function scenario(sw: ScreenwrightHelpers) {
|
|
81
|
+
await sw.scene('Shopping for a Laptop');
|
|
82
|
+
await sw.navigate('http://localhost:3000', {
|
|
83
|
+
narration: 'Let\\'s browse the electronics store.',
|
|
84
|
+
});
|
|
85
|
+
await sw.wait(1500);
|
|
86
|
+
|
|
87
|
+
await sw.click('[data-testid="product-laptop"]', {
|
|
88
|
+
narration: 'We\\'ll select the MacBook Pro.',
|
|
89
|
+
});
|
|
90
|
+
await sw.wait(1000);
|
|
91
|
+
|
|
92
|
+
await sw.scene('Adding to Cart');
|
|
93
|
+
await sw.click('[data-testid="add-to-cart"]', {
|
|
94
|
+
narration: 'Add it to our cart.',
|
|
95
|
+
});
|
|
96
|
+
await sw.wait(1500);
|
|
97
|
+
|
|
98
|
+
await sw.scene('Checkout');
|
|
99
|
+
await sw.fill('[data-testid="email"]', 'sarah.chen@acme.co', {
|
|
100
|
+
narration: 'Enter our email address for the order confirmation.',
|
|
101
|
+
});
|
|
102
|
+
await sw.wait(1000);
|
|
103
|
+
|
|
104
|
+
await sw.click('[data-testid="checkout"]', {
|
|
105
|
+
narration: 'Complete the purchase.',
|
|
106
|
+
});
|
|
107
|
+
await sw.wait(2000);
|
|
108
|
+
await sw.narrate('The order has been confirmed successfully.');
|
|
109
|
+
}
|
|
110
|
+
\`\`\`
|
|
111
|
+
|
|
112
|
+
Edge cases:
|
|
113
|
+
- If the test file has multiple tests, convert only the first test
|
|
114
|
+
- If there is a beforeEach hook, incorporate its actions at the start of the scenario
|
|
115
|
+
- Simplify complex locators to CSS selectors where possible
|
|
116
|
+
|
|
117
|
+
Now convert this test:
|
|
118
|
+
\`\`\`typescript
|
|
119
|
+
${testSource}
|
|
120
|
+
\`\`\`
|
|
121
|
+
|
|
122
|
+
Generate the complete TypeScript scenario file:`;
|
|
123
|
+
return prompt;
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=prompts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompts.js","sourceRoot":"","sources":["../../../src/generator/prompts.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,aAAa,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;sEAoDyC,CAAC;AAEvE,MAAM,UAAU,eAAe,CAC7B,UAAkB,EAClB,cAAoC,EACpC,cAAuB;IAEvB,IAAI,MAAM,GAAG;;mBAEI,cAAc;EAC/B,cAAc,KAAK,OAAO,CAAC,CAAC,CAAC,8DAA8D,CAAC,CAAC,CAAC,yDAAyD;;EAEvJ,cAAc,CAAC,CAAC,CAAC,gBAAgB,cAAc,MAAM,CAAC,CAAC,CAAC,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA2D1D,UAAU;;;gDAGoC,CAAC;IAE/C,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
export interface GenerateOptions {
|
|
2
|
+
testPath: string;
|
|
3
|
+
narrationStyle: 'brief' | 'detailed';
|
|
4
|
+
appDescription?: string;
|
|
5
|
+
}
|
|
6
|
+
export interface GenerateResult {
|
|
7
|
+
scenarioSource: string;
|
|
8
|
+
systemPrompt: string;
|
|
9
|
+
userPrompt: string;
|
|
10
|
+
}
|
|
11
|
+
export interface ValidationError {
|
|
12
|
+
code: string;
|
|
13
|
+
message: string;
|
|
14
|
+
}
|
|
15
|
+
export interface ValidationResult {
|
|
16
|
+
valid: boolean;
|
|
17
|
+
errors: ValidationError[];
|
|
18
|
+
warnings: ValidationError[];
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Read a Playwright test file and produce the LLM prompt pair
|
|
22
|
+
* needed to generate a demo scenario.
|
|
23
|
+
*
|
|
24
|
+
* The actual LLM call happens in the skill layer (Claude Code),
|
|
25
|
+
* not here. This function prepares the prompt and returns it
|
|
26
|
+
* along with any post-processing.
|
|
27
|
+
*
|
|
28
|
+
* When used standalone (without the skill), the user can pipe
|
|
29
|
+
* the prompts to any LLM.
|
|
30
|
+
*/
|
|
31
|
+
export declare function prepareGeneration(opts: GenerateOptions): Promise<{
|
|
32
|
+
systemPrompt: string;
|
|
33
|
+
userPrompt: string;
|
|
34
|
+
}>;
|
|
35
|
+
/**
|
|
36
|
+
* Extract TypeScript code from an LLM response that may contain
|
|
37
|
+
* markdown code fences. When multiple fences are found, returns the
|
|
38
|
+
* longest one (LLMs often produce a small snippet first, then the full code).
|
|
39
|
+
*/
|
|
40
|
+
export declare function extractScenarioCode(llmResponse: string): string;
|
|
41
|
+
/**
|
|
42
|
+
* Validate that a string looks like a valid Screenwright scenario.
|
|
43
|
+
* Returns errors (fatal) and warnings (non-fatal).
|
|
44
|
+
*/
|
|
45
|
+
export declare function validateScenarioCode(code: string): ValidationResult;
|
|
46
|
+
//# sourceMappingURL=scenario-generator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scenario-generator.d.ts","sourceRoot":"","sources":["../../../src/generator/scenario-generator.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,OAAO,GAAG,UAAU,CAAC;IACrC,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,cAAc;IAC7B,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,eAAe,EAAE,CAAC;IAC1B,QAAQ,EAAE,eAAe,EAAE,CAAC;CAC7B;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC;IACtE,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC,CAOD;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAgB/D;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB,CAkDnE"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { SYSTEM_PROMPT, buildUserPrompt } from './prompts.js';
|
|
3
|
+
/**
|
|
4
|
+
* Read a Playwright test file and produce the LLM prompt pair
|
|
5
|
+
* needed to generate a demo scenario.
|
|
6
|
+
*
|
|
7
|
+
* The actual LLM call happens in the skill layer (Claude Code),
|
|
8
|
+
* not here. This function prepares the prompt and returns it
|
|
9
|
+
* along with any post-processing.
|
|
10
|
+
*
|
|
11
|
+
* When used standalone (without the skill), the user can pipe
|
|
12
|
+
* the prompts to any LLM.
|
|
13
|
+
*/
|
|
14
|
+
export async function prepareGeneration(opts) {
|
|
15
|
+
const testSource = await readFile(opts.testPath, 'utf-8');
|
|
16
|
+
return {
|
|
17
|
+
systemPrompt: SYSTEM_PROMPT,
|
|
18
|
+
userPrompt: buildUserPrompt(testSource, opts.narrationStyle, opts.appDescription),
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Extract TypeScript code from an LLM response that may contain
|
|
23
|
+
* markdown code fences. When multiple fences are found, returns the
|
|
24
|
+
* longest one (LLMs often produce a small snippet first, then the full code).
|
|
25
|
+
*/
|
|
26
|
+
export function extractScenarioCode(llmResponse) {
|
|
27
|
+
const fenceRegex = /```(?:typescript|ts)?[\r\n]+([\s\S]*?)```/g;
|
|
28
|
+
let best = null;
|
|
29
|
+
let match;
|
|
30
|
+
while ((match = fenceRegex.exec(llmResponse)) !== null) {
|
|
31
|
+
const code = match[1].trim();
|
|
32
|
+
if (best === null || code.length > best.length) {
|
|
33
|
+
best = code;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
if (best !== null)
|
|
37
|
+
return best;
|
|
38
|
+
// No fence found — assume the whole response is code
|
|
39
|
+
return llmResponse.trim();
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Validate that a string looks like a valid Screenwright scenario.
|
|
43
|
+
* Returns errors (fatal) and warnings (non-fatal).
|
|
44
|
+
*/
|
|
45
|
+
export function validateScenarioCode(code) {
|
|
46
|
+
const errors = [];
|
|
47
|
+
const warnings = [];
|
|
48
|
+
// Empty input
|
|
49
|
+
if (!code || !code.trim()) {
|
|
50
|
+
return { valid: false, errors: [{ code: 'EMPTY_INPUT', message: 'Scenario code is empty' }], warnings: [] };
|
|
51
|
+
}
|
|
52
|
+
// Missing ScreenwrightHelpers import
|
|
53
|
+
if (!/import\s+(?:type\s+)?\{[^}]*(?:type\s+)?ScreenwrightHelpers[^}]*\}\s+from\s+['"]screenwright['"]/.test(code)) {
|
|
54
|
+
errors.push({ code: 'MISSING_IMPORT', message: 'Missing ScreenwrightHelpers import from screenwright' });
|
|
55
|
+
}
|
|
56
|
+
// Missing default async export
|
|
57
|
+
if (!/export\s+default\s+async\s+function/.test(code)) {
|
|
58
|
+
errors.push({ code: 'MISSING_DEFAULT_EXPORT', message: 'Missing export default async function' });
|
|
59
|
+
}
|
|
60
|
+
// Raw page.* calls (but not sw.page.*)
|
|
61
|
+
if (/(?<!sw\.)(?<!\w\.)page\.\w+\s*\(/.test(code)) {
|
|
62
|
+
errors.push({ code: 'RAW_PAGE_CALL', message: 'Raw page.*() calls are not allowed — use sw.* helpers instead' });
|
|
63
|
+
}
|
|
64
|
+
// Assertion imports
|
|
65
|
+
if (/(?:import|require)[^;]*(?:expect|assert)/.test(code)) {
|
|
66
|
+
errors.push({ code: 'ASSERTION_IMPORT', message: 'Assertion library imports are not allowed in scenarios' });
|
|
67
|
+
}
|
|
68
|
+
// Assertion calls
|
|
69
|
+
if (/\b(?:expect|assert)\s*[.(]/.test(code)) {
|
|
70
|
+
errors.push({ code: 'ASSERTION_CALL', message: 'Assertion calls (expect/assert) are not allowed in scenarios' });
|
|
71
|
+
}
|
|
72
|
+
// Warnings — no scenes
|
|
73
|
+
if (!/\.scene\s*\(/.test(code)) {
|
|
74
|
+
warnings.push({ code: 'NO_SCENES', message: 'No sw.scene() calls found — consider adding scene boundaries' });
|
|
75
|
+
}
|
|
76
|
+
// Warnings — no waits
|
|
77
|
+
if (!/\.wait\s*\(/.test(code)) {
|
|
78
|
+
warnings.push({ code: 'NO_WAITS', message: 'No sw.wait() calls found — consider adding pacing' });
|
|
79
|
+
}
|
|
80
|
+
// Warnings — no narration
|
|
81
|
+
if (!/narration/.test(code)) {
|
|
82
|
+
warnings.push({ code: 'NO_NARRATION', message: 'No narration found — consider adding narration to actions' });
|
|
83
|
+
}
|
|
84
|
+
return { valid: errors.length === 0, errors, warnings };
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=scenario-generator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scenario-generator.js","sourceRoot":"","sources":["../../../src/generator/scenario-generator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export type { ScreenwrightHelpers, ActionOptions } from './runtime/action-helpers.js';
|
|
2
|
+
export type { ScenarioFn } from './runtime/instrumented-page.js';
|
|
3
|
+
export type { Timeline, TimelineEvent, SceneEvent, ActionEvent, CursorTargetEvent, NarrationEvent, WaitEvent } from './timeline/types.js';
|
|
4
|
+
export type { ScreenwrightConfig } from './config/config-schema.js';
|
|
5
|
+
export { validateScenarioCode, extractScenarioCode } from './generator/scenario-generator.js';
|
|
6
|
+
export type { ValidationResult, ValidationError, GenerateOptions } from './generator/scenario-generator.js';
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AACA,YAAY,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AACtF,YAAY,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAC;AACjE,YAAY,EAAE,QAAQ,EAAE,aAAa,EAAE,UAAU,EAAE,WAAW,EAAE,iBAAiB,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAC1I,YAAY,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;AAC9F,YAAY,EAAE,gBAAgB,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAC"}
|