agentic-mermaid 0.4.1 → 0.5.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENT_NATIVE.md +94 -627
- package/CHANGELOG.md +651 -0
- package/Instructions_for_agents.md +44 -23
- package/LICENSES/Khroma-MIT.txt +21 -0
- package/LICENSES/Mermaid-MIT.txt +21 -0
- package/LICENSES/es-toolkit-MIT.txt +21 -0
- package/LICENSES/pele-MIT.txt +40 -0
- package/LICENSES/zenuml-core-MIT.txt +21 -0
- package/README.md +93 -50
- package/SECURITY.md +28 -12
- package/THIRD_PARTY_NOTICES.md +60 -0
- package/assets/hero.png +0 -0
- package/dist/agent-core.d.ts +478 -210
- package/dist/agent-core.js +1 -396
- package/dist/agent.d.ts +17 -8
- package/dist/agent.js +1 -408
- package/dist/agentic-mermaid-mcp.js +1 -11
- package/dist/am.js +1 -34562
- package/dist/browser-lazy/chunks/agentic-producer-core-CC6OOLDW.js +1 -0
- package/dist/browser-lazy/chunks/architecture-QUFVKYJR.js +13 -0
- package/dist/browser-lazy/chunks/block-6J3Q63BO.js +11 -0
- package/dist/browser-lazy/chunks/builtin-backends-7SOZZHPF.js +12 -0
- package/dist/browser-lazy/chunks/c4-SQVBZAKJ.js +10 -0
- package/dist/browser-lazy/chunks/chunk-2GPK4VFF.js +5 -0
- package/dist/browser-lazy/chunks/chunk-2I4UPL7Q.js +3 -0
- package/dist/browser-lazy/chunks/chunk-2SH76OTH.js +1 -0
- package/dist/browser-lazy/chunks/chunk-2UIA2IME.js +3 -0
- package/dist/browser-lazy/chunks/chunk-4LHYF3BS.js +1 -0
- package/dist/browser-lazy/chunks/chunk-5B2Z7575.js +1 -0
- package/dist/browser-lazy/chunks/chunk-5FQ534HP.js +1 -0
- package/dist/browser-lazy/chunks/chunk-5UVGUSD6.js +1 -0
- package/dist/browser-lazy/chunks/chunk-5X6MJX3H.js +1 -0
- package/dist/browser-lazy/chunks/chunk-AMJLVPUB.js +4 -0
- package/dist/browser-lazy/chunks/chunk-BU5LHXNJ.js +3 -0
- package/dist/browser-lazy/chunks/chunk-BY2CPG6B.js +1 -0
- package/dist/browser-lazy/chunks/chunk-CN7WTBWB.js +1 -0
- package/dist/browser-lazy/chunks/chunk-CQE4HQEW.js +1 -0
- package/dist/browser-lazy/chunks/chunk-CSFUKSU6.js +1 -0
- package/dist/browser-lazy/chunks/chunk-DF6765YX.js +17 -0
- package/dist/browser-lazy/chunks/chunk-E2WMJZNM.js +1 -0
- package/dist/browser-lazy/chunks/chunk-FAIMVOX5.js +6 -0
- package/dist/browser-lazy/chunks/chunk-GVOEAY52.js +1 -0
- package/dist/browser-lazy/chunks/chunk-HLWUNUCM.js +1 -0
- package/dist/browser-lazy/chunks/chunk-ICC7HBJX.js +1 -0
- package/dist/browser-lazy/chunks/chunk-J35HAQQF.js +20 -0
- package/dist/browser-lazy/chunks/chunk-J7FFAFQF.js +1 -0
- package/dist/browser-lazy/chunks/chunk-LH7HUDKW.js +1 -0
- package/dist/browser-lazy/chunks/chunk-N5ELX7LR.js +2 -0
- package/dist/browser-lazy/chunks/chunk-NMQQMRIR.js +1 -0
- package/dist/browser-lazy/chunks/chunk-NO7ZIVRU.js +1 -0
- package/dist/browser-lazy/chunks/chunk-OZ443IVJ.js +16 -0
- package/dist/browser-lazy/chunks/chunk-PQGPS2YV.js +7 -0
- package/dist/browser-lazy/chunks/chunk-QA6GJQ4X.js +1 -0
- package/dist/browser-lazy/chunks/chunk-RIVTHZAQ.js +1 -0
- package/dist/browser-lazy/chunks/chunk-SZELX2EJ.js +1 -0
- package/dist/browser-lazy/chunks/chunk-TYZOZXUJ.js +22 -0
- package/dist/browser-lazy/chunks/chunk-UL6NDWLL.js +1 -0
- package/dist/browser-lazy/chunks/chunk-VQYYGAXP.js +1 -0
- package/dist/browser-lazy/chunks/chunk-VWVZGQE2.js +1 -0
- package/dist/browser-lazy/chunks/chunk-X2UYKWKM.js +4 -0
- package/dist/browser-lazy/chunks/chunk-YCEICNM6.js +1 -0
- package/dist/browser-lazy/chunks/chunk-Z3FDIVLN.js +20 -0
- package/dist/browser-lazy/chunks/class-5QA4SCTS.js +13 -0
- package/dist/browser-lazy/chunks/decode-63UIZGD2.js +1 -0
- package/dist/browser-lazy/chunks/elk.bundled-L4CADV5W.js +24 -0
- package/dist/browser-lazy/chunks/er-7ZSKGN7Y.js +11 -0
- package/dist/browser-lazy/chunks/eventmodeling-2BPLHWRN.js +19 -0
- package/dist/browser-lazy/chunks/flowchart-NEIMZTB5.js +4 -0
- package/dist/browser-lazy/chunks/forest-implementation-AEP24AIP.js +1 -0
- package/dist/browser-lazy/chunks/gantt-RDPIFYAF.js +11 -0
- package/dist/browser-lazy/chunks/gitgraph-N4Y5RYB7.js +9 -0
- package/dist/browser-lazy/chunks/ishikawa-LD3YBDJN.js +6 -0
- package/dist/browser-lazy/chunks/journey-6YQR5DJX.js +16 -0
- package/dist/browser-lazy/chunks/kanban-PLMJ7NBW.js +20 -0
- package/dist/browser-lazy/chunks/mermaid-yaml-runtime-QVYX4EWK.js +136 -0
- package/dist/browser-lazy/chunks/mindmap-K2UBFO3Y.js +12 -0
- package/dist/browser-lazy/chunks/packet-CUW4QY6Y.js +7 -0
- package/dist/browser-lazy/chunks/pie-7F7UUCG3.js +15 -0
- package/dist/browser-lazy/chunks/quadrant-TOONO2WC.js +10 -0
- package/dist/browser-lazy/chunks/radar-J6JVWVAX.js +16 -0
- package/dist/browser-lazy/chunks/render-core-BZOM3K7D.js +3 -0
- package/dist/browser-lazy/chunks/requirement-CMAKDJPO.js +19 -0
- package/dist/browser-lazy/chunks/sankey-AWXQEP3F.js +13 -0
- package/dist/browser-lazy/chunks/sequence-Q2RJRB4L.js +5 -0
- package/dist/browser-lazy/chunks/state-WRBFQEDX.js +4 -0
- package/dist/browser-lazy/chunks/timeline-D2KILFXM.js +6 -0
- package/dist/browser-lazy/chunks/treemap-N3VYX5D4.js +6 -0
- package/dist/browser-lazy/chunks/xychart-G73OGK66.js +16 -0
- package/dist/browser-lazy/chunks/zenuml-H4BXNYXR.js +16 -0
- package/dist/browser-lazy/index.d.ts +544 -275
- package/dist/browser-lazy/index.js +1 -1
- package/dist/browser.global.js +802 -565
- package/dist/chunk-3LGLPG33.js +2 -0
- package/dist/chunk-7CRDX2QR.js +2 -0
- package/dist/chunk-7PPW2BMO.js +2 -0
- package/dist/chunk-DQDKA5ND.js +2 -0
- package/dist/chunk-EHCMJUMD.js +52 -0
- package/dist/chunk-GVCHLSHH.js +4 -0
- package/dist/chunk-H3NCS2XZ.js +19 -0
- package/dist/chunk-JZOJ4YGS.js +201 -0
- package/dist/chunk-MKE7GNYU.js +146 -0
- package/dist/chunk-NKNFOREZ.js +2 -0
- package/dist/chunk-O7H2UX5K.js +2 -0
- package/dist/chunk-OMY6NRQD.js +58 -0
- package/dist/chunk-UA234O4M.js +4 -0
- package/dist/chunk-VUFVLGTH.js +2 -0
- package/dist/chunk-XU5LPD2D.js +2 -0
- package/dist/cli-YGGTJZH7.js +226 -0
- package/dist/elk-constructor.js +2 -0
- package/dist/elk-constructor.node.js +11 -0
- package/dist/index-EeXqJXr5.d.ts +1223 -0
- package/dist/index.d.ts +4 -1
- package/dist/index.js +1 -334
- package/dist/jsonl-RPJY6YWO.js +2 -0
- package/dist/mcp-cli-63DYXTVD.js +2 -0
- package/dist/{index-BGA_-6LV.d.ts → paint-certification-6rwQjIv_.d.ts} +5283 -6173
- package/dist/server-5NEOHOFS.js +524 -0
- package/dist/svg-styles-BdnoM7AT.d.ts +724 -0
- package/dist/svg-styles.d.ts +1 -0
- package/dist/svg-styles.js +2 -0
- package/dist/svg.d.ts +13 -0
- package/dist/svg.js +2 -0
- package/dist/types-BcS52Mjt.d.ts +1360 -0
- package/dist/zenuml/chunks/appearance-UOQ5KA6O.js +1 -0
- package/dist/zenuml/chunks/builtin-backends-KDKE7YHO.js +12 -0
- package/dist/zenuml/chunks/chunk-42DXZ5C6.js +4 -0
- package/dist/zenuml/chunks/chunk-7TVYPTDW.js +1 -0
- package/dist/zenuml/chunks/chunk-EVPSMEKN.js +1 -0
- package/dist/zenuml/chunks/chunk-OXQWRSBM.js +20 -0
- package/dist/zenuml/chunks/chunk-QWX77U7G.js +2 -0
- package/dist/zenuml/chunks/chunk-RLJEI7YN.js +29 -0
- package/dist/zenuml/chunks/chunk-RZ6XK5CD.js +29 -0
- package/dist/zenuml/chunks/decode-BWERFDGK.js +1 -0
- package/dist/zenuml/chunks/mermaid-yaml-runtime-KZVU74WU.js +136 -0
- package/dist/zenuml/chunks/render-core-V5RQ737O.js +3 -0
- package/dist/zenuml/chunks/zenuml-EA2ZFRUX.js +20 -0
- package/dist/zenuml-frame.global.js +3626 -0
- package/dist/zenuml.d.ts +83 -0
- package/dist/zenuml.js +1 -0
- package/docs/MCP-DIRECTORY-LISTINGS.md +5 -1
- package/docs/README.md +59 -103
- package/docs/agent-api-cookbook.md +26 -16
- package/docs/agent-mutation-policy.md +86 -15
- package/docs/agent-workflow-examples.md +1 -1
- package/docs/api-advanced.md +385 -0
- package/docs/api.md +320 -366
- package/docs/ascii.md +40 -4
- package/docs/browser.md +46 -7
- package/docs/choosing-a-diagram.md +148 -0
- package/docs/code-mode-impact.md +1 -0
- package/docs/comparison.md +244 -28
- package/docs/computational-aesthetics-prototype-plan.md +10 -10
- package/docs/config.md +60 -2
- package/docs/custom-fonts.md +78 -21
- package/docs/diagram-families.md +160 -10
- package/docs/eventmodeling-and-zenuml.md +165 -0
- package/docs/features.md +21 -19
- package/docs/fork-differences.md +105 -32
- package/docs/getting-started.md +56 -51
- package/docs/layout-certification.md +126 -0
- package/docs/mcp-code-mode-rationale.md +20 -12
- package/docs/mcp-http-transport.md +14 -8
- package/docs/quality.md +145 -15
- package/docs/react.md +76 -31
- package/docs/style-authoring.md +23 -11
- package/docs/svg-semantic-contract.md +104 -4
- package/docs/testing-strategy.md +684 -126
- package/docs/theming.md +27 -8
- package/examples/styles/readme-hero.md +25 -0
- package/examples/styles/readme-hero.mmd +13 -0
- package/examples/styles/readme-hero.style.json +7 -0
- package/package.json +114 -57
- package/server.json +2 -2
- package/skills/agentic-mermaid-diagram-workflow/SKILL.md +26 -8
- package/skills/agentic-mermaid-diagram-workflow/references/cli.md +13 -3
- package/skills/agentic-mermaid-diagram-workflow/references/code-mode.md +2 -1
- package/skills/agentic-mermaid-diagram-workflow/references/flowchart.md +9 -6
- package/skills/agentic-mermaid-diagram-workflow/references/hosted-mcp.md +1 -0
- package/skills/agentic-mermaid-diagram-workflow/references/sequence.md +4 -3
- package/skills/agentic-mermaid-diagram-workflow/references/timeline.md +7 -6
- package/skills/agentic-mermaid-diagram-workflow/references/upstream/agentflow.md +574 -0
- package/skills/agentic-mermaid-diagram-workflow/references/upstream/architecture.md +10 -2
- package/skills/agentic-mermaid-diagram-workflow/references/upstream/c4.md +18 -0
- package/skills/agentic-mermaid-diagram-workflow/references/upstream/classDiagram.md +123 -0
- package/skills/agentic-mermaid-diagram-workflow/references/upstream/cynefin.md +6 -1
- package/skills/agentic-mermaid-diagram-workflow/references/upstream/entityRelationshipDiagram.md +129 -9
- package/skills/agentic-mermaid-diagram-workflow/references/upstream/eventmodeling.md +22 -0
- package/skills/agentic-mermaid-diagram-workflow/references/upstream/flowchart.md +188 -60
- package/skills/agentic-mermaid-diagram-workflow/references/upstream/gitgraph.md +13 -7
- package/skills/agentic-mermaid-diagram-workflow/references/upstream/mindmap.md +110 -1
- package/skills/agentic-mermaid-diagram-workflow/references/upstream/packet.md +38 -0
- package/skills/agentic-mermaid-diagram-workflow/references/upstream/requirementDiagram.md +115 -0
- package/skills/agentic-mermaid-diagram-workflow/references/upstream/sequenceDiagram.md +101 -0
- package/skills/agentic-mermaid-diagram-workflow/references/upstream/stateDiagram.md +87 -0
- package/skills/agentic-mermaid-diagram-workflow/references/upstream/swimlanes.md +105 -2
- package/skills/agentic-mermaid-diagram-workflow/references/upstream/timeline.md +12 -6
- package/skills/agentic-mermaid-diagram-workflow/references/upstream/usecase.md +953 -0
- package/skills/agentic-mermaid-diagram-workflow/references/upstream/venn.md +77 -0
- package/skills/agentic-mermaid-diagram-workflow/references/upstream/xyChart.md +1 -1
- package/dist/browser-lazy/chunks/architecture-KTHE2HX3.js +0 -31
- package/dist/browser-lazy/chunks/chunk-2XCPFAD5.js +0 -46
- package/dist/browser-lazy/chunks/chunk-3H4F7RBT.js +0 -1
- package/dist/browser-lazy/chunks/chunk-4EVLW2NJ.js +0 -1
- package/dist/browser-lazy/chunks/chunk-5Q4S74UO.js +0 -1
- package/dist/browser-lazy/chunks/chunk-6OAPWSDO.js +0 -1
- package/dist/browser-lazy/chunks/chunk-A7L4WWVW.js +0 -143
- package/dist/browser-lazy/chunks/chunk-C7FJO2I3.js +0 -4
- package/dist/browser-lazy/chunks/chunk-D3XXDKIO.js +0 -1
- package/dist/browser-lazy/chunks/chunk-DXA5WL7H.js +0 -4
- package/dist/browser-lazy/chunks/chunk-EPFMQPXX.js +0 -1
- package/dist/browser-lazy/chunks/chunk-FFOHLPDA.js +0 -2
- package/dist/browser-lazy/chunks/chunk-FLD63DXE.js +0 -2
- package/dist/browser-lazy/chunks/chunk-G6OLSHRG.js +0 -7
- package/dist/browser-lazy/chunks/chunk-GRXCKTHX.js +0 -0
- package/dist/browser-lazy/chunks/chunk-I6VE56S7.js +0 -1
- package/dist/browser-lazy/chunks/chunk-KJVNXJ5Y.js +0 -1
- package/dist/browser-lazy/chunks/chunk-L227EPFP.js +0 -11
- package/dist/browser-lazy/chunks/chunk-LNIHDJSF.js +0 -1
- package/dist/browser-lazy/chunks/chunk-M6BT2HIP.js +0 -1
- package/dist/browser-lazy/chunks/chunk-NZRUMODH.js +0 -1
- package/dist/browser-lazy/chunks/chunk-OFRMKQA6.js +0 -1
- package/dist/browser-lazy/chunks/chunk-P7HMSKHJ.js +0 -1
- package/dist/browser-lazy/chunks/chunk-PXKL3O6H.js +0 -1
- package/dist/browser-lazy/chunks/chunk-PZEWZT35.js +0 -1
- package/dist/browser-lazy/chunks/chunk-STQRDZ67.js +0 -1
- package/dist/browser-lazy/chunks/chunk-SUFMSWTX.js +0 -1
- package/dist/browser-lazy/chunks/chunk-T7IJ6V4B.js +0 -3
- package/dist/browser-lazy/chunks/chunk-UAEZO5VL.js +0 -1
- package/dist/browser-lazy/chunks/chunk-WEUWIFG3.js +0 -1
- package/dist/browser-lazy/chunks/chunk-X64T74C5.js +0 -24
- package/dist/browser-lazy/chunks/class-F7R6TJ73.js +0 -9
- package/dist/browser-lazy/chunks/er-BDK7CM5L.js +0 -9
- package/dist/browser-lazy/chunks/flowchart-KFU6XV7S.js +0 -4
- package/dist/browser-lazy/chunks/gantt-I64VVDSP.js +0 -28
- package/dist/browser-lazy/chunks/gitgraph-EDUVJ5IJ.js +0 -8
- package/dist/browser-lazy/chunks/journey-TLO2RNM3.js +0 -40
- package/dist/browser-lazy/chunks/mindmap-OJCNDYPM.js +0 -9
- package/dist/browser-lazy/chunks/pie-HVG6XO7K.js +0 -19
- package/dist/browser-lazy/chunks/quadrant-U6S2L4MJ.js +0 -24
- package/dist/browser-lazy/chunks/radar-ZDLOBTVG.js +0 -32
- package/dist/browser-lazy/chunks/render-core-Y2DFNMQG.js +0 -12
- package/dist/browser-lazy/chunks/sequence-Z4WFS3VB.js +0 -12
- package/dist/browser-lazy/chunks/state-2HV2YGN3.js +0 -4
- package/dist/browser-lazy/chunks/timeline-XM4UFPOC.js +0 -20
- package/dist/browser-lazy/chunks/xychart-7JDHWTQY.js +0 -36
- package/dist/chunk-GGXCNCNA.js +0 -4118
- package/dist/chunk-IVD4NXNE.js +0 -615
- package/dist/chunk-JDMRPUAG.js +0 -37
- package/dist/chunk-JWAAW3FH.js +0 -149
- package/dist/chunk-LCGBT32P.js +0 -62036
- package/dist/chunk-RWMZRUIC.js +0 -4715
- package/dist/mcp-cli-4MLKC3ZH.js +0 -17
- package/docs/mutation-testing.md +0 -285
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
`agentic-mermaid-mcp` defaults to stdio for local MCP clients. Use HTTP/SSE only when a client needs a reachable endpoint or when PNG artifacts should be fetched by file/URL instead of returned as large base64 strings.
|
|
4
4
|
|
|
5
|
-
> Looking for a zero-setup endpoint? A **hosted** MCP already runs at `https://agentic-mermaid.dev/mcp` (`claude mcp add --transport http agentic-mermaid https://agentic-mermaid.dev/mcp`). It is a different implementation — stateless Streamable HTTP, Cloudflare-backed,
|
|
5
|
+
> Looking for a zero-setup endpoint? A **hosted** MCP already runs at `https://agentic-mermaid.dev/mcp` (`claude mcp add --transport http agentic-mermaid https://agentic-mermaid.dev/mcp`). It is a different implementation — stateless Streamable HTTP, Cloudflare-backed, inputs capped at 64KB, and no file/URL PNG artifacts (base64 only) — with the tools <!-- BEGIN GENERATED: hosted-mcp-tools -->`execute`, `describe_sdk`, `render_svg`, `render_ascii`, `render_png`, `verify`, `describe`, `mutate`, and `build`<!-- END GENERATED: hosted-mcp-tools -->. See the [as-built record](./project/archive/hosted-mcp-cloudflare-plan.md). Run the local server below when you need file/URL artifacts, larger inputs, offline use, or your own auth.
|
|
6
6
|
>
|
|
7
|
-
> **Protocol versions.** The hosted endpoint is dual-era: it
|
|
7
|
+
> **Protocol versions.** The hosted endpoint is dual-era: it accepts <!-- BEGIN GENERATED: hosted-protocol-versions -->`2025-03-26`, `2025-06-18`, `2025-11-25`, and `2026-07-28`<!-- END GENERATED: hosted-protocol-versions -->. Every revision before `2026-07-28` is handshake-based; `2026-07-28` is the stateless revision that replaces the `initialize` handshake with per-request `_meta` and a mandatory `server/discover`. Clients need do nothing special — send whatever revision you speak in `MCP-Protocol-Version`, and an unsupported one comes back as `-32022` listing the versions we accept. The hosted endpoint does not accept `2024-11-05`: that revision is the HTTP+SSE *transport* (opening with `GET` and expecting an `endpoint` event), and a client using it receives 405. The local server below accepts <!-- BEGIN GENERATED: stdio-protocol-versions -->`2024-11-05`, `2025-06-18`, `2025-11-25`, and `2026-07-28`<!-- END GENERATED: stdio-protocol-versions --> over stdio and <!-- BEGIN GENERATED: http-sse-protocol-versions -->`2024-11-05`<!-- END GENERATED: http-sse-protocol-versions --> over its HTTP+SSE transport.
|
|
8
8
|
>
|
|
9
9
|
> **Privacy and caching:** every hosted call (`execute`, `render_*`, `verify`, `describe`, `mutate`, `build`) sends your diagram source or code to the agentic-mermaid.dev server. Successful deterministic pure-tool results may be reused by a private server-side Workers Cache for up to 24 hours; `execute`, `mutate`, and `build` bypass it. The JSON-RPC HTTP response itself is always `cache-control: no-store`; `x-agentic-mermaid-compute-cache` reports `hit`, `miss`, `mixed`, `bypass`, or `disabled`. For diagrams that must not leave your machine, use the library, the CLI, or the local stdio/HTTP server on this page — the pipeline is fully local and needs no network.
|
|
10
10
|
|
|
@@ -24,14 +24,14 @@ The local `/sse` + `/message` pair is the MCP SSE session transport: `POST /mess
|
|
|
24
24
|
Loopback/local development:
|
|
25
25
|
|
|
26
26
|
```sh
|
|
27
|
-
npx -y agentic-mermaid
|
|
27
|
+
npx -y agentic-mermaid mcp --transport http --host 127.0.0.1 --port 3000 \
|
|
28
28
|
--artifact-dir .agentic-mermaid-artifacts
|
|
29
29
|
```
|
|
30
30
|
|
|
31
31
|
Remote binding requires a bearer token:
|
|
32
32
|
|
|
33
33
|
```sh
|
|
34
|
-
npx -y agentic-mermaid
|
|
34
|
+
npx -y agentic-mermaid mcp --transport http --host 0.0.0.0 --port 3000 \
|
|
35
35
|
--artifact-dir .agentic-mermaid-artifacts \
|
|
36
36
|
--auth-token "$AGENTIC_MERMAID_MCP_TOKEN"
|
|
37
37
|
```
|
|
@@ -88,7 +88,7 @@ Response shape:
|
|
|
88
88
|
"content": [
|
|
89
89
|
{
|
|
90
90
|
"type": "text",
|
|
91
|
-
"text": "{\"ok\":true,\"png_base64\":\"iVBORw0KGgo
|
|
91
|
+
"text": "{\"ok\":true,\"png_base64\":\"iVBORw0KGgo…\",\"receipt\":{\"version\":2,\"output\":\"png\",…},\"runtime\":{\"engine\":\"resvg\",\"binding\":\"napi\",…},\"warnings\":[]}"
|
|
92
92
|
}
|
|
93
93
|
],
|
|
94
94
|
"isError": false
|
|
@@ -96,7 +96,7 @@ Response shape:
|
|
|
96
96
|
}
|
|
97
97
|
```
|
|
98
98
|
|
|
99
|
-
`warnings` always appears. `PNG_FONT_COVERAGE` names missing CJK/emoji coverage and points to `fontDirs`/`loadSystemFonts`; source configuration diagnostics use the same deterministic warning envelope.
|
|
99
|
+
`receipt` is the render request receipt (request/appearance digests plus the capability and execution decisions) and `runtime` records rasterizer provenance (engine, binding, font sources, reproducibility); both are also present on file and URL responses. `warnings` always appears. `PNG_FONT_COVERAGE` names missing CJK/emoji coverage and points to `fontDirs`/`loadSystemFonts`; source configuration diagnostics use the same deterministic warning envelope.
|
|
100
100
|
|
|
101
101
|
### File output
|
|
102
102
|
|
|
@@ -127,7 +127,10 @@ Response shape (`content[0].text` is JSON):
|
|
|
127
127
|
"mimeType": "image/png",
|
|
128
128
|
"bytes": 12345,
|
|
129
129
|
"sha256": "64 lowercase hex characters"
|
|
130
|
-
}
|
|
130
|
+
},
|
|
131
|
+
"receipt": { "version": 2, "output": "png", … },
|
|
132
|
+
"runtime": { "engine": "resvg", "binding": "napi", … },
|
|
133
|
+
"warnings": []
|
|
131
134
|
}
|
|
132
135
|
```
|
|
133
136
|
|
|
@@ -162,7 +165,10 @@ Response shape (`content[0].text` is JSON):
|
|
|
162
165
|
"mimeType": "image/png",
|
|
163
166
|
"bytes": 12345,
|
|
164
167
|
"sha256": "64 lowercase hex characters"
|
|
165
|
-
}
|
|
168
|
+
},
|
|
169
|
+
"receipt": { "version": 2, "output": "png", … },
|
|
170
|
+
"runtime": { "engine": "resvg", "binding": "napi", … },
|
|
171
|
+
"warnings": []
|
|
166
172
|
}
|
|
167
173
|
```
|
|
168
174
|
|
package/docs/quality.md
CHANGED
|
@@ -2,37 +2,42 @@
|
|
|
2
2
|
|
|
3
3
|
A diagram is considered **good looking** when it satisfies, in order:
|
|
4
4
|
|
|
5
|
-
1. **All Tier 1 structural checks pass.**
|
|
6
|
-
`EDGE_MISANCHORED`,
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
1. **All Tier 1 structural checks pass.** None of
|
|
6
|
+
<!-- BEGIN GENERATED: warning-codes:structural -->`EMPTY_DIAGRAM`, `EDGE_MISANCHORED`, `OFF_CANVAS`, `GROUP_BREACH`, `UNKNOWN_SHAPE`, `LABEL_OVERFLOW`, `UNRESOLVABLE_SCHEDULE`, `RENDER_FAILED`, `INTERNAL_ERROR`<!-- END GENERATED: warning-codes:structural -->
|
|
7
|
+
fires (`LABEL_OVERFLOW` default cap: 40 chars).
|
|
8
|
+
Resolve the reported structural or rendering failure before judging aesthetics.
|
|
9
9
|
|
|
10
10
|
2. **Tier 2 geometric checks are within bounds.** `NODE_OVERLAP` count
|
|
11
11
|
and `ROUTE_SELF_CROSS` count are advisory but not catastrophic. A
|
|
12
12
|
diagram with a single intentional overlap (e.g., a self-loop) is
|
|
13
13
|
still considered good. The `ROUTE_*` codes (`ROUTE_HITCH`,
|
|
14
14
|
`ROUTE_UNEXPLAINED_BEND`, `ROUTE_LABEL_ON_SHARED_TRUNK`,
|
|
15
|
-
`ROUTE_CONTAINER_MISANCHOR`, `ROUTE_SHAPE_MISANCHOR`,
|
|
15
|
+
`ROUTE_SELF_LOOP_OCCUPANCY`, `ROUTE_CONTAINER_MISANCHOR`, `ROUTE_SHAPE_MISANCHOR`,
|
|
16
16
|
`ROUTE_STALE_AFTER_NODE_MOVE`) should always be zero — they are
|
|
17
17
|
route-contract tripwires (see `docs/design/system/route-contracts.md`), and
|
|
18
18
|
any hit means the layout pipeline regressed, not the diagram.
|
|
19
|
+
<!-- complete: warning-codes:geometric -->
|
|
19
20
|
|
|
20
21
|
3. **Perceptual metrics fall in the default `QualityBounds` band:**
|
|
21
22
|
|
|
22
23
|
| metric | meaning | default |
|
|
23
24
|
|---|---|---|
|
|
24
|
-
| `edgeCrossings` |
|
|
25
|
-
| `labelLegibility` | fraction of
|
|
25
|
+
| `edgeCrossings` | visible proper crossing incidences per logical edge pair and location | ≤ 5% of visible edge pairs |
|
|
26
|
+
| `labelLegibility` | fraction of measured visible labels whose retained text bounds fit their actual containing region | ≥ 85% |
|
|
26
27
|
| `whitespaceBalance` | node area ÷ canvas area | 5%–55% (too sparse AND too dense lose) |
|
|
27
28
|
| `labelEdgeProximity` | min pixel distance between any edge-label box and a non-attached node, another edge-label box, or another edge path (graph families; cross-family label/box occlusion is gated by `eval/overlap-audit` + `label-overlap-gate.test.ts`) | ≥ 4 px |
|
|
28
|
-
| `
|
|
29
|
+
| `labelConflicts` | counts of padded graph label pills intersecting another label, a node, or another visible route; reported for Flowchart and State | minimize after crossings in candidate selection; no default quality bound |
|
|
30
|
+
| `routeOverlaps` | Flowchart/State edge pairs sharing opposing-direction ink or same-endpoint parallel ink (parallel excludes self-loops) | reported separately from crossings; no default quality bound |
|
|
31
|
+
| `minimumNodeSpacing` | nearest gap between semantically distinct node/mark boxes; authored coincident Quadrant points and XY/Radar data overlays are excluded | ≥ 8 px |
|
|
29
32
|
| `elementDensity` | nodes + edges per 10,000 canvas pixels | 0.02–6 |
|
|
30
33
|
| `minimumTextContrast` | WCAG contrast ratio between foreground and supplied background/surface colors; `null` when a requested paint cannot be resolved | ≥ 4.5:1 |
|
|
31
34
|
| `aspectRatio` | canvas w/h | 0.2–5.0 |
|
|
32
35
|
|
|
33
|
-
These are computed by `measureQuality(layout)`
|
|
34
|
-
|
|
35
|
-
|
|
36
|
+
These are computed by `measureQuality(layout)`; `checkQuality(layout)` applies
|
|
37
|
+
the configured bounds. `labelConflicts` is reported without a quality-bound
|
|
38
|
+
threshold, as is `routeOverlaps`. A low crossing count cannot establish
|
|
39
|
+
readability when routes instead share ambiguous collinear ink. These
|
|
40
|
+
measurements are **deterministic** and run on every PR.
|
|
36
41
|
|
|
37
42
|
4. **LLM-as-judge median ≥ 4.0** on the configured stratified sample of the
|
|
38
43
|
Mermaid-docs corpus across three axes. Since QUAL-1, perceptual metrics and
|
|
@@ -45,6 +50,123 @@ A diagram is considered **good looking** when it satisfies, in order:
|
|
|
45
50
|
supports pre-release sign-off when explicitly run. See
|
|
46
51
|
`eval/llm-judge/judge.ts`.
|
|
47
52
|
|
|
53
|
+
## Layout priorities and their limits
|
|
54
|
+
|
|
55
|
+
Authored meaning and deterministic execution constrain every aesthetic choice:
|
|
56
|
+
identities, endpoint markers, membership, labels and operation order must survive.
|
|
57
|
+
An authored data coordinate is meaning, so separating coincident chart points to
|
|
58
|
+
improve a spacing score is wrong. Resource admission also happens before layout;
|
|
59
|
+
a work-limit refusal is not a poor aesthetic score.
|
|
60
|
+
|
|
61
|
+
For automatic graph layout, apply the following order:
|
|
62
|
+
|
|
63
|
+
1. **Feasibility and readable ownership:** finite in-bounds geometry, containment,
|
|
64
|
+
non-overlapping graph nodes, endpoints on the rendered outline, routes that
|
|
65
|
+
avoid unrelated nodes, and labels associated with their own route. Among
|
|
66
|
+
feasible candidates, prefer readable group titles.
|
|
67
|
+
2. **Crossings, then soft label conflicts:** reduce crossings within the feasible
|
|
68
|
+
set. When crossing counts tie, prefer fewer padded label-conflict pairs.
|
|
69
|
+
These counts keep distinguishing layouts after minimum clearance reaches zero,
|
|
70
|
+
but reducing a soft overlap count cannot buy additional crossings. Hard
|
|
71
|
+
node-avoidance and own-label-association requirements still apply first.
|
|
72
|
+
3. **Continuity and unnecessary bends:** prefer clear direct lanes; distinguish
|
|
73
|
+
unexplained detours from declared symmetric convergence.
|
|
74
|
+
4. **Canonical ports:** prefer side midpoints or declared slots. An endpoint on
|
|
75
|
+
the correct outline is mandatory; the preferred point on that outline is a
|
|
76
|
+
softer choice and can yield to a simpler safe route.
|
|
77
|
+
5. **Symmetry and alignment:** improve balance without silently trading away
|
|
78
|
+
higher-priority constraints. Bundle-owned convergence is an explicit route
|
|
79
|
+
policy, with justified bends excluded from the avoidable-bend metric.
|
|
80
|
+
6. **Compactness, fill and aspect ratio:** use these as family-aware heuristics.
|
|
81
|
+
A data plot with sparse authored coordinates must not fail a graph box-fill
|
|
82
|
+
default; explicit caller bounds still apply.
|
|
83
|
+
|
|
84
|
+
This is a policy order, not a claim that the current heuristic pipeline solves a
|
|
85
|
+
global lexicographic optimum. Several older contracts pull in different
|
|
86
|
+
directions:
|
|
87
|
+
|
|
88
|
+
- Verification treats some overlap warnings as advisory, while the graph rubric
|
|
89
|
+
treats node overlap as hard. Graph final certification uses the stricter graph
|
|
90
|
+
contract; specialized plots need semantic overlap rules rather than a blanket
|
|
91
|
+
node-box rule.
|
|
92
|
+
- Cosmetic straightening and tightening must preserve crossings. Repairs of hard
|
|
93
|
+
node avoidance or own-label association may need a crossing; their conditional
|
|
94
|
+
pass budgets require a measured higher-priority repair. A padded label-conflict
|
|
95
|
+
count is a separate soft preference, not an additional hard feasibility gate.
|
|
96
|
+
- Symmetric fan-in can add geometric bends. The route classifier explains those
|
|
97
|
+
bends as convergence. This is a declared exception, not evidence that raw bend
|
|
98
|
+
count always decreases.
|
|
99
|
+
- Equalizing node dimensions can temporarily move centers before alignment
|
|
100
|
+
passes. Its old per-pass promise to improve symmetry was false and has been
|
|
101
|
+
removed. Preparation and final aesthetic claims are different obligations.
|
|
102
|
+
- A character-count `LABEL_OVERFLOW` guard does not measure rendered fit. Retained
|
|
103
|
+
prepared text and final containing bounds supply that evidence; missing
|
|
104
|
+
measurements produce an explicit quality warning.
|
|
105
|
+
|
|
106
|
+
The pass runner enforces declared before/after metric budgets in production,
|
|
107
|
+
including conditional allowances. Ordering, budgets and post-freeze contracts
|
|
108
|
+
always apply; there is no audit flag that disables them. A duplicate-lane proposal may introduce at
|
|
109
|
+
most one crossing per actual shared duplicate route pair it separates; unrelated
|
|
110
|
+
bucket improvements cannot pay for that proposal. Preferred endpoint spacing or
|
|
111
|
+
fewer bends alone cannot buy a crossing. Canonical ports may yield when the
|
|
112
|
+
certifying route owner measurably repairs hard geometry, reduces crossings or
|
|
113
|
+
removes bends.
|
|
114
|
+
The graph engine independently certifies the
|
|
115
|
+
final candidate before returning it, with at most four deterministic placement candidates
|
|
116
|
+
and an explicit `LAYOUT_CERTIFICATION_FAILED` error on exhaustion. This certifies
|
|
117
|
+
hard graph geometry, not minimum crossings or universal aesthetic quality.
|
|
118
|
+
Within 64 nodes/groups and 128 edges, a certified graph with crossings or label
|
|
119
|
+
conflicts may try one additional distinct strategy. Feasible candidates compare
|
|
120
|
+
readable group titles, crossings, label-conflict pairs, avoidable bends,
|
|
121
|
+
canonical endpoints, symmetry and area in that order.
|
|
122
|
+
|
|
123
|
+
The engine first chooses a certified bundled placement using those existing
|
|
124
|
+
strategies. Only the selected placement may then compare one completed generic
|
|
125
|
+
unbundled route proposal, using the same ELK result and the same preference
|
|
126
|
+
order. The decision to try this proposal reuses the selected placement's existing
|
|
127
|
+
certification score, including the final comparison: unchanged selected geometry
|
|
128
|
+
is not certified a second time. It does not explore an unbundled version of
|
|
129
|
+
every placement strategy.
|
|
130
|
+
Symmetric fan-in/fan-out routing remains enabled.
|
|
131
|
+
Graphs containing parallel edges keep their specialized route owners and skip
|
|
132
|
+
the generic unbundled proposal. A smaller proper-crossing count alone does not
|
|
133
|
+
prove that duplicate endpoint lanes remain visibly distinct.
|
|
134
|
+
|
|
135
|
+
The receipt's `preference.compared` entries retain the certified bundled
|
|
136
|
+
placement scores. `preference.selectedScore` describes the actual final routes,
|
|
137
|
+
and `preference.routing` records the selected placement's bundled/unbundled
|
|
138
|
+
comparison, scores and deciding criterion.
|
|
139
|
+
The receipt's `attempts` counts placement productions; the optional final route
|
|
140
|
+
comparison is recorded separately.
|
|
141
|
+
Clean graphs, equivalent strategies and larger inputs skip these comparisons;
|
|
142
|
+
the upper bound is four placement pipelines plus one unbundled route pipeline,
|
|
143
|
+
with the existing maximum of 16 ELK attempts. The unbundled proposal reuses the
|
|
144
|
+
selected placement's ELK result. Search decisions use graph
|
|
145
|
+
work counts, never elapsed time, so machine speed cannot change the drawing.
|
|
146
|
+
These route comparisons apply to Flowchart and State, which retain the scored
|
|
147
|
+
routes. Architecture uses the graph engine for placement and keeps its existing
|
|
148
|
+
feasibility/title fallback before independently routing authored endpoint sides.
|
|
149
|
+
The common positioning boundary also checks the final projection of every
|
|
150
|
+
native family against the family rubric's hard geometry rules. Specialized
|
|
151
|
+
layouters get one attempt and fail explicitly; their identical layout is not
|
|
152
|
+
repeated as a pretend fallback. Verification and quality reuse that retained
|
|
153
|
+
projection rather than positioning or projecting the artifact again.
|
|
154
|
+
|
|
155
|
+
Route proposals, final ranking, pass budgets and public quality share the crossing predicate in
|
|
156
|
+
`src/shared/edge-crossings.ts`. It excludes invisible shafts, endpoint contacts,
|
|
157
|
+
tangencies and shared collinear ink. It counts each crossing location once per
|
|
158
|
+
logical edge pair, including crossings far from a shared graph endpoint; route
|
|
159
|
+
subdivision does not change the count. Endpoint tolerance is 0.01 physical
|
|
160
|
+
pixels, independent of segment length. Public graph nodes, groups, paths, label
|
|
161
|
+
anchors and canvas bounds retain subpixel coordinates so projection cannot erase
|
|
162
|
+
this evidence or introduce a containment error.
|
|
163
|
+
Invisible links may still have visible labels: those pills remain obstacles.
|
|
164
|
+
Label-conflict counts share one implementation and the renderer's eight-pixel
|
|
165
|
+
pill padding. A bundle certificate or matching text does not authorize two
|
|
166
|
+
distinct labels to occupy the same space.
|
|
167
|
+
Label/node conflicts use conservative node bounding rectangles; hard route/node
|
|
168
|
+
avoidance retains its separate shape-aware contract.
|
|
169
|
+
|
|
48
170
|
## The rubric (used by both the LLM judge and the perceptual checker)
|
|
49
171
|
|
|
50
172
|
```
|
|
@@ -113,9 +235,10 @@ geometry assertions, screenshot/PNG review, or human inspection.
|
|
|
113
235
|
(not bytes-only) for each. The adapters parse `d.canonicalSource` via the
|
|
114
236
|
legacy per-family parser + layouter — the same geometry the SVG renderer draws
|
|
115
237
|
— so an opaque-but-renderable body is still measured; an invalid opaque body
|
|
116
|
-
|
|
238
|
+
fails explicitly with `FamilyLayoutError`; verification reports the failure. What `nodes` / `edges` /
|
|
117
239
|
`groups` mean per family:
|
|
118
240
|
|
|
241
|
+
<!-- complete: family-ids -->
|
|
119
242
|
| Family | nodes | edges | groups |
|
|
120
243
|
|---------------|------------------------------------|--------------|----------------------|
|
|
121
244
|
| flowchart | graph nodes (ELK) | graph edges | subgraphs |
|
|
@@ -133,12 +256,19 @@ geometry assertions, screenshot/PNG review, or human inspection.
|
|
|
133
256
|
| mindmap | hierarchy nodes | parent links | — |
|
|
134
257
|
| gitgraph | commits | parent links | — |
|
|
135
258
|
| radar | curve vertices (one ring per axis) | — | axis spokes/grid |
|
|
259
|
+
| sankey | node rectangles | ribbon links (from/to) | — |
|
|
136
260
|
|
|
137
261
|
Families with no structural relations (pie/quadrant/xychart/journey/gantt/radar) carry an
|
|
138
262
|
honestly-empty `edges` array. Bounds is the family layout's canvas size.
|
|
139
|
-
- **No font-substitution check.**
|
|
140
|
-
|
|
141
|
-
|
|
263
|
+
- **No font-substitution check.** Quality checks consume retained prepared pixel
|
|
264
|
+
text and renderer anchors; they do not guess width from character count.
|
|
265
|
+
`labelMeasurement` reports measured, unmeasured, hidden and semantic-only
|
|
266
|
+
labels, and missing visible-label evidence makes `checkQuality` warn. Painted
|
|
267
|
+
text in `layout.labels` participates without changing semantic node counts;
|
|
268
|
+
XYChart retains its point text and chart chrome there. Final canvas and
|
|
269
|
+
readability checks consume those retained bounds. A trusted
|
|
270
|
+
host measurement profile can improve pixel metrics, but neither that profile
|
|
271
|
+
nor a prepared block proves which font the display ultimately substituted.
|
|
142
272
|
- **Contrast needs resolved paints.** `measureQuality(layout)` scores the crisp
|
|
143
273
|
default palette. For a custom style, pass `{ foreground, background,
|
|
144
274
|
surfaces }` as its second argument, or pass the actual rendered text/surface
|
package/docs/react.md
CHANGED
|
@@ -1,29 +1,75 @@
|
|
|
1
1
|
# React integration
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Browser-rendered React components should use the browser ESM entry. It loads the
|
|
4
|
+
selected diagram family on demand and does not pull the Node/native package
|
|
5
|
+
entry into a client bundle.
|
|
4
6
|
|
|
5
7
|
## Basic component
|
|
6
8
|
|
|
7
9
|
```tsx
|
|
8
|
-
|
|
9
|
-
import { renderMermaidSVG } from 'agentic-mermaid'
|
|
10
|
+
'use client'
|
|
10
11
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
() => renderMermaidSVG(source, { security: 'strict' }),
|
|
14
|
-
[source],
|
|
15
|
-
)
|
|
12
|
+
import { useEffect, useId, useRef, useState } from 'react'
|
|
13
|
+
import { renderMermaidSVGAsync } from 'agentic-mermaid/browser/lazy'
|
|
16
14
|
|
|
17
|
-
|
|
15
|
+
export function MermaidDiagram({ source }: { source: string }) {
|
|
16
|
+
const output = useRef<HTMLDivElement>(null)
|
|
17
|
+
const idPrefix = `diagram-${useId().replace(/[^a-zA-Z0-9_-]/g, '')}`
|
|
18
|
+
const [loading, setLoading] = useState(true)
|
|
19
|
+
const [error, setError] = useState('')
|
|
20
|
+
|
|
21
|
+
useEffect(() => {
|
|
22
|
+
let current = true
|
|
23
|
+
const host = output.current
|
|
24
|
+
if (!host) return
|
|
25
|
+
host.replaceChildren()
|
|
26
|
+
setLoading(true)
|
|
27
|
+
setError('')
|
|
28
|
+
renderMermaidSVGAsync(source, { security: 'strict', idPrefix }).then(
|
|
29
|
+
result => {
|
|
30
|
+
if (!current) return
|
|
31
|
+
const parsed = new DOMParser().parseFromString(result, 'image/svg+xml')
|
|
32
|
+
if (parsed.querySelector('parsererror') || parsed.documentElement.localName !== 'svg') {
|
|
33
|
+
setError('Renderer returned invalid SVG')
|
|
34
|
+
setLoading(false)
|
|
35
|
+
return
|
|
36
|
+
}
|
|
37
|
+
host.replaceChildren(document.importNode(parsed.documentElement, true))
|
|
38
|
+
setLoading(false)
|
|
39
|
+
setError('')
|
|
40
|
+
},
|
|
41
|
+
).catch(cause => {
|
|
42
|
+
if (!current) return
|
|
43
|
+
setError(cause instanceof Error ? cause.message : String(cause))
|
|
44
|
+
setLoading(false)
|
|
45
|
+
})
|
|
46
|
+
return () => { current = false }
|
|
47
|
+
}, [source, idPrefix])
|
|
48
|
+
|
|
49
|
+
return <>
|
|
50
|
+
{error && <pre role="alert">{error}</pre>}
|
|
51
|
+
<div ref={output} className="diagram diagram-surface" aria-busy={loading} />
|
|
52
|
+
</>
|
|
18
53
|
}
|
|
19
54
|
```
|
|
20
55
|
|
|
21
|
-
`security: 'strict'` removes external-fetch references and is the safest default
|
|
56
|
+
`security: 'strict'` removes external-fetch references and is the safest default
|
|
57
|
+
for user- or agent-generated diagrams. The cancellation guard prevents an older
|
|
58
|
+
render from replacing a newer source after it resolves. The per-component
|
|
59
|
+
`idPrefix` prevents collisions between SVG definitions in multiple diagrams.
|
|
60
|
+
Insert only this renderer's strict output, not arbitrary SVG: XML parsing is
|
|
61
|
+
not sanitization. Rendering policy and the host's DOM/CSP policy remain separate.
|
|
62
|
+
|
|
63
|
+
This basic recipe assumes the host does not enforce Trusted Types. With
|
|
64
|
+
`require-trusted-types-for 'script'`, `DOMParser.parseFromString` is also a
|
|
65
|
+
protected sink: adapt insertion through the application's reviewed,
|
|
66
|
+
narrowly scoped TrustedHTML policy. Do not add a permissive default policy or
|
|
67
|
+
disable CSP to make the example work. See [`browser.md`](./browser.md).
|
|
22
68
|
|
|
23
69
|
## Theme from CSS variables
|
|
24
70
|
|
|
25
71
|
```tsx
|
|
26
|
-
const svg =
|
|
72
|
+
const svg = await renderMermaidSVGAsync(source, {
|
|
27
73
|
bg: 'var(--diagram-bg)',
|
|
28
74
|
fg: 'var(--diagram-fg)',
|
|
29
75
|
accent: 'var(--diagram-accent)',
|
|
@@ -55,7 +101,7 @@ Because the SVG keeps CSS variables in place, toggling `.dark` updates existing
|
|
|
55
101
|
|
|
56
102
|
## PNG export button
|
|
57
103
|
|
|
58
|
-
PNG rendering returns bytes.
|
|
104
|
+
PNG rendering returns bytes. The native helper below needs a server action/API route or other Node-capable boundary where `@resvg/resvg-js` is available.
|
|
59
105
|
|
|
60
106
|
```ts
|
|
61
107
|
import { renderMermaidPNG } from 'agentic-mermaid/agent'
|
|
@@ -65,31 +111,30 @@ export function renderDiagramPng(source: string) {
|
|
|
65
111
|
}
|
|
66
112
|
```
|
|
67
113
|
|
|
68
|
-
For client-only exports,
|
|
114
|
+
For client-only exports, the root `agentic-mermaid` entry also exports a
|
|
115
|
+
host-injected browser PNG path: `renderMermaidPNGInBrowserWithReceipt(source,
|
|
116
|
+
options, output, rasterize)` or the reusable
|
|
117
|
+
`createMermaidBrowserPNGRenderer({ rasterize })`. No browser rasterizer ships
|
|
118
|
+
with the library: the host supplies `rasterize(securedSvg, context)` (for
|
|
119
|
+
example with Canvas/OffscreenCanvas), which must resolve to `{ png }` bytes at
|
|
120
|
+
exactly `context.rasterDimensions` on `context.rasterBackground`, and may report
|
|
121
|
+
`fontSources` and `diagnostics`. See [browser PNG details](./api-advanced.md#png-fonts-portability-and-rasterization). Otherwise, post
|
|
122
|
+
the source to a server endpoint.
|
|
69
123
|
|
|
70
124
|
## Error handling
|
|
71
125
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
export function SafeDiagram({ source }: { source: string }) {
|
|
78
|
-
const result = useMemo(() => {
|
|
79
|
-
const parsed = parseRegisteredMermaid(source)
|
|
80
|
-
if (!parsed.ok) return { ok: false, message: parsed.error.map(e => e.message).join('\n') }
|
|
126
|
+
The component above reports parse and render failures through its `role="alert"`
|
|
127
|
+
fallback. If a client workflow also needs structured parse/verify results, use
|
|
128
|
+
the runtime-neutral agent entry; do not import the Node/native
|
|
129
|
+
`agentic-mermaid/agent` entry into the browser bundle:
|
|
81
130
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
return { ok: true, svg: renderMermaidSVG(parsed.value, { security: 'strict' }) }
|
|
86
|
-
}, [source])
|
|
87
|
-
|
|
88
|
-
if (!result.ok) return <pre>{result.message}</pre>
|
|
89
|
-
return <div dangerouslySetInnerHTML={{ __html: result.svg }} />
|
|
90
|
-
}
|
|
131
|
+
```ts
|
|
132
|
+
import { parseRegisteredMermaid, verifyMermaid } from 'agentic-mermaid/agent/core'
|
|
91
133
|
```
|
|
92
134
|
|
|
135
|
+
For server components, build steps, and API routes, the synchronous
|
|
136
|
+
`renderMermaidSVG` export from `agentic-mermaid` remains appropriate.
|
|
137
|
+
|
|
93
138
|
## See also
|
|
94
139
|
|
|
95
140
|
- [`api.md`](./api.md) for render options.
|
package/docs/style-authoring.md
CHANGED
|
@@ -98,6 +98,19 @@ not-applicable evidence; they never repaint or relayout. Transparent output has
|
|
|
98
98
|
no known host backdrop, so contrast reports unmeasurable rather than inventing
|
|
99
99
|
a ratio.
|
|
100
100
|
|
|
101
|
+
Treemap retains explicit Scene text ink when deriving automatic category fills. Its
|
|
102
|
+
shared palette chooses readable, page-visible and distinguishable colors
|
|
103
|
+
together, before brand constraints inspect the Scene. Sketch labels that already
|
|
104
|
+
read on the selected backend's page-colored halo do not constrain the cell fill.
|
|
105
|
+
The actual graphical backend includes host overrides; layout models its nominal
|
|
106
|
+
Style backend. Authored fills stay exact.
|
|
107
|
+
The shared sketch backend still applies its existing page-halo readability
|
|
108
|
+
policy to ink that does not read on that page.
|
|
109
|
+
If bounded search cannot satisfy concrete ink/page choices, choose another text
|
|
110
|
+
color or an explicit readable fill; the renderer reports that configuration
|
|
111
|
+
limit. Unresolved and translucent inks retain their authored values without a
|
|
112
|
+
contrast guarantee.
|
|
113
|
+
|
|
101
114
|
### Export and edit a built-in
|
|
102
115
|
|
|
103
116
|
Built-ins dogfood this same record format. Export one with `getStyle`, validate
|
|
@@ -130,11 +143,8 @@ BrandPack registry is deliberately **not promoted**. Render-time semver ranges,
|
|
|
130
143
|
dependency solving, ambient resource loading, and a second inheritance system
|
|
131
144
|
remain absent.
|
|
132
145
|
|
|
133
|
-
The
|
|
134
|
-
|
|
135
|
-
family role/channel, and built-in export.
|
|
136
|
-
The [all-family evidence sheet](./design/families/section-b-brand-evidence.png)
|
|
137
|
-
shows one deliberately distinctive sentinel plus three holdout styles; its receipt
|
|
146
|
+
The [reviewed all-family rendering golden](../src/__tests__/testdata/section-b-brand-evidence.png)
|
|
147
|
+
shows one deliberately distinctive sentinel plus three holdout styles; its review record
|
|
138
148
|
and honest hard-error baseline live in `eval/section-b-brand-evidence/`.
|
|
139
149
|
|
|
140
150
|
Every field is optional in a reusable fragment, but the resolved final stack
|
|
@@ -162,7 +172,7 @@ accepted as a Style name.
|
|
|
162
172
|
sets via `RenderOptions` colors or Mermaid `themeVariables` wins. The full
|
|
163
173
|
precedence is one line: `defaults < style stack (left→right) <
|
|
164
174
|
themeVariables < explicit color options`.
|
|
165
|
-
- **Determinism.** All stochastic
|
|
175
|
+
- **Determinism.** All stochastic artwork is seeded
|
|
166
176
|
`hash(options.seed, stableNodeId, substream)`. Source, resolved options,
|
|
167
177
|
frozen registry/capability/resource snapshots, runtime contract and seed fix
|
|
168
178
|
the bytes. `seed` re-rolls wobble without moving layout. Opt-in caller or
|
|
@@ -241,12 +251,14 @@ layout-aware dialect) justifies code. Trusted hosts can implement and register
|
|
|
241
251
|
a namespaced `StyleBackend`; selection is an in-process `HostBackendPolicy`,
|
|
242
252
|
not serializable Style data or a CLI/MCP/editor field. Keep the determinism rule
|
|
243
253
|
(seed in, bytes out). Backends never dispatch on diagram family — they see
|
|
244
|
-
semantic
|
|
254
|
+
semantic Scene parts and paint channels. Existing `SceneNode` and `*Mark` type
|
|
255
|
+
names refer to those parts; see the [shared vocabulary](./api.md#vocabulary).
|
|
256
|
+
A registered backend also declares
|
|
245
257
|
feature/operation-level `PrimitiveCapabilityClaim`s for every core Scene
|
|
246
258
|
primitive; registration rejects empty, duplicate, or cross-target claims so an
|
|
247
259
|
extension cannot imply support it has not described. Registration then executes
|
|
248
260
|
a frozen document fixture plus one exact witness for each declared first-party
|
|
249
|
-
core primitive/feature/operation claim. It rejects a backend that varies
|
|
261
|
+
core Scene primitive/feature/operation claim. It rejects a backend that varies
|
|
250
262
|
identical `drawNode`/`render` calls, emits unsafe or malformed SVG, drops the
|
|
251
263
|
document sentinels, or fails any claim-keyed witness. Namespaced extension claims
|
|
252
264
|
with no core witness remain explicitly `unverified-extension`.
|
|
@@ -260,7 +272,7 @@ contract explicitly; no built-in compatibility default is borrowed by
|
|
|
260
272
|
```ts
|
|
261
273
|
registerBackend(backend, {
|
|
262
274
|
version: '1.0.0',
|
|
263
|
-
compatibility: { core: '^0.
|
|
275
|
+
compatibility: { core: '^0.5.0', scene: '^2.0.0' },
|
|
264
276
|
provenance: { owner: 'acme-diagrams', source: 'application-startup' },
|
|
265
277
|
})
|
|
266
278
|
```
|
|
@@ -330,7 +342,7 @@ bun test src/__tests__/styled-output.test.ts --timeout 30000 # determinism + g
|
|
|
330
342
|
bun test src/__tests__/scene-fidelity.test.ts # semantic/backend agreement
|
|
331
343
|
```
|
|
332
344
|
|
|
333
|
-
Then render your style across every registered diagram
|
|
334
|
-
— the poster/contact-sheet harness in `scripts/sketch-prototype/` is the
|
|
345
|
+
Then render your style across every registered diagram family and *look at it small*
|
|
346
|
+
— the optional research poster/contact-sheet harness in `scripts/sketch-prototype/` is the
|
|
335
347
|
visual-review surface. A style ships when it is distinctive at a glance,
|
|
336
348
|
legible at cell size, and honest to its intent.
|