blend1D function

List<Color> blend1D(
  1. int steps,
  2. List<Color> stops, {
  3. required bool hasDarkBackground,
})

Blends a series of Color stops into steps colors (1D gradient).

This is a minimal-first port of lipgloss v2 Blend1D, but uses simple RGB interpolation (rather than Lab) to avoid pulling in a large dependency.

If fewer than 2 blendable stops are provided, returns a list filled with the single stop (or empty if none are blendable).

Implementation

List<Color> blend1D(
  int steps,
  List<Color> stops, {
  required bool hasDarkBackground,
}) {
  if (steps < 0) steps = 0;
  if (steps == 0) return const [];
  if (stops.isEmpty) return const [];

  final rgbStops = <cp.Rgb>[];
  for (final c in stops) {
    final rgb = c.toRgb(hasDarkBackground: hasDarkBackground);
    if (rgb != null) rgbStops.add(rgb);
  }

  if (rgbStops.isEmpty) return const [];
  if (rgbStops.length == 1) {
    final single = _colorFromRgb(rgbStops[0]);
    return List<Color>.filled(steps, single, growable: false);
  }

  if (steps == 1) {
    return [_colorFromRgb(rgbStops.first)];
  }

  final out = List<Color>.filled(
    steps,
    _colorFromRgb(rgbStops.first),
    growable: false,
  );
  final maxPos = rgbStops.length - 1;

  for (var i = 0; i < steps; i++) {
    final pos = i / (steps - 1);
    final target = pos * maxPos;
    final leftIndex = target.floor().clamp(0, maxPos).toInt();
    final rightIndex = (leftIndex + 1).clamp(0, maxPos).toInt();
    final t = target - leftIndex;

    if (leftIndex == rightIndex) {
      out[i] = _colorFromRgb(rgbStops[leftIndex]);
      continue;
    }

    final from = rgbStops[leftIndex];
    final to = rgbStops[rightIndex];
    out[i] = BasicColor(
      _hexFromRgb(
        _lerp(from.r, to.r, t),
        _lerp(from.g, to.g, t),
        _lerp(from.b, to.b, t),
      ),
    );
  }

  return out;
}