Add iOS audio unlock banner to play page

Shows "Tap to enable audio on iOS" banner on iOS devices.
Hides automatically once audio is unlocked via button or play.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
b1rdmania
2025-12-29 16:41:15 +00:00
parent dc1126bdc8
commit 0b952424c3
2 changed files with 57 additions and 1 deletions
+28
View File
@@ -294,6 +294,28 @@
color: var(--gb-lightest);
}
/* iOS audio unlock banner */
.ios-audio-banner {
margin-top: calc(var(--spacing-unit) * 2);
padding: calc(var(--spacing-unit) * 2);
border-top: 2px solid var(--gb-light);
display: none; /* toggled by JS */
text-align: center;
}
.ios-audio-banner p {
font-size: 8px;
color: var(--gb-light);
margin: 0 0 calc(var(--spacing-unit)) 0;
line-height: 2;
}
.ios-audio-banner button {
background: var(--gb-lightest);
color: var(--gb-darkest);
border: var(--pixel-border) solid var(--gb-light);
padding: 12px 20px;
font-size: 10px;
}
/* Footer */
.footer {
margin-top: calc(var(--spacing-unit) * 4);
@@ -338,6 +360,12 @@
</div>
</div>
<!-- iOS Audio Unlock -->
<div id="iosAudioBanner" class="ios-audio-banner">
<p>Tap to enable audio on iOS</p>
<button id="enableAudioBtn" type="button">Enable Audio</button>
</div>
<!-- CTA -->
<div class="cta-link-inline">
<a id="generateOwn" href="/">Generate your own</a>
+29 -1
View File
@@ -1,7 +1,7 @@
import { MIDIService } from './services/MIDIService';
import { MIDIParser } from './midi/MIDIParser';
import { MotifEngine } from './core/MotifEngine';
import { unlockAudio } from './utils/audioUnlock';
import { unlockAudio, isAudioReady } from './utils/audioUnlock';
import type { NoteEvent } from './types';
function qs(id: string): HTMLElement {
@@ -140,6 +140,33 @@ async function main(): Promise<void> {
const currentTimeEl = qs('playCurrentTime') as HTMLElement;
const durationEl = qs('playDuration') as HTMLElement;
const timeRow = qs('playTimeRow') as HTMLElement;
const iosAudioBanner = qs('iosAudioBanner') as HTMLElement;
const enableAudioBtn = qs('enableAudioBtn') as HTMLButtonElement;
// Detect iOS/Safari for audio unlock banner
const isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent) ||
(navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1);
function updateIOSBanner(): void {
if (isIOS && !isAudioReady()) {
iosAudioBanner.style.display = 'block';
} else {
iosAudioBanner.style.display = 'none';
}
}
// Show banner on iOS if needed
updateIOSBanner();
// Handle enable audio button
enableAudioBtn.addEventListener('click', async () => {
try {
await unlockAudio();
updateIOSBanner();
} catch {
// ignore
}
});
const { midiUrl: u, title } = buildMidiUrlFromParams();
@@ -290,6 +317,7 @@ async function main(): Promise<void> {
try {
// Wait for unlock to complete
await unlockPromise;
updateIOSBanner(); // Hide banner once audio is unlocked
// First play generates the artifact (deterministically from MIDI structure).
if (!isGenerated) {