feat: expand color strip sources with new effects, gradient improvements, and daylight/candlelight enhancements
Some checks failed
Lint & Test / test (push) Failing after 29s

Effects: add 7 new procedural effects (rain, comet, bouncing ball, fireworks,
sparkle rain, lava lamp, wave interference) and custom palette support via
user-defined [[pos,R,G,B],...] stops.

Gradient: add easing functions (linear, ease_in_out, step, cubic) for stop
interpolation, plus noise_perturb and hue_rotate animation types.

Daylight: add longitude field and NOAA solar equations for accurate
sunrise/sunset based on latitude, longitude, and day of year.

Candlelight: add wind simulation (correlated gusts), candle type presets
(taper/votive/bonfire), and wax drip effect with localized brightness dips.

Also fixes editor preview to include all new fields for inline LED test.
This commit is contained in:
2026-03-23 22:40:55 +03:00
parent c4dce19b2e
commit 9b80076b5b
12 changed files with 1015 additions and 120 deletions

View File

@@ -31,18 +31,19 @@ function _collectPreviewConfig() {
} else if (sourceType === 'gradient') {
const stops = getGradientStops();
if (stops.length < 2) return null;
config = { source_type: 'gradient', stops: stops.map(s => ({ position: s.position, color: s.color, ...(s.colorRight ? { color_right: s.colorRight } : {}) })), animation: _getAnimationPayload() };
config = { source_type: 'gradient', stops: stops.map(s => ({ position: s.position, color: s.color, ...(s.colorRight ? { color_right: s.colorRight } : {}) })), animation: _getAnimationPayload(), easing: (document.getElementById('css-editor-gradient-easing') as HTMLSelectElement).value };
} else if (sourceType === 'color_cycle') {
const colors = _colorCycleGetColors();
if (colors.length < 2) return null;
config = { source_type: 'color_cycle', colors };
} else if (sourceType === 'effect') {
config = { source_type: 'effect', effect_type: (document.getElementById('css-editor-effect-type') as HTMLInputElement).value, palette: (document.getElementById('css-editor-effect-palette') as HTMLInputElement).value, intensity: parseFloat((document.getElementById('css-editor-effect-intensity') as HTMLInputElement).value), scale: parseFloat((document.getElementById('css-editor-effect-scale') as HTMLInputElement).value), mirror: (document.getElementById('css-editor-effect-mirror') as HTMLInputElement).checked };
if (config.effect_type === 'meteor') { const hex = (document.getElementById('css-editor-effect-color') as HTMLInputElement).value; config.color = [parseInt(hex.slice(1, 3), 16), parseInt(hex.slice(3, 5), 16), parseInt(hex.slice(5, 7), 16)]; }
if (['meteor', 'comet', 'bouncing_ball'].includes(config.effect_type)) { const hex = (document.getElementById('css-editor-effect-color') as HTMLInputElement).value; config.color = [parseInt(hex.slice(1, 3), 16), parseInt(hex.slice(3, 5), 16), parseInt(hex.slice(5, 7), 16)]; }
if (config.palette === 'custom') { const cpText = (document.getElementById('css-editor-effect-custom-palette') as HTMLTextAreaElement)?.value?.trim(); if (cpText) { try { config.custom_palette = JSON.parse(cpText); } catch {} } }
} else if (sourceType === 'daylight') {
config = { source_type: 'daylight', speed: parseFloat((document.getElementById('css-editor-daylight-speed') as HTMLInputElement).value), use_real_time: (document.getElementById('css-editor-daylight-real-time') as HTMLInputElement).checked, latitude: parseFloat((document.getElementById('css-editor-daylight-latitude') as HTMLInputElement).value) };
config = { source_type: 'daylight', speed: parseFloat((document.getElementById('css-editor-daylight-speed') as HTMLInputElement).value), use_real_time: (document.getElementById('css-editor-daylight-real-time') as HTMLInputElement).checked, latitude: parseFloat((document.getElementById('css-editor-daylight-latitude') as HTMLInputElement).value), longitude: parseFloat((document.getElementById('css-editor-daylight-longitude') as HTMLInputElement).value) };
} else if (sourceType === 'candlelight') {
config = { source_type: 'candlelight', color: hexToRgbArray((document.getElementById('css-editor-candlelight-color') as HTMLInputElement).value), intensity: parseFloat((document.getElementById('css-editor-candlelight-intensity') as HTMLInputElement).value), num_candles: parseInt((document.getElementById('css-editor-candlelight-num-candles') as HTMLInputElement).value) || 3, speed: parseFloat((document.getElementById('css-editor-candlelight-speed') as HTMLInputElement).value) };
config = { source_type: 'candlelight', color: hexToRgbArray((document.getElementById('css-editor-candlelight-color') as HTMLInputElement).value), intensity: parseFloat((document.getElementById('css-editor-candlelight-intensity') as HTMLInputElement).value), num_candles: parseInt((document.getElementById('css-editor-candlelight-num-candles') as HTMLInputElement).value) || 3, speed: parseFloat((document.getElementById('css-editor-candlelight-speed') as HTMLInputElement).value), wind_strength: parseFloat((document.getElementById('css-editor-candlelight-wind') as HTMLInputElement).value), candle_type: (document.getElementById('css-editor-candlelight-type') as HTMLSelectElement).value };
}
const clockEl = document.getElementById('css-editor-clock') as HTMLSelectElement | null;
if (clockEl && clockEl.value) config.clock_id = clockEl.value;

View File

@@ -194,11 +194,12 @@ export function onCSSTypeChange() {
_ensureAudioPaletteIconSelect();
onAudioVizChange();
}
if (type === 'gradient') { _ensureGradientPresetIconSelect(); _renderCustomPresetList(); }
if (type === 'gradient') { _ensureGradientPresetIconSelect(); _ensureGradientEasingIconSelect(); _renderCustomPresetList(); }
if (type === 'notification') {
ensureNotificationEffectIconSelect();
ensureNotificationFilterModeIconSelect();
}
if (type === 'candlelight') _ensureCandleTypeIconSelect();
// Animation section — shown for static/gradient only
const animSection = document.getElementById('css-editor-animation-section') as HTMLElement;
@@ -206,7 +207,7 @@ export function onCSSTypeChange() {
if (type === 'static' || type === 'gradient') {
animSection.style.display = '';
const opts = type === 'gradient'
? ['none','breathing','gradient_shift','wave','strobe','sparkle','pulse','candle','rainbow_fade']
? ['none','breathing','gradient_shift','wave','noise_perturb','hue_rotate','strobe','sparkle','pulse','candle','rainbow_fade']
: ['none','breathing','strobe','sparkle','pulse','candle','rainbow_fade'];
animTypeSelect.innerHTML = opts.map(v =>
`<option value="${v}">${t('color_strip.animation.type.' + v)}</option>`
@@ -373,6 +374,8 @@ let _effectPaletteIconSelect: any = null;
let _audioPaletteIconSelect: any = null;
let _audioVizIconSelect: any = null;
let _gradientPresetIconSelect: any = null;
let _gradientEasingIconSelect: any = null;
let _candleTypeIconSelect: any = null;
const _icon = (d: any) => `<svg class="icon" viewBox="0 0 24 24">${d}</svg>`;
function _ensureInterpolationIconSelect() {
@@ -391,11 +394,18 @@ function _ensureEffectTypeIconSelect() {
const sel = document.getElementById('css-editor-effect-type') as HTMLSelectElement | null;
if (!sel) return;
const items = [
{ value: 'fire', icon: _icon(P.zap), label: t('color_strip.effect.fire'), desc: t('color_strip.effect.fire.desc') },
{ value: 'meteor', icon: _icon(P.sparkles), label: t('color_strip.effect.meteor'), desc: t('color_strip.effect.meteor.desc') },
{ value: 'plasma', icon: _icon(P.rainbow), label: t('color_strip.effect.plasma'), desc: t('color_strip.effect.plasma.desc') },
{ value: 'noise', icon: _icon(P.activity), label: t('color_strip.effect.noise'), desc: t('color_strip.effect.noise.desc') },
{ value: 'aurora', icon: _icon(P.sparkles), label: t('color_strip.effect.aurora'), desc: t('color_strip.effect.aurora.desc') },
{ value: 'fire', icon: _icon(P.zap), label: t('color_strip.effect.fire'), desc: t('color_strip.effect.fire.desc') },
{ value: 'meteor', icon: _icon(P.sparkles), label: t('color_strip.effect.meteor'), desc: t('color_strip.effect.meteor.desc') },
{ value: 'plasma', icon: _icon(P.rainbow), label: t('color_strip.effect.plasma'), desc: t('color_strip.effect.plasma.desc') },
{ value: 'noise', icon: _icon(P.activity), label: t('color_strip.effect.noise'), desc: t('color_strip.effect.noise.desc') },
{ value: 'aurora', icon: _icon(P.sparkles), label: t('color_strip.effect.aurora'), desc: t('color_strip.effect.aurora.desc') },
{ value: 'rain', icon: _icon(P.cloudSun), label: t('color_strip.effect.rain'), desc: t('color_strip.effect.rain.desc') },
{ value: 'comet', icon: _icon(P.rocket), label: t('color_strip.effect.comet'), desc: t('color_strip.effect.comet.desc') },
{ value: 'bouncing_ball', icon: _icon(P.activity), label: t('color_strip.effect.bouncing_ball'), desc: t('color_strip.effect.bouncing_ball.desc') },
{ value: 'fireworks', icon: _icon(P.sparkles), label: t('color_strip.effect.fireworks'), desc: t('color_strip.effect.fireworks.desc') },
{ value: 'sparkle_rain', icon: _icon(P.star), label: t('color_strip.effect.sparkle_rain'), desc: t('color_strip.effect.sparkle_rain.desc') },
{ value: 'lava_lamp', icon: _icon(P.flame), label: t('color_strip.effect.lava_lamp'), desc: t('color_strip.effect.lava_lamp.desc') },
{ value: 'wave_interference',icon: _icon(P.rainbow), label: t('color_strip.effect.wave_interference'),desc: t('color_strip.effect.wave_interference.desc') },
];
if (_effectTypeIconSelect) { _effectTypeIconSelect.updateItems(items); return; }
_effectTypeIconSelect = new IconSelect({ target: sel, items, columns: 2 });
@@ -407,10 +417,37 @@ function _ensureEffectPaletteIconSelect() {
const items = Object.entries(_PALETTE_COLORS).map(([key, pts]) => ({
value: key, icon: _gradientStripHTML(pts), label: t(`color_strip.palette.${key}`),
}));
items.push({ value: 'custom', icon: _icon(P.pencil), label: t('color_strip.palette.custom') });
if (_effectPaletteIconSelect) { _effectPaletteIconSelect.updateItems(items); return; }
_effectPaletteIconSelect = new IconSelect({ target: sel, items, columns: 2 });
}
function _ensureGradientEasingIconSelect() {
const sel = document.getElementById('css-editor-gradient-easing') as HTMLSelectElement | null;
if (!sel) return;
const items = [
{ value: 'linear', icon: _icon(P.trendingUp), label: t('color_strip.gradient.easing.linear'), desc: t('color_strip.gradient.easing.linear.desc') },
{ value: 'ease_in_out', icon: _icon(P.activity), label: t('color_strip.gradient.easing.ease_in_out'), desc: t('color_strip.gradient.easing.ease_in_out.desc') },
{ value: 'step', icon: _icon(P.layoutDashboard), label: t('color_strip.gradient.easing.step'), desc: t('color_strip.gradient.easing.step.desc') },
{ value: 'cubic', icon: _icon(P.slidersHorizontal), label: t('color_strip.gradient.easing.cubic'), desc: t('color_strip.gradient.easing.cubic.desc') },
];
if (_gradientEasingIconSelect) { _gradientEasingIconSelect.updateItems(items); return; }
_gradientEasingIconSelect = new IconSelect({ target: sel, items, columns: 2 });
}
function _ensureCandleTypeIconSelect() {
const sel = document.getElementById('css-editor-candlelight-type') as HTMLSelectElement | null;
if (!sel) return;
const items = [
{ value: 'default', icon: _icon(P.flame), label: t('color_strip.candlelight.type.default'), desc: t('color_strip.candlelight.type.default.desc') },
{ value: 'taper', icon: _icon(P.activity), label: t('color_strip.candlelight.type.taper'), desc: t('color_strip.candlelight.type.taper.desc') },
{ value: 'votive', icon: _icon(P.lightbulb), label: t('color_strip.candlelight.type.votive'), desc: t('color_strip.candlelight.type.votive.desc') },
{ value: 'bonfire', icon: _icon(P.zap), label: t('color_strip.candlelight.type.bonfire'), desc: t('color_strip.candlelight.type.bonfire.desc') },
];
if (_candleTypeIconSelect) { _candleTypeIconSelect.updateItems(items); return; }
_candleTypeIconSelect = new IconSelect({ target: sel, items, columns: 2 });
}
function _ensureAudioPaletteIconSelect() {
const sel = document.getElementById('css-editor-audio-palette') as HTMLSelectElement | null;
if (!sel) return;
@@ -500,6 +537,8 @@ function _buildAnimationTypeItems(cssType: any) {
items.push(
{ value: 'gradient_shift', icon: _icon(P.fastForward), label: t('color_strip.animation.type.gradient_shift'), desc: t('color_strip.animation.type.gradient_shift.desc') },
{ value: 'wave', icon: _icon(P.rainbow), label: t('color_strip.animation.type.wave'), desc: t('color_strip.animation.type.wave.desc') },
{ value: 'noise_perturb', icon: _icon(P.activity), label: t('color_strip.animation.type.noise_perturb'), desc: t('color_strip.animation.type.noise_perturb.desc') },
{ value: 'hue_rotate', icon: _icon(P.rotateCw), label: t('color_strip.animation.type.hue_rotate'), desc: t('color_strip.animation.type.hue_rotate.desc') },
);
}
items.push(
@@ -572,18 +611,23 @@ const _PALETTE_COLORS = {
// Default palette per effect type
export function onEffectTypeChange() {
const et = (document.getElementById('css-editor-effect-type') as HTMLInputElement).value;
// palette: all except meteor
(document.getElementById('css-editor-effect-palette-group') as HTMLElement).style.display = et !== 'meteor' ? '' : 'none';
// color picker: meteor only
(document.getElementById('css-editor-effect-color-group') as HTMLElement).style.display = et === 'meteor' ? '' : 'none';
// intensity: fire, meteor, aurora
(document.getElementById('css-editor-effect-intensity-group') as HTMLElement).style.display =
['fire', 'meteor', 'aurora'].includes(et) ? '' : 'none';
// scale: plasma, noise, aurora
(document.getElementById('css-editor-effect-scale-group') as HTMLElement).style.display =
['plasma', 'noise', 'aurora'].includes(et) ? '' : 'none';
// mirror: meteor only
(document.getElementById('css-editor-effect-mirror-group') as HTMLElement).style.display = et === 'meteor' ? '' : 'none';
// palette: all except meteor, comet, bouncing_ball (which use color picker)
const usesColorPicker = ['meteor', 'comet', 'bouncing_ball'].includes(et);
(document.getElementById('css-editor-effect-palette-group') as HTMLElement).style.display = !usesColorPicker ? '' : 'none';
// color picker: meteor, comet, bouncing_ball
(document.getElementById('css-editor-effect-color-group') as HTMLElement).style.display = usesColorPicker ? '' : 'none';
// intensity: most effects use it
const usesIntensity = ['fire', 'meteor', 'aurora', 'rain', 'comet', 'bouncing_ball', 'fireworks', 'sparkle_rain'].includes(et);
(document.getElementById('css-editor-effect-intensity-group') as HTMLElement).style.display = usesIntensity ? '' : 'none';
// scale: effects with spatial parameters
const usesScale = ['plasma', 'noise', 'aurora', 'rain', 'lava_lamp', 'wave_interference'].includes(et);
(document.getElementById('css-editor-effect-scale-group') as HTMLElement).style.display = usesScale ? '' : 'none';
// mirror: meteor, comet
(document.getElementById('css-editor-effect-mirror-group') as HTMLElement).style.display =
['meteor', 'comet'].includes(et) ? '' : 'none';
// custom palette visibility
if (!usesColorPicker) onEffectPaletteChange();
else (document.getElementById('css-editor-effect-custom-palette-group') as HTMLElement).style.display = 'none';
// description
const descEl = document.getElementById('css-editor-effect-type-desc') as HTMLElement | null;
if (descEl) {
@@ -594,6 +638,12 @@ export function onEffectTypeChange() {
_autoGenerateCSSName();
}
export function onEffectPaletteChange() {
const palette = (document.getElementById('css-editor-effect-palette') as HTMLInputElement).value;
const customGroup = document.getElementById('css-editor-effect-custom-palette-group') as HTMLElement;
if (customGroup) customGroup.style.display = palette === 'custom' ? '' : 'none';
}
/* ── Color Cycle helpers ──────────────────────────────────────── */
const _DEFAULT_CYCLE_COLORS = ['#ff0000', '#ffff00', '#00ff00', '#00ffff', '#0000ff', '#ff00ff'];
@@ -1074,7 +1124,7 @@ export function createColorStripCard(source: ColorStripSource, pictureSourceMap:
content: `
<div class="card-header">
<div class="card-title" title="${escapeHtml(source.name)}">
${icon} ${escapeHtml(source.name)}
${icon} <span class="card-title-text">${escapeHtml(source.name)}</span>
</div>
</div>
<div class="stream-card-props">
@@ -1166,6 +1216,8 @@ const _typeHandlers: Record<string, { load: (...args: any[]) => any; reset: (...
{ position: 1.0, color: [0, 0, 255] },
]);
_loadAnimationState(css.animation);
(document.getElementById('css-editor-gradient-easing') as HTMLSelectElement).value = css.easing || 'linear';
if (_gradientEasingIconSelect) _gradientEasingIconSelect.setValue(css.easing || 'linear');
},
reset() {
(document.getElementById('css-editor-gradient-preset') as HTMLInputElement).value = '';
@@ -1174,6 +1226,8 @@ const _typeHandlers: Record<string, { load: (...args: any[]) => any; reset: (...
{ position: 1.0, color: [0, 0, 255] },
]);
_loadAnimationState(null);
(document.getElementById('css-editor-gradient-easing') as HTMLSelectElement).value = 'linear';
if (_gradientEasingIconSelect) _gradientEasingIconSelect.setValue('linear');
},
getPayload(name) {
const gStops = getGradientStops();
@@ -1189,6 +1243,7 @@ const _typeHandlers: Record<string, { load: (...args: any[]) => any; reset: (...
...(s.colorRight ? { color_right: s.colorRight } : {}),
})),
animation: _getAnimationPayload(),
easing: (document.getElementById('css-editor-gradient-easing') as HTMLSelectElement).value,
};
},
},
@@ -1205,6 +1260,10 @@ const _typeHandlers: Record<string, { load: (...args: any[]) => any; reset: (...
(document.getElementById('css-editor-effect-scale') as HTMLInputElement).value = css.scale ?? 1.0;
(document.getElementById('css-editor-effect-scale-val') as HTMLElement).textContent = parseFloat(css.scale ?? 1.0).toFixed(1);
(document.getElementById('css-editor-effect-mirror') as HTMLInputElement).checked = css.mirror || false;
// Custom palette
const cpTextarea = document.getElementById('css-editor-effect-custom-palette') as HTMLTextAreaElement;
if (cpTextarea) cpTextarea.value = css.custom_palette ? JSON.stringify(css.custom_palette) : '';
onEffectPaletteChange();
},
reset() {
(document.getElementById('css-editor-effect-type') as HTMLInputElement).value = 'fire';
@@ -1215,6 +1274,8 @@ const _typeHandlers: Record<string, { load: (...args: any[]) => any; reset: (...
(document.getElementById('css-editor-effect-scale') as HTMLInputElement).value = 1.0 as any;
(document.getElementById('css-editor-effect-scale-val') as HTMLElement).textContent = '1.0';
(document.getElementById('css-editor-effect-mirror') as HTMLInputElement).checked = false;
const cpTextarea = document.getElementById('css-editor-effect-custom-palette') as HTMLTextAreaElement;
if (cpTextarea) cpTextarea.value = '';
},
getPayload(name) {
const payload: any = {
@@ -1225,11 +1286,23 @@ const _typeHandlers: Record<string, { load: (...args: any[]) => any; reset: (...
scale: parseFloat((document.getElementById('css-editor-effect-scale') as HTMLInputElement).value),
mirror: (document.getElementById('css-editor-effect-mirror') as HTMLInputElement).checked,
};
// Meteor uses a color picker
if (payload.effect_type === 'meteor') {
// Meteor/comet/bouncing_ball use a color picker
if (['meteor', 'comet', 'bouncing_ball'].includes(payload.effect_type)) {
const hex = (document.getElementById('css-editor-effect-color') as HTMLInputElement).value;
payload.color = [parseInt(hex.slice(1, 3), 16), parseInt(hex.slice(3, 5), 16), parseInt(hex.slice(5, 7), 16)];
}
// Custom palette
if (payload.palette === 'custom') {
const cpText = (document.getElementById('css-editor-effect-custom-palette') as HTMLTextAreaElement).value.trim();
if (cpText) {
try {
payload.custom_palette = JSON.parse(cpText);
} catch {
cssEditorModal.showError('Invalid custom palette JSON');
return null;
}
}
}
return payload;
},
},
@@ -1345,6 +1418,8 @@ const _typeHandlers: Record<string, { load: (...args: any[]) => any; reset: (...
(document.getElementById('css-editor-daylight-real-time') as HTMLInputElement).checked = css.use_real_time || false;
(document.getElementById('css-editor-daylight-latitude') as HTMLInputElement).value = css.latitude ?? 50.0;
(document.getElementById('css-editor-daylight-latitude-val') as HTMLElement).textContent = parseFloat(css.latitude ?? 50.0).toFixed(0);
(document.getElementById('css-editor-daylight-longitude') as HTMLInputElement).value = css.longitude ?? 0.0;
(document.getElementById('css-editor-daylight-longitude-val') as HTMLElement).textContent = parseFloat(css.longitude ?? 0.0).toFixed(0);
_syncDaylightSpeedVisibility();
},
reset() {
@@ -1353,6 +1428,8 @@ const _typeHandlers: Record<string, { load: (...args: any[]) => any; reset: (...
(document.getElementById('css-editor-daylight-real-time') as HTMLInputElement).checked = false;
(document.getElementById('css-editor-daylight-latitude') as HTMLInputElement).value = 50.0 as any;
(document.getElementById('css-editor-daylight-latitude-val') as HTMLElement).textContent = '50';
(document.getElementById('css-editor-daylight-longitude') as HTMLInputElement).value = 0.0 as any;
(document.getElementById('css-editor-daylight-longitude-val') as HTMLElement).textContent = '0';
},
getPayload(name) {
return {
@@ -1360,6 +1437,7 @@ const _typeHandlers: Record<string, { load: (...args: any[]) => any; reset: (...
speed: parseFloat((document.getElementById('css-editor-daylight-speed') as HTMLInputElement).value),
use_real_time: (document.getElementById('css-editor-daylight-real-time') as HTMLInputElement).checked,
latitude: parseFloat((document.getElementById('css-editor-daylight-latitude') as HTMLInputElement).value),
longitude: parseFloat((document.getElementById('css-editor-daylight-longitude') as HTMLInputElement).value),
};
},
},
@@ -1371,6 +1449,10 @@ const _typeHandlers: Record<string, { load: (...args: any[]) => any; reset: (...
(document.getElementById('css-editor-candlelight-num-candles') as HTMLInputElement).value = css.num_candles ?? 3;
(document.getElementById('css-editor-candlelight-speed') as HTMLInputElement).value = css.speed ?? 1.0;
(document.getElementById('css-editor-candlelight-speed-val') as HTMLElement).textContent = parseFloat(css.speed ?? 1.0).toFixed(1);
(document.getElementById('css-editor-candlelight-wind') as HTMLInputElement).value = css.wind_strength ?? 0.0;
(document.getElementById('css-editor-candlelight-wind-val') as HTMLElement).textContent = parseFloat(css.wind_strength ?? 0.0).toFixed(1);
(document.getElementById('css-editor-candlelight-type') as HTMLSelectElement).value = css.candle_type || 'default';
if (_candleTypeIconSelect) _candleTypeIconSelect.setValue(css.candle_type || 'default');
},
reset() {
(document.getElementById('css-editor-candlelight-color') as HTMLInputElement).value = '#ff9329';
@@ -1379,6 +1461,10 @@ const _typeHandlers: Record<string, { load: (...args: any[]) => any; reset: (...
(document.getElementById('css-editor-candlelight-num-candles') as HTMLInputElement).value = 3 as any;
(document.getElementById('css-editor-candlelight-speed') as HTMLInputElement).value = 1.0 as any;
(document.getElementById('css-editor-candlelight-speed-val') as HTMLElement).textContent = '1.0';
(document.getElementById('css-editor-candlelight-wind') as HTMLInputElement).value = 0.0 as any;
(document.getElementById('css-editor-candlelight-wind-val') as HTMLElement).textContent = '0.0';
(document.getElementById('css-editor-candlelight-type') as HTMLSelectElement).value = 'default';
if (_candleTypeIconSelect) _candleTypeIconSelect.setValue('default');
},
getPayload(name) {
return {
@@ -1387,6 +1473,8 @@ const _typeHandlers: Record<string, { load: (...args: any[]) => any; reset: (...
intensity: parseFloat((document.getElementById('css-editor-candlelight-intensity') as HTMLInputElement).value),
num_candles: parseInt((document.getElementById('css-editor-candlelight-num-candles') as HTMLInputElement).value) || 3,
speed: parseFloat((document.getElementById('css-editor-candlelight-speed') as HTMLInputElement).value),
wind_strength: parseFloat((document.getElementById('css-editor-candlelight-wind') as HTMLInputElement).value),
candle_type: (document.getElementById('css-editor-candlelight-type') as HTMLSelectElement).value,
};
},
},