Module: Unmagic::Color::Harmony
- Included in:
- Unmagic::Color
- Defined in:
- lib/unmagic/color/harmony.rb
Overview
Color harmony and variations module.
Provides methods for generating harmonious color palettes based on color theory principles. All calculations are performed in HSL color space for accurate hue-based relationships.
Included in the base Color class, making these methods available to RGB, HSL, and OKLCH color spaces via inheritance.
## Color Harmonies
Color harmonies are combinations of colors that are aesthetically pleasing based on their positions on the color wheel:
-
Complementary: Colors opposite on the wheel (180° apart)
-
Analogous: Colors adjacent on the wheel (typically 30° apart)
-
Triadic: Three colors evenly spaced (120° apart)
-
Split-complementary: Base color plus two colors adjacent to its complement
-
Tetradic: Four colors forming a rectangle or square on the wheel
## Color Variations
Create related colors by adjusting lightness or saturation:
-
Shades: Darker versions (reducing lightness)
-
Tints: Lighter versions (increasing lightness)
-
Tones: Less saturated versions (reducing saturation)
Instance Method Summary collapse
-
#analogous(angle: 30) ⇒ Array<RGB, HSL, OKLCH>
Returns two analogous colors (adjacent on the color wheel).
-
#complementary ⇒ RGB, ...
Returns the complementary color (180° opposite on the color wheel).
-
#monochromatic(steps: 5) ⇒ Array<RGB, HSL, OKLCH>
Returns an array of colors with varying lightness (same hue).
-
#shades(steps: 5, amount: 0.5) ⇒ Array<RGB, HSL, OKLCH>
Returns an array of progressively darker colors (shades).
-
#split_complementary(angle: 30) ⇒ Array<RGB, HSL, OKLCH>
Returns two split-complementary colors.
-
#tetradic_rectangle(angle: 60) ⇒ Array<RGB, HSL, OKLCH>
Returns three tetradic colors forming a rectangle on the color wheel.
-
#tetradic_square ⇒ Array<RGB, HSL, OKLCH>
Returns three tetradic colors forming a square on the color wheel.
-
#tints(steps: 5, amount: 0.5) ⇒ Array<RGB, HSL, OKLCH>
Returns an array of progressively lighter colors (tints).
-
#tones(steps: 5, amount: 0.5) ⇒ Array<RGB, HSL, OKLCH>
Returns an array of progressively desaturated colors (tones).
-
#triadic ⇒ Array<RGB, HSL, OKLCH>
Returns two triadic colors (evenly spaced 120° on the color wheel).
Instance Method Details
#analogous(angle: 30) ⇒ Array<RGB, HSL, OKLCH>
Returns two analogous colors (adjacent on the color wheel).
Analogous colors create harmonious, cohesive designs. They’re often found in nature and produce a calm, comfortable feel.
73 74 75 |
# File 'lib/unmagic/color/harmony.rb', line 73 def analogous(angle: 30) [rotate_hue(-angle), rotate_hue(angle)] end |
#complementary ⇒ RGB, ...
Returns the complementary color (180° opposite on the color wheel).
Complementary colors create high contrast and visual tension. They’re effective for creating emphasis and drawing attention.
54 55 56 |
# File 'lib/unmagic/color/harmony.rb', line 54 def complementary rotate_hue(180) end |
#monochromatic(steps: 5) ⇒ Array<RGB, HSL, OKLCH>
Returns an array of colors with varying lightness (same hue).
Creates a monochromatic palette by generating colors across a lightness range while preserving hue and saturation.
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 |
# File 'lib/unmagic/color/harmony.rb', line 150 def monochromatic(steps: 5) raise ArgumentError, "steps must be at least 1" if steps < 1 hsl = to_hsl min_lightness = 15.0 max_lightness = 85.0 step_size = (max_lightness - min_lightness) / (steps - 1).to_f (0...steps).map do |i| lightness = min_lightness + (i * step_size) result = HSL.new( hue: hsl.hue.value, saturation: hsl.saturation.value, lightness: lightness, alpha: hsl.alpha.value, ) convert_harmony_result(result) end end |
#shades(steps: 5, amount: 0.5) ⇒ Array<RGB, HSL, OKLCH>
Returns an array of progressively darker colors (shades).
Shades are created by reducing lightness, simulating the effect of adding black to the original color.
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 |
# File 'lib/unmagic/color/harmony.rb', line 183 def shades(steps: 5, amount: 0.5) raise ArgumentError, "steps must be at least 1" if steps < 1 hsl = to_hsl step_amount = amount / steps.to_f (1..steps).map do |i| new_lightness = hsl.lightness.value * (1 - (step_amount * i)) result = HSL.new( hue: hsl.hue.value, saturation: hsl.saturation.value, lightness: new_lightness.clamp(0, 100), alpha: hsl.alpha.value, ) convert_harmony_result(result) end end |
#split_complementary(angle: 30) ⇒ Array<RGB, HSL, OKLCH>
Returns two split-complementary colors.
Split-complementary uses the two colors adjacent to the complement, providing high contrast with less tension than pure complementary.
104 105 106 |
# File 'lib/unmagic/color/harmony.rb', line 104 def split_complementary(angle: 30) [rotate_hue(180 - angle), rotate_hue(180 + angle)] end |
#tetradic_rectangle(angle: 60) ⇒ Array<RGB, HSL, OKLCH>
Returns three tetradic colors forming a rectangle on the color wheel.
Rectangular tetradic uses two complementary pairs with configurable spacing. This provides flexibility between harmony and contrast.
134 135 136 |
# File 'lib/unmagic/color/harmony.rb', line 134 def tetradic_rectangle(angle: 60) [rotate_hue(angle), rotate_hue(180), rotate_hue(180 + angle)] end |
#tetradic_square ⇒ Array<RGB, HSL, OKLCH>
Returns three tetradic colors forming a square on the color wheel.
Square tetradic uses four colors evenly spaced (90° apart). This creates a rich, bold color scheme with equal visual weight.
119 120 121 |
# File 'lib/unmagic/color/harmony.rb', line 119 def tetradic_square [rotate_hue(90), rotate_hue(180), rotate_hue(270)] end |
#tints(steps: 5, amount: 0.5) ⇒ Array<RGB, HSL, OKLCH>
Returns an array of progressively lighter colors (tints).
Tints are created by increasing lightness, simulating the effect of adding white to the original color.
214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 |
# File 'lib/unmagic/color/harmony.rb', line 214 def tints(steps: 5, amount: 0.5) raise ArgumentError, "steps must be at least 1" if steps < 1 hsl = to_hsl step_amount = amount / steps.to_f (1..steps).map do |i| new_lightness = hsl.lightness.value + (100 - hsl.lightness.value) * (step_amount * i) result = HSL.new( hue: hsl.hue.value, saturation: hsl.saturation.value, lightness: new_lightness.clamp(0, 100), alpha: hsl.alpha.value, ) convert_harmony_result(result) end end |
#tones(steps: 5, amount: 0.5) ⇒ Array<RGB, HSL, OKLCH>
Returns an array of progressively desaturated colors (tones).
Tones are created by reducing saturation, simulating the effect of adding gray to the original color.
245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 |
# File 'lib/unmagic/color/harmony.rb', line 245 def tones(steps: 5, amount: 0.5) raise ArgumentError, "steps must be at least 1" if steps < 1 hsl = to_hsl step_amount = amount / steps.to_f (1..steps).map do |i| new_saturation = hsl.saturation.value * (1 - (step_amount * i)) result = HSL.new( hue: hsl.hue.value, saturation: new_saturation.clamp(0, 100), lightness: hsl.lightness.value, alpha: hsl.alpha.value, ) convert_harmony_result(result) end end |
#triadic ⇒ Array<RGB, HSL, OKLCH>
Returns two triadic colors (evenly spaced 120° on the color wheel).
Triadic colors offer strong visual contrast while retaining harmony. They tend to be vibrant even when using pale or unsaturated versions.
88 89 90 |
# File 'lib/unmagic/color/harmony.rb', line 88 def triadic [rotate_hue(120), rotate_hue(240)] end |