跳至内容

Playground

在浏览器中编写演示文稿,幻灯片实时跟随:编译为 WebAssembly 的 go-slides,带自动补全、帮助和示例。

打开 Playground →

Playground 就是 go-slides 本身(v0.18.0),编译为 WebAssembly 后在你的浏览器中运行。 在左侧输入演示文稿,右侧的幻灯片会随之更新。不会向服务器发送任何内容:演示文稿不会,分享链接也不会。

Playground 自身的界面(功能区、帮助、提示信息)使用页面所用的语言: 打开 /zh/playground/ 即为简体中文,本站的十二种语言同理。页面上的语言选择器可以切换语言, 你的选择会保存在此浏览器中;链接中指明了语言时,始终以链接为准。示例演示文稿仍为英文。 乌克兰语、俄语、中文、日语和韩语使用 Noto Sans 的子集(0.06 至 2.3 MiB)绘制,页面只为这些语言下载它。

功能

  • 实时预览 每张幻灯片,渲染在页面主线程之外进行(Web Worker),因此输入时永远不必等待。点击一张幻灯片,编辑器会跳到对应的行; 移动光标,预览会滚动到对应的幻灯片。

  • 放映:即演示本身,支持键盘、屏幕控制器和过渡效果。

  • 演讲者视图:Present(或在放映中按 p)会在第二个窗口中打开它: 当前幻灯片、下一步、演讲者备注(演示文稿中的 <!-- comments -->)、时钟和计时器。 方向键、Space、Home 和 End 在两个窗口中都可使用,两个窗口相互同步, 编辑演示文稿时也是如此。如果窗口没有打开,请允许该站点弹出窗口。 概览视图(o)仅在下载的页面中提供。

  • 自动补全,边输入边提示:指令键(注释中的单页指令 _)、 kind(幻灯片类型)、theme、size、paginate 的取值,以及 {{ }} 内的模板函数和数据字段。

  • 帮助,针对光标下的内容:指令、kind(及其设置的内容)、模板函数。 帮助面板中也有指向本文档各页的链接。自 v0.16.0 起, 指令帮助会跟随界面语言,支持 11 种语言。

  • 问题 显示在对应的行上:模板、YAML 和 HCL 错误会在编辑器中高亮, 并在其下方列出,预览则保留最后一次成功渲染的演示文稿。

  • 示例:欢迎演示文稿、生成幻灯片的模板、幻灯片 kind、 HCL front matter、主题与单页指令,以及数学公式、图片和背景 (![bg]、分栏的 ![bg left:40%]、滤镜)。

  • 文件:编辑器左侧的面板就是演示文稿的项目,其结构与 命令行工具和 VS Code 扩展的读取方式一致:deck.md、 slides.yaml、themes/、kinds/、media/。

    • 点击文件即可编辑。编辑器会按文件语言着色 (Markdown、YAML、HCL、JSON、CSS),并标出其中的问题。
    • 右键(或 Shift+F10)可使用 New File、New Folder、Rename(F2)、 Delete(会先确认)以及 New theme / New kind。把文件拖到文件夹上即可移动。 键盘操作遵循 WAI-ARIA 树形控件模式,包括输入时自动定位。
    • Project ▸ New theme 会创建 themes/my-gaia.css(也可基于 default、 uncover):其中包含对内置主题的 @import 以及你添加的规则。 它会加入 Theme 列表。New kind 和 New data file 同样从模板开始。 每个新文件都会登记在 slides.yaml 中,因此 slides build deck.md 能找到它。
    • Project ▸ Download project (.zip) 会保存全部内容。解压后, 用 slides build deck.md 即可构建。Open project 可以重新打开一个 .zip 或 文件夹。会跳出其所在文件夹(..、绝对路径)、包含超过 256 个文件或单个文件超过 8 MiB, 或解压后膨胀超过 100 倍的压缩包会被拒绝。
    • 所有内容都与草稿一起保存在当前浏览器中。一个项目最多可容纳 64 MiB,文件列表下方的一行会显示已用空间。
  • 媒体:将图片、视频或音频拖放或粘贴到编辑器中,它会被放进 media/,并在演示文稿中引用:![](media/photo.png)。把文件拖到面板中的某个文件夹上, 即可放到该文件夹中。演示文稿保持精简易读,也不会上传任何内容。 预览的沙盒无需放宽限制即可加载这些媒体(由页面把字节数据交给它)。Save as ▸ HTML page 会把它们放进页面中。https: 图片同样可用,但浏览器会从其服务器获取, 服务器因此会看到你的地址。预览不发送 referrer。

  • 可调整大小的窗格:文件面板、编辑器、幻灯片缩略图、预览和帮助之间以可拖动的分隔条隔开 (指针移到分隔条上时会变为调整大小的光标)。分隔条旁边的窗格占用调整出的空间, 其他窗格保持大小不变。双击分隔条,或在其上按 Enter,可以收起窗格,再次操作则恢复。 使用键盘时,F6 在分隔条之间切换,方向键每次移动 16 px,Home 和 End 将分隔条前面的窗格 调到最小和最大,Escape 返回编辑器。View 选项卡仍可关闭窗格。 你设置的尺寸会与草稿一起保存在当前浏览器中;默认尺寸(190、168 和 280 px, 编辑器与预览按 6 比 5 分配剩余空间)从不保存。

  • 格式:Format 选项卡会替你编辑 Markdown,每按一次就是一步撤销。

    • 文本:Bold、Italic、Strikethrough 和 Inline code 作用于所选内容 或光标所在的单词,并可切换(Ctrl+B、Ctrl+I、Ctrl+Shift+X 和 Ctrl+E;Mac 上用 Cmd)。光标位于相应标记内时,按钮显示为按下状态。 Markdown 没有下划线:Underline(Ctrl+U)会用 <u>…</u> 包裹文本, 这个标签在 Marp 默认的 HTML 白名单中,因此关闭原始 HTML 时也能生效。
    • 段落:Heading 1 到 3(Ctrl+Alt+1..3)、项目符号(Ctrl+Shift+8)、 编号(Ctrl+Shift+7)和引用作用于所选的行,并可切换。 水平线使用 <hr> 标签:因为在 Marp 中,---、*** 和 ___ 都会开始一张新幻灯片。
    • 表格:通过网格选择列数和行数。光标位于表格中时,可以添加或删除行、列, 并设置列的对齐方式(:--、:-:、 --:);每次编辑后表格都会重新对齐。
    • 幻灯片文本 左对齐、居中或右对齐,会在当前幻灯片中写入一个 <style scoped> 块。 Marp 没有对齐语法,style 属性也无法通过默认的 HTML 白名单,但 scoped 块可以, 因此关闭原始 HTML 时也能生效,并会显示在预览、HTML 页面和 PDF 中。
    • 链接(Ctrl+K)会写出 [text](url),并选中其中的 url。
  • 高亮 front matter 中任意层级的键,支持 YAML(包括 {a: 1} 形式的映射)和 HCL。

  • 主题 选择器:default、gaia、uncover、项目中的主题 (themes/*.css),以及演示文稿自己定义的主题(<style> 中的 /* @theme name */)。 它会把 theme: 写入 front matter(YAML 或 HCL),因此分享链接会保留主题;编辑 front matter 时,选择器也会随之更新。

  • 输入时预览会保持位置:只替换发生变化的幻灯片,切换主题后预览会重新定位到同一张幻灯片。

  • 分享链接:演示文稿就包含在链接中(压缩后放在其 # 部分), 因此打开链接即可打开演示文稿。链接最多可携带压缩后 64 KiB 的内容,且只包含演示文稿:当项目还有其他内容 (主题、kind、媒体)时,Share 会给出提示并提供 .zip。

  • 另存为:

    • HTML 页面,与 slides deck.md 写出的相同;
    • PDF(矢量,文本可选中,带书签大纲);
    • 可编辑的 PowerPoint 或 OpenDocument 演示文稿。

    它们都在你的浏览器中生成,所用代码与 slides --pdf、 --pptx 和 --odp 相同:100 张幻灯片基准演示文稿的 PDF 与命令行生成的 逐字节相同。第一次导出时会下载导出引擎(约 5 MiB,仅下载一次;浏览器会保留它直到下次更新), 并显示进度,边下载边编译。之后只下载幻灯片实际用到的字体。在 3 MB/s 的网络上, 欢迎演示文稿的第一个 PDF 不到 3 秒即可完成。之后导出 100 张幻灯片的演示文稿约需 3 秒。 https: 图片只有在其服务器允许时(CORS)才会被包含;data: 图片则总会被包含。

  • 草稿会被保留:

    • 演示文稿会在输入时保存在当前浏览器中(IndexedDB,仅限本站点), 重新加载页面后会恢复。不会发送到任何地方。项目中的文本文件 (主题、kind、数据、slides.yaml)也以同样方式保存,即使你刚输入完就关闭标签页也不会丢失; 媒体文件在拖入时即被保存。
    • 打开分享链接会打开其中的演示文稿,同时保留你的草稿:Draft ▸ Restore my draft 可将草稿恢复。
    • 打开示例、Draft ▸ Reset to the example(会先确认)或另一个标签页也都不会抹掉草稿: Draft ▸ Restore replaced 可将其换回。
    • Draft ▸ Forget my drafts 会删除所有已保存的内容。

每次导出渲染的都是预览所显示的项目:包括其 slides.yaml、 主题、kind、数据文件和媒体,媒体会嵌入文档中。

以文件形式输出图片(slides --images)无法在浏览器中完成:请使用 命令行工具或 VS Code 扩展。

撤销、重做与版本

Undo(撤销)和 Redo(重做)位于 Home 选项卡,也可用 Ctrl+Z、Ctrl+Shift+Z 或 Ctrl+Y(Mac 上为 Cmd)。它们先撤销当前所示文件的最后一次编辑(每个文件有自己的历史), 再撤销对整个项目的最后一次操作:选取的示例、Reset、打开的 .zip 或文件夹、恢复的草稿、 删除或重命名的文件或文件夹、恢复的版本。Redo 会把一切恢复到按下 Undo 时的样子。

版本把整个项目保存在此浏览器中,不会向任何地方发送内容。停止输入后不久会保存一个 (最多每 2 分钟一次),对整个项目的每次操作之前、每次导出和生成分享链接时也会保存。 Save version… 会以名称保存一个。Home ▸ Versions 打开 Versions 窗格:

  • Preview 在预览中显示某个版本。
  • Compare with now 逐行显示每个文件的变化,可内联或并排显示; F7 和 Shift+F7 在变化之间移动。
  • Restore 把某个版本放回去;Undo 可撤销这次恢复。
  • Delete 删除某个版本。

保留的内容:最新的 20 个自动版本,之后一天内每小时一个,一个月内每天一个。 命名版本会一直保留,直到你删除(最多 50 个)。所有版本合计最多 96 MiB, 未变化的文件只存储一次。浏览器存储已满时,最旧的自动版本最先被清除。

GitHub

Home ▸ History ▸ GitHub 打开一个窗格,从 GitHub 仓库载入演示文稿的文件夹, 并把你的修改以拉取请求的形式提回去。请填写:

  • 仓库(所有者/名称);
  • 分支(留空:默认分支);
  • 文件夹(留空:根目录):文件夹中必须有 deck.md;
  • 令牌,已遮蔽;
  • 在此设备上记住。

令牌是细粒度个人访问令牌(创建一个), 仅限所选仓库,权限为 Contents 读写和 Pull requests 读写(Metadata 只读为隐含)。然后:

  • 连接 检查令牌和仓库;断开 忘记令牌。
  • 载入 用 GitHub 上的文件夹替换项目。Undo 可以撤回,原来的项目会保存为 “来自 GitHub” 版本。
  • 提出修改… 询问标题,创建新分支 slides/<标题>-<日期时间> 并打开拉取请求。 它从不写入已有分支或默认分支。打开拉取请求 会带你到那里。
  • 检查变化 在 Compare 视图中比较 GitHub 上较新的版本与你的版本。 采用对方的 会载入它。

GitHub 不使用代理:playground 直接与它通信。

令牌只留在标签页的内存中,只发送到 api.github.com:页面的 Content Security Policy 不允许任何其他主机。它从不保存到草稿、版本、分享链接或导出中,也从不 到达幻灯片预览或渲染 worker。在此设备上记住 会把它存入此浏览器的 localStorage,直到 断开(或 Forget my drafts)。仍有一项风险:注入到 playground 页面本身的脚本可以读取它。请优先使用只限于所需仓库的令牌。对于团队, 自托管服务器模式(即将推出)把令牌保存在服务器上。

GitLab.com

窗格中有一个 forge 列表:GitHub 和 GitLab.com。使用 GitLab 时,可以提供范围为 api 的个人访问令牌,或点击 用 GitLab 登录(带 PKCE 的 OAuth 授权码,无需密钥)。 登录会把页面带到 gitlab.com 再返回,地址会立刻被清理。登录得到的令牌只留在此标签页的 内存中(即使选了 在此设备上记住 也不会记在设备上),会在过期前自动刷新, 断开 会在 GitLab 撤销它们。在另一个标签页发起的登录,或重复使用的链接,都会被拒绝。 本站的 GitLab 应用注册后即可使用登录;在此之前请使用个人访问令牌。

请求只发往 api.github.com 和 gitlab.com:页面的 Content Security Policy 不允许任何 其他主机,页面也不发送 referrer。

为什么需要 api?GitLab 的范围表 对 write_repository 写的是 “Does not support API authentication”:它只用于基于 HTTP 的 git,而 GitLab 提供该服务时不带 CORS,浏览器无法使用。提出修改走 REST API,需要 api, 即 “complete read and write access to the API”。被盗的 api 令牌可以做其用户通过 API 能做的一切,涉及该用户能访问的所有项目。请优先使用只限于演示文稿仓库的项目或群组访问令牌, 或只作为演示文稿项目成员的专用 GitLab 账号。

安全

演示文稿显示在一个不具有页面来源(origin)的沙盒 iframe 中:它既无法访问 Playground, 也无法访问其存储,不能提交表单,也不能进行任何导航。其页面带有内容安全策略(Content Security Policy), 只运行它自己的脚本。演示文稿中的原始 HTML 遵循 Marp 的白名单,与 slides 的默认行为相同。 运行超过 5 秒的渲染(例如陷入循环的模板)会被终止。

演讲者窗口同样处于该沙盒中。它由 Playground 本身打开, 并在以同样方式沙盒化的 iframe 中显示演示文稿。两个 iframe 无法共享存储,因此由 Playground 通过消息在它们之间转发幻灯片序号。 任何运行演示文稿的框架都不会获得 Playground 的来源。

项目中的媒体以消息中的字节数据形式传给沙盒框架, 每个框架在自己的来源中为其创建各自的 blob: URL。由 Playground 创建的 blob: URL 在框架中无法加载,而框架的策略仅为媒体和字体额外放开了 blob:。

Playground 可以从你自己的机器上提供服务,并置于登录之后:参见 自托管。

体积与速度

按 GitHub Pages 提供的形式(gzip;Pages 不提供 brotli),模块大小为 8.8 MiB。它只会下载一次并显示进度条,之后由浏览器缓存,直到下次部署。 在 Apple M4 Max 和 Chrome 155 上针对线上页面测量,页面打开后 2.1 s 编辑器即可使用, 其中 1.5 s 用于下载,首批幻灯片在 2.4 s 时出现。修改 100 张幻灯片的基准演示文稿后,约 30 ms 即可反映到预览中:go-slides 只渲染发生变化的幻灯片,预览中也只替换这些幻灯片。

Created on by tannevaled

Modified on by tannevaled