0013 · Presence: waves, raised hands, status notes, minimap and touch controls
- Status: accepted (2026-09-30)
#Context
In a busy office you need to reach somebody who is not next to you without opening a chat, see at a glance where people gather, signal that you want to speak, and say what you are doing. People on phones and tablets had no way to move.
#Decision
- Wave (
wave->wv/wvr): a ping to anyone online, anywhere. The receiver gets a card with "Walk to them" (a server-routed run, see decision 0012) and "Wave back". Busy (do not disturb) and away people are not disturbed and the sender is told why; invisible players can neither wave nor be waved at (it would reveal them). 2 s cooldown per sender. - Raised hand and status note are roster fields (
h,m), so they reuse the existing roster delta: no new broadcast path. The note is one line of at most 60 characters, cleaned on the server, kept in memory only (the client re-sends its own note after reconnecting) and never logged. - Dance is emote 8: the same rate-limited, area-of-interest fan-out as the other reactions, animated on each client.
- Minimap: the client redraws a thumbnail of the already baked map four times a second (not per frame, not through React state) with the people it already knows about (its area of interest) and per-area head counts from the server (
ac). Counts are computed every 2 s and sent only when they change, so the minimap shows busy places across the office without an office-wide position feed. Clicking it runs there. - Cues: synthesised chimes for waves, knocks and direct messages (no audio assets), and opt-in desktop notifications that only fire while the tab is hidden and never include message text.
- Touch pad: an on-screen direction pad and run toggle shown on coarse-pointer devices.
- Announcements: administrators send a one-line banner to everybody online through
POST /api/admin/announce(admin API: authenticated, rate limited, audited). The audit row records that an announcement was made, never its text, and the text is not stored. - Per-person volume: each call tile has a local volume control (100 %, 50 %, muted for me). It only changes playback on that device (LiveKit participant volume) and never affects what others hear or what the SFU forwards.
- Keyboard help:
?(or the topbar button) lists every shortcut.
#Consequences
- Performance: head counts cost one pass over the players every 2 s and one short message per player per change; waves, hands and notes are rare control messages. The minimap reuses the baked map canvas.
- Privacy: notes are presence, like names, and visible to the office; no message text leaves the page in notifications.
- Maintenance: world tests cover waves (delivery, cooldown, busy, invisible), roster fields, note cleaning, head-count publication and the dance emote; the
presencebrowser scenario covers every UI path including the touch pad on an emulated phone.