Add featured Dark House track with default landing ambient playback
Some checks failed
CI Docker Mining Proof / Linux agent hashrate proof (push) Has been cancelled
Some checks failed
CI Docker Mining Proof / Linux agent hashrate proof (push) Has been cancelled
Wire featured-dark-house-2025.mp3 as the default ambient source, enable BGM for first-time visitors, and attempt autoplay on Command Deck with gesture-unlock fallback. The ~57MB MP3 stays gitignored; copy instructions are in public/audio/.gitkeep.
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -35,6 +35,7 @@
|
||||
|
||||
# Local media (not part of the product)
|
||||
/music/
|
||||
/server/web/public/audio/featured-dark-house-2025.mp3
|
||||
|
||||
# Temp downloads
|
||||
*.crdownload
|
||||
|
||||
@@ -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).
|
||||
|
||||
@@ -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', () => {
|
||||
|
||||
@@ -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<string, number> = {
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 (
|
||||
<div
|
||||
className={`global-music-player${isDim ? ' global-music-player--ambient-dim' : ''}`}
|
||||
data-sfx="off"
|
||||
data-ambient-intensity={pageIntensity.toFixed(2)}
|
||||
role="region"
|
||||
aria-label="Background music controls"
|
||||
aria-label={`Background music — ${FEATURED_MUSIC_TITLE}`}
|
||||
title={FEATURED_MUSIC_TITLE}
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
|
||||
@@ -63,6 +63,10 @@ export function AmbientMusicProvider({ children }: { children: React.ReactNode }
|
||||
return ambientMusicPlayer.subscribe(setPlaying);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (enabled) void ambientMusicPlayer.tryPlay();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
ambientMusicPlayer.setEnabled(enabled);
|
||||
ambientMusicPlayer.setVolume(volume);
|
||||
|
||||
@@ -21,7 +21,7 @@ import FleetRuntimePanel from '../components/Fleet/FleetRuntimePanel';
|
||||
import { AuditLogStrip } from '../components/Fleet/FleetOpsWidgets';
|
||||
import { useSound } from '../context/SoundContext';
|
||||
import { useAmbientMusic } from '../context/AmbientMusicContext';
|
||||
import { AMBIENT_MUSIC_SRC } from '../audio/ambientMusic';
|
||||
import { AMBIENT_MUSIC_SRC, FEATURED_MUSIC_TITLE } from '../audio/ambientMusic';
|
||||
import { useVisualEffects } from '../context/VisualEffectsContext';
|
||||
import {
|
||||
FORGE_SKIN_IDS,
|
||||
@@ -732,9 +732,9 @@ export default function SettingsPage() {
|
||||
<hr style={{ border: 'none', borderTop: '1px solid var(--border-dim)', margin: '1.25rem 0' }} />
|
||||
<h3 className="font-tech" style={{ fontSize: '0.85rem', marginBottom: '0.35rem' }}>Background music</h3>
|
||||
<p className="section-desc" style={{ marginBottom: '0.75rem' }}>
|
||||
Optional looping ambient track served from <code className="mono-sm">{AMBIENT_MUSIC_SRC}</code>. Use the
|
||||
mini player in the bottom-right corner on any page, or enable here. Defaults off — browsers block autoplay
|
||||
until you press play or toggle this on.
|
||||
Featured track <strong>{FEATURED_MUSIC_TITLE}</strong> served from{' '}
|
||||
<code className="mono-sm">{AMBIENT_MUSIC_SRC}</code>. On by default on Command Deck — browsers may still
|
||||
block autoplay until you click or press a key; use the mini player in the bottom-right or toggle here.
|
||||
</p>
|
||||
<div className="form-group checkbox-group">
|
||||
<label className="checkbox-label">
|
||||
|
||||
Reference in New Issue
Block a user