Commit Graph
100 Commits
Author SHA1 Message Date
vicrodh eee364e29c style(ui): genre popup extends left, 480px wide, 3 columns 2026-02-02 09:26:17 -06:00
vicrodh e61891bfc2 style(ui): widen genre filter popup to 420px with 4 columns 2026-02-02 09:25:04 -06:00
vicrodh 1b68b85402 style(ui): make genre filter cards smaller and more neutral
- Reduce card height from aspect-ratio to fixed 36px
- Use neutral bg-tertiary background instead of colored gradients
- Horizontal layout with name and check circle
- Selected state uses accent-primary
- Better spacing to prevent overlap
2026-02-02 09:24:37 -06:00
vicrodh d37b4ef7ff fix(ui): prevent infinite loop in GenreFilterButton
Use onMount instead of $effect to load genres once.
Add initialized flag to prevent onFilterChange from firing
during initial subscription setup, which was causing
loadHome -> re-render -> loadGenres -> notify -> loadHome loop.
2026-02-02 09:11:18 -06:00
vicrodh 733a12d702 fix(reco): fix migration for existing users without genre_id column
Remove genre_id from base schema and let migration add it.
This ensures existing databases don't fail when trying to create
index on non-existent column during initial schema execution.
2026-02-02 09:07:47 -06:00
vicrodh 8428fafaa5 feat(home): integrate genre filter into HomeView
- Add GenreFilterButton to home header
- Pass genre_id to fetchFeaturedAlbums API calls
- Reload home content when genre filter changes
- Featured sections now filter by selected genre
2026-02-02 08:53:13 -06:00
vicrodh 0d0da7c5fc feat(ui): add genre filter store and components
- Add genreFilterStore.ts with localStorage persistence
- Add GenreFilterButton.svelte for filter trigger
- Add GenreFilterPopup.svelte with colored genre cards
- Support "Remember my selection" toggle
- Single-genre selection (API limitation)
2026-02-02 08:51:37 -06:00
vicrodh d0dd42db65 feat(reco): add genre backfill commands
- Add reco_backfill_genres command to populate genre_id for existing events
- Add reco_needs_genre_backfill command to check if backfill is needed
- Fetches album details from Qobuz API and updates events in batches
- Includes rate limiting to avoid API throttling
2026-02-02 08:49:02 -06:00
vicrodh b4d7f7f4c3 feat(reco): add genre_id to reco_store schema
- Add genre_id column to reco_events table
- Add migration to add column to existing databases
- Update RecoEventInput and RecoEventRecord structs
- Update insert_event and get_events_since to handle genre_id
- Add get_album_ids_without_genre() for backfill
- Add update_genre_for_album() for backfill
2026-02-02 08:47:43 -06:00
vicrodh c2d61b46dc feat(api): add genre_id filter to get_featured_albums
- Add optional genre_id parameter to client method
- Add optional genre_id parameter to Tauri command
- Qobuz API filters featured albums by genre when provided
2026-02-02 08:45:44 -06:00
vicrodh 8e31717908 feat(api): add genre list endpoint
- Add GENRE_LIST endpoint constant
- Add GenreInfo model with id, name, color, slug, path
- Add get_genres() method to client
- Add get_genres Tauri command
2026-02-02 08:44:42 -06:00
vicrodh b6c723d3df fix(search): use 4-quadrant collage for playlist cards 2026-02-02 08:11:48 -06:00
vicrodh de0b820230 fix(search): use standard menu styles for playlist card dropdown 2026-02-02 08:09:17 -06:00
vicrodh d27ae32aee feat(search): wire up playlist handlers in main page
- Add playPlaylistById to set queue and play first track
- Add queuePlaylistNextById to add playlist tracks next
- Add queuePlaylistLaterById to add playlist tracks later
- Add copyPlaylistToLibraryById using subscribe_playlist
- Add sharePlaylistQobuzLinkById to copy link to clipboard
- Connect all handlers to SearchView component
2026-02-02 08:06:27 -06:00
vicrodh 61dd071326 feat(search): integrate playlists into search page
- Add playlists to unified search results (SearchAllResults)
- Add dedicated Playlists tab in jump-nav
- Create SearchPlaylistCard with album-like overlay (heart/play/menu)
- Add playlist menu: Play next, Add to queue, Copy to library, Share
- Add offset parameter to search_playlists command
- Add PlaylistGenre and extra fields to Playlist model
- Update searchState with Playlist type and playlistResults

UI changes:
- Remove glyphs from search tabs
- Reduce tab spacing (gap 8px→4px, padding 16px→12px)
- Reduce filter font size (13px→12px)
2026-02-02 07:57:16 -06:00
vicrodh f6d2a6bddd feat(immersive): default to coverflow view when opening immersive mode 2026-02-01 19:43:55 -06:00
vicrodh 2431a66545 refactor(settings): move limit quality toggle below streaming quality
- Repositioned toggle to appear right after Streaming Quality dropdown
- Updated description to clarify it overrides quality setting when device
  doesn't support the selected sample rate
2026-02-01 19:40:19 -06:00
vicrodh 39e8814848 feat(settings): add limit quality to device toggle and max sample rate tracking
Frontend changes for quality limiting feature:
- Add limitQualityToDevice state and handler
- Add AudioSettings interface fields for limit_quality_to_device and device_max_sample_rate
- Update handleBackendDeviceChange to send max_sample_rate when device changes
- Update handleOutputDeviceChange to find max_sample_rate from backend devices
- Add Settings UI toggle for "Limit Quality to Device"

This completes the quality limiting feature that prevents requesting tracks
that exceed the device's sample rate capabilities, ensuring bit-perfect playback.
2026-02-01 19:29:15 -06:00
vicrodh 6d53907233 feat(audio): add quality limiting based on device capabilities
- Add limit_quality_to_device setting (enabled by default)
- Add device_max_sample_rate field to store selected device's max rate
- Implement limit_quality_for_device() to restrict quality based on device
- Apply quality limiting in play_track and prefetch_track commands
- Add set_audio_device_max_sample_rate Tauri command

This ensures bit-perfect playback by not requesting tracks that
exceed the device's sample rate capabilities. When enabled:
- Devices <= 48kHz: limited to Lossless (44.1kHz)
- Devices <= 96kHz: limited to HiRes (up to 96kHz)
- Devices > 96kHz: allow UltraHiRes (up to 192kHz)
2026-02-01 19:21:02 -06:00
vicrodh be4786e6d3 feat(settings): add limit_quality_to_device setting
Add new audio setting to limit streaming quality based on device
capabilities. When enabled (default: true), QBZ will avoid requesting
tracks that exceed the device's max supported sample rate.

This ensures bit-perfect playback by preventing the need to resample
high-res tracks on devices that don't support them.

- Add limit_quality_to_device field to AudioSettings
- Add database migration for new column
- Add Tauri command for frontend integration

cc
2026-02-01 19:15:11 -06:00
vicrodh da5ec2abcb feat(audio): implement controlled hw→plughw fallback for ALSA Direct
- Add AlsaDirectError enum for structured error classification
- Add BitPerfectMode enum to track runtime bit-perfect status
- Implement automatic fallback: hw fails with format error → try plughw
- Abort on non-recoverable errors (busy, permissions, invalid params)
- Respect ALSA plugin selection from UI settings
- Log runtime mode for debugging

This allows SMSL-class DACs that fail on hw: to work via plughw:
while maintaining bit-perfect guarantees (format conversion only,
no resampling).

cc
2026-02-01 19:13:11 -06:00
vicrodh 4670b1548a feat(audio): add S24_3LE format support for SMSL-class USB DACs
- Add S24_3LE (S243LE) to format priority list as first choice
- Implement S24_3LE write handler with 3-byte packed conversion
- Add S24LE write handler (was missing explicit implementation)
- Reorder format priority: S24_3LE > S32LE > S24LE > S16LE > FloatLE

This fixes bit-perfect playback on USB DACs that only support
the S24_3LE format (SMSL, Topping, Fosi with TAS1020B chip).

Closes #30

cc
2026-02-01 19:07:17 -06:00
vicrodh bb4fcfd6b8 Optimize visualizer: 16 bins mirrored, Material You colors
- Reduce FFT to 30fps with 16 bins (mirrored to 32 visual bars)
- Use 1024 FFT size for faster processing
- Extract dominant colors from album artwork
- Center artwork with track info and quality badge
- Bars render from edges inward with color gradient
2026-02-01 18:44:52 -06:00
vicrodh 4b74e1c490 Update visualizer track info: larger art, artist/album/track order
- Increase artwork to 108px (20% larger)
- Reorder info: Artist (bold) > Album (italic) > Track
- Add album prop to VisualizerPanel
- Adjust text styling hierarchy
2026-02-01 15:42:43 -06:00
vicrodh a46936da53 Move track info to bottom-right, text aligned left of artwork
- Position track info at bottom-right with margin
- Reduce artwork to 90x90px
- Text aligned right, to the left of artwork
- Compact layout that doesn't obstruct visualization
2026-02-01 15:40:48 -06:00
vicrodh 55c3e80bbc Switch to Canvas 2D wave visualizer for lower CPU usage
- Replace WebGL2 instanced bars with simple Canvas 2D waves
- Mirror wave from center (top + bottom)
- Quadratic bezier curves for smooth lines
- Gradient coloring: cyan -> blue -> purple
- Black #000000 background
- Much lighter than 128 WebGL instances
2026-02-01 15:38:44 -06:00
vicrodh 283d17b5b8 Use black background for visualizer view (skip ImmersiveBackground entirely) 2026-02-01 15:36:35 -06:00
vicrodh 587e204c7b Disable ambient background animation in visualizer view
Reduces CPU usage by disabling the WebGL ambient motion when
the visualizer tab is active - both are GPU intensive.
2026-02-01 15:35:31 -06:00
vicrodh 337d4866d6 Add Visualizer tab to Focus mode with mirror visualization
- Add 'visualizer' to FocusTab type
- Add Visualizer tab with Activity icon in ImmersiveHeader
- Update VisualizerPanel with mirror mode (bars up and down from center)
- Integrate VisualizerPanel in ImmersivePlayer focus view
- Three-color gradient: teal -> purple -> pink
- Track info overlay with artwork, title, artist
2026-02-01 15:33:47 -06:00
vicrodh 06d3de0d73 Add WebGL2 VisualizerPanel frontend component
- Instanced bar rendering with vertex/fragment shaders
- Receives binary frequency data via Tauri events
- R32F texture for efficient frequency data upload
- Cyan-to-magenta gradient coloring
- Auto-enables/disables backend when mounted/unmounted
- 64 frequency bars with logarithmic mapping from backend
2026-02-01 15:11:40 -06:00
vicrodh 7bc429744b Integrate visualizer with audio thread
- Add VisualizerTap to Player for sample capture
- Create wrap_source helper in audio thread
- Wrap all audio sources with TappedSource at 4 append points
- Player now captures samples for visualization when enabled
- Zero overhead when disabled (fast atomic check)

Audio samples flow: Source -> TappedSource -> RingBuffer -> FFT Thread -> Frontend
2026-02-01 15:10:51 -06:00
vicrodh b8cfcfb34a Add audio visualizer backend infrastructure
- Add spectrum-analyzer crate for FFT processing
- Create visualizer module with:
  - RingBuffer: lockless SPSC buffer for audio samples
  - FFT processor: dedicated thread for spectrum analysis
  - TappedSource: rodio Source wrapper for sample capture
  - VisualizerTap: shared state for audio thread integration
- Add Tauri commands: set_visualizer_enabled, is_visualizer_enabled
- Register visualizer in AppState and lib.rs

Backend compiles. Next: integrate with audio thread to capture samples.
2026-02-01 15:07:21 -06:00
vicrodh 5a93ac509d Fix volume spam: deduplicate set_volume calls in backend
- Skip setting volume if already at same value (0.001 tolerance)
- Skip logging when volume unchanged
- Prevents MPRIS/PipeWire feedback loop spam
2026-02-01 14:33:56 -06:00
vicrodh 43444951ba Hypersensitive sleeve parallax: ±120px H, ±35px V with power curve
- Doubled horizontal range to ±120px
- Doubled vertical range to ±35px
- Added power curve (0.7) for hypersensitivity near center
- Small mouse movements now produce dramatic response
2026-02-01 14:27:57 -06:00
vicrodh 33dc0ccafb Increase sleeve parallax range: 120px horizontal, 35px vertical 2026-02-01 14:26:16 -06:00
vicrodh 1a4fa3cc78 Remove all parallax from vinyl - only sleeve moves
- Vinyl stays perfectly centered, only rotates
- Removed X and Y parallax from vinyl position
- Removed parallax uniform from shader
- Only the cover art (sleeve) responds to mouse movement
2026-02-01 14:24:36 -06:00
vicrodh 2fe0efc3d4 Fix vinyl rotation: 33⅓ RPM, concentric, no Y-axis movement
- Set rotation speed to 33.333 RPM (0.0582 rad/frame at 60fps)
- Remove Y-axis parallax from vinyl position (stays centered)
- Remove Y parallax from shader for perfectly concentric rotation
- Add mipmaps and trilinear filtering for anti-aliasing
- Enable anisotropic filtering when available
2026-02-01 14:22:56 -06:00
vicrodh 81232457d1 Fix parallax values to prevent artifacts 2026-02-01 14:15:37 -06:00
vicrodh 68b863ea64 Extreme horizontal parallax and use PNG texture
- Use PNG instead of SVG for better WebGL compatibility
- Extreme horizontal parallax: cover 200px, vinyl 120px
- Reduced vertical parallax for subtle depth
- Shader parallax: 0.15 horizontal, 0.05 vertical
- Disc appears to slide out of sleeve with minimal mouse movement
2026-02-01 14:14:02 -06:00
vicrodh fc85d66f5c Fix VinylPanel: add padding and aggressive parallax
- Add padding around vinyl (scale UV by 1.15x)
- Discard pixels outside bounds to avoid edge artifacts
- Much more aggressive parallax: cover 80/50px, vinyl 50/35px
- Shader parallax offset increased to 0.08
- Vinyl size reduced to 85% for more breathing room
2026-02-01 14:10:55 -06:00
vicrodh 6265e685ea Update logo and regenerate all app icons
- Updated qbz-logo.svg and qbz-logo.png
- Added qbz-vinyl-v3.svg for VinylPanel
- Regenerated all Tauri icons from new logo
- Updated Android icons and favicon
2026-02-01 14:09:57 -06:00
vicrodh b068426e9f Rewrite VinylPanel with WebGL2 for performance
- Use WebGL2 canvas for vinyl rendering instead of CSS
- Load qbz-vinyl-v3.svg as texture
- Shader-based rotation when playing
- Parallax effect via uniforms (no DOM updates)
- Album cover slides left to reveal vinyl
- Much lower CPU usage than CSS animation
2026-02-01 14:08:57 -06:00
vicrodh 20b9aa2c86 Improve VinylPanel parallax sensitivity and alignment
- Double parallax sensitivity (30/20px cover, 18/12px disc)
- Cover and disc now vertically centered together
- Cover slides 15% left when playing to reveal disc
- Simplified transform calculations
2026-02-01 13:55:05 -06:00
vicrodh fcb81dad2b Fix VinylPanel layout and styling to match Figma design
- Correct z-ordering: cover in front (z-10), disc behind
- Cover slides left when playing to reveal disc
- Add mouse parallax effect for depth
- More visible grooves with alternating brightness
- Neutral gray colors instead of amber vintage
- Use system typography instead of Oswald
- Radial gradient on disc for realistic shading
2026-02-01 13:52:26 -06:00
vicrodh d79fdf58b6 Add Vinyl panel to Focus mode and fix MPRIS volume feedback loop
- Add VinylPanel.svelte with spinning vinyl disc animation
- Album cover slides left when playing to reveal disc
- CSS-based grooves (40 rings) and amber center label
- Vintage typography with "33 1/3 RPM" badge
- Add 'vinyl' as new Focus tab option in ImmersiveHeader
- Fix MPRIS/PipeWire volume feedback loop by checking if volume
  actually changed before calling setVolume
2026-02-01 13:51:19 -06:00
vicrodh 319150920b Enhance immersive ambient animation vibrancy and speed
- Increase animation speed to 1.8x for more dynamic movement
- Add per-channel histogram normalization to expand color range
- Boost saturation to 2.5x and brightness to 0.85
- Add 12% red channel boost for warmer tones
- Target color range 30-240 to lift shadows and preserve highlights
2026-02-01 13:42:41 -06:00
vicrodh d4cfd14fc6 fix(immersive): prevent black from dominating in B&W artwork
Problem: brightness(0.5) made whites gray while blacks stayed black,
causing dark areas to dominate even in mostly-white artwork.

Solution:
- Increased brightness from 0.5 to 0.7
- Added shadow lift: maps 0-255 to 25-255
- Black now becomes dark gray (~10% brightness floor)
- Whites remain visible and balanced

Result: 'Panda/cow' effect - both light and dark areas visible.
2026-02-01 13:32:52 -06:00
vicrodh edca4d0bec feat(immersive): dramatically increase ambient animation
New effects added:
- Layer rotation: each layer rotates slowly (1-2° range)
- Scale breathing: zoom levels pulse in/out per layer
- Pulsing vignette: edge darkening varies over time
- Increased drift amplitudes: far ±0.20, mid ±0.14, near ±0.08
- Stronger brightness breathing: ±12% (was ±8%)

All effects are decorrelated (different speeds/phases) for organic feel.
Default intensity now 1.0 for maximum visibility.
2026-02-01 13:28:48 -06:00
vicrodh cec7a799d5 feat(immersive): increase ambient animation visibility
Shader changes:
- Removed 0.5x time multiplier (was making motion too slow)
- Increased drift amplitudes ~3x (far: 0.15, mid: 0.10, near: 0.06)
- Faster drift speeds (~12-17 sec cycles instead of ~40-80 sec)
- Breathing effect doubled (0.08 vs 0.04)

Config changes:
- Default ambientIntensity: 0.8 (was 0.5)

Purpose: Keep pixels active (OLED), make motion perceptible
while maintaining ambient character (no sudden movements).
2026-02-01 13:25:47 -06:00
vicrodh 8bb38ccdda perf(lyrics): remove karaoke animation, plain white text only
Even GPU-accelerated animation was too expensive.
Immersive mode now uses simple bright white text with no animation.
2026-02-01 13:15:39 -06:00
vicrodh dbd706fc64 perf(lyrics): GPU-accelerated underline animation
Replace expensive properties with GPU-accelerated ones:
- transform: scaleX() instead of width (no layout recalc)
- Solid color instead of gradient
- Removed box-shadow blur (very expensive)
- Added will-change: transform hint

This runs entirely on GPU compositor thread.
2026-02-01 13:14:43 -06:00
vicrodh 06469aeaa3 fix(lyrics): use QBZ blue underline for karaoke effect
Revert to glowing underline approach with QBZ brand blue (#5281ff):
- Text stays bright white (no background-clip: text)
- Underline sweeps from left to right during line duration
- Blue glow effect with box-shadow
- Much better readability than gradient text
2026-02-01 13:13:36 -06:00
vicrodh fc382a2237 feat(lyrics): metallic shimmer effect for karaoke
Replace underline with metallic shimmer that sweeps across text:
- Mostly white (40% each side) with purple highlight band in center
- Gradient moves from right to left during line duration
- Uses ease-in-out for natural feel
- GPU-accelerated, single element, no JS polling
2026-02-01 13:11:01 -06:00
vicrodh c1a7a5977a fix(lyrics): use glowing underline instead of gradient text for karaoke
The background-clip: text technique made white appear gray.
New approach uses a pseudo-element underline that:
- Sweeps from left to right with the line duration
- Has purple glow effect (#a78bfa)
- Keeps text bright white and readable
- No impact on text color/brightness
2026-02-01 13:09:54 -06:00
vicrodh db2419fcb0 feat(lyrics): CSS-only karaoke animation for immersive mode
Replace JS-polled karaoke with pure CSS animation:
- Calculate line duration from timing data (timeMs)
- Use CSS animation with background-position sweep
- Animation runs once per line change, no polling needed
- Uses purple (#c4b5fd) to white gradient for visibility

Data flow: Pass full LyricsLine objects (with timeMs) through
component chain instead of stripping timing data.
2026-02-01 13:08:43 -06:00
vicrodh 562f73f350 perf(lyrics): reduce CPU usage in immersive mode by ~90%
Problem: Lyrics split view consumed more CPU than coverflow due to:
- Polling every 80-200ms for karaoke progress updates
- Inline styles on ALL ~50+ lines recalculated on every render
- Transitions tracked on all lines (4 properties each)

Solution:
1. lyricsStore: Add setProgressTrackingEnabled() to skip progress
   updates in immersive mode (only track line index changes)
2. LyricsLines: Use CSS classes for opacity instead of inline styles
   in immersive mode (distance-1, distance-2, distance-3, distance-far)
3. LyricsLines: Add CSS containment (contain: layout style) to isolate
   paint/layout recalculations
4. LyricsLines: Reduce transitions on non-active lines (2 vs 4 props)
5. ImmersivePlayer: Disable progress tracking on mount, re-enable on exit

Result: Immersive lyrics now updates only on line changes (~10-20/min)
instead of continuous progress updates (~300-750/min)
2026-02-01 13:04:13 -06:00
vicrodh f43ecb495f Add book-style collage and custom tooltip styles to SuggestionsPanel
- Book collage: 3 album covers with left/center/right positioning
- Rotated side covers (-12deg/+12deg) with hover animation
- Custom tooltip: opens bottom-right with high z-index (1000)
- Info trigger: 24px with dark background for visibility
- Fade-in animation for tooltip appearance
2026-02-01 12:55:52 -06:00
vicrodh c968beefa0 feat(immersive): merge History into Queue tab + add background transition
Queue/History:
- Removed History as separate tab from header
- Added History as sub-tab within QueuePanel
- Sub-tabs: Queue | History with counts
- Removed history-focus from focus mode tabs
- Removed keyboard shortcut 'H' and '5' for history

Background transition:
- Added 400ms crossfade when artwork changes
- Works for both WebGL and CSS fallback renderers
- Fades out, loads new texture, fades back in
2026-02-01 12:51:31 -06:00
vicrodh 780557efff fix(suggestions): remove book collage, fix badges and tooltip
- Removed book collage (playlist.images are same image at different sizes)
- Using medium quality image (images[1]) for playlist cards
- Fixed z-index on Qobuz/QBZ badges (z-index: 10, above overlay)
- Increased badge icons by 2pt (Qobuz: 22px, QBZ: 19px)
- Replaced native title tooltip with Tooltip component for radio info
2026-02-01 12:42:03 -06:00
vicrodh b20a2edf74 feat(suggestions): book-style collage for playlist cards
- Shows 3 covers like album spines when available
- Center cover fully visible, left/right at -15% offset
- Falls back to medium-quality single image if < 3 images
- Uses images[1] (medium) instead of images[0] (largest)
2026-02-01 12:33:04 -06:00
vicrodh 79672c4afb fix(suggestions): use highest quality playlist artwork
Changed from last (smallest) to first (largest) image in array
2026-02-01 12:30:35 -06:00
vicrodh 5c6ecc6a93 feat(immersive): implement Heavy Immersion shader
Three mandatory mechanisms for depth illusion:

1. Multi-scale texture sampling:
   - Far layer (0.7x zoom) - feels distant
   - Mid layer (0.9x zoom) - transition
   - Near layer (1.3x zoom) - feels close

2. Scale-dependent UV drift:
   - Far: slowest drift (0.03, 0.025)
   - Mid: medium drift (0.05, 0.04)
   - Near: fastest drift (0.07, 0.06)
   - Creates parallax-like depth perception

3. Spatial weighting:
   - Near layer dominant at screen center
   - Far layer dominant at screen edges
   - Mid layer fills the ring between
   - Vignette for additional depth

Result: Background feels spatially enveloping,
not like a zoomed/cropped image.
2026-02-01 12:21:03 -06:00
vicrodh dd0bd1e170 checkpoint: solid immersive baseline before heavy immersion upgrade
Working state:
- Atmospheric background (no recognizable artwork)
- Multi-sample blur in shader
- Gradient tint (cool top, warm bottom)
- Oswald font for lyrics (28px/30px)
- Lyrics panel 700px wide
- Text shadow for contrast
- Karaoke effect disabled in immersive

Ready for Heavy Immersion shader upgrade.
2026-02-01 12:19:52 -06:00
vicrodh 0f6c24f4f9 fix(lyrics): disable karaoke gradient in immersive, increase font +2pt
- Font size: 28px inactive, 30px active
- Disabled background-clip karaoke effect in immersive mode
- Active line now pure white (#ffffff)
- Past lines dimmed to 35% opacity
2026-02-01 12:06:18 -06:00
vicrodh 9d3f05025a fix(immersive): preserve blue colors and improve lyrics readability
Shader:
- Fixed luminance formula that was killing blue (30% blend instead of 100%)

Lyrics:
- Added Oswald font for immersive lyrics
- Increased font size by 2pt (26px inactive, 28px active)
- Active lines now pure white with higher weight for clarity
2026-02-01 11:58:47 -06:00
vicrodh 01adbb7ab4 feat(immersive): enhance shader and widen lyrics panel
Shader improvements:
- Multi-sample blur (4 corners averaged)
- Luminance preservation over saturation
- Gradient tint (cool top, warm bottom) for anti-flat look

Layout:
- Lyrics panel width increased from 560px to 700px (+140px)
- Responsive breakpoint adjusted (480px → 620px)
2026-02-01 11:50:16 -06:00
vicrodh 7535fdb8cc fix(lyrics): add text shadow for contrast against any background
Immersive lyrics now have dark shadow behind text for readability
on light/warm backgrounds like Powerslave's golden tones.
2026-02-01 11:43:41 -06:00
vicrodh 240ca09c6a fix(immersive): sample 90-100% of image for complete color representation
Rely on extreme blur to destroy details, not cropping.
This ensures all dominant colors (like blue sky) are captured.
2026-02-01 11:39:32 -06:00
vicrodh 8917049b00 fix(immersive): increase crop sample size for more relevant colors
Zoom factor changed from 1.5-3x to 1.1-1.6x
Now samples 62-90% of image instead of 33-66%
2026-02-01 11:34:36 -06:00
vicrodh 0bdd83dc08 fix(immersive): destroy artwork structure, preserve only mood
Implement proper atmospheric background pipeline:
- Random NON-CENTERED crop (150-300% zoom) to break composition
- Extreme blur at small size (destroys all semantic detail)
- Scale up with smoothing for additional blur
- Color adjustments (saturation 1.4x, brightness 0.5x)
- Vignette overlay

The background is now an unrecognizable color field derived from
artwork colors. Acceptance test: "Can I identify the album from
the background alone?" must be NO.

Applies to both WebGL and CSS fallback renderers.
2026-02-01 11:32:29 -06:00
vicrodh e4a108dc16 refactor(immersive): separate blur and motion concerns
- texture-loader.ts: Multi-pass blur (4×15px) at 256x256 for CSS-equivalent quality
- ambient.frag: Simplified to UV drift, zoom breathing, and color breathing only
- Blur computed ONCE at load time, shader only does motion effects
- No per-frame blur, image processing, or texture uploads
2026-02-01 11:24:24 -06:00
vicrodh b110516965 feat(immersive): increase source quality to 256x256
- Source canvas now 256x256 (was 64x64)
- Light pre-blur (8px), GPU shader does main blur
- Increased shader blur radius and samples (16 samples)
- Should produce much smoother results
2026-02-01 10:53:13 -06:00
vicrodh add1cf3cc0 feat(immersive): add GPU blur + noise distortion in shader
- Multi-sample blur: 12 samples in circular pattern
- Noise-based UV distortion to break up pixelation
- Random sample offsets for organic blur effect
- All blur computation is GPU-side (no CPU cost)
2026-02-01 10:50:14 -06:00
vicrodh 6fc1156b93 fix(immersive): match original blur quality with triple-pass blur
- Canvas size back to 64x64 (like original)
- Blur radius 20px applied 3 times (20 + 20 + 10 = ~50px total)
- Expanded canvas for blur overflow, then crop to final
- Brightness 0.55, saturation 1.3 (matching original)
2026-02-01 10:46:43 -06:00
vicrodh 7795fa159e fix(immersive): increase animation visibility + more blur + debug logs
- Animation params increased: 8% UV drift, 5% zoom, 12% brightness
- Canvas reduced to 8x8 for maximum blur effect
- Added debug logs to verify animation is running
2026-02-01 10:31:18 -06:00
vicrodh 606fb43853 fix(immersive): proper two-canvas blur technique + reduce to 15fps
Blur fix:
- Use three separate canvases (source, blur, final)
- Apply blur filter when drawing BETWEEN canvases (not to self)
- Canvas size reduced to 16x16 for extreme blur when scaled
- Double blur pass for extra smoothness

CPU fix:
- Reduce animation from 30fps to 15fps
- Slow ambient motion doesn't need high frame rate
2026-02-01 10:27:12 -06:00
vicrodh 3a93651122 fix(immersive): increase blur intensity for proper background effect
- Reduce canvas to 32x32 (was 128) for more natural scaling blur
- Apply triple-pass blur technique:
  1. Scale down (interpolation blur)
  2. Apply blur filter and redraw
  3. Third pass for extra smoothness
- Adjust brightness to 0.45 (darker) and saturation to 1.3
- Lower JPEG quality to 0.7 (blur hides artifacts anyway)
2026-02-01 10:19:11 -06:00
vicrodh 34710e92e1 feat(immersive): integrate WebGL2 renderer into ImmersiveBackground
- ImmersiveBackground now checks WebGL2 availability on mount
- Dynamically imports ImmersiveAmbientCanvas when WebGL2 available
- Falls back to CSS blur when WebGL2 unavailable
- New props: enableAmbient (default true), ambientIntensity

Automatic renderer selection:
1. Check BUILD_IMMERSIVE_ENABLED (compile-time)
2. Check isRuntimeEnabled() (user preference)
3. Check isWebGL2Available() (browser capability)
4. If all pass: use WebGL2 with ambient motion
5. Otherwise: use CSS fallback (original behavior)
2026-02-01 10:13:50 -06:00
vicrodh c94857fc87 feat(immersive): add Phase 3 ambient motion shader
- Add shaders/ambient.frag with:
  - UV drift (slow wandering motion)
  - Zoom oscillation (breathing effect)
  - Color breathing (subtle brightness pulsing)
  - Configurable intensity via u_intensity uniform

- Update ImmersiveAmbientCanvas.svelte:
  - Use ambient shader instead of static
  - Add animation loop with requestAnimationFrame
  - Frame throttling at 30fps for power efficiency
  - Visibility-aware: pauses when tab hidden
  - Props: enableMotion, intensity
  - Responds to enableMotion changes dynamically

All motion computation is GPU-side. No CPU per-frame work
except uniform updates (3 floats).
2026-02-01 10:12:09 -06:00
vicrodh 350352afb9 feat(immersive): add Phase 2 texture loader with pre-blur
- Add utils/texture-loader.ts with:
  - Async pre-blur generation using canvas 2D
  - Blur cache (max 20 entries)
  - Request cancellation for rapid track changes
  - Abort signal support throughout

- Update ImmersiveAmbientCanvas.svelte:
  - Use texture-loader for blurred artwork
  - Handle cancellation gracefully
  - Report texture metrics
  - Clean up pending loads on destroy

Pre-blur is computed once per track change (CPU), then uploaded
to GPU texture. No per-frame blur computation.
2026-02-01 10:10:44 -06:00
vicrodh 979326eeba feat(immersive): add Phase 1 minimal WebGL2 renderer
- Add utils/webgl-utils.ts with context creation, shader compilation,
  texture loading, and cleanup utilities
- Add shaders/fullscreen.vert for fullscreen quad rendering
- Add shaders/static.frag for basic texture display
- Add shaders/index.ts for Vite ?raw shader imports
- Add ImmersiveAmbientCanvas.svelte component with:
  - WebGL2 context management
  - Context loss/restore handling
  - Automatic resize handling
  - Performance metrics reporting
- Update app.d.ts with shader file type declarations

This is a static renderer only - no animation yet.
Phase 2 will connect to real artwork with pre-blur.
2026-02-01 10:09:13 -06:00
vicrodh 19d0916a46 feat(immersive): add Phase 0 infrastructure for WebGL2 rendering
- Create src/lib/immersive/ module structure
- Add types.ts with ImmersiveState, ImmersiveConfig interfaces
- Add config.ts with build-time and runtime feature flags
- Add ImmersiveRenderer.ts with lifecycle management and stores
- Add index.ts as public API boundary
- Add VITE_IMMERSIVE_ENABLED to vite.config.js
- Add app.d.ts for TypeScript env declarations

Build without immersive: QBZ_IMMERSIVE=false pnpm build

No visual changes yet - this is capability detection and guards only.
2026-02-01 10:05:12 -06:00
vicrodh 600a33026a feat(immersive): add infinite play button to player controls 2026-02-01 08:44:20 -06:00
vicrodh 520aaf8185 feat(immersive): add History tab to split and focus modes
- Create HistoryPanel component for viewing playback history
- Add 'history' tab to split mode tabs
- Add 'history-focus' tab to focus mode tabs
- Sync history when immersive mode opens (fix coverflow prev tracks)
- Keyboard shortcuts: H for history, 5 for history-focus
2026-02-01 08:37:16 -06:00
vicrodh e72901ac79 fix(coverflow): include history tracks for previous covers 2026-02-01 08:22:58 -06:00
vicrodh 4e8c2f5a9b fix(coverflow): reduce shadow and reflection intensity 2026-02-01 08:18:54 -06:00
vicrodh 9099f94904 feat(immersive): add real coverflow with queue navigation
- Rename old CoverflowPanel to StaticPanel (single artwork view)
- Create new CoverflowPanel with actual coverflow effect:
  - Shows 5 album covers (2 prev, current, 2 next)
  - 3D perspective rotation on side covers
  - Click on side covers to navigate queue
  - Smooth animation on track change
- Add 'static' tab to focus mode (4 tabs total)
- Update keyboard shortcuts: 1-4 for focus tabs
2026-02-01 08:18:17 -06:00
vicrodh 1aa7e9eb3a fix(immersive): center mode toggle and fix icon direction
- Move mode toggle inside tabs nav (centered)
- Icon now shows target mode, not current mode
- Add divider between toggle and tabs
2026-02-01 08:10:42 -06:00
vicrodh 2004a59660 feat(immersive): unify tab navigation with view mode toggle
Consolidates navigation into single bar with mode toggle:
- Split mode tabs: Lyrics, Track Info, Suggestions, Queue
- Focus mode tabs: Coverflow, Lyrics, Queue
- Mode toggle button (lotus/split-view icons)
- V key toggles view mode, 1-3 for focus tabs
2026-02-01 08:08:51 -06:00
vicrodh aea99a66d6 Hide lyrics scrollbar by default, show on hover 2026-02-01 08:01:20 -06:00
vicrodh 6d2ff56bf0 Fix lyrics auto-scroll by restoring height: 100% to panel-section 2026-02-01 07:59:55 -06:00
vicrodh 15bfad00b8 Add unmaximize permission for restore button 2026-02-01 07:55:30 -06:00
vicrodh 8cdb63912c Fix radio card, suggestions height, and lyrics auto-scroll
- Radio card: Remove queue buttons (radio replaces entire queue)
- Suggestions panel: Add max-height 80vh like other panels
- Lyrics: Revert overflow change that broke auto-scroll
- Lyrics: Apply scrollbar-on-hover to internal LyricsLines component
2026-02-01 07:53:54 -06:00
vicrodh ed5e7d13cf Fix radio glyph z-index on collage overlay 2026-02-01 07:50:24 -06:00
vicrodh 2c389408d0 Add maximize/restore/minimize buttons and QualityBadge placement
Window controls:
- Maximize button shows restore icon when maximized
- Add minimize button
- Button order: Fullscreen | Maximize/Restore | Minimize | Exit | Close

QualityBadge placement:
- Coverflow: below album name
- Split views (Lyrics/TrackInfo/Suggestions/Queue): below album name
- Added album name display in split view

Layout improvements:
- Panel section max-height 80vh
- Lyrics scrollbar only visible on hover
- Content vertically centered with artwork
2026-02-01 07:44:18 -06:00
vicrodh 730ce323c4 Exit fullscreen when leaving immersive mode, add maximize button
- Exit fullscreen automatically when closing immersive view
- Add maximize (window) button separate from fullscreen
- Button order: Fullscreen | Maximize | Exit Immersive | Close App
2026-02-01 07:30:03 -06:00
vicrodh 9502ca9013 Add fullscreen permissions and lighten immersive UI
- Add core:window:allow-set-fullscreen permission
- Add core:window:allow-is-fullscreen permission
- Lighten all buttons and tabs by ~20%
- Reduce background darkness from 0.6 to 0.5
- Increase border visibility
2026-02-01 07:28:03 -06:00
vicrodh e1cd13bd19 Add expandable window controls and fullscreen support
- Add expandable window controls in header (hover to expand)
  - Fullscreen toggle (F11)
  - Exit immersive (Esc)
  - Close app
- Move Repeat button to left group: Fav | Shuffle | Repeat
- Remove QualityBadge from player controls
- Add F11 keyboard shortcut for fullscreen toggle
- Use Tauri window API for fullscreen functionality
2026-02-01 07:22:03 -06:00
vicrodh df0cd9e1dd Simplify immersive player to use single compact controls
- Remove PlayerControlsMedium variant (unused)
- Keep only PlayerControlsCompact as the single player style
- Add QualityBadge above player controls
- Center play/pause button with balanced left/right groups
- Remove expand/compact toggle (no longer needed)
- Pass quality, bitDepth, samplingRate props from parent
2026-02-01 07:09:55 -06:00
vicrodh 62f2e3dffc feat(ui): show ALSA device descriptions in audio badge tooltip
Load ALSA device descriptions from backend and display fancy names
in the tooltip, with fallback to heuristic names when unavailable
2026-02-01 06:03:44 -06:00