Your first vanilla graph
This tutorial creates a Graphora view without a framework. It uses local workspace packages because Graphora is not published to npm.
Expected result: three blue nodes in a circle, with arrows from Gateway to Orders and from Orders to Database.
Open the live Vanilla tutorialPreview availability
Requires repository access, Node.js 22.13+ and pnpm 11.7.0 for local setup. Packages are not published to npm. Project status.
1. Prepare the workspace
From an authorized source checkout:
cd graph-library
pnpm install --frozen-lockfile
pnpm buildThe workspace already contains this runnable tutorial. The files below are included directly from its source; you can run them without copying. Inspect examples/vanilla/first-graph/index.html, examples/vanilla/first-graph/src/style.css, and examples/vanilla/first-graph/src/main.ts using the three snippets below. Keep the checked-in examples/vanilla/vite.config.ts; it resolves the local workspace packages.
2. Give the graph a real size
The renderer reads the container dimensions when it mounts. A container with no height produces no useful drawing area.
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Graphora service dependencies</title>
</head>
<body>
<h1>Service dependencies</h1>
<div id="graph" aria-label="Service dependency graph"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>html,
body {
width: 100%;
height: 100%;
margin: 0;
}
#graph {
min-height: 360px;
}
#graph,
#root {
height: 360px;
}
body {
font-family: system-ui, sans-serif;
background: #f8fafc;
color: #0f172a;
}
h1 {
font-size: 1rem;
margin: 12px 16px;
}3. Create, mount, lay out, and destroy the engine
import { createGraphEngine } from '@graphora/engine'
import { createCircularLayout } from '@graphora/layouts'
import { CanvasGraphRenderer, createViewport } from '@graphora/renderer'
import './style.css'
const container = document.querySelector<HTMLDivElement>('#graph')
if (container === null) {
throw new Error('Missing graph container.')
}
const engine = createGraphEngine({
graph: {
nodes: [
{ id: 'gateway', label: 'Gateway' },
{ id: 'orders', label: 'Orders' },
{ id: 'database', label: 'Database' }
],
edges: [
{
id: 'gateway-orders',
source: 'gateway',
target: 'orders',
directed: true
},
{
id: 'orders-database',
source: 'orders',
target: 'database',
directed: true
}
]
},
renderer: new CanvasGraphRenderer(),
layout: createCircularLayout({ radius: 120 }),
viewport: createViewport({
width: container.clientWidth,
height: container.clientHeight
}),
theme: {
backgroundColor: '#f8fafc',
node: { fill: '#2563eb', radius: 22 },
edge: { stroke: '#64748b', strokeWidth: 2, arrow: { end: true } },
label: { visible: true, fill: '#0f172a', fontSize: 13 }
}
})
engine.mount(container)
window.addEventListener('pagehide', () => engine.destroy(), { once: true })
void engine
.runLayout({ fitToView: { padding: 48 } })
.catch((error: unknown) => {
engine.destroy()
console.error(error)
})The viewport starts with the container's current size. The engine also observes later container resizes when ResizeObserver is available. runLayout() applies all returned positions and fits their bounds with 48 CSS pixels of padding. destroy() disconnects resize observation, cancels pending renders, unsubscribes engine listeners, and destroys the renderer.
4. Run it
The checked-in example can be started from graph-library/:
pnpm exec vite examples/vanilla/first-graph \
--config examples/vanilla/vite.config.tsMake your first change
In src/main.ts, change the theme's node fill from #2563eb to #0f766e and save. Vite refreshes the page: all three nodes become teal, while their labels and connections stay the same. This changes the default node color; item styles can override individual nodes.
Your graph should show Gateway → Orders → Database. If the canvas is empty, check the container height and browser console; see blank canvas troubleshooting.
Continue with your own graph
- Load your own data: replace the sample nodes and edges.
- Choose a layout: change how nodes are arranged.
- Style nodes and edges: encode meaning with color.
- Add interactions: select, drag, pan and zoom.
For exact methods and option types, use GraphEngine, CanvasGraphRenderer, and RawGraph in the API reference.