TrixBox

TriX Executor's ChatBox (for territorial.io)!

当前为 2025-11-16 提交的版本,查看 最新版本

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         TrixBox
// @namespace    http://tampermonkey.net/
// @version      0.5.5
// @description  TriX Executor's ChatBox (for territorial.io)!
// @author       Painsel
// @match        https://territorial.io/*
// @match        https://fxclient.github.io/FXclient/*
// @grant        GM_xmlhttpRequest
// @grant        GM_info
// ==/UserScript==

(function() {
    'use strict';

    const CHATTABLE_HEADER_HEIGHT = 45; // pixels

    // --- Theme Colors (for UI elements outside the iframe) ---
    const theme = {
        icon: '#2f3136',
        modalBg: '#2f3136',
        text: '#dcddde',
        buttonPrimary: '#5865f2',
        buttonSecondary: '#4f545c'
    };
 
    const SCRIPT_UPDATE_URL = 'https://update.greasyfork.org/scripts/555536/TrixBox.meta.js';
    const SCRIPT_INSTALL_URL = 'https://update.greasyfork.org/scripts/555536/TrixBox.user.js';
 
    // --- 1. UPDATE CHECKING LOGIC ---
 
    const showUpdateModal = () => {
        const modalStyle = `
            .trixbox-modal-overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.8); z-index: 100000; display: flex; align-items: center; justify-content: center; }
            .trixbox-modal-content { background: ${theme.modalBg}; color: ${theme.text}; padding: 25px; border-radius: 10px; text-align: center; font-family: sans-serif; box-shadow: 0 5px 15px rgba(0,0,0,0.5); }
            .trixbox-modal-content h2 { margin-top: 0; }
            .trixbox-modal-content p { margin: 15px 0; }
            .trixbox-modal-btn { color: white; border: none; padding: 10px 20px; border-radius: 5px; cursor: pointer; margin: 0 10px; font-size: 14px; }
            .trixbox-modal-btn.primary { background: ${theme.buttonPrimary}; }
            .trixbox-modal-btn.secondary { background: ${theme.buttonSecondary}; }
        `;
        const styleSheet = document.createElement("style");
        styleSheet.innerText = modalStyle;
        document.head.appendChild(styleSheet);
 
        const modalOverlay = document.createElement('div');
        modalOverlay.className = 'trixbox-modal-overlay';
        modalOverlay.innerHTML = `
            <div class="trixbox-modal-content">
                <h2>OUTDATED VERSION</h2>
                <p>You are using an Outdated version of TrixBox.<br>Please update for the best experience!</p>
                <button id="trixbox-update-btn" class="trixbox-modal-btn primary">Update Now!</button>
                <button id="trixbox-later-btn" class="trixbox-modal-btn secondary">Remind Me Later!</button>
            </div>
        `;
        document.body.appendChild(modalOverlay);
 
        document.getElementById('trixbox-update-btn').onclick = () => { window.location.href = SCRIPT_INSTALL_URL; };
        document.getElementById('trixbox-later-btn').onclick = () => { modalOverlay.remove(); };
    };
 
    const checkForUpdates = () => {
        try {
            const localVersion = GM_info.script.version;
            const lastSeenVersion = localStorage.getItem('trixbox-last-version');
            
            // Show changelog if version has changed
            if (lastSeenVersion !== localVersion) {
                localStorage.setItem('trixbox-last-version', localVersion);
                setTimeout(showChangelog, 500);
            }
            
            GM_xmlhttpRequest({
                method: 'GET',
                url: SCRIPT_UPDATE_URL,
                onload: function(response) {
                    if (response.status !== 200) return;
                    const remoteVersionMatch = response.responseText.match(/@version\s+([0-9.]+)/);
                    if (remoteVersionMatch && remoteVersionMatch[1]) {
                        if (remoteVersionMatch[1] > localVersion) {
                            showUpdateModal();
                        }
                    }
                }
            });
        } catch (e) { console.error('TrixBox: Update check failed.', e); }
    };

    const showChangelog = () => {
        const modalStyle = `
            .trixbox-changelog-overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.8); z-index: 100002; display: flex; align-items: center; justify-content: center; }
            .trixbox-changelog-content { background: ${theme.modalBg}; color: ${theme.text}; padding: 25px; border-radius: 10px; font-family: sans-serif; box-shadow: 0 5px 15px rgba(0,0,0,0.5); width: 400px; max-height: 70vh; overflow-y: auto; }
            .trixbox-changelog-content h2 { margin-top: 0; text-align: center; color: ${theme.buttonPrimary}; }
            .trixbox-changelog-section { margin: 15px 0; }
            .trixbox-changelog-version { font-weight: bold; color: ${theme.buttonPrimary}; margin-bottom: 8px; }
            .trixbox-changelog-list { list-style: none; padding-left: 0; margin: 5px 0; }
            .trixbox-changelog-list li { margin: 5px 0; padding-left: 20px; position: relative; }
            .trixbox-changelog-list li:before { content: "✓"; position: absolute; left: 0; color: ${theme.buttonPrimary}; }
            .trixbox-changelog-btn { width: 100%; color: white; border: none; padding: 10px 20px; border-radius: 5px; cursor: pointer; margin-top: 15px; font-size: 14px; background: ${theme.buttonPrimary}; }
            .trixbox-changelog-btn:hover { opacity: 0.9; }
        `;
        const styleSheet = document.createElement("style");
        styleSheet.innerText = modalStyle;
        document.head.appendChild(styleSheet);

        const overlay = document.createElement('div');
        overlay.className = 'trixbox-changelog-overlay';
        overlay.innerHTML = `
            <div class="trixbox-changelog-content">
                <h2>What's New in v0.5.4</h2>
                <div class="trixbox-changelog-section">
                    <div class="trixbox-changelog-version">v0.5.4 - Major Update</div>
                    <ul class="trixbox-changelog-list">
                        <li>Dual chat system - Choose between TrixBox Main and New TrixBox</li>
                        <li>Custom username settings with persistent storage</li>
                        <li>Profile picture upload (visible to all users)</li>
                        <li>Coin flip command (!coinflip)</li>
                        <li>Tendo theme for retro aesthetic</li>
                        <li>Fully draggable chat windows</li>
                        <li>Auto-update checking system</li>
                    </ul>
                </div>
                <button class="trixbox-changelog-btn">Got it!</button>
            </div>
        `;
        document.body.appendChild(overlay);

        overlay.querySelector('button').addEventListener('click', () => {
            overlay.remove();
        });

        overlay.addEventListener('click', (e) => {
            if (e.target === overlay) {
                overlay.remove();
            }
        });
    };
 
    // --- 2. CREATE THE TOGGLE ICON ---
    const toggleIcon = document.createElement('div');
    toggleIcon.id = 'trixbox-toggle-icon';
    toggleIcon.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="${theme.text}" width="28px" height="28px"><path d="M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2z"/></svg>`;
    Object.assign(toggleIcon.style, {
        backgroundColor: theme.icon,
        position: 'fixed', bottom: '20px', right: '20px', width: '50px', height: '50px',
        borderRadius: '50%', display: 'flex', alignItems: 'center',
        justifyContent: 'center', cursor: 'pointer', zIndex: '99998',
        boxShadow: '0 2px 8px rgba(0,0,0,0.3)', transition: 'transform 0.2s ease-in-out'
    });
    toggleIcon.onmouseover = () => { toggleIcon.style.transform = 'scale(1.1)'; };
    toggleIcon.onmouseout = () => { toggleIcon.style.transform = 'scale(1.0)'; };
    document.body.appendChild(toggleIcon);

    // --- 3. CREATE THE CHATBOX ---
    const chatContainer = document.createElement('div');
    chatContainer.id = 'trixbox-container';
    Object.assign(chatContainer.style, {
        position: 'fixed', bottom: '15px', right: '15px', width: '350px', height: '500px',
        zIndex: '99999', display: 'none', flexDirection: 'column',
        boxShadow: '0 4px 12px rgba(0,0,0,0.3)', borderRadius: '8px', overflow: 'hidden'
    });

    const dragHeader = document.createElement('div');
    dragHeader.id = 'trixbox-header';
    Object.assign(dragHeader.style, {
        height: '30px', backgroundColor: 'rgb(210, 210, 255)', cursor: 'move',
        userSelect: 'none', display: 'flex', alignItems: 'center',
        justifyContent: 'space-between', padding: '0 5px 0 15px',
        position: 'relative', zIndex: '1'
    });

    const headerTitle = document.createElement('span');
    headerTitle.textContent = 'TrixBox Chat';
    Object.assign(headerTitle.style, {
        color: 'white', fontWeight: 'bold', fontSize: '14px',
        textShadow: '1px 1px 0 rgb(160, 160, 230), 2px 2px 0 rgba(0, 0, 0, 0.15)'
    });
    dragHeader.appendChild(headerTitle);

    const headerButtons = document.createElement('div');
    headerButtons.style.display = 'flex';
    headerButtons.style.alignItems = 'center';

    const settingsButton = document.createElement('button');
    settingsButton.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="rgb(80, 80, 120)" width="18px" height="18px"><path d="M19.14,12.94c0.04-0.3,0.06-0.61,0.06-0.94c0-0.32-0.02-0.64-0.07-0.94l2.03-1.58c0.18-0.14,0.23-0.41,0.12-0.61 l-1.92-3.32c-0.12-0.22-0.37-0.29-0.59-0.22l-2.39,0.96c-0.5-0.38-1.03-0.69-1.62-0.92L14.4,2.23C14.38,2,14.17,1.84,13.92,1.84H9.92 c-0.25,0-0.47,0.16-0.54,0.39L9.04,4.95C8.45,5.18,7.92,5.49,7.42,5.87L5.03,4.91c-0.22-0.08-0.47,0-0.59,0.22L2.52,8.45 c-0.11,0.2-0.06,0.47,0.12,0.61l2.03,1.58C4.59,11.36,4.56,11.68,4.56,12s0.02,0.64,0.07,0.94l-2.03,1.58 c-0.18,0.14-0.23,0.41-0.12,0.61l1.92,3.32c0.12,0.22,0.37,0.29,0.59,0.22l2.39-0.96c0.5,0.38,1.03,0.69,1.62,0.92l0.34,2.72 c0.07,0.23,0.29,0.39,0.54,0.39h3.99c0.25,0,0.47-0.16,0.54-0.39l0.34-2.72c0.59-0.23,1.12-0.54,1.62-0.92l2.39,0.96 c0.22,0.08,0.47,0,0.59-0.22l1.92-3.32c0.11-0.2,0.06-0.47-0.12-0.61L19.14,12.94z M12,15.6c-1.98,0-3.6-1.62-3.6-3.6 s1.62-3.6,3.6-3.6s3.6,1.62,3.6,3.6S13.98,15.6,12,15.6z"/></svg>`;
    Object.assign(settingsButton.style, {
        background: 'none', border: 'none', cursor: 'pointer',
        padding: '0 8px', lineHeight: '1', display: 'flex', alignItems: 'center'
    });
    headerButtons.appendChild(settingsButton);

    const closeButton = document.createElement('button');
    closeButton.innerHTML = '&times;';
    Object.assign(closeButton.style, {
        background: 'none', border: 'none', color: 'rgb(80, 80, 120)',
        fontSize: '24px', lineHeight: '1', cursor: 'pointer', padding: '0 8px'
    });
    headerButtons.appendChild(closeButton);
    dragHeader.appendChild(headerButtons);
    chatContainer.appendChild(dragHeader);

    const iframeWrapper = document.createElement('div');
    Object.assign(iframeWrapper.style, {
        flexGrow: '1', overflow: 'hidden', position: 'relative'
    });
    chatContainer.appendChild(iframeWrapper);

    const chatLibraryScript = document.createElement('script');
    chatLibraryScript.src = 'https://iframe.chat/scripts/main.min.js';
    document.head.appendChild(chatLibraryScript);

    const chatIframe = document.createElement('iframe');
    chatIframe.src = 'https://iframe.chat/embed?chat=15234533';
    chatIframe.id = 'chattable';
    Object.assign(chatIframe.style, {
        border: 'none', backgroundColor: 'transparent', position: 'absolute',
        height: `calc(100% + ${CHATTABLE_HEADER_HEIGHT}px)`, width: '100%',
        top: `-${CHATTABLE_HEADER_HEIGHT}px`, left: '0'
    });
    iframeWrapper.appendChild(chatIframe);
    document.body.appendChild(chatContainer);

    // --- 4. ADD FUNCTIONALITY ---
    toggleIcon.addEventListener('click', (e) => {
        e.stopPropagation();
        showChatSelectionModal();
    });

    const showChatSelectionModal = () => {
        const modalStyle = `
            .trixbox-selection-overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.8); z-index: 100001; display: flex; align-items: center; justify-content: center; }
            .trixbox-selection-content { background: ${theme.modalBg}; color: ${theme.text}; padding: 25px; border-radius: 10px; text-align: center; font-family: sans-serif; box-shadow: 0 5px 15px rgba(0,0,0,0.5); }
            .trixbox-selection-content h2 { margin-top: 0; margin-bottom: 20px; }
            .trixbox-selection-btn-group { display: flex; gap: 15px; }
            .trixbox-selection-btn { flex: 1; color: white; border: none; padding: 12px 20px; border-radius: 5px; cursor: pointer; font-size: 14px; font-weight: bold; }
            .trixbox-selection-btn.main { background: ${theme.buttonPrimary}; }
            .trixbox-selection-btn.new { background: #7289da; }
            .trixbox-selection-btn:hover { opacity: 0.9; }
        `;
        const styleSheet = document.createElement("style");
        styleSheet.innerText = modalStyle;
        document.head.appendChild(styleSheet);

        const overlay = document.createElement('div');
        overlay.className = 'trixbox-selection-overlay';
        overlay.innerHTML = `
            <div class="trixbox-selection-content">
                <h2>Select Chat</h2>
                <div class="trixbox-selection-btn-group">
                    <button id="trixbox-main-btn" class="trixbox-selection-btn main">TrixBox Main</button>
                    <button id="trixbox-new-btn" class="trixbox-selection-btn new">New TrixBox</button>
                </div>
            </div>
        `;
        document.body.appendChild(overlay);

        document.getElementById('trixbox-main-btn').addEventListener('click', () => {
            overlay.remove();
            chatContainer.style.display = 'flex';
            toggleIcon.style.display = 'none';
        });

        document.getElementById('trixbox-new-btn').addEventListener('click', () => {
            overlay.remove();
            showNewTrixBox();
        });

        overlay.addEventListener('click', (e) => {
            if (e.target === overlay) {
                overlay.remove();
            }
        });
    };

    const showNewTrixBox = () => {
        const newChatContainer = document.createElement('div');
        newChatContainer.id = 'trixbox-new-container';
        Object.assign(newChatContainer.style, {
            position: 'fixed', bottom: '15px', right: '15px', width: '350px', height: '500px',
            zIndex: '99999', display: 'flex', flexDirection: 'column',
            boxShadow: '0 4px 12px rgba(0,0,0,0.3)', borderRadius: '8px', overflow: 'hidden'
        });

        const newDragHeader = document.createElement('div');
        Object.assign(newDragHeader.style, {
            height: '30px', backgroundColor: 'rgb(210, 210, 255)', cursor: 'move',
            userSelect: 'none', display: 'flex', alignItems: 'center',
            justifyContent: 'space-between', padding: '0 5px 0 15px',
            position: 'relative', zIndex: '1'
        });

        const newHeaderTitle = document.createElement('span');
        newHeaderTitle.textContent = 'New TrixBox';
        Object.assign(newHeaderTitle.style, {
            color: 'white', fontWeight: 'bold', fontSize: '14px',
            textShadow: '1px 1px 0 rgb(160, 160, 230), 2px 2px 0 rgba(0, 0, 0, 0.15)'
        });
        newDragHeader.appendChild(newHeaderTitle);

        const newCloseButton = document.createElement('button');
        newCloseButton.innerHTML = '&times;';
        Object.assign(newCloseButton.style, {
            background: 'none', border: 'none', color: 'rgb(80, 80, 120)',
            fontSize: '24px', lineHeight: '1', cursor: 'pointer', padding: '0 8px'
        });
        newCloseButton.addEventListener('click', () => {
            newChatContainer.remove();
            toggleIcon.style.display = 'flex';
        });
        newDragHeader.appendChild(newCloseButton);
        newChatContainer.appendChild(newDragHeader);

        const newIframeWrapper = document.createElement('div');
        Object.assign(newIframeWrapper.style, {
            flexGrow: '1', overflow: 'hidden', position: 'relative'
        });

        const newIframe = document.createElement('iframe');
        newIframe.src = 'https://www5.cbox.ws/box/?boxid=959661&boxtag=LgpZi2';
        newIframe.width = '100%';
        newIframe.height = '100%';
        newIframe.allowTransparency = 'yes';
        newIframe.allow = 'autoplay';
        newIframe.frameBorder = '0';
        newIframe.marginHeight = '0';
        newIframe.marginWidth = '0';
        newIframe.scrolling = 'auto';
        Object.assign(newIframe.style, {
            border: 'none', position: 'absolute', top: '0', left: '0'
        });
        newIframeWrapper.appendChild(newIframe);
        newChatContainer.appendChild(newIframeWrapper);

        // Hide Cbox text in iframe footer
        try {
            const hideStyle = document.createElement('style');
            hideStyle.textContent = `
                iframe#trixbox-new-container-iframe ~ * a[href*="cbox.ws"],
                div[align="center"] a[href*="cbox.ws"] { display: none !important; }
            `;
            document.head.appendChild(hideStyle);
        } catch (e) { }
        document.body.appendChild(newChatContainer);

        // Drag functionality for new chat
        let isDragging = false, offsetX, offsetY;
        newDragHeader.addEventListener('mousedown', (e) => {
            if (e.target !== newDragHeader && e.target !== newHeaderTitle) return;
            isDragging = true;
            offsetX = e.clientX - newChatContainer.getBoundingClientRect().left;
            offsetY = e.clientY - newChatContainer.getBoundingClientRect().top;
            newIframe.style.pointerEvents = 'none';
        });

        document.addEventListener('mousemove', (e) => {
            if (!isDragging) return;
            newChatContainer.style.left = `${e.clientX - offsetX}px`;
            newChatContainer.style.top = `${e.clientY - offsetY}px`;
            newChatContainer.style.bottom = 'auto';
            newChatContainer.style.right = 'auto';
        });

        document.addEventListener('mouseup', () => {
            if (!isDragging) return;
            isDragging = false;
            newIframe.style.pointerEvents = 'auto';
        });
    };

    closeButton.addEventListener('click', (e) => {
        e.stopPropagation();
        chatContainer.style.display = 'none';
        toggleIcon.style.display = 'flex';
    });

    settingsButton.addEventListener('click', (e) => {
        e.stopPropagation();
        showSettingsModal();
    });

    const showSettingsModal = () => {
        const modalStyle = `
            .trixbox-settings-overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.8); z-index: 100001; display: flex; align-items: center; justify-content: center; }
            .trixbox-settings-content { background: ${theme.modalBg}; color: ${theme.text}; padding: 25px; border-radius: 10px; text-align: left; font-family: sans-serif; box-shadow: 0 5px 15px rgba(0,0,0,0.5); width: 350px; max-height: 80vh; overflow-y: auto; }
            .trixbox-settings-content h2 { margin-top: 0; text-align: center; }
            .trixbox-settings-group { margin: 20px 0; }
            .trixbox-settings-group label { display: block; margin-bottom: 8px; font-weight: bold; }
            .trixbox-settings-group input[type="text"], .trixbox-settings-group input[type="file"] { width: 100%; padding: 8px; background: #36393f; color: ${theme.text}; border: 1px solid #4f545c; border-radius: 4px; box-sizing: border-box; }
            .trixbox-settings-group input[type="text"]::placeholder { color: #99aab5; }
            .trixbox-profile-preview { width: 60px; height: 60px; border-radius: 50%; background: #4f545c; margin: 10px auto; overflow: hidden; display: flex; align-items: center; justify-content: center; }
            .trixbox-profile-preview img { width: 100%; height: 100%; object-fit: cover; }
            .trixbox-settings-btn-group { display: flex; gap: 10px; margin-top: 20px; }
            .trixbox-settings-btn { flex: 1; color: white; border: none; padding: 10px; border-radius: 5px; cursor: pointer; font-size: 14px; }
            .trixbox-settings-btn.save { background: ${theme.buttonPrimary}; }
            .trixbox-settings-btn.cancel { background: ${theme.buttonSecondary}; }
        `;
        const styleSheet = document.createElement("style");
        styleSheet.innerText = modalStyle;
        document.head.appendChild(styleSheet);

        const overlay = document.createElement('div');
        overlay.className = 'trixbox-settings-overlay';
        overlay.innerHTML = `
            <div class="trixbox-settings-content">
                <h2>Chat Settings</h2>
                <div class="trixbox-settings-group">
                    <label>Username</label>
                    <input type="text" id="trixbox-username-input" placeholder="Enter your username" maxlength="32">
                </div>
                <div class="trixbox-settings-group">
                    <label>Profile Picture</label>
                    <div class="trixbox-profile-preview" id="trixbox-profile-preview"></div>
                    <input type="file" id="trixbox-profile-upload" accept="image/*">
                </div>
                <div class="trixbox-settings-btn-group">
                    <button id="trixbox-settings-save" class="trixbox-settings-btn save">Save</button>
                    <button id="trixbox-settings-cancel" class="trixbox-settings-btn cancel">Cancel</button>
                </div>
            </div>
        `;
        document.body.appendChild(overlay);

        const usernameInput = document.getElementById('trixbox-username-input');
        const profileUpload = document.getElementById('trixbox-profile-upload');
        const profilePreview = document.getElementById('trixbox-profile-preview');
        const saveBtn = document.getElementById('trixbox-settings-save');
        const cancelBtn = document.getElementById('trixbox-settings-cancel');
        let selectedProfileImage = localStorage.getItem('trixbox-profile-image') || null;

        usernameInput.value = localStorage.getItem('trixbox-username') || '';

        if (selectedProfileImage) {
            profilePreview.innerHTML = `<img src="${selectedProfileImage}" alt="Profile">`;
        }

        profileUpload.addEventListener('change', (e) => {
            const file = e.target.files[0];
            if (file) {
                const reader = new FileReader();
                reader.onload = (event) => {
                    selectedProfileImage = event.target.result;
                    profilePreview.innerHTML = `<img src="${selectedProfileImage}" alt="Profile">`;
                };
                reader.readAsDataURL(file);
            }
        });

        saveBtn.addEventListener('click', () => {
            const username = usernameInput.value.trim();
            if (username) {
                localStorage.setItem('trixbox-username', username);
                if (selectedProfileImage) {
                    localStorage.setItem('trixbox-profile-image', selectedProfileImage);
                }
                if (typeof chattable !== 'undefined') {
                    if (typeof chattable.setName === 'function') {
                        chattable.setName(username);
                    }
                    // Send profile picture to other users via payload
                    if (selectedProfileImage && typeof chattable.sendPayload === 'function') {
                        chattable.sendPayload({
                            type: 'profile-picture',
                            username: username,
                            image: selectedProfileImage
                        });
                    }
                }
                overlay.remove();
            } else {
                alert('Please enter a username');
            }
        });

        cancelBtn.addEventListener('click', () => {
            overlay.remove();
        });

        overlay.addEventListener('click', (e) => {
            if (e.target === overlay) {
                overlay.remove();
            }
        });
    };

    let isDragging = false, offsetX, offsetY;
    dragHeader.addEventListener('mousedown', (e) => {
        if (e.target !== dragHeader && e.target !== headerTitle) return;
        isDragging = true;
        offsetX = e.clientX - chatContainer.getBoundingClientRect().left;
        offsetY = e.clientY - chatContainer.getBoundingClientRect().top;
        chatIframe.style.pointerEvents = 'none';
    });

    document.addEventListener('mousemove', (e) => {
        if (!isDragging) return;
        chatContainer.style.left = `${e.clientX - offsetX}px`;
        chatContainer.style.top = `${e.clientY - offsetY}px`;
        chatContainer.style.bottom = 'auto';
        chatContainer.style.right = 'auto';
    });

    document.addEventListener('mouseup', () => {
        if (!isDragging) return;
        isDragging = false;
        chatIframe.style.pointerEvents = 'auto';
    });

    // --- 5. DEFINE CUSTOM COMMANDS ---
    chattable.commands = {
        "coinflip": function(fullCommand) {
            const result = Math.random() < 0.5 ? "Heads" : "Tails";
            chattable.sendMessage(`🪙 Coin flip result: **${result}**`, "TrixBox", "", false);
        }
    };

    // --- 6. INITIALIZE THE CHAT ---
    chatLibraryScript.onload = function() {
        if (typeof chattable !== 'undefined') {
            chattable.initialize({
                theme: "tendo"
            });

            // Handle profile picture payloads after initialization
            chattable.on('payload', function(data) {
                if (data.type === 'profile-picture') {
                    localStorage.setItem(`trixbox-profile-${data.username}`, data.image);
                }
            });
        }
    };

    // --- 7. RUN THE UPDATE CHECKER ---
    checkForUpdates();

})();