svelte-realtime-demo

A collaborative sticky notes app built with svelte-realtime, svelte-adapter-uws, and svelte-adapter-uws-extensions.

Open the page, get a random name, drop notes on a shared canvas. Every note, cursor, and color change syncs across all browsers in real time. No login, no friction.

Try it now: svelte-realtime-demo.lantean.io - open two tabs and watch the magic. Runs on a Hetzner CPX22 (2 shared vCPUs, 4 GB RAM, 6.49/month).

Source: github.com/lanteanio/svelte-realtime-demo


What it demonstrates

FeaturePackageHow it’s used
live() RPCsvelte-realtimeCreate, update, delete, and move notes
live.stream() crud mergesvelte-realtimeNotes on the canvas → real-time CRUD
live.stream() set mergesvelte-realtimeBoard settings (title, background color)
live.stream() latest mergesvelte-realtimeActivity ticker → ephemeral ring buffer
live.cron()svelte-realtimeBoard cleanup → delete stale boards every minute
batch()svelte-realtimeCoalesce rapid note-drag moves into single WebSocket frames
ctx.batch()svelte-realtimeServer-side batched publish for arrangement actions and cron cleanup
Optimistic updatessvelte-realtimeNote position updates instantly on drag, server confirms async
Undo / redosvelte-realtimeCtrl+Z / Ctrl+Shift+Z to undo note actions
status storesvelte-adapter-uwsConnection status dot in navbar (green/yellow/red)
Redis pub/sub busextensionsMulti-instance deployment with cross-instance updates
Input validationserverBoard titles, note content, colors, and coordinates are validated and bounded
Rate limitingextensions100 RPCs per 10 seconds per user (drag/cursor moves are excluded)
PresenceextensionsWho’s online globally and on each board, with heartbeat + maxAge cleanup
CursorsextensionsLive cursor overlay with per-topic throttle (~60 broadcasts/sec)
Cursor snapshotsextensionsJoining users instantly see existing cursor positions
Circuit breakerextensionsRedis failures degrade gracefully instead of blocking
Real-time unsubscribeadapter 0.4.0Presence and cursors clean up immediately on page navigation
Canvas renderingdemo1000 cursors at 60fps via Canvas 2D with bitmap label caching
Batch SQLdemoFAB actions (tidy, rearrange, shuffle, group) use a single query via unnest()
Board TTLdemoBoards auto-delete after 1 hour of inactivity, with live countdown timer
Mobile supportdemoTouch dragging, responsive navbar, controls visible without hover

Tech stack

  • Frontend - SvelteKit, Svelte 5 (runes), Tailwind CSS v4, DaisyUI v5
  • Server - svelte-adapter-uws (uWebSockets.js)
  • Realtime - svelte-realtime (RPC + live streams over WebSocket)
  • Extensions - svelte-adapter-uws-extensions (Redis-backed presence, cursors, pub/sub, rate limiting, circuit breaker)
  • Database - PostgreSQL (production) / in-memory Map (dev)
  • Cache & pub/sub - Redis (production) / not needed (dev)

How realtime works

  1. Client opens the page → SvelteKit renders HTML server-side
  2. Client JS boots → WebSocket connects via svelte-adapter-uws
  3. Client subscribes to live streams (notes, settings, activity) → gets initial data + events
  4. User does something (creates a note, drags, edits) → calls a live() RPC over WebSocket
  5. Server validates input, writes to Postgres, publishes an event to the topic
  6. All subscribed clients receive the event and update their local store
  7. Svelte reactivity re-renders the changed parts of the UI

Cursors bypass the database. Positions go through Redis pub/sub and are rendered on a Canvas 2D overlay.

Board cleanup runs as a live.cron() job every minute. It queries for boards where last_activity is older than 1 hour, deletes them, and publishes deleted events so all home page viewers see the board disappear.

Was this page helpful?