From ac11982aaecae46a522ceb540f2d34c741a5fe6f Mon Sep 17 00:00:00 2001 From: Brian Luerssen Date: Sat, 4 Jul 2026 13:48:22 -0400 Subject: [PATCH] Add 12 new avatar styles and an Accessories category Brian-approved expansion round (previewed before commit): - Eyes: Closed, Hearts, Dizzy, Sideeye - Mouths: Grin, Tongue, Whistle, Laugh - Noses: Pointed, Button - Bodies: Hoodie, Stripes - New Accessories selector (z-layer above hair) with Earring and Earrings, its own metals+brights palette, and None weighted to 60% in randomize so random avatars stay understated Cut during review: Vneck, Chinstrap, Handlebar, Headphones/Earbuds. Co-Authored-By: Claude Fable 5 --- src/components/App.res | 8 ++++ src/components/AvatarGenerator.css | 1 - src/components/AvatarGenerator.res | 3 ++ src/components/Modal.res | 3 +- src/components/SvgLoader.res | 66 ++++++++++++++++++++++++++++++ src/components/Types.res | 7 ++++ src/components/Wordmark.res | 4 +- src/data/config.json | 44 ++++++++++++++++---- src/helpers/shareUrl.js | 2 + src/pages/Index.res | 4 ++ 10 files changed, 129 insertions(+), 13 deletions(-) diff --git a/src/components/App.res b/src/components/App.res index d4b298a..9f7bf35 100644 --- a/src/components/App.res +++ b/src/components/App.res @@ -65,6 +65,14 @@ let make = ( selectedColor: styles.skinColor, selectedStyle: styles.nose, }, + { + id: #Accessories, + label: "ACCESSORIES", + colors: config.accessoryColors, + styles: config.accessoryStyles, + selectedColor: styles.accessoriesColor, + selectedStyle: styles.accessories, + }, { id: #Background, label: "BACKGROUND", diff --git a/src/components/AvatarGenerator.css b/src/components/AvatarGenerator.css index 6c355a7..b5775e9 100644 --- a/src/components/AvatarGenerator.css +++ b/src/components/AvatarGenerator.css @@ -87,4 +87,3 @@ margin-bottom: 48px; } } - diff --git a/src/components/AvatarGenerator.res b/src/components/AvatarGenerator.res index 1801a5b..d4cdac9 100644 --- a/src/components/AvatarGenerator.res +++ b/src/components/AvatarGenerator.res @@ -2,6 +2,7 @@ let getZIndex = (id: Types.id) => switch id { + | #Accessories => "115" | #Eyes => "110" | #Nose => "100" | #FacialHair => "90" @@ -72,6 +73,7 @@ let make = (~randomize, ~settings: array, ~onChange, ~onExport) = | #Hair => #HairColor | #FacialHair => #FacialHairColor | #Body => #BodyColor + | #Accessories => #AccessoriesColor | #Background => #BackgroundColor | _ => Js.Exn.raiseError("ColorNotFound: " ++ (o.id :> string)) } @@ -87,6 +89,7 @@ let make = (~randomize, ~settings: array, ~onChange, ~onExport) = | #Eyes => #EyesStyle | #Mouth => #MouthStyle | #Nose => #NoseStyle + | #Accessories => #AccessoriesStyle | _ => Js.Exn.raiseError("StyleNotFound: " ++ (o.id :> string)) } onChange(key, style) diff --git a/src/components/Modal.res b/src/components/Modal.res index 1294f00..ed34292 100644 --- a/src/components/Modal.res +++ b/src/components/Modal.res @@ -35,8 +35,7 @@ let make = (~visible, ~onToggle) => { target="_blank" rel="no-follow" href={"https://twitter.com/intent/tweet?text=I+made+this+avatar+with+Personas+by+@Draftbit&url=" ++ - Js.Global.encodeURIComponent(locationHref) ++ - "&related=draftbit"} + Js.Global.encodeURIComponent(locationHref) ++ "&related=draftbit"} className="Modal-button Modal-button--twitter"> {React.string("Twitter")} diff --git a/src/components/SvgLoader.res b/src/components/SvgLoader.res index b2e535a..83d6863 100644 --- a/src/components/SvgLoader.res +++ b/src/components/SvgLoader.res @@ -178,6 +178,58 @@ let getSidebuzz = (fill, size) => let getStraightbun = (fill, size) => `` +/* --- 2026 expansion: eyes --- */ + +let getEyesClosed = (_, size) => + `` + +let getEyesHearts = (_, size) => + `` + +let getEyesDizzy = (_, size) => + `` + +let getEyesSideeye = (_, size) => + `` + +/* --- 2026 expansion: mouths --- */ + +let getMouthGrin = (_, size) => + `` + +let getMouthTongue = (_, size) => + `` + +let getMouthWhistle = (_, size) => + `` + +let getMouthLaugh = (_, size) => + `` + +/* --- 2026 expansion: noses --- */ + +let getNosePointed = (fill, size) => + `` + +let getNoseButton = (fill, size) => + `` + +/* --- 2026 expansion: bodies --- */ + +let getBodyHoodie = (fill, size) => + `` + +let getBodyStripes = (fill, size) => + `` + +/* --- 2026 expansion: accessories --- */ + +let getEarring = (fill, size) => + `` + +let getEarrings = (fill, size) => + `` + @react.component let make = (~style=?, ~className="", ~name, ~fill="#000", ~size="64") => { let getHtml = name => @@ -231,6 +283,20 @@ let make = (~style=?, ~className="", ~name, ~fill="#000", ~size="64") => { | "Sidebuzz" => getSidebuzz(fill, size) | "Straightbun" => getStraightbun(fill, size) | "Background" => getBackground(fill, size) + | "Closed" => getEyesClosed(fill, size) + | "Hearts" => getEyesHearts(fill, size) + | "Dizzy" => getEyesDizzy(fill, size) + | "Sideeye" => getEyesSideeye(fill, size) + | "Grin" => getMouthGrin(fill, size) + | "Tongue" => getMouthTongue(fill, size) + | "Whistle" => getMouthWhistle(fill, size) + | "Laugh" => getMouthLaugh(fill, size) + | "Pointed" => getNosePointed(fill, size) + | "Button" => getNoseButton(fill, size) + | "Hoodie" => getBodyHoodie(fill, size) + | "Stripes" => getBodyStripes(fill, size) + | "Earring" => getEarring(fill, size) + | "Earrings" => getEarrings(fill, size) | _ => "" } diff --git a/src/components/Types.res b/src/components/Types.res index 4ff38c4..8b53870 100644 --- a/src/components/Types.res +++ b/src/components/Types.res @@ -6,6 +6,7 @@ type id = [ | #Eyes | #Mouth | #Nose + | #Accessories | #Background | #Head ] @@ -15,6 +16,7 @@ type color = [ | #HairColor | #FacialHairColor | #BodyColor + | #AccessoriesColor | #BackgroundColor ] @@ -26,6 +28,7 @@ type style = [ | #EyesStyle | #MouthStyle | #NoseStyle + | #AccessoriesStyle ] type key = [color | style] @@ -42,6 +45,8 @@ type styles = { eyes: string, mouth: string, nose: string, + accessories: string, + accessoriesColor: string, bgColor: string, head: string, } @@ -60,6 +65,7 @@ type config = { hairColors: array, facialHairColors: array, bodyColors: array, + accessoryColors: array, bgColors: array, disabledColors: array, skinStyles: array, @@ -69,5 +75,6 @@ type config = { eyeStyles: array, mouthStyles: array, noseStyles: array, + accessoryStyles: array, bgStyles: array, } diff --git a/src/components/Wordmark.res b/src/components/Wordmark.res index 627d647..e74d183 100644 --- a/src/components/Wordmark.res +++ b/src/components/Wordmark.res @@ -3,8 +3,6 @@ let utmHref = (placement: string) => @react.component let make = (~placement: string) => - + diff --git a/src/data/config.json b/src/data/config.json index 9b1baf0..eefb010 100644 --- a/src/data/config.json +++ b/src/data/config.json @@ -1,5 +1,7 @@ { - "skinStyles": ["Skin"], + "skinStyles": [ + "Skin" + ], "hairStyles": [ "Bald", "Hat", @@ -36,7 +38,9 @@ "Oval", "Round", "Square", - "Checkered" + "Checkered", + "Hoodie", + "Stripes" ], "eyeStyles": [ "Glasses", @@ -44,7 +48,11 @@ "Open", "Sleepy", "Sunglasses", - "Wink" + "Wink", + "Closed", + "Hearts", + "Dizzy", + "Sideeye" ], "mouthStyles": [ "Bigsmile", @@ -53,14 +61,27 @@ "Pacifier", "Smile", "Smirk", - "Surprise" + "Surprise", + "Grin", + "Tongue", + "Whistle", + "Laugh" ], "noseStyles": [ "Mediumround", "Smallround", - "Wrinkles" + "Wrinkles", + "Pointed", + "Button" + ], + "accessoryStyles": [ + "None", + "Earring", + "Earrings" + ], + "bgStyles": [ + "Background" ], - "bgStyles": ["Background"], "skinColors": [ "FFCC22", "FFDFC4", @@ -117,6 +138,16 @@ "C866D9", "68C9F2" ], + "accessoryColors": [ + "F3B63A", + "C9CFDB", + "C98850", + "362C47", + "F55D81", + "54D7C7", + "456DFF", + "5A45FF" + ], "bgColors": [ "93A7FF", "A9E775", @@ -142,4 +173,3 @@ "EEEFF5" ] } - diff --git a/src/helpers/shareUrl.js b/src/helpers/shareUrl.js index 1328593..2c7aa6d 100644 --- a/src/helpers/shareUrl.js +++ b/src/helpers/shareUrl.js @@ -13,6 +13,7 @@ const STYLE_KEYS = [ ["eyes", "eyeStyles"], ["mouth", "mouthStyles"], ["nose", "noseStyles"], + ["accessories", "accessoryStyles"], ]; const COLOR_KEYS = [ @@ -20,6 +21,7 @@ const COLOR_KEYS = [ "hairColor", "facialHairColor", "bodyColor", + "accessoriesColor", "bgColor", ]; diff --git a/src/pages/Index.res b/src/pages/Index.res index 7641b0f..3137cb3 100644 --- a/src/pages/Index.res +++ b/src/pages/Index.res @@ -28,6 +28,8 @@ let randomizeStyles = (config: Types.config): Types.styles => { eyes: getRandom(config.eyeStyles), mouth: getRandom(config.mouthStyles), nose: getRandom(config.noseStyles), + accessories: Js.Math.random() < 0.6 ? "None" : getRandom(config.accessoryStyles), + accessoriesColor: getRandom(config.accessoryColors), bgColor: getRandom(config.bgColors), head: "Head", } @@ -57,6 +59,8 @@ let make = () => { | #EyesStyle => {...styles, eyes: value} | #MouthStyle => {...styles, mouth: value} | #NoseStyle => {...styles, nose: value} + | #AccessoriesStyle => {...styles, accessories: value} + | #AccessoriesColor => {...styles, accessoriesColor: value} | #BackgroundColor => {...styles, bgColor: value} } )