|
|
|
|
@ -6,9 +6,9 @@
|
|
|
|
|
los ernaast te zweven. */
|
|
|
|
|
"use strict";
|
|
|
|
|
const AVATAR_SPECIES = ["dino", "monster", "animal"];
|
|
|
|
|
const AVATAR_HAIR = ["none", "spiky", "curly", "ponytail", "mohawk"];
|
|
|
|
|
const AVATAR_HEAD_ACC = ["none", "cap", "crown", "glasses", "sunglasses", "bow", "headphones", "partyhat"];
|
|
|
|
|
const AVATAR_BODY_ACC = ["none", "scarf", "cape", "badge", "necklace", "backpack"];
|
|
|
|
|
const AVATAR_HAIR = ["none", "tuft", "spiky", "curly", "wavy", "bob", "ponytail", "braids", "mohawk"];
|
|
|
|
|
const AVATAR_HEAD_ACC = ["none", "cap", "beanie", "crown", "wizardhat", "glasses", "sunglasses", "eyepatch", "bow", "flower", "headphones", "partyhat"];
|
|
|
|
|
const AVATAR_BODY_ACC = ["none", "scarf", "cape", "badge", "necklace", "bowtie", "belt", "backpack", "satchel", "wings"];
|
|
|
|
|
const AVATAR_DEFAULT = Object.freeze({
|
|
|
|
|
species: "dino", bodyColor: "#3fae6a", hairStyle: "none", hairColor: "#5b3a29",
|
|
|
|
|
accessoryHead: "none", accessoryBody: "none",
|
|
|
|
|
@ -39,147 +39,204 @@ function avatarShade(hex, amt){
|
|
|
|
|
return "#" + [r,g,b].map(v=>clamp(v).toString(16).padStart(2,"0")).join("");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Per-soort silhouet met vaste anatomische ankers: kruin y=2, ogen y=25,
|
|
|
|
|
hals y=53, schouders y=60, heupen y=88 en voetzolen y=108. Armen en benen
|
|
|
|
|
lopen bewust onder het lijf door. Daardoor blijven gewrichten verbonden en
|
|
|
|
|
kunnen accessoires steeds aan hetzelfde lichaamsdeel worden vastgemaakt. */
|
|
|
|
|
/* Groot hoofd en compact, soortspecifiek lijf. De kop beslaat circa twee
|
|
|
|
|
derde van de figuurbreedte; romp en ledematen blijven kort en sluiten onder
|
|
|
|
|
de wangen aan. Alle soorten delen dezelfde accessoire-ankers rond hals y=61,
|
|
|
|
|
borst y=72 en middel y=87. */
|
|
|
|
|
function avatarBodyMarkup(species, bodyColor){
|
|
|
|
|
const outline = avatarShade(bodyColor, -0.48);
|
|
|
|
|
const dark = avatarShade(bodyColor, -0.24);
|
|
|
|
|
const light = avatarShade(bodyColor, 0.4);
|
|
|
|
|
const highlight = avatarShade(bodyColor, 0.7);
|
|
|
|
|
const highlight = avatarShade(bodyColor, 0.72);
|
|
|
|
|
let m = "";
|
|
|
|
|
|
|
|
|
|
/* Onderdelen achter het lijf: soortdetails, benen en doorlopende armen. */
|
|
|
|
|
/* Soortdetails achter kop en lijf. */
|
|
|
|
|
if(species === "dino"){
|
|
|
|
|
m += `<path class="av-part av-tail" d="M 36 78 C 24 82 15 83 5 76 C 12 90 25 96 42 87 Z" fill="${dark}" stroke="${outline}" stroke-width="1.4" stroke-linejoin="round"/>`;
|
|
|
|
|
m += `<path class="av-part av-crest" d="M 68 14 L 78 9 L 75 21 L 84 20 L 77 31" fill="${dark}" stroke="${outline}" stroke-width="1.2" stroke-linejoin="round"/>`;
|
|
|
|
|
m += `<path class="av-part av-tail" d="M 39 79 C 25 83 14 81 3 72 C 10 88 24 94 43 87 Z" fill="${dark}" stroke="${outline}" stroke-width="1.4" stroke-linejoin="round"/>`;
|
|
|
|
|
m += `<path class="av-part av-crest" d="M 73 10 L 85 3 L 81 17 L 91 15 L 84 29" fill="${dark}" stroke="${outline}" stroke-width="1.3" stroke-linejoin="round"/>`;
|
|
|
|
|
}
|
|
|
|
|
if(species === "animal"){
|
|
|
|
|
m += `<path class="av-part av-ear av-ear-left" d="M 30 17 C 16 15 16 2 22 0 C 31 -2 37 7 36 17 Z" fill="${bodyColor}" stroke="${outline}" stroke-width="1.4"/>`;
|
|
|
|
|
m += `<path d="M 28 13 C 21 12 21 6 24 4 C 29 3 32 8 32 13 Z" fill="${light}"/>`;
|
|
|
|
|
m += `<path class="av-part av-ear av-ear-right" d="M 70 17 C 84 15 84 2 78 0 C 69 -2 63 7 64 17 Z" fill="${bodyColor}" stroke="${outline}" stroke-width="1.4"/>`;
|
|
|
|
|
m += `<path d="M 72 13 C 79 12 79 6 76 4 C 71 3 68 8 68 13 Z" fill="${light}"/>`;
|
|
|
|
|
m += `<path class="av-part av-ear av-ear-left" d="M 29 16 C 13 15 10 1 18 -4 C 29 -8 38 4 37 17 Z" fill="${bodyColor}" stroke="${outline}" stroke-width="1.5"/>`;
|
|
|
|
|
m += `<path d="M 27 11 C 19 11 17 4 21 1 C 27 -1 32 6 32 12 Z" fill="${light}"/>`;
|
|
|
|
|
m += `<path class="av-part av-ear av-ear-right" d="M 71 16 C 87 15 90 1 82 -4 C 71 -8 62 4 63 17 Z" fill="${bodyColor}" stroke="${outline}" stroke-width="1.5"/>`;
|
|
|
|
|
m += `<path d="M 73 11 C 81 11 83 4 79 1 C 73 -1 68 6 68 12 Z" fill="${light}"/>`;
|
|
|
|
|
}
|
|
|
|
|
if(species === "monster"){
|
|
|
|
|
m += `<path class="av-part av-horn" d="M 31 18 C 24 12 25 3 30 -3 C 31 7 35 11 39 16 Z" fill="${outline}"/>`;
|
|
|
|
|
m += `<path class="av-part av-horn" d="M 69 18 C 76 12 75 3 70 -3 C 69 7 65 11 61 16 Z" fill="${outline}"/>`;
|
|
|
|
|
m += `<path class="av-part av-horn" d="M 28 15 C 19 8 21 -3 28 -10 C 28 2 34 7 40 13 Z" fill="${outline}"/>`;
|
|
|
|
|
m += `<path class="av-part av-horn" d="M 72 15 C 81 8 79 -3 72 -10 C 72 2 66 7 60 13 Z" fill="${outline}"/>`;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m += `<path class="av-part av-leg av-leg-left" d="M 34 80 C 30 87 29 97 30 101 C 23 102 20 106 23 108 C 29 111 39 109 40 104 L 43 84 Z" fill="${dark}" stroke="${outline}" stroke-width="1.4" stroke-linejoin="round"/>`;
|
|
|
|
|
m += `<path class="av-part av-leg av-leg-right" d="M 66 80 C 70 87 71 97 70 101 C 77 102 80 106 77 108 C 71 111 61 109 60 104 L 57 84 Z" fill="${dark}" stroke="${outline}" stroke-width="1.4" stroke-linejoin="round"/>`;
|
|
|
|
|
m += `<path class="av-part av-arm av-arm-left" d="M 36 61 C 29 58 23 62 19 69 L 14 78 C 11 78 8 80 9 83 C 10 87 16 87 19 84 L 26 75 C 29 72 31 73 35 76 Z" fill="${bodyColor}" stroke="${outline}" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"/>`;
|
|
|
|
|
m += `<path class="av-part av-arm av-arm-right" d="M 64 61 C 71 58 77 62 81 69 L 86 78 C 89 78 92 80 91 83 C 90 87 84 87 81 84 L 74 75 C 71 72 69 73 65 76 Z" fill="${bodyColor}" stroke="${outline}" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"/>`;
|
|
|
|
|
m += `<path d="M 11 81 L 15 83 M 89 81 L 85 83" stroke="${outline}" stroke-width="1.1" stroke-linecap="round"/>`;
|
|
|
|
|
|
|
|
|
|
/* Hals en romp bedekken de aanzetten van armen en benen. */
|
|
|
|
|
m += `<path class="av-part av-neck" d="M 40 45 C 42 55 39 58 35 61 L 65 61 C 61 58 58 55 60 45 Z" fill="${dark}" stroke="${outline}" stroke-width="1.4"/>`;
|
|
|
|
|
m += `<path class="av-part av-torso" d="M 35 57 C 42 53 58 53 65 57 C 72 63 73 79 67 91 C 60 98 40 98 33 91 C 27 79 28 63 35 57 Z" fill="${bodyColor}" stroke="${outline}" stroke-width="1.5" stroke-linejoin="round"/>`;
|
|
|
|
|
m += `<path class="av-part av-belly" d="M 41 63 C 46 59 54 59 59 63 C 64 70 63 85 58 91 C 53 94 47 94 42 91 C 37 85 36 70 41 63 Z" fill="${light}" opacity=".88"/>`;
|
|
|
|
|
m += `<path d="M 43 64 C 48 61 53 61 57 63" stroke="${highlight}" stroke-width="2" fill="none" stroke-linecap="round" opacity=".7"/>`;
|
|
|
|
|
|
|
|
|
|
/* Kop en gelaat; oren en hoorns blijven achter de schedel. */
|
|
|
|
|
const headPath = species === "monster"
|
|
|
|
|
? "M 50 1 C 34 -1 23 9 23 26 C 22 42 31 53 48 55 C 65 57 78 47 77 28 C 77 10 67 2 50 1 Z"
|
|
|
|
|
: species === "dino"
|
|
|
|
|
? "M 48 1 C 33 1 23 11 23 27 C 23 41 31 51 43 54 C 58 59 75 51 77 35 C 79 19 69 4 54 2 Z"
|
|
|
|
|
: "M 50 1 C 34 1 23 11 23 28 C 23 45 34 55 50 55 C 66 55 77 45 77 28 C 77 11 66 1 50 1 Z";
|
|
|
|
|
m += `<path class="av-part av-head" d="${headPath}" fill="${bodyColor}" stroke="${outline}" stroke-width="1.5" stroke-linejoin="round"/>`;
|
|
|
|
|
m += `<path d="M 31 13 C 35 7 42 5 48 5" stroke="${highlight}" stroke-width="2.2" fill="none" stroke-linecap="round" opacity=".65"/>`;
|
|
|
|
|
|
|
|
|
|
/* Korte ledematen verschillen per wezen en verdwijnen onder de romp. */
|
|
|
|
|
if(species === "dino"){
|
|
|
|
|
m += `<path class="av-part av-muzzle" d="M 34 38 C 40 34 62 34 69 40 C 72 47 63 53 51 53 C 39 53 31 47 34 38 Z" fill="${light}"/>`;
|
|
|
|
|
m += `<ellipse cx="43" cy="42" rx="2" ry="2.8" fill="${outline}"/>`;
|
|
|
|
|
m += `<ellipse cx="60" cy="42" rx="2" ry="2.8" fill="${outline}"/>`;
|
|
|
|
|
}
|
|
|
|
|
if(species === "animal"){
|
|
|
|
|
m += `<path class="av-part av-muzzle" d="M 37 37 C 41 33 47 34 50 38 C 53 34 59 33 63 37 C 68 43 61 52 50 52 C 39 52 32 43 37 37 Z" fill="${light}"/>`;
|
|
|
|
|
m += `<path d="M 46 37 Q 50 34 54 37 Q 53 42 50 43 Q 47 42 46 37 Z" fill="#3a2a18"/>`;
|
|
|
|
|
}
|
|
|
|
|
if(species === "monster"){
|
|
|
|
|
m += `<ellipse class="av-part av-eye" cx="37" cy="25" rx="8.5" ry="9.2" fill="#fff" stroke="${outline}" stroke-width="1"/>`;
|
|
|
|
|
m += `<ellipse class="av-part av-eye" cx="63" cy="25" rx="7" ry="7.8" fill="#fff" stroke="${outline}" stroke-width="1"/>`;
|
|
|
|
|
m += `<circle cx="39" cy="27" r="3.6" fill="#232733"/><circle cx="64" cy="27" r="3" fill="#232733"/>`;
|
|
|
|
|
m += `<path class="av-part av-leg av-leg-left" d="M 38 84 C 35 90 35 98 35 100 C 29 101 27 104 30 106 C 35 108 42 106 43 102 L 45 86 Z" fill="${dark}" stroke="${outline}" stroke-width="1.4" stroke-linejoin="round"/>`;
|
|
|
|
|
m += `<path class="av-part av-leg av-leg-right" d="M 62 84 C 65 90 65 98 65 100 C 71 101 73 104 70 106 C 65 108 58 106 57 102 L 55 86 Z" fill="${dark}" stroke="${outline}" stroke-width="1.4" stroke-linejoin="round"/>`;
|
|
|
|
|
m += `<path class="av-part av-arm av-arm-left" d="M 39 65 C 33 63 29 67 26 72 C 23 73 21 76 23 79 C 26 81 30 78 31 75 C 34 73 36 75 39 77 Z" fill="${bodyColor}" stroke="${outline}" stroke-width="1.4" stroke-linejoin="round"/>`;
|
|
|
|
|
m += `<path class="av-part av-arm av-arm-right" d="M 61 65 C 67 63 71 67 74 72 C 77 73 79 76 77 79 C 74 81 70 78 69 75 C 66 73 64 75 61 77 Z" fill="${bodyColor}" stroke="${outline}" stroke-width="1.4" stroke-linejoin="round"/>`;
|
|
|
|
|
m += `<path d="M 23 76 L 27 77 M 77 76 L 73 77" stroke="${outline}" stroke-width="1" stroke-linecap="round"/>`;
|
|
|
|
|
}else if(species === "monster"){
|
|
|
|
|
m += `<path class="av-part av-leg av-leg-left" d="M 36 84 C 32 91 32 98 28 102 C 27 105 34 108 42 104 L 44 86 Z" fill="${dark}" stroke="${outline}" stroke-width="1.4" stroke-linejoin="round"/>`;
|
|
|
|
|
m += `<path class="av-part av-leg av-leg-right" d="M 64 84 C 68 91 68 98 72 102 C 73 105 66 108 58 104 L 56 86 Z" fill="${dark}" stroke="${outline}" stroke-width="1.4" stroke-linejoin="round"/>`;
|
|
|
|
|
m += `<path class="av-part av-arm av-arm-left" d="M 36 64 C 28 61 23 67 19 74 C 14 76 14 82 18 83 C 23 84 26 78 29 74 C 32 72 34 75 37 78 Z" fill="${bodyColor}" stroke="${outline}" stroke-width="1.4" stroke-linejoin="round"/>`;
|
|
|
|
|
m += `<path class="av-part av-arm av-arm-right" d="M 64 64 C 72 61 77 67 81 74 C 86 76 86 82 82 83 C 77 84 74 78 71 74 C 68 72 66 75 63 78 Z" fill="${bodyColor}" stroke="${outline}" stroke-width="1.4" stroke-linejoin="round"/>`;
|
|
|
|
|
m += `<path d="M 16 79 L 21 80 M 84 79 L 79 80 M 29 103 L 34 102 M 71 103 L 66 102" stroke="${outline}" stroke-width="1.1" stroke-linecap="round"/>`;
|
|
|
|
|
}else{
|
|
|
|
|
m += `<ellipse class="av-part av-eye" cx="38" cy="25" rx="7.5" ry="8.2" fill="#fff" stroke="${outline}" stroke-width="1"/>`;
|
|
|
|
|
m += `<ellipse class="av-part av-eye" cx="62" cy="25" rx="7.5" ry="8.2" fill="#fff" stroke="${outline}" stroke-width="1"/>`;
|
|
|
|
|
m += `<circle cx="39.5" cy="27" r="3.2" fill="#232733"/><circle cx="60.5" cy="27" r="3.2" fill="#232733"/>`;
|
|
|
|
|
m += `<path class="av-part av-leg av-leg-left" d="M 38 84 C 35 91 35 98 33 101 C 31 104 35 107 41 106 C 45 104 44 94 45 86 Z" fill="${dark}" stroke="${outline}" stroke-width="1.4"/>`;
|
|
|
|
|
m += `<path class="av-part av-leg av-leg-right" d="M 62 84 C 65 91 65 98 67 101 C 69 104 65 107 59 106 C 55 104 56 94 55 86 Z" fill="${dark}" stroke="${outline}" stroke-width="1.4"/>`;
|
|
|
|
|
m += `<path class="av-part av-arm av-arm-left" d="M 38 65 C 32 63 27 68 25 75 C 22 78 24 82 28 81 C 32 79 32 73 38 76 Z" fill="${bodyColor}" stroke="${outline}" stroke-width="1.4"/>`;
|
|
|
|
|
m += `<path class="av-part av-arm av-arm-right" d="M 62 65 C 68 63 73 68 75 75 C 78 78 76 82 72 81 C 68 79 68 73 62 76 Z" fill="${bodyColor}" stroke="${outline}" stroke-width="1.4"/>`;
|
|
|
|
|
m += `<path d="M 25 78 Q 28 76 31 78 M 75 78 Q 72 76 69 78" stroke="${outline}" stroke-width="1" fill="none" stroke-linecap="round"/>`;
|
|
|
|
|
}
|
|
|
|
|
m += `<circle cx="40.5" cy="25.5" r="1" fill="#fff"/><circle cx="61.5" cy="25.5" r="1" fill="#fff"/>`;
|
|
|
|
|
|
|
|
|
|
m += `<path class="av-part av-neck" d="M 42 52 C 43 59 40 62 37 64 L 63 64 C 60 62 57 59 58 52 Z" fill="${dark}" stroke="${outline}" stroke-width="1.3"/>`;
|
|
|
|
|
const torsoPath = species === "dino"
|
|
|
|
|
? "M 39 61 C 45 58 55 58 61 61 C 67 68 67 83 62 91 C 56 96 44 96 38 91 C 33 83 33 68 39 61 Z"
|
|
|
|
|
: species === "monster"
|
|
|
|
|
? "M 35 62 C 42 57 58 57 65 62 C 71 70 70 85 64 92 C 56 97 44 97 36 92 C 30 85 29 70 35 62 Z"
|
|
|
|
|
: "M 38 61 C 44 58 56 58 62 61 C 67 69 66 84 61 93 C 54 97 46 97 39 93 C 34 84 33 69 38 61 Z";
|
|
|
|
|
m += `<path class="av-part av-torso av-torso-${species}" d="${torsoPath}" fill="${bodyColor}" stroke="${outline}" stroke-width="1.5" stroke-linejoin="round"/>`;
|
|
|
|
|
if(species === "dino"){
|
|
|
|
|
m += `<path d="M 43 48 Q 51 53 59 48" stroke="${outline}" stroke-width="1.6" fill="none" stroke-linecap="round"/>`;
|
|
|
|
|
m += `<path class="av-part av-belly" d="M 43 66 C 47 63 53 63 57 66 C 61 73 60 86 56 91 C 52 93 48 93 44 91 C 40 86 39 73 43 66 Z" fill="${light}" opacity=".9"/>`;
|
|
|
|
|
m += `<circle cx="38" cy="80" r="1.7" fill="${dark}"/><circle cx="63" cy="74" r="1.5" fill="${dark}"/>`;
|
|
|
|
|
}else if(species === "monster"){
|
|
|
|
|
m += `<ellipse class="av-part av-belly" cx="50" cy="77" rx="12" ry="14" fill="${light}" opacity=".72"/>`;
|
|
|
|
|
m += `<circle cx="43" cy="71" r="2" fill="${dark}"/><circle cx="58" cy="82" r="2.5" fill="${dark}"/>`;
|
|
|
|
|
}else{
|
|
|
|
|
m += `<path class="av-part av-chest-fluff" d="M 39 64 L 45 67 L 50 64 L 55 67 L 61 64 C 60 76 57 85 50 90 C 43 85 40 76 39 64 Z" fill="${light}" opacity=".9"/>`;
|
|
|
|
|
}
|
|
|
|
|
if(species === "animal"){
|
|
|
|
|
m += `<path d="M 50 43 L 50 46 M 42 47 Q 46 52 50 47 Q 54 52 58 47" stroke="#3a2a18" stroke-width="1.5" fill="none" stroke-linecap="round" stroke-linejoin="round"/>`;
|
|
|
|
|
|
|
|
|
|
/* De forse kop overlapt de hals en de bovenkant van het kleine lijf. */
|
|
|
|
|
const headPath = species === "monster"
|
|
|
|
|
? "M 50 -3 C 29 -5 16 8 16 30 C 15 51 29 63 48 64 C 69 66 85 53 84 30 C 84 8 71 -2 50 -3 Z"
|
|
|
|
|
: species === "dino"
|
|
|
|
|
? "M 47 -3 C 28 -3 15 10 16 31 C 16 49 28 60 45 63 C 64 67 83 55 85 35 C 87 15 73 -1 55 -2 Z"
|
|
|
|
|
: "M 50 -3 C 30 -3 17 10 17 31 C 17 52 30 64 50 64 C 70 64 83 52 83 31 C 83 10 70 -3 50 -3 Z";
|
|
|
|
|
m += `<path class="av-part av-head av-head-large" d="${headPath}" fill="${bodyColor}" stroke="${outline}" stroke-width="1.6" stroke-linejoin="round"/>`;
|
|
|
|
|
m += `<path d="M 27 12 C 33 4 41 1 49 1" stroke="${highlight}" stroke-width="2.5" fill="none" stroke-linecap="round" opacity=".68"/>`;
|
|
|
|
|
|
|
|
|
|
if(species === "dino"){
|
|
|
|
|
m += `<path class="av-part av-muzzle" d="M 28 39 C 37 34 67 34 75 41 C 79 51 67 59 51 59 C 35 59 24 51 28 39 Z" fill="${light}"/>`;
|
|
|
|
|
m += `<ellipse cx="41" cy="45" rx="2.2" ry="3" fill="${outline}"/><ellipse cx="63" cy="45" rx="2.2" ry="3" fill="${outline}"/>`;
|
|
|
|
|
}else if(species === "animal"){
|
|
|
|
|
m += `<path class="av-part av-muzzle" d="M 33 40 C 38 35 46 36 50 41 C 54 36 62 35 67 40 C 73 49 64 59 50 59 C 36 59 27 49 33 40 Z" fill="${light}"/>`;
|
|
|
|
|
m += `<path d="M 45 40 Q 50 36 55 40 Q 54 46 50 47 Q 46 46 45 40 Z" fill="#3a2a18"/>`;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(species === "monster"){
|
|
|
|
|
m += `<path class="av-part av-mouth" d="M 33 41 Q 50 55 67 41 Q 63 52 50 53 Q 37 52 33 41 Z" fill="#3c2158" stroke="${outline}" stroke-width="1"/>`;
|
|
|
|
|
m += `<path d="M 41 44 L 44 50 L 47 44 Z M 53 44 L 56 50 L 59 44 Z" fill="#fff"/>`;
|
|
|
|
|
m += `<ellipse class="av-part av-eye" cx="35" cy="27" rx="10" ry="10.8" fill="#fff" stroke="${outline}" stroke-width="1"/>`;
|
|
|
|
|
m += `<ellipse class="av-part av-eye" cx="66" cy="27" rx="8.2" ry="9" fill="#fff" stroke="${outline}" stroke-width="1"/>`;
|
|
|
|
|
m += `<circle cx="37" cy="29" r="4" fill="#232733"/><circle cx="67" cy="29" r="3.4" fill="#232733"/>`;
|
|
|
|
|
}else{
|
|
|
|
|
m += `<ellipse class="av-part av-eye" cx="35" cy="27" rx="8.5" ry="9.5" fill="#fff" stroke="${outline}" stroke-width="1"/>`;
|
|
|
|
|
m += `<ellipse class="av-part av-eye" cx="65" cy="27" rx="8.5" ry="9.5" fill="#fff" stroke="${outline}" stroke-width="1"/>`;
|
|
|
|
|
m += `<circle cx="37" cy="29" r="3.7" fill="#232733"/><circle cx="63" cy="29" r="3.7" fill="#232733"/>`;
|
|
|
|
|
}
|
|
|
|
|
m += `<circle cx="38.2" cy="27.5" r="1.2" fill="#fff"/><circle cx="64.2" cy="27.5" r="1.2" fill="#fff"/>`;
|
|
|
|
|
|
|
|
|
|
if(species === "dino"){
|
|
|
|
|
m += `<path d="M 42 54 Q 51 59 60 54" stroke="${outline}" stroke-width="1.7" fill="none" stroke-linecap="round"/>`;
|
|
|
|
|
}else if(species === "animal"){
|
|
|
|
|
m += `<path d="M 50 47 L 50 51 M 40 51 Q 45 57 50 51 Q 55 57 60 51" stroke="#3a2a18" stroke-width="1.6" fill="none" stroke-linecap="round" stroke-linejoin="round"/>`;
|
|
|
|
|
}else{
|
|
|
|
|
m += `<path class="av-part av-mouth" d="M 29 43 Q 50 60 71 43 Q 66 58 50 59 Q 34 58 29 43 Z" fill="#3c2158" stroke="${outline}" stroke-width="1"/>`;
|
|
|
|
|
m += `<path d="M 39 46 L 43 54 L 47 46 Z M 53 46 L 57 54 L 61 46 Z" fill="#fff"/>`;
|
|
|
|
|
}
|
|
|
|
|
return m;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const AVATAR_HAIR_MARKUP = {
|
|
|
|
|
none: () => "",
|
|
|
|
|
spiky: (c) => `
|
|
|
|
|
<path d="M 27 18 L 24 4 L 32 15 Z" fill="${c}"/>
|
|
|
|
|
<path d="M 37 12 L 36 -1 L 44 10 Z" fill="${c}"/>
|
|
|
|
|
<path d="M 48 10 L 50 -3 L 55 10 Z" fill="${c}"/>
|
|
|
|
|
<path d="M 60 10 L 64 -1 L 63 12 Z" fill="${c}"/>
|
|
|
|
|
<path d="M 68 15 L 76 4 L 73 18 Z" fill="${c}"/>`,
|
|
|
|
|
curly: (c) => `
|
|
|
|
|
<circle cx="26" cy="14" r="9" fill="${c}"/>
|
|
|
|
|
<circle cx="37" cy="6" r="10" fill="${c}"/>
|
|
|
|
|
<circle cx="50" cy="3" r="10.5" fill="${c}"/>
|
|
|
|
|
<circle cx="63" cy="6" r="10" fill="${c}"/>
|
|
|
|
|
<circle cx="74" cy="14" r="9" fill="${c}"/>`,
|
|
|
|
|
ponytail: (c) => `
|
|
|
|
|
<path d="M 22 20 Q 24 -6 50 -6 Q 76 -6 78 20 Q 62 2 50 2 Q 38 2 22 20 Z" fill="${c}"/>
|
|
|
|
|
<path d="M 71 9 Q 89 12 87 28 Q 85 42 72 47 Q 81 34 77 22 Q 75 13 67 11 Z" fill="${c}"/>
|
|
|
|
|
<ellipse cx="72" cy="13" rx="4.2" ry="3.2" fill="${avatarShade(c,-0.25)}"/>`,
|
|
|
|
|
mohawk: (c) => `<path d="M 44 20 Q 43 4 50 1 Q 57 4 56 20 Q 50 15 44 20 Z" fill="${c}"/>`,
|
|
|
|
|
none: { back: () => "", front: () => "" },
|
|
|
|
|
tuft: {
|
|
|
|
|
back: () => "",
|
|
|
|
|
front: (c) => `<path class="av-part av-hair av-hair-tuft" d="M 40 8 C 34 0 40 -8 48 0 C 49 -10 59 -9 58 1 C 66 -5 72 3 64 10 C 56 6 48 6 40 8 Z" fill="${c}" stroke="${avatarShade(c,-0.35)}" stroke-width="1.3" stroke-linejoin="round"/>`,
|
|
|
|
|
},
|
|
|
|
|
spiky: {
|
|
|
|
|
back: () => "",
|
|
|
|
|
front: (c) => `<path class="av-part av-hair av-hair-spiky" d="M 18 21 C 18 8 22 1 28 -3 L 27 -11 L 38 -3 L 44 -13 L 51 -3 L 62 -13 L 65 -2 L 78 -9 L 76 3 C 81 7 83 14 82 22 C 68 11 32 11 18 21 Z" fill="${c}" stroke="${avatarShade(c,-0.35)}" stroke-width="1.3" stroke-linejoin="round"/>`,
|
|
|
|
|
},
|
|
|
|
|
curly: {
|
|
|
|
|
back: () => "",
|
|
|
|
|
front: (c) => `<g class="av-part av-hair av-hair-curly" fill="${c}" stroke="${avatarShade(c,-0.32)}" stroke-width="1.1">
|
|
|
|
|
<circle cx="19" cy="16" r="8"/><circle cx="27" cy="5" r="9"/><circle cx="39" cy="-1" r="10"/>
|
|
|
|
|
<circle cx="51" cy="-3" r="10.5"/><circle cx="64" cy="0" r="10"/><circle cx="76" cy="7" r="9"/><circle cx="82" cy="18" r="8"/>
|
|
|
|
|
</g>`,
|
|
|
|
|
},
|
|
|
|
|
wavy: {
|
|
|
|
|
back: (c) => `<path class="av-part av-hair-back av-hair-wavy" d="M 15 17 C 14 -2 30 -11 50 -11 C 71 -11 87 1 86 23 C 88 37 84 50 76 58 C 76 48 70 43 73 33 C 62 42 37 42 26 33 C 29 44 23 50 23 58 C 15 48 12 34 15 17 Z" fill="${c}" stroke="${avatarShade(c,-0.35)}" stroke-width="1.4"/>`,
|
|
|
|
|
front: (c) => `<path class="av-part av-hair av-hair-wavy-fringe" d="M 17 19 C 17 2 31 -8 50 -8 C 69 -8 82 2 83 19 C 76 15 74 9 68 9 C 66 17 58 16 54 10 C 49 18 40 18 37 10 C 31 16 24 17 17 19 Z" fill="${c}" stroke="${avatarShade(c,-0.35)}" stroke-width="1.2"/>`,
|
|
|
|
|
},
|
|
|
|
|
bob: {
|
|
|
|
|
back: (c) => `<path class="av-part av-hair-back av-hair-bob" d="M 13 18 C 13 -2 29 -12 50 -12 C 72 -12 87 0 87 21 L 84 59 L 70 58 L 67 36 L 33 36 L 30 58 L 16 59 Z" fill="${c}" stroke="${avatarShade(c,-0.38)}" stroke-width="1.4" stroke-linejoin="round"/>`,
|
|
|
|
|
front: (c) => `<path class="av-part av-hair av-hair-bob-fringe" d="M 16 20 C 17 1 31 -8 50 -8 C 69 -8 82 2 84 20 C 72 18 68 12 64 7 C 58 14 51 17 43 17 C 35 17 28 14 22 20 Z" fill="${c}" stroke="${avatarShade(c,-0.35)}" stroke-width="1.2"/>`,
|
|
|
|
|
},
|
|
|
|
|
ponytail: {
|
|
|
|
|
back: (c) => `<path class="av-part av-hair-back av-hair-ponytail" d="M 72 5 C 91 3 99 16 94 31 C 91 44 82 54 73 59 C 80 45 78 32 70 23 Z" fill="${c}" stroke="${avatarShade(c,-0.38)}" stroke-width="1.4"/><ellipse cx="75" cy="10" rx="5" ry="4" fill="${avatarShade(c,-0.25)}"/>`,
|
|
|
|
|
front: (c) => `<path class="av-part av-hair av-hair-ponytail-front" d="M 16 20 C 17 0 31 -10 50 -10 C 69 -10 82 1 84 20 C 68 11 32 11 16 20 Z" fill="${c}" stroke="${avatarShade(c,-0.35)}" stroke-width="1.3"/>`,
|
|
|
|
|
},
|
|
|
|
|
braids: {
|
|
|
|
|
back: (c) => `<g class="av-part av-hair-back av-hair-braids" fill="${c}" stroke="${avatarShade(c,-0.38)}" stroke-width="1">
|
|
|
|
|
<path d="M 22 18 C 11 31 15 45 13 58 C 12 65 17 72 22 67 C 26 62 20 57 23 49 C 27 38 30 27 22 18 Z"/>
|
|
|
|
|
<path d="M 78 18 C 89 31 85 45 87 58 C 88 65 83 72 78 67 C 74 62 80 57 77 49 C 73 38 70 27 78 18 Z"/>
|
|
|
|
|
<path d="M 15 38 L 23 42 M 14 51 L 22 55 M 85 38 L 77 42 M 86 51 L 78 55" fill="none" stroke="${avatarShade(c,0.2)}" stroke-width="2"/>
|
|
|
|
|
</g>`,
|
|
|
|
|
front: (c) => `<path class="av-part av-hair av-hair-braids-front" d="M 16 20 C 17 0 31 -10 50 -10 C 69 -10 82 1 84 20 C 75 17 69 12 64 7 C 58 14 50 17 42 16 C 34 15 28 12 22 20 Z" fill="${c}" stroke="${avatarShade(c,-0.35)}" stroke-width="1.3"/>`,
|
|
|
|
|
},
|
|
|
|
|
mohawk: {
|
|
|
|
|
back: () => "",
|
|
|
|
|
front: (c) => `<path class="av-part av-hair av-hair-mohawk" d="M 40 13 C 38 3 39 -7 45 -13 L 50 -5 L 56 -15 C 62 -6 62 4 59 14 C 53 10 46 10 40 13 Z" fill="${c}" stroke="${avatarShade(c,-0.38)}" stroke-width="1.3" stroke-linejoin="round"/>`,
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const AVATAR_HEAD_ACC_MARKUP = {
|
|
|
|
|
none: () => "",
|
|
|
|
|
cap: () => `
|
|
|
|
|
<path class="av-part av-headwear av-cap" d="M 26 15 C 28 1 39 -5 52 -4 C 65 -3 73 4 74 16 C 60 10 41 9 26 15 Z" fill="#3d7ddb" stroke="#234f91" stroke-width="1.3"/>
|
|
|
|
|
<path d="M 26 14 C 38 10 55 10 67 14 C 57 19 40 19 22 20 C 20 19 22 16 26 14 Z" fill="#2f63b3" stroke="#234f91" stroke-width="1.2"/>
|
|
|
|
|
<path d="M 50 -4 L 50 11" stroke="#72a3e8" stroke-width="1.1" opacity=".8"/>`,
|
|
|
|
|
<path class="av-part av-headwear av-cap" d="M 19 17 C 21 0 34 -8 51 -7 C 68 -6 79 3 81 18 C 63 11 39 11 19 17 Z" fill="#3d7ddb" stroke="#234f91" stroke-width="1.4"/>
|
|
|
|
|
<path d="M 20 16 C 37 11 59 12 75 17 C 61 22 39 22 15 22 C 13 20 15 18 20 16 Z" fill="#2f63b3" stroke="#234f91" stroke-width="1.3"/>
|
|
|
|
|
<path d="M 51 -7 L 51 11" stroke="#72a3e8" stroke-width="1.2" opacity=".8"/>`,
|
|
|
|
|
beanie: () => `
|
|
|
|
|
<path class="av-part av-headwear av-beanie" d="M 19 16 C 19 -2 31 -11 50 -11 C 69 -11 81 -2 81 16 Z" fill="#e56a55" stroke="#9f3e31" stroke-width="1.4"/>
|
|
|
|
|
<path d="M 18 13 C 34 10 66 10 82 13 L 81 22 C 64 18 36 18 19 22 Z" fill="#c94f3d" stroke="#9f3e31" stroke-width="1.3"/>
|
|
|
|
|
<circle cx="50" cy="-12" r="5" fill="#f1a15f" stroke="#9f3e31" stroke-width="1"/>`,
|
|
|
|
|
crown: () => `
|
|
|
|
|
<path class="av-part av-headwear av-crown" d="M 27 16 L 30 0 L 39 11 L 50 -5 L 61 11 L 70 0 L 73 16 C 59 12 41 12 27 16 Z" fill="#f0b73a" stroke="#b77b0b" stroke-width="1.2" stroke-linejoin="round"/>
|
|
|
|
|
<path d="M 28 14 C 42 11 58 11 72 14 L 72 18 C 58 15 42 15 28 18 Z" fill="#d99a22"/>
|
|
|
|
|
<circle cx="30" cy="1" r="2.6" fill="#e0483c"/>
|
|
|
|
|
<circle cx="50" cy="-4" r="2.6" fill="#3a8ee0"/>
|
|
|
|
|
<circle cx="70" cy="1" r="2.6" fill="#e0483c"/>`,
|
|
|
|
|
<path class="av-part av-headwear av-crown" d="M 22 17 L 25 -2 L 37 10 L 50 -12 L 63 10 L 75 -2 L 78 17 C 61 12 39 12 22 17 Z" fill="#f0b73a" stroke="#b77b0b" stroke-width="1.3" stroke-linejoin="round"/>
|
|
|
|
|
<path d="M 23 15 C 40 11 60 11 77 15 L 77 20 C 60 16 40 16 23 20 Z" fill="#d99a22"/>
|
|
|
|
|
<circle cx="25" cy="-1" r="2.8" fill="#e0483c"/><circle cx="50" cy="-11" r="3" fill="#3a8ee0"/><circle cx="75" cy="-1" r="2.8" fill="#e0483c"/>`,
|
|
|
|
|
wizardhat: () => `
|
|
|
|
|
<path class="av-part av-headwear av-wizardhat" d="M 49 -16 C 58 -7 64 2 67 15 C 54 12 42 12 30 16 C 39 5 44 -5 49 -16 Z" fill="#6850bd" stroke="#3e2d84" stroke-width="1.4" stroke-linejoin="round"/>
|
|
|
|
|
<path d="M 51 -9 C 57 -3 59 4 61 10" stroke="#9b88df" stroke-width="2" fill="none" stroke-linecap="round"/>
|
|
|
|
|
<path d="M 16 17 C 35 12 66 12 84 17 C 87 20 82 23 75 22 C 57 19 39 19 23 22 C 16 23 12 20 16 17 Z" fill="#513b9d" stroke="#3e2d84" stroke-width="1.4"/>
|
|
|
|
|
<path d="M 45 1 L 47 5 L 52 5 L 48 8 L 50 13 L 45 10 L 41 13 L 42 8 L 38 5 L 43 5 Z" fill="#f1c84c"/>`,
|
|
|
|
|
glasses: () => `
|
|
|
|
|
<circle class="av-part av-eyewear" cx="38" cy="25" r="9.5" fill="rgba(255,255,255,.3)" stroke="#232733" stroke-width="2.4"/>
|
|
|
|
|
<circle class="av-part av-eyewear" cx="62" cy="25" r="9.5" fill="rgba(255,255,255,.3)" stroke="#232733" stroke-width="2.4"/>
|
|
|
|
|
<path d="M 47.5 25 L 52.5 25" stroke="#232733" stroke-width="2.4"/>
|
|
|
|
|
<path d="M 28.5 23 L 22 20" stroke="#232733" stroke-width="2.2" stroke-linecap="round"/>
|
|
|
|
|
<path d="M 71.5 23 L 78 20" stroke="#232733" stroke-width="2.2" stroke-linecap="round"/>`,
|
|
|
|
|
<circle class="av-part av-eyewear av-glasses" cx="35" cy="27" r="10.5" fill="rgba(255,255,255,.28)" stroke="#232733" stroke-width="2.5"/>
|
|
|
|
|
<circle class="av-part av-eyewear av-glasses" cx="65" cy="27" r="10.5" fill="rgba(255,255,255,.28)" stroke="#232733" stroke-width="2.5"/>
|
|
|
|
|
<path d="M 45.5 27 L 54.5 27 M 24.5 24 L 16 20 M 75.5 24 L 84 20" stroke="#232733" stroke-width="2.4" stroke-linecap="round"/>`,
|
|
|
|
|
sunglasses: () => `
|
|
|
|
|
<path class="av-part av-eyewear av-sunglasses" d="M 27 20 Q 27 32 38 32 Q 49 32 48 22 Q 48 18 38 18 Q 27 18 27 20 Z" fill="#1a1d24"/>
|
|
|
|
|
<path d="M 52 22 Q 51 32 62 32 Q 73 32 73 20 Q 73 18 62 18 Q 52 18 52 22 Z" fill="#1a1d24"/>
|
|
|
|
|
<path d="M 48 22 Q 50 20 52 22" stroke="#1a1d24" stroke-width="2.4" fill="none"/>
|
|
|
|
|
<path d="M 27 21 L 20 19 M 73 21 L 80 19" stroke="#1a1d24" stroke-width="2.4" stroke-linecap="round"/>
|
|
|
|
|
<path d="M 31 22 Q 33 20 36 21 M 56 22 Q 58 20 61 21" stroke="#fff" stroke-width="1.6" fill="none" opacity=".55" stroke-linecap="round"/>`,
|
|
|
|
|
<path class="av-part av-eyewear av-sunglasses" d="M 23 21 C 23 35 29 39 37 39 C 46 39 50 33 48 23 C 44 19 29 18 23 21 Z" fill="#1a1d24"/>
|
|
|
|
|
<path d="M 52 23 C 50 33 54 39 63 39 C 71 39 77 35 77 21 C 71 18 56 19 52 23 Z" fill="#1a1d24"/>
|
|
|
|
|
<path d="M 48 24 Q 50 21 52 24 M 23 22 L 15 19 M 77 22 L 85 19" stroke="#1a1d24" stroke-width="2.5" fill="none" stroke-linecap="round"/>
|
|
|
|
|
<path d="M 28 23 Q 32 20 36 22 M 57 23 Q 61 20 65 22" stroke="#fff" stroke-width="1.7" fill="none" opacity=".55" stroke-linecap="round"/>`,
|
|
|
|
|
eyepatch: () => `
|
|
|
|
|
<path class="av-part av-eyewear av-eyepatch" d="M 16 17 C 38 22 61 25 84 17" stroke="#2a2630" stroke-width="2.4" fill="none"/>
|
|
|
|
|
<path d="M 54 23 C 58 18 70 18 75 24 C 75 34 70 40 64 40 C 58 40 54 34 54 23 Z" fill="#34303b" stroke="#17151b" stroke-width="1.3"/>
|
|
|
|
|
<path d="M 60 24 Q 65 21 70 24" stroke="#666170" stroke-width="1.4" fill="none" stroke-linecap="round"/>`,
|
|
|
|
|
bow: () => `
|
|
|
|
|
<path class="av-part av-headwear av-bow" d="M 69 13 C 62 5 56 7 57 14 C 58 20 63 20 69 16 C 75 20 81 20 82 14 C 83 7 76 5 69 13 Z" fill="#e05a8a" stroke="#a93660" stroke-width="1.2"/>
|
|
|
|
|
<circle cx="69" cy="14" r="3.5" fill="#c23f6e"/>`,
|
|
|
|
|
<path class="av-part av-headwear av-bow" d="M 76 13 C 68 3 60 6 61 14 C 62 22 69 22 76 17 C 83 23 91 22 92 14 C 93 6 84 3 76 13 Z" fill="#e05a8a" stroke="#a93660" stroke-width="1.3"/>
|
|
|
|
|
<circle cx="76" cy="15" r="4" fill="#c23f6e"/>`,
|
|
|
|
|
flower: () => `
|
|
|
|
|
<g class="av-part av-headwear av-flower" fill="#f08bb0" stroke="#b74470" stroke-width="1">
|
|
|
|
|
<ellipse cx="78" cy="7" rx="4" ry="7"/><ellipse cx="78" cy="21" rx="4" ry="7"/>
|
|
|
|
|
<ellipse cx="71" cy="14" rx="7" ry="4"/><ellipse cx="85" cy="14" rx="7" ry="4"/>
|
|
|
|
|
<ellipse cx="73" cy="9" rx="4" ry="6" transform="rotate(-45 73 9)"/><ellipse cx="83" cy="19" rx="4" ry="6" transform="rotate(-45 83 19)"/>
|
|
|
|
|
</g><circle cx="78" cy="14" r="4" fill="#f0c84a" stroke="#b77b0b" stroke-width="1"/>`,
|
|
|
|
|
headphones: () => `
|
|
|
|
|
<path class="av-part av-headwear av-headphones" d="M 20 25 C 20 4 32 -7 50 -7 C 68 -7 80 4 80 25" stroke="#333" stroke-width="4.5" fill="none" stroke-linecap="round"/>
|
|
|
|
|
<rect x="15" y="20" width="10" height="19" rx="5" fill="#333" stroke="#17181c" stroke-width="1.2"/>
|
|
|
|
|
<rect x="75" y="20" width="10" height="19" rx="5" fill="#333" stroke="#17181c" stroke-width="1.2"/>
|
|
|
|
|
<rect x="18" y="24" width="4" height="11" rx="2" fill="#667"/>
|
|
|
|
|
<rect x="78" y="24" width="4" height="11" rx="2" fill="#667"/>`,
|
|
|
|
|
<path class="av-part av-headwear av-headphones" d="M 12 29 C 12 3 27 -11 50 -11 C 73 -11 88 3 88 29" stroke="#333" stroke-width="5" fill="none" stroke-linecap="round"/>
|
|
|
|
|
<rect x="8" y="22" width="12" height="23" rx="6" fill="#333" stroke="#17181c" stroke-width="1.3"/>
|
|
|
|
|
<rect x="80" y="22" width="12" height="23" rx="6" fill="#333" stroke="#17181c" stroke-width="1.3"/>
|
|
|
|
|
<rect x="12" y="27" width="4" height="13" rx="2" fill="#667"/><rect x="84" y="27" width="4" height="13" rx="2" fill="#667"/>`,
|
|
|
|
|
partyhat: () => `
|
|
|
|
|
<path class="av-part av-headwear av-partyhat" d="M 50 -8 L 61 19 C 54 22 46 22 39 19 Z" fill="#e05a8a" stroke="#a93660" stroke-width="1.2"/>
|
|
|
|
|
<path d="M 39.5 18 C 46 21 54 21 60.5 18" stroke="#f4c34e" stroke-width="2" fill="none"/>
|
|
|
|
|
<circle cx="45.5" cy="8" r="1.8" fill="#f0b73a"/>
|
|
|
|
|
<circle cx="54" cy="12" r="1.8" fill="#3a8ee0"/>
|
|
|
|
|
<circle cx="47.5" cy="16" r="1.8" fill="#f0b73a"/>
|
|
|
|
|
<circle cx="50" cy="-8" r="3.6" fill="#f0b73a"/>`,
|
|
|
|
|
<path class="av-part av-headwear av-partyhat" d="M 50 -15 L 64 18 C 55 22 45 22 36 18 Z" fill="#e05a8a" stroke="#a93660" stroke-width="1.3"/>
|
|
|
|
|
<path d="M 36.5 17 C 45 21 55 21 63.5 17" stroke="#f4c34e" stroke-width="2.2" fill="none"/>
|
|
|
|
|
<circle cx="45" cy="3" r="2" fill="#f0b73a"/><circle cx="56" cy="8" r="2" fill="#3a8ee0"/><circle cx="47" cy="14" r="2" fill="#f0b73a"/>
|
|
|
|
|
<circle cx="50" cy="-15" r="4.2" fill="#f0b73a"/>`,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const AVATAR_BODY_ACC_MARKUP = {
|
|
|
|
|
@ -187,45 +244,72 @@ const AVATAR_BODY_ACC_MARKUP = {
|
|
|
|
|
scarf: {
|
|
|
|
|
back: () => "",
|
|
|
|
|
front: () => `
|
|
|
|
|
<path class="av-part av-neckwear av-scarf" d="M 35 53 C 43 57 57 57 65 53 L 66 62 C 57 67 43 67 34 62 Z" fill="#d94f4f" stroke="#9d3030" stroke-width="1.2"/>
|
|
|
|
|
<path d="M 57 63 L 62 84 L 53 79 L 50 64 Z" fill="#c23f3f" stroke="#9d3030" stroke-width="1.1" stroke-linejoin="round"/>
|
|
|
|
|
<path d="M 55 75 L 62 78" stroke="#f08080" stroke-width="1.2"/>`,
|
|
|
|
|
<path class="av-part av-neckwear av-scarf" d="M 34 58 C 42 63 58 63 66 58 L 67 67 C 58 72 42 72 33 67 Z" fill="#d94f4f" stroke="#9d3030" stroke-width="1.3"/>
|
|
|
|
|
<path d="M 57 68 L 63 87 L 54 83 L 50 69 Z" fill="#c23f3f" stroke="#9d3030" stroke-width="1.2" stroke-linejoin="round"/>
|
|
|
|
|
<path d="M 56 79 L 62 82" stroke="#f08080" stroke-width="1.2"/>`,
|
|
|
|
|
},
|
|
|
|
|
cape: {
|
|
|
|
|
back: () => `
|
|
|
|
|
<path class="av-part av-backwear av-cape" d="M 33 55 C 19 62 13 79 13 108 C 26 103 38 99 50 91 C 62 99 74 103 87 108 C 87 79 81 62 67 55 C 58 61 42 61 33 55 Z" fill="#7a4bc7" stroke="#54308f" stroke-width="1.5" stroke-linejoin="round"/>
|
|
|
|
|
<path d="M 26 63 C 22 76 23 91 26 101" stroke="#a67de0" stroke-width="2" fill="none" opacity=".65"/>`,
|
|
|
|
|
<path class="av-part av-backwear av-cape" d="M 35 59 C 22 67 17 82 17 108 C 29 103 40 99 50 92 C 60 99 71 103 83 108 C 83 82 78 67 65 59 C 57 64 43 64 35 59 Z" fill="#7a4bc7" stroke="#54308f" stroke-width="1.5" stroke-linejoin="round"/>
|
|
|
|
|
<path d="M 28 67 C 24 80 25 94 28 102" stroke="#a67de0" stroke-width="2" fill="none" opacity=".65"/>`,
|
|
|
|
|
front: () => `
|
|
|
|
|
<path class="av-part av-cape-clasp" d="M 35 56 C 42 61 58 61 65 56" stroke="#f0b73a" stroke-width="2.4" fill="none" stroke-linecap="round"/>
|
|
|
|
|
<circle cx="35" cy="56" r="2.5" fill="#f0b73a"/>
|
|
|
|
|
<circle cx="65" cy="56" r="2.5" fill="#f0b73a"/>`,
|
|
|
|
|
<path class="av-part av-cape-clasp" d="M 36 61 C 43 66 57 66 64 61" stroke="#f0b73a" stroke-width="2.4" fill="none" stroke-linecap="round"/>
|
|
|
|
|
<circle cx="36" cy="61" r="2.5" fill="#f0b73a"/><circle cx="64" cy="61" r="2.5" fill="#f0b73a"/>`,
|
|
|
|
|
},
|
|
|
|
|
badge: {
|
|
|
|
|
back: () => "",
|
|
|
|
|
front: () => `
|
|
|
|
|
<path class="av-part av-chestwear av-badge" d="M 57 67 L 63 67 L 66 72 L 63 78 L 57 78 L 54 72 Z" fill="#f0b73a" stroke="#fff" stroke-width="1.5"/>
|
|
|
|
|
<path d="M 60 69 L 61 72 L 64 72 L 61.5 74 L 62.5 77 L 60 75 L 57.5 77 L 58.5 74 L 56 72 L 59 72 Z" fill="#b8750b"/>`,
|
|
|
|
|
<path class="av-part av-chestwear av-badge" d="M 55 70 L 61 69 L 65 74 L 63 80 L 57 81 L 53 76 Z" fill="#f0b73a" stroke="#fff" stroke-width="1.4"/>
|
|
|
|
|
<path d="M 59 72 L 60 75 L 63 75 L 60.5 77 L 61.5 80 L 59 78 L 56.5 80 L 57.5 77 L 55 75 L 58 75 Z" fill="#b8750b"/>`,
|
|
|
|
|
},
|
|
|
|
|
necklace: {
|
|
|
|
|
back: () => "",
|
|
|
|
|
front: () => `
|
|
|
|
|
<path class="av-part av-neckwear av-necklace" d="M 35 57 C 38 69 44 76 50 77 C 56 76 62 69 65 57" stroke="#f0b73a" stroke-width="2" fill="none" stroke-linecap="round"/>
|
|
|
|
|
<path d="M 50 74 L 55 80 L 50 85 L 45 80 Z" fill="#3a8ee0" stroke="#f0b73a" stroke-width="1.4"/>`,
|
|
|
|
|
<path class="av-part av-neckwear av-necklace" d="M 37 62 C 39 74 45 82 50 83 C 55 82 61 74 63 62" stroke="#f0b73a" stroke-width="2" fill="none" stroke-linecap="round"/>
|
|
|
|
|
<path d="M 50 80 L 55 85 L 50 91 L 45 85 Z" fill="#3a8ee0" stroke="#f0b73a" stroke-width="1.4"/>`,
|
|
|
|
|
},
|
|
|
|
|
bowtie: {
|
|
|
|
|
back: () => "",
|
|
|
|
|
front: () => `
|
|
|
|
|
<path class="av-part av-neckwear av-bowtie" d="M 49 67 C 42 61 36 63 37 70 C 38 76 44 75 49 71 C 54 75 62 76 63 70 C 64 63 57 61 51 67 Z" fill="#3a8ee0" stroke="#205d9c" stroke-width="1.2"/>
|
|
|
|
|
<circle cx="50" cy="69" r="3.5" fill="#f0b73a" stroke="#b77b0b" stroke-width="1"/>`,
|
|
|
|
|
},
|
|
|
|
|
belt: {
|
|
|
|
|
back: () => "",
|
|
|
|
|
front: () => `
|
|
|
|
|
<path class="av-part av-bodywear av-belt" d="M 35 84 C 43 87 57 87 65 84 L 65 91 C 56 94 44 94 35 91 Z" fill="#5a4029" stroke="#392818" stroke-width="1.2"/>
|
|
|
|
|
<rect x="46" y="85" width="9" height="8" rx="1.5" fill="#f0b73a" stroke="#b77b0b" stroke-width="1.2"/>
|
|
|
|
|
<rect x="49" y="87" width="3" height="4" fill="#5a4029"/>`,
|
|
|
|
|
},
|
|
|
|
|
backpack: {
|
|
|
|
|
back: () => `
|
|
|
|
|
<path class="av-part av-backwear av-backpack" d="M 28 63 C 29 54 39 50 50 50 C 61 50 71 54 72 63 L 77 89 C 70 96 30 96 23 89 Z" fill="#8a6a45" stroke="#5a4029" stroke-width="1.6"/>
|
|
|
|
|
<path d="M 39 53 C 40 46 60 46 61 53" stroke="#5a4029" stroke-width="3" fill="none"/>`,
|
|
|
|
|
<path class="av-part av-backwear av-backpack" d="M 30 65 C 31 56 39 53 50 53 C 61 53 69 56 70 65 L 75 91 C 68 97 32 97 25 91 Z" fill="#8a6a45" stroke="#5a4029" stroke-width="1.6"/>
|
|
|
|
|
<path d="M 40 55 C 41 49 59 49 60 55" stroke="#5a4029" stroke-width="3" fill="none"/>`,
|
|
|
|
|
front: () => `
|
|
|
|
|
<path class="av-part av-backpack-strap" d="M 37 57 C 29 63 29 76 33 84 M 63 57 C 71 63 71 76 67 84" stroke="#5a4632" stroke-width="4" fill="none" stroke-linecap="round"/>
|
|
|
|
|
<path d="M 33 83 L 38 86 M 67 83 L 62 86" stroke="#d0a36d" stroke-width="1.5"/>`,
|
|
|
|
|
<path class="av-part av-backpack-strap" d="M 39 62 C 33 69 33 80 36 88 M 61 62 C 67 69 67 80 64 88" stroke="#5a4632" stroke-width="3.5" fill="none" stroke-linecap="round"/>
|
|
|
|
|
<path d="M 35 87 L 40 90 M 65 87 L 60 90" stroke="#d0a36d" stroke-width="1.4"/>`,
|
|
|
|
|
},
|
|
|
|
|
satchel: {
|
|
|
|
|
back: () => `
|
|
|
|
|
<path class="av-part av-backwear av-satchel" d="M 61 75 C 68 72 79 74 83 80 L 82 95 C 76 99 65 98 60 93 Z" fill="#b87545" stroke="#704329" stroke-width="1.5"/>
|
|
|
|
|
<path d="M 63 81 C 69 84 76 84 81 81" stroke="#e3ad72" stroke-width="1.4" fill="none"/>`,
|
|
|
|
|
front: () => `
|
|
|
|
|
<path class="av-part av-satchel-strap" d="M 36 62 C 49 71 58 80 68 94" stroke="#704329" stroke-width="2.8" fill="none" stroke-linecap="round"/>
|
|
|
|
|
<circle cx="67" cy="93" r="2" fill="#f0b73a"/>`,
|
|
|
|
|
},
|
|
|
|
|
wings: {
|
|
|
|
|
back: () => `
|
|
|
|
|
<path class="av-part av-backwear av-wings" d="M 37 65 C 25 51 11 48 5 55 C 1 64 12 72 24 74 C 10 77 6 86 13 91 C 23 96 33 85 41 75 Z" fill="#b8e8ef" stroke="#5799ad" stroke-width="1.5" stroke-linejoin="round" opacity=".95"/>
|
|
|
|
|
<path d="M 63 65 C 75 51 89 48 95 55 C 99 64 88 72 76 74 C 90 77 94 86 87 91 C 77 96 67 85 59 75 Z" fill="#b8e8ef" stroke="#5799ad" stroke-width="1.5" stroke-linejoin="round" opacity=".95"/>
|
|
|
|
|
<path d="M 11 58 C 23 61 30 67 37 74 M 89 58 C 77 61 70 67 63 74" stroke="#fff" stroke-width="2" fill="none" opacity=".7"/>`,
|
|
|
|
|
front: () => `<circle class="av-part av-wing-clasp" cx="37" cy="65" r="2.4" fill="#5799ad"/><circle cx="63" cy="65" r="2.4" fill="#5799ad"/>`,
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* Alleen een pet bedekt het bovenhoofd volledig. Een kroon rust juist op het
|
|
|
|
|
haar; een paardenstaart blijft naast de pet zichtbaar. */
|
|
|
|
|
/* Pet en muts bedekken de voorste haarlaag. Lange stijlen houden hun
|
|
|
|
|
achterlaag, zodat staarten, vlechten en lokken naast de kop zichtbaar zijn. */
|
|
|
|
|
function avatarHairSuppressed(c){
|
|
|
|
|
return c.accessoryHead === "cap" && c.hairStyle !== "ponytail";
|
|
|
|
|
return c.accessoryHead === "cap" || c.accessoryHead === "beanie";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* bouwt de SVG-weergave van een personage; config==null → neutrale
|
|
|
|
|
@ -236,15 +320,17 @@ function renderAvatarFace(config, size){
|
|
|
|
|
const c = avatarSanitize(config);
|
|
|
|
|
const svg = document.createElementNS(AVATAR_SVG_NS, "svg");
|
|
|
|
|
/* Extra ruimte voorkomt afsnijden van hoofddeksels, haar en voetzolen. */
|
|
|
|
|
svg.setAttribute("viewBox", "-6 -12 112 124");
|
|
|
|
|
svg.setAttribute("viewBox", "-8 -21 116 132");
|
|
|
|
|
svg.setAttribute("preserveAspectRatio", "xMidYMid meet");
|
|
|
|
|
svg.setAttribute("class", "avatar-face " + (size || "md") + " av-species-" + c.species);
|
|
|
|
|
svg.setAttribute("role", "img");
|
|
|
|
|
svg.setAttribute("aria-label", T("avatarAlt"));
|
|
|
|
|
const bodyAccessory = AVATAR_BODY_ACC_MARKUP[c.accessoryBody];
|
|
|
|
|
const hair = AVATAR_HAIR_MARKUP[c.hairStyle];
|
|
|
|
|
let markup = bodyAccessory.back();
|
|
|
|
|
markup += hair.back(c.hairColor);
|
|
|
|
|
markup += avatarBodyMarkup(c.species, c.bodyColor);
|
|
|
|
|
if(!avatarHairSuppressed(c)) markup += AVATAR_HAIR_MARKUP[c.hairStyle](c.hairColor);
|
|
|
|
|
if(!avatarHairSuppressed(c)) markup += hair.front(c.hairColor);
|
|
|
|
|
markup += AVATAR_HEAD_ACC_MARKUP[c.accessoryHead]();
|
|
|
|
|
markup += bodyAccessory.front();
|
|
|
|
|
svg.innerHTML = markup;
|
|
|
|
|
|