A tiny HSL theme helper that keeps contrast from going off the rails

Hey folks, I’m working on a white-label UI where product keeps asking for “just one more theme,” and I’m trying to avoid shipping 12 hand-tuned palettes that drift over time. The failure mode I keep hitting is gradients that look nice but end up with unreadable text on one stop.

const clamp = (n, a, b) => Math.min(b, Math.max(a, n));

export function themeFromHue(hue, mode = "light") {
  const bgL = mode === "light" ? 97 : 10;
  const fgL = mode === "light" ? 12 : 92;

  const bg = `hsl(${hue} 25% ${bgL}%)`;
  const fg = `hsl(${hue} 15% ${fgL}%)`;

  const accentS = mode === "light" ? 75 : 70;
  const accentL = mode === "light" ? 45 : 60;
  const accent = `hsl(${hue} ${accentS}% ${accentL}%)`;

  const accent2 = `hsl(${(hue + 35) % 360} ${clamp(accentS - 10, 0, 100)}% ${clamp(accentL + (mode === "light" ? 8 : -8), 0, 100)}%)`;

  const gradient = `linear-gradient(135deg, ${accent}, ${accent2})`;

  return { bg, fg, accent, accent2, gradient };
}

Neat part is it gives design a “palette knob” (hue) while keeping the rest predictable, so the product tradeoff is fewer bespoke themes vs slightly less brand-perfect colors on edge cases.