feat: larger timeline timestamps with mouse-proximity magnification

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-09-22 16:51:56 -04:00
parent 923c7b0e23
commit 27c199e090
2 changed files with 41 additions and 9 deletions

View File

@@ -27,6 +27,9 @@ const THUMB_LANE_HEIGHT = 50;
const WAVEFORM_LANE_HEIGHT = 40;
const CONTROLS_LANE_HEIGHT = 30;
const TICK_HEIGHT = 10;
const BASE_FONT_SIZE = 12;
const MAGNIFY_BONUS = 6;
const MAGNIFY_RADIUS = 80;
export function drawTimeline(
ctx: CanvasRenderingContext2D,
@@ -38,7 +41,8 @@ export function drawTimeline(
pendingInPoint: number | null = null,
waveform: WaveformData = { tiers: null },
thumbnailSpritesheets: ThumbnailSpritesheet[] = [],
hasVideo: boolean = false
hasVideo: boolean = false,
mouseX: number | null = null
): void {
const { width, height } = state;
ctx.clearRect(0, 0, width, height);
@@ -46,7 +50,7 @@ export function drawTimeline(
ctx.fillStyle = '#181825';
ctx.fillRect(0, 0, width, height);
drawTimeTicks(ctx, state, duration);
drawTimeTicks(ctx, state, duration, mouseX);
if (thumbnailSpritesheets.length > 0) {
drawThumbnails(ctx, state, thumbnailSpritesheets, duration, 0, THUMB_LANE_HEIGHT);
@@ -68,27 +72,40 @@ export function drawTimeline(
function drawTimeTicks(
ctx: CanvasRenderingContext2D,
state: TimelineState,
duration: number
duration: number,
mouseX: number | null
): void {
const range = state.visibleEnd - state.visibleStart;
const tickInterval = getTickInterval(range, state.width);
const startTick = Math.floor(state.visibleStart / tickInterval) * tickInterval;
ctx.fillStyle = '#6c7086';
ctx.font = '10px -apple-system, sans-serif';
ctx.textAlign = 'center';
const baselineY = state.height - CONTROLS_LANE_HEIGHT + TICK_HEIGHT + 14;
for (let t = startTick; t <= state.visibleEnd; t += tickInterval) {
if (t < 0 || t > duration) continue;
const x = timeToX(t, state);
ctx.strokeStyle = '#45475a';
ctx.beginPath();
ctx.moveTo(x, state.height - CONTROLS_LANE_HEIGHT);
ctx.lineTo(x, state.height - CONTROLS_LANE_HEIGHT + TICK_HEIGHT);
ctx.stroke();
let fontSize = BASE_FONT_SIZE;
if (mouseX !== null) {
const distance = Math.abs(x - mouseX);
if (distance < MAGNIFY_RADIUS) {
const scale = (1 + Math.cos((Math.PI * distance) / MAGNIFY_RADIUS)) / 2;
fontSize = BASE_FONT_SIZE + MAGNIFY_BONUS * scale;
}
}
ctx.fillStyle = '#6c7086';
ctx.font = `${Math.round(fontSize)}px -apple-system, sans-serif`;
const label = formatTickLabel(t);
ctx.fillText(label, x, state.height - CONTROLS_LANE_HEIGHT + TICK_HEIGHT + 12);
ctx.fillText(label, x, baselineY);
}
}