Merge pull request #118 from meowarex/dev

Idle animation setting (Audio-Viz)
This commit is contained in:
Meow Meow
2026-05-17 18:17:38 +10:00
committed by GitHub
2 changed files with 52 additions and 8 deletions
@@ -54,6 +54,7 @@ export const settings = await ReactiveStore.getPluginStorage(
scrollingOscilloscope: false, scrollingOscilloscope: false,
groupedSlots: false, groupedSlots: false,
transparentContainers: false, transparentContainers: false,
idleMode: 1,
miniSlots: [] as string[], miniSlots: [] as string[],
customColors: [] as string[], customColors: [] as string[],
}, },
@@ -92,6 +93,7 @@ export const Settings = () => {
const [transparentContainers, setTransparentContainers] = React.useState( const [transparentContainers, setTransparentContainers] = React.useState(
settings.transparentContainers, settings.transparentContainers,
); );
const [idleMode, setIdleMode] = React.useState(settings.idleMode);
const [showColorPicker, setShowColorPicker] = React.useState(false); const [showColorPicker, setShowColorPicker] = React.useState(false);
const [isColorAnimIn, setIsColorAnimIn] = React.useState(false); const [isColorAnimIn, setIsColorAnimIn] = React.useState(false);
@@ -313,6 +315,21 @@ export const Settings = () => {
}} }}
/> />
<LunaSelectSetting
title="Idle Animation"
desc="Behaviour when no audio is playing"
value={idleMode}
onChange={(e: React.ChangeEvent<HTMLSelectElement>) => {
const v = Number(e.target.value);
setIdleMode(v);
settings.idleMode = v;
}}
>
<LunaSelectItem value={0}>Enabled</LunaSelectItem>
<LunaSelectItem value={1}>Disabled &amp; Hide</LunaSelectItem>
<LunaSelectItem value={2}>Disabled &amp; Static</LunaSelectItem>
</LunaSelectSetting>
{/* Color picker modal */} {/* Color picker modal */}
{shouldRenderColor && ( {shouldRenderColor && (
<> <>
+35 -8
View File
@@ -46,6 +46,7 @@ interface SlotGroup {
const groups = new Map<string, SlotGroup>(); const groups = new Map<string, SlotGroup>();
let navArrowsEl: HTMLElement | null = null; let navArrowsEl: HTMLElement | null = null;
let idleHidden = false;
const getSlot = (key: SlotKey): VisualizerType => const getSlot = (key: SlotKey): VisualizerType =>
(settings as unknown as Record<string, VisualizerType>)[key] ?? "none"; (settings as unknown as Record<string, VisualizerType>)[key] ?? "none";
@@ -134,8 +135,9 @@ const syncGroupHeights = (group: SlotGroup): void => {
const updateGroupVisibility = (group: SlotGroup): void => { const updateGroupVisibility = (group: SlotGroup): void => {
const activeCount = group.slots.filter(s => s.currentType !== "none").length; const activeCount = group.slots.filter(s => s.currentType !== "none").length;
const allNone = activeCount === 0; const allNone = activeCount === 0;
group.groupContainer.style.display = allNone ? "none" : "flex"; const hidden = allNone || idleHidden;
if (!allNone) syncGroupHeights(group); group.groupContainer.style.display = hidden ? "none" : "flex";
if (!hidden) syncGroupHeights(group);
group.groupContainer.classList.toggle( group.groupContainer.classList.toggle(
"av-grouped", "av-grouped",
@@ -143,7 +145,7 @@ const updateGroupVisibility = (group: SlotGroup): void => {
); );
if (group === groups.get("topNav-left") && navArrowsEl) { if (group === groups.get("topNav-left") && navArrowsEl) {
navArrowsEl.style.marginRight = allNone ? "" : "0"; navArrowsEl.style.marginRight = hidden ? "" : "0";
} }
}; };
@@ -398,6 +400,19 @@ const generateIdleData = (): AudioData => {
}; };
}; };
// Static idle data — flat, silent, no movement
const STATIC_IDLE_DATA: AudioData = {
byteFrequency: new Uint8Array(IDLE_SIZE),
byteTimeDomain: new Uint8Array(IDLE_SIZE).fill(128),
floatFrequency: new Float32Array(IDLE_SIZE).fill(-100),
floatTimeDomain: new Float32Array(IDLE_SIZE),
leftTimeDomain: new Float32Array(IDLE_SIZE),
rightTimeDomain: new Float32Array(IDLE_SIZE),
sampleRate: 44100,
fftSize: IDLE_SIZE * 2,
binCount: IDLE_SIZE,
};
// Animation Loop // Animation Loop
let animationId: number | null = null; let animationId: number | null = null;
@@ -478,12 +493,24 @@ const animate = (): void => {
scheduleRetry(); scheduleRetry();
} }
const renderData = hasSignal ? data : generateIdleData(); // idleMode: 0 = animated, 1 = hide when idle, 2 = static when idle
const idleMode = settings.idleMode ?? 0;
const newIdleHidden = !hasSignal && idleMode === 1;
if (newIdleHidden !== idleHidden) {
idleHidden = newIdleHidden;
for (const group of groups.values()) updateGroupVisibility(group);
}
for (const group of groups.values()) { if (!idleHidden) {
for (const slot of group.slots) { let renderData: AudioData;
if (!slot.canvas || slot.currentType === "none" || !slot.visualizer) continue; if (hasSignal) renderData = data as AudioData;
slot.visualizer.render(renderData, settings.barColor); else if (idleMode === 2) renderData = STATIC_IDLE_DATA;
else renderData = generateIdleData();
for (const group of groups.values()) {
for (const slot of group.slots) {
if (!slot.canvas || slot.currentType === "none" || !slot.visualizer) continue;
slot.visualizer.render(renderData, settings.barColor);
}
} }
} }