pixelpeeps 1.0.1 → 1.0.3

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/dist/index.d.mts CHANGED
@@ -11,14 +11,7 @@ type FaceProps = {
11
11
  r: number;
12
12
  color: string;
13
13
  eyeShape?: "circle" | "ellipse" | "line" | "wink" | "sleepy" | "surprised" | "random";
14
- mouthShape?: "smile" | "frown" | "flat" | "zigzag" | "open" | "random";
15
- glasses?: "none" | "round" | "square" | "random";
16
- eyebrows?: boolean | "random";
17
- blush?: boolean | "random";
18
- freckles?: boolean | "random";
19
- ears?: boolean | "random";
20
- hat?: "none" | "beanie" | "cap" | "random";
21
- outline?: boolean;
14
+ mouthShape?: "smile" | "frown" | "flat" | "zigzag" | "random";
22
15
  pupilColor?: string | "auto";
23
16
  eyeShine?: boolean | "random";
24
17
  rand: () => number;
@@ -30,7 +23,6 @@ type AvatarProps = {
30
23
  mirrored?: boolean;
31
24
  bg?: [string, string] | string | "random";
32
25
  headShape?: HeadShape;
33
- square?: boolean;
34
26
  alignX?: AlignX;
35
27
  alignY?: AlignY;
36
28
  padding?: number;
@@ -38,19 +30,12 @@ type AvatarProps = {
38
30
  variant?: Variant;
39
31
  eyeShape?: FaceProps["eyeShape"];
40
32
  mouthShape?: FaceProps["mouthShape"];
41
- glasses?: FaceProps["glasses"];
42
- eyebrows?: FaceProps["eyebrows"];
43
- blush?: FaceProps["blush"];
44
- freckles?: FaceProps["freckles"];
45
- ears?: FaceProps["ears"];
46
- hat?: FaceProps["hat"];
47
- outline?: boolean;
48
33
  pupilColor?: string | "auto";
49
34
  eyeShine?: boolean;
50
35
  className?: string;
51
36
  style?: React.CSSProperties;
52
37
  title?: string;
53
38
  };
54
- declare function Avatar({ name, size, pixelSize, mirrored, bg, colors, headShape, square, alignX, alignY, padding, variant, className, style, title, eyeShape, mouthShape, glasses, eyebrows, blush, freckles, ears, hat, outline, pupilColor, eyeShine, }: AvatarProps): react_jsx_runtime.JSX.Element;
39
+ declare function Avatar({ name, size, bg, colors }: AvatarProps): react_jsx_runtime.JSX.Element;
55
40
 
56
41
  export { Avatar, Avatar as default };
package/dist/index.d.ts CHANGED
@@ -11,14 +11,7 @@ type FaceProps = {
11
11
  r: number;
12
12
  color: string;
13
13
  eyeShape?: "circle" | "ellipse" | "line" | "wink" | "sleepy" | "surprised" | "random";
14
- mouthShape?: "smile" | "frown" | "flat" | "zigzag" | "open" | "random";
15
- glasses?: "none" | "round" | "square" | "random";
16
- eyebrows?: boolean | "random";
17
- blush?: boolean | "random";
18
- freckles?: boolean | "random";
19
- ears?: boolean | "random";
20
- hat?: "none" | "beanie" | "cap" | "random";
21
- outline?: boolean;
14
+ mouthShape?: "smile" | "frown" | "flat" | "zigzag" | "random";
22
15
  pupilColor?: string | "auto";
23
16
  eyeShine?: boolean | "random";
24
17
  rand: () => number;
@@ -30,7 +23,6 @@ type AvatarProps = {
30
23
  mirrored?: boolean;
31
24
  bg?: [string, string] | string | "random";
32
25
  headShape?: HeadShape;
33
- square?: boolean;
34
26
  alignX?: AlignX;
35
27
  alignY?: AlignY;
36
28
  padding?: number;
@@ -38,19 +30,12 @@ type AvatarProps = {
38
30
  variant?: Variant;
39
31
  eyeShape?: FaceProps["eyeShape"];
40
32
  mouthShape?: FaceProps["mouthShape"];
41
- glasses?: FaceProps["glasses"];
42
- eyebrows?: FaceProps["eyebrows"];
43
- blush?: FaceProps["blush"];
44
- freckles?: FaceProps["freckles"];
45
- ears?: FaceProps["ears"];
46
- hat?: FaceProps["hat"];
47
- outline?: boolean;
48
33
  pupilColor?: string | "auto";
49
34
  eyeShine?: boolean;
50
35
  className?: string;
51
36
  style?: React.CSSProperties;
52
37
  title?: string;
53
38
  };
54
- declare function Avatar({ name, size, pixelSize, mirrored, bg, colors, headShape, square, alignX, alignY, padding, variant, className, style, title, eyeShape, mouthShape, glasses, eyebrows, blush, freckles, ears, hat, outline, pupilColor, eyeShine, }: AvatarProps): react_jsx_runtime.JSX.Element;
39
+ declare function Avatar({ name, size, bg, colors }: AvatarProps): react_jsx_runtime.JSX.Element;
55
40
 
56
41
  export { Avatar, Avatar as default };
package/dist/index.js CHANGED
@@ -35,7 +35,6 @@ __export(index_exports, {
35
35
  module.exports = __toCommonJS(index_exports);
36
36
 
37
37
  // src/Avatar.tsx
38
- var React = __toESM(require("react"));
39
38
  var import_nice_color_palettes = __toESM(require("nice-color-palettes"));
40
39
  var import_jsx_runtime = require("react/jsx-runtime");
41
40
  function cyrb128(str) {
@@ -99,9 +98,6 @@ function yiq(hex) {
99
98
  const { r, g, b } = hexToRgb(hex);
100
99
  return (r * 299 + g * 587 + b * 114) / 1e3;
101
100
  }
102
- function bestFeatureColor(base) {
103
- return yiq(base) > 150 ? "#111827" : "#ffffff";
104
- }
105
101
  var NICE_PALETTES = import_nice_color_palettes.default && Array.isArray(import_nice_color_palettes.default) ? import_nice_color_palettes.default : [["#73a9ff", "#fef3c7", "#ffd6a5", "#d4b4ff", "#a7f3d0"]];
106
102
  function resolveBg(rand, bg) {
107
103
  if (!bg || bg === "random") {
@@ -133,13 +129,6 @@ function Face({
133
129
  color,
134
130
  eyeShape: eyeShapeProp,
135
131
  mouthShape: mouthShapeProp,
136
- glasses: glassesProp,
137
- eyebrows: eyebrowsProp,
138
- blush: blushProp,
139
- freckles: frecklesProp,
140
- ears: earsProp,
141
- hat: hatProp,
142
- outline,
143
132
  pupilColor,
144
133
  eyeShine: eyeShineProp,
145
134
  rand
@@ -149,387 +138,77 @@ function Face({
149
138
  return prop;
150
139
  };
151
140
  const eyeShape = decide(eyeShapeProp ?? "random", ["circle", "ellipse", "line", "wink", "sleepy", "surprised"]);
152
- const mouthShape = decide(mouthShapeProp ?? "random", ["smile", "frown", "flat", "zigzag", "open"]);
153
- const glasses = decide(glassesProp ?? "random", ["none", "round", "square"]);
154
- const eyebrows = decide(eyebrowsProp ?? "random", [true, false]);
155
- const blush = decide(blushProp ?? "random", [true, false]);
156
- const freckles = decide(frecklesProp ?? "random", [true, false]);
157
- const ears = decide(earsProp ?? "random", [true, false]);
158
- const hat = decide(hatProp ?? "random", ["none", "beanie", "cap"]);
141
+ const mouthShape = decide(mouthShapeProp ?? "random", ["smile", "frown", "flat", "zigzag"]);
159
142
  const eyeShine = decide(eyeShineProp ?? "random", [true, false]);
160
- const eyeOffsetX = r * (0.34 + rand() * 0.06);
161
- const eyeOffsetY = r * (0.2 + rand() * 0.06);
162
- const eyeR = Math.max(2, Math.round(r * (0.08 + rand() * 0.02)));
163
- const pupilR = Math.max(1, Math.round(eyeR * (0.45 + rand() * 0.25)));
164
- const mouthWidth = r * (0.7 + rand() * 0.3);
165
- const mouthLift = r * (0.18 + rand() * 0.16);
143
+ const eyeOffsetX = r * 0.36;
144
+ const eyeOffsetY = r * 0.22;
145
+ const eyeR = Math.max(2, r * 0.08);
146
+ const pupilR = eyeR * 0.5;
147
+ const mouthWidth = r * 0.7;
148
+ const mouthLift = r * 0.2;
166
149
  const mouthStroke = Math.max(1, Math.round(r * 0.06));
167
- let finalPupilColor = "#111827";
168
- if (pupilColor && pupilColor !== "auto") finalPupilColor = pupilColor;
169
- else finalPupilColor = yiq(color) > 150 ? "#111827" : "#ffffff";
150
+ const finalPupilColor = pupilColor && pupilColor !== "auto" ? pupilColor : yiq(color) > 150 ? "#111827" : "#ffffff";
170
151
  const x0 = cx - mouthWidth / 2;
171
152
  const x1 = cx + mouthWidth / 2;
172
153
  const my = cy + mouthLift;
173
- const browY = cy - eyeOffsetY - eyeR * 1.6;
174
- const browLen = eyeR * 2.2;
175
- const mouthPathSmile = (() => {
176
- const mouthCurve = (rand() - 0.5) * 0.8;
177
- const cxQ = cx;
178
- const cyQ = my + r * (-0.25 * mouthCurve - 0.1);
179
- return `M ${x0} ${my} Q ${cxQ} ${cyQ} ${x1} ${my}`;
180
- })();
181
- const mouthPathFrown = (() => {
182
- const mouthCurve = (rand() - 0.5) * 0.8;
183
- const cxQ = cx;
184
- const cyQ = my + r * (0.25 * mouthCurve + 0.08);
185
- return `M ${x0} ${my} Q ${cxQ} ${cyQ} ${x1} ${my}`;
186
- })();
187
- const mouthPathZigzag = (() => {
188
- const segs = 6;
189
- const step = mouthWidth / (segs - 1);
190
- let d = `M ${x0} ${my}`;
191
- for (let i = 1; i < segs; i++) {
192
- const px = x0 + step * i;
193
- const py = my + (i % 2 === 0 ? -r * 0.08 : r * 0.08);
194
- d += ` L ${px} ${py}`;
195
- }
196
- return d;
197
- })();
198
- const mouthOpen = (() => {
199
- const w = mouthWidth;
200
- const h = r * 0.26;
201
- const rx = w / 2;
202
- const ry = h / 2;
203
- return { rx, ry, cy: my + ry * 0.25 };
204
- })();
205
- const frecklesCoords = [
206
- { x: cx - eyeOffsetX * 1.1, y: cy + eyeOffsetY * 0.4 },
207
- { x: cx - eyeOffsetX * 0.6, y: cy + eyeOffsetY * 0.6 },
208
- { x: cx + eyeOffsetX * 1.1, y: cy + eyeOffsetY * 0.4 },
209
- { x: cx + eyeOffsetX * 0.6, y: cy + eyeOffsetY * 0.6 }
210
- ];
211
- const eyes = /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
212
- (() => {
213
- const ex = cx - eyeOffsetX;
214
- const ey = cy - eyeOffsetY;
215
- switch (eyeShape) {
216
- case "ellipse":
217
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ellipse", { cx: ex, cy: ey, rx: eyeR * 1.1, ry: eyeR * 0.7, fill: color }, "le");
218
- case "line":
219
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: ex - eyeR, y1: ey, x2: ex + eyeR, y2: ey, stroke: color, strokeWidth: Math.max(1, Math.round(eyeR * 0.4)), strokeLinecap: "round" }, "ll");
220
- case "wink":
221
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: ex - eyeR, y1: ey, x2: ex + eyeR, y2: ey, stroke: color, strokeWidth: Math.max(1, Math.round(eyeR * 0.4)), strokeLinecap: "round" }, "lw");
222
- case "sleepy":
223
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ellipse", { cx: ex, cy: ey, rx: eyeR * 1.05, ry: eyeR * 0.45, fill: color }, "ls") });
224
- case "surprised":
225
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: ex, cy: ey, r: eyeR * 1.1, fill: color }, "lsp");
226
- default:
227
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: ex, cy: ey, r: eyeR, fill: color }, "lc");
228
- }
229
- })(),
230
- (() => {
231
- const ex = cx - eyeOffsetX;
232
- const ey = cy - eyeOffsetY;
233
- if (eyeShape === "line" || eyeShape === "wink") return null;
234
- if (eyeShape === "sleepy") {
235
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: ex, cy: ey, r: Math.max(1, pupilR * 0.6), fill: finalPupilColor }, "lps");
236
- }
237
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
238
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: ex, cy: ey, r: pupilR, fill: finalPupilColor }, "lp"),
239
- eyeShine ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: ex - pupilR * 0.4, cy: ey - pupilR * 0.6, r: Math.max(0.6, pupilR * 0.35), fill: "#ffffff", opacity: 0.8 }, "lshine") : null
240
- ] });
241
- })(),
242
- (() => {
243
- const ex = cx + eyeOffsetX;
244
- const ey = cy - eyeOffsetY;
245
- switch (eyeShape) {
246
- case "ellipse":
247
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ellipse", { cx: ex, cy: ey, rx: eyeR * 1.1, ry: eyeR * 0.7, fill: color }, "re");
248
- case "line":
249
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: ex - eyeR, y1: ey, x2: ex + eyeR, y2: ey, stroke: color, strokeWidth: Math.max(1, Math.round(eyeR * 0.4)), strokeLinecap: "round" }, "rl");
250
- case "wink":
251
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: ex, cy: ey, r: eyeR, fill: color }, "rw");
252
- case "sleepy":
253
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ellipse", { cx: ex, cy: ey, rx: eyeR * 1.05, ry: eyeR * 0.45, fill: color }, "rs");
254
- case "surprised":
255
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: ex, cy: ey, r: eyeR * 1.1, fill: color }, "rsp");
256
- default:
257
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: ex, cy: ey, r: eyeR, fill: color }, "rc");
154
+ const mouthPaths = {
155
+ smile: `M ${x0} ${my} Q ${cx} ${my - r * 0.2} ${x1} ${my}`,
156
+ frown: `M ${x0} ${my} Q ${cx} ${my + r * 0.2} ${x1} ${my}`,
157
+ flat: `M ${x0} ${my} L ${x1} ${my}`,
158
+ zigzag: (() => {
159
+ const segs = 6;
160
+ const step = mouthWidth / (segs - 1);
161
+ let d = `M ${x0} ${my}`;
162
+ for (let i = 1; i < segs; i++) {
163
+ const px = x0 + step * i;
164
+ const py = my + (i % 2 === 0 ? -r * 0.08 : r * 0.08);
165
+ d += ` L ${px} ${py}`;
258
166
  }
259
- })(),
260
- (() => {
261
- const ex = cx + eyeOffsetX;
262
- const ey = cy - eyeOffsetY;
263
- if (eyeShape === "line" || eyeShape === "wink" && rand() > 0.2) {
264
- if (eyeShape === "line") return null;
265
- }
266
- if (eyeShape === "sleepy") {
267
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: ex, cy: ey, r: Math.max(1, pupilR * 0.6), fill: finalPupilColor }, "rps");
268
- }
269
- if (eyeShape === "wink") {
270
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
271
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: ex, cy: ey, r: pupilR, fill: finalPupilColor }, "rp"),
272
- eyeShine ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: ex - pupilR * 0.4, cy: ey - pupilR * 0.6, r: Math.max(0.6, pupilR * 0.35), fill: "#ffffff", opacity: 0.8 }, "rshine") : null
273
- ] });
274
- }
275
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
276
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: ex, cy: ey, r: pupilR, fill: finalPupilColor }, "rp"),
277
- eyeShine ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: ex - pupilR * 0.4, cy: ey - pupilR * 0.6, r: Math.max(0.6, pupilR * 0.35), fill: "#ffffff", opacity: 0.8 }, "rshine2") : null
278
- ] });
167
+ return d;
279
168
  })()
280
- ] });
281
- const brows = eyebrows ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
282
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: `M ${cx - eyeOffsetX - browLen / 2} ${browY} Q ${cx - eyeOffsetX} ${browY - eyeR * 0.4} ${cx - eyeOffsetX + browLen / 2} ${browY}`, stroke: color, strokeWidth: Math.max(1, Math.round(eyeR * 0.25)), strokeLinecap: "round", fill: "none" }),
283
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: `M ${cx + eyeOffsetX - browLen / 2} ${browY} Q ${cx + eyeOffsetX} ${browY - eyeR * 0.4} ${cx + eyeOffsetX + browLen / 2} ${browY}`, stroke: color, strokeWidth: Math.max(1, Math.round(eyeR * 0.25)), strokeLinecap: "round", fill: "none" })
284
- ] }) : null;
285
- const glassesEl = (() => {
286
- if (glasses === "none") return null;
287
- const gx = eyeOffsetX;
288
- const gy = cy - eyeOffsetY;
289
- const frameW = eyeR * 2.4;
290
- const frameH = eyeR * 1.6;
291
- const bridgeW = eyeR * 0.6;
292
- if (glasses === "round") {
293
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
294
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: cx - gx, cy: gy, r: frameW / 2, fill: "transparent", stroke: finalPupilColor, strokeWidth: Math.max(1, Math.round(eyeR * 0.35)) }),
295
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: cx + gx, cy: gy, r: frameW / 2, fill: "transparent", stroke: finalPupilColor, strokeWidth: Math.max(1, Math.round(eyeR * 0.35)) }),
296
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: cx - bridgeW / 2, y1: gy, x2: cx + bridgeW / 2, y2: gy, stroke: finalPupilColor, strokeWidth: Math.max(1, Math.round(eyeR * 0.25)), strokeLinecap: "round" })
297
- ] });
298
- }
299
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
300
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", { x: cx - gx - frameW / 2, y: gy - frameH / 2, width: frameW, height: frameH, rx: Math.max(1, eyeR * 0.25), fill: "transparent", stroke: finalPupilColor, strokeWidth: Math.max(1, Math.round(eyeR * 0.35)) }),
301
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", { x: cx + gx - frameW / 2, y: gy - frameH / 2, width: frameW, height: frameH, rx: Math.max(1, eyeR * 0.25), fill: "transparent", stroke: finalPupilColor, strokeWidth: Math.max(1, Math.round(eyeR * 0.35)) }),
302
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: cx - bridgeW / 2, y1: gy, x2: cx + bridgeW / 2, y2: gy, stroke: finalPupilColor, strokeWidth: Math.max(1, Math.round(eyeR * 0.25)), strokeLinecap: "round" })
303
- ] });
304
- })();
305
- const mouth = (() => {
306
- switch (mouthShape) {
307
- case "frown":
308
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: mouthPathFrown, stroke: color, strokeWidth: mouthStroke, fill: "none", strokeLinecap: "round", strokeLinejoin: "round" });
309
- case "flat":
310
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: x0, y1: my, x2: x1, y2: my, stroke: color, strokeWidth: Math.max(1, Math.round(mouthStroke * 0.9)), strokeLinecap: "round" });
311
- case "zigzag":
312
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: mouthPathZigzag, stroke: color, strokeWidth: Math.max(1, Math.round(mouthStroke * 0.9)), fill: "none", strokeLinecap: "round", strokeLinejoin: "round" });
313
- case "open":
314
- const open = mouthOpen;
315
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
316
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ellipse", { cx, cy: open.cy, rx: open.rx, ry: open.ry, fill: shade(color, -0.6) }),
317
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ellipse", { cx, cy: open.cy, rx: open.rx, ry: open.ry, fill: "none", stroke: color, strokeWidth: Math.max(1, Math.round(mouthStroke * 0.5)) }),
318
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", { x: cx - open.rx * 0.6, y: open.cy, width: open.rx * 1.2, height: Math.max(1, open.ry * 0.25), rx: 1, fill: shade(color, -0.2) })
319
- ] });
169
+ };
170
+ const drawEye = (ex, ey, key) => {
171
+ switch (eyeShape) {
172
+ case "ellipse":
173
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ellipse", { cx: ex, cy: ey, rx: eyeR * 1.1, ry: eyeR * 0.7, fill: color }, key);
174
+ case "line":
175
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: ex - eyeR, y1: ey, x2: ex + eyeR, y2: ey, stroke: color, strokeWidth: eyeR * 0.5, strokeLinecap: "round" }, key);
176
+ case "wink":
177
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: ex - eyeR, y1: ey, x2: ex + eyeR, y2: ey, stroke: color, strokeWidth: eyeR * 0.5, strokeLinecap: "round" }, key);
178
+ case "sleepy":
179
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ellipse", { cx: ex, cy: ey, rx: eyeR * 1.05, ry: eyeR * 0.45, fill: color }, key);
180
+ case "surprised":
181
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: ex, cy: ey, r: eyeR * 1.1, fill: color }, key);
320
182
  default:
321
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: mouthPathSmile, stroke: color, strokeWidth: mouthStroke, fill: "none", strokeLinecap: "round", strokeLinejoin: "round" });
183
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: ex, cy: ey, r: eyeR, fill: color }, key);
322
184
  }
323
- })();
324
- const blushEl = blush ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
325
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: cx - eyeOffsetX * 0.9, cy: cy + eyeOffsetY * 0.6, r: Math.max(3, r * 0.12), fill: shade(color, -0.5), opacity: 0.16 }),
326
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: cx + eyeOffsetX * 0.9, cy: cy + eyeOffsetY * 0.6, r: Math.max(3, r * 0.12), fill: shade(color, -0.5), opacity: 0.16 })
327
- ] }) : null;
328
- const frecklesEl = freckles ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: frecklesCoords.map((f, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: f.x, cy: f.y, r: Math.max(0.8, r * 0.03 * (0.8 + i % 3 * 0.2)), fill: shade(color, -0.6), opacity: 0.9 }, `f${i}`)) }) : null;
329
- const earsEl = ears ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
330
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: cx - r - r * 0.12, cy, r: r * 0.18, fill: color }),
331
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: cx + r + r * 0.12, cy, r: r * 0.18, fill: color })
185
+ };
186
+ const leftEye = drawEye(cx - eyeOffsetX, cy - eyeOffsetY, "le");
187
+ const rightEye = drawEye(cx + eyeOffsetX, cy - eyeOffsetY, "re");
188
+ const pupils = /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
189
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: cx - eyeOffsetX, cy: cy - eyeOffsetY, r: pupilR, fill: finalPupilColor }),
190
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: cx + eyeOffsetX, cy: cy - eyeOffsetY, r: pupilR, fill: finalPupilColor })
191
+ ] });
192
+ const shine = eyeShine ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
193
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: cx - eyeOffsetX - pupilR * 0.4, cy: cy - eyeOffsetY - pupilR * 0.6, r: pupilR * 0.3, fill: "#fff", opacity: 0.8 }),
194
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: cx + eyeOffsetX - pupilR * 0.4, cy: cy - eyeOffsetY - pupilR * 0.6, r: pupilR * 0.3, fill: "#fff", opacity: 0.8 })
332
195
  ] }) : null;
333
- const hatEl = (() => {
334
- if (hat === "none") return null;
335
- if (hat === "beanie") {
336
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: `M ${cx - r} ${cy - r * 0.55} Q ${cx} ${cy - r * 1.02} ${cx + r} ${cy - r * 0.55} L ${cx + r} ${cy - r * 0.85} L ${cx - r} ${cy - r * 0.85} Z`, fill: shade(color, 0.06), opacity: 0.98 });
337
- }
338
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
339
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: `M ${cx - r * 0.75} ${cy - r * 0.6} Q ${cx} ${cy - r * 0.95} ${cx + r * 0.75} ${cy - r * 0.6} L ${cx + r * 0.75} ${cy - r * 0.9} L ${cx - r * 0.75} ${cy - r * 0.9} Z`, fill: shade(color, 0.06) }),
340
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: `M ${cx - r * 0.6} ${cy - r * 0.3} Q ${cx} ${cy - r * 0.05} ${cx + r * 0.6} ${cy - r * 0.3} L ${cx + r * 0.6} ${cy - r * 0.15} Q ${cx} ${cy - r * 0.02} ${cx - r * 0.6} ${cy - r * 0.15} Z`, fill: shade(color, -0.08) })
341
- ] });
342
- })();
343
- const outlineStroke = outline ? { stroke: shade(color, -0.24), strokeWidth: Math.max(1, Math.round(r * 0.06)) } : {};
344
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("g", { children: [
345
- earsEl,
346
- hatEl,
347
- blushEl,
348
- frecklesEl,
349
- brows,
350
- eyes,
351
- glassesEl,
352
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("g", { children: mouth })
196
+ const mouth = /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: mouthPaths[mouthShape], stroke: color, strokeWidth: mouthStroke, fill: "none", strokeLinecap: "round", strokeLinejoin: "round" });
197
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
198
+ leftEye,
199
+ rightEye,
200
+ pupils,
201
+ shine,
202
+ mouth
353
203
  ] });
354
204
  }
355
- function Overlays({
356
- cx,
357
- cy,
358
- r,
359
- a1,
360
- a2,
361
- variant,
362
- shape,
363
- rand
364
- }) {
365
- const x0 = cx - r, y0 = cy - r, x1 = cx + r, y1 = cy + r;
366
- const left = rand() > 0.5;
367
- const tlbr = rand() > 0.5;
368
- const horiz = rand() > 0.5;
369
- const cornerTL = rand() > 0.5;
370
- switch (variant) {
371
- case "plain":
372
- return null;
373
- case "split":
374
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", { x: left ? x0 : cx, y: y0, width: r, height: 2 * r, fill: a1 });
375
- case "diagonal":
376
- return tlbr ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("polygon", { points: `${x0},${y0} ${x1},${y0} ${x1},${y1}`, fill: a1 }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("polygon", { points: `${x0},${y0} ${x0},${y1} ${x1},${y1}`, fill: a1 });
377
- case "cap":
378
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: `M ${x0} ${y0 + r * 0.25} L ${x1} ${y0} L ${x1} ${y0 + r * 0.6} Q ${cx} ${y0 + r * 0.85} ${x0} ${y0 + r * 0.6} Z`, fill: a1 });
379
- case "swoop":
380
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: `M ${x0} ${cy - r * 0.55} Q ${cx} ${cy - r * 1.1} ${x1} ${cy - r * 0.35} L ${x1} ${y1} Q ${cx} ${cy + r * 0.95} ${x0} ${y1} Z`, fill: a1 });
381
- case "crescent":
382
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
383
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: left ? cx - r * 0.55 : cx + r * 0.55, cy, r: r * 0.95, fill: a2 }),
384
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: left ? cx - r * 0.52 : cx + r * 0.52, cy, r: r * 0.75, fill: "transparent", stroke: shade(a2, -0.25), strokeWidth: r * 0.08 })
385
- ] });
386
- case "band":
387
- return horiz ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", { x: x0, y: cy - r * 0.35, width: 2 * r, height: r * 0.5, fill: a1 }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", { x: cx - r * 0.35, y: y0, width: r * 0.5, height: 2 * r, fill: a1 });
388
- case "corner":
389
- return cornerTL ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("polygon", { points: `${x0},${y0} ${x0 + r * 0.9},${y0} ${x0},${y0 + r * 0.9}`, fill: a1 }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("polygon", { points: `${x1},${y0} ${x1 - r * 0.9},${y0} ${x1},${y0 + r * 0.9}`, fill: a1 });
390
- case "ring":
391
- return shape === "circle" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx, cy, r: r * 0.86, fill: "none", stroke: a1, strokeWidth: r * 0.18 }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", { x: cx - r * 0.86, y: cy - r * 0.86, width: 2 * r * 0.86, height: 2 * r * 0.86, rx: r * 0.18, fill: "none", stroke: a1, strokeWidth: r * 0.18 });
392
- case "arc":
393
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: `M ${x0} ${cy - r * 0.2} A ${r} ${r} 0 0 1 ${x1} ${cy - r * 0.2} L ${x1} ${cy + r * 0.15} A ${r} ${r} 0 0 0 ${x0} ${cy + r * 0.15} Z`, fill: a1 });
394
- case "wave":
395
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: `M ${x0} ${cy - r * 0.3} C ${cx - r * 0.6} ${cy - r * 0.8}, ${cx - r * 0.2} ${cy + r * 0.1}, ${cx} ${cy} S ${cx + r * 0.6} ${cy + r * 0.8}, ${x1} ${cy + r * 0.3} L ${x1} ${y1} L ${x0} ${y1} Z`, fill: a1 });
396
- case "half": {
397
- const diag = rand() > 0.4;
398
- if (diag) {
399
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("polygon", { points: `${x0},${y0} ${x1},${y0} ${x1},${cy + (left ? r * 0.1 : -r * 0.1)}`, fill: a1 });
400
- } else {
401
- const offset = left ? -r * 0.18 : r * 0.18;
402
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: cx + offset, cy, r: r * 0.95, fill: a1 });
403
- }
404
- }
405
- default:
406
- return null;
407
- }
408
- }
409
- function Avatar({
410
- name,
411
- size = 128,
412
- pixelSize = 12,
413
- mirrored = true,
414
- bg,
415
- colors,
416
- headShape,
417
- square,
418
- alignX = "center",
419
- alignY = "center",
420
- padding,
421
- variant = "auto",
422
- className,
423
- style,
424
- title,
425
- // new feature props (pass these to control face features)
426
- eyeShape,
427
- mouthShape,
428
- glasses,
429
- eyebrows,
430
- blush,
431
- freckles,
432
- ears,
433
- hat,
434
- outline = false,
435
- pupilColor,
436
- eyeShine
437
- }) {
438
- const shape = headShape ?? (square ? "square" : "circle");
439
- const rand = React.useMemo(() => rngFromSeed(String(name)), [name]);
440
- const [bg1, bg2] = React.useMemo(() => resolveBg(rand, bg), [rand, bg]);
441
- const [base, a1, a2] = React.useMemo(() => resolveCharColors(rand, colors), [rand, colors]);
442
- const faceColor = bestFeatureColor(base);
443
- const grid = Math.max(6, Math.floor(size / pixelSize));
444
- const tile = Math.ceil(size / grid);
445
- const autoPad = Math.max(4, Math.round(size * (0.06 + rand() * 0.02)));
446
- const pad = padding ?? autoPad;
447
- const baseR = Math.floor(size * (0.36 + rand() * 0.04));
448
- const maxR = Math.floor(size / 2 - pad);
449
- const r = Math.max(8, Math.min(baseR, maxR));
450
- let cx = size / 2;
451
- let cy = size / 2;
452
- if (alignX === "left") cx = r + pad;
453
- if (alignX === "right") cx = size - (r + pad);
454
- if (alignY === "top") cy = r + pad;
455
- if (alignY === "bottom") cy = size - (r + pad);
456
- const cells = [];
457
- const cols = mirrored ? Math.ceil(grid / 2) : grid;
458
- for (let y = 0; y < grid; y++) {
459
- for (let x = 0; x < cols; x++) {
460
- const use = rand() > 0.5;
461
- const fill = use ? bg1 : bg2;
462
- const px = x * tile;
463
- const py = y * tile;
464
- cells.push(/* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", { x: px, y: py, width: tile, height: tile, fill }, `L${x},${y}`));
465
- if (mirrored) {
466
- const mx = grid - x - 1;
467
- const mpx = mx * tile;
468
- cells.push(/* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", { x: mpx, y: py, width: tile, height: tile, fill }, `R${mx},${y}`));
469
- }
470
- }
471
- }
472
- const variants = ["split", "swoop", "diagonal", "cap", "crescent", "band", "corner", "ring", "arc", "wave", "plain", "half"];
473
- const chosenVariant = variant === "auto" ? pick(rand, variants) : variant;
474
- const clipId = React.useMemo(() => {
475
- const [a, b, c, d] = cyrb128(`pp-shape-${name}-${shape}-${r}`);
476
- return `pps-${a.toString(16)}${b.toString(16)}${c.toString(16)}${d.toString(16)}`;
477
- }, [name, shape, r]);
478
- const headStrokeProps = outline ? { stroke: shade(base, -0.25), strokeWidth: Math.max(1, Math.round(r * 0.06)) } : {};
479
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
480
- "svg",
481
- {
482
- width: size,
483
- height: size,
484
- viewBox: `0 0 ${size} ${size}`,
485
- xmlns: "http://www.w3.org/2000/svg",
486
- role: "img",
487
- "aria-label": title ?? `Avatar ${name}`,
488
- className,
489
- style: { display: "inline-block", borderRadius: 12, ...style },
490
- children: [
491
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", { width: size, height: size, fill: bg1 }),
492
- cells,
493
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("defs", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("clipPath", { id: clipId, children: shape === "square" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", { x: cx - r, y: cy - r, width: 2 * r, height: 2 * r, rx: Math.max(4, r * 0.12) }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx, cy, r }) }) }),
494
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("g", { clipPath: `url(#${clipId})`, children: [
495
- shape === "square" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
496
- "rect",
497
- {
498
- x: cx - r,
499
- y: cy - r,
500
- width: 2 * r,
501
- height: 2 * r,
502
- rx: Math.max(4, r * 0.12),
503
- fill: base,
504
- ...outline ? { stroke: shade(base, -0.25), strokeWidth: Math.max(1, Math.round(r * 0.06)) } : {}
505
- }
506
- ) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx, cy, r, fill: base, ...outline ? { stroke: shade(base, -0.25), strokeWidth: Math.max(1, Math.round(r * 0.06)) } : {} }),
507
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Overlays, { cx, cy, r, a1, a2, variant: chosenVariant, shape, rand })
508
- ] }),
509
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
510
- Face,
511
- {
512
- cx,
513
- cy,
514
- r,
515
- color: faceColor,
516
- eyeShape,
517
- mouthShape,
518
- glasses,
519
- eyebrows,
520
- blush,
521
- freckles,
522
- ears,
523
- hat,
524
- outline,
525
- pupilColor: pupilColor ?? "auto",
526
- eyeShine,
527
- rand
528
- }
529
- )
530
- ]
531
- }
532
- );
205
+ function Avatar({ name, size = 120, bg = "random", colors = "random" }) {
206
+ const rand = rngFromSeed(name);
207
+ const [bg1, bg2] = resolveBg(rand, bg);
208
+ const [base] = resolveCharColors(rand, colors);
209
+ const cx = size / 2;
210
+ const cy = size / 2;
211
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { width: size, height: size, viewBox: `0 0 ${size} ${size}`, style: { borderRadius: "50%", background: `linear-gradient(135deg, ${bg1}, ${bg2})` }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Face, { cx, cy, r: size / 3, color: base, rand }) });
533
212
  }
534
213
  // Annotate the CommonJS export names for ESM import in node:
535
214
  0 && (module.exports = {