@tokens-studio/tokenscript-schemas 0.0.11 → 0.0.12
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 +30 -4
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.js +29 -4
- 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 +240 -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
- package/dist/cli/index.d.cts +0 -1
- package/dist/cli/index.d.ts +0 -1
- package/dist/index.d.cts +0 -158
- package/dist/index.d.ts +0 -158
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
// Alpha Blend (Porter-Duff Over Compositing)
|
|
2
|
+
// Reference: Porter & Duff "Compositing Digital Images" (1984)
|
|
3
|
+
// Reference: W3C CSS Color Level 4 - Alpha Compositing
|
|
4
|
+
//
|
|
5
|
+
// Formula: result = foreground × α + background × (1 - α)
|
|
6
|
+
//
|
|
7
|
+
// This is the standard "over" operation:
|
|
8
|
+
// - α = 0: result is entirely background
|
|
9
|
+
// - α = 1: result is entirely foreground
|
|
10
|
+
// - 0 < α < 1: blend of both colors
|
|
11
|
+
//
|
|
12
|
+
// Used in:
|
|
13
|
+
// - CSS opacity and rgba
|
|
14
|
+
// - Semi-transparent overlays
|
|
15
|
+
// - Gradient stops
|
|
16
|
+
// - Glass/frosted effects
|
|
17
|
+
|
|
18
|
+
variable input: List = {input};
|
|
19
|
+
variable fg: Color.SRGB = input.get(0).to.srgb();
|
|
20
|
+
variable bg: Color.SRGB = input.get(1).to.srgb();
|
|
21
|
+
|
|
22
|
+
// Default alpha is 0.5 (50% opacity)
|
|
23
|
+
variable alpha: Number = 0.5;
|
|
24
|
+
if (input.length() > 2) [
|
|
25
|
+
alpha = input.get(2);
|
|
26
|
+
];
|
|
27
|
+
|
|
28
|
+
// Clamp alpha to valid range
|
|
29
|
+
if (alpha < 0) [ alpha = 0; ];
|
|
30
|
+
if (alpha > 1) [ alpha = 1; ];
|
|
31
|
+
|
|
32
|
+
// Porter-Duff "over" compositing
|
|
33
|
+
variable inv_alpha: Number = 1 - alpha;
|
|
34
|
+
|
|
35
|
+
variable r: Number = fg.r * alpha + bg.r * inv_alpha;
|
|
36
|
+
variable g: Number = fg.g * alpha + bg.g * inv_alpha;
|
|
37
|
+
variable b: Number = fg.b * alpha + bg.b * inv_alpha;
|
|
38
|
+
|
|
39
|
+
// Create result
|
|
40
|
+
variable result: Color.SRGB;
|
|
41
|
+
result.r = r;
|
|
42
|
+
result.g = g;
|
|
43
|
+
result.b = b;
|
|
44
|
+
|
|
45
|
+
return result;
|
|
46
|
+
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "Alpha Blend",
|
|
3
|
+
"type": "function",
|
|
4
|
+
"description": "Performs Porter-Duff 'over' compositing to blend a foreground color over a background color using the foreground's alpha. Formula: result = fg × α + bg × (1-α). Standard alpha compositing used in CSS and graphics software.",
|
|
5
|
+
"keyword": "alpha_blend",
|
|
6
|
+
"input": {
|
|
7
|
+
"type": "object",
|
|
8
|
+
"properties": {
|
|
9
|
+
"foreground": {
|
|
10
|
+
"type": "color",
|
|
11
|
+
"description": "Foreground (top) color"
|
|
12
|
+
},
|
|
13
|
+
"background": {
|
|
14
|
+
"type": "color",
|
|
15
|
+
"description": "Background (bottom) color"
|
|
16
|
+
},
|
|
17
|
+
"alpha": {
|
|
18
|
+
"type": "number",
|
|
19
|
+
"description": "Opacity of foreground (0-1, default: 0.5)"
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"script": {
|
|
24
|
+
"type": "/api/v1/core/tokenscript/0/",
|
|
25
|
+
"script": "./alpha-blend.tokenscript"
|
|
26
|
+
},
|
|
27
|
+
"requirements": ["/api/v1/core/srgb-color/0/"]
|
|
28
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { executeWithSchema } from "@tests/helpers/schema-test-utils";
|
|
2
|
+
import { describe, expect, it } from "vitest";
|
|
3
|
+
|
|
4
|
+
describe("Alpha Blend 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("alpha_blend", "function");
|
|
9
|
+
|
|
10
|
+
expect(schema.name).toBe("Alpha Blend");
|
|
11
|
+
expect(schema.type).toBe("function");
|
|
12
|
+
expect((schema as any).keyword).toBe("alpha_blend");
|
|
13
|
+
});
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
describe("Extreme Alpha Values", () => {
|
|
17
|
+
it("alpha=0 should return background color", async () => {
|
|
18
|
+
const result = await executeWithSchema(
|
|
19
|
+
"alpha_blend",
|
|
20
|
+
"function",
|
|
21
|
+
`
|
|
22
|
+
variable fg: Color.SRGB;
|
|
23
|
+
fg.r = 1; fg.g = 0; fg.b = 0;
|
|
24
|
+
variable bg: Color.SRGB;
|
|
25
|
+
bg.r = 0; bg.g = 0; bg.b = 1;
|
|
26
|
+
alpha_blend(fg, bg, 0)
|
|
27
|
+
`,
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
expect(result.value.r.value).toBeCloseTo(0, 5);
|
|
31
|
+
expect(result.value.g.value).toBeCloseTo(0, 5);
|
|
32
|
+
expect(result.value.b.value).toBeCloseTo(1, 5);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it("alpha=1 should return foreground color", async () => {
|
|
36
|
+
const result = await executeWithSchema(
|
|
37
|
+
"alpha_blend",
|
|
38
|
+
"function",
|
|
39
|
+
`
|
|
40
|
+
variable fg: Color.SRGB;
|
|
41
|
+
fg.r = 1; fg.g = 0; fg.b = 0;
|
|
42
|
+
variable bg: Color.SRGB;
|
|
43
|
+
bg.r = 0; bg.g = 0; bg.b = 1;
|
|
44
|
+
alpha_blend(fg, bg, 1)
|
|
45
|
+
`,
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
expect(result.value.r.value).toBeCloseTo(1, 5);
|
|
49
|
+
expect(result.value.g.value).toBeCloseTo(0, 5);
|
|
50
|
+
expect(result.value.b.value).toBeCloseTo(0, 5);
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
describe("Default Alpha", () => {
|
|
55
|
+
it("should use 0.5 alpha by default", async () => {
|
|
56
|
+
const result = await executeWithSchema(
|
|
57
|
+
"alpha_blend",
|
|
58
|
+
"function",
|
|
59
|
+
`
|
|
60
|
+
variable fg: Color.SRGB;
|
|
61
|
+
fg.r = 1; fg.g = 1; fg.b = 1;
|
|
62
|
+
variable bg: Color.SRGB;
|
|
63
|
+
bg.r = 0; bg.g = 0; bg.b = 0;
|
|
64
|
+
alpha_blend(fg, bg)
|
|
65
|
+
`,
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
// 50% white over black = 50% gray
|
|
69
|
+
expect(result.value.r.value).toBeCloseTo(0.5, 5);
|
|
70
|
+
expect(result.value.g.value).toBeCloseTo(0.5, 5);
|
|
71
|
+
expect(result.value.b.value).toBeCloseTo(0.5, 5);
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
describe("Blending Formula", () => {
|
|
76
|
+
it("should blend correctly at 25% alpha", async () => {
|
|
77
|
+
const result = await executeWithSchema(
|
|
78
|
+
"alpha_blend",
|
|
79
|
+
"function",
|
|
80
|
+
`
|
|
81
|
+
variable fg: Color.SRGB;
|
|
82
|
+
fg.r = 1; fg.g = 0; fg.b = 0;
|
|
83
|
+
variable bg: Color.SRGB;
|
|
84
|
+
bg.r = 0; bg.g = 1; bg.b = 0;
|
|
85
|
+
alpha_blend(fg, bg, 0.25)
|
|
86
|
+
`,
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
// R: 1*0.25 + 0*0.75 = 0.25
|
|
90
|
+
// G: 0*0.25 + 1*0.75 = 0.75
|
|
91
|
+
// B: 0*0.25 + 0*0.75 = 0
|
|
92
|
+
expect(result.value.r.value).toBeCloseTo(0.25, 5);
|
|
93
|
+
expect(result.value.g.value).toBeCloseTo(0.75, 5);
|
|
94
|
+
expect(result.value.b.value).toBeCloseTo(0, 5);
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
describe("Alpha Clamping", () => {
|
|
99
|
+
it("should clamp negative alpha to 0", async () => {
|
|
100
|
+
const result = await executeWithSchema(
|
|
101
|
+
"alpha_blend",
|
|
102
|
+
"function",
|
|
103
|
+
`
|
|
104
|
+
variable fg: Color.SRGB;
|
|
105
|
+
fg.r = 1; fg.g = 0; fg.b = 0;
|
|
106
|
+
variable bg: Color.SRGB;
|
|
107
|
+
bg.r = 0; bg.g = 1; bg.b = 0;
|
|
108
|
+
alpha_blend(fg, bg, -0.5)
|
|
109
|
+
`,
|
|
110
|
+
);
|
|
111
|
+
|
|
112
|
+
// Should be same as alpha=0 (all background)
|
|
113
|
+
expect(result.value.r.value).toBeCloseTo(0, 5);
|
|
114
|
+
expect(result.value.g.value).toBeCloseTo(1, 5);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it("should clamp alpha > 1 to 1", async () => {
|
|
118
|
+
const result = await executeWithSchema(
|
|
119
|
+
"alpha_blend",
|
|
120
|
+
"function",
|
|
121
|
+
`
|
|
122
|
+
variable fg: Color.SRGB;
|
|
123
|
+
fg.r = 1; fg.g = 0; fg.b = 0;
|
|
124
|
+
variable bg: Color.SRGB;
|
|
125
|
+
bg.r = 0; bg.g = 1; bg.b = 0;
|
|
126
|
+
alpha_blend(fg, bg, 1.5)
|
|
127
|
+
`,
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
// Should be same as alpha=1 (all foreground)
|
|
131
|
+
expect(result.value.r.value).toBeCloseTo(1, 5);
|
|
132
|
+
expect(result.value.g.value).toBeCloseTo(0, 5);
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
});
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// Generate alpha/transparency scale
|
|
2
|
+
// Returns colors from 100% opacity down to nearly transparent
|
|
3
|
+
//
|
|
4
|
+
// Default 10 steps: 100%, 90%, 80%, 70%, 60%, 50%, 40%, 30%, 20%, 10%
|
|
5
|
+
// Useful for: overlays, shadows, backgrounds, hover states
|
|
6
|
+
|
|
7
|
+
variable input: List = {input};
|
|
8
|
+
variable base: Color.SRGB = input.get(0).to.srgb();
|
|
9
|
+
|
|
10
|
+
variable count: Number = 10;
|
|
11
|
+
if (input.length() > 1) [
|
|
12
|
+
count = input.get(1);
|
|
13
|
+
];
|
|
14
|
+
|
|
15
|
+
variable result: List;
|
|
16
|
+
variable i: Number = 0;
|
|
17
|
+
variable step_alpha: Number = 0;
|
|
18
|
+
variable step_color: Color.SRGB;
|
|
19
|
+
|
|
20
|
+
while (i < count) [
|
|
21
|
+
// Alpha from 1.0 down to 0.1
|
|
22
|
+
step_alpha = 1 - (i / count);
|
|
23
|
+
|
|
24
|
+
// Create color with alpha
|
|
25
|
+
// Note: This creates the color value; actual alpha handling
|
|
26
|
+
// depends on how the consuming system processes the output
|
|
27
|
+
step_color.r = base.r;
|
|
28
|
+
step_color.g = base.g;
|
|
29
|
+
step_color.b = base.b;
|
|
30
|
+
|
|
31
|
+
// Store alpha as 4th value (RGBA convention)
|
|
32
|
+
// Use .to.srgb() to create a new color instance for each step
|
|
33
|
+
result = result, step_color.to.srgb(), step_alpha;
|
|
34
|
+
i = i + 1;
|
|
35
|
+
];
|
|
36
|
+
|
|
37
|
+
return result;
|
|
38
|
+
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "Alpha Scale",
|
|
3
|
+
"type": "function",
|
|
4
|
+
"description": "Generates transparency variants of a color. Returns colors with progressively lower opacity. Perfect for overlays, shadows, and layered UI elements.",
|
|
5
|
+
"keyword": "alpha_scale",
|
|
6
|
+
"input": {
|
|
7
|
+
"type": "object",
|
|
8
|
+
"properties": {
|
|
9
|
+
"color": {
|
|
10
|
+
"type": "color",
|
|
11
|
+
"description": "Base color"
|
|
12
|
+
},
|
|
13
|
+
"count": {
|
|
14
|
+
"type": "number",
|
|
15
|
+
"description": "Number of alpha steps. Default is 10"
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"script": {
|
|
20
|
+
"type": "/api/v1/core/tokenscript/0/",
|
|
21
|
+
"script": "./alpha-scale.tokenscript"
|
|
22
|
+
},
|
|
23
|
+
"requirements": ["/api/v1/core/srgb-color/0/"]
|
|
24
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for the Alpha Scale function
|
|
3
|
+
* Generates an alpha transparency scale
|
|
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("Alpha Scale Function", () => {
|
|
11
|
+
describe("Schema Definition", () => {
|
|
12
|
+
it("should have correct schema structure", async () => {
|
|
13
|
+
const schema = (await getBundledSchema("alpha_scale", "function")) as FunctionSpecification;
|
|
14
|
+
|
|
15
|
+
expect(schema.name).toBe("Alpha Scale");
|
|
16
|
+
expect(schema.type).toBe("function");
|
|
17
|
+
expect(schema.keyword).toBe("alpha_scale");
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
describe("Function Execution", () => {
|
|
22
|
+
it("should generate alpha scale", async () => {
|
|
23
|
+
const result = await executeWithSchema(
|
|
24
|
+
"alpha_scale",
|
|
25
|
+
"function",
|
|
26
|
+
`
|
|
27
|
+
variable base: Color.SRGB;
|
|
28
|
+
base.r = 0.2; base.g = 0.4; base.b = 0.8;
|
|
29
|
+
alpha_scale(base)
|
|
30
|
+
`,
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
expect(result).toBeDefined();
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it("should generate specified number of steps", async () => {
|
|
37
|
+
const result = await executeWithSchema(
|
|
38
|
+
"alpha_scale",
|
|
39
|
+
"function",
|
|
40
|
+
`
|
|
41
|
+
variable base: Color.SRGB;
|
|
42
|
+
base.r = 0.9; base.g = 0.2; base.b = 0.3;
|
|
43
|
+
alpha_scale(base, 5)
|
|
44
|
+
`,
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
expect(result).toBeDefined();
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
});
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// Generate analogous colors (adjacent hues)
|
|
2
|
+
// Colors are spread evenly around the base hue
|
|
3
|
+
//
|
|
4
|
+
// Use case: Harmonious, subtle palettes
|
|
5
|
+
// Example: 5 colors with 60° spread = -30°, -15°, 0°, +15°, +30°
|
|
6
|
+
|
|
7
|
+
variable input: List = {input};
|
|
8
|
+
variable base: Color.OKLCH = input.get(0).to.oklch();
|
|
9
|
+
|
|
10
|
+
variable count: Number = 5;
|
|
11
|
+
if (input.length() > 1) [
|
|
12
|
+
count = input.get(1);
|
|
13
|
+
];
|
|
14
|
+
|
|
15
|
+
variable spread: Number = 60;
|
|
16
|
+
if (input.length() > 2) [
|
|
17
|
+
spread = input.get(2);
|
|
18
|
+
];
|
|
19
|
+
|
|
20
|
+
// Calculate step size and starting offset
|
|
21
|
+
variable step: Number = spread / (count - 1);
|
|
22
|
+
variable start_offset: Number = 0 - spread / 2;
|
|
23
|
+
|
|
24
|
+
variable result: List;
|
|
25
|
+
variable i: Number = 0;
|
|
26
|
+
variable hue_offset: Number = 0;
|
|
27
|
+
variable new_hue: Number = 0;
|
|
28
|
+
variable color: Color.OKLCH;
|
|
29
|
+
|
|
30
|
+
while (i < count) [
|
|
31
|
+
hue_offset = start_offset + i * step;
|
|
32
|
+
new_hue = base.h + hue_offset;
|
|
33
|
+
|
|
34
|
+
// Normalize hue 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
|
+
color.l = base.l;
|
|
39
|
+
color.c = base.c;
|
|
40
|
+
color.h = new_hue;
|
|
41
|
+
|
|
42
|
+
result = result, color.to.srgb();
|
|
43
|
+
i = i + 1;
|
|
44
|
+
];
|
|
45
|
+
|
|
46
|
+
return result;
|
|
47
|
+
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "Analogous",
|
|
3
|
+
"type": "function",
|
|
4
|
+
"description": "Generates analogous colors - hues adjacent on the color wheel. Creates harmonious, low-contrast palettes. Perfect for backgrounds and subtle variations.",
|
|
5
|
+
"keyword": "analogous",
|
|
6
|
+
"input": {
|
|
7
|
+
"type": "object",
|
|
8
|
+
"properties": {
|
|
9
|
+
"color": {
|
|
10
|
+
"type": "color",
|
|
11
|
+
"description": "Base color"
|
|
12
|
+
},
|
|
13
|
+
"count": {
|
|
14
|
+
"type": "number",
|
|
15
|
+
"description": "Number of colors (odd recommended). Default is 5"
|
|
16
|
+
},
|
|
17
|
+
"spread": {
|
|
18
|
+
"type": "number",
|
|
19
|
+
"description": "Total angle spread in degrees. Default is 60"
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"script": {
|
|
24
|
+
"type": "/api/v1/core/tokenscript/0/",
|
|
25
|
+
"script": "./analogous.tokenscript"
|
|
26
|
+
},
|
|
27
|
+
"requirements": ["/api/v1/core/oklch-color/0/", "/api/v1/core/srgb-color/0/"]
|
|
28
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for the Analogous function
|
|
3
|
+
* Generates analogous colors (adjacent hues)
|
|
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("Analogous Function", () => {
|
|
11
|
+
describe("Schema Definition", () => {
|
|
12
|
+
it("should have correct schema structure", async () => {
|
|
13
|
+
const schema = (await getBundledSchema("analogous", "function")) as FunctionSpecification;
|
|
14
|
+
|
|
15
|
+
expect(schema.name).toBe("Analogous");
|
|
16
|
+
expect(schema.type).toBe("function");
|
|
17
|
+
expect(schema.keyword).toBe("analogous");
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
describe("Function Execution", () => {
|
|
22
|
+
it("should generate 5 colors by default", async () => {
|
|
23
|
+
const result = await executeWithSchema(
|
|
24
|
+
"analogous",
|
|
25
|
+
"function",
|
|
26
|
+
`
|
|
27
|
+
variable base: Color.SRGB;
|
|
28
|
+
base.r = 0.8; base.g = 0.3; base.b = 0.3;
|
|
29
|
+
analogous(base)
|
|
30
|
+
`,
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
expect(result).toBeDefined();
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it("should generate specified number of colors", async () => {
|
|
37
|
+
const result = await executeWithSchema(
|
|
38
|
+
"analogous",
|
|
39
|
+
"function",
|
|
40
|
+
`
|
|
41
|
+
variable base: Color.SRGB;
|
|
42
|
+
base.r = 0.3; base.g = 0.6; base.b = 0.9;
|
|
43
|
+
analogous(base, 3)
|
|
44
|
+
`,
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
expect(result).toBeDefined();
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it("should use custom spread angle", async () => {
|
|
51
|
+
const result = await executeWithSchema(
|
|
52
|
+
"analogous",
|
|
53
|
+
"function",
|
|
54
|
+
`
|
|
55
|
+
variable base: Color.SRGB;
|
|
56
|
+
base.r = 0.5; base.g = 0.8; base.b = 0.3;
|
|
57
|
+
analogous(base, 5, 30)
|
|
58
|
+
`,
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
expect(result).toBeDefined();
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
});
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
// APCA Contrast (Accessible Perceptual Contrast Algorithm)
|
|
2
|
+
// Version: APCA 0.0.98G (W3C/WCAG 3.0 Draft)
|
|
3
|
+
// Reference: https://github.com/Myndex/apca-w3
|
|
4
|
+
// Reference: https://www.w3.org/TR/wcag-3.0/#visual-contrast-of-text
|
|
5
|
+
//
|
|
6
|
+
// Returns Lc (Lightness contrast) value:
|
|
7
|
+
// - Range: approximately -108 to +106
|
|
8
|
+
// - Positive values: light text on dark background
|
|
9
|
+
// - Negative values: dark text on light background
|
|
10
|
+
// - |Lc| >= 75: Preferred for body text
|
|
11
|
+
// - |Lc| >= 60: Minimum for body text
|
|
12
|
+
// - |Lc| >= 45: Minimum for large text (≥24px)
|
|
13
|
+
// - |Lc| >= 30: Minimum for non-text elements
|
|
14
|
+
//
|
|
15
|
+
// Algorithm:
|
|
16
|
+
// 1. Convert to sRGB and linearize with simple 2.4 gamma
|
|
17
|
+
// 2. Calculate screen luminance Y with sRGB coefficients
|
|
18
|
+
// 3. Apply soft black clamp for flare compensation
|
|
19
|
+
// 4. Calculate contrast with asymmetric formula (BoW vs WoB)
|
|
20
|
+
// 5. Apply low clip and offset
|
|
21
|
+
|
|
22
|
+
variable input: List = {input};
|
|
23
|
+
variable text: Color.SRGB = input.get(0).to.srgb();
|
|
24
|
+
variable bg: Color.SRGB = input.get(1).to.srgb();
|
|
25
|
+
|
|
26
|
+
// APCA Constants (from specification)
|
|
27
|
+
// Exponents
|
|
28
|
+
variable norm_bg: Number = 0.56;
|
|
29
|
+
variable norm_txt: Number = 0.57;
|
|
30
|
+
variable rev_txt: Number = 0.62;
|
|
31
|
+
variable rev_bg: Number = 0.65;
|
|
32
|
+
|
|
33
|
+
// Soft black clamp constants
|
|
34
|
+
variable blk_thrs: Number = 0.022;
|
|
35
|
+
variable blk_clmp: Number = 1.414;
|
|
36
|
+
|
|
37
|
+
// Low clip (noise gate)
|
|
38
|
+
variable lo_clip: Number = 0.1;
|
|
39
|
+
variable delta_y_min: Number = 0.0005;
|
|
40
|
+
|
|
41
|
+
// Scalers and offset
|
|
42
|
+
variable scale_bow: Number = 1.14;
|
|
43
|
+
variable scale_wob: Number = 1.14;
|
|
44
|
+
variable lo_offset: Number = 0.027;
|
|
45
|
+
|
|
46
|
+
// Linearize sRGB with simple 2.4 gamma (NOT full sRGB transfer function)
|
|
47
|
+
// This is per APCA specification which uses simplified gamma
|
|
48
|
+
variable text_r: Number = text.r;
|
|
49
|
+
variable text_g: Number = text.g;
|
|
50
|
+
variable text_b: Number = text.b;
|
|
51
|
+
variable bg_r: Number = bg.r;
|
|
52
|
+
variable bg_g: Number = bg.g;
|
|
53
|
+
variable bg_b: Number = bg.b;
|
|
54
|
+
|
|
55
|
+
// Handle negative values (out of gamut)
|
|
56
|
+
if (text_r < 0) [ text_r = 0 - text_r; ];
|
|
57
|
+
if (text_g < 0) [ text_g = 0 - text_g; ];
|
|
58
|
+
if (text_b < 0) [ text_b = 0 - text_b; ];
|
|
59
|
+
if (bg_r < 0) [ bg_r = 0 - bg_r; ];
|
|
60
|
+
if (bg_g < 0) [ bg_g = 0 - bg_g; ];
|
|
61
|
+
if (bg_b < 0) [ bg_b = 0 - bg_b; ];
|
|
62
|
+
|
|
63
|
+
// Linearize with 2.4 gamma
|
|
64
|
+
variable lin_text_r: Number = pow(text_r, 2.4);
|
|
65
|
+
variable lin_text_g: Number = pow(text_g, 2.4);
|
|
66
|
+
variable lin_text_b: Number = pow(text_b, 2.4);
|
|
67
|
+
variable lin_bg_r: Number = pow(bg_r, 2.4);
|
|
68
|
+
variable lin_bg_g: Number = pow(bg_g, 2.4);
|
|
69
|
+
variable lin_bg_b: Number = pow(bg_b, 2.4);
|
|
70
|
+
|
|
71
|
+
// Calculate screen luminance Y using sRGB coefficients
|
|
72
|
+
// Coefficients from Myndex/APCA spec (via Lindbloom)
|
|
73
|
+
variable y_text: Number = 0.2126729 * lin_text_r + 0.7151522 * lin_text_g + 0.0721750 * lin_text_b;
|
|
74
|
+
variable y_bg: Number = 0.2126729 * lin_bg_r + 0.7151522 * lin_bg_g + 0.0721750 * lin_bg_b;
|
|
75
|
+
|
|
76
|
+
// Soft clamp for flare (low luminance adjustment)
|
|
77
|
+
// If Y >= threshold, use Y as-is
|
|
78
|
+
// Otherwise: Y + (threshold - Y)^1.414
|
|
79
|
+
variable y_txt_clamped: Number = y_text;
|
|
80
|
+
variable y_bg_clamped: Number = y_bg;
|
|
81
|
+
|
|
82
|
+
if (y_text < blk_thrs) [
|
|
83
|
+
variable diff_txt: Number = blk_thrs - y_text;
|
|
84
|
+
y_txt_clamped = y_text + pow(diff_txt, blk_clmp);
|
|
85
|
+
];
|
|
86
|
+
|
|
87
|
+
if (y_bg < blk_thrs) [
|
|
88
|
+
variable diff_bg: Number = blk_thrs - y_bg;
|
|
89
|
+
y_bg_clamped = y_bg + pow(diff_bg, blk_clmp);
|
|
90
|
+
];
|
|
91
|
+
|
|
92
|
+
// Determine polarity: BoW (dark on light) or WoB (light on dark)
|
|
93
|
+
variable sapc: Number = 0;
|
|
94
|
+
variable s_contrast: Number = 0;
|
|
95
|
+
|
|
96
|
+
// Noise gate check
|
|
97
|
+
variable y_diff: Number = y_bg_clamped - y_txt_clamped;
|
|
98
|
+
if (y_diff < 0) [ y_diff = 0 - y_diff; ];
|
|
99
|
+
|
|
100
|
+
// Negative lo_clip for comparison (avoid parsing issues)
|
|
101
|
+
variable neg_lo_clip: Number = 0 - lo_clip;
|
|
102
|
+
|
|
103
|
+
if (y_diff >= delta_y_min) [
|
|
104
|
+
if (y_bg_clamped > y_txt_clamped) [
|
|
105
|
+
// BoW: Dark text on light background (returns POSITIVE per APCA spec)
|
|
106
|
+
s_contrast = pow(y_bg_clamped, norm_bg) - pow(y_txt_clamped, norm_txt);
|
|
107
|
+
sapc = s_contrast * scale_bow;
|
|
108
|
+
|
|
109
|
+
if (sapc < lo_clip) [
|
|
110
|
+
sapc = 0;
|
|
111
|
+
] else [
|
|
112
|
+
sapc = sapc - lo_offset;
|
|
113
|
+
];
|
|
114
|
+
] else [
|
|
115
|
+
// WoB: Light text on dark background (returns NEGATIVE per APCA spec)
|
|
116
|
+
s_contrast = pow(y_bg_clamped, rev_bg) - pow(y_txt_clamped, rev_txt);
|
|
117
|
+
sapc = s_contrast * scale_wob;
|
|
118
|
+
|
|
119
|
+
if (sapc > neg_lo_clip) [
|
|
120
|
+
sapc = 0;
|
|
121
|
+
] else [
|
|
122
|
+
sapc = sapc + lo_offset;
|
|
123
|
+
];
|
|
124
|
+
];
|
|
125
|
+
];
|
|
126
|
+
|
|
127
|
+
// Return Lc * 100 (standard APCA output format)
|
|
128
|
+
return sapc * 100;
|
|
129
|
+
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "APCA Contrast",
|
|
3
|
+
"type": "function",
|
|
4
|
+
"description": "Calculates APCA (Accessible Perceptual Contrast Algorithm) contrast between text and background colors. APCA is part of WCAG 3.0 draft and provides perceptually uniform contrast values. Returns Lc value from -108 to +106. Positive = light text on dark, negative = dark text on light. |Lc| ≥ 60 recommended for body text.",
|
|
5
|
+
"keyword": "apca_contrast",
|
|
6
|
+
"input": {
|
|
7
|
+
"type": "object",
|
|
8
|
+
"properties": {
|
|
9
|
+
"text": {
|
|
10
|
+
"type": "color",
|
|
11
|
+
"description": "Text/foreground color"
|
|
12
|
+
},
|
|
13
|
+
"background": {
|
|
14
|
+
"type": "color",
|
|
15
|
+
"description": "Background color"
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"script": {
|
|
20
|
+
"type": "/api/v1/core/tokenscript/0/",
|
|
21
|
+
"script": "./apca-contrast.tokenscript"
|
|
22
|
+
},
|
|
23
|
+
"requirements": ["/api/v1/core/srgb-color/0/"]
|
|
24
|
+
}
|