remark-mermaid-tldraw — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited remark-mermaid-tldraw (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Pre-render `mermaid fences into tldraw's hand-drawn SVGs at build time. It's two cooperating parts that agree on a filename and never talk to each other:
<img> tags, andreal tldraw editor in Playwright-Chromium and writes the SVGs.
The reader downloads an <img> — no mermaid, no tldraw, no hydration. Package: remark-mermaid-tldraw · GitHub.
npm i -D remark-mermaid-tldraw tldraw @tldraw/mermaid playwright react react-dom
npx playwright install chromiumtldraw, @tldraw/mermaid, playwright, react, react-dom are peer deps (the renderer needs a browser + the React/tldraw stack). vite, @vitejs/plugin-react, unist-util-visit, mdast-util-from-markdown, and tinyglobby come along as regular deps. The remark plugin itself is lightweight — it does NOT pull in tldraw/playwright, so importing it in a config is cheap.
It rewrites each `mermaid fence into <figure class="mermaid-diagram not-prose"> with a light and a dark <img> pointing at /diagrams/<hash>.svg.
import { remarkMermaidTldraw } from "remark-mermaid-tldraw";
// in your markdown/MDX remarkPlugins:
remarkPlugins: [remarkMermaidTldraw];
// or with options: [remarkMermaidTldraw, { theme: "dark" }]A prebuild CLI for most setups:
// package.json
"scripts": {
"mermaid": "remark-mermaid-tldraw --content \"src/**/*.{md,mdx}\" --out public/diagrams"
}Run npm run mermaid whenever a diagram changes, and commit public/diagrams/. (Or wire it into a prebuild step if your CI has a browser.) On Astro, prefer the integration — it auto-renders on config:setup and hot-reloads in dev:
import { mermaidTldraw } from "remark-mermaid-tldraw/astro";
export default defineConfig({
integrations: [mermaidTldraw()],
markdown: { remarkPlugins: [remarkMermaidTldraw] },
});Both variants are emitted with transparent backgrounds; you pick one per scheme:
.mermaid-dark { display: none; }
@media (prefers-color-scheme: dark) {
.mermaid-light { display: none; }
.mermaid-dark { display: inline; }
}
/* class-based theme: html.dark .mermaid-light{display:none} html.dark .mermaid-dark{display:inline} */
.mermaid-diagram { margin: 2rem auto; display: flex; justify-content: center; }
.mermaid-diagram img { width: 100%; height: auto; }On a single-theme site, pass { theme: "dark" } (or "light") to the plugin so the browser never fetches the variant it can't show.
flowchart TD A --> B
width= (bare number → px, or any CSS length) caps a tall flowchart's width.
The plugin emits a raw HTML <figure> node. Plain markdown (Astro .md, remark-rehype) handles that fine. MDX does not — @mdx-js throws Cannot handle unknown node "raw". Fix: add rehype-raw as the FIRST rehype plugin, with passThrough for MDX's own node types, or it will destroy any JSX components in your .mdx files:
import rehypeRaw from "rehype-raw";
rehypePlugins: [
[rehypeRaw, {
passThrough: [
"mdxFlowExpression", "mdxJsxFlowElement", "mdxJsxTextElement",
"mdxTextExpression", "mdxjsEsm",
],
}],
// ...your other rehype plugins after this
](npm i -D rehype-raw.) This step is MDX-only; skip it for plain-markdown pipelines.
markdown.remarkPlugins + the /astrointegration. No rehype-raw needed (Astro markdown handles raw HTML).
remarkPlugins,add rehype-raw (passThrough) as the first rehypePlugins entry, run the CLI as a prebuild.
@next/mdx) — plugin in remarkPlugins, rehype-raw(passThrough) in rehypePlugins, CLI prebuild over content//app/.
sha256(source).slice(0,16) — the URL depends ONLY on thediagram source, so it never changes when render logic does.
RENDER_VERSION(or visual changes from a tldraw upgrade) → diagrams re-render in place, URLs stay stable.
browser.
preloads tldraw's fonts before rendering, so this is handled. If you see it, you're on an old version — update.
rehype-raw. See the gotcha above.
changes the hash → a new file. To GC old files run the CLI with --clean.
class, ER) isn't modeled natively by tldraw, so it falls back to mermaid's own SVG. Flowcharts and sequence diagrams get the tldraw look.
npx playwright install chromium to the workflow before therender/build step.
Build-time only: you need a browser where you build (and in CI). The payoff is zero runtime cost — the visitor gets a cached SVG, never mermaid or tldraw.
Built by Sean Geng; generalizes Sunil Pai's Astro plugin and stands on @tldraw/mermaid. Full writeup: Rendering mermaid diagrams as hand-drawn tldraw.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.