@agent-foundry/replay-server 1.0.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.
@@ -0,0 +1,392 @@
1
+ /**
2
+ * Puppeteer-based Video Renderer
3
+ *
4
+ * This renderer:
5
+ * 1. Launches a headless browser
6
+ * 2. Opens the game at a special replay URL
7
+ * 3. Injects the replay manifest
8
+ * 4. Captures screenshots as JPEG buffers and streams directly to FFmpeg via stdin
9
+ * 5. Encodes video using libx264 (CPU) by default, or h264_nvenc if explicitly enabled
10
+ */
11
+ import puppeteer from 'puppeteer';
12
+ import { spawn } from 'child_process';
13
+ const DEFAULT_CONFIG = {
14
+ width: 720,
15
+ height: 1280,
16
+ fps: 16,
17
+ secondsPerAge: 1.2,
18
+ keepTempFiles: false,
19
+ useHardwareAcceleration: false, // Default to CPU encoding
20
+ };
21
+ export class PuppeteerRenderer {
22
+ browser = null;
23
+ page = null;
24
+ pageErrors = [];
25
+ failedRequests = [];
26
+ /**
27
+ * Render a replay manifest to video
28
+ */
29
+ async render(manifest, config) {
30
+ const startTime = Date.now();
31
+ const fullConfig = {
32
+ ...DEFAULT_CONFIG,
33
+ gameUrl: config.gameUrl,
34
+ outputPath: config.outputPath,
35
+ width: config.width ?? DEFAULT_CONFIG.width,
36
+ height: config.height ?? DEFAULT_CONFIG.height,
37
+ fps: config.fps ?? DEFAULT_CONFIG.fps,
38
+ secondsPerAge: config.secondsPerAge ?? DEFAULT_CONFIG.secondsPerAge,
39
+ useHardwareAcceleration: config.useHardwareAcceleration ?? DEFAULT_CONFIG.useHardwareAcceleration,
40
+ onProgress: config.onProgress,
41
+ };
42
+ try {
43
+ // Initialize browser
44
+ this.reportProgress(config.onProgress, 'init', 0, 1, 'Launching browser...');
45
+ await this.initBrowser(fullConfig);
46
+ // Navigate to game
47
+ this.reportProgress(config.onProgress, 'init', 0, 1, 'Loading game...');
48
+ await this.loadGame(fullConfig.gameUrl, manifest);
49
+ // Capture and encode frames in streaming mode
50
+ const frameCount = manifest.timeline.length * fullConfig.secondsPerAge * fullConfig.fps;
51
+ this.reportProgress(config.onProgress, 'capture', 0, frameCount, 'Starting capture & encode...');
52
+ await this.captureAndEncodeFrames(manifest, fullConfig, config.onProgress);
53
+ const duration = (Date.now() - startTime) / 1000;
54
+ this.reportProgress(config.onProgress, 'complete', 1, 1, `Completed in ${duration.toFixed(1)}s`);
55
+ return {
56
+ success: true,
57
+ outputPath: fullConfig.outputPath,
58
+ duration,
59
+ };
60
+ }
61
+ catch (error) {
62
+ const errorMessage = error instanceof Error ? error.message : String(error);
63
+ this.reportProgress(config.onProgress, 'error', 0, 1, errorMessage);
64
+ return {
65
+ success: false,
66
+ error: errorMessage,
67
+ };
68
+ }
69
+ finally {
70
+ await this.closeBrowser();
71
+ }
72
+ }
73
+ async initBrowser(config) {
74
+ this.browser = await puppeteer.launch({
75
+ executablePath: process.env.PUPPETEER_EXECUTABLE_PATH || '/usr/bin/chromium',
76
+ headless: true,
77
+ timeout: 120_000, // 2 minutes for cold starts
78
+ dumpio: true, // CRITICAL: logs chromium stderr/stdout
79
+ args: [
80
+ '--no-sandbox',
81
+ '--disable-setuid-sandbox',
82
+ '--disable-dev-shm-usage', // /dev/shm is small in containers
83
+ '--no-zygote', // no zygote process in containers
84
+ '--single-process', // safer in containerized environments
85
+ '--disable-gpu',
86
+ '--disable-software-rasterizer',
87
+ '--disable-background-networking',
88
+ '--disable-default-apps',
89
+ '--disable-extensions',
90
+ '--disable-sync',
91
+ '--disable-translate',
92
+ '--metrics-recording-only',
93
+ '--mute-audio',
94
+ '--no-first-run',
95
+ '--safebrowsing-disable-auto-update',
96
+ `--window-size=${config.width},${config.height}`,
97
+ ],
98
+ });
99
+ this.page = await this.browser.newPage();
100
+ await this.page.setViewport({
101
+ width: config.width,
102
+ height: config.height,
103
+ deviceScaleFactor: 1,
104
+ });
105
+ // Set up error tracking
106
+ this.pageErrors = [];
107
+ this.failedRequests = [];
108
+ this.page.on('pageerror', (error) => {
109
+ this.pageErrors.push(error.message);
110
+ console.error('📼 Page error:', error.message);
111
+ });
112
+ this.page.on('requestfailed', (request) => {
113
+ const failure = request.failure();
114
+ this.failedRequests.push({
115
+ url: request.url(),
116
+ errorText: failure?.errorText,
117
+ });
118
+ console.error('📼 Request failed:', request.url(), failure?.errorText);
119
+ });
120
+ }
121
+ async loadGame(gameUrl, manifest) {
122
+ if (!this.page)
123
+ throw new Error('Browser not initialized');
124
+ // Navigate to game with replay mode query parameter
125
+ const url = new URL(gameUrl);
126
+ url.searchParams.set('mode', 'replay');
127
+ console.log(`📼 Navigating to ${url.toString()}`);
128
+ await this.page.goto(url.toString(), {
129
+ waitUntil: 'networkidle0',
130
+ timeout: 30000,
131
+ });
132
+ console.log('📼 Page loaded, waiting for React to initialize...');
133
+ // Wait for React to initialize (check for the app container)
134
+ try {
135
+ await this.page.waitForFunction(() => {
136
+ // Wait for the app to be mounted and initial loading to complete
137
+ const app = document.querySelector('ion-app');
138
+ const loading = document.querySelector('ion-spinner');
139
+ return app !== null && loading === null;
140
+ }, { timeout: 15000 });
141
+ }
142
+ catch (error) {
143
+ // Log errors before failing
144
+ if (this.pageErrors.length > 0) {
145
+ console.error('📼 Page errors detected:', this.pageErrors);
146
+ }
147
+ if (this.failedRequests.length > 0) {
148
+ console.error('📼 Failed requests:', this.failedRequests);
149
+ }
150
+ throw error;
151
+ }
152
+ // Log any errors that occurred (but didn't prevent initialization)
153
+ if (this.pageErrors.length > 0) {
154
+ console.warn('📼 Page errors detected (non-fatal):', this.pageErrors);
155
+ }
156
+ if (this.failedRequests.length > 0) {
157
+ console.warn('📼 Failed requests (non-fatal):', this.failedRequests);
158
+ }
159
+ console.log('📼 React initialized, injecting manifest...');
160
+ // Inject the replay manifest with retry logic
161
+ const maxRetries = 3;
162
+ let retryCount = 0;
163
+ let success = false;
164
+ while (retryCount < maxRetries && !success) {
165
+ // Inject the replay manifest
166
+ await this.page.evaluate((manifestJson) => {
167
+ // Store manifest in window for the game to read
168
+ window.__REPLAY_MANIFEST__ = JSON.parse(manifestJson);
169
+ console.log('📼 Manifest injected, dispatching event...');
170
+ // Dispatch event to notify the game
171
+ window.dispatchEvent(new CustomEvent('replay-manifest-loaded', {
172
+ detail: JSON.parse(manifestJson)
173
+ }));
174
+ }, JSON.stringify(manifest));
175
+ // Wait for the replay ready indicator
176
+ try {
177
+ await this.page.waitForSelector('[data-replay-ready="true"]', {
178
+ timeout: 5000,
179
+ });
180
+ success = true;
181
+ console.log('📼 Replay mode ready!');
182
+ }
183
+ catch {
184
+ retryCount++;
185
+ console.log(`📼 Retry ${retryCount}/${maxRetries}: Waiting for replay ready...`);
186
+ if (retryCount < maxRetries) {
187
+ // Small delay before retry
188
+ await new Promise(resolve => setTimeout(resolve, 500));
189
+ }
190
+ }
191
+ }
192
+ if (!success) {
193
+ console.warn('📼 Warning: Could not confirm replay ready state, proceeding anyway...');
194
+ // Give the app a bit more time to process
195
+ await new Promise(resolve => setTimeout(resolve, 2000));
196
+ }
197
+ // Additional wait for UI to stabilize
198
+ await new Promise(resolve => setTimeout(resolve, 500));
199
+ }
200
+ /**
201
+ * Capture frames and encode video in streaming mode using FFmpeg stdin
202
+ * Frames are captured as JPEG buffers and streamed directly to FFmpeg
203
+ */
204
+ async captureAndEncodeFrames(manifest, config, onProgress) {
205
+ // Use encoder based on configuration
206
+ const encoder = config.useHardwareAcceleration ? 'h264_nvenc' : 'libx264';
207
+ console.log(`📼 Using encoder: ${encoder} (Hardware acceleration: ${config.useHardwareAcceleration ? 'enabled' : 'disabled'})`);
208
+ await this.captureAndEncodeFramesWithEncoder(manifest, config, encoder, onProgress);
209
+ }
210
+ /**
211
+ * Internal method to capture and encode with a specific encoder
212
+ */
213
+ async captureAndEncodeFramesWithEncoder(manifest, config, encoder, onProgress) {
214
+ if (!this.page)
215
+ throw new Error('Browser not initialized');
216
+ const totalAges = manifest.timeline.length;
217
+ const framesPerAge = config.secondsPerAge * config.fps;
218
+ const totalFrames = totalAges * framesPerAge;
219
+ console.log(`📼 Using encoder: ${encoder}`);
220
+ // Launch FFmpeg process with stdin input
221
+ const ffmpeg = this.launchFFmpeg(encoder, config);
222
+ let frameIndex = 0;
223
+ let ffmpegStderr = '';
224
+ // Create promise for waiting FFmpeg completion
225
+ let ffmpegResolve = null;
226
+ let ffmpegReject = null;
227
+ let ffmpegClosed = false;
228
+ let encodingTimeout = null;
229
+ // Create promise that will be resolved when FFmpeg finishes
230
+ const encodingPromise = new Promise((resolve, reject) => {
231
+ ffmpegResolve = resolve;
232
+ ffmpegReject = reject;
233
+ // Set timeout to prevent hanging (5 minutes should be enough for encoding)
234
+ encodingTimeout = setTimeout(() => {
235
+ if (!ffmpegClosed) {
236
+ ffmpegClosed = true;
237
+ const timeoutError = new Error(`FFmpeg encoding timeout after 5 minutes. Process may be stuck.`);
238
+ reject(timeoutError);
239
+ // Force kill if still running
240
+ if (ffmpeg && !ffmpeg.killed) {
241
+ ffmpeg.kill('SIGKILL');
242
+ }
243
+ }
244
+ }, 5 * 60 * 1000); // 5 minutes timeout
245
+ });
246
+ // Handle FFmpeg stderr output (for logging and debugging)
247
+ ffmpeg.stderr?.on('data', (data) => {
248
+ const output = data.toString();
249
+ ffmpegStderr += output;
250
+ });
251
+ // Handle FFmpeg process errors
252
+ ffmpeg.on('error', (err) => {
253
+ if (ffmpegReject && !ffmpegClosed) {
254
+ ffmpegClosed = true;
255
+ if (encodingTimeout)
256
+ clearTimeout(encodingTimeout);
257
+ ffmpegReject(new Error(`Failed to start FFmpeg: ${err.message}`));
258
+ }
259
+ });
260
+ // Set up close event handler BEFORE starting capture
261
+ ffmpeg.on('close', (code) => {
262
+ if (ffmpegClosed)
263
+ return; // Prevent multiple calls
264
+ ffmpegClosed = true;
265
+ if (encodingTimeout) {
266
+ clearTimeout(encodingTimeout);
267
+ }
268
+ if (code === 0) {
269
+ if (ffmpegResolve) {
270
+ ffmpegResolve();
271
+ }
272
+ }
273
+ else {
274
+ const error = new Error(`FFmpeg exited with code ${code}. Stderr: ${ffmpegStderr}`);
275
+ if (ffmpegReject) {
276
+ ffmpegReject(error);
277
+ }
278
+ }
279
+ });
280
+ // Wait for FFmpeg stdin to be ready
281
+ if (!ffmpeg.stdin) {
282
+ throw new Error('FFmpeg stdin not available');
283
+ }
284
+ try {
285
+ // Capture and stream frames
286
+ for (let ageIndex = 0; ageIndex < totalAges; ageIndex++) {
287
+ // Advance to next age in the game
288
+ await this.page.evaluate(() => {
289
+ window.dispatchEvent(new CustomEvent('replay-next-age'));
290
+ });
291
+ // Wait a bit for animation
292
+ await new Promise(resolve => setTimeout(resolve, 100));
293
+ // Capture frames for this age
294
+ for (let f = 0; f < framesPerAge; f++) {
295
+ // Check if FFmpeg process has closed unexpectedly
296
+ if (ffmpegClosed) {
297
+ throw new Error('FFmpeg process closed unexpectedly');
298
+ }
299
+ // Capture screenshot as JPEG buffer
300
+ const screenshotBuffer = await this.page.screenshot({
301
+ type: 'jpeg',
302
+ quality: 85,
303
+ encoding: 'binary',
304
+ });
305
+ // Write frame to FFmpeg stdin
306
+ if (ffmpeg.stdin && !ffmpeg.stdin.destroyed) {
307
+ const writeSuccess = ffmpeg.stdin.write(screenshotBuffer);
308
+ if (!writeSuccess) {
309
+ // Wait for drain event if buffer is full
310
+ await new Promise((resolve) => {
311
+ if (ffmpeg.stdin) {
312
+ ffmpeg.stdin.once('drain', resolve);
313
+ }
314
+ else {
315
+ resolve();
316
+ }
317
+ });
318
+ }
319
+ }
320
+ frameIndex++;
321
+ // Update progress
322
+ if (frameIndex % config.fps === 0) {
323
+ this.reportProgress(onProgress, 'capture', frameIndex, totalFrames, `Capturing & encoding frame ${frameIndex}/${totalFrames} (${encoder})`);
324
+ }
325
+ // Small delay between frames
326
+ await new Promise(resolve => setTimeout(resolve, 1000 / config.fps / 2));
327
+ }
328
+ }
329
+ // Close stdin to signal end of input
330
+ if (ffmpeg.stdin && !ffmpeg.stdin.destroyed) {
331
+ ffmpeg.stdin.end();
332
+ }
333
+ // Wait for FFmpeg to finish encoding
334
+ // The promise was created earlier with event handlers already set up
335
+ await encodingPromise;
336
+ }
337
+ catch (error) {
338
+ // Cleanup on error
339
+ if (!ffmpegClosed) {
340
+ ffmpegClosed = true;
341
+ if (encodingTimeout) {
342
+ clearTimeout(encodingTimeout);
343
+ }
344
+ if (ffmpeg.stdin && !ffmpeg.stdin.destroyed) {
345
+ ffmpeg.stdin.destroy();
346
+ }
347
+ if (ffmpeg && !ffmpeg.killed) {
348
+ ffmpeg.kill('SIGKILL');
349
+ }
350
+ }
351
+ throw error;
352
+ }
353
+ }
354
+ /**
355
+ * Launch FFmpeg process with appropriate parameters
356
+ */
357
+ launchFFmpeg(encoder, config) {
358
+ const args = [
359
+ '-y', // Overwrite output
360
+ '-f', 'image2pipe', // Read from stdin
361
+ '-vcodec', 'mjpeg', // Input format: JPEG
362
+ '-r', String(config.fps), // Input framerate
363
+ '-i', '-', // Read from stdin
364
+ '-c:v', encoder, // Video encoder
365
+ '-preset', 'fast', // Encoding preset
366
+ '-crf', '28', // Constant Rate Factor (higher = smaller file, lower quality)
367
+ '-pix_fmt', 'yuv420p', // Pixel format for compatibility
368
+ '-r', String(config.fps), // Output framerate
369
+ '-movflags', '+faststart', // Enable fast start for web playback
370
+ config.outputPath,
371
+ ];
372
+ // Add NVENC-specific parameters if using hardware encoder
373
+ if (encoder === 'h264_nvenc') {
374
+ // Insert NVENC-specific options before output path
375
+ args.splice(args.length - 1, 0, '-rc', 'vbr', '-cq', '28');
376
+ }
377
+ return spawn('ffmpeg', args);
378
+ }
379
+ async closeBrowser() {
380
+ if (this.browser) {
381
+ await this.browser.close();
382
+ this.browser = null;
383
+ this.page = null;
384
+ }
385
+ }
386
+ reportProgress(callback, stage, current, total, message) {
387
+ if (callback) {
388
+ callback({ stage, current, total, message });
389
+ }
390
+ }
391
+ }
392
+ //# sourceMappingURL=PuppeteerRenderer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PuppeteerRenderer.js","sourceRoot":"","sources":["../../src/renderer/PuppeteerRenderer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export * from './PuppeteerRenderer.js';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/renderer/index.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export * from './PuppeteerRenderer.js';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/renderer/index.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAC"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Replay Render Server
3
+ *
4
+ * HTTP API for rendering replays to video
5
+ *
6
+ * Endpoints:
7
+ * - POST /render - Start a render job
8
+ * - GET /jobs - List all jobs
9
+ * - GET /status/:jobId - Get job status
10
+ * - GET /download/:jobId - Download completed video
11
+ * - GET /bundles - List available game bundles
12
+ */
13
+ export {};
14
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG"}