@botharness/pixel-avatar
Seeded, editable 32×32 chibi pixel avatars with state symbols they can morph into.
import {
pixelAvatarSvg,
seededRecipe,
faceCells,
pixelSymbolCells,
} from '@botharness/pixel-avatar';
const recipe = seededRecipe('DeepSeekBot');
const svg = pixelAvatarSvg(recipe); // 32×32 viewBox, crisp edges, no ids or scripts
seededRecipe(name): the same name always gives the same face.createSeededRecipe(namespace)makes a factory with its own set of faces.AVATAR_PARTS,AVATAR_SWATCHES,AVATAR_PRESETS,DEFAULT_RECIPE: everything an editor needs.isPixelAvatarRecipe,canonicalRecipe: validate and normalise saved recipes.AVATAR_HAIR_PARTS,AVATAR_RANGES,detailedRecipe(recipe): optional finer controls. A recipe may carrybangs,sideHair,backHair,spacing,heightandhairLength, all six or none;detailedRecipederives them from the plainhairso an editor can start from what is on screen. Recipes without them render exactly as before.AVATAR_SPECIES,AVATAR_SPECIES_SWATCHES,AVATAR_PIECE_COLORS,withSpecies(recipe, species): Avatar Species (human,goblin) on the same rig, as asset version 2.withSpecieskeeps every choice, splits side hair intosideHair(left) andrightSideHair, and accepts optionalleftSideHairColor/rightSideHairColor, where left and right are as seen on screen. Consumers built before version 2 reject these recipes withisPixelAvatarRecipeand can show a saved snapshot instead.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 optionalbeard, and a flower'spetalsandflowerBase.hiddenChoicesnames saved choices the current species or headwear keeps but does not draw, so an editor can say so instead of discarding them.PixelCustomPart,withHeadpiece(recipe, part),customPartId,isPixelCustomPart: a Human-drawn Custom Part in theheadpieceslot (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], wherecoloris an appearance color slot (hairColor,skinColor,eyeColor,shirtColor), so the part recolors with the Avatar, or a fixed#rrggbb, andtoneis 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.customPartIdis the SHA-256 of the canonical content; names, authors and origins belong to the consumer's library.HAIR_PART_SLOTS,hairPieceStart(recipe, slot),withCustomPart(recipe, slot, part),wornPart: drawn hair pieces.bangs,leftSideHair,rightSideHairandbackHaireach take a Custom Part (front layer only) that replaces the built-in piece while it stays saved underneath. In a hair part, ahairColorcell at tone 0 is live hair: it is shaded with the rest of the hair exactly like the built-in piece, sohairPieceStartflattens 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.REPLACE_PART_SLOTS,replacePartStart(recipe, slot): drawnoutfit,accessory,beard,glasses,nose,cheeks,petalsandflowerBaseparts (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.replacePartStartflattens 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.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.partLinePoints,partRectPoints,gradientPartLayer,ditherThreshold,noisePartLayer,shadePartLayer: line (with 0°/45°/90° snap), rectangle (with square), tone gradient with 4×4 or 2×2 ordered dithering inside the start region, seeded ±1 tone noise, and a shade stroke that moves each colored cell one tone. All mirror, and all produce ordinary cells: the seed and the tool are not part of the part.AVATAR_PIECE_COLORS_V4,AVATAR_STRANDS,AVATAR_HEADPIECES,withPieces,withBuiltInHeadpiece,builtInHeadpiece,headpieceStart: asset version 4. Bangs, back hair and a singlestrandeach take an optional color (bangsColor,backHairColor,strandColor) that defaults tohairColor, like the side hair colors. The headpiece slot holds a built-in headpiece (ears, horns, halo or small head wings) or a Custom Part, worn together with any accessory. The base sits behind the hair and the rest in front, and the far side hides when the head turns.withPiecesupgrades a recipe when the Human edits and moves an accessory that is now a headpiece into the empty headpiece slot. Saved recipes are never migrated on their own, so they keep rendering as before.headpieceStartflattens the worn headpiece into a Custom Part to start drawing from.AVATAR_ANIMAL_SPECIES,AVATAR_PATTERNS,isAnimalSpecies: animal species in asset version 4. Each has a muzzle, an animal nose and its own ears, uses the skin color as fur, and takes an optional furpatterndrawn in fur tones. A drawnpatternCustom Part replaces the built-in one. Ear headpieces and ear accessories are kept but hidden on an animal.faceCells,pixelSymbolCells,symbolArtCells: pixels for@botharness/pixel-morph.pixelAvatarSvg(recipe, { turns, classPrefix }): optional pre-rendered head turns, and rig layer classes (<prefix>-body,-head,-face,-gaze,-blink) for CSS animation.pixelAvatarSvg(recipe, { mouthLayers: true, speechMouthVersion: 2 }): saved/closed/half-open/open speech layers, with a flatter fully open mouth. OmitspeechMouthVersion(or use1) for the original round opening. Version 2 only changes the open layer, including each head turn; the accepted half-open, closed and saved face remain identical. This is a rendering-only speech artwork version, not a stored recipe migration.pixelFiguretakes the same options. Text pacing and layer opacity stay with the consumer.