limu 是一个用 Rust 和 Go 编写的图表布局引擎。它读取 Mermaid,把绘制交给你的程序。
工作方式
Mermaid 和 Pele(limu 移植自这个 Mermaid 渲染器)布局一张图表后,把它写成 SVG,交给浏览器绘制。
limu 早一步停下,停在场景(scene)。场景是以数据表示的、已经布局好的图表。它记录每个部分是什么、在哪里,但不记录它长什么样。之后由后端来绘制。limu 提供的后端有在 GPU 上绘制的 GPUI 和 MyGo,绘制到位图的 tiny-skia 和 Core Graphics,绘制到终端字符格的后端,以及 SVG。你也可以自己写一个。
场景里没有颜色,所以只需布局一次,就能用任意多种方式绘制。切换主题只需重绘,后端也可以按自己的方式绘制每个部分。
场景 只有方框、路径和标签,没有样式。
Kohu 用 limu 的浅色主题绘制。

KohuDark 只换了颜色。

Liquid Glass 每个部分按自己的方式绘制,用的是 MyGo 的玻璃效果。

后端还可以更进一步,为自己的外观重新布局图表。mygo-platinum 就这样为 Platinum 桌面绘制图表。
Platinum 用点阵字体重新布局,逐像素绘制。

应用还可以向场景查询指针下方是哪个部分。
在应用中使用 limu
1cargo add limu limu-gpuilimu-gpui 在 GPUI 窗口中绘制场景,和窗口的其余部分一起在 GPU 上绘制,并用 GPUI 的文本系统测量文本。场景能告诉你指针下方是哪个部分。
1// 用窗口的文本系统测量文本。2let measurer = TextMeasurer::new(window, Fonts::default());3let layout = limu::layout::Options {4 measurer: &measurer,5 ..Default::default()6};7let scene = limu::layout(src, &layout)?;89// 在 canvas 的绘制闭包中绘制场景,并找出某一点上的部分。10let o = Options {11 look: Look::new(Theme::KOHU_DARK),12 ..Options::default()13};14paint(&scene, &o, bounds.origin, 1.0, window, cx);15if let Some(i) = scene.item_at(at, 4.0) {16 let it = &scene.items[i];17 println!("clicked {} {:?}", it.role.as_str(), it.id);18}1cargo add limu limu-tiny-skialimu-tiny-skia 把场景绘制到位图中,使用程序自带的字体文件,不需要 GPU,也不依赖系统库。布局时要用绘制时的同一套字体。
1let fonts = Fonts::new(std::fs::read("Inter-Regular.ttf")?)?;2let layout = limu::layout::Options {3 measurer: &fonts,4 ..Default::default()5};6let scene = limu::layout(src, &layout)?;7let o = Options {8 look: Look::new(Theme::KOHU),9 fonts: Some(&fonts),10 scale: 2.0,11 ..Options::default()12};13let pixmap = limu_tiny_skia::render(&scene, &o).ok_or("too large to draw")?;14pixmap.save_png("diagram.png")?;1cargo add limu limu-asciilimu-ascii 按终端的字符格布局图表,用框线字符绘制,也可以只用 ASCII。
1let cells = Cells::default();2let layout = limu::layout::Options {3 measurer: &cells,4 font_size: cells.font_size(),5 snap: Some(cells.grid()),6 max_width: 80.0 * cells.width,7 direction_breakpoint: f64::INFINITY,8 ..Default::default()9};10let scene = limu::layout(src, &layout)?;11print!("{}", limu_ascii::render(&scene, &Options::default())?);1cargo add limulimu::scene::svg 把场景写成 SVG,颜色保留为 CSS 变量,页面可以重新设置样式。limu 只用到 Rust 标准库。
1let scene = limu::layout(src, &Default::default())?;2let out = svg::render(&scene, &svg::Options {3 look: Look::new(Theme::KOHU),4 ..Default::default()5});1go get github.com/firede/limu/limumygolimumygo 用 MyGo 的原生 UI 在 GPU 上绘制场景,并告诉你指针下方是哪个部分。布局时要用绘制时的同一套字体。
1fonts := limumygo.DefaultFonts2sc, err := limu.Layout(src, &layout.Options{Measurer: fonts})3if err != nil {4 return err5}67// 在视图中绘制图表,并查看点击了哪个部分。8w := limumygo.View(c, sc, &limumygo.Options{9 Look: style.Look{Theme: style.KohuDark()},10 Fonts: fonts,11})12if it := w.Clicked(); it != nil {13 fmt.Println("clicked", it.Role, it.ID)14}1go get github.com/firede/limusvg 包把场景写成 SVG,颜色保留为 CSS 变量,页面可以重新设置样式。limu 和 svg 包只用到 Go 标准库。
1sc, err := limu.Layout(src, nil)2if err != nil {3 return err4}5out := svg.Render(sc, &svg.Options{Look: style.Look{Theme: style.Kohu()}})继续阅读
示例
limu 支持的每种图表,用它的各个主题绘制。
Playground
边写图表,边看它的布局。
快速上手
布局第一张图表,渲染成 SVG。
主题
用主题和覆盖改颜色,或自己绘制各个部分。
limu 与 Pele
limu 逐个函数移植自 Pele,后者是 Obsidian 团队开发的小巧、快速的 Mermaid 渲染器。共有两个移植版,Rust 版 limu-rs 和 Go 版 limu。两者的测试都逐个数值检查布局是否与 Pele 一致。两者都以 MIT 许可证开源,见 Rust 版和 Go 版。
Pele 得名于夏威夷的火山女神。Limu 在夏威夷语中指海里的藻类。本站的配色取自 limu kohu,一种生长在潮池里的红藻。