ENHANCED: Schedule, Collaborate, Timelapse, Configs & Safety Calculator
// ==UserScript==
// @name Oxm Bot BETA
// @namespace https://github.com/oxmbot
// @version 3.1.0-ENHANCED
// @description ENHANCED: Schedule, Collaborate, Timelapse, Configs & Safety Calculator
// @author Oxm Team
// @match https://pixelplace.io/*
// @exclude https://pixelplace.io/forums*
// @exclude https://pixelplace.io/blog*
// @exclude https://pixelplace.io/api*
// @exclude https://pixelplace.io/gold-chart.php
// @exclude https://pixelplace.io/*ypp=true
// @license MIT
// @icon https://i.postimg.cc/7hyLF9qs/4a292d1b-0dae-4d53-8510-14207825.jpg
// @run-at document-start
// @grant unsafeWindow
// @grant GM.info
// @require https://code.jquery.com/jquery-3.6.0.min.js
// @require https://cdnjs.cloudflare.com/ajax/libs/toastr.js/2.1.4/toastr.min.js
// @require https://update.greasyfork.org/scripts/461063/1708713/Library%20For%20Mxobot.js
// @require https://update.greasyfork.org/scripts/461221/1159560/Hack%20Timerjs%20By%20Turuslan.js
// @require https://update.greasyfork.org/scripts/445697/1244619/Greasy%20Fork%20API.js
// ==/UserScript==
/* global NevinCore, NevinWaitForElm, NevinProtect, NevinLogger, NevinLoggerFactory, toastr*/
/*jshint esversion: 11 */
let currentLang = localStorage.getItem('oxm_lang') || 'en';
const translations = {
en: {
language: 'Language',
links: 'Links',
bottingrules: 'Botting rules',
greasyforkpage: 'Greasyfork page',
discordsrv: 'Discord server',
imageresizer: 'Image resizer',
imageconverter: 'Image converter',
setting: 'Settings',
image: 'Image',
loaded: 'Loaded',
imagenotloaded: 'Image not loaded',
notloaded: 'Not loaded',
nset: 'Not Set',
coordinatesnotset: 'Coordinates not set',
on: 'On',
off: 'Off',
protect: 'Protect',
coordinate: 'Coordinate',
strategy: 'Shape',
speed: 'Speed (ms)',
turbospeed: 'Turbo Speed (ms)',
menusize: 'Menu Size',
welcome: 'Welcome to Oxm Bot ENHANCED! Now with Scheduling & Timelapse!',
warning: 'Use responsibly.',
protectionwarning: 'This may result in account ban, use carefully',
botwarning: 'Bots only allowed in certain locations',
// New CS2 style translations
main: 'Main',
automation: 'Automation',
configs: 'Configs',
visuals: 'Visuals',
misc: 'Misc',
botcontrol: 'Bot Control',
performance: 'Performance',
visualization: 'Visualization',
statistics: 'Statistics',
scheduling: 'Scheduling',
collaboration: 'Team Work',
timelapse: 'Timelapse',
safety: 'Safety Calculator',
configmgmt: 'Config Manager'
},
ru: {
language: 'Язык',
links: 'Ссылки',
bottingrules: 'Правила',
greasyforkpage: 'Greasyfork',
discordsrv: 'Discord',
imageresizer: 'Размер',
imageconverter: 'Конвертер',
setting: 'Настройки',
image: 'Изображение',
loaded: 'Загружено',
imagenotloaded: 'Не загружено',
notloaded: 'Не загружено',
nset: 'Не установлено',
coordinatesnotset: 'Координаты не установлены',
on: 'Вкл',
off: 'Выкл',
protect: 'Защита',
coordinate: 'Координата',
strategy: 'Форма',
speed: 'Скорость (мс)',
turbospeed: 'Турбо (мс)',
menusize: 'Размер меню',
welcome: 'Добро пожаловать в Oxm Bot ENHANCED!',
warning: 'Используйте ответственно.',
protectionwarning: 'Может привести к бану',
botwarning: 'Боты разрешены в определенных местах',
main: 'Основное',
automation: 'Автоматизация',
configs: 'Конфиги',
visuals: 'Визуалы',
misc: 'Разное',
botcontrol: 'Управление ботом',
performance: 'Производительность',
visualization: 'Визуализация',
statistics: 'Статистика',
scheduling: 'Расписание',
collaboration: 'Командная работа',
timelapse: 'Таймлапс',
safety: 'Калькулятор безопасности',
configmgmt: 'Управление конфигами'
}
};
function t(key) {
return translations[currentLang][key] || translations.en[key] || key;
}
function setLanguage(lang) {
currentLang = lang;
localStorage.setItem('oxm_lang', lang);
location.reload();
}
const OXMBOT_EXPERIMENTAL_USE_MULTI_ACC = false;
const OXMBOT_ANIMATE_BOT_CANVAS = true;
const BOT_DO_NOT_DITHER = false;
let OXMBOT_TIMEOUT = localStorage.getItem('oxm_speed') ?
parseInt(localStorage.getItem('oxm_speed')) : 10;
let MENU_SCALE = localStorage.getItem('oxm_menu_scale') ?
parseFloat(localStorage.getItem('oxm_menu_scale')) : 1.0;
const OXMBOT_IMG_NOT_LOADED = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=='
const OXMBOT_DRAWING_STYLES = [
['Quadratic', function (a, b) {
const origx = coordinates[0] + ~~(nimage.image.width >> 1)
const origy = coordinates[1] + ~~(nimage.image.height >> 1)
return (a[0] - origx) ** 8 + (a[1] - origy) ** 8 - (b[0] - origx) ** 8 - (b[1] - origy) ** 8
}],
['Circular', function (a, b) {
const origx = coordinates[0] + ~~(nimage.image.width >> 1);
const origy = coordinates[1] + ~~(nimage.image.height >> 1);
return (a[0] - origx) ** 2 + (a[1] - origy) ** 2 - (b[0] - origx) ** 2 - (b[1] - origy) ** 2;
}],
['Horizontal', (a, b) => a[0] + a[1] * 0xfffff - b[0] - b[1] * 0xfffff],
['Vertical', (a, b) => a[0] * 0xfffff + a[1] - b[0] * 0xfffff - b[1]],
['Chess', (a, b) => ((a[0] + a[1]) % 2) - ((b[0] + b[1]) % 2)],
['Random', () => 1 - Math.random() * 2],
['Diagonal', (pixel1, pixel2) => pixel1[0] - pixel2[0] + (pixel1[1] - pixel2[1])],
['Zigzag', (pixel1, pixel2) => (pixel1[0] + pixel1[1]) % 2 === (pixel2[0] + pixel2[1]) % 2 ? pixel1[0] - pixel2[0] : -(pixel1[0] - pixel2[0])]
];
let core = new NevinCore({
timeout: OXMBOT_TIMEOUT,
multibot: OXMBOT_EXPERIMENTAL_USE_MULTI_ACC,
});
// Session Statistics
let sessionStats = {
pixelsPlaced: 0,
sessionStart: Date.now(),
totalUptime: 0,
lastSaveTime: Date.now()
};
// Load saved stats
const savedStats = localStorage.getItem('oxm_session_stats');
if (savedStats) {
try {
const parsed = JSON.parse(savedStats);
sessionStats.pixelsPlaced = parsed.pixelsPlaced || 0;
sessionStats.totalUptime = parsed.totalUptime || 0;
} catch (e) {}
}
let showPixelCounter = localStorage.getItem('oxm_show_counter') === 'true';
// Menu Customization
let menuCustomization = {
primaryColor: localStorage.getItem('oxm_primary_color') || '#00d9ff',
secondaryColor: localStorage.getItem('oxm_secondary_color') || '#0066ff',
bgColor: localStorage.getItem('oxm_bg_color') || '#0a0a0f',
textColor: localStorage.getItem('oxm_text_color') || '#ffffff',
menuOpacity: parseFloat(localStorage.getItem('oxm_menu_opacity') || '0.98')
};
let isTurboActive = false;
let originalSpeed = OXMBOT_TIMEOUT;
// === NEW FEATURES ===
// Scheduling System (Feature #9)
let scheduleConfig = {
enabled: false,
startTime: '',
stopTime: '',
pixelQuota: 0,
autoPauseOnHighLoad: false,
scheduleInterval: null
};
// Collaboration System (Feature #10)
let collaborationConfig = {
enabled: false,
teamId: '',
workSplit: 100, // 0-100%
syncInterval: 5000,
syncTimer: null
};
// Timelapse System
let timelapseConfig = {
recording: false,
frames: [],
captureInterval: 5000,
captureArea: null, // {x, y, width, height}
lastCapture: 0,
recordingTimer: null
};
// Config Management
let savedConfigs = JSON.parse(localStorage.getItem('oxm_saved_configs') || '{}');
function showCustomToast(message, type = 'warning') {
const toast = document.createElement('div');
const borderColor = type === 'warning' ? '#ff4655' : type === 'success' ? '#00ff88' : '#00d9ff';
const icon = type === 'warning' ? '⚠️' : type === 'success' ? '✓' : 'ℹ️';
toast.style.cssText = `
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: linear-gradient(135deg, #0a0a0f 0%, #141420 100%);
color: white;
padding: 20px 30px;
border-radius: 4px;
border-left: 3px solid ${borderColor};
z-index: 999999;
font-family: 'Segoe UI', sans-serif;
font-size: 14px;
text-align: center;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.8);
animation: toastFadeSlide 3s forwards;
`;
toast.textContent = `${icon} ${message}`;
if (!document.querySelector('#toast-animation')) {
const style = document.createElement('style');
style.id = 'toast-animation';
style.textContent = `
@keyframes toastFadeSlide {
0% { opacity: 0; transform: translate(-50%, -40%); }
20% { opacity: 1; transform: translate(-50%, -50%); }
80% { opacity: 1; transform: translate(-50%, -50%); }
100% { opacity: 0; transform: translate(-50%, -60%); }
}
`;
document.head.appendChild(style);
}
document.querySelectorAll('[style*="position: fixed"][style*="top: 50%"]').forEach(t => t.remove());
document.body.appendChild(toast);
setTimeout(() => toast.remove(), 3000);
}
function draggable(element, handle) {
let x, y;
const mouseDownHandler = (e) => {
x = e.clientX;
y = e.clientY;
document.addEventListener("mousemove", mouseMoveHandler);
document.addEventListener("mouseup", mouseUpHandler);
};
const mouseMoveHandler = (e) => {
const dx = e.clientX - x;
const dy = e.clientY - y;
element.style.top = `${element.offsetTop + dy}px`;
element.style.left = `${element.offsetLeft + dx}px`;
x = e.clientX;
y = e.clientY;
};
const mouseUpHandler = () => {
document.removeEventListener("mousemove", mouseMoveHandler);
document.removeEventListener("mouseup", mouseUpHandler);
};
handle.addEventListener("mousedown", mouseDownHandler);
}
// ============= NEW FEATURE FUNCTIONS =============
// Config Code Generation (64 chars)
function generateConfigCode(config) {
const jsonStr = JSON.stringify(config);
const base64 = btoa(unescape(encodeURIComponent(jsonStr)));
const hash = hashString(base64 + Date.now());
return hash.substring(0, 64).toUpperCase();
}
function hashString(str) {
let hash = 0;
const chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
let result = '';
for (let i = 0; i < str.length; i++) {
const char = str.charCodeAt(i);
hash = ((hash << 5) - hash) + char;
hash = hash & hash;
}
for (let i = 0; i < 64; i++) {
const index = Math.abs(hash + i * 7919) % chars.length;
result += chars[index];
}
return result;
}
// Safety Calculator (Feature #15)
function calculateEstimate() {
if (!nimage || !core.engine.tasks) return null;
const remainingPixels = core.engine.tasks.length;
const currentSpeed = OXMBOT_TIMEOUT;
const pixelsPerSecond = 1000 / currentSpeed;
const secondsRemaining = remainingPixels / pixelsPerSecond;
const hours = Math.floor(secondsRemaining / 3600);
const minutes = Math.floor((secondsRemaining % 3600) / 60);
const seconds = Math.floor(secondsRemaining % 60);
return {
remaining: remainingPixels,
timeSeconds: secondsRemaining,
formatted: `${hours}h ${minutes}m ${seconds}s`,
banRisk: calculateBanRisk(currentSpeed, remainingPixels)
};
}
function calculateBanRisk(speed, pixels) {
let risk = 0;
if (speed < 50) risk += 40;
else if (speed < 100) risk += 25;
else if (speed < 200) risk += 10;
if (pixels > 10000) risk += 30;
else if (pixels > 5000) risk += 20;
else if (pixels > 1000) risk += 10;
if (speed < 20) risk += 20;
return Math.min(risk, 100);
}
function updateSafetyCalculator() {
const estimate = calculateEstimate();
if (!estimate) return;
document.getElementById('est-time').textContent = estimate.formatted;
document.getElementById('est-remaining').textContent = estimate.remaining.toLocaleString();
document.getElementById('risk-bar').style.width = estimate.banRisk + '%';
document.getElementById('risk-text').textContent = estimate.banRisk + '%';
const riskBar = document.getElementById('risk-bar');
if (estimate.banRisk < 30) {
riskBar.style.background = 'linear-gradient(90deg, #00ff88, #00d9ff)';
} else if (estimate.banRisk < 60) {
riskBar.style.background = 'linear-gradient(90deg, #ffaa00, #ff8800)';
} else {
riskBar.style.background = 'linear-gradient(90deg, #ff4655, #ff0000)';
}
const recommendations = document.getElementById('safety-recommendations');
if (estimate.banRisk > 60) {
recommendations.innerHTML = '<small>⚠️ HIGH RISK! Server may rate limit</small>';
} else if (estimate.banRisk > 30) {
recommendations.innerHTML = '<small>⚡ Moderate risk of rate limiting</small>';
} else {
recommendations.innerHTML = '<small>✓ Low rate limit risk</small>';
}
}
// Scheduling (Feature #9)
function checkSchedule() {
if (!scheduleConfig.enabled) return;
const now = new Date();
const currentTime = now.getHours() * 60 + now.getMinutes();
if (scheduleConfig.startTime && scheduleConfig.stopTime) {
const [startH, startM] = scheduleConfig.startTime.split(':').map(Number);
const [stopH, stopM] = scheduleConfig.stopTime.split(':').map(Number);
const startMinutes = startH * 60 + startM;
const stopMinutes = stopH * 60 + stopM;
const shouldRun = currentTime >= startMinutes && currentTime < stopMinutes;
const botToggle = document.getElementById('bot-toggle');
if (shouldRun && !botToggle.checked) {
botToggle.checked = true;
botToggle.dispatchEvent(new Event('change'));
showCustomToast('🕐 Scheduled start!', 'success');
} else if (!shouldRun && botToggle.checked) {
botToggle.checked = false;
botToggle.dispatchEvent(new Event('change'));
showCustomToast('🕐 Scheduled stop', 'info');
}
}
if (scheduleConfig.pixelQuota > 0 && sessionStats.pixelsPlaced >= scheduleConfig.pixelQuota) {
const botToggle = document.getElementById('bot-toggle');
if (botToggle.checked) {
botToggle.checked = false;
botToggle.dispatchEvent(new Event('change'));
showCustomToast('🎯 Quota reached!', 'success');
}
}
}
// Collaboration (Feature #10)
function syncCollaboration() {
if (!collaborationConfig.enabled || !nimage || !core.engine.tasks) return;
const totalPixels = core.engine.tasks.length;
const myShare = Math.floor(totalPixels * (collaborationConfig.workSplit / 100));
core.engine.tasks = core.engine.tasks.slice(0, myShare);
console.log(`[Collab] ${collaborationConfig.workSplit}% = ${myShare} pixels`);
}
// Timelapse Functions
function captureTimelapseFrame() {
if (!timelapseConfig.recording) return;
const now = Date.now();
if (now - timelapseConfig.lastCapture < timelapseConfig.captureInterval) return;
try {
const captureCanvas = document.createElement('canvas');
const ctx = captureCanvas.getContext('2d');
if (timelapseConfig.captureArea) {
const area = timelapseConfig.captureArea;
captureCanvas.width = area.width;
captureCanvas.height = area.height;
ctx.drawImage(canvas, area.x, area.y, area.width, area.height, 0, 0, area.width, area.height);
} else {
captureCanvas.width = canvas.width;
captureCanvas.height = canvas.height;
ctx.drawImage(canvas, 0, 0);
}
const frameData = captureCanvas.toDataURL('image/png');
timelapseConfig.frames.push({
timestamp: now,
data: frameData
});
timelapseConfig.lastCapture = now;
document.getElementById('timelapse-frame-count').textContent = timelapseConfig.frames.length;
if (timelapseConfig.frames.length > 500) {
timelapseConfig.frames.shift();
}
} catch (e) {
console.error('Timelapse error:', e);
}
}
function exportTimelapse() {
if (timelapseConfig.frames.length === 0) {
showCustomToast('No frames captured!', 'warning');
return;
}
showCustomToast(`Exporting ${timelapseConfig.frames.length} frames...`, 'info');
const timelapseData = {
frames: timelapseConfig.frames,
metadata: {
totalFrames: timelapseConfig.frames.length,
captureInterval: timelapseConfig.captureInterval,
captureArea: timelapseConfig.captureArea,
exportDate: new Date().toISOString()
}
};
const dataStr = JSON.stringify(timelapseData);
const dataBlob = new Blob([dataStr], {type: 'application/json'});
const url = URL.createObjectURL(dataBlob);
const link = document.createElement('a');
link.href = url;
link.download = `oxm-timelapse-${Date.now()}.json`;
link.click();
URL.revokeObjectURL(url);
showCustomToast('✓ Timelapse exported!', 'success');
}
function clearTimelapse() {
timelapseConfig.frames = [];
timelapseConfig.lastCapture = 0;
document.getElementById('timelapse-frame-count').textContent = '0';
showCustomToast('Timelapse cleared', 'info');
}
const logoUrl = 'https://i.postimg.cc/7hyLF9qs/4a292d1b-0dae-4d53-8510-14207825.jpg';
const html = `
<div>
<div class="cs2-cheat-menu" id="menu-div" style="transform: scale(${MENU_SCALE}); transform-origin: top left;">
<!-- Header -->
<div class="cs2-header" id="menu-title">
<div class="cs2-header-content">
<img src="${logoUrl}" class="cs2-logo logo-glow" alt="Oxm Bot">
<div class="cs2-title">
<span class="cs2-name">OXM.ENHANCED</span>
<span class="cs2-version">v3.1.0</span>
</div>
</div>
<div class="cs2-header-status">
<div class="status-dot" id="status-indicator"></div>
<span class="status-text" id="status-text">IDLE</span>
</div>
</div>
<!-- BETA WARNING BANNER -->
<div class="beta-warning-banner">
<div class="beta-warning-icon">⚠️</div>
<div class="beta-warning-content">
<strong>BETA VERSION - EXPERIMENTAL FEATURES BUGS EXPECTED</strong>
<p>This version contains new experimental features. Some functionality may be broken or unstable. Use at your own risk!</p>
</div>
</div>
<!-- Tab Navigation -->
<div class="cs2-tabs">
<div class="cs2-tab active" data-tab="main">
<svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor">
<path d="M8 3L2 7h2v6h3V9h2v4h3V7h2L8 3z"/>
</svg>
<span>${t('main')}</span>
</div>
<div class="cs2-tab" data-tab="automation">
<svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor">
<circle cx="8" cy="8" r="3"/>
<path d="M12 8a4 4 0 11-8 0 4 4 0 018 0z"/>
</svg>
<span>${t('automation')}</span>
</div>
<div class="cs2-tab" data-tab="configs">
<svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor">
<path d="M2 3h12v2H2V3zm0 4h12v2H2V7zm0 4h12v2H2v-2z"/>
</svg>
<span>${t('configs')}</span>
</div>
<div class="cs2-tab" data-tab="visuals">
<svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor">
<circle cx="8" cy="8" r="3"/>
<path d="M8 1v2M8 13v2M1 8h2M13 8h2M3.5 3.5l1.4 1.4M11.1 11.1l1.4 1.4M3.5 12.5l1.4-1.4M11.1 4.9l1.4-1.4"/>
</svg>
<span>${t('visuals')}</span>
</div>
<div class="cs2-tab" data-tab="misc">
<svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor">
<circle cx="4" cy="8" r="1.5"/>
<circle cx="8" cy="8" r="1.5"/>
<circle cx="12" cy="8" r="1.5"/>
</svg>
<span>${t('misc')}</span>
</div>
</div>
<!-- Tab Content -->
<div class="cs2-content">
<!-- MAIN TAB -->
<div class="cs2-tab-content active" id="tab-main">
<div class="cs2-section">
<div class="cs2-section-title">${t('botcontrol')}</div>
<div class="cs2-control-group">
<div class="cs2-toggle-wrapper" id="bot_switch">
<div class="cs2-toggle-label">
<span>Enable Bot</span>
<span class="cs2-toggle-desc">Start/Stop automated pixel placement</span>
</div>
<div class="cs2-toggle">
<input type="checkbox" id="bot-toggle">
<label for="bot-toggle"></label>
</div>
</div>
<div class="cs2-toggle-wrapper" id="protect-switch">
<div class="cs2-toggle-label">
<span>${t('protect')}</span>
<span class="cs2-toggle-desc">Auto-fix griefed pixels</span>
</div>
<div class="cs2-toggle">
<input type="checkbox" id="protect-toggle">
<label for="protect-toggle"></label>
</div>
</div>
</div>
</div>
<div class="cs2-section">
<div class="cs2-section-title">${t('image')}</div>
<div class="cs2-image-preview" id="load_image">
<img src="${OXMBOT_IMG_NOT_LOADED}" id="output" class="cs2-preview-img">
<div class="cs2-preview-overlay">
<svg width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<rect x="3" y="3" width="18" height="18" rx="2"/>
<circle cx="8.5" cy="8.5" r="1.5"/>
<path d="M21 15l-5-5L5 21"/>
</svg>
<span>Click to load image</span>
</div>
</div>
<div class="cs2-input-group">
<label>${t('coordinate')}</label>
<div class="cs2-input-wrapper" id="coordinate">
<input type="text" id="coordinate-text" value="${t('nset')}" readonly>
<span class="cs2-input-hint">Click canvas to set</span>
</div>
</div>
</div>
<div class="cs2-section">
<div class="cs2-section-title">${t('performance')}</div>
<div class="cs2-slider-group">
<label>
<span>${t('speed')}</span>
<span class="cs2-slider-value" id="speed-display">${OXMBOT_TIMEOUT}ms</span>
</label>
<input type="range" class="cs2-slider" id="speed-slider" min="1" max="1000" value="${OXMBOT_TIMEOUT}">
<div class="cs2-slider-markers">
<span>Fast</span>
<span>Slow</span>
</div>
</div>
<div class="cs2-input-group">
<label>${t('strategy')}</label>
<select id="strategy" class="cs2-select">
${OXMBOT_DRAWING_STYLES.map(([name]) => `<option>${name}</option>`).join('')}
</select>
</div>
</div>
<!-- Safety Calculator (Feature #15) -->
<div class="cs2-section">
<div class="cs2-section-title">${t('safety')}</div>
<div class="safety-calculator">
<div class="safety-stats-row">
<div class="safety-stat">
<span class="safety-label">Est. Time:</span>
<span class="safety-value" id="est-time">--</span>
</div>
<div class="safety-stat">
<span class="safety-label">Remaining:</span>
<span class="safety-value" id="est-remaining">--</span>
</div>
</div>
<div class="safety-risk">
<span class="safety-label">Rate Limit Risk:</span>
<div class="risk-bar-container">
<div class="risk-bar" id="risk-bar" style="width: 0%">
<span class="risk-text" id="risk-text">0%</span>
</div>
</div>
</div>
<div class="safety-recommendations" id="safety-recommendations">
<small>💡 Load image to see estimates</small>
</div>
</div>
</div>
</div>
<!-- AUTOMATION TAB (Features #9 & #10) -->
<div class="cs2-tab-content" id="tab-automation">
<!-- Scheduling Section -->
<div class="cs2-section">
<div class="cs2-section-title">${t('scheduling')}</div>
<div class="cs2-toggle-wrapper" id="schedule-enable-toggle">
<div class="cs2-toggle-label">
<span>Enable Scheduling</span>
<span class="cs2-toggle-desc">Auto start/stop at specific times</span>
</div>
<div class="cs2-toggle">
<input type="checkbox" id="schedule-toggle">
<label for="schedule-toggle"></label>
</div>
</div>
<div class="cs2-input-group">
<label>Start Time</label>
<input type="time" id="schedule-start" class="cs2-select">
</div>
<div class="cs2-input-group">
<label>Stop Time</label>
<input type="time" id="schedule-stop" class="cs2-select">
</div>
<div class="cs2-input-group">
<label>Pixel Quota (0 = unlimited)</label>
<input type="number" id="schedule-quota" class="cs2-select" value="0" min="0" placeholder="0">
</div>
<div class="cs2-toggle-wrapper" id="schedule-pause-toggle">
<div class="cs2-toggle-label">
<span>Auto-Pause on High Load</span>
<span class="cs2-toggle-desc">Pause when server is busy</span>
</div>
<div class="cs2-toggle">
<input type="checkbox" id="schedule-pause">
<label for="schedule-pause"></label>
</div>
</div>
</div>
<!-- Collaboration Section -->
<div class="cs2-section">
<div class="cs2-section-title">${t('collaboration')}</div>
<div class="cs2-toggle-wrapper" id="collab-enable-toggle">
<div class="cs2-toggle-label">
<span>Enable Team Mode</span>
<span class="cs2-toggle-desc">Split work with teammates</span>
</div>
<div class="cs2-toggle">
<input type="checkbox" id="collab-toggle">
<label for="collab-toggle"></label>
</div>
</div>
<div class="cs2-input-group">
<label>Team ID (same for all team members)</label>
<input type="text" id="collab-team-id" class="cs2-select" placeholder="my-team-2024">
</div>
<div class="cs2-slider-group">
<label>
<span>My Work Share</span>
<span class="cs2-slider-value" id="collab-split-display">100%</span>
</label>
<input type="range" class="cs2-slider" id="collab-split-slider" min="1" max="100" value="100">
<div class="cs2-slider-markers">
<span>1%</span>
<span>100%</span>
</div>
</div>
<div class="cs2-info-box">
<small>💡 Set each bot to different % (e.g., Bot1=50%, Bot2=50%)</small>
</div>
</div>
<!-- Timelapse Section -->
<div class="cs2-section">
<div class="cs2-section-title">${t('timelapse')}</div>
<div class="cs2-toggle-wrapper" id="timelapse-toggle-wrapper">
<div class="cs2-toggle-label">
<span>Recording</span>
<span class="cs2-toggle-desc">Capture frames automatically</span>
</div>
<div class="cs2-toggle">
<input type="checkbox" id="timelapse-recording">
<label for="timelapse-recording"></label>
</div>
</div>
<div class="cs2-input-group">
<label>Capture Interval (ms)</label>
<input type="number" id="timelapse-interval" class="cs2-select" value="5000" min="1000" step="1000">
</div>
<div class="cs2-input-group">
<label>Capture Area (x, y, width, height)</label>
<input type="text" id="timelapse-area" class="cs2-select" placeholder="Leave empty for full canvas">
</div>
<div class="timelapse-stats">
<div class="timelapse-stat">
<span>Frames Captured:</span>
<strong id="timelapse-frame-count">0</strong>
</div>
</div>
<div class="cs2-button-group">
<button class="cs2-button primary" id="timelapse-export">Export</button>
<button class="cs2-button secondary" id="timelapse-clear">Clear</button>
</div>
</div>
</div>
<!-- CONFIGS TAB -->
<div class="cs2-tab-content" id="tab-configs">
<div class="cs2-section">
<div class="cs2-section-title">${t('configmgmt')}</div>
<div class="cs2-input-group">
<label>Config Name</label>
<input type="text" id="config-name" class="cs2-select" placeholder="My Config">
</div>
<div class="cs2-button-group">
<button class="cs2-button primary" id="config-save">Save Config</button>
<button class="cs2-button secondary" id="config-load">Load Config</button>
</div>
<div class="cs2-input-group">
<label>Share Code (64 chars)</label>
<input type="text" id="config-code" class="cs2-select" placeholder="Generated automatically" readonly>
</div>
<button class="cs2-button primary full-width" id="config-copy">Copy Share Code</button>
<div class="cs2-input-group" style="margin-top: 16px;">
<label>Import Config (paste code)</label>
<input type="text" id="config-import" class="cs2-select" placeholder="Paste 64-char code">
</div>
<button class="cs2-button secondary full-width" id="config-import-btn">Import Config</button>
</div>
<div class="cs2-section">
<div class="cs2-section-title">Saved Configs</div>
<div id="saved-configs-list" class="saved-configs-list">
<div class="empty-state">No saved configs yet</div>
</div>
</div>
</div>
<!-- VISUALS TAB -->
<div class="cs2-tab-content" id="tab-visuals">
<div class="cs2-section">
<div class="cs2-section-title">${t('visualization')}</div>
<div class="cs2-toggle-wrapper" id="pixel-counter-toggle">
<div class="cs2-toggle-label">
<span>Pixel Counter</span>
<span class="cs2-toggle-desc">Show session statistics overlay</span>
</div>
<div class="cs2-toggle">
<input type="checkbox" id="counter-toggle" ${showPixelCounter ? 'checked' : ''}>
<label for="counter-toggle"></label>
</div>
</div>
</div>
<div class="cs2-section">
<div class="cs2-section-title">Color Theme</div>
<div class="cs2-color-grid">
<div class="cs2-color-item">
<label>Primary</label>
<input type="color" id="primary-color-picker" value="${menuCustomization.primaryColor}">
</div>
<div class="cs2-color-item">
<label>Secondary</label>
<input type="color" id="secondary-color-picker" value="${menuCustomization.secondaryColor}">
</div>
<div class="cs2-color-item">
<label>Background</label>
<input type="color" id="bg-color-picker" value="${menuCustomization.bgColor}">
</div>
<div class="cs2-color-item">
<label>Text</label>
<input type="color" id="text-color-picker" value="${menuCustomization.textColor}">
</div>
</div>
<div class="cs2-slider-group">
<label>
<span>Menu Opacity</span>
<span class="cs2-slider-value" id="opacity-display">${Math.round(menuCustomization.menuOpacity * 100)}%</span>
</label>
<input type="range" class="cs2-slider" id="opacity-slider" min="0.3" max="1" step="0.1" value="${menuCustomization.menuOpacity}">
</div>
<div class="cs2-button-group">
<button class="cs2-button primary" id="apply-customization">Apply Theme</button>
<button class="cs2-button secondary" id="reset-customization">Reset</button>
</div>
</div>
</div>
<!-- MISC TAB -->
<div class="cs2-tab-content" id="tab-misc">
<div class="cs2-section">
<div class="cs2-section-title">${t('setting')}</div>
<div class="cs2-input-group">
<label>${t('language')}</label>
<select id="language-select" class="cs2-select">
<option value="en" ${currentLang === 'en' ? 'selected' : ''}>English</option>
<option value="ru" ${currentLang === 'ru' ? 'selected' : ''}>Русский</option>
</select>
</div>
<div class="cs2-input-group">
<label>${t('menusize')}</label>
<select id="menusize-select" class="cs2-select">
<option value="0.5" ${MENU_SCALE === 0.5 ? 'selected' : ''}>50%</option>
<option value="0.75" ${MENU_SCALE === 0.75 ? 'selected' : ''}>75%</option>
<option value="1.0" ${MENU_SCALE === 1.0 ? 'selected' : ''}>100%</option>
<option value="1.25" ${MENU_SCALE === 1.25 ? 'selected' : ''}>125%</option>
<option value="1.5" ${MENU_SCALE === 1.5 ? 'selected' : ''}>150%</option>
</select>
</div>
</div>
<div class="cs2-section">
<div class="cs2-section-title">${t('links')}</div>
<div class="cs2-links-grid">
<a id="rules" class="cs2-link-card" target="_blank">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z"/>
<path d="M14 2v6h6M16 13H8M16 17H8M10 9H8"/>
</svg>
<span>${t('bottingrules')}</span>
</a>
<a id="greasyfork" class="cs2-link-card" target="_blank">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="12" cy="12" r="10"/>
<path d="M12 6v6l4 2"/>
</svg>
<span>${t('greasyforkpage')}</span>
</a>
<a id="discord" class="cs2-link-card" target="_blank">
<svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
<path d="M20.317 4.37a19.791 19.791 0 00-4.885-1.515.074.074 0 00-.079.037c-.21.375-.444.864-.608 1.25a18.27 18.27 0 00-5.487 0 12.64 12.64 0 00-.617-1.25.077.077 0 00-.079-.037A19.736 19.736 0 003.677 4.37a.07.07 0 00-.032.027C.533 9.046-.32 13.58.099 18.057a.082.082 0 00.031.057 19.9 19.9 0 005.993 3.03.078.078 0 00.084-.028c.462-.63.874-1.295 1.226-1.994a.076.076 0 00-.041-.106 13.107 13.107 0 01-1.872-.892.077.077 0 01-.008-.128 10.2 10.2 0 00.372-.292.074.074 0 01.077-.01c3.928 1.793 8.18 1.793 12.062 0a.074.074 0 01.078.01c.12.098.246.198.373.292a.077.077 0 01-.006.127 12.299 12.299 0 01-1.873.892.077.077 0 00-.041.107c.36.698.772 1.362 1.225 1.993a.076.076 0 00.084.028 19.839 19.839 0 006.002-3.03.077.077 0 00.032-.054c.5-5.177-.838-9.674-3.549-13.66a.061.061 0 00-.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>
<span>${t('discordsrv')}</span>
</a>
<a id="image_resizer" class="cs2-link-card" target="_blank">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4M17 8l-5-5-5 5M12 3v12"/>
</svg>
<span>${t('imageresizer')}</span>
</a>
<a id="image_converter" class="cs2-link-card" target="_blank">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4M7 10l5 5 5-5M12 15V3"/>
</svg>
<span>${t('imageconverter')}</span>
</a>
</div>
</div>
<!-- Statistics Section -->
<div class="cs2-section">
<div class="cs2-section-title">${t('statistics')}</div>
<div class="cs2-stats-grid">
<div class="cs2-stat-card">
<div class="cs2-stat-icon" style="background: linear-gradient(135deg, #00d9ff 0%, #0066ff 100%);">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<rect x="3" y="3" width="7" height="7"/>
<rect x="14" y="3" width="7" height="7"/>
<rect x="14" y="14" width="7" height="7"/>
<rect x="3" y="14" width="7" height="7"/>
</svg>
</div>
<div class="cs2-stat-info">
<span class="cs2-stat-label">Pixels Placed</span>
<span class="cs2-stat-value" id="pixels-count">0</span>
</div>
</div>
<div class="cs2-stat-card">
<div class="cs2-stat-icon" style="background: linear-gradient(135deg, #ff4655 0%, #ff8800 100%);">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M12 2v20M17 5H9.5a3.5 3.5 0 000 7h5a3.5 3.5 0 010 7H6"/>
</svg>
</div>
<div class="cs2-stat-info">
<span class="cs2-stat-label">Speed</span>
<span class="cs2-stat-value" id="pixels-per-min">0 px/min</span>
</div>
</div>
<div class="cs2-stat-card">
<div class="cs2-stat-icon" style="background: linear-gradient(135deg, #00ff88 0%, #00d9ff 100%);">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="12" cy="12" r="10"/>
<path d="M12 6v6l4 2"/>
</svg>
</div>
<div class="cs2-stat-info">
<span class="cs2-stat-label">Uptime</span>
<span class="cs2-stat-value" id="session-uptime">0m</span>
</div>
</div>
<div class="cs2-stat-card">
<div class="cs2-stat-icon" style="background: linear-gradient(135deg, #8800ff 0%, #ff00ff 100%);">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M3 3h7v7H3zM14 3h7v7h-7zM14 14h7v7h-7zM3 14h7v7H3z"/>
</svg>
</div>
<div class="cs2-stat-info">
<span class="cs2-stat-label">Queue</span>
<span class="cs2-stat-value" id="queue-size">0</span>
</div>
</div>
</div>
</div>
<!-- About Section -->
<div class="cs2-section">
<div class="cs2-section-title">About</div>
<div class="cs2-about">
<p><strong>Oxm Bot ENHANCED</strong> v3.1.0</p>
<p>Advanced pixel placement with scheduling, collaboration & timelapse</p>
<p style="margin-top: 10px; color: #888; font-size: 12px;">
Press <kbd>Insert</kbd> to toggle menu<br>
New: Scheduling • Team Mode • Timelapse • Config Sharing
</p>
</div>
</div>
</div>
</div>
</div>
<style>
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap');
@keyframes fadeIn {
from { opacity: 0; transform: translateY(-10px); }
to { opacity: 1; transform: translateY(0); }
}
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.5; }
}
.oxmbot-ui-canvas {
position: absolute;
pointer-events: none;
opacity: 65%;
outline: 1px solid transparent;
image-rendering: crisp-edges;
}
/* Main Menu Container */
.cs2-cheat-menu {
position: absolute;
z-index: 10000;
top: 50px;
left: 50px;
width: 650px;
font-family: 'Inter', 'Segoe UI', sans-serif;
background: #0a0a0f;
border-radius: 0;
overflow: hidden;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.9);
border: 1px solid #1a1a25;
animation: fadeIn 0.3s ease;
user-select: none;
}
/* Header */
.cs2-header {
background: linear-gradient(135deg, #0f0f18 0%, #1a1a25 100%);
padding: 16px 20px;
display: flex;
justify-content: space-between;
align-items: center;
cursor: move;
border-bottom: 1px solid #252530;
}
.cs2-header-content {
display: flex;
align-items: center;
gap: 12px;
}
.cs2-logo {
width: 32px;
height: 32px;
border-radius: 4px;
object-fit: cover;
}
.cs2-title {
display: flex;
flex-direction: column;
gap: 2px;
}
.cs2-name {
font-size: 14px;
font-weight: 700;
color: #fff;
letter-spacing: 1px;
text-transform: uppercase;
}
.cs2-version {
font-size: 10px;
color: #666;
font-weight: 500;
}
.cs2-header-status {
display: flex;
align-items: center;
gap: 8px;
}
.status-dot {
width: 8px;
height: 8px;
border-radius: 50%;
background: #666;
animation: pulse 2s infinite;
}
.status-dot.active {
background: #00ff88;
}
.status-text {
font-size: 11px;
font-weight: 600;
color: #888;
text-transform: uppercase;
letter-spacing: 1px;
}
/* Tabs Navigation */
.cs2-tabs {
display: flex;
background: #0f0f18;
border-bottom: 1px solid #1a1a25;
}
.cs2-tab {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
padding: 14px 20px;
font-size: 12px;
font-weight: 600;
color: #666;
text-transform: uppercase;
letter-spacing: 0.5px;
cursor: pointer;
transition: all 0.2s;
border-right: 1px solid #1a1a25;
position: relative;
}
.cs2-tab:last-child {
border-right: none;
}
.cs2-tab:hover {
background: #141420;
color: #999;
}
.cs2-tab.active {
color: #00d9ff;
background: #0a0a0f;
}
.cs2-tab.active::after {
content: '';
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 2px;
background: linear-gradient(90deg, #00d9ff, #0066ff);
}
.cs2-tab svg {
width: 16px;
height: 16px;
}
/* Tab Content */
.cs2-content {
background: #0a0a0f;
max-height: 500px;
overflow-y: auto;
overflow-x: hidden;
}
.cs2-content::-webkit-scrollbar {
width: 8px;
}
.cs2-content::-webkit-scrollbar-track {
background: #0f0f18;
}
.cs2-content::-webkit-scrollbar-thumb {
background: #252530;
border-radius: 4px;
}
.cs2-content::-webkit-scrollbar-thumb:hover {
background: #353545;
}
.cs2-tab-content {
display: none;
padding: 20px;
}
.cs2-tab-content.active {
display: block;
}
/* Section */
.cs2-section {
margin-bottom: 20px;
background: #0f0f18;
border-radius: 4px;
padding: 16px;
border: 1px solid #1a1a25;
}
.cs2-section:last-child {
margin-bottom: 0;
}
.cs2-section-title {
font-size: 11px;
font-weight: 700;
color: #00d9ff;
text-transform: uppercase;
letter-spacing: 1.5px;
margin-bottom: 16px;
padding-bottom: 8px;
border-bottom: 1px solid #1a1a25;
}
/* Toggle Switch */
.cs2-control-group {
display: flex;
flex-direction: column;
gap: 12px;
}
.cs2-toggle-wrapper {
display: flex;
justify-content: space-between;
align-items: center;
padding: 12px;
background: #141420;
border-radius: 4px;
border: 1px solid #1a1a25;
cursor: pointer;
transition: all 0.2s;
}
.cs2-toggle-wrapper:hover {
background: #1a1a28;
border-color: #252530;
}
.cs2-toggle-label {
display: flex;
flex-direction: column;
gap: 4px;
}
.cs2-toggle-label > span:first-child {
font-size: 13px;
font-weight: 600;
color: #fff;
}
.cs2-toggle-desc {
font-size: 11px;
color: #666;
}
.cs2-toggle {
position: relative;
}
.cs2-toggle input {
display: none;
}
.cs2-toggle label {
display: block;
width: 42px;
height: 22px;
background: #1a1a25;
border-radius: 11px;
cursor: pointer;
transition: all 0.3s;
position: relative;
border: 1px solid #252530;
}
.cs2-toggle label::after {
content: '';
position: absolute;
top: 2px;
left: 2px;
width: 16px;
height: 16px;
background: #666;
border-radius: 50%;
transition: all 0.3s;
}
.cs2-toggle input:checked + label {
background: linear-gradient(135deg, #00d9ff, #0066ff);
border-color: #00d9ff;
}
.cs2-toggle input:checked + label::after {
left: 22px;
background: #fff;
}
/* Image Preview */
.cs2-image-preview {
position: relative;
height: 120px;
background: #141420;
border-radius: 4px;
border: 1px dashed #252530;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
transition: all 0.2s;
margin-bottom: 16px;
overflow: hidden;
}
.cs2-image-preview:hover {
border-color: #00d9ff;
background: #1a1a28;
}
.cs2-preview-img {
max-width: 90%;
max-height: 90%;
object-fit: contain;
border-radius: 4px;
}
.cs2-preview-overlay {
position: absolute;
inset: 0;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 8px;
color: #666;
font-size: 12px;
font-weight: 500;
pointer-events: none;
}
.cs2-image-preview:hover .cs2-preview-overlay {
color: #00d9ff;
}
/* Input Group */
.cs2-input-group {
margin-bottom: 12px;
}
.cs2-input-group:last-child {
margin-bottom: 0;
}
.cs2-input-group label {
display: block;
font-size: 11px;
font-weight: 600;
color: #888;
text-transform: uppercase;
letter-spacing: 0.5px;
margin-bottom: 8px;
}
.cs2-input-wrapper {
position: relative;
}
.cs2-input-wrapper input {
width: 100%;
padding: 10px 12px;
background: #141420;
border: 1px solid #1a1a25;
border-radius: 4px;
color: #fff;
font-size: 13px;
font-weight: 500;
outline: none;
transition: all 0.2s;
}
.cs2-input-wrapper input:focus {
border-color: #00d9ff;
background: #1a1a28;
}
.cs2-input-hint {
position: absolute;
right: 12px;
top: 50%;
transform: translateY(-50%);
font-size: 10px;
color: #666;
pointer-events: none;
}
/* Select */
.cs2-select {
width: 100%;
padding: 10px 12px;
background: #141420;
border: 1px solid #1a1a25;
border-radius: 4px;
color: #fff;
font-size: 13px;
font-weight: 500;
outline: none;
cursor: pointer;
transition: all 0.2s;
}
.cs2-select:hover {
border-color: #252530;
background: #1a1a28;
}
.cs2-select:focus {
border-color: #00d9ff;
}
/* Slider */
.cs2-slider-group {
margin-bottom: 16px;
}
.cs2-slider-group:last-child {
margin-bottom: 0;
}
.cs2-slider-group label {
display: flex;
justify-content: space-between;
align-items: center;
font-size: 11px;
font-weight: 600;
color: #888;
text-transform: uppercase;
letter-spacing: 0.5px;
margin-bottom: 8px;
}
.cs2-slider-value {
color: #00d9ff;
font-weight: 700;
}
.cs2-slider {
width: 100%;
height: 4px;
background: #1a1a25;
border-radius: 2px;
outline: none;
-webkit-appearance: none;
margin-bottom: 4px;
}
.cs2-slider::-webkit-slider-thumb {
-webkit-appearance: none;
width: 14px;
height: 14px;
background: linear-gradient(135deg, #00d9ff, #0066ff);
border-radius: 50%;
cursor: pointer;
transition: all 0.2s;
}
.cs2-slider::-webkit-slider-thumb:hover {
transform: scale(1.2);
box-shadow: 0 0 0 4px rgba(0, 217, 255, 0.2);
}
.cs2-slider-markers {
display: flex;
justify-content: space-between;
font-size: 10px;
color: #555;
margin-top: 4px;
}
/* Color Grid */
.cs2-color-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 12px;
margin-bottom: 16px;
}
.cs2-color-item {
display: flex;
flex-direction: column;
gap: 8px;
}
.cs2-color-item label {
font-size: 11px;
font-weight: 600;
color: #888;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.cs2-color-item input[type="color"] {
width: 100%;
height: 40px;
background: #141420;
border: 1px solid #1a1a25;
border-radius: 4px;
cursor: pointer;
transition: all 0.2s;
}
.cs2-color-item input[type="color"]:hover {
border-color: #00d9ff;
}
/* Button Group */
.cs2-button-group {
display: flex;
gap: 8px;
}
.cs2-button {
flex: 1;
padding: 10px 16px;
font-size: 12px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.5px;
border-radius: 4px;
border: none;
cursor: pointer;
transition: all 0.2s;
outline: none;
}
.cs2-button.primary {
background: linear-gradient(135deg, #00d9ff, #0066ff);
color: #fff;
}
.cs2-button.primary:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0, 217, 255, 0.4);
}
.cs2-button.secondary {
background: #1a1a25;
color: #888;
border: 1px solid #252530;
}
.cs2-button.secondary:hover {
background: #252530;
color: #aaa;
}
/* Links Grid */
.cs2-links-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 10px;
}
.cs2-link-card {
display: flex;
align-items: center;
gap: 10px;
padding: 12px;
background: #141420;
border: 1px solid #1a1a25;
border-radius: 4px;
color: #888;
text-decoration: none;
font-size: 12px;
font-weight: 500;
transition: all 0.2s;
}
.cs2-link-card:hover {
background: #1a1a28;
border-color: #00d9ff;
color: #00d9ff;
transform: translateY(-2px);
}
.cs2-link-card svg {
width: 20px;
height: 20px;
flex-shrink: 0;
}
/* Stats Grid */
.cs2-stats-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 12px;
}
.cs2-stat-card {
display: flex;
align-items: center;
gap: 12px;
padding: 14px;
background: #141420;
border: 1px solid #1a1a25;
border-radius: 4px;
}
.cs2-stat-icon {
width: 44px;
height: 44px;
border-radius: 4px;
display: flex;
align-items: center;
justify-content: center;
color: #fff;
flex-shrink: 0;
}
.cs2-stat-info {
display: flex;
flex-direction: column;
gap: 4px;
min-width: 0;
}
.cs2-stat-label {
font-size: 10px;
color: #666;
text-transform: uppercase;
letter-spacing: 0.5px;
font-weight: 600;
}
.cs2-stat-value {
font-size: 16px;
font-weight: 700;
color: #fff;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
/* About */
.cs2-about {
padding: 16px;
background: #141420;
border-radius: 4px;
border: 1px solid #1a1a25;
}
.cs2-about p {
margin: 0 0 8px 0;
color: #888;
font-size: 13px;
line-height: 1.6;
}
.cs2-about p:last-child {
margin-bottom: 0;
}
.cs2-about strong {
color: #00d9ff;
}
.cs2-about kbd {
display: inline-block;
padding: 2px 6px;
background: #1a1a25;
border: 1px solid #252530;
border-radius: 3px;
font-size: 11px;
font-weight: 600;
color: #00d9ff;
font-family: 'Courier New', monospace;
}
/* Warning Banner */
.cs2-warning-banner {
display: flex;
align-items: center;
gap: 12px;
padding: 14px 16px;
background: linear-gradient(135deg, rgba(255, 70, 85, 0.15) 0%, rgba(255, 136, 0, 0.15) 100%);
border: 1px solid rgba(255, 70, 85, 0.3);
border-left: 3px solid #ff4655;
border-radius: 4px;
margin-bottom: 20px;
}
.cs2-warning-banner svg {
color: #ff4655;
flex-shrink: 0;
}
.cs2-warning-content {
display: flex;
flex-direction: column;
gap: 4px;
}
.cs2-warning-title {
font-size: 11px;
font-weight: 700;
color: #ff4655;
text-transform: uppercase;
letter-spacing: 1px;
}
.cs2-warning-text {
font-size: 12px;
color: #ffaa88;
line-height: 1.4;
}
/* NEW: Logo Glow Animation */
@keyframes logoGlow {
0%, 100% { filter: drop-shadow(0 0 5px rgba(0, 217, 255, 0.5)); }
50% { filter: drop-shadow(0 0 15px rgba(0, 217, 255, 0.8)); }
}
.logo-glow {
animation: logoGlow 3s ease-in-out infinite;
}
/* BETA WARNING BANNER */
.beta-warning-banner {
display: flex;
align-items: center;
gap: 16px;
padding: 16px 20px;
background: linear-gradient(135deg, rgba(255, 70, 85, 0.15) 0%, rgba(255, 136, 0, 0.15) 100%);
border-bottom: 2px solid #ff4655;
border-top: 1px solid rgba(255, 70, 85, 0.3);
animation: pulseWarning 2s ease-in-out infinite;
}
@keyframes pulseWarning {
0%, 100% { background: linear-gradient(135deg, rgba(255, 70, 85, 0.15) 0%, rgba(255, 136, 0, 0.15) 100%); }
50% { background: linear-gradient(135deg, rgba(255, 70, 85, 0.25) 0%, rgba(255, 136, 0, 0.25) 100%); }
}
.beta-warning-icon {
font-size: 32px;
line-height: 1;
flex-shrink: 0;
animation: shake 3s ease-in-out infinite;
}
@keyframes shake {
0%, 100% { transform: rotate(0deg); }
10%, 30%, 50%, 70%, 90% { transform: rotate(-5deg); }
20%, 40%, 60%, 80% { transform: rotate(5deg); }
}
.beta-warning-content {
flex: 1;
color: #ffaa88;
}
.beta-warning-content strong {
display: block;
color: #ff4655;
font-size: 13px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 1px;
margin-bottom: 6px;
}
.beta-warning-content p {
font-size: 12px;
line-height: 1.4;
margin: 0;
color: #ffccbb;
}
/* NEW: Safety Calculator */
.safety-calculator {
padding: 12px;
background: #141420;
border-radius: 4px;
border: 1px solid #1a1a25;
}
.safety-stats-row {
display: flex;
gap: 12px;
margin-bottom: 16px;
}
.safety-stat {
flex: 1;
display: flex;
flex-direction: column;
gap: 4px;
}
.safety-label {
font-size: 10px;
color: #888;
text-transform: uppercase;
letter-spacing: 0.5px;
font-weight: 600;
}
.safety-value {
font-size: 16px;
font-weight: 700;
color: #00d9ff;
}
.safety-risk {
margin-bottom: 12px;
}
.risk-bar-container {
width: 100%;
height: 24px;
background: #1a1a25;
border-radius: 4px;
overflow: hidden;
margin-top: 8px;
}
.risk-bar {
height: 100%;
display: flex;
align-items: center;
justify-content: center;
transition: width 0.5s ease, background 0.5s ease;
position: relative;
}
.risk-text {
font-size: 11px;
font-weight: 700;
color: #fff;
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5);
}
.safety-recommendations {
padding: 8px;
background: #0f0f18;
border-radius: 4px;
text-align: center;
color: #00d9ff;
}
/* NEW: Info Box */
.cs2-info-box {
padding: 10px 12px;
background: rgba(0, 217, 255, 0.1);
border: 1px solid rgba(0, 217, 255, 0.2);
border-radius: 4px;
color: #00d9ff;
margin-top: 12px;
}
/* NEW: Timelapse Stats */
.timelapse-stats {
padding: 12px;
background: #141420;
border-radius: 4px;
border: 1px solid #1a1a25;
margin-bottom: 16px;
}
.timelapse-stat {
display: flex;
justify-content: space-between;
align-items: center;
font-size: 13px;
color: #888;
}
.timelapse-stat strong {
font-size: 16px;
color: #00d9ff;
font-weight: 700;
}
/* NEW: Full Width Button */
.full-width {
width: 100%;
margin-top: 12px;
}
/* NEW: Saved Configs List */
.saved-configs-list {
display: flex;
flex-direction: column;
gap: 8px;
}
.config-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 12px;
background: #141420;
border: 1px solid #1a1a25;
border-radius: 4px;
transition: all 0.2s;
}
.config-item:hover {
background: #1a1a28;
border-color: #00d9ff;
}
.config-item-name {
font-size: 13px;
font-weight: 600;
color: #fff;
}
.config-item-code {
font-size: 10px;
color: #666;
font-family: 'Courier New', monospace;
}
.config-item-actions {
display: flex;
gap: 8px;
}
.config-item-btn {
padding: 4px 8px;
font-size: 10px;
background: #1a1a25;
border: 1px solid #252530;
border-radius: 3px;
color: #888;
cursor: pointer;
transition: all 0.2s;
}
.config-item-btn:hover {
background: #252530;
color: #00d9ff;
border-color: #00d9ff;
}
.empty-state {
padding: 20px;
text-align: center;
color: #666;
font-size: 13px;
}
/* Enhanced Animations */
@keyframes slideIn {
from {
opacity: 0;
transform: translateY(-10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.cs2-section {
animation: slideIn 0.3s ease;
}
.cs2-tab:active {
transform: scale(0.95);
}
.cs2-button:active {
transform: translateY(0) scale(0.95);
}
</style>
</div>`;
var menu = new DOMParser().parseFromString(html, "text/html").body.children[0];
// Hide menu by default
menu.querySelector('#menu-div').style.display = 'none';
var oxm_coordinates;
var oxm_coordinates_text;
var oxm_menu_div;
var oxm_menu_title;
var oxm_game_canvas;
var oxm_game_context;
var oxm_protect;
var oxm_load_image;
var canvas;
var pixelplace_painting_move;
var pixelplace_coordinates;
function initVars() {
oxm_coordinates = menu.querySelector("#coordinate");
oxm_coordinates_text = menu.querySelector("#coordinate-text");
oxm_menu_div = menu.querySelector("#menu-div");
oxm_menu_title = menu.querySelector("#menu-title");
oxm_protect = menu.querySelector("#protect-switch");
oxm_load_image = menu.querySelector("#load_image");
pixelplace_coordinates = document.querySelector("#coordinates");
pixelplace_painting_move = document.querySelector("#painting-move");
canvas = document.querySelector("#canvas");
}
function createBotCanvas() {
oxm_game_canvas = document.createElement("canvas");
oxm_game_canvas.width = canvas.width;
oxm_game_canvas.height = canvas.height;
oxm_game_context = oxm_game_canvas.getContext("2d");
oxm_game_canvas.className = "oxmbot-ui-canvas";
pixelplace_painting_move.prepend(oxm_game_canvas);
document.getElementById('rules').href = "https://r.resimlink.com/OdYl_N.png";
document.getElementById('greasyfork').href = "https://greasyfork.org/en/scripts/564837-oxm-bot-beta";
document.getElementById('discord').href = "https://discord.gg/bGEk7UEGvg";
document.getElementById('image_resizer').href = "https://resizepixel.com";
document.getElementById('image_converter').href = "https://duchesskero.moe";
}
function clearOxmCanvas() {
if (oxm_game_context) {
oxm_game_context.clearRect(0, 0, oxm_game_canvas.width, oxm_game_canvas.height);
}
}
function updateStatusIndicator(active) {
const statusDot = document.getElementById('status-indicator');
const statusText = document.getElementById('status-text');
if (active) {
statusDot.classList.add('active');
statusText.textContent = 'ACTIVE';
statusText.style.color = '#00ff88';
} else {
statusDot.classList.remove('active');
statusText.textContent = 'IDLE';
statusText.style.color = '#888';
}
}
async function Oxm_UIMain() {
document.body.prepend(menu);
await NevinWaitForElm("#menu-div");
await NevinWaitForElm("#canvas");
initVars();
createBotCanvas();
draggable(oxm_menu_div, oxm_menu_title);
// Tab switching
const tabs = document.querySelectorAll('.cs2-tab');
const tabContents = document.querySelectorAll('.cs2-tab-content');
tabs.forEach(tab => {
tab.addEventListener('click', () => {
const targetTab = tab.getAttribute('data-tab');
tabs.forEach(t => t.classList.remove('active'));
tab.classList.add('active');
tabContents.forEach(content => {
content.classList.remove('active');
if (content.id === `tab-${targetTab}`) {
content.classList.add('active');
}
});
});
});
// Toggle menu with Insert key
document.addEventListener('keydown', (e) => {
if (e.code === 'Insert') {
const menuDiv = document.getElementById('menu-div');
if (menuDiv.style.display === 'none') {
menuDiv.style.display = 'block';
} else {
menuDiv.style.display = 'none';
}
}
});
// Bot toggle
const botToggle = document.getElementById('bot-toggle');
const botSwitch = document.getElementById('bot_switch');
botSwitch.addEventListener('click', () => {
botToggle.checked = !botToggle.checked;
botToggle.dispatchEvent(new Event('change'));
});
botToggle.addEventListener('change', (e) => {
handleBotToggle(e.target.checked);
});
// Protection toggle
const protectToggle = document.getElementById('protect-toggle');
const protectSwitch = document.getElementById('protect-switch');
protectSwitch.addEventListener('click', () => {
protectToggle.checked = !protectToggle.checked;
protectToggle.dispatchEvent(new Event('change'));
});
protectToggle.addEventListener('change', (e) => {
handleProtectionToggle(e.target.checked);
});
// Pixel counter toggle
const counterToggle = document.getElementById('counter-toggle');
const counterSwitch = document.getElementById('pixel-counter-toggle');
counterSwitch.addEventListener('click', () => {
counterToggle.checked = !counterToggle.checked;
counterToggle.dispatchEvent(new Event('change'));
});
counterToggle.addEventListener('change', (e) => {
showPixelCounter = e.target.checked;
localStorage.setItem('oxm_show_counter', e.target.checked);
});
// Speed slider
const speedSlider = document.getElementById('speed-slider');
const speedDisplay = document.getElementById('speed-display');
speedSlider.addEventListener('input', (e) => {
const value = parseInt(e.target.value);
speedDisplay.textContent = value + 'ms';
OXMBOT_TIMEOUT = value;
originalSpeed = value;
localStorage.setItem('oxm_speed', value);
if (core && !isTurboActive) {
core.timeout = value;
}
});
// Opacity slider
const opacitySlider = document.getElementById('opacity-slider');
const opacityDisplay = document.getElementById('opacity-display');
opacitySlider.addEventListener('input', (e) => {
const value = parseFloat(e.target.value);
opacityDisplay.textContent = Math.round(value * 100) + '%';
menuCustomization.menuOpacity = value;
});
// Language select
document.getElementById('language-select').addEventListener('change', (e) => {
setLanguage(e.target.value);
});
// Menu size select
document.getElementById('menusize-select').addEventListener('change', (e) => {
const newScale = parseFloat(e.target.value);
MENU_SCALE = newScale;
localStorage.setItem('oxm_menu_scale', newScale);
oxm_menu_div.style.transform = `scale(${newScale})`;
oxm_menu_div.style.transformOrigin = 'top left';
showCustomToast(`Menu size: ${Math.round(newScale * 100)}%`, 'info');
});
// Color pickers
document.getElementById('primary-color-picker')?.addEventListener('input', (e) => {
menuCustomization.primaryColor = e.target.value;
});
document.getElementById('secondary-color-picker')?.addEventListener('input', (e) => {
menuCustomization.secondaryColor = e.target.value;
});
document.getElementById('bg-color-picker')?.addEventListener('input', (e) => {
menuCustomization.bgColor = e.target.value;
});
document.getElementById('text-color-picker')?.addEventListener('input', (e) => {
menuCustomization.textColor = e.target.value;
});
// Apply/Reset customization
document.getElementById('apply-customization')?.addEventListener('click', applyCustomization);
document.getElementById('reset-customization')?.addEventListener('click', resetCustomization);
// === NEW FEATURE EVENT LISTENERS ===
// Scheduling
const scheduleToggle = document.getElementById('schedule-toggle');
const scheduleEnableToggle = document.getElementById('schedule-enable-toggle');
scheduleEnableToggle?.addEventListener('click', () => {
scheduleToggle.checked = !scheduleToggle.checked;
scheduleToggle.dispatchEvent(new Event('change'));
});
scheduleToggle?.addEventListener('change', (e) => {
scheduleConfig.enabled = e.target.checked;
if (scheduleConfig.enabled) {
scheduleConfig.scheduleInterval = setInterval(checkSchedule, 10000);
showCustomToast('✓ Scheduling enabled', 'success');
} else {
if (scheduleConfig.scheduleInterval) {
clearInterval(scheduleConfig.scheduleInterval);
}
showCustomToast('Scheduling disabled', 'info');
}
});
document.getElementById('schedule-start')?.addEventListener('change', (e) => {
scheduleConfig.startTime = e.target.value;
});
document.getElementById('schedule-stop')?.addEventListener('change', (e) => {
scheduleConfig.stopTime = e.target.value;
});
document.getElementById('schedule-quota')?.addEventListener('change', (e) => {
scheduleConfig.pixelQuota = parseInt(e.target.value) || 0;
});
const schedulePauseToggle = document.getElementById('schedule-pause');
const schedulePauseWrapper = document.getElementById('schedule-pause-toggle');
schedulePauseWrapper?.addEventListener('click', () => {
schedulePauseToggle.checked = !schedulePauseToggle.checked;
scheduleConfig.autoPauseOnHighLoad = schedulePauseToggle.checked;
});
// Collaboration
const collabToggle = document.getElementById('collab-toggle');
const collabEnableToggle = document.getElementById('collab-enable-toggle');
collabEnableToggle?.addEventListener('click', () => {
collabToggle.checked = !collabToggle.checked;
collabToggle.dispatchEvent(new Event('change'));
});
collabToggle?.addEventListener('change', (e) => {
collaborationConfig.enabled = e.target.checked;
if (collaborationConfig.enabled) {
collaborationConfig.syncTimer = setInterval(syncCollaboration, collaborationConfig.syncInterval);
showCustomToast('✓ Team mode enabled', 'success');
} else {
if (collaborationConfig.syncTimer) {
clearInterval(collaborationConfig.syncTimer);
}
showCustomToast('Team mode disabled', 'info');
}
});
document.getElementById('collab-team-id')?.addEventListener('change', (e) => {
collaborationConfig.teamId = e.target.value;
});
const collabSplitSlider = document.getElementById('collab-split-slider');
const collabSplitDisplay = document.getElementById('collab-split-display');
collabSplitSlider?.addEventListener('input', (e) => {
const value = parseInt(e.target.value);
collabSplitDisplay.textContent = value + '%';
collaborationConfig.workSplit = value;
});
// Timelapse
const timelapseRecording = document.getElementById('timelapse-recording');
const timelapseWrapper = document.getElementById('timelapse-toggle-wrapper');
timelapseWrapper?.addEventListener('click', () => {
timelapseRecording.checked = !timelapseRecording.checked;
timelapseRecording.dispatchEvent(new Event('change'));
});
timelapseRecording?.addEventListener('change', (e) => {
timelapseConfig.recording = e.target.checked;
if (timelapseConfig.recording) {
timelapseConfig.recordingTimer = setInterval(captureTimelapseFrame, 1000);
showCustomToast('📹 Recording started', 'success');
} else {
if (timelapseConfig.recordingTimer) {
clearInterval(timelapseConfig.recordingTimer);
}
showCustomToast('📹 Recording stopped', 'info');
}
});
document.getElementById('timelapse-interval')?.addEventListener('change', (e) => {
timelapseConfig.captureInterval = parseInt(e.target.value) || 5000;
});
document.getElementById('timelapse-area')?.addEventListener('change', (e) => {
const value = e.target.value.trim();
if (value) {
const parts = value.split(',').map(v => parseInt(v.trim()));
if (parts.length === 4 && parts.every(n => !isNaN(n))) {
timelapseConfig.captureArea = {
x: parts[0],
y: parts[1],
width: parts[2],
height: parts[3]
};
showCustomToast('✓ Capture area set', 'success');
} else {
showCustomToast('Invalid format! Use: x,y,width,height', 'warning');
}
} else {
timelapseConfig.captureArea = null;
showCustomToast('Capture area cleared (full canvas)', 'info');
}
});
document.getElementById('timelapse-export')?.addEventListener('click', exportTimelapse);
document.getElementById('timelapse-clear')?.addEventListener('click', clearTimelapse);
// Config Management
document.getElementById('config-save')?.addEventListener('click', () => {
const name = document.getElementById('config-name').value.trim();
if (!name) {
showCustomToast('Enter a config name!', 'warning');
return;
}
const config = {
name: name,
speed: OXMBOT_TIMEOUT,
strategy: document.getElementById('strategy').selectedIndex,
schedule: scheduleConfig,
collaboration: collaborationConfig,
timelapse: { interval: timelapseConfig.captureInterval, area: timelapseConfig.captureArea },
timestamp: Date.now()
};
const code = generateConfigCode(config);
savedConfigs[code] = config;
localStorage.setItem('oxm_saved_configs', JSON.stringify(savedConfigs));
document.getElementById('config-code').value = code;
showCustomToast(`✓ Config "${name}" saved!`, 'success');
updateConfigsList();
});
document.getElementById('config-copy')?.addEventListener('click', () => {
const code = document.getElementById('config-code').value;
if (!code) {
showCustomToast('No code to copy!', 'warning');
return;
}
navigator.clipboard.writeText(code).then(() => {
showCustomToast('✓ Code copied to clipboard!', 'success');
});
});
document.getElementById('config-import-btn')?.addEventListener('click', () => {
const code = document.getElementById('config-import').value.trim().toUpperCase();
if (!code || code.length !== 64) {
showCustomToast('Invalid code! Must be 64 characters', 'warning');
return;
}
const config = savedConfigs[code];
if (!config) {
showCustomToast('Config not found for this code', 'warning');
return;
}
// Apply config
if (config.speed) {
OXMBOT_TIMEOUT = config.speed;
document.getElementById('speed-slider').value = config.speed;
document.getElementById('speed-display').textContent = config.speed + 'ms';
}
if (config.strategy !== undefined) {
document.getElementById('strategy').selectedIndex = config.strategy;
}
showCustomToast(`✓ Config "${config.name}" imported!`, 'success');
document.getElementById('config-import').value = '';
});
function updateConfigsList() {
const list = document.getElementById('saved-configs-list');
if (!list) return;
const configs = Object.entries(savedConfigs);
if (configs.length === 0) {
list.innerHTML = '<div class="empty-state">No saved configs yet</div>';
return;
}
list.innerHTML = configs.map(([code, config]) => `
<div class="config-item">
<div>
<div class="config-item-name">${config.name}</div>
<div class="config-item-code">${code.substring(0, 16)}...</div>
</div>
<div class="config-item-actions">
<button class="config-item-btn" onclick="loadConfig('${code}')">Load</button>
<button class="config-item-btn" onclick="deleteConfig('${code}')">Delete</button>
</div>
</div>
`).join('');
}
window.loadConfig = (code) => {
const config = savedConfigs[code];
if (config) {
document.getElementById('config-import').value = code;
document.getElementById('config-import-btn').click();
}
};
window.deleteConfig = (code) => {
if (confirm('Delete this config?')) {
delete savedConfigs[code];
localStorage.setItem('oxm_saved_configs', JSON.stringify(savedConfigs));
updateConfigsList();
showCustomToast('Config deleted', 'info');
}
};
updateConfigsList();
// Update stats display every second
setInterval(updateStatsDisplay, 1000);
// Update safety calculator
setInterval(updateSafetyCalculator, 2000);
}
function handleBotToggle(state) {
if (!nimage) {
showCustomToast(t('imagenotloaded'));
document.getElementById('bot-toggle').checked = false;
return;
}
if (!coordinates) {
showCustomToast(t('coordinatesnotset'));
document.getElementById('bot-toggle').checked = false;
return;
}
if (!state) {
clearOxmCanvas();
core.engine.tasks = [];
core.protection?.stop();
updateStatusIndicator(false);
return;
}
if (!localStorage.getItem('firstBotUse')) {
showCustomToast(t('botwarning'), 'warning');
localStorage.setItem('firstBotUse', 'true');
}
clearOxmCanvas();
oxm_game_context.drawImage(nimage.image, ...coordinates);
core.engine.tasks = [
...core.engine.tasks,
...nimage.convertToTasks(...coordinates, core.nevinWS),
].sort(drawing_style);
updateStatusIndicator(true);
if (document.getElementById('protect-toggle').checked && nimage && coordinates) {
core.protection.load(nimage, coordinates);
core.protection.start();
}
}
function handleProtectionToggle(state) {
if (state) {
if (!localStorage.getItem('firstProtectionUse')) {
showCustomToast(t('protectionwarning'), 'warning');
localStorage.setItem('firstProtectionUse', 'true');
}
if (!nimage) {
showCustomToast(t('imagenotloaded'));
document.getElementById('protect-toggle').checked = false;
return;
}
if (!coordinates) {
showCustomToast(t('coordinatesnotset'));
document.getElementById('protect-toggle').checked = false;
return;
}
if (!core.protection) {
core.protection = new NevinProtect(core);
if (coordinates && nimage) {
core.protection.load(nimage, coordinates);
}
}
core.protection.start();
} else {
core.protection?.stop();
}
}
function applyCustomization() {
localStorage.setItem('oxm_primary_color', menuCustomization.primaryColor);
localStorage.setItem('oxm_secondary_color', menuCustomization.secondaryColor);
localStorage.setItem('oxm_bg_color', menuCustomization.bgColor);
localStorage.setItem('oxm_text_color', menuCustomization.textColor);
localStorage.setItem('oxm_menu_opacity', menuCustomization.menuOpacity);
const menu = document.querySelector('.cs2-cheat-menu');
menu.style.opacity = menuCustomization.menuOpacity;
showCustomToast('Theme applied! Reload to see full changes.', 'info');
}
function resetCustomization() {
menuCustomization = {
primaryColor: '#00d9ff',
secondaryColor: '#0066ff',
bgColor: '#0a0a0f',
textColor: '#ffffff',
menuOpacity: 0.98
};
document.getElementById('primary-color-picker').value = menuCustomization.primaryColor;
document.getElementById('secondary-color-picker').value = menuCustomization.secondaryColor;
document.getElementById('bg-color-picker').value = menuCustomization.bgColor;
document.getElementById('text-color-picker').value = menuCustomization.textColor;
document.getElementById('opacity-slider').value = menuCustomization.menuOpacity;
document.getElementById('opacity-display').textContent = '98%';
localStorage.removeItem('oxm_primary_color');
localStorage.removeItem('oxm_secondary_color');
localStorage.removeItem('oxm_bg_color');
localStorage.removeItem('oxm_text_color');
localStorage.removeItem('oxm_menu_opacity');
showCustomToast('Reset to default theme!', 'info');
}
function updateStatsDisplay() {
const currentTime = Date.now();
const uptime = Math.floor((currentTime - sessionStats.sessionStart) / 1000 / 60);
const pixelsPerMin = uptime > 0 ? Math.round(sessionStats.pixelsPlaced / uptime) : 0;
document.getElementById('pixels-count').textContent = sessionStats.pixelsPlaced.toLocaleString();
document.getElementById('pixels-per-min').textContent = pixelsPerMin.toLocaleString() + ' px/min';
document.getElementById('session-uptime').textContent = uptime + 'm';
document.getElementById('queue-size').textContent = core?.engine?.tasks?.length || 0;
// Save stats every minute
if (currentTime - sessionStats.lastSaveTime > 60000) {
sessionStats.lastSaveTime = currentTime;
localStorage.setItem('oxm_session_stats', JSON.stringify({
pixelsPlaced: sessionStats.pixelsPlaced,
totalUptime: sessionStats.totalUptime + uptime
}));
}
}
var nimage;
var coordinates;
var drawing_style;
async function Oxm_JSMain() {
if (BOT_DO_NOT_DITHER) unsafeWindow.BOT_DO_NOT_DITHER = true;
if (!core) {
core = new NevinCore({
timeout: OXMBOT_TIMEOUT,
multibot: OXMBOT_EXPERIMENTAL_USE_MULTI_ACC,
});
unsafeWindow.core = core;
NevinLogger.LEVEL = NevinLoggerFactory.LEVEL_INFO;
}
// Hook into pixel placement to track stats
const originalEngineRun = core.engine.run;
core.engine.run = function() {
const result = originalEngineRun.apply(this, arguments);
if (this.tasks.length > 0) {
sessionStats.pixelsPlaced++;
}
return result;
};
core.protection = null;
drawing_style = OXMBOT_DRAWING_STYLES[0][1];
function drawingStyleChange(e) {
const index = e.srcElement.selectedIndex;
if (index < OXMBOT_DRAWING_STYLES.length) {
drawing_style = OXMBOT_DRAWING_STYLES[index][1];
core.engine.tasks.sort(drawing_style);
}
}
document.getElementById("strategy").addEventListener("change", drawingStyleChange);
function loadImage(img) {
nimage = img;
nimage.image.addEventListener("load", function () {
document.getElementById("output").src = nimage.image.src;
if (coordinates) {
clearOxmCanvas();
oxm_game_context.drawImage(nimage.image, ...coordinates);
}
});
}
oxm_load_image.addEventListener("click", function () {
core.picker.requestImageFromFileDialog(core.palette).then(loadImage);
});
core.picker.addClipboardListener(core.palette, loadImage);
canvas.addEventListener("click", function () {
coordinates = pixelplace_coordinates.textContent.split(",").map(Number);
oxm_coordinates_text.value = JSON.stringify(coordinates);
if (nimage) {
clearOxmCanvas();
oxm_game_context.drawImage(nimage.image, ...coordinates);
}
});
var oldTitle = document.title;
setInterval(function () {
if (!document.hasFocus()) {
document.title = "Oxm Bot P" + core.engine.tasks.length;
} else if (document.title.startsWith("Oxm Bot")) {
document.title = oldTitle;
}
}, 10);
}
async function Oxm_Main() {
await Oxm_UIMain();
await Oxm_JSMain();
if (!localStorage.getItem('firstUse')) {
showCustomToast(t('welcome'), 'info');
setTimeout(() => showCustomToast(t('warning'), 'info'), 3500);
localStorage.setItem('firstUse', 'true');
}
}
(function () {
var observer = new MutationObserver(function () {
if (document.body) {
Oxm_Main();
observer.disconnect();
}
});
observer.observe(document.documentElement, { childList: true });
})();