Files
spore-ledlab/presets/aurora-curtains-preset.js
2025-10-11 17:46:32 +02:00

112 lines
3.6 KiB
JavaScript

// 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;