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
module CreditCard module_function def valid?(number)
Validating credit card numbers with Luhn
checksum
luhn-algorithm
validation
Intermediate
6 steps
ruby
namespace :counter_cache do desc "Recalculate comments_count for posts after a backfill" task warm_post_comments: :environment do scope = Post.where(comments_count: nil).or(Post.where("comments_count < 0"))
Backfilling counter caches in a Rake task in Rails
counter-cache
batching
rake-tasks
Intermediate
6 steps
ruby
class ToastBroadcaster include ActionView::RecordIdentifier def self.broadcast_to(user, message:, type: :notice)
How Turbo Stream toasts broadcast in Rails
turbo-streams
service-object
real-time
Intermediate
6 steps
ruby
class TemplateInterpolator PLACEHOLDER = /\{\{\s*([\w.]+)\s*\}\}/ def initialize(strict: false)
Interpolating templates with dotted keys in Ruby
regex
string-interpolation
hash-traversal
Intermediate
6 steps
ruby
class KeyTransformer def self.camelize(data) new.camelize(data) end
Recursively camelizing nested Ruby data
recursion
data-transformation
pattern-matching
Intermediate
7 steps
ruby
module Paginatable extend ActiveSupport::Concern private
A reusable pagination concern in Rails
pagination
concerns
http-headers
Intermediate
8 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.