mirror of
https://github.com/meowarex/TidaLuna-Plugins.git
synced 2026-06-17 19:33:10 +10:00
Idle animation setting (Audio-Viz)
This commit is contained in:
@@ -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 & Hide</LunaSelectItem>
|
||||||
|
<LunaSelectItem value={2}>Disabled & Static</LunaSelectItem>
|
||||||
|
</LunaSelectSetting>
|
||||||
|
|
||||||
{/* Color picker modal */}
|
{/* Color picker modal */}
|
||||||
{shouldRenderColor && (
|
{shouldRenderColor && (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user