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 [];

  // If they requested <= number of stops, return the stops (like upstream).
  if (steps <= stops.length) {
    return stops.take(steps).toList(growable: false);
  }

  final rgbStops = <cp.Rgb>[];
  for (final c in stops) {
    final rgb = _toRgb(c, 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);
  }

  final numSegments = rgbStops.length - 1;
  final defaultSize = steps ~/ numSegments;
  final remaining = steps % numSegments;

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

  var outIndex = 0;
  for (var i = 0; i < numSegments; i++) {
    final from = rgbStops[i];
    final to = rgbStops[i + 1];
    var segmentSize = defaultSize;
    if (i < remaining) segmentSize++;

    final divisor = segmentSize > 1 ? (segmentSize - 1) : 1;
    for (var j = 0; j < segmentSize; j++) {
      final t = segmentSize > 1 ? (j / divisor) : 0.0;
      final r = _lerp(from.r, to.r, t);
      final g = _lerp(from.g, to.g, t);
      final b = _lerp(from.b, to.b, t);
      out[outIndex++] = BasicColor(_hexFromRgb(r, g, b));
      if (outIndex >= steps) break;
    }
  }

  return out;
}