Cursor positions throttled, not raw
Browser mousemove fires hundreds of times per second. Sending each one over WebSocket would saturate the connection and waste server resources. Throttle to 20-30 updates per second; the human eye does not need more for smooth cursor rendering, especially with CSS transitions to interpolate between points.
Presence is just a special-case message
"User X is online" is one message; "user X is offline" is another; "user X has cursor at (100,200) in document Y" is another. There is no special "presence" protocol — it is just typed messages your application interprets. Figma calls them presence; Slack calls them user.status; the wire shape is the same.