zcbot/skills/ppt/references/layouts.md

533 lines
25 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 版式库 (16:9, 13.33×7.5 in) — 卡片式视觉系统
> **要点**:版式 helper 全在 `scripts/pptx_helpers.py`,**不要把 helper 源码默写进 build_deck.py** —— 只 `import pptx_helpers as P` 然后调用。配色用 current spec(命名见 SKILL.md §阶段一)里的实际 hex,通过 `P.set_palette(spec_path=...)` 注入,默认商务红 + 自动派生明暗色阶。
>
> **观感升级要点(相对老版"左色条 + 圆点 bullet")**:内容尽量装进**圆角卡片**(`add_card`,自带柔和投影),业务概念配**图标底块**(`add_icon_tile`),数据页优先**KPI 数字卡**(`add_kpi`)而非小柱图,封面/章节用**渐变大色块**(`apply_brand` 已内置)。白底之上靠卡片浮起 + 浅色阶分层,才不是"扁平办公模板"。
## 通用起手(整 deck 单脚本 — 默认路径)
阶段二写一个 `build_deck.py`,一个进程内建完整份 deck、末尾 `save` 一次(**不逐页 run_python**)。每页一个小函数,主流程按逐页大纲依次调用:
```python
import sys
sys.path.insert(0, "<skill_dir>/scripts") # <skill_dir> 用 system prompt 注入的绝对路径替换
import pptx_helpers as P
from pptx.enum.text import MSO_ANCHOR, PP_ALIGN
from pptx.enum.shapes import MSO_SHAPE
SPEC = "<task_dir>/<today>-<task_short_id>-<task_name>.spec.md"
OUT = "<task_dir>/<topic>.pptx"
ICONS = "<task_dir>/assets/icons" # fetch_icon.py 拉到这;种子库在 <skill_dir>/assets/icons
def page_1_cover(prs):
s = P.add_slide(prs)
P.apply_brand(s, "cover")
# ... 见 L1 封面 ...
def page_2(prs):
s = P.add_slide(prs)
# ... 见对应 Lx 版式 ...
def main():
prs = P.new_presentation("16:9") # 默认 16:9;可传 "4:3" / "9:16" / "3:4"
P.set_palette(spec_path=SPEC) # 整 deck 设一次配色 + 派生色阶(同进程常驻)
for build in (page_1_cover, page_2, ...): # 按逐页大纲顺序
build(prs)
prs.save(OUT)
main()
```
跑法:先 `write` 脚本到 `<task_dir>/build_deck.py`,再 `run_python(script_path=...)`。要改(quality_check 报错 / 用户要调)→ 改对应 `page_x` 函数重跑整脚本(可复现,不 edit 成品 .pptx)。
> **风格探针 / 增量补页**:要先看封面 + 1 页观感,把 `main()` 循环临时缩到前 2 个函数跑一遍;或对已存在 deck 追加单页时 `prs = P.load(OUT)` 再 `add_slide`。**常规整建不用 `load`**。
⚠️ 一律用 `P.xxx`(不要 `from pptx_helpers import *`)—— `set_palette` 靠改模块属性覆盖配色,`import *` 会把旧绑定拷进命名空间导致覆盖不生效。
---
## Helper API 速查 (都在 `P.` 命名空间下)
**画布 / 配色入口**
- `P.new_presentation(canvas="16:9")` → 建空 deck,设画布,回填 `P.SLIDE_W/H` 与安全区
- `P.load(path)` → 载入已有 deck,按文件实际尺寸回填画布常量
- `P.add_slide(prs)` → 追加空白 slide
- `P.set_palette(primary=, secondary=, accent=, cn_font=, en_font=, spec_path=)` → 覆盖主题色/字体并**重算派生色阶**;传 `spec_path` 自动取 spec 前 3 个 #hex;默认商务红
**颜色常量**:`P.PRIMARY` `P.SECONDARY` `P.ACCENT` `P.INK` `P.GREY` `P.GREY_LIGHT` `P.HAIRLINE` `P.BG` `P.WHITE`
**派生色阶**(从主/辅/强调自动算):`P.PRIMARY_WASH`(整页/大区域浅底) `P.PRIMARY_SOFT`(卡片/标签浅底) `P.PRIMARY_DARK`(渐变深端) `P.ACCENT_SOFT`(高亮浅底) `P.SURFACE`(卡片白面)
**字体常量**:`P.CN_FONT`(微软雅黑) `P.EN_FONT`(Arial)
**画布常量**:`P.SLIDE_W` `P.SLIDE_H` `P.SAFE_LEFT/TOP/RIGHT/BOTTOM` `P.SAFE_W` `P.SAFE_H`
**色阶工具**:`P.tint(color, pct)` 提亮 / `P.shade(color, pct)` 压暗(自定义中间色用)
**🔥 组合版式件**(一个函数摆一整块 —— 优先用这些,别手摆参差网格/拿卡片硬凑时间线)
- `P.add_card_grid(slide, items, top, height, cols=None, icon_dir=None, accent=None)`**均衡概念网格**;items=每项 `{icon,title,body}`;自动均衡行列(2×2/2×3,不参差),单行图标顶置、多行图标左置;`icon_dir` 给图标目录(图标名去 `tabler_` 前缀)
- `P.add_timeline(slide, nodes, y=3.2)`**横向时间轴**;nodes=`{year,title,body}`;发展历程/路线图用,别塞卡片网格
- `P.add_cycle(slide, steps, cy=4.5, radius=1.55, center_label=)`**流程闭环**(节点沿环+中心词);循环类用。⚠️文字多时改用横向流程(L12)更稳
- `P.add_toc(slide, items, top=2.2)`**目录**(序号+标题+右副标+发丝线,贯通整宽);items=`(title, caption)`
- `P.add_kpi(slide, l, t, w, h, value, label, baseline=, delta=, delta_dir=)`**KPI 数字卡**;`baseline`=对比基准、`delta`=趋势(升绿降红);**数字别孤立**
- `P.add_takeaway(slide, "<一句话结论>", top=None)`**结论框**(浅主色底+左条);内容页论断标题下标配
- `P.add_source(slide, "<来源>")` → 数据来源(右下角弱化);含数据的页必标
- `P.add_picture_bg(slide, png)` → 整页铺渲染好的高清背景图(混合方案:背景图+原生可编辑文字)
**容器 / 质感**(卡片式核心)
- `P.add_card(slide, l, t, w, h, fill=SURFACE, radius=0.12, shadow=False, border=None, accent=None)` → 圆角卡片。**默认平卡**(白底描发丝边);**投影是克制**:平铺对等卡一律平,`shadow=True` 只给真悬浮/被挑出的卡,每页 ≤2-3 个;**一容器一手段**(投影/描边/底色/accent 四选一不叠)。见 design_principles §视觉深度
- `P.add_round_rect(slide, l, t, w, h, fill, radius=0.10)` → 无投影圆角矩形
- `P.add_gradient_rect(slide, l, t, w, h, c1, c2, angle=90, rounded=False)` → 渐变块(封面/章节大色块;原生可编辑非图片)
- `P.set_shadow(shape, ...)` / `P.set_line(shape, color, weight)` → 手动投影 / 描边
- `P.add_bg(slide, color=BG)` → 整页背景(`apply_brand` 已内置)
- 语义色:`P.GOOD`(增长绿)/ `P.BAD`(下降红)—— KPI 趋势用,不计三色制
**组件**
- `P.add_icon_tile(slide, x, y, size=0.9, png_path=None, fill=PRIMARY_SOFT)` → 图标圆角底块 + 居中图标
- `P.add_icon(slide, png_path, x, y, size=0.6)` → 裸图标 PNG(方形源等比)
- `P.add_pill(slide, x, y, w, h, text, fill=PRIMARY, fg=WHITE, size=12)` → 胶囊标签 / chip
- `P.add_eyebrow(slide, x, y, text, color=PRIMARY, size=13)` → 标题上方小标签 / kicker
- `P.add_badge(slide, x, y, num, diameter=0.7)` → 编号徽章(圆+数字)
- `P.add_chevron(slide, x, y, w=0.55, h=0.5, color=GREY_LIGHT)` → 流程箭头
- `P.add_dot(slide, x, y, size=0.18, color=ACCENT)` → 圆点(bullet 前缀)
- `P.add_accent_line(slide, x, y, length=1.0, thickness=0.05)` → 强调短线
- `P.add_divider(slide, x, y, length, vertical=False)` → 细分隔线
**文本 / 标题 / 品牌 / 备注**
- `P.add_textbox(slide, l, t, w, h, text, size, bold=False, color=INK, align=, anchor=, font=None, shrink=True, name=)` → 文本框;`font=None` 自动 latin=Arial + 东亚=微软雅黑(**中文真落雅黑靠这个**),传 `font` 则两槽都用它(纯英文大字/数字)
- `P.page_title(slide, text, page_num=None, total=None, footer=, eyebrow=None)` → 内页标题+强调线(+可选 eyebrow / 页脚页码)
- `P.apply_brand(slide, kind)` → 品牌锚点,`kind` ∈ `"cover"/"inner"/"section"/"end"`;**每页第一行必调**(已含整页背景)
- `P.add_notes(slide, text)` → 演讲者备注(正式产物每页给 2-4 句口述要点)
- `P.assert_inside(l, t, w, h, name="")` → 手动越界校验(放置 helper 已内置)
---
## 🔥 组合件示例 (优先用 —— 一个函数一整块)
### 内容页范式:论断标题 + Takeaway + 均衡网格
> 内容页的"黄金结构"(咨询级):**论断式标题**(写结论)→ **Takeaway 一句话**(浅底框)→ 内容。把它做成本地小函数 `content_header`。
```python
from pptx.enum.text import MSO_ANCHOR
def content_header(s, title, takeaway, eyebrow=None):
ty = P.SAFE_TOP
if eyebrow:
P.add_eyebrow(s, P.SAFE_LEFT, ty, eyebrow); ty += 0.4
P.add_textbox(s, P.SAFE_LEFT, ty, P.SAFE_W, 0.7, title, 28, bold=True,
color=P.PRIMARY, name="title") # 论断标题
if takeaway:
P.add_takeaway(s, takeaway, top=ty + 0.82) # 结论框
s = P.add_slide(prs); P.apply_brand(s, "inner")
content_header(s, "大模型靠规模涌现出通用智能",
"参数突破千亿临界点后,模型从'专用工具'跃升为'通用大脑'",
eyebrow="DEFINITION")
items = [ # 每项 icon 名 + 标题 + 精炼正文(≤18 字)
{"icon": "brain", "title": "超大参数", "body": "千亿参数突破临界点,涌现推理力"},
{"icon": "cpu", "title": "对话生成", "body": "多轮对话、写代码、摘要改写"},
{"icon": "cloud-network", "title": "多模态", "body": "文本+图像+音频+视频统一理解"},
{"icon": "target", "title": "任务规划", "body": "高级推理与链式拆解"},
{"icon": "bolt", "title": "持续成长", "body": "RLHF、RAG、微调持续打磨"},
]
P.add_card_grid(s, items, top=2.35, height=4.5, icon_dir=ICONS) # 平卡,自动均衡
```
### 时间轴(发展历程 / 路线图)
```python
content_header(s, "六年从 GPT-1 到推理模型,能力指数跃迁",
"每一代都在重定义能力边界", eyebrow="TIMELINE")
P.add_timeline(s, [
{"year": "2018", "title": "GPT-1", "body": "预训练范式确立"},
{"year": "2020", "title": "GPT-3", "body": "1750 亿参数,few-shot 涌现"},
{"year": "2022", "title": "ChatGPT", "body": "对话式 AI 引爆全民应用"},
{"year": "2023", "title": "GPT-4", "body": "多模态 + 强推理"},
], y=3.9)
P.add_source(s, "OpenAI / 各厂商公开发布")
```
### KPI 数字卡(数据语境化:对比基准 + 升降)
```python
data = [("158%", "实验吞吐同比", "行业均值 90%", "+68pt", "up"),
("27天", "配方迭代周期", "去年 45 天", "-40%", "up"),
("92.3%", "中试一次通过率", "行业 81%", "+11pt", "up")]
n, gap = len(data), 0.3; cw = (P.SAFE_W - gap*(n-1))/n
for i,(v,lab,base,delta,d) in enumerate(data):
P.add_kpi(s, P.SAFE_LEFT+i*(cw+gap), 2.6, cw, 2.7, v, lab,
baseline=base, delta=delta, delta_dir=d)
```
### breathing 大字页(打破卡片单调 —— 每隔 2-3 页插一个)
```python
s = P.add_slide(prs); P.apply_brand(s, "inner")
P.add_eyebrow(s, P.SAFE_LEFT, 1.5, "THE INFLECTION POINT")
P.add_textbox(s, P.SAFE_LEFT, 2.15, 9.0, 2.5, "2 个月", 150, bold=True,
color=P.PRIMARY, font=P.EN_FONT, shrink=False, name="big_stat")
P.add_textbox(s, P.SAFE_LEFT, 4.7, 11, 0.7, "ChatGPT 月活突破 1 亿", 30,
bold=True, color=P.INK, name="big_label")
P.add_textbox(s, P.SAFE_LEFT, 5.6, 11, 0.6,
"史上最快 —— 此前纪录是 TikTok 的 9 个月", 18, color=P.GREY,
name="big_ctx") # 数据语境化:大数字必带对比
```
### 目录(贯通整宽)
```python
P.page_title(s, "目录", eyebrow="AGENDA")
P.add_toc(s, [("什么是大模型", "规模、能力与边界"),
("发展历程", "六年能力跃迁"),
("AI 智能体", "从对话到自主行动")], top=2.25)
```
### 混合背景封面(杂志级,opt-in)
```python
# 先 run_python: python render_bg.py --out <task_dir>/figures/cover_bg.png --kind cover --primary C00000
s = P.add_slide(prs)
P.add_picture_bg(s, "<task_dir>/figures/cover_bg.png") # 背景图(不可编辑)
P.add_eyebrow(s, 0.95, 1.95, "TECHNOLOGY INSIGHT · 2026", color=P.ACCENT)
P.add_textbox(s, 0.95, 2.45, 8.0, 1.7, "主标题\n副标题行", 44, bold=True,
color=P.WHITE, name="cover_title") # 白字叠背景(可编辑)
```
> 下面 L1-L13 是更细的手摆版式参考;**业务概念/数据/历程/循环优先用上面的组合件**,手摆只在组合件不覆盖时用。
> ⚠️ **给每个元素起语义 `name`**(`"bullet_1"`/`"kpi_val"`/`"eyebrow"`/`"pill"` 等)。quality_check 靠 name 判定"哪些是标签(小字号豁免)、哪些是真 bullet(计 ≤5)、谁压了谁",名字乱起会误报。helper 默认名已合理,自己加文本时照着命名。
> `MSO_SHAPE` / `PP_ALIGN` / `MSO_ANCHOR` 页面里要直接用就自行 import(`pptx_helpers` 内部已 import 但不重导出)。
---
## L1 · 封面 (Cover) —— 渐变大色块 + 左侧标题区
```python
s = P.add_slide(prs)
P.apply_brand(s, "cover") # 右侧 40% 主色→深主色渐变块 + 左上强调短线 + 底细线
# 左侧标题区(避开右侧渐变块,文字区约 7.4 寸宽)
P.add_eyebrow(s, 0.9, 2.0, "2026 年度技术汇报") # kicker 小标签
P.add_textbox(s, 0.9, 2.5, 7.2, 1.6, "项目名称 / 演示主题",
42, bold=True, color=P.INK, name="cover_title")
P.add_textbox(s, 0.9, 4.4, 7.0, 0.6, "一句话副标题或定位",
20, color=P.GREY, name="cover_sub")
P.add_textbox(s, 0.9, 6.4, 7.0, 0.4, "汇报人 · 部门 · 2026-06-08",
14, color=P.GREY_LIGHT, name="cover_meta")
P.add_notes(s, "开场白:点出主题与本次汇报要解决的核心问题。")
```
> 有合适主图时(见 SKILL.md §配图),可把右侧渐变块换成**真实图片**:`s.shapes.add_picture(hero, Inches(P.SLIDE_W*0.6), Inches(0), height=Inches(7.5))`,再在图上叠半透明主色块保证文字区干净。
---
## L2 · 目录 (Agenda) —— 编号徽章 + 文字
```python
from pptx.enum.text import MSO_ANCHOR
s = P.add_slide(prs)
P.apply_brand(s, "inner")
P.page_title(s, "目录")
items = ["背景与现状", "核心问题", "解决方案", "实施计划", "预期成果"]
for i, item in enumerate(items):
y = 1.9 + i * 0.95
P.add_badge(s, P.SAFE_LEFT, y, i + 1, diameter=0.65)
P.add_textbox(s, P.SAFE_LEFT + 1.0, y, P.SAFE_W - 1.0, 0.65, item, 22,
color=P.INK, anchor=MSO_ANCHOR.MIDDLE, name=f"agenda_{i}")
```
---
## L3 · 章节分隔 (Section Divider) —— 渐变整页 + 大字编号(白字)
```python
from pptx.enum.text import MSO_ANCHOR
s = P.add_slide(prs)
P.apply_brand(s, "section") # 主色→深主色整页渐变 + 强调装饰条
# 大编号(白色;font=EN_FONT 让数字走 Arial)
P.add_textbox(s, 1.1, 2.0, 4, 2.5, "01", 150, bold=True, color=P.WHITE,
font=P.EN_FONT, name="sec_num")
# 章节名(白色)
P.add_textbox(s, 5.3, 2.8, 7, 1.0, "背景与现状", 44, bold=True,
color=P.WHITE, anchor=MSO_ANCHOR.MIDDLE, name="sec_title")
# 引言(强调浅色,渐变深底上可读)
P.add_textbox(s, 5.3, 4.0, 7, 0.6, "本章讨论行业现状与机会窗口", 18,
color=P.ACCENT_SOFT, name="sec_lead")
```
> 渐变深底上文字一律用 **白 / `ACCENT_SOFT`** 等浅色,不要用 `INK` 深灰(看不清)。
---
## L4 · 要点 (Bullets) —— 圆点 + 文字;≥3 条建议升级成卡片(见 L11)
```python
from pptx.enum.text import MSO_ANCHOR
s = P.add_slide(prs)
P.apply_brand(s, "inner")
P.page_title(s, "核心结论")
bullets = [
"结论一:用一句话讲清楚",
"结论二:具体数据支撑,如增长 27%",
"结论三:对未来的判断,简洁有力",
"结论四:可选第四条,不要超过 5 条",
]
for i, b in enumerate(bullets):
y = 2.0 + i * 0.95
P.add_dot(s, P.SAFE_LEFT + 0.05, y + 0.22, size=0.18)
P.add_textbox(s, P.SAFE_LEFT + 0.45, y, P.SAFE_W - 0.45, 0.6, b, 22,
color=P.INK, anchor=MSO_ANCHOR.MIDDLE, name=f"bullet_{i}")
```
> 纯圆点 bullet 偏单薄。**业务概念类要点(能力/模块/策略)优先用 L11 卡片网格 + 图标底块**,视觉重量足。
---
## L5 · 双栏对比 (Two-Column) —— 两张卡片,左中右灰
```python
from pptx.enum.text import PP_ALIGN, MSO_ANCHOR
s = P.add_slide(prs)
P.apply_brand(s, "inner")
P.page_title(s, "现状 vs 改进后")
cw = (P.SAFE_W - 0.5) / 2 # 两卡 + 中间 0.5 间隙
ly, lh = 2.0, 4.5
# 左卡:现状(中性灰底,弱化)
P.add_card(s, P.SAFE_LEFT, ly, cw, lh, fill=P.BG, border=True, shadow=False)
P.add_pill(s, P.SAFE_LEFT + 0.35, ly + 0.35, 1.1, 0.36, "现状", fill=P.GREY)
left_pts = ["问题 A:描述", "问题 B:描述", "问题 C:描述"]
for i, p in enumerate(left_pts):
yy = ly + 1.1 + i * 0.7
P.add_dot(s, P.SAFE_LEFT + 0.4, yy + 0.16, color=P.GREY)
P.add_textbox(s, P.SAFE_LEFT + 0.8, yy, cw - 1.1, 0.55, p, 17,
color=P.INK, anchor=MSO_ANCHOR.MIDDLE, name=f"l_pt_{i}")
# 右卡:改进后(主色强调条 + 浅底,突出)
rx = P.SAFE_LEFT + cw + 0.5
P.add_card(s, rx, ly, cw, lh, fill=P.SURFACE, accent=P.PRIMARY)
P.add_pill(s, rx + 0.5, ly + 0.35, 1.3, 0.36, "改进后", fill=P.PRIMARY)
right_pts = ["改善 A:描述", "改善 B:描述", "改善 C:描述"]
for i, p in enumerate(right_pts):
yy = ly + 1.1 + i * 0.7
P.add_dot(s, rx + 0.55, yy + 0.16, color=P.ACCENT)
P.add_textbox(s, rx + 0.95, yy, cw - 1.3, 0.55, p, 17, color=P.INK,
anchor=MSO_ANCHOR.MIDDLE, name=f"r_pt_{i}")
```
---
## L6 · 图表为主 (Chart-focus) —— 标题 + 一句结论 + 大图嵌卡片
```python
from pptx.util import Inches
from pptx.enum.text import PP_ALIGN
# chart.png 已用 matplotlib 生成(见 design_principles.md §7)
s = P.add_slide(prs)
P.apply_brand(s, "inner")
P.page_title(s, "季度营收持续增长")
P.add_textbox(s, P.SAFE_LEFT, P.SAFE_TOP + 1.1, P.SAFE_W, 0.5,
"Q4 同比增长 158%,创历史新高", 18, color=P.GREY, name="lead")
# 图表衬一张白卡片(浮起,比裸图精致)
P.add_card(s, 2.0, 2.4, 9.3, 4.3, fill=P.SURFACE)
s.shapes.add_picture("<task_dir>/slides/chart.png", Inches(2.4),
Inches(2.7), width=Inches(8.5))
P.add_textbox(s, P.SAFE_LEFT, 6.95, P.SAFE_W, 0.4, "数据来源:公司年报 2025",
11, color=P.GREY_LIGHT, align=PP_ALIGN.RIGHT, shrink=False,
name="source")
```
---
## L7 · 图片为主 (Image-focus) —— 图占 58%,文字独立区
```python
from pptx.util import Inches
from pptx.enum.shapes import MSO_SHAPE
s = P.add_slide(prs)
P.add_bg(s, P.WHITE)
# 左侧图(只给 height 等比铺满,避免变形)
s.shapes.add_picture("<task_dir>/slides/hero.jpg", Inches(0), Inches(0),
height=Inches(7.5))
# 右侧浅底文字区
P.add_rect(s, 7.7, 0, 5.63, 7.5, P.PRIMARY_WASH, "text_panel")
P.add_eyebrow(s, 8.1, 1.4, "PRODUCT")
P.add_textbox(s, 8.1, 1.9, 4.9, 1.0, "走进未来", 36, bold=True, color=P.INK,
name="img_title")
P.add_accent_line(s, 8.1, 3.0, length=0.6)
P.add_textbox(s, 8.1, 3.4, 4.9, 1.6, "用一两句话点出主旨,不要把演讲稿搬上来。",
18, color=P.GREY, name="img_caption")
P.add_shape(s, MSO_SHAPE.RIGHT_ARROW, 8.1, 6.4, 0.7, 0.35, P.ACCENT, "img_cta")
```
---
## L8 · 金句 / 大字 (Quote) —— 留白主导
```python
from pptx.enum.text import MSO_ANCHOR
s = P.add_slide(prs)
P.apply_brand(s, "inner")
P.add_textbox(s, 0.8, 0.6, 1.5, 1.5, '"', 200, bold=True, color=P.ACCENT,
font=P.EN_FONT, shrink=False, name="quote_mark")
P.add_textbox(s, 1.5, 2.7, 10.5, 2.0, "把复杂留给我们,把简单留给用户。", 36,
bold=True, color=P.INK, anchor=MSO_ANCHOR.MIDDLE, name="quote_text")
P.add_accent_line(s, 1.5, 5.0, length=0.5)
P.add_textbox(s, 1.5, 5.2, 10.5, 0.5, "—— 公司价值观 2025", 16, color=P.GREY,
name="quote_attr")
```
---
## L9 · 结尾 / Q&A —— 浅底 + 大字,**强制必有**
> **不是可选** —— 任何 deck 都必须以这页收尾。
```python
from pptx.enum.text import PP_ALIGN
s = P.add_slide(prs)
P.apply_brand(s, "end") # PRIMARY_WASH 浅底 + 顶/底强调短线
P.add_textbox(s, 0, 2.5, P.SLIDE_W, 1.6, "Thank You", 80, bold=True,
color=P.PRIMARY, align=PP_ALIGN.CENTER, font=P.EN_FONT,
name="thanks")
P.add_textbox(s, 0, 4.3, P.SLIDE_W, 0.6, "欢迎提问与讨论", 22, color=P.INK,
align=PP_ALIGN.CENTER, name="qa")
P.add_textbox(s, 0, 6.2, P.SLIDE_W, 0.5, "联系方式 / 邮箱 / 公众号", 14,
color=P.GREY_LIGHT, align=PP_ALIGN.CENTER, name="contact")
```
---
## L10 · KPI 数字卡 (Metrics) —— 2-4 张并排,数据页主力
> 数据页**优先用这个**,不要为 2-4 个数字硬画柱状图。大数字 + 标签 + 同比小注,信息密度与质感俱佳。
```python
s = P.add_slide(prs)
P.apply_brand(s, "inner")
P.page_title(s, "平台运行关键指标", eyebrow="运行数据 / 2025")
data = [("158%", "实验吞吐同比", "↑ 较去年"),
("27天", "配方迭代周期", "↓ 缩短 40%"),
("92.3%", "中试一次通过率", "↑ +11pt"),
("4.2万", "累计实验记录", "条")]
n = len(data)
gap = 0.3
cw = (P.SAFE_W - gap * (n - 1)) / n
for i, (v, lab, sub) in enumerate(data):
P.add_kpi(s, P.SAFE_LEFT + i * (cw + gap), 2.6, cw, 2.7, v, lab, sub=sub)
```
> 想突出某张卡:传 `value_color=P.ACCENT` 或给那张卡 `add_card(..., accent=P.ACCENT)` 后 `add_kpi(..., card=False)` 叠上。
---
## L11 · 卡片网格 (Card Grid) —— 图标底块 + 标题 + 说明,业务概念主力
> 能力 / 模块 / 策略 / 价值点这类**业务概念**用它,替代单薄的圆点 bullet。2-4 列均可;图标走 `add_icon_tile`(图标先按 SKILL.md §阶段二第 2 步批量 `fetch_icon.py` 拉到 `<task_dir>/assets/icons`)。
```python
import os
s = P.add_slide(prs)
P.apply_brand(s, "inner")
P.page_title(s, "三大核心能力")
items = [("target", "数据底座", "统一实验/表征/工艺数据湖,一处录入处处可用"),
("cpu", "智能配方", "贝叶斯优化叠加机理约束,迭代更快更稳"),
("chart-bar", "中试放大", "小试到中试参数迁移模型,放大不失真")]
n = len(items)
gap = 0.35
cw = (P.SAFE_W - gap * (n - 1)) / n
for i, (icon, h, body) in enumerate(items):
x = P.SAFE_LEFT + i * (cw + gap)
P.add_card(s, x, 2.3, cw, 3.6, accent=P.PRIMARY)
png = os.path.join(ICONS, f"tabler_{icon}_C00000_128.png") # 主色染色后的图标
P.add_icon_tile(s, x + 0.4, 2.7, 0.95, png_path=png)
P.add_textbox(s, x + 0.4, 3.85, cw - 0.8, 0.5, h, 20, bold=True,
color=P.INK, name=f"card_h_{i}")
P.add_textbox(s, x + 0.4, 4.45, cw - 0.8, 1.1, body, 15, color=P.GREY,
name=f"card_b_{i}")
```
---
## L12 · 流程 / 步骤 (Process) —— 卡片 + chevron 箭头串联
```python
s = P.add_slide(prs)
P.apply_brand(s, "inner")
P.page_title(s, "实施四步走", eyebrow="路线图")
steps = [("01", "调研", "梳理现状与痛点"),
("02", "建模", "搭数据底座与模型"),
("03", "试点", "单产线小批验证"),
("04", "推广", "全厂复制与运维")]
n = len(steps)
arrow_w = 0.5
cw = (P.SAFE_W - arrow_w * (n - 1) - 0.2 * (n - 1)) / n
y, h = 2.8, 2.6
for i, (num, title, body) in enumerate(steps):
x = P.SAFE_LEFT + i * (cw + arrow_w + 0.2)
P.add_card(s, x, y, cw, h, fill=P.SURFACE)
P.add_textbox(s, x + 0.3, y + 0.3, cw - 0.6, 0.7, num, 34, bold=True,
color=P.PRIMARY, font=P.EN_FONT, name=f"step_num_{i}")
P.add_textbox(s, x + 0.3, y + 1.1, cw - 0.6, 0.5, title, 19, bold=True,
color=P.INK, name=f"step_t_{i}")
P.add_textbox(s, x + 0.3, y + 1.65, cw - 0.6, 0.8, body, 14, color=P.GREY,
name=f"step_b_{i}")
if i < n - 1:
P.add_chevron(s, x + cw + 0.1, y + h / 2 - 0.25, arrow_w, 0.5)
```
---
## L13 · 大数字 + 论据 (Stat Highlight) —— 单个震撼数字撑半屏
> 一个核心数字要砸出冲击力时用。左侧超大数字,右侧三两条支撑论据卡。
```python
from pptx.enum.text import MSO_ANCHOR
s = P.add_slide(prs)
P.apply_brand(s, "inner")
P.page_title(s, "一年走完三年的路", eyebrow="成效")
# 左:超大数字(主色)
P.add_textbox(s, P.SAFE_LEFT, 2.4, 5.2, 2.4, "3.6×", 140, bold=True,
color=P.PRIMARY, font=P.EN_FONT, anchor=MSO_ANCHOR.MIDDLE,
name="big_stat")
P.add_textbox(s, P.SAFE_LEFT, 4.9, 5.2, 0.5, "研发效率提升", 20, color=P.INK,
name="big_stat_label")
# 右:支撑论据(浅底小卡堆叠)
facts = ["实验自动排程,人力释放 60%", "失败配方提前预警,返工 ↓45%", "知识沉淀复用,新人上手周期减半"]
for i, f in enumerate(facts):
yy = 2.5 + i * 1.25
P.add_card(s, 6.6, yy, 6.0, 1.05, fill=P.PRIMARY_WASH, shadow=False)
P.add_dot(s, 6.95, yy + 0.45, color=P.PRIMARY)
P.add_textbox(s, 7.35, yy, 5.0, 1.05, f, 16, color=P.INK,
anchor=MSO_ANCHOR.MIDDLE, name=f"fact_{i}")
```
---
## 选版式速查
```
封面 → L1 (Cover)
目录 → L2 (Agenda)
转场 / 换章 → L3 (Section Divider)
要点 ≤ 5 条(纯文字) → L4 (Bullets)
对比类 (前/后, A/B) → L5 (Two-Column)
有数据图表 → L6 (Chart-focus)
有大图 / 视觉优先 → L7 (Image-focus)
观点强调 / 名言 → L8 (Quote)
末页 → L9 (Q&A) [强制]
2-4 个关键数字 → L10 (KPI 数字卡) ← 优先于硬画柱图
业务概念(能力/模块) → L11 (卡片网格 + 图标) ← 优先于圆点 bullet
流程 / 步骤 → L12 (Process)
单个震撼数字 → L13 (Stat Highlight)
```
## 三个常犯的越界场景
1. **bullet 字数超额** —— 22pt 在 11.5 寸宽下每行约 50 个中文字,超 1 行就溢出 0.6 in 框。根本解法是**字数压缩**(见 design_principles.md §字数预算),不要靠 `auto_size` 收字号兜底。
2. **卡片内容超出卡片** —— 卡片内文字按 `卡宽 - 2×0.4` 内边距算框宽;标题/正文字数超了会顶出卡片下边缘。卡片高度留够(KPI 卡 ≥2.5,概念卡 ≥3.4)。
3. **图片不等比拉伸** —— `add_picture(width=, height=)` 同时给会变形;**只给 width 或 height 一项**。
4. **渐变深底上用深色字** —— L3 章节页 / cover 渐变块上的文字必须 `WHITE` / `ACCENT_SOFT`,用 `INK` 看不清。
```