UNPKG

facesjs

Version:

A JavaScript library for generating vector-based cartoon faces

154 lines 4.33 kB
import override from "./override.js"; import { svgsGenders, svgsIndex } from "./svgs-index.js"; import { races } from "./common.js"; import { randChoice, randInt, randUniform } from "./utils.js"; import { generateRelative } from "./generateRelative.js"; const getID = (type, gender) => { const validIDs = svgsIndex[type].filter((_id, index) => { return svgsGenders[type][index] === "both" || svgsGenders[type][index] === gender; }); return randChoice(validIDs); }; export const colors = { white: { skin: ["#f2d6cb", "#ddb7a0"], hair: ["#272421", "#3D2314", "#5A3825", "#CC9966", "#2C1608", "#B55239", "#e9c67b", "#D7BF91"] }, asian: { // https://imgur.com/a/GrBuWYw skin: ["#fedac7", "#f0c5a3", "#eab687"], hair: ["#272421", "#0f0902"] }, brown: { skin: ["#bb876f", "#aa816f", "#a67358"], hair: ["#272421", "#1c1008"] }, black: { skin: ["#ad6453", "#74453d", "#5c3937"], hair: ["#272421"] } }; const defaultTeamColors = ["#89bfd3", "#7a1319", "#07364f"]; const roundTwoDecimals = x => Math.round(x * 100) / 100; export const numberRanges = { "body.size": { female: [0.8, 0.9], male: [0.95, 1.05] }, fatness: { female: [0, 0.4], male: [0, 1] }, "ear.size": { female: [0.5, 1], male: [0.5, 1.5] }, "eye.angle": { female: [-10, 15], male: [-10, 15] }, "eyebrow.angle": { female: [-15, 20], male: [-15, 20] }, "head.shave": { female: [0, 0], male: [0, 0.2] }, "nose.size": { female: [0.5, 1], male: [0.5, 1.25] }, "smileLine.size": { female: [0.25, 2.25], male: [0.25, 2.25] } }; const getRandInt = (key, gender) => { return randInt(numberRanges[key][gender][0], numberRanges[key][gender][1]); }; const getRandUniform = (key, gender) => { return roundTwoDecimals(randUniform(numberRanges[key][gender][0], numberRanges[key][gender][1])); }; export const generate = (overrides, options) => { const gender = options?.gender ?? "male"; let face; if (options?.relative) { face = generateRelative({ gender, race: options.race, relative: options.relative }); } else { const race = options?.race ?? randChoice(races); const palette = colors[race]; const skinColor = randChoice(palette.skin); const hairColor = randChoice(palette.hair); face = { fatness: getRandUniform("fatness", gender), teamColors: defaultTeamColors, hairBg: { id: Math.random() < (gender === "male" ? 0.1 : 0.9) ? getID("hairBg", gender) : "none" }, body: { id: getID("body", gender), color: skinColor, size: getRandUniform("body.size", gender) }, jersey: { id: getID("jersey", gender) }, ear: { id: getID("ear", gender), size: getRandUniform("ear.size", gender) }, head: { id: getID("head", gender), shave: `rgba(0,0,0,${gender === "male" && Math.random() < 0.25 ? getRandUniform("head.shave", gender) : 0})` }, eyeLine: { id: Math.random() < 0.75 ? getID("eyeLine", gender) : "none" }, smileLine: { id: Math.random() < (gender === "male" ? 0.75 : 0.1) ? getID("smileLine", gender) : "none", size: getRandUniform("smileLine.size", gender) }, miscLine: { id: Math.random() < 0.5 ? getID("miscLine", gender) : "none" }, facialHair: { id: Math.random() < 0.5 ? getID("facialHair", gender) : "none" }, eye: { id: getID("eye", gender), angle: getRandInt("eye.angle", gender) }, eyebrow: { id: getID("eyebrow", gender), angle: getRandInt("eyebrow.angle", gender) }, hair: { id: getID("hair", gender), color: hairColor, flip: Math.random() < 0.5 }, mouth: { id: getID("mouth", gender), flip: Math.random() < 0.5 }, nose: { id: getID("nose", gender), flip: Math.random() < 0.5, size: getRandUniform("nose.size", gender) }, glasses: { id: Math.random() < 0.1 ? getID("glasses", gender) : "none" }, accessories: { id: Math.random() < 0.2 ? getID("accessories", gender) : "none" } }; } override(face, overrides); return face; };