diff --git a/packages/studio/src/player/components/Timeline.tsx b/packages/studio/src/player/components/Timeline.tsx index 5b26dae89..92040c67b 100644 --- a/packages/studio/src/player/components/Timeline.tsx +++ b/packages/studio/src/player/components/Timeline.tsx @@ -27,7 +27,7 @@ import { buildStackingTimelineLayers, insertPreviewTrackOrder } from "./timeline import { getTimelineLayerGroupHeaderTotalHeight } from "./TimelineLayerGroupHeader"; import { GUTTER, - generateTicks, + generateVisibleTicks, getTimelineCanvasHeight, shouldShowTimelineShortcutHint, computeTimelineBasisDuration, @@ -362,8 +362,8 @@ export const Timeline = memo(function Timeline({ }); const { major, minor } = useMemo( - () => generateTicks(effectiveDuration, pps), - [effectiveDuration, pps], + () => generateVisibleTicks(effectiveDuration, pps, viewportWidth, GUTTER), + [effectiveDuration, pps, viewportWidth], ); const majorTickInterval = major.length >= 2 ? major[1] - major[0] : effectiveDuration; diff --git a/packages/studio/src/player/components/timelineLayout.ts b/packages/studio/src/player/components/timelineLayout.ts index 69f372cb6..d2ecaabed 100644 --- a/packages/studio/src/player/components/timelineLayout.ts +++ b/packages/studio/src/player/components/timelineLayout.ts @@ -87,6 +87,22 @@ export function generateTicks( return { major, minor }; } +/** + * Ticks spanning the full visible ruler width, not just the composition, so a + * zoomed-out ruler stays filled with labels instead of ending mid-panel. The + * major/minor interval is driven by pixelsPerSecond (pixel spacing), so widening + * the range keeps spacing identical — it only adds ticks past the content end. + */ +export function generateVisibleTicks( + effectiveDuration: number, + pixelsPerSecond: number, + viewportWidth: number, + gutter: number, +): { major: number[]; minor: number[] } { + const visible = viewportWidth > gutter ? (viewportWidth - gutter) / pixelsPerSecond : 0; + return generateTicks(Math.max(effectiveDuration, visible), pixelsPerSecond); +} + export function formatTimelineTickLabel(time: number, duration: number, majorInterval: number) { if (!Number.isFinite(time)) return "0:00"; const safeTime = Math.max(0, time);