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
| Feature | Package | How it’s used |
|---|---|---|
live() RPC | svelte-realtime | Create, update, delete, and move notes |
live.stream() crud merge | svelte-realtime | Notes on the canvas → real-time CRUD |
live.stream() set merge | svelte-realtime | Board settings (title, background color) |
live.stream() latest merge | svelte-realtime | Activity ticker → ephemeral ring buffer |
live.cron() | svelte-realtime | Board cleanup → delete stale boards every minute |
batch() | svelte-realtime | Coalesce rapid note-drag moves into single WebSocket frames |
ctx.batch() | svelte-realtime | Server-side batched publish for arrangement actions and cron cleanup |
| Optimistic updates | svelte-realtime | Note position updates instantly on drag, server confirms async |
| Undo / redo | svelte-realtime | Ctrl+Z / Ctrl+Shift+Z to undo note actions |
status store | svelte-adapter-uws | Connection status dot in navbar (green/yellow/red) |
| Redis pub/sub bus | extensions | Multi-instance deployment with cross-instance updates |
| Input validation | server | Board titles, note content, colors, and coordinates are validated and bounded |
| Rate limiting | extensions | 100 RPCs per 10 seconds per user (drag/cursor moves are excluded) |
| Presence | extensions | Who’s online globally and on each board, with heartbeat + maxAge cleanup |
| Cursors | extensions | Live cursor overlay with per-topic throttle (~60 broadcasts/sec) |
| Cursor snapshots | extensions | Joining users instantly see existing cursor positions |
| Circuit breaker | extensions | Redis failures degrade gracefully instead of blocking |
| Real-time unsubscribe | adapter 0.4.0 | Presence and cursors clean up immediately on page navigation |
| Canvas rendering | demo | 1000 cursors at 60fps via Canvas 2D with bitmap label caching |
| Batch SQL | demo | FAB actions (tidy, rearrange, shuffle, group) use a single query via unnest() |
| Board TTL | demo | Boards auto-delete after 1 hour of inactivity, with live countdown timer |
| Mobile support | demo | Touch 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
- Client opens the page → SvelteKit renders HTML server-side
- Client JS boots → WebSocket connects via
svelte-adapter-uws - Client subscribes to live streams (
notes,settings,activity) → gets initial data + events - User does something (creates a note, drags, edits) → calls a
live()RPC over WebSocket - Server validates input, writes to Postgres, publishes an event to the topic
- All subscribed clients receive the event and update their local store
- 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?