@botharness/pixel-avatar 0.5.0 → 0.7.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 +2 -0
- package/dist/index.d.ts +119 -15
- package/dist/index.js +513 -220
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -21,6 +21,8 @@ const svg = pixelAvatarSvg(recipe); // 32×32 viewBox, crisp edges, no ids or sc
|
|
|
21
21
|
- `AVATAR_SPECIES`, `AVATAR_SPECIES_SWATCHES`, `AVATAR_PIECE_COLORS`, `withSpecies(recipe, species)`: Avatar Species (`human`, `goblin`) on the same rig, as asset version 2. `withSpecies` keeps every choice, splits side hair into `sideHair` (left) and `rightSideHair`, and accepts optional `leftSideHairColor`/`rightSideHairColor`, where left and right are as seen on screen. Consumers built before version 2 reject these recipes with `isPixelAvatarRecipe` and can show a saved snapshot instead.
|
|
22
22
|
- `AVATAR_PARTS_V2`, `AVATAR_EXTRA_PARTS`, `hiddenChoices(recipe)`: version 2 adds elf, dwarf, orc and flower species, armor/robe/tunic/cloak outfits, helmet/hood headwear, an optional `beard`, and a flower's `petals` and `flowerBase`. `hiddenChoices` names saved choices the current species or headwear keeps but does not draw, so an editor can say so instead of discarding them.
|
|
23
23
|
- `PixelCustomPart`, `withHeadpiece(recipe, part)`, `customPartId`, `isPixelCustomPart`: a Human-drawn Custom Part in the `headpiece` slot (the top 32×16 of the tile). Its back layer is drawn behind the hair and its front layer over it, and both follow the head through turns. Each cell is `[x, y, color, tone]`, where `color` is an appearance color slot (`hairColor`, `skinColor`, `eyeColor`, `shirtColor`), so the part recolors with the Avatar, or a fixed `#rrggbb`, and `tone` is a step from −2 to 2 on the rig's shade ramp (`partToneColor`). A recipe wearing a part embeds its own copy as asset version 3. `customPartId` is the SHA-256 of the canonical content; names, authors and origins belong to the consumer's library.
|
|
24
|
+
- `HAIR_PART_SLOTS`, `hairPieceStart(recipe, slot)`, `withCustomPart(recipe, slot, part)`, `wornPart`: drawn hair pieces. `bangs`, `leftSideHair`, `rightSideHair` and `backHair` each take a Custom Part (front layer only) that replaces the built-in piece while it stays saved underneath. In a hair part, a `hairColor` cell at tone 0 is live hair: it is shaded with the rest of the hair exactly like the built-in piece, so `hairPieceStart` flattens the worn built-in piece into such cells and an unchanged copy renders identically. Other cells show their own color. Drawn hair follows turns and is hidden under a helmet or hood and on a flower, like built-in hair.
|
|
25
|
+
- `REPLACE_PART_SLOTS`, `replacePartStart(recipe, slot)`: drawn `outfit`, `accessory`, `beard`, `glasses`, `nose`, `cheeks`, `petals` and `flowerBase` parts (front layer only). A drawn part replaces the built-in part pixel for pixel in the layer that part paints into, while the built-in choice stays saved underneath. `replacePartStart` flattens the worn built-in part for this recipe: pixels that are exactly an appearance color at a tone become that color slot, and the rest become fixed colors, so an unchanged copy renders identically. Drawn face parts never cover the speaking mouth, and drawn parts are hidden wherever the species or headwear hides the built-in part. A drawn accessory replacing a helmet or hood no longer hides the hair.
|
|
24
26
|
- `emptyPartLayer`, `paintPartLayer`, `fillPartLayer`, `mirrorPartX`, `partLayer`, `partCells`, `createCustomPart`: drawing on dense layers, with pencil and eraser strokes, 4-connected flood fill and mirroring across the Avatar centerline.
|
|
25
27
|
- `faceCells`, `pixelSymbolCells`, `symbolArtCells`: pixels for [`@botharness/pixel-morph`](../morph).
|
|
26
28
|
- `pixelAvatarSvg(recipe, { turns, classPrefix })`: optional pre-rendered head turns, and rig layer classes (`<prefix>-body`, `-head`, `-face`, `-gaze`, `-blink`) for CSS animation.
|
package/dist/index.d.ts
CHANGED
|
@@ -72,9 +72,7 @@ type PixelAvatarRecipeV1 = Meta & {
|
|
|
72
72
|
} & { [P in AvatarPart]: (typeof AVATAR_PARTS)[P][number] } & { [P in AvatarHairPart]?: (typeof AVATAR_PARTS)['hair'][number] } & { [P in AvatarRange]?: number } & {
|
|
73
73
|
species?: never;
|
|
74
74
|
rightSideHair?: never;
|
|
75
|
-
} & { [P in AvatarPieceColor | AvatarExtraPart]?: never } & {
|
|
76
|
-
headpiece?: never;
|
|
77
|
-
};
|
|
75
|
+
} & { [P in AvatarPieceColor | AvatarExtraPart]?: never } & { [P in CustomPartKey]?: never };
|
|
78
76
|
/**
|
|
79
77
|
* Asset version 2: a species, the full split hair and geometry, a separate right side hair
|
|
80
78
|
* (`sideHair` is then the left side) and optional per-side hair colors.
|
|
@@ -84,14 +82,31 @@ type PixelAvatarRecipeV2 = Meta & {
|
|
|
84
82
|
} & { [P in AvatarPart]: (typeof AVATAR_PARTS_V2)[P][number] } & { [P in AvatarHairPart]: (typeof AVATAR_PARTS)['hair'][number] } & { [P in AvatarRange]: number } & {
|
|
85
83
|
species: AvatarSpecies;
|
|
86
84
|
rightSideHair: (typeof AVATAR_HAIR_PARTS)['sideHair'][number];
|
|
87
|
-
} & { [P in AvatarPieceColor]?: string } & { [P in AvatarExtraPart]?: (typeof AVATAR_EXTRA_PARTS)[P][number] } & {
|
|
88
|
-
|
|
85
|
+
} & { [P in AvatarPieceColor]?: string } & { [P in AvatarExtraPart]?: (typeof AVATAR_EXTRA_PARTS)[P][number] } & { [P in CustomPartKey]?: never };
|
|
86
|
+
/** The recipe key that embeds the Custom Part worn in each slot. */
|
|
87
|
+
declare const CUSTOM_PART_KEYS: {
|
|
88
|
+
readonly headpiece: "headpiece";
|
|
89
|
+
readonly bangs: "bangsPart";
|
|
90
|
+
readonly leftSideHair: "leftSideHairPart";
|
|
91
|
+
readonly rightSideHair: "rightSideHairPart";
|
|
92
|
+
readonly backHair: "backHairPart";
|
|
93
|
+
readonly outfit: "outfitPart";
|
|
94
|
+
readonly accessory: "accessoryPart";
|
|
95
|
+
readonly beard: "beardPart";
|
|
96
|
+
readonly glasses: "glassesPart";
|
|
97
|
+
readonly nose: "nosePart";
|
|
98
|
+
readonly cheeks: "cheeksPart";
|
|
99
|
+
readonly petals: "petalsPart";
|
|
100
|
+
readonly flowerBase: "flowerBasePart";
|
|
89
101
|
};
|
|
90
|
-
|
|
91
|
-
|
|
102
|
+
type CustomPartKey = (typeof CUSTOM_PART_KEYS)[PartSlot];
|
|
103
|
+
/**
|
|
104
|
+
* Asset version 3: version 2 wearing at least one embedded Custom Part. A drawn hair piece
|
|
105
|
+
* replaces the built-in piece, which stays saved and returns when the part is taken off.
|
|
106
|
+
*/
|
|
107
|
+
type PixelAvatarRecipeV3 = Omit<PixelAvatarRecipeV2, 'assetVersion' | CustomPartKey> & {
|
|
92
108
|
assetVersion: 3;
|
|
93
|
-
|
|
94
|
-
};
|
|
109
|
+
} & { [P in CustomPartKey]?: PixelCustomPart };
|
|
95
110
|
type PixelAvatarRecipe = PixelAvatarRecipeV1 | PixelAvatarRecipeV2 | PixelAvatarRecipeV3;
|
|
96
111
|
declare const DEFAULT_RECIPE: PixelAvatarRecipeV1;
|
|
97
112
|
declare function isPixelAvatarRecipe(value: unknown): value is PixelAvatarRecipe;
|
|
@@ -112,10 +127,14 @@ declare function withSpecies(recipe: PixelAvatarRecipeV3, species: AvatarSpecies
|
|
|
112
127
|
declare function withSpecies(recipe: PixelAvatarRecipeV1 | PixelAvatarRecipeV2, species: AvatarSpecies): PixelAvatarRecipeV2;
|
|
113
128
|
declare function withSpecies(recipe: PixelAvatarRecipe, species: AvatarSpecies): PixelAvatarRecipeV2 | PixelAvatarRecipeV3;
|
|
114
129
|
/**
|
|
115
|
-
* Returns the recipe wearing
|
|
116
|
-
*
|
|
130
|
+
* Returns the recipe wearing `part` in `slot`, or with that slot's part taken off. The recipe
|
|
131
|
+
* embeds its own copy; it is asset version 3 while it wears any part and version 2 otherwise.
|
|
117
132
|
*/
|
|
133
|
+
declare function withCustomPart(recipe: PixelAvatarRecipe, slot: PartSlot, part: PixelCustomPart | undefined): PixelAvatarRecipeV2 | PixelAvatarRecipeV3;
|
|
134
|
+
/** `withCustomPart` for the headpiece slot. */
|
|
118
135
|
declare function withHeadpiece(recipe: PixelAvatarRecipe, part: PixelCustomPart | undefined): PixelAvatarRecipeV2 | PixelAvatarRecipeV3;
|
|
136
|
+
/** The Custom Part worn in a slot, if any. */
|
|
137
|
+
declare function wornPart(recipe: PixelAvatarRecipe, slot: PartSlot): PixelCustomPart | undefined;
|
|
119
138
|
declare function detailedRecipe(recipe: PixelAvatarRecipe): PixelAvatarRecipe;
|
|
120
139
|
declare const AVATAR_SWATCHES: Record<AvatarColor, readonly string[]>;
|
|
121
140
|
/**
|
|
@@ -141,16 +160,79 @@ declare const AVATAR_PRESETS: readonly PixelAvatarRecipe[];
|
|
|
141
160
|
//#region src/part.d.ts
|
|
142
161
|
/**
|
|
143
162
|
* Custom Part slots. A headpiece covers the top of the tile, around the hair: its back layer is
|
|
144
|
-
* drawn behind the hair and its front layer over it.
|
|
145
|
-
*
|
|
163
|
+
* drawn behind the hair and its front layer over it. Hair slots replace one built-in hair piece
|
|
164
|
+
* and use only the front layer. Cells are in tile coordinates, so the Avatar centerline sits
|
|
165
|
+
* between x = 15 and x = 16.
|
|
146
166
|
*/
|
|
147
167
|
declare const PART_SLOTS: {
|
|
148
168
|
readonly headpiece: {
|
|
149
169
|
readonly width: 32;
|
|
150
170
|
readonly height: 16;
|
|
151
171
|
};
|
|
172
|
+
readonly bangs: {
|
|
173
|
+
readonly width: 32;
|
|
174
|
+
readonly height: 32;
|
|
175
|
+
};
|
|
176
|
+
readonly leftSideHair: {
|
|
177
|
+
readonly width: 32;
|
|
178
|
+
readonly height: 32;
|
|
179
|
+
};
|
|
180
|
+
readonly rightSideHair: {
|
|
181
|
+
readonly width: 32;
|
|
182
|
+
readonly height: 32;
|
|
183
|
+
};
|
|
184
|
+
readonly backHair: {
|
|
185
|
+
readonly width: 32;
|
|
186
|
+
readonly height: 32;
|
|
187
|
+
};
|
|
188
|
+
readonly outfit: {
|
|
189
|
+
readonly width: 32;
|
|
190
|
+
readonly height: 32;
|
|
191
|
+
};
|
|
192
|
+
readonly accessory: {
|
|
193
|
+
readonly width: 32;
|
|
194
|
+
readonly height: 32;
|
|
195
|
+
};
|
|
196
|
+
readonly beard: {
|
|
197
|
+
readonly width: 32;
|
|
198
|
+
readonly height: 32;
|
|
199
|
+
};
|
|
200
|
+
readonly glasses: {
|
|
201
|
+
readonly width: 32;
|
|
202
|
+
readonly height: 32;
|
|
203
|
+
};
|
|
204
|
+
readonly nose: {
|
|
205
|
+
readonly width: 32;
|
|
206
|
+
readonly height: 32;
|
|
207
|
+
};
|
|
208
|
+
readonly cheeks: {
|
|
209
|
+
readonly width: 32;
|
|
210
|
+
readonly height: 32;
|
|
211
|
+
};
|
|
212
|
+
readonly petals: {
|
|
213
|
+
readonly width: 32;
|
|
214
|
+
readonly height: 32;
|
|
215
|
+
};
|
|
216
|
+
readonly flowerBase: {
|
|
217
|
+
readonly width: 32;
|
|
218
|
+
readonly height: 32;
|
|
219
|
+
};
|
|
152
220
|
};
|
|
153
221
|
type PartSlot = keyof typeof PART_SLOTS;
|
|
222
|
+
/**
|
|
223
|
+
* Hair slots. In a hair part, a `hairColor` cell at tone 0 is live hair: it is shaded with the
|
|
224
|
+
* rest of the hair, exactly like a built-in piece. Every other cell shows its own color.
|
|
225
|
+
*/
|
|
226
|
+
declare const HAIR_PART_SLOTS: readonly ["bangs", "leftSideHair", "rightSideHair", "backHair"];
|
|
227
|
+
type HairPartSlot = (typeof HAIR_PART_SLOTS)[number];
|
|
228
|
+
declare const isHairPartSlot: (slot: PartSlot) => slot is HairPartSlot;
|
|
229
|
+
/**
|
|
230
|
+
* Slots whose drawn part replaces a built-in part pixel for pixel: the part's cells are painted
|
|
231
|
+
* where the built-in part would be, and every cell shows its own color and tone.
|
|
232
|
+
*/
|
|
233
|
+
declare const REPLACE_PART_SLOTS: readonly ["outfit", "accessory", "beard", "glasses", "nose", "cheeks", "petals", "flowerBase"];
|
|
234
|
+
type ReplacePartSlot = (typeof REPLACE_PART_SLOTS)[number];
|
|
235
|
+
declare const isReplacePartSlot: (slot: PartSlot) => slot is ReplacePartSlot;
|
|
154
236
|
/** Tone steps on the rig's shade ramp: two darker, the color itself, two lighter. */
|
|
155
237
|
declare const PART_TONES: readonly [-2, -1, 0, 1, 2];
|
|
156
238
|
type PartTone = (typeof PART_TONES)[number];
|
|
@@ -161,7 +243,7 @@ type PartCell = readonly [x: number, y: number, color: PartColor, tone: PartTone
|
|
|
161
243
|
declare const PART_LAYERS: readonly ["front", "back"];
|
|
162
244
|
type PartLayerName = (typeof PART_LAYERS)[number];
|
|
163
245
|
/** Most fixed colors one part may use. */
|
|
164
|
-
declare const MAX_PART_FIXED_COLORS =
|
|
246
|
+
declare const MAX_PART_FIXED_COLORS = 32;
|
|
165
247
|
/**
|
|
166
248
|
* A Human-drawn Custom Part. Its content is immutable and its identity is `customPartId`;
|
|
167
249
|
* name, author, origin and parent are metadata kept outside it.
|
|
@@ -215,6 +297,28 @@ declare function pixelFigure(recipe: Recipe, yawDeg: number, options?: PixelFigu
|
|
|
215
297
|
head: string;
|
|
216
298
|
cells: PixelCell$1[];
|
|
217
299
|
};
|
|
300
|
+
/**
|
|
301
|
+
* The hair piece in `slot` as a Custom Part to start drawing from: the drawn part worn there,
|
|
302
|
+
* or the built-in piece flattened for this recipe in the front pose as live `hairColor` cells.
|
|
303
|
+
* A flattened piece keeps this shape and no longer follows face shape or hair length.
|
|
304
|
+
*/
|
|
305
|
+
declare function hairPieceStart(recipe: PixelAvatarRecipe, slot: HairPartSlot): {
|
|
306
|
+
slot: HairPartSlot;
|
|
307
|
+
front: PartCell[];
|
|
308
|
+
back: PartCell[];
|
|
309
|
+
};
|
|
310
|
+
/**
|
|
311
|
+
* The part in a replacement slot as a Custom Part to start drawing from: the drawn part worn
|
|
312
|
+
* there, or the built-in part flattened for this recipe in the front pose. Each pixel becomes a
|
|
313
|
+
* color slot and tone when it is exactly one, so it recolors with the Avatar, and a fixed color
|
|
314
|
+
* otherwise; an unchanged copy renders identically. A flattened helmet or hood no longer hides
|
|
315
|
+
* the hair: only the built-in ones do.
|
|
316
|
+
*/
|
|
317
|
+
declare function replacePartStart(recipe: PixelAvatarRecipe, slot: ReplacePartSlot): {
|
|
318
|
+
slot: ReplacePartSlot;
|
|
319
|
+
front: PartCell[];
|
|
320
|
+
back: PartCell[];
|
|
321
|
+
};
|
|
218
322
|
//#endregion
|
|
219
323
|
//#region src/random.d.ts
|
|
220
324
|
declare function seededRandom(seed: string): () => number;
|
|
@@ -264,5 +368,5 @@ declare function pixelSymbolCells(symbol: PixelSymbol, color: string): PixelCell
|
|
|
264
368
|
*/
|
|
265
369
|
declare function symbolArtCells(rows: readonly string[], color: string): PixelCell$1[];
|
|
266
370
|
//#endregion
|
|
267
|
-
export { AVATAR_COLORS, AVATAR_EXTRA_PARTS, AVATAR_HAIR_PARTS, AVATAR_PARTS, AVATAR_PARTS_V2, AVATAR_PIECE_COLORS, AVATAR_PRESETS, AVATAR_RANGES, AVATAR_SPECIES, AVATAR_SPECIES_SWATCHES, AVATAR_SWATCHES, AVATAR_TURNS, type AvatarColor, type AvatarExtraPart, type AvatarHairPart, type AvatarPart, type AvatarPieceColor, type AvatarRange, type AvatarSpecies, DEFAULT_RECIPE, MAX_PART_FIXED_COLORS, PART_LAYERS, PART_SLOTS, PART_TONES, PIXEL_SYMBOLS, type PartCell, type PartColor, type PartInk, type PartLayer, type PartLayerName, type PartSlot, type PartTone, type PixelAvatarRecipe, type PixelAvatarRecipeV1, type PixelAvatarRecipeV2, type PixelAvatarRecipeV3, type PixelAvatarSvgOptions, type PixelCell, type PixelCustomPart, type PixelFigureOptions, type PixelGrid, type PixelMouthState, type PixelSymbol, canonicalCustomPart, canonicalRecipe, createCustomPart, createSeededRecipe, createSeededRecipeV2, customPartId, detailedRecipe, emptyPartLayer, faceCells, fillPartLayer, hiddenChoices, isPixelAvatarRecipe, isPixelCustomPart, mirrorPartX, paintPartLayer, partCells, partLayer, partToneColor, pixelAvatarSvg, pixelFigure, pixelSymbolCells, pixelTileColor, seededRandom, seededRecipe, seededRecipeV2, symbolArtCells, withHeadpiece, withSpecies };
|
|
371
|
+
export { AVATAR_COLORS, AVATAR_EXTRA_PARTS, AVATAR_HAIR_PARTS, AVATAR_PARTS, AVATAR_PARTS_V2, AVATAR_PIECE_COLORS, AVATAR_PRESETS, AVATAR_RANGES, AVATAR_SPECIES, AVATAR_SPECIES_SWATCHES, AVATAR_SWATCHES, AVATAR_TURNS, type AvatarColor, type AvatarExtraPart, type AvatarHairPart, type AvatarPart, type AvatarPieceColor, type AvatarRange, type AvatarSpecies, CUSTOM_PART_KEYS, type CustomPartKey, DEFAULT_RECIPE, HAIR_PART_SLOTS, type HairPartSlot, MAX_PART_FIXED_COLORS, PART_LAYERS, PART_SLOTS, PART_TONES, PIXEL_SYMBOLS, type PartCell, type PartColor, type PartInk, type PartLayer, type PartLayerName, type PartSlot, type PartTone, type PixelAvatarRecipe, type PixelAvatarRecipeV1, type PixelAvatarRecipeV2, type PixelAvatarRecipeV3, type PixelAvatarSvgOptions, type PixelCell, type PixelCustomPart, type PixelFigureOptions, type PixelGrid, type PixelMouthState, type PixelSymbol, REPLACE_PART_SLOTS, type ReplacePartSlot, canonicalCustomPart, canonicalRecipe, createCustomPart, createSeededRecipe, createSeededRecipeV2, customPartId, detailedRecipe, emptyPartLayer, faceCells, fillPartLayer, hairPieceStart, hiddenChoices, isHairPartSlot, isPixelAvatarRecipe, isPixelCustomPart, isReplacePartSlot, mirrorPartX, paintPartLayer, partCells, partLayer, partToneColor, pixelAvatarSvg, pixelFigure, pixelSymbolCells, pixelTileColor, replacePartStart, seededRandom, seededRecipe, seededRecipeV2, symbolArtCells, withCustomPart, withHeadpiece, withSpecies, wornPart };
|
|
268
372
|
//# sourceMappingURL=index.d.ts.map
|