diff --git a/index.html b/index.html
index d81b584..4b6aab4 100644
--- a/index.html
+++ b/index.html
@@ -46,6 +46,12 @@ canvas{display:block;}
.stbl th{text-align:left;padding:7px 9px;border-bottom:1px solid #222;font-size:11px;opacity:.5;}
.stbl td{padding:7px 9px;border-bottom:1px solid #111;font-size:12px;}
.sticky-start{position:sticky;bottom:0;padding:12px 0 4px;background:linear-gradient(transparent,#0a0a0f 35%);z-index:10;display:flex;gap:8px;justify-content:center;align-items:center;width:100%;max-width:700px;}
+#game-controls{display:flex;gap:0;background:#0d0d18;border-bottom:1px solid #1e1e2e;padding:5px 14px;flex-shrink:0;width:100%;align-items:center;justify-content:center;gap:28px;}
+.gctrl-label{display:flex;align-items:center;gap:8px;cursor:default;}
+.gctrl-icon{font-size:16px;}
+.gctrl-name{font-size:11px;color:#aaa;min-width:44px;}
+.gctrl-slider{width:140px;height:6px;accent-color:#805ad5;cursor:pointer;}
+.gctrl-val{font-size:13px;font-weight:bold;color:#b794f4;min-width:40px;text-align:right;}
#pause-overlay{display:none;position:absolute;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.8);z-index:20;flex-direction:column;align-items:center;justify-content:center;gap:16px;}
#pause-overlay.show{display:flex;}
#pause-overlay h2{font-size:28px;color:#fff;}
@@ -139,9 +145,15 @@ canvas{display:block;}
@@ -2292,7 +2304,8 @@ function beginClassical(){
var n=piece.bg[i];
playSynth(ac,n.f,gameStartTime+n.t/gameSpeed,n.d/gameSpeed,n.i,n.v*1.5,gameSynthNodes);
}
- setTimeout(function(){if(playing)endTurn();},(piece.duration/gameSpeed)*1000+800);
+ gameEndTime=piece.duration/gameSpeed;
+ setTimeout(function(){if(playing)endTurn();},(piece.duration/gameSpeed)*1000+5000);
}
// ── STATE ──────────────────────────────────────────────
@@ -2301,7 +2314,7 @@ let players=[{name:"Player 1"}];
let savedScores=lsLoad();
let previewAc=null,previewNodes=[],previewing=false;
let gameAc=null,mp3Buffer=null,mp3Src=null;
-let notes=[],gameStartTime=null,playing=false;
+let notes=[],gameStartTime=null,gameEndTime=null,playing=false;
let gamePlayers=[],activePIdx=0;
let cScore=0,cStreak=0,cTotal=0,cGood=0,cMaxStreak=0;
let laneFlash=[0,0,0,0,0],msgTmr=null,prevBtns={},gameSynthNodes=[],classicalHitMode='orchestra';
@@ -2348,10 +2361,11 @@ buildPadToggles();
function saveSettings(){localStorage.setItem("drgameSettings",JSON.stringify({speed:gameSpeed,volume:masterVolume}));}
function syncSliders(){
var sv=Math.round(gameSpeed*100),vv=Math.round(masterVolume*100);
- ['speed-slider','hud-speed'].forEach(function(id){var e=document.getElementById(id);if(e)e.value=sv;});
+ ['speed-slider'].forEach(function(id){var e=document.getElementById(id);if(e)e.value=sv;});
['vol-slider','hud-vol'].forEach(function(id){var e=document.getElementById(id);if(e)e.value=vv;});
var se=document.getElementById("speed-val");if(se)se.textContent=sv+"%";
var ve=document.getElementById("vol-val");if(ve)ve.textContent=vv+"%";
+ var hve=document.getElementById("hud-vol-val");if(hve)hve.textContent=vv+"%";
}
function setSpeed(v){gameSpeed=v/100;syncSliders();saveSettings();}
function setVolume(v){masterVolume=v/100;syncSliders();saveSettings();}
@@ -2406,7 +2420,7 @@ function buildMenu(){
sb.onclick=function(){hiddenGenres=[];localStorage.setItem("drgameHidden","[]");buildMenu();};
gt.appendChild(sb);
}
- const rg=document.getElementById("rgrid");rg.innerHTML="";
+ const rg=document.getElementById("rgrid");rg.innerHTML="";rg.ondblclick=()=>startGame();
var songList=SYNTH_GENRES[curGenre]||GENRES[curGenre];
var hidCount=0;
songList.forEach((r,i)=>{
@@ -2530,7 +2544,7 @@ function startGame(){
updateHud();
}
function stopGame(){playing=false;if(mp3Src){try{mp3Src.stop();}catch(e){}mp3Src=null;}gameSynthNodes.forEach(function(n){try{n.stop();}catch(e){}});gameSynthNodes=[];}
-function resetStats(){cScore=0;cStreak=0;cTotal=0;cGood=0;cMaxStreak=0;}
+function resetStats(){cScore=0;cStreak=0;cTotal=0;cGood=0;cMaxStreak=0;gameEndTime=null;}
function buildNotes(r){
const bs=60/r.bpm/gameSpeed,bars=r.bars||8,res=[];
@@ -2555,7 +2569,8 @@ function beginBuiltin(){
for(const p of r.p)
playDrumAt(ac,p.l,gameStartTime+bar*4*bs+p.t*bs,4,[]);
const totalSec=bars*4*bs;
- setTimeout(()=>{if(playing)endTurn();},totalSec*1000+800);
+ gameEndTime=totalSec;
+ setTimeout(()=>{if(playing)endTurn();},totalSec*1000+5000);
}
function beginMp3(){
@@ -2721,6 +2736,11 @@ function draw(){
if(laneFlash[4]){cx.beginPath();cx.arc(W/2,KICK_HIT_Y,kr,0,Math.PI*2);cx.fillStyle=LANES[4].color+"44";cx.fill();}
}
+ // Auto-end when all notes resolved and past expected end time
+ if(playing&&mode==="builtin"&&gameEndTime!=null&&now>=gameEndTime){
+ if(notes.length===0||notes.every(n=>n.hit||n.missed))endTurn();
+ }
+
// Notes
if(mode==="builtin"&&now>-9000){
for(const n of notes){