Fixed race condition where animation frames could continue after pause() by
adding an isPlayingRef that's checked at the start of updatePlaybackPosition.
This ensures any queued animation frames will exit early if pause was called,
preventing the playhead from continuing to move when audio has stopped.
This fixes the issue where the playhead marker would occasionally keep moving
after hitting spacebar to pause, even though no audio was playing.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Changed timeline right padding from 240px to 250px to account for the
vertical scrollbar width in the waveforms area, ensuring perfect alignment
between timeline and waveform playhead markers.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Changed waveforms container from overflow-y-auto to overflow-y-scroll to ensure
the vertical scrollbar is always visible. This maintains consistent width alignment
between the timeline and waveform areas, preventing playhead marker misalignment
that occurred when scrollbar appeared/disappeared based on track count.
Fixes the issue where timeline was slightly wider than waveforms when vertical
scrollbar was present, causing ~15px offset in playhead position.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Added custom-scrollbar class to scrollable elements in:
- EffectBrowser dialog content area
- ProjectsDialog projects list
- CommandPalette results list
- Modal content area
- TrackList automation parameter label containers
This ensures consistent scrollbar styling across all dialogs and UI elements.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Calculate trackWidth based on track duration ratio to project duration
- Shorter tracks now render proportionally instead of stretching
- Longer tracks automatically update project duration
- All existing tracks re-render correctly when duration changes
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add controlsWidth offset to tooltip left position
- Tooltip now appears correctly at mouse cursor position
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Fix timeline width calculation to always fill viewport at minimum
- Fix waveform sampling to match timeline width calculation exactly
- Fix infinite scroll loop by removing circular callback
- Ensure scrollbars appear correctly when zooming in
- Use consistent PIXELS_PER_SECOND_BASE = 5 across all components
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add TimeScale component with canvas-based rendering
- Use 5 pixels per second base scale (duration * zoom * 5)
- Implement viewport-based rendering for performance
- Add scroll synchronization with waveforms
- Add 240px padding for alignment with track controls and master area
- Apply custom scrollbar styling
- Update all waveform width calculations to match timeline
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implemented three major medium effort features to enhance the audio editor:
**1. Region Markers System**
- Add marker type definitions supporting point markers and regions
- Create useMarkers hook for marker state management
- Build MarkerTimeline component for visual marker display
- Create MarkerDialog component for adding/editing markers
- Add keyboard shortcuts: M (add marker), Shift+M (next), Shift+Ctrl+M (previous)
- Support marker navigation, editing, and deletion
**2. Web Worker for Computations**
- Create audio worker for offloading heavy computations
- Implement worker functions: generatePeaks, generateMinMaxPeaks, normalizePeaks, analyzeAudio, findPeak
- Build useAudioWorker hook for easy worker integration
- Integrate worker into Waveform component with peak caching
- Significantly improve UI responsiveness during waveform generation
**3. Bezier Curve Automation**
- Enhance interpolateAutomationValue to support Bezier curves
- Implement cubic Bezier interpolation with control handles
- Add createSmoothHandles for auto-smooth curve generation
- Add generateBezierCurvePoints for smooth curve rendering
- Support bezier alongside existing linear and step curves
All features are type-safe and integrate seamlessly with the existing codebase.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Added keyboard handler for the 'S' key to trigger split at cursor.
The shortcut was defined in the command palette but missing from
the keyboard event handler.
Note: Ctrl+A for Select All was already working correctly.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implemented automation clipboard system:
- Added separate automationClipboard state for automation points
- Created handleCopyAutomation function to copy automation lane points
- Created handlePasteAutomation function to paste at current time with time offset
- Added Copy and Clipboard icon buttons to AutomationHeader component
- Automation points preserve curve type and value when copied/pasted
- Points are sorted by time after pasting
- Toast notifications for user feedback
- Ready for integration when automation lanes are actively used
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implemented track splitting at playback cursor:
- Added handleSplitAtCursor function to split selected track at current time
- Extracts two audio segments: before and after cursor position
- Creates two new tracks from the segments with numbered names
- Removes original track after split
- Added 'Split at Cursor' command to command palette (keyboard shortcut: S)
- Validation for edge cases (no track selected, no audio, invalid position)
- User feedback via toast notifications
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implemented variable playback speed functionality:
- Added playbackRate state and ref to useMultiTrackPlayer (0.25x - 2x range)
- Applied playback rate to AudioBufferSourceNode.playbackRate
- Updated timing calculations to account for playback rate
- Real-time playback speed adjustment for active playback
- Dropdown UI control in PlaybackControls with preset speeds
- Integrated changePlaybackRate function through AudioEditor
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Added complete loop functionality with UI controls:
- Loop state management in useMultiTrackPlayer (loopEnabled, loopStart, loopEnd)
- Automatic restart from loop start when reaching loop end during playback
- Loop toggle button in PlaybackControls with Repeat icon
- Loop points UI showing when loop is enabled (similar to punch in/out)
- Manual loop point adjustment with number inputs
- Quick set buttons to set loop points to current time
- Wired loop functionality through AudioEditor component
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Removed the defaultTrackHeight setting from UI preferences as it doesn't need
to be user-configurable. All tracks now use DEFAULT_TRACK_HEIGHT constant (400px).
Changes:
- Removed defaultTrackHeight from UISettings interface
- Removed track height slider from GlobalSettingsDialog
- Updated AudioEditor to use DEFAULT_TRACK_HEIGHT constant directly
- Simplified dependency arrays in addTrack callbacks
This simplifies the settings interface while maintaining the same visual behavior.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Removed the AudioWorklet compatibility check warning since it's an optional
feature that doesn't affect core functionality. The app works fine without
AudioWorklet support, using standard Web Audio API nodes instead.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Updated PLAN.md to reflect completion of mobile responsiveness enhancements:
- Touch gesture support via collapse/expand chevron buttons
- Collapsible track and master controls with detailed state descriptions
- Track collapse buttons on mobile (dual chevron system)
- Mobile vertical stacking with automation and effects bars
- Height synchronization between track controls and waveform containers
Phase 15.2 now fully complete with comprehensive mobile support.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Added comprehensive mobile support for Phase 15 (Polish & Optimization):
**Mobile Layout Enhancements:**
- Track controls now collapsible on mobile with two states:
- Collapsed: minimal controls with expand chevron, R/M/S buttons, horizontal level meter
- Expanded: full height fader, pan control, all buttons
- Track collapse buttons added to mobile view (left chevron for track collapse, right chevron for control collapse)
- Master controls collapse button hidden on desktop (lg:hidden)
- Automation and effects bars now available on mobile layout
- Both bars collapsible with eye/eye-off icons, horizontally scrollable when zoomed
- Mobile vertical stacking: controls → waveform → automation → effects per track
**Bug Fixes:**
- Fixed track controls and waveform container height matching on desktop
- Fixed Modal component prop: isOpen → open in all dialog components
- Fixed TypeScript null check for audioBuffer.duration
- Fixed keyboard shortcut category: 'help' → 'view'
**Technical Improvements:**
- Consistent height calculation using trackHeight variable
- Proper responsive breakpoints with Tailwind (sm:640px, lg:1024px)
- Progressive disclosure pattern for mobile controls
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Applied performance and audio settings to actual editor behavior:
- enableSpectrogram: conditionally show/hide spectrogram analyzer option
- sampleRate: sync recording sample rate with global audio settings
Changes:
- Switch analyzer view away from spectrogram when setting is disabled
- Adjust analyzer toggle grid columns based on spectrogram visibility
- Sync recording hook's sampleRate with global settings via useEffect
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Modified createTrack and createTrackFromBuffer to accept height parameter
- Updated useMultiTrack to pass height when creating tracks
- Applied settings.ui.defaultTrackHeight when adding new tracks
- Applied settings.editor.defaultZoom for initial zoom state
- Removed duplicate useSettings hook declaration in AudioEditor
- New tracks now use configured default height from settings
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Removed waveformColor from UISettings interface
- Removed waveform color picker from Interface settings tab
- Preserves dynamic per-track waveform coloring system
- Cleaner settings UI with one less option
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Fader handles now respect top-8 bottom-8 track padding
- Handle moves only within the visible track lane (60% range)
- Updated both TrackFader and MasterFader components
- Value calculation clamped to track bounds (32px padding top/bottom)
- Handle position mapped to 20%-80% range instead of 0%-100%
- Prevents handle from going beyond visible track area
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Plus button now conditionally rendered based on track.effectsExpanded
- Matches automation controls behavior
- Cleaner UI when panel is collapsed
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Added EffectBrowser import and state management
- Plus button opens dialog to select from all available effects
- Effect is added to track when selected from browser
- Removed hardcoded low-pass filter addition
- Better UX for adding effects to tracks
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Removed absolute positioning from eye icon button
- Added Plus button to add effects (currently adds low-pass filter)
- All controls now properly inline in normal flex flow
- Eye button correctly positioned at end without overlap
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Removed absolute positioning from eye icon button
- Made all controls part of normal flex flow
- Eye button now correctly positioned at end without overlap
- Chevron controls no longer overlay the eye icon
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Streamlined track controls and master controls to same width (240px)
- Fixed track controls container to use full width of parent column
- Matched TrackControls card structure with MasterControls (gap-3, no w-full/h-full)
- Updated outer container padding from p-2 to p-4 with gap-4
- Adjusted track controls wrapper to center content instead of stretching
- Added max-width constraint to PlaybackControls to prevent width changes
- Centered transport control buttons in footer
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Import cn utility function from @/lib/utils/cn
- Fixes ReferenceError: cn is not defined
- Required for conditional classNames on effect labels
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Effect labels show in primary color when enabled
- Effect labels show in gray when bypassed/disabled
- Added opacity reduction (60%) for bypassed effects
- Visual feedback matches effect state at a glance
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Display effect names as small chips/badges in effects header
- Shows all effect names at a glance without expanding
- Styled with primary color background and border
- Horizontal scrollable if many effects
- Visible whether effects rack is expanded or collapsed
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Remove '(N)' count display from effects bar header
- Effect names are already shown in EffectDevice component:
- Collapsed: vertical text label
- Expanded: header with full name
- Cleaner header appearance
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Replace ChevronDown/ChevronRight with Eye/EyeOff icons
- Position eye icon absolutely on the right side
- Match AutomationHeader styling with bg-muted/50 and border
- Eye icon shows when expanded, EyeOff when collapsed
- Consistent UX between automation and effects bars
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Track component now uses Math.max to ensure track.height is at least MIN_TRACK_HEIGHT
- TrackList component also uses Math.max for consistent enforcement
- Fixes issue where tracks with old height values (340px, 357px) were smaller
- All tracks now guaranteed to be exactly 360px regardless of stored height
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Update DEFAULT_TRACK_HEIGHT from 340px to 360px
- Update MIN_TRACK_HEIGHT from 240px to 360px
- Ensures all tracks have consistent 360px minimum height
- Applies to both control column and waveform column
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Import DEFAULT_TRACK_HEIGHT and COLLAPSED_TRACK_HEIGHT from types
- Use DEFAULT_TRACK_HEIGHT (340px) instead of hardcoded 240px fallback
- Ensures all tracks have the same height as the first track
- Matches the height used when creating tracks
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Remove fixed height from Track waveformOnly mode
- Use h-full class to fill flex container instead
- Allows parent scroll container to show horizontal scrollbar based on zoom
- Waveform now properly expands horizontally without clipping
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Remove h-32 wrapper div around AutomationLane
- AutomationLane now uses its own height (lane.height, defaults to 80px)
- Automation controls (canvas, points) now visible and interactive
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Track container now has fixed height (240px default or track.height)
- Waveform uses flex-1 to take remaining space
- Automation and effects bars use flex-shrink-0 for fixed height
- When bars expand, waveform shrinks instead of container growing
- Matches DAW behavior where track height stays constant
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Replace absolute positioning with flex column layout
- Waveform, automation bar, and effects bar now stacked vertically
- Removes gaps between bars naturally with stacked layout
- Both bars remain collapsible with no position dependencies
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Removed border-t from effects bar container
- Keeps border-b for bottom edge separation
- No gap between automation and effects bars in both folded and unfolded states
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Default selectedParameterId to 'volume' when undefined
- Fixes issue where clicking automation header did nothing
- Chevron now correctly shows fold/unfold state
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add Sparkles icon import to TrackExtensions
- Remove invalid props from AutomationLane (trackId, isPlaying, onSeek)
- Fix createAutomationPoint call to use object parameter with curve property
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Fixed issues:
1. Made automation bar collapsible with chevron indicator
2. Removed border-t from automation lane container (no gap to effects)
3. Restored lane.visible filter so AutomationLane properly renders with controls
The AutomationLane component has all the rich editing UI:
- Click canvas to add automation points
- Drag points to move them
- Double-click to delete points
- Keyboard delete (Del/Backspace) for selected points
- Visual feedback with selected state
All controls are intact and functional when automation bar is expanded.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Fixed all three issues:
1. Removed automation (A) and effects (E) toggle buttons from TrackControls
2. Made automation bar always expanded and non-collapsible
3. Added bottom border to effects bar (border-b)
Changes:
- TrackControls.tsx: Removed entire Row 2 (A/E buttons section)
- TrackList.tsx: Removed click handler and chevron from automation header
- TrackList.tsx: Automation lane always visible (no conditional rendering)
- TrackList.tsx: Added border-b to effects bar container
- TrackList.tsx: Added border-b to automation bar for visual consistency
Bars are now permanent, always-visible UI elements at the bottom of tracks.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Major improvements to automation and effects bars:
- Both bars now positioned at bottom of waveform (not top)
- Bars are always visible when track is expanded (no show/hide buttons)
- Effects bar at absolute bottom
- Automation bar above effects, dynamically positioned based on effects state
- Removed inner container from effects - direct rendering with EffectDevice
- Removed close buttons (X icons) - bars are permanent
- Effects render directly with gap-3 padding, no TrackExtensions wrapper
- Automation controls preserved (AutomationLane unchanged)
This creates a cleaner, always-accessible interface where users can quickly
expand/collapse automation or effects without toggling visibility.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>