Wizardebop 2.00

⚒ Advanced Acellus Mod/Custom Pack – a production–quality productivity suite with persistent settings, movable/resizable widgets, inspirational quotes, custom/star wallpapers, break reminders, and more.

目前为 2025-02-12 提交的版本。查看 最新版本

// ==UserScript==
// @name         Wizardebop 2.00
// @author       Type Stuff
// @description  ⚒ Advanced Acellus Mod/Custom Pack – a production–quality productivity suite with persistent settings, movable/resizable widgets, inspirational quotes, custom/star wallpapers, break reminders, and more.
// @version      11
// @match        https://admin192a.acellus.com/student/*
// @match        https://admin192c.acellus.com/student/*
// @license      
// @run-at       document-start
// @grant        none
// @namespace    https://greasyfork.org/users/1394549
// @icon         https://img.freepik.com/free-vector/halloween-witch-hat-isolated-illustration_18591-83719.jpg
// ==/UserScript==

(function () {
    'use strict';

    /********************************************
     * 1. CSS Styles
     ********************************************/
    const style = document.createElement('style');
    style.innerHTML = `
        /* Animated Wallpaper & Effects */
        @keyframes animated-wallpaper {
            0% { background-position: 0% 50%; }
            50% { background-position: 100% 50%; }
            100% { background-position: 0% 50%; }
        }
        @keyframes snowfall {
            0% { transform: translateY(-10px); }
            100% { transform: translateY(100vh); }
        }
        @keyframes raindrop {
            0% { transform: translateY(-50px); opacity: 0.7; }
            100% { transform: translateY(100vh); opacity: 1; }
        }
        @keyframes floating-emoji {
            0% { transform: translateY(0); opacity: 1; }
            50% { transform: translateY(-30px); opacity: 0.8; }
            100% { transform: translateY(0); opacity: 1; }
        }
        @keyframes color-particles {
            0% { transform: translateX(0) translateY(0); opacity: 1; }
            100% { transform: translateX(200px) translateY(200px); opacity: 0; }
        }
        /* Settings Button */
        #settings-button {
            position: fixed;
            bottom: 20px;
            right: 20px;
            background-color: #28a745;
            color: white;
            border: none;
            border-radius: 5px;
            padding: 10px 20px;
            cursor: pointer;
            font-size: 16px;
            z-index: 1002;
            transition: background-color 0.3s ease;
        }
        #settings-button:hover { background-color: #218838; }
        /* Settings Menu */
        #settings-menu {
            position: fixed;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            width: 75%;
            max-width: 900px;
            max-height: 80%;
            overflow-y: auto;
            background: linear-gradient(45deg, #ffd700, #ff69b4, #e0e0e0, #f0e68c);
            background-size: 200% 200%;
            animation: animated-wallpaper 8s ease infinite;
            border-radius: 15px;
            padding: 0;
            box-shadow: 0px 0px 25px rgba(0, 0, 0, 0.3);
            z-index: 1001;
            display: none;
            overflow: hidden;
        }
        .settings-content { display: flex; width: 100%; height: 100%; border-radius: 15px; }
        .settings-categories {
            width: 25%;
            background-color: rgba(200, 200, 200, 0.9);
            padding: 20px 15px;
            box-sizing: border-box;
            margin: 0;
            border-top-left-radius: 15px;
            border-bottom-left-radius: 15px;
            transition: background-color 0.3s ease;
        }
        .settings-details {
            width: 75%;
            padding: 20px;
            display: flex;
            flex-direction: column;
            box-sizing: border-box;
            background-color: transparent;
        }
        #settings-menu h2 { margin-top: 0; color: #333; }
        .settings-categories button {
            width: 100%;
            padding: 12px;
            margin: 8px 0;
            border: none;
            background-color: rgba(255, 255, 255, 0.8);
            border-radius: 8px;
            cursor: pointer;
            text-align: left;
            color: #333;
            font-weight: bold;
            transition: background-color 0.3s ease, transform 0.2s ease;
        }
        .settings-categories button:hover {
            background-color: #007bff;
            color: white;
            transform: scale(1.05);
        }
        .category-menu {
            padding: 10px;
            background: rgba(249, 249, 249, 0.8);
            border-radius: 10px;
            display: none;
        }
        /* Additional General Settings (Break Reminder) */
        /* (Will appear in the General settings menu) */
        /* Overlay & Close Button */
        #overlay {
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background-color: rgba(0, 0, 0, 0.6);
            display: none;
            z-index: 1000;
            backdrop-filter: blur(8px);
        }
        #close-settings {
            background: none;
            border: none;
            color: #ffffff;
            font-size: 1.5rem;
            position: absolute;
            top: 15px;
            right: 15px;
            cursor: pointer;
            transition: color 0.3s ease;
        }
        #close-settings:hover { color: #555; }
        #close-settings::before { content: '✖'; }
        /* Dark Mode Styles */
        body.dark-mode { background-color: #121212; color: #e0e0e0; }
        .dark-mode #settings-menu {
            background: linear-gradient(45deg, #2f2f2f, #0e4c92, #00bcd4, #008080, #454545, #1c1c1c, #274472, #026873, #123456, #0a0a0a);
            background-size: 200% 200%;
            animation: animated-wallpaper 8s ease infinite;
        }
        .dark-mode .settings-categories { background-color: rgba(80, 80, 80, 0.7); }
        .dark-mode .settings-categories button { background-color: #333333; color: #e0e0e0; }
        .dark-mode .settings-categories button:hover { background-color: #555555; color: #ffffff; }
        .dark-mode .category-menu { background: rgba(68, 68, 68, 0.8); color: #e0e0e0; }
        .dark-mode #close-settings { color: #8b0000; }
        .dark-mode #close-settings:hover { color: #ff6347; }
        /* Apply Buttons */
        #apply-appearance, #apply-wallpaper, #apply-widgets, #apply-general {
            margin-top: 15px;
            padding: 10px;
            background-color: #007bff;
            color: #ffffff;
            border: none;
            border-radius: 5px;
            cursor: pointer;
            transition: background-color 0.3s ease;
        }
        #apply-appearance:hover, #apply-wallpaper:hover, #apply-widgets:hover, #apply-general:hover {
            background-color: #0056b3;
        }
        /* Gradient Options */
        .gradient-option {
            display: inline-block;
            width: 80px;
            height: 50px;
            margin: 5px;
            border-radius: 8px;
            cursor: pointer;
            border: 2px solid transparent;
            transition: border-color 0.3s ease;
        }
        .gradient-option:hover { border-color: #007bff; }
        #wallpaper-preview { margin-top: 10px; display: flex; flex-wrap: wrap; }
        .gradient-bg {
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background-size: 200% 200%;
            animation: animated-wallpaper 20s ease infinite;
            z-index: -1;
        }
        /* Effects Elements */
        .snowflake, .raindrop, .star, .firefly, .emoji, .particle {
            position: fixed;
            top: -10px;
            font-size: 20px;
            color: white;
            z-index: 1005;
        }
        .snowflake { animation: snowfall 10s linear infinite; }
        .raindrop { animation: raindrop 5s linear infinite; font-size: 12px; color: #00bfff; }
        .star { animation: twinkling 3s infinite alternate; color: #fffacd; font-size: 10px; }
        .firefly { background-color: yellow; width: 10px; height: 10px; border-radius: 50%; animation: twinkling 2s infinite alternate; }
        .emoji { animation: floating-emoji 4s infinite alternate; font-size: 30px; }
        .particle { animation: color-particles 6s linear infinite; background-color: #ff4081; border-radius: 50%; width: 10px; height: 10px; }
        /* Clock Widget */
        #clock-widget {
            position: fixed;
            top: 20px;
            left: 20px;
            background-color: #333;
            color: #fff;
            padding: 10px 20px;
            border-radius: 8px;
            font-family: Arial, sans-serif;
            font-size: 18px;
            z-index: 1005;
            user-select: none;
            cursor: grab;
        }
        /* Resize Handle for Widgets */
        .resize-handle {
            position: absolute;
            width: 10px;
            height: 10px;
            background: #007bff;
            bottom: 0;
            right: 0;
            cursor: se-resize;
            z-index: 10;
        }
        /* Good Day Quote Widget & Progress Bar */
        #good-day-quote-widget {
            position: fixed;
            top: 50px;
            right: 20px;
            background: rgba(0,0,0,0.8);
            color: #fff;
            padding: 10px 15px;
            border-radius: 8px;
            font-family: Arial, sans-serif;
            z-index: 1006;
            width: 300px;
            font-size: 14px;
            text-align: center;
        }
        #good-day-quote-widget .quote-progress {
            position: absolute;
            bottom: 0;
            left: 0;
            height: 4px;
            background: #28a745;
            width: 100%;
        }
    `;
    document.head.appendChild(style);

    /********************************************
     * 2. Helper: Movable & Resizable Widgets
     ********************************************/
    function makeMovableResizable(widget, widgetKey) {
        // Load saved position from localStorage (if any)
        const savedPos = localStorage.getItem('widget_' + widgetKey + '_position');
        if (savedPos) {
            try {
                const pos = JSON.parse(savedPos);
                widget.style.left = pos.left;
                widget.style.top = pos.top;
            } catch (e) { /* ignore error */ }
        }
        // Load saved size (if any)
        const savedSize = localStorage.getItem('widget_' + widgetKey + '_size');
        if (savedSize) {
            try {
                const size = JSON.parse(savedSize);
                widget.style.width = size.width;
                widget.style.height = size.height;
            } catch (e) { /* ignore error */ }
        }
        // Ensure widget is fixed positioned
        widget.style.position = 'fixed';
        // DRAG: Only drag when not clicking on the resize-handle
        widget.addEventListener('mousedown', function(e) {
            if (e.target.classList.contains('resize-handle')) return;
            const startX = e.clientX;
            const startY = e.clientY;
            const origLeft = parseInt(widget.style.left, 10) || 0;
            const origTop = parseInt(widget.style.top, 10) || 0;
            function onMouseMove(e) {
                widget.style.left = (origLeft + (e.clientX - startX)) + 'px';
                widget.style.top = (origTop + (e.clientY - startY)) + 'px';
            }
            function onMouseUp() {
                document.removeEventListener('mousemove', onMouseMove);
                document.removeEventListener('mouseup', onMouseUp);
                const pos = { left: widget.style.left, top: widget.style.top };
                localStorage.setItem('widget_' + widgetKey + '_position', JSON.stringify(pos));
            }
            document.addEventListener('mousemove', onMouseMove);
            document.addEventListener('mouseup', onMouseUp);
        });
        // RESIZE: Add a resize handle if not already present
        let resizeHandle = widget.querySelector('.resize-handle');
        if (!resizeHandle) {
            resizeHandle = document.createElement('div');
            resizeHandle.className = 'resize-handle';
            widget.appendChild(resizeHandle);
        }
        resizeHandle.addEventListener('mousedown', function(e) {
            e.stopPropagation();
            const startX = e.clientX;
            const startY = e.clientY;
            const origWidth = widget.offsetWidth;
            const origHeight = widget.offsetHeight;
            function onMouseMove(e) {
                widget.style.width = (origWidth + (e.clientX - startX)) + 'px';
                widget.style.height = (origHeight + (e.clientY - startY)) + 'px';
            }
            function onMouseUp() {
                document.removeEventListener('mousemove', onMouseMove);
                document.removeEventListener('mouseup', onMouseUp);
                const size = { width: widget.style.width, height: widget.style.height };
                localStorage.setItem('widget_' + widgetKey + '_size', JSON.stringify(size));
            }
            document.addEventListener('mousemove', onMouseMove);
            document.addEventListener('mouseup', onMouseUp);
        });
    }

    /********************************************
     * 3. Settings Menu & Overlay
     ********************************************/
    const settingsButton = document.createElement('button');
    settingsButton.id = 'settings-button';
    settingsButton.textContent = 'Settings';
    document.body.appendChild(settingsButton);

    // The settings menu now includes an extra “Break Reminder” option in General
    const settingsMenu = document.createElement('div');
    settingsMenu.id = 'settings-menu';
    settingsMenu.innerHTML = `
        <div class="settings-content">
            <div class="settings-categories">
                <button class="category-btn" data-category="general">General</button>
                <button class="category-btn" data-category="appearance">Appearance</button>
                <button class="category-btn" data-category="wallpaper">Wallpaper</button>
                <button class="category-btn" data-category="effects">Effects</button>
                <button class="category-btn" data-category="widgets">Widgets</button>
            </div>
            <div class="settings-details">
                <!-- General Settings -->
                <div class="category-menu" id="general-menu">
                    <label><input type="checkbox" id="enable-notifications"> Enable Notifications</label><br>
                    <label><input type="checkbox" id="auto-save-progress"> Auto-Save Progress</label><br>
                    <label><input type="checkbox" id="focus-mode"> Enable Focus Mode</label><br>
                    <label><input type="checkbox" id="auto-dark-mode"> Enable Auto Dark Mode</label><br>
                    <label><input type="checkbox" id="disable-animations"> Disable Animations</label><br>
                    <label><input type="checkbox" id="enable-break-reminder"> Enable Break Reminder</label><br>
                    <label>Break Interval (minutes):
                        <input type="number" id="break-interval" min="5" max="60" value="30">
                    </label><br>
                    <button id="apply-general">Apply General Settings</button>
                </div>
                <!-- Appearance Settings -->
                <div class="category-menu" id="appearance-menu">
                    <h2>Appearance Settings</h2>
                    <label>Theme:
                        <select id="theme-selector">
                            <option value="light">Light</option>
                            <option value="dark">Dark</option>
                        </select>
                    </label><br>
                    <label>Gradient Speed:
                        <input type="range" id="gradient-speed" min="5" max="30" step="1" value="20">
                    </label><br>
                    <label><input type="checkbox" id="enable-animations"> Enable Animations</label><br>
                    <label><input type="checkbox" id="enable-background-blur"> Enable Background Blur</label><br>
                    <button id="apply-appearance">Apply</button>
                </div>
                <!-- Wallpaper Settings -->
                <div class="category-menu" id="wallpaper-menu">
                    <h2>Wallpaper Settings</h2>
                    <label>Custom Wallpaper (Image/GIF URL):
                        <input type="text" id="custom-wallpaper-url" placeholder="Enter image or gif URL" />
                    </label><br>
                    <label><input type="checkbox" id="enable-custom-wallpaper"> Enable Custom Wallpaper</label><br>
                    <label><input type="checkbox" id="enable-star-wallpaper"> Enable Star Wallpaper</label><br>
                    <label>Star Density:
                        <input type="range" id="star-density" min="10" max="200" step="10" value="50">
                    </label><br>
                    <button id="apply-wallpaper">Apply Wallpaper</button>
                    <div id="wallpaper-preview">
                        <!-- Gradient options will be appended here -->
                    </div>
                </div>
                <!-- Effects Settings -->
                <div class="category-menu" id="effects-menu">
                    <h2>Visual Effects</h2>
                    <label><input type="checkbox" id="enable-snowfall"> Enable Snowfall Effect</label><br>
                    <label><input type="checkbox" id="enable-rain"> Enable Minecraft-Like Rain Effect</label><br>
                    <label><input type="checkbox" id="enable-stars"> Enable Twinkling Stars Effect</label><br>
                    <label><input type="checkbox" id="enable-fireflies"> Enable Fireflies Effect</label><br>
                    <label><input type="checkbox" id="enable-floating-emojis"> Enable Floating Emojis</label><br>
                    <label><input type="checkbox" id="enable-particles"> Enable Color Particles</label><br>
                    <button id="apply-effects">Apply Effects</button>
                </div>
                <!-- Widgets Settings -->
                <div class="category-menu" id="widgets-menu">
                    <h2>Widgets</h2>
                    <label><input type="checkbox" id="enable-clock-widget"> Enable Clock Widget</label><br>
                    <label><input type="checkbox" id="enable-pomodoro-widget"> Enable Pomodoro Timer</label><br>
                    <label>Pomodoro Duration (minutes):
                        <input type="number" id="pomodoro-duration" min="1" max="60" value="25">
                    </label><br>
                    <label><input type="checkbox" id="enable-todo-widget"> Enable To-Do List</label><br>
                    <label><input type="checkbox" id="enable-good-day-quote"> Enable Good Day Quote</label><br>
                    <button id="apply-widgets">Apply Widgets</button>
                </div>
            </div>
        </div>
        <button id="close-settings"></button>
    `;
    document.body.appendChild(settingsMenu);
    settingsMenu.style.display = 'none';

    const overlay = document.createElement('div');
    overlay.id = 'overlay';
    document.body.appendChild(overlay);
    overlay.style.display = 'none';

    /********************************************
     * 4. Widgets: Clock, Pomodoro, To-Do, Good Day Quote
     ********************************************/
    // Clock Widget
    const clockWidget = document.createElement('div');
    clockWidget.id = 'clock-widget';
    document.body.appendChild(clockWidget);
    clockWidget.style.display = 'none';
    setInterval(() => {
        const now = new Date();
        clockWidget.textContent = now.toLocaleTimeString();
    }, 1000);
    makeMovableResizable(clockWidget, 'clock-widget');

    // Pomodoro Timer Widget
    const pomodoroWidget = document.createElement('div');
    pomodoroWidget.id = 'pomodoro-widget';
    pomodoroWidget.innerHTML = `
        <h3>Pomodoro Timer</h3>
        <div class="time">25:00</div>
        <button id="pomodoro-start-stop">Start</button>
        <button id="pomodoro-reset">Reset</button>
    `;
    document.body.appendChild(pomodoroWidget);
    pomodoroWidget.style.display = 'none';
    makeMovableResizable(pomodoroWidget, 'pomodoro-widget');
    let pomodoroInterval = null;
    let pomodoroTime = 25 * 60; // will be updated from settings
    let pomodoroRunning = false;
    function updatePomodoroDisplay() {
        const minutes = String(Math.floor(pomodoroTime / 60)).padStart(2, '0');
        const seconds = String(pomodoroTime % 60).padStart(2, '0');
        pomodoroWidget.querySelector('.time').textContent = `${minutes}:${seconds}`;
    }
    document.getElementById('pomodoro-start-stop').addEventListener('click', () => {
        if (!pomodoroRunning) {
            pomodoroInterval = setInterval(() => {
                if (pomodoroTime > 0) {
                    pomodoroTime--;
                    updatePomodoroDisplay();
                } else {
                    clearInterval(pomodoroInterval);
                    pomodoroRunning = false;
                    document.getElementById('pomodoro-start-stop').textContent = 'Start';
                    alert('Pomodoro session completed! Take a short break.');
                }
            }, 1000);
            pomodoroRunning = true;
            document.getElementById('pomodoro-start-stop').textContent = 'Pause';
        } else {
            clearInterval(pomodoroInterval);
            pomodoroRunning = false;
            document.getElementById('pomodoro-start-stop').textContent = 'Start';
        }
    });
    document.getElementById('pomodoro-reset').addEventListener('click', () => {
        clearInterval(pomodoroInterval);
        const duration = parseInt(document.getElementById('pomodoro-duration').value, 10) || 25;
        pomodoroTime = duration * 60;
        pomodoroRunning = false;
        updatePomodoroDisplay();
        document.getElementById('pomodoro-start-stop').textContent = 'Start';
    });

    // To-Do List Widget
    const todoWidget = document.createElement('div');
    todoWidget.id = 'todo-widget';
    todoWidget.innerHTML = `
        <h3>To-Do List</h3>
        <input type="text" id="todo-input" placeholder="Add new task...">
        <ul id="todo-list"></ul>
    `;
    document.body.appendChild(todoWidget);
    todoWidget.style.display = 'none';
    makeMovableResizable(todoWidget, 'todo-widget');
    document.getElementById('todo-input').addEventListener('keypress', (e) => {
        if (e.key === 'Enter') {
            const task = e.target.value.trim();
            if (task !== '') {
                addTodoItem(task);
                e.target.value = '';
            }
        }
    });
    function addTodoItem(task) {
        const li = document.createElement('li');
        li.textContent = task;
        const removeBtn = document.createElement('button');
        removeBtn.textContent = '✖';
        removeBtn.addEventListener('click', () => {
            li.remove();
            saveTodoList();
        });
        li.appendChild(removeBtn);
        document.getElementById('todo-list').appendChild(li);
        saveTodoList();
    }
    function saveTodoList() {
        const items = [];
        document.querySelectorAll('#todo-list li').forEach(li => {
            items.push(li.firstChild.textContent);
        });
        localStorage.setItem('todo-list', JSON.stringify(items));
    }
    function loadTodoList() {
        const items = JSON.parse(localStorage.getItem('todo-list') || '[]');
        items.forEach(task => addTodoItem(task));
    }
    loadTodoList();

    // Good Day Quote Widget (Ephemeral: shows for 10 seconds with progress bar)
    let goodDayQuoteWidget = null;
    let goodDayQuoteTimeout = null;
    const goodDayQuotes = [];
    for (let i = 1; i <= 200; i++) {
        goodDayQuotes.push(`Inspiration #${i}: Have a fantastic day and keep pushing forward!`);
    }
    function getRandomGoodDayQuote() {
        const index = Math.floor(Math.random() * goodDayQuotes.length);
        return goodDayQuotes[index];
    }
    function showGoodDayQuote() {
        if (goodDayQuoteWidget) return;
        goodDayQuoteWidget = document.createElement('div');
        goodDayQuoteWidget.id = 'good-day-quote-widget';
        goodDayQuoteWidget.textContent = getRandomGoodDayQuote();
        const progressBar = document.createElement('div');
        progressBar.className = 'quote-progress';
        progressBar.style.transition = 'width 10s linear';
        goodDayQuoteWidget.appendChild(progressBar);
        document.body.appendChild(goodDayQuoteWidget);
        makeMovableResizable(goodDayQuoteWidget, 'good-day-quote-widget');
        void progressBar.offsetWidth; // force reflow
        progressBar.style.width = '0%';
        goodDayQuoteTimeout = setTimeout(() => {
            if (goodDayQuoteWidget) {
                goodDayQuoteWidget.remove();
                goodDayQuoteWidget = null;
            }
        }, 10000);
    }
    function handleGoodDayQuote() {
        const enabled = localStorage.getItem('enable-good-day-quote') === 'true' ||
                        document.getElementById('enable-good-day-quote').checked;
        if (enabled) {
            if (Math.random() < 0.5) { showGoodDayQuote(); }
            setInterval(() => { if (Math.random() < 0.5) { showGoodDayQuote(); } }, 10 * 60 * 1000);
        } else {
            if (goodDayQuoteWidget) { goodDayQuoteWidget.remove(); goodDayQuoteWidget = null; }
            if (goodDayQuoteTimeout) { clearTimeout(goodDayQuoteTimeout); goodDayQuoteTimeout = null; }
        }
    }

    /********************************************
     * 5. Break Reminder (New Feature)
     ********************************************/
    let breakReminderInterval;
    function initBreakReminder() {
        if (breakReminderInterval) clearInterval(breakReminderInterval);
        const interval = parseInt(document.getElementById('break-interval').value, 10) || 30;
        breakReminderInterval = setInterval(() => {
            alert('Time for a break! Take a moment to relax.');
        }, interval * 60 * 1000);
    }

    /********************************************
     * 6. Star Wallpaper Effect
     ********************************************/
function initStarWallpaper() {
    // Remove any existing star wallpaper canvas and gradient backgrounds
    const oldCanvas = document.getElementById('star-wallpaper-canvas');
    if (oldCanvas) { oldCanvas.remove(); }
    const oldGradient = document.querySelector('.gradient-bg');
    if (oldGradient) { oldGradient.remove(); }

    // Create a full-screen canvas for the star wallpaper
    const canvas = document.createElement('canvas');
    canvas.id = 'star-wallpaper-canvas';
    canvas.style.position = 'fixed';
    canvas.style.top = '0';
    canvas.style.left = '0';
    canvas.style.zIndex = '-2';
    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight;
    document.body.appendChild(canvas);
    const ctx = canvas.getContext('2d');

    // Calculate the center of the canvas (used for projection and orbits)
    const centerX = canvas.width / 2;
    const centerY = canvas.height / 2;

    // Draw a deep–black, spacy overlay using a radial gradient
    function drawBackground() {
        const gradient = ctx.createRadialGradient(centerX, centerY, canvas.width / 4, centerX, centerY, canvas.width);
        gradient.addColorStop(0, 'rgba(0, 0, 0, 0.95)');
        gradient.addColorStop(1, 'rgba(0, 0, 0, 1)');
        ctx.fillStyle = gradient;
        ctx.fillRect(0, 0, canvas.width, canvas.height);
    }

    // Simple perspective projection function using a z–value (for 3D effect)
    function project(x, y, z) {
        const scale = 1 / z; // Larger z => further away => smaller scale
        return {
            x: (x - centerX) * scale + centerX,
            y: (y - centerY) * scale + centerY,
            scale
        };
    }

    // Generate a field of stars with a random z coordinate for depth
    const stars = [];
    const densityInput = document.getElementById('star-density');
    const starCount = densityInput ? parseInt(densityInput.value, 10) : 50;
    for (let i = 0; i < starCount; i++) {
        stars.push({
            x: Math.random() * canvas.width,
            y: Math.random() * canvas.height,
            z: Math.random() * 1 + 0.5, // z between 0.5 and 1.5
            baseSize: Math.random() * 2 + 0.5,
            alpha: Math.random(),
            alphaChange: (Math.random() * 0.001) + 0.0005  // slower twinkling
        });
    }

    // Generate cosmic dust particles with depth
    const dustParticles = [];
    for (let i = 0; i < 100; i++) {
        dustParticles.push({
            x: Math.random() * canvas.width,
            y: Math.random() * canvas.height,
            z: Math.random() * 1 + 0.5,
            baseSize: Math.random() * 1.5 + 0.5,
            vx: (Math.random() - 0.5) * 0.1,
            vy: (Math.random() - 0.5) * 0.1,
            alpha: Math.random() * 0.5 + 0.1
        });
    }

    // Define the central sun (larger and circular)
    const sun = { x: centerX, y: centerY, size: 40, color: 'yellow' };

    // Define solar system–inspired planets with 3D–like orbits
    // The "inclination" factor tilts the orbits.
    const inclination = 0.7;
    const solarPlanets = [
        { name: "Mercury", orbitRadius: 50,  size: 3,   color: "#bebebe", speed: 0.01,  angle: Math.random() * Math.PI * 2, ring: false },
        { name: "Venus",   orbitRadius: 80,  size: 5,   color: "#e6c27a", speed: 0.008, angle: Math.random() * Math.PI * 2, ring: false },
        { name: "Earth",   orbitRadius: 110, size: 5.5, color: "#3a81f1", speed: 0.006, angle: Math.random() * Math.PI * 2, ring: false },
        { name: "Mars",    orbitRadius: 140, size: 4,   color: "#c1440e", speed: 0.005, angle: Math.random() * Math.PI * 2, ring: false },
        { name: "Jupiter", orbitRadius: 200, size: 10,  color: "#d3a068", speed: 0.0035, angle: Math.random() * Math.PI * 2, ring: false },
        { name: "Saturn",  orbitRadius: 250, size: 9,   color: "#e6d0a8", speed: 0.0025, angle: Math.random() * Math.PI * 2, ring: true },
        { name: "Uranus",  orbitRadius: 300, size: 7,   color: "#81d1e6", speed: 0.002, angle: Math.random() * Math.PI * 2, ring: false },
        { name: "Neptune", orbitRadius: 350, size: 7,   color: "#3a66e6", speed: 0.0015, angle: Math.random() * Math.PI * 2, ring: false }
    ];

    // For each planet, compute its initial position and a depth indicator.
    // Here we use the unmodified sine of the angle to determine depth:
    solarPlanets.forEach(planet => {
        // Make the orbit wider horizontally by multiplying the orbitRadius by 1.3 for the x coordinate.
        planet.xPos = centerX + planet.orbitRadius * 1.3 * Math.cos(planet.angle);
        planet.yPos = centerY + planet.orbitRadius * Math.sin(planet.angle) * inclination;
        planet.depth = Math.sin(planet.angle);  // negative => behind the sun, positive => in front
    });

    // Array for shooting stars
    const shootingStars = [];

    // Animation loop: update positions and redraw everything
    function animate() {
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        // Draw the deep–black, spacy background
        drawBackground();

        // Draw twinkling stars with perspective projection
        stars.forEach(star => {
            star.alpha += star.alphaChange;
            if (star.alpha <= 0 || star.alpha >= 1) { star.alphaChange = -star.alphaChange; }
            const p = project(star.x, star.y, star.z);
            const size = star.baseSize * p.scale;
            ctx.beginPath();
            ctx.arc(p.x, p.y, size, 0, Math.PI * 2);
            ctx.fillStyle = `rgba(255,255,255,${star.alpha.toFixed(2)})`;
            ctx.fill();
        });

        // Update and draw cosmic dust particles with perspective
        dustParticles.forEach(dust => {
            dust.x += dust.vx;
            dust.y += dust.vy;
            if (dust.x < 0) dust.x = canvas.width;
            if (dust.x > canvas.width) dust.x = 0;
            if (dust.y < 0) dust.y = canvas.height;
            if (dust.y > canvas.height) dust.y = 0;
            const p = project(dust.x, dust.y, dust.z);
            const size = dust.baseSize * p.scale;
            ctx.beginPath();
            ctx.arc(p.x, p.y, size, 0, Math.PI * 2);
            ctx.fillStyle = `rgba(200,200,200,${dust.alpha.toFixed(2)})`;
            ctx.fill();
        });

        // --- Update Solar Planets ---
        // Update each planet's orbit angle and recalc positions
        solarPlanets.forEach(planet => {
            planet.angle += planet.speed;
            planet.xPos = centerX + planet.orbitRadius * 1.3 * Math.cos(planet.angle);
            planet.yPos = centerY + planet.orbitRadius * Math.sin(planet.angle) * inclination;
            planet.depth = Math.sin(planet.angle);
        });
        // Separate planets into two groups: those behind and those in front of the sun
        const behindPlanets = solarPlanets.filter(planet => planet.depth < 0);
        const frontPlanets = solarPlanets.filter(planet => planet.depth >= 0);

        // Draw planets behind the sun
        behindPlanets.forEach(planet => {
            const p = project(planet.xPos, planet.yPos, 1 - planet.depth);
            const size = planet.size * p.scale;
            ctx.beginPath();
            ctx.arc(p.x, p.y, size, 0, Math.PI * 2);
            ctx.fillStyle = planet.color;
            ctx.fill();
            if (planet.ring) {
                // Draw Saturn's ring
                const ringOuterRadius = size + 8;
                const ringInnerRadius = size + 3;
                ctx.save();
                ctx.beginPath();
                ctx.ellipse(p.x, p.y, ringOuterRadius, ringOuterRadius * 0.5, 0, 0, Math.PI * 2);
                const ringGradient = ctx.createRadialGradient(p.x, p.y, ringInnerRadius, p.x, p.y, ringOuterRadius);
                ringGradient.addColorStop(0, 'rgba(230, 200, 150, 0.8)');
                ringGradient.addColorStop(1, 'rgba(210, 180, 130, 0.5)');
                ctx.fillStyle = ringGradient;
                ctx.fill();
                ctx.globalCompositeOperation = 'destination-out';
                ctx.beginPath();
                ctx.ellipse(p.x, p.y, ringInnerRadius, ringInnerRadius * 0.5, 0, 0, Math.PI * 2);
                ctx.fill();
                ctx.globalCompositeOperation = 'source-over';
                ctx.restore();
            }
        });

        // Draw the central sun (always on top of the "behind" layer)
        ctx.beginPath();
        ctx.arc(sun.x, sun.y, sun.size, 0, Math.PI * 2);
        ctx.fillStyle = sun.color;
        ctx.fill();

        // Draw planets in front of the sun
        frontPlanets.forEach(planet => {
            const p = project(planet.xPos, planet.yPos, 1 - planet.depth);
            const size = planet.size * p.scale;
            ctx.beginPath();
            ctx.arc(p.x, p.y, size, 0, Math.PI * 2);
            ctx.fillStyle = planet.color;
            ctx.fill();
            if (planet.ring) {
                const ringOuterRadius = size + 8;
                const ringInnerRadius = size + 3;
                ctx.save();
                ctx.beginPath();
                ctx.ellipse(p.x, p.y, ringOuterRadius, ringOuterRadius * 0.5, 0, 0, Math.PI * 2);
                const ringGradient = ctx.createRadialGradient(p.x, p.y, ringInnerRadius, p.x, p.y, ringOuterRadius);
                ringGradient.addColorStop(0, 'rgba(230, 200, 150, 0.8)');
                ringGradient.addColorStop(1, 'rgba(210, 180, 130, 0.5)');
                ctx.fillStyle = ringGradient;
                ctx.fill();
                ctx.globalCompositeOperation = 'destination-out';
                ctx.beginPath();
                ctx.ellipse(p.x, p.y, ringInnerRadius, ringInnerRadius * 0.5, 0, 0, Math.PI * 2);
                ctx.fill();
                ctx.globalCompositeOperation = 'source-over';
                ctx.restore();
            }
        });

        // Occasionally spawn a shooting star (with slower speeds)
        if (Math.random() < 0.003) {
            shootingStars.push({
                x: Math.random() * canvas.width,
                y: 0,
                vx: (Math.random() * 2) + 3,
                vy: (Math.random() * 1) + 1,
                length: Math.random() * 60 + 20,
                life: 0,
                maxLife: 40
            });
        }

        // Update and draw shooting stars
        for (let i = shootingStars.length - 1; i >= 0; i--) {
            const s = shootingStars[i];
            s.x += s.vx;
            s.y += s.vy;
            s.life++;
            ctx.beginPath();
            ctx.moveTo(s.x, s.y);
            ctx.lineTo(s.x - s.length, s.y - s.length * (s.vy / s.vx));
            ctx.strokeStyle = 'white';
            ctx.lineWidth = 2;
            ctx.stroke();
            if (s.life > s.maxLife) { shootingStars.splice(i, 1); }
        }

        requestAnimationFrame(animate);
    }
    animate();

    // Adjust canvas size on window resize
    window.addEventListener('resize', () => {
        canvas.width = window.innerWidth;
        canvas.height = window.innerHeight;
    });
}

    /********************************************
     * 7. Settings Button & Menu Event Listeners
     ********************************************/
    function openSettingsMenu() {
        overlay.style.display = 'block';
        settingsMenu.style.display = 'flex';
    }
    function closeSettingsMenu() {
        overlay.style.display = 'none';
        settingsMenu.style.display = 'none';
        document.querySelectorAll('.category-menu').forEach(menu => {
            menu.style.display = 'none';
        });
    }
    settingsButton.addEventListener('click', () => {
        const code = prompt('Enter the password:');
        if (code === '123') { openSettingsMenu(); }
        else { alert('Incorrect password'); }
    });
    overlay.addEventListener('click', closeSettingsMenu);
    document.getElementById('close-settings').addEventListener('click', closeSettingsMenu);
    document.querySelectorAll('.category-btn').forEach(button => {
        button.addEventListener('click', (e) => {
            const category = e.target.getAttribute('data-category');
            const menu = document.getElementById(`${category}-menu`);
            document.querySelectorAll('.category-menu').forEach(menu => { menu.style.display = 'none'; });
            if (menu) { menu.style.display = 'block'; }
        });
    });

    /********************************************
     * 8. Wallpaper Functions & Gradient Options
     ********************************************/
    function applyCustomWallpaper(url) {
        const gradientBg = document.querySelector('.gradient-bg');
        if (gradientBg) gradientBg.remove();
        if (url && url.trim() !== '') {
            document.body.style.backgroundImage = `url('${url}')`;
            document.body.style.backgroundPosition = 'center';
            document.body.style.backgroundRepeat = 'no-repeat';
            document.body.style.backgroundSize = 'cover';
        } else {
            document.body.style.backgroundImage = '';
        }
    }
    document.getElementById('apply-wallpaper').addEventListener('click', () => {
        const enableCustom = document.getElementById('enable-custom-wallpaper').checked;
        const enableStar = document.getElementById('enable-star-wallpaper').checked;
        const url = document.getElementById('custom-wallpaper-url').value;
        saveSetting('enable-custom-wallpaper', enableCustom);
        saveSetting('custom-wallpaper-url', url);
        saveSetting('enable-star-wallpaper', enableStar);
        if (enableStar) {
            initStarWallpaper();
        } else if (enableCustom) {
            applyCustomWallpaper(url);
        } else {
            document.body.style.backgroundImage = '';
            const selectedGradient = localStorage.getItem('selected-gradient');
            if (selectedGradient) { applyAnimatedGradient(selectedGradient); }
        }
    });
    // Gradient Options
    const gradients = [
        'linear-gradient(90deg, #ff7e5f, #feb47b)',
        'linear-gradient(90deg, #6a11cb, #2575fc)',
        'linear-gradient(90deg, #43cea2, #185a9d)',
        'linear-gradient(90deg, #ff9a9e, #fad0c4)',
        'linear-gradient(90deg, #a1c4fd, #c2e9fb)',
        'linear-gradient(90deg, #667eea, #764ba2)',
        'linear-gradient(90deg, #89f7fe, #66a6ff)',
    ];
    const wallpaperPreview = document.getElementById('wallpaper-preview');
    gradients.forEach((gradient) => {
        const gradientDiv = document.createElement('div');
        gradientDiv.className = 'gradient-option';
        gradientDiv.style.background = gradient;
        gradientDiv.dataset.gradient = gradient;
        gradientDiv.addEventListener('click', () => {
            applyAnimatedGradient(gradient);
            saveSetting('selected-gradient', gradient);
        });
        wallpaperPreview.appendChild(gradientDiv);
    });
    function applyAnimatedGradient(gradient) {
        let gradientBg = document.querySelector('.gradient-bg');
        if (!gradientBg) {
            gradientBg = document.createElement('div');
            gradientBg.className = 'gradient-bg';
            document.body.appendChild(gradientBg);
        }
        gradientBg.style.background = gradient;
    }

    /********************************************
     * 9. Appearance Settings Functions
     ********************************************/
    function applyTheme() {
        const theme = document.getElementById('theme-selector').value;
        saveSetting('theme-selector', theme);
        if (theme === 'dark') { document.body.classList.add('dark-mode'); }
        else { document.body.classList.remove('dark-mode'); }
    }
    document.getElementById('apply-appearance').addEventListener('click', () => {
        const customWallpaperUrl = document.getElementById('custom-wallpaper-url').value;
        saveSetting('custom-wallpaper-url', customWallpaperUrl);
        applyTheme();
        const blur = document.getElementById('enable-background-blur').checked;
        const gradientSpeed = document.getElementById('gradient-speed').value;
        saveSetting('enable-background-blur', blur);
        saveSetting('gradient-speed', gradientSpeed);
        const gradientBg = document.querySelector('.gradient-bg');
        if (gradientBg) { gradientBg.style.animationDuration = `${gradientSpeed}s`; }
        if (blur) { document.body.style.backdropFilter = 'blur(8px)'; }
        else { document.body.style.backdropFilter = ''; }
    });

    /********************************************
     * 10. Effects Settings Listener
     ********************************************/
    document.getElementById('apply-effects').addEventListener('click', () => {
        const snowfall = document.getElementById('enable-snowfall').checked;
        const rain = document.getElementById('enable-rain').checked;
        const starsEff = document.getElementById('enable-stars').checked;
        const fireflies = document.getElementById('enable-fireflies').checked;
        const floatingEmojis = document.getElementById('enable-floating-emojis').checked;
        const particles = document.getElementById('enable-particles').checked;
        saveSetting('enable-snowfall', snowfall);
        saveSetting('enable-rain', rain);
        saveSetting('enable-stars', starsEff);
        saveSetting('enable-fireflies', fireflies);
        saveSetting('enable-floating-emojis', floatingEmojis);
        saveSetting('enable-particles', particles);
        toggleEffect('snowflake', snowfall);
        toggleEffect('raindrop', rain);
        toggleEffect('star', starsEff);
        toggleEffect('firefly', fireflies);
        toggleEffect('emoji', floatingEmojis);
        toggleEffect('particle', particles);
    });
    function toggleEffect(type, enable) {
        let effectIntervals = {};
        if (enable) {
            if (!effectIntervals[type]) { effectIntervals[type] = setInterval(() => createEffect(type), 500); }
        } else {
            clearInterval(effectIntervals[type]);
            delete effectIntervals[type];
            document.querySelectorAll(`.${type}`).forEach(el => el.remove());
        }
    }
    function createEffect(type) {
        const effectElement = document.createElement('div');
        effectElement.className = type;
        if (type === 'snowflake') { effectElement.textContent = '❄'; }
        else if (type === 'raindrop') { effectElement.textContent = '|'; }
        else if (type === 'star') { effectElement.textContent = '★'; }
        else if (type === 'emoji') { effectElement.textContent = ['🌟', '✨', '❤️', '😊', '🔥', '🌈'][Math.floor(Math.random() * 6)]; }
        effectElement.style.left = Math.random() * window.innerWidth + 'px';
        effectElement.style.animationDuration = (Math.random() * 5 + 5) + 's';
        document.body.appendChild(effectElement);
        setTimeout(() => effectElement.remove(), 10000);
    }

    /********************************************
     * 11. Widgets Settings Listener
     ********************************************/
    document.getElementById('apply-widgets').addEventListener('click', () => {
        const clockEnabled = document.getElementById('enable-clock-widget').checked;
        saveSetting('enable-clock-widget', clockEnabled);
        clockWidget.style.display = clockEnabled ? 'block' : 'none';
        const pomodoroEnabled = document.getElementById('enable-pomodoro-widget').checked;
        saveSetting('enable-pomodoro-widget', pomodoroEnabled);
        pomodoroWidget.style.display = pomodoroEnabled ? 'block' : 'none';
        const todoEnabled = document.getElementById('enable-todo-widget').checked;
        saveSetting('enable-todo-widget', todoEnabled);
        todoWidget.style.display = todoEnabled ? 'block' : 'none';
        const goodDayEnabled = document.getElementById('enable-good-day-quote').checked;
        saveSetting('enable-good-day-quote', goodDayEnabled);
        handleGoodDayQuote();
        // Update Pomodoro Duration
        const pomodoroDuration = parseInt(document.getElementById('pomodoro-duration').value, 10) || 25;
        saveSetting('pomodoro-duration', pomodoroDuration);
        pomodoroTime = pomodoroDuration * 60;
        updatePomodoroDisplay();
    });

    /********************************************
     * 12. Save & Load Settings Utility
     ********************************************/
    const saveSetting = (id, value) => { localStorage.setItem(id, value); };
    const applySavedSettings = () => {
        // General
        document.getElementById('focus-mode').checked = localStorage.getItem('focus-mode') === 'true';
        document.getElementById('auto-dark-mode').checked = localStorage.getItem('auto-dark-mode') === 'true';
        document.getElementById('disable-animations').checked = localStorage.getItem('disable-animations') === 'true';
        document.getElementById('enable-break-reminder').checked = localStorage.getItem('enable-break-reminder') === 'true';
        const breakInterval = localStorage.getItem('break-interval');
        if (breakInterval) { document.getElementById('break-interval').value = breakInterval; }
        // Appearance
        const theme = localStorage.getItem('theme-selector');
        if (theme) { document.getElementById('theme-selector').value = theme; applyTheme(); }
        const customWallpaperUrl = localStorage.getItem('custom-wallpaper-url');
        if (customWallpaperUrl) { document.getElementById('custom-wallpaper-url').value = customWallpaperUrl; }
        const enableCustom = localStorage.getItem('enable-custom-wallpaper') === 'true';
        document.getElementById('enable-custom-wallpaper').checked = enableCustom;
        const enableStar = localStorage.getItem('enable-star-wallpaper') === 'true';
        document.getElementById('enable-star-wallpaper').checked = enableStar;
        if (enableStar) { initStarWallpaper(); }
        else if (enableCustom) { applyCustomWallpaper(customWallpaperUrl); }
        const gradientSpeed = localStorage.getItem('gradient-speed');
        if (gradientSpeed) {
            document.getElementById('gradient-speed').value = gradientSpeed;
            const gradientBg = document.querySelector('.gradient-bg');
            if (gradientBg) { gradientBg.style.animationDuration = `${gradientSpeed}s`; }
        }
        // Effects
        document.getElementById('enable-snowfall').checked = localStorage.getItem('enable-snowfall') === 'true';
        document.getElementById('enable-rain').checked = localStorage.getItem('enable-rain') === 'true';
        document.getElementById('enable-stars').checked = localStorage.getItem('enable-stars') === 'true';
        document.getElementById('enable-fireflies').checked = localStorage.getItem('enable-fireflies') === 'true';
        document.getElementById('enable-floating-emojis').checked = localStorage.getItem('enable-floating-emojis') === 'true';
        document.getElementById('enable-particles').checked = localStorage.getItem('enable-particles') === 'true';
        // Widgets
        document.getElementById('enable-clock-widget').checked = localStorage.getItem('enable-clock-widget') === 'true';
        clockWidget.style.display = (localStorage.getItem('enable-clock-widget') === 'true') ? 'block' : 'none';
        document.getElementById('enable-pomodoro-widget').checked = localStorage.getItem('enable-pomodoro-widget') === 'true';
        pomodoroWidget.style.display = (localStorage.getItem('enable-pomodoro-widget') === 'true') ? 'block' : 'none';
        document.getElementById('enable-todo-widget').checked = localStorage.getItem('enable-todo-widget') === 'true';
        todoWidget.style.display = (localStorage.getItem('enable-todo-widget') === 'true') ? 'block' : 'none';
        document.getElementById('enable-good-day-quote').checked = localStorage.getItem('enable-good-day-quote') === 'true';
        handleGoodDayQuote();
        const savedPomodoroDuration = localStorage.getItem('pomodoro-duration');
        if (savedPomodoroDuration) {
            document.getElementById('pomodoro-duration').value = savedPomodoroDuration;
            pomodoroTime = parseInt(savedPomodoroDuration, 10) * 60;
            updatePomodoroDisplay();
        }
        // Additional general settings
        applyFocusMode(document.getElementById('focus-mode').checked);
        applyAutoDarkMode(document.getElementById('auto-dark-mode').checked);
        applyDisableAnimations(document.getElementById('disable-animations').checked);
        if (document.getElementById('enable-break-reminder').checked) { initBreakReminder(); }
    };
    applySavedSettings();

    /********************************************
     * 13. Additional General Settings Functions
     ********************************************/
    function applyFocusMode(enable) {
        if (enable) {
            document.body.style.filter = "blur(0)";
            document.querySelectorAll('.distracting-element').forEach(el => el.style.display = 'none');
        } else {
            document.querySelectorAll('.distracting-element').forEach(el => el.style.display = '');
        }
    }
    function autoDarkMode() {
        const now = new Date();
        const hour = now.getHours();
        if (hour >= 18 || hour < 6) { document.body.classList.add('dark-mode'); }
        else { document.body.classList.remove('dark-mode'); }
    }
    function applyAutoDarkMode(enable) {
        if (enable) { setInterval(autoDarkMode, 60000); autoDarkMode(); }
    }
    function applyDisableAnimations(enable) {
        if (enable) {
            document.querySelectorAll("*").forEach(el => {
                el.style.animation = "none";
                el.style.transition = "none";
            });
        }
    }
    document.querySelectorAll('input[type="checkbox"]').forEach(checkbox => {
        checkbox.addEventListener('change', function () { saveSetting(this.id, this.checked); });
    });
    document.getElementById('theme-selector').addEventListener('change', applyTheme);

    /********************************************
     * 14. Break Reminder – Hook into General Settings Apply
     ********************************************/
    document.getElementById('apply-general').addEventListener('click', () => {
        const focusMode = document.getElementById('focus-mode').checked;
        const autoDarkModeEnabled = document.getElementById('auto-dark-mode').checked;
        const disableAnimations = document.getElementById('disable-animations').checked;
        const breakReminder = document.getElementById('enable-break-reminder').checked;
        const breakInterval = document.getElementById('break-interval').value;
        saveSetting('focus-mode', focusMode);
        saveSetting('auto-dark-mode', autoDarkModeEnabled);
        saveSetting('disable-animations', disableAnimations);
        saveSetting('enable-break-reminder', breakReminder);
        saveSetting('break-interval', breakInterval);
        applyFocusMode(focusMode);
        applyAutoDarkMode(autoDarkModeEnabled);
        applyDisableAnimations(disableAnimations);
        if (breakReminder) { initBreakReminder(); } else { clearInterval(breakReminderInterval); }
    });

    // End of Script – Your Ultimate Productivity Suite is ready for production!
})();