asopi tech
asopi techIndie Developer

Asopitech With · Design tool

Figma multiplayer with Alopex Chirps

Figma multiplayer is how Figma, the design tool, lets several people edit the same design at once. What if we rebuilt it by applying Alopex Chirps?

Updated: Oct 13, 2026

What the service does

In Figma, several people edit the same design document at once. According to Figma’s engineering blog, clients talk to a cluster of servers over WebSockets, a separate process runs for each document, and everyone editing that document connects to it. The server keeps the latest value sent for each property of each object. The data is the document’s tree of objects and each person’s cursor and selection.

How the communication is built

  • Node membership: the servers that host documents join the mesh as nodes. Through gossip, every node knows which nodes are running.
  • Forwarding edits: edits from people connected to another node are sent, addressed, to the node that hosts the document.
  • Cursor delivery: cursor and selection positions are sent on the ephemeral delivery profile, which tolerates staleness. They flow separately from edits.
  • Node departure: when the node hosting a document stops, a leave event arrives, and another node can reopen the document.

Which node hosts which document, and how property values are decided, are the application’s code.

Deployment

Chirps is embedded in each server node. Nodes connect over QUIC with mutual TLS.

Why Alopex Chirps fits

A multiplayer server carries two flows of different nature: edits that must arrive and cursors that can be thinned out. Chirps sends them on separate delivery profiles, and reports nodes joining and leaving through gossip.

See it in code

A hybrid logical clock gives a consistent order to edits across nodes. Just the core (Rust).

use alopex_chirps_gossip_swim::hlc::{Clock, LocalHlc};
use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::Arc;
use std::time::Duration;

// 説明用の手動クロック(実際はシステム時計)
struct ManualClock(AtomicU64);
impl Clock for ManualClock {
    fn now_millis(&self) -> u64 {
        self.0.load(Ordering::SeqCst)
    }
}

fn main() {
    let skew = Duration::from_secs(1);
    // 文書を受け持つ 2 つのノード A / B。それぞれ論理時計を持つ
    let mut a = LocalHlc::with_clock(skew, Arc::new(ManualClock(AtomicU64::new(100))));
    let mut b = LocalHlc::with_clock(skew, Arc::new(ManualClock(AtomicU64::new(90))));

    // A 側で編集が起きるたびに時計を進める
    let edit1 = a.tick();
    let edit2 = a.tick();
    println!("A: edit1={edit1:?} edit2={edit2:?}");

    // A の編集を B が受け取ると、B の時計は A を追い越す
    let seen = b.receive(edit2).expect("receive");
    println!("B receives A: {seen:?}");

    // その後 B 側で起きた編集は、必ず A の編集より後に順序づく
    let b_edit = b.tick();
    println!("B next: {b_edit:?}");
    assert!(b_edit > edit2);
    println!("OK: どのノードも、オブジェクトの編集を同じ順序で適用できる");
}

A consistent order across nodes means the last value per property agrees for everyone. Splitting edit versus cursor delivery is handled by Chirps, as the prose describes.

Build a multiplayer server with Alopex Chirps, sending edits and cursors between nodes on separate delivery profiles. Start from the quickstart on GitHub.