doa-ppt — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited doa-ppt (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
用户输入(描述 + 参考图)
→ 确认PPT规模
→ 使用公司模板(唯一默认模板)
→ 生成可翻页 HTML 预览
→ 逐页检查 HTML 是否越界/裁切/重叠
→ 用户确认/调整 HTML
→ 只有用户明确确认 HTML 无问题后,才进入 PPT 模式选择
→ 默认推荐截图高保真模式(用户如需二次编辑再切换到可编辑)
→ 生成 PPT当用户提供 PDF、截图、既有 HTML 或已有 PPT,并要求“基于这个继续生成 / 整合 / 扩展 / 转 PPT”时,必须先把资料链路整理清楚,再改版式。
slides.html 才是可维护源文件;截图型 .pptx/.pdf 只作为交付物,不作为反向编辑来源。export_pptx.pyexport_editable_pptx.py_Editable_YYYYMMDD、_HD_YYYYMMDD),防止 PermissionError 和历史交付丢失。2560×1440),再对外宣称“已完成交付”。.pdf、.html、.pptx、生成脚本和相关资源,确认哪一个是主源文件、哪一个是导出结果。pypdf/pdfplumber;如果每页文本为空,说明多半是扫描型 PDF,应使用 PyMuPDF 渲染为图片后逐页查看。active 状态、data-index 和页码。data-index 属性(从 0 连续递增).page-no 页码(当前页 / 新总数)<!-- P7: xxx -->)multi_replace_string_in_file 一次性完成所有页码更新,避免遗漏对于架构、安全、技术选型类 PPT,优先采用以下结构:
1280×720。浏览器预览可以通过 CSS/JS 做自适应缩放,但导出截图必须保持 .slides-viewport 的原始 1280×720 尺寸。.content{height:600px}。如果直接把 .grid-* 用在 .content 上,必须补 .content.grid-*{height:600px} 防止内容压到 footer。slide.className = 'slide active',否则会丢失 cover 等特殊 class。应使用 classList.remove('active','exit-left') 和 classList.add('active')。& "c:/path with spaces/.venv/Scripts/python.exe" script.py。PermissionError。<circle>, <rect> 等)即使超出 viewBox 范围,浏览器仍会渲染并占据布局空间。getBoundingClientRect() 会返回超出 viewBox 的实际渲染区域,导致边界检查报越界。overflow:hidden 只能在视觉上裁剪,但 getBoundingClientRect() 仍然返回子元素的完整渲染尺寸,边界检查仍会报 overflow。<circle>, <rect> 等元素的坐标 + 半径/尺寸必须在 viewBox 范围内。例如 viewBox="0 0 320 320" 中,<circle cx="220" r="130"> 右边界为 350,超出 320,必须减小 cx 或 r。right:-30px 会让 SVG 内容溢出 slide 右边界。背景装饰 SVG 应使用 right:0 并让视觉内容自然收敛在 viewBox 内。position:absolute; pointer-events:none; z-index:0; opacity:0.03~0.08,确保不影响交互且视觉上足够微妙。强制规则:所有使用左右分栏的内容页,左右两列必须等高对齐,底部齐平。这是不可协商的硬性要求。
style="flex:1" 填满剩余高度;多张卡片用 flex:1 让每张卡片等分空间。flex:1 使其自动拉伸填满。禁止出现一侧比另一侧短、底部有大段空白的情况。.content 加 display:flex;flex-direction:column,.grid-2 加 flex:1 或 style="height:100%",确保 grid 占满内容区而非只占内容自然高度。#### 2026-05-31 图文分栏对齐补充(强制)
.screenshot-panel 类自带 padding:8px,会导致图片面板比左侧内容区矮 16px。必须在 style 中加 `padding:0` 覆盖,否则左右高度永远对不齐。width:100%;height:100%;object-fit:cover 铺满面板,不留白边。产品截图用 object-fit:contain 保留完整界面。min-height:auto,内容过多时会撑破容器导致溢出。所有 flex 子元素(左侧内容区、右侧图片面板)都必须加 `min-height:0`。box-shadow 和 border,适用于产品截图,不适用于背景配图。背景配图直接写内联样式 border-radius:14px。min-width:auto,表格等元素可能撑宽导致右侧图片被压缩。加 min-width:0 允许内容区按比例缩小。#### 对齐问题诊断清单
当左右高度不对齐时,按以下顺序检查:
.content 是否有 display:flex;align-items:stretch?padding:0 覆盖默认 padding?width:100%;height:100%;object-fit:cover?min-height:0?min-width:0?overflow:hidden? <div class="grid-2">
<div style="display:flex;flex-direction:column;">
<div style="...title...">标题</div>
<table class="cmp-table" style="flex:1;">...</table>
</div>
<div style="display:flex;flex-direction:column;">
<div style="...title...">标题</div>
<table class="cmp-table" style="flex:1;">...</table>
</div>
</div>.header { padding: 24px 56px 0 } 而非 32px,减少页眉到内容区的间距。色条 .header::after { top: 68px } 同步调整。.content { padding: 16px 56px 10px; height: 600px } 而非旧值 40px/32px/548px,可用面积增加约 20%。.content 设为 display:flex;flex-direction:column,底部摘要块用 margin-top:auto 贴近底部,消除表格与摘要之间的大片空白。margin-top:auto 或 margin-top:10px 控制位置。.grid-2 的父容器 .content 设为 display:flex;flex-direction:column,然后 .grid-2 自身加 flex:1 使其填满剩余空间,避免 grid 与 footer 之间出现大段空白。 <div class="content" style="display:flex;flex-direction:column;">
<table class="cmp-table">...</table>
<div style="margin-top:auto;padding:12px 16px;background:var(--primary-soft);border-radius:8px;">
<strong>💡 结论:</strong>摘要文字
</div>
</div>当用户反馈"字太小、看不清"时,必须按以下策略系统性放大字体,同时联动调整布局参数防止溢出。
font-size:Npx 统一 +2px(13→15, 14→16, 15→17, 16→18, 17→19, 18→20),.page-title 从 30→34px。不要只改一两处导致大小不统一。.content { height } 从 590→600px,padding 从 20px 56px 14px → 16px 56px 10px,腾出更多垂直空间。.slide,计算 scrollHeight - clientHeight,任何 > 2px 的页面必须修复(缩减图片、减少间距、精简文案)。1-2px 的误差属于亚像素渲染,可忽略。<br> 空行。convert('RGB') 去掉 alpha 通道。build_pptx() 和 build_pdf() 两个函数,避免重复截图。截图高保真 PPT 生成后,必须验证:
.pptx 文件存在Presentation(...).slides 页数等于 HTML 中 .slide 数量ppt/media/image*.png 数量等于页数VIEWPORT × DEVICE_SCALE 一致;标准 2x 高清链路下应为 2560×1440image1.png向用户收集以下信息:
必须在生成前与用户确认,使用 vscode_askQuestions 工具提问,提供两个选项:
| 选项 | 说明 | 适用场景 | |
|---|---|---|---|
| 公司品牌模板 | 页眉:左侧渐变圆点 + 标题,右侧 SWO / 微钉双品牌 Logo;页脚:左 "SoftwareOne \ | 微钉科技",右页码胶囊 | 对外商务演示、客户提案、正式交付 |
| AI 自动设计 | AI 根据 PPT 主题和内容自动决定页眉页脚的图标、品牌名和排版风格 | 内部分享、读书会、技术沙龙、个人演示等非品牌场景 |
选择"公司品牌模板"时,使用 Step 1.5 中定义的 Logo 和页脚规范;选择"AI 自动设计"时,AI 根据内容主题自行设计页眉标识(如书名缩写、主题 icon 等)和页脚文字,但仍遵循相同的布局结构和字号规范。
#### 公司品牌模板 Logo 素材
品牌素材位于 .claude/skills/doa-ppt/brand-assets/,生成 PPT 时需复制到 output/<项目名>/ppt_softwareonemedlasoft_assets/:
| 文件名 | 用途 |
|---|---|
SoftwareOne.png | SoftwareOne Logo(黑色,通用于封面/内容页/结尾页) |
Medaslsoft.png | 微钉科技 Logo(彩色,含中英文图标,通用于封面/内容页/结尾页) |
Medaslsoft_Sample.png | 微钉小图标(仅 icon,用于目录页和内容页标题左侧的 .header-dot) |
CSS 引用方式(统一用 background: url(...) center/contain no-repeat):
.header-dot → Medaslsoft_Sample.png(32×32px,替代原来的渐变圆点).cover-logo-swo → SoftwareOne.png,.cover-logo-medalsoft → Medaslsoft.png.header-logo-swo → SoftwareOne.png,.header-logo-medalsoft → Medaslsoft.png.ending-logo-swo → SoftwareOne.png,.ending-logo-medalsoft → Medaslsoft.png必须在生成前与用户确认,使用 vscode_askQuestions 工具提问:
| 规模 | 页数 | 适用场景 | 内容深度 |
|---|---|---|---|
| 单页精华版 | 1 页 | 一页纸汇报、功能速览、电梯演讲 | 核心卖点 + 关键指标 |
| 标准版 | 7-12 页 | 产品介绍、项目汇报、方案评审 | 封面 + 概览 + 功能详解 + 架构 + 数据 + 总结 |
| 完整版 | 17-23 页 | 正式提案、年度汇报、深度技术方案 | 全面覆盖背景、现状、方案、细节、规划、附录 |
所有 PPT 统一使用公司模板,不做主题选择。此模板来源于 DOA-WorkCopilot Skill 产品介绍 PPT 的实际设计成果。
#### 视觉方向
#EDE5F8 → #CDD3EC),保持明亮通透deco-circle 渐变圆点缀右上角,不与内容争夺视线#### 配色体系
| 用途 | 变量 | 色值 |
|---|---|---|
| 主色 | --primary | #4C78FF |
| 主色深 | --primary-dark | #3B32D4 |
| 主色浅 | --primary-soft | #EEF1FF |
| 辅助青 | --accent | #46B6FF |
| 品牌紫 | --purple | #9D6BFF |
| 品牌橙 | --amber | #F2B27C |
| 品牌粉 | --red | #F062C0 |
| 品牌绿 | --green | #58BFC8 |
| 文字主色 | --text-primary | #1E1842 |
| 文字次色 | --text-secondary | #4A4567 |
| 文字辅助 | --text-muted | #7D78A0 |
| 边框 | --border | rgba(141, 136, 208, 0.24) |
#### 页面级背景策略
| 页面类型 | 背景 |
|---|---|
| HTML body 背景(浏览器预览区) | linear-gradient(135deg, #EDE5F8 0%, #DDD8F0 30%, #D5D6EE 60%, #CDD3EC 100%) |
| 所有幻灯片统一底色 | linear-gradient(90deg, #EDE5F8 0%, #DDD8F0 35%, #D5D6EE 65%, #CDD3EC 100%) |
| 底部色条 | linear-gradient(90deg, var(--accent), var(--primary), var(--purple), var(--red)) |
硬性要求:body背景色禁止使用深色(如#1a1a2e),必须使用浅紫到浅蓝的渐变色,与幻灯片底色保持视觉一致。公司模板不在页面间做深浅分层,所有页面使用同一底色。通过"球体+玻璃"装饰强度区分页面类型。
#### 核心装饰母题:紫色球体 + 轨道环 + 玻璃菱形
三类页面(封面、章节页、结尾页)共享同一组视觉元素,通过位置和大小变化营造统一感:
球体(3D 渐变紫色圆球):
background: radial-gradient(circle at 38% 32%, #A480F0, #6535D9 55%, #4520B0);
box-shadow: 0 28px 80px rgba(91,48,215,.35);轨道环(两层同心圆细线):
border: 1px solid rgba(180,175,210,.3); /* 内环 */
border: 1px solid rgba(180,175,210,.18); /* 外环,更淡 */玻璃矩形(旋转 50° 的毛玻璃矩形,带左侧渐变边线):
background: linear-gradient(160deg, rgba(255,255,255,.48), rgba(245,240,255,.25), rgba(230,220,250,.10));
border: 1.5px solid rgba(255,255,255,.50);
backdrop-filter: blur(14px);
transform: rotate(50deg);
border-radius: 24px;/* 左侧渐变边线 */
.cover-glass1::before {
content:''; position:absolute; top:20px; bottom:20px; left:-2px;
width:3px; border-radius:99px;
background:linear-gradient(180deg, #9D6BFF, #6BB8FF);
}装饰圆点(三种颜色点缀):
linear-gradient(135deg, #6BB8FF, #46B6FF)linear-gradient(135deg, #FF6BA0, #FF4081)radial-gradient(circle at 35% 30%, #C4A0FA, #7E50DE 80%)斜切装饰线(极淡渐变线):
background: linear-gradient(90deg, transparent, rgba(76,120,255,.15), rgba(157,107,255,.20));
transform: rotate(-30deg);#### 封面页规范
.cover-logo { left: 28px } — Logo 紧靠左侧.cover-content { padding: 0 48px } — 标题/副标题/作者信息.cover-bottom { left: 48px } — 底部网址和品牌名right:130px; top:60px,z-index:3 background: radial-gradient(circle at 38% 32%, #B898FA, #8050F0 40%, #6030D8 65%, #4A20C0);
box-shadow: 0 32px 90px rgba(91,48,215,.28);z-index:1right:130px; top:40px,border: 1px solid rgba(180,175,210,.25)right:80px; top:-10px,border: 1px solid rgba(180,175,210,.15)rotate(50deg),right:50px; top:300px,z-index:4(在球体前面,半透明覆盖) background: linear-gradient(160deg, rgba(255,255,255,.48), rgba(245,240,255,.25), rgba(230,220,250,.10));
border: 1.5px solid rgba(255,255,255,.50);
backdrop-filter: blur(14px);
border-radius: 24px;::before 伪元素) .cover-glass1::before { position:absolute; top:20px; bottom:20px; left:-2px; width:3px; border-radius:99px; background:linear-gradient(180deg, #9D6BFF, #6BB8FF); }left:130px; top:140px,在左侧空白区right:580px; top:130px,在轨道环上left:-6px; top:380px,半隐藏在页面左边缘right:50px; top:60px,18px 淡紫色,z-index:5width:900px; rotate(-25deg); left:-100px; bottom:60px--primary-dark → --primary → --red)--purple → --accent → --green)top:32px; left:28px,z-index:5bottom:24px; left:48px; right:48px,左侧网址链接,右侧 "Medalsoft"<div class="slide cover active" data-index="0">
<div class="cover-ring-o2"></div>
<div class="cover-ring-o1"></div>
<div class="cover-glass1"></div>
<div class="cover-sphere"></div>
<div class="cover-dot1"></div><div class="cover-dot2"></div><div class="cover-dot3"></div>
<div class="cover-x">×</div>
<div class="cover-line"></div>
<div class="cover-content">
<div class="cover-logo">...</div>
<div class="cover-title">产品名称<br><span>子标题</span></div>
<div class="cover-subtitle">描述文字</div>
<div class="cover-meta">作者 · 公司 · 日期</div>
</div>
<div class="cover-bottom"><a href="#">www.medalsoft.com</a><span>Medalsoft</span></div>
</div>#### 章节分隔页规范(标题页)
章节分隔页是 PPT 必备页面类型,每个主要章节前必须有一张。球体 + 轨道环 + 毛玻璃面板三要素缺一不可。
目录条目与章节分隔页 1:1 对应(强制):目录页有 N 个条目,就必须有 N 个章节分隔页。例如目录 8 个条目编号 1-8,则必须有 8 个分隔页(sd-num 为 01-08),每个分隔页的标题必须与目录中对应条目的标题一致。不允许"只给部分章节加分隔页"——这会让读者在翻页时失去节奏感。
left:210px; top:220pxwidth:fit-content,padding-left:160px; padding-right:50px .sd-glass {
background: linear-gradient(155deg, rgba(255,255,255,.46), rgba(210,200,240,.12));
border: 1px solid rgba(255,255,255,.50);
backdrop-filter: blur(6px);
border-radius: 24px;
}#2E1A6E.slide.section-divider::after { display:none; }.sd-num 数字必须等于目录页中对应条目的序号。例如目录第 2 项“认知革命”,则该章节分隔页显示 02,而不是独立从 01 开始计数。目录页描述文字也必须与对应内容页的标题一致,不得出现通用词糊弄。<div class="slide section-divider">
<div class="sd-ring r2"></div>
<div class="sd-ring r1"></div>
<div class="sd-sphere"></div>
<div class="sd-num">01</div>
<div class="sd-glass"><div class="sd-glass-title">章节标题</div></div>
<div class="sd-dot pink"></div>
<div class="sd-dot purple"></div>
<div class="sd-dot blue"></div>
</div>#### 结尾页规范
top:32px; left:28px(与封面完全一致),z-index:5left:50px; top:100px,z-index:3 background: radial-gradient(circle at 38% 32%, #B898FA, #8050F0 40%, #6030D8 65%, #4A20C0);
box-shadow: 0 32px 90px rgba(91,48,215,.28);z-index:1left:-10px; top:40px,border: 1px solid rgba(180,175,210,.25)left:-60px; top:-10px,border: 1px solid rgba(180,175,210,.15)rotate(28deg),left:450px; top:60px,z-index:4(在球体上面)::after 伪元素)::before 隐藏) .ending-glass {
width: 1100px; height: 600px;
background: linear-gradient(160deg, rgba(255,255,255,.48), rgba(245,240,255,.25), rgba(230,220,250,.10));
border: none;
backdrop-filter: blur(10px);
transform: rotate(28deg);
border-radius: 0 0 24px 24px;
overflow: hidden;
}
/* 左侧渐变边线隐藏 */
.ending-glass::before { display: none; }
/* 底部渐变色条(粉→紫→蓝) */
.ending-glass::after {
content: ''; position: absolute; bottom: 0; left: 0; right: 0;
height: 2px;
background: linear-gradient(90deg, #E95BC2, #8050F0, #3DA5FF);
border-radius: 0 0 24px 24px;
}left:50px; top:100px,在 Logo 下方right:60px; top:140px,在右侧right:50px; top:60px,18px 淡紫色width:1000px; rotate(-25deg); left:0px; bottom:60pxlinear-gradient(180deg, #E95BC2, #3F2FD7)),居右bottom:24px; left:48px; right:48px,左侧 "Medalsoft",右侧日期<div class="slide ending" data-index="最后">
<div class="ending-ring2"></div><div class="ending-ring1"></div>
<div class="ending-glass"></div><div class="ending-sphere"></div>
<div class="ending-dot-pink"></div><div class="ending-dot-blue"></div>
<div class="ending-x">×</div>
<div class="ending-line"></div>
<div class="ending-logo-area">
<div class="ending-logo-swo"></div>
<div class="ending-logo-divider"></div>
<div class="ending-logo-medalsoft"></div>
</div>
<div class="ending-content">
<div class="ending-copy">
<div class="ending-title">THANK<br>YOU</div>
</div>
</div>
<div class="ending-bottom"><span>Medalsoft</span><span>日期</span></div>
</div>#### 内容页组件规范
页眉:左侧微钉小图标 Medaslsoft_Sample.png(32×32px)+ 标题(34px/800),右侧双品牌 Logo。页眉下方 120px 蓝紫渐变色条。
卡片:圆角 20px,白色半透明(.94/.84),双层边框 + 柔和阴影,backdrop-filter:blur(10px)。
终端代码块:深色 #1A1730,带红黄绿三色窗口按钮,代码用 JetBrains Mono,高亮色:蓝 #7dd3fc、绿 #86efac、紫 #c4b5fd。
照片框:圆角 16px,底部渐变遮罩 + 白色说明文字。
表格:表头渐变紫 linear-gradient(135deg, #6D79C8, #7E6ED7),白底行,圆角 14px。
Before/After 对比列:粉色(Before)vs 青色(After),用 justify-content:space-evenly 均匀分布条目。
提示框:白色毛玻璃底,左侧 3px 蓝色竖线,圆角 16px。
流程步骤:48px 渐变圆球 + 连接线 + 文字标签,颜色从蓝到绿到紫渐变。
标签 pill:5 种颜色变体(green/amber/purple/red/blue),圆角 99px。
页脚:左 "SoftwareOne | 微钉科技",右页码(圆角胶囊式,白底紫文字)。
目录条目(毛玻璃卡片式):每个目录项为一张全宽毛玻璃卡片,左侧标题+描述,右侧编号圆球。必须还原毛玻璃效果。
.toc-item {
display: flex; align-items: center; justify-content: space-between;
gap: 16px; padding: 16px 24px;
background: linear-gradient(155deg, rgba(255,255,255,.46), rgba(210,200,240,.12));
border: 1px solid rgba(255,255,255,.50);
backdrop-filter: blur(6px);
border-radius: 16px;
transition: all .3s;
}
.toc-item:hover { box-shadow: var(--shadow); transform: translateY(-2px); }
.toc-num {
width: 44px; height: 44px; border-radius: 50%;
background: linear-gradient(135deg, var(--primary), var(--purple));
color: white; font-size: 16px; font-weight: 800;
display: flex; align-items: center; justify-content: center;
flex-shrink: 0;
box-shadow: 0 4px 16px rgba(76,120,255,.25);
}
.toc-text { font-size: 18px; font-weight: 700; color: var(--primary-dark); }
.toc-desc { font-size: 14px; color: var(--text-muted); margin-top: 4px; }目录页推荐结构(根据条目数量自动选择布局):
布局规则(强制): - ≤ 5 个条目:单列堆叠布局,display:flex;flex-direction:column;gap:12px- 6-8 个条目:双列网格布局,grid-2,每列 3-4 个条目,每个条目加flex:1使同列条目等高 - 超过 8 个:拆分为多个目录页,或精简章节结构
>
禁止在单列布局中塞入超过 5 个条目——必定导致溢出或压缩到无法阅读的尺寸。
<div class="slide" data-index="1">
<div class="header">
<div class="header-left"><div class="header-dot"></div><div class="page-title">目录</div></div>
<div class="header-brand"><span class="logo-text">品牌名</span></div>
</div>
<div class="content" style="display:flex;flex-direction:column;gap:12px;padding-top:16px;">
<div class="toc-item">
<div><div class="toc-text">章节标题</div><div class="toc-desc">简要描述</div></div>
<div class="toc-num">1</div>
</div>
<!-- 更多条目... -->
</div>
<div class="page-footer"><span>品牌名</span><span class="page-no">02 / N</span></div>
</div>关键:.toc-item必须使用backdrop-filter: blur(6px)+ 半透明白色渐变背景实现毛玻璃效果,不要用纯白卡片。编号圆球放在右侧(justify-content: space-between),而非左侧。
#### 动画规范
#### 实战踩坑要点
padding-right:50px 控制右侧留白<div> + flex-direction:column; justify-content:space-evenly,避免底部大片空白flex:1 撑满,避免左右不等高<table style="flex:1"> 生效单页精华版(1 页):
标准版(7-12 页):
完整版(17-23 页):
基于收集的需求和确认的规模,使用公司模板生成一个可左右翻页的 HTML 文件,模拟幻灯片放映效果。
所有页面合并为一个 `slides.html` 文件,内置翻页交互:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>PPT 预览</title>
<style>
/* 主题 CSS 变量(根据选定主题填充) */
:root { ... }
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
background: linear-gradient(135deg, #EDE5F8 0%, #DDD8F0 30%, #D5D6EE 60%, #CDD3EC 100%);
display: flex; justify-content: center; align-items: center;
min-height: 100vh; font-family: 'Noto Sans SC', sans-serif;
overflow: hidden;
}
/* 幻灯片容器 */
.slides-viewport {
position: relative;
width: 1280px; height: 720px;
overflow: hidden; border-radius: 8px;
box-shadow: 0 20px 60px rgba(0,0,0,0.3);
}
.slide {
position: absolute; top: 0; left: 0;
width: 1280px; height: 720px;
opacity: 0; transform: translateX(100px);
transition: all 0.5s cubic-bezier(0.4, 0, 0.2, 1);
pointer-events: none;
}
.slide.active {
opacity: 1; transform: translateX(0);
pointer-events: auto;
}
.slide.exit-left {
opacity: 0; transform: translateX(-100px);
}
/* 导航控件 */
.nav-btn {
position: fixed; top: 50%; transform: translateY(-50%);
width: 50px; height: 50px; border-radius: 50%;
background: rgba(255,255,255,0.5); border: none;
color: #4A4567; font-size: 24px; cursor: pointer;
backdrop-filter: blur(10px);
transition: background 0.3s;
z-index: 100;
}
.nav-btn:hover { background: rgba(255,255,255,0.7); }
.nav-btn.prev { left: 30px; }
.nav-btn.next { right: 30px; }
.nav-btn:disabled { opacity: 0.3; cursor: not-allowed; }
/* 页码指示器 */
.page-indicator {
position: fixed; bottom: 30px; left: 50%;
transform: translateX(-50%);
display: flex; gap: 8px; z-index: 100;
}
.page-dot {
width: 10px; height: 10px; border-radius: 50%;
background: rgba(76,120,255,0.25);
cursor: pointer; transition: all 0.3s;
}
.page-dot.active {
background: #4C78FF; transform: scale(1.3);
}
/* 键盘提示 */
.keyboard-hint {
position: fixed; bottom: 60px; left: 50%;
transform: translateX(-50%);
color: rgba(74,69,103,0.4); font-size: 13px;
}
transform: translateX(-50%);
display: flex; gap: 8px; z-index: 100;
}
.page-dot {
width: 10px; height: 10px; border-radius: 50%;
background: rgba(76,120,255,0.25);
cursor: pointer; transition: all 0.3s;
}
.page-dot.active {
background: #4C78FF; transform: scale(1.3);
}
/* 键盘提示 */
.keyboard-hint {
position: fixed; bottom: 60px; left: 50%;
transform: translateX(-50%);
color: rgba(74,69,103,0.4); font-size: 13px;
}
</style>
</head>
<body>
<div class="slides-viewport">
<div class="slide active" data-index="0">
<!-- 第 1 页内容 -->
</div>
<div class="slide" data-index="1">
<!-- 第 2 页内容 -->
</div>
<!-- ... 更多页面 ... -->
</div>
<button class="nav-btn prev" onclick="navigate(-1)">‹</button>
<button class="nav-btn next" onclick="navigate(1)">›</button>
<div class="page-indicator">
<!-- JS 动态生成 -->
</div>
<div class="keyboard-hint">← → 方向键翻页 | 点击圆点跳转</div>
<script>
let current = 0;
const slides = document.querySelectorAll('.slide');
const total = slides.length;
const indicator = document.querySelector('.page-indicator');
const prevBtn = document.querySelector('.nav-btn.prev');
const nextBtn = document.querySelector('.nav-btn.next');
// 生成页码圆点
for (let i = 0; i < total; i++) {
const dot = document.createElement('div');
dot.className = 'page-dot' + (i === 0 ? ' active' : '');
dot.onclick = () => goTo(i);
indicator.appendChild(dot);
}
function goTo(index) {
if (index < 0 || index >= total || index === current) return;
const dir = index > current ? 1 : -1;
if (dir > 0) slides[current].classList.add('exit-left');
slides[current].classList.remove('active');
current = index;
slides[current].classList.remove('exit-left');
slides[current].classList.add('active');
updateControls();
}
function navigate(dir) { goTo(current + dir); }
function updateControls() {
prevBtn.disabled = current === 0;
nextBtn.disabled = current === total - 1;
document.querySelectorAll('.page-dot').forEach((d, i) =>
d.className = 'page-dot' + (i === current ? ' active' : '')
);
}
// 键盘导航
document.addEventListener('keydown', (e) => {
if (e.key === 'ArrowLeft') navigate(-1);
if (e.key === 'ArrowRight') navigate(1);
});
updateControls();
</script>
</body>
</html>每个 .slide div 内部是完整的幻灯片内容,与之前的单页 HTML 结构一致。所有页面共享同一套 CSS 变量和样式。
#### 封面页:简洁美观
#### 内容页:详实丰富、图文搭配
#### 图文结合的反 AI 味准则(强制)
核心原则:从第一稿开始,每个内容页都必须图文结合,使用真实图片(联网搜索或用户提供),严禁 Emoji 图标,严禁纯文字页面。不要先用 Emoji 占位再让用户修改——第一版就必须到位。
.icon-bar 组件: <div class="icon-bar">
<span class="ib" style="background:var(--primary);">审</span>
<span class="ib" style="background:var(--purple);">核</span>
<span class="ib" style="background:var(--green);">验</span>
</div>.ib 样式:display:inline-flex; width:28px; height:28px; border-radius:7px; color:#fff; font-size:13px; font-weight:700; align-items:center; justify-content:center;
左文右图、上图下结论、大图 + 侧栏摘要、主图 + 底部指标条 这类结构,避免平均分配成四宫格信息墙。#### 图片素材获取与回退策略(强制)
图片是内容页质量的决定性因素,必须主动获取,不能跳过。
##### 有联网能力时(默认流程)
output/<项目名>/images/ 目录,HTML 中使用相对路径 images/xxx.jpg 引用,不依赖外部 URL。https://images.unsplash.com/photo-xxx?w=800),备选 Pexels。某张图 404 时立即换另一张同主题图,不要阻塞流程。##### 无联网能力时(回退流程)
output/<项目名>/images/ 文件夹"。 images/cover.jpg — 书籍封面或主题封面照
images/scene_01.jpg — 第一章节主题配图
images/scene_02.jpg — 第二章节主题配图
...##### 通用规则
#### 图文分栏布局标准模式(强制)
所有内容页必须使用图文分栏布局。不允许任何内容页只有纯文字/纯表格而没有图片。
内容页标准结构为 左文右图 flex 分栏:
<div class="content" style="display:flex;gap:20px;align-items:stretch;">
<!-- 左侧:文字/卡片/表格 -->
<div style="flex:1;display:flex;flex-direction:column;min-width:0;min-height:0;">
<!-- 内容区 -->
<div class="highlight-box" style="margin-top:auto;padding:8px 14px;">
<p style="font-size:12px;margin:0;"><strong>总结文字</strong></p>
</div>
</div>
<!-- 右侧:图片面板 -->
<div class="screenshot-panel" style="flex:0 0 340px;overflow:hidden;min-height:0;padding:0;">
<img src="images/xxx.jpg" style="width:100%;height:100%;object-fit:cover;border-radius:14px;" alt="描述">
</div>
</div>##### 关键规则
| 项目 | 规则 | 原因 |
|---|---|---|
| flex 容器 | display:flex;gap:20px;align-items:stretch | stretch 让左右等高 |
| 左侧内容区 | flex:1;display:flex;flex-direction:column;min-width:0;min-height:0 | min-height:0 防止内容撑破容器 |
| 右侧图片面板 | flex:0 0 300~400px;overflow:hidden;min-height:0;padding:0 | 固定宽度,padding:0 覆盖默认值 |
| 图片样式 | width:100%;height:100%;object-fit:cover;border-radius:14px | cover 填满面板,不留白边 |
| 底部摘要 | margin-top:auto 推到底部 | 消除中间空白 |
##### 不同页面类型的图片面板宽度建议
| 页面类型 | 图片面板 flex-basis | 说明 |
|---|---|---|
| 常规文字+卡片 | flex:0 0 400px | 文字少图片大 |
| 数据表格(单表) | flex:0 0 340px | 表格需要更多宽度 |
| 数据表格(双表/密集) | flex:0 0 300px | 给表格让出更多空间 |
| 产品截图(精确展示) | flex:1(与文字等宽) | 截图需要大面积 |
##### 产品截图 vs 背景配图
| 类型 | 来源 | 用途 | 样式差异 |
|---|---|---|---|
| 产品截图 | Playwright 截图 + 裁剪 | 精确展示界面功能 | object-fit:contain,保留白底,加 box-shadow 和 border |
| 背景配图 | Unsplash/Pexels 联网下载 | 视觉氛围、主题烘托 | object-fit:cover,铺满面板,padding:0 |
##### 表格页图文分栏示例
数据密集的表格页也必须有图片,做法是缩窄表格列宽 + 减小字号:
<div class="content" style="display:flex;gap:20px;align-items:stretch;">
<div style="flex:1;display:flex;flex-direction:column;min-width:0;">
<table class="cmp-table" style="flex:1;font-size:13px;">
<thead><tr><th style="width:50px;">编号</th><th style="width:120px;">名称</th><th>描述</th><th style="width:70px;">等级</th></tr></thead>
<tbody><!-- 数据行 --></tbody>
</table>
<div class="highlight-box" style="margin-top:auto;padding:8px 14px;">
<p style="font-size:12px;margin:0;"><strong>总结</strong></p>
</div>
</div>
<div class="screenshot-panel" style="flex:0 0 340px;overflow:hidden;min-height:0;padding:0;">
<img src="images/bg_theme.jpg" style="width:100%;height:100%;object-fit:cover;border-radius:14px;" alt="主题图">
</div>
</div>#### 内容间距规范(强制)
不同内容块之间必须有可见间距,禁止紧贴在一起。
| 元素 | 间距规则 | CSS |
|---|---|---|
| 表格行间距 | 每行之间留 8px 间距 | border-spacing: 0 8px; |
| 卡片之间 | 卡片之间留 12-16px 间距 | gap: 12px 或 gap: 16px |
| 标题与内容 | 标题下方留 10-12px | margin-bottom: 10px |
| 内容与底部摘要 | 自动推到底部 | margin-top: auto |
| 左右分栏间隔 | 左侧内容与右侧图片之间 | gap: 20px |
| 图文分栏内部 | 左列内部元素之间 | gap: 10px |
| 全宽表格 td | 单元格内边距 | padding: 14px 16px |
##### 表格行间距实现
.cmp-table {
border-spacing: 0 8px; /* 行间距 8px */
border-collapse: separate; /* 必须用 separate 才能生效 */
}
.cmp-table td {
padding: 14px 16px; /* 单元格内边距 */
}##### 禁止的紧凑写法
border-spacing: 0 或 border-collapse: collapse 导致行间无间距gap: 0 或无 gap 导致卡片紧贴highlight-box 或提示框之间无 margin 导致视觉糊在一起#### 多元素对称与布局规范
1280×720 幻灯片安全区域.grid-2 的内容页,左右两列底部必须对齐,禁止出现一侧比另一侧短、底部留有大片空白的情况。通过 flex:1 让卡片/表格自动拉伸填满每页 HTML 尺寸固定:width: 1280px; height: 720px(16:9)
#### 封面页布局
┌─────────────────────────────────────────────┐
│ [SWO Logo] | [微钉Logo] ← 左上角 │
│ [装饰图] ← 右上角 │
│ 主标题(大号加粗渐变) │
│ 副标题 │
│ 补充信息 │
│ │
└─────────────────────────────────────────────┘#### 内容页布局(左右分栏)
┌─────────────────────────────────────────────┐
│ ● 页面标题 [SWO Logo]|[微钉Logo] │
│ ──── │
│ 左侧(文字描述 + 卡片) │ 右侧(图/预览) │
│ ← flex:1 等高拉伸 → │ ← flex:1 等高 → │
│─────────────────────────────────────────────│
│ SoftwareOne | 微钉科技 02 / 20 │
└─────────────────────────────────────────────┘#### 内容页布局(全宽)
┌─────────────────────────────────────────────┐
│ ● 页面标题 [SWO Logo]|[微钉Logo] │
│ ──── │
│ 3-4 列并排卡片 / 流程图 / 架构图 │
│ │
│─────────────────────────────────────────────│
│ SoftwareOne | 微钉科技 03 / 20 │
└─────────────────────────────────────────────┘#### 总结页 / Q&A 页布局
┌─────────────────────────────────────────────┐
│ [装饰图] ← 右上角 │
│ [SWO Logo] | [微钉Logo] │
│ 产品名称 │
│ 副标题描述 │
│ [数据统计卡片] (可选) │
│ Thank You & Q&A │
└─────────────────────────────────────────────┘font-size: 17px; line-height: 1.7,确保在 1280×720 画布和投影场景下清晰可读Noto Sans SC 中文 + 一款英文字体)--primary, --primary-light, --accent 等)width: 1280px; min-height: 720pxborder-left 色条、圆角、轻阴影slides.html 文件(内置翻页交互,所有幻灯片在同一个文件中)保存到用户工作目录,提示用户在浏览器中预览,根据反馈迭代调整。
slides.html 后,必须逐页检查每一页是否存在越界、裁切、遮挡、重叠、贴边或导航控件压住正文的问题逐页至少检查以下项目:
1280×720 安全区域内如果任一项不满足,返回 HTML 调整步骤,不得继续生成 PPT
只有在同时满足以下两个条件后,才允许进入此步骤:
进入此步骤前,使用 vscode_askQuestions 或用户明确文本确认,拿到类似以下结论之一:
按当前 HTML 生成 PPTHTML 没问题,可以导出就用这个版本生成拿到确认后,再使用 vscode_askQuestions 工具让用户选择导出格式和模式:
#### 导出格式选择
使用 vscode_askQuestions 让用户选择输出格式:
| 格式 | 说明 | 适用场景 |
|---|---|---|
| PPTX(默认推荐) | 生成 .pptx 演示文稿 | 需要在 PowerPoint 中放映或编辑 |
| 生成 .pdf 文档 | 只读分发、邮件附件、打印 | |
| 都要 | 同时生成 .pptx 和 .pdf | 既要放映也要分发 |
#### PPT 生成模式选择(仅 PPTX 格式时)
默认推荐:截图高保真 PPT。 只有在用户明确要求“后续需要在 PowerPoint 里继续改字、改布局、改单页内容”时,才优先选择可编辑模式。
| 模式 | 说明 | 优点 | 缺点 |
|---|---|---|---|
| 截图高保真模式 | 将每页 HTML 截图为图片插入 PPT | 还原度 100%,与 HTML 完全一致,最适合作为默认推荐 | 内容不可编辑,文件体积较大 |
| 可编辑模式 | python-pptx 逐元素重建 | 文字/形状均可编辑,灵活修改 | 还原度约 85-90%,复杂布局可能有偏差 |
#### 导出模式切换规则(新增)
将每页 HTML 幻灯片截图为高清图片,再逐张插入 PPT 作为全页背景图。
#### 截图转换参考模板
读取 references/screenshot-pptx-template.py 获取完整的截图转 PPT 脚本模板。
该模板包含:
capture_slides() — Playwright 逐页截图(2x 高清)build_pptx() — 截图插入 PPT 全屏背景auto_detect_total() — 自动检测 HTML 中幻灯片总数HTML_FILE 和 OUTPUT_PPTX 路径即可运行#### 截图时隐藏导航控件(强制要求)
不管输出 PPTX 还是 PDF,只要使用截图方式,必须在截图前通过 JS 隐藏所有导航控件(左右箭头、页码圆点、键盘提示),避免遮挡幻灯片内容:
// 在页面加载完成后、开始截图前执行
document.querySelectorAll('.nav-btn, .page-indicator, .keyboard-hint')
.forEach(el => el.style.display = 'none');模板脚本 screenshot-pptx-template.py 已内置此逻辑。自定义脚本也必须包含此步骤。
#### 截图高保真执行步骤
前置条件:HTML 已逐页检查通过,且用户已明确确认可导出。
pip install python-pptx playwright,然后 playwright install chromium使用 python-pptx 库将 HTML 内容逐元素映射为 PPT 原生对象。
读取 references/pptx-converter-template.py 获取完整的可编辑 PPT 转换脚本模板和工具函数库。
该模板包含:
add_rounded_rect() — 圆角矩形(支持圆角半径调整)add_text_box() — 文本框(支持字体、颜色、对齐、垂直锚点)add_multiline_text() — 多行文本段落add_rich_paragraph() — 富文本(多 run,混合粗体/颜色)add_circle() — 圆形形状set_slide_bg() — 幻灯片背景色Inches(13.333) × Inches(7.5)(16:9 宽屏)prs.slide_layouts[6]a:avLst 的 adj 值控制圆角半径run 实现粗体/颜色混排bodyPr 的 anchor='ctr' 实现前置条件:HTML 已逐页检查通过,且用户已明确确认可导出。
python-pptx 已安装:pip install python-pptxbuild_slideN() 函数,共享颜色常量和工具函数,主函数循环调用将每页 HTML 幻灯片截图为高清图片,再使用 reportlab 合并为 PDF 文档。
#### PDF 导出执行步骤
前置条件:HTML 已逐页检查通过,且用户已明确确认可导出。
pip install playwright reportlab,然后 playwright install chromium# 方式 A:Pillow(最简洁,推荐)
from PIL import Image
images = [Image.open(s).convert('RGB') for s in screenshots]
images[0].save(output_pdf, save_all=True, append_images=images[1:], resolution=144.0)
# 方式 B:reportlab(精确控制页面尺寸)
from reportlab.pdfgen import canvas
page_w = VIEWPORT_W * DEVICE_SCALE # 2560
page_h = VIEWPORT_H * DEVICE_SCALE # 1440
c = canvas.Canvas(output_pdf, pagesize=(page_w, page_h))
for img_path in screenshots:
c.drawImage(img_path, 0, 0, width=page_w, height=page_h)
c.showPage()
c.save()两种方式均可:Pillow 方式代码最简但页面尺寸由图片分辨率决定;reportlab 方式可精确控制 PDF 页面尺寸。如果同时导出 PPTX + PDF,截图只需做一次,分别喂给两个构建函数。
| HTML 元素 | PPT 实现 |
|---|---|
| 渐变背景 | 纯色 RGBColor 近似 |
border-left 色条 | MSO_SHAPE.RECTANGLE 窄矩形 |
| 圆角卡片 | MSO_SHAPE.ROUNDED_RECTANGLE + avLst |
| 图标 emoji | add_text_box() 文本框放 emoji |
| 富文本(粗体/链接色) | 多个 run 设置不同 font 属性 |
| 输入框 | 圆角矩形 + 文本框叠加 |
| 分隔线 | 极窄矩形 height=Pt(1.5) |
| 圆形头像/状态点 | MSO_SHAPE.OVAL |
| 底部指标横幅 | 圆角矩形 + 居中文本框 |
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.