feat(perf): 3-state animation mode (Full / Reduced / Static) (#441)

* feat(perf): 3-state animation mode (Full / Reduced / Static)

Replaces the boolean `reducedAnimations` toggle with a three-way
`animationMode` setting, suggested by Viktor Petrovich after the
Windows audio fix (PR #426) shipped and confirmed a measurable
GPU drop:

- `full` (default): native frame rate, marquee scrolls normally
- `reduced`: 30 fps cap on the animated seekbar wave; player
  marquee runs at half speed
- `static`: rAF loop disabled; the seekbar repaints from the
  ~2 Hz audio:progress heartbeat. Player title/artist truncate
  with ellipsis instead of scrolling.

Migration in `onRehydrateStorage` maps legacy
`reducedAnimations: true` to `'reduced'`, anything else to
`'full'`. Static is opt-in only.

Settings UI follows the ReplayGain Auto/Track/Album pattern with
a contextual hint that explains what each mode does.

i18n: 5 new keys across 8 locales, 2 legacy keys removed.

* docs(changelog): add #441 3-state animation mode entry

* chore(credits): add #441 to Psychotoxical contributions
This commit is contained in:
Frank Stellmacher
2026-05-03 14:12:27 +02:00
committed by GitHub
parent 364b29ceee
commit 98ff73d17a
14 changed files with 174 additions and 41 deletions
+7 -2
View File
@@ -925,8 +925,13 @@ export const deTranslation = {
sidebarLyricsStyleAppleDesc: 'Aktive Zeile oben mit sanfter Animation.',
seekbarStyle: 'Seekbar-Stil',
seekbarStyleDesc: 'Aussehen der Wiedergabe-Seekbar auswählen',
reducedAnimations: 'Animationen reduzieren',
reducedAnimationsDesc: 'Animierte Seekbar-Stile auf 30 fps drosseln, um die GPU-Last auf schwächerer Hardware zu senken. Optisch kaum wahrnehmbar.',
animationMode: 'Animationen',
animationModeDesc: 'Visuelle Glätte gegen geringere GPU-/CPU-Last auf langsamerer Hardware tauschen.',
animationModeFull: 'Voll',
animationModeReduced: 'Reduziert',
animationModeStatic: 'Statisch',
animationModeReducedHint: '30 fps Limit auf der Seekbar-Welle; Titel im Player läuft mit halber Geschwindigkeit.',
animationModeStaticHint: 'Keine Wellenanimation; Titel im Player wird abgeschnitten statt gescrollt.',
seekbarTruewave: 'Echte Wellenform',
seekbarPseudowave: 'Pseudo-Wellenform',
seekbarLinedot: 'Linie & Punkt',
+7 -2
View File
@@ -931,8 +931,13 @@ export const enTranslation = {
fsPortraitDim: 'Photo dimming',
seekbarStyle: 'Seekbar Style',
seekbarStyleDesc: 'Choose the look of the player seek bar',
reducedAnimations: 'Reduce animations',
reducedAnimationsDesc: 'Cap animated seekbar styles to 30 fps to lower GPU usage on slower hardware. Visual difference is minimal.',
animationMode: 'Animations',
animationModeDesc: 'Trade visual smoothness for lower GPU/CPU usage on slower hardware.',
animationModeFull: 'Full',
animationModeReduced: 'Reduced',
animationModeStatic: 'Static',
animationModeReducedHint: '30 fps cap on the seekbar wave; player title scrolls at half speed.',
animationModeStaticHint: 'No wave animation; player title is truncated instead of scrolling.',
seekbarTruewave: 'Truewave',
seekbarPseudowave: 'Pseudowave',
seekbarLinedot: 'Line & Dot',
+7 -2
View File
@@ -918,8 +918,13 @@ export const esTranslation = {
sidebarLyricsStyleAppleDesc: 'La línea activa se ancla arriba con animación suave.',
seekbarStyle: 'Estilo de Barra de Progreso',
seekbarStyleDesc: 'Elige la apariencia de la barra de progreso del reproductor',
reducedAnimations: 'Reducir animaciones',
reducedAnimationsDesc: 'Limita los estilos animados de la barra de progreso a 30 fps para reducir el uso de GPU en hardware más lento. La diferencia visual es mínima.',
animationMode: 'Animaciones',
animationModeDesc: 'Cambia fluidez visual por menor uso de GPU/CPU en hardware más lento.',
animationModeFull: 'Completas',
animationModeReduced: 'Reducidas',
animationModeStatic: 'Estáticas',
animationModeReducedHint: 'Límite de 30 fps en la onda de la barra; el título del reproductor se desplaza a la mitad de velocidad.',
animationModeStaticHint: 'Sin animación de onda; el título del reproductor se trunca en lugar de desplazarse.',
seekbarTruewave: 'Forma de Onda Real',
seekbarPseudowave: 'Forma de Onda Pseudo',
seekbarLinedot: 'Línea y Punto',
+7 -2
View File
@@ -913,8 +913,13 @@ export const frTranslation = {
sidebarLyricsStyleAppleDesc: "La ligne active reste en haut avec une animation fluide.",
seekbarStyle: 'Style de la barre de lecture',
seekbarStyleDesc: 'Choisir l\'apparence de la barre de progression',
reducedAnimations: 'Réduire les animations',
reducedAnimationsDesc: 'Limiter les styles de barre de lecture animés à 30 fps pour réduire l\'utilisation du GPU sur le matériel plus lent. La différence visuelle est minime.',
animationMode: 'Animations',
animationModeDesc: 'Échanger la fluidité visuelle contre une utilisation GPU/CPU réduite sur du matériel plus lent.',
animationModeFull: 'Complètes',
animationModeReduced: 'Réduites',
animationModeStatic: 'Statiques',
animationModeReducedHint: 'Plafond de 30 fps sur l\'onde de la barre ; le titre du lecteur défile à moitié vitesse.',
animationModeStaticHint: 'Pas d\'animation d\'onde ; le titre du lecteur est tronqué au lieu de défiler.',
seekbarTruewave: 'Forme d\'onde réelle',
seekbarPseudowave: 'Forme d\'onde pseudo',
seekbarLinedot: 'Ligne & point',
+7 -2
View File
@@ -912,8 +912,13 @@ export const nbTranslation = {
sidebarLyricsStyleAppleDesc: 'Aktiv linje forankres øverst med jevn animasjon.',
seekbarStyle: 'Søkefelt-stil',
seekbarStyleDesc: 'Velg utseendet på avspillingssøkefeltet',
reducedAnimations: 'Reduser animasjoner',
reducedAnimationsDesc: 'Begrens animerte søkefelt-stiler til 30 fps for å redusere GPU-belastning på tregere maskinvare. Visuell forskjell er minimal.',
animationMode: 'Animasjoner',
animationModeDesc: 'Bytt visuell flyt mot lavere GPU-/CPU-bruk på tregere maskinvare.',
animationModeFull: 'Full',
animationModeReduced: 'Redusert',
animationModeStatic: 'Statisk',
animationModeReducedHint: '30 fps grense på søkefelt-bølgen; spillertittelen ruller med halv hastighet.',
animationModeStaticHint: 'Ingen bølgeanimasjon; spillertittelen forkortes i stedet for å rulle.',
seekbarTruewave: 'Ekte bølgeform',
seekbarPseudowave: 'Pseudo-bølgeform',
seekbarLinedot: 'Linje & punkt',
+7 -2
View File
@@ -912,8 +912,13 @@ export const nlTranslation = {
sidebarLyricsStyleAppleDesc: 'Actieve regel verankerd bovenaan met vloeiende animatie.',
seekbarStyle: 'Zoekbalkstijl',
seekbarStyleDesc: 'Kies het uiterlijk van de afspeelbalk',
reducedAnimations: 'Animaties beperken',
reducedAnimationsDesc: 'Beperk geanimeerde zoekbalkstijlen tot 30 fps om GPU-gebruik op tragere hardware te verminderen. Visueel verschil is minimaal.',
animationMode: 'Animaties',
animationModeDesc: 'Wissel visuele soepelheid in voor minder GPU-/CPU-gebruik op tragere hardware.',
animationModeFull: 'Volledig',
animationModeReduced: 'Gereduceerd',
animationModeStatic: 'Statisch',
animationModeReducedHint: '30 fps limiet op de zoekbalk-golf; spelertitel scrollt op halve snelheid.',
animationModeStaticHint: 'Geen golfanimatie; spelertitel wordt afgekapt in plaats van scrollen.',
seekbarTruewave: 'Echte golfvorm',
seekbarPseudowave: 'Pseudo-golfvorm',
seekbarLinedot: 'Lijn & punt',
+7 -2
View File
@@ -964,8 +964,13 @@ export const ruTranslation = {
sidebarLyricsStyleAppleDesc: 'Активная строка фиксируется сверху с плавной анимацией.',
seekbarStyle: 'Стиль прогресс-бара',
seekbarStyleDesc: 'Выбор внешнего вида полосы воспроизведения',
reducedAnimations: 'Снизить анимации',
reducedAnimationsDesc: 'Ограничить анимированные стили прогресс-бара 30 кадрами в секунду для снижения нагрузки на GPU на слабом железе. Визуальная разница минимальна.',
animationMode: 'Анимации',
animationModeDesc: 'Обменивайте визуальную плавность на меньшую нагрузку на GPU/CPU на слабом железе.',
animationModeFull: 'Полные',
animationModeReduced: 'Сниженные',
animationModeStatic: 'Статичные',
animationModeReducedHint: 'Ограничение 30 fps для волны прогресс-бара; заголовок плеера прокручивается с половинной скоростью.',
animationModeStaticHint: 'Без анимации волны; заголовок плеера обрезается вместо прокрутки.',
seekbarTruewave: 'Реальная форма волны',
seekbarPseudowave: 'Псевдо форма волны',
seekbarLinedot: 'Линия и точка',
+7 -2
View File
@@ -907,8 +907,13 @@ export const zhTranslation = {
sidebarLyricsStyleAppleDesc: '活动行固定在顶部,带有平滑弹簧动画。',
seekbarStyle: '进度条样式',
seekbarStyleDesc: '选择播放进度条的外观',
reducedAnimations: '减少动画',
reducedAnimationsDesc: '将动画进度条样式限制为 30 fps,以降低较慢硬件上的 GPU 占用。视觉差异极小。',
animationMode: '动画',
animationModeDesc: '较慢硬件上以视觉流畅度换取更低的 GPU/CPU 占用。',
animationModeFull: '完整',
animationModeReduced: '减少',
animationModeStatic: '静态',
animationModeReducedHint: '进度条波形限制为 30 fps;播放器标题以半速滚动。',
animationModeStaticHint: '无波形动画;播放器标题被截断而不滚动。',
seekbarTruewave: '真实波形',
seekbarPseudowave: '伪波形',
seekbarLinedot: '线条与点',