#include <FastLED.h>
#define STRINGS 16
#define STRING_SIZE 16
#define NUM_LEDS (STRINGS * STRING_SIZE)
#define MATRIX_PIN 2
#define BRIGHTNESS 228 // Réduit légèrement pour économiser l'énergie (Max: 255)
#define SERPENTINE_LAYOUT true
CRGB leds[NUM_LEDS];
// Palettes de couleurs converties en tableaux fixes pour certaines animations
CRGB palette1[] = { CRGB(0xFF, 0xC0, 0xFF), CRGB(0xFF, 0x00, 0x00), CRGB(0x80, 0x00, 0x00), CRGB(0xCD, 0x5C, 0x5C) };
CRGB palette2[] = { CRGB(0x80, 0xFF, 0x80), CRGB(0x00, 0xFF, 0x00), CRGB(0x00, 0x80, 0x00), CRGB(0x55, 0x6B, 0x2F) };
CRGB palette3[] = { CRGB(0x80, 0xC0, 0xFF), CRGB(0x00, 0x00, 0xFF), CRGB(0xF0, 0xF8, 0xFF), CRGB(0x00, 0x00, 0x80) };
// Nombre total d'animations disponibles
#define TOTAL_EFFECTS 7
uint8_t currentEffect = 0;
void setup() {
Serial.begin(115200);
FastLED.addLeds<WS2812B, MATRIX_PIN, GRB>(leds, NUM_LEDS);
FastLED.setBrightness(BRIGHTNESS);
FastLED.clear();
FastLED.show();
}
void loop() {
// Alterne automatiquement d'effet toutes les 8 secondes sans bloquer le code
EVERY_N_SECONDS(8) {
currentEffect = (currentEffect + 1) % TOTAL_EFFECTS;
FastLED.clear();
}
// Exécute l'image (frame) de l'animation active
switch (currentEffect) {
case 0: helical_double_spiral();break;
/*
case 1: helical_spiral_reversed();break;
case 2: helical_spiral();break;
case 3: swirl_polar(); break;
case 4: perlin_plasma(); break;
case 5: wave_matrix(); break;
case 6: geometric_circles(); break;
case 7: modern_twinkle(); break;
case 8: pulse_everyone(); break;
case 9: rainbow_march(); break;
*/
}
// Affiche les changements à la vitesse maximale du processeur
FastLED.show();
}
// ==========================================
// 1. SWIRL POLAIRE (Effet Vortex/Spirale)
// ==========================================
void swirl_polar() {
uint32_t ms = millis();
for (int y = 0; y < STRING_SIZE; y++) {
for (int x = 0; x < STRINGS; x++) {
// Centrage des coordonnées au milieu de la matrice (7.5)
float dx = x - 7.5;
float dy = y - 7.5;
// Calcul des coordonnées polaires
uint8_t angle = atan2(dy, dx) * (128.0 / PI) + 128; // Angle de 0 à 255
uint8_t radius = sqrt(dx * dx + dy * dy) * 12; // Distance au centre
// Équation mathématique de la spirale temporelle
uint8_t hue = angle + (ms / 8) + (radius * 2);
int led_index = (y * STRINGS) + x;
leds[led_index] = CHSV(hue, 255, 255);
}
}
}
// ==========================================
// 2. PLASMA DE PERLIN (Fluide organique)
// ==========================================
void perlin_plasma() {
uint32_t speed = millis() / 5; // Vitesse d'évolution du fluide
for (int y = 0; y < STRING_SIZE; y++) {
for (int x = 0; x < STRINGS; x++) {
// Génère un bruit de Perlin 3D (X, Y, Temps) fluide et continu
uint8_t noise_val = inoise8(x * 35, y * 35, speed);
int led_index = (y * STRINGS) + x;
// Ajout d'un décalage sur la saturation pour donner du relief
leds[led_index] = CHSV(noise_val, 255, inoise8(y * 20, speed));
}
}
}
// ==========================================
// 3. VAGUES LINÉAIRES (The Algorithm réinventé)
// ==========================================
void wave_matrix() {
uint32_t ms = millis();
for (int y = 0; y < STRING_SIZE; y++) {
for (int x = 0; x < STRINGS; x++) {
// Crée une onde sinusoïdale croisée se déplaçant en diagonale
uint8_t wave = beatsin8(30, 0, 255, 0, x * 16) + beatsin8(15, 0, 255, 0, y * 16);
int led_index = (y * STRINGS) + x;
// Utilise l'onde pour mélanger du Bleu et du Cyan
leds[led_index] = CRGB(0, wave / 2, wave);
}
}
}
// ==========================================
// 4. CERCLES GÉOMÉTRIQUES CONCENTRIQUES
// ==========================================
void geometric_circles() {
uint32_t ms = millis();
for (int y = 0; y < STRING_SIZE; y++) {
for (int x = 0; x < STRINGS; x++) {
float dx = x - 7.5;
float dy = y - 7.5;
uint8_t radius = sqrt(dx * dx + dy * dy) * 16; // Distance pure au centre
// Crée des anneaux de lumière qui se déplacent vers l'extérieur
uint8_t intensity = quadwave8(radius - (ms / 4));
int led_index = (y * STRINGS) + x;
// Teinte évolutive dans le spectre Violet/Rose
leds[led_index] = CHSV(190 + (radius / 4), 255, intensity);
}
}
}
// ==========================================
// 5. TWINKLE FLUIDE (Scintillement étoilé)
// ==========================================
void modern_twinkle() {
// Atténue lentement toutes les LEDs existantes (effet de traînée/fade)
fadeToBlackBy(leds, NUM_LEDS, 15);
// Fait apparaître aléatoirement de nouvelles étoiles à intervalles réguliers
EVERY_N_MILLISECONDS(50) {
int pos = random16(NUM_LEDS);
// Assigne une couleur aléatoire issue de nos palettes stockées
uint8_t r = random8(3);
if (r == 0) leds[pos] = palette1[random8(4)];
else if (r == 1) leds[pos] = palette2[random8(4)];
else leds[pos] = palette3[random8(4)];
}
}
// ==========================================
// 6. PULSATION GLOBALE (Everyone réinventé)
// ==========================================
void pulse_everyone() {
// Génère une onde de luminosité globale fluide en fonction du temps (BPM de 40)
uint8_t pulse = beatsin8(40, 30, 255);
uint8_t hue = millis() / 50; // La couleur globale défile lentement
for (int i = 0; i < NUM_LEDS; i++) {
leds[i] = CHSV(hue + (i / 4), 255, pulse);
}
}
// ==========================================
// 7. RAINBOW MARCH (Défilement Arc-en-ciel)
// ==========================================
void rainbow_march() {
uint8_t change_speed = millis() / 20; // Vitesse de rotation des teintes
for (int y = 0; y < STRING_SIZE; y++) {
for (int x = 0; x < STRINGS; x++) {
int led_index = (y * STRINGS) + x;
// Le dégradé se base sur la colonne (X) pour tourner autour de la sphère
leds[led_index] = CHSV(change_speed + (x * 16), 255, 255);
}
}
}
// ==========================================
// ANIMATION : SPIRALE 3D (HÉLICE ARC-EN-CIEL)
// ==========================================
void helical_spiral() {
uint32_t ms = millis();
// Vitesse de rotation de la spirale (plus le diviseur est grand, plus c'est lent)
uint8_t time_offset = ms / 5;
// Épaisseur de la ligne de la spirale (ajustez pour avoir un trait plus net ou plus large)
uint8_t spiral_thickness = 20;
for (int y = 0; y < STRING_SIZE; y++) {
for (int x = 0; x < STRINGS; x++) {
// 1. Calcul de la position sur l'hélice
// On multiplie x et y pour donner l'angle d'inclinaison de la spirale
uint8_t angle = (x * 16) + (y * 16);
// 2. Détermination de l'intensité lumineuse de la LED
//beatsin8 ou une simple fonction sinus permet de créer une ligne propre
uint8_t intensity = qsub8(sin8(angle - time_offset), 255 - spiral_thickness);
// Si l'intensité est supérieure à 0, on allume avec une couleur dégradée
int led_index = (y * STRINGS) + x;
if (intensity > 0) {
// La couleur évolue en fonction de la hauteur (y) et du temps pour le dégradé
uint8_t hue = (y * 12) + time_offset;
leds[led_index] = CHSV(hue, 255, 255);
} else {
leds[led_index] = CRGB::Black; // Éteint pour créer le contraste de l'image
}
}
}
}
// ==========================================
// ANIMATION : SPIRALE 3D (ROTATION INVERSÉE)
// ==========================================
void helical_spiral_reversed() {
uint32_t ms = millis();
// Vitesse de rotation
uint8_t time_offset = ms / 5;
// Épaisseur du trait de la spirale
uint8_t spiral_thickness = 20;
for (int y = 0; y < STRING_SIZE; y++) {
for (int x = 0; x < STRINGS; x++) {
// Position sur l'hélice
uint8_t angle = (x * 16) + (y * 16);
// CHANGEMENT ICI : Le "+" inverse le sens de défilement temporel de l'onde
uint8_t intensity = qsub8(sin8(angle + time_offset), 255 - spiral_thickness);
int led_index = (y * STRINGS) + x;
if (intensity > 0) {
// La couleur suit également le nouveau sens de défilement
uint8_t hue = (y * 12) - time_offset;
leds[led_index] = CHSV(hue, 255, 255);
} else {
leds[led_index] = CRGB::Black;
}
}
}
}
// ==========================================
// ANIMATION : DOUBLE HÉLICE CROISÉE (ADN)
// ==========================================
void helical_double_spiral() {
uint32_t ms = millis();
uint8_t time_offset = ms / 15;
for (int y = 0; y < STRING_SIZE; y++) {
for (int x = 0; x < STRINGS; x++) {
// Gestion du serpentin
int targetX = x;
if (SERPENTINE_LAYOUT && (y % 2 != 0)) {
targetX = (STRINGS - 1) - x;
}
int led_index = (y * STRINGS) + targetX;
uint8_t angle = (x * 16) + (y * 16);
// --- NOUVELLE APPROCHE DE LUMINOSITÉ MAXIMALE ---
// On récupère la valeur brute du sinus (entre 0 et 255)
uint8_t s1 = sin8(angle - time_offset);
uint8_t s2 = sin8(angle + time_offset);
// Au lieu de soustraire et d'écraser la puissance, on applique un seuil strict.
// Si on est proche du sommet de l'onde (ex: > 220), l'intensité est maximale (255)
uint8_t intensity1 = (s1 > 220) ? 255 : 0;
uint8_t intensity2 = (s2 > 220) ? 255 : 0;
if (intensity1 > 0 || intensity2 > 0) {
CRGB color1 = CRGB::Black;
CRGB color2 = CRGB::Black;
if (intensity1 > 0) {
color1 = CHSV((y * 12) + time_offset, 255, 255); // Éclat max (255)
}
if (intensity2 > 0) {
color2 = CHSV((y * 12) - time_offset + 128, 255, 255); // Éclat max (255)
}
leds[led_index] = color1 + color2;
} else {
leds[led_index] = CRGB::Black;
}
}
}
}