feat: 初始化画个标仓库 - AI驱动设计系统(BYOK模式) - 224源/371504图标+25海报源+130技能
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
/**
|
||||
* 🎨 14 种智能体头像风格 × 100 个 = 1400 个 SVG 生成脚本
|
||||
* - 风格:DiceBear 14 种(资源库 js/data/sources/dicebear-*.js)
|
||||
* - 每种风格专属:渐变圆底 + 白色圆环 + lucide 风格徽章(视觉身份差异化)
|
||||
* - bottts / bottts-neutral 复用 bot-common 过滤负面表情
|
||||
* - 确定性 seed:{style}-1 .. {style}-100,每风格内部唯一
|
||||
*
|
||||
* 用法:node scripts/gen-14styles.js
|
||||
*/
|
||||
'use strict';
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const vm = require('vm');
|
||||
const { generateSeeds } = require('./bot-common');
|
||||
|
||||
const ROOT = path.resolve(__dirname, '..');
|
||||
const OUT = path.join(ROOT, 'output', 'agent-avatars-png', 'avatars');
|
||||
const DATE = '2026-08-19';
|
||||
|
||||
// —— 1. 风格配置(视觉身份 + 渐变 + 徽章图标)——
|
||||
const STYLES = [
|
||||
{ id: 'bottts', name: '科技机器人', desc: '机械与电路', c1: '#0f2a6b', c2: '#2563eb', badge: 'bot' },
|
||||
{ id: 'bottts-neutral', name: '极简机器人', desc: '黑白灰几何', c1: '#374151', c2: '#9ca3af', badge: 'cpu' },
|
||||
{ id: 'avataaars', name: '阿凡达', desc: '可定制人物角色', c1: '#166534', c2: '#4ade80', badge: 'user' },
|
||||
{ id: 'adventurer', name: '冒险家', desc: '探险冒险人物', c1: '#92400e', c2: '#fbbf24', badge: 'compass' },
|
||||
{ id: 'avataaars-neutral', name: '中性阿凡达', desc: '中性色人物角色', c1: '#065f46', c2: '#2dd4bf', badge: 'smile' },
|
||||
{ id: 'adventurer-neutral',name: '中性冒险家', desc: '中性色探险人物', c1: '#78350f', c2: '#d97706', badge: 'map' },
|
||||
{ id: 'open-peeps', name: '手绘小人', desc: '涂鸦风人物', c1: '#4338ca', c2: '#818cf8', badge: 'users' },
|
||||
{ id: 'personas', name: '人物插画', desc: '现代扁平人物', c1: '#be185d', c2: '#f472b6', badge: 'palette' },
|
||||
{ id: 'dylan', name: '迪伦人物', desc: '涂鸦线条人物', c1: '#0e7490', c2: '#67e8f9', badge: 'pen-tool' },
|
||||
{ id: 'miniavs', name: '迷你头像', desc: '极简小人头像', c1: '#155e75', c2: '#22d3ee', badge: 'heart' },
|
||||
{ id: 'big-smile', name: '大笑脸', desc: '圆脸微笑', c1: '#b45309', c2: '#fde047', badge: 'laugh' },
|
||||
{ id: 'big-ears', name: '大耳朵', desc: '圆脸大耳', c1: '#9a3412', c2: '#fb923c', badge: 'ear' },
|
||||
{ id: 'croodles', name: '卡通线条', desc: '简单线条卡通', c1: '#7c2d12', c2: '#f97316', badge: 'pencil' },
|
||||
{ id: 'lorelei', name: '洛雷莱', desc: '唯美插画人物', c1: '#9d174d', c2: '#f9a8d4', badge: 'flower' }
|
||||
];
|
||||
|
||||
// —— 2. 加载引擎 + 风格定义 + lucide 徽章 ——
|
||||
global.window = global;
|
||||
function load(rel) { vm.runInThisContext(fs.readFileSync(path.join(ROOT, rel), 'utf8'), { filename: rel }); }
|
||||
load('js/core/dicebear.js');
|
||||
load('js/data/sources/lucide.js');
|
||||
for (const s of STYLES) load('js/data/sources/dicebear-' + s.id + '.js');
|
||||
|
||||
const lucideIcons = window['HGB_Source_lucide'].icons;
|
||||
|
||||
// —— 3. 徽章 SVG(lucide 24×24 白色线条)——
|
||||
function badgeSvg(name) {
|
||||
const ic = lucideIcons.find(x => x.name === name);
|
||||
if (!ic || !ic.svg) return '';
|
||||
const m = ic.svg.match(/<svg[^>]*>([\s\S]*)<\/svg>/);
|
||||
return m ? m[1] : '';
|
||||
}
|
||||
|
||||
// —— 4. 包装:渐变圆底 + 头像 + 白环 + 徽章 ——
|
||||
function wrap(svg, w, h, st, idx) {
|
||||
const inner = svg.replace(/^<\?xml[^>]*\?>\s*/, '').replace(/^<svg[^>]*>/, '').replace(/<\/svg>\s*$/, '');
|
||||
const s = 200 / Math.max(w, h);
|
||||
const tx = (240 - w * s) / 2, ty = (240 - h * s) / 2;
|
||||
const badge = badgeSvg(st.badge);
|
||||
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 240 240" width="240" height="240">
|
||||
<defs>
|
||||
<linearGradient id="g${idx}" x1="0" y1="0" x2="1" y2="1">
|
||||
<stop offset="0%" stop-color="${st.c1}"/><stop offset="100%" stop-color="${st.c2}"/>
|
||||
</linearGradient>
|
||||
<clipPath id="c${idx}"><circle cx="120" cy="120" r="120"/></clipPath>
|
||||
</defs>
|
||||
<rect width="240" height="240" fill="url(#g${idx})" clip-path="url(#c${idx})"/>
|
||||
<g transform="translate(${tx.toFixed(2)} ${ty.toFixed(2)}) scale(${s.toFixed(4)})">${inner}</g>
|
||||
<circle cx="120" cy="120" r="114" fill="none" stroke="#ffffff" stroke-opacity="0.4" stroke-width="2.5"/>
|
||||
<g transform="translate(196 196)"><circle r="27" fill="#ffffff" fill-opacity="0.22"/><g transform="translate(-12 -12)">${badge}</g></g>
|
||||
</svg>`;
|
||||
}
|
||||
|
||||
// —— 5. 逐风格生成 ——
|
||||
const meta = { generatedAt: new Date().toISOString(), date: DATE, styles: [] };
|
||||
fs.mkdirSync(OUT, { recursive: true });
|
||||
let total = 0;
|
||||
|
||||
for (const st of STYLES) {
|
||||
const cards = generateSeeds(seed => HGB_Dicebear.renderAvatar(st.id, seed), 100);
|
||||
const styleDir = path.join(OUT, st.id);
|
||||
fs.mkdirSync(styleDir, { recursive: true });
|
||||
const list = [];
|
||||
cards.forEach((c, i) => {
|
||||
const n = String(i + 1).padStart(3, '0');
|
||||
const def = window['HGB_Dicebear_' + st.id.replace(/-/g, '_')];
|
||||
const w = def.canvas.width, h = def.canvas.height;
|
||||
const out = wrap(c.svg, w, h, st, i + 1);
|
||||
const file = `${st.id}-${n}.svg`;
|
||||
fs.writeFileSync(path.join(styleDir, file), out, 'utf8');
|
||||
list.push({ file, seed: c.seed, date: DATE });
|
||||
});
|
||||
meta.styles.push({ id: st.id, name: st.name, desc: st.desc, c1: st.c1, c2: st.c2, badge: st.badge, count: list.length, avatars: list });
|
||||
total += list.length;
|
||||
console.log(`✅ ${st.id}(${st.name}): ${list.length} 个`);
|
||||
}
|
||||
|
||||
fs.writeFileSync(path.join(OUT, 'meta.json'), JSON.stringify(meta), 'utf8');
|
||||
console.log(`🎉 共 ${total} 个 SVG → output/agent-avatars-png/avatars/ + meta.json`);
|
||||
Reference in New Issue
Block a user