/** * 🤖 简洁科技感头像 PNG 批量生成(DiceBear bottts-neutral 机器人中性) * 从资源库读取风格定义,seed 确定性渲染;黑灰机器人反白成线框感, * 配深蓝渐变圆形底 + 细亮蓝圆环,Chrome headless 导出 1024×1024 PNG。 * * 用法:node scripts/gen-tech-avatars-png.js */ 'use strict'; const fs = require('fs'); const path = require('path'); const vm = require('vm'); const { execFileSync } = require('child_process'); const ROOT = path.resolve(__dirname, '..'); const OUT_DIR = path.join(ROOT, 'output', 'agent-avatars-png'); const TMP_DIR = path.join(ROOT, 'output', '.tmp-tech'); const CHROME = 'C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe'; // —— 1. 加载资源库风格定义 + 渲染引擎 —— global.window = global; const styleFile = path.join(ROOT, 'js', 'data', 'sources', 'dicebear-bottts-neutral.js'); vm.runInThisContext(fs.readFileSync(styleFile, 'utf8'), { filename: styleFile }); vm.runInThisContext(fs.readFileSync(path.join(ROOT, 'js', 'core', 'dicebear.js'), 'utf8'), { filename: 'dicebear.js' }); // —— 2. 渲染 10 个 seed,反白(黑→白线框感),剥离 svg 外壳取 inner —— const COUNT = 10; const S = 120; // bottts-neutral 画布 120 const ZOOM = 5.4; // 放大到 ~648px const BG_FROM = '#0b1220', BG_TO = '#16294a'; // 深蓝科技渐变 const RING = '#3b82f6'; // 亮蓝圆环 function renderInner(seed) { const { svg } = HGB_Dicebear.renderAvatar('bottts-neutral', seed); const inner = svg.replace(/^<\?xml[^>]*\?>\s*]*>/, '').replace(/<\/svg>\s*$/, ''); return inner.replace(/fill="black"/g, 'fill="white"'); // 反白 } function buildHtml(inner) { return ` ${inner} `; } // —— 3. 导出 PNG —— fs.mkdirSync(OUT_DIR, { recursive: true }); fs.mkdirSync(TMP_DIR, { recursive: true }); for (let i = 1; i <= COUNT; i++) { const idx = String(i).padStart(2, '0'); const htmlFile = path.join(TMP_DIR, `avatar-${idx}.html`); const pngFile = path.join(OUT_DIR, `agent-${idx}.png`); fs.writeFileSync(htmlFile, buildHtml(renderInner('agent-' + i)), 'utf8'); try { execFileSync(CHROME, [ '--headless=new', '--disable-gpu', '--hide-scrollbars', '--force-device-scale-factor=1', '--default-background-color=00000000', '--window-size=1024,1024', '--virtual-time-budget=1000', `--screenshot=${pngFile}`, 'file:///' + htmlFile.replace(/\\/g, '/') ], { stdio: 'pipe' }); console.log(`✅ agent-${idx}.png seed=agent-${i}`); } catch (e) { console.error(`❌ agent-${idx}.png 失败:`, e.message.split('\n')[0]); } } fs.rmSync(TMP_DIR, { recursive: true, force: true }); console.log('\n🎉 完成 → output/agent-avatars-png/');