playwright-director 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 (122) hide show
  1. package/README.md +860 -0
  2. package/dist/Tutorial.d.ts +108 -0
  3. package/dist/Tutorial.d.ts.map +1 -0
  4. package/dist/Tutorial.js +767 -0
  5. package/dist/Tutorial.js.map +1 -0
  6. package/dist/bin/export-transcript.d.ts +3 -0
  7. package/dist/bin/export-transcript.d.ts.map +1 -0
  8. package/dist/bin/export-transcript.js +111 -0
  9. package/dist/bin/export-transcript.js.map +1 -0
  10. package/dist/cursor.d.ts +24 -0
  11. package/dist/cursor.d.ts.map +1 -0
  12. package/dist/cursor.js +96 -0
  13. package/dist/cursor.js.map +1 -0
  14. package/dist/index.d.ts +16 -0
  15. package/dist/index.d.ts.map +1 -0
  16. package/dist/index.js +12 -0
  17. package/dist/index.js.map +1 -0
  18. package/dist/init.d.ts +3 -0
  19. package/dist/init.d.ts.map +1 -0
  20. package/dist/init.js +183 -0
  21. package/dist/init.js.map +1 -0
  22. package/dist/merge.d.ts +26 -0
  23. package/dist/merge.d.ts.map +1 -0
  24. package/dist/merge.js +65 -0
  25. package/dist/merge.js.map +1 -0
  26. package/dist/music.d.ts +29 -0
  27. package/dist/music.d.ts.map +1 -0
  28. package/dist/music.js +107 -0
  29. package/dist/music.js.map +1 -0
  30. package/dist/overlay-html.d.ts +44 -0
  31. package/dist/overlay-html.d.ts.map +1 -0
  32. package/dist/overlay-html.js +150 -0
  33. package/dist/overlay-html.js.map +1 -0
  34. package/dist/overlay.d.ts +39 -0
  35. package/dist/overlay.d.ts.map +1 -0
  36. package/dist/overlay.js +134 -0
  37. package/dist/overlay.js.map +1 -0
  38. package/dist/postinstall.d.ts +3 -0
  39. package/dist/postinstall.d.ts.map +1 -0
  40. package/dist/postinstall.js +38 -0
  41. package/dist/postinstall.js.map +1 -0
  42. package/dist/reporter.d.ts +22 -0
  43. package/dist/reporter.d.ts.map +1 -0
  44. package/dist/reporter.js +166 -0
  45. package/dist/reporter.js.map +1 -0
  46. package/dist/site/build-site.d.ts +2 -0
  47. package/dist/site/build-site.d.ts.map +1 -0
  48. package/dist/site/build-site.js +82 -0
  49. package/dist/site/build-site.js.map +1 -0
  50. package/dist/site/embed.d.ts +48 -0
  51. package/dist/site/embed.d.ts.map +1 -0
  52. package/dist/site/embed.js +45 -0
  53. package/dist/site/embed.js.map +1 -0
  54. package/dist/site/generate-manifest.d.ts +15 -0
  55. package/dist/site/generate-manifest.d.ts.map +1 -0
  56. package/dist/site/generate-manifest.js +106 -0
  57. package/dist/site/generate-manifest.js.map +1 -0
  58. package/dist/site/scaffold.d.ts +3 -0
  59. package/dist/site/scaffold.d.ts.map +1 -0
  60. package/dist/site/scaffold.js +70 -0
  61. package/dist/site/scaffold.js.map +1 -0
  62. package/dist/site/scan-tutorials.d.ts +12 -0
  63. package/dist/site/scan-tutorials.d.ts.map +1 -0
  64. package/dist/site/scan-tutorials.js +54 -0
  65. package/dist/site/scan-tutorials.js.map +1 -0
  66. package/dist/site/types.d.ts +75 -0
  67. package/dist/site/types.d.ts.map +1 -0
  68. package/dist/site/types.js +2 -0
  69. package/dist/site/types.js.map +1 -0
  70. package/dist/skill-stamp.d.ts +21 -0
  71. package/dist/skill-stamp.d.ts.map +1 -0
  72. package/dist/skill-stamp.js +39 -0
  73. package/dist/skill-stamp.js.map +1 -0
  74. package/dist/slugify.d.ts +19 -0
  75. package/dist/slugify.d.ts.map +1 -0
  76. package/dist/slugify.js +29 -0
  77. package/dist/slugify.js.map +1 -0
  78. package/dist/stage-presets.d.ts +51 -0
  79. package/dist/stage-presets.d.ts.map +1 -0
  80. package/dist/stage-presets.js +45 -0
  81. package/dist/stage-presets.js.map +1 -0
  82. package/dist/styles.css +637 -0
  83. package/dist/timeline.d.ts +87 -0
  84. package/dist/timeline.d.ts.map +1 -0
  85. package/dist/timeline.js +108 -0
  86. package/dist/timeline.js.map +1 -0
  87. package/dist/transcript.d.ts +87 -0
  88. package/dist/transcript.d.ts.map +1 -0
  89. package/dist/transcript.js +291 -0
  90. package/dist/transcript.js.map +1 -0
  91. package/dist/tts-provider.d.ts +69 -0
  92. package/dist/tts-provider.d.ts.map +1 -0
  93. package/dist/tts-provider.js +182 -0
  94. package/dist/tts-provider.js.map +1 -0
  95. package/dist/types.d.ts +109 -0
  96. package/dist/types.d.ts.map +1 -0
  97. package/dist/types.js +2 -0
  98. package/dist/types.js.map +1 -0
  99. package/dist/voice-prerender.d.ts +41 -0
  100. package/dist/voice-prerender.d.ts.map +1 -0
  101. package/dist/voice-prerender.js +122 -0
  102. package/dist/voice-prerender.js.map +1 -0
  103. package/dist/voice.d.ts +76 -0
  104. package/dist/voice.d.ts.map +1 -0
  105. package/dist/voice.js +244 -0
  106. package/dist/voice.js.map +1 -0
  107. package/package.json +87 -0
  108. package/skills/tutorialize/SKILL.md +54 -0
  109. package/skills/tutorialize/agent.md +58 -0
  110. package/skills/tutorialize/references/api.md +489 -0
  111. package/skills/tutorialize/references/storytelling.md +193 -0
  112. package/src/styles.css +637 -0
  113. package/templates/site/public/.gitkeep +0 -0
  114. package/templates/site/public/widget.js +273 -0
  115. package/templates/site/src/components/TutorialsHome.astro +141 -0
  116. package/templates/site/src/components/VideoCard.astro +192 -0
  117. package/templates/site/src/components/VideoModal.astro +170 -0
  118. package/templates/site/src/data/.gitkeep +0 -0
  119. package/templates/site/src/layouts/Base.astro +56 -0
  120. package/templates/site/src/pages/[slug].astro +745 -0
  121. package/templates/site/src/pages/index.astro +5 -0
  122. package/templates/site/src/styles/tutorials.css +303 -0
package/dist/merge.js ADDED
@@ -0,0 +1,65 @@
1
+ import { existsSync } from 'fs';
2
+ import { join } from 'path';
3
+ const DEFAULT_OPTIONS = {
4
+ audioDir: 'static/audio/tutorial-voice',
5
+ musicFile: 'static/audio/tutorial-background.mp3',
6
+ musicVolume: 0.15,
7
+ voiceVolume: 2.5
8
+ };
9
+ /**
10
+ * Build the ffmpeg command to merge video with audio
11
+ */
12
+ export function buildMergeCommand(timeline, videoPath, outputPath, options = {}) {
13
+ const opts = { ...DEFAULT_OPTIONS, ...options };
14
+ const fileExists = opts.checkFileExists ?? existsSync;
15
+ const videoDuration = (timeline.totalDurationMs / 1000).toFixed(3);
16
+ const inputs = [videoPath];
17
+ const filterParts = [];
18
+ const audioLabels = [];
19
+ let audioIdx = 1;
20
+ // Add background music
21
+ if (opts.musicFile && fileExists(opts.musicFile)) {
22
+ inputs.push(opts.musicFile);
23
+ filterParts.push(`[1:a]atrim=0:${videoDuration},asetpts=PTS-STARTPTS,volume=${opts.musicVolume}[bg]`);
24
+ audioLabels.push('[bg]');
25
+ audioIdx = 2;
26
+ }
27
+ // Add voice clips — unvoiced steps (empty audioFile) carry no narration
28
+ for (const step of timeline.steps) {
29
+ if (!step.audioFile)
30
+ continue;
31
+ const audioPath = join(opts.audioDir, step.audioFile);
32
+ if (!fileExists(audioPath)) {
33
+ console.warn(`Missing audio: ${step.audioFile}`);
34
+ continue;
35
+ }
36
+ inputs.push(audioPath);
37
+ filterParts.push(`[${audioIdx}:a]volume=${opts.voiceVolume},adelay=${step.startMs}|${step.startMs}[v${audioIdx}]`);
38
+ audioLabels.push(`[v${audioIdx}]`);
39
+ audioIdx++;
40
+ }
41
+ // Build mix filter
42
+ const totalStreams = audioLabels.length;
43
+ let filter;
44
+ if (totalStreams === 0) {
45
+ filter = 'anullsrc=r=48000:cl=stereo[aout]';
46
+ }
47
+ else if (totalStreams === 1) {
48
+ filter = `${filterParts.join(';')};${audioLabels[0]}anull[aout]`;
49
+ }
50
+ else {
51
+ filter = `${filterParts.join(';')};${audioLabels.join('')}amix=inputs=${totalStreams}:duration=longest:dropout_transition=0:normalize=0[aout]`;
52
+ }
53
+ // Build input args
54
+ const inputArgs = inputs.map((input, i) => {
55
+ if (i === 1 && input === opts.musicFile) {
56
+ return `-stream_loop -1 -i "${input}"`;
57
+ }
58
+ return `-i "${input}"`;
59
+ }).join(' ');
60
+ // Trim dead time from video start (preload period)
61
+ const trimSs = timeline.videoTrimMs ? `-ss ${(timeline.videoTrimMs / 1000).toFixed(3)}` : '';
62
+ const command = `ffmpeg -y ${trimSs} ${inputArgs} -filter_complex "${filter}" -map 0:v -map "[aout]" -c:v libvpx-vp9 -b:v 330k -crf 40 -row-mt 1 -cpu-used 4 -c:a libopus -b:a 64k -t ${videoDuration} "${outputPath}"`;
63
+ return { command, inputs, filter };
64
+ }
65
+ //# sourceMappingURL=merge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"merge.js","sourceRoot":"","sources":["../src/merge.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ import type { Page } from '@playwright/test';
2
+ export interface MusicOptions {
3
+ backgroundMusic: string;
4
+ musicVolume: number;
5
+ }
6
+ /**
7
+ * In-browser music for live viewing during test execution.
8
+ * Note: Music is NOT captured via MediaRecorder - it's added in post-processing
9
+ * by the merge script (scripts/merge-tutorial-audio.sh) for continuous playback.
10
+ *
11
+ * All playback methods are no-ops when TUTORIAL_MODE is not enabled,
12
+ * ensuring no audio plays during regular test runs.
13
+ */
14
+ export declare class TutorialMusic {
15
+ private page;
16
+ private options;
17
+ private initialized;
18
+ constructor(page: Page, options: MusicOptions);
19
+ switchPage(page: Page): void;
20
+ get isInitialized(): boolean;
21
+ /**
22
+ * Ensure music is still playing (restart after page navigation)
23
+ */
24
+ ensurePlaying(): Promise<void>;
25
+ start(): Promise<void>;
26
+ stop(fadeOut?: boolean): Promise<void>;
27
+ setVolume(volume: number): Promise<void>;
28
+ }
29
+ //# sourceMappingURL=music.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"music.d.ts","sourceRoot":"","sources":["../src/music.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAI7C,MAAM,WAAW,YAAY;IAC5B,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;GAOG;AACH,qBAAa,aAAa;IACzB,OAAO,CAAC,IAAI,CAAO;IACnB,OAAO,CAAC,OAAO,CAAe;IAC9B,OAAO,CAAC,WAAW,CAAS;gBAEhB,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,YAAY;IAK7C,UAAU,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI;IAI5B,IAAI,aAAa,IAAI,OAAO,CAE3B;IAED;;OAEG;IACG,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IAgB9B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAkCtB,IAAI,CAAC,OAAO,UAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IA0BnC,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAW9C"}
package/dist/music.js ADDED
@@ -0,0 +1,107 @@
1
+ const TUTORIAL_MODE = process.env.TUTORIAL_MODE === 'true';
2
+ /**
3
+ * In-browser music for live viewing during test execution.
4
+ * Note: Music is NOT captured via MediaRecorder - it's added in post-processing
5
+ * by the merge script (scripts/merge-tutorial-audio.sh) for continuous playback.
6
+ *
7
+ * All playback methods are no-ops when TUTORIAL_MODE is not enabled,
8
+ * ensuring no audio plays during regular test runs.
9
+ */
10
+ export class TutorialMusic {
11
+ page;
12
+ options;
13
+ initialized = false;
14
+ constructor(page, options) {
15
+ this.page = page;
16
+ this.options = options;
17
+ }
18
+ switchPage(page) {
19
+ this.page = page;
20
+ }
21
+ get isInitialized() {
22
+ return this.initialized;
23
+ }
24
+ /**
25
+ * Ensure music is still playing (restart after page navigation)
26
+ */
27
+ async ensurePlaying() {
28
+ if (!TUTORIAL_MODE)
29
+ return;
30
+ if (!this.initialized || !this.options.backgroundMusic)
31
+ return;
32
+ const isPlaying = await this.page.evaluate(() => {
33
+ const audio = document.getElementById('tutorial-music');
34
+ return audio && !audio.paused;
35
+ });
36
+ if (!isPlaying) {
37
+ console.log('[Music] Lost after navigation, restarting...');
38
+ this.initialized = false;
39
+ await this.start();
40
+ }
41
+ }
42
+ async start() {
43
+ if (!TUTORIAL_MODE)
44
+ return;
45
+ if (!this.options.backgroundMusic || this.initialized)
46
+ return;
47
+ const result = await this.page.evaluate(({ musicUrl, volume }) => {
48
+ const existing = document.getElementById('tutorial-music');
49
+ if (existing)
50
+ existing.remove();
51
+ const audio = document.createElement('audio');
52
+ audio.id = 'tutorial-music';
53
+ audio.src = musicUrl;
54
+ audio.loop = true;
55
+ audio.volume = volume;
56
+ audio.style.display = 'none';
57
+ document.body.appendChild(audio);
58
+ return audio
59
+ .play()
60
+ .then(() => ({ success: true, error: null }))
61
+ .catch((e) => ({ success: false, error: e.message }));
62
+ }, { musicUrl: this.options.backgroundMusic, volume: this.options.musicVolume });
63
+ if (result?.success) {
64
+ console.log('[Music] Background music playing (live only, will be added in post-processing)');
65
+ }
66
+ else if (result?.error) {
67
+ console.warn(`[Music] Autoplay blocked: ${result.error}`);
68
+ }
69
+ this.initialized = true;
70
+ }
71
+ async stop(fadeOut = true) {
72
+ if (!this.initialized)
73
+ return;
74
+ await this.page.evaluate(({ fadeOut }) => {
75
+ const audio = document.getElementById('tutorial-music');
76
+ if (!audio)
77
+ return;
78
+ if (fadeOut) {
79
+ const fadeInterval = setInterval(() => {
80
+ if (audio.volume > 0.01) {
81
+ audio.volume = Math.max(0, audio.volume - 0.01);
82
+ }
83
+ else {
84
+ clearInterval(fadeInterval);
85
+ audio.pause();
86
+ audio.remove();
87
+ }
88
+ }, 20);
89
+ }
90
+ else {
91
+ audio.pause();
92
+ audio.remove();
93
+ }
94
+ }, { fadeOut });
95
+ this.initialized = false;
96
+ }
97
+ async setVolume(volume) {
98
+ if (!this.initialized)
99
+ return;
100
+ await this.page.evaluate(({ volume }) => {
101
+ const audio = document.getElementById('tutorial-music');
102
+ if (audio)
103
+ audio.volume = Math.max(0, Math.min(1, volume));
104
+ }, { volume });
105
+ }
106
+ }
107
+ //# sourceMappingURL=music.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"music.js","sourceRoot":"","sources":["../src/music.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,44 @@
1
+ import type { ContextStyle, OverlayPosition, SceneOptions } from './types.js';
2
+ /**
3
+ * The multi-scene stage: a browser-like tab bar over a row of iframes.
4
+ *
5
+ * Every scene stays mounted for the whole tutorial — hidden, never unloaded —
6
+ * so a profile logged in behind one tab is still logged in when we come back
7
+ * to it. Tabs are always all visible: that is how a viewer knows who else is
8
+ * in the story and who is speaking now.
9
+ */
10
+ export declare function renderStage(scenes: Record<string, SceneOptions>, active: string[], pinnedSplit?: boolean): string;
11
+ export declare const CURSOR_SVG = "\n<svg viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n\t<path d=\"M4 4L10.5 20.5L13 13L20.5 10.5L4 4Z\" fill=\"white\" stroke=\"var(--tutorial-cursor-stroke, #1e293b)\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n</svg>\n";
12
+ export interface StepOverlayParams {
13
+ tutorialTitle: string;
14
+ step: number;
15
+ title: string;
16
+ description?: string;
17
+ isRtl?: boolean;
18
+ progressPercent?: number;
19
+ position?: OverlayPosition;
20
+ }
21
+ export declare function renderStepOverlay(params: StepOverlayParams): string;
22
+ export interface ContextOverlayParams {
23
+ tutorialTitle: string;
24
+ contextTitle: string;
25
+ text?: string;
26
+ style: ContextStyle;
27
+ isRtl?: boolean;
28
+ }
29
+ export declare function renderContextOverlay(params: ContextOverlayParams): string;
30
+ export interface CompleteOverlayParams {
31
+ title: string;
32
+ message: string;
33
+ }
34
+ export declare function renderCompleteOverlay(params: CompleteOverlayParams): string;
35
+ export interface EmailPreviewParams {
36
+ subject: string;
37
+ from?: string;
38
+ to?: string;
39
+ body: string;
40
+ highlightCode?: string;
41
+ isRtl?: boolean;
42
+ }
43
+ export declare function renderEmailPreview(params: EmailPreviewParams): string;
44
+ //# sourceMappingURL=overlay-html.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"overlay-html.d.ts","sourceRoot":"","sources":["../src/overlay-html.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAK9E;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAC1B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,EACpC,MAAM,EAAE,MAAM,EAAE,EAChB,WAAW,UAAQ,GACjB,MAAM,CAmCR;AAED,eAAO,MAAM,UAAU,2RAItB,CAAC;AAgBF,MAAM,WAAW,iBAAiB;IACjC,aAAa,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,eAAe,CAAC;CAC3B;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,iBAAiB,GAAG,MAAM,CAenE;AAED,MAAM,WAAW,oBAAoB;IACpC,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,YAAY,CAAC;IACpB,KAAK,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,oBAAoB,GAAG,MAAM,CAazE;AAED,MAAM,WAAW,qBAAqB;IACrC,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,qBAAqB,GAAG,MAAM,CAW3E;AAED,MAAM,WAAW,kBAAkB;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,KAAK,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,kBAAkB,GAAG,MAAM,CA+DrE"}
@@ -0,0 +1,150 @@
1
+ const escapeHtml = (s) => s.replace(/[&<>"]/g, (c) => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;' })[c]);
2
+ /**
3
+ * The multi-scene stage: a browser-like tab bar over a row of iframes.
4
+ *
5
+ * Every scene stays mounted for the whole tutorial — hidden, never unloaded —
6
+ * so a profile logged in behind one tab is still logged in when we come back
7
+ * to it. Tabs are always all visible: that is how a viewer knows who else is
8
+ * in the story and who is speaking now.
9
+ */
10
+ export function renderStage(scenes, active, pinnedSplit = false) {
11
+ const isActive = (name) => active.includes(name);
12
+ const tabs = Object.entries(scenes)
13
+ .map(([name, scene]) => `<div class="tutorial-tab" data-tutorial-tab="${name}" data-active="${isActive(name)}">
14
+ <span class="tutorial-tab-dot"></span>${escapeHtml(scene.label)}
15
+ </div>`)
16
+ .join('\n\t\t');
17
+ const panes = Object.entries(scenes)
18
+ .map(([name, scene]) => `<div class="tutorial-scene" data-tutorial-scene="${name}" data-active="${isActive(name)}">
19
+ <div class="tutorial-scene-label" data-tutorial-scene-label="${name}">
20
+ <span class="tutorial-tab-dot"></span>${escapeHtml(scene.label)}
21
+ </div>
22
+ <iframe data-tutorial-frame="${name}" src="about:blank"></iframe>
23
+ </div>`)
24
+ .join('\n\t\t');
25
+ const isSplit = pinnedSplit || active.length > 1;
26
+ const layoutAttr = pinnedSplit ? ` data-layout="split"` : '';
27
+ return `<div class="tutorial-stage" id="tutorial-stage" data-split="${isSplit}"${layoutAttr}>
28
+ <div class="tutorial-tabbar">
29
+ ${tabs}
30
+ </div>
31
+ <div class="tutorial-scenes">
32
+ ${panes}
33
+ </div>
34
+ </div>`;
35
+ }
36
+ export const CURSOR_SVG = `
37
+ <svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
38
+ <path d="M4 4L10.5 20.5L13 13L20.5 10.5L4 4Z" fill="white" stroke="var(--tutorial-cursor-stroke, #1e293b)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
39
+ </svg>
40
+ `;
41
+ const CONTEXT_ICONS = {
42
+ goal: '\uD83C\uDFAF',
43
+ clarification: '\uD83D\uDCA1',
44
+ attention: '\u26A0\uFE0F'
45
+ };
46
+ function positionClass(position, isRtl) {
47
+ const effective = isRtl
48
+ ? { TL: 'TR', TR: 'TL', BL: 'BR', BR: 'BL' }[position]
49
+ : position;
50
+ if (effective === 'TL')
51
+ return '';
52
+ return `tutorial-overlay-${effective.toLowerCase()}`;
53
+ }
54
+ export function renderStepOverlay(params) {
55
+ const { tutorialTitle, step, title, description, isRtl, progressPercent = 0, position = 'TR' } = params;
56
+ const rtlClass = isRtl ? 'tutorial-overlay-rtl' : '';
57
+ const posClass = positionClass(position, !!isRtl);
58
+ return `<div id="tutorial-overlay" class="tutorial-overlay ${rtlClass} ${posClass}">
59
+ <div class="tutorial-header">
60
+ <span class="tutorial-icon">\uD83D\uDCCC</span>
61
+ <h3 class="tutorial-title">${tutorialTitle}</h3>
62
+ <span class="tutorial-step-badge">Step ${step}</span>
63
+ </div>
64
+ <h4 class="tutorial-step-title">${title}</h4>
65
+ ${description ? `<p class="tutorial-step-description">${description}</p>` : ''}
66
+ ${progressPercent > 0 ? `<div class="tutorial-progress"><div class="tutorial-progress-bar" style="width: ${progressPercent}%"></div></div>` : ''}
67
+ </div>`;
68
+ }
69
+ export function renderContextOverlay(params) {
70
+ const { tutorialTitle, contextTitle, text, style, isRtl } = params;
71
+ const icon = CONTEXT_ICONS[style];
72
+ const rtlClass = isRtl ? 'tutorial-overlay-rtl' : '';
73
+ return `<div id="tutorial-overlay" class="tutorial-overlay tutorial-overlay-context tutorial-context-${style} ${rtlClass}">
74
+ <div class="tutorial-header">
75
+ <span class="tutorial-icon">${icon}</span>
76
+ <h3 class="tutorial-title">${tutorialTitle}</h3>
77
+ </div>
78
+ <h4 class="tutorial-step-title">${contextTitle}</h4>
79
+ ${text ? `<p class="tutorial-context-text">${text}</p>` : ''}
80
+ </div>`;
81
+ }
82
+ export function renderCompleteOverlay(params) {
83
+ const { title, message } = params;
84
+ return `<div id="tutorial-overlay" class="tutorial-overlay">
85
+ <div class="tutorial-header">
86
+ <span class="tutorial-icon">\u2705</span>
87
+ <h3 class="tutorial-title">${title}</h3>
88
+ </div>
89
+ <h4 class="tutorial-step-title">${message}</h4>
90
+ <div class="tutorial-progress"><div class="tutorial-progress-bar" style="width: 100%"></div></div>
91
+ </div>`;
92
+ }
93
+ export function renderEmailPreview(params) {
94
+ const { subject, from, to, body, highlightCode, isRtl } = params;
95
+ const rtlClass = isRtl ? 'tutorial-overlay-rtl' : '';
96
+ let displayBody = body;
97
+ if (highlightCode) {
98
+ const highlightStyle = `
99
+ <style>
100
+ .tutorial-code-highlight {
101
+ background: #fff3cd !important;
102
+ color: #856404 !important;
103
+ padding: 4px 12px !important;
104
+ border-radius: 4px !important;
105
+ font-weight: 700 !important;
106
+ font-size: 18px !important;
107
+ letter-spacing: 2px !important;
108
+ display: inline-block !important;
109
+ margin: 8px 0 !important;
110
+ border: 2px solid #ffc107 !important;
111
+ animation: pulse 1.5s ease-in-out infinite !important;
112
+ }
113
+ @keyframes pulse {
114
+ 0%, 100% { box-shadow: 0 0 0 4px rgba(255, 193, 7, 0.3); }
115
+ 50% { box-shadow: 0 0 0 8px rgba(255, 193, 7, 0.5), 0 0 20px rgba(255, 193, 7, 0.3); }
116
+ }
117
+ </style>
118
+ `;
119
+ displayBody = highlightStyle + body.replace(new RegExp(`(${highlightCode})`, 'g'), `<span class="tutorial-code-highlight">$1</span>`);
120
+ }
121
+ // Render inside an iframe via srcdoc so the email's own CSS doesn't collide
122
+ // with the app stylesheet (was causing missing icons / broken layout) and so
123
+ // images with absolute URLs load normally. `srcdoc` is same-origin, so the
124
+ // scroll animation in Tutorial.ts can still access the iframe body.
125
+ const srcdoc = `<!doctype html><html><head><meta charset="utf-8"><style>
126
+ html, body { margin: 0; padding: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; font-size: 14px; line-height: 1.5; color: #333; background: #fff; }
127
+ body { padding: 16px; }
128
+ img { max-width: 100%; height: auto; }
129
+ </style></head><body>${displayBody}</body></html>`;
130
+ const srcdocAttr = srcdoc.replace(/"/g, '&quot;');
131
+ return `<div id="tutorial-email-preview" class="tutorial-email-preview ${rtlClass}">
132
+ <div class="tutorial-email-window">
133
+ <div class="tutorial-email-titlebar">
134
+ <span class="tutorial-email-dot red"></span>
135
+ <span class="tutorial-email-dot yellow"></span>
136
+ <span class="tutorial-email-dot green"></span>
137
+ <span class="tutorial-email-app">\uD83D\uDCE7 Email</span>
138
+ </div>
139
+ <div class="tutorial-email-header">
140
+ ${from ? `<div class="tutorial-email-field"><strong>From:</strong> ${from}</div>` : ''}
141
+ ${to ? `<div class="tutorial-email-field"><strong>To:</strong> ${to}</div>` : ''}
142
+ <div class="tutorial-email-field"><strong>Subject:</strong> ${subject}</div>
143
+ </div>
144
+ <div class="tutorial-email-body-container">
145
+ <iframe class="tutorial-email-body tutorial-email-iframe" srcdoc="${srcdocAttr}" sandbox="allow-same-origin"></iframe>
146
+ </div>
147
+ </div>
148
+ </div>`;
149
+ }
150
+ //# sourceMappingURL=overlay-html.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"overlay-html.js","sourceRoot":"","sources":["../src/overlay-html.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ import type { Page, Locator } from '@playwright/test';
2
+ import type { ContextStyle, OverlayPosition } from './types.js';
3
+ export interface OverlayOptions {
4
+ title: string;
5
+ lang: string;
6
+ highlightDuration: number;
7
+ position: OverlayPosition;
8
+ }
9
+ export declare class TutorialOverlay {
10
+ private page;
11
+ private options;
12
+ private currentStep;
13
+ private totalSteps;
14
+ constructor(page: Page, options: OverlayOptions);
15
+ switchPage(page: Page): void;
16
+ setTotalSteps(total: number): void;
17
+ setCurrentStep(step: number): void;
18
+ incrementStep(): number;
19
+ get step(): number;
20
+ showStep(title: string, description?: string, position?: OverlayPosition): Promise<void>;
21
+ showContext(contextTitle: string, text?: string, style?: ContextStyle): Promise<void>;
22
+ showComplete(message: string): Promise<void>;
23
+ /**
24
+ * Show a simulated email preview popup with HTML rendering
25
+ */
26
+ showEmailPreview(options: {
27
+ subject: string;
28
+ from?: string;
29
+ to?: string;
30
+ body: string;
31
+ highlightCode?: string;
32
+ isHtml?: boolean;
33
+ }): Promise<void>;
34
+ hideEmailPreview(): Promise<void>;
35
+ hide(): Promise<void>;
36
+ highlight(selector: string | Locator, duration?: number): Promise<void>;
37
+ unhighlight(selector: string | Locator): Promise<void>;
38
+ }
39
+ //# sourceMappingURL=overlay.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"overlay.d.ts","sourceRoot":"","sources":["../src/overlay.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAQhE,MAAM,WAAW,cAAc;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,iBAAiB,EAAE,MAAM,CAAC;IAC1B,QAAQ,EAAE,eAAe,CAAC;CAC1B;AAED,qBAAa,eAAe;IAC3B,OAAO,CAAC,IAAI,CAAO;IACnB,OAAO,CAAC,OAAO,CAAiB;IAChC,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,UAAU,CAAK;gBAEX,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,cAAc;IAK/C,UAAU,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI;IAI5B,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAIlC,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAIlC,aAAa,IAAI,MAAM;IAIvB,IAAI,IAAI,IAAI,MAAM,CAEjB;IAEK,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IAwBxF,WAAW,CAChB,YAAY,EAAE,MAAM,EACpB,IAAI,CAAC,EAAE,MAAM,EACb,KAAK,GAAE,YAAqB,GAC1B,OAAO,CAAC,IAAI,CAAC;IAqBV,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAiBlD;;OAEG;IACG,gBAAgB,CAAC,OAAO,EAAE;QAC/B,OAAO,EAAE,MAAM,CAAC;QAChB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,EAAE,CAAC,EAAE,MAAM,CAAC;QACZ,IAAI,EAAE,MAAM,CAAC;QACb,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,MAAM,CAAC,EAAE,OAAO,CAAC;KACjB,GAAG,OAAO,CAAC,IAAI,CAAC;IAsBX,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC;IAOjC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAOrB,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAMvE,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;CAQ5D"}
@@ -0,0 +1,134 @@
1
+ import { renderStepOverlay, renderContextOverlay, renderCompleteOverlay, renderEmailPreview } from './overlay-html.js';
2
+ export class TutorialOverlay {
3
+ page;
4
+ options;
5
+ currentStep = 0;
6
+ totalSteps = 0;
7
+ constructor(page, options) {
8
+ this.page = page;
9
+ this.options = options;
10
+ }
11
+ switchPage(page) {
12
+ this.page = page;
13
+ }
14
+ setTotalSteps(total) {
15
+ this.totalSteps = total;
16
+ }
17
+ setCurrentStep(step) {
18
+ this.currentStep = step;
19
+ }
20
+ incrementStep() {
21
+ return ++this.currentStep;
22
+ }
23
+ get step() {
24
+ return this.currentStep;
25
+ }
26
+ async showStep(title, description, position) {
27
+ const isRtl = this.options.lang === 'ar';
28
+ const progressPercent = this.totalSteps > 0 ? (this.currentStep / this.totalSteps) * 100 : 0;
29
+ const html = renderStepOverlay({
30
+ tutorialTitle: this.options.title,
31
+ step: this.currentStep,
32
+ title,
33
+ description,
34
+ isRtl,
35
+ progressPercent,
36
+ position: position ?? this.options.position
37
+ });
38
+ await this.page.evaluate((html) => {
39
+ const existing = document.getElementById('tutorial-overlay');
40
+ if (existing)
41
+ existing.remove();
42
+ const container = document.createElement('div');
43
+ container.innerHTML = html;
44
+ const overlay = container.firstElementChild;
45
+ document.body.appendChild(overlay);
46
+ }, html);
47
+ }
48
+ async showContext(contextTitle, text, style = 'goal') {
49
+ const isRtl = this.options.lang === 'ar';
50
+ const html = renderContextOverlay({
51
+ tutorialTitle: this.options.title,
52
+ contextTitle,
53
+ text,
54
+ style,
55
+ isRtl
56
+ });
57
+ await this.page.evaluate((html) => {
58
+ const existing = document.getElementById('tutorial-overlay');
59
+ if (existing)
60
+ existing.remove();
61
+ const container = document.createElement('div');
62
+ container.innerHTML = html;
63
+ const overlay = container.firstElementChild;
64
+ document.body.appendChild(overlay);
65
+ }, html);
66
+ }
67
+ async showComplete(message) {
68
+ const html = renderCompleteOverlay({
69
+ title: this.options.title,
70
+ message
71
+ });
72
+ await this.page.evaluate((html) => {
73
+ const overlay = document.getElementById('tutorial-overlay');
74
+ if (overlay) {
75
+ const container = document.createElement('div');
76
+ container.innerHTML = html;
77
+ const newOverlay = container.firstElementChild;
78
+ overlay.replaceWith(newOverlay);
79
+ }
80
+ }, html);
81
+ }
82
+ /**
83
+ * Show a simulated email preview popup with HTML rendering
84
+ */
85
+ async showEmailPreview(options) {
86
+ const isRtl = this.options.lang === 'ar';
87
+ const html = renderEmailPreview({
88
+ subject: options.subject,
89
+ from: options.from,
90
+ to: options.to,
91
+ body: options.body,
92
+ highlightCode: options.highlightCode,
93
+ isRtl
94
+ });
95
+ await this.page.evaluate((html) => {
96
+ const existing = document.getElementById('tutorial-email-preview');
97
+ if (existing)
98
+ existing.remove();
99
+ const container = document.createElement('div');
100
+ container.innerHTML = html;
101
+ const preview = container.firstElementChild;
102
+ document.body.appendChild(preview);
103
+ }, html);
104
+ }
105
+ async hideEmailPreview() {
106
+ await this.page.evaluate(() => {
107
+ const preview = document.getElementById('tutorial-email-preview');
108
+ if (preview)
109
+ preview.remove();
110
+ });
111
+ }
112
+ async hide() {
113
+ await this.page.evaluate(() => {
114
+ const overlay = document.getElementById('tutorial-overlay');
115
+ if (overlay)
116
+ overlay.remove();
117
+ });
118
+ }
119
+ async highlight(selector, duration) {
120
+ const locator = typeof selector === 'string' ? this.page.locator(selector) : selector;
121
+ await locator.evaluate((el) => el.classList.add('tutorial-highlight'));
122
+ await this.page.waitForTimeout(duration ?? this.options.highlightDuration);
123
+ }
124
+ async unhighlight(selector) {
125
+ const locator = typeof selector === 'string' ? this.page.locator(selector) : selector;
126
+ try {
127
+ await locator.evaluate((el) => el.classList.remove('tutorial-highlight'), null, { timeout: 2000 });
128
+ }
129
+ catch {
130
+ // Element may have been removed after click (dialog closed, navigation, etc.)
131
+ }
132
+ }
133
+ }
134
+ //# sourceMappingURL=overlay.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"overlay.js","sourceRoot":"","sources":["../src/overlay.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=postinstall.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"postinstall.d.ts","sourceRoot":"","sources":["../src/postinstall.ts"],"names":[],"mappings":""}