preview_diagram
Render one or more DGMO diagrams into an HTML preview in your browser, with optional theme and source display.
Instructions
Render one or more DGMO diagrams and open an HTML preview in the browser. Supports theme toggle and optional source display. IMPORTANT: Parentheses in DGMO labels = color notation (stripped from name). All labels must be unique. Use dashes for qualifiers, e.g. "App - TS" not "App (TS)".
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| diagrams | Yes | One or more diagrams to preview | |
| theme | No | Color theme | dark |
| palette | No | Color palette | nord |
| include_source | No | Show DGMO source in collapsible blocks |
Implementation Reference
- src/index.ts:434-528 (handler)The main handler function for the preview_diagram tool. It accepts an array of diagrams (each with a title and DGMO markup), a theme, palette, and include_source flag. It renders each diagram via tryRender, builds either a single preview HTML (using buildPreviewHtml) or a multi-diagram report (using buildReportHtml), writes the HTML to a temp file, opens it in the browser, and returns a status message with any errors.
// --- Tool 6: preview_diagram --- server.tool( 'preview_diagram', 'Render one or more DGMO diagrams and open an HTML preview in the browser. Supports theme toggle and optional source display. IMPORTANT: Parentheses in DGMO labels = color notation (stripped from name). All labels must be unique. Use dashes for qualifiers, e.g. "App - TS" not "App (TS)".', { diagrams: z .array( z.object({ title: z.string().optional().describe('Optional title for this diagram'), dgmo: z.string().describe('DGMO diagram markup. Parentheses in labels = color notation. All labels must be unique.'), }), ) .min(1) .describe('One or more diagrams to preview'), theme: z.enum(['light', 'dark']).default('dark').describe('Color theme'), palette: z.string().default('nord').describe('Color palette'), include_source: z.boolean().default(true).describe('Show DGMO source in collapsible blocks'), }, { title: 'Preview Diagram', readOnlyHint: false, destructiveHint: false, openWorldHint: true, }, async ({ diagrams, theme, palette, include_source }) => { const paletteConfig = getPalette(palette); const results = await Promise.all( diagrams.map(async (d) => { const { svg, error } = await tryRender(d.dgmo, theme, palette); return { title: d.title, dgmo: d.dgmo, svg, error }; }), ); const successes = results.filter((r) => r.svg); const failures = results.filter((r) => !r.svg); if (successes.length === 0) { return { content: [ { type: 'text' as const, text: 'All diagrams failed to render:\n' + failures.map((f) => `- ${f.title || 'untitled'}: ${f.error}`).join('\n'), }, ], isError: true, }; } let html: string; if (diagrams.length === 1 && successes.length === 1) { // Single diagram → simple preview const r = results[0]; const shareResult = encodeDiagramUrl(r.dgmo); const shareUrl = shareResult.error ? undefined : shareResult.url; html = buildPreviewHtml({ svg: r.svg!, title: r.title, dgmoSource: include_source ? r.dgmo : undefined, palette: paletteConfig, shareUrl, }); } else { // Multiple diagrams → report layout const sections: ReportSection[] = results.map((r) => ({ title: r.title || 'Untitled', svg: r.svg, dgmoSource: r.dgmo, error: r.error ?? undefined, })); html = buildReportHtml({ title: 'Diagram Preview', sections, palette: paletteConfig, includeSource: include_source, }); } const filePath = writeTempHtml(html, 'dgmo-preview'); await openInBrowser(filePath); let message = `Opened preview in browser: ${filePath}`; if (failures.length > 0) { message += '\n\nWarning — some diagrams failed to render:\n' + failures.map((f) => `- ${f.title || 'untitled'}: ${f.error}`).join('\n'); } return { content: [{ type: 'text' as const, text: message }], }; }, ); - src/index.ts:439-452 (schema)Zod schema definitions for the preview_diagram tool's parameters: diagrams (array of {title?, dgmo}), theme (light/dark, default dark), palette (string, default 'nord'), include_source (boolean, default true).
{ diagrams: z .array( z.object({ title: z.string().optional().describe('Optional title for this diagram'), dgmo: z.string().describe('DGMO diagram markup. Parentheses in labels = color notation. All labels must be unique.'), }), ) .min(1) .describe('One or more diagrams to preview'), theme: z.enum(['light', 'dark']).default('dark').describe('Color theme'), palette: z.string().default('nord').describe('Color palette'), include_source: z.boolean().default(true).describe('Show DGMO source in collapsible blocks'), }, - src/index.ts:436-528 (registration)Registration of the 'preview_diagram' tool via server.tool() with metadata including title 'Preview Diagram', readOnlyHint: false, destructiveHint: false, openWorldHint: true.
server.tool( 'preview_diagram', 'Render one or more DGMO diagrams and open an HTML preview in the browser. Supports theme toggle and optional source display. IMPORTANT: Parentheses in DGMO labels = color notation (stripped from name). All labels must be unique. Use dashes for qualifiers, e.g. "App - TS" not "App (TS)".', { diagrams: z .array( z.object({ title: z.string().optional().describe('Optional title for this diagram'), dgmo: z.string().describe('DGMO diagram markup. Parentheses in labels = color notation. All labels must be unique.'), }), ) .min(1) .describe('One or more diagrams to preview'), theme: z.enum(['light', 'dark']).default('dark').describe('Color theme'), palette: z.string().default('nord').describe('Color palette'), include_source: z.boolean().default(true).describe('Show DGMO source in collapsible blocks'), }, { title: 'Preview Diagram', readOnlyHint: false, destructiveHint: false, openWorldHint: true, }, async ({ diagrams, theme, palette, include_source }) => { const paletteConfig = getPalette(palette); const results = await Promise.all( diagrams.map(async (d) => { const { svg, error } = await tryRender(d.dgmo, theme, palette); return { title: d.title, dgmo: d.dgmo, svg, error }; }), ); const successes = results.filter((r) => r.svg); const failures = results.filter((r) => !r.svg); if (successes.length === 0) { return { content: [ { type: 'text' as const, text: 'All diagrams failed to render:\n' + failures.map((f) => `- ${f.title || 'untitled'}: ${f.error}`).join('\n'), }, ], isError: true, }; } let html: string; if (diagrams.length === 1 && successes.length === 1) { // Single diagram → simple preview const r = results[0]; const shareResult = encodeDiagramUrl(r.dgmo); const shareUrl = shareResult.error ? undefined : shareResult.url; html = buildPreviewHtml({ svg: r.svg!, title: r.title, dgmoSource: include_source ? r.dgmo : undefined, palette: paletteConfig, shareUrl, }); } else { // Multiple diagrams → report layout const sections: ReportSection[] = results.map((r) => ({ title: r.title || 'Untitled', svg: r.svg, dgmoSource: r.dgmo, error: r.error ?? undefined, })); html = buildReportHtml({ title: 'Diagram Preview', sections, palette: paletteConfig, includeSource: include_source, }); } const filePath = writeTempHtml(html, 'dgmo-preview'); await openInBrowser(filePath); let message = `Opened preview in browser: ${filePath}`; if (failures.length > 0) { message += '\n\nWarning — some diagrams failed to render:\n' + failures.map((f) => `- ${f.title || 'untitled'}: ${f.error}`).join('\n'); } return { content: [{ type: 'text' as const, text: message }], }; }, ); - src/index.ts:135-152 (helper)The tryRender helper function that parses DGMO markup, checks for errors, and calls the render function to produce SVG output. Used by the preview_diagram handler to render each diagram.
async function tryRender( dgmo: string, theme: 'light' | 'dark', palette: string, ): Promise<{ svg: string | null; error: string | null }> { const { diagnostics } = parseDgmo(dgmo); const errors = diagnostics.filter((d) => d.severity === 'error'); if (errors.length > 0) { return { svg: null, error: errors.map(formatDgmoError).join('\n') }; } try { const { svg } = await render(dgmo, { theme, palette }); if (!svg) return { svg: null, error: 'Render returned empty SVG.' }; return { svg, error: null }; } catch (err) { return { svg: null, error: err instanceof Error ? err.message : String(err) }; } } - src/html-report.ts:179-208 (helper)The buildPreviewHtml helper function that generates a complete HTML page for a single diagram preview. Includes the SVG, title, optional DGMO source block, palette-based CSS theme, and an open-in-diagrammo.app link.
export function buildPreviewHtml(options: PreviewHtmlOptions): string { const { svg, title, dgmoSource, palette, shareUrl } = options; const pageTitle = title || 'Diagram Preview'; const openLink = shareUrl ? `<a class="open-link" href="${escapeHtml(shareUrl)}" target="_blank" rel="noopener">Open at diagrammo.app ↗</a>` : ''; return `<!DOCTYPE html> <html lang="en" data-theme="dark"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>${escapeHtml(pageTitle)}</title> <style>${buildCss(palette)} .preview-root { display: flex; flex-direction: column; min-height: 100vh; padding: 1rem; } .preview-diagram { flex: 1; overflow: auto; display: flex; align-items: flex-start; justify-content: flex-start; } .preview-diagram svg { max-width: none; height: auto; display: block; } .preview-source { flex-shrink: 0; } </style> </head> <body> ${openLink} <div class="preview-root"> <div class="preview-diagram">${svg}</div> ${dgmoSource ? `<div class="preview-source">${sourceBlock(dgmoSource)}</div>` : ''} </div> ${COPY_SCRIPT} </body> </html>`; }