gogcli slidey Markdown 幻灯片格式完全指南:用 Markdown 驱动 Google Slides 演示文稿

原创2026-09-17 15:29:341,383 阅读

gogcli slidey Markdown 幻灯片格式完全指南:用 Markdown 驱动 Google Slides 演示文稿

testdata/slidey/index.md 是 gogcli 仓库中一份完整的 slidey-flavored Markdown 演示文稿示例("univrs" 商业提案,共 30+ 张幻灯片),也是 gog slides create-from-markdown 命令的端到端测试 fixture。本篇指南将以该文件为实战样本,系统讲解 slidey 格式的每页 frontmatter、演讲者备注、Font Awesome 图标、Mermaid 图、多栏布局与 ::boxes::/::arrows:: 指令块的完整语法,并结合 internal/slidesmarkdown/ 的解析器源码说明其底层原理,让读者能够直接用 Markdown 编写并生成结构完整、排版专业的 Google Slides 演示文稿。

slidey 是什么:从 Markdown 到 Google Slides

gogcli(gog)是一款在终端中操作 Google Workspace 的命令行工具,其中 gog slides create-from-markdown 命令接受两种 Markdown 输入:vanilla Markdown 与 slidey-flavored Markdown。slidey 是一种"为幻灯片而生"的 Markdown 方言,它通过每页 YAML frontmatter、指令块(directive blocks)与行内短代码,把单一 Markdown 文件描述成一套完整演示文稿,再由工具直接调用 Google Slides API 创建演示文稿。

仓库中的 testdata/slidey/index.md 就是这个格式的完整范本——它以 layout: hero 开场,混合使用了 statement、center、default、two-cols、three-cols 等布局,内嵌多段 Mermaid 图、::cols:: 多栏、::boxes:: 图标行与大量 Font Awesome 短代码,几乎覆盖了该格式的全部特性。对应的端到端测试 internal/cmd/slides_e2e_test.go 断言该 fixture 应解析出 30+ 张幻灯片,并且同时包含 hero/title/statement、two-cols、three-cols、## Notes、FA 短代码与 mermaid 块六类要素。

整体流水线由 internal/cmd/slides_formatter.go 中的 CreatePresentationFromMarkdownV2 编排,分七步完成:

  1. 运行资产管线:将图标与 Mermaid 图渲染成 PNG 并上传到 Drive;
  2. 调用 Slides API 创建演示文稿;
  3. 读取其页面尺寸,推导 LayoutGeometry(页面几何常量);
  4. 渲染第一批 BatchUpdate 请求(幻灯片 + 内容 + 图片引用);
  5. 重新拉取演示文稿,找到备注对象 ID;
  6. 渲染第二批 BatchUpdate 请求写入演讲者备注;
  7. 清理临时 Drive 文件。

解析入口是 internal/slidesmarkdown/markdown.go 的 Parse:它先按 --- 把整个文件切成若干 slideBlock(frontmatter + body),再对每个 block 执行"剥离 Notes → 归一化简写列 → 解析带 ID 的块",最终产出 []Slide AST。

幻灯片分隔与每页 frontmatter

在 slidey 格式中,一条裸的 --- 行就是幻灯片分隔符,唯一例外是"连续 YAML 头"——即 --- 之后紧跟着 key: value 形式的行,再以 --- 结束且期间没有空白/正文行时,它会被识别为该页的 frontmatter。这一判定规则由 internal/slidesmarkdown/frontmatter.go 的 splitMarkdownIntoSlideBlocks 实现,要点如下:

  • 文件开头或紧跟另一个分隔符(中间只允许空行)的 --- 会成为 frontmatter 候选;
  • 其后的首个非空行必须匹配 YAML 键模式 ^[A-Za-z_][A-Za-z0-9_-]*:\s(yamlKeyLineRE),否则该 --- 仍是普通分隔符;
  • 连续扫描 YAML 键行,期间一旦出现空行或非键行即放弃候选,保证分隔符后的普通正文不会被误判;
  • 解析器会先对输入做 CRLF 归一化(\r\n → \n),跨平台写作无需担心换行符差异。

每页 frontmatter 目前识别两个键(见 docs/slides-markdown.md 与 internal/slidesmarkdown/ast.go 的 SlideFrontmatter):

键 取值 行为
layout title、hero、statement、center、default、two-cols、three-cols 决定该页的视觉排版;未知值回退为 default
content wide、narrow 已解析但暂未实际应用(Slides 的文本框宽度固定)

其他未知键会存入 Raw 映射,为后续版本兼容留有余地。下面是 testdata/slidey/index.md 首页的写法:

---
layout: hero
---

# univrs

Unfolding Nested Intent · Valid · Reliable · Safe

layout 名称到内部排版类别的映射定义在 internal/cmd/slides_layout.go 的 MapSlideyLayout 中:center → 居中版式,title/hero/statement → 章节头版式,two-cols/three-cols → 双栏/三栏版式,其余一律归入 LayoutKindDefault。注意 fixture 中大量使用了 layout: center(如 "This is not abundance" 一页)与 layout: statement(如 "Not just CRM." 一页),它们的正文会被居中摆放,适合强调性内容。

标题提升:h1/h2 如何成为页标题

解析器对每页 body 会执行"标题提升"(title hoisting),规则定义在 internal/slidesmarkdown/markdown.go 的 hoistTitle:

  • 优先取第一个 #(h1)的文本作为 Slide.Title;
  • 若没有 h1,回退取第一个 ##(h2);
  • 取到的标题行会从 body 块中移除,不再重复渲染。

不过,layout 为 title、hero、statement 的页面会跳过标题提升(layoutSkipsTitleHoist),此时标题保留在正文流中,由排版系统按章节头处理。在 fixture 中,"Start with one spine. Let the company unfold from it"、"The company should remember what it does." 等页面的 ## 标题即被提升为页标题,而 hero 页(如首页 "univrs")与 statement 页(如 "Not just CRM.")则走独立渲染路径。

演讲者备注:## Notes 区块

slidey 约定,每页末尾以 ## Notes(或 ### Notes)开头的区块会被整体抽离为演讲者备注,标题及其后的所有内容从正文移除。实现位于 internal/slidesmarkdown/markdown.go 的 splitOutNotes,它逐行扫描(并正确跳过代码围栏内的同名文本),精确匹配 ## Notes 或 ### Notes;备注中的 FA 短代码会被剥离为纯文本(因为备注无法渲染图片),存入 Slide.Notes。

fixture 中几乎每页都带有 Notes 区,例如 "Why this moment is different" 一页:

## Notes

- AI changes the requirement, not just the interface.
- Owning data is insufficient if the verbs and permissions are not owned too.
- This is why the argument is timely rather than academic.

这些备注最终通过第二批 BatchUpdate 写入 Google Slides 的演讲者备注框(见 CreatePresentationFromMarkdownV2 的步骤 5–6)。若使用 --no-notes 标志,则整个 Notes 写入阶段被跳过(internal/cmd/slides_formatter.go)。

Font Awesome 图标短代码

在正文中可以直接书写 :fa-name: 形式的 Font Awesome 短代码,例如 fixture 中的 :fa-rectangle-ad:(广告)、:fa-headset:(客服)、:fa-dev:(开发)、:fa-people-group:(人事)、:fa-truck-fast:(订单履约)、:fa-building:(设施)。其解析正则在 internal/slidesmarkdown/inlines.go:

:fa([srlbd])?-([a-z0-9][a-z0-9-]*):

短代码前缀决定图标风格(faStyleFromPrefix,见 internal/slidesmarkdown/inlines.go):

前缀 解析风格
fa- 取 --fa-style 默认值(默认 solid)
fas- solid
far- regular
fab- brands
fal-、fad- solid(FA Free 无 light/duotone,以降级处理)

渲染时,图标会从 cdn.jsdelivr.net 拉取 FA Free SVG,经本地 rsvg-convert 或 ImageMagick 栅格化为 PNG 后上传 Drive 插入幻灯片;若本机没有 SVG 栅格化工具,图标会被跳过并告警,--strict 模式下则直接报错。放在列表项开头的图标会渲染为条目左侧的小图片,段落中间的图标则被丢弃。fixture 的 "Why this moment is different" 三栏页正是把 :fas-file:、:fa-database:、:fa-house-circle-check: 用作每栏的视觉锚点。

Mermaid 图:从代码块到 PNG

凡是语言标签为 mermaid 的围栏代码块都会被识别为图(DiagramBlock),例如 fixture 中 "univrs defines fields and rules for agents to act within." 一页的 flowchart,以及附录里描述分层架构的多张图。识别逻辑在 internal/slidesmarkdown/blocks.go:goldmark 解析出 FencedCodeBlock 后,若 lang == "mermaid" 即生成 DiagramBlock 并分配稳定 ID(block-N)。

渲染路径见 internal/cmd/slides_assets.go:解析器把 Mermaid 源码写入临时 .mmd 文件,调用本机 mmdc(Mermaid CLI)以透明背景、2 倍缩放生成 PNG,再上传 Drive。mmdc 路径可通过 --mmdc 指定;置空则禁用图渲染,遇到图时跳过并告警(--strict 下致命)。

fixture 中一张典型 Mermaid 图:

```mermaid
flowchart TB
  subgraph EventLog
     direction TB
      e1[Ticket.Created]
      e2[Order.Placed]
      e3[Ticket.Resolved]
  end
  SalesLens[Sales lens<br/>pipeline · forecast · ARR]:::accent
  EventLog --> SalesLens

## 多栏布局:`::cols::` 与简写标记

slidey 用显式的列指令块实现多栏排版(见 <a href="https://link.gitcode.com/i/ef77360eee9ab7351e406db0fcea0469" target="_blank">docs/slides-markdown.md</a>):

::cols::

left column markdown

::col2::

middle / right column markdown

::col3::

third column markdown

::/cols::


同时 `::right::` 是 `::col2::` 的同义写法(slidey 风格)。在 `layout: two-cols` 和 `layout: three-cols` 的页面中,`::col2::`、`::col3::`、`::right::` 甚至可以**省略开头的 `::cols::`**:标题之后的内容自动成为第一列。这一"简写归一化"逻辑在 <a href="https://link.gitcode.com/i/57b9bf33600668549afa6a8c6dab0474" target="_blank">internal/slidesmarkdown/markdown.go</a> 的 `normalizeShorthandColumns` 中实现——它会检测 body 中是否存在显式 `::cols::` 或简写列标记,若只有简写标记则自动补全 `::cols::` 与 `::/cols::` 包裹。

所有标记常量集中在 <a href="https://link.gitcode.com/i/2536ff7c1a262e44aeec223ab9888578" target="_blank">internal/slidesmarkdown/blocks.go</a>:`::cols::`/`::/cols::`/`::col2::`/`::col3::`/`::right::`,以及 `::boxes::`/`::/boxes::`、`::arrows::`/`::/arrows::`。列内容会递归解析成子块(`columnsBlockFromRaw`),允许每栏内部再嵌套图标行、代码块等元素。fixture 中 "We keep paying to connect what should already be connected" 一页即为标准三栏示例:三栏分别展示"60–70% IT 预算""1000+ SaaS 应用""集成支出年增 15–20%"三组数据。

渲染时,栏宽由 `ColumnBoxes`(<a href="https://link.gitcode.com/i/eab63701942319e35815ed334988ff88" target="_blank">internal/cmd/slides_layout.go</a>)按页面几何计算:内宽 = 页宽 − 2×边距 − (栏数−1)×栏间距,再均分给各栏。

## `::boxes::` 与 `::arrows::` 指令块

这两个块以"图标 + 文本"逐行构成图标行:

::boxes:: :fa-rectangle-ad: Campaigns :fa-headset: Support Tickets :fa-dev: Product & Eng Tracking :fa-people-group: HR & Recruiting :fa-truck-fast: Orders & Fulfilment :fa-building: Facilities ::/boxes::

::arrows::

Step One

Step Two

::/arrows::


解析见 <a href="https://link.gitcode.com/i/e86d7352210689d3904ca980491096dc" target="_blank">internal/slidesmarkdown/blocks.go</a> 的 `consumeIconRowsBlock`:逐行读取到闭合标记为止,每行解析出可选的图标(`IconRef`)与文本(`IconRow`);行首的 Markdown 标题标记(`###` 等)会被剥离,仅保留文本。渲染时二者都输出为正文中的列表:`boxes` 使用圆点字形,`arrows` 使用 `→` 箭头字形(<a href="https://link.gitcode.com/i/ebb6f3abc7986111f15a89c3dfa3c30d" target="_blank">docs/slides-markdown.md</a>)。fixture 中 "AI today is pretending the UI is the product" 一页即用 `::arrows::` 串起"Screen-scrape legacy systems. → Hope the query selectors still match the HTML. → Pray nothing leaks."三步流程。

## 命令行使用:gog slides create-from-markdown

把 slidey 文件变成真实演示文稿的命令定义在 <a href="https://link.gitcode.com/i/58043cc54e16ba7728ab46b3e9a7906b" target="_blank">internal/cmd/slides.go</a>,完整参数如下:

| 参数 | 默认值 | 说明 |
|------|--------|------|
| `title`(位置参数) | 必填 | 演示文稿标题 |
| `--content` | 空 | 直接传入 Markdown 内容(内联) |
| `--content-file` | 空 | 从文件读取 Markdown 内容 |
| `--parent` | 空 | 目标 Drive 文件夹 ID |
| `--debug` | `false` | 输出解析出的幻灯片数量等调试信息 |
| `--fa-style` | `solid` | 无前缀 FA 短代码的默认风格(`solid`/`regular`/`brands`) |
| `--mmdc` | `mmdc` | Mermaid CLI 路径;置空则禁用图渲染 |
| `--strict` | `false` | 把被跳过的图标/图视为致命错误 |
| `--keep-temp-images` | `false` | 导入后不删除临时 Drive 上传 |
| `--no-notes` | `false` | 丢弃 `## Notes` 区而非写入演讲者备注 |

`--content` 与 `--content-file` 至少提供其一。以本仓库 fixture 为例:

```bash
gog slides create-from-markdown "univrs Executive Pitch" \
  --content-file testdata/slidey/index.md \
  --fa-style solid \
  --parent <folder-id>

该命令同样支持 --dry-run 全局标志:不真正调用 API,而是在 JSON 输出中给出 title、slides 数量、no_notes 以及 batch_update(由 buildSlideyDryRunBatchUpdate 生成、包含全部渲染指令的预览),方便在动手前检查解析结果(internal/cmd/slides.go)。运行成功后命令会输出创建的演示文稿链接;配合 JSON 输出格式(--format json 或等价全局选项)可获得完整 presentation 与 file 对象(internal/cmd/slides.go)。

从 fixture 学到的写作范式

对照 testdata/slidey/index.md 的篇章结构,可以提炼出用 slidey 组织商业/技术提案的通用范式:

  1. hero 开场:layout: hero + 产品名 + 一句话副标题(fixture 首页 "univrs / Unfolding Nested Intent · Valid · Reliable · Safe");
  2. statement 立论:layout: statement 配 ::boxes:: 罗列痛点领域("Not just CRM.");
  3. center 强调:layout: center 放大核心论断("This is not abundance — It is operational fragmentation.");
  4. three-cols 数据对比:::cols::/::col2::/::col3:: 放三组关键数据;
  5. 流程图论证:mermaid 块展示"现状 vs 目标"架构("AI today · pixels" vs "univrs · verbs" 双子图);
  6. 代码示例页:普通围栏代码块直接呈现 KDL/TS/SQL 片段(fixture 中 KDL schema、ECS 组件、TS 类层级三栏并置);
  7. 附录收束:layout: two-cols 的"我们选什么 / 我们避免什么"两栏清单(Runtime + UI、Schema + behavior、Persistence + execution、Search + read model 四组);
  8. 全程配 Notes:每页 ## Notes 写演讲提示(fixture 中 CEO/CFO/CIO/CPO 视角的要点各取所需)。

这套范式可以直接套用到团队的技术分享、方案评审与对外提案中——因为正文与备注分离,同一份 Markdown 既能当讲稿又能当讲义。

质量保证:fixture 如何被验证

slidey 格式的解析与渲染质量由多层测试保障。最直接的是 internal/cmd/slides_e2e_test.go 的 TestSlideyFixture_ParsesAndRenders:它读取 testdata/slidey/index.md,断言解析出的幻灯片数 ≥ 30,逐一检查 hero/statement、two-cols、three-cols、Notes、图标、mermaid 图的存在性,并用假资产映射走完整渲染管线,验证 RenderSlides 产出非空 BatchUpdate 请求与备注计划。

单元层面,internal/slidesmarkdown 包为解析器各环节提供了针对性测试:frontmatter_test.go 覆盖 --- 分隔符与 frontmatter 候选判定,blocks_test.go 覆盖列/图标行/围栏状态,inlines_test.go 覆盖 FA 短代码与强调解析,markdown_test.go 覆盖 Notes 剥离与标题提升。此外 internal/cmd/slides_assets_test.go 验证了 mmdc 命令参数拼装、mmdc 缺失时的告警与 --strict 致命行为。这些测试共同保证:任何对 slidey 格式的修改都必须让这份 30+ 页的复杂 fixture 继续通过解析与渲染,从而让格式规范长期保持稳定、可复现。

小结

slidey-flavored Markdown 把"排版决策"压缩为极少的显式语法——每页一个 frontmatter、一套指令块、若干短代码——其余一切交给 gog slides create-from-markdown 的解析器与渲染器。从 testdata/slidey/index.md 这份完整实例出发,配合 docs/slides-markdown.md 的规范与 internal/slidesmarkdown/ 的实现源码,你可以快速掌握这一格式:用 hero/statement/center 控制页面节奏,用 ::cols:: 与 ::boxes::/::arrows:: 组织信息密度,用 FA 短代码与 Mermaid 图补充视觉语言,再用 ## Notes 沉淀演讲要点——最终在终端里一键生成可直接分享的 Google Slides 演示文稿。

登录后查看全文
gogcli