Commit Graph
14 Commits
Author SHA1 Message Date
dependabot[bot] ecc5808457 chore(deps-dev): bump vite from 6.4.2 to 8.0.14 (#13) 2026-05-23 18:16:55 +07:00
dependabot[bot] 6f3094ab13 chore(deps-dev): bump @sveltejs/vite-plugin-svelte from 5.1.1 to 7.1.2 (#12) 2026-05-23 18:14:29 +07:00
dependabot[bot] 4b95fe2071 chore(deps): bump the minor-and-patch group across 1 directory with 4 updates (#11) 2026-05-23 18:12:47 +07:00
dependabot[bot] 113ff09813 chore(deps-dev): bump svelte from 5.55.5 to 5.55.7 (#9) 2026-05-23 18:09:09 +07:00
tiennm99 e3bcebad98 chore: migrate from npm to pnpm 2026-05-13 10:23:21 +07:00
tiennm99 a977adc62d refactor(canvas): drop Upstash entirely after successful DO migration
Production migration ran cleanly (samples_checked: 9, mismatches: []),
canvas data preserved, drawing verified by user. Phase 4 cleanup:

Removed code:
- src/lib/canvas-storage.js (Upstash GETRANGE reader)
- src/lib/redis-client.js   (Upstash REST helpers)
- src/lib/rate-limiter.js   (orphan since Phase 2)
- src/admin/migrate-from-upstash.js (one-shot importer)
- src/durable-objects/canvas-room.js #handleImport route
- src/durable-objects/lib/chunk-storage.js importFullCanvas helper
- src/worker.js /admin/migrate-from-upstash mount + import

Removed tests:
- test/lib/canvas-storage.test.js
- test/lib/redis-client.test.js
- test/integration/redis-canvas-roundtrip.test.js
- test/durable-objects/canvas-room.test.js (was skipped pending rewrite)
- vitest.integration.config.js (only Redis testcontainers used it)

Removed deps:
- @upstash/redis, ioredis, testcontainers (-184 packages)

Removed constants:
- REDIS_KEY_PREFIX, REDIS_CANVAS_KEY (only used by deleted code)

Removed package.json scripts: test:integration, test:all
Removed CF Worker secrets in production:
  UPSTASH_REDIS_REST_URL, UPSTASH_REDIS_REST_TOKEN, MIGRATION_TOKEN

Tests: 94/94 pass (down from 112 — 18 deleted Upstash-specific).
Bundle: 71.90 KiB (down from 79.43 KiB).
Production verified: canvas data intact (38% non-zero bytes), migration
endpoint returns 404, secret list empty.
2026-05-10 02:05:43 +07:00
tiennm99 ce05024858 perf(canvas): port renderer to PixiJS (GPU pan/zoom) + cap DPR at 2
Replace Canvas2D render path with pixi.js v8. Canvas stays authored
as CPU RGBA on an OffscreenCanvas; pixi uses that as a texture source
and uploads on demand. Pan/zoom become pure GPU transforms on a
Container — no CPU work per frame. Overlay is a second sprite in the
same container so it tracks pan/zoom for free.

Key points:
- app.ticker.stop() + manual app.renderer.render() on rAF: idle frames
  cost 0, active frames cost one GPU draw.
- mainTexture.source.update() called only when imageDataDirty (same
  gating as before). Writes stay cheap.
- resolution: Math.min(devicePixelRatio, 2). iPhone 3x → 2x = 44%
  fewer fragments; pixel art gains nothing from 3x.
- Public API preserved: applyUpdates, undo/redo, setOverlay, panBy,
  gotoPoint, getCommittedColor, getPendingPixels, commitPending,
  refetchCanvas, cancelStrokeIfAny all unchanged.
- Overlay sprite rebuilt on setOverlay() with destroy({texture,
  textureSource}) to avoid GPU leaks.

Bundle: +200KB main, +~100KB pixi chunks, ~70KB gz total. Tradeoff
accepted for mobile perf parity with wplace.
2026-04-18 17:51:53 +07:00
tiennm99 6b790f3892 chore: prune dead code, unused exports, and orphan scripts
- scripts/: remove upload-colors.js (broken — imported removed constants)
  and image-to-colors.js (orphan — flow moved fully client-side to
  ImageImporter). Drop sharp from devDependencies.
- constants.js: drop unused BITS_PER_PIXEL export.
- dither-kernels.js: make KERNEL_* consts internal; only the
  ERROR_DIFFUSION_KERNELS map is consumed externally.
- image-pipeline.js: drop unused pipeline.source() accessor.
- image-to-palette.js: drop `options.dither` legacy boolean shim
  (no external caller uses it) and its test.
- canvas-storage.js, App.svelte: drop comments that restated names.
2026-04-18 15:01:49 +07:00
tiennm99 1565776f02 feat(scripts): add image-to-colors + upload-colors CLI scripts
Convert PNG/JPG/WebP to rplace palette JSON (nearest-color or Floyd-Steinberg
dither) and upload at a target (x, y) with client-side credit throttling and
429 backoff. Shared palette conversion lives in src/lib/image-to-palette.js so
the browser importer can reuse it.
2026-04-17 11:25:06 +07:00
tiennm99 8e1f8c4049 test: add Redis integration tests with Testcontainers
Docker-based tests with real Redis verifying:
- BITFIELD write → GETRANGE read round-trip for all 32 colors
- Pixel placement at canvas boundaries and various positions
- Pixel overwrite correctness
- 5-bit boundary isolation (adjacent pixels don't corrupt)
- Batch atomicity (100 pixels in single BITFIELD)
- Rate limiter Lua script: credit grant, deduction, regen, cap, rejection

Test commands: npm test (unit), npm run test:integration (Docker),
npm run test:all (both). 82 total tests.
2026-04-16 22:52:36 +07:00
tiennm99 fcddb1f9c5 test: add unit tests for Durable Object and clean up test setup
- Add CanvasRoom broadcast/close/error tests with mock WebSockets
- Remove @cloudflare/vitest-pool-workers (incompatible with Vitest 4)
- Clean up vitest config (single config, no integration workspace)
- 71 tests across 7 test files, all passing
2026-04-16 22:45:16 +07:00
tiennm99 33cfd3d7b3 test: add comprehensive unit tests with Vitest
65 tests covering canvas decoder, pixel buffer, user ID hashing,
canvas storage (with binary encoding regression test), Redis client
API shape, and worker endpoint validation.
2026-04-16 22:37:12 +07:00
tiennm99 2ccf1c9779 refactor: migrate from Next.js/Vercel to Svelte/Hono/Cloudflare Workers
Replace Next.js + SSE with Svelte frontend + Hono API + Durable Objects
WebSocket on Cloudflare Workers. Single worker serves static assets and
API routes. Native WebSocket replaces SSE polling for real-time updates.
17kb gzipped client bundle vs 90kb+ React runtime.
2026-04-16 16:23:27 +07:00
tiennm99 3beaa9d43f feat: implement core pixel canvas with real-time updates
Next.js App Router + Upstash Redis BITFIELD for 2048x2048 canvas.
- 32-color palette (5-bit encoding) from rplace.live
- Batch pixel placement API (up to 256 pixels per request)
- Stackable credit rate limiting via Redis Lua script
- SSE real-time broadcasting via Redis sorted set
- HTML5 Canvas frontend with zoom/pan and color picker
2026-04-16 15:56:20 +07:00