Add effect palette preview bar in CSS editor

Show a gradient color bar below the effect type description, giving
users a visual preview of palette colors before applying. Updates
live when switching effect type, palette, or meteor head color.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-23 01:59:25 +03:00
parent 9e555cef2e
commit f9a5fb68ed
4 changed files with 48 additions and 3 deletions

View File

@@ -507,6 +507,14 @@
/* ── Gradient editor ────────────────────────────────────────────── */
.effect-palette-preview {
width: 100%;
height: 20px;
border-radius: 6px;
margin-top: 6px;
border: 1px solid var(--border-color);
}
.gradient-editor {
position: relative;
width: 100%;

View File

@@ -89,7 +89,8 @@ import {
// Layer 5: color-strip sources
import {
showCSSEditor, closeCSSEditorModal, forceCSSEditorClose, saveCSSEditor, deleteColorStrip,
onCSSTypeChange, onEffectTypeChange, onAnimationTypeChange, colorCycleAddColor, colorCycleRemoveColor,
onCSSTypeChange, onEffectTypeChange, onAnimationTypeChange, updateEffectPreview,
colorCycleAddColor, colorCycleRemoveColor,
applyGradientPreset,
} from './features/color-strips.js';
@@ -277,6 +278,7 @@ Object.assign(window, {
onCSSTypeChange,
onEffectTypeChange,
onAnimationTypeChange,
updateEffectPreview,
colorCycleAddColor,
colorCycleRemoveColor,
applyGradientPreset,

View File

@@ -131,6 +131,38 @@ function _syncAnimationSpeedState() {
/* ── Effect type helpers ──────────────────────────────────────── */
// Palette color control points — mirrors _PALETTE_DEFS in effect_stream.py
const _PALETTE_COLORS = {
fire: [[0,'0,0,0'],[0.33,'200,24,0'],[0.66,'255,160,0'],[1,'255,255,200']],
ocean: [[0,'0,0,32'],[0.33,'0,16,128'],[0.66,'0,128,255'],[1,'128,224,255']],
lava: [[0,'0,0,0'],[0.25,'128,0,0'],[0.5,'255,32,0'],[0.75,'255,160,0'],[1,'255,255,128']],
forest: [[0,'0,16,0'],[0.33,'0,80,0'],[0.66,'32,160,0'],[1,'128,255,64']],
rainbow: [[0,'255,0,0'],[0.17,'255,255,0'],[0.33,'0,255,0'],[0.5,'0,255,255'],[0.67,'0,0,255'],[0.83,'255,0,255'],[1,'255,0,0']],
aurora: [[0,'0,16,32'],[0.2,'0,80,64'],[0.4,'0,200,100'],[0.6,'64,128,255'],[0.8,'128,0,200'],[1,'0,16,32']],
sunset: [[0,'32,0,64'],[0.25,'128,0,128'],[0.5,'255,64,0'],[0.75,'255,192,64'],[1,'255,255,192']],
ice: [[0,'0,0,64'],[0.33,'0,64,192'],[0.66,'128,192,255'],[1,'240,248,255']],
};
// Default palette per effect type
const _EFFECT_DEFAULT_PALETTE = {
fire: 'fire', meteor: 'fire', plasma: 'rainbow', noise: 'rainbow', aurora: 'aurora',
};
export function updateEffectPreview() {
const el = document.getElementById('css-editor-effect-preview');
if (!el) return;
const et = document.getElementById('css-editor-effect-type').value;
if (et === 'meteor') {
const color = document.getElementById('css-editor-effect-color').value;
el.style.background = color;
} else {
const palette = document.getElementById('css-editor-effect-palette').value || _EFFECT_DEFAULT_PALETTE[et] || 'fire';
const pts = _PALETTE_COLORS[palette] || _PALETTE_COLORS.fire;
const stops = pts.map(([pos, rgb]) => `rgb(${rgb}) ${(pos * 100).toFixed(0)}%`).join(', ');
el.style.background = `linear-gradient(to right, ${stops})`;
}
}
export function onEffectTypeChange() {
const et = document.getElementById('css-editor-effect-type').value;
// palette: all except meteor
@@ -152,6 +184,8 @@ export function onEffectTypeChange() {
descEl.textContent = desc;
descEl.style.display = desc ? '' : 'none';
}
// palette preview
updateEffectPreview();
}
/* ── Color Cycle helpers ──────────────────────────────────────── */