feat: integrate authored nightdrive soundtrack
This commit is contained in:
@@ -17,14 +17,19 @@ import { useAudioEngine } from '@/composables/useAudioEngine';
|
||||
import { useJourneySections } from '@/composables/useJourneySections';
|
||||
import { useKeyboardNavigation } from '@/composables/useKeyboardNavigation';
|
||||
import { useMotionPreferences } from '@/composables/useMotionPreferences';
|
||||
import type { PortfolioContent, SectionId, SectionLayout } from '@/content/types';
|
||||
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';
|
||||
|
||||
declare const __PORTFOLIO_TEST_BUILD__: boolean;
|
||||
const TEST_BUILD = typeof __PORTFOLIO_TEST_BUILD__ !== 'undefined' && __PORTFOLIO_TEST_BUILD__;
|
||||
|
||||
const props = defineProps<{ content: Readonly<PortfolioContent> }>();
|
||||
const props = defineProps<{
|
||||
content: Readonly<PortfolioContent>;
|
||||
manifest: Readonly<PublicAssetManifest>;
|
||||
}>();
|
||||
|
||||
const canonicalSectionIds = [
|
||||
'start', 'profile', 'experience', 'infrastructure', 'selected-builds', 'additional-work', 'toolkit', 'contact',
|
||||
@@ -59,8 +64,44 @@ const journey = useJourneySections(
|
||||
navigation.state,
|
||||
computed(() => motion.policy.value.allowSceneRequest),
|
||||
);
|
||||
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 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' },
|
||||
],
|
||||
};
|
||||
});
|
||||
const audio = useAudioEngine({
|
||||
activeSectionId: audioSectionId,
|
||||
intensity: computed(() => journey.value.acceleration),
|
||||
soundtrack: soundtrackSources,
|
||||
volume: motion.volume,
|
||||
setVolume: motion.setVolume,
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user