When multiple users have the same diagram open, MC Modeler displays a presence strip of colored avatar circles in the toolbar and renders each collaborator’s cursor directly on the canvas. Presence data is carried by Supabase Realtime with no polling — updates appear within milliseconds of a collaborator moving their mouse or joining the session.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/Aston2710/mc-modeler/llms.txt
Use this file to discover all available pages before exploring further.
Presence features require both Supabase and an authenticated session. In local-only mode (no Supabase configured) or when signed out, the presence strip and live cursors are not shown.
Participant identity
Each participant is described by aParticipantMeta record:
name comes from the authenticated user’s full_name, name, or email (in that priority order). The color is deterministically derived from the userId using a simple hash against a fixed 10-color palette — the same user always gets the same color across sessions and devices:
Presence channel
On connecting to a diagram, each client callschannel.track(me) to publish their ParticipantMeta into the Supabase Realtime presence slot keyed by userId. The channel name is diagram:{diagramId}.
sync event (join, leave, or network update) rebuilds the full participant list and pushes it into usePresenceStore, which both PresenceAvatars and RemoteCursors subscribe to.
Presence avatars
ThePresenceAvatars component renders in the toolbar whenever more than one participant is online (showing yourself alone adds no value):
"${name} (tú)" (yourself).
Cursor state
Cursor positions are transmitted as a separateCursorState — intentionally outside the Realtime presence slot:
viewbox:
sendCursor(null) is called and the cursor is removed from other users’ views.
Cursor broadcast
Cursors are sent as Supabase Realtime broadcast events (event name:'cursor') rather than presence updates. Broadcast has lower overhead and higher frequency tolerance than presence, which makes it better suited for the ~50 ms throttle interval used for cursor updates:
onCursor handler in useCollab forwards cursor positions to usePresenceStore, which stores them in a Participant record (extending ParticipantMeta with cursor: CursorState | null).
Rendering remote cursors
TheRemoteCursors component overlays a positioned div layer on the canvas. For each remote participant with a non-null cursor it renders an SVG arrow pointer in their color, followed by a name label:
canvas.viewbox.changed event (zoom or pan) so cursors stay aligned when the local user scrolls or zooms.
Cursor lifecycle
| Event | Cursor behavior |
|---|---|
| User moves mouse on canvas | Cursor position updates every ≤50 ms |
| User moves mouse off canvas | sendCursor(null) — cursor disappears |
| User closes the tab / disconnects | Presence leave event — participant removed from list, cursor disappears |
| User becomes idle (no movement) | Cursor freezes at last known position until they move again |
Canvas session and connection lifecycle
AcanvasSession module tracks whether the local canvas is currently displaying a specific diagramId. The useCollab hook waits for an explicit confirmation signal (isCanvasReadyFor(diagramId)) before starting the Yjs binding — this prevents cross-contamination between diagrams during tab switches.
channel.disconnect() and reset() (clears participants and cursors from the store), ensuring stale data from the previous diagram never bleeds into the next.
Project-level presence indicator
TheuseDiagramsPresence hook extends presence awareness to the diagrams list: cards for diagrams that currently have active participants show a live indicator, letting users see at a glance which diagrams their teammates are working in without opening them.