feat: add opt-in procedural drive audio

This commit is contained in:
2026-09-02 05:22:13 +03:00
parent 190ac1ce62
commit 130ff2d8bb
9 changed files with 1155 additions and 3 deletions

View File

@@ -1,18 +1,30 @@
<script setup lang="ts">
import { computed } from 'vue';
import type { AudioUiState } from '@/audio/types';
import type { MotionPolicy, QualityTier } from '@/journey/motion-policy';
const props = defineProps<{
const props = withDefaults(defineProps<{
policy: MotionPolicy;
maximumQuality: QualityTier;
sceneStatus: string;
}>();
audioState?: AudioUiState;
audioMuted?: boolean;
audioVolume?: number;
}>(), {
audioState: () => ({ kind: 'idle' }),
audioMuted: false,
audioVolume: 0.4,
});
const emit = defineEmits<{
pause: [];
resume: [];
enable: [];
qualityChange: [quality: QualityTier];
audioStart: [];
audioResume: [];
audioMuteToggle: [];
audioVolumeChange: [volume: number];
}>();
const action = computed(() => {
@@ -45,11 +57,51 @@ const changeQuality = (event: Event): void => {
emit('qualityChange', value);
}
};
const changeVolume = (event: Event): void => {
emit('audioVolumeChange', Number((event.currentTarget as HTMLInputElement).value));
};
</script>
<template>
<div class="drive-controls">
<button v-if="action" type="button" @click="runAction">{{ action.label }}</button>
<div v-if="audioState.kind === 'idle'" class="drive-controls__audio-start">
<button type="button" @click="emit('audioStart')">START THE DRIVE</button>
<span>Enables the interactive soundtrack.</span>
</div>
<div v-else-if="audioState.kind === 'starting'" class="drive-controls__audio-start" aria-live="polite">
<button type="button" disabled>Starting drive…</button>
<span>Preparing the interactive soundtrack.</span>
</div>
<p v-else-if="audioState.kind === 'failed'" class="drive-controls__audio-status" role="status">
Audio unavailable. Continue without sound.
</p>
<div
v-else-if="audioState.kind === 'running' || audioState.kind === 'suspended'"
class="drive-controls__audio"
>
<button
v-if="audioState.kind === 'suspended' && audioState.resumeRequiresGesture"
type="button"
@click="emit('audioResume')"
>Resume sound</button>
<button type="button" @click="emit('audioMuteToggle')">
{{ audioMuted ? 'Unmute sound' : 'Mute sound' }}
</button>
<label>
<span>Sound volume</span>
<input
aria-label="Sound volume"
type="range"
min="0"
max="1"
step="0.05"
:value="audioVolume"
@input="changeVolume"
>
</label>
</div>
<label>
<span>Quality</span>
<select :value="maximumQuality" aria-label="Quality control" @change="changeQuality">