diff --git a/Auto-Image.js b/Auto-Image.js
new file mode 100644
index 0000000..1081e7e
--- /dev/null
+++ b/Auto-Image.js
@@ -0,0 +1,822 @@
+(async () => {
+ // Configurações
+ const CONFIG = {
+ COOLDOWN_DEFAULT: 31000,
+ TRANSPARENCY_THRESHOLD: 100,
+ LOG_INTERVAL: 10,
+ THEME: {
+ primary: '#000000',
+ secondary: '#111111',
+ accent: '#222222',
+ text: '#ffffff',
+ highlight: '#4cc9f0',
+ success: '#00ff00',
+ error: '#ff0000',
+ warning: '#ffaa00'
+ }
+ };
+
+ // Estado do aplicativo
+ const state = {
+ running: false,
+ imageLoaded: false,
+ processing: false,
+ totalPixels: 0,
+ paintedPixels: 0,
+ availableColors: [],
+ currentCharges: 0,
+ cooldown: CONFIG.COOLDOWN_DEFAULT,
+ imageData: null,
+ stopFlag: false,
+ colorsChecked: false,
+ startPosition: null,
+ selectingPosition: false,
+ region: null,
+ minimized: false,
+ lastPosition: { x: 0, y: 0 } // Armazena a última posição pintada
+ };
+
+ // Funções utilitárias
+ const Utils = {
+ sleep: ms => new Promise(r => setTimeout(r, ms)),
+
+ colorDistance: (a, b) => Math.sqrt(
+ Math.pow(a[0] - b[0], 2) +
+ Math.pow(a[1] - b[1], 2) +
+ Math.pow(a[2] - b[2], 2)
+ ),
+
+ createImageUploader: () => new Promise(resolve => {
+ const input = document.createElement('input');
+ input.type = 'file';
+ input.accept = 'image/png,image/jpeg';
+ input.onchange = () => {
+ const fr = new FileReader();
+ fr.onload = () => resolve(fr.result);
+ fr.readAsDataURL(input.files[0]);
+ };
+ input.click();
+ }),
+
+ extractAvailableColors: () => {
+ const colorElements = document.querySelectorAll('[id^="color-"]');
+ const availableColors = [];
+
+ colorElements.forEach(el => {
+ if (!el.querySelector('svg')) {
+ const id = parseInt(el.id.replace('color-', ''));
+ const rgbStr = el.style.backgroundColor.match(/\d+/g);
+ const rgb = rgbStr ? rgbStr.map(Number) : [0, 0, 0];
+ availableColors.push({ id, rgb });
+ }
+ });
+
+ return availableColors;
+ },
+
+ formatTime: ms => {
+ const seconds = Math.floor((ms / 1000) % 60);
+ const minutes = Math.floor((ms / (1000 * 60)) % 60);
+ return `${minutes}m ${seconds}s`;
+ },
+
+ showAlert: (message, type = 'info') => {
+ const alert = document.createElement('div');
+ alert.style.position = 'fixed';
+ alert.style.top = '20px';
+ alert.style.left = '50%';
+ alert.style.transform = 'translateX(-50%)';
+ alert.style.padding = '15px 20px';
+ alert.style.background = type === 'error' ? CONFIG.THEME.error :
+ type === 'success' ? CONFIG.THEME.success :
+ type === 'warning' ? CONFIG.THEME.warning : CONFIG.THEME.accent;
+ alert.style.color = CONFIG.THEME.text;
+ alert.style.borderRadius = '5px';
+ alert.style.zIndex = '10000';
+ alert.style.boxShadow = '0 3px 10px rgba(0,0,0,0.3)';
+ alert.style.display = 'flex';
+ alert.style.alignItems = 'center';
+ alert.style.gap = '10px';
+ alert.innerHTML = `
+
+ ${message}
+ `;
+
+ document.body.appendChild(alert);
+
+ setTimeout(() => {
+ alert.style.opacity = '0';
+ alert.style.transition = 'opacity 0.5s';
+ setTimeout(() => alert.remove(), 500);
+ }, 3000);
+ }
+ };
+
+ // Serviço de comunicação com a API
+ const WPlaceService = {
+ async paintPixelInRegion(regionX, regionY, pixelX, pixelY, color) {
+ try {
+ const res = await fetch(`https://backend.wplace.live/s0/pixel/${regionX}/${regionY}`, {
+ method: 'POST',
+ headers: { 'Content-Type': 'text/plain;charset=UTF-8' },
+ credentials: 'include',
+ body: JSON.stringify({ coords: [pixelX, pixelY], colors: [color] })
+ });
+ const data = await res.json();
+ return data?.painted === 1;
+ } catch (error) {
+ console.error('Erro ao pintar pixel:', error);
+ return false;
+ }
+ },
+
+ async getCharges() {
+ try {
+ const res = await fetch('https://backend.wplace.live/me', {
+ credentials: 'include'
+ });
+ const data = await res.json();
+ return {
+ charges: data.charges?.count || 0,
+ cooldown: data.charges?.cooldownMs || CONFIG.COOLDOWN_DEFAULT
+ };
+ } catch (error) {
+ console.error('Erro ao obter cargas:', error);
+ return { charges: 0, cooldown: CONFIG.COOLDOWN_DEFAULT };
+ }
+ }
+ };
+
+ // Processador de imagem
+ class ImageProcessor {
+ constructor(imageSrc) {
+ this.imageSrc = imageSrc;
+ this.img = new Image();
+ this.canvas = document.createElement('canvas');
+ this.ctx = this.canvas.getContext('2d');
+ }
+
+ async load() {
+ return new Promise(resolve => {
+ this.img.onload = () => {
+ this.canvas.width = this.img.width;
+ this.canvas.height = this.img.height;
+ this.ctx.drawImage(this.img, 0, 0);
+ resolve();
+ };
+ this.img.src = this.imageSrc;
+ });
+ }
+
+ getPixelData() {
+ return this.ctx.getImageData(0, 0, this.canvas.width, this.canvas.height).data;
+ }
+
+ getDimensions() {
+ return { width: this.canvas.width, height: this.canvas.height };
+ }
+ }
+
+ // Encontra a cor mais próxima
+ function findClosestColor(rgb, palette) {
+ let closestColor = palette[0];
+ let minDistance = Utils.colorDistance(rgb, palette[0].rgb);
+
+ for (let i = 1; i < palette.length; i++) {
+ const distance = Utils.colorDistance(rgb, palette[i].rgb);
+ if (distance < minDistance) {
+ minDistance = distance;
+ closestColor = palette[i];
+ }
+ }
+
+ return closestColor.id;
+ }
+
+ // Cria a interface do usuário
+ function createUI() {
+ // Adiciona Font Awesome
+ const fontAwesome = document.createElement('link');
+ fontAwesome.rel = 'stylesheet';
+ fontAwesome.href = 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css';
+ document.head.appendChild(fontAwesome);
+
+ // Adiciona estilos
+ const style = document.createElement('style');
+ style.textContent = `
+ @keyframes pulse {
+ 0% { box-shadow: 0 0 0 0 rgba(0, 255, 0, 0.7); }
+ 70% { box-shadow: 0 0 0 10px rgba(0, 255, 0, 0); }
+ 100% { box-shadow: 0 0 0 0 rgba(0, 255, 0, 0); }
+ }
+ @keyframes slideIn {
+ from { transform: translateY(20px); opacity: 0; }
+ to { transform: translateY(0); opacity: 1; }
+ }
+ #wplace-image-bot-container {
+ position: fixed;
+ top: 20px;
+ right: 20px;
+ width: 300px;
+ background: ${CONFIG.THEME.primary};
+ border: 1px solid ${CONFIG.THEME.accent};
+ border-radius: 8px;
+ padding: 0;
+ box-shadow: 0 5px 15px rgba(0,0,0,0.5);
+ z-index: 9998;
+ font-family: 'Segoe UI', Roboto, sans-serif;
+ color: ${CONFIG.THEME.text};
+ animation: slideIn 0.4s ease-out;
+ overflow: hidden;
+ }
+ .wplace-header {
+ padding: 12px 15px;
+ background: ${CONFIG.THEME.secondary};
+ color: ${CONFIG.THEME.highlight};
+ font-size: 16px;
+ font-weight: 600;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ cursor: move;
+ user-select: none;
+ }
+ .wplace-header-title {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ }
+ .wplace-header-controls {
+ display: flex;
+ gap: 10px;
+ }
+ .wplace-header-btn {
+ background: none;
+ border: none;
+ color: ${CONFIG.THEME.text};
+ cursor: pointer;
+ opacity: 0.7;
+ transition: opacity 0.2s;
+ }
+ .wplace-header-btn:hover {
+ opacity: 1;
+ }
+ .wplace-content {
+ padding: 15px;
+ display: block;
+ }
+ .wplace-controls {
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
+ margin-bottom: 15px;
+ }
+ .wplace-btn {
+ padding: 10px;
+ border: none;
+ border-radius: 6px;
+ font-weight: 600;
+ cursor: pointer;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 8px;
+ transition: all 0.2s;
+ }
+ .wplace-btn:hover {
+ transform: translateY(-2px);
+ }
+ .wplace-btn-primary {
+ background: ${CONFIG.THEME.accent};
+ color: white;
+ }
+ .wplace-btn-upload {
+ background: ${CONFIG.THEME.secondary};
+ color: white;
+ border: 1px dashed ${CONFIG.THEME.text};
+ }
+ .wplace-btn-start {
+ background: ${CONFIG.THEME.success};
+ color: white;
+ }
+ .wplace-btn-stop {
+ background: ${CONFIG.THEME.error};
+ color: white;
+ }
+ .wplace-btn-select {
+ background: ${CONFIG.THEME.highlight};
+ color: black;
+ }
+ .wplace-btn:disabled {
+ opacity: 0.5;
+ cursor: not-allowed;
+ transform: none !important;
+ }
+ .wplace-stats {
+ background: ${CONFIG.THEME.secondary};
+ padding: 12px;
+ border-radius: 6px;
+ margin-bottom: 15px;
+ }
+ .wplace-stat-item {
+ display: flex;
+ justify-content: space-between;
+ padding: 6px 0;
+ font-size: 14px;
+ }
+ .wplace-stat-label {
+ display: flex;
+ align-items: center;
+ gap: 6px;
+ opacity: 0.8;
+ }
+ .wplace-progress {
+ width: 100%;
+ background: ${CONFIG.THEME.secondary};
+ border-radius: 4px;
+ margin: 10px 0;
+ overflow: hidden;
+ }
+ .wplace-progress-bar {
+ height: 10px;
+ background: ${CONFIG.THEME.highlight};
+ transition: width 0.3s;
+ }
+ .wplace-status {
+ padding: 8px;
+ border-radius: 4px;
+ text-align: center;
+ font-size: 13px;
+ }
+ .status-default {
+ background: rgba(255,255,255,0.1);
+ }
+ .status-success {
+ background: rgba(0, 255, 0, 0.1);
+ color: ${CONFIG.THEME.success};
+ }
+ .status-error {
+ background: rgba(255, 0, 0, 0.1);
+ color: ${CONFIG.THEME.error};
+ }
+ .status-warning {
+ background: rgba(255, 165, 0, 0.1);
+ color: orange;
+ }
+ #paintEffect {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ pointer-events: none;
+ border-radius: 8px;
+ }
+ .position-info {
+ font-size: 13px;
+ margin-top: 5px;
+ padding: 5px;
+ background: ${CONFIG.THEME.secondary};
+ border-radius: 4px;
+ text-align: center;
+ }
+ .wplace-minimized .wplace-content {
+ display: none;
+ }
+ `;
+ document.head.appendChild(style);
+
+ // Cria o container principal
+ const container = document.createElement('div');
+ container.id = 'wplace-image-bot-container';
+ container.innerHTML = `
+
+
+
+
+
+
+
+
+
+
+
+ Nenhuma posição selecionada
+
+
+
+
+
+
+
+
+
Clique em "Iniciar Auto-BOT" para começar
+
+
+
+
+
+ Aguardando inicialização...
+
+
+ `;
+
+ document.body.appendChild(container);
+
+ // Tornar arrastável
+ const header = container.querySelector('.wplace-header');
+ let pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
+
+ header.onmousedown = dragMouseDown;
+
+ function dragMouseDown(e) {
+ if (e.target.closest('.wplace-header-btn')) return;
+
+ e = e || window.event;
+ e.preventDefault();
+ pos3 = e.clientX;
+ pos4 = e.clientY;
+ document.onmouseup = closeDragElement;
+ document.onmousemove = elementDrag;
+ }
+
+ function elementDrag(e) {
+ e = e || window.event;
+ e.preventDefault();
+ pos1 = pos3 - e.clientX;
+ pos2 = pos4 - e.clientY;
+ pos3 = e.clientX;
+ pos4 = e.clientY;
+ container.style.top = (container.offsetTop - pos2) + "px";
+ container.style.left = (container.offsetLeft - pos1) + "px";
+ }
+
+ function closeDragElement() {
+ document.onmouseup = null;
+ document.onmousemove = null;
+ }
+
+ // Elementos da UI
+ const initBotBtn = container.querySelector('#initBotBtn');
+ const uploadBtn = container.querySelector('#uploadBtn');
+ const selectPosBtn = container.querySelector('#selectPosBtn');
+ const startBtn = container.querySelector('#startBtn');
+ const stopBtn = container.querySelector('#stopBtn');
+ const minimizeBtn = container.querySelector('#minimizeBtn');
+ const statusText = container.querySelector('#statusText');
+ const progressBar = container.querySelector('#progressBar');
+ const statsArea = container.querySelector('#statsArea');
+ const positionInfo = container.querySelector('#positionInfo');
+ const content = container.querySelector('.wplace-content');
+
+ // Minimizar/Maximizar
+ minimizeBtn.addEventListener('click', () => {
+ state.minimized = !state.minimized;
+ if (state.minimized) {
+ container.classList.add('wplace-minimized');
+ minimizeBtn.innerHTML = '';
+ } else {
+ container.classList.remove('wplace-minimized');
+ minimizeBtn.innerHTML = '';
+ }
+ });
+
+ // Atualiza a UI
+ window.updateUI = (message, type = 'default') => {
+ statusText.textContent = message;
+ statusText.className = `wplace-status status-${type}`;
+ statusText.style.animation = 'none';
+ void statusText.offsetWidth;
+ statusText.style.animation = 'slideIn 0.3s ease-out';
+ };
+
+ // Atualiza as estatísticas
+ window.updateStats = async () => {
+ if (!state.colorsChecked) return;
+
+ const { charges, cooldown } = await WPlaceService.getCharges();
+ state.currentCharges = Math.floor(charges); // Arredonda para baixo
+ state.cooldown = cooldown;
+
+ const progress = state.totalPixels > 0 ?
+ Math.round((state.paintedPixels / state.totalPixels) * 100) : 0;
+ const remainingPixels = state.totalPixels - state.paintedPixels;
+
+ progressBar.style.width = `${progress}%`;
+
+ statsArea.innerHTML = `
+
+
Progresso
+
${progress}%
+
+
+
Pixels
+
${state.paintedPixels}/${state.totalPixels}
+
+
+
Cargas
+
${Math.floor(state.currentCharges)}
+
+
+
Restantes
+
${remainingPixels} pixels
+
+ `;
+ };
+
+ // Atualiza a informação da posição
+ function updatePositionInfo() {
+ if (state.startPosition && state.region) {
+ positionInfo.style.display = 'block';
+ positionInfo.innerHTML = `
+
+ Posição: (${state.startPosition.x}, ${state.startPosition.y}) | Região: ${state.region.x}/${state.region.y}
+ `;
+ } else {
+ positionInfo.style.display = 'none';
+ }
+ }
+
+ // Evento do botão Iniciar Auto-BOT
+ initBotBtn.addEventListener('click', async () => {
+ try {
+ updateUI('🔍 Verificando cores disponíveis...', 'default');
+
+ state.availableColors = Utils.extractAvailableColors();
+
+ if (state.availableColors.length === 0) {
+ Utils.showAlert('Abra a paleta de cores no site e tente novamente!', 'error');
+ updateUI('❌ Nenhuma cor disponível encontrada', 'error');
+ return;
+ }
+
+ state.colorsChecked = true;
+ uploadBtn.disabled = false;
+ selectPosBtn.disabled = false;
+ initBotBtn.style.display = 'none'; // Esconde o botão após iniciar
+
+ updateUI(`✅ ${state.availableColors.length} cores disponíveis encontradas`, 'success');
+ updateStats();
+
+ } catch (error) {
+ console.error('Erro ao verificar cores:', error);
+ updateUI('❌ Erro ao verificar cores', 'error');
+ }
+ });
+
+ // Evento do botão Upload da Imagem
+ uploadBtn.addEventListener('click', async () => {
+ try {
+ updateUI('🖼️ Carregando imagem...', 'default');
+ const imageSrc = await Utils.createImageUploader();
+
+ const processor = new ImageProcessor(imageSrc);
+ await processor.load();
+
+ const { width, height } = processor.getDimensions();
+ const pixels = processor.getPixelData();
+
+ state.imageData = {
+ width,
+ height,
+ pixels,
+ totalPixels: width * height
+ };
+
+ state.totalPixels = state.imageData.totalPixels;
+ state.paintedPixels = 0;
+ state.imageLoaded = true;
+ state.lastPosition = { x: 0, y: 0 }; // Reseta a última posição
+
+ if (state.startPosition) {
+ startBtn.disabled = false;
+ }
+
+ updateStats();
+ updateUI('✅ Imagem carregada com sucesso!', 'success');
+ } catch (error) {
+ console.error('Erro ao carregar imagem:', error);
+ updateUI('❌ Erro ao carregar imagem', 'error');
+ }
+ });
+
+ // Evento do botão Selecionar Posição
+ selectPosBtn.addEventListener('click', async () => {
+ if (state.selectingPosition) return;
+
+ state.selectingPosition = true;
+ state.startPosition = null;
+ state.region = null;
+ startBtn.disabled = true;
+ updatePositionInfo();
+
+ Utils.showAlert('Pinte o primeiro pixel na localização onde deseja que a arte comece!', 'info');
+ updateUI('👆 Aguardando você pintar o pixel de referência...', 'default');
+
+ const originalFetch = window.fetch;
+
+ window.fetch = async (url, options) => {
+ if (typeof url === 'string' &&
+ url.includes('https://backend.wplace.live/s0/pixel/') &&
+ options?.method?.toUpperCase() === 'POST') {
+
+ try {
+ const response = await originalFetch(url, options);
+ const clonedResponse = response.clone();
+ const data = await clonedResponse.json();
+
+ if (data?.painted === 1) {
+ const regionMatch = url.match(/\/pixel\/(\d+)\/(\d+)/);
+ if (regionMatch && regionMatch.length >= 3) {
+ state.region = {
+ x: parseInt(regionMatch[1]),
+ y: parseInt(regionMatch[2])
+ };
+ }
+
+ const payload = JSON.parse(options.body);
+ if (payload?.coords && Array.isArray(payload.coords)) {
+ state.startPosition = {
+ x: payload.coords[0],
+ y: payload.coords[1]
+ };
+ state.lastPosition = { x: 0, y: 0 }; // Reseta a última posição
+
+ updatePositionInfo();
+ updateUI('✅ Posição definida com sucesso!', 'success');
+ Utils.showAlert(`Posição capturada na região ${state.region.x}/${state.region.y}!`, 'success');
+
+ if (state.imageLoaded) {
+ startBtn.disabled = false;
+ }
+
+ window.fetch = originalFetch;
+ state.selectingPosition = false;
+ }
+ }
+
+ return response;
+ } catch (error) {
+ console.error('Erro ao interceptar requisição:', error);
+ return originalFetch(url, options);
+ }
+ }
+ return originalFetch(url, options);
+ };
+
+ setTimeout(() => {
+ if (state.selectingPosition) {
+ window.fetch = originalFetch;
+ state.selectingPosition = false;
+ updateUI('❌ Tempo esgotado para selecionar posição', 'error');
+ Utils.showAlert('Tempo esgotado! Clique em "Selecionar Posição" novamente.', 'error');
+ }
+ }, 120000);
+ });
+
+ // Evento do botão Iniciar Pintura
+ startBtn.addEventListener('click', async () => {
+ if (!state.imageLoaded || !state.startPosition || !state.region) {
+ updateUI('❌ Carregue uma imagem e selecione uma posição primeiro', 'error');
+ return;
+ }
+
+ state.running = true;
+ state.stopFlag = false;
+ startBtn.disabled = true;
+ stopBtn.disabled = false;
+ uploadBtn.disabled = true;
+ selectPosBtn.disabled = true;
+
+ updateUI(`🎨 Iniciando pintura na região ${state.region.x}/${state.region.y}...`, 'success');
+
+ try {
+ await processImage();
+ } catch (error) {
+ console.error('Erro durante a pintura:', error);
+ updateUI('❌ Erro durante a pintura', 'error');
+ } finally {
+ state.running = false;
+ stopBtn.disabled = true;
+
+ if (!state.stopFlag) {
+ startBtn.disabled = true;
+ uploadBtn.disabled = false;
+ selectPosBtn.disabled = false;
+ } else {
+ startBtn.disabled = false;
+ }
+ }
+ });
+
+ // Evento do botão Parar Pintura
+ stopBtn.addEventListener('click', () => {
+ state.stopFlag = true;
+ state.running = false;
+ stopBtn.disabled = true;
+ updateUI('⏹️ Pintura interrompida pelo usuário', 'warning');
+ });
+ }
+
+ // Processa a imagem
+ async function processImage() {
+ const { width, height, pixels } = state.imageData;
+ const { x: startX, y: startY } = state.startPosition;
+ const { x: regionX, y: regionY } = state.region;
+
+ // Começa da última posição ou do início
+ let startRow = state.lastPosition.y || 0;
+ let startCol = state.lastPosition.x || 0;
+
+ outerLoop:
+ for (let y = startRow; y < height; y++) {
+ for (let x = (y === startRow ? startCol : 0); x < width; x++) {
+ if (state.stopFlag) {
+ // Salva a última posição pintada
+ state.lastPosition = { x, y };
+ break outerLoop;
+ }
+
+ const idx = (y * width + x) * 4;
+ const rgb = [pixels[idx], pixels[idx + 1], pixels[idx + 2]];
+ const alpha = pixels[idx + 3];
+
+ if (alpha < CONFIG.TRANSPARENCY_THRESHOLD) continue;
+
+ const colorId = findClosestColor(rgb, state.availableColors);
+
+ if (state.currentCharges < 1) {
+ updateUI(`⌛ Sem cargas. Aguardando ${Utils.formatTime(state.cooldown)}...`, 'warning');
+ await Utils.sleep(state.cooldown);
+
+ const chargeUpdate = await WPlaceService.getCharges();
+ state.currentCharges = chargeUpdate.charges;
+ state.cooldown = chargeUpdate.cooldown;
+ }
+
+ const pixelX = startX + x;
+ const pixelY = startY + y;
+
+ const success = await WPlaceService.paintPixelInRegion(
+ regionX,
+ regionY,
+ pixelX,
+ pixelY,
+ colorId
+ );
+
+ if (success) {
+ state.paintedPixels++;
+ state.currentCharges--;
+
+ if (state.paintedPixels % CONFIG.LOG_INTERVAL === 0) {
+ updateStats();
+ updateUI(`🧱 Progresso: ${state.paintedPixels}/${state.totalPixels} pixels...`, 'default');
+ }
+ }
+ }
+ }
+
+ if (state.stopFlag) {
+ updateUI('⏹️ Pintura interrompida pelo usuário', 'warning');
+ } else {
+ updateUI(`✅ Pintura concluída! ${state.paintedPixels} pixels pintados.`, 'success');
+ state.lastPosition = { x: 0, y: 0 }; // Reseta para próxima execução
+ }
+
+ updateStats();
+ }
+
+ // Inicialização
+ createUI();
+ console.log('WPlace Image Bot - Interface carregada com sucesso!');
+})();