mcp-avatar-builder 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/LICENSE +21 -0
- package/README.md +163 -0
- package/build/composer.d.ts +4 -0
- package/build/composer.d.ts.map +1 -0
- package/build/composer.js +65 -0
- package/build/composer.js.map +1 -0
- package/build/index.d.ts +3 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +7 -0
- package/build/index.js.map +1 -0
- package/build/rasterizer.d.ts +2 -0
- package/build/rasterizer.d.ts.map +1 -0
- package/build/rasterizer.js +12 -0
- package/build/rasterizer.js.map +1 -0
- package/build/server.d.ts +3 -0
- package/build/server.d.ts.map +1 -0
- package/build/server.js +118 -0
- package/build/server.js.map +1 -0
- package/build/styles/chibi/index.d.ts +3 -0
- package/build/styles/chibi/index.d.ts.map +1 -0
- package/build/styles/chibi/index.js +57 -0
- package/build/styles/chibi/index.js.map +1 -0
- package/build/styles/chibi/palettes.d.ts +3 -0
- package/build/styles/chibi/palettes.d.ts.map +1 -0
- package/build/styles/chibi/palettes.js +29 -0
- package/build/styles/chibi/palettes.js.map +1 -0
- package/build/styles/chibi/parts/accessories.d.ts +3 -0
- package/build/styles/chibi/parts/accessories.d.ts.map +1 -0
- package/build/styles/chibi/parts/accessories.js +18 -0
- package/build/styles/chibi/parts/accessories.js.map +1 -0
- package/build/styles/chibi/parts/clothing.d.ts +3 -0
- package/build/styles/chibi/parts/clothing.d.ts.map +1 -0
- package/build/styles/chibi/parts/clothing.js +21 -0
- package/build/styles/chibi/parts/clothing.js.map +1 -0
- package/build/styles/chibi/parts/eyebrows.d.ts +3 -0
- package/build/styles/chibi/parts/eyebrows.d.ts.map +1 -0
- package/build/styles/chibi/parts/eyebrows.js +15 -0
- package/build/styles/chibi/parts/eyebrows.js.map +1 -0
- package/build/styles/chibi/parts/eyes.d.ts +3 -0
- package/build/styles/chibi/parts/eyes.d.ts.map +1 -0
- package/build/styles/chibi/parts/eyes.js +29 -0
- package/build/styles/chibi/parts/eyes.js.map +1 -0
- package/build/styles/chibi/parts/hair.d.ts +4 -0
- package/build/styles/chibi/parts/hair.d.ts.map +1 -0
- package/build/styles/chibi/parts/hair.js +29 -0
- package/build/styles/chibi/parts/hair.js.map +1 -0
- package/build/styles/chibi/parts/head.d.ts +3 -0
- package/build/styles/chibi/parts/head.d.ts.map +1 -0
- package/build/styles/chibi/parts/head.js +15 -0
- package/build/styles/chibi/parts/head.js.map +1 -0
- package/build/styles/chibi/parts/mouth.d.ts +3 -0
- package/build/styles/chibi/parts/mouth.d.ts.map +1 -0
- package/build/styles/chibi/parts/mouth.js +12 -0
- package/build/styles/chibi/parts/mouth.js.map +1 -0
- package/build/styles/cyberpunk/defs.d.ts +3 -0
- package/build/styles/cyberpunk/defs.d.ts.map +1 -0
- package/build/styles/cyberpunk/defs.js +74 -0
- package/build/styles/cyberpunk/defs.js.map +1 -0
- package/build/styles/cyberpunk/index.d.ts +3 -0
- package/build/styles/cyberpunk/index.d.ts.map +1 -0
- package/build/styles/cyberpunk/index.js +81 -0
- package/build/styles/cyberpunk/index.js.map +1 -0
- package/build/styles/cyberpunk/palettes.d.ts +3 -0
- package/build/styles/cyberpunk/palettes.d.ts.map +1 -0
- package/build/styles/cyberpunk/palettes.js +43 -0
- package/build/styles/cyberpunk/palettes.js.map +1 -0
- package/build/styles/cyberpunk/parts/accessories.d.ts +3 -0
- package/build/styles/cyberpunk/parts/accessories.d.ts.map +1 -0
- package/build/styles/cyberpunk/parts/accessories.js +77 -0
- package/build/styles/cyberpunk/parts/accessories.js.map +1 -0
- package/build/styles/cyberpunk/parts/background.d.ts +3 -0
- package/build/styles/cyberpunk/parts/background.d.ts.map +1 -0
- package/build/styles/cyberpunk/parts/background.js +132 -0
- package/build/styles/cyberpunk/parts/background.js.map +1 -0
- package/build/styles/cyberpunk/parts/clothing.d.ts +3 -0
- package/build/styles/cyberpunk/parts/clothing.d.ts.map +1 -0
- package/build/styles/cyberpunk/parts/clothing.js +137 -0
- package/build/styles/cyberpunk/parts/clothing.js.map +1 -0
- package/build/styles/cyberpunk/parts/effects.d.ts +3 -0
- package/build/styles/cyberpunk/parts/effects.d.ts.map +1 -0
- package/build/styles/cyberpunk/parts/effects.js +33 -0
- package/build/styles/cyberpunk/parts/effects.js.map +1 -0
- package/build/styles/cyberpunk/parts/eyebrows.d.ts +3 -0
- package/build/styles/cyberpunk/parts/eyebrows.d.ts.map +1 -0
- package/build/styles/cyberpunk/parts/eyebrows.js +15 -0
- package/build/styles/cyberpunk/parts/eyebrows.js.map +1 -0
- package/build/styles/cyberpunk/parts/eyes.d.ts +3 -0
- package/build/styles/cyberpunk/parts/eyes.d.ts.map +1 -0
- package/build/styles/cyberpunk/parts/eyes.js +110 -0
- package/build/styles/cyberpunk/parts/eyes.js.map +1 -0
- package/build/styles/cyberpunk/parts/face_mods.d.ts +3 -0
- package/build/styles/cyberpunk/parts/face_mods.d.ts.map +1 -0
- package/build/styles/cyberpunk/parts/face_mods.js +105 -0
- package/build/styles/cyberpunk/parts/face_mods.js.map +1 -0
- package/build/styles/cyberpunk/parts/hair.d.ts +4 -0
- package/build/styles/cyberpunk/parts/hair.d.ts.map +1 -0
- package/build/styles/cyberpunk/parts/hair.js +175 -0
- package/build/styles/cyberpunk/parts/hair.js.map +1 -0
- package/build/styles/cyberpunk/parts/head.d.ts +3 -0
- package/build/styles/cyberpunk/parts/head.d.ts.map +1 -0
- package/build/styles/cyberpunk/parts/head.js +158 -0
- package/build/styles/cyberpunk/parts/head.js.map +1 -0
- package/build/styles/cyberpunk/parts/mouth.d.ts +3 -0
- package/build/styles/cyberpunk/parts/mouth.d.ts.map +1 -0
- package/build/styles/cyberpunk/parts/mouth.js +71 -0
- package/build/styles/cyberpunk/parts/mouth.js.map +1 -0
- package/build/styles/index.d.ts +4 -0
- package/build/styles/index.d.ts.map +1 -0
- package/build/styles/index.js +15 -0
- package/build/styles/index.js.map +1 -0
- package/build/styles/style.d.ts +15 -0
- package/build/styles/style.d.ts.map +1 -0
- package/build/styles/style.js +2 -0
- package/build/styles/style.js.map +1 -0
- package/build/types.d.ts +37 -0
- package/build/types.d.ts.map +1 -0
- package/build/types.js +2 -0
- package/build/types.js.map +1 -0
- package/package.json +40 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ruslan Strazhnyk
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# MCP Avatar Builder
|
|
2
|
+
|
|
3
|
+
An MCP server that generates composable avatars via SVG layer composition. Plug it into Claude Code (or any MCP client) to create avatars on the fly.
|
|
4
|
+
|
|
5
|
+
## Install as Agent Skill
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npx skills add Desperado/mcp-avatar-builder
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
This registers the avatar-builder skill so your AI agent knows when and how to generate avatars. Browse it on [skills.sh](https://skills.sh/Desperado/mcp-avatar-builder/avatar-builder).
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install
|
|
17
|
+
npm run build
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
### Add to Claude Code
|
|
21
|
+
|
|
22
|
+
Add to your MCP settings (`~/.claude/settings.json` or project `.mcp.json`):
|
|
23
|
+
|
|
24
|
+
```json
|
|
25
|
+
{
|
|
26
|
+
"mcpServers": {
|
|
27
|
+
"avatar-builder": {
|
|
28
|
+
"command": "npx",
|
|
29
|
+
"args": ["-y", "mcp-avatar-builder"]
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Or point to a local build:
|
|
36
|
+
|
|
37
|
+
```json
|
|
38
|
+
{
|
|
39
|
+
"mcpServers": {
|
|
40
|
+
"avatar-builder": {
|
|
41
|
+
"command": "node",
|
|
42
|
+
"args": ["/path/to/mcp-avatar-builder/build/index.js"]
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Other MCP Clients
|
|
49
|
+
|
|
50
|
+
Any MCP-compatible client (Cursor, Cline, GitHub Copilot, etc.) can use this server. Configure the command as shown above in your client's MCP settings.
|
|
51
|
+
|
|
52
|
+
## Tools
|
|
53
|
+
|
|
54
|
+
### `generate_avatar`
|
|
55
|
+
|
|
56
|
+
Generate a composable avatar with customizable parts and colors.
|
|
57
|
+
|
|
58
|
+
| Parameter | Type | Default | Description |
|
|
59
|
+
| --------- | ------ | --------- | ------------------------------------ |
|
|
60
|
+
| `style` | string | `"chibi"` | Style: `chibi` or `cyberpunk` |
|
|
61
|
+
| `options` | object | random | Part selections per category |
|
|
62
|
+
| `colors` | object | palette | Color overrides (hex or palette name)|
|
|
63
|
+
| `seed` | string | — | Seed for deterministic generation |
|
|
64
|
+
| `format` | string | `"svg"` | Output: `svg` or `png` |
|
|
65
|
+
| `size` | number | `200` | PNG size in pixels (16–2048) |
|
|
66
|
+
|
|
67
|
+
Example:
|
|
68
|
+
|
|
69
|
+
```json
|
|
70
|
+
{
|
|
71
|
+
"style": "cyberpunk",
|
|
72
|
+
"options": {
|
|
73
|
+
"background": "rain_city",
|
|
74
|
+
"head": "angular",
|
|
75
|
+
"eyes": "led",
|
|
76
|
+
"mouth": "smirk",
|
|
77
|
+
"hair_back": "mohawk",
|
|
78
|
+
"hair_front": "mohawk",
|
|
79
|
+
"face_mods": "led_tattoo",
|
|
80
|
+
"clothing": "techwear",
|
|
81
|
+
"effects": "glitch"
|
|
82
|
+
},
|
|
83
|
+
"colors": {
|
|
84
|
+
"neon": "hot-pink",
|
|
85
|
+
"hair": "electric-blue",
|
|
86
|
+
"eyes": "cyan"
|
|
87
|
+
},
|
|
88
|
+
"seed": "my-avatar",
|
|
89
|
+
"format": "png",
|
|
90
|
+
"size": 800
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### `list_styles`
|
|
95
|
+
|
|
96
|
+
List all available avatar styles with their categories and palettes.
|
|
97
|
+
|
|
98
|
+
### `list_parts`
|
|
99
|
+
|
|
100
|
+
List available parts/variants for a style, optionally filtered by category.
|
|
101
|
+
|
|
102
|
+
```json
|
|
103
|
+
{ "style": "cyberpunk", "category": "eyes" }
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Available Styles
|
|
107
|
+
|
|
108
|
+
### Chibi (200x200)
|
|
109
|
+
|
|
110
|
+
Simple, cute pixel-art style.
|
|
111
|
+
|
|
112
|
+
**Categories:** head, eyes, eyebrows, mouth, hair_back, hair_front, clothing, accessories
|
|
113
|
+
|
|
114
|
+
**Palettes:**
|
|
115
|
+
- **Skin**: porcelain, ivory, sand, honey, chestnut, espresso
|
|
116
|
+
- **Hair**: black, dark-brown, brown, auburn, ginger, blonde, platinum, pink
|
|
117
|
+
- **Eyes**: brown, hazel, green, blue, gray, violet
|
|
118
|
+
|
|
119
|
+
### Cyberpunk (400x400)
|
|
120
|
+
|
|
121
|
+
High-detail style with neon glow effects, dark backgrounds, and cybernetic parts. Uses SVG filters (glow, scanlines, noise) and gradient fills for a rich look.
|
|
122
|
+
|
|
123
|
+
**Categories:** background, head, eyes, eyebrows, mouth, hair_back, hair_front, face_mods, clothing, accessories, effects
|
|
124
|
+
|
|
125
|
+
**Palettes:**
|
|
126
|
+
- **Skin**: pale-tech, porcelain, tan, bronze, dark, deep
|
|
127
|
+
- **Hair**: jet-black, chrome, neon-pink, electric-blue, toxic-green, white, purple, red
|
|
128
|
+
- **Eyes**: amber-led, cyan, red, white, green-circuit, chrome
|
|
129
|
+
- **Neon**: hot-pink, cyan, yellow, purple, green, orange
|
|
130
|
+
- **Accent**: chrome, gunmetal, matte-black, brushed-steel
|
|
131
|
+
|
|
132
|
+
**Parts:**
|
|
133
|
+
|
|
134
|
+
| Category | Variants |
|
|
135
|
+
| ------------- | -------------------------------------------- |
|
|
136
|
+
| background | circuit_grid, rain_city, dark_void |
|
|
137
|
+
| head | angular, scarred, implanted |
|
|
138
|
+
| eyes | led, visor, cyber |
|
|
139
|
+
| eyebrows | sharp, none |
|
|
140
|
+
| mouth | neutral, respirator, smirk |
|
|
141
|
+
| hair | mohawk, undercut, wired, shaved |
|
|
142
|
+
| face_mods | neural_port, led_tattoo, jaw_plate |
|
|
143
|
+
| clothing | techwear, tactical_vest, collar_rig |
|
|
144
|
+
| accessories | none, headset, holo_visor |
|
|
145
|
+
| effects | none, scanlines, glitch |
|
|
146
|
+
|
|
147
|
+
## Architecture
|
|
148
|
+
|
|
149
|
+
Avatars are composed from SVG fragment layers stacked in z-order. Each style defines its own categories (head, eyes, hair, etc.), color palettes, and part variants. The composer assembles fragments into a complete SVG, and an optional rasterizer converts to PNG via resvg.
|
|
150
|
+
|
|
151
|
+
```
|
|
152
|
+
Style → Part Renderers → Composer (SVG) → Rasterizer (PNG)
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### Adding a New Style
|
|
156
|
+
|
|
157
|
+
1. Create `src/styles/<name>/` with `index.ts`, `palettes.ts`, and `parts/` directory
|
|
158
|
+
2. Implement the `AvatarStyle` interface (see `src/styles/style.ts`)
|
|
159
|
+
3. Register in `src/styles/index.ts`
|
|
160
|
+
|
|
161
|
+
## License
|
|
162
|
+
|
|
163
|
+
MIT
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"composer.d.ts","sourceRoot":"","sources":["../src/composer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,KAAK,EAAE,aAAa,EAAgC,MAAM,YAAY,CAAC;AA2D9E,wBAAgB,OAAO,CACrB,KAAK,EAAE,WAAW,EAClB,OAAO,CAAC,EAAE,aAAa,EACvB,IAAI,CAAC,EAAE,MAAM,GACZ,MAAM,CAWR"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
// XorShift32 PRNG for deterministic seed-based randomization
|
|
2
|
+
function xorshift32(seed) {
|
|
3
|
+
let state = seed | 0 || 1;
|
|
4
|
+
return () => {
|
|
5
|
+
state ^= state << 13;
|
|
6
|
+
state ^= state >> 17;
|
|
7
|
+
state ^= state << 5;
|
|
8
|
+
return (state >>> 0) / 0xFFFFFFFF;
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
function hashString(str) {
|
|
12
|
+
let hash = 0;
|
|
13
|
+
for (let i = 0; i < str.length; i++) {
|
|
14
|
+
hash = ((hash << 5) - hash + str.charCodeAt(i)) | 0;
|
|
15
|
+
}
|
|
16
|
+
return hash;
|
|
17
|
+
}
|
|
18
|
+
function resolveColors(style, colors, rng) {
|
|
19
|
+
const pick = (key, palette) => {
|
|
20
|
+
if (colors?.[key])
|
|
21
|
+
return colors[key];
|
|
22
|
+
if (rng)
|
|
23
|
+
return palette[Math.floor(rng() * palette.length)].value;
|
|
24
|
+
return palette[0].value;
|
|
25
|
+
};
|
|
26
|
+
const resolved = {
|
|
27
|
+
skin: pick("skin", style.palettes.skin),
|
|
28
|
+
hair: pick("hair", style.palettes.hair),
|
|
29
|
+
eyes: pick("eyes", style.palettes.eyes),
|
|
30
|
+
clothing: colors?.clothing ?? "#4A90D9",
|
|
31
|
+
};
|
|
32
|
+
// Resolve any extra palette categories (e.g. neon, accent)
|
|
33
|
+
for (const key of Object.keys(style.palettes)) {
|
|
34
|
+
if (resolved[key] !== undefined)
|
|
35
|
+
continue;
|
|
36
|
+
resolved[key] = pick(key, style.palettes[key]);
|
|
37
|
+
}
|
|
38
|
+
return resolved;
|
|
39
|
+
}
|
|
40
|
+
function resolveParts(style, parts, rng) {
|
|
41
|
+
const resolved = { ...parts };
|
|
42
|
+
for (const category of style.categories) {
|
|
43
|
+
if (resolved[category.name] !== undefined)
|
|
44
|
+
continue;
|
|
45
|
+
if (rng) {
|
|
46
|
+
resolved[category.name] = category.variants[Math.floor(rng() * category.variants.length)];
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
resolved[category.name] = category.variants[category.default];
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return resolved;
|
|
53
|
+
}
|
|
54
|
+
export function compose(style, options, seed) {
|
|
55
|
+
const rng = seed ? xorshift32(hashString(seed)) : undefined;
|
|
56
|
+
const parts = resolveParts(style, options?.parts, rng);
|
|
57
|
+
const colors = resolveColors(style, options?.colors, rng);
|
|
58
|
+
const body = style.render({ parts, colors: options?.colors }, colors);
|
|
59
|
+
return [
|
|
60
|
+
`<svg xmlns="http://www.w3.org/2000/svg" viewBox="${style.viewBox}" width="200" height="200">`,
|
|
61
|
+
body,
|
|
62
|
+
`</svg>`,
|
|
63
|
+
].join("\n");
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=composer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"composer.js","sourceRoot":"","sources":["../src/composer.ts"],"names":[],"mappings":"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"}
|
package/build/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
package/build/index.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
|
+
import { createServer } from "./server.js";
|
|
4
|
+
const server = createServer();
|
|
5
|
+
const transport = new StdioServerTransport();
|
|
6
|
+
await server.connect(transport);
|
|
7
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,MAAM,MAAM,GAAG,YAAY,EAAE,CAAC;AAC9B,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;AAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rasterizer.d.ts","sourceRoot":"","sources":["../src/rasterizer.ts"],"names":[],"mappings":"AAEA,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,GAAE,MAAY,GAAG,MAAM,CASjE"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Resvg } from "@resvg/resvg-js";
|
|
2
|
+
export function rasterize(svg, size = 200) {
|
|
3
|
+
const resvg = new Resvg(svg, {
|
|
4
|
+
fitTo: {
|
|
5
|
+
mode: "width",
|
|
6
|
+
value: size,
|
|
7
|
+
},
|
|
8
|
+
});
|
|
9
|
+
const pngData = resvg.render();
|
|
10
|
+
return Buffer.from(pngData.asPng());
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=rasterizer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rasterizer.js","sourceRoot":"","sources":["../src/rasterizer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAExC,MAAM,UAAU,SAAS,CAAC,GAAW,EAAE,OAAe,GAAG;IACvD,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,GAAG,EAAE;QAC3B,KAAK,EAAE;YACL,IAAI,EAAE,OAAO;YACb,KAAK,EAAE,IAAI;SACZ;KACF,CAAC,CAAC;IACH,MAAM,OAAO,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;IAC/B,OAAO,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;AACtC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAMpE,wBAAgB,YAAY,IAAI,SAAS,CA0IxC"}
|
package/build/server.js
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { getStyle, listStyles } from "./styles/index.js";
|
|
4
|
+
import { compose } from "./composer.js";
|
|
5
|
+
import { rasterize } from "./rasterizer.js";
|
|
6
|
+
export function createServer() {
|
|
7
|
+
const server = new McpServer({
|
|
8
|
+
name: "mcp-avatar-builder",
|
|
9
|
+
version: "0.1.0",
|
|
10
|
+
});
|
|
11
|
+
server.tool("generate_avatar", "Generate a composable avatar. Produces SVG or PNG output with customizable parts and colors.", {
|
|
12
|
+
style: z.string().default("chibi").describe("Avatar style to use"),
|
|
13
|
+
options: z.record(z.union([z.string(), z.number()])).optional().describe("Part selections per category (e.g. {hair_front: 'bangs', eyes: 'cat'})"),
|
|
14
|
+
colors: z.object({
|
|
15
|
+
skin: z.string().optional(),
|
|
16
|
+
hair: z.string().optional(),
|
|
17
|
+
eyes: z.string().optional(),
|
|
18
|
+
clothing: z.string().optional(),
|
|
19
|
+
neon: z.string().optional().describe("Neon accent color (cyberpunk style)"),
|
|
20
|
+
accent: z.string().optional().describe("Metal/accent color (cyberpunk style)"),
|
|
21
|
+
}).optional().describe("Color overrides (hex values or palette names)"),
|
|
22
|
+
seed: z.string().optional().describe("Seed for deterministic random generation"),
|
|
23
|
+
format: z.enum(["svg", "png"]).default("svg").describe("Output format"),
|
|
24
|
+
size: z.number().min(16).max(2048).default(200).describe("Output size in pixels (for PNG)"),
|
|
25
|
+
}, async ({ style: styleName, options, colors, seed, format, size }) => {
|
|
26
|
+
const style = getStyle(styleName);
|
|
27
|
+
if (!style) {
|
|
28
|
+
return {
|
|
29
|
+
content: [{ type: "text", text: `Unknown style: "${styleName}". Use list_styles to see available styles.` }],
|
|
30
|
+
isError: true,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
// Resolve palette names to hex values
|
|
34
|
+
const resolvedColors = colors ? { ...colors } : undefined;
|
|
35
|
+
if (resolvedColors) {
|
|
36
|
+
for (const [key, val] of Object.entries(resolvedColors)) {
|
|
37
|
+
if (val && !val.startsWith("#")) {
|
|
38
|
+
const palette = style.palettes[key];
|
|
39
|
+
if (palette) {
|
|
40
|
+
const entry = palette.find((p) => p.name === val);
|
|
41
|
+
if (entry) {
|
|
42
|
+
resolvedColors[key] = entry.value;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
const avatarOptions = { parts: options, colors: resolvedColors };
|
|
49
|
+
const svg = compose(style, avatarOptions, seed);
|
|
50
|
+
if (format === "png") {
|
|
51
|
+
const png = rasterize(svg, size);
|
|
52
|
+
return {
|
|
53
|
+
content: [{
|
|
54
|
+
type: "image",
|
|
55
|
+
data: png.toString("base64"),
|
|
56
|
+
mimeType: "image/png",
|
|
57
|
+
}],
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
return {
|
|
61
|
+
content: [{ type: "text", text: svg }],
|
|
62
|
+
};
|
|
63
|
+
});
|
|
64
|
+
server.tool("list_styles", "List all available avatar styles with their categories and palette info.", {}, async () => {
|
|
65
|
+
const styles = listStyles();
|
|
66
|
+
const lines = styles.map((s) => {
|
|
67
|
+
const cats = s.categories.map((c) => ` - ${c.name}: ${c.variants.join(", ")}${c.optional ? " (optional)" : ""}`);
|
|
68
|
+
const palettes = Object.entries(s.palettes).map(([k, v]) => ` - ${k}: ${v.map((p) => p.name).join(", ")}`);
|
|
69
|
+
return [
|
|
70
|
+
`## ${s.meta.title} (\`${s.name}\`)`,
|
|
71
|
+
`Author: ${s.meta.author} | License: ${s.meta.license}`,
|
|
72
|
+
"",
|
|
73
|
+
"**Categories:**",
|
|
74
|
+
...cats,
|
|
75
|
+
"",
|
|
76
|
+
"**Palettes:**",
|
|
77
|
+
...palettes,
|
|
78
|
+
].join("\n");
|
|
79
|
+
});
|
|
80
|
+
return {
|
|
81
|
+
content: [{ type: "text", text: lines.join("\n\n") }],
|
|
82
|
+
};
|
|
83
|
+
});
|
|
84
|
+
server.tool("list_parts", "List available parts and variants for a specific style, optionally filtered by category.", {
|
|
85
|
+
style: z.string().describe("Style name"),
|
|
86
|
+
category: z.string().optional().describe("Filter to a specific category"),
|
|
87
|
+
}, async ({ style: styleName, category }) => {
|
|
88
|
+
const style = getStyle(styleName);
|
|
89
|
+
if (!style) {
|
|
90
|
+
return {
|
|
91
|
+
content: [{ type: "text", text: `Unknown style: "${styleName}". Use list_styles to see available styles.` }],
|
|
92
|
+
isError: true,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
let categories = style.categories;
|
|
96
|
+
if (category) {
|
|
97
|
+
categories = categories.filter((c) => c.name === category);
|
|
98
|
+
if (categories.length === 0) {
|
|
99
|
+
return {
|
|
100
|
+
content: [{ type: "text", text: `Unknown category: "${category}" in style "${styleName}".` }],
|
|
101
|
+
isError: true,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
const lines = categories.map((c) => {
|
|
106
|
+
const defaultLabel = c.variants[c.default];
|
|
107
|
+
return [
|
|
108
|
+
`**${c.name}**${c.optional ? " (optional)" : ""}`,
|
|
109
|
+
...c.variants.map((v) => ` - \`${v}\`${v === defaultLabel ? " (default)" : ""}`),
|
|
110
|
+
].join("\n");
|
|
111
|
+
});
|
|
112
|
+
return {
|
|
113
|
+
content: [{ type: "text", text: lines.join("\n\n") }],
|
|
114
|
+
};
|
|
115
|
+
});
|
|
116
|
+
return server;
|
|
117
|
+
}
|
|
118
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,MAAM,UAAU,YAAY;IAC1B,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;QAC3B,IAAI,EAAE,oBAAoB;QAC1B,OAAO,EAAE,OAAO;KACjB,CAAC,CAAC;IAEH,MAAM,CAAC,IAAI,CACT,iBAAiB,EACjB,8FAA8F,EAC9F;QACE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,qBAAqB,CAAC;QAClE,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,wEAAwE,CAAC;QAClJ,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;YACf,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;YAC3B,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;YAC3B,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;YAC3B,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;YAC/B,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,qCAAqC,CAAC;YAC3E,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,sCAAsC,CAAC;SAC/E,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,+CAA+C,CAAC;QACvE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,0CAA0C,CAAC;QAChF,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,eAAe,CAAC;QACvE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,iCAAiC,CAAC;KAC5F,EACD,KAAK,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE;QAClE,MAAM,KAAK,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC;QAClC,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,mBAAmB,SAAS,6CAA6C,EAAE,CAAC;gBAC5G,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;QAED,sCAAsC;QACtC,MAAM,cAAc,GAAG,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,MAAM,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;QAC1D,IAAI,cAAc,EAAE,CAAC;YACnB,KAAK,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,cAAc,CAAC,EAAE,CAAC;gBACxD,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;oBAChC,MAAM,OAAO,GAAG,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;oBACpC,IAAI,OAAO,EAAE,CAAC;wBACZ,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,GAAG,CAAC,CAAC;wBAClD,IAAI,KAAK,EAAE,CAAC;4BACT,cAAyC,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC;wBAChE,CAAC;oBACH,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;QAED,MAAM,aAAa,GAAG,EAAE,KAAK,EAAE,OAA6C,EAAE,MAAM,EAAE,cAAc,EAAE,CAAC;QACvG,MAAM,GAAG,GAAG,OAAO,CAAC,KAAK,EAAE,aAAa,EAAE,IAAI,CAAC,CAAC;QAEhD,IAAI,MAAM,KAAK,KAAK,EAAE,CAAC;YACrB,MAAM,GAAG,GAAG,SAAS,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;YACjC,OAAO;gBACL,OAAO,EAAE,CAAC;wBACR,IAAI,EAAE,OAAO;wBACb,IAAI,EAAE,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC;wBAC5B,QAAQ,EAAE,WAAW;qBACtB,CAAC;aACH,CAAC;QACJ,CAAC;QAED,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC;SACvC,CAAC;IACJ,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,aAAa,EACb,0EAA0E,EAC1E,EAAE,EACF,KAAK,IAAI,EAAE;QACT,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;QAC5B,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;YAC7B,MAAM,IAAI,GAAG,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAClH,MAAM,QAAQ,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAC5G,OAAO;gBACL,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,OAAO,CAAC,CAAC,IAAI,KAAK;gBACpC,WAAW,CAAC,CAAC,IAAI,CAAC,MAAM,eAAe,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE;gBACvD,EAAE;gBACF,iBAAiB;gBACjB,GAAG,IAAI;gBACP,EAAE;gBACF,eAAe;gBACf,GAAG,QAAQ;aACZ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACf,CAAC,CAAC,CAAC;QAEH,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;SACtD,CAAC;IACJ,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,YAAY,EACZ,0FAA0F,EAC1F;QACE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC;QACxC,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,+BAA+B,CAAC;KAC1E,EACD,KAAK,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,EAAE,EAAE;QACvC,MAAM,KAAK,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC;QAClC,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,mBAAmB,SAAS,6CAA6C,EAAE,CAAC;gBAC5G,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;QAED,IAAI,UAAU,GAAG,KAAK,CAAC,UAAU,CAAC;QAClC,IAAI,QAAQ,EAAE,CAAC;YACb,UAAU,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC;YAC3D,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC5B,OAAO;oBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,sBAAsB,QAAQ,eAAe,SAAS,IAAI,EAAE,CAAC;oBAC7F,OAAO,EAAE,IAAI;iBACd,CAAC;YACJ,CAAC;QACH,CAAC;QAED,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;YACjC,MAAM,YAAY,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;YAC3C,OAAO;gBACL,KAAK,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,EAAE;gBACjD,GAAG,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,KAAK,YAAY,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;aAClF,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACf,CAAC,CAAC,CAAC;QAEH,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;SACtD,CAAC;IACJ,CAAC,CACF,CAAC;IAEF,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/styles/chibi/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAsB/C,eAAO,MAAM,UAAU,EAAE,WAwCxB,CAAC"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { chibiPalettes } from "./palettes.js";
|
|
2
|
+
import { variants as headVariants } from "./parts/head.js";
|
|
3
|
+
import { variants as eyeVariants } from "./parts/eyes.js";
|
|
4
|
+
import { variants as eyebrowVariants } from "./parts/eyebrows.js";
|
|
5
|
+
import { variants as mouthVariants } from "./parts/mouth.js";
|
|
6
|
+
import { backVariants as hairBackVariants, frontVariants as hairFrontVariants } from "./parts/hair.js";
|
|
7
|
+
import { variants as clothingVariants } from "./parts/clothing.js";
|
|
8
|
+
import { variants as accessoryVariants } from "./parts/accessories.js";
|
|
9
|
+
const partMap = {
|
|
10
|
+
head: headVariants,
|
|
11
|
+
eyes: eyeVariants,
|
|
12
|
+
eyebrows: eyebrowVariants,
|
|
13
|
+
mouth: mouthVariants,
|
|
14
|
+
hair_back: hairBackVariants,
|
|
15
|
+
hair_front: hairFrontVariants,
|
|
16
|
+
clothing: clothingVariants,
|
|
17
|
+
accessories: accessoryVariants,
|
|
18
|
+
};
|
|
19
|
+
export const chibiStyle = {
|
|
20
|
+
name: "chibi",
|
|
21
|
+
meta: {
|
|
22
|
+
title: "Chibi",
|
|
23
|
+
author: "MCP Avatar Builder",
|
|
24
|
+
license: "MIT",
|
|
25
|
+
},
|
|
26
|
+
categories: [
|
|
27
|
+
{ name: "head", variants: Object.keys(headVariants), default: 0 },
|
|
28
|
+
{ name: "eyes", variants: Object.keys(eyeVariants), default: 0 },
|
|
29
|
+
{ name: "eyebrows", variants: Object.keys(eyebrowVariants), default: 0 },
|
|
30
|
+
{ name: "mouth", variants: Object.keys(mouthVariants), default: 0 },
|
|
31
|
+
{ name: "hair_back", variants: Object.keys(hairBackVariants), default: 0 },
|
|
32
|
+
{ name: "hair_front", variants: Object.keys(hairFrontVariants), default: 0 },
|
|
33
|
+
{ name: "clothing", variants: Object.keys(clothingVariants), default: 0 },
|
|
34
|
+
{ name: "accessories", variants: Object.keys(accessoryVariants), default: 0, optional: true },
|
|
35
|
+
],
|
|
36
|
+
palettes: chibiPalettes,
|
|
37
|
+
layerOrder: ["hair_back", "clothing", "head", "eyes", "eyebrows", "mouth", "accessories", "hair_front"],
|
|
38
|
+
viewBox: "0 0 200 200",
|
|
39
|
+
render(options, colors) {
|
|
40
|
+
const fragments = [];
|
|
41
|
+
for (const layer of this.layerOrder) {
|
|
42
|
+
const category = this.categories.find((cat) => cat.name === layer);
|
|
43
|
+
if (!category)
|
|
44
|
+
continue;
|
|
45
|
+
const selectedVariant = options.parts?.[layer] ?? category.variants[category.default];
|
|
46
|
+
const variants = partMap[layer];
|
|
47
|
+
if (!variants)
|
|
48
|
+
continue;
|
|
49
|
+
const renderer = variants[selectedVariant];
|
|
50
|
+
if (!renderer)
|
|
51
|
+
continue;
|
|
52
|
+
fragments.push(`<g data-layer="${layer}">${renderer(colors)}</g>`);
|
|
53
|
+
}
|
|
54
|
+
return fragments.join("\n");
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/styles/chibi/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"palettes.d.ts","sourceRoot":"","sources":["../../../src/styles/chibi/palettes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAEjD,eAAO,MAAM,aAAa,EAAE,UA2B3B,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export const chibiPalettes = {
|
|
2
|
+
skin: [
|
|
3
|
+
{ name: "porcelain", value: "#FDE8D0" },
|
|
4
|
+
{ name: "ivory", value: "#F5D6B8" },
|
|
5
|
+
{ name: "sand", value: "#DEB887" },
|
|
6
|
+
{ name: "honey", value: "#C68642" },
|
|
7
|
+
{ name: "chestnut", value: "#8D5524" },
|
|
8
|
+
{ name: "espresso", value: "#5C3317" },
|
|
9
|
+
],
|
|
10
|
+
hair: [
|
|
11
|
+
{ name: "black", value: "#1A1A2E" },
|
|
12
|
+
{ name: "dark-brown", value: "#3B2314" },
|
|
13
|
+
{ name: "brown", value: "#6B3A2A" },
|
|
14
|
+
{ name: "auburn", value: "#922B21" },
|
|
15
|
+
{ name: "ginger", value: "#D35400" },
|
|
16
|
+
{ name: "blonde", value: "#F0C040" },
|
|
17
|
+
{ name: "platinum", value: "#E8E0D0" },
|
|
18
|
+
{ name: "pink", value: "#FF69B4" },
|
|
19
|
+
],
|
|
20
|
+
eyes: [
|
|
21
|
+
{ name: "brown", value: "#5D3A1A" },
|
|
22
|
+
{ name: "hazel", value: "#8E7618" },
|
|
23
|
+
{ name: "green", value: "#2E8B57" },
|
|
24
|
+
{ name: "blue", value: "#4169E1" },
|
|
25
|
+
{ name: "gray", value: "#708090" },
|
|
26
|
+
{ name: "violet", value: "#8A2BE2" },
|
|
27
|
+
],
|
|
28
|
+
};
|
|
29
|
+
//# sourceMappingURL=palettes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"palettes.js","sourceRoot":"","sources":["../../../src/styles/chibi/palettes.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,aAAa,GAAe;IACvC,IAAI,EAAE;QACJ,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,SAAS,EAAE;QACvC,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE;QACnC,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE;QAClC,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE;QACnC,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,SAAS,EAAE;QACtC,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,SAAS,EAAE;KACvC;IACD,IAAI,EAAE;QACJ,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE;QACnC,EAAE,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,SAAS,EAAE;QACxC,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE;QACnC,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE;QACpC,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE;QACpC,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE;QACpC,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,SAAS,EAAE;QACtC,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE;KACnC;IACD,IAAI,EAAE;QACJ,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE;QACnC,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE;QACnC,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE;QACnC,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE;QAClC,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE;QAClC,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE;KACrC;CACF,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"accessories.d.ts","sourceRoot":"","sources":["../../../../src/styles/chibi/parts/accessories.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEtD,eAAO,MAAM,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAgBjD,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export const variants = {
|
|
2
|
+
none: () => "",
|
|
3
|
+
glasses: () => `
|
|
4
|
+
<circle cx="75" cy="110" r="14" stroke="#333" stroke-width="2" fill="none" />
|
|
5
|
+
<circle cx="125" cy="110" r="14" stroke="#333" stroke-width="2" fill="none" />
|
|
6
|
+
<line x1="89" y1="110" x2="111" y2="110" stroke="#333" stroke-width="2" />
|
|
7
|
+
<line x1="61" y1="108" x2="50" y2="105" stroke="#333" stroke-width="2" />
|
|
8
|
+
<line x1="139" y1="108" x2="150" y2="105" stroke="#333" stroke-width="2" />
|
|
9
|
+
`,
|
|
10
|
+
round_glasses: () => `
|
|
11
|
+
<circle cx="75" cy="110" r="16" stroke="#886644" stroke-width="1.5" fill="#FFFFFF10" />
|
|
12
|
+
<circle cx="125" cy="110" r="16" stroke="#886644" stroke-width="1.5" fill="#FFFFFF10" />
|
|
13
|
+
<line x1="91" y1="110" x2="109" y2="110" stroke="#886644" stroke-width="1.5" />
|
|
14
|
+
<line x1="59" y1="108" x2="48" y2="104" stroke="#886644" stroke-width="1.5" />
|
|
15
|
+
<line x1="141" y1="108" x2="152" y2="104" stroke="#886644" stroke-width="1.5" />
|
|
16
|
+
`,
|
|
17
|
+
};
|
|
18
|
+
//# sourceMappingURL=accessories.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"accessories.js","sourceRoot":"","sources":["../../../../src/styles/chibi/parts/accessories.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,QAAQ,GAAiC;IACpD,IAAI,EAAE,GAAG,EAAE,CAAC,EAAE;IACd,OAAO,EAAE,GAAG,EAAE,CAAC;;;;;;GAMd;IACD,aAAa,EAAE,GAAG,EAAE,CAAC;;;;;;GAMpB;CACF,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clothing.d.ts","sourceRoot":"","sources":["../../../../src/styles/chibi/parts/clothing.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEtD,eAAO,MAAM,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAmBjD,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export const variants = {
|
|
2
|
+
tshirt: (c) => `
|
|
3
|
+
<path d="M55,175 Q55,168 65,164 Q80,158 100,158 Q120,158 135,164 Q145,168 145,175 L145,200 L55,200Z" fill="${c.clothing}" />
|
|
4
|
+
<path d="M65,164 Q55,168 40,175 L40,200 L55,200 L55,175Z" fill="${c.clothing}" />
|
|
5
|
+
<path d="M135,164 Q145,168 160,175 L160,200 L145,200 L145,175Z" fill="${c.clothing}" />
|
|
6
|
+
`,
|
|
7
|
+
hoodie: (c) => `
|
|
8
|
+
<path d="M50,175 Q50,165 65,160 Q80,155 100,155 Q120,155 135,160 Q150,165 150,175 L150,200 L50,200Z" fill="${c.clothing}" />
|
|
9
|
+
<path d="M65,160 Q50,165 35,175 L35,200 L50,200 L50,175Z" fill="${c.clothing}" />
|
|
10
|
+
<path d="M135,160 Q150,165 165,175 L165,200 L150,200 L150,175Z" fill="${c.clothing}" />
|
|
11
|
+
<path d="M88,158 Q100,170 112,158" stroke="${c.clothing}" stroke-width="2" fill="none" opacity="0.3" />
|
|
12
|
+
`,
|
|
13
|
+
collared: (c) => `
|
|
14
|
+
<path d="M55,175 Q55,168 65,164 Q80,158 100,158 Q120,158 135,164 Q145,168 145,175 L145,200 L55,200Z" fill="${c.clothing}" />
|
|
15
|
+
<path d="M65,164 Q55,168 40,175 L40,200 L55,200 L55,175Z" fill="${c.clothing}" />
|
|
16
|
+
<path d="M135,164 Q145,168 160,175 L160,200 L145,200 L145,175Z" fill="${c.clothing}" />
|
|
17
|
+
<path d="M85,158 L95,172 L100,165" stroke="white" stroke-width="1.5" fill="white" opacity="0.6" />
|
|
18
|
+
<path d="M115,158 L105,172 L100,165" stroke="white" stroke-width="1.5" fill="white" opacity="0.6" />
|
|
19
|
+
`,
|
|
20
|
+
};
|
|
21
|
+
//# sourceMappingURL=clothing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clothing.js","sourceRoot":"","sources":["../../../../src/styles/chibi/parts/clothing.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,QAAQ,GAAiC;IACpD,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC;iHACgG,CAAC,CAAC,QAAQ;sEACrD,CAAC,CAAC,QAAQ;4EACJ,CAAC,CAAC,QAAQ;GACnF;IACD,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC;iHACgG,CAAC,CAAC,QAAQ;sEACrD,CAAC,CAAC,QAAQ;4EACJ,CAAC,CAAC,QAAQ;iDACrC,CAAC,CAAC,QAAQ;GACxD;IACD,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC;iHAC8F,CAAC,CAAC,QAAQ;sEACrD,CAAC,CAAC,QAAQ;4EACJ,CAAC,CAAC,QAAQ;;;GAGnF;CACF,CAAC"}
|