@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,123 @@
|
|
|
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("Delta E 76 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("delta_e_76", "function");
|
|
10
|
+
|
|
11
|
+
expect(schema.name).toBe("Delta E 76");
|
|
12
|
+
expect(schema.type).toBe("function");
|
|
13
|
+
expect((schema as any).keyword).toBe("delta_e_76");
|
|
14
|
+
});
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
describe("Basic Calculations", () => {
|
|
18
|
+
it("should return 0 for identical colors", async () => {
|
|
19
|
+
const result = await executeWithSchema(
|
|
20
|
+
"delta_e_76",
|
|
21
|
+
"function",
|
|
22
|
+
`
|
|
23
|
+
variable c1: Color.SRGB;
|
|
24
|
+
c1.r = 0.5; c1.g = 0.3; c1.b = 0.7;
|
|
25
|
+
variable c2: Color.SRGB;
|
|
26
|
+
c2.r = 0.5; c2.g = 0.3; c2.b = 0.7;
|
|
27
|
+
delta_e_76(c1, c2)
|
|
28
|
+
`,
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
expect(result.value).toBeCloseTo(0, 3);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it("should return large value for black vs white", async () => {
|
|
35
|
+
const result = await executeWithSchema(
|
|
36
|
+
"delta_e_76",
|
|
37
|
+
"function",
|
|
38
|
+
`
|
|
39
|
+
variable c1: Color.SRGB;
|
|
40
|
+
c1.r = 0; c1.g = 0; c1.b = 0;
|
|
41
|
+
variable c2: Color.SRGB;
|
|
42
|
+
c2.r = 1; c2.g = 1; c2.b = 1;
|
|
43
|
+
delta_e_76(c1, c2)
|
|
44
|
+
`,
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
// Black vs white in Lab: L difference is ~100
|
|
48
|
+
expect(result.value).toBeGreaterThan(90);
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
describe("Color.js Parity", () => {
|
|
53
|
+
it("should match Color.js for black vs white", async () => {
|
|
54
|
+
const result = await executeWithSchema(
|
|
55
|
+
"delta_e_76",
|
|
56
|
+
"function",
|
|
57
|
+
`
|
|
58
|
+
variable c1: Color.SRGB;
|
|
59
|
+
c1.r = 0; c1.g = 0; c1.b = 0;
|
|
60
|
+
variable c2: Color.SRGB;
|
|
61
|
+
c2.r = 1; c2.g = 1; c2.b = 1;
|
|
62
|
+
delta_e_76(c1, c2)
|
|
63
|
+
`,
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
const black = new Color("srgb", [0, 0, 0]);
|
|
67
|
+
const white = new Color("srgb", [1, 1, 1]);
|
|
68
|
+
const colorJsDeltaE = black.deltaE(white, "76");
|
|
69
|
+
|
|
70
|
+
expect(result.value).toBeCloseTo(colorJsDeltaE, 1);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it("should match Color.js for chromatic colors", async () => {
|
|
74
|
+
const result = await executeWithSchema(
|
|
75
|
+
"delta_e_76",
|
|
76
|
+
"function",
|
|
77
|
+
`
|
|
78
|
+
variable c1: Color.SRGB;
|
|
79
|
+
c1.r = 0.8; c1.g = 0.2; c1.b = 0.2;
|
|
80
|
+
variable c2: Color.SRGB;
|
|
81
|
+
c2.r = 0.2; c2.g = 0.6; c2.b = 0.8;
|
|
82
|
+
delta_e_76(c1, c2)
|
|
83
|
+
`,
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
const color1 = new Color("srgb", [0.8, 0.2, 0.2]);
|
|
87
|
+
const color2 = new Color("srgb", [0.2, 0.6, 0.8]);
|
|
88
|
+
const colorJsDeltaE = color1.deltaE(color2, "76");
|
|
89
|
+
|
|
90
|
+
expect(result.value).toBeCloseTo(colorJsDeltaE, 1);
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
describe("Symmetry", () => {
|
|
95
|
+
it("should be symmetric", async () => {
|
|
96
|
+
const result1 = await executeWithSchema(
|
|
97
|
+
"delta_e_76",
|
|
98
|
+
"function",
|
|
99
|
+
`
|
|
100
|
+
variable c1: Color.SRGB;
|
|
101
|
+
c1.r = 0.3; c1.g = 0.5; c1.b = 0.7;
|
|
102
|
+
variable c2: Color.SRGB;
|
|
103
|
+
c2.r = 0.7; c2.g = 0.3; c2.b = 0.5;
|
|
104
|
+
delta_e_76(c1, c2)
|
|
105
|
+
`,
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
const result2 = await executeWithSchema(
|
|
109
|
+
"delta_e_76",
|
|
110
|
+
"function",
|
|
111
|
+
`
|
|
112
|
+
variable c1: Color.SRGB;
|
|
113
|
+
c1.r = 0.7; c1.g = 0.3; c1.b = 0.5;
|
|
114
|
+
variable c2: Color.SRGB;
|
|
115
|
+
c2.r = 0.3; c2.g = 0.5; c2.b = 0.7;
|
|
116
|
+
delta_e_76(c1, c2)
|
|
117
|
+
`,
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
expect(result1.value).toBeCloseTo(result2.value, 5);
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
});
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// Delta E OK (ΔE_OK)
|
|
2
|
+
// Perceptual color difference in OKLab space
|
|
3
|
+
// Reference: Björn Ottosson's OKLab specification
|
|
4
|
+
// Reference: Color.js deltaEOK implementation
|
|
5
|
+
//
|
|
6
|
+
// This is simply the Euclidean distance in OKLab space.
|
|
7
|
+
// OKLab is designed to be perceptually uniform, making this
|
|
8
|
+
// a reliable measure of perceived color difference.
|
|
9
|
+
//
|
|
10
|
+
// Interpretation:
|
|
11
|
+
// 0.00 - Identical colors
|
|
12
|
+
// < 0.02 - Imperceptible difference (JND threshold)
|
|
13
|
+
// < 0.05 - Very close colors
|
|
14
|
+
// < 0.1 - Noticeable but small difference
|
|
15
|
+
// 0.1 - 0.5 - Moderate difference
|
|
16
|
+
// > 0.5 - Very different colors
|
|
17
|
+
//
|
|
18
|
+
// Formula: sqrt((L1-L2)² + (a1-a2)² + (b1-b2)²)
|
|
19
|
+
|
|
20
|
+
variable input: List = {input};
|
|
21
|
+
variable color1: Color.OKLab = input.get(0).to.oklab();
|
|
22
|
+
variable color2: Color.OKLab = input.get(1).to.oklab();
|
|
23
|
+
|
|
24
|
+
// Get OKLab components
|
|
25
|
+
variable l1: Number = color1.l;
|
|
26
|
+
variable a1: Number = color1.a;
|
|
27
|
+
variable b1: Number = color1.b;
|
|
28
|
+
|
|
29
|
+
variable l2: Number = color2.l;
|
|
30
|
+
variable a2: Number = color2.a;
|
|
31
|
+
variable b2: Number = color2.b;
|
|
32
|
+
|
|
33
|
+
// Calculate differences
|
|
34
|
+
variable delta_l: Number = l1 - l2;
|
|
35
|
+
variable delta_a: Number = a1 - a2;
|
|
36
|
+
variable delta_b: Number = b1 - b2;
|
|
37
|
+
|
|
38
|
+
// Calculate Euclidean distance (sqrt of sum of squares)
|
|
39
|
+
variable sum_squares: Number = delta_l * delta_l + delta_a * delta_a + delta_b * delta_b;
|
|
40
|
+
variable result: Number = sqrt(sum_squares);
|
|
41
|
+
|
|
42
|
+
return result;
|
|
43
|
+
|
|
@@ -0,0 +1,24 @@
|
|
|
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": "/api/v1/core/tokenscript/0/",
|
|
21
|
+
"script": "./delta-e-ok.tokenscript"
|
|
22
|
+
},
|
|
23
|
+
"requirements": ["/api/v1/core/oklab-color/0/"]
|
|
24
|
+
}
|
|
@@ -0,0 +1,235 @@
|
|
|
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("Delta E OK 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("delta_e_ok", "function");
|
|
10
|
+
|
|
11
|
+
expect(schema.name).toBe("Delta E OK");
|
|
12
|
+
expect(schema.type).toBe("function");
|
|
13
|
+
expect((schema as any).keyword).toBe("delta_e_ok");
|
|
14
|
+
});
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
describe("Basic Calculations", () => {
|
|
18
|
+
it("should return 0 for identical colors", async () => {
|
|
19
|
+
const result = await executeWithSchema(
|
|
20
|
+
"delta_e_ok",
|
|
21
|
+
"function",
|
|
22
|
+
`
|
|
23
|
+
variable c1: Color.SRGB;
|
|
24
|
+
c1.r = 0.5; c1.g = 0.3; c1.b = 0.7;
|
|
25
|
+
variable c2: Color.SRGB;
|
|
26
|
+
c2.r = 0.5; c2.g = 0.3; c2.b = 0.7;
|
|
27
|
+
delta_e_ok(c1, c2)
|
|
28
|
+
`,
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
expect(result.value).toBeCloseTo(0, 5);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it("should return small value for very similar colors", async () => {
|
|
35
|
+
const result = await executeWithSchema(
|
|
36
|
+
"delta_e_ok",
|
|
37
|
+
"function",
|
|
38
|
+
`
|
|
39
|
+
variable c1: Color.SRGB;
|
|
40
|
+
c1.r = 0.5; c1.g = 0.5; c1.b = 0.5;
|
|
41
|
+
variable c2: Color.SRGB;
|
|
42
|
+
c2.r = 0.51; c2.g = 0.5; c2.b = 0.5;
|
|
43
|
+
delta_e_ok(c1, c2)
|
|
44
|
+
`,
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
// Very small difference
|
|
48
|
+
expect(result.value).toBeLessThan(0.05);
|
|
49
|
+
expect(result.value).toBeGreaterThan(0);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it("should return large value for very different colors", async () => {
|
|
53
|
+
const result = await executeWithSchema(
|
|
54
|
+
"delta_e_ok",
|
|
55
|
+
"function",
|
|
56
|
+
`
|
|
57
|
+
variable c1: Color.SRGB;
|
|
58
|
+
c1.r = 0; c1.g = 0; c1.b = 0;
|
|
59
|
+
variable c2: Color.SRGB;
|
|
60
|
+
c2.r = 1; c2.g = 1; c2.b = 1;
|
|
61
|
+
delta_e_ok(c1, c2)
|
|
62
|
+
`,
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
// Black vs white is a very large difference
|
|
66
|
+
expect(result.value).toBeGreaterThan(0.9);
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
describe("Symmetry", () => {
|
|
71
|
+
it("should be symmetric - order of colors should not matter", async () => {
|
|
72
|
+
const result1 = await executeWithSchema(
|
|
73
|
+
"delta_e_ok",
|
|
74
|
+
"function",
|
|
75
|
+
`
|
|
76
|
+
variable c1: Color.SRGB;
|
|
77
|
+
c1.r = 0.2; c1.g = 0.4; c1.b = 0.6;
|
|
78
|
+
variable c2: Color.SRGB;
|
|
79
|
+
c2.r = 0.6; c2.g = 0.2; c2.b = 0.4;
|
|
80
|
+
delta_e_ok(c1, c2)
|
|
81
|
+
`,
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
const result2 = await executeWithSchema(
|
|
85
|
+
"delta_e_ok",
|
|
86
|
+
"function",
|
|
87
|
+
`
|
|
88
|
+
variable c1: Color.SRGB;
|
|
89
|
+
c1.r = 0.6; c1.g = 0.2; c1.b = 0.4;
|
|
90
|
+
variable c2: Color.SRGB;
|
|
91
|
+
c2.r = 0.2; c2.g = 0.4; c2.b = 0.6;
|
|
92
|
+
delta_e_ok(c1, c2)
|
|
93
|
+
`,
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
expect(result1.value).toBeCloseTo(result2.value, 10);
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
describe("Color.js Parity", () => {
|
|
101
|
+
it("should match Color.js deltaE for black vs white", async () => {
|
|
102
|
+
const result = await executeWithSchema(
|
|
103
|
+
"delta_e_ok",
|
|
104
|
+
"function",
|
|
105
|
+
`
|
|
106
|
+
variable c1: Color.SRGB;
|
|
107
|
+
c1.r = 0; c1.g = 0; c1.b = 0;
|
|
108
|
+
variable c2: Color.SRGB;
|
|
109
|
+
c2.r = 1; c2.g = 1; c2.b = 1;
|
|
110
|
+
delta_e_ok(c1, c2)
|
|
111
|
+
`,
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
const black = new Color("srgb", [0, 0, 0]);
|
|
115
|
+
const white = new Color("srgb", [1, 1, 1]);
|
|
116
|
+
const colorJsDeltaE = black.deltaE(white, "OK");
|
|
117
|
+
|
|
118
|
+
expect(result.value).toBeCloseTo(colorJsDeltaE, 3);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it("should match Color.js deltaE for red vs blue", async () => {
|
|
122
|
+
const result = await executeWithSchema(
|
|
123
|
+
"delta_e_ok",
|
|
124
|
+
"function",
|
|
125
|
+
`
|
|
126
|
+
variable c1: Color.SRGB;
|
|
127
|
+
c1.r = 1; c1.g = 0; c1.b = 0;
|
|
128
|
+
variable c2: Color.SRGB;
|
|
129
|
+
c2.r = 0; c2.g = 0; c2.b = 1;
|
|
130
|
+
delta_e_ok(c1, c2)
|
|
131
|
+
`,
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
const red = new Color("srgb", [1, 0, 0]);
|
|
135
|
+
const blue = new Color("srgb", [0, 0, 1]);
|
|
136
|
+
const colorJsDeltaE = red.deltaE(blue, "OK");
|
|
137
|
+
|
|
138
|
+
expect(result.value).toBeCloseTo(colorJsDeltaE, 3);
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
it("should match Color.js deltaE for similar grays", async () => {
|
|
142
|
+
const result = await executeWithSchema(
|
|
143
|
+
"delta_e_ok",
|
|
144
|
+
"function",
|
|
145
|
+
`
|
|
146
|
+
variable c1: Color.SRGB;
|
|
147
|
+
c1.r = 0.5; c1.g = 0.5; c1.b = 0.5;
|
|
148
|
+
variable c2: Color.SRGB;
|
|
149
|
+
c2.r = 0.55; c2.g = 0.55; c2.b = 0.55;
|
|
150
|
+
delta_e_ok(c1, c2)
|
|
151
|
+
`,
|
|
152
|
+
);
|
|
153
|
+
|
|
154
|
+
const gray1 = new Color("srgb", [0.5, 0.5, 0.5]);
|
|
155
|
+
const gray2 = new Color("srgb", [0.55, 0.55, 0.55]);
|
|
156
|
+
const colorJsDeltaE = gray1.deltaE(gray2, "OK");
|
|
157
|
+
|
|
158
|
+
expect(result.value).toBeCloseTo(colorJsDeltaE, 3);
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
it("should match Color.js deltaE for chromatic colors", async () => {
|
|
162
|
+
const result = await executeWithSchema(
|
|
163
|
+
"delta_e_ok",
|
|
164
|
+
"function",
|
|
165
|
+
`
|
|
166
|
+
variable c1: Color.SRGB;
|
|
167
|
+
c1.r = 0.8; c1.g = 0.2; c1.b = 0.4;
|
|
168
|
+
variable c2: Color.SRGB;
|
|
169
|
+
c2.r = 0.3; c2.g = 0.6; c2.b = 0.5;
|
|
170
|
+
delta_e_ok(c1, c2)
|
|
171
|
+
`,
|
|
172
|
+
);
|
|
173
|
+
|
|
174
|
+
const color1 = new Color("srgb", [0.8, 0.2, 0.4]);
|
|
175
|
+
const color2 = new Color("srgb", [0.3, 0.6, 0.5]);
|
|
176
|
+
const colorJsDeltaE = color1.deltaE(color2, "OK");
|
|
177
|
+
|
|
178
|
+
expect(result.value).toBeCloseTo(colorJsDeltaE, 3);
|
|
179
|
+
});
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
describe("Perceptual Thresholds", () => {
|
|
183
|
+
it("should detect imperceptible difference (< 0.02 JND)", async () => {
|
|
184
|
+
const result = await executeWithSchema(
|
|
185
|
+
"delta_e_ok",
|
|
186
|
+
"function",
|
|
187
|
+
`
|
|
188
|
+
variable c1: Color.SRGB;
|
|
189
|
+
c1.r = 0.5; c1.g = 0.5; c1.b = 0.5;
|
|
190
|
+
variable c2: Color.SRGB;
|
|
191
|
+
c2.r = 0.502; c2.g = 0.5; c2.b = 0.5;
|
|
192
|
+
delta_e_ok(c1, c2)
|
|
193
|
+
`,
|
|
194
|
+
);
|
|
195
|
+
|
|
196
|
+
// Should be below JND threshold
|
|
197
|
+
expect(result.value).toBeLessThan(0.02);
|
|
198
|
+
});
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
describe("Edge Cases", () => {
|
|
202
|
+
it("should handle primary colors", async () => {
|
|
203
|
+
const result = await executeWithSchema(
|
|
204
|
+
"delta_e_ok",
|
|
205
|
+
"function",
|
|
206
|
+
`
|
|
207
|
+
variable c1: Color.SRGB;
|
|
208
|
+
c1.r = 1; c1.g = 0; c1.b = 0;
|
|
209
|
+
variable c2: Color.SRGB;
|
|
210
|
+
c2.r = 0; c2.g = 1; c2.b = 0;
|
|
211
|
+
delta_e_ok(c1, c2)
|
|
212
|
+
`,
|
|
213
|
+
);
|
|
214
|
+
|
|
215
|
+
// Red vs green should be a significant difference
|
|
216
|
+
expect(result.value).toBeGreaterThan(0.3);
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
it("should always return non-negative values", async () => {
|
|
220
|
+
const result = await executeWithSchema(
|
|
221
|
+
"delta_e_ok",
|
|
222
|
+
"function",
|
|
223
|
+
`
|
|
224
|
+
variable c1: Color.SRGB;
|
|
225
|
+
c1.r = 0.1; c1.g = 0.9; c1.b = 0.5;
|
|
226
|
+
variable c2: Color.SRGB;
|
|
227
|
+
c2.r = 0.9; c2.g = 0.1; c2.b = 0.5;
|
|
228
|
+
delta_e_ok(c1, c2)
|
|
229
|
+
`,
|
|
230
|
+
);
|
|
231
|
+
|
|
232
|
+
expect(result.value).toBeGreaterThanOrEqual(0);
|
|
233
|
+
});
|
|
234
|
+
});
|
|
235
|
+
});
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// Desaturate a color by decreasing its OKLCH chroma
|
|
2
|
+
// Amount: 0-1 where 0.25 means 25% decrease, 1.0 = full grayscale
|
|
3
|
+
//
|
|
4
|
+
// Algorithm: C' = C * (1 - amount)
|
|
5
|
+
|
|
6
|
+
variable input: List = {input};
|
|
7
|
+
variable color: Color.OKLCH = input.get(0).to.oklch();
|
|
8
|
+
|
|
9
|
+
// Default amount is 0.25 (25%)
|
|
10
|
+
variable amount: Number = 0.25;
|
|
11
|
+
if (input.length() > 1) [
|
|
12
|
+
amount = input.get(1);
|
|
13
|
+
];
|
|
14
|
+
|
|
15
|
+
// Calculate new chroma
|
|
16
|
+
variable current_c: Number = color.c;
|
|
17
|
+
variable new_c: Number = current_c * (1 - amount);
|
|
18
|
+
|
|
19
|
+
// Clamp to valid range
|
|
20
|
+
if (new_c < 0) [ new_c = 0; ];
|
|
21
|
+
|
|
22
|
+
// Create output in OKLCH, return as sRGB
|
|
23
|
+
variable result: Color.OKLCH;
|
|
24
|
+
result.l = color.l;
|
|
25
|
+
result.c = new_c;
|
|
26
|
+
result.h = color.h;
|
|
27
|
+
|
|
28
|
+
return result;
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
|
|
@@ -0,0 +1,24 @@
|
|
|
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": "/api/v1/core/tokenscript/0/",
|
|
21
|
+
"script": "./desaturate.tokenscript"
|
|
22
|
+
},
|
|
23
|
+
"requirements": ["/api/v1/core/oklch-color/0/", "/api/v1/core/srgb-color/0/"]
|
|
24
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for the Desaturate function
|
|
3
|
+
* Decreases color saturation by reducing OKLCH chroma
|
|
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("Desaturate Function", () => {
|
|
11
|
+
describe("Schema Definition", () => {
|
|
12
|
+
it("should have correct schema structure", async () => {
|
|
13
|
+
const schema = (await getBundledSchema("desaturate", "function")) as FunctionSpecification;
|
|
14
|
+
|
|
15
|
+
expect(schema.name).toBe("Desaturate");
|
|
16
|
+
expect(schema.type).toBe("function");
|
|
17
|
+
expect(schema.keyword).toBe("desaturate");
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
describe("Function Execution", () => {
|
|
22
|
+
it("should decrease saturation of a vivid color", async () => {
|
|
23
|
+
const result = await executeWithSchema(
|
|
24
|
+
"desaturate",
|
|
25
|
+
"function",
|
|
26
|
+
`
|
|
27
|
+
variable vivid: Color.SRGB;
|
|
28
|
+
vivid.r = 0.9; vivid.g = 0.2; vivid.b = 0.2;
|
|
29
|
+
desaturate(vivid, 0.1).to.srgb()
|
|
30
|
+
`,
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
expect(result?.constructor.name).toBe("ColorSymbol");
|
|
34
|
+
// Desaturated color channels should be closer together
|
|
35
|
+
const r = (result as any).value.r.value;
|
|
36
|
+
const g = (result as any).value.g.value;
|
|
37
|
+
expect(r - g).toBeLessThan(0.9 - 0.2);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it("should use default amount of 0.1", async () => {
|
|
41
|
+
const result = await executeWithSchema(
|
|
42
|
+
"desaturate",
|
|
43
|
+
"function",
|
|
44
|
+
`
|
|
45
|
+
variable color: Color.SRGB;
|
|
46
|
+
color.r = 0.8; color.g = 0.3; color.b = 0.3;
|
|
47
|
+
desaturate(color).to.srgb()
|
|
48
|
+
`,
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
expect(result?.constructor.name).toBe("ColorSymbol");
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
});
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// Create evenly distributed categorical colors using OKLCH
|
|
2
|
+
// Colors are spaced equally around the hue wheel
|
|
3
|
+
//
|
|
4
|
+
// Ideal for: pie charts, bar charts, legends, category labels
|
|
5
|
+
// Uses golden angle offset for better distinction with many colors
|
|
6
|
+
|
|
7
|
+
variable input: List = {input};
|
|
8
|
+
|
|
9
|
+
// Default count is 6
|
|
10
|
+
variable count: Number = 6;
|
|
11
|
+
if (input.length() > 0) [
|
|
12
|
+
count = input.get(0);
|
|
13
|
+
];
|
|
14
|
+
|
|
15
|
+
// Default lightness is 0.7 (good for both light/dark backgrounds)
|
|
16
|
+
variable lightness: Number = 0.7;
|
|
17
|
+
if (input.length() > 1) [
|
|
18
|
+
lightness = input.get(1);
|
|
19
|
+
];
|
|
20
|
+
|
|
21
|
+
// Default chroma is 0.15 (vivid but not overwhelming)
|
|
22
|
+
variable chroma: Number = 0.15;
|
|
23
|
+
if (input.length() > 2) [
|
|
24
|
+
chroma = input.get(2);
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
// Default start hue is 30 (orange - visually distinct starting point)
|
|
28
|
+
variable start_hue: Number = 30;
|
|
29
|
+
if (input.length() > 3) [
|
|
30
|
+
start_hue = input.get(3);
|
|
31
|
+
];
|
|
32
|
+
|
|
33
|
+
// Calculate hue step (360° / count for even distribution)
|
|
34
|
+
variable hue_step: Number = 360 / count;
|
|
35
|
+
|
|
36
|
+
variable result: List;
|
|
37
|
+
variable i: Number = 0;
|
|
38
|
+
variable current_hue: Number = 0;
|
|
39
|
+
variable color: Color.OKLCH;
|
|
40
|
+
|
|
41
|
+
while (i < count) [
|
|
42
|
+
current_hue = start_hue + i * hue_step;
|
|
43
|
+
if (current_hue >= 360) [ current_hue = current_hue - 360; ];
|
|
44
|
+
|
|
45
|
+
color.l = lightness;
|
|
46
|
+
color.c = chroma;
|
|
47
|
+
color.h = current_hue;
|
|
48
|
+
|
|
49
|
+
result = result, color.to.srgb();
|
|
50
|
+
i = i + 1;
|
|
51
|
+
];
|
|
52
|
+
|
|
53
|
+
return result;
|
|
54
|
+
|
|
@@ -0,0 +1,32 @@
|
|
|
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": "/api/v1/core/tokenscript/0/",
|
|
29
|
+
"script": "./distributed.tokenscript"
|
|
30
|
+
},
|
|
31
|
+
"requirements": ["/api/v1/core/oklch-color/0/", "/api/v1/core/srgb-color/0/"]
|
|
32
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for the Distributed function
|
|
3
|
+
* Creates evenly distributed categorical colors using 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("Distributed Function", () => {
|
|
11
|
+
describe("Schema Definition", () => {
|
|
12
|
+
it("should have correct schema structure", async () => {
|
|
13
|
+
const schema = (await getBundledSchema("distributed", "function")) as FunctionSpecification;
|
|
14
|
+
|
|
15
|
+
expect(schema.name).toBe("Distributed");
|
|
16
|
+
expect(schema.type).toBe("function");
|
|
17
|
+
expect(schema.keyword).toBe("distributed");
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
describe("Function Execution", () => {
|
|
22
|
+
it("should generate 6 colors by default", async () => {
|
|
23
|
+
const result = await executeWithSchema(
|
|
24
|
+
"distributed",
|
|
25
|
+
"function",
|
|
26
|
+
`
|
|
27
|
+
distributed()
|
|
28
|
+
`,
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
expect(result).toBeDefined();
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it("should generate specified number of colors", async () => {
|
|
35
|
+
const result = await executeWithSchema(
|
|
36
|
+
"distributed",
|
|
37
|
+
"function",
|
|
38
|
+
`
|
|
39
|
+
distributed(8)
|
|
40
|
+
`,
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
expect(result).toBeDefined();
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it("should allow custom lightness and chroma", async () => {
|
|
47
|
+
const result = await executeWithSchema(
|
|
48
|
+
"distributed",
|
|
49
|
+
"function",
|
|
50
|
+
`
|
|
51
|
+
distributed(5, 0.6, 0.2)
|
|
52
|
+
`,
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
expect(result).toBeDefined();
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
});
|