From e048312a8d0fe3932cb3e776057f71de49c7b150 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 30 Mar 2026 13:50:24 +0000 Subject: [PATCH] Add Spirituals, World genres, genre hiding, math reset confirmation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Spirituals (8 songs, traditional African American): - Swing Low Sweet Chariot, Go Down Moses, Wade in the Water, Kumbaya, Michael Row the Boat Ashore, He's Got the Whole World, Nobody Knows the Trouble I've Seen, Battle Hymn of the Republic Uses choir synth for authentic spiritual sound. World (8 songs from various cultures): - Hava Nagila (Jewish/Israeli, 1918) - La Cucaracha (Mexican Traditional) - Frère Jacques (French, 1780s) - Cielito Lindo (Mexican, 1882) - Waltzing Matilda (Australian, 1895) - 'O Sole Mio (Italian, 1898) - Take Me Out to the Ball Game (American, 1908) - She'll Be Coming Round the Mountain (American, 1890s) Genre hiding: - Right-click any genre tab to hide it - Hidden genres stored in localStorage - "Show All (N hidden)" button appears to restore - Hidden genre list cleared on Reset All Data Math confirmation for Reset All Data: - Random addition problem (e.g., "What is 17 + 9?") - Must answer correctly to proceed with data wipe - Prevents accidental taps from destroying scores Total: 16 genres, 91 synth pieces, 68 min of content https://claude.ai/code/session_01GdFrFqAe9e2DaJ86jZPEZE --- index.html | 186 +++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 172 insertions(+), 14 deletions(-) diff --git a/index.html b/index.html index e6c926e..20bc3f5 100644 --- a/index.html +++ b/index.html @@ -110,7 +110,7 @@ canvas{display:block;}
No scores yet.
- +
@@ -1984,7 +1984,142 @@ const SINGALONG_PIECES=(function(){ return [drunken,wellerman,molly,whiskey,parting,leavejohnny,blowman,randy,southaus,chariot,hauljoe,spanish,skye,bella,amazing,auld,saints,clementine,scarborough,bonnie]; })(); -var SYNTH_GENRES={"Singalong":SINGALONG_PIECES,"Christmas":CHRISTMAS_PIECES,"Folk":FOLK_PIECES,"Classical":CLASSICAL_PIECES,"Video Games":VIDEOGAME_PIECES,"Chiptune Originals":CHIPTUNE_PIECES}; +// ── SPIRITUALS (traditional African American songs) ── +const SPIRITUAL_PIECES=(function(){ + var C3=NT.C3,D3=NT.D3,E3=NT.E3,F3=NT.F3,G3=NT.G3,A3=NT.A3,Bb3=NT.Bb3,B3=NT.B3, + C4=NT.C4,D4=NT.D4,Eb4=NT.Eb4,E4=NT.E4,F4=NT.F4,G4=NT.G4,A4=NT.A4,Bb4=NT.Bb4,B4=NT.B4, + C5=NT.C5,D5=NT.D5,E5=NT.E5; + function spirit(name,origin,bpm,theme,lanes,durations,passes,root){ + var bg=[],mel=[],t=0,q=0.25; + for(var rep=0;rep0)bg.push({t:t,f:f/2,d:d*0.85,i:'bass',v:v*0.3}); + if(rep>Math.floor(passes*0.5))bg.push({t:t,f:f,d:d*0.85,i:'choir',v:v*0.35}); + if(rep>Math.floor(passes*0.7))bg.push({t:t,f:f,d:d*0.85,i:'brass',v:v*0.3}); + mel.push({t:t,l:lanes[i]});t+=d; + }); + t+=0.4; + } + var r=root||theme[0]; + [r,r*5/4,r*3/2,r*2].forEach(function(f){bg.push({t:t,f:f,d:2.5,i:'choir',v:0.5});bg.push({t:t,f:f,d:2.5,i:'strings',v:0.35});}); + bg.push({t:t,f:r/2,d:2.0,i:'timpani',v:0.5});mel.push({t:t,l:4}); + return {n:name,composer:origin,bpm:bpm,duration:Math.ceil(t+3),isClassical:true,bg:bg,melody:mel}; + } + var swing=spirit("Swing Low, Sweet Chariot","Spiritual (1862)",80, + [G4,C5,C5,E5,D5,C5,A4,G4,E4,G4,A4,G4,E4,C4,D4,E4,G4,C5,C5,E5,D5,C5,A4,G4,E4,G4,A4,C5,G4], + [3,0,0,2,1,0,0,3,2,3,0,3,2,0,1,2,3,0,0,2,1,0,0,3,2,3,0,0,3], + [2,2,1,2,1,1,2,2,1,1,1,2,1,2,1,1,2,2,1,2,1,1,2,2,1,1,2,1,4], + 4,C4); + var godown=spirit("Go Down Moses","Spiritual (Trad.)",90, + [A3,C4,C4,D4,E4,E4,D4,C4,A3,C4,D4,E4,G4,E4,D4,C4,A3,C4,E4,G4,A4,G4,E4,D4,C4,A3], + [0,0,0,1,2,2,1,0,0,0,1,2,3,2,1,0,0,0,2,3,0,3,2,1,0,0], + [1,2,1,1,2,1,1,2,1,1,1,2,1,1,1,2,1,1,1,2,1,1,1,1,2,4], + 5,A3); + var wade=spirit("Wade in the Water","Spiritual (Trad.)",100, + [E4,E4,G4,A4,B4,A4,G4,E4,D4,E4,G4,A4,B4,D5,B4,A4,G4,E4,D4,E4,G4,B4,A4,G4,E4], + [2,2,3,0,3,0,3,2,1,2,3,0,3,1,3,0,3,2,1,2,3,3,0,3,2], + [1,1,1,1,2,1,1,2,1,1,1,1,2,1,1,1,1,2,1,1,1,1,1,1,4], + 5,E4); + var kumbaya=spirit("Kumbaya","Spiritual (Trad.)",75, + [C4,E4,F4,G4,G4,F4,E4,C4,C4,E4,F4,G4,A4,G4,E4,C4,E4,F4,G4,G4,F4,E4,D4,C4], + [0,2,1,3,3,1,2,0,0,2,1,3,0,3,2,0,2,1,3,3,1,2,1,0], + [1,1,1,2,1,1,2,2,1,1,1,2,1,2,1,1,1,1,2,1,1,1,1,4], + 5,C4); + var michael=spirit("Michael Row the Boat Ashore","Spiritual (1860s)",90, + [C4,E4,F4,E4,C4,D4,E4,F4,G4,A4,G4,E4,C4,D4,C4,C4,E4,G4,A4,G4,E4,F4,E4,D4,C4], + [0,2,1,2,0,1,2,1,3,0,3,2,0,1,0,0,2,3,0,3,2,1,2,1,0], + [1,1,1,2,1,1,1,1,2,1,1,1,2,1,3,1,1,2,1,1,1,1,1,1,4], + 5,C4); + var wholeworld=spirit("He's Got the Whole World","Spiritual (Trad.)",110, + [C4,C4,E4,G4,G4,E4,G4,A4,G4,E4,C4,E4,G4,C5,A4,G4,E4,C4,E4,G4,E4,C4], + [0,0,2,3,3,2,3,0,3,2,0,2,3,0,0,3,2,0,2,3,2,0], + [1,1,1,2,1,1,1,1,1,1,2,1,1,2,1,1,1,2,1,1,1,4], + 5,C4); + var nobody=spirit("Nobody Knows the Trouble I've Seen","Spiritual (Trad.)",75, + [C4,E4,G4,A4,G4,E4,C4,D4,E4,G4,C5,A4,G4,E4,D4,C4,E4,G4,A4,C5,A4,G4,E4,D4,C4], + [0,2,3,0,3,2,0,1,2,3,0,0,3,2,1,0,2,3,0,0,0,3,2,1,0], + [1,1,2,1,1,2,2,1,1,2,1,1,1,2,1,2,1,2,1,2,1,1,1,1,4], + 4,C4); + var battle=spirit("Battle Hymn of the Republic","J.W. Howe (1861)",115, + [C4,C4,C4,E4,E4,D4,C4,D4,E4,F4,E4,D4,C4,C4,E4,G4,G4,F4,E4,F4,G4,A4,G4,E4,C4,E4,D4,C4], + [0,0,0,2,2,1,0,1,2,1,2,1,0,0,2,3,3,1,2,1,3,0,3,2,0,2,1,0], + [1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,2,1,1,1,1,1,1,1,1,2,1,1,4], + 4,C4); + return [swing,godown,wade,kumbaya,michael,wholeworld,nobody,battle]; +})(); + +// ── WORLD (folk songs from various cultures) ── +const WORLD_PIECES=(function(){ + var C3=NT.C3,D3=NT.D3,E3=NT.E3,F3=NT.F3,G3=NT.G3,Ab3=NT.Ab3,A3=NT.A3,Bb3=NT.Bb3,B3=NT.B3, + C4=NT.C4,D4=NT.D4,Eb4=NT.Eb4,E4=NT.E4,F4=NT.F4,Gb4=NT.Gb4,G4=NT.G4,Ab4=NT.Ab4,A4=NT.A4,Bb4=NT.Bb4,B4=NT.B4, + C5=NT.C5,D5=NT.D5,E5=NT.E5; + function world(name,origin,bpm,theme,lanes,durations,passes,root){ + var bg=[],mel=[],t=0,q=0.25; + for(var rep=0;rep1)bg.push({t:t,f:f/2,d:d*0.85,i:'bass',v:v*0.35}); + if(rep>Math.floor(passes*0.6))bg.push({t:t,f:f,d:d*0.85,i:'brass',v:v*0.35}); + mel.push({t:t,l:lanes[i]});t+=d; + }); + t+=0.4; + } + var r=root||theme[0]; + [r,r*5/4,r*3/2,r*2].forEach(function(f){bg.push({t:t,f:f,d:2.0,i:'brass',v:0.5});bg.push({t:t,f:f,d:2.0,i:'strings',v:0.4});}); + bg.push({t:t,f:r/2,d:1.5,i:'timpani',v:0.55});mel.push({t:t,l:4}); + return {n:name,composer:origin,bpm:bpm,duration:Math.ceil(t+2.5),isClassical:true,bg:bg,melody:mel}; + } + var hava=world("Hava Nagila","Jewish/Israeli (1918)",130, + [E4,F4,E4,D4,E4,F4,G4,Ab4,G4,F4,E4,F4,G4,Ab4,B4,Ab4,G4,F4,E4,F4,G4,Ab4,G4,F4,E4,D4,E4], + [2,1,2,1,2,1,3,0,3,1,2,1,3,0,3,0,3,1,2,1,3,0,3,1,2,1,2], + [1,1,1,1,1,1,1,2,1,1,1,1,1,2,1,1,1,1,1,1,1,2,1,1,1,1,4], + 5,E4); + var cucaracha=world("La Cucaracha","Mexican (Trad.)",135, + [C4,C4,C4,F4,A4,C4,C4,C4,F4,A4,F4,F4,E4,E4,D4,D4,C4,C4,C4,G4,Bb4,C4,C4,C4,G4,Bb4,A4,G4,F4,E4,D4,C4], + [0,0,0,1,0,0,0,0,1,0,1,1,2,2,1,1,0,0,0,3,2,0,0,0,3,2,0,3,1,2,1,0], + [1,1,1,1,2,1,1,1,1,2,1,1,1,1,1,1,2,1,1,1,2,1,1,1,1,2,1,1,1,1,1,4], + 4,F4); + var frere=world("Fr\u00e8re Jacques","French (1780s)",110, + [C4,D4,E4,C4,C4,D4,E4,C4,E4,F4,G4,E4,F4,G4,G4,A4,G4,F4,E4,C4,G4,A4,G4,F4,E4,C4,C4,G3,C4,C4,G3,C4], + [0,1,2,0,0,1,2,0,2,1,3,2,1,3,3,0,3,1,2,0,3,0,3,1,2,0,0,3,0,0,3,0], + [1,1,1,1,1,1,1,1,1,1,2,1,1,2,1,1,1,1,1,2,1,1,1,1,1,2,1,1,2,1,1,4], + 4,C4); + var cielito=world("Cielito Lindo","Mexican (1882)",120, + [E4,E4,F4,G4,A4,G4,F4,E4,D4,E4,F4,E4,D4,C4,E4,G4,C5,C5,B4,A4,G4,F4,E4,D4,C4,E4,G4,C5], + [2,2,1,3,0,3,1,2,1,2,1,2,1,0,2,3,0,0,3,0,3,1,2,1,0,2,3,0], + [1,1,1,1,2,1,1,1,1,1,1,1,1,3,1,1,2,1,1,1,1,1,1,1,2,1,1,4], + 4,C4); + var waltzing=world("Waltzing Matilda","Australian (1895)",110, + [G4,G4,A4,B4,D5,B4,A4,G4,E4,G4,A4,B4,A4,G4,E4,D4,G4,G4,A4,B4,D5,B4,A4,G4,E4,D4,G4], + [3,3,0,3,1,3,0,3,2,3,0,3,0,3,2,1,3,3,0,3,1,3,0,3,2,1,3], + [1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,2,1,1,1,1,1,1,4], + 5,G4); + var osole=world("'O Sole Mio","Italian (1898)",90, + [C4,D4,E4,F4,G4,A4,G4,F4,E4,D4,C4,D4,E4,F4,G4,C5,B4,A4,G4,F4,E4,F4,G4,A4,G4,F4,E4,D4,C4], + [0,1,2,1,3,0,3,1,2,1,0,1,2,1,3,0,3,0,3,1,2,1,3,0,3,1,2,1,0], + [1,1,1,1,2,1,1,1,1,1,2,1,1,1,2,1,1,1,1,1,2,1,1,1,1,1,1,1,4], + 4,C4); + var ballgame=world("Take Me Out to the Ball Game","American (1908)",125, + [C4,C4,A4,G4,E4,G4,D4,C4,C4,A4,G4,E4,G4,C4,C4,A4,G4,F4,E4,D4,E4,F4,D4,C4,A4,G4,E4,C4], + [0,0,0,3,2,3,1,0,0,0,3,2,3,0,0,0,3,1,2,1,2,1,1,0,0,3,2,0], + [1,1,2,1,1,2,1,2,1,2,1,1,3,1,1,2,1,1,1,1,1,1,2,1,1,1,1,4], + 4,C4); + var mountain=world("She'll Be Coming Round the Mountain","American (1890s)",130, + [G4,G4,B4,B4,D5,D5,B4,G4,A4,B4,C5,C5,A4,A4,G4,B4,D5,D5,B4,G4,A4,C5,B4,A4,G4], + [3,3,3,3,1,1,3,3,0,3,0,0,0,0,3,3,1,1,3,3,0,0,3,0,3], + [1,1,2,1,2,1,1,2,1,1,2,1,2,1,2,1,2,1,1,2,1,1,1,1,4], + 5,G4); + return [hava,cucaracha,frere,cielito,waltzing,osole,ballgame,mountain]; +})(); + +var SYNTH_GENRES={"Singalong":SINGALONG_PIECES,"Christmas":CHRISTMAS_PIECES,"Folk":FOLK_PIECES,"Spirituals":SPIRITUAL_PIECES,"World":WORLD_PIECES,"Classical":CLASSICAL_PIECES,"Video Games":VIDEOGAME_PIECES,"Chiptune Originals":CHIPTUNE_PIECES}; function buildClassicalNotes(piece){ return piece.melody.filter(function(m){return activePads[m.l];}) @@ -2026,6 +2161,7 @@ var gpMap=JSON.parse(localStorage.getItem("drgameGpMap")||"null")||{0:2,1:3,2:0, var remapping=false,remapStep=0,remapResult={}; var _savedSettings=JSON.parse(localStorage.getItem("drgameSettings")||"{}"); var gameSpeed=_savedSettings.speed||1.0,masterVolume=_savedSettings.volume||1.0; +var hiddenGenres=JSON.parse(localStorage.getItem("drgameHidden")||"[]"); let gameRhythm=null; const HIT_WIN=0.17,SPEED=260; @@ -2057,6 +2193,24 @@ function loadSettings(){ document.getElementById("vol-slider").value=Math.round(masterVolume*100); document.getElementById("vol-val").textContent=Math.round(masterVolume*100)+"%"; } +function confirmReset(){ + var a=Math.floor(Math.random()*20)+5,b=Math.floor(Math.random()*20)+5; + var ans=prompt("To reset ALL saved data (scores, settings, gamepad mapping, hidden genres), solve this:\n\nWhat is "+a+" + "+b+"?"); + if(ans===null)return; + if(parseInt(ans)===a+b){ + localStorage.removeItem("drgame5");localStorage.removeItem("drgameSettings"); + localStorage.removeItem("drgameGpMap");localStorage.removeItem("drgameHidden"); + savedScores=[];hiddenGenres=[];gpMap={0:2,1:3,2:0,3:1,4:4,8:4}; + refreshMiniLB();resetSettings();buildMenu(); + alert("All data cleared!"); + } else {alert("Incorrect — data NOT cleared.");} +} +function hideGenre(g){ + if(hiddenGenres.indexOf(g)<0)hiddenGenres.push(g); + localStorage.setItem("drgameHidden",JSON.stringify(hiddenGenres)); + if(curGenre===g){var allG=Object.keys(SYNTH_GENRES).concat(Object.keys(GENRES));curGenre=allG.find(function(x){return hiddenGenres.indexOf(x)<0;})||allG[0];curIdx=0;} + buildMenu(); +} function setHitMode(m){ classicalHitMode=m; document.getElementById("hitmode-drums").className="smbtn"+(m==='drums'?' purple':''); @@ -2069,21 +2223,25 @@ function updateHitModeVisibility(){ // ── MENU ─────────────────────────────────────────────── function buildMenu(){ const gt=document.getElementById("gtabs");gt.innerHTML=""; - // Synth genres first (songs people know) - var synthIcons={"Singalong":"\uD83C\uDFB5","Christmas":"\uD83C\uDF84","Folk":"\uD83C\uDFB6","Classical":"\uD83C\uDFBB","Video Games":"\uD83C\uDFAE","Chiptune Originals":"\uD83D\uDC7E"}; - Object.keys(SYNTH_GENRES).forEach(function(sg){ - var cb=document.createElement("button"); - cb.className="gtab"+(curGenre===sg?" active":""); - cb.textContent=synthIcons[sg]+" "+sg;cb.onclick=function(){curGenre=sg;curIdx=0;stopPreview();buildMenu();}; - gt.appendChild(cb); - }); - // Drum pattern genres - Object.keys(GENRES).forEach(g=>{ - const b=document.createElement("button"); + var synthIcons={"Singalong":"\uD83C\uDFB5","Christmas":"\uD83C\uDF84","Folk":"\uD83C\uDFB6","Spirituals":"\uD83D\uDE4F","World":"\uD83C\uDF0D","Classical":"\uD83C\uDFBB","Video Games":"\uD83C\uDFAE","Chiptune Originals":"\uD83D\uDC7E"}; + var allGenres=Object.keys(SYNTH_GENRES).concat(Object.keys(GENRES)); + var anyHidden=hiddenGenres.length>0; + allGenres.forEach(function(g){ + if(hiddenGenres.indexOf(g)>=0)return; + var b=document.createElement("button"); b.className="gtab"+(g===curGenre?" active":""); - b.textContent=g;b.onclick=()=>{curGenre=g;curIdx=0;stopPreview();buildMenu();}; + b.textContent=(synthIcons[g]?synthIcons[g]+" ":"")+g; + b.onclick=function(){curGenre=g;curIdx=0;stopPreview();buildMenu();}; + b.oncontextmenu=function(e){e.preventDefault();hideGenre(g);}; gt.appendChild(b); }); + if(anyHidden){ + var sb=document.createElement("button"); + sb.className="gtab";sb.style.opacity="0.4";sb.style.fontSize="10px"; + sb.textContent="\u2795 Show All ("+hiddenGenres.length+" hidden)"; + sb.onclick=function(){hiddenGenres=[];localStorage.setItem("drgameHidden","[]");buildMenu();}; + gt.appendChild(sb); + } const rg=document.getElementById("rgrid");rg.innerHTML=""; (SYNTH_GENRES[curGenre]||GENRES[curGenre]).forEach((r,i)=>{ const b=document.createElement("button");