quirkatar 1.0.0 â 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +38 -13
- package/avatar.js +186 -67
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -31,11 +31,12 @@ Quirkatar generates hilarious, memorable, and utterly unique avatars from any st
|
|
|
31
31
|
|---------|-------------|
|
|
32
32
|
| ðŠķ **Zero Dependencies** | Pure vanilla JS + SVG. No bloat, no network requests, no drama |
|
|
33
33
|
| ðē **Deterministic Seeds** | `"user@email.com"` always produces the same chaos |
|
|
34
|
+
| ð **6 Mood Controls** | Happy, sad, angry, surprised, chill, or random |
|
|
35
|
+
| ðĻ **4 Color Palettes** | Default, pastel, neon, monochrome |
|
|
34
36
|
| ð **14 Eye Types** | Normal, cyclops, glasses, stars, hearts, wink, and more |
|
|
35
37
|
| ðš **11 Mouth Styles** | Smiles, fangs, tongues, teeth, zigzags... |
|
|
36
38
|
| ð **7 Ear Options** | Cat, bear, bunny, alien, elf, robot, or none |
|
|
37
39
|
| ðĐ **8 Headwear** | Hats, crowns, horns, headphones, bows |
|
|
38
|
-
| ðĻ **37 Colors** | Hand-picked to look *chef's kiss* |
|
|
39
40
|
| ðū **Download as PNG** | One-click export at 512x512 |
|
|
40
41
|
| ⥠**Lightweight** | ~10KB, loads instantly |
|
|
41
42
|
|
|
@@ -46,7 +47,15 @@ Quirkatar generates hilarious, memorable, and utterly unique avatars from any st
|
|
|
46
47
|
<script src="https://unpkg.com/quirkatar"></script>
|
|
47
48
|
<div id="avatar"></div>
|
|
48
49
|
<script>
|
|
50
|
+
// Random avatar
|
|
49
51
|
document.getElementById('avatar').innerHTML = generateAvatarSvg('your-seed-here');
|
|
52
|
+
|
|
53
|
+
// Happy avatar with neon colors
|
|
54
|
+
document.getElementById('avatar').innerHTML = generateAvatarSvg('your-seed-here', {
|
|
55
|
+
mood: 'happy',
|
|
56
|
+
palette: 'neon',
|
|
57
|
+
size: 200
|
|
58
|
+
});
|
|
50
59
|
</script>
|
|
51
60
|
```
|
|
52
61
|
|
|
@@ -58,8 +67,12 @@ npm install quirkatar
|
|
|
58
67
|
```javascript
|
|
59
68
|
import { generateAvatarSvg } from 'quirkatar';
|
|
60
69
|
|
|
61
|
-
// Generate a 200px avatar
|
|
62
|
-
const avatar = generateAvatarSvg('hello-world',
|
|
70
|
+
// Generate a 200px happy avatar
|
|
71
|
+
const avatar = generateAvatarSvg('hello-world', {
|
|
72
|
+
size: 200,
|
|
73
|
+
mood: 'happy',
|
|
74
|
+
palette: 'pastel'
|
|
75
|
+
});
|
|
63
76
|
document.getElementById('profile').innerHTML = avatar;
|
|
64
77
|
```
|
|
65
78
|
|
|
@@ -71,28 +84,40 @@ Just download `avatar.js` and include it:
|
|
|
71
84
|
|
|
72
85
|
## API
|
|
73
86
|
|
|
74
|
-
### `generateAvatarSvg(seed,
|
|
87
|
+
### `generateAvatarSvg(seed, options)`
|
|
75
88
|
|
|
76
89
|
| Parameter | Type | Default | Description |
|
|
77
90
|
|-----------|------|---------|-------------|
|
|
78
91
|
| `seed` | `string` | *required* | Any string to generate the avatar from |
|
|
79
|
-
| `size` | `number` | `100` | Width/height in pixels |
|
|
80
|
-
| `square` | `boolean` | `false` | `true` for square, `false` for circle |
|
|
81
|
-
| `animated` | `boolean` | `true` | Enable breathing, blinking, twitching animations |
|
|
92
|
+
| `options.size` | `number` | `100` | Width/height in pixels |
|
|
93
|
+
| `options.square` | `boolean` | `false` | `true` for square, `false` for circle |
|
|
94
|
+
| `options.animated` | `boolean` | `true` | Enable breathing, blinking, twitching animations |
|
|
95
|
+
| `options.mood` | `string` | `'random'` | `'random'`, `'happy'`, `'sad'`, `'angry'`, `'surprised'`, `'chill'` |
|
|
96
|
+
| `options.palette` | `string` | `'default'` | `'default'`, `'pastel'`, `'neon'`, `'monochrome'` |
|
|
97
|
+
| `options.eyebrows` | `boolean` | `true` | Show expressive eyebrows |
|
|
82
98
|
|
|
83
99
|
**Returns:** SVG string ready to inject into DOM
|
|
84
100
|
|
|
85
101
|
## Examples
|
|
86
102
|
|
|
87
103
|
```javascript
|
|
88
|
-
// Default
|
|
104
|
+
// Default avatar
|
|
89
105
|
generateAvatarSvg('user123')
|
|
90
106
|
|
|
107
|
+
// Happy avatar with neon colors
|
|
108
|
+
generateAvatarSvg('user123', { mood: 'happy', palette: 'neon' })
|
|
109
|
+
|
|
110
|
+
// Sad avatar with pastel colors
|
|
111
|
+
generateAvatarSvg('user123', { mood: 'sad', palette: 'pastel', size: 200 })
|
|
112
|
+
|
|
91
113
|
// Large square avatar, no animation
|
|
92
|
-
generateAvatarSvg('team-member', 256, true, false)
|
|
114
|
+
generateAvatarSvg('team-member', { size: 256, square: true, animated: false })
|
|
93
115
|
|
|
94
116
|
// Use email as seed (consistent across sessions)
|
|
95
|
-
generateAvatarSvg('john@company.com', 80)
|
|
117
|
+
generateAvatarSvg('john@company.com', { size: 80, mood: 'chill' })
|
|
118
|
+
|
|
119
|
+
// Monochrome avatar for professional UI
|
|
120
|
+
generateAvatarSvg('user-id', { palette: 'monochrome', mood: 'chill' })
|
|
96
121
|
```
|
|
97
122
|
|
|
98
123
|
## Use Cases
|
|
@@ -108,11 +133,11 @@ generateAvatarSvg('john@company.com', 80)
|
|
|
108
133
|
|
|
109
134
|
With the current feature set, Quirkatar can generate:
|
|
110
135
|
|
|
111
|
-
**8 head shapes à 7 ears à 14 eyes à 11 mouths à 7 accessories à 8 headwear à 3 cheeks Ã
|
|
136
|
+
**8 head shapes à 7 ears à 14 eyes à 11 mouths à 7 accessories à 8 headwear à 3 cheeks à 4 eyebrows à 6 moods à 4 palettes =**
|
|
112
137
|
|
|
113
|
-
> **~
|
|
138
|
+
> **~34 million unique avatars**
|
|
114
139
|
|
|
115
|
-
...and that's not even counting color
|
|
140
|
+
...and that's not even counting color variations.
|
|
116
141
|
|
|
117
142
|
## Browser Support
|
|
118
143
|
|
package/avatar.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
// Quirkatar - The quirkiest avatar generator
|
|
2
|
+
// https://github.com/Nitty-Gritty-Design/quirkatar
|
|
3
|
+
|
|
1
4
|
// Simple PRNG
|
|
2
5
|
function xmur3(str) {
|
|
3
6
|
let h = 1779033703 ^ str.length;
|
|
@@ -21,32 +24,127 @@ function mulberry32(a) {
|
|
|
21
24
|
};
|
|
22
25
|
}
|
|
23
26
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
27
|
+
// Color palettes
|
|
28
|
+
const PALETTES = {
|
|
29
|
+
default: [
|
|
30
|
+
'#FFAD08', '#EDD75A', '#73B06F', '#0C8F8F', '#405059',
|
|
31
|
+
'#FF9F1C', '#FFBF69', '#CBF3F0', '#2EC4B6', '#264653',
|
|
32
|
+
'#2A9D8F', '#E9C46A', '#F4A261', '#E76F51', '#FFCDB2',
|
|
33
|
+
'#FFB4A2', '#E5989B', '#B5838D', '#6D6875', '#8ECAE6',
|
|
34
|
+
'#219EBC', '#023047', '#FFB703', '#FB8500', '#CDB4DB',
|
|
35
|
+
'#FFC8DD', '#FFAFCC', '#BDE0FE', '#A2D2FF', '#F94144',
|
|
36
|
+
'#F3722C', '#F8961E', '#F9C74F', '#90BE6D', '#43AA8B', '#577590'
|
|
37
|
+
],
|
|
38
|
+
pastel: [
|
|
39
|
+
'#FFB5E8', '#FF9CEE', '#FFCCF9', '#FCC2FF', '#F6A6FF',
|
|
40
|
+
'#B28DFF', '#C5A3FF', '#D5AAFF', '#ECD4FF', '#AFCBFF',
|
|
41
|
+
'#AFF8DB', '#BFFCC6', '#E7FFAC', '#FFFFD1', '#FFC9DE',
|
|
42
|
+
'#FFABAB', '#FFDAC1', '#B5EAD7', '#C7CEEA', '#E2F0CB'
|
|
43
|
+
],
|
|
44
|
+
neon: [
|
|
45
|
+
'#FF00FF', '#00FFFF', '#FF00AA', '#AAFF00', '#00FF00',
|
|
46
|
+
'#FF6600', '#0066FF', '#FFFF00', '#FF0066', '#6600FF',
|
|
47
|
+
'#00FF66', '#FF3300', '#0033FF', '#FF0099', '#99FF00'
|
|
48
|
+
],
|
|
49
|
+
monochrome: [
|
|
50
|
+
'#1a1a1a', '#2d2d2d', '#404040', '#535353', '#666666',
|
|
51
|
+
'#7a7a7a', '#8d8d8d', '#a0a0a0', '#b3b3b3', '#c6c6c6',
|
|
52
|
+
'#d9d9d9', '#ececec', '#ffffff'
|
|
53
|
+
]
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
// Mood configurations
|
|
57
|
+
const MOODS = {
|
|
58
|
+
happy: {
|
|
59
|
+
eyes: ['happy', 'normal', 'wink', 'star', 'heart'],
|
|
60
|
+
mouth: ['smile', 'openSmile', 'tongue', 'cat'],
|
|
61
|
+
eyebrows: 'raised'
|
|
62
|
+
},
|
|
63
|
+
sad: {
|
|
64
|
+
eyes: ['sleepy', 'normal', 'wink'],
|
|
65
|
+
mouth: ['frown', 'o', 'zigzag'],
|
|
66
|
+
eyebrows: 'droopy'
|
|
67
|
+
},
|
|
68
|
+
angry: {
|
|
69
|
+
eyes: ['normal', 'cyclops', 'wink'],
|
|
70
|
+
mouth: ['frown', 'teeth', 'zigzag'],
|
|
71
|
+
eyebrows: 'angry'
|
|
72
|
+
},
|
|
73
|
+
surprised: {
|
|
74
|
+
eyes: ['normal', 'cyclops', 'three', 'star'],
|
|
75
|
+
mouth: ['o', 'openSmile'],
|
|
76
|
+
eyebrows: 'raised'
|
|
77
|
+
},
|
|
78
|
+
chill: {
|
|
79
|
+
eyes: ['sleepy', 'normal', 'wink', 'glasses'],
|
|
80
|
+
mouth: ['smile', 'cat', 'o'],
|
|
81
|
+
eyebrows: 'neutral'
|
|
82
|
+
},
|
|
83
|
+
random: null
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Generate a quirky avatar SVG
|
|
88
|
+
* @param {string} seed - The seed string for deterministic generation
|
|
89
|
+
* @param {Object|number} options - Options object or size (legacy)
|
|
90
|
+
* @param {number} options.size - Avatar size in pixels (default: 100)
|
|
91
|
+
* @param {boolean} options.square - Square avatar instead of circle (default: false)
|
|
92
|
+
* @param {boolean} options.animated - Enable animations (default: true)
|
|
93
|
+
* @param {string} options.mood - 'random'|'happy'|'sad'|'angry'|'surprised'|'chill' (default: 'random')
|
|
94
|
+
* @param {string} options.palette - 'default'|'pastel'|'neon'|'monochrome' (default: 'default')
|
|
95
|
+
* @param {boolean} options.eyebrows - Show eyebrows (default: true)
|
|
96
|
+
* @returns {string} SVG string
|
|
97
|
+
*/
|
|
98
|
+
function generateAvatarSvg(seed, options = {}) {
|
|
99
|
+
// Legacy support: generateAvatarSvg(seed, size, square, animated)
|
|
100
|
+
if (typeof options === 'number' || typeof options === 'boolean') {
|
|
101
|
+
options = {
|
|
102
|
+
size: typeof options === 'number' ? options : 100,
|
|
103
|
+
square: typeof options === 'boolean' ? options : false,
|
|
104
|
+
animated: arguments[3] !== undefined ? arguments[3] : true
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const {
|
|
109
|
+
size = 100,
|
|
110
|
+
square = false,
|
|
111
|
+
animated = true,
|
|
112
|
+
mood = 'random',
|
|
113
|
+
palette = 'default',
|
|
114
|
+
eyebrows: showEyebrows = true
|
|
115
|
+
} = options;
|
|
33
116
|
|
|
34
|
-
function generateAvatarSvg(seed, size = 100, square = false, animated = true) {
|
|
35
117
|
const seedNum = xmur3(seed)();
|
|
36
118
|
const rand = mulberry32(seedNum);
|
|
37
119
|
|
|
38
120
|
const pick = (arr) => arr[Math.floor(rand() * arr.length)];
|
|
39
121
|
|
|
122
|
+
// Get colors from palette
|
|
123
|
+
const COLORS = PALETTES[palette] || PALETTES.default;
|
|
40
124
|
const bgColor = pick(COLORS);
|
|
41
125
|
let headColor = pick(COLORS);
|
|
42
126
|
while (headColor === bgColor) headColor = pick(COLORS);
|
|
43
127
|
let detailColor = pick(COLORS);
|
|
44
128
|
while (detailColor === bgColor || detailColor === headColor) detailColor = pick(COLORS);
|
|
45
129
|
|
|
130
|
+
// Get mood config
|
|
131
|
+
const moodConfig = MOODS[mood] || MOODS.random;
|
|
132
|
+
|
|
133
|
+
// Select features based on mood
|
|
46
134
|
const headShape = pick(['circle', 'squircle', 'blob', 'triangle', 'hexagon', 'diamond', 'star', 'cloud']);
|
|
47
135
|
const ears = pick(['none', 'cat', 'bear', 'bunny', 'alien', 'elf', 'robot']);
|
|
48
|
-
|
|
49
|
-
|
|
136
|
+
|
|
137
|
+
// Eyes based on mood
|
|
138
|
+
const allEyes = ['normal', 'happy', 'sleepy', 'cyclops', 'glasses', 'three', 'wink', 'star', 'heart'];
|
|
139
|
+
const eyes = moodConfig ? pick(moodConfig.eyes) : pick(allEyes);
|
|
140
|
+
|
|
141
|
+
// Mouth based on mood
|
|
142
|
+
const allMouths = ['smile', 'openSmile', 'frown', 'cat', 'vampire', 'o', 'zigzag', 'tongue', 'teeth'];
|
|
143
|
+
const mouth = moodConfig ? pick(moodConfig.mouth) : pick(allMouths);
|
|
144
|
+
|
|
145
|
+
// Eyebrows based on mood
|
|
146
|
+
const eyebrowType = moodConfig ? moodConfig.eyebrows : pick(['neutral', 'raised', 'droopy', 'angry']);
|
|
147
|
+
|
|
50
148
|
const accessory = pick(['none', 'none', 'none', 'freckles', 'blush', 'mustache', 'beard']);
|
|
51
149
|
const headwear = pick(['none', 'none', 'none', 'hat', 'crown', 'horns', 'headphones', 'bow']);
|
|
52
150
|
const cheeks = pick(['none', 'rosy', 'dimples']);
|
|
@@ -143,96 +241,115 @@ function generateAvatarSvg(seed, size = 100, square = false, animated = true) {
|
|
|
143
241
|
svg += `<path d="M 25 60 C 10 60 10 45 25 45 C 25 30 45 25 55 35 C 65 20 90 30 85 50 C 95 55 90 70 75 70 L 25 70 C 15 70 15 60 25 60 Z" fill="${headColor}" />`;
|
|
144
242
|
}
|
|
145
243
|
|
|
244
|
+
// Eyebrows (above eyes)
|
|
245
|
+
if (showEyebrows) {
|
|
246
|
+
svg += `<g fill="none" stroke="#111" stroke-width="3" stroke-linecap="round">`;
|
|
247
|
+
if (eyebrowType === 'raised') {
|
|
248
|
+
svg += `<path d="M 25 35 Q 35 30 45 35" />
|
|
249
|
+
<path d="M 55 35 Q 65 30 75 35" />`;
|
|
250
|
+
} else if (eyebrowType === 'droopy') {
|
|
251
|
+
svg += `<path d="M 25 35 Q 35 40 45 35" />
|
|
252
|
+
<path d="M 55 35 Q 65 40 75 35" />`;
|
|
253
|
+
} else if (eyebrowType === 'angry') {
|
|
254
|
+
svg += `<path d="M 25 40 L 45 35" />
|
|
255
|
+
<path d="M 55 35 L 75 40" />`;
|
|
256
|
+
} else {
|
|
257
|
+
svg += `<path d="M 25 35 L 45 35" />
|
|
258
|
+
<path d="M 55 35 L 75 35" />`;
|
|
259
|
+
}
|
|
260
|
+
svg += `</g>`;
|
|
261
|
+
}
|
|
262
|
+
|
|
146
263
|
// Eyes
|
|
147
264
|
svg += `<g class="quirks-blink">`;
|
|
148
265
|
if (eyes === 'normal') {
|
|
149
|
-
svg += `<circle cx="35" cy="
|
|
150
|
-
<circle cx="65" cy="
|
|
266
|
+
svg += `<circle cx="35" cy="48" r="6" fill="#111" />
|
|
267
|
+
<circle cx="65" cy="48" r="6" fill="#111" />`;
|
|
151
268
|
} else if (eyes === 'happy') {
|
|
152
|
-
svg += `<path d="M 25
|
|
153
|
-
<path d="M 55
|
|
269
|
+
svg += `<path d="M 25 48 Q 35 38 45 48" stroke="#111" stroke-width="4" stroke-linecap="round" fill="none" />
|
|
270
|
+
<path d="M 55 48 Q 65 38 75 48" stroke="#111" stroke-width="4" stroke-linecap="round" fill="none" />`;
|
|
154
271
|
} else if (eyes === 'sleepy') {
|
|
155
|
-
svg += `<path d="M 25
|
|
156
|
-
<path d="M 55
|
|
272
|
+
svg += `<path d="M 25 48 Q 35 58 45 48" stroke="#111" stroke-width="4" stroke-linecap="round" fill="none" />
|
|
273
|
+
<path d="M 55 48 Q 65 58 75 48" stroke="#111" stroke-width="4" stroke-linecap="round" fill="none" />`;
|
|
157
274
|
} else if (eyes === 'cyclops') {
|
|
158
|
-
svg += `<circle cx="50" cy="
|
|
159
|
-
<circle cx="50" cy="
|
|
275
|
+
svg += `<circle cx="50" cy="45" r="14" fill="#fff" />
|
|
276
|
+
<circle cx="50" cy="45" r="6" fill="#111" />`;
|
|
160
277
|
} else if (eyes === 'glasses') {
|
|
161
|
-
svg += `<rect x="20" y="
|
|
162
|
-
<rect x="54" y="
|
|
163
|
-
<line x1="46" y1="
|
|
164
|
-
<circle cx="33" cy="
|
|
165
|
-
<circle cx="67" cy="
|
|
278
|
+
svg += `<rect x="20" y="38" width="26" height="18" rx="4" fill="none" stroke="#111" stroke-width="4" />
|
|
279
|
+
<rect x="54" y="38" width="26" height="18" rx="4" fill="none" stroke="#111" stroke-width="4" />
|
|
280
|
+
<line x1="46" y1="47" x2="54" y2="47" stroke="#111" stroke-width="4" />
|
|
281
|
+
<circle cx="33" cy="47" r="4" fill="#111" />
|
|
282
|
+
<circle cx="67" cy="47" r="4" fill="#111" />`;
|
|
166
283
|
} else if (eyes === 'three') {
|
|
167
|
-
svg += `<circle cx="50" cy="
|
|
168
|
-
<circle cx="30" cy="
|
|
169
|
-
<circle cx="70" cy="
|
|
284
|
+
svg += `<circle cx="50" cy="38" r="5" fill="#111" />
|
|
285
|
+
<circle cx="30" cy="53" r="5" fill="#111" />
|
|
286
|
+
<circle cx="70" cy="53" r="5" fill="#111" />`;
|
|
170
287
|
} else if (eyes === 'wink') {
|
|
171
|
-
svg += `<circle cx="35" cy="
|
|
172
|
-
<path d="M 55
|
|
288
|
+
svg += `<circle cx="35" cy="48" r="6" fill="#111" />
|
|
289
|
+
<path d="M 55 48 Q 65 38 75 48" stroke="#111" stroke-width="4" stroke-linecap="round" fill="none" />`;
|
|
173
290
|
} else if (eyes === 'star') {
|
|
174
|
-
svg += `<polygon points="35,
|
|
175
|
-
<polygon points="65,
|
|
291
|
+
svg += `<polygon points="35,42 37,46 41,46 38,49 39,53 35,51 31,53 32,49 29,46 33,46" fill="#111" />
|
|
292
|
+
<polygon points="65,42 67,46 71,46 68,49 69,53 65,51 61,53 62,49 59,46 63,46" fill="#111" />`;
|
|
176
293
|
} else if (eyes === 'heart') {
|
|
177
|
-
svg += `<path d="M 35
|
|
178
|
-
<path d="M 65
|
|
294
|
+
svg += `<path d="M 35 51 C 35 47 30 47 30 51 C 30 55 35 58 35 58 C 35 58 40 55 40 51 C 40 47 35 47 35 51 Z" fill="#e91e63" />
|
|
295
|
+
<path d="M 65 51 C 65 47 60 47 60 51 C 60 55 65 58 65 58 C 65 58 70 55 70 51 C 70 47 65 47 65 51 Z" fill="#e91e63" />`;
|
|
179
296
|
}
|
|
180
297
|
svg += `</g>`;
|
|
181
298
|
|
|
182
299
|
// Mouth
|
|
183
300
|
if (mouth === 'smile') {
|
|
184
|
-
svg += `<g class="quirks-smile"><path d="M 35
|
|
301
|
+
svg += `<g class="quirks-smile"><path d="M 35 68 Q 50 83 65 68" stroke="#111" stroke-width="4" stroke-linecap="round" fill="none" /></g>`;
|
|
185
302
|
} else if (mouth === 'openSmile') {
|
|
186
|
-
svg += `<g class="quirks-talk"><path d="M 30
|
|
187
|
-
<path d="M 40
|
|
303
|
+
svg += `<g class="quirks-talk"><path d="M 30 63 Q 50 88 70 63 Z" fill="#111" />
|
|
304
|
+
<path d="M 40 73 Q 50 78 60 73 Q 50 68 40 73" fill="#ff6b6b" /></g>`;
|
|
188
305
|
} else if (mouth === 'frown') {
|
|
189
|
-
svg += `<g class="quirks-frown"><path d="M 35
|
|
306
|
+
svg += `<g class="quirks-frown"><path d="M 35 78 Q 50 63 65 78" stroke="#111" stroke-width="4" stroke-linecap="round" fill="none" /></g>`;
|
|
190
307
|
} else if (mouth === 'cat') {
|
|
191
|
-
svg += `<g class="quirks-twitch"><path d="M 35
|
|
308
|
+
svg += `<g class="quirks-twitch"><path d="M 35 68 Q 42.5 78 50 68 Q 57.5 78 65 68" stroke="#111" stroke-width="4" stroke-linecap="round" fill="none" /></g>`;
|
|
192
309
|
} else if (mouth === 'vampire') {
|
|
193
|
-
svg += `<g class="quirks-smile"><path d="M 35
|
|
194
|
-
<polygon points="40,
|
|
195
|
-
<polygon points="60,
|
|
310
|
+
svg += `<g class="quirks-smile"><path d="M 35 68 Q 50 83 65 68" stroke="#111" stroke-width="4" stroke-linecap="round" fill="none" />
|
|
311
|
+
<polygon points="40,71 45,72 42.5,78" fill="#fff" />
|
|
312
|
+
<polygon points="60,71 55,72 57.5,78" fill="#fff" /></g>`;
|
|
196
313
|
} else if (mouth === 'o') {
|
|
197
|
-
svg += `<g class="quirks-talk"><circle cx="50" cy="
|
|
314
|
+
svg += `<g class="quirks-talk"><circle cx="50" cy="73" r="8" fill="#111" /></g>`;
|
|
198
315
|
} else if (mouth === 'zigzag') {
|
|
199
|
-
svg += `<g class="quirks-frown"><polyline points="35,
|
|
316
|
+
svg += `<g class="quirks-frown"><polyline points="35,68 42.5,73 50,68 57.5,73 65,68" stroke="#111" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" fill="none" /></g>`;
|
|
200
317
|
} else if (mouth === 'tongue') {
|
|
201
|
-
svg += `<g class="quirks-smile"><path d="M 35
|
|
202
|
-
<ellipse cx="50" cy="
|
|
318
|
+
svg += `<g class="quirks-smile"><path d="M 35 68 Q 50 83 65 68" stroke="#111" stroke-width="4" stroke-linecap="round" fill="none" />
|
|
319
|
+
<ellipse cx="50" cy="78" rx="8" ry="10" fill="#e91e63" /></g>`;
|
|
203
320
|
} else if (mouth === 'teeth') {
|
|
204
|
-
svg += `<g class="quirks-talk"><rect x="32" y="
|
|
205
|
-
<rect x="35" y="
|
|
206
|
-
<line x1="40" y1="
|
|
207
|
-
<line x1="50" y1="
|
|
208
|
-
<line x1="60" y1="
|
|
321
|
+
svg += `<g class="quirks-talk"><rect x="32" y="65" width="36" height="18" rx="4" fill="#111" />
|
|
322
|
+
<rect x="35" y="65" width="30" height="8" fill="#fff" />
|
|
323
|
+
<line x1="40" y1="65" x2="40" y2="73" stroke="#111" stroke-width="1" />
|
|
324
|
+
<line x1="50" y1="65" x2="50" y2="73" stroke="#111" stroke-width="1" />
|
|
325
|
+
<line x1="60" y1="65" x2="60" y2="73" stroke="#111" stroke-width="1" /></g>`;
|
|
209
326
|
}
|
|
210
327
|
|
|
211
328
|
// Accessory (face details)
|
|
212
329
|
if (accessory === 'freckles') {
|
|
213
|
-
svg += `<circle cx="25" cy="
|
|
214
|
-
<circle cx="30" cy="
|
|
215
|
-
<circle cx="20" cy="
|
|
216
|
-
<circle cx="75" cy="
|
|
217
|
-
<circle cx="70" cy="
|
|
218
|
-
<circle cx="80" cy="
|
|
330
|
+
svg += `<circle cx="25" cy="58" r="2" fill="#111" opacity="0.3" />
|
|
331
|
+
<circle cx="30" cy="61" r="2" fill="#111" opacity="0.3" />
|
|
332
|
+
<circle cx="20" cy="61" r="2" fill="#111" opacity="0.3" />
|
|
333
|
+
<circle cx="75" cy="58" r="2" fill="#111" opacity="0.3" />
|
|
334
|
+
<circle cx="70" cy="61" r="2" fill="#111" opacity="0.3" />
|
|
335
|
+
<circle cx="80" cy="61" r="2" fill="#111" opacity="0.3" />`;
|
|
219
336
|
} else if (accessory === 'blush') {
|
|
220
|
-
svg += `<ellipse cx="25" cy="
|
|
221
|
-
<ellipse cx="75" cy="
|
|
337
|
+
svg += `<ellipse cx="25" cy="58" rx="8" ry="5" fill="#ff6b6b" opacity="0.5" />
|
|
338
|
+
<ellipse cx="75" cy="58" rx="8" ry="5" fill="#ff6b6b" opacity="0.5" />`;
|
|
222
339
|
} else if (accessory === 'mustache') {
|
|
223
|
-
svg += `<path d="M 30
|
|
340
|
+
svg += `<path d="M 30 63 Q 50 53 70 63 Q 60 68 50 65 Q 40 68 30 63 Z" fill="#111" />`;
|
|
224
341
|
} else if (accessory === 'beard') {
|
|
225
|
-
svg += `<path d="M 30
|
|
226
|
-
<path d="M 35
|
|
342
|
+
svg += `<path d="M 30 68 Q 35 88 50 91 Q 65 88 70 68 Q 60 73 50 75 Q 40 73 30 68 Z" fill="${headColor}" opacity="0.8" />
|
|
343
|
+
<path d="M 35 71 Q 40 81 50 83 Q 60 81 65 71" stroke="#111" stroke-width="2" fill="none" opacity="0.3" />`;
|
|
227
344
|
}
|
|
228
345
|
|
|
229
346
|
// Cheeks
|
|
230
347
|
if (cheeks === 'rosy') {
|
|
231
|
-
svg += `<circle cx="25" cy="
|
|
232
|
-
<circle cx="75" cy="
|
|
348
|
+
svg += `<circle cx="25" cy="61" r="6" fill="#ffb6c1" opacity="0.4" />
|
|
349
|
+
<circle cx="75" cy="61" r="6" fill="#ffb6c1" opacity="0.4" />`;
|
|
233
350
|
} else if (cheeks === 'dimples') {
|
|
234
|
-
svg += `<path d="M 22
|
|
235
|
-
<path d="M 72
|
|
351
|
+
svg += `<path d="M 22 61 Q 25 65 28 61" stroke="#111" stroke-width="2" fill="none" opacity="0.3" />
|
|
352
|
+
<path d="M 72 61 Q 75 65 78 61" stroke="#111" stroke-width="2" fill="none" opacity="0.3" />`;
|
|
236
353
|
}
|
|
237
354
|
|
|
238
355
|
svg += `</g>`;
|
|
@@ -267,7 +384,9 @@ function generateAvatarSvg(seed, size = 100, square = false, animated = true) {
|
|
|
267
384
|
|
|
268
385
|
// Export for both ES modules and CommonJS
|
|
269
386
|
if (typeof module !== 'undefined' && module.exports) {
|
|
270
|
-
module.exports = { generateAvatarSvg };
|
|
387
|
+
module.exports = { generateAvatarSvg, PALETTES, MOODS };
|
|
271
388
|
} else if (typeof window !== 'undefined') {
|
|
272
389
|
window.generateAvatarSvg = generateAvatarSvg;
|
|
390
|
+
window.PALETTES = PALETTES;
|
|
391
|
+
window.MOODS = MOODS;
|
|
273
392
|
}
|
package/package.json
CHANGED