@pixygon/avatar 1.0.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/chunk-5QZCUXJW.mjs +187 -0
- package/dist/components/index.d.mts +18 -0
- package/dist/components/index.d.ts +18 -0
- package/dist/components/index.js +476 -0
- package/dist/components/index.mjs +277 -0
- package/dist/index-DwPxw0AI.d.mts +77 -0
- package/dist/index-DwPxw0AI.d.ts +77 -0
- package/dist/index.d.mts +52 -0
- package/dist/index.d.ts +52 -0
- package/dist/index.js +274 -0
- package/dist/index.mjs +72 -0
- package/package.json +49 -0
- package/src/components/AvatarEditor.tsx +371 -0
- package/src/components/index.ts +7 -0
- package/src/defaults.ts +89 -0
- package/src/hooks/useAvatarEditor.ts +41 -0
- package/src/index.ts +36 -0
- package/src/presets.ts +44 -0
- package/src/skeleton.ts +82 -0
- package/src/types/index.ts +96 -0
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
// src/types/index.ts
|
|
2
|
+
var STYLE_COUNTS = {
|
|
3
|
+
eye: 12,
|
|
4
|
+
brow: 8,
|
|
5
|
+
nose: 8,
|
|
6
|
+
mouth: 8,
|
|
7
|
+
hair: 16,
|
|
8
|
+
facial_hair: 8,
|
|
9
|
+
glasses: 6
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
// src/presets.ts
|
|
13
|
+
var SKIN_PRESETS = [
|
|
14
|
+
[0.98, 0.89, 0.78],
|
|
15
|
+
// Porcelain
|
|
16
|
+
[0.96, 0.84, 0.71],
|
|
17
|
+
// Fair
|
|
18
|
+
[0.92, 0.78, 0.63],
|
|
19
|
+
// Light
|
|
20
|
+
[0.87, 0.72, 0.55],
|
|
21
|
+
// Medium-light
|
|
22
|
+
[0.78, 0.62, 0.46],
|
|
23
|
+
// Medium
|
|
24
|
+
[0.68, 0.51, 0.36],
|
|
25
|
+
// Olive
|
|
26
|
+
[0.58, 0.42, 0.3],
|
|
27
|
+
// Tan
|
|
28
|
+
[0.47, 0.33, 0.22],
|
|
29
|
+
// Brown
|
|
30
|
+
[0.36, 0.24, 0.16],
|
|
31
|
+
// Dark
|
|
32
|
+
[0.26, 0.17, 0.11]
|
|
33
|
+
// Deep
|
|
34
|
+
];
|
|
35
|
+
var EYE_COLOR_PRESETS = [
|
|
36
|
+
[0.1, 0.1, 0.1],
|
|
37
|
+
// Black
|
|
38
|
+
[0.35, 0.22, 0.1],
|
|
39
|
+
// Brown
|
|
40
|
+
[0.55, 0.35, 0.15],
|
|
41
|
+
// Hazel
|
|
42
|
+
[0.25, 0.5, 0.25],
|
|
43
|
+
// Green
|
|
44
|
+
[0.2, 0.4, 0.7],
|
|
45
|
+
// Blue
|
|
46
|
+
[0.45, 0.45, 0.5],
|
|
47
|
+
// Gray
|
|
48
|
+
[0.55, 0.25, 0.25],
|
|
49
|
+
// Red
|
|
50
|
+
[0.5, 0.3, 0.6]
|
|
51
|
+
// Violet
|
|
52
|
+
];
|
|
53
|
+
var HAIR_COLOR_PRESETS = [
|
|
54
|
+
[0.08, 0.06, 0.05],
|
|
55
|
+
// Black
|
|
56
|
+
[0.22, 0.14, 0.08],
|
|
57
|
+
// Dark brown
|
|
58
|
+
[0.4, 0.26, 0.14],
|
|
59
|
+
// Brown
|
|
60
|
+
[0.58, 0.42, 0.24],
|
|
61
|
+
// Light brown
|
|
62
|
+
[0.78, 0.62, 0.34],
|
|
63
|
+
// Dirty blonde
|
|
64
|
+
[0.9, 0.78, 0.48],
|
|
65
|
+
// Blonde
|
|
66
|
+
[0.72, 0.26, 0.12],
|
|
67
|
+
// Red
|
|
68
|
+
[0.88, 0.52, 0.22],
|
|
69
|
+
// Ginger
|
|
70
|
+
[0.6, 0.6, 0.62],
|
|
71
|
+
// Gray
|
|
72
|
+
[0.92, 0.92, 0.94]
|
|
73
|
+
// White
|
|
74
|
+
];
|
|
75
|
+
|
|
76
|
+
// src/defaults.ts
|
|
77
|
+
function defaultAppearance() {
|
|
78
|
+
return {
|
|
79
|
+
body: { height: 0.5, build: 0.5 },
|
|
80
|
+
head: {
|
|
81
|
+
width: 1,
|
|
82
|
+
height: 1,
|
|
83
|
+
eye_style: 0,
|
|
84
|
+
eye_color: [...EYE_COLOR_PRESETS[1]],
|
|
85
|
+
eye_y: 0.5,
|
|
86
|
+
eye_spacing: 0.5,
|
|
87
|
+
eye_size: 0.5,
|
|
88
|
+
eye_rotation: 0.5,
|
|
89
|
+
brow_style: 0,
|
|
90
|
+
brow_color: [...HAIR_COLOR_PRESETS[0]],
|
|
91
|
+
brow_y: 0.5,
|
|
92
|
+
brow_spacing: 0.5,
|
|
93
|
+
brow_size: 0.5,
|
|
94
|
+
brow_rotation: 0.5,
|
|
95
|
+
nose_style: 0,
|
|
96
|
+
nose_y: 0.5,
|
|
97
|
+
nose_size: 0.5,
|
|
98
|
+
mouth_style: 0,
|
|
99
|
+
mouth_y: 0.5,
|
|
100
|
+
mouth_size: 0.5,
|
|
101
|
+
mouth_color: [0.75, 0.35, 0.35],
|
|
102
|
+
hair_style: 0,
|
|
103
|
+
hair_color: [...HAIR_COLOR_PRESETS[2]],
|
|
104
|
+
facial_hair_style: 0,
|
|
105
|
+
facial_hair_color: [...HAIR_COLOR_PRESETS[0]],
|
|
106
|
+
glasses_style: 0,
|
|
107
|
+
glasses_color: [0.1, 0.1, 0.1]
|
|
108
|
+
},
|
|
109
|
+
skin_color: [...SKIN_PRESETS[2]]
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
function randomAppearance() {
|
|
113
|
+
const rng = (min, max) => min + Math.random() * (max - min);
|
|
114
|
+
const rngInt = (max) => Math.floor(Math.random() * max);
|
|
115
|
+
const pick = (arr) => arr[rngInt(arr.length)];
|
|
116
|
+
const hairColor = pick(HAIR_COLOR_PRESETS);
|
|
117
|
+
return {
|
|
118
|
+
body: {
|
|
119
|
+
height: rng(0.2, 0.8),
|
|
120
|
+
build: rng(0.2, 0.8)
|
|
121
|
+
},
|
|
122
|
+
head: {
|
|
123
|
+
width: rng(0.7, 1.3),
|
|
124
|
+
height: rng(0.7, 1.3),
|
|
125
|
+
eye_style: rngInt(STYLE_COUNTS.eye),
|
|
126
|
+
eye_color: [...pick(EYE_COLOR_PRESETS)],
|
|
127
|
+
eye_y: rng(0.3, 0.7),
|
|
128
|
+
eye_spacing: rng(0.3, 0.7),
|
|
129
|
+
eye_size: rng(0.3, 0.7),
|
|
130
|
+
eye_rotation: 0.5,
|
|
131
|
+
brow_style: rngInt(STYLE_COUNTS.brow),
|
|
132
|
+
brow_color: [...hairColor],
|
|
133
|
+
brow_y: rng(0.3, 0.7),
|
|
134
|
+
brow_spacing: rng(0.3, 0.7),
|
|
135
|
+
brow_size: rng(0.3, 0.7),
|
|
136
|
+
brow_rotation: 0.5,
|
|
137
|
+
nose_style: rngInt(STYLE_COUNTS.nose),
|
|
138
|
+
nose_y: rng(0.3, 0.7),
|
|
139
|
+
nose_size: rng(0.3, 0.7),
|
|
140
|
+
mouth_style: rngInt(STYLE_COUNTS.mouth),
|
|
141
|
+
mouth_y: rng(0.3, 0.7),
|
|
142
|
+
mouth_size: rng(0.3, 0.7),
|
|
143
|
+
mouth_color: [0.75, 0.35, 0.35],
|
|
144
|
+
hair_style: rngInt(STYLE_COUNTS.hair),
|
|
145
|
+
hair_color: [...hairColor],
|
|
146
|
+
facial_hair_style: Math.random() < 0.3 ? 1 + rngInt(STYLE_COUNTS.facial_hair - 1) : 0,
|
|
147
|
+
facial_hair_color: [...hairColor],
|
|
148
|
+
glasses_style: Math.random() < 0.2 ? 1 + rngInt(STYLE_COUNTS.glasses - 1) : 0,
|
|
149
|
+
glasses_color: [0.1, 0.1, 0.1]
|
|
150
|
+
},
|
|
151
|
+
skin_color: [...pick(SKIN_PRESETS)]
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// src/hooks/useAvatarEditor.ts
|
|
156
|
+
import { useCallback, useState } from "react";
|
|
157
|
+
function useAvatarEditor(initial) {
|
|
158
|
+
const [appearance, setAppearance] = useState(
|
|
159
|
+
() => initial ?? defaultAppearance()
|
|
160
|
+
);
|
|
161
|
+
const [tab, setTab] = useState("body");
|
|
162
|
+
const update = useCallback((path, value) => {
|
|
163
|
+
setAppearance((prev) => {
|
|
164
|
+
const next = structuredClone(prev);
|
|
165
|
+
const parts = path.split(".");
|
|
166
|
+
let obj = next;
|
|
167
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
168
|
+
obj = obj[parts[i]];
|
|
169
|
+
}
|
|
170
|
+
obj[parts[parts.length - 1]] = value;
|
|
171
|
+
return next;
|
|
172
|
+
});
|
|
173
|
+
}, []);
|
|
174
|
+
const randomize = useCallback(() => setAppearance(randomAppearance()), []);
|
|
175
|
+
const reset = useCallback(() => setAppearance(initial ?? defaultAppearance()), [initial]);
|
|
176
|
+
return { appearance, tab, setTab, update, randomize, reset };
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
export {
|
|
180
|
+
STYLE_COUNTS,
|
|
181
|
+
SKIN_PRESETS,
|
|
182
|
+
EYE_COLOR_PRESETS,
|
|
183
|
+
HAIR_COLOR_PRESETS,
|
|
184
|
+
defaultAppearance,
|
|
185
|
+
randomAppearance,
|
|
186
|
+
useAvatarEditor
|
|
187
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { A as AvatarAppearance } from '../index-DwPxw0AI.mjs';
|
|
3
|
+
|
|
4
|
+
interface AvatarEditorProps {
|
|
5
|
+
/** Initial appearance (uses default if omitted). */
|
|
6
|
+
initial?: AvatarAppearance;
|
|
7
|
+
/** Called whenever the appearance changes. */
|
|
8
|
+
onChange?: (appearance: AvatarAppearance) => void;
|
|
9
|
+
/** Called when the user clicks "Done". */
|
|
10
|
+
onDone?: (appearance: AvatarAppearance) => void;
|
|
11
|
+
/** Called when the user clicks "Cancel". */
|
|
12
|
+
onCancel?: () => void;
|
|
13
|
+
/** Optional class name for the root container. */
|
|
14
|
+
className?: string;
|
|
15
|
+
}
|
|
16
|
+
declare function AvatarEditor({ initial, onChange, onDone, onCancel, className, }: AvatarEditorProps): react_jsx_runtime.JSX.Element;
|
|
17
|
+
|
|
18
|
+
export { AvatarEditor, type AvatarEditorProps };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { A as AvatarAppearance } from '../index-DwPxw0AI.js';
|
|
3
|
+
|
|
4
|
+
interface AvatarEditorProps {
|
|
5
|
+
/** Initial appearance (uses default if omitted). */
|
|
6
|
+
initial?: AvatarAppearance;
|
|
7
|
+
/** Called whenever the appearance changes. */
|
|
8
|
+
onChange?: (appearance: AvatarAppearance) => void;
|
|
9
|
+
/** Called when the user clicks "Done". */
|
|
10
|
+
onDone?: (appearance: AvatarAppearance) => void;
|
|
11
|
+
/** Called when the user clicks "Cancel". */
|
|
12
|
+
onCancel?: () => void;
|
|
13
|
+
/** Optional class name for the root container. */
|
|
14
|
+
className?: string;
|
|
15
|
+
}
|
|
16
|
+
declare function AvatarEditor({ initial, onChange, onDone, onCancel, className, }: AvatarEditorProps): react_jsx_runtime.JSX.Element;
|
|
17
|
+
|
|
18
|
+
export { AvatarEditor, type AvatarEditorProps };
|