How do I generate a color palette with smooth interpolation in Ruby?
Generating a palette by hand — picking each color individually — is tedious and often produces inconsistent results. Interpolating between a small set of anchor colors is faster and tends to produce more harmonious output, particularly when the interpolation happens in a perceptually uniform space. We can use Abachrome::Palette for exactly this: it holds an ordered list of colors and generates interpolated steps between them. Because blending happens in OKLCH by default, every intermediate color has consistent perceived lightness and saturation.
Basic Palette Generation
require 'abachrome'
stops = [
Abachrome.from_oklch(0.4, 0.15, 260), # dark blue
Abachrome.from_oklch(0.7, 0.18, 145), # mid green
Abachrome.from_oklch(0.9, 0.12, 80), # light yellow
]
palette = Abachrome::Palette.new(stops)
steps = palette.interpolate(steps: 11)
steps.each do |color|
puts Abachrome::Outputs::CSS.format(color.to_srgb)
end
The steps parameter controls how many colors you get back in total, including the original anchor colors. A higher number produces a finer gradient.
Outputting as CSS Custom Properties
palette = Abachrome::Palette.new([
Abachrome.from_hex('#264653'),
Abachrome.from_hex('#2a9d8f'),
Abachrome.from_hex('#e9c46a'),
Abachrome.from_hex('#f4a261'),
Abachrome.from_hex('#e76f51'),
])
ramp = palette.interpolate(steps: 9)
css = ramp.each_with_index.map do |color, i|
" --color-#{i + 1}: #{Abachrome::Outputs::CSS.format(color.to_srgb)};"
end.join("\n")
puts ":root {\n#{css}\n}"
This pattern is useful when building a design token system — you define your anchor colors, interpolate to fill the gaps, and emit them as CSS custom properties that the rest of your stylesheet can reference.
Diverging Scales for Data Visualization
A two-stop diverging palette (negative → neutral → positive) works well for heatmaps and choropleth maps:
negative = Abachrome.from_oklch(0.55, 0.22, 20) # warm red
neutral = Abachrome.from_oklch(0.92, 0.01, 0) # near-white
positive = Abachrome.from_oklch(0.55, 0.20, 250) # cool blue
scale = Abachrome::Palette.new([negative, neutral, positive])
.interpolate(steps: 11)
Keeping the lightness values similar across negative and positive anchors ensures neither end of the scale appears visually dominant — an important consideration for accessible data visualization.
Notes
- The
stepscount includes the original anchor colors; pass a higher number for finer gradients. - Always call
.to_srgbbefore formatting for CSS output — OKLCH coordinates are not valid in standard CSS without theoklch()function.