{
  "schemaVersion": 1,
  "slug": "color-hex-hsl-calculator",
  "category": "conversion",
  "kind": "implementation",
  "independentValidation": false,
  "implementationHash": "96a0515d35a9e0f534abac28adc6f42bd3a5a23046bc1a5d6a4fc9302f3159aa",
  "provenance": "Generated from the calculation contract used by the published page. Publication is not external validation.",
  "sourceFiles": [
    "data/calculators/color-hex-hsl-calculator.json",
    "src/engine.js"
  ],
  "runtimeSource": "/sources/engine.txt",
  "runtimeHash": "5c888d8898afbdee36267bb9977829e1e2ac568f6677c8ee87469c139864645c",
  "scope": "The compute function records implemented equations, constants, lookup tables and custom rules. Inputs record defaults and allowed values; outputs record precision and units. Defaults are examples, not recommendations. General background references are not evidence for this specific algorithm.",
  "publishedFormula": {
    "formula": "L = (M + m) ÷ 2; S = Δ ÷ (1 − |2L − 1|); H → 60° × ((G−B)/Δ mod 6 (R = M) | (B−R)/Δ + 2 (G = M) | (R−G)/Δ + 4 (B = M))",
    "vars": [
      [
        "R,G,B",
        "normalised channels (0–1)"
      ],
      [
        "M",
        "max(R, G, B)"
      ],
      [
        "m",
        "min(R, G, B)"
      ],
      [
        "Δ",
        "M − m"
      ],
      [
        "H,S,L",
        "hue °, saturation, lightness"
      ]
    ],
    "note": "R,G,B are 0–1; when Δ = 0, H = S = 0; S and L are reported as percentages."
  },
  "externalEvidence": {
    "reviewedAt": "2026-10-12",
    "sources": [
      {
        "name": "W3C CSS Color — HSL color model",
        "url": "https://www.w3.org/TR/css-color-4/#the-hsl-notation"
      }
    ],
    "referenceRole": "definition",
    "implementationHash": "96a0515d35a9e0f534abac28adc6f42bd3a5a23046bc1a5d6a4fc9302f3159aa",
    "basis": "L = (M + m) ÷ 2; S = Δ ÷ (1 − |2L − 1|); H → 60° × ((G−B)/Δ mod 6 (R = M) | (B−R)/Δ + 2 (G = M) | (R−G)/Δ + 4 (B = M))",
    "limitations": "The references explain definitions and methods; any extra preset must be checked against the assumptions on this page."
  },
  "contract": {
    "compute": "const out=(function(hex){const raw=String(hex).trim().replace(/^#/,'');const empty={hsl:null,h:null,s:null,l:null,rgb:null};if(!/^(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/.test(raw))return{...empty,__error:'inputError'};const full=raw.length===3?raw.split('').map(ch=>ch+ch).join(''):raw;const r=parseInt(full.slice(0,2),16)/255,g=parseInt(full.slice(2,4),16)/255,b=parseInt(full.slice(4,6),16)/255,max=Math.max(r,g,b),min=Math.min(r,g,b),d=max-min;let h=0;if(d>0){if(max===r)h=((g-b)/d)%6;else if(max===g)h=(b-r)/d+2;else h=(r-g)/d+4;h*=60;if(h<0)h+=360;}const l=(max+min)/2,s=d===0?0:d/(1-Math.abs(2*l-1));return{hsl:'hsl('+Math.round(h)+', '+Math.round(s*100)+'%, '+Math.round(l*100)+'%)',h:Math.round(h),s:s*100,l:l*100,rgb:Math.round(r*255)+', '+Math.round(g*255)+', '+Math.round(b*255)};})(hex);if(out.__error)return {...{\"result\":null,\"hsl\":null,\"h\":null,\"s\":null,\"l\":null,\"rgb\":null},...out};out.result=out.hsl;out.__color='rgb('+out.rgb+')';return out;",
    "inputs": [
      {
        "name": "hex",
        "type": "text",
        "default": "#3B82F6",
        "step": 1,
        "preserveEmpty": true
      }
    ],
    "outputs": [
      {
        "name": "result",
        "precision": 4,
        "trimTrailingZeros": true,
        "type": "text"
      },
      {
        "name": "hsl",
        "precision": 0,
        "unit": "",
        "type": "text",
        "showWhen": {
          "hex": []
        }
      },
      {
        "name": "h",
        "precision": 0,
        "unit": "°",
        "notation": "auto"
      },
      {
        "name": "s",
        "precision": 1,
        "unit": "%",
        "notation": "auto"
      },
      {
        "name": "l",
        "precision": 1,
        "unit": "%",
        "notation": "auto"
      },
      {
        "name": "rgb",
        "precision": 0,
        "unit": "",
        "type": "text"
      }
    ],
    "interpret": null
  }
}
