In simplest terms my tools were 24 bits of RGB in the NeoPixel itself, and a little bit of time between each redraw of the pixel colors. I wanted something that would be interesting to watch and, while operating within a necessarily fixed set of capabilities, could make you wonder if you really had seen exactly the same thing a bit ago...
There are 7 basic styles of display in the PICsellator:
- Alternating Foreground/Background Floods
- "Fib Rand Sine"
- Strobies in a Flood Field
- Intensity Ramp
- Sine Springboard
- Color Component Leach
- Strobies Leaving a Random Terminal Color
Each style might alone show something interesting but it became much more appealing when they were folded and blended together randomly! We mix in some random determination of colors, sine function parameters, Fibonacci number selection, delays, and deciding if some styles start afresh with a new (random) color blend or use what was left from the previously run style. Oh, and some styles randomly determine at which end of the NeoPixel sequence they start their work.
Here are the basic descriptions of each of the PICsellator's display styles and some notes on where some decisions dip into the randomness bucket:
Alternating Foregound/Background Floods
A PICsellator "flood" is the filling of a selected number (the "stride") of NeoPixels with a color followed by a single instance of a (possibly different) color. This style randomly chooses foreground color, stride, and background color values for two separate floods then alternates between the two floods for a random amount of time with randomly chosen hold times during both the first and second floods.
"Fib Rand Sine"
This display style fills the selected number of pixels with the results of parameterized sine function for each of the red, green, and blue color components. Each of the RGB value functions is parameterized with an amplitude offset, a max amplitude, a phase shift, and a sine function argument multiplicand and divisor. Presently the following parameters are randomly chosen: each color channel's max amplitude and the sine function argument's multiplicand and divisor. The sine function argument's multiplicand is selected from a set of compiled-in values (thank you, math.h!) while the divisor is selected from a set of the first few Fibonacci numbers.
Strobies in a Flood Field
PICsellator "strobies" are short-duration bursts of a relatively high-intensity random color. This display style pops off a random number of strobies in either a randomly selected flood or what was left from a previous style. The pixel's color after the flash is randomly chosen to be either the original pre-flash color or dark.
This style begins with a color created from the random presence or absence of each of red, green, and blue (i.e., a "binary RGB" color). It randomly chooses to "start low" or "start high" and then increases or decreases the intensity of the color at a random rate until reaching a randomly chosen stopping point.
This display style is similar to Fib Rand Sine. However, instead of Red, Green, and Blue operating independently the Green and Blue max amplitudes are based on Red's with an additional random adjustment. Also, the sine function's multiplicand is fixed at pi rather than being chosen from a set of numbers. Subtle, but weird - always a good plan! ;-)
Color Component Leach
This display style is somewhat similar to the Intensity Ramp but with some interesting variations. First, it chooses a blend of red, green, and blue and determines if it's to accrete toward, or leach away from, that color. It then does so by adding/subtracting the red, green, and blue components at a random rate until it reaches the target color (either the originally chosen blend or all-off, respectively).
Strobies Leaving a Random Terminal Color
Candy! This style is similar to the previously mentioned Strobies style but adds the selection of a random color to be left at a pixel following the strobie flash.
How was all this wedged into the tiny little PIC? "Very carefully" and "over many iterations" are probably the best answers as the code sloshed back and forth from "takes too much RAM" to "not enough Program Memory" (and sometimes both)...