@usenavii/core 0.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/dist/index.cjs +846 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +80 -0
- package/dist/index.d.ts +80 -0
- package/dist/index.js +838 -0
- package/dist/index.js.map +1 -0
- package/dist/parts.cjs +594 -0
- package/dist/parts.cjs.map +1 -0
- package/dist/parts.d.cts +84 -0
- package/dist/parts.d.ts +84 -0
- package/dist/parts.js +574 -0
- package/dist/parts.js.map +1 -0
- package/dist/types-BlMtdWZf.d.cts +64 -0
- package/dist/types-BlMtdWZf.d.ts +64 -0
- package/package.json +58 -0
package/dist/parts.js
ADDED
|
@@ -0,0 +1,574 @@
|
|
|
1
|
+
// src/parts/palette.ts
|
|
2
|
+
var PALETTES = [
|
|
3
|
+
{ id: "indigo", bodyFrom: "#818CF8", bodyTo: "#6366F1", accent: "#FFFFFF", ink: "#1E1B4B", blush: "#F9A8D4" },
|
|
4
|
+
{ id: "mint", bodyFrom: "#6EE7B7", bodyTo: "#34D399", accent: "#ECFDF5", ink: "#064E3B", blush: "#FBCFE8" },
|
|
5
|
+
{ id: "amber", bodyFrom: "#FCD34D", bodyTo: "#F59E0B", accent: "#FFF7ED", ink: "#78350F", blush: "#FB7185" },
|
|
6
|
+
{ id: "sky", bodyFrom: "#93C5FD", bodyTo: "#3B82F6", accent: "#FFFFFF", ink: "#1E3A8A", blush: "#F9A8D4" },
|
|
7
|
+
{ id: "violet", bodyFrom: "#C084FC", bodyTo: "#A855F7", accent: "#FAE8FF", ink: "#4C1D95", blush: "#F472B6" },
|
|
8
|
+
{ id: "cyan", bodyFrom: "#67E8F9", bodyTo: "#06B6D4", accent: "#ECFEFF", ink: "#164E63", blush: "#F9A8D4" },
|
|
9
|
+
{ id: "rose", bodyFrom: "#FDA4AF", bodyTo: "#F43F5E", accent: "#FFE4E6", ink: "#881337", blush: "#FECDD3" },
|
|
10
|
+
{ id: "lime", bodyFrom: "#BEF264", bodyTo: "#84CC16", accent: "#F7FEE7", ink: "#365314", blush: "#FCA5A5" },
|
|
11
|
+
{ id: "peach", bodyFrom: "#FDBA74", bodyTo: "#F97316", accent: "#FFF7ED", ink: "#7C2D12", blush: "#FECACA" },
|
|
12
|
+
{ id: "teal", bodyFrom: "#5EEAD4", bodyTo: "#14B8A6", accent: "#F0FDFA", ink: "#134E4A", blush: "#FBCFE8" },
|
|
13
|
+
{ id: "sand", bodyFrom: "#FDE68A", bodyTo: "#EAB308", accent: "#FEFCE8", ink: "#713F12", blush: "#FCA5A5" },
|
|
14
|
+
{ id: "plum", bodyFrom: "#D8B4FE", bodyTo: "#9333EA", accent: "#F5F3FF", ink: "#3B0764", blush: "#F0ABFC" },
|
|
15
|
+
{ id: "coral", bodyFrom: "#FCA5A5", bodyTo: "#EF4444", accent: "#FEF2F2", ink: "#7F1D1D", blush: "#FECACA" },
|
|
16
|
+
{ id: "forest", bodyFrom: "#86EFAC", bodyTo: "#16A34A", accent: "#F0FDF4", ink: "#14532D", blush: "#FBCFE8" },
|
|
17
|
+
{ id: "slate", bodyFrom: "#CBD5E1", bodyTo: "#64748B", accent: "#F8FAFC", ink: "#0F172A", blush: "#FBCFE8" },
|
|
18
|
+
{ id: "fuchsia", bodyFrom: "#F0ABFC", bodyTo: "#D946EF", accent: "#FDF4FF", ink: "#701A75", blush: "#FBCFE8" },
|
|
19
|
+
// v0.4 additions — broader brand fit
|
|
20
|
+
{ id: "terracotta", bodyFrom: "#FBBF9C", bodyTo: "#C2410C", accent: "#FFF7ED", ink: "#7C2D12", blush: "#FECACA" },
|
|
21
|
+
{ id: "navy", bodyFrom: "#93C5FD", bodyTo: "#1E3A8A", accent: "#EFF6FF", ink: "#172554", blush: "#FBCFE8" },
|
|
22
|
+
{ id: "lavender", bodyFrom: "#DDD6FE", bodyTo: "#7C3AED", accent: "#F5F3FF", ink: "#3B0764", blush: "#F5D0FE" },
|
|
23
|
+
{ id: "charcoal", bodyFrom: "#9CA3AF", bodyTo: "#374151", accent: "#F9FAFB", ink: "#030712", blush: "#FBCFE8" },
|
|
24
|
+
{ id: "butter", bodyFrom: "#FEF9C3", bodyTo: "#FACC15", accent: "#FEFCE8", ink: "#713F12", blush: "#FCA5A5" },
|
|
25
|
+
{ id: "aqua", bodyFrom: "#A5F3FC", bodyTo: "#0891B2", accent: "#ECFEFF", ink: "#083344", blush: "#FBCFE8" }
|
|
26
|
+
];
|
|
27
|
+
var PALETTE_BY_ID = Object.fromEntries(
|
|
28
|
+
PALETTES.map((p) => [p.id, p])
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
// src/parts/anchor.ts
|
|
32
|
+
var ANCHORS = {
|
|
33
|
+
orb: {
|
|
34
|
+
cx: 50,
|
|
35
|
+
eyeY: 52,
|
|
36
|
+
eyeOffset: 10,
|
|
37
|
+
eyeScale: 1,
|
|
38
|
+
mouthY: 62,
|
|
39
|
+
mouthSpan: 7,
|
|
40
|
+
topperX: 50,
|
|
41
|
+
topperY: 22,
|
|
42
|
+
groundY: 86,
|
|
43
|
+
cheekY: 58,
|
|
44
|
+
cheekOffset: 18
|
|
45
|
+
},
|
|
46
|
+
tall: {
|
|
47
|
+
cx: 50,
|
|
48
|
+
eyeY: 49,
|
|
49
|
+
eyeOffset: 8,
|
|
50
|
+
eyeScale: 1.05,
|
|
51
|
+
mouthY: 60,
|
|
52
|
+
mouthSpan: 6,
|
|
53
|
+
topperX: 50,
|
|
54
|
+
topperY: 18,
|
|
55
|
+
groundY: 91,
|
|
56
|
+
cheekY: 55,
|
|
57
|
+
cheekOffset: 14
|
|
58
|
+
},
|
|
59
|
+
squat: {
|
|
60
|
+
cx: 50,
|
|
61
|
+
eyeY: 56,
|
|
62
|
+
eyeOffset: 11,
|
|
63
|
+
eyeScale: 0.95,
|
|
64
|
+
mouthY: 66,
|
|
65
|
+
mouthSpan: 8,
|
|
66
|
+
topperX: 50,
|
|
67
|
+
topperY: 30,
|
|
68
|
+
groundY: 86,
|
|
69
|
+
cheekY: 62,
|
|
70
|
+
cheekOffset: 20
|
|
71
|
+
},
|
|
72
|
+
pear: {
|
|
73
|
+
cx: 50,
|
|
74
|
+
eyeY: 51,
|
|
75
|
+
eyeOffset: 9,
|
|
76
|
+
eyeScale: 1,
|
|
77
|
+
mouthY: 60,
|
|
78
|
+
mouthSpan: 6.5,
|
|
79
|
+
topperX: 50,
|
|
80
|
+
topperY: 24,
|
|
81
|
+
groundY: 90,
|
|
82
|
+
cheekY: 57,
|
|
83
|
+
cheekOffset: 15
|
|
84
|
+
},
|
|
85
|
+
pebble: {
|
|
86
|
+
cx: 50,
|
|
87
|
+
eyeY: 54,
|
|
88
|
+
eyeOffset: 10.5,
|
|
89
|
+
eyeScale: 1,
|
|
90
|
+
mouthY: 63,
|
|
91
|
+
mouthSpan: 7.5,
|
|
92
|
+
topperX: 53,
|
|
93
|
+
topperY: 23,
|
|
94
|
+
groundY: 85,
|
|
95
|
+
cheekY: 59,
|
|
96
|
+
cheekOffset: 19
|
|
97
|
+
},
|
|
98
|
+
dumpling: {
|
|
99
|
+
cx: 50,
|
|
100
|
+
eyeY: 58,
|
|
101
|
+
eyeOffset: 11,
|
|
102
|
+
eyeScale: 0.98,
|
|
103
|
+
mouthY: 68,
|
|
104
|
+
mouthSpan: 8,
|
|
105
|
+
topperX: 50,
|
|
106
|
+
topperY: 32,
|
|
107
|
+
groundY: 88,
|
|
108
|
+
cheekY: 64,
|
|
109
|
+
cheekOffset: 21
|
|
110
|
+
},
|
|
111
|
+
taro: {
|
|
112
|
+
cx: 50,
|
|
113
|
+
eyeY: 50,
|
|
114
|
+
eyeOffset: 9,
|
|
115
|
+
eyeScale: 1.02,
|
|
116
|
+
mouthY: 60,
|
|
117
|
+
mouthSpan: 6.5,
|
|
118
|
+
topperX: 50,
|
|
119
|
+
topperY: 14,
|
|
120
|
+
groundY: 91,
|
|
121
|
+
cheekY: 55,
|
|
122
|
+
cheekOffset: 14
|
|
123
|
+
},
|
|
124
|
+
wisp: {
|
|
125
|
+
cx: 50,
|
|
126
|
+
eyeY: 47,
|
|
127
|
+
eyeOffset: 7.5,
|
|
128
|
+
eyeScale: 1.08,
|
|
129
|
+
mouthY: 58,
|
|
130
|
+
mouthSpan: 5.5,
|
|
131
|
+
topperX: 50,
|
|
132
|
+
topperY: 12,
|
|
133
|
+
groundY: 94,
|
|
134
|
+
cheekY: 53,
|
|
135
|
+
cheekOffset: 12
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
// src/parts/body.ts
|
|
140
|
+
var BODY_PATHS = {
|
|
141
|
+
// Orb — true round, slight under-bulge for grounded feel
|
|
142
|
+
orb: "M50 20 C72 20 84 36 84 54 C84 73 70 86 50 86 C30 86 16 73 16 54 C16 36 28 20 50 20 Z",
|
|
143
|
+
// Tall — egg pointing up, narrow shoulders, fuller bottom
|
|
144
|
+
tall: "M50 15 C66 15 74 30 74 48 C74 70 66 91 50 91 C34 91 26 70 26 48 C26 30 34 15 50 15 Z",
|
|
145
|
+
// Squat — wide mushroom cap, low waist
|
|
146
|
+
squat: "M50 28 C74 28 88 42 88 60 C88 78 74 86 50 86 C26 86 12 78 12 60 C12 42 26 28 50 28 Z",
|
|
147
|
+
// Pear — narrow top, broad rounded bottom
|
|
148
|
+
pear: "M50 18 C62 18 70 32 70 46 C70 56 80 66 80 76 C80 86 68 90 50 90 C32 90 20 86 20 76 C20 66 30 56 30 46 C30 32 38 18 50 18 Z",
|
|
149
|
+
// Pebble — asymmetric river stone, slight tilt right
|
|
150
|
+
pebble: "M52 19 C72 21 86 36 84 56 C82 73 68 85 50 85 C30 85 16 72 16 54 C16 35 32 17 52 19 Z",
|
|
151
|
+
// Dumpling — round bottom-heavy, narrow shoulders, sits low
|
|
152
|
+
dumpling: "M50 30 C62 30 70 38 70 48 C70 56 78 64 80 72 C82 82 70 88 50 88 C30 88 18 82 20 72 C22 64 30 56 30 48 C30 38 38 30 50 30 Z",
|
|
153
|
+
// Taro — gourd shape: small head bulge, fuller bottom
|
|
154
|
+
taro: "M50 14 C58 14 64 22 64 30 C64 36 60 40 60 46 C60 54 76 60 78 76 C80 88 66 91 50 91 C34 91 20 88 22 76 C24 60 40 54 40 46 C40 40 36 36 36 30 C36 22 42 14 50 14 Z",
|
|
155
|
+
// Wisp — tall narrow body, slight bottom flare, ghost-like
|
|
156
|
+
wisp: "M50 12 C60 12 66 24 66 40 C66 60 74 78 70 90 C64 96 36 96 30 90 C26 78 34 60 34 40 C34 24 40 12 50 12 Z"
|
|
157
|
+
};
|
|
158
|
+
function bodyAnchor(id) {
|
|
159
|
+
return ANCHORS[id];
|
|
160
|
+
}
|
|
161
|
+
function renderBodyDefs(_id, _palette, gradId) {
|
|
162
|
+
return `
|
|
163
|
+
<radialGradient id="${gradId}" cx="42%" cy="32%" r="68%">
|
|
164
|
+
<stop offset="0%" stop-color="${_palette.bodyFrom}" />
|
|
165
|
+
<stop offset="100%" stop-color="${_palette.bodyTo}" />
|
|
166
|
+
</radialGradient>`.trim();
|
|
167
|
+
}
|
|
168
|
+
function renderBody(id, palette, gradId) {
|
|
169
|
+
const d = BODY_PATHS[id];
|
|
170
|
+
const a = ANCHORS[id];
|
|
171
|
+
const outlineColor = withAlpha(palette.ink, 0.18);
|
|
172
|
+
return [
|
|
173
|
+
// Ground shadow — soft ellipse just below body, grounds the figure
|
|
174
|
+
`<ellipse cx="${a.cx}" cy="${a.groundY + 4}" rx="22" ry="2.6" fill="${palette.ink}" opacity="0.16" />`,
|
|
175
|
+
// Body fill
|
|
176
|
+
`<path d="${d}" fill="url(#${gradId})" stroke="${outlineColor}" stroke-width="0.7" />`,
|
|
177
|
+
// Sheen — small light spot upper-left, scaled to body
|
|
178
|
+
`<ellipse cx="${a.cx - 12}" cy="${a.eyeY - 14}" rx="11" ry="7" fill="#FFFFFF" opacity="0.22" transform="rotate(-18 ${a.cx - 12} ${a.eyeY - 14})" />`
|
|
179
|
+
].join("");
|
|
180
|
+
}
|
|
181
|
+
function withAlpha(hex, alpha) {
|
|
182
|
+
const h = hex.replace("#", "");
|
|
183
|
+
const v = h.length === 3 ? h.split("").map((c) => c + c).join("") : h;
|
|
184
|
+
const part = v.slice(0, 6);
|
|
185
|
+
const r = parseInt(part.slice(0, 2), 16);
|
|
186
|
+
const g = parseInt(part.slice(2, 4), 16);
|
|
187
|
+
const b = parseInt(part.slice(4, 6), 16);
|
|
188
|
+
return `rgba(${r},${g},${b},${alpha})`;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// src/parts/eyes.ts
|
|
192
|
+
function renderEyes(id, palette, anchor) {
|
|
193
|
+
const lx = anchor.cx - anchor.eyeOffset;
|
|
194
|
+
const rx = anchor.cx + anchor.eyeOffset;
|
|
195
|
+
const y = anchor.eyeY;
|
|
196
|
+
const s = anchor.eyeScale;
|
|
197
|
+
const ink = palette.ink;
|
|
198
|
+
switch (id) {
|
|
199
|
+
case "round":
|
|
200
|
+
return [
|
|
201
|
+
sclera(lx, y, 4 * s, 4.5 * s),
|
|
202
|
+
sclera(rx, y, 4 * s, 4.5 * s),
|
|
203
|
+
pupil(lx, y, 2.2 * s, ink),
|
|
204
|
+
pupil(rx, y, 2.2 * s, ink),
|
|
205
|
+
glint(lx + 1, y - 1),
|
|
206
|
+
glint(rx + 1, y - 1)
|
|
207
|
+
].join("");
|
|
208
|
+
case "wide":
|
|
209
|
+
return [
|
|
210
|
+
sclera(lx, y, 5 * s, 5.5 * s),
|
|
211
|
+
sclera(rx, y, 5 * s, 5.5 * s),
|
|
212
|
+
pupil(lx, y + 0.5, 3 * s, ink),
|
|
213
|
+
pupil(rx, y + 0.5, 3 * s, ink),
|
|
214
|
+
glint(lx + 1.2, y - 0.5),
|
|
215
|
+
glint(rx + 1.2, y - 0.5)
|
|
216
|
+
].join("");
|
|
217
|
+
case "squint":
|
|
218
|
+
return [
|
|
219
|
+
arc(lx - 4.5, y, lx, y - 3.5, lx + 4.5, y, ink, 1.8),
|
|
220
|
+
arc(rx - 4.5, y, rx, y - 3.5, rx + 4.5, y, ink, 1.8)
|
|
221
|
+
].join("");
|
|
222
|
+
case "wink":
|
|
223
|
+
return [
|
|
224
|
+
sclera(lx, y, 4 * s, 4.5 * s),
|
|
225
|
+
pupil(lx, y, 2.2 * s, ink),
|
|
226
|
+
glint(lx + 1, y - 1),
|
|
227
|
+
arc(rx - 4, y, rx, y - 3.5, rx + 4, y, ink, 1.8)
|
|
228
|
+
].join("");
|
|
229
|
+
case "sleepy":
|
|
230
|
+
return [
|
|
231
|
+
// Heavier upper lid — half-closed
|
|
232
|
+
`<path d="M${lx - 4} ${y - 0.5} Q${lx} ${y + 2} ${lx + 4} ${y - 0.5}" stroke="${ink}" stroke-width="1.7" stroke-linecap="round" fill="none" />`,
|
|
233
|
+
`<path d="M${rx - 4} ${y - 0.5} Q${rx} ${y + 2} ${rx + 4} ${y - 0.5}" stroke="${ink}" stroke-width="1.7" stroke-linecap="round" fill="none" />`,
|
|
234
|
+
// tiny visible pupils
|
|
235
|
+
`<circle cx="${lx}" cy="${y + 0.5}" r="0.9" fill="${ink}" />`,
|
|
236
|
+
`<circle cx="${rx}" cy="${y + 0.5}" r="0.9" fill="${ink}" />`
|
|
237
|
+
].join("");
|
|
238
|
+
case "star":
|
|
239
|
+
return [starEye(lx, y, ink), starEye(rx, y, ink)].join("");
|
|
240
|
+
case "heart":
|
|
241
|
+
return [heartEye(lx, y, ink), heartEye(rx, y, ink)].join("");
|
|
242
|
+
case "oval":
|
|
243
|
+
return [
|
|
244
|
+
sclera(lx, y, 4.5 * s, 5 * s),
|
|
245
|
+
sclera(rx, y, 4.5 * s, 5 * s),
|
|
246
|
+
`<ellipse cx="${lx}" cy="${y}" rx="${1.6 * s}" ry="${3 * s}" fill="${ink}" />`,
|
|
247
|
+
`<ellipse cx="${rx}" cy="${y}" rx="${1.6 * s}" ry="${3 * s}" fill="${ink}" />`,
|
|
248
|
+
glint(lx + 0.8, y - 1.5),
|
|
249
|
+
glint(rx + 0.8, y - 1.5)
|
|
250
|
+
].join("");
|
|
251
|
+
case "dot":
|
|
252
|
+
return [
|
|
253
|
+
`<circle cx="${lx}" cy="${y}" r="${1.4 * s}" fill="${ink}" />`,
|
|
254
|
+
`<circle cx="${rx}" cy="${y}" r="${1.4 * s}" fill="${ink}" />`
|
|
255
|
+
].join("");
|
|
256
|
+
case "cross":
|
|
257
|
+
return [crossEye(lx, y, ink), crossEye(rx, y, ink)].join("");
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
function heartEye(cx, cy, color) {
|
|
261
|
+
const s = 2;
|
|
262
|
+
return `<path d="M${cx} ${cy + s * 1.4} L${cx - s * 1.8} ${cy - s * 0.2} A${s} ${s} 0 0 1 ${cx} ${cy - s * 0.6} A${s} ${s} 0 0 1 ${cx + s * 1.8} ${cy - s * 0.2} Z" fill="${color}" />`;
|
|
263
|
+
}
|
|
264
|
+
function crossEye(cx, cy, color) {
|
|
265
|
+
const s = 2.4;
|
|
266
|
+
return `<g stroke="${color}" stroke-width="1.6" stroke-linecap="round"><line x1="${cx - s}" y1="${cy - s}" x2="${cx + s}" y2="${cy + s}" /><line x1="${cx - s}" y1="${cy + s}" x2="${cx + s}" y2="${cy - s}" /></g>`;
|
|
267
|
+
}
|
|
268
|
+
function sclera(cx, cy, rx, ry) {
|
|
269
|
+
return `<ellipse cx="${cx}" cy="${cy}" rx="${rx}" ry="${ry}" fill="#FFFFFF" />`;
|
|
270
|
+
}
|
|
271
|
+
function pupil(cx, cy, r, color) {
|
|
272
|
+
return `<circle cx="${cx}" cy="${cy}" r="${r}" fill="${color}" />`;
|
|
273
|
+
}
|
|
274
|
+
function glint(cx, cy) {
|
|
275
|
+
return `<circle cx="${cx}" cy="${cy}" r="0.8" fill="#FFFFFF" />`;
|
|
276
|
+
}
|
|
277
|
+
function arc(x1, y1, cx, cy, x2, y2, stroke, width) {
|
|
278
|
+
return `<path d="M${x1} ${y1} Q${cx} ${cy} ${x2} ${y2}" stroke="${stroke}" stroke-width="${width}" stroke-linecap="round" fill="none" />`;
|
|
279
|
+
}
|
|
280
|
+
function starEye(cx, cy, color) {
|
|
281
|
+
const s = 3;
|
|
282
|
+
return `<path d="M${cx} ${cy - s} L${cx + s * 0.35} ${cy - s * 0.35} L${cx + s} ${cy} L${cx + s * 0.35} ${cy + s * 0.35} L${cx} ${cy + s} L${cx - s * 0.35} ${cy + s * 0.35} L${cx - s} ${cy} L${cx - s * 0.35} ${cy - s * 0.35} Z" fill="${color}" />`;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// src/parts/mouth.ts
|
|
286
|
+
function renderMouth(id, palette, anchor, curveScale = 1) {
|
|
287
|
+
const cx = anchor.cx;
|
|
288
|
+
const y = anchor.mouthY;
|
|
289
|
+
const w = anchor.mouthSpan * curveScale;
|
|
290
|
+
const ink = palette.ink;
|
|
291
|
+
switch (id) {
|
|
292
|
+
case "smile":
|
|
293
|
+
return `<path d="M${cx - w} ${y} Q${cx} ${y + 5} ${cx + w} ${y}" stroke="${ink}" stroke-width="1.8" stroke-linecap="round" fill="none" />`;
|
|
294
|
+
case "grin":
|
|
295
|
+
return `<path d="M${cx - w - 1} ${y - 2} Q${cx} ${y + 7} ${cx + w + 1} ${y - 2}" stroke="${ink}" stroke-width="1.8" stroke-linecap="round" fill="none" />`;
|
|
296
|
+
case "open":
|
|
297
|
+
return [
|
|
298
|
+
`<path d="M${cx - w - 1} ${y - 2} Q${cx} ${y + 9} ${cx + w + 1} ${y - 2}" stroke="${ink}" stroke-width="1.8" stroke-linecap="round" fill="${ink}" fill-opacity="0.55" />`,
|
|
299
|
+
`<ellipse cx="${cx}" cy="${y + 3}" rx="${w * 0.55}" ry="1.8" fill="#F472B6" opacity="0.75" />`
|
|
300
|
+
].join("");
|
|
301
|
+
case "flat":
|
|
302
|
+
return `<path d="M${cx - w + 1} ${y} L${cx + w - 1} ${y}" stroke="${ink}" stroke-width="1.8" stroke-linecap="round" fill="none" />`;
|
|
303
|
+
case "smirk":
|
|
304
|
+
return `<path d="M${cx - w} ${y} Q${cx} ${y + 3} ${cx + w + 1} ${y - 2}" stroke="${ink}" stroke-width="1.8" stroke-linecap="round" fill="none" />`;
|
|
305
|
+
case "awe":
|
|
306
|
+
return `<ellipse cx="${cx}" cy="${y + 1}" rx="${w * 0.45}" ry="3.2" fill="${ink}" opacity="0.85" />`;
|
|
307
|
+
case "tongue":
|
|
308
|
+
return [
|
|
309
|
+
`<path d="M${cx - w} ${y} Q${cx} ${y + 6} ${cx + w} ${y}" stroke="${ink}" stroke-width="1.8" stroke-linecap="round" fill="none" />`,
|
|
310
|
+
`<path d="M${cx - 2} ${y + 4} Q${cx} ${y + 9} ${cx + 2} ${y + 4} Z" fill="#F472B6" stroke="${ink}" stroke-width="0.6" />`
|
|
311
|
+
].join("");
|
|
312
|
+
case "tooth":
|
|
313
|
+
return [
|
|
314
|
+
`<path d="M${cx - w} ${y} Q${cx} ${y + 5} ${cx + w} ${y}" stroke="${ink}" stroke-width="1.8" stroke-linecap="round" fill="none" />`,
|
|
315
|
+
`<rect x="${cx - 1.2}" y="${y + 0.4}" width="2.4" height="2.6" rx="0.4" fill="#FFFFFF" stroke="${ink}" stroke-width="0.4" />`
|
|
316
|
+
].join("");
|
|
317
|
+
case "wave":
|
|
318
|
+
return `<path d="M${cx - w} ${y + 1} Q${cx - w / 2} ${y - 1.5} ${cx} ${y + 1} Q${cx + w / 2} ${y + 3.5} ${cx + w} ${y + 1}" stroke="${ink}" stroke-width="1.8" stroke-linecap="round" fill="none" />`;
|
|
319
|
+
case "dot":
|
|
320
|
+
return `<circle cx="${cx}" cy="${y + 1}" r="1.2" fill="${ink}" />`;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// src/parts/antenna.ts
|
|
325
|
+
function renderAntenna(id, anchor, palette) {
|
|
326
|
+
if (id === "none") return "";
|
|
327
|
+
const cx = anchor.topperX;
|
|
328
|
+
const topY = anchor.topperY;
|
|
329
|
+
const color = palette.accent;
|
|
330
|
+
const ink = palette.ink;
|
|
331
|
+
switch (id) {
|
|
332
|
+
case "classic":
|
|
333
|
+
return [
|
|
334
|
+
`<path d="M${cx} ${topY} Q${cx + 1} ${topY - 5} ${cx + 2.5} ${topY - 9}" stroke="${ink}" stroke-width="1.2" stroke-linecap="round" fill="none" opacity="0.55" />`,
|
|
335
|
+
`<circle class="spark" cx="${cx + 2.5}" cy="${topY - 10}" r="2.6" fill="${color}" stroke="${ink}" stroke-width="0.6" opacity="0.95" />`
|
|
336
|
+
].join("");
|
|
337
|
+
case "curl":
|
|
338
|
+
return [
|
|
339
|
+
`<path d="M${cx} ${topY} Q${cx + 6} ${topY - 4} ${cx + 1} ${topY - 8} Q${cx - 4} ${topY - 11} ${cx + 1} ${topY - 14}" stroke="${ink}" stroke-width="1.2" stroke-linecap="round" fill="none" opacity="0.55" />`,
|
|
340
|
+
`<circle class="spark" cx="${cx + 1}" cy="${topY - 14}" r="2.2" fill="${color}" stroke="${ink}" stroke-width="0.6" opacity="0.95" />`
|
|
341
|
+
].join("");
|
|
342
|
+
case "double":
|
|
343
|
+
return [
|
|
344
|
+
`<path d="M${cx - 4} ${topY} Q${cx - 5} ${topY - 4} ${cx - 5.5} ${topY - 8}" stroke="${ink}" stroke-width="1.1" stroke-linecap="round" fill="none" opacity="0.55" />`,
|
|
345
|
+
`<path d="M${cx + 4} ${topY} Q${cx + 5} ${topY - 4} ${cx + 5.5} ${topY - 8}" stroke="${ink}" stroke-width="1.1" stroke-linecap="round" fill="none" opacity="0.55" />`,
|
|
346
|
+
`<circle class="spark" cx="${cx - 5.5}" cy="${topY - 9}" r="2.1" fill="${color}" stroke="${ink}" stroke-width="0.5" opacity="0.95" />`,
|
|
347
|
+
`<circle class="spark" cx="${cx + 5.5}" cy="${topY - 9}" r="2.1" fill="${color}" stroke="${ink}" stroke-width="0.5" opacity="0.95" />`
|
|
348
|
+
].join("");
|
|
349
|
+
case "spike":
|
|
350
|
+
return [
|
|
351
|
+
`<path class="spark" d="M${cx - 2.5} ${topY - 1} L${cx + 1} ${topY - 11} L${cx + 4.5} ${topY - 1} Z" fill="${color}" stroke="${ink}" stroke-width="0.6" opacity="0.95" />`
|
|
352
|
+
].join("");
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
// src/parts/accessory.ts
|
|
357
|
+
function renderAccessory(id, palette, anchor) {
|
|
358
|
+
switch (id) {
|
|
359
|
+
case "none":
|
|
360
|
+
return "";
|
|
361
|
+
case "blush": {
|
|
362
|
+
const lx = anchor.cx - anchor.cheekOffset;
|
|
363
|
+
const rx = anchor.cx + anchor.cheekOffset;
|
|
364
|
+
const y = anchor.cheekY;
|
|
365
|
+
return [
|
|
366
|
+
`<ellipse cx="${lx}" cy="${y}" rx="3.6" ry="2.2" fill="${palette.blush}" opacity="0.5" />`,
|
|
367
|
+
`<ellipse cx="${rx}" cy="${y}" rx="3.6" ry="2.2" fill="${palette.blush}" opacity="0.5" />`
|
|
368
|
+
].join("");
|
|
369
|
+
}
|
|
370
|
+
case "freckles": {
|
|
371
|
+
const lx = anchor.cx - 8;
|
|
372
|
+
const rx = anchor.cx + 8;
|
|
373
|
+
const y = anchor.cheekY;
|
|
374
|
+
return [
|
|
375
|
+
dot(lx, y, palette.ink),
|
|
376
|
+
dot(lx + 3, y + 1.5, palette.ink),
|
|
377
|
+
dot(rx, y, palette.ink),
|
|
378
|
+
dot(rx - 3, y + 1.5, palette.ink)
|
|
379
|
+
].join("");
|
|
380
|
+
}
|
|
381
|
+
case "sparkle":
|
|
382
|
+
return [
|
|
383
|
+
sparkle(76, anchor.eyeY - 18, 3, palette),
|
|
384
|
+
sparkle(24, anchor.eyeY - 16, 2.5, palette),
|
|
385
|
+
sparkle(82, anchor.cheekY + 2, 2, palette)
|
|
386
|
+
].join("");
|
|
387
|
+
case "glasses": {
|
|
388
|
+
const lx = anchor.cx - anchor.eyeOffset;
|
|
389
|
+
const rx = anchor.cx + anchor.eyeOffset;
|
|
390
|
+
const y = anchor.eyeY;
|
|
391
|
+
const r = 6;
|
|
392
|
+
return [
|
|
393
|
+
`<circle cx="${lx}" cy="${y}" r="${r}" fill="none" stroke="${palette.ink}" stroke-width="1.2" />`,
|
|
394
|
+
`<circle cx="${rx}" cy="${y}" r="${r}" fill="none" stroke="${palette.ink}" stroke-width="1.2" />`,
|
|
395
|
+
`<line x1="${lx + r}" y1="${y}" x2="${rx - r}" y2="${y}" stroke="${palette.ink}" stroke-width="1.2" />`,
|
|
396
|
+
// subtle lens fill
|
|
397
|
+
`<circle cx="${lx}" cy="${y}" r="${r - 1}" fill="#FFFFFF" opacity="0.18" />`,
|
|
398
|
+
`<circle cx="${rx}" cy="${y}" r="${r - 1}" fill="#FFFFFF" opacity="0.18" />`
|
|
399
|
+
].join("");
|
|
400
|
+
}
|
|
401
|
+
case "eyepatch": {
|
|
402
|
+
const rx = anchor.cx + anchor.eyeOffset;
|
|
403
|
+
const y = anchor.eyeY;
|
|
404
|
+
return [
|
|
405
|
+
`<ellipse cx="${rx}" cy="${y}" rx="6" ry="5.2" fill="${palette.ink}" />`,
|
|
406
|
+
`<path d="M${rx - 6} ${y - 4} L${anchor.cx - 18} ${anchor.eyeY - 8}" stroke="${palette.ink}" stroke-width="0.9" />`,
|
|
407
|
+
`<path d="M${rx + 6} ${y - 3} L${anchor.cx + 22} ${anchor.eyeY - 6}" stroke="${palette.ink}" stroke-width="0.9" />`
|
|
408
|
+
].join("");
|
|
409
|
+
}
|
|
410
|
+
case "mole": {
|
|
411
|
+
return `<circle cx="${anchor.cx - anchor.cheekOffset * 0.6}" cy="${anchor.cheekY + 2}" r="0.9" fill="${palette.ink}" />`;
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
function dot(cx, cy, color) {
|
|
415
|
+
return `<circle cx="${cx}" cy="${cy}" r="0.85" fill="${color}" opacity="0.55" />`;
|
|
416
|
+
}
|
|
417
|
+
function sparkle(cx, cy, s, p) {
|
|
418
|
+
return `<path d="M${cx} ${cy - s} L${cx + s * 0.3} ${cy - s * 0.3} L${cx + s} ${cy} L${cx + s * 0.3} ${cy + s * 0.3} L${cx} ${cy + s} L${cx - s * 0.3} ${cy + s * 0.3} L${cx - s} ${cy} L${cx - s * 0.3} ${cy - s * 0.3} Z" fill="${p.accent}" stroke="${p.ink}" stroke-width="0.3" opacity="0.9" />`;
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
// src/parts/background.ts
|
|
423
|
+
function renderBackground(id, palette, override) {
|
|
424
|
+
const color = override ?? palette.bodyFrom;
|
|
425
|
+
switch (id) {
|
|
426
|
+
case "none":
|
|
427
|
+
return "";
|
|
428
|
+
case "solid":
|
|
429
|
+
return `<rect x="0" y="0" width="100" height="100" fill="${color}" opacity="0.18" />`;
|
|
430
|
+
case "ring":
|
|
431
|
+
return [
|
|
432
|
+
`<circle cx="50" cy="50" r="48" fill="${color}" opacity="0.14" />`,
|
|
433
|
+
`<circle cx="50" cy="50" r="46" fill="none" stroke="${palette.accent}" stroke-width="0.6" opacity="0.4" />`
|
|
434
|
+
].join("");
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
// src/parts/topper.ts
|
|
439
|
+
function renderTopper(id, anchor, palette) {
|
|
440
|
+
if (id === "none") return "";
|
|
441
|
+
const cx = anchor.topperX;
|
|
442
|
+
const topY = anchor.topperY;
|
|
443
|
+
const ink = palette.ink;
|
|
444
|
+
switch (id) {
|
|
445
|
+
case "ears":
|
|
446
|
+
return [
|
|
447
|
+
`<path d="M${cx - 16} ${topY + 6} L${cx - 11} ${topY - 5} L${cx - 6} ${topY + 8} Z" fill="${palette.bodyTo}" stroke="${ink}" stroke-width="0.6" opacity="0.95" />`,
|
|
448
|
+
`<path d="M${cx + 6} ${topY + 8} L${cx + 11} ${topY - 5} L${cx + 16} ${topY + 6} Z" fill="${palette.bodyTo}" stroke="${ink}" stroke-width="0.6" opacity="0.95" />`,
|
|
449
|
+
// inner ear blush
|
|
450
|
+
`<path d="M${cx - 14} ${topY + 4} L${cx - 11} ${topY - 1} L${cx - 8} ${topY + 5} Z" fill="${palette.blush}" opacity="0.65" />`,
|
|
451
|
+
`<path d="M${cx + 8} ${topY + 5} L${cx + 11} ${topY - 1} L${cx + 14} ${topY + 4} Z" fill="${palette.blush}" opacity="0.65" />`
|
|
452
|
+
].join("");
|
|
453
|
+
case "roundEars":
|
|
454
|
+
return [
|
|
455
|
+
`<circle cx="${cx - 13}" cy="${topY + 2}" r="6" fill="${palette.bodyTo}" stroke="${ink}" stroke-width="0.6" />`,
|
|
456
|
+
`<circle cx="${cx + 13}" cy="${topY + 2}" r="6" fill="${palette.bodyTo}" stroke="${ink}" stroke-width="0.6" />`,
|
|
457
|
+
`<circle cx="${cx - 13}" cy="${topY + 2}" r="3" fill="${palette.blush}" opacity="0.6" />`,
|
|
458
|
+
`<circle cx="${cx + 13}" cy="${topY + 2}" r="3" fill="${palette.blush}" opacity="0.6" />`
|
|
459
|
+
].join("");
|
|
460
|
+
case "horn":
|
|
461
|
+
return [
|
|
462
|
+
`<path d="M${cx - 1} ${topY + 2} Q${cx} ${topY - 6} ${cx + 4} ${topY - 10} Q${cx + 6} ${topY - 4} ${cx + 3} ${topY + 2} Z" fill="${palette.accent}" stroke="${ink}" stroke-width="0.6" />`
|
|
463
|
+
].join("");
|
|
464
|
+
case "horns":
|
|
465
|
+
return [
|
|
466
|
+
`<path d="M${cx - 7} ${topY + 4} Q${cx - 8} ${topY - 4} ${cx - 4} ${topY - 7} Q${cx - 2} ${topY - 1} ${cx - 3} ${topY + 4} Z" fill="${palette.accent}" stroke="${ink}" stroke-width="0.6" />`,
|
|
467
|
+
`<path d="M${cx + 3} ${topY + 4} Q${cx + 2} ${topY - 1} ${cx + 4} ${topY - 7} Q${cx + 8} ${topY - 4} ${cx + 7} ${topY + 4} Z" fill="${palette.accent}" stroke="${ink}" stroke-width="0.6" />`
|
|
468
|
+
].join("");
|
|
469
|
+
case "tuft":
|
|
470
|
+
return [
|
|
471
|
+
`<path d="M${cx} ${topY + 2} Q${cx - 2} ${topY - 4} ${cx + 1} ${topY - 8} Q${cx + 6} ${topY - 5} ${cx + 4} ${topY + 1} Z" fill="${ink}" opacity="0.85" />`
|
|
472
|
+
].join("");
|
|
473
|
+
case "cap":
|
|
474
|
+
return [
|
|
475
|
+
`<path d="M${cx - 16} ${topY + 6} Q${cx - 16} ${topY - 8} ${cx} ${topY - 8} Q${cx + 16} ${topY - 8} ${cx + 16} ${topY + 6} Z" fill="${palette.ink}" opacity="0.92" />`,
|
|
476
|
+
`<rect x="${cx - 16}" y="${topY + 5}" width="32" height="2.5" rx="1" fill="${palette.accent}" opacity="0.85" />`,
|
|
477
|
+
`<circle cx="${cx}" cy="${topY - 9}" r="2.2" fill="${palette.accent}" stroke="${ink}" stroke-width="0.5" />`
|
|
478
|
+
].join("");
|
|
479
|
+
case "leaf":
|
|
480
|
+
return [
|
|
481
|
+
`<path d="M${cx - 1} ${topY + 2} Q${cx - 6} ${topY - 4} ${cx - 1} ${topY - 8} Q${cx + 3} ${topY - 4} ${cx - 1} ${topY + 2} Z" fill="#22C55E" stroke="${ink}" stroke-width="0.4" opacity="0.95" />`,
|
|
482
|
+
`<path d="M${cx + 1} ${topY + 2} Q${cx + 5} ${topY - 2} ${cx + 6} ${topY - 6}" stroke="#16A34A" stroke-width="1" fill="none" stroke-linecap="round" />`
|
|
483
|
+
].join("");
|
|
484
|
+
case "headband":
|
|
485
|
+
return [
|
|
486
|
+
`<path d="M${cx - 18} ${topY + 8} Q${cx} ${topY + 2} ${cx + 18} ${topY + 8} L${cx + 18} ${topY + 12} Q${cx} ${topY + 6} ${cx - 18} ${topY + 12} Z" fill="${palette.bodyTo}" stroke="${ink}" stroke-width="0.6" />`,
|
|
487
|
+
`<rect x="${cx - 2}" y="${topY + 4}" width="4" height="4" rx="1" fill="${palette.accent}" stroke="${ink}" stroke-width="0.4" />`
|
|
488
|
+
].join("");
|
|
489
|
+
case "halo":
|
|
490
|
+
return [
|
|
491
|
+
`<ellipse cx="${cx}" cy="${topY - 6}" rx="11" ry="2.5" fill="none" stroke="#FACC15" stroke-width="2" opacity="0.95" />`,
|
|
492
|
+
`<ellipse cx="${cx}" cy="${topY - 6}" rx="8.5" ry="1.6" fill="none" stroke="#FDE68A" stroke-width="0.6" opacity="0.7" />`
|
|
493
|
+
].join("");
|
|
494
|
+
case "crown":
|
|
495
|
+
return [
|
|
496
|
+
`<path d="M${cx - 11} ${topY + 4} L${cx - 11} ${topY - 4} L${cx - 6} ${topY + 1} L${cx} ${topY - 7} L${cx + 6} ${topY + 1} L${cx + 11} ${topY - 4} L${cx + 11} ${topY + 4} Z" fill="#FACC15" stroke="${ink}" stroke-width="0.7" />`,
|
|
497
|
+
`<circle cx="${cx - 11}" cy="${topY - 4}" r="1.4" fill="#EF4444" stroke="${ink}" stroke-width="0.3" />`,
|
|
498
|
+
`<circle cx="${cx}" cy="${topY - 7}" r="1.6" fill="#EF4444" stroke="${ink}" stroke-width="0.3" />`,
|
|
499
|
+
`<circle cx="${cx + 11}" cy="${topY - 4}" r="1.4" fill="#EF4444" stroke="${ink}" stroke-width="0.3" />`
|
|
500
|
+
].join("");
|
|
501
|
+
case "antlers":
|
|
502
|
+
return [
|
|
503
|
+
`<path d="M${cx - 5} ${topY + 4} L${cx - 6} ${topY - 4} M${cx - 6} ${topY - 4} L${cx - 10} ${topY - 6} M${cx - 6} ${topY - 4} L${cx - 6} ${topY - 9} M${cx - 6} ${topY - 9} L${cx - 8} ${topY - 11} M${cx - 6} ${topY - 9} L${cx - 3} ${topY - 11}" stroke="${ink}" stroke-width="1.3" stroke-linecap="round" fill="none" />`,
|
|
504
|
+
`<path d="M${cx + 5} ${topY + 4} L${cx + 6} ${topY - 4} M${cx + 6} ${topY - 4} L${cx + 10} ${topY - 6} M${cx + 6} ${topY - 4} L${cx + 6} ${topY - 9} M${cx + 6} ${topY - 9} L${cx + 8} ${topY - 11} M${cx + 6} ${topY - 9} L${cx + 3} ${topY - 11}" stroke="${ink}" stroke-width="1.3" stroke-linecap="round" fill="none" />`
|
|
505
|
+
].join("");
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
// src/parts/index.ts
|
|
510
|
+
var BODY_IDS = [
|
|
511
|
+
"orb",
|
|
512
|
+
"tall",
|
|
513
|
+
"squat",
|
|
514
|
+
"pear",
|
|
515
|
+
"pebble",
|
|
516
|
+
"dumpling",
|
|
517
|
+
"taro",
|
|
518
|
+
"wisp"
|
|
519
|
+
];
|
|
520
|
+
var EYE_IDS = [
|
|
521
|
+
"round",
|
|
522
|
+
"wide",
|
|
523
|
+
"squint",
|
|
524
|
+
"wink",
|
|
525
|
+
"sleepy",
|
|
526
|
+
"star",
|
|
527
|
+
"heart",
|
|
528
|
+
"oval",
|
|
529
|
+
"dot",
|
|
530
|
+
"cross"
|
|
531
|
+
];
|
|
532
|
+
var MOUTH_IDS = [
|
|
533
|
+
"smile",
|
|
534
|
+
"grin",
|
|
535
|
+
"open",
|
|
536
|
+
"flat",
|
|
537
|
+
"smirk",
|
|
538
|
+
"awe",
|
|
539
|
+
"tongue",
|
|
540
|
+
"tooth",
|
|
541
|
+
"wave",
|
|
542
|
+
"dot"
|
|
543
|
+
];
|
|
544
|
+
var ANTENNA_IDS = ["none", "classic", "curl", "double", "spike"];
|
|
545
|
+
var ACCESSORY_IDS = [
|
|
546
|
+
"none",
|
|
547
|
+
"blush",
|
|
548
|
+
"freckles",
|
|
549
|
+
"sparkle",
|
|
550
|
+
"glasses",
|
|
551
|
+
"eyepatch",
|
|
552
|
+
"mole"
|
|
553
|
+
];
|
|
554
|
+
var BACKGROUND_IDS = ["none", "solid", "ring"];
|
|
555
|
+
var TOPPER_IDS = [
|
|
556
|
+
// 'none' weighted ~2× so plain-headed avatars stay common
|
|
557
|
+
"none",
|
|
558
|
+
"none",
|
|
559
|
+
"ears",
|
|
560
|
+
"roundEars",
|
|
561
|
+
"horn",
|
|
562
|
+
"horns",
|
|
563
|
+
"tuft",
|
|
564
|
+
"cap",
|
|
565
|
+
"leaf",
|
|
566
|
+
"headband",
|
|
567
|
+
"halo",
|
|
568
|
+
"crown",
|
|
569
|
+
"antlers"
|
|
570
|
+
];
|
|
571
|
+
|
|
572
|
+
export { ACCESSORY_IDS, ANCHORS, ANTENNA_IDS, BACKGROUND_IDS, BODY_IDS, EYE_IDS, MOUTH_IDS, PALETTES, PALETTE_BY_ID, TOPPER_IDS, bodyAnchor, renderAccessory, renderAntenna, renderBackground, renderBody, renderBodyDefs, renderEyes, renderMouth, renderTopper };
|
|
573
|
+
//# sourceMappingURL=parts.js.map
|
|
574
|
+
//# sourceMappingURL=parts.js.map
|