XmasTreeLayout¶
XmasTreeLayout is a 3D Layout module that maps one or more LED strings onto a conical Christmas-tree shape. Each string winds from the base (y=0, widest) to the tip (y=height-1, single centre point) using the golden-angle distribution so consecutive LEDs rotate ~137.5° around the axis. The result is a naturally scattered, non-repeating spiral that looks organic without any runtime randomness — positions are fully deterministic.
Purpose¶
A real Christmas tree is a 3D cone, not a flat triangle. With XmasTreeLayout any 3D effect renders on the full virtual cube and only the cells occupied by the spiral string(s) receive colour. The WebGL previewer renders the lit LEDs as a 3D point cloud, showing the conical silhouette from any orbit angle.
Controls¶
| Key | UI type | Min | Max | Default | Description |
|---|---|---|---|---|---|
ledsPerString |
slider | 8 | 500 | 50 | LEDs per string |
strings |
slider | 1 | 8 | 1 | Number of strings, spread evenly around the cone |
height |
slider | 4 | 32 | 12 | Virtual grid height; also sets cone radius and grid width |
Total physical LEDs: strings * ledsPerString.
Wiring¶
Add as a child of a DriverLayer:
{ "type": "XmasTreeLayout", "id": "tree1", "parent_id": "driver1",
"props": { "height": 16, "ledsPerString": 100, "strings": 2 } }
Behaviour¶
- Virtual grid:
(2h-1) x h x (2h-1). Default height=12 gives a 23 x 12 x 23 cube (6348 virtual cells, 50 physical LEDs). - Cone geometry: at normalised position
talong the string (0=base, 1=tip), the LED sits at heighty = round(t * (h-1))and cone radiusr = (1-t) * (h-1). Radius shrinks linearly fromh-1at the base to 0 at the tip. - Golden-angle spiral: consecutive LEDs rotate by
2.3999...radians (~137.5°), the golden angle. This gives the most uniform coverage of the cone surface without bunching. - Multiple strings: string
sstarts with an angular offset ofs * 2π / strings, so strings spread evenly around the circumference. - Tip mapping: the last LED in every string always maps to the virtual centre-top cell
(h-1, h-1, h-1). - onUpdate: any control change triggers
onChildrenReady()on the parentDriverLayerto rebuild the PhysMap.
LED count and grid size¶
| height | ledsPerString | strings | total LEDs | virtual grid |
|---|---|---|---|---|
| 8 | 30 | 1 | 30 | 15 x 8 x 15 |
| 12 | 50 | 1 | 50 | 23 x 12 x 23 |
| 16 | 100 | 2 | 200 | 31 x 16 x 31 |
| 24 | 200 | 3 | 600 | 47 x 24 x 47 |
Test coverage¶
- Extent is
(2h-1) x h x (2h-1)withd == w(square footprint) physCountequalsstrings * ledsPerString- First LED decodes to
y=0(base layer) - Last LED decodes to
(cx, h-1, cz)(centre tip) - All virtual indices within 3D grid bounds
- Two strings produce double the LED count