@tokens-studio/tokenscript-schemas 0.0.13 → 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 (153) hide show
  1. package/README.md +21 -0
  2. package/bundled/functions/adjust_chroma.json +60 -0
  3. package/bundled/functions/adjust_hue.json +60 -0
  4. package/bundled/functions/adjust_lightness.json +60 -0
  5. package/bundled/functions/adjust_to_contrast.json +67 -0
  6. package/bundled/functions/alpha_blend.json +31 -0
  7. package/bundled/functions/alpha_scale.json +27 -0
  8. package/bundled/functions/analogous.json +32 -0
  9. package/bundled/functions/apca_contrast.json +27 -0
  10. package/bundled/functions/are_similar.json +73 -0
  11. package/bundled/functions/auto_text_color.json +66 -0
  12. package/bundled/functions/best_contrast.json +28 -0
  13. package/bundled/functions/chroma.json +54 -0
  14. package/bundled/functions/clamp_chroma.json +66 -0
  15. package/bundled/functions/clamp_lightness.json +66 -0
  16. package/bundled/functions/clamp_to_gamut.json +23 -0
  17. package/bundled/functions/complement.json +24 -0
  18. package/bundled/functions/contrast_ratio.json +27 -0
  19. package/bundled/functions/cooler.json +52 -0
  20. package/bundled/functions/darken.json +28 -0
  21. package/bundled/functions/delta_e_2000.json +40 -0
  22. package/bundled/functions/delta_e_76.json +27 -0
  23. package/bundled/functions/delta_e_ok.json +27 -0
  24. package/bundled/functions/desaturate.json +28 -0
  25. package/bundled/functions/distributed.json +36 -0
  26. package/bundled/functions/diverging.json +36 -0
  27. package/bundled/functions/grayscale.json +24 -0
  28. package/bundled/functions/harmonize.json +65 -0
  29. package/bundled/functions/hue.json +54 -0
  30. package/bundled/functions/hue_difference.json +27 -0
  31. package/bundled/functions/in_gamut.json +27 -0
  32. package/bundled/functions/interpolate.json +66 -0
  33. package/bundled/functions/invert.json +1 -1
  34. package/bundled/functions/is_cool.json +23 -0
  35. package/bundled/functions/is_dark.json +27 -0
  36. package/bundled/functions/is_light.json +27 -0
  37. package/bundled/functions/is_neutral.json +65 -0
  38. package/bundled/functions/is_warm.json +23 -0
  39. package/bundled/functions/lighten.json +28 -0
  40. package/bundled/functions/lightness.json +61 -0
  41. package/bundled/functions/luminance.json +23 -0
  42. package/bundled/functions/meets_contrast.json +31 -0
  43. package/bundled/functions/mix.json +32 -0
  44. package/bundled/functions/monochromatic.json +28 -0
  45. package/bundled/functions/muted.json +59 -0
  46. package/bundled/functions/neutral_variant.json +59 -0
  47. package/bundled/functions/relative_luminance.json +61 -0
  48. package/bundled/functions/rotate_hue.json +28 -0
  49. package/bundled/functions/saturate.json +28 -0
  50. package/bundled/functions/scale_chroma.json +60 -0
  51. package/bundled/functions/scale_lightness.json +60 -0
  52. package/bundled/functions/sepia.json +59 -0
  53. package/bundled/functions/set_chroma.json +28 -0
  54. package/bundled/functions/set_hue.json +28 -0
  55. package/bundled/functions/set_lightness.json +28 -0
  56. package/bundled/functions/shade_scale.json +28 -0
  57. package/bundled/functions/split_complement.json +28 -0
  58. package/bundled/functions/steps.json +32 -0
  59. package/bundled/functions/tetradic.json +24 -0
  60. package/bundled/functions/tint_scale.json +36 -0
  61. package/bundled/functions/to_gamut.json +59 -0
  62. package/bundled/functions/triadic.json +24 -0
  63. package/bundled/functions/vibrant.json +59 -0
  64. package/bundled/functions/warmer.json +52 -0
  65. package/bundled/functions/wcag_level.json +60 -0
  66. package/bundled/functions.json +2602 -6
  67. package/bundled/registry.json +3705 -84
  68. package/bundled/types/css-color.json +151 -0
  69. package/bundled/types/hsl-color.json +66 -0
  70. package/bundled/types/hsv-color.json +57 -0
  71. package/bundled/types/hwb-color.json +66 -0
  72. package/bundled/types/lab-color.json +57 -0
  73. package/bundled/types/lch-color.json +57 -0
  74. package/bundled/types/okhsl-color.json +57 -0
  75. package/bundled/types/okhsv-color.json +57 -0
  76. package/bundled/types/oklab-color.json +87 -0
  77. package/bundled/types/oklch-color.json +57 -0
  78. package/bundled/types/p3-color.json +57 -0
  79. package/bundled/types/p3-linear-color.json +57 -0
  80. package/bundled/types/rgb-color.json +12 -3
  81. package/bundled/types/srgb-color.json +77 -0
  82. package/bundled/types/srgb-linear-color.json +67 -0
  83. package/bundled/types/xyz-d50-color.json +57 -0
  84. package/bundled/types/xyz-d65-color.json +77 -0
  85. package/bundled/types.json +1067 -43
  86. package/dist/cli/index.cjs +231 -22
  87. package/dist/cli/index.cjs.map +1 -1
  88. package/dist/cli/index.js +231 -22
  89. package/dist/cli/index.js.map +1 -1
  90. package/dist/index.cjs +5 -2
  91. package/dist/index.cjs.map +1 -1
  92. package/dist/index.d.cts +4 -1
  93. package/dist/index.d.ts +4 -1
  94. package/dist/index.js +5 -2
  95. package/dist/index.js.map +1 -1
  96. package/package.json +4 -2
  97. package/src/bundler/index.ts +7 -0
  98. package/src/bundler/presets/css.ts +21 -0
  99. package/src/bundler/presets/index.ts +47 -0
  100. package/src/bundler/presets/types.ts +10 -0
  101. package/src/bundler/selective-bundler.ts +9 -0
  102. package/src/bundler/types.ts +1 -0
  103. package/src/cli/commands/bundle.test.ts +34 -0
  104. package/src/cli/commands/bundle.ts +37 -11
  105. package/src/cli/commands/list.ts +36 -4
  106. package/src/cli/commands/presets.ts +81 -0
  107. package/src/cli/index.ts +12 -1
  108. package/src/cli/output-generator.ts +8 -2
  109. package/src/cli/version-info.ts +93 -0
  110. package/src/schemas/types/css-color/from-hsl-color.tokenscript +17 -4
  111. package/src/schemas/types/css-color/from-hwb-color.tokenscript +17 -4
  112. package/src/schemas/types/css-color/from-lab-color.tokenscript +17 -4
  113. package/src/schemas/types/css-color/from-lch-color.tokenscript +17 -4
  114. package/src/schemas/types/css-color/from-oklab-color.tokenscript +17 -4
  115. package/src/schemas/types/css-color/from-oklch-color.tokenscript +17 -4
  116. package/src/schemas/types/css-color/from-p3-color.tokenscript +17 -4
  117. package/src/schemas/types/css-color/from-rgb-color.tokenscript +17 -4
  118. package/src/schemas/types/css-color/from-srgb-color.tokenscript +17 -4
  119. package/src/schemas/types/css-color/from-xyz-d50-color.tokenscript +17 -4
  120. package/src/schemas/types/css-color/from-xyz-d65-color.tokenscript +17 -4
  121. package/src/schemas/types/css-color/unit.test.ts +216 -0
  122. package/src/schemas/types/hex-color/unit.test.ts +18 -0
  123. package/src/schemas/types/hsl-color/hsla-initializer.tokenscript +17 -0
  124. package/src/schemas/types/hsl-color/initializer.tokenscript +6 -1
  125. package/src/schemas/types/hsl-color/schema.json +9 -0
  126. package/src/schemas/types/hsl-color/unit.test.ts +95 -1
  127. package/src/schemas/types/hsv-color/initializer.tokenscript +6 -1
  128. package/src/schemas/types/hsv-color/unit.test.ts +44 -0
  129. package/src/schemas/types/hwb-color/hwba-initializer.tokenscript +17 -0
  130. package/src/schemas/types/hwb-color/initializer.tokenscript +6 -1
  131. package/src/schemas/types/hwb-color/schema.json +9 -0
  132. package/src/schemas/types/hwb-color/unit.test.ts +70 -0
  133. package/src/schemas/types/lab-color/initializer.tokenscript +6 -1
  134. package/src/schemas/types/lab-color/unit.test.ts +44 -0
  135. package/src/schemas/types/lch-color/initializer.tokenscript +6 -1
  136. package/src/schemas/types/lch-color/unit.test.ts +44 -0
  137. package/src/schemas/types/okhsl-color/initializer.tokenscript +8 -1
  138. package/src/schemas/types/okhsl-color/unit.test.ts +37 -0
  139. package/src/schemas/types/okhsv-color/initializer.tokenscript +8 -1
  140. package/src/schemas/types/okhsv-color/unit.test.ts +37 -0
  141. package/src/schemas/types/oklab-color/initializer.tokenscript +6 -1
  142. package/src/schemas/types/oklab-color/unit.test.ts +58 -0
  143. package/src/schemas/types/oklch-color/initializer.tokenscript +6 -1
  144. package/src/schemas/types/oklch-color/unit.test.ts +58 -0
  145. package/src/schemas/types/p3-color/initializer.tokenscript +6 -1
  146. package/src/schemas/types/p3-color/unit.test.ts +47 -0
  147. package/src/schemas/types/rgb-color/initializer.tokenscript +7 -1
  148. package/src/schemas/types/rgb-color/rgba-initializer.tokenscript +17 -0
  149. package/src/schemas/types/rgb-color/schema.json +9 -0
  150. package/src/schemas/types/rgb-color/unit.test.ts +110 -1
  151. package/src/schemas/types/srgb-color/initializer.tokenscript +6 -1
  152. package/src/schemas/types/srgb-color/unit.test.ts +89 -0
  153. package/bundled/types/rgba-color.json +0 -89
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "chroma",
3
+ "type": "function",
4
+ "description": "Extracts the chroma (colorfulness/saturation) value from any color using OKLCH. Returns a value from 0 (gray) to approximately 0.4 (most saturated colors). Chroma in OKLCH represents the colorfulness independent of lightness - higher values mean more vivid colors. Essential for creating consistent color scales and checking color vibrancy.",
5
+ "keyword": "chroma",
6
+ "requirements": [
7
+ "https://schema.tokenscript.dev.gcp.tokens.studio/api/v1/core/srgb-color/0/",
8
+ "https://schema.tokenscript.dev.gcp.tokens.studio/api/v1/core/oklch-color/0/"
9
+ ],
10
+ "schema": {
11
+ "type": "object",
12
+ "properties": {
13
+ "input": {
14
+ "type": "array",
15
+ "items": [
16
+ {
17
+ "description": "Color to extract chroma from",
18
+ "type": "color"
19
+ }
20
+ ],
21
+ "minItems": 1,
22
+ "maxItems": 1
23
+ }
24
+ },
25
+ "required": [
26
+ "input"
27
+ ]
28
+ },
29
+ "returns": {
30
+ "type": "number",
31
+ "description": "Chroma value (0 to ~0.4)"
32
+ },
33
+ "script": {
34
+ "type": "https://schema.tokenscript.dev.gcp.tokens.studio/api/v1/core/tokenscript/0/",
35
+ "script": "// chroma: Extract chroma (colorfulness) from a color\n// Reference: OKLCH Color Space (Björn Ottosson)\n// Reference: https://bottosson.github.io/posts/oklab/\n//\n// Returns the C component from OKLCH, which represents\n// colorfulness/saturation. Range: 0 (gray) to ~0.4 (most vivid).\n\nvariable input: List = {input};\nvariable color: Color.OKLCH = input.get(0).to.oklch();\n\nreturn color.c;"
36
+ },
37
+ "examples": [
38
+ {
39
+ "description": "Gray has chroma 0",
40
+ "input": [
41
+ "#808080"
42
+ ],
43
+ "output": 0
44
+ },
45
+ {
46
+ "description": "Saturated red has high chroma",
47
+ "input": [
48
+ "#ff0000"
49
+ ],
50
+ "output": 0.26
51
+ }
52
+ ],
53
+ "slug": "chroma"
54
+ }
@@ -0,0 +1,66 @@
1
+ {
2
+ "name": "clamp_chroma",
3
+ "type": "function",
4
+ "description": "Constrains a color's chroma (saturation) to a specified range while preserving hue and lightness. Useful for ensuring colors stay within brand guidelines or design constraints. Uses OKLCH for perceptually uniform clamping.",
5
+ "keyword": "clamp_chroma",
6
+ "requirements": [
7
+ "https://schema.tokenscript.dev.gcp.tokens.studio/api/v1/core/srgb-color/0/",
8
+ "https://schema.tokenscript.dev.gcp.tokens.studio/api/v1/core/oklch-color/0/"
9
+ ],
10
+ "schema": {
11
+ "type": "object",
12
+ "properties": {
13
+ "input": {
14
+ "type": "array",
15
+ "items": [
16
+ {
17
+ "description": "Color to clamp",
18
+ "type": "color"
19
+ },
20
+ {
21
+ "description": "Minimum chroma (0+)",
22
+ "type": "number"
23
+ },
24
+ {
25
+ "description": "Maximum chroma (typically 0-0.4)",
26
+ "type": "number"
27
+ }
28
+ ],
29
+ "minItems": 3,
30
+ "maxItems": 3
31
+ }
32
+ },
33
+ "required": [
34
+ "input"
35
+ ]
36
+ },
37
+ "returns": {
38
+ "type": "color",
39
+ "description": "Color with clamped chroma"
40
+ },
41
+ "script": {
42
+ "type": "https://schema.tokenscript.dev.gcp.tokens.studio/api/v1/core/tokenscript/0/",
43
+ "script": "// clamp_chroma: Constrain chroma to a range\n// Preserves hue and lightness\n\nvariable input: List = {input};\nvariable color: Color.OKLCH = input.get(0).to.oklch();\nvariable min_c: Number = input.get(1);\nvariable max_c: Number = input.get(2);\n\n// Clamp chroma\nvariable new_c: Number = color.c;\nif (new_c < min_c) [ new_c = min_c; ];\nif (new_c > max_c) [ new_c = max_c; ];\n\n// Create result\nvariable result: Color.OKLCH;\nresult.l = color.l;\nresult.c = new_c;\nresult.h = color.h;\n\nreturn result;"
44
+ },
45
+ "examples": [
46
+ {
47
+ "description": "Limit maximum saturation",
48
+ "input": [
49
+ "#ff0000",
50
+ 0,
51
+ 0.15
52
+ ],
53
+ "output": "Muted red with chroma 0.15"
54
+ },
55
+ {
56
+ "description": "Ensure minimum saturation",
57
+ "input": [
58
+ "#808080",
59
+ 0.05,
60
+ 0.3
61
+ ],
62
+ "output": "Slightly colored gray"
63
+ }
64
+ ],
65
+ "slug": "clamp_chroma"
66
+ }
@@ -0,0 +1,66 @@
1
+ {
2
+ "name": "clamp_lightness",
3
+ "type": "function",
4
+ "description": "Constrains a color's lightness to a specified range while preserving hue and chroma. Useful for ensuring colors stay within readable/accessible bounds. Uses OKLCH for perceptually uniform clamping.",
5
+ "keyword": "clamp_lightness",
6
+ "requirements": [
7
+ "https://schema.tokenscript.dev.gcp.tokens.studio/api/v1/core/srgb-color/0/",
8
+ "https://schema.tokenscript.dev.gcp.tokens.studio/api/v1/core/oklch-color/0/"
9
+ ],
10
+ "schema": {
11
+ "type": "object",
12
+ "properties": {
13
+ "input": {
14
+ "type": "array",
15
+ "items": [
16
+ {
17
+ "description": "Color to clamp",
18
+ "type": "color"
19
+ },
20
+ {
21
+ "description": "Minimum lightness (0-1)",
22
+ "type": "number"
23
+ },
24
+ {
25
+ "description": "Maximum lightness (0-1)",
26
+ "type": "number"
27
+ }
28
+ ],
29
+ "minItems": 3,
30
+ "maxItems": 3
31
+ }
32
+ },
33
+ "required": [
34
+ "input"
35
+ ]
36
+ },
37
+ "returns": {
38
+ "type": "color",
39
+ "description": "Color with clamped lightness"
40
+ },
41
+ "script": {
42
+ "type": "https://schema.tokenscript.dev.gcp.tokens.studio/api/v1/core/tokenscript/0/",
43
+ "script": "// clamp_lightness: Constrain lightness to a range\n// Preserves hue and chroma\n\nvariable input: List = {input};\nvariable color: Color.OKLCH = input.get(0).to.oklch();\nvariable min_l: Number = input.get(1);\nvariable max_l: Number = input.get(2);\n\n// Clamp lightness\nvariable new_l: Number = color.l;\nif (new_l < min_l) [ new_l = min_l; ];\nif (new_l > max_l) [ new_l = max_l; ];\n\n// Create result\nvariable result: Color.OKLCH;\nresult.l = new_l;\nresult.c = color.c;\nresult.h = color.h;\n\nreturn result;"
44
+ },
45
+ "examples": [
46
+ {
47
+ "description": "Clamp too-dark color to minimum",
48
+ "input": [
49
+ "#111111",
50
+ 0.3,
51
+ 0.9
52
+ ],
53
+ "output": "Color with lightness 0.3"
54
+ },
55
+ {
56
+ "description": "Clamp too-light color to maximum",
57
+ "input": [
58
+ "#ffffff",
59
+ 0.2,
60
+ 0.8
61
+ ],
62
+ "output": "Color with lightness 0.8"
63
+ }
64
+ ],
65
+ "slug": "clamp_lightness"
66
+ }
@@ -0,0 +1,23 @@
1
+ {
2
+ "name": "Clamp to Gamut",
3
+ "type": "function",
4
+ "description": "Clips a color to the sRGB gamut by clamping each RGB channel to [0,1]. This is a simple but lossy approach - for perceptually better results, consider using gamut mapping algorithms that reduce chroma first.",
5
+ "keyword": "clamp_to_gamut",
6
+ "input": {
7
+ "type": "object",
8
+ "properties": {
9
+ "color": {
10
+ "type": "color",
11
+ "description": "Color to clamp"
12
+ }
13
+ }
14
+ },
15
+ "script": {
16
+ "type": "https://schema.tokenscript.dev.gcp.tokens.studio/api/v1/core/tokenscript/0/",
17
+ "script": "// Clamp to Gamut (Simple Clipping)\n// Clips out-of-gamut sRGB values to [0, 1] range\n// Reference: Color.js toGamut with method=\"clip\"\n//\n// This is the simplest gamut mapping approach:\n// - Fast and deterministic\n// - Preserves hue when only one channel clips\n// - Can cause hue shifts when multiple channels clip\n// - May lose saturation detail\n//\n// For perceptually better results, use toGamut() which\n// reduces chroma in OKLCH before clipping.\n\nvariable input: List = {input};\nvariable color: Color.SRGB = input.get(0).to.srgb();\n\n// Get RGB values\nvariable r: Number = color.r;\nvariable g: Number = color.g;\nvariable b: Number = color.b;\n\n// Clamp R\nif (r < 0) [ r = 0; ];\nif (r > 1) [ r = 1; ];\n\n// Clamp G\nif (g < 0) [ g = 0; ];\nif (g > 1) [ g = 1; ];\n\n// Clamp B\nif (b < 0) [ b = 0; ];\nif (b > 1) [ b = 1; ];\n\n// Create clamped result\nvariable result: Color.SRGB;\nresult.r = r;\nresult.g = g;\nresult.b = b;\n\nreturn result;"
18
+ },
19
+ "requirements": [
20
+ "https://schema.tokenscript.dev.gcp.tokens.studio/api/v1/core/srgb-color/0/"
21
+ ],
22
+ "slug": "clamp_to_gamut"
23
+ }
@@ -0,0 +1,24 @@
1
+ {
2
+ "name": "Complement",
3
+ "type": "function",
4
+ "description": "Returns the complementary color by rotating hue 180° in OKLCH space.",
5
+ "keyword": "complement",
6
+ "input": {
7
+ "type": "object",
8
+ "properties": {
9
+ "color": {
10
+ "type": "color",
11
+ "description": "The color to find the complement of"
12
+ }
13
+ }
14
+ },
15
+ "script": {
16
+ "type": "https://schema.tokenscript.dev.gcp.tokens.studio/api/v1/core/tokenscript/0/",
17
+ "script": "// Get the complementary color by rotating hue 180° in OKLCH\n// Preserves lightness and chroma for perceptually balanced results\n\nvariable input: List = {input};\nvariable color: Color.OKLCH = input.get(0).to.oklch();\n\n// Rotate hue by 180°\nvariable new_h: Number = color.h + 180;\nif (new_h >= 360) [ new_h = new_h - 360; ];\n\n// Create complementary color\nvariable result: Color.OKLCH;\nresult.l = color.l;\nresult.c = color.c;\nresult.h = new_h;\n\nreturn result;"
18
+ },
19
+ "requirements": [
20
+ "https://schema.tokenscript.dev.gcp.tokens.studio/api/v1/core/oklch-color/0/",
21
+ "https://schema.tokenscript.dev.gcp.tokens.studio/api/v1/core/srgb-color/0/"
22
+ ],
23
+ "slug": "complement"
24
+ }
@@ -0,0 +1,27 @@
1
+ {
2
+ "name": "Contrast Ratio",
3
+ "type": "function",
4
+ "description": "Calculates the WCAG 2.1 contrast ratio between two colors. Returns a value from 1 (no contrast) to 21 (black/white). WCAG AA requires 4.5:1 for normal text, 3:1 for large text.",
5
+ "keyword": "contrast_ratio",
6
+ "input": {
7
+ "type": "object",
8
+ "properties": {
9
+ "color1": {
10
+ "type": "color",
11
+ "description": "First color (e.g., background)"
12
+ },
13
+ "color2": {
14
+ "type": "color",
15
+ "description": "Second color (e.g., foreground)"
16
+ }
17
+ }
18
+ },
19
+ "script": {
20
+ "type": "https://schema.tokenscript.dev.gcp.tokens.studio/api/v1/core/tokenscript/0/",
21
+ "script": "// Calculate WCAG 2.1 contrast ratio between two colors\n//\n// Returns: 1.0 (identical) to 21.0 (black vs white)\n//\n// WCAG Guidelines:\n// - AA Normal text: ≥ 4.5:1\n// - AA Large text: ≥ 3.0:1\n// - AAA Normal text: ≥ 7.0:1\n// - AAA Large text: ≥ 4.5:1\n//\n// Algorithm:\n// 1. Convert to linear RGB\n// 2. Calculate relative luminance: L = 0.2126*R + 0.7152*G + 0.0722*B\n// 3. Contrast ratio: (L_lighter + 0.05) / (L_darker + 0.05)\n\nvariable input: List = {input};\nvariable color1: Color.LinearSRGB = input.get(0).to.linearsrgb();\nvariable color2: Color.LinearSRGB = input.get(1).to.linearsrgb();\n\n// Calculate relative luminance for each color\nvariable lum1: Number = 0.2126 * color1.r + 0.7152 * color1.g + 0.0722 * color1.b;\nvariable lum2: Number = 0.2126 * color2.r + 0.7152 * color2.g + 0.0722 * color2.b;\n\n// Determine lighter and darker\nvariable lighter: Number = lum1;\nvariable darker: Number = lum2;\nif (lum2 > lum1) [\n lighter = lum2;\n darker = lum1;\n];\n\n// Calculate contrast ratio\nvariable ratio: Number = (lighter + 0.05) / (darker + 0.05);\n\nreturn ratio;"
22
+ },
23
+ "requirements": [
24
+ "https://schema.tokenscript.dev.gcp.tokens.studio/api/v1/core/srgb-linear-color/0/"
25
+ ],
26
+ "slug": "contrast_ratio"
27
+ }
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "cooler",
3
+ "type": "function",
4
+ "description": "Shifts a color's hue towards cool colors (blue, ~260° in OKLCH). The amount parameter controls how much to shift, from 0 (no change) to 1 (fully cool). Preserves lightness and chroma.",
5
+ "keyword": "cooler",
6
+ "requirements": [
7
+ "https://schema.tokenscript.dev.gcp.tokens.studio/api/v1/core/srgb-color/0/",
8
+ "https://schema.tokenscript.dev.gcp.tokens.studio/api/v1/core/oklch-color/0/"
9
+ ],
10
+ "schema": {
11
+ "type": "object",
12
+ "properties": {
13
+ "input": {
14
+ "type": "array",
15
+ "items": [
16
+ {
17
+ "description": "Color to cool",
18
+ "type": "color"
19
+ },
20
+ {
21
+ "description": "Amount to shift (0-1), default 0.25",
22
+ "type": "number"
23
+ }
24
+ ],
25
+ "minItems": 1,
26
+ "maxItems": 2
27
+ }
28
+ },
29
+ "required": [
30
+ "input"
31
+ ]
32
+ },
33
+ "returns": {
34
+ "type": "color",
35
+ "description": "Color shifted towards cool hues"
36
+ },
37
+ "script": {
38
+ "type": "https://schema.tokenscript.dev.gcp.tokens.studio/api/v1/core/tokenscript/0/",
39
+ "script": "// cooler: Shift hue towards cool colors\n//\n// Cool colors are centered around blue (~260° in OKLCH).\n// The function interpolates the hue towards this target via\n// the shortest angular path on the hue wheel.\n//\n// Parameters:\n// color - Input color\n// amount - Shift amount (0 = no change, 1 = fully cool), default 0.25\n//\n// Preserves lightness and chroma.\n\nvariable input: List = {input};\nvariable color: Color.OKLCH = input.get(0).to.oklch();\nvariable amount: Number = 0.25;\n\nif (input.length() > 1) [\n amount = input.get(1);\n];\n\n// Cool hue target (blue in OKLCH is around 260°)\nvariable cool_hue: Number = 260;\n\n// Calculate shortest path hue difference\nvariable hue_diff: Number = cool_hue - color.h;\n\n// Wrap to shortest path\nif (hue_diff > 180) [ hue_diff = hue_diff - 360; ];\nif (hue_diff < -180) [ hue_diff = hue_diff + 360; ];\n\n// Apply interpolation\nvariable new_hue: Number = color.h + (hue_diff * amount);\n\n// Normalize to 0-360\nif (new_hue < 0) [ new_hue = new_hue + 360; ];\nif (new_hue >= 360) [ new_hue = new_hue - 360; ];\n\n// Create result\nvariable result: Color.OKLCH;\nresult.l = color.l;\nresult.c = color.c;\nresult.h = new_hue;\n\nreturn result;"
40
+ },
41
+ "examples": [
42
+ {
43
+ "description": "Make orange cooler",
44
+ "input": [
45
+ "#ff6600",
46
+ 0.5
47
+ ],
48
+ "output": "Orange shifted towards neutral"
49
+ }
50
+ ],
51
+ "slug": "cooler"
52
+ }
@@ -0,0 +1,28 @@
1
+ {
2
+ "name": "Darken",
3
+ "type": "function",
4
+ "description": "Makes a color darker by decreasing its lightness in OKLab space. Amount is 0-1 where 0.25 = 25% darker.",
5
+ "keyword": "darken",
6
+ "input": {
7
+ "type": "object",
8
+ "properties": {
9
+ "color": {
10
+ "type": "color",
11
+ "description": "The color to darken"
12
+ },
13
+ "amount": {
14
+ "type": "number",
15
+ "description": "Amount to darken (0-1). Default is 0.25"
16
+ }
17
+ }
18
+ },
19
+ "script": {
20
+ "type": "https://schema.tokenscript.dev.gcp.tokens.studio/api/v1/core/tokenscript/0/",
21
+ "script": "// darken: Decrease lightness proportionally towards black\n// Amount: 0-1 where 0.25 means 25% closer to black\n//\n// Algorithm: L' = L * (1 - amount)\n// This ensures we approach black (L=0) proportionally.\n//\n// Input: Any color space (converted to OKLab internally)\n// Output: OKLCH (working space)\n// To get sRGB: darken(color, 0.25).to.srgb()\n\nvariable input: List = {input};\nvariable color: Color.OKLab = input.get(0).to.oklab();\n\n// Default amount is 0.25 (25%)\nvariable amount: Number = 0.25;\nif (input.length() > 1) [\n amount = input.get(1);\n];\n\n// Calculate new lightness (move toward 0)\nvariable current_l: Number = color.l;\nvariable new_l: Number = current_l * (1 - amount);\n\n// Clamp to valid range\nif (new_l < 0) [ new_l = 0; ];\n\n// Create output in OKLab, return as OKLCH (working space)\nvariable result: Color.OKLab;\nresult.l = new_l;\nresult.a = color.a;\nresult.b = color.b;\n\nreturn result.to.oklch();"
22
+ },
23
+ "requirements": [
24
+ "https://schema.tokenscript.dev.gcp.tokens.studio/api/v1/core/oklab-color/0/",
25
+ "https://schema.tokenscript.dev.gcp.tokens.studio/api/v1/core/srgb-color/0/"
26
+ ],
27
+ "slug": "darken"
28
+ }
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "Delta E 2000",
3
+ "type": "function",
4
+ "description": "Calculates perceptual color difference using CIEDE2000 (ΔE00), the CIE-recommended color difference formula. More accurate than CIE76 for small differences. Industry standard for color quality control. Uses parametric weighting factors kL, kC, kH (all default to 1).",
5
+ "keyword": "delta_e_2000",
6
+ "input": {
7
+ "type": "object",
8
+ "properties": {
9
+ "color1": {
10
+ "type": "color",
11
+ "description": "First color (reference)"
12
+ },
13
+ "color2": {
14
+ "type": "color",
15
+ "description": "Second color (sample)"
16
+ },
17
+ "kL": {
18
+ "type": "number",
19
+ "description": "Lightness weight (default 1)"
20
+ },
21
+ "kC": {
22
+ "type": "number",
23
+ "description": "Chroma weight (default 1)"
24
+ },
25
+ "kH": {
26
+ "type": "number",
27
+ "description": "Hue weight (default 1)"
28
+ }
29
+ }
30
+ },
31
+ "script": {
32
+ "type": "https://schema.tokenscript.dev.gcp.tokens.studio/api/v1/core/tokenscript/0/",
33
+ "script": "// CIEDE2000 Color Difference Formula (ΔE00)\n// Reference: CIE 142-2001 (Technical Report)\n// Reference: Color.js deltaE2000 implementation\n// Reference: Sharma, Wu, Dalal \"The CIEDE2000 Color-Difference Formula\" (2005)\n//\n// This is the CIE-recommended color difference formula, providing\n// better correlation with visual perception than CIE76 or CIE94.\n//\n// Parametric factors (kL, kC, kH):\n// - All default to 1.0 for reference conditions\n// - kL can be increased for lightness texture/noise\n// - kC can be increased for chroma noise\n//\n// Interpretation (approximate):\n// 0.0 - Identical colors\n// < 1.0 - Not perceptible by human eye\n// 1.0 - 2.0 - Perceptible through close observation\n// 2.0 - 10.0 - Perceptible at a glance\n// > 10.0 - Colors are obviously different\n\nvariable input: List = {input};\n\n// Convert both colors to CIE Lab\nvariable color1: Color.Lab = input.get(0).to.lab();\nvariable color2: Color.Lab = input.get(1).to.lab();\n\n// Get parametric weighting factors (default to 1)\nvariable k_l: Number = 1;\nvariable k_c: Number = 1;\nvariable k_h: Number = 1;\nif (input.length() > 2) [ k_l = input.get(2); ];\nif (input.length() > 3) [ k_c = input.get(3); ];\nif (input.length() > 4) [ k_h = input.get(4); ];\n\n// Constants\nvariable pi: Number = pi();\nvariable r2d: Number = 180 / pi;\nvariable d2r: Number = pi / 180;\nvariable g_factor: Number = 6103515625; // 25^7\nvariable e: Number = 2.718281828459045; // Euler's number\n\n// Get Lab values\nvariable l1: Number = color1.l;\nvariable a1: Number = color1.a;\nvariable b1: Number = color1.b;\n\nvariable l2: Number = color2.l;\nvariable a2: Number = color2.a;\nvariable b2: Number = color2.b;\n\n// Calculate C* (chroma) for both colors\nvariable c1: Number = sqrt(a1 * a1 + b1 * b1);\nvariable c2: Number = sqrt(a2 * a2 + b2 * b2);\n\n// Ensure non-negative chroma\nif (c1 < 0) [ c1 = 0; ];\nif (c2 < 0) [ c2 = 0; ];\n\n// Mean chroma\nvariable c_bar: Number = (c1 + c2) / 2;\n\n// Calculate G (a-axis asymmetry factor)\nvariable c7: Number = c_bar * c_bar * c_bar * c_bar * c_bar * c_bar * c_bar;\nvariable g: Number = 0.5 * (1 - sqrt(c7 / (c7 + g_factor)));\n\n// Scale a* values by asymmetry factor\nvariable a_prime1: Number = (1 + g) * a1;\nvariable a_prime2: Number = (1 + g) * a2;\n\n// Calculate C' from scaled a' and original b\nvariable c_prime1: Number = sqrt(a_prime1 * a_prime1 + b1 * b1);\nvariable c_prime2: Number = sqrt(a_prime2 * a_prime2 + b2 * b2);\n\n// Calculate h' (hue angles in degrees)\nvariable h1: Number = 0;\nif (a_prime1 != 0) [ h1 = atan2(b1, a_prime1); ];\nif (b1 != 0) [ h1 = atan2(b1, a_prime1); ];\nif (a_prime1 == 0) [\n if (b1 == 0) [ h1 = 0; ] else [ h1 = atan2(b1, a_prime1); ];\n];\nh1 = h1 * r2d;\nif (h1 < 0) [ h1 = h1 + 360; ];\n\nvariable h2: Number = 0;\nif (a_prime2 != 0) [ h2 = atan2(b2, a_prime2); ];\nif (b2 != 0) [ h2 = atan2(b2, a_prime2); ];\nif (a_prime2 == 0) [\n if (b2 == 0) [ h2 = 0; ] else [ h2 = atan2(b2, a_prime2); ];\n];\nh2 = h2 * r2d;\nif (h2 < 0) [ h2 = h2 + 360; ];\n\n// Lightness and Chroma differences\nvariable delta_l: Number = l2 - l1;\nvariable delta_c: Number = c_prime2 - c_prime1;\n\n// Hue difference (getting the sign correct)\nvariable h_diff: Number = h2 - h1;\nvariable h_sum: Number = h1 + h2;\nvariable h_abs: Number = h_diff;\nif (h_abs < 0) [ h_abs = 0 - h_abs; ];\n\nvariable delta_h: Number = 0;\nvariable c_product: Number = c_prime1 * c_prime2;\n\nif (c_product == 0) [\n delta_h = 0;\n] else [\n if (h_abs <= 180) [\n delta_h = h_diff;\n ] else [\n if (h_diff > 180) [\n delta_h = h_diff - 360;\n ] else [\n if (h_diff < -180) [\n delta_h = h_diff + 360;\n ] else [\n delta_h = h_diff;\n ];\n ];\n ];\n];\n\n// Weighted hue difference (ΔH')\nvariable delta_h_prime: Number = 2 * sqrt(c_prime2 * c_prime1) * sin(delta_h * d2r / 2);\n\n// Mean lightness and chroma\nvariable l_bar: Number = (l1 + l2) / 2;\nvariable c_bar_prime: Number = (c_prime1 + c_prime2) / 2;\nvariable c_bar_prime7: Number = c_bar_prime * c_bar_prime * c_bar_prime * c_bar_prime * c_bar_prime * c_bar_prime * c_bar_prime;\n\n// Mean hue (handling the 0/360 wraparound)\nvariable h_bar: Number = 0;\nif (c_product == 0) [\n h_bar = h_sum;\n] else [\n if (h_abs <= 180) [\n h_bar = h_sum / 2;\n ] else [\n if (h_sum < 360) [\n h_bar = (h_sum + 360) / 2;\n ] else [\n h_bar = (h_sum - 360) / 2;\n ];\n ];\n];\n\n// SL - Lightness crispening factor (assumes L=50 background)\nvariable l_bar_minus_50: Number = l_bar - 50;\nvariable l_sq: Number = l_bar_minus_50 * l_bar_minus_50;\nvariable s_l: Number = 1 + (0.015 * l_sq) / sqrt(20 + l_sq);\n\n// SC - Chroma factor\nvariable s_c: Number = 1 + 0.045 * c_bar_prime;\n\n// T - Cross term for blue non-linearity\nvariable t: Number = 1;\nt = t - 0.17 * cos((h_bar - 30) * d2r);\nt = t + 0.24 * cos(2 * h_bar * d2r);\nt = t + 0.32 * cos((3 * h_bar + 6) * d2r);\nt = t - 0.20 * cos((4 * h_bar - 63) * d2r);\n\n// SH - Hue factor\nvariable s_h: Number = 1 + 0.015 * c_bar_prime * t;\n\n// RT - Hue rotation term (for blue region 225-315 degrees)\nvariable h_bar_minus_275: Number = h_bar - 275;\nvariable exp_arg: Number = -1 * (h_bar_minus_275 / 25) * (h_bar_minus_275 / 25);\nvariable delta_theta: Number = 30 * pow(e, exp_arg);\nvariable r_c: Number = 2 * sqrt(c_bar_prime7 / (c_bar_prime7 + g_factor));\nvariable r_t: Number = -1 * sin(2 * delta_theta * d2r) * r_c;\n\n// Calculate final ΔE00\nvariable term_l: Number = delta_l / (k_l * s_l);\nvariable term_c: Number = delta_c / (k_c * s_c);\nvariable term_h: Number = delta_h_prime / (k_h * s_h);\n\nvariable de: Number = term_l * term_l + term_c * term_c + term_h * term_h;\nde = de + r_t * (delta_c / (k_c * s_c)) * (delta_h_prime / (k_h * s_h));\n\nvariable result: Number = sqrt(de);\n\nreturn result;"
34
+ },
35
+ "requirements": [
36
+ "https://schema.tokenscript.dev.gcp.tokens.studio/api/v1/core/lab-color/0/",
37
+ "https://schema.tokenscript.dev.gcp.tokens.studio/api/v1/core/lch-color/0/"
38
+ ],
39
+ "slug": "delta_e_2000"
40
+ }
@@ -0,0 +1,27 @@
1
+ {
2
+ "name": "Delta E 76",
3
+ "type": "function",
4
+ "description": "Calculates color difference using CIE76 formula (ΔE*ab). Simple Euclidean distance in CIE Lab space. Less accurate than Delta E 2000 for small differences, but faster and adequate for many applications. Formula: sqrt((L1-L2)² + (a1-a2)² + (b1-b2)²).",
5
+ "keyword": "delta_e_76",
6
+ "input": {
7
+ "type": "object",
8
+ "properties": {
9
+ "color1": {
10
+ "type": "color",
11
+ "description": "First color (reference)"
12
+ },
13
+ "color2": {
14
+ "type": "color",
15
+ "description": "Second color (sample)"
16
+ }
17
+ }
18
+ },
19
+ "script": {
20
+ "type": "https://schema.tokenscript.dev.gcp.tokens.studio/api/v1/core/tokenscript/0/",
21
+ "script": "// Delta E 76 (CIE76 Color Difference)\n// Reference: CIE Publication 15.2 (1986)\n// Reference: ASTM E308 Standard\n//\n// The original CIE color difference formula from 1976.\n// Simple Euclidean distance in CIE Lab space.\n//\n// Formula: ΔE*ab = sqrt((L1-L2)² + (a1-a2)² + (b1-b2)²)\n//\n// Interpretation:\n// 0 - 1: Not perceptible by human eye\n// 1 - 2: Perceptible through close observation\n// 2 - 10: Perceptible at a glance\n// 11 - 49: Colors are more similar than opposite\n// 100+: Colors are exact opposite\n//\n// Limitations:\n// - Lab is not perfectly perceptually uniform\n// - Overestimates differences for saturated colors\n// - Use Delta E 2000 for critical color matching\n\nvariable input: List = {input};\nvariable color1: Color.Lab = input.get(0).to.lab();\nvariable color2: Color.Lab = input.get(1).to.lab();\n\n// Get Lab components\nvariable l1: Number = color1.l;\nvariable a1: Number = color1.a;\nvariable b1: Number = color1.b;\n\nvariable l2: Number = color2.l;\nvariable a2: Number = color2.a;\nvariable b2: Number = color2.b;\n\n// Calculate differences\nvariable delta_l: Number = l1 - l2;\nvariable delta_a: Number = a1 - a2;\nvariable delta_b: Number = b1 - b2;\n\n// Euclidean distance\nvariable sum_squares: Number = delta_l * delta_l + delta_a * delta_a + delta_b * delta_b;\nvariable result: Number = sqrt(sum_squares);\n\nreturn result;"
22
+ },
23
+ "requirements": [
24
+ "https://schema.tokenscript.dev.gcp.tokens.studio/api/v1/core/lab-color/0/"
25
+ ],
26
+ "slug": "delta_e_76"
27
+ }
@@ -0,0 +1,27 @@
1
+ {
2
+ "name": "Delta E OK",
3
+ "type": "function",
4
+ "description": "Calculates perceptual color difference using the OKLab color space (ΔE_OK). This is the Euclidean distance in OKLab space, providing excellent perceptual uniformity. Values: 0 = identical, <0.02 = imperceptible, <0.05 = very close, <0.1 = noticeable, >0.5 = very different.",
5
+ "keyword": "delta_e_ok",
6
+ "input": {
7
+ "type": "object",
8
+ "properties": {
9
+ "color1": {
10
+ "type": "color",
11
+ "description": "First color (reference)"
12
+ },
13
+ "color2": {
14
+ "type": "color",
15
+ "description": "Second color (sample)"
16
+ }
17
+ }
18
+ },
19
+ "script": {
20
+ "type": "https://schema.tokenscript.dev.gcp.tokens.studio/api/v1/core/tokenscript/0/",
21
+ "script": "// Delta E OK (ΔE_OK)\n// Perceptual color difference in OKLab space\n// Reference: Björn Ottosson's OKLab specification\n// Reference: Color.js deltaEOK implementation\n//\n// This is simply the Euclidean distance in OKLab space.\n// OKLab is designed to be perceptually uniform, making this\n// a reliable measure of perceived color difference.\n//\n// Interpretation:\n// 0.00 - Identical colors\n// < 0.02 - Imperceptible difference (JND threshold)\n// < 0.05 - Very close colors\n// < 0.1 - Noticeable but small difference\n// 0.1 - 0.5 - Moderate difference\n// > 0.5 - Very different colors\n//\n// Formula: sqrt((L1-L2)² + (a1-a2)² + (b1-b2)²)\n\nvariable input: List = {input};\nvariable color1: Color.OKLab = input.get(0).to.oklab();\nvariable color2: Color.OKLab = input.get(1).to.oklab();\n\n// Get OKLab components\nvariable l1: Number = color1.l;\nvariable a1: Number = color1.a;\nvariable b1: Number = color1.b;\n\nvariable l2: Number = color2.l;\nvariable a2: Number = color2.a;\nvariable b2: Number = color2.b;\n\n// Calculate differences\nvariable delta_l: Number = l1 - l2;\nvariable delta_a: Number = a1 - a2;\nvariable delta_b: Number = b1 - b2;\n\n// Calculate Euclidean distance (sqrt of sum of squares)\nvariable sum_squares: Number = delta_l * delta_l + delta_a * delta_a + delta_b * delta_b;\nvariable result: Number = sqrt(sum_squares);\n\nreturn result;"
22
+ },
23
+ "requirements": [
24
+ "https://schema.tokenscript.dev.gcp.tokens.studio/api/v1/core/oklab-color/0/"
25
+ ],
26
+ "slug": "delta_e_ok"
27
+ }
@@ -0,0 +1,28 @@
1
+ {
2
+ "name": "Desaturate",
3
+ "type": "function",
4
+ "description": "Decreases color saturation by reducing chroma in OKLCH space. Amount is 0-1 where 0.25 = 25% less saturated.",
5
+ "keyword": "desaturate",
6
+ "input": {
7
+ "type": "object",
8
+ "properties": {
9
+ "color": {
10
+ "type": "color",
11
+ "description": "The color to desaturate"
12
+ },
13
+ "amount": {
14
+ "type": "number",
15
+ "description": "Amount to desaturate (0-1). Default is 0.25"
16
+ }
17
+ }
18
+ },
19
+ "script": {
20
+ "type": "https://schema.tokenscript.dev.gcp.tokens.studio/api/v1/core/tokenscript/0/",
21
+ "script": "// Desaturate a color by decreasing its OKLCH chroma\n// Amount: 0-1 where 0.25 means 25% decrease, 1.0 = full grayscale\n//\n// Algorithm: C' = C * (1 - amount)\n\nvariable input: List = {input};\nvariable color: Color.OKLCH = input.get(0).to.oklch();\n\n// Default amount is 0.25 (25%)\nvariable amount: Number = 0.25;\nif (input.length() > 1) [\n amount = input.get(1);\n];\n\n// Calculate new chroma\nvariable current_c: Number = color.c;\nvariable new_c: Number = current_c * (1 - amount);\n\n// Clamp to valid range\nif (new_c < 0) [ new_c = 0; ];\n\n// Create output in OKLCH, return as sRGB\nvariable result: Color.OKLCH;\nresult.l = color.l;\nresult.c = new_c;\nresult.h = color.h;\n\nreturn result;"
22
+ },
23
+ "requirements": [
24
+ "https://schema.tokenscript.dev.gcp.tokens.studio/api/v1/core/oklch-color/0/",
25
+ "https://schema.tokenscript.dev.gcp.tokens.studio/api/v1/core/srgb-color/0/"
26
+ ],
27
+ "slug": "desaturate"
28
+ }
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "Distributed",
3
+ "type": "function",
4
+ "description": "Creates evenly distributed colors around the OKLCH hue wheel. Perfect for categorical data where each category needs a distinct, visually balanced color.",
5
+ "keyword": "distributed",
6
+ "input": {
7
+ "type": "object",
8
+ "properties": {
9
+ "count": {
10
+ "type": "number",
11
+ "description": "Number of colors to generate. Default is 6"
12
+ },
13
+ "lightness": {
14
+ "type": "number",
15
+ "description": "Lightness for all colors (0-1). Default is 0.7"
16
+ },
17
+ "chroma": {
18
+ "type": "number",
19
+ "description": "Chroma/saturation for all colors (0-0.4). Default is 0.15"
20
+ },
21
+ "start_hue": {
22
+ "type": "number",
23
+ "description": "Starting hue angle (0-360). Default is 30 (orange)"
24
+ }
25
+ }
26
+ },
27
+ "script": {
28
+ "type": "https://schema.tokenscript.dev.gcp.tokens.studio/api/v1/core/tokenscript/0/",
29
+ "script": "// Create evenly distributed categorical colors using OKLCH\n// Colors are spaced equally around the hue wheel\n//\n// Ideal for: pie charts, bar charts, legends, category labels\n// Uses golden angle offset for better distinction with many colors\n\nvariable input: List = {input};\n\n// Default count is 6\nvariable count: Number = 6;\nif (input.length() > 0) [\n count = input.get(0);\n];\n\n// Default lightness is 0.7 (good for both light/dark backgrounds)\nvariable lightness: Number = 0.7;\nif (input.length() > 1) [\n lightness = input.get(1);\n];\n\n// Default chroma is 0.15 (vivid but not overwhelming)\nvariable chroma: Number = 0.15;\nif (input.length() > 2) [\n chroma = input.get(2);\n];\n\n// Default start hue is 30 (orange - visually distinct starting point)\nvariable start_hue: Number = 30;\nif (input.length() > 3) [\n start_hue = input.get(3);\n];\n\n// Calculate hue step (360° / count for even distribution)\nvariable hue_step: Number = 360 / count;\n\nvariable result: List;\nvariable i: Number = 0;\nvariable current_hue: Number = 0;\nvariable color: Color.OKLCH;\n\nwhile (i < count) [\n current_hue = start_hue + i * hue_step;\n if (current_hue >= 360) [ current_hue = current_hue - 360; ];\n \n color.l = lightness;\n color.c = chroma;\n color.h = current_hue;\n \n result = result, color.to.srgb();\n i = i + 1;\n];\n\nreturn result;"
30
+ },
31
+ "requirements": [
32
+ "https://schema.tokenscript.dev.gcp.tokens.studio/api/v1/core/oklch-color/0/",
33
+ "https://schema.tokenscript.dev.gcp.tokens.studio/api/v1/core/srgb-color/0/"
34
+ ],
35
+ "slug": "distributed"
36
+ }
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "Diverging",
3
+ "type": "function",
4
+ "description": "Creates a diverging color palette for heatmaps. Goes from color1 through a neutral midpoint to color2. Perfect for data that diverges from a center value (e.g., -1 to 0 to +1).",
5
+ "keyword": "diverging",
6
+ "input": {
7
+ "type": "object",
8
+ "properties": {
9
+ "color1": {
10
+ "type": "color",
11
+ "description": "Color for negative/low end (e.g., blue)"
12
+ },
13
+ "color2": {
14
+ "type": "color",
15
+ "description": "Color for positive/high end (e.g., red)"
16
+ },
17
+ "count": {
18
+ "type": "number",
19
+ "description": "Number of steps (should be odd for clear midpoint). Default is 9"
20
+ },
21
+ "neutral": {
22
+ "type": "number",
23
+ "description": "Lightness of neutral midpoint (0-1). Default is 0.95 (near white)"
24
+ }
25
+ }
26
+ },
27
+ "script": {
28
+ "type": "https://schema.tokenscript.dev.gcp.tokens.studio/api/v1/core/tokenscript/0/",
29
+ "script": "// Create a diverging color palette for data visualization\n// Goes: color1 → neutral → color2\n//\n// Ideal for: heatmaps, correlation matrices, deviation from mean\n// Example: blue → white → red for temperature anomalies\n\nvariable input: List = {input};\nvariable color1: Color.OKLCH = input.get(0).to.oklch();\nvariable color2: Color.OKLCH = input.get(1).to.oklch();\n\n// Default count is 9 (gives clear midpoint at index 4)\nvariable count: Number = 9;\nif (input.length() > 2) [\n count = input.get(2);\n];\n\n// Default neutral lightness is 0.95 (near white)\nvariable neutral_l: Number = 0.95;\nif (input.length() > 3) [\n neutral_l = input.get(3);\n];\n\n// Calculate midpoint index\nvariable mid: Number = (count - 1) / 2;\n\nvariable result: List;\nvariable i: Number = 0;\nvariable t: Number = 0;\nvariable step_color: Color.OKLCH;\n\nwhile (i < count) [\n if (i < mid) [\n // First half: color1 → neutral\n t = i / mid;\n step_color.l = color1.l + (neutral_l - color1.l) * t;\n step_color.c = color1.c * (1 - t);\n step_color.h = color1.h;\n ] else [\n if (i == mid) [\n // Midpoint: neutral (achromatic)\n step_color.l = neutral_l;\n step_color.c = 0;\n step_color.h = 0;\n ] else [\n // Second half: neutral → color2\n t = (i - mid) / mid;\n step_color.l = neutral_l + (color2.l - neutral_l) * t;\n step_color.c = color2.c * t;\n step_color.h = color2.h;\n ];\n ];\n \n result = result, step_color.to.srgb();\n i = i + 1;\n];\n\nreturn result;"
30
+ },
31
+ "requirements": [
32
+ "https://schema.tokenscript.dev.gcp.tokens.studio/api/v1/core/oklch-color/0/",
33
+ "https://schema.tokenscript.dev.gcp.tokens.studio/api/v1/core/srgb-color/0/"
34
+ ],
35
+ "slug": "diverging"
36
+ }
@@ -0,0 +1,24 @@
1
+ {
2
+ "name": "Grayscale",
3
+ "type": "function",
4
+ "description": "Converts a color to grayscale by removing all chroma in OKLCH space. Preserves perceptual lightness.",
5
+ "keyword": "grayscale",
6
+ "input": {
7
+ "type": "object",
8
+ "properties": {
9
+ "color": {
10
+ "type": "color",
11
+ "description": "The color to convert to grayscale"
12
+ }
13
+ }
14
+ },
15
+ "script": {
16
+ "type": "https://schema.tokenscript.dev.gcp.tokens.studio/api/v1/core/tokenscript/0/",
17
+ "script": "// Convert a color to grayscale by setting OKLCH chroma to 0\n// This preserves perceptual lightness (unlike simple RGB averaging)\n\nvariable input: List = {input};\nvariable color: Color.OKLCH = input.get(0).to.oklch();\n\n// Create grayscale by removing chroma\nvariable result: Color.OKLCH;\nresult.l = color.l;\nresult.c = 0;\nresult.h = 0;\n\nreturn result;"
18
+ },
19
+ "requirements": [
20
+ "https://schema.tokenscript.dev.gcp.tokens.studio/api/v1/core/oklch-color/0/",
21
+ "https://schema.tokenscript.dev.gcp.tokens.studio/api/v1/core/srgb-color/0/"
22
+ ],
23
+ "slug": "grayscale"
24
+ }