Merge pull request #2150 from zed-industries/nate/system-colors

Nate Butler created

Add system color palette

Change summary

styles/package-lock.json          | 655 ++++++++++++++++----------------
styles/package.json               |   7 
styles/src/common.ts              |  21 -
styles/src/system/lib/convert.ts  |  11 
styles/src/system/lib/curve.ts    |  26 +
styles/src/system/lib/generate.ts | 159 ++++++++
styles/src/system/ref/color.ts    | 445 ++++++++++++++++++++++
styles/src/system/ref/curves.ts   |  25 +
styles/src/system/system.ts       |  32 +
styles/src/system/types.ts        |  66 +++
10 files changed, 1,104 insertions(+), 343 deletions(-)

Detailed changes

styles/package-lock.json 🔗

@@ -1,327 +1,338 @@
 {
-    "name": "styles",
-    "version": "1.0.0",
-    "lockfileVersion": 2,
-    "requires": true,
-    "packages": {
-        "": {
-            "name": "styles",
-            "version": "1.0.0",
-            "license": "ISC",
-            "dependencies": {
-                "@types/chroma-js": "^2.1.3",
-                "@types/node": "^17.0.23",
-                "case-anything": "^2.1.10",
-                "chroma-js": "^2.4.2",
-                "toml": "^3.0.0",
-                "ts-node": "^10.7.0"
-            }
-        },
-        "node_modules/@cspotcode/source-map-consumer": {
-            "version": "0.8.0",
-            "resolved": "https://registry.npmjs.org/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz",
-            "integrity": "sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg==",
-            "engines": {
-                "node": ">= 12"
-            }
-        },
-        "node_modules/@cspotcode/source-map-support": {
-            "version": "0.7.0",
-            "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.7.0.tgz",
-            "integrity": "sha512-X4xqRHqN8ACt2aHVe51OxeA2HjbcL4MqFqXkrmQszJ1NOUuUu5u6Vqx/0lZSVNku7velL5FC/s5uEAj1lsBMhA==",
-            "dependencies": {
-                "@cspotcode/source-map-consumer": "0.8.0"
-            },
-            "engines": {
-                "node": ">=12"
-            }
-        },
-        "node_modules/@tsconfig/node10": {
-            "version": "1.0.8",
-            "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz",
-            "integrity": "sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg=="
-        },
-        "node_modules/@tsconfig/node12": {
-            "version": "1.0.9",
-            "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.9.tgz",
-            "integrity": "sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw=="
-        },
-        "node_modules/@tsconfig/node14": {
-            "version": "1.0.1",
-            "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.1.tgz",
-            "integrity": "sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg=="
-        },
-        "node_modules/@tsconfig/node16": {
-            "version": "1.0.2",
-            "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.2.tgz",
-            "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA=="
-        },
-        "node_modules/@types/chroma-js": {
-            "version": "2.1.3",
-            "resolved": "https://registry.npmjs.org/@types/chroma-js/-/chroma-js-2.1.3.tgz",
-            "integrity": "sha512-1xGPhoSGY1CPmXLCBcjVZSQinFjL26vlR8ZqprsBWiFyED4JacJJ9zHhh5aaUXqbY9B37mKQ73nlydVAXmr1+g=="
-        },
-        "node_modules/@types/node": {
-            "version": "17.0.23",
-            "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.23.tgz",
-            "integrity": "sha512-UxDxWn7dl97rKVeVS61vErvw086aCYhDLyvRQZ5Rk65rZKepaFdm53GeqXaKBuOhED4e9uWq34IC3TdSdJJ2Gw=="
-        },
-        "node_modules/acorn": {
-            "version": "8.7.0",
-            "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz",
-            "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==",
-            "bin": {
-                "acorn": "bin/acorn"
-            },
-            "engines": {
-                "node": ">=0.4.0"
-            }
-        },
-        "node_modules/acorn-walk": {
-            "version": "8.2.0",
-            "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz",
-            "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==",
-            "engines": {
-                "node": ">=0.4.0"
-            }
-        },
-        "node_modules/arg": {
-            "version": "4.1.3",
-            "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
-            "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA=="
-        },
-        "node_modules/case-anything": {
-            "version": "2.1.10",
-            "resolved": "https://registry.npmjs.org/case-anything/-/case-anything-2.1.10.tgz",
-            "integrity": "sha512-JczJwVrCP0jPKh05McyVsuOg6AYosrB9XWZKbQzXeDAm2ClE/PJE/BcrrQrVyGYH7Jg8V/LDupmyL4kFlVsVFQ==",
-            "engines": {
-                "node": ">=12.13"
-            },
-            "funding": {
-                "url": "https://github.com/sponsors/mesqueeb"
-            }
-        },
-        "node_modules/chroma-js": {
-            "version": "2.4.2",
-            "resolved": "https://registry.npmjs.org/chroma-js/-/chroma-js-2.4.2.tgz",
-            "integrity": "sha512-U9eDw6+wt7V8z5NncY2jJfZa+hUH8XEj8FQHgFJTrUFnJfXYf4Ml4adI2vXZOjqRDpFWtYVWypDfZwnJ+HIR4A=="
-        },
-        "node_modules/create-require": {
-            "version": "1.1.1",
-            "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
-            "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ=="
-        },
-        "node_modules/diff": {
-            "version": "4.0.2",
-            "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
-            "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
-            "engines": {
-                "node": ">=0.3.1"
-            }
-        },
-        "node_modules/make-error": {
-            "version": "1.3.6",
-            "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
-            "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw=="
-        },
-        "node_modules/toml": {
-            "version": "3.0.0",
-            "resolved": "https://registry.npmjs.org/toml/-/toml-3.0.0.tgz",
-            "integrity": "sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w=="
-        },
-        "node_modules/ts-node": {
-            "version": "10.7.0",
-            "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.7.0.tgz",
-            "integrity": "sha512-TbIGS4xgJoX2i3do417KSaep1uRAW/Lu+WAL2doDHC0D6ummjirVOXU5/7aiZotbQ5p1Zp9tP7U6cYhA0O7M8A==",
-            "dependencies": {
-                "@cspotcode/source-map-support": "0.7.0",
-                "@tsconfig/node10": "^1.0.7",
-                "@tsconfig/node12": "^1.0.7",
-                "@tsconfig/node14": "^1.0.0",
-                "@tsconfig/node16": "^1.0.2",
-                "acorn": "^8.4.1",
-                "acorn-walk": "^8.1.1",
-                "arg": "^4.1.0",
-                "create-require": "^1.1.0",
-                "diff": "^4.0.1",
-                "make-error": "^1.1.1",
-                "v8-compile-cache-lib": "^3.0.0",
-                "yn": "3.1.1"
-            },
-            "bin": {
-                "ts-node": "dist/bin.js",
-                "ts-node-cwd": "dist/bin-cwd.js",
-                "ts-node-esm": "dist/bin-esm.js",
-                "ts-node-script": "dist/bin-script.js",
-                "ts-node-transpile-only": "dist/bin-transpile.js",
-                "ts-script": "dist/bin-script-deprecated.js"
-            },
-            "peerDependencies": {
-                "@swc/core": ">=1.2.50",
-                "@swc/wasm": ">=1.2.50",
-                "@types/node": "*",
-                "typescript": ">=2.7"
-            },
-            "peerDependenciesMeta": {
-                "@swc/core": {
-                    "optional": true
-                },
-                "@swc/wasm": {
-                    "optional": true
-                }
-            }
-        },
-        "node_modules/typescript": {
-            "version": "4.6.3",
-            "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.3.tgz",
-            "integrity": "sha512-yNIatDa5iaofVozS/uQJEl3JRWLKKGJKh6Yaiv0GLGSuhpFJe7P3SbHZ8/yjAHRQwKRoA6YZqlfjXWmVzoVSMw==",
-            "peer": true,
-            "bin": {
-                "tsc": "bin/tsc",
-                "tsserver": "bin/tsserver"
-            },
-            "engines": {
-                "node": ">=4.2.0"
-            }
-        },
-        "node_modules/v8-compile-cache-lib": {
-            "version": "3.0.0",
-            "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.0.tgz",
-            "integrity": "sha512-mpSYqfsFvASnSn5qMiwrr4VKfumbPyONLCOPmsR3A6pTY/r0+tSaVbgPWSAIuzbk3lCTa+FForeTiO+wBQGkjA=="
-        },
-        "node_modules/yn": {
-            "version": "3.1.1",
-            "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
-            "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
-            "engines": {
-                "node": ">=6"
-            }
-        }
+  "name": "styles",
+  "version": "1.0.0",
+  "lockfileVersion": 2,
+  "requires": true,
+  "packages": {
+    "": {
+      "name": "styles",
+      "version": "1.0.0",
+      "license": "ISC",
+      "dependencies": {
+        "@types/chroma-js": "^2.1.3",
+        "@types/node": "^17.0.23",
+        "bezier-easing": "^2.1.0",
+        "case-anything": "^2.1.10",
+        "chroma-js": "^2.4.2",
+        "toml": "^3.0.0",
+        "ts-node": "^10.7.0"
+      }
     },
-    "dependencies": {
-        "@cspotcode/source-map-consumer": {
-            "version": "0.8.0",
-            "resolved": "https://registry.npmjs.org/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz",
-            "integrity": "sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg=="
-        },
-        "@cspotcode/source-map-support": {
-            "version": "0.7.0",
-            "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.7.0.tgz",
-            "integrity": "sha512-X4xqRHqN8ACt2aHVe51OxeA2HjbcL4MqFqXkrmQszJ1NOUuUu5u6Vqx/0lZSVNku7velL5FC/s5uEAj1lsBMhA==",
-            "requires": {
-                "@cspotcode/source-map-consumer": "0.8.0"
-            }
-        },
-        "@tsconfig/node10": {
-            "version": "1.0.8",
-            "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz",
-            "integrity": "sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg=="
-        },
-        "@tsconfig/node12": {
-            "version": "1.0.9",
-            "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.9.tgz",
-            "integrity": "sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw=="
-        },
-        "@tsconfig/node14": {
-            "version": "1.0.1",
-            "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.1.tgz",
-            "integrity": "sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg=="
-        },
-        "@tsconfig/node16": {
-            "version": "1.0.2",
-            "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.2.tgz",
-            "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA=="
-        },
-        "@types/chroma-js": {
-            "version": "2.1.3",
-            "resolved": "https://registry.npmjs.org/@types/chroma-js/-/chroma-js-2.1.3.tgz",
-            "integrity": "sha512-1xGPhoSGY1CPmXLCBcjVZSQinFjL26vlR8ZqprsBWiFyED4JacJJ9zHhh5aaUXqbY9B37mKQ73nlydVAXmr1+g=="
-        },
-        "@types/node": {
-            "version": "17.0.23",
-            "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.23.tgz",
-            "integrity": "sha512-UxDxWn7dl97rKVeVS61vErvw086aCYhDLyvRQZ5Rk65rZKepaFdm53GeqXaKBuOhED4e9uWq34IC3TdSdJJ2Gw=="
-        },
-        "acorn": {
-            "version": "8.7.0",
-            "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz",
-            "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ=="
-        },
-        "acorn-walk": {
-            "version": "8.2.0",
-            "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz",
-            "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA=="
-        },
-        "arg": {
-            "version": "4.1.3",
-            "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
-            "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA=="
-        },
-        "case-anything": {
-            "version": "2.1.10",
-            "resolved": "https://registry.npmjs.org/case-anything/-/case-anything-2.1.10.tgz",
-            "integrity": "sha512-JczJwVrCP0jPKh05McyVsuOg6AYosrB9XWZKbQzXeDAm2ClE/PJE/BcrrQrVyGYH7Jg8V/LDupmyL4kFlVsVFQ=="
-        },
-        "chroma-js": {
-            "version": "2.4.2",
-            "resolved": "https://registry.npmjs.org/chroma-js/-/chroma-js-2.4.2.tgz",
-            "integrity": "sha512-U9eDw6+wt7V8z5NncY2jJfZa+hUH8XEj8FQHgFJTrUFnJfXYf4Ml4adI2vXZOjqRDpFWtYVWypDfZwnJ+HIR4A=="
-        },
-        "create-require": {
-            "version": "1.1.1",
-            "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
-            "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ=="
-        },
-        "diff": {
-            "version": "4.0.2",
-            "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
-            "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A=="
-        },
-        "make-error": {
-            "version": "1.3.6",
-            "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
-            "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw=="
-        },
-        "toml": {
-            "version": "3.0.0",
-            "resolved": "https://registry.npmjs.org/toml/-/toml-3.0.0.tgz",
-            "integrity": "sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w=="
-        },
-        "ts-node": {
-            "version": "10.7.0",
-            "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.7.0.tgz",
-            "integrity": "sha512-TbIGS4xgJoX2i3do417KSaep1uRAW/Lu+WAL2doDHC0D6ummjirVOXU5/7aiZotbQ5p1Zp9tP7U6cYhA0O7M8A==",
-            "requires": {
-                "@cspotcode/source-map-support": "0.7.0",
-                "@tsconfig/node10": "^1.0.7",
-                "@tsconfig/node12": "^1.0.7",
-                "@tsconfig/node14": "^1.0.0",
-                "@tsconfig/node16": "^1.0.2",
-                "acorn": "^8.4.1",
-                "acorn-walk": "^8.1.1",
-                "arg": "^4.1.0",
-                "create-require": "^1.1.0",
-                "diff": "^4.0.1",
-                "make-error": "^1.1.1",
-                "v8-compile-cache-lib": "^3.0.0",
-                "yn": "3.1.1"
-            }
-        },
-        "typescript": {
-            "version": "4.6.3",
-            "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.3.tgz",
-            "integrity": "sha512-yNIatDa5iaofVozS/uQJEl3JRWLKKGJKh6Yaiv0GLGSuhpFJe7P3SbHZ8/yjAHRQwKRoA6YZqlfjXWmVzoVSMw==",
-            "peer": true
-        },
-        "v8-compile-cache-lib": {
-            "version": "3.0.0",
-            "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.0.tgz",
-            "integrity": "sha512-mpSYqfsFvASnSn5qMiwrr4VKfumbPyONLCOPmsR3A6pTY/r0+tSaVbgPWSAIuzbk3lCTa+FForeTiO+wBQGkjA=="
-        },
-        "yn": {
-            "version": "3.1.1",
-            "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
-            "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q=="
+    "node_modules/@cspotcode/source-map-consumer": {
+      "version": "0.8.0",
+      "resolved": "https://registry.npmjs.org/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz",
+      "integrity": "sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg==",
+      "engines": {
+        "node": ">= 12"
+      }
+    },
+    "node_modules/@cspotcode/source-map-support": {
+      "version": "0.7.0",
+      "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.7.0.tgz",
+      "integrity": "sha512-X4xqRHqN8ACt2aHVe51OxeA2HjbcL4MqFqXkrmQszJ1NOUuUu5u6Vqx/0lZSVNku7velL5FC/s5uEAj1lsBMhA==",
+      "dependencies": {
+        "@cspotcode/source-map-consumer": "0.8.0"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@tsconfig/node10": {
+      "version": "1.0.8",
+      "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz",
+      "integrity": "sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg=="
+    },
+    "node_modules/@tsconfig/node12": {
+      "version": "1.0.9",
+      "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.9.tgz",
+      "integrity": "sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw=="
+    },
+    "node_modules/@tsconfig/node14": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.1.tgz",
+      "integrity": "sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg=="
+    },
+    "node_modules/@tsconfig/node16": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.2.tgz",
+      "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA=="
+    },
+    "node_modules/@types/chroma-js": {
+      "version": "2.1.3",
+      "resolved": "https://registry.npmjs.org/@types/chroma-js/-/chroma-js-2.1.3.tgz",
+      "integrity": "sha512-1xGPhoSGY1CPmXLCBcjVZSQinFjL26vlR8ZqprsBWiFyED4JacJJ9zHhh5aaUXqbY9B37mKQ73nlydVAXmr1+g=="
+    },
+    "node_modules/@types/node": {
+      "version": "17.0.23",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.23.tgz",
+      "integrity": "sha512-UxDxWn7dl97rKVeVS61vErvw086aCYhDLyvRQZ5Rk65rZKepaFdm53GeqXaKBuOhED4e9uWq34IC3TdSdJJ2Gw=="
+    },
+    "node_modules/acorn": {
+      "version": "8.7.0",
+      "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz",
+      "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==",
+      "bin": {
+        "acorn": "bin/acorn"
+      },
+      "engines": {
+        "node": ">=0.4.0"
+      }
+    },
+    "node_modules/acorn-walk": {
+      "version": "8.2.0",
+      "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz",
+      "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==",
+      "engines": {
+        "node": ">=0.4.0"
+      }
+    },
+    "node_modules/arg": {
+      "version": "4.1.3",
+      "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
+      "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA=="
+    },
+    "node_modules/bezier-easing": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/bezier-easing/-/bezier-easing-2.1.0.tgz",
+      "integrity": "sha512-gbIqZ/eslnUFC1tjEvtz0sgx+xTK20wDnYMIA27VA04R7w6xxXQPZDbibjA9DTWZRA2CXtwHykkVzlCaAJAZig=="
+    },
+    "node_modules/case-anything": {
+      "version": "2.1.10",
+      "resolved": "https://registry.npmjs.org/case-anything/-/case-anything-2.1.10.tgz",
+      "integrity": "sha512-JczJwVrCP0jPKh05McyVsuOg6AYosrB9XWZKbQzXeDAm2ClE/PJE/BcrrQrVyGYH7Jg8V/LDupmyL4kFlVsVFQ==",
+      "engines": {
+        "node": ">=12.13"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/mesqueeb"
+      }
+    },
+    "node_modules/chroma-js": {
+      "version": "2.4.2",
+      "resolved": "https://registry.npmjs.org/chroma-js/-/chroma-js-2.4.2.tgz",
+      "integrity": "sha512-U9eDw6+wt7V8z5NncY2jJfZa+hUH8XEj8FQHgFJTrUFnJfXYf4Ml4adI2vXZOjqRDpFWtYVWypDfZwnJ+HIR4A=="
+    },
+    "node_modules/create-require": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
+      "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ=="
+    },
+    "node_modules/diff": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
+      "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
+      "engines": {
+        "node": ">=0.3.1"
+      }
+    },
+    "node_modules/make-error": {
+      "version": "1.3.6",
+      "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
+      "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw=="
+    },
+    "node_modules/toml": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/toml/-/toml-3.0.0.tgz",
+      "integrity": "sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w=="
+    },
+    "node_modules/ts-node": {
+      "version": "10.7.0",
+      "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.7.0.tgz",
+      "integrity": "sha512-TbIGS4xgJoX2i3do417KSaep1uRAW/Lu+WAL2doDHC0D6ummjirVOXU5/7aiZotbQ5p1Zp9tP7U6cYhA0O7M8A==",
+      "dependencies": {
+        "@cspotcode/source-map-support": "0.7.0",
+        "@tsconfig/node10": "^1.0.7",
+        "@tsconfig/node12": "^1.0.7",
+        "@tsconfig/node14": "^1.0.0",
+        "@tsconfig/node16": "^1.0.2",
+        "acorn": "^8.4.1",
+        "acorn-walk": "^8.1.1",
+        "arg": "^4.1.0",
+        "create-require": "^1.1.0",
+        "diff": "^4.0.1",
+        "make-error": "^1.1.1",
+        "v8-compile-cache-lib": "^3.0.0",
+        "yn": "3.1.1"
+      },
+      "bin": {
+        "ts-node": "dist/bin.js",
+        "ts-node-cwd": "dist/bin-cwd.js",
+        "ts-node-esm": "dist/bin-esm.js",
+        "ts-node-script": "dist/bin-script.js",
+        "ts-node-transpile-only": "dist/bin-transpile.js",
+        "ts-script": "dist/bin-script-deprecated.js"
+      },
+      "peerDependencies": {
+        "@swc/core": ">=1.2.50",
+        "@swc/wasm": ">=1.2.50",
+        "@types/node": "*",
+        "typescript": ">=2.7"
+      },
+      "peerDependenciesMeta": {
+        "@swc/core": {
+          "optional": true
+        },
+        "@swc/wasm": {
+          "optional": true
         }
+      }
+    },
+    "node_modules/typescript": {
+      "version": "4.6.3",
+      "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.3.tgz",
+      "integrity": "sha512-yNIatDa5iaofVozS/uQJEl3JRWLKKGJKh6Yaiv0GLGSuhpFJe7P3SbHZ8/yjAHRQwKRoA6YZqlfjXWmVzoVSMw==",
+      "peer": true,
+      "bin": {
+        "tsc": "bin/tsc",
+        "tsserver": "bin/tsserver"
+      },
+      "engines": {
+        "node": ">=4.2.0"
+      }
+    },
+    "node_modules/v8-compile-cache-lib": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.0.tgz",
+      "integrity": "sha512-mpSYqfsFvASnSn5qMiwrr4VKfumbPyONLCOPmsR3A6pTY/r0+tSaVbgPWSAIuzbk3lCTa+FForeTiO+wBQGkjA=="
+    },
+    "node_modules/yn": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
+      "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
+      "engines": {
+        "node": ">=6"
+      }
+    }
+  },
+  "dependencies": {
+    "@cspotcode/source-map-consumer": {
+      "version": "0.8.0",
+      "resolved": "https://registry.npmjs.org/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz",
+      "integrity": "sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg=="
+    },
+    "@cspotcode/source-map-support": {
+      "version": "0.7.0",
+      "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.7.0.tgz",
+      "integrity": "sha512-X4xqRHqN8ACt2aHVe51OxeA2HjbcL4MqFqXkrmQszJ1NOUuUu5u6Vqx/0lZSVNku7velL5FC/s5uEAj1lsBMhA==",
+      "requires": {
+        "@cspotcode/source-map-consumer": "0.8.0"
+      }
+    },
+    "@tsconfig/node10": {
+      "version": "1.0.8",
+      "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz",
+      "integrity": "sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg=="
+    },
+    "@tsconfig/node12": {
+      "version": "1.0.9",
+      "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.9.tgz",
+      "integrity": "sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw=="
+    },
+    "@tsconfig/node14": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.1.tgz",
+      "integrity": "sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg=="
+    },
+    "@tsconfig/node16": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.2.tgz",
+      "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA=="
+    },
+    "@types/chroma-js": {
+      "version": "2.1.3",
+      "resolved": "https://registry.npmjs.org/@types/chroma-js/-/chroma-js-2.1.3.tgz",
+      "integrity": "sha512-1xGPhoSGY1CPmXLCBcjVZSQinFjL26vlR8ZqprsBWiFyED4JacJJ9zHhh5aaUXqbY9B37mKQ73nlydVAXmr1+g=="
+    },
+    "@types/node": {
+      "version": "17.0.23",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.23.tgz",
+      "integrity": "sha512-UxDxWn7dl97rKVeVS61vErvw086aCYhDLyvRQZ5Rk65rZKepaFdm53GeqXaKBuOhED4e9uWq34IC3TdSdJJ2Gw=="
+    },
+    "acorn": {
+      "version": "8.7.0",
+      "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz",
+      "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ=="
+    },
+    "acorn-walk": {
+      "version": "8.2.0",
+      "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz",
+      "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA=="
+    },
+    "arg": {
+      "version": "4.1.3",
+      "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
+      "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA=="
+    },
+    "bezier-easing": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/bezier-easing/-/bezier-easing-2.1.0.tgz",
+      "integrity": "sha512-gbIqZ/eslnUFC1tjEvtz0sgx+xTK20wDnYMIA27VA04R7w6xxXQPZDbibjA9DTWZRA2CXtwHykkVzlCaAJAZig=="
+    },
+    "case-anything": {
+      "version": "2.1.10",
+      "resolved": "https://registry.npmjs.org/case-anything/-/case-anything-2.1.10.tgz",
+      "integrity": "sha512-JczJwVrCP0jPKh05McyVsuOg6AYosrB9XWZKbQzXeDAm2ClE/PJE/BcrrQrVyGYH7Jg8V/LDupmyL4kFlVsVFQ=="
+    },
+    "chroma-js": {
+      "version": "2.4.2",
+      "resolved": "https://registry.npmjs.org/chroma-js/-/chroma-js-2.4.2.tgz",
+      "integrity": "sha512-U9eDw6+wt7V8z5NncY2jJfZa+hUH8XEj8FQHgFJTrUFnJfXYf4Ml4adI2vXZOjqRDpFWtYVWypDfZwnJ+HIR4A=="
+    },
+    "create-require": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
+      "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ=="
+    },
+    "diff": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
+      "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A=="
+    },
+    "make-error": {
+      "version": "1.3.6",
+      "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
+      "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw=="
+    },
+    "toml": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/toml/-/toml-3.0.0.tgz",
+      "integrity": "sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w=="
+    },
+    "ts-node": {
+      "version": "10.7.0",
+      "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.7.0.tgz",
+      "integrity": "sha512-TbIGS4xgJoX2i3do417KSaep1uRAW/Lu+WAL2doDHC0D6ummjirVOXU5/7aiZotbQ5p1Zp9tP7U6cYhA0O7M8A==",
+      "requires": {
+        "@cspotcode/source-map-support": "0.7.0",
+        "@tsconfig/node10": "^1.0.7",
+        "@tsconfig/node12": "^1.0.7",
+        "@tsconfig/node14": "^1.0.0",
+        "@tsconfig/node16": "^1.0.2",
+        "acorn": "^8.4.1",
+        "acorn-walk": "^8.1.1",
+        "arg": "^4.1.0",
+        "create-require": "^1.1.0",
+        "diff": "^4.0.1",
+        "make-error": "^1.1.1",
+        "v8-compile-cache-lib": "^3.0.0",
+        "yn": "3.1.1"
+      }
+    },
+    "typescript": {
+      "version": "4.6.3",
+      "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.3.tgz",
+      "integrity": "sha512-yNIatDa5iaofVozS/uQJEl3JRWLKKGJKh6Yaiv0GLGSuhpFJe7P3SbHZ8/yjAHRQwKRoA6YZqlfjXWmVzoVSMw==",
+      "peer": true
+    },
+    "v8-compile-cache-lib": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.0.tgz",
+      "integrity": "sha512-mpSYqfsFvASnSn5qMiwrr4VKfumbPyONLCOPmsR3A6pTY/r0+tSaVbgPWSAIuzbk3lCTa+FForeTiO+wBQGkjA=="
+    },
+    "yn": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
+      "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q=="
     }
+  }
 }

styles/package.json 🔗

@@ -12,9 +12,16 @@
     "dependencies": {
         "@types/chroma-js": "^2.1.3",
         "@types/node": "^17.0.23",
+        "bezier-easing": "^2.1.0",
         "case-anything": "^2.1.10",
         "chroma-js": "^2.4.2",
         "toml": "^3.0.0",
         "ts-node": "^10.7.0"
+    },
+    "prettier": {
+        "semi": false,
+        "printWidth": 80,
+        "htmlWhitespaceSensitivity": "strict",
+        "tabWidth": 4
     }
 }

styles/src/common.ts 🔗

@@ -43,24 +43,3 @@ export const sizes = {
   lg: 8,
   xl: 12,
 };
-
-// export const colors = {
-//   neutral: colorRamp(["white", "black"], { steps: 37, increment: 25 }), // (900/25) + 1
-//   rose: colorRamp("#F43F5EFF"),
-//   red: colorRamp("#EF4444FF"),
-//   orange: colorRamp("#F97316FF"),
-//   amber: colorRamp("#F59E0BFF"),
-//   yellow: colorRamp("#EAB308FF"),
-//   lime: colorRamp("#84CC16FF"),
-//   green: colorRamp("#22C55EFF"),
-//   emerald: colorRamp("#10B981FF"),
-//   teal: colorRamp("#14B8A6FF"),
-//   cyan: colorRamp("#06BBD4FF"),
-//   sky: colorRamp("#0EA5E9FF"),
-//   blue: colorRamp("#3B82F6FF"),
-//   indigo: colorRamp("#6366F1FF"),
-//   violet: colorRamp("#8B5CF6FF"),
-//   purple: colorRamp("#A855F7FF"),
-//   fuschia: colorRamp("#D946E4FF"),
-//   pink: colorRamp("#EC4899FF"),
-// }

styles/src/system/lib/convert.ts 🔗

@@ -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
+}

styles/src/system/lib/curve.ts 🔗

@@ -0,0 +1,26 @@
+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]
+    )
+}

styles/src/system/lib/generate.ts 🔗

@@ -0,0 +1,159 @@
+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()
+
+    // 55 is a magic number. It's the lightness value at which we consider a color to be "light".
+    // It was picked by eye with some testing. We might want to use a more scientific approach in the future.
+    const isLight = lch[0] > 55
+
+    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
+}

styles/src/system/ref/color.ts 🔗

@@ -0,0 +1,445 @@
+import { generateColorFamily } from "../lib/generate"
+import { curve } from "./curves"
+
+// These are the source colors for the color scales in the system.
+// 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.
+
+// Light Gray ======================================== //
+
+export const lightgray = generateColorFamily({
+    name: "lightgray",
+    color: {
+        hue: {
+            start: 210,
+            end: 210,
+            curve: curve.linear,
+        },
+        saturation: {
+            start: 10,
+            end: 15,
+            curve: curve.saturation,
+        },
+        lightness: {
+            start: 97,
+            end: 50,
+            curve: curve.linear,
+        },
+    },
+})
+
+// Light Dark ======================================== //
+
+export const darkgray = generateColorFamily({
+    name: "darkgray",
+    color: {
+        hue: {
+            start: 210,
+            end: 210,
+            curve: curve.linear,
+        },
+        saturation: {
+            start: 15,
+            end: 20,
+            curve: curve.saturation,
+        },
+        lightness: {
+            start: 55,
+            end: 8,
+            curve: curve.linear,
+        },
+    },
+})
+
+// Red ======================================== //
+
+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,
+        },
+    },
+})
+
+// Sunset ======================================== //
+
+export const sunset = generateColorFamily({
+    name: "sunset",
+    color: {
+        hue: {
+            start: 15,
+            end: 15,
+            curve: curve.linear,
+        },
+        saturation: {
+            start: 100,
+            end: 90,
+            curve: curve.saturation,
+        },
+        lightness: {
+            start: 97,
+            end: 25,
+            curve: curve.lightness,
+        },
+    },
+})
+
+// Orange ======================================== //
+
+export const orange = generateColorFamily({
+    name: "orange",
+    color: {
+        hue: {
+            start: 25,
+            end: 25,
+            curve: curve.linear,
+        },
+        saturation: {
+            start: 100,
+            end: 95,
+            curve: curve.saturation,
+        },
+        lightness: {
+            start: 97,
+            end: 20,
+            curve: curve.lightness,
+        },
+    },
+})
+
+// Amber ======================================== //
+
+export const amber = generateColorFamily({
+    name: "amber",
+    color: {
+        hue: {
+            start: 38,
+            end: 38,
+            curve: curve.linear,
+        },
+        saturation: {
+            start: 100,
+            end: 100,
+            curve: curve.saturation,
+        },
+        lightness: {
+            start: 97,
+            end: 18,
+            curve: curve.lightness,
+        },
+    },
+})
+
+// Yellow ======================================== //
+
+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: 15,
+            curve: curve.lightness,
+        },
+    },
+})
+
+// Lemon ======================================== //
+
+export const lemon = generateColorFamily({
+    name: "lemon",
+    color: {
+        hue: {
+            start: 55,
+            end: 55,
+            curve: curve.linear,
+        },
+        saturation: {
+            start: 85,
+            end: 95,
+            curve: curve.saturation,
+        },
+        lightness: {
+            start: 97,
+            end: 15,
+            curve: curve.lightness,
+        },
+    },
+})
+
+// Citron ======================================== //
+
+export const citron = generateColorFamily({
+    name: "citron",
+    color: {
+        hue: {
+            start: 70,
+            end: 70,
+            curve: curve.linear,
+        },
+        saturation: {
+            start: 85,
+            end: 90,
+            curve: curve.saturation,
+        },
+        lightness: {
+            start: 97,
+            end: 15,
+            curve: curve.lightness,
+        },
+    },
+})
+
+// Lime ======================================== //
+
+export const lime = generateColorFamily({
+    name: "lime",
+    color: {
+        hue: {
+            start: 85,
+            end: 85,
+            curve: curve.linear,
+        },
+        saturation: {
+            start: 85,
+            end: 80,
+            curve: curve.saturation,
+        },
+        lightness: {
+            start: 97,
+            end: 18,
+            curve: curve.lightness,
+        },
+    },
+})
+
+// Green ======================================== //
+
+export const green = generateColorFamily({
+    name: "green",
+    color: {
+        hue: {
+            start: 108,
+            end: 108,
+            curve: curve.linear,
+        },
+        saturation: {
+            start: 60,
+            end: 70,
+            curve: curve.saturation,
+        },
+        lightness: {
+            start: 97,
+            end: 18,
+            curve: curve.lightness,
+        },
+    },
+})
+
+// Mint ======================================== //
+
+export const mint = generateColorFamily({
+    name: "mint",
+    color: {
+        hue: {
+            start: 142,
+            end: 142,
+            curve: curve.linear,
+        },
+        saturation: {
+            start: 60,
+            end: 75,
+            curve: curve.saturation,
+        },
+        lightness: {
+            start: 97,
+            end: 20,
+            curve: curve.lightness,
+        },
+    },
+})
+
+// Cyan ======================================== //
+
+export const cyan = generateColorFamily({
+    name: "cyan",
+    color: {
+        hue: {
+            start: 179,
+            end: 179,
+            curve: curve.linear,
+        },
+        saturation: {
+            start: 70,
+            end: 80,
+            curve: curve.saturation,
+        },
+        lightness: {
+            start: 97,
+            end: 20,
+            curve: curve.lightness,
+        },
+    },
+})
+
+// Sky ======================================== //
+
+export const sky = generateColorFamily({
+    name: "sky",
+    color: {
+        hue: {
+            start: 195,
+            end: 205,
+            curve: curve.linear,
+        },
+        saturation: {
+            start: 85,
+            end: 90,
+            curve: curve.saturation,
+        },
+        lightness: {
+            start: 97,
+            end: 15,
+            curve: curve.lightness,
+        },
+    },
+})
+
+// Blue ======================================== //
+
+export const blue = generateColorFamily({
+    name: "blue",
+    color: {
+        hue: {
+            start: 218,
+            end: 218,
+            curve: curve.linear,
+        },
+        saturation: {
+            start: 85,
+            end: 70,
+            curve: curve.saturation,
+        },
+        lightness: {
+            start: 97,
+            end: 15,
+            curve: curve.lightness,
+        },
+    },
+})
+
+// Indigo ======================================== //
+
+export const indigo = generateColorFamily({
+    name: "indigo",
+    color: {
+        hue: {
+            start: 245,
+            end: 245,
+            curve: curve.linear,
+        },
+        saturation: {
+            start: 60,
+            end: 50,
+            curve: curve.saturation,
+        },
+        lightness: {
+            start: 97,
+            end: 22,
+            curve: curve.lightness,
+        },
+    },
+})
+
+// Purple ======================================== //
+
+export const purple = generateColorFamily({
+    name: "purple",
+    color: {
+        hue: {
+            start: 260,
+            end: 270,
+            curve: curve.linear,
+        },
+        saturation: {
+            start: 65,
+            end: 55,
+            curve: curve.saturation,
+        },
+        lightness: {
+            start: 97,
+            end: 20,
+            curve: curve.lightness,
+        },
+    },
+})
+
+// Pink ======================================== //
+
+export const pink = generateColorFamily({
+    name: "pink",
+    color: {
+        hue: {
+            start: 320,
+            end: 330,
+            curve: curve.linear,
+        },
+        saturation: {
+            start: 70,
+            end: 65,
+            curve: curve.saturation,
+        },
+        lightness: {
+            start: 97,
+            end: 32,
+            curve: curve.lightness,
+        },
+    },
+})
+
+// Rose ======================================== //
+
+export const rose = generateColorFamily({
+    name: "rose",
+    color: {
+        hue: {
+            start: 345,
+            end: 345,
+            curve: curve.linear,
+        },
+        saturation: {
+            start: 90,
+            end: 70,
+            curve: curve.saturation,
+        },
+        lightness: {
+            start: 97,
+            end: 32,
+            curve: curve.lightness,
+        },
+    },
+})

styles/src/system/ref/curves.ts 🔗

@@ -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.75, 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],
+    },
+}

styles/src/system/system.ts 🔗

@@ -0,0 +1,32 @@
+import chroma from "chroma-js"
+import * as colorFamily from "./ref/color"
+
+const color = {
+    lightgray: chroma
+        .scale(colorFamily.lightgray.scale.values)
+        .mode("lch")
+        .colors(9),
+    darkgray: chroma
+        .scale(colorFamily.darkgray.scale.values)
+        .mode("lch")
+        .colors(9),
+    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),
+    lemon: chroma.scale(colorFamily.lemon.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 }

styles/src/system/types.ts 🔗

@@ -0,0 +1,66 @@
+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[]
+    rgba: number[]
+    isLight: boolean
+}
+
+export interface ColorScale {
+    colors: Color[]
+    // An array of hex values for each color in the scale
+    values: string[]
+}
+
+export type ColorFamily = {
+    name: string
+    scale: ColorScale
+    invertedScale: ColorScale
+}
+
+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: {
+        hue: ColorFamilyHue
+        saturation: ColorFamilySaturation
+        lightness: ColorFamilyLightness
+    }
+}