While working on a design system recently, I kept running into the same frustrating problem: I’d grab a color from Figma in HEX format, need it in HSL for a CSS variable, and end up bouncing between three different websites just to convert one value. Each site had its own UI quirks, some required JavaScript to be enabled, and none of them gave me a proper color scheme alongside the conversion.
So I did what any reasonable developer would do — I built my own. Because apparently I enjoy reinventing wheels.
The Problem With Existing Solutions
The existing color converter tools online weren’t bad, but they had a few issues that bugged me:
- They were slow — many loaded heavy JavaScript libraries just to do simple math
- They lacked context — I wanted to see complementary colors and schemes alongside the conversion
- They were ad-heavy — I don’t want to dodge pop-ups while trying to match a shade of blue
I wanted something that felt like a native tool: instant, offline-capable, and comprehensive. A single HTML file that I could open, use, and close without ceremony.
The Architecture Decision
The first decision was whether to use a library or write the conversion logic myself. Libraries like color (npm) are battle-tested, but they add weight. Since this is a browser-only tool with no build step, I decided to write the conversions in vanilla JavaScript.
Here’s the core conversion logic that handles the heavy lifting:
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 [Math.round(f(0) * 255), Math.round(f(8) * 255), Math.round(f(4) * 255)];
}
Enter fullscreen mode Exit fullscreen mode
This is the most concise HSL-to-RGB conversion I know. It’s a compact version of the standard formula that avoids the typical case-based approach. The math checks out for all edge cases, including grayscale (when s = 0).
AI-Assisted Development: The Honest Take
I built this tool with heavy AI assistance, and I want to be transparent about how that went. I described my requirements to Claude, iterated on the design, and let it generate most of the initial code. Here’s what I learned:
What the AI Got Right
The AI was excellent at generating the initial structure — the HTML skeleton, CSS variables for theming, and the basic event handling. It had a solid grasp of the i18n pattern I wanted, with a translation dictionary and a t() function that looked up keys.
Where It Stumbled
The first version had a subtle but critical bug in the color conversion. When I tested it with a known color (e.g., #3b82f6 which should be hsl(217, 91%, 60%)), the HSL output was slightly off. The AI had implemented the conversion with floating-point rounding errors that accumulated.
I had to step in and rewrite the conversion functions myself, using the compact formula above. This was a reminder that while AI can generate code, it doesn’t always validate the output against real-world test cases.
The Iteration Process
Getting the AI to fix the issue took several rounds. I’d paste the buggy output, explain what was wrong, and it would suggest a fix. Sometimes the fix worked, sometimes it introduced new bugs. The most effective approach was to:
- Give it a specific test case with expected output
- Ask it to explain the math before writing the code
- Verify the output manually
Here’s the RGB to HSL conversion that I ended up with after iterating:
function rgbToHsl(r, g, b) {
r /= 255;
g /= 255;
b /= 255;
const max = Math.max(r, g, b);
const min = Math.min(r, g, b);
let h, s, l = (max + min) / 2;
if (max === min) {
h = s = 0;
} 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); break;
case g: h = (b - r) / d + 2; break;
default: h = (r - g) / d + 4;
}
h /= 6;
}
return [Math.round(h * 360), Math.round(s * 100), Math.round(l * 100)];
}
Enter fullscreen mode Exit fullscreen mode
The Color Scheme Generation
Beyond just conversion, I wanted the tool to suggest color schemes. This is where the HSL model shines — you can rotate the hue to get complementary colors.
The logic is straightforward: take the current hue, add specific offsets, and you get different scheme types.
function generateSchemes(h, s, l) {
return {
complementary: `hsl(${(h + 180) % 360}, ${s}%, ${l}%)`,
analogous: [
`hsl(${(h + 30) % 360}, ${s}%, ${l}%)`,
`hsl(${(h - 30 + 360) % 360}, ${s}%, ${l}%)`
],
triadic: [
`hsl(${(h + 120) % 360}, ${s}%, ${l}%)`,
`hsl(${(h + 240) % 360}, ${s}%, ${l}%)`
],
monochromatic: [0.7, 0.85, 1, 1.15, 1.3].map(mult =>
`hsl(${h}, ${s}%, ${Math.min(100, l * mult)}%)`
)
};
}
Enter fullscreen mode Exit fullscreen mode
This runs in milliseconds and requires no external API calls. The monochromatic scale uses multipliers to create lighter and darker variations of the same hue.
Handling Edge Cases
One thing that surprised me was how many edge cases exist in color parsing. Users will type anything into those input fields. Here’s how I handled it:
function parseHex(input) {
let hex = input.trim().replace(/^#/, '');
if (hex.length === 3) {
hex = hex.split('').map(c => c + c).join('');
}
if (!/^[0-9a-fA-F]{6}$/.test(hex)) {
throw new Error('Invalid HEX format');
}
return hex;
}
Enter fullscreen mode Exit fullscreen mode
The 3-digit shorthand (e.g., #3bf) was something users expected, so I expanded it. Invalid input throws an error that gets caught and displayed as a friendly message rather than crashing the app.
The i18n Pattern
Since this tool might be used by developers worldwide, I wanted it to support both English and Chinese. The pattern is simple: a dictionary object and a t() function.
const i18n = {
zh: {
'title': '颜色选择器',
'copy': '复制',
'copied': '已复制'
},
en: {
'title': 'Color Picker',
'copy': 'Copy',
'copied': 'Copied'
}
};
function t(key) {
return i18n[currentLang][key] || i18n['zh'][key] || key;
}
Enter fullscreen mode Exit fullscreen mode
Language detection prioritizes URL parameters over browser settings. This was a deliberate choice — developers often want to force a specific language regardless of their browser locale.
Performance Considerations
This tool has zero dependencies and no network requests. The entire thing is a single HTML file that loads instantly. The only “heavy” operation is generating color schemes, which is pure math and takes microseconds.
I did consider using canvas for a more sophisticated color picker (like the color wheel in Photoshop), but the native <input type="color"> element is surprisingly good and requires zero code. The trade-off is less visual polish, but the reliability and cross-browser consistency win.
What I’d Do Differently
Looking back, there are a few things I’d improve:
- Add a color history — remembering recently used colors would be genuinely useful
-
Support for CSS variables output — generating
--color-name: #hexwould be handy - Named color suggestions — mapping hex values to CSS color names
The AI-Assisted Development Verdict
Working with AI on this project was a mixed experience. It excelled at:
- Generating boilerplate and structure quickly
- Understanding design patterns and CSS theming
- Writing the i18n infrastructure
But it struggled with:
- Precise mathematical implementations
- Understanding edge cases without explicit examples
- Validating its own output against real test cases
My advice: use AI for the scaffolding, but always verify the critical logic yourself. For a color converter, that means testing with known values. For anything else, it means writing unit tests.
Final Thoughts
Building this tool taught me that the simplest solutions often require the most careful math. The HSL-to-RGB conversion looks like a one-liner, but getting it right took real attention to detail.
If you’re working on a project that needs color conversion, I’d encourage you to implement it yourself rather than reaching for a library. The math is well-documented, and you’ll gain a deeper understanding of how colors work in the browser.
During this process, I built a small browser-based tool to make this workflow easier. You can try it here if you’re curious about the implementation.
Tags: javascript, css, webdev, colors, tutorial
답글 남기기