From 6f0bf75b69216b029c6a5410daecbe5166315575 Mon Sep 17 00:00:00 2001 From: Miguel Angel Simon Sierra Date: Wed, 8 Jul 2026 23:41:03 -0400 Subject: [PATCH] feat(studio): fill the ruler with ticks across the full timeline width The ruler now generates ticks across the visible width instead of stopping at the composition end, so a zoomed-out ruler stays labelled to the right edge. The tick interval stays pps-driven, so spacing is unchanged. Logic lives in a new generateVisibleTicks helper to keep Timeline.tsx under the 600-line cap. --- .../studio/src/player/components/Timeline.tsx | 6 +++--- .../src/player/components/timelineLayout.ts | 16 ++++++++++++++++ 2 files changed, 19 insertions(+), 3 deletions(-) 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);