watershed Collaborative data structures for Gleam

← watershed · Data structures / Sequences

Sequences

Ordered lists that stay ordered while everyone rearranges them.

Order is the hardest thing to agree on. An index is only meaningful against one version of a list. The moment two people insert, move, or delete concurrently, “position 3” names different items on different screens.

Sequences resolve that by giving every item a stable identity beneath its index. Positions are how you address an edit; identities are how edits merge. Concurrent inserts at one spot both land, a move follows the item rather than the slot, and every replica converges on the same order.

SharedSequence

CRDT
sequence_kernel

An ordered list many people can edit at once: insert, move, and reorder without losing anyone’s changes.

Open the live SharedSequence demo →

A shared sequence holds an ordered list of JSON values. You address an edit by index (insert at 2, move 4 to 1), but the index only records intent. Underneath, every item has a stable identity, and the CRDT delta that ships is expressed against identities, not positions. Two replicas can therefore edit the same region concurrently and still converge: a move follows the item it named rather than whatever later occupies its slot, and two inserts at one position both survive in a deterministic order.

The lattice merge is duplicate- and order-tolerant: a delta delivered twice, or after its neighbors, is absorbed without disturbing the list. Local edits apply optimistically and ride the sequenced stream as deltas; if the server rejects one, it rolls back and the remaining pending edits replay over the sequenced base.

Replace is composed rather than native: it deletes the visible item and inserts the replacement at the same position as one collaborative operation (one pending entry, one wire op, one event). The identity-CRDT design and wire format are watershed’s own.

Best for

  • Shared itineraries, checklists, and ordered plans edited by many hands
  • Reorderable collections (playlists, priority queues, kanban lanes) where a move must not clobber a concurrent edit
  • The ordered substrate beneath SharedText, the collaborative plain-text DDS built on the same identity lattice
Merge rule
each item keeps a stable identity, so concurrent inserts, moves, and deletes merge instead of fighting over index numbers
Optimistic behavior
your edit shows immediately in magenta; items slide when the sequenced order lands
Summary shape
the sequenced list reloads intact; pending edits replay on top
Model
Conflict-free replicated data type: converges by merge

SharedText

CRDT
text_kernel

A string many people can type into at once: insert, delete, and replace characters without losing anyone’s keystrokes.

Open the live SharedText demo →

A shared text holds an ordered run of graphemes (user-perceived characters). You address an edit by grapheme index (insert at 6, delete 3..7, replace 0..5), but the index only records intent against your current view. Underneath, every grapheme has a stable identity, and the CRDT delta that ships is expressed against those identities, not offsets. Two typists can therefore edit the same word concurrently and still converge: an insertion lands beside the grapheme it named, and two insertions at one gap both survive in a deterministic order.

Indexing is by grapheme, never by UTF-16 code unit. An emoji like 👨‍👩‍👧 or a combining sequence like é (e + ◌́) is one grapheme, one index, one identity. A cursor never splits a family emoji or strands a combining mark. The demo computes each edit as a single minimal grapheme span using Intl.Segmenter, so a keystroke becomes one insert, delete, or replace rather than a churn of code-unit diffs.

Local edits apply optimistically and ride the sequenced stream as deltas; the visible string updates the instant you type. If the server rejects one it rolls back, and the remaining pending edits replay over the sequenced base. Replace is one collaborative operation (delete the span, insert the replacement at the same place), so it is a single pending entry, one wire op, one event, even across a range.

Anchors are stable positions that survive concurrent edits: pin one to a grapheme’s identity, keep editing around it, and resolve it back to a live index later. They are the basis for shared cursors and selections that don’t drift when a neighbor inserts. The delta format is watershed’s own, built on the same identity lattice as SharedSequence rather than Fluid’s SharedString merge tree.

Best for

  • Collaborative notes, captions, and comment fields edited by many hands at once
  • Live-typed labels and single-line fields where two people may touch the same word
  • Anything needing shared cursors or selections that stay put as neighbors type (anchors track identities, not offsets)
Merge rule
every grapheme keeps a stable identity, so concurrent insertions and overlapping edits merge instead of fighting over character offsets
Optimistic behavior
your keystroke shows immediately in magenta; the text reflows when the sequenced order lands
Summary shape
the sequenced string reloads intact; pending edits replay on top
Model
Conflict-free replicated data type: converges by merge