130 Widgets

Building tools. Learning to build tools. Learning to build learning tools.

3. Hashing Names to Colors

The djb2 hash algorithm, deterministic hue generation, and the HSL color space.

The Core Idea

Color Identity’s defining feature is that the same workspace name always produces the same color. Open “my-api-server” on any machine, and it gets the same hue. This is achieved through deterministic hashing: a pure function that converts a string to a number in a predictable, repeatable way.

The function needs three properties:

The djb2 Hash Algorithm

/**
 * Deterministic hash of a string → number in [0, 360).
 * Uses djb2 — simple, fast, and produces a well-distributed spread.
 */
export function hashToHue(input: string): number {
    let hash = 5381;
    for (let i = 0; i < input.length; i++) {
        hash = ((hash << 5) + hash + input.charCodeAt(i)) >>> 0;
    }
    return hash % 360;
}

djb2 is one of the most well-known string hash functions, created by Daniel J. Bernstein. Despite its simplicity, it produces an excellent distribution across output values. Let’s trace through the algorithm:

  1. Initialize with a magic number: hash = 5381. This starting value was chosen empirically by Bernstein — it produces fewer collisions than other initial values for typical input strings.
  2. For each character: hash = hash * 33 + charCode. The expression (hash << 5) + hash is a bit-manipulation trick that computes hash * 32 + hash = hash * 33 without using multiplication. Then the character’s Unicode code point is added.
  3. Keep it unsigned: >>> 0 forces the result to an unsigned 32-bit integer. Without this, JavaScript’s bitwise operators would produce signed values, and we’d get negative hashes.
  4. Map to hue range: hash % 360 reduces the 32-bit hash to a value in [0, 360), which is exactly the hue range on the color wheel.
Color Science

Why 360? Because the HSL color wheel is measured in degrees. 0° is red, 120° is green, 240° is blue, and 360° wraps back to red. By mapping the hash output to this range, we get a hue that can be plugged directly into HSL color generation.

How Well Does It Distribute?

Let’s try some common workspace names and see what hues they produce:

Workspace Name Hash Hue Color
my-project 3,218,521,047 207° blue-ish
my-project-2 1,137,454,070 170° teal
api-server 990,001,461 261° purple
frontend 4,135,098,308 308° magenta

Notice how my-project and my-project-2, which differ by only two characters, produce hues 37° apart — visually distinct. That’s the benefit of a well-distributed hash. A naive approach (like summing character codes) would produce similar values for similar strings.

Why not a cryptographic hash?

You might wonder: why not use SHA-256 or MD5? Those would work, but they’re dramatically overkill. We don’t need collision resistance or unpredictability — we just need a good spread. djb2 is a few lines of arithmetic, requires no imports, and runs in nanoseconds. A cryptographic hash would need crypto module imports for something that can be done with addition and bit shifts.

The HSL Color Space

With a hue in hand, we need a color model that lets us control vibrancy and brightness independently. That’s HSL:

The HSL Color Wheel 0°/360° Red ──── 30° Orange ──── 60° Yellow / \ 330° Rose 90° Lime | | 300° Magenta Hue = position 120° Green | Saturation = vibrancy | 270° Purple Lightness = brightness 150° Mint \ / 240° Blue ──── 210° Cyan ──── 180° Teal

The key advantage of HSL over RGB for this project:

Checkpoint

You now understand how a workspace name becomes a hue: djb2 hashes the string to a 32-bit integer, modulo 360 maps it to the color wheel. The hue is the workspace’s identity — it never changes. In the next section, we’ll see how saturation and lightness are derived from the active theme to complete the color palette.