# 版式库 (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, "/scripts") # 用 system prompt 注入的绝对路径替换 import pptx_helpers as P from pptx.enum.text import MSO_ANCHOR, PP_ALIGN from pptx.enum.shapes import MSO_SHAPE SPEC = "/--.spec.md" OUT = "/.pptx" ICONS = "/assets/icons" # fetch_icon.py 拉到这;种子库在 /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` 脚本到 `/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 /figures/cover_bg.png --kind cover --primary C00000 s = P.add_slide(prs) P.add_picture_bg(s, "/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("/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("/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` 拉到 `/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` 看不清。 ```