Nice idea! A lot of my map code is absolute trash though that I’m ashamed to share, ha.

I’ll start off with my tree map for this year, which I’ve added a few comments to. I have an artificial tree I wired “permanently”, so I model it as rings except for the very top, which is a spiral cone.

This map gets me some OK-isy result for +/- 10% X,Y,Z:

##
Here's the code (click to expand)

```
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
var layerPixels = [134, 122, 114,
96, 84, 79, 68,
73, 49, 40, 41, 37,
33];
// Angular starting offset for each layer
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
}
```