// Aurora Curtains preset for LEDLab const BasePreset = require('./base-preset'); const { createFrame, toIndex, samplePalette, hexToRgb } = require('./frame-utils'); class AuroraCurtainsPreset extends BasePreset { constructor(width = 16, height = 16) { super(width, height); this.bands = []; this.defaultParameters = { bandCount: 5, waveSpeed: 0.35, horizontalSway: 0.45, brightness: 1.0, }; } init() { super.init(); this.createBands(); } createBands() { const bandCount = this.getParameter('bandCount') || 5; this.bands = []; for (let index = 0; index < bandCount; ++index) { this.bands.push({ center: Math.random() * (this.width - 1), phase: Math.random() * Math.PI * 2, width: 1.2 + Math.random() * 1.8, }); } } renderFrame() { const frame = createFrame(this.width, this.height); const waveSpeed = this.getParameter('waveSpeed') || 0.35; const horizontalSway = this.getParameter('horizontalSway') || 0.45; const brightness = this.getParameter('brightness') || 1.0; const timeSeconds = this.frameCount * 0.05; // Convert frame count to time const paletteStops = [ { stop: 0.0, color: hexToRgb('01010a') }, { stop: 0.2, color: hexToRgb('041332') }, { stop: 0.4, color: hexToRgb('0c3857') }, { stop: 0.65, color: hexToRgb('1aa07a') }, { stop: 0.85, color: hexToRgb('68d284') }, { stop: 1.0, color: hexToRgb('f4f5c6') }, ]; for (let row = 0; row < this.height; ++row) { const verticalRatio = row / Math.max(1, this.height - 1); for (let col = 0; col < this.width; ++col) { let intensity = 0; this.bands.forEach((band, index) => { const sway = Math.sin(timeSeconds * waveSpeed + band.phase + verticalRatio * Math.PI * 2) * horizontalSway; const center = band.center + sway * (index % 2 === 0 ? 1 : -1); const distance = Math.abs(col - center); const blurred = Math.exp(-(distance * distance) / (2 * band.width * band.width)); intensity += blurred * (0.8 + Math.sin(timeSeconds * 0.4 + index) * 0.2); }); const normalized = Math.min(intensity / this.bands.length, 1); const gradientBlend = Math.min((normalized * 0.7 + verticalRatio * 0.3), 1); let colorHex = samplePalette(paletteStops, gradientBlend); // Apply brightness if (brightness < 1.0) { const rgb = hexToRgb(colorHex); colorHex = Math.round(rgb.r * brightness).toString(16).padStart(2, '0') + Math.round(rgb.g * brightness).toString(16).padStart(2, '0') + Math.round(rgb.b * brightness).toString(16).padStart(2, '0'); } frame[toIndex(col, row, this.width)] = colorHex; } } return frame; } setParameter(name, value) { super.setParameter(name, value); // Recreate bands if band-related parameters change if (name === 'bandCount') { this.createBands(); } } getMetadata() { return { name: 'Aurora Curtains', description: 'Flowing aurora-like curtains with wave motion', parameters: { bandCount: { type: 'range', min: 3, max: 10, step: 1, default: 5 }, waveSpeed: { type: 'range', min: 0.1, max: 2.0, step: 0.05, default: 0.35 }, horizontalSway: { type: 'range', min: 0.1, max: 1.0, step: 0.05, default: 0.45 }, brightness: { type: 'range', min: 0.1, max: 1.0, step: 0.1, default: 1.0 }, }, width: this.width, height: this.height, }; } } module.exports = AuroraCurtainsPreset;