An infinite-canvas ER diagram editor driven by LinkML.
Point it at a LinkML schema and blueprint paints an entity-relationship diagram — one table per class, columns from slots, and edges for the foreign-key relationships implied by slots whose range is another class. Tables can be dragged around freely on an infinite canvas powered by Svelte Flow.
This is the same idea as dbml and its canvas, with two deliberate differences:
@xyflow/svelte (Svelte Flow) for the canvasyaml to parse LinkMLbp)The primary way to use blueprint is the bp command — point it at a LinkML file
and it opens that file in the canvas, no import/export needed:
bun install
bun link # makes `bp` available on your PATH
bp mydb.yaml # builds on first run, serves, opens the browser
Or without linking: bun run bp mydb.yaml.
In this file-backed mode:
mydb.yaml;mydb.bp.json as you drag;mydb.yaml (when they parse cleanly);mydb.yaml in another editor updates the diagram
— the app's own saves are suppressed so they don't echo back.The schema stays the source of truth for what to draw; mydb.bp.json only
holds where. Commit the schema, optionally commit the layout, ignore neither.
bp <schema.yaml> [--port 4321] [--no-open] [--rebuild]
bun run dev # http://localhost:5173
Run without bp and the app falls back to a bundled example, localStorage for
layout, and load/export buttons — so it still works as a pure browser app or
static deployment.
bun test # unit tests (Vitest)
bun run check # type-check (svelte-check)
bun run lint # prettier + eslint
bun run build # production build
| Concern | Module |
|---|---|
| Parse LinkML → ER model | src/lib/linkml/parse.ts |
| ER model types | src/lib/linkml/types.ts |
| Model + layout → flow graph | src/lib/linkml/toFlow.ts |
| Layout persistence (browser) | src/lib/layout/store.ts |
| Disk read/write (file-backed) | src/lib/server/store.ts |
Neighbor path (.bp.json) |
src/lib/server/paths.ts |
| Schema/layout HTTP endpoints | src/routes/api/{schema,layout}/ |
| File watcher → SSE | src/lib/server/watch.ts, src/routes/api/watch/ |
bp CLI launcher |
bin/bp.js |
| Table node rendering | src/lib/components/TableNode.svelte |
| Canvas + editor | src/routes/+page.svelte |
classes with inline attributes and/or referenced top-level slots,
reusable slots, slot_usage overrides, is_a / mixins inheritance, and
imports (slots/classes/types/enums pulled from sibling files, resolved on disk
by bp). Attributes and slots are interchangeable. A slot is treated as a
foreign key when its range matches another class name; identifier: true
(or key: true) marks the primary key.
Equivalence across these representations is locked down by
src/lib/linkml/fixtures/ — every variant of the ecommerce schema must produce
the same canvas (see that folder's README).
This repo uses Seeds (sd) for git-native
issue tracking. Run sd prime for the workflow, sd ready to find work.