editordocs · v0.1.0
reference

Animation primitives

The four motion building blocks remaid ships in v0.1, with the visual semantics each one is meant to communicate.

Animation in remaid is composed from a small number of primitives. They were chosen because each one corresponds to a specific kind of system story you would want to tell: data in flight, arrival, fan-out, recovery. Layered together, they cover the majority of architecture diagrams in tech writing.

packet-flow

A small dot travels from the source node to the target node along the edge. The visual statement is “a piece of data is in transit.” This is the most common primitive and the one to reach for first.

diagram "packet-flow" {
  node a { kind: client }
  node b { kind: service }
  edge req: a -> b { label: "GET /users" }

  scene s {
    loopEvery: 1.5s
    packet-flow req { speed: 700ms }
  }
}
packet-flowDiagram with 2 nodes and 1 edge.GET /usersab
A request traveling from client to API.

Syntax

packet-flow <edge-id> [{ speed: <duration>, after: <edge-id>, delay: <duration> }]

pulse

A ring expands outward from the target node and fades. The visual statement is “something just arrived here.” Use it as a beat after a packet-flowto communicate “and the cache responded.”

diagram "pulse" {
  node a { kind: service, label: "API" }
  node b { kind: cache,   label: "Redis" }
  edge get: a -> b { label: "GET" }

  scene s {
    loopEvery: 1500ms
    packet-flow get { speed: 400ms }
    pulse       get { speed: 500ms, after: get }
  }
}
pulseDiagram with 2 nodes and 1 edge.GETAPIRedis
A GET request arrives at Redis (the ring) right after the packet lands.

Syntax

pulse <edge-id> [{ speed: <duration>, after: <edge-id>, delay: <duration> }]

Note: pulsetakes an edge id, not a node id, and the ring is drawn at that edge's target node. This keeps the syntax consistent with every other primitive.

replication-sync

Multiple packets fan out across all listed edges in lockstep. The visual statement is “this data goes to every destination simultaneously.” Most useful for replication, broadcast, and publish-subscribe scenarios.

diagram "replication-sync" {
  direction: down
  node primary  { kind: database, label: "Primary" }
  node replicaA { kind: database, label: "Replica A" }
  node replicaB { kind: database, label: "Replica B" }

  edge wal_a: primary -> replicaA { label: "WAL" }
  edge wal_b: primary -> replicaB { label: "WAL" }

  scene s {
    loopEvery: 2s
    replication-sync wal_a, wal_b { speed: 600ms }
  }
}
replication-syncDiagram with 3 nodes and 2 edges.WALWALPrimaryReplica AReplica B
WAL streaming from primary to two replicas at once.

Syntax

replication-sync <edge-id>, <edge-id> [, <edge-id>...] [{ speed: ... }]

failover

Visualises a path failing and a backup taking over. Takes exactly two edge ids: the failing path (rendered as a rose-tinted pulse on its target) and the recovery path (a packet flow on the second edge). Both plays inside the step's duration.

diagram "failover" {
  node api     { kind: service,  label: "API" }
  node primary { kind: database, label: "Primary" }
  node standby { kind: database, label: "Standby" }

  edge toPrimary: api -> primary
  edge toStandby: api -> standby

  scene s {
    loopEvery: 3.5s
    packet-flow toPrimary             { speed: 500ms }
    failover    toPrimary, toStandby  { speed: 1s, after: toPrimary }
    packet-flow toStandby             { speed: 500ms, after: toStandby }
  }
}
failoverDiagram with 3 nodes and 2 edges.APIPrimaryStandby
The primary fails (rose pulse), the standby picks up traffic.

Syntax

failover <failed-edge>, <recovery-edge> [{ speed: ... }]

Chaining steps with `after`

after: <edge-id> chains a step to the most recent step that animated that edge in the same scene. This is how you build sequential narratives: request → query → response.

diagram "chained" {
  node web { kind: client }
  node api { kind: service }
  node db  { kind: database }

  edge req:   web -> api
  edge query: api -> db
  edge ack:   api -> web

  scene s {
    loopEvery: 3s
    packet-flow req   { speed: 500ms }
    packet-flow query { speed: 700ms, after: req }
    packet-flow ack   { speed: 400ms, after: query }
  }
}
chainedDiagram with 3 nodes and 3 edges.webapidb
Three steps chained sequentially.

Running steps in parallel

Steps without an after property all start at scene t=0. Use this when two things should happen simultaneously: a write fanning out to a database and an event queue, for example.

diagram "parallel fan-out" {
  node api  { kind: service }
  node db   { kind: database }
  node mq   { kind: queue, label: "Events" }

  edge persist: api -> db
  edge publish: api -> mq

  scene s {
    loopEvery: 2s
    packet-flow persist { speed: 600ms }
    packet-flow publish { speed: 600ms }
  }
}
parallel fan-outDiagram with 3 nodes and 2 edges.apidbEvents
Two steps without `after`. Both fire at the same moment.

Choosing durations

Durations are arbitrary, but a few rules of thumb help diagrams read well:

  • 300-500ms for short hops (cache lookups, in-process calls).
  • 600-900ms for typical network requests.
  • 1-2s for slow paths or to emphasise weight (cold-start, retry, long-running query).
  • Set loopEvery to roughly 1.5x the natural duration so the scene has a moment of stillness before repeating.