« Back

# Procedural Avatars

Procedural avatars are a great way to give some color and uniqueness to an entity that's never going to have a profile picture.
Given an input string we can create a sort of visual hash - a graphic that will always be the same for that given string.
Input String

## tl;dr

export default function ProceduralAvatar({name}: {name: string}) {
    // Step 1
    const decimalHash = hash(name);
    const binary = parseInt(decimalHash).toString(2).slice(0, 16);
    // Step 2
    const booleans = binary.split('').map((ii) => Boolean(parseInt(ii, 2)));
    const chunked = [...Array(4)].map((_) => booleans.splice(0, 4));

    // Step 4
    const colors = ['blue', 'orange', 'green', 'yellow', 'red', 'purple'];
    const color = colors[parseInt(decimalHash.slice(-1), 10) % colors.length];

    // Step 3
    return (
        <Flex flexWrap="wrap" width="3rem" height="3rem">
            {chunked.map((ii, key) => (
                <Box
                    key={key}
                    width="50%"
                    height="50%"
                    borderTopLeftRadius={ii[0] ? '10rem' : undefined}
                    borderTopRightRadius={ii[1] ? '10rem' : undefined}
                    borderBottomRightRadius={ii[2] ? '10rem' : undefined}
                    borderBottomLeftRadius={ii[3] ? '10rem' : undefined}
                    backgroundColor={color}
                />
            ))}
        </Flex>
    );
}
Note: I'm using styled system here to generate the colors and styles. Flex and Box are just divs with some short-hands for setting styles

## Step 1 - Generate a hash from the input

The hash doesn't have to be fancy we just want to consistently convert out string into a binary number. I used this one: https://stackoverflow.com/a/8831937
We slice down to the first 16 digits as that's all we'll need for the later steps.
const decimalHash = hash(name);
const binary = parseInt(decimalHash).toString(2).slice(0, 16);
Input String
Hash
1046896622
Binary
1111100110011001

## Step 2 - Convert binary to four groups of booleans

toString(2) from the previous step gave us a binary representation of the hashed number, but we'll need to parse it back to integers before we can convert to a boolean.
Also this example uses a pretty quick and dirty chunking method. If you've got a utility library like lodash, probably just use that instead.
const booleans = binary.split('').map((ii) => Boolean(parseInt(ii, 2)));
const chunked = [...Array(4)].map(_ => list.splice(0, 4))]
Input String
Chunked
[[true,true,true,true],[true,false,false,true],[true,false,false,true],[true,false,false,true]]

## Step 3 - Use binary digits to toggle 16 borderRadius props

Now that we have 16 booleans in groups of four we can render 4 circles in a grid. Then we can use the random booleans to toggle on or off the 16 different borderRadius props.
<Flex flexWrap="wrap" width="3rem" height="3rem">
    {chunked.map((ii, key) => (
        <Box
            key={key}
            width="50%"
            height="50%"
            borderTopLeftRadius={ii[0] ? '10rem' : undefined}
            borderTopRightRadius={ii[1] ? '10rem' : undefined}
            borderBottomRightRadius={ii[2] ? '10rem' : undefined}
            borderBottomLeftRadius={ii[3] ? '10rem' : undefined}
            backgroundColor={color}
        />
    ))}
</Flex>
Input String

## Step 4 - Pick a color

The final step is to take the last digit from the original hash and use it to choose a predictable color from a list.
As there are only six colors here we can use the modulo operator to handle cases where the number is greater than that.
const colors = ['blue', 'orange', 'green', 'yellow', 'red', 'purple'];
const color = colors[parseInt(decimalHash.slice(-1), 10) % colors.length];
Input String