From 4cbea130aca50bd1a4f114ed6a5170cd0dd00d17 Mon Sep 17 00:00:00 2001 From: skal Date: Thu, 5 Feb 2026 22:08:30 +0100 Subject: fix(timeline-editor): Fix effect drag jump bug and left handle constraint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CRITICAL BUG FIX: Effect Start Time Jumping Root Cause: Line 788: const currentLeft = parseFloat(e.target.style.left) || 0; Problem: e.target is what was CLICKED, not what has the listener - Clicking effect div itself: e.target = effectDiv ✓ - Clicking text inside: e.target = ✗ - If e.target is , it has no style.left property - parseFloat(undefined) returns NaN, || 0 gives 0 - Wrong offset calculation → effect jumps on click! The Fix: Use e.currentTarget instead of e.target - currentTarget = element with the event listener (always effectDiv) - target = element that was actually clicked (could be child) OLD: const currentLeft = parseFloat(e.target.style.left) || 0; NEW: const currentLeft = parseFloat(e.currentTarget.style.left) || 0; Why This Caused Intermittent Jumping: - Click on effect body (not text) → e.target = effectDiv → works fine - Click on effect text → e.target = → jumps! - Appears random because depends on WHERE user clicks Bug Fix #2: Left Handle Can Extend Past Sequence Start Problem: Math.max(0, ...) prevented negative effect start times - Right handle could extend sequence rightward ✓ - Left handle COULDN'T extend sequence leftward ✗ - Inconsistent behavior The Fix: Remove Math.max(0, ...) constraint Allow negative effect start times OLD: effect.startTime = Math.max(0, Math.min(..., effect.endTime - 0.1)); NEW: effect.startTime = Math.min(newStartTime, effect.endTime - 0.1); How It Works Now: 1. Drag left handle past sequence start 2. effect.startTime becomes negative (e.g., -2.0) 3. renderTimeline() calculates sequence bounds: seqVisualStart = seq.startTime + min(effect.startTime) = 10.0 + (-2.0) = 8.0 4. Sequence box extends leftward automatically! Example: Sequence at t=10s with effect [0.0, 5.0] Drag left handle to t=8s: - effect.startTime = 8.0 - 10.0 = -2.0 (relative) - Sequence visual start = 10.0 + (-2.0) = 8.0 (absolute) - Sequence box now starts at 8.0s ✓ Technical Details: - e.currentTarget: Element that addEventListener was called on - e.target: Deepest element that triggered the event - Effect innerHTML has children: - Clicking text triggers event but e.target is , not effectDiv - This is a classic event delegation bug Result: Both dragging and handles now work correctly! --- tools/timeline_editor/index.html | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'tools/timeline_editor') diff --git a/tools/timeline_editor/index.html b/tools/timeline_editor/index.html index f5277d8..c6c54bd 100644 --- a/tools/timeline_editor/index.html +++ b/tools/timeline_editor/index.html @@ -784,10 +784,11 @@ isDragging = true; // Calculate offset from timeline origin (not from element edge) + // CRITICAL: Use currentTarget (element with listener) not target (what was clicked) const timelineRect = timeline.getBoundingClientRect(); - const currentLeft = parseFloat(e.target.style.left) || 0; + const currentLeft = parseFloat(e.currentTarget.style.left) || 0; dragOffset.x = e.clientX - timelineRect.left - currentLeft; - dragOffset.y = e.clientY - e.target.getBoundingClientRect().top; + dragOffset.y = e.clientY - e.currentTarget.getBoundingClientRect().top; selectedItem = { type, index: seqIndex, seqIndex, effectIndex }; renderTimeline(); @@ -870,7 +871,9 @@ if (handleType === 'left') { // Adjust start time, keep end time fixed - effect.startTime = Math.max(0, Math.min(Math.round(relativeTime * 100) / 100, effect.endTime - 0.1)); + // Allow negative times (effect can extend before sequence start) + const newStartTime = Math.round(relativeTime * 100) / 100; + effect.startTime = Math.min(newStartTime, effect.endTime - 0.1); } else if (handleType === 'right') { // Adjust end time, keep start time fixed effect.endTime = Math.max(effect.startTime + 0.1, Math.round(relativeTime * 100) / 100); -- cgit v1.2.3