您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
A cellphone on the canvas: EVERYTHING universally visible, text and icons only with lines. Now with a draggable control menu.
// ==UserScript== // @name Drawaria Canvas Phone // @namespace http://tampermonkey.net/ // @version 2.3 // @description A cellphone on the canvas: EVERYTHING universally visible, text and icons only with lines. Now with a draggable control menu. // @author YouTubeDrawaria // @match https://drawaria.online/* // @grant none // @license MIT // @icon https://www.google.com/s2/favicons?sz=64&domain=drawaria.online // @run-at document-idle // ==/UserScript== (function() { 'use strict'; // --- LETTER PATHS (clean & unified) --- const letterPaths = { a: [[10, 40], [20, 0], [30, 40], [25, 20], [15, 20]], b: [[0, 0], [0, 40], [15, 40], [20, 35], [20, 25], [15, 20], [0, 20], [15, 20], [20, 15], [20, 5], [15, 0], [0, 0]], c: [[20, 0], [0, 0], [0, 40], [20, 40]], d: [[0, 0], [0, 40], [15, 40], [30, 20], [15, 0], [0, 0]], e: [[30, 0], [0, 0], [0, 20], [20, 20], [0, 20], [0, 40], [30, 40]], f: [[0, 0], [0, 40], [20, 40], null, [0, 20], [15, 20]], g: [[30, 10], [20, 0], [10, 0], [0, 10], [0, 30], [10, 40], [20, 40], [30, 30], [20, 20]], i: [[10, 0], [10, 40]], j: [[20, 0], [20, 40], [10, 40], [0, 30]], l: [[0, 0], [0, 40], [20, 40]], m: [[0, 40], [0, 0], [10, 20], [20, 0], [20, 40]], n: [[0, 40], [0, 0], [20, 40], [20, 0]], o: [[10, 0], [20, 0], [30, 10], [30, 30], [20, 40], [10, 40], [0, 30], [0, 10], [10, 0]], p: [[0, 40], [0, 0], [10, 0], [20, 10], [10, 20], [0, 20]], r: [[0, 40], [0, 0], [20, 0], [20, 20], [0, 20], [20, 40]], s: [[20, 0], [10, 0], [0, 10], [20, 20], [30, 30], [20, 40], [10, 40], [0, 30]], t: [[10, 0], [10, 40], null, [1, 0], [20, 0]], u: [[0, 0], [0, 30], [10, 40], [20, 40], [30, 30], [30, 0]], v: [[0, 0], [15, 40], [30, 0]], z: [[7.5, 35], [9, 36]], ' ': [[0, 0]], // Path vacío para el espacio // números: 0: [[10, 0], [20, 0], [30, 10], [30, 30], [20, 40], [10, 40], [0, 30], [0, 10], [10, 0]], 1: [[15, 0], [15, 40], null, [15, 0], [10, 10], null, [10, 40], [20, 40]], 2: [[0, 10], [10, 0], [20, 0], [30, 10], [0, 40], [30, 40]], 3: [[0, 10], [10, 0], [20, 0], [30, 10], [20, 20], [30, 30], [20, 40], [10, 40], [0, 30]], 4: [[20, 0], [20, 40], null, [0, 20], [25, 20], null, [0, 20], [20, 0]], 5: [[30, 0], [0, 0], [0, 20], [20, 20], [30, 30], [20, 40], [10, 40], [0, 30]], 6: [[30, 10], [20, 0], [10, 0], [0, 10], [0, 30], [10, 40], [20, 40], [30, 30], [20, 20], [10, 20], [0, 20], [0, 10]], 7: [[0, 0], [30, 0], [15, 40]], 8: [[15, 0], [25, 10], [15, 20], [5, 10], [15, 0], null, [15, 20], [25, 30], [15, 40], [5, 30], [15, 20]], 9: [[5, 35], [15, 40], [25, 30], [30, 10], [20, 0], [10, 0], [0, 10], [5, 20], [15, 20], [25, 20], [27.5, 20]], }; function drawLetter(path, startX, startY, fontSize, color, thickness) { const scale = fontSize / 40; for (let i = 0; i < path.length - 1; i++) { if (path[i] === null || path[i + 1] === null) continue; const [x1, y1] = path[i], [x2, y2] = path[i + 1]; drawLineServerLocal( startX + x1 * scale, startY + y1 * scale, startX + x2 * scale, startY + y2 * scale, color, thickness ); } } function drawText(str, x, y, color, thickness = 2, fontSize = 18) { let cx = x; for (const char of str) { const path = letterPaths[char.toLowerCase()]; if (path) { drawLetter(path, cx, y, fontSize, color, thickness); } cx += fontSize * 0.6; } } // --- DRAWARIA ADAPTERS --- let drawariaSocket = null, drawariaCanvas = null, drawariaCtx = null; function waitUntilReady() { return new Promise(resolve => { const check = () => { drawariaCanvas = drawariaCanvas || document.getElementById('canvas'); if (drawariaCanvas) { drawariaCtx = drawariaCtx || drawariaCanvas.getContext('2d'); } if (!drawariaSocket && window.WebSocket && window.WebSocket.prototype) { const origSend = WebSocket.prototype.send; WebSocket.prototype.send = function(...args) { if (this.url && this.url.includes('drawaria')) { drawariaSocket = this; WebSocket.prototype.send = origSend; // Restore original send resolve(); } return origSend.apply(this, args); }; } if (drawariaCanvas && drawariaCtx && drawariaSocket) { resolve(); } else { setTimeout(check, 250); } }; check(); }); } function drawLineServerLocal(x1, y1, x2, y2, color = '#222', thickness = 3) { if (!drawariaSocket || !drawariaCanvas) return; const nx1 = (x1 / drawariaCanvas.width).toFixed(4), ny1 = (y1 / drawariaCanvas.height).toFixed(4), nx2 = (x2 / drawariaCanvas.width).toFixed(4), ny2 = (y2 / drawariaCanvas.height).toFixed(4); const cmd = `42["drawcmd",0,[${nx1},${ny1},${nx2},${ny2},false,${-Math.abs(thickness)},"${color}",0,0,{}]]`; drawariaSocket.send(cmd); drawariaCtx.save(); drawariaCtx.strokeStyle = color; drawariaCtx.lineWidth = thickness; drawariaCtx.lineCap = 'round'; drawariaCtx.beginPath(); drawariaCtx.moveTo(x1, y1); drawariaCtx.lineTo(x2, y2); drawariaCtx.stroke(); drawariaCtx.restore(); } function drawFilledRect(x, y, w, h, color = '#eee') { for (let i = 0; i < h; i += 4) drawLineServerLocal(x, y + i, x + w, y + i, color, 4); } function drawRectServerLocal(x, y, w, h, color = '#222', thickness = 3) { drawLineServerLocal(x, y, x + w, y, color, thickness); drawLineServerLocal(x + w, y, x + w, y + h, color, thickness); drawLineServerLocal(x + w, y + h, x, y + h, color, thickness); drawLineServerLocal(x, y + h, x, y, color, thickness); } // --- PHONE UI --- const phoneW = 220, phoneH = 420; function getPhoneRect() { if (!drawariaCanvas) return { x: 40, y: 40, w: phoneW, h: phoneH }; const x = drawariaCanvas.width - phoneW - 32, y = drawariaCanvas.height - phoneH - 32; return { x, y, w: phoneW, h: phoneH }; } let phoneState = 'home', lastButtons = [], lastCalcInput = "", isPhoneActive = false; function drawAppButton(x, y, w, h, action, bgColor, borderColor, icon, iconColor, text, textColor) { drawFilledRect(x, y, w, h, bgColor); drawRectServerLocal(x, y, w, h, borderColor, 2); drawText(icon, x + (w * 0.28), y + 6, iconColor, 3, 23); drawText(text, x + 2, y + 30, textColor, 2, 10); lastButtons.push({ x, y, w, h, action }); } // --- MAIN RENDER --- function renderPhone() { if (!drawariaCanvas || !isPhoneActive) return; const { x, y, w, h } = getPhoneRect(); // Fondo y marco del teléfono drawFilledRect(x, y, w, h, '#F9F9F9'); drawRectServerLocal(x, y, w, h, '#222', 8); drawFilledRect(x + w / 2 - 30, y + 8, 60, 12, '#AAA'); // notch drawFilledRect(x + w / 2 - 20, y + h - 22, 40, 8, '#CCC'); // home btn // Renderizado basado en el estado switch (phoneState) { case 'home': drawText("a n d r o i d", x + 28, y + 31, '#17A', 3, 17); lastButtons = []; drawAppButton(x + 22, y + 79, 45, 45, 'open_football', '#FAFAFF', '#222', 'f', '#173', 't e a m', '#222'); drawAppButton(x + 89, y + 79, 45, 45, 'open_notes', '#FFFDE9', '#222', 'n', '#962', 'n o t e', '#222'); drawAppButton(x + 156, y + 79, 45, 45, 'open_calc', '#EAEEFF', '#222', 'c', '#246', 'c a r s', '#222'); drawAppButton(x + 58, y + 151, 45, 45, 'open_clock', '#F6FFEA', '#222', 'r', '#184', 'r e a d', '#222'); drawAppButton(x + 125, y + 151, 45, 45, 'open_gallery', '#FAEEFF', '#222', 'g', '#71a', 'g a m e', '#222'); break; case 'football': drawText("f u t b o l", x + 50, y + 36, '#173', 3, 18); drawText("b o l a", x + 66, y + 100, '#222', 2, 18); // "mini balón" con líneas y círculo for (let r = 0; r <= 24; r += 3) { const angle = r; drawLineServerLocal(x + w / 2, y + 160, x + w / 2 + Math.cos(angle) * 19, y + 160 + Math.sin(angle) * 19, '#173', 3); } drawFilledRect(x + w / 2 - 4, y + 160 - 4, 9, 9, '#EEE'); break; case 'notes': drawText("n o t a s", x + 71, y + 36, '#962', 3, 18); drawFilledRect(x + 36, y + 80, w - 72, 130, '#fffbe0'); drawRectServerLocal(x + 36, y + 80, w - 72, 130, '#555', 2); drawText("t o m a n o t a !", x + 62, y + 170, "#333", 2, 15); break; case 'calc': drawText("c a l c", x + 68, y + 36, '#246', 3, 18); drawFilledRect(x + 31, y + 80, w - 62, 38, '#f4f7fd'); drawRectServerLocal(x + 31, y + 80, w - 62, 38, '#222', 2); drawText(lastCalcInput || "3 + 2 * 6", x + 45, y + 93, '#246', 2, 18); // Pad 1-9,+,- const bw = 33, bh = 22, pad = 7, cols = 3; const numpad = ['7', '8', '9', '4', '5', '6', '1', '2', '3', '0', '+', '-']; lastButtons = []; for (let i = 0; i < numpad.length; i++) { const bx = x + 38 + ((i % cols) * (bw + pad)), by = y + 132 + (Math.floor(i / cols) * (bh + pad)); drawFilledRect(bx, by, bw, bh, '#eef2f4'); drawRectServerLocal(bx, by, bw, bh, '#222', 2); drawText(numpad[i], bx + 12, by + 3, '#246', 14, 14); lastButtons.push({ x: bx, y: by, w: bw, h: bh, action: 'calcpress', val: numpad[i] }); } // Igual y CE const eqx = x + 38, eqy = y + 132 + (4 * (bh + pad)); drawFilledRect(eqx, eqy, bw + pad, bh, '#86b089'); drawText('=', eqx + 19, eqy + 3, '#fff', 2, 17); lastButtons.push({ x: eqx, y: eqy, w: bw + pad, h: bh, action: 'equals' }); const cex = eqx + (bw + pad) * 2, cey = eqy; drawFilledRect(cex, cey, bw + pad, bh, '#df3434'); drawText('c e', cex + 11, cey + 3, '#fff', 2, 17); lastButtons.push({ x: cex, y: cey, w: bw + pad, h: bh, action: 'ce' }); break; case 'clock': drawText("r e l o j", x + 64, y + 36, '#184', 3, 18); const cx = x + w / 2, cy = y + 155, radius = 44; for (let i = 0; i < 60; i++) { if (i % 5 === 0) { const angle = Math.PI * 2 * i / 60 - Math.PI / 2; drawLineServerLocal(cx + Math.cos(angle) * radius, cy + Math.sin(angle) * radius, cx + Math.cos(angle) * (radius - 7), cy + Math.sin(angle) * (radius - 7), '#262', 3); } } const date = new Date(); const h = date.getHours() % 12, m = date.getMinutes(), s = date.getSeconds(); const ah = Math.PI * 2 * (h + m / 60) / 12 - Math.PI / 2; const am = Math.PI * 2 * m / 60 - Math.PI / 2; const as = Math.PI * 2 * s / 60 - Math.PI / 2; drawLineServerLocal(cx, cy, cx + Math.cos(ah) * 22, cy + Math.sin(ah) * 22, '#222', 7); drawLineServerLocal(cx, cy, cx + Math.cos(am) * 32, cy + Math.sin(am) * 32, '#262', 5); drawLineServerLocal(cx, cy, cx + Math.cos(as) * 38, cy + Math.sin(as) * 38, '#b81f26', 2); break; case 'gallery': drawText("g a l e r", x + 74, y + 36, '#71a', 3, 18); const galleryImgs = [{ bg: '#ffe', border: '#e5c' }, { bg: '#ddf', border: '#8cf' }, { bg: '#f8f', border: '#db5' }]; for (let g = 0; g < galleryImgs.length; g++) { const gx = x + 40 + (g * 39), gy = y + 75; drawFilledRect(gx, gy, 32, 39, galleryImgs[g].bg); drawRectServerLocal(gx, gy, 32, 39, galleryImgs[g].border, 2); drawText("g", gx + 13, gy + 9, "#222", 2, 17); } drawText("O b r a s !", x + 75, y + 140, "#71a", 2, 16); break; } // Botón 'volver' común a todas las apps if (phoneState !== 'home') { const btnColor = (phoneState === 'football') ? '#272' : (phoneState === 'notes' ? '#962' : (phoneState === 'calc' ? '#246' : (phoneState === 'clock' ? '#184' : '#71a'))); lastButtons.push({ x: x + 38, y: y + h - 56, w: w - 76, h: 32, action: 'home' }); drawFilledRect(x + 38, y + h - 56, w - 76, 32, '#DDD'); drawRectServerLocal(x + 38, y + h - 56, w - 76, 32, '#222', 2); drawText("v o l v e r", x + 61, y + h - 50, btnColor, 2, 17); } } // --- HANDLE CLICK --- function getMouseCanvasCoords(e) { const rect = drawariaCanvas.getBoundingClientRect(); return { x: (e.clientX - rect.left) * (drawariaCanvas.width / rect.width), y: (e.clientY - rect.top) * (drawariaCanvas.height / rect.height) }; } function onCanvasClick(e) { if (!isPhoneActive) return; const { x: cx, y: cy } = getMouseCanvasCoords(e); for (const btn of lastButtons) { if (cx >= btn.x && cx <= btn.x + btn.w && cy >= btn.y && cy <= btn.y + btn.h) { switch (btn.action) { case 'open_football': phoneState = 'football'; break; case 'open_notes': phoneState = 'notes'; break; case 'open_calc': phoneState = 'calc'; break; case 'open_clock': phoneState = 'clock'; break; case 'open_gallery': phoneState = 'gallery'; break; case 'home': phoneState = 'home'; break; case 'calcpress': lastCalcInput += btn.val; break; case 'equals': try { lastCalcInput = String(eval(lastCalcInput.replace(/--/g, '+'))); } catch { lastCalcInput = "ERR"; } break; case 'ce': lastCalcInput = ""; break; } renderPhone(); return; } } } // --- MAIN BOOT --- waitUntilReady().then(() => { // Inicializar el menú de control createControlMenu(); // Renderizar el teléfono y el menú const renderLoop = () => { renderPhone(); // El menú se mantiene en el DOM, no necesita renderizarse en el canvas }; setInterval(renderLoop, 2800); drawariaCanvas.addEventListener('click', onCanvasClick); window.addEventListener('keydown', (e) => { if (e.key === 'h' && isPhoneActive) { phoneState = 'home'; renderPhone(); } }); }); // --- CONTROL MENU --- function createControlMenu() { // Crear el elemento del menú const menu = document.createElement('div'); menu.id = 'drawaria-phone-menu'; menu.style.cssText = ` position: absolute; top: 20px; left: 20px; width: 200px; background: linear-gradient(135deg, #1e3c72 0%, #2a5298 100%); border-radius: 12px; box-shadow: 0 4px 15px rgba(0, 0, 0, 0.4); color: #fff; font-family: Arial, sans-serif; z-index: 10000; padding: 15px; cursor: move; `; menu.innerHTML = ` <h4 style="margin: 0 0 10px; font-weight: bold; text-align: center;">Phone Control</h4> <div style="display: flex; flex-direction: column; gap: 10px;"> <button id="toggle-phone" style=" padding: 8px; border: none; border-radius: 8px; background-color: #e2a04a; color: white; font-size: 14px; font-weight: bold; cursor: pointer; transition: background-color 0.3s; ">Turn On</button> <button id="reset-phone" style=" padding: 8px; border: none; border-radius: 8px; background-color: #8c73d9; color: white; font-size: 14px; font-weight: bold; cursor: pointer; transition: background-color 0.3s; ">Reset Home</button> </div> `; document.body.appendChild(menu); // Hacer el menú arrastrable let isDragging = false; let offset = { x: 0, y: 0 }; const header = menu.querySelector('h4'); header.addEventListener('mousedown', (e) => { isDragging = true; offset.x = e.clientX - menu.offsetLeft; offset.y = e.clientY - menu.offsetTop; menu.style.cursor = 'grabbing'; e.preventDefault(); }); document.addEventListener('mousemove', (e) => { if (isDragging) { menu.style.left = `${e.clientX - offset.x}px`; menu.style.top = `${e.clientY - offset.y}px`; } }); document.addEventListener('mouseup', () => { isDragging = false; menu.style.cursor = 'move'; }); // Lógica de los botones const toggleButton = document.getElementById('toggle-phone'); const resetButton = document.getElementById('reset-phone'); toggleButton.addEventListener('click', () => { isPhoneActive = !isPhoneActive; if (isPhoneActive) { toggleButton.textContent = 'Turn Off'; toggleButton.style.backgroundColor = '#4a90e2'; renderPhone(); } else { toggleButton.textContent = 'Turn On'; toggleButton.style.backgroundColor = '#e2a04a'; // Borrar el teléfono del canvas al apagarlo drawLineServerLocal(0, 0, 0, 0, '#fff', 9999); } }); resetButton.addEventListener('click', () => { phoneState = 'home'; if (isPhoneActive) { renderPhone(); } }); } })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址