diff --git a/packages/studio/src/player/components/TimelineTrackHeader.test.tsx b/packages/studio/src/player/components/TimelineTrackHeader.test.tsx
index 86cdc1064..d11f2abd5 100644
--- a/packages/studio/src/player/components/TimelineTrackHeader.test.tsx
+++ b/packages/studio/src/player/components/TimelineTrackHeader.test.tsx
@@ -263,6 +263,34 @@ describe("TimelineTrackHeader", () => {
act(() => view.root.unmount());
});
+ // The visibility control is the old hide eye. On an audio track it silences
+ // rather than hides, and the row already says so with a speaker elsewhere —
+ // so the eye's slot stays empty there. A non-audio track is untouched.
+ it("keeps the visibility control off audio track headers", () => {
+ const audio: TimelineElement = { ...ELEMENT, tag: "audio" };
+ const view = renderHeader({
+ keyframeClip: audio,
+ trackElements: [audio],
+ isAudioTrack: true,
+ animations: [],
+ });
+ const labels = Array.from(view.host.querySelectorAll("button")).map((b) =>
+ b.getAttribute("aria-label"),
+ );
+ expect(labels.some((l) => l && /^(Hide|Show) track/.test(l))).toBe(false);
+ expect(labels).not.toContain("Mute");
+ act(() => view.root.unmount());
+ });
+
+ it("keeps it on a non-audio track", () => {
+ const view = renderHeader({ isAudioTrack: false });
+ const labels = Array.from(view.host.querySelectorAll("button")).map((b) =>
+ b.getAttribute("aria-label"),
+ );
+ expect(labels.some((l) => l && /^Hide track/.test(l))).toBe(true);
+ act(() => view.root.unmount());
+ });
+
// The eye acts on the layer, so it has to be reachable without a pointer and
// in every disclosure state — a hover-gated eye is unusable by keyboard.
it("keeps the visibility eye mounted whether the layer is expanded or collapsed", () => {
diff --git a/packages/studio/src/player/components/TimelineTrackHeader.tsx b/packages/studio/src/player/components/TimelineTrackHeader.tsx
index 1f246e93d..9c88b7cc9 100644
--- a/packages/studio/src/player/components/TimelineTrackHeader.tsx
+++ b/packages/studio/src/player/components/TimelineTrackHeader.tsx
@@ -600,7 +600,7 @@ export function TimelineTrackHeader({
hidden={isTrackHidden}
trackNumber={trackNumber}
trackDisplayNumber={trackDisplayNumber}
- visible
+ visible={!isAudioTrack}
isAudioTrack={isAudioTrack}
onToggle={onToggleTrackHidden}
/>
diff --git a/packages/studio/src/player/components/TimelineTrackPlainHeader.tsx b/packages/studio/src/player/components/TimelineTrackPlainHeader.tsx
index 6f1cf65f9..e5dacfcd9 100644
--- a/packages/studio/src/player/components/TimelineTrackPlainHeader.tsx
+++ b/packages/studio/src/player/components/TimelineTrackPlainHeader.tsx
@@ -103,11 +103,16 @@ export function PlainTrackHeader({
)}
{showTrackLabel && }
+ {/* Not on an audio track. The control is the old visibility eye, and on
+ audio it silences rather than hides — but a row that already says what
+ it is with a speaker does not also need the hide affordance sitting in
+ the eye's slot. `visible={false}` rather than omitting the element, so
+ the spacer keeps every row's control columns aligned. */}