theme improvement

This commit is contained in:
Boof2015
2026-04-01 03:04:12 -04:00
parent d8700173f5
commit 8b39ff5732
5 changed files with 131 additions and 39 deletions
+1
View File
@@ -75,6 +75,7 @@ export function scopeSettingsToOptions(
secondaryLineColor: t.sideLine, secondaryLineColor: t.sideLine,
gradientColors: t.fillGradient, gradientColors: t.fillGradient,
heatColors: t.heatColors, heatColors: t.heatColors,
heatBaseColor: t.heatBase,
backgroundColor: t.background, backgroundColor: t.background,
gridColor: t.guides, gridColor: t.guides,
labelColor: t.labels, labelColor: t.labels,
+17 -16
View File
@@ -14,6 +14,7 @@
--glass-bg: rgba(255, 255, 255, 0.03); --glass-bg: rgba(255, 255, 255, 0.03);
--glass-border: rgba(255, 255, 255, 0.08); --glass-border: rgba(255, 255, 255, 0.08);
--glass-highlight: rgba(255, 255, 255, 0.045); --glass-highlight: rgba(255, 255, 255, 0.045);
--glass-highlight-strong: rgba(255, 255, 255, 0.14);
--text-primary: rgba(255, 255, 255, 0.95); --text-primary: rgba(255, 255, 255, 0.95);
--text-secondary: rgba(255, 255, 255, 0.62); --text-secondary: rgba(255, 255, 255, 0.62);
@@ -377,7 +378,7 @@ select {
border-radius: 999px; border-radius: 999px;
border: 1px solid var(--control-border); border: 1px solid var(--control-border);
background: var(--control-bg); background: var(--control-bg);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.04); box-shadow: inset 0 1px 0 var(--glass-highlight);
color: var(--text-secondary); color: var(--text-secondary);
font-family: 'JetBrains Mono', monospace; font-family: 'JetBrains Mono', monospace;
font-size: 9px; font-size: 9px;
@@ -461,7 +462,7 @@ select {
border-radius: 999px; border-radius: 999px;
border: 1px solid var(--control-border); border: 1px solid var(--control-border);
background: var(--control-bg); background: var(--control-bg);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.04); box-shadow: inset 0 1px 0 var(--glass-highlight);
color: var(--text-tertiary); color: var(--text-tertiary);
font-size: 9px; font-size: 9px;
cursor: pointer; cursor: pointer;
@@ -497,7 +498,7 @@ select {
border-radius: 999px; border-radius: 999px;
border: 1px solid var(--control-border); border: 1px solid var(--control-border);
background: var(--control-bg); background: var(--control-bg);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.04); box-shadow: inset 0 1px 0 var(--glass-highlight);
color: var(--text-secondary); color: var(--text-secondary);
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
@@ -1067,7 +1068,7 @@ select {
border-radius: 10px; border-radius: 10px;
border: 1px solid var(--control-border); border: 1px solid var(--control-border);
background: var(--control-bg); background: var(--control-bg);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.04); box-shadow: inset 0 1px 0 var(--glass-highlight);
color: var(--control-text); color: var(--control-text);
font-size: 11px; font-size: 11px;
transition: border-color 140ms ease, background-color 140ms ease, box-shadow 140ms ease, color 140ms ease; transition: border-color 140ms ease, background-color 140ms ease, box-shadow 140ms ease, color 140ms ease;
@@ -1152,9 +1153,9 @@ select {
border: 1px solid var(--control-border); border: 1px solid var(--control-border);
background: background:
linear-gradient(90deg, var(--slider-fill), var(--slider-fill)) 0 / var(--range-percent) 100% no-repeat, linear-gradient(90deg, var(--slider-fill), var(--slider-fill)) 0 / var(--range-percent) 100% no-repeat,
linear-gradient(180deg, var(--slider-track), rgba(255, 255, 255, 0.04)); linear-gradient(180deg, var(--slider-track), var(--glass-highlight));
box-shadow: box-shadow:
inset 0 1px 0 rgba(255, 255, 255, 0.05), inset 0 1px 0 var(--glass-highlight),
0 0 0 1px rgba(0, 0, 0, 0.22); 0 0 0 1px rgba(0, 0, 0, 0.22);
} }
@@ -1167,7 +1168,7 @@ select {
border: 1px solid var(--control-border-active); border: 1px solid var(--control-border-active);
background: var(--slider-thumb); background: var(--slider-thumb);
box-shadow: box-shadow:
inset 0 1px 0 rgba(255, 255, 255, 0.12), inset 0 1px 0 var(--glass-highlight-strong),
0 0 0 2px rgba(var(--accent-rgb), 0.14), 0 0 0 2px rgba(var(--accent-rgb), 0.14),
0 3px 8px rgba(0, 0, 0, 0.35); 0 3px 8px rgba(0, 0, 0, 0.35);
} }
@@ -1176,9 +1177,9 @@ select {
height: 6px; height: 6px;
border-radius: 999px; border-radius: 999px;
border: 1px solid var(--control-border); border: 1px solid var(--control-border);
background: linear-gradient(180deg, var(--slider-track), rgba(255, 255, 255, 0.04)); background: linear-gradient(180deg, var(--slider-track), var(--glass-highlight));
box-shadow: box-shadow:
inset 0 1px 0 rgba(255, 255, 255, 0.05), inset 0 1px 0 var(--glass-highlight),
0 0 0 1px rgba(0, 0, 0, 0.22); 0 0 0 1px rgba(0, 0, 0, 0.22);
} }
@@ -1189,7 +1190,7 @@ select {
border: 1px solid var(--control-border-active); border: 1px solid var(--control-border-active);
background: var(--slider-thumb); background: var(--slider-thumb);
box-shadow: box-shadow:
inset 0 1px 0 rgba(255, 255, 255, 0.12), inset 0 1px 0 var(--glass-highlight-strong),
0 0 0 2px rgba(var(--accent-rgb), 0.14), 0 0 0 2px rgba(var(--accent-rgb), 0.14),
0 3px 8px rgba(0, 0, 0, 0.35); 0 3px 8px rgba(0, 0, 0, 0.35);
} }
@@ -1197,7 +1198,7 @@ select {
.settings-control__range::-moz-range-progress { .settings-control__range::-moz-range-progress {
height: 6px; height: 6px;
border-radius: 999px; border-radius: 999px;
border: 1px solid rgba(255, 255, 255, 0.02); border: 1px solid var(--glass-highlight);
background: linear-gradient(90deg, var(--slider-fill), var(--slider-fill)); background: linear-gradient(90deg, var(--slider-fill), var(--slider-fill));
} }
@@ -1217,7 +1218,7 @@ select {
.settings-control__range:focus-visible::-webkit-slider-thumb { .settings-control__range:focus-visible::-webkit-slider-thumb {
border-color: rgba(var(--accent-rgb), 0.96); border-color: rgba(var(--accent-rgb), 0.96);
box-shadow: box-shadow:
inset 0 1px 0 rgba(255, 255, 255, 0.16), inset 0 1px 0 var(--glass-highlight-strong),
0 0 0 3px rgba(var(--accent-rgb), 0.18), 0 0 0 3px rgba(var(--accent-rgb), 0.18),
0 3px 10px rgba(0, 0, 0, 0.4); 0 3px 10px rgba(0, 0, 0, 0.4);
} }
@@ -1226,7 +1227,7 @@ select {
.settings-control__range:focus-visible::-moz-range-thumb { .settings-control__range:focus-visible::-moz-range-thumb {
border-color: rgba(var(--accent-rgb), 0.96); border-color: rgba(var(--accent-rgb), 0.96);
box-shadow: box-shadow:
inset 0 1px 0 rgba(255, 255, 255, 0.16), inset 0 1px 0 var(--glass-highlight-strong),
0 0 0 3px rgba(var(--accent-rgb), 0.18), 0 0 0 3px rgba(var(--accent-rgb), 0.18),
0 3px 10px rgba(0, 0, 0, 0.4); 0 3px 10px rgba(0, 0, 0, 0.4);
} }
@@ -1392,7 +1393,7 @@ select {
background: linear-gradient(180deg, var(--input-bg), var(--settings-bg-bottom)); background: linear-gradient(180deg, var(--input-bg), var(--settings-bg-bottom));
cursor: pointer; cursor: pointer;
padding: 3px 4px; padding: 3px 4px;
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.04); box-shadow: inset 0 1px 0 var(--glass-highlight);
} }
.settings-panel__close { .settings-panel__close {
@@ -1739,7 +1740,7 @@ select {
border-radius: 999px; border-radius: 999px;
border: 1px solid transparent; border: 1px solid transparent;
background: var(--control-bg); background: var(--control-bg);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.04); box-shadow: inset 0 1px 0 var(--glass-highlight);
color: var(--text-secondary); color: var(--text-secondary);
cursor: pointer; cursor: pointer;
transition: color 120ms ease, border-color 120ms ease, background-color 120ms ease, transform 120ms ease; transition: color 120ms ease, border-color 120ms ease, background-color 120ms ease, transform 120ms ease;
@@ -1770,7 +1771,7 @@ select {
.settings-control__select:focus-within { .settings-control__select:focus-within {
outline: none; outline: none;
box-shadow: box-shadow:
inset 0 1px 0 rgba(255, 255, 255, 0.06), inset 0 1px 0 var(--glass-highlight),
0 0 0 1px rgba(var(--accent-rgb), 0.32), 0 0 0 1px rgba(var(--accent-rgb), 0.32),
0 0 0 4px rgba(var(--accent-rgb), 0.12); 0 0 0 4px rgba(var(--accent-rgb), 0.12);
} }
@@ -29,6 +29,7 @@ export interface SpectrumAnalyzerOptions {
heatmapFill?: boolean heatmapFill?: boolean
gradientColors?: string[] gradientColors?: string[]
heatColors?: [string, string, string] heatColors?: [string, string, string]
heatBaseColor?: string
backgroundColor?: string backgroundColor?: string
showGrid?: boolean showGrid?: boolean
gridColor?: string gridColor?: string
@@ -198,6 +199,7 @@ const defaultOptions: ResolvedSpectrumAnalyzerOptions = {
heatmapFill: false, heatmapFill: false,
gradientColors: ['rgba(0, 255, 255, 0)', 'rgba(0, 255, 255, 0.3)', 'rgba(138, 43, 226, 0.5)'], gradientColors: ['rgba(0, 255, 255, 0)', 'rgba(0, 255, 255, 0.3)', 'rgba(138, 43, 226, 0.5)'],
heatColors: [...LEGACY_DEFAULT_HEAT_COLORS], heatColors: [...LEGACY_DEFAULT_HEAT_COLORS],
heatBaseColor: 'transparent',
backgroundColor: 'transparent', backgroundColor: 'transparent',
showGrid: true, showGrid: true,
gridColor: 'rgba(255, 255, 255, 0.1)', gridColor: 'rgba(255, 255, 255, 0.1)',
@@ -636,6 +638,12 @@ export class SpectrumAnalyzer {
} }
private renderHeatmap(xPoints: Float32Array, yPoints: Float32Array, heatmapIntensity: Float32Array, pointCount: number, width: number, height: number): void { private renderHeatmap(xPoints: Float32Array, yPoints: Float32Array, heatmapIntensity: Float32Array, pointCount: number, width: number, height: number): void {
const baseColor = this.options.heatBaseColor
if (baseColor && baseColor !== 'transparent') {
this.ctx.fillStyle = baseColor
this.ctx.fillRect(0, 0, width, height)
}
for (let index = 0; index < pointCount; index += 1) { for (let index = 0; index < pointCount; index += 1) {
const x = Math.floor(xPoints[index]) const x = Math.floor(xPoints[index])
const y = yPoints[index] const y = yPoints[index]
+90 -23
View File
@@ -63,6 +63,10 @@ const APP_SCHEMA = {
border: 'border', border: 'border',
text: 'text', text: 'text',
text_muted: 'textMuted', text_muted: 'textMuted',
toolbar_bg: 'toolbarBg',
settings_bg_top: 'settingsBgTop',
settings_bg_bottom: 'settingsBgBottom',
bottom_bar_bg: 'bottomBarBg',
} as const satisfies SectionSchema<ThemeAppTokens> } as const satisfies SectionSchema<ThemeAppTokens>
const CONTROLS_SCHEMA = { const CONTROLS_SCHEMA = {
@@ -77,6 +81,7 @@ const CONTROLS_SCHEMA = {
menu_surface: 'menuSurface', menu_surface: 'menuSurface',
menu_border: 'menuBorder', menu_border: 'menuBorder',
slider: 'slider', slider: 'slider',
flat_controls: 'flatControls',
} as const satisfies SectionSchema<ThemeControlsTokens> } as const satisfies SectionSchema<ThemeControlsTokens>
const SCOPES_SCHEMA = { const SCOPES_SCHEMA = {
@@ -95,11 +100,14 @@ const SPECTRUM_SCHEMA = {
heat_low: 'heatLow', heat_low: 'heatLow',
heat_mid: 'heatMid', heat_mid: 'heatMid',
heat_high: 'heatHigh', heat_high: 'heatHigh',
heat_base: 'heatBase',
guides: 'guides',
} as const satisfies SectionSchema<ThemeSpectrumTokens> } as const satisfies SectionSchema<ThemeSpectrumTokens>
const OSCILLOSCOPE_SCHEMA = { const OSCILLOSCOPE_SCHEMA = {
line: 'line', line: 'line',
fill: 'fill', fill: 'fill',
guides: 'guides',
} as const satisfies SectionSchema<ThemeOscilloscopeTokens> } as const satisfies SectionSchema<ThemeOscilloscopeTokens>
const VECTORSCOPE_SCHEMA = { const VECTORSCOPE_SCHEMA = {
@@ -107,6 +115,7 @@ const VECTORSCOPE_SCHEMA = {
band_low: 'bandLow', band_low: 'bandLow',
band_mid: 'bandMid', band_mid: 'bandMid',
band_high: 'bandHigh', band_high: 'bandHigh',
guides: 'guides',
} as const satisfies SectionSchema<ThemeVectorscopeTokens> } as const satisfies SectionSchema<ThemeVectorscopeTokens>
const SPECTROGRAM_SCHEMA = { const SPECTROGRAM_SCHEMA = {
@@ -121,12 +130,14 @@ const VUMETER_SCHEMA = {
track: 'track', track: 'track',
peak: 'peak', peak: 'peak',
clip: 'clip', clip: 'clip',
scale: 'scale',
} as const satisfies SectionSchema<ThemeVUMeterTokens> } as const satisfies SectionSchema<ThemeVUMeterTokens>
const LUFSMETER_SCHEMA = { const LUFSMETER_SCHEMA = {
level: 'level', level: 'level',
track: 'track', track: 'track',
target: 'target', target: 'target',
scale: 'scale',
} as const satisfies SectionSchema<ThemeLUFSMeterTokens> } as const satisfies SectionSchema<ThemeLUFSMeterTokens>
const WAVEFORM_SCHEMA = { const WAVEFORM_SCHEMA = {
@@ -134,6 +145,7 @@ const WAVEFORM_SCHEMA = {
band_low: 'bandLow', band_low: 'bandLow',
band_mid: 'bandMid', band_mid: 'bandMid',
band_high: 'bandHigh', band_high: 'bandHigh',
guides: 'guides',
} as const satisfies SectionSchema<ThemeWaveformTokens> } as const satisfies SectionSchema<ThemeWaveformTokens>
const ASTRA_SCHEMA = { const ASTRA_SCHEMA = {
@@ -414,6 +426,8 @@ function createEmptyTheme(): PrismTheme {
} }
} }
const PASSTHROUGH_KEYS: ReadonlySet<string> = new Set(['flatControls'])
function normalizeSectionTokens<T extends SectionTokenMap>( function normalizeSectionTokens<T extends SectionTokenMap>(
raw: unknown, raw: unknown,
schema: SectionSchema<T>, schema: SectionSchema<T>,
@@ -433,6 +447,11 @@ function normalizeSectionTokens<T extends SectionTokenMap>(
})?.[1] as keyof T | undefined })?.[1] as keyof T | undefined
if (!key) continue if (!key) continue
if (PASSTHROUGH_KEYS.has(key as string)) {
next[key] = rawValue as T[typeof key]
continue
}
const parsedColor = parseCssColor(rawValue) ?? parseThemeChannelColor(rawValue) const parsedColor = parseCssColor(rawValue) ?? parseThemeChannelColor(rawValue)
if (!parsedColor) continue if (!parsedColor) continue
next[key] = toCssColor(quantizeThemeColor(parsedColor)) as T[typeof key] next[key] = toCssColor(quantizeThemeColor(parsedColor)) as T[typeof key]
@@ -761,7 +780,11 @@ function serializeSection<T extends SectionTokenMap>(
for (const [serializedKey, propertyKey] of Object.entries(schema)) { for (const [serializedKey, propertyKey] of Object.entries(schema)) {
const value = tokens[propertyKey as keyof T] const value = tokens[propertyKey as keyof T]
if (!value) continue if (!value) continue
lines.push(`${serializedKey} = ${toThemeChannels(value)}`) if (PASSTHROUGH_KEYS.has(propertyKey)) {
lines.push(`${serializedKey} = ${value}`)
} else {
lines.push(`${serializedKey} = ${toThemeChannels(value)}`)
}
} }
return lines return lines
@@ -805,10 +828,29 @@ export function createTemplateThemeFile(): string {
# Authoring rules: # Authoring rules:
# - Colors use R, G, B or R, G, B, A (0-255) # - Colors use R, G, B or R, G, B, A (0-255)
# - CSS colors like #hex, rgb(), and rgba() also work # - CSS colors like #hex, rgb(), and rgba() also work
# - [App] controls the overall chrome and text #
# - [Controls] covers buttons, inputs, menus, and sliders # ── UI ──
# - [Scopes] covers the shared analyzer background and guide system # [App] Overall window chrome, background, and text
# - Scope sections should only override visuals unique to that module # toolbar_bg, settings_bg_top, settings_bg_bottom, bottom_bar_bg
# can be set to override the default derived values
# [Controls] Buttons, inputs, menus, and sliders
# Set flat_controls = true to disable glass highlights/gradients
#
# ── Scopes ──
# [Scopes] Shared background and guide color for all scopes
# background defaults to [App] background if not set
# Set it explicitly here to decouple scope bg from window bg
#
# Per-scope sections override colors unique to that module.
# Each scope can set its own guides to override the shared [Scopes] guides.
#
# [Spectrum] line, fill, heat gradient (heat_low/mid/high/base), guides
# [Oscilloscope] line, fill, guides
# [Vectorscope] trace, band_low/mid/high (RGB overlay colors), guides
# [Spectrogram] mono, heat gradient
# [VUMeter] level, track, peak, clip, scale
# [LUFSMeter] level, track, target, scale
# [Waveform] line, band_low/mid/high, guides
# #
${serializeThemeFile(template)}` ${serializeThemeFile(template)}`
} }
@@ -824,6 +866,10 @@ interface ResolvedAppTokens {
border: string border: string
text: string text: string
textMuted: string textMuted: string
toolbarBg: string | null
settingsBgTop: string | null
settingsBgBottom: string | null
bottomBarBg: string | null
} }
interface ResolvedControlsTokens { interface ResolvedControlsTokens {
@@ -838,6 +884,7 @@ interface ResolvedControlsTokens {
menuSurface: string menuSurface: string
menuBorder: string menuBorder: string
slider: string slider: string
flatControls: boolean
} }
interface ResolvedScopesTokens { interface ResolvedScopesTokens {
@@ -871,6 +918,10 @@ function resolveAppTokens(tokens: ThemeAppTokens): ResolvedAppTokens {
border, border,
text, text,
textMuted, textMuted,
toolbarBg: tokens.toolbarBg ?? null,
settingsBgTop: tokens.settingsBgTop ?? null,
settingsBgBottom: tokens.settingsBgBottom ?? null,
bottomBarBg: tokens.bottomBarBg ?? null,
} }
} }
@@ -888,6 +939,7 @@ function resolveControlsTokens(tokens: ThemeControlsTokens, app: ResolvedAppToke
menuSurface: tokens.menuSurface ?? app.surface, menuSurface: tokens.menuSurface ?? app.surface,
menuBorder: tokens.menuBorder ?? 'rgba(255, 255, 255, 0.1)', menuBorder: tokens.menuBorder ?? 'rgba(255, 255, 255, 0.1)',
slider: tokens.slider ?? withAlpha(app.accent, 0.82), slider: tokens.slider ?? withAlpha(app.accent, 0.82),
flatControls: tokens.flatControls === 'true',
} }
} }
@@ -910,6 +962,12 @@ function resolveInterfaceTheme(
controls: ResolvedControlsTokens, controls: ResolvedControlsTokens,
scopes: ResolvedScopesTokens, scopes: ResolvedScopesTokens,
): ResolvedInterfaceTheme { ): ResolvedInterfaceTheme {
const bgParsed = parseCssColor(app.background)
const colorScheme: 'light' | 'dark' = bgParsed && getPerceivedBrightness(bgParsed) >= 156 ? 'light' : 'dark'
const glassHighlight = controls.flatControls ? 'transparent' : withAlpha(app.text, 0.05)
const glassBg = controls.flatControls ? 'transparent' : withAlpha(app.surface, 0.18)
return { return {
primary: app.accent, primary: app.accent,
secondary: app.surfaceAlt, secondary: app.surfaceAlt,
@@ -920,6 +978,7 @@ function resolveInterfaceTheme(
accentHover: lighten(app.accent, 0.2), accentHover: lighten(app.accent, 0.2),
accentGlow: withAlpha(app.accent, 0.3), accentGlow: withAlpha(app.accent, 0.3),
accentRgb: colorToRgbChannels(app.accent), accentRgb: colorToRgbChannels(app.accent),
colorScheme,
bgPrimary: app.background, bgPrimary: app.background,
bgSecondary: darken(app.background, 0.04), bgSecondary: darken(app.background, 0.04),
bgTertiary: darken(app.background, 0.08), bgTertiary: darken(app.background, 0.08),
@@ -927,17 +986,18 @@ function resolveInterfaceTheme(
panelSurfaceSoft: app.surfaceAlt, panelSurfaceSoft: app.surfaceAlt,
panelOutline: app.border, panelOutline: app.border,
panelOutlineStrong: withAlpha(app.border, 0.9), panelOutlineStrong: withAlpha(app.border, 0.9),
glassBg: withAlpha(app.surface, 0.18), glassBg,
glassBorder: withAlpha(app.border, 0.85), glassBorder: withAlpha(app.border, 0.85),
glassHighlight: withAlpha(app.text, 0.05), glassHighlight,
glassHighlightStrong: controls.flatControls ? 'transparent' : withAlpha(app.text, 0.14),
textPrimary: app.text, textPrimary: app.text,
textSecondary: blendText(app.text, app.textMuted, 0.45), textSecondary: blendText(app.text, app.textMuted, 0.45),
textTertiary: blendText(app.text, app.textMuted, 0.7), textTertiary: blendText(app.text, app.textMuted, 0.7),
textMuted: app.textMuted, textMuted: app.textMuted,
toolbarBg: withAlpha(app.surfaceAlt, 0.78), toolbarBg: app.toolbarBg ?? withAlpha(app.surfaceAlt, 0.78),
settingsBgTop: app.surface, settingsBgTop: app.settingsBgTop ?? app.surface,
settingsBgBottom: app.surfaceAlt, settingsBgBottom: app.settingsBgBottom ?? app.surfaceAlt,
bottomBarBg: withAlpha(app.surfaceAlt, 0.98), bottomBarBg: app.bottomBarBg ?? withAlpha(app.surfaceAlt, 0.98),
menuBg: controls.menuSurface, menuBg: controls.menuSurface,
menuBorder: controls.menuBorder, menuBorder: controls.menuBorder,
controlBg: controls.surface, controlBg: controls.surface,
@@ -977,12 +1037,13 @@ function resolveSpectrumTheme(
const line = section.line ?? app.accent const line = section.line ?? app.accent
const sideLine = section.sideLine ?? withAlpha(line, 0.5) const sideLine = section.sideLine ?? withAlpha(line, 0.5)
const fill = section.fill ?? withAlpha(line, 0.34) const fill = section.fill ?? withAlpha(line, 0.34)
const guides = section.guides ?? scopes.guides
return { return {
line, line,
sideLine, sideLine,
guides: scopes.guides, guides,
guidesSecondary: scopes.guidesSecondary, guidesSecondary: multiplyAlpha(guides, 0.5),
labels: scopes.labels, labels: section.guides ? guides : scopes.labels,
background: scopes.background, background: scopes.background,
fill, fill,
fillGradient: [ fillGradient: [
@@ -995,6 +1056,7 @@ function resolveSpectrumTheme(
section.heatMid ?? DEFAULT_HEAT_MID, section.heatMid ?? DEFAULT_HEAT_MID,
section.heatHigh ?? DEFAULT_HEAT_HIGH, section.heatHigh ?? DEFAULT_HEAT_HIGH,
], ],
heatBase: section.heatBase ?? scopes.background,
} }
} }
@@ -1003,10 +1065,11 @@ function resolveOscilloscopeTheme(
app: ResolvedAppTokens, app: ResolvedAppTokens,
scopes: ResolvedScopesTokens, scopes: ResolvedScopesTokens,
): ResolvedOscilloscopeTheme { ): ResolvedOscilloscopeTheme {
const guides = theme.oscilloscope.guides ?? scopes.guides
return { return {
line: theme.oscilloscope.line ?? app.accent, line: theme.oscilloscope.line ?? app.accent,
guides: scopes.guides, guides,
guidesSecondary: scopes.guidesSecondary, guidesSecondary: multiplyAlpha(guides, 0.5),
background: scopes.background, background: scopes.background,
fill: theme.oscilloscope.fill ?? 'rgba(245, 248, 252, 0.18)', fill: theme.oscilloscope.fill ?? 'rgba(245, 248, 252, 0.18)',
} }
@@ -1017,11 +1080,12 @@ function resolveVectorscopeTheme(
app: ResolvedAppTokens, app: ResolvedAppTokens,
scopes: ResolvedScopesTokens, scopes: ResolvedScopesTokens,
): ResolvedVectorscopeTheme { ): ResolvedVectorscopeTheme {
const guides = theme.vectorscope.guides ?? scopes.guides
return { return {
trace: theme.vectorscope.trace ?? app.accent, trace: theme.vectorscope.trace ?? app.accent,
guides: scopes.guides, guides,
guidesSecondary: scopes.guidesSecondary, guidesSecondary: multiplyAlpha(guides, 0.5),
labels: scopes.labels, labels: theme.vectorscope.guides ? guides : scopes.labels,
background: scopes.background, background: scopes.background,
bandLow: theme.vectorscope.bandLow ?? DEFAULT_BAND_LOW, bandLow: theme.vectorscope.bandLow ?? DEFAULT_BAND_LOW,
bandMid: theme.vectorscope.bandMid ?? DEFAULT_BAND_MID, bandMid: theme.vectorscope.bandMid ?? DEFAULT_BAND_MID,
@@ -1056,7 +1120,7 @@ function resolveVUMeterTheme(
track: theme.vumeter.track ?? withAlpha(level, 0.08), track: theme.vumeter.track ?? withAlpha(level, 0.08),
peak: theme.vumeter.peak ?? 'rgb(255, 127, 0)', peak: theme.vumeter.peak ?? 'rgb(255, 127, 0)',
clip: theme.vumeter.clip ?? 'rgba(255, 120, 80, 0.9)', clip: theme.vumeter.clip ?? 'rgba(255, 120, 80, 0.9)',
scale: scopes.guides, scale: theme.vumeter.scale ?? scopes.guides,
labels: blendText(app.text, app.textMuted, 0.35), labels: blendText(app.text, app.textMuted, 0.35),
background: scopes.background, background: scopes.background,
} }
@@ -1072,7 +1136,7 @@ function resolveLUFSMeterTheme(
level, level,
track: theme.lufsmeter.track ?? withAlpha(level, 0.08), track: theme.lufsmeter.track ?? withAlpha(level, 0.08),
target: theme.lufsmeter.target ?? withAlpha(level, 0.25), target: theme.lufsmeter.target ?? withAlpha(level, 0.25),
scale: scopes.guides, scale: theme.lufsmeter.scale ?? scopes.guides,
labels: blendText(app.text, app.textMuted, 0.2), labels: blendText(app.text, app.textMuted, 0.2),
background: scopes.background, background: scopes.background,
} }
@@ -1083,10 +1147,11 @@ function resolveWaveformTheme(
app: ResolvedAppTokens, app: ResolvedAppTokens,
scopes: ResolvedScopesTokens, scopes: ResolvedScopesTokens,
): ResolvedWaveformTheme { ): ResolvedWaveformTheme {
const guides = theme.waveform.guides ?? scopes.guides
return { return {
line: theme.waveform.line ?? app.accent, line: theme.waveform.line ?? app.accent,
guides: scopes.guides, guides,
guidesSecondary: scopes.guidesSecondary, guidesSecondary: multiplyAlpha(guides, 0.5),
background: scopes.background, background: scopes.background,
bandLow: theme.waveform.bandLow ?? DEFAULT_BAND_LOW, bandLow: theme.waveform.bandLow ?? DEFAULT_BAND_LOW,
bandMid: theme.waveform.bandMid ?? DEFAULT_BAND_MID, bandMid: theme.waveform.bandMid ?? DEFAULT_BAND_MID,
@@ -1216,6 +1281,7 @@ export function themeToCssVariables(theme: Pick<PrismResolvedTheme, 'interface'>
'--glass-bg': ui.glassBg, '--glass-bg': ui.glassBg,
'--glass-border': ui.glassBorder, '--glass-border': ui.glassBorder,
'--glass-highlight': ui.glassHighlight, '--glass-highlight': ui.glassHighlight,
'--glass-highlight-strong': ui.glassHighlightStrong,
'--text-primary': ui.textPrimary, '--text-primary': ui.textPrimary,
'--text-secondary': ui.textSecondary, '--text-secondary': ui.textSecondary,
'--text-tertiary': ui.textTertiary, '--text-tertiary': ui.textTertiary,
@@ -1266,6 +1332,7 @@ export function applyResolvedThemeToDocument(
for (const [name, value] of Object.entries(variables)) { for (const [name, value] of Object.entries(variables)) {
root.setProperty(name, value) root.setProperty(name, value)
} }
root.setProperty('color-scheme', theme.interface.colorScheme)
} }
export function getDefaultThemeIdForLocalState(): string { export function getDefaultThemeIdForLocalState(): string {
+15
View File
@@ -25,6 +25,10 @@ export interface ThemeAppTokens {
border?: string border?: string
text?: string text?: string
textMuted?: string textMuted?: string
toolbarBg?: string
settingsBgTop?: string
settingsBgBottom?: string
bottomBarBg?: string
} }
export interface ThemeControlsTokens { export interface ThemeControlsTokens {
@@ -39,6 +43,7 @@ export interface ThemeControlsTokens {
menuSurface?: string menuSurface?: string
menuBorder?: string menuBorder?: string
slider?: string slider?: string
flatControls?: string
} }
export interface ThemeScopesTokens { export interface ThemeScopesTokens {
@@ -57,11 +62,14 @@ export interface ThemeSpectrumTokens {
heatLow?: string heatLow?: string
heatMid?: string heatMid?: string
heatHigh?: string heatHigh?: string
heatBase?: string
guides?: string
} }
export interface ThemeOscilloscopeTokens { export interface ThemeOscilloscopeTokens {
line?: string line?: string
fill?: string fill?: string
guides?: string
} }
export interface ThemeVectorscopeTokens { export interface ThemeVectorscopeTokens {
@@ -69,6 +77,7 @@ export interface ThemeVectorscopeTokens {
bandLow?: string bandLow?: string
bandMid?: string bandMid?: string
bandHigh?: string bandHigh?: string
guides?: string
} }
export interface ThemeSpectrogramTokens { export interface ThemeSpectrogramTokens {
@@ -83,12 +92,14 @@ export interface ThemeVUMeterTokens {
track?: string track?: string
peak?: string peak?: string
clip?: string clip?: string
scale?: string
} }
export interface ThemeLUFSMeterTokens { export interface ThemeLUFSMeterTokens {
level?: string level?: string
track?: string track?: string
target?: string target?: string
scale?: string
} }
export interface ThemeWaveformTokens { export interface ThemeWaveformTokens {
@@ -96,6 +107,7 @@ export interface ThemeWaveformTokens {
bandLow?: string bandLow?: string
bandMid?: string bandMid?: string
bandHigh?: string bandHigh?: string
guides?: string
} }
export interface ThemeAstraTokens { export interface ThemeAstraTokens {
@@ -176,9 +188,11 @@ export interface ResolvedInterfaceTheme {
panelSurfaceSoft: string panelSurfaceSoft: string
panelOutline: string panelOutline: string
panelOutlineStrong: string panelOutlineStrong: string
colorScheme: 'light' | 'dark'
glassBg: string glassBg: string
glassBorder: string glassBorder: string
glassHighlight: string glassHighlight: string
glassHighlightStrong: string
textPrimary: string textPrimary: string
textSecondary: string textSecondary: string
textTertiary: string textTertiary: string
@@ -226,6 +240,7 @@ export interface ResolvedSpectrumTheme {
fill: string fill: string
fillGradient: [string, string, string] fillGradient: [string, string, string]
heatColors: [string, string, string] heatColors: [string, string, string]
heatBase: string
} }
export interface ResolvedOscilloscopeTheme { export interface ResolvedOscilloscopeTheme {