summaryrefslogtreecommitdiff
path: root/apps/web/src/hooks/use-timeline-playhead.ts
diff options
context:
space:
mode:
authorgantiro <gantiro396@gmail.com>2025-07-15 22:56:56 +0700
committergantiro <gantiro396@gmail.com>2025-07-15 22:56:56 +0700
commit52f003f25ab8d3124ddf4880c44f874206d7f988 (patch)
treefee80fc0bedf0122e3aa6f020d23642a4093cee7 /apps/web/src/hooks/use-timeline-playhead.ts
parentb266678fe4bb8c4053688fd037693fa2f930ac14 (diff)
downloadopencut-52f003f25ab8d3124ddf4880c44f874206d7f988.tar.gz
add comment for hooks
Diffstat (limited to 'apps/web/src/hooks/use-timeline-playhead.ts')
-rw-r--r--apps/web/src/hooks/use-timeline-playhead.ts40
1 files changed, 38 insertions, 2 deletions
diff --git a/apps/web/src/hooks/use-timeline-playhead.ts b/apps/web/src/hooks/use-timeline-playhead.ts
index 8aee5b1f..de3f8ccf 100644
--- a/apps/web/src/hooks/use-timeline-playhead.ts
+++ b/apps/web/src/hooks/use-timeline-playhead.ts
@@ -11,6 +11,13 @@ interface UseTimelinePlayheadProps {
rulerScrollRef: React.RefObject<HTMLDivElement>;
}
+/**
+ * useTimelinePlayhead
+ *
+ * Custom hook to manage playhead (scrubbing) logic for a timeline editor.
+ * Handles mouse interaction for timeline ruler, calculates time from mouse,
+ * and enables smooth scrubbing without unnecessary re-renders.
+ */
export function useTimelinePlayhead({
currentTime,
duration,
@@ -19,17 +26,35 @@ export function useTimelinePlayhead({
rulerRef,
rulerScrollRef,
}: UseTimelinePlayheadProps) {
+ // Get current project info (especially FPS) from global store
const { activeProject } = useProjectStore();
+ // Ref to track if currently scrubbing
const isScrubbingRef = useRef(false);
+
+ // Ref to hold the playhead time while scrubbing (does not trigger re-render)
const scrubTimeRef = useRef<number | null>(null);
+
+ // State to force re-render when scrubbing ends
const [_, forceRerender] = useState(0);
+ /**
+ * Determines the actual playhead position:
+ * - If scrubbing, use the value in scrubTimeRef
+ * - Otherwise, use the currentTime (controlled by external state)
+ */
const playheadPosition =
isScrubbingRef.current && scrubTimeRef.current !== null
? scrubTimeRef.current
: currentTime;
+ /**
+ * Calculate timeline time (in seconds) based on mouse X position.
+ * - Gets bounding rect of the ruler
+ * - Adjusts for scroll position if ruler is scrollable
+ * - Converts X pixel offset to seconds using current zoom level
+ * - Snaps to nearest frame using FPS
+ */
const getTimeFromMouse = useCallback(
(e: MouseEvent | React.MouseEvent) => {
const ruler = rulerRef.current;
@@ -43,6 +68,7 @@ export function useTimelinePlayhead({
const scrollLeft = scrollArea.scrollLeft;
const x = e.clientX - rect.left + scrollLeft;
+ // Calculate how many pixels represent one second, depending on zoom
const pixelsPerSecond = 50 * zoomLevel;
const rawTime = Math.max(0, Math.min(duration, x / pixelsPerSecond));
const time = snapTimeToFrame(rawTime, activeProject?.fps || 30);
@@ -51,6 +77,13 @@ export function useTimelinePlayhead({
[rulerRef, rulerScrollRef, duration, zoomLevel, activeProject?.fps]
);
+ /**
+ * Handle mouse down event on the ruler:
+ * - Starts scrubbing and updates playhead immediately
+ * - Registers mousemove/mouseup events to allow scrubbing
+ * - Updates time as mouse moves and seeks to new time
+ * - Cleans up listeners and triggers re-render when scrubbing ends
+ */
const handleRulerMouseDown = useCallback(
(e: React.MouseEvent) => {
e.preventDefault();
@@ -61,6 +94,7 @@ export function useTimelinePlayhead({
scrubTimeRef.current = time;
seek(time);
+ // Mouse move handler: update playhead and seek to new time
const onMouseMove = (e: MouseEvent) => {
const t = getTimeFromMouse(e);
if (t !== scrubTimeRef.current) {
@@ -69,6 +103,7 @@ export function useTimelinePlayhead({
}
};
+ // Mouse up handler: stop scrubbing, cleanup, and force re-render
const onMouseUp = () => {
isScrubbingRef.current = false;
window.removeEventListener("mousemove", onMouseMove);
@@ -76,6 +111,7 @@ export function useTimelinePlayhead({
forceRerender((v) => v + 1);
};
+ // Attach listeners to window for drag outside the ruler area
window.addEventListener("mousemove", onMouseMove);
window.addEventListener("mouseup", onMouseUp);
},
@@ -83,7 +119,7 @@ export function useTimelinePlayhead({
);
return {
- playheadPosition,
- handleRulerMouseDown,
+ playheadPosition, // Current playhead position (real-time while scrubbing)
+ handleRulerMouseDown, // Attach to the ruler's onMouseDown
};
}