diff --git a/Auto-Image.js b/Auto-Image.js
index cbbc75df..4bef3ac6 100644
--- a/Auto-Image.js
+++ b/Auto-Image.js
@@ -1,4 +1,14 @@
-// eslint-disable-next-line prettier/prettier
+// ==UserScript==
+// @name WPlaceBot
+// @namespace http://tampermonkey.net/
+// @version 2025-08-08.3
+// @description Bot
+// @author TH3C0D3R
+// @match https://wplace.live/*
+// @grant none
+// @icon
+// ==/UserScript==
+localStorage.removeItem("lp");
; (async () => {
// CONFIGURATION CONSTANTS
const CONFIG = {
@@ -190,6 +200,27 @@
'pixel-blink': true,
},
},
+ 'Acrylic': {
+ primary: '#00000080',
+ secondary: '#00000040',
+ accent: 'rgba(0,0,0,0.75)',
+ text: '#ffffff',
+ highlight: '#ffffff',
+ success: '#00e500',
+ error: '#e50000',
+ warning: '#e5e500',
+ fontFamily: "'Inter', 'Apple Color Emoji'",
+ borderRadius: '10px',
+ borderStyle: 'solid',
+ borderWidth: '0px',
+ boxShadow: 'none',
+ backdropFilter: 'blur(20px)',
+ animations: {
+ glow: false,
+ scanline: false,
+ 'pixel-blink': false,
+ },
+ },
},
currentTheme: 'Classic Autobot',
PAINT_UNAVAILABLE: true,
@@ -222,6 +253,7 @@
document.documentElement.classList.remove(
'wplace-theme-classic',
'wplace-theme-classic-light',
+ 'wplace-theme-acrylic',
'wplace-theme-neon'
);
@@ -230,6 +262,8 @@
themeClass = 'wplace-theme-neon';
} else if (CONFIG.currentTheme === 'Classic Light') {
themeClass = 'wplace-theme-classic-light';
+ } else if (CONFIG.currentTheme === 'Acrylic') {
+ themeClass = 'wplace-theme-acrylic';
}
document.documentElement.classList.add(themeClass);
@@ -239,7 +273,7 @@
const setVar = (k, v) => {
try {
root.style.setProperty(k, v);
- } catch {}
+ } catch { }
};
setVar('--wplace-primary', theme.primary);
@@ -333,8 +367,7 @@
) {
loadedTranslations[language] = translations;
console.log(
- `📚 Loaded ${language} translations successfully from CDN (${
- Object.keys(translations).length
+ `📚 Loaded ${language} translations successfully from CDN (${Object.keys(translations).length
} keys)`
);
return translations;
@@ -553,6 +586,7 @@
startPosition: null,
selectingPosition: false,
region: null,
+ experiments: null,
minimized: false,
lastPosition: { x: 0, y: 0 },
estimatedTime: 0,
@@ -597,7 +631,9 @@
paintedMap: null,
};
- let _updateResizePreview = () => {};
+ state.experiments = localStorage.getItem("exp_wbot");
+
+ let _updateResizePreview = () => { };
let _resizeDialogCleanup = null;
// --- OVERLAY UPDATE: Optimized OverlayManager class with performance improvements ---
@@ -1189,7 +1225,9 @@
throw error;
}
}
-
+ const randStr = (len, chars = 'abcdefghijklmnopqrstuvwxyz0123456789') =>
+ [...Array(len)].map(() => chars[(crypto?.getRandomValues?.(new Uint32Array(1))[0] % chars.length) || Math.floor(Math.random() * chars.length)]).join('')
+ const fpStr32 = randStr(32);
async function handleCaptchaFallback() {
// Implementation for fallback token generation would go here
// This is a placeholder for browser automation fallback
@@ -1230,14 +1268,13 @@
if (payload.t) {
// 📊 Debug log
console.log(
- `🔍✅ Turnstile Token Captured - Type: ${typeof payload.t}, Value: ${
- payload.t
- ? typeof payload.t === 'string'
- ? payload.t.length > 50
- ? payload.t.substring(0, 50) + '...'
- : payload.t
- : JSON.stringify(payload.t)
- : 'null/undefined'
+ `🔍✅ Turnstile Token Captured - Type: ${typeof payload.t}, Value: ${payload.t
+ ? typeof payload.t === 'string'
+ ? payload.t.length > 50
+ ? payload.t.substring(0, 50) + '...'
+ : payload.t
+ : JSON.stringify(payload.t)
+ : 'null/undefined'
}, Length: ${payload.t?.length || 0}`
);
window.postMessage({ source: 'turnstile-capture', token: payload.t }, '*');
@@ -1346,34 +1383,34 @@
// Debounced scroll-to-adjust handler for sliders
createScrollToAdjust: (element, updateCallback, min, max, step = 1) => {
let debounceTimer = null;
-
+
const handleWheel = (e) => {
// Only trigger when hovering over the slider
if (e.target !== element) return;
-
+
e.preventDefault();
e.stopPropagation();
-
+
// Clear existing debounce timer
if (debounceTimer) {
clearTimeout(debounceTimer);
}
-
+
// Debounce the adjustment to make it precise
debounceTimer = setTimeout(() => {
const currentValue = parseInt(element.value) || 0;
const delta = e.deltaY > 0 ? -step : step;
const newValue = Math.max(min, Math.min(max, currentValue + delta));
-
+
if (newValue !== currentValue) {
element.value = newValue;
updateCallback(newValue);
}
}, 50); // 50ms debounce for precise control
};
-
+
element.addEventListener('wheel', handleWheel, { passive: false });
-
+
// Return cleanup function
return () => {
if (debounceTimer) clearTimeout(debounceTimer);
@@ -1708,9 +1745,9 @@
return isTokenValid()
? {
- sitekey: this._cachedSitekey,
- token: turnstileToken,
- }
+ sitekey: this._cachedSitekey,
+ token: turnstileToken,
+ }
: { sitekey: this._cachedSitekey, token: null };
}
@@ -1972,8 +2009,8 @@
const bdiff = pb - b;
const dist = Math.sqrt(
(((512 + rmean) * rdiff * rdiff) >> 8) +
- 4 * gdiff * gdiff +
- (((767 - rmean) * bdiff * bdiff) >> 8)
+ 4 * gdiff * gdiff +
+ (((767 - rmean) * bdiff * bdiff) >> 8)
);
if (dist < menorDist) {
menorDist = dist;
@@ -2023,9 +2060,8 @@
};
}
- const cacheKey = `${targetRgb[0]},${targetRgb[1]},${targetRgb[2]}|${state.colorMatchingAlgorithm}|${
- state.enableChromaPenalty ? 'c' : 'nc'
- }|${state.chromaPenaltyWeight}|${exactMatch ? 'exact' : 'closest'}`;
+ const cacheKey = `${targetRgb[0]},${targetRgb[1]},${targetRgb[2]}|${state.colorMatchingAlgorithm}|${state.enableChromaPenalty ? 'c' : 'nc'
+ }|${state.chromaPenaltyWeight}|${exactMatch ? 'exact' : 'closest'}`;
if (colorCache.has(cacheKey)) return colorCache.get(cacheKey);
@@ -2075,8 +2111,8 @@
const bdiff = b - targetRgb[2];
const dist = Math.sqrt(
(((512 + rmean) * rdiff * rdiff) >> 8) +
- 4 * gdiff * gdiff +
- (((767 - rmean) * bdiff * bdiff) >> 8)
+ 4 * gdiff * gdiff +
+ (((767 - rmean) * bdiff * bdiff) >> 8)
);
if (dist < bestScore) {
bestScore = dist;
@@ -2224,8 +2260,7 @@
console.log('\n--- AVAILABLE COLORS ---');
availableColors.forEach((color, index) => {
console.log(
- `${
- index + 1
+ `${index + 1
}. ID: ${color.id}, Name: "${color.name}", RGB: (${color.rgb[0]}, ${color.rgb[1]}, ${color.rgb[2]})`
);
});
@@ -2235,8 +2270,7 @@
console.log('\n--- UNAVAILABLE COLORS ---');
unavailableColors.forEach((color, index) => {
console.log(
- `${
- index + 1
+ `${index + 1
}. ID: ${color.id}, Name: "${color.name}", RGB: (${color.rgb[0]}, ${color.rgb[1]}, ${color.rgb[2]}) [LOCKED]`
);
});
@@ -2517,11 +2551,11 @@
},
imageData: state.imageData
? {
- width: state.imageData.width,
- height: state.imageData.height,
- pixels: Array.from(state.imageData.pixels),
- totalPixels: state.imageData.totalPixels,
- }
+ width: state.imageData.width,
+ height: state.imageData.height,
+ pixels: Array.from(state.imageData.pixels),
+ totalPixels: state.imageData.totalPixels,
+ }
: null,
paintedMapPacked: Utils.buildPaintedMapPacked(),
};
@@ -2574,7 +2608,7 @@
if (migrated && migrated !== data) {
try {
localStorage.setItem('wplace-bot-progress', JSON.stringify(migrated));
- } catch {}
+ } catch { }
}
return migrated;
} catch (error) {
@@ -2826,10 +2860,12 @@
coords: [pixelX, pixelY],
colors: [color],
t: turnstileToken,
+ fp: fpStr32,
};
+ var token = await createWasmToken(regionX, regionY, payload);
const res = await fetch(`https://backend.wplace.live/s0/pixel/${regionX}/${regionY}`, {
method: 'POST',
- headers: { 'Content-Type': 'text/plain;charset=UTF-8' },
+ headers: { 'Content-Type': 'text/plain;charset=UTF-8', "x-pawtect-token": token },
credentials: 'include',
body: JSON.stringify(payload),
});
@@ -2986,9 +3022,9 @@
const colorCache = new Map();
// UI UPDATE FUNCTIONS (declared early to avoid reference errors)
- let updateUI = () => {};
- let updateStats = (isManualRefresh) => {};
- let updateDataButtons = () => {};
+ let updateUI = () => { };
+ let updateStats = (isManualRefresh) => { };
+ let updateDataButtons = () => { };
function updateActiveColorPalette() {
state.activeColorPalette = [];
@@ -3202,14 +3238,13 @@
// 📊 Debug log
console.log(
- `🔍 Token received - Type: ${typeof token}, Value: ${
- token
- ? typeof token === 'string'
- ? token.length > 50
- ? token.substring(0, 50) + '...'
- : token
- : JSON.stringify(token)
- : 'null/undefined'
+ `🔍 Token received - Type: ${typeof token}, Value: ${token
+ ? typeof token === 'string'
+ ? token.length > 50
+ ? token.substring(0, 50) + '...'
+ : token
+ : JSON.stringify(token)
+ : 'null/undefined'
}, Length: ${token?.length || 0}`
);
@@ -3349,6 +3384,37 @@
const existingResizeContainer = document.querySelector('.resize-container');
const existingResizeOverlay = document.querySelector('.resize-overlay');
+ document.addEventListener("keydown", async function (event) {
+ if(state.running) return;
+ event.stopPropagation();
+ switch (event.key) {
+ case "ArrowUp":
+ if (state?.startPosition?.y && state?.region?.y) {
+ state.startPosition.y--;
+ await overlayManager.setPosition(state.startPosition, state.region);
+ }
+ break;
+ case "ArrowDown":
+ if (state?.startPosition?.y && state?.region?.y) {
+ state.startPosition.y++;
+ await overlayManager.setPosition(state.startPosition, state.region);
+ }
+ break;
+ case "ArrowLeft":
+ if (state?.startPosition?.x && state?.region?.x) {
+ state.startPosition.x--;
+ await overlayManager.setPosition(state.startPosition, state.region);
+ }
+ break;
+ case "ArrowRight":
+ if (state?.startPosition?.x && state?.region?.x) {
+ state.startPosition.x++;
+ await overlayManager.setPosition(state.startPosition, state.region);
+ }
+ break;
+ }
+ });
+
if (existingContainer) existingContainer.remove();
if (existingStats) existingStats.remove();
if (existingSettings) existingSettings.remove();
@@ -3433,8 +3499,8 @@
@@ -3504,8 +3570,8 @@
${Utils.t('saveData')}
@@ -3516,8 +3582,8 @@
${Utils.t('saveToFile')}
@@ -3539,8 +3605,8 @@
@@ -3580,19 +3646,17 @@
z-index: 99999;
color: ${theme.text || 'white'};
font-family: ${theme.fontFamily || "'Segoe UI', Tahoma, Geneva, Verdana, sans-serif"};
- box-shadow: ${
- theme.boxShadow || '0 20px 40px rgba(0,0,0,0.3), 0 0 0 1px rgba(255,255,255,0.1)'
+ box-shadow: ${theme.boxShadow || '0 20px 40px rgba(0,0,0,0.3), 0 0 0 1px rgba(255,255,255,0.1)'
};
backdrop-filter: ${theme.backdropFilter || 'blur(10px)'};
overflow: hidden;
animation: settings-slide-in 0.4s ease-out;
- ${
- theme.animations?.glow
- ? `
+ ${theme.animations?.glow
+ ? `
box-shadow: ${theme.boxShadow || '0 20px 40px rgba(0,0,0,0.3)'},
0 0 30px ${theme.highlight || theme.neon || '#00ffff'};
`
- : ''
+ : ''
}
`;
@@ -3618,15 +3682,12 @@
Generator mode creates tokens automatically. Hybrid mode falls back to manual when generator fails. Manual mode only uses pixel placement.
@@ -3646,9 +3707,8 @@
@@ -3719,9 +3773,8 @@
${Utils.t('paintWhitePixels')}
-
+
${Utils.t('paintWhitePixelsDescription')}
@@ -3736,9 +3789,8 @@
${Utils.t('paintTransparentPixels')}
-
+
${Utils.t('paintTransparentPixelsDescription')}
@@ -3748,16 +3800,13 @@
@@ -3832,9 +3881,8 @@
@@ -3880,16 +3928,13 @@
@@ -3928,21 +3973,18 @@
@@ -3969,13 +4011,12 @@
@@ -4151,18 +4192,18 @@
+ 'zoomOut'
+ )}">
+ 'zoomIn'
+ )}">
+ 'fitToView'
+ )}">${Utils.t('fit')}
+ 'actualSize'
+ )}">${Utils.t('hundred')}
@@ -4241,12 +4282,10 @@
-
+
-
+
${Utils.t(
- 'pixels'
- )}
+ 'pixels'
+ )}
${state.paintedPixels}/${state.totalPixels}
${Utils.t(
- 'estimatedTime'
- )}
+ 'estimatedTime'
+ )}
${Utils.formatTime(state.estimatedTime)}
`;
@@ -5316,21 +5353,20 @@
--:--:--
- ${
- state.colorsChecked
- ? `
+ ${state.colorsChecked
+ ? `
${Utils.t(
- 'availableColors',
- { count: state.availableColors.length }
- )}
+ 'availableColors',
+ { count: state.availableColors.length }
+ )}
${colorSwatchesHTML}
`
- : ''
- }
+ : ''
+ }
`;
// should be after statsArea.innerHTML = '...'. todo make full stats ui update partial
@@ -6403,13 +6439,13 @@
_resizeDialogCleanup = () => {
try {
zoomSlider.replaceWith(zoomSlider.cloneNode(true));
- } catch {}
+ } catch { }
try {
if (zoomInBtn) zoomInBtn.replaceWith(zoomInBtn.cloneNode(true));
- } catch {}
+ } catch { }
try {
if (zoomOutBtn) zoomOutBtn.replaceWith(zoomOutBtn.cloneNode(true));
- } catch {}
+ } catch { }
};
setTimeout(() => {
if (typeof computeFitZoom === 'function') {
@@ -6429,21 +6465,21 @@
if (typeof _resizeDialogCleanup === 'function') {
_resizeDialogCleanup();
}
- } catch {}
+ } catch { }
resizeOverlay.style.display = 'none';
resizeContainer.style.display = 'none';
- _updateResizePreview = () => {};
+ _updateResizePreview = () => { };
try {
if (typeof cancelAnimationFrame === 'function' && _panRaf) {
cancelAnimationFrame(_panRaf);
}
- } catch {}
+ } catch { }
try {
if (_previewTimer) {
clearTimeout(_previewTimer);
_previewTimer = null;
}
- } catch {}
+ } catch { }
_maskImageData = null;
_maskData = null;
_dirty = null;
@@ -6707,9 +6743,9 @@
Utils.showAlert(
`${Utils.t('savedDataFound')}\n\n` +
- `Saved: ${savedDate}\n` +
- `Progress: ${savedData.state.paintedPixels}/${savedData.state.totalPixels} pixels (${progress}%)\n` +
- `${Utils.t('clickLoadToContinue')}`,
+ `Saved: ${savedDate}\n` +
+ `Progress: ${savedData.state.paintedPixels}/${savedData.state.totalPixels} pixels (${progress}%)\n` +
+ `${Utils.t('clickLoadToContinue')}`,
'info'
);
}
@@ -6721,12 +6757,12 @@
const updateCooldown = (newValue) => {
const threshold = Math.max(1, Math.min(state.maxCharges || 999, parseInt(newValue)));
state.cooldownChargeThreshold = threshold;
-
+
// Update both controls (value shows in input, label shows unit only)
cooldownSlider.value = threshold;
cooldownInput.value = threshold;
cooldownValue.textContent = `${Utils.t('charges')}`;
-
+
saveBotSettings();
NotificationManager.resetEdgeTracking(); // prevent spurious notify after threshold change
};
@@ -7140,8 +7176,7 @@
) {
if (pixelBatch && pixelBatch.pixels.length > 0) {
console.log(
- `🌍 Sending region-change batch with ${pixelBatch.pixels.length} pixels (switching to region ${
- regionX + adderX
+ `🌍 Sending region-change batch with ${pixelBatch.pixels.length} pixels (switching to region ${regionX + adderX
},${regionY + adderY})`
);
const success = await flushPixelBatch(pixelBatch);
@@ -7203,14 +7238,12 @@
continue;
}
console.debug(
- `[COMPARE] Pixel at 📍 (${pixelX}, ${pixelY}) in region (${
- regionX + adderX
+ `[COMPARE] Pixel at 📍 (${pixelX}, ${pixelY}) in region (${regionX + adderX
}, ${regionY + adderY})\n` +
- ` ├── Current color: rgb(${tilePixelRGBA.slice(0, 3).join(', ')}) (id: ${mappedCanvasColor.id})\n` +
- ` ├── Target color: rgb(${targetPixelInfo.r}, ${targetPixelInfo.g}, ${targetPixelInfo.b}) (id: ${targetMappedColorId})\n` +
- ` └── Status: ${
- isMatch ? '✅ Already painted → SKIP' : '🔴 Needs paint → PAINT'
- }\n`
+ ` ├── Current color: rgb(${tilePixelRGBA.slice(0, 3).join(', ')}) (id: ${mappedCanvasColor.id})\n` +
+ ` ├── Target color: rgb(${targetPixelInfo.r}, ${targetPixelInfo.g}, ${targetPixelInfo.b}) (id: ${targetMappedColorId})\n` +
+ ` └── Status: ${isMatch ? '✅ Already painted → SKIP' : '🔴 Needs paint → PAINT'
+ }\n`
);
}
} catch (e) {
@@ -7310,12 +7343,11 @@
console.log(` Skipped - Already painted: ${skippedPixels.alreadyPainted}`);
console.log(` Skipped - Color Unavailable: ${skippedPixels.colorUnavailable}`);
console.log(
- ` Total processed: ${
- state.paintedPixels +
- skippedPixels.transparent +
- skippedPixels.white +
- skippedPixels.alreadyPainted +
- skippedPixels.colorUnavailable
+ ` Total processed: ${state.paintedPixels +
+ skippedPixels.transparent +
+ skippedPixels.white +
+ skippedPixels.alreadyPainted +
+ skippedPixels.colorUnavailable
}`
);
@@ -7420,11 +7452,11 @@
}
try {
- const payload = { coords, colors, t: token };
-
+ const payload = { coords, colors, t: token, fp: fpStr32 };
+ var wasmtoken = await createWasmToken(regionX, regionY, payload);
const res = await fetch(`https://backend.wplace.live/s0/pixel/${regionX}/${regionY}`, {
method: 'POST',
- headers: { 'Content-Type': 'text/plain;charset=UTF-8' },
+ headers: { 'Content-Type': 'text/plain;charset=UTF-8', "x-pawtect-token": wasmtoken },
credentials: 'include',
body: JSON.stringify(payload),
});
@@ -7433,7 +7465,7 @@
let data = null;
try {
data = await res.json();
- } catch (_) {}
+ } catch (_) { }
console.error('❌ 403 Forbidden. Turnstile token might be invalid or expired.');
// Try to generate a new token and retry once
@@ -7443,12 +7475,13 @@
turnstileToken = token;
// Retry the request with new token
- const retryPayload = { coords, colors, t: token };
+ const retryPayload = { coords, colors, t: token, fp: fpStr32 };
+ var wasmtoken = await createWasmToken(regionX, regionY, retryPayload);
const retryRes = await fetch(
`https://backend.wplace.live/s0/pixel/${regionX}/${regionY}`,
{
method: 'POST',
- headers: { 'Content-Type': 'text/plain;charset=UTF-8' },
+ headers: { 'Content-Type': 'text/plain;charset=UTF-8', "x-pawtect-token": wasmtoken },
credentials: 'include',
body: JSON.stringify(retryPayload),
}
@@ -7512,13 +7545,13 @@
blockHeight: state.blockHeight, // Save ignore mask (as base64) with its dimensions
resizeIgnoreMask:
state.resizeIgnoreMask &&
- state.resizeSettings &&
- state.resizeSettings.width * state.resizeSettings.height === state.resizeIgnoreMask.length
+ state.resizeSettings &&
+ state.resizeSettings.width * state.resizeSettings.height === state.resizeIgnoreMask.length
? {
- w: state.resizeSettings.width,
- h: state.resizeSettings.height,
- data: btoa(String.fromCharCode(...state.resizeIgnoreMask)),
- }
+ w: state.resizeSettings.width,
+ h: state.resizeSettings.height,
+ data: btoa(String.fromCharCode(...state.resizeIgnoreMask)),
+ }
: null, // Notifications
notificationsEnabled: state.notificationsEnabled,
notifyOnChargesReached: state.notifyOnChargesReached,
@@ -7816,6 +7849,164 @@
// Load theme preference immediately on startup before creating UI
loadThemePreference();
applyTheme();
+ const isExactlyEqual = (a, b) => a?.[Object.keys(a)[0]]?.variant === b?.[Object.keys(b)[0]]?.variant;
+ var pawtect_chunk = null;
+
+ //find module if pawtect_chunk is null
+ pawtect_chunk ??= await findTokenModule("pawtect_wasm_bg.wasm");
+
+ async function createWasmToken(regionX, regionY, payload) {
+ try {
+ // Load the Pawtect module and WASM
+ const mod = await import(new URL('/_app/immutable/chunks/' + pawtect_chunk, location.origin).href);
+ let wasm;
+ try {
+ wasm = await mod._();
+ console.log('✅ WASM initialized successfully');
+ } catch (wasmError) {
+ console.error('❌ WASM initialization failed:', wasmError);
+ return null;
+ }
+ try {
+ try {
+ const me = await fetch(`https://backend.wplace.live/me`, { credentials: 'include' }).then(r => r.ok ? r.json() : null);
+ if (me?.id) {
+ mod.i(me.id);
+ console.log('✅ user ID set:', me.id);
+ }
+ if (me?.experiments) {
+ if (state.experiments == null) {
+ var item = Object.keys(me.experiments).find((v, _, __) => v.contains("pawtect")) ?? null;
+ if (item) {
+ if (me.experiments[item]?.variant && typeof (me.experiments[item]?.variant) === "string") {
+ localStorage.setItem("exp_wbot", me.experiments);
+ }
+ }
+ }
+ else {
+ var item = Object.keys(me.experiments).find((v, _, __) => v.contains("pawtect")) ?? null;
+ if (item) {
+ if (!isExactlyEqual(state.experiments, me.experiments)) {
+ alert("WPlace updated their PAWTECT Variant! REPORT TO WPLACE BOT DEVELOPERS")
+ }
+ }
+ }
+ }
+ } catch { }
+ } catch (userIdError) {
+ console.log('⚠️ Error setting user ID:', userIdError.message);
+ }
+ try {
+ const testUrl = `https://backend.wplace.live/s0/pixel/${regionX}/${regionY}`;
+ if (mod.r) {
+ mod.r(testUrl);
+ console.log('✅ Request URL set:', testUrl);
+ } else {
+ console.log('⚠️ request_url function (mod.r) not available');
+ }
+ } catch (urlError) {
+ console.log('⚠️ Error setting request URL:', urlError.message);
+ }
+
+ // Create test payload
+
+ console.log('📝 payload:', payload);
+
+ // Encode payload
+ const enc = new TextEncoder();
+ const dec = new TextDecoder();
+ const bodyStr = JSON.stringify(payload);
+ const bytes = enc.encode(bodyStr);
+ console.log('📏 Payload size:', bytes.length, 'bytes');
+ console.log('📄 Payload string:', bodyStr);
+
+ // Allocate WASM memory with validation
+ let inPtr;
+ try {
+ if (!wasm.__wbindgen_malloc) {
+ console.error('❌ __wbindgen_malloc function not found');
+ return null;
+ }
+
+ inPtr = wasm.__wbindgen_malloc(bytes.length, 1);
+ console.log('✅ WASM memory allocated, pointer:', inPtr);
+
+ // Copy data to WASM memory
+ const wasmBuffer = new Uint8Array(wasm.memory.buffer, inPtr, bytes.length);
+ wasmBuffer.set(bytes);
+ console.log('✅ Data copied to WASM memory');
+ } catch (memError) {
+ console.error('❌ Memory allocation error:', memError);
+ return null;
+ }
+
+ // Call the WASM function
+ console.log('🚀 Calling get_pawtected_endpoint_payload...');
+ let outPtr, outLen, token;
+ try {
+ const result = wasm.get_pawtected_endpoint_payload(inPtr, bytes.length);
+ console.log('✅ Function called, result type:', typeof result, result);
+
+ if (Array.isArray(result) && result.length === 2) {
+ [outPtr, outLen] = result;
+ console.log('✅ Got output pointer:', outPtr, 'length:', outLen);
+
+ // Decode the result
+ const outputBuffer = new Uint8Array(wasm.memory.buffer, outPtr, outLen);
+ token = dec.decode(outputBuffer);
+ console.log('✅ Token decoded successfully');
+ } else {
+ console.error('❌ Unexpected function result format:', result);
+ return null;
+ }
+ } catch (funcError) {
+ console.error('❌ Function call error:', funcError);
+ console.error('Stack trace:', funcError.stack);
+ return null;
+ }
+
+ // Cleanup memory
+ try {
+ if (wasm.__wbindgen_free && outPtr && outLen) {
+ wasm.__wbindgen_free(outPtr, outLen, 1);
+ console.log('✅ Output memory freed');
+ }
+ if (wasm.__wbindgen_free && inPtr) {
+ wasm.__wbindgen_free(inPtr, bytes.length, 1);
+ console.log('✅ Input memory freed');
+ }
+ } catch (cleanupError) {
+ console.log('⚠️ Cleanup warning:', cleanupError.message);
+ }
+
+ // Display results
+ console.log('');
+ console.log('🎉 SUCCESS!');
+ console.log('🔑 Full token:');
+ console.log(token);
+ return token;
+ } catch (error) {
+ console.error('❌ Failed to generate fp parameter:', error);
+ return null;
+ }
+ }
+
+ async function findTokenModule(str) {
+ console.log('🔎 Searching for wasm Module...');
+ const links = Array.from(document.querySelectorAll('link[rel="modulepreload"][href$=".js"]'));
+
+ for (const link of links) {
+ try {
+ const url = new URL(link.getAttribute("href"), location.origin).href;
+ const code = await fetch(url).then(r => r.text());
+ if (code.includes(str)) {
+ console.log('✅ Found wasm Module...');
+ return url.split('/').pop();
+ }
+ } catch { }
+ }
+ console.error(`❌ Could not find Pawtect chunk: `, error);
+ }
createUI().then(() => {
// Generate token automatically after UI is ready
diff --git a/auto-image-styles.css b/auto-image-styles.css
index 95b1ffa8..12d2c092 100644
--- a/auto-image-styles.css
+++ b/auto-image-styles.css
@@ -10,6 +10,7 @@
/* Import theme files - classic is default */
@import url('https://wplace-autobot.github.io/WPlace-AutoBOT/main/themes/classic.css');
@import url('https://wplace-autobot.github.io/WPlace-AutoBOT/main/themes/classic-light.css');
+@import url('https://wplace-autobot.github.io/WPlace-AutoBOT/main/themes/acrylic.css');
@import url('https://wplace-autobot.github.io/WPlace-AutoBOT/main/themes/neon.css');
/* Default :root CSS variables for 100% classic theme compliance */
diff --git a/lang/de.json b/lang/de.json
new file mode 100644
index 00000000..b2d2f4bc
--- /dev/null
+++ b/lang/de.json
@@ -0,0 +1,74 @@
+{
+ "title": "WPlace Auto-Image",
+ "toggleOverlay": "Vorschau umschalten",
+ "scanColors": "Farben scannen",
+ "uploadImage": "Bild hochladen",
+ "resizeImage": "Bildgröße ändern",
+ "selectPosition": "Position wählen",
+ "startPainting": "Malen starten",
+ "stopPainting": "Malen stoppen",
+ "checkingColors": "🔍 Verfügbare Farben werden geprüft...",
+ "noColorsFound": "❌ Öffne die Farbpalette und versuche es erneut!",
+ "colorsFound": "✅ {count} verfügbare Farben gefunden. Bereit zum Hochladen.",
+ "loadingImage": "🖼️ Bild wird geladen...",
+ "imageLoaded": "✅ Bild mit {count} gültigen Pixeln geladen",
+ "imageError": "❌ Fehler beim Laden des Bildes",
+ "selectPositionAlert": "Male den ersten Pixel an der Stelle, an der dein Kunstwerk beginnen soll!",
+ "waitingPosition": "👆 Warte, bis du den Referenzpixel malst...",
+ "positionSet": "✅ Position gefunden!",
+ "positionTimeout": "❌ Zeitüberschreitung bei der Positionswahl",
+ "startPaintingMsg": "🎨 Malvorgang wird gestartet...",
+ "paintingProgress": "🧱 Fortschritt: {painted}/{total} Pixel...",
+ "noCharges": "⌛ Keine Ladungen. Warte {time}...",
+ "paintingStopped": "⏹️ Malen vom Benutzer gestoppt",
+ "paintingComplete": "✅ Malvorgang abgeschlossen! {count} Pixel gemalt.",
+ "paintingError": "❌ Fehler während des Malens",
+ "missingRequirements": "❌ Lade zuerst ein Bild und wähle eine Position",
+ "progress": "Fortschritt",
+ "pixels": "Pixel",
+ "charges": "Ladungen",
+ "estimatedTime": "Geschätzte Zeit",
+ "initMessage": "Klicke auf 'Bild hochladen', um zu beginnen",
+ "waitingInit": "Warte auf Initialisierung...",
+ "initializingToken": "🔧 Turnstile-Token-Generator wird initialisiert...",
+ "tokenReady": "✅ Token-Generator bereit - du kannst jetzt malen!",
+ "tokenRetryLater": "⚠️ Token-Generator versucht es später erneut",
+ "resizeSuccess": "✅ Bildgröße auf {width}x{height} geändert",
+ "paintingPaused": "⏸️ Malen pausiert bei X: {x}, Y: {y}",
+ "captchaNeeded": "❗ Token-Generierung fehlgeschlagen. Bitte später erneut versuchen.",
+ "saveData": "Fortschritt speichern",
+ "loadData": "Fortschritt laden",
+ "saveToFile": "In Datei speichern",
+ "loadFromFile": "Aus Datei laden",
+ "dataManager": "Datenverwaltung",
+ "autoSaved": "✅ Fortschritt automatisch gespeichert",
+ "dataLoaded": "✅ Fortschritt erfolgreich geladen",
+ "fileSaved": "✅ Fortschritt erfolgreich in Datei gespeichert",
+ "fileLoaded": "✅ Fortschritt erfolgreich aus Datei geladen",
+ "noSavedData": "❌ Kein gespeicherter Fortschritt gefunden",
+ "savedDataFound": "✅ Gespeicherter Fortschritt gefunden! Laden, um fortzufahren?",
+ "savedDate": "Gespeichert am: {date}",
+ "clickLoadToContinue": "Klicke auf 'Fortschritt laden', um fortzufahren.",
+ "fileError": "❌ Fehler bei der Dateiverarbeitung",
+ "invalidFileFormat": "❌ Ungültiges Dateiformat",
+ "paintingSpeed": "Malgeschwindigkeit",
+ "pixelsPerSecond": "Pixel/Sekunde",
+ "speedSetting": "Geschwindigkeit: {speed} Pixel/Sek",
+ "settings": "Einstellungen",
+ "botSettings": "Bot-Einstellungen",
+ "close": "Schließen",
+ "language": "Sprache",
+ "themeSettings": "Design-Einstellungen",
+ "themeSettingsDesc": "Wähle dein bevorzugtes Design für die Oberfläche.",
+ "languageSelectDesc": "Wähle deine bevorzugte Sprache. Änderungen wirken sofort.",
+ "autoCaptcha": "Auto-CAPTCHA Löser (Turnstile)",
+ "autoCaptchaDesc": "Generiert Turnstile-Tokens automatisch über integrierten Generator. Fällt auf Browser-Automatisierung zurück, falls nötig.",
+ "applySettings": "Einstellungen anwenden",
+ "settingsSaved": "✅ Einstellungen erfolgreich gespeichert!",
+ "cooldownSettings": "Abkühl-Einstellungen",
+ "waitCharges": "Warte bis Ladungen erreichen",
+ "captchaSolving": "🔑 Generiere Turnstile-Token...",
+ "captchaFailed": "❌ Turnstile-Token-Generierung fehlgeschlagen. Versuche Fallback-Methode...",
+ "automation": "Automatisierung",
+ "noChargesThreshold": "⌛ Warte bis {threshold} Ladungen erreicht sind. Aktuell {current}. Nächste in {time}..."
+}
\ No newline at end of file
diff --git a/splitProgressScript.js b/splitProgressScript.js
new file mode 100644
index 00000000..746c1cea
--- /dev/null
+++ b/splitProgressScript.js
@@ -0,0 +1,71 @@
+// Parse input JSON
+let e = await t.text();
+let s = JSON.parse(e);
+
+let { imageData: l } = s;
+let { pixels: r } = l;
+
+// Count total non-transparent pixels
+let a = 0;
+for (let i = 3; i < r.length; i += 4) {
+ if (r[i] > 0) a++;
+}
+
+let c = Math.floor(a / o);
+let x = [];
+
+// Split the work into "o" parts
+for (let part = 0; part < o; part++) {
+ // Deep clone the original object
+ let tClone = JSON.parse(JSON.stringify(s));
+ let lClone = [...r];
+
+ let i = 0;
+ for (let idx = 3; idx < lClone.length; idx += 4) {
+ if (r[idx] > 0) {
+ let inThisPart = (
+ part === 0
+ ? i < c
+ : part === o - 1
+ ? i >= part * c
+ : i >= part * c && i < (part + 1) * c
+ );
+
+ if (!inThisPart) {
+ lClone[idx] = 0;
+ }
+ i++;
+ }
+ }
+
+ // Replace pixels with modified clone
+ tClone.imageData.pixels = lClone;
+
+ // Count visible pixels for this part
+ let d = 0;
+ for (let idx = 3; idx < lClone.length; idx += 4) {
+ if (lClone[idx] > 0) d++;
+ }
+
+ // Add state
+ tClone.state = {
+ totalPixels: d,
+ paintedPixels: 0,
+ };
+
+ // Create downloadable JSON blob
+ let blob = new Blob([JSON.stringify(tClone, null, 2)], {
+ type: "application/json",
+ });
+ let url = URL.createObjectURL(blob);
+
+ // Push info to results
+ x.push({
+ botNumber: part + 1,
+ fileName: `wplace-bot-${part + 1}-progress.json`,
+ visiblePixels: d,
+ totalPixels: a,
+ paintablePixels: d,
+ downloadUrl: url,
+ });
+}
diff --git a/themes/acrylic.css b/themes/acrylic.css
new file mode 100644
index 00000000..fbf1afb9
--- /dev/null
+++ b/themes/acrylic.css
@@ -0,0 +1,603 @@
+/* WPlace Auto-Image Bot - Acrylic Theme */
+/* Beautiful theme with translucent blurred panels */
+
+@import url('https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap');
+
+@font-face {
+ font-family: 'Apple Color Emoji';
+ src: url('https://raw.githubusercontent.com/GORAlexComp/AppleColorEmojiFont/refs/heads/main/fonts/AppleColorEmoji.ttf');
+}
+
+/* Main Container */
+.wplace-theme-acrylic #wplace-image-bot-container {
+ background: var(--wplace-primary);
+ color: var(--wplace-text);
+ border-radius: var(--wplace-radius);
+ box-shadow: none;
+ backdrop-filter: var(--wplace-backdrop);
+ border: var(--wplace-border-width) var(--wplace-border-style)
+ var(--wplace-border-color);
+ min-width: 300px;
+}
+
+.wplace-theme-acrylic #wplace-image-bot-container * {
+ font-size: 15px;
+ line-height: normal;
+}
+
+.wplace-theme-acrylic .wplace-content {
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
+ padding: 10px;
+}
+
+#wplace-image-bot-container.wplace-dragging {
+ transition: none !important;
+ box-shadow: none !important;
+ transform: none !important;
+}
+
+/* Stats */
+.wplace-theme-acrylic #wplace-stats-container {
+ background: var(--wplace-primary);
+ color: var(--wplace-text);
+ border-radius: var(--wplace-radius);
+ box-shadow: none;
+ backdrop-filter: var(--wplace-backdrop);
+ border: var(--wplace-border-width) var(--wplace-border-style)
+ var(--wplace-border-color);
+}
+
+.wplace-theme-acrylic .wplace-stats {
+ margin-bottom: 0;
+}
+
+.wplace-theme-acrylic .wplace-colors-section {
+ border-top: none;
+ margin: 0;
+}
+
+/* Settings Container */
+.wplace-theme-acrylic #wplace-settings-container {
+ background: var(--wplace-primary) !important;
+ color: var(--wplace-text) !important;
+ border-radius: var(--wplace-radius) !important;
+ box-shadow: none !important;
+ backdrop-filter: var(--wplace-backdrop) !important;
+ border: var(--wplace-border-width) var(--wplace-border-style)
+ var(--wplace-border-color) !important;
+ max-width: 400px !important;
+}
+
+.wplace-theme-acrylic .wplace-settings-header {
+ background: transparent;
+ padding: 0;
+}
+
+.wplace-theme-acrylic .wplace-settings-header:hover {
+ background: transparent !important;
+}
+
+.wplace-theme-acrylic .wplace-settings-icon {
+ animation: none;
+ font-size: 15px;
+}
+
+.wplace-theme-acrylic .wplace-settings-content {
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
+}
+
+.wplace-theme-acrylic .wplace-settings-footer {
+ border-top: none;
+ padding: 10px;
+}
+
+.wplace-theme-acrylic .wplace-settings-section {
+ margin: 0;
+}
+
+.wplace-theme-acrylic .wplace-settings-section-wrapper,
+.wplace-theme-acrylic .wplace-overlay-wrapper,
+.wplace-theme-acrylic .wplace-batch-controls {
+ padding: 0 !important;
+ background: transparent !important;
+ border: none !important;
+}
+
+/* Headers */
+.wplace-theme-acrylic .wplace-header,
+.wplace-theme-acrylic .wplace-settings-title-wrapper {
+ height: 40px;
+ padding: 7px 7px 7px 10px;
+ font-weight: 600;
+ background: var(--wplace-accent);
+ color: var(--wplace-highlight);
+}
+
+.wplace-theme-acrylic .wplace-header span,
+.wplace-theme-acrylic .wplace-settings-title {
+ max-width: 150px;
+ font-size: 15px;
+ font-weight: 600;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.wplace-theme-acrylic .wplace-header-controls #compactBtn {
+ display: none;
+}
+
+.wplace-theme-acrylic .wplace-header-btn,
+.wplace-theme-acrylic .wplace-settings-close-btn {
+ background: #2e2e2e;
+ color: var(--wplace-highlight);
+ border: none;
+ font-size: 12px;
+ border-radius: 4px;
+ width: 24px;
+ height: 24px;
+}
+
+.wplace-theme-acrylic .wplace-header-btn i {
+ font-size: 12px !important;
+}
+
+.wplace-theme-acrylic .wplace-header-btn:hover,
+.wplace-theme-acrylic .wplace-settings-close-btn:hover {
+ background: transparent;
+ transform: none;
+}
+
+/* Sections */
+.wplace-theme-acrylic .wplace-section {
+ display: flex;
+ flex-direction: column;
+ gap: 8px;
+ background: transparent;
+ padding: 0;
+ border: none;
+ margin: 0;
+}
+
+.wplace-theme-acrylic .wplace-section-title {
+ color: var(--wplace-highlight);
+ text-transform: capitalize;
+ font-size: 13px;
+ font-weight: 600;
+ pointer-events: none;
+ letter-spacing: unset;
+}
+
+.wplace-theme-acrylic .wplace-section-title i {
+ display: none;
+}
+
+.wplace-theme-acrylic .wplace-status-section {
+ background: transparent;
+ padding: 0;
+ margin: 0;
+ border: none;
+ display: flex;
+ flex-direction: column;
+ gap: 8px;
+}
+
+/* Status Styling */
+.wplace-theme-acrylic .wplace-stats {
+ background: transparent;
+ padding: 0;
+ border: none;
+}
+
+.wplace-theme-acrylic .wplace-stat-value {
+ color: var(--wplace-highlight);
+}
+
+.wplace-theme-acrylic .wplace-status {
+ border-radius: var(--wplace-radius);
+ border: none;
+ box-shadow: none;
+ padding: 10px;
+ font-weight: 500;
+}
+
+.wplace-theme-acrylic .status-default {
+ background: color-mix(in srgb, white 15%, transparent) !important;
+}
+
+.wplace-theme-acrylic .status-success {
+ background: color-mix(in srgb, var(--wplace-success) 15%, transparent);
+ color: var(--wplace-success);
+}
+
+.wplace-theme-acrylic .status-error {
+ background: color-mix(in srgb, var(--wplace-error) 15%, transparent);
+ color: var(--wplace-error);
+}
+
+.wplace-theme-acrylic .status-warning {
+ background: color-mix(in srgb, var(--wplace-warning) 15%, transparent);
+ color: var(--wplace-warning);
+}
+
+/* Buttons */
+.wplace-theme-acrylic .wplace-btn {
+ border-radius: 8px;
+ border: none;
+ height: max-content;
+ padding: 10px;
+ gap: 5px;
+ flex-direction: column;
+ align-items: flex-start;
+ line-height: normal;
+ text-align: left;
+ font-size: 15px !important;
+ box-shadow: none;
+}
+
+.wplace-theme-acrylic .wplace-btn::before {
+ display: none;
+}
+
+.wplace-theme-acrylic .wplace-btn:disabled {
+ box-shadow: none !important;
+}
+
+.wplace-theme-acrylic .wplace-btn:hover:not(:disabled) {
+ transform: none;
+ animation: none;
+ box-shadow: none !important;
+ filter: brightness(0.9);
+}
+
+.wplace-theme-acrylic .wplace-btn-primary,
+.wplace-theme-acrylic .wplace-btn-upload {
+ background: white !important;
+ color: black !important;
+ border: none !important;
+}
+
+.wplace-theme-acrylic .wplace-btn-upload:hover:not(:disabled) {
+ background: revert !important;
+}
+
+.wplace-theme-acrylic .wplace-btn-secondary,
+.wplace-theme-acrylic .wplace-btn-select,
+.wplace-theme-acrylic .wplace-btn-file,
+.wplace-theme-acrylic .wplace-btn-overlay {
+ background: var(--wplace-secondary);
+}
+
+.wplace-theme-acrylic .wplace-btn-start {
+ background: var(--wplace-success);
+ color: white;
+}
+
+.wplace-theme-acrylic .wplace-btn-stop {
+ background: var(--wplace-error);
+ color: white;
+}
+
+.wplace-theme-acrylic .wplace-btn.active {
+ background: white;
+ color: black;
+ box-shadow: none !important;
+}
+
+.wplace-theme-acrylic .wplace-btn.active i {
+ filter: none;
+}
+
+.wplace-theme-acrylic .wplace-settings-apply-btn {
+ background: white;
+ color: black;
+ border-radius: 8px;
+}
+
+/* Compact Input Buttons */
+.wplace-theme-acrylic .wplace-input-btn-small,
+.wplace-theme-acrylic .wplace-input-btn-small:hover,
+.wplace-theme-acrylic .wplace-input-btn-small:active {
+ background: white;
+ color: black;
+ border: none;
+ transform: none;
+ border-radius: 4px;
+ box-shadow: none;
+ font-weight: 500;
+ width: 25px;
+ height: 25px;
+}
+
+/* Alerts */
+.wplace-theme-acrylic .wplace-alert-base {
+ border-radius: var(--wplace-radius);
+ backdrop-filter: var(--wplace-backdrop);
+ border: none;
+ box-shadow: none;
+}
+
+.wplace-theme-acrylic .wplace-alert-info {
+ background: color-mix(in srgb, #0000e5 50%, transparent);
+}
+
+.wplace-theme-acrylic .wplace-alert-success {
+ background: color-mix(in srgb, var(--wplace-success) 50%, transparent);
+}
+
+.wplace-theme-acrylic .wplace-alert-error {
+ background: color-mix(in srgb, var(--wplace-error) 50%, transparent);
+}
+
+.wplace-theme-acrylic .wplace-alert-warning {
+ background: color-mix(in srgb, var(--wplace-warning) 50%, transparent);
+}
+
+/* Progress Bar */
+.wplace-theme-acrylic .wplace-progress {
+ background: var(--wplace-secondary);
+ border-radius: 4px;
+ margin: 0;
+ border: none;
+}
+
+.wplace-theme-acrylic .wplace-progress-bar {
+ background: white;
+}
+
+.wplace-theme-acrylic .wplace-progress-bar::after {
+ display: none;
+}
+
+/* Form Controls */
+.wplace-theme-acrylic .wplace-settings-checkbox,
+.wplace-theme-acrylic .wplace-notification-checkbox,
+.wplace-theme-acrylic .wplace-speed-checkbox {
+ cursor: pointer;
+ width: 20px;
+ height: 20px;
+ flex-shrink: 0;
+ accent-color: var(--wplace-highlight);
+}
+
+.wplace-theme-acrylic .wplace-settings-select,
+.wplace-theme-acrylic .wplace-settings-number-input,
+.wplace-theme-acrylic .wplace-cooldown-input,
+.wplace-theme-acrylic .wplace-notification-interval-input {
+ background: rgb(255 255 255 / 10%);
+ color: white;
+ border: 1px solid rgb(255 255 255 / 25%);
+ border-radius: 8px;
+ box-shadow: none;
+ transition-duration: 0.3s;
+}
+
+.wplace-theme-acrylic .wplace-settings-select:hover,
+.wplace-theme-acrylic .wplace-settings-number-input:hover,
+.wplace-theme-acrylic .wplace-cooldown-input:hover,
+.wplace-theme-acrylic .wplace-notification-interval-input:hover {
+ border-color: rgb(255 255 255 / 50%);
+}
+
+.wplace-theme-acrylic .wplace-settings-select:focus,
+.wplace-theme-acrylic .wplace-settings-number-input:focus,
+.wplace-theme-acrylic .wplace-cooldown-input:focus,
+.wplace-theme-acrylic .wplace-notification-interval-input:focus {
+ border-color: white;
+}
+
+.wplace-theme-acrylic .wplace-settings-option {
+ background: #2d3748;
+ color: white;
+}
+
+.wplace-theme-acrylic .wplace-settings-select option {
+ background: #2d3748;
+ color: white;
+}
+
+.wplace-theme-acrylic .wplace-cooldown-input {
+ border-radius: 4px !important;
+}
+
+.wplace-theme-acrylic .wplace-cooldown-input:focus {
+ background: rgb(255 255 255 / 10%);
+ box-shadow: none;
+}
+
+.wplace-theme-acrylic .wplace-overlay-opacity-value {
+ background-color: var(--wplace-secondary) !important;
+ border: none !important;
+}
+
+/* Sliders */
+.wplace-theme-acrylic .wplace-slider,
+.wplace-theme-acrylic .wplace-speed-slider,
+.wplace-theme-acrylic .wplace-overlay-opacity-slider {
+ background: var(--wplace-secondary) !important;
+ border-radius: 3px !important;
+ height: 6px !important;
+}
+
+.wplace-theme-acrylic .wplace-slider::-webkit-slider-thumb,
+.wplace-theme-acrylic .resize-slider::-webkit-slider-thumb,
+.wplace-theme-acrylic .wplace-speed-slider::-webkit-slider-thumb,
+.wplace-theme-acrylic .wplace-overlay-opacity-slider::-webkit-slider-thumb {
+ width: 16px !important;
+ height: 16px !important;
+ border-radius: 4px !important;
+ background: white !important;
+ box-shadow: none !important;
+ transform: none !important;
+}
+
+.wplace-theme-acrylic .wplace-speed-value {
+ background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
+ border-radius: 8px;
+ color: white;
+ box-shadow: 0 3px 10px rgb(79 172 254 / 30%);
+ border: 1px solid rgb(255 255 255 / 20%);
+}
+
+.wplace-theme-acrylic .resize-slider {
+ -webkit-appearance: revert;
+}
+
+/* Layout Controls */
+.wplace-theme-acrylic .wplace-slider-container {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ gap: 8px;
+ margin: 0;
+}
+
+.wplace-theme-acrylic .wplace-input-label-compact {
+ color: rgba(255, 255, 255, 0.75);
+ margin-left: 4px;
+ text-transform: lowercase;
+ white-space: nowrap;
+}
+
+.wplace-theme-acrylic .wplace-cooldown-control {
+ margin: 0;
+ display: flex;
+ flex-direction: column;
+ gap: 8px;
+}
+
+.wplace-theme-acrylic .wplace-cooldown-control label {
+ font-weight: 400;
+ margin-bottom: 0;
+ display: block;
+}
+
+.wplace-theme-acrylic .wplace-cooldown-input-group {
+ margin: 0;
+ background: transparent;
+}
+
+/* Color Elements */
+.wplace-theme-acrylic .wplace-color-item-name {
+ color: #ccc;
+}
+
+.wplace-theme-acrylic .wplace-color-swatch {
+ border: 1px solid rgb(255 255 255 / 20%);
+ border-radius: 4px;
+}
+
+.wplace-theme-acrylic .wplace-color-swatch:not(.active) {
+ filter: grayscale(80%);
+}
+
+.wplace-theme-acrylic .wplace-color-swatch.unavailable {
+ border-color: #666;
+}
+
+.wplace-theme-acrylic .wplace-color-swatch.unavailable:not(.active) {
+ filter: grayscale(90%);
+}
+
+.wplace-theme-acrylic .wplace-color-swatch.active::after {
+ text-shadow: 0 0 3px black;
+}
+
+.wplace-theme-acrylic .wplace-stat-color-swatch {
+ border-radius: 3px;
+ border: 1px solid rgb(255 255 255 / 10%);
+ box-shadow: inset 0 0 2px rgb(0 0 0 / 50%);
+}
+
+.wplace-theme-acrylic .wplace-stat-colors-grid {
+ background: var(--wplace-secondary);
+ border-radius: 8px;
+}
+
+.wplace-theme-acrylic .wplace-color-divider {
+ background: rgb(255 255 255 / 10%);
+}
+
+/* Icons */
+.wplace-theme-acrylic .wplace-icon-key,
+.wplace-theme-acrylic .wplace-icon-robot,
+.wplace-theme-acrylic .wplace-icon-speed,
+.wplace-theme-acrylic .wplace-icon-bell,
+.wplace-theme-acrylic .wplace-icon-palette,
+.wplace-theme-acrylic .wplace-icon-globe,
+.wplace-theme-acrylic .wplace-icon-paint,
+.wplace-theme-acrylic .wplace-icon-eye,
+.wplace-theme-acrylic .wplace-icon-compass,
+.wplace-theme-acrylic .wplace-icon-route,
+.wplace-theme-acrylic .wplace-icon-table,
+.wplace-theme-acrylic .wplace-icon-dice {
+ color: white;
+}
+
+/* Typography */
+.wplace-theme-acrylic .wplace-cooldown-unit {
+ display: none;
+}
+
+.wplace-theme-acrylic .wplace-settings-toggle-title,
+.wplace-theme-acrylic .wplace-overlay-opacity-label {
+ font-size: 15px !important;
+}
+
+.wplace-theme-acrylic .wplace-settings-description,
+.wplace-theme-acrylic .wplace-random-batch-description,
+.wplace-theme-acrylic .wplace-settings-toggle-description {
+ font-size: 12px;
+ color: rgb(255 255 255 / 75%) !important;
+}
+
+/* Turnstile Overlay */
+.wplace-theme-acrylic .wplace-turnstile-overlay {
+ background: var(--wplace-primary);
+ border-radius: var(--wplace-radius);
+ box-shadow: none;
+ backdrop-filter: var(--wplace-backdrop);
+ border: none;
+ padding: 16px !important;
+ color: var(--wplace-text) !important;
+}
+
+.wplace-theme-acrylic .wplace-turnstile-hide-btn {
+ border-radius: 8px !important;
+ backdrop-filter: var(--wplace-backdrop) !important;
+ background: var(--wplace-primary) !important;
+ top: -25px !important;
+ right: 0 !important;
+ transition: all 0.3s ease !important;
+}
+
+.wplace-theme-acrylic .wplace-turnstile-hide-btn:hover {
+ background: white !important;
+ color: black !important;
+}
+
+/* Resize Tools */
+.wplace-theme-acrylic .resize-tools button {
+ border-radius: 6px;
+ border: 1px solid rgb(255 255 255 / 20%);
+ background: rgb(255 255 255 / 6%);
+ color: #fff;
+}
+
+.wplace-theme-acrylic .resize-overlay {
+ background: rgb(0 0 0 / 50%);
+}
+
+/* TODO: More resize menu styles */
+.wplace-theme-acrylic .resize-container {
+ background: var(--wplace-secondary);
+ backdrop-filter: var(--wplace-backdrop);
+ border: none;
+ border-radius: var(--wplace-radius);
+ color: var(--wplace-text);
+}