A legitimate helper script for Sploop.io, providing enhanced HUD (FPS, CPS, Ping), hitbox visualizations, tracers, transparent UI, built-in ad-blocking, and smooth health bar for a smoother gaming experience.
// ==UserScript==
// @name Sploop.io Plus [V2.0]
// @namespace http://tampermonkey.net/
// @version 2.1
// @description A legitimate helper script for Sploop.io, providing enhanced HUD (FPS, CPS, Ping), hitbox visualizations, tracers, transparent UI, built-in ad-blocking, and smooth health bar for a smoother gaming experience.
// @match *://sploop.io/*
// @icon https://i.postimg.cc/vBz07fcS/Screenshot-2025-08-28-090152.png
// @grant none
// @author Normalplayer + Hori & viper + Fizzixww
// @license MIT
// @run-at document-start
// ==/UserScript==
(function () {
'use strict';
// =========================================================================
// GLOBAL CONFIG
// =========================================================================
const STORAGE_KEY = 'sploop_legit_settings_v6';
const config = {
ghostMode: false,
ghostOpacityTree: 0.3,
ghostOpacityStone: 0.3,
ghostOpacityBush: 0.3,
ghostOpacityGold: 0.3,
ghostOpacityWall: 0.3,
ghostOpacitySpike: 0.3,
ghostOpacityBuilding: 0.3,
ghostOpacityMisc: 0.3,
hitbox: true,
hitboxColorEnemy: "#ff0000",
hitboxColorAlly: "#a4cc4f",
hitboxColorMob: "#e09f3e",
hitboxColorBlock: "#00cfff",
hitboxWidth: 2,
tracers: false,
tracerWidth: 1.5,
tracerOpacity: 0.7,
tracerColorEnemy: "#cc5151",
tracerColorAlly: "#a4cc4f",
tracerColorMob: "#e09f3e",
tracerPlayer: true,
tracerAlly: true,
tracerCow: true,
tracerDuck: true,
tracerWolf: true,
tracerShark: true,
tracerCrocodile: true,
tracerGcow: true,
tracerMammoth: true,
tracerDragon: true,
betterHealthBar: true,
coloredHealthBar: true,
smoothHealthBar: true,
showPercentHealth: true,
hpColorAllyHigh: "#a4cc4f",
hpColorAllyMed: "#e09f3e",
hpColorAllyLow: "#cc5151",
hpColorEnemyHigh: "#cc5151",
hpColorEnemyMed: "#e09f3e",
hpColorEnemyLow: "#a4cc4f",
transparentUI: true,
showOverlay: true,
removeAds: true,
itemCounter: true,
lightMode: false,
keyViewer: true,
statsLocked: false,
statsShowServer: true,
statsShowFps: true,
statsShowCps: true,
statsShowPing: true,
kvLocked: false,
overlayBgOpacity: 0.75,
overlayBgColor: "#0a0a0a",
overlayTextColor: "#ffffff",
overlayFontSize: 17,
kvBgOpacity: 0.75,
kvBgColor: "#0a0a0a",
kvTextColor: "#e5e7eb",
kvCellSize: 46
};
try {
const saved = localStorage.getItem(STORAGE_KEY);
if (saved) Object.assign(config, JSON.parse(saved));
} catch (e) {
console.error('[LegitScript] Config load error:', e);
}
function saveConfig() {
try {
localStorage.setItem(STORAGE_KEY, JSON.stringify(config));
} catch (e) {
console.error('[LegitScript] Config save error:', e);
}
}
const circlesToDraw = [];
// =========================================================================
// PART 1: ITEM COUNTER & CODE HOOKS
// =========================================================================
const max = [0, 0, 0, 100, 30, 8, 2, 12, 32, 1, 2];
window.drawItemBar = (ctx, imageData, index) => {
if (!config.itemCounter || !window.stats || !Sploop) return;
try {
const weaponType = window.weapons[window.stats[Sploop.itemsID][index]][Sploop.weaponID2];
const limit = max[weaponType];
const crntCount = window.stats[Sploop.objCount][weaponType];
if (!limit) return;
const text = `${crntCount}/${limit}`;
ctx.save();
ctx.font = "900 19px 'Baloo Paaji'";
ctx.fillStyle = "white";
ctx.strokeStyle = "#330000";
ctx.lineWidth = 3;
ctx.strokeText(text, imageData[Sploop.x] + imageData.width - ctx.measureText(text).width - 10, imageData[Sploop.y] + 25);
ctx.fillText(text, imageData[Sploop.x] + imageData.width - ctx.measureText(text).width - 10, imageData[Sploop.y] + 25);
ctx.restore();
} catch (e) {}
};
const TYPEOF = (value) => Object.prototype.toString.call(value).slice(8, -1).toLowerCase();
const NumberSystem = [
{ radix: 2, prefix: "0b0*" }, { radix: 8, prefix: "0+" },
{ radix: 10, prefix: "" }, { prefix: "", radix: 16 }
];
class Regex {
constructor(code, unicode, namespace) {
if (!namespace) namespace = "new_script_" + Math.random().toString(36).substr(2, 8);
this.code = code;
this.COPY_CODE = code;
this.unicode = unicode || false;
this.hooks = {};
this.namespace = namespace;
this.totalHooks = 0;
}
static parseValue(value) {
try { return Function(`return (${value})`)(); } catch { return null; }
}
isRegexp(value) { return TYPEOF(value) === "regexp"; }
generateNumberSystem(int) {
const template = NumberSystem.map(({ prefix, radix }) => prefix + int.toString(radix));
return `(?:${template.join("|")})`;
}
parseVariables(regex) {
regex = regex
.replace(/\{VAR\}/g, "(?:let|var|const)")
.replace(/\{QUOTE\}/g, "['\"`]")
.replace(/ARGS\{(\d+)\}/g, (_, n) => {
let count = Number(n), arr = [];
while (count--) arr.push("\\w+");
return arr.join("\\s*,\\s*");
})
.replace(/NUMBER\{(\d+)\}/g, (_, n) => this.generateNumberSystem(Number(n)));
return regex;
}
_hookName(name) { return `${this.namespace}:${name}`; }
format(name, inputRegex, flags) {
this.totalHooks++;
let regex = "";
if (Array.isArray(inputRegex)) {
regex = inputRegex.map(exp => this.isRegexp(exp) ? exp.source : exp).join("\\s*");
} else if (this.isRegexp(inputRegex)) {
regex = inputRegex.source;
} else {
regex = inputRegex;
}
regex = this.parseVariables(regex);
if (this.unicode) regex = regex.replace(/\\w/g, "(?:[^\\x00-\\x7F-]|\\$|\\w)");
const hasInsert = regex.includes("{INSERT}");
const cleanRegex = regex.replace(/\{INSERT\}/, "");
return hasInsert ? new RegExp(regex, flags) : new RegExp(cleanRegex, flags);
}
template(type, name, regex, substr) {
const hookName = this._hookName(name);
const expression = new RegExp(`(${this.format(hookName, regex).source})`);
const match = this.code.match(expression) || [];
this.code = this.code.replace(expression, type === 0 ? "$1" + substr : substr + "$1");
this.hooks[hookName] = { expression, match };
return match;
}
insert(name, regex, substr) {
const { source } = this.format(name, regex);
if (!source.includes("{INSERT}")) throw new Error("Your regexp must contain {INSERT} keyword");
const findExpression = new RegExp(source.replace(/^(.*)\{INSERT\}(.*)$/, "($1)($2)"));
this.code = this.code.replace(findExpression, `$1${substr}$2`);
return this.code.match(findExpression);
}
logHooks() {
console.log("%cApplied Hooks:", "font-weight: bold; font-size: 24px; color:#fff; margin-top: 20px;");
let index = 1;
for (const hookName in this.hooks) {
const hook = this.hooks[hookName];
const matches = Array.isArray(hook.match) ? hook.match : [hook.match];
const ok = matches && matches.length > 0;
console.log(
`%c${index}. ${hookName} | ${ok ? "successful" : "unsuccessful"}`,
ok ? "color:rgb(134,204,125);font-size:14px;" : "color:rgb(221,94,113);font-size:14px;"
);
index++;
}
}
match(name, regex, flags) {
const hookName = this._hookName(name);
const expression = this.format(hookName, regex, flags);
const match = this.code.match(expression) || [];
this.hooks[hookName] = { expression, match };
return match;
}
matchAll(name, regex) {
const hookName = this._hookName(name);
const expression = this.format(hookName, regex, "g");
const matches = [...this.code.matchAll(expression)];
this.hooks[hookName] = { expression, match: matches };
return matches;
}
replace(name, regex, substr, flags) {
const hookName = this._hookName(name);
const expression = this.format(hookName, regex, flags);
const preMatch = this.code.match(expression) || [];
this.code = this.code.replace(expression, substr);
this.hooks[hookName] = { expression, match: preMatch, replaced: preMatch.length > 0 };
return this.code.match(expression) || [];
}
append(name, regex, substr) { return this.template(0, name, regex, substr); }
prepend(name, regex, substr) { return this.template(1, name, regex, substr); }
}
let Sploop = {};
const applyHooks = (code) => {
try {
const Hook = new Regex(code, true);
window.COPY_CODE = (Hook.COPY_CODE.match(/^(\(function \w+\(\w+\)\{.+)\(.+?\);$/) || [])[1];
if (window.COPY_CODE) {
Hook.append("EXTERNAL fix", /\(function (\w+)\(\w+\)\{/, "let $2 = eval(`(() => ${COPY_CODE})()`);delete window.COPY_CODE;");
}
const map = Hook.match("objects", /let \w=(\w).get\(\w\)/)[1];
const X = Hook.match("playerX", /\{this\.(\w{2})=\w\|\|0/)[1];
const Y = Hook.match("playerY", /,this\.(\w{2})=\w\|\|0\}/)[1];
const weaponID2Matches = Hook.matchAll("el", /,(\w+):9,\w+:2/);
const weaponID2 = weaponID2Matches.length > 1 ? weaponID2Matches[1][1] : (weaponID2Matches[0] ? weaponID2Matches[0][1] : null);
const itemsID = Hook.match("IDs", />1\)\{.{3}(\w{2})/)[1];
const objCount = Hook.match("objCount", /\),this.(\w{2})=\w\):/)[1];
const itemBarMatch = Hook.match("defaultData1", /(\W\w+>NUMBER{1}\W.+?(\w+)\.(\w+).+?)function/);
const itemBar = itemBarMatch ? itemBarMatch[3] : null;
Sploop = { x: X, y: Y, map, itemsID, itemBar, objCount, weaponID2 };
const weaponList = Hook.match("weaponList", /\?Math\.PI\/2.+?(\w\(\))/)[1];
Hook.replace("defaultData", /(\W\w+>NUMBER{1}\W.+?(\w+)\.(\w+).+?)function/,
`$1window.stats=$2;window.weapons=${weaponList};window.sprites=tt();function`);
const argsMatch = Hook.match("drawEntityInfo", /\.\w+\),\w(\.restore|\w\(\d+\))\(\)}function \w+\((ARGS{3})\){/);
if (argsMatch && argsMatch[2]) {
let args = argsMatch[2];
Hook.append("drawEntityInfo2",
/\),\w\.drawImage\(\w,\w\.\w{2}-\w\*.{7,9}\/2.\w\.\w{2}-\w\*.{8,9}\+\w,\w\*.{7,9},\w\*.{9}\)/,
`;try{window.getEntityData(${args},${Sploop.map});}catch(e){};`);
}
Hook.append("itemCounter",
/\w\.drawImage\(\w,\.5\*\w{2}\-\.5\*.{7,9},\w\.\w{2}-.{8,9}\);for\(let \w,\w=0,\w=\w{2}\.\w{2};\w\<.{7,9};\w\+\+\)if\(\w=\w\[(\w)\],(\w)\.\w{2}\((\w)\),/,
`window.drawItemBar($4,$3,$2),`);
return Hook.code;
} catch (e) {
console.error("[LegitScript] Critical Hook Error. Game will load without item hooks to prevent crashing.", e);
return code;
}
};
window.eval = new Proxy(window.eval, {
apply(target, _this, args) {
const code = args[0];
if (typeof code === 'string' && code.length > 1e5) {
args[0] = applyHooks(code);
window.eval = target;
target.apply(_this, args);
return;
}
return target.apply(_this, args);
}
});
// =========================================================================
// PART 2: FEATURES
// =========================================================================
function lerpColor(a, b, amount) {
const ah = parseInt(a.replace(/#/g, ''), 16), ar = ah >> 16, ag = (ah >> 8) & 0xff, ab = ah & 0xff;
const bh = parseInt(b.replace(/#/g, ''), 16), br = bh >> 16, bg = (bh >> 8) & 0xff, bb = bh & 0xff;
const rr = ar + amount * (br - ar), rg = ag + amount * (bg - ag), rb = ab + amount * (bb - ab);
return '#' + (((1 << 24) + (rr << 16) + (rg << 8) + rb) | 0).toString(16).slice(1);
}
function drawHpText(ctx, text, xPos, yPos, color) {
ctx.save();
ctx.font = "900 20px 'Baloo Paaji'";
ctx.textAlign = "center";
ctx.textBaseline = "top";
ctx.lineJoin = "round";
ctx.lineWidth = 8;
ctx.strokeStyle = "#313131";
ctx.strokeText(text, xPos, yPos);
ctx.fillStyle = color;
ctx.fillText(text, xPos, yPos);
ctx.restore();
}
const hpTracker = [];
const enhanceFillRect = function (originalFillRect) {
return function (x, y, width, height) {
const fullWidth = 95;
const isHpBar = height > 5 && height < 20 && (this.fillStyle === "#a4cc4f" || this.fillStyle === "#cc5151");
let renderWidth = width;
let hpPercent = Math.max(0, Math.min(1, width / fullWidth));
let percentText = `${Math.round(hpPercent * 100)}%`;
if (isHpBar && this.canvas && this.canvas.id === "game-canvas") {
try {
const matrix = this.getTransform();
const screenX = matrix.a * (x + fullWidth / 2) + matrix.c * y + matrix.e;
const screenY = matrix.b * (x + fullWidth / 2) + matrix.d * y + matrix.f;
const now = Date.now();
window._frameHpBars = window._frameHpBars || [];
const barIsMob = width <= 45;
window._frameHpBars.push({ x: screenX, y: screenY, isAlly: this.fillStyle === "#a4cc4f", isMob: barIsMob, time: now });
if (config.betterHealthBar && config.smoothHealthBar) {
let matchedBar = null;
let minDist = 40;
for (let i = 0; i < hpTracker.length; i++) {
const bar = hpTracker[i];
const dist = Math.hypot(bar.x - screenX, bar.y - screenY);
if (dist < minDist) {
minDist = dist;
matchedBar = bar;
}
}
if (matchedBar) {
matchedBar.x = screenX;
matchedBar.y = screenY;
matchedBar.targetWidth = width;
matchedBar.lastSeen = now;
matchedBar.currentWidth += (matchedBar.targetWidth - matchedBar.currentWidth) * 0.15;
if (Math.abs(matchedBar.targetWidth - matchedBar.currentWidth) < 0.5) {
matchedBar.currentWidth = matchedBar.targetWidth;
}
} else {
matchedBar = { x: screenX, y: screenY, targetWidth: width, currentWidth: width, lastSeen: now };
hpTracker.push(matchedBar);
}
if (Math.random() < 0.05) {
for (let i = hpTracker.length - 1; i >= 0; i--) {
if (now - hpTracker[i].lastSeen > 200) hpTracker.splice(i, 1);
}
}
renderWidth = matchedBar.currentWidth;
hpPercent = Math.max(0, Math.min(1, renderWidth / fullWidth));
percentText = `${Math.round(hpPercent * 100)}%`;
}
} catch(e) {}
}
if (!config.betterHealthBar) return originalFillRect.call(this, x, y, width, height);
if (isHpBar) {
const centerX = x + fullWidth / 2;
let baseColor = this.fillStyle === "#a4cc4f" ? config.hpColorAllyHigh : config.hpColorEnemyHigh;
let color = baseColor;
if (config.coloredHealthBar) {
if (this.fillStyle === "#a4cc4f") {
color = hpPercent > 0.5 ?
lerpColor(config.hpColorAllyHigh, config.hpColorAllyMed, (1 - hpPercent) * 2) :
lerpColor(config.hpColorAllyMed, config.hpColorAllyLow, (0.5 - hpPercent) * 2);
} else if (this.fillStyle === "#cc5151") {
color = hpPercent > 0.5 ?
lerpColor(config.hpColorEnemyHigh, config.hpColorEnemyMed, (1 - hpPercent) * 2) :
lerpColor(config.hpColorEnemyMed, config.hpColorEnemyLow, (0.5 - hpPercent) * 2);
}
}
this.fillStyle = color;
originalFillRect.call(this, x, y, renderWidth, height);
if (config.showPercentHealth) {
drawHpText(this, percentText, centerX, y + height + 7, color);
}
return;
}
originalFillRect.call(this, x, y, width, height);
};
};
CanvasRenderingContext2D.prototype.fillRect = enhanceFillRect(CanvasRenderingContext2D.prototype.fillRect);
// ---- HITBOX PATCH ----
const imageRadii = new Map([
["tree.png",90],["cherry_tree.png",90],["palm_tree.png",90],
["wood_farm.png",80],["wood_farm_cherry.png",80],
["rock.png",75],["stone_farm.png",75],
["bush.png",50],["berry_farm.png",50],["cactus.png",50],
["gold.png",76],["ruby.png",100],["tornado.png",220],
["cave_stone0.png",92],["cave_stone1.png",92],["cave_stone2.png",58],
["fireball.png",100],["ice0.png",92],["ice1.png",20],["chest.png",40],
["wall.png",45],["castle_wall.png",59],["spike.png",45],
["hard_spike.png",45],["ice_spike.png",45],["big_spike.png",45],
["windmill_base.png",45],["trap.png",40],["boost.png",40],
["turret_base.png",45],["heal_pad.png",50],["platform.png",60],
["roof.png",50],["bed.png",50],["teleporter.png",35],["lootbox.png",40],
["wolf.png",50],["duck.png",20],["cow.png",90],["shark.png",90],
["mammoth_body.png",90],["dragon_2_body.png",100],["gcow.png",90],["crocodile.png",90]
]);
const resourceKeywords = ["tree","rock","bush","cactus","ruby","wood","stone","gold",
"wall","spike","windmill","trap","boost","turret","heal_pad","platform",
"roof","bed","teleporter","lootbox","tornado","inv_","ice","cave_stone"];
const skinFragments = new Set();
for (let i = 0; i <= 105; i++) skinFragments.add(`body${i}.png`);
skinFragments.add('45body.png');
skinFragments.add('78body.png');
const origDrawImage = CanvasRenderingContext2D.prototype.drawImage;
CanvasRenderingContext2D.prototype.drawImage = function (img, ...rest) {
if (!img || !img.src) return origDrawImage.apply(this, arguments);
if (img._isProcessed === undefined) {
img._isProcessed = true;
const src = img.src;
const fileName = src.substring(src.lastIndexOf('/') + 1).split('?')[0];
img._radius = imageRadii.get(fileName) || 0;
img._isPlayer = skinFragments.has(fileName);
img._isMob = ["wolf.png","duck.png","cow.png","shark.png","mammoth_body.png","dragon_2_body.png","gcow.png","crocodile.png"].includes(fileName);
img._fileName = fileName;
const ghostTreeFiles = ["tree.png","cherry_tree.png","palm_tree.png","wood_farm.png","wood_farm_cherry.png"];
const ghostStoneFiles = ["rock.png","stone_farm.png","cave_stone0.png","cave_stone1.png","cave_stone2.png"];
const ghostBushFiles = ["bush.png","berry_farm.png","cactus.png"];
const ghostGoldFiles = ["gold.png","ruby.png","lootbox.png","chest.png"];
const ghostWallFiles = ["wall.png","castle_wall.png","platform.png","roof.png"];
const ghostSpikeFiles = ["spike.png","hard_spike.png","ice_spike.png","big_spike.png"];
const ghostBuildFiles = ["windmill_base.png","trap.png","boost.png","turret_base.png","heal_pad.png","bed.png","teleporter.png"];
const ghostMiscFiles = ["tornado.png","fireball.png","ice0.png","ice1.png"];
if (ghostTreeFiles.includes(fileName)) img._ghostGroup = "tree";
else if (ghostStoneFiles.includes(fileName)) img._ghostGroup = "stone";
else if (ghostBushFiles.includes(fileName)) img._ghostGroup = "bush";
else if (ghostGoldFiles.includes(fileName)) img._ghostGroup = "gold";
else if (ghostWallFiles.includes(fileName)) img._ghostGroup = "wall";
else if (ghostSpikeFiles.includes(fileName)) img._ghostGroup = "spike";
else if (ghostBuildFiles.includes(fileName)) img._ghostGroup = "building";
else if (ghostMiscFiles.includes(fileName)) img._ghostGroup = "misc";
else img._ghostGroup = null;
}
const drawImg = img;
const shouldGhost = config.ghostMode && img._ghostGroup !== null && img._ghostGroup !== undefined;
if (shouldGhost) {
this.save();
const opacityMap = {
tree: config.ghostOpacityTree,
stone: config.ghostOpacityStone,
bush: config.ghostOpacityBush,
gold: config.ghostOpacityGold,
wall: config.ghostOpacityWall,
spike: config.ghostOpacitySpike,
building: config.ghostOpacityBuilding,
misc: config.ghostOpacityMisc
};
this.globalAlpha = opacityMap[img._ghostGroup] ?? 0.3;
}
origDrawImage.call(this, drawImg, ...rest);
if (shouldGhost) this.restore();
if (this.canvas && this.canvas.id === "game-canvas") {
const mh = this.canvas.height;
const mw = this.canvas.width;
if (config.hitbox && img._radius > 0 && rest.length >= 4 && !img._isPlayer && !img._isMob) {
const [x, y, w, h] = rest;
const src = img.src;
const isWorldEntity = (img._ghostGroup || src.includes('/entity/')) && !src.includes('inv_') && !src.includes('ui_');
const isHotbarZone = y > mh * 0.8 && x > mw * 0.25 && x < mw * 0.75;
const isChooseZone = y < mh * 0.2 && x > mw * 0.2 && x < mw * 0.8;
if (!((isHotbarZone || isChooseZone) && !isWorldEntity)) {
try {
this.beginPath();
this.arc(x + w / 2, y + h / 2, img._radius, 0, Math.PI * 2);
this.lineWidth = config.hitboxWidth;
this.strokeStyle = config.hitboxColorBlock;
this.stroke();
} catch(e){}
}
}
if ((config.hitbox || config.tracers) && (img._isPlayer || img._isMob) && rest.length >= 4) {
const [x, y, w, h] = rest;
try {
const mat = this.getTransform();
circlesToDraw.push({ x, y, width: w, height: h, radius: img._radius, transform: mat, isPlayer: img._isPlayer, isMob: img._isMob, fileName: img._fileName });
if (img._isMob) {
const lx = x + w / 2, ly = y + h / 2;
const sx = mat.a * lx + mat.c * ly + mat.e;
const sy = mat.b * lx + mat.d * ly + mat.f;
window._lastMobScreenPositions = window._lastMobScreenPositions || [];
window._lastMobScreenPositions.push({ x: sx, y: sy, time: Date.now() });
}
} catch(e){}
}
}
};
// =========================================================================
// PART 3: DOM UI (CATEGORIZED SIDEBAR MENU & OVERLAYS)
// =========================================================================
window.addEventListener('DOMContentLoaded', () => {
const CSS_ID = 'sploop-legit-css';
const ADS_CSS_ID = 'sploop-adblock-css';
function resetMenuStyles() {
const hatMenu = document.getElementById('hat-menu');
if (hatMenu) {
['zoom','position','transform','margin','left','top'].forEach(p => hatMenu.style.removeProperty(p));
hatMenu._legitPatched = false;
Array.from(hatMenu.children).forEach(child => {
if (child.id === 'hat_menu_content') return;
['display','position','left','right','top','transform','margin','visibility','opacity'].forEach(p => child.style.removeProperty(p));
child.childNodes.forEach(node => {
if (node.nodeType === 1) {
const t = node.textContent.trim().toUpperCase();
if (t === 'HATS') node.style.removeProperty('display');
}
});
});
}
const clanMenu = document.getElementById('clan-menu');
if (clanMenu) {
clanMenu._legitPatched = false;
Array.from(clanMenu.children).forEach(child => {
if (child.id === 'clan_menu_content') return;
['display','visibility','opacity','position','left','right','top','transform','margin'].forEach(p => child.style.removeProperty(p));
});
}
}
function updateCSS() {
const existing = document.getElementById(CSS_ID);
if (existing) existing.remove();
let adStyle = document.getElementById(ADS_CSS_ID);
if (config.removeAds) {
if (!adStyle) {
adStyle = document.createElement('style');
adStyle.id = ADS_CSS_ID;
adStyle.innerHTML =
`
#cross-promo,#bottom-wrap,#google_play,
#game-left-content-main,#game-bottom-content,
#game-right-content-main,#left-content,#right-content{display:none!important;}
#game-content{justify-content:center!important;}
#main-content{width:auto!important;}
`;
document.head.appendChild(adStyle);
}
} else {
if (adStyle) adStyle.remove();
}
if (!config.transparentUI) {
resetMenuStyles();
return;
}
const style = document.createElement('style');
style.id = CSS_ID;
style.innerHTML = `
/* ===== HAT SHOP MENU ===== */
#hat-menu {
background: transparent !important;
box-shadow: none !important;
border: none !important;
opacity: 0.55 !important;
transition: opacity 0.25s !important;
}
#hat-menu:hover { opacity: 1 !important; }
#hat_menu_content, #hat_menu_content * {
background: transparent !important;
box-shadow: none !important;
border: none !important;
outline: none !important;
}
#hat_menu_content {
scrollbar-width: none !important;
-ms-overflow-style: none !important;
max-height: 9999px !important;
height: auto !important;
overflow: visible !important;
}
#hat_menu_content::-webkit-scrollbar { display: none !important; }
#hat-menu .hat-shop-title,
#hat-menu .shop-title,
#hat-menu .menu-title {
display: none !important;
}
#clan-menu {
background: transparent !important;
box-shadow: none !important;
opacity: 0.55 !important;
transition: opacity 0.25s !important;
}
#clan-menu:hover { opacity: 1 !important; }
#clan_menu_content, #clan_menu_content * {
background: transparent !important;
box-shadow: none !important;
}
#clan_menu_content {
scrollbar-width: none !important;
-ms-overflow-style: none !important;
}
#clan_menu_content::-webkit-scrollbar { display: none !important; }
#clan_menu_content > div,
#clan_menu_content > li,
#clan_menu_content > p {
margin-bottom: 14px !important;
padding-top: 5px !important;
padding-bottom: 5px !important;
}
#clan-menu input,
#clan-menu textarea,
#clan-menu [placeholder],
#create-clan-button {
background: transparent !important;
box-shadow: none !important;
}
`;
document.head.appendChild(style);
}
const _legitMenuObserver = new MutationObserver(() => {
if (!config.transparentUI) return;
const hatMenu = document.getElementById('hat-menu');
if (hatMenu) {
hatMenu.style.setProperty('zoom', '0.78', 'important');
hatMenu.style.setProperty('position', 'fixed', 'important');
hatMenu.style.setProperty('transform', 'none', 'important');
hatMenu.style.setProperty('margin', '0', 'important');
const rect = hatMenu.getBoundingClientRect();
const vw = window.innerWidth;
const vh = window.innerHeight;
const HAT_OFFSET_X = 200;
const HAT_OFFSET_Y = -75;
const CLOSE_OFFSET_X = 243;
const CLOSE_OFFSET_Y = 6;
const newLeft = Math.round((vw - rect.width) / 2) + HAT_OFFSET_X;
const newTop = Math.round((vh - rect.height) / 2) + HAT_OFFSET_Y;
hatMenu.style.setProperty('left', newLeft + 'px', 'important');
hatMenu.style.setProperty('top', newTop + 'px', 'important');
if (!hatMenu._legitPatched) {
hatMenu._legitPatched = true;
Array.from(hatMenu.children).forEach(child => {
if (child.id === 'hat_menu_content') return;
child.childNodes.forEach(node => {
if (node.nodeType === 3) {
node.textContent = '';
} else if (node.nodeType === 1) {
const t = node.textContent.trim().toUpperCase();
if (t === 'HATS') {
node.style.setProperty('display', 'none', 'important');
}
}
});
const menuW = hatMenu.offsetWidth;
const childW = child.offsetWidth || 30;
const closePx = Math.round((menuW - childW) / 2) + CLOSE_OFFSET_X;
child.style.setProperty('display', 'flex', 'important');
child.style.setProperty('position', 'absolute', 'important');
child.style.setProperty('left', closePx + 'px', 'important');
child.style.setProperty('right', 'auto', 'important');
child.style.setProperty('top', CLOSE_OFFSET_Y + 'px', 'important');
child.style.setProperty('transform', 'none', 'important');
child.style.setProperty('margin', '0', 'important');
child.style.setProperty('visibility','visible', 'important');
child.style.setProperty('opacity', '1', 'important');
});
}
}
const clanMenu = document.getElementById('clan-menu');
if (clanMenu && !clanMenu._legitPatched) {
clanMenu._legitPatched = true;
Array.from(clanMenu.children).forEach(child => {
if (child.id === 'clan_menu_content') return;
child.style.removeProperty('display');
child.style.removeProperty('visibility');
child.style.setProperty('opacity', '1', 'important');
const txt = child.textContent.trim();
const isClose =
txt === 'X' || txt === 'x' || txt === '✕' || txt === '×' || txt === '✖' ||
child.className.toString().toLowerCase().includes('close');
if (isClose) {
child.style.setProperty('position', 'absolute', 'important');
child.style.setProperty('left', '50%', 'important');
child.style.setProperty('right', 'auto', 'important');
child.style.setProperty('top', '8px', 'important');
child.style.setProperty('transform', 'translateX(-50%)', 'important');
child.style.setProperty('margin', '0', 'important');
}
});
}
});
_legitMenuObserver.observe(document.body, { childList: true, subtree: true, attributes: true });
updateCSS();
const miniSwitchGlobalStyles = document.createElement('style');
miniSwitchGlobalStyles.innerHTML = `
.legit-sub-panel {
margin: -4px 0 10px 10px;
padding: 10px 14px;
background: rgba(0, 0, 0, 0.15);
border-left: 3px solid #5a5a62;
border-radius: 0 0 8px 8px;
display: flex;
flex-direction: column;
gap: 8px;
box-sizing: border-box;
}
.legit-mini-row {
display: flex;
justify-content: space-between;
align-items: center;
font-size: 14px;
}
.legit-mini-label {
font-weight: 900;
transition: color 0.2s;
}
.legit-mini-switch {
position: relative;
display: inline-block;
width: 34px;
height: 20px;
cursor: pointer;
}
.legit-mini-switch input { opacity: 0; width: 0; height: 0; margin: 0; }
.legit-mini-slider {
position: absolute;
top: 0; left: 0; right: 0; bottom: 0;
background-color: #cc5151;
transition: .2s ease-in-out; border-radius: 20px;
box-shadow: inset 0 1px 3px rgba(0,0,0,0.4);
}
.legit-mini-slider:before {
position: absolute;
content: ""; height: 14px; width: 14px; left: 3px; bottom: 3px;
background-color: white; transition: .2s ease-in-out; border-radius: 50%;
box-shadow: 0 1px 2px rgba(0,0,0,0.4);
}
.legit-mini-switch input:checked + .legit-mini-slider { background-color: #a4cc4f; }
.legit-mini-switch input:checked + .legit-mini-slider:before { transform: translateX(14px); }
.legit-arrow-btn {
cursor: pointer;
font-size: 13px;
transition: all 0.15s;
user-select: none;
padding: 2px 7px;
border-radius: 5px;
font-weight: 900;
}
.legit-arrow-btn:hover { transform: scale(1.08); }
#stats-overlay-container, #kv-overlay-container {
transition: border-color 0.25s, color 0.25s, box-shadow 0.25s;
}
.kv-cell {
transition: background 0.06s ease, color 0.06s ease, border-color 0.06s ease, transform 0.06s ease!important;
}
#stats-drag-handle, #kv-drag-handle {
transition: background 0.2s, color 0.2s;
}
`;
document.head.appendChild(miniSwitchGlobalStyles);
const menuContainer = document.createElement('div');
menuContainer.id = 'legit-script-menu';
Object.assign(menuContainer.style, {
position: 'fixed', top: '50%', left: '50%',
transform: 'translate(-50%,-50%)',
width: '820px', height: '460px',
borderRadius: '20px', padding: '25px 20px 20px 20px',
zIndex: '1000000', fontFamily: "'Baloo Paaji', cursive, sans-serif",
fontWeight: '900', display: 'none',
boxShadow: '0 0 40px rgba(0,0,0,0.6)',
userSelect: 'none', WebkitFontSmoothing: 'antialiased',
boxSizing: 'border-box',
transition: 'background-color 0.2s, color 0.2s, border-color 0.2s'
});
const xCloseBtn = document.createElement('div');
xCloseBtn.innerText = "✕";
Object.assign(xCloseBtn.style, {
position: 'absolute', top: '18px', right: '20px',
fontSize: '20px', cursor: 'pointer',
transition: 'color 0.15s, transform 0.1s'
});
xCloseBtn.onclick = () => toggleMenu(false);
xCloseBtn.onmouseenter = () => { xCloseBtn.style.transform = "scale(1.15)"; };
xCloseBtn.onmouseleave = () => { xCloseBtn.style.transform = "scale(1)"; };
menuContainer.appendChild(xCloseBtn);
const toggleWrapper = document.createElement('div');
Object.assign(toggleWrapper.style, {
position: 'absolute', top: '15px', left: '20px',
width: '65px', height: '32px', zIndex: '1000002'
});
const toggleLabel = document.createElement('label');
Object.assign(toggleLabel.style, {
position: 'relative', display: 'inline-block',
width: '100%', height: '100%', cursor: 'pointer'
});
const toggleInput = document.createElement('input');
toggleInput.type = 'checkbox';
toggleInput.checked = config.lightMode;
Object.assign(toggleInput.style, { opacity: '0', width: '0', height: '0', margin: '0' });
toggleLabel.appendChild(toggleInput);
const toggleSlider = document.createElement('div');
Object.assign(toggleSlider.style, {
position: 'absolute', top: '0', left: '0', right: '0', bottom: '0',
borderRadius: '30px', overflow: 'hidden',
transition: 'background-color 0.4s',
boxShadow: 'inset 0 2px 5px rgba(0,0,0,0.4)'
});
toggleLabel.appendChild(toggleSlider);
const sliderDecorations = document.createElement('div');
Object.assign(sliderDecorations.style, {
width: '100%', height: '100%', position: 'relative', pointerEvents: 'none'
});
toggleSlider.appendChild(sliderDecorations);
const toggleCircle = document.createElement('div');
Object.assign(toggleCircle.style, {
position: 'absolute', height: '24px', width: '24px',
left: '4px', bottom: '4px', borderRadius: '50%', zIndex: '2',
transition: 'transform 0.4s cubic-bezier(0.4,0,0.2,1), background-color 0.4s, box-shadow 0.4s'
});
toggleLabel.appendChild(toggleCircle);
toggleWrapper.appendChild(toggleLabel);
menuContainer.appendChild(toggleWrapper);
const switchArtStyle = document.createElement('style');
switchArtStyle.innerHTML = `
.legit-slider-bg{background-color:#2c3e50;}
.legit-circle-art{background-color:#f1c40f;box-shadow:inset -3px 2px 0 0 #f39c12,0 0 10px rgba(241,196,15,0.4);}
.legit-star-1,.legit-star-2,.legit-crater{position:absolute;background:white;border-radius:50%;transition:opacity 0.3s;}
.legit-star-1{width:3px;height:3px;top:8px;right:16px;opacity:0.8;}
.legit-star-2{width:2px;height:2px;bottom:8px;right:26px;opacity:0.5;}
.legit-crater{width:4px;height:4px;background:rgba(0,0,0,0.12);opacity:1;top:6px;left:6px;}
.legit-crater-2{position:absolute;width:3px;height:3px;background:rgba(0,0,0,0.12);border-radius:50%;bottom:6px;left:10px;}
.legit-cloud-1,.legit-cloud-2{position:absolute;background:#fff;border-radius:10px;opacity:0;transform:translateY(20px);transition:transform 0.4s,opacity 0.3s;}
.legit-cloud-1{width:22px;height:8px;bottom:4px;left:8px;}
.legit-cloud-2{width:16px;height:6px;bottom:10px;left:22px;}
input:checked+div{background-color:#56ccf2!important;}
input:checked+div .legit-star-1,input:checked+div .legit-star-2{opacity:0!important;}
input:checked+div .legit-cloud-1{opacity:0.9!important;transform:translateY(0);}
input:checked+div .legit-cloud-2{opacity:0.8!important;transform:translateY(0);}
input:checked~.legit-circle-art{transform:translateX(33px)!important;background-color:#ffdb58!important;box-shadow:0 0 14px #ffb300,inset -2px -2px 0 rgba(0,0,0,0.1)!important;}
input:checked~.legit-circle-art .legit-crater,input:checked~.legit-circle-art .legit-crater-2{opacity:0!important;}
`;
document.head.appendChild(switchArtStyle);
['legit-star-1','legit-star-2','legit-cloud-1','legit-cloud-2'].forEach(cls => {
const el = document.createElement('div'); el.className = cls; sliderDecorations.appendChild(el);
});
const crater1 = document.createElement('div'); crater1.className = 'legit-crater'; toggleCircle.appendChild(crater1);
const crater2 = document.createElement('div'); crater2.className = 'legit-crater-2'; toggleCircle.appendChild(crater2);
toggleSlider.className = 'legit-slider-bg';
toggleCircle.className = 'legit-circle-art';
const title = document.createElement('h2');
title.innerText = "SPLOOP.IO LEGIT SCRIPT";
Object.assign(title.style, {
margin: '0 0 20px 0', textAlign: 'center',
paddingBottom: '12px', fontSize: '28px', letterSpacing: '1px',
transition: 'color 0.2s, border-color 0.2s'
});
menuContainer.appendChild(title);
const mainLayout = document.createElement('div');
mainLayout.style.cssText = "display:flex;width:100%;height:350px;gap:15px;box-sizing:border-box;";
menuContainer.appendChild(mainLayout);
const leftPanel = document.createElement('div');
leftPanel.style.cssText = "flex:1;display:flex;flex-direction:column;justify-content:space-between;border-radius:12px;padding:12px;box-sizing:border-box;transition:background-color 0.2s,border-color 0.2s;";
mainLayout.appendChild(leftPanel);
const navContainer = document.createElement('div');
navContainer.style.cssText = "display:flex;flex-direction:column;gap:8px;";
leftPanel.appendChild(navContainer);
const navBtnBase = "padding:10px 14px;font-weight:900;border-radius:8px;cursor:pointer;font-family:'Baloo Paaji';transition:background-color 0.2s,color 0.2s,border-color 0.2s; border:none; font-size:15px; text-align:left; width:100%;";
const navVisualsBtn = document.createElement('button');
navVisualsBtn.innerText = "👁️ Visuals";
navVisualsBtn.style.cssText = navBtnBase;
navContainer.appendChild(navVisualsBtn);
const navHudBtn = document.createElement('button');
navHudBtn.innerText = "📊 HUD Elements";
navHudBtn.style.cssText = navBtnBase;
navContainer.appendChild(navHudBtn);
const navSystemBtn = document.createElement('button');
navSystemBtn.innerText = "🛠️ System & Ads";
navSystemBtn.style.cssText = navBtnBase;
navContainer.appendChild(navSystemBtn);
const navCreditBtn = document.createElement('button');
navCreditBtn.innerText = "📜 View Credits";
navCreditBtn.style.cssText = navBtnBase + "text-align:center;";
leftPanel.appendChild(navCreditBtn);
const rightPanel = document.createElement('div');
rightPanel.id = 'legit-right-panel';
rightPanel.style.cssText = "flex:2.6;border-radius:12px;padding:15px;overflow-y:auto;box-sizing:border-box;transition:background-color 0.2s,color 0.2s,border-color 0.2s;";
mainLayout.appendChild(rightPanel);
const scrollbarStyle = document.createElement('style');
scrollbarStyle.innerHTML = `
#legit-right-panel::-webkit-scrollbar{width:6px;}
#legit-right-panel::-webkit-scrollbar-track{background:transparent;}
#legit-right-panel::-webkit-scrollbar-thumb{background:rgba(90,90,98,0.3);border-radius:10px;}
#legit-right-panel::-webkit-scrollbar-thumb:hover{background:rgba(90,90,98,0.6);}
#legit-right-panel::-webkit-scrollbar-button{display:none;}
`;
document.head.appendChild(scrollbarStyle);
const visualsContent = document.createElement('div');
visualsContent.style.cssText = "display:block;width:100%;";
rightPanel.appendChild(visualsContent);
const hudContent = document.createElement('div');
hudContent.style.cssText = "display:none;width:100%;";
rightPanel.appendChild(hudContent);
const systemContent = document.createElement('div');
systemContent.style.cssText = "display:none;width:100%;";
rightPanel.appendChild(systemContent);
const creditContent = document.createElement('div');
creditContent.style.cssText = "display:none;width:100%;height:100%;flex-direction:column;justify-content:center;align-items:center;text-align:center;gap:15px;";
rightPanel.appendChild(creditContent);
function applyGlobalTheme() {
const isLight = config.lightMode;
const statsContainer = document.getElementById('stats-overlay-container');
const kvContainer = document.getElementById('kv-overlay-container');
if (isLight) {
Object.assign(menuContainer.style, { backgroundColor: '#ffffff', color: '#000000', borderColor: '#cccccc' });
Object.assign(title.style, { color: '#000000', borderBottom: '3px solid #e5e5e5' });
xCloseBtn.style.color = '#333333';
Object.assign(leftPanel.style, { backgroundColor: '#f4f4f6', borderColor: '#e5e5e5' });
Object.assign(rightPanel.style, { backgroundColor: '#fcfcfd', borderColor: '#e5e5e5', color: '#000000' });
if (statsContainer) {
statsContainer.style.borderColor = 'rgba(0, 0, 0, 0.12)';
statsContainer.style.color = '#111111';
statsContainer.style.boxShadow = '0 10px 30px rgba(0, 0, 0, 0.15)';
document.getElementById('stats-drag-handle').style.background = 'rgba(0, 0, 0, 0.05)';
document.getElementById('stats-drag-handle').style.color = 'rgba(0, 0, 0, 0.25)';
}
if (kvContainer) {
kvContainer.style.borderColor = 'rgba(0, 0, 0, 0.12)';
kvContainer.style.boxShadow = '0 10px 30px rgba(0, 0, 0, 0.15)';
document.getElementById('kv-drag-handle').style.background = 'rgba(0, 0, 0, 0.05)';
document.getElementById('kv-drag-handle').style.color = 'rgba(0, 0, 0, 0.25)';
kvContainer.querySelectorAll('.kv-cell').forEach(cell => {
cell.style.background = 'rgba(0, 0, 0, 0.05)';
cell.style.borderColor = 'rgba(0, 0, 0, 0.04)';
cell.style.color = '#222222';
cell.style.textShadow = 'none';
});
}
} else {
Object.assign(menuContainer.style, { backgroundColor: 'rgba(20,20,22,0.98)', color: '#ffffff', borderColor: '#5a5a62' });
Object.assign(title.style, { color: '#e5e5e5', borderBottom: '3px solid #3a3a42' });
xCloseBtn.style.color = '#aaaaaa';
Object.assign(leftPanel.style, { backgroundColor: 'rgba(255,255,255,0.03)', borderColor: '#3a3a42' });
Object.assign(rightPanel.style, { backgroundColor: 'rgba(12,12,14,0.6)', borderColor: '#3a3a42', color: '#ffffff' });
if (statsContainer) {
statsContainer.style.borderColor = 'rgba(255, 255, 255, 0.08)';
statsContainer.style.color = '#ffffff';
statsContainer.style.boxShadow = '0 12px 40px rgba(0, 0, 0, 0.6)';
document.getElementById('stats-drag-handle').style.background = 'rgba(255, 255, 255, 0.06)';
document.getElementById('stats-drag-handle').style.color = 'rgba(255, 255, 255, 0.3)';
}
if (kvContainer) {
kvContainer.style.borderColor = 'rgba(255, 255, 255, 0.08)';
kvContainer.style.boxShadow = '0 12px 40px rgba(0, 0, 0, 0.6)';
document.getElementById('kv-drag-handle').style.background = 'rgba(255, 255, 255, 0.06)';
document.getElementById('kv-drag-handle').style.color = 'rgba(255, 255, 255, 0.3)';
kvContainer.querySelectorAll('.kv-cell').forEach(cell => {
cell.style.background = 'rgba(255, 255, 255, 0.06)';
cell.style.borderColor = 'rgba(255, 255, 255, 0.03)';
cell.style.color = '#e5e7eb';
cell.style.textShadow = '1px 1px 0px rgba(0, 0, 0, 0.4)';
});
}
}
[visualsContent, hudContent, systemContent, creditContent].forEach(box => {
box.querySelectorAll('.legit-toggle-label').forEach(l => { l.style.color = isLight ? '#000000' : '#ffffff'; });
box.querySelectorAll('.legit-group-title').forEach(t => { t.style.color = isLight ? '#55555d' : '#8a8a92'; });
box.querySelectorAll('.legit-mini-label').forEach(l => { l.style.color = isLight ? '#44444a' : '#b5b5bd'; });
box.querySelectorAll('.legit-arrow-btn').forEach(a => {
a.style.color = isLight ? '#222225' : '#8a8a92';
a.style.background = isLight ? 'rgba(0,0,0,0.06)' : 'rgba(255,255,255,0.06)';
});
});
}
function createGroupTitle(targetBox, name) {
const el = document.createElement('div');
el.className = 'legit-group-title';
el.innerText = name;
el.style.cssText = "font-size:17px;margin:5px 0 12px 0;border-left:4px solid #5a5a62;padding-left:8px;letter-spacing:0.5px;font-weight:900;transition:color 0.2s;";
targetBox.appendChild(el);
}
function createToggle(targetBox, labelText, configKey, callback) {
const wrapper = document.createElement('div');
wrapper.style.cssText = "margin-bottom:10px;display:flex;justify-content:space-between;align-items:center;background:rgba(150,150,150,0.04);padding:8px 14px;border-radius:8px;border:1px solid rgba(150,150,150,0.06);";
const label = document.createElement('span');
label.className = 'legit-toggle-label';
label.innerText = labelText;
label.style.cssText = "font-size:16px;font-weight:900;transition:color 0.2s;";
const btn = document.createElement('button');
btn.style.cssText = "width:70px;height:30px;border:2px solid rgba(0,0,0,0.15);border-radius:6px;font-weight:900;cursor:pointer;font-family:'Baloo Paaji',cursive;transition:all 0.2s;font-size:14px;color:white;";
const updateBtnState = () => {
if (config[configKey]) {
btn.innerText = "ON";
btn.style.background = "#a4cc4f";
btn.style.boxShadow = "0 3px 0 #7ca232";
} else {
btn.innerText = "OFF";
btn.style.background = "#cc5151";
btn.style.boxShadow = "0 3px 0 #a33838";
}
btn.style.transform = "translateY(0)";
};
updateBtnState();
btn.onclick = () => {
config[configKey] = !config[configKey];
updateBtnState();
saveConfig();
if (callback) callback(config[configKey]);
};
btn.onmousedown = () => { btn.style.boxShadow = "none"; btn.style.transform = "translateY(3px)"; };
btn.onmouseup = () => { updateBtnState(); };
wrapper.appendChild(label);
wrapper.appendChild(btn);
targetBox.appendChild(wrapper);
return wrapper;
}
function createCollapsibleToggle(targetBox, labelText, configKey, subPanelEl, callback) {
const wrapper = document.createElement('div');
wrapper.style.cssText = "margin-bottom:10px;display:flex;justify-content:space-between;align-items:center;background:rgba(150,150,150,0.04);padding:8px 14px;border-radius:8px;border:1px solid rgba(150,150,150,0.06);";
const leftCluster = document.createElement('div');
leftCluster.style.cssText = "display:flex;align-items:center;gap:12px;";
const label = document.createElement('span');
label.className = 'legit-toggle-label';
label.innerText = labelText;
label.style.cssText = "font-size:16px;font-weight:900;transition:color 0.2s;";
leftCluster.appendChild(label);
const arrow = document.createElement('span');
arrow.className = 'legit-arrow-btn';
arrow.innerText = "▼";
leftCluster.appendChild(arrow);
wrapper.appendChild(leftCluster);
const btn = document.createElement('button');
btn.style.cssText = "width:70px;height:30px;border:2px solid rgba(0,0,0,0.15);border-radius:6px;font-weight:900;cursor:pointer;font-family:'Baloo Paaji',cursive;transition:all 0.2s;font-size:14px;color:white;";
wrapper.appendChild(btn);
let isCollapsed = false;
const refreshCollapseLayout = () => {
if (!config[configKey]) {
subPanelEl.style.display = 'none';
arrow.style.opacity = '0.25';
arrow.style.pointerEvents = 'none';
} else {
arrow.style.opacity = '1';
arrow.style.pointerEvents = 'auto';
if (isCollapsed) {
subPanelEl.style.display = 'none';
arrow.innerText = "▶";
} else {
subPanelEl.style.display = 'flex';
arrow.innerText = "▼";
}
}
};
const updateBtnState = () => {
if (config[configKey]) {
btn.innerText = "ON";
btn.style.background = "#a4cc4f";
btn.style.boxShadow = "0 3px 0 #7ca232";
} else {
btn.innerText = "OFF";
btn.style.background = "#cc5151";
btn.style.boxShadow = "0 3px 0 #a33838";
}
btn.style.transform = "translateY(0)";
refreshCollapseLayout();
};
arrow.onclick = (e) => {
e.stopPropagation();
if (!config[configKey]) return;
isCollapsed = !isCollapsed;
refreshCollapseLayout();
};
btn.onclick = () => {
config[configKey] = !config[configKey];
updateBtnState();
saveConfig();
if (callback) callback(config[configKey]);
};
btn.onmousedown = () => { btn.style.boxShadow = "none"; btn.style.transform = "translateY(3px)"; };
btn.onmouseup = () => { updateBtnState(); };
targetBox.appendChild(wrapper);
updateBtnState();
return wrapper;
}
function createMiniSwitch(parentEl, labelText, configKey, onToggle) {
const row = document.createElement('div');
row.className = 'legit-mini-row';
const label = document.createElement('span');
label.className = 'legit-mini-label';
label.innerText = labelText;
const switchContainer = document.createElement('label');
switchContainer.className = 'legit-mini-switch';
const input = document.createElement('input');
input.type = 'checkbox';
input.checked = config[configKey];
const slider = document.createElement('span');
slider.className = 'legit-mini-slider';
input.addEventListener('change', () => {
config[configKey] = input.checked;
saveConfig();
if (onToggle) onToggle(input.checked);
});
switchContainer.appendChild(input);
switchContainer.appendChild(slider);
row.appendChild(label);
row.appendChild(switchContainer);
parentEl.appendChild(row);
}
function createSlider(parentEl, labelText, configKey, min, max, step, callback) {
const row = document.createElement('div');
row.className = 'legit-mini-row';
row.style.marginBottom = '6px';
const label = document.createElement('span');
label.className = 'legit-mini-label';
label.innerText = labelText;
const valDisplay = document.createElement('span');
valDisplay.innerText = config[configKey];
valDisplay.style.cssText = "font-weight:900; font-size:13px; min-width:24px; text-align:right;";
const input = document.createElement('input');
input.type = 'range';
input.min = min;
input.max = max;
input.step = step;
input.value = config[configKey];
input.style.cssText = "width: 80px; cursor: pointer; accent-color: #a4cc4f;";
let _rafId = null;
input.addEventListener('input', () => {
config[configKey] = parseFloat(input.value);
valDisplay.innerText = config[configKey];
saveConfig();
if (callback) {
if (_rafId) cancelAnimationFrame(_rafId);
_rafId = requestAnimationFrame(() => { _rafId = null; callback(); });
}
});
const rightContainer = document.createElement('div');
rightContainer.style.cssText = "display:flex; align-items:center; gap:8px;";
rightContainer.appendChild(input);
rightContainer.appendChild(valDisplay);
row.appendChild(label);
row.appendChild(rightContainer);
parentEl.appendChild(row);
}
function createStepControl(parentEl, labelText, configKey, min, max, step, displayFn, callback) {
const row = document.createElement('div');
row.className = 'legit-mini-row';
row.style.marginBottom = '6px';
const label = document.createElement('span');
label.className = 'legit-mini-label';
label.innerText = labelText;
const fmt = displayFn || ((v) => v);
const valDisplay = document.createElement('span');
valDisplay.style.cssText = "font-weight:900; font-size:13px; min-width:36px; text-align:center; font-family:'Baloo Paaji',cursive;";
valDisplay.innerText = fmt(config[configKey]);
const btnStyle = (dir) => `
width:26px; height:26px; border-radius:6px; border:none; cursor:pointer;
font-weight:900; font-size:15px; line-height:1;
font-family:'Baloo Paaji',cursive; color:#fff;
background:${dir === '-' ? '#cc5151' : '#a4cc4f'};
box-shadow:0 2px 0 ${dir === '-' ? '#a33838' : '#7ca232'};
transition:transform 0.07s, box-shadow 0.07s;
display:flex; align-items:center; justify-content:center;
`;
const btnDec = document.createElement('button');
btnDec.innerText = '−';
btnDec.style.cssText = btnStyle('-');
const btnInc = document.createElement('button');
btnInc.innerText = '+';
btnInc.style.cssText = btnStyle('+');
const clamp = (v) => Math.round(Math.min(max, Math.max(min, v)) / step) * step;
const apply = () => {
valDisplay.innerText = fmt(config[configKey]);
saveConfig();
if (callback) callback();
};
btnDec.onmousedown = () => { btnDec.style.transform='translateY(2px)'; btnDec.style.boxShadow='none'; };
btnDec.onmouseup = () => { btnDec.style.transform=''; btnDec.style.boxShadow='0 2px 0 #a33838'; };
btnInc.onmousedown = () => { btnInc.style.transform='translateY(2px)'; btnInc.style.boxShadow='none'; };
btnInc.onmouseup = () => { btnInc.style.transform=''; btnInc.style.boxShadow='0 2px 0 #7ca232'; };
btnDec.onclick = () => { config[configKey] = parseFloat(clamp(config[configKey] - step).toFixed(10)); apply(); };
btnInc.onclick = () => { config[configKey] = parseFloat(clamp(config[configKey] + step).toFixed(10)); apply(); };
let _holdTimer = null;
const startHold = (btn, dir) => {
clearInterval(_holdTimer);
_holdTimer = setInterval(() => {
config[configKey] = parseFloat(clamp(config[configKey] + dir * step).toFixed(10));
apply();
}, 80);
};
const stopHold = () => clearInterval(_holdTimer);
btnDec.addEventListener('mousedown', () => startHold(btnDec, -1));
btnInc.addEventListener('mousedown', () => startHold(btnInc, +1));
['mouseup','mouseleave'].forEach(e => {
btnDec.addEventListener(e, stopHold);
btnInc.addEventListener(e, stopHold);
});
const rightContainer = document.createElement('div');
rightContainer.style.cssText = "display:flex; align-items:center; gap:5px;";
rightContainer.appendChild(btnDec);
rightContainer.appendChild(valDisplay);
rightContainer.appendChild(btnInc);
row.appendChild(label);
row.appendChild(rightContainer);
parentEl.appendChild(row);
}
function createColorPicker(parentEl, labelText, configKey, callback) {
const row = document.createElement('div');
row.className = 'legit-mini-row';
row.style.marginBottom = '6px';
const label = document.createElement('span');
label.className = 'legit-mini-label';
label.innerText = labelText;
const inputContainer = document.createElement('div');
inputContainer.style.cssText = "display:flex; align-items:center; gap:8px;";
const input = document.createElement('input');
input.type = 'color';
input.value = config[configKey];
input.style.cssText = "width: 30px; height: 20px; border: none; cursor: pointer; padding: 0; background: transparent;";
input.addEventListener('input', () => {
config[configKey] = input.value;
saveConfig();
if (callback) callback(input.value);
});
inputContainer.appendChild(input);
row.appendChild(label);
row.appendChild(inputContainer);
parentEl.appendChild(row);
}
createGroupTitle(visualsContent, "👁️ VISUAL SETTINGS");
const ghostSubPanel = document.createElement('div');
ghostSubPanel.className = 'legit-sub-panel';
createCollapsibleToggle(visualsContent, "Ghost Mode", "ghostMode", ghostSubPanel, (val) => { });
visualsContent.appendChild(ghostSubPanel);
createStepControl(ghostSubPanel, "Tree / Wood", "ghostOpacityTree", 0.0, 1.0, 0.05, (v) => Math.round(v * 100) + '%');
createStepControl(ghostSubPanel, "Rock / Stone", "ghostOpacityStone", 0.0, 1.0, 0.05, (v) => Math.round(v * 100) + '%');
createStepControl(ghostSubPanel, "Bush / Cactus", "ghostOpacityBush", 0.0, 1.0, 0.05, (v) => Math.round(v * 100) + '%');
createStepControl(ghostSubPanel, "Gold / Ruby / Chest", "ghostOpacityGold", 0.0, 1.0, 0.05, (v) => Math.round(v * 100) + '%');
createStepControl(ghostSubPanel, "Wall / Platform", "ghostOpacityWall", 0.0, 1.0, 0.05, (v) => Math.round(v * 100) + '%');
createStepControl(ghostSubPanel, "Spike", "ghostOpacitySpike", 0.0, 1.0, 0.05, (v) => Math.round(v * 100) + '%');
createStepControl(ghostSubPanel, "Windmill / Turret / Trap", "ghostOpacityBuilding", 0.0, 1.0, 0.05, (v) => Math.round(v * 100) + '%');
createStepControl(ghostSubPanel, "Tornado / Ice / Fire", "ghostOpacityMisc", 0.0, 1.0, 0.05, (v) => Math.round(v * 100) + '%');
const hitboxSubPanel = document.createElement('div');
hitboxSubPanel.className = 'legit-sub-panel';
createCollapsibleToggle(visualsContent, "Hitboxes", "hitbox", hitboxSubPanel, (val) => { });
visualsContent.appendChild(hitboxSubPanel);
createColorPicker(hitboxSubPanel, "Enemy", "hitboxColorEnemy");
createColorPicker(hitboxSubPanel, "Ally", "hitboxColorAlly");
createColorPicker(hitboxSubPanel, "Mob", "hitboxColorMob");
createColorPicker(hitboxSubPanel, "Block", "hitboxColorBlock");
createStepControl(hitboxSubPanel, "Line Thickness", "hitboxWidth", 0.5, 8.0, 0.5, (v) => v.toFixed(1) + 'px');
const tracersSubPanel = document.createElement('div');
tracersSubPanel.className = 'legit-sub-panel';
createCollapsibleToggle(visualsContent, "Tracers", "tracers", tracersSubPanel, (val) => { });
visualsContent.appendChild(tracersSubPanel);
createColorPicker(tracersSubPanel, "Enemy Line Color", "tracerColorEnemy");
createColorPicker(tracersSubPanel, "Ally Line Color", "tracerColorAlly");
createColorPicker(tracersSubPanel, "Mob Line Color", "tracerColorMob");
createStepControl(tracersSubPanel, "Line Thickness", "tracerWidth", 0.5, 5.0, 0.5, (v) => v.toFixed(1) + 'px');
createStepControl(tracersSubPanel, "Line Opacity", "tracerOpacity", 0.1, 1.0, 0.1, (v) => Math.round(v * 100) + '%');
createMiniSwitch(tracersSubPanel, "Players (Enemy)", "tracerPlayer");
createMiniSwitch(tracersSubPanel, "Players (Ally)", "tracerAlly");
createMiniSwitch(tracersSubPanel, "Cow", "tracerCow");
createMiniSwitch(tracersSubPanel, "Duck", "tracerDuck");
createMiniSwitch(tracersSubPanel, "Wolf", "tracerWolf");
createMiniSwitch(tracersSubPanel, "Shark", "tracerShark");
createMiniSwitch(tracersSubPanel, "Crocodile", "tracerCrocodile");
createMiniSwitch(tracersSubPanel, "Golden Cow", "tracerGcow");
createMiniSwitch(tracersSubPanel, "Mammoth", "tracerMammoth");
createMiniSwitch(tracersSubPanel, "Dragon", "tracerDragon");
createToggle(visualsContent, "Big Shop & Transparent UI", "transparentUI", updateCSS);
createGroupTitle(hudContent, "📊 ON-SCREEN HUD INDICATORS");
createToggle(hudContent, "Item Counter", "itemCounter");
const hpSubPanel = document.createElement('div');
hpSubPanel.className = 'legit-sub-panel';
createCollapsibleToggle(hudContent, "Better Health Bar", "betterHealthBar", hpSubPanel, (val) => { });
hudContent.appendChild(hpSubPanel);
(() => {
const headerRow = document.createElement('div');
headerRow.style.cssText = "display:flex;align-items:center;margin-bottom:4px;";
const headerSpacer = document.createElement('span');
headerSpacer.style.cssText = "flex:1;";
const allyHeader = document.createElement('span');
allyHeader.className = 'legit-mini-label';
allyHeader.innerText = "Ally";
allyHeader.style.cssText = "width:52px;text-align:center;font-size:12px;";
const enemyHeader = document.createElement('span');
enemyHeader.className = 'legit-mini-label';
enemyHeader.innerText = "Enemy";
enemyHeader.style.cssText = "width:52px;text-align:center;font-size:12px;";
headerRow.appendChild(headerSpacer);
headerRow.appendChild(allyHeader);
headerRow.appendChild(enemyHeader);
hpSubPanel.appendChild(headerRow);
function createDualColorRow(parentEl, labelText, allyKey, enemyKey) {
const row = document.createElement('div');
row.className = 'legit-mini-row';
row.style.marginBottom = '6px';
const label = document.createElement('span');
label.className = 'legit-mini-label';
label.innerText = labelText;
label.style.flex = '1';
const makeColorCell = (configKey) => {
const wrap = document.createElement('div');
wrap.style.cssText = "width:52px;display:flex;justify-content:center;align-items:center;";
const input = document.createElement('input');
input.type = 'color';
input.value = config[configKey];
input.style.cssText = "width:30px;height:22px;border:none;cursor:pointer;padding:0;background:transparent;border-radius:4px;";
input.addEventListener('input', () => { config[configKey] = input.value; saveConfig(); });
wrap.appendChild(input);
return wrap;
};
row.appendChild(label);
row.appendChild(makeColorCell(allyKey));
row.appendChild(makeColorCell(enemyKey));
parentEl.appendChild(row);
}
createDualColorRow(hpSubPanel, "Full HP", "hpColorAllyHigh", "hpColorEnemyHigh");
createDualColorRow(hpSubPanel, "Half HP", "hpColorAllyMed", "hpColorEnemyMed");
createDualColorRow(hpSubPanel, "Low HP", "hpColorAllyLow", "hpColorEnemyLow");
})();
createMiniSwitch(hpSubPanel, "Colored Health Bar", "coloredHealthBar");
createMiniSwitch(hpSubPanel, "Smooth Health Bar", "smoothHealthBar");
createMiniSwitch(hpSubPanel, "Show % Health", "showPercentHealth");
const statsSubPanel = document.createElement('div');
statsSubPanel.className = 'legit-sub-panel';
createCollapsibleToggle(hudContent, "Stats Overlay", "showOverlay", statsSubPanel, (val) => {
const ov = document.getElementById('stats-overlay-container');
if (ov) ov.style.display = val ? 'flex' : 'none';
});
hudContent.appendChild(statsSubPanel);
createMiniSwitch(statsSubPanel, "Lock Overlay Position", "statsLocked", (val) => {
document.getElementById('stats-drag-handle').style.display = val ? 'none' : 'flex';
});
createMiniSwitch(statsSubPanel, "Show Server Name", "statsShowServer", (val) => {
document.getElementById('stat-server').style.display = val ? 'block' : 'none';
});
createMiniSwitch(statsSubPanel, "Show FPS Counter", "statsShowFps", (val) => {
document.getElementById('stat-fps').style.display = val ? 'block' : 'none';
});
createMiniSwitch(statsSubPanel, "Show CPS Counter", "statsShowCps", (val) => {
document.getElementById('stat-cps').style.display = val ? 'block' : 'none';
});
createMiniSwitch(statsSubPanel, "Show Ping Latency", "statsShowPing", (val) => {
document.getElementById('stat-ping').style.display = val ? 'block' : 'none';
});
function applyOverlayStyle() {
const sc = document.getElementById('stats-overlay-container');
if (!sc) return;
const hex = config.overlayBgColor || '#0a0a0a';
const r = parseInt(hex.slice(1,3),16), g = parseInt(hex.slice(3,5),16), b = parseInt(hex.slice(5,7),16);
sc.style.background = `rgba(${r},${g},${b},${config.overlayBgOpacity})`;
sc.style.color = config.overlayTextColor;
sc.style.fontSize = config.overlayFontSize + 'px';
}
createStepControl(statsSubPanel, "Background Opacity", "overlayBgOpacity", 0.0, 1.0, 0.05, (v) => Math.round(v * 100) + '%', applyOverlayStyle);
createColorPicker(statsSubPanel, "Background Color", "overlayBgColor", applyOverlayStyle);
createColorPicker(statsSubPanel, "Text Color", "overlayTextColor", applyOverlayStyle);
createStepControl(statsSubPanel, "Font Size (px)", "overlayFontSize", 10, 30, 1, (v) => v + 'px', applyOverlayStyle);
const kvSubPanel = document.createElement('div');
kvSubPanel.className = 'legit-sub-panel';
createCollapsibleToggle(hudContent, "Key Viewer", "keyViewer", kvSubPanel, (val) => {
const kv = document.getElementById('kv-overlay-container');
if (kv) kv.style.display = val ? 'flex' : 'none';
});
hudContent.appendChild(kvSubPanel);
createMiniSwitch(kvSubPanel, "Lock Viewer Position", "kvLocked", (val) => {
document.getElementById('kv-drag-handle').style.display = val ? 'none' : 'flex';
});
function applyKvStyle() {
const kvc = document.getElementById('kv-overlay-container');
if (!kvc) return;
const hex = config.kvBgColor || '#0a0a0a';
const r = parseInt(hex.slice(1,3),16), g = parseInt(hex.slice(3,5),16), b = parseInt(hex.slice(5,7),16);
kvc.style.background = `rgba(${r},${g},${b},${config.kvBgOpacity})`;
const base = config.kvCellSize;
const cellPx = base + 'px';
const mousePx = (base * 2 + 8) + 'px';
const spacePx = (base * 4 + 24) + 'px';
const fontSize = Math.round(base * 0.32) + 'px';
kvc.querySelectorAll('.kv-cell').forEach(cell => {
cell.style.color = config.kvTextColor;
cell.style.height = cellPx;
cell.style.fontSize = fontSize;
if (cell.classList.contains('mouse-btn')) {
cell.style.width = mousePx;
} else if (cell.classList.contains('space-btn')) {
cell.style.width = spacePx;
} else {
cell.style.width = cellPx;
}
});
}
createStepControl(kvSubPanel, "Background Opacity", "kvBgOpacity", 0.0, 1.0, 0.05, (v) => Math.round(v * 100) + '%', applyKvStyle);
createColorPicker(kvSubPanel, "Background Color", "kvBgColor", applyKvStyle);
createColorPicker(kvSubPanel, "Text Color", "kvTextColor", applyKvStyle);
createStepControl(kvSubPanel, "Key Size (px)", "kvCellSize", 28, 80, 2, (v) => v + 'px', applyKvStyle);
createGroupTitle(systemContent, "🛠️ SYSTEMS & AD-BLOCKING");
createToggle(systemContent, "Adblock", "removeAds", updateCSS);
const infoCard = document.createElement('div');
infoCard.style.cssText = "background:rgba(150,150,150,0.05);padding:25px;border-radius:15px;border:2px solid #5a5a62;box-shadow:0 5px 15px rgba(0,0,0,0.1);width:85%;";
creditContent.appendChild(infoCard);
const cardTitle = document.createElement('h3');
cardTitle.innerText = "SCRIPT DEVELOPMENT INFORMATION";
cardTitle.style.cssText = "margin:0 0 15px 0;font-size:20px;letter-spacing:1px;";
infoCard.appendChild(cardTitle);
const detailsText = document.createElement('p');
detailsText.innerHTML = "Made by <span style='font-size:24px;'>Normalplayer</span><br><br>Version: <span style='font-size:20px;'>v2.0</span><br><span style='font-size:16px; color:#a4cc4f;'></span>";
detailsText.style.cssText = "font-size:18px;line-height:1.6;margin:0 0 20px 0;";
infoCard.appendChild(detailsText);
const linkBtn = document.createElement('button');
linkBtn.innerText = "🔗 Open Sploop Source Viewer";
linkBtn.style.cssText = "padding:10px 20px;background:#5a5a62;border:none;color:#fff;font-weight:900;border-radius:8px;cursor:pointer;font-family:'Baloo Paaji';font-size:15px;box-shadow:0 4px 0 #3a3a42;transition:all 0.1s;";
linkBtn.onclick = () => window.open("https://bruhhh30092012-max.github.io/sploop-source-viewer-v0.3/", "_blank");
linkBtn.onmousedown = () => { linkBtn.style.boxShadow = "none"; linkBtn.style.transform = "translateY(4px)"; };
linkBtn.onmouseup = () => { linkBtn.style.transform = "translateY(0)"; linkBtn.style.boxShadow = "0 4px 0 #3a3a42"; };
infoCard.appendChild(linkBtn);
const compartments = [
{ btn: navVisualsBtn, box: visualsContent },
{ btn: navHudBtn, box: hudContent },
{ btn: navSystemBtn, box: systemContent },
{ btn: navCreditBtn, box: creditContent }
];
function shiftCompartment(targetIdx) {
compartments.forEach((section, idx) => {
const isActive = idx === targetIdx;
section.box.style.display = isActive ? (section.box === creditContent ? "flex" : "block") : "none";
const isLight = config.lightMode;
if (isActive) {
section.btn.style.backgroundColor = isLight ? "#000000" : "#5a5a62";
section.btn.style.color = "#ffffff";
} else {
section.btn.style.backgroundColor = isLight ? "#e5e5e7" : "#25252a";
section.btn.style.color = isLight ? "#000000" : "#b5b5bd";
}
});
}
navVisualsBtn.onclick = () => shiftCompartment(0);
navHudBtn.onclick = () => shiftCompartment(1);
navSystemBtn.onclick = () => shiftCompartment(2);
navCreditBtn.onclick = () => shiftCompartment(3);
document.body.appendChild(menuContainer);
toggleInput.onchange = () => {
config.lightMode = toggleInput.checked;
applyGlobalTheme();
shiftCompartment(compartments.findIndex(s => s.box.style.display === "block" || s.box.style.display === "flex"));
saveConfig();
};
let isMenuOpen = false;
function toggleMenu(forceState) {
isMenuOpen = (typeof forceState !== 'undefined') ? forceState : !isMenuOpen;
menuContainer.style.display = isMenuOpen ? 'block' : 'none';
}
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape') {
e.preventDefault();
e.stopImmediatePropagation();
toggleMenu();
}
});
const overlayCanvas = document.createElement("canvas");
overlayCanvas.id = 'hitbox-overlay-canvas';
overlayCanvas.width = window.innerWidth;
overlayCanvas.height = window.innerHeight;
Object.assign(overlayCanvas.style, {
position: "absolute", top: "0", left: "0",
pointerEvents: "none", zIndex: "9998"
});
document.body.appendChild(overlayCanvas);
const octx = overlayCanvas.getContext("2d");
const statsStyle = document.createElement('style');
statsStyle.innerHTML = `
#stats-overlay-container {
position: fixed;
top: 20px; left: 20px;
border: 1px solid transparent;
padding: 10px 18px 12px 18px;
border-radius: 14px; z-index: 999999;
display: ${config.showOverlay ? 'flex' : 'none'};
flex-direction: column; gap: 4px;
font-family: 'Baloo Paaji', cursive, sans-serif;
font-weight: 900; user-select: none;
pointer-events: none; font-size: 17px;
letter-spacing: 0.5px;
}
#stats-drag-handle {
height: 16px; border-radius: 6px;
cursor: move; pointer-events: auto;
display: flex; align-items: center;
justify-content: center; font-size: 9px;
letter-spacing: 3px; margin-bottom: 3px;
}
#stats-drag-handle:hover {
background: rgba(150, 150, 150, 0.25)!important;
color: currentColor!important;
}
.stat-line { white-space: nowrap; }
`;
document.head.appendChild(statsStyle);
const statsContainer = document.createElement('div');
statsContainer.id = 'stats-overlay-container';
statsContainer.innerHTML = `
<div id="stats-drag-handle">••••</div>
<div id="stat-server" class="stat-line">SERVER: Loading...</div>
<div id="stat-fps" class="stat-line">FPS: --</div>
<div id="stat-cps" class="stat-line">CPS: 0</div>
<div id="stat-ping" class="stat-line">PING: --ms</div>
`;
document.body.appendChild(statsContainer);
const savedStatsX = localStorage.getItem('stats-pos-x');
const savedStatsY = localStorage.getItem('stats-pos-y');
if (savedStatsX && savedStatsY) {
statsContainer.style.left = savedStatsX;
statsContainer.style.top = savedStatsY;
}
document.getElementById('stats-drag-handle').style.display = config.statsLocked ? 'none' : 'flex';
document.getElementById('stat-server').style.display = config.statsShowServer ? 'block' : 'none';
document.getElementById('stat-fps').style.display = config.statsShowFps ? 'block' : 'none';
document.getElementById('stat-cps').style.display = config.statsShowCps ? 'block' : 'none';
document.getElementById('stat-ping').style.display = config.statsShowPing ? 'block' : 'none';
(() => {
const sc = document.getElementById('stats-overlay-container');
if (!sc) return;
const hex = config.overlayBgColor || '#0a0a0a';
const r = parseInt(hex.slice(1,3),16), g = parseInt(hex.slice(3,5),16), b = parseInt(hex.slice(5,7),16);
sc.style.background = `rgba(${r},${g},${b},${config.overlayBgOpacity})`;
sc.style.color = config.overlayTextColor;
sc.style.fontSize = config.overlayFontSize + 'px';
})();
const statsHandle = document.getElementById('stats-drag-handle');
let isStatsDragging = false;
let statsOffsetX = 0, statsOffsetY = 0;
statsHandle.addEventListener('mousedown', (e) => {
if(config.statsLocked) return;
isStatsDragging = true;
const rect = statsContainer.getBoundingClientRect();
statsOffsetX = e.clientX - rect.left;
statsOffsetY = e.clientY - rect.top;
e.preventDefault();
});
let frameCount = 0, fpsStartTime = performance.now(), fps = 0;
let serverName = "Unknown";
let ping = '...';
const _origWSSend = WebSocket.prototype.send;
WebSocket.prototype.send = function (...args) {
this._lastSentAt = performance.now();
if (!this._pingListenerAttached) {
this._pingListenerAttached = true;
this.addEventListener('message', () => {
if (this._lastSentAt > 0) {
const elapsed = performance.now() - this._lastSentAt;
if (elapsed < 2000) ping = Math.round(elapsed);
this._lastSentAt = 0;
}
});
}
return _origWSSend.apply(this, args);
};
setInterval(() => {
const select = document.getElementById("server-select");
if (select?.options.length > 0) serverName = select.options[select.selectedIndex].text;
}, 1000);
let clickTimestamps = [];
document.addEventListener("mousedown", () => {
const now = Date.now();
clickTimestamps.push(now);
clickTimestamps = clickTimestamps.filter(t => now - t < 1000);
});
window.addEventListener("resize", () => {
overlayCanvas.width = window.innerWidth;
overlayCanvas.height = window.innerHeight;
});
setTimeout(() => {
['#grid-toggle', '#native-friendly-indicator'].forEach(id => {
const el = document.querySelector(id);
if (el) el.click();
});
}, 2000);
// =========================================================================
// PART 4: INTEGRATED KEY VIEWER HUD LOGIC
// =========================================================================
{
const kvStyle = document.createElement('style');
kvStyle.innerHTML = `
#kv-overlay-container {
position: fixed; bottom: 180px; left: 20px;
border: 1px solid transparent; padding: 10px;
border-radius: 14px; z-index: 999999;
display: ${config.keyViewer ? 'flex' : 'none'};
flex-direction: column; gap: 8px;
font-family: 'Baloo Paaji', cursive, sans-serif;
font-weight: 900; user-select: none; pointer-events: none;
}
#kv-drag-handle {
height: 18px; border-radius: 6px; cursor: move; pointer-events: auto;
display: flex; align-items: center; justify-content: center;
font-size: 9px; letter-spacing: 3px;
}
#kv-drag-handle:hover {
background: rgba(150, 150, 150, 0.25)!important;
color: currentColor!important;
}
.kv-row { display: flex; gap: 8px; justify-content: center; }
.kv-cell {
width: 46px; height: 46px; border-radius: 8px;
display: flex; align-items: center; justify-content: center;
font-weight: 900; font-size: 15px; font-family: 'Baloo Paaji', cursive, sans-serif;
}
.kv-cell.mouse-btn { width: 100px; }
.kv-cell.space-btn { width: 208px; font-size: 13px; letter-spacing: 1px; }
#kv-overlay-container:not(.light-active) .kv-cell.active {
background: #ffffff !important; color: #050505 !important;
border-color: #ffffff !important; box-shadow: 0 0 18px rgba(255, 255, 255, 0.7);
transform: scale(0.92);
}
#kv-overlay-container.light-active .kv-cell.active {
background: #111111 !important; color: #ffffff !important;
border-color: #111111 !important; box-shadow: 0 0 15px rgba(0, 0, 0, 0.3);
transform: scale(0.92);
}
`;
document.head.appendChild(kvStyle);
const kvContainer = document.createElement('div');
kvContainer.id = 'kv-overlay-container';
kvContainer.innerHTML = `
<div id="kv-drag-handle">••••</div>
<div class="kv-row">
<div class="kv-cell mouse-btn" id="kv-lmb">LMB</div>
<div class="kv-cell mouse-btn" id="kv-rmb">RMB</div>
</div>
<div class="kv-row">
<div class="kv-cell" id="kv-q">Q</div>
<div class="kv-cell" id="kv-w">W</div>
<div class="kv-cell" id="kv-e">E</div>
<div class="kv-cell" id="kv-r">R</div>
</div>
<div class="kv-row">
<div class="kv-cell" id="kv-a">A</div>
<div class="kv-cell" id="kv-s">S</div>
<div class="kv-cell" id="kv-d">D</div>
<div class="kv-cell" id="kv-f">F</div>
</div>
<div class="kv-row">
<div class="kv-cell space-btn" id="kv-space">SPACE</div>
</div>
`;
document.body.appendChild(kvContainer);
const savedX = localStorage.getItem('kv-pos-x');
const savedY = localStorage.getItem('kv-pos-y');
if (savedX && savedY) {
kvContainer.style.left = savedX;
kvContainer.style.top = savedY;
kvContainer.style.bottom = 'auto';
}
document.getElementById('kv-drag-handle').style.display = config.kvLocked ? 'none' : 'flex';
(() => {
const kvc = document.getElementById('kv-overlay-container');
if (!kvc) return;
const hex = config.kvBgColor || '#0a0a0a';
const r = parseInt(hex.slice(1,3),16), g = parseInt(hex.slice(3,5),16), b = parseInt(hex.slice(5,7),16);
kvc.style.background = `rgba(${r},${g},${b},${config.kvBgOpacity})`;
const base = config.kvCellSize;
const cellPx = base + 'px';
const mousePx = (base * 2 + 8) + 'px';
const spacePx = (base * 4 + 24) + 'px';
const fontSize = Math.round(base * 0.32) + 'px';
kvc.querySelectorAll('.kv-cell').forEach(cell => {
cell.style.color = config.kvTextColor;
cell.style.height = cellPx;
cell.style.fontSize = fontSize;
if (cell.classList.contains('mouse-btn')) {
cell.style.width = mousePx;
} else if (cell.classList.contains('space-btn')) {
cell.style.width = spacePx;
} else {
cell.style.width = cellPx;
}
});
})();
const handle = document.getElementById('kv-drag-handle');
let isDragging = false;
let offsetX = 0, offsetY = 0;
handle.addEventListener('mousedown', (e) => {
if(config.kvLocked) return;
isDragging = true;
const rect = kvContainer.getBoundingClientRect();
offsetX = e.clientX - rect.left;
offsetY = e.clientY - rect.top;
e.preventDefault();
});
window.addEventListener('mousemove', (e) => {
if (isDragging) {
let x = e.clientX - offsetX;
let y = e.clientY - offsetY;
x = Math.max(0, Math.min(x, window.innerWidth - kvContainer.offsetWidth));
y = Math.max(0, Math.min(y, window.innerHeight - kvContainer.offsetHeight));
kvContainer.style.left = x + 'px';
kvContainer.style.top = y + 'px';
kvContainer.style.bottom = 'auto';
}
if (isStatsDragging) {
let x = e.clientX - statsOffsetX;
let y = e.clientY - statsOffsetY;
x = Math.max(0, Math.min(x, window.innerWidth - statsContainer.offsetWidth));
y = Math.max(0, Math.min(y, window.innerHeight - statsContainer.offsetHeight));
statsContainer.style.left = x + 'px';
statsContainer.style.top = y + 'px';
}
});
window.addEventListener('mouseup', () => {
if (isDragging) {
isDragging = false;
localStorage.setItem('kv-pos-x', kvContainer.style.left);
localStorage.setItem('kv-pos-y', kvContainer.style.top);
}
if (isStatsDragging) {
isStatsDragging = false;
localStorage.setItem('stats-pos-x', statsContainer.style.left);
localStorage.setItem('stats-pos-y', statsContainer.style.top);
}
});
const keyElements = {
'KeyQ': document.getElementById('kv-q'),
'KeyW': document.getElementById('kv-w'),
'KeyE': document.getElementById('kv-e'),
'KeyR': document.getElementById('kv-r'),
'KeyA': document.getElementById('kv-a'),
'KeyS': document.getElementById('kv-s'),
'KeyD': document.getElementById('kv-d'),
'KeyF': document.getElementById('kv-f'),
'Space': document.getElementById('kv-space')
};
const mouseElements = {
0: document.getElementById('kv-lmb'),
2: document.getElementById('kv-rmb')
};
window.addEventListener('keydown', (e) => {
if (!e.isTrusted) return;
const code = e.code;
if (keyElements[code]) keyElements[code].classList.add('active');
}, true);
window.addEventListener('keyup', (e) => {
if (!e.isTrusted) return;
const code = e.code;
if (keyElements[code]) keyElements[code].classList.remove('active');
}, true);
window.addEventListener('mousedown', (e) => {
if (!e.isTrusted) return;
if (mouseElements[e.button]) mouseElements[e.button].classList.add('active');
}, true);
window.addEventListener('mouseup', (e) => {
if (!e.isTrusted) return;
if (mouseElements[e.button]) mouseElements[e.button].classList.remove('active');
}, true);
window.addEventListener('blur', () => {
Object.values(keyElements).forEach(el => el.classList.remove('active'));
Object.values(mouseElements).forEach(el => el.classList.remove('active'));
});
}
applyGlobalTheme();
shiftCompartment(0);
function loop() {
requestAnimationFrame(loop);
const now = performance.now();
frameCount++;
if (now - fpsStartTime >= 1000) {
fps = frameCount;
frameCount = 0;
fpsStartTime = now;
}
const cps = clickTimestamps.filter(t => Date.now() - t < 1000).length;
octx.clearRect(0, 0, overlayCanvas.width, overlayCanvas.height);
if (config.hitbox && circlesToDraw.length > 0) {
const nowHb = Date.now();
if (window._frameHpBars) {
window._frameHpBars = window._frameHpBars.filter(b => nowHb - b.time < 100);
}
const hpBarsHb = window._frameHpBars || [];
octx.lineWidth = config.hitboxWidth;
for (const c of circlesToDraw) {
octx.save();
octx.setTransform(c.transform);
if (c.isPlayer) {
const lx = c.x + c.width / 2, ly = c.y + c.height / 2;
const m = c.transform;
const sx = m.a * lx + m.c * ly + m.e;
const sy = m.b * lx + m.d * ly + m.f;
let isAlly = false;
let foundBar = false;
let minBD = Infinity;
for (const bar of hpBarsHb) {
if (bar.isMob) continue;
const bd = Math.hypot(bar.x - sx, bar.y - sy);
if (bd < minBD && bd < 100) { minBD = bd; isAlly = bar.isAlly; foundBar = true; }
}
octx.strokeStyle = (foundBar && isAlly) ? config.hitboxColorAlly : config.hitboxColorEnemy;
octx.beginPath();
octx.arc(c.x + c.width / 2, c.y + c.height / 2, 35, 0, Math.PI * 2);
octx.stroke();
} else if (c.isMob) {
octx.strokeStyle = config.hitboxColorMob;
octx.beginPath();
octx.arc(c.x + c.width / 2, c.y + c.height / 2, c.radius || 35, 0, Math.PI * 2);
octx.stroke();
}
octx.restore();
}
}
if (config.tracers && circlesToDraw.length > 0) {
octx.save();
octx.lineWidth = config.tracerWidth;
const canvasCenterX = overlayCanvas.width / 2;
const canvasCenterY = overlayCanvas.height / 2;
const targets = [];
let myPlayer = null;
let minDist = Infinity;
for (const c of circlesToDraw) {
const localX = c.x + c.width / 2;
const localY = c.y + c.height / 2;
const matrix = c.transform;
const screenX = matrix.a * localX + matrix.c * localY + matrix.e;
const screenY = matrix.b * localX + matrix.d * localY + matrix.f;
const entity = { screenX, screenY, isPlayer: c.isPlayer, fileName: c.fileName };
targets.push(entity);
if (c.isPlayer) {
const dist = Math.hypot(screenX - canvasCenterX, screenY - canvasCenterY);
if (dist < minDist) {
minDist = dist;
myPlayer = entity;
}
}
}
const startX = (myPlayer && minDist < 60) ? myPlayer.screenX : canvasCenterX;
const startY = (myPlayer && minDist < 60) ? myPlayer.screenY : canvasCenterY;
const hexToRgba = (hex, alpha) => {
let r = parseInt(hex.slice(1, 3), 16),
g = parseInt(hex.slice(3, 5), 16),
b = parseInt(hex.slice(5, 7), 16);
return `rgba(${r}, ${g}, ${b}, ${alpha})`;
};
const nowTime = Date.now();
if (window._frameHpBars) {
window._frameHpBars = window._frameHpBars.filter(b => nowTime - b.time < 100);
}
const hpBars = window._frameHpBars || [];
for (const target of targets) {
const dist = Math.hypot(target.screenX - startX, target.screenY - startY);
if (dist > 20) {
let shouldDraw = false;
let hexColor = config.tracerColorMob;
if (target.isPlayer) {
let isAlly = false;
let foundTracerBar = false;
let minBarDist = Infinity;
for (const bar of hpBars) {
if (bar.isMob) continue;
const bDist = Math.hypot(bar.x - target.screenX, bar.y - target.screenY);
if (bDist < minBarDist && bDist < 100) {
minBarDist = bDist;
isAlly = bar.isAlly;
foundTracerBar = true;
}
}
hexColor = (foundTracerBar && isAlly) ? config.tracerColorAlly : config.tracerColorEnemy;
shouldDraw = (foundTracerBar && isAlly) ? config.tracerAlly : config.tracerPlayer;
} else {
switch(target.fileName) {
case "cow.png": shouldDraw = config.tracerCow; break;
case "duck.png": shouldDraw = config.tracerDuck; break;
case "wolf.png": shouldDraw = config.tracerWolf; break;
case "shark.png": shouldDraw = config.tracerShark; break;
case "crocodile.png": shouldDraw = config.tracerCrocodile; break;
case "gcow.png": shouldDraw = config.tracerGcow; break;
case "mammoth_body.png": shouldDraw = config.tracerMammoth; break;
case "dragon_2_body.png": shouldDraw = config.tracerDragon; break;
}
}
if (shouldDraw) {
octx.beginPath();
octx.strokeStyle = hexToRgba(hexColor, config.tracerOpacity);
octx.moveTo(startX, startY);
octx.lineTo(target.screenX, target.screenY);
octx.stroke();
}
}
}
octx.restore();
}
circlesToDraw.length = 0;
const kvContainer = document.getElementById('kv-overlay-container');
if (kvContainer) {
if (config.lightMode) kvContainer.classList.add('light-active');
else kvContainer.classList.remove('light-active');
}
if (config.showOverlay) {
const sEl = document.getElementById('stat-server');
const fEl = document.getElementById('stat-fps');
const cEl = document.getElementById('stat-cps');
const pEl = document.getElementById('stat-ping');
if(sEl) sEl.innerText = `SERVER: ${serverName}`;
if(fEl) fEl.innerText = `FPS: ${fps}`;
if(cEl) cEl.innerText = `CPS: ${cps}`;
if(pEl) pEl.innerText = `PING: ${ping}ms`;
}
}
loop();
});
})();