mirror of
https://github.com/tiennm99/rplace.git
synced 2026-10-13 22:16:24 +00:00
feat(canvas): 4096^2 canvas, 256-color palette (u8 byte-aligned), custom picker (#5)
Canvas: - CANVAS_W/H = 4096, total 16,777,216 pixels - BITS_PER_PIXEL = 8 (byte-aligned) — raw Redis bytes are palette indices - Canvas-decoder becomes an identity wrap/copy - Storage BITFIELD uses u8; offset = y*W + x - Redis key versioned to rplace:canvas:v2 so old 32-color/2048^2 data is orphaned (operators can DEL the old key to reclaim memory) Palette: - 256 entries, generated deterministically: - 0..15 = 16-step grayscale ramp (pure black -> pure white) - 16..255 = 240 HSL wheel (4 lightness rings x 60 hues @ 82% saturation) - nearestPaletteIndex(r,g,b) helper for custom-color snapping UI: - ColorPicker: 16-swatch favorites strip (grays + 8 accents) + current-color swatch + expand toggle for the full 16x16 grid + "Custom..." button that opens the native <input type="color"> and snaps to nearest palette entry - Default selected color bumped to index 0 (black) Tests + docs: - canvas-decoder tests rewritten for identity u8 decode - canvas-storage tests updated for u8 offsets - image-to-palette tests anchored to PALETTE_BLACK=0 / PALETTE_WHITE=15 and COLORS_RGBA[i] probes (no more hardcoded old 32-color indices) - integration test uses u8 BITFIELD and canvas-aware bounds - README, system-architecture, deployment-guide updated (storage math, migration note for orphaned old key)
This commit is contained in:
1 parent
0bf51a410e
commit
cfbac2a586
12 files changed
+371
-214
No files matched your search
@@ -69,6 +69,7 @@ For hobby traffic (< few hundred users/day), free tiers are sufficient. Upstash
|
||||
## Troubleshooting
|
||||
|
||||
- **Canvas loads empty**: Check Upstash credentials in secrets
|
||||
- **Pixels don't persist**: Verify BITFIELD support — test with `redis-cli BITFIELD canvas SET u5 #0 1`
|
||||
- **Pixels don't persist**: Verify BITFIELD support — test with `redis-cli BITFIELD rplace:canvas:v2 SET u8 #0 42`
|
||||
- **Old 32-color canvas still visible after deploy**: the canvas key is versioned (`rplace:canvas:v2`). The old `rplace:canvas` key is orphaned — run `redis-cli DEL rplace:canvas` once to reclaim memory.
|
||||
- **WebSocket not connecting**: Ensure Durable Object migration ran (check `wrangler.json` migrations)
|
||||
- **Rate limiting not working**: Verify `SET key value NX EX 1` returns `"OK"` / `null` as expected on your Upstash tier
|
||||
@@ -23,9 +23,9 @@ rplace is a collaborative pixel canvas deployed as a single Cloudflare Worker. T
|
||||
|
||||
```
|
||||
1. Client fetches GET /api/canvas
|
||||
2. Worker reads Redis key via GETRANGE → raw binary
|
||||
3. Client receives ~2.5MB (5-bit packed pixels)
|
||||
4. Client decodes 5-bit values → color indices → RGBA ImageData
|
||||
2. Worker reads Redis key via GETRANGE → raw binary (16 MB, gzip-compressed by CF edge)
|
||||
3. Client receives 16 MB of bytes — each byte is a palette index (u8, byte-aligned)
|
||||
4. Client maps indices → RGBA ImageData via COLORS_RGBA lookup
|
||||
5. Renders onto HTML5 Canvas with OffscreenCanvas
|
||||
```
|
||||
|
||||
@@ -42,13 +42,14 @@ rplace is a collaborative pixel canvas deployed as a single Cloudflare Worker. T
|
||||
|
||||
## Storage
|
||||
|
||||
### Redis BITFIELD (Canvas)
|
||||
### Redis STRING / BITFIELD (Canvas)
|
||||
|
||||
- Key: `canvas`
|
||||
- Encoding: 5 bits per pixel (u5), 32 colors
|
||||
- Size: `2048 * 2048 * 5 / 8 = 2,621,440 bytes` (~2.5MB)
|
||||
- Key: `rplace:canvas:v2` (bumped from the old `rplace:canvas` so the 32-color/2048² data is ignored on rollout)
|
||||
- Encoding: 8 bits per pixel (u8), 256-color palette — byte-aligned, so raw Redis bytes are the pixel indices directly
|
||||
- Size: `4096 × 4096 × 1 = 16,777,216 bytes` (16 MB)
|
||||
- Offset: `y * CANVAS_WIDTH + x`
|
||||
- Atomic batch writes: single BITFIELD command with chained .set() calls
|
||||
- Atomic batch writes: single BITFIELD command chaining `SET u8 #offset color` per pixel
|
||||
- Reads via GETRANGE return the whole buffer; Cloudflare edge handles gzip
|
||||
|
||||
### Redis STRING (Cooldown)
|
||||
|
||||
|
||||
Reference in new issue
Block a user