Generate color meta, document functions and tidy.

This commit is contained in:
Nate Butler 2023-02-12 19:45:16 -05:00
parent addfcdc1f4
commit 1fcfa5d272
11 changed files with 613 additions and 648 deletions

View file

@ -1,170 +0,0 @@
// Adapted from @k-vyn/coloralgorithm
import bezier from "bezier-easing";
import chroma, { Scale } from "chroma-js";
import { Curve } from "./curves";
import { ColorFamily, ColorProps, ColorSet } from "./types";
function validColor(color: string) {
if (chroma.valid(color)) {
return color;
} else {
throw new Error(`Invalid color: ${color}`);
}
}
function assignColor(scale: Scale, steps: number, step: number) {
const color = scale(step / steps);
const lch = color.lch();
const rgbaArray = color.rgba();
const hex = color.hex();
// Roughly calculate if a color is dark or light
const isLight = lch[0] > 50;
const result = {
step,
hex,
lch,
rgbaArray,
isLight,
};
return result;
}
/** Outputs 101 colors (0-100) */
export function generateColors(props: ColorProps, inverted: boolean) {
const steps = 101;
const colors: ColorSet = [];
const { start, middle, end } = props.color;
const startColor = typeof start === "string" ? validColor(start) : start;
const middleColor = typeof middle === "string" ? validColor(middle) : middle;
const endColor = typeof end === "string" ? validColor(end) : end;
// TODO: Use curve when generating colors
let scale: Scale;
if (inverted) {
scale = chroma.scale([endColor, middleColor, startColor]).mode("lch");
} else {
scale = chroma.scale([startColor, middleColor, endColor]).mode("lch");
}
for (let i = 0; i < steps; i++) {
const color = assignColor(scale, steps, i);
colors.push(color);
}
return colors;
}
export function generateColorsUsingCurve(
startColor: string,
endColor: string,
curve: number[]
) {
const NUM_STEPS = 101;
const easing = bezier(curve[0], curve[1], curve[2], curve[3]);
const curveProgress = [];
for (let i = 0; i <= NUM_STEPS; i++) {
curveProgress.push(easing(i / NUM_STEPS));
}
const colors: chroma.Color[] = [];
for (let i = 0; i < NUM_STEPS; i++) {
// Use HSL as an input as it is easier to construct programatically
// const color = chroma.hsl();
const color = chroma.mix(startColor, endColor, curveProgress[i], "lch");
colors.push(color);
}
return colors;
}
export function generateColors2(
hue: {
start: number;
end: number;
curve: Curve;
},
saturation: {
start: number;
end: number;
curve: Curve;
},
lightness: {
start: number;
end: number;
curve: Curve;
}
) {
const NUM_STEPS = 9;
const hueEasing = bezier(
hue.curve.value[0],
hue.curve.value[1],
hue.curve.value[2],
hue.curve.value[3]
);
const saturationEasing = bezier(
saturation.curve.value[0],
saturation.curve.value[1],
saturation.curve.value[2],
saturation.curve.value[3]
);
const lightnessEasing = bezier(
lightness.curve.value[0],
lightness.curve.value[1],
lightness.curve.value[2],
lightness.curve.value[3]
);
const colors: chroma.Color[] = [];
for (let i = 0; i < NUM_STEPS; i++) {
const hueValue =
hueEasing(i / NUM_STEPS) * (hue.end - hue.start) + hue.start;
const saturationValue =
saturationEasing(i / NUM_STEPS) * (saturation.end - saturation.start) +
saturation.start;
const lightnessValue =
lightnessEasing(i / NUM_STEPS) * (lightness.end - lightness.start) +
lightness.start;
const color = chroma.hsl(
hueValue,
saturationValue / 100,
lightnessValue / 100
);
colors.push(color);
}
const scale = chroma.scale(colors).mode("lch");
return scale;
}
/** Generates two color ramps:
* One for for light, and one for dark.
* By generating two ramps, rather than two default themes, we can use the same reference palette values for tokens in components.
*
* Each ramp has 101 colors (0-100)
*/
export function generateColorSet(props: ColorProps) {
const generatedColors = generateColors(props, false);
const generatedInvertedColors = generateColors(props, true);
const colors = generatedColors.map((color) => color.hex);
const invertedColors = generatedInvertedColors.map((color) => color.hex);
const result: ColorFamily = {
name: props.name,
colors: colors,
invertedColors: invertedColors,
colorsMeta: generatedColors,
invertedMeta: generatedInvertedColors,
};
return result;
}

View file

@ -1,175 +0,0 @@
// Adapted from @k-vyn/coloralgorithm
export interface Curve {
name: string;
formatted_name: string;
value: number[];
}
export interface Curves {
lightness: Curve;
saturation: Curve;
linear: Curve;
easeInCubic: Curve;
easeOutCubic: Curve;
easeInOutCubic: Curve;
easeInSine: Curve;
easeOutSine: Curve;
easeInOutSine: Curve;
easeInQuad: Curve;
easeOutQuad: Curve;
easeInOutQuad: Curve;
easeInQuart: Curve;
easeOutQuart: Curve;
easeInOutQuart: Curve;
easeInQuint: Curve;
easeOutQuint: Curve;
easeInOutQuint: Curve;
easeInExpo: Curve;
easeOutExpo: Curve;
easeInOutExpo: Curve;
easeInCirc: Curve;
easeOutCirc: Curve;
easeInOutCirc: Curve;
easeInBack: Curve;
easeOutBack: Curve;
easeInOutBack: Curve;
}
export const curve: Curves = {
lightness: {
name: "nate",
formatted_name: "Nate",
value: [0.2, 0, 0.85, 1.1],
},
saturation: {
name: "nate",
formatted_name: "Nate",
value: [0.67, 0.6, 0.55, 1.0],
},
linear: {
name: "linear",
formatted_name: "Linear",
value: [0.5, 0.5, 0.5, 0.5],
},
easeInCubic: {
name: "easeInCubic",
formatted_name: "Cubic - EaseIn",
value: [0.55, 0.055, 0.675, 0.19],
},
easeOutCubic: {
name: "easeOutCubic",
formatted_name: "Cubic - EaseOut",
value: [0.215, 0.61, 0.355, 1],
},
easeInOutCubic: {
name: "easeInOutCubic",
formatted_name: "Cubic - EaseInOut",
value: [0.645, 0.045, 0.355, 1],
},
easeInSine: {
name: "easeInSine",
formatted_name: "Sine - EaseIn",
value: [0.47, 0, 0.745, 0.715],
},
easeOutSine: {
name: "easeOutSine",
formatted_name: "Sine - EaseOut",
value: [0.39, 0.575, 0.565, 1],
},
easeInOutSine: {
name: "easeInOutSine",
formatted_name: "Sine - EaseInOut",
value: [0.445, 0.05, 0.55, 0.95],
},
easeInQuad: {
name: "easeInQuad",
formatted_name: "Quad - EaseIn",
value: [0.55, 0.085, 0.68, 0.53],
},
easeOutQuad: {
name: "easeOutQuad",
formatted_name: "Quad - EaseOut",
value: [0.25, 0.46, 0.45, 0.94],
},
easeInOutQuad: {
name: "easeInOutQuad",
formatted_name: "Quad - EaseInOut",
value: [0.455, 0.03, 0.515, 0.955],
},
easeInQuart: {
name: "easeInQuart",
formatted_name: "Quart - EaseIn",
value: [0.895, 0.03, 0.685, 0.22],
},
easeOutQuart: {
name: "easeOutQuart",
formatted_name: "Quart - EaseOut",
value: [0.165, 0.84, 0.44, 1],
},
easeInOutQuart: {
name: "easeInOutQuart",
formatted_name: "Quart - EaseInOut",
value: [0.77, 0, 0.175, 1],
},
easeInQuint: {
name: "easeInQuint",
formatted_name: "Quint - EaseIn",
value: [0.755, 0.05, 0.855, 0.06],
},
easeOutQuint: {
name: "easeOutQuint",
formatted_name: "Quint - EaseOut",
value: [0.23, 1, 0.32, 1],
},
easeInOutQuint: {
name: "easeInOutQuint",
formatted_name: "Quint - EaseInOut",
value: [0.86, 0, 0.07, 1],
},
easeInCirc: {
name: "easeInCirc",
formatted_name: "Circ - EaseIn",
value: [0.6, 0.04, 0.98, 0.335],
},
easeOutCirc: {
name: "easeOutCirc",
formatted_name: "Circ - EaseOut",
value: [0.075, 0.82, 0.165, 1],
},
easeInOutCirc: {
name: "easeInOutCirc",
formatted_name: "Circ - EaseInOut",
value: [0.785, 0.135, 0.15, 0.86],
},
easeInExpo: {
name: "easeInExpo",
formatted_name: "Expo - EaseIn",
value: [0.95, 0.05, 0.795, 0.035],
},
easeOutExpo: {
name: "easeOutExpo",
formatted_name: "Expo - EaseOut",
value: [0.19, 1, 0.22, 1],
},
easeInOutExpo: {
name: "easeInOutExpo",
formatted_name: "Expo - EaseInOut",
value: [1, 0, 0, 1],
},
easeInBack: {
name: "easeInBack",
formatted_name: "Back - EaseIn",
value: [0.6, -0.28, 0.735, 0.045],
},
easeOutBack: {
name: "easeOutBack",
formatted_name: "Back - EaseOut",
value: [0.175, 0.885, 0.32, 1.275],
},
easeInOutBack: {
name: "easeInOutBack",
formatted_name: "Back - EaseInOut",
value: [0.68, -0.55, 0.265, 1.55],
},
};

View file

@ -0,0 +1,11 @@
/** Converts a percentage scale value (0-100) to normalized scale (0-1) value. */
export function percentageToNormalized(value: number) {
const normalized = value / 100;
return normalized;
}
/** Converts a normalized scale (0-1) value to a percentage scale (0-100) value. */
export function normalizedToPercetage(value: number) {
const percentage = value * 100;
return percentage;
}

View file

@ -0,0 +1,21 @@
import bezier from "bezier-easing";
import { Curve } from "../ref/curves";
/**
* Formats our Curve data structure into a bezier easing function.
* @param {Curve} curve - The curve to format.
* @param {Boolean} inverted - Whether or not to invert the curve.
* @returns {EasingFunction} The formatted easing function.
*/
export function curve(curve: Curve, inverted?: Boolean) {
if (inverted) {
return bezier(
curve.value[3],
curve.value[2],
curve.value[1],
curve.value[0]
);
}
return bezier(curve.value[0], curve.value[1], curve.value[2], curve.value[3]);
}

View file

@ -0,0 +1,157 @@
import bezier from "bezier-easing";
import chroma from "chroma-js";
import { Color, ColorFamily, ColorFamilyConfig, ColorScale } from "../types";
import { percentageToNormalized } from "./convert";
import { curve } from "./curve";
// Re-export interface in a more standard format
export type EasingFunction = bezier.EasingFunction;
/**
* Generates a color, outputs it in multiple formats, and returns a variety of useful metadata.
*
* @param {EasingFunction} hueEasing - An easing function for the hue component of the color.
* @param {EasingFunction} saturationEasing - An easing function for the saturation component of the color.
* @param {EasingFunction} lightnessEasing - An easing function for the lightness component of the color.
* @param {ColorFamilyConfig} family - Configuration for the color family.
* @param {number} step - The current step.
* @param {number} steps - The total number of steps in the color scale.
*
* @returns {Color} The generated color, with its calculated contrast against black and white, as well as its LCH values, RGBA array, hexadecimal representation, and a flag indicating if it is light or dark.
*/
function generateColor(
hueEasing: EasingFunction,
saturationEasing: EasingFunction,
lightnessEasing: EasingFunction,
family: ColorFamilyConfig,
step: number,
steps: number
) {
const { hue, saturation, lightness } = family.color;
const stepHue = hueEasing(step / steps) * (hue.end - hue.start) + hue.start;
const stepSaturation =
saturationEasing(step / steps) * (saturation.end - saturation.start) +
saturation.start;
const stepLightness =
lightnessEasing(step / steps) * (lightness.end - lightness.start) +
lightness.start;
const color = chroma.hsl(
stepHue,
percentageToNormalized(stepSaturation),
percentageToNormalized(stepLightness)
);
const contrast = {
black: {
value: chroma.contrast(color, "black"),
aaPass: chroma.contrast(color, "black") >= 4.5,
aaaPass: chroma.contrast(color, "black") >= 7,
},
white: {
value: chroma.contrast(color, "white"),
aaPass: chroma.contrast(color, "white") >= 4.5,
aaaPass: chroma.contrast(color, "white") >= 7,
},
};
const lch = color.lch();
const rgba = color.rgba();
const hex = color.hex();
const isLight = lch[0] > 50;
const result: Color = {
step,
lch,
hex,
rgba,
contrast,
isLight,
};
return result;
}
/**
* Generates a color scale based on a color family configuration.
*
* @param {ColorFamilyConfig} config - The configuration for the color family.
* @param {Boolean} inverted - Specifies whether the color scale should be inverted or not.
*
* @returns {ColorScale} The generated color scale.
*
* @example
* ```ts
* const colorScale = generateColorScale({
* name: "blue",
* color: {
* hue: {
* start: 210,
* end: 240,
* curve: "easeInOut"
* },
* saturation: {
* start: 100,
* end: 100,
* curve: "easeInOut"
* },
* lightness: {
* start: 50,
* end: 50,
* curve: "easeInOut"
* }
* }
* });
* ```
*/
export function generateColorScale(
config: ColorFamilyConfig,
inverted: Boolean = false
) {
const { hue, saturation, lightness } = config.color;
// 101 steps means we get values from 0-100
const NUM_STEPS = 101;
const hueEasing = curve(hue.curve, inverted);
const saturationEasing = curve(saturation.curve, inverted);
const lightnessEasing = curve(lightness.curve, inverted);
let scale: ColorScale = {
colors: [],
values: [],
};
for (let i = 0; i < NUM_STEPS; i++) {
const color = generateColor(
hueEasing,
saturationEasing,
lightnessEasing,
config,
i,
NUM_STEPS
);
scale.colors.push(color);
scale.values.push(color.hex);
}
return scale;
}
/** Generates a color family with a scale and an inverted scale. */
export function generateColorFamily(config: ColorFamilyConfig) {
const scale = generateColorScale(config, false);
const invertedScale = generateColorScale(config, true);
const family: ColorFamily = {
name: config.name,
scale,
invertedScale,
};
return family;
}

View file

@ -1,336 +1,376 @@
import chroma from "chroma-js";
import {
generateColors2,
generateColorSet,
generateColorsUsingCurve,
} from "../algorithm";
import { curve } from "../curves";
import { ColorFamily } from "../types";
import { generateColorFamily } from "../lib/generate";
import { curve } from "./curves";
// These are the source colors for the color scales in the system.
// This should never directly be used in the system, or exported to be used in a component or theme
// As it will generate thousands of lines of code.
// These should never directly be used directly in components or themes as they generate thousands of lines of code.
// Instead, use the outputs from the reference palette which exports a smaller subset of colors.
// Token or user-facing colors should use short, clear names
// and a 100-900 scale to match the font weight scale.
// Token or user-facing colors should use short, clear names and a 100-900 scale to match the font weight scale.
// Red ======================================== //
export const red = generateColors2(
{
start: 0,
end: 0,
curve: curve.linear,
export const red = generateColorFamily({
name: "red",
color: {
hue: {
start: 0,
end: 0,
curve: curve.linear,
},
saturation: {
start: 95,
end: 75,
curve: curve.saturation,
},
lightness: {
start: 97,
end: 25,
curve: curve.lightness,
},
},
{
start: 95,
end: 75,
curve: curve.saturation,
},
{
start: 97,
end: 25,
curve: curve.lightness,
}
);
});
// Sunset ======================================== //
export const sunset = generateColors2(
{
start: 12,
end: 12,
curve: curve.linear,
export const sunset = generateColorFamily({
name: "sunset",
color: {
hue: {
start: 12,
end: 12,
curve: curve.linear,
},
saturation: {
start: 100,
end: 80,
curve: curve.saturation,
},
lightness: {
start: 97,
end: 25,
curve: curve.lightness,
},
},
{
start: 100,
end: 80,
curve: curve.saturation,
},
{
start: 97,
end: 25,
curve: curve.lightness,
}
);
});
// Orange ======================================== //
export const orange = generateColors2(
{
start: 25,
end: 25,
curve: curve.linear,
export const orange = generateColorFamily({
name: "orange",
color: {
hue: {
start: 25,
end: 25,
curve: curve.linear,
},
saturation: {
start: 100,
end: 100,
curve: curve.saturation,
},
lightness: {
start: 97,
end: 25,
curve: curve.lightness,
},
},
{
start: 100,
end: 100,
curve: curve.saturation,
},
{
start: 97,
end: 25,
curve: curve.lightness,
}
);
});
// Amber ======================================== //
export const amber = generateColors2(
{
start: 34,
end: 34,
curve: curve.linear,
export const amber = generateColorFamily({
name: "amber",
color: {
hue: {
start: 34,
end: 34,
curve: curve.linear,
},
saturation: {
start: 100,
end: 100,
curve: curve.saturation,
},
lightness: {
start: 97,
end: 25,
curve: curve.lightness,
},
},
{
start: 100,
end: 100,
curve: curve.saturation,
},
{
start: 97,
end: 25,
curve: curve.lightness,
}
);
});
// Yellow ======================================== //
export const yellow = generateColors2(
{
start: 48,
end: 48,
curve: curve.linear,
export const yellow = generateColorFamily({
name: "yellow",
color: {
hue: {
start: 48,
end: 48,
curve: curve.linear,
},
saturation: {
start: 90,
end: 100,
curve: curve.saturation,
},
lightness: {
start: 97,
end: 28,
curve: curve.lightness,
},
},
{
start: 90,
end: 100,
curve: curve.saturation,
},
{
start: 97,
end: 32,
curve: curve.lightness,
}
);
});
// Citron ======================================== //
export const citron = generateColors2(
{
start: 65,
end: 65,
curve: curve.linear,
export const citron = generateColorFamily({
name: "citron",
color: {
hue: {
start: 65,
end: 65,
curve: curve.linear,
},
saturation: {
start: 85,
end: 70,
curve: curve.saturation,
},
lightness: {
start: 97,
end: 25,
curve: curve.lightness,
},
},
{
start: 85,
end: 70,
curve: curve.saturation,
},
{
start: 97,
end: 25,
curve: curve.lightness,
}
);
});
// Lime ======================================== //
export const lime = generateColors2(
{
start: 85,
end: 85,
curve: curve.linear,
export const lime = generateColorFamily({
name: "lime",
color: {
hue: {
start: 85,
end: 85,
curve: curve.linear,
},
saturation: {
start: 85,
end: 70,
curve: curve.saturation,
},
lightness: {
start: 97,
end: 25,
curve: curve.lightness,
},
},
{
start: 85,
end: 70,
curve: curve.saturation,
},
{
start: 97,
end: 25,
curve: curve.lightness,
}
);
});
// Green ======================================== //
export const green = generateColors2(
{
start: 108,
end: 108,
curve: curve.linear,
export const green = generateColorFamily({
name: "green",
color: {
hue: {
start: 108,
end: 108,
curve: curve.linear,
},
saturation: {
start: 60,
end: 50,
curve: curve.saturation,
},
lightness: {
start: 97,
end: 25,
curve: curve.lightness,
},
},
{
start: 60,
end: 50,
curve: curve.saturation,
},
{
start: 97,
end: 25,
curve: curve.lightness,
}
);
});
// Mint ======================================== //
export const mint = generateColors2(
{
start: 142,
end: 142,
curve: curve.linear,
export const mint = generateColorFamily({
name: "mint",
color: {
hue: {
start: 142,
end: 142,
curve: curve.linear,
},
saturation: {
start: 60,
end: 50,
curve: curve.saturation,
},
lightness: {
start: 97,
end: 20,
curve: curve.lightness,
},
},
{
start: 60,
end: 50,
curve: curve.saturation,
},
{
start: 97,
end: 20,
curve: curve.lightness,
}
);
});
// Cyan ======================================== //
export const cyan = generateColors2(
{
start: 179,
end: 179,
curve: curve.linear,
export const cyan = generateColorFamily({
name: "cyan",
color: {
hue: {
start: 179,
end: 179,
curve: curve.linear,
},
saturation: {
start: 70,
end: 60,
curve: curve.saturation,
},
lightness: {
start: 97,
end: 20,
curve: curve.lightness,
},
},
{
start: 70,
end: 60,
curve: curve.saturation,
},
{
start: 97,
end: 20,
curve: curve.lightness,
}
);
});
// Sky ======================================== //
export const sky = generateColors2(
{
start: 190,
end: 190,
curve: curve.linear,
export const sky = generateColorFamily({
name: "sky",
color: {
hue: {
start: 195,
end: 195,
curve: curve.linear,
},
saturation: {
start: 85,
end: 75,
curve: curve.saturation,
},
lightness: {
start: 97,
end: 20,
curve: curve.lightness,
},
},
{
start: 85,
end: 75,
curve: curve.saturation,
},
{
start: 97,
end: 20,
curve: curve.lightness,
}
);
});
// Blue ======================================== //
export const blue = generateColors2(
{
start: 210,
end: 210,
curve: curve.linear,
export const blue = generateColorFamily({
name: "blue",
color: {
hue: {
start: 210,
end: 210,
curve: curve.linear,
},
saturation: {
start: 90,
end: 75,
curve: curve.saturation,
},
lightness: {
start: 97,
end: 20,
curve: curve.lightness,
},
},
{
start: 90,
end: 60,
curve: curve.saturation,
},
{
start: 97,
end: 20,
curve: curve.lightness,
}
);
});
// Indigo ======================================== //
export const indigo = generateColors2(
{
start: 240,
end: 240,
curve: curve.linear,
export const indigo = generateColorFamily({
name: "indigo",
color: {
hue: {
start: 230,
end: 230,
curve: curve.linear,
},
saturation: {
start: 80,
end: 50,
curve: curve.saturation,
},
lightness: {
start: 97,
end: 20,
curve: curve.lightness,
},
},
{
start: 80,
end: 40,
curve: curve.saturation,
},
{
start: 97,
end: 20,
curve: curve.lightness,
}
);
});
// Purple ======================================== //
export const purple = generateColors2(
{
start: 260,
end: 265,
curve: curve.linear,
export const purple = generateColorFamily({
name: "purple",
color: {
hue: {
start: 260,
end: 265,
curve: curve.linear,
},
saturation: {
start: 80,
end: 50,
curve: curve.saturation,
},
lightness: {
start: 97,
end: 20,
curve: curve.lightness,
},
},
{
start: 80,
end: 50,
curve: curve.saturation,
},
{
start: 97,
end: 20,
curve: curve.lightness,
}
);
});
// Pink ======================================== //
export const pink = generateColors2(
{
start: 310,
end: 310,
curve: curve.linear,
export const pink = generateColorFamily({
name: "pink",
color: {
hue: {
start: 310,
end: 310,
curve: curve.linear,
},
saturation: {
start: 80,
end: 75,
curve: curve.saturation,
},
lightness: {
start: 97,
end: 20,
curve: curve.lightness,
},
},
{
start: 80,
end: 70,
curve: curve.saturation,
},
{
start: 97,
end: 20,
curve: curve.lightness,
}
);
});
// Rose ======================================== //
export const rose = generateColors2(
{
start: 345,
end: 345,
curve: curve.linear,
export const rose = generateColorFamily({
name: "rose",
color: {
hue: {
start: 345,
end: 345,
curve: curve.linear,
},
saturation: {
start: 90,
end: 65,
curve: curve.saturation,
},
lightness: {
start: 97,
end: 20,
curve: curve.lightness,
},
},
{
start: 90,
end: 65,
curve: curve.saturation,
},
{
start: 97,
end: 20,
curve: curve.lightness,
}
);
});

View file

@ -0,0 +1,25 @@
export interface Curve {
name: string;
value: number[];
}
export interface Curves {
lightness: Curve;
saturation: Curve;
linear: Curve;
}
export const curve: Curves = {
lightness: {
name: "lightnessCurve",
value: [0.2, 0, 0.85, 1.0],
},
saturation: {
name: "saturationCurve",
value: [0.67, 0.6, 0.55, 1.0],
},
linear: {
name: "linear",
value: [0.5, 0.5, 0.5, 0.5],
},
};

View file

@ -1,3 +0,0 @@
import * as color from "./ref/color";
export { color };

View file

@ -0,0 +1,23 @@
import chroma from "chroma-js";
import * as colorFamily from "./ref/color";
const color = {
red: chroma.scale(colorFamily.red.scale.values).mode("lch").colors(9),
sunset: chroma.scale(colorFamily.sunset.scale.values).mode("lch").colors(9),
orange: chroma.scale(colorFamily.orange.scale.values).mode("lch").colors(9),
amber: chroma.scale(colorFamily.amber.scale.values).mode("lch").colors(9),
yellow: chroma.scale(colorFamily.yellow.scale.values).mode("lch").colors(9),
citron: chroma.scale(colorFamily.citron.scale.values).mode("lch").colors(9),
lime: chroma.scale(colorFamily.lime.scale.values).mode("lch").colors(9),
green: chroma.scale(colorFamily.green.scale.values).mode("lch").colors(9),
mint: chroma.scale(colorFamily.mint.scale.values).mode("lch").colors(9),
cyan: chroma.scale(colorFamily.cyan.scale.values).mode("lch").colors(9),
sky: chroma.scale(colorFamily.sky.scale.values).mode("lch").colors(9),
blue: chroma.scale(colorFamily.blue.scale.values).mode("lch").colors(9),
indigo: chroma.scale(colorFamily.indigo.scale.values).mode("lch").colors(9),
purple: chroma.scale(colorFamily.purple.scale.values).mode("lch").colors(9),
pink: chroma.scale(colorFamily.pink.scale.values).mode("lch").colors(9),
rose: chroma.scale(colorFamily.rose.scale.values).mode("lch").colors(9),
};
export { color };

View file

@ -1,27 +1,67 @@
import { Color as ChromaColor } from "chroma-js";
import { Curve } from "./ref/curves";
export interface ColorAccessiblityValue {
value: number;
aaPass: boolean;
aaaPass: boolean;
}
/**
* Calculates the color contrast between a specified color and its corresponding background and foreground colors.
*
* @note This implementation is currently basic Currently we only calculate contrasts against black and white, in the future will allow for dynamic color contrast calculation based on the colors present in a given palette.
* @note The goal is to align with WCAG3 accessibility standards as they become stabilized. See the [WCAG 3 Introduction](https://www.w3.org/WAI/standards-guidelines/wcag/wcag3-intro/) for more information.
*/
export interface ColorAccessiblity {
black: ColorAccessiblityValue;
white: ColorAccessiblityValue;
}
export type Color = {
step: number;
contrast: ColorAccessiblity;
hex: string;
lch: number[];
rgbaArray: number[];
rgba: number[];
isLight: boolean;
};
export type ColorSet = Color[];
export interface ColorScale {
colors: Color[];
// An array of hex values for each color in the scale
values: string[];
}
export type ColorFamily = {
name: string;
colors: string[];
invertedColors: string[];
colorsMeta: ColorSet;
invertedMeta: ColorSet;
scale: ColorScale;
invertedScale: ColorScale;
};
export interface ColorProps {
export interface ColorFamilyHue {
start: number;
end: number;
curve: Curve;
}
export interface ColorFamilySaturation {
start: number;
end: number;
curve: Curve;
}
export interface ColorFamilyLightness {
start: number;
end: number;
curve: Curve;
}
export interface ColorFamilyConfig {
name: string;
color: {
start: string | ChromaColor;
middle: string | ChromaColor;
end: string | ChromaColor;
hue: ColorFamilyHue;
saturation: ColorFamilySaturation;
lightness: ColorFamilyLightness;
};
}

View file

@ -1,12 +1,8 @@
/* eslint-disable import/no-relative-packages */
import { Scale } from 'chroma-js';
import { color } from '../../src/system/reference';
import { color } from '../../src/system/system';
import styles from './page.module.css';
function ColorChips({ colorScale }: { colorScale: Scale }) {
const colors = colorScale.colors(11);
function ColorChips({ colors }: { colors: string[] }) {
return (
<div
style={{
@ -38,22 +34,22 @@ export default function Home() {
return (
<main>
<div style={{ display: 'flex', gap: '1px' }}>
<ColorChips colorScale={color.red} />
<ColorChips colorScale={color.sunset} />
<ColorChips colorScale={color.orange} />
<ColorChips colorScale={color.amber} />
<ColorChips colorScale={color.yellow} />
<ColorChips colorScale={color.citron} />
<ColorChips colorScale={color.lime} />
<ColorChips colorScale={color.green} />
<ColorChips colorScale={color.mint} />
<ColorChips colorScale={color.cyan} />
<ColorChips colorScale={color.sky} />
<ColorChips colorScale={color.blue} />
<ColorChips colorScale={color.indigo} />
<ColorChips colorScale={color.purple} />
<ColorChips colorScale={color.pink} />
<ColorChips colorScale={color.rose} />
<ColorChips colors={color.red} />
<ColorChips colors={color.sunset} />
<ColorChips colors={color.orange} />
<ColorChips colors={color.amber} />
<ColorChips colors={color.yellow} />
<ColorChips colors={color.citron} />
<ColorChips colors={color.lime} />
<ColorChips colors={color.green} />
<ColorChips colors={color.mint} />
<ColorChips colors={color.cyan} />
<ColorChips colors={color.sky} />
<ColorChips colors={color.blue} />
<ColorChips colors={color.indigo} />
<ColorChips colors={color.purple} />
<ColorChips colors={color.pink} />
<ColorChips colors={color.rose} />
</div>
</main>
);