Skip to content

Concurrent editing experience: consumer-ready collaborative UX #35

Description

@jonesd

Vision

Multiple users editing the same work concurrently on different devices should feel as fluid as Google Docs or Figma — real-time cursor positions, instant text sync, and clear visual feedback of who changed what.

Current State (Phase 1 COMPLETE)

  • Text sync: WORKING — edits propagate between sessions
  • Awareness/presence: WORKING — bar shows who is viewing the same work with pulsing indicators
  • Cursors: WORKING — colored carets with name labels, different colors per user
  • Selection: PARTIAL — cursor stays at start of selection
  • Conflict resolution: WORKING — CRDT handles merges automatically

Known Issues (Phase 1 refinements)

1. Cursor position at line boundaries

Problem: When cursor is at the start of a line (after a newline), the remote marker may appear at the end of the previous line. This is a contentEditable limitation — <br> and <div> elements don't map cleanly to \n characters in the character index.

Fix needed: Custom character-index-to-DOM-position mapping that accounts for block-level elements. ProseMirror/TipTap use dedicated position mapping layers for this. Options:

  • Walk all DOM nodes (text + br + div + p) counting newlines
  • Use innerText offset mapping
  • Switch to a position-mapping library (e.g., prosemirror-state's TextSelection)

Workaround: Cursor works correctly for mid-line positions. Only the first character of each line may be off by one.

2. Awareness polling (2s latency)

Problem: Cursor positions update every 2 seconds via polling instead of real-time event push.

Fix needed: Handle CrdtAwarenessUpdate events in the client's onMessage handler (#52 optimization #2).

Plan

Phase 1: Real-time cursors and selections (DONE)

  • Remote cursor rendering in CollaborativeEditor
  • Colored caret + name label per user
  • FNV-1a hash for per-user colors (25-color palette)
  • Awareness polling (2s)
  • Initial presence send on work open
  • Selection cursor (stays at start of selected text)
  • Deduplication by user name

Phase 2: Change highlights and attribution

  • Recent change highlights (fade over 3-5s)
  • Per-character attribution colors (toggle)
  • Change markers in margin

Phase 3: Performance and latency

  • Event-based awareness (replace 2s polling)
  • Reduce debounce for faster text sync
  • Connection resilience (queue + reconnect)

Phase 4: Social presence

  • Global presence (see friends online)
  • Activity feed
  • Join a friend's work

Phase 5: Polish

  • Undo/redo awareness
  • Mobile responsive
  • Keyboard shortcuts

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions