How to Build a Self-Hosted Mermaid.ai & Eraser.io Replacement with Your AI Coding Agent
Most AI-generated Mermaid diagram editors freeze the browser main thread on 50+ node graphs, flash blank screens every time you type an unclosed bracket, and export blurry low-res PNGs. This production blueprint gives Claude Code, Cursor, Windsurf, and Devin the complete Web Worker pipeline, non-destructive error recovery state machine, infinite pan/zoom matrix math, and 300 DPI Retina export engine.
Live Blueprint Demo // Sandboxed Web Worker Canvas & 300 DPI Export
1280×720 • Port 3000Split-pane CodeMirror 6 editor with non-destructive syntax error recovery banner, spacebar-drag pan/zoom matrix, and 300 DPI Retina PNG / SVG export.
pnpm install && pnpm run dev (Zero DB Needed)
AST & Matrix Math Verified
pnpm install && pnpm run dev
1. Why Naive Prompts Fail at Building a Mermaid.ai / Eraser Replacement
Sandboxed Web Worker Parsing
Large flowcharts and ERDs lock the main browser thread during Dagre layout math. All parsing runs inside workers/mermaid-worker.ts with a 250ms debounce so typing stays at 60fps.
Preserves Last Valid Diagram on Syntax Errors
When you type A[Start --> mid-sentence, the canvas never blanks out. It keeps displaying the last valid SVG while showing a pinpoint line/column error banner.
Zero-Re-Parse Infinite Pan & Zoom
Spacebar-dragging and pinch-zooming mutate only the (scale, translateX, translateY) matrix without re-triggering editor renders or Mermaid graph parsing.
300 DPI PNG, Vector SVG & Clipboard Copy
Rasterizes the SVG onto a 2x/3x high-DPI <canvas> with transparent or dark backgrounds and supports one-click Async Clipboard API image copy.
2. Serialization & Persistence Schema (PostgreSQL DDL)
Works 100% client-side via URL hash or local storage, with optional PostgreSQL persistence for shared team diagrams.
-- Diagrams Storage
CREATE TABLE diagrams (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
title VARCHAR(255) NOT NULL DEFAULT 'Untitled Diagram',
syntax_type VARCHAR(50) NOT NULL DEFAULT 'mermaid', -- 'mermaid' | 'plantuml' | 'markdown-table'
content TEXT NOT NULL,
viewport_state JSONB NOT NULL DEFAULT '{"zoom": 1.0, "x": 0, "y": 0}'::jsonb,
is_public BOOLEAN DEFAULT FALSE,
created_at TIMESTAMPTZ NOT NULL DEFAULT timezone('utc', now()),
updated_at TIMESTAMPTZ NOT NULL DEFAULT timezone('utc', now())
);
CREATE INDEX idx_diagrams_updated ON diagrams(updated_at DESC);
3. Modular File System Architecture (Hard 200-Line Cap)
src/
├── app/
│ ├── page.tsx # < 95 lines (Hero & diagram launcher)
│ ├── editor/[id]/page.tsx # < 130 lines (Split-pane layout container)
│ └── api/diagrams/route.ts # < 120 lines (Save/load endpoints)
├── components/
│ ├── editor/
│ │ ├── code-editor-pane.tsx # < 150 lines (CodeMirror/Monaco wrapper)
│ │ ├── syntax-error-banner.tsx # < 70 lines (Friendly error recovery line marker)
│ │ └── template-selector.tsx # < 110 lines (Flowchart, Sequence, ERD starters)
│ ├── canvas/
│ │ ├── diagram-canvas.tsx # < 170 lines (SVG viewport & transform root)
│ │ ├── pan-zoom-controls.tsx # < 95 lines (Zoom in, Zoom out, Fit-to-screen)
│ │ └── export-modal.tsx # < 160 lines (SVG, High-DPI PNG, Clipboard copy)
│ └── ui/
│ ├── button.tsx, dialog.tsx # Atomic UI primitives
├── hooks/
│ ├── use-mermaid-renderer.ts # < 150 lines (Web worker debounced render)
│ └── use-canvas-transform.ts # < 140 lines (Matrix math, pinch/zoom, pan)
├── workers/
│ └── mermaid-worker.ts # < 110 lines (Isolated graph parse & SVG stringify)
└── lib/
├── canvas-math.ts # < 90 lines (Matrix transform & boundary clamp)
└── export-image.ts # < 130 lines (SVG to Canvas PNG converter)
4. Phase-by-Phase Prompts for Claude Code, Cursor & Windsurf
I have loaded the Mermaid.ai & Eraser.io Replacement technical blueprint. Do not write any code yet. Verify the Web Worker architecture and matrix transform equations, ask up to 3 clarifying questions, and then proceed with Phase 1.
Execute Phase 1: Set up the split-pane workspace layout using Tailwind and CodeMirror. Left pane: Code editor with syntax highlighting for Mermaid.js and template selector (Flowchart, Sequence, Architecture, ERD). Right pane: Canvas container with dark/light background grid dots. Keep all files under 200 lines.
Execute Phase 2: Build the diagram rendering pipeline. Create `workers/mermaid-worker.ts` running `@mermaid-js/mermaid` inside an isolated worker. Debounce editor changes by 250ms. If parsing fails, catch the error and display `syntax-error-banner.tsx` with line and column numbers while preserving the previous valid diagram on screen.
Execute Phase 3: Implement canvas navigation in `useCanvasTransform`. Add spacebar-click-and-drag panning, trackpad pinch-to-zoom, and mousewheel zoom. Add floating controls: Zoom In (+), Zoom Out (-), Reset (100%), and Fit to Screen (computes bounding box and centers the diagram).
Execute Phase 4: Implement the export modal. Support 3 export modes: 1. Pure SVG download with embedded fonts and styling. 2. High-DPI PNG download (2x scale) with optional transparent or solid background. 3. One-click "Copy Image to Clipboard" using the Async Clipboard API.
Execute Phase 5: Implement URL hash / database diagram saving and Vitest regression suites. Add unit tests verifying: valid flowchart AST parses cleanly, broken syntax string throws friendly recoverable error without killing the worker, and fit-to-screen matrix calculation correctly scales oversized diagrams into viewport bounds.
Frequently Asked Questions: Building a Mermaid.ai & Eraser.io Replacement
How can I build a Mermaid.ai or Eraser.io replacement using AI coding tools?
Use PromptScale's Mermaid Flowchart Canvas Blueprint in Planning Mode inside Claude Code, Cursor, or Windsurf. It structures the app into <200-line modular files with a CodeMirror 6 left pane, a 250ms debounced Web Worker parser, an infinite pan/zoom SVG transform matrix, and a 300 DPI PNG/SVG export pipeline.
How do you prevent Mermaid.js from flashing blank or crashing while the user is mid-keystroke?
While typing A[Client] --> B[Server], intermediate keystrokes are syntactically incomplete. Store lastValidSvg separately from parseError in state: when the worker returns a syntax error, keep rendering lastValidSvg on the canvas and display a non-intrusive error banner with the offending line number.
Why should Mermaid diagram rendering run inside a Web Worker?
Dagre and ELK graph layout calculations for diagrams with 50+ nodes are CPU-heavy and block the browser main thread, causing visible keystroke lag in the editor. Offloading layout calculation to an isolated Web Worker with a 250ms debounce keeps typing smooth at 60fps.
Explore More SaaS Replacement Blueprints
Time Tracker & Invoicing Engine →
UTC clock drift recovery & sequential invoice locks.
Replaces Calendly & Cal.comMulti-Timezone Booking Engine →
PostgreSQL advisory locks & RFC 5545 .ics calendar invites.
Replaces Typeform & TallyConversational Form Engine →
100% keyboard state machine & JSON conditional logic jumps.