summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorskal <pascal.massimino@gmail.com>2026-02-11 23:53:48 +0100
committerskal <pascal.massimino@gmail.com>2026-02-11 23:53:48 +0100
commit01301eb20b18cb99a1a2304d1e88f2de05041595 (patch)
treec68f945d78ab8b2ea655c88b90a263e92fa4591a
parent409bbfb08fae03bfb7daa554a799bd8480806799 (diff)
feat: timeline editor improvements - sticky ticks, grid, collapse
- Sticky time markers stay visible when scrolling - Faint vertical grid lines aligned with ticks for better alignment - Collapsible sequences via double-click (35px collapsed state) - Updated all references from demo.seq to timeline.seq - Consolidated and tightened documentation - Fixed _collapsed initialization bug Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
-rw-r--r--tools/timeline_editor/README.md137
-rw-r--r--tools/timeline_editor/index.html110
2 files changed, 127 insertions, 120 deletions
diff --git a/tools/timeline_editor/README.md b/tools/timeline_editor/README.md
index adf9d4e..a76a5ed 100644
--- a/tools/timeline_editor/README.md
+++ b/tools/timeline_editor/README.md
@@ -1,73 +1,35 @@
# Timeline Editor
-Interactive web-based editor for `demo.seq` timeline files.
+Interactive web-based editor for `timeline.seq` files.
## Features
-✅ **Implemented:**
-- 📂 Load/save `demo.seq` files
-- 📊 Visual Gantt-style timeline
-- 🎯 Drag & drop sequences along timeline
-- 🎯 Drag & drop effects along timeline
-- 🎯 Resize effects with left/right handles
-- ⏱️ Edit timing (start/end times)
+- 📂 Load/save `timeline.seq` files
+- 📊 Visual Gantt-style timeline with sticky time markers
+- 🎯 Drag & drop sequences and effects
+- 🎯 Resize effects with handles
+- 📦 Collapsible sequences (double-click to collapse)
+- 📏 Vertical grid lines synchronized with time ticks
+- ⏱️ Edit timing and properties
- ⚙️ Stack-order based priority system
-- ⚙️ Edit effect class names and constructor arguments
-- 🔍 Zoom in/out (10% - 200%)
-- 🎵 Audio waveform visualization (WAV files)
-- 📋 Real-time statistics
+- 🔍 Zoom (10%-500%) with mouse wheel + Ctrl/Cmd
+- 🎵 Audio waveform visualization
+- 🎼 Snap-to-beat mode
+- 🔄 Re-order sequences by time
- 🗑️ Delete sequences/effects
-- ➕ Add new sequences
-- 🎼 Snap-to-beat mode with beat markers
## Usage
-1. **Open the editor:**
- ```bash
- open tools/timeline_editor/index.html
- ```
- Or double-click `index.html` in Finder.
-
-2. **Load a timeline:**
- - Click "📂 Load demo.seq"
- - Select your `assets/demo.seq` file
-
-3. **Edit the timeline:**
- - **Drag sequences/effects** to move them along the timeline
- - **Click an item** to select it and view properties
- - **Edit properties** in the panel below
- - **Click "Apply"** to save property changes
-
-4. **Save your changes:**
- - Click "💾 Save demo.seq"
- - Choose where to save the modified file
-
-5. **Load audio waveform (optional):**
- - Click "🎵 Load Audio (WAV)" to visualize your music track
- - The waveform appears above the timeline for visual reference
- - Use it to align sequences with beats, drops, and musical phrases
- - Click "✖ Clear Audio" to remove the waveform
-
- **Tip:** Generate a WAV file from your demo using:
- ```bash
- ./build/demo64k --dump_wav output.wav
- ```
- Then load `output.wav` in the timeline editor to align sequences with the actual audio output.
-
-6. **Zoom controls:**
- - Use the zoom slider to adjust timeline scale
- - Higher zoom = more pixels per second
- - Waveform scales automatically with zoom
-
-7. **Snap-to-beat mode:**
- - Enable "Show Beats" checkbox to display beat markers
- - Sequences and effects snap to beat boundaries when dragged
- - Helps maintain musical timing
-
-## Keyboard Shortcuts
-
-- **Delete key**: Delete selected item (when implemented)
-- **Escape**: Deselect current item
+1. **Open:** `open tools/timeline_editor/index.html` or double-click in browser
+2. **Load timeline:** Click "📂 Load timeline.seq" → select `workspaces/main/timeline.seq`
+3. **Edit:**
+ - Drag sequences/effects to reposition
+ - Double-click sequence header to collapse/expand
+ - Click item to edit properties in side panel
+ - Drag effect handles to resize
+4. **Zoom:** Ctrl/Cmd + mouse wheel (zooms at cursor position)
+5. **Audio:** Load WAV file for waveform visualization
+6. **Save:** Click "💾 Save timeline.seq"
## File Format
@@ -106,52 +68,11 @@ SEQUENCE 4b 1 "Beat Drop"
EFFECT = ParticlesEffect 0.0 2.0 # Priority 0 (same layer)
```
-## Color Coding
-
-- **Blue boxes**: Sequences (container for effects)
-- **Gray boxes**: Effects (visual elements)
-- **Green highlight**: Selected sequence
-- **Orange highlight**: Selected effect
-
-## Tips
-
-- **Sequences** have absolute start times
-- **Effects** have start/end times **relative to their sequence**
-- Priority determines rendering order (higher = rendered later = on top)
-- Effect constructor arguments are passed as-is to the C++ code
-
-## Limitations
-
-- No preview rendering (this is intentional - it's just a timeline editor)
-- No automatic overlap detection yet
-- No undo/redo (coming soon)
-- Cannot add effects to sequences (manually edit properties for now)
-
-## Future Enhancements
-
-- [ ] Undo/redo functionality
-- [ ] Add effect button (create new effects within sequences)
-- [ ] Overlap detection warnings
-- [ ] Timeline playback indicator
-- [ ] Multiple file comparison
-- [ ] Export to different formats
-- [ ] **Music.track visualization**: Parse `music.track` file and overlay tracker patterns/samples on timeline for alignment assistance
-
-## Technical Details
-
-- Pure HTML/CSS/JavaScript (no dependencies)
-- No backend required
-- Works offline
-- All processing happens in the browser
-- Files are saved via browser download API
-
-## Integration
-
-After editing in the timeline editor:
-
-1. Save the modified `demo.seq`
-2. Copy it to `assets/demo.seq`
-3. Rebuild the project: `cmake --build build`
-4. The new timeline will be compiled into the demo
+## Technical Notes
-No code changes needed - the `seq_compiler` automatically processes the updated file.
+- Pure HTML/CSS/JavaScript (no dependencies, works offline)
+- Sequences have absolute times, effects are relative to parent sequence
+- Priority determines render order (higher = on top)
+- Collapsed sequences show 35px title bar, expanded show full effect stack
+- Time markers sticky at top when scrolling
+- Vertical grid lines aid alignment
diff --git a/tools/timeline_editor/index.html b/tools/timeline_editor/index.html
index db71beb..ccd2750 100644
--- a/tools/timeline_editor/index.html
+++ b/tools/timeline_editor/index.html
@@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title>Timeline Editor - demo.seq</title>
+ <title>Timeline Editor - timeline.seq</title>
<style>
* {
margin: 0;
@@ -132,10 +132,13 @@
}
.time-markers {
- position: relative;
+ position: sticky;
+ top: 0;
height: 30px;
margin-bottom: 10px;
border-bottom: 1px solid #3c3c3c;
+ background: #252526;
+ z-index: 100;
}
.time-marker {
@@ -155,6 +158,17 @@
background: #3c3c3c;
}
+ .time-marker::after {
+ content: '';
+ position: absolute;
+ left: 0;
+ top: 30px;
+ width: 1px;
+ height: 10000px;
+ background: rgba(60, 60, 60, 0.2);
+ pointer-events: none;
+ }
+
.sequence {
position: absolute;
background: #264f78;
@@ -190,6 +204,36 @@
}
}
+ .sequence-header {
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ padding: 8px;
+ z-index: 5;
+ cursor: pointer;
+ user-select: none;
+ }
+
+ .sequence-header-name {
+ font-size: 14px;
+ font-weight: bold;
+ color: #ffffff;
+ }
+
+ .sequence:not(.collapsed) .sequence-header-name {
+ display: none;
+ }
+
+ .sequence.collapsed {
+ overflow: hidden !important;
+ background: #1a3a4a !important;
+ }
+
+ .sequence.collapsed .sequence-name {
+ display: none !important;
+ }
+
.sequence-name {
position: absolute;
top: 50%;
@@ -408,15 +452,15 @@
<div class="container">
<header>
<h1>📊 Timeline Editor</h1>
- <p>Interactive editor for demo.seq files</p>
+ <p>Interactive editor for timeline.seq files</p>
</header>
<div class="controls">
<label class="file-label">
- 📂 Load demo.seq
+ 📂 Load timeline.seq
<input type="file" id="fileInput" accept=".seq">
</label>
- <button id="saveBtn" disabled>💾 Save demo.seq</button>
+ <button id="saveBtn" disabled>💾 Save timeline.seq</button>
<label class="file-label">
🎵 Load Audio (WAV)
<input type="file" id="audioInput" accept=".wav">
@@ -493,7 +537,7 @@
const pixelsPerSecLabel = document.getElementById('pixelsPerSec');
const stats = document.getElementById('stats');
- // Parser: demo.seq → JavaScript objects
+ // Parser: timeline.seq → JavaScript objects
// Format specification: doc/SEQUENCE.md
function parseSeqFile(content) {
const sequences = [];
@@ -551,7 +595,8 @@
startTime: parseTime(seqMatch[1]),
priority: parseInt(seqMatch[2]),
effects: [],
- name: seqMatch[3] || ''
+ name: seqMatch[3] || '',
+ _collapsed: false
};
sequences.push(currentSequence);
currentPriority = -1; // Reset effect priority for new sequence
@@ -587,7 +632,7 @@
return { sequences, bpm };
}
- // Serializer: JavaScript objects → demo.seq
+ // Serializer: JavaScript objects → timeline.seq
function serializeSeqFile(sequences) {
let output = '# Demo Timeline\n';
output += '# Generated by Timeline Editor\n';
@@ -786,20 +831,53 @@
const seqVisualWidth = seqVisualEnd - seqVisualStart;
+ // Initialize collapsed state if undefined
+ if (seq._collapsed === undefined) {
+ seq._collapsed = false;
+ }
+
// Calculate sequence height based on number of effects (stacked vertically)
const numEffects = seq.effects.length;
const effectSpacing = 30;
- const seqHeight = Math.max(70, 20 + numEffects * effectSpacing + 5);
+ const fullHeight = Math.max(70, 20 + numEffects * effectSpacing + 5);
+ const seqHeight = seq._collapsed ? 35 : fullHeight;
seqDiv.style.left = `${seqVisualStart * pixelsPerSecond}px`;
seqDiv.style.top = `${cumulativeY}px`;
seqDiv.style.width = `${seqVisualWidth * pixelsPerSecond}px`;
seqDiv.style.height = `${seqHeight}px`;
+ seqDiv.style.minHeight = `${seqHeight}px`;
+ seqDiv.style.maxHeight = `${seqHeight}px`;
// Store Y position for this sequence (used by effects and scroll)
seq._yPosition = cumulativeY;
cumulativeY += seqHeight + sequenceGap;
+ // Create sequence header (double-click to collapse)
+ const seqHeaderDiv = document.createElement('div');
+ seqHeaderDiv.className = 'sequence-header';
+
+ const headerName = document.createElement('span');
+ headerName.className = 'sequence-header-name';
+ headerName.textContent = seq.name || `Sequence ${seqIndex + 1}`;
+
+ seqHeaderDiv.appendChild(headerName);
+
+ // Prevent drag on header
+ seqHeaderDiv.addEventListener('mousedown', (e) => {
+ e.stopPropagation();
+ });
+
+ // Double-click to toggle collapse
+ seqHeaderDiv.addEventListener('dblclick', (e) => {
+ e.stopPropagation();
+ e.preventDefault();
+ seq._collapsed = !seq._collapsed;
+ renderTimeline();
+ });
+
+ seqDiv.appendChild(seqHeaderDiv);
+
// Create sequence name overlay (large, centered, fades on hover)
const seqNameDiv = document.createElement('div');
seqNameDiv.className = 'sequence-name';
@@ -807,6 +885,11 @@
seqDiv.appendChild(seqNameDiv);
+ // Apply collapsed state
+ if (seq._collapsed) {
+ seqDiv.classList.add('collapsed');
+ }
+
if (selectedItem && selectedItem.type === 'sequence' && selectedItem.index === seqIndex) {
seqDiv.classList.add('selected');
}
@@ -827,7 +910,8 @@
timeline.appendChild(seqDiv);
- // Render effects within sequence
+ // Render effects within sequence (skip if collapsed)
+ if (!seq._collapsed) {
seq.effects.forEach((effect, effectIndex) => {
const effectDiv = document.createElement('div');
effectDiv.className = 'effect';
@@ -894,6 +978,7 @@
timeline.appendChild(effectDiv);
});
+ }
});
updateStats();
@@ -1172,7 +1257,7 @@
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
- a.download = currentFile || 'demo.seq';
+ a.download = currentFile || 'timeline.seq';
a.click();
URL.revokeObjectURL(url);
showMessage('File saved', 'success');
@@ -1194,7 +1279,8 @@
type: 'sequence',
startTime: 0,
priority: 0,
- effects: []
+ effects: [],
+ _collapsed: false
});
renderTimeline();
showMessage('New sequence added', 'success');