Skip to content
kerfjsGitHub

Cursors

Other people's pointers, with their names, over a shared document.

SourcePackage @kerf-js/veneer

Preview

tsx
import { onCleanup, onMount, state } from '@kerf-js/core'import {  Cursors,  Heading,  Stack,  Text} from '@kerf-js/veneer'import type { CursorPeer } from '@kerf-js/veneer'import type { Peer } from '@kerf-js/veneer'export function Document() {  const peers = state<CursorPeer[]>(CURSOR_PEERS)  onMount(() => {    let tick = 0    const timer = setInterval(() => {      tick++      peers.value = CURSOR_PEERS.map((p, i) => ({        ...p,        cursor: {          ...p.cursor!,          x: 0.2 + 0.6 * Math.abs(Math.sin(tick / 2 + i)),        },      }))    }, 1400)    onCleanup(() => clearInterval(timer))  })  return (    <Stack      gap="related"      style="position:relative"    >      <div data-anchor="title">        <Heading level={3}>Rollback runbook</Heading>      </div>      <div data-anchor="body">        <Text subtle>          When a deploy fails its health check, roll back          first and read the logs second. A failed deploy          never blocks the next one, and the person on          call owns the call.        </Text>      </div>      <Cursors        peers={peers}        idle={3600000}      />    </Stack>  )}const PEOPLE = [  {    id: 'mara',    name: 'Mara Lindqvist',    email: 'mara@kerf.dev',    role: 'Owner',    team: 'Platform',    initials: 'ML',  },  {    id: 'jun',    name: 'Jun Tanaka',    email: 'jun@kerf.dev',    role: 'Admin',    team: 'Platform',    initials: 'JT',  },  {    id: 'priya',    name: 'Priya Raman',    email: 'priya@kerf.dev',    role: 'Member',    team: 'Web',    initials: 'PR',  },  {    id: 'tomas',    name: 'Tomás Oliveira',    email: 'tomas@kerf.dev',    role: 'Member',    team: 'Web',    initials: 'TO',  },  {    id: 'lena',    name: 'Lena Fischer',    email: 'lena@kerf.dev',    role: 'Member',    team: 'Data',    initials: 'LF',  },  {    id: 'noor',    name: 'Noor Haddad',    email: 'noor@kerf.dev',    role: 'Viewer',    team: 'Data',    initials: 'NH',  },  {    id: 'sam',    name: 'Sam Okafor',    email: 'sam@kerf.dev',    role: 'Member',    team: 'Mobile',    initials: 'SO',  },  {    id: 'ines',    name: 'Inés Vidal',    email: 'ines@kerf.dev',    role: 'Viewer',    team: 'Mobile',    initials: 'IV',  },]const PEERS: Peer[] = PEOPLE.map((p, i) => ({  id: p.id,  name: p.name,  color: i + 1,}))const [  MARA,  JUN,  PRIYA,  TOMAS,  LENA,  NOOR,  SAM,  INES,] = PEERS as [  Peer,  Peer,  Peer,  Peer,  Peer,  Peer,  Peer,  Peer,]const CURSOR_PEERS: CursorPeer[] = [  {    ...JUN,    cursor: { anchor: 'title', x: 0.42, y: 0.8 },  },  {    ...LENA,    cursor: { anchor: 'body', x: 0.7, y: 0.35 },  },  {    ...SAM,    cursor: { anchor: 'body', x: 0.22, y: 0.85 },  },]

Installation

npm install @kerf-js/veneer

Usage

tsx
import { Cursors } from '@kerf-js/veneer'

Accessibility

  • The layer is hidden from assistive tech. PresenceStack says who is here.

API Reference

PropTypeDefaultDescription
peersLive<CursorPeer[]>—People and where their cursors are.
anchorstring—Limits the cursors to one anchor.
idlenumber5000Milliseconds before a still cursor fades.

RelatedPeer markPeer selectionPresence stack