From 078ccaa70e4c4707cda00d99b6c53ca25a05c838 Mon Sep 17 00:00:00 2001 From: tiennm99 Date: Thu, 16 Apr 2026 17:03:38 +0700 Subject: [PATCH] fix: final review polish before documentation - Handle base64 encoding from Upstash GETRANGE (atob fallback) - Add optimistic credit deduction on pixel placement - Handle non-ok API responses in placePixel - Enable WebSocket proxy in Vite dev config - Remove dead CANVAS_WIDTH/HEIGHT vars from wrangler.json - Suppress favicon 404 with empty data URI --- src/client/components/CanvasRenderer.svelte | 9 ++++++++- src/index.html | 2 +- src/lib/canvas-storage.js | 14 ++++++++++---- vite.config.js | 5 ++++- wrangler.json | 6 +----- 5 files changed, 24 insertions(+), 12 deletions(-) diff --git a/src/client/components/CanvasRenderer.svelte b/src/client/components/CanvasRenderer.svelte index ed3e9dd..82e2046 100644 --- a/src/client/components/CanvasRenderer.svelte +++ b/src/client/components/CanvasRenderer.svelte @@ -56,6 +56,8 @@ if (x < 0 || x >= CANVAS_WIDTH || y < 0 || y >= CANVAS_HEIGHT) return; if (credits <= 0) return; + // Optimistic deduction + render + onCreditsChange(credits - 1); updatePixel(x, y, selectedColor); render(); @@ -66,7 +68,12 @@ body: JSON.stringify({ pixels: [{ x, y, color: selectedColor }] }), }); const data = await res.json(); - if (data.ok) onCreditsChange(data.credits); + if (data.ok) { + onCreditsChange(data.credits); + } else { + // Server rejected — log reason (pixel stays rendered, WS will correct) + console.warn('Place rejected:', data.error); + } } catch (err) { console.error('Failed to place pixel:', err); } diff --git a/src/index.html b/src/index.html index 34f05e8..e3103b0 100644 --- a/src/index.html +++ b/src/index.html @@ -4,7 +4,7 @@ rplace — Collaborative Pixel Canvas - +
diff --git a/src/lib/canvas-storage.js b/src/lib/canvas-storage.js index 475f54c..6db481b 100644 --- a/src/lib/canvas-storage.js +++ b/src/lib/canvas-storage.js @@ -21,11 +21,17 @@ export async function getFullCanvas(env) { return new Uint8Array(CANVAS_BYTES); } - // Upstash REST returns string — convert to bytes + // Upstash REST may return base64 or raw string for binary data if (typeof data === 'string') { - const bytes = new Uint8Array(data.length); - for (let i = 0; i < data.length; i++) { - bytes[i] = data.charCodeAt(i); + let raw; + try { + raw = atob(data); + } catch { + raw = data; // Already a raw string + } + const bytes = new Uint8Array(raw.length); + for (let i = 0; i < raw.length; i++) { + bytes[i] = raw.charCodeAt(i); } // Pad to full canvas size if shorter if (bytes.length < CANVAS_BYTES) { diff --git a/vite.config.js b/vite.config.js index d2a135e..fa32739 100644 --- a/vite.config.js +++ b/vite.config.js @@ -10,7 +10,10 @@ export default defineConfig({ }, server: { proxy: { - '/api': 'http://localhost:8787', + '/api': { + target: 'http://localhost:8787', + ws: true, + }, }, }, }); diff --git a/wrangler.json b/wrangler.json index a48e814..a40c86c 100644 --- a/wrangler.json +++ b/wrangler.json @@ -18,9 +18,5 @@ "tag": "v1", "new_classes": ["CanvasRoom"] } - ], - "vars": { - "CANVAS_WIDTH": "2048", - "CANVAS_HEIGHT": "2048" - } + ] }