@openpowershift/logic-diagram-language
v0.2.8
Published
Render SEL-style protection-relay logic diagrams from a compact text language (LDL) to SVG, PNG, or PDF.
Maintainers
Readme
LDL — Logic Diagram Language
:toc: macro :toclevels: 2
LDL is a small text language and renderer for logic and protection diagrams. You write boolean equations; the renderer draws the gates, routes the wires, and lays the whole diagram out automatically — producing clean, publication-quality SVG (and PNG/PDF in the browser).
[TIP]
Try it in the browser: openpowershift.github.io/logic-diagram-language — a live playground: type LDL on the left, see the diagram on the right.
Published as @openpowershift/logic-diagram-language. See the <<Use as a library,API Reference>>
for programmatic use.
TRIP = OVERCURRENT AND NOT BLOCK OR (EARTH AND MANUAL)
That single expression yields a complete diagram: boundary inputs on the left, gates in
the middle, the TRIP output on the right, with wires routed and crossings minimised —
no coordinates, no manual placement.
Why
Protection and control schematics are tedious to draw by hand and awkward to keep in sync with the logic they represent. LDL treats the logic as the source of truth: the diagram is a rendering of an expression, so it is diffable, reviewable, and regenerated automatically whenever the logic changes.
Goals & concepts
- Expression-first. A simple boolean expression produces a complete diagram. Names that are consumed elsewhere become shared internal signals; names that aren't become outputs.
- Declarative — the layout is the renderer's job. You describe what is connected, not where things go. A Sugiyama-style layout engine assigns layers and coordinates and actively minimises wire crossings; every reshaping pass validates a single wire-separation contract so wires never overlap or crowd.
- Protection-domain aware. Beyond
AND/OR/NOT, LDL has SEL-style function blocks —TIMER,SRlatch,RISING/FALLINGedge triggers,COMPAREcomparator, and a genericFBblock — plus seal-in/feedback loops drawn as loop-back wires. - Labelled & styled. Inputs, outputs and gates carry
.Name/.Descriptionlabels (with inline TeX math via MathJax), and every element has a stable id/class for CSS. - Readable output. Options control inversion bubbles vs. NOT gates, input bars, compactness, adaptive column spacing, and more.
Use as a library
[source,bash]
npm install @openpowershift/logic-diagram-language
[source,ts]
import { parse, renderDiagram, resolveOptions, } from "@openpowershift/logic-diagram-language";
const { diagram } = parse("O1 = I1 AND NOT I2"); const svg = renderDiagram(diagram, resolveOptions(diagram.options)); // → a complete … string
SVG rendering is isomorphic (Node + browser). In the browser, svgToPngBlob(svg) and
svgToPdfBlob(svg) rasterise it to a PNG/PDF Blob. Full API, options table and PNG/PDF
recipes are in the link:docs/api.adoc[API Reference].
Playground / development
Requires Node 20+ (the dev playground uses Node 24 — see .nvmrc).
[source,bash]
npm install npm run dev # live playground at the printed URL — type LDL, see SVG update live npm run build # type-check + production build of the playground app to dist/ npm run build:lib # build the publishable library to lib/ (index.js + type declarations) npm test # run the test suite (vitest)
The playground has a source editor on the left and a live diagram on the right, with a dropdown of built-in examples covering every language feature. Toggle labels/ids, junction dots, zoom, and export to SVG/PNG/PDF.
A taste of the language
[source,ldl]
OPTION OUTPUT_ORDER = AUTO
// SEL-style: a comparator feeds an SR latch, sealed in, into a pickup timer A = SR(COMPARE(IA, IPICKUP), RESET) TRIP = TIMER(A, 0, 30cyc) ALARM = RISING(COMPARE(IA, IPICKUP))
IA.Name = "$I_a$" IPICKUP.Name = "$I_{pickup}$" TRIP.Name = "Trip"
See the link:docs/user-guide.adoc[User Guide] for the full working syntax with examples, and the link:spec/spec.adoc[LDL Specification] for the formal grammar and the rendering contract. Current implementation status is tracked in link:IMPLEMENTATION.md[IMPLEMENTATION.md].
Generating LDL with an AI agent? Point it at link:docs/ldl-for-llms.md[docs/ldl-for-llms.md] — a compact, implemented-only authoring guide (the full spec includes reserved features that don't render yet, which trips agents up).
Project layout
[cols="1,3",options="header"] |=== | Path | What
| src/index.ts
| Public library API (parse, renderDiagram, layoutDiagram, options, types)
| src/export-image.ts
| Browser-only PNG/PDF helpers (svgToPngBlob, svgToPdfBlob)
| src/parser/
| Tokeniser, parser, and AST for LDL source
| src/renderer/
| Layout engine (layout.ts, graph.ts), A* wire router, SVG renderer, gate symbols
| src/components/
| Lit web components — the playground app, editor and viewer
| src/worker/
| Off-thread parse → layout → render worker
| docs/
| link:docs/user-guide.adoc[User guide] and link:docs/api.adoc[API reference]
| spec/
| AsciiDoc language specification (spec/spec.adoc)
| tests/
| Vitest unit tests, layout invariants, and golden geometry/visual-regression snapshots
|===
Status
LDL is under active development. The core language (boolean expressions, intermediates,
feedback, SEL function blocks, labels, TeX math, styling, and the layout options) is
implemented and tested. Some specified constructs are reserved but not yet implemented —
the NAND/NOR/XOR/XNOR operators, CONNECT, custom SYMBOL definitions,
IMPORT/STYLESHEET, and hyperlinks. See the guide and IMPLEMENTATION.md for the
current boundary.
License
link:LICENSE[MIT] © 2026 Daniel Mulholland
