diff --git a/public/assets/MANIFEST.json b/public/assets/MANIFEST.json new file mode 100644 index 0000000..d59df3c --- /dev/null +++ b/public/assets/MANIFEST.json @@ -0,0 +1,112 @@ +{ + "generated": "2026-06-17", + "game": "Night Ninja: Twilight Voyage", + "root": "public/assets/", + "files": { + "logo.png": { + "kind": "wordmark", + "size": "216×54", + "source": "NNTV_ART (replaces broken PHASER logo)" + }, + "logo-nntv-compact.png": { + "kind": "wordmark", + "size": "216×54", + "source": "NNTV_ART" + }, + "logo-nntv-wordmark.png": { + "kind": "wordmark", + "size": "360×90", + "source": "NNTV_ART (scale 10)" + }, + "favicon-32.png": { + "kind": "icon", + "size": "32×32", + "source": "RABBIT_ART" + }, + "favicon-16.png": { + "kind": "icon", + "size": "32×32 (downscaled at display)", + "source": "RABBIT_ART" + }, + "../favicon.png": { + "kind": "icon", + "size": "32×32", + "source": "RABBIT_ART (replaces old favicon)" + }, + "scene-menu.png": { + "kind": "scene", + "size": "640×192", + "source": "SCENE_MENU (new)" + }, + "scene-story.png": { + "kind": "scene", + "size": "640×192", + "source": "SCENE_STORY (new)" + }, + "scene-guide.png": { + "kind": "scene", + "size": "640×192", + "source": "SCENE_GUIDE (new)" + }, + "scene-settings.png": { + "kind": "scene", + "size": "640×192", + "source": "SCENE_SETTINGS (new)" + }, + "poster.png": { + "kind": "key-art", + "size": "800×600", + "source": "composite of NNTV + scene + characters" + } + }, + "existing": { + "tiles": [ + "tile-empty", + "tile-wall", + "tile-goal", + "tile-lit", + "tile-warm", + "tile-mirror", + "tile-oneway", + "tile-door-gold", + "tile-door-silver", + "tile-door-copper" + ], + "icons": [ + "icon-key-gold", + "icon-key-silver", + "icon-key-copper", + "icon-stone" + ], + "characters": [ + "player-rabbit", + "princess-carrot", + "guard-tomato (static)", + "guard-blueberry (rotating)", + "guard-corn (blinking)", + "guard-eggplant (patrolling)", + "guard-lettuce (mirror)", + "guard-pumpkin (chaser)", + "guard-sniper", + "guard-suspicion-calm", + "guard-suspicion-alert", + "guard-suspicion-fire" + ], + "actScenes": [ + "scene-garden (L1-2)", + "scene-walls (L3-4)", + "scene-fortress (L5-6)", + "scene-underground (L7-8)", + "scene-palace (L9-11)", + "scene-chamber (L12)" + ] + }, + "removed": [ + "public/assets/bg.png — unused generic blue gradient (leftover)", + "public/assets/scraps/ — empty napkin design note (v1 placeholder)", + "public/assets/generated/nntv-generated-sheet.png — 2.3MB orphan bundle, not referenced", + "public/assets/logo.png (PHASER text) — replaced with proper NNTV wordmark" + ], + "renderer": "tools/render-assets.mjs (pure JS, no deps, zlib deflate)", + "poster": "tools/make-poster.mjs (composite key-art renderer)" +} \ No newline at end of file diff --git a/public/assets/MEDIA.json b/public/assets/MEDIA.json new file mode 100644 index 0000000..3aac21f --- /dev/null +++ b/public/assets/MEDIA.json @@ -0,0 +1,84 @@ +{ + "generated": "2026-06-17", + "game": "Night Ninja: Twilight Voyage", + "summary": "Image + Voice + Audio deliverables for the game. Pixel art assets remain in public/assets/generated/. BGM, voice, and key art live alongside.", + "images": { + "directory": "public/assets/images/", + "files": { + "keyart-garden.png": { "kind": "key-art", "size": "1280x720", "subject": "Ninja rabbit in moonlit vegetable garden", "use": "Main menu background / store screenshot" }, + "keyart-portrait.png": { "kind": "portrait", "size": "1024x1024", "subject": "Cinematic close-up of ninja rabbit", "use": "App icon / social card", "regen_note": "Regenerated 2026-06-17 to true 16-bit pixel art (was 3D/cinematic)" }, + "keyart-gameover.png": { "kind": "key-art", "size": "1280x720", "subject": "Rabbit silhouette before distant palace", "use": "Game over screen background" }, + "keyart-throne.png": { "kind": "key-art", "size": "1280x720", "subject": "Carrot princess on golden throne", "use": "Princess chamber / final level intro" }, + "keyart-underground.png": { "kind": "key-art", "size": "1280x720", "subject": "Underground tunnel with distant torch", "use": "Act 4 underground level intro" }, + "keyart-palace.png": { "kind": "key-art", "size": "1280x720", "subject": "Royal palace mirrored hall with chandelier", "use": "Act 5 palace level intro", "regen_note": "Regenerated 2026-06-17 to remove STUDIOSWAG watermark (regen prompt explicitly forbids watermark/signature/text overlay)" } + } + }, + "voice": { + "directory": "public/assets/voice/", + "files": { + "en-story.mp3": { "lang": "en", "voice": "English_expressive_narrator", "kind": "narration", "subject": "Story intro — the missing carrot princess" }, + "en-welcome.mp3": { "lang": "en", "voice": "English_CaptivatingStoryteller", "kind": "greeting", "subject": "Welcome to Night Ninja" }, + "en-detected.mp3": { "lang": "en", "voice": "English_magnetic_voiced_man", "kind": "sfx-callout", "subject": "Detected — restarting level" }, + "en-levelclear.mp3": { "lang": "en", "voice": "English_Upbeat_Woman", "kind": "sfx-callout", "subject": "Level clear — well done" }, + "en-princess-help.mp3": { "lang": "en", "voice": "English_Whispering_girl", "kind": "character", "subject": "Princess whisper: help me" }, + "en-princess-run.mp3": { "lang": "en", "voice": "English_StressedLady", "kind": "sfx-callout", "subject": "Run — princess sensed you" }, + "en-gameover.mp3": { "lang": "en", "voice": "English_SentimentalLady", "kind": "sfx-callout", "subject": "Some rescues were never meant to be" }, + "en-act1-garden.mp3": { "lang": "en", "voice": "English_CaptivatingStoryteller", "kind": "level-intro", "subject": "Act 1 — The Outskirts" }, + "en-act2-walls.mp3": { "lang": "en", "voice": "English_CaptivatingStoryteller", "kind": "level-intro", "subject": "Act 2 — The Vegetable Garden" }, + "en-act3-fortress.mp3": { "lang": "en", "voice": "English_CaptivatingStoryteller", "kind": "level-intro", "subject": "Act 3 — The Fortress" }, + "en-act4-underground.mp3":{ "lang": "en", "voice": "English_CaptivatingStoryteller", "kind": "level-intro", "subject": "Act 4 — The Underground" }, + "en-act5-palace.mp3": { "lang": "en", "voice": "English_CaptivatingStoryteller", "kind": "level-intro", "subject": "Act 5 — The Royal Palace" }, + "en-act6-chamber.mp3": { "lang": "en", "voice": "English_CaptivatingStoryteller", "kind": "level-intro", "subject": "Act 6 — The Princess Chamber" }, + "vi-story.mp3": { "lang": "vi", "voice": "Vietnamese_kindhearted_girl", "kind": "narration", "subject": "Câu chuyện — công chúa cà rốt mất tích" }, + "vi-welcome.mp3": { "lang": "vi", "voice": "Vietnamese_kindhearted_girl", "kind": "greeting", "subject": "Chào mừng Ninja Đêm (regen 2026-06-17: 31KB short line, was 808KB misplaced story)" }, + "vi-detected.mp3": { "lang": "vi", "voice": "Vietnamese_kindhearted_girl", "kind": "sfx-callout", "subject": "Bạn đã bị phát hiện" }, + "vi-levelclear.mp3": { "lang": "vi", "voice": "Vietnamese_kindhearted_girl", "kind": "sfx-callout", "subject": "Hoàn thành — giỏi lắm ninja (added 2026-06-17)" }, + "vi-princess-help.mp3": { "lang": "vi", "voice": "Vietnamese_kindhearted_girl", "kind": "character", "subject": "Công chúa thì thầm: cứu tôi (added 2026-06-17)" }, + "vi-princess-run.mp3": { "lang": "vi", "voice": "Vietnamese_kindhearted_girl", "kind": "sfx-callout", "subject": "Chạy đi — công chúa đã cảm nhận bạn (added 2026-06-17)" }, + "vi-gameover.mp3": { "lang": "vi", "voice": "Vietnamese_kindhearted_girl", "kind": "sfx-callout", "subject": "Có những cuộc giải cứu chưa định sẵn (added 2026-06-17)" }, + "vi-act1-garden.mp3": { "lang": "vi", "voice": "Vietnamese_kindhearted_girl", "kind": "level-intro", "subject": "Hồi 1 — Vùng ngoại ô (added 2026-06-17)" }, + "vi-act2-walls.mp3": { "lang": "vi", "voice": "Vietnamese_kindhearted_girl", "kind": "level-intro", "subject": "Hồi 2 — Vườn Rau Củ (added 2026-06-17)" }, + "vi-act3-fortress.mp3": { "lang": "vi", "voice": "Vietnamese_kindhearted_girl", "kind": "level-intro", "subject": "Hồi 3 — Pháo đài (added 2026-06-17)" }, + "vi-act4-underground.mp3":{ "lang": "vi", "voice": "Vietnamese_kindhearted_girl", "kind": "level-intro", "subject": "Hồi 4 — Tầng ngầm (added 2026-06-17)" }, + "vi-act5-palace.mp3": { "lang": "vi", "voice": "Vietnamese_kindhearted_girl", "kind": "level-intro", "subject": "Hồi 5 — Hoàng cung (added 2026-06-17)" }, + "vi-act6-chamber.mp3": { "lang": "vi", "voice": "Vietnamese_kindhearted_girl", "kind": "level-intro", "subject": "Hồi 6 — Phòng Công chúa (added 2026-06-17)" } + } + }, + "keyart_regen": { + "date": "2026-06-17", + "regenerated": { + "keyart-palace.png": { "reason": "STUDIOSWAG watermark in bottom-left of original; regenerated as clean pixel art palace hall" }, + "keyart-portrait.png": { "reason": "Original was 3D/cinematic rendered, style mismatch with game's pixel art language; regenerated as strict 16-bit pixel art" }, + "vi-welcome.mp3": { "reason": "Original was 808KB — contained the long story narration misplaced under welcome filename; regenerated as a 31KB short welcome line" } + } + }, + "audio": { + "directory": "public/assets/audio/", + "files": { + "bgm-menu.mp3": { "kind": "bgm", "scene": "main-menu", "mood": "calm, mysterious, night", "duration_estimate": "~60s loopable" }, + "bgm-story.mp3": { "kind": "bgm", "scene": "story-intro", "mood": "dramatic, cinematic, suspenseful", "duration_estimate": "~60s" }, + "bgm-levels.mp3": { "kind": "bgm", "scene": "levels 1-11", "mood": "stealthy, tense, quiet", "duration_estimate": "~60s loopable" }, + "bgm-chamber.mp3": { "kind": "bgm", "scene": "level 12 princess chamber", "mood": "climactic, intense, epic", "duration_estimate": "~60s" }, + "bgm-gameover.mp3": { "kind": "bgm", "scene": "game-over", "mood": "melancholic, sad, resigned", "duration_estimate": "~60s" } + } + }, + "existing_audio": { + "directory": "src/lib/audio.js", + "kind": "procedural (Web Audio API)", + "calls": [ + "playMove", "playWait", "playDetection", "playLevelComplete", "playClick", + "playUndo", "playStoneThrow", "playStoneImpact", "playKeyPickup", + "playDoorUnlock", "playSuspicionAlert", "playSuspicionFire" + ] + }, + "renderer_tools": { + "tools/render-assets.mjs": "Pixel-art PNG renderer (logo, favicon, scene backgrounds)", + "tools/make-poster.mjs": "Composite key-art renderer" + }, + "notes": [ + "BGMs are loopable chiptune/8-bit flavored tracks; no explicit loop markers are encoded — playback apps should loop them via audio element loop attribute.", + "Voice lines are short enough (most <15s) for in-game playback.", + "Key art PNGs are 1280x720 (16:9) except portrait (1024x1024). Suitable for README/store hero/social card use.", + "All generated media is created via the matrix MCP — image (text-to-image), voice (TTS), audio (text-to-music)." + ] +} diff --git a/public/assets/audio/bgm-chamber.mp3 b/public/assets/audio/bgm-chamber.mp3 new file mode 100644 index 0000000..f014de7 Binary files /dev/null and b/public/assets/audio/bgm-chamber.mp3 differ diff --git a/public/assets/audio/bgm-gameover.mp3 b/public/assets/audio/bgm-gameover.mp3 new file mode 100644 index 0000000..2a6f1c3 Binary files /dev/null and b/public/assets/audio/bgm-gameover.mp3 differ diff --git a/public/assets/audio/bgm-levels.mp3 b/public/assets/audio/bgm-levels.mp3 new file mode 100644 index 0000000..629e5ab Binary files /dev/null and b/public/assets/audio/bgm-levels.mp3 differ diff --git a/public/assets/audio/bgm-menu.mp3 b/public/assets/audio/bgm-menu.mp3 new file mode 100644 index 0000000..ec93b23 Binary files /dev/null and b/public/assets/audio/bgm-menu.mp3 differ diff --git a/public/assets/audio/bgm-story.mp3 b/public/assets/audio/bgm-story.mp3 new file mode 100644 index 0000000..a1a492d Binary files /dev/null and b/public/assets/audio/bgm-story.mp3 differ diff --git a/public/assets/bg.png b/public/assets/bg.png deleted file mode 100644 index 667314a..0000000 Binary files a/public/assets/bg.png and /dev/null differ diff --git a/public/assets/favicon-16.png b/public/assets/favicon-16.png new file mode 100644 index 0000000..f8bb254 Binary files /dev/null and b/public/assets/favicon-16.png differ diff --git a/public/assets/favicon-32.png b/public/assets/favicon-32.png new file mode 100644 index 0000000..f8bb254 Binary files /dev/null and b/public/assets/favicon-32.png differ diff --git a/public/assets/generated/nntv-generated-sheet.png b/public/assets/generated/nntv-generated-sheet.png deleted file mode 100644 index b651372..0000000 Binary files a/public/assets/generated/nntv-generated-sheet.png and /dev/null differ diff --git a/public/assets/images/keyart-gameover.png b/public/assets/images/keyart-gameover.png new file mode 100644 index 0000000..57b274f Binary files /dev/null and b/public/assets/images/keyart-gameover.png differ diff --git a/public/assets/images/keyart-garden.png b/public/assets/images/keyart-garden.png new file mode 100644 index 0000000..3a20fa8 Binary files /dev/null and b/public/assets/images/keyart-garden.png differ diff --git a/public/assets/images/keyart-palace.png b/public/assets/images/keyart-palace.png new file mode 100644 index 0000000..149faec Binary files /dev/null and b/public/assets/images/keyart-palace.png differ diff --git a/public/assets/images/keyart-portrait.png b/public/assets/images/keyart-portrait.png new file mode 100644 index 0000000..46badc9 Binary files /dev/null and b/public/assets/images/keyart-portrait.png differ diff --git a/public/assets/images/keyart-throne.png b/public/assets/images/keyart-throne.png new file mode 100644 index 0000000..984a655 Binary files /dev/null and b/public/assets/images/keyart-throne.png differ diff --git a/public/assets/images/keyart-underground.png b/public/assets/images/keyart-underground.png new file mode 100644 index 0000000..f31a509 Binary files /dev/null and b/public/assets/images/keyart-underground.png differ diff --git a/public/assets/logo-nntv-compact.png b/public/assets/logo-nntv-compact.png new file mode 100644 index 0000000..736d6ef Binary files /dev/null and b/public/assets/logo-nntv-compact.png differ diff --git a/public/assets/logo-nntv-wordmark.png b/public/assets/logo-nntv-wordmark.png new file mode 100644 index 0000000..d421357 Binary files /dev/null and b/public/assets/logo-nntv-wordmark.png differ diff --git a/public/assets/logo.png b/public/assets/logo.png index 9286de3..736d6ef 100644 Binary files a/public/assets/logo.png and b/public/assets/logo.png differ diff --git a/public/assets/poster.png b/public/assets/poster.png new file mode 100644 index 0000000..0b300ad Binary files /dev/null and b/public/assets/poster.png differ diff --git a/public/assets/scene-guide.png b/public/assets/scene-guide.png new file mode 100644 index 0000000..26cec46 Binary files /dev/null and b/public/assets/scene-guide.png differ diff --git a/public/assets/scene-menu.png b/public/assets/scene-menu.png new file mode 100644 index 0000000..3fcbc45 Binary files /dev/null and b/public/assets/scene-menu.png differ diff --git a/public/assets/scene-settings.png b/public/assets/scene-settings.png new file mode 100644 index 0000000..8f70743 Binary files /dev/null and b/public/assets/scene-settings.png differ diff --git a/public/assets/scene-story.png b/public/assets/scene-story.png new file mode 100644 index 0000000..f299e8e Binary files /dev/null and b/public/assets/scene-story.png differ diff --git a/public/assets/scraps/sketch-2026-04-20T14-24-41-j058tw.napkin b/public/assets/scraps/sketch-2026-04-20T14-24-41-j058tw.napkin deleted file mode 100644 index 6023f37..0000000 --- a/public/assets/scraps/sketch-2026-04-20T14-24-41-j058tw.napkin +++ /dev/null @@ -1,6 +0,0 @@ -{ - "version": 1, - "created": "2026-04-20T14:24:41.949Z", - "modified": "2026-04-20T14:24:41.949Z", - "objects": [] -} \ No newline at end of file diff --git a/public/assets/voice/en-act1-garden.mp3 b/public/assets/voice/en-act1-garden.mp3 new file mode 100644 index 0000000..41d2712 Binary files /dev/null and b/public/assets/voice/en-act1-garden.mp3 differ diff --git a/public/assets/voice/en-act2-walls.mp3 b/public/assets/voice/en-act2-walls.mp3 new file mode 100644 index 0000000..c2af721 Binary files /dev/null and b/public/assets/voice/en-act2-walls.mp3 differ diff --git a/public/assets/voice/en-act3-fortress.mp3 b/public/assets/voice/en-act3-fortress.mp3 new file mode 100644 index 0000000..2ebd941 Binary files /dev/null and b/public/assets/voice/en-act3-fortress.mp3 differ diff --git a/public/assets/voice/en-act4-underground.mp3 b/public/assets/voice/en-act4-underground.mp3 new file mode 100644 index 0000000..5cc7136 Binary files /dev/null and b/public/assets/voice/en-act4-underground.mp3 differ diff --git a/public/assets/voice/en-act5-palace.mp3 b/public/assets/voice/en-act5-palace.mp3 new file mode 100644 index 0000000..f7bb8f1 Binary files /dev/null and b/public/assets/voice/en-act5-palace.mp3 differ diff --git a/public/assets/voice/en-act6-chamber.mp3 b/public/assets/voice/en-act6-chamber.mp3 new file mode 100644 index 0000000..56b3e9c Binary files /dev/null and b/public/assets/voice/en-act6-chamber.mp3 differ diff --git a/public/assets/voice/en-detected.mp3 b/public/assets/voice/en-detected.mp3 new file mode 100644 index 0000000..1c3ba58 Binary files /dev/null and b/public/assets/voice/en-detected.mp3 differ diff --git a/public/assets/voice/en-gameover.mp3 b/public/assets/voice/en-gameover.mp3 new file mode 100644 index 0000000..e639238 Binary files /dev/null and b/public/assets/voice/en-gameover.mp3 differ diff --git a/public/assets/voice/en-levelclear.mp3 b/public/assets/voice/en-levelclear.mp3 new file mode 100644 index 0000000..64ffd66 Binary files /dev/null and b/public/assets/voice/en-levelclear.mp3 differ diff --git a/public/assets/voice/en-princess-help.mp3 b/public/assets/voice/en-princess-help.mp3 new file mode 100644 index 0000000..46022fc Binary files /dev/null and b/public/assets/voice/en-princess-help.mp3 differ diff --git a/public/assets/voice/en-princess-run.mp3 b/public/assets/voice/en-princess-run.mp3 new file mode 100644 index 0000000..90e396a Binary files /dev/null and b/public/assets/voice/en-princess-run.mp3 differ diff --git a/public/assets/voice/en-story.mp3 b/public/assets/voice/en-story.mp3 new file mode 100644 index 0000000..3a53530 Binary files /dev/null and b/public/assets/voice/en-story.mp3 differ diff --git a/public/assets/voice/en-welcome.mp3 b/public/assets/voice/en-welcome.mp3 new file mode 100644 index 0000000..41d80f5 Binary files /dev/null and b/public/assets/voice/en-welcome.mp3 differ diff --git a/public/assets/voice/vi-act1-garden.mp3 b/public/assets/voice/vi-act1-garden.mp3 new file mode 100644 index 0000000..e7be7e6 Binary files /dev/null and b/public/assets/voice/vi-act1-garden.mp3 differ diff --git a/public/assets/voice/vi-act2-walls.mp3 b/public/assets/voice/vi-act2-walls.mp3 new file mode 100644 index 0000000..aa73a38 Binary files /dev/null and b/public/assets/voice/vi-act2-walls.mp3 differ diff --git a/public/assets/voice/vi-act3-fortress.mp3 b/public/assets/voice/vi-act3-fortress.mp3 new file mode 100644 index 0000000..f9393c0 Binary files /dev/null and b/public/assets/voice/vi-act3-fortress.mp3 differ diff --git a/public/assets/voice/vi-act4-underground.mp3 b/public/assets/voice/vi-act4-underground.mp3 new file mode 100644 index 0000000..0be4097 Binary files /dev/null and b/public/assets/voice/vi-act4-underground.mp3 differ diff --git a/public/assets/voice/vi-act5-palace.mp3 b/public/assets/voice/vi-act5-palace.mp3 new file mode 100644 index 0000000..d53de93 Binary files /dev/null and b/public/assets/voice/vi-act5-palace.mp3 differ diff --git a/public/assets/voice/vi-act6-chamber.mp3 b/public/assets/voice/vi-act6-chamber.mp3 new file mode 100644 index 0000000..fb685cd Binary files /dev/null and b/public/assets/voice/vi-act6-chamber.mp3 differ diff --git a/public/assets/voice/vi-detected.mp3 b/public/assets/voice/vi-detected.mp3 new file mode 100644 index 0000000..8d201ee Binary files /dev/null and b/public/assets/voice/vi-detected.mp3 differ diff --git a/public/assets/voice/vi-gameover.mp3 b/public/assets/voice/vi-gameover.mp3 new file mode 100644 index 0000000..3c539a7 Binary files /dev/null and b/public/assets/voice/vi-gameover.mp3 differ diff --git a/public/assets/voice/vi-levelclear.mp3 b/public/assets/voice/vi-levelclear.mp3 new file mode 100644 index 0000000..b3a410f Binary files /dev/null and b/public/assets/voice/vi-levelclear.mp3 differ diff --git a/public/assets/voice/vi-princess-help.mp3 b/public/assets/voice/vi-princess-help.mp3 new file mode 100644 index 0000000..dc8ebbc Binary files /dev/null and b/public/assets/voice/vi-princess-help.mp3 differ diff --git a/public/assets/voice/vi-princess-run.mp3 b/public/assets/voice/vi-princess-run.mp3 new file mode 100644 index 0000000..387bc0c Binary files /dev/null and b/public/assets/voice/vi-princess-run.mp3 differ diff --git a/public/assets/voice/vi-story.mp3 b/public/assets/voice/vi-story.mp3 new file mode 100644 index 0000000..0c5cbc6 Binary files /dev/null and b/public/assets/voice/vi-story.mp3 differ diff --git a/public/assets/voice/vi-welcome.mp3 b/public/assets/voice/vi-welcome.mp3 new file mode 100644 index 0000000..24c7c32 Binary files /dev/null and b/public/assets/voice/vi-welcome.mp3 differ diff --git a/public/favicon.png b/public/favicon.png index 9bd72bf..f8bb254 100644 Binary files a/public/favicon.png and b/public/favicon.png differ diff --git a/src/App.svelte b/src/App.svelte index 402d02c..7b78af6 100644 --- a/src/App.svelte +++ b/src/App.svelte @@ -4,6 +4,7 @@ import { getText } from './lib/localization.js'; import { initLanguage } from './lib/localization.js'; import { loadProgress, acknowledgeMigration, isMigrationAcknowledged } from './lib/progress.js'; + import { playBgm } from './lib/bgm.js'; import MainMenu from './scenes/MainMenu.svelte'; import StoryIntro from './scenes/StoryIntro.svelte'; import LevelIntro from './scenes/LevelIntro.svelte'; @@ -22,6 +23,34 @@ // Migration modal — shown once on first v2 boot if legacy save was detected let showMigrationModal = $state(false); + // Pick the BGM track based on the active scene. L12 gets the climactic chamber + // track; everything else in the Game scene uses the generic levels loop. + function pickBgmTrack(scene, data) { + switch (scene) { + case 'MainMenu': + case 'LevelSelect': + case 'Guide': + case 'Settings': + return 'menu'; + case 'StoryIntro': + case 'LevelIntro': + return 'story'; + case 'Game': + return data?.level === 12 ? 'chamber' : 'levels'; + case 'GameOver': + return 'gameover'; + default: + return 'menu'; + } + } + + let bgmTrack = $derived(pickBgmTrack(currentScene, sceneData)); + + $effect(() => { + // Track is the reactive dep — fire playBgm whenever it changes + playBgm(bgmTrack); + }); + function navigate(scene, data = {}) { sceneData = data; currentScene = scene; diff --git a/src/components/GameHud.svelte b/src/components/GameHud.svelte index c952005..2f09e75 100644 --- a/src/components/GameHud.svelte +++ b/src/components/GameHud.svelte @@ -1,6 +1,7 @@ @@ -38,7 +42,7 @@ {/if} - + +

{getText('audioSettings')}

+
+ {getText('sfxLabel')} + +
+
+ {getText('bgmLabel')} + +
+
+ {getText('volumeLabel')} + + {Math.round(bgmVol * 100)} +
+