(function() { const existing = document.getElementById("pianoGameWindow"); if (existing) existing.remove(); window.KEYS_CONFIG = { col0: { code: 'KeyA', label: 'A' }, col1: { code: 'KeyS', label: 'S' }, col2: { code: 'KeyD', label: 'D' }, col3: { code: 'KeyF', label: 'F' }, col4: { code: 'KeyG', label: 'G' }, col5: { code: 'KeyH', label: 'H' } }; if (localStorage.getItem("floating_piano_keybinds")) { try { window.KEYS_CONFIG = JSON.parse(localStorage.getItem("floating_piano_keybinds")); } catch(e) {} } window.START_SPEED_SETTING = 1.0; window.LANE_COUNT_SETTING = 4; const o = document.createElement("div"); o.id = "pianoGameWindow"; o.style.cssText = "position:fixed; top:40px; right:40px; width:340px; background:#f7f5f0; border:3px solid #222; border-radius:8px; box-shadow:0 12px 40px rgba(0,0,0,0.4); z-index:999999; font-family:Georgia, serif; text-align:center; user-select:none; overflow:hidden;"; o.innerHTML = `
🎹 Polyphonic Piano Tiles
🏠 Menu ⚙️ Bind _
`; document.body.appendChild(o); const lane4Btn = document.getElementById("setLanes4"); const lane6Btn = document.getElementById("setLanes6"); const slider = document.getElementById("speedSlider"); const lbl = document.getElementById("speedLabel"); const names = { "0.6": "Easy", "1.0": "Medium", "1.4": "Hard", "1.8": "Insane", "2.2": "God Mode" }; lane4Btn.addEventListener("click", () => { window.LANE_COUNT_SETTING = 4; lane4Btn.style.cssText = "padding:6px 16px; font-weight:bold; font-size:12px; background:#222; color:#fff; border:1px solid #222; border-radius:4px; cursor:pointer; margin-right:10px;"; lane6Btn.style.cssText = "padding:6px 16px; font-weight:bold; font-size:12px; background:#fff; color:#222; border:1px solid #ccc; border-radius:4px; cursor:pointer;"; }); lane6Btn.addEventListener("click", () => { window.LANE_COUNT_SETTING = 6; lane6Btn.style.cssText = "padding:6px 16px; font-weight:bold; font-size:12px; background:#222; color:#fff; border:1px solid #222; border-radius:4px; cursor:pointer;"; lane4Btn.style.cssText = "padding:6px 16px; font-weight:bold; font-size:12px; background:#fff; color:#222; border:1px solid #ccc; border-radius:4px; cursor:pointer; margin-right:10px;"; }); slider.addEventListener("input", (e) => { window.START_SPEED_SETTING = parseFloat(e.target.value); lbl.innerText = names[e.target.value] || "Custom"; }); })(); (function() { const o = document.getElementById("pianoGameWindow"); const h = document.getElementById("pianoHeader"); let isDrag = false, sx, sy, sl, st; h.addEventListener("mousedown", (e) => { if (["closePianoBtn", "minPianoBtn", "bindPianoBtn", "menuPianoBtn"].includes(e.target.id)) return; isDrag = true; sx = e.clientX; sy = e.clientY; sl = o.offsetLeft; st = o.offsetTop; e.preventDefault(); }); window.addEventListener("mousemove", (e) => { if (isDrag) { o.style.left = sl + (e.clientX - sx) + "px"; o.style.top = st + (e.clientY - sy) + "px"; o.style.right = "auto"; } }); window.addEventListener("mouseup", () => isDrag = false); document.getElementById("closePianoBtn").addEventListener("click", () => o.remove()); let isMin = false; window.checkMin = () => isMin; document.getElementById("minPianoBtn").addEventListener("click", () => { const w = document.getElementById("pianoContentWrapper"); isMin = !isMin; w.style.display = isMin ? "none" : "block"; document.getElementById("minPianoBtn").innerText = isMin ? "⬜" : "_"; if (isMin) document.getElementById("pianoSettingsModal").style.display = "none"; }); const m = document.createElement("div"); m.id = "pianoSettingsModal"; m.style.cssText = "display:none; position:absolute; top:36px; left:0; width:100%; height:calc(100% - 36px); background:rgba(247,245,240,0.95); z-index:10; padding:20px; box-sizing:border-box; font-family:sans-serif; overflow-y:auto;"; m.innerHTML = `

Configure Keybindings

`; o.appendChild(m); const playScreen = document.getElementById("gamePlayScreen"); const menuScreen = document.getElementById("mainMenuScreen"); window.showMenu = function() { window.inGameMode = false; playScreen.style.display = "none"; menuScreen.style.display = "block"; m.style.display = "none"; }; document.getElementById("menuPianoBtn").addEventListener("click", window.showMenu); document.getElementById("bindPianoBtn").addEventListener("click", () => { if (isMin) return; if (m.style.display === "none") { const grid = document.getElementById("dynamicBindGrid"); grid.innerHTML = ""; const totalLanesToShow = window.LANE_COUNT_SETTING || 4; for (let i = 0; i < totalLanesToShow; i++) { const laneDiv = document.createElement("div"); laneDiv.innerHTML = `L${i+1}: `; grid.appendChild(laneDiv); document.getElementById(`bindCol${i}`).addEventListener("click", () => { for(let j = 0; j < totalLanesToShow; j++) { const targetBtn = document.getElementById(`bindCol${j}`); if(targetBtn) targetBtn.style.background = ""; } window.activeBind = i; document.getElementById(`bindCol${i}`).innerText = "..."; document.getElementById(`bindCol${i}`).style.background = "#ffeb3b"; }); } m.style.display = "block"; } else { m.style.display = "none"; } }); document.getElementById("closeSettingsBtn").addEventListener("click", () => m.style.display = "none"); window.activeBind = null; window.addEventListener("keydown", (e) => { if (window.activeBind !== null) { e.preventDefault(); const lbl = e.key.toUpperCase(); window.KEYS_CONFIG[`col${window.activeBind}`] = { code: e.code, label: lbl.length === 1 ? lbl : e.key }; const activeBtn = document.getElementById(`bindCol${window.activeBind}`); if (activeBtn) { activeBtn.innerText = window.KEYS_CONFIG[`col${window.activeBind}`].label; activeBtn.style.background = ""; } window.activeBind = null; if (window.pMap) window.pMap(); localStorage.setItem("floating_piano_keybinds", JSON.stringify(window.KEYS_CONFIG)); } }); })(); (function() { window.canvas = document.getElementById("pianoCanvas"); if (!window.canvas) return; window.ctx = window.canvas.getContext("2d"); const AudioCtx = window.AudioContext || window.webkitAudioContext; window.audioCtx = new AudioCtx(); window.CHORD_BANK = [[220,261.63,329.63,392],[174.61,261.63,329.63,440],[261.63,329.63,392,493.88],[196,246.94,293.66,440]]; window.playChord = function(score) { if (window.audioCtx.state === 'suspended') window.audioCtx.resume(); const notes = window.CHORD_BANK[Math.floor(score / 3) % window.CHORD_BANK.length]; notes.forEach((f, i) => { let osc = window.audioCtx.createOscillator(), g = window.audioCtx.createGain(); osc.type = 'triangle'; osc.frequency.setValueAtTime(f, window.audioCtx.currentTime); const v = i === 0 ? 0.2 : 0.12; g.gain.setValueAtTime(v, window.audioCtx.currentTime); g.gain.exponentialRampToValueAtTime(0.001, window.audioCtx.currentTime + 1.0); osc.connect(g); g.connect(window.audioCtx.destination); osc.start(); osc.stop(window.audioCtx.currentTime + 1.0); }); }; window.playErrorBuzzer = function() { if (window.audioCtx.state === 'suspended') window.audioCtx.resume(); [130.00, 135.00].forEach((freq) => { let osc = window.audioCtx.createOscillator(), g = window.audioCtx.createGain(); osc.type = 'sawtooth'; osc.frequency.setValueAtTime(freq, window.audioCtx.currentTime); g.gain.setValueAtTime(0.15, window.audioCtx.currentTime); g.gain.linearRampToValueAtTime(0.001, window.audioCtx.currentTime + 0.35); osc.connect(g); g.connect(window.audioCtx.destination); osc.start(); osc.stop(window.audioCtx.currentTime + 0.35); }); }; window.hScores = { Classic: 0, Zen: 0 }; if (localStorage.getItem("floating_piano_highscores")) window.hScores = JSON.parse(localStorage.getItem("floating_piano_highscores")); window.upBrd = function() { document.getElementById("leaderboardPanel").innerText = `Best - Classic: ${window.hScores.Classic} | Zen: ${window.hScores.Zen}`; }; })(); (function() { if (!window.canvas) return; let mode = 'Classic', score = 0, gOver = false, speed = 2.8, tiles = [], parts = [], zTime = 30.0, lastT = performance.now(); let COLS = 4, ROW_HEIGHT = 105, COL_WIDTH = window.canvas.width / 4; let KEY_MAP = {}; window.pMap = function() { KEY_MAP = {}; COLS = window.LANE_COUNT_SETTING; COL_WIDTH = window.canvas.width / COLS; for (let i = 0; i < COLS; i++) { KEY_MAP[window.KEYS_CONFIG[`col${i}`].code] = i; } const hint = document.getElementById("controlLabelsHint"); if (hint) { let arr = []; for(let i=0; i { if (!window.inGameMode || window.checkMin() || window.activeBind !== null) return; if (gOver) { if (e.code in KEY_MAP || e.code === "Space") init(); return; } if (!(e.code in KEY_MAP)) return; const col = KEY_MAP[e.code]; let active = null, maxY = -999; for (let i = 0; i < tiles.length; i++) { let t = tiles[i]; if (t.y + ROW_HEIGHT > 0 && t.y < window.canvas.height && !t.clicked && t.y > maxY) { maxY = t.y; active = t; } } if (active && active.blackIdx === col) { active.clicked = true; score++; if (mode === 'Classic') speed += (0.12 * window.START_SPEED_SETTING); upScr(); window.playChord(score); for (let i = 0; i < 6; i++) parts.push({ x: col * COL_WIDTH + COL_WIDTH / 2, y: active.y + ROW_HEIGHT / 2, vx: (Math.random() - 0.5) * 4, vy: (Math.random() - 0.5) * 4, a: 1 }); } else { gOver = true; window.playErrorBuzzer(); if (score > window.hScores[mode]) { window.hScores[mode] = score; localStorage.setItem("floating_piano_highscores", JSON.stringify(window.hScores)); window.upBrd(); } } }); document.getElementById("startGameBtn").addEventListener("click", () => init('Classic')); document.getElementById("btnClassic").addEventListener("click", () => init('Classic')); document.getElementById("btnZen").addEventListener("click", () => init('Zen')); (function loop() { if (!document.getElementById("pianoGameWindow")) return; requestAnimationFrame(loop); if (!window.inGameMode) return; let now = performance.now(), dt = (now - lastT) / 1000; lastT = now; if (!window.checkMin() && mode === 'Zen' && !gOver) { zTime -= dt; upScr(); if (zTime <= 0) { gOver = true; window.playErrorBuzzer(); if (score > window.hScores[mode]) { window.hScores[window.mode] = score; localStorage.setItem("floating_piano_highscores", JSON.stringify(window.hScores)); window.upBrd(); } } } if (gOver) { window.ctx.fillStyle = "rgba(0, 0, 0, 0.85)"; window.ctx.fillRect(0, 0, window.canvas.width, window.canvas.height); window.ctx.fillStyle = "#fff"; window.ctx.font = "bold 20px sans-serif"; window.ctx.textAlign = "center"; window.ctx.fillText(zTime <= 0 && mode === 'Zen' ? "TIME'S UP!" : "GAME OVER", window.canvas.width / 2, window.canvas.height / 2 - 10); window.ctx.font = "14px sans-serif"; window.ctx.fillText(`Score: ${score}`, window.canvas.width / 2, window.canvas.height / 2 + 15); return; } if (window.checkMin()) return; window.ctx.clearRect(0, 0, window.canvas.width, window.canvas.height); for (let i = tiles.length - 1; i >= 0; i--) { let t = tiles[i]; t.y += speed; for (let c = 0; c < COLS; c++) { if (c === t.blackIdx) { window.ctx.fillStyle = t.clicked ? "#e5e5e5" : "#1c1c1c"; } else { window.ctx.fillStyle = "#fffdf9"; } window.ctx.fillRect(c * COL_WIDTH, t.y, COL_WIDTH, ROW_HEIGHT); } if (t.y > window.canvas.height) { if (!t.clicked) { gOver = true; window.playErrorBuzzer(); } tiles.splice(i, 1); } } if (tiles.length < 6) tiles.push({ y: tiles[tiles.length - 1].y - ROW_HEIGHT, blackIdx: Math.floor(Math.random() * COLS), clicked: false }); window.ctx.strokeStyle = "#e8e5dc"; window.ctx.lineWidth = 2; for (let i = 1; i < COLS; i++) { window.ctx.beginPath(); window.ctx.moveTo(i * COL_WIDTH, 0); window.ctx.lineTo(i * COL_WIDTH, window.canvas.height); window.ctx.stroke(); } window.ctx.fillStyle = "rgba(0, 0, 0, 0.2)"; window.ctx.font = "bold 13px sans-serif"; window.ctx.textAlign = "center"; for(let i=0; i= 0; i--) { let p = parts[i]; p.x += p.vx; p.y += p.vy; p.a -= 0.05; if (p.a <= 0) parts.splice(i, 1); else { window.ctx.save(); window.ctx.globalAlpha = p.a; window.ctx.fillStyle = "#999"; window.ctx.beginPath(); window.ctx.arc(p.x, p.y, 2, 0, Math.PI * 2); window.ctx.fill(); window.ctx.restore(); } } })(); window.showMenu(); })(); (function() { window.currentComboCount = 0; window.floatingComboTexts = []; window.triggerComboPopup = function(x, y, baseText) { let displayString = baseText; let fontStyle = "bold 13px sans-serif"; let fillColour = "#3498db"; if (window.currentComboCount >= 5) { displayString += ` x${window.currentComboCount}!`; if (window.currentComboCount >= 20) { fillColour = "#e74c3c"; fontStyle = "bold 17px sans-serif"; } else if (window.currentComboCount >= 10) { fillColour = "#e67e22"; fontStyle = "bold 15px sans-serif"; } } window.floatingComboTexts.push({ x: x, y: y, text: displayString, color: fillColour, font: fontStyle, vy: -1.2, alpha: 1.0 }); }; const originalPlayChord = window.playChord; window.playChord = function(score) { window.currentComboCount++; if (originalPlayChord) originalPlayChord(score); }; const originalPlayErrorBuzzer = window.playErrorBuzzer; window.playErrorBuzzer = function() { window.currentComboCount = 0; if (originalPlayErrorBuzzer) originalPlayErrorBuzzer(); }; setInterval(() => { const canvas = document.getElementById("pianoCanvas"); if (!canvas || window.checkMin() || !window.inGameMode) return; const ctx = canvas.getContext("2d"); for (let i = window.floatingComboTexts.length - 1; i >= 0; i--) { let p = window.floatingComboTexts[i]; p.y += p.vy; p.alpha -= 0.04; if (p.alpha <= 0) { window.floatingComboTexts.splice(i, 1); } else { ctx.save(); ctx.globalAlpha = p.alpha; ctx.fillStyle = p.color; ctx.font = p.font; ctx.textAlign = "center"; ctx.fillText(p.text, p.x, p.y); ctx.restore(); } } }, 1000 / 60); window.addEventListener("keydown", (e) => { if (!window.inGameMode || window.checkMin() || window.activeBind !== null) return; setTimeout(() => { if (window.currentComboCount > 0 && window.floatingComboTexts.length < 50) { let targetRating = "Good"; if (window.currentComboCount > 15) targetRating = "Perfect!"; else if (window.currentComboCount > 5) targetRating = "Great!"; if(window.floatingComboTexts.length === 0 || window.floatingComboTexts[window.floatingComboTexts.length-1].text.indexOf(targetRating) === -1) { window.triggerComboPopup(window.canvas.width / 2, window.canvas.height - 80, targetRating); } } }, 10); }); })();