Skip to content

Programmable LED Art with NeoPixel/WS2812B

Summary

This chapter covers the $15 Moving Rainbow-style NeoPixel kit: how addressable WS2812B LEDs are chained and controlled over a single data line, and the RGB color model (hue, saturation, brightness, color mixing) used to specify any color. It walks through the NeoPixel library's core methods -- fill, set pixel color, and show -- and builds up to animation techniques including color fades, chase effects, sparkle effects, rainbow cycles, and custom color palettes, along with the power budget considerations of driving many LEDs at once. Students finishing this chapter will be able to wire a NeoPixel strip to a Pico and program an original color animation.

Concepts Covered

This chapter covers the following 32 concepts from the learning graph:

  1. NeoPixel
  2. WS2812B LED
  3. Addressable LED
  4. RGB Color Model
  5. RGB Value
  6. Color Mixing
  7. Hue
  8. Saturation
  9. Brightness
  10. Pixel Index
  11. LED Strip
  12. Data Line
  13. Chained LED Protocol
  14. Color Wheel
  15. Rainbow Cycle
  16. Animation Frame
  17. Frame Rate
  18. Color Fade
  19. Chase Animation
  20. Sparkle Animation
  21. Color Palette
  22. Neopixel Library
  23. Show Method
  24. Fill Method
  25. Set Pixel Color
  26. Brightness Scaling
  27. Power Budget For LEDs
  28. Current Draw Per LED
  29. Wearable Electronics
  30. LED Diffuser
  31. Light Painting
  32. Color Theory

Prerequisites

This chapter builds on concepts from:


Let's Paint With Light

Berry waving welcome You've blinked a single LED — now let's control a hundred of them at once, in any color you can imagine, with a single wire. This chapter is the $15 Moving Rainbow-style kit come to life: color theory, addressable LEDs, and enough animation techniques to build something nobody's seen before. Let's build something!

Every LED you wired in Chapters 3 and 4 needed its own GPIO pin and its own current-limiting resistor. That approach works fine for one or two LEDs, but it falls apart fast if you want to control fifty of them independently — you'd run out of pins long before you ran out of ideas. This chapter introduces the component that solves that problem, and turns "one LED" into "programmable LED art."

Before zooming in on the NeoPixel specifically, the poster below places it alongside the single LED from Chapter 3, the RGB LED, and the LED matrix — the four LED technologies you're most likely to meet in a project.

Diagram: LED Types Compared

Run the LED Types Compared poster fullscreen

LED Types Compared (reused poster)

Type: interactive-infographic-poster
sim-id: led-types
Status: Reused
Source: https://dmccreary.github.io/learning-micropython/posters/led-types/
Source Repo: https://github.com/dmccreary/learning-micropython/tree/main/docs/posters/led-types

Reused from the companion book Learning MicroPython's poster catalog. Positions the NeoPixel among the other LED technologies in the book (the single LED from Chapter 3) before this chapter dives into WS2812B specifics.

Meet the NeoPixel

A NeoPixel is Adafruit's brand name for an addressable RGB LED built around the WS2812B LED chip, a small integrated circuit that combines a red, green, and blue LED with its own tiny control chip, all packaged into a single component smaller than a grain of rice. That built-in control chip is what makes a NeoPixel fundamentally different from the plain LED you wired in Chapter 3: each one can be commanded individually to show its own color, remembering that color until it's told to change, without needing a dedicated wire running back to the microcontroller.

That capability has a name: an addressable LED is an LED that can be individually controlled — given its own color and brightness — independently of every other LED on the same circuit, as opposed to a simple LED that only turns fully on or fully off as a whole. Dozens or even hundreds of NeoPixels can be connected together into an LED strip (a flexible circuit board with many NeoPixels mounted in a row, usually with an adhesive backing) or arranged in a grid or matrix, and every pixel on that strip can display a completely different color at the same instant.

How does a single microcontroller pin control that many independent LEDs? The answer is a clever communication protocol. A data line is the single wire that carries color information from the microcontroller to the first NeoPixel on a strip. A chained LED protocol is a communication method where each addressable LED receives a stream of color data over the data line, keeps the portion meant for itself, and forwards the rest of the stream on to the next LED in the chain — so a single data line can control an entire strip, no matter how long it is, because each LED does its own small part of the relay work. Every LED in the chain needs to know which portion of that stream belongs to it, which is where a pixel index comes in: pixel index is the position number of a specific LED within a chained strip, counting from 0 at the LED closest to the microcontroller, used in code to target a single pixel's color without affecting any others.

Berry's Key Insight

Berry thinking This is the whole magic trick of a NeoPixel strip: one data wire, one GPIO pin, and yet every single LED can be its own color. The chained protocol does all the heavy lifting — your code just needs to say "pixel index 12, make it purple" and the data stream handles getting that instruction to the right LED.

Before writing any code, it helps to see this chained handoff happen visually, one pixel at a time.

Diagram: WS2812B Addressable LED Protocol Explorer

Run the WS2812B Addressable LED Protocol Explorer MicroSim fullscreen

WS2812B Addressable LED Protocol Explorer (interactive diagram)

Type: interactive-diagram sim-id: ws2812b-addressable-led-protocol-explorer
Library: p5.js
Status: Specified

Learning objective: Students will explain (Bloom L2: Understand) how a chained LED protocol uses pixel index to deliver color data to a specific addressable LED over a single data line.

Canvas: 700x420px default, responsive — recompute LED spacing as a fraction of windowWidth inside windowResized() so a 12-pixel strip stays fully visible down to 380px wide, wrapping to two rows if needed.

Layout: a horizontal row of 12 circular NeoPixel icons, each labeled with its pixel index (0-11) beneath it, connected left to right by a highlighted data line, with the Pico icon at the far left as the data source.

Controls: a createSlider() labeled "Target Pixel Index" (range 0-11, default 3); a color swatch picker built from three createSlider() instances (Red, Green, Blue, each 0-255); a createButton() labeled "Send Data."

Interaction: clicking "Send Data" animates a small colored packet traveling from the Pico icon along the data line, pausing briefly at each LED in sequence from index 0 upward. At each LED, a brief flash and a "0" or "1" style data-symbol animation shows the LED either "keeping" its assigned color data (if its index matches the slider's target) and lighting up in the chosen RGB color, or "passing it along" (if its index doesn't match) and staying dark while the packet continues rightward. A text log beneath the strip narrates each hop: "Pixel 0: not for me, forwarding..." ending with "Pixel 3: this one's mine!"

Implementation: p5.js. Model the 12 pixels as an array of objects {index, color}; animate the packet's x-position with a per-frame increment, checking proximity to each pixel's x-coordinate to trigger its flash/log-line event. Use createSlider() and createButton() exclusively for controls per project convention, repositioning them inside windowResized().

The RGB Color Model

Every color a NeoPixel displays is built from the same three ingredients. The RGB color model represents any visible color as a combination of red, green, and blue light mixed together at different intensities — the same model your phone or computer screen uses to display every color you see on it. An RGB value is the specific set of three numbers, each typically ranging from 0 to 255, that defines one color under the RGB model — for example, (255, 0, 0) is pure red, (0, 255, 0) is pure green, and (255, 255, 255) is white, because mixing red, green, and blue light at full intensity produces white light. This process of combining different amounts of red, green, and blue to produce a new color is called color mixing, and it works additively — the more of each color channel you add, the closer the result gets to white, which is the opposite of how mixing paint pigments works.

Berry's Tip

Berry sharing a tip If you've ever mixed paint in art class, RGB color mixing will feel backwards at first. Mixing paint colors together tends to get darker and muddier the more colors you add; mixing light colors together gets brighter and eventually reaches white. Light adds up; pigment blocks out.

RGB values are the most direct way to describe a color to a NeoPixel, but they aren't always the most intuitive way for a human to think about color. Three other properties describe color the way people naturally talk about it. Hue is the property of color most people mean when they say "what color is it" — red, orange, yellow, green, blue, or purple — represented as a position, usually in degrees, around a continuous color wheel. Saturation is how vivid or intense a color appears, ranging from a fully saturated, vibrant color at one extreme to a washed-out, grayish version of the same hue at the other. Brightness is how light or dark a color appears overall, independent of hue or saturation — turning brightness all the way down makes any color fade to black, no matter how saturated it started. Together, hue, saturation, and brightness form a second, more human-friendly way of describing exactly the same colors an RGB value describes, and most NeoPixel libraries let you specify color using either system. Understanding both systems, and how they relate to each other, is part of the broader field of color theory — the study of how colors relate to, contrast with, and combine with one another, which artists and designers rely on just as much as programmers building LED art.

Now that RGB values, hue, saturation, and brightness are all defined, let's mix some colors directly.

Diagram: RGB Color Mixer

Run the RGB Color Mixer MicroSim fullscreen

RGB Color Mixer (reused MicroSim)

Type: microsim sim-id: rgb-color-mixer
Library: p5.js
Status: Reused
Source: https://dmccreary.github.io/learning-python/sims/rgb-color-mixer/
Source Repo: https://github.com/dmccreary/learning-python/tree/main/docs/sims/rgb-color-mixer

Reused from the MicroSim catalog (WHAT match score 0.7926). Learning objective: Students will apply (Bloom L3: Apply) the RGB color model by adjusting red, green, and blue sliders to mix a target color and observe the resulting RGB value.

The Color Wheel and Rainbow Cycles

Hue's natural home is a circular diagram rather than a straight line, because color itself wraps back around — spin far enough past violet and you arrive back at red. A color wheel is a circular diagram arranging every hue around a 360-degree circle in the order they appear in a rainbow, positioned so that colors opposite each other on the wheel are the most visually contrasting. Programmatically walking around that wheel, one small step at a time, produces one of the most popular NeoPixel effects in this book: a rainbow cycle is an animation that smoothly shifts every pixel's hue over time (or across position along the strip) by continuously advancing around the color wheel, producing a flowing, colorful pattern with no hard color boundaries.

Before seeing a rainbow cycle rendered directly on a strip, let's connect the color wheel back to hue, defined moments ago, with an interactive version you can spin yourself.

Diagram: Color Wheel and Rainbow Cycle Explorer

Run the Color Wheel and Rainbow Cycle Explorer MicroSim fullscreen

Color Wheel and Rainbow Cycle Explorer (interactive diagram)

Type: interactive-diagram sim-id: color-wheel-rainbow-cycle-explorer
Library: p5.js
Template: https://github.com/dmccreary/moving-rainbow/tree/main/docs/sims/color-wheel
Status: Specified

Learning objective: Students will interpret (Bloom L2: Understand) how rotating a hue value around a color wheel produces a rainbow cycle animation across a simulated NeoPixel strip.

Canvas: 700x460px, responsive — recompute the color wheel's radius and the strip preview's width as fractions of windowWidth inside windowResized(), stacking the wheel above the strip preview below 500px.

Layout: a circular color wheel (top or left panel) with a draggable pointer showing the current hue angle, and a horizontal 12-pixel strip preview (bottom or right panel) beneath it.

Controls: a createSlider() labeled "Rotation Speed" (range 0-10, default 3); a createButton() labeled "Run / Pause" toggling continuous rotation; the color wheel pointer is also directly draggable with the mouse for manual exploration when paused.

Interaction: while running, the pointer sweeps continuously around the wheel, and the strip preview updates every frame so each pixel's hue is offset from its neighbor by a fixed angle, producing a visibly flowing rainbow along the strip. Pausing and manually dragging the pointer to a specific angle freezes the strip preview and displays that angle's exact hue value and equivalent RGB value in a readout beneath the wheel, tying the visual position directly back to the numeric color values from the previous diagram.

Implementation: p5.js. Represent hue as a 0-360 degree float advanced each frame by an amount derived from the speed slider; convert hue (plus fixed saturation/brightness) to RGB using p5's colorMode(HSB) for the wheel and strip rendering. Compute each of the 12 strip pixels' hue as the pointer's current hue plus (pixelIndex * offsetDegrees), wrapping past 360 back to 0.

Programming with the NeoPixel Library

Describing colors is only useful once code can actually push them out to a strip. A NeoPixel library is a pre-written collection of MicroPython functions that handles the low-level chained-LED-protocol timing for you, so your program can simply say what color each pixel should be without managing the data line's exact electrical signal. Three methods from that library cover almost everything you'll do in this chapter. The fill method sets every pixel on the strip to the same color in a single command, which is the fastest way to set a strip's overall color. Set pixel color targets one specific pixel index and assigns it its own RGB value, leaving every other pixel unchanged — this is how a chase or sparkle effect controls individual LEDs. The show method is the command that actually pushes whatever colors you've set (with fill or set pixel color) out along the data line to the physical strip — until you call it, your color changes exist only in the microcontroller's memory, not on the LEDs themselves.

Before the next diagram, one more control belongs alongside these three methods: brightness scaling is a global setting, usually a value between 0.0 and 1.0, that multiplies every pixel's RGB output before it's sent to the strip, letting you dim an entire animation without recalculating every individual color.

Here's what those four pieces look like together in a short program that fills a 12-pixel strip with a single color. The neopixel module's NeoPixel(pin, count) constructor connects to a strip of count pixels wired to pin; strip.fill((r, g, b)) sets every pixel to the given RGB tuple; and strip.show() sends that data out to the physical LEDs.

from machine import Pin
from neopixel import NeoPixel

strip = NeoPixel(Pin(16), 12)   # 12-pixel strip on GPIO 16
strip.fill((0, 100, 255))       # set every pixel to a blue-cyan color
strip.show()                    # push the color data out to the strip

Berry's Tip

Berry sharing a tip Forgetting strip.show() is the single most common NeoPixel bug in this book. Your code can set every pixel's color perfectly and still show a completely dark strip if that last line is missing — the show method is what actually turns "planned colors" into "lit LEDs."

Let's put fill, set pixel color, show, and brightness scaling together in one interactive reference.

Diagram: NeoPixel Library Method Explorer

Run the NeoPixel Library Method Explorer MicroSim fullscreen

NeoPixel Library Method Explorer (MicroSim)

Type: microsim sim-id: neopixel-library-method-explorer
Library: p5.js
Template: https://github.com/dmccreary/moving-rainbow/tree/main/docs/sims/pixel-indexing-explorer
Status: Specified

Learning objective: Students will apply (Bloom L3: Apply) the fill, set pixel color, and show methods, together with brightness scaling, to produce a target appearance on a simulated 12-pixel NeoPixel strip.

Canvas: 700x420px, responsive — recompute the strip preview and code-panel widths from windowWidth inside windowResized(), stacking vertically below 550px.

Data Visibility Requirements: Stage 1: Show a 12-pixel strip preview, all pixels dark, alongside an empty code-so-far panel. Stage 2: As the student clicks method buttons (below), append the corresponding line of code to the code panel and update an internal "pending color buffer" -- but do NOT update the visible strip preview yet, so students see the gap between setting colors and displaying them. Stage 3: Only when "show()" is clicked does the strip preview update to match the pending buffer, visually demonstrating that fill/set-pixel-color changes are invisible until show() runs.

Controls: a createButton() labeled "fill(color)" that opens a small RGB slider popup and appends strip.fill((r,g,b)) when confirmed; a createButton() labeled "setPixelColor(index, color)" that opens both a pixel-index slider (0-11) and an RGB slider popup; a createSlider() labeled "Brightness Scaling" (range 0.0-1.0, default 1.0) that dims the buffer's effect whenever "show()" is next clicked; a createButton() labeled "show()"; a createButton() labeled "Reset."

Interaction: the code panel accumulates a runnable-looking script line by line as the student clicks method buttons, letting them build up a short sequence (e.g., fill blue, then setPixelColor 5 to red, then show) and see the exact resulting strip only once show() is pressed, reinforcing the "nothing changes until show()" rule from the chapter text.

Instructional Rationale: A step-through, data-visible pattern is appropriate for this Apply-level objective because the core misconception this diagram targets -- that fill/setPixelColor alone update the physical strip -- can only be corrected by making the "no visible change yet" state explicit and separate from the "now it's visible" state after show().

Implementation: p5.js. Maintain two parallel 12-element color arrays: pendingBuffer (updated by fill/setPixelColor button actions) and displayedBuffer (only copied from pendingBuffer, scaled by the brightness slider, when "show()" fires). Render the strip from displayedBuffer only. Use createButton() and createSlider() exclusively for controls per project convention.

Animation Techniques

A single static color is only the starting point — the real fun of a NeoPixel strip is making it move. Every animation on a NeoPixel strip is really just a rapid sequence of still images. An animation frame is one single, complete color state of every pixel on the strip, displayed for a brief moment before being replaced by the next frame — exactly like one frame of a movie. Frame rate is how many animation frames are displayed per second, usually written as frames per second (FPS); a higher frame rate produces smoother-looking motion, but pushing too many frames per second at a NeoPixel strip can outrun how fast the chained protocol can physically update every pixel.

With frames and frame rate defined, here are the core animation techniques this chapter's kit is built around:

  • Color fade — smoothly transitioning a pixel (or the whole strip) from one color to another over a series of frames, rather than jumping instantly between them.
  • Chase animation — lighting a small group of pixels that appears to move continuously along the strip, frame by frame, like a marquee sign.
  • Sparkle animation — randomly lighting individual pixels briefly against a darker background, then letting them fade, to imitate twinkling light.
  • Rainbow cycle — the hue-rotation animation introduced earlier in this chapter, continuously shifting color around the color wheel.

Combining several colors intentionally, rather than picking colors at random, is where a color palette comes in: a color palette is a deliberately chosen, limited set of colors used consistently throughout an animation or artwork, which keeps a design visually coherent instead of looking chaotic — the difference between a rainbow cycle (which intentionally uses every hue) and, say, a "sunset" chase animation restricted to just oranges, pinks, and purples.

Berry's Key Insight

Berry thinking Every advanced NeoPixel animation you'll ever see online is built from combining these same few techniques — fade, chase, sparkle, rainbow cycle — layered or sequenced together with a chosen color palette. You already know all the primitives; the art is in how you combine them.

Each technique also has its own personality — some read as calm, some as energetic — which matters when you're designing an animation for a specific mood or occasion rather than just testing that the code works. The table below summarizes the four techniques you just learned, now that every one of them has been explained in prose above.

Technique Visual Feel Frame Rate Sensitivity Typical Use
Color fade Calm, smooth Low — looks fine even at 10-15 FPS Breathing effect, gentle mood lighting
Chase animation Energetic, directional Medium — needs roughly 20+ FPS to look continuous Marquee effect, "loading" indicator
Sparkle animation Playful, random Medium — relies on frequent frame updates to feel lively Starfield effect, festive accents
Rainbow cycle Vibrant, continuous Medium — smoothness depends on both frame rate and hue-step size Full-strip showpiece, demo mode

Notice that frame rate, defined above, isn't equally important to every technique — a slow color fade looks intentional even at a low frame rate, while a chase animation running too slowly starts to look like individual blinks instead of motion. Keeping this table in mind before choosing a frame rate for your own animation will save you some trial and error.

Let's design an animation directly rather than just reading about the techniques.

Diagram: NeoPixel Animation Studio

Run the NeoPixel Animation Studio MicroSim fullscreen

NeoPixel Animation Studio (MicroSim)

Type: microsim sim-id: neopixel-animation-studio
Library: p5.js
Template: https://github.com/dmccreary/moving-rainbow/tree/main/docs/sims/neopixel-wiring-diagram
Status: Specified

Learning objective: Students will create (Bloom L6: Create) an original NeoPixel animation by combining color fade, chase, sparkle, and rainbow cycle techniques with a chosen color palette on a simulated strip.

Canvas: 700x480px, responsive — recompute the strip preview width and control-panel layout from windowWidth inside windowResized().

Layout: a 20-pixel horizontal strip preview along the top, with an animation-technique selector and palette editor beneath it.

Controls: a createSelect() dropdown labeled "Technique" with options "Color Fade," "Chase," "Sparkle," and "Rainbow Cycle" (default: "Chase"); a palette editor of three to five clickable color swatches (default palette: orange, pink, purple) that opens an RGB slider popup when clicked to edit that swatch; a createSlider() labeled "Frame Rate" (range 1-60, default 24); a createButton() labeled "Run / Pause."

Interaction: selecting a technique immediately switches the running animation on the strip preview to that technique, rendered using the current palette's colors (Chase and Sparkle cycle through palette colors per pixel/spark; Fade transitions between consecutive palette colors; Rainbow Cycle ignores the palette and uses the full hue wheel, with a note explaining why). Editing a palette swatch's color updates the running animation's colors live. Dragging the frame rate slider visibly speeds up or slows down the animation, with a readout of the current FPS.

Instructional Rationale: A model-editor / builder pattern is appropriate for this Create-level objective because it gives students direct control over technique, palette, and timing simultaneously, letting them assemble a genuinely original combination rather than only viewing a single fixed example of each technique in isolation.

Implementation: p5.js. Maintain a currentFrame counter advanced by frameRate()-gated logic; each technique function computes all 20 pixels' colors from currentFrame, the selected palette array, and technique-specific parameters (e.g., chase position wraps currentFrame % 20; sparkle uses random() gated by a per-pixel spawn probability). Use createSelect(), createSlider(), and createButton() exclusively for controls per project convention.

First Rainbow!

Berry celebrating However you got there — chase, sparkle, fade, or a full rainbow cycle — that's a strip of light doing something no single LED from Chapter 3 could ever do on its own. That's berry impressive, and it only gets more fun from here.

Powering a Whole Strip Safely

Every NeoPixel draws real current, and a strip with dozens of them adds up fast — this is where Ohm's Law and current from Chapter 3 come back with real consequences. Current draw per LED is the amount of current a single NeoPixel pulls from the power supply, which varies with its brightness and color but tops out around 60 milliamps per pixel at full white brightness. A power budget for LEDs is the total current a NeoPixel strip could draw if every pixel were lit at full brightness simultaneously, calculated by multiplying current draw per LED by the total pixel count — a 60-pixel strip at full white brightness could theoretically demand roughly 3.6 amps, far more than a Pico's own USB power connection can safely supply.

This is exactly why brightness scaling, introduced earlier, matters for more than just aesthetics: reducing brightness scaling to 0.3 cuts that same 60-pixel strip's worst-case draw to roughly 1.1 amps, which is a much more realistic number for a small classroom power supply.

Berry's Gentle Warning

Berry warning Take this one seriously: never assume a Pico's own USB connection can power a long NeoPixel strip at full brightness. Always calculate your power budget before wiring more than a few pixels, and use a separate, appropriately rated power supply for anything longer than about eight pixels at full brightness. Drawing more current than a power source can safely provide can damage the supply, the strip, or both.

Before the final section, let's calculate a real power budget interactively rather than just reading the formula.

Diagram: LED Power Budget Calculator

Run the LED Power Budget Calculator MicroSim fullscreen

LED Power Budget Calculator (MicroSim)

Type: microsim sim-id: led-power-budget-calculator
Library: p5.js
Template: https://github.com/dmccreary/moving-rainbow/tree/main/docs/sims/battery-life-calculator
Status: Specified

Learning objective: Students will calculate (Bloom L3: Apply) the total current draw of a NeoPixel strip from pixel count and brightness scaling, and evaluate (Bloom L5: Evaluate) whether a given power supply can safely support it.

Canvas: 700x400px, responsive — recompute the gauge/readout layout from windowWidth inside windowResized().

Controls: a createSlider() labeled "Pixel Count" (range 1-150, default 60); a createSlider() labeled "Brightness Scaling" (range 0.0-1.0, default 1.0); a createSelect() labeled "Power Supply" with options "Pico USB (~0.5A)," "5V 2A Wall Adapter," and "5V 5A Wall Adapter" (default: "Pico USB (~0.5A)").

Interaction: as any control changes, a live readout recalculates and displays "Worst-case current draw: X.X A" using current draw per LED (60mA) times pixel count times brightness scaling, alongside a horizontal gauge bar comparing that value to the selected power supply's rated current. The gauge bar turns green when the calculated draw is safely under the supply's rating, yellow when it's within 80-100% of the rating, and red with a flashing "Exceeds power supply!" label when the calculated draw exceeds it -- directly dramatizing the chapter's power-budget warning.

Implementation: p5.js. Recompute currentDrawAmps = pixelCount * 0.06 * brightnessScaling every frame from slider state; map that value onto the gauge bar's fill width and color using map() and conditional color logic against the selected supply's rated current. Use createSlider() and createSelect() exclusively for controls per project convention.

Beyond the Breadboard: NeoPixel Art in the Real World

Everything in this chapter scales up into real creative projects once a NeoPixel strip leaves the breadboard. Wearable electronics are electronic components — including NeoPixel strips — integrated into clothing or accessories, designed to be worn and often battery-powered rather than plugged into a wall outlet, which is why the power-budget math from the previous section matters even more once a project leaves your desk. An LED diffuser is a translucent cover, often a strip of frosted plastic or fabric, placed over a NeoPixel strip to soften and blend individual pixel points of light into a smoother glow, which is especially useful in wearable projects where the strip itself shouldn't be visible.

One more creative application deserves a mention before this chapter closes. Light painting is a long-exposure photography technique where a moving light source — such as a NeoPixel strip running a chase or rainbow animation — is captured by a camera over several seconds, recording the light's path as a glowing trail in the final photograph. It's a natural way to show off an original animation you've designed, turning code you wrote into a physical piece of art a camera can capture.

These three ideas — wearable electronics, diffusers, and light painting — combine naturally with everything else in this chapter. A wearable NeoPixel bracelet running a slow color fade behind a diffuser reads as calm and elegant; the same strip run bare, at full brightness, in a fast chase animation and swept through the air during a long-exposure photo becomes a completely different kind of project. Neither approach is more "correct" than the other — the color palette, animation technique, and physical presentation you choose are all creative decisions, not just technical ones, and that combination of decisions is exactly what this book's companion title, Moving Rainbow, explores in much greater depth if this chapter's projects leave you wanting more.

Bringing It Together

You can now explain how a single data line addresses dozens of independent LEDs, mix color using both RGB values and hue/saturation/brightness, and combine fill, set pixel color, and show into real animations — fades, chases, sparkles, and rainbow cycles — built from a deliberate color palette and kept within a safe power budget. This is the first genuinely creative chapter in the book: every NeoPixel project you build from here is limited only by which techniques you choose to combine. The next tier of this book moves from lighting up a strip to building a robot that senses its world and acts on it — and the same fill/setPixelColor/show pattern you just learned will show up again controlling that robot's status lights.

You Unlocked a Superpower!

Berry celebrating That's berry, berry impressive — you just went from a single blinking LED to a fully programmable strip of light art, safely powered and entirely of your own design. STEM is our superpower, and this one's got real sparkle. Let's build something — see you in the next tier of this book!

See Annotated References