ruby
41 lines · 7 steps
Deriving a stable color from a username
Hash a username into a hue, then convert HSL to a hex color so each user gets a consistent, well-spread avatar color.
Explained by
highlit
1class UserColor
2 GOLDEN_RATIO_CONJUGATE = 0.618033988749895
3
4 def initialize(username)
5 @username = username.to_s
6 end
7
8 def to_hex
9 r, g, b = rgb
10 format("#%02x%02x%02x", r, g, b)
11 end
12
13 def rgb
14 hsl_to_rgb(hue, 0.5, 0.6)
15 end
16
17 private
18
19 def hue
20 digest = Digest::SHA256.hexdigest(@username).to_i(16)
21 ((digest % 360) / 360.0 + GOLDEN_RATIO_CONJUGATE) % 1.0
22 end
23
24 def hsl_to_rgb(h, s, l)
25 c = (1 - (2 * l - 1).abs) * s
26 x = c * (1 - ((h * 6) % 2 - 1).abs)
27 m = l - c / 2
28
29 r, g, b =
30 case (h * 6).floor
31 when 0 then [c, x, 0]
32 when 1 then [x, c, 0]
33 when 2 then [0, c, x]
34 when 3 then [0, x, c]
35 when 4 then [x, 0, c]
36 else [c, 0, x]
37 end
38
39 [r, g, b].map { |v| ((v + m) * 255).round.clamp(0, 255) }
40 end
41end
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1Hashing an identifier gives you a deterministic value you can map into any range you need.
- 2Nudging a hue by the golden ratio conjugate spreads sequential values across the color wheel for better visual distinction.
- 3Splitting color math into HSL selection and RGB conversion keeps the pleasing-color logic separate from the pixel format.
Related explainers
ruby
require "shellwords" require "open3" module Backup
Building safe shell commands in Ruby
shell-out
subprocess
command-injection
Intermediate
7 steps
ruby
class UserAgentParser BROWSERS = [ [/Edg\/([\d.]+)/, "Edge"], [/OPR\/([\d.]+)/, "Opera"],
Parsing user-agent strings in Ruby
regex
pattern-matching
lookup-tables
Intermediate
8 steps
ruby
class LogAggregator BUCKET_FORMAT = "%Y-%m-%dT%H:%M" def initialize(entries)
Bucketing log entries by the minute in Ruby
aggregation
hashing
enumerable
Intermediate
5 steps
ruby
class WeeklySignupsReport DEFAULT_WEEKS = 12 def initialize(weeks: DEFAULT_WEEKS, source: User.all)
Building a weekly signups report in Rails
service object
aggregation
group by
Intermediate
7 steps
ruby
class ApplicationController < ActionController::Base EXPERIMENTS = { checkout_button_color: %w[control blue green], onboarding_flow: %w[control streamlined]
How A/B test cohorts are assigned in Rails
a-b-testing
cookies
hashing
Intermediate
8 steps
ruby
class SnippetHighlighter CONTEXT_RADIUS = 60 MAX_TERMS = 8
Building search-result snippets in Ruby
regular-expressions
text-processing
search
Intermediate
9 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/deriving-a-stable-color-from-a-username-explained-ruby-0774/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.