Greasy Fork is available in English.
Gartic.io Better
// ==UserScript==
// @name GarticBetter
// @namespace http://tampermonkey.net/
// @version 1.0
// @description Gartic.io Better
// @author iQuez
// @homepageURL https://discord.gg/2c4qhYudBP
// @license MIT
// @match *://gartic.io/*
// @icon https://i.ibb.co/5WD8w1yK/Gartic-Better.png
// @grant none
// ==/UserScript==
(function() {
'use strict';
let settings = JSON.parse(localStorage.getItem('iquez_settings') || JSON.stringify({
borderColor: '#ff0000',
nameColor: '#ffffff',
chatColor: '#ff0000',
enableBorder: true,
enableNameColor: true,
enableChatColor: true,
enablePing: true,
enableDarkMode: true
}));
let capturedAvatarUrl = '';
const style = document.createElement('style');
const updateStyles = () => {
let baseCSS = `
.scrollElements a { position: relative !important; padding-bottom: 35px !important; }
.iquez-watch-btn {
position: absolute; bottom: 8px; left: 8px; background-color: #0a5efb;
color: white; border: none; border-radius: 5px; padding: 5px 0; font-weight: bold; font-size: 11px;
cursor: pointer; box-shadow: 0 3px 0 #0742b8; transition: all 0.1s ease; text-transform: uppercase;
width: calc(100% - 16px); display: block; text-align: center; z-index: 10;
}
#popUp.iquez-my-popup .content.profile .contentPopup .avatar,
.home .anonymus .avatar,
.logged .userLogged .avatar,
.user.you .avatar {
box-shadow: ${settings.enableBorder ? `0 0 0 4px ${settings.borderColor}` : 'none'} !important;
border-radius: 50% !important;
border-color: transparent !important;
}
.home .anonymus .avatar {
overflow: visible !important;
}
.selectAvatar {
z-index: 10 !important;
}
#popUp.iquez-my-popup .content.profile .contentPopup .avatar canvas,
#popUp.iquez-my-popup .content.profile .contentPopup .avatar .av {
width: 100% !important;
height: 100% !important;
border-radius: 50% !important;
display: block !important;
}
.user.you .infosPlayer .nick,
#popUp.iquez-my-popup .content.profile .contentPopup .nick,
.home .anonymus .fieldset.nick input,
header:not(.game) .userLogged .infos span,
header:not(.game) .userLogged .infos strong,
.scrollElements .iquez-my-msg strong {
color: ${settings.enableNameColor ? settings.nameColor : ''} !important;
}
.textGame input[type="text"] {
color: ${settings.enableChatColor ? settings.chatColor : ''} !important;
}
#iquez-settings-panel {
position: fixed; top: 85px; left: 15px; width: 280px; background: #1a1a1a; color: white;
z-index: 1000000; border-radius: 10px; padding: 15px; border: 2px solid #333;
font-family: sans-serif; display: none; box-shadow: 0 5px 15px rgba(0,0,0,0.5);
max-height: 80vh; overflow-y: auto;
}
#iquez-settings-panel::-webkit-scrollbar { width: 6px; }
#iquez-settings-panel::-webkit-scrollbar-thumb { background: #444; border-radius: 3px; }
.iquez-panel-title { font-weight: bold; margin-bottom: 15px; border-bottom: 1px solid #333; padding-bottom: 5px; text-align: center; font-size: 16px; letter-spacing: 1px; }
.iquez-option { margin-bottom: 15px; display: flex; align-items: center; justify-content: space-between; font-size: 13px; }
.iquez-controls { display: flex; align-items: center; gap: 12px; }
.iquez-option input[type="color"] { border: none; width: 35px; height: 25px; cursor: pointer; background: none; padding: 0; border-radius: 4px; }
.iquez-btn-save { width: 100%; background: #0a5efb; color: white; border: none; padding: 10px; border-radius: 5px; cursor: pointer; font-weight: bold; margin-top: 10px; box-shadow: 0 3px 0 #0742b8; transition: transform 0.1s; }
.iquez-btn-save:active { transform: translateY(2px); box-shadow: none; }
.iquez-watermark { position: fixed; top: 15px; left: 15px; z-index: 999999; font-family: sans-serif; text-shadow: 1px 1px 3px rgba(0,0,0,0.8); }
.iquez-watermark .brand { color: red !important; font-size: 22px; font-weight: 900; }
.iquez-watermark .author { color: white; font-size: 14px; font-weight: bold; display: inline-block;}
#iquez-gear-icon { cursor: pointer; font-size: 18px; margin-left: 5px; display: inline-block; transition: transform 0.3s ease; vertical-align: middle; }
#iquez-gear-icon:hover { transform: rotate(90deg); }
#iquez-ping-display {
position: fixed; top: 15px; right: 15px; z-index: 999999;
background: rgba(0, 0, 0, 0.6); color: white; padding: 6px 12px;
border-radius: 8px; font-family: sans-serif; font-size: 13px;
font-weight: bold; text-shadow: 1px 1px 2px black;
display: ${settings.enablePing ? 'flex' : 'none'};
align-items: center; gap: 6px; box-shadow: 0 2px 5px rgba(0,0,0,0.3);
}
.iquez-switch { position: relative; display: inline-block; width: 36px; height: 20px; }
.iquez-switch input { opacity: 0; width: 0; height: 0; }
.iquez-slider { position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0; background-color: #444; transition: .3s; border-radius: 20px; box-shadow: inset 0 0 5px rgba(0,0,0,0.5); }
.iquez-slider:before { position: absolute; content: ""; height: 14px; width: 14px; left: 3px; bottom: 3px; background-color: white; transition: .3s; border-radius: 50%; box-shadow: 0 2px 4px rgba(0,0,0,0.3); }
input:checked + .iquez-slider { background-color: #0a5efb; }
input:checked + .iquez-slider:before { transform: translateX(16px); }
#iquez-rejoin {
width: 26px !important;
height: 26px !important;
background-color: transparent !important;
background-image: url('https://i.ibb.co/vCWPFjVq/rejoin.png') !important;
background-size: contain !important;
background-repeat: no-repeat !important;
background-position: center !important;
border: none !important;
cursor: pointer !important;
padding: 0 !important;
margin: 0 6px !important;
display: inline-flex !important;
align-items: center !important;
justify-content: center !important;
transition: transform 0.2s ease;
position: relative;
}
#iquez-rejoin:hover {
transform: scale(1.1);
}
`;
if (settings.enableDarkMode) {
baseCSS += `
#background { background-color: transparent !important; }
#fundo { opacity: 0 !important; }
#background:before {
background-color: #252525 !important;
background-image: url(/static/images/new/textura.png) !important;
content: "" !important;
width: 200% !important;
display: block !important;
position: absolute !important;
z-index: 0 !important;
left: 50% !important;
top: 50% !important;
height: 200% !important;
transform: translate(-50%, -50%) rotate(345deg) !important;
}
#screens > div {
background-color: #252525 !important;
box-shadow: -2px 2px 4px 0 rgba(0, 0, 0, 0.3) !important;
border-radius: 10px !important;
}
.home .anonymus .fieldset.nick input,
.home .logged .fieldset.nick input {
background-color: #252525 !important;
}
.home .lastRooms>div ul li:not(.emptyList):not(.empty) {
background-color: #252525 !important;
border: 5px solid #6f6f6f !important;
}
.home .lastRooms>div ul li:not(.emptyList):not(.empty).bgEmptyRoom {
background-color: #252525 !important;
border-color: #6f6f6f !important;
}
input[type=email], input[type=text] {
background-color: #252525 !important;
}
#screens .content.bg {
background-color: #252525 !important;
border: 1px solid #868d96 !important;
}
.rooms .scroll a:not(.emptyList):not(.loading) {
background-color: #252525 !important;
border: 7px solid #868d96 !important;
}
.rooms .scroll a:not(.emptyList):not(.loading).bgEmptyRoom {
background-color: #535353 !important;
border-color: #e4edef !important;
}
#screenRoom .ctt #interaction,
#screenRoom.common .ctt #interaction {
background-color: #252525 !important;
}
#screenRoom .ctt #interaction #chat,
#screenRoom.common .ctt #interaction #chat {
background-color: #252525 !important;
}
.textGame input[type="text"] {
background-color: #252525 !important;
}
#screenRoom .ctt .users-tools #users {
background-color: #252525 !important;
border: 1px solid #979797 !important;
}
#screenRoom .ctt .users-tools #users ul {
background-color: #252525 !important;
}
#popUp .content {
background-color: #252525 !important;
border: 1px solid #868d96 !important;
}
`;
}
style.innerHTML = baseCSS;
};
updateStyles();
document.head.appendChild(style);
function createMenu() {
if (document.querySelector('.iquez-watermark')) return;
const wm = document.createElement('div');
wm.className = 'iquez-watermark';
wm.innerHTML = `<div class="brand">GarticBetter</div><div class="author">by iQuez</div><div id="iquez-gear-icon">⚙️</div>`;
document.body.appendChild(wm);
const panel = document.createElement('div');
panel.id = 'iquez-settings-panel';
panel.innerHTML = `
<div class="iquez-panel-title">GarticBetter Menü</div>
<div class="iquez-option">
<span>Karanlık Mod:</span>
<label class="iquez-switch">
<input type="checkbox" id="iq-dark-t" ${settings.enableDarkMode ? 'checked' : ''}>
<span class="iquez-slider"></span>
</label>
</div>
<hr style="border:0; border-top:1px solid #333; margin: 12px 0;">
<div class="iquez-option">
<span>Çerçeve Rengi:</span>
<div class="iquez-controls">
<label class="iquez-switch">
<input type="checkbox" id="iq-border-t" ${settings.enableBorder ? 'checked' : ''}>
<span class="iquez-slider"></span>
</label>
<input type="color" id="iq-border-c" value="${settings.borderColor}">
</div>
</div>
<hr style="border:0; border-top:1px solid #333; margin: 12px 0;">
<div class="iquez-option">
<span>İsim Rengi:</span>
<div class="iquez-controls">
<label class="iquez-switch">
<input type="checkbox" id="iq-name-t" ${settings.enableNameColor ? 'checked' : ''}>
<span class="iquez-slider"></span>
</label>
<input type="color" id="iq-name-c" value="${settings.nameColor}">
</div>
</div>
<hr style="border:0; border-top:1px solid #333; margin: 12px 0;">
<div class="iquez-option">
<span>Mesaj Rengi:</span>
<div class="iquez-controls">
<label class="iquez-switch">
<input type="checkbox" id="iq-chat-t" ${settings.enableChatColor ? 'checked' : ''}>
<span class="iquez-slider"></span>
</label>
<input type="color" id="iq-chat-c" value="${settings.chatColor}">
</div>
</div>
<hr style="border:0; border-top:1px solid #333; margin: 12px 0;">
<div class="iquez-option">
<span>Ping Göstergesi:</span>
<label class="iquez-switch">
<input type="checkbox" id="iq-ping-t" ${settings.enablePing ? 'checked' : ''}>
<span class="iquez-slider"></span>
</label>
</div>
<button class="iquez-btn-save" id="iq-save-btn">KAYDET</button>
`;
document.body.appendChild(panel);
document.getElementById('iquez-gear-icon').onclick = () => {
panel.style.display = panel.style.display === 'none' ? 'block' : 'none';
};
document.getElementById('iq-save-btn').onclick = () => {
settings.borderColor = document.getElementById('iq-border-c').value;
settings.nameColor = document.getElementById('iq-name-c').value;
settings.chatColor = document.getElementById('iq-chat-c').value;
settings.enableBorder = document.getElementById('iq-border-t').checked;
settings.enableNameColor = document.getElementById('iq-name-t').checked;
settings.enableChatColor = document.getElementById('iq-chat-t').checked;
settings.enablePing = document.getElementById('iq-ping-t').checked;
settings.enableDarkMode = document.getElementById('iq-dark-t').checked;
localStorage.setItem('iquez_settings', JSON.stringify(settings));
updateStyles();
panel.style.display = 'none';
};
}
function createPingDisplay() {
if (!document.getElementById('iquez-ping-display')) {
const pingEl = document.createElement('div');
pingEl.id = 'iquez-ping-display';
pingEl.innerHTML = `<span style="color:#00ff00">●</span> 0 ms`;
document.body.appendChild(pingEl);
setInterval(() => {
if (settings.enablePing) {
const start = Date.now();
fetch('/?t=' + start, { method: 'HEAD', cache: 'no-store' }).then(() => {
const ping = Date.now() - start;
let color = '#00ff00';
if (ping > 80) color = '#ffcc00';
if (ping > 150) color = '#ff3333';
document.getElementById('iquez-ping-display').innerHTML = `<span style="color:${color}">●</span> ${ping} ms`;
}).catch(() => {});
}
}, 2000);
}
}
const originalDrawImage = CanvasRenderingContext2D.prototype.drawImage;
CanvasRenderingContext2D.prototype.drawImage = function(...args) {
const img = args[0];
if (this.canvas && this.canvas.closest) {
const isAvatarCanvas = this.canvas.closest('.avatar') || this.canvas.closest('#popUp');
if (isAvatarCanvas && img && img.src && img.src.startsWith('http')) {
capturedAvatarUrl = img.src;
}
}
return originalDrawImage.apply(this, args);
};
function applyModifications() {
const rejoinRoom = sessionStorage.getItem('iquez_rejoin_room');
if (rejoinRoom) {
const isHome = document.querySelector('.content.home') || window.location.pathname === '/';
if (isHome) {
sessionStorage.removeItem('iquez_rejoin_room');
window.location.href = window.location.origin + rejoinRoom;
return;
}
}
createMenu();
createPingDisplay();
const exitBtn = document.getElementById('exit');
if (exitBtn && !document.getElementById('iquez-rejoin')) {
const rejoinBtn = document.createElement('button');
rejoinBtn.id = 'iquez-rejoin';
rejoinBtn.innerHTML = '<span class="tooltip">Yeniden Gir</span>';
rejoinBtn.onclick = () => {
const roomUrl = window.location.pathname;
if (roomUrl && roomUrl !== '/') {
sessionStorage.setItem('iquez_rejoin_room', roomUrl);
exitBtn.click();
let attempts = 0;
const checkYes = setInterval(() => {
const yesBtn = document.querySelector('.ic-yes');
const popUp = document.getElementById('popUp');
if (yesBtn && popUp && window.getComputedStyle(popUp).display !== 'none') {
clearInterval(checkYes);
setTimeout(() => {
yesBtn.click();
}, 100);
}
if (++attempts > 100) clearInterval(checkYes);
}, 20);
}
};
exitBtn.parentNode.insertBefore(rejoinBtn, exitBtn);
}
document.querySelectorAll('.scrollElements a:not(.has-watch-btn)').forEach(room => {
room.classList.add('has-watch-btn');
const watchBtn = document.createElement('div');
watchBtn.className = 'iquez-watch-btn';
watchBtn.innerHTML = '👁️ İZLE';
watchBtn.onclick = (e) => {
e.preventDefault(); e.stopPropagation();
let url = room.getAttribute('href');
window.open((url.startsWith('http') ? url : window.location.origin + url) + '/viewer', '_blank');
};
room.appendChild(watchBtn);
});
const popupButtons = document.querySelector('#popUp .content.profile .buttons');
if (popupButtons && !popupButtons.classList.contains('has-pic-btn')) {
popupButtons.classList.add('has-pic-btn');
const picBtn = document.createElement('button');
picBtn.className = 'btYellowBig iquez-profile-btn';
picBtn.innerHTML = '<strong>PROFİL RESMİ</strong>';
picBtn.onclick = () => { if (capturedAvatarUrl) window.open(capturedAvatarUrl, '_blank'); };
popupButtons.appendChild(picBtn);
}
let myNick = (document.querySelector('.user.you .infosPlayer .nick') ||
document.querySelector('.logged .userLogged .infos .nick') ||
document.querySelector('.logged .userLogged .infos strong') ||
document.querySelector('header:not(.game) .userLogged .infos span'))?.innerText;
const popup = document.querySelector('#popUp');
if (popup && myNick) {
const pNick = popup.querySelector('.content.profile .contentPopup .nick');
if (pNick?.innerText.trim() === myNick.trim()) {
popup.classList.add('iquez-my-popup');
} else {
popup.classList.remove('iquez-my-popup');
}
}
if (myNick) {
document.querySelectorAll('.scrollElements .msg:not(.iquez-processed)').forEach(msg => {
msg.classList.add('iquez-processed');
const strong = msg.querySelector('strong');
if (strong && strong.innerText.replace(':', '').trim() === myNick.trim()) {
msg.classList.add('iquez-my-msg');
if (settings.enableChatColor) {
const target = msg.querySelector('span') || msg;
target.style.setProperty('color', settings.chatColor, 'important');
}
}
});
}
}
const observer = new MutationObserver(() => applyModifications());
observer.observe(document.body, { childList: true, subtree: true });
applyModifications();
})();