@drawmotive/textgraph
v0.3.1
Published
Render TextGraph flowcharts and directed graphs as PNG images in Node.js, browsers, React, and Web Workers.
Maintainers
Readme
TextGraph
Turn text into diagrams in your application.
Render flowcharts and directed graphs as PNGs or SVGs in Node.js, browsers, React, and Web Workers. TextGraph handles automatic layout and provides source validation and rendering diagnostics. The renderer runs where your code runs; no hosted rendering API or API key is required.
Documentation · Runnable examples · API reference
A few lines. A diagram.
(horizontal)
checkout(primary): Checkout {
pay -> payment
payment ->(dashed warning) pay : No, retry
}
fulfillment(success): Fulfillment {
ship -> delivered
email
}
payment -> ship : Yes
payment -> email : Yes
pay: Pay for order
payment(diamond fill primary): Paid?
ship: Ship order
email: Email receipt
delivered(ellipse fill success): Delivered
Open the full diagram · Copy the source · Try this diagram
For Chinese, Japanese, and color emoji, see the packaged font examples.
Keep source in version control and render again when relationships change. TextGraph uses a small, structured language; it does not interpret unrestricted prose.
Connections inside a group introduce that group's local nodes; no separate
member list is needed. Group bodies also allow bare members, nested groups
and comments. Connections can style their endpoints inline, such as
browse(ellipse) -> checkout. Keep standalone node labels or styles at the
root, in any order. At the root, a short name such as payment finds the
node when that name is unique in the diagram.
shopping(info): Shopping {
browse -> checkout
}
backend: Backend {
payment -> saved
}
checkout -> payment
checkout: Place an order
payment(diamond): Payment accepted?Here payment and backend.payment both refer to the backend node. Root
connections and decorations keep its containment, even when they appear
before the groups. An ungrouped node needs no separate declaration: a root
arrow or decoration can introduce it.
The same name in two groups creates two nodes. Inside each group, short names refer to its local nodes. At the root, use a group prefix only when needed to distinguish matches:
Review { submit -> done }
Delivery { pack -> done }
Review.done -> pack
submit: Place an order
Review.done: Approved
Delivery.done: Delivereddone at the root is ambiguous and reports the matching qualified names.
Group endpoints prefer a local member or group, then a unique declared group
elsewhere. Ambiguous group names need a prefix. Nested names can use a unique
suffix:
with Outer { Backend { payment } }, payment, Backend.payment and
Outer.Backend.payment all work when they identify a single object. A
qualified connection endpoint may refer to another group's existing node
without moving it. Unknown qualified names report an error.
Complete repeated-name example
Choose your workflow
| What you want to do | Use | Working example |
| --- | --- | --- |
| Generate diagrams for documentation, reports, or build jobs | Node.js: write PNG bytes or SVG text to a file | Node sample |
| Embed live diagrams in dashboards or internal tools | React component and shared provider | React + Vite sample |
| Add editable source and previews to a web app | Browser SDK | Plain JavaScript sample |
| Keep the UI responsive while rendering larger diagrams | SDK in a module Web Worker | Worker sample |
| Check syntax and references before rendering | The SDK's validate() method | Validation example |
For existing documentation, use the Markdown/VitePress plugin or VS Code Markdown extension.
Install
npm install @drawmotive/[email protected]The current stable release is 0.3.0, available through latest. The alpha channel includes previews. New releases use canonical numeric versions; every numeric version is stable and publishes to the latest channel. Historical suffixed versions remain available. See release policy.
Supports Node.js 22 or a modern browser with WebAssembly and Web Crypto. Browser applications need HTTPS or localhost. React support is an optional entry in this package, compatible with React 18.2+ and 19.
Supported environments
| Layer | Supported environment | Verification boundary | | --- | --- | --- | | Node runtime and package tools | Node.js 22; npm 10 | Vite samples require Node 22.12+ on the 22 line | | Desktop build and Node rendering | Linux, Windows, macOS | CI targets all three systems with Node 22 | | Browser, React and module Worker rendering | Current Chromium, Firefox and WebKit engines | Playwright tests the SDK and samples on Linux; WebKit is not a Safari device certification | | React entry | React 18.2+ in the 18 line, or React 19 | React is an optional peer dependency |
The standalone audit on 2026-10-01 ran Linux x64 with Node 22.23.2 and npm 10.9.8. The support and CI targets above do not claim that Windows, macOS or every browser was executed in that audit. Browser hosts must provide WebAssembly, JavaScript modules, Web Crypto and a secure origin.
Render a PNG in Node.js
Save as render.mjs, then run node render.mjs:
import { writeFile } from "node:fs/promises";
import { initializeTextGraph } from "@drawmotive/textgraph/node";
const textgraph = await initializeTextGraph();
try {
const result = await textgraph.renderPng("browser -> api -> database");
if (result.success) {
await writeFile("diagram.png", result.png);
console.log("Saved diagram.png");
} else {
console.error(result.diagnostics);
process.exitCode = 1;
}
} finally {
await textgraph.dispose();
}Node reads the included runtime from the installed package. No browser, .NET installation, or asset-copy step is needed. Reuse an initialized instance for multiple diagrams, then dispose it when the job is finished.
For vector output, use the same initialized instance:
const vector = await textgraph.renderSvg("browser -> api -> database", { padding: 10 });
if (vector.success) {
await writeFile("diagram.svg", vector.svg, "utf8");
}SVG returns logical displayWidth and displayHeight. It accepts padding,
language, and signal; raster settings such as scale apply only to PNG.
React components continue to use PNG; browser and Worker SDK instances also expose renderSvg().
Add a diagram to React
For browser, React, and Worker applications, copy the runtime assets before starting development or building:
npx textgraph-copy-assets public/textgraph/wasmThen render a component:
import { TextGraph, TextGraphProvider } from "@drawmotive/textgraph/react";
import type { TextGraphInitializeOptions } from "@drawmotive/textgraph";
const options: TextGraphInitializeOptions = {
resolveAsset: (asset) => new URL(`/textgraph/${asset.path}`, location.origin),
};
export function Diagram({ source }: { source: string }) {
return (
<TextGraphProvider options={options}>
<TextGraph source={source} alt="Service dependencies" />
</TextGraphProvider>
);
}Changing source updates the image. For several diagrams, put one provider
around their common parent. Loading states and rendering diagnostics are built in.
The component renders on the main thread; use the Worker sample for heavier
interactive workloads.
React + Vite sample → · React guide →
Render in a browser
After copying assets as shown above, use this in a bundled browser application:
import { initializeTextGraph } from "@drawmotive/textgraph/browser";
const textgraph = await initializeTextGraph({
resolveAsset: (asset) => new URL(`/textgraph/${asset.path}`, location.origin),
});
try {
const result = await textgraph.renderPng("browser -> api -> database", {
encoding: "base64",
scale: 2,
});
if (result.success) {
const image = document.createElement("img");
image.src = `data:image/png;base64,${result.png}`;
image.alt = "Browser connects to API, which connects to database";
image.width = result.displayWidth ?? result.width / 2;
image.height = result.displayHeight ?? result.height / 2;
image.style.maxWidth = "100%";
image.style.height = "auto";
document.body.append(image);
} else {
console.error(result.diagnostics);
}
} finally {
await textgraph.dispose();
}For repeated edits, keep the runtime alive and dispose it when the editor closes. An async call still computes on its current thread; the Worker sample moves rendering off the UI thread.
Browser example → · Worker example →
Deploy the browser runtime
- Add the asset-copy command to your application's
predevandprebuildscripts. - Deploy the complete copied directory: WASM, JavaScript, fonts, themes, and licenses. Re-copy after SDK updates; keep SDK and runtime versions matched.
- The resolver above assumes hosting at
/. For a subdirectory, use your deployed base path; the Vite samples demonstrateimport.meta.env.BASE_URL.
Validation and output options
On an initialized instance:
const validation = await textgraph.validate("browser -> api -> database");
console.log(validation.valid, validation.diagnostics);
const image = await textgraph.renderPng("browser -> api -> database", {
scale: 2,
padding: 24,
maxWidth: 1200,
});Validation checks parsing and semantic references; rendering additionally checks
layout and output. Diagram failures return diagnostics. Operational failures
reject with DrawMotiveError.
PNG output defaults to bytes, scale 1, padding 10, and a white background.
Use higher scale for more pixels and returned display dimensions for web sizing.
TypeScript declarations are included for every public entry point.
Run the examples locally
Samples are complete applications in the public repository and pin the public
@drawmotive/[email protected] package. To try the React sample from a fresh checkout:
git clone https://github.com/drawmotive/textgraph.git
cd textgraph
cd samples/react-vite
npm ci
npm run devVite samples require Node.js 22.12+. Replace react-vite with browser or
worker for those samples. The Node sample uses npm start instead.
The shared sample guide also describes explicit development tarball testing.
Samples are not included in the npm package.
Current scope
- Available: flowcharts and directed graphs, automatic layout, PNG and SVG rendering, and source validation.
- Not available yet: mind maps, sequence diagrams, and slides.
- Fonts: Noto Sans and Fuzzy Bubbles are included. Custom font descriptors and
the optional published
@drawmotive/[email protected]package are supported. See font configuration.
Project links
Language guide · Changelog · Report an issue · MIT license
For public checkout commands and pull requests, see Contributing. Redistribution notices are indexed in NOTICE. For vulnerability reports, see Security reporting.
Try it in a browser
Open the runnable HTML/JavaScript example to edit source, see its PNG and copy the integration code without installing anything. For visual editing, see the DrawMotive editor.
