tincture 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e3102199850ecef6f4276a6316c9766db75a90aa362db1b3bb06bcd8e476ec40
4
- data.tar.gz: 149c2ce8a9cdfa7a3c35a223d7bcc9404b38711aa1bc4f8205617d6e71106466
3
+ metadata.gz: 582ad42336a7e115f7ae13229231c0adb6e107d0ba1fcf2c4ebf118a9060d87a
4
+ data.tar.gz: 11697f93d17a93794af08edbdaa7d47bbc93cb2385ffccc9216b1c3596776d5d
5
5
  SHA512:
6
- metadata.gz: 31cf7ada2b2bae78a4bb0d6052fc2efcf438c3e21c4f885e5e237c3cec8327cce22174e49b9c42fa87b7861cac7b79f084e15dd6fb07449996d759ac3336af96
7
- data.tar.gz: 0726bfdc5a709161d2b6adb92749a9e69d7acebb38cd9a916e75d20392d05500cc6c455d1f5651042fa166b456dcd1430f1e3e10ea6e3cde1d7fb9679a104fd4
6
+ metadata.gz: 17b562aac3e4ce4bacd5a21285d66cc6e62d461cbbb1f3ab5d5bdd846cc613c30284402b754a9b0a0d7b6aa9d72f1fec178ed47f657898fef8069f3beace291e
7
+ data.tar.gz: 155f3cf6e300659f61f3a2ed6f2c395eb68f13f2f95432fe93d368029c32b6b463dde1c8be775a89f9ae3f4c0e6a71958a7d263e3e8715e936fbc903a9e826ac
data/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.1.0 (2026-10-21)
4
+
5
+ - Performance: `require "tincture"` is about 5 times faster, 10 ms down to 2 ms. Named colours now live in a Ruby hash, so loading the gem no longer loads YAML.
6
+ - Performance: `luminance`, `contrast_ratio`, `contrast_color` and `difference` are 15–50% faster. They look up each channel's linear value in a table and no longer compute a power. Results are unchanged.
7
+ - Performance: parsing a hex colour is about 30% faster, and `hex` (so also `to_s`, `as_json` and saving a `:color` attribute) is about twice as fast.
8
+ - Performance: `nearest_readable_on` is about 6 times faster, 224 µs down to 37 µs. It converts the colour and black or white to Oklab once per search, not on every step, and it searches 2¹⁶ steps toward black or white rather than every float. About 0.4% of results now land one 8-bit step further from the original colour. They still pass.
9
+
3
10
  ## 1.0.0 (2026-10-21)
4
11
 
5
12
  - `Tincture::Color` parses CSS hex, named, `rgb()`, `hsl()`, `hwb()`, `oklab()` and `oklch()` colours, and converts between them and HSV.
data/README.md CHANGED
@@ -169,6 +169,6 @@ bundle exec rake # tests and RuboCop
169
169
  bundle exec rake rdoc # API docs in doc/
170
170
  ```
171
171
 
172
- To release, set the version in `lib/tincture/version.rb`, date the changelog entry, commit, and push a `vX.Y.Z` tag. GitHub Actions runs the checks and publishes the gem to rubygems.org through trusted publishing.
172
+ To release, set the version in `lib/tincture/version.rb`, date the changelog entry, commit, and push a `vX.Y.Z` tag. GitHub Actions runs the checks, publishes the gem to rubygems.org through trusted publishing, and creates a GitHub release with that changelog entry as its notes.
173
173
 
174
174
  Comments are Markdown. Method types are inline RBS (`#: (String) -> Color`), which RDoc shows on each method.
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Tincture
4
- class Color
4
+ class Color # rubocop:disable Style/Documentation
5
5
  # How different two colours look. The formulas live in
6
6
  # Tincture::Difference. Mixed into Color.
7
7
  module Comparison
@@ -28,7 +28,7 @@ module Tincture
28
28
  protected
29
29
 
30
30
  # CIELAB against the D65 white point, as sRGB tools usually report it.
31
- def lab_components # :nodoc:
31
+ def lab_components # :nodoc: # rubocop:disable Metrics/AbcSize
32
32
  red, green, blue = linear_rgb
33
33
 
34
34
  x, y, z = [
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Tincture
4
- class Color
4
+ class Color # rubocop:disable Style/Documentation
5
5
  # WCAG 2 minimum contrast ratios.
6
6
  WCAG_RATIOS = { aa: { normal: 4.5, large: 3.0 }, aaa: { normal: 7.0, large: 4.5 } }.freeze
7
7
 
@@ -18,6 +18,8 @@ module Tincture
18
18
  # WCAG 2 contrast, and picking text colours that read on a background.
19
19
  # Mixed into Color.
20
20
  module Contrast
21
+ MIX_STEPS = 2**16 # :nodoc:
22
+
21
23
  # Added to Color itself.
22
24
  module ClassMethods
23
25
  # Scores for #contrast_color methods other than `:oklab`, keyed by
@@ -138,8 +140,11 @@ module Tincture
138
140
  # The smallest mix toward `extreme` that passes the block. Assumes the
139
141
  # block fails here and passes at `extreme`.
140
142
  def nearest_mix_toward(extreme)
141
- amount = (0.0..1.0).bsearch { |candidate| yield mixed_toward(extreme, candidate) }
142
- mixed_toward(extreme, amount)
143
+ start = oklab_components
144
+ finish = extreme.oklab_components
145
+
146
+ step = (0..MIX_STEPS).bsearch { |candidate| yield mixed_oklab(start, finish, candidate.fdiv(MIX_STEPS)) }
147
+ mixed_oklab(start, finish, step.fdiv(MIX_STEPS))
143
148
  end
144
149
 
145
150
  def contrast_scorer(method)
@@ -150,7 +155,7 @@ module Tincture
150
155
  end
151
156
 
152
157
  def oklab_contrast_color(candidates)
153
- if candidates.sort_by(&:luminance) == [BLACK, WHITE]
158
+ if candidates.sort_by(&:luminance) == [BLACK, WHITE] # rubocop:disable Style/GuardClause
154
159
  oklab_components.first > OKLAB_CONTRAST_THRESHOLD ? BLACK : WHITE
155
160
  else
156
161
  raise ArgumentError, 'method: :oklab picks between black and white only'
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Tincture
4
- class Color
4
+ class Color # rubocop:disable Style/Documentation
5
5
  # HSL and its relatives HWB and HSV, which share its hue angle. Mixed into
6
6
  # Color.
7
7
  module Hsl
@@ -21,7 +21,7 @@ module Tincture
21
21
  # give a grey.
22
22
  #
23
23
  #: (Numeric hue, Numeric whiteness, Numeric blackness, ?Numeric alpha) -> Color
24
- def hwb(hue, whiteness, blackness, alpha = 1.0)
24
+ def hwb(hue, whiteness, blackness, alpha = 1.0) # rubocop:disable Metrics/AbcSize
25
25
  whiteness = whiteness.clamp(0, 100) / 100.0
26
26
  blackness = blackness.clamp(0, 100) / 100.0
27
27
 
@@ -101,7 +101,7 @@ module Tincture
101
101
 
102
102
  private
103
103
 
104
- def hue
104
+ def hue # rubocop:disable Metrics/AbcSize
105
105
  red, green, blue = channel_fractions
106
106
  max, min = channel_fractions.minmax.reverse
107
107
  delta = max - min
@@ -0,0 +1,159 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Tincture
4
+ class Color # rubocop:disable Metrics/ClassLength
5
+ # CSS named colours, keyed by lowercase name, from
6
+ # [CSS Color 4](https://www.w3.org/TR/css-color-4/#named-colors).
7
+ NAMED = {
8
+ 'aliceblue' => '#f0f8ff',
9
+ 'antiquewhite' => '#faebd7',
10
+ 'aqua' => '#00ffff',
11
+ 'aquamarine' => '#7fffd4',
12
+ 'azure' => '#f0ffff',
13
+ 'beige' => '#f5f5dc',
14
+ 'bisque' => '#ffe4c4',
15
+ 'black' => '#000000',
16
+ 'blanchedalmond' => '#ffebcd',
17
+ 'blue' => '#0000ff',
18
+ 'blueviolet' => '#8a2be2',
19
+ 'brown' => '#a52a2a',
20
+ 'burlywood' => '#deb887',
21
+ 'cadetblue' => '#5f9ea0',
22
+ 'chartreuse' => '#7fff00',
23
+ 'chocolate' => '#d2691e',
24
+ 'coral' => '#ff7f50',
25
+ 'cornflowerblue' => '#6495ed',
26
+ 'cornsilk' => '#fff8dc',
27
+ 'crimson' => '#dc143c',
28
+ 'cyan' => '#00ffff',
29
+ 'darkblue' => '#00008b',
30
+ 'darkcyan' => '#008b8b',
31
+ 'darkgoldenrod' => '#b8860b',
32
+ 'darkgray' => '#a9a9a9',
33
+ 'darkgreen' => '#006400',
34
+ 'darkgrey' => '#a9a9a9',
35
+ 'darkkhaki' => '#bdb76b',
36
+ 'darkmagenta' => '#8b008b',
37
+ 'darkolivegreen' => '#556b2f',
38
+ 'darkorange' => '#ff8c00',
39
+ 'darkorchid' => '#9932cc',
40
+ 'darkred' => '#8b0000',
41
+ 'darksalmon' => '#e9967a',
42
+ 'darkseagreen' => '#8fbc8f',
43
+ 'darkslateblue' => '#483d8b',
44
+ 'darkslategray' => '#2f4f4f',
45
+ 'darkslategrey' => '#2f4f4f',
46
+ 'darkturquoise' => '#00ced1',
47
+ 'darkviolet' => '#9400d3',
48
+ 'deeppink' => '#ff1493',
49
+ 'deepskyblue' => '#00bfff',
50
+ 'dimgray' => '#696969',
51
+ 'dimgrey' => '#696969',
52
+ 'dodgerblue' => '#1e90ff',
53
+ 'firebrick' => '#b22222',
54
+ 'floralwhite' => '#fffaf0',
55
+ 'forestgreen' => '#228b22',
56
+ 'fuchsia' => '#ff00ff',
57
+ 'gainsboro' => '#dcdcdc',
58
+ 'ghostwhite' => '#f8f8ff',
59
+ 'gold' => '#ffd700',
60
+ 'goldenrod' => '#daa520',
61
+ 'gray' => '#808080',
62
+ 'green' => '#008000',
63
+ 'greenyellow' => '#adff2f',
64
+ 'grey' => '#808080',
65
+ 'honeydew' => '#f0fff0',
66
+ 'hotpink' => '#ff69b4',
67
+ 'indianred' => '#cd5c5c',
68
+ 'indigo' => '#4b0082',
69
+ 'ivory' => '#fffff0',
70
+ 'khaki' => '#f0e68c',
71
+ 'lavender' => '#e6e6fa',
72
+ 'lavenderblush' => '#fff0f5',
73
+ 'lawngreen' => '#7cfc00',
74
+ 'lemonchiffon' => '#fffacd',
75
+ 'lightblue' => '#add8e6',
76
+ 'lightcoral' => '#f08080',
77
+ 'lightcyan' => '#e0ffff',
78
+ 'lightgoldenrodyellow' => '#fafad2',
79
+ 'lightgray' => '#d3d3d3',
80
+ 'lightgreen' => '#90ee90',
81
+ 'lightgrey' => '#d3d3d3',
82
+ 'lightpink' => '#ffb6c1',
83
+ 'lightsalmon' => '#ffa07a',
84
+ 'lightseagreen' => '#20b2aa',
85
+ 'lightskyblue' => '#87cefa',
86
+ 'lightslategray' => '#778899',
87
+ 'lightslategrey' => '#778899',
88
+ 'lightsteelblue' => '#b0c4de',
89
+ 'lightyellow' => '#ffffe0',
90
+ 'lime' => '#00ff00',
91
+ 'limegreen' => '#32cd32',
92
+ 'linen' => '#faf0e6',
93
+ 'magenta' => '#ff00ff',
94
+ 'maroon' => '#800000',
95
+ 'mediumaquamarine' => '#66cdaa',
96
+ 'mediumblue' => '#0000cd',
97
+ 'mediumorchid' => '#ba55d3',
98
+ 'mediumpurple' => '#9370db',
99
+ 'mediumseagreen' => '#3cb371',
100
+ 'mediumslateblue' => '#7b68ee',
101
+ 'mediumspringgreen' => '#00fa9a',
102
+ 'mediumturquoise' => '#48d1cc',
103
+ 'mediumvioletred' => '#c71585',
104
+ 'midnightblue' => '#191970',
105
+ 'mintcream' => '#f5fffa',
106
+ 'mistyrose' => '#ffe4e1',
107
+ 'moccasin' => '#ffe4b5',
108
+ 'navajowhite' => '#ffdead',
109
+ 'navy' => '#000080',
110
+ 'oldlace' => '#fdf5e6',
111
+ 'olive' => '#808000',
112
+ 'olivedrab' => '#6b8e23',
113
+ 'orange' => '#ffa500',
114
+ 'orangered' => '#ff4500',
115
+ 'orchid' => '#da70d6',
116
+ 'palegoldenrod' => '#eee8aa',
117
+ 'palegreen' => '#98fb98',
118
+ 'paleturquoise' => '#afeeee',
119
+ 'palevioletred' => '#db7093',
120
+ 'papayawhip' => '#ffefd5',
121
+ 'peachpuff' => '#ffdab9',
122
+ 'peru' => '#cd853f',
123
+ 'pink' => '#ffc0cb',
124
+ 'plum' => '#dda0dd',
125
+ 'powderblue' => '#b0e0e6',
126
+ 'purple' => '#800080',
127
+ 'rebeccapurple' => '#663399',
128
+ 'red' => '#ff0000',
129
+ 'rosybrown' => '#bc8f8f',
130
+ 'royalblue' => '#4169e1',
131
+ 'saddlebrown' => '#8b4513',
132
+ 'salmon' => '#fa8072',
133
+ 'sandybrown' => '#f4a460',
134
+ 'seagreen' => '#2e8b57',
135
+ 'seashell' => '#fff5ee',
136
+ 'sienna' => '#a0522d',
137
+ 'silver' => '#c0c0c0',
138
+ 'skyblue' => '#87ceeb',
139
+ 'slateblue' => '#6a5acd',
140
+ 'slategray' => '#708090',
141
+ 'slategrey' => '#708090',
142
+ 'snow' => '#fffafa',
143
+ 'springgreen' => '#00ff7f',
144
+ 'steelblue' => '#4682b4',
145
+ 'tan' => '#d2b48c',
146
+ 'teal' => '#008080',
147
+ 'thistle' => '#d8bfd8',
148
+ 'tomato' => '#ff6347',
149
+ 'transparent' => '#00000000',
150
+ 'turquoise' => '#40e0d0',
151
+ 'violet' => '#ee82ee',
152
+ 'wheat' => '#f5deb3',
153
+ 'white' => '#ffffff',
154
+ 'whitesmoke' => '#f5f5f5',
155
+ 'yellow' => '#ffff00',
156
+ 'yellowgreen' => '#9acd32'
157
+ }.transform_values { parse(it) }.freeze
158
+ end
159
+ end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Tincture
4
- class Color
4
+ class Color # rubocop:disable Style/Documentation
5
5
  # Oklab and its cylindrical form Oklch, where equal steps look equally
6
6
  # different. Mixed into Color.
7
7
  module Oklab
@@ -11,7 +11,7 @@ module Tincture
11
11
  # and `b` (blue–yellow) axes.
12
12
  #
13
13
  #: (Numeric lightness, Numeric green_red, Numeric blue_yellow, ?Numeric alpha) -> Color
14
- def oklab(lightness, green_red, blue_yellow, alpha = 1.0)
14
+ def oklab(lightness, green_red, blue_yellow, alpha = 1.0) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
15
15
  lightness = lightness.clamp(0, 1)
16
16
 
17
17
  l, m, s = [
@@ -77,7 +77,7 @@ module Tincture
77
77
 
78
78
  protected
79
79
 
80
- def oklab_components # :nodoc:
80
+ def oklab_components # :nodoc: # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
81
81
  red, green, blue = linear_rgb
82
82
 
83
83
  l, m, s = [
@@ -95,10 +95,8 @@ module Tincture
95
95
 
96
96
  private
97
97
 
98
- def mixed_toward(other, amount)
99
- lightness, a, b = oklab_components.zip(other.oklab_components).map do |mine, theirs|
100
- mine + ((theirs - mine) * amount)
101
- end
98
+ def mixed_oklab(start, finish, amount)
99
+ lightness, a, b = start.zip(finish).map { |mine, theirs| mine + ((theirs - mine) * amount) }
102
100
  Color.oklab(lightness, a, b, alpha)
103
101
  end
104
102
  end
@@ -1,9 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'yaml'
4
-
5
3
  module Tincture
6
- class Color
4
+ class Color # rubocop:disable Style/Documentation
7
5
  # Reads CSS colour strings: hex, named colours and the `rgb()`, `hsl()`,
8
6
  # `hwb()`, `oklab()` and `oklch()` functions. Extends Color, so its
9
7
  # methods are called on the class: `Tincture::Color.parse`.
@@ -83,7 +81,7 @@ module Tincture
83
81
  return unless digits
84
82
 
85
83
  digits = digits.chars.map { it * 2 }.join if digits.length <= 4
86
- red, green, blue, alpha = digits.scan(/../).map(&:hex)
84
+ red, green, blue, alpha = [digits].pack('H*').bytes
87
85
  rgb(red, green, blue, (alpha || 255) / 255.0)
88
86
  end
89
87
 
@@ -137,8 +135,5 @@ module Tincture
137
135
  end
138
136
 
139
137
  extend Parsing
140
-
141
- # CSS named colours, keyed by lowercase name.
142
- NAMED = YAML.load_file(File.expand_path('../named_colors.yml', __dir__)).transform_values { parse(it) }.freeze
143
138
  end
144
139
  end
@@ -23,6 +23,11 @@ module Tincture
23
23
  # Conversions follow [CSS Color 4](https://www.w3.org/TR/css-color-4/) and
24
24
  # [Oklab](https://bottosson.github.io/posts/oklab/).
25
25
  class Color < Data.define(:red, :green, :blue, :alpha)
26
+ LINEAR_CHANNELS = Array.new(256) do |byte| # :nodoc:
27
+ fraction = byte / 255.0
28
+ fraction <= 0.04045 ? fraction / 12.92 : ((fraction + 0.055) / 1.055)**2.4
29
+ end.freeze
30
+
26
31
  # Builds a colour from 0–255 channels and a 0–1 alpha. Out-of-range
27
32
  # values clamp, as they do in CSS.
28
33
  #
@@ -37,7 +42,7 @@ module Tincture
37
42
  #: () -> String
38
43
  def hex
39
44
  bytes = opaque? ? rgb : [*rgb, alpha_byte]
40
- "##{bytes.map { format('%02x', it) }.join}"
45
+ "##{bytes.pack('C*').unpack1('H*')}"
41
46
  end
42
47
 
43
48
  alias to_s hex
@@ -68,9 +73,7 @@ module Tincture
68
73
 
69
74
  def channel_fractions = rgb.map { it / 255.0 }
70
75
 
71
- def linear_rgb
72
- channel_fractions.map { it <= 0.04045 ? it / 12.92 : ((it + 0.055) / 1.055)**2.4 }
73
- end
76
+ def linear_rgb = rgb.map { LINEAR_CHANNELS[it] }
74
77
 
75
78
  # Adding 0.0 turns -0.0 into 0.0, so CSS never shows "-0".
76
79
  def rounded(number, digits) = number.round(digits) + 0.0
@@ -14,7 +14,7 @@ module ActiveModel # :nodoc:
14
14
  MESSAGE = 'is not a valid color'
15
15
 
16
16
  def validate_each(record, attribute, value) # :nodoc:
17
- if value.nil? && record.read_attribute_before_type_cast(attribute).present?
17
+ if value.nil? && record.read_attribute_before_type_cast(attribute).present? # rubocop:disable Style/GuardClause
18
18
  record.errors.add(attribute, :invalid_color, message: options.fetch(:message, self.class::MESSAGE))
19
19
  end
20
20
  end
@@ -21,7 +21,7 @@ module Tincture
21
21
  # with the weighting factors kL, kC and kH all 1.
22
22
  #
23
23
  #: ([Float, Float, Float] first, [Float, Float, Float] second) -> Float
24
- def ciede2000(first, second)
24
+ def ciede2000(first, second) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
25
25
  (l1, a1, b1), (l2, a2, b2) = first, second
26
26
 
27
27
  chroma_mean = (Math.hypot(a1, b1) + Math.hypot(a2, b2)) / 2
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Tincture
4
- VERSION = '1.0.0' # :nodoc:
4
+ VERSION = '1.1.0' # :nodoc:
5
5
  end
data/lib/tincture.rb CHANGED
@@ -4,6 +4,7 @@ require_relative 'tincture/version'
4
4
  require_relative 'tincture/difference'
5
5
  require_relative 'tincture/color'
6
6
  require_relative 'tincture/color/parsing'
7
+ require_relative 'tincture/color/named_colors'
7
8
  require_relative 'tincture/color/hsl'
8
9
  require_relative 'tincture/color/oklab'
9
10
  require_relative 'tincture/color/contrast'
@@ -25,4 +26,6 @@ module Tincture
25
26
  InvalidColour = InvalidColor
26
27
  end
27
28
 
29
+ # :nocov:
28
30
  require_relative 'tincture/railtie' if defined?(Rails::Railtie)
31
+ # :nocov:
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tincture
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andy Croll
@@ -26,11 +26,11 @@ files:
26
26
  - lib/tincture/color/comparison.rb
27
27
  - lib/tincture/color/contrast.rb
28
28
  - lib/tincture/color/hsl.rb
29
+ - lib/tincture/color/named_colors.rb
29
30
  - lib/tincture/color/oklab.rb
30
31
  - lib/tincture/color/parsing.rb
31
32
  - lib/tincture/color_validator.rb
32
33
  - lib/tincture/difference.rb
33
- - lib/tincture/named_colors.yml
34
34
  - lib/tincture/railtie.rb
35
35
  - lib/tincture/type.rb
36
36
  - lib/tincture/version.rb
@@ -1,150 +0,0 @@
1
- # CSS Color 4 named colors: https://www.w3.org/TR/css-color-4/#named-colors
2
- aliceblue: "#f0f8ff"
3
- antiquewhite: "#faebd7"
4
- aqua: "#00ffff"
5
- aquamarine: "#7fffd4"
6
- azure: "#f0ffff"
7
- beige: "#f5f5dc"
8
- bisque: "#ffe4c4"
9
- black: "#000000"
10
- blanchedalmond: "#ffebcd"
11
- blue: "#0000ff"
12
- blueviolet: "#8a2be2"
13
- brown: "#a52a2a"
14
- burlywood: "#deb887"
15
- cadetblue: "#5f9ea0"
16
- chartreuse: "#7fff00"
17
- chocolate: "#d2691e"
18
- coral: "#ff7f50"
19
- cornflowerblue: "#6495ed"
20
- cornsilk: "#fff8dc"
21
- crimson: "#dc143c"
22
- cyan: "#00ffff"
23
- darkblue: "#00008b"
24
- darkcyan: "#008b8b"
25
- darkgoldenrod: "#b8860b"
26
- darkgray: "#a9a9a9"
27
- darkgreen: "#006400"
28
- darkgrey: "#a9a9a9"
29
- darkkhaki: "#bdb76b"
30
- darkmagenta: "#8b008b"
31
- darkolivegreen: "#556b2f"
32
- darkorange: "#ff8c00"
33
- darkorchid: "#9932cc"
34
- darkred: "#8b0000"
35
- darksalmon: "#e9967a"
36
- darkseagreen: "#8fbc8f"
37
- darkslateblue: "#483d8b"
38
- darkslategray: "#2f4f4f"
39
- darkslategrey: "#2f4f4f"
40
- darkturquoise: "#00ced1"
41
- darkviolet: "#9400d3"
42
- deeppink: "#ff1493"
43
- deepskyblue: "#00bfff"
44
- dimgray: "#696969"
45
- dimgrey: "#696969"
46
- dodgerblue: "#1e90ff"
47
- firebrick: "#b22222"
48
- floralwhite: "#fffaf0"
49
- forestgreen: "#228b22"
50
- fuchsia: "#ff00ff"
51
- gainsboro: "#dcdcdc"
52
- ghostwhite: "#f8f8ff"
53
- gold: "#ffd700"
54
- goldenrod: "#daa520"
55
- gray: "#808080"
56
- green: "#008000"
57
- greenyellow: "#adff2f"
58
- grey: "#808080"
59
- honeydew: "#f0fff0"
60
- hotpink: "#ff69b4"
61
- indianred: "#cd5c5c"
62
- indigo: "#4b0082"
63
- ivory: "#fffff0"
64
- khaki: "#f0e68c"
65
- lavender: "#e6e6fa"
66
- lavenderblush: "#fff0f5"
67
- lawngreen: "#7cfc00"
68
- lemonchiffon: "#fffacd"
69
- lightblue: "#add8e6"
70
- lightcoral: "#f08080"
71
- lightcyan: "#e0ffff"
72
- lightgoldenrodyellow: "#fafad2"
73
- lightgray: "#d3d3d3"
74
- lightgreen: "#90ee90"
75
- lightgrey: "#d3d3d3"
76
- lightpink: "#ffb6c1"
77
- lightsalmon: "#ffa07a"
78
- lightseagreen: "#20b2aa"
79
- lightskyblue: "#87cefa"
80
- lightslategray: "#778899"
81
- lightslategrey: "#778899"
82
- lightsteelblue: "#b0c4de"
83
- lightyellow: "#ffffe0"
84
- lime: "#00ff00"
85
- limegreen: "#32cd32"
86
- linen: "#faf0e6"
87
- magenta: "#ff00ff"
88
- maroon: "#800000"
89
- mediumaquamarine: "#66cdaa"
90
- mediumblue: "#0000cd"
91
- mediumorchid: "#ba55d3"
92
- mediumpurple: "#9370db"
93
- mediumseagreen: "#3cb371"
94
- mediumslateblue: "#7b68ee"
95
- mediumspringgreen: "#00fa9a"
96
- mediumturquoise: "#48d1cc"
97
- mediumvioletred: "#c71585"
98
- midnightblue: "#191970"
99
- mintcream: "#f5fffa"
100
- mistyrose: "#ffe4e1"
101
- moccasin: "#ffe4b5"
102
- navajowhite: "#ffdead"
103
- navy: "#000080"
104
- oldlace: "#fdf5e6"
105
- olive: "#808000"
106
- olivedrab: "#6b8e23"
107
- orange: "#ffa500"
108
- orangered: "#ff4500"
109
- orchid: "#da70d6"
110
- palegoldenrod: "#eee8aa"
111
- palegreen: "#98fb98"
112
- paleturquoise: "#afeeee"
113
- palevioletred: "#db7093"
114
- papayawhip: "#ffefd5"
115
- peachpuff: "#ffdab9"
116
- peru: "#cd853f"
117
- pink: "#ffc0cb"
118
- plum: "#dda0dd"
119
- powderblue: "#b0e0e6"
120
- purple: "#800080"
121
- rebeccapurple: "#663399"
122
- red: "#ff0000"
123
- rosybrown: "#bc8f8f"
124
- royalblue: "#4169e1"
125
- saddlebrown: "#8b4513"
126
- salmon: "#fa8072"
127
- sandybrown: "#f4a460"
128
- seagreen: "#2e8b57"
129
- seashell: "#fff5ee"
130
- sienna: "#a0522d"
131
- silver: "#c0c0c0"
132
- skyblue: "#87ceeb"
133
- slateblue: "#6a5acd"
134
- slategray: "#708090"
135
- slategrey: "#708090"
136
- snow: "#fffafa"
137
- springgreen: "#00ff7f"
138
- steelblue: "#4682b4"
139
- tan: "#d2b48c"
140
- teal: "#008080"
141
- thistle: "#d8bfd8"
142
- tomato: "#ff6347"
143
- transparent: "#00000000"
144
- turquoise: "#40e0d0"
145
- violet: "#ee82ee"
146
- wheat: "#f5deb3"
147
- white: "#ffffff"
148
- whitesmoke: "#f5f5f5"
149
- yellow: "#ffff00"
150
- yellowgreen: "#9acd32"