From a17146fee9503a88266176567c535340509ee51d Mon Sep 17 00:00:00 2001
From: Wizzard <rich@bandaholics.cash>
Date: Mon, 17 Mar 2025 17:48:25 -0400
Subject: [PATCH] Add: Slider customization & fix black spots showing up on map

---
 webradar/index.html |  23 ++-
 webradar/script.js  | 415 +++++++++++++++++++++++++++++---------------
 webradar/styles.css | 147 +++++++++++++---
 3 files changed, 420 insertions(+), 165 deletions(-)

diff --git a/webradar/index.html b/webradar/index.html
index 0978c50..2583c52 100644
--- a/webradar/index.html
+++ b/webradar/index.html
@@ -50,6 +50,12 @@
                 <div>
                     <input type="checkbox" onclick="toggleCentered()" id="centerCheck" name="center" checked />
                     <label for="centerCheck">Player Centered</label>
+                    <div id="zoomLevelContainer" style="margin-top: 5px; margin-left: 20px; display: none;">
+                        <label for="zoomLevelSlider">Zoom Level: </label>
+                        <span id="zoomLevelValue">1.0</span><br>
+                        <input type="range" id="zoomLevelSlider" min="1.0" max="5.0" step="0.1" value="1.0"
+                            style="width: 100%; margin: 5px 0;" oninput="updateZoomLevel(this.value)">
+                    </div>
                 </div>
                 <div class="player-focus">
                     <label for="playerSelect">Focus Player:</label>
@@ -57,6 +63,21 @@
                         <option value="local">YOU</option>
                     </select>
                 </div>
+                <div id="sizeControlsContainer"
+                    style="margin-top: 10px; padding: 5px; border-top: 1px solid rgba(255, 255, 255, 0.2);">
+                    <div class="size-control" style="margin-bottom: 8px;">
+                        <label for="textSizeSlider">Text Size: </label>
+                        <span id="textSizeValue">1.0</span><br>
+                        <input type="range" id="textSizeSlider" min="0.1" max="2.0" step="0.1" value="1.0"
+                            style="width: 100%; margin: 5px 0;" oninput="updateTextSize(this.value)">
+                    </div>
+                    <div class="size-control">
+                        <label for="entitySizeSlider">Player Size: </label>
+                        <span id="entitySizeValue">1.0</span><br>
+                        <input type="range" id="entitySizeSlider" min="0.5" max="2.0" step="0.1" value="1.0"
+                            style="width: 100%; margin: 5px 0;" oninput="updateEntitySize(this.value)">
+                    </div>
+                </div>
                 <button id="showDangerousBtn" onclick="toggleDangerousOptions()">Show Dangerous Options</button>
                 <div class="dangerous-options" id="dangerousOptions">
                     <div>
@@ -71,6 +92,6 @@
     </div>
     <script src="script.js"></script>
     <script src="webstuff.js"></script>
-
 </body>
+
 </html>
\ No newline at end of file
diff --git a/webradar/script.js b/webradar/script.js
index e522725..167c906 100644
--- a/webradar/script.js
+++ b/webradar/script.js
@@ -17,10 +17,23 @@ let drawNames = true;
 let drawGuns = true;
 let drawMoney = true;
 
+let canvasScale = 1;
+let minTextSize = 16;
+let minEntitySize = 10;
+let textSizeMultiplier = 1.0;
+let entitySizeMultiplier = 1.0;
+
+const DEFAULT_TEXT_SIZE = 0.4;
+const DEFAULT_ENTITY_SIZE = 1.2;
+const DEFAULT_ZOOM_LEVEL = 2.4;
+
 const NETWORK_SETTINGS = {
     useInterpolation: true,
     interpolationAmount: 0.6,
-    pingInterval: 3000
+    pingInterval: 3000,
+    maxRetries: 5,
+    requestTimeout: 5000,
+    reconnectDelay: 1000
 };
 
 let connectionHealthy = true;
@@ -40,7 +53,6 @@ let lastKnownPositions = {};
 let entityInterpolationData = {};
 let lastUpdateTime = 0;
 let networkLatencyHistory = [];
-let lastPingSent = 0;
 
 let focusedPlayerYaw = 0;
 let focusedPlayerName = "YOU";
@@ -231,6 +243,7 @@ function render() {
 
     renderFrame();
 }
+
 function sendRequest() {
     isRequestPending = true;
     pingTracker.startRequest();
@@ -280,7 +293,8 @@ function renderFrame() {
 
         drawBombTimer();
     } else if (!loaded) {
-        ctx.font = "40px Arial";
+        const fontSize = Math.max(40 * canvasScale, 16);
+        ctx.font = `${fontSize}px Arial`;
         ctx.textAlign = "center";
         ctx.textBaseline = "middle";
         ctx.fillStyle = textColor;
@@ -288,14 +302,15 @@ function renderFrame() {
     }
 
     if (drawStats) {
-        ctx.font = "16px Arial";
+        const fontSize = Math.max(16 * canvasScale, 12);
+        ctx.font = `${fontSize}px Arial`;
         ctx.textAlign = "left";
         ctx.fillStyle = "#00FF00";
         let rotationStatus = "Active";
         if (temporarilyDisableRotation) rotationStatus = "Manually Disabled";
         else if (rotationDisabledUntilRespawn) rotationStatus = "Disabled (Death)";
 
-        ctx.fillText(`${currentFps} FPS | ${freq} Hz | Ping: ${Math.round(pingTracker.getAveragePing())}ms | Rotation: ${rotationStatus}`, 10, 20);
+        ctx.fillText(`${currentFps} FPS | ${freq} Hz | Ping: ${Math.round(pingTracker.getAveragePing())}ms | Rotation: ${rotationStatus}`, 10, fontSize + 4);
     }
 }
 
@@ -361,43 +376,47 @@ function drawImage() {
 
     ctx.save();
 
-    const shouldRotate = rotateMap &&
+    if (playerCentered && focusedPlayerPos) {
+        if (playerCenteredZoom !== 1.0) {
+            ctx.translate(canvas.width / 2, canvas.height / 2);
+            ctx.scale(playerCenteredZoom, playerCenteredZoom);
+            ctx.translate(-canvas.width / 2, -canvas.height / 2);
+        }
+
+        if (rotateMap &&
+            focusedPlayerPos &&
+            !temporarilyDisableRotation &&
+            !rotationDisabledUntilRespawn) {
+
+            ctx.translate(canvas.width / 2, canvas.height / 2);
+            ctx.rotate(degreesToRadians(focusedPlayerYaw + 270));
+            ctx.translate(-canvas.width / 2, -canvas.height / 2);
+        }
+
+        const playerX = (focusedPlayerPos.x - map.pos_x) / map.scale;
+        const playerY = (focusedPlayerPos.y - map.pos_y) / -map.scale;
+
+        const playerCanvasX = (playerX / image.width) * canvas.width;
+        const playerCanvasY = (playerY / image.height) * canvas.height;
+
+        const translateX = (canvas.width / 2) - playerCanvasX;
+        const translateY = (canvas.height / 2) - playerCanvasY;
+
+        ctx.translate(translateX, translateY);
+    } else if (rotateMap &&
         focusedPlayerPos &&
         !temporarilyDisableRotation &&
-        !rotationDisabledUntilRespawn;
-
-    if (shouldRotate) {
+        !rotationDisabledUntilRespawn) {
         ctx.translate(canvas.width / 2, canvas.height / 2);
         ctx.rotate(degreesToRadians(focusedPlayerYaw + 270));
         ctx.translate(-canvas.width / 2, -canvas.height / 2);
     }
 
-    if (playerCentered && focusedPlayerPos) {
-        const playerX = (focusedPlayerPos.x - map.pos_x) / map.scale;
-        const playerY = (focusedPlayerPos.y - map.pos_y) / -map.scale;
-
-        const zoomLevel = 0.5;
-        const viewWidth = image.width * zoomLevel;
-        const viewHeight = image.height * zoomLevel;
-
-        ctx.drawImage(
-            image,
-            playerX - (viewWidth / 2), playerY - (viewHeight / 2), viewWidth, viewHeight,
-            0, 0, canvas.width, canvas.height
-        );
-    } else if (zoomSet && boundingRect?.x != null) {
-        ctx.drawImage(
-            image,
-            boundingRect.x, boundingRect.y, boundingRect.width, boundingRect.height,
-            0, 0, canvas.width, canvas.height
-        );
-    } else {
-        ctx.drawImage(
-            image,
-            0, 0, image.width, image.height,
-            0, 0, canvas.width, canvas.height
-        );
-    }
+    ctx.drawImage(
+        image,
+        0, 0, image.width, image.height,
+        0, 0, canvas.width, canvas.height
+    );
 
     ctx.restore();
 }
@@ -408,12 +427,119 @@ function toggleHealth() {
     localStorage.setItem('drawHealth', drawHealth ? 'true' : 'false');
 }
 
+function mapAndTransformCoordinates(pos) {
+    const canvasWidth = canvas.width;
+    const canvasHeight = canvas.height;
+    const imageWidth = image ? image.width : 1;
+    const imageHeight = image ? image.height : 1;
+
+    if (!map || !pos) return {
+        pos: { x: 0, y: 0 },
+        textSize: minTextSize * textSizeMultiplier
+    };
+
+    const posX = (pos.x - map.pos_x) / map.scale;
+    const posY = (pos.y - map.pos_y) / -map.scale;
+
+    let screenX = (posX / imageWidth) * canvasWidth;
+    let screenY = (posY / imageHeight) * canvasHeight;
+
+    if (playerCentered && focusedPlayerPos) {
+        const playerX = (focusedPlayerPos.x - map.pos_x) / map.scale;
+        const playerY = (focusedPlayerPos.y - map.pos_y) / -map.scale;
+
+        const playerRelX = playerX / imageWidth;
+        const playerRelY = playerY / imageHeight;
+
+        const centerX = canvasWidth / 2;
+        const centerY = canvasHeight / 2;
+
+        const playerScreenX = (playerX / imageWidth) * canvasWidth;
+        const playerScreenY = (playerY / imageHeight) * canvasHeight;
+
+        const deltaX = screenX - playerScreenX;
+        const deltaY = screenY - playerScreenY;
+
+        const zoomedDeltaX = deltaX * playerCenteredZoom;
+        const zoomedDeltaY = deltaY * playerCenteredZoom;
+
+        screenX = centerX + zoomedDeltaX;
+        screenY = centerY + zoomedDeltaY;
+
+        if (rotateMap &&
+            !temporarilyDisableRotation &&
+            !rotationDisabledUntilRespawn) {
+
+            const relX = screenX - centerX;
+            const relY = screenY - centerY;
+
+            const angle = degreesToRadians(focusedPlayerYaw + 270);
+            const cos = Math.cos(angle);
+            const sin = Math.sin(angle);
+
+            const rotX = relX * cos - relY * sin;
+            const rotY = relX * sin + relY * cos;
+
+            screenX = rotX + centerX;
+            screenY = rotY + centerY;
+        }
+    } else if (rotateMap &&
+        focusedPlayerPos &&
+        !temporarilyDisableRotation &&
+        !rotationDisabledUntilRespawn) {
+
+        const centerX = canvasWidth / 2;
+        const centerY = canvasHeight / 2;
+
+        const relX = screenX - centerX;
+        const relY = screenY - centerY;
+
+        const angle = degreesToRadians(focusedPlayerYaw + 270);
+        const cos = Math.cos(angle);
+        const sin = Math.sin(angle);
+
+        const rotX = relX * cos - relY * sin;
+        const rotY = relX * sin + relY * cos;
+
+        screenX = rotX + centerX;
+        screenY = rotY + centerY;
+    }
+
+    const finalTextSize = playerCentered ?
+        minTextSize * textSizeMultiplier * playerCenteredZoom :
+        minTextSize * textSizeMultiplier;
+
+    return {
+        pos: { x: screenX, y: screenY },
+        textSize: finalTextSize
+    };
+}
+
+function updateZoomLevel(value) {
+    playerCenteredZoom = parseFloat(value);
+    const valueDisplay = document.getElementById('zoomLevelValue');
+    if (valueDisplay) valueDisplay.textContent = value;
+    localStorage.setItem('playerCenteredZoom', value);
+}
+
+function toggleCentered() {
+    playerCentered = !playerCentered;
+    updateZoomSliderVisibility();
+}
+
+function updateZoomSliderVisibility() {
+    const zoomSliderContainer = document.getElementById('zoomLevelContainer');
+    if (zoomSliderContainer) {
+        zoomSliderContainer.style.display = playerCentered ? 'block' : 'none';
+    }
+}
+
 function drawPlayerHealth(pos, playerType, health, hasBomb) {
     if (!map) return;
 
     const transformed = mapAndTransformCoordinates(pos);
     const mapPos = transformed.pos;
-    const textSize = transformed.textSize * 0.8;
+    const textSize = transformed.textSize;
 
     let extraOffset = 0;
     if (drawNames) extraOffset += 15;
@@ -432,8 +558,9 @@ function drawPlayerHealth(pos, playerType, health, hasBomb) {
         healthColor = "#FF0000";
     }
 
-    const barWidth = 40;
-    const barHeight = 5;
+    const barWidth = Math.max(60, 40 * textSizeMultiplier);
+    const barHeight = Math.max(8, 5 * textSizeMultiplier);
+
     ctx.fillStyle = "#444444";
     ctx.fillRect(mapPos.x - barWidth / 2, textY, barWidth, barHeight);
 
@@ -441,15 +568,15 @@ function drawPlayerHealth(pos, playerType, health, hasBomb) {
     const healthWidth = (health / 100) * barWidth;
     ctx.fillRect(mapPos.x - barWidth / 2, textY, healthWidth, barHeight);
 
-    ctx.font = `${textSize}px Arial`;
+    ctx.font = `bold ${textSize}px Arial`;
     ctx.textAlign = "center";
     ctx.textBaseline = "top";
 
-    ctx.lineWidth = 2;
+    ctx.lineWidth = 3;
     ctx.strokeStyle = "black";
-    ctx.strokeText(`${health}HP`, mapPos.x, textY + barHeight + 1);
+    ctx.strokeText(`${health}HP`, mapPos.x, textY + barHeight + 2);
     ctx.fillStyle = healthColor;
-    ctx.fillText(`${health}HP`, mapPos.x, textY + barHeight + 1);
+    ctx.fillText(`${health}HP`, mapPos.x, textY + barHeight + 2);
 }
 
 function drawEntities() {
@@ -577,8 +704,12 @@ function drawBombTimer() {
     const maxWidth = 1024 - 128 - 128;
     const timeleft = radarData.bombDefuseTimeleft;
 
+    const timerHeight = Math.max(16, 10 * canvasScale);
+    const timerY = Math.max(16, 10 * canvasScale);
+    const fontSize = Math.max(24, 18 * canvasScale);
+
     ctx.fillStyle = "black";
-    ctx.fillRect(128, 16, maxWidth, 16);
+    ctx.fillRect(128, timerY, maxWidth, timerHeight);
 
     if (radarData.bombBeingDefused) {
         ctx.fillStyle = radarData.bombCanDefuse ? teamColor : enemyColor;
@@ -586,32 +717,32 @@ function drawBombTimer() {
         ctx.fillStyle = bombColor;
     }
 
-    ctx.fillRect(130, 18, (maxWidth - 2) * (timeleft / 40), 12);
+    ctx.fillRect(130, timerY + 2, (maxWidth - 2) * (timeleft / 40), timerHeight - 4);
 
-    ctx.font = "24px Arial";
+    ctx.font = `bold ${fontSize}px Arial`;
     ctx.textAlign = "center";
     ctx.textBaseline = "middle";
     ctx.fillStyle = textColor;
-    ctx.fillText(`${timeleft.toFixed(1)}s`, 1024 / 2, 28 + 24);
+    ctx.fillText(`${timeleft.toFixed(1)}s`, 1024 / 2, timerY + timerHeight + fontSize / 2 + 4);
 
     ctx.strokeStyle = "black";
     ctx.lineWidth = 2;
 
     ctx.beginPath();
-    ctx.moveTo(128 + (maxWidth * (5 / 40)), 16);
-    ctx.lineTo(128 + (maxWidth * (5 / 40)), 32);
+    ctx.moveTo(128 + (maxWidth * (5 / 40)), timerY);
+    ctx.lineTo(128 + (maxWidth * (5 / 40)), timerY + timerHeight);
     ctx.stroke();
 
     ctx.beginPath();
-    ctx.moveTo(130 + (maxWidth - 2) * (10 / 40), 16);
-    ctx.lineTo(130 + (maxWidth - 2) * (10 / 40), 32);
+    ctx.moveTo(130 + (maxWidth - 2) * (10 / 40), timerY);
+    ctx.lineTo(130 + (maxWidth - 2) * (10 / 40), timerY + timerHeight);
     ctx.stroke();
 
     if (radarData.bombCanDefuse) {
         ctx.strokeStyle = "green";
         ctx.beginPath();
-        ctx.moveTo(130 + (maxWidth - 2) * (radarData.bombDefuseEnd / 40), 16);
-        ctx.lineTo(130 + (maxWidth - 2) * (radarData.bombDefuseEnd / 40), 32);
+        ctx.moveTo(130 + (maxWidth - 2) * (radarData.bombDefuseEnd / 40), timerY);
+        ctx.lineTo(130 + (maxWidth - 2) * (radarData.bombDefuseEnd / 40), timerY + timerHeight);
         ctx.stroke();
     }
 }
@@ -670,79 +801,6 @@ function mapCoordinates(coordinates) {
     return { x: offset_x, y: offset_y };
 }
 
-function mapAndTransformCoordinates(pos) {
-    const canvasWidth = canvas.width;
-    const canvasHeight = canvas.height;
-    const imageWidth = image ? image.width : 1;
-    const imageHeight = image ? image.height : 1;
-
-    if (!map || !pos) return { pos: { x: 0, y: 0 }, textSize: 12 };
-
-    const offset_x = (pos.x - map.pos_x) / map.scale;
-    const offset_y = (pos.y - map.pos_y) / -map.scale;
-
-    let mapPos = { x: offset_x, y: offset_y };
-    let textSize = 12;
-
-    if (zoomSet && boundingRect && boundingRect.x != null) {
-        const xScale = boundingRect.width / imageWidth;
-        const yScale = boundingRect.height / imageHeight;
-        mapPos = {
-            x: (mapPos.x - boundingRect.x) / xScale,
-            y: (mapPos.y - boundingRect.y) / yScale
-        };
-        textSize = (imageWidth / boundingRect.width) * 12;
-    }
-    else if (playerCentered && focusedPlayerPos) {
-        const zoomLevel = 0.5;
-        const viewWidth = imageWidth * zoomLevel;
-        const viewHeight = imageHeight * zoomLevel;
-
-        let playerMapPos;
-        if (focusedPlayerName === "YOU" && localPlayerPos) {
-            const lpx = (localPlayerPos.x - map.pos_x) / map.scale;
-            const lpy = (localPlayerPos.y - map.pos_y) / -map.scale;
-            playerMapPos = { x: lpx, y: lpy };
-        } else if (focusedPlayerPos) {
-            const fpx = (focusedPlayerPos.x - map.pos_x) / map.scale;
-            const fpy = (focusedPlayerPos.y - map.pos_y) / -map.scale;
-            playerMapPos = { x: fpx, y: fpy };
-        } else {
-            playerMapPos = { x: 0, y: 0 };
-        }
-
-        mapPos.x = (mapPos.x - (playerMapPos.x - viewWidth / 2)) * canvasWidth / viewWidth;
-        mapPos.y = (mapPos.y - (playerMapPos.y - viewHeight / 2)) * canvasHeight / viewHeight;
-    }
-    else {
-        mapPos.x = mapPos.x * canvasWidth / imageWidth;
-        mapPos.y = mapPos.y * canvasHeight / imageHeight;
-    }
-
-    const shouldRotate = rotateMap &&
-        typeof focusedPlayerYaw === 'number' &&
-        !temporarilyDisableRotation &&
-        !rotationDisabledUntilRespawn;
-
-    if (shouldRotate) {
-        const canvasCenter = { x: canvasWidth / 2, y: canvasHeight / 2 };
-        const rotationYaw = focusedPlayerName === "YOU" ? localYaw : focusedPlayerYaw;
-        const angle = rotationYaw + 270;
-
-        const radians = angle * (Math.PI / 180);
-        const cos = Math.cos(radians);
-        const sin = Math.sin(radians);
-
-        const nx = mapPos.x - canvasCenter.x;
-        const ny = mapPos.y - canvasCenter.y;
-
-        mapPos.x = nx * cos - ny * sin + canvasCenter.x;
-        mapPos.y = nx * sin + ny * cos + canvasCenter.y;
-    }
-
-    return { pos: mapPos, textSize: textSize };
-}
-
 function drawPlayerName(pos, playerName, playerType, hasAwp, hasBomb, isScoped) {
     if (!map) return;
 
@@ -766,11 +824,11 @@ function drawPlayerName(pos, playerName, playerType, hasAwp, hasBomb, isScoped)
         displayName += " [SCOPED]";
     }
 
-    ctx.font = `${textSize}px Arial`;
+    ctx.font = `bold ${textSize}px Arial`;
     ctx.textAlign = "center";
     ctx.textBaseline = "top";
 
-    ctx.lineWidth = 2;
+    ctx.lineWidth = 3;
     ctx.strokeStyle = "black";
     ctx.strokeText(displayName, mapPos.x, textY);
     ctx.fillText(displayName, mapPos.x, textY);
@@ -800,11 +858,11 @@ function drawPlayerMoney(pos, playerType, money, hasBomb) {
         ctx.fillStyle = "#FF4500";
     }
 
-    ctx.font = `${textSize}px Arial`;
+    ctx.font = `bold ${textSize}px Arial`;
     ctx.textAlign = "center";
     ctx.textBaseline = "top";
 
-    ctx.lineWidth = 2;
+    ctx.lineWidth = 3;
     ctx.strokeStyle = "black";
     ctx.strokeText(formattedMoney, mapPos.x, textY);
     ctx.fillText(formattedMoney, mapPos.x, textY);
@@ -827,11 +885,11 @@ function drawPlayerWeapon(pos, playerType, weaponId) {
         ctx.fillStyle = textColor;
     }
 
-    ctx.font = `${textSize}px Arial`;
+    ctx.font = `bold ${textSize}px Arial`;
     ctx.textAlign = "center";
     ctx.textBaseline = "top";
 
-    ctx.lineWidth = 2;
+    ctx.lineWidth = 3;
     ctx.strokeStyle = "black";
     ctx.strokeText(`[${weaponName}]`, mapPos.x, textY);
     ctx.fillText(`[${weaponName}]`, mapPos.x, textY);
@@ -847,11 +905,11 @@ function drawPlayerBomb(pos, playerType) {
     const textY = mapPos.y + (drawNames ? (drawGuns ? 50 : 35) : (drawGuns ? 35 : 20));
 
     ctx.fillStyle = bombColor;
-    ctx.font = `${textSize}px Arial`;
+    ctx.font = `bold ${textSize}px Arial`;
     ctx.textAlign = "center";
     ctx.textBaseline = "top";
 
-    ctx.lineWidth = 2;
+    ctx.lineWidth = 3;
     ctx.strokeStyle = "black";
     ctx.strokeText("[C4]", mapPos.x, textY);
     ctx.fillText("[C4]", mapPos.x, textY);
@@ -862,18 +920,18 @@ function drawBomb(pos, planted) {
 
     const transformed = mapAndTransformCoordinates(pos);
     const mapPos = transformed.pos;
-    const size = transformed.textSize * 0.7;
+    const size = minEntitySize * entitySizeMultiplier;
 
     ctx.beginPath();
     ctx.arc(mapPos.x, mapPos.y, size, 0, 2 * Math.PI);
     ctx.fillStyle = bombColor;
     ctx.fill();
 
-    ctx.lineWidth = 2;
+    ctx.lineWidth = 3;
     ctx.strokeStyle = "black";
     ctx.stroke();
 
-    ctx.font = size * 1.2 + "px Arial";
+    ctx.font = `bold ${Math.max(size * 1.2, minTextSize)}px Arial`;
     ctx.textAlign = "center";
     ctx.textBaseline = "middle";
     ctx.fillStyle = "white";
@@ -895,7 +953,8 @@ function drawEntity(pos, fillStyle, dormant, hasBomb, yaw, hasAwp, playerType, i
 
     const transformed = mapAndTransformCoordinates(pos);
     const mapPos = transformed.pos;
-    let circleRadius = transformed.textSize * 0.6;
+
+    let circleRadius = minEntitySize * entitySizeMultiplier;
     const distance = circleRadius + 2;
     const radius = distance + 5;
     const arrowWidth = 35;
@@ -918,7 +977,7 @@ function drawEntity(pos, fillStyle, dormant, hasBomb, yaw, hasAwp, playerType, i
     }
 
     if (dormant) {
-        ctx.font = "20px Arial";
+        ctx.font = `bold ${transformed.textSize}px Arial`;
         ctx.textAlign = "center";
         ctx.fillStyle = fillStyle;
         ctx.fillText("?", mapPos.x, mapPos.y);
@@ -977,7 +1036,7 @@ function drawEntity(pos, fillStyle, dormant, hasBomb, yaw, hasAwp, playerType, i
             ctx.lineTo(lineOfSightX, lineOfSightY);
 
             ctx.strokeStyle = playerType == "Enemy" ? enemyColor : teamColor;
-            ctx.lineWidth = 1;
+            ctx.lineWidth = 2;
             ctx.stroke();
         }
     }
@@ -1198,6 +1257,34 @@ function connect() {
     }
 }
 
+function updateTextSize(value) {
+    textSizeMultiplier = parseFloat(value);
+    const valueDisplay = document.getElementById('textSizeValue');
+    if (valueDisplay) valueDisplay.textContent = value;
+    localStorage.setItem('textSizeMultiplier', value);
+}
+
+function updateEntitySize(value) {
+    entitySizeMultiplier = parseFloat(value);
+    const valueDisplay = document.getElementById('entitySizeValue');
+    if (valueDisplay) valueDisplay.textContent = value;
+    localStorage.setItem('entitySizeMultiplier', value);
+}
+
+function resetSizes() {
+    const textSlider = document.getElementById('textSizeSlider');
+    const entitySlider = document.getElementById('entitySizeSlider');
+    const zoomSlider = document.getElementById('zoomLevelSlider');
+
+    if (textSlider) textSlider.value = DEFAULT_TEXT_SIZE.toString();
+    if (entitySlider) entitySlider.value = DEFAULT_ENTITY_SIZE.toString();
+    if (zoomSlider) zoomSlider.value = DEFAULT_ZOOM_LEVEL.toString();
+
+    updateTextSize(DEFAULT_TEXT_SIZE.toString());
+    updateEntitySize(DEFAULT_ENTITY_SIZE.toString());
+    updateZoomLevel(DEFAULT_ZOOM_LEVEL.toString());
+}
+
 function toggleZoom() {
     shouldZoom = !shouldZoom;
 }
@@ -1218,10 +1305,6 @@ function toggleRotate() {
     rotateMap = !rotateMap;
 }
 
-function toggleCentered() {
-    playerCentered = !playerCentered;
-}
-
 function toggleMoneyReveal() {
     if (websocket && websocket.readyState === WebSocket.OPEN) {
         console.log("[radarflow] Sending toggleMoneyReveal command");
@@ -1264,12 +1347,26 @@ function togglePerformanceMode() {
     }
 }
 
+window.addEventListener('resize', () => {
+    if (canvas) {
+        const canvasRect = canvas.getBoundingClientRect();
+        canvasScale = Math.min(canvasRect.width, canvasRect.height) / 1024;
+    }
+});
+
 addEventListener("DOMContentLoaded", () => {
     const savedDrawHealth = localStorage.getItem('drawHealth');
     drawHealth = savedDrawHealth !== null ? savedDrawHealth === 'true' : true;
+
     const savedDrawMoney = localStorage.getItem('drawMoney');
     drawMoney = savedDrawMoney !== null ? savedDrawMoney === 'true' : true;
 
+    const savedTextSize = localStorage.getItem('textSizeMultiplier');
+    textSizeMultiplier = savedTextSize !== null ? parseFloat(savedTextSize) : DEFAULT_TEXT_SIZE;
+
+    const savedEntitySize = localStorage.getItem('entitySizeMultiplier');
+    entitySizeMultiplier = savedEntitySize !== null ? parseFloat(savedEntitySize) : DEFAULT_ENTITY_SIZE;
+
     const checkboxes = {
         "zoomCheck": false,
         "statsCheck": true,
@@ -1278,7 +1375,8 @@ addEventListener("DOMContentLoaded", () => {
         "moneyDisplay": drawMoney,
         "moneyReveal": false,
         "rotateCheck": true,
-        "centerCheck": true
+        "centerCheck": true,
+        "healthCheck": drawHealth
     };
 
     Object.entries(checkboxes).forEach(([id, state]) => {
@@ -1286,12 +1384,41 @@ addEventListener("DOMContentLoaded", () => {
         if (checkbox) checkbox.checked = state;
     });
 
+    const textSizeSlider = document.getElementById('textSizeSlider');
+    if (textSizeSlider) {
+        textSizeSlider.value = textSizeMultiplier;
+        const textSizeValue = document.getElementById('textSizeValue');
+        if (textSizeValue) textSizeValue.textContent = textSizeMultiplier;
+    }
+
+    const entitySizeSlider = document.getElementById('entitySizeSlider');
+    if (entitySizeSlider) {
+        entitySizeSlider.value = entitySizeMultiplier;
+        const entitySizeValue = document.getElementById('entitySizeValue');
+        if (entitySizeValue) entitySizeValue.textContent = entitySizeMultiplier;
+    }
+
+    const savedZoom = localStorage.getItem('playerCenteredZoom');
+    playerCenteredZoom = savedZoom !== null ? parseFloat(savedZoom) : DEFAULT_ZOOM_LEVEL;
+
+    const zoomSlider = document.getElementById('zoomLevelSlider');
+    if (zoomSlider) {
+        zoomSlider.value = playerCenteredZoom;
+        const zoomValue = document.getElementById('zoomLevelValue');
+        if (zoomValue) zoomValue.textContent = playerCenteredZoom;
+    }
+
+    updateZoomSliderVisibility();
+
     canvas = document.getElementById('canvas');
     if (canvas) {
         canvas.width = 1024;
         canvas.height = 1024;
         ctx = canvas.getContext('2d');
 
+        const canvasRect = canvas.getBoundingClientRect();
+        canvasScale = Math.min(canvasRect.width, canvasRect.height) / 1024;
+
         connect();
     } else {
         console.error("[radarflow] Canvas element not found");
diff --git a/webradar/styles.css b/webradar/styles.css
index 971277c..592844d 100644
--- a/webradar/styles.css
+++ b/webradar/styles.css
@@ -23,6 +23,8 @@ body {
 canvas {
     width: 100%;
     height: 100%;
+    image-rendering: -webkit-optimize-contrast;
+    image-rendering: crisp-edges;
 }
 
 #settingsHolder {
@@ -47,6 +49,25 @@ canvas {
     background-color: rgba(25, 25, 25, 0.7);
     border-radius: 5px;
     transition: opacity 0.3s ease;
+    font-size: 14px;
+    max-height: 90vh;
+    overflow-y: auto;
+}
+
+@media (max-width: 768px) {
+    #settingsHolder .settings {
+        font-size: 16px;
+        padding: 12px;
+    }
+
+    #settingsHolder .settings input[type="checkbox"] {
+        transform: scale(1.2);
+        margin-right: 8px;
+    }
+
+    #settingsHolder .settings>div {
+        padding: 6px 0;
+    }
 }
 
 #settingsHolder:hover .settings {
@@ -92,31 +113,67 @@ canvas {
     background-color: #8a0000;
 }
 
+.size-control {
+    margin-bottom: 10px;
+}
+
+.size-control label {
+    display: inline-block;
+    margin-bottom: 3px;
+}
+
+input[type="range"] {
+    width: 100%;
+    margin: 5px 0;
+    -webkit-appearance: none;
+    height: 6px;
+    background: #555;
+    border-radius: 3px;
+    outline: none;
+}
+
+input[type="range"]::-webkit-slider-thumb {
+    -webkit-appearance: none;
+    appearance: none;
+    width: 16px;
+    height: 16px;
+    border-radius: 50%;
+    background: #68a3e5;
+    cursor: pointer;
+}
+
+input[type="range"]::-moz-range-thumb {
+    width: 16px;
+    height: 16px;
+    border-radius: 50%;
+    background: #68a3e5;
+    cursor: pointer;
+    border: none;
+}
+
 @media (max-width: 600px),
 (max-height: 600px) {
     #settingsHolder {
         display: none;
     }
+
+    #showMenuBtn {
+        display: block !important;
+        font-size: 16px !important;
+        padding: 8px 12px !important;
+    }
 }
 
 @media (max-width: 400px),
 (max-height: 400px) {
     #canvasContainer::before {
-        content: 'settings';
-        position: fixed;
-        top: 10px;
-        left: 10px;
-        background-color: rgba(25, 25, 25, 0.7);
-        color: white;
-        width: 30px;
-        height: 30px;
-        border-radius: 15px;
-        display: flex;
-        align-items: center;
-        justify-content: center;
-        font-size: 16px;
-        cursor: pointer;
-        z-index: 101;
+        content: '';
+        display: none;
+    }
+
+    #showMenuBtn {
+        padding: 6px 10px !important;
+        font-size: 14px !important;
     }
 }
 
@@ -129,6 +186,7 @@ canvas {
     margin-left: 5px;
     cursor: pointer;
     min-width: 150px;
+    font-size: inherit;
 }
 
 #playerSelect:hover {
@@ -147,19 +205,23 @@ canvas {
 
 .player-focus {
     margin-top: 10px;
+    display: flex;
+    align-items: center;
+    flex-wrap: wrap;
 }
 
 #hideMenuBtn {
     background-color: #333;
     color: white;
     border: none;
-    padding: 5px 10px;
+    padding: 8px 10px;
     margin-top: 10px;
     border-radius: 3px;
     cursor: pointer;
     font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
     transition: background-color 0.3s;
     width: 100%;
+    font-size: inherit;
 }
 
 #hideMenuBtn:hover {
@@ -170,19 +232,64 @@ canvas {
     position: fixed;
     top: 10px;
     left: 10px;
-    background-color: rgba(25, 25, 25, 0.7);
+    background-color: rgba(25, 25, 25, 0.9);
     color: white;
     border: none;
-    padding: 5px 10px;
+    padding: 8px 12px;
     border-radius: 15px;
-    font-size: 14px;
+    font-size: 16px;
     cursor: pointer;
     z-index: 101;
     font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
     transition: opacity 0.3s;
-    opacity: 0.6;
+    opacity: 0.8;
+    box-shadow: 0 2px 5px rgba(0, 0, 0, 0.3);
 }
 
 #showMenuBtn:hover {
     opacity: 1;
+}
+
+input[type="checkbox"] {
+    margin-right: 8px;
+}
+
+label {
+    cursor: pointer;
+    user-select: none;
+    margin-bottom: 2px;
+}
+
+.settings>div {
+    margin-bottom: 5px;
+    padding: 3px 0;
+}
+
+.touch-device input[type="checkbox"] {
+    transform: scale(1.3);
+    margin: 2px 10px 2px 2px;
+}
+
+.touch-device input[type="range"]::-webkit-slider-thumb {
+    width: 20px;
+    height: 20px;
+}
+
+.touch-device input[type="range"]::-moz-range-thumb {
+    width: 20px;
+    height: 20px;
+}
+
+.touch-device .settings>div {
+    padding: 6px 0;
+}
+
+@media (prefers-color-scheme: dark) {
+    #settingsHolder .settings {
+        background-color: rgba(15, 15, 15, 0.85);
+    }
+
+    #showMenuBtn {
+        background-color: rgba(15, 15, 15, 0.9);
+    }
 }
\ No newline at end of file