mirror of
https://github.com/tiennm99/programming-fengshui.git
synced 2026-05-14 00:58:24 +00:00
651b123f05
KIM was effectively empty (3 GH / 0 GL) because the old rule required S<5 AND L≥70 — only near-white grays. Generalize KIM to any color with L≥70, regardless of hue. Stretches Ngũ Hành orthodoxy slightly (KIM was canonically white-only) but stays within the spirit: highly-reflective pastels read as 'metallic shine'. New distribution: GitHub: KIM 3 → 65 (10%) GitLab: KIM 0 → 6 (7%) Sample-language drift: only Kotlin #A97BFF (L=74 light purple) moves HOẢ → KIM. Updated fixture and plan acceptance criteria to match. See plans/reports/brainstorm-260427-1046-kim-rebalance.md
58 lines
1.6 KiB
JavaScript
58 lines
1.6 KiB
JavaScript
// Algorithm: plans/reports/researcher-260427-0854-nguhanh-color-classifier.md §2
|
|
// Pure HSL classifier mapping a hex color to one of the 5 Ngũ Hành elements.
|
|
|
|
export const ELEMENTS = [
|
|
{ key: 'kim', label: 'KIM' },
|
|
{ key: 'moc', label: 'MỘC' },
|
|
{ key: 'thuy', label: 'THUỶ' },
|
|
{ key: 'hoa', label: 'HOẢ' },
|
|
{ key: 'tho', label: 'THỔ' },
|
|
];
|
|
|
|
const HEX_RE = /^#[0-9a-fA-F]{6}$/;
|
|
|
|
export function hexToHsl(hex) {
|
|
if (typeof hex !== 'string' || !HEX_RE.test(hex)) {
|
|
throw new TypeError(`hexToHsl: expected '#RRGGBB', got ${hex}`);
|
|
}
|
|
const r = parseInt(hex.slice(1, 3), 16) / 255;
|
|
const g = parseInt(hex.slice(3, 5), 16) / 255;
|
|
const b = parseInt(hex.slice(5, 7), 16) / 255;
|
|
|
|
const max = Math.max(r, g, b);
|
|
const min = Math.min(r, g, b);
|
|
const d = max - min;
|
|
const l = (max + min) / 2;
|
|
|
|
let h = 0;
|
|
let s = 0;
|
|
if (d !== 0) {
|
|
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
|
|
switch (max) {
|
|
case r: h = ((g - b) / d) + (g < b ? 6 : 0); break;
|
|
case g: h = ((b - r) / d) + 2; break;
|
|
case b: h = ((r - g) / d) + 4; break;
|
|
}
|
|
h *= 60;
|
|
}
|
|
return { h, s: s * 100, l: l * 100 };
|
|
}
|
|
|
|
export function classify(hex) {
|
|
const { h, s, l } = hexToHsl(hex);
|
|
|
|
// Step 1: KIM — high lightness ("metallic shine"); catches whites + pastels of any hue
|
|
if (l >= 70) return 'kim';
|
|
|
|
// Step 2: grayscale (very low saturation, lightness already < 70)
|
|
if (s < 5) return l < 20 ? 'thuy' : 'tho';
|
|
|
|
// Step 3: hue ranges
|
|
if (h < 20) return 'hoa';
|
|
if (h < 40) return (s >= 60 && l >= 50) ? 'hoa' : 'tho';
|
|
if (h < 70) return 'tho';
|
|
if (h < 200) return 'moc';
|
|
if (h < 260) return 'thuy';
|
|
return 'hoa';
|
|
}
|