Add per-node scene music volume control
Author a music track and volume (0-100%) per story node; the runtime scales it to 0-1 and applies it without restarting the track when only the level changes. Adds migration 024, threads music_volume through the repository/runtime, and gives the node inspector a volume slider. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+8
-5
@@ -2,7 +2,7 @@
|
||||
// SFX. Zero dependencies. Browsers block autoplay until a user gesture, so music/SFX
|
||||
// are primed on the first pointer interaction.
|
||||
type Sfx = 'advance' | 'choice' | 'sting'
|
||||
const MUSIC_VOLUME = 0.5
|
||||
let baseVolume = 0.5 // authored scene volume (0-1); mute overrides to 0
|
||||
|
||||
let ctx: AudioContext | null = null
|
||||
function audioContext() {
|
||||
@@ -43,13 +43,16 @@ function fade(target: number, done?: () => void) {
|
||||
function startMusic() {
|
||||
if (!music || !currentUrl || muted) return
|
||||
const promise = music.play()
|
||||
if (promise) promise.then(() => { pending = false; fade(MUSIC_VOLUME) }).catch(() => { pending = true })
|
||||
if (promise) promise.then(() => { pending = false; fade(baseVolume) }).catch(() => { pending = true })
|
||||
}
|
||||
|
||||
export const audio = {
|
||||
// A null url inherits whatever is already playing; a new url crossfades to it.
|
||||
setMusic(url: string | null) {
|
||||
if (!music || url === currentUrl) return
|
||||
// The same url with a new volume just adjusts the level (no restart).
|
||||
setMusic(url: string | null, volume?: number) {
|
||||
if (!music) return
|
||||
if (volume !== undefined) baseVolume = Math.max(0, Math.min(1, volume))
|
||||
if (url === currentUrl) { if (volume !== undefined && currentUrl && !muted) fade(baseVolume); return }
|
||||
currentUrl = url
|
||||
if (!url) { fade(0, () => music.pause()); pending = false; return }
|
||||
music.src = url
|
||||
@@ -59,7 +62,7 @@ export const audio = {
|
||||
toggleMute() {
|
||||
muted = !muted
|
||||
if (muted) fade(0)
|
||||
else if (currentUrl) startMusic()
|
||||
else if (currentUrl) { if (music && music.paused) startMusic(); else fade(baseVolume) }
|
||||
return muted
|
||||
},
|
||||
isMuted() { return muted },
|
||||
|
||||
Reference in New Issue
Block a user