From 4d10f0a8797bcc10df9ed6c416635b4ff80110a8 Mon Sep 17 00:00:00 2001 From: tiennm99 Date: Wed, 9 Sep 2026 11:14:47 +0700 Subject: [PATCH] feat(audio): play sound effects and background music Nine one-shot effects on the play flow and one ambient loop, both on by default and mutable independently from every header. lib/audio.js owns the single AudioContext, the decoded-buffer cache and the two preferences. Those preferences live in module variables mirrored into localStorage rather than read back from it: a private window throws on both read and write, and re-reading before each sound turned a mute that could not be persisted into a mute that never happened. The gesture listeners stay registered for the life of the page. They open the context on the first interaction, but they are also the only thing that resumes one the browser suspended -- removing them after the first gesture left the game silent for the rest of a session once a phone had been locked. MusicPlayer mounts in the root layout, not in a page, so walking from the menu into a round does not tear down and restart the loop. It loops a decoded buffer rather than an