这个清单来自"一人公司"分享 PPT 的真实迭代过程。每一条都是踩过坑之后总结的,按重要性排序。
生成 PPT 前,先通读一遍;生成后,逐项自检。
现象:颜色、字体看起来像 Swiss,但标题跑到中间、图片不在网格上、页面结构和原始 22P 完全不是一套东西。
根因:生成时把 Swiss 当成风格包,自由组合了新的 P23/P24/自绘 SVG 页面,没有从原始参考 PPT 的 22 个登记版式里选。
做法:
references/swiss-layout-lock.mdS01-S22;新增首页/尾页只能使用 SWISS-COVER-ASCII / SWISS-CLOSING-ASCII<section class="slide"> 必须写 data-layout="Sxx"生成后必须运行:
node <SKILL_ROOT>/scripts/validate-swiss-deck.mjs path/to/index.html
校验会拦截:
data-layouts22-hero-21x9object-position:top center现象:最顶上的中文标题在页面中间,像一页自制海报,不再像原始 PPT。
做法:
S03/S09/S10 这类 statement/split 版式外,顶部标题必须贴原始模板的左上内容轴。S11 或 S17 的骨架,不要自写 4fr 8fr。现象:页眉 chrome-min 和底部 footer 都靠在 5vw 的边线上,但中间区域往内缩了一截,左右对不齐。
根因:.canvas-card 已经自带 padding:5.6vh 5vw 4.4vh。如果在主体区再写 padding:5vh 5vw 4vh,水平方向就变成 5vw + 5vw = 10vw,主体比 chrome-min 多内缩 5vw。
做法:
padding:0,只用 grid gap 控垂直间距.chrome-min{margin-bottom:48px} 提供,不要在主体顶部叠 margin-top / padding-topsplit 模式例外:.slide.split .canvas-card{padding:0},两个 .half 自己定 padding:5.6vh 3.6vw 4.4vh
<!-- ❌ 错:主体多缩了 5vw,左右对不齐 -->
<div class="canvas-card">
<div class="chrome-min">...</div>
<div style="flex:1;padding:5vh 5vw 4vh;...">主体</div>
</div>
<!-- ✅ 对 -->
<div class="canvas-card">
<div class="chrome-min">...</div>
<div style="flex:1;padding:0;display:grid;grid-template-rows:auto 1fr auto;gap:3vh">主体</div>
</div>
自检命令:grep "padding:.*5vw" index.html,如果命中 padding:Xvh 5vw Yvh 在 canvas-card 直系子元素里,就是错的(.half / 装饰层除外)。
现象:小标题(.t-meta / .t-cat)和大标题被挤在同一行,左侧一坨小字、右侧一坨大字,头部失去层级。
根因:grid-template-columns:auto 1fr 把两个本该上下叠的元素压成左右两列。
做法:
<!-- ❌ 错 -->
<div data-anim="head" style="display:grid;grid-template-columns:auto 1fr;gap:3vw;align-items:end">
<div class="t-meta">METHODOLOGY · 03</div>
<h2 class="h-xl-zh">为什么是 N+1</h2>
</div>
<!-- ✅ 对 -->
<div data-anim="head" style="display:flex;flex-direction:column;gap:1.4vh">
<div class="t-meta">METHODOLOGY · 03</div>
<h2 class="h-xl-zh">为什么是 N+1</h2>
</div>
例外:head 一行同时承载"左:kicker+大标题(自己上下叠)"和"右:小注脚",外层可以用 display:grid;grid-template-columns:1fr auto,但内层仍要保持 flex column。
现象:封面用 slide light 白底 + 黑字 + 一个大大的"01"——同时 chrome 角标已经写了 01 / 07,屏幕上出现两个"01",视觉重复;白底太普通,完全没有"开场打招呼"的仪式感。
根因:layouts-swiss.md 旧版默认推荐左 ink + 右 paper 对开,实操中容易写成"白底 + 黑大字 + 编号大字",失去 IKB 这个标志色的开场冲击。
做法(瑞士风必守):
<section class="slide accent">(满屏 IKB),不要 slide.light,也不要 slide.dark;在 .canvas-card 内第一个子元素插入 <canvas class="ascii-bg">(ASCII 字符呼吸场,模板自带 IIFE 自动激活).chrome-min 已经显示 01 / N,封面再放一个巨大的"01"=同义重复,直接删掉font-style:italic;font-weight:300,禁止用 color:var(--accent)——IKB 蓝压 IKB 蓝,人眼看不见任何强调slide.split 双半屏,左半 .half.b-accent + ASCII canvas(与封面色彩闭环),右半 paper 白底放 3 条 takeaway;第 03 条用 var(--accent) 上色,完成"开场全 IKB ↔ 收尾半 IKB"的色彩闭环<style> 里已经预设 mix-blend-mode:screen;opacity:.92,不要去动这个值min(11.6vw,19vh) ~ min(8vw,14vh)(遵守 Y ≥ X × 1.6 规则)自检命令:
grep -c "ascii-bg" index.html——封面 + 封底应至少命中 ≥ 2(各一个 canvas)grep -E '"slide accent"' index.html | head -1——封面应是 slide accent 而非 slide lightgrep "color:var(--accent)" index.html——若命中行同时含 font-style:italic 即危险信号(蓝压蓝),改为只 italic 不 accent;只有封底"03 takeaway"那一处用 var(--accent) 是合法的(此时背景是白色)min(Xvw, Yvh) 中 Y ≥ X × 1.6现象:在 16:9 标准屏(MacBook 13/14/16,常见显示器)打开,标题字号比预期小一截,整页内容显得空旷或缩水。
根因:1vw : 1vh ≈ 1.78,如果写 min(7vw, 10vh),在 16:9 屏 7vw = 12.46vh,会被 10vh 上限截断到 10vh,字号缩水 20%。
做法:推荐数值速查
| 用途 | 推荐 |
|---|---|
| h-hero 巨字宣言 | min(11.6vw, 19vh) |
| h-xl 章节标题 | min(7vw, 12vh) ~ min(7.4vw, 13vh) |
| 大数字 KPI | min(8.4vw, 14vh) |
| 中数字 / 编号 | min(4.6vw, 8.5vh) ~ min(5.6vw, 10vh) |
| 副标 | min(7.6vw, 13vh) |
自检命令:grep -E "font-size:min\([0-9.]+vw,\s*[0-9.]+vh\)" index.html,把所有命中的 X/Y 看一眼,任何 Y/X < 1.6 都改大。
现象:图片像普通 PPT 插图,圆角、阴影、比例混乱;多张截图高度不一,或 GPT-M 2.0 生成图自带标题/页脚,和页面 chrome 重复。
根因:瑞士风的图片不是装饰,而是 grid 里的证据块。没有先选原始版式和图片槽位,就会把任意图片硬塞进页面。
做法:
S22;多图用 S15/S16 的原始网格骨架改造21:9,并在 <img> 上写 data-image-slot="s22-hero-21x9"object-position:center 35% 或 center center,不要用 top center 截人脸.frame-img;不要 border-radius / box-shadow.fit-contain;若已按槽位重生成,必须用对应比例类铺满容器,例如 .frame-img.r-21x9,不能再用固定短高度把图片缩小自检命令:
grep -E "frame-img.*border-radius|box-shadow" index.html——命中就删grep -n "data-image-slot" index.html——每张本地图片都应有槽位声明现象:图片 caption、脚注、timeline 下方 label、底部 KPI 被分页小方块挡住,或者视觉上贴得太近。
根因:#nav 固定在 bottom:2vh,如果主体内容用 align-self:end / align-items:end / margin-top:auto 贴到底,最低处会进入分页区域。
做法:
3vh 呼吸空间.swiss-img-split.align-image-bottom,模板已内置 --nav-safe-bottom:8vh.nav-safe-bottom 或 .nav-safe-bottom-tightbottom:2vh / bottom:0 放说明文字;这会和 nav 抢位置自检:
grep -E "align-items:end|align-self:end|bottom:0|bottom:2vh|margin-top:auto" index.html,命中后逐个确认是否有 nav safe zone现象:生成页看起来像瑞士风,但和原始参考 PPT 的实际字重、间距、时间线、卡片密度不一致;越迭代越偏离参考。
根因:把新增图片版式或实验结构写成了全局样式修改,或无意改动了原始基座类,例如 .h-hero / .h-xl 字重、.tl-node 列宽、.duo-compare 间距。
做法:
/Users/guohao/Documents/op7418的仓库/项目/Thin-Harness-Fat-Skills/ppt/index.html 是 Swiss 主题的 golden source,但要以实际页面用法为准,不要只看未使用的 CSS helperfont-weight:200,强调词/数字用 300;.h-hero / .h-xl / .h-hero-zh / .h-xl-zh 在本模板里必须保持轻字重,不要恢复成 800/900assets/template-swiss.html,先做原始参考对比;可接受差异只应是 ASCII 类、S22 图片定位类、轻字重标题 helper 和已知动效修复自检命令:
compare-swiss-base.mjs,确认输出里 missing in template: 0现象:代码看起来类名正确,但实际页面拥挤、图文关系不对、可选组件堆太多,或者用了不适合内容的版式。
做法:
现象:直接把 layouts.md 的骨架粘到新 HTML,结果样式全部丢失——大标题变成非衬线、数据大字报字体小得像正文、pipeline 多页糊成一坨、图片堆到浏览器底部。
根因:如果当前模板的 <style> 里没有这些类的定义,浏览器就 fallback 到默认样式。
做法:
Read 当前风格对应模板:风格 A 读 assets/template.html,风格 B 读 assets/template-swiss.html,确认 layouts 里用到的类都已定义h-hero / h-xl / h-sub / h-md / lead / meta-row / stat-card / stat-label / stat-nb / stat-unit / stat-note / pipeline-section / pipeline-label / pipeline / step / step-nb / step-title / step-desc / grid-2-7-5 / grid-2-6-6 / grid-2-8-4 / grid-3-3 / frame / img-cap / callout-src<style> 里补上,不要在每页 inline 重写现象:在中式杂志风格里用 emoji(🎯 💡 ✅)会立刻破坏格调。
做法:用 Lucide 图标库,CDN 方式引用:
<script src="https://unpkg.com/lucide@latest/dist/umd/lucide.min.js"></script>
...
<i data-lucide="target" class="ico-md"></i>
...
<script>lucide.createIcons();</script>
常用图标名:target / palette / search-check / compass / share-2 / crown / check-circle / x-circle / plus / arrow-right / grid-2x2 / network
现象:用 aspect-ratio 撑图,网格会在父容器不足时堆叠或切掉图片关键信息(比如截图上部的标题栏)。
做法:图片容器用固定 height + overflow hidden,图片走 object-fit:cover + object-position:top:
<figure class="frame-img" style="height:26vh">
<img src="screenshot.png">
</figure>
CSS 里 .frame-img img 已经预设 object-position:top,只裁底。
绝不用这种写法(会在网格中撑破容器):
<!-- 坏例 -->
<figure class="frame-img" style="aspect-ratio: 16/9">...</figure>
例外:单张主视觉(非网格内)可以用 aspect-ratio + max-height,因为父容器会兜底。
现象:所有 light 页面背景都像蒙了一层灰,甚至 hero light 也灰。
根因:JS 根据 slide 的主题切换两张 canvas 的 opacity。如果整个 deck 开场是 hero dark,而没有任何机制能把 bg 切到 light,body 永远不加 light-bg 类,canvas#bg-dark 一直在上面。
做法:
go() 函数已改为从 classList 推断主题(light / dark),所以 slide 必须明确带 light 或 dark 类。不要漏写,更不要用其他自定义主题名hero light / hero dark,正文页用 light / dark。只写 hero 不带主题色是坏的light-bg现象:除封面 hero dark 外,其余所有页面默认写 light——视觉平淡,没有呼吸感,白花花一片。
根因:layouts.md 的骨架默认全写 light,如果只是粘贴骨架不调整主题,就会全亮。
做法:
hero dark / hero light / light / dark 中的哪一个,对齐后再写代码hero dark + ≥1 hero light;不能全是 light 正文页——必须有 dark 正文页light / dark 交替light(截图/数字/流程需要亮底)hero darkhero dark 与 hero light 交替grep 'class="slide' index.html,目视确认节奏有交错现象:左上角 .chrome 写"Design First · 设计先行",同一页里 .kicker 又写"Phase 01 · 设计阶段"——同义翻译,AI 味浓。
做法:
现象:中文大标题字号设太大(比如 13vw),结果每行只容 1 个字,强制换行非常难看。
做法:
h-hero(最大):10vw,且标题长度 ≤ 5 字h-xl(次大):6vw-7vw<br> 手工断行,不要依赖自动换行white-space:nowrap示例:我不是程序员。(6 字)用 h-xl 7.2vw + nowrap,一行排完。
做法:
所有字体用 Google Fonts CDN 引入,模板里已预设。
align-self:end 贴底现象:左文右图布局里,为了让右列图片和左列 callout 底部对齐,在 <figure> 上加 align-self:end。结果:
align-self 完全失效,图片掉到文档流最下面被浏览器底栏遮挡.foot 和 #nav 圆点遮挡做法:
.frame.grid-2-7-5(或 .grid-2-6-6/.grid-2-8-4)<figure class="frame-img r-16x10"> 或 <figure class="frame-img r-4x3"> 自然贴顶即可justify-content:space-between,不要动右列margin-top:7vh 到 9vh,让图片跟正文内容区对齐现象:aspect-ratio: 2592/1798 这种从原图复制的比例,在不同屏幕下撑出奇怪的空白或溢出。
做法:无论原图什么比例,占位器固定用标准比例 16/10 / 4/3 / 3/2 / 1/1 / 16/9。图片自动 object-fit:cover + object-position:top,顶部不裁,底部裁掉一点无伤大雅。
现象:为了"高级感"加了强阴影或黑框,瞬间变成商务 PPT。
做法:最多 1-4px 的微圆角 + 极淡的底噪(已在模板里)。不要加 box-shadow,不要加 border(除非 1px 极淡的灰)。
推荐节奏(25-30 页):
Hero Cover → Act Divider (hero) → 3-4 pages non-hero → Act Divider (hero)
→ 4-5 pages non-hero → Hero Question → ... → Hero Close
连续 2 页以上 hero 会让人疲劳,连续 4 页以上 non-hero 会让节奏死。
大字报(big numbers / hero question)和密集页(pipeline / image grid)交替出现,听众眼睛才不累。
现象:一会儿写 "Skills",一会儿写 "技能",一会儿写 "薄承载厚技能",全篇不一致。
做法:
用 XX / 总页数 的格式(比如 05 / 27)。不要在右上角加动态页码(会和 .chrome 重复)。
现象:生成后打开浏览器,翻页时内容直接"啪"地出来,没有任何节奏感——杂志风完全靠排版硬撑,少了层级展开的仪式感。
根因:完全没给任何元素加 data-anim,Motion One 脚本找不到可播的元素,整页静态出现。
做法:
data-anim<section> 上加对应 data-animate
data-animate="quote" + 每行 <span data-anim="line" style="display:block">data-animate="directional" + 左列 data-anim="left" + 右列 data-anim="right"data-animate="pipeline" + 每 step 加 data-anim="step"data-anim)自检:生成后 grep -c 'data-anim' index.html,应该数十条以上。如果只有个位数,一定漏标了。
现象:流水线页直接全部淡入,失去"一步步讲"的节奏,但切到下一页时又只能往前翻,没法回到上一个 step。
做法:Layout 6 的 <section> 必须加 data-animate="pipeline"。演示时按 →/空格/滚轮下滑可以逐个点亮 step,全部点亮之后再按 → 才会翻到下一页。这个节奏是刻意的,不是 bug。
dark hero:遮罩 12-15%(WebGL 明显透出) light hero:遮罩 16-20%(WebGL 隐约可见,不抢字) 普通 light/dark 页:遮罩 92-95%(几乎不透)
如果页面文字非常少(hero question),遮罩可以再薄些;如果正文密集,必须加厚遮罩确保可读。
现象:Spiral Vortex、径向涟漪在 light 主题下太显眼,像 Windows 98 屏保。
做法:light hero 用 FBM 域扭曲驱动的无中心流动,底色保持银/纸色(接近 #F0F0F0 / #FBF8F3),彩虹偏色 subtle(0.05 以下)。
Dark hero 可以用 Holographic Dispersion(钛金色散)等带中心结构的 shader,因为黑底能容纳更多视觉信息。
justify-content:space-between:标题贴顶,引用框贴底align-self:endmargin-top:7vh 到 9vhalign-items:start(不是 center / end)margin-top:6vh 到 8vh.frame-img 用同一个固定高度类,如 .h-16 / .h-18 / .h-22,不要用同一个超宽容器硬塞min(5.8vw,10.2vh) 起步,不要直接用英文页的 6.8vw-7vwmin(5.2vw,9.2vh).frame-img 和图片本身都不要圆角、阴影或消费 app 式卡片感。图片放在 images/ 文件夹下,HTML 里用相对路径 images/xxx.png,不要用绝对路径。
.chrome 里写死JS 会动态算总页数并扩展底部翻页圆点,但 .chrome 里的 XX / N 是写死的。加页/删页时要手工改 N。
模板默认支持:← → / 滚轮 / 触屏滑动 / 底部圆点 / Home·End。不要删 JS 里的导航逻辑。
height:100vh 硬设,用 min-height:80vh100vh 会让内容刚好卡满屏幕,但浏览器工具栏、标签栏会吃掉一部分高度,导致内容溢出。用 min-height:80vh + align-content:center 更稳。
生成完 PPT 后,逐项对照这个清单(勾一下):
预检(生成前)
□ 已读过 template.html 的 <style>,确认所需类都存在
□ 已决定每页用哪个 Layout(1-10)
□ 已画出"主题节奏表":每页明确 hero dark / hero light / light / dark
□ 节奏表满足硬规则:无连续 3 页同主题 / 有 ≥1 hero dark + ≥1 hero light(8 页以上) / 至少有 1 个 dark 正文页
□ `<title>` 已改为实际 deck 标题(grep "[必填]" 应无结果)
□ 瑞士风:封面是 `slide accent` 满屏 IKB + `<canvas class="ascii-bg">`(不是 `slide light` 白底)
□ 瑞士风:封底是 `slide split` + 左 `b-accent` + ASCII canvas / 右 paper 3 条 takeaway,第 03 条用 var(--accent)
□ 瑞士风:`grep -c "ascii-bg" index.html` ≥ 2(封面 + 封底各一)
□ 瑞士风:封面没有"01"等大编号(chrome 已显示 01/N,不要重复)
□ 瑞士风:IKB 背景上的强调字用 `font-style:italic`,禁止用 `color:var(--accent)`(蓝压蓝)
内容
□ 每一幕的页数比例合理(不会头重脚轻)
□ 没有使用 emoji 作图标
□ Skills / Harness 等术语用法统一
□ 每页的 kicker + 标题 + 正文 三级信息清晰
排版
□ 所有大标题没有出现 1 字 1 行的换行
□ 图片网格用 height:Nvh 而非 aspect-ratio
□ 图片只裁底部,顶部和左右完整
□ 衬线/非衬线字体分工符合模板
□ Pipeline 多组之间有明显分隔
视觉
□ hero 页和 non-hero 页交替
□ WebGL 背景在 hero 页可见
□ 图片有微弱圆角
□ 没有沉重的阴影和边框
交互
□ ← → 翻页正常
□ 底部圆点数量与总页数匹配
□ chrome 里的页码和实际页号一致
□ ESC 键触发索引视图(如果保留)
□ B 键触发静态/低功耗模式,右下角提示在 `B 静态` / `B 动态` 之间切换
动效
□ `assets/motion.min.js` 存在(本地兜底)
□ 低功耗模式下 WebGL/ASCII canvas 不再挂 RAF 循环,当前页内容仍全部可见
□ 翻页时内容逐个淡入,不是"啪"一下全出
□ 大引用页 `<section>` 带 `data-animate="quote"`,每行 `<span data-anim="line">`
□ Before/After 对比页 `<section>` 带 `data-animate="directional"`,左右列标 left/right
□ Pipeline 页 `<section>` 带 `data-animate="pipeline"`,每 step 标 data-anim="step"
□ `grep -c 'data-anim' index.html` 数量 ≥ 页数 × 3(平均每页 3 个以上标记)
全勾完,才是合格的 PPT。