@argo-video/cli 0.22.0 → 0.23.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/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +39 -0
- package/dist/cli.js.map +1 -1
- package/dist/export.d.ts +3 -0
- package/dist/export.d.ts.map +1 -1
- package/dist/export.js +31 -6
- package/dist/export.js.map +1 -1
- package/dist/import.d.ts +21 -0
- package/dist/import.d.ts.map +1 -0
- package/dist/import.js +82 -0
- package/dist/import.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/media.d.ts +18 -0
- package/dist/media.d.ts.map +1 -1
- package/dist/media.js +90 -1
- package/dist/media.js.map +1 -1
- package/dist/overlays/render-to-png.d.ts +80 -0
- package/dist/overlays/render-to-png.d.ts.map +1 -0
- package/dist/overlays/render-to-png.js +280 -0
- package/dist/overlays/render-to-png.js.map +1 -0
- package/dist/overlays/zones.d.ts.map +1 -1
- package/dist/overlays/zones.js +36 -1
- package/dist/overlays/zones.js.map +1 -1
- package/dist/pipeline.d.ts.map +1 -1
- package/dist/pipeline.js +23 -0
- package/dist/pipeline.js.map +1 -1
- package/dist/preview.d.ts.map +1 -1
- package/dist/preview.js +699 -79
- package/dist/preview.js.map +1 -1
- package/package.json +1 -1
package/dist/media.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { execFileSync } from 'node:child_process';
|
|
1
|
+
import { execFileSync, spawnSync } from 'node:child_process';
|
|
2
2
|
export function getVideoDurationMs(videoPath) {
|
|
3
3
|
let raw;
|
|
4
4
|
try {
|
|
@@ -35,4 +35,93 @@ export function getVideoFrameRate(videoPath) {
|
|
|
35
35
|
}
|
|
36
36
|
return fps;
|
|
37
37
|
}
|
|
38
|
+
/**
|
|
39
|
+
* Compute average luminance of a single video frame at the given timestamp.
|
|
40
|
+
* Returns a value 0–255 or null on failure.
|
|
41
|
+
*/
|
|
42
|
+
function frameLuminance(videoPath, timestampMs) {
|
|
43
|
+
try {
|
|
44
|
+
const ss = (timestampMs / 1000).toFixed(3);
|
|
45
|
+
const result = spawnSync('ffmpeg', [
|
|
46
|
+
'-ss', ss,
|
|
47
|
+
'-i', videoPath,
|
|
48
|
+
'-frames:v', '1',
|
|
49
|
+
'-vf', 'scale=64:36',
|
|
50
|
+
'-f', 'rawvideo',
|
|
51
|
+
'-pix_fmt', 'rgb24',
|
|
52
|
+
'pipe:1',
|
|
53
|
+
], { stdio: ['pipe', 'pipe', 'pipe'], maxBuffer: 64 * 36 * 3 + 1024 });
|
|
54
|
+
// ffmpeg may return non-zero even when stdout has valid frame data (e.g., codec warnings)
|
|
55
|
+
if (!result.stdout || result.stdout.length < 3) {
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
const pixels = result.stdout;
|
|
59
|
+
let totalLuminance = 0;
|
|
60
|
+
const pixelCount = Math.floor(pixels.length / 3);
|
|
61
|
+
for (let i = 0; i < pixelCount; i++) {
|
|
62
|
+
const r = pixels[i * 3];
|
|
63
|
+
const g = pixels[i * 3 + 1];
|
|
64
|
+
const b = pixels[i * 3 + 2];
|
|
65
|
+
totalLuminance += 0.299 * r + 0.587 * g + 0.114 * b;
|
|
66
|
+
}
|
|
67
|
+
return totalLuminance / pixelCount;
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Detect whether a video region is predominantly dark or light.
|
|
75
|
+
* Samples multiple frames across the given time range for robustness
|
|
76
|
+
* (a single frame might be a transition or black screen).
|
|
77
|
+
*
|
|
78
|
+
* Returns the *overlay* theme for contrast: dark video → 'light' overlay,
|
|
79
|
+
* light video → 'dark' overlay. Falls back to 'dark' on error.
|
|
80
|
+
*/
|
|
81
|
+
export function detectVideoTheme(videoPath, startMs = 0, endMs) {
|
|
82
|
+
// Sample up to 5 frames spread across the range; if no endMs, sample around startMs
|
|
83
|
+
const sampleCount = 5;
|
|
84
|
+
const timestamps = [];
|
|
85
|
+
if (endMs !== undefined && endMs > startMs) {
|
|
86
|
+
const step = (endMs - startMs) / (sampleCount + 1);
|
|
87
|
+
for (let i = 1; i <= sampleCount; i++) {
|
|
88
|
+
timestamps.push(Math.round(startMs + step * i));
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
// Single point — sample at start plus small offsets
|
|
93
|
+
timestamps.push(startMs);
|
|
94
|
+
if (startMs > 500)
|
|
95
|
+
timestamps.push(startMs - 500);
|
|
96
|
+
timestamps.push(startMs + 500);
|
|
97
|
+
}
|
|
98
|
+
const luminances = [];
|
|
99
|
+
for (const ts of timestamps) {
|
|
100
|
+
const lum = frameLuminance(videoPath, Math.max(0, ts));
|
|
101
|
+
if (lum !== null)
|
|
102
|
+
luminances.push(lum);
|
|
103
|
+
}
|
|
104
|
+
if (luminances.length === 0)
|
|
105
|
+
return 'dark';
|
|
106
|
+
const avgLuminance = luminances.reduce((a, b) => a + b, 0) / luminances.length;
|
|
107
|
+
return avgLuminance < 128 ? 'light' : 'dark';
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Probe video dimensions (width × height) using ffprobe.
|
|
111
|
+
* Returns { width, height } or null on failure.
|
|
112
|
+
*/
|
|
113
|
+
export function getVideoDimensions(videoPath) {
|
|
114
|
+
try {
|
|
115
|
+
const raw = execFileSync('ffprobe', ['-v', 'error', '-select_streams', 'v:0',
|
|
116
|
+
'-show_entries', 'stream=width,height',
|
|
117
|
+
'-of', 'csv=p=0:s=x', videoPath], { encoding: 'utf-8' }).trim();
|
|
118
|
+
const match = raw.match(/^(\d+)x(\d+)$/);
|
|
119
|
+
if (!match)
|
|
120
|
+
return null;
|
|
121
|
+
return { width: Number(match[1]), height: Number(match[2]) };
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
38
127
|
//# sourceMappingURL=media.js.map
|
package/dist/media.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"media.js","sourceRoot":"","sources":["../src/media.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"media.js","sourceRoot":"","sources":["../src/media.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Render overlay cues to transparent PNGs using Playwright.
|
|
3
|
+
*
|
|
4
|
+
* For imported videos (no Playwright recording step), overlays defined in
|
|
5
|
+
* .scenes.json are never burned into the video. This module renders each
|
|
6
|
+
* overlay as a transparent PNG at the video's resolution so they can be
|
|
7
|
+
* composited via ffmpeg's overlay filter with `enable` timeline.
|
|
8
|
+
*/
|
|
9
|
+
import type { OverlayCue, Zone } from './types.js';
|
|
10
|
+
import type { BackgroundTheme } from './zones.js';
|
|
11
|
+
import type { Placement } from '../tts/align.js';
|
|
12
|
+
export interface OverlayPngInput {
|
|
13
|
+
scene: string;
|
|
14
|
+
overlay: OverlayCue;
|
|
15
|
+
startMs: number;
|
|
16
|
+
endMs: number;
|
|
17
|
+
}
|
|
18
|
+
export interface RenderedOverlayPng {
|
|
19
|
+
scene: string;
|
|
20
|
+
pngPath: string;
|
|
21
|
+
zone: Zone;
|
|
22
|
+
startMs: number;
|
|
23
|
+
endMs: number;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Render overlay cues to transparent PNGs.
|
|
27
|
+
*
|
|
28
|
+
* Launches a headless Chromium browser, renders each overlay as a
|
|
29
|
+
* full-page screenshot with transparent background, and saves them
|
|
30
|
+
* to `outputDir`. PNGs are content-addressed cached — only regenerated
|
|
31
|
+
* when the overlay definition or video dimensions change.
|
|
32
|
+
*
|
|
33
|
+
* @param overlays - Array of overlay cues with timing information
|
|
34
|
+
* @param outputDir - Directory to save PNGs (e.g. `.argo/<demo>/overlay-pngs/`)
|
|
35
|
+
* @param videoWidth - Width of the target video in pixels
|
|
36
|
+
* @param videoHeight - Height of the target video in pixels
|
|
37
|
+
* @param theme - Background theme for overlay styling, or per-overlay map keyed by scene name
|
|
38
|
+
* @returns Array of rendered overlay PNGs with timing and position info
|
|
39
|
+
*/
|
|
40
|
+
export declare function renderOverlaysToPng(overlays: OverlayPngInput[], outputDir: string, videoWidth: number, videoHeight: number, theme?: BackgroundTheme | Record<string, BackgroundTheme>): Promise<RenderedOverlayPng[]>;
|
|
41
|
+
/**
|
|
42
|
+
* Build ffmpeg filter_complex fragments to composite overlay PNGs onto a video.
|
|
43
|
+
*
|
|
44
|
+
* Each PNG is added as an input with `-loop 1` and overlaid using the
|
|
45
|
+
* `enable='between(t,start,end)'` timeline filter.
|
|
46
|
+
*
|
|
47
|
+
* @param pngs - Rendered overlay PNGs with timing
|
|
48
|
+
* @param baseInputCount - Number of ffmpeg inputs before overlay PNGs
|
|
49
|
+
* @returns Object with additional ffmpeg args, filter parts, and updated input count
|
|
50
|
+
*/
|
|
51
|
+
export declare function buildOverlayPngFilters(pngs: RenderedOverlayPng[], baseInputCount: number, videoSourceLabel: string): {
|
|
52
|
+
inputArgs: string[];
|
|
53
|
+
filterParts: string[];
|
|
54
|
+
videoSource: string;
|
|
55
|
+
nextInput: number;
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* Check if a demo is an imported video (has `.imported` marker).
|
|
59
|
+
* For variants (e.g. `demo-mobile`), also checks the base demo name.
|
|
60
|
+
*/
|
|
61
|
+
export declare function isImportedVideo(argoDir: string, demoName: string): boolean;
|
|
62
|
+
/**
|
|
63
|
+
* Build overlay PNGs for an imported video if overlays are defined.
|
|
64
|
+
*
|
|
65
|
+
* Shared across all export paths (CLI, pipeline, preview) to ensure parity.
|
|
66
|
+
* Detects adaptive theme per-overlay from the video frame at each overlay's
|
|
67
|
+
* time range — a dark section gets light overlays and vice versa.
|
|
68
|
+
*
|
|
69
|
+
* @returns Rendered overlay PNGs or undefined if not applicable
|
|
70
|
+
*/
|
|
71
|
+
export declare function buildOverlayPngsForImport(options: {
|
|
72
|
+
argoDir: string;
|
|
73
|
+
demoName: string;
|
|
74
|
+
manifestPath: string;
|
|
75
|
+
placements: Placement[];
|
|
76
|
+
videoWidth: number;
|
|
77
|
+
videoHeight: number;
|
|
78
|
+
deviceScaleFactor?: number;
|
|
79
|
+
}): Promise<RenderedOverlayPng[] | undefined>;
|
|
80
|
+
//# sourceMappingURL=render-to-png.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render-to-png.d.ts","sourceRoot":"","sources":["../../src/overlays/render-to-png.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH,OAAO,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAClD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEjD,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,UAAU,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,IAAI,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;CACf;AAoFD;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,mBAAmB,CACvC,QAAQ,EAAE,eAAe,EAAE,EAC3B,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,EACnB,KAAK,GAAE,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,eAAe,CAAU,GAChE,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAqE/B;AAED;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,kBAAkB,EAAE,EAC1B,cAAc,EAAE,MAAM,EACtB,gBAAgB,EAAE,MAAM,GACvB;IACD,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;CACnB,CA+BA;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAS1E;AAED;;;;;;;;GAQG;AACH,wBAAsB,yBAAyB,CAAC,OAAO,EAAE;IACvD,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,SAAS,EAAE,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B,GAAG,OAAO,CAAC,kBAAkB,EAAE,GAAG,SAAS,CAAC,CAuD5C"}
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Render overlay cues to transparent PNGs using Playwright.
|
|
3
|
+
*
|
|
4
|
+
* For imported videos (no Playwright recording step), overlays defined in
|
|
5
|
+
* .scenes.json are never burned into the video. This module renders each
|
|
6
|
+
* overlay as a transparent PNG at the video's resolution so they can be
|
|
7
|
+
* composited via ffmpeg's overlay filter with `enable` timeline.
|
|
8
|
+
*/
|
|
9
|
+
import { existsSync, mkdirSync, readFileSync, readdirSync, unlinkSync } from 'node:fs';
|
|
10
|
+
import { join } from 'node:path';
|
|
11
|
+
import { createHash } from 'node:crypto';
|
|
12
|
+
import { renderTemplate } from './templates.js';
|
|
13
|
+
/**
|
|
14
|
+
* CSS positioning rules that match the live preview / recording zones.
|
|
15
|
+
* Uses fixed positioning within a viewport-sized container.
|
|
16
|
+
*/
|
|
17
|
+
const ZONE_CSS = {
|
|
18
|
+
'bottom-center': 'position:fixed;bottom:60px;left:50%;transform:translateX(-50%);',
|
|
19
|
+
'top-left': 'position:fixed;top:40px;left:40px;',
|
|
20
|
+
'top-right': 'position:fixed;top:40px;right:40px;',
|
|
21
|
+
'bottom-left': 'position:fixed;bottom:60px;left:40px;',
|
|
22
|
+
'bottom-right': 'position:fixed;bottom:60px;right:40px;',
|
|
23
|
+
'center': 'position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);',
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Map zone positions to ffmpeg overlay x/y expressions.
|
|
27
|
+
* W, H = base video dimensions; w, h = overlay dimensions.
|
|
28
|
+
*/
|
|
29
|
+
const ZONE_FFMPEG_POS = {
|
|
30
|
+
'top-left': 'x=40:y=40',
|
|
31
|
+
'top-right': 'x=W-w-40:y=40',
|
|
32
|
+
'bottom-left': 'x=40:y=H-h-60',
|
|
33
|
+
'bottom-right': 'x=W-w-40:y=H-h-60',
|
|
34
|
+
'bottom-center': 'x=(W-w)/2:y=H-h-60',
|
|
35
|
+
'center': 'x=(W-w)/2:y=(H-h)/2',
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Build a full-page HTML document that renders a single overlay at the
|
|
39
|
+
* correct zone position on a transparent background.
|
|
40
|
+
*/
|
|
41
|
+
function buildOverlayHtml(templateResult, zone, width, height) {
|
|
42
|
+
const styleEntries = Object.entries(templateResult.styles)
|
|
43
|
+
.map(([k, v]) => {
|
|
44
|
+
// Convert camelCase to kebab-case for CSS
|
|
45
|
+
const prop = k.replace(/([A-Z])/g, '-$1').toLowerCase();
|
|
46
|
+
return `${prop}: ${v};`;
|
|
47
|
+
})
|
|
48
|
+
.join(' ');
|
|
49
|
+
const zoneCss = ZONE_CSS[zone];
|
|
50
|
+
return `<!DOCTYPE html>
|
|
51
|
+
<html>
|
|
52
|
+
<head>
|
|
53
|
+
<meta charset="utf-8">
|
|
54
|
+
<style>
|
|
55
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
56
|
+
html, body {
|
|
57
|
+
width: ${width}px;
|
|
58
|
+
height: ${height}px;
|
|
59
|
+
overflow: hidden;
|
|
60
|
+
background: transparent;
|
|
61
|
+
}
|
|
62
|
+
.overlay {
|
|
63
|
+
${zoneCss}
|
|
64
|
+
z-index: 999999;
|
|
65
|
+
pointer-events: none;
|
|
66
|
+
font-family: system-ui, -apple-system, sans-serif;
|
|
67
|
+
${styleEntries}
|
|
68
|
+
}
|
|
69
|
+
</style>
|
|
70
|
+
</head>
|
|
71
|
+
<body>
|
|
72
|
+
<div class="overlay">${templateResult.contentHtml}</div>
|
|
73
|
+
</body>
|
|
74
|
+
</html>`;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Compute a content hash for cache invalidation.
|
|
78
|
+
* Changes to the overlay cue or video dimensions invalidate the cache.
|
|
79
|
+
*/
|
|
80
|
+
function computeHash(overlay, width, height, theme = 'dark') {
|
|
81
|
+
const data = JSON.stringify({ overlay, width, height, theme });
|
|
82
|
+
return createHash('sha256').update(data).digest('hex').slice(0, 16);
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Render overlay cues to transparent PNGs.
|
|
86
|
+
*
|
|
87
|
+
* Launches a headless Chromium browser, renders each overlay as a
|
|
88
|
+
* full-page screenshot with transparent background, and saves them
|
|
89
|
+
* to `outputDir`. PNGs are content-addressed cached — only regenerated
|
|
90
|
+
* when the overlay definition or video dimensions change.
|
|
91
|
+
*
|
|
92
|
+
* @param overlays - Array of overlay cues with timing information
|
|
93
|
+
* @param outputDir - Directory to save PNGs (e.g. `.argo/<demo>/overlay-pngs/`)
|
|
94
|
+
* @param videoWidth - Width of the target video in pixels
|
|
95
|
+
* @param videoHeight - Height of the target video in pixels
|
|
96
|
+
* @param theme - Background theme for overlay styling, or per-overlay map keyed by scene name
|
|
97
|
+
* @returns Array of rendered overlay PNGs with timing and position info
|
|
98
|
+
*/
|
|
99
|
+
export async function renderOverlaysToPng(overlays, outputDir, videoWidth, videoHeight, theme = 'dark') {
|
|
100
|
+
if (overlays.length === 0)
|
|
101
|
+
return [];
|
|
102
|
+
mkdirSync(outputDir, { recursive: true });
|
|
103
|
+
const resolveTheme = (scene) => typeof theme === 'string' ? theme : (theme[scene] ?? 'dark');
|
|
104
|
+
// Check which overlays need rendering (cache check)
|
|
105
|
+
const toRender = [];
|
|
106
|
+
const results = [];
|
|
107
|
+
const validPngPaths = new Set();
|
|
108
|
+
for (const input of overlays) {
|
|
109
|
+
const zone = input.overlay.placement ?? 'bottom-center';
|
|
110
|
+
const overlayTheme = resolveTheme(input.scene);
|
|
111
|
+
const hash = computeHash(input.overlay, videoWidth, videoHeight, overlayTheme);
|
|
112
|
+
const pngPath = join(outputDir, `${input.scene}-overlay-${hash}.png`);
|
|
113
|
+
validPngPaths.add(`${input.scene}-overlay-${hash}.png`);
|
|
114
|
+
if (existsSync(pngPath)) {
|
|
115
|
+
results.push({ scene: input.scene, pngPath, zone, startMs: input.startMs, endMs: input.endMs });
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
toRender.push({ input, pngPath, hash, theme: overlayTheme });
|
|
119
|
+
results.push({ scene: input.scene, pngPath, zone, startMs: input.startMs, endMs: input.endMs });
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
// Clean up stale PNGs whose content hash no longer matches any current overlay
|
|
123
|
+
try {
|
|
124
|
+
for (const file of readdirSync(outputDir)) {
|
|
125
|
+
if (file.endsWith('.png') && !validPngPaths.has(file)) {
|
|
126
|
+
try {
|
|
127
|
+
unlinkSync(join(outputDir, file));
|
|
128
|
+
}
|
|
129
|
+
catch { /* ignore */ }
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
catch { /* dir may not exist yet */ }
|
|
134
|
+
if (toRender.length === 0)
|
|
135
|
+
return results;
|
|
136
|
+
// Lazy-load Playwright to avoid import cost when all PNGs are cached
|
|
137
|
+
const { chromium } = await import('playwright');
|
|
138
|
+
const browser = await chromium.launch({ headless: true });
|
|
139
|
+
try {
|
|
140
|
+
const context = await browser.newContext({
|
|
141
|
+
viewport: { width: videoWidth, height: videoHeight },
|
|
142
|
+
deviceScaleFactor: 1,
|
|
143
|
+
});
|
|
144
|
+
const page = await context.newPage();
|
|
145
|
+
for (const { input, pngPath, theme: overlayTheme } of toRender) {
|
|
146
|
+
const zone = input.overlay.placement ?? 'bottom-center';
|
|
147
|
+
const templateResult = renderTemplate(input.overlay, overlayTheme);
|
|
148
|
+
const html = buildOverlayHtml(templateResult, zone, videoWidth, videoHeight);
|
|
149
|
+
await page.setContent(html, { waitUntil: 'load' });
|
|
150
|
+
await page.screenshot({
|
|
151
|
+
path: pngPath,
|
|
152
|
+
omitBackground: true,
|
|
153
|
+
fullPage: false,
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
await context.close();
|
|
157
|
+
}
|
|
158
|
+
finally {
|
|
159
|
+
await browser.close();
|
|
160
|
+
}
|
|
161
|
+
return results;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Build ffmpeg filter_complex fragments to composite overlay PNGs onto a video.
|
|
165
|
+
*
|
|
166
|
+
* Each PNG is added as an input with `-loop 1` and overlaid using the
|
|
167
|
+
* `enable='between(t,start,end)'` timeline filter.
|
|
168
|
+
*
|
|
169
|
+
* @param pngs - Rendered overlay PNGs with timing
|
|
170
|
+
* @param baseInputCount - Number of ffmpeg inputs before overlay PNGs
|
|
171
|
+
* @returns Object with additional ffmpeg args, filter parts, and updated input count
|
|
172
|
+
*/
|
|
173
|
+
export function buildOverlayPngFilters(pngs, baseInputCount, videoSourceLabel) {
|
|
174
|
+
if (pngs.length === 0) {
|
|
175
|
+
return { inputArgs: [], filterParts: [], videoSource: videoSourceLabel, nextInput: baseInputCount };
|
|
176
|
+
}
|
|
177
|
+
const inputArgs = [];
|
|
178
|
+
const filterParts = [];
|
|
179
|
+
let currentVideo = videoSourceLabel;
|
|
180
|
+
let nextInput = baseInputCount;
|
|
181
|
+
for (let i = 0; i < pngs.length; i++) {
|
|
182
|
+
const png = pngs[i];
|
|
183
|
+
const pngInputIdx = nextInput++;
|
|
184
|
+
// Add PNG as looped input with explicit duration to prevent ffmpeg hanging.
|
|
185
|
+
// Without -t, -loop 1 creates an infinite stream that never terminates.
|
|
186
|
+
const durSec = ((png.endMs + 1000) / 1000).toFixed(3);
|
|
187
|
+
inputArgs.push('-loop', '1', '-t', durSec, '-i', png.pngPath);
|
|
188
|
+
const startSec = (png.startMs / 1000).toFixed(3);
|
|
189
|
+
const endSec = (png.endMs / 1000).toFixed(3);
|
|
190
|
+
const posExpr = ZONE_FFMPEG_POS[png.zone];
|
|
191
|
+
const outputLabel = `ovlpng${i}`;
|
|
192
|
+
filterParts.push(`[${currentVideo}][${pngInputIdx}:v]overlay=${posExpr}:enable='between(t\\,${startSec}\\,${endSec})':format=auto:eof_action=pass[${outputLabel}]`);
|
|
193
|
+
currentVideo = outputLabel;
|
|
194
|
+
}
|
|
195
|
+
return { inputArgs, filterParts, videoSource: currentVideo, nextInput };
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Check if a demo is an imported video (has `.imported` marker).
|
|
199
|
+
* For variants (e.g. `demo-mobile`), also checks the base demo name.
|
|
200
|
+
*/
|
|
201
|
+
export function isImportedVideo(argoDir, demoName) {
|
|
202
|
+
if (existsSync(join(argoDir, demoName, '.imported')))
|
|
203
|
+
return true;
|
|
204
|
+
// Variant subdirs like `demo-mobile` — check the base demo
|
|
205
|
+
const dashIdx = demoName.lastIndexOf('-');
|
|
206
|
+
if (dashIdx > 0) {
|
|
207
|
+
const baseName = demoName.slice(0, dashIdx);
|
|
208
|
+
if (existsSync(join(argoDir, baseName, '.imported')))
|
|
209
|
+
return true;
|
|
210
|
+
}
|
|
211
|
+
return false;
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Build overlay PNGs for an imported video if overlays are defined.
|
|
215
|
+
*
|
|
216
|
+
* Shared across all export paths (CLI, pipeline, preview) to ensure parity.
|
|
217
|
+
* Detects adaptive theme per-overlay from the video frame at each overlay's
|
|
218
|
+
* time range — a dark section gets light overlays and vice versa.
|
|
219
|
+
*
|
|
220
|
+
* @returns Rendered overlay PNGs or undefined if not applicable
|
|
221
|
+
*/
|
|
222
|
+
export async function buildOverlayPngsForImport(options) {
|
|
223
|
+
const { argoDir, demoName, manifestPath, placements, videoWidth, videoHeight, deviceScaleFactor = 1 } = options;
|
|
224
|
+
if (!isImportedVideo(argoDir, demoName))
|
|
225
|
+
return undefined;
|
|
226
|
+
if (placements.length === 0)
|
|
227
|
+
return undefined;
|
|
228
|
+
let scenes;
|
|
229
|
+
try {
|
|
230
|
+
scenes = JSON.parse(readFileSync(manifestPath, 'utf-8'));
|
|
231
|
+
}
|
|
232
|
+
catch {
|
|
233
|
+
return undefined;
|
|
234
|
+
}
|
|
235
|
+
const hasOverlays = scenes.some((s) => s.overlay);
|
|
236
|
+
if (!hasOverlays)
|
|
237
|
+
return undefined;
|
|
238
|
+
const overlayInputs = [];
|
|
239
|
+
for (const entry of scenes) {
|
|
240
|
+
if (!entry.overlay || !entry.scene)
|
|
241
|
+
continue;
|
|
242
|
+
const placement = placements.find((p) => p.scene === entry.scene);
|
|
243
|
+
if (!placement)
|
|
244
|
+
continue;
|
|
245
|
+
overlayInputs.push({
|
|
246
|
+
scene: entry.scene,
|
|
247
|
+
overlay: entry.overlay,
|
|
248
|
+
startMs: placement.startMs,
|
|
249
|
+
endMs: placement.endMs,
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
if (overlayInputs.length === 0)
|
|
253
|
+
return undefined;
|
|
254
|
+
// Detect theme per-overlay from the video at each overlay's time range
|
|
255
|
+
// Try the original-extension video first (imported videos), fall back to .webm
|
|
256
|
+
const { detectVideoTheme } = await import('../media.js');
|
|
257
|
+
const demoDir = join(argoDir, demoName);
|
|
258
|
+
const videoExts = ['.mp4', '.mov', '.mkv', '.avi', '.webm'];
|
|
259
|
+
let videoPath = join(demoDir, 'video.webm');
|
|
260
|
+
for (const ext of videoExts) {
|
|
261
|
+
const candidate = join(demoDir, `video${ext}`);
|
|
262
|
+
if (existsSync(candidate)) {
|
|
263
|
+
videoPath = candidate;
|
|
264
|
+
break;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
const themeMap = {};
|
|
268
|
+
for (const input of overlayInputs) {
|
|
269
|
+
themeMap[input.scene] = detectVideoTheme(videoPath, input.startMs, input.endMs);
|
|
270
|
+
}
|
|
271
|
+
const uniqueThemes = [...new Set(Object.values(themeMap))];
|
|
272
|
+
const themeLabel = uniqueThemes.length === 1 ? uniqueThemes[0] : `mixed (${uniqueThemes.join('/')})`;
|
|
273
|
+
const pngDir = join(argoDir, demoName, 'overlay-pngs');
|
|
274
|
+
const renderW = videoWidth * deviceScaleFactor;
|
|
275
|
+
const renderH = videoHeight * deviceScaleFactor;
|
|
276
|
+
const pngs = await renderOverlaysToPng(overlayInputs, pngDir, renderW, renderH, themeMap);
|
|
277
|
+
console.log(` Rendered ${pngs.length} overlay PNG(s) for compositing (theme: ${themeLabel})`);
|
|
278
|
+
return pngs;
|
|
279
|
+
}
|
|
280
|
+
//# sourceMappingURL=render-to-png.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render-to-png.js","sourceRoot":"","sources":["../../src/overlays/render-to-png.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"zones.d.ts","sourceRoot":"","sources":["../../src/overlays/zones.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAEvC,eAAO,MAAM,cAAc,kBAAkB,CAAC;AAuB9C;;;;;GAKG;AACH,wBAAsB,cAAc,CAClC,IAAI,EAAE,IAAI,EACV,IAAI,EAAE,IAAI,EACV,WAAW,EAAE,MAAM,EACnB,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EACvC,YAAY,CAAC,EAAE,MAAM,GACpB,OAAO,CAAC,IAAI,CAAC,CAgCf;AAED,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,OAAO,CAAC;AAE/C;;;;;GAKG;AACH,wBAAsB,qBAAqB,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,eAAe,CAAC,
|
|
1
|
+
{"version":3,"file":"zones.d.ts","sourceRoot":"","sources":["../../src/overlays/zones.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAEvC,eAAO,MAAM,cAAc,kBAAkB,CAAC;AAuB9C;;;;;GAKG;AACH,wBAAsB,cAAc,CAClC,IAAI,EAAE,IAAI,EACV,IAAI,EAAE,IAAI,EACV,WAAW,EAAE,MAAM,EACnB,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EACvC,YAAY,CAAC,EAAE,MAAM,GACpB,OAAO,CAAC,IAAI,CAAC,CAgCf;AAED,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,OAAO,CAAC;AAE/C;;;;;GAKG;AACH,wBAAsB,qBAAqB,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,eAAe,CAAC,CA2E5F;AAED;;GAEG;AACH,wBAAsB,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAMtE"}
|
package/dist/overlays/zones.js
CHANGED
|
@@ -99,7 +99,42 @@ export async function detectBackgroundTheme(page, zone) {
|
|
|
99
99
|
}
|
|
100
100
|
}
|
|
101
101
|
}
|
|
102
|
-
// Fall back
|
|
102
|
+
// Fall back: resolve CSS custom properties used for backgrounds.
|
|
103
|
+
// getComputedStyle(body).backgroundColor returns transparent when
|
|
104
|
+
// the background is set via CSS variables (e.g., background: var(--bg)).
|
|
105
|
+
// We resolve the variable value and parse the hex/rgb color.
|
|
106
|
+
const rootStyle = getComputedStyle(document.documentElement);
|
|
107
|
+
const bgVarNames = ['--bg', '--background', '--bg-color', '--background-color'];
|
|
108
|
+
for (const varName of bgVarNames) {
|
|
109
|
+
const varVal = rootStyle.getPropertyValue(varName).trim();
|
|
110
|
+
if (!varVal)
|
|
111
|
+
continue;
|
|
112
|
+
// Try hex color
|
|
113
|
+
const hexMatch = varVal.match(/^#([0-9a-f]{3,8})$/i);
|
|
114
|
+
if (hexMatch) {
|
|
115
|
+
let hex = hexMatch[1];
|
|
116
|
+
if (hex.length === 3)
|
|
117
|
+
hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];
|
|
118
|
+
const r = parseInt(hex.slice(0, 2), 16);
|
|
119
|
+
const g = parseInt(hex.slice(2, 4), 16);
|
|
120
|
+
const b = parseInt(hex.slice(4, 6), 16);
|
|
121
|
+
const lum = 0.299 * r + 0.587 * g + 0.114 * b;
|
|
122
|
+
return lum < 128 ? 'light' : 'dark';
|
|
123
|
+
}
|
|
124
|
+
// Try rgb/rgba
|
|
125
|
+
const rgbMatch = varVal.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/);
|
|
126
|
+
if (rgbMatch) {
|
|
127
|
+
const lum = 0.299 * Number(rgbMatch[1]) + 0.587 * Number(rgbMatch[2]) + 0.114 * Number(rgbMatch[3]);
|
|
128
|
+
return lum < 128 ? 'light' : 'dark';
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
// Check if html/body has a class indicating dark mode
|
|
132
|
+
const htmlClasses = document.documentElement.className;
|
|
133
|
+
const bodyClasses = document.body.className;
|
|
134
|
+
if (/\bdark\b/i.test(htmlClasses) || /\bdark\b/i.test(bodyClasses)) {
|
|
135
|
+
return 'light';
|
|
136
|
+
}
|
|
137
|
+
// Last resort: system theme
|
|
103
138
|
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
|
104
139
|
return prefersDark ? 'light' : 'dark';
|
|
105
140
|
}, pos);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"zones.js","sourceRoot":"","sources":["../../src/overlays/zones.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"zones.js","sourceRoot":"","sources":["../../src/overlays/zones.ts"],"names":[],"mappings":"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"}
|
package/dist/pipeline.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../src/pipeline.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../src/pipeline.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAa9C,MAAM,WAAW,eAAe;IAC9B,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CASxD;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,IAAI,CAAC,UAAU,EAAE,SAAS,GAAG,UAAU,GAAG,WAAW,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,GAAG,UAAU,CAAC,EACxG,YAAY,CAAC,EAAE,eAAe,GAC7B,OAAO,CAAC,MAAM,EAAE,CAAC,CAyBnB;AAED,wBAAsB,WAAW,CAC/B,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,IAAI,CAAC,UAAU,EAAE,SAAS,GAAG,UAAU,GAAG,WAAW,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,GAAG,UAAU,CAAC,EACxG,YAAY,CAAC,EAAE,eAAe,GAC7B,OAAO,CAAC,MAAM,CAAC,CAyajB"}
|
package/dist/pipeline.js
CHANGED
|
@@ -12,6 +12,7 @@ import { applySpeedRampToTimeline } from './speed-ramp.js';
|
|
|
12
12
|
import { shiftCameraMoves, scaleCameraMoves } from './camera-move.js';
|
|
13
13
|
import { resolveFreezes, adjustPlacementsForFreezes, totalFreezeDurationMs, } from './freeze.js';
|
|
14
14
|
import { getVideoDurationMs } from './media.js';
|
|
15
|
+
import { buildOverlayPngsForImport } from './overlays/render-to-png.js';
|
|
15
16
|
// Note: MusicGen (AI music generation) is a preview-only feature — runs in browser via WebGPU.
|
|
16
17
|
// Pipeline uses saved WAV files via audio.music config path.
|
|
17
18
|
import { buildPlacementsFromTimingAndDurations, buildSceneTexts, computeHeadTrimMs, readScenesManifest, shiftPlacements, } from './timeline.js';
|
|
@@ -209,6 +210,16 @@ export async function runPipeline(demoName, config, pipelineOpts) {
|
|
|
209
210
|
const chapterMetadataPath = join(argoDir, 'chapters.txt');
|
|
210
211
|
const chapterMetadata = generateChapterMetadata(finalPlacements, finalDurationMs);
|
|
211
212
|
writeFileSync(chapterMetadataPath, chapterMetadata, 'utf-8');
|
|
213
|
+
// Render overlay PNGs for imported videos (no Playwright recording step)
|
|
214
|
+
const overlayPngs = await buildOverlayPngsForImport({
|
|
215
|
+
argoDir: '.argo',
|
|
216
|
+
demoName,
|
|
217
|
+
manifestPath,
|
|
218
|
+
placements: finalPlacements,
|
|
219
|
+
videoWidth: config.video.width,
|
|
220
|
+
videoHeight: config.video.height,
|
|
221
|
+
deviceScaleFactor: config.video.deviceScaleFactor,
|
|
222
|
+
});
|
|
212
223
|
// Step 4: Export final video
|
|
213
224
|
console.log('🎞️ Cutting the final take...');
|
|
214
225
|
const exportOptions = {
|
|
@@ -232,6 +243,7 @@ export async function runPipeline(demoName, config, pipelineOpts) {
|
|
|
232
243
|
musicPath: config.export.audio?.music,
|
|
233
244
|
musicVolume: config.export.audio?.musicVolume,
|
|
234
245
|
watermark: config.export.watermark,
|
|
246
|
+
overlayPngs,
|
|
235
247
|
};
|
|
236
248
|
if (resolvedFreezes.length > 0) {
|
|
237
249
|
exportOptions.freezeSpecs = resolvedFreezes;
|
|
@@ -382,6 +394,16 @@ export async function runPipeline(demoName, config, pipelineOpts) {
|
|
|
382
394
|
variantCameraMoves = shiftCameraMoves(variantCameraMoves, variantHeadTrimMs);
|
|
383
395
|
variantCameraMoves = scaleCameraMoves(variantCameraMoves, config.video.deviceScaleFactor ?? 1);
|
|
384
396
|
}
|
|
397
|
+
// Render overlay PNGs for imported video variants
|
|
398
|
+
const variantOverlayPngs = await buildOverlayPngsForImport({
|
|
399
|
+
argoDir: '.argo',
|
|
400
|
+
demoName: variantSubdir,
|
|
401
|
+
manifestPath,
|
|
402
|
+
placements: variantPlacements,
|
|
403
|
+
videoWidth: variant.video.width,
|
|
404
|
+
videoHeight: variant.video.height,
|
|
405
|
+
deviceScaleFactor: config.video.deviceScaleFactor,
|
|
406
|
+
});
|
|
385
407
|
const variantOutputPath = await exportVideo({
|
|
386
408
|
demoName: variantSubdir,
|
|
387
409
|
argoDir: '.argo',
|
|
@@ -402,6 +424,7 @@ export async function runPipeline(demoName, config, pipelineOpts) {
|
|
|
402
424
|
cameraMoves: variantCameraMoves.length > 0 ? variantCameraMoves : undefined,
|
|
403
425
|
watermark: config.export.watermark,
|
|
404
426
|
freezeSpecs: variantResolvedFreezes.length > 0 ? variantResolvedFreezes : undefined,
|
|
427
|
+
overlayPngs: variantOverlayPngs,
|
|
405
428
|
});
|
|
406
429
|
console.log(`🚀 Variant saved to: ${variantOutputPath}`);
|
|
407
430
|
}
|