Offline Notepad View raw

Shared snapshot

Piano Tiles

(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 = `
    <div id="pianoHeader" style="background:#222; color:#fff; padding:8px; font-weight:bold; cursor:move; font-size:14px; display:flex; justify-content:space-between; align-items:center;">
        <span style="flex-grow:1; text-align:left; padding-left:5px;">🎹 Polyphonic Piano Tiles</span>
        <div style="display:flex; gap:5px; align-items:center;">
            <span id="menuPianoBtn" style="cursor:pointer; font-weight:bold; padding:0 4px; color:#2ecc71; font-family:sans-serif; font-size:11px;">🏠 Menu</span>
            <span id="bindPianoBtn" style="cursor:pointer; font-weight:bold; padding:0 4px; color:#4dabff; font-family:sans-serif; font-size:11px;">⚙️ Bind</span>
            <span id="minPianoBtn" style="cursor:pointer; font-weight:bold; padding:0 8px; color:#ffb300; font-family:sans-serif; font-size:16px; line-height:10px;">_</span>
            <span id="closePianoBtn" style="cursor:pointer; font-weight:bold; padding:0 8px; color:#ff4d4d; font-family:sans-serif;">✕</span>
        </div>
    </div>
    <div id="pianoContentWrapper" style="position:relative; min-height:480px;">
        <div id="gamePlayScreen" style="display:none; padding-top:10px;">
            <div style="margin-bottom:10px;">
                <button id="btnClassic" style="padding: 5px 10px; font-weight:bold; font-size:11px; background:#222; color:#fff; border:1px solid #555; cursor:pointer; border-radius:3px; margin-right:5px;">Classic</button>
                <button id="btnZen" style="padding: 5px 10px; font-weight:bold; font-size:11px; background:#f0f0f0; color:#333; border:1px solid #ccc; cursor:pointer; border-radius:3px;">Zen</button>
            </div>
            <div id="statPanel" style="font-size:15px; font-weight:bold; color:#111; margin-bottom:2px;">Classic Mode | Score: 0</div>
            <div id="leaderboardPanel" style="font-size:11px; font-weight:bold; color:#666; margin-bottom:8px;">Best - Classic: 0 | Zen: 0</div>
            <canvas id="pianoCanvas" width="300" height="420" style="background:#fff; border:2px solid #222; display:block; margin:0 auto;"></canvas>
            <div id="controlLabelsHint" style="color:#666; padding:8px 0; font-size:11px; font-family:sans-serif;"></div>
        </div>
        <div id="mainMenuScreen" style="padding:40px 20px; font-family:sans-serif;">
            <h2 style="margin:0 0 10px 0; font-family:Georgia, serif;">Piano Tiles Deluxe</h2>
            <p style="font-size:13px; color:#666; margin-bottom:30px;">Select your lane setup and difficulty velocity below.</p>
            <div style="margin-bottom:20px;">
                <label style="font-weight:bold; font-size:13px; display:block; margin-bottom:8px;">Game Mode Sizing:</label>
                <button id="setLanes4" style="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;">4 Tiles</button>
                <button id="setLanes6" style="padding:6px 16px; font-weight:bold; font-size:12px; background:#fff; color:#222; border:1px solid #ccc; border-radius:4px; cursor:pointer;">6 Tiles</button>
            </div>
            <div style="margin-bottom:35px; font-size:12px;">
                <label style="font-weight:bold; display:block; margin-bottom:6px;">Starting Speed Multiplier:</label>
                <input type="range" id="speedSlider" min="0.6" max="2.2" step="0.4" value="1.0" style="width:140px; cursor:pointer; vertical-align:middle;">
                <span id="speedLabel" style="font-weight:bold; margin-left:5px; color:#e67e22;">Medium</span>
            </div>
            <button id="startGameBtn" style="width:80%; padding:12px; font-weight:bold; font-size:15px; background:#2ecc71; color:white; border:none; border-radius:5px; cursor:pointer; box-shadow:0 4px 10px rgba(46,204,113,0.3);">PLAY GAME</button>
        </div>
    </div>
`;
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 = `
    <h4 style="margin:0 0 15px 0;">Configure Keybindings</h4>
    <div style="display:grid; grid-template-columns: 1fr 1fr; gap:8px; margin-bottom:15px;" id="dynamicBindGrid"></div>
    <button id="closeSettingsBtn" style="padding:6px 15px; background:#222; color:#fff; border:none; border-radius:3px; cursor:pointer;">Save & Close</button>
`;
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}: <button id="bindCol${i}" style="width:70px; padding:4px;">${window.KEYS_CONFIG[`col${i}`].label}</button>`;
            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<COLS; i++) arr.push(window.KEYS_CONFIG[`col${i}`].label);
        hint.innerText = "Controls: " + arr.join(" | ");
    }
};

function init(m) {
    window.inGameMode = true; document.getElementById("gamePlayScreen").style.display = "block"; document.getElementById("mainMenuScreen").style.display = "none";
    window.pMap(); mode = m || mode; score = 0; gOver = false; tiles = []; parts = []; zTime = 30.0; lastT = performance.now(); window.upBrd();
    speed = (mode === 'Classic' ? 2.8 : 4.2) * window.START_SPEED_SETTING;
    document.getElementById("btnClassic").style.background = mode === 'Classic' ? "#222" : "#f0f0f0";
    document.getElementById("btnClassic").style.color = mode === 'Classic' ? "#fff" : "#333";
    document.getElementById("btnZen").style.background = mode === 'Zen' ? "#222" : "#f0f0f0";
    document.getElementById("btnZen").style.color = mode === 'Zen' ? "#fff" : "#333";
    upScr(); for (let i = 0; i < 5; i++) tiles.push({ y: 150 - (i * ROW_HEIGHT), blackIdx: Math.floor(Math.random() * COLS), clicked: false });
}

function upScr() {
    document.getElementById("statPanel").innerText = mode === 'Classic' ? `Classic Mode | Score: ${score}` : `Zen Mode | Time: ${Math.max(0, zTime).toFixed(1)}s | Score: ${score}`;
}

window.addEventListener("keydown", (e) => {
    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<COLS; i++) window.ctx.fillText(window.KEYS_CONFIG[`col${i}`].label, i * COL_WIDTH + COL_WIDTH / 2, window.canvas.height - 15);
    for (let i = parts.length - 1; 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);
});

})();