From 86d2449619a9c62909ccdf2548b0c143daf60881 Mon Sep 17 00:00:00 2001
From: Tadas Petra <60107328+tadaspetra@users.noreply.github.com>
Date: Thu, 11 Jun 2026 14:32:04 -0500
Subject: [PATCH] Draggable playhead
---
src/index.html | 29 ++++++++++++++++++++++++++---
src/renderer/app.ts | 21 +++++++++++++++++++++
2 files changed, 47 insertions(+), 3 deletions(-)
diff --git a/src/index.html b/src/index.html
index 04baf9c..f0f233e 100644
--- a/src/index.html
+++ b/src/index.html
@@ -372,6 +372,7 @@
R
+
@@ -404,6 +405,28 @@
R
class="relative cursor-pointer select-none"
style="min-width: 100%"
>
+
+
@@ -438,11 +461,11 @@
R
style="opacity: 0.65"
>
-
+
diff --git a/src/renderer/app.ts b/src/renderer/app.ts
index b2aa5d2..ea8c92b 100644
--- a/src/renderer/app.ts
+++ b/src/renderer/app.ts
@@ -123,6 +123,8 @@ const editorTimelineWrapper = document.getElementById('editorTimelineWrapper');
const editorTimeline = document.getElementById('editorTimeline');
const editorSectionMarkers = document.getElementById('editorSectionMarkers');
const editorScrubber = document.getElementById('editorScrubber');
+const editorPlayhead = document.getElementById('editorPlayhead');
+const editorPlayheadRuler = document.getElementById('editorPlayheadRuler');
const editorCameraTrack = document.getElementById('editorCameraTrack');
const editorCameraMarkers = document.getElementById('editorCameraMarkers');
const cameraTrackLabel = document.getElementById('cameraTrackLabel');
@@ -4683,6 +4685,7 @@ function updateScrubberPosition() {
if (!editorState || editorState.duration <= 0) return;
const pct = (editorState.currentTime / editorState.duration) * 100;
editorScrubber.style.left = pct + '%';
+ if (editorPlayhead) editorPlayhead.style.left = pct + '%';
if (editorState.playing) scrollTimelineToPlayhead();
}
@@ -5062,6 +5065,24 @@ function seekFromTimeline(e) {
editorSeek(pct * editorState.duration);
}
+// Playhead ruler above the tracks: dedicated drag-to-scrub surface that cannot
+// accidentally hit section clips or trim handles.
+if (editorPlayheadRuler) {
+ editorPlayheadRuler.addEventListener('mousedown', (e) => {
+ if (!editorState || editorState.rendering) return;
+ e.preventDefault();
+ e.stopPropagation();
+ seekFromTimeline(e);
+ const onMove = (e2) => seekFromTimeline(e2);
+ const onUp = () => {
+ window.removeEventListener('mousemove', onMove);
+ window.removeEventListener('mouseup', onUp);
+ };
+ window.addEventListener('mousemove', onMove);
+ window.addEventListener('mouseup', onUp);
+ });
+}
+
const SECTION_DRAG_THRESHOLD = 5;
function getDragSelectedIds() {