mirror of
https://github.com/aculix/huashu-design.git
synced 2026-10-27 07:15:54 +00:00
init: huashu-design skill v1.0
花叔设计工作台 —— AI 驱动的 HTML 设计工作流,支持 Claude Code / Codex / Cursor / Trae / OpenClaw / Hermes Agent 等任意 skill-compatible agent。 四条主干能力: - HTML 高保真视觉产出(原型/App/幻灯片/动画/变体/信息图) - 设计方向顾问 Fallback(5 流派 × 20 设计哲学 × 24 预制 showcase) - Junior Designer 工作流(先 show 假设再迭代) - 专家级 5 维度评审(哲学/层级/执行/功能/创新) 工程工具链: - HTML → 25fps/60fps MP4 + palette GIF,含 6 首场景化 BGM - HTML → PDF / PPTX 导出 - Playwright 截图 + 控制台错误验证 - iOS/Android/macOS/Browser 设备边框 + Stage/Sprite 动画引擎 初版包含 SKILL.md + 13 份 references + 7 个 scripts + 18 类 assets。 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
commit
7d7bab4a82
89 files changed
+19270
No files matched your search
@@ -0,0 +1,429 @@
|
||||
# Slide Decks:HTML幻灯片制作规范
|
||||
|
||||
做幻灯片是设计工作的高频场景。这份文档说明怎么做好HTML幻灯片。
|
||||
|
||||
**和huashu-slides skill的区别**:huashu-slides focus on「AI演示文稿全流程」(含PPT导出);本文档focus on「用HTML本身作为呈现媒介」的设计方法论。两者可以配合使用——用这里的方法做高质量的HTML deck,再用huashu-slides导出成PPTX。
|
||||
|
||||
---
|
||||
|
||||
## 🛑 先定架构:单文件 还是 多文件?
|
||||
|
||||
**这个选择是做幻灯片的第一步,错了会反复踩坑。先读完这一节再动手。**
|
||||
|
||||
### 两种架构对比
|
||||
|
||||
| 维度 | 单文件 + `deck_stage.js` | **多文件 + `deck_index.html` 拼接器** |
|
||||
|------|--------------------------|--------------------------------------|
|
||||
| 代码结构 | 一个 HTML,所有 slide 是 `<section>` | 每页独立 HTML,`index.html` 用 iframe 拼接 |
|
||||
| CSS 作用域 | ❌ 全局,一页的样式可能影响所有页 | ✅ 天然隔离,iframe 各自一片天 |
|
||||
| 验证粒度 | ❌ 要 JS goTo 才能切到某页 | ✅ 单页文件双击就能在浏览器看 |
|
||||
| 并行开发 | ❌ 一个文件,多 agent 改会冲突 | ✅ 多 agent 可并行做不同页,零冲突 merge |
|
||||
| 调试难度 | ❌ 一处 CSS 出错,全 deck 翻车 | ✅ 一页出错只影响自己 |
|
||||
| 内嵌交互 | ✅ 跨页共享状态很简单 | 🟡 iframe 间需 postMessage |
|
||||
| 打印 PDF | ✅ 内置 | ✅ 拼接器 beforeprint 遍历 iframe |
|
||||
| 键盘导航 | ✅ 内置 | ✅ 拼接器内置 |
|
||||
|
||||
### 选哪个?(决策树)
|
||||
|
||||
```
|
||||
│ 问:deck 预计有多少页?
|
||||
├── ≤10 页、需要 in-deck 动画或跨页交互、pitch deck → 单文件
|
||||
└── ≥10 页、学术讲座、课件、长 deck、多 agent 并行 → 多文件(推荐)
|
||||
```
|
||||
|
||||
**默认走多文件路径**。它不是「备选」,是**长 deck 和团队协作的主路径**。原因:单文件架构的每一个优势(键盘导航、打印、scale)多文件都有,而多文件的作用域隔离和可验证性是单文件补不回来的。
|
||||
|
||||
### 为什么这条规则这么硬?(真实事故记录)
|
||||
|
||||
单文件架构曾经在 AI心理学讲座 deck 制作中连踩四坑:
|
||||
|
||||
1. **CSS 特异性覆盖**:`.emotion-slide { display: grid }` (特异性 10) 干翻 `deck-stage > section { display: none }` (特异性 2),导致所有页同时渲染叠加。
|
||||
2. **Shadow DOM slot 规则被外层 CSS 压制**:`::slotted(section) { display: none }` 挡不住 outer rule 的覆盖,sections 不肯隐藏。
|
||||
3. **localStorage + hash 导航竞态**:刷新后不是跳到 hash 位置,而是停在 localStorage 记录的旧位置。
|
||||
4. **验证成本高**:必须 `page.evaluate(d => d.goTo(n))` 才能截某页,比直接 `goto(file://.../slides/05-X.html)` 慢一倍,还常报错。
|
||||
|
||||
全部根因是**单一全局命名空间**——多文件架构从物理层面把这些问题消除了。
|
||||
|
||||
---
|
||||
|
||||
## 路径 A(默认):多文件架构
|
||||
|
||||
### 目录结构
|
||||
|
||||
```
|
||||
我的Deck/
|
||||
├── index.html # 从 assets/deck_index.html 复制来,改 MANIFEST
|
||||
├── shared/
|
||||
│ ├── tokens.css # 共享设计 token(色板/字号/常用 chrome)
|
||||
│ └── fonts.html # <link> 引入 Google Fonts(每页 include)
|
||||
└── slides/
|
||||
├── 01-cover.html # 每个文件都是完整 1920×1080 HTML
|
||||
├── 02-agenda.html
|
||||
├── 03-problem.html
|
||||
└── ...
|
||||
```
|
||||
|
||||
### 每张 slide 的模板骨架
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>P05 · Chapter Title</title>
|
||||
<link href="https://fonts.googleapis.com/css2?family=..." rel="stylesheet">
|
||||
<link rel="stylesheet" href="../shared/tokens.css">
|
||||
<style>
|
||||
/* 这一页独有的样式。用任何 class 名都不会污染别的页。*/
|
||||
body { padding: 120px; }
|
||||
.my-thing { ... }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- 1920×1080 的内容(由 body 的 width/height 在 tokens.css 里锁定)-->
|
||||
<div class="page-header">...</div>
|
||||
<div>...</div>
|
||||
<div class="page-footer">...</div>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
**关键约束**:
|
||||
- `<body>` 就是画布,直接在上面布局。不要包 `<section>` 或其他 wrapper。
|
||||
- `width: 1920px; height: 1080px` 由 `shared/tokens.css` 里的 `body` 规则锁定。
|
||||
- 引 `shared/tokens.css` 共享设计 token(色板、字号、page-header/footer 等)。
|
||||
- 字体 `<link>` 每页自己写(fonts 单独 import 不贵,且保证每页独立可打开)。
|
||||
|
||||
### 拼接器:`deck_index.html`
|
||||
|
||||
**直接从 `assets/deck_index.html` 复制**。你只需要改一处——`window.DECK_MANIFEST` 数组,按顺序列出所有 slide 文件名和人类可读标签:
|
||||
|
||||
```js
|
||||
window.DECK_MANIFEST = [
|
||||
{ file: "slides/01-cover.html", label: "封面" },
|
||||
{ file: "slides/02-agenda.html", label: "目录" },
|
||||
{ file: "slides/03-problem.html", label: "问题陈述" },
|
||||
// ...
|
||||
];
|
||||
```
|
||||
|
||||
拼接器已内置:键盘导航(←/→/Home/End/数字键/P 打印)、scale + letterbox、右下计数器、localStorage 记忆、hash 跳页、打印模式(遍历 iframe 按页输出 PDF)。
|
||||
|
||||
### 单页验证(这是多文件架构的杀手级优势)
|
||||
|
||||
每张 slide 都是独立 HTML。**做完一张就在浏览器双击打开看**:
|
||||
|
||||
```bash
|
||||
open slides/05-personas.html
|
||||
```
|
||||
|
||||
Playwright 截图也是直接 `goto(file://.../slides/05-personas.html)`,不需要 JS 跳页,也不会被别的页的 CSS 干扰。这让「改一点验一点」的工作流成本接近零。
|
||||
|
||||
### 并行开发
|
||||
|
||||
把每张 slide 的任务拆给不同 agent,同时跑——HTML 文件彼此独立,merge 时没有冲突。长 deck 用这种并行方式能把制作时间压到 1/N。
|
||||
|
||||
### `shared/tokens.css` 该放什么
|
||||
|
||||
只放**真正跨页共用**的东西:
|
||||
|
||||
- CSS 变量(色板、字号阶、间距阶)
|
||||
- `body { width: 1920px; height: 1080px; }` 这样的 canvas 锁定
|
||||
- `.page-header` / `.page-footer` 这种每页都用一模一样的 chrome
|
||||
|
||||
**不要**把单页的布局 class 塞进来——那会退化回单文件架构的全局污染问题。
|
||||
|
||||
---
|
||||
|
||||
## 路径 B(小 deck):单文件 + `deck_stage.js`
|
||||
|
||||
适用于 ≤10 页、需要跨页共享状态(比如一个 React tweaks 面板要操控所有页)、或者做 pitch deck demo 这种要求极度紧凑的场景。
|
||||
|
||||
### 基本用法
|
||||
|
||||
1. 从 `assets/deck_stage.js` 读取内容,嵌入 HTML 的 `<script>`(或 `<script src="deck_stage.js">`)
|
||||
2. 在 body 里用 `<deck-stage>` 包 slide:
|
||||
|
||||
```html
|
||||
<deck-stage>
|
||||
<section>
|
||||
<h1>Slide 1</h1>
|
||||
</section>
|
||||
<section>
|
||||
<h1>Slide 2</h1>
|
||||
</section>
|
||||
</deck-stage>
|
||||
```
|
||||
|
||||
### ⚠️ 单文件架构的 CSS 陷阱(务必阅读)
|
||||
|
||||
单文件架构最常见的坑——**`display` 属性被单页样式偷走**。
|
||||
|
||||
如果你给某张 slide 的样式写了 `display: flex/grid`:
|
||||
|
||||
```css
|
||||
.emotion-slide { display: grid; } /* 特异性: 10 */
|
||||
```
|
||||
|
||||
它会压过 deck 级的「隐藏非 active 页」规则:
|
||||
|
||||
```css
|
||||
deck-stage > section { display: none; } /* 特异性: 2 */
|
||||
```
|
||||
|
||||
结果所有 slide 同时渲染叠加。
|
||||
|
||||
**修复模式**(写 deck 时必做):
|
||||
|
||||
```css
|
||||
/* ✅ 用 :not(.active) + !important 锁死「非激活即隐藏」 */
|
||||
deck-stage > section:not(.active) {
|
||||
display: none !important;
|
||||
}
|
||||
```
|
||||
|
||||
特异性+权重双保险,单页 layout class 的 `display: grid/flex` 就不会影响可见性。
|
||||
|
||||
另一个替代方案:**把单页的 flex/grid 写到内部 wrapper div 上**,section 本身只管 `display: block/none`。
|
||||
|
||||
### 自定义尺寸
|
||||
|
||||
```html
|
||||
<deck-stage width="1080" height="1920">
|
||||
<!-- 9:16 竖版 -->
|
||||
</deck-stage>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Slide Labels
|
||||
|
||||
Deck_stage 和 deck_index 都会给每页打标签(计数器显示)。给它们**更有意义**的 label:
|
||||
|
||||
**多文件**:在 `MANIFEST` 里写 `{ file, label: "04 问题陈述" }`
|
||||
**单文件**:在 section 上加 `<section data-screen-label="04 Problem Statement">`
|
||||
|
||||
**关键:Slide 编号从 1 开始,不要从 0**。
|
||||
|
||||
用户说"slide 5"时,他指的是第 5 张,永远不是数组位置 `[4]`。人类不说 0-indexed。
|
||||
|
||||
---
|
||||
|
||||
## Speaker Notes
|
||||
|
||||
**默认不加**,只在用户明确要求时才加。
|
||||
|
||||
加了 speaker notes 你就可以把 slide 上的文字减少到最小,focus on impactful visuals——notes 承载完整 script。
|
||||
|
||||
### 格式
|
||||
|
||||
**多文件**:在 `index.html` 的 `<head>` 里写:
|
||||
|
||||
```html
|
||||
<script type="application/json" id="speaker-notes">
|
||||
[
|
||||
"第1张的 script...",
|
||||
"第2张的 script...",
|
||||
"..."
|
||||
]
|
||||
</script>
|
||||
```
|
||||
|
||||
**单文件**:同上位置。
|
||||
|
||||
### Notes 写作要点
|
||||
|
||||
- **完整**:不是提纲,是真要讲的话
|
||||
- **对话式**:像平时说话,不是书面语
|
||||
- **对应**:数组第 N 个对应第 N 张 slide
|
||||
- **长度**:200-400 字最佳
|
||||
- **情绪线**:标注重音、停顿、强调点
|
||||
|
||||
---
|
||||
|
||||
## Slide 设计模式
|
||||
|
||||
### 1. 建立一个系统(必做)
|
||||
|
||||
探索完 design context 后,**先口头说你要用的系统**:
|
||||
|
||||
```markdown
|
||||
Deck系统:
|
||||
- 背景色:最多2种(90% 白 + 10% 深色 section divider)
|
||||
- 字型:display 用 Instrument Serif,body 用 Geist Sans
|
||||
- 节奏:section divider 用 full-bleed 彩色 + 白字,普通 slide 白底
|
||||
- 图像:hero slide 用 full-bleed 照片,data slide 用 chart
|
||||
|
||||
我按这个系统做,有问题告诉我。
|
||||
```
|
||||
|
||||
用户确认后再往下做。
|
||||
|
||||
### 2. 常用 slide layouts
|
||||
|
||||
- **Title slide**:纯色背景 + 巨大标题 + 副标题 + 作者/日期
|
||||
- **Section divider**:彩色背景 + 章节号 + 章节标题
|
||||
- **Content slide**:白底 + 标题 + 1-3 bullet points
|
||||
- **Data slide**:标题 + 大图表/数字 + 简短说明
|
||||
- **Image slide**:full-bleed 照片 + 底部小 caption
|
||||
- **Quote slide**:留白 + 巨大 quote + attribution
|
||||
- **Two-column**:左右对比(vs / before-after / problem-solution)
|
||||
|
||||
一个 deck 里最多用 4-5 种 layout。
|
||||
|
||||
### 3. Scale(再次强调)
|
||||
|
||||
- 正文最小 **24px**,理想 28-36px
|
||||
- 标题 **60-120px**
|
||||
- Hero 字 **180-240px**
|
||||
- 幻灯片是给 10 米外看的,字要够大
|
||||
|
||||
### 4. 视觉节奏
|
||||
|
||||
Deck 需要 **intentional variety**:
|
||||
|
||||
- 颜色节奏:大部分白底 + 偶尔彩色 section divider + 偶尔 dark 片段
|
||||
- 密度节奏:几张 text-heavy 的 + 几张 image-heavy 的 + 几张 quote 留白
|
||||
- 字号节奏:正常标题 + 偶尔巨型 hero 文字
|
||||
|
||||
**不要每张 slide 长一样**——那是 PPT 模板,不是设计。
|
||||
|
||||
### 5. 空间呼吸(数据密集页必读)
|
||||
|
||||
**新手最容易踩的坑**:把所有能放的信息都塞进一页。
|
||||
|
||||
信息密度 ≠ 有效信息传达。学术/演讲类 deck 尤其要克制:
|
||||
|
||||
- 列表/矩阵页:不要把 N 个元素都画成同一大小。用 **主次分层**——今天要聊的 5 个放大做主角,剩下 16 个缩小做背景 hint。
|
||||
- 大数字页:数字本身是视觉主角。周围的 caption 不要超过 3 行,否则观众眼球来回跳。
|
||||
- 引用页:引语和 attribution 之间要有留白隔开,不要贴在一起。
|
||||
|
||||
对照「数据是不是主角」「文字有没有挤在一起」两条自我审查,改到留白让你有点不安为止。
|
||||
|
||||
---
|
||||
|
||||
## 打印为 PDF
|
||||
|
||||
**多文件**:`deck_index.html` 已处理 `beforeprint` 事件,按页输出 PDF。
|
||||
|
||||
**单文件**:`deck_stage.js` 同样处理。
|
||||
|
||||
打印样式已写好,不需要额外写 `@media print` CSS。
|
||||
|
||||
---
|
||||
|
||||
## 导出为 PPTX / PDF(自助脚本)
|
||||
|
||||
HTML 优先是第一公民。但用户经常需要 PPTX/PDF 交付。提供两个通用脚本,**任何多文件 deck 都能用**,位于 `scripts/` 下:
|
||||
|
||||
### `export_deck_pdf.mjs` — 导出矢量 PDF(推荐)
|
||||
|
||||
```bash
|
||||
node scripts/export_deck_pdf.mjs --slides <slides-dir> --out deck.pdf
|
||||
```
|
||||
|
||||
**特点**:
|
||||
- 文字**保留矢量**(可复制、可搜索)
|
||||
- 视觉 100% 保真(Playwright 内嵌 Chromium 渲染后打印)
|
||||
- **不需要改 HTML 任何一个字**
|
||||
- 每个 slide 独立 `page.pdf()`,再用 `pdf-lib` 合并
|
||||
|
||||
**依赖**:`npm install playwright pdf-lib`
|
||||
|
||||
**限制**:PDF 不能再编辑文字——要改回到 HTML 改。
|
||||
|
||||
### `export_deck_pptx.mjs` — 导出 PPTX(两种模式)
|
||||
|
||||
```bash
|
||||
# 图片铺底(视觉 100% 保真,不可编辑文字)
|
||||
node scripts/export_deck_pptx.mjs --slides <dir> --out deck.pptx --mode image
|
||||
|
||||
# 每个文本独立文本框(可编辑,但字体会回落)
|
||||
node scripts/export_deck_pptx.mjs --slides <dir> --out deck.pptx --mode editable
|
||||
```
|
||||
|
||||
| 模式 | 视觉保真 | 文字可编辑 | 工作原理 | 限制 |
|
||||
|------|---------|----------|---------|------|
|
||||
| `image` | ✅ 100% | ❌ | Playwright 截图 → pptxgenjs addImage | 文字变图片 |
|
||||
| `editable` | 🟡 ~70% | ✅ | html2pptx 提取每个文本框 | 见下方约束 |
|
||||
|
||||
**editable 模式的硬性约束**(用户 HTML 必须满足,否则该页 skip):
|
||||
- 所有文字必须在 `<p>`/`<h1>`-`<h6>`/`<ul>`/`<ol>` 里(禁止裸文本 div)
|
||||
- `<p>`/`<h*>` 标签自身不能有 background/border/shadow(放外层 div)
|
||||
- 不用 `::before`/`::after` 插入装饰文字(伪元素提不出来)
|
||||
- inline 元素(span/em/strong)不能有 margin
|
||||
- 不用 CSS gradient(不可渲染)
|
||||
- div 不用 `background-image`(用 `<img>`)
|
||||
|
||||
脚本已内置**自动预处理器**——把 "叶子 div 里的裸文本" 自动包成 `<p>`(保留 class)。这解决了最常见的违规(裸文本)。但其他违规(p 上有 border、span 上有 margin 等)仍需 HTML 源头合规。
|
||||
|
||||
**editable 模式的另一个 caveat——字体回落**:
|
||||
- Playwright 用 webfont 测量 text-box 尺寸;PowerPoint/Keynote 用本机字体渲染
|
||||
- 两者不同时会有**溢出或错位**——每页都要肉眼过
|
||||
- 建议目标机器装好 HTML 里用的字体,或 fallback 到 `system-ui`
|
||||
|
||||
### 从一开始就让 HTML 对导出友好
|
||||
|
||||
对性能最稳的 deck:**从写 HTML 时就按 editable 模式的约束写**。这样 `--mode editable` 可以直接全部 pass。额外成本不大:
|
||||
|
||||
```html
|
||||
<!-- ❌ 不好 -->
|
||||
<div class="title">关键发现</div>
|
||||
|
||||
<!-- ✅ 好(p 包裹,class 继承) -->
|
||||
<p class="title">关键发现</p>
|
||||
|
||||
<!-- ❌ 不好(border 在 p 上) -->
|
||||
<p class="stat" style="border-left: 3px solid red;">41%</p>
|
||||
|
||||
<!-- ✅ 好(border 在外层 div) -->
|
||||
<div class="stat-wrap" style="border-left: 3px solid red;">
|
||||
<p class="stat">41%</p>
|
||||
</div>
|
||||
```
|
||||
|
||||
### 何时选哪个
|
||||
|
||||
| 场景 | 推荐 |
|
||||
|------|------|
|
||||
| 给主办方/档案存档 | **PDF**(通用、高保真、文字可搜) |
|
||||
| 发给协作者让他们微调文字 | **PPTX editable**(接受字体回落) |
|
||||
| 要现场演讲、不改内容 | **PDF** 或 **PPTX image** |
|
||||
| HTML 是首选呈现媒介 | 直接浏览器播放,导出只是备份 |
|
||||
|
||||
## 导出为可编辑 PPTX 的深度路径(仅长期项目)
|
||||
|
||||
如果你的 deck 会长期维护、反复修改、团队协作——建议**一开始就按 html2pptx 约束写 HTML**,让 `--mode editable` 稳定通过。详见 `huashu-slides` skill 的 `references/prompt-templates.md` 第 2 节(4 条硬性约束)。
|
||||
|
||||
---
|
||||
|
||||
## 常见问题
|
||||
|
||||
**多文件:iframe 里的页打不开 / 白屏**
|
||||
→ 检查 `MANIFEST` 的 `file` 路径是否相对 `index.html` 正确。用浏览器 DevTools 看 iframe 的 src 能否直接访问。
|
||||
|
||||
**多文件:某页样式和别页冲突**
|
||||
→ 不可能(iframe 隔离)。如果感觉冲突,那是缓存——Cmd+Shift+R 强刷。
|
||||
|
||||
**单文件:多 slide 同时渲染叠加**
|
||||
→ CSS 特异性问题。看上面「单文件架构的 CSS 陷阱」一节。
|
||||
|
||||
**单文件:缩放看起来不对**
|
||||
→ 检查是否所有 slide 直接挂在 `<deck-stage>` 下作为 `<section>`。中间不能包 `<div>`。
|
||||
|
||||
**单文件:想跳到特定 slide**
|
||||
→ URL 加 hash:`index.html#slide-5` 跳到第 5 张。
|
||||
|
||||
**两种架构都适用:字在不同屏幕下位置不一致**
|
||||
→ 用固定尺寸(1920×1080)和 `px` 单位,不要用 `vw`/`vh` 或 `%`。缩放统一处理。
|
||||
|
||||
---
|
||||
|
||||
## 验证检查清单(做完 deck 必过)
|
||||
|
||||
1. [ ] 浏览器直接打开 `index.html`(或主 HTML),检查首页无破图、字体已加载
|
||||
2. [ ] 按 → 键翻到每一页,没有空白页、没有布局错位
|
||||
3. [ ] 按 P 键打印预览,每页恰好一张 A4(或 1920×1080)且无裁切
|
||||
4. [ ] 随机选 3 页 Cmd+Shift+R 强刷,localStorage 记忆正常工作
|
||||
5. [ ] Playwright 批量截图(单页架构:遍历 `slides/*.html`;单文件架构:用 goTo 切换),人工肉眼过一遍
|
||||
6. [ ] 搜一下 `TODO` / `placeholder` 残留,确认都清理了
|
||||
Reference in new issue
Block a user