// Hex → RGB export function hexToRgb(hex) { const h = hex.replace('#', ''); if (!/^[0-9a-fA-F]{3}$/.test(h) && !/^[0-9a-fA-F]{6}$/.test(h)) return null; const n = parseInt(h.length === 3 ? h.split('').map(c => c + c).join('') : h, 16); return { r: (n >> 16) & 255, g: (n >> 8) & 255, b: n & 255 }; } // RGB → Hex export function rgbToHex({ r, g, b }) { return '#' + [r, g, b].map(v => v.toString(16).padStart(2, '0')).join(''); } // RGB → HSL (h: 0-360, s: 0-100, l: 0-100) export function rgbToHsl({ r, g, b }) { r /= 255; g /= 255; b /= 255; const max = Math.max(r, g, b), min = Math.min(r, g, b); let h = 0, s = 0; const l = (max + min) / 2; if (max === min) { // h and s remain 0 (achromatic) } else { const d = max - min; s = l > 0.5 ? d / (2 - max - min) : d / (max + min); switch (max) { case r: h = ((g - b) / d + (g < b ? 6 : 0)) / 6; break; case g: h = ((b - r) / d + 2) / 6; break; case b: h = ((r - g) / d + 4) / 6; break; } } return { h: Math.round(h * 360), s: Math.round(s * 100), l: Math.round(l * 100) }; } // HSL → RGB export function hslToRgb({ h, s, l }) { s /= 100; l /= 100; const k = n => (n + h / 30) % 12; const a = s * Math.min(l, 1 - l); const f = n => l - a * Math.max(-1, Math.min(k(n) - 3, Math.min(9 - k(n), 1))); return { r: Math.round(f(0) * 255), g: Math.round(f(8) * 255), b: Math.round(f(4) * 255) }; } // HSL → Hex export function hslToHex(hsl) { return rgbToHex(hslToRgb(hsl)); } // Hex → HSL export function hexToHsl(hex) { return rgbToHsl(hexToRgb(hex)); } // Harmonien — Input: HSL, Output: Objekt mit Arrays von HSL-Objekten export function getHarmonies(hsl) { const rotate = deg => ({ ...hsl, h: (hsl.h + deg + 360) % 360 }); return { komplementaer: [rotate(180)], analog: [rotate(-30), rotate(30)], triade: [rotate(120), rotate(240)], splitKomplementaer: [rotate(150), rotate(210)], }; }