Chaturbate Multi-Room Animator (Draggable + Minimizable)

Animate multiple Chaturbate rooms simultaneously with draggable/minimizable panel

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         Chaturbate Multi-Room Animator (Draggable + Minimizable)
// @namespace    http://tampermonkey.net/
// @version      2.3
// @description  Animate multiple Chaturbate rooms simultaneously with draggable/minimizable panel
// @author       You
// @match        https://chaturbate.com/*
// @grant        none
// @license MIT
// ==/UserScript==

(function() {
    'use strict';

    // Configuration with localStorage persistence
    let config = {
        simultaneousRooms: 5,
        animationSpeed: 2000,
        enabled: false,
        panelPosition: { x: null, y: null },
        isMinimized: false
    };

    // Drag state
    let isDragging = false;
    let dragOffset = { x: 0, y: 0 };

    // Simple save function that definitely gets called
    function simpleSave() {
        try {
            localStorage.setItem('multiRoom_rooms', config.simultaneousRooms);
            localStorage.setItem('multiRoom_speed', config.animationSpeed);
            if (config.panelPosition.x !== null && config.panelPosition.y !== null) {
                localStorage.setItem('multiRoom_panel_x', config.panelPosition.x);
                localStorage.setItem('multiRoom_panel_y', config.panelPosition.y);
            }
            localStorage.setItem('multiRoom_minimized', config.isMinimized);
        } catch (e) {
            console.error('❌ Error saving settings:', e);
        }
    }

    // Simple load function
    function simpleLoad() {
        try {
            const rooms = localStorage.getItem('multiRoom_rooms');
            const speed = localStorage.getItem('multiRoom_speed');
            const panelX = localStorage.getItem('multiRoom_panel_x');
            const panelY = localStorage.getItem('multiRoom_panel_y');
            const minimized = localStorage.getItem('multiRoom_minimized');

            if (rooms) config.simultaneousRooms = parseInt(rooms);
            if (speed) {
                const loadedSpeed = parseInt(speed);
                // Ensure speed is within new bounds (10-500ms)
                config.animationSpeed = Math.max(10, Math.min(500, loadedSpeed));
            }
            if (panelX && panelY) {
                config.panelPosition.x = parseInt(panelX);
                config.panelPosition.y = parseInt(panelY);
            }
            if (minimized !== null) {
                config.isMinimized = minimized === 'true';
            }

            console.log('📋 Settings loaded:', {rooms: config.simultaneousRooms, speed: config.animationSpeed});
        } catch (e) {
            console.error('❌ Error loading settings:', e);
        }
    }

    let animationInterval;
    let roomElements = [];
    let controlPanel;
    let isPaused = false;
    let isCompletelyDisabled = false;
    let mutationObserver = null;

    // Create control panel
    function createControlPanel() {
        // Remove existing panel if it exists
        const existingPanel = document.getElementById('multi-room-animator-panel');
        if (existingPanel) {
            existingPanel.remove();
        }

        controlPanel = document.createElement('div');
        controlPanel.id = 'multi-room-animator-panel';

        // Determine initial position
        let initialX = config.panelPosition.x !== null ? config.panelPosition.x : (window.innerWidth - 250);
        let initialY = config.panelPosition.y !== null ? config.panelPosition.y : 10;

        controlPanel.style.cssText = `
            position: fixed;
            left: ${initialX}px;
            top: ${initialY}px;
            background: #1a1a1a;
            border: 2px solid #ff6b35;
            border-radius: 7px;
            padding: 0;
            z-index: 9999;
            font-family: Arial, sans-serif;
            font-size: 13px;
            color: white;
            min-width: 224px;
            box-shadow: 0 3px 12px rgba(0,0,0,0.5);
            transform: scale(0.8);
            transform-origin: top left;
            user-select: none;
        `;

        // Create draggable title bar
        const titleBar = document.createElement('div');
        titleBar.id = 'panel-title-bar';
        titleBar.style.cssText = `
            padding: 8px 12px;
            cursor: move;
            background: linear-gradient(135deg, #ff6b35, #ff8555);
            border-radius: 5px 5px 0 0;
            display: flex;
            justify-content: space-between;
            align-items: center;
        `;

        const titleContainer = document.createElement('div');
        titleContainer.style.cssText = 'display: flex; align-items: center; gap: 8px;';

        const title = document.createElement('h3');
        title.style.cssText = 'margin: 0; color: white; font-size: 15px; pointer-events: none;';
        title.textContent = 'Multi-Room Animator';

        const dragIcon = document.createElement('span');
        dragIcon.style.cssText = 'color: rgba(255,255,255,0.7); pointer-events: none; font-size: 18px;';
        dragIcon.textContent = '⋮⋮';

        titleContainer.appendChild(title);
        titleContainer.appendChild(dragIcon);

        // Add minimize button
        const minimizeBtn = document.createElement('button');
        minimizeBtn.id = 'minimize-btn';
        minimizeBtn.style.cssText = `
            background: rgba(255,255,255,0.2);
            color: white;
            border: 1px solid rgba(255,255,255,0.3);
            padding: 2px 8px;
            border-radius: 3px;
            cursor: pointer;
            font-size: 14px;
            font-weight: bold;
            transition: background 0.2s;
            min-width: 24px;
        `;
        minimizeBtn.textContent = config.isMinimized ? '+' : '−';
        minimizeBtn.title = config.isMinimized ? 'Restore' : 'Minimize';

        titleBar.appendChild(titleContainer);
        titleBar.appendChild(minimizeBtn);

        // Create content container
        const contentContainer = document.createElement('div');
        contentContainer.id = 'panel-content';
        contentContainer.style.cssText = 'padding: 12px;';
        if (config.isMinimized) {
            contentContainer.style.display = 'none';
        }

        // Create elements step by step
        const roomCountDiv = document.createElement('div');
        roomCountDiv.style.marginBottom = '9px';

        const roomCountLabel = document.createElement('label');
        roomCountLabel.style.cssText = 'display: block; margin-bottom: 4px; font-size: 12px;';
        roomCountLabel.textContent = 'Simultaneous rooms to animate:';

        const roomCountInput = document.createElement('input');
        roomCountInput.type = 'number';
        roomCountInput.id = 'simultaneous-room-count';
        roomCountInput.value = config.simultaneousRooms;
        roomCountInput.min = '1';
        roomCountInput.max = '50';
        roomCountInput.style.cssText = 'width: 48px; padding: 4px; background: #333; color: white; border: 1px solid #555; font-size: 12px;';

        const speedDiv = document.createElement('div');
        speedDiv.style.marginBottom = '9px';

        const speedLabel = document.createElement('label');
        speedLabel.style.cssText = 'display: block; margin-bottom: 4px; font-size: 12px;';
        speedLabel.innerHTML = `Refresh interval (ms): <span id="speed-display">${config.animationSpeed}</span>`;

        const speedInput = document.createElement('input');
        speedInput.type = 'number';
        speedInput.id = 'animation-speed';
        speedInput.value = config.animationSpeed;
        speedInput.min = '10';
        speedInput.max = '500';
        speedInput.step = '10';
        speedInput.style.cssText = 'width: 64px; padding: 4px; background: #333; color: white; border: 1px solid #555; font-size: 12px;';

        const buttonDiv = document.createElement('div');

        const toggleBtn = document.createElement('button');
        toggleBtn.id = 'toggle-animation';
        toggleBtn.textContent = 'Start';
        toggleBtn.style.cssText = `
            background: #ff6b35;
            color: white;
            border: none;
            padding: 6px 12px;
            border-radius: 3px;
            cursor: pointer;
            margin-right: 4px;
            font-size: 12px;
        `;

        const disableBtn = document.createElement('button');
        disableBtn.id = 'disable-script';
        disableBtn.textContent = 'Disable';
        disableBtn.style.cssText = `
            background: #dc3545;
            color: white;
            border: none;
            padding: 6px 12px;
            border-radius: 3px;
            cursor: pointer;
            margin-left: 4px;
            font-size: 12px;
        `;

        const statusDiv = document.createElement('div');
        statusDiv.style.cssText = 'margin-top: 9px; font-size: 11px; color: #ccc;';
        statusDiv.innerHTML = `
            Status: <span id="status">Stopped</span><br>
            Rooms found: <span id="room-count-display">0</span><br>
            Animating: <span id="animating-display">-</span>
        `;

        // Assemble the panel
        roomCountDiv.appendChild(roomCountLabel);
        roomCountDiv.appendChild(roomCountInput);

        speedDiv.appendChild(speedLabel);
        speedDiv.appendChild(speedInput);

        buttonDiv.appendChild(toggleBtn);
        buttonDiv.appendChild(disableBtn);

        contentContainer.appendChild(roomCountDiv);
        contentContainer.appendChild(speedDiv);
        contentContainer.appendChild(buttonDiv);
        contentContainer.appendChild(statusDiv);

        controlPanel.appendChild(titleBar);
        controlPanel.appendChild(contentContainer);

        document.body.appendChild(controlPanel);

        // Setup minimize functionality
        minimizeBtn.onclick = (e) => {
            e.stopPropagation();
            config.isMinimized = !config.isMinimized;

            if (config.isMinimized) {
                contentContainer.style.display = 'none';
                minimizeBtn.textContent = '+';
                minimizeBtn.title = 'Restore';
            } else {
                contentContainer.style.display = 'block';
                minimizeBtn.textContent = '−';
                minimizeBtn.title = 'Minimize';
            }

            simpleSave();
        };

        // Setup drag functionality
        setupDragFunctionality(titleBar, minimizeBtn);

        // Setup event listeners immediately after creation
        setupEventListeners();
    }

    // Setup drag functionality for the panel
    function setupDragFunctionality(titleBar, minimizeBtn) {
        titleBar.addEventListener('mousedown', startDrag);
        document.addEventListener('mousemove', drag);
        document.addEventListener('mouseup', stopDrag);

        function startDrag(e) {
            if (e.target === minimizeBtn) return;
            e.preventDefault();
            isDragging = true;

            const rect = controlPanel.getBoundingClientRect();
            dragOffset.x = e.clientX - rect.left;
            dragOffset.y = e.clientY - rect.top;

            controlPanel.style.opacity = '0.8';
        }

        function drag(e) {
            if (!isDragging) return;
            e.preventDefault();

            let newX = e.clientX - dragOffset.x;
            let newY = e.clientY - dragOffset.y;

            const scale = 0.8;
            const panelWidth = controlPanel.offsetWidth * scale;
            const panelHeight = controlPanel.offsetHeight * scale;

            newX = Math.max(0, Math.min(newX, window.innerWidth - panelWidth));
            newY = Math.max(0, Math.min(newY, window.innerHeight - panelHeight));

            controlPanel.style.left = newX + 'px';
            controlPanel.style.top = newY + 'px';

            config.panelPosition.x = newX;
            config.panelPosition.y = newY;
        }

        function stopDrag() {
            if (!isDragging) return;
            isDragging = false;
            controlPanel.style.opacity = '1';
            simpleSave();
        }
    }

    // Setup event listeners for control panel
    function setupEventListeners() {
        try {
            const toggleBtn = controlPanel.querySelector('#toggle-animation');
            const disableBtn = controlPanel.querySelector('#disable-script');
            const roomCountInput = controlPanel.querySelector('#simultaneous-room-count');
            const speedInput = controlPanel.querySelector('#animation-speed');

            if (toggleBtn) {
                toggleBtn.onclick = () => toggleAnimation();
            }

            if (disableBtn) {
                disableBtn.onclick = () => {
                    completelyDisableScript();
                };
            }

            if (speedInput) {
                speedInput.onchange = (e) => {
                    const newSpeed = parseInt(e.target.value);
                    config.animationSpeed = newSpeed;
                    simpleSave();
                    updateSpeedDisplay();
                    if (config.enabled) {
                        restartAnimation();
                    }
                };

                speedInput.oninput = (e) => {
                    const newSpeed = parseInt(e.target.value);
                    if (!isNaN(newSpeed)) {
                        config.animationSpeed = newSpeed;
                        simpleSave();
                        updateSpeedDisplay();
                        if (config.enabled) {
                            restartAnimation();
                        }
                    }
                };
            }

            if (roomCountInput) {
                roomCountInput.onchange = (e) => {
                    const newCount = parseInt(e.target.value);
                    config.simultaneousRooms = newCount;
                    simpleSave();
                    updateAnimatingDisplay();
                    if (config.enabled) {
                        restartAnimation();
                    }
                };

                roomCountInput.oninput = (e) => {
                    const newCount = parseInt(e.target.value);
                    if (!isNaN(newCount)) {
                        config.simultaneousRooms = newCount;
                        simpleSave();
                        updateAnimatingDisplay();
                        if (config.enabled) {
                            restartAnimation();
                        }
                    }
                };
            }

        } catch (error) {
            console.error('❌ Error in setupEventListeners:', error);
        }
    }

    // Update speed display
    function updateSpeedDisplay() {
        try {
            const speedDisplay = document.getElementById('speed-display');
            const speedInput = document.getElementById('animation-speed');

            if (speedDisplay) {
                speedDisplay.textContent = config.animationSpeed;
            }

            if (speedInput) {
                speedInput.value = config.animationSpeed;
            }
        } catch (error) {
            console.error('❌ Error updating speed display:', error);
        }
    }

    // Check if an element is meaningfully visible in the viewport
    function isElementVisible(element) {
        const rect = element.getBoundingClientRect();
        const windowHeight = window.innerHeight || document.documentElement.clientHeight;
        const windowWidth = window.innerWidth || document.documentElement.clientWidth;

        // Calculate how much of the element is visible
        const visibleTop = Math.max(rect.top, 0);
        const visibleBottom = Math.min(rect.bottom, windowHeight);
        const visibleLeft = Math.max(rect.left, 0);
        const visibleRight = Math.min(rect.right, windowWidth);

        const visibleHeight = Math.max(0, visibleBottom - visibleTop);
        const visibleWidth = Math.max(0, visibleRight - visibleLeft);
        const visibleArea = visibleHeight * visibleWidth;

        const totalArea = rect.height * rect.width;
        const visibilityPercentage = totalArea > 0 ? (visibleArea / totalArea) : 0;

        // Element must be at least 50% visible and have substantial visible area
        return visibilityPercentage >= 0.5 && visibleHeight >= 100;
    }

    // Get visible rooms from all found rooms
    function getVisibleRooms() {
        if (roomElements.length === 0) return [];

        const visibleRooms = roomElements.filter(room => isElementVisible(room));

        return visibleRooms;
    }

    // Find room elements on the page
    function findRoomElements() {
        const selectors = [
            'li[class*="room"]',
            '.roomCard',
            'div[class*="room"]',
            '.room_list_room',
            '.room-card',
            '[data-room]'
        ];

        const previousCount = roomElements.length;
        roomElements = [];

        for (let selector of selectors) {
            try {
                const elements = document.querySelectorAll(selector);
                if (elements.length > 0) {
                    roomElements = Array.from(elements);
                    break;
                }
            } catch (e) {
                console.log(`Selector "${selector}" failed:`, e);
            }
        }

        if (roomElements.length !== previousCount) {
            console.log(`✅ Found ${roomElements.length} rooms on page (was ${previousCount})`);
        }

        updateRoomCountDisplay();
        return roomElements.length > 0;
    }

    // Update the room count display
    function updateRoomCountDisplay() {
        try {
            const display = document.getElementById('room-count-display');
            if (display) {
                display.textContent = roomElements.length;
            }
            updateAnimatingDisplay();
        } catch (error) {
            console.error('❌ Error updating room count display:', error);
        }
    }

    // Update the animating rooms display
    function updateAnimatingDisplay() {
        try {
            const animatingDisplay = document.getElementById('animating-display');
            if (animatingDisplay) {
                if (config.enabled && roomElements.length > 0) {
                    const visibleRooms = getVisibleRooms();
                    const actualCount = Math.min(config.simultaneousRooms, visibleRooms.length);
                    animatingDisplay.textContent = `${actualCount} visible rooms`;
                } else {
                    animatingDisplay.textContent = '-';
                }
            }
        } catch (error) {
            console.error('❌ Error updating animating display:', error);
        }
    }

    // Completely disable the script and remove all traces
    function completelyDisableScript() {
        console.log('🛑 completelyDisableScript() function called');

        try {
            // Stop animation
            isCompletelyDisabled = true;
            config.enabled = false;

            // Clear ALL intervals (in case there are multiple)
            if (animationInterval) {
                clearInterval(animationInterval);
                animationInterval = null;
                console.log('✅ Animation interval cleared');
            }

            // Clear all timeouts and intervals that might be running
            const highestId = window.setTimeout(() => {}, 0);
            for (let i = 0; i < highestId; i++) {
                window.clearTimeout(i);
                window.clearInterval(i);
            }
            console.log('✅ All timeouts and intervals cleared');

            // Stop mutation observer
            if (mutationObserver) {
                mutationObserver.disconnect();
                mutationObserver = null;
                console.log('✅ Mutation observer disconnected');
            }

            // Stop all video previews immediately
            console.log('🛑 Stopping all video previews...');
            roomElements.forEach(room => {
                // Remove preview images
                const preview = room.querySelector('.direct-video-preview');
                const border = room.querySelector('.animation-border');
                if (preview) preview.remove();
                if (border) border.remove();

                // Force stop all videos
                const videos = room.querySelectorAll('video');
                videos.forEach(video => {
                    video.pause();
                    video.currentTime = 0;
                    video.src = '';
                    video.load();
                });
            });
            console.log('✅ All video previews stopped and cleaned');

            // Remove the control panel
            if (controlPanel) {
                controlPanel.remove();
                controlPanel = null;
                console.log('✅ Control panel removed');
            }

            // Force garbage collection by nullifying everything
            roomElements = null;
            config = null;

            console.log('🎉 Script completely disabled. CPU usage should drop now.');
            alert('Script fully disabled! CPU usage should drop. Refresh page to re-enable.');

        } catch (error) {
            console.error('❌ Error in completelyDisableScript:', error);
        }
    }

    // Create direct video preview using direct URL
    function createDirectVideoPreview(roomElement, username) {
        try {
            // Remove any existing preview and border
            const existingPreview = roomElement.querySelector('.direct-video-preview');
            const existingBorder = roomElement.querySelector('.animation-border');
            if (existingPreview) {
                existingPreview.remove();
            }
            if (existingBorder) {
                existingBorder.remove();
            }

            // Create the direct thumbnail URL with cache busting
            const cacheBuster = Math.random();
            const thumbnailUrl = `https://thumb.live.mmcdn.com/minifwap/${username}.jpg?${cacheBuster}`;

            // Create image element for the preview
            const previewImg = document.createElement('img');
            previewImg.className = 'direct-video-preview';

            // Create border overlay element
            const borderOverlay = document.createElement('div');
            borderOverlay.className = 'animation-border';
            borderOverlay.style.cssText = `
                position: absolute !important;
                top: 0 !important;
                left: 0 !important;
                width: 100% !important;
                height: 100% !important;
                box-shadow: inset 0 0 0 2px rgba(40, 167, 69, 0.8) !important;
                z-index: 10000 !important;
                pointer-events: none !important;
            `;

            // Add to DOM first, then set src to ensure it's connected
            const thumbnailContainer = roomElement.querySelector('.room_thumbnail_container');
            const existingImg = roomElement.querySelector('img');

            if (thumbnailContainer) {
                thumbnailContainer.style.position = 'relative';
                thumbnailContainer.appendChild(previewImg);
                thumbnailContainer.appendChild(borderOverlay);
            } else if (existingImg && existingImg.parentElement) {
                existingImg.parentElement.style.position = 'relative';
                existingImg.parentElement.appendChild(previewImg);
                existingImg.parentElement.appendChild(borderOverlay);
            } else {
                roomElement.style.position = 'relative';
                roomElement.appendChild(previewImg);
                roomElement.appendChild(borderOverlay);
            }

            // Set image styles
            previewImg.style.cssText = `
                position: absolute !important;
                top: 0 !important;
                left: 0 !important;
                width: 100% !important;
                height: 100% !important;
                object-fit: cover !important;
                z-index: 9999 !important;
                pointer-events: none !important;
            `;

            // Add error handler
            previewImg.onerror = () => {
                previewImg.remove();
                borderOverlay.remove();
            };

            // Set the src
            previewImg.src = thumbnailUrl;

            return previewImg;

        } catch (error) {
            return null;
        }
    }

    // Remove direct video preview
    function removeDirectVideoPreview(roomElement) {
        try {
            const existingPreview = roomElement.querySelector('.direct-video-preview');
            const existingBorder = roomElement.querySelector('.animation-border');
            if (existingPreview) {
                existingPreview.remove();
            }
            if (existingBorder) {
                existingBorder.remove();
            }
        } catch (error) {
            // Silently handle errors
        }
    }

    // Animate multiple rooms simultaneously - DIRECT URL METHOD
    function animateMultipleRooms() {
        if (roomElements.length === 0 || isCompletelyDisabled) return;

        // Get only the visible rooms
        const visibleRooms = getVisibleRooms();
        if (visibleRooms.length === 0) {
            return;
        }

        const roomsToAnimate = Math.min(config.simultaneousRooms, visibleRooms.length);

        // Get current usernames that should be animated
        const currentUsernames = [];
        for (let i = 0; i < roomsToAnimate; i++) {
            const room = visibleRooms[i];
            if (room) {
                const roomLink = room.querySelector('a[data-room]');
                const username = roomLink ? roomLink.getAttribute('data-room') : null;
                if (username) {
                    currentUsernames.push({ room, username });
                }
            }
        }

        // Remove previews for rooms that are no longer being animated
        roomElements.forEach((room) => {
            const existingPreview = room.querySelector('.direct-video-preview');
            if (existingPreview) {
                const roomLink = room.querySelector('a[data-room]');
                const username = roomLink ? roomLink.getAttribute('data-room') : null;

                // Only remove if this room is not in current animation list
                if (!currentUsernames.some(item => item.username === username)) {
                    removeDirectVideoPreview(room);
                }
            }
        });

        // Create or update previews for current rooms
        currentUsernames.forEach(({ room, username }) => {
            const existingPreview = room.querySelector('.direct-video-preview');

            if (existingPreview) {
                // Force update by creating a new image and replacing when loaded
                const cacheBuster = Math.random();
                const thumbnailUrl = `https://thumb.live.mmcdn.com/minifwap/${username}.jpg?${cacheBuster}`;

                // Create a new image to preload
                const newImg = document.createElement('img');
                newImg.className = 'direct-video-preview';
                newImg.style.cssText = `
                    position: absolute !important;
                    top: 0 !important;
                    left: 0 !important;
                    width: 100% !important;
                    height: 100% !important;
                    object-fit: cover !important;
                    z-index: 9999 !important;
                    pointer-events: none !important;
                `;

                newImg.onload = () => {
                    // Replace the old image with the new one only after it's loaded
                    if (existingPreview.parentNode) {
                        existingPreview.parentNode.replaceChild(newImg, existingPreview);
                    }
                };

                newImg.onerror = () => {
                    newImg.remove();
                };

                newImg.src = thumbnailUrl;
            } else {
                // Create new preview
                createDirectVideoPreview(room, username);
            }
        });

        updateAnimatingDisplay();
    }

    // Restart animation
    function restartAnimation() {
        console.log(`🔄 Restarting invisible animation: ${config.simultaneousRooms} rooms, ${config.animationSpeed}ms interval`);

        if (animationInterval) {
            clearInterval(animationInterval);
            animationInterval = null;
        }

        if (config.enabled) {
            animationInterval = setInterval(animateMultipleRooms, config.animationSpeed);
            animateMultipleRooms(); // Start immediately
        }
    }

    // Start animation
    function startAnimation() {
        if (isCompletelyDisabled) return;

        console.log('🚀 Starting invisible multi-room animation...');

        if (!findRoomElements()) {
            alert(`No room elements found!

Try these steps:
1. Make sure you're on a page with room listings
2. Try the "Refresh" button after the page loads completely`);
            return;
        }

        console.log(`✅ Found ${roomElements.length} rooms, starting INVISIBLE animation (no scrolling, no borders)`);
        config.enabled = true;

        animationInterval = setInterval(animateMultipleRooms, config.animationSpeed);
        animateMultipleRooms(); // Start immediately

        updateUI();
    }

    // Stop animation
    function stopAnimation() {
        console.log('⏹️ Stopping invisible animation...');
        config.enabled = false;

        if (animationInterval) {
            clearInterval(animationInterval);
            animationInterval = null;
        }

        // Remove all previews
        roomElements.forEach(room => {
            removeDirectVideoPreview(room);
        });

        updateUI();
        updateAnimatingDisplay();
    }

    // Toggle animation
    function toggleAnimation() {
        if (config.enabled) {
            stopAnimation();
        } else {
            startAnimation();
        }
    }

    // Update UI elements
    function updateUI() {
        try {
            const toggleBtn = document.getElementById('toggle-animation');
            const status = document.getElementById('status');

            if (toggleBtn) {
                toggleBtn.textContent = config.enabled ? 'Stop' : 'Start';
                toggleBtn.style.background = config.enabled ? '#dc3545' : '#ff6b35';
            }

            if (status) {
                status.textContent = config.enabled ? 'Running' : 'Stopped';
                status.style.color = config.enabled ? '#4CAF50' : '#ccc';
            }
        } catch (error) {
            console.error('❌ Error updating UI:', error);
        }
    }

    // Initialize when page loads
    function init() {
        console.log('🚀 Multi-Room Animator v2.3 (with drag and minimize) starting...');

        if (document.readyState === 'loading') {
            document.addEventListener('DOMContentLoaded', init);
            return;
        }

        simpleLoad();

        setTimeout(() => {
            createControlPanel();
            if (findRoomElements()) {
                // Auto-start animation after everything is set up
                setTimeout(() => {
                    startAnimation();
                }, 500);
            }
        }, 1000);
    }

    // Handle navigation changes
    let currentUrl = location.href;
    mutationObserver = new MutationObserver(() => {
        if (isCompletelyDisabled) return;

        // Check for URL changes (tab changes)
        if (location.href !== currentUrl) {
            currentUrl = location.href;
            console.log('🔄 Page navigation detected, updating rooms...');

            setTimeout(() => {
                // Re-find rooms on the new page
                if (findRoomElements()) {
                    console.log('✅ Rooms updated after navigation');
                } else {
                    console.log('⚠️ No rooms found after navigation');
                }
            }, 1500); // Wait a bit longer for content to load
        }

        // Also check for content changes (rooms loading/changing)
        const roomContainers = document.querySelectorAll('li[class*="room"], .roomCard');
        if (roomContainers.length !== roomElements.length && roomContainers.length > 0) {
            console.log(`🔄 Room count changed: ${roomElements.length} → ${roomContainers.length}`);

            setTimeout(() => {
                findRoomElements();
            }, 500);
        }
    });
    mutationObserver.observe(document, { subtree: true, childList: true });

    // Start the script
    init();

})();