diff --git a/CHANGELOG.md b/CHANGELOG.md
index 953cf9f1..d69a42bd 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -202,6 +202,14 @@ Foundational work: faster reviews, narrower diffs, and a safety net under the pa
* New opt-in columns **Plays**, **Last played**, and **BPM** on the Album / Playlist / Favorites tracklists, plus matching rows in the Song Info modal. Pulls Navidrome's existing `playCount` / `played` / `bpm` from the Subsonic response — no extra API calls. Genre column also added to the playlist tracklist for parity with Album + Favorites. BPM cells render `—` when Navidrome returns 0 (untagged file); Plays / Last played render `—` only when truly absent.
* Defensive fix in the tracklist column hook: visible columns with no saved width on an older prefs blob now fall back to the ColDef's default width instead of collapsing the row layout.
+### Mainstage hero — prev / next arrow buttons
+
+**By [@Psychotoxical](https://github.com/Psychotoxical), thanks to zunoz for the report on the Psysonic Discord, PR [#735](https://github.com/Psychotoxical/psysonic/pull/735)**
+
+* The featured-album strip on Mainstage now has **Previous** / **Next** chevron buttons on each edge of the hero. The existing 8 px dot indicators were a small target, and a near-miss often opened the underlying album instead of switching slides; the new 44 px buttons give a comfortable hit area on both desktop and touch.
+* Buttons live in a new **`.hero-nav`** flex wrapper (`inset: 0`, `justify-content: space-between`, **`pointer-events: none`**); the buttons themselves opt back into **`pointer-events: auto`** so the rest of the hero stays click-through to the album page. Wrap-around (last → first / first → last) and auto-advance timer restart use the same pattern as the previous dot handler.
+* The dot indicators are kept as **decorative spans** — no click handler, no hover state, **`pointer-events: none`** — so a missed click no longer navigates to the album.
+
## Changed
### Backend — Cargo workspace with 5 domain crates (Rust refactor)
diff --git a/src/components/Hero.tsx b/src/components/Hero.tsx
index e988c6c3..74114d01 100644
--- a/src/components/Hero.tsx
+++ b/src/components/Hero.tsx
@@ -4,7 +4,7 @@ import type { SubsonicAlbum } from '../api/subsonicTypes';
import { songToTrack } from '../utils/playback/songToTrack';
import React, { useEffect, useState, useRef, useCallback, useMemo } from 'react';
import { useNavigate } from 'react-router-dom';
-import { Play, ListPlus } from 'lucide-react';
+import { Play, ListPlus, ChevronLeft, ChevronRight } from 'lucide-react';
import CachedImage, { useCachedUrl } from './CachedImage';
import { usePlayerStore } from '../store/playerStore';
import { useTranslation } from 'react-i18next';
@@ -224,9 +224,18 @@ export default function Hero({ albums: albumsProp }: HeroProps = {}) {
};
}, [albums.length, heroInView, startTimer]);
- const goTo = useCallback((idx: number) => {
- setActiveIdx(idx);
- startTimer(albums.length);
+ const goPrev = useCallback(() => {
+ const len = albums.length;
+ if (len <= 1) return;
+ setActiveIdx(prev => (prev - 1 + len) % len);
+ startTimer(len);
+ }, [albums.length, startTimer]);
+
+ const goNext = useCallback(() => {
+ const len = albums.length;
+ if (len <= 1) return;
+ setActiveIdx(prev => (prev + 1) % len);
+ startTimer(len);
}, [albums.length, startTimer]);
const album = albums[activeIdx] ?? null;
@@ -346,18 +355,38 @@ export default function Hero({ albums: albumsProp }: HeroProps = {}) {
- {/* Carousel dot indicators */}
+ {/* Carousel navigation arrows + decorative dot indicators */}
{albums.length > 1 && (
-