feat: make playhead snap to elements

This commit is contained in:
Maze Winther
2026-02-23 10:55:06 +01:00
parent d352e58570
commit ab64c48c92
@@ -3,10 +3,7 @@ import { useState, useEffect, useCallback, useRef } from "react";
import { useEdgeAutoScroll } from "@/hooks/timeline/use-edge-auto-scroll"; import { useEdgeAutoScroll } from "@/hooks/timeline/use-edge-auto-scroll";
import { useEditor } from "../use-editor"; import { useEditor } from "../use-editor";
import { useShiftKey } from "@/hooks/use-shift-key"; import { useShiftKey } from "@/hooks/use-shift-key";
import { import { useTimelineSnapping } from "@/hooks/timeline/use-timeline-snapping";
useTimelineSnapping,
type SnapPoint,
} from "@/hooks/timeline/use-timeline-snapping";
import { TIMELINE_CONSTANTS } from "@/constants/timeline-constants"; import { TIMELINE_CONSTANTS } from "@/constants/timeline-constants";
interface UseTimelinePlayheadProps { interface UseTimelinePlayheadProps {
@@ -31,8 +28,8 @@ export function useTimelinePlayhead({
const isPlaying = editor.playback.getIsPlaying(); const isPlaying = editor.playback.getIsPlaying();
const isScrubbing = editor.playback.getIsScrubbing(); const isScrubbing = editor.playback.getIsScrubbing();
const isShiftHeldRef = useShiftKey(); const isShiftHeldRef = useShiftKey();
const { snapToNearestPoint } = useTimelineSnapping({ const { snapToNearestPoint, findSnapPoints } = useTimelineSnapping({
enableElementSnapping: false, enableElementSnapping: true,
enablePlayheadSnapping: false, enablePlayheadSnapping: false,
}); });
@@ -80,21 +77,24 @@ export function useTimelinePlayhead({
fps: framesPerSecond, fps: framesPerSecond,
}); });
const bookmarks = editor.scenes.getActiveScene()?.bookmarks ?? []; const shouldSnap = !isShiftHeldRef.current;
const bookmarkSnapPoints: SnapPoint[] = bookmarks.map((bookmark) => ({ const time = (() => {
time: bookmark.time, if (!shouldSnap) return frameTime;
type: "bookmark", const tracks = editor.timeline.getTracks();
})); const bookmarks =
const shouldSnapToBookmark = editor.scenes.getActiveScene()?.bookmarks ?? [];
!isShiftHeldRef.current && bookmarkSnapPoints.length > 0; const snapPoints = findSnapPoints({
const snapResult = shouldSnapToBookmark tracks,
? snapToNearestPoint({ playheadTime: frameTime,
targetTime: frameTime, bookmarks,
snapPoints: bookmarkSnapPoints, });
zoomLevel, const snapResult = snapToNearestPoint({
}) targetTime: frameTime,
: null; snapPoints,
const time = snapResult?.snapPoint ? snapResult.snappedTime : frameTime; zoomLevel,
});
return snapResult.snapPoint ? snapResult.snappedTime : frameTime;
})();
setScrubTime(time); setScrubTime(time);
seek({ time }); seek({ time });
@@ -109,6 +109,8 @@ export function useTimelinePlayhead({
activeProject.settings.fps, activeProject.settings.fps,
isShiftHeldRef, isShiftHeldRef,
editor.scenes, editor.scenes,
editor.timeline,
findSnapPoints,
snapToNearestPoint, snapToNearestPoint,
], ],
); );