getColor = {
const rand = () => Math.random() * 2 - 1
const tempCol = new THREE.Color()
const fromHSV = (h, s, v) => {
const { r, g, b } = tempCol.setHSL(h, s, v)
return [r, g, b]
}
const MAX_Z = Math.max(...LEDs.map(({ z }) => z))
let flakes = []
const stepFlake = () => {
while (flakes.length < 50) flakes.push({
x: rand(),
y: rand(),
z: MAX_Z,
v: Math.random() * 0.05 + 0.01
})
for (const flake of flakes) {
if (flake.z > 0) { flake.z -= flake.v }
}
flakes = flakes.filter(({ z }) => z > 0)
}
let pd = 1.5, pdt = 0.01, pdh = 0.5
const norm = new THREE.Vector3()
const stepPlane = () => {
pd += pdt
if (Math.abs(pd) < 2) return
norm.set(Math.random(), Math.random(), Math.random())
norm.normalize()
const dir = (Math.random() > 0.5) ? 1 : -1
pd = dir * -1.5
pdh = Math.random()
pdt = dir * (Math.random() * 0.01 + 0.01)
}
return (led, state) => {
const { frame, time } = state
const { index, x, y, z, r, θ } = led
const allTime = time % 90
const t = allTime / 10
if (t < 3) {
if (!index) stepFlake()
if (flakes.some((fl) => Math.hypot(fl.x - x, fl.y - y, fl.z - z) < 0.15)) return [1, 1, 1]
} else if (t < 4) {
return (y * Math.cos(t * 20) + (z - 1.5) * Math.sin(t * 20)) > 0 ? [0, 1, 0] : [1, 0, 0]
} else if (t < 5) {
const sweep = Math.abs((t + θ / 6) % 1)
return fromHSV(frame / 200, 0.5, sweep < 0.1 ? 0.5 : 0.05 / sweep)
} else if (t < 6) {
return fromHSV(z / 6 - t, 0.5, 0.5)
} else {
if (!index) stepPlane()
const dist = Math.abs(x * norm.x + y * norm.y + z * norm.z + pd)
return fromHSV(pdh, 0.5, dist < 0.1 ? 0.7 : 0.05 / dist)
}
}
}