Dee Ferdinand commited on
Commit
b41b9bd
·
1 Parent(s): 10992d3

feat: init Dee Video Studio — HyperFrames cloud render for testimonial/teaser/trailer videos

Browse files

- 4 workflows: testimonial (75s), teaser (30s), trailer (60s), community (60s)
- 6 royalty-free Pixabay music tracks auto-selected by workflow
- WebSocket real-time render progress
- Dark-mode Studio UI with drag-drop upload
- HuggingFace Docker Space ready (port 7860)

Files changed (1) hide show
  1. lib/renderer.js +35 -0
lib/renderer.js ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { execFile } from 'child_process';
2
+ import { promisify } from 'util';
3
+ import path from 'path';
4
+ import fs from 'fs';
5
+
6
+ const execFileAsync = promisify(execFile);
7
+
8
+ export async function renderVideo(compDir, outputFile, config, onProgress) {
9
+ const { format = '9:16', duration = 75 } = config;
10
+ const [w, h] = format === '9:16' ? [1080, 1920] : format === '1:1' ? [1080, 1080] : [1920, 1080];
11
+ onProgress?.(0);
12
+
13
+ const meta = { duration, width: w, height: h, fps: 30 };
14
+ fs.writeFileSync(path.join(compDir, 'meta.json'), JSON.stringify(meta, null, 2));
15
+
16
+ return new Promise((resolve, reject) => {
17
+ const proc = execFile('npx', [
18
+ 'hyperframes', 'render',
19
+ '--output', outputFile,
20
+ '--width', String(w),
21
+ '--height', String(h),
22
+ '--fps', '30',
23
+ ], { cwd: compDir, maxBuffer: 500 * 1024 * 1024 });
24
+
25
+ proc.stdout?.on('data', (d) => {
26
+ const m = d.toString().match(/frame\s+(\d+)\/(\d+)/i);
27
+ if (m) onProgress?.(parseInt(m[1]) / parseInt(m[2]));
28
+ });
29
+ proc.stderr?.on('data', (d) => process.stderr.write(d));
30
+ proc.on('close', (code) => {
31
+ if (code === 0) { onProgress?.(1); resolve(outputFile); }
32
+ else reject(new Error(`HyperFrames exited with code ${code}`));
33
+ });
34
+ });
35
+ }