#!/usr/bin/env node /** * Scroll-driven animation capture * Interpolates scrollProgress from 0 to 1 across frames */ import puppeteer from 'puppeteer'; import { execSync } from 'child_process'; import path from 'path'; import { fileURLToPath } from 'url'; import fs from 'fs'; const __dirname = path.dirname(fileURLToPath(import.meta.url)); const outputDir = path.join(__dirname, 'output/scroll-frames'); const htmlFile = path.join(__dirname, 'output/stripe-scroll.html'); // Clean and create output dir fs.rmSync(outputDir, { recursive: true, force: true }); fs.mkdirSync(outputDir, { recursive: true }); async function captureFrames() { const browser = await puppeteer.launch({ headless: true, executablePath: '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome', args: ['--no-sandbox'] }); const page = await browser.newPage(); await page.setViewport({ width: 1920, height: 1080 }); // 12 seconds at 30fps = 360 frames const fps = 30; const duration = 12; const totalFrames = fps * duration; console.log(`Capturing ${totalFrames} frames...`); // Load page and wait for fonts await page.goto(`file://${htmlFile}`, { waitUntil: 'networkidle0' }); await new Promise(r => setTimeout(r, 500)); for (let i = 0; i < totalFrames; i++) { // Calculate scroll progress (0 to 1) // Add a small ease to the overall progression for smoother feel const linearProgress = i / (totalFrames - 1); const scrollProgress = linearProgress; // Keep linear for now, easing is in the HTML // Update the scene await page.evaluate((progress) => { window.updateScene(progress); }, scrollProgress); // Small delay to let CSS transitions settle await new Promise(r => setTimeout(r, 16)); const frameNum = String(i + 1).padStart(4, '0'); await page.screenshot({ path: path.join(outputDir, `frame-${frameNum}.png`), type: 'png' }); if (i % 30 === 0) console.log(`Frame ${i + 1}/${totalFrames} (${Math.round(linearProgress * 100)}%)`); } await browser.close(); // Create MP4 console.log('Creating MP4...'); const mp4Path = path.join(__dirname, 'output/stripe-scroll.mp4'); try { execSync(`ffmpeg -y -framerate ${fps} -i "${outputDir}/frame-%04d.png" -c:v libx264 -pix_fmt yuv420p -crf 18 "${mp4Path}"`, { stdio: 'inherit' }); console.log(`\n✓ MP4 created: ${mp4Path}`); } catch (e) { console.error('FFmpeg error:', e.message); } } captureFrames().catch(console.error);