Introduction

Collabs is a collections library for collaborative data structures. These are data structures that look like Set, Map, Array, etc., except they are synchronized between multiple users: when one user changes a collaborative data structure, their changes show up for every other user.

We call each collaborative data structure a Collab, for short.

Example: Counter

The Quick Start uses a CCounter Collab. This is an object with a simple numeric API:

class CCounter {
  add(toAdd: number): void;
  get value(): number;
  // ...
}

But unlike an ordinary number, when one user calls counter.add(1), 1 is added to every user’s counter.value, not just theirs. If multiple users call counter.add(1) at the same time, all of their additions go through, increasing their shared value by the total number of calls. In this way, everyone eventually ends up seeing the same counter.value, as you’d expect.

You can try this out in the live demo: open it in multiple tabs, then watch how incrementing the value in one tab also increments the value in the other. This also works if you open the tabs on different devices, since they are connected through our demo server.

You can also try disconnecting one tab by unchecking the box at the top. Verify that if you disconnect one tab, increment both tabs, and reconnect, then both increments go through.

Example: Whiteboard

Our whiteboard demo uses a map Collab to store the board state. Specifically, it uses a CValueMap that maps each coordinate [x, y] to its color:

const boardState: CValueMap<[x: number, y: number], Color>;

Once boardState is initialized (discussed later in Documents), you can use it like an ordinary Map<[x: number, y: number], Color>:

class CValueMap<K, V> {
  get(key: K): V | undefined;
  has(key: K);
  set(key: K, value: V): V; // Returns the set value
  entries(): IterableIterator<[K, V]>;
  // ...
}

In particular, when a user draws with color on pixel [x, y], the demo calls boardState.set([x, y], color). You can display the current board by iterating over boardState.entries():

function repaint(ctx: CanvasRenderingContext2D) {
  // Clear old state.
  ctx.fillStyle = "white";
  ctx.fillRect(0, 0, WIDTH, HEIGHT);

  // Draw current state.
  for (const [[x, y], [r, g, b]] of boardState.entries()) {
    ctx.fillStyle = `rgb(${r},${g},${b})`;
    ctx.fillRect(x, y, 1, 1);
  }
}

As an optimization, you can also render changes incrementally, by handling Collab events.

More Collaborative Data Structures

Collabs comes with more collaborative data structures built-in. Fancy ones include CRichText for rich text, and CList for a list of other Collabs. See Built-in Collabs for a summary.

For complex apps, you might want to organize your collaborative state into reusable classes. Data Modeling explains how to do this, by making your own Collab that encapsulates existing Collabs in a custom API - a unique feature of our library.

Using Collabs

Collaborative data structures require a bit more setup than local ones, to make them actually collaborative. The steps are:

  1. Create a document holding your Collabs.

  2. Handle changes to your Collabs, so that when a remote collaborator changes the collaborative state, you update the local display.

  3. Configure network and storage providers that keep your Collabs in sync with remote collaborators and persistent storage.

We go over these steps in the next three pages of the Guide.

Next Steps

Continue following the Guide with Documents.

Or, use the Quick Start to get started with an app template.