import {chromium} from 'playwright';import fs from 'node:fs/promises';import path from 'node:path';import os from 'node:os';import {spawn} from 'node:child_process';
const url=process.env.APP_URL||'http://127.0.0.1:4318';const out=path.resolve(process.env.EXPORTS_DIR||'../../exports');const frames=await fs.mkdtemp(path.join(os.tmpdir(),'inside-machine-frames-'));await fs.mkdir(out,{recursive:true});
const started=new Date(),t0=performance.now();const browser=await chromium.launch({channel:'chrome',headless:true,args:['--enable-webgl','--ignore-gpu-blocklist']});
try{
 const page=await browser.newPage({viewport:{width:1440,height:1000},deviceScaleFactor:1});await page.goto(url+'/?capture=1');await page.waitForFunction(()=>!!window.engineExhibit);
 await page.evaluate(()=>window.engineExhibit.setState({angle:35,selected:1,view:'section',playing:false}));await page.screenshot({path:path.join(out,'desktop-section.png'),fullPage:true});
 await page.setViewportSize({width:390,height:844});await page.screenshot({path:path.join(out,'phone-section.png'),fullPage:true});await page.setViewportSize({width:1440,height:1000});
 await page.evaluate(()=>window.engineExhibit.setState({angle:35,selected:1,view:'section',playing:false}));const glb=await page.evaluate(()=>window.engineExhibit.exportGLTF());await fs.writeFile(path.join(out,'v8-section-static.glb'),Buffer.from(glb));
 await page.evaluate(()=>window.engineExhibit.setState({angle:35,selected:1,view:'assembled',playing:false}));await page.waitForFunction(()=>document.querySelector('[role=tab][aria-selected=true]')?.textContent==='Assembled');await page.screenshot({path:path.join(out,'desktop-assembled.png')});
 const captureStart=performance.now();
 for(let f=0;f<540;f++){
  await page.evaluate(async time=>{window.engineExhibit.seekTour(time);await new Promise(r=>requestAnimationFrame(()=>requestAnimationFrame(r)));},f/30);
  await page.screenshot({path:path.join(frames,String(f).padStart(5,'0')+'.png')});
  if(f%90===0){console.log(`Captured frame ${f}/540 (${(f/30).toFixed(0)} seconds)`);if(f>0)await page.screenshot({path:path.join(out,`tour-${f/30}s.png`)});}
 }
 const captured=performance.now();await browser.close();
 await new Promise((resolve,reject)=>{const p=spawn('ffmpeg',['-y','-loglevel','warning','-framerate','30','-i',path.join(frames,'%05d.png'),'-frames:v','540','-c:v','libx264','-preset','medium','-crf','20','-pix_fmt','yuv420p','-movflags','+faststart',path.join(out,'inside-the-machine-demo.mp4')],{stdio:'inherit'});p.on('exit',c=>c===0?resolve():reject(Error(`FFmpeg exited ${c}`)));});
 const done=performance.now();await fs.writeFile(path.join(out,'capture-record.json'),JSON.stringify({startedUtc:started.toISOString(),endedUtc:new Date().toISOString(),browser:browser.version(),width:1440,height:1000,fps:30,frames:540,durationSeconds:18,captureSeconds:(captured-captureStart)/1000,encodeSeconds:(done-captured)/1000,totalSeconds:(done-t0)/1000,audio:'none',method:'Deterministic screenshots of actual browser app via shared tourState, encoded by FFmpeg'},null,2));
 console.log(`Done: ${out}`);
}finally{await browser.close();await fs.rm(frames,{recursive:true,force:true});}
