UNPKG

facesjs

Version:

A JavaScript library for generating vector-based cartoon faces

89 lines (84 loc) 3.02 kB
import delve from "dlv"; import { dset } from "dset"; import { colors, generate, numberRanges } from "./generate.js"; import { features, races } from "./common.js"; import { deepCopy } from "./utils.js"; import { svgsGenders, svgsIndex } from "./svgs-index.js"; // Currently, race just affects skin color and hair color. Let's ignore hair color (since you could imagine it being dyed anyway) and figure out someone's race just based on skin color. If no race is found, return undefined. const imputeRace = face => { return races.find(race => colors[race].skin.includes(face.body.color)); }; export const generateRelative = ({ gender, race: inputRace, relative }) => { const face = deepCopy(relative); const race = inputRace ?? imputeRace(face); const randomFace = generate(undefined, { gender, race }); // Regenerate some properties always, and others with some probability const regenerateProperties = { accessories: "always", body: { color: inputRace !== undefined ? "always" : "sometimesIfRaceIsKnown", id: "sometimes", size: "always" }, ear: "sometimes", eye: "sometimes", eyebrow: "sometimes", eyeLine: "sometimes", facialHair: "always", fatness: "always", glasses: "always", hair: { color: inputRace !== undefined ? "always" : "sometimesIfRaceIsKnown", flip: "always", id: "always" }, hairBg: "always", head: { id: "sometimes", shave: "always" }, jersey: "never", miscLine: "sometimes", mouth: "sometimes", nose: "sometimes", smileLine: "sometimes", teamColors: "never" }; const probRegenerate = 0.25; const processRegenerateProperties = (objOutput, objRandom, regeneratePropertiesLocal) => { for (const [key, value] of Object.entries(regeneratePropertiesLocal)) { if (typeof value === "string") { if (value === "always" || (value === "sometimes" || value === "sometimesIfRaceIsKnown" && race !== undefined) && Math.random() < probRegenerate) { objOutput[key] = objRandom[key]; } } else { processRegenerateProperties(objOutput[key], objRandom[key], value); } } }; processRegenerateProperties(face, randomFace, regenerateProperties); // Override any ID properties that are not valid for the specified gender for (const key of features) { const svgIndex = svgsIndex[key].findIndex(id => id === face[key].id); const svgGender = svgsGenders[key][svgIndex]; if (svgIndex < 0 || svgGender === "male" && gender === "female" || svgGender === "female" && gender === "male") { face[key].id = randomFace[key].id; } } // Override any numeric properties that are not valid for the specified gender for (const [path, ranges] of Object.entries(numberRanges)) { const current = delve(face, path); const range = ranges[gender]; if (current < range[0] || current > range[1]) { dset(face, path, delve(randomFace, path)); } } return face; };