🎯🎨 Chess.com Custom Arrows

✨ Personalize suas setas com controle total sobre cores, gradientes, espessura, opacidade e tamanho da ponta. ♟️🔥

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         🎯🎨 Chess.com Custom Arrows
// @namespace    http://tampermonkey.net/
// @version      7.2
// @description  ✨ Personalize suas setas com controle total sobre cores, gradientes, espessura, opacidade e tamanho da ponta. ♟️🔥
// @author       aerus15
// @match        *://*.chess.com/*
// @grant        none
// @run-at       document-start
// ==/UserScript==

(function() {
    'use strict';

    // ==========================================
    // 1. ESTADO GLOBAL E SALVAMENTO (LOCALSTORAGE)
    // ==========================================
    const savedGrad = localStorage.getItem('vfx-arrow-use-grad');

    const STATE = {
        thickness: parseFloat(localStorage.getItem('vfx-arrow-thick')) || 15,
        useGradient: savedGrad !== null ? savedGrad === 'true' : true,
        color1: localStorage.getItem('vfx-arrow-c1') || '#ff0000',
        color2: localStorage.getItem('vfx-arrow-c2') || '#ffff00',
        color3: localStorage.getItem('vfx-arrow-c3') || '#00ff00',
        solidColor: localStorage.getItem('vfx-arrow-solid') || '#ffaa00',
        opacity: parseFloat(localStorage.getItem('vfx-arrow-opacity')) || 0.8,

        headSize: parseFloat(localStorage.getItem('vfx-arrow-hsize')) || 1.0,
        headWidth: parseFloat(localStorage.getItem('vfx-arrow-hwidth')) || 1.0,
        headLength: parseFloat(localStorage.getItem('vfx-arrow-hlength')) || 1.0,

        drawnShapes: [],
        currentShape: null,
        isDragging: false,
        boardElement: null,
        svgOverlay: null,
        squareSize: 0,
        isFlipped: false
    };

    // ==========================================
    // 2. CSS PARA ANULAR SETAS NATIVAS E BLINDAR CONTAINER
    // ==========================================
    const cssOverride = `
        /* Oculta APENAS caminhos e polígonos das setas nativas (preserva os círculos e quadrados de outras extensões) */
        wc-chess-board .arrows path,
        wc-chess-board .arrows line,
        wc-chess-board .arrows polyline,
        wc-chess-board .arrows polygon,
        [data-cy="arrows"] path,
        [data-cy="arrows"] line,
        [data-cy="arrows"] polyline,
        [data-cy="arrows"] polygon,
        svg.arrows path,
        svg.arrows line,
        svg.arrows polyline,
        svg.arrows polygon {
            display: none !important;
            opacity: 0 !important;
            visibility: hidden !important;
            pointer-events: none !important;
        }

        #vfx-custom-arrows-container {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            pointer-events: none;
            /* Z-index extremo para garantir que fique em cima de TODAS as peças e marcações do outro script */
            z-index: 2147483650 !important;
        }

        #vfx-master-panel {
            position: fixed;
            right: 15px;
            bottom: 55px; /* Movido ~1cm para cima */
            background: rgba(15, 15, 20, 0.95);
            border: 1px solid #00e5ff;
            border-radius: 8px;
            padding: 15px;
            z-index: 2147483647;
            font-family: system-ui, sans-serif;
            color: white;
            box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5), 0 0 15px rgba(0, 229, 255, 0.2);
            backdrop-filter: blur(10px);
            display: flex;
            flex-direction: column;
            gap: 12px;
            width: 320px;
            max-height: 85vh;
            overflow-y: auto;
            transition: transform 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
            transform-origin: bottom right;
        }

        #vfx-master-panel::-webkit-scrollbar { width: 6px; }
        #vfx-master-panel::-webkit-scrollbar-track { background: rgba(0,0,0,0.2); }
        #vfx-master-panel::-webkit-scrollbar-thumb { background: #00e5ff; border-radius: 3px; }

        #vfx-master-panel.minimized {
            transform: scale(0);
            pointer-events: none;
        }

        #vfx-close-btn {
            position: absolute;
            top: 10px;
            right: 12px;
            color: #ff4444;
            font-size: 16px;
            font-weight: bold;
            cursor: pointer;
            user-select: none;
            line-height: 1;
            transition: 0.2s;
        }
        #vfx-close-btn:hover {
            color: #ff0000;
            transform: scale(1.2);
        }

        .vfx-row {
            display: flex;
            justify-content: space-between;
            align-items: center;
        }
        .vfx-label {
            font-size: 11px;
            font-weight: 600;
            text-transform: uppercase;
            letter-spacing: 0.5px;
            color: #ccc;
            flex: 1;
        }
        .vfx-input {
            background: #222;
            border: 1px solid #444;
            color: white;
            border-radius: 4px;
            padding: 4px;
            outline: none;
        }
        input[type="color"].vfx-input {
            height: 28px;
            width: 40px;
            padding: 0;
            cursor: pointer;
        }
        input[type="range"].vfx-slider {
            width: 110px;
            accent-color: #00e5ff;
            cursor: pointer;
            margin-right: 8px;
        }
        .vfx-val-display {
            width: 30px;
            text-align: right;
            font-size: 11px;
            font-weight: bold;
            color: #00e5ff;
            font-family: monospace;
        }
        .vfx-toggle {
            cursor: pointer;
            background: #333;
            border: 1px solid #555;
            padding: 6px 10px;
            border-radius: 4px;
            font-size: 11px;
            font-weight: bold;
            transition: 0.2s;
            text-align: center;
            width: 100%;
            margin-top: 5px;
            user-select: none;
        }
        .vfx-toggle.active {
            background: #00e5ff;
            color: #000;
            border-color: #00e5ff;
        }
        .vfx-divider {
            height: 1px;
            background: rgba(255,255,255,0.1);
            margin: 5px 0;
        }
        #vfx-floating-btn {
            position: fixed;
            right: 15px;
            bottom: 55px; /* Movido ~1cm para cima */
            width: 45px;
            height: 45px;
            background: #111;
            border: 2px solid #00e5ff;
            border-radius: 50%;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 20px;
            cursor: pointer;
            z-index: 2147483648;
            box-shadow: 0 0 15px rgba(0,229,255,0.4);
            user-select: none;
            transition: all 0.2s ease;
        }
        #vfx-floating-btn:hover {
            transform: scale(1.1);
            background: #222;
        }
    `;

    const styleEl = document.createElement('style');
    styleEl.textContent = cssOverride;
    (document.head || document.documentElement).appendChild(styleEl);

    // ==========================================
    // 3. MATEMÁTICA DO TABULEIRO
    // ==========================================
    const FILES = ['a','b','c','d','e','f','g','h'];

    function getBoardState() {
        if (!STATE.boardElement) return;
        const rect = STATE.boardElement.getBoundingClientRect();
        STATE.squareSize = rect.width / 8;
        STATE.isFlipped = STATE.boardElement.classList.contains('flipped');
    }

    function pointToSquare(x, y) {
        if (!STATE.boardElement || STATE.squareSize === 0) return null;
        let fileIdx = Math.floor(x / STATE.squareSize);
        let rankIdx = Math.floor(y / STATE.squareSize);

        if (fileIdx < 0) fileIdx = 0;
        if (fileIdx > 7) fileIdx = 7;
        if (rankIdx < 0) rankIdx = 0;
        if (rankIdx > 7) rankIdx = 7;

        if (STATE.isFlipped) {
            fileIdx = 7 - fileIdx;
        } else {
            rankIdx = 7 - rankIdx;
        }
        return FILES[fileIdx] + (rankIdx + 1);
    }

    function squareToPoint(sq) {
        if (!STATE.boardElement || STATE.squareSize === 0 || !sq) return {x: 0, y: 0};
        const fileIdx = FILES.indexOf(sq[0]);
        const rankIdx = parseInt(sq[1]) - 1;

        let visualFile, visualRank;

        if (STATE.isFlipped) {
            visualFile = 7 - fileIdx;
            visualRank = rankIdx;
        } else {
            visualFile = fileIdx;
            visualRank = 7 - rankIdx;
        }

        return {
            x: (visualFile + 0.5) * STATE.squareSize,
            y: (visualRank + 0.5) * STATE.squareSize
        };
    }

    // ==========================================
    // 4. MOTOR DE DESENHO (SVG)
    // ==========================================
    function setupSVG() {
        if (!STATE.boardElement) return;

        let container = STATE.boardElement.querySelector('#vfx-custom-arrows-container');
        if (!container) {
            container = document.createElement('div');
            container.id = 'vfx-custom-arrows-container';
            STATE.boardElement.appendChild(container);
        }

        // SVG Container - A opacidade é aplicada DIRETAMENTE AQUI
        container.innerHTML = `
            <svg id="vfx-main-svg" width="100%" height="100%" style="overflow: visible; opacity: ${STATE.opacity};">
                <defs>
                    <linearGradient id="vfx-triple-grad" x1="0%" y1="0%" x2="100%" y2="100%">
                        <stop id="vfx-stop-1" offset="0%" stop-color="${STATE.color1}" />
                        <stop id="vfx-stop-2" offset="50%" stop-color="${STATE.color2}" />
                        <stop id="vfx-stop-3" offset="100%" stop-color="${STATE.color3}" />
                    </linearGradient>
                </defs>
                <g id="vfx-shapes-layer"></g>
            </svg>
        `;
        STATE.svgOverlay = container.querySelector('#vfx-shapes-layer');
    }

    function drawAll() {
        if (!STATE.svgOverlay) return;
        getBoardState();
        STATE.svgOverlay.innerHTML = '';
        STATE.drawnShapes.forEach(shape => renderShape(shape));
    }

    function renderShape(shape) {
        // Ignora cliques simples na mesma casa
        if (shape.start === shape.end) return;

        const p1 = squareToPoint(shape.start);
        const p2 = squareToPoint(shape.end);
        const strokeColor = STATE.useGradient ? 'url(#vfx-triple-grad)' : STATE.solidColor;
        const T = parseFloat(STATE.thickness);

        const file1 = FILES.indexOf(shape.start[0]);
        const rank1 = parseInt(shape.start[1]);
        const file2 = FILES.indexOf(shape.end[0]);
        const rank2 = parseInt(shape.end[1]);

        const dx = Math.abs(file2 - file1);
        const dy = Math.abs(rank2 - rank1);
        const isKnight = (dx === 1 && dy === 2) || (dx === 2 && dy === 1);

        const baseHeadSize = Math.max(15, T * 2.5) * STATE.headSize;
        const headLength = baseHeadSize * STATE.headLength;
        const headWidth = baseHeadSize * STATE.headWidth;

        let pathD = '';
        let arrowAngle = 0;
        let finalP2 = { ...p2 };

        if (isKnight) {
            let cornerSq = (dy > dx) ? (shape.start[0] + shape.end[1]) : (shape.end[0] + shape.start[1]);
            const pc = squareToPoint(cornerSq);

            arrowAngle = Math.atan2(p2.y - pc.y, p2.x - pc.x);

            const retraction = headLength - Math.min(T/2, headLength * 0.2);
            finalP2.x = p2.x - retraction * Math.cos(arrowAngle);
            finalP2.y = p2.y - retraction * Math.sin(arrowAngle);

            pathD = `M ${p1.x} ${p1.y} L ${pc.x} ${pc.y} L ${finalP2.x} ${finalP2.y}`;
        } else {
            arrowAngle = Math.atan2(p2.y - p1.y, p2.x - p1.x);

            const retraction = headLength - Math.min(T/2, headLength * 0.2);
            finalP2.x = p2.x - retraction * Math.cos(arrowAngle);
            finalP2.y = p2.y - retraction * Math.sin(arrowAngle);

            pathD = `M ${p1.x} ${p1.y} L ${finalP2.x} ${finalP2.y}`;
        }

        const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
        path.setAttribute('d', pathD);
        path.setAttribute('class', 'vfx-shaft');

        // BLINDAGEM: Aplicando propriedades inline com !important para vencer o outro script
        path.style.setProperty('fill', 'none', 'important');
        path.style.setProperty('stroke', strokeColor, 'important');
        path.style.setProperty('stroke-width', T + 'px', 'important');
        path.style.setProperty('stroke-linecap', 'round', 'important');
        path.style.setProperty('stroke-linejoin', 'round', 'important');

        const tipX = p2.x;
        const tipY = p2.y;
        const baseX = p2.x - headLength * Math.cos(arrowAngle);
        const baseY = p2.y - headLength * Math.sin(arrowAngle);

        const leftX = baseX - (headWidth/2) * Math.sin(arrowAngle);
        const leftY = baseY + (headWidth/2) * Math.cos(arrowAngle);
        const rightX = baseX + (headWidth/2) * Math.sin(arrowAngle);
        const rightY = baseY - (headWidth/2) * Math.cos(arrowAngle);

        const head = document.createElementNS('http://www.w3.org/2000/svg', 'polygon');
        head.setAttribute('points', `${tipX},${tipY} ${leftX},${leftY} ${rightX},${rightY}`);
        head.setAttribute('class', 'vfx-head');

        // BLINDAGEM PARA A CABEÇA DA SETA
        head.style.setProperty('fill', strokeColor, 'important');
        head.style.setProperty('stroke', strokeColor, 'important');
        head.style.setProperty('stroke-width', (T * 0.1) + 'px', 'important');
        head.style.setProperty('stroke-linejoin', 'round', 'important');

        STATE.svgOverlay.appendChild(path);
        STATE.svgOverlay.appendChild(head);
    }

    // ==========================================
    // 5. EVENTOS (SEM PREVIEW EM TEMPO REAL)
    // ==========================================
    function attachBoardEvents() {
        if (!STATE.boardElement) return;

        STATE.boardElement.addEventListener('contextmenu', e => e.preventDefault(), { capture: true });

        STATE.boardElement.addEventListener('pointerdown', (e) => {
            if (e.button === 2) {
                e.preventDefault();
                getBoardState();
                const rect = STATE.boardElement.getBoundingClientRect();
                const startSq = pointToSquare(e.clientX - rect.left, e.clientY - rect.top);

                if (startSq) {
                    STATE.isDragging = true;
                    STATE.currentShape = { start: startSq, end: startSq };
                }
            } else if (e.button === 0) {
                if (STATE.drawnShapes.length > 0) {
                    STATE.drawnShapes = [];
                    drawAll();
                }
            }
        }, { capture: true });

        window.addEventListener('pointermove', (e) => {
            if (!STATE.isDragging || !STATE.currentShape || !STATE.boardElement) return;

            const rect = STATE.boardElement.getBoundingClientRect();
            const currSq = pointToSquare(e.clientX - rect.left, e.clientY - rect.top);

            if (currSq && currSq !== STATE.currentShape.end) {
                STATE.currentShape.end = currSq;
            }
        }, { capture: true });

        window.addEventListener('pointerup', (e) => {
            if (e.button === 2 && STATE.isDragging) {
                STATE.isDragging = false;

                if (STATE.currentShape && STATE.currentShape.start !== STATE.currentShape.end) {
                    const existsIdx = STATE.drawnShapes.findIndex(
                        s => s.start === STATE.currentShape.start && s.end === STATE.currentShape.end
                    );

                    if (existsIdx > -1) {
                        STATE.drawnShapes.splice(existsIdx, 1);
                    } else {
                        STATE.drawnShapes.push(STATE.currentShape);
                    }
                }
                STATE.currentShape = null;
                drawAll(); // SÓ AGORA DESENHAMOS A SETA
            }
        }, { capture: true });
    }

    // ==========================================
    // 6. UI MASTER COM SAVE E LOAD E BOTÃO FECHAR
    // ==========================================
    function initUI() {
        if (document.getElementById('vfx-master-panel')) return;

        const container = document.createElement('div');
        container.innerHTML = `
            <div id="vfx-floating-btn">🥢</div>
            <div id="vfx-master-panel" class="minimized">
                <div id="vfx-close-btn">✕</div>
                <div style="text-align: center; color: #00e5ff; font-weight: 800; font-size: 14px; margin-bottom: 5px;">VFX ARROWS 7.2</div>

                <div class="vfx-divider"></div>

                <div class="vfx-row">
                    <span class="vfx-label">Espessura</span>
                    <input type="range" id="vfx-thick-slider" class="vfx-slider" min="0.5" max="40" step="0.5" value="${STATE.thickness}">
                    <span id="vfx-thick-val" class="vfx-val-display">${STATE.thickness}</span>
                </div>

                <div class="vfx-row">
                    <span class="vfx-label">Opacidade</span>
                    <input type="range" id="vfx-op-slider" class="vfx-slider" min="0.1" max="1" step="0.05" value="${STATE.opacity}">
                    <span id="vfx-op-val" class="vfx-val-display">${STATE.opacity}</span>
                </div>

                <div class="vfx-divider"></div>
                <div style="font-size: 10px; color: #00e5ff; font-weight: bold; margin-bottom: 5px; text-transform: uppercase;">Cabeça da Seta</div>

                <div class="vfx-row">
                    <span class="vfx-label">Tamanho Global</span>
                    <input type="range" id="vfx-hsize-slider" class="vfx-slider" min="0.2" max="3" step="0.1" value="${STATE.headSize}">
                    <span id="vfx-hsize-val" class="vfx-val-display">${STATE.headSize}</span>
                </div>

                <div class="vfx-row">
                    <span class="vfx-label">Largura (Gorda)</span>
                    <input type="range" id="vfx-hwidth-slider" class="vfx-slider" min="0.2" max="3" step="0.1" value="${STATE.headWidth}">
                    <span id="vfx-hwidth-val" class="vfx-val-display">${STATE.headWidth}</span>
                </div>

                <div class="vfx-row">
                    <span class="vfx-label">Comprimento (Pontuda)</span>
                    <input type="range" id="vfx-hlength-slider" class="vfx-slider" min="0.2" max="3" step="0.1" value="${STATE.headLength}">
                    <span id="vfx-hlength-val" class="vfx-val-display">${STATE.headLength}</span>
                </div>

                <div class="vfx-divider"></div>

                <div id="vfx-mode-btn" class="vfx-toggle ${STATE.useGradient ? 'active' : ''}">${STATE.useGradient ? 'MODO: GRADIENTE' : 'MODO: COR ÚNICA'}</div>

                <div id="vfx-solid-config" class="vfx-row" style="display: ${STATE.useGradient ? 'none' : 'flex'}; margin-top: 10px;">
                    <span class="vfx-label">Cor Principal</span>
                    <input type="color" id="vfx-c-solid" class="vfx-input" value="${STATE.solidColor}">
                </div>

                <div id="vfx-grad-config" style="display: ${STATE.useGradient ? 'flex' : 'none'}; flex-direction: column; gap: 8px; margin-top: 10px;">
                    <div class="vfx-row">
                        <span class="vfx-label">Cor Início</span>
                        <input type="color" id="vfx-c1" class="vfx-input" value="${STATE.color1}">
                    </div>
                    <div class="vfx-row">
                        <span class="vfx-label">Cor Meio</span>
                        <input type="color" id="vfx-c2" class="vfx-input" value="${STATE.color2}">
                    </div>
                    <div class="vfx-row">
                        <span class="vfx-label">Cor Fim</span>
                        <input type="color" id="vfx-c3" class="vfx-input" value="${STATE.color3}">
                    </div>
                </div>
            </div>
        `;
        document.body.appendChild(container);

        const bindSlider = (id, stateKey, storeKey) => {
            const slider = document.getElementById(id);
            const valEl = document.getElementById(id.replace('-slider', '-val'));
            slider.oninput = (e) => {
                STATE[stateKey] = parseFloat(e.target.value);
                valEl.innerText = e.target.value;
                localStorage.setItem(storeKey, e.target.value);

                if (stateKey === 'opacity') {
                    const svgMain = document.getElementById('vfx-main-svg');
                    if (svgMain) svgMain.style.opacity = STATE.opacity;
                } else {
                    drawAll();
                }
            };
        };

        bindSlider('vfx-thick-slider', 'thickness', 'vfx-arrow-thick');
        bindSlider('vfx-op-slider', 'opacity', 'vfx-arrow-opacity');
        bindSlider('vfx-hsize-slider', 'headSize', 'vfx-arrow-hsize');
        bindSlider('vfx-hwidth-slider', 'headWidth', 'vfx-arrow-hwidth');
        bindSlider('vfx-hlength-slider', 'headLength', 'vfx-arrow-hlength');

        const btn = document.getElementById('vfx-floating-btn');
        const panel = document.getElementById('vfx-master-panel');
        const modeBtn = document.getElementById('vfx-mode-btn');
        const solidConf = document.getElementById('vfx-solid-config');
        const gradConf = document.getElementById('vfx-grad-config');
        const closeBtn = document.getElementById('vfx-close-btn');

        let panelOpen = false;

        btn.onclick = () => {
            panelOpen = !panelOpen;
            panel.classList.toggle('minimized', !panelOpen);
            btn.style.transform = panelOpen ? 'rotate(90deg)' : 'rotate(0deg)';
        };

        closeBtn.onclick = () => {
            panelOpen = false;
            panel.classList.add('minimized');
            btn.style.transform = 'rotate(0deg)';
        };

        modeBtn.onclick = () => {
            STATE.useGradient = !STATE.useGradient;
            modeBtn.classList.toggle('active', STATE.useGradient);
            modeBtn.innerText = STATE.useGradient ? 'MODO: GRADIENTE' : 'MODO: COR ÚNICA';
            solidConf.style.display = STATE.useGradient ? 'none' : 'flex';
            gradConf.style.display = STATE.useGradient ? 'flex' : 'none';
            localStorage.setItem('vfx-arrow-use-grad', STATE.useGradient);
            drawAll();
        };

        const updateGradientDef = () => {
            const s1 = document.getElementById('vfx-stop-1');
            const s2 = document.getElementById('vfx-stop-2');
            const s3 = document.getElementById('vfx-stop-3');
            if (s1 && s2 && s3) {
                s1.setAttribute('stop-color', STATE.color1);
                s2.setAttribute('stop-color', STATE.color2);
                s3.setAttribute('stop-color', STATE.color3);
            }
        };

        document.getElementById('vfx-c-solid').oninput = (e) => {
            STATE.solidColor = e.target.value;
            localStorage.setItem('vfx-arrow-solid', STATE.solidColor);
            drawAll();
        };

        ['c1', 'c2', 'c3'].forEach((id, idx) => {
            document.getElementById(`vfx-${id}`).oninput = (e) => {
                STATE[`color${idx+1}`] = e.target.value;
                localStorage.setItem(`vfx-arrow-${id}`, e.target.value);
                updateGradientDef();
            };
        });
    }

    // ==========================================
    // 7. INICIALIZAÇÃO
    // ==========================================
    function initSystem() {
        const board = document.querySelector('wc-chess-board') || document.querySelector('.cg-board');
        if (board && !STATE.boardElement) {
            STATE.boardElement = board;
            setupSVG();
            attachBoardEvents();
            initUI();

            const resizeObserver = new ResizeObserver(() => requestAnimationFrame(drawAll));
            resizeObserver.observe(board);

            const classObserver = new MutationObserver(() => drawAll());
            classObserver.observe(board, { attributes: true, attributeFilter: ['class'] });
        }
    }

    const bootInterval = setInterval(() => {
        initSystem();
        if (STATE.boardElement) clearInterval(bootInterval);
    }, 500);

    document.addEventListener('DOMContentLoaded', initSystem);

})();