Led lamp animation test

(c) 2020 All rights reserved

by PhilQ

HTML

<div id="lamp"></div>
<button id="run">Run animation</button>

SCSS

*, :before, :after {
	margin: 0;
	padding: 0;
	box-sizing: border-box;
}

html, body {
	width: 100vw;
	height: 100vh;
}

body {
  display: flex;
	justify-content: center;
	align-items: center;
  font-family: Helvetica;
  background: #20262E;
}

#lamp {
  width: 400px;
	height: 300px;
	position: relative;
}

#run {
	position: absolute;
	top: 10px;
	right: 10px;
	font-size: 20px;
}

.led {
	position: absolute;
	color: rgba(0,0,0, 0.1);
	// background: #fff;
	width: 1px;
	translate: -50% -50%;
	aspect-ratio: 1/1;
	transition: color 500ms linear;
	
	&:before {
		content: '';
		position: absolute;
		top: 50%;
		left: 50%;
		translate: -50% -50%;
		width: 76%; // 3.8/5
		aspect-ratio: 1/1;
		background: currentColor;
		border-radius: 50%;
	}
}

JavaScript

let lamp, cnv, ctx;

let zoom = 4;
const leds_w = 32;
const leds_h = 16;

const canvas = {
	w: 400,
	h: 300,
};

const center = {
	x: canvas.w / 2,
	y: canvas.h / 2,
};

const led = {
	w: 5,
	h: 5,
	r: 3.8,
	d_strip: 1000/144, // strip length / led
	a_ring: 360/16, // angle / led
	d_ring: 39.5 / 2, // distance from center
	o_ring: 55.9, // ring distance center-to-center
};

const leds = [];

const el = (s, p = document) => {
	return p.querySelectorAll(s);
}

const addLed = (x, y, a = 0) => {
	let e = document.createElement('div');
	e.classList.add('led');
	e.style.width = `${zoom*led.w}px`;
	e.style.height = `${zoom*led.h}px`;
	e.style.left = `${x}px`;
	e.style.top = `${y}px`;
	e.style.rotate = `${a}deg`;
	lamp.append(e);
	leds.push(e);
}

const drawRing = (sx, sy) => {
	for (let i = 0; i < 16; i++) {
		addLed(
			sx + zoom * led.d_ring * Math.sin(Math.PI * 2 * (i/16)),
			sy + zoom * led.d_ring * -Math.cos(Math.PI * 2 * (i/16)),
			i * led.a_ring // Maybe * -1
		);
	}
}

const drawStrips = (start = 0) => {
	// 4 strips, starting at top (0), added counter-clockwise
	for (let i = start; i < start + 4; i++) {
		let a = (i%4) * -90;
		let dx = (i%2)== 0 ? ((i%4)==0 ? -1: 1) : 0;
		let dy = (i%2)== 0 ? 0 : ((i%4)==1 ? 1: -1);
		let total = ((i%2)== 0 ? leds_w : leds_h) - 1;
		
		
		let sx = center.x + (zoom * led.d_strip * (leds_w - 1) * 0.5 * (dx==0 ? -dy : -dx));
		let sy = center.y + (zoom * led.d_strip * (leds_h - 1) * 0.5 * (dy==0 ? dx : -dy));
		
		for (let j = 0; j < total; j++) {
			addLed(
				sx + zoom * led.d_strip * dx * j,
				sy + zoom * led.d_strip * dy * j,
				a
			);
		}
	}
}

const colorLeds = (color, interval, i = 0) => {
	leds[i++].style.color = color;
	
	if (i < leds.length) {
		setTimeout(() => {
			colorLeds(color, interval, i);
		}, interval);
	}
}

const runColors = (colors, duration, interval, loop = false, i = 0) => {
	colorLeds(colors[i++], interval, 0);
	
	if (i < colors.length) {
		// Next color
		setTimeout(() => {
			runColors(colors,...