diff --git a/.gitignore b/.gitignore index b4cd019..821a199 100644 --- a/.gitignore +++ b/.gitignore @@ -35,6 +35,7 @@ # Local media (not part of the product) /music/ +/server/web/public/audio/featured-dark-house-2025.mp3 # Temp downloads *.crdownload diff --git a/server/web/public/audio/.gitkeep b/server/web/public/audio/.gitkeep index cbd1a8a..e06bb5d 100644 --- a/server/web/public/audio/.gitkeep +++ b/server/web/public/audio/.gitkeep @@ -1,2 +1,7 @@ -# Drop your looping ambient track here as ambient.mp3 (MP3 preferred; OGG/WAV also work). -# Enable background music in Settings → Sound & Haptics after adding the file. +# Background music for the dashboard ambient player. +# +# Featured (default): featured-dark-house-2025.mp3 (~57MB — gitignored; copy locally) +# Copy-Item "music/DARK HOUSE 2025 Deep Hypnotic Electronic Experience.mp3" ` +# "server/web/public/audio/featured-dark-house-2025.mp3" +# +# Legacy fallback: ambient.mp3 (smaller loops still work if you point AMBIENT_MUSIC_SRC at them). diff --git a/server/web/src/audio/ambientMusic.test.ts b/server/web/src/audio/ambientMusic.test.ts index 209b27c..918e71c 100644 --- a/server/web/src/audio/ambientMusic.test.ts +++ b/server/web/src/audio/ambientMusic.test.ts @@ -17,11 +17,16 @@ describe('ambientMusic prefs', () => { localStorage.clear(); }); - it('defaults music off and volume ~0.22', () => { - expect(loadBgmEnabled()).toBe(false); + it('defaults music on for first visit and volume ~0.22', () => { + expect(loadBgmEnabled()).toBe(true); expect(loadBgmVolume()).toBeCloseTo(0.22); }); + it('respects explicit opt-out', () => { + localStorage.setItem(BGM_STORAGE_KEY, '0'); + expect(loadBgmEnabled()).toBe(false); + }); + it('persists enabled flag', () => { const p = new AmbientMusicPlayer(); p.setEnabled(true); @@ -38,8 +43,8 @@ describe('ambientMusic prefs', () => { expect(localStorage.getItem(BGM_VOLUME_KEY)).toBe('0'); }); - it('points at public audio path', () => { - expect(AMBIENT_MUSIC_SRC).toBe('/audio/ambient.mp3'); + it('points at featured public audio path', () => { + expect(AMBIENT_MUSIC_SRC).toBe('/audio/featured-dark-house-2025.mp3'); }); it('ducks effective volume 30% while modal registered', () => { diff --git a/server/web/src/audio/ambientMusic.ts b/server/web/src/audio/ambientMusic.ts index 48f434e..569d703 100644 --- a/server/web/src/audio/ambientMusic.ts +++ b/server/web/src/audio/ambientMusic.ts @@ -1,11 +1,14 @@ /** - * Looping background music — drop your MP3 at public/audio/ambient.mp3 - * (MP3 preferred; OGG/WAV also work if you update AMBIENT_MUSIC_SRC). + * Looping background music — featured track at public/audio/featured-dark-house-2025.mp3 + * (copy from repo music/; legacy ambient.mp3 still valid if you change AMBIENT_MUSIC_SRC). */ export const BGM_STORAGE_KEY = 'aetherforge-bgm'; export const BGM_VOLUME_KEY = 'aetherforge-bgm-volume'; -/** Served from Vite public/ — place ambient.mp3 here before enabling in Settings. */ -export const AMBIENT_MUSIC_SRC = '/audio/ambient.mp3'; +/** Featured Command Deck landing track (gitignored when >15MB — copy locally from music/). */ +export const FEATURED_MUSIC_SRC = '/audio/featured-dark-house-2025.mp3'; +export const FEATURED_MUSIC_TITLE = 'Dark House 2025'; +/** Default looping source for the global ambient player. */ +export const AMBIENT_MUSIC_SRC = FEATURED_MUSIC_SRC; /** Route → playback multiplier (0–1). User volume × intensity = effective output. */ export const PAGE_AMBIENT_INTENSITY: Record = { @@ -40,9 +43,10 @@ export function resolvePageAmbientIntensity(pathname: string): number { export function loadBgmEnabled(): boolean { try { const v = localStorage.getItem(BGM_STORAGE_KEY); + if (v === null) return true; return v === '1'; } catch { - return false; + return true; } } diff --git a/server/web/src/components/GlobalMusicPlayer.tsx b/server/web/src/components/GlobalMusicPlayer.tsx index f532b25..dfb9d23 100644 --- a/server/web/src/components/GlobalMusicPlayer.tsx +++ b/server/web/src/components/GlobalMusicPlayer.tsx @@ -1,7 +1,7 @@ import { useEffect } from 'react'; import { useLocation } from 'react-router-dom'; import { useAmbientMusic } from '../context/AmbientMusicContext'; -import { resolvePageAmbientIntensity } from '../audio/ambientMusic'; +import { ambientMusicPlayer, FEATURED_MUSIC_TITLE, resolvePageAmbientIntensity } from '../audio/ambientMusic'; import './GlobalMusicPlayer.css'; export default function GlobalMusicPlayer() { @@ -14,13 +14,19 @@ export default function GlobalMusicPlayer() { setPageIntensity(routeIntensity); }, [routeIntensity, setPageIntensity]); + useEffect(() => { + const path = location.pathname.split('?')[0].replace(/\/$/, '') || '/'; + if (path === '/dashboard') void ambientMusicPlayer.tryPlay(); + }, [location.pathname]); + return (