Building tools. Learning to build tools. Learning to build learning tools.
The djb2 hash algorithm, deterministic hue generation, and the HSL color space.
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:
api-v1 and api-v2) should produce noticeably different hues./**
* 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:
hash = 5381. This starting value
was chosen empirically by Bernstein — it produces fewer collisions than other initial values
for typical input strings.
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.
>>> 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.
hash % 360 reduces the 32-bit hash to a
value in [0, 360), which is exactly the hue range on the color wheel.
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.
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.
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.
With a hue in hand, we need a color model that lets us control vibrancy and brightness independently. That’s HSL:
The key advantage of HSL over RGB for this project:
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.