diff --git a/src/renderer/audio/AudioCapture.ts b/src/renderer/audio/AudioCapture.ts index 323e0c8..b23a846 100644 --- a/src/renderer/audio/AudioCapture.ts +++ b/src/renderer/audio/AudioCapture.ts @@ -64,6 +64,7 @@ function resolveNativeCapturePollDelay(chunkCount: number): number { return chunkCount > 0 ? 0 : 2 } + export interface CaptureManagerStatus { captureMode: CaptureMode backendPolicy: CaptureBackendPolicy @@ -860,10 +861,6 @@ class AudioCapture { capturedAt: chunk.capturedAt, sequence: chunk.sequence, }) - nativeVisualizerTransport.handleChunk(chunk.left, chunk.right, { - sessionId: this.sessionId, - channelCount: chunk.channelCount, - }) } setInputGain(db: number): void { diff --git a/src/renderer/audio/NativeVisualizerTransport.ts b/src/renderer/audio/NativeVisualizerTransport.ts index 77311f5..94aedf5 100644 --- a/src/renderer/audio/NativeVisualizerTransport.ts +++ b/src/renderer/audio/NativeVisualizerTransport.ts @@ -1,11 +1,6 @@ import { oscilloscope, spectrum, vectorscope, isNativeAvailable } from './native' import type { VisualizerConsumerDemand } from './AudioRouter' -export interface NativeVisualizerTransportChunkMeta { - sessionId?: number - channelCount?: number -} - export interface NativeVisualizerTransportSessionState { sessionId: number sampleRate: number @@ -78,23 +73,12 @@ function normalizeDemand(demand: VisualizerConsumerDemand): Required = { ...EMPTY_DEMAND } - private sessionId = 0 private sampleRate = 48000 - private capturing = false - private hasSpectrumData = false - private spectrumMonoScratch = new Float32Array(0) constructor(bridge: NativeVisualizerTransportBridge = defaultBridge) { this.bridge = bridge } - private ensureSpectrumMonoScratch(length: number): Float32Array { - if (this.spectrumMonoScratch.length !== length) { - this.spectrumMonoScratch = new Float32Array(length) - } - return this.spectrumMonoScratch - } - setDemand(demand: VisualizerConsumerDemand): void { const nextDemand = normalizeDemand(demand) if ( @@ -115,7 +99,6 @@ export class NativeVisualizerTransport { } if (this.demand.spectrum && !nextDemand.spectrum) { this.bridge.spectrum.reset() - this.hasSpectrumData = false } if (this.demand.vectorscope && !nextDemand.vectorscope) { this.bridge.vectorscope.reset() @@ -125,7 +108,6 @@ export class NativeVisualizerTransport { } if (!this.demand.spectrum && nextDemand.spectrum) { this.bridge.spectrum.setSampleRate(this.sampleRate) - this.hasSpectrumData = false } if (!this.demand.vectorscope && nextDemand.vectorscope) { this.bridge.vectorscope.setSampleRate(this.sampleRate) @@ -135,52 +117,8 @@ export class NativeVisualizerTransport { this.demand = nextDemand } - handleChunk(left: Float32Array, right: Float32Array, meta: NativeVisualizerTransportChunkMeta = {}): void { - if (!this.capturing || !this.bridge.isAvailable()) { - return - } - - if (meta.sessionId !== undefined && meta.sessionId !== this.sessionId) { - return - } - - if (!this.demand.oscilloscope && !this.demand.spectrum && !this.demand.vectorscope) { - return - } - - const effectiveChannelCount = Math.max(1, Math.floor(meta.channelCount ?? 2) || 1) - const resolvedRight = effectiveChannelCount > 1 && right.length > 0 ? right : left - const length = Math.min(left.length, resolvedRight.length) - if (length === 0) { - return - } - - const leftSamples = left.length === length ? left : left.subarray(0, length) - const rightSamples = resolvedRight.length === length ? resolvedRight : resolvedRight.subarray(0, length) - - if (this.demand.oscilloscope) { - this.bridge.oscilloscope.pushSamples(leftSamples) - } - - if (this.demand.vectorscope) { - this.bridge.vectorscope.pushSamples(leftSamples, rightSamples) - } - - if (this.demand.spectrum) { - const mono = this.ensureSpectrumMonoScratch(length) - for (let index = 0; index < length; index += 1) { - mono[index] = (leftSamples[index] + rightSamples[index]) * 0.5 - } - this.bridge.spectrum.pushSamples(mono) - this.hasSpectrumData = true - } - } - reset(sessionState: NativeVisualizerTransportSessionState): void { - this.sessionId = sessionState.sessionId - this.capturing = sessionState.capturing this.sampleRate = Math.max(1, Math.floor(sessionState.sampleRate) || 1) - this.hasSpectrumData = false if (!this.bridge.isAvailable()) { return @@ -204,14 +142,6 @@ export class NativeVisualizerTransport { this.bridge.vectorscope.setSampleRate(this.sampleRate) } } - - fillLatestSpectrumMagnitudes(output: Float32Array): number { - if (!this.bridge.isAvailable() || !this.demand.spectrum || !this.hasSpectrumData) { - return 0 - } - - return this.bridge.spectrum.fillMagnitudes(output) - } } export const nativeVisualizerTransport = new NativeVisualizerTransport() diff --git a/src/renderer/popouts/ScopePopoutDataSource.ts b/src/renderer/popouts/ScopePopoutDataSource.ts index 3880dec..97cb6f7 100644 --- a/src/renderer/popouts/ScopePopoutDataSource.ts +++ b/src/renderer/popouts/ScopePopoutDataSource.ts @@ -58,12 +58,6 @@ export class ScopePopoutDataSource implements AnyScopeDataSource { if (isStereoScope(this.scopeKind)) { if (!isStereoBatch(batch)) return this.stereoQueue.push(...batch) - for (const chunk of batch) { - this.nativeVisualizerTransport.handleChunk(chunk.left, chunk.right, { - sessionId: this.sessionState.sessionId, - channelCount: this.sessionState.channelCount, - }) - } return } @@ -71,38 +65,16 @@ export class ScopePopoutDataSource implements AnyScopeDataSource { if (isStereoBatch(batch)) { this.monoQueue = [] this.stereoQueue.push(...batch) - if (this.scopeKind === 'spectrum') { - for (const chunk of batch) { - this.nativeVisualizerTransport.handleChunk(chunk.left, chunk.right, { - sessionId: this.sessionState.sessionId, - channelCount: this.sessionState.channelCount, - }) - } - } return } this.stereoQueue = [] this.monoQueue.push(...batch) - if (this.scopeKind === 'spectrum') { - for (const chunk of batch) { - this.nativeVisualizerTransport.handleChunk(chunk, chunk, { - sessionId: this.sessionState.sessionId, - channelCount: 1, - }) - } - } return } if (isStereoBatch(batch)) return this.monoQueue.push(...batch) - for (const chunk of batch) { - this.nativeVisualizerTransport.handleChunk(chunk, chunk, { - sessionId: this.sessionState.sessionId, - channelCount: 1, - }) - } } setSessionState(nextState: ScopePopoutSessionState): void { @@ -134,9 +106,6 @@ export class ScopePopoutDataSource implements AnyScopeDataSource { } } - getNativeVisualizerTransport(): NativeVisualizerTransport { - return this.nativeVisualizerTransport - } getPendingSpectrumSamples(): Float32Array[] { const batch = this.monoQueue diff --git a/src/renderer/visualizers/Oscilloscope.ts b/src/renderer/visualizers/Oscilloscope.ts index c8f4204..6c36a95 100644 --- a/src/renderer/visualizers/Oscilloscope.ts +++ b/src/renderer/visualizers/Oscilloscope.ts @@ -86,6 +86,7 @@ export class Oscilloscope { private staticLayerCtx: CanvasRenderingContext2D private staticLayerKey = '' private renderBuffer = new Float32Array(0) + private pushScratch = new Float32Array(0) private static readonly WARMUP_SAMPLES = 4096 constructor(canvas: HTMLCanvasElement, options: OscilloscopeOptions = {}) { @@ -186,6 +187,31 @@ export class Oscilloscope { return this.renderBuffer } + private concatMonoChunks(chunks: Float32Array[]): Float32Array { + if (chunks.length === 1) return chunks[0] + + let totalLength = 0 + for (const chunk of chunks) { + totalLength += chunk.length + } + + if (this.pushScratch.length < totalLength) { + this.pushScratch = new Float32Array(totalLength) + } + + const out = this.pushScratch.length === totalLength + ? this.pushScratch + : this.pushScratch.subarray(0, totalLength) + + let offset = 0 + for (const chunk of chunks) { + out.set(chunk, offset) + offset += chunk.length + } + + return out + } + private drawFrame = (): void => { const { canvas, ctx, options } = this const width = canvas.width @@ -207,13 +233,11 @@ export class Oscilloscope { return } - const nativeTransport = this.dataSource.getNativeVisualizerTransport?.() ?? null const pendingSamples = this.dataSource.getPendingOscilloscopeSamples() - for (const chunk of pendingSamples) { - if (!nativeTransport) { - nativeOscilloscope.pushSamples(chunk) - } - this.samplesReceived += chunk.length + if (pendingSamples.length > 0) { + const merged = this.concatMonoChunks(pendingSamples) + nativeOscilloscope.pushSamples(merged) + this.samplesReceived += merged.length } if (options.pitchLock && this.samplesReceived < Oscilloscope.WARMUP_SAMPLES) { diff --git a/src/renderer/visualizers/SpectrumAnalyzer.ts b/src/renderer/visualizers/SpectrumAnalyzer.ts index 2797da3..164b3f7 100644 --- a/src/renderer/visualizers/SpectrumAnalyzer.ts +++ b/src/renderer/visualizers/SpectrumAnalyzer.ts @@ -246,6 +246,7 @@ export class SpectrumAnalyzer { private jsBufferedSamples = 0 private jsHasSpectrumData = false private nativeMagnitudeBuffer = new Float32Array(0) + private pushScratch = new Float32Array(0) private primaryPointX = new Float32Array(0) private primaryPointY = new Float32Array(0) private primaryPointHeatmap = new Float32Array(0) @@ -497,11 +498,38 @@ export class SpectrumAnalyzer { } private pushPendingSpectrumChunks(pendingSpectrum: Float32Array[]): void { + if (pendingSpectrum.length === 0) return + + if (pendingSpectrum.length === 1) { + if (pendingSpectrum[0].length > 0) { + nativeSpectrum.pushSamples(pendingSpectrum[0]) + } + return + } + + let totalLength = 0 + for (const chunk of pendingSpectrum) { + totalLength += chunk.length + } + if (totalLength === 0) return + + if (this.pushScratch.length < totalLength) { + this.pushScratch = new Float32Array(totalLength) + } + + const merged = this.pushScratch.length === totalLength + ? this.pushScratch + : this.pushScratch.subarray(0, totalLength) + + let offset = 0 for (const chunk of pendingSpectrum) { if (chunk.length > 0) { - nativeSpectrum.pushSamples(chunk) + merged.set(chunk, offset) + offset += chunk.length } } + + nativeSpectrum.pushSamples(merged) } private clearPendingSpectrumQueues(): void { @@ -747,17 +775,12 @@ export class SpectrumAnalyzer { return } - const nativeTransport = this.dataSource.getNativeVisualizerTransport?.() ?? null const pendingSpectrum = this.dataSource.getPendingSpectrumSamples() - if (!nativeTransport) { - this.pushPendingSpectrumChunks(pendingSpectrum) - } + this.pushPendingSpectrumChunks(pendingSpectrum) const nativeMagnitudes = this.ensureNativeMagnitudeBuffer() primaryData = nativeMagnitudes - primaryDataLength = nativeTransport - ? nativeTransport.fillLatestSpectrumMagnitudes(nativeMagnitudes) - : nativeSpectrum.fillMagnitudes(nativeMagnitudes) + primaryDataLength = nativeSpectrum.fillMagnitudes(nativeMagnitudes) } if (!primaryData || primaryDataLength === 0) { diff --git a/src/renderer/visualizers/Vectorscope.ts b/src/renderer/visualizers/Vectorscope.ts index 655bb3b..a19c177 100644 --- a/src/renderer/visualizers/Vectorscope.ts +++ b/src/renderer/visualizers/Vectorscope.ts @@ -81,6 +81,8 @@ export class Vectorscope { private multibandPointScratch: MultibandChunk = createMultibandChunk(0) private nativePointX = new Float32Array(0) private nativePointY = new Float32Array(0) + private pushScratchL = new Float32Array(0) + private pushScratchR = new Float32Array(0) private staticLayerKey = '' constructor(canvas: HTMLCanvasElement, options: VectorscopeOptions = {}) { @@ -214,16 +216,14 @@ export class Vectorscope { offscreenCtx.fillRect(0, 0, width, height) offscreenCtx.globalCompositeOperation = 'source-over' - const nativeTransport = this.dataSource.getNativeVisualizerTransport?.() ?? null const pendingSamples = this.dataSource.getPendingVectorscopeSamples() if (options.multiband) { this.drawMultibandPoints(offscreenCtx, pendingSamples, centerX, centerY, scale) } else if (isNativeAvailable()) { - if (!nativeTransport) { - for (const chunk of pendingSamples) { - nativeVectorscope.pushSamples(chunk.left, chunk.right) - } + if (pendingSamples.length > 0) { + const { left, right } = this.concatStereoChunks(pendingSamples) + nativeVectorscope.pushSamples(left, right) } const count = this.fillNativePoints(options.displayPoints) @@ -423,6 +423,37 @@ export class Vectorscope { return this.multibandPointScratch } + private concatStereoChunks(chunks: Array<{ left: Float32Array; right: Float32Array }>): { left: Float32Array; right: Float32Array } { + if (chunks.length === 1) return chunks[0] + + let totalLength = 0 + for (const chunk of chunks) { + totalLength += Math.min(chunk.left.length, chunk.right.length) + } + + if (this.pushScratchL.length < totalLength) { + this.pushScratchL = new Float32Array(totalLength) + this.pushScratchR = new Float32Array(totalLength) + } + + const left = this.pushScratchL.length === totalLength + ? this.pushScratchL + : this.pushScratchL.subarray(0, totalLength) + const right = this.pushScratchR.length === totalLength + ? this.pushScratchR + : this.pushScratchR.subarray(0, totalLength) + + let offset = 0 + for (const chunk of chunks) { + const len = Math.min(chunk.left.length, chunk.right.length) + left.set(chunk.left.subarray(0, len), offset) + right.set(chunk.right.subarray(0, len), offset) + offset += len + } + + return { left, right } + } + private drawProjectedDot( ctx: CanvasRenderingContext2D, left: number, diff --git a/src/renderer/visualizers/dataSource.ts b/src/renderer/visualizers/dataSource.ts index cc6982b..8dfb308 100644 --- a/src/renderer/visualizers/dataSource.ts +++ b/src/renderer/visualizers/dataSource.ts @@ -1,18 +1,14 @@ import { audioRouter } from '../audio/AudioRouter' -import { nativeVisualizerTransport } from '../audio/NativeVisualizerTransport' import type { ScopePopoutSessionState } from '../../types/popout' -import type { NativeVisualizerTransport } from '../audio/NativeVisualizerTransport' export interface VisualizerSessionSource { getSampleRate: () => number isPlaying: () => boolean subscribeToSessionChanges: (listener: (state: ScopePopoutSessionState) => void) => () => void - getNativeVisualizerTransport?: () => NativeVisualizerTransport | null } export const defaultVisualizerSessionSource: VisualizerSessionSource = { getSampleRate: () => audioRouter.getSampleRate(), isPlaying: () => audioRouter.isCapturing(), subscribeToSessionChanges: (listener) => audioRouter.subscribeToSessionChanges((state) => listener(state)), - getNativeVisualizerTransport: () => nativeVisualizerTransport, } diff --git a/src/shared/themeState.ts b/src/shared/themeState.ts index d1ac61b..4f3273c 100644 --- a/src/shared/themeState.ts +++ b/src/shared/themeState.ts @@ -94,6 +94,7 @@ const SCOPES_SCHEMA = { } as const satisfies SectionSchema const SPECTRUM_SCHEMA = { + background: 'background', line: 'line', side_line: 'sideLine', fill: 'fill', @@ -102,23 +103,28 @@ const SPECTRUM_SCHEMA = { heat_high: 'heatHigh', heat_base: 'heatBase', guides: 'guides', + labels: 'labels', } as const satisfies SectionSchema const OSCILLOSCOPE_SCHEMA = { + background: 'background', line: 'line', fill: 'fill', guides: 'guides', } as const satisfies SectionSchema const VECTORSCOPE_SCHEMA = { + background: 'background', trace: 'trace', band_low: 'bandLow', band_mid: 'bandMid', band_high: 'bandHigh', guides: 'guides', + labels: 'labels', } as const satisfies SectionSchema const SPECTROGRAM_SCHEMA = { + background: 'background', mono: 'mono', heat_low: 'heatLow', heat_mid: 'heatMid', @@ -126,21 +132,26 @@ const SPECTROGRAM_SCHEMA = { } as const satisfies SectionSchema const VUMETER_SCHEMA = { + background: 'background', level: 'level', track: 'track', peak: 'peak', clip: 'clip', scale: 'scale', + labels: 'labels', } as const satisfies SectionSchema const LUFSMETER_SCHEMA = { + background: 'background', level: 'level', track: 'track', target: 'target', scale: 'scale', + labels: 'labels', } as const satisfies SectionSchema const WAVEFORM_SCHEMA = { + background: 'background', line: 'line', band_low: 'bandLow', band_mid: 'bandMid', @@ -817,40 +828,82 @@ export function serializeThemeFile(theme: PrismTheme): string { } export function createTemplateThemeFile(): string { - const template = createDefaultTheme() - template.id = 'theme_template' - template.name = 'Template Theme' - template.credit = 'Your Name' - template.website = 'https://example.com' + const base = createDefaultTheme() + const resolved = resolveTheme(base) + + const template: PrismTheme = { + id: 'theme_template', + name: 'Template Theme', + credit: 'Your Name', + website: 'https://example.com', + description: 'Custom Prism theme', + app: { + ...base.app, + toolbarBg: resolved.interface.toolbarBg, + settingsBgTop: resolved.interface.settingsBgTop, + settingsBgBottom: resolved.interface.settingsBgBottom, + bottomBarBg: resolved.interface.bottomBarBg, + }, + controls: { ...base.controls }, + scopes: { ...base.scopes }, + spectrum: { + ...base.spectrum, + background: resolved.spectrum.background, + guides: resolved.spectrum.guides, + labels: resolved.spectrum.labels, + heatBase: resolved.spectrum.heatBase, + }, + oscilloscope: { + ...base.oscilloscope, + background: resolved.oscilloscope.background, + guides: resolved.oscilloscope.guides, + }, + vectorscope: { + ...base.vectorscope, + background: resolved.vectorscope.background, + guides: resolved.vectorscope.guides, + labels: resolved.vectorscope.labels, + }, + spectrogram: { + ...base.spectrogram, + background: resolved.spectrogram.background, + }, + vumeter: { + ...base.vumeter, + background: resolved.vumeter.background, + scale: resolved.vumeter.scale, + labels: resolved.vumeter.labels, + }, + lufsmeter: { + ...base.lufsmeter, + background: resolved.lufsmeter.background, + scale: resolved.lufsmeter.scale, + labels: resolved.lufsmeter.labels, + }, + waveform: { + ...base.waveform, + background: resolved.waveform.background, + guides: resolved.waveform.guides, + }, + astra: { ...base.astra }, + } return `# Prism theme template # -# Authoring rules: -# - Colors use R, G, B or R, G, B, A (0-255) -# - CSS colors like #hex, rgb(), and rgba() also work +# Colors use R, G, B or R, G, B, A (0-255) +# CSS colors like #hex, rgb(), and rgba() also work # # ── UI ── -# [App] Overall window chrome, background, and text -# toolbar_bg, settings_bg_top, settings_bg_bottom, bottom_bar_bg -# can be set to override the default derived values +# [App] Window background, text, and accent color # [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 +# [Scopes] Shared defaults for all scopes (background, guides, overlays) # -# 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 +# Each scope section below has FULL control over its own colors. +# Per-scope values override the shared [Scopes] defaults. +# Every token shown below can be changed independently. # ${serializeThemeFile(template)}` } @@ -1038,13 +1091,14 @@ function resolveSpectrumTheme( const sideLine = section.sideLine ?? withAlpha(line, 0.5) const fill = section.fill ?? withAlpha(line, 0.34) const guides = section.guides ?? scopes.guides + const background = section.background ?? scopes.background return { line, sideLine, guides, guidesSecondary: multiplyAlpha(guides, 0.5), - labels: section.guides ? guides : scopes.labels, - background: scopes.background, + labels: section.labels ?? guides, + background, fill, fillGradient: [ withAlpha(fill, 0), @@ -1056,7 +1110,7 @@ function resolveSpectrumTheme( section.heatMid ?? DEFAULT_HEAT_MID, section.heatHigh ?? DEFAULT_HEAT_HIGH, ], - heatBase: section.heatBase ?? scopes.background, + heatBase: section.heatBase ?? background, } } @@ -1070,7 +1124,7 @@ function resolveOscilloscopeTheme( line: theme.oscilloscope.line ?? app.accent, guides, guidesSecondary: multiplyAlpha(guides, 0.5), - background: scopes.background, + background: theme.oscilloscope.background ?? scopes.background, fill: theme.oscilloscope.fill ?? 'rgba(245, 248, 252, 0.18)', } } @@ -1085,8 +1139,8 @@ function resolveVectorscopeTheme( trace: theme.vectorscope.trace ?? app.accent, guides, guidesSecondary: multiplyAlpha(guides, 0.5), - labels: theme.vectorscope.guides ? guides : scopes.labels, - background: scopes.background, + labels: theme.vectorscope.labels ?? guides, + background: theme.vectorscope.background ?? scopes.background, bandLow: theme.vectorscope.bandLow ?? DEFAULT_BAND_LOW, bandMid: theme.vectorscope.bandMid ?? DEFAULT_BAND_MID, bandHigh: theme.vectorscope.bandHigh ?? DEFAULT_BAND_HIGH, @@ -1100,7 +1154,7 @@ function resolveSpectrogramTheme( ): ResolvedSpectrogramTheme { return { mono: theme.spectrogram.mono ?? app.accent, - background: scopes.background, + background: theme.spectrogram.background ?? scopes.background, heatColors: [ theme.spectrogram.heatLow ?? DEFAULT_HEAT_LOW, theme.spectrogram.heatMid ?? DEFAULT_HEAT_MID, @@ -1121,8 +1175,8 @@ function resolveVUMeterTheme( peak: theme.vumeter.peak ?? 'rgb(255, 127, 0)', clip: theme.vumeter.clip ?? 'rgba(255, 120, 80, 0.9)', scale: theme.vumeter.scale ?? scopes.guides, - labels: blendText(app.text, app.textMuted, 0.35), - background: scopes.background, + labels: theme.vumeter.labels ?? blendText(app.text, app.textMuted, 0.35), + background: theme.vumeter.background ?? scopes.background, } } @@ -1137,8 +1191,8 @@ function resolveLUFSMeterTheme( track: theme.lufsmeter.track ?? withAlpha(level, 0.08), target: theme.lufsmeter.target ?? withAlpha(level, 0.25), scale: theme.lufsmeter.scale ?? scopes.guides, - labels: blendText(app.text, app.textMuted, 0.2), - background: scopes.background, + labels: theme.lufsmeter.labels ?? blendText(app.text, app.textMuted, 0.2), + background: theme.lufsmeter.background ?? scopes.background, } } @@ -1152,7 +1206,7 @@ function resolveWaveformTheme( line: theme.waveform.line ?? app.accent, guides, guidesSecondary: multiplyAlpha(guides, 0.5), - background: scopes.background, + background: theme.waveform.background ?? scopes.background, bandLow: theme.waveform.bandLow ?? DEFAULT_BAND_LOW, bandMid: theme.waveform.bandMid ?? DEFAULT_BAND_MID, bandHigh: theme.waveform.bandHigh ?? DEFAULT_BAND_HIGH, diff --git a/src/types/theme.ts b/src/types/theme.ts index 15fbc60..e76ccb0 100644 --- a/src/types/theme.ts +++ b/src/types/theme.ts @@ -56,6 +56,7 @@ export interface ThemeScopesTokens { } export interface ThemeSpectrumTokens { + background?: string line?: string sideLine?: string fill?: string @@ -64,23 +65,28 @@ export interface ThemeSpectrumTokens { heatHigh?: string heatBase?: string guides?: string + labels?: string } export interface ThemeOscilloscopeTokens { + background?: string line?: string fill?: string guides?: string } export interface ThemeVectorscopeTokens { + background?: string trace?: string bandLow?: string bandMid?: string bandHigh?: string guides?: string + labels?: string } export interface ThemeSpectrogramTokens { + background?: string mono?: string heatLow?: string heatMid?: string @@ -88,21 +94,26 @@ export interface ThemeSpectrogramTokens { } export interface ThemeVUMeterTokens { + background?: string level?: string track?: string peak?: string clip?: string scale?: string + labels?: string } export interface ThemeLUFSMeterTokens { + background?: string level?: string track?: string target?: string scale?: string + labels?: string } export interface ThemeWaveformTokens { + background?: string line?: string bandLow?: string bandMid?: string