feat: 初始化画个标仓库 - AI驱动设计系统(BYOK模式) - 224源/371504图标+25海报源+130技能
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
/**
|
||||
* 🏠 emoji 头像 PNG 批量生成
|
||||
* 从资源库 twemoji 源提取 house 表情彩色 SVG,
|
||||
* 生成 10 个渐变背景圆形头像(1024×1024),用 Chrome headless 导出 PNG。
|
||||
*
|
||||
* 用法:node scripts/gen-emoji-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-emoji');
|
||||
const CHROME = 'C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe';
|
||||
|
||||
// —— 1. 从资源库读取 twemoji 源,提取 house(🏠)彩色 SVG ——
|
||||
global.window = global;
|
||||
vm.runInThisContext(fs.readFileSync(path.join(ROOT, 'js', 'data', 'sources', 'twemoji.js'), 'utf8'), { filename: 'twemoji.js' });
|
||||
const icons = window['HGB_Source_twemoji'].icons;
|
||||
const house = icons.find(x => x.id === 'twemoji:house');
|
||||
if (!house) { console.error('❌ 资源库未找到 twemoji:house'); process.exit(1); }
|
||||
const houseBody = house.svg; // 24 坐标系的 g 内容(含 translate(0 0) scale(0.666…))
|
||||
|
||||
// —— 2. 10 个渐变背景(16 进制)——
|
||||
const BG = [
|
||||
{ from: '#667eea', to: '#764ba2' }, // 蓝紫
|
||||
{ from: '#2193b0', to: '#6dd5ed' }, // 青蓝
|
||||
{ from: '#11998e', to: '#38ef7d' }, // 绿
|
||||
{ from: '#f7971e', to: '#ffd200' }, // 橙黄
|
||||
{ from: '#ee9ca7', to: '#ffdde1' }, // 粉
|
||||
{ from: '#cb2d3e', to: '#ef473a' }, // 红
|
||||
{ from: '#41295a', to: '#2F0743' }, // 紫黑
|
||||
{ from: '#1e3c72', to: '#2a5298' }, // 深蓝
|
||||
{ from: '#f953c6', to: '#b91d73' }, // 玫红
|
||||
{ from: '#0575e6', to: '#021B79' } // 靛蓝
|
||||
];
|
||||
|
||||
// —— 3. 生成 HTML:1024×1024 圆形渐变底 + 🏠 居中(emoji 内容按 24 坐标缩放 22 → 528px)——
|
||||
function buildHtml(from, to) {
|
||||
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="${from}"/><stop offset="100%" stop-color="${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)"/>
|
||||
<g transform="translate(512 512) scale(22) translate(-12 -12)">${houseBody}</g>
|
||||
</svg>
|
||||
</body></html>`;
|
||||
}
|
||||
|
||||
// —— 4. 逐张导出 PNG ——
|
||||
fs.mkdirSync(OUT_DIR, { recursive: true });
|
||||
fs.mkdirSync(TMP_DIR, { recursive: true });
|
||||
|
||||
for (let i = 0; i < BG.length; 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(BG[i].from, BG[i].to), '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 ${BG[i].from} → ${BG[i].to}`);
|
||||
} catch (e) {
|
||||
console.error(`❌ agent-${idx}.png 失败:`, e.message.split('\n')[0]);
|
||||
}
|
||||
}
|
||||
|
||||
// 清理临时 HTML
|
||||
fs.rmSync(TMP_DIR, { recursive: true, force: true });
|
||||
console.log('\n🎉 完成 → output/agent-avatars-png/');
|
||||
Reference in New Issue
Block a user