Collaborative cursors: portert fra SpacetimeDB til WebSocket

SpacetimeDB er fjernet (mars 2026). Oppdatert til å bruke
eksisterende WebSocket/portvokter med ephemeral cursor_move-
meldinger (ikke persistert i PG). In-memory HashMap i Rust.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
vegard 2026-03-19 16:57:47 +00:00
parent 2d663f8f67
commit db95cd33d1

View file

@ -1,29 +1,86 @@
# Collaborative Cursors — Sanntids-pekere for flerbrukermiljø
## Idé
Alle brukere som er på samme side ser hverandres musepekere som fargede prikker med navn. Fungerer på storyboard, kanban, whiteboard og kalender.
## Hvorfor interessant?
Gir "jamming together"-følelse under innspilling og planlegging. Produsent og host ser hverandre jobbe i sanntid uten å snakke om det.
## Fungerer slik
1. Klient sender `{ user_id, x, y, page }` til SpacetimeDB ved musebevegelse (throttlet til ~10 Hz)
2. Andre klienter renderer fargede SVG-sirkler med brukernavn
3. Prikken fader ut etter 5 sekunder uten bevegelse
4. Valgfritt: kort "trail" som viser bevegelsesretning
## Bygger på
- SpacetimeDB (pub/sub for posisjoner)
- Svelte ($state store for cursor-map)
## Innsats
Lav — under 50 linjer Svelte + en SpacetimeDB-reducer.
## Wow-faktor
Middels — visuelt tiltalende, men ikke kritisk funksjonalitet.
## Åpne spørsmål
- Bør pekere vises i chat-visning også, eller bare canvas-baserte views?
- Throttling-strategi: SpacetimeDB-reducer eller klient-side debounce?
# Collaborative Cursors — Sanntids-pekere for flerbrukermiljø
## Idé
Alle brukere som er på samme arbeidsflate ser hverandres
musepekere som fargede prikker med navn. Fungerer på spatial
canvas, storyboard, kanban, whiteboard og kalender.
## Hvorfor interessant?
Gir "jamming together"-følelse under innspilling og planlegging.
Produsent og host ser hverandre jobbe i sanntid uten å snakke
om det. Essensielt for delte arbeidsflater (møterom, studio).
## Fungerer slik
1. Klient sender `{ user_id, x, y, context_id }` via WebSocket
ved musebevegelse (throttlet til ~10 Hz)
2. Portvokteren broadcaster til andre klienter i samme kontekst
3. Andre klienter renderer fargede SVG-sirkler med brukernavn
4. Prikken fader ut etter 5 sekunder uten bevegelse
5. Valgfritt: kort "trail" som viser bevegelsesretning
## Teknisk implementering
### Kanal
Bruker eksisterende WebSocket-tilkobling til portvokteren.
Ny meldingstype `cursor_move` som **ikke** persisteres i PG —
dette er ephemeral data som kun lever i minne.
```
Klient → WS → portvokteren → broadcast til andre i samme context_id
```
Portvokteren holder en in-memory map:
```rust
cursors: HashMap<(ContextId, UserId), CursorPosition>
```
Ryddes automatisk ved disconnect eller timeout (5s).
### Throttling
Klientside: `requestAnimationFrame` + 100ms minimum intervall.
~10 meldinger per sekund per bruker. Ved 10 samtidige brukere
i ett rom: ~100 meldinger/sekund — trivielt for WebSocket.
### Rendering
Canvas-laget (over objektene, under toolbar):
```svelte
{#each cursors as cursor (cursor.userId)}
<div
class="cursor-indicator"
style:left="{cursor.x}px"
style:top="{cursor.y}px"
style:background={cursor.color}
style:opacity={cursor.fresh ? 1 : 0}
>
<span class="cursor-label">{cursor.name}</span>
</div>
{/each}
```
## Bygger på
- WebSocket / portvokteren (erstatter SpacetimeDB)
- Canvas-komponent (cursor-lag over objekter)
- Svelte ($state for cursor-map)
## Innsats
Lav — under 100 linjer Svelte + ~50 linjer Rust i portvokteren.
## Wow-faktor
Middels-høy — visuelt tiltalende og essensielt for delte
arbeidsflater (møterom, studio, samarbeid).
## Åpne spørsmål
- Bør pekere vises i chat-visning også, eller bare canvas?
(Sannsynligvis bare canvas og andre spatial views)
- Fargetildeling: per bruker (konsistent) eller per sesjon?
(Per bruker, lagret i person-node metadata)