synops/docs/proposals/collaborative_cursors.md
vegard db95cd33d1 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>
2026-03-19 16:57:47 +00:00

86 lines
2.4 KiB
Markdown

# 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)