Dee Ferdinand commited on
Commit
d3cc583
·
1 Parent(s): 5a4b7f7

fix: correct hyperframes CLI — render <dir> -o <output>, PRODUCER_HEADLESS_SHELL_PATH for Chrome, workers=1 for cpu-basic

Browse files
Files changed (1) hide show
  1. lib/renderer.js +45 -29
lib/renderer.js CHANGED
@@ -7,38 +7,48 @@ export async function renderVideo(compDir, outputFile, config, onProgress) {
7
  const [w, h] = format === '9:16' ? [1080, 1920] : format === '1:1' ? [1080, 1080] : [1920, 1080];
8
  onProgress?.(0);
9
 
10
- // meta.json tells HyperFrames the canvas size and duration
11
  fs.writeFileSync(path.join(compDir, 'meta.json'), JSON.stringify(
12
  { duration, width: w, height: h, fps: 30 }, null, 2
13
  ));
14
 
 
15
  const chromePath = [
16
  process.env.PUPPETEER_EXECUTABLE_PATH,
17
  process.env.CHROME_PATH,
18
  '/usr/bin/chromium',
19
  '/usr/bin/chromium-browser',
20
  '/usr/bin/google-chrome',
21
- ].find(p => p && fs.existsSync(p));
22
 
23
- console.log(`[renderer] Chrome: ${chromePath} | ${w}x${h} | ${duration}s | cwd: ${compDir}`);
24
 
25
- // Run from INSIDE compDir using relative paths
26
- // CLI: npx hyperframes render ./index.html -o ./output.mp4
27
- const localOutput = './render_out.mp4';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
 
29
  return new Promise((resolve, reject) => {
30
- const proc = execFile(
31
- 'npx', ['hyperframes', 'render', './index.html', '-o', localOutput],
32
- {
33
- cwd: compDir, // <-- run from inside the project directory
34
- maxBuffer: 500 * 1024 * 1024,
35
- env: {
36
- ...process.env,
37
- PUPPETEER_EXECUTABLE_PATH: chromePath || '/usr/bin/chromium',
38
- CHROME_PATH: chromePath || '/usr/bin/chromium',
39
- },
40
- }
41
- );
42
 
43
  let stderr = '';
44
  proc.stdout?.on('data', (d) => {
@@ -47,20 +57,26 @@ export async function renderVideo(compDir, outputFile, config, onProgress) {
47
  const m = line.match(/frame\s+(\d+)\/(\d+)/i);
48
  if (m) onProgress?.(parseInt(m[1]) / parseInt(m[2]));
49
  });
50
- proc.stderr?.on('data', (d) => { stderr += d; process.stderr.write(d); });
51
- proc.on('close', async (code) => {
52
- if (code !== 0) {
53
- reject(new Error(`HyperFrames render failed:\n${stderr.slice(-800)}`));
54
- return;
55
- }
56
- // Move output to final destination
57
- const rendered = path.join(compDir, 'render_out.mp4');
58
- if (fs.existsSync(rendered)) {
59
- fs.renameSync(rendered, outputFile);
60
  onProgress?.(1);
61
  resolve(outputFile);
 
 
 
 
 
 
 
 
 
 
62
  } else {
63
- reject(new Error('Render completed but output file not found'));
64
  }
65
  });
66
  });
 
7
  const [w, h] = format === '9:16' ? [1080, 1920] : format === '1:1' ? [1080, 1080] : [1920, 1080];
8
  onProgress?.(0);
9
 
10
+ // meta.json HyperFrames reads width/height/fps/duration from here
11
  fs.writeFileSync(path.join(compDir, 'meta.json'), JSON.stringify(
12
  { duration, width: w, height: h, fps: 30 }, null, 2
13
  ));
14
 
15
+ // Find Chrome for Docker
16
  const chromePath = [
17
  process.env.PUPPETEER_EXECUTABLE_PATH,
18
  process.env.CHROME_PATH,
19
  '/usr/bin/chromium',
20
  '/usr/bin/chromium-browser',
21
  '/usr/bin/google-chrome',
22
+ ].find(p => p && fs.existsSync(p)) || '/usr/bin/chromium';
23
 
24
+ console.log(`[renderer] ${w}x${h} ${duration}s | chrome=${chromePath} | dir=${compDir}`);
25
 
26
+ // Correct CLI: npx hyperframes render <dir> -o <output.mp4>
27
+ // dir is the project directory containing index.html
28
+ // -w 1 = 1 worker (cpu-basic has limited RAM, avoid spawning multiple Chromes)
29
+ const args = [
30
+ 'hyperframes', 'render',
31
+ compDir, // positional: project directory
32
+ '-o', outputFile, // output path
33
+ '-w', '1', // 1 worker for cpu-basic
34
+ '--fps', '30',
35
+ '--quality', 'standard',
36
+ ];
37
+
38
+ const env = {
39
+ ...process.env,
40
+ // HyperFrames uses PRODUCER_HEADLESS_SHELL_PATH for the Chrome path
41
+ PRODUCER_HEADLESS_SHELL_PATH: chromePath,
42
+ PUPPETEER_EXECUTABLE_PATH: chromePath,
43
+ CHROME_PATH: chromePath,
44
+ };
45
 
46
  return new Promise((resolve, reject) => {
47
+ const proc = execFile('npx', args, {
48
+ cwd: compDir,
49
+ maxBuffer: 500 * 1024 * 1024,
50
+ env,
51
+ });
 
 
 
 
 
 
 
52
 
53
  let stderr = '';
54
  proc.stdout?.on('data', (d) => {
 
57
  const m = line.match(/frame\s+(\d+)\/(\d+)/i);
58
  if (m) onProgress?.(parseInt(m[1]) / parseInt(m[2]));
59
  });
60
+ proc.stderr?.on('data', (d) => {
61
+ stderr += d.toString();
62
+ process.stderr.write(d);
63
+ });
64
+ proc.on('close', (code) => {
65
+ if (code === 0 && fs.existsSync(outputFile)) {
 
 
 
 
66
  onProgress?.(1);
67
  resolve(outputFile);
68
+ } else if (code === 0) {
69
+ // HyperFrames may output to renders/ subdir by default
70
+ const defaultOut = path.join(compDir, 'renders', 'index.mp4');
71
+ if (fs.existsSync(defaultOut)) {
72
+ fs.renameSync(defaultOut, outputFile);
73
+ onProgress?.(1);
74
+ resolve(outputFile);
75
+ } else {
76
+ reject(new Error('Render completed but output MP4 not found'));
77
+ }
78
  } else {
79
+ reject(new Error(`HyperFrames render failed (exit ${code}):\n${stderr.slice(-1000)}`));
80
  }
81
  });
82
  });