summaryrefslogtreecommitdiff
path: root/apps/web/src/hooks/timeline
diff options
context:
space:
mode:
Diffstat (limited to 'apps/web/src/hooks/timeline')
-rw-r--r--apps/web/src/hooks/timeline/element/use-element-interaction.ts16
-rw-r--r--apps/web/src/hooks/timeline/element/use-element-resize.ts9
-rw-r--r--apps/web/src/hooks/timeline/use-bookmark-drag.ts20
-rw-r--r--apps/web/src/hooks/timeline/use-timeline-playhead.ts12
-rw-r--r--apps/web/src/hooks/timeline/use-timeline-snapping.ts185
5 files changed, 20 insertions, 222 deletions
diff --git a/apps/web/src/hooks/timeline/element/use-element-interaction.ts b/apps/web/src/hooks/timeline/element/use-element-interaction.ts
index 79f1272c..e7b93813 100644
--- a/apps/web/src/hooks/timeline/element/use-element-interaction.ts
+++ b/apps/web/src/hooks/timeline/element/use-element-interaction.ts
@@ -17,14 +17,16 @@ import { snapTimeToFrame } from "@/lib/time";
import { computeDropTarget } from "@/lib/timeline/drop-utils";
import { getMouseTimeFromClientX } from "@/lib/timeline/drag-utils";
import { generateUUID } from "@/utils/id";
-import { useTimelineSnapping } from "@/hooks/timeline/use-timeline-snapping";
+import {
+ snapElementEdge,
+ type SnapPoint,
+} from "@/lib/timeline/snap-utils";
import type {
DropTarget,
ElementDragState,
TimelineElement,
TimelineTrack,
} from "@/types/timeline";
-import type { SnapPoint } from "@/hooks/timeline/use-timeline-snapping";
interface UseElementInteractionProps {
zoomLevel: number;
@@ -162,7 +164,6 @@ export function useElementInteraction({
const editor = useEditor();
const isShiftHeldRef = useShiftKey();
const tracks = editor.timeline.getTracks();
- const { snapElementEdge } = useTimelineSnapping();
const {
isElementSelected,
selectElement,
@@ -255,14 +256,7 @@ export function useElementInteraction({
snapPoint: snapResult.snapPoint,
};
},
- [
- snappingEnabled,
- editor.playback,
- snapElementEdge,
- tracks,
- zoomLevel,
- isShiftHeldRef,
- ],
+ [snappingEnabled, editor.playback, tracks, zoomLevel, isShiftHeldRef],
);
useEffect(() => {
diff --git a/apps/web/src/hooks/timeline/element/use-element-resize.ts b/apps/web/src/hooks/timeline/element/use-element-resize.ts
index 14693fff..2b303ad9 100644
--- a/apps/web/src/hooks/timeline/element/use-element-resize.ts
+++ b/apps/web/src/hooks/timeline/element/use-element-resize.ts
@@ -5,9 +5,10 @@ import type { TimelineElement, TimelineTrack } from "@/types/timeline";
import { useEditor } from "@/hooks/use-editor";
import { useShiftKey } from "@/hooks/use-shift-key";
import {
- useTimelineSnapping,
+ findSnapPoints,
+ snapToNearestPoint,
type SnapPoint,
-} from "@/hooks/timeline/use-timeline-snapping";
+} from "@/lib/timeline/snap-utils";
import { useTimelineStore } from "@/stores/timeline-store";
export interface ResizeState {
@@ -39,7 +40,7 @@ export function useTimelineElementResize({
const activeProject = editor.project.getActive();
const isShiftHeldRef = useShiftKey();
const snappingEnabled = useTimelineStore((state) => state.snappingEnabled);
- const { findSnapPoints, snapToNearestPoint } = useTimelineSnapping();
+
const [resizing, setResizing] = useState<ResizeState | null>(null);
const [currentTrimStart, setCurrentTrimStart] = useState(element.trimStart);
@@ -269,8 +270,6 @@ export function useTimelineElementResize({
activeProject.settings.fps,
snappingEnabled,
editor,
- findSnapPoints,
- snapToNearestPoint,
element.id,
onSnapPointChange,
canExtendElementDuration,
diff --git a/apps/web/src/hooks/timeline/use-bookmark-drag.ts b/apps/web/src/hooks/timeline/use-bookmark-drag.ts
index faf28e40..0e7fabd5 100644
--- a/apps/web/src/hooks/timeline/use-bookmark-drag.ts
+++ b/apps/web/src/hooks/timeline/use-bookmark-drag.ts
@@ -10,9 +10,12 @@ import { useShiftKey } from "@/hooks/use-shift-key";
import { DRAG_THRESHOLD_PX } from "@/constants/timeline-constants";
import { snapTimeToFrame } from "@/lib/time";
import { getMouseTimeFromClientX } from "@/lib/timeline/drag-utils";
-import { useTimelineSnapping } from "@/hooks/timeline/use-timeline-snapping";
+import {
+ findSnapPoints,
+ snapToNearestPoint,
+ type SnapPoint,
+} from "@/lib/timeline/snap-utils";
import type { Bookmark } from "@/types/timeline";
-import type { SnapPoint } from "@/hooks/timeline/use-timeline-snapping";
export interface BookmarkDragState {
isDragging: boolean;
@@ -47,8 +50,6 @@ export function useBookmarkDrag({
const playheadTime = editor.playback.getCurrentTime();
const duration = editor.timeline.getTotalDuration();
- const { findSnapPoints, snapToNearestPoint } = useTimelineSnapping();
-
const [dragState, setDragState] = useState<BookmarkDragState>({
isDragging: false,
bookmarkTime: null,
@@ -112,16 +113,7 @@ export function useBookmarkDrag({
snapPoint: result.snapPoint,
};
},
- [
- snappingEnabled,
- findSnapPoints,
- snapToNearestPoint,
- tracks,
- playheadTime,
- bookmarks,
- zoomLevel,
- isShiftHeldRef,
- ],
+ [snappingEnabled, tracks, playheadTime, bookmarks, zoomLevel, isShiftHeldRef],
);
useEffect(() => {
diff --git a/apps/web/src/hooks/timeline/use-timeline-playhead.ts b/apps/web/src/hooks/timeline/use-timeline-playhead.ts
index 1e536dae..d6bb29e2 100644
--- a/apps/web/src/hooks/timeline/use-timeline-playhead.ts
+++ b/apps/web/src/hooks/timeline/use-timeline-playhead.ts
@@ -3,7 +3,10 @@ import { useState, useEffect, useCallback, useRef } from "react";
import { useEdgeAutoScroll } from "@/hooks/timeline/use-edge-auto-scroll";
import { useEditor } from "../use-editor";
import { useShiftKey } from "@/hooks/use-shift-key";
-import { useTimelineSnapping } from "@/hooks/timeline/use-timeline-snapping";
+import {
+ findSnapPoints,
+ snapToNearestPoint,
+} from "@/lib/timeline/snap-utils";
import { TIMELINE_CONSTANTS } from "@/constants/timeline-constants";
interface UseTimelinePlayheadProps {
@@ -28,10 +31,6 @@ export function useTimelinePlayhead({
const isPlaying = editor.playback.getIsPlaying();
const isScrubbing = editor.playback.getIsScrubbing();
const isShiftHeldRef = useShiftKey();
- const { snapToNearestPoint, findSnapPoints } = useTimelineSnapping({
- enableElementSnapping: true,
- enablePlayheadSnapping: false,
- });
const seek = useCallback(
({ time }: { time: number }) => editor.playback.seek({ time }),
@@ -87,6 +86,7 @@ export function useTimelinePlayhead({
tracks,
playheadTime: frameTime,
bookmarks,
+ enablePlayheadSnapping: false,
});
const snapResult = snapToNearestPoint({
targetTime: frameTime,
@@ -110,8 +110,6 @@ export function useTimelinePlayhead({
isShiftHeldRef,
editor.scenes,
editor.timeline,
- findSnapPoints,
- snapToNearestPoint,
],
);
diff --git a/apps/web/src/hooks/timeline/use-timeline-snapping.ts b/apps/web/src/hooks/timeline/use-timeline-snapping.ts
deleted file mode 100644
index 5de75448..00000000
--- a/apps/web/src/hooks/timeline/use-timeline-snapping.ts
+++ /dev/null
@@ -1,185 +0,0 @@
-import { useCallback } from "react";
-import type { Bookmark, TimelineTrack } from "@/types/timeline";
-import { TIMELINE_CONSTANTS } from "@/constants/timeline-constants";
-import { BOOKMARK_TIME_EPSILON } from "@/lib/timeline/bookmarks";
-
-export interface SnapPoint {
- time: number;
- type: "element-start" | "element-end" | "playhead" | "bookmark";
- elementId?: string;
- trackId?: string;
-}
-
-export interface SnapResult {
- snappedTime: number;
- snapPoint: SnapPoint | null;
- snapDistance: number;
-}
-
-export interface UseTimelineSnappingOptions {
- snapThreshold?: number;
- enableElementSnapping?: boolean;
- enablePlayheadSnapping?: boolean;
- enableBookmarkSnapping?: boolean;
-}
-
-export function useTimelineSnapping({
- snapThreshold = 10,
- enableElementSnapping = true,
- enablePlayheadSnapping = true,
- enableBookmarkSnapping = true,
-}: UseTimelineSnappingOptions = {}) {
- const findSnapPoints = useCallback(
- ({
- tracks,
- playheadTime,
- excludeElementId,
- bookmarks = [],
- excludeBookmarkTime,
- }: {
- tracks: Array<TimelineTrack>;
- playheadTime: number;
- excludeElementId?: string;
- bookmarks?: Array<Bookmark>;
- excludeBookmarkTime?: number;
- }): SnapPoint[] => {
- const snapPoints: SnapPoint[] = [];
-
- if (enableElementSnapping) {
- for (const track of tracks) {
- for (const element of track.elements) {
- if (element.id === excludeElementId) continue;
-
- const elementStart = element.startTime;
- const elementEnd = element.startTime + element.duration;
-
- snapPoints.push(
- {
- time: elementStart,
- type: "element-start",
- elementId: element.id,
- trackId: track.id,
- },
- {
- time: elementEnd,
- type: "element-end",
- elementId: element.id,
- trackId: track.id,
- },
- );
- }
- }
- }
-
- if (enablePlayheadSnapping) {
- snapPoints.push({
- time: playheadTime,
- type: "playhead",
- });
- }
-
- if (enableBookmarkSnapping) {
- for (const bookmark of bookmarks) {
- if (
- excludeBookmarkTime != null &&
- Math.abs(bookmark.time - excludeBookmarkTime) <
- BOOKMARK_TIME_EPSILON
- ) {
- continue;
- }
- snapPoints.push({
- time: bookmark.time,
- type: "bookmark",
- });
- }
- }
-
- return snapPoints;
- },
- [enableElementSnapping, enablePlayheadSnapping, enableBookmarkSnapping],
- );
-
- const snapToNearestPoint = useCallback(
- ({
- targetTime,
- snapPoints,
- zoomLevel,
- }: {
- targetTime: number;
- snapPoints: Array<SnapPoint>;
- zoomLevel: number;
- }): SnapResult => {
- const pixelsPerSecond = TIMELINE_CONSTANTS.PIXELS_PER_SECOND * zoomLevel;
- const thresholdInSeconds = snapThreshold / pixelsPerSecond;
-
- let closestSnapPoint: SnapPoint | null = null;
- let closestDistance = Infinity;
-
- for (const snapPoint of snapPoints) {
- const distance = Math.abs(targetTime - snapPoint.time);
- if (distance < thresholdInSeconds && distance < closestDistance) {
- closestDistance = distance;
- closestSnapPoint = snapPoint;
- }
- }
-
- return {
- snappedTime: closestSnapPoint ? closestSnapPoint.time : targetTime,
- snapPoint: closestSnapPoint,
- snapDistance: closestDistance,
- };
- },
- [snapThreshold],
- );
-
- const snapElementEdge = useCallback(
- ({
- targetTime,
- elementDuration,
- tracks,
- playheadTime,
- zoomLevel,
- excludeElementId,
- snapToStart = true,
- bookmarks = [],
- }: {
- targetTime: number;
- elementDuration: number;
- tracks: Array<TimelineTrack>;
- playheadTime: number;
- zoomLevel: number;
- excludeElementId?: string;
- snapToStart?: boolean;
- bookmarks?: Array<Bookmark>;
- }): SnapResult => {
- const snapPoints = findSnapPoints({
- tracks,
- playheadTime,
- excludeElementId,
- bookmarks,
- });
-
- const effectiveTargetTime = snapToStart
- ? targetTime
- : targetTime + elementDuration;
- const snapResult = snapToNearestPoint({
- targetTime: effectiveTargetTime,
- snapPoints,
- zoomLevel,
- });
-
- if (!snapToStart && snapResult.snapPoint) {
- snapResult.snappedTime = snapResult.snappedTime - elementDuration;
- }
-
- return snapResult;
- },
- [findSnapPoints, snapToNearestPoint],
- );
-
- return {
- snapElementEdge,
- findSnapPoints,
- snapToNearestPoint,
- };
-}