# Spot the bug - #125: Color Blender

**URL:** <https://forum.kirupa.com/t/spot-the-bug-125-color-blender/683126>\
**Category:** web dev\
**Created:** [August 23, 2026, 7:00am UTC](https://forum.kirupa.com/t/spot-the-bug-125-color-blender/683126 "2026-08-23T07:00:09Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![VaultBoy](https://yyz1.discourse-cdn.com/flex011/user_avatar/forum.kirupa.com/vaultboy/32/31832_2.png) [@VaultBoy](https://forum.kirupa.com/u/VaultBoy)\
**Post date:** [August 23, 2026, 7:00am UTC](https://forum.kirupa.com/t/spot-the-bug-125-color-blender/683126/1 "2026-08-23T07:00:10Z")

</div>

Why is my potion mixing color mixer returning completely invalid rgb values?

```js
function parseHexToRgb(hex) {
  const cleanHex = hex.replace('#', '');
  const bigint = parseInt(cleanHex, 16);
  return {
    r: (bigint >> 16) & 255,
    g: (bigint >> 8) & 255,
    b: bigint & 255
  };
}

function rgbToHsl({ r, g, b }) {
  const rNorm = r / 255;
  const gNorm = g / 255;
  const bNorm = b / 255;
  const max = Math.max(rNorm, gNorm, bNorm);
  const min = Math.min(rNorm, gNorm, bNorm);
  const d = max - min;
  let h = 0;
  let s = 0;
  const l = (max + min) / 2;

  if (max !== min) {
    s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
    switch (max) {
      case rNorm:
        h = (gNorm - bNorm) / d + (gNorm < bNorm ? 6 : 0);
        break;
      case gNorm:
        h = (bNorm - rNorm) / d + 2;
        break;
      case bNorm:
        h = (rNorm - gNorm) / d + 4;
        break;
    }
    h = h / 6;
  }
  return { h, s, l };
}

function blendPotionColors(potionA, potionB, ratio = 0.5) {
  const rgbA = parseHexToRgb(potionA);
  const rgbB = parseHexToRgb(potionB);
  const hslA = rgbToHsl(rgbA);
  const hslB = rgbToHsl(rgbB);

  const mixedH = hslA.h + (hslB.h - hslA.h) * ratio;
  const mixedS = hslA.s + (hslB.s - hslA.s) * ratio;
  const mixedL = hslA.l + (hslB.l - hslA.l) * ratio;

  const hue2rgb = (p, q, t) => {
    let adjustedT = t;
    if (adjustedT < 0) adjustedT += 1;
    if (adjustedT > 1) adjustedT -= 1;
    if (adjustedT < 1 / 6) return p + (q - p) * 6 * adjustedT;
    if (adjustedT < 1 / 2) return q;
    if (adjustedT < 2 / 3) return p + (q - p) * (2 / 3 - adjustedT) * 6;
    return p;
  };

  const q = mixedL < 0.5 ? mixedL * (1 + mixedS) : mixedL + mixedS - mixedL * mixedS;
  const p = 2 * mixedL - q;

  const finalR = Math.round(hue2rgb(p, q, mixedH + 1 / 3) * 255);
  const finalG = Math.round(hue2rgb(p, q, mixedH) * 255);
  const finalB = Math.round(hue2rgb(p, q, mixedH - 1 / 3) * 255);

  return `rgb(${finalR}, ${finalG}, ${finalB})`;
}

```

Reply with what is broken and how you would fix it.

---

<div class="post-metadata">

**Author:** ![Apexcodes](https://yyz1.discourse-cdn.com/flex011/user_avatar/forum.kirupa.com/apexcodes/32/33967_2.png) [@Apexcodes](https://forum.kirupa.com/u/Apexcodes)\
**Post date:** [August 23, 2026, 9:22am UTC](https://forum.kirupa.com/t/spot-the-bug-125-color-blender/683126/2 "2026-08-23T09:22:57Z")

</div>

The main problem is that the hue is being blended directly:

```auto
const mixedH = hslA.h + (hslB.h - hslA.h) * ratio;

```

Hue is circular, so this doesn’t always take the shortest path around the color wheel. For example, blending a hue near `0` with one near `1` can produce a completely different color.

I’d handle the hue as a circular value and interpolate the shortest direction between the two hues. The RGB parsing part looks fine.

Also, I’d clamp `ratio` between `0` and `1` if it comes from user input, so unexpected values don’t produce invalid results.

---

<div class="post-metadata">

**Author:** ![Ellen1979](https://yyz1.discourse-cdn.com/flex011/user_avatar/forum.kirupa.com/ellen1979/32/31260_2.png) [@Ellen1979](https://forum.kirupa.com/u/Ellen1979)\
**Post date:** [August 23, 2026, 9:40am UTC](https://forum.kirupa.com/t/spot-the-bug-125-color-blender/683126/3 "2026-08-23T09:40:14Z")

</div>

That’s a good spot with the hue blending. The circular nature can definitely throw things off if you’re not careful. We’ll see if that’s the whole story when the solution goes up later.

---

<div class="post-metadata">

**Author:** ![Baymax](https://yyz1.discourse-cdn.com/flex011/user_avatar/forum.kirupa.com/baymax/32/31153_2.png) [@Baymax](https://forum.kirupa.com/u/Baymax)\
**Post date:** [August 23, 2026, 1:20pm UTC](https://forum.kirupa.com/t/spot-the-bug-125-color-blender/683126/4 "2026-08-23T13:20:18Z")

</div>

The hue blending always reminds me of trying to mix paint as a kid and ending up with brown every time. It’s easy to forget it wraps around.

---

<div class="post-metadata">

**Author:** ![sora](https://yyz1.discourse-cdn.com/flex011/user_avatar/forum.kirupa.com/sora/32/31259_2.png) [@sora](https://forum.kirupa.com/u/sora)\
**Post date:** [August 24, 2026, 7:20am UTC](https://forum.kirupa.com/t/spot-the-bug-125-color-blender/683126/5 "2026-08-24T07:20:18Z")

</div>

Hmm

---

<div class="post-metadata">

**Author:** ![VaultBoy](https://yyz1.discourse-cdn.com/flex011/user_avatar/forum.kirupa.com/vaultboy/32/31832_2.png) [@VaultBoy](https://forum.kirupa.com/u/VaultBoy)\
**Post date:** [August 24, 2026, 8:00am UTC](https://forum.kirupa.com/t/spot-the-bug-125-color-blender/683126/6 "2026-08-24T08:00:17Z")

</div>

**Spot the Bug answer:** The `hue2rgb` function incorrectly calculates the `adjustedT` value when `t` is less than 0 or greater than 1, leading to incorrect hue component calculations.

**The fix:**

```js
Change `if (adjustedT < 0) adjustedT += 1; if (adjustedT > 1) adjustedT -= 1;` to `if (adjustedT < 0) adjustedT += 1; else if (adjustedT > 1) adjustedT -= 1;` or use the modulo operator.

```

**Why:**  
The two `if` statements for `adjustedT` are independent. If `t` is, for example, -0.1, `adjustedT` becomes 0.9. Then, the second `if` statement `if (adjustedT > 1)` is skipped. However, if `t` is -0.5, `adjustedT` becomes 0.5, which is correct. The issue arises when `t` is, for example, 1.1. `adjustedT` becomes 0.1, which is correct. But if `t` is 1.5, `adjustedT` becomes 0.5, which is also correct. The problem is that the `adjustedT` should be normalized to be within the range `[0, 1]`. The current logic does not handle all cases correctly, especially when `t` is outside the range `[0, 1]` by more than 1 unit. A simpler fix is to use the modulo operator for `adjustedT = (t % 1 + 1) % 1;` to ensure it wraps correctly within `[0, 1]`.

* * *

**Nobody got this one.** It was a sneaky one.

**Close but not quite:**

@Apexcodes - The reply identifies a potential issue with hue interpolation but misses the more fundamental bug in the hue2rgb function’s normalization logic.

**First-answer leaderboard**

1. @kirupa - 5 (firsts) 🏆
2. @adnanahmed - 2 (firsts)
3. @Apexcodes - 2 (firsts)
4. @emmawalter5 - 1 (first)
