从零创建精美的动画 HTML 演示文稿,或转换 PowerPoint 文件。用户需要构建演示文稿、转换 PPT/PPTX 为网页、或为演讲/路演创建幻灯片时使用
前端幻灯片技能是一项面向实际任务的技能,主要用于创建零依赖、动画丰富的 HTML 演示文稿,完全在浏览器中运行;此技能帮助非设计师通过视觉探索("展示,而非告知")发现自己的审美偏好,然后生成生产质量的幻灯片;
生成视觉预览,而非抽象选择;独特设计 — 避免通用的"AI 生成。它将相关步骤、工具调用和结果整理方式集中到统一流程中,帮助使用者更快完成目标并减少重复操作。从功能定位来看,该技能强调把分散的操作要求整理成清晰、可复用的处理流程,使用户能够围绕既定目标快速准备输入、选择执行方式并获得结构化结果。
实际使用前应先确认任务范围、数据来源、运行环境、必要权限和关键参数,再依据技能说明逐步执行;若输入条件不完整,应先补齐信息或采用保守配置,避免因错误假设导致结果偏离需求。执行过程中需要关注工具调用是否成功、接口或依赖是否可用、输出格式是否符合预期,并对异常提示、缺失字段和边界情况进行处理;涉及批量任务时,还应保存进度,避免中断后重复操作。
创建零依赖、动画丰富的 HTML 演示文稿,完全在浏览器中运行。此技能帮助非设计师通过视觉探索("展示,而非告知")发现自己的审美偏好,然后生成生产质量的幻灯片。
首先,确定用户想要什么:
模式 A:新建演示文稿
模式 B:PPT 转换
模式 C:改进现有演示文稿
在设计之前,先了解内容。通过 AskUserQuestion 进行询问:
问题 1:用途
问题 2:幻灯片数量
问题 3:内容
如果用户有内容,请他们分享(文字、要点、图片等)。
关键:这是"展示,而非告知"阶段。
大多数人无法用语言表达设计偏好。我们不是问"你想要极简还是大胆?",而是生成迷你预览让他们做出反应。
问题 1:感受
根据他们的情绪选择,在临时目录中生成 3 种不同的风格预览 作为迷你 HTML 文件。每个预览应是一张标题幻灯片,展示:
基于情绪考虑的风格(选 3 种):
| 情绪 | 风格选项 |
|---|---|
| 印象深刻/自信 | "商务优雅", "深色高管", "简洁极简" |
| 兴奋/充满活力 | "霓虹赛博", "大胆渐变", "动态运动" |
| 平静/专注 | "纸墨风格", "柔和淡雅", "瑞士极简" |
| 受到启发/深受感动 | "电影深色", "温暖编辑", "氛围感" |
重要:永远不要使用这些通用模式:
取而代之,使用独特的选择:
在 .claude-design/slide-previews/ 中创建预览:
.claude-design/slide-previews/ ├── style-a.html # 第一种风格选项 ├── style-b.html # 第二种风格选项 ├── style-c.html # 第三种风格选项 └── assets/ # 共享资源
每个预览文件应:
向用户展示:
我已为你创建了 3 种风格预览供你比较: **风格 A:[名称]** — [一句话描述] **风格 B:[名称]** — [一句话描述] **风格 C:[名称]** — [一句话描述] 打开每个文件查看实际效果: - .claude-design/slide-previews/style-a.html - .claude-design/slide-previews/style-b.html - .claude-design/slide-previews/style-c.html 看一看,告诉我: 1. 哪种风格最打动你? 2. 你喜欢它的哪些方面? 3. 有什么想改变的吗?
然后使用 AskUserQuestion:
问题:选择你的风格
如果选择"混合元素",询问具体需求。
现在基于以下内容生成完整的演示文稿:
对于单份演示文稿:
presentation.html # 自包含演示文稿 assets/ # 图片(如有)
对于包含多份演示文稿的项目:
[presentation-name].html [presentation-name]-assets/
所有演示文稿遵循以下结构:
演示文稿标题
每份演示文稿应包括:
SlidePresentation 类 — 主控制器
Intersection Observer — 用于滚动触发的动画
.visible 类可选增强(基于风格):
注释: 每个部分应有清晰注释,说明:
/* ===========================================
自定义光标
创建跟随鼠标的样式化光标,带轨迹效果。
- 使用 lerp(线性插值)实现平滑移动
- 悬停在交互元素上时变大
=========================================== */
class CustomCursor {
constructor() {
// ...
}
}
可访问性:
, , )@media (prefers-reduced-motion: reduce) {
.reveal {
transition: opacity 0.3s ease;
transform: none;
}
}
响应式:
@media (max-width: 768px) {
.nav-dots,
.keyboard-hint {
display: none;
}
}
转换 PowerPoint 文件时:
使用 Python 和 python-pptx 提取:
from pptx import Presentation
from pptx.util import Inches, Pt
import json
import os
import base64
def extract_pptx(file_path, output_dir):
"""
从 PowerPoint 文件中提取所有内容。
返回包含幻灯片、文本和图片的 JSON 结构。
"""
prs = Presentation(file_path)
slides_data = []
# 创建资源目录
assets_dir = os.path.join(output_dir, 'assets')
os.makedirs(assets_dir, exist_ok=True)
for slide_num, slide in enumerate(prs.slides):
slide_data = {
'number': slide_num + 1,
'title': '',
'content': [],
'images': [],
'notes': ''
}
for shape in slide.shapes:
# 提取标题
if shape.has_text_frame:
if shape == slide.shapes.title:
slide_data['title'] = shape.text
else:
slide_data['content'].append({
'type': 'text',
'content': shape.text
})
# 提取图片
if shape.shape_type == 13: # 图片
image = shape.image
image_bytes = image.blob
image_ext = image.ext
image_name = f"slide{slide_num + 1}_img{len(slide_data['images']) + 1}.{image_ext}"
image_path = os.path.join(assets_dir, image_name)
with open(image_path, 'wb') as f:
f.write(image_bytes)
slide_data['images'].append({
'path': f"assets/{image_name}",
'width': shape.width,
'height': shape.height
})
# 提取备注
if slide.has_notes_slide:
notes_frame = slide.notes_slide.notes_text_frame
slide_data['notes'] = notes_frame.text
slides_data.append(slide_data)
return slides_data
将提取的内容呈现给用户:
我已从你的 PowerPoint 中提取了以下内容: **幻灯片 1:[标题]** - [内容摘要] - 图片:[数量] **幻灯片 2:[标题]** - [内容摘要] - 图片:[数量] ... 所有图片已保存到 assets 文件夹。 看起来是否正确?我可以继续进行风格选择吗?
进入阶段 2(风格发现),同时考虑提取的内容。
将提取的内容转换为所选风格,保留:
演示文稿完成后:
清理临时文件
.claude-design/slide-previews/打开演示文稿
open [filename].html 在浏览器中启动提供摘要
你的演示文稿已准备就绪! 📁 文件:[filename].html 🎨 风格:[风格名称] 📊 幻灯片:[数量] **导航:** - 方向键(← →)或空格键导航 - 滚动/滑动也可用 - 点击右侧的点跳转到对应幻灯片 **自定义:** - 颜色:在顶部查找 `:root` CSS 变量 - 字体:更改 Fontshare/Google Fonts 链接 - 动画:修改 `.reveal` 类的时间设定 是否需要我进行任何调整?
使用此指南将动画与预期感受匹配:
/* 淡入 + 上滑(最常见) */
.reveal {
opacity: 0;
transform: translateY(30px);
transition: opacity 0.6s var(--ease-out-expo),
transform 0.6s var(--ease-out-expo);
}
.visible .reveal {
opacity: 1;
transform: translateY(0);
}
/* 缩放进入 */
.reveal-scale {
opacity: 0;
transform: scale(0.9);
transition: opacity 0.6s, transform 0.6s var(--ease-out-expo);
}
/* 从左滑入 */
.reveal-left {
opacity: 0;
transform: translateX(-50px);
transition: opacity 0.6s, transform 0.6s var(--ease-out-expo);
}
/* 模糊进入 */
.reveal-blur {
opacity: 0;
filter: blur(10px);
transition: opacity 0.8s, filter 0.8s var(--ease-out-expo);
}
/* 渐变网格 */
.gradient-bg {
background:
radial-gradient(ellipse at 20% 80%, rgba(120, 0, 255, 0.3) 0%, transparent 50%),
radial-gradient(ellipse at 80% 20%, rgba(0, 255, 200, 0.2) 0%, transparent 50%),
var(--bg-primary);
}
/* 噪点纹理 */
.noise-bg {
background-image: url("data:image/svg+xml,..."); /* 内联 SVG 噪点 */
}
/* 网格图案 */
.grid-bg {
background-image:
linear-gradient(rgba(255,255,255,0.03) 1px, transparent 1px),
linear-gradient(90deg, rgba(255,255,255,0.03) 1px, transparent 1px);
background-size: 50px 50px;
}
/* 悬停 3D 倾斜 */
class TiltEffect {
constructor(element) {
this.element = element;
this.element.style.transformStyle = 'preserve-3d';
this.element.style.perspective = '1000px';
this.bindEvents();
}
bindEvents() {
this.element.addEventListener('mousemove', (e) => {
const rect = this.element.getBoundingClientRect();
const x = (e.clientX - rect.left) / rect.width - 0.5;
const y = (e.clientY - rect.top) / rect.height - 0.5;
this.element.style.transform = `
rotateY(${x * 10}deg)
rotateX(${-y * 10}deg)
`;
});
this.element.addEventListener('mouseleave', () => {
this.element.style.transform = 'rotateY(0) rotateX(0)';
});
}
}
字体未加载:
动画未触发:
.visible 类是否被添加滚动捕捉无效:
scroll-snap-typescroll-snap-align: start移动端问题:
性能问题:
will-changetransform 和 opacity 动画相关专题
热门下载
相关下载
精品课程
共6课时 | 54.7万人学习
共89课时 | 134.1万人学习
共49课时 | 82.6万人学习