feat: 初始化画个标仓库 - AI驱动设计系统(BYOK模式) - 224源/371504图标+25海报源+130技能

This commit is contained in:
sgp
2026-10-03 21:44:18 +08:00
commit 9e222877ea
497 changed files with 43611 additions and 0 deletions
+81
View File
@@ -0,0 +1,81 @@
/**
* 🎯 简洁科技感头像 PNG —— 从资源库直接挑 10 个 lucide 线性图标
* 10 个图标:bot / brain-circuit / cpu / sparkles / satellite / radar /
* circuit-board / atom / terminal / rocket
* 统一深蓝渐变圆底 + 白色线性图标 + 亮蓝细环,Chrome headless 导出 1024×1024 PNG。
*
* 用法:node scripts/gen-icon-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-icons');
const CHROME = 'C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe';
// —— 1. 加载资源库 lucide 源 ——
global.window = global;
const lucideFile = path.join(ROOT, 'js', 'data', 'sources', 'lucide.js');
vm.runInThisContext(fs.readFileSync(lucideFile, 'utf8'), { filename: lucideFile });
const lucideIcons = window['HGB_Source_lucide'].icons;
// —— 2. 挑选 10 个科技感图标(按名称匹配,保证存在)——
const PICK = ['bot', 'brain-circuit', 'cpu', 'sparkles', 'satellite', 'radar', 'circuit-board', 'atom', 'terminal', 'rocket'];
const picked = PICK.map(name => {
const icon = lucideIcons.find(x => x.name === name);
if (!icon) { console.error('❌ 资源库未找到 lucide:' + name); process.exit(1); }
return { id: icon.id, name, body: icon.svg };
});
const BG_FROM = '#0b1220', BG_TO = '#16294a';
const RING = '#3b82f6';
const S = 24; // lucide 画布 24
const ZOOM = 20; // 放大到 480px
function buildHtml(body) {
return `<!DOCTYPE html>
<html><head><meta charset="utf-8">
<style>html,body{margin:0;padding:0;width:1024px;height:1024px;overflow:hidden;background:transparent}</style>
</head><body>
<svg xmlns="http://www.w3.org/2000/svg" width="1024" height="1024" viewBox="0 0 1024 1024">
<defs>
<linearGradient id="bg" x1="0" y1="0" x2="1" y2="1">
<stop offset="0%" stop-color="${BG_FROM}"/><stop offset="100%" stop-color="${BG_TO}"/>
</linearGradient>
<clipPath id="circle"><circle cx="512" cy="512" r="512"/></clipPath>
</defs>
<rect width="1024" height="1024" fill="url(#bg)" clip-path="url(#circle)"/>
<circle cx="512" cy="512" r="452" fill="none" stroke="${RING}" stroke-width="5" opacity=".45"/>
<g transform="translate(512 512) scale(${ZOOM}) translate(${-S / 2} ${-S / 2})"
fill="none" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">${body}</g>
</svg>
</body></html>`;
}
// —— 3. 导出 PNG ——
fs.mkdirSync(OUT_DIR, { recursive: true });
fs.mkdirSync(TMP_DIR, { recursive: true });
picked.forEach((p, i) => {
const idx = String(i + 1).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(p.body), '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 ← lucide:${p.name}`);
} 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/');