您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Agrega un botón flotante 🎮 que abre un menú con una sección "Colores" (incluye modo Arcoíris) para dibujar en drawaria.online. El color se fuerza a nivel de canvas para que funcione aunque la página cambie su UI.
// ==UserScript== // @name Drawaria – Menú de Colores (Arcoíris) // @namespace https://example.com/userscripts // @version 1.0.0 // @description Agrega un botón flotante 🎮 que abre un menú con una sección "Colores" (incluye modo Arcoíris) para dibujar en drawaria.online. El color se fuerza a nivel de canvas para que funcione aunque la página cambie su UI. // @match https://drawaria.online/* // @run-at document-idle // @grant none // ==/UserScript== (function () { 'use strict'; /*** --------------------------------------------- * ColorManager — Fuente de la verdad del color * --------------------------------------------- */ const ColorManager = { enabled: true, mode: localStorage.getItem('rainbow_menu_mode') || 'solid', // 'solid' | 'rainbow' color: localStorage.getItem('rainbow_menu_color') || '#ff007a', hue: parseInt(localStorage.getItem('rainbow_menu_hue') || '0', 10), getCurrentColor() { if (!this.enabled) return null; if (this.mode === 'rainbow') { const h = this.hue % 360; this.hue = (this.hue + 4) % 360; // velocidad del arcoíris localStorage.setItem('rainbow_menu_hue', String(this.hue)); return `hsl(${h} 100% 50%)`; } return this.color; }, setSolid(hex) { this.mode = 'solid'; this.color = hex; localStorage.setItem('rainbow_menu_mode', 'solid'); localStorage.setItem('rainbow_menu_color', hex); }, setRainbow() { this.mode = 'rainbow'; localStorage.setItem('rainbow_menu_mode', 'rainbow'); } }; /*** --------------------------------------------- * Parcheo de CanvasRenderingContext2D * --------------------------------------------- * En vez de tocar la UI del juego, forzamos el color * a nivel de canvas. Esto hace el script resistente * a cambios en el DOM de drawaria. */ function patchCtx(ctx) { if (!ctx || ctx.__rainbowPatched) return; const applyColor = () => { const c = ColorManager.getCurrentColor(); if (c) { // Forzamos tanto trazo como relleno try { ctx.strokeStyle = c; } catch (e) {} try { ctx.fillStyle = c; } catch (e) {} } }; const wrap = (obj, key, before) => { const orig = obj[key]; if (typeof orig !== 'function') return; obj[key] = function (...args) { try { before && before(this, args); } catch (e) { /* noop */ } return orig.apply(this, args); }; }; // Cambiamos color en trazos y también mientras se dibujan segmentos wrap(ctx, 'stroke', () => applyColor()); wrap(ctx, 'fill', () => applyColor()); wrap(ctx, 'lineTo', () => applyColor()); wrap(ctx, 'bezierCurveTo', () => applyColor()); wrap(ctx, 'quadraticCurveTo', () => applyColor()); wrap(ctx, 'arc', () => applyColor()); ctx.__rainbowPatched = true; } // Parchear todos los contextos 2D existentes y futuros (function patchAllCanvases() { const origGetContext = HTMLCanvasElement.prototype.getContext; HTMLCanvasElement.prototype.getContext = function (type, ...rest) { const ctx = origGetContext.call(this, type, ...rest); if (type === '2d' && ctx) patchCtx(ctx); return ctx; }; // Canvases ya presentes for (const cv of document.querySelectorAll('canvas')) { try { const c = cv.getContext('2d'); if (c) patchCtx(c); } catch (e) {} } })(); /*** --------------------------------------------- * UI — Botón 🎮 y Panel con "Colores" * --------------------------------------------- */ const style = document.createElement('style'); style.textContent = ` .rbw-floating-btn { position: fixed; right: 16px; bottom: 16px; z-index: 999999; width: 56px; height: 56px; border-radius: 50%; border: none; cursor: pointer; font-size: 24px; box-shadow: 0 8px 24px rgba(0,0,0,.25); background: linear-gradient(135deg, #ff007a, #7a00ff); color: white; display:flex; align-items:center; justify-content:center; } .rbw-floating-btn:hover { transform: translateY(-1px); } .rbw-panel { position: fixed; right: 16px; bottom: 84px; width: 300px; max-width: calc(100vw - 32px); background: #0d0d10; color: white; border-radius: 16px; box-shadow: 0 16px 48px rgba(0,0,0,.35); overflow: hidden; z-index: 999998; display: none; } .rbw-panel.open { display: block; animation: rbw-pop .16s ease-out; } @keyframes rbw-pop { from { transform: translateY(6px); opacity: .6; } to { transform: translateY(0); opacity: 1; } } .rbw-header { display:flex; align-items:center; justify-content:space-between; padding: 10px 12px; background: linear-gradient(90deg, red, orange, yellow, green, cyan, blue, violet); color: #111; font-weight: 800; } .rbw-close { background: transparent; border: none; font-size: 18px; line-height: 1; cursor: pointer; padding: 6px; color: #111; } .rbw-body { padding: 10px 12px 14px; } .rbw-section { margin-top: 8px; border: 1px solid #2a2a33; border-radius: 12px; overflow: hidden; } .rbw-section-head { display:flex; align-items:center; justify-content:space-between; background:#15151b; padding: 8px 10px; cursor:pointer; } .rbw-section-title { font-weight: 700; } .rbw-toggle { border: none; background: #242432; color: #d9d9e3; border-radius: 10px; padding: 6px 10px; cursor:pointer; } .rbw-section-body { padding: 10px; display:none; } .rbw-section.open .rbw-section-body { display:block; } .rbw-swatches { display:grid; grid-template-columns: repeat(8, 1fr); gap: 6px; } .rbw-swatch { width: 28px; height: 28px; border-radius: 6px; border: 2px solid rgba(255,255,255,.25); cursor:pointer; } .rbw-swatch[aria-selected="true"] { outline: 2px solid white; outline-offset: 2px; } .rbw-chip { display:inline-flex; align-items:center; gap:8px; background:#15151b; border:1px solid #2a2a33; border-radius:999px; padding:6px 10px; font-size:12px; } .rbw-chip .dot { width:14px; height:14px; border-radius:50%; border:1px solid rgba(255,255,255,.35); } `; document.head.appendChild(style); // Botón flotante 🎮 const fab = document.createElement('button'); fab.className = 'rbw-floating-btn'; fab.title = 'Abrir menú de dibujo'; fab.textContent = '🎮'; // Panel const panel = document.createElement('div'); panel.className = 'rbw-panel'; panel.innerHTML = ` <div class="rbw-header"> <div>Menú de Dibujo</div> <button class="rbw-close" title="Cerrar">✕</button> </div> <div class="rbw-body"> <div class="rbw-chip" id="rbw-status"> <span class="dot"></span> <span>Color activo</span> </div> <div class="rbw-section" id="rbw-colores"> <div class="rbw-section-head"> <div class="rbw-section-title">Colores</div> <button class="rbw-toggle" type="button">Mostrar</button> </div> <div class="rbw-section-body"> <div class="rbw-swatches" id="rbw-swatches"></div> <div style="margin-top:10px; display:flex; gap:8px; flex-wrap:wrap;"> <button id="rbw-solid" class="rbw-toggle" type="button">Modo sólido</button> <button id="rbw-rainbow" class="rbw-toggle" type="button">Arcoíris</button> <input id="rbw-picker" type="color" style="margin-left:auto; background:#15151b; border:1px solid #2a2a33; border-radius:10px; width:44px; height:32px; padding:0;" title="Elegir color" /> </div> </div> </div> </div> `; document.body.appendChild(fab); document.body.appendChild(panel); // Interacciones del panel const closeBtn = panel.querySelector('.rbw-close'); const coloresSection = panel.querySelector('#rbw-colores'); const coloresToggle = coloresSection.querySelector('.rbw-toggle'); const swatchesBox = panel.querySelector('#rbw-swatches'); const picker = panel.querySelector('#rbw-picker'); const btnSolid = panel.querySelector('#rbw-solid'); const btnRainbow = panel.querySelector('#rbw-rainbow'); const statusDot = panel.querySelector('#rbw-status .dot'); const preset = [ '#000000', '#444444', '#7f7f7f', '#bfbfbf', '#ffffff', '#ff0000', '#ff7f00', '#ffff00', '#00ff00', '#00ffff', '#0000ff', '#7f00ff', '#ff00ff', '#ff4d6d', '#ff8fa3', '#ffd166', '#06d6a0', '#118ab2', '#073b4c', '#f72585', '#b5179e', '#7209b7', '#3a0ca3', '#4361ee', '#4cc9f0', ]; function updateStatus() { const c = ColorManager.mode === 'rainbow' ? `conic-gradient(from 0deg, red, orange, yellow, green, cyan, blue, violet, red)` : ColorManager.color; statusDot.style.background = c; } function makeSwatches() { swatchesBox.innerHTML = ''; // Swatch especial: Arcoíris const rainbow = document.createElement('button'); rainbow.className = 'rbw-swatch'; rainbow.title = 'Arcoíris'; rainbow.style.background = 'conic-gradient(from 0deg, red, orange, yellow, green, cyan, blue, violet, red)'; rainbow.addEventListener('click', () => { ColorManager.setRainbow(); updateStatus(); markSelected(null); }); swatchesBox.appendChild(rainbow); // Swatches de colores sólidos for (const hex of preset) { const b = document.createElement('button'); b.className = 'rbw-swatch'; b.style.background = hex; b.setAttribute('data-hex', hex); b.addEventListener('click', () => { ColorManager.setSolid(hex); picker.value = hex; updateStatus(); markSelected(hex); }); swatchesBox.appendChild(b); } } function markSelected(hex) { for (const el of swatchesBox.querySelectorAll('.rbw-swatch')) { const isSel = el.getAttribute('data-hex') === hex && ColorManager.mode === 'solid'; el.setAttribute('aria-selected', isSel ? 'true' : 'false'); } } // Eventos UI fab.addEventListener('click', () => panel.classList.toggle('open')); closeBtn.addEventListener('click', () => panel.classList.remove('open')); coloresToggle.addEventListener('click', () => { coloresSection.classList.toggle('open'); coloresToggle.textContent = coloresSection.classList.contains('open') ? 'Ocultar' : 'Mostrar'; }); btnSolid.addEventListener('click', () => { if (ColorManager.mode !== 'solid') ColorManager.setSolid(ColorManager.color); updateStatus(); }); btnRainbow.addEventListener('click', () => { ColorManager.setRainbow(); updateStatus(); markSelected(null); }); picker.addEventListener('input', (e) => { ColorManager.setSolid(e.target.value); updateStatus(); markSelected(e.target.value.toLowerCase()); }); // Inicialización makeSwatches(); updateStatus(); markSelected(ColorManager.mode === 'solid' ? ColorManager.color.toLowerCase() : null); // Auto-abrir la sección de Colores la primera vez if (!localStorage.getItem('rainbow_menu_seen')) { panel.classList.add('open'); coloresSection.classList.add('open'); coloresToggle.textContent = 'Ocultar'; localStorage.setItem('rainbow_menu_seen', '1'); } })();