Replace example shows with numbered production shows and add sparkle flag
- Rename all show .txt files with NNN_ numeric prefix so order is explicit and controlled by filename (001_heartbeat_red through 006_party) - Drop HOME_SHOW special-casing from convert_all.py; show 0 is simply the lowest-numbered file - Add SHOW_FLAG_SPARKLE support: shows can declare '// flags: sparkle' to overlay random white flashes on top of the base color each frame - Wire sparkle into led_controller and config.h (SPARKLE_CHANCE/FRAMES) - Replace old placeholder/example shows with the six production shows Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -43,6 +43,14 @@
|
||||
|
||||
// -- Active pattern ------------------------------------------
|
||||
// Controls how the current color is mapped to the LEDs.
|
||||
// Only PATTERN_SOLID is included; see DETAILS.md for adding more.
|
||||
// See DETAILS.md for adding more patterns.
|
||||
#define PATTERN_SOLID 0
|
||||
#define ACTIVE_PATTERN PATTERN_SOLID
|
||||
|
||||
// -- Sparkle tuning ------------------------------------------
|
||||
// Applied to shows that have the SHOW_FLAG_SPARKLE flag set.
|
||||
// SPARKLE_CHANCE : 0–255 probability of a new sparkle each frame (~60fps).
|
||||
// 80 ≈ 31%, giving roughly 2–3 simultaneous sparkles on 60 LEDs.
|
||||
// SPARKLE_FRAMES : how many frames each sparkle stays white (1 frame ≈ 16ms).
|
||||
#define SPARKLE_CHANCE 80
|
||||
#define SPARKLE_FRAMES 6
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* 1 tap — next show
|
||||
* 2 taps — previous show
|
||||
* 3 taps — lights off (any tap or hold resumes)
|
||||
* hold — reset to show 0 (blue breath)
|
||||
* hold — reset to show 0 (red heartbeat)
|
||||
*
|
||||
* To add or update shows:
|
||||
* 1. Add or edit a .txt file in converter/shows/
|
||||
@@ -79,7 +79,7 @@ void setup() {
|
||||
s_button.setPressMs(800);
|
||||
s_button.attachClick([]() { load_show((s_show_index + 1) % SHOW_COUNT); });
|
||||
s_button.attachDoubleClick([]() { load_show((s_show_index + SHOW_COUNT - 1) % SHOW_COUNT); });
|
||||
s_button.attachMultiClick([]() { if (s_button.getNumberClicks() == 3) { s_lights_off = true; leds_apply_color(CRGB::Black); leds_show(); } });
|
||||
s_button.attachMultiClick([]() { if (s_button.getNumberClicks() == 3) { s_lights_off = true; leds_apply_color(CRGB::Black, false); leds_show(); } });
|
||||
s_button.attachLongPressStart([]() { load_show(0); });
|
||||
}
|
||||
|
||||
@@ -97,7 +97,8 @@ void loop() {
|
||||
CRGB to = CRGB(step.r, step.g, step.b);
|
||||
uint8_t t8 = step_progress(step, now);
|
||||
|
||||
leds_apply_color(blend(s_from_color, to, t8));
|
||||
bool sparkle = (s_show.flags & SHOW_FLAG_SPARKLE) != 0;
|
||||
leds_apply_color(blend(s_from_color, to, t8), sparkle);
|
||||
leds_show();
|
||||
|
||||
if (t8 == 255) advance_step(to, now);
|
||||
|
||||
@@ -10,14 +10,21 @@ void leds_begin() {
|
||||
FastLED.clear(true); // clear + show: strip starts fully off
|
||||
}
|
||||
|
||||
void leds_apply_color(CRGB color) {
|
||||
void leds_apply_color(CRGB color, bool sparkle) {
|
||||
#if ACTIVE_PATTERN == PATTERN_SOLID
|
||||
// All LEDs show the same color.
|
||||
fill_solid(leds, NUM_LEDS, color);
|
||||
|
||||
// To add a new pattern, add a new #define in config.h and a new branch here.
|
||||
// The pattern receives 'leds', 'NUM_LEDS', and the blended 'color' for this frame.
|
||||
#endif
|
||||
if (!sparkle) return;
|
||||
static uint8_t sparkle_timer[NUM_LEDS];
|
||||
if (random8() < SPARKLE_CHANCE) {
|
||||
sparkle_timer[random8(NUM_LEDS)] = SPARKLE_FRAMES;
|
||||
}
|
||||
for (uint8_t i = 0; i < NUM_LEDS; i++) {
|
||||
if (sparkle_timer[i] > 0) {
|
||||
leds[i] = CRGB::White;
|
||||
sparkle_timer[i]--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void leds_show() {
|
||||
|
||||
@@ -7,8 +7,9 @@
|
||||
void leds_begin();
|
||||
|
||||
// Apply 'color' to all LEDs using the pattern defined in config.h (ACTIVE_PATTERN).
|
||||
// If 'sparkle' is true, randomly flash individual LEDs white on top of the base fill.
|
||||
// Call leds_show() afterwards to push the update to the physical strip.
|
||||
void leds_apply_color(CRGB color);
|
||||
void leds_apply_color(CRGB color, bool sparkle = false);
|
||||
|
||||
// Flush the LED buffer to the physical strip. Call once per frame after leds_apply_color().
|
||||
void leds_show();
|
||||
|
||||
@@ -16,6 +16,9 @@
|
||||
#define SHOW_LOOP 0 // repeat the show indefinitely
|
||||
#define SHOW_SINGLE 1 // play once, then auto-advance to the next show
|
||||
|
||||
// Show flags (bitfield for ShowDef.flags).
|
||||
#define SHOW_FLAG_SPARKLE 0x01 // overlay random white sparkles on this show
|
||||
|
||||
// One step in a lightshow: a target color and the time to reach it.
|
||||
struct Step {
|
||||
uint8_t r, g, b; // Target RGB color (0–255 each)
|
||||
@@ -27,6 +30,7 @@ struct ShowDef {
|
||||
const Step* steps; // Pointer to a PROGMEM Step array
|
||||
uint16_t length; // Number of steps in the array
|
||||
uint8_t mode; // SHOW_LOOP or SHOW_SINGLE
|
||||
uint8_t flags; // Bitfield: see SHOW_FLAG_* above
|
||||
};
|
||||
|
||||
// Read one Step from PROGMEM into a regular struct.
|
||||
@@ -47,5 +51,6 @@ inline ShowDef read_show_def(const ShowDef* ptr) {
|
||||
sd.steps = (const Step*)pgm_read_word(&ptr->steps);
|
||||
sd.length = pgm_read_word(&ptr->length);
|
||||
sd.mode = pgm_read_byte(&ptr->mode);
|
||||
sd.flags = pgm_read_byte(&ptr->flags);
|
||||
return sd;
|
||||
}
|
||||
+6
-7
@@ -1,24 +1,23 @@
|
||||
// Generated by convert_all.py from: 001_heartbeat.txt
|
||||
// Generated by convert_all.py from: 001_heartbeat_red.txt
|
||||
// Do not edit manually — edit the .txt file and run: make shows
|
||||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
#pragma once
|
||||
#include "lightshow_format.h"
|
||||
|
||||
const Step SHOW_001_HEARTBEAT[] PROGMEM = {
|
||||
const Step SHOW_001_HEARTBEAT_RED[] PROGMEM = {
|
||||
{ 5, 0, 0, 0}, // #050000, 0ms
|
||||
{209, 14, 41, 120}, // #D10E29, 120ms
|
||||
{ 48, 0, 0, 100}, // #300000, 100ms
|
||||
{209, 14, 41, 100}, // #D10E29, 100ms
|
||||
{ 5, 0, 0, 700}, // #050000, 700ms
|
||||
{ 5, 0, 0, 600}, // #050000, 600ms
|
||||
{209, 14, 41, 120}, // #D10E29, 120ms
|
||||
{ 48, 0, 0, 100}, // #300000, 100ms
|
||||
{209, 14, 41, 100}, // #D10E29, 100ms
|
||||
{ 5, 0, 0, 700}, // #050000, 700ms
|
||||
{ 5, 0, 0, 600}, // #050000, 600ms
|
||||
{209, 14, 41, 120}, // #D10E29, 120ms
|
||||
{ 48, 0, 0, 100}, // #300000, 100ms
|
||||
{209, 14, 41, 100}, // #D10E29, 100ms
|
||||
{ 5, 0, 0, 700}, // #050000, 700ms
|
||||
{153, 40, 58, 2000}, // #99283A, 2000ms
|
||||
{ 5, 0, 0, 600}, // #050000, 600ms
|
||||
};
|
||||
const uint16_t SHOW_001_HEARTBEAT_LENGTH = 14;
|
||||
const uint16_t SHOW_001_HEARTBEAT_RED_LENGTH = 13;
|
||||
@@ -1,13 +0,0 @@
|
||||
// Generated by convert_all.py from: 002_breath_red.txt
|
||||
// Do not edit manually — edit the .txt file and run: make shows
|
||||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
#pragma once
|
||||
#include "lightshow_format.h"
|
||||
|
||||
const Step SHOW_002_BREATH_RED[] PROGMEM = {
|
||||
{153, 40, 58, 0}, // #99283A, 0ms
|
||||
{217, 30, 30, 2500}, // #D91E1E, 2500ms
|
||||
{153, 40, 58, 2500}, // #99283A, 2500ms
|
||||
};
|
||||
const uint16_t SHOW_002_BREATH_RED_LENGTH = 3;
|
||||
@@ -0,0 +1,12 @@
|
||||
// Generated by convert_all.py from: 002_heartbeat_breathe.txt
|
||||
// Do not edit manually — edit the .txt file and run: make shows
|
||||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
#pragma once
|
||||
#include "lightshow_format.h"
|
||||
|
||||
const Step SHOW_002_HEARTBEAT_BREATHE[] PROGMEM = {
|
||||
{209, 14, 41, 3600}, // #D10E29, 3600ms
|
||||
{ 5, 0, 0, 3600}, // #050000, 3600ms
|
||||
};
|
||||
const uint16_t SHOW_002_HEARTBEAT_BREATHE_LENGTH = 2;
|
||||
+3
-3
@@ -1,15 +1,15 @@
|
||||
// Generated by convert_all.py from: blue_breath.txt
|
||||
// Generated by convert_all.py from: 003_blue_sparkle.txt
|
||||
// Do not edit manually — edit the .txt file and run: make shows
|
||||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
#pragma once
|
||||
#include "lightshow_format.h"
|
||||
|
||||
const Step SHOW_BLUE_BREATH[] PROGMEM = {
|
||||
const Step SHOW_003_BLUE_SPARKLE[] PROGMEM = {
|
||||
{ 5, 0, 24, 0}, // #050018, 0ms
|
||||
{ 32, 32, 255, 2500}, // #2020FF, 2500ms
|
||||
{ 32, 32, 255, 400}, // #2020FF, 400ms
|
||||
{ 5, 0, 24, 2500}, // #050018, 2500ms
|
||||
{ 5, 0, 24, 800}, // #050018, 800ms
|
||||
};
|
||||
const uint16_t SHOW_BLUE_BREATH_LENGTH = 5;
|
||||
const uint16_t SHOW_003_BLUE_SPARKLE_LENGTH = 5;
|
||||
@@ -1,12 +0,0 @@
|
||||
// Generated by convert_all.py from: 003_solid_red.txt
|
||||
// Do not edit manually — edit the .txt file and run: make shows
|
||||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
#pragma once
|
||||
#include "lightshow_format.h"
|
||||
|
||||
const Step SHOW_003_SOLID_RED[] PROGMEM = {
|
||||
{153, 40, 58, 0}, // #99283A, 0ms
|
||||
{153, 40, 58, 30000}, // #99283A, 30000ms
|
||||
};
|
||||
const uint16_t SHOW_003_SOLID_RED_LENGTH = 2;
|
||||
@@ -0,0 +1,13 @@
|
||||
// Generated by convert_all.py from: 004_pulse_yellow.txt
|
||||
// Do not edit manually — edit the .txt file and run: make shows
|
||||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
#pragma once
|
||||
#include "lightshow_format.h"
|
||||
|
||||
const Step SHOW_004_PULSE_YELLOW[] PROGMEM = {
|
||||
{ 32, 32, 0, 0}, // #202000, 0ms
|
||||
{255, 255, 0, 1200}, // #FFFF00, 1200ms
|
||||
{ 32, 32, 0, 1200}, // #202000, 1200ms
|
||||
};
|
||||
const uint16_t SHOW_004_PULSE_YELLOW_LENGTH = 3;
|
||||
@@ -0,0 +1,12 @@
|
||||
// Generated by convert_all.py from: 005_green_static.txt
|
||||
// Do not edit manually — edit the .txt file and run: make shows
|
||||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
#pragma once
|
||||
#include "lightshow_format.h"
|
||||
|
||||
const Step SHOW_005_GREEN_STATIC[] PROGMEM = {
|
||||
{ 0, 204, 0, 0}, // #00CC00, 0ms
|
||||
{ 0, 204, 0, 5000}, // #00CC00, 5000ms
|
||||
};
|
||||
const uint16_t SHOW_005_GREEN_STATIC_LENGTH = 2;
|
||||
+3
-3
@@ -1,11 +1,11 @@
|
||||
// Generated by convert_all.py from: example_party.txt
|
||||
// Generated by convert_all.py from: 006_party.txt
|
||||
// Do not edit manually — edit the .txt file and run: make shows
|
||||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
#pragma once
|
||||
#include "lightshow_format.h"
|
||||
|
||||
const Step SHOW_EXAMPLE_PARTY[] PROGMEM = {
|
||||
const Step SHOW_006_PARTY[] PROGMEM = {
|
||||
{255, 0, 0, 0}, // #FF0000, 0ms
|
||||
{255, 0, 0, 150}, // #FF0000, 150ms
|
||||
{255, 136, 0, 0}, // #FF8800, 0ms
|
||||
@@ -24,4 +24,4 @@ const Step SHOW_EXAMPLE_PARTY[] PROGMEM = {
|
||||
{255, 255, 255, 150}, // #FFFFFF, 150ms
|
||||
{ 0, 0, 0, 500}, // #000000, 500ms
|
||||
};
|
||||
const uint16_t SHOW_EXAMPLE_PARTY_LENGTH = 17;
|
||||
const uint16_t SHOW_006_PARTY_LENGTH = 17;
|
||||
@@ -1,16 +0,0 @@
|
||||
// Generated by convert_all.py from: example_fade.txt
|
||||
// Do not edit manually — edit the .txt file and run: make shows
|
||||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
#pragma once
|
||||
#include "lightshow_format.h"
|
||||
|
||||
const Step SHOW_EXAMPLE_FADE[] PROGMEM = {
|
||||
{255, 0, 0, 0}, // #FF0000, 0ms
|
||||
{ 0, 255, 0, 3000}, // #00FF00, 3000ms
|
||||
{ 0, 0, 255, 0}, // #0000FF, 0ms
|
||||
{255, 0, 255, 2000}, // #FF00FF, 2000ms
|
||||
{255, 128, 0, 1000}, // #FF8000, 1000ms
|
||||
{ 0, 0, 0, 5000}, // #000000, 5000ms
|
||||
};
|
||||
const uint16_t SHOW_EXAMPLE_FADE_LENGTH = 6;
|
||||
@@ -1,13 +0,0 @@
|
||||
// Generated by convert_all.py from: example_pulse.txt
|
||||
// Do not edit manually — edit the .txt file and run: make shows
|
||||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
#pragma once
|
||||
#include "lightshow_format.h"
|
||||
|
||||
const Step SHOW_EXAMPLE_PULSE[] PROGMEM = {
|
||||
{ 32, 0, 0, 0}, // #200000, 0ms
|
||||
{255, 0, 0, 1200}, // #FF0000, 1200ms
|
||||
{ 32, 0, 0, 1200}, // #200000, 1200ms
|
||||
};
|
||||
const uint16_t SHOW_EXAMPLE_PULSE_LENGTH = 3;
|
||||
@@ -1,10 +1,10 @@
|
||||
// =====================================================================
|
||||
// shows.h — Master show index.
|
||||
// Generated by: make shows (converter/convert_all.py)
|
||||
// Do not edit manually — add .txt files to converter/shows/ instead.
|
||||
// Do not edit manually — add NNN_<name>.txt files to converter/shows/ instead.
|
||||
// =====================================================================
|
||||
//
|
||||
// Show 0 is always the home/reset show (blue breath).
|
||||
// Show 0 is the lowest-numbered .txt file (home/reset show).
|
||||
// Holding the button resets back to show 0.
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
@@ -13,23 +13,21 @@
|
||||
#include "lightshow_format.h"
|
||||
|
||||
// ---- Individual show data ----------------------------------------------
|
||||
#include "show_blue_breath.h"
|
||||
#include "show_001_heartbeat.h"
|
||||
#include "show_002_breath_red.h"
|
||||
#include "show_003_solid_red.h"
|
||||
#include "show_example_fade.h"
|
||||
#include "show_example_party.h"
|
||||
#include "show_example_pulse.h"
|
||||
#include "show_001_heartbeat_red.h"
|
||||
#include "show_002_heartbeat_breathe.h"
|
||||
#include "show_003_blue_sparkle.h"
|
||||
#include "show_004_pulse_yellow.h"
|
||||
#include "show_005_green_static.h"
|
||||
#include "show_006_party.h"
|
||||
|
||||
// ---- Show index (PROGMEM) ----------------------------------------------
|
||||
const ShowDef SHOWS[] PROGMEM = {
|
||||
{SHOW_BLUE_BREATH, SHOW_BLUE_BREATH_LENGTH, SHOW_LOOP}, // 0 — home show
|
||||
{SHOW_001_HEARTBEAT, SHOW_001_HEARTBEAT_LENGTH, SHOW_SINGLE}, // 1
|
||||
{SHOW_002_BREATH_RED, SHOW_002_BREATH_RED_LENGTH, SHOW_LOOP}, // 2
|
||||
{SHOW_003_SOLID_RED, SHOW_003_SOLID_RED_LENGTH, SHOW_LOOP}, // 3
|
||||
{SHOW_EXAMPLE_FADE, SHOW_EXAMPLE_FADE_LENGTH, SHOW_LOOP}, // 4
|
||||
{SHOW_EXAMPLE_PARTY, SHOW_EXAMPLE_PARTY_LENGTH, SHOW_LOOP}, // 5
|
||||
{SHOW_EXAMPLE_PULSE, SHOW_EXAMPLE_PULSE_LENGTH, SHOW_LOOP}, // 6
|
||||
{SHOW_001_HEARTBEAT_RED, SHOW_001_HEARTBEAT_RED_LENGTH, SHOW_SINGLE, 0}, // 0 — home show
|
||||
{SHOW_002_HEARTBEAT_BREATHE, SHOW_002_HEARTBEAT_BREATHE_LENGTH, SHOW_LOOP, 0}, // 1
|
||||
{SHOW_003_BLUE_SPARKLE, SHOW_003_BLUE_SPARKLE_LENGTH, SHOW_LOOP, SHOW_FLAG_SPARKLE}, // 2
|
||||
{SHOW_004_PULSE_YELLOW, SHOW_004_PULSE_YELLOW_LENGTH, SHOW_LOOP, 0}, // 3
|
||||
{SHOW_005_GREEN_STATIC, SHOW_005_GREEN_STATIC_LENGTH, SHOW_LOOP, 0}, // 4
|
||||
{SHOW_006_PARTY, SHOW_006_PARTY_LENGTH, SHOW_SINGLE, 0}, // 5
|
||||
};
|
||||
|
||||
const uint8_t SHOW_COUNT = 7;
|
||||
const uint8_t SHOW_COUNT = 6;
|
||||
|
||||
Reference in New Issue
Block a user