(seed: HexColor, isDark: boolean, ink?: HexColor)
| 169 | } |
| 170 | |
| 171 | export function generateNeutralScale(seed: HexColor, isDark: boolean, ink?: HexColor): HexColor[] { |
| 172 | if (ink) { |
| 173 | const base = hexToOklch(seed) |
| 174 | const lift = (tone: number) => |
| 175 | oklchToHex({ |
| 176 | l: base.l + (1 - base.l) * tone, |
| 177 | c: base.c * Math.max(0, 1 - tone), |
| 178 | h: base.h, |
| 179 | }) |
| 180 | const sink = (tone: number) => |
| 181 | oklchToHex({ |
| 182 | l: base.l * (1 - tone), |
| 183 | c: base.c * Math.max(0, 1 - tone * (isDark ? 0.12 : 0.3)), |
| 184 | h: base.h, |
| 185 | }) |
| 186 | const bg = isDark |
| 187 | ? sink(clamp(0.19 + Math.max(0, base.l - 0.12) * 0.33 + base.c * 1.95, 0.17, 0.27)) |
| 188 | : base.l < 0.82 |
| 189 | ? lift(0.86) |
| 190 | : lift(clamp(0.1 + base.c * 3.2 + Math.max(0, 0.95 - base.l) * 0.35, 0.1, 0.28)) |
| 191 | const steps = isDark |
| 192 | ? [0, 0.018, 0.039, 0.064, 0.097, 0.143, 0.212, 0.31, 0.46, 0.649, 0.845, 0.984] |
| 193 | : [0, 0.022, 0.042, 0.068, 0.102, 0.146, 0.208, 0.296, 0.432, 0.61, 0.81, 0.965] |
| 194 | return steps.map((step) => mixColors(bg, ink, step)) |
| 195 | } |
| 196 | |
| 197 | const base = hexToOklch(seed) |
| 198 | const scale: HexColor[] = [] |
| 199 | const neutralChroma = Math.min(base.c, isDark ? 0.068 : 0.04) |
| 200 | |
| 201 | const lightSteps = isDark |
| 202 | ? [0.138, 0.156, 0.178, 0.202, 0.232, 0.272, 0.326, 0.404, clamp(base.l * 0.83, 0.43, 0.55), 0.596, 0.719, 0.956] |
| 203 | : [0.991, 0.979, 0.964, 0.946, 0.931, 0.913, 0.891, 0.83, base.l, 0.617, 0.542, 0.205] |
| 204 | |
| 205 | for (let i = 0; i < 12; i++) { |
| 206 | scale.push( |
| 207 | oklchToHex({ |
| 208 | l: lightSteps[i], |
| 209 | c: neutralChroma, |
| 210 | h: base.h, |
| 211 | }), |
| 212 | ) |
| 213 | } |
| 214 | |
| 215 | return scale |
| 216 | } |
| 217 | |
| 218 | export function generateAlphaScale(scale: HexColor[], isDark: boolean): HexColor[] { |
| 219 | const alphas = isDark |
no test coverage detected