@webreel/core 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. package/README.md +188 -0
  2. package/assets/click-1.mp3 +0 -0
  3. package/assets/click-2.mp3 +0 -0
  4. package/assets/click-3.mp3 +0 -0
  5. package/assets/click-4.mp3 +0 -0
  6. package/assets/key-1.mp3 +0 -0
  7. package/assets/key-2.mp3 +0 -0
  8. package/assets/key-3.mp3 +0 -0
  9. package/assets/key-4.mp3 +0 -0
  10. package/dist/__tests__/actions.test.d.ts +2 -0
  11. package/dist/__tests__/actions.test.d.ts.map +1 -0
  12. package/dist/__tests__/actions.test.js +252 -0
  13. package/dist/__tests__/actions.test.js.map +1 -0
  14. package/dist/__tests__/chrome.test.d.ts +2 -0
  15. package/dist/__tests__/chrome.test.d.ts.map +1 -0
  16. package/dist/__tests__/chrome.test.js +29 -0
  17. package/dist/__tests__/chrome.test.js.map +1 -0
  18. package/dist/__tests__/cursor-motion.test.d.ts +2 -0
  19. package/dist/__tests__/cursor-motion.test.d.ts.map +1 -0
  20. package/dist/__tests__/cursor-motion.test.js +39 -0
  21. package/dist/__tests__/cursor-motion.test.js.map +1 -0
  22. package/dist/__tests__/ffmpeg.test.d.ts +2 -0
  23. package/dist/__tests__/ffmpeg.test.d.ts.map +1 -0
  24. package/dist/__tests__/ffmpeg.test.js +90 -0
  25. package/dist/__tests__/ffmpeg.test.js.map +1 -0
  26. package/dist/__tests__/media.test.d.ts +2 -0
  27. package/dist/__tests__/media.test.d.ts.map +1 -0
  28. package/dist/__tests__/media.test.js +98 -0
  29. package/dist/__tests__/media.test.js.map +1 -0
  30. package/dist/__tests__/overlays.test.d.ts +2 -0
  31. package/dist/__tests__/overlays.test.d.ts.map +1 -0
  32. package/dist/__tests__/overlays.test.js +109 -0
  33. package/dist/__tests__/overlays.test.js.map +1 -0
  34. package/dist/__tests__/recording-context.test.d.ts +2 -0
  35. package/dist/__tests__/recording-context.test.d.ts.map +1 -0
  36. package/dist/__tests__/recording-context.test.js +46 -0
  37. package/dist/__tests__/recording-context.test.js.map +1 -0
  38. package/dist/__tests__/timeline.test.d.ts +2 -0
  39. package/dist/__tests__/timeline.test.d.ts.map +1 -0
  40. package/dist/__tests__/timeline.test.js +88 -0
  41. package/dist/__tests__/timeline.test.js.map +1 -0
  42. package/dist/actions.d.ts +65 -0
  43. package/dist/actions.d.ts.map +1 -0
  44. package/dist/actions.js +729 -0
  45. package/dist/actions.js.map +1 -0
  46. package/dist/cdp.d.ts +3 -0
  47. package/dist/cdp.d.ts.map +1 -0
  48. package/dist/cdp.js +5 -0
  49. package/dist/cdp.js.map +1 -0
  50. package/dist/chrome.d.ts +12 -0
  51. package/dist/chrome.d.ts.map +1 -0
  52. package/dist/chrome.js +241 -0
  53. package/dist/chrome.js.map +1 -0
  54. package/dist/compositor.d.ts +8 -0
  55. package/dist/compositor.d.ts.map +1 -0
  56. package/dist/compositor.js +224 -0
  57. package/dist/compositor.js.map +1 -0
  58. package/dist/cursor-motion.d.ts +17 -0
  59. package/dist/cursor-motion.d.ts.map +1 -0
  60. package/dist/cursor-motion.js +138 -0
  61. package/dist/cursor-motion.js.map +1 -0
  62. package/dist/download.d.ts +6 -0
  63. package/dist/download.d.ts.map +1 -0
  64. package/dist/download.js +78 -0
  65. package/dist/download.js.map +1 -0
  66. package/dist/ffmpeg.d.ts +5 -0
  67. package/dist/ffmpeg.d.ts.map +1 -0
  68. package/dist/ffmpeg.js +106 -0
  69. package/dist/ffmpeg.js.map +1 -0
  70. package/dist/index.d.ts +12 -0
  71. package/dist/index.d.ts.map +1 -0
  72. package/dist/index.js +11 -0
  73. package/dist/index.js.map +1 -0
  74. package/dist/media.d.ts +23 -0
  75. package/dist/media.d.ts.map +1 -0
  76. package/dist/media.js +155 -0
  77. package/dist/media.js.map +1 -0
  78. package/dist/overlays.d.ts +21 -0
  79. package/dist/overlays.d.ts.map +1 -0
  80. package/dist/overlays.js +97 -0
  81. package/dist/overlays.js.map +1 -0
  82. package/dist/recorder.d.ts +41 -0
  83. package/dist/recorder.d.ts.map +1 -0
  84. package/dist/recorder.js +223 -0
  85. package/dist/recorder.js.map +1 -0
  86. package/dist/timeline.d.ts +82 -0
  87. package/dist/timeline.d.ts.map +1 -0
  88. package/dist/timeline.js +140 -0
  89. package/dist/timeline.js.map +1 -0
  90. package/dist/types.d.ts +90 -0
  91. package/dist/types.d.ts.map +1 -0
  92. package/dist/types.js +16 -0
  93. package/dist/types.js.map +1 -0
  94. package/package.json +51 -0
@@ -0,0 +1,138 @@
1
+ import { FRAME_MS, CAPTURE_CYCLE_MS } from "./types.js";
2
+ /**
3
+ * Fitts's law inspired duration: scales with sqrt of distance.
4
+ * Returns milliseconds. Tuned so short moves feel quick but not
5
+ * instant, and long cross-screen moves have enough frames to
6
+ * appear smooth at the target capture rate.
7
+ */
8
+ function moveDuration(distance) {
9
+ return 180 + 16 * Math.sqrt(distance) + (Math.random() - 0.5) * 30;
10
+ }
11
+ /**
12
+ * Asymmetric ease-in-out: reaches 50% progress at 40% of elapsed time.
13
+ * Acceleration is quadratic; deceleration is cubic (gentler settle-in).
14
+ * C1-continuous at the inflection point.
15
+ */
16
+ function humanEase(t) {
17
+ const mid = 0.4;
18
+ if (t <= mid) {
19
+ const s = t / mid;
20
+ return 0.5 * s * s;
21
+ }
22
+ const s = (t - mid) / (1 - mid);
23
+ return 0.5 + 0.5 * (1 - (1 - s) * (1 - s) * (1 - s));
24
+ }
25
+ function bezierControl(x0, y0, x1, y1, dist) {
26
+ const mx = (x0 + x1) / 2;
27
+ const my = (y0 + y1) / 2;
28
+ if (dist < 80)
29
+ return { x: mx, y: my };
30
+ const px = -(y1 - y0) / dist;
31
+ const py = (x1 - x0) / dist;
32
+ const offset = dist * (0.03 + Math.random() * 0.07) * (Math.random() < 0.5 ? -1 : 1);
33
+ return { x: mx + px * offset, y: my + py * offset };
34
+ }
35
+ function evalBezier(t, p0, p1, p2) {
36
+ const m = 1 - t;
37
+ return {
38
+ x: m * m * p0.x + 2 * m * t * p1.x + t * t * p2.x,
39
+ y: m * m * p0.y + 2 * m * t * p1.y + t * t * p2.y,
40
+ };
41
+ }
42
+ /**
43
+ * Animate cursor from one position to another. Pre-computes the full
44
+ * bezier path with easing and jitter, then registers a frame-based
45
+ * tick function (window.__tickCursor) that the recorder calls before
46
+ * every captureScreenshot. Each tick advances exactly one step through
47
+ * the path, so every captured frame shows a smooth intermediate
48
+ * position regardless of actual capture latency.
49
+ */
50
+ export async function animateMoveTo(ctx, client, fromX, fromY, toX, toY) {
51
+ const dx = toX - fromX;
52
+ const dy = toY - fromY;
53
+ const dist = Math.sqrt(dx * dx + dy * dy);
54
+ if (dist < 1)
55
+ return;
56
+ const duration = moveDuration(dist);
57
+ const ctrl = bezierControl(fromX, fromY, toX, toY, dist);
58
+ const p0 = { x: fromX, y: fromY };
59
+ const p2 = { x: toX, y: toY };
60
+ const NUM_STEPS = Math.max(6, Math.round(duration / FRAME_MS));
61
+ const positions = [{ x: fromX, y: fromY }];
62
+ for (let i = 1; i <= NUM_STEPS; i++) {
63
+ const rawT = i / NUM_STEPS;
64
+ const t = humanEase(rawT);
65
+ const pos = evalBezier(t, p0, ctrl, p2);
66
+ const jitter = dist > 60 ? microJitter(rawT, dist) : { x: 0, y: 0 };
67
+ positions.push({
68
+ x: Math.round((pos.x + jitter.x) * 10) / 10,
69
+ y: Math.round((pos.y + jitter.y) * 10) / 10,
70
+ });
71
+ }
72
+ positions[positions.length - 1] = { x: toX, y: toY };
73
+ if (ctx.isRecording && ctx.timeline) {
74
+ ctx.timeline.setCursorPath(positions);
75
+ await new Promise((r) => setTimeout(r, NUM_STEPS * CAPTURE_CYCLE_MS));
76
+ await client.Input.dispatchMouseEvent({
77
+ type: "mouseMoved",
78
+ x: toX,
79
+ y: toY,
80
+ });
81
+ return;
82
+ }
83
+ await client.Runtime.evaluate({
84
+ expression: `(() => {
85
+ const el = document.getElementById("__demo-cursor");
86
+ if (!el) return;
87
+ const pts = ${JSON.stringify(positions)};
88
+ let idx = 0;
89
+ window.__tickCursor = function() {
90
+ if (idx >= pts.length) { window.__tickCursor = null; return; }
91
+ const p = pts[idx++];
92
+ el.style.transform = "translate(" + p.x + "px," + p.y + "px)";
93
+ el.dataset.cx = String(p.x);
94
+ el.dataset.cy = String(p.y);
95
+ if (idx >= pts.length) window.__tickCursor = null;
96
+ };
97
+ window.__tickCursor();
98
+ })()`,
99
+ });
100
+ await new Promise((r) => setTimeout(r, NUM_STEPS * CAPTURE_CYCLE_MS));
101
+ await client.Input.dispatchMouseEvent({
102
+ type: "mouseMoved",
103
+ x: toX,
104
+ y: toY,
105
+ });
106
+ }
107
+ function microJitter(t, dist) {
108
+ const bell = Math.exp(-8 * (t - 0.5) * (t - 0.5));
109
+ const mag = Math.min(0.4, dist * 0.0004) * bell;
110
+ return {
111
+ x: (Math.random() - 0.5) * 2 * mag,
112
+ y: (Math.random() - 0.5) * 2 * mag,
113
+ };
114
+ }
115
+ export function computeEasedPath(fromX, fromY, toX, toY, steps) {
116
+ const dx = toX - fromX;
117
+ const dy = toY - fromY;
118
+ const dist = Math.sqrt(dx * dx + dy * dy);
119
+ if (dist < 1)
120
+ return [{ x: toX, y: toY }];
121
+ const ctrl = bezierControl(fromX, fromY, toX, toY, dist);
122
+ const p0 = { x: fromX, y: fromY };
123
+ const p2 = { x: toX, y: toY };
124
+ const pts = [];
125
+ for (let i = 1; i <= steps; i++) {
126
+ const rawT = i / steps;
127
+ const t = humanEase(rawT);
128
+ pts.push(evalBezier(t, p0, ctrl, p2));
129
+ }
130
+ pts[pts.length - 1] = { x: toX, y: toY };
131
+ return pts;
132
+ }
133
+ export function computeDragTiming(distance) {
134
+ const duration = 300 + 20 * Math.sqrt(distance) + (Math.random() - 0.5) * 40;
135
+ const steps = Math.max(12, Math.round(duration / 30));
136
+ return { steps, delayMs: duration / steps };
137
+ }
138
+ //# sourceMappingURL=cursor-motion.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cursor-motion.js","sourceRoot":"","sources":["../src/cursor-motion.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ export declare function fetchJson(url: string): Promise<unknown>;
2
+ export declare function downloadFile(url: string, destPath: string, label: string): Promise<void>;
3
+ export declare function extractArchive(archivePath: string, destDir: string): void;
4
+ export declare function downloadAndExtract(url: string, destDir: string, label: string): Promise<void>;
5
+ export declare function makeExecutable(path: string): void;
6
+ //# sourceMappingURL=download.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"download.d.ts","sourceRoot":"","sources":["../src/download.ts"],"names":[],"mappings":"AA6BA,wBAAsB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAO7D;AAED,wBAAsB,YAAY,CAChC,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,IAAI,CAAC,CAgBf;AAED,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAmBzE;AAED,wBAAsB,kBAAkB,CACtC,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,IAAI,CAAC,CASf;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAIjD"}
@@ -0,0 +1,78 @@
1
+ import { createWriteStream, mkdirSync, unlinkSync, chmodSync } from "node:fs";
2
+ import { resolve } from "node:path";
3
+ import { execFileSync } from "node:child_process";
4
+ import { Readable } from "node:stream";
5
+ import { pipeline } from "node:stream/promises";
6
+ const MAX_RETRIES = 3;
7
+ const RETRY_DELAY_MS = 1000;
8
+ async function withRetry(fn, label) {
9
+ let lastError = null;
10
+ for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
11
+ try {
12
+ return await fn();
13
+ }
14
+ catch (err) {
15
+ lastError = err;
16
+ if (attempt < MAX_RETRIES) {
17
+ await new Promise((r) => setTimeout(r, RETRY_DELAY_MS * attempt));
18
+ }
19
+ }
20
+ }
21
+ throw new Error(`${label} failed after ${MAX_RETRIES} attempts: ${lastError?.message ?? "unknown error"}`, {
22
+ cause: lastError,
23
+ });
24
+ }
25
+ export async function fetchJson(url) {
26
+ const res = await withRetry(async () => {
27
+ const r = await fetch(url);
28
+ if (!r.ok)
29
+ throw new Error(`HTTP ${r.status} fetching ${url}`);
30
+ return r;
31
+ }, `Fetch ${url}`);
32
+ return res.json();
33
+ }
34
+ export async function downloadFile(url, destPath, label) {
35
+ console.log(`Downloading ${label}... (one-time setup)`);
36
+ mkdirSync(resolve(destPath, ".."), { recursive: true });
37
+ await withRetry(async () => {
38
+ const res = await fetch(url);
39
+ if (!res.ok)
40
+ throw new Error(`HTTP ${res.status} fetching ${url}`);
41
+ if (!res.body)
42
+ throw new Error(`Empty response body from ${url}`);
43
+ const ws = createWriteStream(destPath);
44
+ await pipeline(Readable.fromWeb(res.body), ws);
45
+ }, `Download ${label}`);
46
+ }
47
+ export function extractArchive(archivePath, destDir) {
48
+ mkdirSync(destDir, { recursive: true });
49
+ if (archivePath.endsWith(".tar.xz")) {
50
+ execFileSync("tar", ["-xf", archivePath, "-C", destDir], { stdio: "pipe" });
51
+ }
52
+ else if (process.platform === "win32") {
53
+ execFileSync("powershell", [
54
+ "-Command",
55
+ `Expand-Archive -Force -Path '${archivePath.replace(/'/g, "''")}' -DestinationPath '${destDir.replace(/'/g, "''")}'`,
56
+ ], { stdio: "pipe" });
57
+ }
58
+ else {
59
+ execFileSync("unzip", ["-o", "-q", archivePath, "-d", destDir], {
60
+ stdio: "pipe",
61
+ });
62
+ }
63
+ }
64
+ export async function downloadAndExtract(url, destDir, label) {
65
+ mkdirSync(destDir, { recursive: true });
66
+ const ext = url.endsWith(".tar.xz") ? ".tar.xz" : ".zip";
67
+ const archivePath = resolve(destDir, `_download${ext}`);
68
+ await downloadFile(url, archivePath, label);
69
+ extractArchive(archivePath, destDir);
70
+ unlinkSync(archivePath);
71
+ console.log(`${label} ready.`);
72
+ }
73
+ export function makeExecutable(path) {
74
+ if (process.platform !== "win32") {
75
+ chmodSync(path, 0o755);
76
+ }
77
+ }
78
+ //# sourceMappingURL=download.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"download.js","sourceRoot":"","sources":["../src/download.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export declare function btbnAssetName(): string | null;
2
+ export declare function binaryName(): string;
3
+ export declare function findBinaryInDir(dir: string, name: string): string | null;
4
+ export declare function ensureFfmpeg(): Promise<string>;
5
+ //# sourceMappingURL=ffmpeg.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ffmpeg.d.ts","sourceRoot":"","sources":["../src/ffmpeg.ts"],"names":[],"mappings":"AAgBA,wBAAgB,aAAa,IAAI,MAAM,GAAG,IAAI,CAO7C;AAMD,wBAAgB,UAAU,IAAI,MAAM,CAEnC;AAWD,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAkBxE;AAqCD,wBAAsB,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC,CAoBpD"}
package/dist/ffmpeg.js ADDED
@@ -0,0 +1,106 @@
1
+ import { existsSync, readdirSync, unlinkSync } from "node:fs";
2
+ import { homedir } from "node:os";
3
+ import { resolve } from "node:path";
4
+ import { execSync } from "node:child_process";
5
+ import { fetchJson, downloadAndExtract, downloadFile, extractArchive, makeExecutable, } from "./download.js";
6
+ // BtbN/FFmpeg-Builds: linked from ffmpeg.org, built via GitHub Actions.
7
+ // Covers Linux (x64, arm64) and Windows (x64).
8
+ const BTBN_BASE = "https://github.com/BtbN/FFmpeg-Builds/releases/download/latest";
9
+ export function btbnAssetName() {
10
+ const { platform, arch } = process;
11
+ if (platform === "linux" && arch === "arm64")
12
+ return "ffmpeg-n7.1-latest-linuxarm64-gpl-7.1.tar.xz";
13
+ if (platform === "linux")
14
+ return "ffmpeg-n7.1-latest-linux64-gpl-7.1.tar.xz";
15
+ if (platform === "win32")
16
+ return "ffmpeg-n7.1-latest-win64-gpl-7.1.zip";
17
+ return null;
18
+ }
19
+ // evermeet.cx: linked from ffmpeg.org, macOS x64 static builds.
20
+ // Runs on ARM64 Macs via Rosetta 2.
21
+ const EVERMEET_API = "https://evermeet.cx/ffmpeg/info/ffmpeg/release";
22
+ export function binaryName() {
23
+ return process.platform === "win32" ? "ffmpeg.exe" : "ffmpeg";
24
+ }
25
+ function systemFfmpeg() {
26
+ try {
27
+ execSync("ffmpeg -version", { stdio: "pipe" });
28
+ return "ffmpeg";
29
+ }
30
+ catch {
31
+ return null;
32
+ }
33
+ }
34
+ export function findBinaryInDir(dir, name) {
35
+ if (!existsSync(dir))
36
+ return null;
37
+ const direct = resolve(dir, name);
38
+ if (existsSync(direct))
39
+ return direct;
40
+ try {
41
+ for (const entry of readdirSync(dir, { withFileTypes: true })) {
42
+ if (entry.isDirectory()) {
43
+ const binPath = resolve(dir, entry.name, "bin", name);
44
+ if (existsSync(binPath))
45
+ return binPath;
46
+ const flat = resolve(dir, entry.name, name);
47
+ if (existsSync(flat))
48
+ return flat;
49
+ }
50
+ }
51
+ }
52
+ catch (err) {
53
+ console.warn(`Failed to scan directory ${dir} for ${name}:`, err);
54
+ return null;
55
+ }
56
+ return null;
57
+ }
58
+ async function downloadBtbn(cacheDir) {
59
+ const asset = btbnAssetName();
60
+ if (!asset)
61
+ throw new Error("No BtbN build for this platform");
62
+ const url = `${BTBN_BASE}/${asset}`;
63
+ await downloadAndExtract(url, cacheDir, "ffmpeg");
64
+ const bin = binaryName();
65
+ const found = findBinaryInDir(cacheDir, bin);
66
+ if (found) {
67
+ makeExecutable(found);
68
+ return found;
69
+ }
70
+ throw new Error("Downloaded ffmpeg but could not locate binary");
71
+ }
72
+ async function downloadEvermeet(cacheDir) {
73
+ const info = (await fetchJson(EVERMEET_API));
74
+ const url = info.download.zip.url;
75
+ const archivePath = resolve(cacheDir, "_download.zip");
76
+ await downloadFile(url, archivePath, "ffmpeg");
77
+ extractArchive(archivePath, cacheDir);
78
+ unlinkSync(archivePath);
79
+ const bin = resolve(cacheDir, "ffmpeg");
80
+ if (existsSync(bin)) {
81
+ makeExecutable(bin);
82
+ return bin;
83
+ }
84
+ throw new Error("Downloaded ffmpeg but could not locate binary");
85
+ }
86
+ export async function ensureFfmpeg() {
87
+ if (process.env.FFMPEG_PATH)
88
+ return process.env.FFMPEG_PATH;
89
+ const cacheDir = resolve(homedir(), ".webreel", "bin", "ffmpeg");
90
+ const bin = findBinaryInDir(cacheDir, binaryName());
91
+ if (bin)
92
+ return bin;
93
+ try {
94
+ if (process.platform === "darwin") {
95
+ return await downloadEvermeet(cacheDir);
96
+ }
97
+ return await downloadBtbn(cacheDir);
98
+ }
99
+ catch (err) {
100
+ const sys = systemFfmpeg();
101
+ if (sys)
102
+ return sys;
103
+ throw new Error(`Failed to download ffmpeg and no system ffmpeg found: ${err instanceof Error ? err.message : String(err)}`, { cause: err });
104
+ }
105
+ }
106
+ //# sourceMappingURL=ffmpeg.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ffmpeg.js","sourceRoot":"","sources":["../src/ffmpeg.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ export type { CDPClient, BoundingBox, Point, SoundEvent } from "./types.js";
2
+ export { TARGET_FPS, FRAME_MS, DEFAULT_VIEWPORT_SIZE, OFFSCREEN_MARGIN, CAPTURE_CYCLE_MS, DEFAULT_CURSOR_SVG, DEFAULT_CURSOR_SIZE, DEFAULT_HUD_THEME, } from "./types.js";
3
+ export { connectCDP } from "./cdp.js";
4
+ export { launchChrome, type ChromeInstance, type LaunchChromeOptions } from "./chrome.js";
5
+ export { injectOverlays, showKeys, hideKeys, type OverlayTheme } from "./overlays.js";
6
+ export { RecordingContext, modKey, pause, navigate, waitForSelector, waitForText, findElementByText, findElementBySelector, moveCursorTo, clickAt, pressKey, typeText, dragFromTo, captureScreenshot, } from "./actions.js";
7
+ export { Recorder } from "./recorder.js";
8
+ export { InteractionTimeline, type TimelineData } from "./timeline.js";
9
+ export { compose, type ComposeOptions } from "./compositor.js";
10
+ export { ensureFfmpeg } from "./ffmpeg.js";
11
+ export { extractThumbnail, type SfxConfig } from "./media.js";
12
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC5E,OAAO,EACL,UAAU,EACV,QAAQ,EACR,qBAAqB,EACrB,gBAAgB,EAChB,gBAAgB,EAChB,kBAAkB,EAClB,mBAAmB,EACnB,iBAAiB,GAClB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACtC,OAAO,EAAE,YAAY,EAAE,KAAK,cAAc,EAAE,KAAK,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAC1F,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,YAAY,EAAE,MAAM,eAAe,CAAC;AACtF,OAAO,EACL,gBAAgB,EAChB,MAAM,EACN,KAAK,EACL,QAAQ,EACR,eAAe,EACf,WAAW,EACX,iBAAiB,EACjB,qBAAqB,EACrB,YAAY,EACZ,OAAO,EACP,QAAQ,EACR,QAAQ,EACR,UAAU,EACV,iBAAiB,GAClB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,mBAAmB,EAAE,KAAK,YAAY,EAAE,MAAM,eAAe,CAAC;AACvE,OAAO,EAAE,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAC/D,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,gBAAgB,EAAE,KAAK,SAAS,EAAE,MAAM,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,11 @@
1
+ export { TARGET_FPS, FRAME_MS, DEFAULT_VIEWPORT_SIZE, OFFSCREEN_MARGIN, CAPTURE_CYCLE_MS, DEFAULT_CURSOR_SVG, DEFAULT_CURSOR_SIZE, DEFAULT_HUD_THEME, } from "./types.js";
2
+ export { connectCDP } from "./cdp.js";
3
+ export { launchChrome } from "./chrome.js";
4
+ export { injectOverlays, showKeys, hideKeys } from "./overlays.js";
5
+ export { RecordingContext, modKey, pause, navigate, waitForSelector, waitForText, findElementByText, findElementBySelector, moveCursorTo, clickAt, pressKey, typeText, dragFromTo, captureScreenshot, } from "./actions.js";
6
+ export { Recorder } from "./recorder.js";
7
+ export { InteractionTimeline } from "./timeline.js";
8
+ export { compose } from "./compositor.js";
9
+ export { ensureFfmpeg } from "./ffmpeg.js";
10
+ export { extractThumbnail } from "./media.js";
11
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,UAAU,EACV,QAAQ,EACR,qBAAqB,EACrB,gBAAgB,EAChB,gBAAgB,EAChB,kBAAkB,EAClB,mBAAmB,EACnB,iBAAiB,GAClB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACtC,OAAO,EAAE,YAAY,EAAiD,MAAM,aAAa,CAAC;AAC1F,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,QAAQ,EAAqB,MAAM,eAAe,CAAC;AACtF,OAAO,EACL,gBAAgB,EAChB,MAAM,EACN,KAAK,EACL,QAAQ,EACR,eAAe,EACf,WAAW,EACX,iBAAiB,EACjB,qBAAqB,EACrB,YAAY,EACZ,OAAO,EACP,QAAQ,EACR,QAAQ,EACR,UAAU,EACV,iBAAiB,GAClB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,mBAAmB,EAAqB,MAAM,eAAe,CAAC;AACvE,OAAO,EAAE,OAAO,EAAuB,MAAM,iBAAiB,CAAC;AAC/D,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,gBAAgB,EAAkB,MAAM,YAAY,CAAC"}
@@ -0,0 +1,23 @@
1
+ import type { SoundEvent } from "./types.js";
2
+ export interface SfxConfig {
3
+ click?: 1 | 2 | 3 | 4 | string;
4
+ key?: 1 | 2 | 3 | 4 | string;
5
+ }
6
+ export declare function resolveSfxPath(value: 1 | 2 | 3 | 4 | string | undefined, prefix: "click" | "key"): string;
7
+ export declare function ensureSoundAssets(sfx?: SfxConfig): {
8
+ clickPath: string;
9
+ keyPath: string;
10
+ };
11
+ export declare function buildAudioMixArgs(videoInput: string, events: SoundEvent[], durationSec: number, sfx?: SfxConfig): {
12
+ inputArgs: string[];
13
+ filterComplex: string;
14
+ };
15
+ export interface FinalizeMp4Options {
16
+ remux?: boolean;
17
+ sfx?: SfxConfig;
18
+ }
19
+ export declare function finalizeMp4(ffmpegPath: string, tempVideo: string, outputPath: string, events: SoundEvent[], durationSec: number, options?: FinalizeMp4Options): void;
20
+ export declare function finalizeWebm(ffmpegPath: string, tempVideo: string, outputPath: string, events: SoundEvent[], durationSec: number, sfx?: SfxConfig): void;
21
+ export declare function extractThumbnail(ffmpegPath: string, videoPath: string, outputPath: string, timeSec: number): void;
22
+ export declare function finalizeGif(ffmpegPath: string, tempVideo: string, outputPath: string, width: number): void;
23
+ //# sourceMappingURL=media.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"media.d.ts","sourceRoot":"","sources":["../src/media.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAmB7C,MAAM,WAAW,SAAS;IACxB,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC;IAC/B,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC;CAC9B;AAED,wBAAgB,cAAc,CAC5B,KAAK,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,MAAM,GAAG,SAAS,EACzC,MAAM,EAAE,OAAO,GAAG,KAAK,GACtB,MAAM,CAIR;AAED,wBAAgB,iBAAiB,CAAC,GAAG,CAAC,EAAE,SAAS,GAAG;IAClD,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB,CAKA;AAED,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,UAAU,EAAE,EACpB,WAAW,EAAE,MAAM,EACnB,GAAG,CAAC,EAAE,SAAS,GACd;IAAE,SAAS,EAAE,MAAM,EAAE,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE,CAgChD;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,GAAG,CAAC,EAAE,SAAS,CAAC;CACjB;AAED,wBAAgB,WAAW,CACzB,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,UAAU,EAAE,EACpB,WAAW,EAAE,MAAM,EACnB,OAAO,CAAC,EAAE,kBAAkB,GAC3B,IAAI,CAmCN;AAED,wBAAgB,YAAY,CAC1B,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,UAAU,EAAE,EACpB,WAAW,EAAE,MAAM,EACnB,GAAG,CAAC,EAAE,SAAS,GACd,IAAI,CAoDN;AAED,wBAAgB,gBAAgB,CAC9B,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,GACd,IAAI,CAWN;AAED,wBAAgB,WAAW,CACzB,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,MAAM,GACZ,IAAI,CASN"}
package/dist/media.js ADDED
@@ -0,0 +1,155 @@
1
+ import { spawnSync } from "node:child_process";
2
+ import { rmSync, renameSync } from "node:fs";
3
+ import { resolve, dirname } from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ const __dirname = dirname(fileURLToPath(import.meta.url));
6
+ function runFfmpeg(ffmpegPath, args) {
7
+ const result = spawnSync(ffmpegPath, args, {
8
+ stdio: "pipe",
9
+ maxBuffer: 50 * 1024 * 1024,
10
+ });
11
+ if (result.status !== 0) {
12
+ const stderr = result.stderr?.toString().slice(-2000) ?? "";
13
+ throw new Error(`ffmpeg exited with code ${result.status}${stderr ? `:\n${stderr}` : ""}`);
14
+ }
15
+ }
16
+ const ASSETS_DIR = resolve(__dirname, "..", "assets");
17
+ export function resolveSfxPath(value, prefix) {
18
+ if (value === undefined)
19
+ return resolve(ASSETS_DIR, `${prefix}-1.mp3`);
20
+ if (typeof value === "string")
21
+ return value;
22
+ return resolve(ASSETS_DIR, `${prefix}-${value}.mp3`);
23
+ }
24
+ export function ensureSoundAssets(sfx) {
25
+ return {
26
+ clickPath: resolveSfxPath(sfx?.click, "click"),
27
+ keyPath: resolveSfxPath(sfx?.key, "key"),
28
+ };
29
+ }
30
+ export function buildAudioMixArgs(videoInput, events, durationSec, sfx) {
31
+ const { clickPath, keyPath } = ensureSoundAssets(sfx);
32
+ const inputArgs = [
33
+ "-i",
34
+ videoInput,
35
+ "-f",
36
+ "lavfi",
37
+ "-i",
38
+ `anullsrc=r=44100:cl=mono`,
39
+ "-t",
40
+ durationSec.toFixed(3),
41
+ ];
42
+ const filterParts = [];
43
+ const durationMs = Math.round(durationSec * 1000);
44
+ for (let i = 0; i < events.length; i++) {
45
+ const ev = events[i];
46
+ const soundFile = ev.type === "click" ? clickPath : keyPath;
47
+ const delayMs = Math.min(ev.timeMs, durationMs);
48
+ inputArgs.push("-i", soundFile);
49
+ const baseVol = ev.type === "click" ? 0.25 : 0.15;
50
+ const vol = baseVol + Math.random() * baseVol * 0.6;
51
+ const rate = 44100 * (0.93 + Math.random() * 0.14);
52
+ filterParts.push(`[${i + 2}]asetrate=${Math.round(rate)},aresample=44100,adelay=${delayMs}|${delayMs},volume=${vol.toFixed(3)}[s${i}]`);
53
+ }
54
+ const mixInputs = "[1]" + events.map((_, i) => `[s${i}]`).join("");
55
+ filterParts.push(`${mixInputs}amix=inputs=${events.length + 1}:normalize=0[aout]`);
56
+ return { inputArgs, filterComplex: filterParts.join(";") };
57
+ }
58
+ export function finalizeMp4(ffmpegPath, tempVideo, outputPath, events, durationSec, options) {
59
+ if (events.length === 0 || !options?.sfx) {
60
+ if (options?.remux) {
61
+ runFfmpeg(ffmpegPath, ["-y", "-i", tempVideo, "-c", "copy", outputPath]);
62
+ }
63
+ else {
64
+ renameSync(tempVideo, outputPath);
65
+ }
66
+ return;
67
+ }
68
+ const { inputArgs, filterComplex } = buildAudioMixArgs(tempVideo, events, durationSec, options.sfx);
69
+ runFfmpeg(ffmpegPath, [
70
+ "-y",
71
+ ...inputArgs,
72
+ "-filter_complex",
73
+ filterComplex,
74
+ "-map",
75
+ "0:v",
76
+ "-map",
77
+ "[aout]",
78
+ "-c:v",
79
+ "copy",
80
+ "-c:a",
81
+ "aac",
82
+ "-b:a",
83
+ "128k",
84
+ "-shortest",
85
+ outputPath,
86
+ ]);
87
+ }
88
+ export function finalizeWebm(ffmpegPath, tempVideo, outputPath, events, durationSec, sfx) {
89
+ const silentWebm = tempVideo + "_silent.webm";
90
+ runFfmpeg(ffmpegPath, [
91
+ "-y",
92
+ "-i",
93
+ tempVideo,
94
+ "-c:v",
95
+ "libvpx-vp9",
96
+ "-crf",
97
+ "30",
98
+ "-b:v",
99
+ "0",
100
+ "-pix_fmt",
101
+ "yuv420p",
102
+ silentWebm,
103
+ ]);
104
+ if (events.length === 0 || !sfx) {
105
+ renameSync(silentWebm, outputPath);
106
+ return;
107
+ }
108
+ try {
109
+ const { inputArgs, filterComplex } = buildAudioMixArgs(silentWebm, events, durationSec, sfx);
110
+ runFfmpeg(ffmpegPath, [
111
+ "-y",
112
+ ...inputArgs,
113
+ "-filter_complex",
114
+ filterComplex,
115
+ "-map",
116
+ "0:v",
117
+ "-map",
118
+ "[aout]",
119
+ "-c:v",
120
+ "copy",
121
+ "-c:a",
122
+ "libopus",
123
+ "-b:a",
124
+ "128k",
125
+ "-shortest",
126
+ outputPath,
127
+ ]);
128
+ }
129
+ finally {
130
+ rmSync(silentWebm, { force: true });
131
+ }
132
+ }
133
+ export function extractThumbnail(ffmpegPath, videoPath, outputPath, timeSec) {
134
+ runFfmpeg(ffmpegPath, [
135
+ "-y",
136
+ "-ss",
137
+ String(timeSec),
138
+ "-i",
139
+ videoPath,
140
+ "-frames:v",
141
+ "1",
142
+ outputPath,
143
+ ]);
144
+ }
145
+ export function finalizeGif(ffmpegPath, tempVideo, outputPath, width) {
146
+ runFfmpeg(ffmpegPath, [
147
+ "-y",
148
+ "-i",
149
+ tempVideo,
150
+ "-vf",
151
+ `fps=15,scale=${width}:-1:flags=lanczos,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse`,
152
+ outputPath,
153
+ ]);
154
+ }
155
+ //# sourceMappingURL=media.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"media.js","sourceRoot":"","sources":["../src/media.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ import type { CDPClient } from "./types.js";
2
+ export interface OverlayTheme {
3
+ cursorSvg?: string;
4
+ cursorSize?: number;
5
+ cursorHotspot?: "top-left" | "center";
6
+ hud?: {
7
+ background?: string;
8
+ color?: string;
9
+ fontSize?: number;
10
+ fontFamily?: string;
11
+ borderRadius?: number;
12
+ position?: "top" | "bottom";
13
+ };
14
+ }
15
+ export declare function injectOverlays(client: CDPClient, theme?: OverlayTheme, initialPosition?: {
16
+ x: number;
17
+ y: number;
18
+ }): Promise<void>;
19
+ export declare function showKeys(client: CDPClient, labels: string[]): Promise<void>;
20
+ export declare function hideKeys(client: CDPClient): Promise<void>;
21
+ //# sourceMappingURL=overlays.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"overlays.d.ts","sourceRoot":"","sources":["../src/overlays.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAQ5C,MAAM,WAAW,YAAY;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,UAAU,GAAG,QAAQ,CAAC;IACtC,GAAG,CAAC,EAAE;QACJ,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,EAAE,KAAK,GAAG,QAAQ,CAAC;KAC7B,CAAC;CACH;AAED,wBAAsB,cAAc,CAClC,MAAM,EAAE,SAAS,EACjB,KAAK,CAAC,EAAE,YAAY,EACpB,eAAe,CAAC,EAAE;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,GACzC,OAAO,CAAC,IAAI,CAAC,CAwEf;AAED,wBAAsB,QAAQ,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAcjF;AAED,wBAAsB,QAAQ,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAO/D"}