diff --git a/packages/studio/src/player/components/LayerDisclosureRow.tsx b/packages/studio/src/player/components/LayerDisclosureRow.tsx
index 1dc27408d..718b8e127 100644
--- a/packages/studio/src/player/components/LayerDisclosureRow.tsx
+++ b/packages/studio/src/player/components/LayerDisclosureRow.tsx
@@ -1,7 +1,8 @@
import { TRACK_H } from "./timelineLayout";
import { TrackClipCount } from "./TrackClipCount";
-// Layer row (Figma order: disclosure ∿, diamond, name) — the disclosure lives
+// Layer row (diamond, name, then the ∿ disclosure on the right edge) — the
+// disclosure lives
// here, not on the clip bar, and re-expands a collapsed layer. `∿` (not a
// caret) because a group's own row keeps the caret for its structural
// disclosure (member rows) — this button only ever means "show this row's
@@ -45,27 +46,6 @@ export function LayerDisclosureRow({
background: gutterBackground,
}}
>
-
{/* Decorative: the disclosure button above already names the row's keyframe
state, and aria-label on a plain span is not exposed reliably anyway. */}
@@ -76,6 +56,31 @@ export function LayerDisclosureRow({
{children}
+ {/* Anchored right, on every header that has one: the lane toggle is the
+ row's last word about itself, and a left-hand ∿ put it where the eye
+ looks for identity instead. `ml-auto` rather than a spacer so it holds
+ the edge whatever else the row grows. */}
+
);
}
diff --git a/packages/studio/src/player/components/TimelineGroupHeader.tsx b/packages/studio/src/player/components/TimelineGroupHeader.tsx
index ebf68d91c..0f815eb6f 100644
--- a/packages/studio/src/player/components/TimelineGroupHeader.tsx
+++ b/packages/studio/src/player/components/TimelineGroupHeader.tsx
@@ -133,7 +133,7 @@ export function TimelineGroupHeader({
{/* Line two: what you can DO to it. Its own row so the name is not
squeezed to a few characters by five controls sharing 232px. */}
-
+
event.stopPropagation()}
diff --git a/packages/studio/src/player/components/TimelineTrackHeader.test.tsx b/packages/studio/src/player/components/TimelineTrackHeader.test.tsx
index 63474aadf..845f8a27d 100644
--- a/packages/studio/src/player/components/TimelineTrackHeader.test.tsx
+++ b/packages/studio/src/player/components/TimelineTrackHeader.test.tsx
@@ -771,6 +771,7 @@ describe("TimelineTrackHeader", () => {
expect(header()?.style.paddingLeft).toBe("");
expect(header()?.style.borderLeft).toBe("");
+ expect(header()?.style.background).not.toContain("linear-gradient");
view.rerender({
keyframeClip: VOICE,
@@ -781,6 +782,10 @@ describe("TimelineTrackHeader", () => {
});
expect(header()?.style.paddingLeft).toBe("14px");
expect(header()?.style.borderLeft).toContain("2px");
+ // And a lighter gutter, so the row reads as sitting INSIDE its group
+ // rather than beside it. Overlaid on the theme's own fill rather than a
+ // hard-coded colour, so it follows whatever the gutter is.
+ expect(header()?.style.background).toContain("linear-gradient");
act(() => view.root.unmount());
});
diff --git a/packages/studio/src/player/components/TimelineTrackHeader.tsx b/packages/studio/src/player/components/TimelineTrackHeader.tsx
index 67153ab52..99bf6571f 100644
--- a/packages/studio/src/player/components/TimelineTrackHeader.tsx
+++ b/packages/studio/src/player/components/TimelineTrackHeader.tsx
@@ -34,6 +34,17 @@ import { timelineLogicalRowCellId, timelinePropertyRowId } from "./timelineNavig
* nesting its `aria-level` already reports. */
const GROUP_MEMBER_RAIL = "#3CE6AC59";
const GROUP_MEMBER_INDENT = 14;
+/** A hair lighter than `gutterBackground`, so a member row reads as sitting
+ * INSIDE its group rather than beside it. Overlaid rather than hard-coded so
+ * it tracks whatever the theme's gutter is. */
+const GROUP_MEMBER_TINT = "rgba(255,255,255,0.035)";
+
+/** The gutter fill for a row, tinted when it belongs to a group. */
+function gutterFill(base: string, isGroupMember: boolean): string {
+ return isGroupMember
+ ? `linear-gradient(${GROUP_MEMBER_TINT}, ${GROUP_MEMBER_TINT}), ${base}`
+ : base;
+}
interface TimelineTrackHeaderProps {
/** The track's real key: a FRACTIONAL z-order sort value. Routes callbacks;
@@ -489,7 +500,7 @@ export function TimelineTrackHeader({
}`}
style={{
width: showTrackLabel ? LABEL_COL_W : contentOrigin,
- background: theme.gutterBackground,
+ background: gutterFill(theme.gutterBackground, isGroupMember),
borderRight: `1px solid ${theme.gutterBorder}`,
// A group's member rows are `aria-level="2"`, and until this they read
// as level 2 to a screen reader while looking identical to every
@@ -578,7 +589,7 @@ export function TimelineTrackHeader({
}
clipCount={clipCount}
isExpanded={isExpanded}
- gutterBackground={theme.gutterBackground}
+ gutterBackground={gutterFill(theme.gutterBackground, isGroupMember)}
columnWidth={showTrackLabel ? LABEL_COL_W : contentOrigin}
lanesId={lanesId}
onToggleClipExpanded={onToggleClipExpanded}
@@ -615,7 +626,7 @@ export function TimelineTrackHeader({
expandedElement={keyframeClip}
currentTime={currentTime}
clipPercentage={clipPercentage}
- gutterBackground={theme.gutterBackground}
+ gutterBackground={gutterFill(theme.gutterBackground, isGroupMember)}
columnWidth={showTrackLabel ? LABEL_COL_W : contentOrigin}
onTogglePropertyGroupKeyframe={onTogglePropertyGroupKeyframe}
onSeek={onSeek}
@@ -638,7 +649,7 @@ export function TimelineTrackHeader({
}
top={getTimelineLaneTop(lanes.length) + index * AUTOMATION_LANE_H}
isLastLane={index === automationRows.length - 1}
- gutterBackground={theme.gutterBackground}
+ gutterBackground={gutterFill(theme.gutterBackground, isGroupMember)}
columnWidth={showTrackLabel ? LABEL_COL_W : contentOrigin}
onRemove={onRemoveAutomationLane}
/>