feat(music): add silly cat bg music and toggle controls
This commit is contained in:
parent
193285dfc2
commit
e9367db479
3 changed files with 90 additions and 2 deletions
|
|
@ -8,7 +8,8 @@ meorw
|
||||||
- interactive 60fps canvas particle background
|
- interactive 60fps canvas particle background
|
||||||
- background pre-fetching for instant cats
|
- background pre-fetching for instant cats
|
||||||
- blob-based cross-origin cat downloads
|
- blob-based cross-origin cat downloads
|
||||||
- keyboard navigation (`←` / `→` / `space` / `c` / `d`)
|
- background music player (`silly cat.mp3`)
|
||||||
|
- keyboard navigation (`←` / `→` / `space` / `c` / `d` / `m`)
|
||||||
- cats
|
- cats
|
||||||
- cats
|
- cats
|
||||||
- did i mention cats
|
- did i mention cats
|
||||||
|
|
|
||||||
89
index.html
89
index.html
|
|
@ -248,15 +248,21 @@
|
||||||
<div class="controls">
|
<div class="controls">
|
||||||
<button id="prevBtn" class="btn" onclick="prevCat()" disabled>[← prev]</button>
|
<button id="prevBtn" class="btn" onclick="prevCat()" disabled>[← prev]</button>
|
||||||
<button id="nextBtn" class="btn btn-primary" onclick="nextCat()">[next →]</button>
|
<button id="nextBtn" class="btn btn-primary" onclick="nextCat()">[next →]</button>
|
||||||
|
<button id="musicBtn" class="btn" onclick="toggleMusic()" title="Toggle Background Music (M)">[♫ music: off]</button>
|
||||||
<button id="copyBtn" class="btn" onclick="copyUrl()">[copy url]</button>
|
<button id="copyBtn" class="btn" onclick="copyUrl()">[copy url]</button>
|
||||||
<button id="downloadBtn" class="btn" onclick="downloadCurrentCat()">[download]</button>
|
<button id="downloadBtn" class="btn" onclick="downloadCurrentCat()">[download]</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="shortcuts-hint">
|
<div class="shortcuts-hint">
|
||||||
<kbd>←</kbd> <kbd>→</kbd> <kbd>space</kbd> navigate • <kbd>c</kbd> copy • <kbd>d</kbd> download
|
<kbd>←</kbd> <kbd>→</kbd> <kbd>space</kbd> navigate • <kbd>c</kbd> copy • <kbd>d</kbd> download • <kbd>m</kbd> music
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
|
<audio id="bgMusic" loop preload="auto">
|
||||||
|
<source src="silly%20cat.mp3" type="audio/mpeg">
|
||||||
|
<source src="silly cat.mp3" type="audio/mpeg">
|
||||||
|
</audio>
|
||||||
|
|
||||||
<div id="toast" class="toast"></div>
|
<div id="toast" class="toast"></div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
@ -537,6 +543,83 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Background Music
|
||||||
|
const bgMusic = document.getElementById('bgMusic');
|
||||||
|
const musicBtn = document.getElementById('musicBtn');
|
||||||
|
let isMusicMuted = localStorage.getItem('katimages_music_muted') === 'true';
|
||||||
|
|
||||||
|
function updateMusicUI() {
|
||||||
|
if (!musicBtn || !bgMusic) return;
|
||||||
|
const isPaused = bgMusic.paused || bgMusic.muted;
|
||||||
|
musicBtn.textContent = isPaused ? '[♫ music: off]' : '[♫ music: on]';
|
||||||
|
musicBtn.title = isPaused ? 'Play Background Music (M)' : 'Pause Background Music (M)';
|
||||||
|
}
|
||||||
|
|
||||||
|
function playMusic() {
|
||||||
|
if (!bgMusic) return;
|
||||||
|
bgMusic.volume = 0.45;
|
||||||
|
bgMusic.muted = false;
|
||||||
|
const p = bgMusic.play();
|
||||||
|
if (p !== undefined) {
|
||||||
|
p.then(() => {
|
||||||
|
isMusicMuted = false;
|
||||||
|
localStorage.setItem('katimages_music_muted', 'false');
|
||||||
|
updateMusicUI();
|
||||||
|
}).catch(() => {
|
||||||
|
updateMusicUI();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function pauseMusic() {
|
||||||
|
if (!bgMusic) return;
|
||||||
|
bgMusic.pause();
|
||||||
|
isMusicMuted = true;
|
||||||
|
localStorage.setItem('katimages_music_muted', 'true');
|
||||||
|
updateMusicUI();
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleMusic() {
|
||||||
|
if (!bgMusic) return;
|
||||||
|
if (bgMusic.paused || bgMusic.muted) {
|
||||||
|
playMusic();
|
||||||
|
showToast('music playing');
|
||||||
|
} else {
|
||||||
|
pauseMusic();
|
||||||
|
showToast('music paused');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function initBackgroundMusic() {
|
||||||
|
if (!bgMusic) return;
|
||||||
|
bgMusic.volume = 0.45;
|
||||||
|
bgMusic.addEventListener('play', updateMusicUI);
|
||||||
|
bgMusic.addEventListener('pause', updateMusicUI);
|
||||||
|
updateMusicUI();
|
||||||
|
|
||||||
|
if (!isMusicMuted) {
|
||||||
|
const p = bgMusic.play();
|
||||||
|
if (p !== undefined) {
|
||||||
|
p.then(() => {
|
||||||
|
updateMusicUI();
|
||||||
|
}).catch(() => {
|
||||||
|
// Autoplay policy prevented playback, unlock on first user gesture
|
||||||
|
const unlockAudio = () => {
|
||||||
|
if (!isMusicMuted && bgMusic.paused) {
|
||||||
|
bgMusic.play().then(() => updateMusicUI()).catch(() => {});
|
||||||
|
}
|
||||||
|
window.removeEventListener('click', unlockAudio);
|
||||||
|
window.removeEventListener('keydown', unlockAudio);
|
||||||
|
window.removeEventListener('touchstart', unlockAudio);
|
||||||
|
};
|
||||||
|
window.addEventListener('click', unlockAudio, { once: true });
|
||||||
|
window.addEventListener('keydown', unlockAudio, { once: true });
|
||||||
|
window.addEventListener('touchstart', unlockAudio, { once: true });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Keyboard navigation
|
// Keyboard navigation
|
||||||
window.addEventListener('keydown', e => {
|
window.addEventListener('keydown', e => {
|
||||||
if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') return;
|
if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') return;
|
||||||
|
|
@ -551,6 +634,8 @@
|
||||||
copyUrl();
|
copyUrl();
|
||||||
} else if (e.key === 'd' || e.key === 'D') {
|
} else if (e.key === 'd' || e.key === 'D') {
|
||||||
downloadCurrentCat();
|
downloadCurrentCat();
|
||||||
|
} else if (e.key === 'm' || e.key === 'M') {
|
||||||
|
toggleMusic();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -559,9 +644,11 @@
|
||||||
window.prevCat = prevCat;
|
window.prevCat = prevCat;
|
||||||
window.copyUrl = copyUrl;
|
window.copyUrl = copyUrl;
|
||||||
window.downloadCurrentCat = downloadCurrentCat;
|
window.downloadCurrentCat = downloadCurrentCat;
|
||||||
|
window.toggleMusic = toggleMusic;
|
||||||
|
|
||||||
// Start
|
// Start
|
||||||
initInteractiveParticles();
|
initInteractiveParticles();
|
||||||
|
initBackgroundMusic();
|
||||||
nextCat();
|
nextCat();
|
||||||
prefetchCats(3);
|
prefetchCats(3);
|
||||||
})();
|
})();
|
||||||
|
|
|
||||||
BIN
silly cat.mp3
Normal file
BIN
silly cat.mp3
Normal file
Binary file not shown.
Loading…
Add table
Reference in a new issue