develop #5

Merged
psk merged 32 commits from develop into master 2025-10-12 18:43:02 +00:00
Owner
No description provided.
psk added 32 commits 2025-10-12 18:42:45 +00:00
## Features

### Playlist System
- Add playlist support with auto-advance to next track
- Add playlist window with clickable track list (current track highlighted in green)
- Add "Load Folder" and "Load Multiple Files" buttons
- Playlist persists in config (files + current index)

### Auto-Load Music
- Rename auto_load_last_song → auto_load_last_music for clarity
- Auto-load now restores full playlist with position (not just single file)
- Falls back to single file if no playlist
- Update UI label to "Auto-Load Music" with detailed tooltip

### Drag & Drop
- Drop folder: Load all audio files as playlist (sorted alphabetically)
- Drop multiple files: Create playlist
- Drop single file: Load normally without playlist

### Visual Fixes
- Fix waveform ring seam in Orbit mode (average first/last waveform samples)
- Fix Lissajous corner viz seam (close loop by connecting last point to first)

### UI Improvements
- Make debug window movable (remove anchor, add default_pos)
- Add C key support for Spectrum mode (corner viz cycling)

## Technical Changes
- Add PlaylistResource to manage track list and current index
- Add playlist_files and playlist_current_index to AppConfig
- Add PlaylistEvent resource for UI track selection communication
- Add check_track_finished_system for auto-advance
- Enhance file_drag_drop_system to handle folders and multiple files
- Update init_music_state_from_config to restore playlists on startup

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

Co-Authored-By: Claude <noreply@anthropic.com>
Changes:
- Renamed "Loop" to "Repeat Track" throughout codebase
- Added "Repeat Playlist" feature (wraps to beginning when playlist ends)
- Added "Shuffle" feature with Fisher-Yates algorithm (X key shortcut)
- All features persist in config (global section)
- UI checkboxes show only when relevant (playlist loaded)
- Preset save/load includes all playback settings

Playback logic:
- repeat_track takes precedence over repeat_playlist
- shuffle immediately shuffles playlist when enabled
- repeat_playlist=false stops playback at end of playlist

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

Co-Authored-By: Claude <noreply@anthropic.com>
- Fix critical bug where preset load didn't update config resource, causing auto-save to overwrite loaded settings
- Implement native egui drag-and-drop for playlist reordering without third-party dependencies
- Split randomizer: "Randomize Effects" now saves to current mode overrides only, not global
- Add cursor auto-hide after 2s in fullscreen using Bevy 0.17.2 CursorOptions API
- Update documentation with playlist system, randomizer changes, and Linux dependencies
- Add Linux build/runtime dependency instructions for Debian/Arch distributions

All features validated with zero warnings from cargo check and clippy.

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

Co-Authored-By: Claude <noreply@anthropic.com>
- Reverted from Symphonia+CPAL to Rodio for audio playback (simpler, handles device config automatically)
- Implemented audio seeking via file reload + skip_duration
- Added progress indicator that shows on mouse movement and auto-hides after 2s
- Track playback position and duration using Instant timestamps
- Progress slider supports dragging to seek through audio
- Fixed slider width to fill container (600px frame, dynamic slider width)
- Removed duplicate unused AudioSource methods
- Fixed all clippy warnings

Known issues:
- Seeking blocks main thread (needs async optimization)

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

Co-Authored-By: Claude <noreply@anthropic.com>
Audio System:
- Implement non-blocking async audio loading with streaming playback
- Audio starts playing immediately with StreamingAudioSource
- Background thread loads full buffer for seeking (10s for 141MB)
- Position tracking works during streaming and after buffer load
- Pause/resume properly accumulates playback time
- Seeking updates timing correctly

Seeking Improvements:
- Add exponential speed ramping: 1x → 25x over 2 seconds of holding
- Hold threshold: 300ms tap = track change, >300ms = seek
- Speed formula: 1.0 + 24.0 * (progress^2) with 2s ramp time
- Works with arrow keys and media keys (Left/Right, Previous/Next)

UI Enhancements:
- Pulsing loading indicator when buffer loading (yellow text, sine wave)
- Progress slider only shows when seeking is ready
- Debug panel shows: buffer size (MB), load time (s), seeking status
- Fixed Peak metric position (moved out of seeking section)

Cursor Behavior:
- Auto-hide after 2 seconds in ALL modes (windowed + fullscreen)
- Mouse movement resets timer and shows cursor

Buffer Metrics:
- Track buffer size in MB and load time in seconds
- Display in debug panel with "Seeking: READY/LOADING..."
- Log: "Buffer loaded: X samples (Y MB) in Z.XXs - seeking now available"

Architecture:
- StreamingAudioSource<I>: Immediate playback with FFT capture
- BufferedAudioSource: Sample-accurate seeking from memory
- Dual position tracking: timing-based + buffer-based
- SeekHoldTracker: Tracks hold duration for ramping

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

Co-Authored-By: Claude <noreply@anthropic.com>
Seeking now starts at 10x speed and ramps exponentially to 50x over 2 seconds:
- Formula: 10.0 + 40.0 * (progress^2)
- At 0s hold: 10x speed
- At 2s hold: 50x speed (max)
- Provides faster initial seeking with aggressive acceleration

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

Co-Authored-By: Claude <noreply@anthropic.com>
Changed TilemapSettings.spectrum from [[f32; 4]; 16] to [Vec4; 16] to meet GPU's 16-byte stride requirement. Nested arrays caused encase to see 4-byte stride (individual floats) instead of 16-byte vec4 alignment, triggering validation errors.

Fixes two panics:
- "array stride must be a multiple of 16 (current stride: 4)"
- "Buffer structure size 304 [...] greater than min_binding_size 296"

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

Co-Authored-By: Claude <noreply@anthropic.com>
- Slimmed down TilemapConfig from 20+ settings to 7 essential controls:
  - Opacity, bass/mid/high sensitivity, beat flash, color mode, scroll speed
- Hardcoded optimal defaults in shader for best visual quality:
  - Brightness 1.3, saturation 1.9, logarithmic freq mapping
  - Bass boost 2.0x, treble boost 1.5x, tile blur 0.8
  - Proper HSL color conversion for vibrant rainbow mode
- Updated all save/load operations:
  - Preset save/load in input.rs (2 locations each)
  - Automatic save in audio.rs (save_config_periodically)
  - Exit save in audio.rs (save_config_on_exit)
  - Startup config load in visualization.rs
- Simplified UI controls to match reduced settings
- Updated documentation (CLAUDE.md, README.md, TODO.md):
  - Clarified tilemap is a background effect, not a separate mode
  - Updated config examples to show simplified structure
  - Marked tilemap implementation tasks as complete

All changes verified with cargo check and cargo clippy (zero warnings).

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

Co-Authored-By: Claude <noreply@anthropic.com>
**Package Update Fixes:**
- Updated rand API: gen_range → random_range, gen_bool → random_bool, thread_rng → rng
- Updated rodio 0.21 API:
  - Removed OutputStreamHandle (no longer exists)
  - Changed OutputStream::try_default() → OutputStreamBuilder::open_default_stream()
  - Changed Sink::try_new() → Sink::connect_new(stream.mixer())
  - Removed convert_samples() calls (Decoder outputs f32 directly)
  - Changed Source trait: current_frame_len() → current_span_len()
- Fixed large_enum_variant clippy warning: Boxed RodioAudioHandler in AudioSource::File

**Mute-While-Seeking Feature:**
- Added seeking state tracking to SeekHoldTracker (is_seeking, volume_before_seek)
- Keyboard seeking (arrow keys): Mutes when seeking starts, unmutes when key released
- Slider seeking: Mutes when drag starts, unmutes when drag stops
- Prevents audio artifacts during rapid seeking operations
- Volume automatically restored to previous level after seeking ends

All changes verified with cargo check and cargo clippy (zero errors, zero warnings).

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

Co-Authored-By: Claude <noreply@anthropic.com>
- Implement automatic switching from StreamingAudioSource to BufferedAudioSource on first seek
- Fix Symphonia decoder random access errors by using in-memory buffer for seeking
- Add pause-during-seek to eliminate audio artifacts (pause on seek start, resume on end)
- Consolidate randomization: remove redundant RandomizeMode, keep comprehensive RandomizeEffects
- RandomizeEffects now randomizes all mode-specific + global settings and saves as mode overrides
- Track playback state (was_playing_before_seek) to properly restore after seeking
- Add buffered source state tracking (using_buffered_source, buffer_position)
- Accurate position tracking for both streaming and buffered sources

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

Co-Authored-By: Claude <noreply@anthropic.com>
Presets now only contain visual/mode settings (spectrum, orbit, waveform, background, tilemap, global) and exclude system settings (window resolution, playlist paths, MSAA, UI state, etc).

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

Co-Authored-By: Claude <noreply@anthropic.com>
- Migrated from gizmos to meshes for the background entities spiral and
  galaxy
- aligned volume display with the rules for the progress bar
- Introduced "escape" menu, moved stuff there.
Major Features:
- Add WindowModeConfig enum with Windowed/BorderlessFullscreen/ExclusiveFullscreen modes
- Replace boolean fullscreen flag with proper window mode tracking
- Add desired_resolution field to SystemSettings for user preferences
- Implement dynamic resolution detection from primary monitor video modes
- F key now cycles through all three window modes (was toggle)

UI Improvements:
- Replace resolution slider with ComboBox (prevents glitchy live updates)
- Query available resolutions from monitor instead of hardcoded list
- Reorganize ESC menu for better workflow:
  * Exit/Close buttons moved to top row for easy access
  * Audio Source and Playback settings side-by-side in columns
  * Auto-load music setting moved to Playback section
  * Presets section moved up (after Audio/Playback)
  * Window & Rendering section follows Presets
  * Configuration section at bottom with UI toggles
- Make ESC menu movable for better UX
- Move randomize button to right after mode selector
- Consolidate randomize to include all mode settings + global overrides
- Standardize background color settings order (Color before Opacity)

Playlist Changes:
- Clear Playlist now stops playback and removes all tracks (was keep current)
- Remove unused clear_except_current method

Bug Fixes:
- Fix compilation for Bevy 0.17.2 window mode enums
- Use correct VideoModeSelection::Current for exclusive fullscreen
- Update window mode tracking to handle all three modes properly

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

Co-Authored-By: Claude <noreply@anthropic.com>
Add reset button directly under the randomize button in the sidebar
for quick access to reset current mode to default settings.

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

Co-Authored-By: Claude <noreply@anthropic.com>
Features:
- H key now opens a read-only keybind reference menu
- Menu is movable and positioned to the left of center
- Organized categories: Global, Audio, Visualization, Effects, Mode-Specific, Presets
- Color-coded key display (monospace font, light blue)
- Removed "Hide UI" toggle (H key repurposed)
- Added hint in Configuration section about H key

Menu Layout:
- Default position: Left of center (450px offset)
- Scrollable content with max height 600px
- Clean categorized layout with separators

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

Co-Authored-By: Claude <noreply@anthropic.com>
Sidebar changes:
- Move Load/Save preset buttons to sidebar, side-by-side with mode selector
- Left column: Visualization Mode selector
- Right column: Load (L) and Save (P) preset buttons
- Keeps randomize and reset buttons below as full-width

ESC menu changes:
- Remove Preset Management section (now in sidebar)
- Add Keybinds (H) button to Configuration section
- Improve button spacing with margins on all sides
- Make Exit button red (RGB: 180, 40, 40) for visual distinction
- Add proper spacing between Close and Exit buttons

This puts all frequently-used controls in the sidebar for quick access
while keeping system settings in the ESC menu.

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

Co-Authored-By: Claude <noreply@anthropic.com>
Keybind changes:
- H key now hides/shows UI (original behavior restored)
- Ctrl+H opens the keybind menu
- Updated all UI references (ESC menu button, keybind menu display)
- Added "Hide UI (H)" checkbox back to Configuration section

Sidebar improvements:
- Better button sizing for mode and preset controls
- Mode button: 140px wide (shows "Mode: Orbit" format)
- Preset buttons: 90px wide, stacked vertically
- Proper horizontal layout with spacing

ESC menu improvements:
- Larger buttons: Close (110x30), Exit (80x30)
- Red Exit button for visual distinction
- Fixed Exit button overlap with scrollbar (added right margin)
- Reduced excessive spacing (10px -> 8px between sections)

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

Co-Authored-By: Claude <noreply@anthropic.com>
Fixes the macOS crash where 8x MSAA is not supported on all devices.

Changes:
- Limit MSAA to 0, 2, 4 (removed 8x option)
- WebGPU spec guarantees 1x and 4x work on all platforms
- Updated validation to clamp invalid values (including 8x) to 4x
- Updated UI slider to only show Off, 2x, 4x
- Updated config comments to reflect new limits

This resolves the macOS validation error:
"Sample count 8 is not supported by format Rgba8UnormSrgb on this device"

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

Co-Authored-By: Claude <noreply@anthropic.com>
- Add smart resolution selection based on window mode in main.rs
  - Windowed: Uses last_resolution (user's window size)
  - BorderlessFullscreen/ExclusiveFullscreen: Uses desired_resolution (native)
- Add monitor resolution detection system in system_settings.rs
  - Detects logical vs physical pixels for HiDPI displays
  - Queries monitor native resolution from video modes
  - Updates config with detected resolutions automatically
  - Comprehensive logging for debugging compositor behavior
- Enhance debug overlay to show HiDPI scaling info
  - Displays logical resolution (what compositor reports)
  - Displays physical resolution (actual rendered pixels)
  - Shows scale factor when != 1.0
- Fix monitor selection: Primary → Current for better multi-monitor support

This ensures full-fidelity rendering on Linux across all window managers
and compositors (Hyprland, Sway, i3, KDE, GNOME, etc.) with proper HiDPI
scaling support. On Wayland with 1.5x scaling and 2880x1800 displays, the
app now correctly renders at native resolution while working with logical
coordinates from the compositor.

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

Co-Authored-By: Claude <noreply@anthropic.com>
UI Improvements:
- Document hold-to-seek in keybind menu (arrow keys seek when held)
- Make Settings menu movable (changed from anchored to default_pos)
- Add keyboard shortcuts to sidebar: "Streak (S)" and "Edge Spectrum (E)"
- Move playback controls to Playlist window (Repeat Track/Playlist, Shuffle mode)
- Update Settings menu to point users to Playlist window for playback settings

Documentation:
- Add build profiles section (dev/release/dist)
- Document diagnostics feature flag
- Add platform-specific MSAA limitation for macOS (only supports 1, 2, 4 samples)
- Update development workflow emphasizing cargo check/clippy
- Add justfile commands documentation

Assets:
- Reorganize presets: moved from assets/configs/ to assets/presets/
- Add new orbit presets: blue, cracked, washy, wizzy

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

Co-Authored-By: Claude <noreply@anthropic.com>
- Increase galaxy max count from 50 to 100
- Add soft alpha gradients to galaxy points for smoother glow at high intensities
- Fix spiral color modes (Energy shows frequency-based zones, Mono uses total energy)
- Fix galaxy color modes (Energy has smooth transitions, Mono uses total energy)
- Add spiral pattern count feature (1-7 patterns distributed in circular formation)
- Clean up completed TODO items

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

Co-Authored-By: Claude <noreply@anthropic.com>
Audio-Content-Based Galaxy Placement:
- Compute seed from audio buffer (samples every 10,000th sample)
- Same audio file produces identical galaxy positions across playthroughs
- Galaxies respawn when switching songs (seed change detection)
- File playback: deterministic (waits for buffer to load)
- Microphone input: random placement (no buffer available)

Preset System Fixes:
- Add spiral_pattern_count to preset load/save pipeline
- Update randomizer to include spiral_pattern_count (1-7 range)
- Update galaxy max count in randomizer from 50 to 100

Documentation Updates:
- Add "Adding New Settings/Parameters" section to CLAUDE.md
- 8-step checklist for adding any new setting
- Common mistakes and concrete examples
- Update Background Mode documentation with deterministic galaxy info

Implementation Details:
- AudioSeedResource tracks computed seed from audio buffer
- update_audio_seed_system computes seed when buffer loads
- check_galaxy_seed_change_system triggers respawn on seed change
- GalaxyStates tracks last_audio_seed to detect changes

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

Co-Authored-By: Claude <noreply@anthropic.com>
- Fix galaxy rotation freeze when UI hidden by removing Changed filter
- Add spiral_pattern_count to ResetToDefault handler for proper persistence
- Add spiral_pattern_scale field to config system with full preset support
- Replace galaxy Energy mode static colors with heat map gradient
- Ensure all visualizations respect global energy color settings:
  - Spiral patterns now use global energy color intensity
  - Galaxy sprites now use global energy color intensity
  - Corner visualizations (BeatPulse, FrequencyRings, Lissajous) support energy shift
  - Edge spectrum Rainbow mode applies global energy shift
- Update CLAUDE.md with critical guidelines for global energy color support

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

Co-Authored-By: Claude <noreply@anthropic.com>
Implement a comprehensive EQ system to replace the single freq_boost parameter with separate bass/mid/high frequency controls plus a master gain. This provides precise control over the audio visualization's frequency response similar to a DAW equalizer.

Key changes:
- Replace freq_boost with 4 EQ controls: bass_boost (0-5x), mid_boost (0-5x), high_boost (0-10x), master_gain (0-5x)
- Apply EQ multipliers directly to frequency band energies (20-250Hz, 250-2000Hz, 2000-20000Hz)
- Increase FFT size from 2048 to 4096 samples for better frequency resolution (~10.7 Hz per bin at 44.1kHz)
- Remove progressive frequency weighting from spectrum smoothing
- Add EQ fields to config system with per-mode override support
- Update all existing presets with new EQ fields (default 1.0 = unity gain)
- Add UI controls for all 4 EQ parameters
- Update randomizer to include EQ settings
- Remove obsolete freq_boost from all code paths

Higher high_boost ceiling (10x vs 5x) accommodates typical weak high frequency energy in music.

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

Co-Authored-By: Claude <noreply@anthropic.com>
**Major Changes:**
- Refactor config system from Option<T> to direct per-mode fields
  - Each mode now stores complete visual settings independently
  - Simplifies config structure and improves type safety
  - Add PartialEq for config comparison
- Add preset load modes (load all modes vs current only)
  - New PresetLoadMode enum in UI
  - Persisted in system settings
- Fix window mode startup crash
  - Always start in windowed mode, defer fullscreen application
  - Prevents "Unable to get monitor" crashes on some systems

**UX Improvements:**
- Remove file drag-and-drop support
  - Use O key for file loading only
  - Simplifies UI and reduces confusion with playlist drag
- Add playlist help to Ctrl+H keyboard shortcuts menu
  - Explains drag to reorder, drag out to remove
- Add song title indicator when loading tracks
  - Shows filename without extension for 2 seconds
- Add async file dialog system
  - Non-blocking file operations
  - Support for multiple dialog modes

**Other Changes:**
- Delete .cargo/config.toml (no longer needed)
- Add energy.toml preset
- Update trippy.toml preset with new config structure
- Update tilemap shader for improved rendering
- Update documentation (CLAUDE.md, README.md)
- Mark immediate TODO items as completed

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

Co-Authored-By: Claude <noreply@anthropic.com>
**Problem:**
On macOS, clicking the Browse button in the preset dialog would block
the main thread, even though using async file dialogs. The O key for
loading music worked fine with the same async mechanism.

**Root Cause:**
The preset dialog (egui window) remained open and rendering while
trying to spawn the native file dialog. On macOS, having an egui window
active while showing a native file dialog causes blocking, even with
async dialogs.

**Solution:**
1. Hide the preset dialog before spawning the Browse file dialog
2. Re-show the preset dialog after file selection completes
3. Handle cancel case to re-show dialog if user cancels file selection

This matches the behavior of the O key (no egui window interference)
and prevents the blocking issue on macOS fullscreen mode.

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

Co-Authored-By: Claude <noreply@anthropic.com>
**Problem**: Preset dialog's Browse button blocked main thread on macOS in
fullscreen mode. Root cause was egui dialog window staying open while spawning
native file dialog, causing macOS UI thread conflicts.

**Solution**: Removed preset dialog entirely and made L key work like O key
(direct async file dialog, non-blocking on all platforms).

**Changes**:
- Removed PresetLoadDialog struct, resource, and render system (ui.rs)
- Moved preset load mode toggles to system settings (config already had this)
- Added toggles to ESC menu (Playback & Presets column) next to music settings
- Updated sidebar with compact Load/Save preset buttons using direct file dialogs
- Changed L key to spawn file dialog directly (no intermediate dialog)
- Enhanced FileDialogMode::LoadPreset with full preset application logic
- Removed obsolete FileDialogMode::BrowsePreset and spawn_browse_preset()
- Removed unused UIButtonAction::LoadPreset and PresetLoadMode enum
- Updated poll_file_dialogs_system query to include all components needed for preset loading

**Result**: Preset loading now works consistently across all platforms (Windows,
macOS, Linux) in both windowed and fullscreen modes. Zero blocking, same UX as
music file loading.

Net: -232 lines of code

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

Co-Authored-By: Claude <noreply@anthropic.com>
Updated all buttons in ESC menu for visual consistency:

**Audio Source buttons**:
- 📂 Load File (O) - Load single audio file
- 📁 Load Folder - Load all audio files from folder
- 📑 Load Multiple Files - Select multiple audio files
- 🎤 Start Microphone (I) / 🔴 Stop Microphone (I) - Toggle mic input

**Preset buttons** (already added):
- 📁 Load (L) - Load preset file
- 💾 Save (P) - Save preset file

All buttons now have:
- Emoji icons for quick visual recognition
- Hover tooltips explaining their function
- Keyboard shortcuts in labels where applicable

This creates a cohesive, modern UI appearance across the settings menu
and sidebar, making it easier to identify button functions at a glance.

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

Co-Authored-By: Claude <noreply@anthropic.com>
psk merged commit bcbca8f460 into master 2025-10-12 18:43:02 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
public/soundy-bits!5
No description provided.