@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.
- package/dist/cli/index.cjs +31 -8
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.js +30 -8
- package/dist/cli/index.js.map +1 -1
- package/package.json +2 -1
- package/src/bundler/bundle-schema.ts +146 -0
- package/src/bundler/index.ts +151 -0
- package/src/bundler/schema-dependency-resolver.ts +299 -0
- package/src/bundler/selective-bundler.test.ts +94 -0
- package/src/bundler/selective-bundler.ts +159 -0
- package/src/bundler/types.ts +93 -0
- package/src/bundler/utils.ts +74 -0
- package/src/cli/commands/bundle.integration.test.ts +153 -0
- package/src/cli/commands/bundle.test.ts +57 -0
- package/src/cli/commands/bundle.ts +237 -0
- package/src/cli/commands/list.ts +109 -0
- package/src/cli/config-schema.ts +36 -0
- package/src/cli/index.ts +50 -0
- package/src/cli/output-generator.ts +63 -0
- package/src/downloader/index.ts +248 -0
- package/src/downloader/types.ts +48 -0
- package/src/index.ts +8 -0
- package/src/schemas/functions/adjust_chroma/adjust-chroma.tokenscript +27 -0
- package/src/schemas/functions/adjust_chroma/schema.json +48 -0
- package/src/schemas/functions/adjust_chroma/unit.test.ts +76 -0
- package/src/schemas/functions/adjust_hue/adjust-hue.tokenscript +32 -0
- package/src/schemas/functions/adjust_hue/schema.json +48 -0
- package/src/schemas/functions/adjust_hue/unit.test.ts +68 -0
- package/src/schemas/functions/adjust_lightness/adjust-lightness.tokenscript +31 -0
- package/src/schemas/functions/adjust_lightness/schema.json +48 -0
- package/src/schemas/functions/adjust_lightness/unit.test.ts +88 -0
- package/src/schemas/functions/adjust_to_contrast/adjust-to-contrast.tokenscript +131 -0
- package/src/schemas/functions/adjust_to_contrast/schema.json +56 -0
- package/src/schemas/functions/adjust_to_contrast/unit.test.ts +81 -0
- package/src/schemas/functions/alpha_blend/alpha-blend.tokenscript +46 -0
- package/src/schemas/functions/alpha_blend/schema.json +28 -0
- package/src/schemas/functions/alpha_blend/unit.test.ts +135 -0
- package/src/schemas/functions/alpha_scale/alpha-scale.tokenscript +38 -0
- package/src/schemas/functions/alpha_scale/schema.json +24 -0
- package/src/schemas/functions/alpha_scale/unit.test.ts +50 -0
- package/src/schemas/functions/analogous/analogous.tokenscript +47 -0
- package/src/schemas/functions/analogous/schema.json +28 -0
- package/src/schemas/functions/analogous/unit.test.ts +64 -0
- package/src/schemas/functions/apca_contrast/apca-contrast.tokenscript +129 -0
- package/src/schemas/functions/apca_contrast/schema.json +24 -0
- package/src/schemas/functions/apca_contrast/unit.test.ts +259 -0
- package/src/schemas/functions/are_similar/are-similar.tokenscript +24 -0
- package/src/schemas/functions/are_similar/schema.json +57 -0
- package/src/schemas/functions/are_similar/unit.test.ts +57 -0
- package/src/schemas/functions/auto_text_color/auto-text-color.tokenscript +41 -0
- package/src/schemas/functions/auto_text_color/schema.json +53 -0
- package/src/schemas/functions/auto_text_color/unit.test.ts +122 -0
- package/src/schemas/functions/best_contrast/best-contrast.tokenscript +66 -0
- package/src/schemas/functions/best_contrast/schema.json +24 -0
- package/src/schemas/functions/best_contrast/unit.test.ts +64 -0
- package/src/schemas/functions/chroma/chroma.tokenscript +12 -0
- package/src/schemas/functions/chroma/schema.json +44 -0
- package/src/schemas/functions/chroma/unit.test.ts +86 -0
- package/src/schemas/functions/clamp_chroma/clamp-chroma.tokenscript +21 -0
- package/src/schemas/functions/clamp_chroma/schema.json +52 -0
- package/src/schemas/functions/clamp_chroma/unit.test.ts +60 -0
- package/src/schemas/functions/clamp_lightness/clamp-lightness.tokenscript +21 -0
- package/src/schemas/functions/clamp_lightness/schema.json +52 -0
- package/src/schemas/functions/clamp_lightness/unit.test.ts +76 -0
- package/src/schemas/functions/clamp_to_gamut/clamp-to-gamut.tokenscript +41 -0
- package/src/schemas/functions/clamp_to_gamut/schema.json +20 -0
- package/src/schemas/functions/clamp_to_gamut/unit.test.ts +167 -0
- package/src/schemas/functions/complement/complement.tokenscript +21 -0
- package/src/schemas/functions/complement/schema.json +20 -0
- package/src/schemas/functions/complement/unit.test.ts +81 -0
- package/src/schemas/functions/contrast_ratio/contrast-ratio.tokenscript +36 -0
- package/src/schemas/functions/contrast_ratio/schema.json +24 -0
- package/src/schemas/functions/contrast_ratio/unit.test.ts +91 -0
- package/src/schemas/functions/cooler/cooler.tokenscript +45 -0
- package/src/schemas/functions/cooler/schema.json +43 -0
- package/src/schemas/functions/cooler/unit.test.ts +69 -0
- package/src/schemas/functions/darken/darken.tokenscript +37 -0
- package/src/schemas/functions/darken/schema.json +24 -0
- package/src/schemas/functions/darken/unit.test.ts +105 -0
- package/src/schemas/functions/delta_e_2000/delta-e-2000.tokenscript +184 -0
- package/src/schemas/functions/delta_e_2000/schema.json +36 -0
- package/src/schemas/functions/delta_e_2000/unit.test.ts +243 -0
- package/src/schemas/functions/delta_e_76/delta-e-76.tokenscript +45 -0
- package/src/schemas/functions/delta_e_76/schema.json +24 -0
- package/src/schemas/functions/delta_e_76/unit.test.ts +123 -0
- package/src/schemas/functions/delta_e_ok/delta-e-ok.tokenscript +43 -0
- package/src/schemas/functions/delta_e_ok/schema.json +24 -0
- package/src/schemas/functions/delta_e_ok/unit.test.ts +235 -0
- package/src/schemas/functions/desaturate/desaturate.tokenscript +32 -0
- package/src/schemas/functions/desaturate/schema.json +24 -0
- package/src/schemas/functions/desaturate/unit.test.ts +54 -0
- package/src/schemas/functions/distributed/distributed.tokenscript +54 -0
- package/src/schemas/functions/distributed/schema.json +32 -0
- package/src/schemas/functions/distributed/unit.test.ts +58 -0
- package/src/schemas/functions/diverging/diverging.tokenscript +58 -0
- package/src/schemas/functions/diverging/schema.json +32 -0
- package/src/schemas/functions/diverging/unit.test.ts +70 -0
- package/src/schemas/functions/grayscale/grayscale.tokenscript +17 -0
- package/src/schemas/functions/grayscale/schema.json +20 -0
- package/src/schemas/functions/grayscale/unit.test.ts +79 -0
- package/src/schemas/functions/harmonize/harmonize.tokenscript +61 -0
- package/src/schemas/functions/harmonize/schema.json +52 -0
- package/src/schemas/functions/harmonize/unit.test.ts +56 -0
- package/src/schemas/functions/hue/hue.tokenscript +12 -0
- package/src/schemas/functions/hue/schema.json +44 -0
- package/src/schemas/functions/hue/unit.test.ts +75 -0
- package/src/schemas/functions/hue_difference/hue-difference.tokenscript +42 -0
- package/src/schemas/functions/hue_difference/schema.json +24 -0
- package/src/schemas/functions/hue_difference/unit.test.ts +125 -0
- package/src/schemas/functions/in_gamut/in-gamut.tokenscript +51 -0
- package/src/schemas/functions/in_gamut/schema.json +24 -0
- package/src/schemas/functions/in_gamut/unit.test.ts +178 -0
- package/src/schemas/functions/interpolate/interpolate.tokenscript +61 -0
- package/src/schemas/functions/interpolate/schema.json +52 -0
- package/src/schemas/functions/interpolate/unit.test.ts +96 -0
- package/src/schemas/functions/invert/invert-initializer.tokenscript +29 -0
- package/src/schemas/functions/invert/schema.json +20 -0
- package/src/schemas/functions/invert/unit.test.ts +216 -0
- package/src/schemas/functions/is_cool/is-cool.tokenscript +41 -0
- package/src/schemas/functions/is_cool/schema.json +20 -0
- package/src/schemas/functions/is_cool/unit.test.ts +189 -0
- package/src/schemas/functions/is_dark/is-dark.tokenscript +16 -0
- package/src/schemas/functions/is_dark/schema.json +24 -0
- package/src/schemas/functions/is_dark/unit.test.ts +87 -0
- package/src/schemas/functions/is_light/is-light.tokenscript +16 -0
- package/src/schemas/functions/is_light/schema.json +24 -0
- package/src/schemas/functions/is_light/unit.test.ts +86 -0
- package/src/schemas/functions/is_neutral/is-neutral.tokenscript +16 -0
- package/src/schemas/functions/is_neutral/schema.json +53 -0
- package/src/schemas/functions/is_neutral/unit.test.ts +85 -0
- package/src/schemas/functions/is_warm/is-warm.tokenscript +62 -0
- package/src/schemas/functions/is_warm/schema.json +20 -0
- package/src/schemas/functions/is_warm/unit.test.ts +161 -0
- package/src/schemas/functions/lighten/lighten.tokenscript +37 -0
- package/src/schemas/functions/lighten/schema.json +24 -0
- package/src/schemas/functions/lighten/unit.test.ts +109 -0
- package/src/schemas/functions/lightness/lightness.tokenscript +12 -0
- package/src/schemas/functions/lightness/schema.json +49 -0
- package/src/schemas/functions/lightness/unit.test.ts +99 -0
- package/src/schemas/functions/luminance/luminance.tokenscript +16 -0
- package/src/schemas/functions/luminance/schema.json +20 -0
- package/src/schemas/functions/luminance/unit.test.ts +105 -0
- package/src/schemas/functions/meets_contrast/meets-contrast.tokenscript +49 -0
- package/src/schemas/functions/meets_contrast/schema.json +28 -0
- package/src/schemas/functions/meets_contrast/unit.test.ts +170 -0
- package/src/schemas/functions/mix/mix.tokenscript +47 -0
- package/src/schemas/functions/mix/schema.json +28 -0
- package/src/schemas/functions/mix/unit.test.ts +95 -0
- package/src/schemas/functions/monochromatic/monochromatic.tokenscript +72 -0
- package/src/schemas/functions/monochromatic/schema.json +24 -0
- package/src/schemas/functions/monochromatic/unit.test.ts +91 -0
- package/src/schemas/functions/muted/muted.tokenscript +25 -0
- package/src/schemas/functions/muted/schema.json +48 -0
- package/src/schemas/functions/muted/unit.test.ts +100 -0
- package/src/schemas/functions/neutral_variant/neutral-variant.tokenscript +23 -0
- package/src/schemas/functions/neutral_variant/schema.json +48 -0
- package/src/schemas/functions/neutral_variant/unit.test.ts +102 -0
- package/src/schemas/functions/relative_luminance/relative-luminance.tokenscript +15 -0
- package/src/schemas/functions/relative_luminance/schema.json +49 -0
- package/src/schemas/functions/relative_luminance/unit.test.ts +104 -0
- package/src/schemas/functions/rotate_hue/rotate-hue.tokenscript +20 -0
- package/src/schemas/functions/rotate_hue/schema.json +24 -0
- package/src/schemas/functions/rotate_hue/unit.test.ts +86 -0
- package/src/schemas/functions/saturate/saturate.tokenscript +33 -0
- package/src/schemas/functions/saturate/schema.json +24 -0
- package/src/schemas/functions/saturate/unit.test.ts +59 -0
- package/src/schemas/functions/scale_chroma/scale-chroma.tokenscript +22 -0
- package/src/schemas/functions/scale_chroma/schema.json +48 -0
- package/src/schemas/functions/scale_chroma/unit.test.ts +79 -0
- package/src/schemas/functions/scale_lightness/scale-lightness.tokenscript +23 -0
- package/src/schemas/functions/scale_lightness/schema.json +48 -0
- package/src/schemas/functions/scale_lightness/unit.test.ts +73 -0
- package/src/schemas/functions/sepia/schema.json +48 -0
- package/src/schemas/functions/sepia/sepia.tokenscript +54 -0
- package/src/schemas/functions/sepia/unit.test.ts +88 -0
- package/src/schemas/functions/set_chroma/schema.json +24 -0
- package/src/schemas/functions/set_chroma/set-chroma.tokenscript +18 -0
- package/src/schemas/functions/set_chroma/unit.test.ts +79 -0
- package/src/schemas/functions/set_hue/schema.json +24 -0
- package/src/schemas/functions/set_hue/set-hue.tokenscript +18 -0
- package/src/schemas/functions/set_hue/unit.test.ts +90 -0
- package/src/schemas/functions/set_lightness/schema.json +24 -0
- package/src/schemas/functions/set_lightness/set-lightness.tokenscript +18 -0
- package/src/schemas/functions/set_lightness/unit.test.ts +80 -0
- package/src/schemas/functions/shade_scale/schema.json +24 -0
- package/src/schemas/functions/shade_scale/shade-scale.tokenscript +61 -0
- package/src/schemas/functions/shade_scale/unit.test.ts +64 -0
- package/src/schemas/functions/split_complement/schema.json +24 -0
- package/src/schemas/functions/split_complement/split-complement.tokenscript +38 -0
- package/src/schemas/functions/split_complement/unit.test.ts +53 -0
- package/src/schemas/functions/steps/schema.json +28 -0
- package/src/schemas/functions/steps/steps.tokenscript +54 -0
- package/src/schemas/functions/steps/unit.test.ts +71 -0
- package/src/schemas/functions/tetradic/schema.json +20 -0
- package/src/schemas/functions/tetradic/tetradic.tokenscript +40 -0
- package/src/schemas/functions/tetradic/unit.test.ts +50 -0
- package/src/schemas/functions/tint_scale/schema.json +32 -0
- package/src/schemas/functions/tint_scale/tint-scale.tokenscript +71 -0
- package/src/schemas/functions/tint_scale/unit.test.ts +64 -0
- package/src/schemas/functions/to_gamut/schema.json +48 -0
- package/src/schemas/functions/to_gamut/to-gamut.tokenscript +96 -0
- package/src/schemas/functions/to_gamut/unit.test.ts +97 -0
- package/src/schemas/functions/triadic/schema.json +20 -0
- package/src/schemas/functions/triadic/triadic.tokenscript +33 -0
- package/src/schemas/functions/triadic/unit.test.ts +64 -0
- package/src/schemas/functions/vibrant/schema.json +48 -0
- package/src/schemas/functions/vibrant/unit.test.ts +55 -0
- package/src/schemas/functions/vibrant/vibrant.tokenscript +29 -0
- package/src/schemas/functions/warmer/schema.json +43 -0
- package/src/schemas/functions/warmer/unit.test.ts +69 -0
- package/src/schemas/functions/warmer/warmer.tokenscript +45 -0
- package/src/schemas/functions/wcag_level/schema.json +48 -0
- package/src/schemas/functions/wcag_level/unit.test.ts +75 -0
- package/src/schemas/functions/wcag_level/wcag-level.tokenscript +50 -0
- package/src/schemas/types/css-color/from-hsl-color.tokenscript +16 -0
- package/src/schemas/types/css-color/from-hwb-color.tokenscript +16 -0
- package/src/schemas/types/css-color/from-lab-color.tokenscript +16 -0
- package/src/schemas/types/css-color/from-lch-color.tokenscript +16 -0
- package/src/schemas/types/css-color/from-oklab-color.tokenscript +16 -0
- package/src/schemas/types/css-color/from-oklch-color.tokenscript +16 -0
- package/src/schemas/types/css-color/from-p3-color.tokenscript +16 -0
- package/src/schemas/types/css-color/from-rgb-color.tokenscript +15 -0
- package/src/schemas/types/css-color/from-srgb-color.tokenscript +16 -0
- package/src/schemas/types/css-color/from-srgb-linear-color.tokenscript +16 -0
- package/src/schemas/types/css-color/from-xyz-d50-color.tokenscript +16 -0
- package/src/schemas/types/css-color/from-xyz-d65-color.tokenscript +16 -0
- package/src/schemas/types/css-color/initializer.tokenscript +13 -0
- package/src/schemas/types/css-color/schema.json +148 -0
- package/src/schemas/types/css-color/unit.test.ts +402 -0
- package/src/schemas/types/hex-color/initializer.tokenscript +3 -0
- package/src/schemas/types/hex-color/schema.json +24 -0
- package/src/schemas/types/hex-color/unit.test.ts +123 -0
- package/src/schemas/types/hsl-color/from-srgb.tokenscript +87 -0
- package/src/schemas/types/hsl-color/initializer.tokenscript +16 -0
- package/src/schemas/types/hsl-color/schema.json +48 -0
- package/src/schemas/types/hsl-color/unit.test.ts +201 -0
- package/src/schemas/types/hsv-color/from-srgb.tokenscript +80 -0
- package/src/schemas/types/hsv-color/initializer.tokenscript +16 -0
- package/src/schemas/types/hsv-color/schema.json +48 -0
- package/src/schemas/types/hsv-color/unit.test.ts +162 -0
- package/src/schemas/types/hwb-color/from-hsv.tokenscript +31 -0
- package/src/schemas/types/hwb-color/initializer.tokenscript +16 -0
- package/src/schemas/types/hwb-color/schema.json +48 -0
- package/src/schemas/types/hwb-color/unit.test.ts +150 -0
- package/src/schemas/types/lab-color/from-xyz-d50.tokenscript +78 -0
- package/src/schemas/types/lab-color/initializer.tokenscript +16 -0
- package/src/schemas/types/lab-color/schema.json +48 -0
- package/src/schemas/types/lab-color/unit.test.ts +263 -0
- package/src/schemas/types/lch-color/from-lab.tokenscript +44 -0
- package/src/schemas/types/lch-color/initializer.tokenscript +16 -0
- package/src/schemas/types/lch-color/schema.json +48 -0
- package/src/schemas/types/lch-color/unit.test.ts +173 -0
- package/src/schemas/types/okhsl-color/from-oklab.tokenscript +410 -0
- package/src/schemas/types/okhsl-color/initializer.tokenscript +24 -0
- package/src/schemas/types/okhsl-color/schema.json +48 -0
- package/src/schemas/types/okhsl-color/unit.test.ts +514 -0
- package/src/schemas/types/okhsv-color/from-oklab.tokenscript +286 -0
- package/src/schemas/types/okhsv-color/initializer.tokenscript +24 -0
- package/src/schemas/types/okhsv-color/schema.json +48 -0
- package/src/schemas/types/okhsv-color/unit.test.ts +499 -0
- package/src/schemas/types/oklab-color/from-okhsl.tokenscript +195 -0
- package/src/schemas/types/oklab-color/from-okhsv.tokenscript +197 -0
- package/src/schemas/types/oklab-color/from-oklch.tokenscript +39 -0
- package/src/schemas/types/oklab-color/from-xyz-d65.tokenscript +43 -0
- package/src/schemas/types/oklab-color/initializer.tokenscript +16 -0
- package/src/schemas/types/oklab-color/schema.json +78 -0
- package/src/schemas/types/oklab-color/unit.test.ts +345 -0
- package/src/schemas/types/oklch-color/from-oklab.tokenscript +45 -0
- package/src/schemas/types/oklch-color/initializer.tokenscript +16 -0
- package/src/schemas/types/oklch-color/schema.json +48 -0
- package/src/schemas/types/oklch-color/unit.test.ts +267 -0
- package/src/schemas/types/p3-color/from-p3-linear.tokenscript +59 -0
- package/src/schemas/types/p3-color/initializer.tokenscript +16 -0
- package/src/schemas/types/p3-color/schema.json +48 -0
- package/src/schemas/types/p3-color/unit.test.ts +119 -0
- package/src/schemas/types/p3-linear-color/from-xyz-d65.tokenscript +47 -0
- package/src/schemas/types/p3-linear-color/initializer.tokenscript +16 -0
- package/src/schemas/types/p3-linear-color/schema.json +48 -0
- package/src/schemas/types/p3-linear-color/unit.test.ts +82 -0
- package/src/schemas/types/rgb-color/from-hex.tokenscript +43 -0
- package/src/schemas/types/rgb-color/initializer.tokenscript +16 -0
- package/src/schemas/types/rgb-color/schema.json +55 -0
- package/src/schemas/types/rgb-color/to-hex.tokenscript +42 -0
- package/src/schemas/types/rgb-color/unit.test.ts +302 -0
- package/src/schemas/types/srgb-color/from-hsl.tokenscript +106 -0
- package/src/schemas/types/srgb-color/from-linear.tokenscript +58 -0
- package/src/schemas/types/srgb-color/from-rgb.tokenscript +20 -0
- package/src/schemas/types/srgb-color/initializer.tokenscript +16 -0
- package/src/schemas/types/srgb-color/schema.json +68 -0
- package/src/schemas/types/srgb-color/unit.test.ts +303 -0
- package/src/schemas/types/srgb-linear-color/from-srgb.tokenscript +55 -0
- package/src/schemas/types/srgb-linear-color/from-xyz-d65.tokenscript +34 -0
- package/src/schemas/types/srgb-linear-color/initializer.tokenscript +13 -0
- package/src/schemas/types/srgb-linear-color/schema.json +58 -0
- package/src/schemas/types/srgb-linear-color/unit.test.ts +291 -0
- package/src/schemas/types/xyz-d50-color/from-xyz-d65.tokenscript +36 -0
- package/src/schemas/types/xyz-d50-color/initializer.tokenscript +16 -0
- package/src/schemas/types/xyz-d50-color/schema.json +48 -0
- package/src/schemas/types/xyz-d50-color/unit.test.ts +240 -0
- package/src/schemas/types/xyz-d65-color/from-linear-p3.tokenscript +47 -0
- package/src/schemas/types/xyz-d65-color/from-linear-srgb.tokenscript +38 -0
- package/src/schemas/types/xyz-d65-color/from-oklab.tokenscript +44 -0
- package/src/schemas/types/xyz-d65-color/initializer.tokenscript +16 -0
- package/src/schemas/types/xyz-d65-color/schema.json +68 -0
- package/src/schemas/types/xyz-d65-color/unit.test.ts +319 -0
- package/src/utils/schema-uri.ts +192 -0
- package/src/utils/type.ts +194 -0
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { executeWithSchema } from "@tests/helpers/schema-test-utils";
|
|
2
|
+
import { describe, expect, it } from "vitest";
|
|
3
|
+
|
|
4
|
+
describe("Clamp to Gamut Function", () => {
|
|
5
|
+
describe("Schema Definition", () => {
|
|
6
|
+
it("should have correct schema structure", async () => {
|
|
7
|
+
const { getBundledSchema } = await import("@tests/helpers/schema-test-utils");
|
|
8
|
+
const schema = await getBundledSchema("clamp_to_gamut", "function");
|
|
9
|
+
|
|
10
|
+
expect(schema.name).toBe("Clamp to Gamut");
|
|
11
|
+
expect(schema.type).toBe("function");
|
|
12
|
+
expect((schema as any).keyword).toBe("clamp_to_gamut");
|
|
13
|
+
});
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
describe("In-Gamut Colors", () => {
|
|
17
|
+
it("should not modify colors already in gamut", async () => {
|
|
18
|
+
const result = await executeWithSchema(
|
|
19
|
+
"clamp_to_gamut",
|
|
20
|
+
"function",
|
|
21
|
+
`
|
|
22
|
+
variable c: Color.SRGB;
|
|
23
|
+
c.r = 0.5; c.g = 0.3; c.b = 0.7;
|
|
24
|
+
clamp_to_gamut(c)
|
|
25
|
+
`,
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
expect(result.value.r.value).toBeCloseTo(0.5, 5);
|
|
29
|
+
expect(result.value.g.value).toBeCloseTo(0.3, 5);
|
|
30
|
+
expect(result.value.b.value).toBeCloseTo(0.7, 5);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it("should preserve black", async () => {
|
|
34
|
+
const result = await executeWithSchema(
|
|
35
|
+
"clamp_to_gamut",
|
|
36
|
+
"function",
|
|
37
|
+
`
|
|
38
|
+
variable c: Color.SRGB;
|
|
39
|
+
c.r = 0; c.g = 0; c.b = 0;
|
|
40
|
+
clamp_to_gamut(c)
|
|
41
|
+
`,
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
expect(result.value.r.value).toBe(0);
|
|
45
|
+
expect(result.value.g.value).toBe(0);
|
|
46
|
+
expect(result.value.b.value).toBe(0);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it("should preserve white", async () => {
|
|
50
|
+
const result = await executeWithSchema(
|
|
51
|
+
"clamp_to_gamut",
|
|
52
|
+
"function",
|
|
53
|
+
`
|
|
54
|
+
variable c: Color.SRGB;
|
|
55
|
+
c.r = 1; c.g = 1; c.b = 1;
|
|
56
|
+
clamp_to_gamut(c)
|
|
57
|
+
`,
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
expect(result.value.r.value).toBe(1);
|
|
61
|
+
expect(result.value.g.value).toBe(1);
|
|
62
|
+
expect(result.value.b.value).toBe(1);
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
describe("Clamping Overflow Values", () => {
|
|
67
|
+
it("should clamp R > 1 to 1", async () => {
|
|
68
|
+
const result = await executeWithSchema(
|
|
69
|
+
"clamp_to_gamut",
|
|
70
|
+
"function",
|
|
71
|
+
`
|
|
72
|
+
variable c: Color.SRGB;
|
|
73
|
+
c.r = 1.5; c.g = 0.5; c.b = 0.5;
|
|
74
|
+
clamp_to_gamut(c)
|
|
75
|
+
`,
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
expect(result.value.r.value).toBe(1);
|
|
79
|
+
expect(result.value.g.value).toBeCloseTo(0.5, 5);
|
|
80
|
+
expect(result.value.b.value).toBeCloseTo(0.5, 5);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it("should clamp G > 1 to 1", async () => {
|
|
84
|
+
const result = await executeWithSchema(
|
|
85
|
+
"clamp_to_gamut",
|
|
86
|
+
"function",
|
|
87
|
+
`
|
|
88
|
+
variable c: Color.SRGB;
|
|
89
|
+
c.r = 0.5; c.g = 2.0; c.b = 0.5;
|
|
90
|
+
clamp_to_gamut(c)
|
|
91
|
+
`,
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
expect(result.value.r.value).toBeCloseTo(0.5, 5);
|
|
95
|
+
expect(result.value.g.value).toBe(1);
|
|
96
|
+
expect(result.value.b.value).toBeCloseTo(0.5, 5);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it("should clamp B > 1 to 1", async () => {
|
|
100
|
+
const result = await executeWithSchema(
|
|
101
|
+
"clamp_to_gamut",
|
|
102
|
+
"function",
|
|
103
|
+
`
|
|
104
|
+
variable c: Color.SRGB;
|
|
105
|
+
c.r = 0.5; c.g = 0.5; c.b = 1.3;
|
|
106
|
+
clamp_to_gamut(c)
|
|
107
|
+
`,
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
expect(result.value.r.value).toBeCloseTo(0.5, 5);
|
|
111
|
+
expect(result.value.g.value).toBeCloseTo(0.5, 5);
|
|
112
|
+
expect(result.value.b.value).toBe(1);
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
describe("Clamping Underflow Values", () => {
|
|
117
|
+
it("should clamp R < 0 to 0", async () => {
|
|
118
|
+
const result = await executeWithSchema(
|
|
119
|
+
"clamp_to_gamut",
|
|
120
|
+
"function",
|
|
121
|
+
`
|
|
122
|
+
variable c: Color.SRGB;
|
|
123
|
+
c.r = -0.5; c.g = 0.5; c.b = 0.5;
|
|
124
|
+
clamp_to_gamut(c)
|
|
125
|
+
`,
|
|
126
|
+
);
|
|
127
|
+
|
|
128
|
+
expect(result.value.r.value).toBe(0);
|
|
129
|
+
expect(result.value.g.value).toBeCloseTo(0.5, 5);
|
|
130
|
+
expect(result.value.b.value).toBeCloseTo(0.5, 5);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it("should clamp negative G to 0", async () => {
|
|
134
|
+
const result = await executeWithSchema(
|
|
135
|
+
"clamp_to_gamut",
|
|
136
|
+
"function",
|
|
137
|
+
`
|
|
138
|
+
variable c: Color.SRGB;
|
|
139
|
+
c.r = 0.5; c.g = -0.1; c.b = 0.5;
|
|
140
|
+
clamp_to_gamut(c)
|
|
141
|
+
`,
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
expect(result.value.r.value).toBeCloseTo(0.5, 5);
|
|
145
|
+
expect(result.value.g.value).toBe(0);
|
|
146
|
+
expect(result.value.b.value).toBeCloseTo(0.5, 5);
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
describe("Multiple Channel Clamping", () => {
|
|
151
|
+
it("should clamp all channels that are out of range", async () => {
|
|
152
|
+
const result = await executeWithSchema(
|
|
153
|
+
"clamp_to_gamut",
|
|
154
|
+
"function",
|
|
155
|
+
`
|
|
156
|
+
variable c: Color.SRGB;
|
|
157
|
+
c.r = -0.2; c.g = 1.5; c.b = 2.0;
|
|
158
|
+
clamp_to_gamut(c)
|
|
159
|
+
`,
|
|
160
|
+
);
|
|
161
|
+
|
|
162
|
+
expect(result.value.r.value).toBe(0);
|
|
163
|
+
expect(result.value.g.value).toBe(1);
|
|
164
|
+
expect(result.value.b.value).toBe(1);
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
});
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// Get the complementary color by rotating hue 180° in OKLCH
|
|
2
|
+
// Preserves lightness and chroma for perceptually balanced results
|
|
3
|
+
|
|
4
|
+
variable input: List = {input};
|
|
5
|
+
variable color: Color.OKLCH = input.get(0).to.oklch();
|
|
6
|
+
|
|
7
|
+
// Rotate hue by 180°
|
|
8
|
+
variable new_h: Number = color.h + 180;
|
|
9
|
+
if (new_h >= 360) [ new_h = new_h - 360; ];
|
|
10
|
+
|
|
11
|
+
// Create complementary color
|
|
12
|
+
variable result: Color.OKLCH;
|
|
13
|
+
result.l = color.l;
|
|
14
|
+
result.c = color.c;
|
|
15
|
+
result.h = new_h;
|
|
16
|
+
|
|
17
|
+
return result;
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
@@ -0,0 +1,20 @@
|
|
|
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": "/api/v1/core/tokenscript/0/",
|
|
17
|
+
"script": "./complement.tokenscript"
|
|
18
|
+
},
|
|
19
|
+
"requirements": ["/api/v1/core/oklch-color/0/", "/api/v1/core/srgb-color/0/"]
|
|
20
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for the Complement function
|
|
3
|
+
* Returns the complementary color (180° hue rotation in OKLCH)
|
|
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("Complement Function", () => {
|
|
11
|
+
describe("Schema Definition", () => {
|
|
12
|
+
it("should have correct schema structure", async () => {
|
|
13
|
+
const schema = (await getBundledSchema("complement", "function")) as FunctionSpecification;
|
|
14
|
+
|
|
15
|
+
expect(schema.name).toBe("Complement");
|
|
16
|
+
expect(schema.type).toBe("function");
|
|
17
|
+
expect(schema.keyword).toBe("complement");
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
describe("Function Execution", () => {
|
|
22
|
+
it("should return complementary color (red → cyan)", async () => {
|
|
23
|
+
const result = await executeWithSchema(
|
|
24
|
+
"complement",
|
|
25
|
+
"function",
|
|
26
|
+
`
|
|
27
|
+
variable red: Color.SRGB;
|
|
28
|
+
red.r = 0.9; red.g = 0.2; red.b = 0.2;
|
|
29
|
+
complement(red).to.srgb()
|
|
30
|
+
`,
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
expect(result?.constructor.name).toBe("ColorSymbol");
|
|
34
|
+
const r = (result as any).value.r.value;
|
|
35
|
+
const g = (result as any).value.g.value;
|
|
36
|
+
const b = (result as any).value.b.value;
|
|
37
|
+
// Complement of red-ish should be cyan-ish (g and b higher than r)
|
|
38
|
+
expect(g).toBeGreaterThan(r);
|
|
39
|
+
expect(b).toBeGreaterThan(r);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("should be reversible (complement of complement = original hue)", async () => {
|
|
43
|
+
const result = await executeWithSchema(
|
|
44
|
+
"complement",
|
|
45
|
+
"function",
|
|
46
|
+
`
|
|
47
|
+
variable blue: Color.SRGB;
|
|
48
|
+
blue.r = 0.2; blue.g = 0.3; blue.b = 0.8;
|
|
49
|
+
complement(complement(blue)).to.srgb()
|
|
50
|
+
`,
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
expect(result?.constructor.name).toBe("ColorSymbol");
|
|
54
|
+
const r = (result as any).value.r.value;
|
|
55
|
+
const b = (result as any).value.b.value;
|
|
56
|
+
// Should be back to blue-ish
|
|
57
|
+
expect(b).toBeGreaterThan(r);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it("should preserve lightness", async () => {
|
|
61
|
+
const result = await executeWithSchema(
|
|
62
|
+
"complement",
|
|
63
|
+
"function",
|
|
64
|
+
`
|
|
65
|
+
variable light: Color.SRGB;
|
|
66
|
+
light.r = 0.9; light.g = 0.85; light.b = 0.5;
|
|
67
|
+
complement(light).to.srgb()
|
|
68
|
+
`,
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
expect(result?.constructor.name).toBe("ColorSymbol");
|
|
72
|
+
// Result should have similar luminance
|
|
73
|
+
const r = (result as any).value.r.value;
|
|
74
|
+
const g = (result as any).value.g.value;
|
|
75
|
+
const b = (result as any).value.b.value;
|
|
76
|
+
const avgOriginal = (0.9 + 0.85 + 0.5) / 3;
|
|
77
|
+
const avgResult = (r + g + b) / 3;
|
|
78
|
+
expect(Math.abs(avgOriginal - avgResult)).toBeLessThan(0.3);
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
});
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// Calculate WCAG 2.1 contrast ratio between two colors
|
|
2
|
+
//
|
|
3
|
+
// Returns: 1.0 (identical) to 21.0 (black vs white)
|
|
4
|
+
//
|
|
5
|
+
// WCAG Guidelines:
|
|
6
|
+
// - AA Normal text: ≥ 4.5:1
|
|
7
|
+
// - AA Large text: ≥ 3.0:1
|
|
8
|
+
// - AAA Normal text: ≥ 7.0:1
|
|
9
|
+
// - AAA Large text: ≥ 4.5:1
|
|
10
|
+
//
|
|
11
|
+
// Algorithm:
|
|
12
|
+
// 1. Convert to linear RGB
|
|
13
|
+
// 2. Calculate relative luminance: L = 0.2126*R + 0.7152*G + 0.0722*B
|
|
14
|
+
// 3. Contrast ratio: (L_lighter + 0.05) / (L_darker + 0.05)
|
|
15
|
+
|
|
16
|
+
variable input: List = {input};
|
|
17
|
+
variable color1: Color.LinearSRGB = input.get(0).to.linearsrgb();
|
|
18
|
+
variable color2: Color.LinearSRGB = input.get(1).to.linearsrgb();
|
|
19
|
+
|
|
20
|
+
// Calculate relative luminance for each color
|
|
21
|
+
variable lum1: Number = 0.2126 * color1.r + 0.7152 * color1.g + 0.0722 * color1.b;
|
|
22
|
+
variable lum2: Number = 0.2126 * color2.r + 0.7152 * color2.g + 0.0722 * color2.b;
|
|
23
|
+
|
|
24
|
+
// Determine lighter and darker
|
|
25
|
+
variable lighter: Number = lum1;
|
|
26
|
+
variable darker: Number = lum2;
|
|
27
|
+
if (lum2 > lum1) [
|
|
28
|
+
lighter = lum2;
|
|
29
|
+
darker = lum1;
|
|
30
|
+
];
|
|
31
|
+
|
|
32
|
+
// Calculate contrast ratio
|
|
33
|
+
variable ratio: Number = (lighter + 0.05) / (darker + 0.05);
|
|
34
|
+
|
|
35
|
+
return ratio;
|
|
36
|
+
|
|
@@ -0,0 +1,24 @@
|
|
|
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": "/api/v1/core/tokenscript/0/",
|
|
21
|
+
"script": "./contrast-ratio.tokenscript"
|
|
22
|
+
},
|
|
23
|
+
"requirements": ["/api/v1/core/srgb-linear-color/0/"]
|
|
24
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for the Contrast Ratio function
|
|
3
|
+
* Calculates WCAG 2.1 contrast ratio between two colors
|
|
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("Contrast Ratio Function", () => {
|
|
11
|
+
describe("Schema Definition", () => {
|
|
12
|
+
it("should have correct schema structure", async () => {
|
|
13
|
+
const schema = (await getBundledSchema(
|
|
14
|
+
"contrast_ratio",
|
|
15
|
+
"function",
|
|
16
|
+
)) as FunctionSpecification;
|
|
17
|
+
|
|
18
|
+
expect(schema.name).toBe("Contrast Ratio");
|
|
19
|
+
expect(schema.type).toBe("function");
|
|
20
|
+
expect(schema.keyword).toBe("contrast_ratio");
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
describe("Function Execution", () => {
|
|
25
|
+
it("should return 21:1 for black on white", async () => {
|
|
26
|
+
const result = await executeWithSchema(
|
|
27
|
+
"contrast_ratio",
|
|
28
|
+
"function",
|
|
29
|
+
`
|
|
30
|
+
variable white: Color.SRGB;
|
|
31
|
+
white.r = 1; white.g = 1; white.b = 1;
|
|
32
|
+
variable black: Color.SRGB;
|
|
33
|
+
black.r = 0; black.g = 0; black.b = 0;
|
|
34
|
+
contrast_ratio(white, black)
|
|
35
|
+
`,
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
expect(result).toBeDefined();
|
|
39
|
+
const ratio = (result as any).value ?? result;
|
|
40
|
+
expect(ratio).toBeCloseTo(21, 0);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it("should return 1:1 for identical colors", async () => {
|
|
44
|
+
const result = await executeWithSchema(
|
|
45
|
+
"contrast_ratio",
|
|
46
|
+
"function",
|
|
47
|
+
`
|
|
48
|
+
variable c1: Color.SRGB;
|
|
49
|
+
c1.r = 0.5; c1.g = 0.5; c1.b = 0.5;
|
|
50
|
+
variable c2: Color.SRGB;
|
|
51
|
+
c2.r = 0.5; c2.g = 0.5; c2.b = 0.5;
|
|
52
|
+
contrast_ratio(c1, c2)
|
|
53
|
+
`,
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
expect(result).toBeDefined();
|
|
57
|
+
const ratio = (result as any).value ?? result;
|
|
58
|
+
expect(ratio).toBeCloseTo(1, 0);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it("should be symmetrical (a,b = b,a)", async () => {
|
|
62
|
+
const result1 = await executeWithSchema(
|
|
63
|
+
"contrast_ratio",
|
|
64
|
+
"function",
|
|
65
|
+
`
|
|
66
|
+
variable dark: Color.SRGB;
|
|
67
|
+
dark.r = 0.2; dark.g = 0.2; dark.b = 0.3;
|
|
68
|
+
variable light: Color.SRGB;
|
|
69
|
+
light.r = 0.8; light.g = 0.85; light.b = 0.9;
|
|
70
|
+
contrast_ratio(dark, light)
|
|
71
|
+
`,
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
const result2 = await executeWithSchema(
|
|
75
|
+
"contrast_ratio",
|
|
76
|
+
"function",
|
|
77
|
+
`
|
|
78
|
+
variable dark: Color.SRGB;
|
|
79
|
+
dark.r = 0.2; dark.g = 0.2; dark.b = 0.3;
|
|
80
|
+
variable light: Color.SRGB;
|
|
81
|
+
light.r = 0.8; light.g = 0.85; light.b = 0.9;
|
|
82
|
+
contrast_ratio(light, dark)
|
|
83
|
+
`,
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
const ratio1 = (result1 as any).value ?? result1;
|
|
87
|
+
const ratio2 = (result2 as any).value ?? result2;
|
|
88
|
+
expect(ratio1).toBeCloseTo(ratio2, 1);
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
});
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// cooler: Shift hue towards cool colors
|
|
2
|
+
//
|
|
3
|
+
// Cool colors are centered around blue (~260° in OKLCH).
|
|
4
|
+
// The function interpolates the hue towards this target via
|
|
5
|
+
// the shortest angular path on the hue wheel.
|
|
6
|
+
//
|
|
7
|
+
// Parameters:
|
|
8
|
+
// color - Input color
|
|
9
|
+
// amount - Shift amount (0 = no change, 1 = fully cool), default 0.25
|
|
10
|
+
//
|
|
11
|
+
// Preserves lightness and chroma.
|
|
12
|
+
|
|
13
|
+
variable input: List = {input};
|
|
14
|
+
variable color: Color.OKLCH = input.get(0).to.oklch();
|
|
15
|
+
variable amount: Number = 0.25;
|
|
16
|
+
|
|
17
|
+
if (input.length() > 1) [
|
|
18
|
+
amount = input.get(1);
|
|
19
|
+
];
|
|
20
|
+
|
|
21
|
+
// Cool hue target (blue in OKLCH is around 260°)
|
|
22
|
+
variable cool_hue: Number = 260;
|
|
23
|
+
|
|
24
|
+
// Calculate shortest path hue difference
|
|
25
|
+
variable hue_diff: Number = cool_hue - color.h;
|
|
26
|
+
|
|
27
|
+
// Wrap to shortest path
|
|
28
|
+
if (hue_diff > 180) [ hue_diff = hue_diff - 360; ];
|
|
29
|
+
if (hue_diff < -180) [ hue_diff = hue_diff + 360; ];
|
|
30
|
+
|
|
31
|
+
// Apply interpolation
|
|
32
|
+
variable new_hue: Number = color.h + (hue_diff * amount);
|
|
33
|
+
|
|
34
|
+
// Normalize to 0-360
|
|
35
|
+
if (new_hue < 0) [ new_hue = new_hue + 360; ];
|
|
36
|
+
if (new_hue >= 360) [ new_hue = new_hue - 360; ];
|
|
37
|
+
|
|
38
|
+
// Create result
|
|
39
|
+
variable result: Color.OKLCH;
|
|
40
|
+
result.l = color.l;
|
|
41
|
+
result.c = color.c;
|
|
42
|
+
result.h = new_hue;
|
|
43
|
+
|
|
44
|
+
return result;
|
|
45
|
+
|
|
@@ -0,0 +1,43 @@
|
|
|
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": ["/api/v1/core/srgb-color/0/", "/api/v1/core/oklch-color/0/"],
|
|
7
|
+
"schema": {
|
|
8
|
+
"type": "object",
|
|
9
|
+
"properties": {
|
|
10
|
+
"input": {
|
|
11
|
+
"type": "array",
|
|
12
|
+
"items": [
|
|
13
|
+
{
|
|
14
|
+
"description": "Color to cool",
|
|
15
|
+
"type": "color"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"description": "Amount to shift (0-1), default 0.25",
|
|
19
|
+
"type": "number"
|
|
20
|
+
}
|
|
21
|
+
],
|
|
22
|
+
"minItems": 1,
|
|
23
|
+
"maxItems": 2
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"required": ["input"]
|
|
27
|
+
},
|
|
28
|
+
"returns": {
|
|
29
|
+
"type": "color",
|
|
30
|
+
"description": "Color shifted towards cool hues"
|
|
31
|
+
},
|
|
32
|
+
"script": {
|
|
33
|
+
"type": "https://schema.tokenscript.dev.gcp.tokens.studio/api/v1/core/tokenscript/0/",
|
|
34
|
+
"script": "./cooler.tokenscript"
|
|
35
|
+
},
|
|
36
|
+
"examples": [
|
|
37
|
+
{
|
|
38
|
+
"description": "Make orange cooler",
|
|
39
|
+
"input": ["#ff6600", 0.5],
|
|
40
|
+
"output": "Orange shifted towards neutral"
|
|
41
|
+
}
|
|
42
|
+
]
|
|
43
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for the cooler function
|
|
3
|
+
* Shifts hue towards cool colors
|
|
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("cooler function", () => {
|
|
11
|
+
describe("Schema Definition", () => {
|
|
12
|
+
it("should have correct schema structure", async () => {
|
|
13
|
+
const schema = (await getBundledSchema("cooler", "function")) as FunctionSpecification;
|
|
14
|
+
|
|
15
|
+
expect(schema.name).toBe("cooler");
|
|
16
|
+
expect(schema.type).toBe("function");
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
describe("Function Execution", () => {
|
|
21
|
+
it("should shift red towards cool (purple)", async () => {
|
|
22
|
+
const result = await executeWithSchema(
|
|
23
|
+
"cooler",
|
|
24
|
+
"function",
|
|
25
|
+
`
|
|
26
|
+
variable red: Color.SRGB;
|
|
27
|
+
red.r = 1; red.g = 0; red.b = 0;
|
|
28
|
+
cooler(red, 0.5).to.srgb()
|
|
29
|
+
`,
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
expect(result).toBeDefined();
|
|
33
|
+
// Red shifted cool should have more blue
|
|
34
|
+
const b = (result as any).value?.b?.value ?? (result as any).value?.b;
|
|
35
|
+
expect(b).toBeGreaterThan(0.1);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it("should shift yellow towards cool (green)", async () => {
|
|
39
|
+
const result = await executeWithSchema(
|
|
40
|
+
"cooler",
|
|
41
|
+
"function",
|
|
42
|
+
`
|
|
43
|
+
variable yellow: Color.SRGB;
|
|
44
|
+
yellow.r = 1; yellow.g = 1; yellow.b = 0;
|
|
45
|
+
cooler(yellow, 0.5).to.srgb()
|
|
46
|
+
`,
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
expect(result).toBeDefined();
|
|
50
|
+
// Yellow shifted cool should have reduced red or increased blue
|
|
51
|
+
const r = (result as any).value?.r?.value ?? (result as any).value?.r;
|
|
52
|
+
expect(r).toBeLessThan(1);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it("should use default amount if not provided", async () => {
|
|
56
|
+
const result = await executeWithSchema(
|
|
57
|
+
"cooler",
|
|
58
|
+
"function",
|
|
59
|
+
`
|
|
60
|
+
variable red: Color.SRGB;
|
|
61
|
+
red.r = 1; red.g = 0; red.b = 0;
|
|
62
|
+
cooler(red).to.srgb()
|
|
63
|
+
`,
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
expect(result).toBeDefined();
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
});
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// darken: Decrease lightness proportionally towards black
|
|
2
|
+
// Amount: 0-1 where 0.25 means 25% closer to black
|
|
3
|
+
//
|
|
4
|
+
// Algorithm: L' = L * (1 - amount)
|
|
5
|
+
// This ensures we approach black (L=0) proportionally.
|
|
6
|
+
//
|
|
7
|
+
// Input: Any color space (converted to OKLab internally)
|
|
8
|
+
// Output: OKLCH (working space)
|
|
9
|
+
// To get sRGB: darken(color, 0.25).to.srgb()
|
|
10
|
+
|
|
11
|
+
variable input: List = {input};
|
|
12
|
+
variable color: Color.OKLab = input.get(0).to.oklab();
|
|
13
|
+
|
|
14
|
+
// Default amount is 0.25 (25%)
|
|
15
|
+
variable amount: Number = 0.25;
|
|
16
|
+
if (input.length() > 1) [
|
|
17
|
+
amount = input.get(1);
|
|
18
|
+
];
|
|
19
|
+
|
|
20
|
+
// Calculate new lightness (move toward 0)
|
|
21
|
+
variable current_l: Number = color.l;
|
|
22
|
+
variable new_l: Number = current_l * (1 - amount);
|
|
23
|
+
|
|
24
|
+
// Clamp to valid range
|
|
25
|
+
if (new_l < 0) [ new_l = 0; ];
|
|
26
|
+
|
|
27
|
+
// Create output in OKLab, return as OKLCH (working space)
|
|
28
|
+
variable result: Color.OKLab;
|
|
29
|
+
result.l = new_l;
|
|
30
|
+
result.a = color.a;
|
|
31
|
+
result.b = color.b;
|
|
32
|
+
|
|
33
|
+
return result.to.oklch();
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
|
|
@@ -0,0 +1,24 @@
|
|
|
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": "/api/v1/core/tokenscript/0/",
|
|
21
|
+
"script": "./darken.tokenscript"
|
|
22
|
+
},
|
|
23
|
+
"requirements": ["/api/v1/core/oklab-color/0/", "/api/v1/core/srgb-color/0/"]
|
|
24
|
+
}
|