const dgram = require('dgram'); const host = process.argv[2]; const port = parseInt(process.argv[3] || '4210', 10); const pixels = parseInt(process.argv[4] || '64', 10); const intervalMs = parseInt(process.argv[5] || '30', 10); if (!host) { console.error('Usage: node rainbow.js [port] [pixels] [interval-ms]'); process.exit(1); } const socket = dgram.createSocket('udp4'); let offset = 0; const isBroadcast = host === '255.255.255.255' || host.endsWith('.255'); function wheel(pos) { pos = 255 - pos; if (pos < 85) { return [255 - pos * 3, 0, pos * 3]; } if (pos < 170) { pos -= 85; return [0, pos * 3, 255 - pos * 3]; } pos -= 170; return [pos * 3, 255 - pos * 3, 0]; } function generateFrame() { let payload = 'RAW:'; for (let i = 0; i < pixels; i++) { const colorIndex = (i * 256 / pixels + offset) & 255; const [r, g, b] = wheel(colorIndex); payload += r.toString(16).padStart(2, '0'); payload += g.toString(16).padStart(2, '0'); payload += b.toString(16).padStart(2, '0'); } offset = (offset + 1) & 255; return payload; } function sendFrame() { const payload = generateFrame(); const message = Buffer.from(payload, 'utf8'); socket.send(message, port, host); } setInterval(sendFrame, intervalMs); if (isBroadcast) { socket.bind(() => { socket.setBroadcast(true); }); } console.log(`Streaming rainbow pattern to ${host}:${port} with ${pixels} pixels (interval=${intervalMs}ms)`);