Live cursors

Everyone on this page, and on the home page, shares one presence channel. Move over the canvas and your position goes straight to the other browsers.

Connecting

Move your pointer here, drag a finger, or focus the canvas and use the arrow keys.

Open a second window

How it works

The channel name starts with presence-, so joining needs a signature from a server that holds the app secret. This site's backend signs a name and a colour for each visitor; that data is what shows up in the member list.

Positions are client messages (opcode 8): the server relays them to the other members without calling your backend. They are sent as fractions of the canvas so pointers line up on any screen size, and throttled to one every 50 ms. The server rejects client messages that arrive less than 20 ms apart.

Read the presence guide

cursors.ts
const channel = pikoman.listenPresence("presence-cursors", authenticator);

// Fires on join and whenever someone arrives or leaves.
channel.members((members) => {
  for (const [id, { name, color }] of members) drawPointer(id, name, color);
});

// Client messages carry the sender's id first.
channel.on("move", (id, { x, y }) => movePointer(id, x, y));

canvas.addEventListener("pointermove", throttle((e) => {
  channel.send("move", toFraction(e));
}, 50));

We are rebuilding the dashboard

Self-service sign-up is closed while we do. Until the new dashboard is ready we set up apps by hand: write to us with a line about what you are building, and we will send you an app id and a secret.

Write to hello@pikoman.se