UNPKG

@css-doodle/cli

Version:

Command-line tool for css-doodle to preview and generate images/videos

93 lines (76 loc) 2.7 kB
import process from 'node:process'; import { setTimeout } from 'node:timers/promises'; import { clearLine, style } from '../utils.js'; const defaultWindowWidth = 1200; const defaultWindowHeight = 800; const defaultScale = 1; // Delay after viewport resize to ensure rendering is complete const viewportSettleDelay = 200; // Delay when element has no size, waiting for content to render const elementRenderDelay = 1000; export async function screencast(page, options) { const { scale, output, selector, windowWidth, windowHeight, format } = options; const WIDTH = windowWidth || defaultWindowWidth; const HEIGHT = windowHeight || defaultWindowHeight; const SCALE = scale || defaultScale; await page.setViewport({ width: WIDTH, height: HEIGHT, deviceScaleFactor: SCALE, }); await setTimeout(viewportSettleDelay); const castOption = { scale: SCALE, format: format || 'mp4', path: output, }; const crop = await page.evaluate(async (selector) => { const element = document.querySelector(selector); if (element) { const rect = element.getBoundingClientRect(); if (rect.width === 0 || rect.height === 0) { await setTimeout(elementRenderDelay); } const { width, height, x, y } = element.getBoundingClientRect(); return { x, y, width, height: height || width, }; } }, selector); if (crop) { crop.x = Math.max(crop.x, 0) || 0; crop.y = Math.max(crop.y, 0) || 0; crop.width = Math.min(crop.width, WIDTH) || WIDTH; crop.height = Math.min(crop.height, HEIGHT) || HEIGHT; castOption.crop = crop; await page.setViewport({ width: Math.max(WIDTH, parseInt(crop.x + crop.width)), height: Math.max(HEIGHT, parseInt(crop.y + crop.height)), deviceScaleFactor: SCALE, }); } const totalSeconds = Math.ceil(options.time / 1000); const updateStatus = (remaining) => { if (!options.quiet) { clearLine(); process.stdout.write(style.green('●') + style.dim(` recording... (${remaining}s)`)); } }; updateStatus(totalSeconds); let remaining = totalSeconds; const interval = setInterval(() => { remaining--; updateStatus(remaining); }, 1000); const recorder = await page.screencast(castOption); await setTimeout(options.time); clearInterval(interval); await recorder.stop(); if (!options.quiet) { clearLine(); } return output; }