51 lines
2.1 KiB
TypeScript
51 lines
2.1 KiB
TypeScript
import { describe, expect, it } from 'vitest';
|
|
import { rgb, wavePalette, WAVE_COLORS } from './wave-anim';
|
|
|
|
function hsl(color: string) {
|
|
const [r, g, b] = rgb(color).map((v) => v / 255) as [number, number, number];
|
|
const max = Math.max(r, g, b);
|
|
const min = Math.min(r, g, b);
|
|
const c = max - min;
|
|
const l = (max + min) / 2;
|
|
const h = c === 0 ? 0 : max === r ? (g - b) / c : max === g ? (b - r) / c + 2 : (r - g) / c + 4;
|
|
return { h: (h * 60 + 360) % 360, s: c === 0 ? 0 : c / (1 - Math.abs(2 * l - 1)), l };
|
|
}
|
|
|
|
describe('wave cover palette', () => {
|
|
it.each([
|
|
undefined, [], ['#fff'], ['#000', '#888', '#fff'],
|
|
['#010203', '#fefdfc', '#808182'], ['#ff0000', 'invalid', '#0000ff'],
|
|
])('uses the default palette for missing, neutral or malformed colors: %j', (colors) => {
|
|
expect(wavePalette(colors)).toEqual(WAVE_COLORS);
|
|
});
|
|
|
|
it('ignores neutral colors and preserves the strongest cover hue', () => {
|
|
const colors = ['#ffffff', '#007733', '#222222'];
|
|
const before = [...colors];
|
|
expect(hsl(wavePalette(colors)[0]).h).toBeCloseTo(hsl('#007733').h, 0);
|
|
expect(wavePalette(colors)).toEqual(wavePalette(['#007733', '#222222', '#ffffff']));
|
|
expect(colors).toEqual(before);
|
|
expect(wavePalette(['#fff', '#073', '#222'])).toEqual(wavePalette(colors));
|
|
});
|
|
|
|
it.each([
|
|
['#040e08', '#18281d', '#374450'], // dark, muted cover like the reported case
|
|
['#ff0000', '#00ff00', '#0000ff'], // opposing hues must not mix to gray
|
|
['#ffff00', '#ffffff', '#000000'],
|
|
['#ff0080', '#540029', '#fefefe'], // hue offsets wrap around red
|
|
])('keeps a visible, saturated, harmonious palette for %j', (...colors) => {
|
|
const palette = wavePalette(colors);
|
|
const base = hsl(palette[0]);
|
|
for (const color of palette) {
|
|
expect(color).toMatch(/^#[\da-f]{6}$/i);
|
|
const { h, s, l } = hsl(color);
|
|
expect(s).toBeGreaterThanOrEqual(0.70);
|
|
expect(s).toBeLessThanOrEqual(0.84);
|
|
expect(l).toBeGreaterThanOrEqual(0.45);
|
|
expect(l).toBeLessThanOrEqual(0.59);
|
|
const distance = Math.abs(h - base.h);
|
|
expect(Math.min(distance, 360 - distance)).toBeLessThan(29);
|
|
}
|
|
});
|
|
});
|