solfaces 2.2.0 → 2.3.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.
Files changed (64) hide show
  1. package/README.md +45 -19
  2. package/SKILL.md +2 -3
  3. package/dist/agent/index.cjs +13 -14
  4. package/dist/agent/index.js +3 -4
  5. package/dist/agent/mcp-server.cjs +326 -333
  6. package/dist/{chunk-5DT27HMT.js → chunk-2KW35VRI.js} +3 -3
  7. package/dist/{chunk-5DT27HMT.js.map → chunk-2KW35VRI.js.map} +1 -1
  8. package/dist/{chunk-PVJR3SFG.cjs → chunk-BI3GHRKQ.cjs} +14 -15
  9. package/dist/chunk-BI3GHRKQ.cjs.map +1 -0
  10. package/dist/{chunk-DRUSCLEF.js → chunk-MYUSB4LA.js} +28 -8
  11. package/dist/chunk-MYUSB4LA.js.map +1 -0
  12. package/dist/{chunk-3CE7Q44S.js → chunk-N5GDLCCL.js} +324 -110
  13. package/dist/chunk-N5GDLCCL.js.map +1 -0
  14. package/dist/{chunk-74CSG63X.js → chunk-O2IIBSQH.js} +6 -7
  15. package/dist/chunk-O2IIBSQH.js.map +1 -0
  16. package/dist/{chunk-6QRDULAO.cjs → chunk-PCSRDAWQ.cjs} +28 -7
  17. package/dist/chunk-PCSRDAWQ.cjs.map +1 -0
  18. package/dist/{chunk-WIXGHS77.cjs → chunk-T7HEUW2O.cjs} +6 -6
  19. package/dist/{chunk-WIXGHS77.cjs.map → chunk-T7HEUW2O.cjs.map} +1 -1
  20. package/dist/{chunk-F54WHRCE.cjs → chunk-W2U6ITMR.cjs} +328 -110
  21. package/dist/chunk-W2U6ITMR.cjs.map +1 -0
  22. package/dist/core/index.cjs +43 -44
  23. package/dist/core/index.d.cts +39 -5
  24. package/dist/core/index.d.ts +39 -5
  25. package/dist/core/index.js +2 -3
  26. package/dist/index.cjs +53 -50
  27. package/dist/index.d.cts +3 -3
  28. package/dist/index.d.ts +3 -3
  29. package/dist/index.js +4 -5
  30. package/dist/react/index.cjs +107 -120
  31. package/dist/react/index.cjs.map +1 -1
  32. package/dist/react/index.d.cts +23 -1
  33. package/dist/react/index.d.ts +23 -1
  34. package/dist/react/index.js +95 -108
  35. package/dist/react/index.js.map +1 -1
  36. package/dist/solfaces.cdn.global.js +2 -2
  37. package/dist/solfaces.cdn.global.js.map +1 -1
  38. package/dist/themes/index.cjs +18 -14
  39. package/dist/themes/index.d.cts +30 -4
  40. package/dist/themes/index.d.ts +30 -4
  41. package/dist/themes/index.js +1 -1
  42. package/dist/traits-D4tbtZIr.d.cts +259 -0
  43. package/dist/traits-D4tbtZIr.d.ts +259 -0
  44. package/dist/vanilla/index.cjs +6 -7
  45. package/dist/vanilla/index.cjs.map +1 -1
  46. package/dist/vanilla/index.d.cts +1 -1
  47. package/dist/vanilla/index.d.ts +1 -1
  48. package/dist/vanilla/index.js +2 -3
  49. package/dist/vanilla/index.js.map +1 -1
  50. package/package.json +4 -1
  51. package/python/solfaces.py +103 -119
  52. package/reference/integrations.md +1 -1
  53. package/dist/chunk-3CE7Q44S.js.map +0 -1
  54. package/dist/chunk-6QRDULAO.cjs.map +0 -1
  55. package/dist/chunk-74CSG63X.js.map +0 -1
  56. package/dist/chunk-CKHLRORB.js +0 -239
  57. package/dist/chunk-CKHLRORB.js.map +0 -1
  58. package/dist/chunk-DRUSCLEF.js.map +0 -1
  59. package/dist/chunk-F54WHRCE.cjs.map +0 -1
  60. package/dist/chunk-PVJR3SFG.cjs.map +0 -1
  61. package/dist/chunk-TYTBYDQU.cjs +0 -244
  62. package/dist/chunk-TYTBYDQU.cjs.map +0 -1
  63. package/dist/traits-sfe7rM9C.d.cts +0 -106
  64. package/dist/traits-sfe7rM9C.d.ts +0 -106
@@ -16,7 +16,10 @@ var EYE_COLORS = [
16
16
  "#3868A8",
17
17
  "#38784C",
18
18
  "#808838",
19
- "#586878"
19
+ "#586878",
20
+ "#A06830",
21
+ "#685898",
22
+ "#889898"
20
23
  ];
21
24
  var HAIR_COLORS = [
22
25
  "#1A1A24",
@@ -40,7 +43,9 @@ var BG_COLORS = [
40
43
  "#7f8bbd",
41
44
  "#8869ab",
42
45
  "#b785b3",
43
- "#ab6984"
46
+ "#ab6984",
47
+ "#a07ab5",
48
+ "#74b5a0"
44
49
  ];
45
50
  function djb2(str) {
46
51
  let hash = 5381;
@@ -64,22 +69,20 @@ function generateTraits(walletAddress, overrides) {
64
69
  const traits = {
65
70
  faceShape: Math.floor(rand() * 4),
66
71
  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),
72
+ eyeStyle: Math.floor(rand() * 9),
73
+ eyeColor: Math.floor(rand() * 8),
74
+ eyebrows: Math.floor(rand() * 8),
75
+ nose: Math.floor(rand() * 8),
71
76
  mouth: Math.floor(rand() * 8),
72
77
  hairStyle: Math.floor(rand() * 10),
73
78
  hairColor: Math.floor(rand() * 10),
74
- accessory: Math.floor(rand() * 10),
75
- bgColor: Math.floor(rand() * 10)
79
+ accessory: Math.floor(rand() * 12),
80
+ bgColor: Math.floor(rand() * 12)
76
81
  };
77
82
  return overrides ? { ...traits, ...overrides } : traits;
78
83
  }
79
84
  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;
85
+ const ai = traits.accessory % 12;
83
86
  return ai;
84
87
  }
85
88
  var FACE_LABELS = ["Squircle"];
@@ -95,22 +98,22 @@ var SKIN_LABELS = [
95
98
  "Brown",
96
99
  "Deep"
97
100
  ];
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"];
101
+ var EYE_STYLE_LABELS = ["Round", "Minimal", "Almond", "Wide", "Relaxed", "Joyful", "Bright", "Gentle", "Side-look"];
102
+ var EYE_COLOR_LABELS = ["Chocolate", "Sky", "Emerald", "Hazel", "Storm", "Amber", "Violet", "Gray"];
103
+ var BROW_LABELS = ["Wispy", "Straight", "Natural", "Arched", "Angled", "Worried", "Bushy", "Thin"];
104
+ var NOSE_LABELS = ["Shadow", "Button", "Soft", "Nostrils", "Pointed", "Wide", "Bridge", "Snub"];
102
105
  var MOUTH_LABELS = ["Smile", "Calm", "Happy", "Oh", "Smirk", "Grin", "Flat", "Pout"];
103
106
  var HAIR_STYLE_LABELS = [
104
107
  "Bald",
105
- "Short",
108
+ "Crew",
106
109
  "Curly",
107
- "Side Sweep",
108
- "Puff",
110
+ "Side Part",
109
111
  "Long",
110
- "Bob",
111
112
  "Buzz",
112
- "Wavy",
113
- "Topknot"
113
+ "Beanie",
114
+ "Cap",
115
+ "Mohawk",
116
+ "Bun"
114
117
  ];
115
118
  var HAIR_COLOR_LABELS = [
116
119
  "Black",
@@ -134,7 +137,9 @@ var ACCESSORY_LABELS = [
134
137
  "Freckles",
135
138
  "Stud Earrings",
136
139
  "Aviators",
137
- "Band-Aid"
140
+ "Band-Aid",
141
+ "Left Eyebrow Slit",
142
+ "Right Eyebrow Slit"
138
143
  ];
139
144
  var BG_COLOR_LABELS = [
140
145
  "Rose",
@@ -146,7 +151,9 @@ var BG_COLOR_LABELS = [
146
151
  "Sky",
147
152
  "Lavender",
148
153
  "Orchid",
149
- "Blush"
154
+ "Blush",
155
+ "Lilac",
156
+ "Seafoam"
150
157
  ];
151
158
  function getTraitLabels(traits) {
152
159
  return {
@@ -209,7 +216,21 @@ function blend(a, b, t = 0.5) {
209
216
  }
210
217
  function luminance(hex) {
211
218
  const [r, g, b] = hexToRgb(hex);
212
- return (r + g + b) / 3;
219
+ return 0.299 * r + 0.587 * g + 0.114 * b;
220
+ }
221
+ function relativeLuminance(hex) {
222
+ const [r, g, b] = hexToRgb(hex).map((c) => {
223
+ const s = c / 255;
224
+ return s <= 0.03928 ? s / 12.92 : Math.pow((s + 0.055) / 1.055, 2.4);
225
+ });
226
+ return 0.2126 * r + 0.7152 * g + 0.0722 * b;
227
+ }
228
+ function contrastRatio(hex1, hex2) {
229
+ const l1 = relativeLuminance(hex1);
230
+ const l2 = relativeLuminance(hex2);
231
+ const lighter = Math.max(l1, l2);
232
+ const darker = Math.min(l1, l2);
233
+ return (lighter + 0.05) / (darker + 0.05);
213
234
  }
214
235
  function deriveSkinColors(skin) {
215
236
  const sL = luminance(skin);
@@ -243,11 +264,20 @@ function deriveSkinColors(skin) {
243
264
  const lipRaw = blend(skin, lipBase, Math.min(0.82, lipBlend));
244
265
  const [lr, lg, lb] = hexToRgb(lipRaw);
245
266
  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);
267
+ let lipColor = lipD < 60 ? blend(skin, lipBase, 0.78) : lipRaw;
268
+ let attempts = 0;
269
+ while (contrastRatio(lipColor, skin) < 1.8 && attempts < 12) {
270
+ lipColor = darken(lipColor, 0.06);
271
+ attempts++;
272
+ }
273
+ const browColor = isDark ? lighten(skin, sL < 80 ? 0.35 : sL < 100 ? 0.32 : 0.25) : darken(skin, 0.55);
274
+ const noseShift = 0.2 + 0.06 * (1 - Math.abs(sL - 100) / 140);
275
+ const noseFill = isDark ? lighten(skin, noseShift) : darken(skin, noseShift);
249
276
  const earT = Math.max(0, Math.min(1, (sL - 100) / 60));
250
- const earFill = blend(lighten(skin, 0.08), skinMid, earT);
277
+ let earFill = blend(lighten(skin, 0.08), skinMid, earT);
278
+ if (contrastRatio(earFill, skin) < 1.05) {
279
+ earFill = isDark ? lighten(earFill, 0.06) : darken(earFill, 0.06);
280
+ }
251
281
  const earShadow = darken(skin, 0.1 + 0.06 * (1 - Math.min(1, sL / 160)));
252
282
  const lidColor = isDark ? lighten(skin, 0.18) : darken(skin, 0.15);
253
283
  const ewT = Math.max(0, Math.min(1, (sL - 60) / 180));
@@ -271,10 +301,209 @@ function deriveSkinColors(skin) {
271
301
  accessoryColor
272
302
  };
273
303
  }
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;
304
+
305
+ // src/core/describe.ts
306
+ var SKIN_TONES = {
307
+ 0: "porcelain",
308
+ 1: "ivory",
309
+ 2: "fair",
310
+ 3: "light",
311
+ 4: "sand",
312
+ 5: "golden",
313
+ 6: "warm",
314
+ 7: "caramel",
315
+ 8: "brown",
316
+ 9: "deep"
317
+ };
318
+ var EYE_STYLES = {
319
+ 0: "round, wide-open",
320
+ 1: "small and minimal",
321
+ 2: "almond-shaped",
322
+ 3: "wide and expressive",
323
+ 4: "relaxed, half-lidded",
324
+ 5: "joyful, crescent-shaped",
325
+ 6: "bright and sparkling",
326
+ 7: "gentle and narrow",
327
+ 8: "side-looking, shifted"
328
+ };
329
+ var EYE_COLORS_DESC = {
330
+ 0: "dark brown",
331
+ 1: "blue",
332
+ 2: "green",
333
+ 3: "hazel",
334
+ 4: "gray",
335
+ 5: "amber",
336
+ 6: "violet",
337
+ 7: "steel gray"
338
+ };
339
+ var EYEBROW_STYLES = {
340
+ 0: "wispy",
341
+ 1: "straight",
342
+ 2: "natural",
343
+ 3: "elegantly arched",
344
+ 4: "sharply angled",
345
+ 5: "worried, furrowed",
346
+ 6: "bushy",
347
+ 7: "thin, delicate"
348
+ };
349
+ var NOSE_STYLES = {
350
+ 0: "a subtle shadow nose",
351
+ 1: "a small button nose",
352
+ 2: "a soft curved nose",
353
+ 3: "a button nose with visible nostrils",
354
+ 4: "a pointed nose",
355
+ 5: "a wide, broad nose",
356
+ 6: "a nose with a visible bridge",
357
+ 7: "a small snub nose"
358
+ };
359
+ var MOUTH_STYLES = {
360
+ 0: "a gentle smile",
361
+ 1: "a calm, neutral expression",
362
+ 2: "a happy grin",
363
+ 3: "a surprised O-shaped mouth",
364
+ 4: "a confident smirk",
365
+ 5: "a wide, toothy grin",
366
+ 6: "a flat, straight expression",
367
+ 7: "a soft pout"
368
+ };
369
+ var ACCESSORY_DESC = {
370
+ 0: "",
371
+ 1: "a beauty mark",
372
+ 2: "round glasses",
373
+ 3: "rectangular glasses",
374
+ 4: "a dangling earring",
375
+ 5: "a headband",
376
+ 6: "freckles",
377
+ 7: "stud earrings",
378
+ 8: "aviator sunglasses",
379
+ 9: "a band-aid",
380
+ 10: "a left eyebrow slit",
381
+ 11: "a right eyebrow slit"
382
+ };
383
+ var BG_COLORS_DESC = {
384
+ 0: "rose",
385
+ 1: "olive",
386
+ 2: "sage",
387
+ 3: "fern",
388
+ 4: "mint",
389
+ 5: "ocean",
390
+ 6: "sky",
391
+ 7: "lavender",
392
+ 8: "orchid",
393
+ 9: "blush",
394
+ 10: "lilac",
395
+ 11: "seafoam"
396
+ };
397
+ function describeAppearance(walletAddress, options) {
398
+ const traits = generateTraits(walletAddress);
399
+ const {
400
+ includeBackground = true,
401
+ format = "paragraph",
402
+ perspective = "third",
403
+ name
404
+ } = options ?? {};
405
+ if (format === "structured") return buildStructured(traits, includeBackground);
406
+ if (format === "compact") return buildCompact(traits);
407
+ return buildParagraph(traits, perspective, name, includeBackground);
408
+ }
409
+ function describeTraits(traits, options) {
410
+ const {
411
+ includeBackground = true,
412
+ format = "paragraph",
413
+ perspective = "third",
414
+ name
415
+ } = options ?? {};
416
+ if (format === "structured") return buildStructured(traits, includeBackground);
417
+ if (format === "compact") return buildCompact(traits);
418
+ return buildParagraph(traits, perspective, name, includeBackground);
419
+ }
420
+ function buildParagraph(t, perspective, name, includeBg) {
421
+ const parts = [];
422
+ const ai = effectiveAccessory(t);
423
+ const subject = perspective === "first" ? name ? `I'm ${name}. I have` : "I have" : name ? `${name} has` : "This SolFace has";
424
+ const im = perspective === "first" ? "I'm" : "They're";
425
+ parts.push(`${subject} a squircle face with ${SKIN_TONES[t.skinColor] ?? "warm"} skin`);
426
+ const eyeStyle = EYE_STYLES[t.eyeStyle] ?? "round";
427
+ const eyeColor = EYE_COLORS_DESC[t.eyeColor] ?? "dark";
428
+ parts.push(`${eyeStyle} ${eyeColor} eyes`);
429
+ const brows = EYEBROW_STYLES[t.eyebrows];
430
+ if (brows) parts.push(`${brows} eyebrows`);
431
+ parts.push(perspective === "first" ? "and am bald" : "and is bald");
432
+ let desc = parts[0];
433
+ if (parts.length > 2) {
434
+ desc += ", " + parts.slice(1, -1).join(", ") + ", " + parts[parts.length - 1];
435
+ } else if (parts.length === 2) {
436
+ desc += " and " + parts[1];
437
+ }
438
+ desc += ".";
439
+ const nose = NOSE_STYLES[t.nose];
440
+ if (nose) {
441
+ const noseSubject = perspective === "first" ? "I have" : (name ?? "They") + (name ? " has" : " have");
442
+ desc += ` ${noseSubject} ${nose}.`;
443
+ }
444
+ const acc = ACCESSORY_DESC[ai];
445
+ if (acc) {
446
+ desc += ` ${im} wearing ${acc}.`;
447
+ }
448
+ const mouth = MOUTH_STYLES[t.mouth] ?? "a smile";
449
+ const mouthVerb = perspective === "first" ? "I have" : (name ?? "They") + (name ? " has" : " have");
450
+ desc += ` ${mouthVerb} ${mouth}.`;
451
+ if (includeBg) {
452
+ const bg = BG_COLORS_DESC[t.bgColor] ?? "colorful";
453
+ desc += ` The background is ${bg}.`;
454
+ }
455
+ return desc;
456
+ }
457
+ function buildStructured(t, includeBg) {
458
+ const ai = effectiveAccessory(t);
459
+ const lines = [
460
+ `Face: squircle`,
461
+ `Skin: ${SKIN_TONES[t.skinColor] ?? "warm"}`,
462
+ `Eyes: ${EYE_STYLES[t.eyeStyle] ?? "round"}, ${EYE_COLORS_DESC[t.eyeColor] ?? "dark"}`,
463
+ `Eyebrows: ${EYEBROW_STYLES[t.eyebrows] ?? "wispy"}`
464
+ ];
465
+ const nose = NOSE_STYLES[t.nose];
466
+ if (nose) lines.push(`Nose: ${nose.replace(/^a /, "")}`);
467
+ lines.push(`Mouth: ${MOUTH_STYLES[t.mouth] ?? "smile"}`);
468
+ lines.push("Hair: bald");
469
+ const acc = ACCESSORY_DESC[ai];
470
+ if (acc) lines.push(`Accessory: ${acc}`);
471
+ if (includeBg) {
472
+ lines.push(`Background: ${BG_COLORS_DESC[t.bgColor] ?? "colorful"}`);
473
+ }
474
+ return lines.join("\n");
475
+ }
476
+ function buildCompact(t) {
477
+ const ai = effectiveAccessory(t);
478
+ const parts = [];
479
+ parts.push(`squircle face`);
480
+ parts.push(`${SKIN_TONES[t.skinColor] ?? "warm"} skin`);
481
+ parts.push(`${EYE_COLORS_DESC[t.eyeColor] ?? "dark"} ${EYE_STYLES[t.eyeStyle] ?? "round"} eyes`);
482
+ parts.push("bald");
483
+ const acc = ACCESSORY_DESC[ai];
484
+ if (acc) parts.push(acc);
485
+ parts.push((MOUTH_STYLES[t.mouth] ?? "smiling").replace(/^a /, ""));
486
+ return parts.join(", ");
487
+ }
488
+ function solFaceAltText(walletAddress) {
489
+ return `SolFace avatar: ${describeAppearance(walletAddress, { format: "compact", includeBackground: false })}`;
490
+ }
491
+ function agentAppearancePrompt(walletAddress, agentName) {
492
+ const desc = describeAppearance(walletAddress, {
493
+ perspective: "first",
494
+ name: agentName,
495
+ includeBackground: false,
496
+ format: "paragraph"
497
+ });
498
+ const hash = (djb2Simple(walletAddress) >>> 0).toString(16).padStart(8, "0");
499
+ return `My visual identity is a SolFace avatar (ID: ${hash}) derived from my wallet address. ${desc} This appearance is deterministic \u2014 anyone who looks up my wallet will see the same face.`;
500
+ }
501
+ function djb2Simple(str) {
502
+ let hash = 5381;
503
+ for (let i = 0; i < str.length; i++) {
504
+ hash = (hash << 5) + hash + str.charCodeAt(i) | 0;
505
+ }
506
+ return hash >>> 0;
278
507
  }
279
508
 
280
509
  // src/core/renderer.ts
@@ -290,12 +519,9 @@ function buildDefs(id, skin, skinHi, skinLo, hairCol, bgCol, cheekColor, cheekOp
290
519
  let d = "<defs>";
291
520
  d += `<linearGradient id="${id}sg" x1="0" y1="0" x2="0" y2="1">`;
292
521
  d += `<stop offset="0%" stop-color="${skinHi}"/>`;
522
+ d += `<stop offset="50%" stop-color="${skin}"/>`;
293
523
  d += `<stop offset="100%" stop-color="${skinLo}"/>`;
294
524
  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
525
  d += `<linearGradient id="${id}bg" x1="0" y1="0" x2="1" y2="1">`;
300
526
  d += `<stop offset="0%" stop-color="${lighten(bgCol, 0.12)}"/>`;
301
527
  d += `<stop offset="100%" stop-color="${darken(bgCol, 0.12)}"/>`;
@@ -321,18 +547,8 @@ function buildDefs(id, skin, skinHi, skinLo, hairCol, bgCol, cheekColor, cheekOp
321
547
  d += "</defs>";
322
548
  return d;
323
549
  }
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
- }
550
+ function renderHairBack(_hi, _id, _flat) {
551
+ return "";
336
552
  }
337
553
  function renderEars(earFill, earShadow) {
338
554
  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"/>`;
@@ -346,35 +562,8 @@ function renderFaceOverlays(id, flat) {
346
562
  if (flat) return "";
347
563
  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
564
  }
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
- }
565
+ function renderHairFront(_hi, _id, _hairCol, _skin, _flat) {
566
+ return "";
378
567
  }
379
568
  function renderEyes(ei, eyeCol, eyeWhite, lidColor, full) {
380
569
  const lx = 25, rx = 39, y = 33;
@@ -389,8 +578,10 @@ function renderEyes(ei, eyeCol, eyeWhite, lidColor, full) {
389
578
  if (full) s += `<circle cx="${rx + 1.5}" cy="${y - 1}" r="0.7" fill="white" opacity="0.8"/>`;
390
579
  break;
391
580
  case 1:
392
- s += `<circle cx="${lx}" cy="${y}" r="2" fill="${eyeCol}"/>`;
393
- s += `<circle cx="${rx}" cy="${y}" r="2" fill="${eyeCol}"/>`;
581
+ s += `<circle cx="${lx}" cy="${y}" r="2.2" fill="${eyeCol}"/>`;
582
+ if (full) s += `<circle cx="${lx + 0.5}" cy="${y - 0.5}" r="0.5" fill="white" opacity="0.4"/>`;
583
+ s += `<circle cx="${rx}" cy="${y}" r="2.2" fill="${eyeCol}"/>`;
584
+ if (full) s += `<circle cx="${rx + 0.5}" cy="${y - 0.5}" r="0.5" fill="white" opacity="0.4"/>`;
394
585
  break;
395
586
  case 2:
396
587
  s += `<ellipse cx="${lx}" cy="${y}" rx="4.5" ry="2.8" fill="${eyeWhite}"/>`;
@@ -417,24 +608,16 @@ function renderEyes(ei, eyeCol, eyeWhite, lidColor, full) {
417
608
  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
609
  break;
419
610
  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"/>`;
611
+ s += `<path d="M${lx - 4} ${y} Q${lx} ${y + 4.5} ${lx + 4} ${y}" fill="none" stroke="${eyeCol}" stroke-width="2" stroke-linecap="round"/>`;
612
+ s += `<path d="M${rx - 4} ${y} Q${rx} ${y + 4.5} ${rx + 4} ${y}" fill="none" stroke="${eyeCol}" stroke-width="2" stroke-linecap="round"/>`;
422
613
  break;
423
614
  case 6:
424
615
  s += `<circle cx="${lx}" cy="${y}" r="3.5" fill="${eyeWhite}"/>`;
425
616
  s += `<circle cx="${lx + 0.5}" cy="${y}" r="2" fill="${eyeCol}"/>`;
426
617
  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
618
  s += `<circle cx="${rx}" cy="${y}" r="3.5" fill="${eyeWhite}"/>`;
432
619
  s += `<circle cx="${rx + 0.5}" cy="${y}" r="2" fill="${eyeCol}"/>`;
433
620
  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
621
  break;
439
622
  case 7:
440
623
  s += `<ellipse cx="${lx}" cy="${y}" rx="4.5" ry="1.5" fill="${eyeWhite}"/>`;
@@ -442,6 +625,14 @@ function renderEyes(ei, eyeCol, eyeWhite, lidColor, full) {
442
625
  s += `<ellipse cx="${rx}" cy="${y}" rx="4.5" ry="1.5" fill="${eyeWhite}"/>`;
443
626
  s += `<ellipse cx="${rx + 0.5}" cy="${y}" rx="2.2" ry="1.2" fill="${eyeCol}"/>`;
444
627
  break;
628
+ case 8:
629
+ s += `<circle cx="${lx}" cy="${y}" r="3.5" fill="${eyeWhite}"/>`;
630
+ s += `<circle cx="${lx - 1}" cy="${y}" r="2" fill="${eyeCol}"/>`;
631
+ if (full) s += `<circle cx="${lx - 0.3}" cy="${y - 0.8}" r="0.7" fill="white" opacity="0.8"/>`;
632
+ s += `<circle cx="${rx}" cy="${y}" r="3.5" fill="${eyeWhite}"/>`;
633
+ s += `<circle cx="${rx - 1}" cy="${y}" r="2" fill="${eyeCol}"/>`;
634
+ if (full) s += `<circle cx="${rx - 0.3}" cy="${y - 0.8}" r="0.7" fill="white" opacity="0.8"/>`;
635
+ break;
445
636
  default:
446
637
  s += `<circle cx="${lx}" cy="${y}" r="3.5" fill="${eyeWhite}"/>`;
447
638
  s += `<circle cx="${lx + 0.8}" cy="${y}" r="2" fill="${eyeCol}"/>`;
@@ -454,7 +645,7 @@ function renderEyes(ei, eyeCol, eyeWhite, lidColor, full) {
454
645
  }
455
646
  return s;
456
647
  }
457
- function renderEyebrows(bi, browColor) {
648
+ function renderEyebrows(bi, browColor, full = true) {
458
649
  const lx = 25, rx = 39, y = 27;
459
650
  switch (bi) {
460
651
  case 0:
@@ -467,6 +658,14 @@ function renderEyebrows(bi, browColor) {
467
658
  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
659
  case 4:
469
660
  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"/>`;
661
+ case 5:
662
+ return `<line x1="${lx - 3}" y1="${y - 1}" x2="${lx + 3}" y2="${y + 1}" stroke="${browColor}" stroke-width="1.1" stroke-linecap="round"/><line x1="${rx - 3}" y1="${y + 1}" x2="${rx + 3}" y2="${y - 1}" stroke="${browColor}" stroke-width="1.1" stroke-linecap="round"/>`;
663
+ case 6: {
664
+ const bw = full ? "2.0" : "1.5";
665
+ return `<path d="M${lx - 4} ${y + 0.5} Q${lx} ${y - 2} ${lx + 4} ${y + 0.5}" fill="none" stroke="${browColor}" stroke-width="${bw}" stroke-linecap="round"/><path d="M${rx - 4} ${y + 0.5} Q${rx} ${y - 2} ${rx + 4} ${y + 0.5}" fill="none" stroke="${browColor}" stroke-width="${bw}" stroke-linecap="round"/>`;
666
+ }
667
+ case 7:
668
+ return `<path d="M${lx - 3.5} ${y} Q${lx} ${y - 1.5} ${lx + 3.5} ${y}" fill="none" stroke="${browColor}" stroke-width="0.5" stroke-linecap="round"/><path d="M${rx - 3.5} ${y} Q${rx} ${y - 1.5} ${rx + 3.5} ${y}" fill="none" stroke="${browColor}" stroke-width="0.5" stroke-linecap="round"/>`;
470
669
  default:
471
670
  return "";
472
671
  }
@@ -482,6 +681,14 @@ function renderNose(ni, noseFill) {
482
681
  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
682
  case 3:
484
683
  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"/>`;
684
+ case 4:
685
+ return `<path d="M${cx} ${y - 2} L${cx - 2} ${y + 1.5} L${cx + 2} ${y + 1.5} Z" fill="${noseFill}" opacity="0.4"/>`;
686
+ case 5:
687
+ return `<ellipse cx="${cx}" cy="${y}" rx="3.5" ry="1.5" fill="${noseFill}" opacity="0.35"/>`;
688
+ case 6:
689
+ return `<line x1="${cx}" y1="${y - 3}" x2="${cx}" y2="${y + 1}" stroke="${noseFill}" stroke-width="1.2" stroke-linecap="round" opacity="0.4"/>`;
690
+ case 7:
691
+ return `<circle cx="${cx}" cy="${y + 0.5}" r="2" fill="${noseFill}" opacity="0.35"/><ellipse cx="${cx}" cy="${y - 0.5}" rx="1" ry="0.5" fill="${noseFill}" opacity="0.15"/>`;
485
692
  default:
486
693
  return `<ellipse cx="${cx}" cy="${y}" rx="2" ry="1.2" fill="${noseFill}" opacity="0.35"/>`;
487
694
  }
@@ -503,20 +710,20 @@ function renderMouth(mi, lipColor, isDark) {
503
710
  case 5:
504
711
  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
712
  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"/>`;
713
+ return `<path d="M${cx - 4} ${y + 0.5} Q${cx} ${y + 1.5} ${cx + 4} ${y + 0.5}" fill="none" stroke="${lipColor}" stroke-width="1.4" stroke-linecap="round"/>`;
507
714
  case 7:
508
715
  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
716
  default:
510
717
  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
718
  }
512
719
  }
513
- function renderAccessory(ai, accessoryColor, glassesColor, earringColor, headbandColor) {
720
+ function renderAccessory(ai, accessoryColor, glassesColor, earringColor, headbandColor, beautyMarkColor = "#3a2a2a", freckleColor = "#a0785a", skinColor = "#E8BA8B") {
514
721
  switch (ai) {
515
722
  case 0:
516
723
  return "";
517
724
  // None
518
725
  case 1:
519
- return `<circle cx="40" cy="44" r="0.8" fill="#3a2a2a"/>`;
726
+ return `<circle cx="40" cy="44" r="0.8" fill="${beautyMarkColor}"/>`;
520
727
  case 2:
521
728
  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
729
  case 3:
@@ -526,13 +733,17 @@ function renderAccessory(ai, accessoryColor, glassesColor, earringColor, headban
526
733
  case 5:
527
734
  return `<rect x="13" y="20" width="38" height="3.5" rx="1.5" fill="${headbandColor}" opacity="0.85"/>`;
528
735
  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>`;
736
+ return `<g fill="${freckleColor}" 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
737
  case 7:
531
738
  return `<circle cx="10" cy="37" r="1.2" fill="${earringColor}"/><circle cx="54" cy="37" r="1.2" fill="${earringColor}"/>`;
532
739
  case 8:
533
740
  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
741
  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>`;
742
+ return `<g><rect x="38" y="38" width="9" height="4.5" rx="1.2" fill="#f0d0a0" transform="rotate(-15 42 40)"/><rect x="39.5" y="38.5" width="6" height="3.5" rx="0.8" fill="#f5ddb5" transform="rotate(-15 42 40)"/><circle cx="42.5" cy="40.25" r="0.5" fill="#d4b898" transform="rotate(-15 42 40)"/></g>`;
743
+ case 10:
744
+ return `<line x1="23" y1="24.8" x2="23.8" y2="29.2" stroke="${skinColor}" stroke-width="1.3" stroke-linecap="butt"/>`;
745
+ case 11:
746
+ return `<line x1="41" y1="24.8" x2="40.2" y2="29.2" stroke="${skinColor}" stroke-width="1.3" stroke-linecap="butt"/>`;
536
747
  default:
537
748
  return "";
538
749
  }
@@ -562,14 +773,17 @@ function renderSolFaceSVG(walletAddress, options) {
562
773
  const glassesColor = theme?.glassesColor ?? "#4a4a5a";
563
774
  const earringColor = theme?.earringColor ?? blend(skin, "#d4a840", 0.4);
564
775
  const headbandColor = theme?.headbandColor ?? blend(hairCol, "#c04040", 0.5);
776
+ const beautyMarkColor = theme?.beautyMarkColor ?? "#3a2a2a";
777
+ const freckleColor = theme?.freckleColor ?? "#a0785a";
565
778
  const id = "sf" + djb22(walletAddress).toString(36);
566
779
  const cheekEnabled = theme?.cheekEnabled ?? true;
567
780
  const cheekColor = theme?.cheekColor ?? derived.cheekColor;
568
781
  const cheekOpacity = theme?.cheekOpacity ?? derived.cheekOpacity;
569
- const hi = traits.hairStyle % 10;
782
+ traits.hairStyle % 10;
570
783
  const ai = effectiveAccessory(traits);
571
784
  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}>`;
785
+ const altText = solFaceAltText(walletAddress).replace(/"/g, "&quot;");
786
+ let svg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" width="${size}" height="${size}"${classAttr} role="img" aria-label="${altText}">`;
573
787
  const glowIntensity = theme?.glowIntensity ?? 0.1;
574
788
  svg += buildDefs(id, skin, derived.skinHi, derived.skinLo, hairCol, bgCol, cheekColor, cheekOpacity, flat, full && cheekEnabled, glowIntensity);
575
789
  const blinkEnabled = !!enableBlink;
@@ -582,29 +796,29 @@ function renderSolFaceSVG(walletAddress, options) {
582
796
  }
583
797
  const bgFill = flat ? bgCol : `url(#${id}bg)`;
584
798
  svg += `<rect x="0" y="0" width="64" height="64" fill="${bgFill}" opacity="${bgOpacity}" rx="${bgRadius}"/>`;
585
- svg += renderHairBack(hi, id, flat);
586
- svg += renderEars(derived.earFill, derived.earShadow);
799
+ if (theme?.hairEnabled !== false) svg += renderHairBack();
800
+ if (theme?.earsEnabled !== false) svg += renderEars(theme?.earColor ?? derived.earFill, derived.earShadow);
587
801
  const skinOpacity = theme?.skinOpacity ?? 1;
588
802
  svg += renderFace(id, skin, flat, skinOpacity);
589
803
  const shadowEnabled = theme?.shadowEnabled ?? true;
590
804
  if (full && cheekEnabled && shadowEnabled) {
591
805
  svg += renderFaceOverlays(id, flat);
592
806
  }
593
- if (ai === 5) {
594
- svg += renderAccessory(5, accColor, glassesColor, earringColor, headbandColor);
807
+ if (theme?.hairEnabled !== false) svg += renderHairFront();
808
+ if (ai === 5 && theme?.accessoriesEnabled !== false) {
809
+ svg += renderAccessory(5, accColor, glassesColor, earringColor, headbandColor, beautyMarkColor, freckleColor, skin);
595
810
  }
596
- svg += renderHairFront(hi, id, hairCol, skin, flat);
597
811
  if (blinkEnabled) {
598
812
  const uid = `sf-${walletAddress.slice(0, 8)}`;
599
813
  svg += `<g class="${uid}-eyes">`;
600
814
  }
601
- svg += renderEyes(traits.eyeStyle % 8, eyeCol, eyeWhite, derived.lidColor, full);
815
+ svg += renderEyes(traits.eyeStyle % 9, eyeCol, eyeWhite, theme?.lidColor ?? derived.lidColor, full);
602
816
  if (blinkEnabled) svg += `</g>`;
603
- svg += renderEyebrows(traits.eyebrows % 5, browColor);
604
- svg += renderNose(traits.nose % 4, noseFill);
817
+ if (theme?.eyebrowsEnabled !== false) svg += renderEyebrows(traits.eyebrows % 8, browColor, full);
818
+ if (theme?.noseEnabled !== false) svg += renderNose(traits.nose % 8, noseFill);
605
819
  svg += renderMouth(traits.mouth % 8, lipColor, derived.isDark);
606
- if (ai !== 0 && ai !== 5) {
607
- svg += renderAccessory(ai, accColor, glassesColor, earringColor, headbandColor);
820
+ if (ai !== 0 && ai !== 5 && theme?.accessoriesEnabled !== false) {
821
+ svg += renderAccessory(ai, accColor, glassesColor, earringColor, headbandColor, beautyMarkColor, freckleColor, skin);
608
822
  }
609
823
  if (theme?.border) {
610
824
  svg += `<rect x="0" y="0" width="64" height="64" fill="none" stroke="${theme.border.color}" stroke-width="${theme.border.width}" rx="${bgRadius}"/>`;
@@ -621,6 +835,6 @@ function renderSolFaceBase64(walletAddress, options) {
621
835
  return `data:image/svg+xml;base64,${btoa(svg)}`;
622
836
  }
623
837
 
624
- 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 };
625
- //# sourceMappingURL=chunk-3CE7Q44S.js.map
626
- //# sourceMappingURL=chunk-3CE7Q44S.js.map
838
+ export { BG_COLORS, EYE_COLORS, HAIR_COLORS, SKIN_COLORS, agentAppearancePrompt, blend, contrastRatio, darken, deriveSkinColors, describeAppearance, describeTraits, effectiveAccessory, generateTraits, getTraitLabels, hexToRgb, lighten, luminance, mergeTheme, renderSolFaceBase64, renderSolFaceDataURI, renderSolFaceSVG, resolveTheme, rgbToHex, solFaceAltText, traitHash };
839
+ //# sourceMappingURL=chunk-N5GDLCCL.js.map
840
+ //# sourceMappingURL=chunk-N5GDLCCL.js.map