Medusa’s Arrows (Rida’s Halloween Costume)

🎃 Result Photos

The result looks great and I’m really proud of this first cosplaying & Halloween parade attempt!! The character is Medusa Gorgon from Soul Eater (the anime) and the goal was to create replicates of her arrows that pair well with the costume. The purple fading light at the arrow heads turned out to be a perfect point of direction for my big classmate group at the parade too and I was recognized by the standby audience. 🥳🥳🥳

What Medusa and Dr. Stein looks like in Soul Eater:

📷Process photos

📘Reason of making

I wanted to cosplay Medusa from Soul Eater and thought NeonPixel and basic Arduino would be the best tools to product a glowing arrow effect, which by itself is a good wearable to wear around the waist and extend from behind.

🎩 How to wear

The plan was to attach 6 arrows around a waist band vertically to prevent sliding but I fell sick half of the week and only got to get 2 arrows done. Becky suggested it is common practice for cosers to wear the gears with a small backpack and that’s what I did with my costume in black. I basically shoveled the root of the arrows, connected to the Gemma M0 board and a power bank, into my backpack. I then fastened the structure by bending and securing the body of the arrow onto the shoulder belts as well as with tightened zippers. It turned out to be pretty sturdy and well.

📚 What I learned

  • Improved soldering skills on tiny LEDs
  • Improvising with material to achieve great outcomes
  • Basic Arduino coding

💭 What I would do differently

  • Plan better and order side LEDs earlier so to reserve more time to the most tedious soldering & wiring process

🧱 Materials

  • LEDs
  • Gemma M0
  • wires (blue, red, black)
  • soldering supplies
  • black foam tube (1 1/4” inner diameter)
  • blue foam
  • black acrylic paint

🔌 Circuit Diagram

(Will upload tomorrow morning)

⌨️ Arduino Code

// NeoPixel test program showing use of the WHITE channel for RGBW
// pixels only (won't look correct on regular RGB NeoPixel strips).

#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
 #include <avr/power.h> // Required for 16 MHz Adafruit Trinket
#endif

// Which pin on the Arduino is connected to the NeoPixels?
// On a Trinket or Gemma we suggest changing this to 1:
#define LED_PIN     1

// How many NeoPixels are attached to the Arduino?
#define LED_COUNT  25

// NeoPixel brightness, 0 (min) to 255 (max)
#define BRIGHTNESS 50 // Set BRIGHTNESS to about 1/5 (max = 255)

// Declare our NeoPixel strip object:
Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);
// Argument 1 = Number of pixels in NeoPixel strip
// Argument 2 = Arduino pin number (most are valid)
// Argument 3 = Pixel type flags, add together as needed:
//   NEO_KHZ800  800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
//   NEO_KHZ400  400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)
//   NEO_GRB     Pixels are wired for GRB bitstream (most NeoPixel products)
//   NEO_RGB     Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)
//   NEO_RGBW    Pixels are wired for RGBW bitstream (NeoPixel RGBW products)

void setup() {
  // These lines are specifically to support the Adafruit Trinket 5V 16 MHz.
  // Any other board, you can remove this part (but no harm leaving it):
#if defined(__AVR_ATtiny85__) && (F_CPU == 16000000)
  clock_prescale_set(clock_div_1);
#endif
  // END of Trinket-specific code.

  strip.begin();           // INITIALIZE NeoPixel strip object (REQUIRED)
  strip.show();            // Turn OFF all pixels ASAP
  strip.setBrightness(BRIGHTNESS);
  Serial.begin(9600);
  colorWipe(strip.Color(0,   0,   0, 0)     , 0); 
}

void loop() {
  // Fill along the length of the strip in various colors...
  /*
  
  colorWipe(strip.Color(  0, 255,   0)     , 50); // Green
  colorWipe(strip.Color(  0,   0, 255)     , 50); // Blue
  colorWipe(strip.Color(  0,   0,   0, 255), 50); // True white (not RGB white)

  whiteOverRainbow(75, 5);

  pulseWhite(5);

  rainbowFade2White(3, 3, 1);
  */
  fadeToPurple(120);
}


void fadeToPurple(int wait) {
  //for(int i=0; i<strip.numPixels(); i++) { // For each pixel in strip...
    //strip.setPixelColor(i, color);         //  Set pixel's color (in RAM)
    // fade in from min to max in increments of 5 points:
    for (int fadeValue = 0; fadeValue <= 255; fadeValue += 5) {
    // sets the value (range from 0 to 255):
        colorAll(strip.Color(fadeValue,   0,   fadeValue,0), 0);

    //strip.setPixelColor(i, strip.Color(fadeValue,   0,   255,0));
   // analogWrite(ledPin, fadeValue);
    // wait for 30 milliseconds to see the dimming effect
    delay(40);
    Serial.print("fadevalue= ");
    Serial.println(fadeValue);
      strip.show();                          //  Update strip to match
  }

  // fade out from max to min in increments of 5 points:
  for (int fadeValue = 255; fadeValue >= 0; fadeValue -= 3) {
    // sets the value (range from 0 to 255):
    colorAll(strip.Color(fadeValue,   0,   fadeValue,0), 0);
    //strip.setPixelColor(i, strip.Color(fadeValue,   0,   255,0));
    // wait for 30 milliseconds to see the dimming effect
    delay(40);
  Serial.print("fadevalue= ");
    Serial.println(fadeValue);  }
  strip.show();                          //  Update strip to match
  
//}
//delay(wait);
}


// Fill strip pixels one after another with a color. Strip is NOT cleared
// first; anything there will be covered pixel by pixel. Pass in color
void colorAll(uint32_t color, int wait) {
  for(int i=0; i<strip.numPixels(); i++) { // For each pixel in strip...
    strip.setPixelColor(i, color);         //  Set pixel's color (in RAM)
  }
    strip.show();                          //  Update strip to match
    delay(wait);                           //  Pause for a moment
}
// (as a single 'packed' 32-bit value, which you can get by calling
// strip.Color(red, green, blue) as shown in the loop() function above),
// and a delay time (in milliseconds) between pixels.
void colorWipe(uint32_t color, int wait) {
  for(int i=0; i<strip.numPixels(); i++) { // For each pixel in strip...
    strip.setPixelColor(i, color);         //  Set pixel's color (in RAM)
    strip.show();                          //  Update strip to match
    delay(wait);                           //  Pause for a moment
  }
}

void whiteOverRainbow(int whiteSpeed, int whiteLength) {

  if(whiteLength >= strip.numPixels()) whiteLength = strip.numPixels() - 1;

  int      head          = whiteLength - 1;
  int      tail          = 0;
  int      loops         = 3;
  int      loopNum       = 0;
  uint32_t lastTime      = millis();
  uint32_t firstPixelHue = 0;

  for(;;) { // Repeat forever (or until a 'break' or 'return')
    for(int i=0; i<strip.numPixels(); i++) {  // For each pixel in strip...
      if(((i >= tail) && (i <= head)) ||      //  If between head & tail...
         ((tail > head) && ((i >= tail) || (i <= head)))) {
        strip.setPixelColor(i, strip.Color(0, 0, 0, 255)); // Set white
      } else {                                             // else set rainbow
        int pixelHue = firstPixelHue + (i * 65536L / strip.numPixels());
        strip.setPixelColor(i, strip.gamma32(strip.ColorHSV(pixelHue)));
      }
    }

    strip.show(); // Update strip with new contents
    // There's no delay here, it just runs full-tilt until the timer and
    // counter combination below runs out.

    firstPixelHue += 40; // Advance just a little along the color wheel

    if((millis() - lastTime) > whiteSpeed) { // Time to update head/tail?
      if(++head >= strip.numPixels()) {      // Advance head, wrap around
        head = 0;
        if(++loopNum >= loops) return;
      }
      if(++tail >= strip.numPixels()) {      // Advance tail, wrap around
        tail = 0;
      }
      lastTime = millis();                   // Save time of last movement
    }
  }
}

void pulseWhite(uint8_t wait) {
  for(int j=0; j<256; j++) { // Ramp up from 0 to 255
    // Fill entire strip with white at gamma-corrected brightness level 'j':
    strip.fill(strip.Color(0, 0, 0, strip.gamma8(j)));
    strip.show();
    delay(wait);
  }

  for(int j=255; j>=0; j--) { // Ramp down from 255 to 0
    strip.fill(strip.Color(0, 0, 0, strip.gamma8(j)));
    strip.show();
    delay(wait);
  }
}

void rainbowFade2White(int wait, int rainbowLoops, int whiteLoops) {
  int fadeVal=0, fadeMax=100;

  // Hue of first pixel runs 'rainbowLoops' complete loops through the color
  // wheel. Color wheel has a range of 65536 but it's OK if we roll over, so
  // just count from 0 to rainbowLoops*65536, using steps of 256 so we
  // advance around the wheel at a decent clip.
  for(uint32_t firstPixelHue = 0; firstPixelHue < rainbowLoops*65536;
    firstPixelHue += 256) {

    for(int i=0; i<strip.numPixels(); i++) { // For each pixel in strip...

      // Offset pixel hue by an amount to make one full revolution of the
      // color wheel (range of 65536) along the length of the strip
      // (strip.numPixels() steps):
      uint32_t pixelHue = firstPixelHue + (i * 65536L / strip.numPixels());

      // strip.ColorHSV() can take 1 or 3 arguments: a hue (0 to 65535) or
      // optionally add saturation and value (brightness) (each 0 to 255).
      // Here we're using just the three-argument variant, though the
      // second value (saturation) is a constant 255.
      strip.setPixelColor(i, strip.gamma32(strip.ColorHSV(pixelHue, 255,
        255 * fadeVal / fadeMax)));
    }

    strip.show();
    delay(wait);

    if(firstPixelHue < 65536) {                              // First loop,
      if(fadeVal < fadeMax) fadeVal++;                       // fade in
    } else if(firstPixelHue >= ((rainbowLoops-1) * 65536)) { // Last loop,
      if(fadeVal > 0) fadeVal--;                             // fade out
    } else {
      fadeVal = fadeMax; // Interim loop, make sure fade is at max
    }
  }

  for(int k=0; k<whiteLoops; k++) {
    for(int j=0; j<256; j++) { // Ramp up 0 to 255
      // Fill entire strip with white at gamma-corrected brightness level 'j':
      strip.fill(strip.Color(0, 0, 0, strip.gamma8(j)));
      strip.show();
    }
    delay(1000); // Pause 1 second
    for(int j=255; j>=0; j--) { // Ramp down 255 to 0
      strip.fill(strip.Color(0, 0, 0, strip.gamma8(j)));
      strip.show();
    }
  }

  delay(500); // Pause 1/2 second
}

Sige’s Halloween Costume – NoFace/TwoFace Ghost

This Halloween I made a costume as the No-face ghost but made it into a two-face ghost. This is an interactive costume – when I high five with another person, the face of white light will flash red; when I make a heart shape with my hand, the neutral face will change into a love face that flashes pink and blue color.

This costume is inspired by the movie Spirited Away. In the movie, the No Face ghost follows Sen, the young girl, at the end of her journey and onto the train. The Two Face ghost follows me around NYC and on the subway of NYC.

Materials

  1. Black cloth
  2. LED light strips
    • strip lights from the front, cut into 12 sections to make the neutral face and the mouths
    • strip lights from the side, cut into 2 sections to make the hearted eyes
  3. Wires
    • to connect lights
  4. Thick wires
    • to make the frame to support the ghost (cloth)
  5. Solder
    • to connect lights and wires
  6. Zip tie
    • to connect the wire frame
  7. Hot glue
    • to seal the sharp wire edges
  8. Electric tape
  9. Gemma
  10. Power Bank
  11. Vibration sensor
  12. Magnetic switch

Circuit Diagram

Arduino Code

https://www.tinkercad.com/things/dKrVTRXBeRQ-siges-halloween-code?sharecode=1lYuPeBtHUzDRoIwtiQ0rHkCWOYn-FoT_Had3ImEeuQ

#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
 #include <avr/power.h> // Required for 16 MHz Adafruit Trinket
#endif

#define BUTTON_PIN   2

#define VIBRATION_PIN   0

#define PIXEL_PIN    1  // Digital IO pin connected to the NeoPixels.

#define PIXEL_COUNT 77  // Number of NeoPixels

// Declare our NeoPixel strip object:
Adafruit_NeoPixel strip(PIXEL_COUNT, PIXEL_PIN, NEO_GRB + NEO_KHZ800);

boolean oldStateV = HIGH;
int     modeV     = 0;    // Currently-active animation mode, 0-9
boolean oldStateM = HIGH;
int     mode     = 0;    // Currently-active animation mode, 0-9

void grouponeanimate(uint32_t color, int wait) {
  for(int i=0; i<31 ; i++) { // For each pixel in strip...
    strip.setPixelColor(i, color);         //  Set pixel's color (in RAM)
  }
    strip.show();                          //  Update strip to match
    delay(wait);                           //  Pause for a moment
  }

void grouptwoanimate(uint32_t color, int wait) {
  for(int i=31; i<strip.numPixels(); i++) { // For each pixel in strip...
    strip.setPixelColor(i, color);         //  Set pixel's color (in RAM)
  }
    strip.show();                          //  Update strip to match
    delay(wait);                           //  Pause for a moment
  }

void g2Purple(int wait) {
    for (int fadeValue = 0; fadeValue <= 255; fadeValue += 15) {
      for(int i=31; i<strip.numPixels(); i++) { // For each pixel in strip...
        strip.setPixelColor(i, strip.Color(fadeValue,   0,   255,0));         //  Set pixel's color (in RAM)
      }
        strip.show(); 
        delay(wait); 

    Serial.print("fadevalue= ");
    Serial.println(fadeValue);
      strip.show();                          //  Update strip to match
  

  // fade out from max to min in increments of 5 points:
    for (int fadeValue = 255; fadeValue >= 0; fadeValue -= 15) {
      for(int i=31; i<strip.numPixels(); i++) { // For each pixel in strip...
        strip.setPixelColor(i, strip.Color(fadeValue,   0,   255,0));         //  Set pixel's color (in RAM)
      }
        strip.show();   
        delay(wait);    
    }
    Serial.print("fadevalue= ");
    Serial.println(fadeValue);  }
      strip.show();                          //  Update strip to match
}

void setup() {
  pinMode(BUTTON_PIN, INPUT_PULLUP);
  pinMode(VIBRATION_PIN, INPUT_PULLUP);
  strip.begin(); // Initialize NeoPixel strip object (REQUIRED)
  strip.show();  // Initialize all pixels to 'off'
}

void loop(){
  boolean newStateV = digitalRead(VIBRATION_PIN);
  boolean newStateM = digitalRead(BUTTON_PIN);

  if(newStateV != oldStateV) {
    // Short delay to debounce button.
    delay(10);
    // Check if button is still low after debounce.
    newStateV = digitalRead(VIBRATION_PIN);
    if(newStateV != oldStateV) {      // Yes
      grouptwoanimate((  0, 0,   0), 50);
      if(++modeV > 1) modeV = 0; // Advance to next mode, wrap around after #1
      switch(modeV) {           // Start the new animation...
        case 0:
          grouponeanimate(strip.Color(180,   180,   255), 50);    // white
          break;
        case 1:
          grouponeanimate(strip.Color(  255, 0,   0), 50);    // red
          break;
      }
    }
      oldStateV = newStateV;
    } else {
      if (newStateM != oldStateM) {
        grouponeanimate(strip.Color(  0, 0,   0), 50);
        g2Purple(50);
        oldStateM = newStateM;
    }
  }
}

Process

1. Make the wire frame for the ghost structure

2. Connect the wire to Arduino and breadboard

I connected 1 long light strip to the Arduino and the breadboard so that I can test the code I will use

3. Write & test code

4. Connect the light and switch and sensor to Gemma, cut light strip into sections, solder them together with wires of various length so I can structure the light strip into the shapes of the face

While I’m soldering the light strips together, I tested the connection after each connection to make sure there’s nothing wrong.

5. Edit the code to fit the number of lights used and the Gemma port

6. Sew the light strip to the black cloth and wire structure

Voila!

Tong’s Halloween Costume Final

My final costume is a self-created half-deity, half-demon with Chinese traditional elements (quite a long title)

I cut a circular board with a diameter of 32 centimeters from an acrylic sheet, then used laser engraving to carve traditional Chinese cloud patterns and concentric circles mimicking a halo. Then, using a glue gun, I attached LED light strips to the edge of the circular board, so when the lights are on, this disc looks like a halo floating behind my head.

My concept is that when the halo is yellow, he is a merciful god, and when the halo turns red, he becomes a demon. However, on Halloween, his halo constantly shifts between yellow and red, as if the red demon is trying to break out, but the yellow god is trying to suppress him, and they are in a struggle.

This is my circuit diagram, it’s very simple.

This is my code,

#include <Adafruit_NeoPixel.h>

#define PIN         1    // 灯带引脚
#define NUMPIXELS   75   // 灯带灯珠数
#define STATIC_R    242  // 静态颜色 R
#define STATIC_G    163  // 静态颜色 G
#define STATIC_B    0    // 静态颜色 B
#define METEOR_R    224  // 流星颜色 R
#define METEOR_G    163  // 流星颜色 G
#define METEOR_B    22   // 流星颜色 B

Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);

void setup() {
  pixels.begin();  // 初始化灯带
  pixels.clear();  // 确保开始时灯带关闭
}

void loop() {
  // 1. 从两端向中间依次点亮
  lightUpFromEnds(STATIC_R, STATIC_G, STATIC_B);
  delay(500);  // 短暂停留后进入褪色效果

  // 2. 进入初始褪色效果,单次5秒,共循环20秒
  for (int i = 0; i < 4; i++) {  // 循环4次,20秒
    fadeEffect(STATIC_R, STATIC_G, STATIC_B, 5000);
  }

  // 3. 从中间向两端光点流星效果
  meteorEffect(METEOR_R, METEOR_G, METEOR_B, STATIC_R, STATIC_G, STATIC_B);
  
  // 4. 黄色光点从两端向中间流星效果
  meteorToCenter(METEOR_R, METEOR_G, METEOR_B);

  // 5. 光点分散到第19颗和第56颗并分两段同时环绕点亮
  disperseAndRing(STATIC_R, STATIC_G, STATIC_B);

// 7. 新增褪色效果,单次5秒,共循环20秒
  for (int i = 0; i < 4; i++) {  // 循环4次,20秒
    fadeEffect(STATIC_R, STATIC_G, STATIC_B, 5000);
  }

// 黄色呼吸灯逐渐加快到红色频闪灯效果
  acceleratingBreatheToStrobe(2000, 200, 5000);  // 初始周期2秒,最终周期0.2秒,红色频闪持续5秒

// 黄色常亮2秒
  setAllPixels(242, 163, 0);  // 黄色
  pixels.show();
  delay(6000);  // 常亮2秒

  

  // 6. 从第1颗开始缓慢长拖尾流星效果跑5秒
  runSingleMeteorAroundRing(METEOR_R, METEOR_G, METEOR_B, 3);

  // 7. 进行褪色渐变颜色效果
  fadeCycle();

  // 8. 所有灯常亮2秒后,进行5秒褪色效果,持续30秒
  staticLightAndFade(STATIC_R, STATIC_G, STATIC_B);
}

// 从两端向中间依次点亮的函数
void lightUpFromEnds(int r, int g, int b) {
  int left = 0;
  int right = NUMPIXELS - 1;
  while (left <= right) {
    pixels.setPixelColor(left, pixels.Color(r, g, b));
    pixels.setPixelColor(right, pixels.Color(r, g, b));
    pixels.show();
    delay(50);
    left++;
    right--;
  }
}

// 初始褪色效果函数
void fadeEffect(int r, int g, int b, int cycleTime) {
  int fadeSteps = 255;
  int stepDelay = cycleTime / (2 * fadeSteps);

  // 渐亮
  for (int i = 0; i <= fadeSteps; i++) {
    setAllPixels(r * i / fadeSteps, g * i / fadeSteps, b * i / fadeSteps);
    delay(stepDelay);
  }

  // 渐暗
  for (int i = fadeSteps; i >= 0; i--) {
    setAllPixels(r * i / fadeSteps, g * i / fadeSteps, b * i / fadeSteps);
    delay(stepDelay);
  }
}

// 从中间向两端光点流星效果并变色
void meteorEffect(int midR, int midG, int midB, int finalR, int finalG, int finalB) {
  int left = (NUMPIXELS - 1) / 2;
  int right = left + 1;

  while (left >= 0 || right < NUMPIXELS) {
    for (int i = 0; i < NUMPIXELS; i++) {
      if (i == left || i == right) {
        pixels.setPixelColor(i, pixels.Color(midR, midG, midB));
      } else {
        uint32_t currentColor = pixels.getPixelColor(i);
        int r = (currentColor >> 16) & 0xFF;
        int g = (currentColor >> 8) & 0xFF;
        int b = currentColor & 0xFF;
        pixels.setPixelColor(i, pixels.Color(r * 0.8, g * 0.8, b * 0.8));
      }
    }
    pixels.show();
    delay(50);

    if (left >= 0) left--;
    if (right < NUMPIXELS) right++;
  }

  for (int i = 0; i < NUMPIXELS; i++) {
    pixels.setPixelColor(i, pixels.Color(finalR, finalG, finalB));
  }
  pixels.show();
}

// 黄色光点从两端向中间流星效果
// 长拖尾流星效果从两端向中间
void meteorToCenter(int r, int g, int b) {
  int left = 0;
  int right = NUMPIXELS - 1;

  while (left <= right) {
    pixels.clear();

    // 设置左侧和右侧的流星头部光点
    pixels.setPixelColor(left, pixels.Color(r, g, b));
    pixels.setPixelColor(right, pixels.Color(r, g, b));

    // 为左右流星创建长拖尾效果
    for (int j = 1; j <= 15; j++) {  // 拖尾长度为15
      int leftPos = (left - j + NUMPIXELS) % NUMPIXELS;
      int rightPos = (right + j - NUMPIXELS) % NUMPIXELS;

      // 计算拖尾的亮度,越靠近头部亮度越高
      int tailBrightness = 255 * (15 - j) / 15;  // 逐渐减少亮度
      pixels.setPixelColor(leftPos, pixels.Color(r * tailBrightness / 255, g * tailBrightness / 255, b * tailBrightness / 255));
      pixels.setPixelColor(rightPos, pixels.Color(r * tailBrightness / 255, g * tailBrightness / 255, b * tailBrightness / 255));
    }

    pixels.show();
    delay(50);  // 控制流星移动速度

    // 向中间移动
    left++;
    right--;
  }
}

// 从黄色呼吸灯逐渐加快到红色频闪灯的效果
void acceleratingBreatheToStrobe(int initialCycleTime, int finalCycleTime, int strobeDuration) {
  int yellowR = 242, yellowG = 163, yellowB = 0;  // 黄色
  int redR = 255, redG = 0, redB = 0;             // 红色
  int currentCycleTime = initialCycleTime;
  
  // 循环控制呼吸灯逐渐加快
  while (currentCycleTime > finalCycleTime) {
    // 黄色呼吸效果:先亮后暗
    for (int i = 0; i <= 100; i++) {
      setAllPixels(yellowR * i / 100, yellowG * i / 100, yellowB * i / 100);
      delay(currentCycleTime / 200);  // 每次呼吸的亮起延迟
    }
    for (int i = 100; i >= 0; i--) {
      setAllPixels(yellowR * i / 100, yellowG * i / 100, yellowB * i / 100);
      delay(currentCycleTime / 200);  // 每次呼吸的暗下延迟
    }

    // 减少循环时间,使呼吸速度加快
    currentCycleTime = max(currentCycleTime - 100, finalCycleTime);
  }

  // 红色频闪效果
  unsigned long startTime = millis();
  while (millis() - startTime < strobeDuration) {
    setAllPixels(redR, redG, redB);  // 红色亮起
    delay(50);                       // 频闪亮的时间
    setAllPixels(0, 0, 0);           // 灭
    delay(50);                       // 频闪灭的时间
  }
}



// // 光点分散到第19颗和第56颗并分两段环绕点亮
void disperseAndRing(int r, int g, int b) {
  int leftTarget = 18;  // 第19颗灯珠(从0计数)
  int rightTarget = 55; // 第56颗灯珠(从0计数)

  pixels.clear();
  
  // 设置光点在第19颗和第56颗位置
  pixels.setPixelColor(leftTarget, pixels.Color(r, g, b));
  pixels.setPixelColor(rightTarget, pixels.Color(r, g, b));
  pixels.show();
  delay(500);

  // 环绕点亮:第19颗到第55颗
  for (int i = leftTarget; i <= rightTarget; i++) {
    pixels.setPixelColor(i, pixels.Color(r, g, b));
    pixels.show();
    delay(50);
  }

  // 环绕点亮:第56颗到第75颗
  for (int i = rightTarget + 1; i < NUMPIXELS; i++) {
    pixels.setPixelColor(i, pixels.Color(r, g, b));
    pixels.show();
    delay(50);
  }

  // 环绕点亮:第1颗到第18颗
  for (int i = 0; i < leftTarget; i++) {
    pixels.setPixelColor(i, pixels.Color(r, g, b));
    pixels.show();
    delay(50);
  }
}


// 单颗光点从第1颗开始缓慢长拖尾流星效果跑6圈,最后一圈结束后从第一颗依次点亮整条灯带
void runSingleMeteorAroundRing(int r, int g, int b, int numCircuits) {
  for (int circuit = 0; circuit < numCircuits; circuit++) {
    for (int i = 0; i < NUMPIXELS; i++) {
      pixels.clear();
      
      // 当前光点设置为亮度最大
      pixels.setPixelColor(i, pixels.Color(r, g, b));
      
      // 创建长拖尾效果
      for (int j = 1; j <= 15; j++) {  // 拖尾长度为10
        int pos = (i - j + NUMPIXELS) % NUMPIXELS;
        int tailBrightness = 255 * (10 - j) / 10;  // 逐渐减少亮度
        pixels.setPixelColor(pos, pixels.Color(r * tailBrightness / 255, g * tailBrightness / 255, b * tailBrightness / 255));
      }
      
      pixels.show();
      delay(50);  // 控制光点移动速度
    }
  }

  // 结束后从第一颗依次点亮整条灯带
  for (int i = 0; i < NUMPIXELS; i++) {
    pixels.setPixelColor(i, pixels.Color(r, g, b));
    pixels.show();
    delay(50);  // 控制每颗灯依次点亮的速度
  }
}

// 褪色渐变颜色效果函数
void fadeCycle() {
  for (int i = 0; i < 5; i++) { // 循环2次
    // 渐变 黄色 (242, 163, 0) -> 白色 (255, 255, 255)
    fadeToColor(242, 163, 0, 255, 0, 0, 2500);

    // 渐变 白色 (255, 255, 255) -> 红色 (255, 0, 0)
    fadeToColor(255, 0, 0, 242, 163, 0, 2500);
  }
}

// 渐变到指定颜色的函数
void fadeToColor(int r1, int g1, int b1, int r2, int g2, int b2, int duration) {
  int steps = 100;  // 渐变的步骤数
  int delayTime = duration / steps;  // 每步的延迟时间

  for (int i = 0; i <= steps; i++) {
    int r = r1 + ((r2 - r1) * i) / steps;
    int g = g1 + ((g2 - g1) * i) / steps;
    int b = b1 + ((b2 - b1) * i) / steps;

    setAllPixels(r, g, b);  // 将颜色设置到所有灯珠
    delay(delayTime);       // 延迟以控制渐变速度
  }
}

// 呼吸效果函数
void breatheEffect(int r, int g, int b, int cycleTime) {
  int fadeSteps = 150;  // 呼吸效果的渐变步骤数
  int stepDelay = cycleTime / (2 * fadeSteps); // 每步的延迟时间

  // 渐亮
  for (int i = 0; i <= fadeSteps; i++) {
    setAllPixels(r * i / fadeSteps, g * i / fadeSteps, b * i / fadeSteps);
    delay(stepDelay);
  }

  // 渐暗
  for (int i = fadeSteps; i >= 0; i--) {
    setAllPixels(r * i / fadeSteps, g * i / fadeSteps, b * i / fadeSteps);
    delay(stepDelay);
  }
}

// 常亮2秒后进行5秒褪色效果,持续30秒
void staticLightAndFade(int r, int g, int b) {
  unsigned long startTime = millis();

  while (millis() - startTime < 15000) { // 持续30秒
    // 常亮2秒
    setAllPixels(r, g, b);
    delay(2000);

    // 5秒的褪色效果
    fadeEffect(r, g, b, 5000);
  }
}

// 设置所有像素为指定颜色
void setAllPixels(int r, int g, int b) {
  for (int i = 0; i < NUMPIXELS; i++) {
    pixels.setPixelColor(i, pixels.Color(r, g, b));
  }
  pixels.show();
}

This is the complete loop video。

More photos:

East meets West in magic.

Shot with FIMO CStill 800T.

World-breaking dimensions

The little kitty also loves today’s god-demon.

Jessie’s Final Halloween Costume

IDEATION:

MATERIALS:

shocking pink / salmon / baby pink felt

chenille stems cure-pipes

CIRCUIT DIAGRAM:

To make the gemma show only white colors with a breathing effect.

ARDUINO:

Base on example: strandtest

Modification:

void loop() {

  breathingEffect(strip.Color(255, 255, 255), 20); // White breathing effect

}

void breathingEffect(uint32_t color, int delayTime) {

  // Increase brightness

  for (int brightness = 0; brightness <= 255; brightness++) {

    setStripBrightness(color, brightness);

    delay(delayTime);

  }

  // Decrease brightness

  for (int brightness = 255; brightness >= 0; brightness–) {

    setStripBrightness(color, brightness);

    delay(delayTime);

  }

}

void setStripBrightness(uint32_t color, int brightness) {

  // Set brightness and color to each LED

  for (int i = 0; i < strip.numPixels(); i++) {

    uint8_t r = (uint8_t)(Red(color) * brightness / 255);

    uint8_t g = (uint8_t)(Green(color) * brightness / 255);

    uint8_t b = (uint8_t)(Blue(color) * brightness / 255);

    strip.setPixelColor(i, r, g, b);

  }

  strip.show();

}

uint8_t Red(uint32_t color) {

  return (color >> 16) & 0xFF;

}

uint8_t Green(uint32_t color) {

  return (color >> 8) & 0xFF;

}

uint8_t Blue(uint32_t color) {

  return color & 0xFF;

}

In-progress Images: 

FINAL LOOK:

Lynn’s Halloween  Shitty Idea

As a designer, I spend a lot of time coming up with ideas. And let’s be honest—sometimes they’re just shitty and trashy. So for Halloween, I’m literally wrapped in a trash bag, and on my head is a lightbulb, symbolizing those ‘aha’ moments… except this one’s got a glowing poop inside.

Material list:

Clear Ball Ornaments, 160mm/6.3inch

3D printed poop shaped shell (12x12x12cm, transparent PETG)

3D printed bulb holder (12x12x12cm, black PLA, spray painted in copper color)

XL trash bag (realized it’s still too small)

black leggings

Adafruit NeoPixel Digital RGB LED Strip

Gemma M0 board

button

Idea Sketches:

3D modeling:

Circuit Diagram:

 Arduino code:

#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
 #include <avr/power.h> // Required for 16 MHz Adafruit Trinket
#endif

#define BUTTON_PIN   2
#define PIXEL_PIN    1  
#define PIXEL_COUNT 78  

Adafruit_NeoPixel strip(PIXEL_COUNT, PIXEL_PIN, NEO_GRB + NEO_KHZ800);

boolean oldState = HIGH;
int     mode     = 0;    

void setup() {
  pinMode(BUTTON_PIN, INPUT_PULLUP);
  strip.begin(); 
  strip.show();  
}

void colorWipe(uint32_t color, int wait) {
  for(int i=0; i<strip.numPixels(); i++) { 
    strip.setPixelColor(i, color);         
    strip.show();                          
    delay(wait);                           
  }
}

//mode3: offset orange blink
void orangeblink(int wait) {
  for (int offset = 0; offset < 3; offset++) {  // offset each 3 pixels
    strip.clear();  // clear all pixels
    for (int i = offset; i < strip.numPixels(); i += 3) {
      strip.setPixelColor(i, strip.Color(255, 165, 0)); // orange
    }
    strip.show(); // 
    delay(wait);  // 
  }
}

// Mode 4: Theater chase effect
void theaterChase(uint32_t color, int wait) {
  for (int a=0; a<10; a++) { // Repeat the chase effect
    for (int b=0; b<3; b++) { // 3 pixels lit per cycle
      strip.clear(); // Clear the pixels
      for (int c=0; c < strip.numPixels(); c+=3) {
        strip.setPixelColor(c+b, color); // Set every third pixel to the given color
      }
      strip.show(); // Update the strip
      delay(wait); // Wait before the next step
    }
  }
}

// mode5: rainbow
void rainbow(int wait) {
  for (long firstPixelHue = 0; firstPixelHue < 3*65536; firstPixelHue += 256) {
    for (int i = 0; i < strip.numPixels(); i++) {
      int pixelHue = firstPixelHue + (i * 65536L / strip.numPixels());
      strip.setPixelColor(i, strip.gamma32(strip.ColorHSV(pixelHue)));
    }
    strip.show();
    delay(wait);
  }
}

void loop() {
  boolean newState = digitalRead(BUTTON_PIN);

// Check if state changed from high to low (button press).
  if((newState == LOW) && (oldState == HIGH)) {
    // Short delay to debounce button.
    delay(20);
    // Check if button is still low after debounce.
    newState = digitalRead(BUTTON_PIN);
    if(newState == LOW) {      // Yes, still low
      if(++mode > 10) mode = 0; // Advance to next mode, wrap around after #8
      switch(mode) {           // Start the new animation...
        case 0:
          colorWipe(strip.Color(  0,   0,   0), 50);    // Black/off
          break;
        case 1:
          orangeTheaterChase();
          break;
        case 2:
          fade(20);    
          break;
        case 3:
         theaterChase(strip.Color(255, 0, 0), 50); // red
          break;
        case 4:
         theaterChase(strip.Color(255, 255, 0), 50); // yellow
          break;
        case 5:
         theaterChase(strip.Color(0, 255, 0), 50); // green
          break;
        case 6:
         theaterChase(strip.Color(0, 0, 255), 50); // blue
          break;
        case 7:
         theaterChase(strip.Color(128, 0, 128), 50); // purple
          break;
        case 8:
          rainbow(10);
          break;
      }
    }
  }

oldState = newState;
}
  
//mode2: poop up, poop down
void orangeTheaterChase() {
  for (int repeat = 0; repeat < 2; repeat++) { // Repeat the effect twice
    // Gradually light up from the first to the last pixel
    for (int a = 0; a < strip.numPixels(); a++) {
      strip.clear();
      for (int b = 0; b <= a; b++) {
        strip.setPixelColor(b, strip.Color(255, 60, 0)); // Set color to orange
      }
      strip.show();
      delay(50);  // Delay between each pixel lighting up
    }

    // Gradually turn off from the last to the first pixel
    for (int a = strip.numPixels() - 1; a >= 0; a--) {
      strip.clear();
      for (int b = 0; b <= a; b++) {
        strip.setPixelColor(b, strip.Color(255, 60, 0)); // Keep color orange
      }
      strip.show();
      delay(50);  // Delay between each pixel turning off
    }
  }
}

// //mode3: fade 3 times with dif leds
void fade(int wait) {
  // int fadeTimes = 3;  
  // for (int t = 0; t < fadeTimes; t++) { 
    // light up
    for (int brightness = 0; brightness <= 255; brightness += 5) {
      strip.clear();
      for (int i = 0; i < strip.numPixels(); i += 3) {
        strip.setPixelColor(i, strip.Color((brightness * 255) / 255, (brightness * 80) / 255, 0)); 

      }
      strip.show();
      delay(wait);  
    }
    // turn down
    for (int brightness = 255; brightness >= 0; brightness -= 5) {
      strip.clear();
      for (int i = 0; i < strip.numPixels(); i += 3) {
        strip.setPixelColor(i, strip.Color((brightness * 255) / 255, (brightness * 80) / 255, 0)); 
      }
      strip.show();
      delay(wait);  
    }
    for (int brightness = 0; brightness <= 255; brightness += 5) {
      strip.clear();
      for (int i = 1; i < strip.numPixels(); i += 3) {
        strip.setPixelColor(i, strip.Color((brightness * 255) / 255, (brightness * 80) / 255, 0)); 

      }
      strip.show();
      delay(wait);  
    }
    // turn down
    for (int brightness = 255; brightness >= 0; brightness -= 5) {
      strip.clear();
      for (int i = 1; i < strip.numPixels(); i += 3) {
        strip.setPixelColor(i, strip.Color((brightness * 255) / 255, (brightness * 80) / 255, 0)); 
      }
      strip.show();
      delay(wait);  
    }

    for (int brightness = 0; brightness <= 255; brightness += 5) {
      strip.clear();
      for (int i = 2; i < strip.numPixels(); i += 3) {
        strip.setPixelColor(i, strip.Color((brightness * 255) / 255, (brightness * 80) / 255, 0)); 

      }
      strip.show();
      delay(wait);  
    }
    // turn down
    for (int brightness = 255; brightness >= 0; brightness -= 5) {
      strip.clear();
      for (int i = 2; i < strip.numPixels(); i += 3) {
        strip.setPixelColor(i, strip.Color((brightness * 255) / 255, (brightness * 80) / 255, 0)); 
      }
      strip.show();
      delay(wait);  
    }
  }

Light Result!

Sofia is an Angler Fish?????

My Angler Fish is complete!!! This was the result of sewing, soldering, and a lot of fabric.

Materials

  1. Black Morph Suit (Amazon: https://www.amazon.com/dp/B00LEF3IRW?ref=ppx_yo2ov_dt_b_fed_asin_title )
  2. Mermaid Trim (Amazon: https://www.amazon.com/dp/B0BGL6D47N?ref=ppx_yo2ov_dt_b_fed_asin_title&th=1 https://www.amazon.com/dp/B0BLSDY374?ref=ppx_yo2ov_dt_b_fed_asin_title&th=1 , but I recommend Etsy if you have the time)
  3. Black Fabric (Flea Market)
  4. NeoPixel Gemma
  5. NeoPixel Strip
  6. Sewing Machine
  7. Hope
@astralsofia

does anyone know the sound that goes la la la la with bubble sound effects in the background that youtubers used to use in their videos yea that’s what I wanted in the background of thus video

♬ under your spell – ✯

I had a lot of fun learning how to sew during this process and there are a couple things I would have done differently.

@astralsofia

work in progress for my halloween costume…. sexy angler fish coming your way🐡🐟🐠

♬ Whiplash – aespa
  1. Make the hood bigger and have a small wire to make it stick up.
  2. Have a magnet in between the wig and hood to keep the light and hood in place.
  3. Buy more trim and add more layers
  4. Add LED lights to the ends of the trim for a more fun effect
  5. Use a stronger clip for the head light.

Overall, the costume making process was fun, and I managed to meet all of the goals that I set out to accomplish at the beginning.

Some my favorite pics from the parade:>

Soldering Components

//fades all pixels subtly
//code by Tony Sherwood for Adafruit Industries

#include <Adafruit_NeoPixel.h>

#define PIN 1

// Parameter 1 = number of pixels in strip
// Parameter 2 = pin number (most are valid)
// Parameter 3 = pixel type flags, add together as needed:
//   NEO_KHZ800  800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
//   NEO_KHZ400  400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)
//   NEO_GRB     Pixels are wired for GRB bitstream (most NeoPixel products)
//   NEO_RGB     Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)
Adafruit_NeoPixel strip = Adafruit_NeoPixel(14, PIN, NEO_GRBW + NEO_KHZ800);
Adafruit_NeoPixel strip2 = Adafruit_NeoPixel(14, PIN, NEO_GRB + NEO_KHZ800);

int alpha; // Current value of the pixels
int dir = 1; // Direction of the pixels... 1 = getting brighter, 0 = getting dimmer
int flip; // Randomly flip the direction every once in a while
int minAlpha = 100; // Min value of brightness
int maxAlpha = 250; // Max value of brightness
int alphaDelta = 5; // Delta of brightness between times through the loop

void setup() {
  strip.begin();
  strip.show(); // Initialize all pixels to 'off'
}

void loop() {
  flip = random(32);
  if(flip > 20) {
    dir = 1 - dir;
  }
  // Some example procedures showing how to display to the pixels:
  if (dir == 1) {
    alpha += alphaDelta;
  }
  if (dir == 0) {
    alpha -= alphaDelta;
  }
  if (alpha < minAlpha) {
    alpha = minAlpha;
    dir = 1;
  }
  if (alpha > maxAlpha) {
    alpha = maxAlpha;
    dir = 0;
  }
  // Change the line below to alter the color of the lights
  // The numbers represent the Red, Green, and Blue values
  // of the lights, as a value between 0(off) and 1(max brightness)
  //
  // EX:
  // colorSet(strip.Color(alpha, 0, alpha/2)); // Pink
  colorSet(strip.Color(0, 0, alpha)); // Blue
  //colorSet(strip.Color(alpha, alpha/2, 0)); // Yellow
  //colorSet(strip.Color(alpha, 0, 0)); // Red
}

// Fill the dots one after the other with a color
void colorSet(uint32_t c) {
  for(uint16_t i=0; i<strip.numPixels(); i++) {
      strip.setPixelColor(i, c);
      strip.show();
  }
}

Look out for Angler Fish Part 2 next year!!!!

Haosen’s Halloween galaxy Angel

My Halloween costume concept is an angel who governs the workings of the galaxy. The various spheres on my head represent planets of different sizes, while the wings on my back symbolize my angelic identity.

For the galaxy horn decoration on the head:

Materials used:

  1. acrylic sphere: link attached
  2. Iron wire:Different Dimensions (VFL)
  3. Small led strip for the little balls (Becky)
  4. Glow-in-the-dark white paint: link attached
  5. horn (amazon and shame!!): Link attached

Making process and refection:

My process involved painting the inside of small transparent acrylic spheres with glow-in-the-dark paint to simulate planetary atmospheres. I connected these spheres with wires in a circular arrangement. After completing the soldering for the LED string lights, gamma, and switch, I placed the LED string inside, making the spheres glow. Finally, I attached them to a horned headpiece.

Throughout this project, I learned some valuable lessons. One was the importance of ensuring that no other coating is on the wires before soldering; they need to be sanded down first. Also, during testing, it’s essential to solder everything first and then conduct tests. I also learned some Arduino programming knowledge.

If I were to make this decoration again, I might suspend the galaxy spheres above my head using wire. I’d also consider adding a motor and corresponding Arduino code to make my “galaxy” rotate.

My Arduino Code

My Circuit Diagram:

For the angel wing:

Materials used:

  1. Warping foam: Fedex
  2. Iron wire: VFL
  3. Old white T-shirt

Making process and refection:

I started my wing-making process with a wire frame for the structure. Then, I used fabric from old clothes to create a flat surface between the wires. I cut foam into three different sizes—large, medium, and small—to mimic feathers and glued them in the natural growth direction on the wings. Finally, I used curved wires to wrap the wings around my arms for support.

Throughout this project, I learned the importance of collaboration. A big thanks to Tong and Ana for helping me to achieve this last-minute idea, and to Monty, who taught me how to secure the wires. If I were to make the wings again, I’d make the back fuller to give them a more authentic wing-like appearance.

Thanks for listening and watching!!!

Qianyue’s Luminous Flight

For Halloween, I designed a glowing butterfly headpiece, inspired by the elegance and vibrance of blue butterflies. The headpiece is adorned with artificial butterflies and small LED lights woven through blue, glittery fabric to create a whimsical, ethereal effect. I chose this concept because butterflies symbolize transformation and beauty—perfect for a night of costumes and creativity.

Throughout the process, I learned a lot about wiring and working with LEDs to achieve the right brightness. One thing I’d do differently is adjust the wiring to make it less visible, perhaps by hiding it within thicker fabric or creating a dedicated channel for the wires.

Materials Used:

  • Artificial butterflies
  • Blue glitter fabric
  • LED string lights
  • Battery pack
  • Wire
#include <Adafruit_NeoPixel.h>

#define PIN 1

#define NUM_LEDS 8

#define BRIGHTNESS 50

// Parameter 1 = number of pixels in strip
// Parameter 2 = pin number (most are valid)
// Parameter 3 = pixel type flags, add together as needed:
//   NEO_RGB     Pixels are wired for RGB bitstream
//   NEO_GRB     Pixels are wired for GRB bitstream, correct if colors are swapped upon testing
//   NEO_RGBW    Pixels are wired for RGBW bitstream
//   NEO_KHZ400  400 KHz bitstream (e.g. FLORA pixels)
//   NEO_KHZ800  800 KHz bitstream (e.g. High Density LED strip), correct for neopixel stick
Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_LEDS, PIN, NEO_GRBW + NEO_KHZ800);

void setup() {

  strip.setBrightness(BRIGHTNESS);
  strip.begin();
  strip.show(); // Initialize all pixels to 'off'
}

void loop() {
  // Alternate fading between blue and purple
  fadeColor(strip.Color(0, 0, 255));   // Blue
  fadeColor(strip.Color(128, 0, 128)); // Purple
}

// Function to fade in and out a specified color
void fadeColor(uint32_t color) {
  // Gradually increase brightness
  for (int brightness = 0; brightness <= 255; brightness += 5) {
    setStripColor(color, brightness);
    delay(30); // Adjust delay for slower or faster fade
  }
  
  // Gradually decrease brightness
  for (int brightness = 255; brightness >= 0; brightness -= 5) {
    setStripColor(color, brightness);
    delay(30); // Adjust delay for slower or faster fade
  }
}

// Function to set all LEDs to a specific color with specified brightness
void setStripColor(uint32_t color, int brightness) {
  uint8_t r = (color >> 16) & 0xFF;
  uint8_t g = (color >>  8) & 0xFF;
  uint8_t b =  color        & 0xFF;

  // Apply brightness scaling
  r = (r * brightness) / 255;
  g = (g * brightness) / 255;
  b = (b * brightness) / 255;

  // Set color for all LEDs
  for (int i = 0; i < strip.numPixels(); i++) {
    strip.setPixelColor(i, strip.Color(r, g, b));
  }
  strip.show();
}

}

// Fill the dots one after the other with a color
void colorWipe(uint32_t c, uint8_t wait) {
  for(uint16_t i=0; i<strip.numPixels(); i++) {
    strip.setPixelColor(i, c);
    strip.show();
    delay(wait);
  }
}

void pulseWhite(uint8_t wait) {
  for(int j = 0; j < 256 ; j++){
      for(uint16_t i=0; i<strip.numPixels(); i++) {
          strip.setPixelColor(i, strip.Color(0,0,0, j ) );
        }
        delay(wait);
        strip.show();
      }

  for(int j = 255; j >= 0 ; j--){
      for(uint16_t i=0; i<strip.numPixels(); i++) {
          strip.setPixelColor(i, strip.Color(0,0,0, j ) );
        }
        delay(wait);
        strip.show();
      }
}


void rainbowFade2White(uint8_t wait, int rainbowLoops, int whiteLoops) {
  float fadeMax = 100.0;
  int fadeVal = 0;
  uint32_t wheelVal;
  int redVal, greenVal, blueVal;

  for(int k = 0 ; k < rainbowLoops ; k ++){
    
    for(int j=0; j<256; j++) { // 5 cycles of all colors on wheel

      for(int i=0; i< strip.numPixels(); i++) {

        wheelVal = Wheel(((i * 256 / strip.numPixels()) + j) & 255);

        redVal = red(wheelVal) * float(fadeVal/fadeMax);
        greenVal = green(wheelVal) * float(fadeVal/fadeMax);
        blueVal = blue(wheelVal) * float(fadeVal/fadeMax);

        strip.setPixelColor( i, strip.Color( redVal, greenVal, blueVal ) );

      }

      //First loop, fade in!
      if(k == 0 && fadeVal < fadeMax-1) {
          fadeVal++;
      }

      //Last loop, fade out!
      else if(k == rainbowLoops - 1 && j > 255 - fadeMax ){
          fadeVal--;
      }

        strip.show();
        delay(wait);
    }
  
  }



  delay(500);


  for(int k = 0 ; k < whiteLoops ; k ++){

    for(int j = 0; j < 256 ; j++){

        for(uint16_t i=0; i < strip.numPixels(); i++) {
            strip.setPixelColor(i, strip.Color(0,0,0, j ) );
          }
          strip.show();
        }

        delay(2000);
    for(int j = 255; j >= 0 ; j--){

        for(uint16_t i=0; i < strip.numPixels(); i++) {
            strip.setPixelColor(i, strip.Color(0,0,0, j ) );
          }
          strip.show();
        }
  }

  delay(500);


}

void whiteOverRainbow(uint8_t wait, uint8_t whiteSpeed, uint8_t whiteLength ) {
  
  if(whiteLength >= strip.numPixels()) whiteLength = strip.numPixels() - 1;

  int head = whiteLength - 1;
  int tail = 0;

  int loops = 3;
  int loopNum = 0;

  static unsigned long lastTime = 0;


  while(true){
    for(int j=0; j<256; j++) {
      for(uint16_t i=0; i<strip.numPixels(); i++) {
        if((i >= tail && i <= head) || (tail > head && i >= tail) || (tail > head && i <= head) ){
          strip.setPixelColor(i, strip.Color(0,0,0, 255 ) );
        }
        else{
          strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + j) & 255));
        }
        
      }

      if(millis() - lastTime > whiteSpeed) {
        head++;
        tail++;
        if(head == strip.numPixels()){
          loopNum++;
        }
        lastTime = millis();
      }

      if(loopNum == loops) return;
    
      head%=strip.numPixels();
      tail%=strip.numPixels();
        strip.show();
        delay(wait);
    }
  }
  
}
void fullWhite() {
  
    for(uint16_t i=0; i<strip.numPixels(); i++) {
        strip.setPixelColor(i, strip.Color(0,0,0, 255 ) );
    }
      strip.show();
}


// Slightly different, this makes the rainbow equally distributed throughout
void rainbowCycle(uint8_t wait) {
  uint16_t i, j;

  for(j=0; j<256 * 5; j++) { // 5 cycles of all colors on wheel
    for(i=0; i< strip.numPixels(); i++) {
      strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + j) & 255));
    }
    strip.show();
    delay(wait);
  }
}

void rainbow(uint8_t wait) {
  uint16_t i, j;

  for(j=0; j<256; j++) {
    for(i=0; i<strip.numPixels(); i++) {
      strip.setPixelColor(i, Wheel((i+j) & 255));
    }
    strip.show();
    delay(wait);
  }
}

// Input a value 0 to 255 to get a color value.
// The colours are a transition r - g - b - back to r.
uint32_t Wheel(byte WheelPos) {
  WheelPos = 255 - WheelPos;
  if(WheelPos < 85) {
    return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3,0);
  }
  if(WheelPos < 170) {
    WheelPos -= 85;
    return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3,0);
  }
  WheelPos -= 170;
  return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0,0);
}

uint8_t red(uint32_t c) {
  return (c >> 8);
}
uint8_t green(uint32_t c) {
  return (c >> 16);
}
uint8_t blue(uint32_t c) {
  return (c);
}

Eva ‘s Halloween Cloudy Umbrella

This Halloween, I designed a unique “cloud umbrella” that lights up like a storm! 🌧️✨ The canopy is covered with fluffy cotton clouds, and raindrop-like details that dangle around the edges. Inside the umbrella, an Arduino setup creates a dramatic lightning effect, with light strips flashing in different intensities to mimic the rumbling storm. ⚡️💡


In past Halloweens, I always went with smaller accessories, like masks or hats. But this year, with a bit more time and the chance to get creative, I wanted to make something bigger – and that’s how the Storm Cloud Umbrella was born! I have to admit, I’m really happy with how it looks. However, it turned out way heavier than I expected. (I used the cheapest umbrella I could find, and the frame couldn’t handle the weight of the chains, so I had to reinforce it with wire, which made it even heavier.) Carrying it around is definitely a workout!

My materials are: clear umbrella, cotton, wire, decorations that look like raindrops, glue gun, strong glue, insulating tape, and my circuit board.

This is what it looks like without the cotton, a bald head~🧑‍🦲

Circuit Diagram: 

Here’s the final look. ⚡️⚡️⚡️⚡️⚡️⚡️⚡️⚡️⚡️⚡️⚡️⚡️⚡️⚡️⚡️⚡️⚡️⚡️⚡️⚡️⚡️⚡️⚡️⚡️⚡️⚡️⚡️⚡️

This is what it looks like after it’s been through the crowds. 😱

My Code:

// Simple demonstration on using an input device to trigger changes on your

// NeoPixels. Wire a momentary push button to connect from ground to a

// digital IO pin. When the button is pressed it will change to a new pixel

// animation. Initial state has all pixels off -- press the button once to

// start the first animation. As written, the button does not interrupt an

// animation in-progress, it works only when idle.

// Here is where you can put in your favorite colors that will appear!

// just add new {nnn, nnn, nnn}, lines. They will be picked out randomly

// R G B

uint8_t myFavoriteColors[][3] = {{200, 200, 200}, // white

{200, 200, 0}, // yellow

{200, 200, 200}, // white

};

// don't edit the line below

#define FAVCOLORS sizeof(myFavoriteColors) / 3

#include <Adafruit_NeoPixel.h>

#ifdef __AVR__

#include <avr/power.h> // Required for 16 MHz Adafruit Trinket

#endif

// Digital IO pin connected to the button. This will be driven with a

// pull-up resistor so the switch pulls the pin to ground momentarily.

// On a high -> low transition the button press logic will execute.

#define BUTTON_PIN 2

#define PIXEL_PIN 1 // Digital IO pin connected to the NeoPixels.

#define PIXEL_COUNT 28 // Number of NeoPixels

// Declare our NeoPixel strip object:

Adafruit_NeoPixel strip(PIXEL_COUNT, PIXEL_PIN, NEO_GRB + NEO_KHZ800);

// Argument 1 = Number of pixels in NeoPixel strip

// Argument 2 = Arduino pin number (most are valid)

// Argument 3 = Pixel type flags, add together as needed:

// NEO_KHZ800 800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)

// NEO_KHZ400 400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)

// NEO_GRB Pixels are wired for GRB bitstream (most NeoPixel products)

// NEO_RGB Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)

// NEO_RGBW Pixels are wired for RGBW bitstream (NeoPixel RGBW products)

boolean oldState = HIGH;

int mode = 0; // Currently-active animation mode, 0-9

void setup() {

pinMode(BUTTON_PIN, INPUT_PULLUP);

strip.begin(); // Initialize NeoPixel strip object (REQUIRED)

strip.show(); // Initialize all pixels to 'off'

}

void loop() {

// Get current button state.

boolean newState = digitalRead(BUTTON_PIN);

// Check if state changed from high to low (button press).

if((newState == LOW) && (oldState == HIGH)) {

// Short delay to debounce button.

delay(20);

// Check if button is still low after debounce.

newState = digitalRead(BUTTON_PIN);

if(newState == LOW) { // Yes, still low

if(++mode > 2) mode = 0; // Advance to next mode, wrap around after #8

switch(mode) { // Start the new animation...

case 0:

//colorWipe(strip.Color( 0, 0, 0), 50); // Black/off

flashRandom(5, 20);

flashRandom(5, 20);

flashRandom(5, 20);

flashRandom(5, 20);

break;

case 1:

flashRandom(5, 20);

flashRandom(5, 12);

flashRandom(5, 15);

flashRandom(5, 10);

flashRandom(5, 2);

flashRandom(5, 2);

flashRandom(5, 2);

flashRandom(5, 2);

break;

}

}

}

// Set the last-read button state to the old state.

oldState = newState;

}

// Fill strip pixels one after another with a color. Strip is NOT cleared

// first; anything there will be covered pixel by pixel. Pass in color

// (as a single 'packed' 32-bit value, which you can get by calling

// strip.Color(red, green, blue) as shown in the loop() function above),

// and a delay time (in milliseconds) between pixels.

void colorWipe(uint32_t color, int wait) {

for(int i=0; i<strip.numPixels(); i++) { // For each pixel in strip...

strip.setPixelColor(i, color); // Set pixel's color (in RAM)

strip.show(); // Update strip to match

delay(wait); // Pause for a moment

}

}

// Theater-marquee-style chasing lights. Pass in a color (32-bit value,

// a la strip.Color(r,g,b) as mentioned above), and a delay time (in ms)

// between frames.

void theaterChase(uint32_t color, int wait) {

for(int a=0; a<10; a++) { // Repeat 10 times...

for(int b=0; b<3; b++) { // 'b' counts from 0 to 2...

strip.clear(); // Set all pixels in RAM to 0 (off)

// 'c' counts up from 'b' to end of strip in steps of 3...

for(int c=b; c<strip.numPixels(); c += 3) {

strip.setPixelColor(c, color); // Set pixel 'c' to value 'color'

}

strip.show(); // Update strip with new contents

delay(wait); // Pause for a moment

}

}

}

// Rainbow cycle along whole strip. Pass delay time (in ms) between frames.

void rainbow(int wait) {

// Hue of first pixel runs 3 complete loops through the color wheel.

// Color wheel has a range of 65536 but it's OK if we roll over, so

// just count from 0 to 3*65536. Adding 256 to firstPixelHue each time

// means we'll make 3*65536/256 = 768 passes through this outer loop:

for(long firstPixelHue = 0; firstPixelHue < 3*65536; firstPixelHue += 256) {

for(int i=0; i<strip.numPixels(); i++) { // For each pixel in strip...

// Offset pixel hue by an amount to make one full revolution of the

// color wheel (range of 65536) along the length of the strip

// (strip.numPixels() steps):

int pixelHue = firstPixelHue + (i * 65536L / strip.numPixels());

// strip.ColorHSV() can take 1 or 3 arguments: a hue (0 to 65535) or

// optionally add saturation and value (brightness) (each 0 to 255).

// Here we're using just the single-argument hue variant. The result

// is passed through strip.gamma32() to provide 'truer' colors

// before assigning to each pixel:

strip.setPixelColor(i, strip.gamma32(strip.ColorHSV(pixelHue)));

}

strip.show(); // Update strip with new contents

delay(wait); // Pause for a moment

}

}

// Rainbow-enhanced theater marquee. Pass delay time (in ms) between frames.

void theaterChaseRainbow(int wait) {

int firstPixelHue = 0; // First pixel starts at red (hue 0)

for(int a=0; a<30; a++) { // Repeat 30 times...

for(int b=0; b<3; b++) { // 'b' counts from 0 to 2...

strip.clear(); // Set all pixels in RAM to 0 (off)

// 'c' counts up from 'b' to end of strip in increments of 3...

for(int c=b; c<strip.numPixels(); c += 3) {

// hue of pixel 'c' is offset by an amount to make one full

// revolution of the color wheel (range 65536) along the length

// of the strip (strip.numPixels() steps):

int hue = firstPixelHue + c * 65536L / strip.numPixels();

uint32_t color = strip.gamma32(strip.ColorHSV(hue)); // hue -> RGB

strip.setPixelColor(c, color); // Set pixel 'c' to value 'color'

}

strip.show(); // Update strip with new contents

delay(wait); // Pause for a moment

firstPixelHue += 65536 / 90; // One cycle of color wheel over 90 frames

}

}

}

void flashRandom(int wait, uint8_t howmany) {

for(uint16_t i=0; i<howmany; i++) {

// pick a random favorite color!

int c = random(FAVCOLORS);

int red = myFavoriteColors[c][0];

int green = myFavoriteColors[c][1];

int blue = myFavoriteColors[c][2];

// get a random pixel from the list

int j = random(strip.numPixels());

//Serial.print("Lighting up "); Serial.println(j);

// now we will 'fade' it in 5 steps

for (int x=0; x < 5; x++) {

int r = red * (x+1); r /= 5;

int g = green * (x+1); g /= 5;

int b = blue * (x+1); b /= 5;

strip.setPixelColor(j, strip.Color(r, g, b));

strip.show();

delay(wait);

}

// & fade out in 5 steps

for (int x=5; x >= 0; x--) {

int r = red * x; r /= 5;

int g = green * x; g /= 5;

int b = blue * x; b /= 5;

strip.setPixelColor(j, strip.Color(r, g, b));

strip.show();

delay(wait);

}

}

// LEDs will be off when done (they are faded to 0)

}

And, I like all of us in our costumes! This Halloween was awesome!

Ana and Sophia’s Simlish Halloween!

Sul sul!

For Halloween this year we dressed up as the Pleasant sisters, Lilith and Angela Pleasant, from the Sims including a Plumbob with lights to display all of the different Sims’ emotions.

I, Ana, grew up playing Sims (maybe too early in my life) and I’ve always wanted to be a Sim for Halloween. When we were brainstorming ideas for Halloween, I shared with Sophia that I was thinking of being a Sim, and she loved the idea. On that day… Sophia and I became Sims, the Pleasant sisters to be exact. Overall, it was really fun to get dressed up and be a Sim for a little bit but I do think we can make some improvements. It felt pretty uncomfortable and not too secure to be wearing a wig and a headband and a tall wire on our heads, so I think for next time, maybe we would make the height of the Plumbob a little shorter so the weight distribution doesn’t have as much effect. Also maybe we would professionally hire someone to put the wigs on us 😅

and I, Sophia, approve this message hehe

Materials and parts used:

  1. Blank Mylar Stencil Sheets
  2. Headband
  3. Red wig
  4. 20 gauge wire from VFL
  5. Cute outfit <3
  6. Gemma M0
  7. 2x NeoPixel LED Strips
  8. Plumbob template below

After much trial and tribulation here is our Arduino code that triggers the 5 different Sims color emotions with the push of a button on our headbands

// Simple demonstration on using an input device to trigger changes on your
// NeoPixels. Wire a momentary push button to connect from ground to a
// digital IO pin. When the button is pressed it will change to a new pixel
// animation. Initial state has all pixels off -- press the button once to
// start the first animation. As written, the button does not interrupt an
// animation in-progress, it works only when idle.

#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
 #include <avr/power.h> // Required for 16 MHz Adafruit Trinket
#endif

// Digital IO pin connected to the button. This will be driven with a
// pull-up resistor so the switch pulls the pin to ground momentarily.
// On a high -> low transition the button press logic will execute.
#define BUTTON_PIN   2

#define PIXEL_PIN    1  // Digital IO pin connected to the NeoPixels.

#define PIXEL_COUNT 8  // Number of NeoPixels

// Declare our NeoPixel strip object:
Adafruit_NeoPixel strip(PIXEL_COUNT, PIXEL_PIN, NEO_GRBW + NEO_KHZ800);
// Argument 1 = Number of pixels in NeoPixel strip
// Argument 2 = Arduino pin number (most are valid)
// Argument 3 = Pixel type flags, add together as needed:
//   NEO_KHZ800  800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
//   NEO_KHZ400  400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)
//   NEO_GRB     Pixels are wired for GRB bitstream (most NeoPixel products)
//   NEO_RGB     Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)
//   NEO_RGBW    Pixels are wired for RGBW bitstream (NeoPixel RGBW products)

boolean oldState = HIGH;
int     mode     = 0;    // Currently-active animation mode, 0-9

void setup() {
  pinMode(BUTTON_PIN, INPUT_PULLUP);
    strip.setBrightness(150); // Set BRIGHTNESS to about 1/5 (max = 255)
  strip.begin(); // Initialize NeoPixel strip object (REQUIRED)
  strip.show();  // Initialize all pixels to 'off'

  //Serial.begin(9600); 
  
}

void loop() {
  // Get current button state.

  boolean newState = digitalRead(BUTTON_PIN);

/*
  if (newState == 1){
    colorWipe(strip.Color(0,   255,   0), 50);
  }

  if (newState == 0){
    colorWipe(strip.Color(0,   0,   0), 50);
  }
*/
  //Serial.print(newState);

  // Check if state changed from high to low (button press).
  if((newState == 0) && (oldState == 1)) {
    // Short delay to debounce button.
    delay(20);
    // Check if button is still low after debounce.
    newState = digitalRead(BUTTON_PIN);
    //if(newState == 0) {      // Yes, still low
      if(++mode > 7) mode = 0; // Advance to next mode, wrap around after #8
      switch(mode) {           // Start the new animation...
        case 0:
          colorWipe(strip.Color(  0,   0,   0), 50);    // Black/off
          break;
        case 1:
          colorWipe(strip.Color(0,   255,   0), 50);    // Green
          break;
        case 2:
          colorWipe(strip.Color(  255, 0,   0), 50);    // Red
          break;
        case 3:
          colorWipe(strip.Color(  0,   0, 255), 50);    // Dark Blue
          break;
        case 4:
          colorWipe(strip.Color(255, 80, 147), 50); // Pink
          break;
        case 5:
          colorWipe(strip.Color(255,   255,   0), 50); // Yellow
          break;
      }
    //}
  }

  // Set the last-read button state to the old state.
  oldState = newState;
}

// Fill strip pixels one after another with a color. Strip is NOT cleared
// first; anything there will be covered pixel by pixel. Pass in color
// (as a single 'packed' 32-bit value, which you can get by calling
// strip.Color(red, green, blue) as shown in the loop() function above),
// and a delay time (in milliseconds) between pixels.
void colorWipe(uint32_t color, int wait) {
  for(int i=0; i<strip.numPixels(); i++) { // For each pixel in strip...
    strip.setPixelColor(i, color);         //  Set pixel's color (in RAM)
    strip.show();                          //  Update strip to match
    delay(wait);                           //  Pause for a moment
  }
}

// Theater-marquee-style chasing lights. Pass in a color (32-bit value,
// a la strip.Color(r,g,b) as mentioned above), and a delay time (in ms)
// between frames.
void theaterChase(uint32_t color, int wait) {
  for(int a=0; a<10; a++) {  // Repeat 10 times...
    for(int b=0; b<3; b++) { //  'b' counts from 0 to 2...
      strip.clear();         //   Set all pixels in RAM to 0 (off)
      // 'c' counts up from 'b' to end of strip in steps of 3...
      for(int c=b; c<strip.numPixels(); c += 3) {
        strip.setPixelColor(c, color); // Set pixel 'c' to value 'color'
      }
      strip.show(); // Update strip with new contents
      delay(wait);  // Pause for a moment
    }
  }
}

// Rainbow cycle along whole strip. Pass delay time (in ms) between frames.
void rainbow(int wait) {
  // Hue of first pixel runs 3 complete loops through the color wheel.
  // Color wheel has a range of 65536 but it's OK if we roll over, so
  // just count from 0 to 3*65536. Adding 256 to firstPixelHue each time
  // means we'll make 3*65536/256 = 768 passes through this outer loop:
  for(long firstPixelHue = 0; firstPixelHue < 3*65536; firstPixelHue += 256) {
    for(int i=0; i<strip.numPixels(); i++) { // For each pixel in strip...
      // Offset pixel hue by an amount to make one full revolution of the
      // color wheel (range of 65536) along the length of the strip
      // (strip.numPixels() steps):
      int pixelHue = firstPixelHue + (i * 65536L / strip.numPixels());
      // strip.ColorHSV() can take 1 or 3 arguments: a hue (0 to 65535) or
      // optionally add saturation and value (brightness) (each 0 to 255).
      // Here we're using just the single-argument hue variant. The result
      // is passed through strip.gamma32() to provide 'truer' colors
      // before assigning to each pixel:
      strip.setPixelColor(i, strip.gamma32(strip.ColorHSV(pixelHue)));
    }
    strip.show(); // Update strip with new contents
    delay(wait);  // Pause for a moment
  }
}

// Rainbow-enhanced theater marquee. Pass delay time (in ms) between frames.
void theaterChaseRainbow(int wait) {
  int firstPixelHue = 0;     // First pixel starts at red (hue 0)
  for(int a=0; a<30; a++) {  // Repeat 30 times...
    for(int b=0; b<3; b++) { //  'b' counts from 0 to 2...
      strip.clear();         //   Set all pixels in RAM to 0 (off)
      // 'c' counts up from 'b' to end of strip in increments of 3...
      for(int c=b; c<strip.numPixels(); c += 3) {
        // hue of pixel 'c' is offset by an amount to make one full
        // revolution of the color wheel (range 65536) along the length
        // of the strip (strip.numPixels() steps):
        int      hue   = firstPixelHue + c * 65536L / strip.numPixels();
        uint32_t color = strip.gamma32(strip.ColorHSV(hue)); // hue -> RGB
        strip.setPixelColor(c, color); // Set pixel 'c' to value 'color'
      }
      strip.show();                // Update strip with new contents
      delay(wait);                 // Pause for a moment
      firstPixelHue += 65536 / 90; // One cycle of color wheel over 90 frames
    }
  }
}

And here is our circuit diagram

Along with a few in-progress sketches and images

Dag Dag 🙂