BEST Cheat for Chess.com (Stockfish 17.1, 16.1 & 10.0.2, No Anti-Ban)

Triple model automated cheat engine (SF 17.1, SF 16.1, SF 10.0.2) with fully customizable UI and configuration settings.

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name          BEST Cheat for Chess.com (Stockfish 17.1, 16.1 & 10.0.2, No Anti-Ban)
// @namespace     http://tampermonkey.net/
// @version       6.9
// @description   Triple model automated cheat engine (SF 17.1, SF 16.1, SF 10.0.2) with fully customizable UI and configuration settings.
// @author        Ech0
// @copyright     2025, Ech0
// @license       MIT
// @match         https://www.chess.com/play/*
// @match         https://www.chess.com/game/*
// @match         https://www.chess.com/puzzles/*
// @match         https://www.chess.com/daily
// @grant         GM_getResourceText
// @grant         GM_getValue
// @grant         GM_setValue
// @grant         GM_xmlhttpRequest
// @resource      stockfish.js https://cdnjs.cloudflare.com/ajax/libs/stockfish.js/10.0.2/stockfish.js
// @run-at        document-idle
// ==/UserScript==
(function () {
    "use strict";
    const CONFIG = { BOARD_SEL: "chess-board, wc-chess-board", LOOP_MS: 50, API: { MAX_DEPTH: 18, MAX_TIME: 2000 } };
    const state = {
        board: null,
        isThinking: !1,
        ui: {},
        lastRawFEN: "N/A",
        lastSentFEN: "",
        lastSanitizedBoardFEN: "",
        lastMoveResult: "Waiting for analysis...",
        lastLiveResult: "Depth | Evaluation: Best move will appear here.",
        lastPayload: "N/A",
        lastResponse: "N/A",
        moveTargetTime: 0,
        calculatedDelay: 0,
        localEngine: null,
        localConfigSent: !1,
        currentCloudRequest: null,
        currentBestMove: null,
        analysisStartTime: 0,
        h: 180,
        s: 100,
        l: 50,
        newGameObserver: null,
        queueTimeout: null,
    };
    const DEFAULT_SETTINGS = {
        engineMode: "cloud",
        depth: 12,
        maxThinkingTime: 2000,
        contempt: 100,
        searchMoves: "",
        autoRun: !0,
        autoMove: !1,
        autoQueue: !1,
        minDelay: 0,
        maxDelay: 0,
        highlightColor: "#00eeff",
        innerOpacity: 0.6,
        outerOpacity: 0.2,
        gradientBias: 0,
        debugLogs: !1,
    };
    const settings = { ...DEFAULT_SETTINGS };
    const hexToRgb = (hex) => {
        const r = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
        return r ? { r: parseInt(r[1], 16), g: parseInt(r[2], 16), b: parseInt(r[3], 16) } : { r: 0, g: 0, b: 0 };
    };
    const rgbToHex = (r, g, b) => "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
    const rgbToHsl = (r, g, b) => {
        r /= 255;
        g /= 255;
        b /= 255;
        const max = Math.max(r, g, b),
            min = Math.min(r, g, b);
        let h,
            s,
            l = (max + min) / 2;
        if (max === min) h = s = 0;
        else {
            const d = max - min;
            s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
            switch (max) {
                case r:
                    h = (g - b) / d + (g < b ? 6 : 0);
                    break;
                case g:
                    h = (b - r) / d + 2;
                    break;
                case b:
                    h = (r - g) / d + 4;
                    break;
            }
            h /= 6;
        }
        return { h: h * 360, s: s * 100, l: l * 100 };
    };
    const hslToRgb = (h, s, l) => {
        let r, g, b;
        h /= 360;
        s /= 100;
        l /= 100;
        if (s === 0) r = g = b = l;
        else {
            const hue2rgb = (p, q, t) => {
                if (t < 0) t += 1;
                if (t > 1) t -= 1;
                if (t < 1 / 6) return p + (q - p) * 6 * t;
                if (t < 1 / 2) return q;
                if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
                return p;
            };
            const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
            const p = 2 * l - q;
            r = hue2rgb(p, q, h + 1 / 3);
            g = hue2rgb(p, q, h);
            b = hue2rgb(p, q, h - 1 / 3);
        }
        return { r: Math.round(r * 255), g: Math.round(g * 255), b: Math.round(b * 255) };
    };
    function getRawBoardFEN() {
        if (!state.board?.game) return null;
        try {
            if (typeof state.board.game.getFEN === "function") return state.board.game.getFEN();
            if (typeof state.board.game.fen === "string") return state.board.game.fen;
            if (state.board.game.getPosition) return state.board.game.getPosition();
        } catch (e) {}
        return null;
    }
    function sanitizeFEN(rawFEN) {
        if (!rawFEN) return "";
        let parts = rawFEN.replace(/\s+/g, " ").trim().split(" ");
        if (parts.length < 6) {
            const def = ["w", "-", "-", "0", "1"];
            for (let i = parts.length; i < 6; i++) parts.push(def[i - 1]);
        }
        if (parts[3] && parts[3] !== "-") parts[3] = parts[3].toLowerCase();
        return parts.join(" ");
    }
    function loadLocalEngine() {
        if (state.localEngine) return;
        try {
            const scriptContent = GM_getResourceText("stockfish.js");
            if (!scriptContent) throw new Error("Stockfish resource not found.");
            const blob = new Blob([scriptContent], { type: "application/javascript" });
            state.localEngine = new Worker(URL.createObjectURL(blob));
            state.localEngine.onmessage = handleLocalMessage;
            state.localEngine.onerror = (e) => handleError("Local Engine Error", e);
            [
                "ucinewgame",
                "isready",
                "setoption name MultiPV value 1",
                `setoption name Contempt value ${settings.contempt}`,
            ].forEach((c) => state.localEngine.postMessage(c));
            console.log("Stockfish 10 Local Loaded.");
        } catch (e) {
            handleError("Engine Load Fail", e);
        }
    }
    function analyze(depth = settings.depth, fenOverride = null, isRetry = !1) {
        if (state.isThinking && !fenOverride && !isRetry) return;
        let finalFEN = fenOverride || sanitizeFEN(getRawBoardFEN());
        if (!finalFEN) return;
        state.lastRawFEN = finalFEN;
        state.lastSentFEN = finalFEN;
        if (!fenOverride) state.lastSanitizedBoardFEN = finalFEN;
        state.isThinking = !0;
        state.analysisStartTime = performance.now();
        const minMs = settings.minDelay * 1000;
        const maxMs = settings.maxDelay * 1000;
        const delay = Math.random() * (maxMs - minMs) + minMs;
        state.moveTargetTime = performance.now() + delay;
        state.calculatedDelay = (delay / 1000).toFixed(2);
        updateUI();
        if (settings.engineMode === "cloud") {
            analyzeCloud(finalFEN, depth, isRetry);
        } else if (settings.engineMode === "sfonline") {
            analyzeSF16(finalFEN, depth);
        } else {
            analyzeLocal(finalFEN, depth);
        }
    }
    function analyzeCloud(finalFEN, depth, isRetry) {
        const actualDepth = Math.min(depth, 18);
        const payload = {
            fen: finalFEN,
            depth: actualDepth,
            maxThinkingTime: Math.min(settings.maxThinkingTime, CONFIG.API.MAX_TIME),
            taskId: Math.random().toString(36).substring(7),
        };
        if (settings.searchMoves.trim()) payload.searchmoves = settings.searchMoves.trim();
        state.lastPayload = `POST https://chess-api.com/v1\n${JSON.stringify(payload, null, 2)}`;
        if (state.ui.liveOutput)
            state.ui.liveOutput.innerHTML = isRetry ? "♻️ Retrying Safe FEN..." : "☁️ SF17 Analysis...";
        updateUI();
        state.currentCloudRequest = GM_xmlhttpRequest({
            method: "POST",
            url: "https://chess-api.com/v1",
            headers: { "Content-Type": "application/json" },
            data: JSON.stringify(payload),
            timeout: 15000,
            onload: (res) => handleCloudResponse(res, finalFEN, actualDepth, isRetry),
            onerror: (err) => handleError("Network Error", err),
            ontimeout: () => handleError("Timeout (15s)"),
        });
    }
    function analyzeSF16(finalFEN, depth) {
        const actualDepth = Math.min(depth, 15);
        const encodedFEN = encodeURIComponent(finalFEN);
        const url = `https://stockfish.online/api/s/v2.php?fen=${encodedFEN}&depth=${actualDepth}&mode=bestmove`;
        state.lastPayload = `GET ${url}`;
        if (state.ui.liveOutput) state.ui.liveOutput.innerHTML = "☁️ SF16.1 Analysis...";
        updateUI();
        state.currentCloudRequest = GM_xmlhttpRequest({
            method: "GET",
            url: url,
            timeout: 20000,
            onload: (res) => handleSF16Response(res),
            onerror: (err) => handleError("Network Error (SF16)", err),
            ontimeout: () => handleError("Timeout (SF16 20s)"),
        });
    }
    function handleSF16Response(response) {
        state.isThinking = !1;
        state.lastResponse = response.responseText;
        try {
            if (response.status !== 200) throw new Error(`HTTP ${response.status}`);
            let data;
            try {
                data = JSON.parse(response.responseText);
            } catch (e) {
                throw new Error("Invalid JSON from SF16");
            }
            if (!data.success || !data.bestmove) throw new Error(data.data || "Unknown SF16 Error");
            const bestMove = data.bestmove.split(" ")[1] || data.bestmove;
            const duration = ((performance.now() - state.analysisStartTime) / 1000).toFixed(2);
            let evalScore = data.evaluation;
            let mate = data.mate;
            processBestMove(
                bestMove,
                evalScore,
                mate,
                data.continuation ? data.continuation.split(" ") : null,
                null,
                duration
            );
        } catch (e) {
            handleError("SF16 API Error", e);
        }
        updateUI();
    }
    function handleCloudResponse(response, sentFEN, depth, isRetry) {
        state.isThinking = !1;
        state.lastResponse = response.responseText;
        if (response.responseText.includes("HIGH_USAGE") || response.status === 429) {
            state.lastMoveResult = "⚠️ API COOLDOWN";
            state.lastLiveResult = "<span style='color:red; font-weight:bold;'>HIGH USAGE: Cooldown ~30-60m.</span>";
            updateUI();
            return;
        }
        try {
            if (response.status !== 200) throw new Error(`HTTP ${response.status}`);
            let rawData;
            try {
                rawData = JSON.parse(response.responseText);
            } catch (e) {
                throw new Error("Invalid JSON");
            }
            const result = Array.isArray(rawData) ? rawData[0] : rawData;
            if (!result || result.error || result.status === "error") {
                const errText = result?.error || result?.message || "Unknown Error";
                if (errText.includes("HIGH_USAGE")) {
                    state.lastMoveResult = "⚠️ API COOLDOWN";
                    state.lastLiveResult =
                        "<span style='color:red; font-weight:bold;'>HIGH USAGE: Cooldown ~30-60m.</span>";
                    updateUI();
                    return;
                }
                if ((errText.includes("FEN") || errText.includes("VALIDATION")) && !isRetry) {
                    const parts = sentFEN.split(" ");
                    if (parts.length >= 4 && parts[3] !== "-") {
                        parts[3] = "-";
                        analyze(depth, parts.join(" "), !0);
                        return;
                    }
                }
                throw new Error(errText);
            }
            if (result.move || result.bestmove) {
                const duration = ((performance.now() - state.analysisStartTime) / 1000).toFixed(2);
                processBestMove(
                    result.move || result.bestmove,
                    result.eval,
                    result.mate,
                    result.continuationArr,
                    result.winChance,
                    duration
                );
            } else {
                state.lastMoveResult = "⚠️ No move returned.";
            }
        } catch (e) {
            handleError("API Error", e);
        }
        updateUI();
    }
    function analyzeLocal(fen, depth) {
        if (!state.localEngine) loadLocalEngine();
        if (!state.localEngine) return;
        if (!state.localConfigSent) {
            state.localEngine.postMessage(`setoption name Contempt value ${settings.contempt}`);
            state.localConfigSent = !0;
        }
        const actualDepth = Math.min(depth, 23);
        const cmds = [`position fen ${fen}`, `go depth ${actualDepth}`];
        state.lastPayload = `Worker CMDs:\n${cmds.join("\n")}`;
        state.ui.liveOutput.innerHTML = "⚡ Local Analysis...";
        updateUI();
        cmds.forEach((cmd) => state.localEngine.postMessage(cmd));
    }
    function handleLocalMessage(e) {
        const msg = e.data;
        if (typeof msg !== "string") return;
        state.lastResponse =
            (state.lastResponse.length > 500 ? "..." + state.lastResponse.slice(-500) : state.lastResponse) +
            "\n" +
            msg;
        if (msg.startsWith("info") && msg.includes("depth") && msg.includes("score")) {
            const depthMatch = msg.match(/depth (\d+)/);
            const scoreMatch = msg.match(/score (cp|mate) (-?\d+)/);
            const pvMatch = msg.match(/ pv (.*)/);
            if (depthMatch && scoreMatch) {
                const depth = depthMatch[1];
                let val = parseInt(scoreMatch[2]);
                const type = scoreMatch[1];
                const fenParts = state.lastSentFEN ? state.lastSentFEN.split(" ") : [];
                const sideToMove = fenParts.length > 1 ? fenParts[1] : "w";
                if (sideToMove === "b") val = -val;
                const pv = pvMatch ? pvMatch[1] : "";
                let scoreTxt;
                if (type === "mate") {
                    scoreTxt = "M" + Math.abs(val);
                    if (val < 0) scoreTxt = "-" + scoreTxt;
                } else {
                    scoreTxt = (val > 0 ? "+" : "") + (val / 100).toFixed(2);
                }
                const duration = ((performance.now() - state.analysisStartTime) / 1000).toFixed(2);
                if (pv) {
                    const best = pv.split(" ")[0];
                    highlightMove(best);
                    state.lastMoveResult = `⏳ D${depth}: <span style="font-weight:bold; color:var(--bot-primary);">${best}</span>`;
                }
                state.lastLiveResult = `
                    <div style="display:flex; justify-content:space-between; align-items:center; font-weight:bold;">
                        <span style="color:var(--bot-primary); font-size:1.1em;">${scoreTxt} <span style="font-size:0.7em; color:#aaa; font-weight:normal;">(${duration}s)</span></span>
                        <span style="font-size:0.8em; color:#aaa;">(Local Depth ${depth})</span>
                    </div>
                    <div style="margin-top:5px; font-size:0.85em; color:#bbb; width:100%; max-width:100%; box-sizing:border-box; word-wrap:break-word; overflow-wrap:anywhere; white-space:normal;">
                        <span style="color:#888;">PV:</span> ${pv.split(" ").slice(0, 5).join(" ")}...
                    </div>
                 `;
                updateUI();
            }
        }
        if (msg.startsWith("bestmove")) {
            state.isThinking = !1;
            const parts = msg.split(" ");
            const bestMove = parts[1];
            if (bestMove && bestMove !== "(none)") {
                const duration = ((performance.now() - state.analysisStartTime) / 1000).toFixed(2);
                processBestMove(bestMove, undefined, undefined, undefined, undefined, duration);
            } else state.lastMoveResult = "⚠️ No move found";
            updateUI();
        }
    }
    function processBestMove(bestMove, evalScore, mate, continuationArr, winChance, duration) {
        state.currentBestMove = bestMove;
        highlightMove(bestMove);
        let scoreTxt = "";
        let pvStr = "N/A";
        if (evalScore !== undefined || mate !== undefined) {
            if (mate) {
                scoreTxt = `M${Math.abs(mate)}`;
                if (mate < 0) scoreTxt = "-" + scoreTxt;
            } else {
                const sc = parseFloat(evalScore);
                scoreTxt = (sc > 0 ? "+" : "") + sc;
            }
            if (continuationArr) pvStr = continuationArr.join(" ");
        }
        const durHtml = duration
            ? `<span style="font-size:0.7em; color:#aaa; font-weight:normal;">(${duration}s)</span>`
            : "";
        state.lastMoveResult = `✅ Best: <span style="font-weight:bold; color:var(--bot-primary);">${bestMove}</span>`;
        let wcHtml = "";
        if (winChance) wcHtml = `<span style="color:#aaa; font-size:0.8em;">(${Math.round(winChance)}%)</span>`;
        state.lastLiveResult = `
            <div style="display:flex; justify-content:space-between; align-items:center; font-weight:bold;">
                <span style="color:var(--bot-primary); font-size:1.1em;">${scoreTxt} ${durHtml}</span>
                <span>${wcHtml}</span>
            </div>
            <div style="margin-top:5px; font-size:0.85em; color:#bbb; width:100%; max-width:100%; box-sizing:border-box; word-wrap:break-word; overflow-wrap:anywhere; white-space:normal;">
                <span style="color:#888;">PV:</span> ${pvStr}
            </div>
        `;
        if (settings.autoMove) triggerAutoMove();
    }
    function triggerAutoMove() {
        if (!state.currentBestMove || !state.board?.game) return;
        const turn = state.board.game.getTurn();
        const playingAs = state.board.game.getPlayingAs();
        if (turn !== playingAs) return;
        const wait = Math.max(0, state.moveTargetTime - performance.now());
        setTimeout(() => playMove(state.currentBestMove), wait);
    }
    function handleError(type, err) {
        state.isThinking = !1;
        console.error(type, err);
        state.lastResponse = `${type}: ${err.message || err}`;
        state.lastMoveResult = `❌ ${type}`;
        updateUI();
    }
    function playMove(move) {
        if (!state.board?.game) return;
        const from = move.substring(0, 2);
        const to = move.substring(2, 4);
        const currentRaw = getRawBoardFEN();
        if (currentRaw && sanitizeFEN(currentRaw).split(" ")[0] !== state.lastSentFEN.split(" ")[0]) return;
        for (const m of state.board.game.getLegalMoves()) {
            if (m.from === from && m.to === to) {
                const promotion = move.length > 4 ? move.substring(4, 5) : "q";
                state.board.game.move({ ...m, promotion, animate: !0, userGenerated: !0 });
                return;
            }
        }
    }
    function highlightMove(move) {
        document.querySelectorAll(".bot-highlight").forEach((el) => el.remove());
        if (!move) return;
        const { highlightColor, innerOpacity, outerOpacity, gradientBias } = settings;
        const { r, g, b } = hexToRgb(highlightColor);
        const col = (a) => `rgba(${r}, ${g}, ${b}, ${a})`;
        const from = move.substring(0, 2);
        const to = move.substring(2, 4);
        [from, to].forEach((alg) => {
            const sqId = `${alg.charCodeAt(0) - 96}${alg.charAt(1)}`;
            const div = document.createElement("div");
            div.className = `square-${sqId} bot-highlight`;
            const biasPct = gradientBias + "%";
            div.style.cssText = `
                position: absolute; pointer-events: none; z-index: 200;
                width: 12.5%; height: 12.5%; box-sizing: border-box;
                background: radial-gradient(closest-side, ${col(innerOpacity)} ${biasPct}, ${col(outerOpacity)} 100%);
            `;
            state.board.appendChild(div);
        });
    }
    function toggleAutoQueue() {
        if (state.newGameObserver) {
            state.newGameObserver.disconnect();
            state.newGameObserver = null;
        }
        if (state.queueTimeout) {
            clearTimeout(state.queueTimeout);
            state.queueTimeout = null;
        }
        if (settings.autoQueue) {
            state.newGameObserver = new MutationObserver((mutations) => {
                const btns = Array.from(document.querySelectorAll("button"));
                const newGameBtn = btns.find((b) => {
                    const txt = b.innerText.toLowerCase();
                    return txt.includes("new") && !txt.includes("rematch") && b.offsetParent !== null;
                });
                if (newGameBtn) {
                    if (!state.queueTimeout) {
                        state.queueTimeout = setTimeout(() => {
                            newGameBtn.click();
                            state.queueTimeout = null;
                        }, 500);
                    }
                }
            });
            state.newGameObserver.observe(document.body, { childList: !0, subtree: !0 });
        }
    }
    function saveSetting(key, val) {
        GM_setValue(`bot_${key}`, val);
    }
    function resetSettings() {
        const currentModel = settings.engineMode;
        Object.assign(settings, DEFAULT_SETTINGS);
        settings.engineMode = currentModel;
        Object.keys(DEFAULT_SETTINGS).forEach((k) => {
            if (k !== "engineMode") saveSetting(k, DEFAULT_SETTINGS[k]);
        });
        saveSetting("engineMode", currentModel);
        const hsl = rgbToHsl(...Object.values(hexToRgb(settings.highlightColor)));
        state.h = hsl.h;
        state.s = hsl.s;
        state.l = hsl.l;
        toggleAutoQueue();
        createUI();
    }
    function syncColor() {
        const rgb = hslToRgb(state.h, state.s, state.l);
        const hex = rgbToHex(rgb.r, rgb.g, rgb.b);
        settings.highlightColor = hex;
        saveSetting("highlightColor", hex);
        if (state.ui.inpR) {
            state.ui.inpR.value = rgb.r;
            state.ui.inpG.value = rgb.g;
            state.ui.inpB.value = rgb.b;
            state.ui.inpHex.value = hex;
            state.ui.colorPreview.style.background = hex;
            state.ui.sliderH.value = state.h;
            state.ui.sliderS.value = state.s;
            state.ui.sliderL.value = state.l;
        }
        highlightMove(state.currentBestMove);
    }
    function createUI() {
        if (document.getElementById("enginePanel")) document.getElementById("enginePanel").remove();
        if (document.getElementById("modalOv")) document.getElementById("modalOv").remove();
        Object.keys(DEFAULT_SETTINGS).forEach((k) => {
            const saved = GM_getValue(`bot_${k}`);
            if (saved !== undefined) settings[k] = saved;
        });
        const initHsl = rgbToHsl(...Object.values(hexToRgb(settings.highlightColor)));
        state.h = initHsl.h;
        state.s = initHsl.s;
        state.l = initHsl.l;
        const savedW = GM_getValue("panelW", "33vw");
        const savedH = GM_getValue("panelH", "100vh");
        const savedX = GM_getValue("pX", "auto");
        const savedY = GM_getValue("pY", "0");
        const isMini = GM_getValue("isMini", !1);
        const style = `
            :root { --bot-bg:#222; --bot-b:#444; --bot-p:#81b64c; --bot-t:#eee; --bot-inp:#333; }
            #enginePanel * { box-sizing: border-box; }
            #enginePanel {
                position:fixed; width:${savedW}; height:${savedH};
                min-width:300px; min-height:300px;
                background:var(--bot-bg); border:1px solid var(--bot-b);
                color:var(--bot-t); z-index:9999; font-family:sans-serif;
                box-shadow:-4px 0 15px rgba(0,0,0,0.5); font-size:14px;
                display:flex; flex-direction:column; resize:both; overflow:hidden;
            }
            #enginePanel.minified #panelContent { display:none; }
            #enginePanel.minified { height:38px !important; resize:none; min-height:0 !important; overflow:hidden !important; border-bottom:0; }
            #panelHeader {
                background:var(--bot-p); color:#000; padding:10px; font-weight:bold;
                display:flex; justify-content:space-between; align-items:center;
                cursor:move; flex:none; user-select:none; height:38px;
            }
            #panelContent { padding:15px; display:flex; flex-direction:column; gap:10px; overflow-y:auto; flex:1; min-height: 0; }
            .sect { border-top:1px solid #333; padding-top:10px; display:flex; flex-direction:column; gap:8px; }
            .sect-title { font-size:0.85em; color:#aaa; font-weight:bold; text-transform:uppercase; margin-bottom:4px; }
            .row { display:flex; justify-content:space-between; align-items:center; gap: 10px; }
            input, select { background:var(--bot-inp); color:var(--bot-t); border:1px solid var(--bot-b); padding:4px; border-radius:4px; }
            input[type="number"] { width: 60px; }
            select { width: 120px; }
            input[type="text"] { flex:1; }
            button { background:var(--bot-p); border:none; padding:10px; color:#000; font-weight:bold; cursor:pointer; border-radius:4px; }
            button:disabled { opacity:0.6; cursor:not-allowed; }
            #custBtn { background:#00bcd4; margin-top:5px; }
            .log-box {
                background:#111; padding:8px; font-family:monospace; font-size:0.75em; border-radius:4px;
                overflow-y:auto; word-break:break-all; white-space:pre-wrap; border:1px solid #333; height:100px; resize:vertical;
                user-select: text !important; -webkit-user-select: text !important; cursor: text;
            }
            #statusBox { background:#003344; padding:8px; border:1px solid #00bcd4; border-radius:4px; font-size:0.9em; min-height:40px; width: 100%; flex-shrink: 0; display: flex; flex-direction: column; gap: 5px; }
            #modalOv { position:fixed; top:0; left:0; width:100%; height:100%; background:rgba(0,0,0,0.8); z-index:10000; display:none; justify-content:center; align-items:center; }
            #modal { background:var(--bot-bg); padding:20px; border-radius:8px; width:350px; border:1px solid var(--bot-b); }
            #modal * { color:var(--bot-t); }
            #modal label { color: #ffffff !important; opacity: 1 !important; font-weight: 600; }
            #modal input[type="color"] { height: 24px; padding: 0; width: 40px; cursor:pointer; border: none; }
            #modal select { height: 24px; padding: 0 4px; font-size: 0.9em; }
            .show-cloud { display: none; } .show-local { display: none; }
            body.mode-cloud .show-cloud { display: flex; }
            body.mode-local .show-local { display: flex; }
            .rgb-inputs { display: flex; gap: 5px; flex: 1; justify-content: flex-end; }
            .rgb-inputs input { width: 45px; text-align: center; }
            #sliderH { background: linear-gradient(to right, #f00, #ff0, #0f0, #0ff, #00f, #f0f, #f00); height: 10px; border-radius: 5px; appearance: none; }
            #sliderH::-webkit-slider-thumb { -webkit-appearance: none; width: 15px; height: 15px; border-radius: 50%; background: #fff; cursor: pointer; border: 1px solid #000; }
        `;
        const html = `
            <style>${style}</style>
            <div id="enginePanel" class="${isMini ? "minified" : ""}">
                <div id="panelHeader">
                    <div style="display:flex; align-items:center; gap:5px;">
                        <span>Engine Controls</span>
                        <span id="minBtn" style="cursor:pointer; padding:0 5px;">▼</span>
                    </div>
                    <button id="btnReset" style="padding:2px 8px; font-size:0.8em; background:#0002; color:#000; cursor:pointer;">Reset Defaults</button>
                </div>
                <div id="panelContent">
                    <div id="statusBox">${state.lastLiveResult}</div>
                    <div id="moveResult" style="background:#333; padding:5px; border-radius:4px; text-align:center;">${state.lastMoveResult}</div>
                    <div class="sect">
                        <div class="sect-title">Engine Config</div>
                        <div class="row">
                            <label>Model</label>
                            <select id="selMode" style="width:240px;">
                                <option value="cloud">SF 17.1.0(cloud 0.25-0.48s)</option>
                                <option value="sfonline">SF 16.1.0(cloud 0.15-11.0s)</option>
                                <option value="local">SF 10.0.2(local 0.00-75.0s)</option>
                            </select>
                        </div>
                        <div class="row"><label>Depth (Max <span id="lblMaxDepth">18</span>)</label><input type="number" id="inpDepth" min="1" max="18" value="${settings.depth}"></div>
                        <div class="row show-cloud"><label>Max Time (ms)</label><input type="number" id="inpTime" value="${settings.maxThinkingTime}"></div>
                        <div class="row show-local"><label>Contempt (-100→100)</label><input type="number" id="inpContempt" min="-100" max="100" value="${settings.contempt}"></div>
                        <div class="row show-cloud"><label>Search</label><input type="text" id="inpSearch" value="${settings.searchMoves}"></div>
                    </div>
                    <div class="sect">
                        <div class="sect-title">Automation</div>
                        <div class="row">
                            <label><input type="checkbox" id="chkRun" ${settings.autoRun ? "checked" : ""}> Auto-Analyze</label>
                            <label><input type="checkbox" id="chkMove" ${settings.autoMove ? "checked" : ""}> Auto-Move</label>
                            <label><input type="checkbox" id="chkQueue" ${settings.autoQueue ? "checked" : ""}> Auto-Queue</label>
                        </div>
                        <div class="row"><label>Randomized Delay (s)</label><div style="display:flex; gap:5px;"><input type="number" id="inpMin" style="width:50px" value="${settings.minDelay}"><span>-</span><input type="number" id="inpMax" style="width:50px" value="${settings.maxDelay}"></div></div>
                        <div style="font-size:0.7em; color:#888; text-align:right;" id="delayDisplay">Next: N/A</div>
                    </div>
                    <button id="btnAnalyze">Analyze Position</button>
                    <button id="custBtn">🎨 Visual Customization</button>
                    <div class="sect">
                         <div class="row"><label style="cursor:pointer"><input type="checkbox" id="chkDebug" ${settings.debugLogs ? "checked" : ""}> Show Debug Logs</label></div>
                         <div id="debugArea" style="display:${settings.debugLogs ? "block" : "none"}">
                             <div class="log-box" id="sentCommandOutput"></div>
                             <div class="log-box" id="receivedMessageOutput"></div>
                         </div>
                    </div>
                </div>
            </div>
            <div id="modalOv">
                <div id="modal">
                    <div class="row" style="border-bottom:1px solid #444; padding-bottom:10px; margin-bottom:10px;">
                        <h3 style="margin:0; color:var(--bot-p);">Visual Settings</h3>
                        <button id="modalClose" style="padding:2px 8px; font-weight:bold; cursor:pointer;">×</button>
                    </div>
                    <div class="sect" style="border:none; padding:0;">
                         <div class="row"><label>Inner Opacity</label><input type="range" id="visInnerOp" min="0" max="1" step="0.1" value="${settings.innerOpacity}"></div>
                         <div class="row"><label>Outer Opacity</label><input type="range" id="visOuterOp" min="0" max="1" step="0.1" value="${settings.outerOpacity}"></div>
                         <div class="row" style="padding-bottom:10px;"><label>Gradient Bias</label><input type="range" id="visBias" min="0" max="100" step="5" value="${settings.gradientBias}"></div>
                    </div>
                    <div class="sect">
                        <div class="sect-title" style="margin-bottom:10px;">Color Editor</div>
                        <div style="display:flex; flex-direction:column; gap:10px;">
                            <div class="row" style="width:100%;">
                                <div id="colorPreview" style="width:30px; height:30px; border-radius:50%; border:2px solid #555; background:${settings.highlightColor};"></div>
                                <div class="rgb-inputs">
                                   <input type="number" id="inpR" min="0" max="255" placeholder="R">
                                   <input type="number" id="inpG" min="0" max="255" placeholder="G">
                                   <input type="number" id="inpB" min="0" max="255" placeholder="B">
                                </div>
                            </div>
                            <div class="row"><label>Hue</label><input type="range" id="sliderH" min="0" max="360" value="${state.h}"></div>
                            <div class="row"><label>Saturation</label><input type="range" id="sliderS" min="0" max="100" value="${state.s}"></div>
                            <div class="row"><label>Brightness</label><input type="range" id="sliderL" min="0" max="100" value="${state.l}"></div>
                            <div class="row" style="width:100%; margin-top:5px;"><label>Hex</label><input type="text" id="inpHex" style="text-transform:uppercase; text-align:center;"></div>
                        </div>
                    </div>
                </div>
            </div>
        `;
        document.body.insertAdjacentHTML("beforeend", html);
        const panel = document.getElementById("enginePanel");
        const computed = window.getComputedStyle(panel);
        panel.style.width = computed.width;
        if (!isMini) {
            panel.style.height = computed.height;
        }
        if (savedX === "auto") {
            panel.style.right = "0px";
            panel.style.left = "auto";
        } else {
            panel.style.left = savedX + "px";
        }
        panel.style.top = savedY + "px";
        state.ui = {
            panel: panel,
            header: document.getElementById("panelHeader"),
            minBtn: document.getElementById("minBtn"),
            moveResult: document.getElementById("moveResult"),
            liveOutput: document.getElementById("statusBox"),
            logSent: document.getElementById("sentCommandOutput"),
            logRec: document.getElementById("receivedMessageOutput"),
            delayDisplay: document.getElementById("delayDisplay"),
            btnAnalyze: document.getElementById("btnAnalyze"),
            selMode: document.getElementById("selMode"),
            inpDepth: document.getElementById("inpDepth"),
            inpTime: document.getElementById("inpTime"),
            inpContempt: document.getElementById("inpContempt"),
            inpSearch: document.getElementById("inpSearch"),
            chkRun: document.getElementById("chkRun"),
            chkMove: document.getElementById("chkMove"),
            chkQueue: document.getElementById("chkQueue"),
            inpMin: document.getElementById("inpMin"),
            inpMax: document.getElementById("inpMax"),
            chkDebug: document.getElementById("chkDebug"),
            debugArea: document.getElementById("debugArea"),
            btnReset: document.getElementById("btnReset"),
            lblMaxDepth: document.getElementById("lblMaxDepth"),
            custBtn: document.getElementById("custBtn"),
            modal: document.getElementById("modalOv"),
            modalClose: document.getElementById("modalClose"),
            visInnerOp: document.getElementById("visInnerOp"),
            visOuterOp: document.getElementById("visOuterOp"),
            visBias: document.getElementById("visBias"),
            sliderH: document.getElementById("sliderH"),
            sliderS: document.getElementById("sliderS"),
            sliderL: document.getElementById("sliderL"),
            colorPreview: document.getElementById("colorPreview"),
            inpR: document.getElementById("inpR"),
            inpG: document.getElementById("inpG"),
            inpB: document.getElementById("inpB"),
            inpHex: document.getElementById("inpHex"),
        };
        state.ui.selMode.value = settings.engineMode;
        const bind = (el, key, type = "val") => {
            if (!el) return;
            el.addEventListener(type === "chk" ? "change" : "input", (e) => {
                const val =
                    type === "chk" ? e.target.checked : type === "num" ? parseFloat(e.target.value) : e.target.value;
                settings[key] = val;
                saveSetting(key, val);
                if (key === "autoMove" && val === !0) triggerAutoMove();
                if (key === "autoQueue") toggleAutoQueue();
                if (["innerOpacity", "outerOpacity", "gradientBias"].includes(key))
                    highlightMove(state.currentBestMove);
                updateUI();
            });
        };
        state.ui.btnAnalyze.onclick = () => analyze();
        state.ui.btnReset.onclick = resetSettings;
        state.ui.custBtn.onclick = () => (state.ui.modal.style.display = "flex");
        state.ui.modalClose.onclick = () => (state.ui.modal.style.display = "none");
        state.ui.minBtn.onclick = () => {
            const isMini = state.ui.panel.classList.toggle("minified");
            GM_setValue("isMini", isMini);
        };
        [state.ui.sliderH, state.ui.sliderS, state.ui.sliderL].forEach((el) => {
            el.oninput = () => {
                state.h = parseFloat(state.ui.sliderH.value);
                state.s = parseFloat(state.ui.sliderS.value);
                state.l = parseFloat(state.ui.sliderL.value);
                syncColor();
            };
        });
        [state.ui.inpR, state.ui.inpG, state.ui.inpB].forEach((el) => {
            el.oninput = () => {
                const r = parseInt(state.ui.inpR.value) || 0,
                    g = parseInt(state.ui.inpG.value) || 0,
                    b = parseInt(state.ui.inpB.value) || 0;
                const hsl = rgbToHsl(r, g, b);
                state.h = hsl.h;
                state.s = hsl.s;
                state.l = hsl.l;
                syncColor();
            };
        });
        state.ui.inpHex.onchange = (e) => {
            const hex = e.target.value;
            if (/^#[0-9A-F]{6}$/i.test(hex)) {
                const rgb = hexToRgb(hex);
                const hsl = rgbToHsl(rgb.r, rgb.g, rgb.b);
                state.h = hsl.h;
                state.s = hsl.s;
                state.l = hsl.l;
                syncColor();
            }
        };
        syncColor();
        state.ui.header.onmousedown = (e) => {
            if (e.target.id === "minBtn" || e.target.id === "btnReset") return;
            e.preventDefault();
            const startX = e.clientX - state.ui.panel.offsetLeft;
            const startY = e.clientY - state.ui.panel.offsetTop;
            const onMove = (mv) => {
                let x = mv.clientX - startX;
                let y = mv.clientY - startY;
                x = Math.max(0, Math.min(x, window.innerWidth - state.ui.panel.offsetWidth));
                y = Math.max(0, Math.min(y, window.innerHeight - state.ui.panel.offsetHeight));
                state.ui.panel.style.left = x + "px";
                state.ui.panel.style.top = y + "px";
                state.ui.panel.style.right = "auto";
                GM_setValue("pX", x);
                GM_setValue("pY", y);
            };
            document.addEventListener("mousemove", onMove);
            document.onmouseup = () => document.removeEventListener("mousemove", onMove);
        };
        new ResizeObserver(() => {
            if (!state.ui.panel.classList.contains("minified")) {
                GM_setValue("panelW", state.ui.panel.style.width);
                GM_setValue("panelH", state.ui.panel.style.height);
            }
        }).observe(state.ui.panel);
        state.ui.selMode.onchange = (e) => {
            settings.engineMode = e.target.value;
            saveSetting("engineMode", e.target.value);
            state.isThinking = !1;
            if (settings.engineMode === "local") loadLocalEngine();
            updateUI();
        };
        state.ui.chkDebug.onchange = (e) => {
            settings.debugLogs = e.target.checked;
            saveSetting("debugLogs", e.target.checked);
            updateUI();
        };
        bind(state.ui.inpDepth, "depth", "num");
        bind(state.ui.inpTime, "maxThinkingTime", "num");
        bind(state.ui.inpContempt, "contempt", "num");
        bind(state.ui.inpSearch, "searchMoves");
        bind(state.ui.chkRun, "autoRun", "chk");
        bind(state.ui.chkMove, "autoMove", "chk");
        bind(state.ui.chkQueue, "autoQueue", "chk");
        bind(state.ui.inpMin, "minDelay", "num");
        bind(state.ui.inpMax, "maxDelay", "num");
        bind(state.ui.visInnerOp, "innerOpacity", "num");
        bind(state.ui.visOuterOp, "outerOpacity", "num");
        bind(state.ui.visBias, "gradientBias", "num");
        toggleAutoQueue();
        updateUI();
    }
    function enforceBounds() {
        if (state.ui.panel) {
            const rect = state.ui.panel.getBoundingClientRect();
            const winW = window.innerWidth;
            const winH = window.innerHeight;
            if (rect.right > winW) state.ui.panel.style.width = winW - rect.left + "px";
            if (rect.bottom > winH) state.ui.panel.style.height = winH - rect.top + "px";
            if (rect.left < 0) state.ui.panel.style.left = "0px";
            if (rect.top < 0) state.ui.panel.style.top = "0px";
        }
        requestAnimationFrame(enforceBounds);
    }
    requestAnimationFrame(enforceBounds);
    function updateUI() {
        if (!state.ui.panel) return;
        document.body.classList.remove("mode-cloud", "mode-local", "mode-sfonline");
        document.body.classList.add(`mode-${settings.engineMode}`);
        if (state.ui.debugArea) state.ui.debugArea.style.display = settings.debugLogs ? "block" : "none";
        let maxD = 18;
        if (settings.engineMode === "local") maxD = 23;
        else if (settings.engineMode === "sfonline") maxD = 15;
        if (state.ui.lblMaxDepth) state.ui.lblMaxDepth.innerText = maxD;
        if (state.ui.inpDepth) state.ui.inpDepth.max = maxD;
        if (state.ui.btnAnalyze) state.ui.btnAnalyze.disabled = state.isThinking;
        if (state.ui.moveResult) state.ui.moveResult.innerHTML = state.lastMoveResult;
        if (state.ui.liveOutput) state.ui.liveOutput.innerHTML = state.lastLiveResult;
        if (state.ui.delayDisplay) state.ui.delayDisplay.innerText = `Randomized Delay: ${state.calculatedDelay}s`;
        if (state.ui.logSent) state.ui.logSent.innerText = state.lastPayload;
        if (state.ui.logRec) state.ui.logRec.innerText = state.lastResponse;
        if (document.activeElement !== state.ui.inpDepth) state.ui.inpDepth.value = settings.depth;
    }
    function mainLoop() {
        state.board = document.querySelector(CONFIG.BOARD_SEL);
        if (!state.ui.panel) createUI();
        if (state.board?.game && settings.autoRun) {
            const raw = getRawBoardFEN();
            if (raw) {
                const clean = sanitizeFEN(raw);
                const isTurn = state.board.game.getTurn() === state.board.game.getPlayingAs();
                if (isTurn && clean !== state.lastSanitizedBoardFEN) {
                    analyze(settings.depth);
                }
            }
        }
        updateUI();
    }
    setInterval(mainLoop, CONFIG.LOOP_MS);
})();