RGB Script Manager

Control panel for RGB scripts with page load alerts

  1. // ==UserScript==
  2. // @name RGB Script Manager
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.0
  5. // @description Control panel for RGB scripts with page load alerts
  6. // @author Jyomama28
  7. // @match *://*/*
  8. // @grant GM_getValue
  9. // @grant GM_setValue
  10. // @grant GM_registerMenuCommand
  11. // ==/UserScript==
  12.  
  13. (function() {
  14. 'use strict';
  15.  
  16. const rgbTyperEnabled = GM_getValue('rgbTyperEnabled', true);
  17. const rgbCursorEnabled = GM_getValue('rgbCursorEnabled', true);
  18. const pageAlertsEnabled = GM_getValue('pageAlertsEnabled', true);
  19.  
  20. function initRGBTyper() {
  21. const style = document.createElement('style');
  22. style.innerHTML = `
  23. @keyframes rgbText {
  24. 0% { color: rgb(255, 0, 0); }
  25. 33% { color: rgb(0, 255, 0); }
  26. 66% { color: rgb(0, 0, 255); }
  27. 100% { color: rgb(255, 0, 0); }
  28. }
  29. .rgb-animated {
  30. animation: rgbText 3s linear infinite;
  31. }
  32. `;
  33. document.head.appendChild(style);
  34.  
  35. function handleInput(event) {
  36. const element = event.target;
  37. if (
  38. element.tagName === 'INPUT' ||
  39. element.tagName === 'TEXTAREA' ||
  40. element.getAttribute('contenteditable') === 'true'
  41. ) {
  42. element.classList.add('rgb-animated');
  43. if (element.tagName === 'INPUT' || element.tagName === 'TEXTAREA') {
  44. element.style.animation = 'rgbText 3s linear infinite';
  45. }
  46. }
  47. }
  48.  
  49. const observer = new MutationObserver((mutations) => {
  50. mutations.forEach((mutation) => {
  51. mutation.addedNodes.forEach((node) => {
  52. if (node.nodeType === 1) {
  53. const inputs = node.querySelectorAll('input, textarea, [contenteditable="true"]');
  54. inputs.forEach(input => {
  55. input.addEventListener('input', handleInput);
  56. });
  57. }
  58. });
  59. });
  60. });
  61.  
  62. observer.observe(document.body, {
  63. childList: true,
  64. subtree: true
  65. });
  66.  
  67. document.querySelectorAll('input, textarea, [contenteditable="true"]').forEach(input => {
  68. input.addEventListener('input', handleInput);
  69. });
  70. }
  71.  
  72. function initRGBCursor() {
  73. const cursor = document.createElement('div');
  74. cursor.id = 'rainbow-cursor';
  75. const trailCount = 20;
  76. const trail = [];
  77. for (let i = 0; i < trailCount; i++) {
  78. const dot = document.createElement('div');
  79. dot.className = 'rainbow-trail-dot';
  80. document.body.appendChild(dot);
  81. trail.push({
  82. element: dot,
  83. x: 0,
  84. y: 0
  85. });
  86. }
  87. const style = document.createElement('style');
  88. style.innerHTML = `
  89. html, body {
  90. cursor: none !important;
  91. }
  92. #rainbow-cursor {
  93. position: fixed;
  94. pointer-events: none;
  95. width: 10px;
  96. height: 10px;
  97. background: white;
  98. border-radius: 50%;
  99. box-shadow: 0 0 5px rgba(0,0,0,0.5);
  100. z-index: 9999;
  101. transform: translate(-50%, -50%);
  102. }
  103. .rainbow-trail-dot {
  104. position: fixed;
  105. pointer-events: none;
  106. width: 8px;
  107. height: 8px;
  108. border-radius: 50%;
  109. z-index: 9998;
  110. transform: translate(-50%, -50%);
  111. opacity: 0.8;
  112. transition: width 0.1s, height 0.1s;
  113. }
  114. `;
  115. document.head.appendChild(style);
  116. document.body.appendChild(cursor);
  117. let mouseX = 0;
  118. let mouseY = 0;
  119. document.addEventListener('mousemove', (e) => {
  120. mouseX = e.clientX;
  121. mouseY = e.clientY;
  122. cursor.style.left = mouseX + 'px';
  123. cursor.style.top = mouseY + 'px';
  124. });
  125. function updateTrail() {
  126. for (let i = trail.length - 1; i > 0; i--) {
  127. trail[i].x = trail[i-1].x;
  128. trail[i].y = trail[i-1].y;
  129. }
  130. trail[0].x = mouseX;
  131. trail[0].y = mouseY;
  132. trail.forEach((dot, index) => {
  133. const hue = (Date.now() / 20 + index * 10) % 360;
  134. dot.element.style.left = dot.x + 'px';
  135. dot.element.style.top = dot.y + 'px';
  136. dot.element.style.backgroundColor = `hsl(${hue}, 100%, 50%)`;
  137. const size = 8 - (index * 0.3);
  138. if (size > 0) {
  139. dot.element.style.width = size + 'px';
  140. dot.element.style.height = size + 'px';
  141. dot.element.style.opacity = 1 - (index / trail.length);
  142. }
  143. });
  144. requestAnimationFrame(updateTrail);
  145. }
  146. updateTrail();
  147. window.addEventListener('blur', () => {
  148. cursor.style.display = 'none';
  149. trail.forEach(dot => {
  150. dot.element.style.display = 'none';
  151. });
  152. });
  153. window.addEventListener('focus', () => {
  154. cursor.style.display = 'block';
  155. trail.forEach(dot => {
  156. dot.element.style.display = 'block';
  157. });
  158. });
  159. }
  160.  
  161. function showPageAlert() {
  162. if (pageAlertsEnabled) {
  163. alert('Thank you for using my RGB scripts! Enjoy your colorful browsing experience!');
  164. }
  165. }
  166.  
  167. function createMenu() {
  168. const menu = document.createElement('div');
  169. menu.id = 'rgb-script-menu';
  170. const style = document.createElement('style');
  171. style.innerHTML = `
  172. #rgb-script-menu {
  173. position: fixed;
  174. top: 50%;
  175. left: 50%;
  176. transform: translate(-50%, -50%);
  177. background: linear-gradient(135deg, #1a1a1a, #333);
  178. border-radius: 10px;
  179. padding: 20px;
  180. box-shadow: 0 0 20px rgba(0,0,0,0.5);
  181. z-index: 10000;
  182. color: white;
  183. font-family: Arial, sans-serif;
  184. min-width: 300px;
  185. border: 2px solid transparent;
  186. animation: rgbBorder 3s linear infinite;
  187. display: none;
  188. }
  189. @keyframes rgbBorder {
  190. 0% { border-color: rgb(255, 0, 0); }
  191. 33% { border-color: rgb(0, 255, 0); }
  192. 66% { border-color: rgb(0, 0, 255); }
  193. 100% { border-color: rgb(255, 0, 0); }
  194. }
  195. #rgb-script-menu h2 {
  196. margin-top: 0;
  197. text-align: center;
  198. color: white;
  199. animation: rgbText 3s linear infinite;
  200. }
  201. @keyframes rgbText {
  202. 0% { color: rgb(255, 0, 0); }
  203. 33% { color: rgb(0, 255, 0); }
  204. 66% { color: rgb(0, 0, 255); }
  205. 100% { color: rgb(255, 0, 0); }
  206. }
  207. .menu-button {
  208. background: linear-gradient(135deg, #444, #222);
  209. color: white;
  210. border: none;
  211. padding: 10px 15px;
  212. margin: 5px;
  213. border-radius: 5px;
  214. cursor: pointer;
  215. width: 100%;
  216. transition: all 0.3s;
  217. }
  218. .menu-button:hover {
  219. background: linear-gradient(135deg, #555, #333);
  220. transform: translateY(-2px);
  221. }
  222. .toggle-on {
  223. background: linear-gradient(135deg, #4CAF50, #2E7D32);
  224. }
  225. .toggle-off {
  226. background: linear-gradient(135deg, #F44336, #C62828);
  227. }
  228. .tab-content {
  229. display: none;
  230. }
  231. .tab-content.active {
  232. display: block;
  233. }
  234. .tab-buttons {
  235. display: flex;
  236. margin-bottom: 10px;
  237. }
  238. .tab-button {
  239. flex: 1;
  240. padding: 8px;
  241. background: #444;
  242. border: none;
  243. color: white;
  244. cursor: pointer;
  245. }
  246. .tab-button.active {
  247. background: #666;
  248. }
  249. .close-button {
  250. position: absolute;
  251. top: 5px;
  252. right: 5px;
  253. background: none;
  254. border: none;
  255. color: white;
  256. font-size: 20px;
  257. cursor: pointer;
  258. }
  259. `;
  260. document.head.appendChild(style);
  261. menu.innerHTML = `
  262. <button class="close-button">&times;</button>
  263. <h2>RGB Script Manager</h2>
  264. <div class="tab-buttons">
  265. <button class="tab-button active" data-tab="main">Main</button>
  266. <button class="tab-button" data-tab="about">About</button>
  267. <button class="tab-button" data-tab="help">Help</button>
  268. </div>
  269. <div id="main-tab" class="tab-content active">
  270. <button id="toggle-typer" class="menu-button ${rgbTyperEnabled ? 'toggle-on' : 'toggle-off'}">
  271. RGB Typer: ${rgbTyperEnabled ? 'ON' : 'OFF'}
  272. </button>
  273. <button id="toggle-cursor" class="menu-button ${rgbCursorEnabled ? 'toggle-on' : 'toggle-off'}">
  274. RGB Cursor: ${rgbCursorEnabled ? 'ON' : 'OFF'}
  275. </button>
  276. <button id="toggle-alerts" class="menu-button ${pageAlertsEnabled ? 'toggle-on' : 'toggle-off'}">
  277. Page Alerts: ${pageAlertsEnabled ? 'ON' : 'OFF'}
  278. </button>
  279. </div>
  280. <div id="about-tab" class="tab-content">
  281. <p>RGB Script Manager v1.0</p>
  282. <p>Created by Jyomama28</p>
  283. <p>Control your RGB scripts with this handy panel.</p>
  284. </div>
  285. <div id="help-tab" class="tab-content">
  286. <p><strong>Hotkey:</strong> Press \` (backtick) to toggle this menu</p>
  287. <p><strong>RGB Typer:</strong> Animates text in input fields with RGB colors</p>
  288. <p><strong>RGB Cursor:</strong> Replaces your cursor with a rainbow trail</p>
  289. <p><strong>Page Alerts:</strong> Shows a welcome message on new pages</p>
  290. </div>
  291. `;
  292. document.body.appendChild(menu);
  293. const closeButton = menu.querySelector('.close-button');
  294. closeButton.addEventListener('click', () => {
  295. menu.style.display = 'none';
  296. });
  297. const tabButtons = menu.querySelectorAll('.tab-button');
  298. tabButtons.forEach(button => {
  299. button.addEventListener('click', () => {
  300. tabButtons.forEach(btn => btn.classList.remove('active'));
  301. button.classList.add('active');
  302. const tabId = button.getAttribute('data-tab') + '-tab';
  303. document.querySelectorAll('.tab-content').forEach(content => {
  304. content.classList.remove('active');
  305. });
  306. document.getElementById(tabId).classList.add('active');
  307. });
  308. });
  309. const toggleTyper = menu.querySelector('#toggle-typer');
  310. toggleTyper.addEventListener('click', () => {
  311. const newState = !GM_getValue('rgbTyperEnabled', true);
  312. GM_setValue('rgbTyperEnabled', newState);
  313. toggleTyper.textContent = `RGB Typer: ${newState ? 'ON' : 'OFF'}`;
  314. toggleTyper.className = `menu-button ${newState ? 'toggle-on' : 'toggle-off'}`;
  315. if (newState) initRGBTyper();
  316. });
  317. const toggleCursor = menu.querySelector('#toggle-cursor');
  318. toggleCursor.addEventListener('click', () => {
  319. const newState = !GM_getValue('rgbCursorEnabled', true);
  320. GM_setValue('rgbCursorEnabled', newState);
  321. toggleCursor.textContent = `RGB Cursor: ${newState ? 'ON' : 'OFF'}`;
  322. toggleCursor.className = `menu-button ${newState ? 'toggle-on' : 'toggle-off'}`;
  323. if (newState) initRGBCursor();
  324. });
  325. const toggleAlerts = menu.querySelector('#toggle-alerts');
  326. toggleAlerts.addEventListener('click', () => {
  327. const newState = !GM_getValue('pageAlertsEnabled', true);
  328. GM_setValue('pageAlertsEnabled', newState);
  329. toggleAlerts.textContent = `Page Alerts: ${newState ? 'ON' : 'OFF'}`;
  330. toggleAlerts.className = `menu-button ${newState ? 'toggle-on' : 'toggle-off'}`;
  331. });
  332. return menu;
  333. }
  334.  
  335. let menu = null;
  336. let menuVisible = false;
  337.  
  338. function toggleMenu() {
  339. if (!menu) {
  340. menu = createMenu();
  341. }
  342. menuVisible = !menuVisible;
  343. menu.style.display = menuVisible ? 'block' : 'none';
  344. }
  345.  
  346. document.addEventListener('keydown', (e) => {
  347. if (e.key === '`' || e.key === '~') {
  348. toggleMenu();
  349. }
  350. });
  351.  
  352. if (rgbTyperEnabled) initRGBTyper();
  353. if (rgbCursorEnabled) initRGBCursor();
  354.  
  355. window.addEventListener('load', showPageAlert);
  356. window.addEventListener('hashchange', showPageAlert);
  357. window.addEventListener('popstate', showPageAlert);
  358. })();