13 Commits
Author SHA1 Message Date
tiennm99 8e0bddc83c build(deps): upgrade to Vitest 5 2026-10-03 13:20:00 +07:00
tiennm99 a461744dbf fix(deps): update dependencies to latest compatible versions
Rebased onto current main: the original commit only touched pnpm files and
versions main has since moved past, so it is replaced by a fresh npm update
within the declared ranges plus npm audit fix.
2026-10-03 12:41:57 +07:00
tiennm99 150917a69a build: move from pnpm to npm
Replace pnpm-lock.yaml with package-lock.json. pnpm-workspace.yaml's
allowBuilds becomes package.json#allowScripts, which npm 11 gates the same way,
listing only the packages actually present in the tree.
2026-08-17 13:07:36 +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
dependabot[bot] e042748b41 chore(deps): bump @xmldom/xmldom from 0.8.12 to 0.8.13 (#6)
Bumps [@xmldom/xmldom](https://github.com/xmldom/xmldom) from 0.8.12 to 0.8.13.
- [Release notes](https://github.com/xmldom/xmldom/releases)
- [Changelog](https://github.com/xmldom/xmldom/blob/master/CHANGELOG.md)
- [Commits](https://github.com/xmldom/xmldom/compare/0.8.12...0.8.13)

---
updated-dependencies:
- dependency-name: "@xmldom/xmldom"
  dependency-version: 0.8.13
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-07 13:33:13 +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 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