solfaces 1.0.2 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +489 -97
- package/SKILL.md +171 -0
- package/dist/agent/index.cjs +15 -14
- package/dist/agent/index.js +5 -4
- package/dist/agent/mcp-server.cjs +2956 -287
- package/dist/chunk-6QRDULAO.cjs +191 -0
- package/dist/chunk-6QRDULAO.cjs.map +1 -0
- package/dist/{chunk-RX6D5FGH.js → chunk-77SPWQU5.js} +69 -28
- package/dist/chunk-77SPWQU5.js.map +1 -0
- package/dist/chunk-CQWXUU7P.js +239 -0
- package/dist/chunk-CQWXUU7P.js.map +1 -0
- package/dist/chunk-CXRVPOTI.cjs +244 -0
- package/dist/chunk-CXRVPOTI.cjs.map +1 -0
- package/dist/chunk-DRUSCLEF.js +177 -0
- package/dist/chunk-DRUSCLEF.js.map +1 -0
- package/dist/{chunk-VMNATBH3.cjs → chunk-F244Q4KC.cjs} +74 -33
- package/dist/chunk-F244Q4KC.cjs.map +1 -0
- package/dist/chunk-HVPGR6G5.cjs +647 -0
- package/dist/chunk-HVPGR6G5.cjs.map +1 -0
- package/dist/{chunk-SNJABBAT.js → chunk-MGP7F65H.js} +3 -3
- package/dist/{chunk-SNJABBAT.js.map → chunk-MGP7F65H.js.map} +1 -1
- package/dist/chunk-R3MC2AJZ.cjs +2247 -0
- package/dist/chunk-R3MC2AJZ.cjs.map +1 -0
- package/dist/chunk-SWML743U.js +625 -0
- package/dist/chunk-SWML743U.js.map +1 -0
- package/dist/chunk-SX3FQDKM.js +2238 -0
- package/dist/chunk-SX3FQDKM.js.map +1 -0
- package/dist/{chunk-A6N3RPEA.cjs → chunk-WTCXTXTV.cjs} +6 -6
- package/dist/{chunk-A6N3RPEA.cjs.map → chunk-WTCXTXTV.cjs.map} +1 -1
- package/dist/constants-Bi5uTRp5.d.cts +17 -0
- package/dist/constants-Bi5uTRp5.d.ts +17 -0
- package/dist/core/index.cjs +69 -29
- package/dist/core/index.d.cts +29 -47
- package/dist/core/index.d.ts +29 -47
- package/dist/core/index.js +3 -3
- package/dist/index.cjs +104 -35
- package/dist/index.d.cts +4 -2
- package/dist/index.d.ts +4 -2
- package/dist/index.js +6 -5
- package/dist/names/index.cjs +40 -0
- package/dist/names/index.cjs.map +1 -0
- package/dist/names/index.d.cts +36 -0
- package/dist/names/index.d.ts +36 -0
- package/dist/names/index.js +3 -0
- package/dist/names/index.js.map +1 -0
- package/dist/react/index.cjs +454 -397
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +17 -3
- package/dist/react/index.d.ts +17 -3
- package/dist/react/index.js +450 -394
- package/dist/react/index.js.map +1 -1
- package/dist/solfaces.cdn.global.js +2 -2
- package/dist/solfaces.cdn.global.js.map +1 -1
- package/dist/themes/index.cjs +29 -17
- package/dist/themes/index.d.cts +10 -7
- package/dist/themes/index.d.ts +10 -7
- package/dist/themes/index.js +1 -1
- package/dist/{traits-DAFZnXeS.d.cts → traits-QlWuxZDD.d.cts} +45 -1
- package/dist/{traits-DAFZnXeS.d.ts → traits-QlWuxZDD.d.ts} +45 -1
- package/dist/vanilla/index.cjs +20 -8
- package/dist/vanilla/index.cjs.map +1 -1
- package/dist/vanilla/index.d.cts +1 -1
- package/dist/vanilla/index.d.ts +1 -1
- package/dist/vanilla/index.js +17 -5
- package/dist/vanilla/index.js.map +1 -1
- package/package.json +22 -5
- package/python/solfaces.py +830 -237
- package/reference/integrations.md +166 -0
- package/reference/react.md +108 -0
- package/reference/themes.md +124 -0
- package/dist/chunk-2DIKGLXZ.cjs +0 -126
- package/dist/chunk-2DIKGLXZ.cjs.map +0 -1
- package/dist/chunk-CVFO7YHY.cjs +0 -97
- package/dist/chunk-CVFO7YHY.cjs.map +0 -1
- package/dist/chunk-H3SK3MNX.cjs +0 -409
- package/dist/chunk-H3SK3MNX.cjs.map +0 -1
- package/dist/chunk-KSGFMW33.js +0 -401
- package/dist/chunk-KSGFMW33.js.map +0 -1
- package/dist/chunk-LQWJRHGC.js +0 -86
- package/dist/chunk-LQWJRHGC.js.map +0 -1
- package/dist/chunk-RX6D5FGH.js.map +0 -1
- package/dist/chunk-VMNATBH3.cjs.map +0 -1
- package/dist/chunk-WURY4QGH.js +0 -117
- package/dist/chunk-WURY4QGH.js.map +0 -1
- package/skill.md +0 -463
|
@@ -0,0 +1,625 @@
|
|
|
1
|
+
// src/core/traits.ts
|
|
2
|
+
var SKIN_COLORS = [
|
|
3
|
+
"#faeae5",
|
|
4
|
+
"#efd6c8",
|
|
5
|
+
"#e4c5aa",
|
|
6
|
+
"#d5b590",
|
|
7
|
+
"#c59e77",
|
|
8
|
+
"#b4875f",
|
|
9
|
+
"#9d6d4d",
|
|
10
|
+
"#805742",
|
|
11
|
+
"#654134",
|
|
12
|
+
"#4b2d25"
|
|
13
|
+
];
|
|
14
|
+
var EYE_COLORS = [
|
|
15
|
+
"#382414",
|
|
16
|
+
"#3868A8",
|
|
17
|
+
"#38784C",
|
|
18
|
+
"#808838",
|
|
19
|
+
"#586878"
|
|
20
|
+
];
|
|
21
|
+
var HAIR_COLORS = [
|
|
22
|
+
"#1A1A24",
|
|
23
|
+
"#4C3428",
|
|
24
|
+
"#887058",
|
|
25
|
+
"#D4B868",
|
|
26
|
+
"#A84830",
|
|
27
|
+
"#C0C0CC",
|
|
28
|
+
"#484858",
|
|
29
|
+
"#783850",
|
|
30
|
+
"#D8B0A0",
|
|
31
|
+
"#C08048"
|
|
32
|
+
];
|
|
33
|
+
var BG_COLORS = [
|
|
34
|
+
"#b98387",
|
|
35
|
+
"#a9a360",
|
|
36
|
+
"#9eb785",
|
|
37
|
+
"#69ab79",
|
|
38
|
+
"#81bbb0",
|
|
39
|
+
"#6499af",
|
|
40
|
+
"#7f8bbd",
|
|
41
|
+
"#8869ab",
|
|
42
|
+
"#b785b3",
|
|
43
|
+
"#ab6984"
|
|
44
|
+
];
|
|
45
|
+
function djb2(str) {
|
|
46
|
+
let hash = 5381;
|
|
47
|
+
for (let i = 0; i < str.length; i++) {
|
|
48
|
+
hash = (hash << 5) + hash + str.charCodeAt(i) | 0;
|
|
49
|
+
}
|
|
50
|
+
return hash >>> 0;
|
|
51
|
+
}
|
|
52
|
+
function mulberry32(seed) {
|
|
53
|
+
let s = seed | 0;
|
|
54
|
+
return () => {
|
|
55
|
+
s = s + 1831565813 | 0;
|
|
56
|
+
let t = Math.imul(s ^ s >>> 15, 1 | s);
|
|
57
|
+
t = t + Math.imul(t ^ t >>> 7, 61 | t) ^ t;
|
|
58
|
+
return ((t ^ t >>> 14) >>> 0) / 4294967296;
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
function generateTraits(walletAddress, overrides) {
|
|
62
|
+
const seed = djb2(walletAddress);
|
|
63
|
+
const rand = mulberry32(seed);
|
|
64
|
+
const traits = {
|
|
65
|
+
faceShape: Math.floor(rand() * 4),
|
|
66
|
+
skinColor: Math.floor(rand() * 10),
|
|
67
|
+
eyeStyle: Math.floor(rand() * 8),
|
|
68
|
+
eyeColor: Math.floor(rand() * 5),
|
|
69
|
+
eyebrows: Math.floor(rand() * 5),
|
|
70
|
+
nose: Math.floor(rand() * 4),
|
|
71
|
+
mouth: Math.floor(rand() * 8),
|
|
72
|
+
hairStyle: Math.floor(rand() * 10),
|
|
73
|
+
hairColor: Math.floor(rand() * 10),
|
|
74
|
+
accessory: Math.floor(rand() * 10),
|
|
75
|
+
bgColor: Math.floor(rand() * 10)
|
|
76
|
+
};
|
|
77
|
+
return overrides ? { ...traits, ...overrides } : traits;
|
|
78
|
+
}
|
|
79
|
+
function effectiveAccessory(traits) {
|
|
80
|
+
const ai = traits.accessory % 10;
|
|
81
|
+
const hi = traits.hairStyle % 10;
|
|
82
|
+
if ((ai === 4 || ai === 7) && (hi === 5 || hi === 6)) return 0;
|
|
83
|
+
return ai;
|
|
84
|
+
}
|
|
85
|
+
var FACE_LABELS = ["Squircle"];
|
|
86
|
+
var SKIN_LABELS = [
|
|
87
|
+
"Porcelain",
|
|
88
|
+
"Ivory",
|
|
89
|
+
"Fair",
|
|
90
|
+
"Light",
|
|
91
|
+
"Sand",
|
|
92
|
+
"Golden",
|
|
93
|
+
"Warm",
|
|
94
|
+
"Caramel",
|
|
95
|
+
"Brown",
|
|
96
|
+
"Deep"
|
|
97
|
+
];
|
|
98
|
+
var EYE_STYLE_LABELS = ["Round", "Minimal", "Almond", "Wide", "Relaxed", "Joyful", "Bright", "Gentle"];
|
|
99
|
+
var EYE_COLOR_LABELS = ["Chocolate", "Sky", "Emerald", "Hazel", "Storm"];
|
|
100
|
+
var BROW_LABELS = ["Wispy", "Straight", "Natural", "Arched", "Angled"];
|
|
101
|
+
var NOSE_LABELS = ["Shadow", "Button", "Soft", "Nostrils"];
|
|
102
|
+
var MOUTH_LABELS = ["Smile", "Calm", "Happy", "Oh", "Smirk", "Grin", "Flat", "Pout"];
|
|
103
|
+
var HAIR_STYLE_LABELS = [
|
|
104
|
+
"Bald",
|
|
105
|
+
"Short",
|
|
106
|
+
"Curly",
|
|
107
|
+
"Side Sweep",
|
|
108
|
+
"Puff",
|
|
109
|
+
"Long",
|
|
110
|
+
"Bob",
|
|
111
|
+
"Buzz",
|
|
112
|
+
"Wavy",
|
|
113
|
+
"Topknot"
|
|
114
|
+
];
|
|
115
|
+
var HAIR_COLOR_LABELS = [
|
|
116
|
+
"Black",
|
|
117
|
+
"Espresso",
|
|
118
|
+
"Walnut",
|
|
119
|
+
"Honey",
|
|
120
|
+
"Copper",
|
|
121
|
+
"Silver",
|
|
122
|
+
"Charcoal",
|
|
123
|
+
"Burgundy",
|
|
124
|
+
"Strawberry",
|
|
125
|
+
"Ginger"
|
|
126
|
+
];
|
|
127
|
+
var ACCESSORY_LABELS = [
|
|
128
|
+
"None",
|
|
129
|
+
"Beauty Mark",
|
|
130
|
+
"Round Glasses",
|
|
131
|
+
"Rect Glasses",
|
|
132
|
+
"Earring",
|
|
133
|
+
"Headband",
|
|
134
|
+
"Freckles",
|
|
135
|
+
"Stud Earrings",
|
|
136
|
+
"Aviators",
|
|
137
|
+
"Band-Aid"
|
|
138
|
+
];
|
|
139
|
+
var BG_COLOR_LABELS = [
|
|
140
|
+
"Rose",
|
|
141
|
+
"Olive",
|
|
142
|
+
"Sage",
|
|
143
|
+
"Fern",
|
|
144
|
+
"Mint",
|
|
145
|
+
"Ocean",
|
|
146
|
+
"Sky",
|
|
147
|
+
"Lavender",
|
|
148
|
+
"Orchid",
|
|
149
|
+
"Blush"
|
|
150
|
+
];
|
|
151
|
+
function getTraitLabels(traits) {
|
|
152
|
+
return {
|
|
153
|
+
faceShape: FACE_LABELS[0],
|
|
154
|
+
skinColor: SKIN_LABELS[traits.skinColor] ?? "Fair",
|
|
155
|
+
eyeStyle: EYE_STYLE_LABELS[traits.eyeStyle] ?? "Round",
|
|
156
|
+
eyeColor: EYE_COLOR_LABELS[traits.eyeColor] ?? "Chocolate",
|
|
157
|
+
eyebrows: BROW_LABELS[traits.eyebrows] ?? "Wispy",
|
|
158
|
+
nose: NOSE_LABELS[traits.nose] ?? "Shadow",
|
|
159
|
+
mouth: MOUTH_LABELS[traits.mouth] ?? "Smile",
|
|
160
|
+
hairStyle: HAIR_STYLE_LABELS[traits.hairStyle] ?? "Bald",
|
|
161
|
+
hairColor: HAIR_COLOR_LABELS[traits.hairColor] ?? "Black",
|
|
162
|
+
accessory: ACCESSORY_LABELS[effectiveAccessory(traits)] ?? "None",
|
|
163
|
+
bgColor: BG_COLOR_LABELS[traits.bgColor] ?? "Rose"
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
function traitHash(walletAddress) {
|
|
167
|
+
return (djb2(walletAddress) >>> 0).toString(16).padStart(8, "0");
|
|
168
|
+
}
|
|
169
|
+
function resolveTheme(themeName, themes) {
|
|
170
|
+
if (!themeName || !themes) return void 0;
|
|
171
|
+
return themes[themeName];
|
|
172
|
+
}
|
|
173
|
+
function mergeTheme(base, overrides) {
|
|
174
|
+
if (!base) return overrides || null;
|
|
175
|
+
if (!overrides) return base;
|
|
176
|
+
return { ...base, ...overrides };
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// src/core/colors.ts
|
|
180
|
+
function hexToRgb(hex) {
|
|
181
|
+
const h = hex.replace("#", "");
|
|
182
|
+
return [
|
|
183
|
+
parseInt(h.slice(0, 2), 16),
|
|
184
|
+
parseInt(h.slice(2, 4), 16),
|
|
185
|
+
parseInt(h.slice(4, 6), 16)
|
|
186
|
+
];
|
|
187
|
+
}
|
|
188
|
+
function rgbToHex(r, g, b) {
|
|
189
|
+
return "#" + [r, g, b].map(
|
|
190
|
+
(v) => Math.max(0, Math.min(255, Math.round(v))).toString(16).padStart(2, "0")
|
|
191
|
+
).join("");
|
|
192
|
+
}
|
|
193
|
+
function darken(hex, pct = 0.12) {
|
|
194
|
+
const [r, g, b] = hexToRgb(hex);
|
|
195
|
+
return rgbToHex(r * (1 - pct), g * (1 - pct), b * (1 - pct));
|
|
196
|
+
}
|
|
197
|
+
function lighten(hex, pct = 0.15) {
|
|
198
|
+
const [r, g, b] = hexToRgb(hex);
|
|
199
|
+
return rgbToHex(r + (255 - r) * pct, g + (255 - g) * pct, b + (255 - b) * pct);
|
|
200
|
+
}
|
|
201
|
+
function blend(a, b, t = 0.5) {
|
|
202
|
+
const [r1, g1, b1] = hexToRgb(a);
|
|
203
|
+
const [r2, g2, b2] = hexToRgb(b);
|
|
204
|
+
return rgbToHex(
|
|
205
|
+
r1 + (r2 - r1) * t,
|
|
206
|
+
g1 + (g2 - g1) * t,
|
|
207
|
+
b1 + (b2 - b1) * t
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
function luminance(hex) {
|
|
211
|
+
const [r, g, b] = hexToRgb(hex);
|
|
212
|
+
return (r + g + b) / 3;
|
|
213
|
+
}
|
|
214
|
+
function deriveSkinColors(skin) {
|
|
215
|
+
const sL = luminance(skin);
|
|
216
|
+
const isDark = sL < 100;
|
|
217
|
+
const skinHi = lighten(skin, 0.1);
|
|
218
|
+
const skinLo = darken(skin, 0.22);
|
|
219
|
+
const skinMid = darken(skin, 0.05);
|
|
220
|
+
const [sr, sg, sb] = hexToRgb(skin);
|
|
221
|
+
let cheekColor;
|
|
222
|
+
if (sL > 120) {
|
|
223
|
+
const rB = sL > 180 ? 0.03 : 0.06;
|
|
224
|
+
const gD = sL > 180 ? 0.3 : 0.28;
|
|
225
|
+
const bD = sL > 180 ? 0.25 : 0.22;
|
|
226
|
+
cheekColor = rgbToHex(
|
|
227
|
+
Math.min(255, sr + sr * rB),
|
|
228
|
+
Math.max(0, sg - sg * gD),
|
|
229
|
+
Math.max(0, sb - sb * bD)
|
|
230
|
+
);
|
|
231
|
+
} else {
|
|
232
|
+
cheekColor = rgbToHex(
|
|
233
|
+
Math.min(255, sr + 50),
|
|
234
|
+
Math.max(0, sg - 10),
|
|
235
|
+
Math.max(0, sb - 5)
|
|
236
|
+
);
|
|
237
|
+
}
|
|
238
|
+
const cheekOpacity = 0.15 + 0.18 * (1 - Math.min(1, sL / 240));
|
|
239
|
+
const lipT = Math.max(0, Math.min(1, (sL - 60) / 180));
|
|
240
|
+
const lipBase = blend("#D89090", "#A83848", lipT);
|
|
241
|
+
const midBoost = 1 - Math.abs(sL - 140) / 80;
|
|
242
|
+
const lipBlend = (isDark ? 0.7 : 0.62) + Math.max(0, midBoost) * 0.12;
|
|
243
|
+
const lipRaw = blend(skin, lipBase, Math.min(0.82, lipBlend));
|
|
244
|
+
const [lr, lg, lb] = hexToRgb(lipRaw);
|
|
245
|
+
const lipD = Math.abs(sr - lr) + Math.abs(sg - lg) + Math.abs(sb - lb);
|
|
246
|
+
const lipColor = lipD < 60 ? blend(skin, lipBase, 0.78) : lipRaw;
|
|
247
|
+
const browColor = isDark ? lighten(skin, sL < 80 ? 0.35 : 0.25) : darken(skin, 0.55);
|
|
248
|
+
const noseFill = isDark ? lighten(skin, 0.2) : darken(skin, 0.2);
|
|
249
|
+
const earT = Math.max(0, Math.min(1, (sL - 100) / 60));
|
|
250
|
+
const earFill = blend(lighten(skin, 0.08), skinMid, earT);
|
|
251
|
+
const earShadow = darken(skin, 0.1 + 0.06 * (1 - Math.min(1, sL / 160)));
|
|
252
|
+
const lidColor = isDark ? lighten(skin, 0.18) : darken(skin, 0.15);
|
|
253
|
+
const ewT = Math.max(0, Math.min(1, (sL - 60) / 180));
|
|
254
|
+
const eyeWhiteAdapted = blend("#EDE8E0", "#FBF8F2", ewT);
|
|
255
|
+
const warmth = sL > 140 ? 0.3 : sL > 100 ? 0.5 : 0.7;
|
|
256
|
+
const accessoryColor = blend("#808890", blend(skin, "#B0A898", 0.3), warmth);
|
|
257
|
+
return {
|
|
258
|
+
skinHi,
|
|
259
|
+
skinLo,
|
|
260
|
+
skinMid,
|
|
261
|
+
isDark,
|
|
262
|
+
cheekColor,
|
|
263
|
+
cheekOpacity,
|
|
264
|
+
lipColor,
|
|
265
|
+
noseFill,
|
|
266
|
+
browColor,
|
|
267
|
+
earFill,
|
|
268
|
+
earShadow,
|
|
269
|
+
eyeWhiteAdapted,
|
|
270
|
+
lidColor,
|
|
271
|
+
accessoryColor
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
function buzzOpacity(hairCol, skin) {
|
|
275
|
+
const [hr, hg, hb] = hexToRgb(hairCol);
|
|
276
|
+
const [sr, sg, sb] = hexToRgb(skin);
|
|
277
|
+
return Math.abs(hr - sr) + Math.abs(hg - sg) + Math.abs(hb - sb) < 80 ? 0.7 : 0.5;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// src/core/renderer.ts
|
|
281
|
+
function djb22(str) {
|
|
282
|
+
let hash = 5381;
|
|
283
|
+
for (let i = 0; i < str.length; i++) {
|
|
284
|
+
hash = (hash << 5) + hash + str.charCodeAt(i) | 0;
|
|
285
|
+
}
|
|
286
|
+
return hash >>> 0;
|
|
287
|
+
}
|
|
288
|
+
function buildDefs(id, skin, skinHi, skinLo, hairCol, bgCol, cheekColor, cheekOpacity, flat, full) {
|
|
289
|
+
if (flat) return "";
|
|
290
|
+
let d = "<defs>";
|
|
291
|
+
d += `<linearGradient id="${id}sg" x1="0" y1="0" x2="0" y2="1">`;
|
|
292
|
+
d += `<stop offset="0%" stop-color="${skinHi}"/>`;
|
|
293
|
+
d += `<stop offset="100%" stop-color="${skinLo}"/>`;
|
|
294
|
+
d += `</linearGradient>`;
|
|
295
|
+
d += `<linearGradient id="${id}hg" x1="0" y1="0" x2="0" y2="1">`;
|
|
296
|
+
d += `<stop offset="0%" stop-color="${lighten(hairCol, 0.15)}"/>`;
|
|
297
|
+
d += `<stop offset="100%" stop-color="${darken(hairCol, 0.15)}"/>`;
|
|
298
|
+
d += `</linearGradient>`;
|
|
299
|
+
d += `<linearGradient id="${id}bg" x1="0" y1="0" x2="1" y2="1">`;
|
|
300
|
+
d += `<stop offset="0%" stop-color="${lighten(bgCol, 0.12)}"/>`;
|
|
301
|
+
d += `<stop offset="100%" stop-color="${darken(bgCol, 0.12)}"/>`;
|
|
302
|
+
d += `</linearGradient>`;
|
|
303
|
+
if (full) {
|
|
304
|
+
d += `<radialGradient id="${id}glow" cx="0.5" cy="0.28" r="0.45">`;
|
|
305
|
+
d += `<stop offset="0%" stop-color="#ffffff" stop-opacity="0.10"/>`;
|
|
306
|
+
d += `<stop offset="100%" stop-color="#ffffff" stop-opacity="0"/>`;
|
|
307
|
+
d += `</radialGradient>`;
|
|
308
|
+
d += `<radialGradient id="${id}chin" cx="0.5" cy="0.85" r="0.35">`;
|
|
309
|
+
d += `<stop offset="0%" stop-color="${skinLo}" stop-opacity="0.30"/>`;
|
|
310
|
+
d += `<stop offset="100%" stop-color="${skinLo}" stop-opacity="0"/>`;
|
|
311
|
+
d += `</radialGradient>`;
|
|
312
|
+
d += `<radialGradient id="${id}cL" cx="0.5" cy="0.5" r="0.5">`;
|
|
313
|
+
d += `<stop offset="0%" stop-color="${cheekColor}" stop-opacity="${cheekOpacity.toFixed(2)}"/>`;
|
|
314
|
+
d += `<stop offset="100%" stop-color="${cheekColor}" stop-opacity="0"/>`;
|
|
315
|
+
d += `</radialGradient>`;
|
|
316
|
+
d += `<radialGradient id="${id}cR" cx="0.5" cy="0.5" r="0.5">`;
|
|
317
|
+
d += `<stop offset="0%" stop-color="${cheekColor}" stop-opacity="${cheekOpacity.toFixed(2)}"/>`;
|
|
318
|
+
d += `<stop offset="100%" stop-color="${cheekColor}" stop-opacity="0"/>`;
|
|
319
|
+
d += `</radialGradient>`;
|
|
320
|
+
}
|
|
321
|
+
d += "</defs>";
|
|
322
|
+
return d;
|
|
323
|
+
}
|
|
324
|
+
function renderHairBack(hi, id, flat) {
|
|
325
|
+
const fill = flat ? "currentColor" : `url(#${id}hg)`;
|
|
326
|
+
switch (hi) {
|
|
327
|
+
case 5:
|
|
328
|
+
return `<g fill="${fill}"><rect x="10" y="14" width="44" height="42" rx="6"/></g>`;
|
|
329
|
+
case 6:
|
|
330
|
+
return `<g fill="${fill}"><rect x="12" y="14" width="40" height="32" rx="8"/></g>`;
|
|
331
|
+
case 8:
|
|
332
|
+
return `<g fill="${fill}"><rect x="11" y="14" width="42" height="38" rx="8"/></g>`;
|
|
333
|
+
default:
|
|
334
|
+
return "";
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
function renderEars(earFill, earShadow) {
|
|
338
|
+
return `<ellipse cx="11" cy="34" rx="4" ry="5" fill="${earFill}"/><ellipse cx="11" cy="34" rx="2.5" ry="3.5" fill="${earShadow}" opacity="0.3"/><ellipse cx="53" cy="34" rx="4" ry="5" fill="${earFill}"/><ellipse cx="53" cy="34" rx="2.5" ry="3.5" fill="${earShadow}" opacity="0.3"/>`;
|
|
339
|
+
}
|
|
340
|
+
function renderFace(id, skin, flat, opacity = 1) {
|
|
341
|
+
const fill = flat ? skin : `url(#${id}sg)`;
|
|
342
|
+
const opAttr = opacity < 1 ? ` opacity="${opacity}"` : "";
|
|
343
|
+
return `<rect x="14" y="16" width="36" height="38" rx="12" ry="12" fill="${fill}"${opAttr}/>`;
|
|
344
|
+
}
|
|
345
|
+
function renderFaceOverlays(id, flat) {
|
|
346
|
+
if (flat) return "";
|
|
347
|
+
return `<rect x="14" y="16" width="36" height="38" rx="12" ry="12" fill="url(#${id}glow)"/><rect x="14" y="16" width="36" height="38" rx="12" ry="12" fill="url(#${id}chin)"/><ellipse cx="22" cy="42" rx="5" ry="3.5" fill="url(#${id}cL)"/><ellipse cx="42" cy="42" rx="5" ry="3.5" fill="url(#${id}cR)"/><line x1="20" y1="50" x2="44" y2="50" stroke="currentColor" stroke-width="0.3" opacity="0.08" stroke-linecap="round"/>`;
|
|
348
|
+
}
|
|
349
|
+
function renderHairFront(hi, id, hairCol, skin, flat) {
|
|
350
|
+
const fill = flat ? hairCol : `url(#${id}hg)`;
|
|
351
|
+
switch (hi) {
|
|
352
|
+
case 0:
|
|
353
|
+
return "";
|
|
354
|
+
// Bald
|
|
355
|
+
case 1:
|
|
356
|
+
return `<path d="M14 28 Q14 14 32 12 Q50 14 50 28 L50 22 Q50 12 32 10 Q14 12 14 22 Z" fill="${fill}"/>`;
|
|
357
|
+
case 2:
|
|
358
|
+
return `<g fill="${fill}"><circle cx="20" cy="14" r="5"/><circle cx="28" cy="11" r="5.5"/><circle cx="36" cy="11" r="5.5"/><circle cx="44" cy="14" r="5"/><circle cx="16" cy="20" r="4"/><circle cx="48" cy="20" r="4"/></g>`;
|
|
359
|
+
case 3:
|
|
360
|
+
return `<path d="M14 26 Q14 12 32 10 Q50 12 50 26 L50 20 Q50 10 32 8 Q14 10 14 20 Z" fill="${fill}"/><path d="M14 20 Q8 16 10 8 Q14 10 20 16 Z" fill="${fill}"/>`;
|
|
361
|
+
case 4:
|
|
362
|
+
return `<ellipse cx="32" cy="10" rx="14" ry="8" fill="${fill}"/>`;
|
|
363
|
+
case 5:
|
|
364
|
+
return `<path d="M14 28 Q14 12 32 10 Q50 12 50 28 L50 20 Q50 10 32 8 Q14 10 14 20 Z" fill="${fill}"/>`;
|
|
365
|
+
case 6:
|
|
366
|
+
return `<path d="M14 28 Q14 12 32 10 Q50 12 50 28 L50 20 Q50 10 32 8 Q14 10 14 20 Z" fill="${fill}"/><rect x="10" y="28" width="8" height="14" rx="4" fill="${fill}"/><rect x="46" y="28" width="8" height="14" rx="4" fill="${fill}"/>`;
|
|
367
|
+
case 7: {
|
|
368
|
+
const bOp = buzzOpacity(hairCol, skin);
|
|
369
|
+
return `<rect x="15" y="13" width="34" height="16" rx="10" ry="8" fill="${hairCol}" opacity="${bOp.toFixed(2)}"/>`;
|
|
370
|
+
}
|
|
371
|
+
case 8:
|
|
372
|
+
return `<path d="M14 28 Q14 12 32 10 Q50 12 50 28 L50 20 Q50 10 32 8 Q14 10 14 20 Z" fill="${fill}"/><path d="M12 30 Q10 20 14 16" fill="none" stroke="${fill}" stroke-width="4" stroke-linecap="round"/><path d="M52 30 Q54 20 50 16" fill="none" stroke="${fill}" stroke-width="4" stroke-linecap="round"/>`;
|
|
373
|
+
case 9:
|
|
374
|
+
return `<path d="M14 28 Q14 14 32 12 Q50 14 50 28 L50 22 Q50 12 32 10 Q14 12 14 22 Z" fill="${fill}"/><ellipse cx="32" cy="6" rx="6" ry="5" fill="${fill}"/>`;
|
|
375
|
+
default:
|
|
376
|
+
return "";
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
function renderEyes(ei, eyeCol, eyeWhite, lidColor, full) {
|
|
380
|
+
const lx = 25, rx = 39, y = 33;
|
|
381
|
+
let s = "";
|
|
382
|
+
switch (ei) {
|
|
383
|
+
case 0:
|
|
384
|
+
s += `<circle cx="${lx}" cy="${y}" r="4" fill="${eyeWhite}"/>`;
|
|
385
|
+
s += `<circle cx="${lx + 0.8}" cy="${y}" r="2.2" fill="${eyeCol}"/>`;
|
|
386
|
+
if (full) s += `<circle cx="${lx + 1.5}" cy="${y - 1}" r="0.7" fill="white" opacity="0.8"/>`;
|
|
387
|
+
s += `<circle cx="${rx}" cy="${y}" r="4" fill="${eyeWhite}"/>`;
|
|
388
|
+
s += `<circle cx="${rx + 0.8}" cy="${y}" r="2.2" fill="${eyeCol}"/>`;
|
|
389
|
+
if (full) s += `<circle cx="${rx + 1.5}" cy="${y - 1}" r="0.7" fill="white" opacity="0.8"/>`;
|
|
390
|
+
break;
|
|
391
|
+
case 1:
|
|
392
|
+
s += `<circle cx="${lx}" cy="${y}" r="2" fill="${eyeCol}"/>`;
|
|
393
|
+
s += `<circle cx="${rx}" cy="${y}" r="2" fill="${eyeCol}"/>`;
|
|
394
|
+
break;
|
|
395
|
+
case 2:
|
|
396
|
+
s += `<ellipse cx="${lx}" cy="${y}" rx="4.5" ry="2.8" fill="${eyeWhite}"/>`;
|
|
397
|
+
s += `<circle cx="${lx + 0.5}" cy="${y}" r="1.8" fill="${eyeCol}"/>`;
|
|
398
|
+
if (full) s += `<circle cx="${lx + 1.2}" cy="${y - 0.8}" r="0.6" fill="white" opacity="0.7"/>`;
|
|
399
|
+
s += `<ellipse cx="${rx}" cy="${y}" rx="4.5" ry="2.8" fill="${eyeWhite}"/>`;
|
|
400
|
+
s += `<circle cx="${rx + 0.5}" cy="${y}" r="1.8" fill="${eyeCol}"/>`;
|
|
401
|
+
if (full) s += `<circle cx="${rx + 1.2}" cy="${y - 0.8}" r="0.6" fill="white" opacity="0.7"/>`;
|
|
402
|
+
break;
|
|
403
|
+
case 3:
|
|
404
|
+
s += `<circle cx="${lx}" cy="${y}" r="5" fill="${eyeWhite}"/>`;
|
|
405
|
+
s += `<circle cx="${lx}" cy="${y + 0.5}" r="2.8" fill="${eyeCol}"/>`;
|
|
406
|
+
if (full) s += `<circle cx="${lx + 1.5}" cy="${y - 1}" r="0.8" fill="white" opacity="0.8"/>`;
|
|
407
|
+
s += `<circle cx="${rx}" cy="${y}" r="5" fill="${eyeWhite}"/>`;
|
|
408
|
+
s += `<circle cx="${rx}" cy="${y + 0.5}" r="2.8" fill="${eyeCol}"/>`;
|
|
409
|
+
if (full) s += `<circle cx="${rx + 1.5}" cy="${y - 1}" r="0.8" fill="white" opacity="0.8"/>`;
|
|
410
|
+
break;
|
|
411
|
+
case 4:
|
|
412
|
+
s += `<ellipse cx="${lx}" cy="${y + 1}" rx="4" ry="2.2" fill="${eyeWhite}"/>`;
|
|
413
|
+
s += `<circle cx="${lx}" cy="${y + 1}" r="1.5" fill="${eyeCol}"/>`;
|
|
414
|
+
if (full) s += `<line x1="${lx - 4.5}" y1="${y - 0.5}" x2="${lx + 4.5}" y2="${y - 0.5}" stroke="${lidColor}" stroke-width="0.8" stroke-linecap="round"/>`;
|
|
415
|
+
s += `<ellipse cx="${rx}" cy="${y + 1}" rx="4" ry="2.2" fill="${eyeWhite}"/>`;
|
|
416
|
+
s += `<circle cx="${rx}" cy="${y + 1}" r="1.5" fill="${eyeCol}"/>`;
|
|
417
|
+
if (full) s += `<line x1="${rx - 4.5}" y1="${y - 0.5}" x2="${rx + 4.5}" y2="${y - 0.5}" stroke="${lidColor}" stroke-width="0.8" stroke-linecap="round"/>`;
|
|
418
|
+
break;
|
|
419
|
+
case 5:
|
|
420
|
+
s += `<path d="M${lx - 4} ${y} Q${lx} ${y + 4} ${lx + 4} ${y}" fill="none" stroke="${eyeCol}" stroke-width="1.8" stroke-linecap="round"/>`;
|
|
421
|
+
s += `<path d="M${rx - 4} ${y} Q${rx} ${y + 4} ${rx + 4} ${y}" fill="none" stroke="${eyeCol}" stroke-width="1.8" stroke-linecap="round"/>`;
|
|
422
|
+
break;
|
|
423
|
+
case 6:
|
|
424
|
+
s += `<circle cx="${lx}" cy="${y}" r="3.5" fill="${eyeWhite}"/>`;
|
|
425
|
+
s += `<circle cx="${lx + 0.5}" cy="${y}" r="2" fill="${eyeCol}"/>`;
|
|
426
|
+
s += `<circle cx="${lx + 1.5}" cy="${y - 1}" r="1" fill="white" opacity="0.9"/>`;
|
|
427
|
+
if (full) {
|
|
428
|
+
s += `<line x1="${lx + 2.5}" y1="${y - 3.5}" x2="${lx + 4}" y2="${y - 5}" stroke="${eyeCol}" stroke-width="0.8" stroke-linecap="round"/>`;
|
|
429
|
+
s += `<line x1="${lx + 3.5}" y1="${y - 2.5}" x2="${lx + 5}" y2="${y - 3.5}" stroke="${eyeCol}" stroke-width="0.8" stroke-linecap="round"/>`;
|
|
430
|
+
}
|
|
431
|
+
s += `<circle cx="${rx}" cy="${y}" r="3.5" fill="${eyeWhite}"/>`;
|
|
432
|
+
s += `<circle cx="${rx + 0.5}" cy="${y}" r="2" fill="${eyeCol}"/>`;
|
|
433
|
+
s += `<circle cx="${rx + 1.5}" cy="${y - 1}" r="1" fill="white" opacity="0.9"/>`;
|
|
434
|
+
if (full) {
|
|
435
|
+
s += `<line x1="${rx + 2.5}" y1="${y - 3.5}" x2="${rx + 4}" y2="${y - 5}" stroke="${eyeCol}" stroke-width="0.8" stroke-linecap="round"/>`;
|
|
436
|
+
s += `<line x1="${rx + 3.5}" y1="${y - 2.5}" x2="${rx + 5}" y2="${y - 3.5}" stroke="${eyeCol}" stroke-width="0.8" stroke-linecap="round"/>`;
|
|
437
|
+
}
|
|
438
|
+
break;
|
|
439
|
+
case 7:
|
|
440
|
+
s += `<ellipse cx="${lx}" cy="${y}" rx="4.5" ry="1.5" fill="${eyeWhite}"/>`;
|
|
441
|
+
s += `<ellipse cx="${lx + 0.5}" cy="${y}" rx="2.2" ry="1.2" fill="${eyeCol}"/>`;
|
|
442
|
+
s += `<ellipse cx="${rx}" cy="${y}" rx="4.5" ry="1.5" fill="${eyeWhite}"/>`;
|
|
443
|
+
s += `<ellipse cx="${rx + 0.5}" cy="${y}" rx="2.2" ry="1.2" fill="${eyeCol}"/>`;
|
|
444
|
+
break;
|
|
445
|
+
default:
|
|
446
|
+
s += `<circle cx="${lx}" cy="${y}" r="3.5" fill="${eyeWhite}"/>`;
|
|
447
|
+
s += `<circle cx="${lx + 0.8}" cy="${y}" r="2" fill="${eyeCol}"/>`;
|
|
448
|
+
s += `<circle cx="${rx}" cy="${y}" r="3.5" fill="${eyeWhite}"/>`;
|
|
449
|
+
s += `<circle cx="${rx + 0.8}" cy="${y}" r="2" fill="${eyeCol}"/>`;
|
|
450
|
+
}
|
|
451
|
+
if (full && ei !== 1 && ei !== 5) {
|
|
452
|
+
s += `<path d="M${lx - 4} ${y - 1.5} Q${lx} ${y - 4} ${lx + 4} ${y - 1.5}" fill="none" stroke="${lidColor}" stroke-width="0.5" opacity="0.4"/>`;
|
|
453
|
+
s += `<path d="M${rx - 4} ${y - 1.5} Q${rx} ${y - 4} ${rx + 4} ${y - 1.5}" fill="none" stroke="${lidColor}" stroke-width="0.5" opacity="0.4"/>`;
|
|
454
|
+
}
|
|
455
|
+
return s;
|
|
456
|
+
}
|
|
457
|
+
function renderEyebrows(bi, browColor) {
|
|
458
|
+
const lx = 25, rx = 39, y = 27;
|
|
459
|
+
switch (bi) {
|
|
460
|
+
case 0:
|
|
461
|
+
return `<line x1="${lx - 3}" y1="${y}" x2="${lx + 3}" y2="${y - 0.5}" stroke="${browColor}" stroke-width="0.7" stroke-linecap="round"/><line x1="${rx - 3}" y1="${y - 0.5}" x2="${rx + 3}" y2="${y}" stroke="${browColor}" stroke-width="0.7" stroke-linecap="round"/>`;
|
|
462
|
+
case 1:
|
|
463
|
+
return `<line x1="${lx - 3.5}" y1="${y}" x2="${lx + 3.5}" y2="${y}" stroke="${browColor}" stroke-width="1.2" stroke-linecap="round"/><line x1="${rx - 3.5}" y1="${y}" x2="${rx + 3.5}" y2="${y}" stroke="${browColor}" stroke-width="1.2" stroke-linecap="round"/>`;
|
|
464
|
+
case 2:
|
|
465
|
+
return `<path d="M${lx - 3.5} ${y + 0.5} Q${lx} ${y - 1.5} ${lx + 3.5} ${y + 0.5}" fill="none" stroke="${browColor}" stroke-width="1.2" stroke-linecap="round"/><path d="M${rx - 3.5} ${y + 0.5} Q${rx} ${y - 1.5} ${rx + 3.5} ${y + 0.5}" fill="none" stroke="${browColor}" stroke-width="1.2" stroke-linecap="round"/>`;
|
|
466
|
+
case 3:
|
|
467
|
+
return `<path d="M${lx - 4} ${y + 1} Q${lx} ${y - 3} ${lx + 4} ${y + 1}" fill="none" stroke="${browColor}" stroke-width="1" stroke-linecap="round"/><path d="M${rx - 4} ${y + 1} Q${rx} ${y - 3} ${rx + 4} ${y + 1}" fill="none" stroke="${browColor}" stroke-width="1" stroke-linecap="round"/>`;
|
|
468
|
+
case 4:
|
|
469
|
+
return `<polyline points="${lx - 3},${y + 1} ${lx},${y - 2} ${lx + 3},${y}" fill="none" stroke="${browColor}" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/><polyline points="${rx - 3},${y} ${rx},${y - 2} ${rx + 3},${y + 1}" fill="none" stroke="${browColor}" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>`;
|
|
470
|
+
default:
|
|
471
|
+
return "";
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
function renderNose(ni, noseFill) {
|
|
475
|
+
const cx = 32, y = 39;
|
|
476
|
+
switch (ni) {
|
|
477
|
+
case 0:
|
|
478
|
+
return `<ellipse cx="${cx}" cy="${y}" rx="2" ry="1.2" fill="${noseFill}" opacity="0.35"/>`;
|
|
479
|
+
case 1:
|
|
480
|
+
return `<circle cx="${cx}" cy="${y}" r="1.8" fill="${noseFill}" opacity="0.5"/>`;
|
|
481
|
+
case 2:
|
|
482
|
+
return `<path d="M${cx - 2} ${y + 1} Q${cx} ${y - 2} ${cx + 2} ${y + 1}" fill="none" stroke="${noseFill}" stroke-width="1" stroke-linecap="round" opacity="0.5"/>`;
|
|
483
|
+
case 3:
|
|
484
|
+
return `<circle cx="${cx - 1.8}" cy="${y}" r="1.2" fill="${noseFill}" opacity="0.4"/><circle cx="${cx + 1.8}" cy="${y}" r="1.2" fill="${noseFill}" opacity="0.4"/>`;
|
|
485
|
+
default:
|
|
486
|
+
return `<ellipse cx="${cx}" cy="${y}" rx="2" ry="1.2" fill="${noseFill}" opacity="0.35"/>`;
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
function renderMouth(mi, lipColor, isDark) {
|
|
490
|
+
const cx = 32, y = 45;
|
|
491
|
+
const teethCol = isDark ? "#e8e0d8" : "#ffffff";
|
|
492
|
+
switch (mi) {
|
|
493
|
+
case 0:
|
|
494
|
+
return `<path d="M${cx - 4} ${y} Q${cx} ${y + 4} ${cx + 4} ${y}" fill="none" stroke="${lipColor}" stroke-width="1.4" stroke-linecap="round"/>`;
|
|
495
|
+
case 1:
|
|
496
|
+
return `<line x1="${cx - 3}" y1="${y + 1}" x2="${cx + 3}" y2="${y + 1}" stroke="${lipColor}" stroke-width="1.2" stroke-linecap="round"/>`;
|
|
497
|
+
case 2:
|
|
498
|
+
return `<path d="M${cx - 5} ${y} Q${cx} ${y + 5} ${cx + 5} ${y}" fill="none" stroke="${lipColor}" stroke-width="1.5" stroke-linecap="round"/>`;
|
|
499
|
+
case 3:
|
|
500
|
+
return `<ellipse cx="${cx}" cy="${y + 1}" rx="2.5" ry="3" fill="${lipColor}" opacity="0.7"/>`;
|
|
501
|
+
case 4:
|
|
502
|
+
return `<path d="M${cx - 4} ${y + 1} Q${cx + 1} ${y + 1} ${cx + 4} ${y - 1.5}" fill="none" stroke="${lipColor}" stroke-width="1.3" stroke-linecap="round"/>`;
|
|
503
|
+
case 5:
|
|
504
|
+
return `<path d="M${cx - 5} ${y} Q${cx} ${y + 6} ${cx + 5} ${y}" fill="${teethCol}" stroke="${lipColor}" stroke-width="1"/><line x1="${cx - 4}" y1="${y + 1.5}" x2="${cx + 4}" y2="${y + 1.5}" stroke="${lipColor}" stroke-width="0.3" opacity="0.3"/>`;
|
|
505
|
+
case 6:
|
|
506
|
+
return `<line x1="${cx - 4}" y1="${y + 1}" x2="${cx + 4}" y2="${y + 1}" stroke="${lipColor}" stroke-width="1.5" stroke-linecap="round"/>`;
|
|
507
|
+
case 7:
|
|
508
|
+
return `<ellipse cx="${cx}" cy="${y + 1}" rx="3.5" ry="2" fill="${lipColor}" opacity="0.25"/><path d="M${cx - 3} ${y} Q${cx} ${y + 2.5} ${cx + 3} ${y}" fill="none" stroke="${lipColor}" stroke-width="1.2" stroke-linecap="round"/>`;
|
|
509
|
+
default:
|
|
510
|
+
return `<path d="M${cx - 4} ${y} Q${cx} ${y + 4} ${cx + 4} ${y}" fill="none" stroke="${lipColor}" stroke-width="1.4" stroke-linecap="round"/>`;
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
function renderAccessory(ai, accessoryColor, glassesColor, earringColor, headbandColor) {
|
|
514
|
+
switch (ai) {
|
|
515
|
+
case 0:
|
|
516
|
+
return "";
|
|
517
|
+
// None
|
|
518
|
+
case 1:
|
|
519
|
+
return `<circle cx="40" cy="44" r="0.8" fill="#3a2a2a"/>`;
|
|
520
|
+
case 2:
|
|
521
|
+
return `<g fill="none" stroke="${glassesColor}" stroke-width="1"><circle cx="25" cy="33" r="5.5"/><circle cx="39" cy="33" r="5.5"/><line x1="30.5" y1="33" x2="33.5" y2="33"/><line x1="19.5" y1="33" x2="14" y2="31"/><line x1="44.5" y1="33" x2="50" y2="31"/></g>`;
|
|
522
|
+
case 3:
|
|
523
|
+
return `<g fill="none" stroke="${glassesColor}" stroke-width="1"><rect x="19" y="29" width="12" height="8" rx="1.5"/><rect x="33" y="29" width="12" height="8" rx="1.5"/><line x1="31" y1="33" x2="33" y2="33"/><line x1="19" y1="33" x2="14" y2="31"/><line x1="45" y1="33" x2="50" y2="31"/></g>`;
|
|
524
|
+
case 4:
|
|
525
|
+
return `<circle cx="10" cy="38" r="1.5" fill="${earringColor}"/><circle cx="10" cy="41" r="2" fill="${earringColor}" opacity="0.8"/>`;
|
|
526
|
+
case 5:
|
|
527
|
+
return `<rect x="13" y="20" width="38" height="3.5" rx="1.5" fill="${headbandColor}" opacity="0.85"/>`;
|
|
528
|
+
case 6:
|
|
529
|
+
return `<g fill="#a0785a" opacity="0.35"><circle cx="21" cy="40" r="0.6"/><circle cx="23" cy="42" r="0.5"/><circle cx="19" cy="41.5" r="0.5"/><circle cx="43" cy="40" r="0.6"/><circle cx="41" cy="42" r="0.5"/><circle cx="45" cy="41.5" r="0.5"/></g>`;
|
|
530
|
+
case 7:
|
|
531
|
+
return `<circle cx="10" cy="37" r="1.2" fill="${earringColor}"/><circle cx="54" cy="37" r="1.2" fill="${earringColor}"/>`;
|
|
532
|
+
case 8:
|
|
533
|
+
return `<g fill="none" stroke="${glassesColor}" stroke-width="1.2"><path d="M19 30 Q19 28 25 28 Q31 28 31 33 Q31 38 25 38 Q19 38 19 33 Z" fill="${glassesColor}" fill-opacity="0.15"/><path d="M33 30 Q33 28 39 28 Q45 28 45 33 Q45 38 39 38 Q33 38 33 33 Z" fill="${glassesColor}" fill-opacity="0.15"/><line x1="31" y1="32" x2="33" y2="32"/><line x1="19" y1="31" x2="14" y2="29"/><line x1="45" y1="31" x2="50" y2="29"/></g>`;
|
|
534
|
+
case 9:
|
|
535
|
+
return `<g><rect x="38" y="38" width="8" height="4" rx="1" fill="#f0d0a0" transform="rotate(-15 42 40)"/><line x1="40" y1="39" x2="40" y2="41" stroke="#c0a080" stroke-width="0.4" transform="rotate(-15 42 40)"/><line x1="42" y1="39" x2="42" y2="41" stroke="#c0a080" stroke-width="0.4" transform="rotate(-15 42 40)"/><line x1="44" y1="39" x2="44" y2="41" stroke="#c0a080" stroke-width="0.4" transform="rotate(-15 42 40)"/></g>`;
|
|
536
|
+
default:
|
|
537
|
+
return "";
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
function renderSolFaceSVG(walletAddress, options) {
|
|
541
|
+
const { size = 64, theme, traitOverrides, enableBlink, className, colorOverrides } = options ?? {};
|
|
542
|
+
const traits = generateTraits(walletAddress, traitOverrides);
|
|
543
|
+
const detailOpt = options?.detail ?? "auto";
|
|
544
|
+
const full = detailOpt === "full" || detailOpt === "auto" && size >= 48;
|
|
545
|
+
const flat = theme?.flat ?? false;
|
|
546
|
+
const skinColors = theme?.skinColors ?? SKIN_COLORS;
|
|
547
|
+
const eyeColors = theme?.eyeColors ?? EYE_COLORS;
|
|
548
|
+
const hairColors = theme?.hairColors ?? HAIR_COLORS;
|
|
549
|
+
const bgColors = theme?.bgColors ?? BG_COLORS;
|
|
550
|
+
const skin = colorOverrides?.skin ?? skinColors[traits.skinColor % skinColors.length];
|
|
551
|
+
const eyeCol = colorOverrides?.eyes ?? eyeColors[traits.eyeColor % eyeColors.length];
|
|
552
|
+
const hairCol = colorOverrides?.hair ?? hairColors[traits.hairColor % hairColors.length];
|
|
553
|
+
const bgCol = colorOverrides?.bg ?? bgColors[traits.bgColor % bgColors.length];
|
|
554
|
+
const derived = deriveSkinColors(skin);
|
|
555
|
+
const bgOpacity = theme?.bgOpacity ?? 1;
|
|
556
|
+
const bgRadius = theme?.bgRadius ?? 4;
|
|
557
|
+
const browColor = colorOverrides?.eyebrow ?? theme?.eyebrowColor ?? derived.browColor;
|
|
558
|
+
const noseFill = colorOverrides?.nose ?? theme?.noseColor ?? derived.noseFill;
|
|
559
|
+
const lipColor = colorOverrides?.mouth ?? theme?.mouthColor ?? derived.lipColor;
|
|
560
|
+
const accColor = colorOverrides?.accessory ?? theme?.accessoryColor ?? derived.accessoryColor;
|
|
561
|
+
const eyeWhite = colorOverrides?.eyeWhite ?? theme?.eyeWhiteColor ?? derived.eyeWhiteAdapted;
|
|
562
|
+
const glassesColor = theme?.glassesColor ?? "#4a4a5a";
|
|
563
|
+
const earringColor = theme?.earringColor ?? blend(skin, "#d4a840", 0.4);
|
|
564
|
+
const headbandColor = theme?.headbandColor ?? blend(hairCol, "#c04040", 0.5);
|
|
565
|
+
const id = "sf" + djb22(walletAddress).toString(36);
|
|
566
|
+
const cheekEnabled = theme?.cheekEnabled ?? true;
|
|
567
|
+
const cheekColor = theme?.cheekColor ?? derived.cheekColor;
|
|
568
|
+
const cheekOpacity = theme?.cheekOpacity ?? derived.cheekOpacity;
|
|
569
|
+
const hi = traits.hairStyle % 10;
|
|
570
|
+
const ai = effectiveAccessory(traits);
|
|
571
|
+
const classAttr = className ? ` class="${className}"` : "";
|
|
572
|
+
let svg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" width="${size}" height="${size}"${classAttr}>`;
|
|
573
|
+
svg += buildDefs(id, skin, derived.skinHi, derived.skinLo, hairCol, bgCol, cheekColor, cheekOpacity, flat, full && cheekEnabled);
|
|
574
|
+
const blinkEnabled = !!enableBlink;
|
|
575
|
+
const blinkDuration = typeof enableBlink === "object" ? enableBlink.duration ?? 4 : 4;
|
|
576
|
+
const blinkDelay = typeof enableBlink === "object" ? enableBlink.delay ?? 0 : 0;
|
|
577
|
+
if (blinkEnabled) {
|
|
578
|
+
const uid = `sf-${walletAddress.slice(0, 8)}`;
|
|
579
|
+
const delayStr = blinkDelay ? ` ${blinkDelay}s` : "";
|
|
580
|
+
svg += `<style>@keyframes ${uid}-blink{0%,90%,100%{transform:scaleY(1)}95%{transform:scaleY(0.1)}}.${uid}-eyes{animation:${uid}-blink ${blinkDuration}s ease-in-out${delayStr} infinite;transform-origin:32px 33px}</style>`;
|
|
581
|
+
}
|
|
582
|
+
const bgFill = flat ? bgCol : `url(#${id}bg)`;
|
|
583
|
+
svg += `<rect x="0" y="0" width="64" height="64" fill="${bgFill}" opacity="${bgOpacity}" rx="${bgRadius}"/>`;
|
|
584
|
+
svg += renderHairBack(hi, id, flat);
|
|
585
|
+
svg += renderEars(derived.earFill, derived.earShadow);
|
|
586
|
+
const skinOpacity = theme?.skinOpacity ?? 1;
|
|
587
|
+
svg += renderFace(id, skin, flat, skinOpacity);
|
|
588
|
+
const shadowEnabled = theme?.shadowEnabled ?? true;
|
|
589
|
+
if (full && cheekEnabled && shadowEnabled) {
|
|
590
|
+
svg += renderFaceOverlays(id, flat);
|
|
591
|
+
}
|
|
592
|
+
if (ai === 5) {
|
|
593
|
+
svg += renderAccessory(5, accColor, glassesColor, earringColor, headbandColor);
|
|
594
|
+
}
|
|
595
|
+
svg += renderHairFront(hi, id, hairCol, skin, flat);
|
|
596
|
+
if (blinkEnabled) {
|
|
597
|
+
const uid = `sf-${walletAddress.slice(0, 8)}`;
|
|
598
|
+
svg += `<g class="${uid}-eyes">`;
|
|
599
|
+
}
|
|
600
|
+
svg += renderEyes(traits.eyeStyle % 8, eyeCol, eyeWhite, derived.lidColor, full);
|
|
601
|
+
if (blinkEnabled) svg += `</g>`;
|
|
602
|
+
svg += renderEyebrows(traits.eyebrows % 5, browColor);
|
|
603
|
+
svg += renderNose(traits.nose % 4, noseFill);
|
|
604
|
+
svg += renderMouth(traits.mouth % 8, lipColor, derived.isDark);
|
|
605
|
+
if (ai !== 0 && ai !== 5) {
|
|
606
|
+
svg += renderAccessory(ai, accColor, glassesColor, earringColor, headbandColor);
|
|
607
|
+
}
|
|
608
|
+
if (theme?.border) {
|
|
609
|
+
svg += `<rect x="0" y="0" width="64" height="64" fill="none" stroke="${theme.border.color}" stroke-width="${theme.border.width}" rx="${bgRadius}"/>`;
|
|
610
|
+
}
|
|
611
|
+
svg += `</svg>`;
|
|
612
|
+
return svg;
|
|
613
|
+
}
|
|
614
|
+
function renderSolFaceDataURI(walletAddress, options) {
|
|
615
|
+
const svg = renderSolFaceSVG(walletAddress, options);
|
|
616
|
+
return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svg)}`;
|
|
617
|
+
}
|
|
618
|
+
function renderSolFaceBase64(walletAddress, options) {
|
|
619
|
+
const svg = renderSolFaceSVG(walletAddress, options);
|
|
620
|
+
return `data:image/svg+xml;base64,${btoa(svg)}`;
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
export { BG_COLORS, EYE_COLORS, HAIR_COLORS, SKIN_COLORS, blend, buzzOpacity, darken, deriveSkinColors, effectiveAccessory, generateTraits, getTraitLabels, hexToRgb, lighten, luminance, mergeTheme, renderSolFaceBase64, renderSolFaceDataURI, renderSolFaceSVG, resolveTheme, rgbToHex, traitHash };
|
|
624
|
+
//# sourceMappingURL=chunk-SWML743U.js.map
|
|
625
|
+
//# sourceMappingURL=chunk-SWML743U.js.map
|