refactor: split soundtrack chapter and drive commands

This commit is contained in:
2026-09-04 15:43:41 +03:00
parent 5250a3174c
commit b427d101fa
9 changed files with 170 additions and 136 deletions

View File

@@ -14,6 +14,7 @@ import SiteNavigation from './SiteNavigation.vue';
import ToolkitGrid from './ToolkitGrid.vue';
import { useAdaptiveQuality } from '@/composables/useAdaptiveQuality';
import { useAudioEngine } from '@/composables/useAudioEngine';
import { useAudioIntent } from '@/composables/useAudioIntent';
import { useJourneySections } from '@/composables/useJourneySections';
import { useKeyboardNavigation } from '@/composables/useKeyboardNavigation';
import { useMotionPreferences } from '@/composables/useMotionPreferences';
@@ -21,7 +22,7 @@ import { assetUrl } from '@/content/asset-url';
import type { PortfolioContent, PublicAssetManifest, SectionId, SectionLayout } from '@/content/types';
import type { SceneHostState } from '@/composables/useSceneController';
import type { MotionPolicy } from '@/journey/motion-policy';
import type { SoundtrackSources } from '@/audio/types';
import type { AudioSourceVariant, SoundtrackSources } from '@/audio/types';
declare const __PORTFOLIO_TEST_BUILD__: boolean;
const TEST_BUILD = typeof __PORTFOLIO_TEST_BUILD__ !== 'undefined' && __PORTFOLIO_TEST_BUILD__;
@@ -65,43 +66,30 @@ const journeyBinding = useJourneySections(
computed(() => motion.policy.value.allowSceneRequest),
);
const journey = journeyBinding.snapshot;
const pendingAudioDestination = shallowRef<SectionId | null>(null);
let audioNavigationEpoch = -1;
watch(
[navigation.state, () => journey.value.activeSectionId],
([navigationState, activeSectionId]) => {
if (navigationState.epoch !== audioNavigationEpoch) {
audioNavigationEpoch = navigationState.epoch;
pendingAudioDestination.value = navigationState.source === 'passive-scroll'
? null
: navigationState.destinationId;
}
if (pendingAudioDestination.value === activeSectionId) {
pendingAudioDestination.value = null;
}
},
{ flush: 'sync', immediate: true },
);
const audioSectionId = computed(() => (
pendingAudioDestination.value ?? journey.value.activeSectionId
));
const audioIntent = useAudioIntent({
canonicalIds: canonicalSectionIds,
journey: journeyBinding,
navigation: navigation.state,
});
const variants = (
sources: { readonly opusAssetId: string; readonly mp3AssetId: string },
): readonly AudioSourceVariant[] => [
{ url: assetUrl(props.manifest, sources.opusAssetId), mediaType: 'audio/ogg' },
{ url: assetUrl(props.manifest, sources.mp3AssetId), mediaType: 'audio/mpeg' },
];
const soundtrackSources = computed<SoundtrackSources | null>(() => {
const soundtrack = props.content.soundtrack;
if (soundtrack === undefined) return null;
return {
intro: [
{ url: assetUrl(props.manifest, soundtrack.intro.opusAssetId), mediaType: 'audio/ogg' },
{ url: assetUrl(props.manifest, soundtrack.intro.mp3AssetId), mediaType: 'audio/mpeg' },
],
main: [
{ url: assetUrl(props.manifest, soundtrack.main.opusAssetId), mediaType: 'audio/ogg' },
{ url: assetUrl(props.manifest, soundtrack.main.mp3AssetId), mediaType: 'audio/mpeg' },
],
intro: variants(soundtrack.intro),
main: variants(soundtrack.main),
afterglow: variants(soundtrack.afterglow),
driveLift: variants(soundtrack.driveLift),
};
});
const audio = useAudioEngine({
activeSectionId: audioSectionId,
intensity: computed(() => journey.value.acceleration),
chapter: audioIntent.chapter,
drive: audioIntent.drive,
soundtrack: soundtrackSources,
volume: motion.volume,
setVolume: motion.setVolume,