@tokens-studio/tokenscript-schemas 0.0.11 → 0.0.13

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 (307) hide show
  1. package/dist/cli/index.cjs +31 -8
  2. package/dist/cli/index.cjs.map +1 -1
  3. package/dist/cli/index.js +30 -8
  4. package/dist/cli/index.js.map +1 -1
  5. package/package.json +2 -1
  6. package/src/bundler/bundle-schema.ts +146 -0
  7. package/src/bundler/index.ts +151 -0
  8. package/src/bundler/schema-dependency-resolver.ts +299 -0
  9. package/src/bundler/selective-bundler.test.ts +94 -0
  10. package/src/bundler/selective-bundler.ts +159 -0
  11. package/src/bundler/types.ts +93 -0
  12. package/src/bundler/utils.ts +74 -0
  13. package/src/cli/commands/bundle.integration.test.ts +153 -0
  14. package/src/cli/commands/bundle.test.ts +57 -0
  15. package/src/cli/commands/bundle.ts +237 -0
  16. package/src/cli/commands/list.ts +109 -0
  17. package/src/cli/config-schema.ts +36 -0
  18. package/src/cli/index.ts +50 -0
  19. package/src/cli/output-generator.ts +63 -0
  20. package/src/downloader/index.ts +248 -0
  21. package/src/downloader/types.ts +48 -0
  22. package/src/index.ts +8 -0
  23. package/src/schemas/functions/adjust_chroma/adjust-chroma.tokenscript +27 -0
  24. package/src/schemas/functions/adjust_chroma/schema.json +48 -0
  25. package/src/schemas/functions/adjust_chroma/unit.test.ts +76 -0
  26. package/src/schemas/functions/adjust_hue/adjust-hue.tokenscript +32 -0
  27. package/src/schemas/functions/adjust_hue/schema.json +48 -0
  28. package/src/schemas/functions/adjust_hue/unit.test.ts +68 -0
  29. package/src/schemas/functions/adjust_lightness/adjust-lightness.tokenscript +31 -0
  30. package/src/schemas/functions/adjust_lightness/schema.json +48 -0
  31. package/src/schemas/functions/adjust_lightness/unit.test.ts +88 -0
  32. package/src/schemas/functions/adjust_to_contrast/adjust-to-contrast.tokenscript +131 -0
  33. package/src/schemas/functions/adjust_to_contrast/schema.json +56 -0
  34. package/src/schemas/functions/adjust_to_contrast/unit.test.ts +81 -0
  35. package/src/schemas/functions/alpha_blend/alpha-blend.tokenscript +46 -0
  36. package/src/schemas/functions/alpha_blend/schema.json +28 -0
  37. package/src/schemas/functions/alpha_blend/unit.test.ts +135 -0
  38. package/src/schemas/functions/alpha_scale/alpha-scale.tokenscript +38 -0
  39. package/src/schemas/functions/alpha_scale/schema.json +24 -0
  40. package/src/schemas/functions/alpha_scale/unit.test.ts +50 -0
  41. package/src/schemas/functions/analogous/analogous.tokenscript +47 -0
  42. package/src/schemas/functions/analogous/schema.json +28 -0
  43. package/src/schemas/functions/analogous/unit.test.ts +64 -0
  44. package/src/schemas/functions/apca_contrast/apca-contrast.tokenscript +129 -0
  45. package/src/schemas/functions/apca_contrast/schema.json +24 -0
  46. package/src/schemas/functions/apca_contrast/unit.test.ts +259 -0
  47. package/src/schemas/functions/are_similar/are-similar.tokenscript +24 -0
  48. package/src/schemas/functions/are_similar/schema.json +57 -0
  49. package/src/schemas/functions/are_similar/unit.test.ts +57 -0
  50. package/src/schemas/functions/auto_text_color/auto-text-color.tokenscript +41 -0
  51. package/src/schemas/functions/auto_text_color/schema.json +53 -0
  52. package/src/schemas/functions/auto_text_color/unit.test.ts +122 -0
  53. package/src/schemas/functions/best_contrast/best-contrast.tokenscript +66 -0
  54. package/src/schemas/functions/best_contrast/schema.json +24 -0
  55. package/src/schemas/functions/best_contrast/unit.test.ts +64 -0
  56. package/src/schemas/functions/chroma/chroma.tokenscript +12 -0
  57. package/src/schemas/functions/chroma/schema.json +44 -0
  58. package/src/schemas/functions/chroma/unit.test.ts +86 -0
  59. package/src/schemas/functions/clamp_chroma/clamp-chroma.tokenscript +21 -0
  60. package/src/schemas/functions/clamp_chroma/schema.json +52 -0
  61. package/src/schemas/functions/clamp_chroma/unit.test.ts +60 -0
  62. package/src/schemas/functions/clamp_lightness/clamp-lightness.tokenscript +21 -0
  63. package/src/schemas/functions/clamp_lightness/schema.json +52 -0
  64. package/src/schemas/functions/clamp_lightness/unit.test.ts +76 -0
  65. package/src/schemas/functions/clamp_to_gamut/clamp-to-gamut.tokenscript +41 -0
  66. package/src/schemas/functions/clamp_to_gamut/schema.json +20 -0
  67. package/src/schemas/functions/clamp_to_gamut/unit.test.ts +167 -0
  68. package/src/schemas/functions/complement/complement.tokenscript +21 -0
  69. package/src/schemas/functions/complement/schema.json +20 -0
  70. package/src/schemas/functions/complement/unit.test.ts +81 -0
  71. package/src/schemas/functions/contrast_ratio/contrast-ratio.tokenscript +36 -0
  72. package/src/schemas/functions/contrast_ratio/schema.json +24 -0
  73. package/src/schemas/functions/contrast_ratio/unit.test.ts +91 -0
  74. package/src/schemas/functions/cooler/cooler.tokenscript +45 -0
  75. package/src/schemas/functions/cooler/schema.json +43 -0
  76. package/src/schemas/functions/cooler/unit.test.ts +69 -0
  77. package/src/schemas/functions/darken/darken.tokenscript +37 -0
  78. package/src/schemas/functions/darken/schema.json +24 -0
  79. package/src/schemas/functions/darken/unit.test.ts +105 -0
  80. package/src/schemas/functions/delta_e_2000/delta-e-2000.tokenscript +184 -0
  81. package/src/schemas/functions/delta_e_2000/schema.json +36 -0
  82. package/src/schemas/functions/delta_e_2000/unit.test.ts +243 -0
  83. package/src/schemas/functions/delta_e_76/delta-e-76.tokenscript +45 -0
  84. package/src/schemas/functions/delta_e_76/schema.json +24 -0
  85. package/src/schemas/functions/delta_e_76/unit.test.ts +123 -0
  86. package/src/schemas/functions/delta_e_ok/delta-e-ok.tokenscript +43 -0
  87. package/src/schemas/functions/delta_e_ok/schema.json +24 -0
  88. package/src/schemas/functions/delta_e_ok/unit.test.ts +235 -0
  89. package/src/schemas/functions/desaturate/desaturate.tokenscript +32 -0
  90. package/src/schemas/functions/desaturate/schema.json +24 -0
  91. package/src/schemas/functions/desaturate/unit.test.ts +54 -0
  92. package/src/schemas/functions/distributed/distributed.tokenscript +54 -0
  93. package/src/schemas/functions/distributed/schema.json +32 -0
  94. package/src/schemas/functions/distributed/unit.test.ts +58 -0
  95. package/src/schemas/functions/diverging/diverging.tokenscript +58 -0
  96. package/src/schemas/functions/diverging/schema.json +32 -0
  97. package/src/schemas/functions/diverging/unit.test.ts +70 -0
  98. package/src/schemas/functions/grayscale/grayscale.tokenscript +17 -0
  99. package/src/schemas/functions/grayscale/schema.json +20 -0
  100. package/src/schemas/functions/grayscale/unit.test.ts +79 -0
  101. package/src/schemas/functions/harmonize/harmonize.tokenscript +61 -0
  102. package/src/schemas/functions/harmonize/schema.json +52 -0
  103. package/src/schemas/functions/harmonize/unit.test.ts +56 -0
  104. package/src/schemas/functions/hue/hue.tokenscript +12 -0
  105. package/src/schemas/functions/hue/schema.json +44 -0
  106. package/src/schemas/functions/hue/unit.test.ts +75 -0
  107. package/src/schemas/functions/hue_difference/hue-difference.tokenscript +42 -0
  108. package/src/schemas/functions/hue_difference/schema.json +24 -0
  109. package/src/schemas/functions/hue_difference/unit.test.ts +125 -0
  110. package/src/schemas/functions/in_gamut/in-gamut.tokenscript +51 -0
  111. package/src/schemas/functions/in_gamut/schema.json +24 -0
  112. package/src/schemas/functions/in_gamut/unit.test.ts +178 -0
  113. package/src/schemas/functions/interpolate/interpolate.tokenscript +61 -0
  114. package/src/schemas/functions/interpolate/schema.json +52 -0
  115. package/src/schemas/functions/interpolate/unit.test.ts +96 -0
  116. package/src/schemas/functions/invert/invert-initializer.tokenscript +29 -0
  117. package/src/schemas/functions/invert/schema.json +20 -0
  118. package/src/schemas/functions/invert/unit.test.ts +216 -0
  119. package/src/schemas/functions/is_cool/is-cool.tokenscript +41 -0
  120. package/src/schemas/functions/is_cool/schema.json +20 -0
  121. package/src/schemas/functions/is_cool/unit.test.ts +189 -0
  122. package/src/schemas/functions/is_dark/is-dark.tokenscript +16 -0
  123. package/src/schemas/functions/is_dark/schema.json +24 -0
  124. package/src/schemas/functions/is_dark/unit.test.ts +87 -0
  125. package/src/schemas/functions/is_light/is-light.tokenscript +16 -0
  126. package/src/schemas/functions/is_light/schema.json +24 -0
  127. package/src/schemas/functions/is_light/unit.test.ts +86 -0
  128. package/src/schemas/functions/is_neutral/is-neutral.tokenscript +16 -0
  129. package/src/schemas/functions/is_neutral/schema.json +53 -0
  130. package/src/schemas/functions/is_neutral/unit.test.ts +85 -0
  131. package/src/schemas/functions/is_warm/is-warm.tokenscript +62 -0
  132. package/src/schemas/functions/is_warm/schema.json +20 -0
  133. package/src/schemas/functions/is_warm/unit.test.ts +161 -0
  134. package/src/schemas/functions/lighten/lighten.tokenscript +37 -0
  135. package/src/schemas/functions/lighten/schema.json +24 -0
  136. package/src/schemas/functions/lighten/unit.test.ts +109 -0
  137. package/src/schemas/functions/lightness/lightness.tokenscript +12 -0
  138. package/src/schemas/functions/lightness/schema.json +49 -0
  139. package/src/schemas/functions/lightness/unit.test.ts +99 -0
  140. package/src/schemas/functions/luminance/luminance.tokenscript +16 -0
  141. package/src/schemas/functions/luminance/schema.json +20 -0
  142. package/src/schemas/functions/luminance/unit.test.ts +105 -0
  143. package/src/schemas/functions/meets_contrast/meets-contrast.tokenscript +49 -0
  144. package/src/schemas/functions/meets_contrast/schema.json +28 -0
  145. package/src/schemas/functions/meets_contrast/unit.test.ts +170 -0
  146. package/src/schemas/functions/mix/mix.tokenscript +47 -0
  147. package/src/schemas/functions/mix/schema.json +28 -0
  148. package/src/schemas/functions/mix/unit.test.ts +95 -0
  149. package/src/schemas/functions/monochromatic/monochromatic.tokenscript +72 -0
  150. package/src/schemas/functions/monochromatic/schema.json +24 -0
  151. package/src/schemas/functions/monochromatic/unit.test.ts +91 -0
  152. package/src/schemas/functions/muted/muted.tokenscript +25 -0
  153. package/src/schemas/functions/muted/schema.json +48 -0
  154. package/src/schemas/functions/muted/unit.test.ts +100 -0
  155. package/src/schemas/functions/neutral_variant/neutral-variant.tokenscript +23 -0
  156. package/src/schemas/functions/neutral_variant/schema.json +48 -0
  157. package/src/schemas/functions/neutral_variant/unit.test.ts +102 -0
  158. package/src/schemas/functions/relative_luminance/relative-luminance.tokenscript +15 -0
  159. package/src/schemas/functions/relative_luminance/schema.json +49 -0
  160. package/src/schemas/functions/relative_luminance/unit.test.ts +104 -0
  161. package/src/schemas/functions/rotate_hue/rotate-hue.tokenscript +20 -0
  162. package/src/schemas/functions/rotate_hue/schema.json +24 -0
  163. package/src/schemas/functions/rotate_hue/unit.test.ts +86 -0
  164. package/src/schemas/functions/saturate/saturate.tokenscript +33 -0
  165. package/src/schemas/functions/saturate/schema.json +24 -0
  166. package/src/schemas/functions/saturate/unit.test.ts +59 -0
  167. package/src/schemas/functions/scale_chroma/scale-chroma.tokenscript +22 -0
  168. package/src/schemas/functions/scale_chroma/schema.json +48 -0
  169. package/src/schemas/functions/scale_chroma/unit.test.ts +79 -0
  170. package/src/schemas/functions/scale_lightness/scale-lightness.tokenscript +23 -0
  171. package/src/schemas/functions/scale_lightness/schema.json +48 -0
  172. package/src/schemas/functions/scale_lightness/unit.test.ts +73 -0
  173. package/src/schemas/functions/sepia/schema.json +48 -0
  174. package/src/schemas/functions/sepia/sepia.tokenscript +54 -0
  175. package/src/schemas/functions/sepia/unit.test.ts +88 -0
  176. package/src/schemas/functions/set_chroma/schema.json +24 -0
  177. package/src/schemas/functions/set_chroma/set-chroma.tokenscript +18 -0
  178. package/src/schemas/functions/set_chroma/unit.test.ts +79 -0
  179. package/src/schemas/functions/set_hue/schema.json +24 -0
  180. package/src/schemas/functions/set_hue/set-hue.tokenscript +18 -0
  181. package/src/schemas/functions/set_hue/unit.test.ts +90 -0
  182. package/src/schemas/functions/set_lightness/schema.json +24 -0
  183. package/src/schemas/functions/set_lightness/set-lightness.tokenscript +18 -0
  184. package/src/schemas/functions/set_lightness/unit.test.ts +80 -0
  185. package/src/schemas/functions/shade_scale/schema.json +24 -0
  186. package/src/schemas/functions/shade_scale/shade-scale.tokenscript +61 -0
  187. package/src/schemas/functions/shade_scale/unit.test.ts +64 -0
  188. package/src/schemas/functions/split_complement/schema.json +24 -0
  189. package/src/schemas/functions/split_complement/split-complement.tokenscript +38 -0
  190. package/src/schemas/functions/split_complement/unit.test.ts +53 -0
  191. package/src/schemas/functions/steps/schema.json +28 -0
  192. package/src/schemas/functions/steps/steps.tokenscript +54 -0
  193. package/src/schemas/functions/steps/unit.test.ts +71 -0
  194. package/src/schemas/functions/tetradic/schema.json +20 -0
  195. package/src/schemas/functions/tetradic/tetradic.tokenscript +40 -0
  196. package/src/schemas/functions/tetradic/unit.test.ts +50 -0
  197. package/src/schemas/functions/tint_scale/schema.json +32 -0
  198. package/src/schemas/functions/tint_scale/tint-scale.tokenscript +71 -0
  199. package/src/schemas/functions/tint_scale/unit.test.ts +64 -0
  200. package/src/schemas/functions/to_gamut/schema.json +48 -0
  201. package/src/schemas/functions/to_gamut/to-gamut.tokenscript +96 -0
  202. package/src/schemas/functions/to_gamut/unit.test.ts +97 -0
  203. package/src/schemas/functions/triadic/schema.json +20 -0
  204. package/src/schemas/functions/triadic/triadic.tokenscript +33 -0
  205. package/src/schemas/functions/triadic/unit.test.ts +64 -0
  206. package/src/schemas/functions/vibrant/schema.json +48 -0
  207. package/src/schemas/functions/vibrant/unit.test.ts +55 -0
  208. package/src/schemas/functions/vibrant/vibrant.tokenscript +29 -0
  209. package/src/schemas/functions/warmer/schema.json +43 -0
  210. package/src/schemas/functions/warmer/unit.test.ts +69 -0
  211. package/src/schemas/functions/warmer/warmer.tokenscript +45 -0
  212. package/src/schemas/functions/wcag_level/schema.json +48 -0
  213. package/src/schemas/functions/wcag_level/unit.test.ts +75 -0
  214. package/src/schemas/functions/wcag_level/wcag-level.tokenscript +50 -0
  215. package/src/schemas/types/css-color/from-hsl-color.tokenscript +16 -0
  216. package/src/schemas/types/css-color/from-hwb-color.tokenscript +16 -0
  217. package/src/schemas/types/css-color/from-lab-color.tokenscript +16 -0
  218. package/src/schemas/types/css-color/from-lch-color.tokenscript +16 -0
  219. package/src/schemas/types/css-color/from-oklab-color.tokenscript +16 -0
  220. package/src/schemas/types/css-color/from-oklch-color.tokenscript +16 -0
  221. package/src/schemas/types/css-color/from-p3-color.tokenscript +16 -0
  222. package/src/schemas/types/css-color/from-rgb-color.tokenscript +15 -0
  223. package/src/schemas/types/css-color/from-srgb-color.tokenscript +16 -0
  224. package/src/schemas/types/css-color/from-srgb-linear-color.tokenscript +16 -0
  225. package/src/schemas/types/css-color/from-xyz-d50-color.tokenscript +16 -0
  226. package/src/schemas/types/css-color/from-xyz-d65-color.tokenscript +16 -0
  227. package/src/schemas/types/css-color/initializer.tokenscript +13 -0
  228. package/src/schemas/types/css-color/schema.json +148 -0
  229. package/src/schemas/types/css-color/unit.test.ts +402 -0
  230. package/src/schemas/types/hex-color/initializer.tokenscript +3 -0
  231. package/src/schemas/types/hex-color/schema.json +24 -0
  232. package/src/schemas/types/hex-color/unit.test.ts +123 -0
  233. package/src/schemas/types/hsl-color/from-srgb.tokenscript +87 -0
  234. package/src/schemas/types/hsl-color/initializer.tokenscript +16 -0
  235. package/src/schemas/types/hsl-color/schema.json +48 -0
  236. package/src/schemas/types/hsl-color/unit.test.ts +201 -0
  237. package/src/schemas/types/hsv-color/from-srgb.tokenscript +80 -0
  238. package/src/schemas/types/hsv-color/initializer.tokenscript +16 -0
  239. package/src/schemas/types/hsv-color/schema.json +48 -0
  240. package/src/schemas/types/hsv-color/unit.test.ts +162 -0
  241. package/src/schemas/types/hwb-color/from-hsv.tokenscript +31 -0
  242. package/src/schemas/types/hwb-color/initializer.tokenscript +16 -0
  243. package/src/schemas/types/hwb-color/schema.json +48 -0
  244. package/src/schemas/types/hwb-color/unit.test.ts +150 -0
  245. package/src/schemas/types/lab-color/from-xyz-d50.tokenscript +78 -0
  246. package/src/schemas/types/lab-color/initializer.tokenscript +16 -0
  247. package/src/schemas/types/lab-color/schema.json +48 -0
  248. package/src/schemas/types/lab-color/unit.test.ts +263 -0
  249. package/src/schemas/types/lch-color/from-lab.tokenscript +44 -0
  250. package/src/schemas/types/lch-color/initializer.tokenscript +16 -0
  251. package/src/schemas/types/lch-color/schema.json +48 -0
  252. package/src/schemas/types/lch-color/unit.test.ts +173 -0
  253. package/src/schemas/types/okhsl-color/from-oklab.tokenscript +410 -0
  254. package/src/schemas/types/okhsl-color/initializer.tokenscript +24 -0
  255. package/src/schemas/types/okhsl-color/schema.json +48 -0
  256. package/src/schemas/types/okhsl-color/unit.test.ts +514 -0
  257. package/src/schemas/types/okhsv-color/from-oklab.tokenscript +286 -0
  258. package/src/schemas/types/okhsv-color/initializer.tokenscript +24 -0
  259. package/src/schemas/types/okhsv-color/schema.json +48 -0
  260. package/src/schemas/types/okhsv-color/unit.test.ts +499 -0
  261. package/src/schemas/types/oklab-color/from-okhsl.tokenscript +195 -0
  262. package/src/schemas/types/oklab-color/from-okhsv.tokenscript +197 -0
  263. package/src/schemas/types/oklab-color/from-oklch.tokenscript +39 -0
  264. package/src/schemas/types/oklab-color/from-xyz-d65.tokenscript +43 -0
  265. package/src/schemas/types/oklab-color/initializer.tokenscript +16 -0
  266. package/src/schemas/types/oklab-color/schema.json +78 -0
  267. package/src/schemas/types/oklab-color/unit.test.ts +345 -0
  268. package/src/schemas/types/oklch-color/from-oklab.tokenscript +45 -0
  269. package/src/schemas/types/oklch-color/initializer.tokenscript +16 -0
  270. package/src/schemas/types/oklch-color/schema.json +48 -0
  271. package/src/schemas/types/oklch-color/unit.test.ts +267 -0
  272. package/src/schemas/types/p3-color/from-p3-linear.tokenscript +59 -0
  273. package/src/schemas/types/p3-color/initializer.tokenscript +16 -0
  274. package/src/schemas/types/p3-color/schema.json +48 -0
  275. package/src/schemas/types/p3-color/unit.test.ts +119 -0
  276. package/src/schemas/types/p3-linear-color/from-xyz-d65.tokenscript +47 -0
  277. package/src/schemas/types/p3-linear-color/initializer.tokenscript +16 -0
  278. package/src/schemas/types/p3-linear-color/schema.json +48 -0
  279. package/src/schemas/types/p3-linear-color/unit.test.ts +82 -0
  280. package/src/schemas/types/rgb-color/from-hex.tokenscript +43 -0
  281. package/src/schemas/types/rgb-color/initializer.tokenscript +16 -0
  282. package/src/schemas/types/rgb-color/schema.json +55 -0
  283. package/src/schemas/types/rgb-color/to-hex.tokenscript +42 -0
  284. package/src/schemas/types/rgb-color/unit.test.ts +302 -0
  285. package/src/schemas/types/srgb-color/from-hsl.tokenscript +106 -0
  286. package/src/schemas/types/srgb-color/from-linear.tokenscript +58 -0
  287. package/src/schemas/types/srgb-color/from-rgb.tokenscript +20 -0
  288. package/src/schemas/types/srgb-color/initializer.tokenscript +16 -0
  289. package/src/schemas/types/srgb-color/schema.json +68 -0
  290. package/src/schemas/types/srgb-color/unit.test.ts +303 -0
  291. package/src/schemas/types/srgb-linear-color/from-srgb.tokenscript +55 -0
  292. package/src/schemas/types/srgb-linear-color/from-xyz-d65.tokenscript +34 -0
  293. package/src/schemas/types/srgb-linear-color/initializer.tokenscript +13 -0
  294. package/src/schemas/types/srgb-linear-color/schema.json +58 -0
  295. package/src/schemas/types/srgb-linear-color/unit.test.ts +291 -0
  296. package/src/schemas/types/xyz-d50-color/from-xyz-d65.tokenscript +36 -0
  297. package/src/schemas/types/xyz-d50-color/initializer.tokenscript +16 -0
  298. package/src/schemas/types/xyz-d50-color/schema.json +48 -0
  299. package/src/schemas/types/xyz-d50-color/unit.test.ts +240 -0
  300. package/src/schemas/types/xyz-d65-color/from-linear-p3.tokenscript +47 -0
  301. package/src/schemas/types/xyz-d65-color/from-linear-srgb.tokenscript +38 -0
  302. package/src/schemas/types/xyz-d65-color/from-oklab.tokenscript +44 -0
  303. package/src/schemas/types/xyz-d65-color/initializer.tokenscript +16 -0
  304. package/src/schemas/types/xyz-d65-color/schema.json +68 -0
  305. package/src/schemas/types/xyz-d65-color/unit.test.ts +319 -0
  306. package/src/utils/schema-uri.ts +192 -0
  307. package/src/utils/type.ts +194 -0
@@ -0,0 +1,259 @@
1
+ import { executeWithSchema } from "@tests/helpers/schema-test-utils";
2
+ import Color from "colorjs.io";
3
+ import { describe, expect, it } from "vitest";
4
+
5
+ describe("APCA Contrast Function", () => {
6
+ describe("Schema Definition", () => {
7
+ it("should have correct schema structure", async () => {
8
+ const { getBundledSchema } = await import("@tests/helpers/schema-test-utils");
9
+ const schema = await getBundledSchema("apca_contrast", "function");
10
+
11
+ expect(schema.name).toBe("APCA Contrast");
12
+ expect(schema.type).toBe("function");
13
+ expect((schema as any).keyword).toBe("apca_contrast");
14
+ });
15
+ });
16
+
17
+ describe("Basic Contrast Calculations", () => {
18
+ it("should return high positive contrast for black text on white background", async () => {
19
+ // Black text on white background = dark on light = POSITIVE Lc
20
+ const result = await executeWithSchema(
21
+ "apca_contrast",
22
+ "function",
23
+ `
24
+ variable text: Color.SRGB;
25
+ text.r = 0; text.g = 0; text.b = 0;
26
+ variable bg: Color.SRGB;
27
+ bg.r = 1; bg.g = 1; bg.b = 1;
28
+ apca_contrast(text, bg)
29
+ `,
30
+ );
31
+
32
+ expect(typeof result.value).toBe("number");
33
+ expect(result.value).toBeGreaterThan(100); // Should be around +106
34
+ });
35
+
36
+ it("should return high negative contrast for white text on black background", async () => {
37
+ // White text on black background = light on dark = NEGATIVE Lc
38
+ const result = await executeWithSchema(
39
+ "apca_contrast",
40
+ "function",
41
+ `
42
+ variable text: Color.SRGB;
43
+ text.r = 1; text.g = 1; text.b = 1;
44
+ variable bg: Color.SRGB;
45
+ bg.r = 0; bg.g = 0; bg.b = 0;
46
+ apca_contrast(text, bg)
47
+ `,
48
+ );
49
+
50
+ expect(typeof result.value).toBe("number");
51
+ expect(result.value).toBeLessThan(-100); // Should be around -108
52
+ });
53
+
54
+ it("should return zero contrast for identical colors", async () => {
55
+ const result = await executeWithSchema(
56
+ "apca_contrast",
57
+ "function",
58
+ `
59
+ variable text: Color.SRGB;
60
+ text.r = 0.5; text.g = 0.5; text.b = 0.5;
61
+ variable bg: Color.SRGB;
62
+ bg.r = 0.5; bg.g = 0.5; bg.b = 0.5;
63
+ apca_contrast(text, bg)
64
+ `,
65
+ );
66
+
67
+ expect(result.value).toBeCloseTo(0, 1);
68
+ });
69
+ });
70
+
71
+ describe("Polarity (BoW vs WoB)", () => {
72
+ it("should return positive for dark text on light background", async () => {
73
+ // Dark on light = POSITIVE (per APCA spec)
74
+ const result = await executeWithSchema(
75
+ "apca_contrast",
76
+ "function",
77
+ `
78
+ variable text: Color.SRGB;
79
+ text.r = 0.2; text.g = 0.2; text.b = 0.2;
80
+ variable bg: Color.SRGB;
81
+ bg.r = 0.9; bg.g = 0.9; bg.b = 0.9;
82
+ apca_contrast(text, bg)
83
+ `,
84
+ );
85
+
86
+ expect(result.value).toBeGreaterThan(0);
87
+ });
88
+
89
+ it("should return negative for light text on dark background", async () => {
90
+ // Light on dark = NEGATIVE (per APCA spec)
91
+ const result = await executeWithSchema(
92
+ "apca_contrast",
93
+ "function",
94
+ `
95
+ variable text: Color.SRGB;
96
+ text.r = 0.9; text.g = 0.9; text.b = 0.9;
97
+ variable bg: Color.SRGB;
98
+ bg.r = 0.2; bg.g = 0.2; bg.b = 0.2;
99
+ apca_contrast(text, bg)
100
+ `,
101
+ );
102
+
103
+ expect(result.value).toBeLessThan(0);
104
+ });
105
+ });
106
+
107
+ describe("Color.js Parity", () => {
108
+ // Note: In Color.js, colorObj.contrast(other, "APCA") treats:
109
+ // - colorObj as BACKGROUND
110
+ // - other as FOREGROUND (text)
111
+ // Our apca_contrast(text, bg) uses opposite order:
112
+ // - text as FOREGROUND
113
+ // - bg as BACKGROUND
114
+ // So apca_contrast(A, B) should match B.contrast(A, "APCA")
115
+
116
+ it("should match Color.js APCA for black text on white background", async () => {
117
+ const result = await executeWithSchema(
118
+ "apca_contrast",
119
+ "function",
120
+ `
121
+ variable text: Color.SRGB;
122
+ text.r = 0; text.g = 0; text.b = 0;
123
+ variable bg: Color.SRGB;
124
+ bg.r = 1; bg.g = 1; bg.b = 1;
125
+ apca_contrast(text, bg)
126
+ `,
127
+ );
128
+
129
+ // apca_contrast(black, white) = black text on white bg
130
+ // In Color.js: white.contrast(black, "APCA") = black fg on white bg
131
+ const white = new Color("srgb", [1, 1, 1]);
132
+ const black = new Color("srgb", [0, 0, 0]);
133
+ const colorJsApca = white.contrast(black, "APCA");
134
+
135
+ expect(result.value).toBeCloseTo(colorJsApca, 0);
136
+ });
137
+
138
+ it("should match Color.js APCA for white text on black background", async () => {
139
+ const result = await executeWithSchema(
140
+ "apca_contrast",
141
+ "function",
142
+ `
143
+ variable text: Color.SRGB;
144
+ text.r = 1; text.g = 1; text.b = 1;
145
+ variable bg: Color.SRGB;
146
+ bg.r = 0; bg.g = 0; bg.b = 0;
147
+ apca_contrast(text, bg)
148
+ `,
149
+ );
150
+
151
+ // apca_contrast(white, black) = white text on black bg
152
+ // In Color.js: black.contrast(white, "APCA") = white fg on black bg
153
+ const white = new Color("srgb", [1, 1, 1]);
154
+ const black = new Color("srgb", [0, 0, 0]);
155
+ const colorJsApca = black.contrast(white, "APCA");
156
+
157
+ expect(result.value).toBeCloseTo(colorJsApca, 0);
158
+ });
159
+
160
+ it("should match Color.js APCA for blue text on light gray", async () => {
161
+ const result = await executeWithSchema(
162
+ "apca_contrast",
163
+ "function",
164
+ `
165
+ variable text: Color.SRGB;
166
+ text.r = 0.2; text.g = 0.4; text.b = 0.8;
167
+ variable bg: Color.SRGB;
168
+ bg.r = 0.95; bg.g = 0.95; bg.b = 0.95;
169
+ apca_contrast(text, bg)
170
+ `,
171
+ );
172
+
173
+ // apca_contrast(blue, lightGray) = blue text on lightGray bg
174
+ // In Color.js: lightGray.contrast(blue, "APCA")
175
+ const blue = new Color("srgb", [0.2, 0.4, 0.8]);
176
+ const lightGray = new Color("srgb", [0.95, 0.95, 0.95]);
177
+ const colorJsApca = lightGray.contrast(blue, "APCA");
178
+
179
+ expect(result.value).toBeCloseTo(colorJsApca, 0);
180
+ });
181
+
182
+ it("should match Color.js APCA for mid-contrast scenario", async () => {
183
+ const result = await executeWithSchema(
184
+ "apca_contrast",
185
+ "function",
186
+ `
187
+ variable text: Color.SRGB;
188
+ text.r = 0.4; text.g = 0.4; text.b = 0.4;
189
+ variable bg: Color.SRGB;
190
+ bg.r = 0.8; bg.g = 0.8; bg.b = 0.8;
191
+ apca_contrast(text, bg)
192
+ `,
193
+ );
194
+
195
+ const darkGray = new Color("srgb", [0.4, 0.4, 0.4]);
196
+ const lightGray = new Color("srgb", [0.8, 0.8, 0.8]);
197
+ // darkGray text on lightGray bg → lightGray.contrast(darkGray)
198
+ const colorJsApca = lightGray.contrast(darkGray, "APCA");
199
+
200
+ expect(result.value).toBeCloseTo(colorJsApca, 0);
201
+ });
202
+ });
203
+
204
+ describe("WCAG 3.0 Threshold Guidelines", () => {
205
+ it("should meet body text threshold (|Lc| >= 60) for dark gray on white", async () => {
206
+ const result = await executeWithSchema(
207
+ "apca_contrast",
208
+ "function",
209
+ `
210
+ variable text: Color.SRGB;
211
+ text.r = 0.3; text.g = 0.3; text.b = 0.3;
212
+ variable bg: Color.SRGB;
213
+ bg.r = 1; bg.g = 1; bg.b = 1;
214
+ apca_contrast(text, bg)
215
+ `,
216
+ );
217
+
218
+ // Dark gray on white should be positive and meet body text requirements
219
+ expect(result.value).toBeGreaterThan(60);
220
+ });
221
+ });
222
+
223
+ describe("Edge Cases", () => {
224
+ it("should handle very dark colors (soft black clamp)", async () => {
225
+ const result = await executeWithSchema(
226
+ "apca_contrast",
227
+ "function",
228
+ `
229
+ variable text: Color.SRGB;
230
+ text.r = 0.01; text.g = 0.01; text.b = 0.01;
231
+ variable bg: Color.SRGB;
232
+ bg.r = 0.02; bg.g = 0.02; bg.b = 0.02;
233
+ apca_contrast(text, bg)
234
+ `,
235
+ );
236
+
237
+ // Very dark colors should still produce a valid result
238
+ expect(typeof result.value).toBe("number");
239
+ expect(Number.isFinite(result.value)).toBe(true);
240
+ });
241
+
242
+ it("should work with chromatic colors", async () => {
243
+ const result = await executeWithSchema(
244
+ "apca_contrast",
245
+ "function",
246
+ `
247
+ variable text: Color.SRGB;
248
+ text.r = 0.8; text.g = 0.2; text.b = 0.2;
249
+ variable bg: Color.SRGB;
250
+ bg.r = 0.2; bg.g = 0.6; bg.b = 0.2;
251
+ apca_contrast(text, bg)
252
+ `,
253
+ );
254
+
255
+ expect(typeof result.value).toBe("number");
256
+ expect(Number.isFinite(result.value)).toBe(true);
257
+ });
258
+ });
259
+ });
@@ -0,0 +1,24 @@
1
+ // are_similar: Check if two colors are perceptually similar
2
+ // Uses Delta E OK (OKLab Euclidean distance) for perceptual comparison
3
+ // Default threshold 0.02 approximates "just noticeable difference"
4
+
5
+ variable input: List = {input};
6
+ variable color1: Color.OKLab = input.get(0).to.oklab();
7
+ variable color2: Color.OKLab = input.get(1).to.oklab();
8
+
9
+ // Default threshold for JND (just noticeable difference)
10
+ variable threshold: Number = 0.02;
11
+ if (input.length() > 2) [
12
+ threshold = input.get(2);
13
+ ];
14
+
15
+ // Calculate Delta E OK (Euclidean distance in OKLab)
16
+ variable delta_l: Number = color1.l - color2.l;
17
+ variable delta_a: Number = color1.a - color2.a;
18
+ variable delta_b: Number = color1.b - color2.b;
19
+
20
+ variable delta_e: Number = sqrt(delta_l * delta_l + delta_a * delta_a + delta_b * delta_b);
21
+
22
+ // Return true if within threshold
23
+ return delta_e <= threshold;
24
+
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "are_similar",
3
+ "type": "function",
4
+ "description": "Determines if two colors are perceptually similar using Delta E OK (Euclidean distance in OKLab space). Returns true if the colors are within the specified threshold. Default threshold of 0.02 corresponds to a 'just noticeable difference' (JND). Based on Björn Ottosson's OKLab color space which provides excellent perceptual uniformity.",
5
+ "keyword": "are_similar",
6
+ "requirements": ["/api/v1/core/srgb-color/0/", "/api/v1/core/oklab-color/0/"],
7
+ "schema": {
8
+ "type": "object",
9
+ "properties": {
10
+ "input": {
11
+ "type": "array",
12
+ "items": [
13
+ {
14
+ "description": "First color",
15
+ "type": "color"
16
+ },
17
+ {
18
+ "description": "Second color",
19
+ "type": "color"
20
+ },
21
+ {
22
+ "description": "Delta E threshold (default 0.02 ≈ JND)",
23
+ "type": "number"
24
+ }
25
+ ],
26
+ "minItems": 2,
27
+ "maxItems": 3
28
+ }
29
+ },
30
+ "required": ["input"]
31
+ },
32
+ "returns": {
33
+ "type": "boolean",
34
+ "description": "True if colors are perceptually similar (within threshold)"
35
+ },
36
+ "script": {
37
+ "type": "https://schema.tokenscript.dev.gcp.tokens.studio/api/v1/core/tokenscript/0/",
38
+ "script": "./are-similar.tokenscript"
39
+ },
40
+ "examples": [
41
+ {
42
+ "description": "Nearly identical colors",
43
+ "input": ["#ff0000", "#ff0001"],
44
+ "output": true
45
+ },
46
+ {
47
+ "description": "Obviously different colors",
48
+ "input": ["#ff0000", "#00ff00"],
49
+ "output": false
50
+ },
51
+ {
52
+ "description": "Custom threshold for stricter comparison",
53
+ "input": ["#808080", "#818181", 0.01],
54
+ "output": true
55
+ }
56
+ ]
57
+ }
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Unit tests for the are_similar function
3
+ * Checks if two colors are perceptually similar
4
+ */
5
+
6
+ import { executeWithSchema, getBundledSchema } from "@tests/helpers/schema-test-utils";
7
+ import { describe, expect, it } from "vitest";
8
+ import type { FunctionSpecification } from "@/bundler/types";
9
+
10
+ describe("are_similar function", () => {
11
+ describe("Schema Definition", () => {
12
+ it("should have correct schema structure", async () => {
13
+ const schema = (await getBundledSchema("are_similar", "function")) as FunctionSpecification;
14
+
15
+ expect(schema.name).toBe("are_similar");
16
+ expect(schema.type).toBe("function");
17
+ });
18
+ });
19
+
20
+ describe("Function Execution", () => {
21
+ it("should return true for identical colors", async () => {
22
+ const result = await executeWithSchema(
23
+ "are_similar",
24
+ "function",
25
+ `
26
+ variable c1: Color.SRGB;
27
+ c1.r = 0.5; c1.g = 0.5; c1.b = 0.5;
28
+ variable c2: Color.SRGB;
29
+ c2.r = 0.5; c2.g = 0.5; c2.b = 0.5;
30
+ are_similar(c1, c2)
31
+ `,
32
+ );
33
+
34
+ expect(result).toBeDefined();
35
+ const similar = (result as any).value ?? result;
36
+ expect(similar).toBe(true);
37
+ });
38
+
39
+ it("should return false for obviously different colors", async () => {
40
+ const result = await executeWithSchema(
41
+ "are_similar",
42
+ "function",
43
+ `
44
+ variable red: Color.SRGB;
45
+ red.r = 1; red.g = 0; red.b = 0;
46
+ variable green: Color.SRGB;
47
+ green.r = 0; green.g = 1; green.b = 0;
48
+ are_similar(red, green)
49
+ `,
50
+ );
51
+
52
+ expect(result).toBeDefined();
53
+ const similar = (result as any).value ?? result;
54
+ expect(similar).toBe(false);
55
+ });
56
+ });
57
+ });
@@ -0,0 +1,41 @@
1
+ // auto_text_color: Select black or white text for optimal contrast
2
+ // Reference: WCAG 2.1 Relative Luminance
3
+ // Reference: https://www.w3.org/TR/WCAG21/#dfn-relative-luminance
4
+ //
5
+ // Returns black (#000) or white (#fff) depending on which provides
6
+ // better contrast against the input background color.
7
+ //
8
+ // Default threshold: 0.179 (geometric mean of WCAG luminance range)
9
+ // - sqrt(1.05 * 0.05) - 0.05 ≈ 0.179
10
+ // - Above threshold: light background → black text
11
+ // - Below threshold: dark background → white text
12
+
13
+ variable input: List = {input};
14
+
15
+ // Default threshold based on WCAG luminance midpoint
16
+ variable threshold: Number = 0.179;
17
+ if (input.length() > 1) [
18
+ threshold = input.get(1);
19
+ ];
20
+
21
+ // Convert to XYZ-D65 to get relative luminance (Y component)
22
+ variable xyz: Color.XYZD65 = input.get(0).to.xyzd65();
23
+ variable luminance: Number = xyz.y;
24
+
25
+ // If luminance is above threshold, background is "light" -> use black text
26
+ // If luminance is below threshold, background is "dark" -> use white text
27
+ variable result: Color.SRGB;
28
+
29
+ if (luminance > threshold) [
30
+ // Light background: return black
31
+ result.r = 0;
32
+ result.g = 0;
33
+ result.b = 0;
34
+ ] else [
35
+ // Dark background: return white
36
+ result.r = 1;
37
+ result.g = 1;
38
+ result.b = 1;
39
+ ];
40
+
41
+ return result;
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "auto_text_color",
3
+ "type": "function",
4
+ "description": "Returns black or white text color for optimal contrast against a background. Uses WCAG relative luminance to determine if the background is light or dark, then returns the opposite for maximum readability. Essential for generating accessible text colors in design systems.",
5
+ "keyword": "auto_text_color",
6
+ "requirements": ["/api/v1/core/srgb-color/0/", "/api/v1/core/xyz-d65-color/0/"],
7
+ "schema": {
8
+ "type": "object",
9
+ "properties": {
10
+ "input": {
11
+ "type": "array",
12
+ "items": [
13
+ {
14
+ "description": "Background color to test",
15
+ "type": "color"
16
+ },
17
+ {
18
+ "description": "Optional threshold (0-1, default 0.179 per WCAG). Higher values bias toward white text.",
19
+ "type": "number"
20
+ }
21
+ ],
22
+ "minItems": 1,
23
+ "maxItems": 2
24
+ }
25
+ },
26
+ "required": ["input"]
27
+ },
28
+ "returns": {
29
+ "type": "color",
30
+ "description": "Either black (#000000) or white (#ffffff) for optimal contrast"
31
+ },
32
+ "script": {
33
+ "type": "https://schema.tokenscript.dev.gcp.tokens.studio/api/v1/core/tokenscript/0/",
34
+ "script": "./auto-text-color.tokenscript"
35
+ },
36
+ "examples": [
37
+ {
38
+ "description": "Dark background returns white text",
39
+ "input": ["#1a1a1a"],
40
+ "output": "#ffffff"
41
+ },
42
+ {
43
+ "description": "Light background returns black text",
44
+ "input": ["#f0f0f0"],
45
+ "output": "#000000"
46
+ },
47
+ {
48
+ "description": "Mid-tone with custom threshold",
49
+ "input": ["#808080", 0.5],
50
+ "output": "#ffffff"
51
+ }
52
+ ]
53
+ }
@@ -0,0 +1,122 @@
1
+ /**
2
+ * Unit tests for the auto_text_color function
3
+ * Returns black or white for optimal contrast against a background
4
+ */
5
+
6
+ import { executeWithSchema, getBundledSchema } from "@tests/helpers/schema-test-utils";
7
+ import { describe, expect, it } from "vitest";
8
+ import type { FunctionSpecification } from "@/bundler/types";
9
+
10
+ describe("auto_text_color function", () => {
11
+ describe("Schema Definition", () => {
12
+ it("should have correct schema structure", async () => {
13
+ const schema = (await getBundledSchema(
14
+ "auto_text_color",
15
+ "function",
16
+ )) as FunctionSpecification;
17
+
18
+ expect(schema.name).toBe("auto_text_color");
19
+ expect(schema.type).toBe("function");
20
+ });
21
+ });
22
+
23
+ describe("Function Execution", () => {
24
+ it("should return white text for dark backgrounds", async () => {
25
+ const result = await executeWithSchema(
26
+ "auto_text_color",
27
+ "function",
28
+ `
29
+ variable bg: Color.SRGB;
30
+ bg.r = 0.1; bg.g = 0.1; bg.b = 0.1;
31
+ auto_text_color(bg)
32
+ `,
33
+ );
34
+
35
+ expect(result).toBeDefined();
36
+ const r = (result as any).value?.r?.value ?? (result as any).value?.r;
37
+ expect(r).toBeCloseTo(1, 1);
38
+ });
39
+
40
+ it("should return black text for light backgrounds", async () => {
41
+ const result = await executeWithSchema(
42
+ "auto_text_color",
43
+ "function",
44
+ `
45
+ variable bg: Color.SRGB;
46
+ bg.r = 0.94; bg.g = 0.94; bg.b = 0.94;
47
+ auto_text_color(bg)
48
+ `,
49
+ );
50
+
51
+ expect(result).toBeDefined();
52
+ const r = (result as any).value?.r?.value ?? (result as any).value?.r;
53
+ expect(r).toBeCloseTo(0, 1);
54
+ });
55
+
56
+ it("should return black text for pure white", async () => {
57
+ const result = await executeWithSchema(
58
+ "auto_text_color",
59
+ "function",
60
+ `
61
+ variable bg: Color.SRGB;
62
+ bg.r = 1; bg.g = 1; bg.b = 1;
63
+ auto_text_color(bg)
64
+ `,
65
+ );
66
+
67
+ expect(result).toBeDefined();
68
+ const r = (result as any).value?.r?.value ?? (result as any).value?.r;
69
+ expect(r).toBeCloseTo(0, 1);
70
+ });
71
+
72
+ it("should return white text for pure black", async () => {
73
+ const result = await executeWithSchema(
74
+ "auto_text_color",
75
+ "function",
76
+ `
77
+ variable bg: Color.SRGB;
78
+ bg.r = 0; bg.g = 0; bg.b = 0;
79
+ auto_text_color(bg)
80
+ `,
81
+ );
82
+
83
+ expect(result).toBeDefined();
84
+ const r = (result as any).value?.r?.value ?? (result as any).value?.r;
85
+ expect(r).toBeCloseTo(1, 1);
86
+ });
87
+
88
+ it("should return black text for bright yellow (high luminance)", async () => {
89
+ const result = await executeWithSchema(
90
+ "auto_text_color",
91
+ "function",
92
+ `
93
+ variable bg: Color.SRGB;
94
+ bg.r = 1; bg.g = 1; bg.b = 0;
95
+ auto_text_color(bg)
96
+ `,
97
+ );
98
+
99
+ expect(result).toBeDefined();
100
+ const r = (result as any).value?.r?.value ?? (result as any).value?.r;
101
+ // Yellow has high luminance -> black text
102
+ expect(r).toBeCloseTo(0, 1);
103
+ });
104
+
105
+ it("should return white text for dark blue", async () => {
106
+ const result = await executeWithSchema(
107
+ "auto_text_color",
108
+ "function",
109
+ `
110
+ variable bg: Color.SRGB;
111
+ bg.r = 0; bg.g = 0.4; bg.b = 0.8;
112
+ auto_text_color(bg)
113
+ `,
114
+ );
115
+
116
+ expect(result).toBeDefined();
117
+ const r = (result as any).value?.r?.value ?? (result as any).value?.r;
118
+ // Blue has low luminance -> white text
119
+ expect(r).toBeCloseTo(1, 1);
120
+ });
121
+ });
122
+ });
@@ -0,0 +1,66 @@
1
+ // Select the most contrasting color from a list of candidates
2
+ // Uses WCAG 2.1 contrast ratio based on relative luminance
3
+ //
4
+ // Algorithm:
5
+ // 1. Calculate relative luminance: L = 0.2126*R + 0.7152*G + 0.0722*B (linear RGB)
6
+ // 2. Contrast ratio: (L_lighter + 0.05) / (L_darker + 0.05)
7
+ // 3. Return candidate with highest contrast ratio
8
+ //
9
+ // Default candidates: black (#000) and white (#fff)
10
+
11
+ variable input: List = {input};
12
+ variable bg: Color.LinearSRGB = input.get(0).to.linearsrgb();
13
+
14
+ // Calculate background luminance
15
+ variable bg_lum: Number = 0.2126 * bg.r + 0.7152 * bg.g + 0.0722 * bg.b;
16
+
17
+ // Get candidates list, default to black and white
18
+ variable candidates: List;
19
+ if (input.length() > 1) [
20
+ candidates = input.get(1);
21
+ ] else [
22
+ // Default: black and white
23
+ variable black: Color.SRGB;
24
+ black.r = 0; black.g = 0; black.b = 0;
25
+ variable white: Color.SRGB;
26
+ white.r = 1; white.g = 1; white.b = 1;
27
+ candidates = black, white;
28
+ ];
29
+
30
+ // Find candidate with highest contrast
31
+ variable best_color: Color.SRGB = candidates.get(0).to.srgb();
32
+ variable best_contrast: Number = 0;
33
+ variable candidate: Color.LinearSRGB;
34
+ variable cand_lum: Number = 0;
35
+ variable lighter: Number = 0;
36
+ variable darker: Number = 0;
37
+ variable contrast: Number = 0;
38
+
39
+ variable i: Number = 0;
40
+ while (i < candidates.length()) [
41
+ candidate = candidates.get(i).to.linearsrgb();
42
+
43
+ // Calculate candidate luminance
44
+ cand_lum = 0.2126 * candidate.r + 0.7152 * candidate.g + 0.0722 * candidate.b;
45
+
46
+ // Calculate contrast ratio (lighter / darker)
47
+ lighter = bg_lum;
48
+ darker = cand_lum;
49
+ if (cand_lum > bg_lum) [
50
+ lighter = cand_lum;
51
+ darker = bg_lum;
52
+ ];
53
+
54
+ contrast = (lighter + 0.05) / (darker + 0.05);
55
+
56
+ // Track best
57
+ if (contrast > best_contrast) [
58
+ best_contrast = contrast;
59
+ best_color = candidates.get(i).to.srgb();
60
+ ];
61
+
62
+ i = i + 1;
63
+ ];
64
+
65
+ return best_color;
66
+