- {/* Breadcrumb + Player controls */}
+ {/* Preview + player controls — takes remaining space above timeline */}
+
+
+
+ {previewOverlay}
+
+ {/* Player controls always visible, regardless of timeline state */}
{compositionStack.length > 1 && (
)}
-
-
-
- {/* Timeline tracks */}
-
{
- if ((e.target as HTMLElement).closest("[data-clip]")) return;
- if (compositionStack.length > 1) {
- updateCompositionStack((prev) => prev.slice(0, -1));
- }
- }}
- >
- {timelineToolbar}
-
- {timelineFooter}
+
+ {(timelineVisible ?? true) && (
+ <>
+ {/* Resize divider */}
+
+
+ {/* Timeline section — fixed height, resizable */}
+
+ {/* Timeline tracks */}
+
{
+ if ((e.target as HTMLElement).closest("[data-clip]")) return;
+ if (compositionStack.length > 1) {
+ updateCompositionStack((prev) => prev.slice(0, -1));
+ }
+ }}
+ >
+ {timelineToolbar}
+
+ {timelineFooter}
+
+
+ >
+ )}
);
});
diff --git a/packages/studio/src/player/components/PlayerControls.tsx b/packages/studio/src/player/components/PlayerControls.tsx
index 82c43decb..86a8a971d 100644
--- a/packages/studio/src/player/components/PlayerControls.tsx
+++ b/packages/studio/src/player/components/PlayerControls.tsx
@@ -8,11 +8,15 @@ const SPEED_OPTIONS = [0.25, 0.5, 1, 1.5, 2] as const;
interface PlayerControlsProps {
onTogglePlay: () => void;
onSeek: (time: number) => void;
+ timelineVisible?: boolean;
+ onToggleTimeline?: () => void;
}
export const PlayerControls = memo(function PlayerControls({
onTogglePlay,
onSeek,
+ timelineVisible,
+ onToggleTimeline,
}: PlayerControlsProps) {
// Subscribe to only the fields we render — each selector prevents cascading re-renders
const isPlaying = usePlayerStore((s) => s.isPlaying);
@@ -224,6 +228,33 @@ export const PlayerControls = memo(function PlayerControls({
)}
+
+ {/* Timeline toggle */}
+ {onToggleTimeline !== undefined && (
+