#include <FastLED.h>

#define NUM_LEDS 48
CRGB leds[NUM_LEDS];

void setup() {
  FastLED.addLeds<NEOPIXEL, PB1>(leds, NUM_LEDS);
}

CRGB pattern[] = {
 CRGB(255, 255, 255), CRGB(255, 255, 255),
 CRGB(255, 0, 0), CRGB(255, 0, 0),
 CRGB(0, 255, 0), CRGB(0, 255, 0),
 CRGB(0, 0, 255), CRGB(0, 0, 255),
};
size_t pattern_sz = sizeof(pattern) / sizeof(*pattern);

void loop() {
  // a 8.8 fixed point position (so 256 = 1.0, 512 = 2.0, 65535 = 255.996)
  static uint16_t basepos = 0;
  // a copy of basepos to be modified over the length of the strip
  uint16_t ledpos = basepos;
  for (uint8_t ledno = 0; ledno < NUM_LEDS; ledno++) {
    // find the integer and fractional parts for this LED 
    uint8_t intpos = ledpos >> 8;
    uint8_t fracpos = ledpos & 0xff;
    // select the two colours to be blended for this LED
    CRGB colA = pattern[intpos % pattern_sz];
    CRGB colB = pattern[(intpos + 1) % pattern_sz];
    // fade colA towards colB by the fractional position
    leds[ledno] = fadeTowardColor(colA, colB, fracpos);
    // move along the source pattern by some fraction of a pixel
    ledpos += 128;
  }
  FastLED.show();
  delay(10);
  // move the base position by some fractional amount
  basepos += beatsin8(5, 1, 128);
}


// Mark Kriegsman's fadeTowardColor from:
// https://gist.github.com/kriegsman/d0a5ed3c8f38c64adcb4837dafb6e690

// Helper function that blends one uint8_t toward another by a given amount
void nblendU8TowardU8( uint8_t& cur, const uint8_t target, uint8_t amount)
{
  if( cur == target) return;
  
  if( cur < target ) {
    uint8_t delta = target - cur;
    delta = scale8_video( delta, amount);
    cur += delta;
  } else {
    uint8_t delta = cur - target;
    delta = scale8_video( delta, amount);
    cur -= delta;
  }
}

// Blend one CRGB color toward another CRGB color by a given amount.
// Blending is linear, and done in the RGB color space.
// This function modifies 'cur' in place.
CRGB fadeTowardColor( CRGB& cur, const CRGB& target, uint8_t amount)
{
  nblendU8TowardU8( cur.red,   target.red,   amount);
  nblendU8TowardU8( cur.green, target.green, amount);
  nblendU8TowardU8( cur.blue,  target.blue,  amount);
  return cur;
}
ATTINY8520PU