Installation
RealtimeCursorscontainer component- Individual
Cursorcomponent with smooth animations - Custom hook for cursor tracking
- Convex presence backend
- Convex client setup
What’s Included
Smooth Animations
Cursor movements animated with Framer Motion
Color Coding
Each user gets a unique color for identification
Presence Tracking
Automatic join/leave detection and cleanup
Position Throttling
Optimized updates to prevent network overload
Setup
Component
RealtimeCursors
Container component that tracks and displays cursors.Props
Unique identifier for the room. Users in the same room see each other’s cursors.
Display name shown next to the cursor.
Hex color for the user’s cursor (e.g.,
"#ff0000").Content to render inside the cursor container.
Additional CSS classes for the container.
Usage Examples
Custom Hook
useRealtimeCursors
Use the cursor tracking logic independently:Room identifier
Current user’s display name
Hex color for cursor
Minimum milliseconds between position updates
Cursor Type
Backend Functions
list
Query all active users in a room.update
Update cursor position.leave
Remove user from room (called on unmount).Features
Position Throttling
Cursor updates are throttled to prevent overwhelming the network:- Default: 100ms between updates (10 updates/second)
- Configurable via
throttleMsprop - Smooth for users, efficient for servers
Automatic Cleanup
Users are automatically removed when:- Component unmounts
- Browser tab closes
- Connection is lost
Session Management
Each component instance gets a unique session ID:- Generated on mount:
session-{timestamp}-{random} - NOT stored in localStorage (prevents iframe conflicts)
- Filters out own cursor automatically
Relative Positioning
Cursor positions are relative to the container:- Works with scrolling containers
- Positions calculated from
getBoundingClientRect() - Accurate even with nested elements
Animations
Cursors use Framer Motion for smooth animations:components/cursor.tsx
Customization
Custom Cursor Design
Modifycomponents/cursor.tsx:
Custom Update Frequency
Schema
The presence table schema:convex/schema.ts
Performance
Throttled Updates
Position updates limited to 10/second by default
Indexed Queries
Fast room lookups using Convex indexes
Automatic Cleanup
Old presence records removed on unmount
Efficient Rendering
Only re-renders when cursor positions change
Troubleshooting
Cursors not appearing
Cursors not appearing
Verify the container has
position: relative (or className includes positioning). The cursors use position: absolute and need a positioned ancestor.Position is offset
Position is offset
Ensure you’re tracking mouse position relative to the container. The hook’s
createMouseMoveHandler calculates this automatically using getBoundingClientRect().Multiple cursors for same user
Multiple cursors for same user
This happens if
sessionId is shared across tabs. The component generates unique session IDs per instance. Don’t use localStorage for session management.Cursors lag or jump
Cursors lag or jump
Adjust
throttleMs to a lower value for more frequent updates, or higher to reduce network traffic. Default 100ms is optimal for most use cases.Next Steps
Avatar Stack
Show who’s in the room with avatars
Realtime Chat
Add chat to your collaborative app
Password Auth
Authenticate users in collaborative spaces