@hypersocial/decks-cli 0.9.4 → 0.9.5
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/package.json +1 -1
- package/src/export-video.mjs +4 -2
- package/src/preview-capture.mjs +37 -1
- package/src/runtime.mjs +1 -1
package/package.json
CHANGED
package/src/export-video.mjs
CHANGED
|
@@ -19,7 +19,7 @@ import { tmpdir } from 'node:os';
|
|
|
19
19
|
import { dirname, extname, join } from 'node:path';
|
|
20
20
|
import { execFile } from 'node:child_process';
|
|
21
21
|
import { promisify } from 'node:util';
|
|
22
|
-
import { allowCaptureDestination, installChromium, isMissingBrowser, routeCaptureRequest } from './preview-capture.mjs';
|
|
22
|
+
import { allowCaptureDestination, installChromium, isMissingBrowser, noteSoftwareWebgl, recorderArgs, routeCaptureRequest } from './preview-capture.mjs';
|
|
23
23
|
import { installFrameClock } from './frame-clock.mjs';
|
|
24
24
|
|
|
25
25
|
const run = promisify(execFile);
|
|
@@ -272,9 +272,11 @@ export async function recordVideo(config, { log = () => {}, chromium: injected,
|
|
|
272
272
|
browser = await launchRecorder(chromium, {
|
|
273
273
|
// config.sandbox: false only for CI runners whose AppArmor blocks Chromium's sandbox (the smoke suite).
|
|
274
274
|
headless: true, timeout: 30000, chromiumSandbox: config.sandbox ?? process.platform === 'linux',
|
|
275
|
-
|
|
275
|
+
// On a Mac the head is drawn on the graphics card (recorderArgs); elsewhere in software.
|
|
276
|
+
args: ['--autoplay-policy=no-user-gesture-required', '--mute-audio', ...recorderArgs()],
|
|
276
277
|
env: { ...(process.platform === 'win32' ? { SystemRoot: process.env.SystemRoot } : {}), PATH: process.env.PATH, TMPDIR: temp, HOME: temp },
|
|
277
278
|
}, { log, ...(install ? { install } : {}) });
|
|
279
|
+
await noteSoftwareWebgl(browser, log);
|
|
278
280
|
const pageUrl = exportPageUrl(config.url, config);
|
|
279
281
|
const context = await browser.newContext({ viewport: geometry.viewport, deviceScaleFactor: geometry.scale, serviceWorkers: 'block', acceptDownloads: false });
|
|
280
282
|
const blockedUrls = [];
|
package/src/preview-capture.mjs
CHANGED
|
@@ -22,6 +22,42 @@ export async function installChromium({ exec = run } = {}) {
|
|
|
22
22
|
}
|
|
23
23
|
// Playwright's launch error when the browser build is not on disk.
|
|
24
24
|
export const isMissingBrowser = (e) => /Executable doesn't exist/.test(String(e?.message ?? e));
|
|
25
|
+
// Chromium's WebGL flags for capture and video export. On a Mac, ANGLE's Metal
|
|
26
|
+
// backend draws WebGL (the live head) on the graphics card: the investor deck's
|
|
27
|
+
// 1080p export rendered in 7 min instead of 48 (docs/spikes/mac-video-export-gpu.md).
|
|
28
|
+
// Elsewhere (Linux, the render worker's GPU-less machines) WebGL stays in
|
|
29
|
+
// SwiftShader, on the CPU. --enable-unsafe-swiftshader is kept on every
|
|
30
|
+
// platform: it is what Chromium falls back to when it cannot use the GPU.
|
|
31
|
+
export function recorderArgs(platform = process.platform) {
|
|
32
|
+
return platform === 'darwin' ? ['--use-angle=metal', '--enable-unsafe-swiftshader'] : ['--enable-unsafe-swiftshader'];
|
|
33
|
+
}
|
|
34
|
+
// The WebGL renderer (UNMASKED_RENDERER_WEBGL) a launched browser draws with,
|
|
35
|
+
// or null when it cannot tell (no WebGL, or no answer within `ms`).
|
|
36
|
+
export async function webglRenderer(browser, ms = 10000) {
|
|
37
|
+
let page, timer;
|
|
38
|
+
try {
|
|
39
|
+
const read = (async () => {
|
|
40
|
+
page = await browser.newPage();
|
|
41
|
+
return page.evaluate(() => {
|
|
42
|
+
const gl = document.createElement('canvas').getContext('webgl');
|
|
43
|
+
const info = gl?.getExtension('WEBGL_debug_renderer_info');
|
|
44
|
+
return gl ? String(gl.getParameter(info ? info.UNMASKED_RENDERER_WEBGL : gl.RENDERER)) : null;
|
|
45
|
+
});
|
|
46
|
+
})();
|
|
47
|
+
read.catch(() => {});
|
|
48
|
+
return await Promise.race([read, new Promise((ok) => { timer = setTimeout(() => ok(null), ms); })]);
|
|
49
|
+
} catch { return null; }
|
|
50
|
+
finally { clearTimeout(timer); await page?.close().catch(() => {}); }
|
|
51
|
+
}
|
|
52
|
+
export const isSoftwareRenderer = (renderer) => /swiftshader/i.test(renderer ?? '');
|
|
53
|
+
// On a Mac, one line when Chromium could not use the graphics card and fell
|
|
54
|
+
// back to drawing WebGL in software. Returns the renderer it read.
|
|
55
|
+
export async function noteSoftwareWebgl(browser, log, platform = process.platform) {
|
|
56
|
+
if (platform !== 'darwin') return null;
|
|
57
|
+
const renderer = await webglRenderer(browser);
|
|
58
|
+
if (isSoftwareRenderer(renderer)) log('Chromium could not use this Mac\'s graphics card; the head is drawn in software, so the export runs several times slower');
|
|
59
|
+
return renderer;
|
|
60
|
+
}
|
|
25
61
|
export async function setupCapture(pos, opts) {
|
|
26
62
|
if (pos.length || Object.keys(opts).some(k => !['json', 'dev', 'convex', 'prod'].includes(k))) throw new Error('usage: preview setup');
|
|
27
63
|
await installChromium();
|
|
@@ -207,7 +243,7 @@ export async function capturePreview(config) {
|
|
|
207
243
|
try {
|
|
208
244
|
temp = await mkdtemp(join(tmpdir(), 'hyperdecks-preview-'));
|
|
209
245
|
try {
|
|
210
|
-
browser = await chromium.launch({ headless: true, timeout:30000, chromiumSandbox: process.platform === 'linux', args: ['--mute-audio',
|
|
246
|
+
browser = await chromium.launch({ headless: true, timeout:30000, chromiumSandbox: process.platform === 'linux', args: ['--mute-audio', ...recorderArgs()], env: { ...(process.platform === 'win32' ? { SystemRoot: process.env.SystemRoot } : {}), PATH: process.env.PATH, TMPDIR: temp, HOME: temp } });
|
|
211
247
|
} catch { throw new Error(`Could not launch isolated Chromium. ${SETUP}`); }
|
|
212
248
|
deadline = setTimeout(() => { timedOut = true; browser.close().catch(() => {}); }, 60000);
|
|
213
249
|
server = await serveSource(config);
|
package/src/runtime.mjs
CHANGED
|
@@ -8,7 +8,7 @@ import { fileURLToPath } from "node:url";
|
|
|
8
8
|
import { ConvexHttpClient } from "convex/browser";
|
|
9
9
|
import { makeFunctionReference } from "convex/server";
|
|
10
10
|
|
|
11
|
-
export const VERSION = "0.9.
|
|
11
|
+
export const VERSION = "0.9.5";
|
|
12
12
|
const UPLOAD_TIMEOUT_MS = 125_000;
|
|
13
13
|
|
|
14
14
|
export const PROD = {
|