Get started
Make your first diagram
pronounced like skemd /skɛmd/Write a few lines of text and turn them into accessible, deterministic SVG for circuits or UML.
- sheet
- 1 / 11
- rev
- v0.2
- sections
- 2
- compiled
- 2
01 / InstallCompile text into SVG
We treat a schematic the way a compiler treats source, so the first step is the one every compiler asks: install it, then hand it a string.
npm install @schemd/coreA schemd document is bounded before it is parsed. parseSchematicFence validates the fence header — the canvas dimensions and an accessible title — and compileSchematic walks the declarations into deterministic SVG:
import { compileSchematic, parseSchematicFence } from '@schemd/core';
const fence = parseSchematicFence('schemd bounds="640x260" title="Sensor input"')!;
const { svg, document, metrics } = compileSchematic(source, fence);All of this runs on a server or during a build — no DOM, no font-loading pass, no layout library. The compiler reserves space from the bounds we declared, so the page never reflows once the vector lands.
Consider a sensor front-end: a source, a series resistor, a shunt capacitor to ground. The diagram beside this is not a drawing of that network — it is that network, compiled. Because the topology is explicit, we can reason about it: the resistor and capacitor form a first-order low-pass filter with cutoff
which, for and , lands near .
port:VIN "Sensor" at (60, 150) #blue
resistor:R1 "10 k\Omega" at (245, 150) #amber
capacitor:C1 "100 nF" at (455, 150) #cyan
port:ADC "ADC" at (660, 150) #emerald
VIN.out -> R1.in #blue [line]
R1.out -> C1.in #amber [ortho]
C1.out -> ADC.in #emerald [line marker-end=arrow]02 / MarkdownKeep Markdown in your app
Core ships no Markdown parser, and the omission is deliberate: the boundary between parse my prose and compile my diagrams belongs to us. Keep the parser on the server, recognize schemd fences, forward only the body.
import { compileSchematic, parseSchematicFence } from '@schemd/core';
function renderSchemdFence(body: string, info: string) {
const fence = parseSchematicFence(info);
if (!fence) return undefined;
return compileSchematic(body, fence).svg;
}Wire that one function into Marked, markdown-it, unified, or a build step of our own. This site uses exactly that boundary — not a byte of compiler or Markdown code reaches the browser. Note that the grammar which drew the circuit above also describes structure; below it holds a two-class model instead of a filter.
class:User "User" at (200, 180) #slate [attributes="- id: UUID; + email: string" operations="+ save(): void"]
class:Admin "Admin" at (560, 180) #blue [operations="+ suspend(user): void"]
Admin.left -> User.right #blue [ortho generalization]