Commit Graph
5 Commits
Author SHA1 Message Date
tiennm99 c3f7c02f6d feat(canvas): migrate canvas + cooldown storage to DO SQLite
Move pixel state and rate-limit cooldowns out of Upstash Redis and into
the existing CanvasRoom Durable Object's SQLite-backed storage. Worker
becomes a thin validation/proxy; the DO does atomic cooldown check +
pixel write + WS broadcast in one in-memory step.

Why: eliminate external dependency, keep $0/month free-tier forever,
exploit single-threaded actor for strong consistency without round-trips.

Architecture:
- canvas_chunks: 256 BLOB rows × 64 KB; CHUNK_COUNT derived from
  CANVAS_WIDTH × CANVAS_HEIGHT / CHUNK_BYTES so resize is config-only.
- cooldowns: user_id → expires_at, 1% sample-rate lazy GC.
- Worker forwards /api/canvas, /api/place, /api/ws to DO endpoints.
- POST /admin/migrate-from-upstash: token-gated one-shot importer.

Phases 1-3 code complete; Upstash dependency stays until prod migration
runs and 7-day rollback window passes (Phase 4).

Plan: plans/260509-2309-canvas-on-do-storage/
2026-05-09 23:53:21 +07:00
tiennm99 8c6b9aa191 perf(importer): offload pipeline to worker, stage cache, quick-preview tier
Replaces the synchronous reactive pipeline with a debounced worker RPC.
Slider drags and file loads no longer block the main thread.

- image-pipeline.js: pure staged pipeline (transform → resize →
  color-correction → quantize). Each upstream stage keeps one cached
  slot keyed on the inputs it depends on, so a single-slider change
  reruns only the downstream stages.
- image-pipeline-worker.js: hosts the pipeline inside a module Worker.
  Accepts set-source (transferable) and run(params). Returns indices
  + preview RGBA as transferable ArrayBuffers.
- image-pipeline-client.js: main-thread RPC with request-id tracking
  and stale-response dropping.
- ImageImporter.svelte: two-tier scheduler — throttled quick request
  (<=384px) for the preview panel while inputs churn, debounced full
  request (180ms) for overlay/buildPixels/opaque-count on settle.
  Source buffer cloned and transferred to the worker on load/resume.

Main bundle shrinks ~4KB (pipeline code now in its own worker chunk).
2026-04-18 14:51:48 +07:00
tiennm99 0bf51a410e feat(ui): pick-position, cooldown, goto, shortcuts, progressive skip, resume (#4)
* feat(ui): pick-position, cooldown badge, goto, shortcuts, progressive skip, resume

- Pick-position mode: "Pick on canvas" replaces the broken "Use cursor"
  button. Next left-click (no drag) sets origin; Esc or second press cancels.
- Visible cooldown on Submit: disables button + shows "Wait Xs" countdown
  after a successful place or 429 response.
- Goto-coordinates: "x,y" input in CanvasControls; Enter centers the
  viewport on that canvas point.
- Keyboard shortcuts: Q/E zoom, WASD pan (40px), Esc cancels pick or stroke.
  Guarded against firing in focused inputs.
- Progressive skip-already-matching: uploader re-filters remaining queue
  every 8 batches via an optional shouldSkip predicate.
- Auto-save + resume: new image-job-storage module (localStorage + PNG
  dataURL); uploader emits onCheckpoint after each batch; importer shows
  a Resume/Discard banner when an unfinished job is found on mount.

* docs(reports): wplace-autobot logic + wplace.live design research
2026-04-18 12:48:16 +07:00
tiennm99 ad8d2a6f71 docs: add ultrareview reports and fix-sweep plan
Three review reports (backend, frontend, security/scale) and a
follow-up re-review after pull. Plan documents which findings were
addressed in this sweep and which were intentionally deferred.
2026-04-17 10:14:45 +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