// ==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!
})();