Kawaii Helper & Drawing Bot for Gartic.io

Helper for Gartic.io with auto-guess, drawing assistance, and drawing bot

Від 12.03.2025. Дивіться остання версія.

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(У мене вже є менеджер скриптів, дайте мені встановити його!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         Kawaii Helper & Drawing Bot for Gartic.io
// @name:tr      Gartic.io için Kawaii Yardımcı & Çizim Botu
// @namespace    http://tampermonkey.net/
// @version      2025-03-13
// @description  Helper for Gartic.io with auto-guess, drawing assistance, and drawing bot
// @description:tr  Gartic.io için otomatik tahmin, çizim yardımı ve çizim botu ile yardımcı
// @author       anonimbiri & Gartic-Developers
// @license      MIT
// @match        https://gartic.io/*
// @icon         https://i.imgur.com/efEvdp5.png
// @run-at       document-start
// @grant        none
// ==/UserScript==

// I used the word list from 'https://github.com/Gartic-Developers/Gartic-WordList/'.
// Thanks to Gartic Developers for providing this resource. Also, thanks to Qwyua!

(function() {
    'use strict';

    // Çeviri objesi
    const translations = {
        en: {
            "✧ Kawaii Helper ✧": "✧ Kawaii Helper ✧",
            "Guessing": "Guessing",
            "Drawing": "Drawing",
            "Auto Guess": "Auto Guess",
            "Speed": "Speed",
            "Custom Words": "Custom Words",
            "Drop word list here or click to upload": "Drop word list here or click to upload",
            "Enter pattern (e.g., ___e___)": "Enter pattern (e.g., ___e___)",
            "Type a pattern to see matches ✧": "Type a pattern to see matches ✧",
            "Upload a custom word list ✧": "Upload a custom word list ✧",
            "No words available ✧": "No words available ✧",
            "No matches found ✧": "No matches found ✧",
            "Tried Words": "Tried Words",
            "Drop image here or click to upload": "Drop image here or click to upload",
            "Draw Speed": "Draw Speed",
            "Max Colors": "Max Colors",
            "Draw Now ✧": "Draw Now ✧",
            "Made with ♥ by Anonimbiri & Gartic-Developers": "Made with ♥ by Anonimbiri & Gartic-Developers",
            "Loaded ${wordList['Custom'].length} words from ${file.name}": "Loaded ${wordList['Custom'].length} words from ${file.name}",
            "Not your turn or game not loaded! ✧": "Not your turn or game not loaded! ✧",
            "Game not ready or not your turn! ✧": "Game not ready or not your turn! ✧",
            "Canvas not accessible! ✧": "Canvas not accessible! ✧",
            "Canvas context not available! ✧": "Canvas context not available! ✧",
            "Temp canvas context failed! ✧": "Temp canvas context failed! ✧",
            "Image data error: ${e.message} ✧": "Image data error: ${e.message} ✧",
            "Drawing completed! ✧": "Drawing completed! ✧",
            "Failed to load image! ✧": "Failed to load image! ✧"
        },
        tr: {
            "✧ Kawaii Helper ✧": "✧ Kawaii Yardımcı ✧",
            "Guessing": "Tahmin",
            "Drawing": "Çizim",
            "Auto Guess": "Otomatik Tahmin",
            "Speed": "Hız",
            "Custom Words": "Özel Kelimeler",
            "Drop word list here or click to upload": "Kelime listesini buraya bırak veya yüklemek için tıkla",
            "Enter pattern (e.g., ___e___)": "Desen gir (ör., ___e___)",
            "Type a pattern to see matches ✧": "Eşleşmeleri görmek için bir desen yaz ✧",
            "Upload a custom word list ✧": "Özel bir kelime listesi yükle ✧",
            "No words available ✧": "Kelime yok ✧",
            "No matches found ✧": "Eşleşme bulunamadı ✧",
            "Tried Words": "Denenen Kelimeler",
            "Drop image here or click to upload": "Resmi buraya bırak veya yüklemek için tıkla",
            "Draw Speed": "Çizim Hızı",
            "Max Colors": "Maksimum Renk",
            "Draw Now ✧": "Şimdi Çiz ✧",
            "Made with ♥ by Anonimbiri & Gartic-Developers": "Anonimbiri & Gartic-Developers tarafından ♥ ile yapıldı",
            "Loaded ${wordList['Custom'].length} words from ${file.name}": "${file.name} dosyasından ${wordList['Custom'].length} kelime yüklendi",
            "Not your turn or game not loaded! ✧": "Sıra sende değil veya oyun yüklenmedi! ✧",
            "Game not ready or not your turn! ✧": "Oyun hazır değil veya sıra sende değil! ✧",
            "Canvas not accessible! ✧": "Tuval erişilemez! ✧",
            "Canvas context not available! ✧": "Tuval bağlamı kullanılamıyor! ✧",
            "Temp canvas context failed! ✧": "Geçici tuval bağlamı başarısız! ✧",
            "Image data error: ${e.message} ✧": "Görüntü verisi hatası: ${e.message} ✧",
            "Drawing completed! ✧": "Çizim tamamlandı! ✧",
            "Failed to load image! ✧": "Görüntü yüklenemedi! ✧"
        }
    };

    let currentLang = navigator.language.split('-')[0];
    if (!translations[currentLang]) {
        currentLang = 'en';
    }

    function localize(key, params = {}) {
        let text = translations[currentLang][key] || key;
        for (const [param, value] of Object.entries(params)) {
            text = text.replace(`\${${param}}`, value);
        }
        return text;
    }

    // Script interception (unchanged)
    Node.prototype.appendChild = new Proxy(Node.prototype.appendChild, {
        apply: function(target, thisArg, argumentsList) {
            const node = argumentsList[0];
            if (node.nodeName.toLowerCase() === 'script' && node.src && node.src.includes('room')) {
                console.log('Target script detected:', node.src);
                fetch(node.src)
                    .then(response => response.text())
                    .then(scriptContent => {
                    let modifiedContent = scriptContent
                    .replace(
                        'r.created||c?Rt("input",{type:"text",name:"chat",className:"mousetrap",autoComplete:"off",autoCorrect:"off",autoCapitalize:"off",value:i,placeholder:this._lang.chatHere,maxLength:100,enterKeyHint:"send",onChange:this.handleText,ref:this._ref}):Rt("input",{type:"text",name:"chat",className:"mousetrap",autoComplete:"off",autoCorrect:"off",autoCapitalize:"off",value:this._lang.loginChat,maxLength:100,ref:this._ref,disabled:!0})',
                        'Rt("input",{type:"text",name:"chat",className:"mousetrap",autoComplete:"off",autoCorrect:"off",autoCapitalize:"off",value:i,placeholder:this._lang.chatHere,maxLength:100,enterKeyHint:"send",onChange:this.handleText,ref:this._ref})'
                    )
                    .replace(
                        'this._timerAtivo=setInterval((function(){Date.now()-e._ativo>15e4&&(O(Object(f.a)(n.prototype),"emit",e).call(e,"avisoInativo"),e._ativo=Date.now())}),1e3)',
                        'this._timerAtivo=setInterval((function(){Date.now()-e._ativo>15e4&&e.active()}),1e3)'
                    )
                    .replace(
                        'e.unlock()}',
                        'e.unlock();window.game=e;setInterval(()=>{window.game=e},1000);e.on("votekick",(t,i,o)=>{if(i.id===e.me.id){e.votekick(t.id,true);}});}'
                    );
                    let blob = new Blob([modifiedContent], { type: 'application/javascript' });
                    let blobUrl = URL.createObjectURL(blob);
                    node.src = blobUrl;
                    node.textContent = '';
                    return target.apply(thisArg, [node]);
                })
                    .catch(error => console.error('Failed to fetch/modify script:', error));
                return node;
            }
            return target.apply(thisArg, argumentsList);
        }
    });

    // Load fonts
    const fontLink = document.createElement('link');
    fontLink.rel = 'stylesheet';
    fontLink.href = 'https://fonts.googleapis.com/css2?family=M+PLUS+Rounded+1c:wght@400;700&display=swap';
    document.head.appendChild(fontLink);

    // Inject HTML
    const kawaiiHTML = `
        <div class="kawaii-cheat" id="kawaiiCheat">
            <div class="kawaii-header" id="kawaiiHeader">
                <img src="https://i.imgur.com/efEvdp5.png" alt="Anime Girl" class="header-icon">
                <h2 data-translate="✧ Kawaii Helper ✧">✧ Kawaii Helper ✧</h2>
                <button class="minimize-btn" id="minimizeBtn">▼</button>
            </div>
            <div class="kawaii-body" id="kawaiiBody">
                <div class="kawaii-tabs">
                    <button class="kawaii-tab active" data-tab="guessing" data-translate="Guessing">Guessing</button>
                    <button class="kawaii-tab" data-tab="drawing" data-translate="Drawing">Drawing</button>
                </div>
                <div class="kawaii-content" id="guessing-tab">
                    <div class="checkbox-container">
                        <input type="checkbox" id="autoGuess">
                        <label for="autoGuess" data-translate="Auto Guess">Auto Guess</label>
                    </div>
                    <div class="slider-container" id="speedContainer" style="display: none;">
                        <div class="slider-label" data-translate="Speed">Speed</div>
                        <div class="custom-slider">
                            <input type="range" id="guessSpeed" min="100" max="5000" value="1000" step="100">
                            <div class="slider-track"></div>
                            <span id="speedValue">1s</span>
                        </div>
                    </div>
                    <div class="checkbox-container">
                        <input type="checkbox" id="customWords">
                        <label for="customWords" data-translate="Custom Words">Custom Words</label>
                    </div>
                    <div class="dropzone-container" id="wordListContainer" style="display: none;">
                        <div class="dropzone" id="wordListDropzone">
                            <input type="file" id="wordList" accept=".txt">
                            <div class="dropzone-content">
                                <div class="dropzone-icon">❀</div>
                                <p data-translate="Drop word list here or click to upload">Drop word list here or click to upload</p>
                            </div>
                        </div>
                    </div>
                    <div class="input-container">
                        <input type="text" id="guessPattern" data-translate-placeholder="Enter pattern (e.g., ___e___)" placeholder="Enter pattern (e.g., ___e___)">
                    </div>
                    <div class="hit-list" id="hitList">
                        <div class="message" data-translate="Type a pattern to see matches ✧">Type a pattern to see matches ✧</div>
                    </div>
                </div>
                <div class="kawaii-content" id="drawing-tab" style="display: none;">
                    <div class="dropzone-container">
                        <div class="dropzone" id="imageDropzone">
                            <input type="file" id="imageUpload" accept="image/*">
                            <div class="dropzone-content">
                                <div class="dropzone-icon">✎</div>
                                <p data-translate="Drop image here or click to upload">Drop image here or click to upload</p>
                            </div>
                        </div>
                        <div class="image-preview" id="imagePreview" style="display: none;">
                            <img id="previewImg">
                            <div class="preview-controls">
                                <button class="cancel-btn" id="cancelImage">✕</button>
                            </div>
                        </div>
                    </div>
                    <div class="slider-container">
                        <div class="slider-label" data-translate="Draw Speed">Draw Speed</div>
                        <div class="custom-slider">
                            <input type="range" id="drawSpeed" min="20" max="5000" value="200" step="100">
                            <div class="slider-track"></div>
                            <span id="drawSpeedValue">200ms</span>
                        </div>
                    </div>
                    <div class="slider-container">
                        <div class="slider-label" data-translate="Max Colors">Max Colors</div>
                        <div class="custom-slider">
                            <input type="range" id="maxColors" min="3" max="1000" value="100" step="1">
                            <div class="slider-track"></div>
                            <span id="maxColorsValue">100</span>
                        </div>
                    </div>
                    <button class="draw-btn" id="sendDraw" disabled data-translate="Draw Now ✧">Draw Now ✧</button>
                </div>
                <div class="kawaii-footer">
                    <span class="credit-text" data-translate="Made with ♥ by Anonimbiri & Gartic-Developers">Made with ♥ by Anonimbiri & Gartic-Developers</span>
                </div>
            </div>
        </div>
        <div class="kawaii-notifications" id="kawaiiNotifications"></div>
    `;

    const waitForBody = setInterval(() => {
        if (document.body) {
            clearInterval(waitForBody);
            document.body.insertAdjacentHTML('beforeend', kawaiiHTML);
            addStylesAndBehavior();
        }
    }, 100);

    function addStylesAndBehavior() {
        const style = document.createElement('style');
        style.textContent = `
            :root {
                --primary-color: #FF69B4;
                --primary-dark: #FF1493;
                --primary-light: #FFC0CB;
                --bg-color: #FFB6C1;
                --text-color: #5d004f;
                --panel-bg: rgba(255, 182, 193, 0.95);
                --panel-border: #FF69B4;
                --element-bg: rgba(255, 240, 245, 0.7);
                --element-hover: rgba(255, 240, 245, 0.9);
                --element-active: #FF69B4;
                --element-active-text: #FFF0F5;
            }

            .kawaii-cheat {
                position: fixed;
                top: 20px;
                right: 20px;
                width: 280px;
                background: var(--panel-bg);
                border-radius: 15px;
                box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2);
                padding: 10px;
                display: flex;
                flex-direction: column;
                gap: 10px;
                color: var(--text-color);
                user-select: none;
                z-index: 1000;
                font-family: 'M PLUS Rounded 1c', sans-serif;
                border: 2px solid var(--panel-border);
                transition: all 0.4s ease-in-out;
                max-height: calc(100vh - 40px);
                overflow: hidden;
            }

            .kawaii-cheat.minimized {
                height: 50px;
                opacity: 0.9;
                transform: scale(0.95);
                overflow: hidden;
            }

            .kawaii-cheat:not(.minimized) {
                opacity: 1;
                transform: scale(1);
            }

            .kawaii-cheat.minimized .kawaii-body {
                opacity: 0;
                max-height: 0;
                overflow: hidden;
                transition: opacity 0.2s ease-in-out, max-height 0.4s ease-in-out;
            }

            .kawaii-cheat:not(.minimized) .kawaii-body {
                opacity: 1;
                max-height: 500px;
                transition: opacity 0.2s ease-in-out 0.2s, max-height 0.4s ease-in-out;
            }

            .kawaii-cheat.dragging {
                opacity: 0.8;
                transition: none;
            }

            .kawaii-header {
                display: flex;
                justify-content: space-between;
                align-items: center;
                padding: 5px 10px;
                cursor: move;
                background: var(--element-bg);
                border-radius: 10px;
                border: 2px solid var(--primary-color);
            }

            .header-icon {
                width: 30px;
                height: 30px;
                border-radius: 50%;
                margin-right: 10px;
                border: 1px dashed var(--primary-color);
            }

            .kawaii-header h2 {
                margin: 0;
                font-size: 18px;
                font-weight: 700;
                color: var(--primary-dark);
                text-shadow: 1px 1px 2px var(--primary-light);
            }

            .minimize-btn {
                background: transparent;
                border: 1px dashed var(--primary-dark);
                border-radius: 6px;
                width: 24px;
                height: 24px;
                color: var(--primary-dark);
                font-size: 16px;
                line-height: 20px;
                text-align: center;
                cursor: pointer;
                transition: all 0.3s ease;
            }

            .minimize-btn:hover {
                background: var(--primary-color);
                color: var(--element-active-text);
                border-color: var(--primary-color);
                transform: rotate(180deg);
            }

            .kawaii-tabs {
                display: flex;
                gap: 8px;
                padding: 5px 0;
            }

            .kawaii-tab {
                flex: 1;
                background: var(--element-bg);
                border: 1px dashed var(--primary-color);
                padding: 6px;
                border-radius: 10px;
                font-size: 12px;
                font-weight: 700;
                color: var(--text-color);
                cursor: pointer;
                transition: background 0.3s ease, transform 0.3s ease;
                text-align: center;
            }

            .kawaii-tab.active {
                background: var(--primary-color);
                color: var(--element-active-text);
                border-color: var(--primary-dark);
            }

            .kawaii-tab:hover:not(.active) {
                background: var(--element-hover);
                transform: scale(1.05);
            }

            .kawaii-content {
                display: flex;
                flex-direction: column;
                gap: 10px;
                min-height: 0;
                flex-grow: 1;
                overflow: hidden;
                padding: 5px;
            }

            .checkbox-container {
                display: flex;
                align-items: center;
                gap: 8px;
                background: var(--element-bg);
                padding: 8px;
                border-radius: 10px;
                border: 1px dashed var(--primary-color);
                cursor: pointer;
                transition: background 0.3s ease;
            }

            .checkbox-container:hover {
                background: var(--element-hover);
            }

            .checkbox-container input[type="checkbox"] {
                appearance: none;
                width: 18px;
                height: 18px;
                background: var(--element-active-text);
                border: 1px dashed var(--primary-color);
                border-radius: 50%;
                cursor: pointer;
                position: relative;
            }

            .checkbox-container input[type="checkbox"]:checked {
                background: var(--primary-color);
                border-color: var(--primary-dark);
            }

            .checkbox-container input[type="checkbox"]:checked::after {
                content: "♥";
                position: absolute;
                top: 50%;
                left: 50%;
                transform: translate(-50%, -50%);
                color: var(--element-active-text);
                font-size: 12px;
            }

            .checkbox-container label {
                font-size: 12px;
                font-weight: 700;
                color: var(--text-color);
                cursor: pointer;
            }

            .input-container {
                background: var(--element-bg);
                padding: 8px;
                border-radius: 10px;
                border: 1px dashed var(--primary-color);
            }

            .input-container input[type="text"] {
                width: 100%;
                background: var(--element-active-text);
                border: 1px dashed var(--primary-light);
                border-radius: 8px;
                padding: 6px 10px;
                color: var(--text-color);
                font-size: 12px;
                font-weight: 500;
                box-sizing: border-box;
                transition: border-color 0.3s ease;
                outline: none;
            }

            .input-container input[type="text"]:focus {
                border-color: var(--primary-dark);
            }

            .dropzone-container {
                display: flex;
                flex-direction: column;
                gap: 10px;
            }

            .dropzone {
                position: relative;
                background: var(--element-bg);
                border: 1px dashed var(--primary-color);
                border-radius: 10px;
                padding: 15px;
                display: flex;
                flex-direction: column;
                align-items: center;
                justify-content: center;
                cursor: pointer;
                transition: background 0.3s ease, border-color 0.3s ease;
                min-height: 80px;
            }

            .dropzone:hover, .dropzone.drag-over {
                background: var(--element-hover);
                border-color: var(--primary-dark);
            }

            .dropzone input[type="file"] {
                position: absolute;
                top: 0;
                left: 0;
                width: 100%;
                height: 100%;
                opacity: 0;
                cursor: pointer;
            }

            .dropzone-content {
                display: flex;
                flex-direction: column;
                align-items: center;
                gap: 8px;
                text-align: center;
                pointer-events: none;
            }

            .dropzone-icon {
                font-size: 24px;
                color: var(--primary-color);
                animation: pulse 1.5s infinite ease-in-out;
            }

            @keyframes pulse {
                0%, 100% { transform: scale(1); }
                50% { transform: scale(1.1); }
            }

            .dropzone-content p {
                margin: 0;
                color: var(--text-color);
                font-size: 12px;
                font-weight: 500;
            }

            .slider-container {
                display: flex;
                flex-direction: column;
                gap: 6px;
                background: var(--element-bg);
                padding: 8px;
                border-radius: 10px;
                border: 1px dashed var(--primary-color);
            }

            .slider-label {
                font-size: 12px;
                color: var(--text-color);
                font-weight: 700;
                text-align: center;
            }

            .custom-slider {
                position: relative;
                height: 25px;
                padding: 0 8px;
            }

            .custom-slider input[type="range"] {
                -webkit-appearance: none;
                width: 100%;
                height: 6px;
                background: transparent;
                position: absolute;
                top: 50%;
                left: 0;
                transform: translateY(-50%);
                z-index: 2;
            }

            .custom-slider .slider-track {
                position: absolute;
                top: 50%;
                left: 0;
                width: 100%;
                height: 6px;
                background: linear-gradient(to right, var(--primary-dark) 0%, var(--primary-dark) var(--slider-progress), var(--primary-light) var(--slider-progress), var(--primary-light) 100%);
                border-radius: 3px;
                transform: translateY(-50%);
                z-index: 1;
            }

            .custom-slider input[type="range"]::-webkit-slider-thumb {
                -webkit-appearance: none;
                width: 16px;
                height: 16px;
                background: var(--primary-color);
                border-radius: 50%;
                border: 1px dashed var(--element-active-text);
                cursor: pointer;
                transition: transform 0.3s ease;
            }

            .custom-slider input[type="range"]::-webkit-slider-thumb:hover {
                transform: scale(1.2);
            }

            .custom-slider span {
                position: absolute;
                bottom: -15px;
                left: 50%;
                transform: translateX(-50%);
                font-size: 10px;
                color: var(--text-color);
                background: var(--element-active-text);
                padding: 2px 6px;
                border-radius: 8px;
                border: 1px dashed var(--primary-color);
                white-space: nowrap;
            }

            .hit-list {
                max-height: 180px;
                overflow-y: scroll;
                background: var(--element-bg);
                border: 1px dashed var(--primary-color);
                border-radius: 10px;
                padding: 8px;
                display: flex;
                flex-direction: column;
                gap: 6px;
                scrollbar-width: thin;
                scrollbar-color: var(--primary-color) var(--element-bg);
            }

            .hit-list::-webkit-scrollbar {
                width: 6px;
            }

            .hit-list::-webkit-scrollbar-thumb {
                background-color: var(--primary-color);
                border-radius: 10px;
            }

            .hit-list::-webkit-scrollbar-track {
                background: var(--element-bg);
            }

            .hit-list button {
                background: rgba(255, 240, 245, 0.8);
                border: 1px dashed var(--primary-color);
                padding: 6px 10px;
                border-radius: 8px;
                color: var(--text-color);
                font-size: 12px;
                font-weight: 700;
                cursor: pointer;
                transition: background 0.3s ease, transform 0.3s ease;
                text-align: left;
            }

            .hit-list button:hover:not(.tried) {
                background: var(--primary-color);
                color: var(--element-active-text);
                transform: scale(1.03);
            }

            .hit-list button.tried {
                background: rgba(255, 182, 193, 0.6);
                border-color: var(--primary-light);
                color: var(--primary-dark);
                opacity: 0.7;
                cursor: not-allowed;
            }

            .hit-list .tried-label {
                font-size: 10px;
                color: var(--primary-dark);
                text-align: center;
                padding: 4px;
                background: var(--element-active-text);
                border-radius: 8px;
                border: 1px dashed var(--primary-color);
            }

            .hit-list .message {
                font-size: 12px;
                color: var(--text-color);
                text-align: center;
                padding: 8px;
            }

            .image-preview {
                position: relative;
                margin-top: 10px;
                background: var(--element-bg);
                padding: 8px;
                border-radius: 10px;
                border: 1px dashed var(--primary-color);
            }

            .image-preview img {
                max-width: 100%;
                max-height: 120px;
                border-radius: 8px;
                display: block;
                margin: 0 auto;
            }

            .preview-controls {
                position: absolute;
                top: 12px;
                right: 12px;
                display: flex;
                gap: 6px;
            }

            .cancel-btn {
                background: transparent;
                border: 1px dashed var(--primary-dark);
                border-radius: 6px;
                width: 24px;
                height: 24px;
                color: var(--primary-dark);
                font-size: 16px;
                line-height: 20px;
                text-align: center;
                cursor: pointer;
                transition: all 0.3s ease;
            }

            .cancel-btn:hover {
                background: var(--primary-dark);
                color: var(--element-active-text);
                transform: scale(1.1);
            }

            .draw-btn {
                background: var(--primary-color);
                border: 1px dashed var(--primary-dark);
                padding: 8px;
                border-radius: 10px;
                color: var(--element-active-text);
                font-size: 14px;
                font-weight: 700;
                cursor: pointer;
                transition: background 0.3s ease, transform 0.3s ease;
                text-align: center;
                width: 100%;
                box-sizing: border-box;
            }

            .draw-btn:hover:not(:disabled) {
                background: var(--primary-dark);
                transform: scale(1.05);
            }

            .draw-btn:disabled {
                background: rgba(255, 105, 180, 0.5);
                cursor: not-allowed;
            }

            .kawaii-footer {
                display: flex;
                justify-content: center;
                align-items: center;
                margin-top: 10px;
                padding: 6px;
                background: var(--element-bg);
                border-radius: 10px;
                border: 2px solid var(--primary-color);
            }

            .credit-text {
                font-size: 10px;
                color: var(--text-color);
                font-weight: 700;
            }

            .kawaii-notifications {
                position: fixed;
                top: 20px;
                right: 20px;
                display: flex;
                flex-direction: column;
                gap: 10px;
                z-index: 2000;
                pointer-events: none;
            }

            .kawaii-notification {
                background: var(--panel-bg);
                border: 2px solid var(--panel-border);
                border-radius: 12px;
                padding: 12px 18px;
                color: var(--text-color);
                font-family: 'M PLUS Rounded 1c', sans-serif;
                font-size: 14px;
                font-weight: 700;
                box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
                display: flex;
                align-items: center;
                gap: 10px;
                max-width: 300px;
                opacity: 0;
                transform: translateX(100%);
                transition: opacity 0.3s ease, transform 0.3s ease;
                pointer-events: auto;
            }

            .kawaii-notification.show {
                opacity: 1;
                transform: translateX(0);
            }

            .kawaii-notification-icon {
                font-size: 20px;
                color: var(--primary-dark);
                animation: bounce 1s infinite ease-in-out;
            }

            @keyframes bounce {
                0%, 100% { transform: translateY(0); }
                50% { transform: translateY(-5px); }
            }

            .kawaii-notification-close {
                background: transparent;
                border: 1px dashed var(--primary-dark);
                border-radius: 6px;
                width: 20px;
                height: 20px;
                color: var(--primary-dark);
                font-size: 12px;
                line-height: 18px;
                text-align: center;
                cursor: pointer;
                transition: all 0.3s ease;
            }

            .kawaii-notification-close:hover {
                background: var(--primary-dark);
                color: var(--element-active-text);
                transform: scale(1.1);
            }
        `;
        document.head.appendChild(style);

        // DOM Elements
        const kawaiiCheat = document.getElementById('kawaiiCheat');
        const kawaiiHeader = document.getElementById('kawaiiHeader');
        const minimizeBtn = document.getElementById('minimizeBtn');
        const tabButtons = document.querySelectorAll('.kawaii-tab');
        const tabContents = document.querySelectorAll('.kawaii-content');
        const autoGuessCheckbox = document.getElementById('autoGuess');
        const speedContainer = document.getElementById('speedContainer');
        const guessSpeed = document.getElementById('guessSpeed');
        const speedValue = document.getElementById('speedValue');
        const customWordsCheckbox = document.getElementById('customWords');
        const wordListContainer = document.getElementById('wordListContainer');
        const wordListDropzone = document.getElementById('wordListDropzone');
        const wordListInput = document.getElementById('wordList');
        const guessPattern = document.getElementById('guessPattern');
        const hitList = document.getElementById('hitList');
        const imageDropzone = document.getElementById('imageDropzone');
        const imageUpload = document.getElementById('imageUpload');
        const imagePreview = document.getElementById('imagePreview');
        const previewImg = document.getElementById('previewImg');
        const cancelImage = document.getElementById('cancelImage');
        const drawSpeed = document.getElementById('drawSpeed');
        const drawSpeedValue = document.getElementById('drawSpeedValue');
        const maxColors = document.getElementById('maxColors');
        const maxColorsValue = document.getElementById('maxColorsValue');
        const sendDraw = document.getElementById('sendDraw');

        // Variables
        let isDragging = false;
        let initialX, initialY;
        let xOffset = 0, yOffset = 0;
        let rafId = null;
        let autoGuessInterval = null;
        let wordList = { "Custom": [] };
        let triedLabelAdded = false;

        const wordListURLs = {
            "General (en)": "https://cdn.jsdelivr.net/gh/Gartic-Developers/Gartic-WordList@master/languages/English/general.json",
            "General (tr)": "https://cdn.jsdelivr.net/gh/Gartic-Developers/Gartic-WordList@master/languages/Turkish/general.json"
        };

        // Dil güncelleme fonksiyonu
        function updateLanguage() {
            document.querySelectorAll('[data-translate]').forEach(element => {
                const key = element.getAttribute('data-translate');
                element.textContent = localize(key);
            });
            document.querySelectorAll('[data-translate-placeholder]').forEach(element => {
                const key = element.getAttribute('data-translate-placeholder');
                element.setAttribute('placeholder', localize(key));
            });
        }

        // İlk yüklemede dil uygulansın
        updateLanguage();

        // Utility Functions
        function updateSliderTrack(slider) {
            const min = parseInt(slider.min);
            const max = parseInt(slider.max);
            const value = parseInt(slider.value);
            const progress = ((value - min) / (max - min)) * 100;
            slider.parentElement.querySelector('.slider-track').style.setProperty('--slider-progress', `${progress}%`);
        }

        function preventDefaults(e) {
            e.preventDefault();
            e.stopPropagation();
        }

        // Initial Setup
        updateSliderTrack(guessSpeed);
        updateSliderTrack(drawSpeed);
        updateSliderTrack(maxColors);

        // Dragging Functionality with Optimization
        kawaiiHeader.addEventListener('mousedown', (e) => {
            if (e.target !== minimizeBtn) {
                initialX = e.clientX - xOffset;
                initialY = e.clientY - yOffset;
                isDragging = true;
                kawaiiCheat.classList.add('dragging');
                if (rafId) cancelAnimationFrame(rafId);
            }
        });

        document.addEventListener('mousemove', (e) => {
            if (isDragging) {
                e.preventDefault();
                const newX = e.clientX - initialX;
                const newY = e.clientY - initialY;

                if (rafId) cancelAnimationFrame(rafId);
                rafId = requestAnimationFrame(() => {
                    kawaiiCheat.style.transform = `translate(${newX}px, ${newY}px)`;
                    xOffset = newX;
                    yOffset = newY;
                });
            }
        });

        document.addEventListener('mouseup', () => {
            if (isDragging) {
                isDragging = false;
                kawaiiCheat.classList.remove('dragging');
                if (rafId) cancelAnimationFrame(rafId);
            }
        });

        // Minimize Button
        minimizeBtn.addEventListener('click', () => {
            kawaiiCheat.classList.toggle('minimized');
            minimizeBtn.textContent = kawaiiCheat.classList.contains('minimized') ? '▲' : '▼';
        });

        // Tab Switching
        tabButtons.forEach(btn => {
            btn.addEventListener('click', () => {
                tabButtons.forEach(b => b.classList.remove('active'));
                tabContents.forEach(c => c.style.display = 'none');
                btn.classList.add('active');
                document.getElementById(`${btn.dataset.tab}-tab`).style.display = 'flex';
            });
        });

        // Checkbox Container Click
        document.querySelectorAll('.checkbox-container').forEach(container => {
            const checkbox = container.querySelector('input[type="checkbox"]');
            const label = container.querySelector('label');

            container.addEventListener('click', (e) => {
                if (e.target !== checkbox && e.target !== label) {
                    checkbox.checked = !checkbox.checked;
                    checkbox.dispatchEvent(new Event('change'));
                }
            });

            label.addEventListener('click', (e) => {
                e.stopPropagation();
                checkbox.checked = !checkbox.checked;
                checkbox.dispatchEvent(new Event('change'));
            });
        });

        // Auto Guess Checkbox
        autoGuessCheckbox.addEventListener('change', (e) => {
            speedContainer.style.display = e.target.checked ? 'flex' : 'none';
            if (!e.target.checked) stopAutoGuess();
            else if (guessPattern.value) startAutoGuess();
        });

        // Guess Speed Slider
        guessSpeed.addEventListener('input', (e) => {
            updateSliderTrack(e.target);
            speedValue.textContent = e.target.value >= 1000 ? `${e.target.value / 1000}s` : `${e.target.value}ms`;
            if (autoGuessCheckbox.checked && autoGuessInterval) {
                stopAutoGuess();
                startAutoGuess();
            }
        });

        // Custom Words Checkbox
        customWordsCheckbox.addEventListener('change', (e) => {
            wordListContainer.style.display = e.target.checked ? 'block' : 'none';
            updateHitList(guessPattern.value.trim());
        });

        // Word List Dropzone
        ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
            wordListDropzone.addEventListener(eventName, preventDefaults, false);
        });

        wordListDropzone.addEventListener('dragenter', () => wordListDropzone.classList.add('drag-over'));
        wordListDropzone.addEventListener('dragover', () => wordListDropzone.classList.add('drag-over'));
        wordListDropzone.addEventListener('dragleave', () => wordListDropzone.classList.remove('drag-over'));
        wordListDropzone.addEventListener('drop', (e) => {
            wordListDropzone.classList.remove('drag-over');
            const file = e.dataTransfer.files[0];
            if (file && file.type === 'text/plain') handleWordListFile(file);
        });

        wordListInput.addEventListener('change', (e) => {
            const file = e.target.files[0];
            if (file) {
                handleWordListFile(file);
                e.target.value = '';
            }
        });

        function handleWordListFile(file) {
            const reader = new FileReader();
            reader.onload = function(event) {
                wordList["Custom"] = event.target.result.split('\n').map(word => word.trim()).filter(word => word.length > 0);
                showNotification(localize("Loaded ${wordList['Custom'].length} words from ${file.name}", {
                    "wordList['Custom'].length": wordList["Custom"].length,
                    "file.name": file.name
                }), 4000);
                updateHitList(guessPattern.value.trim());
            };
            reader.readAsText(file);
        }

        // Guess Pattern Input
        guessPattern.addEventListener('input', (e) => updateHitList(e.target.value.trim()));

        // Hit List Functionality
        hitList.addEventListener('click', (e) => {
            if (e.target.tagName === 'BUTTON' && !e.target.classList.contains('tried')) {
                const button = e.target;
                button.classList.add('tried');
                if (!triedLabelAdded && hitList.querySelectorAll('button.tried').length === 1) {
                    const triedLabel = document.createElement('div');
                    triedLabel.classList.add('tried-label');
                    triedLabel.textContent = localize("Tried Words");
                    hitList.appendChild(triedLabel);
                    triedLabelAdded = true;
                }
                if (window.game && window.game._socket) {
                    window.game._socket.emit(13, window.game._codigo, button.textContent);
                }
                hitList.appendChild(button);
            }
        });

        function startAutoGuess() {
            if (!autoGuessCheckbox.checked) return;
            stopAutoGuess();
            const speed = parseInt(guessSpeed.value);
            autoGuessInterval = setInterval(() => {
                const buttons = hitList.querySelectorAll('button:not(.tried)');
                if (buttons.length > 0 && window.game && window.game._socket) {
                    const word = buttons[0].textContent;
                    buttons[0].classList.add('tried');
                    window.game._socket.emit(13, window.game._codigo, word);
                    if (!triedLabelAdded && hitList.querySelectorAll('button.tried').length === 1) {
                        const triedLabel = document.createElement('div');
                        triedLabel.classList.add('tried-label');
                        triedLabel.textContent = localize("Tried Words");
                        hitList.appendChild(triedLabel);
                        triedLabelAdded = true;
                    }
                    hitList.appendChild(buttons[0]);
                }
            }, speed);
        }

        function stopAutoGuess() {
            if (autoGuessInterval) {
                clearInterval(autoGuessInterval);
                autoGuessInterval = null;
            }
        }

        function updateHitList(pattern) {
            hitList.innerHTML = '';
            triedLabelAdded = false;
            const activeTheme = customWordsCheckbox.checked || !window.game || !window.game._dadosSala || !window.game._dadosSala.tema
            ? "Custom" : window.game._dadosSala.tema;
            const activeList = wordList[activeTheme] || [];

            if (!pattern) {
                if (activeList.length === 0) {
                    hitList.innerHTML = `<div class="message">${localize(customWordsCheckbox.checked ? "Upload a custom word list ✧" : "No words available ✧")}</div>`;
                } else {
                    activeList.forEach(word => {
                        const button = document.createElement('button');
                        button.textContent = word;
                        hitList.appendChild(button);
                    });
                }
                return;
            }

            const regex = new RegExp(`^${pattern.split('').map(char => char === '_' ? '.' : char).join('')}$`, 'i');
            const matches = activeList.filter(word => regex.test(word));

            if (matches.length === 0) {
                hitList.innerHTML = `<div class="message">${localize("No matches found ✧")}</div>`;
            } else {
                matches.forEach(word => {
                    const button = document.createElement('button');
                    button.textContent = word;
                    hitList.appendChild(button);
                });
            }
        }

        async function fetchWordList(theme) {
            if (!wordList[theme] && wordListURLs[theme]) {
                try {
                    const response = await fetch(wordListURLs[theme]);
                    if (!response.ok) throw new Error(`Failed to fetch ${theme} word list`);
                    const data = await response.json();
                    wordList[theme] = data.words || data;
                    console.log(`Loaded ${wordList[theme].length} words for ${theme}`);
                } catch (error) {
                    console.error(`Error fetching word list for ${theme}:`, error);
                    wordList[theme] = [];
                }
            }
        }

        // Image Upload
        ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
            imageDropzone.addEventListener(eventName, preventDefaults, false);
        });

        imageDropzone.addEventListener('dragenter', () => imageDropzone.classList.add('drag-over'));
        imageDropzone.addEventListener('dragover', () => imageDropzone.classList.add('drag-over'));
        imageDropzone.addEventListener('dragleave', () => imageDropzone.classList.remove('drag-over'));
        imageDropzone.addEventListener('drop', (e) => {
            imageDropzone.classList.remove('drag-over');
            const file = e.dataTransfer.files[0];
            if (file && file.type.startsWith('image/')) handleImageFile(file);
        });

        imageUpload.addEventListener('change', (e) => {
            const file = e.target.files[0];
            if (file) {
                handleImageFile(file);
                e.target.value = '';
            }
        });

        function handleImageFile(file) {
            const reader = new FileReader();
            reader.onload = function(event) {
                previewImg.src = event.target.result;
                imageDropzone.style.display = 'none';
                imagePreview.style.display = 'block';
                sendDraw.disabled = false;
            };
            reader.readAsDataURL(file);
        }

        cancelImage.addEventListener('click', () => {
            previewImg.src = '';
            imageDropzone.style.display = 'flex';
            imagePreview.style.display = 'none';
            sendDraw.disabled = true;
            imageUpload.value = '';
        });

        drawSpeed.addEventListener('input', (e) => {
            updateSliderTrack(e.target);
            drawSpeedValue.textContent = e.target.value >= 1000 ? `${e.target.value / 1000}s` : `${e.target.value}ms`;
        });

        maxColors.addEventListener('input', (e) => {
            updateSliderTrack(e.target);
            maxColorsValue.textContent = e.target.value;
        });

        sendDraw.addEventListener('click', () => {
            if (previewImg.src) {
                if (!window.game || !window.game.turn) {
                    showNotification(localize("Not your turn or game not loaded! ✧"), 3000);
                    return;
                }
                sendDraw.disabled = true;
                processAndDrawImage(previewImg.src);
            }
        });

        // Socket Integration
        const checkGame = setInterval(() => {
            if (window.game && window.game._socket) {
                clearInterval(checkGame);
                const currentTheme = window.game._dadosSala.tema || "Custom";
                if (currentTheme !== "Custom") {
                    fetchWordList(currentTheme).then(() => updateHitList(guessPattern.value.trim()));
                }

                window.game._socket.on(30, (hint) => {
                    hint = String(hint).replace(/,/g, '');
                    guessPattern.value = hint;
                    updateHitList(hint);
                    if (autoGuessCheckbox.checked) startAutoGuess();
                });

                window.game._socket.on(19, () => {
                    guessPattern.value = '';
                    stopAutoGuess();
                    updateHitList('');
                });

                window.game._socket.on(15, (playerId) => {
                    if (playerId === window.game.me.id) {
                        guessPattern.value = '';
                        stopAutoGuess();
                        updateHitList('');
                    }
                });

                let lastTheme = currentTheme;
                setInterval(() => {
                    const newTheme = window.game._dadosSala.tema || "Custom";
                    if (newTheme !== lastTheme && newTheme !== "Custom") {
                        lastTheme = newTheme;
                        fetchWordList(newTheme).then(() => updateHitList(guessPattern.value.trim()));
                    }
                }, 1000);
            }
        }, 100);

        // Bildirim Gösterme Fonksiyonu
        function showNotification(message, duration = 3000) {
            const notificationsContainer = document.getElementById('kawaiiNotifications');
            const notification = document.createElement('div');
            notification.className = 'kawaii-notification';

            notification.innerHTML = `
                <span class="kawaii-notification-icon">✧</span>
                <span class="kawaii-notification-text">${message}</span>
                <button class="kawaii-notification-close">✕</button>
            `;

            notificationsContainer.appendChild(notification);

            setTimeout(() => notification.classList.add('show'), 10);

            const timeout = setTimeout(() => {
                notification.classList.remove('show');
                setTimeout(() => notification.remove(), 300);
            }, duration);

            notification.querySelector('.kawaii-notification-close').addEventListener('click', () => {
                clearTimeout(timeout);
                notification.classList.remove('show');
                setTimeout(() => notification.remove(), 300);
            });
        }
    }

    function processAndDrawImage(imageSrc) {
        if (!window.game || !window.game._socket || !window.game._desenho || !window.game.turn) {
            showNotification(localize("Game not ready or not your turn! ✧"), 3000);
            return;
        }

        const img = new Image();
        img.crossOrigin = "Anonymous";
        img.onload = async function() {
            const gameCanvas = window.game._desenho._canvas.canvas;
            if (!gameCanvas || !gameCanvas.width || !gameCanvas.height) {
                showNotification(localize("Canvas not accessible! ✧"), 3000);
                sendDraw.disabled = false;
                return;
            }

            const ctx = gameCanvas.getContext('2d');
            if (!ctx) {
                showNotification(localize("Canvas context not available! ✧"), 3000);
                sendDraw.disabled = false;
                return;
            }

            const canvasWidth = Math.floor(gameCanvas.width);
            const canvasHeight = Math.floor(gameCanvas.height);

            const tempCanvas = document.createElement('canvas');
            const tempCtx = tempCanvas.getContext('2d');
            if (!tempCtx) {
                showNotification(localize("Temp canvas context failed! ✧"), 3000);
                sendDraw.disabled = false;
                return;
            }

            const scale = Math.min(canvasWidth / img.width, canvasHeight / img.height);
            const newWidth = Math.floor(img.width * scale);
            const newHeight = Math.floor(img.height * scale);

            tempCanvas.width = canvasWidth;
            tempCanvas.height = canvasHeight;

            const offsetX = Math.floor((canvasWidth - newWidth) / 2);
            const offsetY = Math.floor((canvasHeight - newHeight) / 2);

            tempCtx.drawImage(img, offsetX, offsetY, newWidth, newHeight);

            let imageData;
            try {
                imageData = tempCtx.getImageData(0, 0, canvasWidth, canvasHeight);
            } catch (e) {
                showNotification(localize("Image data error: ${e.message} ✧", { "e.message": e.message }), 4000);
                sendDraw.disabled = false;
                return;
            }

            const data = imageData.data;
            const drawSpeedValue = parseInt(drawSpeed.value) || 200;

            const maxColorsValue = parseInt(maxColors.value) || 100;

            const imgLeft = offsetX;
            const imgRight = offsetX + newWidth - 1;
            const imgTop = offsetY;
            const imgBottom = offsetY + newHeight - 1;

            const colorCounts = new Map();
            const sampleStep = Math.max(1, Math.floor(newWidth / 50));

            for (let x = imgLeft; x <= imgRight; x += sampleStep) {
                for (let y of [imgTop, imgTop+1, imgTop+2, imgBottom-2, imgBottom-1, imgBottom]) {
                    if (y >= imgTop && y <= imgBottom) {
                        const index = (y * canvasWidth + x) * 4;
                        const r = data[index];
                        const g = data[index+1];
                        const b = data[index+2];
                        const key = `${r},${g},${b}`;
                        colorCounts.set(key, (colorCounts.get(key) || 0) + 3);
                    }
                }
            }

            for (let y = imgTop; y <= imgBottom; y += sampleStep) {
                for (let x of [imgLeft, imgLeft+1, imgLeft+2, imgRight-2, imgRight-1, imgRight]) {
                    if (x >= imgLeft && x <= imgRight) {
                        const index = (y * canvasWidth + x) * 4;
                        const r = data[index];
                        const g = data[index+1];
                        const b = data[index+2];
                        const key = `${r},${g},${b}`;
                        colorCounts.set(key, (colorCounts.get(key) || 0) + 3);
                    }
                }
            }

            for (let x = imgLeft + 3; x <= imgRight - 3; x += sampleStep * 2) {
                for (let y = imgTop + 3; y <= imgBottom - 3; y += sampleStep * 2) {
                    const index = (y * canvasWidth + x) * 4;
                    const r = data[index];
                    const g = data[index+1];
                    const b = data[index+2];
                    const key = `${r},${g},${b}`;
                    colorCounts.set(key, (colorCounts.get(key) || 0) + 1);
                }
            }

            let maxCount = 0;
            let backgroundColor = [255, 255, 255];

            for (const [key, count] of colorCounts) {
                if (count > maxCount) {
                    maxCount = count;
                    backgroundColor = key.split(',').map(Number);
                }
            }

            if (backgroundColor[0] > 240 && backgroundColor[1] > 240 && backgroundColor[2] > 240) {
                backgroundColor = [255, 255, 255];
            }

            const bgHex = 'x' + backgroundColor.map(c =>
                                                    c.toString(16).padStart(2, '0').toUpperCase()
                                                   ).join('');

            window.game._socket.emit(10, window.game._codigo, [4]);
            ctx.clearRect(0, 0, canvasWidth, canvasHeight);
            await new Promise(resolve => setTimeout(resolve, drawSpeedValue));

            window.game._socket.emit(10, window.game._codigo, [5, bgHex]);
            ctx.fillStyle = `#${bgHex.slice(1)}`;
            await new Promise(resolve => setTimeout(resolve, drawSpeedValue));

            window.game._socket.emit(10, window.game._codigo, [3, 0, 0, canvasWidth, canvasHeight]);
            ctx.fillRect(0, 0, canvasWidth, canvasHeight);
            await new Promise(resolve => setTimeout(resolve, drawSpeedValue));

            const colorClusters = new Map();
            for (let y = imgTop; y <= imgBottom; y += sampleStep) {
                for (let x = imgLeft; x <= imgRight; x += sampleStep) {
                    const index = (y * canvasWidth + x) * 4;
                    const r = data[index];
                    const g = data[index+1];
                    const b = data[index+2];
                    const key = `${r},${g},${b}`;

                    if (colorDistance([r, g, b], backgroundColor) > 30) {
                        colorClusters.set(key, (colorClusters.get(key) || 0) + 1);
                    }
                }
            }

            const topColors = [...colorClusters.entries()]
            .sort((a, b) => b[1] - a[1])
            .slice(0, maxColorsValue)
            .map(([key]) => ({
                rgb: key.split(',').map(Number),
                hex: 'x' + key.split(',').map(c =>
                                              Number(c).toString(16).padStart(2, '0').toUpperCase()
                                             ).join('')
            }));

            const fillsByColor = {};
            const visited = new Set();
            const stripHeight = 1;
            const stripWidth = 1;
            const minStripSize = 1;

            for (let y = imgTop; y <= imgBottom; y += stripHeight) {
                let startX = null;
                let currentColor = null;
                let stripLength = 0;

                for (let x = imgLeft; x <= imgRight; x += 1) {
                    const index = (y * canvasWidth + x) * 4;
                    const pixelColor = [data[index], data[index+1], data[index+2]];
                    const bgDist = colorDistance(pixelColor, backgroundColor);

                    if (bgDist > 30 && !visited.has(`${x},${y}`)) {
                        const nearestColor = topColors.reduce((prev, curr) =>
                                                              colorDistance(pixelColor, prev.rgb) < colorDistance(pixelColor, curr.rgb) ? prev : curr
                                                             );

                        if (startX === null || currentColor?.hex !== nearestColor.hex) {
                            if (startX !== null && stripLength >= minStripSize) {
                                if (!fillsByColor[currentColor.hex]) fillsByColor[currentColor.hex] = [];
                                fillsByColor[currentColor.hex].push([startX, y, stripLength, stripHeight]);
                                for (let dx = 0; dx < stripLength; dx++) {
                                    visited.add(`${startX + dx},${y}`);
                                }
                            }
                            startX = x;
                            currentColor = nearestColor;
                            stripLength = 1;
                        } else {
                            stripLength++;
                        }
                    } else if (startX !== null && bgDist <= 30) {
                        if (stripLength >= minStripSize) {
                            if (!fillsByColor[currentColor.hex]) fillsByColor[currentColor.hex] = [];
                            fillsByColor[currentColor.hex].push([startX, y, stripLength, stripHeight]);
                            for (let dx = 0; dx < stripLength; dx++) {
                                visited.add(`${startX + dx},${y}`);
                            }
                        }
                        startX = null;
                        currentColor = null;
                        stripLength = 0;
                    }
                }

                if (startX !== null && stripLength >= minStripSize) {
                    if (!fillsByColor[currentColor.hex]) fillsByColor[currentColor.hex] = [];
                    fillsByColor[currentColor.hex].push([startX, y, stripLength, stripHeight]);
                    for (let dx = 0; dx < stripLength; dx++) {
                        visited.add(`${startX + dx},${y}`);
                    }
                }
            }

            for (let x = imgLeft; x <= imgRight; x += stripWidth) {
                let startY = null;
                let currentColor = null;
                let stripLength = 0;

                for (let y = imgTop; y <= imgBottom; y += 1) {
                    const index = (y * canvasWidth + x) * 4;
                    const pixelColor = [data[index], data[index+1], data[index+2]];
                    const bgDist = colorDistance(pixelColor, backgroundColor);

                    if (bgDist > 30 && !visited.has(`${x},${y}`)) {
                        const nearestColor = topColors.reduce((prev, curr) =>
                                                              colorDistance(pixelColor, prev.rgb) < colorDistance(pixelColor, curr.rgb) ? prev : curr
                                                             );

                        if (startY === null || currentColor?.hex !== nearestColor.hex) {
                            if (startY !== null && stripLength >= minStripSize) {
                                if (!fillsByColor[currentColor.hex]) fillsByColor[currentColor.hex] = [];
                                fillsByColor[currentColor.hex].push([x, startY, stripWidth, stripLength]);
                                for (let dy = 0; dy < stripLength; dy++) {
                                    visited.add(`${x},${startY + dy}`);
                                }
                            }
                            startY = y;
                            currentColor = nearestColor;
                            stripLength = 1;
                        } else {
                            stripLength++;
                        }
                    } else if (startY !== null && bgDist <= 30) {
                        if (stripLength >= minStripSize) {
                            if (!fillsByColor[currentColor.hex]) fillsByColor[currentColor.hex] = [];
                            fillsByColor[currentColor.hex].push([x, startY, stripWidth, stripLength]);
                            for (let dy = 0; dy < stripLength; dy++) {
                                visited.add(`${x},${startY + dy}`);
                            }
                        }
                        startY = null;
                        currentColor = null;
                        stripLength = 0;
                    }
                }

                if (startY !== null && stripLength >= minStripSize) {
                    if (!fillsByColor[currentColor.hex]) fillsByColor[currentColor.hex] = [];
                    fillsByColor[currentColor.hex].push([x, startY, stripWidth, stripLength]);
                    for (let dy = 0; dy < stripLength; dy++) {
                        visited.add(`${x},${startY + dy}`);
                    }
                }
            }

            for (let y = imgTop; y <= imgBottom; y += 1) {
                for (let x = imgLeft; x <= imgRight; x += 1) {
                    if (visited.has(`${x},${y}`)) continue;

                    const index = (y * canvasWidth + x) * 4;
                    const pixelColor = [data[index], data[index+1], data[index+2]];
                    if (colorDistance(pixelColor, backgroundColor) <= 30) continue;

                    const nearestColor = topColors.reduce((prev, curr) =>
                                                          colorDistance(pixelColor, prev.rgb) < colorDistance(pixelColor, curr.rgb) ? prev : curr
                                                         );

                    if (!fillsByColor[nearestColor.hex]) fillsByColor[nearestColor.hex] = [];
                    fillsByColor[nearestColor.hex].push([x, y, 1, 1]);
                    visited.add(`${x},${y}`);
                }
            }

            for (const color in fillsByColor) {
                const fillCommand = [3];
                fillsByColor[color].forEach(([x, y, width, height]) => {
                    fillCommand.push(x, y, width, height);
                });

                window.game._socket.emit(10, window.game._codigo, [5, color]);
                ctx.fillStyle = `#${color.slice(1)}`;
                await new Promise(resolve => setTimeout(resolve, drawSpeedValue));

                window.game._socket.emit(10, window.game._codigo, fillCommand);
                fillsByColor[color].forEach(([x, y, width, height]) => {
                    ctx.fillRect(x, y, width, height);
                });
                await new Promise(resolve => setTimeout(resolve, drawSpeedValue));
            }

            showNotification(localize("Drawing completed! ✧"), 3000);
            sendDraw.disabled = false;
        };
        img.onerror = function() {
            showNotification(localize("Failed to load image! ✧"), 3000);
            sendDraw.disabled = false;
        };
        img.src = imageSrc;
    }

    function colorDistance(color1, color2) {
        const rMean = (color1[0] + color2[0]) / 2;
        const r = color1[0] - color2[0];
        const g = color1[1] - color2[1];
        const b = color1[2] - color2[2];

        return Math.sqrt(
            (2 + rMean/256) * r*r +
            4 * g*g +
            (2 + (255-rMean)/256) * b*b
        );
    }
})();