summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/timeline_editor/index.html35
1 files changed, 32 insertions, 3 deletions
diff --git a/tools/timeline_editor/index.html b/tools/timeline_editor/index.html
index 94e88f6..d450522 100644
--- a/tools/timeline_editor/index.html
+++ b/tools/timeline_editor/index.html
@@ -372,6 +372,7 @@
<button id="saveBtn" disabled>💾 Save demo.seq</button>
<button id="addSequenceBtn" disabled>➕ Add Sequence</button>
<button id="deleteBtn" disabled>🗑️ Delete Selected</button>
+ <button id="reorderBtn" disabled>🔄 Re-order by Time</button>
</div>
<div class="zoom-controls">
@@ -423,6 +424,7 @@
const saveBtn = document.getElementById('saveBtn');
const addSequenceBtn = document.getElementById('addSequenceBtn');
const deleteBtn = document.getElementById('deleteBtn');
+ const reorderBtn = document.getElementById('reorderBtn');
const propertiesPanel = document.getElementById('propertiesPanel');
const propertiesContent = document.getElementById('propertiesContent');
const messageArea = document.getElementById('messageArea');
@@ -868,6 +870,7 @@
renderTimeline();
saveBtn.disabled = false;
addSequenceBtn.disabled = false;
+ reorderBtn.disabled = false;
showMessage(`Loaded ${currentFile} - ${sequences.length} sequences`, 'success');
} catch (err) {
showMessage(`Error parsing file: ${err.message}`, 'error');
@@ -916,6 +919,30 @@
showMessage('Item deleted', 'success');
});
+ // Re-order sequences by time
+ reorderBtn.addEventListener('click', () => {
+ // Store current active sequence (if any)
+ const currentActiveSeq = lastActiveSeqIndex >= 0 ? sequences[lastActiveSeqIndex] : null;
+
+ // Sort sequences by start time (ascending)
+ sequences.sort((a, b) => a.startTime - b.startTime);
+
+ // Re-render timeline
+ renderTimeline();
+
+ // Restore focus on previously active sequence
+ if (currentActiveSeq) {
+ const newIndex = sequences.indexOf(currentActiveSeq);
+ if (newIndex >= 0 && sequences[newIndex]._yPosition !== undefined) {
+ // Scroll to keep it in view
+ timelineContainer.scrollTop = sequences[newIndex]._yPosition;
+ lastActiveSeqIndex = newIndex;
+ }
+ }
+
+ showMessage('Sequences re-ordered by start time', 'success');
+ });
+
// Zoom
zoomSlider.addEventListener('input', (e) => {
const zoom = parseInt(e.target.value);
@@ -963,12 +990,14 @@
// Horizontal scroll
timelineContainer.scrollLeft += e.deltaY;
- // Calculate current time position (left edge of viewport)
+ // Calculate current time position with 10% headroom for visual comfort
const currentScrollLeft = timelineContainer.scrollLeft;
- const currentTime = currentScrollLeft / pixelsPerSecond;
+ const viewportWidth = timelineContainer.clientWidth;
+ const slack = (viewportWidth / pixelsPerSecond) * 0.1; // 10% of viewport width in seconds
+ const currentTime = (currentScrollLeft / pixelsPerSecond) + slack;
// Find the closest sequence that should be visible at current time
- // (the last sequence that starts before or at current time)
+ // (the last sequence that starts before or at current time + slack)
let targetSeqIndex = 0;
for (let i = 0; i < sequences.length; i++) {
if (sequences[i].startTime <= currentTime) {