🪄✨ Chess.com VFX Effects

🎨✨ Transforme seu tabuleiro do Chess.com com efeitos visuais, partículas, rastros, animações e efeitos especiais personalizados! 🪄⚡

スクリプトをインストールするには、Tampermonkey, GreasemonkeyViolentmonkey のような拡張機能のインストールが必要です。

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

スクリプトをインストールするには、TampermonkeyViolentmonkey のような拡張機能のインストールが必要です。

スクリプトをインストールするには、TampermonkeyUserscripts のような拡張機能のインストールが必要です。

このスクリプトをインストールするには、Tampermonkeyなどの拡張機能をインストールする必要があります。

このスクリプトをインストールするには、ユーザースクリプト管理ツールの拡張機能をインストールする必要があります。

(ユーザースクリプト管理ツールは設定済みなのでインストール!)

このスタイルをインストールするには、Stylusなどの拡張機能をインストールする必要があります。

このスタイルをインストールするには、Stylus などの拡張機能をインストールする必要があります。

このスタイルをインストールするには、Stylus tなどの拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

(ユーザースタイル管理ツールは設定済みなのでインストール!)

このスクリプトの質問や評価の投稿はこちら通報はこちらへお寄せください
// ==UserScript==
// @name         🪄✨ Chess.com VFX Effects
// @namespace    http://tampermonkey.net/
// @version      5.1
// @description  🎨✨ Transforme seu tabuleiro do Chess.com com efeitos visuais, partículas, rastros, animações e efeitos especiais personalizados! 🪄⚡
// @author       aerus15
// @match        *://*.chess.com/*
// @grant        GM_addStyle
// ==/UserScript==

(function() {
    'use strict';

    GM_addStyle(`
        /* Força a peça arrastada a ficar na camada z-index 100000 para permitir que o canvas fique atrás ou na frente de forma exata */
        .piece.dragging, wc-chess-board .piece.dragging, .piece.dragging-active {
            z-index: 100000 !important;
        }

        #vfx-toggle-btn {
            position: fixed;
            bottom: 40px;
            left: 10px;
            width: 38px;
            height: 38px;
            background: #2b2b2b;
            color: #00e5ff;
            border-radius: 50%;
            display: flex;
            align-items: center;
            justify-content: center;
            cursor: pointer;
            z-index: 2147483647;
            box-shadow: 0 4px 10px rgba(0, 229, 255, 0.3);
            font-size: 20px;
            user-select: none;
            transition: transform 0.2s, box-shadow 0.2s;
            border: 1px solid #00e5ff;
        }
        #vfx-toggle-btn:hover {
            transform: scale(1.1);
            box-shadow: 0 4px 15px rgba(0, 229, 255, 0.6);
        }
        #vfx-panel {
            position: fixed;
            bottom: 90px;
            left: 10px;
            background: rgba(15, 15, 18, 0.95);
            color: #eee;
            border-radius: 12px;
            z-index: 2147483647;
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            font-size: 12px;
            display: none;
            backdrop-filter: blur(12px);
            border: 1px solid rgba(255, 255, 255, 0.1);
            box-shadow: 0 8px 32px rgba(0, 0, 0, 0.8);
            width: 300px;
            overflow: hidden;
        }
        .vfx-header {
            font-weight: bold;
            text-align: center;
            font-size: 15px;
            color: #00e5ff;
            padding: 12px;
            background: rgba(0, 0, 0, 0.3);
            border-bottom: 1px solid rgba(255, 255, 255, 0.05);
            letter-spacing: 1px;
            text-transform: uppercase;
        }
        .vfx-tabs {
            display: flex;
            border-bottom: 1px solid rgba(255, 255, 255, 0.1);
        }
        .vfx-tab-btn {
            flex: 1;
            padding: 10px 0;
            background: transparent;
            color: #aaa;
            border: none;
            cursor: pointer;
            font-weight: bold;
            transition: all 0.2s;
            font-size: 12px;
        }
        .vfx-tab-btn:hover {
            color: #fff;
            background: rgba(255,255,255,0.05);
        }
        .vfx-tab-btn.active {
            color: #00e5ff;
            border-bottom: 2px solid #00e5ff;
            background: rgba(0, 229, 255, 0.05);
        }
        .vfx-tab-content {
            display: none;
            padding: 15px;
            max-height: 500px;
            overflow-y: auto;
        }
        .vfx-tab-content.active {
            display: block;
        }
        .vfx-tab-content::-webkit-scrollbar {
            width: 6px;
        }
        .vfx-tab-content::-webkit-scrollbar-thumb {
            background: #444;
            border-radius: 3px;
        }
        #vfx-panel label {
            display: flex;
            justify-content: space-between;
            margin-top: 12px;
            margin-bottom: 6px;
            font-weight: 600;
            color: #ddd;
        }
        #vfx-panel input[type="range"], #vfx-panel select, #vfx-panel input[type="color"], #vfx-panel input[type="file"] {
            width: 100%;
            background: rgba(0, 0, 0, 0.4);
            color: #fff;
            border: 1px solid rgba(255, 255, 255, 0.15);
            border-radius: 6px;
            padding: 6px;
            box-sizing: border-box;
            outline: none;
            transition: border-color 0.2s;
        }
        #vfx-panel input[type="color"] {
            height: 35px;
            padding: 2px;
            cursor: pointer;
        }
        #vfx-panel select:focus {
            border-color: #00e5ff;
        }
        #vfx-panel input[type="range"] {
            -webkit-appearance: none;
            height: 6px;
            padding: 0;
            border: none;
            background: #444;
            border-radius: 3px;
        }
        #vfx-panel input[type="range"]::-webkit-slider-thumb {
            -webkit-appearance: none;
            width: 14px;
            height: 14px;
            border-radius: 50%;
            background: #00e5ff;
            cursor: pointer;
            box-shadow: 0 0 5px rgba(0,229,255,0.5);
        }
        #vfx-canvas {
            pointer-events: none;
        }
        #vfx-hover-light {
            position: absolute;
            width: 12.5%;
            height: 12.5%;
            top: 0;
            left: 0;
            pointer-events: none;
            z-index: 2;
            transition: transform 0.12s cubic-bezier(0.2, 0.8, 0.2, 1), background-color 0.2s, box-shadow 0.2s, opacity 0.2s;
            opacity: 0;
            will-change: transform, opacity;
            border-radius: 4px;
            box-sizing: border-box;
        }
        .vfx-sub-config {
            background: rgba(255, 255, 255, 0.05);
            padding: 10px;
            border-radius: 8px;
            margin-top: 10px;
            border: 1px solid rgba(255, 255, 255, 0.08);
        }
        .vfx-checkbox-group {
            display: flex;
            flex-wrap: wrap;
            gap: 8px;
            margin-top: 6px;
        }
        .vfx-checkbox-label {
            display: flex !important;
            align-items: center;
            gap: 5px;
            font-size: 11px;
            color: #eee;
            cursor: pointer;
            margin: 0 !important;
        }
        .vfx-btn-action {
            background: #00e5ff;
            color: #000;
            border: none;
            padding: 6px 10px;
            border-radius: 4px;
            font-weight: bold;
            cursor: pointer;
            font-size: 11px;
            transition: background 0.2s;
        }
        .vfx-btn-action:hover {
            background: #00b3cc;
        }
        .vfx-glitch { animation: glitch-anim 2s infinite linear alternate-reverse; filter: contrast(1.2) brightness(1.1); }
        .vfx-glitch-piece { animation: glitch-piece-anim 0.3s infinite !important; }
        .vfx-vibrate { animation: vibrate-anim 0.1s infinite !important; }
        @keyframes glitch-anim {
            0% { clip-path: inset(10% 0 80% 0); transform: translate(-2px, 2px); filter: hue-rotate(90deg); }
            20% { clip-path: inset(80% 0 5% 0); transform: translate(2px, -2px); filter: hue-rotate(-90deg); }
            40% { clip-path: inset(30% 0 30% 0); transform: translate(-2px, 0); filter: hue-rotate(0deg); }
            60% { clip-path: inset(50% 0 30% 0); transform: translate(2px, 2px); filter: hue-rotate(45deg); }
            80% { clip-path: inset(5% 0 80% 0); transform: translate(-1px, -1px); filter: hue-rotate(-45deg); }
            100% { clip-path: inset(40% 0 10% 0); transform: translate(1px, 1px); filter: hue-rotate(0deg); }
        }
        @keyframes glitch-piece-anim {
            0% { transform: translate(0); opacity: 1; }
            20% { transform: translate(-3px, 1px) skewX(20deg); opacity: 0.8; }
            40% { transform: translate(2px, -2px) skewX(-20deg); opacity: 0.9; }
            60% { transform: translate(-1px, 2px) skewX(10deg); opacity: 1; }
            80% { transform: translate(3px, -1px) skewX(-10deg); opacity: 0.8; }
            100% { transform: translate(0); opacity: 1; }
        }
        @keyframes vibrate-anim {
            0% { transform: translate(2px, 1px) rotate(0deg); }
            20% { transform: translate(-3px, 0px) rotate(1deg); }
            40% { transform: translate(1px, -1px) rotate(1deg); }
            60% { transform: translate(-3px, 1px) rotate(0deg); }
            80% { transform: translate(-1px, -1px) rotate(1deg); }
            100% { transform: translate(1px, -2px) rotate(-1deg); }
        }
    `);

    const uiBtn = document.createElement('div');
    uiBtn.id = 'vfx-toggle-btn';
    uiBtn.innerText = '🪄';
    document.body.appendChild(uiBtn);

    const uiPanel = document.createElement('div');
    uiPanel.id = 'vfx-panel';
    uiPanel.innerHTML = `
        <div class="vfx-header">VFX Tabuleiro Pro</div>
        <div class="vfx-tabs">
            <button class="vfx-tab-btn active" data-target="tab-geral">Gerais</button>
            <button class="vfx-tab-btn" data-target="tab-movimento">Movimentos</button>
        </div>

        <div id="tab-geral" class="vfx-tab-content active">
            <label>Efeito Global:</label>
            <select id="vfx-select" class="vfx-save">
                <option value="none">Nenhum</option>
                <option value="space">Espaço (Estrelas)</option>
                <option value="warp">Hyperespaço (Warp)</option>
                <option value="rain">Chuva</option>
                <option value="snow">Neve</option>
                <option value="smoke">Fumaça</option>
                <option value="fire">Fogo</option>
                <option value="wind">Vento</option>
                <option value="lights">Luzes Mágicas</option>
                <option value="fairydust">Pó de Fada</option>
                <option value="fireflies">Vaga-lumes</option>
                <option value="meteors">Meteoros</option>
                <option value="lightning">Raios</option>
                <option value="birds">Corvos / Pássaros</option>
                <option value="lasers">Guerra (Tiros/Lasers)</option>
                <option value="matrix">Matrix</option>
                <option value="glitch">Glitch / Bugado</option>
                <option value="vibrate">Terremoto (Vibração)</option>
            </select>
            <label>Velocidade: <span id="vfx-speed-val" style="color:#00e5ff;">1x</span></label>
            <input type="range" id="vfx-speed" class="vfx-save" min="0.1" max="5" step="0.1" value="1">
            <label>Tamanho: <span id="vfx-size-val" style="color:#00e5ff;">1x</span></label>
            <input type="range" id="vfx-size" class="vfx-save" min="0.5" max="5" step="0.1" value="1">
        </div>

        <div id="tab-movimento" class="vfx-tab-content">
            <label>Partículas ao Arrastar:</label>
            <select id="vfx-drag-effect" class="vfx-save">
                <option value="none">Nenhum</option>
                <option value="water">Ondas de Água</option>
                <option value="sparkles">Faíscas</option>
                <option value="magic">Pó Mágico</option>
                <option value="trail">Rastro (Fumaça/Luz)</option>
                <option value="image">Adicionar Imagens</option>
            </select>

            <div id="vfx-sparkles-cfg" class="vfx-sub-config" style="display: none;">
                <label>Intensidade das Faíscas: <span id="vfx-sparkle-val" style="color:#ffae00;">50%</span></label>
                <input type="range" id="vfx-sparkle-int" class="vfx-save" min="10" max="100" step="5" value="50">
            </div>

            <div id="vfx-trail-cfg" class="vfx-sub-config" style="display: none;">
                <label>Cor do Rastro:</label>
                <input type="color" id="vfx-trail-color" class="vfx-save" value="#ffffff">
                <label>Espessura do Rastro: <span id="vfx-trail-thick-val" style="color:#00e5ff;">15px</span></label>
                <input type="range" id="vfx-trail-thick" class="vfx-save" min="5" max="40" step="1" value="15">
                <label>Velocidade de Sumiço: <span id="vfx-trail-fade-val" style="color:#00e5ff;">Média</span></label>
                <input type="range" id="vfx-trail-fade" class="vfx-save" min="0.01" max="0.1" step="0.01" value="0.04">
            </div>

            <div id="vfx-image-cfg" class="vfx-sub-config" style="display: none;">
                <label>Imagem da Peça:</label>
                <input type="file" id="vfx-img-file" accept="image/*">

                <label>Posição X: <span id="vfx-img-x-val" style="color:#00e5ff;">0px</span></label>
                <input type="range" id="vfx-img-x" class="vfx-save" min="-150" max="150" step="1" value="0">

                <label>Posição Y: <span id="vfx-img-y-val" style="color:#00e5ff;">0px</span></label>
                <input type="range" id="vfx-img-y" class="vfx-save" min="-150" max="150" step="1" value="0">

                <label>Tamanho da Imagem: <span id="vfx-img-scale-val" style="color:#00e5ff;">1x</span></label>
                <input type="range" id="vfx-img-scale" class="vfx-save" min="0.2" max="3" step="0.05" value="1">

                <hr style="border:0; border-top:1px solid rgba(255,255,255,0.1); margin: 10px 0;">

                <label>Tamanho dos Efeitos: <span id="vfx-eff-size-val" style="color:#00e5ff;">1x</span></label>
                <input type="range" id="vfx-eff-size" class="vfx-save" min="0.2" max="3" step="0.1" value="1">

                <label>Intensidade dos Efeitos: <span id="vfx-eff-int-val" style="color:#00e5ff;">100%</span></label>
                <input type="range" id="vfx-eff-int" class="vfx-save" min="10" max="300" step="10" value="100">

                <label>Efeitos na Imagem:</label>
                <div class="vfx-checkbox-group">
                    <label class="vfx-checkbox-label"><input type="checkbox" id="vfx-eff-jetpack" class="vfx-save"> Jetpack</label>
                    <label class="vfx-checkbox-label"><input type="checkbox" id="vfx-eff-fire" class="vfx-save"> Fogo</label>
                    <label class="vfx-checkbox-label"><input type="checkbox" id="vfx-eff-smoke" class="vfx-save"> Fumaça</label>
                    <label class="vfx-checkbox-label"><input type="checkbox" id="vfx-eff-sparkles" class="vfx-save"> Faíscas</label>
                    <label class="vfx-checkbox-label"><input type="checkbox" id="vfx-eff-trail" class="vfx-save"> Rastro</label>
                    <label class="vfx-checkbox-label"><input type="checkbox" id="vfx-eff-snow" class="vfx-save"> Neve</label>
                    <label class="vfx-checkbox-label"><input type="checkbox" id="vfx-eff-fairydust" class="vfx-save"> Pó de Fada</label>
                    <label class="vfx-checkbox-label"><input type="checkbox" id="vfx-eff-magiclights" class="vfx-save"> Luzes Mágicas</label>
                    <label class="vfx-checkbox-label"><input type="checkbox" id="vfx-eff-fireflies" class="vfx-save"> Vagalumes</label>
                    <label class="vfx-checkbox-label" style="width: 100%; color: #00e5ff;"><input type="checkbox" id="vfx-eff-dash" class="vfx-save"> Rastro Dash (Fantasmas)</label>
                    <label class="vfx-checkbox-label" style="width: 100%; color: #ffae00; margin-top: 4px;"><input type="checkbox" id="vfx-eff-keep-active" class="vfx-save"> Manter Efeito Ativo (Parado / Ao Segurar)</label>
                </div>

                <label>Camada dos Efeitos:</label>
                <select id="vfx-effect-layer" class="vfx-save">
                    <option value="behind_piece">Atrás da Peça</option>
                    <option value="over_piece">Por Cima da Peça</option>
                </select>

                <label>Preview & Origem dos Efeitos:</label>
                <div style="position: relative; width: 100%; height: 160px; background: #111; border: 1px solid rgba(0,229,255,0.3); border-radius: 6px; margin-top: 5px; overflow: hidden; display: flex; align-items: center; justify-content: center;">
                    <canvas id="vfx-preview-canvas" width="220" height="150" style="cursor: crosshair;"></canvas>
                </div>
                <div style="display: flex; gap: 5px; margin-top: 8px;">
                    <button id="vfx-add-dot-btn" type="button" class="vfx-btn-action" style="flex:1;">+ Ponto Efeito</button>
                    <button id="vfx-clear-dots-btn" type="button" class="vfx-btn-action" style="flex:1; background:#ff4444; color:#fff;">Resetar Pontos</button>
                </div>
            </div>

            <hr style="border:0; border-top:1px solid rgba(255,255,255,0.1); margin: 15px 0;">

            <label>Iluminar Casas (Hover):</label>
            <select id="vfx-hover-toggle" class="vfx-save">
                <option value="on">Ativado</option>
                <option value="off">Desativado</option>
            </select>

            <label>Cor da Iluminação:</label>
            <input type="color" id="vfx-light-color" class="vfx-save" value="#00e5ff">

            <label>Intensidade da Cor: <span id="vfx-intensity-val" style="color:#00e5ff;">50%</span></label>
            <input type="range" id="vfx-light-intensity" class="vfx-save" min="0" max="1" step="0.05" value="0.5">

            <label>Vazamento da Luz (Blur): <span id="vfx-bleed-val" style="color:#00e5ff;">25px</span></label>
            <input type="range" id="vfx-light-bleed" class="vfx-save" min="0" max="80" step="1" value="25">
        </div>
    `;
    document.body.appendChild(uiPanel);

    let panelOpen = false;
    uiBtn.addEventListener('click', () => {
        panelOpen = !panelOpen;
        uiPanel.style.display = panelOpen ? 'block' : 'none';
        if (panelOpen) renderPreview();
    });

    document.querySelectorAll('.vfx-tab-btn').forEach(btn => {
        btn.addEventListener('click', (e) => {
            document.querySelectorAll('.vfx-tab-btn').forEach(b => b.classList.remove('active'));
            document.querySelectorAll('.vfx-tab-content').forEach(c => c.classList.remove('active'));
            e.target.classList.add('active');
            document.getElementById(e.target.getAttribute('data-target')).classList.add('active');
            if (e.target.getAttribute('data-target') === 'tab-movimento') {
                renderPreview();
            }
        });
    });

    const canvas = document.createElement('canvas');
    canvas.id = 'vfx-canvas';
    const ctx = canvas.getContext('2d', { alpha: true });

    let boardEl = null;
    let hoverLightEl = null;
    let particles = [];
    let dragParticles = [];
    let animationId = null;

    let currentEffect = 'none';
    let speedMult = 1;
    let sizeMult = 1;

    let customImg = new Image();
    let customImgLoaded = false;
    let emissionPoints = [{ x: 0.5, y: 0.8 }];

    // Inicializado com coordenadas distantes para evitar vazamentos acidentais no começo
    let lastDragMousePos = { x: -1000, y: -1000 };

    const previewCanvas = document.getElementById('vfx-preview-canvas');
    const previewCtx = previewCanvas.getContext('2d');
    let activeDotIndex = -1;
    let isDraggingDot = false;

    // Helper para obter o container correto de coordenadas
    function getTargetContainer(board) {
        if (!board) return null;
        return board.tagName.toLowerCase() === 'canvas' ? board.parentElement : board;
    }

    function saveSettings() {
        const settings = {};
        document.querySelectorAll('.vfx-save').forEach(input => {
            if (input.type === 'checkbox') {
                settings[input.id] = input.checked;
            } else {
                settings[input.id] = input.value;
            }
        });
        localStorage.setItem('vfx_chess_pro_settings', JSON.stringify(settings));
        localStorage.setItem('vfx_emission_points', JSON.stringify(emissionPoints));
    }

    function loadSettings() {
        const saved = localStorage.getItem('vfx_chess_pro_settings');
        if (saved) {
            try {
                const settings = JSON.parse(saved);
                Object.keys(settings).forEach(id => {
                    const el = document.getElementById(id);
                    if (el) {
                        if (el.type === 'checkbox') {
                            el.checked = settings[id];
                        } else {
                            el.value = settings[id];
                        }
                    }
                });
            } catch (e) {}
        }

        const savedImg = localStorage.getItem('vfx_custom_img_data');
        if (savedImg) {
            customImg.onload = () => {
                customImgLoaded = true;
                renderPreview();
            };
            customImg.src = savedImg;
        }

        const savedPoints = localStorage.getItem('vfx_emission_points');
        if (savedPoints) {
            try {
                emissionPoints = JSON.parse(savedPoints);
            } catch (e) {
                emissionPoints = [{ x: 0.5, y: 0.8 }];
            }
        }

        document.getElementById('vfx-select').dispatchEvent(new Event('change'));
        document.getElementById('vfx-speed').dispatchEvent(new Event('input'));
        document.getElementById('vfx-size').dispatchEvent(new Event('input'));
        document.getElementById('vfx-drag-effect').dispatchEvent(new Event('change'));
        document.getElementById('vfx-sparkle-int').dispatchEvent(new Event('input'));
        document.getElementById('vfx-trail-thick').dispatchEvent(new Event('input'));
        document.getElementById('vfx-trail-fade').dispatchEvent(new Event('input'));
        document.getElementById('vfx-img-x').dispatchEvent(new Event('input'));
        document.getElementById('vfx-img-y').dispatchEvent(new Event('input'));
        document.getElementById('vfx-img-scale').dispatchEvent(new Event('input'));
        document.getElementById('vfx-eff-size').dispatchEvent(new Event('input'));
        document.getElementById('vfx-eff-int').dispatchEvent(new Event('input'));
        document.getElementById('vfx-light-intensity').dispatchEvent(new Event('input'));
        document.getElementById('vfx-light-bleed').dispatchEvent(new Event('input'));
        updateLightStyles();
    }

    document.querySelectorAll('.vfx-save').forEach(el => {
        el.addEventListener('change', () => { saveSettings(); renderPreview(); });
        el.addEventListener('input', () => { saveSettings(); renderPreview(); });
    });

    document.getElementById('vfx-select').addEventListener('change', (e) => {
        currentEffect = e.target.value;
        initParticles();
        handleBoardEffects();
    });
    document.getElementById('vfx-speed').addEventListener('input', (e) => {
        speedMult = parseFloat(e.target.value);
        document.getElementById('vfx-speed-val').innerText = speedMult + 'x';
    });
    document.getElementById('vfx-size').addEventListener('input', (e) => {
        sizeMult = parseFloat(e.target.value);
        document.getElementById('vfx-size-val').innerText = sizeMult + 'x';
        initParticles();
    });

    document.getElementById('vfx-drag-effect').addEventListener('change', (e) => {
        const val = e.target.value;
        document.getElementById('vfx-sparkles-cfg').style.display = val === 'sparkles' ? 'block' : 'none';
        document.getElementById('vfx-trail-cfg').style.display = val === 'trail' ? 'block' : 'none';
        document.getElementById('vfx-image-cfg').style.display = val === 'image' ? 'block' : 'none';
        if (val === 'image') renderPreview();
    });

    document.getElementById('vfx-sparkle-int').addEventListener('input', (e) => {
        document.getElementById('vfx-sparkle-val').innerText = e.target.value + '%';
    });

    document.getElementById('vfx-trail-thick').addEventListener('input', (e) => {
        document.getElementById('vfx-trail-thick-val').innerText = e.target.value + 'px';
    });

    document.getElementById('vfx-trail-fade').addEventListener('input', (e) => {
        const val = parseFloat(e.target.value);
        let texto = "Média";
        if (val <= 0.02) texto = "Lenta";
        else if (val >= 0.08) texto = "Rápida";
        document.getElementById('vfx-trail-fade-val').innerText = texto;
    });

    document.getElementById('vfx-img-x').addEventListener('input', (e) => {
        document.getElementById('vfx-img-x-val').innerText = e.target.value + 'px';
        renderPreview();
    });
    document.getElementById('vfx-img-y').addEventListener('input', (e) => {
        document.getElementById('vfx-img-y-val').innerText = e.target.value + 'px';
        renderPreview();
    });
    document.getElementById('vfx-img-scale').addEventListener('input', (e) => {
        document.getElementById('vfx-img-scale-val').innerText = e.target.value + 'x';
        renderPreview();
    });
    document.getElementById('vfx-eff-size').addEventListener('input', (e) => {
        document.getElementById('vfx-eff-size-val').innerText = e.target.value + 'x';
    });
    document.getElementById('vfx-eff-int').addEventListener('input', (e) => {
        document.getElementById('vfx-eff-int-val').innerText = e.target.value + '%';
    });

    document.getElementById('vfx-img-file').addEventListener('change', (e) => {
        const file = e.target.files[0];
        if (file) {
            const reader = new FileReader();
            reader.onload = (evt) => {
                customImg = new Image();
                customImg.onload = () => {
                    customImgLoaded = true;
                    localStorage.setItem('vfx_custom_img_data', evt.target.result);
                    renderPreview();
                };
                customImg.src = evt.target.result;
            };
            reader.readAsDataURL(file);
        }
    });

    document.getElementById('vfx-add-dot-btn').addEventListener('click', () => {
        emissionPoints.push({ x: 0.5, y: 0.8 });
        saveSettings();
        renderPreview();
    });

    document.getElementById('vfx-clear-dots-btn').addEventListener('click', () => {
        emissionPoints = [{ x: 0.5, y: 0.8 }];
        saveSettings();
        renderPreview();
    });

    const lightInputs = ['vfx-light-color', 'vfx-light-intensity', 'vfx-light-bleed', 'vfx-hover-toggle'];
    lightInputs.forEach(id => {
        document.getElementById(id).addEventListener('input', () => {
            if (id === 'vfx-light-intensity') document.getElementById('vfx-intensity-val').innerText = Math.round(document.getElementById(id).value * 100) + '%';
            if (id === 'vfx-light-bleed') document.getElementById('vfx-bleed-val').innerText = document.getElementById(id).value + 'px';
            updateLightStyles();
        });
    });

    function getPreviewImageBounds() {
        const pw = previewCanvas.width;
        const ph = previewCanvas.height;
        const scale = parseFloat(document.getElementById('vfx-img-scale').value);
        const offsetX = parseFloat(document.getElementById('vfx-img-x').value) * 0.5;
        const offsetY = parseFloat(document.getElementById('vfx-img-y').value) * 0.5;

        let iw = customImgLoaded ? customImg.width : 60;
        let ih = customImgLoaded ? customImg.height : 60;

        let aspect = iw / ih;
        let drawW = 60 * scale;
        let drawH = drawW / aspect;

        let cx = pw / 2 + offsetX;
        let cy = ph / 2 + offsetY;

        return {
            x: cx - drawW / 2,
            y: cy - drawH / 2,
            w: drawW,
            h: drawH,
            cx: cx,
            cy: cy
        };
    }

    function renderPreview() {
        if (!previewCanvas) return;
        previewCtx.clearRect(0, 0, previewCanvas.width, previewCanvas.height);

        previewCtx.fillStyle = '#18181c';
        previewCtx.fillRect(0, 0, previewCanvas.width, previewCanvas.height);

        const bounds = getPreviewImageBounds();

        previewCtx.beginPath();
        previewCtx.arc(previewCanvas.width / 2, previewCanvas.height / 2, 22, 0, Math.PI * 2);
        previewCtx.fillStyle = 'rgba(255, 255, 255, 0.15)';
        previewCtx.strokeStyle = 'rgba(0, 229, 255, 0.4)';
        previewCtx.lineWidth = 1;
        previewCtx.fill();
        previewCtx.stroke();

        previewCtx.fillStyle = '#00e5ff';
        previewCtx.font = '10px sans-serif';
        previewCtx.textAlign = 'center';
        previewCtx.fillText('PEÇA', previewCanvas.width / 2, previewCanvas.height / 2 + 3);

        if (customImgLoaded) {
            previewCtx.drawImage(customImg, bounds.x, bounds.y, bounds.w, bounds.h);
            previewCtx.strokeStyle = 'rgba(255, 255, 255, 0.2)';
            previewCtx.strokeRect(bounds.x, bounds.y, bounds.w, bounds.h);
        } else {
            previewCtx.strokeStyle = '#555';
            previewCtx.setLineDash([4, 4]);
            previewCtx.strokeRect(bounds.x, bounds.y, bounds.w, bounds.h);
            previewCtx.setLineDash([]);
            previewCtx.fillStyle = '#888';
            previewCtx.font = '10px sans-serif';
            previewCtx.fillText('Sem Imagem', bounds.cx, bounds.cy);
        }

        emissionPoints.forEach((pt, index) => {
            let px = bounds.x + pt.x * bounds.w;
            let py = bounds.y + pt.y * bounds.h;

            previewCtx.beginPath();
            previewCtx.arc(px, py, 6, 0, Math.PI * 2);
            previewCtx.fillStyle = '#ffffff';
            previewCtx.shadowBlur = 8;
            previewCtx.shadowColor = '#00e5ff';
            previewCtx.fill();
            previewCtx.shadowBlur = 0;

            previewCtx.strokeStyle = '#00e5ff';
            previewCtx.lineWidth = 2;
            previewCtx.stroke();

            previewCtx.fillStyle = '#000';
            previewCtx.font = '9px sans-serif';
            previewCtx.fillText((index + 1).toString(), px, py + 3);
        });
    }

    previewCanvas.addEventListener('mousedown', (e) => {
        const rect = previewCanvas.getBoundingClientRect();
        const mx = e.clientX - rect.left;
        const my = e.clientY - rect.top;
        const bounds = getPreviewImageBounds();

        activeDotIndex = -1;
        for (let i = 0; i < emissionPoints.length; i++) {
            let px = bounds.x + emissionPoints[i].x * bounds.w;
            let py = bounds.y + emissionPoints[i].y * bounds.h;
            let dist = Math.hypot(mx - px, my - py);
            if (dist <= 10) {
                activeDotIndex = i;
                break;
            }
        }

        if (activeDotIndex !== -1) {
            isDraggingDot = true;
        } else if (bounds.w > 0 && bounds.h > 0) {
            let nx = (mx - bounds.x) / bounds.w;
            let ny = (my - bounds.y) / bounds.h;
            nx = Math.max(0, Math.min(1, nx));
            ny = Math.max(0, Math.min(1, ny));
            emissionPoints.push({ x: nx, y: ny });
            activeDotIndex = emissionPoints.length - 1;
            isDraggingDot = true;
            saveSettings();
            renderPreview();
        }
    });

    previewCanvas.addEventListener('mousemove', (e) => {
        if (!isDraggingDot || activeDotIndex === -1) return;
        const rect = previewCanvas.getBoundingClientRect();
        const mx = e.clientX - rect.left;
        const my = e.clientY - rect.top;
        const bounds = getPreviewImageBounds();

        if (bounds.w > 0 && bounds.h > 0) {
            let nx = (mx - bounds.x) / bounds.w;
            let ny = (my - bounds.y) / bounds.h;
            nx = Math.max(0, Math.min(1, nx));
            ny = Math.max(0, Math.min(1, ny));
            emissionPoints[activeDotIndex] = { x: nx, y: ny };
            renderPreview();
        }
    });

    window.addEventListener('mouseup', () => {
        if (isDraggingDot) {
            isDraggingDot = false;
            saveSettings();
        }
    });

    function getBoard() {
        return document.querySelector('wc-chess-board') || document.querySelector('.board') || document.querySelector('#board-layout-main canvas');
    }

    function updateCanvasBounds() {
        boardEl = getBoard();
        const targetContainer = getTargetContainer(boardEl);

        if (targetContainer) {
            if (canvas.parentNode !== targetContainer) {
                targetContainer.appendChild(canvas);
                if (getComputedStyle(targetContainer).position === 'static') {
                    targetContainer.style.position = 'relative';
                }
            }

            canvas.style.position = 'absolute';
            canvas.style.top = '0px';
            canvas.style.left = '0px';
            canvas.style.pointerEvents = 'none';

            const rect = targetContainer.getBoundingClientRect();
            if (canvas.width !== Math.floor(rect.width) || canvas.height !== Math.floor(rect.height)) {
                canvas.width = rect.width;
                canvas.height = rect.height;
                initParticles();
            }

            if (!hoverLightEl) {
                hoverLightEl = document.createElement('div');
                hoverLightEl.id = 'vfx-hover-light';
                targetContainer.appendChild(hoverLightEl);
                updateLightStyles();
            } else if (hoverLightEl.parentNode !== targetContainer) {
                targetContainer.appendChild(hoverLightEl);
            }
        } else {
            canvas.width = 0;
            canvas.height = 0;
        }
    }

    function updateLightStyles() {
        if (!hoverLightEl) return;
        const toggle = document.getElementById('vfx-hover-toggle').value;
        if (toggle === 'off') {
            hoverLightEl.style.display = 'none';
            return;
        }
        hoverLightEl.style.display = 'block';

        const colorHex = document.getElementById('vfx-light-color').value;
        const intensity = document.getElementById('vfx-light-intensity').value;
        const bleed = document.getElementById('vfx-light-bleed').value;

        let r = parseInt(colorHex.substring(1,3), 16);
        let g = parseInt(colorHex.substring(3,5), 16);
        let b = parseInt(colorHex.substring(5,7), 16);

        hoverLightEl.style.backgroundColor = `rgba(${r},${g},${b},${intensity})`;
        if (bleed > 0) {
            hoverLightEl.style.boxShadow = `0 0 ${bleed}px ${bleed/2}px rgba(${r},${g},${b}, ${Math.min(1, intensity * 1.5)})`;
        } else {
            hoverLightEl.style.boxShadow = 'none';
        }
    }

    function handleBoardEffects() {
        if (!boardEl) return;
        const pieces = boardEl.querySelectorAll('.piece');
        boardEl.classList.remove('vfx-glitch', 'vfx-vibrate');
        pieces.forEach(p => p.classList.remove('vfx-glitch-piece'));
        document.querySelectorAll('.vfx-glitch-piece').forEach(p => p.classList.remove('vfx-glitch-piece'));
        if (currentEffect === 'glitch') {
            boardEl.classList.add('vfx-glitch');
            pieces.forEach(p => p.classList.add('vfx-glitch-piece'));
        } else if (currentEffect === 'vibrate') {
            boardEl.classList.add('vfx-vibrate');
        }
    }

    let isDragging = false;
    let currentHoverCol = -1;
    let currentHoverRow = -1;
    let lastSpawnTime = 0;

    document.addEventListener('mousedown', (e) => {
        if (e.target.closest('.piece') || e.target.closest('.square')) {
            isDragging = true;
            if (boardEl) {
                const targetContainer = getTargetContainer(boardEl);
                if (targetContainer) {
                    const rect = targetContainer.getBoundingClientRect();
                    lastDragMousePos = { x: e.clientX - rect.left, y: e.clientY - rect.top };
                }
            }
            updateHoverSquare(e);
        }
    });

    document.addEventListener('mouseup', () => {
        isDragging = false;
        if (hoverLightEl) hoverLightEl.style.opacity = '0';
    });

    document.addEventListener('mousemove', (e) => {
        if (isDragging) {
            updateHoverSquare(e);
            spawnDragParticle(e);
        }
    });

    function updateHoverSquare(e) {
        if (!boardEl || !hoverLightEl || document.getElementById('vfx-hover-toggle').value === 'off') return;

        const targetContainer = getTargetContainer(boardEl);
        if (!targetContainer) return;
        const rect = targetContainer.getBoundingClientRect();
        let x = e.clientX - rect.left;
        let y = e.clientY - rect.top;

        if (x < 0 || x > rect.width || y < 0 || y > rect.height) {
            hoverLightEl.style.opacity = '0';
            return;
        }

        let sqSize = rect.width / 8;
        let col = Math.floor(x / sqSize);
        let row = Math.floor(y / sqSize);

        if (col !== currentHoverCol || row !== currentHoverRow) {
            currentHoverCol = col;
            currentHoverRow = row;
            hoverLightEl.style.transform = `translate(${col * 100}%, ${row * 100}%)`;
            hoverLightEl.style.opacity = '1';
        }
    }

    function spawnDragParticle(e) {
        const type = document.getElementById('vfx-drag-effect').value;
        if (type === 'none' || !boardEl) return;

        let now = Date.now();
        let delay = type === 'water' ? 80 : (type === 'trail' ? 8 : (type === 'image' ? 15 : 12));

        if (now - lastSpawnTime > delay) {
            const targetContainer = getTargetContainer(boardEl);
            if (!targetContainer) return;
            const rect = targetContainer.getBoundingClientRect();

            let cx, cy;
            if (e) {
                cx = e.clientX - rect.left;
                cy = e.clientY - rect.top;
                lastDragMousePos = { x: cx, y: cy };
            } else {
                cx = lastDragMousePos.x;
                cy = lastDragMousePos.y;
            }

            if (cx >= 0 && cx <= rect.width && cy >= 0 && cy <= rect.height) {
                if (type === 'sparkles') {
                    const intensity = parseInt(document.getElementById('vfx-sparkle-int').value);
                    const amount = Math.floor((intensity / 100) * 18) + 2;
                    for (let i = 0; i < amount; i++) {
                        dragParticles.push(new DragParticle(cx, cy, type));
                    }
                } else if (type === 'image') {
                    const scale = parseFloat(document.getElementById('vfx-img-scale').value);
                    const offX = parseFloat(document.getElementById('vfx-img-x').value);
                    const offY = parseFloat(document.getElementById('vfx-img-y').value);

                    const effSize = parseFloat(document.getElementById('vfx-eff-size').value) || 1;
                    const effInt = (parseFloat(document.getElementById('vfx-eff-int').value) || 100) / 100;

                    let sqSize = rect.width / 8;
                    let imgW = (customImgLoaded ? customImg.width : sqSize) * scale;
                    let imgH = (customImgLoaded ? customImg.height : sqSize) * scale;

                    let imgX = cx + offX - imgW / 2;
                    let imgY = cy + offY - imgH / 2;

                    const activeEffs = {
                        jetpack: document.getElementById('vfx-eff-jetpack').checked,
                        fire: document.getElementById('vfx-eff-fire').checked,
                        smoke: document.getElementById('vfx-eff-smoke').checked,
                        sparkles: document.getElementById('vfx-eff-sparkles').checked,
                        trail: document.getElementById('vfx-eff-trail').checked,
                        snow: document.getElementById('vfx-eff-snow').checked,
                        fairydust: document.getElementById('vfx-eff-fairydust').checked,
                        magiclights: document.getElementById('vfx-eff-magiclights').checked,
                        fireflies: document.getElementById('vfx-eff-fireflies').checked,
                        dash: document.getElementById('vfx-eff-dash').checked
                    };

                    const getCount = (base) => {
                        let c = base * effInt;
                        let f = Math.floor(c);
                        if (Math.random() < (c - f)) f++;
                        return f;
                    };

                    if (activeEffs.dash && customImgLoaded) {
                        dragParticles.push(new DragParticle(imgX, imgY, 'dash_ghost', { w: imgW, h: imgH, img: customImg }));
                    }

                    emissionPoints.forEach(pt => {
                        let eX = imgX + pt.x * imgW;
                        let eY = imgY + pt.y * imgH;

                        if (activeEffs.jetpack) {
                            for (let i = 0; i < getCount(3); i++) dragParticles.push(new DragParticle(eX, eY, 'jetpack_fire', { sizeMult: effSize }));
                            for (let i = 0; i < getCount(2); i++) dragParticles.push(new DragParticle(eX, eY, 'jetpack_smoke', { sizeMult: effSize }));
                        }
                        if (activeEffs.fire) {
                            for (let i = 0; i < getCount(2); i++) dragParticles.push(new DragParticle(eX, eY, 'fire_eff', { sizeMult: effSize }));
                        }
                        if (activeEffs.smoke) {
                            for (let i = 0; i < getCount(1); i++) dragParticles.push(new DragParticle(eX, eY, 'smoke_eff', { sizeMult: effSize }));
                        }
                        if (activeEffs.sparkles) {
                            for (let i = 0; i < getCount(3); i++) dragParticles.push(new DragParticle(eX, eY, 'sparkles', { sizeMult: effSize }));
                        }
                        if (activeEffs.trail) {
                            for (let i = 0; i < getCount(1); i++) dragParticles.push(new DragParticle(eX, eY, 'trail', { sizeMult: effSize }));
                        }
                        if (activeEffs.snow) {
                            for (let i = 0; i < getCount(1); i++) dragParticles.push(new DragParticle(eX, eY, 'snow_eff', { sizeMult: effSize }));
                        }
                        if (activeEffs.fairydust) {
                            for (let i = 0; i < getCount(2); i++) dragParticles.push(new DragParticle(eX, eY, 'fairydust_eff', { sizeMult: effSize }));
                        }
                        if (activeEffs.magiclights) {
                            for (let i = 0; i < getCount(1); i++) dragParticles.push(new DragParticle(eX, eY, 'magiclights_eff', { sizeMult: effSize }));
                        }
                        if (activeEffs.fireflies) {
                            for (let i = 0; i < getCount(1); i++) dragParticles.push(new DragParticle(eX, eY, 'fireflies_eff', { sizeMult: effSize }));
                        }
                    });
                } else {
                    dragParticles.push(new DragParticle(cx, cy, type));
                }

                lastSpawnTime = now;
            }
        }
    }

    class DragParticle {
        constructor(x, y, type, cfg = {}) {
            this.x = x;
            this.y = y;
            this.type = type;
            this.life = 1.0;
            this.colorHex = document.getElementById('vfx-light-color').value;
            let sm = cfg.sizeMult || 1;

            if (type === 'dash_ghost') {
                this.img = cfg.img;
                this.w = cfg.w;
                this.h = cfg.h;
                this.decay = 0.06;
            } else if (type === 'water') {
                this.radius = 5 * sm;
                this.speed = 1.5 + Math.random();
                this.decay = 0.02;
            } else if (type === 'sparkles') {
                this.colorHex = ['#ffcc00', '#ff9900', '#ffffff', '#ff5500'][Math.floor(Math.random()*4)];
                this.vx = (Math.random() - 0.5) * 15;
                this.vy = (Math.random() - 0.5) * 15;
                this.size = (Math.random() * 2.5 + 0.5) * sm;
                this.decay = 0.04 + Math.random() * 0.03;
            } else if (type === 'magic') {
                this.vx = (Math.random() - 0.5) * 3;
                this.vy = (Math.random() - 0.5) * 3 - 1;
                this.size = (Math.random() * 4 + 1) * sm;
                this.decay = 0.015;
            } else if (type === 'trail') {
                this.colorHex = document.getElementById('vfx-trail-color').value;
                this.radius = parseInt(document.getElementById('vfx-trail-thick').value) * sm;
                this.decay = parseFloat(document.getElementById('vfx-trail-fade').value);
                this.vx = (Math.random() - 0.5) * 0.5;
                this.vy = (Math.random() - 0.5) * 0.5;
            } else if (type === 'jetpack_fire') {
                this.colorHex = ['#ff2200', '#ff6600', '#ffcc00', '#ffffff'][Math.floor(Math.random()*4)];
                this.vx = (Math.random() - 0.5) * 4;
                this.vy = Math.random() * 7 + 4;
                this.size = (Math.random() * 10 + 5) * sm;
                this.decay = 0.05 + Math.random() * 0.03;
            } else if (type === 'jetpack_smoke') {
                this.colorHex = 'rgba(120, 120, 120, 0.5)';
                this.vx = (Math.random() - 0.5) * 5;
                this.vy = Math.random() * 5 + 3;
                this.size = (Math.random() * 14 + 8) * sm;
                this.decay = 0.02 + Math.random() * 0.02;
            } else if (type === 'fire_eff') {
                this.colorHex = ['#ff3300', '#ff8800', '#ffd700'][Math.floor(Math.random()*3)];
                this.vx = (Math.random() - 0.5) * 3;
                this.vy = -(Math.random() * 4 + 2);
                this.size = (Math.random() * 12 + 6) * sm;
                this.decay = 0.04;
            } else if (type === 'smoke_eff') {
                this.colorHex = 'rgba(100, 100, 100, 0.4)';
                this.vx = (Math.random() - 0.5) * 2;
                this.vy = -(Math.random() * 3 + 1);
                this.size = (Math.random() * 16 + 10) * sm;
                this.decay = 0.02;
            } else if (type === 'snow_eff') {
                this.colorHex = 'rgba(255, 255, 255, 0.9)';
                this.vx = (Math.random() - 0.5) * 1.5;
                this.vy = (Math.random() * 2 + 1);
                this.size = (Math.random() * 3 + 1.5) * sm;
                this.decay = 0.02;
            } else if (type === 'fairydust_eff') {
                this.colorHex = '#ffb6c1';
                this.vx = (Math.random() - 0.5) * 2;
                this.vy = -(Math.random() * 2 + 1);
                this.size = (Math.random() * 2.5 + 1) * sm;
                this.decay = 0.03;
                this.angle = Math.random() * Math.PI * 2;
            } else if (type === 'magiclights_eff') {
                const colors = ['#ff00ff', '#00ffff', '#ffff00', '#00ff00', '#ff0055'];
                this.colorHex = colors[Math.floor(Math.random() * colors.length)];
                this.vx = (Math.random() - 0.5) * 1.5;
                this.vy = -(Math.random() - 0.5) * 1.5;
                this.size = (Math.random() * 6 + 3) * sm;
                this.decay = 0.02;
                this.glow = (Math.random() * 15 + 5) * sm;
            } else if (type === 'fireflies_eff') {
                this.colorHex = '#c6ff00';
                this.vx = (Math.random() - 0.5) * 2;
                this.vy = (Math.random() - 0.5) * 2;
                this.size = (Math.random() * 3 + 1.5) * sm;
                this.decay = 0.015;
                this.angle = Math.random() * Math.PI * 2;
            }
        }
        update() {
            if (this.type === 'dash_ghost') {
            } else if (this.type === 'water') {
                this.radius += this.speed;
            } else if (this.type === 'trail') {
                this.x += this.vx;
                this.y += this.vy;
                this.radius += 0.3;
            } else if (this.type === 'jetpack_smoke' || this.type === 'smoke_eff') {
                this.x += this.vx;
                this.y += this.vy;
                this.size += 0.3;
            } else if (this.type === 'fairydust_eff' || this.type === 'fireflies_eff') {
                this.angle += (Math.random() * 0.2 - 0.1);
                this.x += this.vx + Math.cos(this.angle) * 1.5;
                this.y += this.vy + Math.sin(this.angle) * 1.5;
            } else {
                this.x += this.vx;
                this.y += this.vy;
                if (this.type === 'sparkles') {
                    this.vy += 0.3;
                    this.vx *= 0.95;
                }
            }
            this.life -= this.decay;
        }
        draw(ctx) {
            ctx.globalAlpha = Math.max(0, this.life);
            if (this.type === 'dash_ghost') {
                if (this.img) {
                    ctx.globalAlpha = Math.max(0, this.life * 0.4);
                    ctx.drawImage(this.img, this.x, this.y, this.w, this.h);
                }
            } else if (this.type === 'water') {
                ctx.beginPath();
                ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
                ctx.strokeStyle = this.colorHex;
                ctx.lineWidth = 2 * this.life;
                ctx.stroke();
            } else if (this.type === 'sparkles') {
                ctx.beginPath();
                ctx.moveTo(this.x, this.y);
                ctx.lineTo(this.x - (this.vx * 1.5), this.y - (this.vy * 1.5));
                ctx.strokeStyle = this.colorHex;
                ctx.lineWidth = this.size;
                ctx.lineCap = 'round';
                ctx.shadowBlur = 8;
                ctx.shadowColor = this.colorHex;
                ctx.stroke();
                ctx.shadowBlur = 0;
            } else if (this.type === 'magic') {
                ctx.beginPath();
                ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
                ctx.fillStyle = this.colorHex;
                ctx.shadowBlur = 10;
                ctx.shadowColor = this.colorHex;
                ctx.fill();
                ctx.shadowBlur = 0;
            } else if (this.type === 'magiclights_eff') {
                ctx.beginPath();
                ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
                ctx.fillStyle = this.colorHex;
                ctx.shadowBlur = this.glow;
                ctx.shadowColor = this.colorHex;
                ctx.fill();
                ctx.shadowBlur = 0;
            } else if (this.type === 'fairydust_eff' || this.type === 'fireflies_eff') {
                ctx.beginPath();
                ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
                ctx.fillStyle = this.colorHex;
                ctx.shadowBlur = 8;
                ctx.shadowColor = this.colorHex;
                ctx.fill();
                ctx.shadowBlur = 0;
            } else if (this.type === 'trail' || this.type === 'jetpack_fire' || this.type === 'jetpack_smoke' || this.type === 'fire_eff' || this.type === 'smoke_eff' || this.type === 'snow_eff') {
                ctx.beginPath();
                ctx.arc(this.x, this.y, this.type === 'trail' ? this.radius : this.size, 0, Math.PI * 2);
                ctx.fillStyle = this.colorHex;
                if (this.type === 'jetpack_fire' || this.type === 'fire_eff') {
                    ctx.shadowBlur = 12;
                    ctx.shadowColor = this.colorHex;
                }
                ctx.fill();
                ctx.shadowBlur = 0;
            }
            ctx.globalAlpha = 1.0;
        }
    }

    class Particle {
        constructor(type) {
            this.type = type;
            this.reset(true);
            if (type === 'warp') {
                this.z = Math.random() * canvas.width;
            }
        }

        reset(initial = false) {
            const w = canvas.width;
            const h = canvas.height;

            if (this.type === 'space') {
                this.x = Math.random() * w;
                this.y = Math.random() * h;
                this.size = (Math.random() * 2 + 0.5) * sizeMult;
                this.speed = (Math.random() * 0.5 + 0.1);
                this.angle = Math.random() * Math.PI * 2;
                const colors = ['#ffffff', '#ffe9c4', '#d4fbff', '#ffb3ba', '#ffffaa'];
                this.color = colors[Math.floor(Math.random() * colors.length)];
                this.life = Math.random();
            }
            else if (this.type === 'warp') {
                this.x = (Math.random() - 0.5) * w * 2;
                this.y = (Math.random() - 0.5) * h * 2;
                this.z = w;
                this.size = (Math.random() * 5 + 3) * sizeMult;
                const colors = ['#ffffff', '#d4fbff', '#00ffff', '#ffb3ba'];
                this.color = colors[Math.floor(Math.random() * colors.length)];
            }
            else if (this.type === 'rain') {
                this.x = Math.random() * w;
                this.y = initial ? Math.random() * h : -20;
                this.size = (Math.random() * 1.5 + 0.5) * sizeMult;
                this.speedY = (Math.random() * 10 + 15);
                this.speedX = (Math.random() * 2 - 1);
                this.color = 'rgba(174, 194, 224, 0.7)';
            }
            else if (this.type === 'snow') {
                this.x = Math.random() * w;
                this.y = initial ? Math.random() * h : -10;
                this.size = (Math.random() * 3 + 1) * sizeMult;
                this.speedY = (Math.random() * 1.5 + 1);
                this.speedX = (Math.random() * 2 - 1);
                this.color = 'rgba(255, 255, 255, 0.9)';
            }
            else if (this.type === 'smoke') {
                this.x = Math.random() * w;
                this.y = initial ? Math.random() * h : h + 50;
                this.size = (Math.random() * 40 + 20) * sizeMult;
                this.speedY = -(Math.random() * 1.5 + 0.5);
                this.speedX = (Math.random() * 2 - 1);
                this.life = Math.random() * 0.5 + 0.1;
                this.color = `rgba(100, 100, 100, ${this.life * 0.15})`;
            }
            else if (this.type === 'fire') {
                this.x = Math.random() * w;
                this.y = h + (Math.random() * 20);
                this.size = (Math.random() * 20 + 10) * sizeMult;
                this.speedY = -(Math.random() * 3 + 1);
                this.speedX = (Math.random() * 2 - 1);
                this.life = 1.0;
                const colors = ['#ff4500', '#ff8c00', '#ffd700'];
                this.baseColor = colors[Math.floor(Math.random() * colors.length)];
            }
            else if (this.type === 'wind') {
                this.x = initial ? Math.random() * w : -100;
                this.y = Math.random() * h;
                this.size = (Math.random() * 50 + 20) * sizeMult;
                this.speedX = (Math.random() * 15 + 20);
                this.color = 'rgba(255, 255, 255, 0.4)';
            }
            else if (this.type === 'lights') {
                this.x = Math.random() * w;
                this.y = Math.random() * h;
                this.size = (Math.random() * 6 + 3) * sizeMult;
                this.speedX = (Math.random() * 2 - 1);
                this.speedY = (Math.random() * 2 - 1);
                const colors = ['#ff00ff', '#00ffff', '#ffff00', '#00ff00', '#ff0055'];
                this.color = colors[Math.floor(Math.random() * colors.length)];
                this.glow = (Math.random() * 15 + 5) * sizeMult;
            }
            else if (this.type === 'fairydust') {
                this.x = Math.random() * w;
                this.y = initial ? Math.random() * h : h + 20;
                this.size = (Math.random() * 3 + 1) * sizeMult;
                this.speedY = -(Math.random() * 2 + 1);
                this.speedX = (Math.random() * 2 - 1);
                this.life = 1.0;
                this.angle = Math.random() * Math.PI * 2;
                this.color = '#ffb6c1';
            }
            else if (this.type === 'fireflies') {
                this.x = Math.random() * w;
                this.y = Math.random() * h;
                this.size = (Math.random() * 3 + 1.5) * sizeMult;
                this.speedX = (Math.random() * 1.5 - 0.75);
                this.speedY = (Math.random() * 1.5 - 0.75);
                this.color = '#c6ff00';
                this.angle = Math.random() * Math.PI * 2;
            }
            else if (this.type === 'meteors') {
                this.x = Math.random() * w * 1.5;
                this.y = -50;
                this.size = (Math.random() * 4 + 2) * sizeMult;
                this.speedX = -(Math.random() * 10 + 10);
                this.speedY = (Math.random() * 10 + 10);
                this.length = (Math.random() * 60 + 30) * sizeMult;
                const colors = ['#ffaa00', '#ff5500', '#ffffff'];
                this.color = colors[Math.floor(Math.random() * colors.length)];
            }
            else if (this.type === 'lightning') {
                this.life = initial ? Math.random() : 1.0;
                this.points = [];
                let currX = Math.random() * w;
                let currY = 0;
                this.points.push({x: currX, y: currY});
                while(currY < h) {
                    currY += Math.random() * 40 + 20;
                    currX += (Math.random() * 60 - 30);
                    this.points.push({x: currX, y: currY});
                }
            }
            else if (this.type === 'birds') {
                this.x = initial ? Math.random() * w : -50;
                this.y = Math.random() * (h * 0.7);
                this.size = (Math.random() * 8 + 4) * sizeMult;
                this.speedX = (Math.random() * 3 + 2);
                this.speedY = (Math.random() * 1 - 0.5);
                this.flapSpeed = Math.random() * 0.2 + 0.1;
                this.flapPhase = Math.random() * Math.PI * 2;
            }
            else if (this.type === 'lasers') {
                this.x = initial ? Math.random() * w : (Math.random() > 0.5 ? -100 : w + 100);
                this.y = Math.random() * h;
                this.size = (Math.random() * 3 + 2) * sizeMult;
                this.speedX = (this.x < 0 ? 1 : -1) * (Math.random() * 20 + 20);
                this.speedY = (Math.random() * 4 - 2);
                this.length = (Math.random() * 100 + 50) * sizeMult;
                const colors = ['#ff0000', '#00ff00', '#0088ff'];
                this.color = colors[Math.floor(Math.random() * colors.length)];
            }
            else if (this.type === 'matrix') {
                this.x = Math.floor(Math.random() * (w / 20)) * 20;
                this.y = initial ? Math.random() * h : -20;
                this.size = (Math.random() * 5 + 12) * sizeMult;
                this.speedY = (Math.random() * 5 + 2);
                const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789@#$%^&*';
                this.char = chars.charAt(Math.floor(Math.random() * chars.length));
                this.life = Math.random();
            }
        }

        update() {
            const w = canvas.width;
            const h = canvas.height;

            if (this.type === 'space') {
                this.x += Math.cos(this.angle) * this.speed * speedMult;
                this.y += Math.sin(this.angle) * this.speed * speedMult;
                this.life -= 0.005 * speedMult;
                if (this.life <= 0 || this.x < 0 || this.x > w || this.y < 0 || this.y > h) this.reset();
            }
            else if (this.type === 'warp') {
                this.z -= (12 * speedMult);
                if (this.z <= 0) this.reset();
            }
            else if (this.type === 'rain') {
                this.x += this.speedX * speedMult;
                this.y += this.speedY * speedMult;
                if (this.y > h) this.reset();
            }
            else if (this.type === 'snow') {
                this.x += (this.speedX + Math.sin(Date.now()*0.001)*0.5) * speedMult;
                this.y += this.speedY * speedMult;
                if (this.y > h) this.reset();
            }
            else if (this.type === 'smoke') {
                this.x += this.speedX * speedMult;
                this.y += this.speedY * speedMult;
                this.size += 0.1 * speedMult;
                if (this.y < -this.size) this.reset();
            }
            else if (this.type === 'fire') {
                this.x += this.speedX * speedMult;
                this.y += this.speedY * speedMult;
                this.size -= 0.3 * speedMult;
                this.life -= 0.02 * speedMult;
                if (this.life <= 0 || this.size <= 0) this.reset();
            }
            else if (this.type === 'wind') {
                this.x += this.speedX * speedMult;
                if (this.x > w + this.size) this.reset();
            }
            else if (this.type === 'lights') {
                this.x += this.speedX * speedMult;
                this.y += this.speedY * speedMult;
                if (this.x < 0 || this.x > w || this.y < 0 || this.y > h) this.reset();
            }
            else if (this.type === 'fairydust') {
                this.angle += (Math.random() * 0.2 - 0.1) * speedMult;
                this.x += Math.cos(this.angle) * 2 * speedMult;
                this.y += this.speedY * speedMult;
                this.life -= 0.01 * speedMult;
                if (this.life <= 0 || this.y < -10) this.reset();
            }
            else if (this.type === 'fireflies') {
                this.angle += (Math.random() * 0.2 - 0.1) * speedMult;
                this.x += Math.cos(this.angle) * 2 * speedMult;
                this.y += Math.sin(this.angle) * 2 * speedMult;
                if (this.x < 0 || this.x > w || this.y < 0 || this.y > h) this.reset();
            }
            else if (this.type === 'meteors') {
                this.x += this.speedX * speedMult;
                this.y += this.speedY * speedMult;
                if (this.y > h + this.length || this.x < -this.length) this.reset();
            }
            else if (this.type === 'lightning') {
                this.life -= 0.05 * speedMult;
                if (this.life <= 0 && Math.random() > 0.95) this.reset();
            }
            else if (this.type === 'birds') {
                this.x += this.speedX * speedMult;
                this.y += this.speedY * speedMult;
                this.flapPhase += this.flapSpeed * speedMult;
                if (this.x > w + 50 || this.y < -50 || this.y > h + 50) this.reset();
            }
            else if (this.type === 'lasers') {
                this.x += this.speedX * speedMult;
                this.y += this.speedY * speedMult;
                if (this.x > w + this.length*2 || this.x < -this.length*2 || this.y < -100 || this.y > h + 100) this.reset();
            }
            else if (this.type === 'matrix') {
                this.y += this.speedY * speedMult;
                if (Math.random() < 0.05) {
                    const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789@#$%^&*';
                    this.char = chars.charAt(Math.floor(Math.random() * chars.length));
                }
                if (this.y > h + 20) this.reset();
            }
        }

        draw(ctx) {
            const w = canvas.width;
            const h = canvas.height;
            ctx.beginPath();

            if (this.type === 'space') {
                ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
                ctx.fillStyle = this.color;
                ctx.globalAlpha = Math.max(0, this.life);
                ctx.fill();
                ctx.globalAlpha = 1;
            }
            else if (this.type === 'warp') {
                if (this.z <= 0) return;
                let sx = (this.x / this.z) * w + w / 2;
                let sy = (this.y / this.z) * h + h / 2;
                let r = (w / this.z) * this.size * 0.015;

                if (sx >= 0 && sx <= w && sy >= 0 && sy <= h) {
                    ctx.arc(sx, sy, Math.max(0.5, r), 0, Math.PI * 2);
                    ctx.fillStyle = this.color;
                    ctx.fill();

                    ctx.strokeStyle = this.color;
                    ctx.lineWidth = Math.max(0.5, r * 0.8);
                    ctx.lineCap = 'round';
                    ctx.moveTo(sx, sy);
                    ctx.lineTo(sx - (this.x / this.z) * (w*0.12), sy - (this.y / this.z) * (h*0.12));
                    ctx.stroke();
                }
            }
            else if (this.type === 'rain') {
                ctx.moveTo(this.x, this.y);
                ctx.lineTo(this.x + this.speedX, this.y + this.size * 10);
                ctx.strokeStyle = this.color;
                ctx.lineWidth = 1;
                ctx.stroke();
            }
            else if (this.type === 'snow') {
                ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
                ctx.fillStyle = this.color;
                ctx.fill();
            }
            else if (this.type === 'smoke') {
                ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
                ctx.fillStyle = this.color;
                ctx.fill();
            }
            else if (this.type === 'fire') {
                ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
                ctx.fillStyle = this.baseColor;
                ctx.globalAlpha = Math.max(0, this.life);
                ctx.fill();
                ctx.globalAlpha = 1;
            }
            else if (this.type === 'wind') {
                ctx.moveTo(this.x, this.y);
                ctx.lineTo(this.x + this.size, this.y);
                ctx.strokeStyle = this.color;
                ctx.lineWidth = 2 * sizeMult;
                ctx.stroke();
            }
            else if (this.type === 'lights') {
                ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
                ctx.fillStyle = this.color;
                ctx.shadowBlur = this.glow;
                ctx.shadowColor = this.color;
                ctx.fill();
                ctx.shadowBlur = 0;
            }
            else if (this.type === 'fairydust') {
                ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
                ctx.fillStyle = this.color;
                ctx.globalAlpha = Math.max(0, this.life);
                ctx.shadowBlur = 5 * sizeMult;
                ctx.shadowColor = this.color;
                ctx.fill();
                ctx.globalAlpha = 1;
                ctx.shadowBlur = 0;
            }
            else if (this.type === 'fireflies') {
                ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
                ctx.fillStyle = this.color;
                ctx.shadowBlur = 10 * sizeMult;
                ctx.shadowColor = this.color;
                ctx.fill();
                ctx.shadowBlur = 0;
            }
            else if (this.type === 'meteors') {
                const grad = ctx.createLinearGradient(this.x, this.y, this.x - this.speedX*3, this.y - this.speedY*3);
                grad.addColorStop(0, this.color);
                grad.addColorStop(1, 'transparent');
                ctx.moveTo(this.x, this.y);
                ctx.lineTo(this.x - this.speedX*3, this.y - this.speedY*3);
                ctx.strokeStyle = grad;
                ctx.lineWidth = this.size;
                ctx.lineCap = 'round';
                ctx.stroke();

                ctx.beginPath();
                ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
                ctx.fillStyle = '#ffffff';
                ctx.shadowBlur = 15;
                ctx.shadowColor = this.color;
                ctx.fill();
                ctx.shadowBlur = 0;
            }
            else if (this.type === 'lightning') {
                if (this.life > 0 && this.points.length > 0) {
                    ctx.moveTo(this.points[0].x, this.points[0].y);
                    for (let i = 1; i < this.points.length; i++) {
                        ctx.lineTo(this.points[i].x, this.points[i].y);
                    }
                    ctx.strokeStyle = '#e0f7fa';
                    ctx.lineWidth = (Math.random() * 3 + 1) * sizeMult;
                    ctx.shadowBlur = 20;
                    ctx.shadowColor = '#00e5ff';
                    ctx.globalAlpha = Math.max(0, this.life);
                    ctx.stroke();
                    ctx.globalAlpha = 1;
                    ctx.shadowBlur = 0;
                }
            }
            else if (this.type === 'birds') {
                const wingY = Math.sin(this.flapPhase) * this.size;
                ctx.moveTo(this.x - this.size, this.y - wingY);
                ctx.quadraticCurveTo(this.x, this.y, this.x + this.size, this.y - wingY);
                ctx.strokeStyle = '#111';
                ctx.lineWidth = 2 * sizeMult;
                ctx.lineCap = 'round';
                ctx.stroke();
            }
            else if (this.type === 'lasers') {
                ctx.moveTo(this.x, this.y);
                const dirX = this.speedX > 0 ? -1 : 1;
                ctx.lineTo(this.x + dirX * this.length, this.y - this.speedY*2);
                ctx.strokeStyle = this.color;
                ctx.lineWidth = this.size;
                ctx.lineCap = 'round';
                ctx.shadowBlur = 15;
                ctx.shadowColor = this.color;
                ctx.stroke();
                ctx.shadowBlur = 0;
            }
            else if (this.type === 'matrix') {
                ctx.font = `${this.size}px monospace`;
                ctx.fillStyle = `rgba(0, 255, 65, ${Math.max(0.2, this.life)})`;
                ctx.shadowBlur = 5;
                ctx.shadowColor = '#00ff41';
                ctx.fillText(this.char, this.x, this.y);
                ctx.shadowBlur = 0;
            }
        }
    }

    function initParticles() {
        particles = [];
        if (currentEffect === 'none' || currentEffect === 'glitch' || currentEffect === 'vibrate') return;

        let count = 0;
        if (currentEffect === 'space') count = 200;
        else if (currentEffect === 'warp') count = 350;
        else if (currentEffect === 'rain') count = 400;
        else if (currentEffect === 'snow') count = 250;
        else if (currentEffect === 'smoke') count = 50;
        else if (currentEffect === 'fire') count = 150;
        else if (currentEffect === 'wind') count = 30;
        else if (currentEffect === 'lights') count = 40;
        else if (currentEffect === 'fairydust') count = 100;
        else if (currentEffect === 'fireflies') count = 60;
        else if (currentEffect === 'meteors') count = 15;
        else if (currentEffect === 'lightning') count = 3;
        else if (currentEffect === 'birds') count = 15;
        else if (currentEffect === 'lasers') count = 25;
        else if (currentEffect === 'matrix') count = 100;

        for (let i = 0; i < count; i++) {
            particles.push(new Particle(currentEffect));
        }
    }

    function animate() {
        ctx.clearRect(0, 0, canvas.width, canvas.height);

        const dragType = document.getElementById('vfx-drag-effect').value;
        const effectLayer = document.getElementById('vfx-effect-layer').value;

        // Ajusta camada Z do canvas conforme 'behind_piece' ou 'over_piece'
        canvas.style.zIndex = effectLayer === 'behind_piece' ? '9999' : '100001';

        // Se estiver segurando e a opção 'Manter Efeito Ativo' estiver marcada, continua gerando partículas mesmo parado
        if (isDragging) {
            const keepActiveEl = document.getElementById('vfx-eff-keep-active');
            if (keepActiveEl && keepActiveEl.checked) {
                spawnDragParticle();
            }
        }

        // Função encapsulada para desenhar a imagem da peça
        const drawPieceImage = () => {
            if (dragType === 'image' && isDragging && customImgLoaded && boardEl) {
                const scale = parseFloat(document.getElementById('vfx-img-scale').value);
                const offX = parseFloat(document.getElementById('vfx-img-x').value);
                const offY = parseFloat(document.getElementById('vfx-img-y').value);

                let imgW = customImg.width * scale;
                let imgH = customImg.height * scale;

                let imgX = lastDragMousePos.x + offX - imgW / 2;
                let imgY = lastDragMousePos.y + offY - imgH / 2;

                ctx.drawImage(customImg, imgX, imgY, imgW, imgH);
            }
        };

        // 1. Desenha as partículas globais do tabuleiro
        for (let p of particles) {
            p.update();
            p.draw(ctx);
        }

        // 2. Se a configuração for POR CIMA, desenhamos a imagem
        if (effectLayer === 'over_piece') {
            drawPieceImage();
        }

        // 3. Desenha as partículas do rastro / arrasto
        for (let i = dragParticles.length - 1; i >= 0; i--) {
            let dp = dragParticles[i];
            dp.update();
            dp.draw(ctx);
            if (dp.life <= 0) dragParticles.splice(i, 1);
        }

        // 4. Se a configuração for ATRÁS, desenhamos a imagem
        if (effectLayer === 'behind_piece') {
            drawPieceImage();
        }

        if (currentEffect === 'glitch' && Math.random() < 0.05 * speedMult) {
            ctx.fillStyle = `rgba(${Math.random()*255},${Math.random()*255},${Math.random()*255},0.2)`;
            ctx.fillRect(Math.random()*canvas.width, Math.random()*canvas.height, Math.random()*100, Math.random()*20);
        }

        animationId = requestAnimationFrame(animate);
    }

    setInterval(() => {
        updateCanvasBounds();
        if (currentEffect === 'glitch' || currentEffect === 'vibrate') {
            handleBoardEffects();
        }
    }, 500);

    window.addEventListener('resize', updateCanvasBounds);

    loadSettings();
    initParticles();
    animate();

    // --- INÍCIO DA ADIÇÃO DO MURAL DE IMAGENS ---
    const imageWallHTML = `
        <label style="color: #00e5ff; font-weight: bold; margin-top: 15px;">Mural de Imagens Salvas:</label>
        <div id="vfx-image-wall" style="display: flex; gap: 8px; overflow-x: auto; padding: 10px 5px; margin-bottom: 10px; background: rgba(0,0,0,0.4); border-radius: 6px; border: 1px solid rgba(255,255,255,0.1); min-height: 50px; align-items: center;">
        </div>
        <div style="display: flex; gap: 5px; margin-bottom: 15px;">
            <button id="vfx-clear-wall-btn" type="button" class="vfx-btn-action" style="flex:1; background:#ff4444; color:#fff;">Limpar Imagens Baixadas</button>
        </div>
    `;

    const imgCfgContainer = document.getElementById('vfx-image-cfg');
    imgCfgContainer.insertAdjacentHTML('afterbegin', imageWallHTML);

    // Constante com os links do github (Adicione mais links aqui se precisar)
    const defaultImages = [
        "https://raw.githubusercontent.com/dasfar45/chess-assets-2/main/jetpack.png",
        "https://raw.githubusercontent.com/dasfar45/chess-assets-2/main/asas.png?",
        "https://raw.githubusercontent.com/dasfar45/Assets-VFX/main/Abutre%20Louco.png",
        "https://raw.githubusercontent.com/dasfar45/Assets-VFX/main/Asas%20Atro%C3%A7as.png",
        "https://raw.githubusercontent.com/dasfar45/Assets-VFX/main/Butterfly.png",
        "https://raw.githubusercontent.com/dasfar45/Assets-VFX/main/Joias%20Misticas.png",
        "https://raw.githubusercontent.com/dasfar45/Assets-VFX/main/Mogged.png",
        "https://raw.githubusercontent.com/dasfar45/Assets-VFX/main/Money%2C%20Money%2C%20Money.png",
        "https://raw.githubusercontent.com/dasfar45/Assets-VFX/main/asas%20vermelha.png",
        "https://raw.githubusercontent.com/dasfar45/Assets-VFX/main/jetpack%202.png",
        "https://raw.githubusercontent.com/dasfar45/Assets-VFX/main/Espadas%20Da%20Conspira%C3%A7%C3%A3o.png",
        "https://raw.githubusercontent.com/dasfar45/Assets-VFX/main/Spiral%20Mortif%C3%A9ra.png",
        "https://raw.githubusercontent.com/dasfar45/Assets-VFX/main/capa%20doutor%20estranho.png"
    ];

    // Configurações de fábrica para o Jetpack e Asas
    const defaultWallSettings = {
        'vfx-img-x': "1",
        'vfx-img-y': "15",
        'vfx-img-scale': "0.2",
        'vfx-eff-size': "0.4",
        'vfx-eff-int': "20",
        'vfx-eff-jetpack': true,
        'vfx-eff-fire': false,
        'vfx-eff-smoke': false,
        'vfx-eff-sparkles': false,
        'vfx-eff-trail': false,
        'vfx-eff-snow': false,
        'vfx-eff-fairydust': false,
        'vfx-eff-magiclights': false,
        'vfx-eff-fireflies': false,
        'vfx-eff-dash': true,
        'vfx-eff-keep-active': true,
        'vfx-effect-layer': 'behind_piece'
    };

    let userWallImages = JSON.parse(localStorage.getItem('vfx_user_wall_images')) || [];
    let wallConfigs = JSON.parse(localStorage.getItem('vfx_wall_configs')) || {};
    let currentWallImageId = null;

    // Garante que as configurações de fábrica estejam salvas para as imagens do github
    defaultImages.forEach(src => {
        if (!wallConfigs[src]) {
            wallConfigs[src] = { ...defaultWallSettings };
        }
    });

    const configKeys = Object.keys(defaultWallSettings);

    function renderImageWall() {
        const wall = document.getElementById('vfx-image-wall');
        wall.innerHTML = '';
        const allImages = [...defaultImages.map(src => ({ id: src, src: src, isDefault: true })), ...userWallImages];

        allImages.forEach(imgData => {
            const imgEl = document.createElement('img');
            imgEl.src = imgData.src;
            imgEl.style.width = '45px';
            imgEl.style.height = '45px';
            imgEl.style.objectFit = 'contain';
            imgEl.style.cursor = 'pointer';
            imgEl.style.transition = 'all 0.2s';
            imgEl.style.border = currentWallImageId === imgData.id ? '2px solid #00e5ff' : '2px solid transparent';
            imgEl.style.borderRadius = '6px';
            imgEl.style.background = 'rgba(255,255,255,0.05)';
            imgEl.style.padding = '2px';
            if (currentWallImageId === imgData.id) {
                imgEl.style.boxShadow = '0 0 8px rgba(0,229,255,0.6)';
            }
            imgEl.onclick = () => selectWallImage(imgData.id, imgData.src);
            wall.appendChild(imgEl);
        });
    }

    function applyConfigToUI(id) {
        const conf = wallConfigs[id] || defaultWallSettings;
        configKeys.forEach(key => {
            const el = document.getElementById(key);
            if (el) {
                if (el.type === 'checkbox') {
                    el.checked = conf[key] !== undefined ? conf[key] : defaultWallSettings[key];
                } else {
                    el.value = conf[key] !== undefined ? conf[key] : defaultWallSettings[key];
                }
                el.dispatchEvent(new Event('input')); // Atualiza os sliders na interface
            }
        });
    }

    function selectWallImage(id, src) {
        currentWallImageId = id;
        localStorage.setItem('vfx_last_wall_id', id);

        renderImageWall();

        customImg = new Image();
        customImg.crossOrigin = "Anonymous";
        customImg.onload = () => {
            customImgLoaded = true;
            applyConfigToUI(id);
            renderPreview();
        };
        customImg.onerror = () => {
            customImgLoaded = false;
        };
        customImg.src = src;
    }

    function saveCurrentWallConfig() {
        if (!currentWallImageId) return;
        let conf = {};
        configKeys.forEach(key => {
            const el = document.getElementById(key);
            if (el) {
                conf[key] = el.type === 'checkbox' ? el.checked : el.value;
            }
        });
        wallConfigs[currentWallImageId] = conf;
        localStorage.setItem('vfx_wall_configs', JSON.stringify(wallConfigs));
    }

    // Adiciona listener nos controles para salvar a config da imagem atual em tempo real
    configKeys.forEach(key => {
        const el = document.getElementById(key);
        if (el) {
            el.addEventListener('change', saveCurrentWallConfig);
            el.addEventListener('input', saveCurrentWallConfig);
        }
    });

    // Sobrescreve o input de arquivo clonando para remover o listener antigo que apagava a imagem atual
    const oldFileInput = document.getElementById('vfx-img-file');
    const newFileInput = oldFileInput.cloneNode(true);
    oldFileInput.parentNode.replaceChild(newFileInput, oldFileInput);

    newFileInput.addEventListener('change', (e) => {
        const file = e.target.files[0];
        if (file) {
            const reader = new FileReader();
            reader.onload = (evt) => {
                const src = evt.target.result;
                const id = 'custom_' + Date.now();
                userWallImages.push({ id: id, src: src, isDefault: false });
                localStorage.setItem('vfx_user_wall_images', JSON.stringify(userWallImages));

                // Aplica a config base de fábrica para novas imagens
                wallConfigs[id] = { ...defaultWallSettings };
                localStorage.setItem('vfx_wall_configs', JSON.stringify(wallConfigs));

                selectWallImage(id, src);
            };
            reader.readAsDataURL(file);
        }
    });

    // Botão para limpar imagens salvas pelo usuário
    document.getElementById('vfx-clear-wall-btn').addEventListener('click', () => {
        if(confirm("Deseja remover todas as imagens que você enviou do mural?")) {
            userWallImages = [];
            localStorage.setItem('vfx_user_wall_images', JSON.stringify([]));
            selectWallImage(defaultImages[0], defaultImages[0]);
        }
    });

    // Inicia o Mural carregando a última imagem escolhida ou a primeira do GitHub
    const savedLastId = localStorage.getItem('vfx_last_wall_id');
    if (savedLastId && (defaultImages.includes(savedLastId) || userWallImages.find(i => i.id === savedLastId))) {
        const imgObj = userWallImages.find(i => i.id === savedLastId) || { src: savedLastId };
        selectWallImage(savedLastId, imgObj.src);
    } else {
        selectWallImage(defaultImages[0], defaultImages[0]);
    }
// --- FIM DA ADIÇÃO DO MURAL DE IMAGENS ---

    // =========================================================================
    // --- SISTEMA UNIFICADO DE EFEITOS NO TABULEIRO (VFX BOARD OVERLAY) ---
    // =========================================================================

    // Injeção de Estilos CSS para a lista unificada
    const styleElem = document.createElement('style');
    styleElem.innerHTML = `
        .vfx-eff-row {
            display: flex;
            align-items: center;
            justify-content: space-between;
            padding: 5px 8px;
            margin-bottom: 4px;
            background: rgba(255,255,255,0.05);
            border-radius: 4px;
            border: 1px solid rgba(255,255,255,0.05);
        }
        .vfx-eff-row:hover {
            background: rgba(255,255,255,0.1);
        }
        .vfx-eff-row input[type="color"] {
            width: 26px;
            height: 22px;
            border: none;
            padding: 0;
            background: transparent;
            cursor: pointer;
            border-radius: 3px;
        }
    `;
    document.head.appendChild(styleElem);

    // 1. INJEÇÃO DA INTERFACE UNIFICADA (UI)

    // 1.1 Lista Única de Efeitos Globais na Aba "Gerais"
    const tabGeral = document.getElementById('tab-geral');
    if (tabGeral) {
        tabGeral.insertAdjacentHTML('beforeend', `
            <hr style="border:0; border-top:1px solid rgba(255,255,255,0.1); margin: 12px 0;">
            <label style="font-weight: bold; color: #00e5ff; display: block; margin-bottom: 6px;">Efeitos Globais do Tabuleiro (Ative vários):</label>

            <div id="vfx-global-effects-list" style="max-height: 220px; overflow-y: auto; background: rgba(0,0,0,0.3); padding: 6px; border-radius: 6px; border: 1px solid rgba(255,255,255,0.1); margin-bottom: 10px;">
                <div class="vfx-eff-row"><label class="vfx-checkbox-label" style="margin:0 !important;"><input type="checkbox" class="vfx-effect-enable vfx-save" data-effect="petals"> Pétalas de Cerejeira</label><input type="color" class="vfx-effect-color vfx-save" data-effect="petals" value="#ffb7c5"></div>
                <div class="vfx-eff-row"><label class="vfx-checkbox-label" style="margin:0 !important;"><input type="checkbox" class="vfx-effect-enable vfx-save" data-effect="leaves"> Folhas ao Vento</label><input type="color" class="vfx-effect-color vfx-save" data-effect="leaves" value="#ffaa33"></div>
                <div class="vfx-eff-row"><label class="vfx-checkbox-label" style="margin:0 !important;"><input type="checkbox" class="vfx-effect-enable vfx-save" data-effect="dust"> Poeira ao Vento</label><input type="color" class="vfx-effect-color vfx-save" data-effect="dust" value="#ffe89c"></div>
                <div class="vfx-eff-row"><label class="vfx-checkbox-label" style="margin:0 !important;"><input type="checkbox" class="vfx-effect-enable vfx-save" data-effect="feathers"> Penas ao Vento</label><input type="color" class="vfx-effect-color vfx-save" data-effect="feathers" value="#ffffff"></div>
                <div class="vfx-eff-row"><label class="vfx-checkbox-label" style="margin:0 !important;"><input type="checkbox" class="vfx-effect-enable vfx-save" data-effect="butterflies"> Borboletas</label><input type="color" class="vfx-effect-color vfx-save" data-effect="butterflies" value="#00e5ff"></div>
                <div class="vfx-eff-row"><label class="vfx-checkbox-label" style="margin:0 !important;"><input type="checkbox" class="vfx-effect-enable vfx-save" data-effect="magic_dust"> Poeira Mágica</label><input type="color" class="vfx-effect-color vfx-save" data-effect="magic_dust" value="#e066ff"></div>
                <div class="vfx-eff-row"><label class="vfx-checkbox-label" style="margin:0 !important;"><input type="checkbox" class="vfx-effect-enable vfx-save" data-effect="shooting_stars"> Estrelas Cadentes</label><input type="color" class="vfx-effect-color vfx-save" data-effect="shooting_stars" value="#ffffff"></div>
                <div class="vfx-eff-row"><label class="vfx-checkbox-label" style="margin:0 !important;"><input type="checkbox" class="vfx-effect-enable vfx-save" data-effect="vortex"> Vórtice Mágico</label><input type="color" class="vfx-effect-color vfx-save" data-effect="vortex" value="#00f0ff"></div>
                <div class="vfx-eff-row"><label class="vfx-checkbox-label" style="margin:0 !important;"><input type="checkbox" class="vfx-effect-enable vfx-save" data-effect="constellations"> Constelações</label><input type="color" class="vfx-effect-color vfx-save" data-effect="constellations" value="#77aaff"></div>
                <div class="vfx-eff-row"><label class="vfx-checkbox-label" style="margin:0 !important;"><input type="checkbox" class="vfx-effect-enable vfx-save" data-effect="rainbow"> Arco-Íris em Movimento</label><input type="color" class="vfx-effect-color vfx-save" data-effect="rainbow" value="#ff007f"></div>
                <div class="vfx-eff-row"><label class="vfx-checkbox-label" style="margin:0 !important;"><input type="checkbox" class="vfx-effect-enable vfx-save" data-effect="snow"> Neve</label><input type="color" class="vfx-effect-color vfx-save" data-effect="snow" value="#ffffff"></div>
                <div class="vfx-eff-row"><label class="vfx-checkbox-label" style="margin:0 !important;"><input type="checkbox" class="vfx-effect-enable vfx-save" data-effect="rain"> Chuva</label><input type="color" class="vfx-effect-color vfx-save" data-effect="rain" value="#88ccff"></div>
                <div class="vfx-eff-row"><label class="vfx-checkbox-label" style="margin:0 !important;"><input type="checkbox" class="vfx-effect-enable vfx-save" data-effect="matrix"> Matrix</label><input type="color" class="vfx-effect-color vfx-save" data-effect="matrix" value="#00ff66"></div>
                <div class="vfx-eff-row"><label class="vfx-checkbox-label" style="margin:0 !important;"><input type="checkbox" class="vfx-effect-enable vfx-save" data-effect="stars"> Brilhos / Stardust</label><input type="color" class="vfx-effect-color vfx-save" data-effect="stars" value="#ffffff"></div>
            </div>

            <label>Intensidade Geral dos Efeitos: <span id="vfx-global-intensity-val" style="color:#00e5ff;">1x</span></label>
            <input type="range" id="vfx-global-intensity" class="vfx-save" min="0.1" max="3" step="0.1" value="1">

            <label>Direção do Fluxo:</label>
            <select id="vfx-global-direction" class="vfx-save">
                <option value="default">Padrão</option>
                <option value="horizontal">Horizontal</option>
                <option value="vertical">Vertical</option>
                <option value="diagonal_down">Diagonal Descendente</option>
                <option value="diagonal_up">Diagonal Ascendente</option>
            </select>
        `);
    }

// =========================================================================
    // 1.2 SISTEMA SEGURO E ISOLADO DE GIRAR/TREMER (ANTI-TRAVAMENTO)
    // =========================================================================
    (function sistemaSeguroGirarTremer() {
        const CHAVE_COFRE = '__VFX_GIRAR_TREMER_SALVO__';

        // Valores de fábrica
        const estadoPadrao = {
            'vfx-eff-rotate': false,
            'vfx-rotate-speed': '1',
            'vfx-rotate-int': '100',
            'vfx-eff-shake': false,
            'vfx-shake-speed': '10',
            'vfx-shake-int': '5'
        };

        // Lê o que você salvou no navegador
        function lerCofre() {
            try {
                let dados = localStorage.getItem(CHAVE_COFRE);
                return dados ? { ...estadoPadrao, ...JSON.parse(dados) } : { ...estadoPadrao };
            } catch (e) {
                return { ...estadoPadrao };
            }
        }

        // Salva silenciosamente sempre que você interagir
        function aoInteragir(e) {
            let id = e.target.id;
            if (estadoPadrao[id] !== undefined) {
                let estado = lerCofre();
                estado[id] = e.target.type === 'checkbox' ? e.target.checked : e.target.value;
                try {
                    localStorage.setItem(CHAVE_COFRE, JSON.stringify(estado));
                } catch(err) {}
            }
        }

        // Sistema leve que checa a tela a cada 500ms (Não trava o navegador)
        setInterval(() => {
            let container = document.getElementById('vfx-image-cfg');
            if (!container) return; // Se o menu estiver fechado, não gasta processamento

            let imgCheckGroup = container.querySelector('.vfx-checkbox-group');
            if (!imgCheckGroup) return;

            // 1. Injeta os controles apenas se eles sumirem da tela
            if (!document.getElementById('vfx-eff-rotate')) {
                imgCheckGroup.insertAdjacentHTML('beforeend', `
                    <label class="vfx-checkbox-label" style="margin-top: 4px; color:#00e5ff;">
                        <input type="checkbox" id="vfx-eff-rotate"> Girar Imagem
                    </label>
                    <label class="vfx-checkbox-label" style="color:#ffaa33;">
                        <input type="checkbox" id="vfx-eff-shake"> Tremer Imagem
                    </label>
                `);

                container.insertAdjacentHTML('beforeend', `
                    <div id="vfx-rotate-cfg" class="vfx-sub-config" style="display: none; background: rgba(0,0,0,0.3); padding: 8px; border-radius: 6px; border: 1px solid rgba(255,255,255,0.1); margin-top: 8px;">
                        <label>Velocidade do Giro: <span id="vfx-rotate-speed-val" style="color:#00e5ff;">1x</span></label>
                        <input type="range" id="vfx-rotate-speed" min="0.1" max="5" step="0.1" value="1">
                        <label>Intensidade do Giro: <span id="vfx-rotate-int-val" style="color:#00e5ff;">100%</span></label>
                        <input type="range" id="vfx-rotate-int" min="10" max="300" step="10" value="100">
                    </div>

                    <div id="vfx-shake-cfg" class="vfx-sub-config" style="display: none; background: rgba(0,0,0,0.3); padding: 8px; border-radius: 6px; border: 1px solid rgba(255,255,255,0.1); margin-top: 8px;">
                        <label>Velocidade do Tremer: <span id="vfx-shake-speed-val" style="color:#00e5ff;">10</span></label>
                        <input type="range" id="vfx-shake-speed" min="1" max="30" step="1" value="10">
                        <label>Intensidade do Tremer: <span id="vfx-shake-int-val" style="color:#00e5ff;">5px</span></label>
                        <input type="range" id="vfx-shake-int" min="1" max="25" step="1" value="5">
                    </div>
                `);

                // Conecta a função de salvar no exato momento que você mexe
                Object.keys(estadoPadrao).forEach(id => {
                    let el = document.getElementById(id);
                    if (el) {
                        el.addEventListener('change', aoInteragir);
                        el.addEventListener('input', aoInteragir);
                    }
                });
            }

            // 2. Mantém a tela com os valores que você salvou (Só muda se for diferente, evitando travamentos)
            let salvos = lerCofre();

            ['vfx-eff-rotate', 'vfx-eff-shake'].forEach(id => {
                let el = document.getElementById(id);
                if (el && el.checked !== Boolean(salvos[id])) {
                    el.checked = Boolean(salvos[id]);
                }
            });

            ['vfx-rotate-speed', 'vfx-rotate-int', 'vfx-shake-speed', 'vfx-shake-int'].forEach(id => {
                let el = document.getElementById(id);
                if (el && el.value !== String(salvos[id])) {
                    el.value = String(salvos[id]);
                }
            });

            // 3. Atualiza os painéis visuais
            let rotCfg = document.getElementById('vfx-rotate-cfg');
            let displayRot = salvos['vfx-eff-rotate'] ? 'block' : 'none';
            if (rotCfg && rotCfg.style.display !== displayRot) rotCfg.style.display = displayRot;

            let rotSpeedVal = document.getElementById('vfx-rotate-speed-val');
            let txtRotSpeed = salvos['vfx-rotate-speed'] + 'x';
            if (rotSpeedVal && rotSpeedVal.innerText !== txtRotSpeed) rotSpeedVal.innerText = txtRotSpeed;

            let rotIntVal = document.getElementById('vfx-rotate-int-val');
            let txtRotInt = salvos['vfx-rotate-int'] + '%';
            if (rotIntVal && rotIntVal.innerText !== txtRotInt) rotIntVal.innerText = txtRotInt;

            let shakeCfg = document.getElementById('vfx-shake-cfg');
            let displayShake = salvos['vfx-eff-shake'] ? 'block' : 'none';
            if (shakeCfg && shakeCfg.style.display !== displayShake) shakeCfg.style.display = displayShake;

            let shakeSpeedVal = document.getElementById('vfx-shake-speed-val');
            let txtShakeSpeed = String(salvos['vfx-shake-speed']);
            if (shakeSpeedVal && shakeSpeedVal.innerText !== txtShakeSpeed) shakeSpeedVal.innerText = txtShakeSpeed;

            let shakeIntVal = document.getElementById('vfx-shake-int-val');
            let txtShakeInt = salvos['vfx-shake-int'] + 'px';
            if (shakeIntVal && shakeIntVal.innerText !== txtShakeInt) shakeIntVal.innerText = txtShakeInt;

        }, 500); // 500 milissegundos
    })();
    // 1.3 Iluminação Hover das Casas
    const lightColorInput = document.getElementById('vfx-light-color');
    if (lightColorInput && lightColorInput.parentNode) {
        lightColorInput.insertAdjacentHTML('afterend', `
            <label style="margin-top: 10px;">Modo de Cor da Iluminação:</label>
            <select id="vfx-light-mode" class="vfx-save">
                <option value="solid">Cor Fixa</option>
                <option value="rgb_smooth">RGB Suave (Degradê Completo)</option>
                <option value="rgb_custom">RGB Cores Isoladas/Específicas</option>
            </select>

            <div id="vfx-hover-rgb-cfg" class="vfx-sub-config" style="display: none;">
                <label>Velocidade de Transição do RGB: <span id="vfx-hover-rgb-speed-val" style="color:#00e5ff;">1x</span></label>
                <input type="range" id="vfx-hover-rgb-speed" class="vfx-save" min="0.1" max="5" step="0.1" value="1">

                <div id="vfx-hover-custom-rgb-container" style="display: none; margin-top: 8px;">
                    <label>Cores Isoladas do RGB:</label>
                    <div style="display: flex; gap: 5px; margin-top: 4px;">
                        <input type="color" id="vfx-hover-rgb-c1" class="vfx-save" value="#ff8800">
                        <input type="color" id="vfx-hover-rgb-c2" class="vfx-save" value="#ff0000">
                        <input type="color" id="vfx-hover-rgb-c3" class="vfx-save" value="#8800ff">
                        <input type="color" id="vfx-hover-rgb-c4" class="vfx-save" value="#00e5ff">
                    </div>
                </div>
            </div>
        `);
    }

    // 2. FUNÇÕES AUXILIARES DE CORES E TABULEIRO
    function hexToRgb(hex) {
        if (!hex) return { r: 255, g: 255, b: 255 };
        hex = hex.replace('#', '');
        if (hex.length === 3) hex = hex.split('').map(c => c + c).join('');
        const num = parseInt(hex, 16);
        return { r: (num >> 16) & 255, g: (num >> 8) & 255, b: num & 255 };
    }

    function hslToRgb(h, s, l) {
        l /= 100;
        const a = s * Math.min(l, 1 - l) / 100;
        const f = n => {
            const k = (n + h / 30) % 12;
            const color = l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1);
            return Math.round(255 * color);
        };
        return { r: f(0), g: f(8), b: f(4) };
    }

    function interpolateColors(c1Hex, c2Hex, factor) {
        const rgb1 = hexToRgb(c1Hex);
        const rgb2 = hexToRgb(c2Hex);
        return {
            r: Math.round(rgb1.r + factor * (rgb2.r - rgb1.r)),
            g: Math.round(rgb1.g + factor * (rgb2.g - rgb1.g)),
            b: Math.round(rgb1.b + factor * (rgb2.b - rgb1.b))
        };
    }

    // Retorna dinamicamente os limites do tabuleiro
    function getBoardRect() {
        const boardEl = document.querySelector('chess-board, #board, .board, .cg-wrap, #chessboard, .board-area');
        if (boardEl) {
            return boardEl.getBoundingClientRect();
        }
        const size = Math.min(window.innerWidth, window.innerHeight) * 0.8;
        return {
            left: (window.innerWidth - size) / 2,
            top: (window.innerHeight - size) / 2,
            width: size,
            height: size
        };
    }

    // 3. DESENHO SEGURO DA IMAGEM DO MURAL (GIRAR E TREMER)
    let currentRotationAngle = 0;
    let lastShakeTime = 0;
    let currentShakeOffsetX = 0;
    let currentShakeOffsetY = 0;

    const originalDrawImage = ctx.drawImage;
    ctx.drawImage = function(image, ...args) {
        if (!image) return;

        try {
            const isRotate = document.getElementById('vfx-eff-rotate')?.checked;
            const isShake = document.getElementById('vfx-eff-shake')?.checked;

            if (isRotate || isShake) {
                let dx, dy, dw, dh;

                if (args.length === 2) {
                    dx = args[0]; dy = args[1];
                    dw = image.naturalWidth || image.width || 50;
                    dh = image.naturalHeight || image.height || 50;
                } else if (args.length === 4) {
                    dx = args[0]; dy = args[1]; dw = args[2]; dh = args[3];
                } else if (args.length === 8) {
                    dx = args[4]; dy = args[5]; dw = args[6]; dh = args[7];
                } else {
                    return originalDrawImage.apply(this, [image, ...args]);
                }

                if (isRotate) {
                    const speed = parseFloat(document.getElementById('vfx-rotate-speed')?.value || 1);
                    const intensity = parseFloat(document.getElementById('vfx-rotate-int')?.value || 100) / 100;
                    currentRotationAngle += (0.02 * speed * intensity);
                }

                if (isShake) {
                    const shakeSpeed = parseFloat(document.getElementById('vfx-shake-speed')?.value || 10);
                    const shakeInt = parseFloat(document.getElementById('vfx-shake-int')?.value || 5);
                    const now = Date.now();
                    if (now - lastShakeTime > (1000 / shakeSpeed)) {
                        currentShakeOffsetX = (Math.random() - 0.5) * 2 * shakeInt;
                        currentShakeOffsetY = (Math.random() - 0.5) * 2 * shakeInt;
                        lastShakeTime = now;
                    }
                } else {
                    currentShakeOffsetX = 0;
                    currentShakeOffsetY = 0;
                }

                const centerX = dx + dw / 2 + currentShakeOffsetX;
                const centerY = dy + dh / 2 + currentShakeOffsetY;

                this.save();
                this.translate(centerX, centerY);
                if (isRotate) this.rotate(currentRotationAngle);

                if (args.length === 8) {
                    originalDrawImage.call(this, image, args[0], args[1], args[2], args[3], -dw / 2, -dh / 2, dw, dh);
                } else {
                    originalDrawImage.call(this, image, -dw / 2, -dh / 2, dw, dh);
                }

                this.restore();
                return;
            }
        } catch (e) {}

        return originalDrawImage.apply(this, [image, ...args]);
    };

    // 4. EFEITOS VETORIAIS PUROS (SEM EMOJIS, TOTALMENTE LEVES)
    class BoardParticle {
        constructor(type, rect, color) {
            this.type = type;
            this.color = color || '#ffffff';
            this.dead = false;
            this.time = Math.random() * 100;

            this.x = rect.left + Math.random() * rect.width;
            this.y = rect.top + Math.random() * rect.height;

            if (type === 'snow') {
                this.size = Math.random() * 2.5 + 1.5;
                this.speedY = Math.random() * 1.2 + 0.5;
                this.speedX = Math.random() * 0.4 - 0.2;
            } else if (type === 'rain') {
                this.size = Math.random() * 10 + 6;
                this.speedY = Math.random() * 7 + 6;
                this.speedX = -1;
            } else if (type === 'matrix') {
                this.size = Math.random() * 4 + 10;
                this.speedY = Math.random() * 2.5 + 1.5;
                this.speedX = 0;
                this.char = String.fromCharCode(0x30A0 + Math.floor(Math.random() * 96));
            } else if (type === 'stars') {
                this.size = Math.random() * 2.5 + 1;
                this.speedY = 0;
                this.speedX = 0;
                this.alpha = Math.random();
                this.alphaSpeed = Math.random() * 0.03 + 0.01;
            } else if (type === 'petals') {
                this.size = Math.random() * 5 + 4;
                this.speedY = Math.random() * 1 + 0.5;
                this.speedX = Math.random() * 0.6 - 0.3;
                this.rotation = Math.random() * Math.PI * 2;
                this.rotSpeed = (Math.random() - 0.5) * 0.04;
            } else if (type === 'leaves') {
                this.size = Math.random() * 6 + 5;
                this.speedY = Math.random() * 1.2 + 0.6;
                this.speedX = Math.random() * 1 + 0.2;
                this.rotation = Math.random() * Math.PI * 2;
                this.rotSpeed = (Math.random() - 0.5) * 0.05;
            } else if (type === 'dust') {
                this.size = Math.random() * 2 + 1;
                this.speedY = Math.random() * 0.4 + 0.1;
                this.speedX = Math.random() * 0.6 - 0.3;
            } else if (type === 'feathers') {
                this.size = Math.random() * 8 + 6;
                this.speedY = Math.random() * 0.7 + 0.3;
                this.speedX = 0;
                this.rotation = 0;
            } else if (type === 'butterflies') {
                this.size = Math.random() * 4 + 4;
                this.speedY = Math.random() * 0.6 + 0.2;
                this.speedX = Math.random() * 1 - 0.5;
                this.wingAngle = 0;
            } else if (type === 'magic_dust') {
                this.size = Math.random() * 3 + 2;
                this.speedY = -(Math.random() * 0.8 + 0.2);
                this.speedX = Math.random() * 0.8 - 0.4;
                this.pulse = Math.random() * Math.PI;
            } else if (type === 'shooting_stars') {
                this.x = rect.left + Math.random() * rect.width;
                this.y = rect.top + Math.random() * (rect.height * 0.4);
                this.length = Math.random() * 40 + 20;
                this.speedX = Math.random() * 6 + 4;
                this.speedY = Math.random() * 3 + 2;
            } else if (type === 'vortex') {
                this.angle = Math.random() * Math.PI * 2;
                this.radius = Math.random() * (rect.width * 0.45);
                this.angularSpeed = Math.random() * 0.03 + 0.01;
                this.radialSpeed = Math.random() * 0.3 + 0.1;
                this.size = Math.random() * 2.5 + 1;
            } else if (type === 'constellations') {
                this.size = Math.random() * 2 + 1.5;
                this.speedX = (Math.random() - 0.5) * 0.6;
                this.speedY = (Math.random() - 0.5) * 0.6;
            }
        }

        update(rect, globalDir, globalInt) {
            this.time += 0.05;

            let vx = this.speedX || 0;
            let vy = this.speedY || 0;

            if (this.type === 'vortex') {
                this.angle += this.angularSpeed * globalInt;
                this.radius -= this.radialSpeed * globalInt;
                const centerX = rect.left + rect.width / 2;
                const centerY = rect.top + rect.height / 2;
                this.x = centerX + Math.cos(this.angle) * this.radius;
                this.y = centerY + Math.sin(this.angle) * this.radius;

                if (this.radius <= 5) this.dead = true;
                return;
            }

            if (this.type === 'petals') {
                vx += Math.sin(this.time) * 0.4;
                this.rotation += this.rotSpeed;
            } else if (this.type === 'leaves') {
                vx += Math.sin(this.time * 0.8) * 0.6;
                this.rotation += this.rotSpeed;
            } else if (this.type === 'feathers') {
                vx = Math.sin(this.time * 0.6) * 1.2;
                this.rotation = Math.sin(this.time * 0.6) * 0.3;
            } else if (this.type === 'butterflies') {
                vx += Math.cos(this.time) * 0.6;
                vy += Math.sin(this.time * 1.5) * 0.3;
                this.wingAngle = Math.sin(this.time * 12);
            } else if (this.type === 'magic_dust') {
                this.pulse += 0.05;
            } else if (this.type === 'stars') {
                this.alpha += this.alphaSpeed;
                if (this.alpha > 1 || this.alpha < 0.2) this.alphaSpeed = -this.alphaSpeed;
            }

            if (globalDir === 'horizontal') { vx = Math.abs(vy || 2); vy = 0; }
            else if (globalDir === 'vertical') { vx = 0; vy = Math.abs(vy || 2); }
            else if (globalDir === 'diagonal_down') { vx = Math.abs(vy || 2); vy = Math.abs(vy || 2); }
            else if (globalDir === 'diagonal_up') { vx = Math.abs(vy || 2); vy = -Math.abs(vy || 2); }

            this.x += vx * globalInt;
            this.y += vy * globalInt;

            // Se sair da área do tabuleiro, morre para dar lugar a outra
            if (this.x < rect.left - 20 || this.x > rect.left + rect.width + 20 ||
                this.y < rect.top - 20 || this.y > rect.top + rect.height + 20) {
                this.dead = true;
            }
        }

        draw(ctx) {
            ctx.save();
            const rgb = hexToRgb(this.color);

            if (this.type === 'petals') { // Pétala vetorial
                ctx.translate(this.x, this.y);
                ctx.rotate(this.rotation);
                ctx.fillStyle = `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 0.75)`;
                ctx.beginPath();
                ctx.ellipse(0, 0, this.size, this.size / 2, 0, 0, Math.PI * 2);
                ctx.fill();

            } else if (this.type === 'leaves') { // Folha vetorial
                ctx.translate(this.x, this.y);
                ctx.rotate(this.rotation);
                ctx.fillStyle = `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 0.8)`;
                ctx.beginPath();
                ctx.moveTo(0, -this.size);
                ctx.quadraticCurveTo(this.size, 0, 0, this.size);
                ctx.quadraticCurveTo(-this.size, 0, 0, -this.size);
                ctx.fill();

            } else if (this.type === 'dust') { // Poeira suave
                ctx.fillStyle = `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 0.5)`;
                ctx.beginPath();
                ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
                ctx.fill();

            } else if (this.type === 'feathers') { // Pena vetorial
                ctx.translate(this.x, this.y);
                ctx.rotate(this.rotation);
                ctx.strokeStyle = `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 0.7)`;
                ctx.lineWidth = 1.2;
                ctx.beginPath();
                ctx.moveTo(0, -this.size);
                ctx.quadraticCurveTo(this.size / 2, 0, 0, this.size);
                ctx.stroke();

            } else if (this.type === 'butterflies') { // Borboleta vetorial
                ctx.translate(this.x, this.y);
                ctx.fillStyle = `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 0.85)`;
                const wingScale = Math.abs(this.wingAngle || 1);
                ctx.beginPath();
                ctx.ellipse(-this.size * wingScale, 0, this.size, this.size / 1.5, 0, 0, Math.PI * 2);
                ctx.ellipse(this.size * wingScale, 0, this.size, this.size / 1.5, 0, 0, Math.PI * 2);
                ctx.fill();

            } else if (this.type === 'magic_dust') { // Poeira mágica com brilho
                const pAlpha = 0.3 + Math.sin(this.pulse) * 0.4;
                const grad = ctx.createRadialGradient(this.x, this.y, 0, this.x, this.y, this.size * 2);
                grad.addColorStop(0, `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${pAlpha})`);
                grad.addColorStop(1, 'rgba(0,0,0,0)');
                ctx.fillStyle = grad;
                ctx.beginPath();
                ctx.arc(this.x, this.y, this.size * 2, 0, Math.PI * 2);
                ctx.fill();

            } else if (this.type === 'shooting_stars') { // Estrela cadente
                const grad = ctx.createLinearGradient(this.x, this.y, this.x - this.speedX * 5, this.y - this.speedY * 5);
                grad.addColorStop(0, `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 1)`);
                grad.addColorStop(1, 'rgba(0,0,0,0)');
                ctx.strokeStyle = grad;
                ctx.lineWidth = 2;
                ctx.beginPath();
                ctx.moveTo(this.x, this.y);
                ctx.lineTo(this.x - this.speedX * 5, this.y - this.speedY * 5);
                ctx.stroke();

            } else if (this.type === 'vortex' || this.type === 'snow' || this.type === 'constellations') {
                ctx.fillStyle = `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 0.8)`;
                ctx.beginPath();
                ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
                ctx.fill();

            } else if (this.type === 'rain') {
                ctx.strokeStyle = `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 0.65)`;
                ctx.lineWidth = 1.5;
                ctx.beginPath();
                ctx.moveTo(this.x, this.y);
                ctx.lineTo(this.x - 1, this.y + this.size);
                ctx.stroke();

            } else if (this.type === 'matrix') {
                ctx.fillStyle = `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 0.85)`;
                ctx.font = `${this.size}px monospace`;
                ctx.fillText(this.char, this.x, this.y);

            } else if (this.type === 'stars') {
                ctx.fillStyle = `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${this.alpha || 0.8})`;
                ctx.beginPath();
                ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
                ctx.fill();
            }

            ctx.restore();
        }
    }

    // 5. GERENCIADOR DO CANVAS DO TABULEIRO (RESTRITO AO TABULEIRO)
    let vfxGlobalCanvas = document.getElementById('vfx-global-canvas');
    if (!vfxGlobalCanvas) {
        vfxGlobalCanvas = document.createElement('canvas');
        vfxGlobalCanvas.id = 'vfx-global-canvas';
        vfxGlobalCanvas.style.position = 'fixed';
        vfxGlobalCanvas.style.top = '0';
        vfxGlobalCanvas.style.left = '0';
        vfxGlobalCanvas.style.width = '100vw';
        vfxGlobalCanvas.style.height = '100vh';
        vfxGlobalCanvas.style.pointerEvents = 'none';
        vfxGlobalCanvas.style.zIndex = '9999';
        document.body.appendChild(vfxGlobalCanvas);
    }
    const globalVfxCtx = vfxGlobalCanvas.getContext('2d');

    function resizeGlobalVFXCanvas() {
        if (vfxGlobalCanvas) {
            vfxGlobalCanvas.width = window.innerWidth;
            vfxGlobalCanvas.height = window.innerHeight;
        }
    }
    window.addEventListener('resize', resizeGlobalVFXCanvas);
    resizeGlobalVFXCanvas();

    const globalParticles = [];
    let rainbowAngle = 0;

    function renderGlobalVFXLoop() {
        if (globalVfxCtx && vfxGlobalCanvas) {
            globalVfxCtx.clearRect(0, 0, vfxGlobalCanvas.width, vfxGlobalCanvas.height);

            const rect = getBoardRect();

            // MÁSCARA DE RECORTE: Garante que NADA saia do tabuleiro
            globalVfxCtx.save();
            globalVfxCtx.beginPath();
            globalVfxCtx.rect(rect.left, rect.top, rect.width, rect.height);
            globalVfxCtx.clip();

            const activeEffects = [];
            const effectColors = {};

            document.querySelectorAll('.vfx-effect-enable').forEach(cb => {
                if (cb.checked) {
                    const eff = cb.getAttribute('data-effect');
                    activeEffects.push(eff);
                    const colorInput = document.querySelector(`.vfx-effect-color[data-effect="${eff}"]`);
                    effectColors[eff] = colorInput ? colorInput.value : '#ffffff';
                }
            });

            // Efeito Especial: Arco-Íris em Movimento (Desenho de fundo no tabuleiro)
            if (activeEffects.includes('rainbow')) {
                rainbowAngle += 0.005;
                const rColor = hexToRgb(effectColors['rainbow'] || '#ff007f');
                const grad = globalVfxCtx.createLinearGradient(
                    rect.left + Math.cos(rainbowAngle) * rect.width,
                    rect.top + Math.sin(rainbowAngle) * rect.height,
                    rect.left + rect.width,
                    rect.top + rect.height
                );
                grad.addColorStop(0, `rgba(${rColor.r}, ${rColor.g}, ${rColor.b}, 0.15)`);
                grad.addColorStop(0.5, 'rgba(0, 229, 255, 0.15)');
                grad.addColorStop(1, 'rgba(255, 230, 0, 0.15)');
                globalVfxCtx.fillStyle = grad;
                globalVfxCtx.fillRect(rect.left, rect.top, rect.width, rect.height);
            }

            // Limpa partículas inativas
            for (let i = globalParticles.length - 1; i >= 0; i--) {
                if (!activeEffects.includes(globalParticles[i].type)) {
                    globalParticles.splice(i, 1);
                }
            }

            // Criação de novas partículas
            activeEffects.forEach(eff => {
                if (eff === 'rainbow') return;
                const count = globalParticles.filter(p => p.type === eff).length;
                const limit = (eff === 'dust' || eff === 'snow' || eff === 'rain') ? 40 : 20;

                if (count < limit) {
                    globalParticles.push(new BoardParticle(eff, rect, effectColors[eff]));
                }
            });

            const globalDir = document.getElementById('vfx-global-direction')?.value || 'default';
            const globalInt = parseFloat(document.getElementById('vfx-global-intensity')?.value || 1);

            // Efeito Especial: Constelações (Linhas ligando os pontos próximos)
            if (activeEffects.includes('constellations')) {
                const constParticles = globalParticles.filter(p => p.type === 'constellations');
                const cColor = hexToRgb(effectColors['constellations'] || '#77aaff');
                for (let i = 0; i < constParticles.length; i++) {
                    for (let j = i + 1; j < constParticles.length; j++) {
                        const dist = Math.hypot(constParticles[i].x - constParticles[j].x, constParticles[i].y - constParticles[j].y);
                        if (dist < 75) {
                            globalVfxCtx.strokeStyle = `rgba(${cColor.r}, ${cColor.g}, ${cColor.b}, ${1 - dist / 75})`;
                            globalVfxCtx.lineWidth = 0.8;
                            globalVfxCtx.beginPath();
                            globalVfxCtx.moveTo(constParticles[i].x, constParticles[i].y);
                            globalVfxCtx.lineTo(constParticles[j].x, constParticles[j].y);
                            globalVfxCtx.stroke();
                        }
                    }
                }
            }

            // Atualiza e Desenha cada partícula
            for (let i = globalParticles.length - 1; i >= 0; i--) {
                const p = globalParticles[i];
                p.color = effectColors[p.type] || p.color;
                p.update(rect, globalDir, globalInt);
                p.draw(globalVfxCtx);

                if (p.dead) {
                    globalParticles.splice(i, 1);
                }
            }

            globalVfxCtx.restore(); // Fecha o recorte da máscara do tabuleiro
        }
        requestAnimationFrame(renderGlobalVFXLoop);
    }
    requestAnimationFrame(renderGlobalVFXLoop);

    // 6. ILUMINAÇÃO HOVER DAS CASAS
    function updateRGBHoverLight() {
        if (!hoverLightEl) return;
        const toggle = document.getElementById('vfx-hover-toggle')?.value;
        if (toggle === 'off') {
            hoverLightEl.style.display = 'none';
            return;
        }
        hoverLightEl.style.display = 'block';

        const mode = document.getElementById('vfx-light-mode')?.value || 'solid';
        const speed = parseFloat(document.getElementById('vfx-hover-rgb-speed')?.value || 1);
        const intensity = parseFloat(document.getElementById('vfx-light-intensity')?.value || 0.5);
        const bleed = parseFloat(document.getElementById('vfx-light-bleed')?.value || 25);

        let rgb = { r: 0, g: 229, b: 255 };

        if (mode === 'solid') {
            const colorHex = document.getElementById('vfx-light-color')?.value || '#00e5ff';
            rgb = hexToRgb(colorHex);
        } else if (mode === 'rgb_smooth') {
            const hue = (Date.now() * 0.05 * speed) % 360;
            rgb = hslToRgb(hue, 100, 50);
        } else if (mode === 'rgb_custom') {
            const c1 = document.getElementById('vfx-hover-rgb-c1')?.value || '#ff8800';
            const c2 = document.getElementById('vfx-hover-rgb-c2')?.value || '#ff0000';
            const c3 = document.getElementById('vfx-hover-rgb-c3')?.value || '#8800ff';
            const c4 = document.getElementById('vfx-hover-rgb-c4')?.value || '#00e5ff';
            const colors = [c1, c2, c3, c4];

            const N = colors.length;
            const totalProgress = (Date.now() * 0.001 * speed) % N;
            const i = Math.floor(totalProgress);
            const j = (i + 1) % N;
            const factor = totalProgress - i;

            rgb = interpolateColors(colors[i], colors[j], factor);
        }

        hoverLightEl.style.backgroundColor = `rgba(${rgb.r},${rgb.g},${rgb.b},${intensity})`;
        if (bleed > 0) {
            hoverLightEl.style.boxShadow = `0 0 ${bleed}px ${bleed / 2}px rgba(${rgb.r},${rgb.g},${rgb.b}, ${Math.min(1, intensity * 1.5)})`;
        } else {
            hoverLightEl.style.boxShadow = 'none';
        }
    }

    setInterval(() => {
        const mode = document.getElementById('vfx-light-mode')?.value;
        if (mode === 'rgb_smooth' || mode === 'rgb_custom') {
            updateRGBHoverLight();
        }
    }, 16);

    // 7. ATUALIZAÇÃO E SALVAMENTO AUTOMÁTICO
    function updateUIElementsVisibility() {
        const rotateChecked = document.getElementById('vfx-eff-rotate')?.checked;
        const rotateCfg = document.getElementById('vfx-rotate-cfg');
        if (rotateCfg) rotateCfg.style.display = rotateChecked ? 'block' : 'none';

        const shakeChecked = document.getElementById('vfx-eff-shake')?.checked;
        const shakeCfg = document.getElementById('vfx-shake-cfg');
        if (shakeCfg) shakeCfg.style.display = shakeChecked ? 'block' : 'none';

        const lightMode = document.getElementById('vfx-light-mode')?.value || 'solid';
        const hoverRgbCfg = document.getElementById('vfx-hover-rgb-cfg');
        const customRgbContainer = document.getElementById('vfx-hover-custom-rgb-container');

        if (hoverRgbCfg) hoverRgbCfg.style.display = (lightMode === 'solid') ? 'none' : 'block';
        if (customRgbContainer) customRgbContainer.style.display = (lightMode === 'rgb_custom') ? 'block' : 'none';

        const gInt = document.getElementById('vfx-global-intensity');
        if (gInt) document.getElementById('vfx-global-intensity-val').innerText = gInt.value + 'x';

        const rSpeed = document.getElementById('vfx-rotate-speed');
        if (rSpeed) document.getElementById('vfx-rotate-speed-val').innerText = rSpeed.value + 'x';

        const rInt = document.getElementById('vfx-rotate-int');
        if (rInt) document.getElementById('vfx-rotate-int-val').innerText = rInt.value + '%';

        const sSpeed = document.getElementById('vfx-shake-speed');
        if (sSpeed) document.getElementById('vfx-shake-speed-val').innerText = sSpeed.value;

        const sInt = document.getElementById('vfx-shake-int');
        if (sInt) document.getElementById('vfx-shake-int-val').innerText = sInt.value + 'px';

        const rgbSpeed = document.getElementById('vfx-hover-rgb-speed');
        if (rgbSpeed) document.getElementById('vfx-hover-rgb-speed-val').innerText = rgbSpeed.value + 'x';

        updateRGBHoverLight();
    }

    document.querySelectorAll('#vfx-panel .vfx-save').forEach(el => {
        el.addEventListener('input', () => {
            updateUIElementsVisibility();
            if (typeof saveSettings === 'function') saveSettings();
        });
        el.addEventListener('change', () => {
            updateUIElementsVisibility();
            if (typeof saveSettings === 'function') saveSettings();
        });
    });

    if (typeof loadSettings === 'function') {
        loadSettings();
    }
    updateUIElementsVisibility();

// =========================================================================
// --- FIM DAS ATUALIZAÇÕES DOS EFEITOS GERAIS ---
// =========================================================================

        // --- 7. LÓGICA INTERNA: APLICAR COR NO GLITCH/BUGADO ---
        function aplicarCorGlitch(cor, intensidade) {
            try {
                const elementosGlitch = document.querySelectorAll('.vfx-glitch-active, .glitch-effect, #vfx-glitch-layer, [data-vfx="glitch"]');
                if (!elementosGlitch || elementosGlitch.length === 0) return;

                const corFinal = cor || (typeof salvos !== 'undefined' && salvos['vfx-glitch-color']) || '#ff0055';
                const rotInt = intensidade !== undefined ? intensidade : ((typeof salvos !== 'undefined' && salvos['vfx-rotate-int']) || 0);

                elementosGlitch.forEach(el => {
                    el.style.setProperty('--glitch-color', corFinal);
                    el.style.filter = `hue-rotate(${rotInt}deg) drop-shadow(0 0 5px ${corFinal})`;
                });
            } catch (err) {
                console.error("Erro ao aplicar cor no glitch:", err);
            }
        }

        // Loop de verificação e atualização contínua dos efeitos visuais e do glitch
        setInterval(function() {
            try {
                aplicarCorGlitch();

                if (typeof salvos !== 'undefined') {
                    const rotIntVal = document.getElementById('vfx-rotate-int-val');
                    let txtRotInt = (salvos['vfx-rotate-int'] || 0) + '%';
                    if (rotIntVal && rotIntVal.innerText !== txtRotInt) {
                        rotIntVal.innerText = txtRotInt;
                    }
                }
            } catch (e) {}
        }, 500);

    // =========================================================================
    // --- SISTEMA DE PERSISTÊNCIA E FORÇAMENTO DO MURAL DE IMAGENS em 2º PLANO ---
    // =========================================================================
    (function sistemaPersistenciaMural() {
        const CHAVE_ULTIMA_IMG_ID = 'vfx_last_wall_id';
        const CHAVE_ULTIMA_IMG_SRC = 'vfx_last_wall_src';

        // Salva forçadamente no localStorage todos os identificadores da imagem selecionada
        function forcarSalvarImagemMural(id, src) {
            if (!id || !src) return;
            try {
                localStorage.setItem(CHAVE_ULTIMA_IMG_ID, id);
                localStorage.setItem(CHAVE_ULTIMA_IMG_SRC, src);
                localStorage.setItem('vfx_custom_img_data', src);
            } catch (err) {}
        }

        // Sobrescreve a função original de seleção do mural garantindo o salvamento forçado
        if (typeof selectWallImage === 'function') {
            const selectWallImageOriginal = selectWallImage;
            selectWallImage = function(id, src) {
                forcarSalvarImagemMural(id, src);
                selectWallImageOriginal(id, src);
            };
        }

        // Escuta cliques diretos no mural de imagens para garantir salvamento imediato
        document.addEventListener('click', function(e) {
            const imgWall = e.target.closest('#vfx-image-wall img');
            if (imgWall && imgWall.src) {
                const idSalvo = imgWall.getAttribute('data-id') || localStorage.getItem(CHAVE_ULTIMA_IMG_ID) || imgWall.src;
                forcarSalvarImagemMural(idSalvo, imgWall.src);
            }
        }, true);

        // Sistema de restauração em segundo plano (força a restruturação após F5)
        function restaurarImagemForcada() {
            const savedId = localStorage.getItem(CHAVE_ULTIMA_IMG_ID);
            const savedSrc = localStorage.getItem(CHAVE_ULTIMA_IMG_SRC) || localStorage.getItem('vfx_custom_img_data');

            if (savedId && savedSrc) {
                if (typeof currentWallImageId !== 'undefined') {
                    currentWallImageId = savedId;
                }
                if (typeof customImg !== 'undefined') {
                    if (!customImg.src || customImg.src !== savedSrc) {
                        customImg = new Image();
                        customImg.crossOrigin = "Anonymous";
                        customImg.onload = () => {
                            if (typeof customImgLoaded !== 'undefined') customImgLoaded = true;
                            if (typeof applyConfigToUI === 'function') applyConfigToUI(savedId);
                            if (typeof renderPreview === 'function') renderPreview();
                            if (typeof renderImageWall === 'function') renderImageWall();
                        };
                        customImg.src = savedSrc;
                    }
                }
            }
        }

        // Executa imediatamente no carregamento e mantém um ciclo leve de verificação
        setTimeout(restaurarImagemForcada, 100);
        setTimeout(restaurarImagemForcada, 500);
        setInterval(restaurarImagemForcada, 2000);
    })();

        // --- 3. QUANTIDADE E COR NO 'EFEITO GLOBAL' (PRIMEIRA LISTA) ---
        const vfxSizeInput = document.getElementById('vfx-size');
        if (vfxSizeInput && !document.getElementById('vfx-global-qty')) {
            vfxSizeInput.insertAdjacentHTML('afterend', `
                <label style="margin-top: 10px;">Quantidade do Efeito: <span id="vfx-global-qty-val" style="color:#00e5ff;">1x</span></label>
                <input type="range" id="vfx-global-qty" class="vfx-save" min="0.1" max="5" step="0.1" value="1">

                <label style="margin-top: 10px;">Cor do Efeito (Lasers, Glitch, etc):</label>
                <div style="display: flex; gap: 5px; align-items: center; margin-top: 5px;">
                    <input type="color" id="vfx-global-color" class="vfx-save" value="#ff0000" style="width: 40px; height: 30px; cursor: pointer;">
                    <label class="vfx-checkbox-label" style="margin:0 !important; cursor: pointer;">
                        <input type="checkbox" id="vfx-use-global-color" class="vfx-save"> Ativar Cor Especial
                    </label>
                </div>
            `);

            document.getElementById('vfx-global-qty').addEventListener('input', (e) => {
                document.getElementById('vfx-global-qty-val').innerText = e.target.value + 'x';
                if (typeof initParticles === 'function') initParticles();
                if (typeof saveSettings === 'function') saveSettings();
            });

            document.getElementById('vfx-global-color').addEventListener('input', () => {
                if (typeof initParticles === 'function') initParticles();
                if (typeof handleBoardEffects === 'function') handleBoardEffects();
                if (typeof saveSettings === 'function') saveSettings();
            });

            document.getElementById('vfx-use-global-color').addEventListener('change', () => {
                if (typeof initParticles === 'function') initParticles();
                if (typeof handleBoardEffects === 'function') handleBoardEffects();
                if (typeof saveSettings === 'function') saveSettings();
            });
        }

        // --- 4. TAMANHO E QUANTIDADE EM 'EFEITOS GLOBAIS DO TABULEIRO (ATIVE VÁRIOS)' ---
        const globalDirSelect = document.getElementById('vfx-global-direction');
        if (globalDirSelect && !document.getElementById('vfx-multi-size')) {
            globalDirSelect.insertAdjacentHTML('afterend', `
                <hr style="border:0; border-top:1px solid rgba(255,255,255,0.1); margin: 12px 0;">
                <label>Tamanho dos Efeitos (Ative Vários): <span id="vfx-multi-size-val" style="color:#00e5ff;">1x</span></label>
                <input type="range" id="vfx-multi-size" class="vfx-save" min="0.1" max="5" step="0.1" value="1">

                <label style="margin-top: 10px;">Quantidade dos Efeitos (Ative Vários): <span id="vfx-multi-qty-val" style="color:#00e5ff;">1x</span></label>
                <input type="range" id="vfx-multi-qty" class="vfx-save" min="0.1" max="5" step="0.1" value="1">
            `);

            document.getElementById('vfx-multi-size').addEventListener('input', (e) => {
                document.getElementById('vfx-multi-size-val').innerText = e.target.value + 'x';
                if (typeof saveSettings === 'function') saveSettings();
            });
            document.getElementById('vfx-multi-qty').addEventListener('input', (e) => {
                document.getElementById('vfx-multi-qty-val').innerText = e.target.value + 'x';
                if (typeof saveSettings === 'function') saveSettings();
            });
        }

        // Restaura valores específicos criados pela nova injeção
        if (typeof loadSettings === 'function') {
            const saved = localStorage.getItem('vfx_chess_pro_settings');
            if (saved) {
                try {
                    const settings = JSON.parse(saved);
                    ['vfx-global-qty', 'vfx-global-color', 'vfx-use-global-color', 'vfx-multi-size', 'vfx-multi-qty'].forEach(id => {
                        const el = document.getElementById(id);
                        if (el && settings[id] !== undefined) {
                            if (el.type === 'checkbox') el.checked = settings[id];
                            else el.value = settings[id];
                            el.dispatchEvent(new Event('input'));
                        }
                    });
                } catch(e) {}
            }
        }

        // --- 5. LÓGICA INTERNA: APLICAR QUANTIDADE NA initParticles ---
        if (typeof initParticles === 'function') {
            const oldInit = initParticles;
            initParticles = function() {
                oldInit();
                const qtyEl = document.getElementById('vfx-global-qty');
                const qtyMult = qtyEl ? parseFloat(qtyEl.value) : 1;

                if (typeof particles !== 'undefined' && particles && particles.length > 0 && qtyMult !== 1) {
                    const baseCount = particles.length;
                    const newCount = Math.floor(baseCount * qtyMult);

                    if (newCount > baseCount) {
                        const type = particles[0].type;
                        for (let i = 0; i < (newCount - baseCount); i++) {
                            if (typeof Particle !== 'undefined') particles.push(new Particle(type));
                        }
                    } else if (newCount < baseCount) {
                        particles.splice(newCount);
                    }
                }
            };
            initParticles();
        }

        // --- 6. LÓGICA INTERNA: APLICAR COR EM PARTÍCULAS (LASERS, ETC) ---
        if (typeof Particle !== 'undefined' && Particle.prototype.reset) {
            if (!Particle.prototype._originalReset) {
                Particle.prototype._originalReset = Particle.prototype.reset;
                Particle.prototype.reset = function(initial) {
                    this._originalReset(initial);

                    const useColorEl = document.getElementById('vfx-use-global-color');
                    const colorEl = document.getElementById('vfx-global-color');

                    if (useColorEl && useColorEl.checked && colorEl) {
                        this.color = colorEl.value;
                        if (this.type === 'fire') {
                            this.baseColor = colorEl.value;
                        }
                    }
                };
            }
        }

// --- 7. LÓGICA INTERNA: APLICAR COR NO GLITCH/BUGADO ---
        function aplicarCorGlitch(cor, intensidade) {
            try {
                const elementosGlitch = document.querySelectorAll('.vfx-glitch-active, .glitch-effect, #vfx-glitch-layer, [data-vfx="glitch"]');
                if (!elementosGlitch || elementosGlitch.length === 0) return;

                const corFinal = cor || (typeof salvos !== 'undefined' && salvos['vfx-glitch-color']) || '#ff0055';
                const rotInt = intensidade !== undefined ? intensidade : ((typeof salvos !== 'undefined' && salvos['vfx-rotate-int']) || 0);

                elementosGlitch.forEach(el => {
                    el.style.setProperty('--glitch-color', corFinal);
                    el.style.filter = `hue-rotate(${rotInt}deg) drop-shadow(0 0 5px ${corFinal})`;
                });
            } catch (err) {
                console.error("Erro ao aplicar cor no glitch:", err);
            }
        }

        // Loop de verificação e atualização contínua dos efeitos visuais e do glitch
        setInterval(function() {
            try {
                aplicarCorGlitch();

                if (typeof salvos !== 'undefined') {
                    const rotIntVal = document.getElementById('vfx-rotate-int-val');
                    const txtRotInt = (salvos['vfx-rotate-int'] || 0) + '%';
                    if (rotIntVal && rotIntVal.innerText !== txtRotInt) {
                        rotIntVal.innerText = txtRotInt;
                    }
                }
            } catch (e) {}
        }, 500);

    // =========================================================================
    // --- SISTEMA DE PERSISTÊNCIA E FORÇAMENTO DO MURAL DE IMAGENS em 2º PLANO ---
    // =========================================================================
    (function sistemaPersistenciaMural() {
        const CHAVE_ULTIMA_IMG_ID = 'vfx_last_wall_id';
        const CHAVE_ULTIMA_IMG_SRC = 'vfx_last_wall_src';

        // Salva forçadamente no localStorage todos os identificadores da imagem selecionada
        function forcarSalvarImagemMural(id, src) {
            if (!id || !src) return;
            try {
                localStorage.setItem(CHAVE_ULTIMA_IMG_ID, id);
                localStorage.setItem(CHAVE_ULTIMA_IMG_SRC, src);
                localStorage.setItem('vfx_custom_img_data', src);
            } catch (err) {}
        }

        // Sobrescreve a função original de seleção do mural garantindo o salvamento forçado
        if (typeof selectWallImage === 'function') {
            const selectWallImageOriginal = selectWallImage;
            selectWallImage = function(id, src) {
                forcarSalvarImagemMural(id, src);
                selectWallImageOriginal(id, src);
            };
        }

        // Escuta cliques diretos no mural de imagens para garantir salvamento imediato
        document.addEventListener('click', function(e) {
            const imgWall = e.target.closest('#vfx-image-wall img');
            if (imgWall && imgWall.src) {
                const idSalvo = localStorage.getItem(CHAVE_ULTIMA_IMG_ID) || imgWall.src;
                forcarSalvarImagemMural(idSalvo, imgWall.src);
            }
        }, true);

        // Sistema de restauração em segundo plano (força a restruturação após F5)
        function restaurarImagemForcada() {
            const savedId = localStorage.getItem(CHAVE_ULTIMA_IMG_ID);
            const savedSrc = localStorage.getItem(CHAVE_ULTIMA_IMG_SRC) || localStorage.getItem('vfx_custom_img_data');

            if (savedId && savedSrc) {
                if (typeof currentWallImageId !== 'undefined') {
                    currentWallImageId = savedId;
                }
                if (typeof customImg !== 'undefined') {
                    if (!customImg.src || customImg.src !== savedSrc) {
                        customImg = new Image();
                        customImg.crossOrigin = "Anonymous";
                        customImg.onload = () => {
                            if (typeof customImgLoaded !== 'undefined') customImgLoaded = true;
                            if (typeof applyConfigToUI === 'function') applyConfigToUI(savedId);
                            if (typeof renderPreview === 'function') renderPreview();
                            if (typeof renderImageWall === 'function') renderImageWall();
                        };
                        customImg.src = savedSrc;
                    }
                }
            }
        }

        // Executa imediatamente no carregamento e mantém um ciclo leve de verificação
        setTimeout(restaurarImagemForcada, 100);
        setTimeout(restaurarImagemForcada, 500);
        setInterval(restaurarImagemForcada, 2000);
    })();
})();