cookbook/recipes/waves.md
Difficulty Level: ⭐⭐ Intermediate Time to Complete: 35-45 minutes Prerequisites:
You'll Learn:
Various wave effects including sine waves, color waves, and ocean-inspired patterns.
Basic sine wave pattern moving along the strip:
void sineWave() {
static uint8_t phase = 0;
for (int i = 0; i < NUM_LEDS; i++) {
// Calculate sine wave brightness for each LED
uint8_t brightness = sin8(phase + (i * 255 / NUM_LEDS));
leds[i] = CHSV(160, 255, brightness);
}
phase += 4; // Wave speed
}
Wave of changing colors traveling along the strip:
void colorWave() {
static uint8_t hue = 0;
for (int i = 0; i < NUM_LEDS; i++) {
// Each LED gets a different hue based on position
uint8_t ledHue = hue + (i * 10);
leds[i] = CHSV(ledHue, 255, 255);
}
hue++; // Shift colors
}
Combine three waves with different speeds and phases:
void multiWave() {
for (int i = 0; i < NUM_LEDS; i++) {
// Combine three waves with different speeds and phases
uint8_t wave1 = sin8(millis() / 10 + i * 8);
uint8_t wave2 = sin8(millis() / 20 + i * 12);
uint8_t wave3 = sin8(millis() / 30 + i * 16);
uint8_t combined = (wave1 + wave2 + wave3) / 3;
leds[i] = CHSV(combined, 255, 255);
}
}
Complex ocean wave simulation with multiple layers:
void pacifica() {
// Four layers of waves
pacifica_one_layer(1, 26, 100, 11);
pacifica_one_layer(2, 13, 65, 17);
pacifica_one_layer(3, 8, 43, 23);
pacifica_one_layer(4, 5, 28, 29);
// Add whitecaps
pacifica_add_whitecaps();
// Deepen colors
pacifica_deepen_colors();
}
void pacifica_one_layer(uint8_t layer, uint16_t speed, uint8_t scale, uint8_t offset) {
uint16_t dataOffset = layer * NUM_LEDS;
for (int i = 0; i < NUM_LEDS; i++) {
uint16_t angle = (millis() / speed) + (i * scale) + offset;
uint8_t level = sin8(angle) / 2 + 127;
leds[i] += CHSV(200, 255, level); // Blue-green
}
}
void pacifica_add_whitecaps() {
uint8_t basethreshold = beatsin8(9, 55, 65);
for (int i = 0; i < NUM_LEDS; i++) {
uint8_t threshold = basethreshold + (i * 2);
if (leds[i].blue > threshold) {
uint8_t overage = leds[i].blue - threshold;
leds[i] += CRGB(overage, overage, overage);
}
}
}
void pacifica_deepen_colors() {
for (int i = 0; i < NUM_LEDS; i++) {
leds[i].blue = scale8(leds[i].blue, 145);
leds[i].green = scale8(leds[i].green, 200);
}
}
Expanding ripples from a center point:
int center = NUM_LEDS / 2;
uint8_t maxDistance = NUM_LEDS / 2;
void ripple() {
static uint8_t wavePos = 0;
fadeToBlackBy(leds, NUM_LEDS, 10);
for (int i = 0; i < NUM_LEDS; i++) {
// Distance from center
uint8_t distance = abs(i - center);
// Create ripple
if (distance == wavePos || distance == wavePos - 5) {
leds[i] = CHSV(160, 255, 255);
}
}
wavePos++;
if (wavePos >= maxDistance) wavePos = 0;
}
Wave patterns use trigonometric functions to create smooth, flowing motion:
Sine Wave Components:
Wave Frequency:
Smooth scanner:
void loop() {
static uint8_t pos = 0;
for (int i = 0; i < NUM_LEDS; i++) {
int distance = abs(i - pos);
uint8_t brightness = qadd8(sin8((255 / NUM_LEDS) * distance), 50);
leds[i] = CHSV(0, 255, brightness);
}
pos++;
if (pos >= NUM_LEDS) pos = 0;
FastLED.show();
delay(20);
}
Pride wave:
void pride() {
static uint16_t sPseudotime = 0;
static uint16_t sLastMillis = 0;
static uint16_t sHue16 = 0;
uint8_t sat8 = beatsin88(87, 220, 250);
uint8_t brightdepth = beatsin88(341, 96, 224);
uint16_t brightnessthetainc16 = beatsin88(203, (25 * 256), (40 * 256));
uint8_t msmultiplier = beatsin88(147, 23, 60);
uint16_t hue16 = sHue16;
uint16_t hueinc16 = beatsin88(113, 1, 3000);
uint16_t ms = millis();
uint16_t deltams = ms - sLastMillis;
sLastMillis = ms;
sPseudotime += deltams * msmultiplier;
sHue16 += deltams * beatsin88(400, 5, 9);
uint16_t brightnesstheta16 = sPseudotime;
for (uint16_t i = 0; i < NUM_LEDS; i++) {
hue16 += hueinc16;
uint8_t hue8 = hue16 / 256;
brightnesstheta16 += brightnessthetainc16;
uint16_t b16 = sin16(brightnesstheta16) + 32768;
uint16_t bri16 = (uint32_t)((uint32_t)b16 * (uint32_t)b16) / 65536;
uint8_t bri8 = (uint32_t)(((uint32_t)bri16) * brightdepth) / 65536;
bri8 += (255 - brightdepth);
CRGB newcolor = CHSV(hue8, sat8, bri8);
uint16_t pixelnumber = i;
pixelnumber = (NUM_LEDS - 1) - pixelnumber;
nblend(leds[pixelnumber], newcolor, 64);
}
}
Dual Wave:
void dualWave() {
static uint8_t phase = 0;
for (int i = 0; i < NUM_LEDS; i++) {
uint8_t wave1 = sin8(phase + (i * 8));
uint8_t wave2 = sin8(phase + (i * 16) + 128); // Offset phase
leds[i] = CHSV(wave1, 255, wave2);
}
phase += 2;
}
Plasma Wave:
void plasma() {
static uint8_t time_offset = 0;
for (int i = 0; i < NUM_LEDS; i++) {
uint8_t val1 = sin8(time_offset + i * 8);
uint8_t val2 = sin8(time_offset * 2 + i * 4);
uint8_t val3 = sin8(time_offset / 2 + i * 16);
uint8_t combined = (val1 + val2 + val3) / 3;
leds[i] = CHSV(combined, 255, 255);
}
time_offset++;
}
Traveling Peaks:
void travelingPeaks() {
static uint8_t peak1 = 0;
static uint8_t peak2 = NUM_LEDS / 2;
fadeToBlackBy(leds, NUM_LEDS, 20);
// Draw peaks with falloff
for (int i = 0; i < NUM_LEDS; i++) {
int dist1 = abs(i - peak1);
int dist2 = abs(i - peak2);
uint8_t brightness = qadd8(
qsub8(255, dist1 * 20),
qsub8(255, dist2 * 20)
);
leds[i] += CHSV(160, 255, brightness);
}
peak1 = (peak1 + 1) % NUM_LEDS;
peak2 = (peak2 + 1) % NUM_LEDS;
}
sin8() instead of sin() for better performancefadeToBlackBy() with waves for trail effectsmillis() for time-based animation that doesn't depend on frame rate