Destiny V3

Deadshot.io Cheat (AIMBOT, WALL HACKS) -- discord.gg/783Ve3Fd

이 스크립트를 설치하려면 Tampermonkey, Greasemonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램을 설치해야 합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Userscripts와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 유저 스크립트 관리자 확장 프로그램이 필요합니다.

(이미 유저 스크립트 관리자가 설치되어 있습니다. 설치를 진행합니다!)

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

(이미 유저 스타일 관리자가 설치되어 있습니다. 설치를 진행합니다!)

// ==UserScript==
// @name         Destiny V3
// @namespace    http://tampermonkey.net/
// @version      3.0
// @description  Deadshot.io Cheat (AIMBOT, WALL HACKS) -- discord.gg/783Ve3Fd
// @match        *://*deadshot.io/*
// @grant        none
// @run-at       document-start
// @license      MIT
// ==/UserScript==

(function () {
    'use strict';

    // =====================================================================
    // CONFIG
    // =====================================================================
    const STORAGE_KEY = 'destiny_v2_config';

    const defaultConfig = {
        // Aimbot
        aimbotEnabled: true,
        aimKey: 'RightClick',
        aimSmooth: 1.5,
        lockDist: 80,
        hitbox: 0,
        priority: 1,
        targetLock: false,
        predictionEnabled: true,
        predictionStrength: 2.0,
        velocityTracking: true,
        visibilityCheck: true,

        // TriggerBot
        triggerBot: false,
        triggerDelay: 50,
        triggerRadius: 12,

        // ESP / Visuals
        espEnabled: true,
        showDistance: true,
        showTracers: false,
        espThickness: 2,
        showFov: false,
        fov: 300,
        fovGradient: true,
        showCrosshair: false,
        showFPS: true,

        // Program detection
        autoDetect: true,
        manualTargetID: -1,

        // Combat
        crouchSpam: false,
        crouchSpamSpeed: 80,
        autoStrafe: false,
        autoStrafeSpeed: 100,

        // Hacks
        fovHack: false,
        fovHackScale: 1.0,

        // Misc
        antiAFK: false,
        performanceMode: false,
        blockFullscreen: false,
        debugOverlay: true,

        // Radar & Indicators
        radarEnabled: true,
        radarSize: 120,
        radarRange: 80,
        offScreenIndicators: true,

        // UI
        menuVisible: true,
        menuKey: 'Insert',
        accentColor: '#a855f7',
        x: 60,
        y: 60,
    };

    let config = { ...defaultConfig };
    try {
        const saved = localStorage.getItem(STORAGE_KEY);
        if (saved) config = { ...config, ...JSON.parse(saved) };
    } catch (e) {}

    let _saveTimer = null;
    function save() {
        if (_saveTimer) clearTimeout(_saveTimer);
        _saveTimer = setTimeout(saveImmediate, 200);
    }
    function saveImmediate() {
        if (_saveTimer) { clearTimeout(_saveTimer); _saveTimer = null; }
        try { localStorage.setItem(STORAGE_KEY, JSON.stringify(config)); } catch (e) {}
    }

    if (config.blockFullscreen) {
        const block = () => Promise.resolve();
        ['requestFullscreen', 'webkitRequestFullscreen', 'mozRequestFullScreen', 'msRequestFullscreen']
            .forEach(fn => { if (Element.prototype[fn]) Element.prototype[fn] = block; });
    }

    // =====================================================================
    // STATE
    // =====================================================================
    const state = {
        programCounter: 0,
        vpMatrices: [],
        matricesByProgram: new Map(),
        programScores: new Map(),
        detectedTargetID: -1,
        modelMatrices: [],
        lockedTarget: null,

        lastPositions: new Map(),
        velocities: new Map(),
        deadPositions: new Map(),

        lastMouseMove: Date.now(),
        lastTriggerFire: 0,
        lastCrouchToggle: 0,
        crouchDown: false,
        lastStrafeToggle: 0,
        strafeRight: false,

        input: { left: false, right: false, shift: false, alt: false },
        pointerLocked: false,
        rebindingField: null,
        keyJustRebound: false,

        accX: 0,
        accY: 0,

        fps: 0,
        frameCount: 0,
        lastFPSUpdate: Date.now(),
        totalTargets: 0,

        overlayCtx: null,
        baselineVP0: 0,
        currentZoom: 1.0,
    };

    // =====================================================================
    // INPUT
    // =====================================================================
    function aimKeyHeld() {
        switch (config.aimKey) {
            case 'RightClick': return state.input.right;
            case 'LeftClick':  return state.input.left;
            case 'ShiftLeft':  return state.input.shift;
            case 'AltLeft':    return state.input.alt;
            case 'Always':     return true;
            default:           return state.input.right;
        }
    }

    document.addEventListener('keydown', (e) => {
        if (state.rebindingField) {
            const field = state.rebindingField;
            state.rebindingField = null;
            state.keyJustRebound = true;
            config[field] = e.code;
            saveImmediate();
            refreshGUI();
            e.preventDefault();
            e.stopImmediatePropagation();
            return;
        }
        if (e.code === config.menuKey) {
            config.menuVisible = !config.menuVisible;
            const el = document.getElementById('d2-root');
            if (el) el.style.display = config.menuVisible ? 'flex' : 'none';
            saveImmediate();
            e.preventDefault();
            e.stopImmediatePropagation();
        }
        if (e.code === 'ArrowRight') {
            config.autoDetect = false;
            config.manualTargetID++;
            state.modelMatrices = [];
            save();
            refreshTargetBadge();
            e.preventDefault();
            e.stopImmediatePropagation();
        }
        if (e.code === 'ArrowLeft') {
            config.autoDetect = false;
            config.manualTargetID--;
            state.modelMatrices = [];
            save();
            refreshTargetBadge();
            e.preventDefault();
            e.stopImmediatePropagation();
        }
        if (e.code === 'ShiftLeft') state.input.shift = true;
        if (e.code === 'AltLeft')   state.input.alt = true;
    }, true);

    document.addEventListener('keyup', (e) => {
        if (e.code === 'ShiftLeft') state.input.shift = false;
        if (e.code === 'AltLeft')   state.input.alt = false;
    }, true);

    const onMouseDown = e => {
        if (e.button === 0) state.input.left = true;
        if (e.button === 2) state.input.right = true;
    };
    const onMouseUp = e => {
        if (e.button === 0) state.input.left = false;
        if (e.button === 2) state.input.right = false;
    };
    document.addEventListener('mousedown', onMouseDown, true);
    document.addEventListener('mouseup', onMouseUp, true);
    window.addEventListener('mousedown', onMouseDown);
    window.addEventListener('mouseup', onMouseUp);

    document.addEventListener('pointerlockchange', () => {
        const wasLocked = state.pointerLocked;
        state.pointerLocked = !!document.pointerLockElement;
        if (state.pointerLocked && !wasLocked) {
            state.lastPositions.clear();
            state.velocities.clear();
            state.deadPositions.clear();
            state.lockedTarget = null;
        }
    }, true);

    // Browser mouse input: dispatchEvent with Object.defineProperty for movementX/Y
    function mouseMove(dx, dy) {
        const evt = new MouseEvent('mousemove', { bubbles: true, cancelable: true });
        Object.defineProperty(evt, 'movementX', { value: dx });
        Object.defineProperty(evt, 'movementY', { value: dy });
        const canvas = document.pointerLockElement || document.querySelector('canvas');
        if (canvas) canvas.dispatchEvent(evt);
        const evt2 = new MouseEvent('mousemove', { bubbles: true, cancelable: true });
        Object.defineProperty(evt2, 'movementX', { value: dx });
        Object.defineProperty(evt2, 'movementY', { value: dy });
        window.dispatchEvent(evt2);
    }

    function mouseClick(isDown) {
        window.dispatchEvent(new MouseEvent(isDown ? 'mousedown' : 'mouseup', { button: 0, bubbles: true }));
    }

    // =====================================================================
    // WEBGL HOOK
    // =====================================================================
    const originalGetContext = HTMLCanvasElement.prototype.getContext;
    const proxyCache = new WeakMap();
    const programMap = new WeakMap();

    function spoof(fake, real) {
        Object.defineProperty(fake, 'name', { value: real.name, configurable: true });
        Object.defineProperty(fake, 'toString', { value: () => real.toString(), configurable: true });
        return fake;
    }

    function currentTargetID() {
        return config.autoDetect ? state.detectedTargetID : config.manualTargetID;
    }

    HTMLCanvasElement.prototype.getContext = spoof(function (type, options) {
        const ctx = originalGetContext.call(this, type, options);
        if (!ctx || (type !== 'webgl' && type !== 'webgl2')) return ctx;
        if (proxyCache.has(ctx)) return proxyCache.get(ctx);

        const handler = {
            get(target, prop) {
                const val = target[prop];
                if (typeof val !== 'function') return val;

                if (prop === 'uniformMatrix4fv') {
                    return function (loc, transpose, value) {
                        if (value && value.length === 16) {
                            if (Math.abs(value[11] + 1) < 0.1 && Math.abs(value[15]) < 0.1) {
                                if (state.vpMatrices.length > 3) state.vpMatrices.shift();
                                state.vpMatrices.push(new Float32Array(value));

                                if (config.fovHack && config.fovHackScale !== 1.0) {
                                    const modified = new Float32Array(value);
                                    modified[0] *= config.fovHackScale;
                                    modified[5] *= config.fovHackScale;
                                    arguments[2] = modified;
                                }
                            }
                            else if (Math.abs(value[3]) < 1e-6 &&
                                     Math.abs(value[7]) < 1e-6 &&
                                     Math.abs(value[15] - 1) < 1e-6) {
                                const gl = target;
                                const pid = programMap.get(gl.getParameter(gl.CURRENT_PROGRAM));
                                if (pid !== undefined) {
                                    let arr = state.matricesByProgram.get(pid);
                                    if (!arr) { arr = []; state.matricesByProgram.set(pid, arr); }
                                    if (arr.length < 64) arr.push(new Float32Array(value));
                                }
                            }
                        }
                        return val.apply(target, arguments);
                    };
                }
                if (prop === 'useProgram') {
                    return function (program) {
                        if (program && !programMap.has(program)) {
                            programMap.set(program, state.programCounter++);
                        }
                        return val.apply(target, arguments);
                    };
                }
                if (prop === 'drawElements') {
                    return function () {
                        const gl = target;
                        const pid = programMap.get(gl.getParameter(gl.CURRENT_PROGRAM));
                        const tgt = currentTargetID();
                        const espActive = config.aimbotEnabled && config.espEnabled && pid === tgt && tgt >= 0;
                        if (espActive) gl.disable(gl.DEPTH_TEST);
                        const res = val.apply(target, arguments);
                        if (espActive) gl.enable(gl.DEPTH_TEST);
                        return res;
                    };
                }
                return val.bind(target);
            },
        };
        const proxied = new Proxy(ctx, handler);
        proxyCache.set(ctx, proxied);
        return proxied;
    }, originalGetContext);

    // =====================================================================
    // AUTO-DETECT
    // =====================================================================
    function scoreProgramsThisFrame() {
        if (!config.autoDetect) return;
        const now = Date.now();
        for (const [pid, mats] of state.matricesByProgram.entries()) {
            const n = mats.length;
            if (n < 2 || n > 40) { decay(pid, now); continue; }
            let sumX = 0, sumZ = 0, minY = Infinity, maxY = -Infinity;
            for (let i = 0; i < n; i++) {
                const m = mats[i];
                sumX += m[12]; sumZ += m[14];
                if (m[13] < minY) minY = m[13];
                if (m[13] > maxY) maxY = m[13];
            }
            const meanX = sumX / n, meanZ = sumZ / n;
            let varXZ = 0;
            for (let i = 0; i < n; i++) {
                const m = mats[i];
                const dx = m[12] - meanX, dz = m[14] - meanZ;
                varXZ += dx * dx + dz * dz;
            }
            varXZ /= n;
            const spread = Math.sqrt(varXZ);
            if (spread < 0.8) { decay(pid, now); continue; }
            if (maxY - minY > 200) { decay(pid, now); continue; }
            const countScore = n <= 3 ? n / 3 : n <= 12 ? 1.0 : Math.max(0, 1 - (n - 12) / 28);
            const spreadScore = Math.min(1, spread / 10);
            const frameScore = countScore * 0.6 + spreadScore * 0.4;
            const prev = state.programScores.get(pid) || { score: 0, lastSeen: 0 };
            const alpha = 0.25;
            prev.score = prev.score * (1 - alpha) + frameScore * alpha;
            prev.lastSeen = now;
            prev.matrixCount = n;
            prev.spread = spread;
            state.programScores.set(pid, prev);
        }
        for (const [pid, data] of state.programScores.entries()) {
            if (!state.matricesByProgram.has(pid)) decay(pid, now);
            if (now - data.lastSeen > 5000) state.programScores.delete(pid);
        }
        let best = -1, bestScore = 0.15;
        for (const [pid, data] of state.programScores.entries()) {
            if (data.score > bestScore) { best = pid; bestScore = data.score; }
        }
        if (best !== state.detectedTargetID) {
            state.detectedTargetID = best;
            refreshTargetBadge();
        }
    }

    function decay(pid, now) {
        const prev = state.programScores.get(pid);
        if (!prev) return;
        prev.score *= 0.85;
        prev.lastSeen = now;
    }

    // =====================================================================
    // CANVAS & UTILITIES
    // =====================================================================
    let overlayCanvas = null;

    function setupCanvas() {
        if (overlayCanvas) return;
        overlayCanvas = document.createElement('canvas');
        overlayCanvas.id = 'd2-overlay';
        overlayCanvas.style.cssText = 'position:fixed;top:0;left:0;width:100vw;height:100vh;z-index:2147483645;pointer-events:none;';
        (document.body || document.documentElement).appendChild(overlayCanvas);

        const resize = () => {
            overlayCanvas.width = window.innerWidth;
            overlayCanvas.height = window.innerHeight;
        };
        window.addEventListener('resize', resize);
        document.addEventListener('fullscreenchange', () => setTimeout(resize, 50));
        document.addEventListener('webkitfullscreenchange', () => setTimeout(resize, 50));
        resize();

        (function loop() { render(); requestAnimationFrame(loop); })();
        setInterval(() => { if (!document.getElementById('d2-root')) createGUI(); }, 2000);
    }

    function getBoneOffset() {
        return config.hitbox === 0 ? 2.15 : config.hitbox === 1 ? 1.5 : 0.8;
    }

    function calculateVelocity(posKey, pos) {
        const last = state.lastPositions.get(posKey);
        const now = Date.now();
        if (last) {
            const dt = (now - last.time) / 1000;
            if (dt > 0.001 && dt < 0.5) {
                const vx = (pos.x - last.x) / dt;
                const vy = (pos.y - last.y) / dt;
                const vz = (pos.z - last.z) / dt;
                const prev = state.velocities.get(posKey);
                const blend = 0.85;
                if (prev) {
                    state.velocities.set(posKey, {
                        vx: vx * blend + prev.vx * (1 - blend),
                        vy: vy * blend + prev.vy * (1 - blend),
                        vz: vz * blend + prev.vz * (1 - blend),
                        time: now,
                    });
                } else {
                    state.velocities.set(posKey, { vx, vy, vz, time: now });
                }
            }
        }
        state.lastPositions.set(posKey, { x: pos.x, y: pos.y, z: pos.z, time: now });
    }

    function project(vp, x, y, z, w, h) {
        const X = x*vp[0] + y*vp[4] + z*vp[8]  + vp[12];
        const Y = x*vp[1] + y*vp[5] + z*vp[9]  + vp[13];
        const W = x*vp[3] + y*vp[7] + z*vp[11] + vp[15];
        if (W < 0.1) return null;
        return { x: (X/W + 1) * w * 0.5, y: (-Y/W + 1) * h * 0.5, w: W };
    }

    function easeOutQuart(x) { return 1 - Math.pow(1 - x, 4); }
    function easeInOutCubic(x) { return x < 0.5 ? 4*x*x*x : 1 - Math.pow(-2*x+2, 3) / 2; }

    function applySmoothCurve(value) {
        return value < 0.5 ? 4*value*value*value : 1 - Math.pow(-2*value+2, 3) / 2;
    }

    // =====================================================================
    // RENDER LOOP
    // =====================================================================
    function render() {
        if (!overlayCanvas) return;
        if (!state.overlayCtx) state.overlayCtx = overlayCanvas.getContext('2d');
        const ctx = state.overlayCtx;
        const w = overlayCanvas.width;
        const h = overlayCanvas.height;
        const cx = w / 2, cy = h / 2;
        ctx.clearRect(0, 0, w, h);

        state.frameCount++;
        const now = Date.now();
        if (now - state.lastFPSUpdate > 1000) {
            state.fps = state.frameCount;
            state.frameCount = 0;
            state.lastFPSUpdate = now;
            updateStatusBar();
        }

        scoreProgramsThisFrame();
        const tgt = currentTargetID();
        state.modelMatrices = (tgt >= 0 && state.matricesByProgram.get(tgt)) || [];

        if (config.debugOverlay) {
            ctx.font = '10px monospace';
            let dy = 10;
            const sorted = [...state.programScores.entries()].sort((a,b) => b[1].score - a[1].score);
            for (let i = 0; i < Math.min(sorted.length, 6); i++) {
                const [pid, data] = sorted[i];
                const mats = state.matricesByProgram.get(pid);
                const n = mats ? mats.length : 0;
                ctx.fillStyle = pid === tgt ? '#0f0' : '#888';
                ctx.fillText(`pid:${pid} score:${data.score.toFixed(3)} mats:${n} spread:${(data.spread||0).toFixed(1)}`, 10, dy);
                dy += 12;
            }
        }

        if (config.showFPS) {
            ctx.font = 'bold 14px Segoe UI, system-ui';
            ctx.fillStyle = config.accentColor;
            ctx.fillText(`${state.fps} fps`, 10, 24);
        }

        if (config.debugOverlay) {
            ctx.font = '11px monospace';
            ctx.fillStyle = state.pointerLocked ? '#0f0' : '#f77';
            const keyLbl = aimKeyHeld() ? 'FIRE' : 'idle';
            ctx.fillText(`ptr:${state.pointerLocked?'lock':'free'}  key:${keyLbl}  tgt:${tgt}  mats:${state.modelMatrices.length}  zoom:${state.currentZoom.toFixed(2)}`, 10, h - 10);
        }

        if (config.showCrosshair) {
            const s = 10, g = 4;
            ctx.strokeStyle = config.accentColor;
            ctx.lineWidth = 2;
            ctx.beginPath();
            ctx.moveTo(cx, cy-g-s); ctx.lineTo(cx, cy-g);
            ctx.moveTo(cx, cy+g);   ctx.lineTo(cx, cy+g+s);
            ctx.moveTo(cx-g-s, cy); ctx.lineTo(cx-g, cy);
            ctx.moveTo(cx+g, cy);   ctx.lineTo(cx+g+s, cy);
            ctx.stroke();
            ctx.fillStyle = config.accentColor;
            ctx.fillRect(cx-1, cy-1, 2, 2);
        }

        if (config.showFov) {
            ctx.beginPath();
            ctx.arc(cx, cy, config.fov, 0, Math.PI * 2);
            if (config.fovGradient && !config.performanceMode) {
                const grad = ctx.createRadialGradient(cx, cy, 0, cx, cy, config.fov);
                grad.addColorStop(0, 'transparent');
                grad.addColorStop(0.8, 'transparent');
                grad.addColorStop(1, config.accentColor + '40');
                ctx.fillStyle = grad;
                ctx.fill();
            }
            ctx.strokeStyle = config.accentColor;
            ctx.lineWidth = 1.5;
            ctx.stroke();
        }

        if (state.vpMatrices.length === 0) { clearFrameBuffers(); return; }

        const vp = state.vpMatrices[state.vpMatrices.length - 1];
        let bestTarget = null;
        let bestScore = Infinity;
        let bestLockData = null;
        state.totalTargets = 0;

        const MIN_DIST_SQ = 0.25;
        const processed = [];

        for (let i = 0; i < state.modelMatrices.length; i++) {
            const mat = state.modelMatrices[i];
            const wx = mat[12], wy = mat[13], wz = mat[14];

            let dup = false;
            for (let j = 0; j < processed.length; j++) {
                const p = processed[j];
                const ddx = wx-p.x, ddy = wy-p.y, ddz = wz-p.z;
                if (ddx*ddx+ddy*ddy+ddz*ddz < MIN_DIST_SQ) { dup = true; break; }
            }
            if (dup) continue;
            if (processed.length < 24) processed.push({ x: wx, y: wy, z: wz });

            const posKey = `${Math.round(wx*10)}_${Math.round(wy*10)}_${Math.round(wz*10)}`;
            if (config.velocityTracking && config.predictionEnabled) {
                calculateVelocity(posKey, { x: wx, y: wy, z: wz });
            }

            const boneY = getBoneOffset();
            const head = project(vp, wx, wy + boneY, wz, w, h);
            const foot = project(vp, wx, wy, wz, w, h);
            if (!head || !foot) continue;

            const boxH = foot.y - head.y;
            const boxW = boxH * 0.6;
            if (boxH < 30 || boxH > 400) continue;
            if (boxW < 15 || boxW > 250) continue;
            const aspect = boxW / boxH;
            if (aspect < 0.3 || aspect > 1.0) continue;
            if (head.x < -100 || head.x > w + 100) continue;
            if (head.y < -100 || head.y > h + 100) continue;

            let px = wx, py = wy + boneY, pz = wz;
            if (config.predictionEnabled && config.velocityTracking) {
                const vel = state.velocities.get(posKey);
                if (vel && now - vel.time < 200) {
                    const dt = config.predictionStrength * 0.05;
                    px += vel.vx * dt;
                    py += vel.vy * dt;
                    pz += vel.vz * dt;
                }
            }

            const curVel = state.velocities.get(posKey);
            if (!curVel || Math.abs(curVel.vx) > 0.2 || Math.abs(curVel.vy) > 0.5 || Math.abs(curVel.vz) > 0.2) {
                state.deadPositions.set(posKey, now);
            } else if (!state.deadPositions.has(posKey)) {
                state.deadPositions.set(posKey, now);
            }

            const depthRatio = head.w / (foot.w + 0.001);
            const isOccluded = depthRatio < 0.3 || depthRatio > 3.0;

            const lastMoving = state.deadPositions.get(posKey);
            const velCheck = state.velocities.get(posKey);
            const isCurrentlyStill = velCheck && Math.abs(velCheck.vx) < 0.1 && Math.abs(velCheck.vy) < 0.3 && Math.abs(velCheck.vz) < 0.1;
            const isDead = isCurrentlyStill && lastMoving && (now - lastMoving > 3000);

            state.totalTargets++;
            const dist3D = Math.sqrt(wx*wx + wy*wy + wz*wz);
            const dist2D = Math.hypot(head.x - cx, head.y - cy);

            // ── ESP Drawing ──
            if (config.espEnabled) {
                const inFov = dist2D <= config.fov;
                const bx = head.x - boxW / 2;
                const by = head.y;
                const cornerLen = Math.min(boxW, boxH) * 0.25;
                const alpha = isDead ? '40' : isOccluded ? '60' : 'ff';
                const baseColor = inFov ? config.accentColor : '#888888';
                const color = baseColor + alpha;

                ctx.strokeStyle = color;
                ctx.lineWidth = config.espThickness;
                ctx.beginPath();
                ctx.moveTo(bx, by+cornerLen); ctx.lineTo(bx, by); ctx.lineTo(bx+cornerLen, by);
                ctx.moveTo(bx+boxW-cornerLen, by); ctx.lineTo(bx+boxW, by); ctx.lineTo(bx+boxW, by+cornerLen);
                ctx.moveTo(bx, by+boxH-cornerLen); ctx.lineTo(bx, by+boxH); ctx.lineTo(bx+cornerLen, by+boxH);
                ctx.moveTo(bx+boxW-cornerLen, by+boxH); ctx.lineTo(bx+boxW, by+boxH); ctx.lineTo(bx+boxW, by+boxH-cornerLen);
                ctx.stroke();

                if (!config.performanceMode) {
                    const barW = 3, barX = bx - barW - 3;
                    const hpGrad = ctx.createLinearGradient(barX, by, barX, by + boxH);
                    hpGrad.addColorStop(0, '#00e676' + alpha);
                    hpGrad.addColorStop(1, '#ff1744' + alpha);
                    ctx.fillStyle = '#00000060';
                    ctx.fillRect(barX-1, by-1, barW+2, boxH+2);
                    ctx.fillStyle = hpGrad;
                    ctx.fillRect(barX, by, barW, boxH);

                    if (config.showDistance) {
                        const distText = `${Math.round(dist3D)}m`;
                        ctx.font = 'bold 10px "Segoe UI", system-ui';
                        const tw = ctx.measureText(distText).width;
                        const pillX = head.x - tw/2 - 4, pillY = by - 18;
                        ctx.fillStyle = '#00000090';
                        ctx.beginPath();
                        ctx.roundRect(pillX, pillY, tw+8, 14, 4);
                        ctx.fill();
                        ctx.fillStyle = '#ffffff' + alpha;
                        ctx.fillText(distText, pillX+4, pillY+11);
                    }

                    if (isDead) {
                        ctx.font = 'bold 9px "Segoe UI", system-ui';
                        ctx.fillStyle = '#ff5555';
                        ctx.fillText('DEAD', head.x - 14, by + boxH + 12);
                    }

                    if (config.showTracers) {
                        ctx.beginPath();
                        ctx.moveTo(cx, h);
                        ctx.lineTo(foot.x, foot.y);
                        ctx.strokeStyle = baseColor + '40';
                        ctx.lineWidth = 1;
                        ctx.setLineDash([4,4]);
                        ctx.stroke();
                        ctx.setLineDash([]);
                    }
                }
            }

            if (dist2D > config.fov) continue;

            if (config.visibilityCheck) {
                if (head.w < 0.01 || head.w > 100) continue;
                if (dist3D / (dist2D + 1) > 50) continue;
            }

            if (isOccluded) continue;
            if (isDead) continue;

            const score = config.priority === 1 ? dist2D : head.w;
            if (score < bestScore) {
                bestScore = score;
                const pred = project(vp, px, py, pz, w, h);
                bestTarget = pred || head;
                bestLockData = { wx, wy, wz, boneY, posKey };
            }
        }

        // Target lock
        if (config.targetLock) {
            if (state.lockedTarget) {
                const lt = state.lockedTarget;
                let lx = lt.wx, ly = lt.wy + lt.boneY, lz = lt.wz;
                if (config.predictionEnabled && config.velocityTracking) {
                    const vel = state.velocities.get(lt.posKey);
                    if (vel && now - vel.time < 200) {
                        const dt = config.predictionStrength * 0.05;
                        lx += vel.vx * dt; ly += vel.vy * dt; lz += vel.vz * dt;
                    }
                }
                const locked = project(vp, lx, ly, lz, w, h);
                const lastSeen = state.lastPositions.get(lt.posKey);
                if (locked && lastSeen && now - lastSeen.time < 500) {
                    bestTarget = locked;
                } else {
                    state.lockedTarget = null;
                }
            }
            if (!state.lockedTarget && bestLockData) state.lockedTarget = bestLockData;
        } else if (state.lockedTarget) {
            state.lockedTarget = null;
        }

        // Aim target highlight
        if (config.aimbotEnabled && bestTarget) {
            const pulse = 0.6 + Math.sin(now * 0.008) * 0.4;
            const glowSize = 12 + pulse * 6;
            ctx.beginPath();
            ctx.arc(bestTarget.x, bestTarget.y, glowSize, 0, Math.PI * 2);
            const glow = ctx.createRadialGradient(bestTarget.x, bestTarget.y, 0, bestTarget.x, bestTarget.y, glowSize);
            glow.addColorStop(0, `rgba(255, 50, 50, ${0.5 * pulse})`);
            glow.addColorStop(1, 'rgba(255, 50, 50, 0)');
            ctx.fillStyle = glow;
            ctx.fill();

            ctx.beginPath();
            ctx.arc(bestTarget.x, bestTarget.y, 4, 0, Math.PI * 2);
            ctx.fillStyle = '#ff3232';
            ctx.fill();

            if (config.debugOverlay) {
                ctx.beginPath();
                ctx.moveTo(cx, cy);
                ctx.lineTo(bestTarget.x, bestTarget.y);
                const lineGrad = ctx.createLinearGradient(cx, cy, bestTarget.x, bestTarget.y);
                lineGrad.addColorStop(0, 'rgba(255,255,0,0.1)');
                lineGrad.addColorStop(1, 'rgba(255,50,50,0.6)');
                ctx.strokeStyle = lineGrad;
                ctx.lineWidth = 1.5;
                ctx.stroke();
            }
        }

        // TriggerBot
        if (config.triggerBot && bestTarget) {
            const tdx = bestTarget.x - cx, tdy = bestTarget.y - cy;
            if (Math.hypot(tdx, tdy) < config.triggerRadius && now - state.lastTriggerFire > config.triggerDelay) {
                mouseClick(true);
                setTimeout(() => mouseClick(false), 50);
                state.lastTriggerFire = now;
            }
        }

        // ── AIMBOT (browser smooth approach) ──
        const shouldAim = config.aimbotEnabled && bestTarget && state.pointerLocked && aimKeyHeld();

        // Zoom detection
        if (vp) {
            const vpScale = Math.abs(vp[0]);
            if (vpScale > 0.5 && vpScale < 20) {
                if (state.baselineVP0 === 0) {
                    state.baselineVP0 = vpScale;
                } else if (vpScale < state.baselineVP0 * 1.1) {
                    state.baselineVP0 = state.baselineVP0 * 0.95 + vpScale * 0.05;
                }
                state.currentZoom = state.baselineVP0 > 0 ? vpScale / state.baselineVP0 : 1.0;
            }
        }

        if (shouldAim) {
            const dx = bestTarget.x - cx;
            const dy = bestTarget.y - cy;
            const dist = Math.hypot(dx, dy);

            // Zoom compensation for scoped weapons
            const zoom = state.currentZoom;
            const zoomComp = zoom > 1.5 ? 1.0 / zoom : 1.0;

            const DEADZONE = 3;
            if (dist < DEADZONE) {
                state.accX *= 0.7;
                state.accY *= 0.7;
            } else {
                let smooth = config.aimSmooth;
                const distRatio = Math.min(1, dist / config.fov);

                if (dist < config.lockDist * 0.5) {
                    smooth *= 2.5;
                } else if (dist < config.lockDist) {
                    const closeRatio = (dist - config.lockDist * 0.5) / (config.lockDist * 0.5);
                    smooth *= 1.5 + easeOutQuart(closeRatio);
                } else if (dist < config.lockDist * 2) {
                    const midRatio = (dist - config.lockDist) / config.lockDist;
                    smooth *= 1.0 + (0.5 * easeInOutCubic(midRatio));
                }

                const easedProgress = applySmoothCurve(distRatio);
                smooth = smooth * (0.8 + easedProgress * 0.4);

                let tx = (dx / smooth) * zoomComp;
                let ty = (dy / smooth) * zoomComp;
                tx += state.accX * 0.85;
                ty += state.accY * 0.85;

                let mx = Math.round(tx);
                let my = Math.round(ty);
                state.accX = (tx - mx) * 0.9;
                state.accY = (ty - my) * 0.9;

                if (Math.abs(mx) >= 1 || Math.abs(my) >= 1) {
                    mouseMove(mx, my);
                    state.lastMouseMove = now;
                }
            }
        } else {
            state.accX *= 0.5;
            state.accY *= 0.5;
        }

        // Crouch spam
        if (config.crouchSpam && state.pointerLocked && state.input.left) {
            if (now - state.lastCrouchToggle > config.crouchSpamSpeed) {
                state.crouchDown = !state.crouchDown;
                document.dispatchEvent(new KeyboardEvent(state.crouchDown ? 'keydown' : 'keyup', {
                    code: 'ShiftLeft', key: 'Shift', keyCode: 16, which: 16, bubbles: true, cancelable: true
                }));
                state.lastCrouchToggle = now;
            }
        } else if (state.crouchDown) {
            document.dispatchEvent(new KeyboardEvent('keyup', {
                code: 'ShiftLeft', key: 'Shift', keyCode: 16, which: 16, bubbles: true, cancelable: true
            }));
            state.crouchDown = false;
        }

        // Auto-strafe
        if (config.autoStrafe && state.pointerLocked && state.input.left) {
            if (now - state.lastStrafeToggle > config.autoStrafeSpeed) {
                const oldKey = state.strafeRight ? 'KeyD' : 'KeyA';
                document.dispatchEvent(new KeyboardEvent('keyup', { code: oldKey, key: state.strafeRight ? 'd' : 'a', bubbles: true }));
                state.strafeRight = !state.strafeRight;
                const newKey = state.strafeRight ? 'KeyD' : 'KeyA';
                document.dispatchEvent(new KeyboardEvent('keydown', { code: newKey, key: state.strafeRight ? 'd' : 'a', bubbles: true }));
                state.lastStrafeToggle = now;
            }
        } else if (state.lastStrafeToggle > 0) {
            document.dispatchEvent(new KeyboardEvent('keyup', { code: 'KeyA', key: 'a', bubbles: true }));
            document.dispatchEvent(new KeyboardEvent('keyup', { code: 'KeyD', key: 'd', bubbles: true }));
            state.lastStrafeToggle = 0;
        }

        // Minimap radar
        if (config.radarEnabled && state.vpMatrices.length > 0 && state.pointerLocked) {
            const rSize = config.radarSize;
            const rX = w - rSize - 15, rY = 15;
            const rCx = rX + rSize/2, rCy = rY + rSize/2;
            const rScale = (rSize / 2) / config.radarRange;

            ctx.beginPath();
            ctx.arc(rCx, rCy, rSize/2, 0, Math.PI * 2);
            ctx.fillStyle = 'rgba(0,0,0,0.55)';
            ctx.fill();
            ctx.strokeStyle = 'rgba(255,255,255,0.15)';
            ctx.lineWidth = 1;
            ctx.stroke();

            ctx.beginPath();
            ctx.moveTo(rCx, rY+4); ctx.lineTo(rCx, rY+rSize-4);
            ctx.moveTo(rX+4, rCy); ctx.lineTo(rX+rSize-4, rCy);
            ctx.strokeStyle = 'rgba(255,255,255,0.06)';
            ctx.stroke();

            ctx.beginPath();
            ctx.arc(rCx, rCy, 3, 0, Math.PI * 2);
            ctx.fillStyle = '#00e676';
            ctx.fill();

            const fwdX = -vp[2], fwdZ = -vp[10];
            const fwdLen = Math.sqrt(fwdX*fwdX + fwdZ*fwdZ) || 1;
            const cosA = fwdX/fwdLen, sinA = fwdZ/fwdLen;

            for (let i = 0; i < state.modelMatrices.length; i++) {
                const mat = state.modelMatrices[i];
                const rx = mat[12]*cosA + mat[14]*sinA;
                const rz = -mat[12]*sinA + mat[14]*cosA;
                const dotX = rCx + rx*rScale, dotY = rCy - rz*rScale;
                if (Math.hypot(dotX-rCx, dotY-rCy) > rSize/2 - 4) continue;
                ctx.beginPath();
                ctx.arc(dotX, dotY, 2.5, 0, Math.PI * 2);
                ctx.fillStyle = '#ff3232';
                ctx.fill();
            }
        }

        // Off-screen indicators
        if (config.offScreenIndicators && state.pointerLocked) {
            const margin = 30;
            for (let i = 0; i < state.modelMatrices.length; i++) {
                const mat = state.modelMatrices[i];
                const bY = getBoneOffset();
                const projected = project(vp, mat[12], mat[13]+bY, mat[14], w, h);
                if (!projected) continue;
                if (projected.x >= 0 && projected.x <= w && projected.y >= 0 && projected.y <= h) continue;
                const adx = projected.x - cx, ady = projected.y - cy;
                const angle = Math.atan2(ady, adx);
                const edgeX = Math.max(margin, Math.min(w-margin, cx + Math.cos(angle)*(w/2-margin)));
                const edgeY = Math.max(margin, Math.min(h-margin, cy + Math.sin(angle)*(h/2-margin)));
                ctx.save();
                ctx.translate(edgeX, edgeY);
                ctx.rotate(angle);
                ctx.beginPath();
                ctx.moveTo(10, 0); ctx.lineTo(-5, -6); ctx.lineTo(-5, 6);
                ctx.closePath();
                ctx.fillStyle = '#ff3232cc';
                ctx.fill();
                ctx.restore();
            }
        }

        if (config.antiAFK && now - state.lastMouseMove > 60000) {
            mouseMove(1, 0);
            state.lastMouseMove = now;
        }

        state.pointerLocked = !!document.pointerLockElement;

        if (now % 2000 < 16) {
            const cutoff = now - 3000;
            for (const [k,v] of state.lastPositions.entries()) if (v.time < cutoff) state.lastPositions.delete(k);
            for (const [k,v] of state.velocities.entries())    if (v.time < cutoff) state.velocities.delete(k);
            for (const [k,t] of state.deadPositions.entries()) if (t < cutoff)      state.deadPositions.delete(k);
        }

        clearFrameBuffers();
    }

    function clearFrameBuffers() { state.matricesByProgram.clear(); }

    // =====================================================================
    // GUI
    // =====================================================================
    const TABS = [
        { id: 'aim',    label: 'AIMBOT',  icon: '\u25CE' },
        { id: 'esp',    label: 'ESP',     icon: '\u25A3' },
        { id: 'combat', label: 'COMBAT',  icon: '\u2694' },
        { id: 'other',  label: 'OTHER',   icon: '\u2699' },
        { id: 'config', label: 'CONFIGS', icon: '\u25A1' },
    ];
    let currentTab = 'aim';

    const CSS = `
#d2-root *{box-sizing:border-box;margin:0;padding:0;font-family:'Segoe UI',system-ui,-apple-system,sans-serif}
#d2-root{position:fixed;display:flex;flex-direction:row;width:820px;height:540px;background:#0d0d11;border:1px solid rgba(255,255,255,.04);border-radius:10px;color:#c5c5cc;z-index:2147483646;user-select:none;box-shadow:0 30px 80px rgba(0,0,0,.85);overflow:hidden}
#d2-root .d2-sidebar{width:160px;background:#0a0a0e;display:flex;flex-direction:column;border-right:1px solid rgba(255,255,255,.04)}
#d2-root .d2-brand{padding:20px 12px 16px;text-align:center;overflow:hidden}
#d2-root .d2-brand-logo{font-size:22px;font-weight:900;letter-spacing:2px;color:#fff;line-height:1;white-space:nowrap}
#d2-root .d2-brand-logo span{color:var(--accent)}
#d2-root .d2-brand-sub{font-size:9px;color:#444;letter-spacing:4px;text-transform:uppercase;margin-top:2px}
#d2-root .d2-nav{flex:1;padding:8px;display:flex;flex-direction:column;gap:2px}
#d2-root .d2-nav-item{display:flex;align-items:center;gap:10px;padding:10px 14px;border-radius:6px;font-size:11px;font-weight:600;letter-spacing:1px;color:#555;cursor:pointer;transition:all .12s;position:relative}
#d2-root .d2-nav-item:hover{background:rgba(255,255,255,.025);color:#999}
#d2-root .d2-nav-item.active{color:var(--accent);background:rgba(168,85,247,.06)}
#d2-root .d2-nav-item.active::before{content:'';position:absolute;left:0;top:6px;bottom:6px;width:3px;background:var(--accent);border-radius:0 3px 3px 0}
#d2-root .d2-nav-icon{font-size:14px;width:18px;text-align:center;opacity:.8}
#d2-root .d2-status-box{margin:8px;padding:12px;background:rgba(255,255,255,.02);border:1px solid rgba(255,255,255,.04);border-radius:8px}
#d2-root .d2-status-name{display:flex;align-items:center;gap:6px;font-size:11px;font-weight:700;color:#ddd}
#d2-root .d2-status-dot{width:7px;height:7px;border-radius:50%;background:#00e676;box-shadow:0 0 6px #00e676}
#d2-root .d2-status-label{font-size:9px;color:#00e676;font-weight:700;letter-spacing:1px;margin-top:3px}
#d2-root .d2-status-ver{font-size:8px;color:#333;font-family:monospace;margin-top:6px}
#d2-root .d2-main{flex:1;display:flex;flex-direction:column;min-width:0}
#d2-root .d2-topbar{display:flex;align-items:center;justify-content:space-between;height:42px;padding:0 16px;background:#09090c;border-bottom:1px solid rgba(255,255,255,.04);cursor:move;flex-shrink:0}
#d2-root .d2-tab-pills{display:flex;gap:0;height:100%}
#d2-root .d2-tab-pill{display:flex;align-items:center;gap:6px;padding:0 16px;font-size:11px;font-weight:600;letter-spacing:1px;color:#555;cursor:pointer;border-bottom:2px solid transparent;transition:all .12s;height:100%}
#d2-root .d2-tab-pill:hover{color:#999}
#d2-root .d2-tab-pill.active{color:var(--accent);border-bottom-color:var(--accent)}
#d2-root .d2-tab-pill .tp-icon{font-size:12px;opacity:.7}
#d2-root .d2-win-btns{display:flex;gap:2px}
#d2-root .d2-win-btn{width:28px;height:28px;display:flex;align-items:center;justify-content:center;background:transparent;border:none;color:#444;cursor:pointer;border-radius:4px;font-size:14px;transition:all .12s}
#d2-root .d2-win-btn:hover{background:rgba(255,255,255,.05);color:#ccc}
#d2-root .d2-win-btn.close:hover{background:#c53030;color:#fff}
#d2-root .d2-body{flex:1;overflow-y:auto;overflow-x:hidden;padding:16px 18px;scrollbar-width:thin;scrollbar-color:rgba(255,255,255,.08) transparent}
#d2-root .d2-body::-webkit-scrollbar{width:4px}
#d2-root .d2-body::-webkit-scrollbar-thumb{background:rgba(255,255,255,.1);border-radius:4px}
#d2-root .d2-body::-webkit-scrollbar-track{background:transparent}
#d2-root .d2-grid{display:grid;grid-template-columns:1fr 1fr;gap:14px}
#d2-root .d2-grid .span-2{grid-column:span 2}
#d2-root .d2-card{background:rgba(255,255,255,.018);border:1px solid rgba(255,255,255,.04);border-radius:8px;padding:14px 16px;min-width:0}
#d2-root .d2-card-title{font-size:10px;font-weight:700;letter-spacing:2px;color:#666;text-transform:uppercase;margin-bottom:12px;padding-bottom:8px;border-bottom:1px solid rgba(255,255,255,.04)}
#d2-root .d2-row{display:flex;align-items:center;justify-content:space-between;padding:4px 0;min-height:28px}
#d2-root .d2-row>.label{font-size:12px;color:#bbb;white-space:nowrap}
#d2-root .d2-toggle{position:relative;width:36px;height:18px;cursor:pointer;display:inline-block;flex-shrink:0}
#d2-root .d2-toggle input{opacity:0;width:0;height:0;position:absolute}
#d2-root .d2-toggle .slider{position:absolute;inset:0;background:rgba(255,255,255,.07);border-radius:10px;transition:all .2s}
#d2-root .d2-toggle .slider:before{content:'';position:absolute;width:14px;height:14px;left:2px;top:2px;background:#666;border-radius:50%;transition:all .2s}
#d2-root .d2-toggle input:checked+.slider{background:color-mix(in srgb,var(--accent) 40%,transparent)}
#d2-root .d2-toggle input:checked+.slider:before{transform:translateX(18px);background:var(--accent);box-shadow:0 0 8px color-mix(in srgb,var(--accent) 60%,transparent)}
#d2-root .d2-slider{padding:5px 0}
#d2-root .d2-slider-label{display:flex;justify-content:space-between;font-size:11px;color:#888;margin-bottom:4px}
#d2-root .d2-slider-label .val{color:var(--accent);font-family:'Cascadia Code','Consolas',monospace;font-size:11px;font-weight:700}
#d2-root input[type=range]{-webkit-appearance:none;width:100%;height:4px;background:rgba(255,255,255,.06);border-radius:4px;outline:none;cursor:pointer}
#d2-root input[type=range]::-webkit-slider-thumb{-webkit-appearance:none;width:14px;height:14px;background:var(--accent);border-radius:50%;cursor:pointer;border:2px solid #0d0d11;box-shadow:0 0 6px color-mix(in srgb,var(--accent) 50%,transparent)}
#d2-root .d2-select{padding:4px 0}
#d2-root .d2-select .label{font-size:11px;color:#777;margin-bottom:4px;display:block}
#d2-root select{width:100%;background:#111116;color:#ccc;border:1px solid rgba(255,255,255,.06);padding:7px 10px;border-radius:6px;font-size:11px;outline:none;cursor:pointer;font-family:inherit}
#d2-root select:hover{border-color:rgba(255,255,255,.12)}
#d2-root select:focus{border-color:var(--accent)}
#d2-root .d2-keybind{background:#111116;color:#ccc;border:1px solid rgba(255,255,255,.06);padding:5px 12px;border-radius:5px;font-size:10px;font-family:'Cascadia Code','Consolas',monospace;font-weight:600;cursor:pointer;min-width:72px;text-align:center;transition:all .12s}
#d2-root .d2-keybind:hover{border-color:var(--accent);color:var(--accent)}
#d2-root .d2-keybind.listening{background:var(--accent);color:#000;animation:d2Pulse 1s infinite}
@keyframes d2Pulse{0%,100%{opacity:1}50%{opacity:.5}}
#d2-root .d2-btn{width:100%;padding:9px;background:rgba(255,255,255,.025);color:var(--accent);border:1px solid rgba(255,255,255,.05);border-radius:6px;cursor:pointer;font-size:10px;font-weight:700;letter-spacing:1.2px;text-transform:uppercase;transition:all .15s;font-family:inherit}
#d2-root .d2-btn:hover{background:rgba(255,255,255,.05);border-color:var(--accent)}
#d2-root .d2-btn.danger{color:#ff5c5c}
#d2-root .d2-btn.danger:hover{border-color:#ff5c5c}
#d2-root .d2-stats{display:grid;grid-template-columns:1fr 1fr 1fr;gap:8px}
#d2-root .d2-stat{background:rgba(255,255,255,.02);border:1px solid rgba(255,255,255,.04);border-radius:6px;padding:10px;text-align:center}
#d2-root .d2-stat-val{font-size:20px;font-weight:800;color:var(--accent);font-family:'Cascadia Code','Consolas',monospace}
#d2-root .d2-stat-lbl{font-size:7px;color:#444;text-transform:uppercase;letter-spacing:2px;margin-top:2px}
#d2-root .d2-badge{display:flex;align-items:center;justify-content:space-between;gap:8px;background:rgba(255,255,255,.02);border:1px solid rgba(255,255,255,.04);border-radius:6px;padding:10px 14px;margin-top:10px}
#d2-root .d2-badge .lbl{font-size:9px;color:#555;text-transform:uppercase;letter-spacing:2px}
#d2-root .d2-badge .val{font-size:16px;font-weight:800;color:var(--accent);font-family:'Cascadia Code','Consolas',monospace}
#d2-root .d2-badge .hint{font-size:9px;color:#444;font-family:monospace}
#d2-root .d2-color{width:28px;height:28px;border:1px solid rgba(255,255,255,.08);border-radius:6px;padding:0;background:var(--accent);cursor:pointer;flex-shrink:0}
#d2-root input[type=color]{opacity:0;width:0;height:0;position:absolute}
`;

    function row(label, inner) {
        return `<div class="d2-row"><span class="label">${label}</span>${inner}</div>`;
    }
    function toggle(id, checked) {
        return `<label class="d2-toggle"><input type="checkbox" id="${id}" ${checked ? 'checked' : ''}><span class="slider"></span></label>`;
    }
    function slider(id, label, val, min, max, step) {
        return `<div class="d2-slider"><div class="d2-slider-label"><span>${label}</span><span class="val" id="${id}-v">${val}</span></div><input type="range" id="${id}" min="${min}" max="${max}" step="${step}" value="${val}"></div>`;
    }
    function select(id, label, options, current) {
        const opts = options.map(o => `<option value="${o.v}" ${String(current)===String(o.v)?'selected':''}>${o.l}</option>`).join('');
        return `<div class="d2-select"><span class="label">${label}</span><select id="${id}">${opts}</select></div>`;
    }
    function card(title, content, extraClass) {
        return `<div class="d2-card ${extraClass||''}"><div class="d2-card-title">${title}</div>${content}</div>`;
    }
    function keybind(field, value) {
        return `<button class="d2-keybind" data-rebind="${field}">${value || '\u2014'}</button>`;
    }

    function aimTab() {
        return `<div class="d2-grid">` +
            card('General', [
                row('Aimbot', toggle('t-aim', config.aimbotEnabled)),
                row('Aim Key', keybind('aimKey', config.aimKey)),
                row('Visible Check', toggle('t-vis', config.visibilityCheck)),
                row('Target Lock', toggle('t-lock', config.targetLock)),
            ].join('')) +
            card('Target', [
                select('sel-prio','Selection',[{v:1,l:'Closest to Crosshair'},{v:0,l:'Closest Distance'}], config.priority),
                select('sel-bone','Hitbox',[{v:0,l:'Head'},{v:1,l:'Neck'},{v:2,l:'Body'}], config.hitbox),
                slider('s-lockd','Lock Distance', config.lockDist, 5, 200, 1),
                slider('s-smooth','Smoothing', config.aimSmooth, 1, 10, 0.1),
            ].join('')) +
            card('Prediction', [
                row('Enabled', toggle('t-pred', config.predictionEnabled)),
                row('Track Velocity', toggle('t-vel', config.velocityTracking)),
                slider('s-pred','Strength', config.predictionStrength, 0.5, 3, 0.1),
            ].join('')) +
            card('TriggerBot', [
                row('Enabled', toggle('t-trig', config.triggerBot)),
                slider('s-trigr','Trigger Radius', config.triggerRadius, 4, 30, 1),
                slider('s-trigd','Trigger Delay', config.triggerDelay, 0, 500, 10),
            ].join('')) +
            `<div class="d2-badge span-2"><span class="lbl">Target Program</span><span class="val" id="d2-target-val">${currentTargetID()}</span><span class="hint">${config.autoDetect?'AUTO':'MANUAL'}</span></div>` +
        `</div>`;
    }

    function espTab() {
        return `<div class="d2-grid">` +
            card('ESP', [
                row('Box ESP', toggle('t-esp', config.espEnabled)),
                row('Distance', toggle('t-dist', config.showDistance)),
                row('Tracers', toggle('t-tracers', config.showTracers)),
                slider('s-thick','Box Thickness', config.espThickness, 1, 5, 0.5),
            ].join('')) +
            card('Overlay', [
                row('FOV Circle', toggle('t-fov', config.showFov)),
                row('FOV Gradient', toggle('t-grad', config.fovGradient)),
                slider('s-fov','FOV Radius', config.fov, 50, 600, 10),
                row('Crosshair', toggle('t-cross', config.showCrosshair)),
            ].join('')) +
            card('Radar', [
                row('Minimap', toggle('t-radar', config.radarEnabled)),
                row('Off-Screen Arrows', toggle('t-offscreen', config.offScreenIndicators)),
                slider('s-rsize','Radar Size', config.radarSize, 80, 200, 10),
                slider('s-rrange','Radar Range', config.radarRange, 30, 200, 10),
            ].join('')) +
            card('Display', [
                row('Show FPS', toggle('t-fps', config.showFPS)),
                row('Debug Strip', toggle('t-dbg', config.debugOverlay)),
            ].join('')) +
        `</div>`;
    }

    function combatTab() {
        return `<div class="d2-grid">` +
            card('Crouch Spam', [
                row('Enabled', toggle('t-crouch', config.crouchSpam)),
                slider('s-crouchspd','Speed (ms)', config.crouchSpamSpeed, 20, 300, 10),
            ].join('')) +
            card('Auto Strafe', [
                row('Enabled', toggle('t-strafe', config.autoStrafe)),
                slider('s-strafespd','Speed (ms)', config.autoStrafeSpeed, 40, 300, 10),
            ].join('')) +
            card('Anti-AFK', [
                row('Enabled', toggle('t-afk', config.antiAFK)),
            ].join('')) +
            card('Performance', [
                row('Performance Mode', toggle('t-perf', config.performanceMode)),
                row('Block Fullscreen', toggle('t-blockfs', config.blockFullscreen)),
            ].join('')) +
        `</div>`;
    }

    function otherTab() {
        return `<div class="d2-grid">` +
            card('FOV Hack', [
                row('Enabled', toggle('t-fovhack', config.fovHack)),
                slider('s-fovscale','FOV Scale', config.fovHackScale, 0.3, 1.0, 0.05),
            ].join('')) +
            card('Stats', `
                <div class="d2-stats">
                    <div class="d2-stat"><div class="d2-stat-val" id="stat-fps">${state.fps}</div><div class="d2-stat-lbl">FPS</div></div>
                    <div class="d2-stat"><div class="d2-stat-val" id="stat-tgts">${state.totalTargets}</div><div class="d2-stat-lbl">Targets</div></div>
                    <div class="d2-stat"><div class="d2-stat-val" id="stat-prog">${state.programScores.size}</div><div class="d2-stat-lbl">Programs</div></div>
                </div>
            `) +
            card('Detection', [
                `<div style="display:flex;gap:8px"><button class="d2-btn" id="btn-auto">${config.autoDetect?'Auto Detect ON':'Enable Auto'}</button><button class="d2-btn" id="btn-reset-tgt">Reset Target</button></div>`,
            ].join(''), 'span-2') +
        `</div>`;
    }

    function configTab() {
        return `<div class="d2-grid">` +
            card('Interface', [
                row('Menu Key', keybind('menuKey', config.menuKey)),
                row('Accent Color', `<label class="d2-color" style="background:${config.accentColor}"><input type="color" id="c-accent" value="${config.accentColor}"></label>`),
            ].join('')) +
            card('Danger Zone', `
                <button class="d2-btn danger" id="btn-reset">Reset All Settings</button>
            `) +
        `</div>`;
    }

    function tabContent() {
        if (currentTab === 'aim')    return aimTab();
        if (currentTab === 'esp')    return espTab();
        if (currentTab === 'combat') return combatTab();
        if (currentTab === 'other')  return otherTab();
        if (currentTab === 'config') return configTab();
        return '';
    }

    function createGUI() {
        if (document.getElementById('d2-root')) return;
        if (!document.body) return;

        let style = document.getElementById('d2-style');
        if (!style) {
            style = document.createElement('style');
            style.id = 'd2-style';
            style.textContent = CSS;
            document.head.appendChild(style);
        }
        document.documentElement.style.setProperty('--accent', config.accentColor);

        const root = document.createElement('div');
        root.id = 'd2-root';
        root.style.left = config.x + 'px';
        root.style.top  = config.y + 'px';
        root.style.display = config.menuVisible ? 'flex' : 'none';

        root.innerHTML = `
            <div class="d2-sidebar">
                <div class="d2-brand">
                    <div class="d2-brand-logo"><span>D</span>ESTINY</div>
                    <div class="d2-brand-sub">DEADSHOT</div>
                </div>
                <div class="d2-nav">
                    ${TABS.map(t => `<div class="d2-nav-item ${t.id===currentTab?'active':''}" data-tab="${t.id}"><span class="d2-nav-icon">${t.icon}</span><span>${t.label}</span></div>`).join('')}
                </div>
                <div class="d2-status-box">
                    <div class="d2-status-name"><span class="d2-status-dot"></span> DESTINY</div>
                    <div class="d2-status-label">STATUS: UNDETECTED</div>
                    <div class="d2-status-ver">Version 3.0.0<br>destiny.menu</div>
                </div>
            </div>
            <div class="d2-main">
                <div class="d2-topbar" id="d2-header">
                    <div class="d2-tab-pills">
                        ${TABS.map(t => `<div class="d2-tab-pill ${t.id===currentTab?'active':''}" data-tab="${t.id}"><span class="tp-icon">${t.icon}</span><span>${t.label}</span></div>`).join('')}
                    </div>
                    <div class="d2-win-btns">
                        <button class="d2-win-btn close" id="d2-close" title="Close">\u00D7</button>
                    </div>
                </div>
                <div class="d2-body" id="d2-body">${tabContent()}</div>
            </div>
        `;
        document.body.appendChild(root);

        // Drag
        const header = document.getElementById('d2-header');
        let drag = false, ox = 0, oy = 0;
        header.addEventListener('mousedown', (e) => {
            drag = true; ox = e.clientX - root.offsetLeft; oy = e.clientY - root.offsetTop; e.preventDefault();
        });
        window.addEventListener('mousemove', (e) => {
            if (!drag) return;
            const x = Math.max(0, Math.min(window.innerWidth - root.offsetWidth, e.clientX - ox));
            const y = Math.max(0, Math.min(window.innerHeight - root.offsetHeight, e.clientY - oy));
            root.style.left = x + 'px'; root.style.top = y + 'px';
            config.x = x; config.y = y;
        });
        window.addEventListener('mouseup', () => { if (drag) save(); drag = false; });

        root.querySelectorAll('.d2-nav-item, .d2-tab-pill').forEach(el => {
            el.addEventListener('click', (e) => { e.stopPropagation(); currentTab = el.dataset.tab; refreshGUI(); });
        });
        document.getElementById('d2-close').addEventListener('click', () => {
            config.menuVisible = false; root.style.display = 'none'; saveImmediate();
        });

        attachHandlers();
    }

    function refreshGUI() {
        const root = document.getElementById('d2-root');
        if (!root) { createGUI(); return; }
        document.documentElement.style.setProperty('--accent', config.accentColor);
        root.querySelectorAll('.d2-nav-item').forEach(el => el.classList.toggle('active', el.dataset.tab === currentTab));
        root.querySelectorAll('.d2-tab-pill').forEach(el => el.classList.toggle('active', el.dataset.tab === currentTab));
        const body = document.getElementById('d2-body');
        if (body) body.innerHTML = tabContent();
        attachHandlers();
        refreshTargetBadge();
    }

    function bindToggle(id, field) {
        const el = document.getElementById(id);
        if (el) el.addEventListener('change', e => { config[field] = e.target.checked; save(); });
    }
    function bindSlider(id, field, parser = parseFloat) {
        const el = document.getElementById(id);
        const valEl = document.getElementById(id + '-v');
        if (el) el.addEventListener('input', e => {
            const v = parser(e.target.value);
            config[field] = v;
            if (valEl) valEl.textContent = v;
            save();
        });
    }
    function bindSelect(id, field, parser = (x => x)) {
        const el = document.getElementById(id);
        if (el) el.addEventListener('change', e => { config[field] = parser(e.target.value); save(); });
    }

    function attachHandlers() {
        bindToggle('t-aim',   'aimbotEnabled');
        bindToggle('t-pred',  'predictionEnabled');
        bindToggle('t-vel',   'velocityTracking');
        bindToggle('t-lock',  'targetLock');
        bindToggle('t-trig',  'triggerBot');
        bindToggle('t-crouch','crouchSpam');
        bindToggle('t-strafe','autoStrafe');
        bindSlider('s-crouchspd','crouchSpamSpeed', parseInt);
        bindSlider('s-strafespd','autoStrafeSpeed', parseInt);
        bindSlider('s-lockd', 'lockDist', parseInt);
        bindSlider('s-smooth','aimSmooth');
        bindSlider('s-pred',  'predictionStrength');
        bindSlider('s-trigr', 'triggerRadius', parseInt);
        bindSlider('s-trigd', 'triggerDelay', parseInt);
        bindSelect('sel-bone','hitbox', parseInt);
        bindSelect('sel-prio','priority', parseInt);

        const btnAuto = document.getElementById('btn-auto');
        if (btnAuto) btnAuto.addEventListener('click', () => { config.autoDetect = true; save(); refreshGUI(); });
        const btnResetTgt = document.getElementById('btn-reset-tgt');
        if (btnResetTgt) btnResetTgt.addEventListener('click', () => {
            config.autoDetect = true; config.manualTargetID = -1;
            state.detectedTargetID = -1; state.programScores.clear();
            save(); refreshGUI();
        });

        bindToggle('t-esp',     'espEnabled');
        bindToggle('t-dist',    'showDistance');
        bindToggle('t-tracers', 'showTracers');
        bindSlider('s-thick',   'espThickness');
        bindToggle('t-fov',     'showFov');
        bindToggle('t-grad',    'fovGradient');
        bindSlider('s-fov',     'fov', parseInt);
        bindToggle('t-cross',   'showCrosshair');
        bindToggle('t-fps',     'showFPS');
        bindToggle('t-dbg',     'debugOverlay');

        bindToggle('t-radar',    'radarEnabled');
        bindSlider('s-rsize',    'radarSize', parseInt);
        bindSlider('s-rrange',   'radarRange', parseInt);
        bindToggle('t-offscreen','offScreenIndicators');

        bindToggle('t-vis',     'visibilityCheck');
        bindToggle('t-perf',    'performanceMode');
        bindToggle('t-fovhack', 'fovHack');
        bindSlider('s-fovscale','fovHackScale');
        bindToggle('t-afk',     'antiAFK');
        const blockFs = document.getElementById('t-blockfs');
        if (blockFs) blockFs.addEventListener('change', e => {
            config.blockFullscreen = e.target.checked; saveImmediate();
            if (confirm('Reload to apply fullscreen setting?')) location.reload();
        });

        const accent = document.getElementById('c-accent');
        if (accent) accent.addEventListener('input', e => {
            config.accentColor = e.target.value;
            document.documentElement.style.setProperty('--accent', config.accentColor);
            const swatch = accent.parentElement;
            if (swatch) swatch.style.background = config.accentColor;
            save();
        });
        const reset = document.getElementById('btn-reset');
        if (reset) reset.addEventListener('click', () => {
            if (!confirm('Reset all settings?')) return;
            config = { ...defaultConfig };
            saveImmediate();
            refreshGUI();
        });

        document.querySelectorAll('#d2-root .d2-keybind').forEach(btn => {
            const field = btn.dataset.rebind;
            const aimKeyDropdown = field === 'aimKey';
            btn.addEventListener('click', () => {
                if (aimKeyDropdown) {
                    const opts = ['RightClick','LeftClick','ShiftLeft','AltLeft','Always'];
                    const idx = opts.indexOf(config.aimKey);
                    config.aimKey = opts[(idx+1)%opts.length];
                    saveImmediate(); refreshGUI();
                    return;
                }
                document.querySelectorAll('#d2-root .d2-keybind').forEach(b => b.classList.remove('listening'));
                btn.classList.add('listening');
                btn.textContent = '\u2026';
                state.rebindingField = field;
            });
        });
    }

    function refreshTargetBadge() {
        const tv = document.getElementById('d2-target-val');
        if (tv) tv.textContent = currentTargetID();
    }
    function updateStatusBar() {
        const c = document.getElementById('stat-fps');  if (c) c.textContent = state.fps;
        const d = document.getElementById('stat-tgts'); if (d) d.textContent = state.totalTargets;
        const e = document.getElementById('stat-prog'); if (e) e.textContent = state.programScores.size;
    }

    // =====================================================================
    // INIT
    // =====================================================================
    function init() {
        setupCanvas();
        createGUI();
    }

    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', init);
    } else {
        init();
    }
})();