---
title: MoonBit のパッケージ依存関係を 6 通りの図で描いた
description: moon tree と moon ide outline でこのブログの MoonBit パッケージの依存関係を取り出し、mermaid（dagre / ELK）、beautiful-mermaid、d2（dagre / ELK / TALA）の 6 通りで描いて見比べた。それぞれのインストールと使い方、SVG を PNG にして確かめた話も。
prev: 2026-10-26-draw-svg-with-llm.md
---

`moonbit/` の下には、このブログを動かしている MoonBit のパッケージが 17 個ある。
`pkg/` にライブラリ、`examples/blog/` にそれを使うアプリケーション、という分け方は Go 版と同じだ。
最近は `pkg/http` や `examples/blog/worker` が増えて、どこがどこに依存しているのかを口で説明するのが面倒になってきた。

そこで[issue #85](https://github.com/podhmo/html-sandbox/issues/85#issuecomment-6421445157)で、依存関係を図にしてみることにした。
せっかくなので描き方を 1 つに決めず、mermaid（dagre と ELK）、beautiful-mermaid（ELK）、d2（dagre、ELK、TALA）の 6 通りを並べて比べる。
同じグラフを別のエンジンがどう配置するかは、実際に見るまで分からない。

## まず依存関係を取り出す

MoonBit のツールチェーンには、依存関係を見るためのコマンドが 2 つある。
`moon tree` と `moon ide outline` だ。

### moon tree

まず何も付けずに `moon tree` を `moonbit/` で実行する。

```console
$ cd moonbit
$ moon tree
podhmo/html-sandbox@0.1.0 (local /home/po/ghq/github.com/podhmo/html-sandbox/moonbit):
└─ moonbitlang/async -> moonbitlang/async@0.22.5
```

これはモジュール単位の依存で、このモジュールが使っているのは `moonbitlang/async` だけだ。
自分たちのパッケージ同士の関係は出てこない。
欲しいのはそちらなので、`--package` を付ける。

```console
$ moon tree --package
```

こちらはパッケージを起点に、そのパッケージが import しているパッケージを展開する。
テキストでも読めるが、図を描くには JSON のほうが扱いやすい。
`--json` を付けると、ノードとエッジがそのまま入った 1 個の JSON になる。

```console
$ moon tree --package --json > /tmp/pkgtree.json
```

中身はこうなっている（抜粋）。

```json
{
  "version": 2,
  "status": "success",
  "root": [33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49],
  "nodes": [
    {
      "module": "podhmo/html-sandbox",
      "version": "0.1.0",
      "source": { "kind": "local", "path": "/home/po/ghq/github.com/podhmo/html-sandbox/moonbit" },
      "rel": "pkg/el"
    },
    { "module": "moonbitlang/async", "version": "0.22.5", "source": { "kind": "registry" }, "rel": "http" }
  ],
  "edges": [
    { "from": 46, "to": 42, "alias": "el", "kinds": ["source"] }
  ]
}
```

`root` がこのモジュールのパッケージで、`nodes` には依存先のモジュールのパッケージも入る。
`edges` の `kinds` が import の種類で、`source` はコードが必要としている依存、`blackbox-test` はテストだけが必要としている依存だ。
`alias` は `moon.pkg` に書いた `@el` のような別名で、図には出さないが、どの import かを見分けるのに便利だった。

標準ライブラリは `nodes` に入らない。
`moon tree --package --json` は「standard library 以外のパッケージ」を返すと書いてあるので、`moonbitlang/core/*` は最初からいない。
今回はこのモジュールの中の関係だけを描くので、`module` が `podhmo/html-sandbox` のノードだけを残し、外のモジュールへのエッジは `external` として別に保存した。
`examples/blog/compare/cmd` が `moonbitlang/async` の 3 パッケージを使っているのが、その 3 本だ。

### moon ide outline

依存の線だけだと、どのパッケージが大きいのか分からない。
`moon ide outline` はパッケージのファイルと宣言（関数、型、定数など）を一覧にしてくれる。

```console
$ moon ide outline pkg/picoel
picoel.mbt:
 11 |pub const STYLESHEET_URL = "https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.min.css"
    |...
 17 |pub fn document(
 18 |  lang : String,
 19 |  head~ : Array[@el.Node],
 20 |  body~ : Array[@el.Node],
 21 | ) -> @el.Node {
    |...
```

ファイル名の見出しと、行番号付きの宣言が並ぶ。
これをパッケージごとに実行して、宣言の数と `pub` の数を数えれば、ノードの大きさの目安になる。

ここで 2 つつまずいた。

1 つは、`moon ide outline` はパッケージがビルドされるターゲットを必要とすること。
`pkg/tinymarkdown/js` は js ターゲット専用で、デフォルトのターゲットでは「could not find package」と言われる。
`--target js` を付けると読める。
`examples/blog/compare/cmd` は native 専用なので `--target native` だ。
スクリプトでは、デフォルト、`wasm-gc`、`native`、`js` の順に試して、ファイルの見出しが含まれていたら採用するようにした。

もう 1 つは、そのエラーでも終了コードが 0 のときがあること。

```console
$ moon ide outline examples/blog/compare/cmd
Error: could not find package for folder /.../examples/blog/compare/cmd
$ echo $?
0
```

最初は「成功したのに空の出力」を受け取ってしまい、宣言数が 0 になった。
なので、出力に `main.mbt:` のような見出しがあるかどうかで判断している。

あと、正規表現で宣言を数えるときは `async fn` を忘れないほうがいい。
`main.mbt` は `async fn fetch`、`async fn try_fetch`、`async fn main` の 3 つで、`fn` だけを見ていると全部取りこぼす。

### graph.json

2 つをまとめて `graph.json` にした。
`moonbit/experiments/pkg-graph/scripts/extract-graph.mjs` が `moon tree --package --json` を呼び、各パッケージに `moon ide outline` の数字を足す。

```json
{
  "project": "podhmo/html-sandbox",
  "generatedBy": "moon tree --package --json, annotated with moon ide outline",
  "moonVersion": "moon 0.1.20261012 (748b63c 2026-10-12)",
  "packages": [
    {
      "name": "pkg/el",
      "kind": "library",
      "files": 4,
      "testFiles": 2,
      "declarations": 80,
      "public": 71
    }
  ],
  "edges": [
    { "from": "pkg/picoel", "to": "pkg/el", "kinds": ["source"] }
  ],
  "external": [
    { "from": "examples/blog/compare/cmd", "to": "moonbitlang/async/http", "kinds": ["source"] }
  ]
}
```

`kind` は `moon tree` が返すものではなく、こちらの分類だ。
`pkg/` を `library`、`examples/blog/` を `application`、`examples/blog/{assets,posts,slops,repodocs}` を、embed スクリプトが生成する `generated` とした。
生成物を手書きのコードと同じ形で描くと、依存の読み方が変わってしまうからだ。

17 パッケージの数字はこうなった。

| パッケージ | 種別 | ソース | テスト | 宣言 | pub |
| --- | --- | ---: | ---: | ---: | ---: |
| `examples/blog/assets` | generated | 1 | 0 | 8 | 8 |
| `examples/blog/compare` | application | 1 | 1 | 9 | 7 |
| `examples/blog/compare/cmd` | application | 1 | 0 | 3 | 0 |
| `examples/blog/posts` | generated | 1 | 0 | 4 | 1 |
| `examples/blog/preview` | application | 1 | 1 | 1 | 1 |
| `examples/blog/repodocs` | generated | 1 | 1 | 22 | 1 |
| `examples/blog/site` | application | 7 | 2 | 115 | 14 |
| `examples/blog/slops` | generated | 1 | 1 | 18 | 1 |
| `examples/blog/worker` | application | 1 | 0 | 11 | 2 |
| `pkg/el` | library | 4 | 2 | 80 | 71 |
| `pkg/http` | library | 6 | 1 | 49 | 42 |
| `pkg/http/wasm` | library | 2 | 2 | 18 | 7 |
| `pkg/http/wasm/integration` | library | 1 | 0 | 8 | 2 |
| `pkg/picoel` | library | 1 | 1 | 37 | 35 |
| `pkg/tinyfrontmatter` | library | 1 | 1 | 10 | 5 |
| `pkg/tinymarkdown` | library | 2 | 3 | 39 | 14 |
| `pkg/tinymarkdown/js` | library | 1 | 1 | 15 | 3 |

エッジは 21 本。
`examples/blog/site` から出るものが 9 本と多く、`pkg/el` は 3 本（`preview`、`site`、`picoel`）を受けている。
テストだけの依存は、`site` から `posts`、`slops`、`repodocs` への 3 本と、`tinymarkdown` から `repodocs` への 1 本だった。
図ではこれを破線にして `test` とラベルを付ける。

## 6 通りを描く

同じ `graph.json` から、mermaid 用と d2 用のソースを生成する。
ノードは 17 個、エッジは 21 本で、向きは左から右。
`pkg/` は四角、アプリケーションは角の丸い箱、生成物はシリンダーにした（d2 は全部四角になる）。

最初はカテゴリーごとのサブグラフ（mermaid の `subgraph`、d2 のコンテナ）で囲んでいたが、dagre だと 3 つのクラスタが斜めに積み重なって 1209x1360 の読みにくい図になった。
エンジンの違いを見るのが目的なので、クラスタはやめて色と形だけで区別している。

### mermaid（dagre と ELK）

mermaid は npm で入れる。
ELK レイアウトは別パッケージになっているので、それも入れる。

```console
$ npm install mermaid@12.2.0 @mermaid-js/layout-elk@1.0.1 puppeteer
$ npx puppeteer browsers install chrome
```

mermaid はブラウザーで描くライブラリなので、SVG を作るには DOM が要る。
そのために puppeteer で Chrome を動かす。
`mermaid-cli`（`mmdc`）もあるのだが、設定ファイルに `{"layout":"elk"}` を書いても dagre とバイト単位で同じ SVG が出てきた。
mermaid-cli が同梱している mermaid には ELK のローダーが登録されていないようだ。
`@mermaid-js/layout-elk` を `mermaid.registerLayoutLoaders()` に渡す必要がある。

なので、mmdc は使わず、小さなページを自分で用意した。

```html
<script type="module">
  import mermaid from "/node_modules/mermaid/dist/mermaid.esm.min.mjs";
  import elkLayouts from "/node_modules/@mermaid-js/layout-elk/dist/mermaid-layout-elk.esm.min.mjs";

  mermaid.registerLayoutLoaders(elkLayouts);

  let n = 0;
  window.renderDiagram = async (code, layout) => {
    mermaid.initialize({
      startOnLoad: false,
      layout,
      theme: "default",
      securityLevel: "loose",
      flowchart: { htmlLabels: true, useMaxWidth: false },
    });
    const { svg } = await mermaid.render(`diagram-${n++}`, code);
    return svg;
  };
</script>
```

Chrome は `file://` からの ES モジュールの import を拒否するので、実験ディレクトリをローカル HTTP サーバーで配る。
puppeteer でそのページを開き、`page.evaluate()` で `window.renderDiagram(code, "elk")` を呼んで SVG を受け取る。
`useMaxWidth: false` にしておくと、SVG に実寸の `width` と `height` が入る。

mermaid のソースはこうなった（先頭部分）。

```text
graph LR
  examples_blog_assets[("examples/blog/assets")]
  examples_blog_compare("examples/blog/compare")
  pkg_el["pkg/el"]
  pkg_picoel["pkg/picoel"]
  classDef library fill:#e8f0fe,stroke:#1a73e8,color:#1a3a6b
  classDef application fill:#fff4e5,stroke:#e8710a,color:#7a3b00
  classDef generated fill:#f1f3f4,stroke:#9aa0a6,color:#3c4043,stroke-dasharray:4 3
  class pkg_el,pkg_picoel library
  pkg_picoel --> pkg_el
  examples_blog_site -. "test" .-> examples_blog_posts
```

ノード ID には `/` が使えないので、`pkg/el` を `pkg_el` に置き換えている。
ラベルには元の名前をそのまま入れた。

### beautiful-mermaid

beautiful-mermaid は mermaid の別実装で、ELK を内部に持っていて、ブラウザーなしで同期に SVG を返す。

```console
$ npm install beautiful-mermaid@1.1.3
```

```js
import { renderMermaidSVG } from "beautiful-mermaid";

const svg = renderMermaidSVG(code, {
  bg: "#ffffff",
  fg: "#27272a",
  accent: "#1a73e8",
});
```

同じ mermaid のソースがそのまま読めた。
`classDef` の色、シリンダー、破線のエッジと `test` ラベルも保持している。
ブラウザーも Chrome も要らないので、この 6 通りの中で一番手軽だった。

### d2

d2 はバイナリを入れる。
公式のインストールスクリプトに prefix を渡すと、その下の `bin/` に入る。

```console
$ curl -fsSL https://d2lang.com/install.sh | sh -s -- --prefix "$HOME/.local"
$ export PATH="$HOME/.local/bin:$PATH"
$ d2 --version
v0.9.0
```

d2 0.9 は dagre、ELK、TALA の 3 つのレイアウトエンジンを同梱している。

```console
$ d2 layout
Available layout engines found:

dagre (bundled) - The directed graph layout library Dagre
elk (bundled) - Eclipse Layout Kernel (ELK) with the Layered algorithm.
tala (bundled) - TALA is D2's native layout and edge-routing engine.
```

ソースは mermaid より素直に書ける。

```text
direction: right

classes: {
  library: { style: { fill: "#e8f0fe"; stroke: "#1a73e8"; font-color: "#1a3a6b" } }
  application: { style: { fill: "#fff4e5"; stroke: "#e8710a"; font-color: "#7a3b00" } }
  generated: { style: { fill: "#f1f3f4"; stroke: "#9aa0a6"; font-color: "#3c4043"; stroke-dash: 4 } }
}

pkg_el: "pkg/el" { class: library }
examples_blog_site: "examples/blog/site" { class: application }

pkg_picoel -> pkg_el
examples_blog_site -> examples_blog_posts: "test" { style.stroke-dash: 3 }
```

描くのは 1 行で済む。

```console
$ d2 --layout=dagre --pad=40 build/graph.d2 build/d2-dagre.svg
$ d2 --layout=elk   --pad=40 build/graph.d2 build/d2-elk.svg
$ d2 --layout=tala  --pad=40 build/graph.d2 build/d2-tala.svg
```

### この環境でのつまずき

手元の環境（WSL の Ubuntu 26.04）では、Chrome の準備でいくつか引っかかった。
普通のデスクトップなら `npx puppeteer browsers install chrome` だけで終わるはずなので、読み飛ばしてよい。

- npm 11 は postinstall を勝手に実行しない。puppeteer の Chrome ダウンロードは `npx puppeteer browsers install chrome` で明示的に走らせる。
- そのダウンロードが `unzip` を呼ぶらしく、`unzip` が無いと失敗する。Chrome for Testing の zip を取ってきて Python の `zipfile` で展開した。
- 展開した Chrome は `libnspr4`、`libnss3`、`libasound2t64` を要求した。`apt-get download` で deb を取り、`dpkg-deb -x` でローカルに展開して `LD_LIBRARY_PATH` を通した。
- zip の展開で実行ビットが落ちるので、`chrome_crashpad_handler` に `chmod +x` が要る。

## できた図を確かめる

SVG はテキストなので、開けば何かは分かる。
だが、レイアウトが良いかどうかはやはり目で見ないと分からない。
そこで、描いた SVG を Chrome のページに読み込ませ、SVG 要素だけを PNG に撮って確認した。

```js
const page = await browser.newPage();
await page.setContent(`<body style="margin:0;background:#fff">${svg}</body>`);
const el = await page.$("svg");
await el.screenshot({ path: "build/d2-elk.png" });
```

このひと手間があると、エッジがノードを突き抜けているとか、ラベルが重なっているといったことがすぐ分かる。
実際、最初のサブグラフ付きの図はこの方法で見て、没にした。

ついでに、各 SVG を読み直してノードとエッジの数を数えるスクリプトも置いた（`scripts/measure.mjs`）。
mermaid は `class="node default ..."` と `data-et="edge"`、d2 は `<g class="shape">` と `<path class="connection">`、beautiful-mermaid は `<g class="node">` と `<polyline class="edge">` を数える。
どれか 1 つでもノードやエッジを落としていたら失敗するので、レンダラーの取りこぼしに気づける。

## 結果

6 通りの大きさはこうなった。

| レンダラー | レイアウト | キャンバス | ノード | エッジ | SVG |
| --- | --- | ---: | ---: | ---: | ---: |
| beautiful-mermaid | ELK | 1005x632 | 17 | 21 | 19.8 KiB |
| d2 | dagre | 1324x1261 | 17 | 21 | 21.9 KiB |
| d2 | ELK | 1736x1044 | 17 | 21 | 22.3 KiB |
| d2 | TALA | 917x1323 | 17 | 21 | 20.8 KiB |
| mermaid | dagre | 1085x1105 | 17 | 21 | 47.9 KiB |
| mermaid | ELK | 1361x827 | 17 | 21 | 46.9 KiB |

見比べて分かったこと。

- mermaid の dagre はほぼ正方形になる。`graph LR` でも、17 個のノードが少ない列に縦に積まれるためだ。`examples/blog/site` から出る 9 本のエッジも、それぞれ曲線で散らばる。
- 同じ mermaid でも ELK にすると横長（1361x827）になり、`site` から出るエッジを直交する幹線にまとめてから分岐させる。個人的にはこれが一番読みやすかった。
- d2 の dagre と ELK も同じ傾向で、この 2 つが最も面積が大きい。ELK は `site` が非常に縦長の箱になる。9 本のエッジが同じ列から出るためだ。
- TALA は別物だった。`direction: right` を指定しても縦寄り（917x1323）になるが、直交ルーティングで交差が少なく、依存は追いやすい。
- beautiful-mermaid は 1005x632 と最も小さい。ELK の結果をそのまま使い、色も形も保つ。フローチャートしか描けないのが制約だが、今回の用途には十分だった。
- mermaid の SVG は他より約 2 倍大きい。CSS、フォント、マーカーを各ファイルに書き込むためだ。

ノードが 17 個なら、どれも読めないことはない。
違いが出るのはエッジの引き回しと、`site` の fan-out がキャンバスのどれだけを占めるかだった。
次に数を増やすときは、ELK か TALA を選ぶと思う。

## おわりに

作業は `moonbit/experiments/pkg-graph` にまとめた。
`make graph` で `graph.json` を作り直し、`make all` で 6 つの SVG を `build/` に出す。
`d2` と Chrome（puppeteer 経由）が要る以外は、`npm install` だけで動く。

図そのものは [issue #85 のコメント](https://github.com/podhmo/html-sandbox/issues/85#issuecomment-6430335323)に添付してある。

``` svg
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" data-d2-version="v0.9.0" preserveAspectRatio="xMinYMin meet" viewBox="0 0 1736 1044"><svg class="d2-42652198 d2-svg" width="1736" height="1044" viewBox="-29 -29 1736 1044"><rect x="-29" y="-29" width="1736" height="1044" rx="0" fill="#FFFFFF" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
.d2-42652198 .text-bold {
	font-family: "d2-42652198-font-bold";
}
@font-face {
	font-family: d2-42652198-font-bold;
	src: url("data:application/font-woff;base64,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");
}
.d2-42652198 .text-italic {
	font-family: "d2-42652198-font-italic";
}
@font-face {
	font-family: d2-42652198-font-italic;
	src: url("data:application/font-woff;base64,d09GRgABAAAAAAcYAAoAAAAAC9gAARhRAAAAAAAAAAAAAAAAAAAAAAAAAABPUy8yAAAA9AAAAGAAAABgW1SVeGNtYXAAAAFUAAAAPAAAADwAmACeZ2x5ZgAAAZAAAAGiAAABpDJD1RpoZWFkAAADNAAAADYAAAA2G7Ur2mhoZWEAAANsAAAAJAAAACQLeAioaG10eAAAA5AAAAAQAAAAEActAIFsb2NhAAADoAAAAAoAAAAKAToA0m1heHAAAAOsAAAAIAAAACAAHAD2bmFtZQAAA8wAAAMrAAAIMgntVzNwb3N0AAAG+AAAACAAAAAg/8YAMgADAeEBkAAFAAACigJY//EASwKKAlgARAFeADIBIwAAAgsFAwMEAwkCBCAAAHcAAAADAAAAAAAAAABBREJPAAEAIP//Au7/BgAAA9gBESAAAZMAAAAAAeYClAAAACAAAwAAAAEAAwABAAAADAAEADAAAAAGAAQAAQACAGUAdP//AAAAZQBz////nP+PAAEAAAAAAAAAAQACAAMAAHicNM+/btNAHMDx390lPpW4DbVjmxrXbuL4nATHJDnbh6XiNCqogjKUSvwRUARDB1CF2FFV6FDxAF1gQmJCPAETCwNPwBPAQpiqLEhgI1n0CT7fL1ShDYCf4WMgMAd1UEAD4GqTEC6EaxDu+y6lwldV2j5EXw/fVtbv/ei8+x04lY1XHzZ/PfqIj//uoZc7Bwf5/de7u3em07yHvk0BADB4xQx9RidgggdgtFgcZZiPdF1rSLQp6TofJcKQJMKTJI4Yc1vS99tP+psPBmJiy9X8y9zKem85Nezlm28KTJSuGz+Unz6++nw7CLdGFl8Yb3lLi1xzkFc7N28NnVuAij/FDO2jE/BL0RelEkfMZyyOkoSPdIOWlNbQjTJFej/cWRoYa6x3uXspTINrQXjdClXeZMNkJYsG23LUYU4ndE3fMbPuhYnXtjsNs+/YTGmtBv0rHgCC1WKG7uI9sP6fJkJ1x5hTTl0iaY3T109rUQWlG7Ub7cn5F/J+SqzWgllbPHtRHvfr5jxS0urRUZb/VBTbPlMVtA7/AAAA//8DAE1aVyYAAAABAAAAARhRFnCM9V8PPPUAAQPoAAAAANhdoMwAAAAA3WYvN/69/t0IHQPJAAIAAwACAAAAAAAAAAEAAAPY/u8AAAhA/r39vAgdA+gAwv/RAAAAAAAAAAAAAAAEAnQAJAHhACUBkv/8AUUAPAAAAC4AaACkANIAAAABAAAABACMAAwAZgAHAAEAAAAAAAAAAAAAAAAABAADeJyclN1uGlcUhT9ioE3/Liorcm6sc5lKzuBGcZTEV+M6VkZFkDKkP1JVaYAxIGBmxAw4zhP0um/Rt8hVH6NPUfW62psNYSKrVlAUaw1n/6yz9toH2Odf9qhU7wJ/1ZeGKxzWfzZ8hy/qTcN7nNU/M1zlqPa34RqD2lvDdR7UOoY/4V31D8Of8rj6m+G7HFQvDH/Oo+q+4S/3HP8Y/orHvFvhCjzld8MVDsgM32GfXw3vcQ+rWalyj2PDNb7m0HCdQ6DLmIIpYxKGOC4ZM2TBnJickJg5Yy6JGeAI8JlS6K8JkSLH8MZfI0IK5kRacUSBY0rIlIickVV8q1kpr7Sj9Jkrkm4+BSMiepoxISLBkTIkJSFmonUKCjKe06BBTl/5ZhTkeOSMmeKRMmdIgzYXNOkyYkyO40IrCbOQlEsKroi0v7MIUaZPTEJurBYkDJSnU36xZgc0cbTJNHa7crNU4QjHj5ot3CTG8S2e/ndbzMp912wilqqnaNhjqjyvdIIjVVz6+vyguOA5bid9ykxu12ig7GTWY3osdP4yP8kTJgnOHeATqoNCdx/HmX4HhKrITwR0eUmb13T126dDB58WXQJeaG6bDo7vaNPiXDMCxauzC3VMi19wfE+gMVI7Nn1Ec/l6Q2buFu7iDLnHjEy3QGYs9xfnxztNWHYoLbkjV1f0dY8kUvZAVJE9ixiaKzJ1xUy1XHsjN/0G5gg5LXS2789lG5a2e+stvibVHXYsjJNMbsXotql6H3jmSv95RAxI6WlEn5QZDQqu9W6viFgwxXGuPn6pW1Lgb3Kkz7W6JGamDAISrTMn07+R+SY07v2S7529JbJ5M93RyeZWu3SRysnWjF6reuuz0FSOtybQsKmmliMTlsqrm4r3Jdor8Q/V/bm+bikPCbSuTLJ/4ytwzDNOOGWkXaR6wnJzJq+ERJyqAhNijZI3841q9QiPEzyecMIJz3jygZZrNs74uBKf7f4+55zR5vTW26xi25zxolTt/zv/qWyP9T6Oh5uvpztP88FHuPYbjkrvZkdfA9mgpVV7vx0tImbCxR1sa+Hu4/0HAAD//wMAcqFRQAAAAwAA//UAAP/OADIAAAAAAAAAAAAAAAAAAAAAAAAAAA==");
}]]></style><style type="text/css"><![CDATA[.shape {
  shape-rendering: geometricPrecision;
  stroke-linejoin: round;
}
.connection {
  stroke-linecap: round;
  stroke-linejoin: round;
}
.blend {
  mix-blend-mode: multiply;
  opacity: 0.5;
}

		.d2-42652198 .fill-N2{fill:#676C7E;}
		.d2-42652198 .fill-N7{fill:#FFFFFF;}
		.d2-42652198 .fill-B1{fill:#0D32B2;}
		.d2-42652198 .fill-B2{fill:#0D32B2;}
		.d2-42652198 .stroke-B1{stroke:#0D32B2;}
		.d2-42652198 .stroke-B2{stroke:#0D32B2;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.light-code{display: block}.dark-code{display: none}]]></style><g class="ZXhhbXBsZXNfYmxvZ19hc3NldHM= generated"><g class="shape" ><rect x="842" y="162" width="199" height="66" stroke="#9aa0a6" fill="#f1f3f4" style="stroke-width:2;stroke-dasharray:8.000000,7.892511;" /></g><text x="941.5" y="200.5" fill="#3c4043" class="text-bold" style="text-anchor:middle;font-size:16px">examples/blog/assets</text></g><g class="ZXhhbXBsZXNfYmxvZ19jb21wYXJl application"><g class="shape" ><rect x="345" y="12" width="217" height="66" stroke="#e8710a" fill="#fff4e5" style="stroke-width:2;" /></g><text x="453.5" y="50.5" fill="#7a3b00" class="text-bold" style="text-anchor:middle;font-size:16px">examples/blog/compare</text></g><g class="ZXhhbXBsZXNfYmxvZ19jb21wYXJlX2NtZA== application"><g class="shape" ><rect x="12" y="12" width="253" height="66" stroke="#e8710a" fill="#fff4e5" style="stroke-width:2;" /></g><text x="138.5" y="50.5" fill="#7a3b00" class="text-bold" style="text-anchor:middle;font-size:16px">examples/blog/compare/cmd</text></g><g class="ZXhhbXBsZXNfYmxvZ19wb3N0cw== generated"><g class="shape" ><rect x="1171" y="711" width="194" height="66" stroke="#9aa0a6" fill="#f1f3f4" style="stroke-width:2;stroke-dasharray:8.000000,7.892511;" /></g><text x="1268" y="749.5" fill="#3c4043" class="text-bold" style="text-anchor:middle;font-size:16px">examples/blog/posts</text></g><g class="ZXhhbXBsZXNfYmxvZ19wcmV2aWV3 application"><g class="shape" ><rect x="52" y="231" width="213" height="80" stroke="#e8710a" fill="#fff4e5" style="stroke-width:2;" /></g><text x="158.5" y="276.5" fill="#7a3b00" class="text-bold" style="text-anchor:middle;font-size:16px">examples/blog/preview</text></g><g class="ZXhhbXBsZXNfYmxvZ19yZXBvZG9jcw== generated"><g class="shape" ><rect x="1445" y="424" width="221" height="80" stroke="#9aa0a6" fill="#f1f3f4" style="stroke-width:2;stroke-dasharray:8.000000,7.892511;" /></g><text x="1555.5" y="469.5" fill="#3c4043" class="text-bold" style="text-anchor:middle;font-size:16px">examples/blog/repodocs</text></g><g class="ZXhhbXBsZXNfYmxvZ19zaXRl application"><g class="shape" ><rect x="374" y="295" width="181" height="360" stroke="#e8710a" fill="#fff4e5" style="stroke-width:2;" /></g><text x="464.5" y="480.5" fill="#7a3b00" class="text-bold" style="text-anchor:middle;font-size:16px">examples/blog/site</text></g><g class="ZXhhbXBsZXNfYmxvZ19zbG9wcw== generated"><g class="shape" ><rect x="1171" y="450" width="192" height="66" stroke="#9aa0a6" fill="#f1f3f4" style="stroke-width:2;stroke-dasharray:8.000000,7.892511;" /></g><text x="1267" y="488.5" fill="#3c4043" class="text-bold" style="text-anchor:middle;font-size:16px">examples/blog/slops</text></g><g class="ZXhhbXBsZXNfYmxvZ193b3JrZXI= application"><g class="shape" ><rect x="58" y="740" width="207" height="120" stroke="#e8710a" fill="#fff4e5" style="stroke-width:2;" /></g><text x="161.5" y="805.5" fill="#7a3b00" class="text-bold" style="text-anchor:middle;font-size:16px">examples/blog/worker</text></g><g class="cGtnX2Vs library"><g class="shape" ><rect x="1171" y="159" width="90" height="120" stroke="#1a73e8" fill="#e8f0fe" style="stroke-width:2;" /></g><text x="1216" y="224.5" fill="#1a3a6b" class="text-bold" style="text-anchor:middle;font-size:16px">pkg/el</text></g><g class="cGtnX2h0dHA= library"><g class="shape" ><rect x="842" y="787" width="107" height="160" stroke="#1a73e8" fill="#e8f0fe" style="stroke-width:2;" /></g><text x="895.5" y="872.5" fill="#1a3a6b" class="text-bold" style="text-anchor:middle;font-size:16px">pkg/http</text></g><g class="cGtnX2h0dHBfd2FzbQ== library"><g class="shape" ><rect x="366" y="840" width="153" height="80" stroke="#1a73e8" fill="#e8f0fe" style="stroke-width:2;" /></g><text x="442.5" y="885.5" fill="#1a3a6b" class="text-bold" style="text-anchor:middle;font-size:16px">pkg/http/wasm</text></g><g class="cGtnX2h0dHBfd2FzbV9pbnRlZ3JhdGlvbg== library"><g class="shape" ><rect x="26" y="894" width="239" height="80" stroke="#1a73e8" fill="#e8f0fe" style="stroke-width:2;" /></g><text x="145.5" y="939.5" fill="#1a3a6b" class="text-bold" style="text-anchor:middle;font-size:16px">pkg/http/wasm/integration</text></g><g class="cGtnX3BpY29lbA== library"><g class="shape" ><rect x="881" y="309" width="120" height="66" stroke="#1a73e8" fill="#e8f0fe" style="stroke-width:2;" /></g><text x="941" y="347.5" fill="#1a3a6b" class="text-bold" style="text-anchor:middle;font-size:16px">pkg/picoel</text></g><g class="cGtnX3Rpbnlmcm9udG1hdHRlcg== library"><g class="shape" ><rect x="842" y="514" width="190" height="66" stroke="#1a73e8" fill="#e8f0fe" style="stroke-width:2;" /></g><text x="937" y="552.5" fill="#1a3a6b" class="text-bold" style="text-anchor:middle;font-size:16px">pkg/tinyfrontmatter</text></g><g class="cGtnX3RpbnltYXJrZG93bg== library"><g class="shape" ><rect x="848" y="633" width="181" height="80" stroke="#1a73e8" fill="#e8f0fe" style="stroke-width:2;" /></g><text x="938.5" y="678.5" fill="#1a3a6b" class="text-bold" style="text-anchor:middle;font-size:16px">pkg/tinymarkdown</text></g><g class="cGtnX3RpbnltYXJrZG93bl9qcw== library"><g class="shape" ><rect x="364" y="675" width="198" height="66" stroke="#1a73e8" fill="#e8f0fe" style="stroke-width:2;" /></g><text x="463" y="713.5" fill="#1a3a6b" class="text-bold" style="text-anchor:middle;font-size:16px">pkg/tinymarkdown/js</text></g><g class="KGV4YW1wbGVzX2Jsb2dfY29tcGFyZV9jbWQgLSZndDsgZXhhbXBsZXNfYmxvZ19jb21wYXJlKVswXQ=="><marker id="mk-d2-42652198-3488378134" markerWidth="10" markerHeight="12" refX="7" refY="6" viewBox="0 0 10 12" orient="auto" markerUnits="userSpaceOnUse"> <polygon points="0,0 10,6 0,12" fill="#0D32B2" class="connection fill-B1" stroke-width="2" /> </marker><path d="M 267 45 L 341 45" stroke="#0D32B2" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-d2-42652198-3488378134)" mask="url(#d2-42652198)" /></g><g class="KGV4YW1wbGVzX2Jsb2dfcHJldmlldyAtJmd0OyBleGFtcGxlc19ibG9nX3NpdGUpWzBd"><path d="M 267 284.833008 L 295 284.833008 S 305 284.833008 305 294.833008 L 305 405.5 S 305 415.5 315 415.5 L 370 415.5" stroke="#0D32B2" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-d2-42652198-3488378134)" mask="url(#d2-42652198)" /></g><g class="KGV4YW1wbGVzX2Jsb2dfcHJldmlldyAtJmd0OyBwa2dfZWwpWzBd"><path d="M 267 258.165985 L 295 258.165985 S 305 258.165985 305 248.165985 L 305 131.333 S 305 121.333 315 121.333 L 1071 121.333 S 1081 121.333 1081 131.333 L 1081 179.832993 S 1081 189.832993 1091 189.832993 L 1167 189.832993" stroke="#0D32B2" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-d2-42652198-3488378134)" mask="url(#d2-42652198)" /></g><g class="KGV4YW1wbGVzX2Jsb2dfc2l0ZSAtJmd0OyBleGFtcGxlc19ibG9nX2Fzc2V0cylbMF0="><path d="M 557 331.5 L 592 331.5 S 602 331.5 602 321.5 L 602 205.332993 S 602 195.332993 612 195.332993 L 838 195.332993" stroke="#0D32B2" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-d2-42652198-3488378134)" mask="url(#d2-42652198)" /></g><g class="KGV4YW1wbGVzX2Jsb2dfc2l0ZSAtJmd0OyBleGFtcGxlc19ibG9nX3Bvc3RzKVswXQ=="><marker id="mk-d2-42652198-2177206569" markerWidth="10" markerHeight="12" refX="7" refY="6" viewBox="0 0 10 12" orient="auto" markerUnits="userSpaceOnUse"> <polygon points="0,0 10,6 0,12" fill="#0D32B2" class="connection fill-B2" stroke-width="2" /> </marker><path d="M 557 583.5 L 692 583.5 S 702 583.5 702 593.5 L 702 734.166016 S 702 744.166016 712 744.166016 L 1167 744.166016" stroke="#0D32B2" fill="none" class="connection stroke-B2" style="stroke-width:2;stroke-dasharray:6.000000,5.919384;" marker-end="url(#mk-d2-42652198-2177206569)" mask="url(#d2-42652198)" /><text x="783" y="750" fill="#676C7E" class="text-italic fill-N2" style="text-anchor:middle;font-size:16px">test</text></g><g class="KGV4YW1wbGVzX2Jsb2dfc2l0ZSAtJmd0OyBleGFtcGxlc19ibG9nX3JlcG9kb2NzKVswXQ=="><path d="M 557 439.5 L 742 439.5 S 752 439.5 752 429.5 L 752 419.333008 S 752 409.333008 762 409.333008 L 1395 409.333008 S 1405 409.333008 1405 419.333008 L 1405 440.665985 S 1405 450.665985 1415 450.665985 L 1441 450.665985" stroke="#0D32B2" fill="none" class="connection stroke-B2" style="stroke-width:2;stroke-dasharray:6.000000,5.919384;" marker-end="url(#mk-d2-42652198-2177206569)" mask="url(#d2-42652198)" /><text x="1006" y="415" fill="#676C7E" class="text-italic fill-N2" style="text-anchor:middle;font-size:16px">test</text></g><g class="KGV4YW1wbGVzX2Jsb2dfc2l0ZSAtJmd0OyBleGFtcGxlc19ibG9nX3Nsb3BzKVswXQ=="><path d="M 557 483.333008 L 1167 483.333008" stroke="#0D32B2" fill="none" class="connection stroke-B2" style="stroke-width:2;stroke-dasharray:6.000000,5.919384;" marker-end="url(#mk-d2-42652198-2177206569)" mask="url(#d2-42652198)" /><text x="863" y="489" fill="#676C7E" class="text-italic fill-N2" style="text-anchor:middle;font-size:16px">test</text></g><g class="KGV4YW1wbGVzX2Jsb2dfc2l0ZSAtJmd0OyBwa2dfZWwpWzBd"><path d="M 557 367.5 L 642 367.5 S 652 367.5 652 357.5 L 652 278.333008 S 652 268.333008 662 268.333008 L 1071 268.333008 S 1081 268.333008 1081 258.333008 L 1081 229.832993 S 1081 219.832993 1091 219.832993 L 1167 219.832993" stroke="#0D32B2" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-d2-42652198-3488378134)" mask="url(#d2-42652198)" /></g><g class="KGV4YW1wbGVzX2Jsb2dfc2l0ZSAtJmd0OyBwa2dfaHR0cClbMF0="><path d="M 557 619.5 L 642 619.5 S 652 619.5 652 629.5 L 652 809.333008 S 652 819.333008 662 819.333008 L 838 819.333008" stroke="#0D32B2" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-d2-42652198-3488378134)" mask="url(#d2-42652198)" /></g><g class="KGV4YW1wbGVzX2Jsb2dfc2l0ZSAtJmd0OyBwa2dfcGljb2VsKVswXQ=="><path d="M 557 403.5 L 692 403.5 S 702 403.5 702 393.5 L 702 352.333008 S 702 342.333008 712 342.333008 L 878 342.333008" stroke="#0D32B2" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-d2-42652198-3488378134)" mask="url(#d2-42652198)" /></g><g class="KGV4YW1wbGVzX2Jsb2dfc2l0ZSAtJmd0OyBwa2dfdGlueWZyb250bWF0dGVyKVswXQ=="><path d="M 557 511.5 L 792 511.5 S 802 511.5 802 521.5 L 802 537.333008 S 802 547.333008 812 547.333008 L 838 547.333008" stroke="#0D32B2" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-d2-42652198-3488378134)" mask="url(#d2-42652198)" /></g><g class="KGV4YW1wbGVzX2Jsb2dfc2l0ZSAtJmd0OyBwa2dfdGlueW1hcmtkb3duKVswXQ=="><path d="M 557 547.5 L 742 547.5 S 752 547.5 752 557.5 L 752 649.833008 S 752 659.833008 762 659.833008 L 844 659.833008" stroke="#0D32B2" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-d2-42652198-3488378134)" mask="url(#d2-42652198)" /></g><g class="KGV4YW1wbGVzX2Jsb2dfd29ya2VyIC0mZ3Q7IGV4YW1wbGVzX2Jsb2dfc2l0ZSlbMF0="><path d="M 267 770.333008 L 295 770.333008 S 305 770.333008 305 760.333008 L 305 545.5 S 305 535.5 315 535.5 L 370 535.5" stroke="#0D32B2" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-d2-42652198-3488378134)" mask="url(#d2-42652198)" /></g><g class="KGV4YW1wbGVzX2Jsb2dfd29ya2VyIC0mZ3Q7IHBrZ19odHRwKVswXQ=="><path d="M 267 799.333008 L 592 799.333008 S 602 799.333008 602 809.333008 L 602 841.333008 S 602 851.333008 612 851.333008 L 838 851.333008" stroke="#0D32B2" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-d2-42652198-3488378134)" mask="url(#d2-42652198)" /></g><g class="KGV4YW1wbGVzX2Jsb2dfd29ya2VyIC0mZ3Q7IHBrZ19odHRwX3dhc20pWzBd"><path d="M 267 830.333008 L 295 830.333008 S 305 830.333008 305 840.333008 L 305 857 S 305 867 315 867 L 362 867" stroke="#0D32B2" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-d2-42652198-3488378134)" mask="url(#d2-42652198)" /></g><g class="KHBrZ19odHRwX3dhc20gLSZndDsgcGtnX2h0dHApWzBd"><path d="M 521 883.333008 L 838 883.333008" stroke="#0D32B2" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-d2-42652198-3488378134)" mask="url(#d2-42652198)" /></g><g class="KHBrZ19odHRwX3dhc21faW50ZWdyYXRpb24gLSZndDsgcGtnX2h0dHApWzBd"><path d="M 267 963 L 592 963 S 602 963 602 953 L 602 925.333008 S 602 915.333008 612 915.333008 L 838 915.333008" stroke="#0D32B2" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-d2-42652198-3488378134)" mask="url(#d2-42652198)" /></g><g class="KHBrZ19odHRwX3dhc21faW50ZWdyYXRpb24gLSZndDsgcGtnX2h0dHBfd2FzbSlbMF0="><path d="M 267 920.833008 L 295 920.833008 S 305 920.833008 305 910.833008 L 305 903.666016 S 305 893.666016 315 893.666016 L 362 893.666016" stroke="#0D32B2" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-d2-42652198-3488378134)" mask="url(#d2-42652198)" /></g><g class="KHBrZ19waWNvZWwgLSZndDsgcGtnX2VsKVswXQ=="><path d="M 1003 342.333008 L 1121 342.333008 S 1131 342.333008 1131 332.333008 L 1131 259.832993 S 1131 249.832993 1141 249.832993 L 1167 249.832993" stroke="#0D32B2" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-d2-42652198-3488378134)" mask="url(#d2-42652198)" /></g><g class="KHBrZ190aW55bWFya2Rvd24gLSZndDsgZXhhbXBsZXNfYmxvZ19yZXBvZG9jcylbMF0="><path d="M 1031 673.166016 L 1395 673.166016 S 1405 673.166016 1405 663.166016 L 1405 487.333008 S 1405 477.333008 1415 477.333008 L 1441 477.333008" stroke="#0D32B2" fill="none" class="connection stroke-B2" style="stroke-width:2;stroke-dasharray:6.000000,5.919384;" marker-end="url(#mk-d2-42652198-2177206569)" mask="url(#d2-42652198)" /><text x="1335" y="679" fill="#676C7E" class="text-italic fill-N2" style="text-anchor:middle;font-size:16px">test</text></g><g class="KHBrZ190aW55bWFya2Rvd25fanMgLSZndDsgcGtnX3RpbnltYXJrZG93bilbMF0="><path d="M 564 708.5 L 742 708.5 S 752 708.5 752 698.5 L 752 696.5 S 752 686.5 762 686.5 L 844 686.5" stroke="#0D32B2" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-d2-42652198-3488378134)" mask="url(#d2-42652198)" /></g><mask id="d2-42652198" maskUnits="userSpaceOnUse" x="-29" y="-29" width="1736" height="1044">
<rect x="-29" y="-29" width="1736" height="1044" fill="white"></rect>
<rect x="768" y="734" width="30" height="21" fill="black"></rect>
<rect x="991" y="399" width="30" height="21" fill="black"></rect>
<rect x="848" y="473" width="30" height="21" fill="black"></rect>
<rect x="1320" y="663" width="30" height="21" fill="black"></rect>
</mask></svg></svg>
```


MoonBit の依存関係を見るだけなら `moon tree --package` で足りる。
そこから一歩進んで、パッケージの大きさも一緒に見たいなら `moon ide outline` を足す。
この 2 つを JSON にしておけば、あとは好きなレンダラーに流し込むだけだ。

---

特別なフォントを埋めこむとmarkdown側のコードブロックの記述が汚れる。
