Built-in project · Arduino Uno R3

LED fireworks on an Arduino Uno

Rockets climb a 30-LED WS2812B strip and burst into fading sparks while a piezo whistles and pops, with a button for the grand finale. Safe for any age and any noise rule. The whole build, an Arduino Uno and 4 more parts, runs here in your browser on the firmware below; open it in the editor to change the wiring or the code and run it again.

Teaching? Assign it to your class in one click.

Intermediate Runs in your browser. Free, and no account needed.

LED fireworks · Arduino Uno R3live0.000 s 0.00x
Press the button for the grand finale
The circuit itself, running here on the simulator. Press what can be pressed; click anything else to open it in the editor.

The code

The firmware exactly as the editor opens it. Change a line there and press Run: it compiles in the browser.

sketch.ino · Arduino Uno R3
// LED fireworks: rockets climb a strip of LEDs, burst into sparks that fly
// both ways and fade, and a piezo whistles on the way up and pops at the top.
// Press the button for the grand finale.
//
//   strip     30 WS2812B LEDs, DIN <- 330 ohms <- pin 6 (stand it up straight)
//   piezo     pin 8 -> piezo -> GND
//   button    pin 2 -> button -> GND        (INPUT_PULLUP): the finale
//
// Hang the strip up a window or along a fence post, LED 0 at the bottom. A
// rocket is one bright dot with a short tail that slows as it climbs, the way
// a real one does, and bursts at a random height. The burst throws sparks of
// one color up and down from that point, each slowing and fading, with a few
// white glitters at the end.
//
// Everything moves on a frame clock: each frame moves the rocket, ages the
// sparks and draws them all, then returns, so the button is read between
// frames and is never missed.
//
// Real fireworks are for the professionals. These ones are safe for any age,
// any weather and any noise rule.
//
// Things to try. Press the button for the finale. Add colors to COLORS. Make
// the bursts bigger with SPARKS.

#include <Adafruit_NeoPixel.h>

const int LEDS = 30;
const int PIEZO_PIN = 8;
const int BUTTON_PIN = 2;
const int SPARKS = 8;

Adafruit_NeoPixel strip(LEDS, 6, NEO_GRB + NEO_KHZ800);

const uint32_t COLORS[] = {0xFF2020, 0xFFFFFF, 0x2050FF, 0xFFC020, 0x30FF60, 0xFF40FF};
const int SHADES = sizeof(COLORS) / sizeof(COLORS[0]);

// Positions and speeds in 1/16ths of an LED, so things can move slowly.
int rocket = -1, rocketSpeed = 0, burstAt = 0;
int sparkPos[SPARKS], sparkSpeed[SPARKS];
uint8_t sparkLife = 0;
uint32_t sparkColor = 0;
unsigned long nextLaunch = 1000;
int launches = 0;
int finale = 0;   // rockets left in the finale

void launch() {
  rocket = 0;
  rocketSpeed = random(10, 14);
  burstAt = random(LEDS / 2, LEDS - 3) * 16;
  launches++;
  Serial.print("Launch ");
  Serial.println(launches);
}

void burst() {
  sparkColor = COLORS[random(0, SHADES)];
  for (int i = 0; i < SPARKS; i++) {
    sparkPos[i] = rocket;
    sparkSpeed[i] = (i % 2 ? 1 : -1) * random(3, 12);
  }
  sparkLife = 255;
  rocket = -1;
  tone(PIEZO_PIN, 140, 60);   // pop
}

void setup() {
  Serial.begin(9600);
  pinMode(BUTTON_PIN, INPUT_PULLUP);
  strip.begin();
  strip.setBrightness(200);
  strip.show();
  randomSeed(analogRead(A0));
  Serial.println("Fireworks ready: press the button for the finale");
}

void loop() {
  unsigned long now = millis();
  if (digitalRead(BUTTON_PIN) == LOW && finale == 0) {
    finale = 6;
    Serial.println("Grand finale!");
  }
  if (rocket < 0 && sparkLife < 120 && (now >= nextLaunch || finale > 0)) {
    launch();
    if (finale > 0) finale--;
    nextLaunch = now + random(1500, 3500);
  }

  strip.clear();
  if (rocket >= 0) {
    rocket += rocketSpeed;
    if (rocketSpeed > 4 && random(0, 3) == 0) rocketSpeed--;   // slowing
    tone(PIEZO_PIN, 1500 + rocket * 2, 20);                     // whistle
    int at = rocket / 16;
    strip.setPixelColor(at, 255, 200, 120);
    if (at > 0) strip.setPixelColor(at - 1, 60, 30, 0);
    if (rocket >= burstAt) burst();
  }
  if (sparkLife > 0) {
    uint8_t r = (uint8_t)(sparkColor >> 16) * sparkLife / 255;
    uint8_t g = (uint8_t)(sparkColor >> 8) * sparkLife / 255;
    uint8_t b = (uint8_t)sparkColor * sparkLife / 255;
    for (int i = 0; i < SPARKS; i++) {
      sparkPos[i] += sparkSpeed[i];
      if (sparkSpeed[i] > 1) sparkSpeed[i]--;
      if (sparkSpeed[i] < -1) sparkSpeed[i]++;
      int at = sparkPos[i] / 16;
      if (at >= 0 && at < LEDS) {
        bool glitter = sparkLife < 60 && random(0, 4) == 0;
        strip.setPixelColor(at, glitter ? strip.Color(255, 255, 255) : strip.Color(r, g, b));
      }
    }
    sparkLife = sparkLife > 8 ? sparkLife - 8 : 0;
  }
  strip.show();
  delay(25);
}

Parts list

6 parts, plus the jumper wires. Every one is in the editor's parts bin.

How it is wired

6 connections, pin by pin, read from the circuit itself. Each line is one set of pins joined together, by a jumper wire or a breadboard strip.

  • Arduino Uno R3 pin 8; Piezo speaker pin 1
  • Arduino Uno R3 pin 6; Resistor, 330 Ω pin 1
  • Arduino Uno R3 pin 2; Pushbutton pin 1a
  • Arduino Uno R3 pin 5V; Addressable RGB LEDs pin VDD
  • Ground: Arduino Uno R3 pin GND; Pushbutton pin 2a; Addressable RGB LEDs pin VSS; Piezo speaker pin 2
  • Resistor, 330 Ω pin 2; Addressable RGB LEDs pin DIN

Change it and keep it

Open it in the editor, change the circuit or the code, and keep your version in a free account.