Universal Crosshair by Kakoncheater

Customizable crosshairs for any website.

// ==UserScript==
// @name         Universal Crosshair by Kakoncheater
// @namespace    http://tampermonkey.net/
// @version      4.23
// @description  Customizable crosshairs for any website.
// @author       made by Kakoncheater
// @match        *://*/*
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    // --- Crosshair Settings ---
    let crosshairStyle = "cross"; // Options: "cross", "dot", "circle", "square"
    let crosshairColor = "white";
    let crosshairSize = 20; // Unified Size
    let crosshairThickness = 2;
    let crosshairGap = 5;
    let crosshairOpacity = 1; // Values between 0.1 and 1

    // --- Menu Settings ---
    let menuBackgroundColor = "rgba(0, 0, 0, 0.8)"; // Initial menu background color
    let menuOpacity = 1; // Initial menu opacity (SET TO 1)

    // --- UI Elements ---
    let menuVisible = true; // Initial menu visibility
    let crosshairSettingsVisible = false; // Initial visibility of crosshair settings
    let crosshairEnabled = true; // Initial state of crosshair

    // --- Function to Create a UI Element ---
    function createElement(tag, attributes = {}, styles = {}) {
        const element = document.createElement(tag);
        for (const key in attributes) {
            element.setAttribute(key, attributes[key]);
        }
        for (const key in styles) {
            element.style[key] = styles[key];
        }
        return element; //Return the element
    }

    // --- Function to Update Crosshair Style ---
    function updateCrosshairStyle() {
        // Remove existing crosshair elements if any
        if (window.crosshairElements) {
            window.crosshairElements.forEach(el => el.remove());
        }
        window.crosshairElements = [];

        if (!crosshairEnabled || crosshairStyle === "none") return;

        if (crosshairStyle === "cross") { // Cross is Now Just +

            const halfSize = crosshairSize / 2;

            // Top Vertical Bar
            const verticalBarTop = createElement('div', {}, {
                position: 'fixed',
                top: '50%',
                left: '50%',
                transform: `translate(-50%, calc(-50% - ${halfSize + crosshairGap}px))`,
                width: crosshairThickness + 'px',
                height: crosshairSize + 'px',
                backgroundColor: crosshairColor,
                opacity: crosshairOpacity,
                zIndex: 10000,
            });

            // Bottom Vertical Bar
            const verticalBarBottom = createElement('div', {}, {
                position: 'fixed',
                top: '50%',
                left: '50%',
                transform: `translate(-50%, calc(-50% + ${halfSize + crosshairGap}px))`,
                width: crosshairThickness + 'px',
                height: crosshairSize + 'px',
                backgroundColor: crosshairColor,
                opacity: crosshairOpacity,
                zIndex: 10000,
            });

            // Left Horizontal Bar
            const HorizontalBarLeft = createElement('div', {}, {
                position: 'fixed',
                top: '50%',
                left: '50%',
                transform: `translate(calc(-50% - ${halfSize + crosshairGap}px), -50%)`,
                width: crosshairSize + 'px',
                height: crosshairThickness + 'px',
                backgroundColor: crosshairColor,
                opacity: crosshairOpacity,
                zIndex: 10000,
            });

            // Right Horizontal Bar
            const HorizontalBarRight = createElement('div', {}, {
                position: 'fixed',
                top: '50%',
                left: '50%',
                transform: `translate(calc(-50% + ${halfSize + crosshairGap}px), -50%)`,
                width: crosshairSize + 'px',
                height: crosshairThickness + 'px',
                backgroundColor: crosshairColor,
                opacity: crosshairOpacity,
                zIndex: 10000,
            });

            window.crosshairElements.push(verticalBarTop);
            window.crosshairElements.push(verticalBarBottom);
            window.crosshairElements.push(HorizontalBarLeft);
            window.crosshairElements.push(HorizontalBarRight);

        } else if (crosshairStyle === "dot") {
            const dot = createElement('div', {}, {
                position: 'fixed',
                top: '50%',
                left: '50%',
                transform: 'translate(-50%, -50%)',
                width: crosshairSize + 'px',  // Using unified size for dot diameter
                height: crosshairSize + 'px', // Using unified size for dot diameter
                backgroundColor: crosshairColor,
                borderRadius: '50%',
                opacity: crosshairOpacity,
                zIndex: 10000,
            });
            window.crosshairElements.push(dot);

        } else if (crosshairStyle === "circle") {
            const circle = createElement('div', {}, {
                position: 'fixed',
                top: '50%',
                left: '50%',
                transform: 'translate(-50%, -50%)',
                width: (crosshairSize * 2) + 'px', // Using unified size for circle diameter
                height: (crosshairSize * 2) + 'px', // Using unified size for circle diameter
                borderRadius: '50%',
                border: crosshairThickness + 'px solid ' + crosshairColor,
                opacity: crosshairOpacity,
                boxSizing: 'border-box',
                zIndex: 10000,
            });
            window.crosshairElements.push(circle);
        } else if (crosshairStyle === "square") {
            const square = createElement('div', {}, {
                position: 'fixed',
                top: '50%',
                left: '50%',
                transform: 'translate(-50%, -50%)',
                width: crosshairSize + 'px', // Using unified size for square side
                height: crosshairSize + 'px', // Using unified size for square side
                border: crosshairThickness + 'px solid ' + crosshairColor,
                opacity: crosshairOpacity,
                boxSizing: 'border-box',
                zIndex: 10000,
            });
            window.crosshairElements.push(square);
        }
        window.crosshairElements.forEach(el => document.body.appendChild(el));
    }

    // --- Create the Main Menu ---
    const menuContainer = createElement('div', {}, {
        position: 'fixed',
        top: '10px',
        left: '10px',
        zIndex: '10000',
        backgroundColor: menuBackgroundColor, // Use menu background color variable
        padding: '10px',
        borderRadius: '5px',
        color: 'white',
        fontFamily: 'sans-serif',
        display: menuVisible ? 'block' : 'none', // Initial visibility
        opacity: menuOpacity, // Use menu opacity variable
    });

    // --- Menu Title ---
    const menuTitle = createElement('div', {}, {
        textAlign: 'center',
        fontWeight: 'bold',
        marginBottom: '10px',
        fontSize: '16px'
    });
    menuTitle.textContent = "Universal Crosshair";
    menuContainer.appendChild(menuTitle);

    // --- Watermark ---
    const watermark = createElement('div', {}, {
        position: 'absolute',
        bottom: '5px',
        right: '5px',
        fontSize: '10px',
        color: 'rgba(255, 255, 255, 0.5)' // Semi-transparent white
    });
    watermark.textContent = "made by Kakoncheater";

     // --- Helper function to create labels and inputs ---
   function createSliderSetting(labelText, currentValue, changeHandler, min, max, step = 1) {
        const label = createElement('label', {}, { display: 'block', marginBottom: '5px' });
        label.textContent = labelText + ':';

        const slider = createElement('input', { type: 'range', value: currentValue, min: min, max: max, step:step, style: { width: '150px' } }); // Increased width
        slider.addEventListener('input', function() {
            changeHandler(parseFloat(this.value)); // Call the handler with the value, not the event
        });

        label.appendChild(slider);
        return label;
    }

    // --- Menu Background Color Picker ---
    const menuColorLabel = createElement('label', {}, { display: 'block', marginBottom: '5px' });
    menuColorLabel.textContent = 'Menu Background Color:';
    const menuColorInput = createElement('input', { type: 'color', value: rgbaToHex(menuBackgroundColor) }, {width: '50px'});
    menuColorInput.addEventListener('change', function() {
        menuBackgroundColor = this.value;
        menuContainer.style.backgroundColor = menuBackgroundColor;
    });
    menuColorLabel.appendChild(menuColorInput);
    menuContainer.appendChild(menuColorLabel);

   // --- Menu Opacity Setting ---
    const menuOpacityLabel = createSliderSetting(
        'Menu Opacity',
        menuOpacity,
        function(newValue) {
            menuOpacity = newValue;
            menuContainer.style.opacity = newValue;
        },
        0.1,
        1,
        0.05 // Step
    );
    menuContainer.appendChild(menuOpacityLabel);

    // --- Crosshair Style Dropdown ---
    const styleLabel = createElement('label', {}, { display: 'block', marginBottom: '5px' });
    styleLabel.textContent = 'Crosshair Style:';
    const styleSelect = createElement('select', {}, { width: '100px' });
    const styles = ["cross", "dot", "circle", "square"];
    styles.forEach(style => {
        const option = createElement('option', { value: style });
        option.textContent = style.charAt(0).toUpperCase() + style.slice(1); // Capitalize first letter
        styleSelect.appendChild(option);
    });
    styleSelect.value = crosshairStyle; // Set initial value
    styleSelect.addEventListener('change', function() {
        crosshairStyle = this.value;
        updateCrosshairStyle();
    });
    styleLabel.appendChild(styleSelect);
    menuContainer.appendChild(styleLabel);

    // --- Color Picker ---
    const colorLabel = createElement('label', {}, { display: 'block', marginBottom: '5px' });
    colorLabel.textContent = 'Crosshair Color:';
    const colorInput = createElement('input', { type: 'color', value: crosshairColor }, {width: '50px'});
    colorInput.addEventListener('change', function() {
        crosshairColor = this.value;
        updateCrosshairStyle();
    });
    colorLabel.appendChild(colorInput);
    menuContainer.appendChild(colorLabel);

   // --- Crosshair Opacity Setting ---
    const crosshairOpacityLabel = createSliderSetting(
        'Crosshair Opacity',
        crosshairOpacity,
        function(newValue) {
            crosshairOpacity = newValue;
            updateCrosshairStyle();
        },
        0.1,
        1,
        0.05 // Step
    );
    menuContainer.appendChild(crosshairOpacityLabel);

    // --- Create Crosshair Settings Menu ---
    const crosshairSettingsContainer = createElement('div', {}, {
        position: 'fixed',
        top: '10px',
        left: '0px', // Initialized to 0, updated when shown
        zIndex: '10001',
        backgroundColor: 'rgba(0, 0, 0, 0.7)',
        padding: '10px',
        borderRadius: '5px',
        color: 'white',
        fontFamily: 'sans-serif',
        display: crosshairSettingsVisible ? 'block' : 'none',
    });

    // --- Size Setting ---
    const sizeLabel = createSliderSetting('Size', crosshairSize, function(newValue) {
        crosshairSize = newValue;
        updateCrosshairStyle();
    }, 1, 100);
    crosshairSettingsContainer.appendChild(sizeLabel);

    // --- Thickness Setting ---
    const thicknessLabel = createSliderSetting('Thickness', crosshairThickness, function(newValue) {
        crosshairThickness = newValue;
        updateCrosshairStyle();
    }, 1, 100);
    crosshairSettingsContainer.appendChild(thicknessLabel);

    // --- Gap Setting ---
    const gapLabel = createSliderSetting('Gap', crosshairGap, function(newValue) {
        crosshairGap = newValue;
        updateCrosshairStyle();
    }, 1, 100);
    crosshairSettingsContainer.appendChild(gapLabel);

    // --- Close Button for Settings Menu ---
    const closeButton = createElement('button', {}, { marginBottom: '5px' });
    closeButton.textContent = "Close";
    closeButton.addEventListener('click', function() {
        crosshairSettingsVisible = false;
        crosshairSettingsContainer.style.display = 'none';
    });
    crosshairSettingsContainer.appendChild(closeButton);

    // --- Toggle Crosshair Settings Button ---
    const changeCrosshairButton = createElement('button', {}, { marginBottom: '5px' });
    changeCrosshairButton.textContent = "Change Crosshair";
    changeCrosshairButton.addEventListener('click', function() {
        crosshairSettingsVisible = !crosshairSettingsVisible;
        crosshairSettingsContainer.style.display = crosshairSettingsVisible ? 'block' : 'none';
        // Reposition on open
        if (crosshairSettingsVisible) {
            crosshairSettingsContainer.style.left = parseFloat(menuContainer.style.left) + menuContainer.offsetWidth + 'px';
        }
    });
    menuContainer.appendChild(changeCrosshairButton);

     // --- Toggle Crosshair Button ---
    const toggleCrosshairButton = createElement('button', {}, {
        marginBottom: '5px',
        backgroundColor: crosshairEnabled ? 'green' : 'red',
        color: 'white',
        border: 'none',
        padding: '5px 10px',
        borderRadius: '3px',
        cursor: 'pointer'
    });

    function updateToggleButtonText() {
        toggleCrosshairButton.textContent = crosshairEnabled ? "Crosshair ON" : "Crosshair OFF";
    }

    updateToggleButtonText(); // Set initial text

    toggleCrosshairButton.addEventListener('click', function() {
        crosshairEnabled = !crosshairEnabled;
        toggleCrosshairButton.style.backgroundColor = crosshairEnabled ? 'green' : 'red';
        updateToggleButtonText();
        updateCrosshairStyle();
    });
    menuContainer.appendChild(toggleCrosshairButton);

    // --- Function to handle Insert key press ---
    function handleInsertKeyPress(event) {
        if (event.key === 'Insert') {
            menuVisible = !menuVisible;
            menuContainer.style.display = menuVisible ? 'block' : 'none';
            if (!menuVisible) { // Also hide crosshair settings if main menu is hidden
                crosshairSettingsVisible = false;
                crosshairSettingsContainer.style.display = 'none';
            }
        }
    }

    // --- Hotkey to toggle menu visibility ---
    document.addEventListener('keydown', handleInsertKeyPress);

    // --- Helper function to convert RGBA to Hex for color picker ---
    function rgbaToHex(rgba) {
        const match = rgba.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*([\d.]+))?\)/);
        if (match) {
            const r = parseInt(match[1]);
            const g = parseInt(match[2]);
            const b = parseInt(match[3]);
            return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1, 7);
        }
        return "#000000"; // Default to black if parsing fails
    }

    // --- Append Watermark ---
    menuContainer.appendChild(watermark);

    // --- Append Menus to Body ---
    document.body.appendChild(menuContainer);
    document.body.appendChild(crosshairSettingsContainer);

    // --- Initialize Crosshair ---
    updateCrosshairStyle();

    // Set initial menu opacity to max
    menuContainer.style.opacity = menuOpacity;

})();

// --- Set the position of crosshairSettingsContainer after the DOM is fully loaded ---
window.addEventListener('load', function() {
    const menuContainer = document.querySelector('div[style*="z-index: 10000;"]'); // Select the menu
    const crosshairSettingsContainer = document.querySelector('div[style*="z-index: 10001;"]'); // Select settings

    if (menuContainer && crosshairSettingsContainer) {
        crosshairSettingsContainer.style.left = parseFloat(menuContainer.style.left) + menuContainer.offsetWidth + 'px';
    } else {
        console.warn("Universal Crosshair: Could not find menu or settings container to position correctly.");
    }
});