zcbot/skills/ppt/references/layouts.md

25 KiB
Raw Permalink Blame History

版式库 (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)。每页一个小函数,主流程按逐页大纲依次调用:

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

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)   # 平卡,自动均衡

时间轴(发展历程 / 路线图)

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 数字卡(数据语境化:对比基准 + 升降)

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 页插一个)

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")   # 数据语境化:大数字必带对比

目录(贯通整宽)

P.page_title(s, "目录", eyebrow="AGENDA")
P.add_toc(s, [("什么是大模型", "规模、能力与边界"),
              ("发展历程", "六年能力跃迁"),
              ("AI 智能体", "从对话到自主行动")], top=2.25)

混合背景封面(杂志级,opt-in)

# 先 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) —— 渐变大色块 + 左侧标题区

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) —— 编号徽章 + 文字

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) —— 渐变整页 + 大字编号(白字)

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)

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) —— 两张卡片,左中右灰

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) —— 标题 + 一句结论 + 大图嵌卡片

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%,文字独立区

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) —— 留白主导

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 都必须以这页收尾。

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 个数字硬画柱状图。大数字 + 标签 + 同比小注,信息密度与质感俱佳。

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)。

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 箭头串联

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) —— 单个震撼数字撑半屏

一个核心数字要砸出冲击力时用。左侧超大数字,右侧三两条支撑论据卡。

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 看不清。