* Render key frames from a composition as PNG screenshots. * The agent can Read these to verify its output visually.
(
projectDir: string,
opts: {
frames?: number;
timeout?: number;
at?: number[];
outputDir?: string;
angle?: Camera;
includeEnd?: boolean;
},
)
| 182 | * The agent can Read these to verify its output visually. |
| 183 | */ |
| 184 | async function captureSnapshots( |
| 185 | projectDir: string, |
| 186 | opts: { |
| 187 | frames?: number; |
| 188 | timeout?: number; |
| 189 | at?: number[]; |
| 190 | outputDir?: string; |
| 191 | angle?: Camera; |
| 192 | includeEnd?: boolean; |
| 193 | }, |
| 194 | ): Promise<string[]> { |
| 195 | const { bundleToSingleHtml } = await import("@hyperframes/core/compiler"); |
| 196 | const { ensureBrowser } = await import("../browser/manager.js"); |
| 197 | |
| 198 | const numFrames = opts.frames ?? 5; |
| 199 | |
| 200 | const html = await bundleToSingleHtml(projectDir); |
| 201 | const server = await serveStaticProjectHtml(projectDir, html); |
| 202 | |
| 203 | const savedPaths: string[] = []; |
| 204 | |
| 205 | try { |
| 206 | const browser = await ensureBrowser(); |
| 207 | const puppeteer = await import("puppeteer-core"); |
| 208 | const chromeBrowser = await puppeteer.default.launch({ |
| 209 | headless: true, |
| 210 | executablePath: browser.executablePath, |
| 211 | args: [ |
| 212 | "--no-sandbox", |
| 213 | "--disable-gpu", |
| 214 | "--disable-dev-shm-usage", |
| 215 | "--enable-webgl", |
| 216 | "--use-gl=angle", |
| 217 | "--use-angle=swiftshader", |
| 218 | ], |
| 219 | }); |
| 220 | |
| 221 | try { |
| 222 | const page = await chromeBrowser.newPage(); |
| 223 | await page.setViewport(resolveCompositionViewportFromHtml(html)); |
| 224 | |
| 225 | await page.goto(server.url, { |
| 226 | waitUntil: "domcontentloaded", |
| 227 | timeout: 10000, |
| 228 | }); |
| 229 | |
| 230 | // __renderReady is set after the player is constructed AND the root |
| 231 | // timeline is bound — waiting for it guarantees renderSeek will work. |
| 232 | const timeoutMs = opts.timeout ?? 5000; |
| 233 | const runtimeReady = await page |
| 234 | .waitForFunction(() => !!(window as any).__renderReady, { timeout: timeoutMs }) |
| 235 | .then(() => true) |
| 236 | .catch(() => false); |
| 237 | |
| 238 | if (!runtimeReady) { |
| 239 | console.warn( |
| 240 | `\n ${c.warn("⚠")} Runtime did not become render-ready within ${timeoutMs}ms — snapshots may be inaccurate`, |
| 241 | ); |
no test coverage detected