Design

COLOR PICKER & CONVERTER

Convert colors between HEX, RGB, HSL, HSV, and CMYK. Generate shades, tints, and complementary palettes.

Color Formats
HEX
#ff2200
RGB
rgb(255, 34, 0)
HSL
hsl(8, 100%, 50%)
HSV
hsv(8, 100%, 100%)
CMYK
cmyk(0%, 87%, 100%, 0%)
Tints & Shades
Color Harmony
Developer Reference

Core Algorithm & Standalone Script

Standalone, zero-dependency JavaScript implementation powering this tool. Free to inspect, copy, and build upon.

// ── Color math ───────────────────────────────────────────────
  function hexToRgb(hex) {
    hex = hex.replace(/^#/, '');
    if (hex.length === 3) hex = hex.split('').map(c => c + c).join('');
    const n = parseInt(hex, 16);
    return { r: (n >> 16) & 255, g: (n >> 8) & 255, b: n & 255 };
  }
  function rgbToHex(r, g, b) {
    return '#' + [r, g, b].map(v => v.toString(16).padStart(2, '0')).join('');
  }
  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, 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)) / 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) };
  }
  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) };
  }
  function rgbToHsv(r, g, b) {
    r /= 255; g /= 255; b /= 255;
    const max = Math.max(r, g, b), min = Math.min(r, g, b), d = max - min;
    let h = 0, s = max === 0 ? 0 : d / max, v = max;
    if (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), v: Math.round(v * 100) };
  }
  function rgbToCmyk(r, g, b) {
    r /= 255; g /= 255; b /= 255;
    const k = 1 - Math.max(r, g, b);
    if (k === 1) return { c: 0, m: 0, y: 0, k: 100 };
    return {
      c: Math.round(((1 - r - k) / (1 - k)) * 100),
      m: Math.round(((1 - g - k) / (1 - k)) * 100),
      y: Math.round(((1 - b - k) / (1 - k)) * 100),
      k: Math.round(k * 100)
    };
  }

  // CSS named colors lookup (subset)
  const CSS_COLORS = {
    '#000000':'black','#ffffff':'white','#ff0000':'red','#00ff00':'lime',
    '#0000ff':'blue','#ffff00':'yellow','#00ffff':'cyan','#ff00ff':'magenta',
    '#c0c0c0':'silver','#808080':'gray','#800000':'maroon','#808000':'olive',
    '#008000':'green','#800080':'purple','#008080':'teal','#000080':'navy',
    '#ffa500':'orange','#ff6347':'tomato','#ff69b4':'hotpink','#ffd700':'gold',
    '#4169e1':'royalblue','#dc143c':'crimson','#00ced1':'darkturquoise',
    '#ff8c00':'darkorange','#9932cc':'darkorchid','#8b0000':'darkred',
    '#2f4f4f':'darkslategray','#696969':'dimgray','#b8860b':'darkgoldenrod',
    '#006400':'darkgreen','#bdb76b':'darkkhaki','#8b008b':'darkmagenta',
    '#556b2f':'darkolivegreen','#ff8c00':'darkorange','#9932cc':'darkorchid',
    '#e9967a':'darksalmon','#8fbc8f':'darkseagreen','#483d8b':'darkslateblue',
    '#1e90ff':'dodgerblue','#b22222':'firebrick','#fffaf0':'floralwhite',
    '#228b22':'forestgreen','#dcdcdc':'gainsboro','#f8f8ff':'ghostwhite',
    '#adff2f':'greenyellow','#ff69b4':'hotpink','#cd5c5c':'indianred',
    '#4b0082':'indigo','#fffff0':'ivory','#f0e68c':'khaki','#e6e6fa':'lavender',
    '#7cfc00':'lawngreen','#add8e6':'lightblue','#f08080':'lightcoral',
    '#90ee90':'lightgreen','#ffb6c1':'lightpink','#20b2aa':'lightseagreen',
    '#87ceeb':'lightskyblue','#778899':'lightslategray','#b0c4de':'lightsteelblue',
    '#ffffe0':'lightyellow','#32cd32':'limegreen','#faf0e6':'linen',
    '#66cdaa':'mediumaquamarine','#0000cd':'mediumblue','#ba55d3':'mediumorchid',
    '#9370db':'mediumpurple','#3cb371':'mediumseagreen','#7b68ee':'mediumslateblue',
    '#00fa9a':'mediumspringgreen','#48d1cc':'mediumturquoise','#c71585':'mediumvioletred',
    '#191970':'midnightblue','#f5fffa':'mintcream','#ffe4e1':'mistyrose',
    '#ffe4b5':'moccasin','#000080':'navy','#fdf5e6':'oldlace','#6b8e23':'olivedrab',
    '#ff4500':'orangered','#da70d6':'orchid','#eee8aa':'palegoldenrod',
    '#98fb98':'palegreen','#afeeee':'paleturquoise','#db7093':'palevioletred',
    '#ffdab9':'peachpuff','#cd853f':'peru','#ffc0cb':'pink','#dda0dd':'plum',
    '#b0e0e6':'powderblue','#bc8f8f':'rosybrown','#4169e1':'royalblue',
    '#8b4513':'saddlebrown','#fa8072':'salmon','#f4a460':'sandybrown',
    '#2e8b57':'seagreen','#fff5ee':'seashell','#a0522d':'sienna','#87ceeb':'skyblue',
    '#6a5acd':'slateblue','#708090':'slategray','#fffafa':'snow',
    '#00ff7f':'springgreen','#4682b4':'steelblue','#d2b48c':'tan',
    '#d8bfd8':'thistle','#ff6347':'tomato','#40e0d0':'turquoise',
    '#ee82ee':'violet','#f5deb3':'wheat','#9acd32':'yellowgreen'
  };

  // ── State ────────────────────────────────────────────────────
  let currentRgb = hexToRgb('#ff2200');

  function updateAll(hex) {
    hex = hex.toLowerCase();
    const rgb = hexToRgb(hex);
    if (!rgb) return;
    currentRgb = rgb;

    // Swatch
    document.getElementById('swatchBox').style.background = hex;
    document.getElementById('colorPicker').value = hex;
    document.getElementById('hexInput').value = hex;
    document.getElementById('hexInput').classList.remove('invalid');

    // CSS name
    const cssName = CSS_COLORS[hex] || '';
    document.getElementById('cssName').textContent = cssName;

    // Conversions
    const { r, g, b } = rgb;
    const hsl = rgbToHsl(r, g, b);
    const hsv = rgbToHsv(r, g, b);
    const cmyk = rgbToCmyk(r, g, b);

    document.getElementById('c-hex').textContent = hex;
    document.getElementById('c-rgb').textContent = `rgb(${r}, ${g}, ${b})`;
    document.getElementById('c-hsl').textContent = `hsl(${hsl.h}, ${hsl.s}%, ${hsl.l}%)`;
    document.getElementById('c-hsv').textContent = `hsv(${hsv.h}, ${hsv.s}%, ${hsv.v}%)`;
    document.getElementById('c-cmyk').textContent = `cmyk(${cmyk.c}%, ${cmyk.m}%, ${cmyk.y}%, ${cmyk.k}%)`;

    if (cssName) {
      document.getElementById('c-named').textContent = cssName;
      document.getElementById('c-named-card').style.display = '';
    } else {
      document.getElementById('c-named-card').style.display = 'none';
    }

    updateShades(r, g, b);
    updateHarmony(hsl.h, hsl.s, hsl.l);
  }

  function updateShades(r, g, b) {
    const strip = document.getElementById('shadeStrip');
    strip.innerHTML = '';
    const hsl = rgbToHsl(r, g, b);

    // 9 tints (lighter)
    for (let i = 9; i >= 1; i--) {
      const l = hsl.l + (100 - hsl.l) * (i / 10);
      const rgb2 = hslToRgb(hsl.h, hsl.s, Math.min(100, Math.round(l)));
      const hex2 = rgbToHex(rgb2.r, rgb2.g, rgb2.b);
      addSwatch(strip, hex2, 'Tint ' + i, true);
    }
    // Original
    const origHex = rgbToHex(r, g, b);
    addSwatch(strip, origHex, 'Original', false, true);
    // 9 shades (darker)
    for (let i = 1; i <= 9; i++) {
      const l = hsl.l * (1 - i / 10);
      const rgb2 = hslToRgb(hsl.h, hsl.s, Math.round(l));
      const hex2 = rgbToHex(rgb2.r, rgb2.g, rgb2.b);
      addSwatch(strip, hex2, 'Shade ' + i, true);
    }
  }

  function addSwatch(container, hex, label, clickable, active) {
    const el = document.createElement('div');
    el.className = 'shade-swatch';
    el.style.background = hex;
    el.title = hex;
    if (active) el.style.borderColor = 'rgba(255,255,255,0.6)';
    if (clickable) {
      el.onclick = () => { copyHex(hex); updateAll(hex); };
    }
    container.appendChild(el);
  }

  function updateHarmony(h, s, l) {
    const row = document.getElementById('harmonyRow');
    row.innerHTML = '';

    const harmonies = [
      { name: 'Complementary', angles: [h, (h + 180) % 360] },
      { name: 'Split-Complementary', angles: [h, (h + 150) % 360, (h + 210) % 360] },
      { name: 'Triadic', angles: [h, (h + 120) % 360, (h + 240) % 360] },
      { name: 'Analogous', angles: [h, (h + 30) % 360, (h - 30 + 360) % 360] },
    ];

    harmonies.forEach(harm => {
      const group = document.createElement('div');
      group.className = 'harmony-group';
      const label = document.createElement('div');
      label.className = 'harmony-label';
      label.textContent = harm.name;
      group.appendChild(label);
      const swatches = document.createElement('div');
      swatches.className = 'harmony-swatches';
      harm.angles.forEach(angle => {
        const rgb2 = hslToRgb(angle, s, l);
        const hex2 = rgbToHex(rgb2.r, rgb2.g, rgb2.b);
        const wrap = document.createElement('div');
        wrap.style.position = 'relative';
        wrap.style.marginBottom = '20px';
        const sw = document.createElement('div');
        sw.className = 'harmony-swatch';
        sw.style.background = hex2;
        sw.title = hex2;
        sw.onclick = () => { copyHex(hex2); updateAll(hex2); };
        const hexLbl = document.createElement('div');
        hexLbl.className = 'harmony-swatch-hex';
        hexLbl.textContent = hex2;
        wrap.appendChild(sw);
        wrap.appendChild(hexLbl);
        swatches.appendChild(wrap);
      });
      group.appendChild(swatches);
      row.appendChild(group);
    });
  }

  function copyHex(hex) {
    navigator.clipboard.writeText(hex).catch(() => {});
    showToast('Copied ' + hex);
  }

  function showToast(msg) {
    const t = document.getElementById('toast');
    t.textContent = msg;
    t.classList.add('show');
    setTimeout(() => t.classList.remove('show'), 2000);
  }

  function onPickerChange(val) {
    updateAll(val);
  }

  function onHexInput(val) {
    const clean = val.trim();
    if (/^#[0-9a-fA-F]{6}$/.test(clean)) {
      document.getElementById('hexInput').classList.remove('invalid');
      updateAll(clean.toLowerCase());
    } else if (/^#[0-9a-fA-F]{3}$/.test(clean)) {
      document.getElementById('hexInput').classList.remove('invalid');
      updateAll(clean.toLowerCase());
    } else {
      document.getElementById('hexInput').classList.add('invalid');
    }
  }

  function copyConv(id, btn) {
    const text = document.getElementById(id).textContent;
    navigator.clipboard.writeText(text).catch(() => {});
    btn.textContent = 'copied!';
    btn.classList.add('copied');
    setTimeout(() => { btn.textContent = 'copy'; btn.classList.remove('copied'); }, 2000);
  }

  // Init
  updateAll('#ff2200');