Hi @sgroen,
It is possible to write in the traditional way, writing values into arrays.
Most neopixel APIs have something like setPixel(index, r,g,b)
and patterns often fill the led buffer by iterating from 0 to the number of pixels. Some patterns work by selectively updating the values, or using the previous values in the next frame. These styles are also possible in Pixelblaze using arrays. Sparks and blinkfade and KITT are some examples.
The Pixelblaze way is more math centric. There’s no right or wrong way.
You want to have 3 red pixels run around in a blue background.
The first thing that pops up in my mind is keeping track of only 1, and then repeating or mirroring it 3 times. It would be fairly easy to calculate the others, and you could then make the number of red pixels configurable.
So we’d have a variable that keeps track of where this pixel is. We’ll need to know how fast to move it. For smooth animation, we’ll keep track of subpixel position, and add an amount to the position each animation frame. We could ‘draw’ it into an array 3 times (offset by 1/3 if the strip each time), but it’s also possible to check with some math in the render function.
Here’s a version that does it with arrays, using a tiny API that is similar to what you would find in other microcontroller libraries for driving LEDs:
//keep track of pixels
var pixels = array(pixelCount)
//keep track of current pixel position
export var position = 0
//set a variable for how much it should move for each frame
var speed = 10 //in pixels/sec
var blueHue = 2/3
var redHue = 0/3
//helper to set a pixel
function setPixel(index, color) {
pixels[index] = color
}
//helper to set the whole strip
function setStrip(color) {
var i
for (i = 0; i < pixelCount; i++) {
setPixel(i, color)
}
}
//all the work is done here, once per animation frame
export function beforeRender(delta) {
var i, pixelIndex
//erase the array, filling it with "blue"
setStrip(blueHue)
//move the position, wrapping back to the start if its past the end
//delta is in ms, so dividing by 1000 we get a number proportional to how much of a second has ellapsed.
//multpling by speed then will give us that many pixels per second
position = position + speed * delta / 1000
position = position % pixelCount //"wrap" to keep the value inside of the strip using modulus math
//By the way, here's another way to "wrap" that is less mathy
/*
if (position >= pixelCount)
position = 0;
*/
//draw the 3 pixels by looping 3 times, and drawing the position advanced by 1/3rd of the strip offset each time
for (i = 0; i < 3; i++) {
//pixelCount / 3 gives us 1/3rd, and multiplying that by 'i' will give us [0/3, 1/3, and 2/3] of the strip.
//recall that position is a real number, and 1/3rd of a strip might have some fractional component
//taking the floor gives us an integer (whole number) that can be used to acess an array
pixelIndex = floor(position + (i * pixelCount / 3))
pixelIndex = pixelIndex % pixelCount //"wrap" to keep the value inside of the strip using modulus math
//draw a blue pixel at each of these positions
setPixel(pixelIndex, redHue)
}
}
export function render(index) {
//the render function is simplified, it only will pluck hue values from the array
h = pixels[index]
s = 1
v = 1
hsv(h, s, v)
}
Three Red Pixels (array).epe (7.3 KB)
And here’s a version that does it in a more math heavy way:
//keep track of pixels
var pixels = array(pixelCount)
//keep track of current pixel position
export var position = 0
//set a variable for how much it should move for each frame
var speed = 10 //in pixels/sec
var blueHue = 2/3
var redHue = 0/3
//we will use modulus math to wrap the index in a space that is 1/3rd pixelCount
var numRedPixels = 3
var wrapDistance = floor(pixelCount/numRedPixels)
export function beforeRender(delta) {
//move the position, wrapping back to the start if its past the end
//delta is in ms, so dividing by 1000 we get a number proportional to how much of a second has ellapsed.
//multpling by speed then will give us that many pixels per second
position = position + speed * delta / 1000
position = position % pixelCount //"wrap" to keep the value inside of the strip using modulus math
//By the way, here's another way to "wrap" that is less mathy
/*
if (position >= pixelCount)
position = 0;
*/
}
export function render(index) {
//the current position is subtracted from the current pixel index (along with a healthy buffer that will be removed by the modulus)
//this is effectively shifting things to the right and won't go negative
//take the floor of that, and check to see if its zero (any value up to 1/3rd of the pixelCount would do). If so, its one of the pixels or its mirrors.
if (floor((pixelCount + index - position) % wrapDistance) == 0) {
h = redHue
} else {
h = blueHue
}
s = 1
v = 1
hsv(h, s, v)
}
Three Red Pixels (mathy).epe (6.8 KB)
Both are also up on the pattern site.
I hope that helps give you some different ideas towards implementing patterns you want to create. I think the most important tip is to break the problem down into small parts. I think about how to model the effect, such as the position and speed, and then how to translate that model into pixels. I can’t claim its easy, and I’m open to ideas and suggestions for different ways of doing it that might be easier!