v0.2 · 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.
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 of you: 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);Everything here happens on a server or during a build — there is no DOM, no font-loading pass, no client-side layout library. Because the compiler reserves space from the bounds you declared, the page never reflows once the vector arrives.
Consider a sensor front-end: a source, a series resistor, and a shunt capacitor to ground. The diagram to the right is not a drawing of that network — it is that network, compiled. And because the topology is explicit, we can reason about it. The resistor and capacitor form a first-order low-pass filter whose cutoff sits at
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 that omission is deliberate: the boundary between parse my prose and compile my diagrams belongs to you. Keep your parser on the server, recognize schemd fences, and forward only the fence body to the compiler.
npm install @schemd/coreimport { 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 your own build step. This site uses exactly that server-only boundary — not a byte of compiler or Markdown code reaches the browser. And the grammar that drew the circuit above is the same grammar that describes structure; here it is holding 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]