const CAT_MODES = [ { name: "Classic", filter: "none" }, { name: "Shadow Cat", filter: "invert(1) drop-shadow(0 0 3px #cba6f7)" }, { name: "Ghost Cat", filter: "grayscale(1) brightness(1.7) opacity(0.55) drop-shadow(0 0 4px #89dceb)" }, { name: "CRT Cat", filter: "invert(48%) sepia(80%) saturate(2000%) hue-rotate(85deg) brightness(0.9) contrast(1.2)" }, { name: "Vaporwave Cat", filter: "invert(60%) sepia(90%) saturate(3000%) hue-rotate(280deg) brightness(0.95)" }, { name: "Gold Cat", filter: "invert(75%) sepia(85%) saturate(1400%) hue-rotate(8deg) brightness(1.0)" }, { name: "Sapphire Cat", filter: "invert(45%) sepia(90%) saturate(2500%) hue-rotate(200deg) brightness(1.0)" }, ]; const UNLOCK_EVERY = 5; // clicks needed to unlock each new mode const SPRITE = "/images/oneko.gif"; const IDLE_POS = "-96px -96px"; // idle frame of the sprite sheet (function catModes() { const oneko = document.getElementById("oneko"); if (!oneko) return; oneko.style.pointerEvents = "auto"; oneko.style.cursor = "pointer"; const ls = window.localStorage; let clicks = parseInt(ls.getItem("onekoClicks") || "0", 10); let mode = parseInt(ls.getItem("onekoMode") || "0", 10); const unlockedCount = () => Math.min(CAT_MODES.length, 1 + Math.floor(clicks / UNLOCK_EVERY)); const isUnlocked = (i) => i < unlockedCount(); const apply = (i) => (oneko.style.filter = CAT_MODES[i].filter); /* ---------- picker overlay (no visible trigger — press C to find it) ---------- */ const overlay = document.createElement("div"); overlay.className = "cat-picker"; overlay.hidden = true; overlay.innerHTML = ` `; document.body.appendChild(overlay); const grid = overlay.querySelector(".cat-grid"); function renderGrid() { grid.innerHTML = ""; CAT_MODES.forEach((c, i) => { const unlocked = isUnlocked(i); const opt = document.createElement(unlocked ? "button" : "div"); opt.className = "cat-option" + (unlocked ? "" : " locked") + (i === mode ? " current" : ""); if (unlocked) opt.type = "button"; const previewFilter = unlocked ? c.filter : "brightness(0) opacity(0.3)"; opt.innerHTML = ` ${unlocked ? c.name : "???"}`; if (unlocked) opt.addEventListener("click", () => selectMode(i)); grid.appendChild(opt); }); } function selectMode(i) { mode = i; ls.setItem("onekoMode", String(i)); apply(i); renderGrid(); } const openPicker = () => { renderGrid(); overlay.hidden = false; }; const closePicker = () => (overlay.hidden = true); const togglePicker = () => (overlay.hidden ? openPicker() : closePicker()); overlay .querySelector(".cat-picker-close") .addEventListener("click", closePicker); overlay.addEventListener("click", (e) => { if (e.target === overlay) closePicker(); }); document.addEventListener("keydown", (e) => { // ignore while typing in a field or with modifier keys held const typing = /^(INPUT|TEXTAREA|SELECT)$/.test(document.activeElement?.tagName || ""); if (e.key === "Escape" && !overlay.hidden) { closePicker(); } else if ( (e.key === "c" || e.key === "C") && !e.ctrlKey && !e.metaKey && !e.altKey && !typing ) { togglePicker(); } }); /* ---------- toast ---------- */ let toastEl, toastTimer; function toast(msg) { if (!toastEl) { toastEl = document.createElement("div"); toastEl.className = "cat-toast"; document.body.appendChild(toastEl); } toastEl.textContent = msg; toastEl.classList.remove("show"); void toastEl.offsetWidth; toastEl.classList.add("show"); clearTimeout(toastTimer); toastTimer = setTimeout(() => toastEl.classList.remove("show"), 1700); } /* ---------- init + cat click ---------- */ mode = Math.max(0, Math.min(mode, unlockedCount() - 1)); apply(mode); oneko.addEventListener("click", (e) => { e.preventDefault(); e.stopPropagation(); const before = unlockedCount(); clicks += 1; ls.setItem("onekoClicks", String(clicks)); const after = unlockedCount(); if (after > before) { mode = after - 1; toast(`✨ Unlocked: ${CAT_MODES[mode].name}!`); } else { mode = (mode + 1) % after; toast(CAT_MODES[mode].name); } ls.setItem("onekoMode", String(mode)); apply(mode); if (!overlay.hidden) renderGrid(); }); })();