
Evil Genius Labs
Custom Electronic Art
Custom Electronic Art
rgb
functionhsv
functionindex
variablepixelCount
variabletime
functionrender3D
functionThe Pixelblaze controller inside your cube allows you to write your own patterns! In fact, you can view and edit the code for every pattern included with it.
Let’s get started writing your first pattern.
If you haven’t already, I would highly recommend going through the tutorials for writing 2D patterns for Pixelblaze. They were created for Lux Lavalier, but they really apply to anything that’s powered by Pixelblaze.
Note:
Any time you see a render2D
function, just rename it to render3D
instead, or you’ll get an error: ⚠️ No valid render function found!
Type (or copy and paste) the following code into the editor:
export function render() {
rgb(1, 0, 0)
}
rgb(0, 1, 0)
and all of the pixels should turn green.rgb(0, 0, 1)
and they’ll turn blue.rgb(.5, 0, .5)
and they’ll turn purple.rgb(1, 1, 1)
and they’ll turn white.Explanation time!
The render function gets called repeatedly, once for each pixel, in order and then wraps from the end back to the beginning. Inside the render function above, we’re calling another function that is included with the Pixelblaze, called rgb
.
rgb
functionEach pixel internally has three LEDs: Red, Green, and Blue. We can directly control those tiny little individual LEDs inside each pixel with the rgb
function. The numbers passed to the function should be between 0.0 and 1.0. A value of 0 turns that LED off completely. A value of 1 turns that LED on completely. Any number in between turns it on a percentage. A value of 0.1 will turn it on at 10% brightness.
The Pixelblaze automatically scales this down with the global brightness you’ve set with the brightness slider in the upper-right corner of the page.
You may have found that it can be a little difficult to get just the right color by mixing different values for red, green, and blue. So let’s explore a different way of handling colors: HSV!
hsv
functionWe can also control the pixel colors by using the hsv
function.
Change the second line of the code to hsv(0, 1, 1)
and all of the pixels should turn red.
Here’s the complete code:
export function render() {
hsv(0, 1, 1)
}
hsv(.33, 1, 1)
and they’ll turn green.hsv(.66, 1, 1)
and they’ll turn blue.hsv(1, 1, 1)
and they’ll turn back to red.hsv(1, .99, 1)
and they’ll turn pink.HSV stands for Hue, Saturation, and Value.
The first number (hue) controls the color or shade from the rainbow color wheel:
Notice that at 0 at the top it’s red. As hue increases, it rotates clockwise so at .25 it’s one quarter of the way around. At .33 or a third it’s at green, then at .66 or two thirds (2/3) it’s at blue, then it circles back towards red.
Using the color wheel, change the first number in the hsv
function and it should be much easier to set the LEDs to whatever color you want.
The second number (saturation) controls the ‘whiteness’ of the color:
A saturation of zero will be white, regardless of the hue. A saturation of 1 is fully saturated, the strongest possible color of the hue. In between are more pastel colors.
The third and final number (value) controls the brightness (or inversely blackness) of the color:
A value of zero will be black, regardless of the hue or saturation. A value of 1 will be fully bright. In between are darker colors.
Experiment with using different combinations of hue, saturation, and value to create different colors.
Changing every pixel to be the same color is neat, but what if we want each pixel to be a different color?
index
variableWe can use the pixel index to make each LED a different color.
Change the first line, adding index
in between the parentheses of the render function:
export function render(index) {
Change the second line to hsv(index / pixelCount, 1, 1)
Here’s the complete code:
export function render(index) {
hsv(index / pixelCount, 1, 1)
}
Congratulations, you made a rainbow!
// TODO: add an image
The render
function includes index
, which is the index of the current pixel being rendered. The very first time render is called, index is set to 0. The next time, index is 1, etc, until index is the number of pixels minus one. Then it wraps back to the beginning so that the next time it’s called it starts back over at 0.
pixelCount
variableOn the second line of code, we used pixelCount
, which is a special global variable that Pixelblaze automatically sets for us to the total number of pixels. Assuming we have 64 pixels, we used it to convert the index
which ranges from 0 to 63, to hue
which ranges from 0 to 1. The first time render is called, index is 0, which divided by any number is still 0. The second time, index is 1, and 1 / 64 = 0.015625
. When used as a hue, that gives a color very close to red, but slightly rotated around the color wheel towards orange. For pixel 21, we’re about one-third of the way through the pixels and the color wheel: 21 / 64 = 0.328125
which, when used as a hue, gives a color close to green.
So now we have changed each pixel to be a different color, and made rainbows, but what about animation?
We can use time to make the pixel colors change!
Replace the code with the following:
export function render(index) {
t = time(.1)
i = index / pixelCount
h = i + t
hsv(h, 1, 1)
}
And now the rainbow moves!
// TODO: add an image
Try different values in the time
function on the second line. You should find that 1
makes it move extremely slowly, taking over a minute to make a full rotation, while 0.005
is very fast. With low enough numbers for time, it will rotate so fast that it looks white!
Note that we’ve reorganized the code a bit:
t
and set it by calling the time
function. The t
variable value will now slowly change over time.i
and set it to index / pixelCount
, which is exactly what we were doing before: make each pixel have a unique hue, according to its index.h
and set it by adding i
and t
, so now the hue for each pixel changes over time.hsv
, passing it h
for the hue.time
functionThe time
function returns a value between 0 and 1 that loops over and over. The speed it loops is controlled by the value passed to it. A value of 1 will loop about every 65 seconds. A value of .1 will loop about every 6.5 seconds. When added to a hue, this rotates the color around the hue color wheel. Since we add that to each pixel’s fixed hue (index / pixelCount
), they all rotate at the same speed.
Note that Pixelblaze automatically handles values for hue larger than 1, wrapping it around to the other side of the color wheel. So a hue of 1.33
is the same green as 0.33
.
render3D
functionWhat if we want to use some other way of drawing patterns, other than index
? How would we make a vertical or horizontal rainbow?
Replace the code with the following:
export function render3D(index, x, y, z) {
hsv(x, 1, 1)
}
You should now see a horizontal rainbow!
Change the hue (the first parameter inside the hsv
function) from x
to y
and it’ll change to vertical.
Change it to (x + y + z) / 3
and it’ll be diagonal!
Notice that we changed from using the render
function to the render3D
function. In addition to the index
parameter, it also includes x
, y
and z
. These parameters range from 0 to 1, and indicate the current pixel’s three-dimensional position in the display, with (0,0,0)
in the top left corner, and (1,1,1)
in the bottom right.
We can animate these three dimensional rainbows the same way we did before, with time:
hsv(x + time(.1), 1, 1)
should give you a rainbow that scrolls from right to left:
To make it change direction, subtract instead of adding time:
hsv(x - time(.1), 1, 1)
To make it scroll vertically, change x
to z
:
hsv(z - time(.1), 1, 1)
Diagonal:
hsv((x + y + z) / 3 + time(.1), 1, 1)
What if we want to make it rotate, expand, or contract? For that, we need some basic trigonometry! Wait, where are you going? Come back, I promise it’s not that bad!
Replace the code with the following:
export function render3D(index, x, y, z) {
v = 1 - hypot3(x, y, z)
hsv(1, 1, v)
}
You should see a red quarter sphere in the back bottom left corner!
The hypot3
function calculates the radius of the current point, or the distance of the point (x,y,z)
from the origin (0,0)
(the upper-left corner). If we want the origin in the center of the display, we change the second line to:
v = 1 - hypot3(x - .5, y - .5, z - .5)
It may be difficult to tell it’s a sphere now, so let’s increase the contrast by adding this line:
v = v * v
Make it move by adding time:
export function render3D(index, x, y, z) {
t = time(.01)
v = t - hypot3(x - .5, y - .5, z - .5)
v = v * v
hsv(1, 1, v)
}
Flip the direction and make it move inward by adding time:
v = 1 - (t + hypot3(x - .5, y - .5, z - .5))
Experiment by changing any of the numbers in the code with different values:
More coming soon!