feat: coordinate adaptive audio intent

This commit is contained in:
2026-09-04 15:34:32 +03:00
parent 7632c8b9c0
commit 5250a3174c
6 changed files with 812 additions and 15 deletions

View File

@@ -1,25 +1,56 @@
import type { AudioJourneyState } from '@/audio/types';
import type { SectionId } from '@/content/types';
import type {
AudioJourneyState,
ChapterIntent,
DriveEnergySample,
MusicMood,
} from '@/audio/types';
const JOURNEY_MUSIC = Object.freeze({
start: { bias: 'open', entryPhrase: 0 },
profile: { bias: 'open', entryPhrase: 1 },
experience: { bias: 'shadow', entryPhrase: 2 },
infrastructure: { bias: 'shadow', entryPhrase: 3 },
'selected-builds': { bias: 'lift', entryPhrase: 4 },
'additional-work': { bias: 'lift', entryPhrase: 5 },
toolkit: { bias: 'resolve', entryPhrase: 6 },
contact: { bias: 'resolve', entryPhrase: 7 },
} as const);
start: { mood: 'open', entryPhrase: 0 },
profile: { mood: 'open', entryPhrase: 1 },
experience: { mood: 'shadow', entryPhrase: 2 },
infrastructure: { mood: 'shadow', entryPhrase: 3 },
'selected-builds': { mood: 'lift', entryPhrase: 4 },
'additional-work': { mood: 'lift', entryPhrase: 5 },
toolkit: { mood: 'resolve', entryPhrase: 6 },
contact: { mood: 'resolve', entryPhrase: 7 },
} as const satisfies Readonly<Record<
SectionId,
{ readonly mood: MusicMood; readonly entryPhrase: number }
>>);
export function resolveChapterIntent(
sectionId: SectionId,
generation = 0,
): ChapterIntent {
const chapter = JOURNEY_MUSIC[sectionId];
return Object.freeze({
sectionId,
mood: chapter.mood,
atStart: sectionId === 'start',
entryPhrase: chapter.entryPhrase,
generation: Math.max(0, Math.trunc(generation)),
});
}
export const DEFAULT_CHAPTER_INTENT = resolveChapterIntent('start');
export const DEFAULT_DRIVE_ENERGY = Object.freeze({
energy: 0,
source: 'idle',
} as const satisfies DriveEnergySample);
export function resolveJourneyMusicState(sectionId: string, intensity = 0): AudioJourneyState {
const chapter = Object.hasOwn(JOURNEY_MUSIC, sectionId)
? JOURNEY_MUSIC[sectionId as keyof typeof JOURNEY_MUSIC]
: JOURNEY_MUSIC.start;
const canonicalId = Object.hasOwn(JOURNEY_MUSIC, sectionId)
? sectionId as SectionId
: 'start';
const chapter = resolveChapterIntent(canonicalId);
const finiteIntensity = Number.isFinite(intensity) ? intensity : 0;
return Object.freeze({
...chapter,
atStart: sectionId === 'start',
intensity: Math.min(1, Math.max(0, finiteIntensity)),
bias: chapter.mood,
entryPhrase: chapter.entryPhrase,
});
}