Show HN: Anyone else frustrated with mermaid diagrams? A tool called ablauf, published as the npm package @uberblick/ablauf by uberblick.ai, renders diagrams from a small text format in which the author fixes every element's position, producing deterministic themed SVG rather than using Mermaid's automatic layout. The package requires Node.js 22.18 or newer, ships compiled JavaScript and TypeScript declarations with no runtime dependencies, and its render(source, options?) function returns { svg, diagnostics, layout }, reporting source problems with one-based line numbers while still producing SVG. Ablauf supports two diagram kinds, routed flows and standalone outcome fan-outs, both at v0, and offers no automatic layout and no Mermaid import or export; its author states that "if you need Mermaid's breadth, Mermaid is the better choice. A small text format for diagrams that agents write and people read, rendered as deterministic, themed SVG. The author decides where everything goes, the way they would draw the figure by hand. The text records those decisions, so another agent can read and edit the diagram without looking at the picture. The renderer sizes the grid and draws; it never moves anything, and it reports every problem with its line number. The kinds are routed flows and standalone outcome fan-outs; both formats are v0. See them on ablauf.uberblick.ai https://ablauf.uberblick.ai . We started with Mermaid, and the first version of ablauf was a Mermaid subset. Mermaid lays a diagram out automatically, which makes it quick to write. For the documents we work on we wanted the author to decide where each step sits and which side each edge leaves and enters, so that a small edit to the text leaves the rest of the picture where it was. Edges are still spelled like Mermaid's -- , : label , because agents already know that spelling. ablauf is much narrower than Mermaid: two kinds, flows and fan-outs, no automatic layout and no Mermaid import or export. If you need Mermaid's breadth, Mermaid is the better choice. The motivation page https://ablauf.uberblick.ai/motivation has the longer story. The playground puts an editor beside the live render and lists each problem with its line number; click one to jump to it. It switches between light and dark and between a bare page and a 710 px document column, and it opens every example in this repository. In a checkout, with mise https://mise.jdx.dev : mise trust && mise run setup mise run playground Then open http://localhost:4620 http://localhost:4620 . Rendered examples of both kinds are on ablauf.uberblick.ai https://ablauf.uberblick.ai . Requires Node.js 22.18 or newer. The package ships compiled JavaScript and TypeScript declarations, with no runtime dependencies or TypeScript loader required. Its public entry point is an ES module. Install it in your project: npm install @uberblick/ablauf Save this as render-flow.mjs : js import { readFile, writeFile } from "node:fs/promises"; import { render } from "@uberblick/ablauf"; const input, output = process.argv.slice 2 ; if input || output { console.error "Usage: node render-flow.mjs input.flow output.svg" ; process.exit 2 ; } const source = await readFile input, "utf8" ; const { svg, diagnostics } = render source, { idPrefix: "build-flow", scheme: "light", } ; await writeFile output, svg ; for const { line, severity, message } of diagnostics { console.error ${input}:${line} ${severity}: ${message} ; } // Keep the SVG for inspection, but fail the build on any source problem. process.exitCode = diagnostics.length ? 1 : 0; Run it with a flow file and the desired output path: node render-flow.mjs diagram.flow diagram.svg render source, options? returns { svg, diagnostics, layout } . Source problems return diagnostics with one-based line , severity and message fields while still producing SVG. Invalid caller options can throw. idPrefix defaults to "ab" ; supply distinct prefixes for diagrams sharing a page. Omit scheme to follow the system theme, or pin it to "light" or "dark" . The existing fonts option accepts host font families and synchronous width metrics; see host fonts and width metrics https://github.com/uberblick-ai/ablauf/blob/main/docs/plan.md host-fonts-and-width-metrics . TypeScript consumers can import RenderOptions , Diagnostic , FontOptions , FontsOptions and TextStyle from the same entry point. LIGHT and DARK export the default palettes. flow v0 columns fix main manual pill push col=main tone=muted "push to main" box build "compile and package" box test "unit and integration tests" box staging "deploy to staging" box smoke "smoke tests" box production "deploy to production" end live "Live" pill failed col=fix row=test tone=rework "checks failed" box rollback col=fix row=production tone=rework "restore the last release" panel approve col=manual row=smoke tone=stop strong "Release manager" muted "approves the release" push -- build : on push build -- test test -- staging : green staging -- smoke smoke -- approve tone=stop : passed approve -- production tone=stop from=bottom to=right label=end : approved production -- live : healthy build -- failed tone=rework to=top.2 : fails test -- failed tone=rework : red failed -- push tone=rework from=top.1 to=left label=end : fix and push production -- rollback tone=rework : unhealthy legend pill "event or state" box "automated job" panel "manual step" edge tone=rework "failure path" - columns names the columns left to right. Each node starts a new row unless row= puts it beside another node. - Nodes are text , pill , box , end , panel or decision , coloured by a tone. - Edges use Mermaid's arrows. from= and to= pick the sides an edge leaves and enters; each pair of sides has one fixed shape. - legend explains the shapes in fine print under the diagram. spike/PRIMER.md https://github.com/uberblick-ai/ablauf/blob/main/spike/PRIMER.md is the full format on one page, and the page an agent reads before writing a flow. For phone widths, author separate wide and narrow layouts https://github.com/uberblick-ai/ablauf/blob/main/docs/narrow-layouts.md . The worked pair keeps the same content and lets the host select a readable SVG. From spike/examples/checkout.flow https://github.com/uberblick-ai/ablauf/blob/main/spike/examples/checkout.flow , with two sections: The loop ub-agents https://github.com/uberblick-ai/ub-agents runs on Uberblick's repositories, from spike/examples/loop.flow https://github.com/uberblick-ai/ablauf/blob/main/spike/examples/loop.flow : decision asks a question over a small diamond, and label=inline sets each answer into a gap in its edge. From spike/examples/project-workflow.flow https://github.com/uberblick-ai/ablauf/blob/main/spike/examples/project-workflow.flow : A fan-out v0 diagram is one step and its ordered outcomes, each with a reason and a destination: fan-out v0 step "Check whether approval permits the run" outcome "Approved" reason="A maintainer started it and the input is unchanged" destination="Start the run" tone="done" outcome "Outside input" reason="The input has not been cleared by a maintainer" destination="Ask a maintainer" tone="stop" outcome "Edited since" reason="The input changed after the maintainer started it" destination="Ask a maintainer" tone="stop" Inline SVGs can follow a page's data-theme="light" / data-theme="dark" switch through the existing --ab- CSS properties, without rerendering. See host page themes https://github.com/uberblick-ai/ablauf/blob/main/docs/theming.md for the complete base and tone palette, copyable host CSS and the difference between inline SVG and image embedding. You need mise https://mise.jdx.dev . In a fresh checkout or worktree: mise trust && mise run setup | Command | What it does | |---|---| | mise run setup | Installs the pinned Node and pnpm and the locked dependencies. | | mise run playground | Serves the review page at http://localhost:4620 http://localhost:4620 another port if that one is busy . Open examples/loop to see the loop beside its hand-drawn reference. | | mise run check FILE | Renders one .flow file to an .svg beside it and lists its problems with line numbers. | | mise run render | Renders every example to spike/out/ and refreshes the figures in this README. | | mise run site | Builds ablauf.uberblick.ai https://github.com/uberblick-ai/ablauf/blob/main/site/README.md into site/out/ ; mise run site-serve serves it. | | mise run measure | Shows what moved between the loop and the loop with a role inserted. | | mise run ci | Lint, typecheck and tests, before you push. | pnpm build emits the package into dist/ . npm pack builds it automatically. The tests in mise run ci install the actual tarball with production dependencies only in an isolated directory and exercise the public import and this build script. mise tasks lists everything. The plan is in docs/plan.md https://github.com/uberblick-ai/ablauf/blob/main/docs/plan.md , and the spike's results in spike/FINDINGS.md https://github.com/uberblick-ai/ablauf/blob/main/spike/FINDINGS.md . Maintainers release an already-prepared version with mise run release X.Y.Z . Start with mise run release X.Y.Z --check ; see releases https://github.com/uberblick-ai/ablauf/blob/main/docs/releases.md for trusted-publishing setup, confirmation and partial-release recovery. The earlier Mermaid-subset version lives in uberblick-ai/old-ablauf https://github.com/uberblick-ai/old-ablauf . MIT