/** Звук эффекта «Луч света» (`public/luch_sveta.mp3`). */ const SUNBEAM_SFX_VOLUME = 0.88; /** Воспроизведение на 50% быстрее → реальная длительность = файл / 1.5. */ export const SUNBEAM_PLAYBACK_RATE = 1.5; const DEFAULT_SUNBEAM_LIFE_MS = 600; export function sunbeamEffectSoundUrl(): string { return new URL('luch_sveta.mp3', window.location.href).href; } let cachedSunbeamSfxDurationMs: number | null = null; /** Длительность файла в мс (как в метаданных, без ускорения). */ export function getSunbeamSfxDurationMs(): Promise { if (cachedSunbeamSfxDurationMs !== null) { return Promise.resolve(cachedSunbeamSfxDurationMs); } const url = sunbeamEffectSoundUrl(); return new Promise((resolve) => { const a = new Audio(); const done = (ms: number): void => { cachedSunbeamSfxDurationMs = ms; a.removeAttribute('src'); resolve(ms); }; a.addEventListener('loadedmetadata', () => { const d = a.duration; done(Number.isFinite(d) && d > 0 ? Math.round(d * 1000) : DEFAULT_SUNBEAM_LIFE_MS); }); a.addEventListener('error', () => done(DEFAULT_SUNBEAM_LIFE_MS)); a.src = url; a.load(); }); } /** * Длительность визуала луча = время проигрывания при ускорении 1.5× (совпадает со звуком). */ export async function getSunbeamEffectLifeMs(): Promise { const raw = await getSunbeamSfxDurationMs(); const wallMs = raw / SUNBEAM_PLAYBACK_RATE; return Math.min(60_000, Math.max(400, Math.round(wallMs))); } export function playSunbeamEffectSound(): void { try { const el = new Audio(sunbeamEffectSoundUrl()); el.volume = SUNBEAM_SFX_VOLUME; el.playbackRate = SUNBEAM_PLAYBACK_RATE; void el.play().catch(() => undefined); } catch { /* ignore */ } }