// Оптимизация скриншотов для сайта: PNG (2880×1800 @2x) → WebP с ресайзом и srcset. // Без внешних зависимостей (sharp/cwebp недоступны на dev-vm) — кодируем через // canvas.toDataURL('image/webp') в headless-Chromium (Playwright уже установлен). // // Для каждого исходного PNG из public/screenshots делает: // .webp — 1440w (служит 2x для ~720px-слота), качество 0.86 // @2x.webp — 2880w (для srcset на крупных экранах), качество 0.82 // Все файлы ≤ 300 КБ (UI-скриншоты сжимаются отлично). // // Запуск: node scripts/optimize-screenshots.mjs import { chromium } from 'playwright' import path from 'node:path' import fs from 'node:fs' import { fileURLToPath, pathToFileURL } from 'node:url' const __dirname = path.dirname(fileURLToPath(import.meta.url)) const DIR = path.resolve(__dirname, '..', 'public', 'screenshots') const CHROME = process.env.CHROME ?? '/usr/bin/google-chrome' const pngs = fs.readdirSync(DIR).filter((f) => f.endsWith('.png')) const browser = await chromium.launch({ headless: true, executablePath: CHROME, args: ['--no-sandbox', '--disable-dev-shm-usage'], }) const page = await browser.newPage() async function encode(srcPng, outName, targetW, quality) { const dataUrl = 'data:image/png;base64,' + fs.readFileSync(path.join(DIR, srcPng)).toString('base64') const b64 = await page.evaluate(async ({ url, targetW, quality }) => { const img = new Image() await new Promise((res, rej) => { img.onload = res; img.onerror = rej; img.src = url }) const scale = Math.min(1, targetW / img.naturalWidth) const w = Math.round(img.naturalWidth * scale) const h = Math.round(img.naturalHeight * scale) const c = document.createElement('canvas') c.width = w; c.height = h const ctx = c.getContext('2d') ctx.imageSmoothingEnabled = true ctx.imageSmoothingQuality = 'high' ctx.drawImage(img, 0, 0, w, h) return c.toDataURL('image/webp', quality).split(',')[1] }, { url: dataUrl, targetW, quality }) const buf = Buffer.from(b64, 'base64') fs.writeFileSync(path.join(DIR, outName), buf) return buf.length } for (const png of pngs) { const base = png.replace(/\.png$/, '') const s1 = await encode(png, `${base}.webp`, 1440, 0.86) const s2 = await encode(png, `${base}@2x.webp`, 2880, 0.82) const kb = (n) => (n / 1024).toFixed(0) + 'KB' const warn = (s1 > 300 * 1024 || s2 > 300 * 1024) ? ' ⚠ >300KB' : '' console.log(`${base}: 1x ${kb(s1)}, 2x ${kb(s2)}${warn}`) } await browser.close() console.log('done')