OpenMAIC 幻灯片页面设计规范指南:slide-craft 技能详解
【免费下载链接】OpenMAICOpen Multi-Agent Interactive Classroom — Get an immersive, multi-agent learning experience in just one click项目地址: https://gitcode.com/GitHub_Trending/op/OpenMAIC
导读
slide-craft是 OpenMAIC 多智能体交互课堂中定义"一页幻灯片长什么样才算好"的设计法则文档。它不是操作流程,而是页面设计定律:画布几何、文字高度表、字号阶梯、对比度配对、间距节奏,以及十种元素类型各自应承载何种内容。本文以该技能文档为主体,结合 slide-dsl 字段手册、page-clone 与 pro-editing 编辑流程,以及仓库中结构校验与 latex 重渲染的真实实现,为你完整还原这套"用数字而非眼睛"设计幻灯片页面的规则。读完你将掌握:如何在 1000 × 562.5 的画布上精确落位元素、如何按高度表重算文本框、如何用对比度配对而非凭感觉改色、以及如何让富文本与公式在播放器里真正按预期渲染。
适用场景:逐元素修补幻灯片、修正颜色或对比度问题、让文字在框内生长或收缩、页面显得拥挤或空旷、或需要用真实富文本结构替换内容时,都应加载本技能。它是
page-clone和pro-editing两个流程的评判标准——那两个技能决定改哪些页、按什么顺序改,本技能决定改完之后一页好页面应该长什么样。
正在编辑的画布
画布尺寸与安全边距
OpenMAIC 运行时中的每张幻灯片都是在同一套规则下绘制的,画布几何是这套规则的起点:
- 画布为 1000 × 562.5(设计像素)。这一数值在底层由
viewportSize: 1000(画布宽,px)与viewportRatio: 0.5625(高 ÷ 宽)共同决定,在 element-schema.ts 的滑动画布结构 schema 中两者均为必填字段,并被 slide-dsl 明确记录为 "canvaswidth in px—1000in this product"。 - 所有元素遵守 50px 边距。因此有效区域为
left ∈ [50, 950]、top ∈ [50, 512.5],元素的右边缘(left + width)必须 ≤ 950,底边缘必须 ≤ 512.5。 - 画布边缘不裁剪 DOM 中的元素,但快照/导出捕获会裁剪画布外的内容,所以画布外的几何本身就是 bug。
页面对齐网格
页面上已有的元素都落在同一个对齐网格上,修补时应当读取邻居的框,落在它们已经在用的那一列上:
| 对齐方式 | left 取值 |
|---|---|
| 左对齐内容 | left = 60或left = 80 |
| 居中对齐内容 | left = (1000 - width) / 2—— 重新计算,绝不靠猜 |
| 右对齐内容 | left = 1000 - width - 60 |
需要注意:居中的内容改变width会连带改变left,且这是两次独立的写入。一个孤立的元素相对共享左边缘偏差 8px,即使没有任何溢出,看起来也像一次错误。
不存在"对齐操作"
这套运行时没有对齐操作。每个位置都是一个显式数字,通过该元素自身的left/top/width/height写入,一次调用一个路径,数值由你读取到的邻居计算得出。对齐一行意味着给每个元素赋予这一行已经在用的数字——而不是请求页面自己整理。这正是 slide-dsl 强调的 JSON Pointer 写入模型:/content/canvas/elements/N/left这样的叶子路径就是唯一的对齐手段。
文字按表定尺寸,不凭肉眼
10px 内边距与文字高度表
文本元素四边各有 10px 内边距,因此可用区域为(width - 20) × (height - 20)。文本框的高度只能从一个固定表格取值(行高 1.5,已含内边距):
| 字号 | 1 行 | 2 行 | 3 行 | 4 行 | 5 行 |
|---|---|---|---|---|---|
| 14px | 43 | 64 | 85 | 106 | 127 |
| 16px | 46 | 70 | 94 | 118 | 142 |
| 18px | 49 | 76 | 103 | 130 | 157 |
| 20px | 52 | 82 | 112 | 142 | 172 |
| 24px | 58 | 94 | 130 | 166 | 202 |
| 28px | 64 | 106 | 148 | 190 | 232 |
| 32px | 70 | 118 | 166 | 214 | 262 |
| 36px | 76 | 130 | 184 | 238 | 292 |
替换文字后的高度重推导
替换元素的文字时,重新推导高度而不是沿用旧值:
characters_per_line = (width - 20) / font_size。让最长行保持在它的≤ 75%以内;超过 100% 文字就会换行,多占一行你没有预算的行。- 数出新内容需要的行数——每个
<p>算一行,每个超过characters_per_line的段落再加一行换行——然后加约0.8 行的余量并向上取整。 - 对照内容中存在的最大字号(不是平均字号)查表。
高度是容器,不是钳子:溢出的文字会溢出盒子而不是收缩,页面会如实显示溢出。修复顺序是先缩短文字,再升一档表格行,最后加宽盒子——按此顺序,因为需要更大盒子的幻灯片通常只需要更少的文字。
字号阶梯(Type Scale)
| 内容 | 字号 |
|---|---|
| 主标题 Main title | 32-36px |
| 副标题 Subtitle | 24-28px |
| 要点 Key points | 18-20px |
| 正文 Body | 16-18px |
| 说明 Caption | 14-16px |
各层级之间保持 2-4px 的差距,同一层级的所有内容使用同一个字号。当你触碰一个元素时,从该页面上扮演相同角色的兄弟元素那里取字号,而不是从这张表里现取——页面自身的阶梯优先,这张表是你识别元素属于哪个层级的工具。
字号存在于内容 HTML 中,以内联font-size写在<p>上——没有可供写入的 font-size 字段。因此改变字号意味着写回整个内容字符串,这意味着你必须了解你要替换的标记结构。
渲染器对你的 HTML 究竟做了什么
文本元素的content是一个 HTML 字符串,而该页面的 CSS reset 抹掉了大多数标签语义。以下四个后果决定你如何书写富文本:
<ul>/<ol>不渲染项目符号。样式表的 reset 剥离了list-style和缩进,而把它放回来的规则只作用于浏览器编辑器——不作用于课堂播放。以<ul><li>…</li></ul>发送的列表最终会呈现为裸的、无缩进的行。要像课件本身那样写项目符号:每项一个<p>,符号写在文本里,例如<p style="font-size:18px;">• 第一点</p>。<h1>–<h6>是无效的。reset 对它们设置了font-size: inherit和font-weight: inherit,所以标题标签只是多几个字符的<p>。字号和字重来自内联的font-size和<strong>,它们才真正生效。- 堆叠的
<p>标签之间没有间隙——只有 line-height 分隔它们。如果两行之间需要空气,就提高元素的lineHeight或把它们拆成两个元素;不要指望空<p>(它的高度仍然要占一个表格行)。 - 纯文本中的换行不是换行。纯文本会被包进单个
<p>,换行折叠成空格。多行内容必须以真正的<p>标签到达,每行一个。
任何看起来像标签的内容都会被当作标记透传而不是转义,所以包含<后跟字母的文本(如if x<y> then)会被当作 HTML 读取并损坏——请以转义实体发送。
受支持的内联样式为font-size、color、text-align、line-height、font-weight、font-family;受支持的标签为<p>、<span>、<strong>/<b>、<em>/<i>、<u>。除此之外都不是契约。
在源码层面,这一行为与结构校验器的边界完全对应:正如 slide-dsl 所述,写入路径只检查 DSL结构schema(字段名、类型、必填字段、封闭对象),不检查标签、CSS、颜色格式、长度或几何边界——"guard rail catches shape, not meaning",本技能就是意义的来源。
对比度是一对,而不是一种颜色
命名这对组合
在改任何颜色之前,先说出将要叠放在一起的两样东西。文字是否可读是相对于它的直接背景而言的:位于形状上时是形状的fill;文本元素自身有fill时是它自己的fill;否则是页面背景。
哪个字段承载哪种颜色
| 墨色 | 字段 |
|---|---|
| 文本元素字形 | defaultColor,或内容中的内联color |
| 文本元素背景 | fill(未设置 = 页面透出) |
| 形状标签字形 | text.defaultColor |
| 形状主体 | fill |
| 公式 | latex 元素上的color |
| 线条 / 箭头 | line 元素上的color |
一次颜色修改就是对渲染器实际读取的那个字段的一次写入——文本用defaultColor或内容里的内联color,形状标签用text.defaultColor,latex 或 line 元素用color。先读源 JSON 并保留其内联 span。文本元素上的opacity会同时淡化字形和填充,因为它作用于整个盒子——它不是给活文字后面柔化背景的方式。
对比度目标与校准点
正文文字目标是≥ 4.5:1,24px 及以上的标题目标是≥ 3:1。本课件调色板有两个校准点:白色上的#333333约为 12:1,任何地方都安全;白色上的强调色#5b9bd5约为 3:1,能通过 32px 标题但通不过 16px 正文。这里始终有效的模式是浅色调填充配深色同色调文字——如#1e40af配#dbeafe、#166534配#dcfce7、#92400e配#fef3c7,每组约为 6-7:1。只改这样一对中的一半会破坏它;要么都改,要么都不改。
形状上的文字是一个对象
卡片内的标签不是独立元素——它的盒子是从形状派生出来的:
text.width = shape.width - 40 (每边 20px 内边距) text.height = 一个表格值 ≤ shape.height - 40 text.left = shape.left + (shape.width - text.width) / 2 text.top = shape.top + (shape.height - text.height) / 2中心点应在2px 内一致。所以移动形状总是两次编辑——先移动形状,再重新推导标签——而升到表格下一行的文字高度可能迫使卡片随之增高。经典的错误修复是给标签赋予形状自己的left/top,这会把它钉在左上角而不是居中。在底层,形状标签由ShapeText结构承载(content、defaultFontName、defaultColor、align均必填,见 element-schema.ts),水平对齐来自 HTML 内的text-align,垂直锚点才是align——这正是上面派生公式要解决的问题。
节奏,用精确数字
并行的事物用完全相同的值,而不是接近的值:一行三张卡片共享一个width、一个height、一个top和一个间距。人眼能分辨 5px 的差异,所以近似是可见的。当你删除一行中的一张卡片或向它复制一张时,要按这一行自身的算术重新分布所有卡片,而不是把新来者放到邻居旁边。
页面构建所依据的间距标准:
- 标题 → 副标题 30-40px;标题 → 正文 35-50px;段落块之间 20-30px;文字 ↔ 图片垂直 25-35px、水平 30-40px。
- 多列间距 40-60px。任何被连接箭头穿过的间距需要60-80px,否则箭头会落进相邻的盒子。
- 任何东西都不低于画布边缘 50px。
从清单诊断密度
盒子会告诉你真相,无需渲染:把内容元素按top排序,读间距。拥挤的页面表现为间距低于约 20px、底边缘接近 512;空旷的页面表现为一个簇和它下方 150px 的死空间。修复拥挤靠删词和合并元素,而不是把字号降到阶梯以下——正文降到 12px 的页面就是内容太多的页面。修复空旷靠把类型升一级并垂直重新居中这个块,而不是加填充物。
一种内容,一种元素
页面上有十种元素类型,它们不可互换。搞错这一点是导致幻灯片上渲染出字面源码的失败。
- 任何数学都是 latex 元素。文本元素或表格单元格里的 LaTeX 语法会渲染为原始字符串——学习者会看到
\frac{a}{b}。小的也一样(x^2、a/b)。 - latex 元素的渲染形式被缓存。把新源码写入该元素的
latex,服务器会重新渲染渲染器实际绘制的缓存html。用预览验证结果。这一机制在仓库中有明确的实现证据:apply.ts 会在 patch 改变某元素latex后调用renderLatexElementHtml(element.latex)重新生成html(渲染失败则删除html),除此之外文档中没有任何内容被触碰——这正是 slide-dsl 所称"整个写入路径中唯一的自动重写"。 - 表格单元格是纯文本。没有公式,没有标记。
- 代码元素接受纯文本行,按换行拆分,渲染为固定的浅色卡片,带自己的边框和标题栏——它不能被主题化成深色页面。默认字号 14px,高度必须覆盖 32px 的头部加每一行。
- line 元素的
width是描边粗细,不是长度。长度来自start/end。保持描边在 2-4(绝不超过 6):箭头是width × 3宽,所以width: 60会画出 180px 的箭头。 - 图片保持宽高比。同时改变
width和height;写新src不会触碰盒子,所以不同形状的图片需要重新推导盒子。
派生元素跟随其锚点
下划线、分隔线和高亮条都是形状,其几何从它们装饰的文字计算而来。移动或缩放文字,它们不会跟随——要重新计算:
- 标题下划线:
left = text.left + 10,width = text.width - 20,top = text.top + text.height + 8..12,height = 2..4。 - 章节分隔线:
width700-900,height1-2,上下留 25-35px 的净空。 - 高亮条:
left = text.left - 15,top = text.top + 0.1 × text.height,height = 0.8 × text.height,width3-6。
一条孤零零漂在被移动文字旁边的线,是粗心修补最显眼的标志之一。
层级就是数组顺序
元素按数组顺序绘制,靠后的在上。背景形状必须排在承载它的文字之前。当某物被另一物遮住时,修复方式是按你想要的顺序重写元素数组——绝不移动盒子来逃避重叠,也绝不删除背景层。在 JSON Pointer 写入模型中,这是唯一没有叶子可寻址的变更:你需要整体写入/content/canvas/elements,把所有元素原样带回并重新排序,id 集合和每个 id→类型配对必须原样返回(见 slide-dsl 的 restacking 规则)。
修补之后:检查清单
只检查你动过的元素,检查这些项:
- 在边距内——
left/top≥ 50,右边缘和底边缘 ≤ 950 / 512.5。 - 高度是内容中最大字号对应的表格值,且最长行低于
characters_per_line的 75%。 - 每个你改过的颜色仍与它背后的东西构成可读的一对。
- 形状上的文字对仍在 2px 内居中;并行元素仍共享精确值。
- 任何锚定在你移动过的内容上的装饰形状已随之移动。
- 文本或表格内容中没有 LaTeX,也没有原始标记。
- 文字读起来仍像幻灯片——关键词和短语,每行约 20 个词或 30 个汉字以内,没有口语化的完整句子,也没有以教师名字或角色署名的文字。想被朗读的散文属于该页的旁白(narration),不属于页面本身。
在可用的地方,把预览花在列表无法定夺的变更上:公式、密度判断、或你怀疑溢出的文字。
本技能在整个技能栈中的位置
本技能明确声明自己不是一个独立流程,而是page-clone与pro-editing的评判基准:
- slide-dsl是位于本技能之下的字段参考——每种元素类型的字段、哪个承载文字、什么值合法、渲染器对每个字段真正做什么。它说你可以写什么;本技能说什么值得写。需要字段名或合法值时加载它。
- page-clone是基于现有页面构建新页面的流程。它决定哪些元素是内容、哪些是骨架;本技能决定你放进内容的文字是否做得好。
- pro-editing是修订已存在页面的流程——该用哪个操作、多小的粒度、如何验证。本技能就是那个操作落地之后"做得好"的定义。
- stage-design仍然掌管整个课堂(stage)的构建。
硬性规则(Hard Rules)
- 任何东西永远不进入距边缘 50px 以内——重新计算数字,不要微调。
- 高度来自表格,每次文字变更后重新计算。
- 颜色是一对。绝不要单独改文字/背景对的一侧;修补上面列出的渲染器持有的颜色字段。
- 真实结构用真实 HTML——每行一个
<p>、用符号字符而不是<ul>、用内联font-size而不是标题标签。 - 公式是 latex 元素,且其渲染形态不跟随字符串修补——替换,而不是修补。
- 并行元素共享精确数字——从清单里复制它们。
- 先删词,再撑盒子。只能以 12px 容纳的页面就是内容太多的页面。
相关阅读
- 深入阅读字段手册 slide-dsl,掌握十种元素类型逐字段的合法值、优先级规则与 PPTX 导出的读写差异。
- 查看克隆页面的完整操作序列 page-clone 与修订页面的最小编辑纪律 pro-editing。
- 在源码中验证结构 schema:element-schema.ts(画布
viewportSize/viewportRatio、ShapeText与defaultColor/lineHeight/paragraphSpace等字段约束);验证 latex 重渲染机制:apply.ts。 - 如需了解页面如何在播放器与预览两种渲染器中呈现,参考 slide-dsl 的"Two renderers paint your page"章节——本技能的许多规则(如列表无符号、
paragraphSpace在播放中失效)正是这两种渲染器差异的直接推论。
【免费下载链接】OpenMAICOpen Multi-Agent Interactive Classroom — Get an immersive, multi-agent learning experience in just one click项目地址: https://gitcode.com/GitHub_Trending/op/OpenMAIC
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考