Here are some patterns and a 3D map generator I made last year that look pretty good on a tree.
A few are new; many are existing patterns adapted for this map. All are slowed down. We wanted more subtle fades that don’t distract you when doing other things in the same room.
Code
In order to not clutter the pattern library, here’s a:
- .zip file of the individual patterns as .epes
- Full .pbb backup archive - use this with a Pixelblaze standard. Restoring this will overwrite all your patterns.
Map
The map is mostly a stack of rings. This worked well even though it was more like a spiral cone in practice. I could specify the number of LEDs in each revolution and the starting rotation of each ring, which was easier than trying to string it with an accurate spiral. I include a mapping helper pattern above to make it easier to set the LEDs-per-revolution and angular alignment arrays.
Map generator code
function (pixelCount) {
var map = []
// Flat ring generator
function ring(pixels, r, h, start) {
for (j = 0; j < pixels; j++) {
c = j / pixels * Math.PI * 2;
point = [r * Math.cos(c - start), r * Math.sin(c - start), h]
map.push(point)
}
}
// Wizard's spiral cone generator
function cone(cpixels) {
loops = 3
r = 4
phase = 0
pixelSpacing = 1.3
resolution = .00005 //controls the resolution of the integral
a = Math.PI * 2 * loops
function conicalHelix(t, r, a) {
z = layerPixels.length +130*t/cpixels
x = (1-t) * r * Math.cos(t * a - phase * Math.PI * 2)
y = (1-t) * r * Math.sin(t * a - phase * Math.PI * 2)
return [x,y,z]
}
function conicalHelixArcLength(t1, t2, r, a) {
h1 = conicalHelix(t1, r, a)
h2 = conicalHelix(t2, r, a)
dh = [h1[0] - h2[0], h1[1] - h2[1], h1[2] - h2[2]]
return Math.sqrt(dh[0]*dh[0] + dh[1]*dh[1] + dh[2]*dh[2])
}
for (t = 0, i = 0; i < cpixels; i++) {
//integrate arc lengths until we cover the distance to our next pixel
l = 0;
while (l < pixelSpacing) {
l += conicalHelixArcLength(t, t+resolution, r, a)
t += resolution
}
map.push(conicalHelix(t, r, a))
}
}
// Number of pixels in each ring layer, bottom to top
var layerPixels = [134, 122, 114,
96, 84, 79, 68,
73, 49, 40, 41, 37,
33];
// Angular starting offset for each layer
// Unit is revolutions (multiply by 2 PI to get radians)
var layerAngles = [ -0.02, 0.02, 0.13,
-.08, -.07, 0.03,
0.05, -.08, -.05, 0.04, .1, -.66,
0.6];
// For each layer
for (i = 0; i < layerPixels.length; i++) {
ring(layerPixels[i], // pixels
layerPixels.length - i + 3, // radius - gets smaller each layer, but min radius of 3
i, // height
layerAngles[i] * Math.PI * 2); // angular offset
}
cone(30) // top is a simple spiral
return map
}
Even though it’s an approximation, I found it was less work than correcting the 2% wildly-errant LED positions that the nascent auto-mapping tools produce.
LEDs
Two years ago I strung my tree with 1000 WS2811 (12V) bullets (now $280, with green wire). I’ve used strands of 20mm SK9822 modules in other projects, but they don’t have the classic bulb look like the bullets do.
If doing this now I would try out these 12V* 5V GS8206 bullets - the 8206 is supposedly the IC version of the GS8208. The the GS8208 is the 5050 LED+chip with a great 12-bit gamma curve that some of us have really come to like.
I think some people are happy with the fairy-light style LEDs as well.
*Edit: Thanks, @hex337 - you’re right, the GS8206 bullets seem to all be 5V