Commit Graph

207 Commits

Author SHA1 Message Date
839128a93f fix: add missing onUpdateTrack prop to Track component
Fixed "onUpdateTrack is not defined" error by:
- Added onUpdateTrack to TrackProps interface
- Added onUpdateTrack to Track component destructuring
- Passed onUpdateTrack prop from TrackList to Track

This prop is required for:
- Track height resizing functionality
- Automation lane updates
- General track property updates

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-18 16:44:19 +01:00
ecf7f060ec feat: Complete Ableton-style track layout redesign
Track height & spacing improvements:
- Increased DEFAULT_TRACK_HEIGHT from 180px to 240px for vertical controls
- Increased MIN_TRACK_HEIGHT from 60px to 120px
- Increased MAX_TRACK_HEIGHT from 300px to 400px
- Added COLLAPSED_TRACK_HEIGHT constant (48px)
- Reduced control panel gap from 8px to 6px for tighter spacing
- Added min-h-0 and overflow-hidden to prevent flex overflow
- Optimized fader container with max-h-[140px] constraint

Clip-style waveform visualization (Ableton-like):
- Wrapped waveform canvas in visible "clip" container
- Added border, rounded corners, and shadow for clip identity
- Added 16px clip header bar showing track name
- Implemented hover state for better interactivity
- Added gradient background from-foreground/5 to-transparent

Track height resize functionality:
- Added draggable bottom-edge resize handle
- Implemented cursor-ns-resize with hover feedback
- Constrain resizing to MIN/MAX height range
- Real-time height updates with smooth visual feedback
- Active state highlighting during resize

Effects section visual integration:
- Changed from solid background to gradient (from-muted/80 to-muted/60)
- Reduced device rack height from 192px to 176px for better proportion
- Improved visual hierarchy and connection to track row

Flexible VerticalFader component:
- Changed from fixed h-32 (128px) to flex-1 layout
- Added min-h-[80px] and max-h-[140px] constraints
- Allows parent container to control actual height
- Maintains readability and proportions at all sizes

CSS enhancements (globals.css):
- Added .track-clip-container utility class
- Added .track-clip-header utility class
- Theme-aware clip styling for light/dark modes
- OKLCH color space for consistent appearance

Visual results:
- Professional DAW appearance matching Ableton Live
- Clear clip/region boundaries for audio editing
- Better proportions for vertical controls (240px tracks)
- Resizable track heights (120-400px range)
- Improved visual hierarchy and organization

Files modified:
- types/track.ts (height constants)
- components/tracks/Track.tsx (layout + clip styling + resize)
- components/ui/VerticalFader.tsx (flexible height)
- app/globals.css (clip styling)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-18 16:41:58 +01:00
9b1eedc379 feat: Ableton Live-style effects and complete automation system
Enhanced visual design:
- Improved device rack container with darker background and inner shadow
- Device cards now have rounded corners, shadows, and colored indicators
- Better visual separation between enabled/disabled effects
- Active devices highlighted with accent border

Complete automation infrastructure (Phase 9):
- Created comprehensive type system for automation lanes and points
- Implemented AutomationPoint component with drag-and-drop editing
- Implemented AutomationHeader with mode controls (Read/Write/Touch/Latch)
- Implemented AutomationLane with canvas-based curve rendering
- Integrated automation lanes into Track component below effects
- Created automation playback engine with real-time interpolation
- Added automation data persistence to localStorage

Automation features:
- Add/remove automation points by clicking/double-clicking
- Drag points to change time and value
- Multiple automation modes (Read, Write, Touch, Latch)
- Linear and step curve types (bezier planned)
- Adjustable lane height (60-180px)
- Show/hide automation per lane
- Real-time value display at playhead
- Color-coded lanes by parameter type
- Keyboard delete support (Delete/Backspace)

Track type updates:
- Added automation field to Track interface
- Updated track creation to initialize empty automation
- Updated localStorage save/load to include automation data

Files created:
- components/automation/AutomationPoint.tsx
- components/automation/AutomationHeader.tsx
- components/automation/AutomationLane.tsx
- lib/audio/automation/utils.ts (helper functions)
- lib/audio/automation/playback.ts (playback engine)
- types/automation.ts (complete type system)

Files modified:
- components/effects/EffectDevice.tsx (Ableton-style visual improvements)
- components/tracks/Track.tsx (automation lanes integration)
- types/track.ts (automation field added)
- lib/audio/track-utils.ts (automation initialization)
- lib/hooks/useMultiTrack.ts (automation persistence)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-18 16:30:01 +01:00
dc9647731d feat: redesign track controls to Ableton Live style
Major UI Redesign:
- Reduced track control width from 288px to 192px (33% narrower)
- Replaced horizontal sliders with vertical fader and circular knob
- More compact, professional appearance matching Ableton Live
- Global settings dialog replaces inline recording settings

New Components Created:
- VerticalFader.tsx: Vertical volume control with integrated level meter
  - Shows volume dB at top, level dB at bottom
  - Level meter displayed as background gradient
  - Draggable handle for precise control

- CircularKnob.tsx: Rotary pan control
  - SVG-based rotary knob with arc indicator
  - Vertical drag interaction (200px sensitivity)
  - Displays L/C/R values

- GlobalSettingsDialog.tsx: Centralized settings
  - Tabbed interface (Recording, Playback, Interface)
  - Recording settings moved from inline to dialog
  - Accessible via gear icon in header
  - Modal dialog with backdrop

Track Control Panel Changes:
- Track name: More compact (text-xs)
- Buttons: Smaller (h-6 w-6), text-based S/M buttons
- Record button: Circle indicator instead of icon
- Pan: Circular knob (40px) instead of horizontal slider
- Volume: Vertical fader with integrated meter
- Removed: Inline recording settings panel

Header Changes:
- Added Settings button (gear icon) before ThemeToggle
- Opens GlobalSettingsDialog on click
- Clean, accessible from anywhere

Props Cleanup:
- Removed recordingSettings props from Track/TrackList
- Removed onInputGainChange, onRecordMonoChange, onSampleRateChange props
- Settings now managed globally via dialog

Technical Details:
- VerticalFader uses mouse drag for smooth control
- CircularKnob rotates -135° to +135° (270° range)
- Global event listeners for drag interactions
- Proper cleanup on unmount

Benefits:
 33% narrower tracks = more tracks visible
 Professional Ableton-style appearance
 Cleaner, less cluttered interface
 Global settings accessible anywhere
 Better use of vertical space
 Consistent with industry-standard DAWs

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-18 16:15:04 +01:00
49dd0c2d38 feat: complete Phase 8.3 - recording settings (input gain, mono/stereo, sample rate)
Recording Settings (Phase 8.3):
- Added input gain control (0.0-2.0 with dB display)
- Real-time gain adjustment via GainNode during recording
- Mono/Stereo recording mode selection
- Sample rate matching (44.1kHz, 48kHz, 96kHz)
- Mono conversion averages all channels when enabled
- Recording settings panel shown when track is armed

Components Created:
- RecordingSettings.tsx: Settings panel with gain slider, mono/stereo toggle, sample rate buttons

Components Modified:
- useRecording hook: Added settings state and GainNode integration
- AudioEditor: Pass recording settings to TrackList
- TrackList: Forward settings to Track components
- Track: Show RecordingSettings when armed for recording

Technical Details:
- GainNode inserted between source and analyser in recording chain
- Real-time gain updates via gainNode.gain.value
- AudioContext created with target sample rate
- Mono conversion done post-recording by averaging channels
- Settings persist during recording session

Phase 8 Complete:
-  Phase 8.1: Audio Input
-  Phase 8.2: Recording Controls (punch/overdub)
-  Phase 8.3: Recording Settings
- 📋 Phase 9: Automation (NEXT)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-18 15:51:38 +01:00
5f0017facb feat: complete Phase 8.2 - punch-in/punch-out and overdub recording
Recording Controls (Phase 8.2):
- Added punch-in/punch-out UI controls with time inputs
- Punch mode toggle button with visual feedback
- Set punch times from current playback position
- Collapsible punch time editor shown when enabled
- Overdub mode toggle for layering recordings
- Overdub implementation mixes recorded audio with existing track audio

Components Modified:
- PlaybackControls: Added punch and overdub controls with icons
- AudioEditor: Implemented overdub mixing logic and state management
- PLAN.md: Marked Phase 8.1 and 8.2 as complete

Technical Details:
- Overdub mixes audio buffers by averaging samples to avoid clipping
- Handles multi-channel audio correctly
- Punch controls use AlignVerticalJustifyStart/End icons
- Overdub uses Layers icon for visual clarity

Phase 8 Progress:
-  Phase 8.1: Audio Input (complete)
-  Phase 8.2: Recording Controls (complete)
- 🔲 Phase 8.3: Recording Settings (next)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-18 15:44:13 +01:00
a5a75a5f5c feat: show volume off icon when track volume is 0
- Volume icon now switches between Volume2 and VolumeX based on volume value
- Matches behavior of master volume controls for consistency
- Icon size remains consistent at h-3.5 w-3.5

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-18 15:36:25 +01:00
85d27c3b13 feat: standardize icon sizes and replace pan icon with UnfoldHorizontal
- Replaced CircleArrowOutUpRight pan icon with UnfoldHorizontal
- Standardized all track control icons to h-3.5 w-3.5:
  - Volume, Pan, Mic, and Gauge icons now have consistent sizing
- Improves visual consistency across the track control panel

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-18 15:35:02 +01:00
546c80e4ae feat: display dB values and use gauge icon for level meters
Changed level meter display to show professional dB values instead
of percentages, and replaced volume icon with gauge icon.

Display Changes:
- Show dB values (-60 to 0) instead of percentage (0-100%)
- Use monospace font for consistent digit alignment
- Show "-∞" for silence (level = 0) instead of "-60"
- Rounded to nearest integer dB (no decimals for cleaner display)

Icon Updates:
- Replaced Volume2 icon with Gauge icon for playback levels
- Kept Mic icon for recording input levels
- Gauge better represents metering/measurement vs audio control

dB Conversion:
- Formula: dB = (normalized * 60) - 60
- Reverse of: normalized = (dB + 60) / 60
- Range: -60dB (silence) to 0dB (full scale)

Display Examples:
  0.00 (0%) = -∞   (silence)
  0.17 (17%) = -50dB (very quiet)
  0.50 (50%) = -30dB (moderate)
  0.83 (83%) = -10dB (loud)
  1.00 (100%) = 0dB (full scale)

Benefits:
 Professional dB notation matching industry standards
 Clearer for audio engineers and musicians
 Easier to identify levels relative to 0dBFS
 Gauge icon better conveys "measurement"
 Monospace font prevents number jumping

Now meters show "-18" instead of "70%" making it immediately
clear where you are in the dynamic range.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-18 15:28:35 +01:00
dc567d0144 feat: add professional gradient to level meters matching dB scale
Replaced solid color blocks with smooth gradient to match
professional audio metering standards and dB scale mapping.

The Problem:
- Hard color transitions (green/yellow/red) looked jarring
- Didn't match professional DAW aesthetics
- Color didn't reflect actual dB values visually

The Solution:
- Implemented CSS linear gradient across meter bar
- Gradient matches dB scale breakpoints:
  * Green: 0-70% (-60dB to -18dB) - Safe zone
  * Yellow: 70-90% (-18dB to -6dB) - Getting hot
  * Red: 90-100% (-6dB to 0dB) - Very loud/clipping

Gradient Details:
Horizontal: linear-gradient(to right, ...)
Vertical: linear-gradient(to top, ...)

Color stops:
  0%: rgb(34, 197, 94)   - Green start
 70%: rgb(34, 197, 94)   - Green hold
 85%: rgb(234, 179, 8)   - Yellow transition
100%: rgb(239, 68, 68)   - Red peak

Visual Behavior:
- Smooth color transition as levels increase
- Green dominates safe zone (-60dB to -18dB)
- Yellow appears in warning zone (-18dB to -6dB)
- Red shows critical/clipping zone (-6dB to 0dB)
- Matches Pro Tools, Logic Pro, Ableton Live style

Benefits:
 Professional appearance matching industry DAWs
 Smooth visual feedback instead of jarring transitions
 Colors accurately represent dB ranges
 Better user experience for mixing/mastering
 Gradient visible even at low levels

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-18 15:26:10 +01:00
db01209f77 feat: implement professional logarithmic dB scale for level meters
Converted level meters from linear to logarithmic (dB) scale to
match professional audio software behavior and human hearing.

The Problem:
- Linear scale (0-100%) doesn't match perceived loudness
- Doesn't match professional DAW meter behavior
- Half-volume audio appears at 50% but sounds much quieter
- No industry-standard dB reference

The Solution:
- Convert linear amplitude to dB: 20 * log10(linear)
- Normalize -60dB to 0dB range to 0-100% display
- Matches professional audio metering standards

dB Scale Mapping:
  0 dB (linear 1.0)    = 100% (full scale, clipping)
 -6 dB (linear ~0.5)   = 90%  (loud)
-12 dB (linear ~0.25)  = 80%  (normal)
-20 dB (linear ~0.1)   = 67%  (moderate)
-40 dB (linear ~0.01)  = 33%  (quiet)
-60 dB (linear ~0.001) = 0%   (silence threshold)

Implementation:
- Added linearToDbScale() function to both hooks
- useMultiTrackPlayer: playback level monitoring
- useRecording: input level monitoring
- Formula: (dB - minDb) / (maxDb - minDb)
- Range: -60dB (min) to 0dB (max)

Benefits:
 Professional audio metering standards
 Matches human perception of loudness
 Consistent with DAWs (Pro Tools, Logic, Ableton)
 Better visual feedback for mixing/mastering
 More responsive in useful range (-20dB to 0dB)

Now properly mastered tracks will show levels in the
90-100% range, matching what you'd see in professional software.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-18 15:23:33 +01:00
a0ce83a654 fix: use Float32Array for accurate full-range level measurement
Switched from Uint8Array to Float32Array for level monitoring
to get accurate, full-precision audio measurements.

The Problem:
- getByteTimeDomainData() uses Uint8Array (0-255)
- Byte conversion: (value - 128) / 128 has asymmetric range
- Positive peaks: (255-128)/128 = 0.992 (not full 1.0)
- Precision loss from byte quantization
- Mastered tracks with peaks at 0dBFS only showed ~50%

The Solution:
- Switched to getFloatTimeDomainData() with Float32Array
- Returns actual sample values directly in -1.0 to +1.0 range
- No conversion needed, no precision loss
- Accurate representation of audio peaks

Changes Applied:
- useMultiTrackPlayer: Float32Array with analyser.fftSize samples
- useRecording: Float32Array with analyser.fftSize samples
- Peak detection: Math.abs() on float values directly

Benefits:
 Full 0-100% range for properly mastered audio
 Higher precision (32-bit float vs 8-bit byte)
 Symmetric range (-1.0 to +1.0, not -1.0 to ~0.992)
 Accurate metering for professional audio files

Now mastered tracks with peaks at 0dBFS will correctly show
~100% on the meters instead of being capped at 50%.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-18 15:21:31 +01:00
3e6fbda755 fix: move analyser before gain node to show true audio levels
Repositioned analyser nodes in audio graph to measure raw audio
levels before volume/gain adjustments.

The Problem:
- Analyser was after gain node in signal chain
- Track volume defaults to 0.8 (80%)
- Audio was scaled down before measurement
- Meters only showed ~50% of actual audio peaks

The Solution:
- Moved analyser to immediately after source
- Now measures raw audio before any processing
- Shows true audio content independent of fader position

Audio Graph Changes:
Before: source -> gain -> pan -> effects -> analyser -> master
After:  source -> analyser -> gain -> pan -> effects -> master

Benefits:
 Meters show full 0-100% range based on audio content
 Meter reading independent of volume fader position
 Accurate representation of track audio levels
 Increased smoothingTimeConstant to 0.8 for smoother motion

This is how professional DAWs work - level meters show the
audio content, not the output level after the fader.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-18 15:17:42 +01:00
8367cbf6e7 fix: switch from RMS to peak detection for more accurate level meters
Changed level calculation from RMS to peak detection to show
more realistic and responsive meter values.

The Problem:
- RMS calculation produced values typically in 0-30% range
- Audio signals have low average RMS (0.1-0.3 for music)
- Meters appeared broken, never reaching higher levels

The Solution:
- Switched to peak detection (max absolute value)
- Peaks now properly show 0-100% range
- More responsive to transients and dynamics
- Matches typical DAW meter behavior

Algorithm Change:
Before (RMS):
  rms = sqrt(sum(normalized²) / length)

After (Peak):
  peak = max(abs(normalized))

Applied to Both:
- Recording input level monitoring (useRecording)
- Playback output level monitoring (useMultiTrackPlayer)

Benefits:
 Full 0-100% range utilization
 More responsive visual feedback
 Accurate representation of audio peaks
 Consistent with professional audio software

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-18 15:15:16 +01:00
a157172e3d fix: resolve playback level monitoring closure issue
Fixed playback level meters staying at 0% by resolving React closure
issue in the monitoring loop - same pattern as the recording fix.

The Problem:
- monitorPlaybackLevels callback checked stale `isPlaying` state
- Animation loop would run once and never continue
- Dependency on isPlaying caused callback recreation on every state change

The Solution:
- Added isMonitoringLevelsRef to track state independent of React
- Removed isPlaying dependency from callback (now has empty deps [])
- Set ref to true when starting playback
- Set ref to false when pausing, stopping, or ending playback
- Animation loop checks ref instead of stale closure state

Monitoring State Management:
- Start: play() sets isMonitoringLevelsRef.current = true
- Stop: pause(), stop(), onended, and cleanup set it to false
- Loop: continues while ref is true, stops when false

This ensures the requestAnimationFrame loop runs continuously
during playback and calculates real-time RMS levels for all tracks.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-18 15:12:42 +01:00
6fbb677bd2 feat: implement real-time playback level monitoring for all tracks
Added comprehensive playback level monitoring system that shows
real-time audio levels during playback for each track.

useMultiTrackPlayer Hook:
- Added AnalyserNode for each track in audio graph
- Implemented RMS-based level calculation with requestAnimationFrame
- Added trackLevels state (Record<string, number>) tracking levels by track ID
- Insert analysers after effects chain, before master gain
- Monitor levels continuously during playback
- Clean up level monitoring on pause/stop

Audio Graph Chain:
source -> gain -> pan -> effects -> analyser -> master gain -> destination

AudioEditor Integration:
- Extract trackLevels from useMultiTrackPlayer hook
- Pass trackLevels down to TrackList component

TrackList & Track Components:
- Accept and forward trackLevels prop
- Pass playbackLevel to individual Track components
- Track component displays appropriate level:
  * Recording level (with "Input" label) when armed/recording
  * Playback level (with "Level" label) during normal playback

Visual Feedback:
- Color-coded meters: green -> yellow (70%) -> red (90%)
- Real-time percentage display
- Seamless switching between input and output modes

This completes Phase 8 (Recording) with full bidirectional level monitoring!

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-18 15:01:55 +01:00
cf0c37caa6 fix: resolve recording level meter monitoring closure issue
Fixed the input level meter staying at 0% during recording by:

Closure Issue Resolution:
- Added isMonitoringRef to track monitoring state independent of React state
- Removed state dependencies from monitorInputLevel callback
- Animation loop now checks ref instead of stale closure state

Changes:
- Set isMonitoringRef.current = true when starting recording
- Set isMonitoringRef.current = false when stopping/pausing recording
- Animation frame continues while ref is true, stops when false
- Proper cleanup in stopRecording, pauseRecording, and unmount effect

This ensures the requestAnimationFrame loop continues properly and
updates the RMS level calculation in real-time during recording.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-18 14:56:30 +01:00
c0ca4d7913 fix: migrate existing tracks to new 180px height from localStorage
Added migration logic to useMultiTrack hook:
- When loading tracks from localStorage, check if height < DEFAULT_TRACK_HEIGHT
- Automatically upgrade old heights (120px, 150px) to new default (180px)
- Preserves custom heights that are already >= 180px

This fixes the inline style issue where existing tracks had
style="height: 120px" that was cutting off the level meter.

After this update, refreshing the page will automatically upgrade
all existing tracks to the new height without losing any data.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-18 14:53:31 +01:00
fa397a1dfe fix: always show level meter and increase track height to 180px
Fixed layout issues with the level meter:

Track Height:
- Increased DEFAULT_TRACK_HEIGHT from 150px to 180px
- Ensures enough vertical space for all controls without clipping

Level Meter Display:
- Now always visible (not conditional on recording state)
- Shows "Input" with mic icon when track is armed or recording
- Shows "Level" with volume icon when not recording
- Displays appropriate level based on state

This prevents the meter from being cut off and provides consistent
visual feedback for all tracks. Future enhancement: show actual
playback output levels when not recording.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-18 14:51:26 +01:00
2775fdb517 fix: increase default track height to accommodate input meter
Increased DEFAULT_TRACK_HEIGHT from 120px to 150px to properly fit:
- Volume slider
- Pan slider
- Input level meter (when track is armed or recording)

This ensures all controls have adequate vertical spacing and the input
meter doesn't get cramped when it appears under the pan control.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-18 14:47:58 +01:00
f65dd0be7f feat: complete Phase 8.2 - integrate recording into multi-track UI
Completed the integration of recording functionality into the AudioEditor:

Recording Controls:
- Added global record button to PlaybackControls component
- Implemented track arming system (arm track before recording)
- Added visual feedback with pulsing red animations during recording
- Connected recording state from useRecording hook to UI

AudioEditor Integration:
- Added handleToggleRecordEnable for per-track record arming
- Added handleStartRecording with permission checks and toast notifications
- Added handleStopRecording to save recorded audio to track buffer
- Connected recording input level monitoring to track meters

TrackList Integration:
- Pass recording props (onToggleRecordEnable, recordingTrackId, recordingLevel)
- Individual tracks show input level meters when armed or recording
- Visual indicators for armed and actively recording tracks

This completes Phase 8 (Recording) implementation with:
 MediaRecorder API integration
 Input level monitoring with RMS calculation
 Per-track record arming
 Global record button
 Real-time visual feedback
 Permission handling
 Error handling with user notifications

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-18 14:44:15 +01:00
5e6c61d951 feat: implement Phase 8.1 - audio recording infrastructure
Added recording capabilities to the multi-track editor:
- useRecording hook with MediaRecorder API integration
- Audio input device enumeration and selection
- Microphone permission handling
- Input level monitoring with RMS calculation
- InputLevelMeter component with visual feedback
- Record-enable button per track with pulsing indicator
- Real-time input level display when recording

Recording infrastructure is complete. Next: integrate into AudioEditor
for global recording control and buffer storage.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-18 14:37:01 +01:00
166385d29a fix: drag-to-select now works reliably without Shift key
Fixed async state update issue where selections were being cleared
immediately after creation. The mouseUp handler now checks drag
distance directly instead of relying on async state, ensuring
selections persist correctly.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-18 14:28:09 +01:00
1dc0604635 feat: add intuitive drag-to-select on waveforms
Improved selection UX to match professional DAWs:
- Drag directly on waveform to create selections (no modifier keys needed)
- Click without dragging seeks playhead and clears selection
- 3-pixel drag threshold prevents accidental selections
- Fixed variable name conflict with existing file drag-and-drop feature

Users can now naturally drag across waveforms to select regions for
editing, providing a more intuitive workflow.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-18 14:25:49 +01:00
74879a42cf feat: implement multi-track waveform selection and editing with undo/redo
Added comprehensive selection and editing capabilities to multi-track editor:
- Visual selection overlay with Shift+drag interaction on waveforms
- Multi-track edit commands (cut, copy, paste, delete, duplicate)
- Full keyboard shortcut support (Ctrl+X/C/V/D, Delete, Ctrl+Z/Y)
- Complete undo/redo integration via command pattern
- Per-track selection state with localStorage persistence
- Audio buffer manipulation utilities (extract, insert, delete, duplicate segments)
- Toast notifications for all edit operations
- Red playhead to distinguish from blue selection overlay

All edit operations are fully undoable and integrated with the existing
history manager system.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-18 13:05:05 +01:00
beb7085c89 feat: complete Phase 7.4 - real-time track effects system
Implemented comprehensive real-time effect processing for multi-track audio:

Core Features:
- Per-track effect chains with drag-and-drop reordering
- Effect bypass/enable toggle per effect
- Real-time parameter updates (filters, dynamics, time-based, distortion, bitcrusher, pitch, timestretch)
- Add/remove effects during playback without interruption
- Effect chain persistence via localStorage
- Automatic playback stop when tracks are deleted

Technical Implementation:
- Effect processor with dry/wet routing for bypass functionality
- Real-time effect parameter updates using AudioParam setValueAtTime
- Structure change detection for add/remove/reorder operations
- Stale closure fix using refs for latest track state
- ScriptProcessorNode for bitcrusher, pitch shifter, and time stretch
- Dual-tap delay line for pitch shifting
- Overlap-add synthesis for time stretching

UI Components:
- EffectBrowser dialog with categorized effects
- EffectDevice component with parameter controls
- EffectParameters for all 19 real-time effect types
- Device rack with horizontal scrolling (Ableton-style)

Removed offline-only effects (normalize, fadeIn, fadeOut, reverse) as they don't fit the real-time processing model.

Completed all items in Phase 7.4:
- [x] Per-track effect chain
- [x] Effect rack UI
- [x] Effect bypass per track
- [x] Real-time effect processing during playback
- [x] Add/remove effects during playback
- [x] Real-time parameter updates
- [x] Effect chain persistence

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-18 12:08:33 +01:00
cbcd38b1ed refactor: remove master effects section, add TODO note
Removed the master effects section from AudioEditor footer:
- Simplified footer to only show transport controls
- Removed master channel strip area
- Removed border separator between sections

Added note to PLAN.md:
- 🔲 Master channel effects (TODO)
- Will implement master effect chain UI later
- Similar to per-track effects but for final mix
- Documented in Phase 7 multi-track features section

This cleans up the UI for now - we'll add master effects
with a proper device rack UI later, similar to how per-track
effects work (collapsible section with horizontal device cards).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-18 08:43:38 +01:00
ecb5152d21 feat: boost light theme to true neon intensity
Cranked up the neon vibes in light theme to match dark theme energy!

Light Theme Neon Boost:
- Bright cyan-tinted backgrounds (180-200° hue)
- Vivid magenta primary (0.28 chroma - max intensity!)
- Rich magenta/purple foreground (20% lightness, 0.12 chroma)
- Electric cyan accent (90% lightness, 0.12 chroma, 180° hue)
- Saturated borders (0.08 chroma)
- Neon cyan waveforms (60% lightness, 0.26 chroma)
- Magenta progress bars (58% lightness, 0.28 chroma)

Color Intensity Increased:
- Primary: 0.28 chroma (was 0.22 - 27% boost!)
- Foreground: 0.12 chroma (was 0.05 - 140% boost!)
- Accent: 0.12-0.18 chroma (was 0.05-0.10 - doubled!)
- Borders: 0.08 chroma (was 0.03 - nearly tripled!)
- Waveforms: 0.26-0.28 chroma (was 0.22 - 20% boost!)

Hue Shift:
- Cyan dominance (180-200° backgrounds)
- Magenta accents (300-320° primaries/foregrounds)
- Electric color combinations throughout

Now both themes have matching neon energy:
- Dark: Neon cyberpunk (purple/cyan/magenta)
- Light: Bright neon pop (cyan/magenta/purple)

Both themes now pop with vibrant, eye-catching colors! 

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-18 08:40:38 +01:00
bc7158dbe0 feat: vibrant neon color palette for both themes
Replaced gentle grays with eye-catching neon/vibrant colors!

Dark Theme - Neon Cyberpunk:
- Deep purple/blue backgrounds (265-290° hue)
- Bright neon magenta primary (75% lightness, 0.25 chroma, 310° hue)
- Neon cyan foreground (92% lightness, cyan tint)
- Vibrant borders with purple glow (30% lightness, 0.05 chroma)
- Electric accent colors throughout
- Neon cyan waveforms with magenta progress

Light Theme - Vibrant Pastels:
- Soft purple-tinted backgrounds (280-290° hue)
- Vivid magenta primary (55% lightness, 0.22 chroma)
- Rich purple foreground (25% lightness)
- Colorful borders and accents
- High saturation throughout (0.15-0.22 chroma)
- Vibrant purple/cyan waveforms

Color Intensity:
- Increased chroma from 0.14-0.15 to 0.20-0.25
- Much more saturated, punchy colors
- Vibrant accent colors (cyan, magenta, purple, green)
- Neon-style success (green), warning (yellow), destructive (red)

Hue Shifts:
- Purple/magenta theme (260-320° range)
- Cyan accents (180-200°)
- Warm warnings (80°)
- Green success (160°)

This gives a bold, modern, energetic aesthetic perfect
for a creative audio application - like FL Studio or
Ableton Live's colorful themes!

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-18 08:39:23 +01:00
ee24f04d76 feat: add automatic waveform repaint on theme change
Implemented MutationObserver to detect theme changes:

- Added themeKey state that increments on theme change
- MutationObserver watches document.documentElement for class changes
- Detects when "dark" class is toggled
- Added themeKey to waveform effect dependencies
- Canvas automatically redraws with new theme colors

How it works:
1. Observer listens for class attribute changes on <html>
2. When dark mode is toggled, themeKey increments
3. useEffect dependency triggers canvas redraw
4. getComputedStyle reads fresh --color-waveform-bg value
5. Waveform renders with correct theme background

Benefits:
- Seamless theme transitions
- Waveform colors always match current theme
- No manual refresh needed
- Automatic cleanup on unmount

Now switching between light/dark themes instantly updates
all waveform backgrounds with the correct theme colors!

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-18 08:36:49 +01:00
2a0d6cd673 fix: replace hardcoded colors with theme variables in Track component
Replaced hardcoded slate colors with theme-aware variables:

Track.tsx changes:
- Waveform area: bg-slate-900 → bg-waveform-bg
- Effects section: bg-slate-900/50 → bg-muted/50
- Expanded effects: bg-slate-900/30 → bg-muted/70
- Canvas background: rgb(15, 23, 42) → --color-waveform-bg

This ensures that:
- Light theme shows proper light gray backgrounds
- Dark theme shows proper dark gray backgrounds
- All components respect theme colors
- No more hardcoded colors that bypass the theme

Now the entire UI properly responds to theme changes with
the harmonized gray palettes we configured.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-18 08:34:14 +01:00
2948557e94 feat: soften light theme with gentler gray tones
Reduced contrast in light theme for softer, more comfortable appearance:

Background tones (darker, gentler):
- waveform-bg: 97% (was 99% - less bright)
- card: 96% (was 98% - softer)
- background: 93% (was 96% - more muted)
- muted: 90% (was 94% - darker)
- secondary/accent: 88% (was 92% - more visible)
- border: 85% (was 88% - stronger definition)
- input: 88% (was 92% - better contrast)

Foreground tones (lighter, softer):
- foreground: 28% (was 20% - less harsh)
- card-foreground: 28% (was 20% - softer)
- secondary-foreground: 32% (was 25% - lighter)
- muted-foreground: 48% (was 45% - easier to read)

Color adjustments:
- Reduced color intensity from 0.15 to 0.14
- Softer primary: oklch(58% 0.14 240)
- All colors slightly desaturated for gentler feel

Benefits:
- Reduced contrast reduces eye strain
- Softer, warmer appearance
- More comfortable for extended use
- Better balance between light and dark themes
- Modern low-contrast aesthetic
- Similar to Figma, Linear, or Notion's light modes

Both themes now have beautifully balanced, low-contrast
palettes that are easy on the eyes and professional.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-18 08:31:52 +01:00
0dfbdca00c feat: lighten dark theme for softer, gentler appearance
Significantly lightened all dark theme colors for reduced contrast:

Background tones (lighter, softer):
- waveform-bg: 16% (was 10% - too dark)
- background: 18% (was 12% - lifted significantly)
- card: 22% (was 15% - more visible)
- muted: 25% (was 18% - lighter)
- secondary: 28% (was 20% - softer)
- accent: 30% (was 22% - warmer)
- border: 32% (was 25% - more subtle)

Foreground tones (softer, less harsh):
- foreground: 78% (was 85% - reduced contrast)
- card-foreground: 78% (was 85% - softer)
- secondary-foreground: 75% (was 80% - gentler)
- muted-foreground: 58% (was 60% - slightly muted)

Color adjustments:
- Reduced color intensity (0.14 vs 0.15)
- Softer blue primary: oklch(68% 0.14 240)
- More muted accent colors throughout

Benefits:
- Much softer, gentler appearance
- Reduced contrast reduces eye strain
- More comfortable for long editing sessions
- Warmer, more inviting feel
- Modern low-contrast aesthetic
- Similar to VSCode's "Dark+" or Figma's dark mode

The theme now has a beautiful, soft low-contrast aesthetic
that's easy on the eyes while maintaining readability.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-18 08:30:24 +01:00
f74c8abbf9 feat: harmonize light theme with soft gray tones
Replaced harsh whites with a soft, professional light gray palette:

Light tones (lightest to darkest):
- waveform-bg: 99% - near-white for waveform area
- card: 98% - soft white for cards/panels
- background: 96% - main background (was 100% harsh white)
- muted: 94% - muted elements
- secondary/accent: 92% - secondary/accent elements
- input: 92% - input backgrounds
- border: 88% - borders and dividers

Dark tones (text, darker):
- foreground: 20% - main text (was 9.8% too dark)
- card-foreground: 20% - card text
- secondary-foreground: 25% - secondary text
- muted-foreground: 45% - muted text (lighter for better contrast)

Primary color:
- Changed to pleasant blue: oklch(55% 0.15 240)
- Matches dark theme primary color concept
- More modern than pure black

Benefits:
- Softer, more pleasant appearance
- Reduced eye strain in light mode
- Better harmony with dark mode
- Professional appearance like Figma, Linear, etc.
- Maintains excellent readability
- Consistent gray palette across both themes

Both light and dark themes now have harmonized gray palettes
that are easy on the eyes and professional-looking.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-18 08:28:23 +01:00
46ce75f3a5 feat: harmonize dark theme with softer gray tones
Replaced harsh white contrasts with a harmonized gray palette:

Background tones (darkest to lightest):
- waveform-bg: 10% - deepest black for waveform area
- background: 12% - main app background
- card: 15% - card/panel backgrounds
- muted: 18% - muted elements
- secondary: 20% - secondary elements
- accent: 22% - accent elements
- border: 25% - borders and dividers

Foreground tones (lighter, softer):
- foreground: 85% - main text (was 98% harsh white)
- card-foreground: 85% - card text
- secondary-foreground: 80% - secondary text
- muted-foreground: 60% - muted text

Primary color:
- Changed from white to blue: oklch(70% 0.15 240)
- More pleasant, less harsh than pure white
- Better visual hierarchy

Benefits:
- Reduced eye strain with softer contrasts
- More professional, cohesive appearance
- Better visual hierarchy
- Maintains readability while being easier on the eyes
- Harmonized gray scale throughout the interface

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-18 08:26:43 +01:00
439c14db87 feat: show effect chain in collapsed state and polish visual integration
Visual improvements:
- Effects section background now matches waveform (slate-900/50)
- More subtle border (border-border/50)
- Compact header (py-1.5 instead of py-2)
- Expanded area has darker background (slate-900/30) for depth

Collapsed state improvements:
- When collapsed, shows mini effect chips in the header
- Each chip shows effect name with visual state:
  - Enabled: primary color with border (blue/accent)
  - Disabled: muted with border
- Chips are scrollable horizontally if many effects
- Falls back to "Devices (count)" when no effects

Better integration:
- Background colors tie to waveform area
- Subtle hover effect on header (accent/30)
- Visual hierarchy: waveform -> effects blend together
- No more "abandoned" feeling - feels like part of the track

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-18 08:23:20 +01:00
25be7027f3 refactor: make effects section always visible with inline collapse toggle
- Removed "Devices" button from control panel
- Effects section now always present below each track
- Collapsible via chevron in the effects header itself
- Click header to expand/collapse the device rack
- "+" button in header to add effects (with stopPropagation)
- Each track has independent collapse state
- Hover effect on header for better UX

This matches the typical DAW layout where each track has its own
device section that can be individually collapsed/expanded.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-18 08:16:41 +01:00
b9ffbf28ef feat: move effects section to collapsible area below track waveform
Major UX improvement inspired by Ableton Live's device view:

- Effects section now appears below the waveform in the track lane
- Toggle button in control panel shows/hides the effects area
- Gives much more horizontal space for device rack
- Effects section spans full width of track (control panel + waveform)
- Clean separation between track controls and effects
- Header with device count, add button, and close button

Layout changes:
- Track structure changed from horizontal to vertical flex
- Top row contains control panel + waveform (fixed height)
- Bottom section contains collapsible effects area (when shown)
- Effects hidden by default, toggled via "Devices" button
- When collapsed, track doesn't show effects section

This provides a cleaner workflow where users can focus on mixing
when effects are hidden, then expand to full device view when needed.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-18 08:14:13 +01:00
a3fb8a564e fix: remove pan separator and make effects container full width
- Removed border-t border-border from devices section
- Added negative margin (-mx-3) and padding (px-3) to effects container
  to make it extend full width of the track control panel

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-18 08:11:20 +01:00
6bfc8d3cfe feat: implement horizontal device rack with collapsible effect cards
- Created EffectDevice component with expand/collapse state
- Each device shows name, type, enabled/disabled toggle, and remove button
- When expanded, devices show parameter details
- Replaced vertical effect list with horizontal scrolling rack
- Effects display in 192px wide cards with visual feedback
- Power button toggles effect enabled/disabled state
- Parameters display shown when expanded (controls coming soon)

This matches the Ableton Live/Bitwig workflow where effects are
arranged horizontally with collapsible UI for each device.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-18 08:09:49 +01:00
fa3588d619 fix: move useMemo before early return to fix React hooks order 2025-11-18 08:03:36 +01:00
cb396ddfd6 feat: add EffectBrowser dialog for adding effects to tracks
Created a beautiful effect browser dialog inspired by Ableton Live:

**EffectBrowser Component:**
- Modal dialog with search functionality
- Effects organized by category:
  - Dynamics (Compressor, Limiter, Gate)
  - Filters (Lowpass, Highpass, Bandpass, etc.)
  - Time-Based (Delay, Reverb, Chorus, Flanger, Phaser)
  - Distortion (Distortion, Bitcrusher)
  - Pitch & Time (Pitch Shifter, Time Stretch)
  - Utility (Normalize, Fade In/Out, Reverse)
- Grid layout with hover effects
- Real-time search filtering
- Click effect to add to track

**Integration:**
- "+" button in track strip opens EffectBrowser dialog
- Selecting an effect adds it to the track's effect chain
- Effects appear immediately in the Devices section
- Full enable/disable and remove functionality

**UX Flow:**
1. Click "+" in track Devices section
2. Browse or search for effect
3. Click effect to add it
4. Effect appears in Devices list
5. Toggle on/off with ●/○
6. Remove with × button

Effects are now fully manageable in the UI! Next: Apply them to audio.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-18 08:02:21 +01:00
25e843236d fix: add missing Plus icon import in Track component 2025-11-18 07:52:24 +01:00
4547446ced fix: improve devices section UX
- Remove border separator above Devices section for cleaner look
- Add "+" button next to Devices header to add new effects
- Button placement matches Ableton/Bitwig pattern
- TODO: Implement effect browser dialog when + is clicked

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-18 07:51:51 +01:00
f3f5b65e1e feat: implement Ableton Live-style DAW layout
Major UX refactor to match professional DAW workflows (Ableton/Bitwig):

**Layout Changes:**
- Removed sidebar completely
- Track actions moved to header toolbar (Add/Import/Clear All)
- Each track now shows its own devices/effects in the track strip
- Master section moved to bottom footer area
- Full-width waveform display

**Track Strip (left panel):**
- Track name (editable inline)
- Color indicator
- Collapse/Solo/Mute/Delete buttons
- Volume slider with percentage
- Pan slider with L/C/R indicator
- Collapsible "Devices" section showing track effects
  - Shows effect count in header
  - Each effect card shows: name, enable/disable toggle, remove button
  - Effects are colored based on enabled/disabled state
  - Click to expand/collapse devices section

**Master Section (bottom):**
- Transport controls (Play/Pause/Stop) with timeline
- Master volume control
- Master effects placeholder (to be implemented)

**Benefits:**
- True DAW experience like Ableton Live
- Each track is self-contained with its own effect chain
- No context switching between tabs
- Effects are always visible for each track
- More screen space for waveforms
- Professional mixer-style layout

Note: Effects are visible but not yet applied to audio - that's next!

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-18 07:46:27 +01:00
a8f2391400 refactor: improve UX with 2-tab sidebar layout (Option A)
Changed from confusing 3-tab layout to cleaner 2-tab design inspired by
professional DAWs like Ableton Live:

**Tracks Tab:**
- Track management actions (Add/Import/Clear)
- Track count with selected track indicator
- Contextual help text
- Selected track's effects shown below (when track is selected)
- Clear visual separation with border-top

**Master Tab:**
- Master channel description
- Master effects chain
- Preset management for master effects
- Clear that these apply to final mix

Benefits:
- Clear separation: track operations vs master operations
- Contextual: selecting a track shows its effects in same tab
- Less cognitive load than 3 tabs
- Follows DAW conventions (track strip vs master strip)
- Selected track name shown in status area

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-18 07:41:16 +01:00
f640f2f9d4 feat: implement per-track and master effect chains (Option 3)
Architecture:
- Each track now has its own effect chain stored in track.effectChain
- Separate master effect chain for the final mix output
- SidePanel has 3 tabs: Tracks, Track FX, Master FX

Changes:
- types/track.ts: Add effectChain field to Track interface
- lib/audio/track-utils.ts: Initialize effect chain when creating tracks
- lib/hooks/useMultiTrack.ts: Exclude effectChain from localStorage, recreate on load
- components/editor/AudioEditor.tsx:
  - Add master effect chain state using useEffectChain hook
  - Add handlers for per-track effect chain manipulation
  - Pass both track and master effect chains to SidePanel
- components/layout/SidePanel.tsx:
  - Update to 3-tab interface (Tracks | Track FX | Master FX)
  - Track FX tab shows effects for currently selected track
  - Master FX tab shows master bus effects with preset management
  - Different icons for track vs master effects tabs

Note: Effect processing in Web Audio API not yet implemented.
This commit sets up the data structures and UI.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-18 07:30:46 +01:00
2f8718626c feat: implement global volume and mute controls
- Add masterVolume state to AudioEditor (default 0.8)
- Pass masterVolume to useMultiTrackPlayer hook
- Create master gain node in audio graph
- Connect all tracks through master gain before destination
- Update master gain in real-time when volume changes
- Wire up PlaybackControls volume slider and mute button
- Clean up master gain node on unmount

Fixes global volume and mute controls not working in transport controls.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-18 07:20:29 +01:00
5817598c48 fix: playback position animation frame not updating
Fixed issue where currentTime wasn't updating during playback:
- Removed 'isPlaying' from updatePlaybackPosition dependencies
- This was causing the RAF loop to stop when state changed
- Now animation frame continues running throughout playback
- Playhead now updates smoothly in waveform and timeline slider

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-18 07:16:07 +01:00
c6b9cb9af6 fix: improve spacebar shortcut to ignore buttons
Updated spacebar handler to skip when focus is on:
- Input fields
- Textareas
- Buttons (HTMLButtonElement)
- Elements with role="button"

This prevents spacebar from triggering play/pause when clicking
playback control buttons or other UI controls.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-18 07:14:10 +01:00