Minecraft UUID Color: The Exact Algorithm, Worked Through
How Java Edition turns a UUID into a Locator Bar color: the UUID.hashCode() XOR, the low three bytes, the 0.9 shade — Notch derived step by step to #DC5D7F.
Last updated: 2026-07-23
The Minecraft Wiki gives the fact in one clause: in Java Edition, "the color of a waypoint is assigned to an entity based on its UUID." What it does not give is the arithmetic. This page does.
Everything below is reproducible. Take a UUID, follow five steps, and you land on the same color the 1.21.6 client draws on the Locator Bar — no lookup table, no randomness, no server involvement. It is the same computation the color finder on this site runs.
The reference case throughout is Notch's account, 069a79f4-44e9-4726-a5be-fca90e38aaf5, which resolves to #DC5D7F. That result was checked against a live client, so if your implementation produces a different value for that UUID, your implementation is wrong.
The algorithm in one block
1. Normalise the UUID to 32 hex digits.
2. msb = first 16 hex digits as a 64-bit integer
lsb = last 16 hex digits as a 64-bit integer
3. hilo = msb XOR lsb
hash = (int)(hilo >> 32) XOR (int)hilo // java.util.UUID.hashCode()
4. r = (hash >> 16) & 0xFF
g = (hash >> 8) & 0xFF
b = hash & 0xFF
5. r = floor(r * 0.9)
g = floor(g * 0.9)
b = floor(b * 0.9)
Five steps, no state. The rest of this page is why each one is there.
Step 1: normalise the UUID
Hyphens are punctuation, not data. Case is not data either — hexadecimal A and a are the same nibble. So 069A79F444E94726A5BEFCA90E38AAF5 and 069a79f4-44e9-4726-a5be-fca90e38aaf5 are the same 128-bit value and must produce the same color. Strip the hyphens, lowercase the digits, and check you have exactly 32 of them. Anything else is not a UUID and there is nothing to compute.
Step 2: split into two 64-bit halves
Java stores a UUID as two long fields, mostSigBits and leastSigBits. The first 16 hex digits are the most significant half, the last 16 are the least significant half.
For Notch:
msb = 0x069A79F444E94726
lsb = 0xA5BEFCA90E38AAF5
The split point is exactly halfway through the string, at the boundary that in hyphenated form sits in the middle of the third and fourth groups. Do not try to split on hyphens.
Step 3: fold 128 bits into 32 — UUID.hashCode()
This is the load-bearing step, and it is not a Minecraft invention at all. It is the JDK's own hash function for java.util.UUID:
public int hashCode() {
long hilo = mostSigBits ^ leastSigBits;
return ((int)(hilo >> 32)) ^ (int) hilo;
}
Two XORs. First the two 64-bit halves are XORed together into one 64-bit value; then that value's own top and bottom 32-bit halves are XORed together, producing a signed 32-bit integer.
For Notch, XOR the halves:
0x069A79F444E94726
^ 0xA5BEFCA90E38AAF5
= 0xA324855D4AD1EDD3
Then fold that 64-bit result in half:
0xA324855D (the high 32 bits, hilo >> 32)
^ 0x4AD1EDD3 (the low 32 bits, (int)hilo)
= 0xE9F5688E
0xE9F5688E as a signed 32-bit integer is -369792882. Signedness does not affect the outcome, because the next step only reads individual bytes, but it matters if you are comparing against a Java debugger's output — Java will print the negative number.
Two things to be careful about when porting this:
Use 64-bit arithmetic that does not lose precision. JavaScript numbers cannot hold 64 bits of integer exactly, so a naive port silently corrupts the XOR. Use BigInt for step 3, then narrow to 32 bits. Python integers are arbitrary precision and fine, but you must mask with & 0xFFFFFFFF yourself because Python has no 32-bit wraparound.
>> in Java is an arithmetic shift. Here it does not matter, because the result is immediately truncated to 32 bits by the (int) cast, but if you rearrange the expression it can start to matter.
Step 4: take the low three bytes as RGB
The 32-bit hash is treated as a packed color, exactly the way Minecraft packs colors everywhere else: 0xAARRGGBB with the top byte ignored.
For Notch, 0xE9F5688E:
0xE9 discarded
0xF5 -> red = 245
0x68 -> green = 104
0x8E -> blue = 142
The top byte, 0xE9, is thrown away. That is worth noticing, because it means the algorithm only uses 24 of the 32 hash bits — the color space is 2^24 = 16,777,216 values, not 2^32.
At this point the unshaded color is #F5688E. That is not what you see in game. One step remains.
Step 5: shade every channel to 90%
The client multiplies each channel by 0.9 and truncates:
red = floor(245 * 0.9) = floor(220.5) = 220 = 0xDC
green = floor(104 * 0.9) = floor( 93.6) = 93 = 0x5D
blue = floor(142 * 0.9) = floor(127.8) = 127 = 0x7F
Final color: #DC5D7F, or rgb(220, 93, 127) — a dusty rose.
Skip this step and you get #F5688E, which is noticeably brighter and pinker. This is the single most common reason a home-made calculator disagrees with the game: the hash is right, the bytes are right, the shading is missing.
Be honest about the status of that 0.9: it is an empirical finding, not something Mojang documents. It was derived by comparing computed values against colors the 1.21.6 client actually renders, and Notch's UUID landing exactly on #DC5D7F is the check that it is correct. Mojang has published no specification of this pipeline at all. If a future version changes the shading, this page changes with it.
The full derivation on one screen
UUID 069a79f4-44e9-4726-a5be-fca90e38aaf5
msb 0x069A79F444E94726
lsb 0xA5BEFCA90E38AAF5
hilo 0xA324855D4AD1EDD3 (msb XOR lsb)
hi/lo 0xA324855D XOR 0x4AD1EDD3
hash 0xE9F5688E (-369792882 signed)
bytes E9 | F5 68 8E (top byte discarded)
raw rgb(245, 104, 142) #F5688E
shade x0.9, floored
final rgb(220, 93, 127) #DC5D7F
Reference implementations
JavaScript, using BigInt so the 64-bit XOR is exact:
function locatorColor(uuid) {
const hex = uuid.replace(/-/g, '').toLowerCase();
const msb = BigInt('0x' + hex.slice(0, 16));
const lsb = BigInt('0x' + hex.slice(16, 32));
const hilo = msb ^ lsb;
const hi = Number((hilo >> 32n) & 0xffffffffn);
const lo = Number(hilo & 0xffffffffn);
const hash = (hi ^ lo) >>> 0;
const shade = (c) => Math.floor(c * 0.9);
return {
r: shade((hash >> 16) & 0xff),
g: shade((hash >> 8) & 0xff),
b: shade(hash & 0xff),
};
}
Java, where the hash is already built in:
int hash = uuid.hashCode();
int r = (int) (((hash >> 16) & 0xFF) * 0.9);
int g = (int) (((hash >> 8) & 0xFF) * 0.9);
int b = (int) (( hash & 0xFF) * 0.9);
Python, masking manually because there is no 32-bit int:
def locator_color(uuid_str):
h = int(uuid_str.replace("-", ""), 16)
msb, lsb = h >> 64, h & ((1 << 64) - 1)
hilo = msb ^ lsb
hash_ = ((hilo >> 32) ^ hilo) & 0xFFFFFFFF
ch = lambda s: int(((hash_ >> s) & 0xFF) * 0.9)
return ch(16), ch(8), ch(0)
More worked examples
These are computed with the algorithm above from UUIDs confirmed live against Mojang's profile API. Unlike Notch's, they have not each been checked against a running client — the algorithm has, once, and it is deterministic, but that is the honest provenance.
- jeb_ —
853c80ef-3c37-49fd-aa49-938b674adae6, hash0x7408807F, raw#08807F, final#077372/rgb(7, 115, 114). A dark teal. - Dinnerbone —
61699b2e-d327-4a01-9f1e-0ea8c3f06bc6, hash0xEEA0B441, raw#A0B441, final#90A23A/rgb(144, 162, 58). An olive green. - Grumm —
e6b5c088-0680-44df-9e1b-9bf11792291b, hash0x69BC36BD, raw#BC36BD, final#A930AA/rgb(169, 48, 170). A strong magenta.
Notice how unrelated the colors are. Two UUIDs that differ in one bit produce completely different results, because XOR-folding propagates that bit into the low bytes. There is no "family" of colors for similar names, and no way to nudge a UUID toward a nicer color.
What the color does and does not depend on
It depends on: the 128 bits of the UUID. That is the entire input.
It does not depend on: your username, your skin, your cape, the server you are on, the world seed, the time of day, how many players are online, or your position. Change none of those and the color is the same; change all of them and the color is still the same.
Because usernames on an online-mode server do not affect the UUID, renaming does not change your Locator Bar color. On an offline-mode server the opposite is true — the UUID is derived from the name by MD5, so renaming there gives you a completely new UUID and therefore a completely new color. The mechanics of that split are covered in what a Minecraft UUID is.
Two things do override the UUID-derived default, and neither replaces the algorithm — they sit on top of it:
- Team color. If the entity belongs to a scoreboard team with a color, the waypoint takes the team color instead.
- The
/waypointcommand. An explicitcolororcolor hexoverrides everything until it is reset. Details on Locator Bar colors, and the command generator will write the line for you.
/waypoint modify <target> color reset drops back to the default — which for a player means back to the UUID-derived color computed above.
Why mob colors look random but player colors do not
The Minecraft Wiki's /waypoint page describes the default color as "chosen randomly by the game," while the Locator Bar page says it is "assigned to an entity based on its UUID." Both are right, and the apparent contradiction is informative.
Every entity has a UUID, not just players. A mob's UUID is generated fresh when it spawns, so its Locator Bar color is effectively a random draw and will be different next time you spawn one. A player's UUID was minted once, at account registration, and never changes — so the same deterministic function produces the same color forever. Same algorithm, different input stability.
Collisions: how likely is a clash?
The color space is 24 bits, 16,777,216 values, but the 0.9 shading collapses it slightly: floor(v * 0.9) maps 256 input values onto 230 outputs per channel, so roughly 12.2 million distinct colors are actually reachable.
Exact collisions are therefore rare. On a 100-player server, the probability that any two players share a byte-identical color is about 0.04%.
Visual collisions are a different story, and far more common. Two colors do not need to be identical to be indistinguishable as 8-pixel dots on a HUD during a fight. Using a redmean perceptual distance with a "hard to tell apart" threshold of 90, a Monte Carlo run over 2,000,000 random pairs from the reachable color space puts the chance that any given pair is confusable at about 3.8%. Compounded over a group:
- 4 players: roughly 21% chance at least one pair is hard to distinguish
- 6 players: roughly 44%
- 8 players: roughly 66%
- 10 players: roughly 83%
- 16 players: roughly 99%
These are our own simulation figures, not Mojang's, and the threshold is a judgement call — but the shape of the result is not in doubt. Past about six people, expecting the defaults to stay legible is optimistic. The color checker runs this comparison on a real party list and flags the pairs, and the generator writes the /waypoint commands to separate them.
Where the numbers came from
- The hash is
java.util.UUID.hashCode(), quoted from the JDK source and documented by Oracle. - The claim that Java Edition derives waypoint color from UUID is from the Minecraft Wiki's Locator Bar page.
- The byte extraction and the 0.9 shading factor are empirical: reverse-engineered from what the 1.21.6 client draws, and verified against Notch's UUID producing
#DC5D7F. Mojang has published no specification of this pipeline, and this page does not pretend otherwise. - The Bedrock caveat is from the same Wiki page: there, "the color is randomly assigned to the player at every session," so none of this applies.