Introduction

cloud-arch

cloud-arch is a browser-based tool for visualizing and explaining distributed system architectures through animated, code-driven diagrams.

Instead of dragging boxes on a canvas, you write a short TypeScript script that describes your topology and how data flows through it. The result is a live, zoomable, fully animated diagram — shareable via URL, diffable in version control, and precise enough for real production systems.

Key features

Code-first diagrams

Every diagram is a plain TypeScript script. No proprietary format, no drag-and-drop state. You describe what exists (groups, nodes, connections) and the renderer figures out the layout.

const topology = new TopologyBuilder(true);
 
const backend = topology.createGroup('backend', {
  label: 'Backend Services'
}, { x: 200, y: 100 });
 
backend
  .addProcess({ id: 'api', label: 'API Server', state: 'running' })
  .addProcess({ id: 'db', label: 'PostgreSQL', shape: 'cylinder', state: 'running' })
  .autoResize();
 
topology.connect('api', 'db', { protocol: 'postgresql', label: 'SQL' });
 
await topology.apply();
return null;

Animated data flow

Each script can define multiple animation scenarios showing how packets travel through the system — with explanatory messages at each hop. Scenarios run in the browser with play/pause/replay controls.

const flow = new FlowBuilder();
 
flow.scenario('happy-path', 'Normal Request', 'End-to-end success');
flow
  .from('client')
  .showMessage('[REQUEST] GET /api/users/42')
  .to('api')
  .showMessage('[PROCESS] Auth passed. Querying user.')
  .to('db')
  .showMessage('[QUERY] SELECT * FROM users WHERE id = 42')
  .from('db').to('api')
  .showMessage('[ROW] User found: {id:42, name:"Alice"}')
  .from('api').to('client')
  .showMessage('[200 OK] Response delivered in 12ms');
 
return flow;

Progressive layers

A single script can represent multiple views of the same system — MVP vs highload, v1 vs v2 vs v3. Layer pills in the top-right corner of the canvas let users toggle groups, nodes, and edges in and out of view without switching scripts.

// Node only visible when 'highload' layer is active
group.addProcess({
  id: 'cassandra',
  label: 'Cassandra Cluster',
  shape: 'cylinder',
  layer: 'highload',
  state: 'running'
});

Quick example

Here is a minimal working script — topology plus a two-scenario animation:

my-system.ts
const topology = new TopologyBuilder(false);
 
const clientGroup = topology.createGroup('clients', {
  label: 'Clients'
}, { x: 300, y: 40 });
 
clientGroup
  .addProcess({ id: 'browser', label: 'Browser', state: 'running' })
  .autoResize();
 
const serverGroup = topology.createGroup('server', {
  label: 'Backend'
}, { x: 300, y: 220 });
 
serverGroup
  .addProcess({ id: 'api', label: 'REST API', state: 'running' })
  .addProcess({ id: 'pg', label: 'PostgreSQL', shape: 'cylinder', state: 'running' })
  .autoResize();
 
topology.connect('browser', 'api', { protocol: 'http', label: 'REST' });
topology.connect('api', 'pg', { protocol: 'postgresql', label: 'SQL' });
 
await topology.apply();
 
const flow = new FlowBuilder();
 
flow.scenario('success', 'Happy Path');
flow
  .from('browser').to('api')
  .showMessage('[GET] /api/data')
  .to('pg')
  .showMessage('[QUERY] SELECT ...')
  .from('pg').to('api')
  .showMessage('[ROWS] 42 records returned')
  .from('api').to('browser')
  .showMessage('[200 OK] Data delivered');
 
flow.scenario('error', 'Database Timeout');
flow
  .from('browser').to('api')
  .showMessage('[GET] /api/data')
  .to('pg')
  .showError('[TIMEOUT] No response after 30s')
  .from('api').to('browser')
  .showError('[503] Service unavailable');
 
return flow;

Scripts run as plain JavaScript in the browser sandbox. No import or export — classes like TopologyBuilder and FlowBuilder are injected as globals automatically.

Next steps