omni-color 0.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.
Files changed (293) hide show
  1. package/LICENSE +7 -0
  2. package/README.md +1042 -0
  3. package/dist/__test__/color-interop.test.d.ts +1 -0
  4. package/dist/__test__/color-interop.test.js +82 -0
  5. package/dist/__test__/comparison_culori.test.d.ts +1 -0
  6. package/dist/__test__/comparison_culori.test.js +169 -0
  7. package/dist/__test__/interop-chroma.test.d.ts +1 -0
  8. package/dist/__test__/interop-chroma.test.js +676 -0
  9. package/dist/__test__/interop-tinycolor.test.d.ts +1 -0
  10. package/dist/__test__/interop-tinycolor.test.js +499 -0
  11. package/dist/color/__test__/baseColor.test.d.ts +2 -0
  12. package/dist/color/__test__/baseColor.test.d.ts.map +1 -0
  13. package/dist/color/__test__/baseColor.test.js +34 -0
  14. package/dist/color/__test__/baseColor.test.js.map +1 -0
  15. package/dist/color/__test__/blank.d.ts +1 -0
  16. package/dist/color/__test__/blank.js +3 -0
  17. package/dist/color/__test__/color.test.d.ts +1 -0
  18. package/dist/color/__test__/color.test.js +1073 -0
  19. package/dist/color/__test__/colorSpaces.test.d.ts +1 -0
  20. package/dist/color/__test__/colorSpaces.test.js +69 -0
  21. package/dist/color/__test__/combinations.test.d.ts +1 -0
  22. package/dist/color/__test__/combinations.test.js +665 -0
  23. package/dist/color/__test__/conversions.test.d.ts +1 -0
  24. package/dist/color/__test__/conversions.test.js +719 -0
  25. package/dist/color/__test__/deltaE.test.d.ts +1 -0
  26. package/dist/color/__test__/deltaE.test.js +120 -0
  27. package/dist/color/__test__/formats.test.d.ts +1 -0
  28. package/dist/color/__test__/formats.test.js +514 -0
  29. package/dist/color/__test__/gradients.test.d.ts +1 -0
  30. package/dist/color/__test__/gradients.test.js +414 -0
  31. package/dist/color/__test__/harmonies.test.d.ts +1 -0
  32. package/dist/color/__test__/harmonies.test.js +676 -0
  33. package/dist/color/__test__/manipulations.test.d.ts +1 -0
  34. package/dist/color/__test__/manipulations.test.js +264 -0
  35. package/dist/color/__test__/names.test.d.ts +1 -0
  36. package/dist/color/__test__/names.test.js +67 -0
  37. package/dist/color/__test__/parse.test.d.ts +1 -0
  38. package/dist/color/__test__/parse.test.js +256 -0
  39. package/dist/color/__test__/random.test.d.ts +1 -0
  40. package/dist/color/__test__/random.test.js +262 -0
  41. package/dist/color/__test__/readability.test.d.ts +1 -0
  42. package/dist/color/__test__/readability.test.js +2596 -0
  43. package/dist/color/__test__/srgb.test.d.ts +1 -0
  44. package/dist/color/__test__/srgb.test.js +43 -0
  45. package/dist/color/__test__/swatch.test.d.ts +1 -0
  46. package/dist/color/__test__/swatch.test.js +267 -0
  47. package/dist/color/__test__/temperature.test.d.ts +1 -0
  48. package/dist/color/__test__/temperature.test.js +223 -0
  49. package/dist/color/__test__/utils.test.d.ts +1 -0
  50. package/dist/color/__test__/utils.test.js +409 -0
  51. package/dist/color/__test__/validations.test.d.ts +1 -0
  52. package/dist/color/__test__/validations.test.js +239 -0
  53. package/dist/color/color.constants.d.ts +4 -0
  54. package/dist/color/color.constants.d.ts.map +1 -0
  55. package/dist/color/color.constants.js +152 -0
  56. package/dist/color/color.constants.js.map +1 -0
  57. package/dist/color/color.consts.d.ts +4 -0
  58. package/dist/color/color.consts.js +152 -0
  59. package/dist/color/color.d.ts +788 -0
  60. package/dist/color/color.d.ts.map +1 -0
  61. package/dist/color/color.helpers.d.ts +6 -0
  62. package/dist/color/color.helpers.js +4 -0
  63. package/dist/color/color.js +919 -0
  64. package/dist/color/color.js.map +1 -0
  65. package/dist/color/colorSpaces.d.ts +15 -0
  66. package/dist/color/colorSpaces.js +127 -0
  67. package/dist/color/combinations.d.ts +45 -0
  68. package/dist/color/combinations.js +562 -0
  69. package/dist/color/conversions.d.ts +16 -0
  70. package/dist/color/conversions.d.ts.map +1 -0
  71. package/dist/color/conversions.js +705 -0
  72. package/dist/color/conversions.js.map +1 -0
  73. package/dist/color/deltaE.d.ts +59 -0
  74. package/dist/color/deltaE.js +110 -0
  75. package/dist/color/formats.d.ts +128 -0
  76. package/dist/color/formats.d.ts.map +1 -0
  77. package/dist/color/formats.js +153 -0
  78. package/dist/color/formats.js.map +1 -0
  79. package/dist/color/gradients.d.ts +49 -0
  80. package/dist/color/gradients.js +672 -0
  81. package/dist/color/harmonies.d.ts +18 -0
  82. package/dist/color/harmonies.js +128 -0
  83. package/dist/color/manipulations.d.ts +29 -0
  84. package/dist/color/manipulations.js +106 -0
  85. package/dist/color/names.d.ts +38 -0
  86. package/dist/color/names.js +108 -0
  87. package/dist/color/parse.d.ts +2 -0
  88. package/dist/color/parse.js +437 -0
  89. package/dist/color/random.d.ts +30 -0
  90. package/dist/color/random.js +65 -0
  91. package/dist/color/readability.d.ts +53 -0
  92. package/dist/color/readability.js +284 -0
  93. package/dist/color/srgb.d.ts +8 -0
  94. package/dist/color/srgb.js +33 -0
  95. package/dist/color/swatch.d.ts +49 -0
  96. package/dist/color/swatch.js +118 -0
  97. package/dist/color/temperature.d.ts +26 -0
  98. package/dist/color/temperature.js +141 -0
  99. package/dist/color/utils.d.ts +49 -0
  100. package/dist/color/utils.d.ts.map +1 -0
  101. package/dist/color/utils.js +104 -0
  102. package/dist/color/utils.js.map +1 -0
  103. package/dist/color/validations.d.ts +2 -0
  104. package/dist/color/validations.d.ts.map +1 -0
  105. package/dist/color/validations.js +178 -0
  106. package/dist/color/validations.js.map +1 -0
  107. package/dist/demo/src/AppFooter.d.ts +1 -0
  108. package/dist/demo/src/AppFooter.js +4 -0
  109. package/dist/demo/src/AppHeader.d.ts +5 -0
  110. package/dist/demo/src/AppHeader.js +6 -0
  111. package/dist/demo/src/components/Card.d.ts +9 -0
  112. package/dist/demo/src/components/Card.js +9 -0
  113. package/dist/demo/src/components/Chip.d.ts +21 -0
  114. package/dist/demo/src/components/Chip.js +23 -0
  115. package/dist/demo/src/components/ColorBox.d.ts +16 -0
  116. package/dist/demo/src/components/ColorBox.js +45 -0
  117. package/dist/demo/src/components/ColorInfoCard.d.ts +7 -0
  118. package/dist/demo/src/components/ColorInfoCard.js +50 -0
  119. package/dist/demo/src/components/ExpandableCodeSnippet.d.ts +5 -0
  120. package/dist/demo/src/components/ExpandableCodeSnippet.js +17 -0
  121. package/dist/demo/src/components/Icon.d.ts +11 -0
  122. package/dist/demo/src/components/Icon.js +50 -0
  123. package/dist/demo/src/components/Icon.types.d.ts +14 -0
  124. package/dist/demo/src/components/Icon.types.js +15 -0
  125. package/dist/demo/src/components/SectionContainer.d.ts +10 -0
  126. package/dist/demo/src/components/SectionContainer.js +12 -0
  127. package/dist/demo/src/components/VSpace.d.ts +5 -0
  128. package/dist/demo/src/components/VSpace.js +4 -0
  129. package/dist/demo/src/components/inputs/Checkbox.d.ts +7 -0
  130. package/dist/demo/src/components/inputs/Checkbox.js +4 -0
  131. package/dist/demo/src/components/inputs/InputGroup.d.ts +6 -0
  132. package/dist/demo/src/components/inputs/InputGroup.js +4 -0
  133. package/dist/demo/src/components/inputs/NumberInput.d.ts +10 -0
  134. package/dist/demo/src/components/inputs/NumberInput.js +8 -0
  135. package/dist/demo/src/components/inputs/Select.d.ts +12 -0
  136. package/dist/demo/src/components/inputs/Select.js +6 -0
  137. package/dist/demo/src/components/inputs/Slider.d.ts +10 -0
  138. package/dist/demo/src/components/inputs/Slider.js +4 -0
  139. package/dist/demo/src/components/utils.d.ts +17 -0
  140. package/dist/demo/src/components/utils.js +24 -0
  141. package/dist/demo/src/demo/ColorDemo.d.ts +1 -0
  142. package/dist/demo/src/demo/ColorDemo.js +45 -0
  143. package/dist/demo/src/demo/ColorHarmonyDemo.d.ts +6 -0
  144. package/dist/demo/src/demo/ColorHarmonyDemo.js +18 -0
  145. package/dist/demo/src/demo/ColorInfo.d.ts +6 -0
  146. package/dist/demo/src/demo/ColorInfo.js +14 -0
  147. package/dist/demo/src/demo/ColorInput.d.ts +7 -0
  148. package/dist/demo/src/demo/ColorInput.js +58 -0
  149. package/dist/demo/src/demo/ColorManipulationDemo.d.ts +6 -0
  150. package/dist/demo/src/demo/ColorManipulationDemo.js +63 -0
  151. package/dist/demo/src/demo/ColorSwatch.d.ts +13 -0
  152. package/dist/demo/src/demo/ColorSwatch.js +15 -0
  153. package/dist/demo/src/demo/ReadabilityDemo.d.ts +6 -0
  154. package/dist/demo/src/demo/ReadabilityDemo.js +24 -0
  155. package/dist/demo/src/demo/combinations/AverageColorsOptionInputs.d.ts +7 -0
  156. package/dist/demo/src/demo/combinations/AverageColorsOptionInputs.js +7 -0
  157. package/dist/demo/src/demo/combinations/BlendColorsOptionInputs.d.ts +7 -0
  158. package/dist/demo/src/demo/combinations/BlendColorsOptionInputs.js +13 -0
  159. package/dist/demo/src/demo/combinations/ColorCombinationDemo.d.ts +6 -0
  160. package/dist/demo/src/demo/combinations/ColorCombinationDemo.js +78 -0
  161. package/dist/demo/src/demo/combinations/MixColorsOptionInputs.d.ts +7 -0
  162. package/dist/demo/src/demo/combinations/MixColorsOptionInputs.js +10 -0
  163. package/dist/demo/src/demo/combinations/colorCombinationDemo.consts.d.ts +4 -0
  164. package/dist/demo/src/demo/combinations/colorCombinationDemo.consts.js +12 -0
  165. package/dist/demo/src/demo/gradients/GradientOptionInputs.d.ts +10 -0
  166. package/dist/demo/src/demo/gradients/GradientOptionInputs.js +42 -0
  167. package/dist/demo/src/demo/gradients/GradientThroughCard.d.ts +6 -0
  168. package/dist/demo/src/demo/gradients/GradientThroughCard.js +50 -0
  169. package/dist/demo/src/demo/gradients/GradientToCard.d.ts +6 -0
  170. package/dist/demo/src/demo/gradients/GradientToCard.js +54 -0
  171. package/dist/demo/src/demo/gradients/GradientsDemo.d.ts +6 -0
  172. package/dist/demo/src/demo/gradients/GradientsDemo.js +6 -0
  173. package/dist/demo/src/demo/gradients/gradientOptions.consts.d.ts +3 -0
  174. package/dist/demo/src/demo/gradients/gradientOptions.consts.js +16 -0
  175. package/dist/demo/src/demo/palette/ColorPaletteDemo.d.ts +6 -0
  176. package/dist/demo/src/demo/palette/ColorPaletteDemo.js +26 -0
  177. package/dist/demo/src/demo/palette/PaletteGenerationOptions.d.ts +8 -0
  178. package/dist/demo/src/demo/palette/PaletteGenerationOptions.js +53 -0
  179. package/dist/demo/src/demo/palette/PaletteHarmonyOptions.d.ts +7 -0
  180. package/dist/demo/src/demo/palette/PaletteHarmonyOptions.js +5 -0
  181. package/dist/demo/src/main.d.ts +1 -0
  182. package/dist/demo/src/main.js +14 -0
  183. package/dist/demo/src/pages/DemoPage.d.ts +1 -0
  184. package/dist/demo/src/pages/DemoPage.js +28 -0
  185. package/dist/demo/src/pages/PlaygroundPage.d.ts +1 -0
  186. package/dist/demo/src/pages/PlaygroundPage.js +24 -0
  187. package/dist/demo/src/playground/Playground.d.ts +1 -0
  188. package/dist/demo/src/playground/Playground.js +42 -0
  189. package/dist/demo/src/playground/playgroundUtils.d.ts +16 -0
  190. package/dist/demo/src/playground/playgroundUtils.js +202 -0
  191. package/dist/demo/src/seo/PageHead.d.ts +9 -0
  192. package/dist/demo/src/seo/PageHead.js +76 -0
  193. package/dist/demo/src/seo/StructuredData.d.ts +6 -0
  194. package/dist/demo/src/seo/StructuredData.js +13 -0
  195. package/dist/demo/src/toast/ToastProvider.d.ts +2 -0
  196. package/dist/demo/src/toast/ToastProvider.js +62 -0
  197. package/dist/demo/src/toast/index.d.ts +2 -0
  198. package/dist/demo/src/toast/index.js +2 -0
  199. package/dist/demo/src/toast/toastBus.d.ts +13 -0
  200. package/dist/demo/src/toast/toastBus.js +27 -0
  201. package/dist/index.d.ts +1233 -0
  202. package/dist/index.d.ts.map +1 -0
  203. package/dist/index.js +5235 -0
  204. package/dist/index.js.map +1 -0
  205. package/dist/palette/__test__/palette.test.d.ts +1 -0
  206. package/dist/palette/__test__/palette.test.js +397 -0
  207. package/dist/palette/palette.d.ts +41 -0
  208. package/dist/palette/palette.js +126 -0
  209. package/dist/src/__test__/interop-chroma.test.d.ts +1 -0
  210. package/dist/src/__test__/interop-chroma.test.js +673 -0
  211. package/dist/src/__test__/interop-tinycolor.test.d.ts +1 -0
  212. package/dist/src/__test__/interop-tinycolor.test.js +499 -0
  213. package/dist/src/color/__test__/color.test.d.ts +1 -0
  214. package/dist/src/color/__test__/color.test.js +1071 -0
  215. package/dist/src/color/__test__/colorSpaces.test.d.ts +1 -0
  216. package/dist/src/color/__test__/colorSpaces.test.js +69 -0
  217. package/dist/src/color/__test__/combinations.test.d.ts +1 -0
  218. package/dist/src/color/__test__/combinations.test.js +665 -0
  219. package/dist/src/color/__test__/conversions.test.d.ts +1 -0
  220. package/dist/src/color/__test__/conversions.test.js +719 -0
  221. package/dist/src/color/__test__/deltaE.test.d.ts +1 -0
  222. package/dist/src/color/__test__/deltaE.test.js +120 -0
  223. package/dist/src/color/__test__/formats.test.d.ts +1 -0
  224. package/dist/src/color/__test__/formats.test.js +470 -0
  225. package/dist/src/color/__test__/gradients.test.d.ts +1 -0
  226. package/dist/src/color/__test__/gradients.test.js +414 -0
  227. package/dist/src/color/__test__/harmonies.test.d.ts +1 -0
  228. package/dist/src/color/__test__/harmonies.test.js +734 -0
  229. package/dist/src/color/__test__/manipulations.test.d.ts +1 -0
  230. package/dist/src/color/__test__/manipulations.test.js +264 -0
  231. package/dist/src/color/__test__/names.test.d.ts +1 -0
  232. package/dist/src/color/__test__/names.test.js +67 -0
  233. package/dist/src/color/__test__/parse.test.d.ts +1 -0
  234. package/dist/src/color/__test__/parse.test.js +251 -0
  235. package/dist/src/color/__test__/random.test.d.ts +1 -0
  236. package/dist/src/color/__test__/random.test.js +262 -0
  237. package/dist/src/color/__test__/readability.test.d.ts +1 -0
  238. package/dist/src/color/__test__/readability.test.js +2596 -0
  239. package/dist/src/color/__test__/swatch.test.d.ts +1 -0
  240. package/dist/src/color/__test__/swatch.test.js +267 -0
  241. package/dist/src/color/__test__/temperature.test.d.ts +1 -0
  242. package/dist/src/color/__test__/temperature.test.js +223 -0
  243. package/dist/src/color/__test__/utils.test.d.ts +1 -0
  244. package/dist/src/color/__test__/utils.test.js +409 -0
  245. package/dist/src/color/__test__/validations.test.d.ts +1 -0
  246. package/dist/src/color/__test__/validations.test.js +239 -0
  247. package/dist/src/color/color.consts.d.ts +4 -0
  248. package/dist/src/color/color.consts.js +152 -0
  249. package/dist/src/color/color.d.ts +775 -0
  250. package/dist/src/color/color.js +903 -0
  251. package/dist/src/color/colorSpaces.d.ts +15 -0
  252. package/dist/src/color/colorSpaces.js +127 -0
  253. package/dist/src/color/combinations.d.ts +45 -0
  254. package/dist/src/color/combinations.js +557 -0
  255. package/dist/src/color/conversions.d.ts +16 -0
  256. package/dist/src/color/conversions.js +705 -0
  257. package/dist/src/color/deltaE.d.ts +59 -0
  258. package/dist/src/color/deltaE.js +110 -0
  259. package/dist/src/color/formats.d.ts +126 -0
  260. package/dist/src/color/formats.js +150 -0
  261. package/dist/src/color/gradients.d.ts +49 -0
  262. package/dist/src/color/gradients.js +673 -0
  263. package/dist/src/color/harmonies.d.ts +18 -0
  264. package/dist/src/color/harmonies.js +129 -0
  265. package/dist/src/color/manipulations.d.ts +29 -0
  266. package/dist/src/color/manipulations.js +107 -0
  267. package/dist/src/color/names.d.ts +38 -0
  268. package/dist/src/color/names.js +108 -0
  269. package/dist/src/color/parse.d.ts +2 -0
  270. package/dist/src/color/parse.js +438 -0
  271. package/dist/src/color/random.d.ts +30 -0
  272. package/dist/src/color/random.js +65 -0
  273. package/dist/src/color/readability.d.ts +53 -0
  274. package/dist/src/color/readability.js +284 -0
  275. package/dist/src/color/swatch.d.ts +49 -0
  276. package/dist/src/color/swatch.js +117 -0
  277. package/dist/src/color/temperature.d.ts +26 -0
  278. package/dist/src/color/temperature.js +142 -0
  279. package/dist/src/color/utils.d.ts +57 -0
  280. package/dist/src/color/utils.js +142 -0
  281. package/dist/src/color/validations.d.ts +2 -0
  282. package/dist/src/color/validations.js +178 -0
  283. package/dist/src/index.d.ts +20 -0
  284. package/dist/src/index.js +2 -0
  285. package/dist/src/palette/__test__/palette.test.d.ts +1 -0
  286. package/dist/src/palette/__test__/palette.test.js +397 -0
  287. package/dist/src/palette/palette.d.ts +41 -0
  288. package/dist/src/palette/palette.js +127 -0
  289. package/dist/src/utils.d.ts +20 -0
  290. package/dist/src/utils.js +42 -0
  291. package/dist/utils.d.ts +20 -0
  292. package/dist/utils.js +42 -0
  293. package/package.json +96 -0
package/README.md ADDED
@@ -0,0 +1,1042 @@
1
+ # omni-color
2
+
3
+ > ⚠️ This is a work-in-progress library. API and structure may change before 1.0.0.
4
+
5
+ A modern color manipulation and color scheme generation library for TypeScript/JavaScript projects.
6
+
7
+ [![License: ISC](https://img.shields.io/badge/license-ISC-blue.svg)](./LICENSE) [![CI](https://github.com/rteammco/omni-color/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/rteammco/omni-color/actions/workflows/ci.yml) [![Demo Deployed](https://github.com/rteammco/omni-color/actions/workflows/pages.yml/badge.svg?branch=main)](https://github.com/rteammco/omni-color/actions/workflows/pages.yml)
8
+
9
+ **Live demo:** https://rteammco.github.io/omni-color/
10
+
11
+ ## 📦 Install
12
+
13
+ ```bash
14
+ npm install omni-color
15
+ ```
16
+
17
+ ## ℹ️ Documentation
18
+
19
+ **_omni-color_** is built around the [`Color`](#types-color) class. [`Color`](#types-color) is immutable - all operations will return a new instance. Import directly from the package:
20
+
21
+ ```ts
22
+ import { Color } from 'omni-color';
23
+
24
+ const color = new Color('#ff7f50');
25
+ const translucent = color.setAlpha(0.5);
26
+ const darker = translucent.darken({ amount: 20 });
27
+ const hex8String = darker.toHex8();
28
+ ```
29
+
30
+ ### Initialize Colors
31
+
32
+ #### `new Color(color?: Color | ColorFormat | string | null): Color`
33
+
34
+ _`constructor`_
35
+
36
+ - <ins>Returns</ins> a new [`Color`](#types-color) instance of the specified color input.
37
+ - <ins>Inputs</ins>:
38
+ - `color` (optional) - an existing [`Color`](#types-color), any valid [`ColorFormat`](#types-color-format), a named CSS color, or any parsable color format (e.g. `"rgb(0,255,255)"`) including partial or exact matches of a [`ColorTemperatureLabel`](#types-color-temperature-label).
39
+ - Supports modern CSS Color 4/5 syntax including `hwb()`, `lab()`, `lch()`, `oklch()`, and `color()` for the `srgb`, `display-p3`, and `rec2020` color spaces.
40
+ - No input or passing in `null`/`undefined` generates a random color.
41
+ - **Invalid inputs throw an exception.**
42
+
43
+ ```ts
44
+ const red = new Color('#ff0000'); // #ff0000
45
+ const byName = new Color('red'); // #ff0000
46
+ const fromObj = new Color({ h: 210, s: 80, l: 40 }); // #1466b8
47
+ const parsed = new Color('rgba(255, 0, 0, 0.5)'); // #ff000080
48
+ const fromTemperature = new Color('Incandescent lamp'); // #ffa757
49
+ const fromCSSColor = new Color('color(display-p3 1 0.5 0)'); // #ff7600
50
+ const random = new Color();
51
+ ```
52
+
53
+ #### `Color.random(options?: RandomColorOptions): Color`
54
+
55
+ _`static`_
56
+
57
+ - <ins>Returns</ins> a new [`Color`](#types-color) instance of a randomly-generated color.
58
+ - <ins>Inputs</ins>:
59
+ - `options` (optional) - customize how the color will be randomized with `RandomColorOptions`:
60
+ - `alpha` - the alpha value of the random color (0-1). If not specified, it will default to 1 (opaque) unless `randomizeAlpha` is `true`.
61
+ - `randomizeAlpha` - if `true`, the alpha value of the generated color will be randomized (0-1). This option is ignored if an `alpha` value is explicitly provided. Defaults to `false`.
62
+ - `anchorColor` - randomize within the specified hue / named color family ([`BaseColorName`](#types)). Defaults to no anchor, meaning the hue is chosen from the full range.
63
+ - `paletteSuitable` - if `true`, the generated color will have moderate lightness and sufficient saturation to make them suitable for creating color palettes. This option will be ignored if `anchorColor` is `"Black"`, `"White"`, or `"Gray"`. Defaults to `false`.
64
+
65
+ ```ts
66
+ const random = Color.random();
67
+ const punchy = Color.random({ anchorColor: 'Orange', paletteSuitable: true });
68
+ const translucent = Color.random({ randomizeAlpha: true });
69
+ ```
70
+
71
+ #### `Color.fromTemperature(temperature: number | ColorTemperatureLabel): Color`
72
+
73
+ _`static`_
74
+
75
+ - <ins>Returns</ins> an off-white [`Color`](#types-color) reflecting the given color temperature.
76
+ - Kelvin to RGB conversion algorithm: https://tannerhelland.com/2012/09/18/convert-temperature-rgb-algorithm-code.html.
77
+ - <ins>Inputs</ins>:
78
+ - `temperature` - a color temperature value in Kelvin (valid range is ~1000 to ~40000) or a [`ColorTemperatureLabel`](#types-color-temperature-label).
79
+
80
+ ```ts
81
+ const daylight = Color.fromTemperature(6500);
82
+ daylight.toHex(); // '#fffefa'
83
+ const cozy = Color.fromTemperature('Incandescent lamp');
84
+ cozy.toHex(); // '#ffa757'
85
+ ```
86
+
87
+ ### Color Information and Utils
88
+
89
+ #### `getName(): { name: BaseColorName; lightness: ColorLightnessModifier }`
90
+
91
+ - <ins>Returns</ins> a human-friendly [`BaseColorName`](#types-base-color-name) paired with a lightness descriptor: `type ColorLightnessModifier = "Light" | "Normal" | "Dark"`.
92
+
93
+ ```ts
94
+ new Color('#ff0000').getName(); // { name: 'Red', lightness: 'Normal' }
95
+ new Color('#006400').getName(); // { name: 'Green', lightness: 'Dark' }
96
+ ```
97
+
98
+ #### `getNameAsString(): string`
99
+
100
+ - <ins>Returns</ins> the color name and lightness as a lowercase string (e.g., `"dark green"`).
101
+
102
+ ```ts
103
+ new Color('#ff0000').getNameAsString(); // 'red'
104
+ new Color('#87cefa').getNameAsString(); // 'light blue'
105
+ ```
106
+
107
+ #### `equals(color: Color | ColorFormat | string): boolean`
108
+
109
+ - <ins>Returns</ins> `true` if the color matches another color within rounding tolerance.
110
+ - <ins>Inputs</ins>:
111
+ - `color` - another [`Color`](#types-color), any [`ColorFormat`](#types-color-format), or a parsable color string to compare against.
112
+
113
+ ```ts
114
+ new Color('#ff0000').equals(new Color('rgb(255, 0, 0)')); // true
115
+ new Color('#ff0000').equals('red'); // true
116
+ new Color('#ff0000').equals({ r: 0, g: 255, b: 0 }); // false
117
+ ```
118
+
119
+ #### `isDark(options?: IsColorDarkOptions): boolean`
120
+
121
+ - <ins>Returns</ins> `true` if the color is considered visually dark based on luminance checks.
122
+ - <ins>Inputs</ins>:
123
+ - `options` (optional) - customize the darkness algorithm with `IsColorDarkOptions`:
124
+ - `colorDarknessMode` - the algorithm to use, either `"WCAG"` (default / recommended) or `"YIQ"` (legacy).
125
+ - `wcagThreshold` - the threshold (0 to 1) for considering a color "dark" when using the WCAG algorithm. Default is 0.179. Only applicable to `"WCAG"` mode.
126
+ - `yiqThreshold` - the threshold (0 to 255) for considering a color "dark" when using the YIQ algorithm. Default is 128. Only applicable to `"YIQ"` mode.
127
+
128
+ ```ts
129
+ new Color('#000000').isDark(); // true
130
+ new Color('#ffffff').isDark(); // false
131
+ new Color('#ff0000').isDark({ colorDarknessMode: 'YIQ' }); // true
132
+ ```
133
+
134
+ #### `isOffWhite(): boolean`
135
+
136
+ - <ins>Returns</ins> `true` if the color is pure white or a very light off-white.
137
+
138
+ ```ts
139
+ new Color('#ffffff').isOffWhite(); // true
140
+ new Color('#cccccc').isOffWhite(); // false
141
+ ```
142
+
143
+ #### `isPaletteSuitable(): boolean`
144
+
145
+ - <ins>Returns</ins> `true` if the color matches the same "palette suitable" constraints used by `Color.random({ paletteSuitable: true })`.
146
+ - A palette-suitable color must have:
147
+ - saturation >= 40%
148
+ - lightness between 25% and 75% (inclusive)
149
+
150
+ ```ts
151
+ new Color('#ff0000').isPaletteSuitable(); // true
152
+ new Color('#f2f2f2').isPaletteSuitable(); // false
153
+ ```
154
+
155
+ #### `getTemperature(): { temperature: number; label: ColorTemperatureLabel }`
156
+
157
+ - <ins>Returns</ins> the estimated correlated color temperature in Kelvin plus a [`ColorTemperatureLabel`](#types-color-temperature-label) describing the closest standard lighting condition.
158
+
159
+ ```ts
160
+ new Color('#ff0000').getTemperature(); // { temperature: 2655, label: 'Incandescent lamp' }
161
+ ```
162
+
163
+ #### `getTemperatureAsString(options?: ColorTemperatureStringFormatOptions): string`
164
+
165
+ - <ins>Returns</ins> the color temperature formatted as a string in Kelvin, optionally including the label when the color is close to the Planckian locus.
166
+ - <ins>Inputs</ins>:
167
+ - `options` (optional) - `ColorTemperatureStringFormatOptions`:
168
+ - `formatNumber` - set to `true` to format the temperature value with locale separators. Defaults to `false` (unformatted number).
169
+
170
+ ```ts
171
+ new Color('#ffffff').getTemperatureAsString(); // '6504 K (cloudy sky)'
172
+ new Color('#ffffff').getTemperatureAsString({ formatNumber: true }); // '6,504 K (cloudy sky)'
173
+ ```
174
+
175
+ #### `getAlpha(): number`
176
+
177
+ - <ins>Returns</ins> the current alpha value (0–1).
178
+
179
+ ```ts
180
+ new Color('#ff0000').getAlpha(); // 1
181
+ new Color('#ff000080').getAlpha(); // 0.5
182
+ ```
183
+
184
+ #### `setAlpha(value: number): Color`
185
+
186
+ - <ins>Returns</ins> a new [`Color`](#types-color) with the specified alpha. Out-of-bounds alpha values will be clamped between 0 and 1.
187
+
188
+ ```ts
189
+ new Color('#ff0000').setAlpha(0.25).toRGBAString(); // 'rgb(255 0 0 / 0.25)'
190
+ ```
191
+
192
+ #### `clone(): Color`
193
+
194
+ - <ins>Returns</ins> a new [`Color`](#types-color) identical to the source instance.
195
+
196
+ ```ts
197
+ const original = new Color('#ff7f50');
198
+ const copy = original.clone();
199
+ original.equals(copy); // true
200
+ ```
201
+
202
+ ### Color Formats and Conversions
203
+
204
+ #### `toHex(): ColorHex`
205
+
206
+ - <ins>Returns</ins> a [`ColorHex`](#types-color-hex) string in 6-digit `"#rrggbb"` form (alpha is ignored).
207
+
208
+ ```ts
209
+ new Color('red').toHex(); // #ff0000
210
+ ```
211
+
212
+ #### `toHex8(): ColorHex`
213
+
214
+ - <ins>Returns</ins> a [`ColorHex`](#types-color-hex) string in 8-digit `"#rrggbbaa"` form, including the alpha channel.
215
+
216
+ ```ts
217
+ new Color('rgba(0, 0, 255, 0.5)').toHex8(); // #0000ff80
218
+ ```
219
+
220
+ #### `toRGB(): { r: number; g: number; b: number }`
221
+
222
+ - <ins>Returns</ins> a [`ColorRGB`](#types-color-rgb) object with 0–255 channel values.
223
+
224
+ ```ts
225
+ new Color('#33cc99').toRGB(); // { r: 51, g: 204, b: 153 }
226
+ ```
227
+
228
+ #### `toRGBA(): { r: number; g: number; b: number; a: number }`
229
+
230
+ - <ins>Returns</ins> a [`ColorRGBA`](#types-color-rgba) object with 0–255 RGB channels and alpha 0–1.
231
+
232
+ ```ts
233
+ new Color('#33cc99').toRGBA(); // { r: 51, g: 204, b: 153, a: 1 }
234
+ ```
235
+
236
+ #### `toRGBString(): string`
237
+
238
+ - <ins>Returns</ins> a CSS `"rgb(r g b)"` string.
239
+
240
+ ```ts
241
+ new Color('#33cc99').toRGBString(); // 'rgb(51 204 153)'
242
+ ```
243
+
244
+ #### `toRGBAString(): string`
245
+
246
+ - <ins>Returns</ins> a CSS `"rgb(r g b / a)"` string.
247
+
248
+ ```ts
249
+ new Color('#33cc99').setAlpha(0.5).toRGBAString(); // 'rgb(51 204 153 / 0.5)'
250
+ ```
251
+
252
+ #### `toHSL(): { h: number; s: number; l: number }`
253
+
254
+ - <ins>Returns</ins> a [`ColorHSL`](#types-color-hsl) object with hue 0–360 and saturation/lightness 0–100.
255
+
256
+ ```ts
257
+ new Color('#663399').toHSL(); // { h: 270, s: 50, l: 40 }
258
+ ```
259
+
260
+ #### `toHSLA(): { h: number; s: number; l: number; a: number }`
261
+
262
+ - <ins>Returns</ins> a [`ColorHSLA`](#types-color-hsla) object with hue 0–360, saturation/lightness 0–100, and alpha 0–1.
263
+
264
+ ```ts
265
+ new Color('#663399').toHSLA(); // { h: 270, s: 50, l: 40, a: 1 }
266
+ ```
267
+
268
+ #### `toHSLString(): string`
269
+
270
+ - <ins>Returns</ins> a CSS `"hsl(h s% l%)"` string.
271
+
272
+ ```ts
273
+ new Color('#663399').toHSLString(); // 'hsl(270 50% 40%)'
274
+ ```
275
+
276
+ #### `toHSLAString(): string`
277
+
278
+ - <ins>Returns</ins> a CSS `"hsl(h s% l% / a)"` string.
279
+
280
+ ```ts
281
+ new Color('#663399').toHSLAString(); // 'hsl(270 50% 40% / 1)'
282
+ ```
283
+
284
+ #### `toHSV(): { h: number; s: number; v: number }`
285
+
286
+ - <ins>Returns</ins> a [`ColorHSV`](#types-color-hsv) object with hue 0–360 and saturation/value 0–100.
287
+
288
+ ```ts
289
+ new Color('#1e90ff').toHSV(); // { h: 210, s: 88, v: 100 }
290
+ ```
291
+
292
+ #### `toHSVString(): string`
293
+
294
+ - <ins>Returns</ins> an `"hsv(h s% v%)"` string.
295
+
296
+ ```ts
297
+ new Color('#1e90ff').toHSVString(); // 'hsv(210 88.235% 100%)'
298
+ ```
299
+
300
+ #### `toHSVA(): { h: number; s: number; v: number; a: number }`
301
+
302
+ - <ins>Returns</ins> a [`ColorHSVA`](#types-color-hsva) object with hue 0–360, saturation/value 0–100, and alpha 0–1.
303
+
304
+ ```ts
305
+ new Color('#1e90ff').toHSVA(); // { h: 210, s: 88, v: 100, a: 1 }
306
+ ```
307
+
308
+ #### `toHSVAString(): string`
309
+
310
+ - <ins>Returns</ins> an `"hsva(h s% v% / a)"` string.
311
+
312
+ ```ts
313
+ new Color('#1e90ff').toHSVAString(); // 'hsv(210 88.235% 100% / 1)'
314
+ ```
315
+
316
+ #### `toHWB(): { h: number; w: number; b: number }`
317
+
318
+ - <ins>Returns</ins> a [`ColorHWB`](#types-color-hwb) object with hue 0–360 and whiteness/blackness 0–100.
319
+
320
+ ```ts
321
+ new Color('#808080').toHWB(); // { h: 0, w: 50, b: 50 }
322
+ ```
323
+
324
+ #### `toHWBString(): string`
325
+
326
+ - <ins>Returns</ins> a CSS `"hwb(h w% b% / a)"` string.
327
+
328
+ ```ts
329
+ new Color('rgba(26, 102, 179, 0.25)').toHWBString(); // 'hwb(210 10% 30% / 0.25)'
330
+ ```
331
+
332
+ #### `toHWBA(): { h: number; w: number; b: number; a: number }`
333
+
334
+ - <ins>Returns</ins> a [`ColorHWBA`](#types-color-hwba) object with hue 0–360, whiteness/blackness 0–100, and alpha 0–1.
335
+
336
+ ```ts
337
+ new Color('rgba(26, 102, 179, 0.25)').toHWBA(); // { h: 210, w: 10, b: 30, a: 0.25 }
338
+ ```
339
+
340
+ #### `toHWBAString(): string`
341
+
342
+ - <ins>Returns</ins> a CSS `"hwb(h w% b% / a)"` string including the alpha channel even when fully opaque.
343
+
344
+ ```ts
345
+ new Color('#1a66b3cc').toHWBAString(); // 'hwb(210 10% 30% / 0.8)'
346
+ ```
347
+
348
+ #### `toCMYK(): { c: number; m: number; y: number; k: number }`
349
+
350
+ - <ins>Returns</ins> a [`ColorCMYK`](#types-color-cmyk) object with channel values 0–100.
351
+
352
+ ```ts
353
+ new Color('#00b7eb').toCMYK(); // { c: 100, m: 22, y: 0, k: 8 }
354
+ ```
355
+
356
+ #### `toCMYKString(): string`
357
+
358
+ - <ins>Returns</ins> a CSS `"device-cmyk(c% m% y% k%)"` string.
359
+
360
+ ```ts
361
+ new Color('#00b7eb').toCMYKString(); // 'device-cmyk(100% 22% 0% 8%)'
362
+ ```
363
+
364
+ #### `toLAB(): { l: number; a: number; b: number }`
365
+
366
+ - <ins>Returns</ins> a [`ColorLAB`](#types-color-lab) object (CIELAB values).
367
+
368
+ ```ts
369
+ new Color('#00b7eb').toLAB(); // { l: 69.373, a: -20.411, b: -36.677 }
370
+ ```
371
+
372
+ #### `toLABString(): string`
373
+
374
+ - <ins>Returns</ins> a CSS `"lab(l% a b)"` string.
375
+
376
+ ```ts
377
+ new Color('#00b7eb').toLABString(); // 'lab(69.373% -20.411 -36.677)'
378
+ ```
379
+
380
+ #### `toOKLAB(): { l: number; a: number; b: number }`
381
+
382
+ - <ins>Returns</ins> a [`ColorOKLAB`](#types-color-oklab) object (OKLAB values).
383
+
384
+ ```ts
385
+ new Color('#ff0000').toOKLAB(); // { l: 0.627955, a: 0.224863, b: 0.125846 }
386
+ ```
387
+
388
+ #### `toOKLABString(): string`
389
+
390
+ - <ins>Returns</ins> a CSS `"oklab(l a b)"` string.
391
+
392
+ ```ts
393
+ new Color('#ff0000').toOKLABString(); // 'oklab(0.627955 0.224863 0.125846)'
394
+ ```
395
+
396
+ #### `toLCH(): { l: number; c: number; h: number }`
397
+
398
+ - <ins>Returns</ins> a [`ColorLCH`](#types-color-lch) object (CIELCh values).
399
+
400
+ ```ts
401
+ new Color('#00b7eb').toLCH(); // { l: 69.373, c: 41.974, h: 240.903 }
402
+ ```
403
+
404
+ #### `toLCHString(): string`
405
+
406
+ - <ins>Returns</ins> a CSS `"lch(l% c h)"` string.
407
+
408
+ ```ts
409
+ new Color('#00b7eb').toLCHString(); // 'lch(69.373% 41.974 240.903)'
410
+ ```
411
+
412
+ #### `toOKLCH(): { l: number; c: number; h: number }`
413
+
414
+ - <ins>Returns</ins> a [`ColorOKLCH`](#types-color-oklch) object (OKLCH values).
415
+
416
+ ```ts
417
+ new Color('#00b7eb').toOKLCH(); // { l: 0.727148, c: 0.140767, h: 227.27 }
418
+ ```
419
+
420
+ #### `toOKLCHString(): string`
421
+
422
+ - <ins>Returns</ins> a CSS `"oklch(l c h)"` string.
423
+
424
+ ```ts
425
+ new Color('#00b7eb').toOKLCHString(); // 'oklch(0.727148 0.140767 227.27)'
426
+ ```
427
+
428
+ #### `toColorString(options?: ColorStringOptions): string`
429
+
430
+ - <ins>Returns</ins> a CSS `"color(space r g b / a)"` string in the requested color space.
431
+ - <ins>Inputs</ins>:
432
+ - `options` (optional) - `ColorStringOptions`:
433
+ - `space` (optional) - target color space for the `color()` string: [`ColorSpace`](#types-color-space). Defaults to `"SRGB"`.
434
+
435
+ ```ts
436
+ new Color('#ff000080').toColorString(); // 'color(srgb 1 0 0 / 0.5)'
437
+ new Color('#ff000080').toColorString({ space: 'DISPLAY-P3' });
438
+ // 'color(display-p3 0.917488 0.200287 0.138561 / 0.5)'
439
+ new Color('#336699').toColorString({ space: 'rec2020' });
440
+ // 'color(rec2020 0.250128 0.336705 0.537794)'
441
+ ```
442
+
443
+ ### Color Manipulations
444
+
445
+ #### `spin(degrees: number): Color`
446
+
447
+ - <ins>Returns</ins> a new [`Color`](#types-color) with its hue rotated in HSL space (wraps at 0–360). Alpha is preserved.
448
+ - <ins>Inputs</ins>:
449
+ - `degrees` - amount to rotate the hue by in degrees.
450
+
451
+ ```ts
452
+ new Color('#ff0000').spin(180).toHex(); // '#00ffff'
453
+ new Color('#008080').spin(-90).toHex(); // '#408000'
454
+ new Color('hsl(30, 80%, 60%)').spin(405).toHex(); // '#c2eb47'
455
+ new Color('rgba(255, 0, 0, 0.35)').spin(60).toHex8(); // '#ffff0059'
456
+ ```
457
+
458
+ #### `brighten(options?: ColorBrightnessOptions): Color`
459
+
460
+ - <ins>Returns</ins> a new [`Color`](#types-color) with increased lightness. Alpha is preserved.
461
+ - <ins>Inputs</ins>:
462
+ - `options` (optional) - ColorBrightnessOptions:
463
+ - `amount` (optional) - a percentage-style amount by which to brighten the color (adjusts the selected space's L channel). Default is `10`.
464
+ - `space` (optional) - the color space to use for the brightness increase calculation: `"HSL" | "LAB" | "LCH"`. Default is `"HSL"`.
465
+ - `labScale` (optional) - when using `"LAB"` or `"LCH"`, the per-step delta applied to the lightness channel. The actual change is `(amount / 10) * labScale`. Defaults to `18`.
466
+
467
+ ```ts
468
+ const neutral = new Color('#808080');
469
+ neutral.brighten().toHex(); // '#999999'
470
+ neutral.brighten({ amount: 25 }).toHex(); // '#bfbfbf'
471
+ neutral.brighten({ space: 'LAB', amount: 20 }).toHex(); // '#e1e1e1'
472
+ new Color('rgba(0, 128, 128, 0.35)').brighten({ space: 'LCH', amount: 15, labScale: 10 }).toHex8(); // '#43a8a759'
473
+ ```
474
+
475
+ #### `darken(options?: ColorBrightnessOptions): Color`
476
+
477
+ - <ins>Returns</ins> a new [`Color`](#types-color) with decreased lightness. Alpha is preserved.
478
+ - <ins>Inputs</ins>:
479
+ - `options` (optional) - ColorBrightnessOptions:
480
+ - `amount` (optional) - a percentage-style amount by which to darken the color (adjusts the selected space's L channel). Default is `10`.
481
+ - `space` (optional) - the color space to use for the brightness decrease calculation: `"HSL" | "LAB" | "LCH"`. Default is `"HSL"`.
482
+ - `labScale` (optional) - when using `"LAB"` or `"LCH"`, the per-step delta applied to the lightness channel. The actual change is `(amount / 10) * labScale`. Defaults to `18`.
483
+
484
+ ```ts
485
+ const cornflower = new Color('#6699cc');
486
+ cornflower.darken().toHex(); // '#4080bf'
487
+ cornflower.darken({ amount: 30 }).toHex(); // '#264d73'
488
+ cornflower.darken({ space: 'LAB', amount: 5 }).toHex(); // '#4d82b3'
489
+ cornflower.darken({ space: 'LCH', amount: 15, labScale: 8 }).toHex(); // '#447aab'
490
+ ```
491
+
492
+ #### `saturate(options?: ColorSaturationOptions): Color`
493
+
494
+ - <ins>Returns</ins> a new [`Color`](#types-color) with increased saturation. Alpha is preserved.
495
+ - <ins>Inputs</ins>:
496
+ - `options` (optional) - ColorSaturationOptions:
497
+ - `amount` (optional) - a percentage-style amount by which to saturate the color (adjusts the selected space's S channel in `"HSL"` space, or C channel in `"LCH"` space). Default is `10`.
498
+ - `space` (optional) - the color space to use for the saturation change: `"HSL" | "LCH"`. Default is `"HSL"`.
499
+ - `labScale` (optional) - when using `"LCH"`, the per-step delta applied to the chroma channel. The actual change is `(amount / 10) * labScale`. Defaults to `18`.
500
+
501
+ ```ts
502
+ const sky = new Color('hsl(200, 40%, 50%)');
503
+ sky.saturate().toHSLString(); // 'hsl(200 50% 50%)'
504
+ sky.saturate({ amount: 35 }).toHSLString(); // 'hsl(200 75% 50%)'
505
+ sky.saturate({ space: 'LCH' }).toHex(); // '#0096cf'
506
+ sky.saturate({ space: 'LCH', amount: 5, labScale: 8 }).toHex(); // '#3c92b9'
507
+ ```
508
+
509
+ #### `desaturate(options?: ColorSaturationOptions): Color`
510
+
511
+ - <ins>Returns</ins> a new [`Color`](#types-color) with decreased saturation. Alpha is preserved.
512
+ - <ins>Inputs</ins>:
513
+ - `options` (optional) - ColorSaturationOptions:
514
+ - `amount` (optional) - a percentage-style amount by which to desaturate the color (adjusts the selected space's S channel in `"HSL"` space, or C channel in `"LCH"` space). Default is `10`.
515
+ - `space` (optional) - the color space to use for the saturation decrease calculation: `"HSL" | "LCH"`. Default is `"HSL"`.
516
+ - `labScale` (optional) - when using `"LCH"`, the per-step delta applied to the chroma channel. The actual change is `(amount / 10) * labScale`. Defaults to `18`.
517
+
518
+ ```ts
519
+ const sky = new Color('hsl(200, 40%, 50%)');
520
+ sky.desaturate().toHSLString(); // 'hsl(200 30% 50%)'
521
+ sky.desaturate({ amount: 15 }).toHSLString(); // 'hsl(200 25% 50%)'
522
+ sky.desaturate({ space: 'LCH' }).toHex(); // '#7a8c97'
523
+ sky.desaturate({ space: 'LCH', amount: 5, labScale: 8 }).toHex(); // '#5a90ad'
524
+ ```
525
+
526
+ #### `grayscale(): Color`
527
+
528
+ - <ins>Returns</ins> a new [`Color`](#types-color) converted to grayscale while preserving lightness.
529
+
530
+ ```ts
531
+ new Color('#ff7f50').grayscale().toHex(); // '#a8a8a8'
532
+ new Color('rgba(255, 127, 80, 0.5)').grayscale().toHex8(); // '#a8a8a880'
533
+ ```
534
+
535
+ ### Color Combinations
536
+
537
+ #### `mixWith(others: Array<Color | ColorFormat | string>, options?: MixColorsOptions): Color`
538
+
539
+ - <ins>Returns</ins> a new [`Color`](#types-color) created by additively or subtractively mixing this color with additional colors. If `others` is empty, the original color will be returned.
540
+ - <ins>Inputs</ins>:
541
+ - `others` - one or more [`Color`](#types-color), [`ColorFormat`](#types-color-format), or parsable color inputs to mix with this color.
542
+ - `options` (optional) - `MixColorsOptions`:
543
+ - `space` - the mix space: `"LINEAR_RGB" | "RGB" | "HSL" | "LCH" | "OKLCH"`. Defaults to `"LINEAR_RGB"`.
544
+ - `type` - the mix type: `"ADDITIVE" | "SUBTRACTIVE"`. Defaults to `"ADDITIVE"`.
545
+ - `weights` - per-color weights for how much each color is weighted during mixing. Number of weights must match the number of colors being mixed (i.e. `others.length + 1`). Colors are weighted equally by default.
546
+
547
+ ```ts
548
+ const coral = new Color('#ff7f50');
549
+ const mixed = coral.mixWith(['red', '#00ff00', new Color('blue')]);
550
+ mixed.toHex(); // '#ffffff'
551
+ const weightedMix = coral.mixWith([new Color()], { space: 'LCH', weights: [2, 1] });
552
+ weightedMix.toHex(); // '#fffdd0'
553
+ ```
554
+
555
+ #### `blendWith(other: Color | ColorFormat | string, options?: BlendColorsOptions): Color`
556
+
557
+ - <ins>Returns</ins> a new [`Color`](#types-color) that blends this color with another.
558
+ - <ins>Inputs</ins>:
559
+ - `other` - the [`Color`](#types-color), [`ColorFormat`](#types-color-format), or parsable color input to blend with.
560
+ - `options` (optional) - `BlendColorsOptions`:
561
+ - `mode` - the blend mode: `"NORMAL" | "MULTIPLY" | "SCREEN" | "OVERLAY"`. Defaults to `"NORMAL"`.
562
+ - `space` - the blend space: `"RGB" | "HSL"`. Defaults to `"RGB"`.
563
+ - `ratio` - the blend ratio between `0` and `1` (default is `0.5`).
564
+
565
+ ```ts
566
+ new Color('#ff0000').blendWith('blue', { space: 'HSL' }); // '#ff00ff'
567
+ new Color('#00ff00').blendWith(new Color('#00ffff'), { mode: 'SCREEN', ratio: 0.25 }); // '#00ff40'
568
+ ```
569
+
570
+ #### `averageWith(others: Array<Color | ColorFormat | string>, options?: AverageColorsOptions): Color`
571
+
572
+ - <ins>Returns</ins> a new [`Color`](#types-color) averaging channel values with other colors.
573
+ - <ins>Inputs</ins>:
574
+ - `others` - one or more [`Color`](#types-color), [`ColorFormat`](#types-color-format), or parsable color inputs to average with this color.
575
+ - `options` (optional) - `AverageColorsOptions`:
576
+ - `space` - the averaging space: `"LINEAR_RGB" | "RGB" | "HSL" | "LCH" | "OKLCH"`. Defaults to `"LINEAR_RGB"`.
577
+ - `weights` - per-color weights for how much each color is weighted during averaging. Number of weights must match the number of colors being averaged (i.e. `others.length + 1`). Colors are weighted equally by default.
578
+ - alpha channels are averaged using the same normalized weights provided for channel averaging.
579
+
580
+ ```ts
581
+ const base = new Color('#ff0000');
582
+ base.averageWith([new Color('#00ff00'), new Color('#0000ff')], { space: 'RGB' }).toHex(); // '#555555'
583
+ ```
584
+
585
+ ### Perceptual Difference (Delta E)
586
+
587
+ Delta E calculations measure how visually different two colors appear.
588
+
589
+ #### `differenceFrom(other: Color | ColorFormat | string, options?: DeltaEOptions): number`
590
+
591
+ - <ins>Returns</ins> the Delta E value where higher numbers represent a more visible difference. The value depends on the algorithm used.
592
+ - <ins>Inputs</ins>:
593
+ - `other` - the [`Color`](#types-color), [`ColorFormat`](#types-color-format), or parsable color input to compare against.
594
+ - `options` (optional) - `DeltaEOptions`:
595
+ - `method` - the algorithm to use, either `"CIE76"`, `"CIE94"`, or `"CIEDE2000"` (default is `"CIEDE2000"`).
596
+ - `cie94Options` - optional inputs for the `"CIE94"` algorithm only (does not apply to any other selected `method`), `CIE94Options`:
597
+ - `kL` - lightness weighting factor. Defaults to `1`.
598
+ - `kC` - chroma weighting factor. Defaults to `1`.
599
+ - `kH` - hue weighting factor. Defaults to `1`.
600
+ - `K1` - chroma scaling constant. Defaults to `0.045`.
601
+ - `K2` - hue scaling constant. Defaults to `0.015`.
602
+ - `ciede2000Options` - optional inputs for the `"CIEDE2000"` algorithm only (does not apply to any other selected `method`), `CIEDE2000Options`:
603
+ - `kL` - lightness weighting factor. Defaults to `1`.
604
+ - `kC` - chroma weighting factor. Defaults to `1`.
605
+ - `kH` - hue weighting factor. Defaults to `1`.
606
+
607
+ ```ts
608
+ const base = new Color('#e63946');
609
+
610
+ base.differenceFrom(new Color('#e5383b')); // ~2.81 (CIEDE2000)
611
+ base.differenceFrom(new Color('#14a085'), { method: 'CIE76' }); // ~110.91
612
+ base.differenceFrom(new Color({ l: 70, c: 40, h: 210 }), { method: 'CIE94' }); // ~71.40
613
+ base.differenceFrom(new Color('#aa0000'), {
614
+ method: 'CIE94',
615
+ cie94Options: { kL: 2, kC: 1, kH: 1.5 },
616
+ }); // ~9.96
617
+ base.differenceFrom(new Color('#aa0000'), {
618
+ method: 'CIEDE2000',
619
+ ciede2000Options: { kL: 2, kC: 1, kH: 1.5 },
620
+ }); // ~15.27
621
+ ```
622
+
623
+ ### Gradients and Color Scales
624
+
625
+ #### `Color.createInterpolatedGradient(colors: Array<Color | ColorFormat | string>, options?: ColorGradientOptions): Color[]`
626
+
627
+ _`static`_
628
+
629
+ - <ins>Returns</ins> an array of new [`Color`](#types-color) instances interpolated between the provided anchors.
630
+ - <ins>Inputs</ins>:
631
+ - `colors` - two or more [`Color`](#types-color), [`ColorFormat`](#types-color-format), or parsable color inputs to interpolate between.
632
+ - **Fewer than 2 color inputs will throw an exception.**
633
+ - `options` (optional) - `ColorGradientOptions`:
634
+ - `stops` - number of colors to return (anchors included, defaults to `5`).
635
+ - `space` - interpolation space: `"RGB" | "HSL" | "HSV" | "LCH" | "OKLCH"` (default is `"OKLCH"`).
636
+ - `hueInterpolationMode` - strategy for hue interpolation in polar spaces: `"SHORTEST" | "LONGEST" | "INCREASING" | "DECREASING" | "RAW" | "CARTESIAN"` (default is `"SHORTEST"`).
637
+ - `interpolation` - `'LINEAR'` (segment-based) or `'BEZIER'` (uses anchors as control points). Defaults to `'LINEAR'`.
638
+ - `easing` - `"LINEAR" | "EASE_IN" | "EASE_OUT" | "EASE_IN_OUT"` or a custom `(t) => number` easing function. Defaults to `"LINEAR"`.
639
+ - `clamp` - keep intermediate stops inside the selected gamut (default `true`).
640
+
641
+ ```ts
642
+ const linearGradient = Color.createInterpolatedGradient(['#ff0000', '#00ff00', '#0000ff'], {
643
+ stops: 7,
644
+ space: 'OKLCH',
645
+ easing: 'EASE_IN_OUT',
646
+ });
647
+ linearGradient.map((color) => color.toHex());
648
+ // ['#ff0000', '#ef6c00', '#99da00', '#00ff00', '#00db86', '#006ee6', '#0000ff']
649
+
650
+ const bezierGradient = Color.createInterpolatedGradient(['#f43f5e', '#fbbf24', '#22d3ee'], {
651
+ stops: 5,
652
+ interpolation: 'BEZIER',
653
+ space: 'HSL',
654
+ });
655
+ bezierGradient.map((color) => color.toHex());
656
+ // ['#f43e5c', '#e16647', '#c1995e', '#70a67c', '#20d3ee']
657
+ ```
658
+
659
+ #### `createGradientThrough(colors: Array<Color | ColorFormat | string>, options?: ColorGradientOptions): Color[]`
660
+
661
+ - <ins>Returns</ins> an array of new [`Color`](#types-color) instances interpolated through the provided anchors, ensuring every anchor is included as a stop.
662
+ - <ins>Inputs</ins>:
663
+ - `colors` - two or more [`Color`](#types-color), [`ColorFormat`](#types-color-format), or parsable color inputs to pass through.
664
+ - `options` (optional) - `ColorGradientOptions` (same as [`Color.createInterpolatedGradient`](#colorcreateinterpolatedgradientcolors-arraycolor--colorformat--string-options-colorgradientoptions-color), inheriting defaults of `space: "OKLCH"`, `interpolation: "LINEAR"`, and `easing: "LINEAR"`).
665
+
666
+ ```ts
667
+ const throughGradient = Color.createGradientThrough(['#ff7f50', '#1a73e8', '#10b981'], {
668
+ stops: 6,
669
+ });
670
+ throughGradient.map((color) => color.toHex());
671
+ // ['#ff7f50', '#d04e8d', '#9b44c4', '#4d66da', '#26a1b4', '#10b981']
672
+ ```
673
+
674
+ #### `createGradientTo(color: Color | ColorFormat | string, options?: ColorGradientOptions): Color[]`
675
+
676
+ - <ins>Returns</ins> an array of new [`Color`](#types-color) instances interpolated from the current color to the target color.
677
+ - <ins>Inputs</ins>:
678
+ - `color` - the destination [`Color`](#types-color), [`ColorFormat`](#types-color-format), or parsable color input.
679
+ - `options` (optional) - gradient options excluding `interpolation`, forwarded to [`Color.createInterpolatedGradient`](#colorcreateinterpolatedgradientcolors-arraycolor--colorformat--string-options-colorgradientoptions-color); defaults still apply (`space: "OKLCH"`, `easing: "LINEAR"`).
680
+
681
+ ```ts
682
+ const [start, end] = new Color('#3b82f6').createGradientTo('#f472b6', { stops: 2 });
683
+ start.toHex(); // '#3b82f6'
684
+ end.toHex(); // '#f472b6'
685
+ ```
686
+
687
+ ### Color Harmonies
688
+
689
+ #### `getComplementaryColors(options?: ColorHarmonyOptions): [Color, Color]`
690
+
691
+ - <ins>Returns</ins> the base [`Color`](#types-color) and its complementary [`Color`](#types-color) (hues 180° apart).
692
+ - <ins>Inputs</ins>:
693
+ - `options` (optional) - `ColorHarmonyOptions`:
694
+ - `grayscaleHandlingMode` - [`GrayscaleHandlingMode`](#types-grayscale-handling-mode) behavior for grayscale inputs (default is `'SPIN_LIGHTNESS'`).
695
+
696
+ ```ts
697
+ const [base, complement] = new Color('#ff0000').getComplementaryColors();
698
+ base.toHex(); // '#ff0000'
699
+ complement.toHex(); // '#00ffff'
700
+ ```
701
+
702
+ #### `getSplitComplementaryColors(options?: ColorHarmonyOptions): [Color, Color, Color]`
703
+
704
+ - <ins>Returns</ins> the base [`Color`](#types-color) plus two [`Color`](#types-color) hues adjacent to its complement (rotated ±30° from 180°).
705
+ - <ins>Inputs</ins>:
706
+ - `options` (optional) - `ColorHarmonyOptions`:
707
+ - `grayscaleHandlingMode` - [`GrayscaleHandlingMode`](#types-grayscale-handling-mode) behavior for grayscale inputs (default is `'SPIN_LIGHTNESS'`).
708
+
709
+ ```ts
710
+ const [base, split1, split2] = new Color('#ff0000').getSplitComplementaryColors();
711
+ base.toHex(); // '#ff0000'
712
+ split1.toHex(); // '#0080ff'
713
+ split2.toHex(); // '#00ff80'
714
+ ```
715
+
716
+ #### `getTriadicHarmonyColors(options?: ColorHarmonyOptions): [Color, Color, Color]`
717
+
718
+ - <ins>Returns</ins> three evenly spaced [`Color`](#types-color) hues 120° apart on the color wheel.
719
+ - <ins>Inputs</ins>:
720
+ - `options` (optional) - `ColorHarmonyOptions`:
721
+ - `grayscaleHandlingMode` - [`GrayscaleHandlingMode`](#types-grayscale-handling-mode) behavior for grayscale inputs (default is `'SPIN_LIGHTNESS'`).
722
+
723
+ ```ts
724
+ const [base, triad1, triad2] = new Color('#ff0000').getTriadicHarmonyColors();
725
+ base.toHex(); // '#ff0000'
726
+ triad1.toHex(); // '#0000ff'
727
+ triad2.toHex(); // '#00ff00'
728
+ ```
729
+
730
+ #### `getSquareHarmonyColors(options?: ColorHarmonyOptions): [Color, Color, Color, Color]`
731
+
732
+ - <ins>Returns</ins> four [`Color`](#types-color) hues forming a square on the color wheel (90° apart).
733
+ - <ins>Inputs</ins>:
734
+ - `options` (optional) - `ColorHarmonyOptions`:
735
+ - `grayscaleHandlingMode` - [`GrayscaleHandlingMode`](#types-grayscale-handling-mode) behavior for grayscale inputs (default is `'SPIN_LIGHTNESS'`).
736
+
737
+ ```ts
738
+ const [base, square1, square2, square3] = new Color('#ff0000').getSquareHarmonyColors();
739
+ base.toHex(); // '#ff0000'
740
+ square1.toHex(); // '#80ff00'
741
+ square2.toHex(); // '#00ffff'
742
+ square3.toHex(); // '#8000ff'
743
+ ```
744
+
745
+ #### `getTetradicHarmonyColors(options?: ColorHarmonyOptions): [Color, Color, Color, Color]`
746
+
747
+ - <ins>Returns</ins> a rectangular harmony of four [`Color`](#types-color) instances made of two complementary pairs.
748
+ - <ins>Inputs</ins>:
749
+ - `options` (optional) - `ColorHarmonyOptions`:
750
+ - `grayscaleHandlingMode` - [`GrayscaleHandlingMode`](#types-grayscale-handling-mode) behavior for grayscale inputs (default is `'SPIN_LIGHTNESS'`).
751
+
752
+ ```ts
753
+ const [base, tetrad1, tetrad2, tetrad3] = new Color('#ff0000').getTetradicHarmonyColors();
754
+ base.toHex(); // '#ff0000'
755
+ tetrad1.toHex(); // '#ffff00'
756
+ tetrad2.toHex(); // '#00ffff'
757
+ tetrad3.toHex(); // '#0000ff'
758
+ ```
759
+
760
+ #### `getAnalogousHarmonyColors(options?: ColorHarmonyOptions): [Color, Color, Color, Color, Color]`
761
+
762
+ - <ins>Returns</ins> five neighboring [`Color`](#types-color) hues around the base color (±30° steps).
763
+ - <ins>Inputs</ins>:
764
+ - `options` (optional) - `ColorHarmonyOptions`:
765
+ - `grayscaleHandlingMode` - [`GrayscaleHandlingMode`](#types-grayscale-handling-mode) behavior for grayscale inputs (default is `'SPIN_LIGHTNESS'`).
766
+
767
+ ```ts
768
+ const [base, analogous1, analogous2, analogous3, analogous4] = new Color(
769
+ '#ff0000'
770
+ ).getAnalogousHarmonyColors();
771
+ base.toHex(); // '#ff0000'
772
+ analogous1.toHex(); // '#ff0080'
773
+ analogous2.toHex(); // '#ff8000'
774
+ analogous3.toHex(); // '#ff00ff'
775
+ analogous4.toHex(); // '#ffff00'
776
+ ```
777
+
778
+ #### `getMonochromaticHarmonyColors(): [Color, Color, Color, Color, Color]`
779
+
780
+ - <ins>Returns</ins> five [`Color`](#types-color) variants of the base hue with differing lightness and saturation.
781
+
782
+ ```ts
783
+ const [base, mono1, mono2, mono3, mono4] = new Color('#ff0000').getMonochromaticHarmonyColors();
784
+ base.toHex(); // '#ff0000'
785
+ mono1.toHex(); // '#ff6666'
786
+ mono2.toHex(); // '#990000'
787
+ mono3.toHex(); // '#ff0000'
788
+ mono4.toHex(); // '#e61919'
789
+ ```
790
+
791
+ #### `getHarmonyColors(harmony: ColorHarmony, options?: ColorHarmonyOptions): Color[]`
792
+
793
+ - <ins>Returns</ins> new [`Color`](#types-color) instances generated by the specified `ColorHarmony` algorithm.
794
+ - <ins>Inputs</ins>:
795
+ - `harmony` - one of `"COMPLEMENTARY" | "SPLIT_COMPLEMENTARY" | "TRIADIC" | "SQUARE" | "TETRADIC" | "ANALOGOUS" | "MONOCHROMATIC"`.
796
+ - `options` (optional) - `ColorHarmonyOptions`:
797
+ - `grayscaleHandlingMode` - [`GrayscaleHandlingMode`](#types-grayscale-handling-mode) behavior for grayscale inputs (default is `'SPIN_LIGHTNESS'`).
798
+
799
+ ```ts
800
+ new Color('#ff7f50').getHarmonyColors('TRIADIC').map((color) => color.toHex());
801
+ // ['#ff7f50', '#507fff', '#50ff7f']
802
+ ```
803
+
804
+ ### Swatches and Palettes
805
+
806
+ #### `getColorSwatch(options?: ColorSwatchOptions): ColorSwatch`
807
+
808
+ - <ins>Returns</ins> a [`ColorSwatch`](#types-color-swatch) of lighter and darker variants keyed `100`–`900`, reporting the anchored stop via `mainStop`. When `extended` is `true`, returns instead an [`ExtendedColorSwatch`](#types-extended-color-swatch) with half-steps `50`–`950` are added without moving the base color to a half-stop; otherwise, [`BaseColorSwatch`](#types-base-color-swatch).
809
+ - <ins>Inputs</ins>:
810
+ - `options` (optional) - `ColorSwatchOptions`:
811
+ - `centerOn500` - force the original color onto the `500` stop instead of dynamically anchoring by lightness (default is `false`).
812
+ - `extended` - set to `true` to include midpoint stops `50`–`950` and return an [`ExtendedColorSwatch`](#types-extended-color-swatch). Defaults to `false` (basic stops only).
813
+
814
+ ```ts
815
+ const green = new Color('green');
816
+ const swatch = green.getColorSwatch({ centerOn500: true });
817
+ swatch.mainStop; // 500
818
+ swatch[500].equals(green); // true
819
+ swatch[100].toHex(); // lightest
820
+ swatch[900].toHex(); // darkest
821
+
822
+ const extendedSwatch = new Color('#008000').getColorSwatch({ extended: true });
823
+ extendedSwatch.mainStop; // 700
824
+ extendedSwatch[700].equals('#008000'); // true
825
+ extendedSwatch[50].toHex(); // lightest
826
+ extendedSwatch[500].toHex(); // middle
827
+ extendedSwatch[950].toHex(); // darkest
828
+ ```
829
+
830
+ #### `getColorPalette(harmony = 'COMPLEMENTARY', options?: GenerateColorPaletteOptions): ColorPalette`
831
+
832
+ - <ins>Returns</ins> a complete [`ColorPalette`](#types-color-palette) containing the primary swatch, secondary swatches from the chosen harmony, neutral/tinted neutrals, and semantic swatches (`info`, `positive`, `negative`, `warning`, `special`).
833
+ - <ins>Inputs</ins>:
834
+ - `harmony` (optional) - [`ColorHarmony`](#types-color-harmony) used to generate secondary colors (defaults to `'COMPLEMENTARY'`).
835
+ - `options` (optional) - `GenerateColorPaletteOptions`:
836
+ - `neutralHarmonization` - `tintChromaFactor` (fraction of chroma applied to neutrals) and `maxTintChroma` cap. Defaults to `{ tintChromaFactor: 0.1, maxTintChroma: 0.04 }`.
837
+ - `semanticHarmonization` - `huePull` (blend semantic hues toward the base hue) and `chromaRange` bounds for semantic swatches. Defaults to `{ huePull: 0.1, chromaRange: [0.02, 0.25] }`.
838
+ - `swatchOptions` - forwarded to swatch generation for every palette color; palettes center the source color on `500` by default, override `centerOn500` to opt into dynamic anchoring.
839
+
840
+ ```ts
841
+ const palette = new Color('#ff7f50').getColorPalette('ANALOGOUS', {
842
+ neutralHarmonization: { tintChromaFactor: 0.12 },
843
+ semanticHarmonization: { huePull: 0.35 },
844
+ swatchOptions: { centerOn500: false },
845
+ });
846
+ palette.info[500].toHex(); // '#9d40d4'
847
+ ```
848
+
849
+ ### Readability and Accessibility
850
+
851
+ **_omni-color_** supports two readability algorithms:
852
+
853
+ - <ins>WCAG 2.x contrast ratio</ins> (`getWCAGContrastRatio`, `getWCAGReadabilityReport`, `isReadableAsTextColor`) for established pass/fail conformance checks. WCAG stands for *Web Content Accessibility Guidelines* (W3C).
854
+ - <ins>APCA Lc score</ins> (`getAPCAReadabilityScore`, `getAPCAReadabilityReport`) for directional contrast analysis. APCA stands for *Advanced Perceptual Contrast Algorithm*. APCA is still draft guidance for WCAG 3, so this library defaults APCA to *advisory mode* unless you opt into a threshold policy.
855
+
856
+ Reference resources:
857
+
858
+ - WCAG 2.2 specification: https://www.w3.org/TR/WCAG22/
859
+ - WCAG Understanding SC 1.4.3 (Contrast Minimum): https://www.w3.org/WAI/WCAG22/Understanding/contrast-minimum.html
860
+ - APCA project repository (used for ongoing algorithm drafts): https://github.com/Myndex/apca-w3
861
+ - APCA documentation index: https://git.apcacontrast.com/documentation/
862
+
863
+ #### `getWCAGContrastRatio(color: Color | ColorFormat | string): number`
864
+
865
+ - <ins>Returns</ins> the WCAG contrast ratio against another color (alpha-aware).
866
+ - <ins>Inputs</ins>:
867
+ - `color` - the background [`Color`](#types-color), [`ColorFormat`](#types-color-format), or parsable color input.
868
+
869
+ ```ts
870
+ new Color('#000000').getWCAGContrastRatio('#ffffff'); // 21
871
+ ```
872
+
873
+ #### `getAPCAReadabilityScore(background: Color | ColorFormat | string): number`
874
+
875
+ **Note:** This implementation uses the `0.0.98G-4g` constants from the draft APCA recommendations published via the APCA project. As WCAG 3 is not yet finalized, this score is experimental and provided for advisory use only.
876
+
877
+ - <ins>Returns</ins> the signed APCA readability score (Lc) against a background color.
878
+ - <ins>Inputs</ins>:
879
+ - `background` - the background [`Color`](#types-color), [`ColorFormat`](#types-color-format), or parsable color input.
880
+
881
+ ```ts
882
+ new Color('#1a73e8').getAPCAReadabilityScore('#ffffff'); // e.g. 71.61
883
+ ```
884
+
885
+ #### `getAPCAReadabilityReport(background: Color | ColorFormat | string, options?: APCAReadabilityOptions): APCAReadabilityReport`
886
+
887
+ - <ins>Returns</ins> APCA score metadata: `{ score, absoluteScore, isReadable, requiredLc, shortfall }`.
888
+ - <ins>Inputs</ins>:
889
+ - `background` - the background [`Color`](#types-color), [`ColorFormat`](#types-color-format), or parsable color input.
890
+ - `options` (optional) - `APCAReadabilityOptions`:
891
+ - `policy` - `'NONE' | 'PRESET' | 'CUSTOM'` (default: `'NONE'`).
892
+ - `'NONE'` is advisory-only: `isReadable`, `requiredLc`, and `shortfall` are `null`.
893
+ - `'PRESET'` uses a named threshold via `preset`.
894
+ - `'CUSTOM'` uses an explicit numeric Lc threshold via `threshold`.
895
+ - `preset` - `'BODY' | 'LARGE_TEXT' | 'NON_TEXT' | 'VERY_LOW_VISION'` (default: `'BODY'` when policy is `'PRESET'`).
896
+ - `threshold` - custom required absolute Lc when policy is `'CUSTOM'`.
897
+
898
+ ```ts
899
+ const textColor = new Color('#4b5563');
900
+
901
+ // Advisory APCA (default): no pass/fail classification
902
+ textColor.getAPCAReadabilityReport('#ffffff');
903
+ // { score: 51.42, absoluteScore: 51.42, isReadable: null, requiredLc: null, shortfall: null }
904
+
905
+ // Preset threshold policy
906
+ textColor.getAPCAReadabilityReport('#ffffff', { policy: 'PRESET', preset: 'BODY' });
907
+ // { ..., isReadable: false, requiredLc: 60, shortfall: 8.58 }
908
+
909
+ // Custom threshold policy
910
+ textColor.getAPCAReadabilityReport('#ffffff', { policy: 'CUSTOM', threshold: 45 });
911
+ // { ..., isReadable: true, requiredLc: 45, shortfall: 0 }
912
+ ```
913
+
914
+ #### `getWCAGReadabilityReport(background: Color | ColorFormat | string, options?: WCAGReadabilityOptions): WCAGReadabilityReport`
915
+
916
+ - <ins>Returns</ins> `{ contrastRatio, requiredContrast, isReadable, shortfall }` for WCAG levels `"AA" | "AAA"` and text sizes `"SMALL" | "LARGE"`.
917
+ - <ins>Inputs</ins>:
918
+ - `background` - the background [`Color`](#types-color), [`ColorFormat`](#types-color-format), or parsable color input.
919
+ - `options` (optional) - `WCAGReadabilityOptions` specifying WCAG level (`"AA" | "AAA"`) and text size (`"SMALL" | "LARGE"`). Defaults to `level: "AA"` and `size: "SMALL"`.
920
+
921
+ ```ts
922
+ new Color('#444').getWCAGReadabilityReport(new Color('#bbb'), { level: 'AA', size: 'LARGE' });
923
+ // { contrastRatio: 5.07, requiredContrast: 3, isReadable: true, shortfall: 0 }
924
+ ```
925
+
926
+ #### `isReadableAsTextColor(background: Color | ColorFormat | string, options?: ReadabilityOptions): boolean`
927
+
928
+ - <ins>Returns</ins> readability pass/fail (`true` or `false`) for the selected algorithm.
929
+ - <ins>Inputs</ins>:
930
+ - `background` - the background [`Color`](#types-color), [`ColorFormat`](#types-color-format), or parsable color input.
931
+ - `options` (optional) - `ReadabilityOptions`:
932
+ - `algorithm` - `'WCAG' | 'APCA'` (defaults to `'WCAG'`).
933
+ - `wcagOptions` - WCAG level/size options used only when algorithm is `'WCAG'`.
934
+ - `apcaOptions` - APCA policy options used only when algorithm is `'APCA'`. If omitted or advisory (`policy: 'NONE'`), this method uses a default APCA pass threshold of `BODY` (`Lc >= 60`).
935
+
936
+ ```ts
937
+ new Color('#000000').isReadableAsTextColor('#ffffff'); // true
938
+ new Color('#000000').isReadableAsTextColor('#ffffff', { algorithm: 'APCA' }); // true
939
+ new Color('#000000').isReadableAsTextColor('#ffffff', {
940
+ algorithm: 'APCA',
941
+ apcaOptions: { policy: 'PRESET', preset: 'BODY' },
942
+ }); // true
943
+ ```
944
+
945
+ #### `getMostReadableTextColor(candidateTextColors: Array<Color | ColorFormat | string> | ColorSwatch, options?: ReadabilityOptions): Color`
946
+
947
+ - <ins>Returns</ins> the candidate [`Color`](#types-color) with the strongest readability against the current color used as the background.
948
+ - <ins>Inputs</ins>:
949
+ - `candidateTextColors` - one or more candidate text colors as [`Color`](#types-color), [`ColorFormat`](#types-color-format), parsable color inputs, or a [`ColorSwatch`](#types-color-swatch) to choose from.
950
+ - **Empty list of candidate colors will throw an exception.**
951
+ - `options` (optional) - `ReadabilityOptions` to choose between `"WCAG"` contrast or `"APCA"` scoring. You can pass `wcagOptions` for WCAG and/or `apcaOptions` for APCA policy (`'NONE'`, `'PRESET'`, `'CUSTOM'`). Defaults to `"WCAG"` contrast.
952
+
953
+ ```ts
954
+ const background = new Color('#121212');
955
+ const text = background.getMostReadableTextColor(['#ffffff', '#bbbbbb', '#00ffd0']);
956
+ text.toHex(); // '#ffffff'
957
+
958
+ const bestSwatchColor = background.getMostReadableTextColor(
959
+ new Color('#2563eb').getColorSwatch({ extended: true })
960
+ );
961
+ bestSwatchColor.toHex(); // '#f5f8ff'
962
+ ```
963
+
964
+ #### `getBestBackgroundColor(candidateBackgroundColors: Array<Color | ColorFormat | string> | ColorSwatch, options?: ReadabilityOptions): Color`
965
+
966
+ - <ins>Returns</ins> the background [`Color`](#types-color) that maximizes readability for the current color used as text.
967
+ - <ins>Inputs</ins>:
968
+ - `candidateBackgroundColors` - one or more candidate background colors as [`Color`](#types-color), [`ColorFormat`](#types-color-format), parsable color inputs, or a [`ColorSwatch`](#types-color-swatch) to choose from.
969
+ - **Empty list of candidate colors will throw an exception.**
970
+ - `options` (optional) - `ReadabilityOptions` to choose between `"WCAG"` contrast or `"APCA"` scoring. You can pass `wcagOptions` for WCAG and/or `apcaOptions` for APCA policy (`'NONE'`, `'PRESET'`, `'CUSTOM'`). Defaults to `"WCAG"` contrast.
971
+
972
+ ```ts
973
+ const textColor = new Color('#ff7f50');
974
+ const background = textColor.getBestBackgroundColor(['#0d0d0d', '#1c1c1c', '#2a2a2a']);
975
+ background.toHex(); // '#0d0d0d'
976
+
977
+ const bestSwatchBackground = textColor.getBestBackgroundColor(
978
+ textColor.getColorSwatch({ extended: true })
979
+ );
980
+ bestSwatchBackground.toHex(); // '#301308'
981
+ ```
982
+
983
+ ### Types
984
+
985
+ - <span id="types-color">`Color`</span> - the main, immutable color instance.
986
+ - <span id="types-base-color-name">`BaseColorName`</span> - base hue color names: `"Red" | "Orange" | "Yellow" | "Green" | "Blue" | "Purple" | "Pink" | "Black" | "Gray" | "White"`.
987
+ - <span id="types-color-format">`ColorFormat`</span> - any of the following supported color formats:
988
+ - <span id="types-color-hex">`ColorHex`</span> - a string of the form `#rrggbb` or `#rrggbbaa` (not case-sensitive).
989
+ - <span id="types-color-rgb">`ColorRGB`</span> - red, green, and blue channels. `{ r: number; g: number; b: number }` where `r`, `g`, and `b` are integers between 0 and 255.
990
+ - <span id="types-color-rgba">`ColorRGBA`</span> - same as [`ColorRGB`](#types-color-rgb) but with an alpha channel. `{ r: number; g: number; b: number; a: number }` where `r`, `g`, and `b` are integers between 0 and 255 and `a` is a number between 0 and 1.
991
+ - <span id="types-color-hsl">`ColorHSL`</span> - hue, saturation, and lightness channels. `{ h: number; s: number; l: number }` where `h` is a number between 0 and 360 (degrees), and `s` and `l` are numbers between 0 and 100 (percentages).
992
+ - <span id="types-color-hsla">`ColorHSLA`</span> - same as [`ColorHSL`](#types-color-hsl) but with an alpha channel. `{ h: number; s: number; l: number; a: number }` where `h` is a number between 0 and 360 (degrees), `s` and `l` are numbers between 0 and 100 (percentages), and `a` is a number between 0 and 1.
993
+ - <span id="types-color-hsv">`ColorHSV`</span> - hue, saturation, and value channels. `{ h: number; s: number; v: number }` where `h` is a number between 0 and 360 (degrees), and `s` and `v` are numbers between 0 and 100 (percentages).
994
+ - <span id="types-color-hsva">`ColorHSVA`</span> - same as [`ColorHSV`](#types-color-hsv) but with an alpha channel. `{ h: number; s: number; v: number; a: number }` where `h` is a number between 0 and 360 (degrees), `s` and `v` are numbers between 0 and 100 (percentages), and `a` is a number between 0 and 1.
995
+ - <span id="types-color-hwb">`ColorHWB`</span> - hue, whiteness, and blackness channels. `{ h: number; w: number; b: number }` where `h` is a number between 0 and 360 (degrees), and `w` and `b` are numbers between 0 and 100 (percentages).
996
+ - <span id="types-color-hwba">`ColorHWBA`</span> - same as [`ColorHWB`](#types-color-hwb) but with an alpha channel. `{ h: number; w: number; b: number; a: number }` where `h` is a number between 0 and 360 (degrees), `w` and `b` are numbers between 0 and 100 (percentages), and `a` is a number between 0 and 1.
997
+ - <span id="types-color-cmyk">`ColorCMYK`</span> - cyan, magenta, yellow, and key (black) channels. `{ c: number; m: number; y: number; k: number }` where `c`, `m`, `y`, and `k` are numbers between 0 and 100 (percentages).
998
+ - <span id="types-color-lab">`ColorLAB`</span> - CIELAB color space with lightness and color-opponent dimensions. `{ l: number; a: number; b: number }` where `l` is a number between 0 and 100 (lightness), and `a` and `b` are numbers typically between -128 and 127 (color-opponent dimensions).
999
+ - <span id="types-color-oklab">`ColorOKLAB`</span> - OKLAB color space with lightness and color-opponent dimensions. `{ l: number; a: number; b: number }` where `l` is a number between 0 and 1 (lightness), and `a` and `b` are numbers typically between -0.4 and 0.4 (color-opponent dimensions).
1000
+ - <span id="types-color-lch">`ColorLCH`</span> - CIELCh color space with lightness, chroma, and hue. `{ l: number; c: number; h: number }` where `l` is a number between 0 and 100 (lightness), `c` is a number representing chroma (typically 0–150+), and `h` is a number between 0 and 360 (hue in degrees).
1001
+ - <span id="types-color-oklch">`ColorOKLCH`</span> - OKLCH color space with lightness, chroma, and hue. `{ l: number; c: number; h: number }` where `l` is a number between 0 and 1 (lightness), `c` is a number representing chroma (typically 0–0.4), and `h` is a number between 0 and 360 (hue in degrees).
1002
+ - <span id="types-color-space">`ColorSpace`</span> - supported color spaces for `Color.toColorString()`: `"SRGB" | "DISPLAY-P3" | "REC2020"`.
1003
+ - <span id="types-color-temperature-label">`ColorTemperatureLabel`</span> - color temperature options: `"Candlelight" | "Incandescent lamp" | "Halogen lamp" | "Fluorescent lamp" | "Daylight" | "Cloudy sky" | "Shade" | "Blue sky"`
1004
+ - <span id="types-base-color-swatch">`BaseColorSwatch`</span> - a swatch representing shades of the same color from 100 to 900 `{ 100: number; 200 number; ... 900: number }` where `100` is the lightest shade and `900` is the darkest shade.
1005
+ - <span id="types-extended-color-swatch">`ExtendedColorSwatch`</span> - same as a [`ColorSwatch`](#types-color-swatch) but includes half-shades at 50, 100, 150, ..., 950. It is a superset of [`ColorSwatch`](#types-color-swatch).
1006
+ - <span id="types-color-swatch">`ColorSwatch`</span> - `BaseColorSwatch | ExtendedColorSwatch`.
1007
+ - <span id="types-color-palette">`ColorPalette`</span> - a collection of [`ColorSwatch`](#types-color-swatch)es representing a color palette for a specified [`ColorHarmony`](#types-color-harmony). Includes a `primary` swatch for the main (base) color, `secondaryColors` swatches depending on the color harmony, and swatches for `neutrals`, `tintedNeutrals` (neutrals slightly tinted towards the main color), and swatches for semantic colors `info`, `negative`, `positive`, `special`, and `warning`.
1008
+ - <span id="types-color-harmony">`ColorHarmony`</span> - a type of color harmony to generate [`ColorPalette`](#types-color-palette): `"COMPLEMENTARY" | "SPLIT_COMPLEMENTARY" | "TRIADIC" | "SQUARE" | "TETRADIC" | "ANALOGOUS" | "MONOCHROMATIC"`
1009
+ - <span id="types-grayscale-handling-mode">`GrayscaleHandlingMode`</span> - how hue rotations handle grayscale inputs: `"SPIN_LIGHTNESS" | "IGNORE"`.
1010
+
1011
+ ---
1012
+
1013
+ ## 🛠 Dev
1014
+
1015
+ ### First-Time Setup
1016
+
1017
+ From the project's <ins>root directory</ins>:
1018
+
1019
+ 1. `npx simple-git-hooks` - run once to initiate the pre-commit checks that will run automatically.
1020
+
1021
+ ### Run Demo
1022
+
1023
+ From the project's <ins>root directory</ins>:
1024
+
1025
+ - `npm install` - install library dependencies.
1026
+ - `npm run install:demo` - install demo dependencies.
1027
+ - `npm run dev:demo` - run the demo locally.
1028
+
1029
+ _GitHub actions will automatically update the live demo on merges to the `main` branch._
1030
+
1031
+ ### Run Tests and Checks
1032
+
1033
+ From the project's <ins>root directory</ins>:
1034
+
1035
+ - Run tests:
1036
+ - `npm run test` - run all tests.
1037
+ - `npm run test:watch` - run all tests in watch mode.
1038
+ - `npm run test -- src/color/__test__/validations.test.ts` - run a specific test file.
1039
+ - `npm run lint` - run linter.
1040
+ - `npm run lint:fix` - run linter with auto-fixes (for example import sorting) before committing.
1041
+ - `npm run typecheck` - run TS type checker.
1042
+ - `npm run format:check` - run Prettier code format checker.