12557 个 Star 的仓库里,一行幻灯片代码都没有
- 主仓库 12557 Star 却不含幻灯片代码,仅承担官网、生态导览和论坛职责,实际功能分布在四个活跃子仓库
- 作者 2019 年埋掉约 8000 Star 的旧 Electron 应用,重写为 Marpit、Core、CLI、VS Code 四层解耦架构并沿用至今
- Marpit 将每页幻灯片包进 inline SVG 与 foreignObject,实现零 JS 矢量缩放与样式隔离,且语法严格兼容 CommonMark
- 主题系统简化为纯 CSS 加 @theme 声明,marp-cli 导出 PPTX 提供截图与 LibreOffice 转换两条路径,分别牺牲可编辑性与还原度
- 生态依赖 yhatt 一人维护,bus factor 为 1,当年规划的 Marp Web 主界面未兑现,VS Code 扩展成为实际主力
昨天想找个 Markdown 写幻灯片的工具,顺手点开了 Marp。12557 个 Star,MIT 协议,TypeScript,描述写着「Markdown 演示生态的入口仓库」。我心想这体量,源码得有多少东西。
clone 下来一看,愣住了。
116 个文件,没有一行幻灯片代码。仓库主体是一个 Next.js 官网(marp.app)加一份 README,README 的核心内容是一张表,告诉你真正的代码在另外四个仓库里。Star 挂在门口,货在别处,这个仓库本身就是它工程哲学的展品。
八千星的桌面应用,说埋就埋
要看懂这个空仓库,得把时间拨回 2016 年。日本开发者 Yuki Hattori 给自己写了个叫 mdSlide 的小工具,后来改名 Marp,一个基于 Electron 的 Markdown 幻灯片编辑器。到 2019 年,这个项目攒了约 8000 Star,教育场景一堆用户,看着是标准的开源成功故事。
但作者在 2019 年 6 月的官方博文里说了实话,头痛来自缺失的可维护性。用户的请求源源不断,旧 Marp 的架构扛不住演进。他的解法不是重构,是推倒。旧应用停止维护、归档,今天你去翻 yhatt/marp 那个坟场仓库,7850 Star,最后一次提交停在 2019 年 9 月。博文里的原话翻译过来大意是,我绝不建议继续使用旧 Marp,它的维护两年前就停了,有安全方面的顾虑。
把自己的明星产品亲手埋掉,换成一套全新的生态,这个决定当时并不轻松。博文里还记了一笔旧账,2017 年有人提议把 Marp 做成网页应用,离线用户强烈反对,那时候 PWA 还没深入人心。两年后作者还是走了这条路,只不过换了姿势,不再做「一个应用」,改做「一套零件」。
重写后的 Marp Next 分成四层。Marpit 是最底层的瘦身框架,只干一件事,把 Markdown 变成最小化的 HTML 和 CSS。Marp Core 在上面加电池,内置主题、Emoji、KaTeX 数学公式、自动缩放。Marp CLI 是瑞士军刀,负责导出 HTML、PDF、PPTX 和图片。Marp for VS Code 让你在编辑器里直接预览。这套分法到今天都没变过,四个仓库现在全部活跃,最近一次提交都在两个月内。
星数挂在门口,代码住在别处
回到那个空仓库。它其实有明确的职责,官网源码、生态导览、Discussions 论坛,三件事。GitHub 上的 issue 区是空的,因为讨论都汇聚到主仓库的 Discussions 里,四个子仓库各自保持安静。
| 仓库 | 职责 | Star | 最近提交 |
|---|---|---|---|
| marp | 入口 + 官网 + 论坛 | 12557 | 2026-07 |
| marp-cli | 转换器,导出四件套 | 3829 | 2026-09 |
| marp-vscode | VS Code 扩展 | 2092 | 2026-08 |
| marpit | 底层框架 | 1381 | 2026-09 |
| marp-core | 核心转换器 | 1154 | 2026-09 |
这张表有个耐人寻味的细节。星数最高的仓库贡献最小,真正干活的 marpit 只有约十分之一的星。社区把掌声给了门面,作者也乐意让门面当流量入口,反正生态里随便哪个仓库都是 MIT。
四层关系摞起来是这样。
顺着图看,入口仓库不带逻辑,应用层三个宿主各自挑场景,底下的 Marpit 才是契约本体。右角那张虚线卡我们后面再聊,它是一个没兑现的承诺。
一张幻灯片,一个 foreignObject
Marpit 最独特的设计,是把每一页幻灯片包进一个 inline SVG。我翻了 src/markdown/inline_svg.js,实现比想象中朴素,markdown-it 解析出 token 后,按幻灯片边界切开,每一页包进一个 svg 元素,带上 data-marpit-svg 标记和 viewBox,尺寸从主题的 widthPixel 和 heightPixel 读出来,页内内容再包一层 foreignObject。
你想想看这个结构换来了什么。SVG 天生矢量缩放,viewBox 定死就是像素级精确,PowerPoint 和 Keynote 那种所见即所得的尺寸感回来了,而整个幻灯片不需要一行 JavaScript 就能在浏览器里看。foreignObject 还是个隔离罩,Markdown 内容注入的 DOM 关在盒子里面,不会撑破主题 CSS 定义的设计。官方管这叫零 JS 幻灯片,静态 HTML 文件双击打开就是一场演示。
还有一条纪律值得单说。Marpit 加的任何语法都不许破坏 CommonMark,一份 Marp Markdown 拿到普通编辑器里打开,还是一篇正常的文档。这是当年旧 Marp 被用户反复教育出来的,有人要花哨语法,也有人要求严格遵守 Markdown 规范,两头都得伺候。
主题是 CSS,不是配置文件
旧 Marp 的主题系统要懂构建流程、懂 Sass、懂应用内部逻辑才能改。Marpit 重做这套时选了个聪明角度,主题就是一份纯 CSS,在文件开头用一行 @theme 名字 的注释声明身份。
src/theme.js 里是一整条 PostCSS 管线,meta、nesting、root 替换、section 尺寸,各管一段。幻灯片宽高直接从 CSS 的像素值解析,顺手还带了一张绝对单位换算表,cm、mm、in、pt、pc、q 全部换算成 px。会写网页就会做 Marp 主题,这个门槛砍得足够低。
顺带说个集成上的巧宗。Marp for VS Code 能做得很顺,一个公开原因是 VS Code 的 Markdown 预览和 Marpit 用的是同一台 markdown-it 引擎,同一份文档在编辑器原生预览和幻灯片预览之间不会精神分裂。这种「搭别人的船」的判断力,贯穿了整个生态。
导出这条路上站满了别人的轮子
marp-cli 的转换器把「不重造轮子」执行得很彻底,我数了一下它导出 PPTX 的两条路。
默认路径是截图。converter.ts 里的 convertFileToPPTX 先把每页渲染成 PNG(走 puppeteer-core 拉起 Chrome,默认 2 倍缩放),然后用 pptxgenjs 组装,版式按幻灯片像素除以 96 定义成英寸,每页 PNG 转成 base64 贴成满版背景,Marp 注释里写的讲者备注通过 addNotes 塞进每页。所以默认导出的 PPTX 打开是能放、有备注,但一个字都改不了,它本质是一叠图。
想改字,走第二条路,--pptx-editable。这条路先转 PDF,再调用本机的 LibreOffice,用 --infilter=impress_pdf_import 让 Impress 按 PDF 导入再转出 PPTX。代码里印着一行实验性警告,原意是输出依赖 LibreOffice,幻灯片的还原性不完全保证。这条警告说得很诚实,PDF 转出来的可编辑 PPTX,布局能飘到什么程度用过 LibreOffice 的人心里都有数。
前两天我刚拆过 GenOffice,那边走的是原生 OOXML 生成的路线,公式、文本都是真对象。Marp 这两条路一条牺牲可编辑性,一条牺牲还原度,正好是「Markdown 转 PPTX」这个命题的两条经典逃逸路径。
两条路并排看更清楚。
左边是默认的截图路线,右边是实验性的 LibreOffice 路线,工具选型的时候,你对 PPTX 的期待是「能放」还是「能改」,直接决定该用哪条路,这事得先想清楚。
一个人的生态,和没兑现的 Web 梦
说完成绩单,该翻翻另一面了。
先说最要紧的一点,这是一个人的生态。主仓库贡献者 10 人,除了 yhatt 本人就是 dependabot 机器人和零星补丁,marpit 也差不多。八年时间一个人扛着五个仓库往前走,质量确实稳(四个仓库全部活跃、CI 严格、文档齐整),但 bus factor 等于 1 这个事实不会因为稳就消失。你在生产链路里引入 Marp,说到底是在押注 yhatt 的个人持续投入和他的赞助者名单。
再翻一份旧账。2019 年那份路线图没有完全兑现,博文的迁移计划写得明白,将来的主界面会是 Marp Web,桌面应用顶多变成 Web 界面的壳。七年过去,你猜怎么着,Marp Web 至今顶着一个 tech demo 的帽子,被折叠在 README 的「过时与不活跃项目」列表里,和 Marp React、Marp Vue 躺在一块。真正的主界面变成了谁?VS Code 扩展加命令行。作者当年押注浏览器优先,用户最终用脚投票选了编辑器优先。计划图和地形图,永远不是同一张图。
装机成本也别忽略。CLI 导 PDF 和截图走 Chrome,可编辑 PPTX 走 LibreOffice,两个大家伙都得你自己装,marp-cli 只带了 puppeteer-core 这种不含浏览器的核心包。想在一台干净的服务器上跑自动化导出,先掂量一下依赖体积。
说到底什么人该用 Marp?我的判断,写技术分享、课程讲义、内部分档,内容以文字和代码为主,源文件想进 git 想要 diff 的,Marp 是这个场景里最成熟的答案,VS Code 里装个扩展五分钟就能开工。要视觉冲击力的大场面发布会 deck,或者要在 PowerPoint 里跟设计团队协作,另请高明,它的主题再漂亮也是 Markdown 的漂亮。
先有契约,再有生态
拆完我一直在想,一个空仓库凭什么值 12557 个 Star。
答案不在仓库里。
它从来不是在给一个产品攒星,是在给一份契约攒星。Marpit 定义了 Markdown 怎么变成幻灯片,主题 CSS 定义了设计怎么表达,这两份契约稳定了,上层的宿主可以随便换,CLI 是宿主,VS Code 是宿主,理论上你今天想给 Vim 写个预览插件也能当宿主。旧 Marp 死就死在应用和逻辑长在了一块,埋掉应用才救出了逻辑。
这个思路对做工具的人很有迁移价值。你在做一个开发者工具吗?可以先问自己一句,我的核心能不能抽成一份不带界面的契约?契约立住了,界面、插件、集成都是别人可以帮你长出来的部分。一个人维护不过来一个产品,但维护得动一份契约加四个小仓库,Marp 用八年证明了这件事。
项目地址在上面,想体验的话不用 clone 它,装 VS Code 扩展或者一行 npx @marp-team/marp-cli 就够了。毕竟这个仓库里,本来也没有代码可 clone。

评论互动