To avoid confusion I did not want to include whole project and decided to include only a snipped that was relevant to the question. My project consists of 30+ .cpp and .h files. Unfortunately I am not able to upload files here and I am hesitant to make my github repository public. To provide an example at least, I will try to paste some code here but without project in whole they may not provide full picture or my "vision". 
// selects animation (factory that creates animation sequence) based on the pin jumpers
class PinAnimationFactory : public IAnimationFactory
{
private:
IAnimationFactory* factories[3] = {
new ThanksgivingAnimationFactory(),
new NewYearAnimationFactory(),
new HalloweenAnimationFactory()
};
public:
PinAnimationFactory()
{
pinMode(FIRST_PIN, INPUT_PULLUP);
pinMode(SECOND_PIN, INPUT_PULLUP);
pinMode(THIRD_PIN, INPUT_PULLUP);
}
IAnimation* create()
{
uint8_t val = (!digitalRead(FIRST_PIN) << 2) | (!digitalRead(SECOND_PIN) << 1) | !digitalRead(THIRD_PIN);
Serial.print("Creating Animation: ");
Serial.println(val);
if (val >= 0 && val <= 1) {
IAnimationFactory* f = factories[val];
return f->create();
}
return new SolidColorAnimation(CRGB::White);
};
};
// creates thanksgiving animation sequence
class ThanksgivingAnimationFactory : public IAnimationFactory
{
private:
const CRGB brightRed = CRGB(255,0,0);
const CRGB lightRed = CRGB(40,25,35);
const CRGB darkRed = CRGB(50, 0, 0);
const CRGB brightOrange = CRGB(255,100,25);
const CRGB white = CRGB(217,211,250);
const CRGB gray = CRGB(90,90,90);
const CRGB darkGray = CRGB(30,30,30);
const CRGB brightGold= CRGB(255,200,25);
const CRGB darkGold = CRGB(50,40,0);
const CRGBPalette16 palette =
{
brightRed, gray, lightRed, gray,
lightRed, gray, darkGold, gray,
brightOrange, gray, white, gray,
brightGold, gray, darkGold, gray
};
IAnimationFactory* effects[5] = {
(new TwinkleEffectFactory())->setColors(lightRed, brightOrange)->setTiming(250,2000,750,2000)->setFillPct(80),
(new TwoColorFactory())->setColors(CRGB::DimGray, brightGold, brightOrange)->setTiming(100, 1000)->setColorSize(2, true),
(new SparkleAnimationFactory())->setColors(darkGold, CRGB::Gray),
(new TwinkleEffectFactory())->setColors(CRGB::DimGray, brightGold)->setTiming(750,1000,750,100)->setFillPct(80),
(new PaletteWaveFactory())->setSpeed(200)->setPalette(palette)
};
public:
IAnimation* create()
{
return new SequenceAnimation(effects, ARRAY_SIZE(effects), ANIMATION_DURATION_MS, ANIMATION_TRANSITION_MS);
};
};
// SequenceAnimation handles sequence and cross fade transitions between effects
void SequenceAnimation::attach(LedStrip* strip)
{
mainStrip = strip;
currentAnimation = getNextFactory()->create();
if (currentAnimation == NULL)
return;
currentStrip = mainStrip->createVirtual();
currentAnimation->attach(currentStrip);
}
void SequenceAnimation::detach()
{
if (currentAnimation != NULL) { currentAnimation->detach(); delete currentAnimation; currentAnimation = NULL; }
if (nextAnimation != NULL) { nextAnimation->detach(); delete nextAnimation; nextAnimation = NULL; }
if (currentStrip != NULL) { delete currentStrip; currentStrip = NULL; }
if (nextStrip != NULL) { delete nextStrip; nextStrip = NULL; }
this->mainStrip = NULL;
}
void SequenceAnimation::draw()
{
if (mainStrip == NULL || currentAnimation == NULL)
return;
unsigned long currentTime = millis();
uint8_t currentIndex = (currentTime / animationLength) % 2;
uint8_t newIndex = ((currentTime + crossFadeLength) / animationLength) % 2;
if (currentIndex != newIndex)
{
if (nextAnimation == NULL)
{
nextAnimation = getNextFactory()->create();
if (nextAnimation == NULL)
return;
nextStrip = mainStrip->createVirtual();
nextAnimation->attach(nextStrip);
}
currentAnimation->draw();
nextAnimation->draw();
uint16_t transitionTime = (currentTime + crossFadeLength) % animationLength;
fract8 amt = transitionTime/(crossFadeLength / (float)256);
for(unsigned int i = 0; i < mainStrip->count; i++) {
mainStrip->leds[i]=blend(currentStrip->leds[i], nextStrip->leds[i], amt);
}
}
else
{
if (nextAnimation != NULL)
{
currentAnimation->detach();
delete currentAnimation;
delete currentStrip;
currentAnimation = nextAnimation;
currentStrip = nextStrip;
nextAnimation = NULL;
nextStrip = NULL;
currentIndex = newIndex;
}
currentAnimation->draw();
for(unsigned int i = 0; i < currentStrip->count; i++) {
mainStrip->leds[i] = currentStrip->leds[i];
}
}
}
class AnimationBase : public IAnimation
{
private:
bool firstFrame = true;
protected:
LedStrip* strip;
virtual void onDraw() = 0;
virtual void onAttach() { }
virtual void onDetach() { }
virtual void onFirstFrame() { }
public:
void attach(LedStrip* strip)
{
this->strip = strip;
firstFrame = true;
onAttach();
}
void detach()
{
onDetach();
this->strip = NULL;
}
void draw()
{
if (!strip)
return;
if (firstFrame)
onFirstFrame();
onDraw();
firstFrame = false;
}
virtual ~AnimationBase()
{
}
};
// effect that simply moves palette along the LED strip configurable with constructor parameters
class PaletteWaveAnimation : public AnimationBase
{
private:
CRGBPalette16 palette;
unsigned int startIndex;
TBlendType blendType;
uint8_t speed = 200;
public:
PaletteWaveAnimation(CRGBPalette16 palette, unsigned int speed, TBlendType blendType)
{
this->palette = palette;
this->blendType = blendType;
this->speed = speed;
startIndex = 0;
Serial.println("Create Palette Wave Effect");
}
void onAttach() override
{
startIndex = 0;
}
void onDraw()
{
uint8_t delay = 255 - speed;
EVERY_N_MILLISECONDS(delay) {
drawLeds();
};
}
void drawLeds()
{
int colorIndex = startIndex;
for( int i = 0; i < strip->count; i++) {
CRGB color = ColorFromPalette(palette, colorIndex, 255, blendType);
strip->leds[i] = color;
colorIndex += 3;
}
startIndex++;
}
};
My vision or aim really is to be able to setup animations quickly and clearly, using some kind of method chaining maybe and short of using video editor
. For example in pseudocode:
IAnimation* timeline = createTimeline()
.play(SparkleEffect(color1, color2), 60sec)
.transition(CrossFadeTransition(), 1000ms)
.play(RainbowPaletteEffect(), 30seconds)
.transition(DissolveTransition(), 500ms)
.play(SparkleEffect(color3, color4), 30sec)
.repeat(3times))
.play(createSomeOtherComplexTimeline())
//and so on and so forth
This would allow me to mix and match animations for different scenarios or occasions without worrying too much about inner workings. But I guess when I get to this point Arduino Mega will be stretched too thin. 