Community写作与编辑github.com

tjst-t/boxloom

将幻灯片以 Boxloom Markdown (.bx.md) 格式编写,并转换为原生可编辑的 PPTX 文件。当你需要制作演示文稿/PPT/幻灯片,或编辑 .bx.md 文件时使用。涵盖语法、如何为每种内容选择合适的模式、布局引擎限制的密度,以及检查→修复循环。

boxloom 是什么?

Boxloom 是一个专注于将内容与样式分离的幻灯片工具。开发者只需以特定的 .bx.md 格式编写内容(如要点列表、选项对比、日期计划),模板会自动处理所有颜色、字体、边距和位置。该工具支持多种复杂布局,如统计卡片、图表、矩阵、流程图、甘特图、组织结构图等,并内置了严格的语法检查和布局引擎,确保输出符合模板约束。目前主要支持 Go 语言运行环境(Go 1.24+),无需其他依赖。Boxloom 特别强调“先读模式,再写内容”的工作流:开发者需要通过 `boxloom schema` 命令了解当前模板支持的块和子系统,然后在 `check→fix→build` 的循环中反复验证,直到无错误和布局溢出警告为止。

兼容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/tjst-t/boxloom/tree/HEAD/skills/boxloom

Installed? Explore more 写作与编辑 skills: steipete/notion, langchain-ai/langchain, bytedance/podcast-generation · View all 6 →

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

预览

来自技能 README

alt text
alt

文档

Boxloom:编写演示文稿

Boxloom 将含义与外观分离。你只需编写内容本身是什么(要点列表、选项对比、带日期的计划)。模板决定了所有的颜色、字体大小、边距和位置。除了一个逃生通道(shapes,最后手段)外,你永远不需要编写颜色、大小或坐标。

流程总是:

  1. boxloom schema — 读取当前模板接受的内容(先做这一步)。
  2. 编写 deck.bx.md。
  3. boxloom check -format json deck.bx.md — 修复所有错误,然后修复你能修复的所有警告。
  4. 重复第3步,直到 "ok": true 且没有 layout-overflow 警告。
  5. boxloom build -o deck.pptx deck.bx.md(标志位于文件之前)。

命令从仓库的 boxloom/ 目录运行: go run ./cmd/boxloom <schema|check|build|parse> …(Go 1.24+,无其他依赖)。

1. 先读取模式

boxloom schema [-template light|dark] 输出一个 JSON 文档。它是真理之源;如果本文件和模式冲突,以模式为准。

  • markdown.rules — 语法规则(简短列表;需全部遵守)。
  • markdown.frontMatter — --- 头部允许的键(title 是必需的)。
  • templates[].blocks — 此模板识别的围栏块(:::name),包含 inside(允许出现的位置)、contains(内部包含的内容)和 minChildren。
  • templates[].subsystems — 图形类型(```name 代码块),包含 markdown(其额外规则)和 schema(一个指向 irSchema 的 JSON 指针,列出了所有允许的键)。
  • 未列出的任何内容都是错误。不要发明块名、属性或键。
  • 模板通过名称选择(front matter 中的 template: light,或 -template dark)。自定义模板是一个按路径传递的值表文件:-template ./my.json(适用于 schema、check、build、fonts;示例 examples/templates/forest.json)。当演示文稿将使用自定义模板构建时,请使用相同的 -template 运行 schema 和 check — 角色名称和文本样式来自该文件。
  • variant(# Title {variant=…})存在于语法中,但当前模板未声明任何变体(templates[].variants 为空),因此不要使用它。

输出很大。只看你需要的内容:

go run ./cmd/boxloom schema -template light > /tmp/schema.json
python3 -c "import json;d=json.load(open('/tmp/schema.json'));print(json.dumps({'rules':d['markdown']['rules'],'blocks':d['templates'][0]['blocks'],'subsystems':[(x['name'],x['markdown']) for x in d['templates'][0]['subsystems']]},ensure_ascii=False,indent=1))"
python3 -c "import json;d=json.load(open('/tmp/schema.json'));print(json.dumps(d['irSchema']['\$defs']['gantt'],ensure_ascii=False,indent=1))"   # 所有甘特图键

2. 一屏看完的语法

---
title: Moving the reporting service to the new cluster
subtitle: Plan and options (fictional example)
author: Platform team
date: 2026-11-11
confidential: Internal
disclaimer: All names and figures are fictional
template: light
---

# Vendor support of the old cluster

:::lead
The old cluster loses vendor support in March 2028, so the 14 services on it must move before then.
:::

- The vendor ends security fixes on **2028-03-31**
- 14 services still run there; 9 can move without code changes
- Moving takes about 6 weeks per service group

:::source
Vendor support notice of 2026-09; service inventory as of October 2026
:::

:::notes
Speaker notes go here. Plain paragraphs and bullets only.
:::
  • # Title 开始一张幻灯片。保持标题为一行内能显示的简短标题(“旧集群的供应商支持”);换行的标题会被警告(title-wrap)。将幻灯片要表达的内容——结论——用一句 :::lead 写在标题正下方(1–2 行)。模板将 lead 放在标题下方,正文之外。

  • --- 不是幻灯片分隔符(它是错误的)。## 及更深层次的标题是错误的(分组标题应写作 :::column Title,而不是子标题)。

  • 正文:段落、- / 1. 项目符号(最多两级)、**强调**(仅一种强调)、`code`、[text](url)、行尾的 \(表示有意义换行)。没有斜体、删除线、脚注、HTML。

  • 围栏块:以 :::name 开始,以相同数量的冒号结束。嵌套时,外层围栏比内层多一个冒号:

    :::::compare
    ::::option Keep the old cluster
    :::pros
    - No migration work this year
    :::
    :::cons
    - No security fixes after March 2028
    :::
    ::::
    ::::option Move to the new cluster
    :::pros
    - Supported until 2033
    :::
    :::cons
    - Six weeks of work per service group
    :::
    ::::
    :::::
    
  • :::lead(幻灯片的消息)、:::notes(演讲者备注)和 :::source(幻灯片数据的来源)必须位于幻灯片的最顶层,每张幻灯片各一次。仅内容幻灯片使用 :::lead。

  • front matter 中的 date、confidential 和 disclaimer 为整个演示文稿编写一次;模板将其放在封面(confidential 也放在页脚)。不要在每张幻灯片的 :::note 中重复“虚构”/“保密”。

  • 图形是围栏代码块,其语言是子系统名称,主体为受限制的 YAML:无锚点/别名(&、*)、无标签、无多行值、无 |/> 块;布尔值只能使用 true/false;日期为字符串 YYYY-MM 或 YYYY-MM-DD;范围 2027-01 .. 2027-06。对任何以 *、&、! 开头或包含 ": " 的值加引号,例如 text: ["**Slowest step**", 5 days on average] — 一个未加引号的 **…** 在流程项开头会被解读为 YAML 别名并被拒绝。

3. 为每段内容选择合适的模式

在编写之前决定内容的类型。按顺序应用这些规则,并使用第一个匹配的规则。(完整规则集及好/坏示例:docs/patterns.md §4。)

当前可用(请检查 boxloom schema — 可能已添加更多):

内容使用说明
章节分隔# Part 2: How we migrate {type=section}标题文本是章节标题;其后只能跟 :::notes。不是目录 — 当演示文稿有两个或更多章节时,模板会在每张章节幻灯片上自动绘制当前高亮的章节列表
幻灯片只说一句话;证据在别的幻灯片上# Migration must move two years earlier {type=statement}标题文本就是这句话(这是唯一一种标题是完整句子的幻灯片类型);其后只能跟 :::notes 和 :::source。如果你要添加理由,请使用带简短标题和 :::lead 作为结论的普通幻灯片
1–4 个要强有力展示的数字,且无系列可比较::::stat → :::value 3 → 12 {unit=models} + 单行标签5 个及以上数字或时间序列应使用图表/表格,而非 stat。值按原样编写,必须包含数字。值和单位永不在中间断开,因此保持简短 — 4 个卡片较窄(stat-value)
数字系列(3+ 点):排名、随时间变化、整体中的份额、分布、两个量的关系```chartcompare: item / timeSeries / component / frequency / correlation — 系统会自动为你选择图表类型(永远不要写柱状图/折线图/饼图)。categories: [...]、series: [{name, values: [...]}](每个分类一个值,数字不加引号,最多 3 个系列)、可选的 unit、emphasis: [category](一个系列)或一个系列的 emphasis: true、当系列是整体的部分时使用 stacked: true。correlation 使用 xAxis: {title, unit?}、yAxis 和 points: [[x, y], …] 代替 categories。component(份额)有 1 个系列且最多 6 部分 — 将小部分合并为“其他”
别人的话:::quote Source text + 内部文字来源(标题文本)是必需的。永远不要引用你自己的结论
需要在普通幻灯片内强调的一句话:::takeaway + 一句话每张幻灯片最多一个,通常放在最后
纯文本或数字的行×列GFM 表格:| A | B | + | --- | --- | + 行第一行是表头;每行每个列有一个单元格(table-shape)。没有对齐标记(:--、--: 是错误的);数字列会自动右对齐。单元格仅限内联。表格后紧跟一行 : caption 作为其标题。如果最后一行是总计,则在该行末尾加上 {total=last}(: Estimates {total=last},或仅 : {total=last});该行将渲染为总计行。系统不会计算总计 — 请写入数值。将单位放在标题或表头中一次,不要在每个单元格中重复。单元格中的评级 → matrix(见下文)
每个单元格都是评级的行×列(已支持 / 有条件 / 不支持 / 风险)```matrixcolumns: [A, B]、rows: [{label, cells: [{status, text?}]}]、可选的 legend: {support: Good}。每列一个单元格(matrix-cells)。推荐选项:emphasis: <column heading text>(与 columns 中的写法完全一致,matrix-emphasis) — 永远不要在正文中说“蓝色列”。单元格是普通文本或数字的是表格,不是矩阵
3–7 个步骤(无日期,有方向,前一步的输出是下一步的输入)```processsteps: [{title, detail?, status?, emphasis?}]、可选的 caption。系统会自动添加数字(1. 2. …)和箭头;长流程会换行到第二行。如果使用 status,请在 legend: {conditional: Needs approval} 中说明其含义(figure-legend)
两个或更多选项,每个有优缺点:::compare → :::option → :::pros / :::cons如果 3 个及以上共享标准适用于每个选项,则矩阵更合适(见上文)
有子项(及孙项)的父项:团队设置、所有权结构```orgchartroot: {title, detail?}、units: [{title, detail?, members: [{title, detail?}]}]。最多 3 层。盒子上的 status 需要 legend: {conditional: Two more people needed} — 图表下方的图例解释它;不要在 :::note 中解释轮廓颜色。不适用于并列的不相关团队
阶段数量减少(访问 → 注册 → 付费)```funnelstages: [{label, value, note?}]、可选的 unit。value 是数字或文本;条形宽度是阶梯式的,不成比例。阶段间转化率(↓ 45%)会自动从数值计算出来 — 不要在 note 中写;使用 note 说明为什么阶段下降。status 需要 legend。增长的数值会被警告(funnel-increase) — 对于简单步骤使用 process
带日期的计划、周期、截止日期、随时间变化的状态```gantt状态为 support、conditional、none、danger(角色,而非颜色)。硬件/支持风险周期是组 risk: A .. B。注释通过 target 指向一个组/行 id;子系统会放置它们
2–3 个并列分组并排阅读(“今年 / 明年 / 不做”)::::columns → :::column Group title(2 或 3 个)每个分组包含段落、项目符号、一个表格、一张图片、一个 ```chart 或 :::note。无嵌套的 columns、compare、gallery 或其他图形。图表及其解读并排放置:一个分组放图表,另一个分组的项目符号放要点。宽度不是数字:标记一个主要分组 {role=main}(其他分组支持它),或让所有分组相等。4 个及以上单行分组 → 使用项目符号。不适用于分成两半的一个论点
能说明问题的图片(截图、照片、绘图)一个仅包含 ![alt text](images/x.png "caption") 的段落替代文本是必需的(image-alt)。路径相对于演示文稿文件;无 URL、绝对路径或 ..(image-path)。仅 PNG 或 JPEG(image-format)。保持比例,绝不裁剪。图片 + 文字并排 → ::::columns,图片放在一个分组中
2–6 张图片比较或按顺序一个段落包含 2–6 个 ![alt](path "caption")成为画廊(2–3 张一排,4–6 张网格)。7 张及以上是错误的:拆分幻灯片
并列的要点项目符号最多 2 级
连贯的散文段落2–3 句
幻灯片要说明的内容:其结论(一句或两句):::lead 在内容幻灯片的最顶层,一个段落每张内容幻灯片都有一个。 模板将其放在标题正下方,正文之外;它会占用正文空间(1 行 ≈ 32 pt,2 行 ≈ 57 pt)。当需要两行时,引擎会在句末(。)或(如不行)在逗号(、)后断行,不另起一行 — 因此两个短句最易读。不是要点的摘要,而是它们要证明的主张
幻灯片中数字、表格、图形或引用的来源(来源、样本量、日期):::source 在幻灯片最顶层,一个段落每张显示数字、表格、图表或引用的幻灯片都有一个。 仅限内容幻灯片和陈述幻灯片(非章节)。模板将其放在正文下方,页脚上方;它会占用正文空间(layout-overflow 会计入它)。每张幻灯片一个:多个来源放在一个段落中
演示文稿范围的日期、保密性、免责声明(“所有数字均为虚构”)front matter 中的 date、confidential、disclaimer编写一次;显示在封面(confidential 也放在页脚)
警告/类似脚注的说明:::note一个短行。不用于来源(:::source)、不用于演示文稿范围的免责声明(front matter),也绝不用于结论或关键数字
位置/链接承载含义且上述项均不合适的图示```shapes最后手段,参见 §3.1

在上述所有四种图形中,你仅编写文本、status(support、conditional、none、danger)和 emphasis: true;位置、大小和颜色来自模板。在 chart 中,你仅编写比较的对象和数字;图表是真正的 PowerPoint 图表,其值仍然可编辑。强调标题要说明的那一点:

compare: timeSeries
unit: " sign-ups"
categories: [Apr, May, Jun, Jul, Aug, Sep]
emphasis: [Sep]
series:
  - name: Sign-ups
    values: [120, 150, 180, 220, 290, 380]

4. 密度限制

布局引擎为可用的空间建模,密度限制是硬性的:它们防止幻灯片在构建时溢出到右侧或底部(感觉像一个盒子,其内容必须适合内部,否则你会看到溢出)。

在处理了一张幻灯片后,引擎会报告 layout-overflow 警告。在你的 check 输出中查找它:

"warnings": [
  {
    "rule": "layout-overflow",
    "slide_id": 1,
    "message": "Slide 1 overflows its content area by 42 pt",
    "instruction": "Reduce body content by approximately 2 lines"
  }
]

要修复:

  • 依靠 instruction — 它给出了删除多少文本的估算(行数)。首先删除这个量。
  • 简化 :::lead(两行会占用大量空间)。
  • 将项目符号压缩为更少的项,或将长项拆分为两张幻灯片。
  • 将大表格/图形移动到自己单独的幻灯片。

5. 检查 → 修复循环

目前不要执行构建。重复以下步骤:

go run ./cmd/boxloom check -format json deck.bx.md | python3 -m json.tool

编辑 deck.bx.md,然后重新运行。当 check 输出 "ok": true 且无 layout-overflow 警告时,转到 build:

go run ./cmd/boxloom build -o deck.pptx deck.bx.md

附录 A:常见陷阱

  • 缺少 :::lead — 如果内容幻灯片没有 :::lead,表格将认为它是一个章节幻灯片并产生格式混乱的 cover+body。
  • 在 :::lead 中使用项目符号 — 使用包含 - 的行(例如,行以 - 开头)会使它看起来像两个独立行,一字排开。读取器将前两个字符解释为项目符号。最好的写法是 :::lead 是一段不被拆分的文本。
  • 错误而使用 type=statement 的幻灯片 — 它只能有标题和 :::notes。如果你添加了 :::lead,则会错误。
  • :::source 内有空行 — 来源是单行段落。空行会被视为新段落并可能干扰布局。
  • :::note 包含冗长信息 — 演讲者备注很短(一句话);如果幻灯片本身有正文,则不要使用它们作为正文。
  • 自定义模板缺少元数据 — 如果 -template ./my.json 缺少 markdown 或 irSchema 键,check 会出错。始终从现有模板开始,并仅修改视觉属性。
  • 忘记在 check 中使用 -template — 如果使用自定义模板构建,请使用相同的 -template 运行 check;否则角色检查将失败,因为默认模板可能不包含自定义角色。

此版本不包括 docs/patterns.md 的 §3(形状)、§5(示例工作流)和附录(自定义模板格式)。专注于掌握这些核心部分。

相关技能