Sunday, 26 July 2026

LightDraw Diagram Engine: JSON In, Animated Visuals Out

Standard

Hi, this is part 2 of my LightDraw series. Last time we covered the big picture (dashboards, automotive, diagrams, UI). Today we go deep on one feature people keep asking about: diagram wire-flow animation, and how to drive every chart from plain JSON you can store, edit, or generate with AI.

By the end of this post you’ll be able to:

  • Describe a flowchart, pipeline, network, org chart, schematic, or UML class diagram as JSON
  • Pass that JSON to JavaScript and render it with LightDraw
  • Turn on path animation (dashes + packets + status tint) and use the built-in play/pause toolbar
  • Copy working examples without fighting a framework stack

Requires: lightdraw@1.2.1+ for the built-in diagram toolbar when flow.enabled is on.

The mental model (keep this)

Everything in this post follows the same three steps:

  1. Write a scene object: { type, props }
  2. Mount it: Diagram.fromJSON(type, props, app)app.add(chart)
  3. Optional polish: fitToBounds, editor, flow controls
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/lightdraw@1/dist/lightdraw.min.css">
<div id="app" style="position:relative; width:800px; height:480px;"></div>
<script src="https://cdn.jsdelivr.net/npm/lightdraw@1/dist/lightdraw.min.js"></script>
<script>
const app = LightDraw.createApp('#app', {
  width: 800,
  height: 480,
  renderer: 'canvas',
  background: '#0f172a',
});

function mountDiagram(scene) {
  app.clear();
  const chart = LightDraw.Diagram.fromJSON(scene.type, scene.props, app);
  app.add(chart);
  LightDraw.Diagram.fitToBounds(chart, 800, 480, 24);
  return chart;
}

// later: mountDiagram(yourScene);
</script>

That’s the whole contract. Your diagrams live as JSON. JS only loads and renders them.

1. Flowchart: decisions, paths, and motion

Figure: Flowchart with multi-path wire flow and status tint (idle → active → done).

A flowchart is nodes + edges. Animation is just an ordered list of node ids under flow.paths.

const flowchartScene = {
  type: 'flowchart',
  props: {
    width: 800,
    height: 480,
    data: {
      nodes: [
        { id: 'start', label: 'Start', type: 'start', x: 360, y: 24 },
        { id: 'check', label: 'Valid?', type: 'decision', x: 360, y: 110 },
        { id: 'process', label: 'Process', type: 'process', x: 360, y: 210 },
        { id: 'notify', label: 'Notify', type: 'process', x: 140, y: 210 },
        { id: 'end', label: 'Done', type: 'end', x: 360, y: 320 },
      ],
      edges: [
        { from: 'start', to: 'check' },
        { from: 'check', to: 'process', label: 'Yes' },
        { from: 'check', to: 'notify', label: 'No' },
        { from: 'process', to: 'end' },
        { from: 'notify', to: 'end' },
      ],
    },
    flow: {
      enabled: true,
      mode: 'both',          // 'dash' | 'packet' | 'both'
      playback: 'loop',      // or 'once'
      highlight: 'pulse',
      statusHighlight: true,
      speed: 1.5,
      pathGapMs: 400,
      paths: [
        ['start', 'check', 'process', 'end'],
        ['start', 'check', 'notify', 'end'],
      ],
    },
  },
};

mountDiagram(flowchartScene);

Tip: Status tint needs packet or both. Grey = not yet visited, yellow = current hop, green = done for this path run.

2. Process pipeline: CI / ETL stages

Figure: Process pipeline stages animating in order.

const pipelineScene = {
  type: 'processPipeline',
  props: {
    width: 800,
    height: 280,
    stages: [
      { id: 'ingest', label: 'Ingest', status: 'done', type: 'input' },
      { id: 'validate', label: 'Validate', status: 'done', type: 'test' },
      { id: 'build', label: 'Build', status: 'active', type: 'build' },
      { id: 'test', label: 'Test', status: 'pending', type: 'test' },
      { id: 'deploy', label: 'Deploy', status: 'pending', type: 'deploy' },
    ],
    flow: {
      enabled: true,
      mode: 'both',
      playback: 'loop',
      statusHighlight: true,
      path: ['ingest', 'validate', 'build', 'test', 'deploy'],
    },
  },
};

mountDiagram(pipelineScene);

Use a single path for one run, or paths: [['a','b'], ['a','c']] for alternating runs (same as flowchart).

3. Network topology: traffic between devices

Figure: Network icons with two traffic paths (edge → web, edge → API → DB).

const networkScene = {
  type: 'networkTopology',
  props: {
    width: 800,
    height: 400,
    data: {
      nodes: [
        { id: 'inet', label: 'Internet', type: 'cloud', x: 360, y: 24 },
        { id: 'fw', label: 'NGFW', type: 'ngfw', x: 360, y: 130 },
        { id: 'web', label: 'Web', type: 'server', x: 160, y: 260 },
        { id: 'api', label: 'API', type: 'server', x: 360, y: 260 },
        { id: 'db', label: 'SQL', type: 'sql_database', x: 560, y: 260 },
      ],
      edges: [
        { from: 'inet', to: 'fw' },
        { from: 'fw', to: 'web' },
        { from: 'fw', to: 'api' },
        { from: 'api', to: 'db' },
      ],
    },
    flow: {
      enabled: true,
      mode: 'both',
      playback: 'loop',
      paths: [
        ['inet', 'fw', 'web'],
        ['inet', 'fw', 'api', 'db'],
      ],
    },
  },
};

mountDiagram(networkScene);

Node type values map to a Visio/Cisco-style catalog (server, router, ngfw, sql_database, cloud, …). Perfect for NOC boards and security runbooks.

4. Animation properties & controls (the JSON knobs)

Figure: Built-in toolbar (▶⏸↻ + zoom + Fit) with path status tint.

All of these live under props.flow and round-trip with Diagram.toJSON / fromJSON:

PropertyValuesWhat it does
enabledtrue / falseStart wire-flow animation
modedash · packet · bothMarching dashes, traveling dot, or both
playbackloop · onceRepeat forever, or play then pause
paths / patharray of node idsOrdered hops to animate
speednumber (e.g. 1.5)Playback rate
pathGapMsmsPause between path runs
highlightpulse · breathe · flash · noneMotion chrome on active hops
statusHighlightboolIdle / active / done color tint
statusColorsobjectOverride idle/active/done/error colors
chrometrue (default) / falseShow ▶⏸↻ + zoom overlay

Control from JS (same chart you mounted):

LightDraw.Diagram.applyFlow(app, chart, { /* same options as flow */ });
LightDraw.Diagram.pauseFlow(app, chart);
LightDraw.Diagram.resumeFlow(app, chart);
LightDraw.Diagram.toggleFlowPause(app, chart);
LightDraw.Diagram.replayFlow(app, chart);
LightDraw.Diagram.stopFlow(chart);

// Manual toolbar if you disabled chrome in JSON:
// LightDraw.Diagram.installToolbar(app, chart);
// LightDraw.Diagram.uninstallToolbar(chart);

Give the host #app { position: relative; } so the toolbar overlays correctly.

5. Org chart: hierarchy from a nested tree

Figure: Org chart rendered from a nested root JSON tree.

No edges array here, just a tree. Same mount helper.

const orgScene = {
  type: 'orgChart',
  props: {
    width: 900,
    height: 480,
    root: {
      name: 'Alex Rivera',
      role: 'CEO',
      children: [
        {
          name: 'Sam Chen',
          role: 'CTO',
          department: 'Engineering',
          children: [
            { name: 'Priya N.', role: 'Platform Lead' },
            { name: 'Jordan K.', role: 'Frontend Lead' },
          ],
        },
        {
          name: 'Morgan Lee',
          role: 'CFO',
          department: 'Finance',
          children: [{ name: 'Riley P.', role: 'Controller' }],
        },
        { name: 'Casey Brooks', role: 'COO', department: 'Ops' },
      ],
    },
  },
};

mountDiagram(orgScene);

// Optional: drag / resize / collapse in the editor
LightDraw.Diagram.installEditor(app, chart, {
  mode: 'arrange',
  allowResize: true,
});

6. Schematic diagram: IEC symbols as JSON

Figure: Battery → switch → resistor → LED → ground from a component list.

const schematicScene = {
  type: 'electricalSchematic',
  props: {
    width: 800,
    height: 360,
    components: [
      { id: 'bat', type: 'battery', x: 80, y: 120, label: 'BAT' },
      { id: 'sw', type: 'spst', x: 220, y: 120, label: 'S1' },
      { id: 'r1', type: 'resistor', x: 360, y: 120, label: 'R1' },
      { id: 'led', type: 'led', x: 500, y: 120, label: 'D1' },
      { id: 'gnd', type: 'ground', x: 500, y: 220, label: 'GND' },
    ],
  },
};

mountDiagram(schematicScene);

Symbol kinds come from the IEC catalog (spst, nmos, opAmp, led, …). Discover them with LightDraw.Diagram.listSchematicSymbols().

7. UML class diagram: structure + animated relations

Figure: Class boxes with inheritance paths animated for a walkthrough.

const umlScene = {
  type: 'classDiagram',
  props: {
    width: 800,
    height: 400,
    data: {
      classes: [
        { id: 'drawable', name: 'Drawable', x: 80, y: 40, methods: ['draw()'], stereotype: 'interface' },
        { id: 'shape', name: 'Shape', x: 360, y: 40, attrs: ['id: string'], methods: ['draw()'] },
        { id: 'rect', name: 'Rect', x: 220, y: 240, attrs: ['w', 'h'], methods: ['draw()'] },
        { id: 'circle', name: 'Circle', x: 520, y: 240, attrs: ['r'], methods: ['draw()'] },
      ],
      relations: [
        { from: 'shape', to: 'drawable', type: 'realization' },
        { from: 'rect', to: 'shape', type: 'inheritance' },
        { from: 'circle', to: 'shape', type: 'inheritance' },
      ],
    },
    flow: {
      enabled: true,
      mode: 'both',
      playback: 'loop',
      paths: [
        ['rect', 'shape', 'drawable'],
        ['circle', 'shape', 'drawable'],
      ],
    },
  },
};

mountDiagram(umlScene);

Load JSON from a file or API

Because the scene is just data, you can keep charts next to configs:

// From a static file
const scene = await fetch('/scenes/onboarding-flow.json').then((r) => r.json());
mountDiagram(scene);

// Or via the app helper when the diagram plugin is registered
app.loadJSON(scene);

// Round-trip after the user edits in the canvas
const saved = LightDraw.Diagram.toJSON(chart);
localStorage.setItem('my-diagram', JSON.stringify(saved));

This is why LightDraw works well for AI agents and config-driven UIs: the agent emits JSON; your page only mounts it.

Quick reference: diagram type values

typeKey propsWire flow?
flowchartdata.nodes, data.edgesYes
stateMachinedata.states, data.transitionsYes
processPipelinestages[]Yes
networkTopologydata.nodes, data.edgesYes
canNetworkdata.ecus, data.busLabelYes (virtual bus hops)
classDiagramdata.classes, data.relationsYes
orgChartroot treeNo
electricalSchematiccomponents[]No
mindMapcenter, branchesNo

Try it yourself

  1. npm install lightdraw or drop the CDN script from the top of this post
  2. Copy any scene JSON above into mountDiagram(scene)
  3. Open the live diagram playground: rakeshrajena.github.io/lightDraw/#diagram
  4. Read the flow guide: docs/diagram-flow.md

If this helped, tell me which diagram type you want next (CAN bus walkthrough, mind maps, or exporting animated scenes for docs). Part 1 introduced the library; this part should be enough to ship a real animated diagram from JSON alone.

LightDraw · zero-dependency · JSON-first graphics for the browser